mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-10 21:23:58 +01:00
r12336@catbus: nickm | 2007-04-10 17:34:25 -0400
Unit tests and debugging for memory pool implementation. svn:r9938
This commit is contained in:
parent
d7359eb996
commit
6ba0b0e9f4
@ -56,6 +56,8 @@
|
||||
/** DOCDOC */
|
||||
#define MIN_CHUNK 4096
|
||||
|
||||
typedef struct mp_allocated_t mp_allocated_t;
|
||||
|
||||
/** DOCDOC */
|
||||
struct mp_allocated_t {
|
||||
mp_chunk_t *in_chunk;
|
||||
@ -66,6 +68,20 @@ struct mp_allocated_t {
|
||||
};
|
||||
};
|
||||
|
||||
/** DOCDOC */
|
||||
struct mp_chunk_t {
|
||||
unsigned long magic;
|
||||
mp_chunk_t *next;
|
||||
mp_chunk_t *prev;
|
||||
mp_pool_t *pool;
|
||||
mp_allocated_t *first_free;
|
||||
int n_allocated;
|
||||
int capacity;
|
||||
size_t mem_size;
|
||||
char *next_mem;
|
||||
char mem[1];
|
||||
};
|
||||
|
||||
/** DOCDOC */
|
||||
#define MP_CHUNK_MAGIC 0x09870123
|
||||
|
||||
@ -73,9 +89,9 @@ struct mp_allocated_t {
|
||||
#define CHUNK_OVERHEAD (sizeof(mp_chunk_t)-1)
|
||||
|
||||
/** DOCDOC */
|
||||
#define A2M(a) (&(a)->mem)
|
||||
#define A2M(a) (&(a)->mem[0])
|
||||
/** DOCDOC */
|
||||
#define M2A(p) ( ((char*)p) - STRUCT_OFFSET(mp_chunk_t, mem) )
|
||||
#define M2A(p) ( ((char*)p) - STRUCT_OFFSET(mp_allocated_t, mem) )
|
||||
|
||||
/* INVARIANT: every chunk can hold 2 or more items. */
|
||||
|
||||
@ -113,6 +129,7 @@ mp_pool_get(mp_pool_t *pool)
|
||||
chunk->next->prev = chunk;
|
||||
pool->used_chunks = chunk;
|
||||
ASSERT(!chunk->prev);
|
||||
--pool->n_empty_chunks;
|
||||
} else {
|
||||
/* Allocate a new chunk and add it to the used list. */
|
||||
chunk = mp_chunk_new(pool);
|
||||
@ -130,7 +147,7 @@ mp_pool_get(mp_pool_t *pool)
|
||||
chunk->first_free = allocated->next_free;
|
||||
allocated->next_free = NULL; /* debugging */
|
||||
} else {
|
||||
ASSERT(chunk->next_mem + pool->item_alloc_size <
|
||||
ASSERT(chunk->next_mem + pool->item_alloc_size <=
|
||||
chunk->mem + chunk->mem_size);
|
||||
allocated = (void*)chunk->next_mem;
|
||||
chunk->next_mem += pool->item_alloc_size;
|
||||
@ -147,7 +164,8 @@ mp_pool_get(mp_pool_t *pool)
|
||||
chunk->next->prev = NULL;
|
||||
|
||||
chunk->next = pool->full_chunks;
|
||||
pool->full_chunks->prev = chunk;
|
||||
if (chunk->next)
|
||||
chunk->next->prev = chunk;
|
||||
pool->full_chunks = chunk;
|
||||
}
|
||||
|
||||
@ -245,7 +263,7 @@ mp_pool_new(size_t item_size, size_t chunk_capacity)
|
||||
if (chunk_capacity < MIN_CHUNK) /* Guess system page size. */
|
||||
chunk_capacity = MIN_CHUNK;
|
||||
|
||||
pool->new_chunk_capacity = (chunk_capacity-CHUNK_OVERHEAD / alloc_size);
|
||||
pool->new_chunk_capacity = (chunk_capacity-CHUNK_OVERHEAD) / alloc_size;
|
||||
pool->item_alloc_size = alloc_size;
|
||||
|
||||
return pool;
|
||||
@ -291,3 +309,54 @@ mp_pool_destroy(mp_pool_t *pool)
|
||||
FREE(pool);
|
||||
}
|
||||
|
||||
static int
|
||||
assert_chunks_ok(mp_pool_t *pool, mp_chunk_t *chunk, int empty, int full)
|
||||
{
|
||||
mp_allocated_t *allocated;
|
||||
int n = 0;
|
||||
if (chunk)
|
||||
ASSERT(chunk->prev == NULL);
|
||||
|
||||
while (chunk) {
|
||||
n++;
|
||||
ASSERT(chunk->magic == MP_CHUNK_MAGIC);
|
||||
ASSERT(chunk->pool == pool);
|
||||
for (allocated = chunk->first_free; allocated;
|
||||
allocated = allocated->next_free) {
|
||||
ASSERT(allocated->in_chunk == chunk);
|
||||
}
|
||||
if (empty)
|
||||
ASSERT(chunk->n_allocated == 0);
|
||||
else if (full)
|
||||
ASSERT(chunk->n_allocated == chunk->capacity);
|
||||
else
|
||||
ASSERT(chunk->n_allocated > 0 && chunk->n_allocated < chunk->capacity);
|
||||
|
||||
ASSERT(chunk->capacity == pool->new_chunk_capacity);
|
||||
|
||||
ASSERT(chunk->mem_size ==
|
||||
pool->new_chunk_capacity * pool->item_alloc_size);
|
||||
|
||||
ASSERT(chunk->next_mem >= chunk->mem &&
|
||||
chunk->next_mem <= chunk->mem + chunk->mem_size);
|
||||
|
||||
if (chunk->next)
|
||||
ASSERT(chunk->next->prev == chunk);
|
||||
|
||||
chunk = chunk->next;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
void
|
||||
mp_pool_assert_ok(mp_pool_t *pool)
|
||||
{
|
||||
int n_empty;
|
||||
|
||||
n_empty = assert_chunks_ok(pool, pool->empty_chunks, 1, 0);
|
||||
assert_chunks_ok(pool, pool->full_chunks, 0, 1);
|
||||
assert_chunks_ok(pool, pool->used_chunks, 0, 0);
|
||||
|
||||
ASSERT(pool->n_empty_chunks == n_empty);
|
||||
}
|
||||
|
||||
|
@ -17,32 +17,18 @@ void mp_pool_release(void *item);
|
||||
mp_pool_t *mp_pool_new(size_t item_size, unsigned int n_per_chunk);
|
||||
void mp_pool_clean(mp_pool_t *pool);
|
||||
void mp_pool_destroy(mp_pool_t *pool);
|
||||
void mp_pool_assert_ok(mp_pool_t *pool);
|
||||
|
||||
#ifdef MEMPOOL_PRIVATE
|
||||
typedef struct mp_allocated_t mp_allocated_t;
|
||||
typedef struct mp_chunk_t mp_chunk_t;
|
||||
|
||||
/** DOCDOC */
|
||||
struct mp_chunk_t {
|
||||
unsigned long magic;
|
||||
mp_chunk_t *next;
|
||||
mp_chunk_t *prev;
|
||||
mp_pool_t *pool;
|
||||
mp_allocated_t *first_free;
|
||||
int n_allocated;
|
||||
int capacity;
|
||||
size_t mem_size;
|
||||
char *next_mem;
|
||||
char mem[1];
|
||||
};
|
||||
|
||||
/** DOCDOC */
|
||||
struct mp_pool_t {
|
||||
mp_chunk_t *empty_chunks;
|
||||
mp_chunk_t *used_chunks;
|
||||
mp_chunk_t *full_chunks;
|
||||
int n_empty_chunks;
|
||||
size_t new_chunk_capacity;
|
||||
int new_chunk_capacity;
|
||||
size_t item_alloc_size;
|
||||
};
|
||||
#endif
|
||||
|
@ -23,9 +23,12 @@ const char test_c_id[] =
|
||||
#include <dirent.h>
|
||||
#endif
|
||||
|
||||
#define MEMPOOL_PRIVATE
|
||||
|
||||
#include "or.h"
|
||||
#include "../common/test.h"
|
||||
#include "../common/torgzip.h"
|
||||
#include "../common/mempool.h"
|
||||
|
||||
int have_failed = 0;
|
||||
|
||||
@ -2104,6 +2107,52 @@ bench_aes(void)
|
||||
crypto_free_cipher_env(c);
|
||||
}
|
||||
|
||||
static void
|
||||
test_mempool(void)
|
||||
{
|
||||
mp_pool_t *pool;
|
||||
smartlist_t *allocated;
|
||||
int i;
|
||||
|
||||
pool = mp_pool_new(1, 100);
|
||||
test_assert(pool->new_chunk_capacity >= 100);
|
||||
test_assert(pool->item_alloc_size >= sizeof(void*)+1);
|
||||
mp_pool_destroy(pool);
|
||||
|
||||
pool = mp_pool_new(241, 10);
|
||||
test_assert(pool->new_chunk_capacity >= 10);
|
||||
test_assert(pool->item_alloc_size >= sizeof(void*)+241);
|
||||
test_eq(pool->item_alloc_size & 0x03, 0);
|
||||
test_assert(pool->new_chunk_capacity < 60);
|
||||
|
||||
allocated = smartlist_create();
|
||||
for (i = 0; i < 100000; ++i) {
|
||||
if (smartlist_len(allocated) < 20 || crypto_rand_int(2)) {
|
||||
void *m = mp_pool_get(pool);
|
||||
memset(m, 0x09, 241);
|
||||
smartlist_add(allocated, m);
|
||||
//printf("%d: %p\n", i, m);
|
||||
//mp_pool_assert_ok(pool);
|
||||
} else {
|
||||
int idx = crypto_rand_int(smartlist_len(allocated));
|
||||
void *m = smartlist_get(allocated, idx);
|
||||
//printf("%d: free %p\n", i, m);
|
||||
smartlist_del(allocated, idx);
|
||||
mp_pool_release(m);
|
||||
//mp_pool_assert_ok(pool);
|
||||
}
|
||||
if (crypto_rand_int(777)==0)
|
||||
mp_pool_clean(pool);
|
||||
|
||||
if (i % 777)
|
||||
mp_pool_assert_ok(pool);
|
||||
}
|
||||
SMARTLIST_FOREACH(allocated, void *, m, mp_pool_release(m));
|
||||
mp_pool_assert_ok(pool);
|
||||
mp_pool_destroy(pool);
|
||||
smartlist_free(allocated);
|
||||
}
|
||||
|
||||
int
|
||||
main(int c, char**v)
|
||||
{
|
||||
@ -2145,6 +2194,7 @@ main(int c, char**v)
|
||||
test_gzip();
|
||||
test_util();
|
||||
test_smartlist();
|
||||
test_mempool();
|
||||
test_strmap();
|
||||
test_control_formats();
|
||||
test_pqueue();
|
||||
|
Loading…
Reference in New Issue
Block a user