Add arena-level name.

An arena-level name can help identify manual arenas.
This commit is contained in:
Guangli Dai 2022-09-01 16:42:56 -07:00 committed by Qi Wang
parent a0734fd6ee
commit ba19d2cb78
8 changed files with 146 additions and 9 deletions

View File

@ -88,6 +88,8 @@ ehooks_t *arena_get_ehooks(arena_t *arena);
extent_hooks_t *arena_set_extent_hooks(tsd_t *tsd, arena_t *arena, extent_hooks_t *arena_set_extent_hooks(tsd_t *tsd, arena_t *arena,
extent_hooks_t *extent_hooks); extent_hooks_t *extent_hooks);
bool arena_dss_prec_set(arena_t *arena, dss_prec_t dss_prec); bool arena_dss_prec_set(arena_t *arena, dss_prec_t dss_prec);
void arena_name_get(arena_t *arena, char *name);
void arena_name_set(arena_t *arena, const char *name);
ssize_t arena_dirty_decay_ms_default_get(void); ssize_t arena_dirty_decay_ms_default_get(void);
bool arena_dirty_decay_ms_default_set(ssize_t decay_ms); bool arena_dirty_decay_ms_default_set(ssize_t decay_ms);
ssize_t arena_muzzy_decay_ms_default_get(void); ssize_t arena_muzzy_decay_ms_default_get(void);

View File

@ -91,6 +91,9 @@ struct arena_s {
/* Used to determine uptime. Read-only after initialization. */ /* Used to determine uptime. Read-only after initialization. */
nstime_t create_time; nstime_t create_time;
/* The name of the arena. */
char name[ARENA_NAME_LEN];
/* /*
* The arena is allocated alongside its bins; really this is a * The arena is allocated alongside its bins; really this is a
* dynamically sized array determined by the binshard settings. * dynamically sized array determined by the binshard settings.

View File

@ -8,6 +8,8 @@
#define MUZZY_DECAY_MS_DEFAULT (0) #define MUZZY_DECAY_MS_DEFAULT (0)
/* Number of event ticks between time checks. */ /* Number of event ticks between time checks. */
#define ARENA_DECAY_NTICKS_PER_UPDATE 1000 #define ARENA_DECAY_NTICKS_PER_UPDATE 1000
/* Maximum length of the arena name. */
#define ARENA_NAME_LEN 32
typedef struct arena_decay_s arena_decay_t; typedef struct arena_decay_s arena_decay_t;
typedef struct arena_s arena_t; typedef struct arena_s arena_t;

View File

@ -1547,6 +1547,22 @@ arena_dss_prec_set(arena_t *arena, dss_prec_t dss_prec) {
return false; return false;
} }
void
arena_name_get(arena_t *arena, char *name) {
char *end = (char *)memchr((void *)arena->name, '\0', ARENA_NAME_LEN);
assert(end != NULL);
size_t len = (uintptr_t)end - (uintptr_t)arena->name + 1;
assert(len > 0 && len <= ARENA_NAME_LEN);
strncpy(name, arena->name, len);
}
void
arena_name_set(arena_t *arena, const char *name) {
strncpy(arena->name, name, ARENA_NAME_LEN);
arena->name[ARENA_NAME_LEN - 1] = '\0';
}
ssize_t ssize_t
arena_dirty_decay_ms_default_get(void) { arena_dirty_decay_ms_default_get(void) {
return atomic_load_zd(&dirty_decay_ms_default, ATOMIC_RELAXED); return atomic_load_zd(&dirty_decay_ms_default, ATOMIC_RELAXED);
@ -1670,6 +1686,11 @@ arena_new(tsdn_t *tsdn, unsigned ind, const arena_config_t *config) {
arena_set(ind, arena); arena_set(ind, arena);
arena->ind = ind; arena->ind = ind;
/* Init the name. */
malloc_snprintf(arena->name, sizeof(arena->name), "%s_%u",
arena_is_auto(arena) ? "auto" : "manual", arena->ind);
arena->name[ARENA_NAME_LEN - 1] = '\0';
nstime_init_update(&arena->create_time); nstime_init_update(&arena->create_time);
/* /*

View File

@ -170,6 +170,7 @@ CTL_PROTO(arena_i_dirty_decay_ms)
CTL_PROTO(arena_i_muzzy_decay_ms) CTL_PROTO(arena_i_muzzy_decay_ms)
CTL_PROTO(arena_i_extent_hooks) CTL_PROTO(arena_i_extent_hooks)
CTL_PROTO(arena_i_retain_grow_limit) CTL_PROTO(arena_i_retain_grow_limit)
CTL_PROTO(arena_i_name)
INDEX_PROTO(arena_i) INDEX_PROTO(arena_i)
CTL_PROTO(arenas_bin_i_size) CTL_PROTO(arenas_bin_i_size)
CTL_PROTO(arenas_bin_i_nregs) CTL_PROTO(arenas_bin_i_nregs)
@ -504,11 +505,12 @@ static const ctl_named_node_t arena_i_node[] = {
* Undocumented for now, since we anticipate an arena API in flux after * Undocumented for now, since we anticipate an arena API in flux after
* we cut the last 5-series release. * we cut the last 5-series release.
*/ */
{NAME("oversize_threshold"), CTL(arena_i_oversize_threshold)}, {NAME("oversize_threshold"), CTL(arena_i_oversize_threshold)},
{NAME("dirty_decay_ms"), CTL(arena_i_dirty_decay_ms)}, {NAME("dirty_decay_ms"), CTL(arena_i_dirty_decay_ms)},
{NAME("muzzy_decay_ms"), CTL(arena_i_muzzy_decay_ms)}, {NAME("muzzy_decay_ms"), CTL(arena_i_muzzy_decay_ms)},
{NAME("extent_hooks"), CTL(arena_i_extent_hooks)}, {NAME("extent_hooks"), CTL(arena_i_extent_hooks)},
{NAME("retain_grow_limit"), CTL(arena_i_retain_grow_limit)} {NAME("retain_grow_limit"), CTL(arena_i_retain_grow_limit)},
{NAME("name"), CTL(arena_i_name)}
}; };
static const ctl_named_node_t super_arena_i_node[] = { static const ctl_named_node_t super_arena_i_node[] = {
{NAME(""), CHILD(named, arena_i)} {NAME(""), CHILD(named, arena_i)}
@ -2983,6 +2985,61 @@ label_return:
return ret; return ret;
} }
/*
* When writing, newp should point to a char array storing the name to be set.
* A name longer than ARENA_NAME_LEN will be arbitrarily cut. When reading,
* oldp should point to a char array whose length is no shorter than
* ARENA_NAME_LEN or the length of the name when it was set.
*/
static int
arena_i_name_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
int ret;
unsigned arena_ind;
char *name;
malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx);
MIB_UNSIGNED(arena_ind, 1);
if (arena_ind == MALLCTL_ARENAS_ALL || arena_ind >=
ctl_arenas->narenas) {
ret = EINVAL;
goto label_return;
}
arena_t *arena = arena_get(tsd_tsdn(tsd), arena_ind, false);
if (arena == NULL) {
ret = EFAULT;
goto label_return;
}
if (oldp != NULL && oldlenp != NULL) {
/*
* Read the arena name. When reading, the input oldp should
* point to an array with a length no shorter than
* ARENA_NAME_LEN or the length when it was set.
*/
if (*oldlenp != sizeof(char *)) {
ret = EINVAL;
goto label_return;
}
name = *(char **)oldp;
arena_name_get(arena, name);
}
if (newp != NULL) {
/* Write the arena name. */
WRITE(name, char *);
if (name == NULL) {
ret = EINVAL;
goto label_return;
}
arena_name_set(arena, name);
}
ret = 0;
label_return:
malloc_mutex_unlock(tsd_tsdn(tsd), &ctl_mtx);
return ret;
}
static const ctl_named_node_t * static const ctl_named_node_t *
arena_i_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, arena_i_index(tsdn_t *tsdn, const size_t *mib, size_t miblen,
size_t i) { size_t i) {

View File

@ -42,15 +42,18 @@ const char *arena_mutex_names[mutex_prof_num_arena_mutexes] = {
assert(miblen_new == miblen + 1); \ assert(miblen_new == miblen + 1); \
} while (0) } while (0)
#define CTL_M2_GET(n, i, v, t) do { \ #define CTL_MIB_GET(n, i, v, t, ind) do { \
size_t mib[CTL_MAX_DEPTH]; \ size_t mib[CTL_MAX_DEPTH]; \
size_t miblen = sizeof(mib) / sizeof(size_t); \ size_t miblen = sizeof(mib) / sizeof(size_t); \
size_t sz = sizeof(t); \ size_t sz = sizeof(t); \
xmallctlnametomib(n, mib, &miblen); \ xmallctlnametomib(n, mib, &miblen); \
mib[2] = (i); \ mib[(ind)] = (i); \
xmallctlbymib(mib, miblen, (void *)v, &sz, NULL, 0); \ xmallctlbymib(mib, miblen, (void *)v, &sz, NULL, 0); \
} while (0) } while (0)
#define CTL_M1_GET(n, i, v, t) CTL_MIB_GET(n, i, v, t, 1)
#define CTL_M2_GET(n, i, v, t) CTL_MIB_GET(n, i, v, t, 2)
/******************************************************************************/ /******************************************************************************/
/* Data. */ /* Data. */
@ -1042,6 +1045,8 @@ JEMALLOC_COLD
static void static void
stats_arena_print(emitter_t *emitter, unsigned i, bool bins, bool large, stats_arena_print(emitter_t *emitter, unsigned i, bool bins, bool large,
bool mutex, bool extents, bool hpa) { bool mutex, bool extents, bool hpa) {
char name[ARENA_NAME_LEN];
char *namep = name;
unsigned nthreads; unsigned nthreads;
const char *dss; const char *dss;
ssize_t dirty_decay_ms, muzzy_decay_ms; ssize_t dirty_decay_ms, muzzy_decay_ms;
@ -1059,6 +1064,10 @@ stats_arena_print(emitter_t *emitter, unsigned i, bool bins, bool large,
uint64_t uptime; uint64_t uptime;
CTL_GET("arenas.page", &page, size_t); CTL_GET("arenas.page", &page, size_t);
if (i != MALLCTL_ARENAS_ALL && i != MALLCTL_ARENAS_DESTROYED) {
CTL_M1_GET("arena.0.name", i, (void *)&namep, const char *);
emitter_kv(emitter, "name", "name", emitter_type_string, &namep);
}
CTL_M2_GET("stats.arenas.0.nthreads", i, &nthreads, unsigned); CTL_M2_GET("stats.arenas.0.nthreads", i, &nthreads, unsigned);
emitter_kv(emitter, "nthreads", "assigned threads", emitter_kv(emitter, "nthreads", "assigned threads",

View File

@ -266,7 +266,7 @@
#define expect_false(a, ...) expect_b_eq(a, false, __VA_ARGS__) #define expect_false(a, ...) expect_b_eq(a, false, __VA_ARGS__)
#define verify_str_eq(may_abort, a, b, ...) do { \ #define verify_str_eq(may_abort, a, b, ...) do { \
if (strcmp((a), (b))) { \ if (strcmp((a), (b)) != 0) { \
char prefix[ASSERT_BUFSIZE]; \ char prefix[ASSERT_BUFSIZE]; \
char message[ASSERT_BUFSIZE]; \ char message[ASSERT_BUFSIZE]; \
malloc_snprintf(prefix, sizeof(prefix), \ malloc_snprintf(prefix, sizeof(prefix), \
@ -284,7 +284,7 @@
} while (0) } while (0)
#define verify_str_ne(may_abort, a, b, ...) do { \ #define verify_str_ne(may_abort, a, b, ...) do { \
if (!strcmp((a), (b))) { \ if (strcmp((a), (b)) == 0) { \
char prefix[ASSERT_BUFSIZE]; \ char prefix[ASSERT_BUFSIZE]; \
char message[ASSERT_BUFSIZE]; \ char message[ASSERT_BUFSIZE]; \
malloc_snprintf(prefix, sizeof(prefix), \ malloc_snprintf(prefix, sizeof(prefix), \

View File

@ -711,6 +711,48 @@ TEST_BEGIN(test_arena_i_dss) {
} }
TEST_END TEST_END
TEST_BEGIN(test_arena_i_name) {
unsigned arena_ind;
size_t ind_sz = sizeof(arena_ind);
size_t mib[3];
size_t miblen;
char name_old[ARENA_NAME_LEN];
char *name_oldp = name_old;
size_t sz = sizeof(name_oldp);
char default_name[ARENA_NAME_LEN];
const char *name_new = "test name";
const char *super_long_name = "A name longer than ARENA_NAME_LEN";
size_t super_long_name_len = strlen(super_long_name);
assert(super_long_name_len > ARENA_NAME_LEN);
miblen = sizeof(mib)/sizeof(size_t);
expect_d_eq(mallctlnametomib("arena.0.name", mib, &miblen), 0,
"Unexpected mallctlnametomib() error");
expect_d_eq(mallctl("arenas.create", (void *)&arena_ind, &ind_sz, NULL,
0), 0, "Unexpected mallctl() failure");
mib[1] = arena_ind;
malloc_snprintf(default_name, sizeof(default_name), "manual_%u",
arena_ind);
expect_d_eq(mallctlbymib(mib, miblen, (void *)&name_oldp, &sz,
(void *)&name_new, sizeof(name_new)), 0,
"Unexpected mallctl() failure");
expect_str_eq(name_old, default_name,
"Unexpected default value for arena name");
expect_d_eq(mallctlbymib(mib, miblen, (void *)&name_oldp, &sz,
(void *)&super_long_name, sizeof(super_long_name)), 0,
"Unexpected mallctl() failure");
expect_str_eq(name_old, name_new, "Unexpected value for arena name");
expect_d_eq(mallctlbymib(mib, miblen, (void *)&name_oldp, &sz,
NULL, 0), 0, "Unexpected mallctl() failure");
int cmp = strncmp(name_old, super_long_name, ARENA_NAME_LEN - 1);
expect_true(cmp == 0, "Unexpected value for long arena name ");
}
TEST_END
TEST_BEGIN(test_arena_i_retain_grow_limit) { TEST_BEGIN(test_arena_i_retain_grow_limit) {
size_t old_limit, new_limit, default_limit; size_t old_limit, new_limit, default_limit;
size_t mib[3]; size_t mib[3];
@ -1258,6 +1300,7 @@ main(void) {
test_arena_i_purge, test_arena_i_purge,
test_arena_i_decay, test_arena_i_decay,
test_arena_i_dss, test_arena_i_dss,
test_arena_i_name,
test_arena_i_retain_grow_limit, test_arena_i_retain_grow_limit,
test_arenas_dirty_decay_ms, test_arenas_dirty_decay_ms,
test_arenas_muzzy_decay_ms, test_arenas_muzzy_decay_ms,