[util] Split cmem's free cache-line over size bins

They're binned by powers of two (with in between sizes going to the
smaller bin should I make cache-line allocations NPOT (which I think
might be worthwhile). However, there seems to still be a bug somewhere
causing a nasty leak as now my hacked qfvis consumes 40G in less than a
minute.
This commit is contained in:
Bill Currie 2020-12-29 20:42:39 +09:00
parent 4039075f41
commit 73544f0790
2 changed files with 38 additions and 12 deletions

View file

@ -30,6 +30,7 @@
#include "QF/qtypes.h"
#define MEM_LINE_SIZE 64
#define MAX_CACHE_LINES 9
typedef struct memline_s {
/* chain of free line blocks for fast allocation
@ -97,7 +98,16 @@ typedef struct memsuper_s {
* allocated, and 64 bytes and up consume entire cache lines.
*/
memsline_t *last_freed[4];
memline_t *free_lines;
/* Free chache lines grouped by size.
*
* The index is the base-2 log of the MINIMUM number of cache lines
* available in each block. ie, blocks with 4, 5, 6 and 7 lines will all
* be in the third list (index 2). For 4k page sizes, only 6 lists are
* needed (32-63 lines) because a page can hold only 62 lines (1 for the
* control block and one to avoid a cache-line being on a page boundary).
* Having 9 (MAX_CACHE_LINES) lists allows page sizes up to 16kB.
*/
memline_t *free_lines[MAX_CACHE_LINES];
} memsuper_t;
memsuper_t *new_memsuper (void);

View file

@ -29,6 +29,15 @@
#include "QF/alloc.h"
#include "QF/cmem.h"
static size_t __attribute__((const))
ilog2 (size_t x)
{
size_t l = 0;
while (x >>= 1) {
l++;
}
return l;
}
memsuper_t *
new_memsuper (void)
@ -54,12 +63,13 @@ delete_memsuper (memsuper_t *super)
static void
link_free_line (memsuper_t *super, memline_t *line)
{
if (super->free_lines) {
super->free_lines->free_prev = &line->free_next;
size_t ind = ilog2 (line->size) - 6;
if (super->free_lines[ind]) {
super->free_lines[ind]->free_prev = &line->free_next;
}
line->free_next = super->free_lines;
line->free_prev = &super->free_lines;
super->free_lines = line;
line->free_next = super->free_lines[ind];
line->free_prev = &super->free_lines[ind];
super->free_lines[ind] = line;
}
static void
@ -105,13 +115,14 @@ init_block (memsuper_t *super, void *mem, size_t alloc_size)
if (block->pre_size) {
memline_t *line = (memline_t *) ((size_t) block - block->pre_size);
link_free_line (super, line);
line->block = block;
line->size = block->pre_size;
line->block_next = 0;
line->block_prev = &block->free_lines;
block->free_lines = line;
line->size = block->pre_size;
link_free_line (super, line);
}
return block;
}
@ -274,8 +285,13 @@ cmemalloc (memsuper_t *super, size_t size)
size = 4 << ind;
if (size >= MEM_LINE_SIZE) {
// whole cache lines are required for this object
memline_t *line = super->free_lines;
// convert from byte log2 to cache-line log2
ind -= 4;
memline_t *line = 0;
while (!line && ind < MAX_CACHE_LINES) {
line = super->free_lines[ind++];
}
while (line && line->size < size) {
line = line->free_next;
}
@ -293,8 +309,8 @@ cmemalloc (memsuper_t *super, size_t size)
// sets super->free_lines, the block is guarnateed to be big
// enough to hold the requested allocation as otherwise a full
// block allocation would have been used
init_block (super, mem, super->page_size);
line = super->free_lines;
memblock_t *block = init_block (super, mem, super->page_size);
line = block->free_lines;
}
return alloc_line (line, size);;
} else {