nvme/pcie: Add statistics per poll group

Check if qpair has a poll group during the connect process,
use poll group's statistics or allocate own structure per
qpair. That is done due to not all applications use poll
groups and we want to avoid "if (qpair->group)"
conditions in data path.

Admin qpair always allocates its own statistics
structure but the statistics are not reported
since this qpair is not attached to a poll group.

Statistics are reported by spdk_nvme_perf tool
if --transport-stats and in bdev_nvme_transport_statistics
RPC method.

Change-Id: I58765be161491fe394968ea65ea22db1478b219a
Signed-off-by: Alexey Marchuk <alexeymar@mellanox.com>
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/6304
Community-CI: Broadcom CI
Community-CI: Mellanox Build Bot
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
This commit is contained in:
Alexey Marchuk 2020-12-07 13:51:17 +03:00 committed by Jim Harris
parent 5c33437b99
commit 558be98fd3
8 changed files with 158 additions and 1 deletions

View File

@ -3036,6 +3036,16 @@ Example response:
"recv_sq_doorbell_updates": 348445
}
]
},
{
"trname": "PCIE",
"polls": 435419831,
"idle_polls": 434901004,
"completions": 1485543,
"cq_doorbell_updates": 518827,
"queued_requests": 0,
"submitted_requests": 1485543,
"sq_doobell_updates": 516081
}
]
},
@ -3068,6 +3078,16 @@ Example response:
"recv_sq_doorbell_updates": 357956
}
]
},
{
"trname": "PCIE",
"polls": 429044294,
"idle_polls": 428525658,
"completions": 1478730,
"cq_doorbell_updates": 518636,
"queued_requests": 0,
"submitted_requests": 1478730,
"sq_doobell_updates": 511658
}
]
}

View File

@ -1044,6 +1044,23 @@ nvme_dump_rdma_statistics(struct spdk_nvme_transport_poll_group_stat *stat)
}
}
static void
nvme_dump_pcie_statistics(struct spdk_nvme_transport_poll_group_stat *stat)
{
struct spdk_nvme_pcie_stat *pcie_stat;
pcie_stat = &stat->pcie;
printf("PCIE transport:\n");
printf("\tpolls: %"PRIu64"\n", pcie_stat->polls);
printf("\tidle_polls: %"PRIu64"\n", pcie_stat->idle_polls);
printf("\tcompletions: %"PRIu64"\n", pcie_stat->completions);
printf("\tcq_doorbell_updates: %"PRIu64"\n", pcie_stat->cq_doorbell_updates);
printf("\tsubmitted_requests: %"PRIu64"\n", pcie_stat->submitted_requests);
printf("\tsq_doobell_updates: %"PRIu64"\n", pcie_stat->sq_doobell_updates);
printf("\tqueued_requests: %"PRIu64"\n", pcie_stat->queued_requests);
}
static void
nvme_dump_transport_stats(uint32_t lcore, struct ns_worker_ctx *ns_ctx)
{
@ -1071,6 +1088,9 @@ nvme_dump_transport_stats(uint32_t lcore, struct ns_worker_ctx *ns_ctx)
case SPDK_NVME_TRANSPORT_RDMA:
nvme_dump_rdma_statistics(stat->transport_stat[i]);
break;
case SPDK_NVME_TRANSPORT_PCIE:
nvme_dump_pcie_statistics(stat->transport_stat[i]);
break;
default:
fprintf(stderr, "Unknown transport statistics %d %s\n", stat->transport_stat[i]->trtype,
spdk_nvme_transport_id_trtype_str(stat->transport_stat[i]->trtype));

View File

@ -462,6 +462,16 @@ struct spdk_nvme_rdma_device_stat {
uint64_t recv_doorbell_updates;
};
struct spdk_nvme_pcie_stat {
uint64_t polls;
uint64_t idle_polls;
uint64_t completions;
uint64_t cq_doorbell_updates;
uint64_t submitted_requests;
uint64_t queued_requests;
uint64_t sq_doobell_updates;
};
struct spdk_nvme_transport_poll_group_stat {
spdk_nvme_transport_type_t trtype;
union {
@ -469,6 +479,7 @@ struct spdk_nvme_transport_poll_group_stat {
uint32_t num_devices;
struct spdk_nvme_rdma_device_stat *device_stats;
} rdma;
struct spdk_nvme_pcie_stat pcie;
};
};

View File

@ -3,7 +3,7 @@
*
* Copyright (c) Intel Corporation. All rights reserved.
* Copyright (c) 2017, IBM Corporation. All rights reserved.
* Copyright (c) 2019, 2020 Mellanox Technologies LTD. All rights reserved.
* Copyright (c) 2019-2021 Mellanox Technologies LTD. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -1218,11 +1218,13 @@ nvme_pcie_qpair_submit_request(struct spdk_nvme_qpair *qpair, struct nvme_reques
tr = TAILQ_FIRST(&pqpair->free_tr);
if (tr == NULL) {
pqpair->stat->queued_requests++;
/* Inform the upper layer to try again later. */
rc = -EAGAIN;
goto exit;
}
pqpair->stat->submitted_requests++;
TAILQ_REMOVE(&pqpair->free_tr, tr, tq_list); /* remove tr from free_tr */
TAILQ_INSERT_TAIL(&pqpair->outstanding_tr, tr, tq_list);
tr->req = req;
@ -1276,6 +1278,39 @@ spdk_nvme_pcie_set_hotplug_filter(spdk_nvme_pcie_hotplug_filter_cb filter_cb)
g_hotplug_filter_cb = filter_cb;
}
static int
nvme_pcie_poll_group_get_stats(struct spdk_nvme_transport_poll_group *tgroup,
struct spdk_nvme_transport_poll_group_stat **_stats)
{
struct nvme_pcie_poll_group *group;
struct spdk_nvme_transport_poll_group_stat *stats;
if (tgroup == NULL || _stats == NULL) {
SPDK_ERRLOG("Invalid stats or group pointer\n");
return -EINVAL;
}
group = SPDK_CONTAINEROF(tgroup, struct nvme_pcie_poll_group, group);
stats = calloc(1, sizeof(*stats));
if (!stats) {
SPDK_ERRLOG("Can't allocate memory for RDMA stats\n");
return -ENOMEM;
}
stats->trtype = SPDK_NVME_TRANSPORT_PCIE;
memcpy(&stats->pcie, &group->stats, sizeof(group->stats));
*_stats = stats;
return 0;
}
static void
nvme_pcie_poll_group_free_stats(struct spdk_nvme_transport_poll_group *tgroup,
struct spdk_nvme_transport_poll_group_stat *stats)
{
free(stats);
}
static struct spdk_pci_id nvme_pci_driver_id[] = {
{
.class_id = SPDK_PCI_CLASS_NVME,
@ -1329,6 +1364,8 @@ const struct spdk_nvme_transport_ops pcie_ops = {
.poll_group_remove = nvme_pcie_poll_group_remove,
.poll_group_process_completions = nvme_pcie_poll_group_process_completions,
.poll_group_destroy = nvme_pcie_poll_group_destroy,
.poll_group_get_stats = nvme_pcie_poll_group_get_stats,
.poll_group_free_stats = nvme_pcie_poll_group_free_stats
};
SPDK_NVME_TRANSPORT_REGISTER(pcie, &pcie_ops);

View File

@ -2,6 +2,7 @@
* BSD LICENSE
*
* Copyright (c) Intel Corporation. All rights reserved.
* Copyright (c) 2021 Mellanox Technologies LTD. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -271,6 +272,13 @@ nvme_pcie_ctrlr_construct_admin_qpair(struct spdk_nvme_ctrlr *ctrlr, uint16_t nu
return rc;
}
pqpair->stat = spdk_zmalloc(sizeof(*pqpair->stat), 64, NULL, SPDK_ENV_SOCKET_ID_ANY,
SPDK_MALLOC_SHARE);
if (!pqpair->stat) {
SPDK_ERRLOG("Failed to allocate admin qpair statistics\n");
return -ENOMEM;
}
return nvme_pcie_qpair_construct(ctrlr->adminq, NULL);
}
@ -444,6 +452,24 @@ _nvme_pcie_ctrlr_create_io_qpair(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme
return -ENOMEM;
}
/* Statistics may already be allocated in the case of controller reset */
if (!pqpair->stat) {
if (qpair->poll_group) {
struct nvme_pcie_poll_group *group = SPDK_CONTAINEROF(qpair->poll_group,
struct nvme_pcie_poll_group, group);
pqpair->stat = &group->stats;
pqpair->shared_stats = true;
} else {
pqpair->stat = calloc(1, sizeof(*pqpair->stat));
if (!pqpair->stat) {
SPDK_ERRLOG("Failed to allocate qpair statistics\n");
free(status);
return -ENOMEM;
}
}
}
rc = nvme_pcie_ctrlr_cmd_create_io_cq(ctrlr, qpair, nvme_completion_poll_cb, status);
if (rc != 0) {
free(status);
@ -781,6 +807,8 @@ nvme_pcie_qpair_process_completions(struct spdk_nvme_qpair *qpair, uint32_t max_
max_completions = pqpair->max_completions_cap;
}
pqpair->stat->polls++;
while (1) {
cpl = &pqpair->cpl[pqpair->cq_head];
@ -838,7 +866,10 @@ nvme_pcie_qpair_process_completions(struct spdk_nvme_qpair *qpair, uint32_t max_
}
if (num_completions > 0) {
pqpair->stat->completions += num_completions;
nvme_pcie_qpair_ring_cq_doorbell(qpair);
} else {
pqpair->stat->idle_polls++;
}
if (pqpair->flags.delay_cmd_submit) {
@ -891,6 +922,17 @@ nvme_pcie_qpair_destroy(struct spdk_nvme_qpair *qpair)
nvme_qpair_deinit(qpair);
if (!pqpair->shared_stats) {
if (qpair->id) {
free(pqpair->stat);
} else {
/* statistics of admin qpair are allocates from huge pages because
* admin qpair is shared for multi-process */
spdk_free(pqpair->stat);
}
}
spdk_free(pqpair);
return 0;

View File

@ -2,6 +2,7 @@
* BSD LICENSE
*
* Copyright (c) Intel Corporation. All rights reserved.
* Copyright (c) 2021 Mellanox Technologies LTD. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -120,6 +121,7 @@ SPDK_STATIC_ASSERT((offsetof(struct nvme_tracker, meta_sgl) & 7) == 0, "SGL must
struct nvme_pcie_poll_group {
struct spdk_nvme_transport_poll_group group;
struct spdk_nvme_pcie_stat stats;
};
/* PCIe transport extensions for spdk_nvme_qpair */
@ -142,6 +144,8 @@ struct nvme_pcie_qpair {
/* Array of trackers indexed by command ID. */
struct nvme_tracker *tr;
struct spdk_nvme_pcie_stat *stat;
uint16_t num_entries;
uint8_t retry_count;
@ -185,6 +189,7 @@ struct nvme_pcie_qpair {
*/
bool sq_in_cmb;
bool shared_stats;
uint64_t cmd_bus_addr;
uint64_t cpl_bus_addr;
@ -260,6 +265,7 @@ nvme_pcie_qpair_ring_sq_doorbell(struct spdk_nvme_qpair *qpair)
if (spdk_likely(need_mmio)) {
spdk_wmb();
pqpair->stat->sq_doobell_updates++;
g_thread_mmio_ctrlr = pctrlr;
spdk_mmio_write_4(pqpair->sq_tdbl, pqpair->sq_tail);
g_thread_mmio_ctrlr = NULL;
@ -281,6 +287,7 @@ nvme_pcie_qpair_ring_cq_doorbell(struct spdk_nvme_qpair *qpair)
}
if (spdk_likely(need_mmio)) {
pqpair->stat->cq_doorbell_updates++;
g_thread_mmio_ctrlr = pctrlr;
spdk_mmio_write_4(pqpair->cq_hdbl, pqpair->cq_head);
g_thread_mmio_ctrlr = NULL;

View File

@ -973,6 +973,19 @@ rpc_bdev_nvme_rdma_stats(struct spdk_json_write_ctx *w,
spdk_json_write_array_end(w);
}
static void
rpc_bdev_nvme_pcie_stats(struct spdk_json_write_ctx *w,
struct spdk_nvme_transport_poll_group_stat *stat)
{
spdk_json_write_named_uint64(w, "polls", stat->pcie.polls);
spdk_json_write_named_uint64(w, "idle_polls", stat->pcie.idle_polls);
spdk_json_write_named_uint64(w, "completions", stat->pcie.completions);
spdk_json_write_named_uint64(w, "cq_doorbell_updates", stat->pcie.cq_doorbell_updates);
spdk_json_write_named_uint64(w, "queued_requests", stat->pcie.queued_requests);
spdk_json_write_named_uint64(w, "submitted_requests", stat->pcie.submitted_requests);
spdk_json_write_named_uint64(w, "sq_doobell_updates", stat->pcie.sq_doobell_updates);
}
static void
rpc_bdev_nvme_stats_per_channel(struct spdk_io_channel_iter *i)
{
@ -1009,6 +1022,9 @@ rpc_bdev_nvme_stats_per_channel(struct spdk_io_channel_iter *i)
case SPDK_NVME_TRANSPORT_RDMA:
rpc_bdev_nvme_rdma_stats(ctx->w, tr_stat);
break;
case SPDK_NVME_TRANSPORT_PCIE:
rpc_bdev_nvme_pcie_stats(ctx->w, tr_stat);
break;
default:
SPDK_WARNLOG("Can't handle trtype %d %s\n", tr_stat->trtype,
spdk_nvme_transport_id_trtype_str(tr_stat->trtype));

View File

@ -3,6 +3,7 @@
*
* Copyright (c) Intel Corporation.
* All rights reserved.
* Copyright (c) 2021 Mellanox Technologies LTD. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -79,6 +80,9 @@ DEFINE_STUB(spdk_pci_register_error_handler, int, (spdk_pci_error_handler sighan
0);
DEFINE_STUB_V(spdk_pci_unregister_error_handler, (spdk_pci_error_handler sighandler));
DEFINE_STUB(nvme_transport_get_name, const char *, (const struct spdk_nvme_transport *transport),
NULL);
SPDK_LOG_REGISTER_COMPONENT(nvme)
struct nvme_driver *g_spdk_nvme_driver = NULL;