2020-10-22 10:47:57 +08:00
|
|
|
#include "test/jemalloc_test.h"
|
|
|
|
|
|
|
|
enum {
|
|
|
|
alloc_option_start = 0,
|
|
|
|
use_malloc = 0,
|
|
|
|
use_mallocx,
|
|
|
|
alloc_option_end
|
|
|
|
};
|
|
|
|
|
|
|
|
enum {
|
|
|
|
dalloc_option_start = 0,
|
|
|
|
use_free = 0,
|
|
|
|
use_dallocx,
|
|
|
|
use_sdallocx,
|
|
|
|
dalloc_option_end
|
|
|
|
};
|
|
|
|
|
|
|
|
static unsigned alloc_option, dalloc_option;
|
|
|
|
static size_t tcache_max;
|
|
|
|
|
|
|
|
static void *
|
|
|
|
alloc_func(size_t sz) {
|
|
|
|
void *ret;
|
|
|
|
|
|
|
|
switch (alloc_option) {
|
|
|
|
case use_malloc:
|
|
|
|
ret = malloc(sz);
|
|
|
|
break;
|
|
|
|
case use_mallocx:
|
|
|
|
ret = mallocx(sz, 0);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
unreachable();
|
|
|
|
}
|
|
|
|
expect_ptr_not_null(ret, "Unexpected malloc / mallocx failure");
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
dalloc_func(void *ptr, size_t sz) {
|
|
|
|
switch (dalloc_option) {
|
|
|
|
case use_free:
|
|
|
|
free(ptr);
|
|
|
|
break;
|
|
|
|
case use_dallocx:
|
|
|
|
dallocx(ptr, 0);
|
|
|
|
break;
|
|
|
|
case use_sdallocx:
|
|
|
|
sdallocx(ptr, sz, 0);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
unreachable();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static size_t
|
|
|
|
tcache_bytes_read(void) {
|
|
|
|
uint64_t epoch;
|
|
|
|
assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, sizeof(epoch)),
|
|
|
|
0, "Unexpected mallctl() failure");
|
|
|
|
|
|
|
|
size_t tcache_bytes;
|
|
|
|
size_t sz = sizeof(tcache_bytes);
|
|
|
|
assert_d_eq(mallctl(
|
|
|
|
"stats.arenas." STRINGIFY(MALLCTL_ARENAS_ALL) ".tcache_bytes",
|
|
|
|
&tcache_bytes, &sz, NULL, 0), 0, "Unexpected mallctl failure");
|
|
|
|
|
|
|
|
return tcache_bytes;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
tcache_bytes_check_update(size_t *prev, ssize_t diff) {
|
|
|
|
size_t tcache_bytes = tcache_bytes_read();
|
|
|
|
expect_zu_eq(tcache_bytes, *prev + diff, "tcache bytes not expected");
|
|
|
|
|
|
|
|
*prev += diff;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
test_tcache_bytes_alloc(size_t alloc_size) {
|
|
|
|
expect_d_eq(mallctl("thread.tcache.flush", NULL, NULL, NULL, 0), 0,
|
|
|
|
"Unexpected tcache flush failure");
|
|
|
|
|
|
|
|
size_t usize = sz_s2u(alloc_size);
|
|
|
|
/* No change is expected if usize is outside of tcache_max range. */
|
|
|
|
bool cached = (usize <= tcache_max);
|
|
|
|
ssize_t diff = cached ? usize : 0;
|
|
|
|
|
|
|
|
void *ptr1 = alloc_func(alloc_size);
|
|
|
|
void *ptr2 = alloc_func(alloc_size);
|
|
|
|
|
|
|
|
size_t bytes = tcache_bytes_read();
|
|
|
|
dalloc_func(ptr2, alloc_size);
|
|
|
|
/* Expect tcache_bytes increase after dalloc */
|
|
|
|
tcache_bytes_check_update(&bytes, diff);
|
|
|
|
|
|
|
|
dalloc_func(ptr1, alloc_size);
|
|
|
|
/* Expect tcache_bytes increase again */
|
|
|
|
tcache_bytes_check_update(&bytes, diff);
|
|
|
|
|
|
|
|
void *ptr3 = alloc_func(alloc_size);
|
|
|
|
if (cached) {
|
|
|
|
expect_ptr_eq(ptr1, ptr3, "Unexpected cached ptr");
|
|
|
|
}
|
|
|
|
/* Expect tcache_bytes decrease after alloc */
|
|
|
|
tcache_bytes_check_update(&bytes, -diff);
|
|
|
|
|
|
|
|
void *ptr4 = alloc_func(alloc_size);
|
|
|
|
if (cached) {
|
|
|
|
expect_ptr_eq(ptr2, ptr4, "Unexpected cached ptr");
|
|
|
|
}
|
|
|
|
/* Expect tcache_bytes decrease again */
|
|
|
|
tcache_bytes_check_update(&bytes, -diff);
|
|
|
|
|
|
|
|
dalloc_func(ptr3, alloc_size);
|
|
|
|
tcache_bytes_check_update(&bytes, diff);
|
|
|
|
dalloc_func(ptr4, alloc_size);
|
|
|
|
tcache_bytes_check_update(&bytes, diff);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
test_tcache_max_impl(void) {
|
|
|
|
size_t sz;
|
|
|
|
sz = sizeof(tcache_max);
|
|
|
|
assert_d_eq(mallctl("arenas.tcache_max", (void *)&tcache_max,
|
|
|
|
&sz, NULL, 0), 0, "Unexpected mallctl() failure");
|
|
|
|
|
|
|
|
/* opt.tcache_max set to 1024 in tcache_max.sh */
|
|
|
|
expect_zu_eq(tcache_max, 1024, "tcache_max not expected");
|
|
|
|
|
|
|
|
test_tcache_bytes_alloc(1);
|
|
|
|
test_tcache_bytes_alloc(tcache_max - 1);
|
|
|
|
test_tcache_bytes_alloc(tcache_max);
|
|
|
|
test_tcache_bytes_alloc(tcache_max + 1);
|
|
|
|
|
|
|
|
test_tcache_bytes_alloc(PAGE - 1);
|
|
|
|
test_tcache_bytes_alloc(PAGE);
|
|
|
|
test_tcache_bytes_alloc(PAGE + 1);
|
|
|
|
|
|
|
|
size_t large;
|
|
|
|
sz = sizeof(large);
|
|
|
|
assert_d_eq(mallctl("arenas.lextent.0.size", (void *)&large, &sz, NULL,
|
|
|
|
0), 0, "Unexpected mallctl() failure");
|
|
|
|
|
|
|
|
test_tcache_bytes_alloc(large - 1);
|
|
|
|
test_tcache_bytes_alloc(large);
|
|
|
|
test_tcache_bytes_alloc(large + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_BEGIN(test_tcache_max) {
|
|
|
|
test_skip_if(!config_stats);
|
|
|
|
test_skip_if(!opt_tcache);
|
2021-11-16 07:23:47 +08:00
|
|
|
test_skip_if(opt_prof);
|
2021-10-19 08:33:15 +08:00
|
|
|
test_skip_if(san_uaf_detection_enabled());
|
2020-10-22 10:47:57 +08:00
|
|
|
|
|
|
|
for (alloc_option = alloc_option_start;
|
|
|
|
alloc_option < alloc_option_end;
|
|
|
|
alloc_option++) {
|
|
|
|
for (dalloc_option = dalloc_option_start;
|
|
|
|
dalloc_option < dalloc_option_end;
|
|
|
|
dalloc_option++) {
|
|
|
|
test_tcache_max_impl();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
TEST_END
|
|
|
|
|
|
|
|
int
|
|
|
|
main(void) {
|
|
|
|
return test(test_tcache_max);
|
|
|
|
}
|