summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Young <chris@unsatisfactorysoftware.co.uk>2013-02-26 19:39:05 (GMT)
committer Chris Young <chris@unsatisfactorysoftware.co.uk>2013-02-26 19:39:05 (GMT)
commit439f14b83969a5bdbce21a3f0143a5d0fbffc8f2 (patch)
tree45eefeae3a41959c5ba433ca631d8a8a2aa30b9e
parent53a1eb165791de4976df55af63751d7adfd74c4c (diff)
downloadlibwapcaplet-439f14b83969a5bdbce21a3f0143a5d0fbffc8f2.tar.gz
libwapcaplet-439f14b83969a5bdbce21a3f0143a5d0fbffc8f2.tar.bz2
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.
-rw-r--r--include/libwapcaplet/libwapcaplet.h3
-rw-r--r--src/Makefile2
-rw-r--r--src/libwapcaplet.c91
-rwxr-xr-xsrc/mempool.c147
-rwxr-xr-xsrc/mempool.h22
5 files changed, 214 insertions, 51 deletions
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 <string.h>
#include <assert.h>
+#include "mempool.h"
#include "libwapcaplet/libwapcaplet.h"
-#ifdef __amigaos4__
-#include <proto/exec.h>
-#include <proto/onchipmem.h>
-#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
--- a/dev/null
+++ b/src/mempool.c
@@ -0,0 +1,147 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include "mempool.h"
+
+#ifdef __amigaos4__
+#include <proto/exec.h>
+#include <proto/onchipmem.h>
+
+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
--- a/dev/null
+++ b/src/mempool.h
@@ -0,0 +1,22 @@
+#ifndef MEMPOOL_H
+#define MEMPOOL_H 1
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+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 */