Fixups for poisson rate
authorJens Axboe <axboe@fb.com>
Mon, 9 Nov 2015 19:54:37 +0000 (12:54 -0700)
committerJens Axboe <axboe@fb.com>
Mon, 9 Nov 2015 19:56:44 +0000 (12:56 -0700)
- Change name to poisson_rate, we could add other uses for this
  functionality (like depth, etc).

- Add "rate" as option parent.

- Ensure we convert the option for client/server, bump protocol
  version.

- Add a separate rand state for poisson, so it becomes randomly
  controllable (through randrepeat).

- Add random 0..1 helper.

Signed-off-by: Jens Axboe <axboe@fb.com>
HOWTO
backend.c
cconv.c
fio.1
fio.h
init.c
lib/rand.h
options.c
server.h
thread_options.h

diff --git a/HOWTO b/HOWTO
index 81217b77906a6956d1e6bd8ebd70c2986dbb6348..03a0060c4ede820428d491f7d10b4a8143c07ed6 100644 (file)
--- a/HOWTO
+++ b/HOWTO
@@ -1064,6 +1064,9 @@ rate_iops_min=int If fio doesn't meet this rate of IO, it will cause
                the job to exit. The same format as rate is used for read vs
                write separation.
 
+rate_poisson=bool      When rate limited, try to simulate request flow under
+               Poisson process (instead of even distribution). Default: false.
+
 latency_target=int     If set, fio will attempt to find the max performance
                point that the given workload will run at while maintaining a
                latency below this target. The values is given in microseconds.
index 7a030ebbbe40e2f3a10347376d1dd26eb045479c..85a981dc4d3fdf05183661fd9b012522a60c2aed 100644 (file)
--- a/backend.c
+++ b/backend.c
@@ -782,17 +782,18 @@ static long long usec_for_io(struct thread_data *td, enum fio_ddir ddir)
        bytes = td->rate_io_issue_bytes[ddir];
        bps = td->rate_bps[ddir];
 
-       if (td->o.poisson_request) {
+       if (td->o.poisson_rate) {
                iops = bps / td->o.bs[ddir];
-               td->last_usec += (long long)(1000000 / iops) *
-                       (-logf(((float)rand() + 1) / ((float)RAND_MAX + 1)));
+               td->last_usec += (int64_t) (1000000 / iops) *
+                                       -logf(__rand_0_1(&td->poisson_state));
                return td->last_usec;
        } else if (bps) {
                secs = bytes / bps;
                remainder = bytes % bps;
                return remainder * 1000000 / bps + secs * 1000000;
-       } else
-               return 0;
+       }
+
+       return 0;
 }
 
 /*
diff --git a/cconv.c b/cconv.c
index fde8c6de6e8dc9baa5de2bc89f1f21b54ffd336b..26b90b93611342b3de8e2cfc5cb635ad19a8389f 100644 (file)
--- a/cconv.c
+++ b/cconv.c
@@ -254,6 +254,7 @@ void convert_thread_options_to_cpu(struct thread_options *o,
        o->per_job_logs = le32_to_cpu(top->per_job_logs);
 
        o->trim_backlog = le64_to_cpu(top->trim_backlog);
+       o->poisson_rate = le32_to_cpu(top->poisson_rate);
 
        for (i = 0; i < FIO_IO_U_LIST_MAX_LEN; i++)
                o->percentile_list[i].u.f = fio_uint64_to_double(le64_to_cpu(top->percentile_list[i].u.i));
@@ -474,6 +475,7 @@ void convert_thread_options_to_net(struct thread_options_pack *top,
        top->trim_backlog = __cpu_to_le64(o->trim_backlog);
        top->offset_increment = __cpu_to_le64(o->offset_increment);
        top->number_ios = __cpu_to_le64(o->number_ios);
+       top->poisson_rate = cpu_to_le32(o->poisson_rate);
 
        for (i = 0; i < FIO_IO_U_LIST_MAX_LEN; i++)
                top->percentile_list[i].u.i = __cpu_to_le64(fio_double_to_uint64(o->percentile_list[i].u.f));
diff --git a/fio.1 b/fio.1
index 2ecc3d3300f389dc37ab0193005d3e5f899abf3f..99d9f9e07e63a7ccb2c6462bef9e70843ebc82a0 100644 (file)
--- a/fio.1
+++ b/fio.1
@@ -963,8 +963,8 @@ size is used as the metric.
 If this rate of I/O is not met, the job will exit. The same format as \fBrate\fR
 is used for read vs write separation.
 .TP
-.BI poisson \fR=\fPbool
-When rate limited, try simulate request flow under Poisson process (instead
+.BI rate_poisson \fR=\fPbool
+When rate limited, try to simulate request flow under Poisson process (instead
 of even distribution). Default: false.
 .TP
 .BI ratecycle \fR=\fPint
diff --git a/fio.h b/fio.h
index 6bb1949f9faed23d2d8977ed3df3f2db32dfd4ab..7b198b216411b81043e761e4fa444c09dfb5f012 100644 (file)
--- a/fio.h
+++ b/fio.h
@@ -95,6 +95,7 @@ enum {
        FIO_RAND_SEQ_RAND_TRIM_OFF,
        FIO_RAND_START_DELAY,
        FIO_DEDUPE_OFF,
+       FIO_RAND_POISSON_OFF,
        FIO_RAND_NR_OFFS,
 };
 
@@ -243,7 +244,8 @@ struct thread_data {
        unsigned long rate_blocks[DDIR_RWDIR_CNT];
        unsigned long rate_io_issue_bytes[DDIR_RWDIR_CNT];
        struct timeval lastrate[DDIR_RWDIR_CNT];
-       unsigned long long last_usec;
+       int64_t last_usec;
+       struct frand_state poisson_state;
 
        /*
         * Enforced rate submission/completion workqueue
diff --git a/init.c b/init.c
index 242518ccd703f426eb216f86c9e5718da5138df2..04b4a1e5020c0b85d767ea33bcb1918e320a1eb8 100644 (file)
--- a/init.c
+++ b/init.c
@@ -858,6 +858,7 @@ static void td_fill_rand_seeds_internal(struct thread_data *td, int use64)
        init_rand_seed(&td->file_size_state, td->rand_seeds[FIO_RAND_FILE_SIZE_OFF], use64);
        init_rand_seed(&td->trim_state, td->rand_seeds[FIO_RAND_TRIM_OFF], use64);
        init_rand_seed(&td->delay_state, td->rand_seeds[FIO_RAND_START_DELAY], use64);
+       init_rand_seed(&td->poisson_state, td->rand_seeds[FIO_RAND_POISSON_OFF], 0);
 
        if (!td_random(td))
                return;
index b99f618c000f108db5fb56adfc4bc0eaa00cad30..3d78115d48580f3ea5a0afc3e6e4cbcd7206e83a 100644 (file)
@@ -104,6 +104,19 @@ static inline uint64_t __rand(struct frand_state *state)
                return __rand32(&state->state32);
 }
 
+static inline double __rand_0_1(struct frand_state *state)
+{
+       if (state->use64) {
+               uint64_t val = __rand64(&state->state64);
+
+               return (double) val / (FRAND64_MAX + 1.0);
+       } else {
+               uint32_t val = __rand32(&state->state32);
+
+               return (double) val / (FRAND32_MAX + 1.0);
+       }
+}
+
 extern void init_rand(struct frand_state *, int);
 extern void init_rand_seed(struct frand_state *, unsigned int seed, int);
 extern void __fill_random_buf(void *buf, unsigned int len, unsigned long seed);
index 8198e6b424a631e466ce680beaa8b931a2d2480a..ac41565c8677783aaa222ccf15929a74c1b7b39a 100644 (file)
--- a/options.c
+++ b/options.c
@@ -2856,12 +2856,13 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .group  = FIO_OPT_G_RATE,
        },
        {
-               .name   = "poisson",
+               .name   = "rate_poisson",
                .lname  = "simulate requests under Poisson process",
                .type   = FIO_OPT_BOOL,
-               .off1   = td_var_offset(poisson_request),
-               .help   = "with rate limit, try simulate requests that follow Poisson process",
+               .off1   = td_var_offset(poisson_rate),
+               .help   = "With rate limit, simulate requests that follow Poisson process",
                .def    = "0",
+               .parent = "rate",
                .hide   = 1,
                .category = FIO_OPT_C_IO,
                .group  = FIO_OPT_G_RATE,
index eb29de7817e28f148c19427c136ee9d174ba5c48..6709b5fbdef6dce37c7ffecc28888304ce0ec489 100644 (file)
--- a/server.h
+++ b/server.h
@@ -38,7 +38,7 @@ struct fio_net_cmd_reply {
 };
 
 enum {
-       FIO_SERVER_VER                  = 47,
+       FIO_SERVER_VER                  = 48,
 
        FIO_SERVER_MAX_FRAGMENT_PDU     = 1024,
        FIO_SERVER_MAX_CMD_MB           = 2048,
index 4c26dcb53ff759a6b9d7a06e75525dbc0c6e70aa..067079444b7854ba5570bf9e818d55f06a984933 100644 (file)
@@ -231,7 +231,7 @@ struct thread_options {
        unsigned int io_submit_mode;
        unsigned int rate_iops[DDIR_RWDIR_CNT];
        unsigned int rate_iops_min[DDIR_RWDIR_CNT];
-       unsigned int poisson_request;
+       unsigned int poisson_rate;
 
        char *ioscheduler;
 
@@ -472,7 +472,7 @@ struct thread_options_pack {
        uint32_t io_submit_mode;
        uint32_t rate_iops[DDIR_RWDIR_CNT];
        uint32_t rate_iops_min[DDIR_RWDIR_CNT];
-       uint32_t poisson_request;
+       uint32_t poisson_rate;
        uint32_t padding_0;   /* for alignment assert */
 
        uint8_t ioscheduler[FIO_TOP_STR_MAX];