DPDK patches and discussions
 help / color / mirror / Atom feed
* [RFC] memarea: introduce memory area library
@ 2022-07-21  4:46 Chengwen Feng
  2022-07-21 15:22 ` Stephen Hemminger
                   ` (23 more replies)
  0 siblings, 24 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-07-21  4:46 UTC (permalink / raw)
  To: thomas; +Cc: dev

The memarea library is an allocator of variable-size object. It is a
collection of allocated objects that can be efficiently alloc or free
all at once, the main feature are as follows:
a) it facilitate alloc and free of memory with low overhead.

b) it provides refcnt feature which could be useful in some scenes.

c) it supports MT-safe as long as it's specified at creation time.

d) it's memory source could comes from:
d.1) system API: malloc in C library.
d.2) user provided address: it can be from the rte_malloc API series
or extended memory as long as it is available.
d.3) user provided memarea: it can be from another memarea.

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 <fengchengwen@huawei.com>
---
 lib/memarea/meson.build   |  10 ++
 lib/memarea/rte_memarea.c |  52 ++++++++++
 lib/memarea/rte_memarea.h | 205 ++++++++++++++++++++++++++++++++++++++
 lib/memarea/version.map   |  16 +++
 lib/meson.build           |   1 +
 5 files changed, 284 insertions(+)
 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/lib/memarea/meson.build b/lib/memarea/meson.build
new file mode 100644
index 0000000000..d5c2c442f5
--- /dev/null
+++ b/lib/memarea/meson.build
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2022 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..2989b56c60
--- /dev/null
+++ b/lib/memarea/rte_memarea.c
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 202 HiSilicon Limited
+ */
+
+#include <rte_common.h>
+#include <rte_memarea.h>
+
+struct rte_memarea *
+rte_memarea_create(const struct rte_memarea_param *init)
+{
+	RTE_SET_USED(init);
+	return NULL;
+}
+
+int
+rte_memarea_destroy(struct rte_memarea *ma)
+{
+	RTE_SET_USED(ma);
+	return 0;
+}
+
+void *
+rte_memarea_alloc(struct rte_memarea *ma, uint32_t size)
+{
+	RTE_SET_USED(ma);
+	RTE_SET_USED(size);
+	return NULL;
+}
+
+void
+rte_memarea_free(struct rte_memarea *ma, void *ptr)
+{
+	RTE_SET_USED(ma);
+	RTE_SET_USED(ptr);
+}
+
+int
+rte_memarea_refcnt_update(struct rte_memarea *ma, void *ptr, int16_t value)
+{
+	RTE_SET_USED(ma);
+	RTE_SET_USED(ptr);
+	RTE_SET_USED(value);
+	return 0;
+}
+
+int
+rte_memarea_dump(struct rte_memarea *ma, FILE *f)
+{
+	RTE_SET_USED(ma);
+	RTE_SET_USED(f);
+	return 0;
+}
diff --git a/lib/memarea/rte_memarea.h b/lib/memarea/rte_memarea.h
new file mode 100644
index 0000000000..dfbe845595
--- /dev/null
+++ b/lib/memarea/rte_memarea.h
@@ -0,0 +1,205 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2022 HiSilicon Limited
+ */
+
+#ifndef RTE_MEMAREA_H
+#define RTE_MEMAREA_H
+
+/**
+ * @file
+ * RTE Memarea.
+ *
+ * A memory area is an allocator of variable-size object. It is identified
+ * by its name.
+ *
+ * The memarea is a collection of allocated objects that can be efficiently
+ * alloc or free all at once, the main feature are as follows:
+ *   a) it facilitate alloc and free of memory with low overhead.
+ *   b) it provides refcnt feature which could be useful in some scenes.
+ *   c) it supports MT-safe as long as it's specified at creation time.
+ *   d) it's memory source could comes from:
+ *      d.1) system API: malloc in C library.
+ *      d.2) user provided address: it can be from the rte_malloc API series
+ *           or extended memory as long as it is available.
+ *      d.3) user provided memarea: it can be from another memarea. So we can
+ *           build the following memory management structure:
+ *                         memarea-1
+ *                             |
+ *                             v
+ *                 ------------------------
+ *                 |           |          |
+ *                 v           v          v
+ *              memarea-2   memarea-3    obj
+ *
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include <rte_compat.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define RTE_MEMAREA_NAMESIZE	64
+
+/**
+ * Memarea memory source.
+ */
+enum rte_memarea_source {
+	/** Memory source comes from sys api (e.g. malloc) */
+	RTE_MEMAREA_SOURCE_SYSAPI,
+	/** Memory source comes from user-provided address */
+	RTE_MEMAREA_SOURCE_USER_ADDR,
+	/** Memory source comes from user-provided memarea */
+	RTE_MEMAREA_SOURCE_USER_MEMAREA,
+};
+
+struct rte_memarea;
+
+struct rte_memarea_param {
+	char name[RTE_MEMAREA_NAMESIZE]; /**< Name of memarea */
+	enum rte_memarea_source source;  /**< Memory source of memarea */
+	uint64_t size;                   /**< Size (byte) of memarea */
+	uint32_t align;                  /**< Align of allocated object */
+	/** Indicates whether the memarea should be MT-safe */
+	bool mt_safe;
+	/** Indicates whether the memarea is visible to multiple process.
+	 * If the memory source is RTE_MEMAREA_SOURCE_USER_ADDR, this filed
+	 * depends on user settings and must be set.
+	 * If the memory source is RTE_MEMAREA_SOURCE_SYSAPI or
+	 * RTE_MEMAREA_SOURCE_USER_MEMAREA, this filed does not need to be set.
+	 */
+	bool mp_visible;
+	/** User provided address, this field is valid only when source
+	 * is set to RTE_MEMAREA_SOURCE_USER_ADDR.
+	 */
+	void *user_addr;
+	/** User provided memarea, this field is valid only when source
+	 * is set to RTE_MEMAREA_SOURCE_MEMAREA.
+	 */
+	struct rte_memarea *user_memarea;
+};
+
+struct rte_memarea {
+	void *private_data; /**< private management data pointer*/
+	struct rte_memarea_param init;
+};
+
+/**
+ * @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.
+ *
+ * @return
+ *   0 on success. Otherwise negative value is returned.
+ */
+__rte_experimental
+int rte_memarea_destroy(struct rte_memarea *ma);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Allocate memory from memarea.
+ *
+ * Allocate one memory region from the memarea.
+ *
+ * @param ma
+ *   The pointer of memarea.
+ * @param size
+ *   The memory size to be allocated.
+ *
+ * @return
+ *   Non-NULL on success. Otherwise NULL is returned.
+ */
+__rte_experimental
+void *rte_memarea_alloc(struct rte_memarea *ma, uint32_t size);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Free memory to memarea.
+ *
+ * Free one memory region to the memarea.
+ *
+ * @param ma
+ *   The pointer of memarea.
+ * @param ptr
+ *   The pointer of memory region which need be freed.
+ */
+__rte_experimental
+void rte_memarea_free(struct rte_memarea *ma, void *ptr);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Update memory's refcnt.
+ *
+ * Update one memory region's refcnt.
+ *
+ * @param ma
+ *   The pointer of memarea.
+ * @param ptr
+ *   The pointer of memory region which need be updated refcnt.
+ * @param value
+ *   The value which need be updated.
+ *   Note: it could be negative.
+ *
+ * @return
+ *   0 on success. Otherwise negative value is returned.
+ */
+__rte_experimental
+int rte_memarea_refcnt_update(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.
+ *
+ * @return
+ *   0 on success. Otherwise negative value is returned.
+ */
+__rte_experimental
+int rte_memarea_dump(struct rte_memarea *ma, FILE *f);
+
+#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..6d75f9f7c4
--- /dev/null
+++ b/lib/memarea/version.map
@@ -0,0 +1,16 @@
+EXPERIMENTAL {
+	global:
+
+	rte_memarea_alloc;
+	rte_memarea_create;
+	rte_memarea_destroy;
+	rte_memarea_dump;
+	rte_memarea_free;
+	rte_memarea_refcnt_update;
+
+	local: *;
+};
+
+INTERNAL {
+	local: *;
+};
diff --git a/lib/meson.build b/lib/meson.build
index c648f7d800..521a25d6c0 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -42,6 +42,7 @@ libraries = [
         'kni',
         'latencystats',
         'lpm',
+        'memarea',
         'member',
         'pcapng',
         'power',
-- 
2.33.0


^ permalink raw reply	[flat|nested] 222+ messages in thread

* Re: [RFC] memarea: introduce memory area library
  2022-07-21  4:46 [RFC] memarea: introduce memory area library Chengwen Feng
@ 2022-07-21 15:22 ` Stephen Hemminger
  2022-08-04  6:36 ` Jerin Jacob
                   ` (22 subsequent siblings)
  23 siblings, 0 replies; 222+ messages in thread
From: Stephen Hemminger @ 2022-07-21 15:22 UTC (permalink / raw)
  To: Chengwen Feng; +Cc: thomas, dev

On Thu, 21 Jul 2022 12:46:48 +0800
Chengwen Feng <fengchengwen@huawei.com> wrote:

> +struct rte_memarea {
> +	void *private_data; /**< private management data pointer*/
> +	struct rte_memarea_param init;
> +};

Why does this structure have to be exposed in user API?
Hiding it in implementation would reduce ABI breakage problems.

^ permalink raw reply	[flat|nested] 222+ messages in thread

* Re: [RFC] memarea: introduce memory area library
  2022-07-21  4:46 [RFC] memarea: introduce memory area library Chengwen Feng
  2022-07-21 15:22 ` Stephen Hemminger
@ 2022-08-04  6:36 ` Jerin Jacob
  2022-08-30 12:41 ` Dmitry Kozlyuk
                   ` (21 subsequent siblings)
  23 siblings, 0 replies; 222+ messages in thread
From: Jerin Jacob @ 2022-08-04  6:36 UTC (permalink / raw)
  To: Chengwen Feng; +Cc: Thomas Monjalon, dpdk-dev

On Thu, Jul 21, 2022 at 10:23 AM Chengwen Feng <fengchengwen@huawei.com> wrote:
>
> The memarea library is an allocator of variable-size object. It is a
> collection of allocated objects that can be efficiently alloc or free
> all at once, the main feature are as follows:
> a) it facilitate alloc and free of memory with low overhead.
>
> b) it provides refcnt feature which could be useful in some scenes.
>
> c) it supports MT-safe as long as it's specified at creation time.
>
> d) it's memory source could comes from:
> d.1) system API: malloc in C library.
> d.2) user provided address: it can be from the rte_malloc API series
> or extended memory as long as it is available.
> d.3) user provided memarea: it can be from another memarea.
>
> 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
>

Looks like a good feature to add to DPDK .


> Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
> ---
>  lib/memarea/meson.build   |  10 ++
>  lib/memarea/rte_memarea.c |  52 ++++++++++
>  lib/memarea/rte_memarea.h | 205 ++++++++++++++++++++++++++++++++++++++
>  lib/memarea/version.map   |  16 +++
>  lib/meson.build           |   1 +
>  5 files changed, 284 insertions(+)
>  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/lib/memarea/rte_memarea.h b/lib/memarea/rte_memarea.h
> new file mode 100644
> index 0000000000..dfbe845595
> --- /dev/null
> +++ b/lib/memarea/rte_memarea.h
> @@ -0,0 +1,205 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2022 HiSilicon Limited
> + */
> +
> +#ifndef RTE_MEMAREA_H
> +#define RTE_MEMAREA_H
> +
> +/**
> + * @file
> + * RTE Memarea.
> + *
> + * A memory area is an allocator of variable-size object. It is identified
> + * by its name.
> + *
> + * The memarea is a collection of allocated objects that can be efficiently
> + * alloc or free all at once, the main feature are as follows:
> + *   a) it facilitate alloc and free of memory with low overhead.
> + *   b) it provides refcnt feature which could be useful in some scenes.
> + *   c) it supports MT-safe as long as it's specified at creation time.
> + *   d) it's memory source could comes from:
> + *      d.1) system API: malloc in C library.
> + *      d.2) user provided address: it can be from the rte_malloc API series
> + *           or extended memory as long as it is available.
> + *      d.3) user provided memarea: it can be from another memarea. So we can
> + *           build the following memory management structure:
> + *                         memarea-1
> + *                             |
> + *                             v
> + *                 ------------------------
> + *                 |           |          |
> + *                 v           v          v
> + *              memarea-2   memarea-3    obj
> + *
> + */
> +
> +#include <stdbool.h>
> +#include <stdint.h>
> +#include <stdio.h>
> +
> +#include <rte_compat.h>
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif
> +
> +#define RTE_MEMAREA_NAMESIZE   64
> +
> +/**
> + * Memarea memory source.
> + */
> +enum rte_memarea_source {
> +       /** Memory source comes from sys api (e.g. malloc) */
> +       RTE_MEMAREA_SOURCE_SYSAPI,
> +       /** Memory source comes from user-provided address */
> +       RTE_MEMAREA_SOURCE_USER_ADDR,
> +       /** Memory source comes from user-provided memarea */
> +       RTE_MEMAREA_SOURCE_USER_MEMAREA,
> +};
> +
> +struct rte_memarea;
> +
> +struct rte_memarea_param {
> +       char name[RTE_MEMAREA_NAMESIZE]; /**< Name of memarea */
> +       enum rte_memarea_source source;  /**< Memory source of memarea */
> +       uint64_t size;                   /**< Size (byte) of memarea */
> +       uint32_t align;                  /**< Align of allocated object */
> +       /** Indicates whether the memarea should be MT-safe */
> +       bool mt_safe;
> +       /** Indicates whether the memarea is visible to multiple process.
> +        * If the memory source is RTE_MEMAREA_SOURCE_USER_ADDR, this filed
> +        * depends on user settings and must be set.
> +        * If the memory source is RTE_MEMAREA_SOURCE_SYSAPI or
> +        * RTE_MEMAREA_SOURCE_USER_MEMAREA, this filed does not need to be set.
> +        */
> +       bool mp_visible;
> +       /** User provided address, this field is valid only when source
> +        * is set to RTE_MEMAREA_SOURCE_USER_ADDR.
> +        */
> +       void *user_addr;
> +       /** User provided memarea, this field is valid only when source
> +        * is set to RTE_MEMAREA_SOURCE_MEMAREA.
> +        */
> +       struct rte_memarea *user_memarea;

Above two can be in union as it is  based on enum rte_memarea_source.

> +};
> +
> +struct rte_memarea {
> +       void *private_data; /**< private management data pointer*/
> +       struct rte_memarea_param init;
> +};


Make it opaque to application.

Also, In Terms of features, good to have following items

1)Stats
2)Detects the memory leak.

^ permalink raw reply	[flat|nested] 222+ messages in thread

* Re: [RFC] memarea: introduce memory area library
  2022-07-21  4:46 [RFC] memarea: introduce memory area library Chengwen Feng
  2022-07-21 15:22 ` Stephen Hemminger
  2022-08-04  6:36 ` Jerin Jacob
@ 2022-08-30 12:41 ` Dmitry Kozlyuk
  2022-09-20  3:46 ` [PATCH 0/8] introduce memarea library Chengwen Feng
                   ` (20 subsequent siblings)
  23 siblings, 0 replies; 222+ messages in thread
From: Dmitry Kozlyuk @ 2022-08-30 12:41 UTC (permalink / raw)
  To: Chengwen Feng; +Cc: Thomas Monjalon, dpdk-dev

[-- Attachment #1: Type: text/plain, Size: 4369 bytes --]

>
> Note:
> a) the memarea is oriented towards the application layer, which could
> provides 'region-based memory management' [1] function.
>

Judging from the API, this library would rather provide
an interface to a generic allocator over a fixed memory extent,
because it offers freeing of specific elements, and thus must track them.
So it's more than RBMM. Is this intended?
It's a very interesting RFC anyway, just trying to understand the scope.

b) the eal library also provide memory zone/heap management, but these
> are tied to huge pages management.
>
[...]
> + * The memarea is a collection of allocated objects that can be
> efficiently
> + * alloc or free all at once, the main feature are as follows:
> + *   a) it facilitate alloc and free of memory with low overhead.
> + *   [...]
>
+ *   c) it supports MT-safe as long as it's specified at creation time.
>

These two bullets seem to add the most value compared to DPDK heap API.
DPDK heap overhead is at least 64 bytes per allocation (sizeof malloc_elem),
so I assume memarea aims at a large number of small elements.


> +struct rte_memarea_param {
> +       char name[RTE_MEMAREA_NAMESIZE]; /**< Name of memarea */
> +       enum rte_memarea_source source;  /**< Memory source of memarea */
> +       uint64_t size;                   /**< Size (byte) of memarea */
>

Is it an upper limit or a guaranteed size?
It probably depends on the source: guaranteed for USER_ADDR,
upper limit for SYSAPI (or it would be no different from USER_ADDR),
not sure about USER_MEMAREA.

Do you envision memarea as always limited?
Generic allocators usually have means of adding extents,
even if this one doesn't currently.

Nit: size is uint64_t here but uint32_t in rte_memarea_allloc().
Should be size_t in both places.


> +       uint32_t align;                  /**< Align of allocated object */
>
+       /** Indicates whether the memarea should be MT-safe */
> +       bool mt_safe;
> +       /** Indicates whether the memarea is visible to multiple process.
> +        * If the memory source is RTE_MEMAREA_SOURCE_USER_ADDR, this filed
> +        * depends on user settings and must be set.
> +        * If the memory source is RTE_MEMAREA_SOURCE_SYSAPI or
> +        * RTE_MEMAREA_SOURCE_USER_MEMAREA, this filed does not need to be
> set.
> +        */
> +       bool mp_visible;
> +       /** User provided address, this field is valid only when source
> +        * is set to RTE_MEMAREA_SOURCE_USER_ADDR.
> +        */
> +       void *user_addr;
> +       /** User provided memarea, this field is valid only when source
> +        * is set to RTE_MEMAREA_SOURCE_MEMAREA.
> +        */
> +       struct rte_memarea *user_memarea;
>

Jerin already suggested a union here.
I'll add another reason to do so: if in the future there will be new
memarea types
that require new options, one pointer-sized field can be used to pass
anything
without breaking the ABI once this structure becomes stable.


> +/**
> + * @warning
> + * @b EXPERIMENTAL: this API may change without prior notice.
> + *
> + * Update memory's refcnt.
> + *
> + * Update one memory region's refcnt.
> + *
> + * @param ma
> + *   The pointer of memarea.
> + * @param ptr
> + *   The pointer of memory region which need be updated refcnt.
> + * @param value
> + *   The value which need be updated.
> + *   Note: it could be negative.
> + *
> + * @return
> + *   0 on success. Otherwise negative value is returned.
> + */
> +__rte_experimental
> +int rte_memarea_refcnt_update(struct rte_memarea *ma, void *ptr, int16_t
> value);
>

If this function only updates the refcnt, an API to inspect the refcnt is
missing.
Furthermore, in this case refcnt is just a value attached to every object,
what is the benefit compared to simply storing it in the object?

If this function also frees "ptr" when refcnt reaches zero,
missing is a way for the user to know that it did.
What happens if refcnt > 1 on rte_memarea_free()?

I don't think refcnt belongs to this library.
A principal objection: memarea is for freeing all objects at once,
refcnt is for releasing objects one-by-one when they're not used.
Technical issues I foresee: refcnt can be atomic (and require alignment) or
not,
16 bits may be too few (rte_flow_action_handle ref'd by thousands of
rte_flow).
Refcnt could be optional per memarea, but it seems like another
complication.

[-- Attachment #2: Type: text/html, Size: 6663 bytes --]

^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH 0/8] introduce memarea library
  2022-07-21  4:46 [RFC] memarea: introduce memory area library Chengwen Feng
                   ` (2 preceding siblings ...)
  2022-08-30 12:41 ` Dmitry Kozlyuk
@ 2022-09-20  3:46 ` Chengwen Feng
  2022-09-20  3:46   ` [PATCH 1/8] memarea: introduce memory area library Chengwen Feng
                     ` (7 more replies)
  2022-09-21  3:12 ` [PATCH v2 0/9] introduce memarea library Chengwen Feng
                   ` (19 subsequent siblings)
  23 siblings, 8 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-09-20  3:46 UTC (permalink / raw)
  To: thomas; +Cc: dev, stephen, jerinjacobk, dmitry.kozliuk

The memarea library is an allocator of variable-size object. It is a
collection of allocated objects that can be efficiently alloc or free
all at once, the main feature are as follows:
a) it facilitate alloc and free of memory with low overhead.

b) it provides refcnt feature which could be useful in some scenes.

c) it supports MT-safe as long as it's specified at creation time.

d) it's memory source could comes from:
d.1) system API: malloc in C library.
d.2) user provided address: it can be from the rte_malloc API series
or extended memory as long as it is available.
d.3) user provided memarea: it can be from another memarea.

e) it provides backup memory mechanism, the memarea object could use
another memarea object 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 <fengchengwen@huawei.com>

Chengwen Feng (8):
  memarea: introduce memory area 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

 MAINTAINERS                            |   6 +
 app/test/meson.build                   |   2 +
 app/test/test_memarea.c                | 340 ++++++++++++++++++++++
 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  |  57 ++++
 doc/guides/rel_notes/release_22_11.rst |   6 +
 lib/eal/include/rte_log.h              |   1 +
 lib/memarea/memarea_private.h          |  35 +++
 lib/memarea/meson.build                |  16 +
 lib/memarea/rte_memarea.c              | 385 +++++++++++++++++++++++++
 lib/memarea/rte_memarea.h              | 214 ++++++++++++++
 lib/memarea/version.map                |  16 +
 lib/meson.build                        |   1 +
 15 files changed, 1083 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.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH 1/8] memarea: introduce memory area library
  2022-09-20  3:46 ` [PATCH 0/8] introduce memarea library Chengwen Feng
@ 2022-09-20  3:46   ` Chengwen Feng
  2022-09-20 11:30     ` Dmitry Kozlyuk
  2022-09-20  3:46   ` [PATCH 2/8] test/memarea: support memarea test Chengwen Feng
                     ` (6 subsequent siblings)
  7 siblings, 1 reply; 222+ messages in thread
From: Chengwen Feng @ 2022-09-20  3:46 UTC (permalink / raw)
  To: thomas; +Cc: dev, stephen, jerinjacobk, dmitry.kozliuk

The memarea library is an allocator of variable-size object. It is a
collection of allocated objects that can be efficiently alloc or free
all at once, the main features are as follows:
a) it facilitate alloc and free of memory with low overhead.

b) it provides refcnt feature which could be useful in some scenes.

c) it supports MT-safe as long as it's specified at creation time.

d) it's memory source could comes from:
d.1) system API: malloc in C library.
d.2) user provided address: it can be from the rte_malloc API series
or extended memory as long as it is available.
d.3) user provided memarea: it can be from another memarea.

This patch provides create/destroy API.

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 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  |  41 ++++++++
 doc/guides/rel_notes/release_22_11.rst |   6 ++
 lib/eal/include/rte_log.h              |   1 +
 lib/memarea/memarea_private.h          |  30 ++++++
 lib/memarea/meson.build                |  16 +++
 lib/memarea/rte_memarea.c              | 140 +++++++++++++++++++++++++
 lib/memarea/rte_memarea.h              | 131 +++++++++++++++++++++++
 lib/memarea/version.map                |  12 +++
 lib/meson.build                        |   1 +
 13 files changed, 387 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 32ffdd1a61..92e77f1318 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1557,6 +1557,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 <fengchengwen@huawei.com>
+F: lib/memarea
+F: doc/guides/prog_guide/memarea_lib.rst
+
 Membership - EXPERIMENTAL
 M: Yipeng Wang <yipeng1.wang@intel.com>
 M: Sameh Gobriel <sameh.gobriel@intel.com>
diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md
index 186a258be4..25dbef0b68 100644
--- a/doc/api/doxy-api-index.md
+++ b/doc/api/doxy-api-index.md
@@ -64,7 +64,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 608494a7c0..bdc5d2b0d5 100644
--- a/doc/api/doxy-api.conf.in
+++ b/doc/api/doxy-api.conf.in
@@ -55,6 +55,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..1979f0a12c
--- /dev/null
+++ b/doc/guides/prog_guide/memarea_lib.rst
@@ -0,0 +1,41 @@
+..  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:
+
+* It facilitate alloc and free of memory with low overhead.
+
+* It's memory source could comes from: 1) System API: e.g. malloc/memalign in
+  C library. 2) User provided address: it can be from the rte_malloc API series
+  or extended memory as long as it is available. 3) User provided memarea: it
+  can be from another memarea.
+
+* The default aligement size is ``RTE_CACHE_LINE_SIZE``.
+
+* It provides refcnt feature which could be useful in some scenes.
+
+* 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 object, 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 object.
+
+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 8c021cf050..1cf522132c 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 library is an allocator of variable-size objects, it is oriented
+  towards the application layer, which could provides 'region-based memory
+  management' function.
+
 
 Removed Items
 -------------
diff --git a/lib/eal/include/rte_log.h b/lib/eal/include/rte_log.h
index 25ce42cdfc..708f3a39dd 100644
--- a/lib/eal/include/rte_log.h
+++ b/lib/eal/include/rte_log.h
@@ -48,6 +48,7 @@ extern "C" {
 #define RTE_LOGTYPE_EFD       18 /**< Log related to EFD. */
 #define RTE_LOGTYPE_EVENTDEV  19 /**< Log related to eventdev. */
 #define RTE_LOGTYPE_GSO       20 /**< Log related to GSO. */
+#define RTE_LOGTYPE_MEMAREA   21 /**< Log related to memarea. */
 
 /* these log types can be used in an application */
 #define RTE_LOGTYPE_USER1     24 /**< User-defined log type 1. */
diff --git a/lib/memarea/memarea_private.h b/lib/memarea/memarea_private.h
new file mode 100644
index 0000000000..94931b46e9
--- /dev/null
+++ b/lib/memarea/memarea_private.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2022 HiSilicon Limited
+ */
+
+#ifndef MEMAREA_PRIVATE_H
+#define MEMAREA_PRIVATE_H
+
+#include <rte_memarea.h>
+
+#define MEMAREA_FREE_ELEM_COOKIE	0xFFFFFFFF
+
+struct memarea_elem {
+	size_t   size;
+	uint32_t cookie;
+	int32_t  refcnt; /* Non-zero indicates that it has been allocated */
+	TAILQ_ENTRY(memarea_elem) elem_node;
+	TAILQ_ENTRY(memarea_elem) free_node;
+} __rte_cache_aligned;
+
+TAILQ_HEAD(memarea_elem_list, memarea_elem);
+
+struct memarea_private {
+	struct rte_memarea_param init;
+	rte_spinlock_t           lock;
+	void                    *area_addr;
+	struct memarea_elem_list elem_list;
+	struct memarea_elem_list free_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..0a74fb4cd1
--- /dev/null
+++ b/lib/memarea/meson.build
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2022 HiSilicon Limited
+
+if is_windows
+    build = false
+    reason = 'not supported on Windows'
+    subdir_done()
+endif
+
+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..3f535d315f
--- /dev/null
+++ b/lib/memarea/rte_memarea.c
@@ -0,0 +1,140 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2022 HiSilicon Limited
+ */
+
+#include <stdio.h>
+
+#include <rte_common.h>
+#include <rte_log.h>
+#include <rte_malloc.h>
+#include <rte_memarea.h>
+#include <rte_spinlock.h>
+
+#include "memarea_private.h"
+
+static int
+memarea_check_param(const struct rte_memarea_param *init)
+{
+	size_t len;
+
+	len = strnlen(init->name, RTE_MEMAREA_NAMESIZE);
+	if (len == 0 || len >= RTE_MEMAREA_NAMESIZE) {
+		RTE_LOG(ERR, MEMAREA, "memarea name invalid!\n");
+		return -EINVAL;
+	}
+
+	if (init->source >= RTE_MEMAREA_SOURCE_BUTT) {
+		RTE_LOG(ERR, MEMAREA, "memarea source invalid!\n");
+		return -EINVAL;
+	}
+
+	if (init->total_sz <= sizeof(struct memarea_elem)) {
+		RTE_LOG(ERR, MEMAREA, "memarea total size invalid!\n");
+		return -EINVAL;
+	}
+
+	if (init->source == RTE_MEMAREA_SOURCE_USER_ADDR && init->user_addr == NULL) {
+		RTE_LOG(ERR, MEMAREA, "memarea user provided addr invalid!\n");
+		return -EINVAL;
+	}
+
+	if (init->source == RTE_MEMAREA_SOURCE_USER_ADDR &&
+	    ((uintptr_t)init->user_addr & (RTE_CACHE_LINE_SIZE - 1))) {
+		RTE_LOG(ERR, MEMAREA, "memarea user provided addr align invalid!\n");
+		return -EINVAL;
+	}
+
+	if (init->source == RTE_MEMAREA_SOURCE_USER_MEMAREA && init->user_memarea == NULL) {
+		RTE_LOG(ERR, MEMAREA, "memarea user provided memarea invalid!\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void *
+memarea_alloc_from_system_api(size_t size)
+{
+	void *ptr = NULL;
+	int ret;
+
+	ret = posix_memalign(&ptr, RTE_CACHE_LINE_SIZE, size);
+	if (ret)
+		return NULL;
+	return ptr;
+}
+
+static void *
+memarea_alloc_area(const struct rte_memarea_param *init)
+{
+	void *ptr = NULL;
+
+	if (init->source == RTE_MEMAREA_SOURCE_SYSTEM_API)
+		ptr = memarea_alloc_from_system_api(init->total_sz);
+	else if (init->source == RTE_MEMAREA_SOURCE_USER_ADDR)
+		ptr = init->user_addr;
+
+	if (ptr == NULL)
+		RTE_LOG(ERR, MEMAREA, "memarea alloc memory area fail!\n");
+
+	return ptr;
+}
+
+struct rte_memarea *
+rte_memarea_create(const struct rte_memarea_param *init)
+{
+	struct memarea_private *priv;
+	struct memarea_elem *elem;
+	struct rte_memarea *ma;
+	void *addr;
+	int ret;
+
+	ret = memarea_check_param(init);
+	if (ret)
+		return NULL;
+
+	addr = memarea_alloc_area(init);
+	if (addr == NULL)
+		return NULL;
+
+	ma = rte_zmalloc(NULL, sizeof(struct rte_memarea), RTE_CACHE_LINE_SIZE);
+	priv = rte_zmalloc(NULL, sizeof(struct memarea_private), RTE_CACHE_LINE_SIZE);
+	if (ma == NULL || priv == NULL) {
+		RTE_LOG(ERR, MEMAREA, "malloc memarea management obj fail!\n");
+		rte_free(ma);
+		rte_free(priv);
+		return NULL;
+	}
+
+	ma->private_data = priv;
+	priv->init = *init;
+	rte_spinlock_init(&priv->lock);
+	TAILQ_INIT(&priv->elem_list);
+	TAILQ_INIT(&priv->free_list);
+	priv->area_addr = addr;
+	elem = addr;
+	elem->size = init->total_sz - sizeof(struct memarea_elem);
+	elem->cookie = MEMAREA_FREE_ELEM_COOKIE;
+	elem->refcnt = 0;
+	TAILQ_INSERT_TAIL(&priv->elem_list, elem, elem_node);
+	TAILQ_INSERT_TAIL(&priv->free_list, elem, free_node);
+
+	return ma;
+}
+
+static void
+memarea_free_area(struct memarea_private *priv)
+{
+	if (priv->init.source == RTE_MEMAREA_SOURCE_SYSTEM_API)
+		free(priv->area_addr);
+}
+
+void
+rte_memarea_destroy(struct rte_memarea *ma)
+{
+	if (ma == NULL)
+		return;
+	memarea_free_area(ma->private_data);
+	rte_free(ma->private_data);
+	rte_free(ma);
+}
diff --git a/lib/memarea/rte_memarea.h b/lib/memarea/rte_memarea.h
new file mode 100644
index 0000000000..ddca0a47e2
--- /dev/null
+++ b/lib/memarea/rte_memarea.h
@@ -0,0 +1,131 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2022 HiSilicon Limited
+ */
+
+#ifndef RTE_MEMAREA_H
+#define RTE_MEMAREA_H
+
+/**
+ * @file
+ * RTE Memarea.
+ *
+ * A memory area is an allocator of variable-size object. It is identified
+ * by its name.
+ *
+ * The memarea is a collection of allocated objects that can be efficiently
+ * alloc or free all at once, the main feature are as follows:
+ *   a) It facilitate alloc and free of memory with low overhead.
+ *   b) It's memory source could comes from:
+ *      1) System API: malloc/memalign in C library.
+ *      2) User provided address: it can be from the rte_malloc API series
+ *         or extended memory as long as it is available. The address must be
+ *         aligned to RTE_CACHE_LINE_SIZE.
+ *      3) User provided memarea: it can be from another memarea. So we can
+ *         build the following memory management structure:
+ *         \code{.unparsed}
+ *                           -------------
+ *                           | memarea-1 |
+ *                           -------------
+ *                                 |
+ *                                 v
+ *                  ------------------------------
+ *                  |               |            |
+ *                  v               v            v
+ *            -------------   -------------   -------
+ *            | memarea-2 |   | memarea-3 |   | obj |
+ *            -------------   -------------   -------
+ *         \endcode
+ *   c) The default alignment size is RTE_CACHE_LINE_SIZE.
+ *   d) It provides refcnt feature which could be useful in some scenes.
+ *   e) 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 object.
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include <rte_compat.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define RTE_MEMAREA_NAMESIZE	64
+
+/**
+ * Memarea memory source.
+ */
+enum rte_memarea_source {
+	/** Memory source comes from system API (e.g. malloc). */
+	RTE_MEMAREA_SOURCE_SYSTEM_API,
+	/** Memory source comes from user-provided address. */
+	RTE_MEMAREA_SOURCE_USER_ADDR,
+	/** Memory source comes from user-provided memarea. */
+	RTE_MEMAREA_SOURCE_USER_MEMAREA,
+
+	RTE_MEMAREA_SOURCE_BUTT
+};
+
+struct rte_memarea {
+	void *private_data; /**< private management data pointer. */
+};
+
+struct rte_memarea_param {
+	char name[RTE_MEMAREA_NAMESIZE]; /**< Name of memarea. */
+	enum rte_memarea_source source;  /**< Memory source of memarea. */
+	size_t total_sz;                 /**< total size (bytes) of memarea. */
+	/** Indicates whether the memarea API should be MT-safe. */
+	uint32_t mt_safe : 1;
+	union {
+		/** User provided address, this field is valid only when the
+		 * source is set to be RTE_MEMAREA_SOURCE_USER_ADDR.
+		 * Note: the provided address must align at least
+		 * RTE_CACHE_LINE_SIZE.
+		 */
+		void *user_addr;
+		/** User provided memarea, this field is valid only when the
+		 * source is set to be RTE_MEMAREA_SOURCE_USER_MEMAREA.
+		 */
+		struct rte_memarea *user_memarea;
+	};
+};
+
+/**
+ * @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 c648f7d800..521a25d6c0 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -42,6 +42,7 @@ libraries = [
         'kni',
         'latencystats',
         'lpm',
+        'memarea',
         'member',
         'pcapng',
         'power',
-- 
2.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH 2/8] test/memarea: support memarea test
  2022-09-20  3:46 ` [PATCH 0/8] introduce memarea library Chengwen Feng
  2022-09-20  3:46   ` [PATCH 1/8] memarea: introduce memory area library Chengwen Feng
@ 2022-09-20  3:46   ` Chengwen Feng
  2022-09-20  3:46   ` [PATCH 3/8] memarea: support alloc/free/update-refcnt API Chengwen Feng
                     ` (5 subsequent siblings)
  7 siblings, 0 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-09-20  3:46 UTC (permalink / raw)
  To: thomas; +Cc: dev, stephen, jerinjacobk, dmitry.kozliuk

This patch support memarea test about API rte_memarea_create and
rte_memarea_destroy.

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 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 92e77f1318..e051829906 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1561,6 +1561,7 @@ Memarea - EXPERIMENTAL
 M: Chengwen Feng <fengchengwen@huawei.com>
 F: lib/memarea
 F: doc/guides/prog_guide/memarea_lib.rst
+F: app/test/test_memarea*
 
 Membership - EXPERIMENTAL
 M: Yipeng Wang <yipeng1.wang@intel.com>
diff --git a/app/test/meson.build b/app/test/meson.build
index bf1d81f84a..ad4e0baee5 100644
--- a/app/test/meson.build
+++ b/app/test/meson.build
@@ -83,6 +83,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',
@@ -198,6 +199,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..3b03b9f06c
--- /dev/null
+++ b/app/test/test_memarea.c
@@ -0,0 +1,130 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2022 HiSilicon Limited
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#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 <rte_memarea.h>
+
+#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 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_BUTT;
+	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");
+
+	return 0;
+}
+
+static int
+test_memarea_create_destroy(void)
+{
+	struct rte_memarea_param init;
+	uint8_t user_buffer[MEMAREA_TEST_DEFAULT_SIZE + RTE_CACHE_LINE_SIZE];
+	struct rte_memarea *ma;
+
+	/* test for create with system API */
+	test_memarea_init_def_param(&init);
+	init.source = RTE_MEMAREA_SOURCE_SYSTEM_API;
+	ma = rte_memarea_create(&init);
+	RTE_TEST_ASSERT(ma != NULL, "Expected Non-NULL");
+	rte_memarea_destroy(ma);
+
+	/* test for create with user-address */
+	test_memarea_init_def_param(&init);
+	init.source = RTE_MEMAREA_SOURCE_USER_ADDR;
+	init.user_addr = (void *)(((uintptr_t)user_buffer + RTE_CACHE_LINE_SIZE) &
+				  ~(RTE_CACHE_LINE_SIZE - 1));
+	ma = rte_memarea_create(&init);
+	RTE_TEST_ASSERT(ma != NULL, "Expected Non-NULL");
+	rte_memarea_destroy(ma);
+
+	return 0;
+}
+
+static int
+test_memarea(void)
+{
+	MEMAREA_TEST_API_RUN(test_memarea_create_bad_param);
+	MEMAREA_TEST_API_RUN(test_memarea_create_destroy);
+	return 0;
+}
+
+#endif /* !RTE_EXEC_ENV_WINDOWS */
+
+REGISTER_TEST_COMMAND(memarea_autotest, test_memarea);
-- 
2.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH 3/8] memarea: support alloc/free/update-refcnt API
  2022-09-20  3:46 ` [PATCH 0/8] introduce memarea library Chengwen Feng
  2022-09-20  3:46   ` [PATCH 1/8] memarea: introduce memory area library Chengwen Feng
  2022-09-20  3:46   ` [PATCH 2/8] test/memarea: support memarea test Chengwen Feng
@ 2022-09-20  3:46   ` Chengwen Feng
  2022-09-20  3:46   ` [PATCH 4/8] test/memarea: support alloc/free/update-refcnt test Chengwen Feng
                     ` (4 subsequent siblings)
  7 siblings, 0 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-09-20  3:46 UTC (permalink / raw)
  To: thomas; +Cc: dev, stephen, jerinjacobk, dmitry.kozliuk

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

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 doc/guides/prog_guide/memarea_lib.rst |  10 ++
 lib/memarea/memarea_private.h         |   3 +
 lib/memarea/rte_memarea.c             | 140 ++++++++++++++++++++++++++
 lib/memarea/rte_memarea.h             |  56 +++++++++++
 lib/memarea/version.map               |   3 +
 5 files changed, 212 insertions(+)

diff --git a/doc/guides/prog_guide/memarea_lib.rst b/doc/guides/prog_guide/memarea_lib.rst
index 1979f0a12c..967129d560 100644
--- a/doc/guides/prog_guide/memarea_lib.rst
+++ b/doc/guides/prog_guide/memarea_lib.rst
@@ -35,6 +35,16 @@ failed.
 
 The ``rte_memarea_destroy()`` function is used to destroy a memarea object.
 
+The ``rte_memarea_alloc()`` function is used to alloc one memory region from
+the memarea object.
+
+The ``rte_memarea_free()`` function is used to free one memory region which
+allocated by ``rte_memarea_alloc()``.
+
+The ``rte_memarea_update_refcnt()`` function is used to update the memory
+region's reference count, if the count reaches zero, the memory region will
+be freed to memarea object.
+
 Reference
 ---------
 
diff --git a/lib/memarea/memarea_private.h b/lib/memarea/memarea_private.h
index 94931b46e9..f71e01e7b5 100644
--- a/lib/memarea/memarea_private.h
+++ b/lib/memarea/memarea_private.h
@@ -25,6 +25,9 @@ struct memarea_private {
 	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 3f535d315f..fe4a820173 100644
--- a/lib/memarea/rte_memarea.c
+++ b/lib/memarea/rte_memarea.c
@@ -3,6 +3,7 @@
  */
 
 #include <stdio.h>
+#include <sys/queue.h>
 
 #include <rte_common.h>
 #include <rte_log.h>
@@ -73,6 +74,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 alloc memory area fail!\n");
@@ -127,6 +130,8 @@ memarea_free_area(struct memarea_private *priv)
 {
 	if (priv->init.source == RTE_MEMAREA_SOURCE_SYSTEM_API)
 		free(priv->area_addr);
+	else if (priv->init.source == RTE_MEMAREA_SOURCE_USER_MEMAREA)
+		rte_memarea_free(priv->init.user_memarea, priv->area_addr);
 }
 
 void
@@ -138,3 +143,138 @@ rte_memarea_destroy(struct rte_memarea *ma)
 	rte_free(ma->private_data);
 	rte_free(ma);
 }
+
+static inline void
+memarea_lock(struct memarea_private *priv)
+{
+	if (priv->init.mt_safe)
+		rte_spinlock_lock(&priv->lock);
+}
+
+static inline void
+memarea_unlock(struct memarea_private *priv)
+{
+	if (priv->init.mt_safe)
+		rte_spinlock_unlock(&priv->lock);
+}
+
+#define 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 = 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 memarea_private *priv, struct memarea_elem *elem, size_t need_size)
+{
+	size_t align_size = 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(&priv->elem_list, elem, new_elem, elem_node);
+	TAILQ_INSERT_AFTER(&priv->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_private *priv;
+	struct memarea_elem *elem;
+	void *ptr = NULL;
+
+	if (unlikely(ma == NULL || size == 0))
+		return NULL;
+
+	priv = ma->private_data;
+	memarea_lock(priv);
+	TAILQ_FOREACH(elem, &priv->free_list, free_node) {
+		if (elem->size < size)
+			continue;
+		if (memarea_whether_add_node(elem->size, size))
+			memarea_add_node(priv, elem, size);
+		elem->cookie = cookie;
+		elem->refcnt = 1;
+		TAILQ_REMOVE(&priv->free_list, elem, free_node);
+		ptr = (void *)((uintptr_t)elem + sizeof(struct memarea_elem));
+		break;
+	}
+	if (unlikely(ptr == NULL))
+		priv->alloc_fails++;
+	memarea_unlock(priv);
+
+	return ptr;
+}
+
+void
+rte_memarea_free(struct rte_memarea *ma, void *ptr)
+{
+	rte_memarea_update_refcnt(ma, ptr, -1);
+}
+
+static inline void
+memarea_merge_node(struct memarea_private *priv, struct memarea_elem *curr,
+		   struct memarea_elem *next, bool del_next_from_free,
+		   bool add_curr_to_free)
+{
+	curr->size += next->size + sizeof(struct memarea_elem);
+	next->size = 0;
+	next->cookie = 0;
+	TAILQ_REMOVE(&priv->elem_list, next, elem_node);
+	if (del_next_from_free)
+		TAILQ_REMOVE(&priv->free_list, next, free_node);
+	if (add_curr_to_free)
+		TAILQ_INSERT_TAIL(&priv->free_list, curr, free_node);
+}
+
+static inline void
+memarea_free_elem(struct memarea_private *priv, struct memarea_elem *elem)
+{
+	struct memarea_elem *prev, *next;
+	bool merged = false;
+	prev = TAILQ_PREV(elem, memarea_elem_list, elem_node);
+	next = TAILQ_NEXT(elem, elem_node);
+	if (prev != NULL && prev->refcnt == 0) {
+		memarea_merge_node(priv, prev, elem, false, false);
+		elem = prev;
+		merged = true;
+	}
+	if (next != NULL && next->refcnt == 0) {
+		memarea_merge_node(priv, elem, next, true, !merged);
+		merged = true;
+	}
+	if (!merged) {
+		elem->cookie = MEMAREA_FREE_ELEM_COOKIE;
+		TAILQ_INSERT_TAIL(&priv->free_list, elem, free_node);
+	}
+}
+
+void
+rte_memarea_update_refcnt(struct rte_memarea *ma, void *ptr, int16_t value)
+{
+	struct memarea_elem *elem = (struct memarea_elem *)((uintptr_t)ptr -
+							    sizeof(struct memarea_elem));
+	struct memarea_private *priv = ma->private_data;
+
+	memarea_lock(priv);
+	if (unlikely(elem->refcnt <= 0 || elem->refcnt + value < 0)) {
+		RTE_LOG(ERR, MEMAREA,
+			"memarea cookie: %u curr refcnt: %d update refcnt: %d check fail!\n",
+			elem->cookie, elem->refcnt, value);
+		priv->refcnt_check_fails++;
+		if (elem->refcnt > 0)
+			elem->refcnt += value;
+		memarea_unlock(priv);
+		return;
+	}
+	elem->refcnt += value;
+	if (elem->refcnt == 0)
+		memarea_free_elem(priv, elem);
+	memarea_unlock(priv);
+}
diff --git a/lib/memarea/rte_memarea.h b/lib/memarea/rte_memarea.h
index ddca0a47e2..cded2904e3 100644
--- a/lib/memarea/rte_memarea.h
+++ b/lib/memarea/rte_memarea.h
@@ -124,6 +124,62 @@ 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 region from the memarea.
+ *
+ * @param ma
+ *   The pointer of memarea.
+ * @param size
+ *   The memory size to be allocated.
+ * @param cookie
+ *   User-provided footprint which could used to debug memory leak problem.
+ *
+ * @return
+ *   Non-NULL on success. Otherwise NULL is returned.
+ */
+__rte_experimental
+void *rte_memarea_alloc(struct rte_memarea *ma, size_t size, uint32_t cookie);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Free memory to memarea.
+ *
+ * Free one memory region to the memarea.
+ *
+ * @param ma
+ *   The pointer of memarea.
+ * @param ptr
+ *   The pointer of memory region which need be freed.
+ */
+__rte_experimental
+void rte_memarea_free(struct rte_memarea *ma, void *ptr);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Update memory's refcnt.
+ *
+ * Update one memory region's refcnt.
+ * When refcnt is updated to be zero, the memory region is freed.
+ *
+ * @param ma
+ *   The pointer of memarea.
+ * @param ptr
+ *   The pointer of memory region which need be updated refcnt.
+ * @param value
+ *   The value which need be updated.
+ */
+__rte_experimental
+void rte_memarea_update_refcnt(struct rte_memarea *ma, void *ptr, int16_t value);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/memarea/version.map b/lib/memarea/version.map
index f36a04d7cf..a0026fc5f9 100644
--- a/lib/memarea/version.map
+++ b/lib/memarea/version.map
@@ -1,8 +1,11 @@
 EXPERIMENTAL {
 	global:
 
+	rte_memarea_alloc;
 	rte_memarea_create;
 	rte_memarea_destroy;
+	rte_memarea_free;
+	rte_memarea_update_refcnt;
 
 	local: *;
 };
-- 
2.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH 4/8] test/memarea: support alloc/free/update-refcnt test
  2022-09-20  3:46 ` [PATCH 0/8] introduce memarea library Chengwen Feng
                     ` (2 preceding siblings ...)
  2022-09-20  3:46   ` [PATCH 3/8] memarea: support alloc/free/update-refcnt API Chengwen Feng
@ 2022-09-20  3:46   ` Chengwen Feng
  2022-09-20  3:46   ` [PATCH 5/8] memarea: support dump API Chengwen Feng
                     ` (3 subsequent siblings)
  7 siblings, 0 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-09-20  3:46 UTC (permalink / raw)
  To: thomas; +Cc: dev, stephen, jerinjacobk, dmitry.kozliuk

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

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 app/test/test_memarea.c | 138 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 137 insertions(+), 1 deletion(-)

diff --git a/app/test/test_memarea.c b/app/test/test_memarea.c
index 3b03b9f06c..66616be0b6 100644
--- a/app/test/test_memarea.c
+++ b/app/test/test_memarea.c
@@ -40,6 +40,12 @@ test_memarea_init_def_param(struct rte_memarea_param *init)
 	init->mt_safe = 1;
 }
 
+static void
+test_memarea_fill_alloced_region(void *ptr, size_t size)
+{
+	memset(ptr, 0xff, size);
+}
+
 static int
 test_memarea_create_bad_param(void)
 {
@@ -94,9 +100,9 @@ test_memarea_create_bad_param(void)
 static int
 test_memarea_create_destroy(void)
 {
+	struct rte_memarea *ma, *user_ma;
 	struct rte_memarea_param init;
 	uint8_t user_buffer[MEMAREA_TEST_DEFAULT_SIZE + RTE_CACHE_LINE_SIZE];
-	struct rte_memarea *ma;
 
 	/* test for create with system API */
 	test_memarea_init_def_param(&init);
@@ -114,6 +120,133 @@ 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 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_alloced_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_alloced_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 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_alloced_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_alloced_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)
+{
+#define ALLOC_MAX_NUM	8
+	struct rte_memarea_param init;
+	struct rte_memarea *ma;
+	void *ptr[ALLOC_MAX_NUM];
+	int i;
+
+	/* 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");
+	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, 0);
+
+	/* 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, ptr[6]);
+
+	rte_memarea_destroy(ma);
+
 	return 0;
 }
 
@@ -122,6 +255,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 0;
 }
 
-- 
2.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH 5/8] memarea: support dump API
  2022-09-20  3:46 ` [PATCH 0/8] introduce memarea library Chengwen Feng
                     ` (3 preceding siblings ...)
  2022-09-20  3:46   ` [PATCH 4/8] test/memarea: support alloc/free/update-refcnt test Chengwen Feng
@ 2022-09-20  3:46   ` Chengwen Feng
  2022-09-20  3:46   ` [PATCH 6/8] test/memarea: support dump test Chengwen Feng
                     ` (2 subsequent siblings)
  7 siblings, 0 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-09-20  3:46 UTC (permalink / raw)
  To: thomas; +Cc: dev, stephen, jerinjacobk, dmitry.kozliuk

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

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 doc/guides/prog_guide/memarea_lib.rst |  3 +
 lib/memarea/rte_memarea.c             | 83 +++++++++++++++++++++++++++
 lib/memarea/rte_memarea.h             | 21 +++++++
 lib/memarea/version.map               |  1 +
 4 files changed, 108 insertions(+)

diff --git a/doc/guides/prog_guide/memarea_lib.rst b/doc/guides/prog_guide/memarea_lib.rst
index 967129d560..7686625c90 100644
--- a/doc/guides/prog_guide/memarea_lib.rst
+++ b/doc/guides/prog_guide/memarea_lib.rst
@@ -45,6 +45,9 @@ The ``rte_memarea_update_refcnt()`` function is used to update the memory
 region's reference count, if the count reaches zero, the memory region will
 be freed to memarea object.
 
+The ``rte_memarea_dump()`` function is used to dump the internal information
+of a memarea object.
+
 Reference
 ---------
 
diff --git a/lib/memarea/rte_memarea.c b/lib/memarea/rte_memarea.c
index fe4a820173..e40715d16a 100644
--- a/lib/memarea/rte_memarea.c
+++ b/lib/memarea/rte_memarea.c
@@ -2,6 +2,7 @@
  * Copyright(c) 2022 HiSilicon Limited
  */
 
+#include <inttypes.h>
 #include <stdio.h>
 #include <sys/queue.h>
 
@@ -278,3 +279,85 @@ rte_memarea_update_refcnt(struct rte_memarea *ma, void *ptr, int16_t value)
 		memarea_free_elem(priv, elem);
 	memarea_unlock(priv);
 }
+
+static const char *
+memarea_source_name(enum rte_memarea_source source)
+{
+	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_name(struct rte_memarea *ma)
+{
+	struct memarea_private *priv = ma->private_data;
+	return priv->init.name;
+}
+
+static uint32_t
+memarea_elem_list_num(struct memarea_private *priv)
+{
+	struct memarea_elem *elem;
+	uint32_t num = 0;
+
+	TAILQ_FOREACH(elem, &priv->elem_list, elem_node)
+		num++;
+
+	return num;
+}
+
+static uint32_t
+memarea_free_list_num(struct memarea_private *priv)
+{
+	struct memarea_elem *elem;
+	uint32_t num = 0;
+
+	TAILQ_FOREACH(elem, &priv->free_list, free_node)
+		num++;
+
+	return num;
+}
+
+static void
+memarea_dump_all(struct memarea_private *priv, FILE *f)
+{
+	struct memarea_elem *elem;
+
+	fprintf(f, "  regions:\n");
+	TAILQ_FOREACH(elem, &priv->elem_list, elem_node)
+		fprintf(f, "    size: 0x%lx cookie: %u refcnt: %d\n",
+			elem->size, elem->cookie, elem->refcnt);
+}
+
+int
+rte_memarea_dump(struct rte_memarea *ma, FILE *f, bool dump_all)
+{
+	struct memarea_private *priv;
+
+	if (ma == NULL || f == NULL)
+		return -EINVAL;
+
+	priv = ma->private_data;
+	memarea_lock(priv);
+	fprintf(f, "memarea name: %s\n", priv->init.name);
+	fprintf(f, "  source: %s\n", memarea_source_name(priv->init.source));
+	if (priv->init.source == RTE_MEMAREA_SOURCE_USER_MEMAREA)
+		fprintf(f, "  source-user-memarea: %s\n", memarea_name(priv->init.user_memarea));
+	fprintf(f, "  total-size: 0x%lx\n", priv->init.total_sz);
+	fprintf(f, "  mt-safe: %s\n", priv->init.mt_safe ? "yes" : "no");
+	fprintf(f, "  total-regions: %u\n", memarea_elem_list_num(priv));
+	fprintf(f, "  total-free-regions: %u\n", memarea_free_list_num(priv));
+	fprintf(f, "  alloc_fails: %" PRIu64 "\n", priv->alloc_fails);
+	fprintf(f, "  refcnt_check_fails: %" PRIu64 "\n", priv->refcnt_check_fails);
+	if (dump_all)
+		memarea_dump_all(priv, f);
+	memarea_unlock(priv);
+
+	return 0;
+}
diff --git a/lib/memarea/rte_memarea.h b/lib/memarea/rte_memarea.h
index cded2904e3..d1383f18c3 100644
--- a/lib/memarea/rte_memarea.h
+++ b/lib/memarea/rte_memarea.h
@@ -180,6 +180,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 region 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/version.map
@@ -4,6 +4,7 @@ EXPERIMENTAL {
 	rte_memarea_alloc;
 	rte_memarea_create;
 	rte_memarea_destroy;
+	rte_memarea_dump;
 	rte_memarea_free;
 	rte_memarea_update_refcnt;
 
-- 
2.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH 6/8] test/memarea: support dump test
  2022-09-20  3:46 ` [PATCH 0/8] introduce memarea library Chengwen Feng
                     ` (4 preceding siblings ...)
  2022-09-20  3:46   ` [PATCH 5/8] memarea: support dump API Chengwen Feng
@ 2022-09-20  3:46   ` Chengwen Feng
  2022-09-20  3:46   ` [PATCH 7/8] memarea: support backup memory mechanism Chengwen Feng
  2022-09-20  3:46   ` [PATCH 8/8] test/memarea: support backup memory test Chengwen Feng
  7 siblings, 0 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-09-20  3:46 UTC (permalink / raw)
  To: thomas; +Cc: dev, stephen, jerinjacobk, dmitry.kozliuk

This patch supports rte_memarea_dump() test.

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 app/test/test_memarea.c | 33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/app/test/test_memarea.c b/app/test/test_memarea.c
index 66616be0b6..a1214f7080 100644
--- a/app/test/test_memarea.c
+++ b/app/test/test_memarea.c
@@ -250,6 +250,38 @@ test_memarea_alloc_free(void)
 	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);
+
+	return 0;
+}
+
 static int
 test_memarea(void)
 {
@@ -258,6 +290,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.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH 7/8] memarea: support backup memory mechanism
  2022-09-20  3:46 ` [PATCH 0/8] introduce memarea library Chengwen Feng
                     ` (5 preceding siblings ...)
  2022-09-20  3:46   ` [PATCH 6/8] test/memarea: support dump test Chengwen Feng
@ 2022-09-20  3:46   ` Chengwen Feng
  2022-09-20  3:46   ` [PATCH 8/8] test/memarea: support backup memory test Chengwen Feng
  7 siblings, 0 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-09-20  3:46 UTC (permalink / raw)
  To: thomas; +Cc: dev, stephen, jerinjacobk, dmitry.kozliuk

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

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 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             |  6 ++++++
 4 files changed, 33 insertions(+)

diff --git a/doc/guides/prog_guide/memarea_lib.rst b/doc/guides/prog_guide/memarea_lib.rst
index 7686625c90..c52ab95aeb 100644
--- a/doc/guides/prog_guide/memarea_lib.rst
+++ b/doc/guides/prog_guide/memarea_lib.rst
@@ -26,6 +26,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 memory object could use another
+  memarea object as a backup.
+
 Library API Overview
 --------------------
 
diff --git a/lib/memarea/memarea_private.h b/lib/memarea/memarea_private.h
index f71e01e7b5..ce765ed801 100644
--- a/lib/memarea/memarea_private.h
+++ b/lib/memarea/memarea_private.h
@@ -23,11 +23,13 @@ struct memarea_private {
 	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 e40715d16a..3efe8d4819 100644
--- a/lib/memarea/rte_memarea.c
+++ b/lib/memarea/rte_memarea.c
@@ -116,6 +116,7 @@ rte_memarea_create(const struct rte_memarea_param *init)
 	TAILQ_INIT(&priv->elem_list);
 	TAILQ_INIT(&priv->free_list);
 	priv->area_addr = addr;
+	priv->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;
@@ -183,6 +184,15 @@ memarea_add_node(struct memarea_private *priv, struct memarea_elem *elem, size_t
 	elem->size = align_size;
 }
 
+static inline void *
+memarea_alloc_backup(struct memarea_private *priv, size_t size, uint32_t cookie)
+{
+	void *ptr = rte_memarea_alloc(priv->init.bak_memarea, size, cookie);
+	if (unlikely(ptr == NULL))
+		priv->bak_alloc_fails++;
+	return ptr;
+}
+
 void *
 rte_memarea_alloc(struct rte_memarea *ma, size_t size, uint32_t cookie)
 {
@@ -206,6 +216,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 && priv->init.bak_memarea != NULL)
+		ptr = memarea_alloc_backup(priv, size, cookie);
 	if (unlikely(ptr == NULL))
 		priv->alloc_fails++;
 	memarea_unlock(priv);
@@ -264,6 +276,12 @@ rte_memarea_update_refcnt(struct rte_memarea *ma, void *ptr, int16_t value)
 	struct memarea_private *priv = ma->private_data;
 
 	memarea_lock(priv);
+	if (ptr < priv->area_addr || ptr > priv->top_addr) {
+		rte_memarea_update_refcnt(priv->init.bak_memarea, ptr, value);
+		memarea_unlock(priv);
+		return;
+	}
+
 	if (unlikely(elem->refcnt <= 0 || elem->refcnt + value < 0)) {
 		RTE_LOG(ERR, MEMAREA,
 			"memarea cookie: %u curr refcnt: %d update refcnt: %d check fail!\n",
@@ -274,6 +292,7 @@ rte_memarea_update_refcnt(struct rte_memarea *ma, void *ptr, int16_t value)
 		memarea_unlock(priv);
 		return;
 	}
+
 	elem->refcnt += value;
 	if (elem->refcnt == 0)
 		memarea_free_elem(priv, elem);
@@ -351,10 +370,13 @@ rte_memarea_dump(struct rte_memarea *ma, FILE *f, bool dump_all)
 		fprintf(f, "  source-user-memarea: %s\n", memarea_name(priv->init.user_memarea));
 	fprintf(f, "  total-size: 0x%lx\n", priv->init.total_sz);
 	fprintf(f, "  mt-safe: %s\n", priv->init.mt_safe ? "yes" : "no");
+	if (priv->init.bak_memarea)
+		fprintf(f, "  backup-memarea-name: %s\n", memarea_name(priv->init.bak_memarea));
 	fprintf(f, "  total-regions: %u\n", memarea_elem_list_num(priv));
 	fprintf(f, "  total-free-regions: %u\n", memarea_free_list_num(priv));
 	fprintf(f, "  alloc_fails: %" PRIu64 "\n", priv->alloc_fails);
 	fprintf(f, "  refcnt_check_fails: %" PRIu64 "\n", priv->refcnt_check_fails);
+	fprintf(f, "  backup_alloc_fails: %" PRIu64 "\n", priv->bak_alloc_fails);
 	if (dump_all)
 		memarea_dump_all(priv, f);
 	memarea_unlock(priv);
diff --git a/lib/memarea/rte_memarea.h b/lib/memarea/rte_memarea.h
index d1383f18c3..a467627523 100644
--- a/lib/memarea/rte_memarea.h
+++ b/lib/memarea/rte_memarea.h
@@ -41,6 +41,8 @@
  *      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 object.
+ *   f) It provides backup memory mechanism, the memarea object could use
+ *      another memarea object as a backup.
  */
 
 #include <stdbool.h>
@@ -91,6 +93,10 @@ struct rte_memarea_param {
 		 */
 		struct rte_memarea *user_memarea;
 	};
+	/** Backup memarea, which is used to handle the scenario where the
+	 * current memarea object allocation failure.
+	 */
+	struct rte_memarea *bak_memarea;
 };
 
 /**
-- 
2.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH 8/8] test/memarea: support backup memory test
  2022-09-20  3:46 ` [PATCH 0/8] introduce memarea library Chengwen Feng
                     ` (6 preceding siblings ...)
  2022-09-20  3:46   ` [PATCH 7/8] memarea: support backup memory mechanism Chengwen Feng
@ 2022-09-20  3:46   ` Chengwen Feng
  7 siblings, 0 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-09-20  3:46 UTC (permalink / raw)
  To: thomas; +Cc: dev, stephen, jerinjacobk, dmitry.kozliuk

This patch supports backup memory mechanism test.

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 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 a1214f7080..1f7ab3fb1f 100644
--- a/app/test/test_memarea.c
+++ b/app/test/test_memarea.c
@@ -282,6 +282,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)
 {
@@ -291,6 +331,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.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* Re: [PATCH 1/8] memarea: introduce memory area library
  2022-09-20  3:46   ` [PATCH 1/8] memarea: introduce memory area library Chengwen Feng
@ 2022-09-20 11:30     ` Dmitry Kozlyuk
  2022-09-20 11:31       ` Dmitry Kozlyuk
  2022-09-20 12:06       ` fengchengwen
  0 siblings, 2 replies; 222+ messages in thread
From: Dmitry Kozlyuk @ 2022-09-20 11:30 UTC (permalink / raw)
  To: Chengwen Feng; +Cc: thomas, dev, stephen, jerinjacobk

2022-09-20 03:46 (UTC+0000), Chengwen Feng:
> The memarea library is an allocator of variable-size object. It is a
> collection of allocated objects that can be efficiently alloc or free
> all at once, the main features are as follows:
> a) it facilitate alloc and free of memory with low overhead.

Yet, the overhead is 64B per element, just like rte_malloc.

> b) it provides refcnt feature which could be useful in some scenes.

Are you sure refcnt should be in this library?
I've expressed my concerns here:

https://inbox.dpdk.org/dev/CAEYuUWBpC-9dCqKJ0LZi6RkCUwyeYEghLRBMBUBtUx4Ljg+pAQ@mail.gmail.com

There are more unanswered questions in that mail,
it would be good to clarify them before reviewing these patches
in order to understand all the intentions.

> +static int
> +memarea_check_param(const struct rte_memarea_param *init)
> +{
> +	size_t len;
> +
> +	len = strnlen(init->name, RTE_MEMAREA_NAMESIZE);
> +	if (len == 0 || len >= RTE_MEMAREA_NAMESIZE) {
> +		RTE_LOG(ERR, MEMAREA, "memarea name invalid!\n");
> +		return -EINVAL;
> +	}

Please check init->name == NULL first.

> +struct rte_memarea *
> +rte_memarea_create(const struct rte_memarea_param *init)
> +{
[...]
> +		RTE_LOG(ERR, MEMAREA, "malloc memarea management obj fail!\n");

In all error messages, it would be useful to provide details:
the name of the area, what size was requested, etc.

> +/**
> + * Memarea memory source.
> + */
> +enum rte_memarea_source {
> +	/** Memory source comes from system API (e.g. malloc). */
> +	RTE_MEMAREA_SOURCE_SYSTEM_API,
> +	/** Memory source comes from user-provided address. */
> +	RTE_MEMAREA_SOURCE_USER_ADDR,
> +	/** Memory source comes from user-provided memarea. */
> +	RTE_MEMAREA_SOURCE_USER_MEMAREA,
> +
> +	RTE_MEMAREA_SOURCE_BUTT

DPDK enumerations must not include an item to hold the element count,
because it is harmful for ABI (e.g. developers create arrays of this size
and when a new item is added in a new DPDK version, the array overflows).

If it's supposed to mean "the end of item list",
the proper word would be "last" or "max" BTW :)

> +};
> +
> +struct rte_memarea {
> +	void *private_data; /**< private management data pointer. */
> +};

Jerin and Stephen suggested to make the structure opaque,
i.e. only declare the struct and define it privately.
It would reduce ABI and simplify allocation.
Any justification to expose it?

^ permalink raw reply	[flat|nested] 222+ messages in thread

* Re: [PATCH 1/8] memarea: introduce memory area library
  2022-09-20 11:30     ` Dmitry Kozlyuk
@ 2022-09-20 11:31       ` Dmitry Kozlyuk
  2022-09-20 12:06       ` fengchengwen
  1 sibling, 0 replies; 222+ messages in thread
From: Dmitry Kozlyuk @ 2022-09-20 11:31 UTC (permalink / raw)
  To: Chengwen Feng; +Cc: thomas, dev, stephen, jerinjacobk

2022-09-20 14:30 (UTC+0300), Dmitry Kozlyuk:
> 2022-09-20 03:46 (UTC+0000), Chengwen Feng:
> > The memarea library is an allocator of variable-size object. It is a
> > collection of allocated objects that can be efficiently alloc or free
> > all at once, the main features are as follows:
> > a) it facilitate alloc and free of memory with low overhead.  
> 
> Yet, the overhead is 64B per element, just like rte_malloc.

Disregard this one, rte_malloc overhead is 128B (2 cache lines).

^ permalink raw reply	[flat|nested] 222+ messages in thread

* Re: [PATCH 1/8] memarea: introduce memory area library
  2022-09-20 11:30     ` Dmitry Kozlyuk
  2022-09-20 11:31       ` Dmitry Kozlyuk
@ 2022-09-20 12:06       ` fengchengwen
  1 sibling, 0 replies; 222+ messages in thread
From: fengchengwen @ 2022-09-20 12:06 UTC (permalink / raw)
  To: Dmitry Kozlyuk; +Cc: thomas, dev, stephen, jerinjacobk

Hi Dmitry,

On 2022/9/20 19:30, Dmitry Kozlyuk wrote:
> 2022-09-20 03:46 (UTC+0000), Chengwen Feng:
>> The memarea library is an allocator of variable-size object. It is a
>> collection of allocated objects that can be efficiently alloc or free
>> all at once, the main features are as follows:
>> a) it facilitate alloc and free of memory with low overhead.
> Yet, the overhead is 64B per element, just like rte_malloc.
>
>> b) it provides refcnt feature which could be useful in some scenes.
> Are you sure refcnt should be in this library?
> I've expressed my concerns here:
>
> https://inbox.dpdk.org/dev/CAEYuUWBpC-9dCqKJ0LZi6RkCUwyeYEghLRBMBUBtUx4Ljg+pAQ@mail.gmail.com
>
> There are more unanswered questions in that mail,
> it would be good to clarify them before reviewing these patches
> in order to understand all the intentions.

Sorry to forgot reply it.

We have the following scene which used refcnt:

     nic-rx  ->  decoder ->  process

                                    |

                                   ->  recording

as above show, the process and recording module both use the decoder's 
output, the are just reader.

so in this case, the refcnt is useful.

>
>> +static int
>> +memarea_check_param(const struct rte_memarea_param *init)
>> +{
>> +	size_t len;
>> +
>> +	len = strnlen(init->name, RTE_MEMAREA_NAMESIZE);
>> +	if (len == 0 || len >= RTE_MEMAREA_NAMESIZE) {
>> +		RTE_LOG(ERR, MEMAREA, "memarea name invalid!\n");
>> +		return -EINVAL;
>> +	}
> Please check init->name == NULL first.

No need checking because name is an array.

Maybe I should check init == NULL here.

>
>> +struct rte_memarea *
>> +rte_memarea_create(const struct rte_memarea_param *init)
>> +{
> [...]
>> +		RTE_LOG(ERR, MEMAREA, "malloc memarea management obj fail!\n");
> In all error messages, it would be useful to provide details:
> the name of the area, what size was requested, etc.

will fix in v2.

>
>> +/**
>> + * Memarea memory source.
>> + */
>> +enum rte_memarea_source {
>> +	/** Memory source comes from system API (e.g. malloc). */
>> +	RTE_MEMAREA_SOURCE_SYSTEM_API,
>> +	/** Memory source comes from user-provided address. */
>> +	RTE_MEMAREA_SOURCE_USER_ADDR,
>> +	/** Memory source comes from user-provided memarea. */
>> +	RTE_MEMAREA_SOURCE_USER_MEMAREA,
>> +
>> +	RTE_MEMAREA_SOURCE_BUTT
> DPDK enumerations must not include an item to hold the element count,
> because it is harmful for ABI (e.g. developers create arrays of this size
> and when a new item is added in a new DPDK version, the array overflows).
>
> If it's supposed to mean "the end of item list",
> the proper word would be "last" or "max" BTW :)
will fix in v2
>
>> +};
>> +
>> +struct rte_memarea {
>> +	void *private_data; /**< private management data pointer. */
>> +};
> Jerin and Stephen suggested to make the structure opaque,
> i.e. only declare the struct and define it privately.
> It would reduce ABI and simplify allocation.
> Any justification to expose it?

do you mean the rte_memarea just void * ? it just (void 
*)(memarea_private *)priv ?

It's another popular type to impl ABI compatiable.

It's more simpler, will fix in v2


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v2 0/9] introduce memarea library
  2022-07-21  4:46 [RFC] memarea: introduce memory area library Chengwen Feng
                   ` (3 preceding siblings ...)
  2022-09-20  3:46 ` [PATCH 0/8] introduce memarea library Chengwen Feng
@ 2022-09-21  3:12 ` Chengwen Feng
  2022-09-21  3:12   ` [PATCH v2 1/9] memarea: introduce memory area library Chengwen Feng
                     ` (8 more replies)
  2022-09-24  7:49 ` [PATCH v3 00/10] introduce memarea library Chengwen Feng
                   ` (18 subsequent siblings)
  23 siblings, 9 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-09-21  3:12 UTC (permalink / raw)
  To: thomas; +Cc: dev, stephen, jerinjacobk, dmitry.kozliuk

The memarea library is an allocator of variable-size object. It is a
collection of allocated objects that can be efficiently alloc or free
all at once, the main feature are as follows:
a) it facilitate alloc and free of memory with low overhead.

b) it provides refcnt feature which could be useful in some scenes.

c) it supports MT-safe as long as it's specified at creation time.

d) it's memory source could comes from:
d.1) system API: malloc in C library.
d.2) user provided address: it can be from the rte_malloc API series
or extended memory as long as it is available.
d.3) user provided memarea: it can be from another memarea.

e) it provides backup memory mechanism, the memarea object could use
another memarea object 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 <fengchengwen@huawei.com>

Chengwen Feng (9):
  memarea: introduce memory area 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
  test/memarea: support no MT-safe test

---
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                | 379 +++++++++++++++++++++++++
 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  |  57 ++++
 doc/guides/rel_notes/release_22_11.rst |   6 +
 lib/eal/include/rte_log.h              |   1 +
 lib/memarea/memarea_private.h          |  35 +++
 lib/memarea/meson.build                |  16 ++
 lib/memarea/rte_memarea.c              | 379 +++++++++++++++++++++++++
 lib/memarea/rte_memarea.h              | 210 ++++++++++++++
 lib/memarea/version.map                |  16 ++
 lib/meson.build                        |   1 +
 15 files changed, 1112 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.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v2 1/9] memarea: introduce memory area library
  2022-09-21  3:12 ` [PATCH v2 0/9] introduce memarea library Chengwen Feng
@ 2022-09-21  3:12   ` Chengwen Feng
  2022-09-21  3:12   ` [PATCH v2 2/9] test/memarea: support memarea test Chengwen Feng
                     ` (7 subsequent siblings)
  8 siblings, 0 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-09-21  3:12 UTC (permalink / raw)
  To: thomas; +Cc: dev, stephen, jerinjacobk, dmitry.kozliuk

The memarea library is an allocator of variable-size object. It is a
collection of allocated objects that can be efficiently alloc or free
all at once, the main features are as follows:
a) it facilitate alloc and free of memory with low overhead.

b) it provides refcnt feature which could be useful in some scenes.

c) it supports MT-safe as long as it's specified at creation time.

d) it's memory source could comes from:
d.1) system API: malloc in C library.
d.2) user provided address: it can be from the rte_malloc API series
or extended memory as long as it is available.
d.3) user provided memarea: it can be from another memarea.

This patch provides create/destroy API.

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 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  |  41 +++++++
 doc/guides/rel_notes/release_22_11.rst |   6 ++
 lib/eal/include/rte_log.h              |   1 +
 lib/memarea/memarea_private.h          |  30 ++++++
 lib/memarea/meson.build                |  16 +++
 lib/memarea/rte_memarea.c              | 144 +++++++++++++++++++++++++
 lib/memarea/rte_memarea.h              | 127 ++++++++++++++++++++++
 lib/memarea/version.map                |  12 +++
 lib/meson.build                        |   1 +
 13 files changed, 387 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 26d3a7077c..4d5bf986c6 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1558,6 +1558,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 <fengchengwen@huawei.com>
+F: lib/memarea
+F: doc/guides/prog_guide/memarea_lib.rst
+
 Membership - EXPERIMENTAL
 M: Yipeng Wang <yipeng1.wang@intel.com>
 M: Sameh Gobriel <sameh.gobriel@intel.com>
diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md
index 186a258be4..25dbef0b68 100644
--- a/doc/api/doxy-api-index.md
+++ b/doc/api/doxy-api-index.md
@@ -64,7 +64,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 608494a7c0..bdc5d2b0d5 100644
--- a/doc/api/doxy-api.conf.in
+++ b/doc/api/doxy-api.conf.in
@@ -55,6 +55,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..1979f0a12c
--- /dev/null
+++ b/doc/guides/prog_guide/memarea_lib.rst
@@ -0,0 +1,41 @@
+..  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:
+
+* It facilitate alloc and free of memory with low overhead.
+
+* It's memory source could comes from: 1) System API: e.g. malloc/memalign in
+  C library. 2) User provided address: it can be from the rte_malloc API series
+  or extended memory as long as it is available. 3) User provided memarea: it
+  can be from another memarea.
+
+* The default aligement size is ``RTE_CACHE_LINE_SIZE``.
+
+* It provides refcnt feature which could be useful in some scenes.
+
+* 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 object, 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 object.
+
+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 8c021cf050..1cf522132c 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 library is an allocator of variable-size objects, it is oriented
+  towards the application layer, which could provides 'region-based memory
+  management' function.
+
 
 Removed Items
 -------------
diff --git a/lib/eal/include/rte_log.h b/lib/eal/include/rte_log.h
index 25ce42cdfc..708f3a39dd 100644
--- a/lib/eal/include/rte_log.h
+++ b/lib/eal/include/rte_log.h
@@ -48,6 +48,7 @@ extern "C" {
 #define RTE_LOGTYPE_EFD       18 /**< Log related to EFD. */
 #define RTE_LOGTYPE_EVENTDEV  19 /**< Log related to eventdev. */
 #define RTE_LOGTYPE_GSO       20 /**< Log related to GSO. */
+#define RTE_LOGTYPE_MEMAREA   21 /**< Log related to memarea. */
 
 /* these log types can be used in an application */
 #define RTE_LOGTYPE_USER1     24 /**< User-defined log type 1. */
diff --git a/lib/memarea/memarea_private.h b/lib/memarea/memarea_private.h
new file mode 100644
index 0000000000..c76392d3e6
--- /dev/null
+++ b/lib/memarea/memarea_private.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2022 HiSilicon Limited
+ */
+
+#ifndef MEMAREA_PRIVATE_H
+#define MEMAREA_PRIVATE_H
+
+#include <rte_memarea.h>
+
+#define MEMAREA_FREE_ELEM_COOKIE	0xFFFFFFFF
+
+struct memarea_elem {
+	size_t   size;
+	uint32_t cookie;
+	int32_t  refcnt; /* Non-zero indicates that it has been allocated */
+	TAILQ_ENTRY(memarea_elem) elem_node;
+	TAILQ_ENTRY(memarea_elem) free_node;
+} __rte_cache_aligned;
+
+TAILQ_HEAD(memarea_elem_list, memarea_elem);
+
+struct rte_memarea {
+	struct rte_memarea_param init;
+	rte_spinlock_t           lock;
+	void                    *area_addr;
+	struct memarea_elem_list elem_list;
+	struct memarea_elem_list free_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..0a74fb4cd1
--- /dev/null
+++ b/lib/memarea/meson.build
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2022 HiSilicon Limited
+
+if is_windows
+    build = false
+    reason = 'not supported on Windows'
+    subdir_done()
+endif
+
+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..6e918dfaf9
--- /dev/null
+++ b/lib/memarea/rte_memarea.c
@@ -0,0 +1,144 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2022 HiSilicon Limited
+ */
+
+#include <stdio.h>
+
+#include <rte_common.h>
+#include <rte_log.h>
+#include <rte_malloc.h>
+#include <rte_spinlock.h>
+
+#include "rte_memarea.h"
+#include "memarea_private.h"
+
+static int
+memarea_check_param(const struct rte_memarea_param *init)
+{
+	size_t len;
+
+	if (init == NULL) {
+		RTE_LOG(ERR, MEMAREA, "memarea init param is NULL!\n");
+		return -EINVAL;
+	}
+
+	len = strnlen(init->name, RTE_MEMAREA_NAMESIZE);
+	if (len == 0 || len >= RTE_MEMAREA_NAMESIZE) {
+		RTE_LOG(ERR, MEMAREA, "memarea name size %zu invalid!\n", len);
+		return -EINVAL;
+	}
+
+	if (init->source != RTE_MEMAREA_SOURCE_SYSTEM_API &&
+	    init->source != RTE_MEMAREA_SOURCE_USER_ADDR &&
+	    init->source != RTE_MEMAREA_SOURCE_USER_MEMAREA) {
+		RTE_LOG(ERR, MEMAREA, "memarea: %s source: %d not supported!\n",
+			init->name, init->source);
+		return -EINVAL;
+	}
+
+	if (init->total_sz <= sizeof(struct memarea_elem)) {
+		RTE_LOG(ERR, MEMAREA, "memarea: %s total-size: %zu too small!\n",
+			init->name, init->total_sz);
+		return -EINVAL;
+	}
+
+	if (init->source == RTE_MEMAREA_SOURCE_USER_ADDR && init->user_addr == NULL) {
+		RTE_LOG(ERR, MEMAREA, "memarea: %s user provided addr is NULL!\n", init->name);
+		return -EINVAL;
+	}
+
+	if (init->source == RTE_MEMAREA_SOURCE_USER_ADDR &&
+	    ((uintptr_t)init->user_addr & (RTE_CACHE_LINE_SIZE - 1))) {
+		RTE_LOG(ERR, MEMAREA, "memarea: %s user provided addr should align: %d!\n",
+			init->name, RTE_CACHE_LINE_SIZE);
+		return -EINVAL;
+	}
+
+	if (init->source == RTE_MEMAREA_SOURCE_USER_MEMAREA && init->user_memarea == NULL) {
+		RTE_LOG(ERR, MEMAREA, "memarea: %s user provided memarea is NULL!\n", init->name);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void *
+memarea_alloc_from_system_api(size_t size)
+{
+	void *ptr = NULL;
+	int ret;
+
+	ret = posix_memalign(&ptr, RTE_CACHE_LINE_SIZE, size);
+	if (ret)
+		return NULL;
+	return ptr;
+}
+
+static void *
+memarea_alloc_area(const struct rte_memarea_param *init)
+{
+	void *ptr = NULL;
+
+	if (init->source == RTE_MEMAREA_SOURCE_SYSTEM_API)
+		ptr = memarea_alloc_from_system_api(init->total_sz);
+	else if (init->source == RTE_MEMAREA_SOURCE_USER_ADDR)
+		ptr = init->user_addr;
+
+	if (ptr == NULL)
+		RTE_LOG(ERR, MEMAREA, "memarea: %s alloc memory area fail!\n", init->name);
+
+	return ptr;
+}
+
+struct rte_memarea *
+rte_memarea_create(const struct rte_memarea_param *init)
+{
+	struct memarea_elem *elem;
+	struct rte_memarea *ma;
+	void *addr;
+	int ret;
+
+	ret = memarea_check_param(init);
+	if (ret)
+		return NULL;
+
+	addr = memarea_alloc_area(init);
+	if (addr == NULL)
+		return NULL;
+
+	ma = rte_zmalloc(NULL, sizeof(struct rte_memarea), RTE_CACHE_LINE_SIZE);
+	if (ma == NULL) {
+		RTE_LOG(ERR, MEMAREA, "malloc memarea: %s management obj fail!\n", init->name);
+		return NULL;
+	}
+
+	ma->init = *init;
+	rte_spinlock_init(&ma->lock);
+	TAILQ_INIT(&ma->elem_list);
+	TAILQ_INIT(&ma->free_list);
+	ma->area_addr = addr;
+	elem = addr;
+	elem->size = init->total_sz - sizeof(struct memarea_elem);
+	elem->cookie = MEMAREA_FREE_ELEM_COOKIE;
+	elem->refcnt = 0;
+	TAILQ_INSERT_TAIL(&ma->elem_list, elem, elem_node);
+	TAILQ_INSERT_TAIL(&ma->free_list, elem, free_node);
+
+	return ma;
+}
+
+static void
+memarea_free_area(struct rte_memarea *ma)
+{
+	if (ma->init.source == RTE_MEMAREA_SOURCE_SYSTEM_API)
+		free(ma->area_addr);
+}
+
+void
+rte_memarea_destroy(struct rte_memarea *ma)
+{
+	if (ma == NULL)
+		return;
+	memarea_free_area(ma);
+	rte_free(ma);
+}
diff --git a/lib/memarea/rte_memarea.h b/lib/memarea/rte_memarea.h
new file mode 100644
index 0000000000..15f6fabcb5
--- /dev/null
+++ b/lib/memarea/rte_memarea.h
@@ -0,0 +1,127 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2022 HiSilicon Limited
+ */
+
+#ifndef RTE_MEMAREA_H
+#define RTE_MEMAREA_H
+
+/**
+ * @file
+ * RTE Memarea.
+ *
+ * A memory area is an allocator of variable-size object. It is identified
+ * by its name.
+ *
+ * The memarea is a collection of allocated objects that can be efficiently
+ * alloc or free all at once, the main feature are as follows:
+ *   a) It facilitate alloc and free of memory with low overhead.
+ *   b) It's memory source could comes from:
+ *      1) System API: malloc/memalign in C library.
+ *      2) User provided address: it can be from the rte_malloc API series
+ *         or extended memory as long as it is available. The address must be
+ *         aligned to RTE_CACHE_LINE_SIZE.
+ *      3) User provided memarea: it can be from another memarea. So we can
+ *         build the following memory management structure:
+ *         \code{.unparsed}
+ *                           -------------
+ *                           | memarea-1 |
+ *                           -------------
+ *                                 |
+ *                                 v
+ *                  ------------------------------
+ *                  |               |            |
+ *                  v               v            v
+ *            -------------   -------------   -------
+ *            | memarea-2 |   | memarea-3 |   | obj |
+ *            -------------   -------------   -------
+ *         \endcode
+ *   c) The default alignment size is RTE_CACHE_LINE_SIZE.
+ *   d) It provides refcnt feature which could be useful in some scenes.
+ *   e) 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 object.
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include <rte_compat.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define RTE_MEMAREA_NAMESIZE	64
+
+/**
+ * Memarea memory source.
+ */
+enum rte_memarea_source {
+	/** Memory source comes from system API (e.g. malloc). */
+	RTE_MEMAREA_SOURCE_SYSTEM_API,
+	/** Memory source comes from user-provided address. */
+	RTE_MEMAREA_SOURCE_USER_ADDR,
+	/** Memory source comes from user-provided memarea. */
+	RTE_MEMAREA_SOURCE_USER_MEMAREA,
+};
+
+struct rte_memarea;
+
+struct rte_memarea_param {
+	char name[RTE_MEMAREA_NAMESIZE]; /**< Name of memarea. */
+	enum rte_memarea_source source;  /**< Memory source of memarea. */
+	size_t total_sz;                 /**< total size (bytes) of memarea. */
+	/** Indicates whether the memarea API should be MT-safe. */
+	uint32_t mt_safe : 1;
+	union {
+		/** User provided address, this field is valid only when the
+		 * source is set to be RTE_MEMAREA_SOURCE_USER_ADDR.
+		 * Note: the provided address must align at least
+		 * RTE_CACHE_LINE_SIZE.
+		 */
+		void *user_addr;
+		/** User provided memarea, this field is valid only when the
+		 * source is set to be RTE_MEMAREA_SOURCE_USER_MEMAREA.
+		 */
+		struct rte_memarea *user_memarea;
+	};
+};
+
+/**
+ * @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 c648f7d800..521a25d6c0 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -42,6 +42,7 @@ libraries = [
         'kni',
         'latencystats',
         'lpm',
+        'memarea',
         'member',
         'pcapng',
         'power',
-- 
2.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v2 2/9] test/memarea: support memarea test
  2022-09-21  3:12 ` [PATCH v2 0/9] introduce memarea library Chengwen Feng
  2022-09-21  3:12   ` [PATCH v2 1/9] memarea: introduce memory area library Chengwen Feng
@ 2022-09-21  3:12   ` Chengwen Feng
  2022-09-21  3:12   ` [PATCH v2 3/9] memarea: support alloc/free/update-refcnt API Chengwen Feng
                     ` (6 subsequent siblings)
  8 siblings, 0 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-09-21  3:12 UTC (permalink / raw)
  To: thomas; +Cc: dev, stephen, jerinjacobk, dmitry.kozliuk

This patch support memarea test about API rte_memarea_create and
rte_memarea_destroy.

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 MAINTAINERS             |   1 +
 app/test/meson.build    |   2 +
 app/test/test_memarea.c | 134 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 137 insertions(+)
 create mode 100644 app/test/test_memarea.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 4d5bf986c6..eb2de32884 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1562,6 +1562,7 @@ Memarea - EXPERIMENTAL
 M: Chengwen Feng <fengchengwen@huawei.com>
 F: lib/memarea
 F: doc/guides/prog_guide/memarea_lib.rst
+F: app/test/test_memarea*
 
 Membership - EXPERIMENTAL
 M: Yipeng Wang <yipeng1.wang@intel.com>
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 0000000000..b2dbc71a50
--- /dev/null
+++ b/app/test/test_memarea.c
@@ -0,0 +1,134 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2022 HiSilicon Limited
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#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 <rte_memarea.h>
+
+#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");
+
+	return 0;
+}
+
+static int
+test_memarea_create_destroy(void)
+{
+	struct rte_memarea_param init;
+	uint8_t user_buffer[MEMAREA_TEST_DEFAULT_SIZE + RTE_CACHE_LINE_SIZE];
+	struct rte_memarea *ma;
+
+	/* test for create with system API */
+	test_memarea_init_def_param(&init);
+	init.source = RTE_MEMAREA_SOURCE_SYSTEM_API;
+	ma = rte_memarea_create(&init);
+	RTE_TEST_ASSERT(ma != NULL, "Expected Non-NULL");
+	rte_memarea_destroy(ma);
+
+	/* test for create with user-address */
+	test_memarea_init_def_param(&init);
+	init.source = RTE_MEMAREA_SOURCE_USER_ADDR;
+	init.user_addr = (void *)(((uintptr_t)user_buffer + RTE_CACHE_LINE_SIZE) &
+				  ~(RTE_CACHE_LINE_SIZE - 1));
+	ma = rte_memarea_create(&init);
+	RTE_TEST_ASSERT(ma != NULL, "Expected Non-NULL");
+	rte_memarea_destroy(ma);
+
+	return 0;
+}
+
+static int
+test_memarea(void)
+{
+	MEMAREA_TEST_API_RUN(test_memarea_create_bad_param);
+	MEMAREA_TEST_API_RUN(test_memarea_create_destroy);
+	return 0;
+}
+
+#endif /* !RTE_EXEC_ENV_WINDOWS */
+
+REGISTER_TEST_COMMAND(memarea_autotest, test_memarea);
-- 
2.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v2 3/9] memarea: support alloc/free/update-refcnt API
  2022-09-21  3:12 ` [PATCH v2 0/9] introduce memarea library Chengwen Feng
  2022-09-21  3:12   ` [PATCH v2 1/9] memarea: introduce memory area library Chengwen Feng
  2022-09-21  3:12   ` [PATCH v2 2/9] test/memarea: support memarea test Chengwen Feng
@ 2022-09-21  3:12   ` Chengwen Feng
  2022-09-21  3:12   ` [PATCH v2 4/9] test/memarea: support alloc/free/update-refcnt test Chengwen Feng
                     ` (5 subsequent siblings)
  8 siblings, 0 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-09-21  3:12 UTC (permalink / raw)
  To: thomas; +Cc: dev, stephen, jerinjacobk, dmitry.kozliuk

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

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 doc/guides/prog_guide/memarea_lib.rst |  10 ++
 lib/memarea/memarea_private.h         |   3 +
 lib/memarea/rte_memarea.c             | 141 ++++++++++++++++++++++++++
 lib/memarea/rte_memarea.h             |  56 ++++++++++
 lib/memarea/version.map               |   3 +
 5 files changed, 213 insertions(+)

diff --git a/doc/guides/prog_guide/memarea_lib.rst b/doc/guides/prog_guide/memarea_lib.rst
index 1979f0a12c..967129d560 100644
--- a/doc/guides/prog_guide/memarea_lib.rst
+++ b/doc/guides/prog_guide/memarea_lib.rst
@@ -35,6 +35,16 @@ failed.
 
 The ``rte_memarea_destroy()`` function is used to destroy a memarea object.
 
+The ``rte_memarea_alloc()`` function is used to alloc one memory region from
+the memarea object.
+
+The ``rte_memarea_free()`` function is used to free one memory region which
+allocated by ``rte_memarea_alloc()``.
+
+The ``rte_memarea_update_refcnt()`` function is used to update the memory
+region's reference count, if the count reaches zero, the memory region will
+be freed to memarea object.
+
 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 6e918dfaf9..7c85dbf491 100644
--- a/lib/memarea/rte_memarea.c
+++ b/lib/memarea/rte_memarea.c
@@ -3,6 +3,7 @@
  */
 
 #include <stdio.h>
+#include <sys/queue.h>
 
 #include <rte_common.h>
 #include <rte_log.h>
@@ -83,6 +84,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);
@@ -132,6 +135,8 @@ memarea_free_area(struct rte_memarea *ma)
 {
 	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
@@ -142,3 +147,139 @@ 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 = (void *)((uintptr_t)elem + sizeof(struct memarea_elem));
+		break;
+	}
+	if (unlikely(ptr == NULL))
+		ma->alloc_fails++;
+	memarea_unlock(ma);
+
+	return ptr;
+}
+
+void
+rte_memarea_free(struct rte_memarea *ma, void *ptr)
+{
+	rte_memarea_update_refcnt(ma, ptr, -1);
+}
+
+static inline void
+memarea_merge_node(struct rte_memarea *ma, struct memarea_elem *curr,
+		   struct memarea_elem *next, bool del_next_from_free,
+		   bool add_curr_to_free)
+{
+	curr->size += next->size + sizeof(struct memarea_elem);
+	next->size = 0;
+	next->cookie = 0;
+	TAILQ_REMOVE(&ma->elem_list, next, elem_node);
+	if (del_next_from_free)
+		TAILQ_REMOVE(&ma->free_list, next, free_node);
+	if (add_curr_to_free)
+		TAILQ_INSERT_TAIL(&ma->free_list, curr, free_node);
+}
+
+static inline void
+memarea_free_elem(struct rte_memarea *ma, struct memarea_elem *elem)
+{
+	struct memarea_elem *prev, *next;
+	bool merged = false;
+	prev = TAILQ_PREV(elem, memarea_elem_list, elem_node);
+	next = TAILQ_NEXT(elem, elem_node);
+	if (prev != NULL && prev->refcnt == 0) {
+		memarea_merge_node(ma, prev, elem, false, false);
+		elem = prev;
+		merged = true;
+	}
+	if (next != NULL && next->refcnt == 0) {
+		memarea_merge_node(ma, elem, next, true, !merged);
+		merged = true;
+	}
+	if (!merged) {
+		elem->cookie = MEMAREA_FREE_ELEM_COOKIE;
+		TAILQ_INSERT_TAIL(&ma->free_list, elem, free_node);
+	}
+}
+
+void
+rte_memarea_update_refcnt(struct rte_memarea *ma, void *ptr, int16_t value)
+{
+	struct memarea_elem *elem = (struct memarea_elem *)((uintptr_t)ptr -
+							    sizeof(struct memarea_elem));
+
+	if (unlikely(ma == NULL || ptr == NULL))
+		return;
+
+	memarea_lock(ma);
+	if (unlikely(elem->refcnt <= 0 || elem->refcnt + value < 0)) {
+		RTE_LOG(ERR, MEMAREA,
+			"memarea: %s cookie: %u curr refcnt: %d update refcnt: %d check fail!\n",
+			ma->init.name, elem->cookie, elem->refcnt, value);
+		ma->refcnt_check_fails++;
+		if (elem->refcnt > 0)
+			elem->refcnt += value;
+		memarea_unlock(ma);
+		return;
+	}
+
+	elem->refcnt += value;
+	if (elem->refcnt == 0)
+		memarea_free_elem(ma, elem);
+	memarea_unlock(ma);
+}
diff --git a/lib/memarea/rte_memarea.h b/lib/memarea/rte_memarea.h
index 15f6fabcb5..0ad195c4f9 100644
--- a/lib/memarea/rte_memarea.h
+++ b/lib/memarea/rte_memarea.h
@@ -120,6 +120,62 @@ 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 region from the memarea.
+ *
+ * @param ma
+ *   The pointer of memarea.
+ * @param size
+ *   The memory size to be allocated.
+ * @param cookie
+ *   User-provided footprint which could used to debug memory leak problem.
+ *
+ * @return
+ *   Non-NULL on success. Otherwise NULL is returned.
+ */
+__rte_experimental
+void *rte_memarea_alloc(struct rte_memarea *ma, size_t size, uint32_t cookie);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Free memory to memarea.
+ *
+ * Free one memory region to the memarea.
+ *
+ * @param ma
+ *   The pointer of memarea.
+ * @param ptr
+ *   The pointer of memory region which need be freed.
+ */
+__rte_experimental
+void rte_memarea_free(struct rte_memarea *ma, void *ptr);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Update memory's refcnt.
+ *
+ * Update one memory region's refcnt.
+ * When refcnt is updated to be zero, the memory region is freed.
+ *
+ * @param ma
+ *   The pointer of memarea.
+ * @param ptr
+ *   The pointer of memory region which need be updated refcnt.
+ * @param value
+ *   The value which need be updated.
+ */
+__rte_experimental
+void rte_memarea_update_refcnt(struct rte_memarea *ma, void *ptr, int16_t value);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/memarea/version.map b/lib/memarea/version.map
index f36a04d7cf..a0026fc5f9 100644
--- a/lib/memarea/version.map
+++ b/lib/memarea/version.map
@@ -1,8 +1,11 @@
 EXPERIMENTAL {
 	global:
 
+	rte_memarea_alloc;
 	rte_memarea_create;
 	rte_memarea_destroy;
+	rte_memarea_free;
+	rte_memarea_update_refcnt;
 
 	local: *;
 };
-- 
2.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v2 4/9] test/memarea: support alloc/free/update-refcnt test
  2022-09-21  3:12 ` [PATCH v2 0/9] introduce memarea library Chengwen Feng
                     ` (2 preceding siblings ...)
  2022-09-21  3:12   ` [PATCH v2 3/9] memarea: support alloc/free/update-refcnt API Chengwen Feng
@ 2022-09-21  3:12   ` Chengwen Feng
  2022-09-21  3:12   ` [PATCH v2 5/9] memarea: support dump API Chengwen Feng
                     ` (4 subsequent siblings)
  8 siblings, 0 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-09-21  3:12 UTC (permalink / raw)
  To: thomas; +Cc: dev, stephen, jerinjacobk, dmitry.kozliuk

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

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 app/test/test_memarea.c | 143 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 142 insertions(+), 1 deletion(-)

diff --git a/app/test/test_memarea.c b/app/test/test_memarea.c
index b2dbc71a50..866b86165f 100644
--- a/app/test/test_memarea.c
+++ b/app/test/test_memarea.c
@@ -40,6 +40,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)
 {
@@ -98,9 +104,9 @@ test_memarea_create_bad_param(void)
 static int
 test_memarea_create_destroy(void)
 {
+	struct rte_memarea *ma, *user_ma;
 	struct rte_memarea_param init;
 	uint8_t user_buffer[MEMAREA_TEST_DEFAULT_SIZE + RTE_CACHE_LINE_SIZE];
-	struct rte_memarea *ma;
 
 	/* test for create with system API */
 	test_memarea_init_def_param(&init);
@@ -118,6 +124,138 @@ 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 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)
+{
+#define ALLOC_MAX_NUM	8
+	struct rte_memarea_param init;
+	struct rte_memarea *ma;
+	void *ptr[ALLOC_MAX_NUM];
+	int i;
+
+	/* 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");
+	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, 0);
+
+	/* 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, ptr[6]);
+
+	rte_memarea_destroy(ma);
+
 	return 0;
 }
 
@@ -126,6 +264,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 0;
 }
 
-- 
2.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v2 5/9] memarea: support dump API
  2022-09-21  3:12 ` [PATCH v2 0/9] introduce memarea library Chengwen Feng
                     ` (3 preceding siblings ...)
  2022-09-21  3:12   ` [PATCH v2 4/9] test/memarea: support alloc/free/update-refcnt test Chengwen Feng
@ 2022-09-21  3:12   ` Chengwen Feng
  2022-09-21  3:12   ` [PATCH v2 6/9] test/memarea: support dump test Chengwen Feng
                     ` (3 subsequent siblings)
  8 siblings, 0 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-09-21  3:12 UTC (permalink / raw)
  To: thomas; +Cc: dev, stephen, jerinjacobk, dmitry.kozliuk

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

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 doc/guides/prog_guide/memarea_lib.rst |  3 ++
 lib/memarea/rte_memarea.c             | 73 +++++++++++++++++++++++++++
 lib/memarea/rte_memarea.h             | 21 ++++++++
 lib/memarea/version.map               |  1 +
 4 files changed, 98 insertions(+)

diff --git a/doc/guides/prog_guide/memarea_lib.rst b/doc/guides/prog_guide/memarea_lib.rst
index 967129d560..7686625c90 100644
--- a/doc/guides/prog_guide/memarea_lib.rst
+++ b/doc/guides/prog_guide/memarea_lib.rst
@@ -45,6 +45,9 @@ The ``rte_memarea_update_refcnt()`` function is used to update the memory
 region's reference count, if the count reaches zero, the memory region will
 be freed to memarea object.
 
+The ``rte_memarea_dump()`` function is used to dump the internal information
+of a memarea object.
+
 Reference
 ---------
 
diff --git a/lib/memarea/rte_memarea.c b/lib/memarea/rte_memarea.c
index 7c85dbf491..e4d43e5907 100644
--- a/lib/memarea/rte_memarea.c
+++ b/lib/memarea/rte_memarea.c
@@ -2,6 +2,7 @@
  * Copyright(c) 2022 HiSilicon Limited
  */
 
+#include <inttypes.h>
 #include <stdio.h>
 #include <sys/queue.h>
 
@@ -283,3 +284,75 @@ 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_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 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: %u 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, "  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 0ad195c4f9..2a92755b63 100644
--- a/lib/memarea/rte_memarea.h
+++ b/lib/memarea/rte_memarea.h
@@ -176,6 +176,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 region 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/version.map
@@ -4,6 +4,7 @@ EXPERIMENTAL {
 	rte_memarea_alloc;
 	rte_memarea_create;
 	rte_memarea_destroy;
+	rte_memarea_dump;
 	rte_memarea_free;
 	rte_memarea_update_refcnt;
 
-- 
2.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v2 6/9] test/memarea: support dump test
  2022-09-21  3:12 ` [PATCH v2 0/9] introduce memarea library Chengwen Feng
                     ` (4 preceding siblings ...)
  2022-09-21  3:12   ` [PATCH v2 5/9] memarea: support dump API Chengwen Feng
@ 2022-09-21  3:12   ` Chengwen Feng
  2022-09-21  3:12   ` [PATCH v2 7/9] memarea: support backup memory mechanism Chengwen Feng
                     ` (2 subsequent siblings)
  8 siblings, 0 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-09-21  3:12 UTC (permalink / raw)
  To: thomas; +Cc: dev, stephen, jerinjacobk, dmitry.kozliuk

This patch supports rte_memarea_dump() test.

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 app/test/test_memarea.c | 33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/app/test/test_memarea.c b/app/test/test_memarea.c
index 866b86165f..a07fb4424f 100644
--- a/app/test/test_memarea.c
+++ b/app/test/test_memarea.c
@@ -259,6 +259,38 @@ test_memarea_alloc_free(void)
 	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);
+
+	return 0;
+}
+
 static int
 test_memarea(void)
 {
@@ -267,6 +299,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.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v2 7/9] memarea: support backup memory mechanism
  2022-09-21  3:12 ` [PATCH v2 0/9] introduce memarea library Chengwen Feng
                     ` (5 preceding siblings ...)
  2022-09-21  3:12   ` [PATCH v2 6/9] test/memarea: support dump test Chengwen Feng
@ 2022-09-21  3:12   ` Chengwen Feng
  2022-09-21  3:12   ` [PATCH v2 8/9] test/memarea: support backup memory test Chengwen Feng
  2022-09-21  3:12   ` [PATCH v2 9/9] test/memarea: support no MT-safe test Chengwen Feng
  8 siblings, 0 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-09-21  3:12 UTC (permalink / raw)
  To: thomas; +Cc: dev, stephen, jerinjacobk, dmitry.kozliuk

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

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 doc/guides/prog_guide/memarea_lib.rst |  3 +++
 lib/memarea/memarea_private.h         |  2 ++
 lib/memarea/rte_memarea.c             | 21 +++++++++++++++++++++
 lib/memarea/rte_memarea.h             |  6 ++++++
 4 files changed, 32 insertions(+)

diff --git a/doc/guides/prog_guide/memarea_lib.rst b/doc/guides/prog_guide/memarea_lib.rst
index 7686625c90..c52ab95aeb 100644
--- a/doc/guides/prog_guide/memarea_lib.rst
+++ b/doc/guides/prog_guide/memarea_lib.rst
@@ -26,6 +26,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 memory object could use another
+  memarea object 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 e4d43e5907..6cad9d5b2f 100644
--- a/lib/memarea/rte_memarea.c
+++ b/lib/memarea/rte_memarea.c
@@ -121,6 +121,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;
@@ -187,6 +188,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)
 {
@@ -208,6 +218,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);
@@ -268,6 +280,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: %u curr refcnt: %d update refcnt: %d check fail!\n",
@@ -346,10 +364,13 @@ rte_memarea_dump(struct rte_memarea *ma, FILE *f, bool dump_all)
 		fprintf(f, "  source-user-memarea: %s\n", ma->init.user_memarea->init.name);
 	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);
+	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 2a92755b63..ed5e8c5db5 100644
--- a/lib/memarea/rte_memarea.h
+++ b/lib/memarea/rte_memarea.h
@@ -41,6 +41,8 @@
  *      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 object.
+ *   f) It provides backup memory mechanism, the memarea object could use
+ *      another memarea object as a backup.
  */
 
 #include <stdbool.h>
@@ -87,6 +89,10 @@ struct rte_memarea_param {
 		 */
 		struct rte_memarea *user_memarea;
 	};
+	/** Backup memarea, which is used to handle the scenario where the
+	 * current memarea object allocation failure.
+	 */
+	struct rte_memarea *bak_memarea;
 };
 
 /**
-- 
2.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v2 8/9] test/memarea: support backup memory test
  2022-09-21  3:12 ` [PATCH v2 0/9] introduce memarea library Chengwen Feng
                     ` (6 preceding siblings ...)
  2022-09-21  3:12   ` [PATCH v2 7/9] memarea: support backup memory mechanism Chengwen Feng
@ 2022-09-21  3:12   ` Chengwen Feng
  2022-09-21  3:12   ` [PATCH v2 9/9] test/memarea: support no MT-safe test Chengwen Feng
  8 siblings, 0 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-09-21  3:12 UTC (permalink / raw)
  To: thomas; +Cc: dev, stephen, jerinjacobk, dmitry.kozliuk

This patch supports backup memory mechanism test.

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 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 a07fb4424f..9609909d7c 100644
--- a/app/test/test_memarea.c
+++ b/app/test/test_memarea.c
@@ -291,6 +291,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)
 {
@@ -300,6 +340,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.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v2 9/9] test/memarea: support no MT-safe test
  2022-09-21  3:12 ` [PATCH v2 0/9] introduce memarea library Chengwen Feng
                     ` (7 preceding siblings ...)
  2022-09-21  3:12   ` [PATCH v2 8/9] test/memarea: support backup memory test Chengwen Feng
@ 2022-09-21  3:12   ` Chengwen Feng
  8 siblings, 0 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-09-21  3:12 UTC (permalink / raw)
  To: thomas; +Cc: dev, stephen, jerinjacobk, dmitry.kozliuk

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

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 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 9609909d7c..2ab90fb5b5 100644
--- a/app/test/test_memarea.c
+++ b/app/test/test_memarea.c
@@ -331,6 +331,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)
 {
@@ -341,6 +370,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.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v3 00/10] introduce memarea library
  2022-07-21  4:46 [RFC] memarea: introduce memory area library Chengwen Feng
                   ` (4 preceding siblings ...)
  2022-09-21  3:12 ` [PATCH v2 0/9] introduce memarea library Chengwen Feng
@ 2022-09-24  7:49 ` Chengwen Feng
  2022-09-24  7:49   ` [PATCH v3 01/10] memarea: " Chengwen Feng
                     ` (10 more replies)
  2022-10-05  3:38 ` [PATCH v4 " datshan
                   ` (17 subsequent siblings)
  23 siblings, 11 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-09-24  7:49 UTC (permalink / raw)
  To: thomas; +Cc: dev, stephen, jerinjacobk, dmitry.kozliuk

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 <fengchengwen@huawei.com>

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

---
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.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v3 01/10] memarea: introduce memarea library
  2022-09-24  7:49 ` [PATCH v3 00/10] introduce memarea library Chengwen Feng
@ 2022-09-24  7:49   ` Chengwen Feng
  2022-09-24  7:49   ` [PATCH v3 02/10] test/memarea: support memarea test Chengwen Feng
                     ` (9 subsequent siblings)
  10 siblings, 0 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-09-24  7:49 UTC (permalink / raw)
  To: thomas; +Cc: dev, stephen, jerinjacobk, dmitry.kozliuk

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 <fengchengwen@huawei.com>
---
 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 26d3a7077c..4d5bf986c6 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1558,6 +1558,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 <fengchengwen@huawei.com>
+F: lib/memarea
+F: doc/guides/prog_guide/memarea_lib.rst
+
 Membership - EXPERIMENTAL
 M: Yipeng Wang <yipeng1.wang@intel.com>
 M: Sameh Gobriel <sameh.gobriel@intel.com>
diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md
index 186a258be4..25dbef0b68 100644
--- a/doc/api/doxy-api-index.md
+++ b/doc/api/doxy-api-index.md
@@ -64,7 +64,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 608494a7c0..bdc5d2b0d5 100644
--- a/doc/api/doxy-api.conf.in
+++ b/doc/api/doxy-api.conf.in
@@ -55,6 +55,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..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 43502349bd..1625424141 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 library is an allocator of variable-size objects, it is oriented
+  towards the application layer, which could provides 'region-based memory
+  management' function.
+
 
 Removed Items
 -------------
diff --git a/lib/eal/common/eal_common_log.c b/lib/eal/common/eal_common_log.c
index bd7b188ceb..3d62af59c6 100644
--- a/lib/eal/common/eal_common_log.c
+++ b/lib/eal/common/eal_common_log.c
@@ -369,6 +369,7 @@ static const struct logtype logtype_strings[] = {
 	{RTE_LOGTYPE_EFD,        "lib.efd"},
 	{RTE_LOGTYPE_EVENTDEV,   "lib.eventdev"},
 	{RTE_LOGTYPE_GSO,        "lib.gso"},
+	{RTE_LOGTYPE_MEMAREA,    "lib.memarea"},
 	{RTE_LOGTYPE_USER1,      "user1"},
 	{RTE_LOGTYPE_USER2,      "user2"},
 	{RTE_LOGTYPE_USER3,      "user3"},
diff --git a/lib/eal/include/rte_log.h b/lib/eal/include/rte_log.h
index 25ce42cdfc..708f3a39dd 100644
--- a/lib/eal/include/rte_log.h
+++ b/lib/eal/include/rte_log.h
@@ -48,6 +48,7 @@ extern "C" {
 #define RTE_LOGTYPE_EFD       18 /**< Log related to EFD. */
 #define RTE_LOGTYPE_EVENTDEV  19 /**< Log related to eventdev. */
 #define RTE_LOGTYPE_GSO       20 /**< Log related to GSO. */
+#define RTE_LOGTYPE_MEMAREA   21 /**< Log related to memarea. */
 
 /* these log types can be used in an application */
 #define RTE_LOGTYPE_USER1     24 /**< User-defined log type 1. */
diff --git a/lib/memarea/memarea_private.h b/lib/memarea/memarea_private.h
new file mode 100644
index 0000000000..c76392d3e6
--- /dev/null
+++ b/lib/memarea/memarea_private.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2022 HiSilicon Limited
+ */
+
+#ifndef MEMAREA_PRIVATE_H
+#define MEMAREA_PRIVATE_H
+
+#include <rte_memarea.h>
+
+#define MEMAREA_FREE_ELEM_COOKIE	0xFFFFFFFF
+
+struct memarea_elem {
+	size_t   size;
+	uint32_t cookie;
+	int32_t  refcnt; /* Non-zero indicates that it has been allocated */
+	TAILQ_ENTRY(memarea_elem) elem_node;
+	TAILQ_ENTRY(memarea_elem) free_node;
+} __rte_cache_aligned;
+
+TAILQ_HEAD(memarea_elem_list, memarea_elem);
+
+struct rte_memarea {
+	struct rte_memarea_param init;
+	rte_spinlock_t           lock;
+	void                    *area_addr;
+	struct memarea_elem_list elem_list;
+	struct memarea_elem_list free_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..0a74fb4cd1
--- /dev/null
+++ b/lib/memarea/meson.build
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2022 HiSilicon Limited
+
+if is_windows
+    build = false
+    reason = 'not supported on Windows'
+    subdir_done()
+endif
+
+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..868da7661d
--- /dev/null
+++ b/lib/memarea/rte_memarea.c
@@ -0,0 +1,157 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2022 HiSilicon Limited
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <rte_common.h>
+#include <rte_log.h>
+#include <rte_malloc.h>
+#include <rte_spinlock.h>
+
+#include "rte_memarea.h"
+#include "memarea_private.h"
+
+static int
+memarea_check_param(const struct rte_memarea_param *init)
+{
+	size_t len;
+
+	if (init == NULL) {
+		RTE_LOG(ERR, MEMAREA, "memarea init param is NULL!\n");
+		return -EINVAL;
+	}
+
+	len = strnlen(init->name, RTE_MEMAREA_NAMESIZE);
+	if (len == 0 || len >= RTE_MEMAREA_NAMESIZE) {
+		RTE_LOG(ERR, MEMAREA, "memarea name size %zu invalid!\n", len);
+		return -EINVAL;
+	}
+
+	if (init->source != RTE_MEMAREA_SOURCE_RTE_MEMORY &&
+	    init->source != RTE_MEMAREA_SOURCE_SYSTEM_API &&
+	    init->source != RTE_MEMAREA_SOURCE_USER_ADDR &&
+	    init->source != RTE_MEMAREA_SOURCE_USER_MEMAREA) {
+		RTE_LOG(ERR, MEMAREA, "memarea: %s source: %d not supported!\n",
+			init->name, init->source);
+		return -EINVAL;
+	}
+
+	if (init->total_sz <= sizeof(struct memarea_elem)) {
+		RTE_LOG(ERR, MEMAREA, "memarea: %s total-size: %zu too small!\n",
+			init->name, init->total_sz);
+		return -EINVAL;
+	}
+
+	if (init->source == RTE_MEMAREA_SOURCE_USER_ADDR && init->user_addr == NULL) {
+		RTE_LOG(ERR, MEMAREA, "memarea: %s user provided addr is NULL!\n", init->name);
+		return -EINVAL;
+	}
+
+	if (init->source == RTE_MEMAREA_SOURCE_USER_ADDR &&
+	    ((uintptr_t)init->user_addr & (RTE_CACHE_LINE_SIZE - 1))) {
+		RTE_LOG(ERR, MEMAREA, "memarea: %s user provided addr should align: %d!\n",
+			init->name, RTE_CACHE_LINE_SIZE);
+		return -EINVAL;
+	}
+
+	if (init->source == RTE_MEMAREA_SOURCE_USER_MEMAREA && init->user_memarea == NULL) {
+		RTE_LOG(ERR, MEMAREA, "memarea: %s user provided memarea is NULL!\n", init->name);
+		return -EINVAL;
+	}
+
+	if (init->alg != RTE_MEMAREA_ALG_DEFAULT) {
+		RTE_LOG(ERR, MEMAREA, "memarea: %s alg: %d not supported!\n",
+			init->name, init->alg);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void *
+memarea_alloc_from_system_api(size_t size)
+{
+	void *ptr = NULL;
+	int ret;
+
+	ret = posix_memalign(&ptr, RTE_CACHE_LINE_SIZE, size);
+	if (ret)
+		return NULL;
+	return ptr;
+}
+
+static void *
+memarea_alloc_area(const struct rte_memarea_param *init)
+{
+	void *ptr = NULL;
+
+	if (init->source == RTE_MEMAREA_SOURCE_RTE_MEMORY)
+		ptr = rte_malloc_socket(NULL, init->total_sz, RTE_CACHE_LINE_SIZE,
+					init->numa_socket);
+	else if (init->source == RTE_MEMAREA_SOURCE_SYSTEM_API)
+		ptr = memarea_alloc_from_system_api(init->total_sz);
+	else if (init->source == RTE_MEMAREA_SOURCE_USER_ADDR)
+		ptr = init->user_addr;
+
+	if (ptr == NULL)
+		RTE_LOG(ERR, MEMAREA, "memarea: %s alloc memory area fail!\n", init->name);
+
+	return ptr;
+}
+
+struct rte_memarea *
+rte_memarea_create(const struct rte_memarea_param *init)
+{
+	struct memarea_elem *elem;
+	struct rte_memarea *ma;
+	void *addr;
+	int ret;
+
+	ret = memarea_check_param(init);
+	if (ret)
+		return NULL;
+
+	addr = memarea_alloc_area(init);
+	if (addr == NULL)
+		return NULL;
+
+	ma = rte_zmalloc(NULL, sizeof(struct rte_memarea), RTE_CACHE_LINE_SIZE);
+	if (ma == NULL) {
+		RTE_LOG(ERR, MEMAREA, "malloc memarea: %s management obj fail!\n", init->name);
+		return NULL;
+	}
+
+	ma->init = *init;
+	rte_spinlock_init(&ma->lock);
+	TAILQ_INIT(&ma->elem_list);
+	TAILQ_INIT(&ma->free_list);
+	ma->area_addr = addr;
+	elem = addr;
+	elem->size = init->total_sz - sizeof(struct memarea_elem);
+	elem->cookie = MEMAREA_FREE_ELEM_COOKIE;
+	elem->refcnt = 0;
+	TAILQ_INSERT_TAIL(&ma->elem_list, elem, elem_node);
+	TAILQ_INSERT_TAIL(&ma->free_list, elem, free_node);
+
+	return ma;
+}
+
+static void
+memarea_free_area(struct rte_memarea *ma)
+{
+	if (ma->init.source == RTE_MEMAREA_SOURCE_RTE_MEMORY)
+		rte_free(ma->area_addr);
+	else if (ma->init.source == RTE_MEMAREA_SOURCE_SYSTEM_API)
+		free(ma->area_addr);
+}
+
+void
+rte_memarea_destroy(struct rte_memarea *ma)
+{
+	if (ma == NULL)
+		return;
+	memarea_free_area(ma);
+	rte_free(ma);
+}
diff --git a/lib/memarea/rte_memarea.h b/lib/memarea/rte_memarea.h
new file mode 100644
index 0000000000..543cda4cac
--- /dev/null
+++ b/lib/memarea/rte_memarea.h
@@ -0,0 +1,145 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2022 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 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. So we can build
+ *      the following memory management structure:
+ *         \code{.unparsed}
+ *                           -------------
+ *                           | memarea-1 |
+ *                           -------------
+ *                                 |
+ *                                 v
+ *                  -------------------------------
+ *                  |               |             |
+ *                  v               v             v
+ *            -------------   -------------   ----------
+ *            | memarea-2 |   | memarea-3 |   | object |
+ *            -------------   -------------   ----------
+ *         \endcode
+ *      As shown above, the memarea-2/3 both create from memarea-1's memory.
+ * - 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. 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 <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include <rte_compat.h>
+
+#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_RTE_MEMORY,
+	/** Memory source comes from system API. */
+	RTE_MEMAREA_SOURCE_SYSTEM_API,
+	/** Memory source comes from user-provided address. */
+	RTE_MEMAREA_SOURCE_USER_ADDR,
+	/** Memory source comes from user-provided memarea. */
+	RTE_MEMAREA_SOURCE_USER_MEMAREA,
+};
+
+/**
+ * Memarea memory management algorithm.
+ */
+enum rte_memarea_alg {
+	/* The default management algorithm is a variant of the next fit
+	 * algorithm. It uses a free-list to apply for memory and uses an
+	 * element-list in ascending order of address to support merging
+	 * upon free.
+	 */
+	RTE_MEMAREA_ALG_DEFAULT,
+};
+
+struct rte_memarea;
+
+struct rte_memarea_param {
+	char name[RTE_MEMAREA_NAMESIZE]; /**< Name of memarea. */
+	enum rte_memarea_source source;  /**< Memory source of memarea. */
+	enum rte_memarea_alg 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_RTE_MEMORY.
+		 */
+		int numa_socket;
+		/** User provided address, this field is valid only when the
+		 * source is set to be RTE_MEMAREA_SOURCE_USER_ADDR.
+		 * Note: the provided address must align at least
+		 * RTE_CACHE_LINE_SIZE.
+		 */
+		void *user_addr;
+		/** User provided memarea, this field is valid only when the
+		 * source is set to be RTE_MEMAREA_SOURCE_USER_MEMAREA.
+		 */
+		struct rte_memarea *user_memarea;
+	};
+};
+
+/**
+ * @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 c648f7d800..521a25d6c0 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -42,6 +42,7 @@ libraries = [
         'kni',
         'latencystats',
         'lpm',
+        'memarea',
         'member',
         'pcapng',
         'power',
-- 
2.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v3 02/10] test/memarea: support memarea test
  2022-09-24  7:49 ` [PATCH v3 00/10] introduce memarea library Chengwen Feng
  2022-09-24  7:49   ` [PATCH v3 01/10] memarea: " Chengwen Feng
@ 2022-09-24  7:49   ` Chengwen Feng
  2022-09-24  7:49   ` [PATCH v3 03/10] memarea: support alloc/free/update-refcnt API Chengwen Feng
                     ` (8 subsequent siblings)
  10 siblings, 0 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-09-24  7:49 UTC (permalink / raw)
  To: thomas; +Cc: dev, stephen, jerinjacobk, dmitry.kozliuk

This patch supports memarea test about API rte_memarea_create and
rte_memarea_destroy.

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 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 4d5bf986c6..eb2de32884 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1562,6 +1562,7 @@ Memarea - EXPERIMENTAL
 M: Chengwen Feng <fengchengwen@huawei.com>
 F: lib/memarea
 F: doc/guides/prog_guide/memarea_lib.rst
+F: app/test/test_memarea*
 
 Membership - EXPERIMENTAL
 M: Yipeng Wang <yipeng1.wang@intel.com>
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 0000000000..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 <stdio.h>
+#include <string.h>
+
+#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 <rte_memory.h>
+#include <rte_memarea.h>
+
+#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_SOURCE_RTE_MEMORY;
+	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 system API */
+	test_memarea_init_def_param(&init);
+	init.source = RTE_MEMAREA_SOURCE_SYSTEM_API;
+	ma = rte_memarea_create(&init);
+	RTE_TEST_ASSERT(ma != NULL, "Expected Non-NULL");
+	rte_memarea_destroy(ma);
+
+	/* test for create with user-address */
+	test_memarea_init_def_param(&init);
+	init.source = RTE_MEMAREA_SOURCE_USER_ADDR;
+	init.user_addr = (void *)(((uintptr_t)user_buffer + RTE_CACHE_LINE_SIZE) &
+				  ~(RTE_CACHE_LINE_SIZE - 1));
+	ma = rte_memarea_create(&init);
+	RTE_TEST_ASSERT(ma != NULL, "Expected Non-NULL");
+	rte_memarea_destroy(ma);
+
+	return 0;
+}
+
+static int
+test_memarea(void)
+{
+	MEMAREA_TEST_API_RUN(test_memarea_create_bad_param);
+	MEMAREA_TEST_API_RUN(test_memarea_create_destroy);
+	return 0;
+}
+
+#endif /* !RTE_EXEC_ENV_WINDOWS */
+
+REGISTER_TEST_COMMAND(memarea_autotest, test_memarea);
-- 
2.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v3 03/10] memarea: support alloc/free/update-refcnt API
  2022-09-24  7:49 ` [PATCH v3 00/10] introduce memarea library Chengwen Feng
  2022-09-24  7:49   ` [PATCH v3 01/10] memarea: " Chengwen Feng
  2022-09-24  7:49   ` [PATCH v3 02/10] test/memarea: support memarea test Chengwen Feng
@ 2022-09-24  7:49   ` Chengwen Feng
  2022-09-24  7:49   ` [PATCH v3 04/10] test/memarea: support alloc/free/update-refcnt test Chengwen Feng
                     ` (7 subsequent siblings)
  10 siblings, 0 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-09-24  7:49 UTC (permalink / raw)
  To: thomas; +Cc: dev, stephen, jerinjacobk, dmitry.kozliuk

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

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 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 <stdio.h>
 #include <stdlib.h>
+#include <sys/queue.h>
 
 #include <rte_common.h>
 #include <rte_log.h>
@@ -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 = (void *)((uintptr_t)elem + sizeof(struct memarea_elem));
+		break;
+	}
+	if (unlikely(ptr == NULL))
+		ma->alloc_fails++;
+	memarea_unlock(ma);
+
+	return ptr;
+}
+
+void
+rte_memarea_free(struct rte_memarea *ma, void *ptr)
+{
+	rte_memarea_update_refcnt(ma, ptr, -1);
+}
+
+static inline void
+memarea_merge_node(struct rte_memarea *ma, struct memarea_elem *curr,
+		   struct memarea_elem *next, bool del_next_from_free,
+		   bool add_curr_to_free)
+{
+	curr->size += next->size + sizeof(struct memarea_elem);
+	next->size = 0;
+	next->cookie = 0;
+	TAILQ_REMOVE(&ma->elem_list, next, elem_node);
+	if (del_next_from_free)
+		TAILQ_REMOVE(&ma->free_list, next, free_node);
+	if (add_curr_to_free) {
+		curr->cookie = MEMAREA_FREE_ELEM_COOKIE;
+		TAILQ_INSERT_TAIL(&ma->free_list, curr, free_node);
+	}
+}
+
+static inline void
+memarea_free_elem(struct rte_memarea *ma, struct memarea_elem *elem)
+{
+	struct memarea_elem *prev, *next;
+	bool merged = false;
+	prev = TAILQ_PREV(elem, memarea_elem_list, elem_node);
+	next = TAILQ_NEXT(elem, elem_node);
+	if (prev != NULL && prev->refcnt == 0) {
+		memarea_merge_node(ma, prev, elem, false, false);
+		elem = prev;
+		merged = true;
+	}
+	if (next != NULL && next->refcnt == 0) {
+		memarea_merge_node(ma, elem, next, true, !merged);
+		merged = true;
+	}
+	if (!merged) {
+		elem->cookie = MEMAREA_FREE_ELEM_COOKIE;
+		TAILQ_INSERT_TAIL(&ma->free_list, elem, free_node);
+	}
+}
+
+void
+rte_memarea_update_refcnt(struct rte_memarea *ma, void *ptr, int16_t value)
+{
+	struct memarea_elem *elem = (struct memarea_elem *)((uintptr_t)ptr -
+							    sizeof(struct memarea_elem));
+
+	if (unlikely(ma == NULL || ptr == NULL))
+		return;
+
+	memarea_lock(ma);
+	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",
+			ma->init.name, elem->cookie, elem->refcnt, value);
+		ma->refcnt_check_fails++;
+		if (elem->refcnt > 0)
+			elem->refcnt += value;
+		memarea_unlock(ma);
+		return;
+	}
+
+	elem->refcnt += value;
+	if (elem->refcnt == 0)
+		memarea_free_elem(ma, elem);
+	memarea_unlock(ma);
+}
diff --git a/lib/memarea/rte_memarea.h b/lib/memarea/rte_memarea.h
index 543cda4cac..10e0d6ad5a 100644
--- a/lib/memarea/rte_memarea.h
+++ b/lib/memarea/rte_memarea.h
@@ -138,6 +138,62 @@ 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.
+ * @param cookie
+ *   User-provided footprint which could used to debug memory leak.
+ *
+ * @return
+ *   Non-NULL on success. Otherwise NULL is returned.
+ */
+__rte_experimental
+void *rte_memarea_alloc(struct rte_memarea *ma, size_t size, uint32_t cookie);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Free memory to memarea.
+ *
+ * Free one memory object to the memarea.
+ *
+ * @param ma
+ *   The pointer of memarea.
+ * @param ptr
+ *   The pointer of memory object which need be freed.
+ */
+__rte_experimental
+void rte_memarea_free(struct rte_memarea *ma, void *ptr);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Update memory's refcnt.
+ *
+ * Update one memory object's refcnt.
+ * When refcnt is updated to be zero, the memory object is freed.
+ *
+ * @param ma
+ *   The pointer of memarea.
+ * @param ptr
+ *   The pointer of memory object which need be updated refcnt.
+ * @param value
+ *   The value which need be updated.
+ */
+__rte_experimental
+void rte_memarea_update_refcnt(struct rte_memarea *ma, void *ptr, int16_t value);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/memarea/version.map b/lib/memarea/version.map
index f36a04d7cf..a0026fc5f9 100644
--- a/lib/memarea/version.map
+++ b/lib/memarea/version.map
@@ -1,8 +1,11 @@
 EXPERIMENTAL {
 	global:
 
+	rte_memarea_alloc;
 	rte_memarea_create;
 	rte_memarea_destroy;
+	rte_memarea_free;
+	rte_memarea_update_refcnt;
 
 	local: *;
 };
-- 
2.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v3 04/10] test/memarea: support alloc/free/update-refcnt test
  2022-09-24  7:49 ` [PATCH v3 00/10] introduce memarea library Chengwen Feng
                     ` (2 preceding siblings ...)
  2022-09-24  7:49   ` [PATCH v3 03/10] memarea: support alloc/free/update-refcnt API Chengwen Feng
@ 2022-09-24  7:49   ` Chengwen Feng
  2022-09-24  7:49   ` [PATCH v3 05/10] memarea: support dump API Chengwen Feng
                     ` (6 subsequent siblings)
  10 siblings, 0 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-09-24  7:49 UTC (permalink / raw)
  To: thomas; +Cc: dev, stephen, jerinjacobk, dmitry.kozliuk

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

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 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)
+{
+#define ALLOC_MAX_NUM	8
+	struct rte_memarea_param init;
+	struct rte_memarea *ma;
+	void *ptr[ALLOC_MAX_NUM];
+	int i;
+
+	/* 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");
+	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, 0);
+
+	/* 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, ptr[6]);
+
+	rte_memarea_destroy(ma);
+
 	return 0;
 }
 
@@ -141,6 +286,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 0;
 }
 
-- 
2.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v3 05/10] memarea: support dump API
  2022-09-24  7:49 ` [PATCH v3 00/10] introduce memarea library Chengwen Feng
                     ` (3 preceding siblings ...)
  2022-09-24  7:49   ` [PATCH v3 04/10] test/memarea: support alloc/free/update-refcnt test Chengwen Feng
@ 2022-09-24  7:49   ` Chengwen Feng
  2022-09-24  7:49   ` [PATCH v3 06/10] test/memarea: support dump test Chengwen Feng
                     ` (5 subsequent siblings)
  10 siblings, 0 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-09-24  7:49 UTC (permalink / raw)
  To: thomas; +Cc: dev, stephen, jerinjacobk, dmitry.kozliuk

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

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 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 <inttypes.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/queue.h>
@@ -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/version.map
@@ -4,6 +4,7 @@ EXPERIMENTAL {
 	rte_memarea_alloc;
 	rte_memarea_create;
 	rte_memarea_destroy;
+	rte_memarea_dump;
 	rte_memarea_free;
 	rte_memarea_update_refcnt;
 
-- 
2.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v3 06/10] test/memarea: support dump test
  2022-09-24  7:49 ` [PATCH v3 00/10] introduce memarea library Chengwen Feng
                     ` (4 preceding siblings ...)
  2022-09-24  7:49   ` [PATCH v3 05/10] memarea: support dump API Chengwen Feng
@ 2022-09-24  7:49   ` Chengwen Feng
  2022-09-24  7:49   ` [PATCH v3 07/10] memarea: support backup memory mechanism Chengwen Feng
                     ` (4 subsequent siblings)
  10 siblings, 0 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-09-24  7:49 UTC (permalink / raw)
  To: thomas; +Cc: dev, stephen, jerinjacobk, dmitry.kozliuk

This patch supports rte_memarea_dump() test.

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 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.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v3 07/10] memarea: support backup memory mechanism
  2022-09-24  7:49 ` [PATCH v3 00/10] introduce memarea library Chengwen Feng
                     ` (5 preceding siblings ...)
  2022-09-24  7:49   ` [PATCH v3 06/10] test/memarea: support dump test Chengwen Feng
@ 2022-09-24  7:49   ` Chengwen Feng
  2022-09-24  7:49   ` [PATCH v3 08/10] test/memarea: support backup memory test Chengwen Feng
                     ` (3 subsequent siblings)
  10 siblings, 0 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-09-24  7:49 UTC (permalink / raw)
  To: thomas; +Cc: dev, stephen, jerinjacobk, dmitry.kozliuk

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

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 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 object from backup memarea when
+ *   the current memarea failed to allocate.
  */
 
 #include <stdbool.h>
@@ -105,6 +108,10 @@ struct rte_memarea_param {
 		 */
 		struct rte_memarea *user_memarea;
 	};
+	/** Backup memarea, which is used to handle the scenario where the
+	 * current memarea allocation failure.
+	 */
+	struct rte_memarea *bak_memarea;
 };
 
 /**
-- 
2.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v3 08/10] test/memarea: support backup memory test
  2022-09-24  7:49 ` [PATCH v3 00/10] introduce memarea library Chengwen Feng
                     ` (6 preceding siblings ...)
  2022-09-24  7:49   ` [PATCH v3 07/10] memarea: support backup memory mechanism Chengwen Feng
@ 2022-09-24  7:49   ` Chengwen Feng
  2022-09-24  7:49   ` [PATCH v3 09/10] memarea: detect memory corruption based on magic Chengwen Feng
                     ` (2 subsequent siblings)
  10 siblings, 0 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-09-24  7:49 UTC (permalink / raw)
  To: thomas; +Cc: dev, stephen, jerinjacobk, dmitry.kozliuk

This patch supports backup memory mechanism test.

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 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.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v3 09/10] memarea: detect memory corruption based on magic
  2022-09-24  7:49 ` [PATCH v3 00/10] introduce memarea library Chengwen Feng
                     ` (7 preceding siblings ...)
  2022-09-24  7:49   ` [PATCH v3 08/10] test/memarea: support backup memory test Chengwen Feng
@ 2022-09-24  7:49   ` Chengwen Feng
  2022-09-24  7:49   ` [PATCH v3 10/10] test/memarea: support no MT-safe test Chengwen Feng
  2022-10-03  7:42   ` [PATCH v3 00/10] introduce memarea library David Marchand
  10 siblings, 0 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-09-24  7:49 UTC (permalink / raw)
  To: thomas; +Cc: dev, stephen, jerinjacobk, dmitry.kozliuk

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

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 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 <rte_memarea.h>
 
+#define MEMAREA_ELEM_MAGIC_NUM		0xbeef1234
 #define MEMAREA_FREE_ELEM_COOKIE	0xFFFFFFFF
 
 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.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v3 10/10] test/memarea: support no MT-safe test
  2022-09-24  7:49 ` [PATCH v3 00/10] introduce memarea library Chengwen Feng
                     ` (8 preceding siblings ...)
  2022-09-24  7:49   ` [PATCH v3 09/10] memarea: detect memory corruption based on magic Chengwen Feng
@ 2022-09-24  7:49   ` Chengwen Feng
  2022-10-03  7:42   ` [PATCH v3 00/10] introduce memarea library David Marchand
  10 siblings, 0 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-09-24  7:49 UTC (permalink / raw)
  To: thomas; +Cc: dev, stephen, jerinjacobk, dmitry.kozliuk

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

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 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.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* Re: [PATCH v3 00/10] introduce memarea library
  2022-09-24  7:49 ` [PATCH v3 00/10] introduce memarea library Chengwen Feng
                     ` (9 preceding siblings ...)
  2022-09-24  7:49   ` [PATCH v3 10/10] test/memarea: support no MT-safe test Chengwen Feng
@ 2022-10-03  7:42   ` David Marchand
  2022-10-05  4:19     ` datshan
  10 siblings, 1 reply; 222+ messages in thread
From: David Marchand @ 2022-10-03  7:42 UTC (permalink / raw)
  To: Chengwen Feng, Morten Brørup, Burakov, Anatoly,
	dmitry.kozliuk, stephen
  Cc: thomas, dev, jerinjacobk

On Sat, Sep 24, 2022 at 9:56 AM Chengwen Feng <fengchengwen@huawei.com> 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 <fengchengwen@huawei.com>

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.

-- 
David Marchand


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v4 00/10] introduce memarea library
  2022-07-21  4:46 [RFC] memarea: introduce memory area library Chengwen Feng
                   ` (5 preceding siblings ...)
  2022-09-24  7:49 ` [PATCH v3 00/10] introduce memarea library Chengwen Feng
@ 2022-10-05  3:38 ` datshan
       [not found] ` <20221005033848.2241-1-datshan@qq.com>
                   ` (16 subsequent siblings)
  23 siblings, 0 replies; 222+ messages in thread
From: datshan @ 2022-10-05  3:38 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk
  Cc: thomas, dev, datshan, Chengwen Feng

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 <fengchengwen@huawei.com>

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


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v4 01/10] memarea: introduce memarea library
       [not found] ` <20221005033848.2241-1-datshan@qq.com>
@ 2022-10-05  3:38   ` datshan
  2022-10-05  3:38   ` [PATCH v4 02/10] test/memarea: support memarea test datshan
                     ` (8 subsequent siblings)
  9 siblings, 0 replies; 222+ messages in thread
From: datshan @ 2022-10-05  3:38 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk
  Cc: thomas, dev, Chengwen Feng

From: Chengwen Feng <fengchengwen@huawei.com>

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 <fengchengwen@huawei.com>
---
 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 <fengchengwen@huawei.com>
+F: lib/memarea
+F: doc/guides/prog_guide/memarea_lib.rst
+
 Membership - EXPERIMENTAL
 M: Yipeng Wang <yipeng1.wang@intel.com>
 M: Sameh Gobriel <sameh.gobriel@intel.com>
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..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 library is an allocator of variable-size objects, it is oriented
+  towards the application layer, which could provides 'region-based memory
+  management' function.
+
 * **Added configuration for asynchronous flow connection tracking.**
 
   Added connection tracking action number hint to ``rte_flow_configure``
diff --git a/lib/eal/common/eal_common_log.c b/lib/eal/common/eal_common_log.c
index bd7b188ceb..3d62af59c6 100644
--- a/lib/eal/common/eal_common_log.c
+++ b/lib/eal/common/eal_common_log.c
@@ -369,6 +369,7 @@ static const struct logtype logtype_strings[] = {
 	{RTE_LOGTYPE_EFD,        "lib.efd"},
 	{RTE_LOGTYPE_EVENTDEV,   "lib.eventdev"},
 	{RTE_LOGTYPE_GSO,        "lib.gso"},
+	{RTE_LOGTYPE_MEMAREA,    "lib.memarea"},
 	{RTE_LOGTYPE_USER1,      "user1"},
 	{RTE_LOGTYPE_USER2,      "user2"},
 	{RTE_LOGTYPE_USER3,      "user3"},
diff --git a/lib/eal/include/rte_log.h b/lib/eal/include/rte_log.h
index 25ce42cdfc..708f3a39dd 100644
--- a/lib/eal/include/rte_log.h
+++ b/lib/eal/include/rte_log.h
@@ -48,6 +48,7 @@ extern "C" {
 #define RTE_LOGTYPE_EFD       18 /**< Log related to EFD. */
 #define RTE_LOGTYPE_EVENTDEV  19 /**< Log related to eventdev. */
 #define RTE_LOGTYPE_GSO       20 /**< Log related to GSO. */
+#define RTE_LOGTYPE_MEMAREA   21 /**< Log related to memarea. */
 
 /* these log types can be used in an application */
 #define RTE_LOGTYPE_USER1     24 /**< User-defined log type 1. */
diff --git a/lib/memarea/memarea_private.h b/lib/memarea/memarea_private.h
new file mode 100644
index 0000000000..c76392d3e6
--- /dev/null
+++ b/lib/memarea/memarea_private.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2022 HiSilicon Limited
+ */
+
+#ifndef MEMAREA_PRIVATE_H
+#define MEMAREA_PRIVATE_H
+
+#include <rte_memarea.h>
+
+#define MEMAREA_FREE_ELEM_COOKIE	0xFFFFFFFF
+
+struct memarea_elem {
+	size_t   size;
+	uint32_t cookie;
+	int32_t  refcnt; /* Non-zero indicates that it has been allocated */
+	TAILQ_ENTRY(memarea_elem) elem_node;
+	TAILQ_ENTRY(memarea_elem) free_node;
+} __rte_cache_aligned;
+
+TAILQ_HEAD(memarea_elem_list, memarea_elem);
+
+struct rte_memarea {
+	struct rte_memarea_param init;
+	rte_spinlock_t           lock;
+	void                    *area_addr;
+	struct memarea_elem_list elem_list;
+	struct memarea_elem_list free_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..0a74fb4cd1
--- /dev/null
+++ b/lib/memarea/meson.build
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2022 HiSilicon Limited
+
+if is_windows
+    build = false
+    reason = 'not supported on Windows'
+    subdir_done()
+endif
+
+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..868da7661d
--- /dev/null
+++ b/lib/memarea/rte_memarea.c
@@ -0,0 +1,157 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2022 HiSilicon Limited
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <rte_common.h>
+#include <rte_log.h>
+#include <rte_malloc.h>
+#include <rte_spinlock.h>
+
+#include "rte_memarea.h"
+#include "memarea_private.h"
+
+static int
+memarea_check_param(const struct rte_memarea_param *init)
+{
+	size_t len;
+
+	if (init == NULL) {
+		RTE_LOG(ERR, MEMAREA, "memarea init param is NULL!\n");
+		return -EINVAL;
+	}
+
+	len = strnlen(init->name, RTE_MEMAREA_NAMESIZE);
+	if (len == 0 || len >= RTE_MEMAREA_NAMESIZE) {
+		RTE_LOG(ERR, MEMAREA, "memarea name size %zu invalid!\n", len);
+		return -EINVAL;
+	}
+
+	if (init->source != RTE_MEMAREA_SOURCE_RTE_MEMORY &&
+	    init->source != RTE_MEMAREA_SOURCE_SYSTEM_API &&
+	    init->source != RTE_MEMAREA_SOURCE_USER_ADDR &&
+	    init->source != RTE_MEMAREA_SOURCE_USER_MEMAREA) {
+		RTE_LOG(ERR, MEMAREA, "memarea: %s source: %d not supported!\n",
+			init->name, init->source);
+		return -EINVAL;
+	}
+
+	if (init->total_sz <= sizeof(struct memarea_elem)) {
+		RTE_LOG(ERR, MEMAREA, "memarea: %s total-size: %zu too small!\n",
+			init->name, init->total_sz);
+		return -EINVAL;
+	}
+
+	if (init->source == RTE_MEMAREA_SOURCE_USER_ADDR && init->user_addr == NULL) {
+		RTE_LOG(ERR, MEMAREA, "memarea: %s user provided addr is NULL!\n", init->name);
+		return -EINVAL;
+	}
+
+	if (init->source == RTE_MEMAREA_SOURCE_USER_ADDR &&
+	    ((uintptr_t)init->user_addr & (RTE_CACHE_LINE_SIZE - 1))) {
+		RTE_LOG(ERR, MEMAREA, "memarea: %s user provided addr should align: %d!\n",
+			init->name, RTE_CACHE_LINE_SIZE);
+		return -EINVAL;
+	}
+
+	if (init->source == RTE_MEMAREA_SOURCE_USER_MEMAREA && init->user_memarea == NULL) {
+		RTE_LOG(ERR, MEMAREA, "memarea: %s user provided memarea is NULL!\n", init->name);
+		return -EINVAL;
+	}
+
+	if (init->alg != RTE_MEMAREA_ALG_DEFAULT) {
+		RTE_LOG(ERR, MEMAREA, "memarea: %s alg: %d not supported!\n",
+			init->name, init->alg);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void *
+memarea_alloc_from_system_api(size_t size)
+{
+	void *ptr = NULL;
+	int ret;
+
+	ret = posix_memalign(&ptr, RTE_CACHE_LINE_SIZE, size);
+	if (ret)
+		return NULL;
+	return ptr;
+}
+
+static void *
+memarea_alloc_area(const struct rte_memarea_param *init)
+{
+	void *ptr = NULL;
+
+	if (init->source == RTE_MEMAREA_SOURCE_RTE_MEMORY)
+		ptr = rte_malloc_socket(NULL, init->total_sz, RTE_CACHE_LINE_SIZE,
+					init->numa_socket);
+	else if (init->source == RTE_MEMAREA_SOURCE_SYSTEM_API)
+		ptr = memarea_alloc_from_system_api(init->total_sz);
+	else if (init->source == RTE_MEMAREA_SOURCE_USER_ADDR)
+		ptr = init->user_addr;
+
+	if (ptr == NULL)
+		RTE_LOG(ERR, MEMAREA, "memarea: %s alloc memory area fail!\n", init->name);
+
+	return ptr;
+}
+
+struct rte_memarea *
+rte_memarea_create(const struct rte_memarea_param *init)
+{
+	struct memarea_elem *elem;
+	struct rte_memarea *ma;
+	void *addr;
+	int ret;
+
+	ret = memarea_check_param(init);
+	if (ret)
+		return NULL;
+
+	addr = memarea_alloc_area(init);
+	if (addr == NULL)
+		return NULL;
+
+	ma = rte_zmalloc(NULL, sizeof(struct rte_memarea), RTE_CACHE_LINE_SIZE);
+	if (ma == NULL) {
+		RTE_LOG(ERR, MEMAREA, "malloc memarea: %s management obj fail!\n", init->name);
+		return NULL;
+	}
+
+	ma->init = *init;
+	rte_spinlock_init(&ma->lock);
+	TAILQ_INIT(&ma->elem_list);
+	TAILQ_INIT(&ma->free_list);
+	ma->area_addr = addr;
+	elem = addr;
+	elem->size = init->total_sz - sizeof(struct memarea_elem);
+	elem->cookie = MEMAREA_FREE_ELEM_COOKIE;
+	elem->refcnt = 0;
+	TAILQ_INSERT_TAIL(&ma->elem_list, elem, elem_node);
+	TAILQ_INSERT_TAIL(&ma->free_list, elem, free_node);
+
+	return ma;
+}
+
+static void
+memarea_free_area(struct rte_memarea *ma)
+{
+	if (ma->init.source == RTE_MEMAREA_SOURCE_RTE_MEMORY)
+		rte_free(ma->area_addr);
+	else if (ma->init.source == RTE_MEMAREA_SOURCE_SYSTEM_API)
+		free(ma->area_addr);
+}
+
+void
+rte_memarea_destroy(struct rte_memarea *ma)
+{
+	if (ma == NULL)
+		return;
+	memarea_free_area(ma);
+	rte_free(ma);
+}
diff --git a/lib/memarea/rte_memarea.h b/lib/memarea/rte_memarea.h
new file mode 100644
index 0000000000..543cda4cac
--- /dev/null
+++ b/lib/memarea/rte_memarea.h
@@ -0,0 +1,145 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2022 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 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. So we can build
+ *      the following memory management structure:
+ *         \code{.unparsed}
+ *                           -------------
+ *                           | memarea-1 |
+ *                           -------------
+ *                                 |
+ *                                 v
+ *                  -------------------------------
+ *                  |               |             |
+ *                  v               v             v
+ *            -------------   -------------   ----------
+ *            | memarea-2 |   | memarea-3 |   | object |
+ *            -------------   -------------   ----------
+ *         \endcode
+ *      As shown above, the memarea-2/3 both create from memarea-1's memory.
+ * - 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. 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 <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include <rte_compat.h>
+
+#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_RTE_MEMORY,
+	/** Memory source comes from system API. */
+	RTE_MEMAREA_SOURCE_SYSTEM_API,
+	/** Memory source comes from user-provided address. */
+	RTE_MEMAREA_SOURCE_USER_ADDR,
+	/** Memory source comes from user-provided memarea. */
+	RTE_MEMAREA_SOURCE_USER_MEMAREA,
+};
+
+/**
+ * Memarea memory management algorithm.
+ */
+enum rte_memarea_alg {
+	/* The default management algorithm is a variant of the next fit
+	 * algorithm. It uses a free-list to apply for memory and uses an
+	 * element-list in ascending order of address to support merging
+	 * upon free.
+	 */
+	RTE_MEMAREA_ALG_DEFAULT,
+};
+
+struct rte_memarea;
+
+struct rte_memarea_param {
+	char name[RTE_MEMAREA_NAMESIZE]; /**< Name of memarea. */
+	enum rte_memarea_source source;  /**< Memory source of memarea. */
+	enum rte_memarea_alg 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_RTE_MEMORY.
+		 */
+		int numa_socket;
+		/** User provided address, this field is valid only when the
+		 * source is set to be RTE_MEMAREA_SOURCE_USER_ADDR.
+		 * Note: the provided address must align at least
+		 * RTE_CACHE_LINE_SIZE.
+		 */
+		void *user_addr;
+		/** User provided memarea, this field is valid only when the
+		 * source is set to be RTE_MEMAREA_SOURCE_USER_MEMAREA.
+		 */
+		struct rte_memarea *user_memarea;
+	};
+};
+
+/**
+ * @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 c648f7d800..521a25d6c0 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -42,6 +42,7 @@ libraries = [
         'kni',
         'latencystats',
         'lpm',
+        'memarea',
         'member',
         'pcapng',
         'power',
-- 
2.34.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v4 02/10] test/memarea: support memarea test
       [not found] ` <20221005033848.2241-1-datshan@qq.com>
  2022-10-05  3:38   ` [PATCH v4 01/10] memarea: " datshan
@ 2022-10-05  3:38   ` datshan
  2022-10-05  3:38   ` [PATCH v4 03/10] memarea: support alloc/free/update-refcnt API datshan
                     ` (7 subsequent siblings)
  9 siblings, 0 replies; 222+ messages in thread
From: datshan @ 2022-10-05  3:38 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk
  Cc: thomas, dev, Chengwen Feng

From: Chengwen Feng <fengchengwen@huawei.com>

This patch supports memarea test about API rte_memarea_create and
rte_memarea_destroy.

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 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 <fengchengwen@huawei.com>
 F: lib/memarea
 F: doc/guides/prog_guide/memarea_lib.rst
+F: app/test/test_memarea*
 
 Membership - EXPERIMENTAL
 M: Yipeng Wang <yipeng1.wang@intel.com>
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 0000000000..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 <stdio.h>
+#include <string.h>
+
+#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 <rte_memory.h>
+#include <rte_memarea.h>
+
+#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_SOURCE_RTE_MEMORY;
+	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 system API */
+	test_memarea_init_def_param(&init);
+	init.source = RTE_MEMAREA_SOURCE_SYSTEM_API;
+	ma = rte_memarea_create(&init);
+	RTE_TEST_ASSERT(ma != NULL, "Expected Non-NULL");
+	rte_memarea_destroy(ma);
+
+	/* test for create with user-address */
+	test_memarea_init_def_param(&init);
+	init.source = RTE_MEMAREA_SOURCE_USER_ADDR;
+	init.user_addr = (void *)(((uintptr_t)user_buffer + RTE_CACHE_LINE_SIZE) &
+				  ~(RTE_CACHE_LINE_SIZE - 1));
+	ma = rte_memarea_create(&init);
+	RTE_TEST_ASSERT(ma != NULL, "Expected Non-NULL");
+	rte_memarea_destroy(ma);
+
+	return 0;
+}
+
+static int
+test_memarea(void)
+{
+	MEMAREA_TEST_API_RUN(test_memarea_create_bad_param);
+	MEMAREA_TEST_API_RUN(test_memarea_create_destroy);
+	return 0;
+}
+
+#endif /* !RTE_EXEC_ENV_WINDOWS */
+
+REGISTER_TEST_COMMAND(memarea_autotest, test_memarea);
-- 
2.34.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v4 03/10] memarea: support alloc/free/update-refcnt API
       [not found] ` <20221005033848.2241-1-datshan@qq.com>
  2022-10-05  3:38   ` [PATCH v4 01/10] memarea: " datshan
  2022-10-05  3:38   ` [PATCH v4 02/10] test/memarea: support memarea test datshan
@ 2022-10-05  3:38   ` datshan
  2022-10-05  3:38   ` [PATCH v4 04/10] test/memarea: support alloc/free/update-refcnt test datshan
                     ` (6 subsequent siblings)
  9 siblings, 0 replies; 222+ messages in thread
From: datshan @ 2022-10-05  3:38 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk
  Cc: thomas, dev, Chengwen Feng

From: Chengwen Feng <fengchengwen@huawei.com>

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

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 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 <stdio.h>
 #include <stdlib.h>
+#include <sys/queue.h>
 
 #include <rte_common.h>
 #include <rte_log.h>
@@ -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 = (void *)((uintptr_t)elem + sizeof(struct memarea_elem));
+		break;
+	}
+	if (unlikely(ptr == NULL))
+		ma->alloc_fails++;
+	memarea_unlock(ma);
+
+	return ptr;
+}
+
+void
+rte_memarea_free(struct rte_memarea *ma, void *ptr)
+{
+	rte_memarea_update_refcnt(ma, ptr, -1);
+}
+
+static inline void
+memarea_merge_node(struct rte_memarea *ma, struct memarea_elem *curr,
+		   struct memarea_elem *next, bool del_next_from_free,
+		   bool add_curr_to_free)
+{
+	curr->size += next->size + sizeof(struct memarea_elem);
+	next->size = 0;
+	next->cookie = 0;
+	TAILQ_REMOVE(&ma->elem_list, next, elem_node);
+	if (del_next_from_free)
+		TAILQ_REMOVE(&ma->free_list, next, free_node);
+	if (add_curr_to_free) {
+		curr->cookie = MEMAREA_FREE_ELEM_COOKIE;
+		TAILQ_INSERT_TAIL(&ma->free_list, curr, free_node);
+	}
+}
+
+static inline void
+memarea_free_elem(struct rte_memarea *ma, struct memarea_elem *elem)
+{
+	struct memarea_elem *prev, *next;
+	bool merged = false;
+	prev = TAILQ_PREV(elem, memarea_elem_list, elem_node);
+	next = TAILQ_NEXT(elem, elem_node);
+	if (prev != NULL && prev->refcnt == 0) {
+		memarea_merge_node(ma, prev, elem, false, false);
+		elem = prev;
+		merged = true;
+	}
+	if (next != NULL && next->refcnt == 0) {
+		memarea_merge_node(ma, elem, next, true, !merged);
+		merged = true;
+	}
+	if (!merged) {
+		elem->cookie = MEMAREA_FREE_ELEM_COOKIE;
+		TAILQ_INSERT_TAIL(&ma->free_list, elem, free_node);
+	}
+}
+
+void
+rte_memarea_update_refcnt(struct rte_memarea *ma, void *ptr, int16_t value)
+{
+	struct memarea_elem *elem = (struct memarea_elem *)((uintptr_t)ptr -
+							    sizeof(struct memarea_elem));
+
+	if (unlikely(ma == NULL || ptr == NULL))
+		return;
+
+	memarea_lock(ma);
+	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",
+			ma->init.name, elem->cookie, elem->refcnt, value);
+		ma->refcnt_check_fails++;
+		if (elem->refcnt > 0)
+			elem->refcnt += value;
+		memarea_unlock(ma);
+		return;
+	}
+
+	elem->refcnt += value;
+	if (elem->refcnt == 0)
+		memarea_free_elem(ma, elem);
+	memarea_unlock(ma);
+}
diff --git a/lib/memarea/rte_memarea.h b/lib/memarea/rte_memarea.h
index 543cda4cac..10e0d6ad5a 100644
--- a/lib/memarea/rte_memarea.h
+++ b/lib/memarea/rte_memarea.h
@@ -138,6 +138,62 @@ 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.
+ * @param cookie
+ *   User-provided footprint which could used to debug memory leak.
+ *
+ * @return
+ *   Non-NULL on success. Otherwise NULL is returned.
+ */
+__rte_experimental
+void *rte_memarea_alloc(struct rte_memarea *ma, size_t size, uint32_t cookie);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Free memory to memarea.
+ *
+ * Free one memory object to the memarea.
+ *
+ * @param ma
+ *   The pointer of memarea.
+ * @param ptr
+ *   The pointer of memory object which need be freed.
+ */
+__rte_experimental
+void rte_memarea_free(struct rte_memarea *ma, void *ptr);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Update memory's refcnt.
+ *
+ * Update one memory object's refcnt.
+ * When refcnt is updated to be zero, the memory object is freed.
+ *
+ * @param ma
+ *   The pointer of memarea.
+ * @param ptr
+ *   The pointer of memory object which need be updated refcnt.
+ * @param value
+ *   The value which need be updated.
+ */
+__rte_experimental
+void rte_memarea_update_refcnt(struct rte_memarea *ma, void *ptr, int16_t value);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/memarea/version.map b/lib/memarea/version.map
index f36a04d7cf..a0026fc5f9 100644
--- a/lib/memarea/version.map
+++ b/lib/memarea/version.map
@@ -1,8 +1,11 @@
 EXPERIMENTAL {
 	global:
 
+	rte_memarea_alloc;
 	rte_memarea_create;
 	rte_memarea_destroy;
+	rte_memarea_free;
+	rte_memarea_update_refcnt;
 
 	local: *;
 };
-- 
2.34.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v4 04/10] test/memarea: support alloc/free/update-refcnt test
       [not found] ` <20221005033848.2241-1-datshan@qq.com>
                     ` (2 preceding siblings ...)
  2022-10-05  3:38   ` [PATCH v4 03/10] memarea: support alloc/free/update-refcnt API datshan
@ 2022-10-05  3:38   ` datshan
  2022-10-05  3:38   ` [PATCH v4 05/10] memarea: support dump API datshan
                     ` (5 subsequent siblings)
  9 siblings, 0 replies; 222+ messages in thread
From: datshan @ 2022-10-05  3:38 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk
  Cc: thomas, dev, Chengwen Feng

From: Chengwen Feng <fengchengwen@huawei.com>

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

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 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)
+{
+#define ALLOC_MAX_NUM	8
+	struct rte_memarea_param init;
+	struct rte_memarea *ma;
+	void *ptr[ALLOC_MAX_NUM];
+	int i;
+
+	/* 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");
+	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, 0);
+
+	/* 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, ptr[6]);
+
+	rte_memarea_destroy(ma);
+
 	return 0;
 }
 
@@ -141,6 +286,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 0;
 }
 
-- 
2.34.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v4 05/10] memarea: support dump API
       [not found] ` <20221005033848.2241-1-datshan@qq.com>
                     ` (3 preceding siblings ...)
  2022-10-05  3:38   ` [PATCH v4 04/10] test/memarea: support alloc/free/update-refcnt test datshan
@ 2022-10-05  3:38   ` datshan
  2022-10-05  3:38   ` [PATCH v4 06/10] test/memarea: support dump test datshan
                     ` (4 subsequent siblings)
  9 siblings, 0 replies; 222+ messages in thread
From: datshan @ 2022-10-05  3:38 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk
  Cc: thomas, dev, Chengwen Feng

From: Chengwen Feng <fengchengwen@huawei.com>

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

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 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 <inttypes.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/queue.h>
@@ -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/version.map
@@ -4,6 +4,7 @@ EXPERIMENTAL {
 	rte_memarea_alloc;
 	rte_memarea_create;
 	rte_memarea_destroy;
+	rte_memarea_dump;
 	rte_memarea_free;
 	rte_memarea_update_refcnt;
 
-- 
2.34.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v4 06/10] test/memarea: support dump test
       [not found] ` <20221005033848.2241-1-datshan@qq.com>
                     ` (4 preceding siblings ...)
  2022-10-05  3:38   ` [PATCH v4 05/10] memarea: support dump API datshan
@ 2022-10-05  3:38   ` datshan
  2022-10-05  3:38   ` [PATCH v4 07/10] memarea: support backup memory mechanism datshan
                     ` (3 subsequent siblings)
  9 siblings, 0 replies; 222+ messages in thread
From: datshan @ 2022-10-05  3:38 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk
  Cc: thomas, dev, Chengwen Feng

From: Chengwen Feng <fengchengwen@huawei.com>

This patch supports rte_memarea_dump() test.

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 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


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v4 07/10] memarea: support backup memory mechanism
       [not found] ` <20221005033848.2241-1-datshan@qq.com>
                     ` (5 preceding siblings ...)
  2022-10-05  3:38   ` [PATCH v4 06/10] test/memarea: support dump test datshan
@ 2022-10-05  3:38   ` datshan
  2022-10-05  3:38   ` [PATCH v4 08/10] test/memarea: support backup memory test datshan
                     ` (2 subsequent siblings)
  9 siblings, 0 replies; 222+ messages in thread
From: datshan @ 2022-10-05  3:38 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk
  Cc: thomas, dev, Chengwen Feng

From: Chengwen Feng <fengchengwen@huawei.com>

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

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 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 object from backup memarea when
+ *   the current memarea failed to allocate.
  */
 
 #include <stdbool.h>
@@ -105,6 +108,10 @@ struct rte_memarea_param {
 		 */
 		struct rte_memarea *user_memarea;
 	};
+	/** Backup memarea, which is used to handle the scenario where the
+	 * current memarea allocation failure.
+	 */
+	struct rte_memarea *bak_memarea;
 };
 
 /**
-- 
2.34.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v4 08/10] test/memarea: support backup memory test
       [not found] ` <20221005033848.2241-1-datshan@qq.com>
                     ` (6 preceding siblings ...)
  2022-10-05  3:38   ` [PATCH v4 07/10] memarea: support backup memory mechanism datshan
@ 2022-10-05  3:38   ` datshan
  2022-10-05  3:38   ` [PATCH v4 09/10] memarea: detect memory corruption based on magic datshan
  2022-10-05  3:38   ` [PATCH v4 10/10] test/memarea: support no MT-safe test datshan
  9 siblings, 0 replies; 222+ messages in thread
From: datshan @ 2022-10-05  3:38 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk
  Cc: thomas, dev, Chengwen Feng

From: Chengwen Feng <fengchengwen@huawei.com>

This patch supports backup memory mechanism test.

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 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



^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v4 09/10] memarea: detect memory corruption based on magic
       [not found] ` <20221005033848.2241-1-datshan@qq.com>
                     ` (7 preceding siblings ...)
  2022-10-05  3:38   ` [PATCH v4 08/10] test/memarea: support backup memory test datshan
@ 2022-10-05  3:38   ` datshan
  2022-10-05  3:38   ` [PATCH v4 10/10] test/memarea: support no MT-safe test datshan
  9 siblings, 0 replies; 222+ messages in thread
From: datshan @ 2022-10-05  3:38 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk
  Cc: thomas, dev, Chengwen Feng

From: Chengwen Feng <fengchengwen@huawei.com>

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

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 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 <rte_memarea.h>
 
+#define MEMAREA_ELEM_MAGIC_NUM		0xbeef1234
 #define MEMAREA_FREE_ELEM_COOKIE	0xFFFFFFFF
 
 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


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v4 10/10] test/memarea: support no MT-safe test
       [not found] ` <20221005033848.2241-1-datshan@qq.com>
                     ` (8 preceding siblings ...)
  2022-10-05  3:38   ` [PATCH v4 09/10] memarea: detect memory corruption based on magic datshan
@ 2022-10-05  3:38   ` datshan
  9 siblings, 0 replies; 222+ messages in thread
From: datshan @ 2022-10-05  3:38 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk
  Cc: thomas, dev, Chengwen Feng

From: Chengwen Feng <fengchengwen@huawei.com>

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

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 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


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v5 00/10] introduce memarea library
  2022-07-21  4:46 [RFC] memarea: introduce memory area library Chengwen Feng
                   ` (7 preceding siblings ...)
       [not found] ` <20221005033848.2241-1-datshan@qq.com>
@ 2022-10-05  4:09 ` datshan
       [not found] ` <20221005040952.8166-1-datshan@qq.com>
                   ` (14 subsequent siblings)
  23 siblings, 0 replies; 222+ messages in thread
From: datshan @ 2022-10-05  4:09 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk
  Cc: thomas, dev, datshan, Chengwen Feng

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 <fengchengwen@huawei.com>

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


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v5 01/10] memarea: introduce memarea library
       [not found] ` <20221005040952.8166-1-datshan@qq.com>
@ 2022-10-05  4:09   ` datshan
  2022-10-06 20:15     ` Mattias Rönnblom
  2022-10-05  4:09   ` [PATCH v5 02/10] test/memarea: support memarea test datshan
                     ` (8 subsequent siblings)
  9 siblings, 1 reply; 222+ messages in thread
From: datshan @ 2022-10-05  4:09 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk
  Cc: thomas, dev, Chengwen Feng

From: Chengwen Feng <fengchengwen@huawei.com>

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 <fengchengwen@huawei.com>
---
 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 <fengchengwen@huawei.com>
+F: lib/memarea
+F: doc/guides/prog_guide/memarea_lib.rst
+
 Membership - EXPERIMENTAL
 M: Yipeng Wang <yipeng1.wang@intel.com>
 M: Sameh Gobriel <sameh.gobriel@intel.com>
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..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 library is an allocator of variable-size objects, it is oriented
+  towards the application layer, which could provides 'region-based memory
+  management' function.
+
 * **Added configuration for asynchronous flow connection tracking.**
 
   Added connection tracking action number hint to ``rte_flow_configure``
diff --git a/lib/eal/common/eal_common_log.c b/lib/eal/common/eal_common_log.c
index bd7b188ceb..3d62af59c6 100644
--- a/lib/eal/common/eal_common_log.c
+++ b/lib/eal/common/eal_common_log.c
@@ -369,6 +369,7 @@ static const struct logtype logtype_strings[] = {
 	{RTE_LOGTYPE_EFD,        "lib.efd"},
 	{RTE_LOGTYPE_EVENTDEV,   "lib.eventdev"},
 	{RTE_LOGTYPE_GSO,        "lib.gso"},
+	{RTE_LOGTYPE_MEMAREA,    "lib.memarea"},
 	{RTE_LOGTYPE_USER1,      "user1"},
 	{RTE_LOGTYPE_USER2,      "user2"},
 	{RTE_LOGTYPE_USER3,      "user3"},
diff --git a/lib/eal/include/rte_log.h b/lib/eal/include/rte_log.h
index 25ce42cdfc..708f3a39dd 100644
--- a/lib/eal/include/rte_log.h
+++ b/lib/eal/include/rte_log.h
@@ -48,6 +48,7 @@ extern "C" {
 #define RTE_LOGTYPE_EFD       18 /**< Log related to EFD. */
 #define RTE_LOGTYPE_EVENTDEV  19 /**< Log related to eventdev. */
 #define RTE_LOGTYPE_GSO       20 /**< Log related to GSO. */
+#define RTE_LOGTYPE_MEMAREA   21 /**< Log related to memarea. */
 
 /* these log types can be used in an application */
 #define RTE_LOGTYPE_USER1     24 /**< User-defined log type 1. */
diff --git a/lib/memarea/memarea_private.h b/lib/memarea/memarea_private.h
new file mode 100644
index 0000000000..c76392d3e6
--- /dev/null
+++ b/lib/memarea/memarea_private.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2022 HiSilicon Limited
+ */
+
+#ifndef MEMAREA_PRIVATE_H
+#define MEMAREA_PRIVATE_H
+
+#include <rte_memarea.h>
+
+#define MEMAREA_FREE_ELEM_COOKIE	0xFFFFFFFF
+
+struct memarea_elem {
+	size_t   size;
+	uint32_t cookie;
+	int32_t  refcnt; /* Non-zero indicates that it has been allocated */
+	TAILQ_ENTRY(memarea_elem) elem_node;
+	TAILQ_ENTRY(memarea_elem) free_node;
+} __rte_cache_aligned;
+
+TAILQ_HEAD(memarea_elem_list, memarea_elem);
+
+struct rte_memarea {
+	struct rte_memarea_param init;
+	rte_spinlock_t           lock;
+	void                    *area_addr;
+	struct memarea_elem_list elem_list;
+	struct memarea_elem_list free_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..0a74fb4cd1
--- /dev/null
+++ b/lib/memarea/meson.build
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2022 HiSilicon Limited
+
+if is_windows
+    build = false
+    reason = 'not supported on Windows'
+    subdir_done()
+endif
+
+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..868da7661d
--- /dev/null
+++ b/lib/memarea/rte_memarea.c
@@ -0,0 +1,157 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2022 HiSilicon Limited
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <rte_common.h>
+#include <rte_log.h>
+#include <rte_malloc.h>
+#include <rte_spinlock.h>
+
+#include "rte_memarea.h"
+#include "memarea_private.h"
+
+static int
+memarea_check_param(const struct rte_memarea_param *init)
+{
+	size_t len;
+
+	if (init == NULL) {
+		RTE_LOG(ERR, MEMAREA, "memarea init param is NULL!\n");
+		return -EINVAL;
+	}
+
+	len = strnlen(init->name, RTE_MEMAREA_NAMESIZE);
+	if (len == 0 || len >= RTE_MEMAREA_NAMESIZE) {
+		RTE_LOG(ERR, MEMAREA, "memarea name size %zu invalid!\n", len);
+		return -EINVAL;
+	}
+
+	if (init->source != RTE_MEMAREA_SOURCE_RTE_MEMORY &&
+	    init->source != RTE_MEMAREA_SOURCE_SYSTEM_API &&
+	    init->source != RTE_MEMAREA_SOURCE_USER_ADDR &&
+	    init->source != RTE_MEMAREA_SOURCE_USER_MEMAREA) {
+		RTE_LOG(ERR, MEMAREA, "memarea: %s source: %d not supported!\n",
+			init->name, init->source);
+		return -EINVAL;
+	}
+
+	if (init->total_sz <= sizeof(struct memarea_elem)) {
+		RTE_LOG(ERR, MEMAREA, "memarea: %s total-size: %zu too small!\n",
+			init->name, init->total_sz);
+		return -EINVAL;
+	}
+
+	if (init->source == RTE_MEMAREA_SOURCE_USER_ADDR && init->user_addr == NULL) {
+		RTE_LOG(ERR, MEMAREA, "memarea: %s user provided addr is NULL!\n", init->name);
+		return -EINVAL;
+	}
+
+	if (init->source == RTE_MEMAREA_SOURCE_USER_ADDR &&
+	    ((uintptr_t)init->user_addr & (RTE_CACHE_LINE_SIZE - 1))) {
+		RTE_LOG(ERR, MEMAREA, "memarea: %s user provided addr should align: %d!\n",
+			init->name, RTE_CACHE_LINE_SIZE);
+		return -EINVAL;
+	}
+
+	if (init->source == RTE_MEMAREA_SOURCE_USER_MEMAREA && init->user_memarea == NULL) {
+		RTE_LOG(ERR, MEMAREA, "memarea: %s user provided memarea is NULL!\n", init->name);
+		return -EINVAL;
+	}
+
+	if (init->alg != RTE_MEMAREA_ALG_DEFAULT) {
+		RTE_LOG(ERR, MEMAREA, "memarea: %s alg: %d not supported!\n",
+			init->name, init->alg);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void *
+memarea_alloc_from_system_api(size_t size)
+{
+	void *ptr = NULL;
+	int ret;
+
+	ret = posix_memalign(&ptr, RTE_CACHE_LINE_SIZE, size);
+	if (ret)
+		return NULL;
+	return ptr;
+}
+
+static void *
+memarea_alloc_area(const struct rte_memarea_param *init)
+{
+	void *ptr = NULL;
+
+	if (init->source == RTE_MEMAREA_SOURCE_RTE_MEMORY)
+		ptr = rte_malloc_socket(NULL, init->total_sz, RTE_CACHE_LINE_SIZE,
+					init->numa_socket);
+	else if (init->source == RTE_MEMAREA_SOURCE_SYSTEM_API)
+		ptr = memarea_alloc_from_system_api(init->total_sz);
+	else if (init->source == RTE_MEMAREA_SOURCE_USER_ADDR)
+		ptr = init->user_addr;
+
+	if (ptr == NULL)
+		RTE_LOG(ERR, MEMAREA, "memarea: %s alloc memory area fail!\n", init->name);
+
+	return ptr;
+}
+
+struct rte_memarea *
+rte_memarea_create(const struct rte_memarea_param *init)
+{
+	struct memarea_elem *elem;
+	struct rte_memarea *ma;
+	void *addr;
+	int ret;
+
+	ret = memarea_check_param(init);
+	if (ret)
+		return NULL;
+
+	addr = memarea_alloc_area(init);
+	if (addr == NULL)
+		return NULL;
+
+	ma = rte_zmalloc(NULL, sizeof(struct rte_memarea), RTE_CACHE_LINE_SIZE);
+	if (ma == NULL) {
+		RTE_LOG(ERR, MEMAREA, "malloc memarea: %s management obj fail!\n", init->name);
+		return NULL;
+	}
+
+	ma->init = *init;
+	rte_spinlock_init(&ma->lock);
+	TAILQ_INIT(&ma->elem_list);
+	TAILQ_INIT(&ma->free_list);
+	ma->area_addr = addr;
+	elem = addr;
+	elem->size = init->total_sz - sizeof(struct memarea_elem);
+	elem->cookie = MEMAREA_FREE_ELEM_COOKIE;
+	elem->refcnt = 0;
+	TAILQ_INSERT_TAIL(&ma->elem_list, elem, elem_node);
+	TAILQ_INSERT_TAIL(&ma->free_list, elem, free_node);
+
+	return ma;
+}
+
+static void
+memarea_free_area(struct rte_memarea *ma)
+{
+	if (ma->init.source == RTE_MEMAREA_SOURCE_RTE_MEMORY)
+		rte_free(ma->area_addr);
+	else if (ma->init.source == RTE_MEMAREA_SOURCE_SYSTEM_API)
+		free(ma->area_addr);
+}
+
+void
+rte_memarea_destroy(struct rte_memarea *ma)
+{
+	if (ma == NULL)
+		return;
+	memarea_free_area(ma);
+	rte_free(ma);
+}
diff --git a/lib/memarea/rte_memarea.h b/lib/memarea/rte_memarea.h
new file mode 100644
index 0000000000..543cda4cac
--- /dev/null
+++ b/lib/memarea/rte_memarea.h
@@ -0,0 +1,145 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2022 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 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. So we can build
+ *      the following memory management structure:
+ *         \code{.unparsed}
+ *                           -------------
+ *                           | memarea-1 |
+ *                           -------------
+ *                                 |
+ *                                 v
+ *                  -------------------------------
+ *                  |               |             |
+ *                  v               v             v
+ *            -------------   -------------   ----------
+ *            | memarea-2 |   | memarea-3 |   | object |
+ *            -------------   -------------   ----------
+ *         \endcode
+ *      As shown above, the memarea-2/3 both create from memarea-1's memory.
+ * - 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. 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 <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include <rte_compat.h>
+
+#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_RTE_MEMORY,
+	/** Memory source comes from system API. */
+	RTE_MEMAREA_SOURCE_SYSTEM_API,
+	/** Memory source comes from user-provided address. */
+	RTE_MEMAREA_SOURCE_USER_ADDR,
+	/** Memory source comes from user-provided memarea. */
+	RTE_MEMAREA_SOURCE_USER_MEMAREA,
+};
+
+/**
+ * Memarea memory management algorithm.
+ */
+enum rte_memarea_alg {
+	/* The default management algorithm is a variant of the next fit
+	 * algorithm. It uses a free-list to apply for memory and uses an
+	 * element-list in ascending order of address to support merging
+	 * upon free.
+	 */
+	RTE_MEMAREA_ALG_DEFAULT,
+};
+
+struct rte_memarea;
+
+struct rte_memarea_param {
+	char name[RTE_MEMAREA_NAMESIZE]; /**< Name of memarea. */
+	enum rte_memarea_source source;  /**< Memory source of memarea. */
+	enum rte_memarea_alg 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_RTE_MEMORY.
+		 */
+		int numa_socket;
+		/** User provided address, this field is valid only when the
+		 * source is set to be RTE_MEMAREA_SOURCE_USER_ADDR.
+		 * Note: the provided address must align at least
+		 * RTE_CACHE_LINE_SIZE.
+		 */
+		void *user_addr;
+		/** User provided memarea, this field is valid only when the
+		 * source is set to be RTE_MEMAREA_SOURCE_USER_MEMAREA.
+		 */
+		struct rte_memarea *user_memarea;
+	};
+};
+
+/**
+ * @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 c648f7d800..521a25d6c0 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -42,6 +42,7 @@ libraries = [
         'kni',
         'latencystats',
         'lpm',
+        'memarea',
         'member',
         'pcapng',
         'power',
-- 
2.34.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v5 02/10] test/memarea: support memarea test
       [not found] ` <20221005040952.8166-1-datshan@qq.com>
  2022-10-05  4:09   ` [PATCH v5 01/10] memarea: " datshan
@ 2022-10-05  4:09   ` datshan
  2022-10-05  4:09   ` [PATCH v5 03/10] memarea: support alloc/free/update-refcnt API datshan
                     ` (7 subsequent siblings)
  9 siblings, 0 replies; 222+ messages in thread
From: datshan @ 2022-10-05  4:09 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk
  Cc: thomas, dev, Chengwen Feng

From: Chengwen Feng <fengchengwen@huawei.com>

This patch supports memarea test about API rte_memarea_create and
rte_memarea_destroy.

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 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 <fengchengwen@huawei.com>
 F: lib/memarea
 F: doc/guides/prog_guide/memarea_lib.rst
+F: app/test/test_memarea*
 
 Membership - EXPERIMENTAL
 M: Yipeng Wang <yipeng1.wang@intel.com>
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 0000000000..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 <stdio.h>
+#include <string.h>
+
+#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 <rte_memory.h>
+#include <rte_memarea.h>
+
+#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_SOURCE_RTE_MEMORY;
+	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 system API */
+	test_memarea_init_def_param(&init);
+	init.source = RTE_MEMAREA_SOURCE_SYSTEM_API;
+	ma = rte_memarea_create(&init);
+	RTE_TEST_ASSERT(ma != NULL, "Expected Non-NULL");
+	rte_memarea_destroy(ma);
+
+	/* test for create with user-address */
+	test_memarea_init_def_param(&init);
+	init.source = RTE_MEMAREA_SOURCE_USER_ADDR;
+	init.user_addr = (void *)(((uintptr_t)user_buffer + RTE_CACHE_LINE_SIZE) &
+				  ~(RTE_CACHE_LINE_SIZE - 1));
+	ma = rte_memarea_create(&init);
+	RTE_TEST_ASSERT(ma != NULL, "Expected Non-NULL");
+	rte_memarea_destroy(ma);
+
+	return 0;
+}
+
+static int
+test_memarea(void)
+{
+	MEMAREA_TEST_API_RUN(test_memarea_create_bad_param);
+	MEMAREA_TEST_API_RUN(test_memarea_create_destroy);
+	return 0;
+}
+
+#endif /* !RTE_EXEC_ENV_WINDOWS */
+
+REGISTER_TEST_COMMAND(memarea_autotest, test_memarea);
-- 
2.34.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v5 03/10] memarea: support alloc/free/update-refcnt API
       [not found] ` <20221005040952.8166-1-datshan@qq.com>
  2022-10-05  4:09   ` [PATCH v5 01/10] memarea: " datshan
  2022-10-05  4:09   ` [PATCH v5 02/10] test/memarea: support memarea test datshan
@ 2022-10-05  4:09   ` datshan
  2022-10-06 19:43     ` Mattias Rönnblom
  2022-10-05  4:09   ` [PATCH v5 04/10] test/memarea: support alloc/free/update-refcnt test datshan
                     ` (6 subsequent siblings)
  9 siblings, 1 reply; 222+ messages in thread
From: datshan @ 2022-10-05  4:09 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk
  Cc: thomas, dev, Chengwen Feng

From: Chengwen Feng <fengchengwen@huawei.com>

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

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 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 <stdio.h>
 #include <stdlib.h>
+#include <sys/queue.h>
 
 #include <rte_common.h>
 #include <rte_log.h>
@@ -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 = (void *)((uintptr_t)elem + sizeof(struct memarea_elem));
+		break;
+	}
+	if (unlikely(ptr == NULL))
+		ma->alloc_fails++;
+	memarea_unlock(ma);
+
+	return ptr;
+}
+
+void
+rte_memarea_free(struct rte_memarea *ma, void *ptr)
+{
+	rte_memarea_update_refcnt(ma, ptr, -1);
+}
+
+static inline void
+memarea_merge_node(struct rte_memarea *ma, struct memarea_elem *curr,
+		   struct memarea_elem *next, bool del_next_from_free,
+		   bool add_curr_to_free)
+{
+	curr->size += next->size + sizeof(struct memarea_elem);
+	next->size = 0;
+	next->cookie = 0;
+	TAILQ_REMOVE(&ma->elem_list, next, elem_node);
+	if (del_next_from_free)
+		TAILQ_REMOVE(&ma->free_list, next, free_node);
+	if (add_curr_to_free) {
+		curr->cookie = MEMAREA_FREE_ELEM_COOKIE;
+		TAILQ_INSERT_TAIL(&ma->free_list, curr, free_node);
+	}
+}
+
+static inline void
+memarea_free_elem(struct rte_memarea *ma, struct memarea_elem *elem)
+{
+	struct memarea_elem *prev, *next;
+	bool merged = false;
+	prev = TAILQ_PREV(elem, memarea_elem_list, elem_node);
+	next = TAILQ_NEXT(elem, elem_node);
+	if (prev != NULL && prev->refcnt == 0) {
+		memarea_merge_node(ma, prev, elem, false, false);
+		elem = prev;
+		merged = true;
+	}
+	if (next != NULL && next->refcnt == 0) {
+		memarea_merge_node(ma, elem, next, true, !merged);
+		merged = true;
+	}
+	if (!merged) {
+		elem->cookie = MEMAREA_FREE_ELEM_COOKIE;
+		TAILQ_INSERT_TAIL(&ma->free_list, elem, free_node);
+	}
+}
+
+void
+rte_memarea_update_refcnt(struct rte_memarea *ma, void *ptr, int16_t value)
+{
+	struct memarea_elem *elem = (struct memarea_elem *)((uintptr_t)ptr -
+							    sizeof(struct memarea_elem));
+
+	if (unlikely(ma == NULL || ptr == NULL))
+		return;
+
+	memarea_lock(ma);
+	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",
+			ma->init.name, elem->cookie, elem->refcnt, value);
+		ma->refcnt_check_fails++;
+		if (elem->refcnt > 0)
+			elem->refcnt += value;
+		memarea_unlock(ma);
+		return;
+	}
+
+	elem->refcnt += value;
+	if (elem->refcnt == 0)
+		memarea_free_elem(ma, elem);
+	memarea_unlock(ma);
+}
diff --git a/lib/memarea/rte_memarea.h b/lib/memarea/rte_memarea.h
index 543cda4cac..10e0d6ad5a 100644
--- a/lib/memarea/rte_memarea.h
+++ b/lib/memarea/rte_memarea.h
@@ -138,6 +138,62 @@ 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.
+ * @param cookie
+ *   User-provided footprint which could used to debug memory leak.
+ *
+ * @return
+ *   Non-NULL on success. Otherwise NULL is returned.
+ */
+__rte_experimental
+void *rte_memarea_alloc(struct rte_memarea *ma, size_t size, uint32_t cookie);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Free memory to memarea.
+ *
+ * Free one memory object to the memarea.
+ *
+ * @param ma
+ *   The pointer of memarea.
+ * @param ptr
+ *   The pointer of memory object which need be freed.
+ */
+__rte_experimental
+void rte_memarea_free(struct rte_memarea *ma, void *ptr);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Update memory's refcnt.
+ *
+ * Update one memory object's refcnt.
+ * When refcnt is updated to be zero, the memory object is freed.
+ *
+ * @param ma
+ *   The pointer of memarea.
+ * @param ptr
+ *   The pointer of memory object which need be updated refcnt.
+ * @param value
+ *   The value which need be updated.
+ */
+__rte_experimental
+void rte_memarea_update_refcnt(struct rte_memarea *ma, void *ptr, int16_t value);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/memarea/version.map b/lib/memarea/version.map
index f36a04d7cf..a0026fc5f9 100644
--- a/lib/memarea/version.map
+++ b/lib/memarea/version.map
@@ -1,8 +1,11 @@
 EXPERIMENTAL {
 	global:
 
+	rte_memarea_alloc;
 	rte_memarea_create;
 	rte_memarea_destroy;
+	rte_memarea_free;
+	rte_memarea_update_refcnt;
 
 	local: *;
 };
-- 
2.34.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v5 04/10] test/memarea: support alloc/free/update-refcnt test
       [not found] ` <20221005040952.8166-1-datshan@qq.com>
                     ` (2 preceding siblings ...)
  2022-10-05  4:09   ` [PATCH v5 03/10] memarea: support alloc/free/update-refcnt API datshan
@ 2022-10-05  4:09   ` datshan
  2022-10-05  4:09   ` [PATCH v5 05/10] memarea: support dump API datshan
                     ` (5 subsequent siblings)
  9 siblings, 0 replies; 222+ messages in thread
From: datshan @ 2022-10-05  4:09 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk
  Cc: thomas, dev, Chengwen Feng

From: Chengwen Feng <fengchengwen@huawei.com>

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

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 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)
+{
+#define ALLOC_MAX_NUM	8
+	struct rte_memarea_param init;
+	struct rte_memarea *ma;
+	void *ptr[ALLOC_MAX_NUM];
+	int i;
+
+	/* 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");
+	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, 0);
+
+	/* 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, ptr[6]);
+
+	rte_memarea_destroy(ma);
+
 	return 0;
 }
 
@@ -141,6 +286,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 0;
 }
 
-- 
2.34.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v5 05/10] memarea: support dump API
       [not found] ` <20221005040952.8166-1-datshan@qq.com>
                     ` (3 preceding siblings ...)
  2022-10-05  4:09   ` [PATCH v5 04/10] test/memarea: support alloc/free/update-refcnt test datshan
@ 2022-10-05  4:09   ` datshan
  2022-10-05  4:09   ` [PATCH v5 06/10] test/memarea: support dump test datshan
                     ` (4 subsequent siblings)
  9 siblings, 0 replies; 222+ messages in thread
From: datshan @ 2022-10-05  4:09 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk
  Cc: thomas, dev, Chengwen Feng

From: Chengwen Feng <fengchengwen@huawei.com>

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

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 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 <inttypes.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/queue.h>
@@ -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/version.map
@@ -4,6 +4,7 @@ EXPERIMENTAL {
 	rte_memarea_alloc;
 	rte_memarea_create;
 	rte_memarea_destroy;
+	rte_memarea_dump;
 	rte_memarea_free;
 	rte_memarea_update_refcnt;
 
-- 
2.34.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v5 06/10] test/memarea: support dump test
       [not found] ` <20221005040952.8166-1-datshan@qq.com>
                     ` (4 preceding siblings ...)
  2022-10-05  4:09   ` [PATCH v5 05/10] memarea: support dump API datshan
@ 2022-10-05  4:09   ` datshan
  2022-10-05  4:09   ` [PATCH v5 07/10] memarea: support backup memory mechanism datshan
                     ` (3 subsequent siblings)
  9 siblings, 0 replies; 222+ messages in thread
From: datshan @ 2022-10-05  4:09 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk
  Cc: thomas, dev, Chengwen Feng

From: Chengwen Feng <fengchengwen@huawei.com>

This patch supports rte_memarea_dump() test.

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 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


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v5 07/10] memarea: support backup memory mechanism
       [not found] ` <20221005040952.8166-1-datshan@qq.com>
                     ` (5 preceding siblings ...)
  2022-10-05  4:09   ` [PATCH v5 06/10] test/memarea: support dump test datshan
@ 2022-10-05  4:09   ` datshan
  2022-10-06 19:53     ` Mattias Rönnblom
  2022-10-05  4:09   ` [PATCH v5 08/10] test/memarea: support backup memory test datshan
                     ` (2 subsequent siblings)
  9 siblings, 1 reply; 222+ messages in thread
From: datshan @ 2022-10-05  4:09 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk
  Cc: thomas, dev, Chengwen Feng

From: Chengwen Feng <fengchengwen@huawei.com>

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

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 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 object from backup memarea when
+ *   the current memarea failed to allocate.
  */
 
 #include <stdbool.h>
@@ -105,6 +108,10 @@ struct rte_memarea_param {
 		 */
 		struct rte_memarea *user_memarea;
 	};
+	/** Backup memarea, which is used to handle the scenario where the
+	 * current memarea allocation failure.
+	 */
+	struct rte_memarea *bak_memarea;
 };
 
 /**
-- 
2.34.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v5 08/10] test/memarea: support backup memory test
       [not found] ` <20221005040952.8166-1-datshan@qq.com>
                     ` (6 preceding siblings ...)
  2022-10-05  4:09   ` [PATCH v5 07/10] memarea: support backup memory mechanism datshan
@ 2022-10-05  4:09   ` datshan
  2022-10-05  4:09   ` [PATCH v5 09/10] memarea: detect memory corruption based on magic datshan
  2022-10-05  4:09   ` [PATCH v5 10/10] test/memarea: support no MT-safe test datshan
  9 siblings, 0 replies; 222+ messages in thread
From: datshan @ 2022-10-05  4:09 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk
  Cc: thomas, dev, Chengwen Feng

From: Chengwen Feng <fengchengwen@huawei.com>

This patch supports backup memory mechanism test.

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 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



^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v5 09/10] memarea: detect memory corruption based on magic
       [not found] ` <20221005040952.8166-1-datshan@qq.com>
                     ` (7 preceding siblings ...)
  2022-10-05  4:09   ` [PATCH v5 08/10] test/memarea: support backup memory test datshan
@ 2022-10-05  4:09   ` datshan
  2022-10-05  4:09   ` [PATCH v5 10/10] test/memarea: support no MT-safe test datshan
  9 siblings, 0 replies; 222+ messages in thread
From: datshan @ 2022-10-05  4:09 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk
  Cc: thomas, dev, Chengwen Feng

From: Chengwen Feng <fengchengwen@huawei.com>

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

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 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 <rte_memarea.h>
 
+#define MEMAREA_ELEM_MAGIC_NUM		0xbeef1234
 #define MEMAREA_FREE_ELEM_COOKIE	0xFFFFFFFF
 
 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


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v5 10/10] test/memarea: support no MT-safe test
       [not found] ` <20221005040952.8166-1-datshan@qq.com>
                     ` (8 preceding siblings ...)
  2022-10-05  4:09   ` [PATCH v5 09/10] memarea: detect memory corruption based on magic datshan
@ 2022-10-05  4:09   ` datshan
  9 siblings, 0 replies; 222+ messages in thread
From: datshan @ 2022-10-05  4:09 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk
  Cc: thomas, dev, Chengwen Feng

From: Chengwen Feng <fengchengwen@huawei.com>

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

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 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


^ permalink raw reply	[flat|nested] 222+ messages in thread

* Re: [PATCH v3 00/10] introduce memarea library
  2022-10-03  7:42   ` [PATCH v3 00/10] introduce memarea library David Marchand
@ 2022-10-05  4:19     ` datshan
  0 siblings, 0 replies; 222+ messages in thread
From: datshan @ 2022-10-05  4:19 UTC (permalink / raw)
  To: David Marchand, Chengwen Feng, Morten Brørup, Burakov,
	Anatoly, dmitry.kozliuk, stephen
  Cc: thomas, dev, jerinjacobk

Hi David,

   The v5 (send by datshan@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 <fengchengwen@huawei.com> 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 <fengchengwen@huawei.com>
> 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.
>

^ permalink raw reply	[flat|nested] 222+ messages in thread

* Re: [PATCH v5 03/10] memarea: support alloc/free/update-refcnt API
  2022-10-05  4:09   ` [PATCH v5 03/10] memarea: support alloc/free/update-refcnt API datshan
@ 2022-10-06 19:43     ` Mattias Rönnblom
  2022-10-08  8:02       ` fengchengwen
  0 siblings, 1 reply; 222+ messages in thread
From: Mattias Rönnblom @ 2022-10-06 19:43 UTC (permalink / raw)
  To: datshan, david.marchand, mb, anatoly.burakov, dmitry.kozliuk,
	jerinjacobk
  Cc: thomas, dev, Chengwen Feng

On 2022-10-05 06:09, datshan wrote:
> From: Chengwen Feng <fengchengwen@huawei.com>
> 
> This patch supports rte_memarea_alloc()/rte_memarea_free()/
> rte_memarea_update_refcnt() API.
> 
> Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
> ---
>   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 <stdio.h>
>   #include <stdlib.h>
> +#include <sys/queue.h>
>   
>   #include <rte_common.h>
>   #include <rte_log.h>
> @@ -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))
> +

You should be able to use RTE_ALIGN_CEIL() instead of your own roundup 
macro, assuming this function isn't used in a patch I'm yet to review, 
with a potentially non-power-of-2 align parameter value.

If not, change the macro to a function.

> +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);

Use RTE_PTR_ADD().

> +	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 = (void *)((uintptr_t)elem + sizeof(struct memarea_elem));

RTE_PTR_ADD() again.

> +		break;
> +	}
> +	if (unlikely(ptr == NULL))
> +		ma->alloc_fails++;
> +	memarea_unlock(ma);
> +
> +	return ptr;
> +}
> +
> +void
> +rte_memarea_free(struct rte_memarea *ma, void *ptr)
> +{
> +	rte_memarea_update_refcnt(ma, ptr, -1);
> +}
> +
> +static inline void
> +memarea_merge_node(struct rte_memarea *ma, struct memarea_elem *curr,
> +		   struct memarea_elem *next, bool del_next_from_free,
> +		   bool add_curr_to_free)
> +{
> +	curr->size += next->size + sizeof(struct memarea_elem);
> +	next->size = 0;
> +	next->cookie = 0;
> +	TAILQ_REMOVE(&ma->elem_list, next, elem_node);
> +	if (del_next_from_free)
> +		TAILQ_REMOVE(&ma->free_list, next, free_node);
> +	if (add_curr_to_free) {
> +		curr->cookie = MEMAREA_FREE_ELEM_COOKIE;
> +		TAILQ_INSERT_TAIL(&ma->free_list, curr, free_node);
> +	}
> +}
> +
> +static inline void
> +memarea_free_elem(struct rte_memarea *ma, struct memarea_elem *elem)
> +{
> +	struct memarea_elem *prev, *next;
> +	bool merged = false;
> +	prev = TAILQ_PREV(elem, memarea_elem_list, elem_node);
> +	next = TAILQ_NEXT(elem, elem_node);
> +	if (prev != NULL && prev->refcnt == 0) {
> +		memarea_merge_node(ma, prev, elem, false, false);
> +		elem = prev;
> +		merged = true;
> +	}
> +	if (next != NULL && next->refcnt == 0) {
> +		memarea_merge_node(ma, elem, next, true, !merged);
> +		merged = true;
> +	}
> +	if (!merged) {
> +		elem->cookie = MEMAREA_FREE_ELEM_COOKIE;
> +		TAILQ_INSERT_TAIL(&ma->free_list, elem, free_node);
> +	}
> +}
> +
> +void
> +rte_memarea_update_refcnt(struct rte_memarea *ma, void *ptr, int16_t value)
> +{
> +	struct memarea_elem *elem = (struct memarea_elem *)((uintptr_t)ptr -
> +							    sizeof(struct memarea_elem));
> +
> +	if (unlikely(ma == NULL || ptr == NULL))
> +		return;
> +
> +	memarea_lock(ma);
> +	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",
> +			ma->init.name, elem->cookie, elem->refcnt, value);
> +		ma->refcnt_check_fails++;
> +		if (elem->refcnt > 0)
> +			elem->refcnt += value;
> +		memarea_unlock(ma);
> +		return;
> +	}
> +
> +	elem->refcnt += value;
> +	if (elem->refcnt == 0)
> +		memarea_free_elem(ma, elem);
> +	memarea_unlock(ma);
> +}
> diff --git a/lib/memarea/rte_memarea.h b/lib/memarea/rte_memarea.h
> index 543cda4cac..10e0d6ad5a 100644
> --- a/lib/memarea/rte_memarea.h
> +++ b/lib/memarea/rte_memarea.h
> @@ -138,6 +138,62 @@ 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.
> + * @param cookie
> + *   User-provided footprint which could used to debug memory leak.
> + *
> + * @return
> + *   Non-NULL on success. Otherwise NULL is returned.
> + */
> +__rte_experimental
> +void *rte_memarea_alloc(struct rte_memarea *ma, size_t size, uint32_t cookie);
> +
> +/**
> + * @warning
> + * @b EXPERIMENTAL: this API may change without prior notice.
> + *
> + * Free memory to memarea.
> + *
> + * Free one memory object to the memarea.
> + *
> + * @param ma
> + *   The pointer of memarea.
> + * @param ptr
> + *   The pointer of memory object which need be freed.
> + */
> +__rte_experimental
> +void rte_memarea_free(struct rte_memarea *ma, void *ptr);
> +
> +/**
> + * @warning
> + * @b EXPERIMENTAL: this API may change without prior notice.
> + *
> + * Update memory's refcnt.
> + *
> + * Update one memory object's refcnt.
> + * When refcnt is updated to be zero, the memory object is freed.
> + *
> + * @param ma
> + *   The pointer of memarea.
> + * @param ptr
> + *   The pointer of memory object which need be updated refcnt.
> + * @param value
> + *   The value which need be updated.
> + */
> +__rte_experimental
> +void rte_memarea_update_refcnt(struct rte_memarea *ma, void *ptr, int16_t value);
> +
>   #ifdef __cplusplus
>   }
>   #endif
> diff --git a/lib/memarea/version.map b/lib/memarea/version.map
> index f36a04d7cf..a0026fc5f9 100644
> --- a/lib/memarea/version.map
> +++ b/lib/memarea/version.map
> @@ -1,8 +1,11 @@
>   EXPERIMENTAL {
>   	global:
>   
> +	rte_memarea_alloc;
>   	rte_memarea_create;
>   	rte_memarea_destroy;
> +	rte_memarea_free;
> +	rte_memarea_update_refcnt;
>   
>   	local: *;
>   };

^ permalink raw reply	[flat|nested] 222+ messages in thread

* Re: [PATCH v5 07/10] memarea: support backup memory mechanism
  2022-10-05  4:09   ` [PATCH v5 07/10] memarea: support backup memory mechanism datshan
@ 2022-10-06 19:53     ` Mattias Rönnblom
  2022-10-08  7:56       ` fengchengwen
  0 siblings, 1 reply; 222+ messages in thread
From: Mattias Rönnblom @ 2022-10-06 19:53 UTC (permalink / raw)
  To: datshan, david.marchand, mb, anatoly.burakov, dmitry.kozliuk,
	jerinjacobk
  Cc: thomas, dev, Chengwen Feng

On 2022-10-05 06:09, datshan wrote:
> From: Chengwen Feng <fengchengwen@huawei.com>
> 
> This patch supports backup memory mechanism, the memarea could use
> another memarea as a backup.

Maybe it's worth mentioning what backup means already here.

"This patch adds a memarea backup mechanism, where an allocation request 
which cannot be met by a certain memarea is deferred to its backup memarea."

I assume they can be nested indefinitely?

> 
> Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
> ---
>   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);

RTE_PTR_ADD()

>   	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)

Maybe you want an unlikely() around the above, too. I assume using the 
backup area is an exceptional case.

> +		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 object from backup memarea when
> + *   the current memarea failed to allocate.
>    */
>   
>   #include <stdbool.h>
> @@ -105,6 +108,10 @@ struct rte_memarea_param {
>   		 */
>   		struct rte_memarea *user_memarea;
>   	};
> +	/** Backup memarea, which is used to handle the scenario where the
> +	 * current memarea allocation failure.
> +	 */
> +	struct rte_memarea *bak_memarea;
>   };
>   
>   /**

^ permalink raw reply	[flat|nested] 222+ messages in thread

* Re: [PATCH v5 01/10] memarea: introduce memarea library
  2022-10-05  4:09   ` [PATCH v5 01/10] memarea: " datshan
@ 2022-10-06 20:15     ` Mattias Rönnblom
  2022-10-08  7:53       ` fengchengwen
  0 siblings, 1 reply; 222+ messages in thread
From: Mattias Rönnblom @ 2022-10-06 20:15 UTC (permalink / raw)
  To: datshan, david.marchand, mb, anatoly.burakov, dmitry.kozliuk,
	jerinjacobk
  Cc: thomas, dev, Chengwen Feng

On 2022-10-05 06:09, datshan wrote:
> From: Chengwen Feng <fengchengwen@huawei.com>
> 
> 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 <fengchengwen@huawei.com>
> ---
>   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 <fengchengwen@huawei.com>
> +F: lib/memarea
> +F: doc/guides/prog_guide/memarea_lib.rst
> +
>   Membership - EXPERIMENTAL
>   M: Yipeng Wang <yipeng1.wang@intel.com>
>   M: Sameh Gobriel <sameh.gobriel@intel.com>
> 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..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 library is an allocator of variable-size objects, it is oriented
> +  towards the application layer, which could provides 'region-based memory
> +  management' function.
> +
>   * **Added configuration for asynchronous flow connection tracking.**
>   
>     Added connection tracking action number hint to ``rte_flow_configure``
> diff --git a/lib/eal/common/eal_common_log.c b/lib/eal/common/eal_common_log.c
> index bd7b188ceb..3d62af59c6 100644
> --- a/lib/eal/common/eal_common_log.c
> +++ b/lib/eal/common/eal_common_log.c
> @@ -369,6 +369,7 @@ static const struct logtype logtype_strings[] = {
>   	{RTE_LOGTYPE_EFD,        "lib.efd"},
>   	{RTE_LOGTYPE_EVENTDEV,   "lib.eventdev"},
>   	{RTE_LOGTYPE_GSO,        "lib.gso"},
> +	{RTE_LOGTYPE_MEMAREA,    "lib.memarea"},
>   	{RTE_LOGTYPE_USER1,      "user1"},
>   	{RTE_LOGTYPE_USER2,      "user2"},
>   	{RTE_LOGTYPE_USER3,      "user3"},
> diff --git a/lib/eal/include/rte_log.h b/lib/eal/include/rte_log.h
> index 25ce42cdfc..708f3a39dd 100644
> --- a/lib/eal/include/rte_log.h
> +++ b/lib/eal/include/rte_log.h
> @@ -48,6 +48,7 @@ extern "C" {
>   #define RTE_LOGTYPE_EFD       18 /**< Log related to EFD. */
>   #define RTE_LOGTYPE_EVENTDEV  19 /**< Log related to eventdev. */
>   #define RTE_LOGTYPE_GSO       20 /**< Log related to GSO. */
> +#define RTE_LOGTYPE_MEMAREA   21 /**< Log related to memarea. */
>   
>   /* these log types can be used in an application */
>   #define RTE_LOGTYPE_USER1     24 /**< User-defined log type 1. */
> diff --git a/lib/memarea/memarea_private.h b/lib/memarea/memarea_private.h
> new file mode 100644
> index 0000000000..c76392d3e6
> --- /dev/null
> +++ b/lib/memarea/memarea_private.h
> @@ -0,0 +1,30 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2022 HiSilicon Limited
> + */
> +
> +#ifndef MEMAREA_PRIVATE_H
> +#define MEMAREA_PRIVATE_H
> +
> +#include <rte_memarea.h>
> +
> +#define MEMAREA_FREE_ELEM_COOKIE	0xFFFFFFFF
> +
> +struct memarea_elem {
> +	size_t   size;
> +	uint32_t cookie;
> +	int32_t  refcnt; /* Non-zero indicates that it has been allocated */
> +	TAILQ_ENTRY(memarea_elem) elem_node;
> +	TAILQ_ENTRY(memarea_elem) free_node;
> +} __rte_cache_aligned;
> +

Why is the elem type cache line aligned? Need the elem data start be 
cache line aligned?

> +TAILQ_HEAD(memarea_elem_list, memarea_elem);
> +
> +struct rte_memarea {
> +	struct rte_memarea_param init;
> +	rte_spinlock_t           lock;
> +	void                    *area_addr;
> +	struct memarea_elem_list elem_list;
> +	struct memarea_elem_list free_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..0a74fb4cd1
> --- /dev/null
> +++ b/lib/memarea/meson.build
> @@ -0,0 +1,16 @@
> +# SPDX-License-Identifier: BSD-3-Clause
> +# Copyright(c) 2022 HiSilicon Limited
> +
> +if is_windows
> +    build = false
> +    reason = 'not supported on Windows'
> +    subdir_done()
> +endif
> +
> +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..868da7661d
> --- /dev/null
> +++ b/lib/memarea/rte_memarea.c
> @@ -0,0 +1,157 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2022 HiSilicon Limited
> + */
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +
> +#include <rte_common.h>
> +#include <rte_log.h>
> +#include <rte_malloc.h>
> +#include <rte_spinlock.h>
> +
> +#include "rte_memarea.h"
> +#include "memarea_private.h"
> +
> +static int
> +memarea_check_param(const struct rte_memarea_param *init)
> +{
> +	size_t len;
> +
> +	if (init == NULL) {
> +		RTE_LOG(ERR, MEMAREA, "memarea init param is NULL!\n");
> +		return -EINVAL;
> +	}
> +
> +	len = strnlen(init->name, RTE_MEMAREA_NAMESIZE);
> +	if (len == 0 || len >= RTE_MEMAREA_NAMESIZE) {
> +		RTE_LOG(ERR, MEMAREA, "memarea name size %zu invalid!\n", len);
> +		return -EINVAL;
> +	}
> +
> +	if (init->source != RTE_MEMAREA_SOURCE_RTE_MEMORY &&
> +	    init->source != RTE_MEMAREA_SOURCE_SYSTEM_API &&
> +	    init->source != RTE_MEMAREA_SOURCE_USER_ADDR &&
> +	    init->source != RTE_MEMAREA_SOURCE_USER_MEMAREA) {
> +		RTE_LOG(ERR, MEMAREA, "memarea: %s source: %d not supported!\n",
> +			init->name, init->source);
> +		return -EINVAL;
> +	}
> +
> +	if (init->total_sz <= sizeof(struct memarea_elem)) {
> +		RTE_LOG(ERR, MEMAREA, "memarea: %s total-size: %zu too small!\n",
> +			init->name, init->total_sz);
> +		return -EINVAL;
> +	}
> +
> +	if (init->source == RTE_MEMAREA_SOURCE_USER_ADDR && init->user_addr == NULL) {
> +		RTE_LOG(ERR, MEMAREA, "memarea: %s user provided addr is NULL!\n", init->name);
> +		return -EINVAL;
> +	}
> +
> +	if (init->source == RTE_MEMAREA_SOURCE_USER_ADDR &&
> +	    ((uintptr_t)init->user_addr & (RTE_CACHE_LINE_SIZE - 1))) {
> +		RTE_LOG(ERR, MEMAREA, "memarea: %s user provided addr should align: %d!\n",
> +			init->name, RTE_CACHE_LINE_SIZE);
> +		return -EINVAL;
> +	}
> +
> +	if (init->source == RTE_MEMAREA_SOURCE_USER_MEMAREA && init->user_memarea == NULL) {
> +		RTE_LOG(ERR, MEMAREA, "memarea: %s user provided memarea is NULL!\n", init->name);
> +		return -EINVAL;
> +	}
> +
> +	if (init->alg != RTE_MEMAREA_ALG_DEFAULT) {
> +		RTE_LOG(ERR, MEMAREA, "memarea: %s alg: %d not supported!\n",
> +			init->name, init->alg);
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static void *
> +memarea_alloc_from_system_api(size_t size)
> +{
> +	void *ptr = NULL;
> +	int ret;
> +
> +	ret = posix_memalign(&ptr, RTE_CACHE_LINE_SIZE, size);
> +	if (ret)
> +		return NULL;
> +	return ptr;
> +}
> +
> +static void *
> +memarea_alloc_area(const struct rte_memarea_param *init)
> +{
> +	void *ptr = NULL;
> +
> +	if (init->source == RTE_MEMAREA_SOURCE_RTE_MEMORY)

Delete MEMORY. Of course it's memory. What else? If you want to make it 
clear it's from the RTE heap, it should spell out HEAP. Or MALLOC.

> +		ptr = rte_malloc_socket(NULL, init->total_sz, RTE_CACHE_LINE_SIZE,
> +					init->numa_socket);
> +	else if (init->source == RTE_MEMAREA_SOURCE_SYSTEM_API)
> +		ptr = memarea_alloc_from_system_api(init->total_sz);

"SYSTEM_API" doesn't strike me as a good name.

RTE_MEMAREA_SOURCE_LIBC
RTE_MEMAREA_SOURCE_STD_HEAP
or at least remove API so it'll be
RTE_MEMAREA_SOURCE_SYSTEM

> +	else if (init->source == RTE_MEMAREA_SOURCE_USER_ADDR)

I would delete "ADDR".

> +		ptr = init->user_addr;
> +
> +	if (ptr == NULL)
> +		RTE_LOG(ERR, MEMAREA, "memarea: %s alloc memory area fail!\n", init->name);
> +
> +	return ptr;
> +}
> +
> +struct rte_memarea *
> +rte_memarea_create(const struct rte_memarea_param *init)
> +{
> +	struct memarea_elem *elem;
> +	struct rte_memarea *ma;
> +	void *addr;
> +	int ret;
> +
> +	ret = memarea_check_param(init);
> +	if (ret)
> +		return NULL;
> +
> +	addr = memarea_alloc_area(init);
> +	if (addr == NULL)
> +		return NULL;
> +
> +	ma = rte_zmalloc(NULL, sizeof(struct rte_memarea), RTE_CACHE_LINE_SIZE);
> +	if (ma == NULL) {
> +		RTE_LOG(ERR, MEMAREA, "malloc memarea: %s management obj fail!\n", init->name);
> +		return NULL;
> +	}
> +
> +	ma->init = *init;
> +	rte_spinlock_init(&ma->lock);
> +	TAILQ_INIT(&ma->elem_list);
> +	TAILQ_INIT(&ma->free_list);
> +	ma->area_addr = addr;
> +	elem = addr;
> +	elem->size = init->total_sz - sizeof(struct memarea_elem);
> +	elem->cookie = MEMAREA_FREE_ELEM_COOKIE;
> +	elem->refcnt = 0;
> +	TAILQ_INSERT_TAIL(&ma->elem_list, elem, elem_node);
> +	TAILQ_INSERT_TAIL(&ma->free_list, elem, free_node);
> +
> +	return ma;
> +}
> +
> +static void
> +memarea_free_area(struct rte_memarea *ma)
> +{
> +	if (ma->init.source == RTE_MEMAREA_SOURCE_RTE_MEMORY)
> +		rte_free(ma->area_addr);
> +	else if (ma->init.source == RTE_MEMAREA_SOURCE_SYSTEM_API)
> +		free(ma->area_addr);
> +}
> +
> +void
> +rte_memarea_destroy(struct rte_memarea *ma)
> +{
> +	if (ma == NULL)
> +		return;
> +	memarea_free_area(ma);
> +	rte_free(ma);
> +}
> diff --git a/lib/memarea/rte_memarea.h b/lib/memarea/rte_memarea.h
> new file mode 100644
> index 0000000000..543cda4cac
> --- /dev/null
> +++ b/lib/memarea/rte_memarea.h
> @@ -0,0 +1,145 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2022 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 default alignment size is RTE_CACHE_LINE_SIZE.

This can be read as two things: the object size is aligned, or the start 
address is aligned.

> + * - The memory region can be initialized from the following memory sources:
> + *   1. RTE memory: e.g. invoke rte_malloc_socket to obtain.

Remove "to obtain", or add "memory" after "obtain". Do you really mean 
"e.g.", and not "i.e."?

> + *   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.

What is extended memory?

> + *   4) User provided memarea: it can be from another memarea. So we can build
> + *      the following memory management structure:
> + *         \code{.unparsed}
> + *                           -------------
> + *                           | memarea-1 |
> + *                           -------------
> + *                                 |
> + *                                 v
> + *                  -------------------------------
> + *                  |               |             |
> + *                  v               v             v
> + *            -------------   -------------   ----------
> + *            | memarea-2 |   | memarea-3 |   | object |
> + *            -------------   -------------   ----------
> + *         \endcode
> + *      As shown above, the memarea-2/3 both create from memarea-1's memory.
> + * - 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. 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 <stdbool.h>
> +#include <stdint.h>
> +#include <stdio.h>
> +
> +#include <rte_compat.h>
> +
> +#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_RTE_MEMORY,
> +	/** Memory source comes from system API. */
> +	RTE_MEMAREA_SOURCE_SYSTEM_API,
> +	/** Memory source comes from user-provided address. */
> +	RTE_MEMAREA_SOURCE_USER_ADDR,
> +	/** Memory source comes from user-provided memarea. */
> +	RTE_MEMAREA_SOURCE_USER_MEMAREA,
> +};
> +
> +/**
> + * Memarea memory management algorithm.
> + */
> +enum rte_memarea_alg {
> +	/* The default management algorithm is a variant of the next fit
> +	 * algorithm. It uses a free-list to apply for memory and uses an
> +	 * element-list in ascending order of address to support merging
> +	 * upon free.
> +	 */
> +	RTE_MEMAREA_ALG_DEFAULT,
> +};
> +
> +struct rte_memarea;
> +
> +struct rte_memarea_param {

Does this struct need to be public?

> +	char name[RTE_MEMAREA_NAMESIZE]; /**< Name of memarea. */
> +	enum rte_memarea_source source;  /**< Memory source of memarea. */
> +	enum rte_memarea_alg 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;

Why not bool?

> +	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_RTE_MEMORY.
> +		 */
> +		int numa_socket;
> +		/** User provided address, this field is valid only when the
> +		 * source is set to be RTE_MEMAREA_SOURCE_USER_ADDR.
> +		 * Note: the provided address must align at least
> +		 * RTE_CACHE_LINE_SIZE.
> +		 */
> +		void *user_addr;
> +		/** User provided memarea, this field is valid only when the
> +		 * source is set to be RTE_MEMAREA_SOURCE_USER_MEMAREA.
> +		 */
> +		struct rte_memarea *user_memarea;
> +	};
> +};
> +
> +/**
> + * @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 c648f7d800..521a25d6c0 100644
> --- a/lib/meson.build
> +++ b/lib/meson.build
> @@ -42,6 +42,7 @@ libraries = [
>           'kni',
>           'latencystats',
>           'lpm',
> +        'memarea',
>           'member',
>           'pcapng',
>           'power',

^ permalink raw reply	[flat|nested] 222+ messages in thread

* Re: [PATCH v5 01/10] memarea: introduce memarea library
  2022-10-06 20:15     ` Mattias Rönnblom
@ 2022-10-08  7:53       ` fengchengwen
  2022-10-10 16:53         ` Mattias Rönnblom
  0 siblings, 1 reply; 222+ messages in thread
From: fengchengwen @ 2022-10-08  7:53 UTC (permalink / raw)
  To: Mattias Rönnblom, datshan, david.marchand, mb,
	anatoly.burakov, dmitry.kozliuk, jerinjacobk
  Cc: thomas, dev

Hi Mattias, Thanks for your review, most will fix in v6.

On 2022/10/7 4:15, Mattias Rönnblom wrote:
> On 2022-10-05 06:09, datshan wrote:
>> From: Chengwen Feng <fengchengwen@huawei.com>
>>
>> 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 <fengchengwen@huawei.com>
>> ---
>>   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 <fengchengwen@huawei.com>
>> +F: lib/memarea
>> +F: doc/guides/prog_guide/memarea_lib.rst
>> +
>>   Membership - EXPERIMENTAL
>>   M: Yipeng Wang <yipeng1.wang@intel.com>
>>   M: Sameh Gobriel <sameh.gobriel@intel.com>
>> 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..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 library is an allocator of variable-size objects, it is oriented
>> +  towards the application layer, which could provides 'region-based memory
>> +  management' function.
>> +
>>   * **Added configuration for asynchronous flow connection tracking.**
>>       Added connection tracking action number hint to ``rte_flow_configure``
>> diff --git a/lib/eal/common/eal_common_log.c b/lib/eal/common/eal_common_log.c
>> index bd7b188ceb..3d62af59c6 100644
>> --- a/lib/eal/common/eal_common_log.c
>> +++ b/lib/eal/common/eal_common_log.c
>> @@ -369,6 +369,7 @@ static const struct logtype logtype_strings[] = {
>>       {RTE_LOGTYPE_EFD,        "lib.efd"},
>>       {RTE_LOGTYPE_EVENTDEV,   "lib.eventdev"},
>>       {RTE_LOGTYPE_GSO,        "lib.gso"},
>> +    {RTE_LOGTYPE_MEMAREA,    "lib.memarea"},
>>       {RTE_LOGTYPE_USER1,      "user1"},
>>       {RTE_LOGTYPE_USER2,      "user2"},
>>       {RTE_LOGTYPE_USER3,      "user3"},
>> diff --git a/lib/eal/include/rte_log.h b/lib/eal/include/rte_log.h
>> index 25ce42cdfc..708f3a39dd 100644
>> --- a/lib/eal/include/rte_log.h
>> +++ b/lib/eal/include/rte_log.h
>> @@ -48,6 +48,7 @@ extern "C" {
>>   #define RTE_LOGTYPE_EFD       18 /**< Log related to EFD. */
>>   #define RTE_LOGTYPE_EVENTDEV  19 /**< Log related to eventdev. */
>>   #define RTE_LOGTYPE_GSO       20 /**< Log related to GSO. */
>> +#define RTE_LOGTYPE_MEMAREA   21 /**< Log related to memarea. */
>>     /* these log types can be used in an application */
>>   #define RTE_LOGTYPE_USER1     24 /**< User-defined log type 1. */
>> diff --git a/lib/memarea/memarea_private.h b/lib/memarea/memarea_private.h
>> new file mode 100644
>> index 0000000000..c76392d3e6
>> --- /dev/null
>> +++ b/lib/memarea/memarea_private.h
>> @@ -0,0 +1,30 @@
>> +/* SPDX-License-Identifier: BSD-3-Clause
>> + * Copyright(c) 2022 HiSilicon Limited
>> + */
>> +
>> +#ifndef MEMAREA_PRIVATE_H
>> +#define MEMAREA_PRIVATE_H
>> +
>> +#include <rte_memarea.h>
>> +
>> +#define MEMAREA_FREE_ELEM_COOKIE    0xFFFFFFFF
>> +
>> +struct memarea_elem {
>> +    size_t   size;
>> +    uint32_t cookie;
>> +    int32_t  refcnt; /* Non-zero indicates that it has been allocated */
>> +    TAILQ_ENTRY(memarea_elem) elem_node;
>> +    TAILQ_ENTRY(memarea_elem) free_node;
>> +} __rte_cache_aligned;
>> +
> 
> Why is the elem type cache line aligned? Need the elem data start be cache line aligned?

Yes, the elem data align at cache-line default.

> 
>> +TAILQ_HEAD(memarea_elem_list, memarea_elem);
>> +
>> +struct rte_memarea {
>> +    struct rte_memarea_param init;
>> +    rte_spinlock_t           lock;
>> +    void                    *area_addr;
>> +    struct memarea_elem_list elem_list;
>> +    struct memarea_elem_list free_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..0a74fb4cd1
>> --- /dev/null
>> +++ b/lib/memarea/meson.build
>> @@ -0,0 +1,16 @@
>> +# SPDX-License-Identifier: BSD-3-Clause
>> +# Copyright(c) 2022 HiSilicon Limited
>> +
>> +if is_windows
>> +    build = false
>> +    reason = 'not supported on Windows'
>> +    subdir_done()
>> +endif
>> +
>> +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..868da7661d
>> --- /dev/null
>> +++ b/lib/memarea/rte_memarea.c
>> @@ -0,0 +1,157 @@
>> +/* SPDX-License-Identifier: BSD-3-Clause
>> + * Copyright(c) 2022 HiSilicon Limited
>> + */
>> +
>> +#include <stdio.h>
>> +#include <stdlib.h>
>> +
>> +#include <rte_common.h>
>> +#include <rte_log.h>
>> +#include <rte_malloc.h>
>> +#include <rte_spinlock.h>
>> +
>> +#include "rte_memarea.h"
>> +#include "memarea_private.h"
>> +
>> +static int
>> +memarea_check_param(const struct rte_memarea_param *init)
>> +{
>> +    size_t len;
>> +
>> +    if (init == NULL) {
>> +        RTE_LOG(ERR, MEMAREA, "memarea init param is NULL!\n");
>> +        return -EINVAL;
>> +    }
>> +
>> +    len = strnlen(init->name, RTE_MEMAREA_NAMESIZE);
>> +    if (len == 0 || len >= RTE_MEMAREA_NAMESIZE) {
>> +        RTE_LOG(ERR, MEMAREA, "memarea name size %zu invalid!\n", len);
>> +        return -EINVAL;
>> +    }
>> +
>> +    if (init->source != RTE_MEMAREA_SOURCE_RTE_MEMORY &&
>> +        init->source != RTE_MEMAREA_SOURCE_SYSTEM_API &&
>> +        init->source != RTE_MEMAREA_SOURCE_USER_ADDR &&
>> +        init->source != RTE_MEMAREA_SOURCE_USER_MEMAREA) {
>> +        RTE_LOG(ERR, MEMAREA, "memarea: %s source: %d not supported!\n",
>> +            init->name, init->source);
>> +        return -EINVAL;
>> +    }
>> +
>> +    if (init->total_sz <= sizeof(struct memarea_elem)) {
>> +        RTE_LOG(ERR, MEMAREA, "memarea: %s total-size: %zu too small!\n",
>> +            init->name, init->total_sz);
>> +        return -EINVAL;
>> +    }
>> +
>> +    if (init->source == RTE_MEMAREA_SOURCE_USER_ADDR && init->user_addr == NULL) {
>> +        RTE_LOG(ERR, MEMAREA, "memarea: %s user provided addr is NULL!\n", init->name);
>> +        return -EINVAL;
>> +    }
>> +
>> +    if (init->source == RTE_MEMAREA_SOURCE_USER_ADDR &&
>> +        ((uintptr_t)init->user_addr & (RTE_CACHE_LINE_SIZE - 1))) {
>> +        RTE_LOG(ERR, MEMAREA, "memarea: %s user provided addr should align: %d!\n",
>> +            init->name, RTE_CACHE_LINE_SIZE);
>> +        return -EINVAL;
>> +    }
>> +
>> +    if (init->source == RTE_MEMAREA_SOURCE_USER_MEMAREA && init->user_memarea == NULL) {
>> +        RTE_LOG(ERR, MEMAREA, "memarea: %s user provided memarea is NULL!\n", init->name);
>> +        return -EINVAL;
>> +    }
>> +
>> +    if (init->alg != RTE_MEMAREA_ALG_DEFAULT) {
>> +        RTE_LOG(ERR, MEMAREA, "memarea: %s alg: %d not supported!\n",
>> +            init->name, init->alg);
>> +        return -EINVAL;
>> +    }
>> +
>> +    return 0;
>> +}
>> +
>> +static void *
>> +memarea_alloc_from_system_api(size_t size)
>> +{
>> +    void *ptr = NULL;
>> +    int ret;
>> +
>> +    ret = posix_memalign(&ptr, RTE_CACHE_LINE_SIZE, size);
>> +    if (ret)
>> +        return NULL;
>> +    return ptr;
>> +}
>> +
>> +static void *
>> +memarea_alloc_area(const struct rte_memarea_param *init)
>> +{
>> +    void *ptr = NULL;
>> +
>> +    if (init->source == RTE_MEMAREA_SOURCE_RTE_MEMORY)
> 
> Delete MEMORY. Of course it's memory. What else? If you want to make it clear it's from the RTE heap, it should spell out HEAP. Or MALLOC.

HEAP seem better.

> 
>> +        ptr = rte_malloc_socket(NULL, init->total_sz, RTE_CACHE_LINE_SIZE,
>> +                    init->numa_socket);
>> +    else if (init->source == RTE_MEMAREA_SOURCE_SYSTEM_API)
>> +        ptr = memarea_alloc_from_system_api(init->total_sz);
> 
> "SYSTEM_API" doesn't strike me as a good name.
> 
> RTE_MEMAREA_SOURCE_LIBC

LIBC seem better.

> RTE_MEMAREA_SOURCE_STD_HEAP
> or at least remove API so it'll be
> RTE_MEMAREA_SOURCE_SYSTEM
> 
>> +    else if (init->source == RTE_MEMAREA_SOURCE_USER_ADDR)
> 
> I would delete "ADDR".

+1

> 
>> +        ptr = init->user_addr;
>> +
>> +    if (ptr == NULL)
>> +        RTE_LOG(ERR, MEMAREA, "memarea: %s alloc memory area fail!\n", init->name);
>> +
>> +    return ptr;
>> +}
>> +
>> +struct rte_memarea *
>> +rte_memarea_create(const struct rte_memarea_param *init)
>> +{
>> +    struct memarea_elem *elem;
>> +    struct rte_memarea *ma;
>> +    void *addr;
>> +    int ret;
>> +
>> +    ret = memarea_check_param(init);
>> +    if (ret)
>> +        return NULL;
>> +
>> +    addr = memarea_alloc_area(init);
>> +    if (addr == NULL)
>> +        return NULL;
>> +
>> +    ma = rte_zmalloc(NULL, sizeof(struct rte_memarea), RTE_CACHE_LINE_SIZE);
>> +    if (ma == NULL) {
>> +        RTE_LOG(ERR, MEMAREA, "malloc memarea: %s management obj fail!\n", init->name);
>> +        return NULL;
>> +    }
>> +
>> +    ma->init = *init;
>> +    rte_spinlock_init(&ma->lock);
>> +    TAILQ_INIT(&ma->elem_list);
>> +    TAILQ_INIT(&ma->free_list);
>> +    ma->area_addr = addr;
>> +    elem = addr;
>> +    elem->size = init->total_sz - sizeof(struct memarea_elem);
>> +    elem->cookie = MEMAREA_FREE_ELEM_COOKIE;
>> +    elem->refcnt = 0;
>> +    TAILQ_INSERT_TAIL(&ma->elem_list, elem, elem_node);
>> +    TAILQ_INSERT_TAIL(&ma->free_list, elem, free_node);
>> +
>> +    return ma;
>> +}
>> +
>> +static void
>> +memarea_free_area(struct rte_memarea *ma)
>> +{
>> +    if (ma->init.source == RTE_MEMAREA_SOURCE_RTE_MEMORY)
>> +        rte_free(ma->area_addr);
>> +    else if (ma->init.source == RTE_MEMAREA_SOURCE_SYSTEM_API)
>> +        free(ma->area_addr);
>> +}
>> +
>> +void
>> +rte_memarea_destroy(struct rte_memarea *ma)
>> +{
>> +    if (ma == NULL)
>> +        return;
>> +    memarea_free_area(ma);
>> +    rte_free(ma);
>> +}
>> diff --git a/lib/memarea/rte_memarea.h b/lib/memarea/rte_memarea.h
>> new file mode 100644
>> index 0000000000..543cda4cac
>> --- /dev/null
>> +++ b/lib/memarea/rte_memarea.h
>> @@ -0,0 +1,145 @@
>> +/* SPDX-License-Identifier: BSD-3-Clause
>> + * Copyright(c) 2022 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 default alignment size is RTE_CACHE_LINE_SIZE.
> 
> This can be read as two things: the object size is aligned, or the start address is aligned.

It means the start address align, will define more clear in v6.

> 
>> + * - The memory region can be initialized from the following memory sources:
>> + *   1. RTE memory: e.g. invoke rte_malloc_socket to obtain.
> 
> Remove "to obtain", or add "memory" after "obtain". Do you really mean "e.g.", and not "i.e."?

will fix in v6.

> 
>> + *   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.
> 
> What is extended memory?

Like rte_extmen

> 
>> + *   4) User provided memarea: it can be from another memarea. So we can build
>> + *      the following memory management structure:
>> + *         \code{.unparsed}
>> + *                           -------------
>> + *                           | memarea-1 |
>> + *                           -------------
>> + *                                 |
>> + *                                 v
>> + *                  -------------------------------
>> + *                  |               |             |
>> + *                  v               v             v
>> + *            -------------   -------------   ----------
>> + *            | memarea-2 |   | memarea-3 |   | object |
>> + *            -------------   -------------   ----------
>> + *         \endcode
>> + *      As shown above, the memarea-2/3 both create from memarea-1's memory.
>> + * - 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. 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 <stdbool.h>
>> +#include <stdint.h>
>> +#include <stdio.h>
>> +
>> +#include <rte_compat.h>
>> +
>> +#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_RTE_MEMORY,
>> +    /** Memory source comes from system API. */
>> +    RTE_MEMAREA_SOURCE_SYSTEM_API,
>> +    /** Memory source comes from user-provided address. */
>> +    RTE_MEMAREA_SOURCE_USER_ADDR,
>> +    /** Memory source comes from user-provided memarea. */
>> +    RTE_MEMAREA_SOURCE_USER_MEMAREA,
>> +};
>> +
>> +/**
>> + * Memarea memory management algorithm.
>> + */
>> +enum rte_memarea_alg {
>> +    /* The default management algorithm is a variant of the next fit
>> +     * algorithm. It uses a free-list to apply for memory and uses an
>> +     * element-list in ascending order of address to support merging
>> +     * upon free.
>> +     */
>> +    RTE_MEMAREA_ALG_DEFAULT,
>> +};
>> +
>> +struct rte_memarea;
>> +
>> +struct rte_memarea_param {
> 
> Does this struct need to be public?

Yes, the rte_memarea_param contains create parameters for create memarea which need be public.

And rte_memarea which pointer implementation struction which just a declare here.

> 
>> +    char name[RTE_MEMAREA_NAMESIZE]; /**< Name of memarea. */
>> +    enum rte_memarea_source source;  /**< Memory source of memarea. */
>> +    enum rte_memarea_alg 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;
> 
> Why not bool?

Use bit field other than bool will provides more reserved field.

> 
>> +    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_RTE_MEMORY.
>> +         */
>> +        int numa_socket;
>> +        /** User provided address, this field is valid only when the
>> +         * source is set to be RTE_MEMAREA_SOURCE_USER_ADDR.
>> +         * Note: the provided address must align at least
>> +         * RTE_CACHE_LINE_SIZE.
>> +         */
>> +        void *user_addr;
>> +        /** User provided memarea, this field is valid only when the
>> +         * source is set to be RTE_MEMAREA_SOURCE_USER_MEMAREA.
>> +         */
>> +        struct rte_memarea *user_memarea;
>> +    };
>> +};
>> +
>> +/**
>> + * @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 c648f7d800..521a25d6c0 100644
>> --- a/lib/meson.build
>> +++ b/lib/meson.build
>> @@ -42,6 +42,7 @@ libraries = [
>>           'kni',
>>           'latencystats',
>>           'lpm',
>> +        'memarea',
>>           'member',
>>           'pcapng',
>>           'power',
> 
> .

^ permalink raw reply	[flat|nested] 222+ messages in thread

* Re: [PATCH v5 07/10] memarea: support backup memory mechanism
  2022-10-06 19:53     ` Mattias Rönnblom
@ 2022-10-08  7:56       ` fengchengwen
  0 siblings, 0 replies; 222+ messages in thread
From: fengchengwen @ 2022-10-08  7:56 UTC (permalink / raw)
  To: Mattias Rönnblom, datshan, david.marchand, mb,
	anatoly.burakov, dmitry.kozliuk, jerinjacobk
  Cc: thomas, dev

Hi Mattias,

On 2022/10/7 3:53, Mattias Rönnblom wrote:
> On 2022-10-05 06:09, datshan wrote:
>> From: Chengwen Feng <fengchengwen@huawei.com>
>>
>> This patch supports backup memory mechanism, the memarea could use
>> another memarea as a backup.
> 
> Maybe it's worth mentioning what backup means already here.
> 
> "This patch adds a memarea backup mechanism, where an allocation request which cannot be met by a certain memarea is deferred to its backup memarea."

+1

> 
> I assume they can be nested indefinitely?

Theoretically, yes.
And I'm going to add, to avoid loops

> 
>>
>> Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
>> ---
>>   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);
> 
> RTE_PTR_ADD()
> 
>>       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)
> 
> Maybe you want an unlikely() around the above, too. I assume using the backup area is an exceptional case.

+1

> 
>> +        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 object from backup memarea when
>> + *   the current memarea failed to allocate.
>>    */
>>     #include <stdbool.h>
>> @@ -105,6 +108,10 @@ struct rte_memarea_param {
>>            */
>>           struct rte_memarea *user_memarea;
>>       };
>> +    /** Backup memarea, which is used to handle the scenario where the
>> +     * current memarea allocation failure.
>> +     */
>> +    struct rte_memarea *bak_memarea;
>>   };
>>     /**
> 
> .

^ permalink raw reply	[flat|nested] 222+ messages in thread

* Re: [PATCH v5 03/10] memarea: support alloc/free/update-refcnt API
  2022-10-06 19:43     ` Mattias Rönnblom
@ 2022-10-08  8:02       ` fengchengwen
  0 siblings, 0 replies; 222+ messages in thread
From: fengchengwen @ 2022-10-08  8:02 UTC (permalink / raw)
  To: Mattias Rönnblom, datshan, david.marchand, mb,
	anatoly.burakov, dmitry.kozliuk, jerinjacobk
  Cc: thomas, dev

Hi Mattias,

On 2022/10/7 3:43, Mattias Rönnblom wrote:
> On 2022-10-05 06:09, datshan wrote:
>> From: Chengwen Feng <fengchengwen@huawei.com>
>>
>> This patch supports rte_memarea_alloc()/rte_memarea_free()/
>> rte_memarea_update_refcnt() API.
>>
>> Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
>> ---
>>   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 <stdio.h>
>>   #include <stdlib.h>
>> +#include <sys/queue.h>
>>     #include <rte_common.h>
>>   #include <rte_log.h>
>> @@ -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))
>> +
> 
> You should be able to use RTE_ALIGN_CEIL() instead of your own roundup macro, assuming this function isn't used in a patch I'm yet to review, with a potentially non-power-of-2 align parameter value.
> 
> If not, change the macro to a function.

Current, the default align size is CACHE_LINE_SIZE, and it's power-of-2, so will use RTE_ALIGN_CEIL in v6.

> 
>> +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);
> 
> Use RTE_PTR_ADD().
> 
>> +    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 = (void *)((uintptr_t)elem + sizeof(struct memarea_elem));
> 
> RTE_PTR_ADD() again.
> 
>> +        break;
>> +    }
>> +    if (unlikely(ptr == NULL))
>> +        ma->alloc_fails++;
>> +    memarea_unlock(ma);
>> +
>> +    return ptr;
>> +}
>> +
>> +void
>> +rte_memarea_free(struct rte_memarea *ma, void *ptr)
>> +{
>> +    rte_memarea_update_refcnt(ma, ptr, -1);
>> +}
>> +
>> +static inline void
>> +memarea_merge_node(struct rte_memarea *ma, struct memarea_elem *curr,
>> +           struct memarea_elem *next, bool del_next_from_free,
>> +           bool add_curr_to_free)
>> +{
>> +    curr->size += next->size + sizeof(struct memarea_elem);
>> +    next->size = 0;
>> +    next->cookie = 0;
>> +    TAILQ_REMOVE(&ma->elem_list, next, elem_node);
>> +    if (del_next_from_free)
>> +        TAILQ_REMOVE(&ma->free_list, next, free_node);
>> +    if (add_curr_to_free) {
>> +        curr->cookie = MEMAREA_FREE_ELEM_COOKIE;
>> +        TAILQ_INSERT_TAIL(&ma->free_list, curr, free_node);
>> +    }
>> +}
>> +
>> +static inline void
>> +memarea_free_elem(struct rte_memarea *ma, struct memarea_elem *elem)
>> +{
>> +    struct memarea_elem *prev, *next;
>> +    bool merged = false;
>> +    prev = TAILQ_PREV(elem, memarea_elem_list, elem_node);
>> +    next = TAILQ_NEXT(elem, elem_node);
>> +    if (prev != NULL && prev->refcnt == 0) {
>> +        memarea_merge_node(ma, prev, elem, false, false);
>> +        elem = prev;
>> +        merged = true;
>> +    }
>> +    if (next != NULL && next->refcnt == 0) {
>> +        memarea_merge_node(ma, elem, next, true, !merged);
>> +        merged = true;
>> +    }
>> +    if (!merged) {
>> +        elem->cookie = MEMAREA_FREE_ELEM_COOKIE;
>> +        TAILQ_INSERT_TAIL(&ma->free_list, elem, free_node);
>> +    }
>> +}
>> +
>> +void
>> +rte_memarea_update_refcnt(struct rte_memarea *ma, void *ptr, int16_t value)
>> +{
>> +    struct memarea_elem *elem = (struct memarea_elem *)((uintptr_t)ptr -
>> +                                sizeof(struct memarea_elem));
>> +
>> +    if (unlikely(ma == NULL || ptr == NULL))
>> +        return;
>> +
>> +    memarea_lock(ma);
>> +    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",
>> +            ma->init.name, elem->cookie, elem->refcnt, value);
>> +        ma->refcnt_check_fails++;
>> +        if (elem->refcnt > 0)
>> +            elem->refcnt += value;
>> +        memarea_unlock(ma);
>> +        return;
>> +    }
>> +
>> +    elem->refcnt += value;
>> +    if (elem->refcnt == 0)
>> +        memarea_free_elem(ma, elem);
>> +    memarea_unlock(ma);
>> +}
>> diff --git a/lib/memarea/rte_memarea.h b/lib/memarea/rte_memarea.h
>> index 543cda4cac..10e0d6ad5a 100644
>> --- a/lib/memarea/rte_memarea.h
>> +++ b/lib/memarea/rte_memarea.h
>> @@ -138,6 +138,62 @@ 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.
>> + * @param cookie
>> + *   User-provided footprint which could used to debug memory leak.
>> + *
>> + * @return
>> + *   Non-NULL on success. Otherwise NULL is returned.
>> + */
>> +__rte_experimental
>> +void *rte_memarea_alloc(struct rte_memarea *ma, size_t size, uint32_t cookie);
>> +
>> +/**
>> + * @warning
>> + * @b EXPERIMENTAL: this API may change without prior notice.
>> + *
>> + * Free memory to memarea.
>> + *
>> + * Free one memory object to the memarea.
>> + *
>> + * @param ma
>> + *   The pointer of memarea.
>> + * @param ptr
>> + *   The pointer of memory object which need be freed.
>> + */
>> +__rte_experimental
>> +void rte_memarea_free(struct rte_memarea *ma, void *ptr);
>> +
>> +/**
>> + * @warning
>> + * @b EXPERIMENTAL: this API may change without prior notice.
>> + *
>> + * Update memory's refcnt.
>> + *
>> + * Update one memory object's refcnt.
>> + * When refcnt is updated to be zero, the memory object is freed.
>> + *
>> + * @param ma
>> + *   The pointer of memarea.
>> + * @param ptr
>> + *   The pointer of memory object which need be updated refcnt.
>> + * @param value
>> + *   The value which need be updated.
>> + */
>> +__rte_experimental
>> +void rte_memarea_update_refcnt(struct rte_memarea *ma, void *ptr, int16_t value);
>> +
>>   #ifdef __cplusplus
>>   }
>>   #endif
>> diff --git a/lib/memarea/version.map b/lib/memarea/version.map
>> index f36a04d7cf..a0026fc5f9 100644
>> --- a/lib/memarea/version.map
>> +++ b/lib/memarea/version.map
>> @@ -1,8 +1,11 @@
>>   EXPERIMENTAL {
>>       global:
>>   +    rte_memarea_alloc;
>>       rte_memarea_create;
>>       rte_memarea_destroy;
>> +    rte_memarea_free;
>> +    rte_memarea_update_refcnt;
>>         local: *;
>>   };
> 
> .

^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v6 00/10] introduce memarea library
  2022-07-21  4:46 [RFC] memarea: introduce memory area library Chengwen Feng
                   ` (9 preceding siblings ...)
       [not found] ` <20221005040952.8166-1-datshan@qq.com>
@ 2022-10-08 11:33 ` Chengwen Feng
  2022-10-08 11:33   ` [PATCH v6 01/10] memarea: " Chengwen Feng
                     ` (9 more replies)
  2022-10-08 11:58 ` [PATCH v7 00/10] introduce memarea library Chengwen Feng
                   ` (12 subsequent siblings)
  23 siblings, 10 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-10-08 11:33 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk, hofors
  Cc: thomas, dev, datshan

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

- The allocated object aligned at RTE_CACHE_LINE_SIZE default.

- 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. User provided: it can be from e.g. rte_extmem_xxx as long as it is
     available. The memory's start 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. It will attempts to allocate object from backup
  memarea when the current memarea failed to allocate.

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 <fengchengwen@huawei.com>

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

---
v6:
* address Mattias's comments.
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                | 420 ++++++++++++++++++++++++
 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  |  56 ++++
 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              | 428 +++++++++++++++++++++++++
 lib/memarea/rte_memarea.h              | 234 ++++++++++++++
 lib/memarea/version.map                |  16 +
 lib/meson.build                        |   1 +
 16 files changed, 1228 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.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v6 01/10] memarea: introduce memarea library
  2022-10-08 11:33 ` [PATCH v6 00/10] introduce memarea library Chengwen Feng
@ 2022-10-08 11:33   ` Chengwen Feng
  2022-10-08 11:33   ` [PATCH v6 02/10] test/memarea: support memarea test Chengwen Feng
                     ` (8 subsequent siblings)
  9 siblings, 0 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-10-08 11:33 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk, hofors
  Cc: thomas, dev, datshan

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 <fengchengwen@huawei.com>
---
 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              | 146 +++++++++++++++++++++++
 lib/memarea/version.map                |  12 ++
 lib/meson.build                        |   1 +
 14 files changed, 418 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 3757ccc3b3..6c1cb637b0 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1562,6 +1562,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 <fengchengwen@huawei.com>
+F: lib/memarea
+F: doc/guides/prog_guide/memarea_lib.rst
+
 Membership - EXPERIMENTAL
 M: Yipeng Wang <yipeng1.wang@intel.com>
 M: Sameh Gobriel <sameh.gobriel@intel.com>
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..27b280da6e
--- /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 allocated object aligned at ``RTE_CACHE_LINE_SIZE`` default.
+
+* The memory region can be initialized from the following memory sources:
+  a) HEAP: e.g. invoke ``rte_malloc_socket``. b) LIBC: e.g. invoke
+  posix_memalign to obtain. c) User provided: it can be from e.g.
+  rte_extmem_xxx 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 1cd5a39e02..b3088ff539 100644
--- a/doc/guides/rel_notes/release_22_11.rst
+++ b/doc/guides/rel_notes/release_22_11.rst
@@ -63,6 +63,12 @@ New Features
   In theory this implementation should work with any target based on
   ``LoongArch`` ISA.
 
+* **Added memarea library.**
+
+  The memarea library is an allocator of variable-size objects, it is oriented
+  towards the application layer, which could provides 'region-based memory
+  management' function.
+
 * **Added ethdev Rx/Tx descriptor dump API.**
 
   Added the ethdev Rx/Tx descriptor dump API which provides functions
diff --git a/lib/eal/common/eal_common_log.c b/lib/eal/common/eal_common_log.c
index bd7b188ceb..3d62af59c6 100644
--- a/lib/eal/common/eal_common_log.c
+++ b/lib/eal/common/eal_common_log.c
@@ -369,6 +369,7 @@ static const struct logtype logtype_strings[] = {
 	{RTE_LOGTYPE_EFD,        "lib.efd"},
 	{RTE_LOGTYPE_EVENTDEV,   "lib.eventdev"},
 	{RTE_LOGTYPE_GSO,        "lib.gso"},
+	{RTE_LOGTYPE_MEMAREA,    "lib.memarea"},
 	{RTE_LOGTYPE_USER1,      "user1"},
 	{RTE_LOGTYPE_USER2,      "user2"},
 	{RTE_LOGTYPE_USER3,      "user3"},
diff --git a/lib/eal/include/rte_log.h b/lib/eal/include/rte_log.h
index 25ce42cdfc..708f3a39dd 100644
--- a/lib/eal/include/rte_log.h
+++ b/lib/eal/include/rte_log.h
@@ -48,6 +48,7 @@ extern "C" {
 #define RTE_LOGTYPE_EFD       18 /**< Log related to EFD. */
 #define RTE_LOGTYPE_EVENTDEV  19 /**< Log related to eventdev. */
 #define RTE_LOGTYPE_GSO       20 /**< Log related to GSO. */
+#define RTE_LOGTYPE_MEMAREA   21 /**< Log related to memarea. */
 
 /* these log types can be used in an application */
 #define RTE_LOGTYPE_USER1     24 /**< User-defined log type 1. */
diff --git a/lib/memarea/memarea_private.h b/lib/memarea/memarea_private.h
new file mode 100644
index 0000000000..c76392d3e6
--- /dev/null
+++ b/lib/memarea/memarea_private.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2022 HiSilicon Limited
+ */
+
+#ifndef MEMAREA_PRIVATE_H
+#define MEMAREA_PRIVATE_H
+
+#include <rte_memarea.h>
+
+#define MEMAREA_FREE_ELEM_COOKIE	0xFFFFFFFF
+
+struct memarea_elem {
+	size_t   size;
+	uint32_t cookie;
+	int32_t  refcnt; /* Non-zero indicates that it has been allocated */
+	TAILQ_ENTRY(memarea_elem) elem_node;
+	TAILQ_ENTRY(memarea_elem) free_node;
+} __rte_cache_aligned;
+
+TAILQ_HEAD(memarea_elem_list, memarea_elem);
+
+struct rte_memarea {
+	struct rte_memarea_param init;
+	rte_spinlock_t           lock;
+	void                    *area_addr;
+	struct memarea_elem_list elem_list;
+	struct memarea_elem_list free_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..0a74fb4cd1
--- /dev/null
+++ b/lib/memarea/meson.build
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2022 HiSilicon Limited
+
+if is_windows
+    build = false
+    reason = 'not supported on Windows'
+    subdir_done()
+endif
+
+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..bb0bfc2149
--- /dev/null
+++ b/lib/memarea/rte_memarea.c
@@ -0,0 +1,157 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2022 HiSilicon Limited
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <rte_common.h>
+#include <rte_log.h>
+#include <rte_malloc.h>
+#include <rte_spinlock.h>
+
+#include "rte_memarea.h"
+#include "memarea_private.h"
+
+static int
+memarea_check_param(const struct rte_memarea_param *init)
+{
+	size_t len;
+
+	if (init == NULL) {
+		RTE_LOG(ERR, MEMAREA, "memarea init param is NULL!\n");
+		return -EINVAL;
+	}
+
+	len = strnlen(init->name, RTE_MEMAREA_NAMESIZE);
+	if (len == 0 || len >= RTE_MEMAREA_NAMESIZE) {
+		RTE_LOG(ERR, MEMAREA, "memarea name size %zu invalid!\n", len);
+		return -EINVAL;
+	}
+
+	if (init->source != RTE_MEMAREA_SOURCE_HEAP &&
+	    init->source != RTE_MEMAREA_SOURCE_LIBC &&
+	    init->source != RTE_MEMAREA_SOURCE_USER &&
+	    init->source != RTE_MEMAREA_SOURCE_USER_MEMAREA) {
+		RTE_LOG(ERR, MEMAREA, "memarea: %s source: %d not supported!\n",
+			init->name, init->source);
+		return -EINVAL;
+	}
+
+	if (init->total_sz <= sizeof(struct memarea_elem)) {
+		RTE_LOG(ERR, MEMAREA, "memarea: %s total-size: %zu too small!\n",
+			init->name, init->total_sz);
+		return -EINVAL;
+	}
+
+	if (init->source == RTE_MEMAREA_SOURCE_USER && init->user_addr == NULL) {
+		RTE_LOG(ERR, MEMAREA, "memarea: %s user provided addr is NULL!\n", init->name);
+		return -EINVAL;
+	}
+
+	if (init->source == RTE_MEMAREA_SOURCE_USER &&
+	    ((uintptr_t)init->user_addr & (RTE_CACHE_LINE_SIZE - 1))) {
+		RTE_LOG(ERR, MEMAREA, "memarea: %s user provided addr should align: %d!\n",
+			init->name, RTE_CACHE_LINE_SIZE);
+		return -EINVAL;
+	}
+
+	if (init->source == RTE_MEMAREA_SOURCE_USER_MEMAREA && init->user_memarea == NULL) {
+		RTE_LOG(ERR, MEMAREA, "memarea: %s user provided memarea is NULL!\n", init->name);
+		return -EINVAL;
+	}
+
+	if (init->alg != RTE_MEMAREA_ALG_DEFAULT) {
+		RTE_LOG(ERR, MEMAREA, "memarea: %s alg: %d not supported!\n",
+			init->name, init->alg);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void *
+memarea_alloc_from_libc(size_t size)
+{
+	void *ptr = NULL;
+	int ret;
+
+	ret = posix_memalign(&ptr, RTE_CACHE_LINE_SIZE, size);
+	if (ret)
+		return NULL;
+	return ptr;
+}
+
+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);
+	else if (init->source == RTE_MEMAREA_SOURCE_USER)
+		ptr = init->user_addr;
+
+	if (ptr == NULL)
+		RTE_LOG(ERR, MEMAREA, "memarea: %s alloc memory area fail!\n", init->name);
+
+	return ptr;
+}
+
+struct rte_memarea *
+rte_memarea_create(const struct rte_memarea_param *init)
+{
+	struct memarea_elem *elem;
+	struct rte_memarea *ma;
+	void *addr;
+	int ret;
+
+	ret = memarea_check_param(init);
+	if (ret)
+		return NULL;
+
+	addr = memarea_alloc_area(init);
+	if (addr == NULL)
+		return NULL;
+
+	ma = rte_zmalloc(NULL, sizeof(struct rte_memarea), RTE_CACHE_LINE_SIZE);
+	if (ma == NULL) {
+		RTE_LOG(ERR, MEMAREA, "malloc memarea: %s management obj fail!\n", init->name);
+		return NULL;
+	}
+
+	ma->init = *init;
+	rte_spinlock_init(&ma->lock);
+	TAILQ_INIT(&ma->elem_list);
+	TAILQ_INIT(&ma->free_list);
+	ma->area_addr = addr;
+	elem = addr;
+	elem->size = init->total_sz - sizeof(struct memarea_elem);
+	elem->cookie = MEMAREA_FREE_ELEM_COOKIE;
+	elem->refcnt = 0;
+	TAILQ_INSERT_TAIL(&ma->elem_list, elem, elem_node);
+	TAILQ_INSERT_TAIL(&ma->free_list, elem, free_node);
+
+	return ma;
+}
+
+static void
+memarea_free_area(struct rte_memarea *ma)
+{
+	if (ma->init.source == RTE_MEMAREA_SOURCE_HEAP)
+		rte_free(ma->area_addr);
+	else if (ma->init.source == RTE_MEMAREA_SOURCE_LIBC)
+		free(ma->area_addr);
+}
+
+void
+rte_memarea_destroy(struct rte_memarea *ma)
+{
+	if (ma == NULL)
+		return;
+	memarea_free_area(ma);
+	rte_free(ma);
+}
diff --git a/lib/memarea/rte_memarea.h b/lib/memarea/rte_memarea.h
new file mode 100644
index 0000000000..f6d1fc2a59
--- /dev/null
+++ b/lib/memarea/rte_memarea.h
@@ -0,0 +1,146 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2022 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 allocated object aligned at RTE_CACHE_LINE_SIZE default.
+ * - 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. User provided: it can be from e.g. rte_extmem_xxx as long as it is
+ *      available. The memory's start address must be aligned to
+ *      RTE_CACHE_LINE_SIZE.
+ *   4) User provided memarea: it can be from another memarea. So we can build
+ *      the following memory management structure:
+ *         \code{.unparsed}
+ *                           -------------
+ *                           | memarea-1 |
+ *                           -------------
+ *                                 |
+ *                                 v
+ *                  -------------------------------
+ *                  |               |             |
+ *                  v               v             v
+ *            -------------   -------------   ----------
+ *            | memarea-2 |   | memarea-3 |   | object |
+ *            -------------   -------------   ----------
+ *         \endcode
+ *      As shown above, the memarea-2/3 both create from memarea-1's memory.
+ * - 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. 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 <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include <rte_compat.h>
+
+#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 user-provided memory. */
+	RTE_MEMAREA_SOURCE_USER,
+	/** Memory source comes from user-provided memarea. */
+	RTE_MEMAREA_SOURCE_USER_MEMAREA,
+};
+
+/**
+ * Memarea memory management algorithm.
+ */
+enum rte_memarea_alg {
+	/* The default management algorithm is a variant of the next fit
+	 * algorithm. It uses a free-list to apply for memory and uses an
+	 * element-list in ascending order of address to support merging
+	 * upon free.
+	 */
+	RTE_MEMAREA_ALG_DEFAULT,
+};
+
+struct rte_memarea;
+
+struct rte_memarea_param {
+	char name[RTE_MEMAREA_NAMESIZE]; /**< Name of memarea. */
+	enum rte_memarea_source source;  /**< Memory source of memarea. */
+	enum rte_memarea_alg 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;
+		/** User provided address, this field is valid only when the
+		 * source is set to be RTE_MEMAREA_SOURCE_USER.
+		 * Note: the provided address must align at least
+		 * RTE_CACHE_LINE_SIZE.
+		 */
+		void *user_addr;
+		/** User provided memarea, this field is valid only when the
+		 * source is set to be RTE_MEMAREA_SOURCE_USER_MEMAREA.
+		 */
+		struct rte_memarea *user_memarea;
+	};
+};
+
+/**
+ * @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 c648f7d800..521a25d6c0 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -42,6 +42,7 @@ libraries = [
         'kni',
         'latencystats',
         'lpm',
+        'memarea',
         'member',
         'pcapng',
         'power',
-- 
2.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v6 02/10] test/memarea: support memarea test
  2022-10-08 11:33 ` [PATCH v6 00/10] introduce memarea library Chengwen Feng
  2022-10-08 11:33   ` [PATCH v6 01/10] memarea: " Chengwen Feng
@ 2022-10-08 11:33   ` Chengwen Feng
  2022-10-08 11:33   ` [PATCH v6 03/10] memarea: support alloc/free/update-refcnt API Chengwen Feng
                     ` (7 subsequent siblings)
  9 siblings, 0 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-10-08 11:33 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk, hofors
  Cc: thomas, dev, datshan

This patch supports memarea test about API rte_memarea_create and
rte_memarea_destroy.

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 MAINTAINERS             |   1 +
 app/test/meson.build    |   2 +
 app/test/test_memarea.c | 168 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 171 insertions(+)
 create mode 100644 app/test/test_memarea.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 6c1cb637b0..7adeef31bf 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1566,6 +1566,7 @@ Memarea - EXPERIMENTAL
 M: Chengwen Feng <fengchengwen@huawei.com>
 F: lib/memarea
 F: doc/guides/prog_guide/memarea_lib.rst
+F: app/test/test_memarea*
 
 Membership - EXPERIMENTAL
 M: Yipeng Wang <yipeng1.wang@intel.com>
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 0000000000..6b6612dc82
--- /dev/null
+++ b/app/test/test_memarea.c
@@ -0,0 +1,168 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2022 HiSilicon Limited
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#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 <rte_memory.h>
+#include <rte_memarea.h>
+
+#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_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_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;
+	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;
+	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;
+	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 HEAP */
+	test_memarea_init_def_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_def_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);
+
+	/* test for create with user-provided */
+	test_memarea_init_def_param(&init);
+	init.source = RTE_MEMAREA_SOURCE_USER;
+	init.user_addr = (void *)(((uintptr_t)user_buffer + RTE_CACHE_LINE_SIZE) &
+				  ~(RTE_CACHE_LINE_SIZE - 1));
+	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();
+}
+
+#endif /* !RTE_EXEC_ENV_WINDOWS */
+
+REGISTER_TEST_COMMAND(memarea_autotest, test_memarea);
-- 
2.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v6 03/10] memarea: support alloc/free/update-refcnt API
  2022-10-08 11:33 ` [PATCH v6 00/10] introduce memarea library Chengwen Feng
  2022-10-08 11:33   ` [PATCH v6 01/10] memarea: " Chengwen Feng
  2022-10-08 11:33   ` [PATCH v6 02/10] test/memarea: support memarea test Chengwen Feng
@ 2022-10-08 11:33   ` Chengwen Feng
  2022-10-08 11:33   ` [PATCH v6 04/10] test/memarea: support alloc/free/update-refcnt test Chengwen Feng
                     ` (6 subsequent siblings)
  9 siblings, 0 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-10-08 11:33 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk, hofors
  Cc: thomas, dev, datshan

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

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 doc/guides/prog_guide/memarea_lib.rst |  10 ++
 lib/memarea/memarea_private.h         |   3 +
 lib/memarea/rte_memarea.c             | 141 ++++++++++++++++++++++++++
 lib/memarea/rte_memarea.h             |  56 ++++++++++
 lib/memarea/version.map               |   3 +
 5 files changed, 213 insertions(+)

diff --git a/doc/guides/prog_guide/memarea_lib.rst b/doc/guides/prog_guide/memarea_lib.rst
index 27b280da6e..97decf27de 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 bb0bfc2149..522092637e 100644
--- a/lib/memarea/rte_memarea.c
+++ b/lib/memarea/rte_memarea.c
@@ -4,6 +4,7 @@
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <sys/queue.h>
 
 #include <rte_common.h>
 #include <rte_log.h>
@@ -94,6 +95,8 @@ memarea_alloc_area(const struct rte_memarea_param *init)
 		ptr = memarea_alloc_from_libc(init->total_sz);
 	else if (init->source == RTE_MEMAREA_SOURCE_USER)
 		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_LIBC)
 		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,139 @@ 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);
+}
+
+static inline bool
+memarea_whether_add_node(size_t free_size, size_t need_size)
+{
+	size_t align_size = RTE_ALIGN_CEIL(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 = RTE_ALIGN_CEIL(need_size, RTE_CACHE_LINE_SIZE);
+	struct memarea_elem *new_elem;
+	new_elem = (struct memarea_elem *)RTE_PTR_ADD(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 = RTE_PTR_ADD(elem, sizeof(struct memarea_elem));
+		break;
+	}
+	if (unlikely(ptr == NULL))
+		ma->alloc_fails++;
+	memarea_unlock(ma);
+
+	return ptr;
+}
+
+void
+rte_memarea_free(struct rte_memarea *ma, void *ptr)
+{
+	rte_memarea_update_refcnt(ma, ptr, -1);
+}
+
+static inline void
+memarea_merge_node(struct rte_memarea *ma, struct memarea_elem *curr,
+		   struct memarea_elem *next, bool del_next_from_free,
+		   bool add_curr_to_free)
+{
+	curr->size += next->size + sizeof(struct memarea_elem);
+	next->size = 0;
+	next->cookie = 0;
+	TAILQ_REMOVE(&ma->elem_list, next, elem_node);
+	if (del_next_from_free)
+		TAILQ_REMOVE(&ma->free_list, next, free_node);
+	if (add_curr_to_free) {
+		curr->cookie = MEMAREA_FREE_ELEM_COOKIE;
+		TAILQ_INSERT_TAIL(&ma->free_list, curr, free_node);
+	}
+}
+
+static inline void
+memarea_free_elem(struct rte_memarea *ma, struct memarea_elem *elem)
+{
+	struct memarea_elem *prev, *next;
+	bool merged = false;
+	prev = TAILQ_PREV(elem, memarea_elem_list, elem_node);
+	next = TAILQ_NEXT(elem, elem_node);
+	if (prev != NULL && prev->refcnt == 0) {
+		memarea_merge_node(ma, prev, elem, false, false);
+		elem = prev;
+		merged = true;
+	}
+	if (next != NULL && next->refcnt == 0) {
+		memarea_merge_node(ma, elem, next, true, !merged);
+		merged = true;
+	}
+	if (!merged) {
+		elem->cookie = MEMAREA_FREE_ELEM_COOKIE;
+		TAILQ_INSERT_TAIL(&ma->free_list, elem, free_node);
+	}
+}
+
+void
+rte_memarea_update_refcnt(struct rte_memarea *ma, void *ptr, int16_t value)
+{
+	struct memarea_elem *elem = (struct memarea_elem *)RTE_PTR_SUB(ptr,
+							    sizeof(struct memarea_elem));
+
+	if (unlikely(ma == NULL || ptr == NULL))
+		return;
+
+	memarea_lock(ma);
+	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",
+			ma->init.name, elem->cookie, elem->refcnt, value);
+		ma->refcnt_check_fails++;
+		if (elem->refcnt > 0)
+			elem->refcnt += value;
+		memarea_unlock(ma);
+		return;
+	}
+
+	elem->refcnt += value;
+	if (elem->refcnt == 0)
+		memarea_free_elem(ma, elem);
+	memarea_unlock(ma);
+}
diff --git a/lib/memarea/rte_memarea.h b/lib/memarea/rte_memarea.h
index f6d1fc2a59..9e25969bf4 100644
--- a/lib/memarea/rte_memarea.h
+++ b/lib/memarea/rte_memarea.h
@@ -139,6 +139,62 @@ 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.
+ * @param cookie
+ *   User-provided footprint which could used to debug memory leak.
+ *
+ * @return
+ *   Non-NULL on success. Otherwise NULL is returned.
+ */
+__rte_experimental
+void *rte_memarea_alloc(struct rte_memarea *ma, size_t size, uint32_t cookie);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Free memory to memarea.
+ *
+ * Free one memory object to the memarea.
+ *
+ * @param ma
+ *   The pointer of memarea.
+ * @param ptr
+ *   The pointer of memory object which need be freed.
+ */
+__rte_experimental
+void rte_memarea_free(struct rte_memarea *ma, void *ptr);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Update memory's refcnt.
+ *
+ * Update one memory object's refcnt.
+ * When refcnt is updated to be zero, the memory object is freed.
+ *
+ * @param ma
+ *   The pointer of memarea.
+ * @param ptr
+ *   The pointer of memory object which need be updated refcnt.
+ * @param value
+ *   The value which need be updated.
+ */
+__rte_experimental
+void rte_memarea_update_refcnt(struct rte_memarea *ma, void *ptr, int16_t value);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/memarea/version.map b/lib/memarea/version.map
index f36a04d7cf..a0026fc5f9 100644
--- a/lib/memarea/version.map
+++ b/lib/memarea/version.map
@@ -1,8 +1,11 @@
 EXPERIMENTAL {
 	global:
 
+	rte_memarea_alloc;
 	rte_memarea_create;
 	rte_memarea_destroy;
+	rte_memarea_free;
+	rte_memarea_update_refcnt;
 
 	local: *;
 };
-- 
2.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v6 04/10] test/memarea: support alloc/free/update-refcnt test
  2022-10-08 11:33 ` [PATCH v6 00/10] introduce memarea library Chengwen Feng
                     ` (2 preceding siblings ...)
  2022-10-08 11:33   ` [PATCH v6 03/10] memarea: support alloc/free/update-refcnt API Chengwen Feng
@ 2022-10-08 11:33   ` Chengwen Feng
  2022-10-08 11:33   ` [PATCH v6 05/10] memarea: support dump API Chengwen Feng
                     ` (5 subsequent siblings)
  9 siblings, 0 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-10-08 11:33 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk, hofors
  Cc: thomas, dev, datshan

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

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 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 6b6612dc82..5ace384b8a 100644
--- a/app/test/test_memarea.c
+++ b/app/test/test_memarea.c
@@ -57,6 +57,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)
 {
@@ -122,8 +128,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 HEAP */
 	test_memarea_init_def_param(&init);
@@ -149,6 +155,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_LIBC;
+	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_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, 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_LIBC;
+	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)
+{
+#define ALLOC_MAX_NUM	8
+	struct rte_memarea_param init;
+	struct rte_memarea *ma;
+	void *ptr[ALLOC_MAX_NUM];
+	int i;
+
+	/* prepare env */
+	test_memarea_init_def_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, 0);
+
+	/* 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;
 }
 
@@ -159,6 +304,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();
 }
-- 
2.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v6 05/10] memarea: support dump API
  2022-10-08 11:33 ` [PATCH v6 00/10] introduce memarea library Chengwen Feng
                     ` (3 preceding siblings ...)
  2022-10-08 11:33   ` [PATCH v6 04/10] test/memarea: support alloc/free/update-refcnt test Chengwen Feng
@ 2022-10-08 11:33   ` Chengwen Feng
  2022-10-08 11:33   ` [PATCH v6 06/10] test/memarea: support dump test Chengwen Feng
                     ` (4 subsequent siblings)
  9 siblings, 0 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-10-08 11:33 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk, hofors
  Cc: thomas, dev, datshan

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

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 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 97decf27de..720d8099e2 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 522092637e..bc51d2a5ff 100644
--- a/lib/memarea/rte_memarea.c
+++ b/lib/memarea/rte_memarea.c
@@ -2,6 +2,7 @@
  * Copyright(c) 2022 HiSilicon Limited
  */
 
+#include <inttypes.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/queue.h>
@@ -296,3 +297,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_HEAP)
+		return "heap";
+	else if (source == RTE_MEMAREA_SOURCE_LIBC)
+		return "libc";
+	else if (source == RTE_MEMAREA_SOURCE_USER)
+		return "user";
+	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 9e25969bf4..4bf2f36c7c 100644
--- a/lib/memarea/rte_memarea.h
+++ b/lib/memarea/rte_memarea.h
@@ -195,6 +195,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/version.map
@@ -4,6 +4,7 @@ EXPERIMENTAL {
 	rte_memarea_alloc;
 	rte_memarea_create;
 	rte_memarea_destroy;
+	rte_memarea_dump;
 	rte_memarea_free;
 	rte_memarea_update_refcnt;
 
-- 
2.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v6 06/10] test/memarea: support dump test
  2022-10-08 11:33 ` [PATCH v6 00/10] introduce memarea library Chengwen Feng
                     ` (4 preceding siblings ...)
  2022-10-08 11:33   ` [PATCH v6 05/10] memarea: support dump API Chengwen Feng
@ 2022-10-08 11:33   ` Chengwen Feng
  2022-10-08 11:33   ` [PATCH v6 07/10] memarea: support backup memory mechanism Chengwen Feng
                     ` (3 subsequent siblings)
  9 siblings, 0 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-10-08 11:33 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk, hofors
  Cc: thomas, dev, datshan

This patch supports rte_memarea_dump() test.

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 app/test/test_memarea.c | 33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/app/test/test_memarea.c b/app/test/test_memarea.c
index 5ace384b8a..d159e4f2ef 100644
--- a/app/test/test_memarea.c
+++ b/app/test/test_memarea.c
@@ -297,6 +297,38 @@ test_memarea_alloc_free(void)
 	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_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, 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);
+
+	return 0;
+}
+
 static int
 test_memarea(void)
 {
@@ -307,6 +339,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();
 }
-- 
2.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v6 07/10] memarea: support backup memory mechanism
  2022-10-08 11:33 ` [PATCH v6 00/10] introduce memarea library Chengwen Feng
                     ` (5 preceding siblings ...)
  2022-10-08 11:33   ` [PATCH v6 06/10] test/memarea: support dump test Chengwen Feng
@ 2022-10-08 11:33   ` Chengwen Feng
  2022-10-08 11:33   ` [PATCH v6 08/10] test/memarea: support backup memory test Chengwen Feng
                     ` (2 subsequent siblings)
  9 siblings, 0 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-10-08 11:33 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk, hofors
  Cc: thomas, dev, datshan

This patch adds a memarea backup mechanism, where an allocation request
which cannot be met by the current memarea is deferred to its backup
memarea.

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 doc/guides/prog_guide/memarea_lib.rst |  4 ++++
 lib/memarea/memarea_private.h         |  2 ++
 lib/memarea/rte_memarea.c             | 22 ++++++++++++++++++++++
 lib/memarea/rte_memarea.h             | 11 +++++++++++
 4 files changed, 39 insertions(+)

diff --git a/doc/guides/prog_guide/memarea_lib.rst b/doc/guides/prog_guide/memarea_lib.rst
index 720d8099e2..feebafabcc 100644
--- a/doc/guides/prog_guide/memarea_lib.rst
+++ b/doc/guides/prog_guide/memarea_lib.rst
@@ -25,6 +25,10 @@ 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. It will attempts to allocate object from backup memarea when
+  the current memarea failed to allocate.
+
 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 bc51d2a5ff..f95f89b6ec 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 = RTE_PTR_ADD(addr, init->total_sz - 1);
 	elem = addr;
 	elem->size = init->total_sz - sizeof(struct memarea_elem);
 	elem->cookie = MEMAREA_FREE_ELEM_COOKIE;
@@ -198,6 +199,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)
 {
@@ -219,6 +229,8 @@ rte_memarea_alloc(struct rte_memarea *ma, size_t size, uint32_t cookie)
 		ptr = RTE_PTR_ADD(elem, sizeof(struct memarea_elem));
 		break;
 	}
+	if (unlikely(ptr == NULL && ma->init.bak_memarea != NULL))
+		ptr = memarea_alloc_backup(ma, size, cookie);
 	if (unlikely(ptr == NULL))
 		ma->alloc_fails++;
 	memarea_unlock(ma);
@@ -281,6 +293,12 @@ rte_memarea_update_refcnt(struct rte_memarea *ma, void *ptr, int16_t value)
 		return;
 
 	memarea_lock(ma);
+	if (unlikely(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",
@@ -371,10 +389,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 4bf2f36c7c..815d0e3d75 100644
--- a/lib/memarea/rte_memarea.h
+++ b/lib/memarea/rte_memarea.h
@@ -40,6 +40,13 @@
  *   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 object from backup memarea when
+ *   the current memarea failed to allocate.
+ *   @note If the backup memarea is set improperly, loops may occur (e.g.
+ *   memarea-1's backup is memarea-2, and memarea-2's backup is memarea-1) and
+ *   the program will hangs, it is the responsibility of the application to
+ *   ensure that the loops do not form.
  */
 
 #include <stdbool.h>
@@ -106,6 +113,10 @@ struct rte_memarea_param {
 		 */
 		struct rte_memarea *user_memarea;
 	};
+	/** Backup memarea, which is used to handle the scenario where the
+	 * current memarea allocation failure.
+	 */
+	struct rte_memarea *bak_memarea;
 };
 
 /**
-- 
2.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v6 08/10] test/memarea: support backup memory test
  2022-10-08 11:33 ` [PATCH v6 00/10] introduce memarea library Chengwen Feng
                     ` (6 preceding siblings ...)
  2022-10-08 11:33   ` [PATCH v6 07/10] memarea: support backup memory mechanism Chengwen Feng
@ 2022-10-08 11:33   ` Chengwen Feng
  2022-10-08 11:33   ` [PATCH v6 09/10] memarea: detect memory corruption based on magic Chengwen Feng
  2022-10-08 11:33   ` [PATCH v6 10/10] test/memarea: support no MT-safe test Chengwen Feng
  9 siblings, 0 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-10-08 11:33 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk, hofors
  Cc: thomas, dev, datshan

This patch supports backup memory mechanism test.

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 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 d159e4f2ef..28c66b886c 100644
--- a/app/test/test_memarea.c
+++ b/app/test/test_memarea.c
@@ -329,6 +329,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_LIBC;
+	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_LIBC;
+	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)
 {
@@ -340,6 +380,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 test_memarea_retcode();
 }
-- 
2.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v6 09/10] memarea: detect memory corruption based on magic
  2022-10-08 11:33 ` [PATCH v6 00/10] introduce memarea library Chengwen Feng
                     ` (7 preceding siblings ...)
  2022-10-08 11:33   ` [PATCH v6 08/10] test/memarea: support backup memory test Chengwen Feng
@ 2022-10-08 11:33   ` Chengwen Feng
  2022-10-08 11:33   ` [PATCH v6 10/10] test/memarea: support no MT-safe test Chengwen Feng
  9 siblings, 0 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-10-08 11:33 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk, hofors
  Cc: thomas, dev, datshan

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

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 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 <rte_memarea.h>
 
+#define MEMAREA_ELEM_MAGIC_NUM		0xbeef1234
 #define MEMAREA_FREE_ELEM_COOKIE	0xFFFFFFFF
 
 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 f95f89b6ec..2983a36801 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 = RTE_PTR_ADD(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);
@@ -192,6 +193,7 @@ memarea_add_node(struct rte_memarea *ma, struct memarea_elem *elem, size_t need_
 	new_elem = (struct memarea_elem *)RTE_PTR_ADD(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);
@@ -219,6 +221,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))
@@ -251,6 +255,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)
@@ -293,6 +298,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 (unlikely(ptr < ma->area_addr || ptr > ma->top_addr)) {
 		rte_memarea_update_refcnt(ma->init.bak_memarea, ptr, value);
 		memarea_unlock(ma);
@@ -346,8 +358,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;
 }
@@ -358,8 +373,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;
 }
@@ -370,9 +388,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.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v6 10/10] test/memarea: support no MT-safe test
  2022-10-08 11:33 ` [PATCH v6 00/10] introduce memarea library Chengwen Feng
                     ` (8 preceding siblings ...)
  2022-10-08 11:33   ` [PATCH v6 09/10] memarea: detect memory corruption based on magic Chengwen Feng
@ 2022-10-08 11:33   ` Chengwen Feng
  9 siblings, 0 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-10-08 11:33 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk, hofors
  Cc: thomas, dev, datshan

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

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 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 28c66b886c..adadc6dcfc 100644
--- a/app/test/test_memarea.c
+++ b/app/test/test_memarea.c
@@ -369,6 +369,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_LIBC;
+	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)
 {
@@ -381,6 +410,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 test_memarea_retcode();
 }
-- 
2.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v7 00/10] introduce memarea library
  2022-07-21  4:46 [RFC] memarea: introduce memory area library Chengwen Feng
                   ` (10 preceding siblings ...)
  2022-10-08 11:33 ` [PATCH v6 00/10] introduce memarea library Chengwen Feng
@ 2022-10-08 11:58 ` Chengwen Feng
  2022-10-08 11:58   ` [PATCH v7 01/10] memarea: " Chengwen Feng
                     ` (10 more replies)
  2022-10-11 12:17 ` [PATCH v8 0/9] " Chengwen Feng
                   ` (11 subsequent siblings)
  23 siblings, 11 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-10-08 11:58 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk, hofors
  Cc: thomas, dev

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

- The allocated object aligned at RTE_CACHE_LINE_SIZE default.

- 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. User provided: it can be from e.g. rte_extmem_xxx as long as it is
     available. The memory's start 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. It will attempts to allocate object from backup
  memarea when the current memarea failed to allocate.

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 <fengchengwen@huawei.com>

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

---
v6:
* address Mattias's comments.
* repost patches as there are spread over different series in patchwork.
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                | 420 ++++++++++++++++++++++++
 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  |  56 ++++
 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              | 428 +++++++++++++++++++++++++
 lib/memarea/rte_memarea.h              | 234 ++++++++++++++
 lib/memarea/version.map                |  16 +
 lib/meson.build                        |   1 +
 16 files changed, 1228 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.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v7 01/10] memarea: introduce memarea library
  2022-10-08 11:58 ` [PATCH v7 00/10] introduce memarea library Chengwen Feng
@ 2022-10-08 11:58   ` Chengwen Feng
  2022-10-08 11:58   ` [PATCH v7 02/10] test/memarea: support memarea test Chengwen Feng
                     ` (9 subsequent siblings)
  10 siblings, 0 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-10-08 11:58 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk, hofors
  Cc: thomas, dev

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 <fengchengwen@huawei.com>
---
 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              | 146 +++++++++++++++++++++++
 lib/memarea/version.map                |  12 ++
 lib/meson.build                        |   1 +
 14 files changed, 418 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 3757ccc3b3..6c1cb637b0 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1562,6 +1562,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 <fengchengwen@huawei.com>
+F: lib/memarea
+F: doc/guides/prog_guide/memarea_lib.rst
+
 Membership - EXPERIMENTAL
 M: Yipeng Wang <yipeng1.wang@intel.com>
 M: Sameh Gobriel <sameh.gobriel@intel.com>
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..27b280da6e
--- /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 allocated object aligned at ``RTE_CACHE_LINE_SIZE`` default.
+
+* The memory region can be initialized from the following memory sources:
+  a) HEAP: e.g. invoke ``rte_malloc_socket``. b) LIBC: e.g. invoke
+  posix_memalign to obtain. c) User provided: it can be from e.g.
+  rte_extmem_xxx 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 aef2d622dd..1bf5b2b8db 100644
--- a/doc/guides/rel_notes/release_22_11.rst
+++ b/doc/guides/rel_notes/release_22_11.rst
@@ -63,6 +63,12 @@ New Features
   In theory this implementation should work with any target based on
   ``LoongArch`` ISA.
 
+* **Added memarea library.**
+
+  The memarea library is an allocator of variable-size objects, it is oriented
+  towards the application layer, which could provides 'region-based memory
+  management' function.
+
 * **Added support for congestion management in ethdev.**
 
   Added new API functions ``rte_eth_cman_config_init()``,
diff --git a/lib/eal/common/eal_common_log.c b/lib/eal/common/eal_common_log.c
index bd7b188ceb..3d62af59c6 100644
--- a/lib/eal/common/eal_common_log.c
+++ b/lib/eal/common/eal_common_log.c
@@ -369,6 +369,7 @@ static const struct logtype logtype_strings[] = {
 	{RTE_LOGTYPE_EFD,        "lib.efd"},
 	{RTE_LOGTYPE_EVENTDEV,   "lib.eventdev"},
 	{RTE_LOGTYPE_GSO,        "lib.gso"},
+	{RTE_LOGTYPE_MEMAREA,    "lib.memarea"},
 	{RTE_LOGTYPE_USER1,      "user1"},
 	{RTE_LOGTYPE_USER2,      "user2"},
 	{RTE_LOGTYPE_USER3,      "user3"},
diff --git a/lib/eal/include/rte_log.h b/lib/eal/include/rte_log.h
index 25ce42cdfc..708f3a39dd 100644
--- a/lib/eal/include/rte_log.h
+++ b/lib/eal/include/rte_log.h
@@ -48,6 +48,7 @@ extern "C" {
 #define RTE_LOGTYPE_EFD       18 /**< Log related to EFD. */
 #define RTE_LOGTYPE_EVENTDEV  19 /**< Log related to eventdev. */
 #define RTE_LOGTYPE_GSO       20 /**< Log related to GSO. */
+#define RTE_LOGTYPE_MEMAREA   21 /**< Log related to memarea. */
 
 /* these log types can be used in an application */
 #define RTE_LOGTYPE_USER1     24 /**< User-defined log type 1. */
diff --git a/lib/memarea/memarea_private.h b/lib/memarea/memarea_private.h
new file mode 100644
index 0000000000..c76392d3e6
--- /dev/null
+++ b/lib/memarea/memarea_private.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2022 HiSilicon Limited
+ */
+
+#ifndef MEMAREA_PRIVATE_H
+#define MEMAREA_PRIVATE_H
+
+#include <rte_memarea.h>
+
+#define MEMAREA_FREE_ELEM_COOKIE	0xFFFFFFFF
+
+struct memarea_elem {
+	size_t   size;
+	uint32_t cookie;
+	int32_t  refcnt; /* Non-zero indicates that it has been allocated */
+	TAILQ_ENTRY(memarea_elem) elem_node;
+	TAILQ_ENTRY(memarea_elem) free_node;
+} __rte_cache_aligned;
+
+TAILQ_HEAD(memarea_elem_list, memarea_elem);
+
+struct rte_memarea {
+	struct rte_memarea_param init;
+	rte_spinlock_t           lock;
+	void                    *area_addr;
+	struct memarea_elem_list elem_list;
+	struct memarea_elem_list free_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..0a74fb4cd1
--- /dev/null
+++ b/lib/memarea/meson.build
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2022 HiSilicon Limited
+
+if is_windows
+    build = false
+    reason = 'not supported on Windows'
+    subdir_done()
+endif
+
+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..bb0bfc2149
--- /dev/null
+++ b/lib/memarea/rte_memarea.c
@@ -0,0 +1,157 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2022 HiSilicon Limited
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <rte_common.h>
+#include <rte_log.h>
+#include <rte_malloc.h>
+#include <rte_spinlock.h>
+
+#include "rte_memarea.h"
+#include "memarea_private.h"
+
+static int
+memarea_check_param(const struct rte_memarea_param *init)
+{
+	size_t len;
+
+	if (init == NULL) {
+		RTE_LOG(ERR, MEMAREA, "memarea init param is NULL!\n");
+		return -EINVAL;
+	}
+
+	len = strnlen(init->name, RTE_MEMAREA_NAMESIZE);
+	if (len == 0 || len >= RTE_MEMAREA_NAMESIZE) {
+		RTE_LOG(ERR, MEMAREA, "memarea name size %zu invalid!\n", len);
+		return -EINVAL;
+	}
+
+	if (init->source != RTE_MEMAREA_SOURCE_HEAP &&
+	    init->source != RTE_MEMAREA_SOURCE_LIBC &&
+	    init->source != RTE_MEMAREA_SOURCE_USER &&
+	    init->source != RTE_MEMAREA_SOURCE_USER_MEMAREA) {
+		RTE_LOG(ERR, MEMAREA, "memarea: %s source: %d not supported!\n",
+			init->name, init->source);
+		return -EINVAL;
+	}
+
+	if (init->total_sz <= sizeof(struct memarea_elem)) {
+		RTE_LOG(ERR, MEMAREA, "memarea: %s total-size: %zu too small!\n",
+			init->name, init->total_sz);
+		return -EINVAL;
+	}
+
+	if (init->source == RTE_MEMAREA_SOURCE_USER && init->user_addr == NULL) {
+		RTE_LOG(ERR, MEMAREA, "memarea: %s user provided addr is NULL!\n", init->name);
+		return -EINVAL;
+	}
+
+	if (init->source == RTE_MEMAREA_SOURCE_USER &&
+	    ((uintptr_t)init->user_addr & (RTE_CACHE_LINE_SIZE - 1))) {
+		RTE_LOG(ERR, MEMAREA, "memarea: %s user provided addr should align: %d!\n",
+			init->name, RTE_CACHE_LINE_SIZE);
+		return -EINVAL;
+	}
+
+	if (init->source == RTE_MEMAREA_SOURCE_USER_MEMAREA && init->user_memarea == NULL) {
+		RTE_LOG(ERR, MEMAREA, "memarea: %s user provided memarea is NULL!\n", init->name);
+		return -EINVAL;
+	}
+
+	if (init->alg != RTE_MEMAREA_ALG_DEFAULT) {
+		RTE_LOG(ERR, MEMAREA, "memarea: %s alg: %d not supported!\n",
+			init->name, init->alg);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void *
+memarea_alloc_from_libc(size_t size)
+{
+	void *ptr = NULL;
+	int ret;
+
+	ret = posix_memalign(&ptr, RTE_CACHE_LINE_SIZE, size);
+	if (ret)
+		return NULL;
+	return ptr;
+}
+
+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);
+	else if (init->source == RTE_MEMAREA_SOURCE_USER)
+		ptr = init->user_addr;
+
+	if (ptr == NULL)
+		RTE_LOG(ERR, MEMAREA, "memarea: %s alloc memory area fail!\n", init->name);
+
+	return ptr;
+}
+
+struct rte_memarea *
+rte_memarea_create(const struct rte_memarea_param *init)
+{
+	struct memarea_elem *elem;
+	struct rte_memarea *ma;
+	void *addr;
+	int ret;
+
+	ret = memarea_check_param(init);
+	if (ret)
+		return NULL;
+
+	addr = memarea_alloc_area(init);
+	if (addr == NULL)
+		return NULL;
+
+	ma = rte_zmalloc(NULL, sizeof(struct rte_memarea), RTE_CACHE_LINE_SIZE);
+	if (ma == NULL) {
+		RTE_LOG(ERR, MEMAREA, "malloc memarea: %s management obj fail!\n", init->name);
+		return NULL;
+	}
+
+	ma->init = *init;
+	rte_spinlock_init(&ma->lock);
+	TAILQ_INIT(&ma->elem_list);
+	TAILQ_INIT(&ma->free_list);
+	ma->area_addr = addr;
+	elem = addr;
+	elem->size = init->total_sz - sizeof(struct memarea_elem);
+	elem->cookie = MEMAREA_FREE_ELEM_COOKIE;
+	elem->refcnt = 0;
+	TAILQ_INSERT_TAIL(&ma->elem_list, elem, elem_node);
+	TAILQ_INSERT_TAIL(&ma->free_list, elem, free_node);
+
+	return ma;
+}
+
+static void
+memarea_free_area(struct rte_memarea *ma)
+{
+	if (ma->init.source == RTE_MEMAREA_SOURCE_HEAP)
+		rte_free(ma->area_addr);
+	else if (ma->init.source == RTE_MEMAREA_SOURCE_LIBC)
+		free(ma->area_addr);
+}
+
+void
+rte_memarea_destroy(struct rte_memarea *ma)
+{
+	if (ma == NULL)
+		return;
+	memarea_free_area(ma);
+	rte_free(ma);
+}
diff --git a/lib/memarea/rte_memarea.h b/lib/memarea/rte_memarea.h
new file mode 100644
index 0000000000..f6d1fc2a59
--- /dev/null
+++ b/lib/memarea/rte_memarea.h
@@ -0,0 +1,146 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2022 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 allocated object aligned at RTE_CACHE_LINE_SIZE default.
+ * - 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. User provided: it can be from e.g. rte_extmem_xxx as long as it is
+ *      available. The memory's start address must be aligned to
+ *      RTE_CACHE_LINE_SIZE.
+ *   4) User provided memarea: it can be from another memarea. So we can build
+ *      the following memory management structure:
+ *         \code{.unparsed}
+ *                           -------------
+ *                           | memarea-1 |
+ *                           -------------
+ *                                 |
+ *                                 v
+ *                  -------------------------------
+ *                  |               |             |
+ *                  v               v             v
+ *            -------------   -------------   ----------
+ *            | memarea-2 |   | memarea-3 |   | object |
+ *            -------------   -------------   ----------
+ *         \endcode
+ *      As shown above, the memarea-2/3 both create from memarea-1's memory.
+ * - 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. 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 <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include <rte_compat.h>
+
+#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 user-provided memory. */
+	RTE_MEMAREA_SOURCE_USER,
+	/** Memory source comes from user-provided memarea. */
+	RTE_MEMAREA_SOURCE_USER_MEMAREA,
+};
+
+/**
+ * Memarea memory management algorithm.
+ */
+enum rte_memarea_alg {
+	/* The default management algorithm is a variant of the next fit
+	 * algorithm. It uses a free-list to apply for memory and uses an
+	 * element-list in ascending order of address to support merging
+	 * upon free.
+	 */
+	RTE_MEMAREA_ALG_DEFAULT,
+};
+
+struct rte_memarea;
+
+struct rte_memarea_param {
+	char name[RTE_MEMAREA_NAMESIZE]; /**< Name of memarea. */
+	enum rte_memarea_source source;  /**< Memory source of memarea. */
+	enum rte_memarea_alg 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;
+		/** User provided address, this field is valid only when the
+		 * source is set to be RTE_MEMAREA_SOURCE_USER.
+		 * Note: the provided address must align at least
+		 * RTE_CACHE_LINE_SIZE.
+		 */
+		void *user_addr;
+		/** User provided memarea, this field is valid only when the
+		 * source is set to be RTE_MEMAREA_SOURCE_USER_MEMAREA.
+		 */
+		struct rte_memarea *user_memarea;
+	};
+};
+
+/**
+ * @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 c648f7d800..521a25d6c0 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -42,6 +42,7 @@ libraries = [
         'kni',
         'latencystats',
         'lpm',
+        'memarea',
         'member',
         'pcapng',
         'power',
-- 
2.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v7 02/10] test/memarea: support memarea test
  2022-10-08 11:58 ` [PATCH v7 00/10] introduce memarea library Chengwen Feng
  2022-10-08 11:58   ` [PATCH v7 01/10] memarea: " Chengwen Feng
@ 2022-10-08 11:58   ` Chengwen Feng
  2022-10-08 11:58   ` [PATCH v7 03/10] memarea: support alloc/free/update-refcnt API Chengwen Feng
                     ` (8 subsequent siblings)
  10 siblings, 0 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-10-08 11:58 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk, hofors
  Cc: thomas, dev

This patch supports memarea test about API rte_memarea_create and
rte_memarea_destroy.

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 MAINTAINERS             |   1 +
 app/test/meson.build    |   2 +
 app/test/test_memarea.c | 168 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 171 insertions(+)
 create mode 100644 app/test/test_memarea.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 6c1cb637b0..7adeef31bf 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1566,6 +1566,7 @@ Memarea - EXPERIMENTAL
 M: Chengwen Feng <fengchengwen@huawei.com>
 F: lib/memarea
 F: doc/guides/prog_guide/memarea_lib.rst
+F: app/test/test_memarea*
 
 Membership - EXPERIMENTAL
 M: Yipeng Wang <yipeng1.wang@intel.com>
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 0000000000..6b6612dc82
--- /dev/null
+++ b/app/test/test_memarea.c
@@ -0,0 +1,168 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2022 HiSilicon Limited
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#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 <rte_memory.h>
+#include <rte_memarea.h>
+
+#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_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_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;
+	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;
+	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;
+	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 HEAP */
+	test_memarea_init_def_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_def_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);
+
+	/* test for create with user-provided */
+	test_memarea_init_def_param(&init);
+	init.source = RTE_MEMAREA_SOURCE_USER;
+	init.user_addr = (void *)(((uintptr_t)user_buffer + RTE_CACHE_LINE_SIZE) &
+				  ~(RTE_CACHE_LINE_SIZE - 1));
+	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();
+}
+
+#endif /* !RTE_EXEC_ENV_WINDOWS */
+
+REGISTER_TEST_COMMAND(memarea_autotest, test_memarea);
-- 
2.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v7 03/10] memarea: support alloc/free/update-refcnt API
  2022-10-08 11:58 ` [PATCH v7 00/10] introduce memarea library Chengwen Feng
  2022-10-08 11:58   ` [PATCH v7 01/10] memarea: " Chengwen Feng
  2022-10-08 11:58   ` [PATCH v7 02/10] test/memarea: support memarea test Chengwen Feng
@ 2022-10-08 11:58   ` Chengwen Feng
  2022-10-08 11:58   ` [PATCH v7 04/10] test/memarea: support alloc/free/update-refcnt test Chengwen Feng
                     ` (7 subsequent siblings)
  10 siblings, 0 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-10-08 11:58 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk, hofors
  Cc: thomas, dev

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

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 doc/guides/prog_guide/memarea_lib.rst |  10 ++
 lib/memarea/memarea_private.h         |   3 +
 lib/memarea/rte_memarea.c             | 141 ++++++++++++++++++++++++++
 lib/memarea/rte_memarea.h             |  56 ++++++++++
 lib/memarea/version.map               |   3 +
 5 files changed, 213 insertions(+)

diff --git a/doc/guides/prog_guide/memarea_lib.rst b/doc/guides/prog_guide/memarea_lib.rst
index 27b280da6e..97decf27de 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 bb0bfc2149..522092637e 100644
--- a/lib/memarea/rte_memarea.c
+++ b/lib/memarea/rte_memarea.c
@@ -4,6 +4,7 @@
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <sys/queue.h>
 
 #include <rte_common.h>
 #include <rte_log.h>
@@ -94,6 +95,8 @@ memarea_alloc_area(const struct rte_memarea_param *init)
 		ptr = memarea_alloc_from_libc(init->total_sz);
 	else if (init->source == RTE_MEMAREA_SOURCE_USER)
 		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_LIBC)
 		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,139 @@ 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);
+}
+
+static inline bool
+memarea_whether_add_node(size_t free_size, size_t need_size)
+{
+	size_t align_size = RTE_ALIGN_CEIL(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 = RTE_ALIGN_CEIL(need_size, RTE_CACHE_LINE_SIZE);
+	struct memarea_elem *new_elem;
+	new_elem = (struct memarea_elem *)RTE_PTR_ADD(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 = RTE_PTR_ADD(elem, sizeof(struct memarea_elem));
+		break;
+	}
+	if (unlikely(ptr == NULL))
+		ma->alloc_fails++;
+	memarea_unlock(ma);
+
+	return ptr;
+}
+
+void
+rte_memarea_free(struct rte_memarea *ma, void *ptr)
+{
+	rte_memarea_update_refcnt(ma, ptr, -1);
+}
+
+static inline void
+memarea_merge_node(struct rte_memarea *ma, struct memarea_elem *curr,
+		   struct memarea_elem *next, bool del_next_from_free,
+		   bool add_curr_to_free)
+{
+	curr->size += next->size + sizeof(struct memarea_elem);
+	next->size = 0;
+	next->cookie = 0;
+	TAILQ_REMOVE(&ma->elem_list, next, elem_node);
+	if (del_next_from_free)
+		TAILQ_REMOVE(&ma->free_list, next, free_node);
+	if (add_curr_to_free) {
+		curr->cookie = MEMAREA_FREE_ELEM_COOKIE;
+		TAILQ_INSERT_TAIL(&ma->free_list, curr, free_node);
+	}
+}
+
+static inline void
+memarea_free_elem(struct rte_memarea *ma, struct memarea_elem *elem)
+{
+	struct memarea_elem *prev, *next;
+	bool merged = false;
+	prev = TAILQ_PREV(elem, memarea_elem_list, elem_node);
+	next = TAILQ_NEXT(elem, elem_node);
+	if (prev != NULL && prev->refcnt == 0) {
+		memarea_merge_node(ma, prev, elem, false, false);
+		elem = prev;
+		merged = true;
+	}
+	if (next != NULL && next->refcnt == 0) {
+		memarea_merge_node(ma, elem, next, true, !merged);
+		merged = true;
+	}
+	if (!merged) {
+		elem->cookie = MEMAREA_FREE_ELEM_COOKIE;
+		TAILQ_INSERT_TAIL(&ma->free_list, elem, free_node);
+	}
+}
+
+void
+rte_memarea_update_refcnt(struct rte_memarea *ma, void *ptr, int16_t value)
+{
+	struct memarea_elem *elem = (struct memarea_elem *)RTE_PTR_SUB(ptr,
+							    sizeof(struct memarea_elem));
+
+	if (unlikely(ma == NULL || ptr == NULL))
+		return;
+
+	memarea_lock(ma);
+	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",
+			ma->init.name, elem->cookie, elem->refcnt, value);
+		ma->refcnt_check_fails++;
+		if (elem->refcnt > 0)
+			elem->refcnt += value;
+		memarea_unlock(ma);
+		return;
+	}
+
+	elem->refcnt += value;
+	if (elem->refcnt == 0)
+		memarea_free_elem(ma, elem);
+	memarea_unlock(ma);
+}
diff --git a/lib/memarea/rte_memarea.h b/lib/memarea/rte_memarea.h
index f6d1fc2a59..9e25969bf4 100644
--- a/lib/memarea/rte_memarea.h
+++ b/lib/memarea/rte_memarea.h
@@ -139,6 +139,62 @@ 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.
+ * @param cookie
+ *   User-provided footprint which could used to debug memory leak.
+ *
+ * @return
+ *   Non-NULL on success. Otherwise NULL is returned.
+ */
+__rte_experimental
+void *rte_memarea_alloc(struct rte_memarea *ma, size_t size, uint32_t cookie);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Free memory to memarea.
+ *
+ * Free one memory object to the memarea.
+ *
+ * @param ma
+ *   The pointer of memarea.
+ * @param ptr
+ *   The pointer of memory object which need be freed.
+ */
+__rte_experimental
+void rte_memarea_free(struct rte_memarea *ma, void *ptr);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Update memory's refcnt.
+ *
+ * Update one memory object's refcnt.
+ * When refcnt is updated to be zero, the memory object is freed.
+ *
+ * @param ma
+ *   The pointer of memarea.
+ * @param ptr
+ *   The pointer of memory object which need be updated refcnt.
+ * @param value
+ *   The value which need be updated.
+ */
+__rte_experimental
+void rte_memarea_update_refcnt(struct rte_memarea *ma, void *ptr, int16_t value);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/memarea/version.map b/lib/memarea/version.map
index f36a04d7cf..a0026fc5f9 100644
--- a/lib/memarea/version.map
+++ b/lib/memarea/version.map
@@ -1,8 +1,11 @@
 EXPERIMENTAL {
 	global:
 
+	rte_memarea_alloc;
 	rte_memarea_create;
 	rte_memarea_destroy;
+	rte_memarea_free;
+	rte_memarea_update_refcnt;
 
 	local: *;
 };
-- 
2.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v7 04/10] test/memarea: support alloc/free/update-refcnt test
  2022-10-08 11:58 ` [PATCH v7 00/10] introduce memarea library Chengwen Feng
                     ` (2 preceding siblings ...)
  2022-10-08 11:58   ` [PATCH v7 03/10] memarea: support alloc/free/update-refcnt API Chengwen Feng
@ 2022-10-08 11:58   ` Chengwen Feng
  2022-10-08 11:58   ` [PATCH v7 05/10] memarea: support dump API Chengwen Feng
                     ` (6 subsequent siblings)
  10 siblings, 0 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-10-08 11:58 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk, hofors
  Cc: thomas, dev

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

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 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 6b6612dc82..5ace384b8a 100644
--- a/app/test/test_memarea.c
+++ b/app/test/test_memarea.c
@@ -57,6 +57,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)
 {
@@ -122,8 +128,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 HEAP */
 	test_memarea_init_def_param(&init);
@@ -149,6 +155,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_LIBC;
+	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_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, 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_LIBC;
+	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)
+{
+#define ALLOC_MAX_NUM	8
+	struct rte_memarea_param init;
+	struct rte_memarea *ma;
+	void *ptr[ALLOC_MAX_NUM];
+	int i;
+
+	/* prepare env */
+	test_memarea_init_def_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, 0);
+
+	/* 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;
 }
 
@@ -159,6 +304,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();
 }
-- 
2.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v7 05/10] memarea: support dump API
  2022-10-08 11:58 ` [PATCH v7 00/10] introduce memarea library Chengwen Feng
                     ` (3 preceding siblings ...)
  2022-10-08 11:58   ` [PATCH v7 04/10] test/memarea: support alloc/free/update-refcnt test Chengwen Feng
@ 2022-10-08 11:58   ` Chengwen Feng
  2022-10-08 11:58   ` [PATCH v7 06/10] test/memarea: support dump test Chengwen Feng
                     ` (5 subsequent siblings)
  10 siblings, 0 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-10-08 11:58 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk, hofors
  Cc: thomas, dev

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

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 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 97decf27de..720d8099e2 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 522092637e..bc51d2a5ff 100644
--- a/lib/memarea/rte_memarea.c
+++ b/lib/memarea/rte_memarea.c
@@ -2,6 +2,7 @@
  * Copyright(c) 2022 HiSilicon Limited
  */
 
+#include <inttypes.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/queue.h>
@@ -296,3 +297,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_HEAP)
+		return "heap";
+	else if (source == RTE_MEMAREA_SOURCE_LIBC)
+		return "libc";
+	else if (source == RTE_MEMAREA_SOURCE_USER)
+		return "user";
+	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 9e25969bf4..4bf2f36c7c 100644
--- a/lib/memarea/rte_memarea.h
+++ b/lib/memarea/rte_memarea.h
@@ -195,6 +195,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/version.map
@@ -4,6 +4,7 @@ EXPERIMENTAL {
 	rte_memarea_alloc;
 	rte_memarea_create;
 	rte_memarea_destroy;
+	rte_memarea_dump;
 	rte_memarea_free;
 	rte_memarea_update_refcnt;
 
-- 
2.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v7 06/10] test/memarea: support dump test
  2022-10-08 11:58 ` [PATCH v7 00/10] introduce memarea library Chengwen Feng
                     ` (4 preceding siblings ...)
  2022-10-08 11:58   ` [PATCH v7 05/10] memarea: support dump API Chengwen Feng
@ 2022-10-08 11:58   ` Chengwen Feng
  2022-10-08 11:58   ` [PATCH v7 07/10] memarea: support backup memory mechanism Chengwen Feng
                     ` (4 subsequent siblings)
  10 siblings, 0 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-10-08 11:58 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk, hofors
  Cc: thomas, dev

This patch supports rte_memarea_dump() test.

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 app/test/test_memarea.c | 33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/app/test/test_memarea.c b/app/test/test_memarea.c
index 5ace384b8a..d159e4f2ef 100644
--- a/app/test/test_memarea.c
+++ b/app/test/test_memarea.c
@@ -297,6 +297,38 @@ test_memarea_alloc_free(void)
 	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_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, 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);
+
+	return 0;
+}
+
 static int
 test_memarea(void)
 {
@@ -307,6 +339,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();
 }
-- 
2.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v7 07/10] memarea: support backup memory mechanism
  2022-10-08 11:58 ` [PATCH v7 00/10] introduce memarea library Chengwen Feng
                     ` (5 preceding siblings ...)
  2022-10-08 11:58   ` [PATCH v7 06/10] test/memarea: support dump test Chengwen Feng
@ 2022-10-08 11:58   ` Chengwen Feng
  2022-10-08 11:58   ` [PATCH v7 08/10] test/memarea: support backup memory test Chengwen Feng
                     ` (3 subsequent siblings)
  10 siblings, 0 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-10-08 11:58 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk, hofors
  Cc: thomas, dev

This patch adds a memarea backup mechanism, where an allocation request
which cannot be met by the current memarea is deferred to its backup
memarea.

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 doc/guides/prog_guide/memarea_lib.rst |  4 ++++
 lib/memarea/memarea_private.h         |  2 ++
 lib/memarea/rte_memarea.c             | 22 ++++++++++++++++++++++
 lib/memarea/rte_memarea.h             | 11 +++++++++++
 4 files changed, 39 insertions(+)

diff --git a/doc/guides/prog_guide/memarea_lib.rst b/doc/guides/prog_guide/memarea_lib.rst
index 720d8099e2..feebafabcc 100644
--- a/doc/guides/prog_guide/memarea_lib.rst
+++ b/doc/guides/prog_guide/memarea_lib.rst
@@ -25,6 +25,10 @@ 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. It will attempts to allocate object from backup memarea when
+  the current memarea failed to allocate.
+
 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 bc51d2a5ff..f95f89b6ec 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 = RTE_PTR_ADD(addr, init->total_sz - 1);
 	elem = addr;
 	elem->size = init->total_sz - sizeof(struct memarea_elem);
 	elem->cookie = MEMAREA_FREE_ELEM_COOKIE;
@@ -198,6 +199,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)
 {
@@ -219,6 +229,8 @@ rte_memarea_alloc(struct rte_memarea *ma, size_t size, uint32_t cookie)
 		ptr = RTE_PTR_ADD(elem, sizeof(struct memarea_elem));
 		break;
 	}
+	if (unlikely(ptr == NULL && ma->init.bak_memarea != NULL))
+		ptr = memarea_alloc_backup(ma, size, cookie);
 	if (unlikely(ptr == NULL))
 		ma->alloc_fails++;
 	memarea_unlock(ma);
@@ -281,6 +293,12 @@ rte_memarea_update_refcnt(struct rte_memarea *ma, void *ptr, int16_t value)
 		return;
 
 	memarea_lock(ma);
+	if (unlikely(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",
@@ -371,10 +389,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 4bf2f36c7c..815d0e3d75 100644
--- a/lib/memarea/rte_memarea.h
+++ b/lib/memarea/rte_memarea.h
@@ -40,6 +40,13 @@
  *   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 object from backup memarea when
+ *   the current memarea failed to allocate.
+ *   @note If the backup memarea is set improperly, loops may occur (e.g.
+ *   memarea-1's backup is memarea-2, and memarea-2's backup is memarea-1) and
+ *   the program will hangs, it is the responsibility of the application to
+ *   ensure that the loops do not form.
  */
 
 #include <stdbool.h>
@@ -106,6 +113,10 @@ struct rte_memarea_param {
 		 */
 		struct rte_memarea *user_memarea;
 	};
+	/** Backup memarea, which is used to handle the scenario where the
+	 * current memarea allocation failure.
+	 */
+	struct rte_memarea *bak_memarea;
 };
 
 /**
-- 
2.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v7 08/10] test/memarea: support backup memory test
  2022-10-08 11:58 ` [PATCH v7 00/10] introduce memarea library Chengwen Feng
                     ` (6 preceding siblings ...)
  2022-10-08 11:58   ` [PATCH v7 07/10] memarea: support backup memory mechanism Chengwen Feng
@ 2022-10-08 11:58   ` Chengwen Feng
  2022-10-08 11:58   ` [PATCH v7 09/10] memarea: detect memory corruption based on magic Chengwen Feng
                     ` (2 subsequent siblings)
  10 siblings, 0 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-10-08 11:58 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk, hofors
  Cc: thomas, dev

This patch supports backup memory mechanism test.

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 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 d159e4f2ef..28c66b886c 100644
--- a/app/test/test_memarea.c
+++ b/app/test/test_memarea.c
@@ -329,6 +329,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_LIBC;
+	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_LIBC;
+	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)
 {
@@ -340,6 +380,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 test_memarea_retcode();
 }
-- 
2.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v7 09/10] memarea: detect memory corruption based on magic
  2022-10-08 11:58 ` [PATCH v7 00/10] introduce memarea library Chengwen Feng
                     ` (7 preceding siblings ...)
  2022-10-08 11:58   ` [PATCH v7 08/10] test/memarea: support backup memory test Chengwen Feng
@ 2022-10-08 11:58   ` Chengwen Feng
  2022-10-08 11:58   ` [PATCH v7 10/10] test/memarea: support no MT-safe test Chengwen Feng
  2022-10-08 12:14   ` [PATCH v7 00/10] introduce memarea library fengchengwen
  10 siblings, 0 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-10-08 11:58 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk, hofors
  Cc: thomas, dev

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

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 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 <rte_memarea.h>
 
+#define MEMAREA_ELEM_MAGIC_NUM		0xbeef1234
 #define MEMAREA_FREE_ELEM_COOKIE	0xFFFFFFFF
 
 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 f95f89b6ec..2983a36801 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 = RTE_PTR_ADD(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);
@@ -192,6 +193,7 @@ memarea_add_node(struct rte_memarea *ma, struct memarea_elem *elem, size_t need_
 	new_elem = (struct memarea_elem *)RTE_PTR_ADD(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);
@@ -219,6 +221,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))
@@ -251,6 +255,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)
@@ -293,6 +298,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 (unlikely(ptr < ma->area_addr || ptr > ma->top_addr)) {
 		rte_memarea_update_refcnt(ma->init.bak_memarea, ptr, value);
 		memarea_unlock(ma);
@@ -346,8 +358,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;
 }
@@ -358,8 +373,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;
 }
@@ -370,9 +388,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.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v7 10/10] test/memarea: support no MT-safe test
  2022-10-08 11:58 ` [PATCH v7 00/10] introduce memarea library Chengwen Feng
                     ` (8 preceding siblings ...)
  2022-10-08 11:58   ` [PATCH v7 09/10] memarea: detect memory corruption based on magic Chengwen Feng
@ 2022-10-08 11:58   ` Chengwen Feng
  2022-10-08 12:14   ` [PATCH v7 00/10] introduce memarea library fengchengwen
  10 siblings, 0 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-10-08 11:58 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk, hofors
  Cc: thomas, dev

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

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 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 28c66b886c..adadc6dcfc 100644
--- a/app/test/test_memarea.c
+++ b/app/test/test_memarea.c
@@ -369,6 +369,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_LIBC;
+	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)
 {
@@ -381,6 +410,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 test_memarea_retcode();
 }
-- 
2.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* Re: [PATCH v7 00/10] introduce memarea library
  2022-10-08 11:58 ` [PATCH v7 00/10] introduce memarea library Chengwen Feng
                     ` (9 preceding siblings ...)
  2022-10-08 11:58   ` [PATCH v7 10/10] test/memarea: support no MT-safe test Chengwen Feng
@ 2022-10-08 12:14   ` fengchengwen
  10 siblings, 0 replies; 222+ messages in thread
From: fengchengwen @ 2022-10-08 12:14 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk, hofors
  Cc: thomas, dev

On 2022/10/8 19:58, 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:
> 

...

> 
> ---
> v6:
> * address Mattias's comments.
> * repost patches as there are spread over different series in patchwork.

Sorry about the confusion, the repost operation should be classified as v7.
As it's cover-letter, I didn't send v8 to fix it. If necessary, I will send v8.

> 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                | 420 ++++++++++++++++++++++++
>  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  |  56 ++++
>  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              | 428 +++++++++++++++++++++++++
>  lib/memarea/rte_memarea.h              | 234 ++++++++++++++
>  lib/memarea/version.map                |  16 +
>  lib/meson.build                        |   1 +
>  16 files changed, 1228 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
> 

^ permalink raw reply	[flat|nested] 222+ messages in thread

* Re: [PATCH v5 01/10] memarea: introduce memarea library
  2022-10-08  7:53       ` fengchengwen
@ 2022-10-10 16:53         ` Mattias Rönnblom
  2022-10-10 23:33           ` fengchengwen
  0 siblings, 1 reply; 222+ messages in thread
From: Mattias Rönnblom @ 2022-10-10 16:53 UTC (permalink / raw)
  To: fengchengwen, datshan, david.marchand, mb, anatoly.burakov,
	dmitry.kozliuk, jerinjacobk
  Cc: thomas, dev

On 2022-10-08 09:53, fengchengwen wrote:
> Hi Mattias, Thanks for your review, most will fix in v6.
> 
> On 2022/10/7 4:15, Mattias Rönnblom wrote:
>> On 2022-10-05 06:09, datshan wrote:
>>> From: Chengwen Feng <fengchengwen@huawei.com>
>>>
>>> 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 <fengchengwen@huawei.com>
>>> ---
>>>    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 <fengchengwen@huawei.com>
>>> +F: lib/memarea
>>> +F: doc/guides/prog_guide/memarea_lib.rst
>>> +
>>>    Membership - EXPERIMENTAL
>>>    M: Yipeng Wang <yipeng1.wang@intel.com>
>>>    M: Sameh Gobriel <sameh.gobriel@intel.com>
>>> 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..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 library is an allocator of variable-size objects, it is oriented
>>> +  towards the application layer, which could provides 'region-based memory
>>> +  management' function.
>>> +
>>>    * **Added configuration for asynchronous flow connection tracking.**
>>>        Added connection tracking action number hint to ``rte_flow_configure``
>>> diff --git a/lib/eal/common/eal_common_log.c b/lib/eal/common/eal_common_log.c
>>> index bd7b188ceb..3d62af59c6 100644
>>> --- a/lib/eal/common/eal_common_log.c
>>> +++ b/lib/eal/common/eal_common_log.c
>>> @@ -369,6 +369,7 @@ static const struct logtype logtype_strings[] = {
>>>        {RTE_LOGTYPE_EFD,        "lib.efd"},
>>>        {RTE_LOGTYPE_EVENTDEV,   "lib.eventdev"},
>>>        {RTE_LOGTYPE_GSO,        "lib.gso"},
>>> +    {RTE_LOGTYPE_MEMAREA,    "lib.memarea"},
>>>        {RTE_LOGTYPE_USER1,      "user1"},
>>>        {RTE_LOGTYPE_USER2,      "user2"},
>>>        {RTE_LOGTYPE_USER3,      "user3"},
>>> diff --git a/lib/eal/include/rte_log.h b/lib/eal/include/rte_log.h
>>> index 25ce42cdfc..708f3a39dd 100644
>>> --- a/lib/eal/include/rte_log.h
>>> +++ b/lib/eal/include/rte_log.h
>>> @@ -48,6 +48,7 @@ extern "C" {
>>>    #define RTE_LOGTYPE_EFD       18 /**< Log related to EFD. */
>>>    #define RTE_LOGTYPE_EVENTDEV  19 /**< Log related to eventdev. */
>>>    #define RTE_LOGTYPE_GSO       20 /**< Log related to GSO. */
>>> +#define RTE_LOGTYPE_MEMAREA   21 /**< Log related to memarea. */
>>>      /* these log types can be used in an application */
>>>    #define RTE_LOGTYPE_USER1     24 /**< User-defined log type 1. */
>>> diff --git a/lib/memarea/memarea_private.h b/lib/memarea/memarea_private.h
>>> new file mode 100644
>>> index 0000000000..c76392d3e6
>>> --- /dev/null
>>> +++ b/lib/memarea/memarea_private.h
>>> @@ -0,0 +1,30 @@
>>> +/* SPDX-License-Identifier: BSD-3-Clause
>>> + * Copyright(c) 2022 HiSilicon Limited
>>> + */
>>> +
>>> +#ifndef MEMAREA_PRIVATE_H
>>> +#define MEMAREA_PRIVATE_H
>>> +
>>> +#include <rte_memarea.h>
>>> +
>>> +#define MEMAREA_FREE_ELEM_COOKIE    0xFFFFFFFF
>>> +
>>> +struct memarea_elem {
>>> +    size_t   size;
>>> +    uint32_t cookie;
>>> +    int32_t  refcnt; /* Non-zero indicates that it has been allocated */
>>> +    TAILQ_ENTRY(memarea_elem) elem_node;
>>> +    TAILQ_ENTRY(memarea_elem) free_node;
>>> +} __rte_cache_aligned;
>>> +
>>
>> Why is the elem type cache line aligned? Need the elem data start be cache line aligned?
> 
> Yes, the elem data align at cache-line default.
> 
>>
>>> +TAILQ_HEAD(memarea_elem_list, memarea_elem);
>>> +
>>> +struct rte_memarea {
>>> +    struct rte_memarea_param init;
>>> +    rte_spinlock_t           lock;
>>> +    void                    *area_addr;
>>> +    struct memarea_elem_list elem_list;
>>> +    struct memarea_elem_list free_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..0a74fb4cd1
>>> --- /dev/null
>>> +++ b/lib/memarea/meson.build
>>> @@ -0,0 +1,16 @@
>>> +# SPDX-License-Identifier: BSD-3-Clause
>>> +# Copyright(c) 2022 HiSilicon Limited
>>> +
>>> +if is_windows
>>> +    build = false
>>> +    reason = 'not supported on Windows'
>>> +    subdir_done()
>>> +endif
>>> +
>>> +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..868da7661d
>>> --- /dev/null
>>> +++ b/lib/memarea/rte_memarea.c
>>> @@ -0,0 +1,157 @@
>>> +/* SPDX-License-Identifier: BSD-3-Clause
>>> + * Copyright(c) 2022 HiSilicon Limited
>>> + */
>>> +
>>> +#include <stdio.h>
>>> +#include <stdlib.h>
>>> +
>>> +#include <rte_common.h>
>>> +#include <rte_log.h>
>>> +#include <rte_malloc.h>
>>> +#include <rte_spinlock.h>
>>> +
>>> +#include "rte_memarea.h"
>>> +#include "memarea_private.h"
>>> +
>>> +static int
>>> +memarea_check_param(const struct rte_memarea_param *init)
>>> +{
>>> +    size_t len;
>>> +
>>> +    if (init == NULL) {
>>> +        RTE_LOG(ERR, MEMAREA, "memarea init param is NULL!\n");
>>> +        return -EINVAL;
>>> +    }
>>> +
>>> +    len = strnlen(init->name, RTE_MEMAREA_NAMESIZE);
>>> +    if (len == 0 || len >= RTE_MEMAREA_NAMESIZE) {
>>> +        RTE_LOG(ERR, MEMAREA, "memarea name size %zu invalid!\n", len);
>>> +        return -EINVAL;
>>> +    }
>>> +
>>> +    if (init->source != RTE_MEMAREA_SOURCE_RTE_MEMORY &&
>>> +        init->source != RTE_MEMAREA_SOURCE_SYSTEM_API &&
>>> +        init->source != RTE_MEMAREA_SOURCE_USER_ADDR &&
>>> +        init->source != RTE_MEMAREA_SOURCE_USER_MEMAREA) {
>>> +        RTE_LOG(ERR, MEMAREA, "memarea: %s source: %d not supported!\n",
>>> +            init->name, init->source);
>>> +        return -EINVAL;
>>> +    }
>>> +
>>> +    if (init->total_sz <= sizeof(struct memarea_elem)) {
>>> +        RTE_LOG(ERR, MEMAREA, "memarea: %s total-size: %zu too small!\n",
>>> +            init->name, init->total_sz);
>>> +        return -EINVAL;
>>> +    }
>>> +
>>> +    if (init->source == RTE_MEMAREA_SOURCE_USER_ADDR && init->user_addr == NULL) {
>>> +        RTE_LOG(ERR, MEMAREA, "memarea: %s user provided addr is NULL!\n", init->name);
>>> +        return -EINVAL;
>>> +    }
>>> +
>>> +    if (init->source == RTE_MEMAREA_SOURCE_USER_ADDR &&
>>> +        ((uintptr_t)init->user_addr & (RTE_CACHE_LINE_SIZE - 1))) {
>>> +        RTE_LOG(ERR, MEMAREA, "memarea: %s user provided addr should align: %d!\n",
>>> +            init->name, RTE_CACHE_LINE_SIZE);
>>> +        return -EINVAL;
>>> +    }
>>> +
>>> +    if (init->source == RTE_MEMAREA_SOURCE_USER_MEMAREA && init->user_memarea == NULL) {
>>> +        RTE_LOG(ERR, MEMAREA, "memarea: %s user provided memarea is NULL!\n", init->name);
>>> +        return -EINVAL;
>>> +    }
>>> +
>>> +    if (init->alg != RTE_MEMAREA_ALG_DEFAULT) {
>>> +        RTE_LOG(ERR, MEMAREA, "memarea: %s alg: %d not supported!\n",
>>> +            init->name, init->alg);
>>> +        return -EINVAL;
>>> +    }
>>> +
>>> +    return 0;
>>> +}
>>> +
>>> +static void *
>>> +memarea_alloc_from_system_api(size_t size)
>>> +{
>>> +    void *ptr = NULL;
>>> +    int ret;
>>> +
>>> +    ret = posix_memalign(&ptr, RTE_CACHE_LINE_SIZE, size);
>>> +    if (ret)
>>> +        return NULL;
>>> +    return ptr;
>>> +}
>>> +
>>> +static void *
>>> +memarea_alloc_area(const struct rte_memarea_param *init)
>>> +{
>>> +    void *ptr = NULL;
>>> +
>>> +    if (init->source == RTE_MEMAREA_SOURCE_RTE_MEMORY)
>>
>> Delete MEMORY. Of course it's memory. What else? If you want to make it clear it's from the RTE heap, it should spell out HEAP. Or MALLOC.
> 
> HEAP seem better.
> 
>>
>>> +        ptr = rte_malloc_socket(NULL, init->total_sz, RTE_CACHE_LINE_SIZE,
>>> +                    init->numa_socket);
>>> +    else if (init->source == RTE_MEMAREA_SOURCE_SYSTEM_API)
>>> +        ptr = memarea_alloc_from_system_api(init->total_sz);
>>
>> "SYSTEM_API" doesn't strike me as a good name.
>>
>> RTE_MEMAREA_SOURCE_LIBC
> 
> LIBC seem better.
> 
>> RTE_MEMAREA_SOURCE_STD_HEAP
>> or at least remove API so it'll be
>> RTE_MEMAREA_SOURCE_SYSTEM
>>
>>> +    else if (init->source == RTE_MEMAREA_SOURCE_USER_ADDR)
>>
>> I would delete "ADDR".
> 
> +1
> 
>>
>>> +        ptr = init->user_addr;
>>> +
>>> +    if (ptr == NULL)
>>> +        RTE_LOG(ERR, MEMAREA, "memarea: %s alloc memory area fail!\n", init->name);
>>> +
>>> +    return ptr;
>>> +}
>>> +
>>> +struct rte_memarea *
>>> +rte_memarea_create(const struct rte_memarea_param *init)
>>> +{
>>> +    struct memarea_elem *elem;
>>> +    struct rte_memarea *ma;
>>> +    void *addr;
>>> +    int ret;
>>> +
>>> +    ret = memarea_check_param(init);
>>> +    if (ret)
>>> +        return NULL;
>>> +
>>> +    addr = memarea_alloc_area(init);
>>> +    if (addr == NULL)
>>> +        return NULL;
>>> +
>>> +    ma = rte_zmalloc(NULL, sizeof(struct rte_memarea), RTE_CACHE_LINE_SIZE);
>>> +    if (ma == NULL) {
>>> +        RTE_LOG(ERR, MEMAREA, "malloc memarea: %s management obj fail!\n", init->name);
>>> +        return NULL;
>>> +    }
>>> +
>>> +    ma->init = *init;
>>> +    rte_spinlock_init(&ma->lock);
>>> +    TAILQ_INIT(&ma->elem_list);
>>> +    TAILQ_INIT(&ma->free_list);
>>> +    ma->area_addr = addr;
>>> +    elem = addr;
>>> +    elem->size = init->total_sz - sizeof(struct memarea_elem);
>>> +    elem->cookie = MEMAREA_FREE_ELEM_COOKIE;
>>> +    elem->refcnt = 0;
>>> +    TAILQ_INSERT_TAIL(&ma->elem_list, elem, elem_node);
>>> +    TAILQ_INSERT_TAIL(&ma->free_list, elem, free_node);
>>> +
>>> +    return ma;
>>> +}
>>> +
>>> +static void
>>> +memarea_free_area(struct rte_memarea *ma)
>>> +{
>>> +    if (ma->init.source == RTE_MEMAREA_SOURCE_RTE_MEMORY)
>>> +        rte_free(ma->area_addr);
>>> +    else if (ma->init.source == RTE_MEMAREA_SOURCE_SYSTEM_API)
>>> +        free(ma->area_addr);
>>> +}
>>> +
>>> +void
>>> +rte_memarea_destroy(struct rte_memarea *ma)
>>> +{
>>> +    if (ma == NULL)
>>> +        return;
>>> +    memarea_free_area(ma);
>>> +    rte_free(ma);
>>> +}
>>> diff --git a/lib/memarea/rte_memarea.h b/lib/memarea/rte_memarea.h
>>> new file mode 100644
>>> index 0000000000..543cda4cac
>>> --- /dev/null
>>> +++ b/lib/memarea/rte_memarea.h
>>> @@ -0,0 +1,145 @@
>>> +/* SPDX-License-Identifier: BSD-3-Clause
>>> + * Copyright(c) 2022 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 default alignment size is RTE_CACHE_LINE_SIZE.
>>
>> This can be read as two things: the object size is aligned, or the start address is aligned.
> 
> It means the start address align, will define more clear in v6.
> 
>>
>>> + * - The memory region can be initialized from the following memory sources:
>>> + *   1. RTE memory: e.g. invoke rte_malloc_socket to obtain.
>>
>> Remove "to obtain", or add "memory" after "obtain". Do you really mean "e.g.", and not "i.e."?
> 
> will fix in v6.
> 
>>
>>> + *   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.
>>
>> What is extended memory?
> 
> Like rte_extmen
> 
>>
>>> + *   4) User provided memarea: it can be from another memarea. So we can build
>>> + *      the following memory management structure:
>>> + *         \code{.unparsed}
>>> + *                           -------------
>>> + *                           | memarea-1 |
>>> + *                           -------------
>>> + *                                 |
>>> + *                                 v
>>> + *                  -------------------------------
>>> + *                  |               |             |
>>> + *                  v               v             v
>>> + *            -------------   -------------   ----------
>>> + *            | memarea-2 |   | memarea-3 |   | object |
>>> + *            -------------   -------------   ----------
>>> + *         \endcode
>>> + *      As shown above, the memarea-2/3 both create from memarea-1's memory.
>>> + * - 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. 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 <stdbool.h>
>>> +#include <stdint.h>
>>> +#include <stdio.h>
>>> +
>>> +#include <rte_compat.h>
>>> +
>>> +#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_RTE_MEMORY,
>>> +    /** Memory source comes from system API. */
>>> +    RTE_MEMAREA_SOURCE_SYSTEM_API,
>>> +    /** Memory source comes from user-provided address. */
>>> +    RTE_MEMAREA_SOURCE_USER_ADDR,
>>> +    /** Memory source comes from user-provided memarea. */
>>> +    RTE_MEMAREA_SOURCE_USER_MEMAREA,
>>> +};
>>> +
>>> +/**
>>> + * Memarea memory management algorithm.
>>> + */
>>> +enum rte_memarea_alg {
>>> +    /* The default management algorithm is a variant of the next fit
>>> +     * algorithm. It uses a free-list to apply for memory and uses an
>>> +     * element-list in ascending order of address to support merging
>>> +     * upon free.
>>> +     */
>>> +    RTE_MEMAREA_ALG_DEFAULT,
>>> +};

Do you need to expose the algorithm/management scheme option in the 
public API, if there is only one implementation to choose from?

You can always have a rte_memarea_create_alg(/../) in the future, or 
just change the signature between ABI-breaking releases.

Also, shouldn't the default algorithm have name? Rather than just 
DEFAULT. RTE_MEMAREA_ALG_NEXTFIT maybe.

>>> +
>>> +struct rte_memarea;
>>> +
>>> +struct rte_memarea_param {
>>
>> Does this struct need to be public?
> 
> Yes, the rte_memarea_param contains create parameters for create memarea which need be public.
> 

Why isn't the public API just a bunch of create-function parameters? Or, 
alternatively, you have an assortment of create functions, for different 
combinations of parameters. Then you don't have to think about having 
reserved bits or other kind of ABI-related issues due to the struct 
being public.

> And rte_memarea which pointer implementation struction which just a declare here.
> 
>>
>>> +    char name[RTE_MEMAREA_NAMESIZE]; /**< Name of memarea. */
>>> +    enum rte_memarea_source source;  /**< Memory source of memarea. */
>>> +    enum rte_memarea_alg 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;
>>
>> Why not bool?
> 
> Use bit field other than bool will provides more reserved field.
> 
>>
>>> +    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_RTE_MEMORY.
>>> +         */
>>> +        int numa_socket;
>>> +        /** User provided address, this field is valid only when the
>>> +         * source is set to be RTE_MEMAREA_SOURCE_USER_ADDR.
>>> +         * Note: the provided address must align at least
>>> +         * RTE_CACHE_LINE_SIZE.
>>> +         */
>>> +        void *user_addr;
>>> +        /** User provided memarea, this field is valid only when the
>>> +         * source is set to be RTE_MEMAREA_SOURCE_USER_MEMAREA.
>>> +         */
>>> +        struct rte_memarea *user_memarea;
>>> +    };
>>> +};
>>> +
>>> +/**
>>> + * @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 c648f7d800..521a25d6c0 100644
>>> --- a/lib/meson.build
>>> +++ b/lib/meson.build
>>> @@ -42,6 +42,7 @@ libraries = [
>>>            'kni',
>>>            'latencystats',
>>>            'lpm',
>>> +        'memarea',
>>>            'member',
>>>            'pcapng',
>>>            'power',
>>
>> .

^ permalink raw reply	[flat|nested] 222+ messages in thread

* Re: [PATCH v5 01/10] memarea: introduce memarea library
  2022-10-10 16:53         ` Mattias Rönnblom
@ 2022-10-10 23:33           ` fengchengwen
  2022-10-11 15:35             ` Mattias Rönnblom
  0 siblings, 1 reply; 222+ messages in thread
From: fengchengwen @ 2022-10-10 23:33 UTC (permalink / raw)
  To: Mattias Rönnblom, datshan, david.marchand, mb,
	anatoly.burakov, dmitry.kozliuk, jerinjacobk
  Cc: thomas, dev

On 2022/10/11 0:53, Mattias Rönnblom wrote:
> On 2022-10-08 09:53, fengchengwen wrote:
>> Hi Mattias, Thanks for your review, most will fix in v6.
>>
>> On 2022/10/7 4:15, Mattias Rönnblom wrote:
>>> On 2022-10-05 06:09, datshan wrote:
>>>> From: Chengwen Feng <fengchengwen@huawei.com>
>>>>
>>>> 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 <fengchengwen@huawei.com>
>>>> ---
>>>>    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 <fengchengwen@huawei.com>
>>>> +F: lib/memarea
>>>> +F: doc/guides/prog_guide/memarea_lib.rst
>>>> +
>>>>    Membership - EXPERIMENTAL
>>>>    M: Yipeng Wang <yipeng1.wang@intel.com>
>>>>    M: Sameh Gobriel <sameh.gobriel@intel.com>
>>>> 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..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 library is an allocator of variable-size objects, it 
>>>> is oriented
>>>> +  towards the application layer, which could provides 
>>>> 'region-based memory
>>>> +  management' function.
>>>> +
>>>>    * **Added configuration for asynchronous flow connection 
>>>> tracking.**
>>>>        Added connection tracking action number hint to 
>>>> ``rte_flow_configure``
>>>> diff --git a/lib/eal/common/eal_common_log.c 
>>>> b/lib/eal/common/eal_common_log.c
>>>> index bd7b188ceb..3d62af59c6 100644
>>>> --- a/lib/eal/common/eal_common_log.c
>>>> +++ b/lib/eal/common/eal_common_log.c
>>>> @@ -369,6 +369,7 @@ static const struct logtype logtype_strings[] = {
>>>>        {RTE_LOGTYPE_EFD,        "lib.efd"},
>>>>        {RTE_LOGTYPE_EVENTDEV,   "lib.eventdev"},
>>>>        {RTE_LOGTYPE_GSO,        "lib.gso"},
>>>> +    {RTE_LOGTYPE_MEMAREA,    "lib.memarea"},
>>>>        {RTE_LOGTYPE_USER1,      "user1"},
>>>>        {RTE_LOGTYPE_USER2,      "user2"},
>>>>        {RTE_LOGTYPE_USER3,      "user3"},
>>>> diff --git a/lib/eal/include/rte_log.h b/lib/eal/include/rte_log.h
>>>> index 25ce42cdfc..708f3a39dd 100644
>>>> --- a/lib/eal/include/rte_log.h
>>>> +++ b/lib/eal/include/rte_log.h
>>>> @@ -48,6 +48,7 @@ extern "C" {
>>>>    #define RTE_LOGTYPE_EFD       18 /**< Log related to EFD. */
>>>>    #define RTE_LOGTYPE_EVENTDEV  19 /**< Log related to eventdev. */
>>>>    #define RTE_LOGTYPE_GSO       20 /**< Log related to GSO. */
>>>> +#define RTE_LOGTYPE_MEMAREA   21 /**< Log related to memarea. */
>>>>      /* these log types can be used in an application */
>>>>    #define RTE_LOGTYPE_USER1     24 /**< User-defined log type 1. */
>>>> diff --git a/lib/memarea/memarea_private.h 
>>>> b/lib/memarea/memarea_private.h
>>>> new file mode 100644
>>>> index 0000000000..c76392d3e6
>>>> --- /dev/null
>>>> +++ b/lib/memarea/memarea_private.h
>>>> @@ -0,0 +1,30 @@
>>>> +/* SPDX-License-Identifier: BSD-3-Clause
>>>> + * Copyright(c) 2022 HiSilicon Limited
>>>> + */
>>>> +
>>>> +#ifndef MEMAREA_PRIVATE_H
>>>> +#define MEMAREA_PRIVATE_H
>>>> +
>>>> +#include <rte_memarea.h>
>>>> +
>>>> +#define MEMAREA_FREE_ELEM_COOKIE    0xFFFFFFFF
>>>> +
>>>> +struct memarea_elem {
>>>> +    size_t   size;
>>>> +    uint32_t cookie;
>>>> +    int32_t  refcnt; /* Non-zero indicates that it has been 
>>>> allocated */
>>>> +    TAILQ_ENTRY(memarea_elem) elem_node;
>>>> +    TAILQ_ENTRY(memarea_elem) free_node;
>>>> +} __rte_cache_aligned;
>>>> +
>>>
>>> Why is the elem type cache line aligned? Need the elem data start be 
>>> cache line aligned?
>>
>> Yes, the elem data align at cache-line default.
>>
>>>
>>>> +TAILQ_HEAD(memarea_elem_list, memarea_elem);
>>>> +
>>>> +struct rte_memarea {
>>>> +    struct rte_memarea_param init;
>>>> +    rte_spinlock_t           lock;
>>>> +    void                    *area_addr;
>>>> +    struct memarea_elem_list elem_list;
>>>> +    struct memarea_elem_list free_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..0a74fb4cd1
>>>> --- /dev/null
>>>> +++ b/lib/memarea/meson.build
>>>> @@ -0,0 +1,16 @@
>>>> +# SPDX-License-Identifier: BSD-3-Clause
>>>> +# Copyright(c) 2022 HiSilicon Limited
>>>> +
>>>> +if is_windows
>>>> +    build = false
>>>> +    reason = 'not supported on Windows'
>>>> +    subdir_done()
>>>> +endif
>>>> +
>>>> +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..868da7661d
>>>> --- /dev/null
>>>> +++ b/lib/memarea/rte_memarea.c
>>>> @@ -0,0 +1,157 @@
>>>> +/* SPDX-License-Identifier: BSD-3-Clause
>>>> + * Copyright(c) 2022 HiSilicon Limited
>>>> + */
>>>> +
>>>> +#include <stdio.h>
>>>> +#include <stdlib.h>
>>>> +
>>>> +#include <rte_common.h>
>>>> +#include <rte_log.h>
>>>> +#include <rte_malloc.h>
>>>> +#include <rte_spinlock.h>
>>>> +
>>>> +#include "rte_memarea.h"
>>>> +#include "memarea_private.h"
>>>> +
>>>> +static int
>>>> +memarea_check_param(const struct rte_memarea_param *init)
>>>> +{
>>>> +    size_t len;
>>>> +
>>>> +    if (init == NULL) {
>>>> +        RTE_LOG(ERR, MEMAREA, "memarea init param is NULL!\n");
>>>> +        return -EINVAL;
>>>> +    }
>>>> +
>>>> +    len = strnlen(init->name, RTE_MEMAREA_NAMESIZE);
>>>> +    if (len == 0 || len >= RTE_MEMAREA_NAMESIZE) {
>>>> +        RTE_LOG(ERR, MEMAREA, "memarea name size %zu invalid!\n", 
>>>> len);
>>>> +        return -EINVAL;
>>>> +    }
>>>> +
>>>> +    if (init->source != RTE_MEMAREA_SOURCE_RTE_MEMORY &&
>>>> +        init->source != RTE_MEMAREA_SOURCE_SYSTEM_API &&
>>>> +        init->source != RTE_MEMAREA_SOURCE_USER_ADDR &&
>>>> +        init->source != RTE_MEMAREA_SOURCE_USER_MEMAREA) {
>>>> +        RTE_LOG(ERR, MEMAREA, "memarea: %s source: %d not 
>>>> supported!\n",
>>>> +            init->name, init->source);
>>>> +        return -EINVAL;
>>>> +    }
>>>> +
>>>> +    if (init->total_sz <= sizeof(struct memarea_elem)) {
>>>> +        RTE_LOG(ERR, MEMAREA, "memarea: %s total-size: %zu too 
>>>> small!\n",
>>>> +            init->name, init->total_sz);
>>>> +        return -EINVAL;
>>>> +    }
>>>> +
>>>> +    if (init->source == RTE_MEMAREA_SOURCE_USER_ADDR && 
>>>> init->user_addr == NULL) {
>>>> +        RTE_LOG(ERR, MEMAREA, "memarea: %s user provided addr is 
>>>> NULL!\n", init->name);
>>>> +        return -EINVAL;
>>>> +    }
>>>> +
>>>> +    if (init->source == RTE_MEMAREA_SOURCE_USER_ADDR &&
>>>> +        ((uintptr_t)init->user_addr & (RTE_CACHE_LINE_SIZE - 1))) {
>>>> +        RTE_LOG(ERR, MEMAREA, "memarea: %s user provided addr 
>>>> should align: %d!\n",
>>>> +            init->name, RTE_CACHE_LINE_SIZE);
>>>> +        return -EINVAL;
>>>> +    }
>>>> +
>>>> +    if (init->source == RTE_MEMAREA_SOURCE_USER_MEMAREA && 
>>>> init->user_memarea == NULL) {
>>>> +        RTE_LOG(ERR, MEMAREA, "memarea: %s user provided memarea 
>>>> is NULL!\n", init->name);
>>>> +        return -EINVAL;
>>>> +    }
>>>> +
>>>> +    if (init->alg != RTE_MEMAREA_ALG_DEFAULT) {
>>>> +        RTE_LOG(ERR, MEMAREA, "memarea: %s alg: %d not supported!\n",
>>>> +            init->name, init->alg);
>>>> +        return -EINVAL;
>>>> +    }
>>>> +
>>>> +    return 0;
>>>> +}
>>>> +
>>>> +static void *
>>>> +memarea_alloc_from_system_api(size_t size)
>>>> +{
>>>> +    void *ptr = NULL;
>>>> +    int ret;
>>>> +
>>>> +    ret = posix_memalign(&ptr, RTE_CACHE_LINE_SIZE, size);
>>>> +    if (ret)
>>>> +        return NULL;
>>>> +    return ptr;
>>>> +}
>>>> +
>>>> +static void *
>>>> +memarea_alloc_area(const struct rte_memarea_param *init)
>>>> +{
>>>> +    void *ptr = NULL;
>>>> +
>>>> +    if (init->source == RTE_MEMAREA_SOURCE_RTE_MEMORY)
>>>
>>> Delete MEMORY. Of course it's memory. What else? If you want to make 
>>> it clear it's from the RTE heap, it should spell out HEAP. Or MALLOC.
>>
>> HEAP seem better.
>>
>>>
>>>> +        ptr = rte_malloc_socket(NULL, init->total_sz, 
>>>> RTE_CACHE_LINE_SIZE,
>>>> +                    init->numa_socket);
>>>> +    else if (init->source == RTE_MEMAREA_SOURCE_SYSTEM_API)
>>>> +        ptr = memarea_alloc_from_system_api(init->total_sz);
>>>
>>> "SYSTEM_API" doesn't strike me as a good name.
>>>
>>> RTE_MEMAREA_SOURCE_LIBC
>>
>> LIBC seem better.
>>
>>> RTE_MEMAREA_SOURCE_STD_HEAP
>>> or at least remove API so it'll be
>>> RTE_MEMAREA_SOURCE_SYSTEM
>>>
>>>> +    else if (init->source == RTE_MEMAREA_SOURCE_USER_ADDR)
>>>
>>> I would delete "ADDR".
>>
>> +1
>>
>>>
>>>> +        ptr = init->user_addr;
>>>> +
>>>> +    if (ptr == NULL)
>>>> +        RTE_LOG(ERR, MEMAREA, "memarea: %s alloc memory area 
>>>> fail!\n", init->name);
>>>> +
>>>> +    return ptr;
>>>> +}
>>>> +
>>>> +struct rte_memarea *
>>>> +rte_memarea_create(const struct rte_memarea_param *init)
>>>> +{
>>>> +    struct memarea_elem *elem;
>>>> +    struct rte_memarea *ma;
>>>> +    void *addr;
>>>> +    int ret;
>>>> +
>>>> +    ret = memarea_check_param(init);
>>>> +    if (ret)
>>>> +        return NULL;
>>>> +
>>>> +    addr = memarea_alloc_area(init);
>>>> +    if (addr == NULL)
>>>> +        return NULL;
>>>> +
>>>> +    ma = rte_zmalloc(NULL, sizeof(struct rte_memarea), 
>>>> RTE_CACHE_LINE_SIZE);
>>>> +    if (ma == NULL) {
>>>> +        RTE_LOG(ERR, MEMAREA, "malloc memarea: %s management obj 
>>>> fail!\n", init->name);
>>>> +        return NULL;
>>>> +    }
>>>> +
>>>> +    ma->init = *init;
>>>> +    rte_spinlock_init(&ma->lock);
>>>> +    TAILQ_INIT(&ma->elem_list);
>>>> +    TAILQ_INIT(&ma->free_list);
>>>> +    ma->area_addr = addr;
>>>> +    elem = addr;
>>>> +    elem->size = init->total_sz - sizeof(struct memarea_elem);
>>>> +    elem->cookie = MEMAREA_FREE_ELEM_COOKIE;
>>>> +    elem->refcnt = 0;
>>>> +    TAILQ_INSERT_TAIL(&ma->elem_list, elem, elem_node);
>>>> +    TAILQ_INSERT_TAIL(&ma->free_list, elem, free_node);
>>>> +
>>>> +    return ma;
>>>> +}
>>>> +
>>>> +static void
>>>> +memarea_free_area(struct rte_memarea *ma)
>>>> +{
>>>> +    if (ma->init.source == RTE_MEMAREA_SOURCE_RTE_MEMORY)
>>>> +        rte_free(ma->area_addr);
>>>> +    else if (ma->init.source == RTE_MEMAREA_SOURCE_SYSTEM_API)
>>>> +        free(ma->area_addr);
>>>> +}
>>>> +
>>>> +void
>>>> +rte_memarea_destroy(struct rte_memarea *ma)
>>>> +{
>>>> +    if (ma == NULL)
>>>> +        return;
>>>> +    memarea_free_area(ma);
>>>> +    rte_free(ma);
>>>> +}
>>>> diff --git a/lib/memarea/rte_memarea.h b/lib/memarea/rte_memarea.h
>>>> new file mode 100644
>>>> index 0000000000..543cda4cac
>>>> --- /dev/null
>>>> +++ b/lib/memarea/rte_memarea.h
>>>> @@ -0,0 +1,145 @@
>>>> +/* SPDX-License-Identifier: BSD-3-Clause
>>>> + * Copyright(c) 2022 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 default alignment size is RTE_CACHE_LINE_SIZE.
>>>
>>> This can be read as two things: the object size is aligned, or the 
>>> start address is aligned.
>>
>> It means the start address align, will define more clear in v6.
>>
>>>
>>>> + * - The memory region can be initialized from the following 
>>>> memory sources:
>>>> + *   1. RTE memory: e.g. invoke rte_malloc_socket to obtain.
>>>
>>> Remove "to obtain", or add "memory" after "obtain". Do you really 
>>> mean "e.g.", and not "i.e."?
>>
>> will fix in v6.
>>
>>>
>>>> + *   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.
>>>
>>> What is extended memory?
>>
>> Like rte_extmen
>>
>>>
>>>> + *   4) User provided memarea: it can be from another memarea. So 
>>>> we can build
>>>> + *      the following memory management structure:
>>>> + *         \code{.unparsed}
>>>> + *                           -------------
>>>> + *                           | memarea-1 |
>>>> + *                           -------------
>>>> + *                                 |
>>>> + *                                 v
>>>> + *                  -------------------------------
>>>> + *                  |               |             |
>>>> + *                  v               v             v
>>>> + *            -------------   -------------   ----------
>>>> + *            | memarea-2 |   | memarea-3 |   | object |
>>>> + *            -------------   -------------   ----------
>>>> + *         \endcode
>>>> + *      As shown above, the memarea-2/3 both create from 
>>>> memarea-1's memory.
>>>> + * - 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. 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 <stdbool.h>
>>>> +#include <stdint.h>
>>>> +#include <stdio.h>
>>>> +
>>>> +#include <rte_compat.h>
>>>> +
>>>> +#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_RTE_MEMORY,
>>>> +    /** Memory source comes from system API. */
>>>> +    RTE_MEMAREA_SOURCE_SYSTEM_API,
>>>> +    /** Memory source comes from user-provided address. */
>>>> +    RTE_MEMAREA_SOURCE_USER_ADDR,
>>>> +    /** Memory source comes from user-provided memarea. */
>>>> +    RTE_MEMAREA_SOURCE_USER_MEMAREA,
>>>> +};
>>>> +
>>>> +/**
>>>> + * Memarea memory management algorithm.
>>>> + */
>>>> +enum rte_memarea_alg {
>>>> +    /* The default management algorithm is a variant of the next fit
>>>> +     * algorithm. It uses a free-list to apply for memory and uses an
>>>> +     * element-list in ascending order of address to support merging
>>>> +     * upon free.
>>>> +     */
>>>> +    RTE_MEMAREA_ALG_DEFAULT,
>>>> +};
>
> Do you need to expose the algorithm/management scheme option in the 
> public API, if there is only one implementation to choose from?


Yes, we plan to support SLAB algorithm in future by adding a new alg.


>
> You can always have a rte_memarea_create_alg(/../) in the future, or 
> just change the signature between ABI-breaking releases.


I don't think add a new API is a good idea.

You can see that, we put all init parameter in one struct in this 
design, and could extend function by adding new field .


>
>
> Also, shouldn't the default algorithm have name? Rather than just 
> DEFAULT. RTE_MEMAREA_ALG_NEXTFIT maybe.


Yes, will fix in next version.


>
>>>> +
>>>> +struct rte_memarea;
>>>> +
>>>> +struct rte_memarea_param {
>>>
>>> Does this struct need to be public?
>>
>> Yes, the rte_memarea_param contains create parameters for create 
>> memarea which need be public.
>>
>
> Why isn't the public API just a bunch of create-function parameters? 
> Or, alternatively, you have an assortment of create functions, for 
> different combinations of parameters. Then you don't have to think 
> about having reserved bits or other kind of ABI-related issues due to 
> the struct being public.


These are two API design styles,and I prefer the one create-function API 
style just it seem simple (by inner usage voice).


>
>> And rte_memarea which pointer implementation struction which just a 
>> declare here.
>>
>>>
>>>> +    char name[RTE_MEMAREA_NAMESIZE]; /**< Name of memarea. */
>>>> +    enum rte_memarea_source source;  /**< Memory source of 
>>>> memarea. */
>>>> +    enum rte_memarea_alg 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;
>>>
>>> Why not bool?
>>
>> Use bit field other than bool will provides more reserved field.
>>
>>>
>>>> +    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_RTE_MEMORY.
>>>> +         */
>>>> +        int numa_socket;
>>>> +        /** User provided address, this field is valid only when the
>>>> +         * source is set to be RTE_MEMAREA_SOURCE_USER_ADDR.
>>>> +         * Note: the provided address must align at least
>>>> +         * RTE_CACHE_LINE_SIZE.
>>>> +         */
>>>> +        void *user_addr;
>>>> +        /** User provided memarea, this field is valid only when the
>>>> +         * source is set to be RTE_MEMAREA_SOURCE_USER_MEMAREA.
>>>> +         */
>>>> +        struct rte_memarea *user_memarea;
>>>> +    };
>>>> +};
>>>> +
>>>> +/**
>>>> + * @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 c648f7d800..521a25d6c0 100644
>>>> --- a/lib/meson.build
>>>> +++ b/lib/meson.build
>>>> @@ -42,6 +42,7 @@ libraries = [
>>>>            'kni',
>>>>            'latencystats',
>>>>            'lpm',
>>>> +        'memarea',
>>>>            'member',
>>>>            'pcapng',
>>>>            'power',
>>>
>>> .
>

^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v8 0/9] introduce memarea library
  2022-07-21  4:46 [RFC] memarea: introduce memory area library Chengwen Feng
                   ` (11 preceding siblings ...)
  2022-10-08 11:58 ` [PATCH v7 00/10] introduce memarea library Chengwen Feng
@ 2022-10-11 12:17 ` Chengwen Feng
  2022-10-11 12:17   ` [PATCH v8 1/9] memarea: " Chengwen Feng
                     ` (8 more replies)
  2022-10-12 10:47 ` [PATCH v9 0/7] introduce memarea library Chengwen Feng
                   ` (10 subsequent siblings)
  23 siblings, 9 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-10-11 12:17 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk, hofors
  Cc: thomas, dev

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

- The allocated object aligned at RTE_CACHE_LINE_SIZE default.

- 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. User memory: it can be from e.g. rte_extmem_xxx as long as it is
     available. The memory's start address must be aligned to
     RTE_CACHE_LINE_SIZE.
  4. Another 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. It will attempts to allocate object from backup
  memarea when the current memarea failed to allocate.

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 <fengchengwen@huawei.com>

Chengwen Feng (9):
  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
  app/test: add memarea to malloc-perf-autotest

---
v8:
* address Mattias's comments (rename ALG_DEFAULT with ALG_NEXTFIT).
* small feature patches are combined.
* enhanced backup memory mechanism.
* add memarea to malloc-perf-autotest.
* other tiny naming optimize.
v7:
* repost patches as there are spread over different series in patchwork.
v6:
* address Mattias's comments.
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_malloc_perf.c            |  55 ++-
 app/test/test_memarea.c                | 442 +++++++++++++++++++++++
 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  |  56 +++
 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          |  39 ++
 lib/memarea/meson.build                |  16 +
 lib/memarea/rte_memarea.c              | 476 +++++++++++++++++++++++++
 lib/memarea/rte_memarea.h              | 223 ++++++++++++
 lib/memarea/version.map                |  16 +
 lib/meson.build                        |   1 +
 17 files changed, 1343 insertions(+), 2 deletions(-)
 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.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v8 1/9] memarea: introduce memarea library
  2022-10-11 12:17 ` [PATCH v8 0/9] " Chengwen Feng
@ 2022-10-11 12:17   ` Chengwen Feng
  2022-10-11 15:58     ` Dmitry Kozlyuk
  2022-10-11 12:17   ` [PATCH v8 2/9] test/memarea: support memarea test Chengwen Feng
                     ` (7 subsequent siblings)
  8 siblings, 1 reply; 222+ messages in thread
From: Chengwen Feng @ 2022-10-11 12:17 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk, hofors
  Cc: thomas, dev

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 <fengchengwen@huawei.com>
---
 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          |  33 ++++++
 lib/memarea/meson.build                |  16 +++
 lib/memarea/rte_memarea.c              | 158 +++++++++++++++++++++++++
 lib/memarea/rte_memarea.h              | 136 +++++++++++++++++++++
 lib/memarea/version.map                |  12 ++
 lib/meson.build                        |   1 +
 14 files changed, 412 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 2bd4a55f1b..3d8d4c2dbe 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1551,6 +1551,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 <fengchengwen@huawei.com>
+F: lib/memarea
+F: doc/guides/prog_guide/memarea_lib.rst
+
 Membership - EXPERIMENTAL
 M: Yipeng Wang <yipeng1.wang@intel.com>
 M: Sameh Gobriel <sameh.gobriel@intel.com>
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..85ad57145f
--- /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 allocated object aligned at ``RTE_CACHE_LINE_SIZE`` default.
+
+* The memory region can be initialized from the following memory sources:
+  a) HEAP: e.g. invoke ``rte_malloc_socket``. b) LIBC: e.g. invoke
+  posix_memalign to obtain. c) User memory: it can be from e.g. rte_extmem_xxx
+  as long as it is available. d) Another memarea: it can be allocated 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 2da8bc9661..f5a67cec7b 100644
--- a/doc/guides/rel_notes/release_22_11.rst
+++ b/doc/guides/rel_notes/release_22_11.rst
@@ -63,6 +63,12 @@ New Features
   In theory this implementation should work with any target based on
   ``LoongArch`` ISA.
 
+* **Added memarea library.**
+
+  The memarea library is an allocator of variable-size objects, it is oriented
+  towards the application layer, which could provides 'region-based memory
+  management' function.
+
 * **Added support for multiple mbuf pools per ethdev Rx queue.**
 
   The capability allows application to provide many mempools
diff --git a/lib/eal/common/eal_common_log.c b/lib/eal/common/eal_common_log.c
index bd7b188ceb..3d62af59c6 100644
--- a/lib/eal/common/eal_common_log.c
+++ b/lib/eal/common/eal_common_log.c
@@ -369,6 +369,7 @@ static const struct logtype logtype_strings[] = {
 	{RTE_LOGTYPE_EFD,        "lib.efd"},
 	{RTE_LOGTYPE_EVENTDEV,   "lib.eventdev"},
 	{RTE_LOGTYPE_GSO,        "lib.gso"},
+	{RTE_LOGTYPE_MEMAREA,    "lib.memarea"},
 	{RTE_LOGTYPE_USER1,      "user1"},
 	{RTE_LOGTYPE_USER2,      "user2"},
 	{RTE_LOGTYPE_USER3,      "user3"},
diff --git a/lib/eal/include/rte_log.h b/lib/eal/include/rte_log.h
index 25ce42cdfc..708f3a39dd 100644
--- a/lib/eal/include/rte_log.h
+++ b/lib/eal/include/rte_log.h
@@ -48,6 +48,7 @@ extern "C" {
 #define RTE_LOGTYPE_EFD       18 /**< Log related to EFD. */
 #define RTE_LOGTYPE_EVENTDEV  19 /**< Log related to eventdev. */
 #define RTE_LOGTYPE_GSO       20 /**< Log related to GSO. */
+#define RTE_LOGTYPE_MEMAREA   21 /**< Log related to memarea. */
 
 /* these log types can be used in an application */
 #define RTE_LOGTYPE_USER1     24 /**< User-defined log type 1. */
diff --git a/lib/memarea/memarea_private.h b/lib/memarea/memarea_private.h
new file mode 100644
index 0000000000..59be9c1d00
--- /dev/null
+++ b/lib/memarea/memarea_private.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2022 HiSilicon Limited
+ */
+
+#ifndef MEMAREA_PRIVATE_H
+#define MEMAREA_PRIVATE_H
+
+#include <rte_memarea.h>
+
+#define MEMAREA_AVAILABLE_ELEM_MAGIC	0xbeef1234
+#define MEMAREA_ALLOCATED_ELEM_MAGIC	0xbeef1230
+#define MEMAREA_AVAILABLE_ELEM_COOKIE	0xffffffff
+
+struct memarea_elem {
+	TAILQ_ENTRY(memarea_elem) elem_node;
+	TAILQ_ENTRY(memarea_elem) free_node;
+	size_t   size;
+	uint32_t magic;
+	uint32_t cookie;
+	int32_t  refcnt; /* Non-zero indicates that it has been allocated */
+} __rte_cache_aligned;
+
+TAILQ_HEAD(memarea_elem_list, memarea_elem);
+
+struct rte_memarea {
+	struct rte_memarea_param init;
+	rte_spinlock_t           lock;
+	void                    *area_addr;
+	struct memarea_elem_list elem_list;
+	struct memarea_elem_list free_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..0a74fb4cd1
--- /dev/null
+++ b/lib/memarea/meson.build
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2022 HiSilicon Limited
+
+if is_windows
+    build = false
+    reason = 'not supported on Windows'
+    subdir_done()
+endif
+
+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..85975029e2
--- /dev/null
+++ b/lib/memarea/rte_memarea.c
@@ -0,0 +1,158 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2022 HiSilicon Limited
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <rte_common.h>
+#include <rte_log.h>
+#include <rte_malloc.h>
+#include <rte_spinlock.h>
+
+#include "rte_memarea.h"
+#include "memarea_private.h"
+
+static int
+memarea_check_param(const struct rte_memarea_param *init)
+{
+	size_t len;
+
+	if (init == NULL) {
+		RTE_LOG(ERR, MEMAREA, "memarea init param is NULL!\n");
+		return -EINVAL;
+	}
+
+	len = strnlen(init->name, RTE_MEMAREA_NAMESIZE);
+	if (len == 0 || len >= RTE_MEMAREA_NAMESIZE) {
+		RTE_LOG(ERR, MEMAREA, "memarea name size %zu invalid!\n", len);
+		return -EINVAL;
+	}
+
+	if (init->source != RTE_MEMAREA_SOURCE_HEAP &&
+	    init->source != RTE_MEMAREA_SOURCE_LIBC &&
+	    init->source != RTE_MEMAREA_SOURCE_USER &&
+	    init->source != RTE_MEMAREA_SOURCE_MEMAREA) {
+		RTE_LOG(ERR, MEMAREA, "memarea: %s source: %d not supported!\n",
+			init->name, init->source);
+		return -EINVAL;
+	}
+
+	if (init->total_sz <= sizeof(struct memarea_elem)) {
+		RTE_LOG(ERR, MEMAREA, "memarea: %s total-size: %zu too small!\n",
+			init->name, init->total_sz);
+		return -EINVAL;
+	}
+
+	if (init->source == RTE_MEMAREA_SOURCE_USER && init->user_addr == NULL) {
+		RTE_LOG(ERR, MEMAREA, "memarea: %s user memory address is NULL!\n", init->name);
+		return -EINVAL;
+	}
+
+	if (init->source == RTE_MEMAREA_SOURCE_USER &&
+	    ((uintptr_t)init->user_addr & (RTE_CACHE_LINE_SIZE - 1))) {
+		RTE_LOG(ERR, MEMAREA, "memarea: %s user memory address should align: %d!\n",
+			init->name, RTE_CACHE_LINE_SIZE);
+		return -EINVAL;
+	}
+
+	if (init->source == RTE_MEMAREA_SOURCE_MEMAREA && init->src_memarea == NULL) {
+		RTE_LOG(ERR, MEMAREA, "memarea: %s source memarea is NULL!\n", init->name);
+		return -EINVAL;
+	}
+
+	if (init->alg != RTE_MEMAREA_ALG_NEXTFIT) {
+		RTE_LOG(ERR, MEMAREA, "memarea: %s alg: %d not supported!\n",
+			init->name, init->alg);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void *
+memarea_alloc_from_libc(size_t size)
+{
+	void *ptr = NULL;
+	int ret;
+
+	ret = posix_memalign(&ptr, RTE_CACHE_LINE_SIZE, size);
+	if (ret)
+		return NULL;
+	return ptr;
+}
+
+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);
+	else if (init->source == RTE_MEMAREA_SOURCE_USER)
+		ptr = init->user_addr;
+
+	if (ptr == NULL)
+		RTE_LOG(ERR, MEMAREA, "memarea: %s alloc memory area fail!\n", init->name);
+
+	return ptr;
+}
+
+struct rte_memarea *
+rte_memarea_create(const struct rte_memarea_param *init)
+{
+	struct memarea_elem *elem;
+	struct rte_memarea *ma;
+	void *addr;
+	int ret;
+
+	ret = memarea_check_param(init);
+	if (ret)
+		return NULL;
+
+	addr = memarea_alloc_area(init);
+	if (addr == NULL)
+		return NULL;
+
+	ma = rte_zmalloc(NULL, sizeof(struct rte_memarea), RTE_CACHE_LINE_SIZE);
+	if (ma == NULL) {
+		RTE_LOG(ERR, MEMAREA, "malloc memarea: %s management obj fail!\n", init->name);
+		return NULL;
+	}
+
+	ma->init = *init;
+	rte_spinlock_init(&ma->lock);
+	TAILQ_INIT(&ma->elem_list);
+	TAILQ_INIT(&ma->free_list);
+	ma->area_addr = addr;
+	elem = addr;
+	TAILQ_INSERT_TAIL(&ma->elem_list, elem, elem_node);
+	TAILQ_INSERT_TAIL(&ma->free_list, elem, free_node);
+	elem->size = init->total_sz - sizeof(struct memarea_elem);
+	elem->magic = MEMAREA_AVAILABLE_ELEM_MAGIC;
+	elem->cookie = MEMAREA_AVAILABLE_ELEM_COOKIE;
+	elem->refcnt = 0;
+
+	return ma;
+}
+
+static void
+memarea_free_area(struct rte_memarea *ma)
+{
+	if (ma->init.source == RTE_MEMAREA_SOURCE_HEAP)
+		rte_free(ma->area_addr);
+	else if (ma->init.source == RTE_MEMAREA_SOURCE_LIBC)
+		free(ma->area_addr);
+}
+
+void
+rte_memarea_destroy(struct rte_memarea *ma)
+{
+	if (ma == NULL)
+		return;
+	memarea_free_area(ma);
+	rte_free(ma);
+}
diff --git a/lib/memarea/rte_memarea.h b/lib/memarea/rte_memarea.h
new file mode 100644
index 0000000000..ac2d63a4d3
--- /dev/null
+++ b/lib/memarea/rte_memarea.h
@@ -0,0 +1,136 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2022 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 allocated object aligned at RTE_CACHE_LINE_SIZE default.
+ *
+ * - 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. User memory: it can be from e.g. rte_extmem_xxx as long as it is
+ *      available. The memory's start address must be aligned to
+ *      RTE_CACHE_LINE_SIZE.
+ *   4. Another memarea: it can be allocated 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. 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 <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include <rte_compat.h>
+
+#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 user memory. */
+	RTE_MEMAREA_SOURCE_USER,
+	/** Memory source comes from another memarea. */
+	RTE_MEMAREA_SOURCE_MEMAREA,
+};
+
+/**
+ * Memarea memory management algorithm.
+ */
+enum rte_memarea_alg {
+	/** The default management algorithm is a variant of the next fit
+	 * algorithm. It uses a free-list to apply for memory and uses an
+	 * element-list in ascending order of address to support merging
+	 * upon free.
+	 */
+	RTE_MEMAREA_ALG_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_alg 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;
+		/** User memory address, this field is valid only when the
+		 * source is set to be RTE_MEMAREA_SOURCE_USER.
+		 * Note: the address must align at least RTE_CACHE_LINE_SIZE.
+		 */
+		void *user_addr;
+		/** Source memarea, this field is valid only when the source is
+		 * set to be RTE_MEMAREA_SOURCE_MEMAREA.
+		 */
+		struct rte_memarea *src_memarea;
+	};
+};
+
+/**
+ * @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 c51cdc24fa..87d621e792 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -42,6 +42,7 @@ libraries = [
         'kni',
         'latencystats',
         'lpm',
+        'memarea',
         'member',
         'pcapng',
         'power',
-- 
2.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v8 2/9] test/memarea: support memarea test
  2022-10-11 12:17 ` [PATCH v8 0/9] " Chengwen Feng
  2022-10-11 12:17   ` [PATCH v8 1/9] memarea: " Chengwen Feng
@ 2022-10-11 12:17   ` Chengwen Feng
  2022-10-11 12:17   ` [PATCH v8 3/9] memarea: support alloc/free/update-refcnt API Chengwen Feng
                     ` (6 subsequent siblings)
  8 siblings, 0 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-10-11 12:17 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk, hofors
  Cc: thomas, dev

This patch supports memarea test about API rte_memarea_create and
rte_memarea_destroy.

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 MAINTAINERS             |   1 +
 app/test/meson.build    |   2 +
 app/test/test_memarea.c | 168 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 171 insertions(+)
 create mode 100644 app/test/test_memarea.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 3d8d4c2dbe..38625ae1be 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1555,6 +1555,7 @@ Memarea - EXPERIMENTAL
 M: Chengwen Feng <fengchengwen@huawei.com>
 F: lib/memarea
 F: doc/guides/prog_guide/memarea_lib.rst
+F: app/test/test_memarea*
 
 Membership - EXPERIMENTAL
 M: Yipeng Wang <yipeng1.wang@intel.com>
diff --git a/app/test/meson.build b/app/test/meson.build
index 396b133959..8943f24668 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..f02b33394f
--- /dev/null
+++ b/app/test/test_memarea.c
@@ -0,0 +1,168 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2022 HiSilicon Limited
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#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 <rte_memory.h>
+#include <rte_memarea.h>
+
+#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", "test-memarea");
+	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;
+	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_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 user memory address NULL */
+	test_memarea_init_param(&init);
+	init.source = RTE_MEMAREA_SOURCE_USER;
+	ma = rte_memarea_create(&init);
+	RTE_TEST_ASSERT(ma == NULL, "Expected NULL");
+
+	/* test for user memory address align invalid */
+	test_memarea_init_param(&init);
+	init.source = RTE_MEMAREA_SOURCE_USER;
+	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 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 alg invalid */
+	test_memarea_init_param(&init);
+	init.alg = RTE_MEMAREA_ALG_NEXTFIT + 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 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);
+
+	/* test for create with user memory */
+	test_memarea_init_param(&init);
+	init.source = RTE_MEMAREA_SOURCE_USER;
+	init.user_addr = (void *)(((uintptr_t)user_buffer + RTE_CACHE_LINE_SIZE) &
+				  ~(RTE_CACHE_LINE_SIZE - 1));
+	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();
+}
+
+#endif /* !RTE_EXEC_ENV_WINDOWS */
+
+REGISTER_TEST_COMMAND(memarea_autotest, test_memarea);
-- 
2.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v8 3/9] memarea: support alloc/free/update-refcnt API
  2022-10-11 12:17 ` [PATCH v8 0/9] " Chengwen Feng
  2022-10-11 12:17   ` [PATCH v8 1/9] memarea: " Chengwen Feng
  2022-10-11 12:17   ` [PATCH v8 2/9] test/memarea: support memarea test Chengwen Feng
@ 2022-10-11 12:17   ` Chengwen Feng
  2022-10-11 15:58     ` Dmitry Kozlyuk
  2022-10-11 12:17   ` [PATCH v8 4/9] test/memarea: support alloc/free/update-refcnt test Chengwen Feng
                     ` (5 subsequent siblings)
  8 siblings, 1 reply; 222+ messages in thread
From: Chengwen Feng @ 2022-10-11 12:17 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk, hofors
  Cc: thomas, dev

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

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 doc/guides/prog_guide/memarea_lib.rst |  10 ++
 lib/memarea/memarea_private.h         |   3 +
 lib/memarea/rte_memarea.c             | 155 ++++++++++++++++++++++++++
 lib/memarea/rte_memarea.h             |  56 ++++++++++
 lib/memarea/version.map               |   3 +
 5 files changed, 227 insertions(+)

diff --git a/doc/guides/prog_guide/memarea_lib.rst b/doc/guides/prog_guide/memarea_lib.rst
index 85ad57145f..a9c58dc44d 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 59be9c1d00..f5accf2987 100644
--- a/lib/memarea/memarea_private.h
+++ b/lib/memarea/memarea_private.h
@@ -28,6 +28,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 85975029e2..8ad1c0acb5 100644
--- a/lib/memarea/rte_memarea.c
+++ b/lib/memarea/rte_memarea.c
@@ -4,6 +4,7 @@
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <sys/queue.h>
 
 #include <rte_common.h>
 #include <rte_log.h>
@@ -94,6 +95,8 @@ memarea_alloc_area(const struct rte_memarea_param *init)
 		ptr = memarea_alloc_from_libc(init->total_sz);
 	else if (init->source == RTE_MEMAREA_SOURCE_USER)
 		ptr = init->user_addr;
+	else if (init->source == RTE_MEMAREA_SOURCE_MEMAREA)
+		ptr = rte_memarea_alloc(init->src_memarea, init->total_sz, 0);
 
 	if (ptr == NULL)
 		RTE_LOG(ERR, MEMAREA, "memarea: %s alloc memory area fail!\n", init->name);
@@ -146,6 +149,8 @@ memarea_free_area(struct rte_memarea *ma)
 		rte_free(ma->area_addr);
 	else if (ma->init.source == RTE_MEMAREA_SOURCE_LIBC)
 		free(ma->area_addr);
+	else if (ma->init.source == RTE_MEMAREA_SOURCE_MEMAREA)
+		rte_memarea_free(ma->init.src_memarea, ma->area_addr);
 }
 
 void
@@ -156,3 +161,153 @@ 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);
+}
+
+static inline bool
+memarea_whether_add_node(size_t free_size, size_t need_size)
+{
+	size_t align_size = RTE_ALIGN_CEIL(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 = RTE_ALIGN_CEIL(need_size, RTE_CACHE_LINE_SIZE);
+	struct memarea_elem *new_elem;
+	new_elem = (struct memarea_elem *)RTE_PTR_ADD(elem, sizeof(struct memarea_elem) +
+							    align_size);
+	new_elem->size = elem->size - align_size - sizeof(struct memarea_elem);
+	new_elem->magic = MEMAREA_AVAILABLE_ELEM_MAGIC;
+	new_elem->cookie = MEMAREA_AVAILABLE_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 (unlikely(elem->magic != MEMAREA_AVAILABLE_ELEM_MAGIC))
+			break;
+		if (elem->size < size)
+			continue;
+		if (memarea_whether_add_node(elem->size, size))
+			memarea_add_node(ma, elem, size);
+		elem->magic = MEMAREA_ALLOCATED_ELEM_MAGIC;
+		elem->cookie = cookie;
+		elem->refcnt = 1;
+		TAILQ_REMOVE(&ma->free_list, elem, free_node);
+		ptr = RTE_PTR_ADD(elem, sizeof(struct memarea_elem));
+		break;
+	}
+	if (unlikely(ptr == NULL))
+		ma->alloc_fails++;
+	memarea_unlock(ma);
+
+	return ptr;
+}
+
+void
+rte_memarea_free(struct rte_memarea *ma, void *ptr)
+{
+	rte_memarea_update_refcnt(ma, ptr, -1);
+}
+
+static inline void
+memarea_merge_node(struct rte_memarea *ma, struct memarea_elem *curr,
+		   struct memarea_elem *next, bool del_next_from_free,
+		   bool add_curr_to_free)
+{
+	curr->size += next->size + sizeof(struct memarea_elem);
+	next->size = 0;
+	next->magic = 0;
+	next->cookie = 0;
+	TAILQ_REMOVE(&ma->elem_list, next, elem_node);
+	if (del_next_from_free)
+		TAILQ_REMOVE(&ma->free_list, next, free_node);
+	if (add_curr_to_free) {
+		curr->magic = MEMAREA_AVAILABLE_ELEM_MAGIC;
+		curr->cookie = MEMAREA_AVAILABLE_ELEM_COOKIE;
+		TAILQ_INSERT_TAIL(&ma->free_list, curr, free_node);
+	}
+}
+
+static inline void
+memarea_free_elem(struct rte_memarea *ma, struct memarea_elem *elem)
+{
+	struct memarea_elem *prev, *next;
+	bool merged = false;
+	prev = TAILQ_PREV(elem, memarea_elem_list, elem_node);
+	next = TAILQ_NEXT(elem, elem_node);
+	if (prev != NULL && prev->refcnt == 0) {
+		memarea_merge_node(ma, prev, elem, false, false);
+		elem = prev;
+		merged = true;
+	}
+	if (next != NULL && next->refcnt == 0) {
+		memarea_merge_node(ma, elem, next, true, !merged);
+		merged = true;
+	}
+	if (!merged) {
+		elem->magic = MEMAREA_AVAILABLE_ELEM_MAGIC;
+		elem->cookie = MEMAREA_AVAILABLE_ELEM_COOKIE;
+		TAILQ_INSERT_TAIL(&ma->free_list, elem, free_node);
+	}
+}
+
+void
+rte_memarea_update_refcnt(struct rte_memarea *ma, void *ptr, int16_t value)
+{
+	struct memarea_elem *elem = (struct memarea_elem *)RTE_PTR_SUB(ptr,
+							    sizeof(struct memarea_elem));
+
+	if (unlikely(ma == NULL || ptr == NULL))
+		return;
+
+	memarea_lock(ma);
+	if (unlikely(elem->magic != MEMAREA_ALLOCATED_ELEM_MAGIC)) {
+		RTE_LOG(ERR, MEMAREA, "memarea: %s magic: 0x%x check fail!\n",
+			ma->init.name, elem->magic);
+		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",
+			ma->init.name, elem->cookie, elem->refcnt, value);
+		ma->refcnt_check_fails++;
+		if (elem->refcnt > 0)
+			elem->refcnt += value;
+		memarea_unlock(ma);
+		return;
+	}
+
+	elem->refcnt += value;
+	if (elem->refcnt == 0)
+		memarea_free_elem(ma, elem);
+	memarea_unlock(ma);
+}
diff --git a/lib/memarea/rte_memarea.h b/lib/memarea/rte_memarea.h
index ac2d63a4d3..f866fa7b67 100644
--- a/lib/memarea/rte_memarea.h
+++ b/lib/memarea/rte_memarea.h
@@ -129,6 +129,62 @@ 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.
+ * @param cookie
+ *   User-provided footprint which could used to debug memory leak.
+ *
+ * @return
+ *   Non-NULL on success. Otherwise NULL is returned.
+ */
+__rte_experimental
+void *rte_memarea_alloc(struct rte_memarea *ma, size_t size, uint32_t cookie);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Free memory to memarea.
+ *
+ * Free one memory object to the memarea.
+ *
+ * @param ma
+ *   The pointer of memarea.
+ * @param ptr
+ *   The pointer of memory object which need be freed.
+ */
+__rte_experimental
+void rte_memarea_free(struct rte_memarea *ma, void *ptr);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Update memory's refcnt.
+ *
+ * Update one memory object's refcnt.
+ * When refcnt is updated to be zero, the memory object is freed.
+ *
+ * @param ma
+ *   The pointer of memarea.
+ * @param ptr
+ *   The pointer of memory object which need be updated refcnt.
+ * @param value
+ *   The value which need be updated.
+ */
+__rte_experimental
+void rte_memarea_update_refcnt(struct rte_memarea *ma, void *ptr, int16_t value);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/memarea/version.map b/lib/memarea/version.map
index f36a04d7cf..a0026fc5f9 100644
--- a/lib/memarea/version.map
+++ b/lib/memarea/version.map
@@ -1,8 +1,11 @@
 EXPERIMENTAL {
 	global:
 
+	rte_memarea_alloc;
 	rte_memarea_create;
 	rte_memarea_destroy;
+	rte_memarea_free;
+	rte_memarea_update_refcnt;
 
 	local: *;
 };
-- 
2.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v8 4/9] test/memarea: support alloc/free/update-refcnt test
  2022-10-11 12:17 ` [PATCH v8 0/9] " Chengwen Feng
                     ` (2 preceding siblings ...)
  2022-10-11 12:17   ` [PATCH v8 3/9] memarea: support alloc/free/update-refcnt API Chengwen Feng
@ 2022-10-11 12:17   ` Chengwen Feng
  2022-10-11 12:17   ` [PATCH v8 5/9] memarea: support dump API Chengwen Feng
                     ` (4 subsequent siblings)
  8 siblings, 0 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-10-11 12:17 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk, hofors
  Cc: thomas, dev

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

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 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 f02b33394f..5f7868f8f6 100644
--- a/app/test/test_memarea.c
+++ b/app/test/test_memarea.c
@@ -57,6 +57,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)
 {
@@ -122,8 +128,8 @@ static int
 test_memarea_create_destroy(void)
 {
 	uint8_t user_buffer[MEMAREA_TEST_DEFAULT_SIZE + RTE_CACHE_LINE_SIZE];
+	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);
@@ -149,6 +155,145 @@ 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_memarea = 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, 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_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_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_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 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_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_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)
+{
+#define ALLOC_MAX_NUM	8
+	struct rte_memarea_param init;
+	struct rte_memarea *ma;
+	void *ptr[ALLOC_MAX_NUM];
+	int i;
+
+	/* prepare env */
+	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, 0);
+
+	/* 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;
 }
 
@@ -159,6 +304,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();
 }
-- 
2.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v8 5/9] memarea: support dump API
  2022-10-11 12:17 ` [PATCH v8 0/9] " Chengwen Feng
                     ` (3 preceding siblings ...)
  2022-10-11 12:17   ` [PATCH v8 4/9] test/memarea: support alloc/free/update-refcnt test Chengwen Feng
@ 2022-10-11 12:17   ` Chengwen Feng
  2022-10-11 12:17   ` [PATCH v8 6/9] test/memarea: support dump test Chengwen Feng
                     ` (3 subsequent siblings)
  8 siblings, 0 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-10-11 12:17 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk, hofors
  Cc: thomas, dev

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

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 doc/guides/prog_guide/memarea_lib.rst |  3 +
 lib/memarea/rte_memarea.c             | 98 +++++++++++++++++++++++++++
 lib/memarea/rte_memarea.h             | 21 ++++++
 lib/memarea/version.map               |  1 +
 4 files changed, 123 insertions(+)

diff --git a/doc/guides/prog_guide/memarea_lib.rst b/doc/guides/prog_guide/memarea_lib.rst
index a9c58dc44d..8b616b57e6 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 8ad1c0acb5..163ebfa792 100644
--- a/lib/memarea/rte_memarea.c
+++ b/lib/memarea/rte_memarea.c
@@ -2,6 +2,7 @@
  * Copyright(c) 2022 HiSilicon Limited
  */
 
+#include <inttypes.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/queue.h>
@@ -311,3 +312,100 @@ 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_HEAP)
+		return "heap";
+	else if (source == RTE_MEMAREA_SOURCE_LIBC)
+		return "libc";
+	else if (source == RTE_MEMAREA_SOURCE_USER)
+		return "user";
+	else if (source == RTE_MEMAREA_SOURCE_MEMAREA)
+		return "memarea";
+	else
+		return "unknown";
+}
+
+static const char *
+memarea_alg_name(enum rte_memarea_alg alg)
+{
+	if (alg == RTE_MEMAREA_ALG_NEXTFIT)
+		return "nextfit";
+	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) {
+		if (elem->magic != MEMAREA_AVAILABLE_ELEM_MAGIC &&
+		    elem->magic != MEMAREA_ALLOCATED_ELEM_MAGIC)
+			break;
+		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) {
+		if (elem->magic != MEMAREA_AVAILABLE_ELEM_MAGIC)
+			break;
+		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) {
+		if (elem->magic != MEMAREA_AVAILABLE_ELEM_MAGIC &&
+		    elem->magic != MEMAREA_ALLOCATED_ELEM_MAGIC) {
+			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
+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_MEMAREA)
+		fprintf(f, "  source-memarea: %s\n", ma->init.src_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 f866fa7b67..5e3f23700b 100644
--- a/lib/memarea/rte_memarea.h
+++ b/lib/memarea/rte_memarea.h
@@ -185,6 +185,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/version.map
@@ -4,6 +4,7 @@ EXPERIMENTAL {
 	rte_memarea_alloc;
 	rte_memarea_create;
 	rte_memarea_destroy;
+	rte_memarea_dump;
 	rte_memarea_free;
 	rte_memarea_update_refcnt;
 
-- 
2.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v8 6/9] test/memarea: support dump test
  2022-10-11 12:17 ` [PATCH v8 0/9] " Chengwen Feng
                     ` (4 preceding siblings ...)
  2022-10-11 12:17   ` [PATCH v8 5/9] memarea: support dump API Chengwen Feng
@ 2022-10-11 12:17   ` Chengwen Feng
  2022-10-11 12:17   ` [PATCH v8 7/9] memarea: support backup memory mechanism Chengwen Feng
                     ` (2 subsequent siblings)
  8 siblings, 0 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-10-11 12:17 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk, hofors
  Cc: thomas, dev

This patch supports rte_memarea_dump() test.

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 app/test/test_memarea.c | 33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/app/test/test_memarea.c b/app/test/test_memarea.c
index 5f7868f8f6..50b92db9b3 100644
--- a/app/test/test_memarea.c
+++ b/app/test/test_memarea.c
@@ -297,6 +297,38 @@ test_memarea_alloc_free(void)
 	return 0;
 }
 
+static int
+test_memarea_dump(void)
+{
+	struct rte_memarea_param init;
+	struct rte_memarea *ma;
+	int ret;
+
+	/* prepare env */
+	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, 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);
+
+	return 0;
+}
+
 static int
 test_memarea(void)
 {
@@ -307,6 +339,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();
 }
-- 
2.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v8 7/9] memarea: support backup memory mechanism
  2022-10-11 12:17 ` [PATCH v8 0/9] " Chengwen Feng
                     ` (5 preceding siblings ...)
  2022-10-11 12:17   ` [PATCH v8 6/9] test/memarea: support dump test Chengwen Feng
@ 2022-10-11 12:17   ` Chengwen Feng
  2022-10-11 15:58     ` Dmitry Kozlyuk
  2022-10-11 12:17   ` [PATCH v8 8/9] test/memarea: support backup memory test Chengwen Feng
  2022-10-11 12:17   ` [PATCH v8 9/9] app/test: add memarea to malloc-perf-autotest Chengwen Feng
  8 siblings, 1 reply; 222+ messages in thread
From: Chengwen Feng @ 2022-10-11 12:17 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk, hofors
  Cc: thomas, dev

This patch adds a memarea backup mechanism, where an allocation request
which cannot be met by the current memarea is deferred to its backup
memarea.

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 doc/guides/prog_guide/memarea_lib.rst |  4 ++
 lib/memarea/memarea_private.h         |  3 ++
 lib/memarea/rte_memarea.c             | 67 ++++++++++++++++++++++++++-
 lib/memarea/rte_memarea.h             | 10 ++++
 4 files changed, 83 insertions(+), 1 deletion(-)

diff --git a/doc/guides/prog_guide/memarea_lib.rst b/doc/guides/prog_guide/memarea_lib.rst
index 8b616b57e6..6b180bb0e4 100644
--- a/doc/guides/prog_guide/memarea_lib.rst
+++ b/doc/guides/prog_guide/memarea_lib.rst
@@ -25,6 +25,10 @@ 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. It will attempts to allocate object from backup memarea when
+  the current memarea failed to allocate.
+
 Library API Overview
 --------------------
 
diff --git a/lib/memarea/memarea_private.h b/lib/memarea/memarea_private.h
index f5accf2987..062e967250 100644
--- a/lib/memarea/memarea_private.h
+++ b/lib/memarea/memarea_private.h
@@ -14,6 +14,7 @@
 struct memarea_elem {
 	TAILQ_ENTRY(memarea_elem) elem_node;
 	TAILQ_ENTRY(memarea_elem) free_node;
+	struct rte_memarea       *owner;
 	size_t   size;
 	uint32_t magic;
 	uint32_t cookie;
@@ -26,11 +27,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 163ebfa792..3de4297cf7 100644
--- a/lib/memarea/rte_memarea.c
+++ b/lib/memarea/rte_memarea.c
@@ -132,9 +132,11 @@ 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 = RTE_PTR_ADD(addr, init->total_sz - 1);
 	elem = addr;
 	TAILQ_INSERT_TAIL(&ma->elem_list, elem, elem_node);
 	TAILQ_INSERT_TAIL(&ma->free_list, elem, free_node);
+	elem->owner = NULL;
 	elem->size = init->total_sz - sizeof(struct memarea_elem);
 	elem->magic = MEMAREA_AVAILABLE_ELEM_MAGIC;
 	elem->cookie = MEMAREA_AVAILABLE_ELEM_COOKIE;
@@ -154,11 +156,41 @@ memarea_free_area(struct rte_memarea *ma)
 		rte_memarea_free(ma->init.src_memarea, ma->area_addr);
 }
 
+static inline void memarea_lock(struct rte_memarea *ma);
+static inline void memarea_unlock(struct rte_memarea *ma);
+static inline void memarea_free_elem(struct rte_memarea *ma, struct memarea_elem *elem);
+
+static void
+memarea_free_owner_objs(struct rte_memarea *ma, struct rte_memarea *owner)
+{
+	struct memarea_elem *elem, *tmp_elem;
+
+	memarea_lock(ma);
+	/* The TAILQ_FOREACH_SAFE is undefined in sys/queue.h, so extend it here. */
+	for (elem = TAILQ_FIRST(&ma->elem_list);
+	     elem && (tmp_elem = TAILQ_NEXT(elem, elem_node), 1);
+	     elem = tmp_elem) {
+		if (elem->owner != owner)
+			continue;
+		elem->refcnt = 0;
+		memarea_free_elem(ma, elem);
+	}
+	if (ma->init.bak_memarea != NULL)
+		memarea_free_owner_objs(ma->init.bak_memarea, owner);
+	memarea_unlock(ma);
+}
+
 void
 rte_memarea_destroy(struct rte_memarea *ma)
 {
 	if (ma == NULL)
 		return;
+	if (ma->init.bak_memarea != NULL) {
+		/* Some objects are allocated from backup memarea, these objects need to be
+		 * freed when the memarea is destroyed.
+		 */
+		memarea_free_owner_objs(ma->init.bak_memarea, ma);
+	}
 	memarea_free_area(ma);
 	rte_free(ma);
 }
@@ -191,6 +223,7 @@ memarea_add_node(struct rte_memarea *ma, struct memarea_elem *elem, size_t need_
 	struct memarea_elem *new_elem;
 	new_elem = (struct memarea_elem *)RTE_PTR_ADD(elem, sizeof(struct memarea_elem) +
 							    align_size);
+	new_elem->owner = NULL;
 	new_elem->size = elem->size - align_size - sizeof(struct memarea_elem);
 	new_elem->magic = MEMAREA_AVAILABLE_ELEM_MAGIC;
 	new_elem->cookie = MEMAREA_AVAILABLE_ELEM_COOKIE;
@@ -200,6 +233,23 @@ memarea_add_node(struct rte_memarea *ma, struct memarea_elem *elem, size_t need_
 	elem->size = align_size;
 }
 
+static inline void
+memarea_mark_owner(struct rte_memarea *ma, void *ptr)
+{
+	struct memarea_elem *elem;
+	elem = (struct memarea_elem *)RTE_PTR_SUB(ptr, sizeof(struct memarea_elem));
+	elem->owner = ma;
+}
+
+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)
 {
@@ -224,7 +274,11 @@ rte_memarea_alloc(struct rte_memarea *ma, size_t size, uint32_t cookie)
 		ptr = RTE_PTR_ADD(elem, sizeof(struct memarea_elem));
 		break;
 	}
-	if (unlikely(ptr == NULL))
+	if (unlikely(ptr == NULL && ma->init.bak_memarea != NULL))
+		ptr = memarea_alloc_backup(ma, size, cookie);
+	if (likely(ptr != NULL))
+		memarea_mark_owner(ma, ptr);
+	else
 		ma->alloc_fails++;
 	memarea_unlock(ma);
 
@@ -261,6 +315,7 @@ memarea_free_elem(struct rte_memarea *ma, struct memarea_elem *elem)
 {
 	struct memarea_elem *prev, *next;
 	bool merged = false;
+	elem->owner = NULL;
 	prev = TAILQ_PREV(elem, memarea_elem_list, elem_node);
 	next = TAILQ_NEXT(elem, elem_node);
 	if (prev != NULL && prev->refcnt == 0) {
@@ -296,6 +351,12 @@ rte_memarea_update_refcnt(struct rte_memarea *ma, void *ptr, int16_t value)
 		return;
 	}
 
+	if (unlikely(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",
@@ -399,10 +460,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 5e3f23700b..abfff3d996 100644
--- a/lib/memarea/rte_memarea.h
+++ b/lib/memarea/rte_memarea.h
@@ -28,6 +28,12 @@
  *   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 object from backup memarea when
+ *   the current memarea failed to allocate.
+ *   @note If the backup of memarea-A is memarea-B, then must destroy memarea-A
+ *   before destroying memarae-B.
  */
 
 #include <stdbool.h>
@@ -96,6 +102,10 @@ struct rte_memarea_param {
 		 */
 		struct rte_memarea *src_memarea;
 	};
+	/** Backup memarea, which is used to allocate object from when the current
+	 * memarea failed to allocate.
+	 */
+	struct rte_memarea *bak_memarea;
 };
 
 /**
-- 
2.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v8 8/9] test/memarea: support backup memory test
  2022-10-11 12:17 ` [PATCH v8 0/9] " Chengwen Feng
                     ` (6 preceding siblings ...)
  2022-10-11 12:17   ` [PATCH v8 7/9] memarea: support backup memory mechanism Chengwen Feng
@ 2022-10-11 12:17   ` Chengwen Feng
  2022-10-11 12:17   ` [PATCH v8 9/9] app/test: add memarea to malloc-perf-autotest Chengwen Feng
  8 siblings, 0 replies; 222+ messages in thread
From: Chengwen Feng @ 2022-10-11 12:17 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk, hofors
  Cc: thomas, dev

This patch supports backup memory mechanism test.

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 app/test/test_memarea.c | 93 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 93 insertions(+)

diff --git a/app/test/test_memarea.c b/app/test/test_memarea.c
index 50b92db9b3..c12af6338e 100644
--- a/app/test/test_memarea.c
+++ b/app/test/test_memarea.c
@@ -329,6 +329,97 @@ 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_param(&init);
+	strcat(init.name, "_backup");
+	init.source = RTE_MEMAREA_SOURCE_LIBC;
+	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_param(&init);
+	init.source = RTE_MEMAREA_SOURCE_LIBC;
+	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_backup_destroy(void)
+{
+#define ALLOC_MAX_NUM	8
+	struct rte_memarea *ma, *bak_ma, *bakbak_ma;
+	struct rte_memarea_param init;
+	void *ptr[ALLOC_MAX_NUM];
+	int i;
+
+	/* prepare env */
+	test_memarea_init_param(&init);
+	strcat(init.name, "_bakbak");
+	init.source = RTE_MEMAREA_SOURCE_LIBC;
+	init.total_sz = MEMAREA_TEST_DEFAULT_SIZE * ALLOC_MAX_NUM;
+	bakbak_ma = rte_memarea_create(&init);
+	RTE_TEST_ASSERT(bakbak_ma != NULL, "Expected Non-NULL");
+	test_memarea_init_param(&init);
+	strcat(init.name, "_bak");
+	init.source = RTE_MEMAREA_SOURCE_LIBC;
+	init.bak_memarea = bakbak_ma;
+	init.total_sz = MEMAREA_TEST_DEFAULT_SIZE * ALLOC_MAX_NUM / 2;
+	bak_ma = rte_memarea_create(&init);
+	RTE_TEST_ASSERT(bak_ma != NULL, "Expected Non-NULL");
+	test_memarea_init_param(&init);
+	init.source = RTE_MEMAREA_SOURCE_LIBC;
+	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");
+
+	/* alloc for multiple count */
+	for (i = 0; i < ALLOC_MAX_NUM; i++) {
+		ptr[i] = rte_memarea_alloc(ma, MEMAREA_TEST_DEFAULT_SIZE, 0);
+		RTE_TEST_ASSERT(ptr[i] != NULL, "Expected Non-NULL");
+		rte_memarea_update_refcnt(ma, ptr[i], i + 1);
+	}
+	(void)rte_memarea_dump(ma, stderr, true);
+	(void)rte_memarea_dump(bak_ma, stderr, true);
+	(void)rte_memarea_dump(bakbak_ma, stderr, true);
+
+	/* try destroy outmost memarea */
+	rte_memarea_destroy(ma);
+	(void)rte_memarea_dump(bak_ma, stderr, true);
+	(void)rte_memarea_dump(bakbak_ma, stderr, true);
+
+	rte_memarea_destroy(bak_ma);
+	rte_memarea_destroy(bakbak_ma);
+
+	return 0;
+}
+
 static int
 test_memarea(void)
 {
@@ -340,6 +431,8 @@ 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);
+	MEMAREA_TEST_API_RUN(test_memarea_backup_destroy);
 
 	return test_memarea_retcode();
 }
-- 
2.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* [PATCH v8 9/9] app/test: add memarea to malloc-perf-autotest
  2022-10-11 12:17 ` [PATCH v8 0/9] " Chengwen Feng
                     ` (7 preceding siblings ...)
  2022-10-11 12:17   ` [PATCH v8 8/9] test/memarea: support backup memory test Chengwen Feng
@ 2022-10-11 12:17   ` Chengwen Feng
  2022-10-11 15:58     ` Dmitry Kozlyuk
  8 siblings, 1 reply; 222+ messages in thread
From: Chengwen Feng @ 2022-10-11 12:17 UTC (permalink / raw)
  To: david.marchand, mb, anatoly.burakov, dmitry.kozliuk, jerinjacobk, hofors
  Cc: thomas, dev

This patch adds memarea to malloc_perf_autotest.

Test platform: Kunpeng920
Test command: dpdk-test -a 0000:7d:00.3 -l 10-12
Test result:
USER1: Performance: rte_memarea
USER1:    Size (B)   Runs  Alloc (us) Free (us) Total (us)  memset (us)
USER1:          64  10000        0.03      0.03       0.06         0.01
USER1:         128  10000        0.02      0.03       0.05         0.01
USER1:        1024  10000        0.03      0.05       0.07         0.20
USER1:        4096  10000        0.03      0.05       0.07         0.34
USER1:       65536  10000        0.10      0.08       0.18         2.14
USER1:     1048576    644        0.10      0.04       0.14        29.07
USER1:     2097152    322        0.10      0.04       0.14        57.50
USER1:     4194304    161        0.12      0.04       0.15       114.50
USER1:    16777216     40        0.11      0.04       0.15       456.09
USER1:  1073741824 Interrupted: out of memory. [1]

Compared with rte_malloc:
USER1: Performance: rte_malloc
USER1:    Size (B)   Runs  Alloc (us) Free (us) Total (us)  memset (us)
USER1:          64  10000        0.14      0.07       0.21         0.01
USER1:         128  10000        0.10      0.05       0.15         0.01
USER1:        1024  10000        0.11      0.18       0.29         0.21
USER1:        4096  10000        0.13      0.39       0.53         0.35
USER1:       65536  10000        0.17      2.27       2.44         2.15
USER1:     1048576  10000       37.21     71.63     108.84        29.08
USER1:     2097152  10000     8831.15    160.02    8991.17        63.52
USER1:     4194304  10000    47131.88    413.75   47545.62       173.79
USER1:    16777216   4221   119604.60   2209.73  121814.34       964.42
USER1:  1073741824     31   335058.32 223369.31  558427.63     62440.87

[1] The total-size of the memarea is restricted to avoid creation
failed.

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
---
 app/test/test_malloc_perf.c | 55 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 54 insertions(+), 1 deletion(-)

diff --git a/app/test/test_malloc_perf.c b/app/test/test_malloc_perf.c
index ccec43ae84..a8b4531fe3 100644
--- a/app/test/test_malloc_perf.c
+++ b/app/test/test_malloc_perf.c
@@ -7,10 +7,12 @@
 #include <rte_cycles.h>
 #include <rte_errno.h>
 #include <rte_malloc.h>
+#include <rte_memarea.h>
 #include <rte_memzone.h>
 
 #include "test.h"
 
+#define PERFTEST_MAX_RUNS	10000
 #define TEST_LOG(level, ...) RTE_LOG(level, USER1, __VA_ARGS__)
 
 typedef void * (alloc_t)(const char *name, size_t size, unsigned int align);
@@ -147,10 +149,52 @@ memzone_free(void *addr)
 	rte_memzone_free((struct rte_memzone *)addr);
 }
 
+static struct rte_memarea *test_ma;
+
+static int
+memarea_pre_env(void)
+{
+	struct rte_memarea_param init = { 0 };
+	snprintf(init.name, sizeof(init.name), "perftest");
+	init.source = RTE_MEMAREA_SOURCE_HEAP;
+	init.alg = RTE_MEMAREA_ALG_NEXTFIT;
+	init.total_sz = PERFTEST_MAX_RUNS * KB * 66; /* test for max 64KB (add 2KB for meta) */
+	init.mt_safe = 1;
+	init.numa_socket = SOCKET_ID_ANY;
+	init.bak_memarea = NULL;
+	test_ma = rte_memarea_create(&init);
+	if (test_ma == NULL) {
+		fprintf(stderr, "memarea create failed, skip memarea perftest!\n");
+		return -1;
+	}
+	return 0;
+}
+
+static void
+memarea_clear_env(void)
+{
+	rte_memarea_destroy(test_ma);
+	test_ma = NULL;
+}
+
+static void *
+memarea_alloc(const char *name, size_t size, unsigned int align)
+{
+	RTE_SET_USED(name);
+	RTE_SET_USED(align);
+	return rte_memarea_alloc(test_ma, size, 0);
+}
+
+static void
+memarea_free(void *addr)
+{
+	rte_memarea_free(test_ma, addr);
+}
+
 static int
 test_malloc_perf(void)
 {
-	static const size_t MAX_RUNS = 10000;
+	static const size_t MAX_RUNS = PERFTEST_MAX_RUNS;
 
 	double memset_us_gb = 0;
 
@@ -168,6 +212,15 @@ test_malloc_perf(void)
 			NULL, memset_us_gb, RTE_MAX_MEMZONE - 1) < 0)
 		return -1;
 
+	if (memarea_pre_env() < 0)
+		return 0;
+	if (test_alloc_perf("rte_memarea", memarea_alloc, memarea_free,
+			memset, memset_us_gb, MAX_RUNS) < 0) {
+		memarea_clear_env();
+		return -1;
+	}
+	memarea_clear_env();
+
 	return 0;
 }
 
-- 
2.17.1


^ permalink raw reply	[flat|nested] 222+ messages in thread

* Re: [PATCH v5 01/10] memarea: introduce memarea library
  2022-10-10 23:33           ` fengchengwen
@ 2022-10-11 15:35             ` Mattias Rönnblom
  0 siblings, 0 replies; 222+ messages in thread
From: Mattias Rönnblom @ 2022-10-11 15:35 UTC (permalink / raw)
  To: fengchengwen, datshan, david.marchand, mb, anatoly.burakov,
	dmitry.kozliuk, jerinjacobk
  Cc: thomas, dev

On 2022-10-11 01:33, fengchengwen wrote:
> On 2022/10/11 0:53, Mattias Rönnblom wrote:
>> On 2022-10-08 09:53, fengchengwen wrote:
>>> Hi Mattias, Thanks for your review, most will fix in v6.
>>>
>>> On 2022/10/7 4:15, Mattias Rönnblom wrote:
>>>> On 2022-10-05 06:09, datshan wrote:
>>>>> From: Chengwen Feng <fengchengwen@huawei.com>
>>>>>
>>>>> 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 <fengchengwen@huawei.com>
>>>>> ---
>>>>>    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 <fengchengwen@huawei.com>
>>>>> +F: lib/memarea
>>>>> +F: doc/guides/prog_guide/memarea_lib.rst
>>>>> +
>>>>>    Membership - EXPERIMENTAL
>>>>>    M: Yipeng Wang <yipeng1.wang@intel.com>
>>>>>    M: Sameh Gobriel <sameh.gobriel@intel.com>
>>>>> 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..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 library is an allocator of variable-size objects, it 
>>>>> is oriented
>>>>> +  towards the application layer, which could provides 
>>>>> 'region-based memory
>>>>> +  management' function.
>>>>> +
>>>>>    * **Added configuration for asynchronous flow connection 
>>>>> tracking.**
>>>>>        Added connection tracking action number hint to 
>>>>> ``rte_flow_configure``
>>>>> diff --git a/lib/eal/common/eal_common_log.c 
>>>>> b/lib/eal/common/eal_common_log.c
>>>>> index bd7b188ceb..3d62af59c6 100644
>>>>> --- a/lib/eal/common/eal_common_log.c
>>>>> +++ b/lib/eal/common/eal_common_log.c
>>>>> @@ -369,6 +369,7 @@ static const struct logtype logtype_strings[] = {
>>>>>        {RTE_LOGTYPE_EFD,        "lib.efd"},
>>>>>        {RTE_LOGTYPE_EVENTDEV,   "lib.eventdev"},
>>>>>        {RTE_LOGTYPE_GSO,        "lib.gso"},
>>>>> +    {RTE_LOGTYPE_MEMAREA,    "lib.memarea"},
>>>>>        {RTE_LOGTYPE_USER1,      "user1"},
>>>>>        {RTE_LOGTYPE_USER2,      "user2"},
>>>>>        {RTE_LOGTYPE_USER3,      "user3"},
>>>>> diff --git a/lib/eal/include/rte_log.h b/lib/eal/include/rte_log.h
>>>>> index 25ce42cdfc..708f3a39dd 100644
>>>>> --- a/lib/eal/include/rte_log.h
>>>>> +++ b/lib/eal/include/rte_log.h
>>>>> @@ -48,6 +48,7 @@ extern "C" {
>>>>>    #define RTE_LOGTYPE_EFD       18 /**< Log related to EFD. */
>>>>>    #define RTE_LOGTYPE_EVENTDEV  19 /**< Log related to eventdev. */
>>>>>    #define RTE_LOGTYPE_GSO       20 /**< Log related to GSO. */
>>>>> +#define RTE_LOGTYPE_MEMAREA   21 /**< Log related to memarea. */
>>>>>      /* these log types can be used in an application */
>>>>>    #define RTE_LOGTYPE_USER1     24 /**< User-defined log type 1. */
>>>>> diff --git a/lib/memarea/memarea_private.h 
>>>>> b/lib/memarea/memarea_private.h
>>>>> new file mode 100644
>>>>> index 0000000000..c76392d3e6
>>>>> --- /dev/null
>>>>> +++ b/lib/memarea/memarea_private.h
>>>>> @@ -0,0 +1,30 @@
>>>>> +/* SPDX-License-Identifier: BSD-3-Clause
>>>>> + * Copyright(c) 2022 HiSilicon Limited
>>>>> + */
>>>>> +
>>>>> +#ifndef MEMAREA_PRIVATE_H
>>>>> +#define MEMAREA_PRIVATE_H
>>>>> +
>>>>> +#include <rte_memarea.h>
>>>>> +
>>>>> +#define MEMAREA_FREE_ELEM_COOKIE    0xFFFFFFFF
>>>>> +
>>>>> +struct memarea_elem {
>>>>> +    size_t   size;
>>>>> +    uint32_t cookie;
>>>>> +    int32_t  refcnt; /* Non-zero indicates that it has been 
>>>>> allocated */
>>>>> +    TAILQ_ENTRY(memarea_elem) elem_node;
>>>>> +    TAILQ_ENTRY(memarea_elem) free_node;
>>>>> +} __rte_cache_aligned;
>>>>> +
>>>>
>>>> Why is the elem type cache line aligned? Need the elem data start be 
>>>> cache line aligned?
>>>
>>> Yes, the elem data align at cache-line default.
>>>
>>>>
>>>>> +TAILQ_HEAD(memarea_elem_list, memarea_elem);
>>>>> +
>>>>> +struct rte_memarea {
>>>>> +    struct rte_memarea_param init;
>>>>> +    rte_spinlock_t           lock;
>>>>> +    void                    *area_addr;
>>>>> +    struct memarea_elem_list elem_list;
>>>>> +    struct memarea_elem_list free_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..0a74fb4cd1
>>>>> --- /dev/null
>>>>> +++ b/lib/memarea/meson.build
>>>>> @@ -0,0 +1,16 @@
>>>>> +# SPDX-License-Identifier: BSD-3-Clause
>>>>> +# Copyright(c) 2022 HiSilicon Limited
>>>>> +
>>>>> +if is_windows
>>>>> +    build = false
>>>>> +    reason = 'not supported on Windows'
>>>>> +    subdir_done()
>>>>> +endif
>>>>> +
>>>>> +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..868da7661d
>>>>> --- /dev/null
>>>>> +++ b/lib/memarea/rte_memarea.c
>>>>> @@ -0,0 +1,157 @@
>>>>> +/* SPDX-License-Identifier: BSD-3-Clause
>>>>> + * Copyright(c) 2022 HiSilicon Limited
>>>>> + */
>>>>> +
>>>>> +#include <stdio.h>
>>>>> +#include <stdlib.h>
>>>>> +
>>>>> +#include <rte_common.h>
>>>>> +#include <rte_log.h>
>>>>> +#include <rte_malloc.h>
>>>>> +#include <rte_spinlock.h>
>>>>> +
>>>>> +#include "rte_memarea.h"
>>>>> +#include "memarea_private.h"
>>>>> +
>>>>> +static int
>>>>> +memarea_check_param(const struct rte_memarea_param *init)
>>>>> +{
>>>>> +    size_t len;
>>>>> +
>>>>> +    if (init == NULL) {
>>>>> +        RTE_LOG(ERR, MEMAREA, "memarea init param is NULL!\n");
>>>>> +        return -EINVAL;
>>>>> +    }
>>>>> +
>>>>> +    len = strnlen(init->name, RTE_MEMAREA_NAMESIZE);
>>>>> +    if (len == 0 || len >= RTE_MEMAREA_NAMESIZE) {
>>>>> +        RTE_LOG(ERR, MEMAREA, "memarea name size %zu invalid!\n", 
>>>>> len);
>>>>> +        return -EINVAL;
>>>>> +    }
>>>>> +
>>>>> +    if (init->source != RTE_MEMAREA_SOURCE_RTE_MEMORY &&
>>>>> +        init->source != RTE_MEMAREA_SOURCE_SYSTEM_API &&
>>>>> +        init->source != RTE_MEMAREA_SOURCE_USER_ADDR &&
>>>>> +        init->source != RTE_MEMAREA_SOURCE_USER_MEMAREA) {
>>>>> +        RTE_LOG(ERR, MEMAREA, "memarea: %s source: %d not 
>>>>> supported!\n",
>>>>> +            init->name, init->source);
>>>>> +        return -EINVAL;
>>>>> +    }
>>>>> +
>>>>> +    if (init->total_sz <= sizeof(struct memarea_elem)) {
>>>>> +        RTE_LOG(ERR, MEMAREA, "memarea: %s total-size: %zu too 
>>>>> small!\n",
>>>>> +            init->name, init->total_sz);
>>>>> +        return -EINVAL;
>>>>> +    }
>>>>> +
>>>>> +    if (init->source == RTE_MEMAREA_SOURCE_USER_ADDR && 
>>>>> init->user_addr == NULL) {
>>>>> +        RTE_LOG(ERR, MEMAREA, "memarea: %s user provided addr is 
>>>>> NULL!\n", init->name);
>>>>> +        return -EINVAL;
>>>>> +    }
>>>>> +
>>>>> +    if (init->source == RTE_MEMAREA_SOURCE_USER_ADDR &&
>>>>> +        ((uintptr_t)init->user_addr & (RTE_CACHE_LINE_SIZE - 1))) {
>>>>> +        RTE_LOG(ERR, MEMAREA, "memarea: %s user provided addr 
>>>>> should align: %d!\n",
>>>>> +            init->name, RTE_CACHE_LINE_SIZE);
>>>>> +        return -EINVAL;
>>>>> +    }
>>>>> +
>>>>> +    if (init->source == RTE_MEMAREA_SOURCE_USER_MEMAREA && 
>>>>> init->user_memarea == NULL) {
>>>>> +        RTE_LOG(ERR, MEMAREA, "memarea: %s user provided memarea 
>>>>> is NULL!\n", init->name);
>>>>> +        return -EINVAL;
>>>>> +    }
>>>>> +
>>>>> +    if (init->alg != RTE_MEMAREA_ALG_DEFAULT) {
>>>>> +        RTE_LOG(ERR, MEMAREA, "memarea: %s alg: %d not sup