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
This commit is contained in:
Nick Mathewson 2007-04-23 14:42:27 +00:00
parent bc0b78bc10
commit 2f4784cbd8
3 changed files with 108 additions and 14 deletions

View File

@ -26,6 +26,8 @@ Changes in version 0.2.0.1-alpha - 2007-??-??
internally and transfer the data in-process. This saves two internally and transfer the data in-process. This saves two
sockets per anonymous directory connection (at the client and at sockets per anonymous directory connection (at the client and at
the server), and avoids the nasty Windows socketpair() workaround. 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): o Minor features (build):
- Make autoconf search for libevent, openssl, and zlib consistently. - Make autoconf search for libevent, openssl, and zlib consistently.

View File

@ -377,7 +377,7 @@ mp_pool_new(size_t item_size, size_t chunk_capacity)
} }
/** If there are more than <b>n</b> empty chunks in <b>pool</b>, free the /** If there are more than <b>n</b> empty chunks in <b>pool</b>, free the
* exces ones that have been empty for the longest. (If <b>n</b> is less * excess ones that have been empty for the longest. (If <b>n</b> is less
* than zero, free only empty chunks that were not used since the last * than zero, free only empty chunks that were not used since the last
* call to mp_pool_clean(), leaving only -<b>n</b>.) */ * call to mp_pool_clean(), leaving only -<b>n</b>.) */
void void

View File

@ -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. <b>new_capacity</b> must be \>= /** Change a buffer's capacity. <b>new_capacity</b> must be \>=
* buf->datalen. */ * buf->datalen. */
static void 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 /* XXX Some play code to throw away old buffers sometimes rather
* than constantly reallocing them; just in case this is our memory * than constantly reallocing them; just in case this is our memory
* problem. It looks for now like it isn't, so disabled. -RD */ * 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); oldmem = RAW_MEM(buf->mem);
tor_free(oldmem); tor_free(oldmem);
buf->mem = buf->cur = newmem; 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 { } else {
buf->mem = GUARDED_MEM(tor_realloc(RAW_MEM(buf->mem), char *raw;
ALLOC_LEN(new_capacity))); 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); SET_GUARDS(buf->mem, new_capacity);
buf->cur = buf->mem+offset; buf->cur = buf->mem+offset;
} }
@ -239,7 +305,8 @@ buf_resize(buf_t *buf, size_t new_capacity)
(size_t)(buf->len-offset)); (size_t)(buf->len-offset));
buf->cur += new_capacity-buf->len; 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 #ifdef CHECK_AFTER_RESIZE
assert_buf_ok(buf); assert_buf_ok(buf);
@ -292,6 +359,11 @@ buf_shrink(buf_t *buf)
size_t new_len; size_t new_len;
new_len = buf->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) while (buf->highwater < (new_len>>2) && new_len > MIN_LAZY_SHRINK_SIZE*2)
new_len >>= 1; new_len >>= 1;
@ -328,16 +400,22 @@ buf_nul_terminate(buf_t *buf)
return 0; return 0;
} }
/** Create and return a new buf with capacity <b>size</b>. */ /** Create and return a new buf with capacity <b>size</b>.
* (Used for testing). */
buf_t * buf_t *
buf_new_with_capacity(size_t size) buf_new_with_capacity(size_t size)
{ {
buf_t *buf; buf_t *buf;
buf = tor_malloc_zero(sizeof(buf_t)); buf = tor_malloc_zero(sizeof(buf_t));
buf->magic = BUFFER_MAGIC; buf->magic = BUFFER_MAGIC;
if (size == MIN_LAZY_SHRINK_SIZE) {
buf_get_initial_mem(buf);
} else {
buf->cur = buf->mem = GUARDED_MEM(tor_malloc(ALLOC_LEN(size))); buf->cur = buf->mem = GUARDED_MEM(tor_malloc(ALLOC_LEN(size)));
SET_GUARDS(buf->mem, size); SET_GUARDS(buf->mem, size);
buf->len = buf->memsize = size; buf->len = size;
buf->memsize = ALLOC_LEN(size);
}
assert_buf_ok(buf); assert_buf_ok(buf);
return buf; return buf;
@ -356,7 +434,7 @@ buf_clear(buf_t *buf)
{ {
buf->datalen = 0; buf->datalen = 0;
buf->cur = buf->mem; buf->cur = buf->mem;
buf->len = buf->memsize; /* buf->len = buf->memsize; bad. */
} }
/** Return the number of bytes stored in <b>buf</b> */ /** Return the number of bytes stored in <b>buf</b> */
@ -389,8 +467,12 @@ buf_free(buf_t *buf)
char *oldmem; char *oldmem;
assert_buf_ok(buf); assert_buf_ok(buf);
buf->magic = 0xDEADBEEF; buf->magic = 0xDEADBEEF;
if (buf->len == MIN_LAZY_SHRINK_SIZE) {
add_buf_mem_to_freelist(buf);
} else {
oldmem = RAW_MEM(buf->mem); oldmem = RAW_MEM(buf->mem);
tor_free(oldmem); tor_free(oldmem);
}
tor_free(buf); tor_free(buf);
} }
@ -1405,14 +1487,24 @@ assert_buf_ok(buf_t *buf)
{ {
tor_assert(buf); tor_assert(buf);
tor_assert(buf->magic == BUFFER_MAGIC); tor_assert(buf->magic == BUFFER_MAGIC);
tor_assert(buf->mem);
tor_assert(buf->highwater <= buf->len); tor_assert(buf->highwater <= buf->len);
tor_assert(buf->datalen <= buf->highwater); 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 #ifdef SENTINELS
{ if (buf->mem) {
uint32_t u32 = get_uint32(buf->mem - 4); uint32_t u32 = get_uint32(buf->mem - 4);
tor_assert(u32 == START_MAGIC); 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); tor_assert(u32 == END_MAGIC);
} }
#endif #endif