mirror of
https://github.com/jemalloc/jemalloc.git
synced 2026-06-03 18:54:16 +03:00
Improve unit test coverage in tcache, pac, hpa_central
This commit is contained in:
parent
1619dda8a4
commit
716bda4394
7 changed files with 1305 additions and 0 deletions
236
test/unit/emap.c
Normal file
236
test/unit/emap.c
Normal file
|
|
@ -0,0 +1,236 @@
|
|||
#include "test/jemalloc_test.h"
|
||||
|
||||
#include "jemalloc/internal/emap.h"
|
||||
|
||||
#define EMAP_TEST_ARENA_IND 123
|
||||
#define EMAP_TEST_ADDR_BASE ((uintptr_t)0x40000000U)
|
||||
|
||||
typedef struct emap_test_data_s emap_test_data_t;
|
||||
struct emap_test_data_s {
|
||||
base_t *base;
|
||||
emap_t emap;
|
||||
malloc_mutex_t mtx;
|
||||
};
|
||||
|
||||
static edata_t *
|
||||
test_edata_alloc(uintptr_t addr, size_t size, bool slab, szind_t szind,
|
||||
uint64_t sn, extent_state_t state, extent_pai_t pai,
|
||||
extent_head_state_t is_head) {
|
||||
edata_t *edata = (edata_t *)mallocx(sizeof(edata_t),
|
||||
MALLOCX_ALIGN(EDATA_ALIGNMENT));
|
||||
assert_ptr_not_null(edata, "Unexpected edata allocation failure");
|
||||
memset(edata, 0, sizeof(*edata));
|
||||
edata_init(edata, EMAP_TEST_ARENA_IND, (void *)addr, size, slab,
|
||||
szind, sn, state, /* zeroed */ false, /* committed */ true, pai,
|
||||
is_head);
|
||||
return edata;
|
||||
}
|
||||
|
||||
static emap_test_data_t *
|
||||
emap_test_data_create(void) {
|
||||
emap_test_data_t *data = calloc(1, sizeof(*data));
|
||||
assert_ptr_not_null(data, "Unexpected calloc failure");
|
||||
data->base = base_new(TSDN_NULL, EMAP_TEST_ARENA_IND,
|
||||
&ehooks_default_extent_hooks, /* metadata_use_hooks */ true);
|
||||
assert_ptr_not_null(data->base, "Unexpected base_new failure");
|
||||
assert_false(emap_init(&data->emap, data->base, /* zeroed */ true),
|
||||
"Unexpected emap_init failure");
|
||||
assert_false(malloc_mutex_init(&data->mtx, "emap_test",
|
||||
WITNESS_RANK_EXTENTS, malloc_mutex_rank_exclusive),
|
||||
"Unexpected mutex initialization failure");
|
||||
return data;
|
||||
}
|
||||
|
||||
static void
|
||||
emap_test_data_destroy(emap_test_data_t *data) {
|
||||
base_delete(TSDN_NULL, data->base);
|
||||
free(data);
|
||||
}
|
||||
|
||||
static void
|
||||
expect_full_lookup(emap_t *emap, void *ptr, edata_t *edata, szind_t szind,
|
||||
bool slab) {
|
||||
emap_full_alloc_ctx_t ctx;
|
||||
emap_full_alloc_ctx_lookup(TSDN_NULL, emap, ptr, &ctx);
|
||||
expect_ptr_eq(edata, ctx.edata, "Unexpected emap edata");
|
||||
expect_u_eq(szind, ctx.szind, "Unexpected emap szind");
|
||||
expect_b_eq(slab, ctx.slab, "Unexpected emap slab bit");
|
||||
}
|
||||
|
||||
TEST_BEGIN(test_emap_register_and_lookup_slab) {
|
||||
emap_test_data_t *data = emap_test_data_create();
|
||||
|
||||
szind_t szind = 0;
|
||||
edata_t *slab = test_edata_alloc(EMAP_TEST_ADDR_BASE, 4 * PAGE,
|
||||
/* slab */ true, szind, 1, extent_state_active, EXTENT_PAI_PAC,
|
||||
EXTENT_NOT_HEAD);
|
||||
expect_false(emap_register_boundary(TSDN_NULL, &data->emap, slab,
|
||||
szind, /* slab */ true),
|
||||
"Unexpected boundary registration failure");
|
||||
emap_register_interior(TSDN_NULL, &data->emap, slab, szind);
|
||||
expect_full_lookup(&data->emap, (void *)EMAP_TEST_ADDR_BASE, slab,
|
||||
szind, true);
|
||||
expect_full_lookup(&data->emap, (void *)(EMAP_TEST_ADDR_BASE + PAGE),
|
||||
slab, szind, true);
|
||||
expect_full_lookup(&data->emap,
|
||||
(void *)(EMAP_TEST_ADDR_BASE + 3 * PAGE), slab, szind, true);
|
||||
|
||||
emap_deregister_interior(TSDN_NULL, &data->emap, slab);
|
||||
emap_deregister_boundary(TSDN_NULL, &data->emap, slab);
|
||||
expect_ptr_null(emap_edata_lookup(TSDN_NULL, &data->emap,
|
||||
(void *)EMAP_TEST_ADDR_BASE), "Boundary should be cleared");
|
||||
|
||||
dallocx(slab, 0);
|
||||
emap_test_data_destroy(data);
|
||||
}
|
||||
TEST_END
|
||||
|
||||
TEST_BEGIN(test_emap_remap_updates_szind) {
|
||||
emap_test_data_t *data = emap_test_data_create();
|
||||
|
||||
szind_t szind = 0;
|
||||
edata_t *remap = test_edata_alloc(EMAP_TEST_ADDR_BASE + HUGEPAGE,
|
||||
2 * PAGE, /* slab */ false, SC_NSIZES, 2, extent_state_active,
|
||||
EXTENT_PAI_PAC, EXTENT_NOT_HEAD);
|
||||
expect_false(emap_register_boundary(TSDN_NULL, &data->emap, remap,
|
||||
SC_NSIZES, /* slab */ false),
|
||||
"Unexpected boundary registration failure");
|
||||
emap_remap(TSDN_NULL, &data->emap, remap, szind, /* slab */ false);
|
||||
expect_full_lookup(&data->emap, edata_base_get(remap), remap, szind,
|
||||
false);
|
||||
expect_full_lookup(&data->emap, edata_last_get(remap), remap,
|
||||
SC_NSIZES, false);
|
||||
|
||||
dallocx(remap, 0);
|
||||
emap_test_data_destroy(data);
|
||||
}
|
||||
TEST_END
|
||||
|
||||
TEST_BEGIN(test_emap_split_then_merge) {
|
||||
emap_test_data_t *data = emap_test_data_create();
|
||||
|
||||
uintptr_t split_base = EMAP_TEST_ADDR_BASE + 2 * HUGEPAGE;
|
||||
edata_t *lead = test_edata_alloc(split_base, 4 * PAGE,
|
||||
/* slab */ false, SC_NSIZES, 3, extent_state_active,
|
||||
EXTENT_PAI_PAC, EXTENT_NOT_HEAD);
|
||||
edata_t *trail = test_edata_alloc(split_base + 2 * PAGE, 2 * PAGE,
|
||||
/* slab */ false, SC_NSIZES, 3, extent_state_active,
|
||||
EXTENT_PAI_PAC, EXTENT_NOT_HEAD);
|
||||
expect_false(emap_register_boundary(TSDN_NULL, &data->emap, lead,
|
||||
SC_NSIZES, /* slab */ false),
|
||||
"Unexpected boundary registration failure");
|
||||
|
||||
emap_prepare_t prepare;
|
||||
expect_false(emap_split_prepare(TSDN_NULL, &data->emap, &prepare, lead,
|
||||
2 * PAGE, trail, 2 * PAGE), "Unexpected split prepare failure");
|
||||
edata_size_set(lead, 2 * PAGE);
|
||||
emap_split_commit(TSDN_NULL, &data->emap, &prepare, lead, 2 * PAGE,
|
||||
trail, 2 * PAGE);
|
||||
expect_ptr_eq(lead, emap_edata_lookup(TSDN_NULL, &data->emap,
|
||||
(void *)split_base), "Split lead base should map to lead");
|
||||
expect_ptr_eq(lead, emap_edata_lookup(TSDN_NULL, &data->emap,
|
||||
(void *)(split_base + PAGE)), "Split lead end should map to lead");
|
||||
expect_ptr_eq(trail, emap_edata_lookup(TSDN_NULL, &data->emap,
|
||||
(void *)(split_base + 2 * PAGE)),
|
||||
"Split trail base should map to trail");
|
||||
expect_ptr_eq(trail, emap_edata_lookup(TSDN_NULL, &data->emap,
|
||||
(void *)(split_base + 3 * PAGE)),
|
||||
"Split trail end should map to trail");
|
||||
|
||||
emap_merge_prepare(TSDN_NULL, &data->emap, &prepare, lead, trail);
|
||||
edata_size_set(lead, 4 * PAGE);
|
||||
emap_merge_commit(TSDN_NULL, &data->emap, &prepare, lead, trail);
|
||||
expect_ptr_eq(lead, emap_edata_lookup(TSDN_NULL, &data->emap,
|
||||
(void *)split_base), "Merged base should map to lead");
|
||||
expect_ptr_null(emap_edata_lookup(TSDN_NULL, &data->emap,
|
||||
(void *)(split_base + PAGE)),
|
||||
"Old lead boundary should be cleared after merge");
|
||||
expect_ptr_null(emap_edata_lookup(TSDN_NULL, &data->emap,
|
||||
(void *)(split_base + 2 * PAGE)),
|
||||
"Old trail boundary should be cleared after merge");
|
||||
expect_ptr_eq(lead, emap_edata_lookup(TSDN_NULL, &data->emap,
|
||||
(void *)(split_base + 3 * PAGE)),
|
||||
"Merged last page should map to lead");
|
||||
|
||||
dallocx(lead, 0);
|
||||
dallocx(trail, 0);
|
||||
emap_test_data_destroy(data);
|
||||
}
|
||||
TEST_END
|
||||
|
||||
TEST_BEGIN(test_emap_neighbor_acquisition) {
|
||||
emap_test_data_t *data = emap_test_data_create();
|
||||
|
||||
edata_t *page_one = test_edata_alloc(PAGE, PAGE, /* slab */ false,
|
||||
SC_NSIZES, 1, extent_state_active, EXTENT_PAI_PAC,
|
||||
EXTENT_NOT_HEAD);
|
||||
malloc_mutex_lock(TSDN_NULL, &data->mtx);
|
||||
expect_ptr_null(emap_try_acquire_edata_neighbor(TSDN_NULL, &data->emap,
|
||||
page_one, EXTENT_PAI_PAC, extent_state_dirty,
|
||||
/* forward */ false),
|
||||
"Backward acquisition from the first page should return NULL");
|
||||
malloc_mutex_unlock(TSDN_NULL, &data->mtx);
|
||||
|
||||
uintptr_t base = EMAP_TEST_ADDR_BASE + 4 * HUGEPAGE;
|
||||
edata_t *active = test_edata_alloc(base, PAGE, /* slab */ false,
|
||||
SC_NSIZES, 2, extent_state_active, EXTENT_PAI_PAC,
|
||||
EXTENT_NOT_HEAD);
|
||||
edata_t *dirty = test_edata_alloc(base + PAGE, PAGE,
|
||||
/* slab */ false, SC_NSIZES, 3, extent_state_active,
|
||||
EXTENT_PAI_PAC, EXTENT_NOT_HEAD);
|
||||
expect_false(emap_register_boundary(TSDN_NULL, &data->emap, active,
|
||||
SC_NSIZES, /* slab */ false), "Unexpected registration failure");
|
||||
expect_false(emap_register_boundary(TSDN_NULL, &data->emap, dirty,
|
||||
SC_NSIZES, /* slab */ false), "Unexpected registration failure");
|
||||
|
||||
malloc_mutex_lock(TSDN_NULL, &data->mtx);
|
||||
emap_update_edata_state(TSDN_NULL, &data->emap, dirty,
|
||||
extent_state_dirty);
|
||||
expect_ptr_null(emap_try_acquire_edata_neighbor(TSDN_NULL, &data->emap,
|
||||
active, EXTENT_PAI_PAC, extent_state_muzzy, /* forward */ true),
|
||||
"State mismatch should reject neighbor acquisition");
|
||||
expect_d_eq(extent_state_dirty, edata_state_get(dirty),
|
||||
"Rejected neighbor should keep its state");
|
||||
|
||||
edata_t *neighbor = emap_try_acquire_edata_neighbor(TSDN_NULL,
|
||||
&data->emap, active, EXTENT_PAI_PAC, extent_state_dirty,
|
||||
/* forward */ true);
|
||||
expect_ptr_eq(dirty, neighbor, "Expected forward dirty neighbor");
|
||||
expect_d_eq(extent_state_merging, edata_state_get(dirty),
|
||||
"Acquired neighbor should enter merging state");
|
||||
emap_release_edata(TSDN_NULL, &data->emap, dirty, extent_state_dirty);
|
||||
expect_d_eq(extent_state_dirty, edata_state_get(dirty),
|
||||
"Released neighbor should return to requested state");
|
||||
malloc_mutex_unlock(TSDN_NULL, &data->mtx);
|
||||
|
||||
edata_t *hpa_neighbor = test_edata_alloc(base + 2 * PAGE, PAGE,
|
||||
/* slab */ false, SC_NSIZES, 4, extent_state_active,
|
||||
EXTENT_PAI_HPA, EXTENT_NOT_HEAD);
|
||||
expect_false(emap_register_boundary(TSDN_NULL, &data->emap,
|
||||
hpa_neighbor, SC_NSIZES, /* slab */ false),
|
||||
"Unexpected registration failure");
|
||||
malloc_mutex_lock(TSDN_NULL, &data->mtx);
|
||||
emap_update_edata_state(
|
||||
TSDN_NULL, &data->emap, hpa_neighbor, extent_state_dirty);
|
||||
expect_ptr_null(emap_try_acquire_edata_neighbor_expand(TSDN_NULL,
|
||||
&data->emap, dirty, EXTENT_PAI_PAC, extent_state_dirty),
|
||||
"PAI mismatch should reject expand acquisition");
|
||||
emap_update_edata_state(TSDN_NULL, &data->emap, hpa_neighbor,
|
||||
extent_state_active);
|
||||
malloc_mutex_unlock(TSDN_NULL, &data->mtx);
|
||||
|
||||
dallocx(page_one, 0);
|
||||
dallocx(active, 0);
|
||||
dallocx(dirty, 0);
|
||||
dallocx(hpa_neighbor, 0);
|
||||
emap_test_data_destroy(data);
|
||||
}
|
||||
TEST_END
|
||||
|
||||
int
|
||||
main(void) {
|
||||
return test_no_reentrancy(test_emap_register_and_lookup_slab,
|
||||
test_emap_remap_updates_szind,
|
||||
test_emap_split_then_merge,
|
||||
test_emap_neighbor_acquisition);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue