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