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
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
|