mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-24 04:13:28 +01:00
r12706@catbus: nickm | 2007-05-09 18:39:46 -0400
Keep two freelists for buffer ram chunks: one of 4k chunks, and one of 16k chunks. Also, document the whole business. svn:r10150
This commit is contained in:
parent
b248ed620f
commit
34a09c24b5
@ -38,9 +38,9 @@ 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
|
- Keep unused 4k and 16k buffers on free lists, rather than wasting 8k
|
||||||
single inactive connection_t.
|
for every single inactive connection_t.
|
||||||
- Free items from the 4k-buffer free list when they haven't been used
|
- Free items from the 4/16k-buffer free lists when they haven't been used
|
||||||
for a while.
|
for a while.
|
||||||
|
|
||||||
o Minor features (build):
|
o Minor features (build):
|
||||||
|
170
src/or/buffers.c
170
src/or/buffers.c
@ -158,80 +158,122 @@ _split_range(buf_t *buf, char *at, size_t *len,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** DOCDOC */
|
/** A freelist of buffer RAM chunks. */
|
||||||
static char *free_mem_list = NULL;
|
typedef struct free_mem_list_t {
|
||||||
static int free_mem_list_len = 0;
|
char *list; /**< The first item on the list; begins with pointer to the
|
||||||
static int free_mem_list_lowwater = 0;
|
* next item. */
|
||||||
|
int len; /**< How many entries in <b>list</b>. */
|
||||||
|
int lowwater; /**< The smallest that list has gotten since the last call to
|
||||||
|
* buf_shrink_freelists(). */
|
||||||
|
const size_t chunksize; /**< How big are the items on the list? */
|
||||||
|
const int slack; /**< We always keep at least this many items on the list
|
||||||
|
* when shrinking it. */
|
||||||
|
const int max; /**< How many elements are we willing to throw onto the list?
|
||||||
|
*/
|
||||||
|
} free_mem_list_t;
|
||||||
|
|
||||||
/** DOCDOC */
|
/** Freelists to hold 4k and 16k memory chunks. This seems to be what
|
||||||
static void
|
* we use most. */
|
||||||
|
static free_mem_list_t free_mem_list_4k = { NULL, 0, 0, 4096, 16, INT_MAX };
|
||||||
|
static free_mem_list_t free_mem_list_16k = { NULL, 0, 0, 16384, 4, 128 };
|
||||||
|
|
||||||
|
/** Macro: True iff the size is one for which we keep a freelist. */
|
||||||
|
#define IS_FREELIST_SIZE(sz) ((sz) == 4096 || (sz) == 16384)
|
||||||
|
|
||||||
|
/** Return the proper freelist for chunks of size <b>sz</b>, or fail
|
||||||
|
* with an assertion. */
|
||||||
|
static INLINE free_mem_list_t *
|
||||||
|
get_free_mem_list(size_t sz)
|
||||||
|
{
|
||||||
|
if (sz == 4096) {
|
||||||
|
return &free_mem_list_4k;
|
||||||
|
} else {
|
||||||
|
tor_assert(sz == 16384);
|
||||||
|
return &free_mem_list_16k;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Throw the memory from <b>buf</b> onto the appropriate freelist.
|
||||||
|
* Return true if we added the memory, 0 if the freelist was full. */
|
||||||
|
static int
|
||||||
add_buf_mem_to_freelist(buf_t *buf)
|
add_buf_mem_to_freelist(buf_t *buf)
|
||||||
{
|
{
|
||||||
char *mem;
|
char *mem;
|
||||||
|
free_mem_list_t *list;
|
||||||
|
|
||||||
tor_assert(buf->len == MIN_LAZY_SHRINK_SIZE);
|
|
||||||
tor_assert(buf->datalen == 0);
|
tor_assert(buf->datalen == 0);
|
||||||
tor_assert(buf->mem);
|
tor_assert(buf->mem);
|
||||||
|
list = get_free_mem_list(buf->len);
|
||||||
|
|
||||||
|
if (list->len >= list->max)
|
||||||
|
return 0;
|
||||||
|
|
||||||
mem = RAW_MEM(buf->mem);
|
mem = RAW_MEM(buf->mem);
|
||||||
buf->len = buf->memsize = 0;
|
buf->len = buf->memsize = 0;
|
||||||
buf->mem = buf->cur = NULL;
|
buf->mem = buf->cur = NULL;
|
||||||
|
|
||||||
*(char**)mem = free_mem_list;
|
*(char**)mem = list->list;
|
||||||
free_mem_list = mem;
|
list->list = mem;
|
||||||
++free_mem_list_len;
|
++list->len;
|
||||||
log_info(LD_GENERAL, "Add buf mem to freelist. Freelist has %d entries.",
|
log_debug(LD_GENERAL, "Add buf mem to %d-byte freelist. Freelist has "
|
||||||
free_mem_list_len);
|
"%d entries.", (int)list->chunksize, list->len);
|
||||||
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** DOCDOC */
|
/** Pull memory of size <b>sz</b> from the appropriate freelist for use by
|
||||||
|
* <b>buf</b>, or allocate it as needed. */
|
||||||
static void
|
static void
|
||||||
buf_get_initial_mem(buf_t *buf)
|
buf_get_initial_mem(buf_t *buf, size_t sz)
|
||||||
{
|
{
|
||||||
char *mem;
|
char *mem;
|
||||||
|
free_mem_list_t *list = get_free_mem_list(sz);
|
||||||
tor_assert(!buf->mem);
|
tor_assert(!buf->mem);
|
||||||
|
|
||||||
if (free_mem_list) {
|
if (list->list) {
|
||||||
mem = free_mem_list;
|
mem = list->list;
|
||||||
free_mem_list = *(char**)mem;
|
list->list = *(char**)mem;
|
||||||
if (--free_mem_list_len < free_mem_list_lowwater)
|
if (--list->len < list->lowwater)
|
||||||
free_mem_list_lowwater = free_mem_list_len;
|
list->lowwater = list->len;
|
||||||
log_info(LD_GENERAL, "Got buf mem from freelist. Freelist has %d entries.",
|
log_debug(LD_GENERAL, "Got buf mem from %d-byte freelist. Freelist has "
|
||||||
free_mem_list_len);
|
"%d entries.", (int)list->chunksize, list->len);
|
||||||
} else {
|
} else {
|
||||||
log_info(LD_GENERAL, "Freelist empty; allocating another chunk.");
|
log_debug(LD_GENERAL, "%d-byte freelist empty; allocating another chunk.",
|
||||||
tor_assert(free_mem_list_len == 0);
|
(int)list->chunksize);
|
||||||
mem = tor_malloc(ALLOC_LEN(MIN_LAZY_SHRINK_SIZE));
|
tor_assert(list->len == 0);
|
||||||
|
mem = tor_malloc(ALLOC_LEN(sz));
|
||||||
}
|
}
|
||||||
buf->mem = GUARDED_MEM(mem);
|
buf->mem = GUARDED_MEM(mem);
|
||||||
SET_GUARDS(buf->mem, MIN_LAZY_SHRINK_SIZE);
|
SET_GUARDS(buf->mem, sz);
|
||||||
buf->len = MIN_LAZY_SHRINK_SIZE;
|
buf->len = sz;
|
||||||
buf->memsize = ALLOC_LEN(MIN_LAZY_SHRINK_SIZE);
|
buf->memsize = ALLOC_LEN(sz);
|
||||||
buf->cur = buf->mem;
|
buf->cur = buf->mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** DOCDOC 64k of 4k buffers. */
|
/** Remove elements from the freelists that haven't been needed since the
|
||||||
#define BUF_FREELIST_SLACK 16
|
* last call to this function. */
|
||||||
|
|
||||||
/** DOCDOC */
|
|
||||||
void
|
void
|
||||||
buf_shrink_freelist(void)
|
buf_shrink_freelists(void)
|
||||||
{
|
{
|
||||||
if (free_mem_list_lowwater > BUF_FREELIST_SLACK) {
|
int j;
|
||||||
int i;
|
for (j = 0; j < 2; ++j) {
|
||||||
log_info(LD_GENERAL, "We haven't used %d/%d allocated buffer memory "
|
free_mem_list_t *list = j ? &free_mem_list_16k : &free_mem_list_4k;
|
||||||
"chunks since the last call(); freeing all but %d of them",
|
if (list->lowwater > list->slack) {
|
||||||
free_mem_list_lowwater, free_mem_list_len,
|
int i;
|
||||||
BUF_FREELIST_SLACK);
|
log_info(LD_GENERAL, "We haven't used %d/%d allocated %d-byte buffer "
|
||||||
for (i = BUF_FREELIST_SLACK; i < free_mem_list_lowwater; ++i) {
|
"memory chunks since the last call; freeing all but %d of them",
|
||||||
char *mem = free_mem_list;
|
list->lowwater, list->len, list->chunksize, list->slack);
|
||||||
tor_assert(mem);
|
for (i = list->slack; i < list->lowwater; ++i) {
|
||||||
free_mem_list = *(char**)mem;
|
/* XXXX we should really free the last few entries, not the first. */
|
||||||
tor_free(mem);
|
char *mem = list->list;
|
||||||
--free_mem_list_len;
|
tor_assert(mem);
|
||||||
|
list->list = *(char**)mem;
|
||||||
|
tor_free(mem);
|
||||||
|
--list->len;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
list->lowwater = list->len;
|
||||||
}
|
}
|
||||||
free_mem_list_lowwater = free_mem_list_len;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Change a buffer's capacity. <b>new_capacity</b> must be \>=
|
/** Change a buffer's capacity. <b>new_capacity</b> must be \>=
|
||||||
@ -281,26 +323,12 @@ buf_resize(buf_t *buf, size_t new_capacity)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
if (new_capacity < MIN_LAZY_SHRINK_SIZE)
|
||||||
/* 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 */
|
|
||||||
if (0 && new_capacity == MIN_LAZY_SHRINK_SIZE &&
|
|
||||||
!buf->datalen &&
|
|
||||||
buf->len >= 1<<16) {
|
|
||||||
/* don't realloc; free and malloc */
|
|
||||||
char *oldmem, *newmem = GUARDED_MEM(tor_malloc(ALLOC_LEN(new_capacity)));
|
|
||||||
SET_GUARDS(newmem, 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;
|
new_capacity = MIN_LAZY_SHRINK_SIZE;
|
||||||
|
|
||||||
|
if (buf->len == 0 && IS_FREELIST_SIZE(new_capacity)) {
|
||||||
tor_assert(!buf->mem);
|
tor_assert(!buf->mem);
|
||||||
buf_get_initial_mem(buf);
|
buf_get_initial_mem(buf, new_capacity);
|
||||||
} else {
|
} else {
|
||||||
char *raw;
|
char *raw;
|
||||||
if (buf->mem)
|
if (buf->mem)
|
||||||
@ -385,9 +413,9 @@ buf_shrink(buf_t *buf)
|
|||||||
|
|
||||||
new_len = buf->len;
|
new_len = buf->len;
|
||||||
if (buf->datalen == 0 && buf->highwater == 0 &&
|
if (buf->datalen == 0 && buf->highwater == 0 &&
|
||||||
buf->len == MIN_LAZY_SHRINK_SIZE) {
|
IS_FREELIST_SIZE(buf->len)) {
|
||||||
add_buf_mem_to_freelist(buf);
|
if (add_buf_mem_to_freelist(buf))
|
||||||
return;
|
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;
|
||||||
@ -433,8 +461,8 @@ 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) {
|
if (IS_FREELIST_SIZE(size)) {
|
||||||
buf_get_initial_mem(buf);
|
buf_get_initial_mem(buf, size);
|
||||||
} else {
|
} 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);
|
||||||
@ -492,10 +520,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) {
|
if (IS_FREELIST_SIZE(buf->len)) {
|
||||||
buf->datalen = 0; /* Avoid assert in add_buf_mem_to_freelist. */
|
buf->datalen = 0; /* Avoid assert in add_buf_mem_to_freelist. */
|
||||||
add_buf_mem_to_freelist(buf);
|
add_buf_mem_to_freelist(buf);
|
||||||
} else if (buf->mem) {
|
}
|
||||||
|
if (buf->mem) {
|
||||||
|
/* The freelist didn't want the RAM. */
|
||||||
oldmem = RAW_MEM(buf->mem);
|
oldmem = RAW_MEM(buf->mem);
|
||||||
tor_free(oldmem);
|
tor_free(oldmem);
|
||||||
}
|
}
|
||||||
|
@ -1021,7 +1021,7 @@ run_scheduled_events(time_t now)
|
|||||||
buf_shrink(conn->inbuf);
|
buf_shrink(conn->inbuf);
|
||||||
}
|
}
|
||||||
clean_cell_pool();
|
clean_cell_pool();
|
||||||
buf_shrink_freelist();
|
buf_shrink_freelists();
|
||||||
time_to_shrink_memory = now + MEM_SHRINK_INTERVAL;
|
time_to_shrink_memory = now + MEM_SHRINK_INTERVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2020,7 +2020,7 @@ buf_t *buf_new_with_capacity(size_t size);
|
|||||||
void buf_free(buf_t *buf);
|
void buf_free(buf_t *buf);
|
||||||
void buf_clear(buf_t *buf);
|
void buf_clear(buf_t *buf);
|
||||||
void buf_shrink(buf_t *buf);
|
void buf_shrink(buf_t *buf);
|
||||||
void buf_shrink_freelist(void);
|
void buf_shrink_freelists(void);
|
||||||
|
|
||||||
size_t buf_datalen(const buf_t *buf);
|
size_t buf_datalen(const buf_t *buf);
|
||||||
size_t buf_capacity(const buf_t *buf);
|
size_t buf_capacity(const buf_t *buf);
|
||||||
|
Loading…
Reference in New Issue
Block a user