Home | History | Annotate | Download | only in profiles
      1 #include "../fio.h"
      2 #include "../profile.h"
      3 #include "../parse.h"
      4 
      5 /*
      6  * 1x loads
      7  */
      8 #define R_LOAD		2000
      9 #define W_LOAD		1000
     10 
     11 #define SAMPLE_SEC	3600		/* 1h checks */
     12 
     13 struct act_pass_criteria {
     14 	unsigned int max_usec;
     15 	unsigned int max_perm;
     16 };
     17 #define ACT_MAX_CRIT	3
     18 
     19 static struct act_pass_criteria act_pass[ACT_MAX_CRIT] = {
     20 	{
     21 		.max_usec =	1000,
     22 		.max_perm =	50,
     23 	},
     24 	{
     25 		.max_usec =	8000,
     26 		.max_perm =	10,
     27 	},
     28 	{
     29 		.max_usec = 	64000,
     30 		.max_perm =	1,
     31 	},
     32 };
     33 
     34 struct act_slice {
     35 	uint64_t lat_buckets[ACT_MAX_CRIT];
     36 	uint64_t total_ios;
     37 };
     38 
     39 struct act_run_data {
     40 	struct fio_mutex *mutex;
     41 	unsigned int pending;
     42 
     43 	struct act_slice *slices;
     44 	unsigned int nr_slices;
     45 };
     46 static struct act_run_data *act_run_data;
     47 
     48 struct act_prof_data {
     49 	struct timeval sample_tv;
     50 	struct act_slice *slices;
     51 	unsigned int cur_slice;
     52 	unsigned int nr_slices;
     53 };
     54 
     55 static char *device_names;
     56 static unsigned int load;
     57 static unsigned int prep;
     58 static unsigned int threads_per_queue;
     59 static unsigned int num_read_blocks;
     60 static unsigned int write_size;
     61 static unsigned long long test_duration;
     62 
     63 #define ACT_MAX_OPTS	128
     64 static const char *act_opts[ACT_MAX_OPTS] = {
     65 	"direct=1",
     66 	"ioengine=sync",
     67 	"random_generator=lfsr",
     68 	"group_reporting=1",
     69 	"thread",
     70 	NULL,
     71 };
     72 static unsigned int opt_idx = 5;
     73 static unsigned int org_idx;
     74 
     75 static int act_add_opt(const char *format, ...) __attribute__ ((__format__ (__printf__, 1, 2)));
     76 
     77 struct act_options {
     78 	unsigned int pad;
     79 	char *device_names;
     80 	unsigned int load;
     81 	unsigned int prep;
     82 	unsigned int threads_per_queue;
     83 	unsigned int num_read_blocks;
     84 	unsigned int write_size;
     85 	unsigned long long test_duration;
     86 };
     87 
     88 static struct act_options act_options;
     89 
     90 static struct fio_option options[] = {
     91 	{
     92 		.name	= "device-names",
     93 		.lname	= "device-names",
     94 		.type	= FIO_OPT_STR_STORE,
     95 		.off1	= offsetof(struct act_options, device_names),
     96 		.help	= "Devices to use",
     97 		.category = FIO_OPT_C_PROFILE,
     98 		.group	= FIO_OPT_G_ACT,
     99 	},
    100 	{
    101 		.name	= "load",
    102 		.lname	= "Load multiplier",
    103 		.type	= FIO_OPT_INT,
    104 		.off1	= offsetof(struct act_options, load),
    105 		.help	= "ACT load multipler (default 1x)",
    106 		.def	= "1",
    107 		.category = FIO_OPT_C_PROFILE,
    108 		.group	= FIO_OPT_G_ACT,
    109 	},
    110 	{
    111 		.name	= "test-duration",
    112 		.lname	= "Test duration",
    113 		.type	= FIO_OPT_STR_VAL_TIME,
    114 		.off1	= offsetof(struct act_options, test_duration),
    115 		.help	= "How long the entire test takes to run",
    116 		.def	= "24h",
    117 		.category = FIO_OPT_C_PROFILE,
    118 		.group	= FIO_OPT_G_ACT,
    119 	},
    120 	{
    121 		.name	= "threads-per-queue",
    122 		.lname	= "Number of read IO threads per device",
    123 		.type	= FIO_OPT_INT,
    124 		.off1	= offsetof(struct act_options, threads_per_queue),
    125 		.help	= "Number of read IO threads per device",
    126 		.def	= "8",
    127 		.category = FIO_OPT_C_PROFILE,
    128 		.group	= FIO_OPT_G_ACT,
    129 	},
    130 	{
    131 		.name	= "read-req-num-512-blocks",
    132 		.lname	= "Number of 512b blocks to read",
    133 		.type	= FIO_OPT_INT,
    134 		.off1	= offsetof(struct act_options, num_read_blocks),
    135 		.help	= "Number of 512b blocks to read at the time",
    136 		.def	= "3",
    137 		.category = FIO_OPT_C_PROFILE,
    138 		.group	= FIO_OPT_G_ACT,
    139 	},
    140 	{
    141 		.name	= "large-block-op-kbytes",
    142 		.lname	= "Size of large block ops (writes)",
    143 		.type	= FIO_OPT_INT,
    144 		.off1	= offsetof(struct act_options, write_size),
    145 		.help	= "Size of large block ops (writes)",
    146 		.def	= "128k",
    147 		.category = FIO_OPT_C_PROFILE,
    148 		.group	= FIO_OPT_G_ACT,
    149 	},
    150 	{
    151 		.name	= "prep",
    152 		.lname	= "Run ACT prep phase",
    153 		.type	= FIO_OPT_STR_SET,
    154 		.off1	= offsetof(struct act_options, prep),
    155 		.help	= "Set to run ACT prep phase",
    156 		.category = FIO_OPT_C_PROFILE,
    157 		.group	= FIO_OPT_G_ACT,
    158 	},
    159 	{
    160 		.name	= NULL,
    161 	},
    162 };
    163 
    164 static int act_add_opt(const char *str, ...)
    165 {
    166 	char buffer[512];
    167 	va_list args;
    168 	size_t len;
    169 
    170 	if (opt_idx == ACT_MAX_OPTS) {
    171 		log_err("act: ACT_MAX_OPTS is too small\n");
    172 		return 1;
    173 	}
    174 
    175 	va_start(args, str);
    176 	len = vsnprintf(buffer, sizeof(buffer), str, args);
    177 	va_end(args);
    178 
    179 	if (len)
    180 		act_opts[opt_idx++] = strdup(buffer);
    181 
    182 	return 0;
    183 }
    184 
    185 static int act_add_rw(const char *dev, int reads)
    186 {
    187 	if (act_add_opt("name=act-%s-%s", reads ? "read" : "write", dev))
    188 		return 1;
    189 	if (act_add_opt("filename=%s", dev))
    190 		return 1;
    191 	if (act_add_opt("rw=%s", reads ? "randread" : "randwrite"))
    192 		return 1;
    193 	if (reads) {
    194 		int rload = load * R_LOAD / threads_per_queue;
    195 
    196 		if (act_add_opt("numjobs=%u", threads_per_queue))
    197 			return 1;
    198 		if (act_add_opt("rate_iops=%u", rload))
    199 			return 1;
    200 		if (act_add_opt("bs=%u", num_read_blocks * 512))
    201 			return 1;
    202 	} else {
    203 		const int rsize = write_size / (num_read_blocks * 512);
    204 		int wload = (load * W_LOAD + rsize - 1) / rsize;
    205 
    206 		if (act_add_opt("rate_iops=%u", wload))
    207 			return 1;
    208 		if (act_add_opt("bs=%u", write_size))
    209 			return 1;
    210 	}
    211 
    212 	return 0;
    213 }
    214 
    215 static int act_add_dev_prep(const char *dev)
    216 {
    217 	/* Add sequential zero phase */
    218 	if (act_add_opt("name=act-prep-zeroes-%s", dev))
    219 		return 1;
    220 	if (act_add_opt("filename=%s", dev))
    221 		return 1;
    222 	if (act_add_opt("bs=1M"))
    223 		return 1;
    224 	if (act_add_opt("zero_buffers"))
    225 		return 1;
    226 	if (act_add_opt("rw=write"))
    227 		return 1;
    228 
    229 	/* Randomly overwrite device */
    230 	if (act_add_opt("name=act-prep-salt-%s", dev))
    231 		return 1;
    232 	if (act_add_opt("stonewall"))
    233 		return 1;
    234 	if (act_add_opt("filename=%s", dev))
    235 		return 1;
    236 	if (act_add_opt("bs=4k"))
    237 		return 1;
    238 	if (act_add_opt("ioengine=libaio"))
    239 		return 1;
    240 	if (act_add_opt("iodepth=64"))
    241 		return 1;
    242 	if (act_add_opt("rw=randwrite"))
    243 		return 1;
    244 
    245 	return 0;
    246 }
    247 
    248 static int act_add_dev(const char *dev)
    249 {
    250 	if (prep)
    251 		return act_add_dev_prep(dev);
    252 
    253 	if (act_add_opt("runtime=%llus", test_duration))
    254 		return 1;
    255 	if (act_add_opt("time_based=1"))
    256 		return 1;
    257 
    258 	if (act_add_rw(dev, 1))
    259 		return 1;
    260 	if (act_add_rw(dev, 0))
    261 		return 1;
    262 
    263 	return 0;
    264 }
    265 
    266 /*
    267  * Fill our private options into the command line
    268  */
    269 static int act_prep_cmdline(void)
    270 {
    271 	if (!device_names) {
    272 		log_err("act: you need to set IO target(s) with the "
    273 			"device-names option.\n");
    274 		return 1;
    275 	}
    276 
    277 	org_idx = opt_idx;
    278 
    279 	do {
    280 		char *dev;
    281 
    282 		dev = strsep(&device_names, ",");
    283 		if (!dev)
    284 			break;
    285 
    286 		if (act_add_dev(dev)) {
    287 			log_err("act: failed adding device to the mix\n");
    288 			break;
    289 		}
    290 	} while (1);
    291 
    292 	return 0;
    293 }
    294 
    295 static int act_io_u_lat(struct thread_data *td, uint64_t usec)
    296 {
    297 	struct act_prof_data *apd = td->prof_data;
    298 	struct act_slice *slice;
    299 	int i, ret = 0;
    300 	double perm;
    301 
    302 	if (prep)
    303 		return 0;
    304 
    305 	/*
    306 	 * Really should not happen, but lets not let jitter at the end
    307 	 * ruin our day.
    308 	 */
    309 	if (apd->cur_slice >= apd->nr_slices)
    310 		return 0;
    311 
    312 	slice = &apd->slices[apd->cur_slice];
    313 	slice->total_ios++;
    314 
    315 	for (i = ACT_MAX_CRIT - 1; i >= 0; i--) {
    316 		if (usec > act_pass[i].max_usec) {
    317 			slice->lat_buckets[i]++;
    318 			break;
    319 		}
    320 	}
    321 
    322 	if (time_since_now(&apd->sample_tv) < SAMPLE_SEC)
    323 		return 0;
    324 
    325 	/* SAMPLE_SEC has passed, check criteria for pass */
    326 	for (i = 0; i < ACT_MAX_CRIT; i++) {
    327 		perm = (1000.0 * slice->lat_buckets[i]) / slice->total_ios;
    328 		if (perm < act_pass[i].max_perm)
    329 			continue;
    330 
    331 		log_err("act: %f%% exceeds pass criteria of %f%%\n", perm / 10.0, (double) act_pass[i].max_perm / 10.0);
    332 		ret = 1;
    333 		break;
    334 	}
    335 
    336 	fio_gettime(&apd->sample_tv, NULL);
    337 	apd->cur_slice++;
    338 	return ret;
    339 }
    340 
    341 static void get_act_ref(void)
    342 {
    343 	fio_mutex_down(act_run_data->mutex);
    344 	act_run_data->pending++;
    345 	fio_mutex_up(act_run_data->mutex);
    346 }
    347 
    348 static int show_slice(struct act_slice *slice, unsigned int slice_num)
    349 {
    350 	unsigned int i, failed = 0;
    351 
    352 	log_info("   %2u", slice_num);
    353 
    354 	for (i = 0; i < ACT_MAX_CRIT; i++) {
    355 		double perc = 0.0;
    356 
    357 		if (slice->total_ios)
    358 			perc = 100.0 * (double) slice->lat_buckets[i] / (double) slice->total_ios;
    359 		if ((perc * 10.0) >= act_pass[i].max_perm)
    360 			failed++;
    361 		log_info("\t%2.2f", perc);
    362 	}
    363 	for (i = 0; i < ACT_MAX_CRIT; i++) {
    364 		double perc = 0.0;
    365 
    366 		if (slice->total_ios)
    367 			perc = 100.0 * (double) slice->lat_buckets[i] / (double) slice->total_ios;
    368 		log_info("\t%2.2f", perc);
    369 	}
    370 	log_info("\n");
    371 
    372 	return failed;
    373 }
    374 
    375 static void act_show_all_stats(void)
    376 {
    377 	unsigned int i, fails = 0;
    378 
    379 	log_info("        trans                   device\n");
    380 	log_info("        %%>(ms)                  %%>(ms)\n");
    381 	log_info(" slice");
    382 
    383 	for (i = 0; i < ACT_MAX_CRIT; i++)
    384 		log_info("\t %2u", act_pass[i].max_usec / 1000);
    385 	for (i = 0; i < ACT_MAX_CRIT; i++)
    386 		log_info("\t %2u", act_pass[i].max_usec / 1000);
    387 
    388 	log_info("\n");
    389 	log_info(" -----  -----   -----  ------   -----   -----  ------\n");
    390 
    391 	for (i = 0; i < act_run_data->nr_slices; i++)
    392 		fails += show_slice(&act_run_data->slices[i], i + 1);
    393 
    394 	log_info("\nact: test complete, device(s): %s\n", fails ? "FAILED" : "PASSED");
    395 }
    396 
    397 static void put_act_ref(struct thread_data *td)
    398 {
    399 	struct act_prof_data *apd = td->prof_data;
    400 	unsigned int i, slice;
    401 
    402 	fio_mutex_down(act_run_data->mutex);
    403 
    404 	if (!act_run_data->slices) {
    405 		act_run_data->slices = calloc(apd->nr_slices, sizeof(struct act_slice));
    406 		act_run_data->nr_slices = apd->nr_slices;
    407 	}
    408 
    409 	for (slice = 0; slice < apd->nr_slices; slice++) {
    410 		struct act_slice *dst = &act_run_data->slices[slice];
    411 		struct act_slice *src = &apd->slices[slice];
    412 
    413 		dst->total_ios += src->total_ios;
    414 
    415 		for (i = 0; i < ACT_MAX_CRIT; i++)
    416 			dst->lat_buckets[i] += src->lat_buckets[i];
    417 	}
    418 
    419 	if (!--act_run_data->pending)
    420 		act_show_all_stats();
    421 
    422 	fio_mutex_up(act_run_data->mutex);
    423 }
    424 
    425 static int act_td_init(struct thread_data *td)
    426 {
    427 	struct act_prof_data *apd;
    428 	unsigned int nr_slices;
    429 
    430 	get_act_ref();
    431 
    432 	apd = calloc(1, sizeof(*apd));
    433 	nr_slices = (test_duration + SAMPLE_SEC - 1) / SAMPLE_SEC;
    434 	apd->slices = calloc(nr_slices, sizeof(struct act_slice));
    435 	apd->nr_slices = nr_slices;
    436 	fio_gettime(&apd->sample_tv, NULL);
    437 	td->prof_data = apd;
    438 	return 0;
    439 }
    440 
    441 static void act_td_exit(struct thread_data *td)
    442 {
    443 	struct act_prof_data *apd = td->prof_data;
    444 
    445 	put_act_ref(td);
    446 	free(apd->slices);
    447 	free(apd);
    448 	td->prof_data = NULL;
    449 }
    450 
    451 static struct prof_io_ops act_io_ops = {
    452 	.td_init	= act_td_init,
    453 	.td_exit	= act_td_exit,
    454 	.io_u_lat	= act_io_u_lat,
    455 };
    456 
    457 static struct profile_ops act_profile = {
    458 	.name		= "act",
    459 	.desc		= "ACT Aerospike like benchmark",
    460 	.options	= options,
    461 	.opt_data	= &act_options,
    462 	.prep_cmd	= act_prep_cmdline,
    463 	.cmdline	= act_opts,
    464 	.io_ops		= &act_io_ops,
    465 };
    466 
    467 static void fio_init act_register(void)
    468 {
    469 	act_run_data = calloc(1, sizeof(*act_run_data));
    470 	act_run_data->mutex = fio_mutex_init(FIO_MUTEX_UNLOCKED);
    471 
    472 	if (register_profile(&act_profile))
    473 		log_err("fio: failed to register profile 'act'\n");
    474 }
    475 
    476 static void fio_exit act_unregister(void)
    477 {
    478 	while (org_idx && org_idx < opt_idx)
    479 		free((void *) act_opts[++org_idx]);
    480 
    481 	unregister_profile(&act_profile);
    482 	fio_mutex_remove(act_run_data->mutex);
    483 	free(act_run_data->slices);
    484 	free(act_run_data);
    485 	act_run_data = NULL;
    486 }
    487