Commit ea86c035 authored by Alexey Marchuk's avatar Alexey Marchuk Committed by Tomasz Zawadzki
Browse files

nvme/tcp: NVME TCP poll group statistics



Enable dump of transport stats in functional test.
Update unit tests to support the new statistics

Signed-off-by: default avatarAlexey Marchuk <alexeymar@mellanox.com>
Change-Id: I815aeea7d07bd33a915f19537d60611ba7101361
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/8885


Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Community-CI: Broadcom CI <spdk-ci.pdl@broadcom.com>
Community-CI: Mellanox Build Bot
Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
Reviewed-by: default avatarBen Walker <benjamin.walker@intel.com>
Reviewed-by: default avatarShuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
parent 7d589976
Loading
Loading
Loading
Loading
+19 −0
Original line number Diff line number Diff line
@@ -1064,6 +1064,22 @@ nvme_dump_pcie_statistics(struct spdk_nvme_transport_poll_group_stat *stat)
	printf("\tqueued_requests: %"PRIu64"\n", pcie_stat->queued_requests);
}

static void
nvme_dump_tcp_statistics(struct spdk_nvme_transport_poll_group_stat *stat)
{
	struct spdk_nvme_tcp_stat *tcp_stat;

	tcp_stat = &stat->tcp;

	printf("TCP transport:\n");
	printf("\tpolls:              %"PRIu64"\n", tcp_stat->polls);
	printf("\tidle_polls:         %"PRIu64"\n", tcp_stat->idle_polls);
	printf("\tsock_completions:   %"PRIu64"\n", tcp_stat->socket_completions);
	printf("\tnvme_completions:   %"PRIu64"\n", tcp_stat->nvme_completions);
	printf("\tsubmitted_requests: %"PRIu64"\n", tcp_stat->submitted_requests);
	printf("\tqueued_requests:    %"PRIu64"\n", tcp_stat->queued_requests);
}

static void
nvme_dump_transport_stats(uint32_t lcore, struct ns_worker_ctx *ns_ctx)
{
@@ -1094,6 +1110,9 @@ nvme_dump_transport_stats(uint32_t lcore, struct ns_worker_ctx *ns_ctx)
		case SPDK_NVME_TRANSPORT_PCIE:
			nvme_dump_pcie_statistics(stat->transport_stat[i]);
			break;
		case SPDK_NVME_TRANSPORT_TCP:
			nvme_dump_tcp_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));
+10 −0
Original line number Diff line number Diff line
@@ -497,6 +497,15 @@ struct spdk_nvme_pcie_stat {
	uint64_t sq_doobell_updates;
};

struct spdk_nvme_tcp_stat {
	uint64_t polls;
	uint64_t idle_polls;
	uint64_t socket_completions;
	uint64_t nvme_completions;
	uint64_t submitted_requests;
	uint64_t queued_requests;
};

struct spdk_nvme_transport_poll_group_stat {
	spdk_nvme_transport_type_t trtype;
	union {
@@ -505,6 +514,7 @@ struct spdk_nvme_transport_poll_group_stat {
			struct spdk_nvme_rdma_device_stat *device_stats;
		} rdma;
		struct spdk_nvme_pcie_stat pcie;
		struct spdk_nvme_tcp_stat tcp;
	};
};

+66 −3
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@
 *
 *   Copyright (c) Intel Corporation. All rights reserved.
 *   Copyright (c) 2020 Mellanox Technologies LTD. All rights reserved.
 *   Copyright (c) 2021 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
 *
 *   Redistribution and use in source and binary forms, with or without
 *   modification, are permitted provided that the following conditions
@@ -70,6 +71,7 @@ struct nvme_tcp_poll_group {
	int64_t num_completions;

	TAILQ_HEAD(, nvme_tcp_qpair) needs_poll;
	struct spdk_nvme_tcp_stat stats;
};

/* NVMe TCP qpair extensions for spdk_nvme_qpair */
@@ -85,8 +87,8 @@ struct nvme_tcp_qpair {
	struct nvme_tcp_pdu			*send_pdu; /* only for error pdu and init pdu */
	struct nvme_tcp_pdu			*send_pdus; /* Used by tcp_reqs */
	enum nvme_tcp_pdu_recv_state		recv_state;

	struct nvme_tcp_req			*tcp_reqs;
	struct spdk_nvme_tcp_stat		*stats;

	uint16_t				num_entries;
	uint16_t				async_complete;
@@ -351,6 +353,7 @@ nvme_tcp_ctrlr_delete_io_qpair(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_q
	nvme_qpair_deinit(qpair);
	tqpair = nvme_tcp_qpair(qpair);
	nvme_tcp_free_reqs(tqpair);
	free(tqpair->stats);
	free(tqpair);

	return 0;
@@ -422,6 +425,7 @@ _tcp_write_pdu(struct nvme_tcp_pdu *pdu)
	pdu->sock_req.cb_fn = _pdu_write_done;
	pdu->sock_req.cb_arg = pdu;
	TAILQ_INSERT_TAIL(&tqpair->send_queue, pdu, tailq);
	tqpair->stats->submitted_requests++;
	spdk_sock_writev_async(tqpair->sock, &pdu->sock_req);
}

@@ -737,6 +741,7 @@ nvme_tcp_qpair_submit_request(struct spdk_nvme_qpair *qpair,

	tcp_req = nvme_tcp_req_get(tqpair);
	if (!tcp_req) {
		tqpair->stats->queued_requests++;
		/* Inform the upper layer to try again later. */
		return -EAGAIN;
	}
@@ -1821,6 +1826,7 @@ nvme_tcp_qpair_sock_cb(void *ctx, struct spdk_sock_group *group, struct spdk_soc

	if (pgroup->num_completions >= 0 && num_completions >= 0) {
		pgroup->num_completions += num_completions;
		pgroup->stats.nvme_completions += num_completions;
	} else {
		pgroup->num_completions = -ENXIO;
	}
@@ -1983,6 +1989,7 @@ nvme_tcp_ctrlr_connect_qpair(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_qpa
{
	int rc = 0;
	struct nvme_tcp_qpair *tqpair;
	struct nvme_tcp_poll_group *tgroup;

	tqpair = nvme_tcp_qpair(qpair);

@@ -1999,6 +2006,14 @@ nvme_tcp_ctrlr_connect_qpair(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_qpa
			SPDK_ERRLOG("Unable to activate the tcp qpair.\n");
			return rc;
		}
		tgroup = nvme_tcp_poll_group(qpair->poll_group);
		tqpair->stats = &tgroup->stats;
	} else {
		tqpair->stats = calloc(1, sizeof(*tqpair->stats));
		if (!tqpair->stats) {
			SPDK_ERRLOG("tcp stats memory allocation failed\n");
			return -ENOMEM;
		}
	}

	tqpair->maxr2t = NVME_TCP_MAX_R2T_DEFAULT;
@@ -2257,11 +2272,19 @@ static int
nvme_tcp_poll_group_remove(struct spdk_nvme_transport_poll_group *tgroup,
			   struct spdk_nvme_qpair *qpair)
{
	struct nvme_tcp_qpair *tqpair;
	int rc = 0;

	if (qpair->poll_group_tailq_head == &tgroup->connected_qpairs) {
		return nvme_poll_group_disconnect_qpair(qpair);
		rc = nvme_poll_group_disconnect_qpair(qpair);
	}

	return 0;
	tqpair = nvme_tcp_qpair(qpair);
	/* When qpair is deleted, stats are freed. free(NULL) is valid case, so just set
	 * stats pointer to NULL */
	tqpair->stats = NULL;

	return rc;
}

static int64_t
@@ -2275,6 +2298,7 @@ nvme_tcp_poll_group_process_completions(struct spdk_nvme_transport_poll_group *t

	group->completions_per_qpair = completions_per_qpair;
	group->num_completions = 0;
	group->stats.polls++;

	num_events = spdk_sock_group_poll(group->sock_group);

@@ -2292,6 +2316,9 @@ nvme_tcp_poll_group_process_completions(struct spdk_nvme_transport_poll_group *t
		return num_events;
	}

	group->stats.idle_polls += !num_events;
	group->stats.socket_completions += num_events;

	return group->num_completions;
}

@@ -2316,6 +2343,40 @@ nvme_tcp_poll_group_destroy(struct spdk_nvme_transport_poll_group *tgroup)
	return 0;
}

static int
nvme_tcp_poll_group_get_stats(struct spdk_nvme_transport_poll_group *tgroup,
			      struct spdk_nvme_transport_poll_group_stat **_stats)
{
	struct nvme_tcp_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 = nvme_tcp_poll_group(tgroup);

	stats = calloc(1, sizeof(*stats));
	if (!stats) {
		SPDK_ERRLOG("Can't allocate memory for TCP stats\n");
		return -ENOMEM;
	}
	stats->trtype = SPDK_NVME_TRANSPORT_TCP;
	memcpy(&stats->tcp, &group->stats, sizeof(group->stats));

	*_stats = stats;

	return 0;
}

static void
nvme_tcp_poll_group_free_stats(struct spdk_nvme_transport_poll_group *tgroup,
			       struct spdk_nvme_transport_poll_group_stat *stats)
{
	free(stats);
}

const struct spdk_nvme_transport_ops tcp_ops = {
	.name = "TCP",
	.type = SPDK_NVME_TRANSPORT_TCP,
@@ -2356,6 +2417,8 @@ const struct spdk_nvme_transport_ops tcp_ops = {
	.poll_group_remove = nvme_tcp_poll_group_remove,
	.poll_group_process_completions = nvme_tcp_poll_group_process_completions,
	.poll_group_destroy = nvme_tcp_poll_group_destroy,
	.poll_group_get_stats = nvme_tcp_poll_group_get_stats,
	.poll_group_free_stats = nvme_tcp_poll_group_free_stats,
};

SPDK_NVME_TRANSPORT_REGISTER(tcp, &tcp_ops);
+15 −0
Original line number Diff line number Diff line
@@ -1014,6 +1014,18 @@ rpc_bdev_nvme_pcie_stats(struct spdk_json_write_ctx *w,
	spdk_json_write_named_uint64(w, "sq_doobell_updates", stat->pcie.sq_doobell_updates);
}

static void
rpc_bdev_nvme_tcp_stats(struct spdk_json_write_ctx *w,
			struct spdk_nvme_transport_poll_group_stat *stat)
{
	spdk_json_write_named_uint64(w, "polls", stat->tcp.polls);
	spdk_json_write_named_uint64(w, "idle_polls", stat->tcp.idle_polls);
	spdk_json_write_named_uint64(w, "socket_completions", stat->tcp.socket_completions);
	spdk_json_write_named_uint64(w, "nvme_completions", stat->tcp.nvme_completions);
	spdk_json_write_named_uint64(w, "queued_requests", stat->tcp.queued_requests);
	spdk_json_write_named_uint64(w, "submitted_requests", stat->tcp.submitted_requests);
}

static void
rpc_bdev_nvme_stats_per_channel(struct spdk_io_channel_iter *i)
{
@@ -1051,6 +1063,9 @@ rpc_bdev_nvme_stats_per_channel(struct spdk_io_channel_iter *i)
		case SPDK_NVME_TRANSPORT_PCIE:
			rpc_bdev_nvme_pcie_stats(ctx->w, tr_stat);
			break;
		case SPDK_NVME_TRANSPORT_TCP:
			rpc_bdev_nvme_tcp_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));
+1 −1
Original line number Diff line number Diff line
@@ -44,7 +44,7 @@ fi

$SPDK_EXAMPLE_DIR/perf -q 1 -o 4096 -w randrw -M 50 -t 1 -r "trtype:$TEST_TRANSPORT adrfam:IPv4 traddr:$NVMF_FIRST_TARGET_IP trsvcid:$NVMF_PORT"
$SPDK_EXAMPLE_DIR/perf -q 32 -o 4096 -w randrw -M 50 -t 1 -HI -r "trtype:$TEST_TRANSPORT adrfam:IPv4 traddr:$NVMF_FIRST_TARGET_IP trsvcid:$NVMF_PORT"
$SPDK_EXAMPLE_DIR/perf -q 128 -o 262144 -w randrw -M 50 -t 2 -r "trtype:$TEST_TRANSPORT adrfam:IPv4 traddr:$NVMF_FIRST_TARGET_IP trsvcid:$NVMF_PORT"
$SPDK_EXAMPLE_DIR/perf -q 128 -o 262144 -w randrw -M 50 -t 2 -r "trtype:$TEST_TRANSPORT adrfam:IPv4 traddr:$NVMF_FIRST_TARGET_IP trsvcid:$NVMF_PORT" --transport-stat
sync
$rpc_py nvmf_delete_subsystem nqn.2016-06.io.spdk:cnode1

Loading