diff --git a/test/lib/nvme/nvme.sh b/test/lib/nvme/nvme.sh index 25c0361a5..65bcd622c 100755 --- a/test/lib/nvme/nvme.sh +++ b/test/lib/nvme/nvme.sh @@ -42,7 +42,7 @@ $rootdir/examples/nvme/hello_world/hello_world timing_exit timing_enter overhead -$rootdir/test/lib/nvme/overhead/overhead -s 4096 -t 1 +$rootdir/test/lib/nvme/overhead/overhead -s 4096 -t 1 -H timing_exit overhead PLUGIN_DIR=$rootdir/examples/nvme/fio_plugin diff --git a/test/lib/nvme/overhead/overhead.c b/test/lib/nvme/overhead/overhead.c index c5a84c0e8..b901e82a4 100644 --- a/test/lib/nvme/overhead/overhead.c +++ b/test/lib/nvme/overhead/overhead.c @@ -39,6 +39,7 @@ #include "spdk/env.h" #include "spdk/string.h" #include "spdk/nvme_intel.h" +#include "spdk/histogram_data.h" #if HAVE_LIBAIO #include @@ -78,6 +79,9 @@ struct ns_entry { bool is_draining; uint32_t current_queue_depth; char name[1024]; + + struct spdk_histogram_data submit_histogram; + struct spdk_histogram_data complete_histogram; }; struct perf_task { @@ -88,6 +92,8 @@ struct perf_task { #endif }; +static bool g_enable_histogram = false; + static struct ctrlr_entry *g_ctrlr = NULL; static struct ns_entry *g_ns = NULL; @@ -144,6 +150,8 @@ register_ns(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_ns *ns) entry->size_in_ios = spdk_nvme_ns_get_size(ns) / g_io_size_bytes; entry->io_size_blocks = g_io_size_bytes / spdk_nvme_ns_get_sector_size(ns); + spdk_histogram_data_reset(&entry->submit_histogram); + spdk_histogram_data_reset(&entry->complete_histogram); snprintf(entry->name, 44, "%-20.20s (%-20.20s)", cdata->mn, cdata->sn); @@ -305,6 +313,9 @@ submit_single_io(void) if (tsc_submit > g_tsc_submit_max) { g_tsc_submit_max = tsc_submit; } + if (g_enable_histogram) { + spdk_histogram_data_tally(&entry->submit_histogram, tsc_submit); + } if (rc != 0) { fprintf(stderr, "starting I/O failed\n"); @@ -357,6 +368,9 @@ check_io(void) if (tsc_complete > g_tsc_complete_max) { g_tsc_complete_max = tsc_complete; } + if (g_enable_histogram) { + spdk_histogram_data_tally(&g_ns->complete_histogram, tsc_complete); + } g_io_completed++; if (!g_ns->is_draining) { submit_single_io(); @@ -466,6 +480,25 @@ static void usage(char *program_name) printf("\t[-s io size in bytes]\n"); printf("\t[-t time in seconds]\n"); printf("\t\t(default: 1)]\n"); + printf("\t[-H enable histograms]\n"); +} + +static void +print_bucket(void *ctx, uint64_t start, uint64_t end, uint64_t count, + uint64_t total, uint64_t so_far) +{ + double so_far_pct; + + if (count == 0) { + return; + } + + so_far_pct = (double)so_far * 100 / total; + + printf("%9.3f - %9.3f: %9.4f%% (%9ju)\n", + (double)start * 1000 * 1000 / g_tsc_rate, + (double)end * 1000 * 1000 / g_tsc_rate, + so_far_pct, count); } static void @@ -479,6 +512,24 @@ print_stats(void) (float)g_tsc_submit / g_io_completed, g_tsc_submit_min, g_tsc_submit_max); printf("complete avg, min, max = %8.1f, %ju, %ju\n", (float)g_tsc_complete / g_io_completed, g_tsc_complete_min, g_tsc_complete_max); + + if (!g_enable_histogram) { + return; + } + + printf("\n"); + printf("Submit histogram\n"); + printf("================\n"); + printf(" Range in us Cumulative Count\n"); + spdk_histogram_data_iterate(&g_ns->submit_histogram, print_bucket, NULL); + printf("\n"); + + printf("Complete histogram\n"); + printf("==================\n"); + printf(" Range in us Cumulative Count\n"); + spdk_histogram_data_iterate(&g_ns->complete_histogram, print_bucket, NULL); + printf("\n"); + } static int @@ -490,7 +541,7 @@ parse_args(int argc, char **argv) g_io_size_bytes = 0; g_time_in_sec = 0; - while ((op = getopt(argc, argv, "s:t:")) != -1) { + while ((op = getopt(argc, argv, "s:t:H")) != -1) { switch (op) { case 's': g_io_size_bytes = atoi(optarg); @@ -498,6 +549,9 @@ parse_args(int argc, char **argv) case 't': g_time_in_sec = atoi(optarg); break; + case 'H': + g_enable_histogram = true; + break; default: usage(argv[0]); return 1;