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.
 
                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.
 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];
 
        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];
                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;
                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->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));
 
        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->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));
 
        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
 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
 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_SEQ_RAND_TRIM_OFF,
        FIO_RAND_START_DELAY,
        FIO_DEDUPE_OFF,
+       FIO_RAND_POISSON_OFF,
        FIO_RAND_NR_OFFS,
 };
 
        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 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
 
        /*
         * 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->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;
 
        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);
 }
 
                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);
 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,
        },
        {
                .group  = FIO_OPT_G_RATE,
        },
        {
-               .name   = "poisson",
+               .name   = "rate_poisson",
                .lname  = "simulate requests under Poisson process",
                .type   = FIO_OPT_BOOL,
                .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",
                .def    = "0",
+               .parent = "rate",
                .hide   = 1,
                .category = FIO_OPT_C_IO,
                .group  = FIO_OPT_G_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 {
 };
 
 enum {
-       FIO_SERVER_VER                  = 47,
+       FIO_SERVER_VER                  = 48,
 
        FIO_SERVER_MAX_FRAGMENT_PDU     = 1024,
        FIO_SERVER_MAX_CMD_MB           = 2048,
 
        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 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;
 
 
        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 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];
        uint32_t padding_0;   /* for alignment assert */
 
        uint8_t ioscheduler[FIO_TOP_STR_MAX];