#include "profile.h"
#include "time.h"
#include "lib/getopt.h"
+#include "lib/rand.h"
#ifdef FIO_HAVE_GUASI
#include <guasi.h>
#define FIO_IO_U_LAT_U_NR 10
#define FIO_IO_U_LAT_M_NR 12
+/*
+ * Aggregate clat samples to report percentile(s) of them.
+ *
+ * EXECUTIVE SUMMARY
+ *
+ * FIO_IO_U_PLAT_BITS determines the maximum statistical error on the
+ * value of resulting percentiles. The error will be approximately
+ * 1/2^(FIO_IO_U_PLAT_BITS+1) of the value.
+ *
+ * FIO_IO_U_PLAT_GROUP_NR and FIO_IO_U_PLAT_BITS determine the maximum
+ * range being tracked for latency samples. The maximum value tracked
+ * accurately will be 2^(GROUP_NR + PLAT_BITS -1) microseconds.
+ *
+ * FIO_IO_U_PLAT_GROUP_NR and FIO_IO_U_PLAT_BITS determine the memory
+ * requirement of storing those aggregate counts. The memory used will
+ * be (FIO_IO_U_PLAT_GROUP_NR * 2^FIO_IO_U_PLAT_BITS) * sizeof(int)
+ * bytes.
+ *
+ * FIO_IO_U_PLAT_NR is the total number of buckets.
+ *
+ * DETAILS
+ *
+ * Suppose the clat varies from 0 to 999 (usec), the straightforward
+ * method is to keep an array of (999 + 1) buckets, in which a counter
+ * keeps the count of samples which fall in the bucket, e.g.,
+ * {[0],[1],...,[999]}. However this consumes a huge amount of space,
+ * and can be avoided if an approximation is acceptable.
+ *
+ * One such method is to let the range of the bucket to be greater
+ * than one. This method has low accuracy when the value is small. For
+ * example, let the buckets be {[0,99],[100,199],...,[900,999]}, and
+ * the represented value of each bucket be the mean of the range. Then
+ * a value 0 has an round-off error of 49.5. To improve on this, we
+ * use buckets with non-uniform ranges, while bounding the error of
+ * each bucket within a ratio of the sample value. A simple example
+ * would be when error_bound = 0.005, buckets are {
+ * {[0],[1],...,[99]}, {[100,101],[102,103],...,[198,199]},..,
+ * {[900,909],[910,919]...} }. The total range is partitioned into
+ * groups with different ranges, then buckets with uniform ranges. An
+ * upper bound of the error is (range_of_bucket/2)/value_of_bucket
+ *
+ * For better efficiency, we implement this using base two. We group
+ * samples by their Most Significant Bit (MSB), extract the next M bit
+ * of them as an index within the group, and discard the rest of the
+ * bits.
+ *
+ * E.g., assume a sample 'x' whose MSB is bit n (starting from bit 0),
+ * and use M bit for indexing
+ *
+ * | n | M bits | bit (n-M-1) ... bit 0 |
+ *
+ * Because x is at least 2^n, and bit 0 to bit (n-M-1) is at most
+ * (2^(n-M) - 1), discarding bit 0 to (n-M-1) makes the round-off
+ * error
+ *
+ * 2^(n-M)-1 2^(n-M) 1
+ * e <= --------- <= ------- = ---
+ * 2^n 2^n 2^M
+ *
+ * Furthermore, we use "mean" of the range to represent the bucket,
+ * the error e can be lowered by half to 1 / 2^(M+1). By using M bits
+ * as the index, each group must contains 2^M buckets.
+ *
+ * E.g. Let M (FIO_IO_U_PLAT_BITS) be 6
+ * Error bound is 1/2^(6+1) = 0.0078125 (< 1%)
+ *
+ * Group MSB #discarded range of #buckets
+ * error_bits value
+ * ----------------------------------------------------------------
+ * 0* 0~5 0 [0,63] 64
+ * 1* 6 0 [64,127] 64
+ * 2 7 1 [128,255] 64
+ * 3 8 2 [256,511] 64
+ * 4 9 3 [512,1023] 64
+ * ... ... ... [...,...] ...
+ * 18 23 17 [8838608,+inf]** 64
+ *
+ * * Special cases: when n < (M-1) or when n == (M-1), in both cases,
+ * the value cannot be rounded off. Use all bits of the sample as
+ * index.
+ *
+ * ** If a sample's MSB is greater than 23, it will be counted as 23.
+ */
+
+#define FIO_IO_U_PLAT_BITS 6
+#define FIO_IO_U_PLAT_VAL (1 << FIO_IO_U_PLAT_BITS)
+#define FIO_IO_U_PLAT_GROUP_NR 19
+#define FIO_IO_U_PLAT_NR (FIO_IO_U_PLAT_GROUP_NR * FIO_IO_U_PLAT_VAL)
+#define FIO_IO_U_LIST_MAX_LEN 20 /* The size of the default and user-specified
+ list of percentiles */
+
#define MAX_PATTERN_SIZE 512
struct thread_stat {
/*
* IO depth and latency stats
*/
+ unsigned int clat_percentiles;
+ double* percentile_list;
+
unsigned int io_u_map[FIO_IO_U_MAP_NR];
unsigned int io_u_submit[FIO_IO_U_MAP_NR];
unsigned int io_u_complete[FIO_IO_U_MAP_NR];
unsigned int io_u_lat_u[FIO_IO_U_LAT_U_NR];
unsigned int io_u_lat_m[FIO_IO_U_LAT_M_NR];
+ unsigned int io_u_plat[2][FIO_IO_U_PLAT_NR];
unsigned long total_io_u[3];
unsigned long short_io_u[3];
unsigned long total_submit;
unsigned int rw_seq;
unsigned int kb_base;
unsigned int ddir_seq_nr;
+ long ddir_seq_add;
unsigned int iodepth;
unsigned int iodepth_low;
unsigned int iodepth_batch;
unsigned int iodepth_batch_complete;
unsigned long long size;
+ unsigned int size_percent;
unsigned int fill_device;
unsigned long long file_size_low;
unsigned long long file_size_high;
char verify_pattern[MAX_PATTERN_SIZE];
unsigned int verify_pattern_bytes;
unsigned int verify_fatal;
+ unsigned int verify_dump;
unsigned int verify_async;
unsigned long long verify_backlog;
unsigned int verify_batch;
unsigned int do_disk_util;
unsigned int override_sync;
unsigned int rand_repeatable;
+ unsigned int use_os_rand;
unsigned int write_lat_log;
unsigned int write_bw_log;
unsigned int norandommap;
unsigned int fsync_blocks;
unsigned int fdatasync_blocks;
unsigned int barrier_blocks;
- unsigned long start_delay;
+ unsigned long long start_delay;
unsigned long long timeout;
unsigned long long ramp_time;
unsigned int overwrite;
unsigned int file_service_type;
unsigned int group_reporting;
unsigned int fadvise_hint;
- unsigned int fallocate;
+ enum fio_fallocate_mode fallocate_mode;
unsigned int zero_buffers;
unsigned int refill_buffers;
+ unsigned int scramble_buffers;
unsigned int time_based;
unsigned int disable_lat;
unsigned int disable_clat;
unsigned int trim_batch;
unsigned int trim_zero;
unsigned long long trim_backlog;
+ unsigned int clat_percentiles;
+ unsigned int overwrite_plist;
+ double percentile_list[FIO_IO_U_LIST_MAX_LEN];
char *read_iolog_file;
char *write_iolog_file;
unsigned int gid;
unsigned int sync_file_range;
+
+ unsigned int userspace_libaio_reap;
};
#define FIO_VERROR_SIZE 128
union {
unsigned int next_file;
os_random_state_t next_file_state;
+ struct frand_state __next_file_state;
};
int error;
int done;
char *sysfs_root;
- unsigned long rand_seeds[7];
+ unsigned long rand_seeds[8];
- os_random_state_t bsrange_state;
- os_random_state_t verify_state;
- os_random_state_t trim_state;
+ union {
+ os_random_state_t bsrange_state;
+ struct frand_state __bsrange_state;
+ };
+ union {
+ os_random_state_t verify_state;
+ struct frand_state __verify_state;
+ };
+ union {
+ os_random_state_t trim_state;
+ struct frand_state __trim_state;
+ };
+
+ struct frand_state buf_state;
unsigned int verify_batch;
unsigned int trim_batch;
/*
* State for random io, a bitmap of blocks done vs not done
*/
- os_random_state_t random_state;
+ union {
+ os_random_state_t random_state;
+ struct frand_state __random_state;
+ };
struct timeval start; /* start of this loop */
struct timeval epoch; /* time job was started */
/*
* read/write mixed workload state
*/
- os_random_state_t rwmix_state;
+ union {
+ os_random_state_t rwmix_state;
+ struct frand_state __rwmix_state;
+ };
unsigned long rwmix_issues;
enum fio_ddir rwmix_ddir;
unsigned int ddir_seq_nr;
/*
* For generating file sizes
*/
- os_random_state_t file_size_state;
+ union {
+ os_random_state_t file_size_state;
+ struct frand_state __file_size_state;
+ };
/*
* Error counts
extern int fio_gtod_offload;
extern int fio_gtod_cpu;
extern enum fio_cs fio_clock_source;
+extern int warnings_fatal;
+extern int terse_version;
extern struct thread_data *threads;
assert(!(io_u->ddir == DDIR_WRITE && !td_write(td)));
}
-#define BLOCKS_PER_MAP (8 * sizeof(int))
+#define BLOCKS_PER_MAP (8 * sizeof(unsigned long))
#define TO_MAP_BLOCK(f, b) (b)
#define RAND_MAP_IDX(f, b) (TO_MAP_BLOCK(f, b) / BLOCKS_PER_MAP)
#define RAND_MAP_BIT(f, b) (TO_MAP_BLOCK(f, b) & (BLOCKS_PER_MAP - 1))
-#define MAX_JOBS (1024)
+#define REAL_MAX_JOBS 2048
#define td_non_fatal_error(e) ((e) == EIO || (e) == EILSEQ)
* Init/option functions
*/
extern int __must_check parse_options(int, char **);
+extern int parse_jobs_ini(char *, int, int);
+extern int exec_run(void);
+extern void reset_fio_state(void);
extern int fio_options_parse(struct thread_data *, char **, int);
extern void fio_keywords_init(void);
extern int fio_cmd_option_parse(struct thread_data *, const char *, char *);
if (!(cond)) { \
int *__foo = NULL; \
fprintf(stderr, "file:%s:%d, assert %s failed\n", __FILE__, __LINE__, #cond); \
- (td)->runstate = TD_EXITED; \
+ td_set_runstate((td), TD_EXITED); \
(td)->error = EFAULT; \
*__foo = 0; \
} \