[PATCH v4 00/10] introduce memarea library

2022-10-04 Thread datshan
The memarea library is an allocator of variable-size object which based
on a memory region. The main features are as follows:

- The default alignment size is RTE_CACHE_LINE_SIZE.

- The memory region can be initialized from the following memory
  sources:
  1. RTE memory: e.g. invoke rte_malloc_socket to obtain.
  2. System API: e.g. invoke posix_memalign to obtain.
  3. User provided address: it can be from extended memory as long as
 it is available. The address must be aligned to
 RTE_CACHE_LINE_SIZE.
  4. User provided memarea: it can be from another memarea.

- It provides refcnt feature which could be useful in multi-reader
  scenario.

- It provides backup memory mechanism, the memarea could use another
  memarea as a backup.

Note:
a) The memarea is oriented towards the application layer, which could
provides 'region-based memory management' [1] function.
b) The eal library also provide memory zone/heap management, but these
are tied to huge pages management.

[1] https://en.wikipedia.org/wiki/Region-based_memory_management

Signed-off-by: Chengwen Feng 

Chengwen Feng (10):
  memarea: introduce memarea library
  test/memarea: support memarea test
  memarea: support alloc/free/update-refcnt API
  test/memarea: support alloc/free/update-refcnt test
  memarea: support dump API
  test/memarea: support dump test
  memarea: support backup memory mechanism
  test/memarea: support backup memory test
  memarea: detect memory corruption based on magic
  test/memarea: support no MT-safe test

---
v4:
* repost patches as there are spread over different series in patchwork.
v3:
* add memory source of RTE memory.
* add algorithm field to facilitate the introduction of new algorithms.
* fix memarea log don't output problem.
v2:
* fix compile issues reported by dpdk-test-report.
* address Dimitry and Jerin's comments.
* add no MT-safe test.

 MAINTAINERS|   6 +
 app/test/meson.build   |   2 +
 app/test/test_memarea.c| 401 +++
 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  |  55 
 doc/guides/rel_notes/release_22_11.rst |   6 +
 lib/eal/common/eal_common_log.c|   1 +
 lib/eal/include/rte_log.h  |   1 +
 lib/memarea/memarea_private.h  |  37 +++
 lib/memarea/meson.build|  16 +
 lib/memarea/rte_memarea.c  | 430 +
 lib/memarea/rte_memarea.h  | 229 +
 lib/memarea/version.map|  16 +
 lib/meson.build|   1 +
 16 files changed, 1205 insertions(+), 1 deletion(-)
 create mode 100644 app/test/test_memarea.c
 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

-- 
2.34.1



[PATCH v4 01/10] memarea: introduce memarea library

2022-10-04 Thread datshan
From: Chengwen Feng 

The memarea library is an allocator of variable-size object which based
on a memory region.

This patch provides create/destroy API.

Signed-off-by: Chengwen Feng 
---
 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  |  39 ++
 doc/guides/rel_notes/release_22_11.rst |   6 +
 lib/eal/common/eal_common_log.c|   1 +
 lib/eal/include/rte_log.h  |   1 +
 lib/memarea/memarea_private.h  |  30 +
 lib/memarea/meson.build|  16 +++
 lib/memarea/rte_memarea.c  | 157 +
 lib/memarea/rte_memarea.h  | 145 +++
 lib/memarea/version.map|  12 ++
 lib/meson.build|   1 +
 14 files changed, 417 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 a55b379d73..b9c638221d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1550,6 +1550,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 00..b96dad15f6
--- /dev/null
+++ b/doc/guides/prog_guide/memarea_lib.rst
@@ -0,0 +1,39 @@
+..  SPDX-License-Identifier: BSD-3-Clause
+Copyright(c) 2022 HiSilicon Limited
+
+Memarea Library
+===
+
+Introduction
+
+
+The memarea library provides an allocator of variable-size objects, it is
+oriented towards the application layer, which could provides 'region-based
+memory management' function [1].
+
+The main features are as follows:
+
+* The default aligement size is ``RTE_CACHE_LINE_SIZE``.
+
+* The memory region can be initialized from the following memory sources:
+  a) RTE memory: e.g. invoke ``rte_malloc_socket`` to obtain. b) System API:
+  e.g. invoke posix_memalign to obtain. c) User provided address: it can be 
from
+  extendedd memory as long as it is available. d) User provided memarea: it can
+  be from another memarea.
+
+* It provides refcnt feature which could be useful in multi-reader scenario.
+
+* 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.
+
+Reference
+-
+
+[1] https://en.wikipedia.org/wiki/Region-based_memory_management
diff --git a/doc/guides/rel_notes/release_22_11.rst 
b/doc/guides/rel_notes/release_22_11.rst
index 5d8ef669b8..4c1f760b98 100644
--- a/doc/guides/rel_notes/release_22_11.rst
+++ b/doc/guides/rel_notes/release_22_11.rst
@@ -55,6 +55,12 @@ New Features
  Also, make sure to start the actual text at the margin.
  ===
 
+* **Added memarea library.**
+
+  The memarea 

[PATCH v4 02/10] test/memarea: support memarea test

2022-10-04 Thread datshan
From: Chengwen Feng 

This patch supports memarea test about API rte_memarea_create and
rte_memarea_destroy.

Signed-off-by: Chengwen Feng 
---
 MAINTAINERS |   1 +
 app/test/meson.build|   2 +
 app/test/test_memarea.c | 149 
 3 files changed, 152 insertions(+)
 create mode 100644 app/test/test_memarea.c

diff --git a/MAINTAINERS b/MAINTAINERS
index b9c638221d..bfdb36f1b5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1554,6 +1554,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 d5cad72116..778de8d65d 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',
@@ -199,6 +200,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 00..7c3d78652d
--- /dev/null
+++ b/app/test/test_memarea.c
@@ -0,0 +1,149 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2022 HiSilicon Limited
+ */
+
+#include 
+#include 
+
+#include "test.h"
+
+#ifdef RTE_EXEC_ENV_WINDOWS
+static int
+test_memarea(void)
+{
+   printf("memarea not supported on Windows, skipping test\n");
+   return TEST_SKIPPED;
+}
+
+#else
+
+#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); \
+   else \
+   printf("%s Passed\n", #test_func); \
+   } while (0)
+
+static void
+test_memarea_init_def_param(struct rte_memarea_param *init)
+{
+   memset(init, 0, sizeof(struct rte_memarea_param));
+   sprintf(init->name, "%s", "test-memarea");
+   init->source = RTE_MEMAREA_SOURCE_SYSTEM_API;
+   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;
+   int i;
+
+   /* 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_def_param(&init);
+   init.source = RTE_MEMAREA_SOURCE_USER_MEMAREA + 1;
+   ma = rte_memarea_create(&init);
+   RTE_TEST_ASSERT(ma == NULL, "Expected NULL");
+
+   /* test for total_sz */
+   test_memarea_init_def_param(&init);
+   init.total_sz = 0;
+   ma = rte_memarea_create(&init);
+   RTE_TEST_ASSERT(ma == NULL, "Expected NULL");
+
+   /* test for user address NULL */
+   test_memarea_init_def_param(&init);
+   init.source = RTE_MEMAREA_SOURCE_USER_ADDR;
+   ma = rte_memarea_create(&init);
+   RTE_TEST_ASSERT(ma == NULL, "Expected NULL");
+
+   /* test for user address align invalid */
+   test_memarea_init_def_param(&init);
+   init.source = RTE_MEMAREA_SOURCE_USER_ADDR;
+   for (i = 1; i < RTE_CACHE_LINE_SIZE; i++) {
+   init.user_addr = (void *)((uintptr_t)i);
+   ma = rte_memarea_create(&init);
+   RTE_TEST_ASSERT(ma == NULL, "Expected NULL");
+   }
+
+   /* test for user memarea NULL */
+   test_memarea_init_def_param(&init);
+   init.source = RTE_MEMAREA_SOURCE_USER_MEMAREA;
+   ma = rte_memarea_create(&init);
+   RTE_TEST_ASSERT(ma == NULL, "Expected NULL");
+
+   /* test for alg invalid */
+   test_memarea_init_def_param(&init);
+   init.alg = RTE_MEMAREA_ALG_DEFAULT + 1;
+   ma = rte_memarea_create(&init);
+   RTE_TEST_ASSERT(ma == NULL, "Expected NULL");
+
+   return 0;
+}
+
+static int
+test_memarea_create_destroy(void)
+{
+   uint8_t user_buffer[MEMAREA_TEST_DEFAULT_SIZE + RTE_CACHE_LINE_SIZE];
+   struct rte_memarea_param init;
+   struct rte_memarea *ma;
+
+   /* test for create with RTE memory */
+   test_memarea_init_def_param(&init);
+   init.source = RTE_MEMAREA_SOURC

[PATCH v4 03/10] memarea: support alloc/free/update-refcnt API

2022-10-04 Thread datshan
From: Chengwen Feng 

This patch supports rte_memarea_alloc()/rte_memarea_free()/
rte_memarea_update_refcnt() API.

Signed-off-by: Chengwen Feng 
---
 doc/guides/prog_guide/memarea_lib.rst |  10 ++
 lib/memarea/memarea_private.h |   3 +
 lib/memarea/rte_memarea.c | 143 ++
 lib/memarea/rte_memarea.h |  56 ++
 lib/memarea/version.map   |   3 +
 5 files changed, 215 insertions(+)

diff --git a/doc/guides/prog_guide/memarea_lib.rst 
b/doc/guides/prog_guide/memarea_lib.rst
index b96dad15f6..41bc0a90cd 100644
--- a/doc/guides/prog_guide/memarea_lib.rst
+++ b/doc/guides/prog_guide/memarea_lib.rst
@@ -33,6 +33,16 @@ 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()``.
+
+The ``rte_memarea_update_refcnt()`` function is used to update the memory
+object's reference count, if the count reaches zero, the memory object will
+be freed to memarea.
+
 Reference
 -
 
diff --git a/lib/memarea/memarea_private.h b/lib/memarea/memarea_private.h
index c76392d3e6..98406879b9 100644
--- a/lib/memarea/memarea_private.h
+++ b/lib/memarea/memarea_private.h
@@ -25,6 +25,9 @@ struct rte_memarea {
void*area_addr;
struct memarea_elem_list elem_list;
struct memarea_elem_list free_list;
+
+   uint64_t alloc_fails;
+   uint64_t refcnt_check_fails;
 } __rte_cache_aligned;
 
 #endif /* MEMAREA_PRIVATE_H */
diff --git a/lib/memarea/rte_memarea.c b/lib/memarea/rte_memarea.c
index 868da7661d..a072f07f20 100644
--- a/lib/memarea/rte_memarea.c
+++ b/lib/memarea/rte_memarea.c
@@ -4,6 +4,7 @@
 
 #include 
 #include 
+#include 
 
 #include 
 #include 
@@ -94,6 +95,8 @@ memarea_alloc_area(const struct rte_memarea_param *init)
ptr = memarea_alloc_from_system_api(init->total_sz);
else if (init->source == RTE_MEMAREA_SOURCE_USER_ADDR)
ptr = init->user_addr;
+   else if (init->source == RTE_MEMAREA_SOURCE_USER_MEMAREA)
+   ptr = rte_memarea_alloc(init->user_memarea, init->total_sz, 0);
 
if (ptr == NULL)
RTE_LOG(ERR, MEMAREA, "memarea: %s alloc memory area fail!\n", 
init->name);
@@ -145,6 +148,8 @@ memarea_free_area(struct rte_memarea *ma)
rte_free(ma->area_addr);
else if (ma->init.source == RTE_MEMAREA_SOURCE_SYSTEM_API)
free(ma->area_addr);
+   else if (ma->init.source == RTE_MEMAREA_SOURCE_USER_MEMAREA)
+   rte_memarea_free(ma->init.user_memarea, ma->area_addr);
 }
 
 void
@@ -155,3 +160,141 @@ rte_memarea_destroy(struct rte_memarea *ma)
memarea_free_area(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);
+}
+
+#define memarea_roundup(val, align) val) + ((align) - 1)) / (align)) * 
(align))
+
+static inline bool
+memarea_whether_add_node(size_t free_size, size_t need_size)
+{
+   size_t align_size = memarea_roundup(need_size, RTE_CACHE_LINE_SIZE);
+   return free_size > align_size && (free_size - align_size) > 
sizeof(struct memarea_elem);
+}
+
+static inline void
+memarea_add_node(struct rte_memarea *ma, struct memarea_elem *elem, size_t 
need_size)
+{
+   size_t align_size = memarea_roundup(need_size, RTE_CACHE_LINE_SIZE);
+   struct memarea_elem *new_elem;
+   new_elem = (struct memarea_elem *)((uintptr_t)elem + sizeof(struct 
memarea_elem) +
+  align_size);
+   new_elem->size = elem->size - align_size - sizeof(struct memarea_elem);
+   new_elem->cookie = MEMAREA_FREE_ELEM_COOKIE;
+   new_elem->refcnt = 0;
+   TAILQ_INSERT_AFTER(&ma->elem_list, elem, new_elem, elem_node);
+   TAILQ_INSERT_AFTER(&ma->free_list, elem, new_elem, free_node);
+   elem->size = align_size;
+}
+
+void *
+rte_memarea_alloc(struct rte_memarea *ma, size_t size, uint32_t cookie)
+{
+   struct memarea_elem *elem;
+   void *ptr = NULL;
+
+   if (unlikely(ma == NULL || size == 0))
+   return NULL;
+
+   memarea_lock(ma);
+   TAILQ_FOREACH(elem, &ma->free_list, free_node) {
+   if (elem->size < size)
+   continue;
+   if (memarea_whether_add_node(elem->size, size))
+   memarea_add_node(ma, elem, size);
+   elem->cookie = cookie;
+   elem->refcnt = 1;
+   TAILQ_REMOVE(&ma->free_list, elem, free_node);
+   ptr = (vo

[PATCH v4 05/10] memarea: support dump API

2022-10-04 Thread datshan
From: Chengwen Feng 

This patch supports rte_memarea_dump() API which could be used for
debug.

Signed-off-by: Chengwen Feng 
---
 doc/guides/prog_guide/memarea_lib.rst |  3 +
 lib/memarea/rte_memarea.c | 85 +++
 lib/memarea/rte_memarea.h | 21 +++
 lib/memarea/version.map   |  1 +
 4 files changed, 110 insertions(+)

diff --git a/doc/guides/prog_guide/memarea_lib.rst 
b/doc/guides/prog_guide/memarea_lib.rst
index 41bc0a90cd..c77012fe44 100644
--- a/doc/guides/prog_guide/memarea_lib.rst
+++ b/doc/guides/prog_guide/memarea_lib.rst
@@ -43,6 +43,9 @@ The ``rte_memarea_update_refcnt()`` function is used to 
update the memory
 object's reference count, if the count reaches zero, the memory object will
 be freed to memarea.
 
++The ``rte_memarea_dump()`` function is used to dump the internal information
++of a memarea.
+
 Reference
 -
 
diff --git a/lib/memarea/rte_memarea.c b/lib/memarea/rte_memarea.c
index a072f07f20..b70830d0bb 100644
--- a/lib/memarea/rte_memarea.c
+++ b/lib/memarea/rte_memarea.c
@@ -2,6 +2,7 @@
  * Copyright(c) 2022 HiSilicon Limited
  */
 
+#include 
 #include 
 #include 
 #include 
@@ -298,3 +299,87 @@ rte_memarea_update_refcnt(struct rte_memarea *ma, void 
*ptr, int16_t value)
memarea_free_elem(ma, elem);
memarea_unlock(ma);
 }
+
+static const char *
+memarea_source_name(enum rte_memarea_source source)
+{
+   if (source == RTE_MEMAREA_SOURCE_RTE_MEMORY)
+   return "rte-memory";
+   else if (source == RTE_MEMAREA_SOURCE_SYSTEM_API)
+   return "system-api";
+   else if (source == RTE_MEMAREA_SOURCE_USER_ADDR)
+   return "user-addr";
+   else if (source == RTE_MEMAREA_SOURCE_USER_MEMAREA)
+   return "user-memarea";
+   else
+   return "unknown";
+}
+
+static const char *
+memarea_alg_name(enum rte_memarea_alg alg)
+{
+   if (alg == RTE_MEMAREA_ALG_DEFAULT)
+   return "default";
+   else
+   return "unknown";
+}
+
+static uint32_t
+memarea_elem_list_num(struct rte_memarea *ma)
+{
+   struct memarea_elem *elem;
+   uint32_t num = 0;
+
+   TAILQ_FOREACH(elem, &ma->elem_list, elem_node)
+   num++;
+
+   return num;
+}
+
+static uint32_t
+memarea_free_list_num(struct rte_memarea *ma)
+{
+   struct memarea_elem *elem;
+   uint32_t num = 0;
+
+   TAILQ_FOREACH(elem, &ma->free_list, free_node)
+   num++;
+
+   return num;
+}
+
+static void
+memarea_dump_all(struct rte_memarea *ma, FILE *f)
+{
+   struct memarea_elem *elem;
+
+   fprintf(f, "  regions:\n");
+   TAILQ_FOREACH(elem, &ma->elem_list, elem_node)
+   fprintf(f, "size: 0x%zx cookie: 0x%x refcnt: %d\n",
+   elem->size, elem->cookie, elem->refcnt);
+}
+
+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_USER_MEMAREA)
+   fprintf(f, "  source-user-memarea: %s\n", 
ma->init.user_memarea->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");
+   fprintf(f, "  total-regions: %u\n", memarea_elem_list_num(ma));
+   fprintf(f, "  total-free-regions: %u\n", memarea_free_list_num(ma));
+   fprintf(f, "  alloc_fails: %" PRIu64 "\n", ma->alloc_fails);
+   fprintf(f, "  refcnt_check_fails: %" PRIu64 "\n", 
ma->refcnt_check_fails);
+   if (dump_all)
+   memarea_dump_all(ma, f);
+   memarea_unlock(ma);
+
+   return 0;
+}
diff --git a/lib/memarea/rte_memarea.h b/lib/memarea/rte_memarea.h
index 10e0d6ad5a..10b8229c64 100644
--- a/lib/memarea/rte_memarea.h
+++ b/lib/memarea/rte_memarea.h
@@ -194,6 +194,27 @@ void rte_memarea_free(struct rte_memarea *ma, void *ptr);
 __rte_experimental
 void rte_memarea_update_refcnt(struct rte_memarea *ma, void *ptr, int16_t 
value);
 
+/**
+ * @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 a0026fc5f9..d8ddd93c13 100644
--- a/lib/memarea/version.map
+++ b/lib/memarea/ve

[PATCH v4 06/10] test/memarea: support dump test

2022-10-04 Thread datshan
From: Chengwen Feng 

This patch supports rte_memarea_dump() test.

Signed-off-by: Chengwen Feng 
---
 app/test/test_memarea.c | 35 ++-
 1 file changed, 34 insertions(+), 1 deletion(-)

diff --git a/app/test/test_memarea.c b/app/test/test_memarea.c
index 0a54ede4c1..ab360f0265 100644
--- a/app/test/test_memarea.c
+++ b/app/test/test_memarea.c
@@ -274,7 +274,39 @@ test_memarea_alloc_free(void)
rte_memarea_free(ma, ptr[5]);
 
/* test free NULL */
-   rte_memarea_free(ma, ptr[6]);
+   rte_memarea_free(ma, NULL);
+
+   rte_memarea_destroy(ma);
+
+   return 0;
+}
+
+static int
+test_memarea_dump(void)
+{
+   struct rte_memarea_param init;
+   struct rte_memarea *ma;
+   int ret;
+
+   /* prepare env */
+   test_memarea_init_def_param(&init);
+   init.source = RTE_MEMAREA_SOURCE_SYSTEM_API;
+   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, 0);
+   (void)rte_memarea_alloc(ma, 1, 0);
+   (void)rte_memarea_alloc(ma, 1, 0);
+   ret = rte_memarea_dump(ma, stderr, true);
+   RTE_TEST_ASSERT(ret == 0, "Expected ZERO");
 
rte_memarea_destroy(ma);
 
@@ -289,6 +321,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 0;
 }
 
-- 
2.34.1



[PATCH v4 07/10] memarea: support backup memory mechanism

2022-10-04 Thread datshan
From: Chengwen Feng 

This patch supports backup memory mechanism, the memarea could use
another memarea as a backup.

Signed-off-by: Chengwen Feng 
---
 doc/guides/prog_guide/memarea_lib.rst |  3 +++
 lib/memarea/memarea_private.h |  2 ++
 lib/memarea/rte_memarea.c | 22 ++
 lib/memarea/rte_memarea.h |  7 +++
 4 files changed, 34 insertions(+)

diff --git a/doc/guides/prog_guide/memarea_lib.rst 
b/doc/guides/prog_guide/memarea_lib.rst
index c77012fe44..842d35f77a 100644
--- a/doc/guides/prog_guide/memarea_lib.rst
+++ b/doc/guides/prog_guide/memarea_lib.rst
@@ -25,6 +25,9 @@ The main features are as follows:
 
 * It supports MT-safe as long as it's specified at creation time.
 
+* It provides backup memory mechanism, the memarea could use another memarea
+  as a backup.
+
 Library API Overview
 
 
diff --git a/lib/memarea/memarea_private.h b/lib/memarea/memarea_private.h
index 98406879b9..08735ca81f 100644
--- a/lib/memarea/memarea_private.h
+++ b/lib/memarea/memarea_private.h
@@ -23,11 +23,13 @@ struct rte_memarea {
struct rte_memarea_param init;
rte_spinlock_t   lock;
void*area_addr;
+   void*top_addr;
struct memarea_elem_list elem_list;
struct memarea_elem_list free_list;
 
uint64_t alloc_fails;
uint64_t refcnt_check_fails;
+   uint64_t bak_alloc_fails;
 } __rte_cache_aligned;
 
 #endif /* MEMAREA_PRIVATE_H */
diff --git a/lib/memarea/rte_memarea.c b/lib/memarea/rte_memarea.c
index b70830d0bb..f45191aa7f 100644
--- a/lib/memarea/rte_memarea.c
+++ b/lib/memarea/rte_memarea.c
@@ -132,6 +132,7 @@ rte_memarea_create(const struct rte_memarea_param *init)
TAILQ_INIT(&ma->elem_list);
TAILQ_INIT(&ma->free_list);
ma->area_addr = addr;
+   ma->top_addr = (void *)((uintptr_t)addr + init->total_sz - 1);
elem = addr;
elem->size = init->total_sz - sizeof(struct memarea_elem);
elem->cookie = MEMAREA_FREE_ELEM_COOKIE;
@@ -200,6 +201,15 @@ memarea_add_node(struct rte_memarea *ma, struct 
memarea_elem *elem, size_t need_
elem->size = align_size;
 }
 
+static inline void *
+memarea_alloc_backup(struct rte_memarea *ma, size_t size, uint32_t cookie)
+{
+   void *ptr = rte_memarea_alloc(ma->init.bak_memarea, size, cookie);
+   if (unlikely(ptr == NULL))
+   ma->bak_alloc_fails++;
+   return ptr;
+}
+
 void *
 rte_memarea_alloc(struct rte_memarea *ma, size_t size, uint32_t cookie)
 {
@@ -221,6 +231,8 @@ rte_memarea_alloc(struct rte_memarea *ma, size_t size, 
uint32_t cookie)
ptr = (void *)((uintptr_t)elem + sizeof(struct memarea_elem));
break;
}
+   if (ptr == NULL && ma->init.bak_memarea != NULL)
+   ptr = memarea_alloc_backup(ma, size, cookie);
if (unlikely(ptr == NULL))
ma->alloc_fails++;
memarea_unlock(ma);
@@ -283,6 +295,12 @@ rte_memarea_update_refcnt(struct rte_memarea *ma, void 
*ptr, int16_t value)
return;
 
memarea_lock(ma);
+   if (ptr < ma->area_addr || ptr > ma->top_addr) {
+   rte_memarea_update_refcnt(ma->init.bak_memarea, ptr, value);
+   memarea_unlock(ma);
+   return;
+   }
+
if (unlikely(elem->refcnt <= 0 || elem->refcnt + value < 0)) {
RTE_LOG(ERR, MEMAREA,
"memarea: %s cookie: 0x%x curr refcnt: %d update 
refcnt: %d check fail!\n",
@@ -373,10 +391,14 @@ rte_memarea_dump(struct rte_memarea *ma, FILE *f, bool 
dump_all)
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");
+   if (ma->init.bak_memarea)
+   fprintf(f, "  backup-memarea-name: %s\n", 
ma->init.bak_memarea->init.name);
fprintf(f, "  total-regions: %u\n", memarea_elem_list_num(ma));
fprintf(f, "  total-free-regions: %u\n", memarea_free_list_num(ma));
fprintf(f, "  alloc_fails: %" PRIu64 "\n", ma->alloc_fails);
fprintf(f, "  refcnt_check_fails: %" PRIu64 "\n", 
ma->refcnt_check_fails);
+   if (ma->init.bak_memarea)
+   fprintf(f, "  backup_alloc_fails: %" PRIu64 "\n", 
ma->bak_alloc_fails);
if (dump_all)
memarea_dump_all(ma, f);
memarea_unlock(ma);
diff --git a/lib/memarea/rte_memarea.h b/lib/memarea/rte_memarea.h
index 10b8229c64..348febab7f 100644
--- a/lib/memarea/rte_memarea.h
+++ b/lib/memarea/rte_memarea.h
@@ -39,6 +39,9 @@
  *   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.
+ * - It provides backup memory mechanism, the memarea could use another memarea
+ *   as a backup. It will attempts to allocate obj

[PATCH v4 08/10] test/memarea: support backup memory test

2022-10-04 Thread datshan
From: Chengwen Feng 

This patch supports backup memory mechanism test.

Signed-off-by: Chengwen Feng 
---
 app/test/test_memarea.c | 41 +
 1 file changed, 41 insertions(+)

diff --git a/app/test/test_memarea.c b/app/test/test_memarea.c
index ab360f0265..ec3475c354 100644
--- a/app/test/test_memarea.c
+++ b/app/test/test_memarea.c
@@ -313,6 +313,46 @@ test_memarea_dump(void)
return 0;
 }
 
+static int
+test_memarea_backup(void)
+{
+   struct rte_memarea *ma, *bak_ma;
+   struct rte_memarea_param init;
+   void *ptr;
+
+   /* prepare env */
+   test_memarea_init_def_param(&init);
+   strcat(init.name, "_backup");
+   init.source = RTE_MEMAREA_SOURCE_SYSTEM_API;
+   init.total_sz = MEMAREA_TEST_DEFAULT_SIZE;
+   bak_ma = rte_memarea_create(&init);
+   RTE_TEST_ASSERT(bak_ma != NULL, "Expected Non-NULL");
+   test_memarea_init_def_param(&init);
+   init.source = RTE_MEMAREA_SOURCE_SYSTEM_API;
+   init.total_sz = MEMAREA_TEST_DEFAULT_SIZE >> 2;
+   init.bak_memarea = bak_ma;
+   ma = rte_memarea_create(&init);
+   RTE_TEST_ASSERT(ma != NULL, "Expected Non-NULL");
+
+   /* test for backup */
+   ptr = rte_memarea_alloc(ma, MEMAREA_TEST_DEFAULT_SIZE >> 3, 0);
+   RTE_TEST_ASSERT(ptr != NULL, "Expected Non-NULL");
+   ptr = rte_memarea_alloc(ma, MEMAREA_TEST_DEFAULT_SIZE >> 1, 0);
+   RTE_TEST_ASSERT(ptr != NULL, "Expected Non-NULL");
+   (void)rte_memarea_dump(ma, stderr, true);
+   (void)rte_memarea_dump(bak_ma, stderr, true);
+   rte_memarea_free(ma, ptr);
+   ptr = rte_memarea_alloc(ma, MEMAREA_TEST_DEFAULT_SIZE, 0);
+   RTE_TEST_ASSERT(ptr == NULL, "Expected NULL");
+   (void)rte_memarea_dump(ma, stderr, true);
+   (void)rte_memarea_dump(bak_ma, stderr, true);
+
+   rte_memarea_destroy(ma);
+   rte_memarea_destroy(bak_ma);
+
+   return 0;
+}
+
 static int
 test_memarea(void)
 {
@@ -322,6 +362,7 @@ test_memarea(void)
MEMAREA_TEST_API_RUN(test_memarea_free_fail);
MEMAREA_TEST_API_RUN(test_memarea_alloc_free);
MEMAREA_TEST_API_RUN(test_memarea_dump);
+   MEMAREA_TEST_API_RUN(test_memarea_backup);
return 0;
 }
 
-- 
2.34.1




[PATCH v4 04/10] test/memarea: support alloc/free/update-refcnt test

2022-10-04 Thread datshan
From: Chengwen Feng 

This patch supports rte_memarea_alloc()/rte_memarea_free()/
rte_memarea_update_refcnt() test.

Signed-off-by: Chengwen Feng 
---
 app/test/test_memarea.c | 150 +++-
 1 file changed, 149 insertions(+), 1 deletion(-)

diff --git a/app/test/test_memarea.c b/app/test/test_memarea.c
index 7c3d78652d..0a54ede4c1 100644
--- a/app/test/test_memarea.c
+++ b/app/test/test_memarea.c
@@ -41,6 +41,12 @@ test_memarea_init_def_param(struct rte_memarea_param *init)
init->mt_safe = 1;
 }
 
+static void
+test_memarea_fill_allocated_region(void *ptr, size_t size)
+{
+   memset(ptr, 0xff, size);
+}
+
 static int
 test_memarea_create_bad_param(void)
 {
@@ -106,8 +112,8 @@ static int
 test_memarea_create_destroy(void)
 {
uint8_t user_buffer[MEMAREA_TEST_DEFAULT_SIZE + RTE_CACHE_LINE_SIZE];
+   struct rte_memarea *ma, *user_ma;
struct rte_memarea_param init;
-   struct rte_memarea *ma;
 
/* test for create with RTE memory */
test_memarea_init_def_param(&init);
@@ -133,6 +139,145 @@ test_memarea_create_destroy(void)
RTE_TEST_ASSERT(ma != NULL, "Expected Non-NULL");
rte_memarea_destroy(ma);
 
+   /* test for create with user-memarea */
+   test_memarea_init_def_param(&init);
+   init.source = RTE_MEMAREA_SOURCE_SYSTEM_API;
+   user_ma = rte_memarea_create(&init);
+   RTE_TEST_ASSERT(user_ma != NULL, "Expected Non-NULL");
+   test_memarea_init_def_param(&init);
+   init.source = RTE_MEMAREA_SOURCE_USER_MEMAREA;
+   init.total_sz = init.total_sz >> 1;
+   init.user_memarea = user_ma;
+   ma = rte_memarea_create(&init);
+   RTE_TEST_ASSERT(ma != NULL, "Expected Non-NULL");
+   rte_memarea_destroy(ma);
+   rte_memarea_destroy(user_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_def_param(&init);
+   init.source = RTE_MEMAREA_SOURCE_SYSTEM_API;
+   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, 0);
+   RTE_TEST_ASSERT(ptr[0] == NULL, "Expected NULL");
+
+   /* test alloc fail because no memory */
+   ptr[0] = rte_memarea_alloc(ma, MEMAREA_TEST_DEFAULT_SIZE - 
RTE_CACHE_LINE_SIZE, 0);
+   RTE_TEST_ASSERT(ptr[0] != NULL, "Expected Non-NULL");
+   ptr[1] = rte_memarea_alloc(ma, 1, 0);
+   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, 0);
+   RTE_TEST_ASSERT(ptr[0] != NULL, "Expected Non-NULL");
+   test_memarea_fill_allocated_region(ptr[0], MEMAREA_TEST_DEFAULT_SIZE >> 
1);
+   ptr[1] = rte_memarea_alloc(ma, MEMAREA_TEST_DEFAULT_SIZE >> 1, 0);
+   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, 0);
+   RTE_TEST_ASSERT(ptr[1] != NULL, "Expected Non-NULL");
+   test_memarea_fill_allocated_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;
+
+   /* prepare env */
+   test_memarea_init_def_param(&init);
+   init.source = RTE_MEMAREA_SOURCE_SYSTEM_API;
+   init.total_sz = MEMAREA_TEST_DEFAULT_SIZE;
+   ma = rte_memarea_create(&init);
+   RTE_TEST_ASSERT(ma != NULL, "Expected Non-NULL");
+
+   /* test invalid parameters with update-refcnt */
+   rte_memarea_update_refcnt(NULL, (void *)(uintptr_t)1, 0);
+   rte_memarea_update_refcnt(ma, NULL, 0);
+   rte_memarea_update_refcnt(NULL, NULL, 0);
+
+   /* test free with refcnt fail */
+   ptr = rte_memarea_alloc(ma, MEMAREA_TEST_DEFAULT_SIZE >> 1, 0);
+   RTE_TEST_ASSERT(ptr != NULL, "Expected Non-NULL");
+   test_memarea_fill_allocated_region(ptr, MEMAREA_TEST_DEFAULT_SIZE >> 1);
+   rte_memarea_free(ma, ptr);
+   rte_memarea_free(ma, ptr);
+
+   /* test update refcnt with fail */
+   ptr = rte_memarea_alloc(ma, MEMAREA_TEST_DEFAULT_SIZE >> 1, 0);
+   RTE_TEST_ASSERT(ptr != NULL, "Expected Non-NULL");
+   test_memarea_fill_allocated_region(ptr, MEMAREA_TEST_DEFAULT_SIZE >> 1);
+   rte_memarea_update_refcnt(ma, ptr, -2);
+   ptr = rte_memarea_alloc(ma, MEMAREA_TEST_DEFAULT_SIZE >> 1, 0);
+   RTE_TEST_ASSERT(ptr == NULL, "Expected NULL");
+
+   rte_memarea_destroy(ma);
+
+   return 0;
+}
+
+static int
+test_memarea_alloc_free(void)

[PATCH v4 09/10] memarea: detect memory corruption based on magic

2022-10-04 Thread datshan
From: Chengwen Feng 

This patch provides lightweight mechanism for detecting memory
corruption which based on magic field in each element node.

Signed-off-by: Chengwen Feng 
---
 lib/memarea/memarea_private.h |  2 ++
 lib/memarea/rte_memarea.c | 29 ++---
 2 files changed, 28 insertions(+), 3 deletions(-)

diff --git a/lib/memarea/memarea_private.h b/lib/memarea/memarea_private.h
index 08735ca81f..4f5393e6f9 100644
--- a/lib/memarea/memarea_private.h
+++ b/lib/memarea/memarea_private.h
@@ -7,10 +7,12 @@
 
 #include 
 
+#define MEMAREA_ELEM_MAGIC_NUM 0xbeef1234
 #define MEMAREA_FREE_ELEM_COOKIE   0x
 
 struct memarea_elem {
size_t   size;
+   uint32_t magic;
uint32_t cookie;
int32_t  refcnt; /* Non-zero indicates that it has been allocated */
TAILQ_ENTRY(memarea_elem) elem_node;
diff --git a/lib/memarea/rte_memarea.c b/lib/memarea/rte_memarea.c
index f45191aa7f..c81d4dd3fa 100644
--- a/lib/memarea/rte_memarea.c
+++ b/lib/memarea/rte_memarea.c
@@ -135,6 +135,7 @@ rte_memarea_create(const struct rte_memarea_param *init)
ma->top_addr = (void *)((uintptr_t)addr + init->total_sz - 1);
elem = addr;
elem->size = init->total_sz - sizeof(struct memarea_elem);
+   elem->magic = MEMAREA_ELEM_MAGIC_NUM;
elem->cookie = MEMAREA_FREE_ELEM_COOKIE;
elem->refcnt = 0;
TAILQ_INSERT_TAIL(&ma->elem_list, elem, elem_node);
@@ -194,6 +195,7 @@ memarea_add_node(struct rte_memarea *ma, struct 
memarea_elem *elem, size_t need_
new_elem = (struct memarea_elem *)((uintptr_t)elem + sizeof(struct 
memarea_elem) +
   align_size);
new_elem->size = elem->size - align_size - sizeof(struct memarea_elem);
+   new_elem->magic = MEMAREA_ELEM_MAGIC_NUM;
new_elem->cookie = MEMAREA_FREE_ELEM_COOKIE;
new_elem->refcnt = 0;
TAILQ_INSERT_AFTER(&ma->elem_list, elem, new_elem, elem_node);
@@ -221,6 +223,8 @@ rte_memarea_alloc(struct rte_memarea *ma, size_t size, 
uint32_t cookie)
 
memarea_lock(ma);
TAILQ_FOREACH(elem, &ma->free_list, free_node) {
+   if (unlikely(elem->magic != MEMAREA_ELEM_MAGIC_NUM))
+   break;
if (elem->size < size)
continue;
if (memarea_whether_add_node(elem->size, size))
@@ -253,6 +257,7 @@ memarea_merge_node(struct rte_memarea *ma, struct 
memarea_elem *curr,
 {
curr->size += next->size + sizeof(struct memarea_elem);
next->size = 0;
+   next->magic = ~MEMAREA_ELEM_MAGIC_NUM;
next->cookie = 0;
TAILQ_REMOVE(&ma->elem_list, next, elem_node);
if (del_next_from_free)
@@ -295,6 +300,13 @@ rte_memarea_update_refcnt(struct rte_memarea *ma, void 
*ptr, int16_t value)
return;
 
memarea_lock(ma);
+   if (unlikely(elem->magic != MEMAREA_ELEM_MAGIC_NUM)) {
+   RTE_LOG(ERR, MEMAREA, "memarea: %s magic: 0x%x check fail!\n",
+   ma->init.name, elem->magic);
+   memarea_unlock(ma);
+   return;
+   }
+
if (ptr < ma->area_addr || ptr > ma->top_addr) {
rte_memarea_update_refcnt(ma->init.bak_memarea, ptr, value);
memarea_unlock(ma);
@@ -348,8 +360,11 @@ memarea_elem_list_num(struct rte_memarea *ma)
struct memarea_elem *elem;
uint32_t num = 0;
 
-   TAILQ_FOREACH(elem, &ma->elem_list, elem_node)
+   TAILQ_FOREACH(elem, &ma->elem_list, elem_node) {
+   if (elem->magic != MEMAREA_ELEM_MAGIC_NUM)
+   break;
num++;
+   }
 
return num;
 }
@@ -360,8 +375,11 @@ memarea_free_list_num(struct rte_memarea *ma)
struct memarea_elem *elem;
uint32_t num = 0;
 
-   TAILQ_FOREACH(elem, &ma->free_list, free_node)
+   TAILQ_FOREACH(elem, &ma->free_list, free_node) {
+   if (elem->magic != MEMAREA_ELEM_MAGIC_NUM)
+   break;
num++;
+   }
 
return num;
 }
@@ -372,9 +390,14 @@ memarea_dump_all(struct rte_memarea *ma, FILE *f)
struct memarea_elem *elem;
 
fprintf(f, "  regions:\n");
-   TAILQ_FOREACH(elem, &ma->elem_list, elem_node)
+   TAILQ_FOREACH(elem, &ma->elem_list, elem_node) {
+   if (elem->magic != MEMAREA_ELEM_MAGIC_NUM) {
+   fprintf(f, "magic: 0x%x chech fail!\n", 
elem->magic);
+   break;
+   }
fprintf(f, "size: 0x%zx cookie: 0x%x refcnt: %d\n",
elem->size, elem->cookie, elem->refcnt);
+   }
 }
 
 int
-- 
2.34.1



[PATCH v4 10/10] test/memarea: support no MT-safe test

2022-10-04 Thread datshan
From: Chengwen Feng 

MT-safe is enabled by default in previous test, this patch adds no
MT-safe test.

Signed-off-by: Chengwen Feng 
---
 app/test/test_memarea.c | 30 ++
 1 file changed, 30 insertions(+)

diff --git a/app/test/test_memarea.c b/app/test/test_memarea.c
index ec3475c354..b4012086fc 100644
--- a/app/test/test_memarea.c
+++ b/app/test/test_memarea.c
@@ -353,6 +353,35 @@ test_memarea_backup(void)
return 0;
 }
 
+static int
+test_memarea_no_mt_safe(void)
+{
+   struct rte_memarea_param init;
+   struct rte_memarea *ma;
+   int ret;
+
+   /* prepare env */
+   test_memarea_init_def_param(&init);
+   init.source = RTE_MEMAREA_SOURCE_SYSTEM_API;
+   init.total_sz = MEMAREA_TEST_DEFAULT_SIZE;
+   init.mt_safe = false;
+   ma = rte_memarea_create(&init);
+   RTE_TEST_ASSERT(ma != NULL, "Expected Non-NULL");
+
+   /* test for all API */
+   (void)rte_memarea_alloc(ma, 1, 0);
+   (void)rte_memarea_alloc(ma, 1, 0);
+   rte_memarea_free(ma, rte_memarea_alloc(ma, 1, 0));
+   rte_memarea_update_refcnt(ma, rte_memarea_alloc(ma, 1, 0), 1);
+   rte_memarea_update_refcnt(ma, rte_memarea_alloc(ma, 1, 0), -1);
+   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)
 {
@@ -363,6 +392,7 @@ test_memarea(void)
MEMAREA_TEST_API_RUN(test_memarea_alloc_free);
MEMAREA_TEST_API_RUN(test_memarea_dump);
MEMAREA_TEST_API_RUN(test_memarea_backup);
+   MEMAREA_TEST_API_RUN(test_memarea_no_mt_safe);
return 0;
 }
 
-- 
2.34.1



[PATCH v5 00/10] introduce memarea library

2022-10-04 Thread datshan
The memarea library is an allocator of variable-size object which based
on a memory region. The main features are as follows:

- The default alignment size is RTE_CACHE_LINE_SIZE.

- The memory region can be initialized from the following memory
  sources:
  1. RTE memory: e.g. invoke rte_malloc_socket to obtain.
  2. System API: e.g. invoke posix_memalign to obtain.
  3. User provided address: it can be from extended memory as long as
 it is available. The address must be aligned to
 RTE_CACHE_LINE_SIZE.
  4. User provided memarea: it can be from another memarea.

- It provides refcnt feature which could be useful in multi-reader
  scenario.

- It provides backup memory mechanism, the memarea could use another
  memarea as a backup.

Note:
a) The memarea is oriented towards the application layer, which could
provides 'region-based memory management' [1] function.
b) The eal library also provide memory zone/heap management, but these
are tied to huge pages management.

[1] https://en.wikipedia.org/wiki/Region-based_memory_management

Signed-off-by: Chengwen Feng 

Chengwen Feng (10):
  memarea: introduce memarea library
  test/memarea: support memarea test
  memarea: support alloc/free/update-refcnt API
  test/memarea: support alloc/free/update-refcnt test
  memarea: support dump API
  test/memarea: support dump test
  memarea: support backup memory mechanism
  test/memarea: support backup memory test
  memarea: detect memory corruption based on magic
  test/memarea: support no MT-safe test

---
v5:
* fix 09/10 patch spell warning.
v4:
* repost patches as there are spread over different series in patchwork.
v3:
* add memory source of RTE memory.
* add algorithm field to facilitate the introduction of new algorithms.
* fix memarea log don't output problem.
v2:
* fix compile issues reported by dpdk-test-report.
* address Dimitry and Jerin's comments.
* add no MT-safe test.

 MAINTAINERS|   6 +
 app/test/meson.build   |   2 +
 app/test/test_memarea.c| 401 +++
 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  |  55 
 doc/guides/rel_notes/release_22_11.rst |   6 +
 lib/eal/common/eal_common_log.c|   1 +
 lib/eal/include/rte_log.h  |   1 +
 lib/memarea/memarea_private.h  |  37 +++
 lib/memarea/meson.build|  16 +
 lib/memarea/rte_memarea.c  | 430 +
 lib/memarea/rte_memarea.h  | 229 +
 lib/memarea/version.map|  16 +
 lib/meson.build|   1 +
 16 files changed, 1205 insertions(+), 1 deletion(-)
 create mode 100644 app/test/test_memarea.c
 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

-- 
2.34.1



[PATCH v5 01/10] memarea: introduce memarea library

2022-10-04 Thread datshan
From: Chengwen Feng 

The memarea library is an allocator of variable-size object which based
on a memory region.

This patch provides create/destroy API.

Signed-off-by: Chengwen Feng 
---
 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  |  39 ++
 doc/guides/rel_notes/release_22_11.rst |   6 +
 lib/eal/common/eal_common_log.c|   1 +
 lib/eal/include/rte_log.h  |   1 +
 lib/memarea/memarea_private.h  |  30 +
 lib/memarea/meson.build|  16 +++
 lib/memarea/rte_memarea.c  | 157 +
 lib/memarea/rte_memarea.h  | 145 +++
 lib/memarea/version.map|  12 ++
 lib/meson.build|   1 +
 14 files changed, 417 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 a55b379d73..b9c638221d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1550,6 +1550,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 00..b96dad15f6
--- /dev/null
+++ b/doc/guides/prog_guide/memarea_lib.rst
@@ -0,0 +1,39 @@
+..  SPDX-License-Identifier: BSD-3-Clause
+Copyright(c) 2022 HiSilicon Limited
+
+Memarea Library
+===
+
+Introduction
+
+
+The memarea library provides an allocator of variable-size objects, it is
+oriented towards the application layer, which could provides 'region-based
+memory management' function [1].
+
+The main features are as follows:
+
+* The default aligement size is ``RTE_CACHE_LINE_SIZE``.
+
+* The memory region can be initialized from the following memory sources:
+  a) RTE memory: e.g. invoke ``rte_malloc_socket`` to obtain. b) System API:
+  e.g. invoke posix_memalign to obtain. c) User provided address: it can be 
from
+  extendedd memory as long as it is available. d) User provided memarea: it can
+  be from another memarea.
+
+* It provides refcnt feature which could be useful in multi-reader scenario.
+
+* 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.
+
+Reference
+-
+
+[1] https://en.wikipedia.org/wiki/Region-based_memory_management
diff --git a/doc/guides/rel_notes/release_22_11.rst 
b/doc/guides/rel_notes/release_22_11.rst
index 5d8ef669b8..4c1f760b98 100644
--- a/doc/guides/rel_notes/release_22_11.rst
+++ b/doc/guides/rel_notes/release_22_11.rst
@@ -55,6 +55,12 @@ New Features
  Also, make sure to start the actual text at the margin.
  ===
 
+* **Added memarea library.**
+
+  The memarea 

[PATCH v5 02/10] test/memarea: support memarea test

2022-10-04 Thread datshan
From: Chengwen Feng 

This patch supports memarea test about API rte_memarea_create and
rte_memarea_destroy.

Signed-off-by: Chengwen Feng 
---
 MAINTAINERS |   1 +
 app/test/meson.build|   2 +
 app/test/test_memarea.c | 149 
 3 files changed, 152 insertions(+)
 create mode 100644 app/test/test_memarea.c

diff --git a/MAINTAINERS b/MAINTAINERS
index b9c638221d..bfdb36f1b5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1554,6 +1554,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 d5cad72116..778de8d65d 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',
@@ -199,6 +200,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 00..7c3d78652d
--- /dev/null
+++ b/app/test/test_memarea.c
@@ -0,0 +1,149 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2022 HiSilicon Limited
+ */
+
+#include 
+#include 
+
+#include "test.h"
+
+#ifdef RTE_EXEC_ENV_WINDOWS
+static int
+test_memarea(void)
+{
+   printf("memarea not supported on Windows, skipping test\n");
+   return TEST_SKIPPED;
+}
+
+#else
+
+#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); \
+   else \
+   printf("%s Passed\n", #test_func); \
+   } while (0)
+
+static void
+test_memarea_init_def_param(struct rte_memarea_param *init)
+{
+   memset(init, 0, sizeof(struct rte_memarea_param));
+   sprintf(init->name, "%s", "test-memarea");
+   init->source = RTE_MEMAREA_SOURCE_SYSTEM_API;
+   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;
+   int i;
+
+   /* 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_def_param(&init);
+   init.source = RTE_MEMAREA_SOURCE_USER_MEMAREA + 1;
+   ma = rte_memarea_create(&init);
+   RTE_TEST_ASSERT(ma == NULL, "Expected NULL");
+
+   /* test for total_sz */
+   test_memarea_init_def_param(&init);
+   init.total_sz = 0;
+   ma = rte_memarea_create(&init);
+   RTE_TEST_ASSERT(ma == NULL, "Expected NULL");
+
+   /* test for user address NULL */
+   test_memarea_init_def_param(&init);
+   init.source = RTE_MEMAREA_SOURCE_USER_ADDR;
+   ma = rte_memarea_create(&init);
+   RTE_TEST_ASSERT(ma == NULL, "Expected NULL");
+
+   /* test for user address align invalid */
+   test_memarea_init_def_param(&init);
+   init.source = RTE_MEMAREA_SOURCE_USER_ADDR;
+   for (i = 1; i < RTE_CACHE_LINE_SIZE; i++) {
+   init.user_addr = (void *)((uintptr_t)i);
+   ma = rte_memarea_create(&init);
+   RTE_TEST_ASSERT(ma == NULL, "Expected NULL");
+   }
+
+   /* test for user memarea NULL */
+   test_memarea_init_def_param(&init);
+   init.source = RTE_MEMAREA_SOURCE_USER_MEMAREA;
+   ma = rte_memarea_create(&init);
+   RTE_TEST_ASSERT(ma == NULL, "Expected NULL");
+
+   /* test for alg invalid */
+   test_memarea_init_def_param(&init);
+   init.alg = RTE_MEMAREA_ALG_DEFAULT + 1;
+   ma = rte_memarea_create(&init);
+   RTE_TEST_ASSERT(ma == NULL, "Expected NULL");
+
+   return 0;
+}
+
+static int
+test_memarea_create_destroy(void)
+{
+   uint8_t user_buffer[MEMAREA_TEST_DEFAULT_SIZE + RTE_CACHE_LINE_SIZE];
+   struct rte_memarea_param init;
+   struct rte_memarea *ma;
+
+   /* test for create with RTE memory */
+   test_memarea_init_def_param(&init);
+   init.source = RTE_MEMAREA_SOURC

[PATCH v5 03/10] memarea: support alloc/free/update-refcnt API

2022-10-04 Thread datshan
From: Chengwen Feng 

This patch supports rte_memarea_alloc()/rte_memarea_free()/
rte_memarea_update_refcnt() API.

Signed-off-by: Chengwen Feng 
---
 doc/guides/prog_guide/memarea_lib.rst |  10 ++
 lib/memarea/memarea_private.h |   3 +
 lib/memarea/rte_memarea.c | 143 ++
 lib/memarea/rte_memarea.h |  56 ++
 lib/memarea/version.map   |   3 +
 5 files changed, 215 insertions(+)

diff --git a/doc/guides/prog_guide/memarea_lib.rst 
b/doc/guides/prog_guide/memarea_lib.rst
index b96dad15f6..41bc0a90cd 100644
--- a/doc/guides/prog_guide/memarea_lib.rst
+++ b/doc/guides/prog_guide/memarea_lib.rst
@@ -33,6 +33,16 @@ 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()``.
+
+The ``rte_memarea_update_refcnt()`` function is used to update the memory
+object's reference count, if the count reaches zero, the memory object will
+be freed to memarea.
+
 Reference
 -
 
diff --git a/lib/memarea/memarea_private.h b/lib/memarea/memarea_private.h
index c76392d3e6..98406879b9 100644
--- a/lib/memarea/memarea_private.h
+++ b/lib/memarea/memarea_private.h
@@ -25,6 +25,9 @@ struct rte_memarea {
void*area_addr;
struct memarea_elem_list elem_list;
struct memarea_elem_list free_list;
+
+   uint64_t alloc_fails;
+   uint64_t refcnt_check_fails;
 } __rte_cache_aligned;
 
 #endif /* MEMAREA_PRIVATE_H */
diff --git a/lib/memarea/rte_memarea.c b/lib/memarea/rte_memarea.c
index 868da7661d..a072f07f20 100644
--- a/lib/memarea/rte_memarea.c
+++ b/lib/memarea/rte_memarea.c
@@ -4,6 +4,7 @@
 
 #include 
 #include 
+#include 
 
 #include 
 #include 
@@ -94,6 +95,8 @@ memarea_alloc_area(const struct rte_memarea_param *init)
ptr = memarea_alloc_from_system_api(init->total_sz);
else if (init->source == RTE_MEMAREA_SOURCE_USER_ADDR)
ptr = init->user_addr;
+   else if (init->source == RTE_MEMAREA_SOURCE_USER_MEMAREA)
+   ptr = rte_memarea_alloc(init->user_memarea, init->total_sz, 0);
 
if (ptr == NULL)
RTE_LOG(ERR, MEMAREA, "memarea: %s alloc memory area fail!\n", 
init->name);
@@ -145,6 +148,8 @@ memarea_free_area(struct rte_memarea *ma)
rte_free(ma->area_addr);
else if (ma->init.source == RTE_MEMAREA_SOURCE_SYSTEM_API)
free(ma->area_addr);
+   else if (ma->init.source == RTE_MEMAREA_SOURCE_USER_MEMAREA)
+   rte_memarea_free(ma->init.user_memarea, ma->area_addr);
 }
 
 void
@@ -155,3 +160,141 @@ rte_memarea_destroy(struct rte_memarea *ma)
memarea_free_area(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);
+}
+
+#define memarea_roundup(val, align) val) + ((align) - 1)) / (align)) * 
(align))
+
+static inline bool
+memarea_whether_add_node(size_t free_size, size_t need_size)
+{
+   size_t align_size = memarea_roundup(need_size, RTE_CACHE_LINE_SIZE);
+   return free_size > align_size && (free_size - align_size) > 
sizeof(struct memarea_elem);
+}
+
+static inline void
+memarea_add_node(struct rte_memarea *ma, struct memarea_elem *elem, size_t 
need_size)
+{
+   size_t align_size = memarea_roundup(need_size, RTE_CACHE_LINE_SIZE);
+   struct memarea_elem *new_elem;
+   new_elem = (struct memarea_elem *)((uintptr_t)elem + sizeof(struct 
memarea_elem) +
+  align_size);
+   new_elem->size = elem->size - align_size - sizeof(struct memarea_elem);
+   new_elem->cookie = MEMAREA_FREE_ELEM_COOKIE;
+   new_elem->refcnt = 0;
+   TAILQ_INSERT_AFTER(&ma->elem_list, elem, new_elem, elem_node);
+   TAILQ_INSERT_AFTER(&ma->free_list, elem, new_elem, free_node);
+   elem->size = align_size;
+}
+
+void *
+rte_memarea_alloc(struct rte_memarea *ma, size_t size, uint32_t cookie)
+{
+   struct memarea_elem *elem;
+   void *ptr = NULL;
+
+   if (unlikely(ma == NULL || size == 0))
+   return NULL;
+
+   memarea_lock(ma);
+   TAILQ_FOREACH(elem, &ma->free_list, free_node) {
+   if (elem->size < size)
+   continue;
+   if (memarea_whether_add_node(elem->size, size))
+   memarea_add_node(ma, elem, size);
+   elem->cookie = cookie;
+   elem->refcnt = 1;
+   TAILQ_REMOVE(&ma->free_list, elem, free_node);
+   ptr = (vo

[PATCH v5 05/10] memarea: support dump API

2022-10-04 Thread datshan
From: Chengwen Feng 

This patch supports rte_memarea_dump() API which could be used for
debug.

Signed-off-by: Chengwen Feng 
---
 doc/guides/prog_guide/memarea_lib.rst |  3 +
 lib/memarea/rte_memarea.c | 85 +++
 lib/memarea/rte_memarea.h | 21 +++
 lib/memarea/version.map   |  1 +
 4 files changed, 110 insertions(+)

diff --git a/doc/guides/prog_guide/memarea_lib.rst 
b/doc/guides/prog_guide/memarea_lib.rst
index 41bc0a90cd..c77012fe44 100644
--- a/doc/guides/prog_guide/memarea_lib.rst
+++ b/doc/guides/prog_guide/memarea_lib.rst
@@ -43,6 +43,9 @@ The ``rte_memarea_update_refcnt()`` function is used to 
update the memory
 object's reference count, if the count reaches zero, the memory object will
 be freed to memarea.
 
++The ``rte_memarea_dump()`` function is used to dump the internal information
++of a memarea.
+
 Reference
 -
 
diff --git a/lib/memarea/rte_memarea.c b/lib/memarea/rte_memarea.c
index a072f07f20..b70830d0bb 100644
--- a/lib/memarea/rte_memarea.c
+++ b/lib/memarea/rte_memarea.c
@@ -2,6 +2,7 @@
  * Copyright(c) 2022 HiSilicon Limited
  */
 
+#include 
 #include 
 #include 
 #include 
@@ -298,3 +299,87 @@ rte_memarea_update_refcnt(struct rte_memarea *ma, void 
*ptr, int16_t value)
memarea_free_elem(ma, elem);
memarea_unlock(ma);
 }
+
+static const char *
+memarea_source_name(enum rte_memarea_source source)
+{
+   if (source == RTE_MEMAREA_SOURCE_RTE_MEMORY)
+   return "rte-memory";
+   else if (source == RTE_MEMAREA_SOURCE_SYSTEM_API)
+   return "system-api";
+   else if (source == RTE_MEMAREA_SOURCE_USER_ADDR)
+   return "user-addr";
+   else if (source == RTE_MEMAREA_SOURCE_USER_MEMAREA)
+   return "user-memarea";
+   else
+   return "unknown";
+}
+
+static const char *
+memarea_alg_name(enum rte_memarea_alg alg)
+{
+   if (alg == RTE_MEMAREA_ALG_DEFAULT)
+   return "default";
+   else
+   return "unknown";
+}
+
+static uint32_t
+memarea_elem_list_num(struct rte_memarea *ma)
+{
+   struct memarea_elem *elem;
+   uint32_t num = 0;
+
+   TAILQ_FOREACH(elem, &ma->elem_list, elem_node)
+   num++;
+
+   return num;
+}
+
+static uint32_t
+memarea_free_list_num(struct rte_memarea *ma)
+{
+   struct memarea_elem *elem;
+   uint32_t num = 0;
+
+   TAILQ_FOREACH(elem, &ma->free_list, free_node)
+   num++;
+
+   return num;
+}
+
+static void
+memarea_dump_all(struct rte_memarea *ma, FILE *f)
+{
+   struct memarea_elem *elem;
+
+   fprintf(f, "  regions:\n");
+   TAILQ_FOREACH(elem, &ma->elem_list, elem_node)
+   fprintf(f, "size: 0x%zx cookie: 0x%x refcnt: %d\n",
+   elem->size, elem->cookie, elem->refcnt);
+}
+
+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_USER_MEMAREA)
+   fprintf(f, "  source-user-memarea: %s\n", 
ma->init.user_memarea->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");
+   fprintf(f, "  total-regions: %u\n", memarea_elem_list_num(ma));
+   fprintf(f, "  total-free-regions: %u\n", memarea_free_list_num(ma));
+   fprintf(f, "  alloc_fails: %" PRIu64 "\n", ma->alloc_fails);
+   fprintf(f, "  refcnt_check_fails: %" PRIu64 "\n", 
ma->refcnt_check_fails);
+   if (dump_all)
+   memarea_dump_all(ma, f);
+   memarea_unlock(ma);
+
+   return 0;
+}
diff --git a/lib/memarea/rte_memarea.h b/lib/memarea/rte_memarea.h
index 10e0d6ad5a..10b8229c64 100644
--- a/lib/memarea/rte_memarea.h
+++ b/lib/memarea/rte_memarea.h
@@ -194,6 +194,27 @@ void rte_memarea_free(struct rte_memarea *ma, void *ptr);
 __rte_experimental
 void rte_memarea_update_refcnt(struct rte_memarea *ma, void *ptr, int16_t 
value);
 
+/**
+ * @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 a0026fc5f9..d8ddd93c13 100644
--- a/lib/memarea/version.map
+++ b/lib/memarea/ve

[PATCH v5 07/10] memarea: support backup memory mechanism

2022-10-04 Thread datshan
From: Chengwen Feng 

This patch supports backup memory mechanism, the memarea could use
another memarea as a backup.

Signed-off-by: Chengwen Feng 
---
 doc/guides/prog_guide/memarea_lib.rst |  3 +++
 lib/memarea/memarea_private.h |  2 ++
 lib/memarea/rte_memarea.c | 22 ++
 lib/memarea/rte_memarea.h |  7 +++
 4 files changed, 34 insertions(+)

diff --git a/doc/guides/prog_guide/memarea_lib.rst 
b/doc/guides/prog_guide/memarea_lib.rst
index c77012fe44..842d35f77a 100644
--- a/doc/guides/prog_guide/memarea_lib.rst
+++ b/doc/guides/prog_guide/memarea_lib.rst
@@ -25,6 +25,9 @@ The main features are as follows:
 
 * It supports MT-safe as long as it's specified at creation time.
 
+* It provides backup memory mechanism, the memarea could use another memarea
+  as a backup.
+
 Library API Overview
 
 
diff --git a/lib/memarea/memarea_private.h b/lib/memarea/memarea_private.h
index 98406879b9..08735ca81f 100644
--- a/lib/memarea/memarea_private.h
+++ b/lib/memarea/memarea_private.h
@@ -23,11 +23,13 @@ struct rte_memarea {
struct rte_memarea_param init;
rte_spinlock_t   lock;
void*area_addr;
+   void*top_addr;
struct memarea_elem_list elem_list;
struct memarea_elem_list free_list;
 
uint64_t alloc_fails;
uint64_t refcnt_check_fails;
+   uint64_t bak_alloc_fails;
 } __rte_cache_aligned;
 
 #endif /* MEMAREA_PRIVATE_H */
diff --git a/lib/memarea/rte_memarea.c b/lib/memarea/rte_memarea.c
index b70830d0bb..f45191aa7f 100644
--- a/lib/memarea/rte_memarea.c
+++ b/lib/memarea/rte_memarea.c
@@ -132,6 +132,7 @@ rte_memarea_create(const struct rte_memarea_param *init)
TAILQ_INIT(&ma->elem_list);
TAILQ_INIT(&ma->free_list);
ma->area_addr = addr;
+   ma->top_addr = (void *)((uintptr_t)addr + init->total_sz - 1);
elem = addr;
elem->size = init->total_sz - sizeof(struct memarea_elem);
elem->cookie = MEMAREA_FREE_ELEM_COOKIE;
@@ -200,6 +201,15 @@ memarea_add_node(struct rte_memarea *ma, struct 
memarea_elem *elem, size_t need_
elem->size = align_size;
 }
 
+static inline void *
+memarea_alloc_backup(struct rte_memarea *ma, size_t size, uint32_t cookie)
+{
+   void *ptr = rte_memarea_alloc(ma->init.bak_memarea, size, cookie);
+   if (unlikely(ptr == NULL))
+   ma->bak_alloc_fails++;
+   return ptr;
+}
+
 void *
 rte_memarea_alloc(struct rte_memarea *ma, size_t size, uint32_t cookie)
 {
@@ -221,6 +231,8 @@ rte_memarea_alloc(struct rte_memarea *ma, size_t size, 
uint32_t cookie)
ptr = (void *)((uintptr_t)elem + sizeof(struct memarea_elem));
break;
}
+   if (ptr == NULL && ma->init.bak_memarea != NULL)
+   ptr = memarea_alloc_backup(ma, size, cookie);
if (unlikely(ptr == NULL))
ma->alloc_fails++;
memarea_unlock(ma);
@@ -283,6 +295,12 @@ rte_memarea_update_refcnt(struct rte_memarea *ma, void 
*ptr, int16_t value)
return;
 
memarea_lock(ma);
+   if (ptr < ma->area_addr || ptr > ma->top_addr) {
+   rte_memarea_update_refcnt(ma->init.bak_memarea, ptr, value);
+   memarea_unlock(ma);
+   return;
+   }
+
if (unlikely(elem->refcnt <= 0 || elem->refcnt + value < 0)) {
RTE_LOG(ERR, MEMAREA,
"memarea: %s cookie: 0x%x curr refcnt: %d update 
refcnt: %d check fail!\n",
@@ -373,10 +391,14 @@ rte_memarea_dump(struct rte_memarea *ma, FILE *f, bool 
dump_all)
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");
+   if (ma->init.bak_memarea)
+   fprintf(f, "  backup-memarea-name: %s\n", 
ma->init.bak_memarea->init.name);
fprintf(f, "  total-regions: %u\n", memarea_elem_list_num(ma));
fprintf(f, "  total-free-regions: %u\n", memarea_free_list_num(ma));
fprintf(f, "  alloc_fails: %" PRIu64 "\n", ma->alloc_fails);
fprintf(f, "  refcnt_check_fails: %" PRIu64 "\n", 
ma->refcnt_check_fails);
+   if (ma->init.bak_memarea)
+   fprintf(f, "  backup_alloc_fails: %" PRIu64 "\n", 
ma->bak_alloc_fails);
if (dump_all)
memarea_dump_all(ma, f);
memarea_unlock(ma);
diff --git a/lib/memarea/rte_memarea.h b/lib/memarea/rte_memarea.h
index 10b8229c64..348febab7f 100644
--- a/lib/memarea/rte_memarea.h
+++ b/lib/memarea/rte_memarea.h
@@ -39,6 +39,9 @@
  *   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.
+ * - It provides backup memory mechanism, the memarea could use another memarea
+ *   as a backup. It will attempts to allocate obj

[PATCH v5 04/10] test/memarea: support alloc/free/update-refcnt test

2022-10-04 Thread datshan
From: Chengwen Feng 

This patch supports rte_memarea_alloc()/rte_memarea_free()/
rte_memarea_update_refcnt() test.

Signed-off-by: Chengwen Feng 
---
 app/test/test_memarea.c | 150 +++-
 1 file changed, 149 insertions(+), 1 deletion(-)

diff --git a/app/test/test_memarea.c b/app/test/test_memarea.c
index 7c3d78652d..0a54ede4c1 100644
--- a/app/test/test_memarea.c
+++ b/app/test/test_memarea.c
@@ -41,6 +41,12 @@ test_memarea_init_def_param(struct rte_memarea_param *init)
init->mt_safe = 1;
 }
 
+static void
+test_memarea_fill_allocated_region(void *ptr, size_t size)
+{
+   memset(ptr, 0xff, size);
+}
+
 static int
 test_memarea_create_bad_param(void)
 {
@@ -106,8 +112,8 @@ static int
 test_memarea_create_destroy(void)
 {
uint8_t user_buffer[MEMAREA_TEST_DEFAULT_SIZE + RTE_CACHE_LINE_SIZE];
+   struct rte_memarea *ma, *user_ma;
struct rte_memarea_param init;
-   struct rte_memarea *ma;
 
/* test for create with RTE memory */
test_memarea_init_def_param(&init);
@@ -133,6 +139,145 @@ test_memarea_create_destroy(void)
RTE_TEST_ASSERT(ma != NULL, "Expected Non-NULL");
rte_memarea_destroy(ma);
 
+   /* test for create with user-memarea */
+   test_memarea_init_def_param(&init);
+   init.source = RTE_MEMAREA_SOURCE_SYSTEM_API;
+   user_ma = rte_memarea_create(&init);
+   RTE_TEST_ASSERT(user_ma != NULL, "Expected Non-NULL");
+   test_memarea_init_def_param(&init);
+   init.source = RTE_MEMAREA_SOURCE_USER_MEMAREA;
+   init.total_sz = init.total_sz >> 1;
+   init.user_memarea = user_ma;
+   ma = rte_memarea_create(&init);
+   RTE_TEST_ASSERT(ma != NULL, "Expected Non-NULL");
+   rte_memarea_destroy(ma);
+   rte_memarea_destroy(user_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_def_param(&init);
+   init.source = RTE_MEMAREA_SOURCE_SYSTEM_API;
+   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, 0);
+   RTE_TEST_ASSERT(ptr[0] == NULL, "Expected NULL");
+
+   /* test alloc fail because no memory */
+   ptr[0] = rte_memarea_alloc(ma, MEMAREA_TEST_DEFAULT_SIZE - 
RTE_CACHE_LINE_SIZE, 0);
+   RTE_TEST_ASSERT(ptr[0] != NULL, "Expected Non-NULL");
+   ptr[1] = rte_memarea_alloc(ma, 1, 0);
+   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, 0);
+   RTE_TEST_ASSERT(ptr[0] != NULL, "Expected Non-NULL");
+   test_memarea_fill_allocated_region(ptr[0], MEMAREA_TEST_DEFAULT_SIZE >> 
1);
+   ptr[1] = rte_memarea_alloc(ma, MEMAREA_TEST_DEFAULT_SIZE >> 1, 0);
+   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, 0);
+   RTE_TEST_ASSERT(ptr[1] != NULL, "Expected Non-NULL");
+   test_memarea_fill_allocated_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;
+
+   /* prepare env */
+   test_memarea_init_def_param(&init);
+   init.source = RTE_MEMAREA_SOURCE_SYSTEM_API;
+   init.total_sz = MEMAREA_TEST_DEFAULT_SIZE;
+   ma = rte_memarea_create(&init);
+   RTE_TEST_ASSERT(ma != NULL, "Expected Non-NULL");
+
+   /* test invalid parameters with update-refcnt */
+   rte_memarea_update_refcnt(NULL, (void *)(uintptr_t)1, 0);
+   rte_memarea_update_refcnt(ma, NULL, 0);
+   rte_memarea_update_refcnt(NULL, NULL, 0);
+
+   /* test free with refcnt fail */
+   ptr = rte_memarea_alloc(ma, MEMAREA_TEST_DEFAULT_SIZE >> 1, 0);
+   RTE_TEST_ASSERT(ptr != NULL, "Expected Non-NULL");
+   test_memarea_fill_allocated_region(ptr, MEMAREA_TEST_DEFAULT_SIZE >> 1);
+   rte_memarea_free(ma, ptr);
+   rte_memarea_free(ma, ptr);
+
+   /* test update refcnt with fail */
+   ptr = rte_memarea_alloc(ma, MEMAREA_TEST_DEFAULT_SIZE >> 1, 0);
+   RTE_TEST_ASSERT(ptr != NULL, "Expected Non-NULL");
+   test_memarea_fill_allocated_region(ptr, MEMAREA_TEST_DEFAULT_SIZE >> 1);
+   rte_memarea_update_refcnt(ma, ptr, -2);
+   ptr = rte_memarea_alloc(ma, MEMAREA_TEST_DEFAULT_SIZE >> 1, 0);
+   RTE_TEST_ASSERT(ptr == NULL, "Expected NULL");
+
+   rte_memarea_destroy(ma);
+
+   return 0;
+}
+
+static int
+test_memarea_alloc_free(void)

[PATCH v5 09/10] memarea: detect memory corruption based on magic

2022-10-04 Thread datshan
From: Chengwen Feng 

This patch provides lightweight mechanism for detecting memory
corruption which based on magic field in each element node.

Signed-off-by: Chengwen Feng 
---
 lib/memarea/memarea_private.h |  2 ++
 lib/memarea/rte_memarea.c | 29 ++---
 2 files changed, 28 insertions(+), 3 deletions(-)

diff --git a/lib/memarea/memarea_private.h b/lib/memarea/memarea_private.h
index 08735ca81f..4f5393e6f9 100644
--- a/lib/memarea/memarea_private.h
+++ b/lib/memarea/memarea_private.h
@@ -7,10 +7,12 @@
 
 #include 
 
+#define MEMAREA_ELEM_MAGIC_NUM 0xbeef1234
 #define MEMAREA_FREE_ELEM_COOKIE   0x
 
 struct memarea_elem {
size_t   size;
+   uint32_t magic;
uint32_t cookie;
int32_t  refcnt; /* Non-zero indicates that it has been allocated */
TAILQ_ENTRY(memarea_elem) elem_node;
diff --git a/lib/memarea/rte_memarea.c b/lib/memarea/rte_memarea.c
index f45191aa7f..6290e3449a 100644
--- a/lib/memarea/rte_memarea.c
+++ b/lib/memarea/rte_memarea.c
@@ -135,6 +135,7 @@ rte_memarea_create(const struct rte_memarea_param *init)
ma->top_addr = (void *)((uintptr_t)addr + init->total_sz - 1);
elem = addr;
elem->size = init->total_sz - sizeof(struct memarea_elem);
+   elem->magic = MEMAREA_ELEM_MAGIC_NUM;
elem->cookie = MEMAREA_FREE_ELEM_COOKIE;
elem->refcnt = 0;
TAILQ_INSERT_TAIL(&ma->elem_list, elem, elem_node);
@@ -194,6 +195,7 @@ memarea_add_node(struct rte_memarea *ma, struct 
memarea_elem *elem, size_t need_
new_elem = (struct memarea_elem *)((uintptr_t)elem + sizeof(struct 
memarea_elem) +
   align_size);
new_elem->size = elem->size - align_size - sizeof(struct memarea_elem);
+   new_elem->magic = MEMAREA_ELEM_MAGIC_NUM;
new_elem->cookie = MEMAREA_FREE_ELEM_COOKIE;
new_elem->refcnt = 0;
TAILQ_INSERT_AFTER(&ma->elem_list, elem, new_elem, elem_node);
@@ -221,6 +223,8 @@ rte_memarea_alloc(struct rte_memarea *ma, size_t size, 
uint32_t cookie)
 
memarea_lock(ma);
TAILQ_FOREACH(elem, &ma->free_list, free_node) {
+   if (unlikely(elem->magic != MEMAREA_ELEM_MAGIC_NUM))
+   break;
if (elem->size < size)
continue;
if (memarea_whether_add_node(elem->size, size))
@@ -253,6 +257,7 @@ memarea_merge_node(struct rte_memarea *ma, struct 
memarea_elem *curr,
 {
curr->size += next->size + sizeof(struct memarea_elem);
next->size = 0;
+   next->magic = ~MEMAREA_ELEM_MAGIC_NUM;
next->cookie = 0;
TAILQ_REMOVE(&ma->elem_list, next, elem_node);
if (del_next_from_free)
@@ -295,6 +300,13 @@ rte_memarea_update_refcnt(struct rte_memarea *ma, void 
*ptr, int16_t value)
return;
 
memarea_lock(ma);
+   if (unlikely(elem->magic != MEMAREA_ELEM_MAGIC_NUM)) {
+   RTE_LOG(ERR, MEMAREA, "memarea: %s magic: 0x%x check fail!\n",
+   ma->init.name, elem->magic);
+   memarea_unlock(ma);
+   return;
+   }
+
if (ptr < ma->area_addr || ptr > ma->top_addr) {
rte_memarea_update_refcnt(ma->init.bak_memarea, ptr, value);
memarea_unlock(ma);
@@ -348,8 +360,11 @@ memarea_elem_list_num(struct rte_memarea *ma)
struct memarea_elem *elem;
uint32_t num = 0;
 
-   TAILQ_FOREACH(elem, &ma->elem_list, elem_node)
+   TAILQ_FOREACH(elem, &ma->elem_list, elem_node) {
+   if (elem->magic != MEMAREA_ELEM_MAGIC_NUM)
+   break;
num++;
+   }
 
return num;
 }
@@ -360,8 +375,11 @@ memarea_free_list_num(struct rte_memarea *ma)
struct memarea_elem *elem;
uint32_t num = 0;
 
-   TAILQ_FOREACH(elem, &ma->free_list, free_node)
+   TAILQ_FOREACH(elem, &ma->free_list, free_node) {
+   if (elem->magic != MEMAREA_ELEM_MAGIC_NUM)
+   break;
num++;
+   }
 
return num;
 }
@@ -372,9 +390,14 @@ memarea_dump_all(struct rte_memarea *ma, FILE *f)
struct memarea_elem *elem;
 
fprintf(f, "  regions:\n");
-   TAILQ_FOREACH(elem, &ma->elem_list, elem_node)
+   TAILQ_FOREACH(elem, &ma->elem_list, elem_node) {
+   if (elem->magic != MEMAREA_ELEM_MAGIC_NUM) {
+   fprintf(f, "magic: 0x%x check fail!\n", 
elem->magic);
+   break;
+   }
fprintf(f, "size: 0x%zx cookie: 0x%x refcnt: %d\n",
elem->size, elem->cookie, elem->refcnt);
+   }
 }
 
 int
-- 
2.34.1



[PATCH v5 06/10] test/memarea: support dump test

2022-10-04 Thread datshan
From: Chengwen Feng 

This patch supports rte_memarea_dump() test.

Signed-off-by: Chengwen Feng 
---
 app/test/test_memarea.c | 35 ++-
 1 file changed, 34 insertions(+), 1 deletion(-)

diff --git a/app/test/test_memarea.c b/app/test/test_memarea.c
index 0a54ede4c1..ab360f0265 100644
--- a/app/test/test_memarea.c
+++ b/app/test/test_memarea.c
@@ -274,7 +274,39 @@ test_memarea_alloc_free(void)
rte_memarea_free(ma, ptr[5]);
 
/* test free NULL */
-   rte_memarea_free(ma, ptr[6]);
+   rte_memarea_free(ma, NULL);
+
+   rte_memarea_destroy(ma);
+
+   return 0;
+}
+
+static int
+test_memarea_dump(void)
+{
+   struct rte_memarea_param init;
+   struct rte_memarea *ma;
+   int ret;
+
+   /* prepare env */
+   test_memarea_init_def_param(&init);
+   init.source = RTE_MEMAREA_SOURCE_SYSTEM_API;
+   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, 0);
+   (void)rte_memarea_alloc(ma, 1, 0);
+   (void)rte_memarea_alloc(ma, 1, 0);
+   ret = rte_memarea_dump(ma, stderr, true);
+   RTE_TEST_ASSERT(ret == 0, "Expected ZERO");
 
rte_memarea_destroy(ma);
 
@@ -289,6 +321,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 0;
 }
 
-- 
2.34.1



[PATCH v5 10/10] test/memarea: support no MT-safe test

2022-10-04 Thread datshan
From: Chengwen Feng 

MT-safe is enabled by default in previous test, this patch adds no
MT-safe test.

Signed-off-by: Chengwen Feng 
---
 app/test/test_memarea.c | 30 ++
 1 file changed, 30 insertions(+)

diff --git a/app/test/test_memarea.c b/app/test/test_memarea.c
index ec3475c354..b4012086fc 100644
--- a/app/test/test_memarea.c
+++ b/app/test/test_memarea.c
@@ -353,6 +353,35 @@ test_memarea_backup(void)
return 0;
 }
 
+static int
+test_memarea_no_mt_safe(void)
+{
+   struct rte_memarea_param init;
+   struct rte_memarea *ma;
+   int ret;
+
+   /* prepare env */
+   test_memarea_init_def_param(&init);
+   init.source = RTE_MEMAREA_SOURCE_SYSTEM_API;
+   init.total_sz = MEMAREA_TEST_DEFAULT_SIZE;
+   init.mt_safe = false;
+   ma = rte_memarea_create(&init);
+   RTE_TEST_ASSERT(ma != NULL, "Expected Non-NULL");
+
+   /* test for all API */
+   (void)rte_memarea_alloc(ma, 1, 0);
+   (void)rte_memarea_alloc(ma, 1, 0);
+   rte_memarea_free(ma, rte_memarea_alloc(ma, 1, 0));
+   rte_memarea_update_refcnt(ma, rte_memarea_alloc(ma, 1, 0), 1);
+   rte_memarea_update_refcnt(ma, rte_memarea_alloc(ma, 1, 0), -1);
+   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)
 {
@@ -363,6 +392,7 @@ test_memarea(void)
MEMAREA_TEST_API_RUN(test_memarea_alloc_free);
MEMAREA_TEST_API_RUN(test_memarea_dump);
MEMAREA_TEST_API_RUN(test_memarea_backup);
+   MEMAREA_TEST_API_RUN(test_memarea_no_mt_safe);
return 0;
 }
 
-- 
2.34.1



[PATCH v5 08/10] test/memarea: support backup memory test

2022-10-04 Thread datshan
From: Chengwen Feng 

This patch supports backup memory mechanism test.

Signed-off-by: Chengwen Feng 
---
 app/test/test_memarea.c | 41 +
 1 file changed, 41 insertions(+)

diff --git a/app/test/test_memarea.c b/app/test/test_memarea.c
index ab360f0265..ec3475c354 100644
--- a/app/test/test_memarea.c
+++ b/app/test/test_memarea.c
@@ -313,6 +313,46 @@ test_memarea_dump(void)
return 0;
 }
 
+static int
+test_memarea_backup(void)
+{
+   struct rte_memarea *ma, *bak_ma;
+   struct rte_memarea_param init;
+   void *ptr;
+
+   /* prepare env */
+   test_memarea_init_def_param(&init);
+   strcat(init.name, "_backup");
+   init.source = RTE_MEMAREA_SOURCE_SYSTEM_API;
+   init.total_sz = MEMAREA_TEST_DEFAULT_SIZE;
+   bak_ma = rte_memarea_create(&init);
+   RTE_TEST_ASSERT(bak_ma != NULL, "Expected Non-NULL");
+   test_memarea_init_def_param(&init);
+   init.source = RTE_MEMAREA_SOURCE_SYSTEM_API;
+   init.total_sz = MEMAREA_TEST_DEFAULT_SIZE >> 2;
+   init.bak_memarea = bak_ma;
+   ma = rte_memarea_create(&init);
+   RTE_TEST_ASSERT(ma != NULL, "Expected Non-NULL");
+
+   /* test for backup */
+   ptr = rte_memarea_alloc(ma, MEMAREA_TEST_DEFAULT_SIZE >> 3, 0);
+   RTE_TEST_ASSERT(ptr != NULL, "Expected Non-NULL");
+   ptr = rte_memarea_alloc(ma, MEMAREA_TEST_DEFAULT_SIZE >> 1, 0);
+   RTE_TEST_ASSERT(ptr != NULL, "Expected Non-NULL");
+   (void)rte_memarea_dump(ma, stderr, true);
+   (void)rte_memarea_dump(bak_ma, stderr, true);
+   rte_memarea_free(ma, ptr);
+   ptr = rte_memarea_alloc(ma, MEMAREA_TEST_DEFAULT_SIZE, 0);
+   RTE_TEST_ASSERT(ptr == NULL, "Expected NULL");
+   (void)rte_memarea_dump(ma, stderr, true);
+   (void)rte_memarea_dump(bak_ma, stderr, true);
+
+   rte_memarea_destroy(ma);
+   rte_memarea_destroy(bak_ma);
+
+   return 0;
+}
+
 static int
 test_memarea(void)
 {
@@ -322,6 +362,7 @@ test_memarea(void)
MEMAREA_TEST_API_RUN(test_memarea_free_fail);
MEMAREA_TEST_API_RUN(test_memarea_alloc_free);
MEMAREA_TEST_API_RUN(test_memarea_dump);
+   MEMAREA_TEST_API_RUN(test_memarea_backup);
return 0;
 }
 
-- 
2.34.1




Re: [PATCH v3 00/10] introduce memarea library

2022-10-04 Thread datshan

Hi David,

  The v5 (send by dats...@qq.com) is sent to fix it, please have a look.

Thanks.

On 2022/10/3 15:42, David Marchand wrote:

On Sat, Sep 24, 2022 at 9:56 AM Chengwen Feng  wrote:

The memarea library is an allocator of variable-size object which based
on a memory region. The main features are as follows:

- The default alignment size is RTE_CACHE_LINE_SIZE.

- The memory region can be initialized from the following memory
   sources:
   1. RTE memory: e.g. invoke rte_malloc_socket to obtain.
   2. System API: e.g. invoke posix_memalign to obtain.
   3. User provided address: it can be from extended memory as long as
  it is available. The address must be aligned to
  RTE_CACHE_LINE_SIZE.
   4. User provided memarea: it can be from another memarea.

- It provides refcnt feature which could be useful in multi-reader
   scenario.

- It provides backup memory mechanism, the memarea could use another
   memarea as a backup.

Note:
a) The memarea is oriented towards the application layer, which could
provides 'region-based memory management' [1] function.
b) The eal library also provide memory zone/heap management, but these
are tied to huge pages management.

[1] https://en.wikipedia.org/wiki/Region-based_memory_management

Signed-off-by: Chengwen Feng 

This series did not pass through the CI, as its patches are spread
over different series in patchwork.
https://patchwork.dpdk.org/project/dpdk/list/?submitter=2146

There was probably something wrong when sending the patches, please
check your setup and repost them.


Thanks.