DCA(Dynamic context attachment) support many RC QPs to share the WQE buffer in a memory pool, this help reducing the memory consumption when there are many QPs are inactive. Signed-off-by: Chengchang Tang <tangchengchang@huawei.com>
205 lines
6.0 KiB
Diff
205 lines
6.0 KiB
Diff
From c8d7a2dc811a18ffd314b8764c961234e5f2ec77 Mon Sep 17 00:00:00 2001
|
|
From: Chengchang Tang <tangchengchang@huawei.com>
|
|
Date: Mon, 10 May 2021 17:13:13 +0800
|
|
Subject: libhns: Add support for shrinking DCA memory pool
|
|
|
|
driver inclusion
|
|
category: feature
|
|
bugzilla: https://gitee.com/src-openeuler/rdma-core/issues/I63L1M
|
|
|
|
----------------------------------------------------------
|
|
|
|
The QP's WQE buffer may be detached after QP is modified or CQE is polled,
|
|
and the state of DCA mem object may be changed as clean for no QP is using
|
|
it. So shrink the clean DCA mem from the memory pool and destroy the DCA
|
|
mem's buffer to reduce the memory consumption.
|
|
|
|
Signed-off-by: Chengchang Tang <tangchengchang@huawei.com>
|
|
Reviewed-by: Yangyang Li <liyangyang20@huawei.com>
|
|
---
|
|
providers/hns/hns_roce_u.h | 2 +
|
|
providers/hns/hns_roce_u_buf.c | 103 +++++++++++++++++++++++++++++++
|
|
providers/hns/hns_roce_u_hw_v2.c | 7 +++
|
|
3 files changed, 112 insertions(+)
|
|
|
|
diff --git a/providers/hns/hns_roce_u.h b/providers/hns/hns_roce_u.h
|
|
index 0e25ce5..7b5c5c9 100644
|
|
--- a/providers/hns/hns_roce_u.h
|
|
+++ b/providers/hns/hns_roce_u.h
|
|
@@ -212,6 +212,7 @@ struct hns_roce_dca_ctx {
|
|
int mem_cnt;
|
|
unsigned int unit_size;
|
|
uint64_t max_size;
|
|
+ uint64_t min_size;
|
|
uint64_t curr_size;
|
|
};
|
|
|
|
@@ -580,6 +581,7 @@ void hns_roce_qp_spinlock_destroy(struct hns_roce_qp *qp);
|
|
|
|
void hns_roce_free_qp_buf(struct hns_roce_qp *qp, struct hns_roce_context *ctx);
|
|
|
|
+void hns_roce_shrink_dca_mem(struct hns_roce_context *ctx);
|
|
void hns_roce_cleanup_dca_mem(struct hns_roce_context *ctx);
|
|
int hns_roce_add_dca_mem(struct hns_roce_context *ctx, uint32_t size);
|
|
|
|
diff --git a/providers/hns/hns_roce_u_buf.c b/providers/hns/hns_roce_u_buf.c
|
|
index 02c43ae..c0f86e9 100644
|
|
--- a/providers/hns/hns_roce_u_buf.c
|
|
+++ b/providers/hns/hns_roce_u_buf.c
|
|
@@ -101,6 +101,20 @@ static inline uint64_t dca_mem_to_key(struct hns_roce_dca_mem *dca_mem)
|
|
return (uintptr_t)dca_mem;
|
|
}
|
|
|
|
+static struct hns_roce_dca_mem *key_to_dca_mem(struct hns_roce_dca_ctx *ctx,
|
|
+ uint64_t key)
|
|
+{
|
|
+ struct hns_roce_dca_mem *mem;
|
|
+ struct hns_roce_dca_mem *tmp;
|
|
+
|
|
+ list_for_each_safe(&ctx->mem_list, mem, tmp, entry) {
|
|
+ if (dca_mem_to_key(mem) == key)
|
|
+ return mem;
|
|
+ }
|
|
+
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
static inline void *dca_mem_addr(struct hns_roce_dca_mem *dca_mem, int offset)
|
|
{
|
|
return dca_mem->buf.buf + offset;
|
|
@@ -156,6 +170,32 @@ void hns_roce_cleanup_dca_mem(struct hns_roce_context *ctx)
|
|
deregister_dca_mem(ctx, mem->handle);
|
|
}
|
|
|
|
+struct hns_dca_mem_shrink_resp {
|
|
+ uint32_t free_mems;
|
|
+ uint64_t free_key;
|
|
+};
|
|
+
|
|
+static int shrink_dca_mem(struct hns_roce_context *ctx, uint32_t handle,
|
|
+ uint64_t size, struct hns_dca_mem_shrink_resp *resp)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ DECLARE_COMMAND_BUFFER(cmd, HNS_IB_OBJECT_DCA_MEM,
|
|
+ HNS_IB_METHOD_DCA_MEM_SHRINK, 4);
|
|
+ fill_attr_in_obj(cmd, HNS_IB_ATTR_DCA_MEM_SHRINK_HANDLE, handle);
|
|
+ fill_attr_in_uint64(cmd, HNS_IB_ATTR_DCA_MEM_SHRINK_RESERVED_SIZE, size);
|
|
+ fill_attr_out(cmd, HNS_IB_ATTR_DCA_MEM_SHRINK_OUT_FREE_KEY,
|
|
+ &resp->free_key, sizeof(resp->free_key));
|
|
+ fill_attr_out(cmd, HNS_IB_ATTR_DCA_MEM_SHRINK_OUT_FREE_MEMS,
|
|
+ &resp->free_mems, sizeof(resp->free_mems));
|
|
+
|
|
+ ret = execute_ioctl(&ctx->ibv_ctx.context, cmd);
|
|
+ if (ret)
|
|
+ verbs_err(&ctx->ibv_ctx, "failed to shrink DCA mem, ret = %d.\n",
|
|
+ ret);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
static bool add_dca_mem_enabled(struct hns_roce_dca_ctx *ctx,
|
|
uint32_t alloc_size)
|
|
{
|
|
@@ -175,6 +215,17 @@ static bool add_dca_mem_enabled(struct hns_roce_dca_ctx *ctx,
|
|
return enable;
|
|
}
|
|
|
|
+static bool shrink_dca_mem_enabled(struct hns_roce_dca_ctx *ctx)
|
|
+{
|
|
+ bool enable;
|
|
+
|
|
+ pthread_spin_lock(&ctx->lock);
|
|
+ enable = ctx->mem_cnt > 0 && ctx->min_size < ctx->max_size;
|
|
+ pthread_spin_unlock(&ctx->lock);
|
|
+
|
|
+ return enable;
|
|
+}
|
|
+
|
|
int hns_roce_add_dca_mem(struct hns_roce_context *ctx, uint32_t size)
|
|
{
|
|
struct hns_roce_dca_ctx *dca_ctx = &ctx->dca_ctx;
|
|
@@ -207,3 +258,55 @@ int hns_roce_add_dca_mem(struct hns_roce_context *ctx, uint32_t size)
|
|
|
|
return 0;
|
|
}
|
|
+
|
|
+void hns_roce_shrink_dca_mem(struct hns_roce_context *ctx)
|
|
+{
|
|
+ struct hns_roce_dca_ctx *dca_ctx = &ctx->dca_ctx;
|
|
+ struct hns_dca_mem_shrink_resp resp = {};
|
|
+ struct hns_roce_dca_mem *mem;
|
|
+ int dca_mem_cnt;
|
|
+ uint32_t handle;
|
|
+ int ret;
|
|
+
|
|
+ pthread_spin_lock(&dca_ctx->lock);
|
|
+ dca_mem_cnt = ctx->dca_ctx.mem_cnt;
|
|
+ pthread_spin_unlock(&dca_ctx->lock);
|
|
+ while (dca_mem_cnt > 0 && shrink_dca_mem_enabled(dca_ctx)) {
|
|
+ resp.free_mems = 0;
|
|
+ /* Step 1: Use any DCA mem uobject to shrink pool */
|
|
+ pthread_spin_lock(&dca_ctx->lock);
|
|
+ mem = list_tail(&dca_ctx->mem_list,
|
|
+ struct hns_roce_dca_mem, entry);
|
|
+ handle = mem ? mem->handle : 0;
|
|
+ pthread_spin_unlock(&dca_ctx->lock);
|
|
+ if (!mem)
|
|
+ break;
|
|
+
|
|
+ ret = shrink_dca_mem(ctx, handle, dca_ctx->min_size, &resp);
|
|
+ if (ret || likely(resp.free_mems < 1))
|
|
+ break;
|
|
+
|
|
+ /* Step 2: Remove shrunk DCA mem node from pool */
|
|
+ pthread_spin_lock(&dca_ctx->lock);
|
|
+ mem = key_to_dca_mem(dca_ctx, resp.free_key);
|
|
+ if (mem) {
|
|
+ list_del(&mem->entry);
|
|
+ dca_ctx->mem_cnt--;
|
|
+ dca_ctx->curr_size -= mem->buf.length;
|
|
+ }
|
|
+
|
|
+ handle = mem ? mem->handle : 0;
|
|
+ pthread_spin_unlock(&dca_ctx->lock);
|
|
+ if (!mem)
|
|
+ break;
|
|
+
|
|
+ /* Step 3: Destroy DCA mem uobject */
|
|
+ deregister_dca_mem(ctx, handle);
|
|
+ free_dca_mem(ctx, mem);
|
|
+ /* No any free memory after deregister 1 DCA mem */
|
|
+ if (resp.free_mems <= 1)
|
|
+ break;
|
|
+
|
|
+ dca_mem_cnt--;
|
|
+ }
|
|
+}
|
|
diff --git a/providers/hns/hns_roce_u_hw_v2.c b/providers/hns/hns_roce_u_hw_v2.c
|
|
index 7b2f2d1..f3a7e6b 100644
|
|
--- a/providers/hns/hns_roce_u_hw_v2.c
|
|
+++ b/providers/hns/hns_roce_u_hw_v2.c
|
|
@@ -738,6 +738,10 @@ static int hns_roce_u_v2_poll_cq(struct ibv_cq *ibvcq, int ne,
|
|
|
|
hns_roce_spin_unlock(&cq->hr_lock);
|
|
|
|
+ /* Try to shrink the DCA mem */
|
|
+ if (ctx->dca_ctx.mem_cnt > 0)
|
|
+ hns_roce_shrink_dca_mem(ctx);
|
|
+
|
|
return err == V2_CQ_POLL_ERR ? err : npolled;
|
|
}
|
|
|
|
@@ -1674,6 +1678,9 @@ static int hns_roce_u_v2_destroy_qp(struct ibv_qp *ibqp)
|
|
|
|
free(qp);
|
|
|
|
+ if (ctx->dca_ctx.mem_cnt > 0)
|
|
+ hns_roce_shrink_dca_mem(ctx);
|
|
+
|
|
return ret;
|
|
}
|
|
|
|
--
|
|
2.30.0
|
|
|