diff --git a/CMakeLists.txt b/CMakeLists.txt index cc092f4..f82ad70 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,6 +23,7 @@ target_compile_definitions(slotsboxmalloc PRIVATE # 依赖 blockmalloc 走 header-only(src/slotsboxmalloc.c 里 #define *_IMPLEMENTATION), # 故不链接它的 .so;头的搜索路径由系统 include 提供。 +enable_testing() add_subdirectory(tutorial) include("${CMAKE_CURRENT_LIST_DIR}/cmake/packagex.cmake") diff --git a/include/slotsboxmalloc/slotsboxobj.h b/include/slotsboxmalloc/slotsboxobj.h index 113711c..15e0467 100644 --- a/include/slotsboxmalloc/slotsboxobj.h +++ b/include/slotsboxmalloc/slotsboxobj.h @@ -268,9 +268,9 @@ static inline void sbo_update_parent(sbo_meta_t *meta, sbo_box_t *box, if (sbo_usage_cmp(nm, box->child_max_cap) != 0) box->child_max_cap = nm; else child_c = false; } - if ((slot_c || child_c) && box->parent > 0) { + if ((slot_c || child_c) && sbo_self_id(meta, box) != 0) { sbo_box_t *p = sbo_child(meta, box, box->parent); - if (p) sbo_update_parent(meta, p, slot_c, child_c); + if (p) sbo_update_parent(meta, p, false, true); } } @@ -292,7 +292,7 @@ static inline void sbo_box_format(sbo_meta_t *meta, sbo_box_t *box, box->slots[i].state = SBO_FREE; box->children[i] = -1; } - box->child_max_cap = (sbo_usage_t){objlevel + 1, 1}; + box->child_max_cap = (sbo_usage_t){0, 0}; } /* ================================================================ @@ -330,7 +330,7 @@ static inline int8_t sbo_alloc_obj_slots(sbo_meta_t *meta, sbo_box_t *box, uint8 uint8_t nc = sbo_continuous_max(box); if (box->max_obj_cap != nc) { box->max_obj_cap = nc; - if (box->parent > 0) { + if (sbo_self_id(meta, box) != 0) { sbo_box_t *pp = sbo_child(meta, box, box->parent); if (pp) sbo_update_parent(meta, pp, false, true); } @@ -358,7 +358,7 @@ static inline void sbo_free_obj_slots(sbo_meta_t *meta, sbo_box_t *box, uint8_t uint8_t nc = sbo_continuous_max(box); if (box->max_obj_cap != nc) { box->max_obj_cap = nc; - if (box->parent > 0) { + if (sbo_self_id(meta, box) != 0) { sbo_box_t *parent = sbo_child(meta, box, box->parent); if (parent) sbo_update_parent(meta, parent, false, true); } @@ -372,7 +372,7 @@ static inline void sbo_free_obj_slots(sbo_meta_t *meta, sbo_box_t *box, uint8_t #define SBO_ALLOC_FAIL ((uint64_t)-1) static inline uint64_t sbo_find_alloc(sbo_meta_t *meta, sbo_box_t *box, - sbo_box_t *parent, sbo_usage_t usage) { + sbo_usage_t usage) { if (!box || box->state != SBO_BOX) return SBO_ALLOC_FAIL; if (usage.level == box->objlevel) { @@ -388,7 +388,7 @@ static inline uint64_t sbo_find_alloc(sbo_meta_t *meta, sbo_box_t *box, sbo_box_t *ch = sbo_child(meta, box, box->children[i]); if (!ch) continue; if (sbo_usage_cmp(sbo_box_and_child_max_cap(ch), usage) < 0) continue; - uint64_t sub = sbo_find_alloc(meta, ch, box, usage); + uint64_t sub = sbo_find_alloc(meta, ch, usage); if (sub != SBO_ALLOC_FAIL) return sbo_offset_raw(box->objlevel, (uint8_t)i) + sub; } @@ -408,15 +408,11 @@ static inline uint64_t sbo_find_alloc(sbo_meta_t *meta, sbo_box_t *box, sbo_box_format(meta, ch, box->objlevel - 1, sbo_self_id(meta, box)); ch->slot_id = box->slot_id; - uint8_t nc = sbo_continuous_max(box); - if (box->max_obj_cap != nc) { - box->max_obj_cap = nc; - if (parent) sbo_update_parent(meta, parent, true, false); - } + sbo_update_parent(meta, box, true, true); sbo_usage_t ch_max = {ch->objlevel + 1, 1}; if (sbo_usage_cmp(ch_max, usage) >= 0) { - uint64_t sub = sbo_find_alloc(meta, ch, box, usage); + uint64_t sub = sbo_find_alloc(meta, ch, usage); if (sub != SBO_ALLOC_FAIL) return sbo_offset_raw(box->objlevel, (uint8_t)slot) + sub; } @@ -482,6 +478,7 @@ int sbo_init(void *metaptr, size_t head_size, size_t data_size) { meta->per_slot_meta = per_slot_meta; for (uint8_t si = 0; si < root_slots; si++) { + atomic_init(&sbo_pool_lock(meta, si)->lock, 0); void *pool_mem = sbo_pool_mem(meta, si); blocks_init(sbo_pool_meta(meta, si), per_slot_meta, sizeof(sbo_box_t)); @@ -518,7 +515,7 @@ uint64_t sbo_alloc(void *metaptr, size_t size) { sbo_box_t *root = (sbo_box_t *)((uint8_t *)sbo_pool_mem(meta, si) + meta->sizeof_block_head); if (sbo_usage_cmp(sbo_box_and_child_max_cap(root), usage) >= 0) { - uint64_t off = sbo_find_alloc(meta, root, NULL, usage); + uint64_t off = sbo_find_alloc(meta, root, usage); if (off != SBO_ALLOC_FAIL) { uint64_t total = (uint64_t)si * meta->slot_bytes + off; if (total + sbo_offset_of(usage) <= meta->data_size) { diff --git a/tutorial/03_stress.c b/tutorial/03_stress.c index d473099..0ad7251 100644 --- a/tutorial/03_stress.c +++ b/tutorial/03_stress.c @@ -8,16 +8,17 @@ #define SMALL_OBJ_SIZE 8 // 小对象大小 <=8byte int main() { + const size_t data_size = 8ULL * 64 * 64 * 64 * 64; // 初始化 slotsboxmalloc 的元数据和数据区,使用更大的内存池以支持高负载 uint8_t *buddy = malloc(4 * 1024 * 1024); // 元数据区,增大到4MB - uint8_t *data = malloc(64 * 1024 * 1024); // 数据区,增大到64MB + uint8_t *data = malloc(data_size); if (!buddy || !data) { perror("Failed to allocate memory for slotsboxmalloc"); return 1; } // 初始化 slotsboxmalloc - if (sbo_init(buddy, 4 * 1024 * 1024, 64 * 1024 * 1024) != 0) { + if (sbo_init(buddy, 4 * 1024 * 1024, data_size) != 0) { printf("Failed to initialize slotsboxmalloc\n"); free(buddy); free(data); @@ -61,6 +62,7 @@ int main() { printf("Phase 2: Starting random free/malloc loop (2s limit)...\n"); srand(time(NULL)); // 初始化随机种子 long long loop_count = 0; + int failed = 0; clock_t start = clock(); while (1) { @@ -77,7 +79,8 @@ int main() { uint64_t new_offset = sbo_alloc(buddy, SMALL_OBJ_SIZE); if (new_offset == (uint64_t)-1) { printf("Re-allocation failed at loop %lld\n", loop_count); - break; // 如果分配失败,退出循环 + failed = 1; + break; } // 更新指针数组 @@ -103,5 +106,5 @@ int main() { free(buddy); free(data); printf("Stress test completed after %lld loops.\n", loop_count); - return 0; -} \ No newline at end of file + return failed; +} diff --git a/tutorial/18_capacity.c b/tutorial/18_capacity.c new file mode 100644 index 0000000..d0b7ebf --- /dev/null +++ b/tutorial/18_capacity.c @@ -0,0 +1,62 @@ +#include +#include +#include +#include +#include + +static int exercise(void *meta, uint8_t *data, size_t data_size) { + uint64_t offsets[190]; + size_t sizes[190]; + int count = 0; + size_t size = data_size; + for (int depth = 0; depth < 3; depth++) { + size /= 64; + int n = depth == 2 ? 64 : 63; + for (int i = 0; i < n; i++) { + uint64_t off = sbo_alloc(meta, size); + if (off == UINT64_MAX || off + size > data_size || + sbo_allocated_size(meta, off) != size) + return 2; + for (int j = 0; j < count; j++) { + if (off < offsets[j] + sizes[j] && offsets[j] < off + size) + return 3; + } + offsets[count] = off; + sizes[count] = size; + data[off] = data[off + size - 1] = (uint8_t)count; + count++; + } + } + if (sbo_alloc(meta, size) != UINT64_MAX) + return 4; + + int hole = 143; + sbo_free(meta, offsets[hole]); + uint64_t replacement = sbo_alloc(meta, sizes[hole]); + if (replacement != offsets[hole]) + return 5; + for (int i = 0; i < count; i++) { + if (i != hole && (data[offsets[i]] != (uint8_t)i || + data[offsets[i] + sizes[i] - 1] != (uint8_t)i)) + return 6; + sbo_free(meta, offsets[i]); + } + return 0; +} + +int main(void) { + size_t data_size = 8ULL * 64 * 64 * 64 * 64; + size_t head_size = sbo_meta_size(data_size, 256 * 1024); + void *meta = malloc(head_size); + uint8_t *data = calloc(1, data_size); + int rc = 1; + if (meta) + memset(meta, 0xa5, head_size); + if (meta && data && sbo_init(meta, head_size, data_size) == 0) + rc = exercise(meta, data, data_size); + free(data); + free(meta); + if (rc == 0) + puts("capacity and reuse passed"); + return rc; +} diff --git a/tutorial/CMakeLists.txt b/tutorial/CMakeLists.txt index 9551d40..52ff288 100644 --- a/tutorial/CMakeLists.txt +++ b/tutorial/CMakeLists.txt @@ -71,3 +71,8 @@ target_link_libraries(16_bench_malloc slotsboxmalloc Threads::Threads) add_executable(17_data_integrity 17_data_integrity.c) target_link_libraries(17_data_integrity slotsboxmalloc) +add_test(NAME 17_data_integrity COMMAND 17_data_integrity) + +add_executable(18_capacity 18_capacity.c) +target_link_libraries(18_capacity slotsboxmalloc) +add_test(NAME 18_capacity COMMAND 18_capacity)