mirror of https://github.com/svaarala/duktape.git
Sami Vaarala
10 years ago
3 changed files with 284 additions and 0 deletions
@ -0,0 +1,10 @@ |
|||
===================== |
|||
Hybrid pool allocator |
|||
===================== |
|||
|
|||
Example allocator that tries to satisfy memory allocations for small sizes |
|||
from a set of fixed pools, but always falls back to malloc/realloc/free if |
|||
a larger size is requested or the pools have been exhausted. |
|||
|
|||
This may be useful to reduce memory churn when the platform allocator does |
|||
not handle allocations for a lot of small memory areas efficiently. |
@ -0,0 +1,263 @@ |
|||
/*
|
|||
* Example memory allocator with pool allocation for small sizes and |
|||
* fallback into malloc/realloc/free for larger sizes or when the pools |
|||
* are exhausted. |
|||
* |
|||
* Useful to reduce memory churn or work around a platform allocator |
|||
* that doesn't handle a lot of small allocations efficiently. |
|||
*/ |
|||
|
|||
#include "duktape.h" |
|||
#include <stdio.h> |
|||
#include <stdlib.h> |
|||
#include <string.h> |
|||
#include <stdint.h> |
|||
|
|||
typedef struct { |
|||
size_t size; |
|||
int count; |
|||
} pool_size_spec; |
|||
|
|||
static pool_size_spec pool_sizes[] = { |
|||
{ 32, 1024 }, |
|||
{ 48, 2048 }, |
|||
{ 64, 2048 }, |
|||
{ 128, 2048 }, |
|||
{ 256, 512 }, |
|||
{ 1024, 64 }, |
|||
{ 2048, 32 } |
|||
}; |
|||
|
|||
#define NUM_POOLS (sizeof(pool_sizes) / sizeof(pool_size_spec)) |
|||
|
|||
/* This must fit into the smallest pool entry. */ |
|||
struct pool_free_entry; |
|||
typedef struct pool_free_entry pool_free_entry; |
|||
struct pool_free_entry { |
|||
pool_free_entry *next; |
|||
}; |
|||
|
|||
typedef struct { |
|||
pool_free_entry *free; |
|||
char *alloc_start; |
|||
char *alloc_end; |
|||
size_t size; |
|||
int count; |
|||
} pool_header; |
|||
|
|||
typedef struct { |
|||
pool_header headers[NUM_POOLS]; |
|||
size_t pool_max_size; |
|||
char *alloc_start; |
|||
char *alloc_end; |
|||
} pool_state; |
|||
|
|||
#define ADDR_IN_STATE_ALLOC(st,p) \ |
|||
((char *) (p) >= (st)->alloc_start && (char *) (p) < (st)->alloc_end) |
|||
#define ADDR_IN_HEADER_ALLOC(hdr,p) \ |
|||
((char *) (p) >= (hdr)->alloc_start && (char *) (p) < (hdr)->alloc_end) |
|||
|
|||
static void dump_pool_state(pool_state *st) { |
|||
pool_free_entry *free; |
|||
int free_len; |
|||
int i; |
|||
|
|||
printf("=== Pool state: st=%p\n", (void *) st); |
|||
for (i = 0; i < (int) NUM_POOLS; i++) { |
|||
pool_header *hdr = st->headers + i; |
|||
|
|||
for (free = hdr->free, free_len = 0; free != NULL; free = free->next) { |
|||
free_len++; |
|||
} |
|||
|
|||
printf("[%d]: size %ld, count %ld, used %ld, free list len %ld\n", |
|||
i, (long) hdr->size, (long) hdr->count, |
|||
(long) (hdr->count - free_len), |
|||
(long) free_len); |
|||
} |
|||
} |
|||
|
|||
void *duk_alloc_hybrid_init(void) { |
|||
pool_state *st; |
|||
size_t total_size, max_size; |
|||
int i, j; |
|||
char *p; |
|||
|
|||
st = malloc(sizeof(pool_state)); |
|||
if (!st) { |
|||
return NULL; |
|||
} |
|||
memset((void *) st, 0, sizeof(pool_state)); |
|||
st->alloc_start = NULL; |
|||
st->alloc_end = NULL; |
|||
|
|||
for (i = 0, total_size = 0, max_size = 0; i < (int) NUM_POOLS; i++) { |
|||
printf("Pool %d: size %ld, count %ld\n", i, (long) pool_sizes[i].size, (long) pool_sizes[i].count); |
|||
total_size += pool_sizes[i].size * pool_sizes[i].count; |
|||
if (pool_sizes[i].size > max_size) { |
|||
max_size = pool_sizes[i].size; |
|||
} |
|||
} |
|||
printf("Total size %ld, max pool size %ld\n", (long) total_size, (long) max_size); |
|||
|
|||
st->alloc_start = malloc(total_size); |
|||
if (!st->alloc_start) { |
|||
free(st); |
|||
return NULL; |
|||
} |
|||
st->alloc_end = st->alloc_start + total_size; |
|||
st->pool_max_size = max_size; |
|||
memset((void *) st->alloc_start, 0, total_size); |
|||
|
|||
for (i = 0, p = st->alloc_start; i < (int) NUM_POOLS; i++) { |
|||
pool_header *hdr = st->headers + i; |
|||
|
|||
hdr->alloc_start = p; |
|||
hdr->alloc_end = p + pool_sizes[i].size * pool_sizes[i].count; |
|||
hdr->free = (pool_free_entry *) p; |
|||
hdr->size = pool_sizes[i].size; |
|||
hdr->count = pool_sizes[i].count; |
|||
|
|||
for (j = 0; j < pool_sizes[i].count; j++) { |
|||
pool_free_entry *ent = (pool_free_entry *) p; |
|||
if (j == pool_sizes[i].count - 1) { |
|||
ent->next = (pool_free_entry *) NULL; |
|||
} else { |
|||
ent->next = (pool_free_entry *) (p + pool_sizes[i].size); |
|||
} |
|||
p += pool_sizes[i].size; |
|||
} |
|||
} |
|||
|
|||
dump_pool_state(st); |
|||
|
|||
/* Use 'st' as udata. */ |
|||
return (void *) st; |
|||
} |
|||
|
|||
void *duk_alloc_hybrid(void *udata, duk_size_t size) { |
|||
pool_state *st = (pool_state *) udata; |
|||
int i; |
|||
void *new_ptr; |
|||
|
|||
#if 0 |
|||
dump_pool_state(st); |
|||
#endif |
|||
|
|||
if (size == 0) { |
|||
return NULL; |
|||
} |
|||
if (size > st->pool_max_size) { |
|||
printf("alloc fallback: %ld\n", (long) size); |
|||
return malloc(size); |
|||
} |
|||
|
|||
for (i = 0; i < (int) NUM_POOLS; i++) { |
|||
pool_header *hdr = st->headers + i; |
|||
if (hdr->size < size) { |
|||
continue; |
|||
} |
|||
|
|||
if (hdr->free) { |
|||
#if 0 |
|||
printf("alloc from pool: %ld -> pool size %ld\n", (long) size, (long) hdr->size); |
|||
#endif |
|||
new_ptr = (void *) hdr->free; |
|||
hdr->free = hdr->free->next; |
|||
return new_ptr; |
|||
} else { |
|||
break; |
|||
} |
|||
} |
|||
|
|||
printf("alloc fallback (out of pool): %ld\n", (long) size); |
|||
return malloc(size); |
|||
} |
|||
|
|||
void *duk_realloc_hybrid(void *udata, void *ptr, duk_size_t size) { |
|||
pool_state *st = (pool_state *) udata; |
|||
void *new_ptr; |
|||
int i; |
|||
|
|||
#if 0 |
|||
dump_pool_state(st); |
|||
#endif |
|||
|
|||
if (ADDR_IN_STATE_ALLOC(st, ptr)) { |
|||
/* 'ptr' cannot be NULL. */ |
|||
for (i = 0; i < (int) NUM_POOLS; i++) { |
|||
pool_header *hdr = st->headers + i; |
|||
if (ADDR_IN_HEADER_ALLOC(hdr, ptr)) { |
|||
if (size <= hdr->size) { |
|||
/* Still fits, no shrink support. */ |
|||
#if 0 |
|||
printf("realloc original from pool: still fits, size %ld, pool size %ld\n", |
|||
(long) size, (long) hdr->size); |
|||
#endif |
|||
return ptr; |
|||
} |
|||
|
|||
new_ptr = duk_alloc_hybrid(udata, size); |
|||
if (!new_ptr) { |
|||
printf("realloc original from pool: needed larger size, failed to alloc\n"); |
|||
return NULL; |
|||
} |
|||
memcpy(new_ptr, ptr, hdr->size); |
|||
|
|||
((pool_free_entry *) ptr)->next = hdr->free; |
|||
hdr->free = (pool_free_entry *) ptr; |
|||
#if 0 |
|||
printf("realloc original from pool: size %ld, pool size %ld\n", (long) size, (long) hdr->size); |
|||
#endif |
|||
return new_ptr; |
|||
} |
|||
} |
|||
printf("NEVER HERE\n"); |
|||
return NULL; |
|||
} else if (ptr != NULL) { |
|||
if (size == 0) { |
|||
free(ptr); |
|||
return NULL; |
|||
} else { |
|||
printf("realloc fallback: size %ld\n", (long) size); |
|||
return realloc(ptr, size); |
|||
} |
|||
} else { |
|||
#if 0 |
|||
printf("realloc NULL ptr, call alloc: %ld\n", (long) size); |
|||
#endif |
|||
return duk_alloc_hybrid(udata, size); |
|||
} |
|||
} |
|||
|
|||
void duk_free_hybrid(void *udata, void *ptr) { |
|||
pool_state *st = (pool_state *) udata; |
|||
int i; |
|||
|
|||
#if 0 |
|||
dump_pool_state(st); |
|||
#endif |
|||
|
|||
if (!ADDR_IN_STATE_ALLOC(st, ptr)) { |
|||
if (ptr == NULL) { |
|||
return; |
|||
} |
|||
#if 0 |
|||
printf("free out of pool: %p\n", (void *) ptr); |
|||
#endif |
|||
free(ptr); |
|||
return; |
|||
} |
|||
|
|||
for (i = 0; i < (int) NUM_POOLS; i++) { |
|||
pool_header *hdr = st->headers + i; |
|||
if (ADDR_IN_HEADER_ALLOC(hdr, ptr)) { |
|||
((pool_free_entry *) ptr)->next = hdr->free; |
|||
hdr->free = (pool_free_entry *) ptr; |
|||
#if 0 |
|||
printf("free from pool: %p\n", ptr); |
|||
#endif |
|||
return; |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,11 @@ |
|||
#ifndef DUK_ALLOC_HYBRID_H_INCLUDED |
|||
#define DUK_ALLOC_HYBRID_H_INCLUDED |
|||
|
|||
#include "duktape.h" |
|||
|
|||
void *duk_alloc_hybrid_init(void); |
|||
void *duk_alloc_hybrid(void *udata, duk_size_t size); |
|||
void *duk_realloc_hybrid(void *udata, void *ptr, duk_size_t size); |
|||
void duk_free_hybrid(void *udata, void *ptr); |
|||
|
|||
#endif /* DUK_ALLOC_HYBRID_H_INCLUDED */ |
Loading…
Reference in new issue