From patchwork Wed Feb 8 08:24:47 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: fengchengwen X-Patchwork-Id: 123429 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id DAF6441C3C; Wed, 8 Feb 2023 09:31:00 +0100 (CET) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 8550841153; Wed, 8 Feb 2023 09:30:57 +0100 (CET) Received: from szxga02-in.huawei.com (szxga02-in.huawei.com [45.249.212.188]) by mails.dpdk.org (Postfix) with ESMTP id 5B9DE40DFD for ; Wed, 8 Feb 2023 09:30:55 +0100 (CET) Received: from dggpeml500024.china.huawei.com (unknown [172.30.72.53]) by szxga02-in.huawei.com (SkyGuard) with ESMTP id 4PBY6k2NQBzRrwY; Wed, 8 Feb 2023 16:28:30 +0800 (CST) Received: from localhost.localdomain (10.50.163.32) by dggpeml500024.china.huawei.com (7.185.36.10) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.34; Wed, 8 Feb 2023 16:30:53 +0800 From: Chengwen Feng To: , , , , , CC: , Subject: [PATCH v13 1/6] memarea: introduce memarea library Date: Wed, 8 Feb 2023 08:24:47 +0000 Message-ID: <20230208082452.43883-2-fengchengwen@huawei.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20230208082452.43883-1-fengchengwen@huawei.com> References: <20220721044648.6817-1-fengchengwen@huawei.com> <20230208082452.43883-1-fengchengwen@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.50.163.32] X-ClientProxiedBy: dggems701-chm.china.huawei.com (10.3.19.178) To dggpeml500024.china.huawei.com (7.185.36.10) X-CFilter-Loop: Reflected X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org The memarea library is an allocator of variable-size object which based on a memory region. This patch provides rte_memarea_create() and rte_memarea_destroy() API. Signed-off-by: Chengwen Feng Reviewed-by: Dongdong Liu Acked-by: Morten Brørup --- MAINTAINERS | 5 + doc/api/doxy-api-index.md | 3 +- doc/api/doxy-api.conf.in | 1 + doc/guides/prog_guide/index.rst | 1 + doc/guides/prog_guide/memarea_lib.rst | 46 +++++++ doc/guides/rel_notes/release_23_03.rst | 6 + lib/memarea/memarea_private.h | 58 +++++++++ lib/memarea/meson.build | 10 ++ lib/memarea/rte_memarea.c | 171 +++++++++++++++++++++++++ lib/memarea/rte_memarea.h | 122 ++++++++++++++++++ lib/memarea/version.map | 12 ++ lib/meson.build | 1 + 12 files changed, 435 insertions(+), 1 deletion(-) create mode 100644 doc/guides/prog_guide/memarea_lib.rst create mode 100644 lib/memarea/memarea_private.h create mode 100644 lib/memarea/meson.build create mode 100644 lib/memarea/rte_memarea.c create mode 100644 lib/memarea/rte_memarea.h create mode 100644 lib/memarea/version.map diff --git a/MAINTAINERS b/MAINTAINERS index 3495946d0f..60078ffc72 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1575,6 +1575,11 @@ F: app/test/test_lpm* F: app/test/test_func_reentrancy.c F: app/test/test_xmmt_ops.h +Memarea - EXPERIMENTAL +M: Chengwen Feng +F: lib/memarea +F: doc/guides/prog_guide/memarea_lib.rst + Membership - EXPERIMENTAL M: Yipeng Wang M: Sameh Gobriel diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md index de488c7abf..24456604f8 100644 --- a/doc/api/doxy-api-index.md +++ b/doc/api/doxy-api-index.md @@ -62,7 +62,8 @@ The public API headers are grouped by topics: [memzone](@ref rte_memzone.h), [mempool](@ref rte_mempool.h), [malloc](@ref rte_malloc.h), - [memcpy](@ref rte_memcpy.h) + [memcpy](@ref rte_memcpy.h), + [memarea](@ref rte_memarea.h) - **timers**: [cycles](@ref rte_cycles.h), diff --git a/doc/api/doxy-api.conf.in b/doc/api/doxy-api.conf.in index f0886c3bd1..8334ebcbd6 100644 --- a/doc/api/doxy-api.conf.in +++ b/doc/api/doxy-api.conf.in @@ -53,6 +53,7 @@ INPUT = @TOPDIR@/doc/api/doxy-api-index.md \ @TOPDIR@/lib/latencystats \ @TOPDIR@/lib/lpm \ @TOPDIR@/lib/mbuf \ + @TOPDIR@/lib/memarea \ @TOPDIR@/lib/member \ @TOPDIR@/lib/mempool \ @TOPDIR@/lib/meter \ diff --git a/doc/guides/prog_guide/index.rst b/doc/guides/prog_guide/index.rst index 8564883018..e9015d65e3 100644 --- a/doc/guides/prog_guide/index.rst +++ b/doc/guides/prog_guide/index.rst @@ -37,6 +37,7 @@ Programmer's Guide hash_lib toeplitz_hash_lib efd_lib + memarea_lib member_lib lpm_lib lpm6_lib diff --git a/doc/guides/prog_guide/memarea_lib.rst b/doc/guides/prog_guide/memarea_lib.rst new file mode 100644 index 0000000000..3630328642 --- /dev/null +++ b/doc/guides/prog_guide/memarea_lib.rst @@ -0,0 +1,46 @@ +.. SPDX-License-Identifier: BSD-3-Clause + Copyright(c) 2023 HiSilicon Limited + +Memarea Library +=============== + +Introduction +------------ + +The memarea library provides an allocator of variable-size objects, it is +oriented towards the application layer, providing 'region-based memory +management' function [1]. + +The main features are as follows: + +* The memory region can be initialized from the following memory sources: + + - HEAP: e.g. invoke ``rte_malloc_socket``. + + - LIBC: e.g. invoke posix_memalign. + + - Another memarea: it can be allocated from another memarea. + +* It supports MT-safe as long as it's specified at creation time. + +Library API Overview +-------------------- + +The ``rte_memarea_create()`` function is used to create a memarea, the function +returns the pointer to the created memarea or ``NULL`` if the creation failed. + +The ``rte_memarea_destroy()`` function is used to destroy a memarea. + +Debug Mode +---------- + +In debug mode, cookies are added at the beginning and end of objects, it will +help debugging buffer overflows. + +Debug mode is disabled by default, but can be enabled by setting +``RTE_LIBRTE_MEMAREA_DEBUG`` in ``config/rte_config.h``. + +Reference +--------- + +[1] https://en.wikipedia.org/wiki/Region-based_memory_management diff --git a/doc/guides/rel_notes/release_23_03.rst b/doc/guides/rel_notes/release_23_03.rst index 1fa101c420..afc7cd3530 100644 --- a/doc/guides/rel_notes/release_23_03.rst +++ b/doc/guides/rel_notes/release_23_03.rst @@ -55,6 +55,12 @@ New Features Also, make sure to start the actual text at the margin. ======================================================= +* **Added memarea library.** + + The memarea library is an allocator of variable-size objects, it is oriented + towards the application layer, providing 'region-based memory management' + function. + * **Updated AMD axgbe driver.** * Added multi-process support. diff --git a/lib/memarea/memarea_private.h b/lib/memarea/memarea_private.h new file mode 100644 index 0000000000..c41d071032 --- /dev/null +++ b/lib/memarea/memarea_private.h @@ -0,0 +1,58 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 HiSilicon Limited + */ + +#ifndef MEMAREA_PRIVATE_H +#define MEMAREA_PRIVATE_H + +#include + +#define MEMAREA_OBJECT_SIZE_ALIGN 8 + +#define MEMAREA_OBJECT_HEADER_AVAILABLE_COOKIE 0xbeef1234beef1234ULL +#define MEMAREA_OBJECT_HEADER_ALLOCATED_COOKIE 0x12345678abcdef12ULL +#define MEMAREA_OBJECT_TRAILER_COOKIE 0xabcd1234abcd5678ULL + +#define MEMAREA_OBJECT_IS_ALLOCATED(hdr) (TAILQ_NEXT((hdr), avail_next) == (void *)-1) +#define MEMAREA_OBJECT_MARK_ALLOCATED(hdr) (TAILQ_NEXT((hdr), avail_next) = (void *)-1) + +#ifdef RTE_LIBRTE_MEMAREA_DEBUG +#define MEMAREA_OBJECT_GET_SIZE(hdr) \ + ((uintptr_t)TAILQ_NEXT((hdr), obj_next) - (uintptr_t)(hdr) - \ + sizeof(struct memarea_objhdr) - sizeof(struct memarea_objtlr)) +#else +#define MEMAREA_OBJECT_GET_SIZE(hdr) \ + ((uintptr_t)TAILQ_NEXT((hdr), obj_next) - (uintptr_t)(hdr) - \ + sizeof(struct memarea_objhdr)) +#endif + +struct memarea_objhdr { + /** The obj_next list is an address ascending ordered linked list. */ + TAILQ_ENTRY(memarea_objhdr) obj_next; + /** The avail_next list is an unordered linked list. If it's tqe_next + * is -1, means it has been allocated. + */ + TAILQ_ENTRY(memarea_objhdr) avail_next; +#ifdef RTE_LIBRTE_MEMAREA_DEBUG + uint64_t cookie; /**< Debug cookie */ +#endif +}; + +#ifdef RTE_LIBRTE_MEMAREA_DEBUG +struct memarea_objtlr { + uint64_t cookie; /**< Debug cookie */ +}; +#endif + +TAILQ_HEAD(memarea_objhdr_list, memarea_objhdr); + +struct rte_memarea { + struct rte_memarea_param init; + rte_spinlock_t lock; + void *area_base; + struct memarea_objhdr *guard_hdr; + struct memarea_objhdr_list obj_list; + struct memarea_objhdr_list avail_list; +} __rte_cache_aligned; + +#endif /* MEMAREA_PRIVATE_H */ diff --git a/lib/memarea/meson.build b/lib/memarea/meson.build new file mode 100644 index 0000000000..5d2632a38e --- /dev/null +++ b/lib/memarea/meson.build @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2023 HiSilicon Limited + +sources = files( + 'rte_memarea.c', +) +headers = files( + 'rte_memarea.h', +) +deps += [] diff --git a/lib/memarea/rte_memarea.c b/lib/memarea/rte_memarea.c new file mode 100644 index 0000000000..523f34eb41 --- /dev/null +++ b/lib/memarea/rte_memarea.c @@ -0,0 +1,171 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 HiSilicon Limited + */ + +#include +#include + +#include +#include +#include +#include + +#include "rte_memarea.h" +#include "memarea_private.h" + +RTE_LOG_REGISTER_DEFAULT(rte_memarea_logtype, INFO); +#define RTE_MEMAREA_LOG(level, ...) \ + rte_log(RTE_LOG_ ## level, rte_memarea_logtype, RTE_FMT("memarea: " \ + RTE_FMT_HEAD(__VA_ARGS__,) "\n", RTE_FMT_TAIL(__VA_ARGS__,))) + +static int +memarea_check_param(const struct rte_memarea_param *init) +{ +#define MEMAREA_MIN_SIZE 1024 + size_t len; + + if (init == NULL) { + RTE_MEMAREA_LOG(ERR, "init param is NULL!"); + return -EINVAL; + } + + len = strnlen(init->name, RTE_MEMAREA_NAMESIZE); + if (len == 0 || len >= RTE_MEMAREA_NAMESIZE) { + RTE_MEMAREA_LOG(ERR, "name size: %zu invalid!", len); + return -EINVAL; + } + + if (init->source != RTE_MEMAREA_SOURCE_HEAP && + init->source != RTE_MEMAREA_SOURCE_LIBC && + init->source != RTE_MEMAREA_SOURCE_MEMAREA) { + RTE_MEMAREA_LOG(ERR, "%s source: %d not supported!", + init->name, init->source); + return -EINVAL; + } + + if (init->total_sz < MEMAREA_MIN_SIZE) { + RTE_MEMAREA_LOG(ERR, "%s total-size: %zu too small!", + init->name, init->total_sz); + return -EINVAL; + } + + if (init->source == RTE_MEMAREA_SOURCE_MEMAREA && init->src_ma == NULL) { + RTE_MEMAREA_LOG(ERR, "%s source memarea is NULL!", init->name); + return -EINVAL; + } + + if (init->alg != RTE_MEMAREA_ALGORITHM_NEXTFIT) { + RTE_MEMAREA_LOG(ERR, "%s algorithm: %d not supported!", + init->name, init->alg); + return -EINVAL; + } + + return 0; +} + +static void * +memarea_alloc_from_libc(size_t size) +{ +#ifdef RTE_EXEC_ENV_WINDOWS + return _aligned_malloc(size, RTE_CACHE_LINE_SIZE); +#else + void *ptr = NULL; + int ret; + ret = posix_memalign(&ptr, RTE_CACHE_LINE_SIZE, size); + if (ret) + return NULL; + return ptr; + #endif +} + +static void * +memarea_alloc_area(const struct rte_memarea_param *init) +{ + void *ptr = NULL; + + if (init->source == RTE_MEMAREA_SOURCE_HEAP) + ptr = rte_malloc_socket(NULL, init->total_sz, RTE_CACHE_LINE_SIZE, + init->numa_socket); + else if (init->source == RTE_MEMAREA_SOURCE_LIBC) + ptr = memarea_alloc_from_libc(init->total_sz); + + return ptr; +} + +static void +memarea_free_area(const struct rte_memarea_param *init, void *ptr) +{ + if (init->source == RTE_MEMAREA_SOURCE_HEAP) + rte_free(ptr); + else if (init->source == RTE_MEMAREA_SOURCE_LIBC) + free(ptr); +} + +struct rte_memarea * +rte_memarea_create(const struct rte_memarea_param *init) +{ + struct memarea_objhdr *hdr, *guard_hdr; +#ifdef RTE_LIBRTE_MEMAREA_DEBUG + struct memarea_objtlr *tlr; +#endif + struct rte_memarea *ma; + size_t align_sz; + void *ptr; + int ret; + + ret = memarea_check_param(init); + if (ret) + return NULL; + + ptr = memarea_alloc_area(init); + if (ptr == NULL) { + RTE_MEMAREA_LOG(ERR, "%s alloc memory area fail!", init->name); + return NULL; + } + + ma = rte_zmalloc(NULL, sizeof(struct rte_memarea), RTE_CACHE_LINE_SIZE); + if (ma == NULL) { + memarea_free_area(init, ptr); + RTE_MEMAREA_LOG(ERR, "malloc %s management object fail!", init->name); + return NULL; + } + + hdr = ptr; + align_sz = RTE_ALIGN_FLOOR(init->total_sz, MEMAREA_OBJECT_SIZE_ALIGN); + guard_hdr = RTE_PTR_ADD(ptr, align_sz - sizeof(struct memarea_objhdr)); + + ma->init = *init; + rte_spinlock_init(&ma->lock); + ma->area_base = ptr; + ma->guard_hdr = guard_hdr; + TAILQ_INIT(&ma->obj_list); + TAILQ_INIT(&ma->avail_list); + + TAILQ_INSERT_TAIL(&ma->obj_list, hdr, obj_next); + TAILQ_INSERT_TAIL(&ma->avail_list, hdr, avail_next); +#ifdef RTE_LIBRTE_MEMAREA_DEBUG + hdr->cookie = MEMAREA_OBJECT_HEADER_AVAILABLE_COOKIE; + tlr = RTE_PTR_SUB(guard_hdr, sizeof(struct memarea_objtlr)); + tlr->cookie = MEMAREA_OBJECT_TRAILER_COOKIE; +#endif + + memset(guard_hdr, 0, sizeof(struct memarea_objhdr)); + TAILQ_INSERT_AFTER(&ma->obj_list, hdr, guard_hdr, obj_next); + MEMAREA_OBJECT_MARK_ALLOCATED(guard_hdr); +#ifdef RTE_LIBRTE_MEMAREA_DEBUG + guard_hdr->cookie = MEMAREA_OBJECT_HEADER_ALLOCATED_COOKIE; + /* The guard object have no trailer cookie. */ +#endif + + return ma; +} + +void +rte_memarea_destroy(struct rte_memarea *ma) +{ + if (ma == NULL) + return; + memarea_free_area(&ma->init, ma->area_base); + rte_free(ma); +} + diff --git a/lib/memarea/rte_memarea.h b/lib/memarea/rte_memarea.h new file mode 100644 index 0000000000..435dca293f --- /dev/null +++ b/lib/memarea/rte_memarea.h @@ -0,0 +1,122 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 HiSilicon Limited + */ + +#ifndef RTE_MEMAREA_H +#define RTE_MEMAREA_H + +/** + * @file + * RTE Memarea. + * + * The memarea is an allocator of variable-size object which based on a memory + * region. It has the following features: + * + * - The memory region can be initialized from the following memory sources: + * 1. HEAP: e.g. invoke rte_malloc_socket. + * 2. LIBC: e.g. invoke posix_memalign. + * 3. Another memarea: it can be allocated from another memarea. + * + * - It supports MT-safe as long as it's specified at creation time. If not + * specified, all the functions of the memarea API are lock-free, and assume + * to not be invoked in parallel on different logical cores to work on the + * same memarea. + */ + +#include +#include +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define RTE_MEMAREA_NAMESIZE 64 + +/** + * Memarea memory source. + */ +enum rte_memarea_source { + /** Memory source comes from rte memory. */ + RTE_MEMAREA_SOURCE_HEAP, + /** Memory source comes from libc. */ + RTE_MEMAREA_SOURCE_LIBC, + /** Memory source comes from another memarea. */ + RTE_MEMAREA_SOURCE_MEMAREA, +}; + +/** + * Memarea memory management algorithm. + */ +enum rte_memarea_algorithm { + /** The default management algorithm is a variant of the next fit + * algorithm. It uses a free-list to apply for memory and uses an + * object-list in ascending order of address to support merging + * upon free. + */ + RTE_MEMAREA_ALGORITHM_NEXTFIT, +}; + +struct rte_memarea; + +/** + * Memarea creation parameters. + */ +struct rte_memarea_param { + char name[RTE_MEMAREA_NAMESIZE]; /**< Name of memarea. */ + enum rte_memarea_source source; /**< Memory source of memarea. */ + enum rte_memarea_algorithm alg; /**< Memory management algorithm. */ + size_t total_sz; /**< Total size (bytes) of memarea. */ + /** Indicates whether the memarea API should be MT-safe. */ + uint32_t mt_safe : 1; + union { + /** Numa socket from which to apply for memarea's memory, this + * field is valid only when the source is set to be + * RTE_MEMAREA_SOURCE_HEAP. + */ + int numa_socket; + /** Source memarea, this field is valid only when the source is + * set to be RTE_MEMAREA_SOURCE_MEMAREA. + */ + struct rte_memarea *src_ma; + }; +}; + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice. + * + * Create memarea. + * + * Create one new memarea. + * + * @param init + * The init parameter of memarea. + * + * @return + * Non-NULL on success. Otherwise NULL is returned. + */ +__rte_experimental +struct rte_memarea *rte_memarea_create(const struct rte_memarea_param *init); + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice. + * + * Destroy memarea. + * + * Destroy the memarea. + * + * @param ma + * The pointer of memarea. + */ +__rte_experimental +void rte_memarea_destroy(struct rte_memarea *ma); + +#ifdef __cplusplus +} +#endif + +#endif /* RTE_MEMAREA_H */ diff --git a/lib/memarea/version.map b/lib/memarea/version.map new file mode 100644 index 0000000000..f36a04d7cf --- /dev/null +++ b/lib/memarea/version.map @@ -0,0 +1,12 @@ +EXPERIMENTAL { + global: + + rte_memarea_create; + rte_memarea_destroy; + + local: *; +}; + +INTERNAL { + local: *; +}; diff --git a/lib/meson.build b/lib/meson.build index a90fee31b7..f561875305 100644 --- a/lib/meson.build +++ b/lib/meson.build @@ -42,6 +42,7 @@ libraries = [ 'kni', 'latencystats', 'lpm', + 'memarea', 'member', 'pcapng', 'power', From patchwork Wed Feb 8 08:24:48 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: fengchengwen X-Patchwork-Id: 123430 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id E2B6441C3C; Wed, 8 Feb 2023 09:31:06 +0100 (CET) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id BA43442B7E; Wed, 8 Feb 2023 09:30:58 +0100 (CET) Received: from szxga08-in.huawei.com (szxga08-in.huawei.com [45.249.212.255]) by mails.dpdk.org (Postfix) with ESMTP id DEBEB40EE1 for ; Wed, 8 Feb 2023 09:30:55 +0100 (CET) Received: from dggpeml500024.china.huawei.com (unknown [172.30.72.54]) by szxga08-in.huawei.com (SkyGuard) with ESMTP id 4PBY6y3Gd4z16NTb; Wed, 8 Feb 2023 16:28:42 +0800 (CST) Received: from localhost.localdomain (10.50.163.32) by dggpeml500024.china.huawei.com (7.185.36.10) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.34; Wed, 8 Feb 2023 16:30:53 +0800 From: Chengwen Feng To: , , , , , CC: , Subject: [PATCH v13 2/6] test/memarea: support memarea test Date: Wed, 8 Feb 2023 08:24:48 +0000 Message-ID: <20230208082452.43883-3-fengchengwen@huawei.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20230208082452.43883-1-fengchengwen@huawei.com> References: <20220721044648.6817-1-fengchengwen@huawei.com> <20230208082452.43883-1-fengchengwen@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.50.163.32] X-ClientProxiedBy: dggems701-chm.china.huawei.com (10.3.19.178) To dggpeml500024.china.huawei.com (7.185.36.10) X-CFilter-Loop: Reflected X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org This patch supports memarea test of rte_memarea_create() and rte_memarea_destroy() API. Signed-off-by: Chengwen Feng Reviewed-by: Dongdong Liu Acked-by: Morten Brørup --- MAINTAINERS | 1 + app/test/meson.build | 2 + app/test/test_memarea.c | 130 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 133 insertions(+) create mode 100644 app/test/test_memarea.c diff --git a/MAINTAINERS b/MAINTAINERS index 60078ffc72..4bd47fb478 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1579,6 +1579,7 @@ Memarea - EXPERIMENTAL M: Chengwen Feng F: lib/memarea F: doc/guides/prog_guide/memarea_lib.rst +F: app/test/test_memarea* Membership - EXPERIMENTAL M: Yipeng Wang diff --git a/app/test/meson.build b/app/test/meson.build index f34d19e3c3..fde0155cf9 100644 --- a/app/test/meson.build +++ b/app/test/meson.build @@ -84,6 +84,7 @@ test_sources = files( 'test_malloc.c', 'test_malloc_perf.c', 'test_mbuf.c', + 'test_memarea.c', 'test_member.c', 'test_member_perf.c', 'test_memcpy.c', @@ -200,6 +201,7 @@ fast_tests = [ ['malloc_autotest', false, true], ['mbuf_autotest', false, true], ['mcslock_autotest', false, true], + ['memarea_autotest', true, true], ['memcpy_autotest', true, true], ['memory_autotest', false, true], ['mempool_autotest', false, true], diff --git a/app/test/test_memarea.c b/app/test/test_memarea.c new file mode 100644 index 0000000000..db5efc4c1b --- /dev/null +++ b/app/test/test_memarea.c @@ -0,0 +1,130 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2023 HiSilicon Limited + */ + +#include +#include + +#include "test.h" + +#include +#include + +#define MEMAREA_TEST_DEFAULT_SIZE 0x1000 + +#define MEMAREA_TEST_API_RUN(test_func) \ + do { \ + int ret = test_func(); \ + if (ret < 0) { \ + printf("%s Failed\n", #test_func); \ + fails++; \ + } else { \ + printf("%s Passed\n", #test_func); \ + } \ + } while (0) + +static int fails; + +static void +test_memarea_prepare(void) +{ + fails = 0; +} + +static int +test_memarea_retcode(void) +{ + return fails > 0 ? -1 : 0; +} + +static void +test_memarea_init_param(struct rte_memarea_param *init) +{ + memset(init, 0, sizeof(struct rte_memarea_param)); + sprintf(init->name, "%s", "autotest"); + init->source = RTE_MEMAREA_SOURCE_LIBC; + init->total_sz = MEMAREA_TEST_DEFAULT_SIZE; + init->mt_safe = 1; +} + +static int +test_memarea_create_bad_param(void) +{ + struct rte_memarea_param init; + struct rte_memarea *ma; + + /* test for NULL */ + ma = rte_memarea_create(NULL); + RTE_TEST_ASSERT(ma == NULL, "Expected NULL"); + + /* test for invalid name */ + memset(&init, 0, sizeof(init)); + ma = rte_memarea_create(&init); + RTE_TEST_ASSERT(ma == NULL, "Expected NULL"); + memset(&init.name, 1, sizeof(init.name)); + ma = rte_memarea_create(&init); + RTE_TEST_ASSERT(ma == NULL, "Expected NULL"); + + /* test for invalid source */ + test_memarea_init_param(&init); + init.source = RTE_MEMAREA_SOURCE_MEMAREA + 1; + ma = rte_memarea_create(&init); + RTE_TEST_ASSERT(ma == NULL, "Expected NULL"); + + /* test for total_sz */ + test_memarea_init_param(&init); + init.total_sz = 0; + ma = rte_memarea_create(&init); + RTE_TEST_ASSERT(ma == NULL, "Expected NULL"); + + /* test for memarea NULL */ + test_memarea_init_param(&init); + init.source = RTE_MEMAREA_SOURCE_MEMAREA; + ma = rte_memarea_create(&init); + RTE_TEST_ASSERT(ma == NULL, "Expected NULL"); + + /* test for algorithm invalid */ + test_memarea_init_param(&init); + init.alg = RTE_MEMAREA_ALGORITHM_NEXTFIT + 1; + ma = rte_memarea_create(&init); + RTE_TEST_ASSERT(ma == NULL, "Expected NULL"); + + return 0; +} + +static int +test_memarea_create_destroy(void) +{ + struct rte_memarea_param init; + struct rte_memarea *ma; + + /* test for create with HEAP */ + test_memarea_init_param(&init); + init.source = RTE_MEMAREA_SOURCE_HEAP; + init.numa_socket = SOCKET_ID_ANY; + ma = rte_memarea_create(&init); + RTE_TEST_ASSERT(ma != NULL, "Expected Non-NULL"); + rte_memarea_destroy(ma); + + /* test for create with LIBC */ + test_memarea_init_param(&init); + init.source = RTE_MEMAREA_SOURCE_LIBC; + ma = rte_memarea_create(&init); + RTE_TEST_ASSERT(ma != NULL, "Expected Non-NULL"); + rte_memarea_destroy(ma); + + return 0; +} + +static int +test_memarea(void) +{ + test_memarea_prepare(); + + MEMAREA_TEST_API_RUN(test_memarea_create_bad_param); + MEMAREA_TEST_API_RUN(test_memarea_create_destroy); + + return test_memarea_retcode(); +} + +REGISTER_TEST_COMMAND(memarea_autotest, test_memarea); From patchwork Wed Feb 8 08:24:49 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: fengchengwen X-Patchwork-Id: 123433 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 0D9B541C3C; Wed, 8 Feb 2023 09:31:26 +0100 (CET) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id DF53A42D16; Wed, 8 Feb 2023 09:31:01 +0100 (CET) Received: from szxga02-in.huawei.com (szxga02-in.huawei.com [45.249.212.188]) by mails.dpdk.org (Postfix) with ESMTP id 009E7410EE for ; Wed, 8 Feb 2023 09:30:55 +0100 (CET) Received: from dggpeml500024.china.huawei.com (unknown [172.30.72.56]) by szxga02-in.huawei.com (SkyGuard) with ESMTP id 4PBY7X24fczJsGX; Wed, 8 Feb 2023 16:29:12 +0800 (CST) Received: from localhost.localdomain (10.50.163.32) by dggpeml500024.china.huawei.com (7.185.36.10) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.34; Wed, 8 Feb 2023 16:30:53 +0800 From: Chengwen Feng To: , , , , , CC: , Subject: [PATCH v13 3/6] memarea: support alloc and free API Date: Wed, 8 Feb 2023 08:24:49 +0000 Message-ID: <20230208082452.43883-4-fengchengwen@huawei.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20230208082452.43883-1-fengchengwen@huawei.com> References: <20220721044648.6817-1-fengchengwen@huawei.com> <20230208082452.43883-1-fengchengwen@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.50.163.32] X-ClientProxiedBy: dggems701-chm.china.huawei.com (10.3.19.178) To dggpeml500024.china.huawei.com (7.185.36.10) X-CFilter-Loop: Reflected X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org This patch supports rte_memarea_alloc() and rte_memarea_free() API. Signed-off-by: Chengwen Feng Reviewed-by: Dongdong Liu Acked-by: Morten Brørup --- doc/guides/prog_guide/memarea_lib.rst | 6 + lib/memarea/rte_memarea.c | 180 ++++++++++++++++++++++++++ lib/memarea/rte_memarea.h | 42 ++++++ lib/memarea/version.map | 2 + 4 files changed, 230 insertions(+) diff --git a/doc/guides/prog_guide/memarea_lib.rst b/doc/guides/prog_guide/memarea_lib.rst index 3630328642..55ca4b1166 100644 --- a/doc/guides/prog_guide/memarea_lib.rst +++ b/doc/guides/prog_guide/memarea_lib.rst @@ -31,6 +31,12 @@ returns the pointer to the created memarea or ``NULL`` if the creation failed. The ``rte_memarea_destroy()`` function is used to destroy a memarea. +The ``rte_memarea_alloc()`` function is used to alloc one memory object from +the memarea. + +The ``rte_memarea_free()`` function is used to free one memory object which +allocated by ``rte_memarea_alloc()``. + Debug Mode ---------- diff --git a/lib/memarea/rte_memarea.c b/lib/memarea/rte_memarea.c index 523f34eb41..158e24b7f3 100644 --- a/lib/memarea/rte_memarea.c +++ b/lib/memarea/rte_memarea.c @@ -2,8 +2,10 @@ * Copyright(c) 2023 HiSilicon Limited */ +#include #include #include +#include #include #include @@ -88,6 +90,8 @@ memarea_alloc_area(const struct rte_memarea_param *init) init->numa_socket); else if (init->source == RTE_MEMAREA_SOURCE_LIBC) ptr = memarea_alloc_from_libc(init->total_sz); + else if (init->source == RTE_MEMAREA_SOURCE_MEMAREA) + ptr = rte_memarea_alloc(init->src_ma, init->total_sz); return ptr; } @@ -99,6 +103,8 @@ memarea_free_area(const struct rte_memarea_param *init, void *ptr) rte_free(ptr); else if (init->source == RTE_MEMAREA_SOURCE_LIBC) free(ptr); + else if (init->source == RTE_MEMAREA_SOURCE_MEMAREA) + rte_memarea_free(init->src_ma, ptr); } struct rte_memarea * @@ -169,3 +175,177 @@ rte_memarea_destroy(struct rte_memarea *ma) rte_free(ma); } +static inline void +memarea_lock(struct rte_memarea *ma) +{ + if (ma->init.mt_safe) + rte_spinlock_lock(&ma->lock); +} + +static inline void +memarea_unlock(struct rte_memarea *ma) +{ + if (ma->init.mt_safe) + rte_spinlock_unlock(&ma->lock); +} + +/** + * Check cookie or panic. + * + * @param status + * - 0: object is supposed to be available + * - 1: object is supposed to be allocated + * - 2: just check that cookie is valid (available or allocated) + */ +static inline void +memarea_check_cookie(const struct rte_memarea *ma, const struct memarea_objhdr *hdr, int status) +{ +#ifdef RTE_LIBRTE_MEMAREA_DEBUG + static const char *const str[] = { " PASS", " FAILED" }; + struct memarea_objtlr *tlr; + bool hdr_fail, tlr_fail; + + if (unlikely(hdr == ma->guard_hdr)) + return; + + tlr = RTE_PTR_SUB(TAILQ_NEXT(hdr, obj_next), sizeof(struct memarea_objtlr)); + hdr_fail = (status == 0 && hdr->cookie != MEMAREA_OBJECT_HEADER_AVAILABLE_COOKIE) || + (status == 1 && hdr->cookie != MEMAREA_OBJECT_HEADER_ALLOCATED_COOKIE) || + (status == 2 && (hdr->cookie != MEMAREA_OBJECT_HEADER_AVAILABLE_COOKIE && + hdr->cookie != MEMAREA_OBJECT_HEADER_ALLOCATED_COOKIE)); + tlr_fail = (tlr->cookie != MEMAREA_OBJECT_TRAILER_COOKIE); + if (!hdr_fail && !tlr_fail) + return; + + rte_panic("MEMAREA: %s check cookies failed! addr-%p header-cookie<0x%" PRIx64 "%s> trailer-cookie<0x%" PRIx64 "%s>\n", + ma->init.name, RTE_PTR_ADD(hdr, sizeof(struct memarea_objhdr)), + hdr->cookie, str[hdr_fail], tlr->cookie, str[tlr_fail]); +#else + RTE_SET_USED(ma); + RTE_SET_USED(hdr); + RTE_SET_USED(status); +#endif +} + +static inline bool +memarea_whether_add_node(size_t avail_sz, size_t alloc_sz) +{ + return (avail_sz - alloc_sz) > (sizeof(struct memarea_objhdr) + + MEMAREA_OBJECT_SIZE_ALIGN +#ifdef RTE_LIBRTE_MEMAREA_DEBUG + + sizeof(struct memarea_objtlr) + +#endif + ); +} + +static inline void +memarea_add_node(struct rte_memarea *ma, struct memarea_objhdr *hdr, size_t alloc_sz) +{ +#ifdef RTE_LIBRTE_MEMAREA_DEBUG + struct memarea_objtlr *cur_tlr; +#endif + struct memarea_objhdr *new_hdr; + +#ifdef RTE_LIBRTE_MEMAREA_DEBUG + cur_tlr = RTE_PTR_ADD(hdr, sizeof(struct memarea_objhdr) + alloc_sz); + cur_tlr->cookie = MEMAREA_OBJECT_TRAILER_COOKIE; + new_hdr = RTE_PTR_ADD(cur_tlr, sizeof(struct memarea_objtlr)); + new_hdr->cookie = MEMAREA_OBJECT_HEADER_AVAILABLE_COOKIE; +#else + new_hdr = RTE_PTR_ADD(hdr, sizeof(struct memarea_objhdr) + alloc_sz); +#endif + TAILQ_INSERT_AFTER(&ma->obj_list, hdr, new_hdr, obj_next); + TAILQ_INSERT_AFTER(&ma->avail_list, hdr, new_hdr, avail_next); +} + +void * +rte_memarea_alloc(struct rte_memarea *ma, size_t size) +{ + size_t align_sz = RTE_ALIGN(size, MEMAREA_OBJECT_SIZE_ALIGN); + struct memarea_objhdr *hdr; + size_t avail_sz; + void *ptr = NULL; + + if (unlikely(ma == NULL || size == 0 || align_sz < size)) + return ptr; + + memarea_lock(ma); + TAILQ_FOREACH(hdr, &ma->avail_list, avail_next) { + memarea_check_cookie(ma, hdr, 0); + avail_sz = MEMAREA_OBJECT_GET_SIZE(hdr); + if (avail_sz < align_sz) + continue; + if (memarea_whether_add_node(avail_sz, align_sz)) + memarea_add_node(ma, hdr, align_sz); + TAILQ_REMOVE(&ma->avail_list, hdr, avail_next); + MEMAREA_OBJECT_MARK_ALLOCATED(hdr); +#ifdef RTE_LIBRTE_MEMAREA_DEBUG + hdr->cookie = MEMAREA_OBJECT_HEADER_ALLOCATED_COOKIE; +#endif + ptr = RTE_PTR_ADD(hdr, sizeof(struct memarea_objhdr)); + break; + } + memarea_unlock(ma); + + return ptr; +} + +static inline void +memarea_merge_node(struct rte_memarea *ma, struct memarea_objhdr *curr, + struct memarea_objhdr *next) +{ +#ifdef RTE_LIBRTE_MEMAREA_DEBUG + struct memarea_objtlr *tlr; +#endif + RTE_SET_USED(curr); + TAILQ_REMOVE(&ma->obj_list, next, obj_next); + TAILQ_REMOVE(&ma->avail_list, next, avail_next); +#ifdef RTE_LIBRTE_MEMAREA_DEBUG + next->cookie = 0; + tlr = RTE_PTR_SUB(next, sizeof(struct memarea_objtlr)); + tlr->cookie = 0; +#endif +} + +void +rte_memarea_free(struct rte_memarea *ma, void *ptr) +{ + struct memarea_objhdr *hdr, *prev, *next; + + if (unlikely(ma == NULL || ptr == NULL)) + return; + + hdr = RTE_PTR_SUB(ptr, sizeof(struct memarea_objhdr)); + if (unlikely(!MEMAREA_OBJECT_IS_ALLOCATED(hdr))) { + RTE_MEMAREA_LOG(ERR, "detect invalid object when free!"); + return; + } + memarea_check_cookie(ma, hdr, 1); + + memarea_lock(ma); + + /** 1st: add to avail list. */ +#ifdef RTE_LIBRTE_MEMAREA_DEBUG + hdr->cookie = MEMAREA_OBJECT_HEADER_AVAILABLE_COOKIE; +#endif + TAILQ_INSERT_HEAD(&ma->avail_list, hdr, avail_next); + + /** 2nd: merge if previous object is avail. */ + prev = TAILQ_PREV(hdr, memarea_objhdr_list, obj_next); + if (prev != NULL && !MEMAREA_OBJECT_IS_ALLOCATED(prev)) { + memarea_check_cookie(ma, prev, 0); + memarea_merge_node(ma, prev, hdr); + hdr = prev; + } + + /** 3rd: merge if next object is avail. */ + next = TAILQ_NEXT(hdr, obj_next); + if (next != NULL && !MEMAREA_OBJECT_IS_ALLOCATED(next)) { + memarea_check_cookie(ma, next, 0); + memarea_merge_node(ma, hdr, next); + } + + memarea_unlock(ma); +} + diff --git a/lib/memarea/rte_memarea.h b/lib/memarea/rte_memarea.h index 435dca293f..02b4825461 100644 --- a/lib/memarea/rte_memarea.h +++ b/lib/memarea/rte_memarea.h @@ -115,6 +115,48 @@ struct rte_memarea *rte_memarea_create(const struct rte_memarea_param *init); __rte_experimental void rte_memarea_destroy(struct rte_memarea *ma); +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice. + * + * Allocate memory from memarea. + * + * Allocate one memory object from the memarea. + * + * @param ma + * The pointer of memarea. + * @param size + * The memory size to be allocated. + * + * @return + * - NULL on error. Not enough memory, or invalid arguments (ma is NULL, + * size is 0). + * - Otherwise, the pointer to the allocated object. + */ +__rte_experimental +void *rte_memarea_alloc(struct rte_memarea *ma, size_t size); + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice. + * + * Free memory to memarea. + * + * Free one memory object to the memarea. + * @note The memory object must have been returned by a previous call to + * rte_memarea_alloc(), it must be freed to the same memarea which previous + * allocated from. The behaviour of rte_memarea_free() is undefined if the + * memarea or pointer does not match these requirements. + * + * @param ma + * The pointer of memarea. If the ma is NULL, the function does nothing. + * @param ptr + * The pointer of memory object which need be freed. If the pointer is NULL, + * the function does nothing. + */ +__rte_experimental +void rte_memarea_free(struct rte_memarea *ma, void *ptr); + #ifdef __cplusplus } #endif diff --git a/lib/memarea/version.map b/lib/memarea/version.map index f36a04d7cf..effbd0b488 100644 --- a/lib/memarea/version.map +++ b/lib/memarea/version.map @@ -1,8 +1,10 @@ EXPERIMENTAL { global: + rte_memarea_alloc; rte_memarea_create; rte_memarea_destroy; + rte_memarea_free; local: *; }; From patchwork Wed Feb 8 08:24:50 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: fengchengwen X-Patchwork-Id: 123428 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 8A98C41C3C; Wed, 8 Feb 2023 09:30:56 +0100 (CET) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 72EC7427F2; Wed, 8 Feb 2023 09:30:56 +0100 (CET) Received: from szxga02-in.huawei.com (szxga02-in.huawei.com [45.249.212.188]) by mails.dpdk.org (Postfix) with ESMTP id 4DF6440141 for ; Wed, 8 Feb 2023 09:30:55 +0100 (CET) Received: from dggpeml500024.china.huawei.com (unknown [172.30.72.57]) by szxga02-in.huawei.com (SkyGuard) with ESMTP id 4PBY6k5DmczRrxG; Wed, 8 Feb 2023 16:28:30 +0800 (CST) Received: from localhost.localdomain (10.50.163.32) by dggpeml500024.china.huawei.com (7.185.36.10) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.34; Wed, 8 Feb 2023 16:30:53 +0800 From: Chengwen Feng To: , , , , , CC: , Subject: [PATCH v13 4/6] test/memarea: support alloc and free API test Date: Wed, 8 Feb 2023 08:24:50 +0000 Message-ID: <20230208082452.43883-5-fengchengwen@huawei.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20230208082452.43883-1-fengchengwen@huawei.com> References: <20220721044648.6817-1-fengchengwen@huawei.com> <20230208082452.43883-1-fengchengwen@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.50.163.32] X-ClientProxiedBy: dggems701-chm.china.huawei.com (10.3.19.178) To dggpeml500024.china.huawei.com (7.185.36.10) X-CFilter-Loop: Reflected X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org This patch supports rte_memarea_alloc() and rte_memarea_free() API test. Signed-off-by: Chengwen Feng Reviewed-by: Dongdong Liu Acked-by: Morten Brørup --- app/test/test_memarea.c | 135 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 134 insertions(+), 1 deletion(-) diff --git a/app/test/test_memarea.c b/app/test/test_memarea.c index db5efc4c1b..3e67e59227 100644 --- a/app/test/test_memarea.c +++ b/app/test/test_memarea.c @@ -47,6 +47,12 @@ test_memarea_init_param(struct rte_memarea_param *init) init->mt_safe = 1; } +static void +test_memarea_fill_region(void *ptr, size_t size) +{ + memset(ptr, 0xff, size); +} + static int test_memarea_create_bad_param(void) { @@ -95,8 +101,8 @@ test_memarea_create_bad_param(void) static int test_memarea_create_destroy(void) { + struct rte_memarea *ma, *src_ma; struct rte_memarea_param init; - struct rte_memarea *ma; /* test for create with HEAP */ test_memarea_init_param(&init); @@ -113,6 +119,130 @@ test_memarea_create_destroy(void) RTE_TEST_ASSERT(ma != NULL, "Expected Non-NULL"); rte_memarea_destroy(ma); + /* test for create with another memarea */ + test_memarea_init_param(&init); + init.source = RTE_MEMAREA_SOURCE_LIBC; + src_ma = rte_memarea_create(&init); + RTE_TEST_ASSERT(src_ma != NULL, "Expected Non-NULL"); + test_memarea_init_param(&init); + init.source = RTE_MEMAREA_SOURCE_MEMAREA; + init.total_sz = init.total_sz >> 1; + init.src_ma = src_ma; + ma = rte_memarea_create(&init); + RTE_TEST_ASSERT(ma != NULL, "Expected Non-NULL"); + rte_memarea_destroy(ma); + rte_memarea_destroy(src_ma); + + return 0; +} + +static int +test_memarea_alloc_fail(void) +{ + struct rte_memarea_param init; + struct rte_memarea *ma; + void *ptr[2]; + + test_memarea_init_param(&init); + init.source = RTE_MEMAREA_SOURCE_LIBC; + init.total_sz = MEMAREA_TEST_DEFAULT_SIZE; + ma = rte_memarea_create(&init); + RTE_TEST_ASSERT(ma != NULL, "Expected Non-NULL"); + + /* test alloc fail with big size */ + ptr[0] = rte_memarea_alloc(ma, MEMAREA_TEST_DEFAULT_SIZE); + RTE_TEST_ASSERT(ptr[0] == NULL, "Expected NULL"); + + /* test alloc fail because no memory */ + ptr[0] = rte_memarea_alloc(ma, MEMAREA_TEST_DEFAULT_SIZE >> 1); + RTE_TEST_ASSERT(ptr[0] != NULL, "Expected Non-NULL"); + ptr[1] = rte_memarea_alloc(ma, MEMAREA_TEST_DEFAULT_SIZE >> 1); + RTE_TEST_ASSERT(ptr[1] == NULL, "Expected NULL"); + rte_memarea_free(ma, ptr[0]); + + /* test alloc fail when second fail */ + ptr[0] = rte_memarea_alloc(ma, MEMAREA_TEST_DEFAULT_SIZE >> 1); + RTE_TEST_ASSERT(ptr[0] != NULL, "Expected Non-NULL"); + test_memarea_fill_region(ptr[0], MEMAREA_TEST_DEFAULT_SIZE >> 1); + ptr[1] = rte_memarea_alloc(ma, MEMAREA_TEST_DEFAULT_SIZE >> 1); + RTE_TEST_ASSERT(ptr[1] == NULL, "Expected NULL"); + rte_memarea_free(ma, ptr[0]); + ptr[1] = rte_memarea_alloc(ma, MEMAREA_TEST_DEFAULT_SIZE >> 1); + RTE_TEST_ASSERT(ptr[1] != NULL, "Expected Non-NULL"); + test_memarea_fill_region(ptr[1], MEMAREA_TEST_DEFAULT_SIZE >> 1); + rte_memarea_free(ma, ptr[1]); + + rte_memarea_destroy(ma); + + return 0; +} + +static int +test_memarea_free_fail(void) +{ + struct rte_memarea_param init; + struct rte_memarea *ma; + void *ptr; + + test_memarea_init_param(&init); + init.source = RTE_MEMAREA_SOURCE_LIBC; + init.total_sz = MEMAREA_TEST_DEFAULT_SIZE; + ma = rte_memarea_create(&init); + RTE_TEST_ASSERT(ma != NULL, "Expected Non-NULL"); + + /* test repeat free */ + ptr = rte_memarea_alloc(ma, MEMAREA_TEST_DEFAULT_SIZE >> 1); + RTE_TEST_ASSERT(ptr != NULL, "Expected Non-NULL"); + test_memarea_fill_region(ptr, MEMAREA_TEST_DEFAULT_SIZE >> 1); + rte_memarea_free(ma, ptr); + rte_memarea_free(ma, ptr); + + rte_memarea_destroy(ma); + + return 0; +} + +static int +test_memarea_alloc_free(void) +{ +#define ALLOC_MAX_NUM 8 + struct rte_memarea_param init; + void *ptr[ALLOC_MAX_NUM]; + struct rte_memarea *ma; + int i; + + test_memarea_init_param(&init); + init.source = RTE_MEMAREA_SOURCE_LIBC; + init.total_sz = MEMAREA_TEST_DEFAULT_SIZE; + ma = rte_memarea_create(&init); + RTE_TEST_ASSERT(ma != NULL, "Expected Non-NULL"); + memset(ptr, 0, sizeof(ptr)); + + /* test random alloc and free */ + for (i = 0; i < ALLOC_MAX_NUM; i++) + ptr[i] = rte_memarea_alloc(ma, 1); + + /* test merge left */ + rte_memarea_free(ma, ptr[0]); + rte_memarea_free(ma, ptr[1]); + + /* test merge right */ + rte_memarea_free(ma, ptr[7]); + rte_memarea_free(ma, ptr[6]); + + /* test merge left and right */ + rte_memarea_free(ma, ptr[3]); + rte_memarea_free(ma, ptr[2]); + + /* test merge remains */ + rte_memarea_free(ma, ptr[4]); + rte_memarea_free(ma, ptr[5]); + + /* test free NULL */ + rte_memarea_free(ma, NULL); + + rte_memarea_destroy(ma); + return 0; } @@ -123,6 +253,9 @@ test_memarea(void) MEMAREA_TEST_API_RUN(test_memarea_create_bad_param); MEMAREA_TEST_API_RUN(test_memarea_create_destroy); + MEMAREA_TEST_API_RUN(test_memarea_alloc_fail); + MEMAREA_TEST_API_RUN(test_memarea_free_fail); + MEMAREA_TEST_API_RUN(test_memarea_alloc_free); return test_memarea_retcode(); } From patchwork Wed Feb 8 08:24:51 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: fengchengwen X-Patchwork-Id: 123434 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id E047741C3C; Wed, 8 Feb 2023 09:31:31 +0100 (CET) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 0547842D20; Wed, 8 Feb 2023 09:31:03 +0100 (CET) Received: from szxga08-in.huawei.com (szxga08-in.huawei.com [45.249.212.255]) by mails.dpdk.org (Postfix) with ESMTP id 35EAF42670 for ; Wed, 8 Feb 2023 09:30:56 +0100 (CET) Received: from dggpeml500024.china.huawei.com (unknown [172.30.72.53]) by szxga08-in.huawei.com (SkyGuard) with ESMTP id 4PBY6y6Gt9z16Mr2; Wed, 8 Feb 2023 16:28:42 +0800 (CST) Received: from localhost.localdomain (10.50.163.32) by dggpeml500024.china.huawei.com (7.185.36.10) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.34; Wed, 8 Feb 2023 16:30:53 +0800 From: Chengwen Feng To: , , , , , CC: , Subject: [PATCH v13 5/6] memarea: support dump API Date: Wed, 8 Feb 2023 08:24:51 +0000 Message-ID: <20230208082452.43883-6-fengchengwen@huawei.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20230208082452.43883-1-fengchengwen@huawei.com> References: <20220721044648.6817-1-fengchengwen@huawei.com> <20230208082452.43883-1-fengchengwen@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.50.163.32] X-ClientProxiedBy: dggems701-chm.china.huawei.com (10.3.19.178) To dggpeml500024.china.huawei.com (7.185.36.10) X-CFilter-Loop: Reflected X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org This patch supports rte_memarea_dump() API which could be used for debug. Signed-off-by: Chengwen Feng Reviewed-by: Dongdong Liu Acked-by: Morten Brørup --- doc/guides/prog_guide/memarea_lib.rst | 3 + lib/memarea/rte_memarea.c | 97 +++++++++++++++++++++++++++ lib/memarea/rte_memarea.h | 21 ++++++ lib/memarea/version.map | 1 + 4 files changed, 122 insertions(+) diff --git a/doc/guides/prog_guide/memarea_lib.rst b/doc/guides/prog_guide/memarea_lib.rst index 55ca4b1166..d9fac69ed3 100644 --- a/doc/guides/prog_guide/memarea_lib.rst +++ b/doc/guides/prog_guide/memarea_lib.rst @@ -37,6 +37,9 @@ the memarea. The ``rte_memarea_free()`` function is used to free one memory object which allocated by ``rte_memarea_alloc()``. ++The ``rte_memarea_dump()`` function is used to dump the internal information ++of a memarea. + Debug Mode ---------- diff --git a/lib/memarea/rte_memarea.c b/lib/memarea/rte_memarea.c index 158e24b7f3..68e6e4687d 100644 --- a/lib/memarea/rte_memarea.c +++ b/lib/memarea/rte_memarea.c @@ -349,3 +349,100 @@ rte_memarea_free(struct rte_memarea *ma, void *ptr) memarea_unlock(ma); } +static const char * +memarea_source_name(enum rte_memarea_source source) +{ + if (source == RTE_MEMAREA_SOURCE_HEAP) + return "heap"; + else if (source == RTE_MEMAREA_SOURCE_LIBC) + return "libc"; + else if (source == RTE_MEMAREA_SOURCE_MEMAREA) + return "memarea"; + else + return "unknown"; +} + +static const char * +memarea_alg_name(enum rte_memarea_algorithm alg) +{ + if (alg == RTE_MEMAREA_ALGORITHM_NEXTFIT) + return "nextfit"; + else + return "unknown"; +} + +static void +memarea_dump_objects_brief(struct rte_memarea *ma, FILE *f) +{ + uint32_t total_objs = 0, total_avail_objs = 0; + struct memarea_objhdr *hdr; + size_t total_avail_sz = 0; + + TAILQ_FOREACH(hdr, &ma->obj_list, obj_next) { + if (hdr == ma->guard_hdr) + break; + memarea_check_cookie(ma, hdr, 2); + total_objs++; + if (!MEMAREA_OBJECT_IS_ALLOCATED(hdr)) { + total_avail_objs++; + total_avail_sz += MEMAREA_OBJECT_GET_SIZE(hdr); + } + } + fprintf(f, " total-objects: %u\n", total_objs); + fprintf(f, " total-avail-objects: %u\n", total_avail_objs); + fprintf(f, " total-avail-objects-size: 0x%zx\n", total_avail_sz); +} + +static void +memarea_dump_objects_detail(struct rte_memarea *ma, FILE *f) +{ + struct memarea_objhdr *hdr; + size_t offset; + void *ptr; + + fprintf(f, " objects:\n"); + TAILQ_FOREACH(hdr, &ma->obj_list, obj_next) { + if (hdr == ma->guard_hdr) + break; + memarea_check_cookie(ma, hdr, 2); + ptr = RTE_PTR_ADD(hdr, sizeof(struct memarea_objhdr)); + offset = RTE_PTR_DIFF(ptr, ma->area_base); +#ifdef RTE_LIBRTE_MEMAREA_DEBUG + fprintf(f, " %p off: 0x%zx size: 0x%zx %s\n", + ptr, offset, MEMAREA_OBJECT_GET_SIZE(hdr), + MEMAREA_OBJECT_IS_ALLOCATED(hdr) ? "allocated" : ""); +#else + fprintf(f, " off: 0x%zx size: 0x%zx %s\n", + offset, MEMAREA_OBJECT_GET_SIZE(hdr), + MEMAREA_OBJECT_IS_ALLOCATED(hdr) ? "allocated" : ""); +#endif + } +} + +int +rte_memarea_dump(struct rte_memarea *ma, FILE *f, bool dump_all) +{ + if (ma == NULL || f == NULL) + return -EINVAL; + + memarea_lock(ma); + fprintf(f, "memarea name: %s\n", ma->init.name); + fprintf(f, " source: %s\n", memarea_source_name(ma->init.source)); + if (ma->init.source == RTE_MEMAREA_SOURCE_HEAP) + fprintf(f, " heap-numa-socket: %d\n", ma->init.numa_socket); + else if (ma->init.source == RTE_MEMAREA_SOURCE_MEMAREA) + fprintf(f, " source-memarea: %s\n", ma->init.src_ma->init.name); + fprintf(f, " algorithm: %s\n", memarea_alg_name(ma->init.alg)); + fprintf(f, " total-size: 0x%zx\n", ma->init.total_sz); + fprintf(f, " mt-safe: %s\n", ma->init.mt_safe ? "yes" : "no"); +#ifdef RTE_LIBRTE_MEMAREA_DEBUG + fprintf(f, " area-base: %p\n", ma->area_base); + fprintf(f, " guard-header: %p\n", ma->guard_hdr); +#endif + memarea_dump_objects_brief(ma, f); + if (dump_all) + memarea_dump_objects_detail(ma, f); + memarea_unlock(ma); + + return 0; +} diff --git a/lib/memarea/rte_memarea.h b/lib/memarea/rte_memarea.h index 02b4825461..c871accda6 100644 --- a/lib/memarea/rte_memarea.h +++ b/lib/memarea/rte_memarea.h @@ -157,6 +157,27 @@ void *rte_memarea_alloc(struct rte_memarea *ma, size_t size); __rte_experimental void rte_memarea_free(struct rte_memarea *ma, void *ptr); +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice. + * + * Dump memarea. + * + * Dump one memarea. + * + * @param ma + * The pointer of memarea. + * @param f + * The file to write the output to. + * @param dump_all + * Indicate whether to dump the allocated and free memory objects information. + * + * @return + * 0 on success. Otherwise negative value is returned. + */ +__rte_experimental +int rte_memarea_dump(struct rte_memarea *ma, FILE *f, bool dump_all); + #ifdef __cplusplus } #endif diff --git a/lib/memarea/version.map b/lib/memarea/version.map index effbd0b488..9513d91e0b 100644 --- a/lib/memarea/version.map +++ b/lib/memarea/version.map @@ -4,6 +4,7 @@ EXPERIMENTAL { rte_memarea_alloc; rte_memarea_create; rte_memarea_destroy; + rte_memarea_dump; rte_memarea_free; local: *; From patchwork Wed Feb 8 08:24:52 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: fengchengwen X-Patchwork-Id: 123431 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 2F7C541C3C; Wed, 8 Feb 2023 09:31:13 +0100 (CET) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id CDB4042BD9; Wed, 8 Feb 2023 09:30:59 +0100 (CET) Received: from szxga03-in.huawei.com (szxga03-in.huawei.com [45.249.212.189]) by mails.dpdk.org (Postfix) with ESMTP id 2821F41153 for ; Wed, 8 Feb 2023 09:30:56 +0100 (CET) Received: from dggpeml500024.china.huawei.com (unknown [172.30.72.54]) by szxga03-in.huawei.com (SkyGuard) with ESMTP id 4PBY494DzgzJqyG; Wed, 8 Feb 2023 16:26:17 +0800 (CST) Received: from localhost.localdomain (10.50.163.32) by dggpeml500024.china.huawei.com (7.185.36.10) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.34; Wed, 8 Feb 2023 16:30:54 +0800 From: Chengwen Feng To: , , , , , CC: , Subject: [PATCH v13 6/6] test/memarea: support dump API test Date: Wed, 8 Feb 2023 08:24:52 +0000 Message-ID: <20230208082452.43883-7-fengchengwen@huawei.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20230208082452.43883-1-fengchengwen@huawei.com> References: <20220721044648.6817-1-fengchengwen@huawei.com> <20230208082452.43883-1-fengchengwen@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.50.163.32] X-ClientProxiedBy: dggems701-chm.china.huawei.com (10.3.19.178) To dggpeml500024.china.huawei.com (7.185.36.10) X-CFilter-Loop: Reflected X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org This patch supports rte_memarea_dump() API test. Signed-off-by: Chengwen Feng Reviewed-by: Dongdong Liu Acked-by: Morten Brørup --- app/test/test_memarea.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/app/test/test_memarea.c b/app/test/test_memarea.c index 3e67e59227..ad40dbf613 100644 --- a/app/test/test_memarea.c +++ b/app/test/test_memarea.c @@ -246,6 +246,39 @@ test_memarea_alloc_free(void) return 0; } +static int +test_memarea_dump(void) +{ + struct rte_memarea_param init; + struct rte_memarea *ma; + int ret; + + test_memarea_init_param(&init); + init.source = RTE_MEMAREA_SOURCE_LIBC; + init.total_sz = MEMAREA_TEST_DEFAULT_SIZE; + ma = rte_memarea_create(&init); + RTE_TEST_ASSERT(ma != NULL, "Expected Non-NULL"); + + /* test for invalid parameters */ + ret = rte_memarea_dump(NULL, stderr, false); + RTE_TEST_ASSERT(ret == -EINVAL, "Expected EINVAL"); + ret = rte_memarea_dump(ma, NULL, false); + RTE_TEST_ASSERT(ret == -EINVAL, "Expected EINVAL"); + + /* test for dump */ + (void)rte_memarea_alloc(ma, 1); + (void)rte_memarea_alloc(ma, 1); + (void)rte_memarea_alloc(ma, 1); + (void)rte_memarea_alloc(ma, MEMAREA_TEST_DEFAULT_SIZE); + (void)rte_memarea_alloc(ma, MEMAREA_TEST_DEFAULT_SIZE); + ret = rte_memarea_dump(ma, stderr, true); + RTE_TEST_ASSERT(ret == 0, "Expected ZERO"); + + rte_memarea_destroy(ma); + + return 0; +} + static int test_memarea(void) { @@ -256,6 +289,7 @@ test_memarea(void) MEMAREA_TEST_API_RUN(test_memarea_alloc_fail); MEMAREA_TEST_API_RUN(test_memarea_free_fail); MEMAREA_TEST_API_RUN(test_memarea_alloc_free); + MEMAREA_TEST_API_RUN(test_memarea_dump); return test_memarea_retcode(); }