summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/mimalloc.h1
-rw-r--r--src/heap.c9
-rw-r--r--test/main-override-static.c205
3 files changed, 209 insertions, 6 deletions
diff --git a/include/mimalloc.h b/include/mimalloc.h
index 91ad352..c9d48c0 100644
--- a/include/mimalloc.h
+++ b/include/mimalloc.h
@@ -256,6 +256,7 @@ typedef struct mi_heap_area_s {
size_t committed; // current available bytes for this area
size_t used; // number of allocated blocks
size_t block_size; // size in bytes of each block
+ size_t full_block_size; // size in bytes of a full block including padding and metadata.
} mi_heap_area_t;
typedef bool (mi_cdecl mi_block_visit_fun)(const mi_heap_t* heap, const mi_heap_area_t* area, void* block, size_t block_size, void* arg);
diff --git a/src/heap.c b/src/heap.c
index 7cb4e5d..f465446 100644
--- a/src/heap.c
+++ b/src/heap.c
@@ -470,13 +470,14 @@ static bool mi_heap_area_visit_blocks(const mi_heap_area_ex_t* xarea, mi_block_v
if (page->used == 0) return true;
const size_t bsize = mi_page_block_size(page);
+ const size_t ubsize = mi_page_usable_block_size(page); // without padding
size_t psize;
uint8_t* pstart = _mi_page_start(_mi_page_segment(page), page, &psize);
if (page->capacity == 1) {
// optimize page with one block
mi_assert_internal(page->used == 1 && page->free == NULL);
- return visitor(mi_page_heap(page), area, pstart, bsize, arg);
+ return visitor(mi_page_heap(page), area, pstart, ubsize, arg);
}
// create a bitmap of free blocks.
@@ -510,7 +511,7 @@ static bool mi_heap_area_visit_blocks(const mi_heap_area_ex_t* xarea, mi_block_v
else if ((m & ((uintptr_t)1 << bit)) == 0) {
used_count++;
uint8_t* block = pstart + (i * bsize);
- if (!visitor(mi_page_heap(page), area, block, bsize, arg)) return false;
+ if (!visitor(mi_page_heap(page), area, block, ubsize, arg)) return false;
}
}
mi_assert_internal(page->used == used_count);
@@ -526,12 +527,14 @@ static bool mi_heap_visit_areas_page(mi_heap_t* heap, mi_page_queue_t* pq, mi_pa
mi_heap_area_visit_fun* fun = (mi_heap_area_visit_fun*)vfun;
mi_heap_area_ex_t xarea;
const size_t bsize = mi_page_block_size(page);
+ const size_t ubsize = mi_page_usable_block_size(page);
xarea.page = page;
xarea.area.reserved = page->reserved * bsize;
xarea.area.committed = page->capacity * bsize;
xarea.area.blocks = _mi_page_start(_mi_page_segment(page), page, NULL);
xarea.area.used = page->used * bsize;
- xarea.area.block_size = bsize;
+ xarea.area.block_size = ubsize;
+ xarea.area.full_block_size = bsize;
return fun(heap, &xarea, arg);
}
diff --git a/test/main-override-static.c b/test/main-override-static.c
index 071e424..e64b987 100644
--- a/test/main-override-static.c
+++ b/test/main-override-static.c
@@ -16,6 +16,9 @@ static void test_aslr(void);
static void test_process_info(void);
static void test_reserved(void);
static void negative_stat(void);
+static void alloc_huge(void);
+static void test_heap_walk(void);
+
int main() {
mi_version();
@@ -29,6 +32,8 @@ int main() {
// invalid_free();
// test_reserved();
// negative_stat();
+ test_heap_walk();
+ // alloc_huge();
void* p1 = malloc(78);
void* p2 = malloc(24);
@@ -48,8 +53,10 @@ int main() {
//free(p1);
//p2 = malloc(32);
//mi_free(p2);
- mi_collect(true);
- mi_stats_print(NULL);
+
+ //mi_collect(true);
+ //mi_stats_print(NULL);
+
// test_process_info();
return 0;
}
@@ -179,4 +186,196 @@ static void negative_stat(void) {
*p = 100;
mi_free(p);
mi_stats_print_out(NULL, NULL);
-} \ No newline at end of file
+}
+
+static void alloc_huge(void) {
+ void* p = mi_malloc(67108872);
+ mi_free(p);
+}
+
+static bool test_visit(const mi_heap_t* heap, const mi_heap_area_t* area, void* block, size_t block_size, void* arg) {
+ printf("I'm visiting a block of size %zu, allocated size %zu\n", block_size, mi_usable_size(block));
+ return true;
+}
+
+static void test_heap_walk(void) {
+ mi_heap_t* heap = mi_heap_new();
+ //mi_heap_malloc(heap, 2097152);
+ mi_heap_malloc(heap, 2067152);
+ mi_heap_malloc(heap, 2097160);
+ mi_heap_malloc(heap, 24576);
+ mi_heap_visit_blocks(heap, true, &test_visit, NULL);
+}
+
+// ----------------------------
+// bin size experiments
+// ------------------------------
+
+#if 0
+#include <stdint.h>
+#include <stdbool.h>
+
+#define MI_INTPTR_SIZE 8
+#define MI_LARGE_WSIZE_MAX (4*1024*1024 / MI_INTPTR_SIZE)
+
+#define MI_BIN_HUGE 100
+//#define MI_ALIGN2W
+
+// Bit scan reverse: return the index of the highest bit.
+static inline uint8_t mi_bsr32(uint32_t x);
+
+#if defined(_MSC_VER)
+#include <windows.h>
+#include <intrin.h>
+static inline uint8_t mi_bsr32(uint32_t x) {
+ uint32_t idx;
+ _BitScanReverse((DWORD*)&idx, x);
+ return idx;
+}
+#elif defined(__GNUC__) || defined(__clang__)
+static inline uint8_t mi_bsr32(uint32_t x) {
+ return (31 - __builtin_clz(x));
+}
+#else
+static inline uint8_t mi_bsr32(uint32_t x) {
+ // de Bruijn multiplication, see <http://supertech.csail.mit.edu/papers/debruijn.pdf>
+ static const uint8_t debruijn[32] = {
+ 31, 0, 22, 1, 28, 23, 18, 2, 29, 26, 24, 10, 19, 7, 3, 12,
+ 30, 21, 27, 17, 25, 9, 6, 11, 20, 16, 8, 5, 15, 4, 14, 13,
+ };
+ x |= x >> 1;
+ x |= x >> 2;
+ x |= x >> 4;
+ x |= x >> 8;
+ x |= x >> 16;
+ x++;
+ return debruijn[(x*0x076be629) >> 27];
+}
+#endif
+
+/*
+// Bit scan reverse: return the index of the highest bit.
+uint8_t _mi_bsr(uintptr_t x) {
+ if (x == 0) return 0;
+ #if MI_INTPTR_SIZE==8
+ uint32_t hi = (x >> 32);
+ return (hi == 0 ? mi_bsr32((uint32_t)x) : 32 + mi_bsr32(hi));
+ #elif MI_INTPTR_SIZE==4
+ return mi_bsr32(x);
+ #else
+ # error "define bsr for non-32 or 64-bit platforms"
+ #endif
+}
+*/
+
+
+static inline size_t _mi_wsize_from_size(size_t size) {
+ return (size + sizeof(uintptr_t) - 1) / sizeof(uintptr_t);
+}
+
+// Return the bin for a given field size.
+// Returns MI_BIN_HUGE if the size is too large.
+// We use `wsize` for the size in "machine word sizes",
+// i.e. byte size == `wsize*sizeof(void*)`.
+extern inline uint8_t _mi_bin8(size_t size) {
+ size_t wsize = _mi_wsize_from_size(size);
+ uint8_t bin;
+ if (wsize <= 1) {
+ bin = 1;
+ }
+#if defined(MI_ALIGN4W)
+ else if (wsize <= 4) {
+ bin = (uint8_t)((wsize+1)&~1); // round to double word sizes
+ }
+#elif defined(MI_ALIGN2W)
+ else if (wsize <= 8) {
+ bin = (uint8_t)((wsize+1)&~1); // round to double word sizes
+ }
+#else
+ else if (wsize <= 8) {
+ bin = (uint8_t)wsize;
+ }
+#endif
+ else if (wsize > MI_LARGE_WSIZE_MAX) {
+ bin = MI_BIN_HUGE;
+ }
+ else {
+#if defined(MI_ALIGN4W)
+ if (wsize <= 16) { wsize = (wsize+3)&~3; } // round to 4x word sizes
+#endif
+ wsize--;
+ // find the highest bit
+ uint8_t b = mi_bsr32((uint32_t)wsize);
+ // and use the top 3 bits to determine the bin (~12.5% worst internal fragmentation).
+ // - adjust with 3 because we use do not round the first 8 sizes
+ // which each get an exact bin
+ bin = ((b << 2) + (uint8_t)((wsize >> (b - 2)) & 0x03)) - 3;
+ }
+ return bin;
+}
+
+static inline uint8_t _mi_bin4(size_t size) {
+ size_t wsize = _mi_wsize_from_size(size);
+ uint8_t bin;
+ if (wsize <= 1) {
+ bin = 1;
+ }
+#if defined(MI_ALIGN4W)
+ else if (wsize <= 4) {
+ bin = (uint8_t)((wsize+1)&~1); // round to double word sizes
+ }
+#elif defined(MI_ALIGN2W)
+ else if (wsize <= 8) {
+ bin = (uint8_t)((wsize+1)&~1); // round to double word sizes
+ }
+#else
+ else if (wsize <= 8) {
+ bin = (uint8_t)wsize;
+ }
+#endif
+ else if (wsize > MI_LARGE_WSIZE_MAX) {
+ bin = MI_BIN_HUGE;
+ }
+ else {
+ uint8_t b = mi_bsr32((uint32_t)wsize);
+ bin = ((b << 1) + (uint8_t)((wsize >> (b - 1)) & 0x01)) + 3;
+ }
+ return bin;
+}
+
+static size_t _mi_binx4(size_t bsize) {
+ if (bsize==0) return 0;
+ uint8_t b = mi_bsr32((uint32_t)bsize);
+ if (b <= 1) return bsize;
+ size_t bin = ((b << 1) | (bsize >> (b - 1))&0x01);
+ return bin;
+}
+
+static size_t _mi_binx8(size_t bsize) {
+ if (bsize<=1) return bsize;
+ uint8_t b = mi_bsr32((uint32_t)bsize);
+ if (b <= 2) return bsize;
+ size_t bin = ((b << 2) | (bsize >> (b - 2))&0x03) - 5;
+ return bin;
+}
+
+static void mi_bins(void) {
+ //printf(" QNULL(1), /* 0 */ \\\n ");
+ size_t last_bin = 0;
+ size_t min_bsize = 0;
+ size_t last_bsize = 0;
+ for (size_t bsize = 1; bsize < 2*1024; bsize++) {
+ size_t size = bsize * 64 * 1024;
+ size_t bin = _mi_binx8(bsize);
+ if (bin != last_bin) {
+ printf("min bsize: %6zd, max bsize: %6zd, bin: %6zd\n", min_bsize, last_bsize, last_bin);
+ //printf("QNULL(%6zd), ", wsize);
+ //if (last_bin%8 == 0) printf("/* %i */ \\\n ", last_bin);
+ last_bin = bin;
+ min_bsize = bsize;
+ }
+ last_bsize = bsize;
+ }
+}
+#endif
+