Skip to contentSkip to conversation

Recent changes (master)

PATCH Jens Axboe 1 participant 1 message Nov 10, 2015 Library code

lore
Share & tools
lore

Jens Axboe

author
#0 lore raw

The following changes since commit 9c3e13e3314da394698ca32f21cc46d46b7cfe47:

smalloc: only clear the bitmap, not the whole pool (2015-11-07 17:33:38 -0700)

are available in the git repository at:

git://git.kernel.dk/fio.git master

for you to fetch changes up to 0127c57b82cfef26149c04b1d785897a68a6dffa:

smalloc: get rid of global lock (2015-11-09 19:38:15 -0700)

----------------------------------------------------------------
Jens Axboe (6):
Fixups for poisson rate
Add poisson rate selection to FD_RATE output Provide some consistency in rate_* options Rename rate_poisson to rate_process Clarify spread/lambda of poisson
smalloc: get rid of global lock

Song Liu (4):
Enable request flow under Poisson process
make sure __rand_0_1 does not return 0.0
add example using --rate_poisson
In fio.1 and HOWTO, add link to Poisson process in wikipedia

 HOWTO                                | 13 +++++++--
 backend.c                            | 22 +++++++++++++---
 cconv.c                              |  2 ++
 examples/poisson-rate-submission.fio | 14 ++++++++++
 fio.1                                | 44 ++++++++++++++++++-------------
 fio.h                                |  8 +++++-
 init.c                               |  2 ++
 lib/rand.h                           | 13 +++++++++
 options.c                            | 28 ++++++++++++++++++--
 server.h                             |  2 +-
 smalloc.c                            | 51 +++---------------------------------
 thread_options.h                     |  3 +++
 12 files changed, 127 insertions(+), 75 deletions(-)
 create mode 100644 examples/poisson-rate-submission.fio

---

Diff of recent changes:

HOWTO +11 -2
index 81217b7..a534aa8 100644
@@ -1049,7 +1049,7 @@ rate=int	Cap the bandwidth used by this job. The number is in bytes/sec,
 		will only limit writes (to 500KB/sec), the latter will only
 		limit reads.
 
-ratemin=int	Tell fio to do whatever it can to maintain at least this
+rate_min=int	Tell fio to do whatever it can to maintain at least this
 		bandwidth. Failing to meet this requirement, will cause
 		the job to exit. The same format as rate is used for
 		read vs write separation.
@@ -1064,6 +1064,15 @@ 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_process=str	This option controls how fio manages rated IO
+		submissions. The default is 'linear', which submits IO in a
+		linear fashion with fixed delays between IOs that gets
+		adjusted based on IO completion rates. If this is set to
+		'poisson', fio will submit IO based on a more real world
+		random request flow, known as the Poisson process
+		(https://en.wikipedia.org/wiki/Poisson_process). The lambda
+		will be 10^6 / IOPS for the given workload.
+
 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.
@@ -1081,7 +1090,7 @@ latency_percentile=float	The percentage of IOs that must fall within the
 max_latency=int	If set, fio will exit the job if it exceeds this maximum
 		latency. It will exit with an ETIME error.
 
-ratecycle=int	Average bandwidth for 'rate' and 'ratemin' over this number
+rate_cycle=int	Average bandwidth for 'rate' and 'rate_min' over this number
 		of milliseconds.
 
 cpumask=int	Set the CPU affinity of this job. The parameter given is a
backend.c +18 -4
index 0a42da3..aa94acf 100644
@@ -35,6 +35,7 @@
 #include <sys/wait.h>
 #include <sys/ipc.h>
 #include <sys/mman.h>
+#include <math.h>
 
 #include "fio.h"
 #ifndef FIO_NO_HAVE_SHM_H
@@ -775,17 +776,30 @@ static int io_complete_bytes_exceeded(struct thread_data *td)
  */
 static long long usec_for_io(struct thread_data *td, enum fio_ddir ddir)
 {
-	uint64_t secs, remainder, bps, bytes;
+	uint64_t secs, remainder, bps, bytes, iops;
 
 	assert(!(td->flags & TD_F_CHILD));
 	bytes = td->rate_io_issue_bytes[ddir];
 	bps = td->rate_bps[ddir];
-	if (bps) {
+
+	if (td->o.rate_process == RATE_PROCESS_POISSON) {
+		uint64_t val;
+		iops = bps / td->o.bs[ddir];
+		val = (int64_t) (1000000 / iops) *
+				-logf(__rand_0_1(&td->poisson_state));
+		if (val) {
+			dprint(FD_RATE, "poisson rate iops=%llu\n",
+					(unsigned long long) 1000000 / val);
+		}
+		td->last_usec += val;
+		return td->last_usec;
+	} else if (bps) {
 		secs = bytes / bps;
 		remainder = bytes % bps;
 		return remainder * 1000000 / bps + secs * 1000000;
-	} else
-		return 0;
+	}
+
+	return 0;
 }
 
 /*
cconv.c +2 -0
index fde8c6d..c309578 100644
@@ -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->rate_process = le32_to_cpu(top->rate_process);
 
 	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->rate_process = cpu_to_le32(o->rate_process);
 
 	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));
examples/poisson-rate-submission.fio new file +14 -0
new file mode 100644
index 0000000..4bb28f2
@@ -0,0 +1,14 @@
+[poisson-rate-submit]
+size=128m
+rw=randread
+ioengine=libaio
+iodepth=32
+direct=1
+# by setting the submit mode to offload, we can guarantee a fixed rate of
+# submission regardless of what the device completion rate is.
+io_submit_mode=offload
+rate_iops=50
+# Real world random request flow follows Poisson process. To give better
+# insight on latency distribution, we simulate request flow under Poisson
+# process.
+rate_process=poisson
fio.1 +26 -18

119 lines not on this page · raw message

fio.h +7 -1
index 5e8ac66..a2b3d9f 100644
@@ -95,12 +95,16 @@ enum {
 	FIO_RAND_SEQ_RAND_TRIM_OFF,
 	FIO_RAND_START_DELAY,
 	FIO_DEDUPE_OFF,
+	FIO_RAND_POISSON_OFF,
 	FIO_RAND_NR_OFFS,
 };
 
 enum {
 	IO_MODE_INLINE = 0,
-	IO_MODE_OFFLOAD,
+	IO_MODE_OFFLOAD = 1,
+
+	RATE_PROCESS_LINEAR = 0,
+	RATE_PROCESS_POISSON = 1,
 };
 
 /*
@@ -243,6 +247,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];
+	int64_t last_usec;
+	struct frand_state poisson_state;
 
 	/*
 	 * Enforced rate submission/completion workqueue
init.c +2 -0
index e09872f..04b4a1e 100644
@@ -473,6 +473,7 @@ static int __setup_rate(struct thread_data *td, enum fio_ddir ddir)
 
 	td->rate_next_io_time[ddir] = 0;
 	td->rate_io_issue_bytes[ddir] = 0;
+	td->last_usec = 0;
 	return 0;
 }
 
@@ -857,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;
lib/rand.h +13 -0
index b99f618..a95bd28 100644
@@ -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 (val + 1.0) / (FRAND64_MAX + 1.0);
+	} else {
+		uint32_t val = __rand32(&state->state32);
+
+		return (val + 1.0) / (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);
options.c +26 -2
index 5584413..a61606c 100644
@@ -2818,7 +2818,8 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
 		.group	= FIO_OPT_G_RATE,
 	},
 	{
-		.name	= "ratemin",
+		.name	= "rate_min",
+		.alias	= "ratemin",
 		.lname	= "I/O min rate",
 		.type	= FIO_OPT_INT,
 		.off1	= td_var_offset(ratemin[DDIR_READ]),
@@ -2856,7 +2857,30 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
 		.group	= FIO_OPT_G_RATE,
 	},
 	{
-		.name	= "ratecycle",
+		.name	= "rate_process",
+		.lname	= "Rate Process",
+		.type	= FIO_OPT_STR,
+		.off1	= td_var_offset(rate_process),
+		.help	= "What process controls how rated IO is managed",
+		.def	= "linear",
+		.category = FIO_OPT_C_IO,
+		.group	= FIO_OPT_G_RATE,
+		.posval = {
+			  { .ival = "linear",
+			    .oval = RATE_PROCESS_LINEAR,
+			    .help = "Linear rate of IO",
+			  },
+			  {
+			    .ival = "poisson",
+			    .oval = RATE_PROCESS_POISSON,
+			    .help = "Rate follows Poisson process",
+			  },
+		},
+		.parent = "rate",
+	},
+	{
+		.name	= "rate_cycle",
+		.alias	= "ratecycle",
 		.lname	= "I/O rate cycle",
 		.type	= FIO_OPT_INT,
 		.off1	= td_var_offset(ratecycle),
server.h +1 -1
index eb29de7..6709b5f 100644
@@ -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,
smalloc.c +4 -47

121 lines not on this page · raw message

thread_options.h +3 -0
index ed960ee..567df81 100644
@@ -231,6 +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 rate_process;
 
 	char *ioscheduler;
 
@@ -471,6 +472,8 @@ 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 rate_process;
+	uint32_t padding_0;   /* for alignment assert */
 
 	uint8_t ioscheduler[FIO_TOP_STR_MAX];