From 6ba0b0e9f46cedfa83813f1faf63ab4a24456e4d Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 11 Apr 2007 00:30:25 +0000 Subject: [PATCH] r12336@catbus: nickm | 2007-04-10 17:34:25 -0400 Unit tests and debugging for memory pool implementation. svn:r9938 --- src/common/mempool.c | 79 +++++++++++++++++++++++++++++++++++++++++--- src/common/mempool.h | 18 ++-------- src/or/test.c | 50 ++++++++++++++++++++++++++++ 3 files changed, 126 insertions(+), 21 deletions(-) diff --git a/src/common/mempool.c b/src/common/mempool.c index f62821ba7c..853c2b371a 100644 --- a/src/common/mempool.c +++ b/src/common/mempool.c @@ -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); +} + diff --git a/src/common/mempool.h b/src/common/mempool.h index 45e3646819..2ee32fb137 100644 --- a/src/common/mempool.h +++ b/src/common/mempool.h @@ -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 diff --git a/src/or/test.c b/src/or/test.c index 03a589c2c0..7294e413a7 100644 --- a/src/or/test.c +++ b/src/or/test.c @@ -23,9 +23,12 @@ const char test_c_id[] = #include #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();