example/perf: add extended lba format performance tests support

Change-Id: I127279ba32388bcedb85ed0a2eba9b5345c02eda
Signed-off-by: Changpeng Liu <changpeng.liu@intel.com>
Reviewed-on: https://review.gerrithub.io/366532
Tested-by: SPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: Daniel Verkamp <daniel.verkamp@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
This commit is contained in:
Changpeng Liu 2017-06-21 21:57:56 -04:00 committed by Jim Harris
parent f53bd63f96
commit 4046e063c5

View File

@ -41,6 +41,7 @@
#include "spdk/string.h"
#include "spdk/nvme_intel.h"
#include "spdk/histogram_data.h"
#include "spdk/endian.h"
#if HAVE_LIBAIO
#include <libaio.h>
@ -76,6 +77,9 @@ struct ns_entry {
struct ns_entry *next;
uint32_t io_size_blocks;
uint64_t size_in_ios;
uint32_t io_flags;
uint16_t apptag_mask;
uint16_t apptag;
char name[1024];
};
@ -130,6 +134,8 @@ struct perf_task {
struct ns_worker_ctx *ns_ctx;
void *buf;
uint64_t submit_tsc;
uint16_t appmask;
uint16_t apptag;
#if HAVE_LIBAIO
struct iocb iocb;
#endif
@ -157,6 +163,10 @@ static uint64_t g_tsc_rate;
static uint32_t g_io_align = 0x200;
static uint32_t g_io_size_bytes;
static uint32_t g_max_io_md_size;
static uint32_t g_max_io_size_blocks;
static uint32_t g_metacfg_pract_flag;
static uint32_t g_metacfg_prchk_flags;
static int g_rw_percentage;
static int g_is_random;
static int g_queue_depth;
@ -182,6 +192,23 @@ static int g_aio_optind; /* Index of first AIO filename in argv */
static void
task_complete(struct perf_task *task);
static uint16_t crc16_t10dif(uint8_t *buf, size_t len)
{
uint32_t rem = 0;
unsigned int i, j;
uint16_t poly = 0x8bb7;
for (i = 0; i < len; i++) {
rem = rem ^ (buf[i] << 8);
for (j = 0; j < 8; j++) {
rem = rem << 1;
rem = (rem & 0x10000) ? rem ^ poly : rem;
}
}
return (uint16_t)rem;
}
static void
register_ns(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_ns *ns)
{
@ -226,7 +253,7 @@ register_ns(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_ns *ns)
return;
}
entry = malloc(sizeof(struct ns_entry));
entry = calloc(1, sizeof(struct ns_entry));
if (entry == NULL) {
perror("ns_entry malloc");
exit(1);
@ -240,6 +267,18 @@ register_ns(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_ns *ns)
g_io_size_bytes;
entry->io_size_blocks = g_io_size_bytes / spdk_nvme_ns_get_sector_size(ns);
if (spdk_nvme_ns_get_flags(ns) & SPDK_NVME_NS_DPS_PI_SUPPORTED) {
entry->io_flags = g_metacfg_pract_flag | g_metacfg_prchk_flags;
}
if (g_max_io_md_size < spdk_nvme_ns_get_md_size(ns)) {
g_max_io_md_size = spdk_nvme_ns_get_md_size(ns);
}
if (g_max_io_size_blocks < entry->io_size_blocks) {
g_max_io_size_blocks = entry->io_size_blocks;
}
snprintf(entry->name, 44, "%-20.20s (%-20.20s)", cdata->mn, cdata->sn);
g_num_namespaces++;
@ -445,6 +484,77 @@ aio_check_io(struct ns_worker_ctx *ns_ctx)
}
#endif /* HAVE_LIBAIO */
static void
task_extended_lba_setup_pi(struct ns_entry *entry, struct perf_task *task, uint64_t lba,
uint32_t lba_count, bool is_write)
{
struct spdk_nvme_protection_info *pi;
uint32_t i, md_size, sector_size, pi_offset;
uint16_t crc16;
const struct spdk_nvme_ns_data *nsdata;
task->appmask = 0;
task->apptag = 0;
if (!spdk_nvme_ns_supports_extended_lba(entry->u.nvme.ns)) {
return;
}
if (spdk_nvme_ns_get_pi_type(entry->u.nvme.ns) ==
SPDK_NVME_FMT_NVM_PROTECTION_DISABLE) {
return;
}
if (entry->io_flags & SPDK_NVME_IO_FLAGS_PRACT) {
return;
}
/* Type3 don't support REFTAG */
if (spdk_nvme_ns_get_pi_type(entry->u.nvme.ns) ==
SPDK_NVME_FMT_NVM_PROTECTION_TYPE3) {
return;
}
sector_size = spdk_nvme_ns_get_sector_size(entry->u.nvme.ns);
md_size = spdk_nvme_ns_get_md_size(entry->u.nvme.ns);
nsdata = spdk_nvme_ns_get_data(entry->u.nvme.ns);
/* PI locates at the first 8 bytes of metadata,
* doesn't support now
*/
if (nsdata->dps.md_start) {
return;
}
if (entry->io_flags & SPDK_NVME_IO_FLAGS_PRCHK_APPTAG) {
/* Let's use number of lbas for application tag */
task->appmask = 0xffff;
task->apptag = lba_count;
}
for (i = 0; i < lba_count; i++) {
pi_offset = ((sector_size + md_size) * (i + 1)) - 8;
pi = (struct spdk_nvme_protection_info *)(task->buf + pi_offset);
memset(pi, 0, sizeof(*pi));
if (is_write) {
if (entry->io_flags & SPDK_NVME_IO_FLAGS_PRCHK_GUARD) {
/* CRC buffer should not include PI */
crc16 = crc16_t10dif(task->buf + (sector_size + md_size) * i,
sector_size + md_size - 8);
to_be16(&pi->guard, crc16);
}
if (entry->io_flags & SPDK_NVME_IO_FLAGS_PRCHK_APPTAG) {
/* Let's use number of lbas for application tag */
to_be16(&pi->app_tag, lba_count);
}
if (entry->io_flags & SPDK_NVME_IO_FLAGS_PRCHK_REFTAG) {
to_be32(&pi->ref_tag, (uint32_t)lba + i);
}
}
}
}
static void io_complete(void *ctx, const struct spdk_nvme_cpl *completion);
static __thread unsigned int seed = 0;
@ -477,9 +587,15 @@ submit_single_io(struct perf_task *task)
} else
#endif
{
rc = spdk_nvme_ns_cmd_read(entry->u.nvme.ns, ns_ctx->u.nvme.qpair, task->buf,
offset_in_ios * entry->io_size_blocks,
entry->io_size_blocks, io_complete, task, 0);
task_extended_lba_setup_pi(entry, task, offset_in_ios * entry->io_size_blocks,
entry->io_size_blocks, false);
rc = spdk_nvme_ns_cmd_read_with_md(entry->u.nvme.ns, ns_ctx->u.nvme.qpair,
task->buf, NULL,
offset_in_ios * entry->io_size_blocks,
entry->io_size_blocks, io_complete,
task, entry->io_flags,
task->appmask, task->apptag);
}
} else {
#if HAVE_LIBAIO
@ -489,9 +605,15 @@ submit_single_io(struct perf_task *task)
} else
#endif
{
rc = spdk_nvme_ns_cmd_write(entry->u.nvme.ns, ns_ctx->u.nvme.qpair, task->buf,
offset_in_ios * entry->io_size_blocks,
entry->io_size_blocks, io_complete, task, 0);
task_extended_lba_setup_pi(entry, task, offset_in_ios * entry->io_size_blocks,
entry->io_size_blocks, true);
rc = spdk_nvme_ns_cmd_write_with_md(entry->u.nvme.ns, ns_ctx->u.nvme.qpair,
task->buf, NULL,
offset_in_ios * entry->io_size_blocks,
entry->io_size_blocks, io_complete,
task, entry->io_flags,
task->appmask, task->apptag);
}
}
@ -560,6 +682,7 @@ static void
submit_io(struct ns_worker_ctx *ns_ctx, int queue_depth)
{
struct perf_task *task;
uint32_t max_io_size_bytes;
while (queue_depth-- > 0) {
task = calloc(1, sizeof(*task));
@ -568,12 +691,17 @@ submit_io(struct ns_worker_ctx *ns_ctx, int queue_depth)
exit(1);
}
task->buf = spdk_dma_zmalloc(g_io_size_bytes, g_io_align, NULL);
/* maximum extended lba format size from all active
* namespace, it's same with g_io_size_bytes for
* namespace without metadata
*/
max_io_size_bytes = g_io_size_bytes + g_max_io_md_size * g_max_io_size_blocks;
task->buf = spdk_dma_zmalloc(max_io_size_bytes, g_io_align, NULL);
if (task->buf == NULL) {
fprintf(stderr, "task->buf spdk_dma_zmalloc failed\n");
exit(1);
}
memset(task->buf, queue_depth % 8 + 1, g_io_size_bytes);
memset(task->buf, queue_depth % 8 + 1, max_io_size_bytes);
task->ns_ctx = ns_ctx;
@ -718,6 +846,12 @@ static void usage(char *program_name)
printf("\t subnqn Subsystem NQN (default: %s)\n", SPDK_NVMF_DISCOVERY_NQN);
printf("\t Example: -r 'trtype:PCIe traddr:0000:04:00.0' for PCIe or\n");
printf("\t -r 'trtype:RDMA adrfam:IPv4 traddr:192.168.100.8 trsvcid:4420' for NVMeoF\n");
printf("\t[-e metadata configuration]\n");
printf("\t Keys:\n");
printf("\t PRACT Protection Information Action bit (PRACT=1 or PRACT=0)\n");
printf("\t PRCHK Control of Protection Information Checking (PRCHK=GUARD|REFTAG|APPTAG)\n");
printf("\t Example: -e 'PRACT=0,PRCHK=GUARD|REFTAG|APPTAG'\n");
printf("\t -e 'PRACT=1,PRCHK=GUARD'\n");
printf("\t[-d DPDK huge memory size in MB.]\n");
printf("\t[-m max completions per poll]\n");
printf("\t\t(default: 0 - unlimited)\n");
@ -980,6 +1114,35 @@ add_trid(const char *trid_str)
return 0;
}
static int
parse_metadata(const char *metacfg_str)
{
const char *sep;
if (strstr(metacfg_str, "PRACT=1") != NULL) {
g_metacfg_pract_flag = SPDK_NVME_IO_FLAGS_PRACT;
}
sep = strchr(metacfg_str, ',');
if (!sep) {
return 0;
}
if (strstr(sep, "PRCHK=") != NULL) {
if (strstr(sep, "GUARD") != NULL) {
g_metacfg_prchk_flags = SPDK_NVME_IO_FLAGS_PRCHK_GUARD;
}
if (strstr(sep, "REFTAG") != NULL) {
g_metacfg_prchk_flags |= SPDK_NVME_IO_FLAGS_PRCHK_REFTAG;
}
if (strstr(sep, "APPTAG") != NULL) {
g_metacfg_prchk_flags |= SPDK_NVME_IO_FLAGS_PRCHK_APPTAG;
}
}
return 0;
}
static int
parse_args(int argc, char **argv)
{
@ -996,7 +1159,7 @@ parse_args(int argc, char **argv)
g_core_mask = NULL;
g_max_completions = 0;
while ((op = getopt(argc, argv, "c:d:i:lm:q:r:s:t:w:DLM:")) != -1) {
while ((op = getopt(argc, argv, "c:d:e:i:lm:q:r:s:t:w:DLM:")) != -1) {
switch (op) {
case 'c':
g_core_mask = optarg;
@ -1004,6 +1167,12 @@ parse_args(int argc, char **argv)
case 'd':
g_dpdk_mem = atoi(optarg);
break;
case 'e':
if (parse_metadata(optarg)) {
usage(argv[0]);
return 1;
}
break;
case 'i':
g_shm_id = atoi(optarg);
break;
@ -1031,6 +1200,9 @@ parse_args(int argc, char **argv)
case 'w':
workload_type = optarg;
break;
case 'D':
g_disable_sq_cmb = 1;
break;
case 'L':
g_latency_sw_tracking_level++;
break;
@ -1038,9 +1210,6 @@ parse_args(int argc, char **argv)
g_rw_percentage = atoi(optarg);
mix_specified = true;
break;
case 'D':
g_disable_sq_cmb = 1;
break;
default:
usage(argv[0]);
return 1;