mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-02-22 11:41:38 +00:00
[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:
parent
4039075f41
commit
73544f0790
2 changed files with 38 additions and 12 deletions
|
@ -30,6 +30,7 @@
|
||||||
#include "QF/qtypes.h"
|
#include "QF/qtypes.h"
|
||||||
|
|
||||||
#define MEM_LINE_SIZE 64
|
#define MEM_LINE_SIZE 64
|
||||||
|
#define MAX_CACHE_LINES 9
|
||||||
|
|
||||||
typedef struct memline_s {
|
typedef struct memline_s {
|
||||||
/* chain of free line blocks for fast allocation
|
/* 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.
|
* allocated, and 64 bytes and up consume entire cache lines.
|
||||||
*/
|
*/
|
||||||
memsline_t *last_freed[4];
|
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;
|
||||||
|
|
||||||
memsuper_t *new_memsuper (void);
|
memsuper_t *new_memsuper (void);
|
||||||
|
|
|
@ -29,6 +29,15 @@
|
||||||
#include "QF/alloc.h"
|
#include "QF/alloc.h"
|
||||||
#include "QF/cmem.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 *
|
memsuper_t *
|
||||||
new_memsuper (void)
|
new_memsuper (void)
|
||||||
|
@ -54,12 +63,13 @@ delete_memsuper (memsuper_t *super)
|
||||||
static void
|
static void
|
||||||
link_free_line (memsuper_t *super, memline_t *line)
|
link_free_line (memsuper_t *super, memline_t *line)
|
||||||
{
|
{
|
||||||
if (super->free_lines) {
|
size_t ind = ilog2 (line->size) - 6;
|
||||||
super->free_lines->free_prev = &line->free_next;
|
if (super->free_lines[ind]) {
|
||||||
|
super->free_lines[ind]->free_prev = &line->free_next;
|
||||||
}
|
}
|
||||||
line->free_next = super->free_lines;
|
line->free_next = super->free_lines[ind];
|
||||||
line->free_prev = &super->free_lines;
|
line->free_prev = &super->free_lines[ind];
|
||||||
super->free_lines = line;
|
super->free_lines[ind] = line;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -105,13 +115,14 @@ init_block (memsuper_t *super, void *mem, size_t alloc_size)
|
||||||
if (block->pre_size) {
|
if (block->pre_size) {
|
||||||
memline_t *line = (memline_t *) ((size_t) block - block->pre_size);
|
memline_t *line = (memline_t *) ((size_t) block - block->pre_size);
|
||||||
|
|
||||||
link_free_line (super, line);
|
|
||||||
|
|
||||||
line->block = block;
|
line->block = block;
|
||||||
|
line->size = block->pre_size;
|
||||||
|
|
||||||
line->block_next = 0;
|
line->block_next = 0;
|
||||||
line->block_prev = &block->free_lines;
|
line->block_prev = &block->free_lines;
|
||||||
block->free_lines = line;
|
block->free_lines = line;
|
||||||
line->size = block->pre_size;
|
|
||||||
|
link_free_line (super, line);
|
||||||
}
|
}
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
@ -274,8 +285,13 @@ cmemalloc (memsuper_t *super, size_t size)
|
||||||
size = 4 << ind;
|
size = 4 << ind;
|
||||||
if (size >= MEM_LINE_SIZE) {
|
if (size >= MEM_LINE_SIZE) {
|
||||||
// whole cache lines are required for this object
|
// 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) {
|
while (line && line->size < size) {
|
||||||
line = line->free_next;
|
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
|
// sets super->free_lines, the block is guarnateed to be big
|
||||||
// enough to hold the requested allocation as otherwise a full
|
// enough to hold the requested allocation as otherwise a full
|
||||||
// block allocation would have been used
|
// block allocation would have been used
|
||||||
init_block (super, mem, super->page_size);
|
memblock_t *block = init_block (super, mem, super->page_size);
|
||||||
line = super->free_lines;
|
line = block->free_lines;
|
||||||
}
|
}
|
||||||
return alloc_line (line, size);;
|
return alloc_line (line, size);;
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in a new issue