mirror of
https://github.com/jemalloc/jemalloc.git
synced 2026-04-14 22:51:50 +03:00
243 lines
8.1 KiB
C
243 lines
8.1 KiB
C
#include "test/jemalloc_test.h"
|
|
|
|
typedef struct {
|
|
char *buf;
|
|
size_t len;
|
|
size_t capacity;
|
|
} stats_buf_t;
|
|
|
|
static void
|
|
stats_buf_init(stats_buf_t *sbuf) {
|
|
/* 1MB buffer should be enough since per-arena stats are omitted. */
|
|
sbuf->capacity = 1 << 20;
|
|
sbuf->buf = mallocx(sbuf->capacity, MALLOCX_TCACHE_NONE);
|
|
assert_ptr_not_null(sbuf->buf, "Failed to allocate stats buffer");
|
|
sbuf->len = 0;
|
|
sbuf->buf[0] = '\0';
|
|
}
|
|
|
|
static void
|
|
stats_buf_fini(stats_buf_t *sbuf) {
|
|
dallocx(sbuf->buf, MALLOCX_TCACHE_NONE);
|
|
}
|
|
|
|
static void
|
|
stats_buf_write_cb(void *opaque, const char *str) {
|
|
stats_buf_t *sbuf = (stats_buf_t *)opaque;
|
|
size_t slen = strlen(str);
|
|
|
|
if (sbuf->len + slen + 1 > sbuf->capacity) {
|
|
return;
|
|
}
|
|
memcpy(&sbuf->buf[sbuf->len], str, slen + 1);
|
|
sbuf->len += slen;
|
|
}
|
|
|
|
static bool
|
|
json_extract_uint64(const char *json, const char *key, uint64_t *result) {
|
|
char search_key[128];
|
|
size_t key_len;
|
|
|
|
key_len = snprintf(search_key, sizeof(search_key), "\"%s\":", key);
|
|
if (key_len >= sizeof(search_key)) {
|
|
return true;
|
|
}
|
|
|
|
const char *pos = strstr(json, search_key);
|
|
if (pos == NULL) {
|
|
return true;
|
|
}
|
|
|
|
pos += key_len;
|
|
while (*pos == ' ' || *pos == '\t' || *pos == '\n') {
|
|
pos++;
|
|
}
|
|
|
|
char *endptr;
|
|
uint64_t value = strtoull(pos, &endptr, 10);
|
|
if (endptr == pos) {
|
|
return true;
|
|
}
|
|
|
|
*result = value;
|
|
return false;
|
|
}
|
|
|
|
static const char *
|
|
json_find_section(const char *json, const char *section_name) {
|
|
char search_pattern[128];
|
|
size_t pattern_len;
|
|
|
|
pattern_len = snprintf(
|
|
search_pattern, sizeof(search_pattern), "\"%s\":", section_name);
|
|
if (pattern_len >= sizeof(search_pattern)) {
|
|
return NULL;
|
|
}
|
|
|
|
return strstr(json, search_pattern);
|
|
}
|
|
|
|
static void
|
|
verify_mutex_json(const char *mutexes_section, const char *mallctl_prefix,
|
|
const char *mutex_name) {
|
|
char mallctl_path[128];
|
|
size_t sz;
|
|
|
|
const char *mutex_section = json_find_section(
|
|
mutexes_section, mutex_name);
|
|
expect_ptr_not_null(mutex_section,
|
|
"Could not find %s mutex section in JSON", mutex_name);
|
|
|
|
uint64_t ctl_num_ops, ctl_num_wait, ctl_num_spin_acq;
|
|
uint64_t ctl_num_owner_switch, ctl_total_wait_time, ctl_max_wait_time;
|
|
uint32_t ctl_max_num_thds;
|
|
|
|
sz = sizeof(uint64_t);
|
|
snprintf(mallctl_path, sizeof(mallctl_path), "%s.%s.num_ops",
|
|
mallctl_prefix, mutex_name);
|
|
expect_d_eq(mallctl(mallctl_path, &ctl_num_ops, &sz, NULL, 0), 0,
|
|
"Unexpected mallctl() failure for %s", mallctl_path);
|
|
|
|
snprintf(mallctl_path, sizeof(mallctl_path), "%s.%s.num_wait",
|
|
mallctl_prefix, mutex_name);
|
|
expect_d_eq(mallctl(mallctl_path, &ctl_num_wait, &sz, NULL, 0), 0,
|
|
"Unexpected mallctl() failure for %s", mallctl_path);
|
|
|
|
snprintf(mallctl_path, sizeof(mallctl_path), "%s.%s.num_spin_acq",
|
|
mallctl_prefix, mutex_name);
|
|
expect_d_eq(mallctl(mallctl_path, &ctl_num_spin_acq, &sz, NULL, 0), 0,
|
|
"Unexpected mallctl() failure for %s", mallctl_path);
|
|
|
|
snprintf(mallctl_path, sizeof(mallctl_path), "%s.%s.num_owner_switch",
|
|
mallctl_prefix, mutex_name);
|
|
expect_d_eq(mallctl(mallctl_path, &ctl_num_owner_switch, &sz, NULL, 0),
|
|
0, "Unexpected mallctl() failure for %s", mallctl_path);
|
|
|
|
snprintf(mallctl_path, sizeof(mallctl_path), "%s.%s.total_wait_time",
|
|
mallctl_prefix, mutex_name);
|
|
expect_d_eq(mallctl(mallctl_path, &ctl_total_wait_time, &sz, NULL, 0),
|
|
0, "Unexpected mallctl() failure for %s", mallctl_path);
|
|
|
|
snprintf(mallctl_path, sizeof(mallctl_path), "%s.%s.max_wait_time",
|
|
mallctl_prefix, mutex_name);
|
|
expect_d_eq(mallctl(mallctl_path, &ctl_max_wait_time, &sz, NULL, 0), 0,
|
|
"Unexpected mallctl() failure for %s", mallctl_path);
|
|
|
|
sz = sizeof(uint32_t);
|
|
snprintf(mallctl_path, sizeof(mallctl_path), "%s.%s.max_num_thds",
|
|
mallctl_prefix, mutex_name);
|
|
expect_d_eq(mallctl(mallctl_path, &ctl_max_num_thds, &sz, NULL, 0), 0,
|
|
"Unexpected mallctl() failure for %s", mallctl_path);
|
|
|
|
uint64_t json_num_ops, json_num_wait, json_num_spin_acq;
|
|
uint64_t json_num_owner_switch, json_total_wait_time,
|
|
json_max_wait_time;
|
|
uint64_t json_max_num_thds;
|
|
|
|
expect_false(
|
|
json_extract_uint64(mutex_section, "num_ops", &json_num_ops),
|
|
"%s: num_ops not found in JSON", mutex_name);
|
|
expect_false(
|
|
json_extract_uint64(mutex_section, "num_wait", &json_num_wait),
|
|
"%s: num_wait not found in JSON", mutex_name);
|
|
expect_false(json_extract_uint64(
|
|
mutex_section, "num_spin_acq", &json_num_spin_acq),
|
|
"%s: num_spin_acq not found in JSON", mutex_name);
|
|
expect_false(json_extract_uint64(mutex_section, "num_owner_switch",
|
|
&json_num_owner_switch),
|
|
"%s: num_owner_switch not found in JSON", mutex_name);
|
|
expect_false(json_extract_uint64(mutex_section, "total_wait_time",
|
|
&json_total_wait_time),
|
|
"%s: total_wait_time not found in JSON", mutex_name);
|
|
expect_false(json_extract_uint64(
|
|
mutex_section, "max_wait_time", &json_max_wait_time),
|
|
"%s: max_wait_time not found in JSON", mutex_name);
|
|
expect_false(json_extract_uint64(
|
|
mutex_section, "max_num_thds", &json_max_num_thds),
|
|
"%s: max_num_thds not found in JSON", mutex_name);
|
|
|
|
expect_u64_eq(json_num_ops, ctl_num_ops,
|
|
"%s: JSON num_ops doesn't match mallctl", mutex_name);
|
|
expect_u64_eq(json_num_wait, ctl_num_wait,
|
|
"%s: JSON num_wait doesn't match mallctl", mutex_name);
|
|
expect_u64_eq(json_num_spin_acq, ctl_num_spin_acq,
|
|
"%s: JSON num_spin_acq doesn't match mallctl", mutex_name);
|
|
expect_u64_eq(json_num_owner_switch, ctl_num_owner_switch,
|
|
"%s: JSON num_owner_switch doesn't match mallctl", mutex_name);
|
|
expect_u64_eq(json_total_wait_time, ctl_total_wait_time,
|
|
"%s: JSON total_wait_time doesn't match mallctl", mutex_name);
|
|
expect_u64_eq(json_max_wait_time, ctl_max_wait_time,
|
|
"%s: JSON max_wait_time doesn't match mallctl", mutex_name);
|
|
expect_u32_eq((uint32_t)json_max_num_thds, ctl_max_num_thds,
|
|
"%s: JSON max_num_thds doesn't match mallctl", mutex_name);
|
|
}
|
|
|
|
static const char *global_mutex_names[] = {"background_thread",
|
|
"max_per_bg_thd", "ctl", "prof", "prof_thds_data", "prof_dump",
|
|
"prof_recent_alloc", "prof_recent_dump", "prof_stats"};
|
|
static const size_t num_global_mutexes = sizeof(global_mutex_names)
|
|
/ sizeof(global_mutex_names[0]);
|
|
|
|
static const char *arena_mutex_names[] = {"large", "extent_avail",
|
|
"extents_dirty", "extents_muzzy", "extents_retained", "decay_dirty",
|
|
"decay_muzzy", "base", "tcache_list", "hpa_shard", "hpa_shard_grow",
|
|
"hpa_sec"};
|
|
static const size_t num_arena_mutexes = sizeof(arena_mutex_names)
|
|
/ sizeof(arena_mutex_names[0]);
|
|
|
|
TEST_BEGIN(test_json_stats_mutexes) {
|
|
test_skip_if(!config_stats);
|
|
|
|
uint64_t epoch;
|
|
expect_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, sizeof(epoch)),
|
|
0, "Unexpected mallctl() failure");
|
|
|
|
stats_buf_t sbuf;
|
|
stats_buf_init(&sbuf);
|
|
/* "J" for JSON format, "a" to omit per-arena stats. */
|
|
malloc_stats_print(stats_buf_write_cb, &sbuf, "Ja");
|
|
|
|
/* Verify global mutexes under stats.mutexes. */
|
|
const char *global_mutexes_section = json_find_section(
|
|
sbuf.buf, "mutexes");
|
|
expect_ptr_not_null(global_mutexes_section,
|
|
"Could not find global mutexes section in JSON output");
|
|
|
|
for (size_t i = 0; i < num_global_mutexes; i++) {
|
|
verify_mutex_json(global_mutexes_section, "stats.mutexes",
|
|
global_mutex_names[i]);
|
|
}
|
|
|
|
/* Verify arena mutexes under stats.arenas.merged.mutexes. */
|
|
const char *arenas_section = json_find_section(
|
|
sbuf.buf, "stats.arenas");
|
|
expect_ptr_not_null(arenas_section,
|
|
"Could not find stats.arenas section in JSON output");
|
|
|
|
const char *merged_section = json_find_section(
|
|
arenas_section, "merged");
|
|
expect_ptr_not_null(
|
|
merged_section, "Could not find merged section in JSON output");
|
|
|
|
const char *arena_mutexes_section = json_find_section(
|
|
merged_section, "mutexes");
|
|
expect_ptr_not_null(arena_mutexes_section,
|
|
"Could not find arena mutexes section in JSON output");
|
|
|
|
for (size_t i = 0; i < num_arena_mutexes; i++) {
|
|
/*
|
|
* MALLCTL_ARENAS_ALL is 4096 representing all arenas in
|
|
* mallctl queries.
|
|
*/
|
|
verify_mutex_json(arena_mutexes_section,
|
|
"stats.arenas.4096.mutexes", arena_mutex_names[i]);
|
|
}
|
|
|
|
stats_buf_fini(&sbuf);
|
|
}
|
|
TEST_END
|
|
|
|
int
|
|
main(void) {
|
|
return test(test_json_stats_mutexes);
|
|
}
|