Allow setting default ncached_max for each bin through malloc_conf
This commit is contained in:
parent
867eedfc58
commit
8a22d10b83
@ -242,6 +242,7 @@ TESTS_UNIT := \
|
|||||||
$(srcroot)test/unit/mq.c \
|
$(srcroot)test/unit/mq.c \
|
||||||
$(srcroot)test/unit/mtx.c \
|
$(srcroot)test/unit/mtx.c \
|
||||||
$(srcroot)test/unit/nstime.c \
|
$(srcroot)test/unit/nstime.c \
|
||||||
|
$(srcroot)test/unit/ncached_max.c \
|
||||||
$(srcroot)test/unit/oversize_threshold.c \
|
$(srcroot)test/unit/oversize_threshold.c \
|
||||||
$(srcroot)test/unit/pa.c \
|
$(srcroot)test/unit/pa.c \
|
||||||
$(srcroot)test/unit/pack.c \
|
$(srcroot)test/unit/pack.c \
|
||||||
|
@ -35,6 +35,11 @@ extern unsigned global_do_not_change_tcache_nbins;
|
|||||||
*/
|
*/
|
||||||
extern size_t global_do_not_change_tcache_maxclass;
|
extern size_t global_do_not_change_tcache_maxclass;
|
||||||
|
|
||||||
|
/* Default bin info for each bin. */
|
||||||
|
extern cache_bin_info_t opt_tcache_ncached_max[TCACHE_NBINS_MAX];
|
||||||
|
/* Records whether a bin's info is specified by malloc_conf. */
|
||||||
|
extern bool opt_tcache_ncached_max_set[TCACHE_NBINS_MAX];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Explicit tcaches, managed via the tcache.{create,flush,destroy} mallctls and
|
* Explicit tcaches, managed via the tcache.{create,flush,destroy} mallctls and
|
||||||
* usable via the MALLOCX_TCACHE() flag. The automatic per thread tcaches are
|
* usable via the MALLOCX_TCACHE() flag. The automatic per thread tcaches are
|
||||||
@ -55,6 +60,9 @@ void tcache_bin_flush_large(tsd_t *tsd, tcache_t *tcache,
|
|||||||
cache_bin_t *cache_bin, szind_t binind, unsigned rem);
|
cache_bin_t *cache_bin, szind_t binind, unsigned rem);
|
||||||
void tcache_bin_flush_stashed(tsd_t *tsd, tcache_t *tcache,
|
void tcache_bin_flush_stashed(tsd_t *tsd, tcache_t *tcache,
|
||||||
cache_bin_t *cache_bin, szind_t binind, bool is_small);
|
cache_bin_t *cache_bin, szind_t binind, bool is_small);
|
||||||
|
bool tcache_bin_info_settings_parse(const char *bin_settings_segment_cur,
|
||||||
|
size_t len_left, cache_bin_info_t tcache_bin_info[TCACHE_NBINS_MAX],
|
||||||
|
bool bin_info_is_set[TCACHE_NBINS_MAX]);
|
||||||
bool tcache_bins_ncached_max_write(tsd_t *tsd, char *settings, size_t len);
|
bool tcache_bins_ncached_max_write(tsd_t *tsd, char *settings, size_t len);
|
||||||
bool tcache_bin_ncached_max_read(tsd_t *tsd, size_t bin_size,
|
bool tcache_bin_ncached_max_read(tsd_t *tsd, size_t bin_size,
|
||||||
cache_bin_sz_t *ncached_max);
|
cache_bin_sz_t *ncached_max);
|
||||||
|
@ -1322,6 +1322,18 @@ malloc_conf_init_helper(sc_data_t *sc_data, unsigned bin_shard_sizes[SC_NBINS],
|
|||||||
} while (vlen_left > 0);
|
} while (vlen_left > 0);
|
||||||
CONF_CONTINUE;
|
CONF_CONTINUE;
|
||||||
}
|
}
|
||||||
|
if (CONF_MATCH("tcache_ncached_max")) {
|
||||||
|
bool err = tcache_bin_info_settings_parse(
|
||||||
|
v, vlen, opt_tcache_ncached_max,
|
||||||
|
opt_tcache_ncached_max_set);
|
||||||
|
if (err) {
|
||||||
|
CONF_ERROR("Invalid settings for "
|
||||||
|
"tcache_ncached_max", k, klen, v,
|
||||||
|
vlen);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
CONF_CONTINUE;
|
||||||
|
}
|
||||||
CONF_HANDLE_INT64_T(opt_mutex_max_spin,
|
CONF_HANDLE_INT64_T(opt_mutex_max_spin,
|
||||||
"mutex_max_spin", -1, INT64_MAX, CONF_CHECK_MIN,
|
"mutex_max_spin", -1, INT64_MAX, CONF_CHECK_MIN,
|
||||||
CONF_DONT_CHECK_MAX, false);
|
CONF_DONT_CHECK_MAX, false);
|
||||||
|
47
src/tcache.c
47
src/tcache.c
@ -71,6 +71,15 @@ unsigned global_do_not_change_tcache_nbins;
|
|||||||
*/
|
*/
|
||||||
size_t global_do_not_change_tcache_maxclass;
|
size_t global_do_not_change_tcache_maxclass;
|
||||||
|
|
||||||
|
/* Default bin info for each bin. Will be initialized when thread starts. */
|
||||||
|
cache_bin_info_t opt_tcache_ncached_max[TCACHE_NBINS_MAX] = {{0}};
|
||||||
|
/*
|
||||||
|
* Marks whether a bin's info is set already. This is used in
|
||||||
|
* tcache_bin_info_compute to avoid overwriting ncached_max specified by
|
||||||
|
* malloc_conf.
|
||||||
|
*/
|
||||||
|
bool opt_tcache_ncached_max_set[TCACHE_NBINS_MAX] = {0};
|
||||||
|
|
||||||
tcaches_t *tcaches;
|
tcaches_t *tcaches;
|
||||||
|
|
||||||
/* Index of first element within tcaches that has never been used. */
|
/* Index of first element within tcaches that has never been used. */
|
||||||
@ -800,7 +809,9 @@ tcache_bin_info_compute(cache_bin_info_t tcache_bin_info[TCACHE_NBINS_MAX]) {
|
|||||||
* than tcache_nbins, no items will be cached.
|
* than tcache_nbins, no items will be cached.
|
||||||
*/
|
*/
|
||||||
for (szind_t i = 0; i < TCACHE_NBINS_MAX; i++) {
|
for (szind_t i = 0; i < TCACHE_NBINS_MAX; i++) {
|
||||||
unsigned ncached_max = tcache_ncached_max_compute(i);
|
unsigned ncached_max = opt_tcache_ncached_max_set[i] ?
|
||||||
|
opt_tcache_ncached_max[i].ncached_max:
|
||||||
|
tcache_ncached_max_compute(i);
|
||||||
assert(ncached_max <= CACHE_BIN_NCACHED_MAX);
|
assert(ncached_max <= CACHE_BIN_NCACHED_MAX);
|
||||||
cache_bin_info_init(&tcache_bin_info[i], ncached_max);
|
cache_bin_info_init(&tcache_bin_info[i], ncached_max);
|
||||||
}
|
}
|
||||||
@ -984,17 +995,9 @@ thread_tcache_max_set(tsd_t *tsd, size_t tcache_max) {
|
|||||||
assert(tcache_nbins_get(tcache_slow) == sz_size2index(tcache_max) + 1);
|
assert(tcache_nbins_get(tcache_slow) == sz_size2index(tcache_max) + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool tcache_bin_info_settings_parse(const char *bin_settings_segment_cur,
|
||||||
tcache_bins_ncached_max_write(tsd_t *tsd, char *settings, size_t len) {
|
size_t len_left, cache_bin_info_t tcache_bin_info[TCACHE_NBINS_MAX],
|
||||||
assert(tcache_available(tsd));
|
bool bin_info_is_set[TCACHE_NBINS_MAX]) {
|
||||||
tcache_t *tcache = tsd_tcachep_get(tsd);
|
|
||||||
assert(tcache != NULL);
|
|
||||||
cache_bin_info_t tcache_bin_info[TCACHE_NBINS_MAX];
|
|
||||||
tcache_bin_settings_backup(tcache, tcache_bin_info);
|
|
||||||
const char *bin_settings_segment_cur = settings;
|
|
||||||
size_t len_left = len;
|
|
||||||
assert(len_left != 0);
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
size_t size_start, size_end;
|
size_t size_start, size_end;
|
||||||
size_t ncached_max;
|
size_t ncached_max;
|
||||||
@ -1019,9 +1022,29 @@ tcache_bins_ncached_max_write(tsd_t *tsd, char *settings, size_t len) {
|
|||||||
for (szind_t i = bin_start; i <= bin_end; i++) {
|
for (szind_t i = bin_start; i <= bin_end; i++) {
|
||||||
cache_bin_info_init(&tcache_bin_info[i],
|
cache_bin_info_init(&tcache_bin_info[i],
|
||||||
(cache_bin_sz_t)ncached_max);
|
(cache_bin_sz_t)ncached_max);
|
||||||
|
if (bin_info_is_set != NULL) {
|
||||||
|
bin_info_is_set[i] = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} while (len_left > 0);
|
} while (len_left > 0);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
tcache_bins_ncached_max_write(tsd_t *tsd, char *settings, size_t len) {
|
||||||
|
assert(tcache_available(tsd));
|
||||||
|
assert(len != 0);
|
||||||
|
tcache_t *tcache = tsd_tcachep_get(tsd);
|
||||||
|
assert(tcache != NULL);
|
||||||
|
cache_bin_info_t tcache_bin_info[TCACHE_NBINS_MAX];
|
||||||
|
tcache_bin_settings_backup(tcache, tcache_bin_info);
|
||||||
|
|
||||||
|
if(tcache_bin_info_settings_parse(settings, len, tcache_bin_info,
|
||||||
|
NULL)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
arena_t *assigned_arena = tcache->tcache_slow->arena;
|
arena_t *assigned_arena = tcache->tcache_slow->arena;
|
||||||
tcache_cleanup(tsd);
|
tcache_cleanup(tsd);
|
||||||
tsd_tcache_data_init_with_bin_settings(tsd, assigned_arena,
|
tsd_tcache_data_init_with_bin_settings(tsd, assigned_arena,
|
||||||
|
264
test/unit/ncached_max.c
Normal file
264
test/unit/ncached_max.c
Normal file
@ -0,0 +1,264 @@
|
|||||||
|
#include "test/jemalloc_test.h"
|
||||||
|
#include "test/san.h"
|
||||||
|
|
||||||
|
const char *malloc_conf =
|
||||||
|
"tcache_ncached_max:256-1024:1001|2048-2048:0,tcache_max:4096";
|
||||||
|
extern void tcache_bin_info_compute(
|
||||||
|
cache_bin_info_t tcache_bin_info[TCACHE_NBINS_MAX]);
|
||||||
|
|
||||||
|
static void
|
||||||
|
check_bins_info(cache_bin_info_t tcache_bin_info[TCACHE_NBINS_MAX]) {
|
||||||
|
size_t mib_get[4], mib_get_len;
|
||||||
|
mib_get_len = sizeof(mib_get) / sizeof(size_t);
|
||||||
|
const char *get_name = "thread.tcache.ncached_max.read_sizeclass";
|
||||||
|
size_t ncached_max;
|
||||||
|
size_t sz = sizeof(size_t);
|
||||||
|
expect_d_eq(mallctlnametomib(get_name, mib_get, &mib_get_len), 0,
|
||||||
|
"Unexpected mallctlnametomib() failure");
|
||||||
|
|
||||||
|
for (szind_t i = 0; i < TCACHE_NBINS_MAX; i++) {
|
||||||
|
size_t bin_size = sz_index2size(i);
|
||||||
|
expect_d_eq(mallctlbymib(mib_get, mib_get_len,
|
||||||
|
(void *)&ncached_max, &sz,
|
||||||
|
(void *)&bin_size, sizeof(size_t)), 0,
|
||||||
|
"Unexpected mallctlbymib() failure");
|
||||||
|
expect_zu_eq(ncached_max, tcache_bin_info[i].ncached_max,
|
||||||
|
"Unexpected ncached_max for bin %d", i);
|
||||||
|
/* Check ncached_max returned under a non-bin size. */
|
||||||
|
bin_size--;
|
||||||
|
size_t temp_ncached_max = 0;
|
||||||
|
expect_d_eq(mallctlbymib(mib_get, mib_get_len,
|
||||||
|
(void *)&temp_ncached_max, &sz,
|
||||||
|
(void *)&bin_size, sizeof(size_t)), 0,
|
||||||
|
"Unexpected mallctlbymib() failure");
|
||||||
|
expect_zu_eq(temp_ncached_max, ncached_max,
|
||||||
|
"Unexpected ncached_max for inaccurate bin size.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *
|
||||||
|
ncached_max_check(void* args) {
|
||||||
|
cache_bin_info_t tcache_bin_info[TCACHE_NBINS_MAX];
|
||||||
|
cache_bin_info_t tcache_bin_info_backup[TCACHE_NBINS_MAX];
|
||||||
|
tsd_t *tsd = tsd_fetch();
|
||||||
|
tcache_t *tcache = tsd_tcachep_get(tsd);
|
||||||
|
assert(tcache != NULL);
|
||||||
|
tcache_slow_t *tcache_slow = tcache->tcache_slow;
|
||||||
|
|
||||||
|
|
||||||
|
tcache_bin_info_compute(tcache_bin_info);
|
||||||
|
memcpy(tcache_bin_info_backup, tcache_bin_info,
|
||||||
|
sizeof(tcache_bin_info));
|
||||||
|
/* Check ncached_max set by malloc_conf. */
|
||||||
|
for (szind_t i = 0; i < TCACHE_NBINS_MAX; i++) {
|
||||||
|
bool first_range = (i >= sz_size2index(256) &&
|
||||||
|
i <= sz_size2index(1024));
|
||||||
|
bool second_range = (i == sz_size2index(2048));
|
||||||
|
cache_bin_sz_t target_ncached_max = 0;
|
||||||
|
if (first_range || second_range) {
|
||||||
|
target_ncached_max = first_range ? 1001: 0;
|
||||||
|
expect_true(opt_tcache_ncached_max_set[i],
|
||||||
|
"Unexpected state for bin %u", i);
|
||||||
|
expect_zu_eq(target_ncached_max,
|
||||||
|
tcache_bin_info[i].ncached_max,
|
||||||
|
"Unexpected generated ncached_max for bin %u", i);
|
||||||
|
} else {
|
||||||
|
expect_false(opt_tcache_ncached_max_set[i],
|
||||||
|
"Unexpected state for bin %u", i);
|
||||||
|
}
|
||||||
|
expect_zu_eq(target_ncached_max,
|
||||||
|
opt_tcache_ncached_max[i].ncached_max,
|
||||||
|
"Unexpected pre-set ncached_max for bin %u", i);
|
||||||
|
}
|
||||||
|
unsigned nbins = tcache_nbins_get(tcache_slow);
|
||||||
|
for (szind_t i = nbins; i < TCACHE_NBINS_MAX; i++) {
|
||||||
|
cache_bin_info_init(&tcache_bin_info[i], 0);
|
||||||
|
}
|
||||||
|
/* Check the initial bin settings. */
|
||||||
|
check_bins_info(tcache_bin_info);
|
||||||
|
|
||||||
|
size_t mib_set[4], mib_set_len;
|
||||||
|
mib_set_len = sizeof(mib_set) / sizeof(size_t);
|
||||||
|
const char *set_name = "thread.tcache.ncached_max.write";
|
||||||
|
expect_d_eq(mallctlnametomib(set_name, mib_set, &mib_set_len), 0,
|
||||||
|
"Unexpected mallctlnametomib() failure");
|
||||||
|
|
||||||
|
/* Test the ncached_max set with tcache on. */
|
||||||
|
char inputs[100] = "8-128:1|160-160:11|170-320:22|224-8388609:0";
|
||||||
|
char *inputp = inputs;
|
||||||
|
expect_d_eq(mallctlbymib(mib_set, mib_set_len, NULL, NULL,
|
||||||
|
(void *)&inputp, sizeof(char *)), 0,
|
||||||
|
"Unexpected mallctlbymib() failure");
|
||||||
|
for (szind_t i = 0; i < TCACHE_NBINS_MAX; i++) {
|
||||||
|
if (i >= sz_size2index(8) &&i <= sz_size2index(128)) {
|
||||||
|
cache_bin_info_init(&tcache_bin_info[i], 1);
|
||||||
|
}
|
||||||
|
if (i == sz_size2index(160)) {
|
||||||
|
cache_bin_info_init(&tcache_bin_info[i], 11);
|
||||||
|
}
|
||||||
|
if (i >= sz_size2index(170) && i <= sz_size2index(320)) {
|
||||||
|
cache_bin_info_init(&tcache_bin_info[i], 22);
|
||||||
|
}
|
||||||
|
if (i >= sz_size2index(224)) {
|
||||||
|
cache_bin_info_init(&tcache_bin_info[i], 0);
|
||||||
|
}
|
||||||
|
if (i >= nbins) {
|
||||||
|
cache_bin_info_init(&tcache_bin_info[i], 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
check_bins_info(tcache_bin_info);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Close the tcache and set ncached_max of some bins. It will be
|
||||||
|
* set properly but thread.tcache.ncached_max.read still returns 0
|
||||||
|
* since the bin is not available yet. After enabling the tcache,
|
||||||
|
* the new setting will not be carried on. Instead, the default
|
||||||
|
* settings will be applied.
|
||||||
|
*/
|
||||||
|
bool e0 = false, e1;
|
||||||
|
size_t bool_sz = sizeof(bool);
|
||||||
|
expect_d_eq(mallctl("thread.tcache.enabled", (void *)&e1, &bool_sz,
|
||||||
|
(void *)&e0, bool_sz), 0, "Unexpected mallctl() error");
|
||||||
|
expect_true(e1, "Unexpected previous tcache state");
|
||||||
|
strcpy(inputs, "0-112:8");
|
||||||
|
/* Setting returns ENOENT when the tcache is disabled. */
|
||||||
|
expect_d_eq(mallctlbymib(mib_set, mib_set_len, NULL, NULL,
|
||||||
|
(void *)&inputp, sizeof(char *)), ENOENT,
|
||||||
|
"Unexpected mallctlbymib() failure");
|
||||||
|
/* All ncached_max should return 0 once tcache is disabled. */
|
||||||
|
for (szind_t i = 0; i < TCACHE_NBINS_MAX; i++) {
|
||||||
|
cache_bin_info_init(&tcache_bin_info[i], 0);
|
||||||
|
}
|
||||||
|
check_bins_info(tcache_bin_info);
|
||||||
|
|
||||||
|
e0 = true;
|
||||||
|
expect_d_eq(mallctl("thread.tcache.enabled", (void *)&e1, &bool_sz,
|
||||||
|
(void *)&e0, bool_sz), 0, "Unexpected mallctl() error");
|
||||||
|
expect_false(e1, "Unexpected previous tcache state");
|
||||||
|
memcpy(tcache_bin_info, tcache_bin_info_backup,
|
||||||
|
sizeof(tcache_bin_info_backup));
|
||||||
|
for (szind_t i = tcache_nbins_get(tcache_slow); i < TCACHE_NBINS_MAX;
|
||||||
|
i++) {
|
||||||
|
cache_bin_info_init(&tcache_bin_info[i], 0);
|
||||||
|
}
|
||||||
|
check_bins_info(tcache_bin_info);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set ncached_max of bins not enabled yet. Then, enable them by
|
||||||
|
* resetting tcache_max. The ncached_max changes should stay.
|
||||||
|
*/
|
||||||
|
size_t tcache_max = 1024;
|
||||||
|
assert_d_eq(mallctl("thread.tcache.max",
|
||||||
|
NULL, NULL, (void *)&tcache_max, sizeof(size_t)),.0,
|
||||||
|
"Unexpected.mallctl().failure");
|
||||||
|
for (szind_t i = sz_size2index(1024) + 1; i < TCACHE_NBINS_MAX; i++) {
|
||||||
|
cache_bin_info_init(&tcache_bin_info[i], 0);
|
||||||
|
}
|
||||||
|
strcpy(inputs, "2048-6144:123");
|
||||||
|
expect_d_eq(mallctlbymib(mib_set, mib_set_len, NULL, NULL,
|
||||||
|
(void *)&inputp, sizeof(char *)), 0,
|
||||||
|
"Unexpected mallctlbymib() failure");
|
||||||
|
check_bins_info(tcache_bin_info);
|
||||||
|
|
||||||
|
tcache_max = 6144;
|
||||||
|
assert_d_eq(mallctl("thread.tcache.max",
|
||||||
|
NULL, NULL, (void *)&tcache_max, sizeof(size_t)),.0,
|
||||||
|
"Unexpected.mallctl().failure");
|
||||||
|
memcpy(tcache_bin_info, tcache_bin_info_backup,
|
||||||
|
sizeof(tcache_bin_info_backup));
|
||||||
|
for (szind_t i = sz_size2index(2048); i < TCACHE_NBINS_MAX; i++) {
|
||||||
|
if (i <= sz_size2index(6144)) {
|
||||||
|
cache_bin_info_init(&tcache_bin_info[i], 123);
|
||||||
|
} else if (i > sz_size2index(6144)) {
|
||||||
|
cache_bin_info_init(&tcache_bin_info[i], 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
check_bins_info(tcache_bin_info);
|
||||||
|
|
||||||
|
/* Test an empty input, it should do nothing. */
|
||||||
|
strcpy(inputs, "");
|
||||||
|
expect_d_eq(mallctlbymib(mib_set, mib_set_len, NULL, NULL,
|
||||||
|
(void *)&inputp, sizeof(char *)), 0,
|
||||||
|
"Unexpected mallctlbymib() failure");
|
||||||
|
check_bins_info(tcache_bin_info);
|
||||||
|
|
||||||
|
/* Test a half-done string, it should return EINVAL and do nothing. */
|
||||||
|
strcpy(inputs, "4-1024:7|256-1024");
|
||||||
|
expect_d_eq(mallctlbymib(mib_set, mib_set_len, NULL, NULL,
|
||||||
|
(void *)&inputp, sizeof(char *)), EINVAL,
|
||||||
|
"Unexpected mallctlbymib() failure");
|
||||||
|
check_bins_info(tcache_bin_info);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test an invalid string with start size larger than end size. It
|
||||||
|
* should return success but do nothing.
|
||||||
|
*/
|
||||||
|
strcpy(inputs, "1024-256:7");
|
||||||
|
expect_d_eq(mallctlbymib(mib_set, mib_set_len, NULL, NULL,
|
||||||
|
(void *)&inputp, sizeof(char *)), 0,
|
||||||
|
"Unexpected mallctlbymib() failure");
|
||||||
|
check_bins_info(tcache_bin_info);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test a string exceeding the length limit, it should return EINVAL
|
||||||
|
* and do nothing.
|
||||||
|
*/
|
||||||
|
char *long_inputs = (char *)malloc(10000 * sizeof(char));
|
||||||
|
expect_true(long_inputs != NULL, "Unexpected allocation failure.");
|
||||||
|
for (int i = 0; i < 200; i++) {
|
||||||
|
memcpy(long_inputs + i * 9, "4-1024:3|", 9);
|
||||||
|
}
|
||||||
|
memcpy(long_inputs + 200 * 9, "4-1024:3", 8);
|
||||||
|
long_inputs[200 * 9 + 8] = '\0';
|
||||||
|
inputp = long_inputs;
|
||||||
|
expect_d_eq(mallctlbymib(mib_set, mib_set_len, NULL, NULL,
|
||||||
|
(void *)&inputp, sizeof(char *)), EINVAL,
|
||||||
|
"Unexpected mallctlbymib() failure");
|
||||||
|
check_bins_info(tcache_bin_info);
|
||||||
|
free(long_inputs);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test a string with invalid characters, it should return EINVAL
|
||||||
|
* and do nothing.
|
||||||
|
*/
|
||||||
|
strcpy(inputs, "k8-1024:77p");
|
||||||
|
inputp = inputs;
|
||||||
|
expect_d_eq(mallctlbymib(mib_set, mib_set_len, NULL, NULL,
|
||||||
|
(void *)&inputp, sizeof(char *)), EINVAL,
|
||||||
|
"Unexpected mallctlbymib() failure");
|
||||||
|
check_bins_info(tcache_bin_info);
|
||||||
|
|
||||||
|
/* Test large ncached_max, it should return success but capped. */
|
||||||
|
strcpy(inputs, "1024-1024:65540");
|
||||||
|
expect_d_eq(mallctlbymib(mib_set, mib_set_len, NULL, NULL,
|
||||||
|
(void *)&inputp, sizeof(char *)), 0,
|
||||||
|
"Unexpected mallctlbymib() failure");
|
||||||
|
cache_bin_info_init(&tcache_bin_info[sz_size2index(1024)],
|
||||||
|
CACHE_BIN_NCACHED_MAX);
|
||||||
|
check_bins_info(tcache_bin_info);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_BEGIN(test_ncached_max) {
|
||||||
|
test_skip_if(!config_stats);
|
||||||
|
test_skip_if(!opt_tcache);
|
||||||
|
test_skip_if(san_uaf_detection_enabled());
|
||||||
|
/* TODO: change nthreads to 8 to reduce CI loads. */
|
||||||
|
unsigned nthreads = 108;
|
||||||
|
VARIABLE_ARRAY(thd_t, threads, nthreads);
|
||||||
|
for (unsigned i = 0; i < nthreads; i++) {
|
||||||
|
thd_create(&threads[i], ncached_max_check, NULL);
|
||||||
|
}
|
||||||
|
for (unsigned i = 0; i < nthreads; i++) {
|
||||||
|
thd_join(threads[i], NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TEST_END
|
||||||
|
|
||||||
|
int
|
||||||
|
main(void) {
|
||||||
|
return test(
|
||||||
|
test_ncached_max);
|
||||||
|
}
|
||||||
|
|
@ -366,238 +366,10 @@ TEST_BEGIN(test_thread_tcache_max) {
|
|||||||
}
|
}
|
||||||
TEST_END
|
TEST_END
|
||||||
|
|
||||||
static void
|
|
||||||
check_bins_info(cache_bin_info_t tcache_bin_info[TCACHE_NBINS_MAX]) {
|
|
||||||
size_t mib_get[4], mib_get_len;
|
|
||||||
mib_get_len = sizeof(mib_get) / sizeof(size_t);
|
|
||||||
const char *get_name = "thread.tcache.ncached_max.read_sizeclass";
|
|
||||||
size_t ncached_max;
|
|
||||||
size_t sz = sizeof(size_t);
|
|
||||||
expect_d_eq(mallctlnametomib(get_name, mib_get, &mib_get_len), 0,
|
|
||||||
"Unexpected mallctlnametomib() failure");
|
|
||||||
|
|
||||||
for (szind_t i = 0; i < TCACHE_NBINS_MAX; i++) {
|
|
||||||
size_t bin_size = sz_index2size(i);
|
|
||||||
expect_d_eq(mallctlbymib(mib_get, mib_get_len,
|
|
||||||
(void *)&ncached_max, &sz,
|
|
||||||
(void *)&bin_size, sizeof(size_t)), 0,
|
|
||||||
"Unexpected mallctlbymib() failure");
|
|
||||||
expect_zu_eq(ncached_max, tcache_bin_info[i].ncached_max,
|
|
||||||
"Unexpected ncached_max for bin %d", i);
|
|
||||||
/* Check ncached_max returned under a non-bin size. */
|
|
||||||
bin_size--;
|
|
||||||
size_t temp_ncached_max = 0;
|
|
||||||
expect_d_eq(mallctlbymib(mib_get, mib_get_len,
|
|
||||||
(void *)&temp_ncached_max, &sz,
|
|
||||||
(void *)&bin_size, sizeof(size_t)), 0,
|
|
||||||
"Unexpected mallctlbymib() failure");
|
|
||||||
expect_zu_eq(temp_ncached_max, ncached_max,
|
|
||||||
"Unexpected ncached_max for inaccurate bin size.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *
|
|
||||||
ncached_max_check(void* args) {
|
|
||||||
cache_bin_info_t tcache_bin_info[TCACHE_NBINS_MAX];
|
|
||||||
cache_bin_info_t tcache_bin_info_backup[TCACHE_NBINS_MAX];
|
|
||||||
tsd_t *tsd = tsd_fetch();
|
|
||||||
tcache_t *tcache = tsd_tcachep_get(tsd);
|
|
||||||
assert(tcache != NULL);
|
|
||||||
tcache_slow_t *tcache_slow = tcache->tcache_slow;
|
|
||||||
|
|
||||||
/* Check the initial bin settings. */
|
|
||||||
tcache_bin_info_compute(tcache_bin_info);
|
|
||||||
memcpy(tcache_bin_info_backup, tcache_bin_info,
|
|
||||||
sizeof(tcache_bin_info));
|
|
||||||
unsigned nbins = tcache_nbins_get(tcache_slow);
|
|
||||||
for (szind_t i = nbins; i < TCACHE_NBINS_MAX; i++) {
|
|
||||||
cache_bin_info_init(&tcache_bin_info[i], 0);
|
|
||||||
}
|
|
||||||
check_bins_info(tcache_bin_info);
|
|
||||||
|
|
||||||
size_t mib_set[4], mib_set_len;
|
|
||||||
mib_set_len = sizeof(mib_set) / sizeof(size_t);
|
|
||||||
const char *set_name = "thread.tcache.ncached_max.write";
|
|
||||||
expect_d_eq(mallctlnametomib(set_name, mib_set, &mib_set_len), 0,
|
|
||||||
"Unexpected mallctlnametomib() failure");
|
|
||||||
|
|
||||||
/* Test the ncached_max set with tcache on. */
|
|
||||||
char inputs[100] = "8-128:1|160-160:11|170-320:22|224-8388609:0";
|
|
||||||
char *inputp = inputs;
|
|
||||||
expect_d_eq(mallctlbymib(mib_set, mib_set_len, NULL, NULL,
|
|
||||||
(void *)&inputp, sizeof(char *)), 0,
|
|
||||||
"Unexpected mallctlbymib() failure");
|
|
||||||
for (szind_t i = 0; i < TCACHE_NBINS_MAX; i++) {
|
|
||||||
if (i >= sz_size2index(8) &&i <= sz_size2index(128)) {
|
|
||||||
cache_bin_info_init(&tcache_bin_info[i], 1);
|
|
||||||
}
|
|
||||||
if (i == sz_size2index(160)) {
|
|
||||||
cache_bin_info_init(&tcache_bin_info[i], 11);
|
|
||||||
}
|
|
||||||
if (i >= sz_size2index(170) && i <= sz_size2index(320)) {
|
|
||||||
cache_bin_info_init(&tcache_bin_info[i], 22);
|
|
||||||
}
|
|
||||||
if (i >= sz_size2index(224)) {
|
|
||||||
cache_bin_info_init(&tcache_bin_info[i], 0);
|
|
||||||
}
|
|
||||||
if (i >= nbins) {
|
|
||||||
cache_bin_info_init(&tcache_bin_info[i], 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
check_bins_info(tcache_bin_info);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Close the tcache and set ncached_max of some bins. It will be
|
|
||||||
* set properly but thread.tcache.ncached_max.read still returns 0
|
|
||||||
* since the bin is not available yet. After enabling the tcache,
|
|
||||||
* the new setting will not be carried on. Instead, the default
|
|
||||||
* settings will be applied.
|
|
||||||
*/
|
|
||||||
bool e0 = false, e1;
|
|
||||||
size_t bool_sz = sizeof(bool);
|
|
||||||
expect_d_eq(mallctl("thread.tcache.enabled", (void *)&e1, &bool_sz,
|
|
||||||
(void *)&e0, bool_sz), 0, "Unexpected mallctl() error");
|
|
||||||
expect_true(e1, "Unexpected previous tcache state");
|
|
||||||
strcpy(inputs, "0-112:8");
|
|
||||||
/* Setting returns ENOENT when the tcache is disabled. */
|
|
||||||
expect_d_eq(mallctlbymib(mib_set, mib_set_len, NULL, NULL,
|
|
||||||
(void *)&inputp, sizeof(char *)), ENOENT,
|
|
||||||
"Unexpected mallctlbymib() failure");
|
|
||||||
/* All ncached_max should return 0 once tcache is disabled. */
|
|
||||||
for (szind_t i = 0; i < TCACHE_NBINS_MAX; i++) {
|
|
||||||
cache_bin_info_init(&tcache_bin_info[i], 0);
|
|
||||||
}
|
|
||||||
check_bins_info(tcache_bin_info);
|
|
||||||
|
|
||||||
e0 = true;
|
|
||||||
expect_d_eq(mallctl("thread.tcache.enabled", (void *)&e1, &bool_sz,
|
|
||||||
(void *)&e0, bool_sz), 0, "Unexpected mallctl() error");
|
|
||||||
expect_false(e1, "Unexpected previous tcache state");
|
|
||||||
memcpy(tcache_bin_info, tcache_bin_info_backup,
|
|
||||||
sizeof(tcache_bin_info_backup));
|
|
||||||
for (szind_t i = tcache_nbins_get(tcache_slow); i < TCACHE_NBINS_MAX;
|
|
||||||
i++) {
|
|
||||||
cache_bin_info_init(&tcache_bin_info[i], 0);
|
|
||||||
}
|
|
||||||
check_bins_info(tcache_bin_info);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Set ncached_max of bins not enabled yet. Then, enable them by
|
|
||||||
* resetting tcache_max. The ncached_max changes should stay.
|
|
||||||
*/
|
|
||||||
size_t tcache_max = 1024;
|
|
||||||
assert_d_eq(mallctl("thread.tcache.max",
|
|
||||||
NULL, NULL, (void *)&tcache_max, sizeof(size_t)),.0,
|
|
||||||
"Unexpected.mallctl().failure");
|
|
||||||
for (szind_t i = sz_size2index(1024) + 1; i < TCACHE_NBINS_MAX; i++) {
|
|
||||||
cache_bin_info_init(&tcache_bin_info[i], 0);
|
|
||||||
}
|
|
||||||
strcpy(inputs, "2048-6144:123");
|
|
||||||
expect_d_eq(mallctlbymib(mib_set, mib_set_len, NULL, NULL,
|
|
||||||
(void *)&inputp, sizeof(char *)), 0,
|
|
||||||
"Unexpected mallctlbymib() failure");
|
|
||||||
check_bins_info(tcache_bin_info);
|
|
||||||
|
|
||||||
tcache_max = 6144;
|
|
||||||
assert_d_eq(mallctl("thread.tcache.max",
|
|
||||||
NULL, NULL, (void *)&tcache_max, sizeof(size_t)),.0,
|
|
||||||
"Unexpected.mallctl().failure");
|
|
||||||
memcpy(tcache_bin_info, tcache_bin_info_backup,
|
|
||||||
sizeof(tcache_bin_info_backup));
|
|
||||||
for (szind_t i = sz_size2index(2048); i < TCACHE_NBINS_MAX; i++) {
|
|
||||||
if (i <= sz_size2index(6144)) {
|
|
||||||
cache_bin_info_init(&tcache_bin_info[i], 123);
|
|
||||||
} else if (i > sz_size2index(6144)) {
|
|
||||||
cache_bin_info_init(&tcache_bin_info[i], 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
check_bins_info(tcache_bin_info);
|
|
||||||
|
|
||||||
/* Test an empty input, it should do nothing. */
|
|
||||||
strcpy(inputs, "");
|
|
||||||
expect_d_eq(mallctlbymib(mib_set, mib_set_len, NULL, NULL,
|
|
||||||
(void *)&inputp, sizeof(char *)), 0,
|
|
||||||
"Unexpected mallctlbymib() failure");
|
|
||||||
check_bins_info(tcache_bin_info);
|
|
||||||
|
|
||||||
/* Test a half-done string, it should return EINVAL and do nothing. */
|
|
||||||
strcpy(inputs, "4-1024:7|256-1024");
|
|
||||||
expect_d_eq(mallctlbymib(mib_set, mib_set_len, NULL, NULL,
|
|
||||||
(void *)&inputp, sizeof(char *)), EINVAL,
|
|
||||||
"Unexpected mallctlbymib() failure");
|
|
||||||
check_bins_info(tcache_bin_info);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Test an invalid string with start size larger than end size. It
|
|
||||||
* should return success but do nothing.
|
|
||||||
*/
|
|
||||||
strcpy(inputs, "1024-256:7");
|
|
||||||
expect_d_eq(mallctlbymib(mib_set, mib_set_len, NULL, NULL,
|
|
||||||
(void *)&inputp, sizeof(char *)), 0,
|
|
||||||
"Unexpected mallctlbymib() failure");
|
|
||||||
check_bins_info(tcache_bin_info);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Test a string exceeding the length limit, it should return EINVAL
|
|
||||||
* and do nothing.
|
|
||||||
*/
|
|
||||||
char *long_inputs = (char *)malloc(10000 * sizeof(char));
|
|
||||||
expect_true(long_inputs != NULL, "Unexpected allocation failure.");
|
|
||||||
for (int i = 0; i < 200; i++) {
|
|
||||||
memcpy(long_inputs + i * 9, "4-1024:3|", 9);
|
|
||||||
}
|
|
||||||
memcpy(long_inputs + 200 * 9, "4-1024:3", 8);
|
|
||||||
long_inputs[200 * 9 + 8] = '\0';
|
|
||||||
inputp = long_inputs;
|
|
||||||
expect_d_eq(mallctlbymib(mib_set, mib_set_len, NULL, NULL,
|
|
||||||
(void *)&inputp, sizeof(char *)), EINVAL,
|
|
||||||
"Unexpected mallctlbymib() failure");
|
|
||||||
check_bins_info(tcache_bin_info);
|
|
||||||
free(long_inputs);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Test a string with invalid characters, it should return EINVAL
|
|
||||||
* and do nothing.
|
|
||||||
*/
|
|
||||||
strcpy(inputs, "k8-1024:77p");
|
|
||||||
inputp = inputs;
|
|
||||||
expect_d_eq(mallctlbymib(mib_set, mib_set_len, NULL, NULL,
|
|
||||||
(void *)&inputp, sizeof(char *)), EINVAL,
|
|
||||||
"Unexpected mallctlbymib() failure");
|
|
||||||
check_bins_info(tcache_bin_info);
|
|
||||||
|
|
||||||
/* Test large ncached_max, it should return success but capped. */
|
|
||||||
strcpy(inputs, "1024-1024:65540");
|
|
||||||
expect_d_eq(mallctlbymib(mib_set, mib_set_len, NULL, NULL,
|
|
||||||
(void *)&inputp, sizeof(char *)), 0,
|
|
||||||
"Unexpected mallctlbymib() failure");
|
|
||||||
cache_bin_info_init(&tcache_bin_info[sz_size2index(1024)],
|
|
||||||
CACHE_BIN_NCACHED_MAX);
|
|
||||||
check_bins_info(tcache_bin_info);
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_BEGIN(test_ncached_max) {
|
|
||||||
test_skip_if(!config_stats);
|
|
||||||
test_skip_if(!opt_tcache);
|
|
||||||
test_skip_if(san_uaf_detection_enabled());
|
|
||||||
unsigned nthreads = 8;
|
|
||||||
VARIABLE_ARRAY(thd_t, threads, nthreads);
|
|
||||||
for (unsigned i = 0; i < nthreads; i++) {
|
|
||||||
thd_create(&threads[i], ncached_max_check, NULL);
|
|
||||||
}
|
|
||||||
for (unsigned i = 0; i < nthreads; i++) {
|
|
||||||
thd_join(threads[i], NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TEST_END
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main(void) {
|
main(void) {
|
||||||
return test(
|
return test(
|
||||||
test_tcache_max,
|
test_tcache_max,
|
||||||
test_thread_tcache_max,
|
test_thread_tcache_max);
|
||||||
test_ncached_max);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user