nvme/rdma: Reap multiple completions per poll

This is more CPU efficient than only grabbing one
completion per call to ibv_poll_cq.

Change-Id: I0c70d33639f0f345482d9e7c810f9c6723937058
Signed-off-by: Ben Walker <benjamin.walker@intel.com>
This commit is contained in:
Ben Walker 2016-12-20 12:18:30 -07:00 committed by Daniel Verkamp
parent 378fc7787c
commit eb2ec1b07b

View File

@ -1374,93 +1374,85 @@ nvme_rdma_qpair_fail(struct spdk_nvme_qpair *qpair)
return 0; return 0;
} }
#define MAX_COMPLETIONS_PER_POLL 128
int int
nvme_rdma_qpair_process_completions(struct spdk_nvme_qpair *qpair, nvme_rdma_qpair_process_completions(struct spdk_nvme_qpair *qpair,
uint32_t max_completions) uint32_t max_completions)
{ {
struct nvme_rdma_qpair *rqpair; struct nvme_rdma_qpair *rqpair = nvme_rdma_qpair(qpair);
struct ibv_wc wc; struct ibv_wc wc[MAX_COMPLETIONS_PER_POLL];
uint32_t size; int i, rc, batch_size;
int rc; uint32_t reaped;
uint32_t io_completed = 0;
rqpair = nvme_rdma_qpair(qpair); if (max_completions == 0) {
size = rqpair->num_entries - 1U; max_completions = rqpair->num_entries;
if (!max_completions || max_completions > size) { } else {
max_completions = size; max_completions = nvme_min(max_completions, rqpair->num_entries);
} }
/* poll the send_cq */ /* Consume all send completions */
while (true) { reaped = 0;
rc = ibv_poll_cq(rqpair->cm_id->send_cq, 1, &wc); do {
if (rc == 0) { batch_size = nvme_min((max_completions - reaped),
break; MAX_COMPLETIONS_PER_POLL);
} rc = ibv_poll_cq(rqpair->cm_id->send_cq, batch_size, wc);
if (rc < 0) { if (rc < 0) {
SPDK_ERRLOG("Poll CQ error!(%d): %s\n", SPDK_ERRLOG("Error polling CQ! (%d): %s\n",
errno, strerror(errno)); errno, strerror(errno));
return -1; return -1;
} } else if (rc == 0) {
/* Ran out of completions */
if (wc.status) {
SPDK_ERRLOG("CQ completion error status %d, exiting handler\n",
wc.status);
break;
}
if (wc.opcode == IBV_WC_SEND) {
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "CQ send completion\n");
} else {
SPDK_ERRLOG("Poll cq opcode type unknown!!!!! completion\n");
return -1;
}
}
/* poll the recv_cq */
while (true) {
rc = ibv_poll_cq(rqpair->cm_id->recv_cq, 1, &wc);
if (rc == 0) {
break; break;
} }
reaped += rc;
} while (reaped < max_completions);
/* Poll for recv completions */
reaped = 0;
do {
batch_size = nvme_min((max_completions - reaped),
MAX_COMPLETIONS_PER_POLL);
rc = ibv_poll_cq(rqpair->cm_id->recv_cq, batch_size, wc);
if (rc < 0) { if (rc < 0) {
SPDK_ERRLOG("Poll CQ error!(%d): %s\n", SPDK_ERRLOG("Error polling CQ! (%d): %s\n",
errno, strerror(errno)); errno, strerror(errno));
return -1; return -1;
} } else if (rc == 0) {
/* Ran out of completions */
if (wc.status) {
SPDK_ERRLOG("CQ Completion Error For Response %lu: %d (%s)\n",
wc.wr_id, wc.status, ibv_wc_status_str(wc.status));
break; break;
} }
if (wc.opcode == IBV_WC_RECV) { reaped += rc;
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "CQ recv completion\n"); for (i = 0; i < rc; i++) {
if (wc.byte_len < sizeof(struct spdk_nvme_cpl)) { if (wc[i].status) {
SPDK_ERRLOG("recv length %u less than expected response size\n", wc.byte_len); SPDK_ERRLOG("CQ error on Queue Pair %p, Response Index %lu (%d): %s\n",
qpair, wc[i].wr_id, wc[i].status, ibv_wc_status_str(wc[i].status));
return -1; return -1;
} }
rc = nvme_rdma_recv(rqpair, wc.wr_id); switch (wc[i].opcode) {
if (rc) { case IBV_WC_RECV:
SPDK_ERRLOG("nvme_rdma_recv processing failure\n"); SPDK_TRACELOG(SPDK_TRACE_DEBUG, "CQ recv completion\n");
if (wc[i].byte_len < sizeof(struct spdk_nvme_cpl)) {
SPDK_ERRLOG("recv length %u less than expected response size\n", wc[i].byte_len);
return -1;
}
if (nvme_rdma_recv(rqpair, wc[i].wr_id)) {
SPDK_ERRLOG("nvme_rdma_recv processing failure\n");
return -1;
}
break;
default:
SPDK_ERRLOG("Received an unexpected opcode on the CQ: %d\n", wc[i].opcode);
return -1; return -1;
} }
io_completed++;
} else {
SPDK_ERRLOG("Poll cq opcode type unknown!!!!! completion\n");
return -1;
} }
} while (reaped < max_completions);
if (io_completed == max_completions) { return reaped;
break;
}
}
return io_completed;
} }
uint32_t uint32_t