* [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
* 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 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
* [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
* 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
* [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
[parent not found: <20221005033848.2241-1-datshan@qq.com>]
* [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
[parent not found: <20221005040952.8166-1-datshan@qq.com>]
* [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
* 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 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
* 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 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). > > My reaction when I saw the test code, was that it was needlessly complicated to create a memarea. Intuitions vary, I suppose. Anyway, the style you prefer is represented elsewhere in DPDK already, so I'm good with this. >> >>> 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 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
* 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 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 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
* 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 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
* [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
* [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
* [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
* Re: [PATCH v8 1/9] memarea: introduce memarea library 2022-10-11 12:17 ` [PATCH v8 1/9] memarea: " Chengwen Feng @ 2022-10-11 15:58 ` Dmitry Kozlyuk 2022-10-12 4:06 ` fengchengwen 0 siblings, 1 reply; 222+ messages in thread From: Dmitry Kozlyuk @ 2022-10-11 15:58 UTC (permalink / raw) To: Chengwen Feng Cc: david.marchand, mb, anatoly.burakov, jerinjacobk, hofors, thomas, dev 2022-10-11 12:17 (UTC+0000), Chengwen Feng: [...] > 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. Isn't this an implementation detail? Stating it in the API description limits optimization opportunities. Cache line alignment is good in many cases, but it can also be a waste of space, e.g. for a thread-unsafe region for small objects. Can this limitation only (temporarily?) apply to user memory? Or can the minimal alignment be a property of memarea? > + > +* 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. I think mentioning rte_extmem_xxx() is bogus because user memory does not need to be registered with DPDK (I understand it's an example, but still an unrelated reference). Please format as a list. > + > +* 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. "which could provides" -> "providing" > + > * **Added support for multiple mbuf pools per ethdev Rx queue.** > > The capability allows application to provide many mempools [...] ^ permalink raw reply [flat|nested] 222+ messages in thread
* Re: [PATCH v8 1/9] memarea: introduce memarea library 2022-10-11 15:58 ` Dmitry Kozlyuk @ 2022-10-12 4:06 ` fengchengwen 2022-10-13 10:45 ` fengchengwen 0 siblings, 1 reply; 222+ messages in thread From: fengchengwen @ 2022-10-12 4:06 UTC (permalink / raw) To: Dmitry Kozlyuk Cc: david.marchand, mb, anatoly.burakov, jerinjacobk, hofors, thomas, dev Hi Dmitry, On 2022/10/11 23:58, Dmitry Kozlyuk wrote: > 2022-10-11 12:17 (UTC+0000), Chengwen Feng: > [...] >> 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. > > Isn't this an implementation detail? > Stating it in the API description limits optimization opportunities. > Cache line alignment is good in many cases, > but it can also be a waste of space, > e.g. for a thread-unsafe region for small objects. > Can this limitation only (temporarily?) apply to user memory? > Or can the minimal alignment be a property of memarea? You are right, to be more general, I'll add the align parameter to rte_memarea_alloc instead of stating it here. > >> + >> +* 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. > > I think mentioning rte_extmem_xxx() is bogus > because user memory does not need to be registered with DPDK > (I understand it's an example, but still an unrelated reference). > Please format as a list. okay > >> + >> +* 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. > > "which could provides" -> "providing" okay > >> + >> * **Added support for multiple mbuf pools per ethdev Rx queue.** >> >> The capability allows application to provide many mempools > [...] > . > ^ permalink raw reply [flat|nested] 222+ messages in thread
* Re: [PATCH v8 1/9] memarea: introduce memarea library 2022-10-12 4:06 ` fengchengwen @ 2022-10-13 10:45 ` fengchengwen 0 siblings, 0 replies; 222+ messages in thread From: fengchengwen @ 2022-10-13 10:45 UTC (permalink / raw) To: Dmitry Kozlyuk Cc: david.marchand, mb, anatoly.burakov, jerinjacobk, hofors, thomas, dev Sorry to self-reply. On 2022/10/12 12:06, fengchengwen wrote: > Hi Dmitry, > > On 2022/10/11 23:58, Dmitry Kozlyuk wrote: >> 2022-10-11 12:17 (UTC+0000), Chengwen Feng: >> [...] >>> 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. >> >> Isn't this an implementation detail? >> Stating it in the API description limits optimization opportunities. >> Cache line alignment is good in many cases, >> but it can also be a waste of space, >> e.g. for a thread-unsafe region for small objects. >> Can this limitation only (temporarily?) apply to user memory? >> Or can the minimal alignment be a property of memarea? > > You are right, to be more general, I'll add the align parameter to rte_memarea_alloc instead of stating it here. The memarea is targeted to not so general usage, so v9 doesn't add align parameter to rte_memarea_alloc, at least from the internal feedback. We could add rte_memarea_align_alloc() if the align requirement does exist. > >> >>> + >>> +* 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. >> >> I think mentioning rte_extmem_xxx() is bogus >> because user memory does not need to be registered with DPDK >> (I understand it's an example, but still an unrelated reference). >> Please format as a list. > > okay > >> >>> + >>> +* 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. >> >> "which could provides" -> "providing" > > okay > >> >>> + >>> * **Added support for multiple mbuf pools per ethdev Rx queue.** >>> >>> The capability allows application to provide many mempools >> [...] >> . >> > > . > ^ 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
* Re: [PATCH v8 3/9] memarea: support alloc/free/update-refcnt API 2022-10-11 12:17 ` [PATCH v8 3/9] memarea: support alloc/free/update-refcnt API Chengwen Feng @ 2022-10-11 15:58 ` Dmitry Kozlyuk 2022-10-12 7:28 ` fengchengwen 0 siblings, 1 reply; 222+ messages in thread From: Dmitry Kozlyuk @ 2022-10-11 15:58 UTC (permalink / raw) To: Chengwen Feng Cc: david.marchand, mb, anatoly.burakov, jerinjacobk, hofors, thomas, dev 2022-10-11 12:17 (UTC+0000), Chengwen Feng: > 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,