bdevperf: Random map for picking I/O offsets
Added a random map feature (-D command line option), which enables offset tracking of every I/O for random read, random write and random rw mix, to make sure every offset is accessed the same number of times. Change-Id: I5a0a23718b9f0a94ca094f86175c036b3230fb8b Signed-off-by: Slawomir Ptak <slawomir.ptak@intel.com> Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/16865 Reviewed-by: Konrad Sztyber <konrad.sztyber@intel.com> Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Reviewed-by: Tomasz Zawadzki <tomasz.zawadzki@intel.com> Reviewed-by: Jim Harris <james.r.harris@intel.com>
This commit is contained in:
parent
d78b5f77ef
commit
d254a3b924
@ -69,6 +69,7 @@ static int g_timeout_in_sec;
|
||||
static struct spdk_conf *g_bdevperf_conf = NULL;
|
||||
static const char *g_bdevperf_conf_file = NULL;
|
||||
static double g_zipf_theta;
|
||||
static bool g_random_map = false;
|
||||
|
||||
static struct spdk_cpuset g_all_cpuset;
|
||||
static struct spdk_poller *g_perf_timer = NULL;
|
||||
@ -148,6 +149,7 @@ struct bdevperf_job {
|
||||
|
||||
/* keep channel's histogram data before being destroyed */
|
||||
struct spdk_histogram_data *histogram;
|
||||
struct spdk_bit_array *random_map;
|
||||
};
|
||||
|
||||
struct spdk_bdevperf {
|
||||
@ -448,6 +450,7 @@ bdevperf_job_free(struct bdevperf_job *job)
|
||||
{
|
||||
spdk_histogram_data_free(job->histogram);
|
||||
spdk_bit_array_free(&job->outstanding);
|
||||
spdk_bit_array_free(&job->random_map);
|
||||
spdk_zipf_free(&job->zipf);
|
||||
free(job->name);
|
||||
free(job);
|
||||
@ -1095,6 +1098,7 @@ bdevperf_submit_single(struct bdevperf_job *job, struct bdevperf_task *task)
|
||||
{
|
||||
uint64_t offset_in_ios;
|
||||
uint64_t rand_value;
|
||||
uint32_t first_clear;
|
||||
|
||||
if (job->zipf) {
|
||||
offset_in_ios = spdk_zipf_generate(job->zipf);
|
||||
@ -1105,6 +1109,31 @@ bdevperf_submit_single(struct bdevperf_job *job, struct bdevperf_task *task)
|
||||
*/
|
||||
rand_value = (uint64_t)rand_r(&job->seed) * RAND_MAX + rand_r(&job->seed);
|
||||
offset_in_ios = rand_value % job->size_in_ios;
|
||||
|
||||
if (g_random_map) {
|
||||
/* Make sure, that the offset does not exceed the maximum size
|
||||
* of the bit array (verified during job creation)
|
||||
*/
|
||||
assert(offset_in_ios < UINT32_MAX);
|
||||
|
||||
first_clear = spdk_bit_array_find_first_clear(job->random_map, (uint32_t)offset_in_ios);
|
||||
|
||||
if (first_clear == UINT32_MAX) {
|
||||
first_clear = spdk_bit_array_find_first_clear(job->random_map, 0);
|
||||
|
||||
if (first_clear == UINT32_MAX) {
|
||||
/* If there are no more clear bits in the array, we start over
|
||||
* and select the previously selected random value.
|
||||
*/
|
||||
spdk_bit_array_clear_mask(job->random_map);
|
||||
first_clear = (uint32_t)offset_in_ios;
|
||||
}
|
||||
}
|
||||
|
||||
spdk_bit_array_set(job->random_map, first_clear);
|
||||
|
||||
offset_in_ios = first_clear;
|
||||
}
|
||||
} else {
|
||||
offset_in_ios = job->offset_in_ios++;
|
||||
if (job->offset_in_ios == job->size_in_ios) {
|
||||
@ -1689,6 +1718,21 @@ bdevperf_construct_job(struct spdk_bdev *bdev, struct job_config *config,
|
||||
|
||||
TAILQ_INIT(&job->task_list);
|
||||
|
||||
if (g_random_map) {
|
||||
if (job->size_in_ios >= UINT32_MAX) {
|
||||
SPDK_ERRLOG("Due to constraints of the random map, the job storage capacity is too large\n");
|
||||
bdevperf_job_free(job);
|
||||
return -ENOMEM;
|
||||
}
|
||||
job->random_map = spdk_bit_array_create(job->size_in_ios);
|
||||
if (job->random_map == NULL) {
|
||||
SPDK_ERRLOG("Could not create random_map array bitmap for bdev %s\n",
|
||||
spdk_bdev_get_name(bdev));
|
||||
bdevperf_job_free(job);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
task_num = job->queue_depth;
|
||||
if (job->reset) {
|
||||
task_num += 1;
|
||||
@ -2335,6 +2379,8 @@ bdevperf_parse_arg(int ch, char *arg)
|
||||
}
|
||||
} else if (ch == 'l') {
|
||||
g_latency_display_level++;
|
||||
} else if (ch == 'D') {
|
||||
g_random_map = true;
|
||||
} else {
|
||||
tmp = spdk_strtoll(optarg, 10);
|
||||
if (tmp < 0) {
|
||||
@ -2399,6 +2445,7 @@ bdevperf_usage(void)
|
||||
printf(" -C enable every core to send I/Os to each bdev\n");
|
||||
printf(" -j <filename> use job config file\n");
|
||||
printf(" -l display latency histogram, default: disable. -l display summary, -ll display details\n");
|
||||
printf(" -D use a random map for picking offsets not previously read or written (for all jobs)\n");
|
||||
}
|
||||
|
||||
static int
|
||||
@ -2490,6 +2537,16 @@ verify_test_params(struct spdk_app_opts *opts)
|
||||
}
|
||||
}
|
||||
|
||||
if (strcmp(g_workload_type, "randread") &&
|
||||
strcmp(g_workload_type, "randwrite") &&
|
||||
strcmp(g_workload_type, "randrw")) {
|
||||
if (g_random_map) {
|
||||
fprintf(stderr, "Ignoring -D option... Please use -D option"
|
||||
" only when using randread, randwrite or randrw.\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
out:
|
||||
spdk_app_usage();
|
||||
@ -2511,7 +2568,7 @@ main(int argc, char **argv)
|
||||
opts.rpc_addr = NULL;
|
||||
opts.shutdown_cb = spdk_bdevperf_shutdown_cb;
|
||||
|
||||
if ((rc = spdk_app_parse_args(argc, argv, &opts, "Zzfq:o:t:w:k:CF:M:P:S:T:Xlj:", NULL,
|
||||
if ((rc = spdk_app_parse_args(argc, argv, &opts, "Zzfq:o:t:w:k:CF:M:P:S:T:Xlj:D", NULL,
|
||||
bdevperf_parse_arg, bdevperf_usage)) !=
|
||||
SPDK_APP_PARSE_ARGS_SUCCESS) {
|
||||
return rc;
|
||||
|
Loading…
Reference in New Issue
Block a user