Recent changes (master)
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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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