2 #include "../profile.h"
11 #define SAMPLE_SEC 3600 /* 1h checks */
13 struct act_pass_criteria {
14 unsigned int max_usec;
15 unsigned int max_perm;
17 #define ACT_MAX_CRIT 3
19 static struct act_pass_criteria act_pass[ACT_MAX_CRIT] = {
35 struct fio_mutex *mutex;
38 uint64_t lat_buckets[ACT_MAX_CRIT];
41 static struct act_run_data *act_run_data;
43 struct act_prof_data {
44 struct timeval sample_tv;
45 uint64_t lat_buckets[ACT_MAX_CRIT];
47 uint64_t cum_lat_buckets[ACT_MAX_CRIT];
48 uint64_t cum_total_ios;
51 static char *device_names;
52 static unsigned int load = 1;
53 static unsigned int prep;
54 static unsigned int threads_per_queue;
55 static unsigned int num_read_blocks;
56 static unsigned int write_size;
58 #define ACT_MAX_OPTS 128
59 static const char *act_opts[ACT_MAX_OPTS] = {
62 "random_generator=lfsr",
67 static unsigned int opt_idx = 5;
68 static unsigned int org_idx;
70 static int act_add_opt(const char *format, ...) __attribute__ ((__format__ (__printf__, 1, 2)));
72 static struct fio_option options[] = {
74 .name = "device-names",
75 .lname = "device-names",
76 .type = FIO_OPT_STR_STORE,
77 .roff1 = &device_names,
78 .help = "Devices to use",
79 .category = FIO_OPT_C_PROFILE,
80 .group = FIO_OPT_G_ACT,
84 .lname = "Load multiplier",
87 .help = "ACT load multipler (default 1x)",
89 .category = FIO_OPT_C_PROFILE,
90 .group = FIO_OPT_G_ACT,
93 .name = "threads-per-queue",
94 .lname = "Number of read IO threads per device",
96 .roff1 = &threads_per_queue,
97 .help = "Number of read IO threads per device",
99 .category = FIO_OPT_C_PROFILE,
100 .group = FIO_OPT_G_ACT,
103 .name = "read-req-num-512-blocks",
104 .lname = "Number of 512b blocks to read",
106 .roff1 = &num_read_blocks,
107 .help = "Number of 512b blocks to read at the time",
109 .category = FIO_OPT_C_PROFILE,
110 .group = FIO_OPT_G_ACT,
113 .name = "large-block-op-kbytes",
114 .lname = "Size of large block ops (writes)",
116 .roff1 = &write_size,
117 .help = "Size of large block ops (writes)",
119 .category = FIO_OPT_C_PROFILE,
120 .group = FIO_OPT_G_ACT,
124 .lname = "Run ACT prep phase",
125 .type = FIO_OPT_STR_SET,
127 .help = "Set to run ACT prep phase",
128 .category = FIO_OPT_C_PROFILE,
129 .group = FIO_OPT_G_ACT,
136 static int act_add_opt(const char *str, ...)
142 if (opt_idx == ACT_MAX_OPTS) {
143 log_err("act: ACT_MAX_OPTS is too small\n");
148 len = vsnprintf(buffer, sizeof(buffer), str, args);
152 act_opts[opt_idx++] = strdup(buffer);
157 static int act_add_rw(const char *dev, int reads)
159 if (act_add_opt("name=act-%s-%s", reads ? "read" : "write", dev))
161 if (act_add_opt("filename=%s", dev))
163 if (act_add_opt("rw=%s", reads ? "randread" : "randwrite"))
166 int rload = load * R_LOAD / threads_per_queue;
168 if (act_add_opt("numjobs=%u", threads_per_queue))
170 if (act_add_opt("rate_iops=%u", rload))
172 if (act_add_opt("bs=%u", num_read_blocks * 512))
175 const int rsize = write_size / (num_read_blocks * 512);
176 int wload = (load * W_LOAD + rsize - 1) / rsize;
178 if (act_add_opt("rate_iops=%u", wload))
180 if (act_add_opt("bs=%u", write_size))
187 static int act_add_dev_prep(const char *dev)
189 /* Add sequential zero phase */
190 if (act_add_opt("name=act-prep-zeroes-%s", dev))
192 if (act_add_opt("filename=%s", dev))
194 if (act_add_opt("bs=1M"))
196 if (act_add_opt("zero_buffers"))
198 if (act_add_opt("rw=write"))
201 /* Randomly overwrite device */
202 if (act_add_opt("name=act-prep-salt-%s", dev))
204 if (act_add_opt("stonewall"))
206 if (act_add_opt("filename=%s", dev))
208 if (act_add_opt("bs=4k"))
210 if (act_add_opt("ioengine=libaio"))
212 if (act_add_opt("iodepth=64"))
214 if (act_add_opt("rw=randwrite"))
220 static int act_add_dev(const char *dev)
223 return act_add_dev_prep(dev);
225 if (act_add_opt("runtime=24h"))
227 if (act_add_opt("time_based=1"))
230 if (act_add_rw(dev, 1))
232 if (act_add_rw(dev, 0))
239 * Fill our private options into the command line
241 static int act_prep_cmdline(void)
244 log_err("act: need device-names\n");
253 dev = strsep(&device_names, ",");
257 if (act_add_dev(dev)) {
258 log_err("act: failed adding device to the mix\n");
266 static int act_io_u_lat(struct thread_data *td, uint64_t usec)
268 struct act_prof_data *apd = td->prof_data;
277 for (i = ACT_MAX_CRIT - 1; i >= 0; i--) {
278 if (usec > act_pass[i].max_usec) {
279 apd->lat_buckets[i]++;
284 if (time_since_now(&apd->sample_tv) < SAMPLE_SEC)
287 /* SAMPLE_SEC has passed, check criteria for pass */
288 for (i = 0; i < ACT_MAX_CRIT; i++) {
289 perm = (1000.0 * apd->lat_buckets[i]) / apd->total_ios;
290 if (perm < act_pass[i].max_perm)
293 log_err("act: %f%% exceeds pass criteria of %f%%\n", perm / 10.0, (double) act_pass[i].max_perm / 10.0);
298 for (i = 0; i < ACT_MAX_CRIT; i++) {
299 apd->cum_lat_buckets[i] += apd->lat_buckets[i];
300 apd->lat_buckets[i] = 0;
303 apd->cum_total_ios += apd->total_ios;
306 fio_gettime(&apd->sample_tv, NULL);
310 static void get_act_ref(void)
312 fio_mutex_down(act_run_data->mutex);
313 act_run_data->pending++;
314 fio_mutex_up(act_run_data->mutex);
317 static void act_show_all_stats(void)
321 log_info(" trans device\n");
322 log_info(" %%>(ms) %%>(ms)\n");
325 for (i = 0; i < ACT_MAX_CRIT; i++)
326 log_info("\t%2u", act_pass[i].max_usec / 1000);
327 for (i = 0; i < ACT_MAX_CRIT; i++)
328 log_info("\t%2u", act_pass[i].max_usec / 1000);
331 log_info(" ----- ------ ------ ------ ------ ------ ------\n");
334 for (i = 0; i < ACT_MAX_CRIT; i++) {
337 perc = 100.0 * (double) act_run_data->lat_buckets[i] / (double) act_run_data->total_ios;
338 log_info("\t%2.2f", perc);
340 for (i = 0; i < ACT_MAX_CRIT; i++) {
343 perc = 100.0 * (double) act_run_data->lat_buckets[i] / (double) act_run_data->total_ios;
344 log_info("\t%2.2f", perc);
349 static void put_act_ref(struct thread_data *td)
351 struct act_prof_data *apd = td->prof_data;
354 fio_mutex_down(act_run_data->mutex);
356 for (i = 0; i < ACT_MAX_CRIT; i++) {
357 act_run_data->lat_buckets[i] += apd->cum_lat_buckets[i];
358 act_run_data->lat_buckets[i] += apd->lat_buckets[i];
361 act_run_data->total_ios += apd->cum_total_ios + apd->total_ios;
363 if (!--act_run_data->pending)
364 act_show_all_stats();
366 fio_mutex_up(act_run_data->mutex);
369 static int act_td_init(struct thread_data *td)
371 struct act_prof_data *apd;
375 apd = calloc(sizeof(*apd), 1);
376 fio_gettime(&apd->sample_tv, NULL);
381 static void act_td_exit(struct thread_data *td)
385 td->prof_data = NULL;
388 static struct prof_io_ops act_io_ops = {
389 .td_init = act_td_init,
390 .td_exit = act_td_exit,
391 .io_u_lat = act_io_u_lat,
394 static struct profile_ops act_profile = {
396 .desc = "ACT Aerospike like benchmark",
398 .prep_cmd = act_prep_cmdline,
400 .io_ops = &act_io_ops,
403 static void fio_init act_register(void)
405 act_run_data = calloc(sizeof(*act_run_data), 1);
406 act_run_data->mutex = fio_mutex_init(FIO_MUTEX_UNLOCKED);
408 if (register_profile(&act_profile))
409 log_err("fio: failed to register profile 'act'\n");
412 static void fio_exit act_unregister(void)
414 while (org_idx && org_idx < opt_idx)
415 free((void *) act_opts[++org_idx]);
417 unregister_profile(&act_profile);
418 fio_mutex_remove(act_run_data->mutex);