From 2f4784cbd8901a59cb20b10d247ad383b8539152 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Mon, 23 Apr 2007 14:42:27 +0000 Subject: [PATCH] r12499@catbus: nickm | 2007-04-23 10:42:23 -0400 Keep a freelist of unused 4k buffer chunks, rather than wasting 8k for every inactive connection_t. svn:r10006 --- ChangeLog | 2 + src/common/mempool.c | 2 +- src/or/buffers.c | 118 ++++++++++++++++++++++++++++++++++++++----- 3 files changed, 108 insertions(+), 14 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1457e97647..5a43ff007c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -26,6 +26,8 @@ Changes in version 0.2.0.1-alpha - 2007-??-?? internally and transfer the data in-process. This saves two sockets per anonymous directory connection (at the client and at the server), and avoids the nasty Windows socketpair() workaround. + - Keep unused 4k buffers on a free list, rather than wasting 8k for every + single inactive connection_t. o Minor features (build): - Make autoconf search for libevent, openssl, and zlib consistently. diff --git a/src/common/mempool.c b/src/common/mempool.c index dcdb27c3c7..feb32230b1 100644 --- a/src/common/mempool.c +++ b/src/common/mempool.c @@ -377,7 +377,7 @@ mp_pool_new(size_t item_size, size_t chunk_capacity) } /** If there are more than n empty chunks in pool, free the - * exces ones that have been empty for the longest. (If n is less + * excess ones that have been empty for the longest. (If n is less * than zero, free only empty chunks that were not used since the last * call to mp_pool_clean(), leaving only -n.) */ void diff --git a/src/or/buffers.c b/src/or/buffers.c index e9ca2d7f1a..cf5b0bb0e9 100644 --- a/src/or/buffers.c +++ b/src/or/buffers.c @@ -158,6 +158,57 @@ _split_range(buf_t *buf, char *at, size_t *len, } } +/** DOCDOC */ +static char *free_mem_list = NULL; +static int free_mem_list_len = 0; +/*XXXX020 Actually remove stuff from freelist when it gets too big */ + +/** DOCDOC */ +static void +add_buf_mem_to_freelist(buf_t *buf) +{ + char *mem; + + tor_assert(buf->len == MIN_LAZY_SHRINK_SIZE); + tor_assert(buf->datalen == 0); + tor_assert(buf->mem); + + mem = RAW_MEM(buf->mem); + buf->len = buf->memsize = 0; + buf->mem = buf->cur = NULL; + + *(char**)mem = free_mem_list; + free_mem_list = mem; + ++free_mem_list_len; + log_info(LD_GENERAL, "Add buf mem to freelist. Freelist has %d entries.", + free_mem_list_len); +} + +/** DOCDOC */ +static void +buf_get_initial_mem(buf_t *buf) +{ + char *mem; + tor_assert(!buf->mem); + + if (free_mem_list) { + mem = free_mem_list; + free_mem_list = *(char**)mem; + --free_mem_list_len; + log_info(LD_GENERAL, "Got buf mem from freelist. Freelist has %d entries.", + free_mem_list_len); + } else { + log_info(LD_GENERAL, "Freelist empty; allocating another chunk."); + tor_assert(free_mem_list_len == 0); + mem = tor_malloc(ALLOC_LEN(MIN_LAZY_SHRINK_SIZE)); + } + buf->mem = GUARDED_MEM(mem); + SET_GUARDS(buf->mem, MIN_LAZY_SHRINK_SIZE); + buf->len = MIN_LAZY_SHRINK_SIZE; + buf->memsize = ALLOC_LEN(MIN_LAZY_SHRINK_SIZE); + buf->cur = buf->mem; +} + /** Change a buffer's capacity. new_capacity must be \>= * buf->datalen. */ static void @@ -205,6 +256,7 @@ buf_resize(buf_t *buf, size_t new_capacity) } } +#if 0 /* XXX Some play code to throw away old buffers sometimes rather * than constantly reallocing them; just in case this is our memory * problem. It looks for now like it isn't, so disabled. -RD */ @@ -217,9 +269,23 @@ buf_resize(buf_t *buf, size_t new_capacity) oldmem = RAW_MEM(buf->mem); tor_free(oldmem); buf->mem = buf->cur = newmem; + } else { /* ... */ } +#endif + + if (buf->len == 0 && new_capacity <= MIN_LAZY_SHRINK_SIZE) { + new_capacity = MIN_LAZY_SHRINK_SIZE; + tor_assert(!buf->mem); + buf_get_initial_mem(buf); } else { - buf->mem = GUARDED_MEM(tor_realloc(RAW_MEM(buf->mem), - ALLOC_LEN(new_capacity))); + char *raw; + if (buf->mem) + raw = tor_realloc(RAW_MEM(buf->mem), ALLOC_LEN(new_capacity)); + else { + log_info(LD_GENERAL, "Jumping straight from 0 bytes to %d", + (int)new_capacity); + raw = tor_malloc(ALLOC_LEN(new_capacity)); + } + buf->mem = GUARDED_MEM(raw); SET_GUARDS(buf->mem, new_capacity); buf->cur = buf->mem+offset; } @@ -239,7 +305,8 @@ buf_resize(buf_t *buf, size_t new_capacity) (size_t)(buf->len-offset)); buf->cur += new_capacity-buf->len; } - buf->memsize = buf->len = new_capacity; + buf->len = new_capacity; + buf->memsize = ALLOC_LEN(buf->len); #ifdef CHECK_AFTER_RESIZE assert_buf_ok(buf); @@ -292,6 +359,11 @@ buf_shrink(buf_t *buf) size_t new_len; new_len = buf->len; + if (buf->datalen == 0 && buf->highwater == 0 && + buf->len == MIN_LAZY_SHRINK_SIZE) { + add_buf_mem_to_freelist(buf); + return; + } while (buf->highwater < (new_len>>2) && new_len > MIN_LAZY_SHRINK_SIZE*2) new_len >>= 1; @@ -328,16 +400,22 @@ buf_nul_terminate(buf_t *buf) return 0; } -/** Create and return a new buf with capacity size. */ +/** Create and return a new buf with capacity size. + * (Used for testing). */ buf_t * buf_new_with_capacity(size_t size) { buf_t *buf; buf = tor_malloc_zero(sizeof(buf_t)); buf->magic = BUFFER_MAGIC; - buf->cur = buf->mem = GUARDED_MEM(tor_malloc(ALLOC_LEN(size))); - SET_GUARDS(buf->mem, size); - buf->len = buf->memsize = size; + if (size == MIN_LAZY_SHRINK_SIZE) { + buf_get_initial_mem(buf); + } else { + buf->cur = buf->mem = GUARDED_MEM(tor_malloc(ALLOC_LEN(size))); + SET_GUARDS(buf->mem, size); + buf->len = size; + buf->memsize = ALLOC_LEN(size); + } assert_buf_ok(buf); return buf; @@ -356,7 +434,7 @@ buf_clear(buf_t *buf) { buf->datalen = 0; buf->cur = buf->mem; - buf->len = buf->memsize; + /* buf->len = buf->memsize; bad. */ } /** Return the number of bytes stored in buf */ @@ -389,8 +467,12 @@ buf_free(buf_t *buf) char *oldmem; assert_buf_ok(buf); buf->magic = 0xDEADBEEF; - oldmem = RAW_MEM(buf->mem); - tor_free(oldmem); + if (buf->len == MIN_LAZY_SHRINK_SIZE) { + add_buf_mem_to_freelist(buf); + } else { + oldmem = RAW_MEM(buf->mem); + tor_free(oldmem); + } tor_free(buf); } @@ -1405,14 +1487,24 @@ assert_buf_ok(buf_t *buf) { tor_assert(buf); tor_assert(buf->magic == BUFFER_MAGIC); - tor_assert(buf->mem); tor_assert(buf->highwater <= buf->len); tor_assert(buf->datalen <= buf->highwater); + + if (buf->mem) { + tor_assert(buf->cur >= buf->mem); + tor_assert(buf->cur < buf->mem+buf->len); + tor_assert(buf->memsize == ALLOC_LEN(buf->len)); + } else { + tor_assert(!buf->cur); + tor_assert(!buf->len); + tor_assert(!buf->memsize); + } + #ifdef SENTINELS - { + if (buf->mem) { uint32_t u32 = get_uint32(buf->mem - 4); tor_assert(u32 == START_MAGIC); - u32 = get_uint32(buf->mem + buf->memsize); + u32 = get_uint32(buf->mem + buf->memsize - 8); tor_assert(u32 == END_MAGIC); } #endif