From 439f14b83969a5bdbce21a3f0143a5d0fbffc8f2 Mon Sep 17 00:00:00 2001 From: Chris Young Date: Tue, 26 Feb 2013 19:39:05 +0000 Subject: Experiment 2: Allocate the lwc_string into memory pools (two of 64K each to cover the 4091 buckets). The first of these pools is allocated in OCM if available. The string itself is moved to a separate allocation in main memory to prevent variable-length allocations in the pools. --- include/libwapcaplet/libwapcaplet.h | 3 +- src/Makefile | 2 +- src/libwapcaplet.c | 91 +++++++++++----------- src/mempool.c | 147 ++++++++++++++++++++++++++++++++++++ src/mempool.h | 22 ++++++ 5 files changed, 214 insertions(+), 51 deletions(-) create mode 100755 src/mempool.c create mode 100755 src/mempool.h diff --git a/include/libwapcaplet/libwapcaplet.h b/include/libwapcaplet/libwapcaplet.h index 47d93a6..dd1c401 100644 --- a/include/libwapcaplet/libwapcaplet.h +++ b/include/libwapcaplet/libwapcaplet.h @@ -43,6 +43,7 @@ typedef struct lwc_string_s { lwc_hash hash; lwc_refcounter refcnt; struct lwc_string_s * insensitive; + char *string; } lwc_string; /** @@ -215,7 +216,7 @@ lwc__intern_caseless_string(lwc_string *str); * in future. Any code relying on it currently should be * modified to use ::lwc_string_length if possible. */ -#define lwc_string_data(str) ((const char *)((str)+1)) +#define lwc_string_data(str) ((const char *)((str)->string)) /** * Retrieve the data length for an interned string. diff --git a/src/Makefile b/src/Makefile index 4e03048..870989c 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,3 +1,3 @@ -DIR_SOURCES := libwapcaplet.c +DIR_SOURCES := libwapcaplet.c mempool.c include $(NSBUILD)/Makefile.subdir diff --git a/src/libwapcaplet.c b/src/libwapcaplet.c index ecc1fb9..4cbb555 100644 --- a/src/libwapcaplet.c +++ b/src/libwapcaplet.c @@ -10,13 +10,9 @@ #include #include +#include "mempool.h" #include "libwapcaplet/libwapcaplet.h" -#ifdef __amigaos4__ -#include -#include -#endif - #ifndef UNUSED #define UNUSED(x) ((x) = (x)) #endif @@ -36,10 +32,12 @@ lwc__calculate_hash(const char *str, size_t len) return z; } -#define STR_OF(str) ((char *)(str + 1)) -#define CSTR_OF(str) ((const char *)(str + 1)) +#define STR_OF(str) ((char *)(str->string)) +#define CSTR_OF(str) ((const char *)(str->string)) #define NR_BUCKETS_DEFAULT (4091) +#define MAX_MEM_POOLS 2 +#define MEM_POOL_BLOCKS (65536) / (sizeof(lwc_string) + sizeof(void *)) typedef struct lwc_context_s { lwc_string ** buckets; @@ -50,55 +48,45 @@ static lwc_context *ctx = NULL; #define LWC_ALLOC(s) malloc(s) #define LWC_FREE(p) free(p) +#define LWC_ALLOC_STR() str_alloc() +#define LWC_FREE_STR(p) str_free(p) -#ifndef __amigaos4__ -#define LWC_ALLOC_BUCKET(s) malloc(s) -#define LWC_FREE_BUCKET(p) free(p) -#else -#define LWC_ALLOC_BUCKET(s) onchipmem_malloc(s) -#define LWC_FREE_BUCKET(p) onchipmem_free(p) +memory_pool_t *mp[MAX_MEM_POOLS] = { NULL, NULL }; -struct Library *ocmb; -struct OCMIFace *IOCM = NULL; -bool using_onchipmem; +typedef lwc_hash (*lwc_hasher)(const char *, size_t); +typedef int (*lwc_strncmp)(const char *, const char *, size_t); +typedef void (*lwc_memcpy)(char *, const char *, size_t); -void *onchipmem_malloc(int s); -void onchipmem_free(void *p); +static void *str_alloc(void); +static void str_free(void *p); -void *onchipmem_malloc(int s) +static void *str_alloc(void) { - /* NB: If using OCM this always allocates 64K, ie. a bucket size of 16384 */ - uint8 *ocm = NULL; - - if((ocmb = IExec->OpenResource("onchipmem.resource"))) { - if((IOCM = (struct OCMIFace *)IExec->GetInterface((struct Library *)ocmb, "main", 1, NULL))) { - ocm = (uint8 *)IOCM->ObtainOnChipMem(); + void *p; + int i; + + for(i = 0; i < MAX_MEM_POOLS; i++) { + if(mp[i] == NULL) { + mp[i] = memory_pool_create(sizeof(lwc_string), MEM_POOL_BLOCKS); + if(mp[i] == NULL) return NULL; /* out of memory */ } - } - if(ocm == NULL) { - ocm = malloc(s); - using_onchipmem = false; - } else { - using_onchipmem = true; + if((p = memory_pool_alloc(mp[i]))) { + return p; + } } - return ocm; + return NULL; /* out of memory pools */ } -void onchipmem_free(void *p) +static void str_free(void *p) { - if(using_onchipmem == true) { - IOCM->ReleaseOnChipMem(); - IExec->DropInterface((struct Interface *)IOCM); - } else { - free(p); + int i; + + for(i = 0; i < MAX_MEM_POOLS; i++) { + if(memory_pool_free(mp[i], p)) + return; } } -#endif - -typedef lwc_hash (*lwc_hasher)(const char *, size_t); -typedef int (*lwc_strncmp)(const char *, const char *, size_t); -typedef void (*lwc_memcpy)(char *, const char *, size_t); static lwc_error lwc__initialise(void) @@ -114,10 +102,10 @@ lwc__initialise(void) memset(ctx, 0, sizeof(lwc_context)); ctx->bucketcount = NR_BUCKETS_DEFAULT; - ctx->buckets = LWC_ALLOC_BUCKET(sizeof(lwc_string *) * ctx->bucketcount); + ctx->buckets = LWC_ALLOC(sizeof(lwc_string *) * ctx->bucketcount); if (ctx->buckets == NULL) { - LWC_FREE_BUCKET(ctx); + LWC_FREE(ctx); ctx = NULL; return lwc_error_oom; } @@ -163,12 +151,16 @@ lwc__intern(const char *s, size_t slen, str = str->next; } - /* Add one for the additional NUL. */ - *ret = str = LWC_ALLOC(sizeof(lwc_string) + slen + 1); + *ret = str = LWC_ALLOC_STR(); if (str == NULL) return lwc_error_oom; - + + /* Add one for the additional NUL. */ + str->string = LWC_ALLOC(slen + 1); + if (str->string == NULL) + return lwc_error_oom; + str->prevptr = &(ctx->buckets[bucket]); str->next = ctx->buckets[bucket]; if (str->next != NULL) @@ -230,7 +222,8 @@ lwc_string_destroy(lwc_string *str) memset(str, 0xA5, sizeof(*str) + str->len); #endif - LWC_FREE(str); + LWC_FREE_STR(str); + LWC_FREE(STR_OF(str)); } /**** Shonky caseless bits ****/ diff --git a/src/mempool.c b/src/mempool.c new file mode 100755 index 0000000..5dc5498 --- /dev/null +++ b/src/mempool.c @@ -0,0 +1,147 @@ +#include +#include +#include +#include +#include "mempool.h" + +#ifdef __amigaos4__ +#include +#include + +struct Library *ocmb; +struct OCMIFace *IOCM = NULL; +#endif + +#define MEMORY_POOL_ALLOCED_CONST ((void *) 0xFFFFFFFFu) + +memory_pool_t * memory_pool_create(size_t bs, size_t c) +{ + memory_pool_t *mp = malloc(sizeof(memory_pool_t)); + if (!mp) + return NULL; + + mp->block_size = bs; + mp->count = c; + mp->pool = NULL; + + if((ocmb = IExec->OpenResource("onchipmem.resource"))) { + if((IOCM = (struct OCMIFace *)IExec->GetInterface((struct Library *)ocmb, "main", 1, NULL))) { + mp->pool = IOCM->ObtainOnChipMem(); + } + } + + if(mp->pool == NULL) { + mp->pool = malloc((mp->block_size + sizeof(void *)) * mp->count); + } + + memory_pool_clear(mp); + + mp->empty_blocks = mp->pool; + + return mp; +} + +void memory_pool_destroy(memory_pool_t *mp) +{ + if (!mp) + return; + + memory_pool_clear(mp); + +/**TODO: Track if this is an OCM or standard memory pool. + * At the moment we have no way of freeing on exit so it doesn't matter. + + IOCM->ReleaseOnChipMem(); + IExec->DropInterface((struct Interface *)IOCM); + free(mp->pool); +*/ + free(mp); +} + +void memory_pool_clear(memory_pool_t *mp) +{ + if (!mp) + return; + + size_t i; + void **p; + + for (i = 0; i < mp->count - 1; i++) + { + p = (void **) ((uint8_t *) mp->pool + (mp->block_size * (i + 1) + + sizeof(void *) * i)); + *p = (uint8_t *) mp->pool + (mp->block_size + sizeof(void *)) * (i + 1); + } + + p = (void **) ((uint8_t *) mp->pool + (mp->block_size * mp->count + + sizeof(void *) * (mp->count - 1))); + *p = NULL; + + mp->empty_blocks = mp->pool; +} + +void memory_pool_dump(memory_pool_t *mp, void (* print_func) (void *value)) +{ + printf("start: %p, size: %d, count: %d\n", mp->pool, + (mp->block_size + sizeof(void *)) * mp->count, mp->count); + + void *block; + void **next; + size_t i; + + for (i = 0; i < mp->count; i++) + { + block = (void *) ((uint8_t *) mp->pool + (mp->block_size * i) + + sizeof(void *) * i); + next = (void **) ((uint8_t *) block + sizeof(void *)); + + printf("block #%i(%p):", i, block); + + if (*next == MEMORY_POOL_ALLOCED_CONST) + { + printf(" allocated"); + + if (print_func) + { + printf(", value: "); + print_func(block); + } + + printf("\n"); + } else + { + printf(" free, next address %p\n", *next); + } + } +} + +void * memory_pool_alloc(memory_pool_t *mp) +{ + void *p; + + if (mp->empty_blocks) + { + p = mp->empty_blocks; + mp->empty_blocks = * (void **) ((uint8_t *) mp->empty_blocks + + mp->block_size); + *(void **) ((uint8_t *) p + mp->block_size) = MEMORY_POOL_ALLOCED_CONST; + return p; + } else + { + return NULL; + } +} + +bool memory_pool_free(memory_pool_t *mp, void *p) +{ + if (p && (p >= mp->pool) && (p <= (void *) ((uint8_t *) mp->pool + + (mp->block_size + sizeof(void *)) * mp->count))) + { + *(void **) ((uint8_t *) p + mp->block_size) = mp->empty_blocks; + mp->empty_blocks = p; + return true; + } else { + return false; + } +} + diff --git a/src/mempool.h b/src/mempool.h new file mode 100755 index 0000000..c99f239 --- /dev/null +++ b/src/mempool.h @@ -0,0 +1,22 @@ +#ifndef MEMPOOL_H +#define MEMPOOL_H 1 + +#include +#include +#include + +typedef struct memory_pool_s +{ + void *pool; + void *empty_blocks; + size_t block_size; + size_t count; +} __attribute__ ((__aligned__)) memory_pool_t; + +memory_pool_t * memory_pool_create(size_t bs, size_t c); +void memory_pool_destroy(memory_pool_t *mp); +void memory_pool_clear(memory_pool_t *mp); +void memory_pool_dump(memory_pool_t *mp, void (* print_func) (void *value)); +void *memory_pool_alloc(memory_pool_t *mp); +bool memory_pool_free(memory_pool_t *mp, void *p); +#endif /* MEMPOOL_H */ -- cgit v1.2.3