mirror of
https://github.com/jemalloc/jemalloc.git
synced 2026-04-14 14:41:42 +03:00
112 lines
3.1 KiB
C
112 lines
3.1 KiB
C
#include "test/jemalloc_test.h"
|
|
|
|
/* Test config (set in reset_test_config) */
|
|
#define ALLOC_ITERATIONS_IN_THRESHOLD 10
|
|
uint64_t threshold_bytes = 0;
|
|
uint64_t chunk_size = 0;
|
|
|
|
/* Test globals for calblack */
|
|
uint64_t hook_calls = 0;
|
|
uint64_t last_peak = 0;
|
|
uint64_t last_alloc = 0;
|
|
uint64_t alloc_baseline = 0;
|
|
|
|
void
|
|
mock_prof_threshold_hook(uint64_t alloc, uint64_t dealloc, uint64_t peak) {
|
|
hook_calls++;
|
|
last_peak = peak;
|
|
last_alloc = alloc;
|
|
}
|
|
|
|
/* Need the do_write flag because NULL is a valid to_write value. */
|
|
static void
|
|
read_write_prof_threshold_hook(prof_threshold_hook_t *to_read, bool do_write,
|
|
prof_threshold_hook_t to_write) {
|
|
size_t hook_sz = sizeof(prof_threshold_hook_t);
|
|
expect_d_eq(
|
|
mallctl("experimental.hooks.prof_threshold", (void *)to_read,
|
|
&hook_sz, do_write ? &to_write : NULL, hook_sz),
|
|
0, "Unexpected prof_threshold_hook mallctl failure");
|
|
}
|
|
|
|
static void
|
|
write_prof_threshold_hook(prof_threshold_hook_t new_hook) {
|
|
read_write_prof_threshold_hook(NULL, true, new_hook);
|
|
}
|
|
|
|
static prof_threshold_hook_t
|
|
read_prof_threshold_hook() {
|
|
prof_threshold_hook_t hook;
|
|
read_write_prof_threshold_hook(&hook, false, NULL);
|
|
return hook;
|
|
}
|
|
|
|
static void
|
|
reset_test_config() {
|
|
hook_calls = 0;
|
|
last_peak = 0;
|
|
alloc_baseline = last_alloc; /* We run the test multiple times */
|
|
last_alloc = 0;
|
|
threshold_bytes = 1 << opt_experimental_lg_prof_threshold;
|
|
chunk_size = threshold_bytes / ALLOC_ITERATIONS_IN_THRESHOLD;
|
|
}
|
|
|
|
static void
|
|
expect_threshold_calls(int calls) {
|
|
expect_u64_eq(
|
|
hook_calls, calls, "Hook called the right amount of times");
|
|
expect_u64_lt(
|
|
last_peak, chunk_size * 2, "We allocate chunk_size at a time");
|
|
expect_u64_ge(
|
|
last_alloc, threshold_bytes * calls + alloc_baseline, "Crosses");
|
|
}
|
|
|
|
static void
|
|
allocate_chunks(int chunks) {
|
|
for (int i = 0; i < chunks; i++) {
|
|
void *p = mallocx((size_t)chunk_size, 0);
|
|
expect_ptr_not_null(p, "Failed to allocate");
|
|
free(p);
|
|
}
|
|
}
|
|
|
|
TEST_BEGIN(test_prof_threshold_hook) {
|
|
test_skip_if(!config_stats);
|
|
|
|
/* Test setting and reading the hook (both value and null) */
|
|
write_prof_threshold_hook(mock_prof_threshold_hook);
|
|
expect_ptr_eq(read_prof_threshold_hook(), mock_prof_threshold_hook,
|
|
"Unexpected hook");
|
|
|
|
write_prof_threshold_hook(NULL);
|
|
expect_ptr_null(read_prof_threshold_hook(), "Hook was erased");
|
|
|
|
/* Reset everything before the test */
|
|
reset_test_config();
|
|
write_prof_threshold_hook(mock_prof_threshold_hook);
|
|
|
|
int err = mallctl("thread.peak.reset", NULL, NULL, NULL, 0);
|
|
expect_d_eq(err, 0, "Peak reset failed");
|
|
|
|
/* Note that since we run this test multiple times and we don't reset
|
|
the allocation counter, each time we offset the callback by the
|
|
amount we allocate over the threshold. */
|
|
|
|
/* A simple small allocation is not enough to trigger the callback */
|
|
allocate_chunks(1);
|
|
expect_u64_eq(hook_calls, 0, "Hook not called yet");
|
|
|
|
/* Enough allocations to trigger the callback */
|
|
allocate_chunks(ALLOC_ITERATIONS_IN_THRESHOLD);
|
|
expect_threshold_calls(1);
|
|
|
|
/* Enough allocations to trigger the callback again */
|
|
allocate_chunks(ALLOC_ITERATIONS_IN_THRESHOLD);
|
|
expect_threshold_calls(2);
|
|
}
|
|
TEST_END
|
|
|
|
int
|
|
main(void) {
|
|
return test(test_prof_threshold_hook);
|
|
}
|