tiobench: ensure that ioengine is being specified
[fio.git] / profiles / act.c
CommitLineData
d4afedfd
JA
1#include "../fio.h"
2#include "../profile.h"
3#include "../parse.h"
4
00f81c37
JA
5/*
6 * 1x loads
7 */
d4afedfd
JA
8#define R_LOAD 2000
9#define W_LOAD 1000
10
11#define SAMPLE_SEC 3600 /* 1h checks */
12
13struct act_pass_criteria {
14 unsigned int max_usec;
15 unsigned int max_perm;
16};
17#define ACT_MAX_CRIT 3
18
19static struct act_pass_criteria act_pass[ACT_MAX_CRIT] = {
20 {
21 .max_usec = 1000,
22 .max_perm = 50,
23 },
24 {
78a6aad7 25 .max_usec = 8000,
d4afedfd
JA
26 .max_perm = 10,
27 },
28 {
29 .max_usec = 64000,
30 .max_perm = 1,
31 },
32};
33
4a88752a
JA
34struct act_run_data {
35 struct fio_mutex *mutex;
36 unsigned int pending;
37
38 uint64_t lat_buckets[ACT_MAX_CRIT];
39 uint64_t total_ios;
40};
41static struct act_run_data *act_run_data;
42
d4afedfd
JA
43struct act_prof_data {
44 struct timeval sample_tv;
45 uint64_t lat_buckets[ACT_MAX_CRIT];
46 uint64_t total_ios;
4a88752a
JA
47 uint64_t cum_lat_buckets[ACT_MAX_CRIT];
48 uint64_t cum_total_ios;
d4afedfd
JA
49};
50
51static char *device_names;
52static unsigned int load = 1;
00f81c37
JA
53static unsigned int prep;
54static unsigned int threads_per_queue;
55static unsigned int num_read_blocks;
56static unsigned int write_size;
d4afedfd 57
00f81c37
JA
58#define ACT_MAX_OPTS 128
59static const char *act_opts[ACT_MAX_OPTS] = {
d4afedfd 60 "direct=1",
00f81c37 61 "ioengine=sync",
d4afedfd 62 "random_generator=lfsr",
00f81c37 63 "group_reporting=1",
4a88752a 64 "thread",
d4afedfd
JA
65 NULL,
66};
4a88752a 67static unsigned int opt_idx = 5;
d4afedfd
JA
68static unsigned int org_idx;
69
00f81c37 70static int act_add_opt(const char *format, ...) __attribute__ ((__format__ (__printf__, 1, 2)));
d4afedfd
JA
71
72static struct fio_option options[] = {
73 {
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,
81 },
82 {
83 .name = "load",
84 .lname = "Load multiplier",
85 .type = FIO_OPT_INT,
86 .roff1 = &load,
87 .help = "ACT load multipler (default 1x)",
00f81c37
JA
88 .def = "1",
89 .category = FIO_OPT_C_PROFILE,
90 .group = FIO_OPT_G_ACT,
91 },
92 {
93 .name = "threads-per-queue",
94 .lname = "Number of read IO threads per device",
95 .type = FIO_OPT_INT,
96 .roff1 = &threads_per_queue,
97 .help = "Number of read IO threads per device",
98 .def = "8",
99 .category = FIO_OPT_C_PROFILE,
100 .group = FIO_OPT_G_ACT,
101 },
102 {
103 .name = "read-req-num-512-blocks",
104 .lname = "Number of 512b blocks to read",
105 .type = FIO_OPT_INT,
106 .roff1 = &num_read_blocks,
107 .help = "Number of 512b blocks to read at the time",
108 .def = "3",
109 .category = FIO_OPT_C_PROFILE,
110 .group = FIO_OPT_G_ACT,
111 },
112 {
113 .name = "large-block-op-kbytes",
114 .lname = "Size of large block ops (writes)",
115 .type = FIO_OPT_INT,
116 .roff1 = &write_size,
117 .help = "Size of large block ops (writes)",
118 .def = "128k",
119 .category = FIO_OPT_C_PROFILE,
120 .group = FIO_OPT_G_ACT,
121 },
122 {
123 .name = "prep",
124 .lname = "Run ACT prep phase",
125 .type = FIO_OPT_STR_SET,
126 .roff1 = &prep,
127 .help = "Set to run ACT prep phase",
d4afedfd
JA
128 .category = FIO_OPT_C_PROFILE,
129 .group = FIO_OPT_G_ACT,
130 },
131 {
132 .name = NULL,
133 },
134};
135
00f81c37 136static int act_add_opt(const char *str, ...)
d4afedfd
JA
137{
138 char buffer[512];
139 va_list args;
140 size_t len;
141
00f81c37
JA
142 if (opt_idx == ACT_MAX_OPTS) {
143 log_err("act: ACT_MAX_OPTS is too small\n");
144 return 1;
145 }
146
d4afedfd
JA
147 va_start(args, str);
148 len = vsnprintf(buffer, sizeof(buffer), str, args);
149 va_end(args);
150
151 if (len)
152 act_opts[opt_idx++] = strdup(buffer);
00f81c37
JA
153
154 return 0;
155}
156
157static int act_add_rw(const char *dev, int reads)
158{
159 if (act_add_opt("name=act-%s-%s", reads ? "read" : "write", dev))
160 return 1;
161 if (act_add_opt("filename=%s", dev))
162 return 1;
163 if (act_add_opt("rw=%s", reads ? "randread" : "randwrite"))
164 return 1;
165 if (reads) {
166 int rload = load * R_LOAD / threads_per_queue;
167
168 if (act_add_opt("numjobs=%u", threads_per_queue))
169 return 1;
170 if (act_add_opt("rate_iops=%u", rload))
171 return 1;
172 if (act_add_opt("bs=%u", num_read_blocks * 512))
173 return 1;
174 } else {
175 const int rsize = write_size / (num_read_blocks * 512);
176 int wload = (load * W_LOAD + rsize - 1) / rsize;
177
178 if (act_add_opt("rate_iops=%u", wload))
179 return 1;
180 if (act_add_opt("bs=%u", write_size))
181 return 1;
182 }
183
184 return 0;
185}
186
187static int act_add_dev_prep(const char *dev)
188{
189 /* Add sequential zero phase */
190 if (act_add_opt("name=act-prep-zeroes-%s", dev))
191 return 1;
192 if (act_add_opt("filename=%s", dev))
193 return 1;
194 if (act_add_opt("bs=1M"))
195 return 1;
196 if (act_add_opt("zero_buffers"))
197 return 1;
198 if (act_add_opt("rw=write"))
199 return 1;
200
201 /* Randomly overwrite device */
202 if (act_add_opt("name=act-prep-salt-%s", dev))
203 return 1;
204 if (act_add_opt("stonewall"))
205 return 1;
206 if (act_add_opt("filename=%s", dev))
207 return 1;
208 if (act_add_opt("bs=4k"))
209 return 1;
210 if (act_add_opt("ioengine=libaio"))
211 return 1;
212 if (act_add_opt("iodepth=64"))
213 return 1;
214 if (act_add_opt("rw=randwrite"))
215 return 1;
216
217 return 0;
d4afedfd
JA
218}
219
00f81c37 220static int act_add_dev(const char *dev)
d4afedfd 221{
00f81c37
JA
222 if (prep)
223 return act_add_dev_prep(dev);
224
225 if (act_add_opt("runtime=24h"))
226 return 1;
227 if (act_add_opt("time_based=1"))
228 return 1;
229
230 if (act_add_rw(dev, 1))
231 return 1;
232 if (act_add_rw(dev, 0))
233 return 1;
234
235 return 0;
d4afedfd
JA
236}
237
238/*
239 * Fill our private options into the command line
240 */
241static int act_prep_cmdline(void)
242{
243 if (!device_names) {
244 log_err("act: need device-names\n");
245 return 1;
246 }
247
248 org_idx = opt_idx;
d4afedfd
JA
249
250 do {
251 char *dev;
252
253 dev = strsep(&device_names, ",");
254 if (!dev)
255 break;
256
00f81c37
JA
257 if (act_add_dev(dev)) {
258 log_err("act: failed adding device to the mix\n");
259 break;
260 }
d4afedfd
JA
261 } while (1);
262
263 return 0;
264}
265
266static int act_io_u_lat(struct thread_data *td, uint64_t usec)
267{
268 struct act_prof_data *apd = td->prof_data;
269 int i, ret = 0;
270 double perm;
271
00f81c37
JA
272 if (prep)
273 return 0;
274
d4afedfd
JA
275 apd->total_ios++;
276
78a6aad7
JA
277 for (i = ACT_MAX_CRIT - 1; i >= 0; i--) {
278 if (usec > act_pass[i].max_usec) {
d4afedfd
JA
279 apd->lat_buckets[i]++;
280 break;
281 }
282 }
283
d4afedfd
JA
284 if (time_since_now(&apd->sample_tv) < SAMPLE_SEC)
285 return 0;
286
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;
78a6aad7 290 if (perm < act_pass[i].max_perm)
d4afedfd
JA
291 continue;
292
293 log_err("act: %f%% exceeds pass criteria of %f%%\n", perm / 10.0, (double) act_pass[i].max_perm / 10.0);
294 ret = 1;
295 break;
296 }
297
4a88752a
JA
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;
301 }
302
303 apd->cum_total_ios += apd->total_ios;
78a6aad7
JA
304 apd->total_ios = 0;
305
d4afedfd
JA
306 fio_gettime(&apd->sample_tv, NULL);
307 return ret;
308}
309
4a88752a
JA
310static void get_act_ref(void)
311{
312 fio_mutex_down(act_run_data->mutex);
313 act_run_data->pending++;
314 fio_mutex_up(act_run_data->mutex);
315}
316
317static void act_show_all_stats(void)
318{
319 unsigned int i;
320
321 log_info(" trans device\n");
322 log_info(" %%>(ms) %%>(ms)\n");
323 log_info(" slice");
324
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);
329
330 log_info("\n");
331 log_info(" ----- ------ ------ ------ ------ ------ ------\n");
332 log_info(" 1");
333
334 for (i = 0; i < ACT_MAX_CRIT; i++) {
335 double perc;
336
337 perc = 100.0 * (double) act_run_data->lat_buckets[i] / (double) act_run_data->total_ios;
338 log_info("\t%2.2f", perc);
339 }
340 for (i = 0; i < ACT_MAX_CRIT; i++) {
341 double perc;
342
343 perc = 100.0 * (double) act_run_data->lat_buckets[i] / (double) act_run_data->total_ios;
344 log_info("\t%2.2f", perc);
345 }
346
347}
348
349static void put_act_ref(struct thread_data *td)
350{
351 struct act_prof_data *apd = td->prof_data;
352 unsigned int i;
353
354 fio_mutex_down(act_run_data->mutex);
355
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];
359 }
360
361 act_run_data->total_ios += apd->cum_total_ios + apd->total_ios;
362
363 if (!--act_run_data->pending)
364 act_show_all_stats();
365
366 fio_mutex_up(act_run_data->mutex);
367}
368
d4afedfd
JA
369static int act_td_init(struct thread_data *td)
370{
371 struct act_prof_data *apd;
372
4a88752a
JA
373 get_act_ref();
374
d4afedfd
JA
375 apd = calloc(sizeof(*apd), 1);
376 fio_gettime(&apd->sample_tv, NULL);
377 td->prof_data = apd;
378 return 0;
379}
380
381static void act_td_exit(struct thread_data *td)
382{
4a88752a 383 put_act_ref(td);
d4afedfd
JA
384 free(td->prof_data);
385 td->prof_data = NULL;
386}
387
388static 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,
392};
393
394static struct profile_ops act_profile = {
395 .name = "act",
396 .desc = "ACT Aerospike like benchmark",
397 .options = options,
398 .prep_cmd = act_prep_cmdline,
399 .cmdline = act_opts,
400 .io_ops = &act_io_ops,
401};
402
403static void fio_init act_register(void)
404{
4a88752a
JA
405 act_run_data = calloc(sizeof(*act_run_data), 1);
406 act_run_data->mutex = fio_mutex_init(FIO_MUTEX_UNLOCKED);
407
d4afedfd
JA
408 if (register_profile(&act_profile))
409 log_err("fio: failed to register profile 'act'\n");
410}
411
412static void fio_exit act_unregister(void)
413{
414 while (org_idx && org_idx < opt_idx)
415 free((void *) act_opts[++org_idx]);
416
417 unregister_profile(&act_profile);
4a88752a
JA
418 fio_mutex_remove(act_run_data->mutex);
419 free(act_run_data);
420 act_run_data = NULL;
d4afedfd 421}