From 0c18e653e80821bbaee498576942c73e111a036b Mon Sep 17 00:00:00 2001 From: goldsimon Date: Thu, 21 Jun 2007 20:12:11 +0000 Subject: [PATCH] Introduced the option MEM_USE_POOLS to use 4 pools with different sized elements instead of a heap. This both prevents memory fragmentation and gives a higher speed at the cost of more memory consumption. Turned off by default. --- CHANGELOG | 6 ++++ src/core/mem.c | 78 +++++++++++++++++++++++++++++++++++++++-- src/core/memp.c | 32 ++++++++++++++--- src/include/lwip/mem.h | 12 ++++++- src/include/lwip/memp.h | 10 ++++++ src/include/lwip/opt.h | 44 +++++++++++++++++++++-- 6 files changed, 171 insertions(+), 11 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 32585ebf..3d147823 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -19,6 +19,12 @@ HISTORY ++ New features: + 2007-06-21 Simon Goldschmidt + * mem.c, memp.c, mem.h, memp.h, opt.h: task #6863: Introduced the option + MEM_USE_POOLS to use 4 pools with different sized elements instead of a + heap. This both prevents memory fragmentation and gives a higher speed + at the cost of more memory consumption. Turned off by default. + 2007-06-21 Simon Goldschmidt * api_lib.c, api_msg.c, api.h, api_msg.h: Converted the length argument of netconn_write (and therefore also api_msg_msg.msg.w.len) from u16_t into diff --git a/src/core/mem.c b/src/core/mem.c index 12d91e1b..99faf2ce 100644 --- a/src/core/mem.c +++ b/src/core/mem.c @@ -48,7 +48,79 @@ #include "lwip/stats.h" -#if (MEM_LIBC_MALLOC == 0) +#if !MEM_LIBC_MALLOC +#if MEM_USE_POOLS +/* lwIP head implemented with different sized pools */ + +/** + * This structure is used to save the pool one element came from. + */ +struct mem_helper +{ + memp_t poolnr; +}; + +/** + * Allocate memory: determine the smallest pool that is big enough + * to contain an element of 'size' and get an element from that pool. + * + * @param size the size in bytes of the memory needed + * @return a pointer to the allocated memory or NULL if the pool is empty + */ +void * +mem_malloc(mem_size_t size) +{ + struct mem_helper *element; + int poolnr = -1; + + for (poolnr = MEMP_MEM_POOL_1; poolnr < (MEMP_MEM_POOL_1 + MEM_POOL_COUNT); poolnr++) { + if ((size + sizeof(struct mem_helper)) <= memp_sizes[poolnr]) { + break; + } + } + if (poolnr == -1) { + LWIP_ASSERT("mem_malloc(): no pool is that big!", 0); + return NULL; + } + element = (struct mem_helper*)memp_malloc(poolnr); + if (element == NULL) { + /* No need to DEBUGF or ASSERT: This error is already + taken care of in memp.c */ + /** @todo: we could try a bigger pool if this one is empty! */ + return NULL; + } + + element->poolnr = poolnr; + element++; + + return element; +} + +/** + * Free memory previously allocated by mem_malloc. Loads the pool number + * and calls memp_free with that pool number to put the element back into + * its pool + * + * @param rmem the memory element to free + */ +void +mem_free(void *rmem) +{ + struct mem_helper *hmem = (struct mem_helper*)rmem; + + LWIP_ASSERT("rmem != NULL", (rmem != NULL)); + LWIP_ASSERT("rmem == MEM_ALIGN(rmem)", (rmem == MEM_ALIGN(rmem))); + + hmem--; + + LWIP_ASSERT("hmem != NULL", (hmem != NULL)); + LWIP_ASSERT("hmem == MEM_ALIGN(hmem)", (hmem == MEM_ALIGN(hmem))); + LWIP_ASSERT("hmem->poolnr < MEMP_MAX", (hmem->poolnr < MEMP_MAX)); + + memp_free(hmem->poolnr, hmem); +} + +#else /* MEM_USE_POOLS */ /* lwIP replacement for your libc malloc() */ /* This does not have to be aligned since for getting its size, @@ -427,5 +499,5 @@ mem_malloc(mem_size_t size) return NULL; } -#endif /* MEM_LIBC_MALLOC == 0 */ - +#endif /* MEM_USE_POOLS */ +#endif /* !MEM_LIBC_MALLOC */ diff --git a/src/core/memp.c b/src/core/memp.c index 2edf2425..98acb4ef 100644 --- a/src/core/memp.c +++ b/src/core/memp.c @@ -99,7 +99,10 @@ static struct memp *memp_tab[MEMP_MAX]; #endif /* MEMP_OVERFLOW_CHECK */ -static const u16_t memp_sizes[MEMP_MAX] = { +#if !MEM_USE_POOLS +static +#endif +const u16_t memp_sizes[MEMP_MAX] = { MEMP_ALIGN_SIZE(sizeof(struct pbuf)), MEMP_ALIGN_SIZE(sizeof(struct raw_pcb)), MEMP_ALIGN_SIZE(sizeof(struct udp_pcb)), @@ -113,7 +116,13 @@ static const u16_t memp_sizes[MEMP_MAX] = { MEMP_ALIGN_SIZE(sizeof(struct etharp_q_entry)), #endif MEMP_ALIGN_SIZE(sizeof(struct pbuf)) + MEMP_ALIGN_SIZE(PBUF_POOL_BUFSIZE), - MEMP_ALIGN_SIZE(sizeof(struct sys_timeo)) + MEMP_ALIGN_SIZE(sizeof(struct sys_timeo)), +#if MEM_USE_POOLS + MEMP_ALIGN_SIZE(MEM_POOL_SIZE_1), + MEMP_ALIGN_SIZE(MEM_POOL_SIZE_2), + MEMP_ALIGN_SIZE(MEM_POOL_SIZE_3), + MEMP_ALIGN_SIZE(MEM_POOL_SIZE_4), +#endif }; static const u16_t memp_num[MEMP_MAX] = { @@ -130,7 +139,13 @@ static const u16_t memp_num[MEMP_MAX] = { MEMP_NUM_ARP_QUEUE, #endif PBUF_POOL_SIZE, - MEMP_NUM_SYS_TIMEOUT + MEMP_NUM_SYS_TIMEOUT, +#if MEM_USE_POOLS + MEM_POOL_NUM_1, + MEM_POOL_NUM_2, + MEM_POOL_NUM_3, + MEM_POOL_NUM_4, +#endif }; #define MEMP_TYPE_SIZE(qty, type) \ @@ -150,8 +165,15 @@ static u8_t memp_memory[MEM_ALIGNMENT - 1 + MEMP_TYPE_SIZE(MEMP_NUM_ARP_QUEUE, struct etharp_q_entry) + #endif MEMP_TYPE_SIZE(PBUF_POOL_SIZE, struct pbuf) + - PBUF_POOL_SIZE * MEMP_ALIGN_SIZE(PBUF_POOL_BUFSIZE) + - MEMP_TYPE_SIZE(MEMP_NUM_SYS_TIMEOUT, struct sys_timeo)]; + ((PBUF_POOL_SIZE) * MEMP_ALIGN_SIZE(PBUF_POOL_BUFSIZE)) + + MEMP_TYPE_SIZE(MEMP_NUM_SYS_TIMEOUT, struct sys_timeo) +#if MEM_USE_POOLS + + ((MEM_POOL_NUM_1) * MEMP_ALIGN_SIZE(MEM_POOL_SIZE_1)) + + ((MEM_POOL_NUM_2) * MEMP_ALIGN_SIZE(MEM_POOL_SIZE_2)) + + ((MEM_POOL_NUM_3) * MEMP_ALIGN_SIZE(MEM_POOL_SIZE_3)) + + ((MEM_POOL_NUM_4) * MEMP_ALIGN_SIZE(MEM_POOL_SIZE_4)) +#endif +]; #if MEMP_SANITY_CHECK /** diff --git a/src/include/lwip/mem.h b/src/include/lwip/mem.h index b5894309..4091c964 100644 --- a/src/include/lwip/mem.h +++ b/src/include/lwip/mem.h @@ -66,11 +66,21 @@ typedef u16_t mem_size_t; #define mem_realloc(x, size) realloc(x,size) #endif #else /* MEM_LIBC_MALLOC */ +#if MEM_USE_POOLS +/** The pool implementation of the heap currently uses 4 pools */ +#define MEM_POOL_COUNT 4 +/** mem_init is not used when using pools instead of a heap */ +#define mem_init() +/** mem_realloc is not used when using pools instead of a heap: + we can't free part of a pool element and don't want to copy the rest */ +#define mem_realloc(mem, size) (mem) +#else /* MEM_USE_POOLS */ /* lwIP alternative malloc */ void mem_init(void); +void *mem_realloc(void *mem, mem_size_t size); +#endif /* MEM_USE_POOLS */ void *mem_malloc(mem_size_t size); void mem_free(void *mem); -void *mem_realloc(void *mem, mem_size_t size); #endif /* MEM_LIBC_MALLOC */ #ifndef LWIP_MEM_ALIGN_SIZE diff --git a/src/include/lwip/memp.h b/src/include/lwip/memp.h index 64447c93..3f272b4c 100644 --- a/src/include/lwip/memp.h +++ b/src/include/lwip/memp.h @@ -56,6 +56,12 @@ typedef enum { #endif MEMP_PBUF_POOL, MEMP_SYS_TIMEOUT, +#if MEM_USE_POOLS + MEMP_MEM_POOL_1, + MEMP_MEM_POOL_2, + MEMP_MEM_POOL_3, + MEMP_MEM_POOL_4, +#endif MEMP_MAX } memp_t; @@ -70,6 +76,10 @@ void *memp_malloc(memp_t type); #endif void memp_free(memp_t type, void *mem); +#if MEM_USE_POOLS +extern const u16_t memp_sizes[MEMP_MAX]; +#endif + #ifdef __cplusplus } #endif diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index 5aca48b4..0fd1d20a 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -66,6 +66,8 @@ #endif /* ---------- Memory options ---------- */ +/* Use malloc/free/realloc provided by your C-library instead of the + lwip internal allocator. Can save code size if you already use it. */ #ifndef MEM_LIBC_MALLOC #define MEM_LIBC_MALLOC 0 #endif @@ -73,13 +75,51 @@ /* MEM_ALIGNMENT: should be set to the alignment of the CPU for which lwIP is compiled. 4 byte alignment -> define MEM_ALIGNMENT to 4, 2 byte alignment -> define MEM_ALIGNMENT to 2. */ - #ifndef MEM_ALIGNMENT #define MEM_ALIGNMENT 1 #endif +/* Memory can be allocated from 4 pools with element of different size. + When mem_malloc is called, and element of the smallest pool that can + provide the lenght needed is returned. */ +#ifndef MEM_USE_POOLS +#define MEM_USE_POOLS 0 +#endif + +#if MEM_USE_POOLS +/* The element sizes of the 4 pools. + The sizes must be increasing, e.g. the elements in pool 2 must be + bigger than the elements in pool 1 and so on. If this is not the case, + mem_malloc will not work correctly. */ +#ifndef MEM_POOL_SIZE_1 +#error You must have at least one pool if MEM_USE_POOLS is set to 1! +#endif +#ifndef MEM_POOL_SIZE_2 +#define MEM_POOL_SIZE_2 0 +#endif +#ifndef MEM_POOL_SIZE_3 +#define MEM_POOL_SIZE_3 0 +#endif +#ifndef MEM_POOL_SIZE_4 +#define MEM_POOL_SIZE_4 0 +#endif +/* The element count of the 4 pools */ +#ifndef MEM_POOL_NUM_1 +#error You must have at least one pool if MEM_USE_POOLS is set to 1! +#endif +#ifndef MEM_POOL_NUM_2 +#define MEM_POOL_NUM_2 0 +#endif +#ifndef MEM_POOL_NUM_3 +#define MEM_POOL_NUM_3 0 +#endif +#ifndef MEM_POOL_NUM_4 +#define MEM_POOL_NUM_4 0 +#endif +#endif + /* MEM_SIZE: the size of the heap memory. If the application will send -a lot of data that needs to be copied, this should be set high. */ + a lot of data that needs to be copied, this should be set high. */ #ifndef MEM_SIZE #define MEM_SIZE 1600 #endif