You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

210 lines
5.1 KiB

#include <stdio.h>
#include <stdlib.h>
#include "memory.h"
#include "templates.h"
#include "freelist.h"
typedef struct chunk chunk;
struct chunk {
chunk *next; /* only used when in free_lists */
};
#define GRAN (sizeof (struct chunk))
#define ALLOC_SIZE (1 << 20)
#define MAX_CHUNK_SIZE 256
#define NUM_BLOCK_TYPES (MAX_CHUNK_SIZE / GRAN)
#ifdef MDEBUG1
#define MAX_POOLS 100
#else
#define MAX_POOLS 1
#endif
#ifdef MDEBUG1
static void freesize(void *p, size_t s) { (void)s; free(p); }
static void die(char *blah) { perror(blah); abort(); }
LIST(alloclist, chunk *);
LIST_IMPL(alloclist, chunk *, KEEP(chunk *), malloc, freesize);
void print_memblock_summary2(int size);
#endif
struct chunkpool {
chunk *ch;
MDEBUG1_ONLY( int pool_id; )
MDEBUG1_ONLY( alloclist *all; )
};
static struct chunkpool free_lists[NUM_BLOCK_TYPES][MAX_POOLS];
#ifdef MDEBUG1
static int total[NUM_BLOCK_TYPES][MAX_POOLS];
static int used[NUM_BLOCK_TYPES][MAX_POOLS];
static int allocs[NUM_BLOCK_TYPES][MAX_POOLS];
static int total_mallocs = 0;
static int total_alloc = 0;
#endif
void *block_malloc(size_t size) {
return block_malloc2(size, -1);
}
void *block_malloc2(size_t size, int pool_id) {
chunk **fl = NULL;
void *result;
int granmult;
int pool = 0;
if (size > MAX_CHUNK_SIZE || size % GRAN != 0) {
MDEBUG1_ONLY( total_mallocs++; )
return malloc(size);
}
granmult = size / GRAN;
#ifdef MDEBUG1
for (pool = 0; pool + 1 < MAX_POOLS; pool++) {
if (free_lists[granmult - 1][pool].pool_id == 0) {
free_lists[granmult - 1][pool].pool_id = pool_id;
}
if (free_lists[granmult - 1][pool].pool_id == pool_id) {
break;
}
}
#endif
fl = &free_lists[granmult - 1][pool].ch;
if (*fl == NULL)
{
chunk *new_block = malloc(ALLOC_SIZE);
chunk *p;
MDEBUG1_ONLY( int old_size = total[granmult-1][pool]; )
if (!new_block) return NULL;
MDEBUG1_ONLY( insert_alloclist(&free_lists[granmult - 1][pool].all, new_block); )
for (p = new_block; (char*)(p + granmult) <= ((char*)new_block) + ALLOC_SIZE; p += granmult) {
/* each iteration adds a new chunk to the list */
MDEBUG1_ONLY( total[granmult-1][pool]++; )
*fl = p;
fl = &p->next;
}
*fl = NULL;
fl = &free_lists[granmult - 1][pool].ch;
MDEBUG1_ONLY( assert((total[granmult-1][pool]-old_size)*size <= ALLOC_SIZE); )
MDEBUG1_ONLY( assert(total[granmult-1][pool]*(int)size - old_size > ALLOC_SIZE - (int) size); )
#ifdef MDEBUG1
// print some info
MDEBUG2_ONLY(
fprintf(stderr, "ALLOC: for size %2ld (%d:line %d), %4ld B of %4ld B used, total alloced is %8ld KiB\n", (long int) size, pool, pool_id, (long int) used[granmult-1][pool] * size, (long int) total[granmult-1][pool] * size, (long int) total_alloc / 1024);
)
assert( used[granmult-1][pool] <= (signed long) total[granmult-1][pool] );
total_alloc += ALLOC_SIZE;
#endif
}
#ifdef MDEBUG1
{
static unsigned long cnt = 0, cnt2 = 0;
if (++cnt % (1L << 20) == 0) {
if (++cnt2 % 10 == 0) {
print_memblock_summary2(0);
} else {
print_memblock_summary();
}
}
}
#endif
MDEBUG1_ONLY( used[granmult-1][pool]++; )
MDEBUG1_ONLY( allocs[granmult-1][pool]++; )
result = *fl;
*fl = (*fl)->next;
*(int *)result = ~0;
return result;
}
#ifdef MDEBUG1
static int find_closest(void *vmem, size_t size, chunk **ch, int *p) {
int pool;
*ch = NULL;
for (pool = 0; pool < MAX_POOLS; pool++) {
alloclist *a;
if (!free_lists[size/GRAN - 1][pool].all) break;
for (a = free_lists[size/GRAN - 1][pool].all; a; a = a->next) {
if (*ch < a->value && a->value <= (chunk*)vmem) {
*ch = a->value;
*p = pool;
}
}
}
assert((char*)*ch <= (char*)vmem);
if ((char*)vmem - (char*)*ch < ALLOC_SIZE) {
return 1;
} else {
return 0;
}
}
#endif
void block_free(void *vmem, size_t size) {
int pool = 0;
if (size > MAX_CHUNK_SIZE || size % GRAN != 0) {
free(vmem);
return;
}
#if MDEBUG1
{ chunk *closest;
if (!find_closest(vmem, size, &closest, &pool)) {
fprintf(stderr, "AIEE: %p + %lx < %p\n", closest, (unsigned long) ALLOC_SIZE, vmem);
assert(0);
}
}
#endif
MDEBUG1_ONLY( used[size/GRAN-1][pool]--; )
{
chunk **fl, *x;
fl = &free_lists[size/GRAN - 1][pool].ch;
x = (chunk *) vmem;
x->next = *fl;
*fl = x;
}
}
#ifdef MDEBUG1
void print_memblock_summary(void) {
print_memblock_summary2(5*1024*1024);
}
void print_memblock_summary2(int size) {
unsigned int i, j;
fprintf(stderr, "MEMORY SUMMARY:\n");
for (i = 0; i < NUM_BLOCK_TYPES; i++) {
for (j = 0; j < MAX_POOLS; j++) {
if (total[i][j] * GRAN * (i+1) < size) continue;
if (free_lists[i][j].all != NULL) {
fprintf(stderr, " pool %dB/%d:%d; %d used %d allocated (%0.1f%% of %d MiB, %0.2f%% current)\n",
(i+1) * GRAN, j, free_lists[i][j].pool_id,
used[i][j], total[i][j],
(100.0 * used[i][j]) / total[i][j],
total[i][j] * GRAN * (i+1) / 1024 / 1024,
(100.0 * used[i][j]) / allocs[i][j]);
}
}
}
}
#endif