Skip to contentSkip to conversation

Recent changes (master)

PATCH Jens Axboe 1 participant 1 message Dec 17, 2016 Kbuild

lore
Share & tools
lore

Jens Axboe

author
#0 lore raw

The following changes since commit 0d60927f167d318a685b9e5309bb392c624776e4:

fio: move _FORTIFY_SOURCE to only when optimization is turned on (2016-12-15 14:55:00 -0700)

are available in the git repository at:

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

for you to fetch changes up to 104ee4dea7246d51d053076c55b917548dd0e7e2:

fio: add additional support for dev-dax ioengine (2016-12-16 16:05:05 -0700)

----------------------------------------------------------------
Dave Jiang (1):
fio: add additional support for dev-dax ioengine

Jens Axboe (11):
Add local TODO for steady-state work
steady-state: convert options across the wire
TODO: man page missing
steadystate: move into its own header
steadystate: cleanups
steadystate: more cleanups
steadystate: rename 'steadystate' to 'steadystate_enabled'
steadystate: eliminate some steadystate_data members
steadystate: kill off ->attained
steadystate: kill ->last_in_group and ->ramp_time_over
Merge https://bitbucket.org/vincentfu/fio-steadystate into steady-state-2

Vincent Fu (30):
Allow fio to terminate jobs when steady state is attained
Fix typo, restore unintended HOWTO deletion
Add locking around reads of td->io_blocks and io_byes.
Change steadystate reporting:
Steady state detection: enhance reporting of results, change memory allocation point
JSON output, code formatting changes
Fix bug where measurements were not printed in the correct order when steady state was not attained
Split helper thread debug logging away from steadystate debug logging
Update test script for new JSON steadystate['criterion'] reporting
Clear up white space errors
steadystate: bug fixes
steadystate: reject job if steadystate options are not consistent within reporting group
steadystate: add example job file
steadystate: update man page
steadystate: rename __FIO_SS_LAST to __FIO_SS_DATA
steadystate: get rid of ->ss_pct and encode this information in ->state via __FIO_SS_PCT
steadystate: add line for output-format=normal
steadystate: implement transmission of steadystate data over the wire in client/server mode
steadystate: instead of including ss_sum_y in thread_stat record whether ss_sum_y is nonzero in ss_state via __FIO_SS_BUFFER_FULL
steadystate: rename TODO to STEADYSTATE-TODO
steadystate: ensure that pointers in thread_stat occupy the same amount of storage in 32- and 64-bit platforms
steadystate: fix alignment in stat.h
steadystate: use uint64_t for storing bw and iops calculations and related values. Also fix an overflow with group_bw on 32-bit platforms.
steadystate: clean up checks for when steadystate termination is not engaged
steadystate: rename options->ss to options->ss_state since ss is used elsewhere to refer to struct steadystate_data
steadystate: improve output of test script
steadystate: make file for read testing optional on posix systems
steadystate: make test script work better under Windows
Merge git://git.kernel.dk/fio into steady-state
use type double in creating floating point JSON values

 HOWTO                           |  47 ++++-
 Makefile                        |   3 +-
 STEADYSTATE-TODO                |  14 ++
 backend.c                       |   7 +
 cconv.c                         |   8 +
 client.c                        |  25 +++
 debug.h                         |   2 +
 examples/dev-dax.fio            |  45 +++++
 examples/steadystate.fio        |  45 +++++
 fio.1                           |  47 +++++
 fio.h                           |   3 +
 helper_thread.c                 |  27 ++-
 init.c                          |  14 ++
 json.c                          |   2 +-
 libfio.c                        |   1 +
 options.c                       | 134 +++++++++++++++
 server.c                        |  32 +++-
 server.h                        |   2 +-
 stat.c                          |  94 ++++++++++
 stat.h                          |  24 ++-
 steadystate.c                   | 368 ++++++++++++++++++++++++++++++++++++++++
 steadystate.h                   |  61 +++++++
 thread_options.h                |   9 +
 unit_tests/steadystate_tests.py | 222 ++++++++++++++++++++++++
 24 files changed, 1225 insertions(+), 11 deletions(-)
 create mode 100644 STEADYSTATE-TODO
 create mode 100644 examples/dev-dax.fio
 create mode 100644 examples/steadystate.fio
 create mode 100644 steadystate.c
 create mode 100644 steadystate.h
 create mode 100755 unit_tests/steadystate_tests.py

---

Diff of recent changes:

HOWTO +46 -1
index 577eed9..6893c86 100644
@@ -297,7 +297,7 @@ irange	Integer range with suffix. Allows value range to be given, such
 	1k:4k. If the option allows two sets of ranges, they can be
 	specified with a ',' or '/' delimiter: 1k-4k/8k-32k. Also see
 	int.
-float_list	A list of floating numbers, separated by a ':' character.
+float_list	A list of floating point numbers, separated by a ':' character.
 
 With the above in mind, here follows the complete list of fio job
 parameters.
@@ -819,6 +819,9 @@ ioengine=str	Defines how the job issues io to the file. The following
 			pmemblk	Read and write through the NVML libpmemblk
 				interface.
 
+			dev-dax Read and write through a DAX device exposed
+				from persistent memory.
+
 			external Prefix to specify loading an external
 				IO engine object file. Append the engine
 				filename, eg ioengine=external:/tmp/foo.o
@@ -1218,6 +1221,48 @@ ramp_time=time	If set, fio will run the specified workload for this amount
 		thus it will increase the total runtime if a special timeout
 		or runtime is specified.
 
+steadystate=str:float
+ss=str:float	Define the criterion and limit for assessing steady state
+		performance. The first parameter designates the criterion
+		whereas the second parameter sets the threshold. When the
+		criterion falls below the threshold for the specified duration,
+		the job will stop. For example, iops_slope:0.1% will direct fio
+		to terminate the job when the least squares regression slope
+		falls below 0.1% of the mean IOPS. If group_reporting is
+		enabled this will apply to all jobs in the group. Below is the
+		list of available steady state assessment criteria. All
+		assessments are carried out using only data from the rolling
+		collection window. Threshold limits can be expressed as a fixed
+		value or as a percentage of the mean in the collection window.
+			iops	Collect IOPS data. Stop the job if all
+				individual IOPS measurements are within the
+				specified limit of the mean IOPS (e.g., iops:2
+				means that all individual IOPS values must be
+				within 2 of the mean, whereas iops:0.2% means
+				that all individual IOPS values must be within
+				0.2% of	the mean IOPS to terminate the job).
+			iops_slope
+				Collect IOPS data and calculate the least
+				squares regression slope. Stop the job if the
+				slope falls below the specified limit.
+			bw	Collect bandwidth data. Stop the job if all
+				individual bandwidth measurements are within
+				the specified limit of the mean bandwidth.
+			bw_slope
+				Collect bandwidth data and calculate the least
+				squares regression slope. Stop the job if the
+				slope falls below the specified limit.
+
+steadystate_duration=time
+ss_dur=time	A rolling window of this duration will be used to judge whether
+		steady state has been reached. Data will be collected once per
+		second. The default is 0 which disables steady state detection.
+
+steadystate_ramp_time=time
+ss_ramp=time	Allow the job to run for the specified duration before
+		beginning data collection for checking the steady state job
+		termination criterion. The default is 0.
+
 invalidate=bool	Invalidate the buffer/page cache parts for this file prior
 		to starting io. Defaults to true.
 
Makefile +2 -1
index d27380b..4c64168 100644
@@ -45,7 +45,8 @@ SOURCE :=	$(patsubst $(SRCDIR)/%,%,$(wildcard $(SRCDIR)/crc/*.c)) \
 		server.c client.c iolog.c backend.c libfio.c flow.c cconv.c \
 		gettime-thread.c helpers.c json.c idletime.c td_error.c \
 		profiles/tiobench.c profiles/act.c io_u_queue.c filelock.c \
-		workqueue.c rate-submit.c optgroup.c helper_thread.c
+		workqueue.c rate-submit.c optgroup.c helper_thread.c \
+		steadystate.c
 
 ifdef CONFIG_LIBHDFS
   HDFSFLAGS= -I $(JAVA_HOME)/include -I $(JAVA_HOME)/include/linux -I $(FIO_LIBHDFS_INCLUDE)
STEADYSTATE-TODO new file +14 -0
new file mode 100644
index 0000000..e4b146e
@@ -0,0 +1,14 @@
+Known issues/TODO (for steady-state)
+
+- Allow user to specify the frequency of measurements
+
+- Better documentation for output
+
+- Report read, write, trim IOPS/BW separately
+
+- Semantics for the ring buffer ss->head are confusing. ss->head points
+  to the beginning of the buffer up through the point where the buffer
+  is filled for the first time. afterwards, when a new element is added,
+  ss->head is advanced to point to the second element in the buffer. if
+  steady state is attained upon adding a new element, ss->head is not
+  advanced so it actually does point to the head of the buffer.
backend.c +7 -0
index ac71521..a048452 100644
@@ -1665,6 +1665,7 @@ static void *thread_main(void *data)
 	fio_getrusage(&td->ru_start);
 	memcpy(&td->bw_sample_time, &td->epoch, sizeof(td->epoch));
 	memcpy(&td->iops_sample_time, &td->epoch, sizeof(td->epoch));
+	memcpy(&td->ss.prev_time, &td->epoch, sizeof(td->epoch));
 
 	if (o->ratemin[DDIR_READ] || o->ratemin[DDIR_WRITE] ||
 			o->ratemin[DDIR_TRIM]) {
@@ -2415,6 +2416,12 @@ int fio_backend(struct sk_out *sk_out)
 	}
 
 	for_each_td(td, i) {
+		if (td->ss.dur) {
+			if (td->ss.iops_data != NULL) {
+				free(td->ss.iops_data);
+				free(td->ss.bw_data);
+			}
+		}
 		fio_options_free(td);
 		if (td->rusage_sem) {
 			fio_mutex_remove(td->rusage_sem);
cconv.c +8 -0
index 0032cc0..336805b 100644
@@ -213,6 +213,10 @@ void convert_thread_options_to_cpu(struct thread_options *o,
 	o->start_delay_high = le64_to_cpu(top->start_delay_high);
 	o->timeout = le64_to_cpu(top->timeout);
 	o->ramp_time = le64_to_cpu(top->ramp_time);
+	o->ss_dur = le64_to_cpu(top->ss_dur);
+	o->ss_ramp_time = le64_to_cpu(top->ss_ramp_time);
+	o->ss_state = le32_to_cpu(top->ss_state);
+	o->ss_limit.u.f = fio_uint64_to_double(le64_to_cpu(top->ss_limit.u.i));
 	o->zone_range = le64_to_cpu(top->zone_range);
 	o->zone_size = le64_to_cpu(top->zone_size);
 	o->zone_skip = le64_to_cpu(top->zone_skip);
@@ -523,6 +527,10 @@ void convert_thread_options_to_net(struct thread_options_pack *top,
 	top->start_delay_high = __cpu_to_le64(o->start_delay_high);
 	top->timeout = __cpu_to_le64(o->timeout);
 	top->ramp_time = __cpu_to_le64(o->ramp_time);
+	top->ss_dur = __cpu_to_le64(top->ss_dur);
+	top->ss_ramp_time = __cpu_to_le64(top->ss_ramp_time);
+	top->ss_state = cpu_to_le32(top->ss_state);
+	top->ss_limit.u.i = __cpu_to_le64(fio_double_to_uint64(o->ss_limit.u.f));
 	top->zone_range = __cpu_to_le64(o->zone_range);
 	top->zone_size = __cpu_to_le64(o->zone_size);
 	top->zone_skip = __cpu_to_le64(o->zone_skip);
client.c +25 -0
index c613887..48d4c52 100644
@@ -946,6 +946,21 @@ static void convert_ts(struct thread_stat *dst, struct thread_stat *src)
 	dst->nr_block_infos	= le64_to_cpu(src->nr_block_infos);
 	for (i = 0; i < dst->nr_block_infos; i++)
 		dst->block_infos[i] = le32_to_cpu(src->block_infos[i]);
+
+	dst->ss_dur		= le64_to_cpu(src->ss_dur);
+	dst->ss_state		= le32_to_cpu(src->ss_state);
+	dst->ss_head		= le32_to_cpu(src->ss_head);
+	dst->ss_limit.u.f 	= fio_uint64_to_double(le64_to_cpu(src->ss_limit.u.i));
+	dst->ss_slope.u.f 	= fio_uint64_to_double(le64_to_cpu(src->ss_slope.u.i));
+	dst->ss_deviation.u.f 	= fio_uint64_to_double(le64_to_cpu(src->ss_deviation.u.i));
+	dst->ss_criterion.u.f 	= fio_uint64_to_double(le64_to_cpu(src->ss_criterion.u.i));
+
+	if (dst->ss_state & __FIO_SS_DATA) {
+		for (i = 0; i < dst->ss_dur; i++ ) {
+			dst->ss_iops_data[i] = le64_to_cpu(src->ss_iops_data[i]);
+			dst->ss_bw_data[i] = le64_to_cpu(src->ss_bw_data[i]);
+		}
+	}
 }
 
 static void convert_gs(struct group_run_stats *dst, struct group_run_stats *src)
@@ -1617,6 +1632,7 @@ int fio_handle_client(struct fio_client *client)
 {
 	struct client_ops *ops = client->ops;
 	struct fio_net_cmd *cmd;
+	int size;
 
 	dprint(FD_NET, "client: handle %s\n", client->hostname);
 
@@ -1649,6 +1665,15 @@ int fio_handle_client(struct fio_client *client)
 	case FIO_NET_CMD_TS: {
 		struct cmd_ts_pdu *p = (struct cmd_ts_pdu *) cmd->payload;
 
+		dprint(FD_NET, "client: ts->ss_state = %u\n", (unsigned int) le32_to_cpu(p->ts.ss_state));
+		if (le32_to_cpu(p->ts.ss_state) & __FIO_SS_DATA) {
+			dprint(FD_NET, "client: received steadystate ring buffers\n");
+
+			size = le64_to_cpu(p->ts.ss_dur);
+			p->ts.ss_iops_data = (uint64_t *) ((struct cmd_ts_pdu *)cmd->payload + 1);
+			p->ts.ss_bw_data = p->ts.ss_iops_data + size;
+		}
+
 		convert_ts(&p->ts, &p->ts);
 		convert_gs(&p->rs, &p->rs);
 
debug.h +2 -0
index 923fa39..e3aa3f1 100644
@@ -21,6 +21,8 @@ enum {
 	FD_NET,
 	FD_RATE,
 	FD_COMPRESS,
+	FD_STEADYSTATE,
+	FD_HELPERTHREAD,
 	FD_DEBUG_MAX,
 };
 
examples/dev-dax.fio new file +45 -0

45 lines not on this page · raw message

examples/steadystate.fio new file +45 -0

45 lines not on this page · raw message

fio.1 +47 -0

59 lines not on this page · raw message

fio.h +3 -0
index 7e32788..5726bef 100644
@@ -41,6 +41,7 @@
 #include "flow.h"
 #include "io_u_queue.h"
 #include "workqueue.h"
+#include "steadystate.h"
 
 #ifdef CONFIG_SOLARISAIO
 #include <sys/asynch.h>
@@ -395,6 +396,8 @@ struct thread_data {
 
 	void *pinned_mem;
 
+	struct steadystate_data ss;
+
 	char verror[FIO_VERROR_SIZE];
 };
 
helper_thread.c +23 -4
index f031df4..47ec728 100644
@@ -1,6 +1,7 @@
 #include "fio.h"
 #include "smalloc.h"
 #include "helper_thread.h"
+#include "steadystate.h"
 
 static struct helper_data {
 	volatile int exit;
@@ -69,14 +70,15 @@ void helper_thread_exit(void)
 static void *helper_thread_main(void *data)
 {
 	struct helper_data *hd = data;
-	unsigned int msec_to_next_event, next_log;
-	struct timeval tv, last_du;
+	unsigned int msec_to_next_event, next_log, next_ss = STEADYSTATE_MSEC;
+	struct timeval tv, last_du, last_ss;
 	int ret = 0;
 
 	sk_out_assign(hd->sk_out);
 
 	gettimeofday(&tv, NULL);
 	memcpy(&last_du, &tv, sizeof(tv));
+	memcpy(&last_ss, &tv, sizeof(tv));
 
 	fio_mutex_up(hd->startup_mutex);
 
@@ -84,7 +86,7 @@ static void *helper_thread_main(void *data)
 	while (!ret && !hd->exit) {
 		struct timespec ts;
 		struct timeval now;
-		uint64_t since_du;
+		uint64_t since_du, since_ss = 0;
 
 		timeval_add_msec(&tv, msec_to_next_event);
 		ts.tv_sec = tv.tv_sec;
@@ -98,6 +100,7 @@ static void *helper_thread_main(void *data)
 		if (hd->reset) {
 			memcpy(&tv, &now, sizeof(tv));
 			memcpy(&last_du, &now, sizeof(last_du));
+			memcpy(&last_ss, &now, sizeof(last_ss));
 			hd->reset = 0;
 		}
 
@@ -122,7 +125,22 @@ static void *helper_thread_main(void *data)
 		if (!next_log)
 			next_log = DISK_UTIL_MSEC;
 
-		msec_to_next_event = min(next_log, msec_to_next_event);
+		if (steadystate_enabled) {
+			since_ss = mtime_since(&last_ss, &now);
+			if (since_ss >= STEADYSTATE_MSEC || STEADYSTATE_MSEC - since_ss < 10) {
+				steadystate_check();
+				timeval_add_msec(&last_ss, since_ss);
+				if (since_ss > STEADYSTATE_MSEC)
+					next_ss = STEADYSTATE_MSEC - (since_ss - STEADYSTATE_MSEC);
+				else
+					next_ss = STEADYSTATE_MSEC;
+			}
+			else
+				next_ss = STEADYSTATE_MSEC - since_ss;
+                }
+
+		msec_to_next_event = min(min(next_log, msec_to_next_event), next_ss);
+		dprint(FD_HELPERTHREAD, "since_ss: %llu, next_ss: %u, next_log: %u, msec_to_next_event: %u\n", (unsigned long long)since_ss, next_ss, next_log, msec_to_next_event);
 
 		if (!is_backend)
 			print_thread_status();
@@ -142,6 +160,7 @@ int helper_thread_create(struct fio_mutex *startup_mutex, struct sk_out *sk_out)
 	hd = smalloc(sizeof(*hd));
 
 	setup_disk_util();
+	steadystate_setup();
 
 	hd->sk_out = sk_out;
 
init.c +14 -0
index 36feb51..f26f35d 100644
@@ -25,6 +25,7 @@
 #include "server.h"
 #include "idletime.h"
 #include "filelock.h"
+#include "steadystate.h"
 
 #include "oslib/getopt.h"
 #include "oslib/strcasestr.h"
@@ -1563,6 +1564,9 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num,
 			log_info("...\n");
 	}
 
+	if (td_steadystate_init(td))
+		goto err;
+
 	/*
 	 * recurse add identical jobs, clear numjobs and stonewall options
 	 * as they don't apply to sub-jobs
@@ -1578,6 +1582,8 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num,
 		td_new->o.stonewall = 0;
 		td_new->o.new_group = 0;
 		td_new->subjob_number = numjobs;
+		td_new->o.ss_dur = o->ss_dur * 1000000l;
+		td_new->o.ss_limit = o->ss_limit;
 
 		if (file_alloced) {
 			if (td_new->files) {
@@ -2120,6 +2126,14 @@ struct debug_level debug_levels[] = {
 	  .help = "Log compression logging",
 	  .shift = FD_COMPRESS,
 	},
+	{ .name = "steadystate",
+	  .help = "Steady state detection logging",
+	  .shift = FD_STEADYSTATE,
+	},
+	{ .name = "helperthread",
+	  .help = "Helper thread logging",
+	  .shift = FD_HELPERTHREAD,
+	},
 	{ .name = NULL, },
 };
 
json.c +1 -1
index 190fa9e..e0227ec 100644
@@ -40,7 +40,7 @@ static struct json_value *json_create_value_int(long long number)
 	return value;
 }
 
-static struct json_value *json_create_value_float(float number)
+static struct json_value *json_create_value_float(double number)
 {
 	struct json_value *value = malloc(sizeof(struct json_value));
 
libfio.c +1 -0
index 0f9f4e7..960daf6 100644
@@ -152,6 +152,7 @@ void reset_all_stats(struct thread_data *td)
 	memcpy(&td->start, &td->epoch, sizeof(struct timeval));
 	memcpy(&td->iops_sample_time, &td->epoch, sizeof(struct timeval));
 	memcpy(&td->bw_sample_time, &td->epoch, sizeof(struct timeval));
+	memcpy(&td->ss.prev_time, &td->epoch, sizeof(struct timeval));
 
 	lat_target_reset(td);
 	clear_rusage_stat(td);
options.c +134 -0

152 lines not on this page · raw message

server.c +31 -1
index 172ccc0..2e05415 100644
@@ -1462,6 +1462,8 @@ void fio_server_send_ts(struct thread_stat *ts, struct group_run_stats *rs)
 {
 	struct cmd_ts_pdu p;
 	int i, j;
+	void *ss_buf;
+	uint64_t *ss_iops, *ss_bw;
 
 	dprint(FD_NET, "server sending end stats\n");
 
@@ -1545,9 +1547,37 @@ void fio_server_send_ts(struct thread_stat *ts, struct group_run_stats *rs)
 	for (i = 0; i < p.ts.nr_block_infos; i++)
 		p.ts.block_infos[i] = cpu_to_le32(ts->block_infos[i]);
 
+	p.ts.ss_dur		= cpu_to_le64(ts->ss_dur);
+	p.ts.ss_state		= cpu_to_le32(ts->ss_state);
+	p.ts.ss_head		= cpu_to_le32(ts->ss_head);
+	p.ts.ss_limit.u.i	= cpu_to_le64(fio_double_to_uint64(ts->ss_limit.u.f));
+	p.ts.ss_slope.u.i	= cpu_to_le64(fio_double_to_uint64(ts->ss_slope.u.f));
+	p.ts.ss_deviation.u.i	= cpu_to_le64(fio_double_to_uint64(ts->ss_deviation.u.f));
+	p.ts.ss_criterion.u.i	= cpu_to_le64(fio_double_to_uint64(ts->ss_criterion.u.f));
+
 	convert_gs(&p.rs, rs);
 
-	fio_net_queue_cmd(FIO_NET_CMD_TS, &p, sizeof(p), NULL, SK_F_COPY);
+	dprint(FD_NET, "ts->ss_state = %d\n", ts->ss_state);
+	if (ts->ss_state & __FIO_SS_DATA) {
+		dprint(FD_NET, "server sending steadystate ring buffers\n");
+
+		ss_buf = malloc(sizeof(p) + 2*ts->ss_dur*sizeof(uint64_t));
+
+		memcpy(ss_buf, &p, sizeof(p));
+
+		ss_iops = (uint64_t *) ((struct cmd_ts_pdu *)ss_buf + 1);
+		ss_bw = ss_iops + (int) ts->ss_dur;
+		for (i = 0; i < ts->ss_dur; i++) {
+			ss_iops[i] = cpu_to_le64(ts->ss_iops_data[i]);
+			ss_bw[i] = cpu_to_le64(ts->ss_bw_data[i]);
+		}
+
+		fio_net_queue_cmd(FIO_NET_CMD_TS, ss_buf, sizeof(p) + 2*ts->ss_dur*sizeof(uint64_t), NULL, SK_F_COPY);
+
+		free(ss_buf);
+	}
+	else
+		fio_net_queue_cmd(FIO_NET_CMD_TS, &p, sizeof(p), NULL, SK_F_COPY);
 }
 
 void fio_server_send_gs(struct group_run_stats *rs)
server.h +1 -1
index 4a81bcd..3a1d0b0 100644
@@ -38,7 +38,7 @@ struct fio_net_cmd_reply {
 };
 
 enum {
-	FIO_SERVER_VER			= 59,
+	FIO_SERVER_VER			= 60,
 
 	FIO_SERVER_MAX_FRAGMENT_PDU	= 1024,
 	FIO_SERVER_MAX_CMD_MB		= 2048,
stat.c +94 -0

118 lines not on this page · raw message

stat.h +22 -2
index 75d1f4e..22083da 100644
@@ -198,10 +198,10 @@ struct thread_stat {
 	 */
 	union {
 		uint16_t continue_on_error;
-		uint64_t pad2;
+		uint32_t pad2;
 	};
-	uint64_t total_err_count;
 	uint32_t first_error;
+	uint64_t total_err_count;
 
 	uint64_t nr_block_infos;
 	uint32_t block_infos[MAX_NR_BLOCK_INFOS];
@@ -210,9 +210,29 @@ struct thread_stat {
 	uint32_t unit_base;
 
 	uint32_t latency_depth;
+	uint32_t pad3;
 	uint64_t latency_target;
 	fio_fp64_t latency_percentile;
 	uint64_t latency_window;
+
+	uint64_t ss_dur;
+	uint32_t ss_state;
+	uint32_t ss_head;
+
+	fio_fp64_t ss_limit;
+	fio_fp64_t ss_slope;
+	fio_fp64_t ss_deviation;
+	fio_fp64_t ss_criterion;
+
+	union {
+		uint64_t *ss_iops_data;
+		uint64_t pad4;
+	};
+
+	union {
+		uint64_t *ss_bw_data;
+		uint64_t pad5;
+	};
 } __attribute__((packed));
 
 struct jobs_eta {
steadystate.c new file +368 -0

368 lines not on this page · raw message

steadystate.h new file +61 -0

61 lines not on this page · raw message

thread_options.h +9 -0
index 8ec6b97..dd5b9ef 100644
@@ -170,6 +170,10 @@ struct thread_options {
 	unsigned long long start_delay_high;
 	unsigned long long timeout;
 	unsigned long long ramp_time;
+	unsigned int ss_state;
+	fio_fp64_t ss_limit;
+	unsigned long long ss_dur;
+	unsigned long long ss_ramp_time;
 	unsigned int overwrite;
 	unsigned int bw_avg_time;
 	unsigned int iops_avg_time;
@@ -434,6 +438,10 @@ struct thread_options_pack {
 	uint64_t start_delay_high;
 	uint64_t timeout;
 	uint64_t ramp_time;
+	uint64_t ss_dur;
+	uint64_t ss_ramp_time;
+	uint32_t ss_state;
+	fio_fp64_t ss_limit;
 	uint32_t overwrite;
 	uint32_t bw_avg_time;
 	uint32_t iops_avg_time;
@@ -494,6 +502,7 @@ struct thread_options_pack {
 	uint64_t trim_backlog;
 	uint32_t clat_percentiles;
 	uint32_t percentile_precision;
+	uint32_t padding;	/* REMOVE ME when possible to maintain alignment */
 	fio_fp64_t percentile_list[FIO_IO_U_LIST_MAX_LEN];
 
 	uint8_t read_iolog_file[FIO_TOP_STR_MAX];
unit_tests/steadystate_tests.py new file +222 -0

222 lines not on this page · raw message