From 90e35c7a5e9dd18de95636630b545a96c4b117b6 Mon Sep 17 00:00:00 2001 From: Stanislav Paskalev Date: Sun, 1 Oct 2023 09:31:54 +0300 Subject: [PATCH] Calculate and report fragmentation as a range of 0-255. Avoid using floats. --- buddy_alloc.h | 59 ++++++++++++++++++++++++++++----------------------- tests.c | 19 ++++++++++++----- 2 files changed, 47 insertions(+), 31 deletions(-) diff --git a/buddy_alloc.h b/buddy_alloc.h index 3f8c12d..ee1b7ca 100644 --- a/buddy_alloc.h +++ b/buddy_alloc.h @@ -133,10 +133,10 @@ void *buddy_walk(struct buddy *buddy, void *(fp)(void *ctx, void *addr, size_t s */ /* - * Calculates the fragmentation in the allocator in a 0.0 - 1.0 range. + * Calculates the fragmentation in the allocator in a 0 - 255 range. * NOTE: if you are using a non-power-of-two sized arena the maximum upper bound can be lower. */ -float buddy_fragmentation(struct buddy *buddy); +unsigned char buddy_fragmentation(struct buddy *buddy); #ifdef __cplusplus #ifndef BUDDY_CPP_MANGLED @@ -319,10 +319,8 @@ static void buddy_tree_debug(struct buddy_tree *t, struct buddy_tree_pos pos, si /* Implementation defined */ unsigned int buddy_tree_check_invariant(struct buddy_tree *t, struct buddy_tree_pos pos); -#ifndef BUDDY_FRAG_OPTIONAL -/* Report fragmentation in a 0.0 - 1.0 range */ -static float buddy_tree_fragmentation(struct buddy_tree *t); -#endif +/* Report fragmentation in a 0 - 255 range */ +static unsigned char buddy_tree_fragmentation(struct buddy_tree *t); /* * A char-backed bitset implementation @@ -370,8 +368,8 @@ static inline size_t ceiling_power_of_two(size_t value); * Math */ -/* Approximates the square root of a float */ -static inline float approximate_square_root(float f); +/* Calculates the integer square root of an integer */ +static inline size_t integer_square_root(size_t f); /* Implementation @@ -919,14 +917,12 @@ void *buddy_walk(struct buddy *buddy, return NULL; } -#ifndef BUDDY_FRAG_OPTIONAL -float buddy_fragmentation(struct buddy *buddy) { +unsigned char buddy_fragmentation(struct buddy *buddy) { if (buddy == NULL) { return 0; } return buddy_tree_fragmentation(buddy_tree(buddy)); } -#endif static size_t depth_for_size(struct buddy *buddy, size_t requested_size) { size_t depth, effective_memory_size; @@ -1729,16 +1725,17 @@ unsigned int buddy_tree_check_invariant(struct buddy_tree *t, struct buddy_tree_ return fail; } -#ifndef BUDDY_FRAG_OPTIONAL /* * Calculate tree fragmentation based on free slots. * Based on https://asawicki.info/news_1757_a_metric_for_memory_fragmentation */ -static float buddy_tree_fragmentation(struct buddy_tree *t) { +static unsigned char buddy_tree_fragmentation(struct buddy_tree *t) { + const size_t fractional_bits = 8; + const size_t fractional_mask = 255; + uint8_t tree_order; - size_t root_status, quality, total_free_size, virtual_size; + size_t root_status, quality, total_free_size, virtual_size, quality_percent; struct buddy_tree_walk_state state; - float quality_percent, fragmentation; tree_order = buddy_tree_order(t); root_status = buddy_tree_status(t, buddy_tree_root()); @@ -1769,11 +1766,11 @@ static float buddy_tree_fragmentation(struct buddy_tree *t) { return 0; } - quality_percent = approximate_square_root((float) quality) / (float) total_free_size; - fragmentation = 1 - (quality_percent * quality_percent); - return fragmentation; + quality_percent = (integer_square_root(quality) << fractional_bits) / total_free_size; + quality_percent *= quality_percent; + quality_percent >>= fractional_bits; + return fractional_mask - (quality_percent & fractional_mask); } -#endif /* * A char-backed bitset implementation @@ -1952,13 +1949,23 @@ static inline size_t ceiling_power_of_two(size_t value) { return ((size_t)1u) << (highest_bit_position(value + value - 1)-1); } -static inline float approximate_square_root(float f) { - /* As listed in https://en.wikipedia.org/wiki/Methods_of_computing_square_roots */ - union { float f; uint32_t i; } val = {f}; - val.i -= 1 << 23; /* Subtract 2^m. */ - val.i >>= 1; /* Divide by 2. */ - val.i += 1 << 29; /* Add ((b + 1) / 2) * 2^m. */ - return val.f; /* Interpret again as float */ +static inline size_t integer_square_root(size_t op) { + /* by Martin Guy, 1985 - http://medialab.freaknet.org/martin/src/sqrt/ */ + size_t result = 0; + size_t cursor = (SIZE_MAX - (SIZE_MAX >> 1)) >> 1; /* second-to-top bit set */ + while (cursor > op) { + cursor >>= 2; + } + /* "cursor" starts at the highest power of four <= than the argument. */ + while (cursor != 0) { + if (op >= result + cursor) { + op -= result + cursor; + result += 2 * cursor; + } + result >>= 1; + cursor >>= 2; + } + return result; } #ifdef __cplusplus diff --git a/tests.c b/tests.c index c59d738..c725325 100644 --- a/tests.c +++ b/tests.c @@ -1703,6 +1703,7 @@ void test_buddy_unsafe_release_02(void) { void test_buddy_fragmentation(void) { size_t buddy_size = PSS(256); + void *ptrs[4]; unsigned char *buddy_buf = malloc(buddy_sizeof(buddy_size)); unsigned char *data_buf = malloc(buddy_size); struct buddy *b = buddy_init(buddy_buf, data_buf, buddy_size); @@ -1713,19 +1714,27 @@ void test_buddy_fragmentation(void) { // just through the allocator public interface // No fragmentation for invalid allocator - assert(buddy_fragmentation(NULL) == 0.0); + assert(buddy_fragmentation(NULL) == 0); // No fragmentation for empty allocator - assert(buddy_fragmentation(b) == 0.0); + assert(buddy_fragmentation(b) == 0); // No fragmentation for full allocator either buddy_malloc(b, buddy_size); - assert(buddy_fragmentation(b) == 0.0); + assert(buddy_fragmentation(b) == 0); buddy_free(b, data_buf); // Some fragmentation for partially-used allocator buddy_malloc(b, PSS(64)); - assert(buddy_fragmentation(b) == 0.4375); + assert(buddy_fragmentation(b) == 143); + + buddy_free(b, data_buf); + for (size_t i = 0; i < 4; i++){ + ptrs[i] = buddy_malloc(b, PSS(64)); + } + buddy_free(b, ptrs[0]); + buddy_free(b, ptrs[2]); + assert(buddy_fragmentation(b) == 191); free(buddy_buf); free(data_buf); @@ -2268,7 +2277,7 @@ void test_buddy_tree_fragmentation(void) { // Some fragmentation for partially-allocated tree buddy_tree_mark(t, buddy_tree_left_child(buddy_tree_left_child(buddy_tree_root()))); - assert(buddy_tree_fragmentation(t) == 0.4375); + assert(buddy_tree_fragmentation(t) == 143); } int main(void) {