Commit cf808b83 authored by Rusty Russell's avatar Rusty Russell

Finished uniform allocation code.

parent 53edefb8
...@@ -3,10 +3,13 @@ ...@@ -3,10 +3,13 @@
#include <string.h> #include <string.h>
#include <limits.h> #include <limits.h>
#include <assert.h> #include <assert.h>
#include <stdlib.h>
#include "alloc.h" #include "alloc.h"
#include "build_assert/build_assert.h" #include "build_assert/build_assert.h"
#include "config.h" #include "config.h"
/* FIXME: We assume getpagesize() doesnt change. Remapping file with
* different pagesize should still work. */
#if HAVE_ALIGNOF #if HAVE_ALIGNOF
#define ALIGNOF(t) __alignof__(t) #define ALIGNOF(t) __alignof__(t)
#else #else
...@@ -24,15 +27,24 @@ ...@@ -24,15 +27,24 @@
/* File layout: /* File layout:
* *
* file := pagestates pad metadata * file := pagestates pad uniform-cache metadata
* pagestates := pages * 2-bits-per-page * pagestates := pages * 2-bits-per-page
* pad := pad to next ALIGNOF(metadata) * pad := pad to next ALIGNOF(metaheader)
* *
* metadata := metalen next-ptr metabits * metadata := metalen next-ptr metabits
* metabits := freeblock | bitblock * metabits := freeblock | bitblock | uniformblock
* freeblock := 0+ * freeblock := FREE +
* bitblock := 2-bits-per-bit-in-page 1 * bitblock := BITMAP + 2-bits-per-bit-in-page + pad-to-byte
* uniformblock := UNIFORM + 14-bit-byte-len + bits + pad-to-byte
*/ */
#define UNIFORM_CACHE_NUM 16
struct uniform_cache
{
uint16_t size[UNIFORM_CACHE_NUM];
/* These could be u32 if we're prepared to limit size. */
unsigned long page[UNIFORM_CACHE_NUM];
};
struct metaheader struct metaheader
{ {
/* Next meta header, or 0 */ /* Next meta header, or 0 */
...@@ -46,6 +58,11 @@ static unsigned long align_up(unsigned long x, unsigned long a) ...@@ -46,6 +58,11 @@ static unsigned long align_up(unsigned long x, unsigned long a)
return (x + a - 1) & ~(a - 1); return (x + a - 1) & ~(a - 1);
} }
static unsigned long align_down(unsigned long x, unsigned long a)
{
return x & ~(a - 1);
}
static unsigned long div_up(unsigned long x, unsigned long a) static unsigned long div_up(unsigned long x, unsigned long a)
{ {
return (x + a - 1) / a; return (x + a - 1) / a;
...@@ -78,20 +95,26 @@ enum alloc_state ...@@ -78,20 +95,26 @@ enum alloc_state
enum sub_metadata_type enum sub_metadata_type
{ {
/* FREE is same as alloc state */ /* FREE is same as alloc state */
BITMAP = 1, BITMAP = 1, /* bitmap allocated page */
UNIFORM, /* uniform size allocated page */
}; };
/* Page states are represented by bitpairs, at the start of the pool. */ /* Page states are represented by bitpairs, at the start of the pool. */
#define BITS_PER_PAGE 2 #define BITS_PER_PAGE 2
static uint8_t *get_page_statebits(const void *pool)
{
return (uint8_t *)pool + sizeof(struct uniform_cache);
}
static enum alloc_state get_page_state(const void *pool, unsigned long page) static enum alloc_state get_page_state(const void *pool, unsigned long page)
{ {
return get_bit_pair(pool, page); return get_bit_pair(get_page_statebits(pool), page);
} }
static void set_page_state(void *pool, unsigned long page, enum alloc_state s) static void set_page_state(void *pool, unsigned long page, enum alloc_state s)
{ {
set_bit_pair(pool, page, s); set_bit_pair(get_page_statebits(pool), page, s);
} }
/* The offset of metadata for a subpage allocation is found at the end /* The offset of metadata for a subpage allocation is found at the end
...@@ -114,7 +137,7 @@ static struct metaheader *first_mheader(void *pool, unsigned long poolsize) ...@@ -114,7 +137,7 @@ static struct metaheader *first_mheader(void *pool, unsigned long poolsize)
pagestatelen = align_up(div_up(poolsize/getpagesize() * BITS_PER_PAGE, pagestatelen = align_up(div_up(poolsize/getpagesize() * BITS_PER_PAGE,
CHAR_BIT), CHAR_BIT),
ALIGNOF(struct metaheader)); ALIGNOF(struct metaheader));
return (struct metaheader *)((char *)pool + pagestatelen); return (struct metaheader *)(get_page_statebits(pool) + pagestatelen);
} }
static struct metaheader *next_mheader(void *pool, struct metaheader *mh) static struct metaheader *next_mheader(void *pool, struct metaheader *mh)
...@@ -141,8 +164,8 @@ void alloc_init(void *pool, unsigned long poolsize) ...@@ -141,8 +164,8 @@ void alloc_init(void *pool, unsigned long poolsize)
mh = first_mheader(pool, poolsize); mh = first_mheader(pool, poolsize);
/* Mark all page states FREE, and all of metaheader bitmap which takes /* Mark all page states FREE, all uniform caches zero, and all of
* rest of first page. */ * metaheader bitmap which takes rest of first page. */
len = align_up(pool_offset(pool, mh + 1), getpagesize()); len = align_up(pool_offset(pool, mh + 1), getpagesize());
BUILD_ASSERT(FREE == 0); BUILD_ASSERT(FREE == 0);
memset(pool, 0, len); memset(pool, 0, len);
...@@ -195,7 +218,8 @@ static unsigned long alloc_from_bitmap(uint8_t *bits, unsigned long off, ...@@ -195,7 +218,8 @@ static unsigned long alloc_from_bitmap(uint8_t *bits, unsigned long off,
static unsigned long alloc_get_pages(void *pool, unsigned long poolsize, static unsigned long alloc_get_pages(void *pool, unsigned long poolsize,
unsigned long pages, unsigned long align) unsigned long pages, unsigned long align)
{ {
return alloc_from_bitmap(pool, 0, poolsize / getpagesize(), pages, return alloc_from_bitmap(get_page_statebits(pool),
0, poolsize / getpagesize(), pages,
align / getpagesize()); align / getpagesize());
} }
...@@ -221,9 +245,15 @@ static unsigned long sub_page_alloc(void *pool, unsigned long page, ...@@ -221,9 +245,15 @@ static unsigned long sub_page_alloc(void *pool, unsigned long page,
{ {
uint8_t *bits = get_page_metadata(pool, page); uint8_t *bits = get_page_metadata(pool, page);
unsigned long i; unsigned long i;
enum sub_metadata_type type;
type = get_bit_pair(bits, 0);
/* If this is a uniform page, we can't allocate from it. */
if (type == UNIFORM)
return 0;
/* TAKEN at start means a bitwise alloc. */ assert(type == BITMAP);
assert(get_bit_pair(bits, 0) == BITMAP);
/* We use a standart bitmap, but offset because of that BITMAP /* We use a standart bitmap, but offset because of that BITMAP
* header. */ * header. */
...@@ -253,6 +283,33 @@ static unsigned long get_metalen(void *pool, unsigned long poolsize, ...@@ -253,6 +283,33 @@ static unsigned long get_metalen(void *pool, unsigned long poolsize,
return i * getpagesize() - pool_offset(pool, mh + 1); return i * getpagesize() - pool_offset(pool, mh + 1);
} }
static unsigned int uniform_metalen(unsigned int usize)
{
unsigned int metalen;
assert(usize < (1 << 14));
/* Two bits for the header, 14 bits for size, then one bit for each
* element the page can hold. Round up to number of bytes. */
metalen = div_up(2*CHAR_BIT + SUBPAGE_METAOFF / usize, CHAR_BIT);
/* To ensure metaheader is always aligned, round bytes up. */
metalen = align_up(metalen, ALIGNOF(struct metaheader));
return metalen;
}
static unsigned int decode_usize(uint8_t *meta)
{
return ((unsigned)meta[1] << (CHAR_BIT-2)) | (meta[0] >> 2);
}
static void encode_usize(uint8_t *meta, unsigned int usize)
{
meta[0] = (UNIFORM | (usize << 2));
meta[1] = (usize >> (CHAR_BIT - 2));
}
static uint8_t *alloc_metaspace(void *pool, unsigned long poolsize, static uint8_t *alloc_metaspace(void *pool, unsigned long poolsize,
struct metaheader *mh, unsigned long bytes, struct metaheader *mh, unsigned long bytes,
enum sub_metadata_type type) enum sub_metadata_type type)
...@@ -262,7 +319,7 @@ static uint8_t *alloc_metaspace(void *pool, unsigned long poolsize, ...@@ -262,7 +319,7 @@ static uint8_t *alloc_metaspace(void *pool, unsigned long poolsize,
metalen = get_metalen(pool, poolsize, mh); metalen = get_metalen(pool, poolsize, mh);
/* TAKEN tags end a subpage alloc. */ /* Walk through metadata looking for free. */
for (i = 0; i < metalen * CHAR_BIT / BITS_PER_PAGE; i += len) { for (i = 0; i < metalen * CHAR_BIT / BITS_PER_PAGE; i += len) {
switch (get_bit_pair(meta, i)) { switch (get_bit_pair(meta, i)) {
case FREE: case FREE:
...@@ -280,6 +337,12 @@ static uint8_t *alloc_metaspace(void *pool, unsigned long poolsize, ...@@ -280,6 +337,12 @@ static uint8_t *alloc_metaspace(void *pool, unsigned long poolsize,
len = BITMAP_METALEN * CHAR_BIT / BITS_PER_PAGE; len = BITMAP_METALEN * CHAR_BIT / BITS_PER_PAGE;
free = 0; free = 0;
break; break;
case UNIFORM:
/* Figure metalen given usize. */
len = decode_usize(meta + i * BITS_PER_PAGE / CHAR_BIT);
len = uniform_metalen(len) * CHAR_BIT / BITS_PER_PAGE;
free = 0;
break;
default: default:
assert(0); assert(0);
return NULL; return NULL;
...@@ -294,13 +357,11 @@ static uint8_t *new_metadata(void *pool, unsigned long poolsize, ...@@ -294,13 +357,11 @@ static uint8_t *new_metadata(void *pool, unsigned long poolsize,
{ {
struct metaheader *mh, *newmh; struct metaheader *mh, *newmh;
unsigned long page; unsigned long page;
uint8_t *meta;
for (mh = first_mheader(pool,poolsize); mh; mh = next_mheader(pool,mh)){ for (mh = first_mheader(pool,poolsize); mh; mh = next_mheader(pool,mh))
uint8_t *meta = alloc_metaspace(pool, poolsize, mh, bytes,type); if ((meta = alloc_metaspace(pool, poolsize, mh, bytes, type)))
if (meta)
return meta; return meta;
}
/* No room for metadata? Can we expand an existing one? */ /* No room for metadata? Can we expand an existing one? */
for (mh = first_mheader(pool,poolsize); mh; mh = next_mheader(pool,mh)){ for (mh = first_mheader(pool,poolsize); mh; mh = next_mheader(pool,mh)){
...@@ -309,7 +370,7 @@ static uint8_t *new_metadata(void *pool, unsigned long poolsize, ...@@ -309,7 +370,7 @@ static uint8_t *new_metadata(void *pool, unsigned long poolsize,
/* We start on this page. */ /* We start on this page. */
nextpage = pool_offset(pool, (char *)(mh+1))/getpagesize(); nextpage = pool_offset(pool, (char *)(mh+1))/getpagesize();
/* Iterate through any other pages we own. */ /* Iterate through any other pages we own. */
while (get_page_state(pool, ++nextpage) == TAKEN) while (get_page_state(pool, ++nextpage) == TAKEN);
/* Now, can we grab that page? */ /* Now, can we grab that page? */
if (get_page_state(pool, nextpage) != FREE) if (get_page_state(pool, nextpage) != FREE)
...@@ -347,11 +408,139 @@ static void alloc_free_pages(void *pool, unsigned long pagenum) ...@@ -347,11 +408,139 @@ static void alloc_free_pages(void *pool, unsigned long pagenum)
set_page_state(pool, pagenum, FREE); set_page_state(pool, pagenum, FREE);
} }
static void maybe_transform_uniform_page(void *pool, unsigned long offset)
{
/* FIXME: If possible and page isn't full, change to a bitmap */
}
/* Returns 0 or the size of the uniform alloc to use */
static unsigned long suitable_for_uc(unsigned long size, unsigned long align)
{
unsigned long num_elems, wastage, usize;
unsigned long bitmap_cost;
if (size == 0)
size = 1;
/* Fix up silly alignments. */
usize = align_up(size, align);
/* How many can fit in this page? */
num_elems = SUBPAGE_METAOFF / usize;
/* Can happen with bigger alignments. */
if (!num_elems)
return 0;
/* Usize maxes out at 14 bits. */
if (usize >= (1 << 14))
return 0;
/* How many bytes would be left at the end? */
wastage = SUBPAGE_METAOFF % usize;
/* If we can get a larger allocation within alignment constraints, we
* should do it, otherwise might as well leave wastage at the end. */
usize += align_down(wastage / num_elems, align);
/* Bitmap allocation costs 2 bits per BITMAP_GRANULARITY bytes, plus
* however much we waste in rounding up to BITMAP_GRANULARITY. */
bitmap_cost = 2 * div_up(size, BITMAP_GRANULARITY)
+ CHAR_BIT * (align_up(size, BITMAP_GRANULARITY) - size);
/* Our cost is 1 bit, plus usize overhead */
if (bitmap_cost < 1 + (usize - size) * CHAR_BIT)
return 0;
return usize;
}
static unsigned long uniform_alloc(void *pool, unsigned long poolsize,
struct uniform_cache *uc,
unsigned long ucnum)
{
uint8_t *metadata = get_page_metadata(pool, uc->page[ucnum]) + 2;
unsigned long i, max;
/* Simple one-bit-per-object bitmap. */
max = SUBPAGE_METAOFF / uc->size[ucnum];
for (i = 0; i < max; i++) {
if (!(metadata[i / CHAR_BIT] & (1 << (i % CHAR_BIT)))) {
metadata[i / CHAR_BIT] |= (1 << (i % CHAR_BIT));
return uc->page[ucnum] * getpagesize()
+ i * uc->size[ucnum];
}
}
return 0;
}
static unsigned long new_uniform_page(void *pool, unsigned long poolsize,
unsigned long usize)
{
unsigned long page, metalen;
uint8_t *metadata;
page = alloc_get_pages(pool, poolsize, 1, 1);
if (page == 0)
return 0;
metalen = uniform_metalen(usize);
/* Get metadata for page. */
metadata = new_metadata(pool, poolsize, metalen, UNIFORM);
if (!metadata) {
alloc_free_pages(pool, page);
return 0;
}
encode_usize(metadata, usize);
BUILD_ASSERT(FREE == 0);
memset(metadata + 2, 0, metalen - 2);
/* Actually, this is a subpage page now. */
set_page_state(pool, page, SPECIAL);
/* Set metadata pointer for page. */
set_page_metadata(pool, page, metadata);
return page;
}
static unsigned long alloc_sub_page(void *pool, unsigned long poolsize, static unsigned long alloc_sub_page(void *pool, unsigned long poolsize,
unsigned long size, unsigned long align) unsigned long size, unsigned long align)
{ {
unsigned long i; unsigned long i, usize;
uint8_t *metadata; uint8_t *metadata;
struct uniform_cache *uc = pool;
usize = suitable_for_uc(size, align);
if (usize) {
/* Look for a uniform page. */
for (i = 0; i < UNIFORM_CACHE_NUM; i++) {
if (uc->size[i] == usize) {
unsigned long ret;
ret = uniform_alloc(pool, poolsize, uc, i);
if (ret != 0)
return ret;
/* OK, that one is full, remove from cache. */
uc->size[i] = 0;
break;
}
}
/* OK, try a new uniform page. Use random discard for now. */
i = random() % UNIFORM_CACHE_NUM;
maybe_transform_uniform_page(pool, uc->page[i]);
uc->page[i] = new_uniform_page(pool, poolsize, usize);
if (uc->page[i]) {
uc->size[i] = usize;
return uniform_alloc(pool, poolsize, uc, i);
}
uc->size[i] = 0;
}
/* Look for partial page. */ /* Look for partial page. */
for (i = 0; i < poolsize / getpagesize(); i++) { for (i = 0; i < poolsize / getpagesize(); i++) {
...@@ -386,6 +575,75 @@ static unsigned long alloc_sub_page(void *pool, unsigned long poolsize, ...@@ -386,6 +575,75 @@ static unsigned long alloc_sub_page(void *pool, unsigned long poolsize,
return sub_page_alloc(pool, i, size, align); return sub_page_alloc(pool, i, size, align);
} }
static bool bitmap_page_is_empty(uint8_t *meta)
{
unsigned int i;
/* Skip the header (first bit of metadata). */
for (i = 1; i < SUBPAGE_METAOFF/BITMAP_GRANULARITY+1; i++)
if (get_bit_pair(meta, i) != FREE)
return false;
return true;
}
static bool uniform_page_is_empty(uint8_t *meta)
{
unsigned int i, metalen;
metalen = uniform_metalen(decode_usize(meta));
/* Skip the header (first two bytes of metadata). */
for (i = 2; i < metalen + 2; i++) {
BUILD_ASSERT(FREE == 0);
if (meta[i])
return false;
}
return true;
}
static bool special_page_is_empty(void *pool, unsigned long page)
{
uint8_t *meta;
enum sub_metadata_type type;
meta = get_page_metadata(pool, page);
type = get_bit_pair(meta, 0);
switch (type) {
case UNIFORM:
return uniform_page_is_empty(meta);
case BITMAP:
return bitmap_page_is_empty(meta);
default:
assert(0);
}
}
static void clear_special_metadata(void *pool, unsigned long page)
{
uint8_t *meta;
enum sub_metadata_type type;
meta = get_page_metadata(pool, page);
type = get_bit_pair(meta, 0);
switch (type) {
case UNIFORM:
/* First two bytes are the header, rest is already FREE */
BUILD_ASSERT(FREE == 0);
memset(meta, 0, 2);
break;
case BITMAP:
/* First two bits is the header. */
BUILD_ASSERT(BITMAP_METALEN > 1);
meta[0] = 0;
break;
default:
assert(0);
}
}
/* Returns true if we cleaned any pages. */ /* Returns true if we cleaned any pages. */
static bool clean_empty_subpages(void *pool, unsigned long poolsize) static bool clean_empty_subpages(void *pool, unsigned long poolsize)
{ {
...@@ -393,19 +651,11 @@ static bool clean_empty_subpages(void *pool, unsigned long poolsize) ...@@ -393,19 +651,11 @@ static bool clean_empty_subpages(void *pool, unsigned long poolsize)
bool progress = false; bool progress = false;
for (i = 0; i < poolsize/getpagesize(); i++) { for (i = 0; i < poolsize/getpagesize(); i++) {
uint8_t *meta;
unsigned int j;
if (get_page_state(pool, i) != SPECIAL) if (get_page_state(pool, i) != SPECIAL)
continue; continue;
meta = get_page_metadata(pool, i); if (special_page_is_empty(pool, i)) {
/* Skip the header (first bit of metadata). */ clear_special_metadata(pool, i);
for (j = 1; j < SUBPAGE_METAOFF/BITMAP_GRANULARITY+1; j++)
if (get_bit_pair(meta, j) != FREE)
break;
/* So, is this page totally empty? */
if (j == SUBPAGE_METAOFF/BITMAP_GRANULARITY+1) {
set_page_state(pool, i, FREE); set_page_state(pool, i, FREE);
progress = true; progress = true;
} }
...@@ -495,16 +745,11 @@ again: ...@@ -495,16 +745,11 @@ again:
return NULL; return NULL;
} }
static void subpage_free(void *pool, unsigned long pagenum, void *free) static void bitmap_free(void *pool, unsigned long pagenum, unsigned long off,
uint8_t *metadata)
{ {
unsigned long off = (unsigned long)free % getpagesize();
uint8_t *metadata;
assert(off < SUBPAGE_METAOFF);
assert(off % BITMAP_GRANULARITY == 0); assert(off % BITMAP_GRANULARITY == 0);
metadata = get_page_metadata(pool, pagenum);
off /= BITMAP_GRANULARITY; off /= BITMAP_GRANULARITY;
/* Offset by one because first bit is used for header. */ /* Offset by one because first bit is used for header. */
...@@ -516,6 +761,46 @@ static void subpage_free(void *pool, unsigned long pagenum, void *free) ...@@ -516,6 +761,46 @@ static void subpage_free(void *pool, unsigned long pagenum, void *free)
set_bit_pair(metadata, off++, FREE); set_bit_pair(metadata, off++, FREE);
} }
static void uniform_free(void *pool, unsigned long pagenum, unsigned long off,
uint8_t *metadata)
{
unsigned int usize, bit;
usize = decode_usize(metadata);
/* Must have been this size. */
assert(off % usize == 0);
bit = off / usize;
/* Skip header. */
metadata += 2;
/* Must have been allocated. */
assert(metadata[bit / CHAR_BIT] & (1 << (bit % CHAR_BIT)));
metadata[bit / CHAR_BIT] &= ~(1 << (bit % CHAR_BIT));
}
static void subpage_free(void *pool, unsigned long pagenum, void *free)
{
unsigned long off = (unsigned long)free % getpagesize();
uint8_t *metadata = get_page_metadata(pool, pagenum);
enum sub_metadata_type type;
type = get_bit_pair(metadata, 0);
assert(off < SUBPAGE_METAOFF);
switch (type) {
case BITMAP:
bitmap_free(pool, pagenum, off, metadata);
break;
case UNIFORM:
uniform_free(pool, pagenum, off, metadata);
break;
default:
assert(0);
}
}
void alloc_free(void *pool, unsigned long poolsize, void *free) void alloc_free(void *pool, unsigned long poolsize, void *free)
{ {
unsigned long pagenum; unsigned long pagenum;
...@@ -557,26 +842,10 @@ static bool is_metadata_page(void *pool, unsigned long poolsize, ...@@ -557,26 +842,10 @@ static bool is_metadata_page(void *pool, unsigned long poolsize,
return false; return false;
} }
static bool check_subpage(void *pool, unsigned long poolsize, static bool check_bitmap_metadata(void *pool, unsigned long *mhoff)
unsigned long page)
{ {
unsigned long *mhoff = metadata_off(pool, page);
unsigned int i;
enum alloc_state last_state = FREE; enum alloc_state last_state = FREE;
unsigned int i;
if (*mhoff + sizeof(struct metaheader) > poolsize)
return false;
if (*mhoff % ALIGNOF(struct metaheader) != 0)
return false;
/* It must point to a metadata page. */
if (!is_metadata_page(pool, poolsize, *mhoff / getpagesize()))
return false;
/* Header at start of subpage allocation */
if (get_bit_pair((uint8_t *)pool + *mhoff, 0) != BITMAP)
return false;
for (i = 0; i < SUBPAGE_METAOFF / BITMAP_GRANULARITY; i++) { for (i = 0; i < SUBPAGE_METAOFF / BITMAP_GRANULARITY; i++) {
enum alloc_state state; enum alloc_state state;
...@@ -598,6 +867,60 @@ static bool check_subpage(void *pool, unsigned long poolsize, ...@@ -598,6 +867,60 @@ static bool check_subpage(void *pool, unsigned long poolsize,
return true; return true;
} }
static bool check_uniform_metadata(void *pool, unsigned long *mhoff)
{
uint8_t *meta = (uint8_t *)pool + *mhoff;
unsigned int i, usize;
struct uniform_cache *uc = pool;
usize = decode_usize(meta);
if (usize == 0 || suitable_for_uc(usize, 1) != usize)
return false;
/* If it's in uniform cache, make sure that agrees on size. */
for (i = 0; i < UNIFORM_CACHE_NUM; i++) {
uint8_t *ucm;
if (!uc->size[i])
continue;
ucm = get_page_metadata(pool, uc->page[i]);
if (ucm != meta)
continue;
if (usize != uc->size[i])
return false;
}
return true;
}
static bool check_subpage(void *pool, unsigned long poolsize,
unsigned long page)
{
unsigned long *mhoff = metadata_off(pool, page);
if (*mhoff + sizeof(struct metaheader) > poolsize)
return false;
if (*mhoff % ALIGNOF(struct metaheader) != 0)
return false;
/* It must point to a metadata page. */
if (!is_metadata_page(pool, poolsize, *mhoff / getpagesize()))
return false;
/* Header at start of subpage allocation */
switch (get_bit_pair((uint8_t *)pool + *mhoff, 0)) {
case BITMAP:
return check_bitmap_metadata(pool, mhoff);
case UNIFORM:
return check_uniform_metadata(pool, mhoff);
default:
return false;
}
}
bool alloc_check(void *pool, unsigned long poolsize) bool alloc_check(void *pool, unsigned long poolsize)
{ {
unsigned long i; unsigned long i;
...@@ -667,6 +990,7 @@ bool alloc_check(void *pool, unsigned long poolsize) ...@@ -667,6 +990,7 @@ bool alloc_check(void *pool, unsigned long poolsize)
void alloc_visualize(FILE *out, void *pool, unsigned long poolsize) void alloc_visualize(FILE *out, void *pool, unsigned long poolsize)
{ {
struct metaheader *mh; struct metaheader *mh;
struct uniform_cache *uc = pool;
unsigned long pagebitlen, metadata_pages, count[1<<BITS_PER_PAGE], tot; unsigned long pagebitlen, metadata_pages, count[1<<BITS_PER_PAGE], tot;
long i; long i;
...@@ -675,12 +999,35 @@ void alloc_visualize(FILE *out, void *pool, unsigned long poolsize) ...@@ -675,12 +999,35 @@ void alloc_visualize(FILE *out, void *pool, unsigned long poolsize)
return; return;
} }
tot = 0;
for (i = 0; i < UNIFORM_CACHE_NUM; i++)
tot += (uc->size[i] != 0);
fprintf(out, "Uniform cache (%lu entries):\n", tot);
for (i = 0; i < UNIFORM_CACHE_NUM; i++) {
unsigned int j, total = 0;
uint8_t *meta;
if (!uc->size[i])
continue;
/* First two bytes are header. */
meta = get_page_metadata(pool, uc->page[i]) + 2;
for (j = 0; j < SUBPAGE_METAOFF / uc->size[i]; j++)
if (meta[j / 8] & (1 << (j % 8)))
total++;
printf(" %u: %u/%u (%u%% density)\n",
uc->size[j], total, SUBPAGE_METAOFF / uc->size[i],
(total * 100) / (SUBPAGE_METAOFF / uc->size[i]));
}
memset(count, 0, sizeof(count)); memset(count, 0, sizeof(count));
for (i = 0; i < poolsize / getpagesize(); i++) for (i = 0; i < poolsize / getpagesize(); i++)
count[get_page_state(pool, i)]++; count[get_page_state(pool, i)]++;
mh = first_mheader(pool, poolsize); mh = first_mheader(pool, poolsize);
pagebitlen = (char *)mh - (char *)pool; pagebitlen = (uint8_t *)mh - get_page_statebits(pool);
fprintf(out, "%lu bytes of page bits: FREE/TAKEN/TAKEN_START/SUBPAGE = %lu/%lu/%lu/%lu\n", fprintf(out, "%lu bytes of page bits: FREE/TAKEN/TAKEN_START/SUBPAGE = %lu/%lu/%lu/%lu\n",
pagebitlen, count[0], count[1], count[2], count[3]); pagebitlen, count[0], count[1], count[2], count[3]);
...@@ -689,14 +1036,15 @@ void alloc_visualize(FILE *out, void *pool, unsigned long poolsize) ...@@ -689,14 +1036,15 @@ void alloc_visualize(FILE *out, void *pool, unsigned long poolsize)
/* Now do each metadata page. */ /* Now do each metadata page. */
for (; mh; mh = next_mheader(pool,mh)) { for (; mh; mh = next_mheader(pool,mh)) {
unsigned long free = 0, subpageblocks = 0, len = 0, metalen; unsigned long free = 0, bitmapblocks = 0, uniformblocks = 0,
len = 0, uniformlen = 0, bitmaplen = 0, metalen;
uint8_t *meta = (uint8_t *)(mh + 1); uint8_t *meta = (uint8_t *)(mh + 1);
metalen = get_metalen(pool, poolsize, mh); metalen = get_metalen(pool, poolsize, mh);
metadata_pages += (sizeof(*mh) + metalen) / getpagesize(); metadata_pages += (sizeof(*mh) + metalen) / getpagesize();
for (i = 0; i < metalen * CHAR_BIT / BITS_PER_PAGE; i += len) { for (i = 0; i < metalen * CHAR_BIT / BITS_PER_PAGE; i += len) {
switch (get_page_state(meta, i)) { switch (get_bit_pair(meta, i)) {
case FREE: case FREE:
len = 1; len = 1;
free++; free++;
...@@ -704,19 +1052,27 @@ void alloc_visualize(FILE *out, void *pool, unsigned long poolsize) ...@@ -704,19 +1052,27 @@ void alloc_visualize(FILE *out, void *pool, unsigned long poolsize)
case BITMAP: case BITMAP:
/* Skip over this allocated part. */ /* Skip over this allocated part. */
len = BITMAP_METALEN * CHAR_BIT; len = BITMAP_METALEN * CHAR_BIT;
subpageblocks++; bitmapblocks++;
bitmaplen += len;
break;
case UNIFORM:
/* Skip over this part. */
len = decode_usize(meta + i * BITS_PER_PAGE / CHAR_BIT);
len = uniform_metalen(len) * CHAR_BIT / BITS_PER_PAGE;
uniformblocks++;
uniformlen += len;
break; break;
default: default:
assert(0); assert(0);
} }
} }
fprintf(out, "Metadata %lu-%lu: %lu free, %lu subpageblocks, %lu%% density\n", fprintf(out, "Metadata %lu-%lu: %lu free, %lu bitmapblocks, %lu uniformblocks, %lu%% density\n",
pool_offset(pool, mh), pool_offset(pool, mh),
pool_offset(pool, (char *)(mh+1) + metalen), pool_offset(pool, (char *)(mh+1) + metalen),
free, subpageblocks, free, bitmapblocks, uniformblocks,
subpageblocks * BITMAP_METALEN * 100 (bitmaplen + uniformlen) * 100
/ (free + subpageblocks * BITMAP_METALEN)); / (free + bitmaplen + uniformlen));
} }
/* Account for total pages allocated. */ /* Account for total pages allocated. */
...@@ -728,21 +1084,36 @@ void alloc_visualize(FILE *out, void *pool, unsigned long poolsize) ...@@ -728,21 +1084,36 @@ void alloc_visualize(FILE *out, void *pool, unsigned long poolsize)
/* Now do every subpage. */ /* Now do every subpage. */
for (i = 0; i < poolsize / getpagesize(); i++) { for (i = 0; i < poolsize / getpagesize(); i++) {
uint8_t *meta; uint8_t *meta;
unsigned int j; unsigned int j, allocated;
enum sub_metadata_type type;
if (get_page_state(pool, i) != SPECIAL) if (get_page_state(pool, i) != SPECIAL)
continue; continue;
memset(count, 0, sizeof(count)); memset(count, 0, sizeof(count));
meta = get_page_metadata(pool, i); meta = get_page_metadata(pool, i);
type = get_bit_pair(meta, 0);
if (type == BITMAP) {
for (j = 0; j < SUBPAGE_METAOFF/BITMAP_GRANULARITY; j++) for (j = 0; j < SUBPAGE_METAOFF/BITMAP_GRANULARITY; j++)
count[get_page_state(meta, j)]++; count[get_page_state(meta, j)]++;
allocated = (count[1] + count[2]) * BITMAP_GRANULARITY;
fprintf(out, "Subpage %lu: " fprintf(out, "Subpage bitmap ");
"FREE/TAKEN/TAKEN_START = %lu/%lu/%lu %lu%% density\n", } else {
unsigned int usize = decode_usize(meta);
assert(type == UNIFORM);
fprintf(out, "Subpage uniform (%u) ", usize);
meta += 2;
for (j = 0; j < SUBPAGE_METAOFF / usize; j++)
count[!!(meta[j / 8] & (1 << (j % 8)))]++;
allocated = count[1] * usize;
}
fprintf(out, "%lu: FREE/TAKEN/TAKEN_START = %lu/%lu/%lu %u%% density\n",
i, count[0], count[1], count[2], i, count[0], count[1], count[2],
((count[1] + count[2]) * BITMAP_GRANULARITY) * 100 allocated * 100 / getpagesize());
/ getpagesize()); tot += allocated;
tot += (count[1] + count[2]) * BITMAP_GRANULARITY;
} }
/* This is optimistic, since we overalloc in several cases. */ /* This is optimistic, since we overalloc in several cases. */
......
#include "alloc/alloc.h" #include "alloc/alloc.h"
#include "tap.h" #include "tap/tap.h"
#include "alloc/alloc.c" #include "alloc/alloc.c"
#include <stdlib.h> #include <stdlib.h>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment