[RFC] memarea: introduce memory area library
Checks
Commit Message
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
Comments
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.
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.
>
> 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.
new file mode 100644
@@ -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 += []
new file mode 100644
@@ -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;
+}
new file mode 100644
@@ -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 */
new file mode 100644
@@ -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: *;
+};
@@ -42,6 +42,7 @@ libraries = [
'kni',
'latencystats',
'lpm',
+ 'memarea',
'member',
'pcapng',
'power',