mirror of
https://github.com/jemalloc/jemalloc.git
synced 2026-06-19 10:25:38 +03:00
Expose psset state stats
When evaluating changes in HPA logic, it is useful to know internal `hpa_shard` state. Great deal of this state is `psset`. Some of the `psset` stats was available, but in disaggregated form, which is not very convenient. This commit exposed `psset` counters to `mallctl` and malloc stats dumps. Example of how malloc stats dump will look like after the change. HPA shard stats: Pageslabs: 14899 (4354 huge, 10545 nonhuge) Active pages: 6708166 (2228917 huge, 4479249 nonhuge) Dirty pages: 233816 (331 huge, 233485 nonhuge) Retained pages: 686306 Purge passes: 8730 (10 / sec) Purges: 127501 (146 / sec) Hugeifies: 4358 (5 / sec) Dehugifies: 4 (0 / sec) Pageslabs, active pages, dirty pages and retained pages are rows added by this change.
This commit is contained in:
parent
3820e38dc1
commit
9a69bb6c6b
6 changed files with 458 additions and 58 deletions
|
|
@ -1002,6 +1002,63 @@ TEST_BEGIN(test_stats_arenas) {
|
|||
}
|
||||
TEST_END
|
||||
|
||||
TEST_BEGIN(test_stats_arenas_hpa_shard_counters) {
|
||||
test_skip_if(!config_stats);
|
||||
|
||||
#define TEST_STATS_ARENAS_HPA_SHARD_COUNTERS(t, name) do { \
|
||||
t name; \
|
||||
size_t sz = sizeof(t); \
|
||||
expect_d_eq(mallctl("stats.arenas.0.hpa_shard."#name, \
|
||||
(void *)&name, &sz, \
|
||||
NULL, 0), 0, "Unexpected mallctl() failure"); \
|
||||
} while (0)
|
||||
|
||||
TEST_STATS_ARENAS_HPA_SHARD_COUNTERS(size_t, npageslabs);
|
||||
TEST_STATS_ARENAS_HPA_SHARD_COUNTERS(size_t, nactive);
|
||||
TEST_STATS_ARENAS_HPA_SHARD_COUNTERS(size_t, ndirty);
|
||||
TEST_STATS_ARENAS_HPA_SHARD_COUNTERS(uint64_t, npurge_passes);
|
||||
TEST_STATS_ARENAS_HPA_SHARD_COUNTERS(uint64_t, npurges);
|
||||
TEST_STATS_ARENAS_HPA_SHARD_COUNTERS(uint64_t, nhugifies);
|
||||
TEST_STATS_ARENAS_HPA_SHARD_COUNTERS(uint64_t, ndehugifies);
|
||||
|
||||
#undef TEST_STATS_ARENAS_HPA_SHARD_COUNTERS
|
||||
}
|
||||
TEST_END
|
||||
|
||||
TEST_BEGIN(test_stats_arenas_hpa_shard_slabs) {
|
||||
test_skip_if(!config_stats);
|
||||
|
||||
#define TEST_STATS_ARENAS_HPA_SHARD_SLABS_GEN(t, slab, name) do { \
|
||||
t slab##_##name; \
|
||||
size_t sz = sizeof(t); \
|
||||
expect_d_eq(mallctl("stats.arenas.0.hpa_shard."#slab"."#name, \
|
||||
(void *)&slab##_##name, &sz, \
|
||||
NULL, 0), 0, "Unexpected mallctl() failure"); \
|
||||
} while (0)
|
||||
|
||||
#define TEST_STATS_ARENAS_HPA_SHARD_SLABS(t, slab, name) do { \
|
||||
TEST_STATS_ARENAS_HPA_SHARD_SLABS_GEN(t, slab, \
|
||||
name##_##nonhuge); \
|
||||
TEST_STATS_ARENAS_HPA_SHARD_SLABS_GEN(t, slab, name##_##huge); \
|
||||
} while (0)
|
||||
|
||||
TEST_STATS_ARENAS_HPA_SHARD_SLABS(size_t, slabs, npageslabs);
|
||||
TEST_STATS_ARENAS_HPA_SHARD_SLABS(size_t, slabs, nactive);
|
||||
TEST_STATS_ARENAS_HPA_SHARD_SLABS(size_t, slabs, ndirty);
|
||||
|
||||
TEST_STATS_ARENAS_HPA_SHARD_SLABS(size_t, full_slabs, npageslabs);
|
||||
TEST_STATS_ARENAS_HPA_SHARD_SLABS(size_t, full_slabs, nactive);
|
||||
TEST_STATS_ARENAS_HPA_SHARD_SLABS(size_t, full_slabs, ndirty);
|
||||
|
||||
TEST_STATS_ARENAS_HPA_SHARD_SLABS(size_t, empty_slabs, npageslabs);
|
||||
TEST_STATS_ARENAS_HPA_SHARD_SLABS(size_t, empty_slabs, nactive);
|
||||
TEST_STATS_ARENAS_HPA_SHARD_SLABS(size_t, empty_slabs, ndirty);
|
||||
|
||||
#undef TEST_STATS_ARENAS_HPA_SHARD_SLABS
|
||||
#undef TEST_STATS_ARENAS_HPA_SHARD_SLABS_GEN
|
||||
}
|
||||
TEST_END
|
||||
|
||||
static void
|
||||
alloc_hook(void *extra, UNUSED hook_alloc_t type, UNUSED void *result,
|
||||
UNUSED uintptr_t result_raw, UNUSED uintptr_t args_raw[3]) {
|
||||
|
|
@ -1321,6 +1378,8 @@ main(void) {
|
|||
test_arenas_lookup,
|
||||
test_prof_active,
|
||||
test_stats_arenas,
|
||||
test_stats_arenas_hpa_shard_counters,
|
||||
test_stats_arenas_hpa_shard_slabs,
|
||||
test_hooks,
|
||||
test_hooks_exhaustion,
|
||||
test_thread_idle,
|
||||
|
|
|
|||
|
|
@ -64,6 +64,24 @@ test_psset_alloc_reuse(psset_t *psset, edata_t *r_edata, size_t size) {
|
|||
return false;
|
||||
}
|
||||
|
||||
static hpdata_t *
|
||||
test_psset_hugify(psset_t *psset, edata_t *edata) {
|
||||
hpdata_t *ps = edata_ps_get(edata);
|
||||
psset_update_begin(psset, ps);
|
||||
hpdata_hugify(ps);
|
||||
psset_update_end(psset, ps);
|
||||
return ps;
|
||||
}
|
||||
|
||||
static hpdata_t *
|
||||
test_psset_dehugify(psset_t *psset, edata_t *edata) {
|
||||
hpdata_t *ps = edata_ps_get(edata);
|
||||
psset_update_begin(psset, ps);
|
||||
hpdata_dehugify(ps);
|
||||
psset_update_end(psset, ps);
|
||||
return ps;
|
||||
}
|
||||
|
||||
static hpdata_t *
|
||||
test_psset_dalloc(psset_t *psset, edata_t *edata) {
|
||||
hpdata_t *ps = edata_ps_get(edata);
|
||||
|
|
@ -339,6 +357,149 @@ TEST_BEGIN(test_multi_pageslab) {
|
|||
}
|
||||
TEST_END
|
||||
|
||||
TEST_BEGIN(test_stats_merged) {
|
||||
hpdata_t pageslab;
|
||||
hpdata_init(&pageslab, PAGESLAB_ADDR, PAGESLAB_AGE);
|
||||
|
||||
edata_t alloc[HUGEPAGE_PAGES];
|
||||
|
||||
psset_t psset;
|
||||
psset_init(&psset);
|
||||
expect_zu_eq(0, psset.stats.merged.npageslabs, "");
|
||||
expect_zu_eq(0, psset.stats.merged.nactive, "");
|
||||
expect_zu_eq(0, psset.stats.merged.ndirty, "");
|
||||
|
||||
edata_init_test(&alloc[0]);
|
||||
test_psset_alloc_new(&psset, &pageslab, &alloc[0], PAGE);
|
||||
for (size_t i = 1; i < HUGEPAGE_PAGES; i++) {
|
||||
expect_zu_eq(1, psset.stats.merged.npageslabs, "");
|
||||
expect_zu_eq(i, psset.stats.merged.nactive, "");
|
||||
expect_zu_eq(0, psset.stats.merged.ndirty, "");
|
||||
|
||||
edata_init_test(&alloc[i]);
|
||||
bool err = test_psset_alloc_reuse(&psset, &alloc[i], PAGE);
|
||||
expect_false(err, "Nonempty psset failed page allocation.");
|
||||
}
|
||||
expect_zu_eq(1, psset.stats.merged.npageslabs, "");
|
||||
expect_zu_eq(HUGEPAGE_PAGES, psset.stats.merged.nactive, "");
|
||||
expect_zu_eq(0, psset.stats.merged.ndirty, "");
|
||||
|
||||
for (ssize_t i = HUGEPAGE_PAGES - 1; i > 0; i--) {
|
||||
test_psset_dalloc(&psset, &alloc[i]);
|
||||
expect_zu_eq(1, psset.stats.merged.npageslabs, "");
|
||||
expect_zu_eq(i, psset.stats.merged.nactive, "");
|
||||
expect_zu_eq(HUGEPAGE_PAGES - i, psset.stats.merged.ndirty, "");
|
||||
}
|
||||
/* No allocations have left. */
|
||||
test_psset_dalloc(&psset, &alloc[0]);
|
||||
expect_zu_eq(0, psset.stats.merged.npageslabs, "");
|
||||
expect_zu_eq(0, psset.stats.merged.nactive, "");
|
||||
|
||||
/*
|
||||
* Last test_psset_dalloc call removed empty pageslab from psset, so
|
||||
* nothing has left there, even no dirty pages.
|
||||
*/
|
||||
expect_zu_eq(0, psset.stats.merged.ndirty, "");
|
||||
|
||||
test_psset_alloc_new(&psset, &pageslab, &alloc[0], PAGE);
|
||||
expect_zu_eq(1, psset.stats.merged.npageslabs, "");
|
||||
expect_zu_eq(1, psset.stats.merged.nactive, "");
|
||||
expect_zu_eq(0, psset.stats.merged.ndirty, "");
|
||||
|
||||
psset_update_begin(&psset, &pageslab);
|
||||
expect_zu_eq(0, psset.stats.merged.npageslabs, "");
|
||||
expect_zu_eq(0, psset.stats.merged.nactive, "");
|
||||
expect_zu_eq(0, psset.stats.merged.ndirty, "");
|
||||
|
||||
psset_update_end(&psset, &pageslab);
|
||||
expect_zu_eq(1, psset.stats.merged.npageslabs, "");
|
||||
expect_zu_eq(1, psset.stats.merged.nactive, "");
|
||||
expect_zu_eq(0, psset.stats.merged.ndirty, "");
|
||||
}
|
||||
TEST_END
|
||||
|
||||
TEST_BEGIN(test_stats_huge) {
|
||||
test_skip_if(!config_stats);
|
||||
|
||||
hpdata_t pageslab;
|
||||
hpdata_init(&pageslab, PAGESLAB_ADDR, PAGESLAB_AGE);
|
||||
|
||||
edata_t alloc[HUGEPAGE_PAGES];
|
||||
|
||||
psset_t psset;
|
||||
psset_init(&psset);
|
||||
for (int huge = 0; huge < PSSET_NHUGE; ++huge) {
|
||||
expect_zu_eq(0, psset.stats.slabs[huge].npageslabs, "");
|
||||
expect_zu_eq(0, psset.stats.slabs[huge].nactive, "");
|
||||
expect_zu_eq(0, psset.stats.slabs[huge].ndirty, "");
|
||||
}
|
||||
|
||||
edata_init_test(&alloc[0]);
|
||||
test_psset_alloc_new(&psset, &pageslab, &alloc[0], PAGE);
|
||||
for (size_t i = 1; i < HUGEPAGE_PAGES; i++) {
|
||||
expect_zu_eq(1, psset.stats.slabs[0].npageslabs, "");
|
||||
expect_zu_eq(i, psset.stats.slabs[0].nactive, "");
|
||||
expect_zu_eq(0, psset.stats.slabs[0].ndirty, "");
|
||||
|
||||
expect_zu_eq(0, psset.stats.slabs[1].npageslabs, "");
|
||||
expect_zu_eq(0, psset.stats.slabs[1].nactive, "");
|
||||
expect_zu_eq(0, psset.stats.slabs[1].ndirty, "");
|
||||
|
||||
edata_init_test(&alloc[i]);
|
||||
bool err = test_psset_alloc_reuse(&psset, &alloc[i], PAGE);
|
||||
expect_false(err, "Nonempty psset failed page allocation.");
|
||||
}
|
||||
expect_zu_eq(1, psset.stats.slabs[0].npageslabs, "");
|
||||
expect_zu_eq(HUGEPAGE_PAGES, psset.stats.slabs[0].nactive, "");
|
||||
expect_zu_eq(0, psset.stats.slabs[0].ndirty, "");
|
||||
|
||||
expect_zu_eq(0, psset.stats.slabs[1].npageslabs, "");
|
||||
expect_zu_eq(0, psset.stats.slabs[1].nactive, "");
|
||||
expect_zu_eq(0, psset.stats.slabs[1].ndirty, "");
|
||||
|
||||
test_psset_hugify(&psset, &alloc[0]);
|
||||
|
||||
/* All stats should been moved from nonhuge to huge. */
|
||||
expect_zu_eq(0, psset.stats.slabs[0].npageslabs, "");
|
||||
expect_zu_eq(0, psset.stats.slabs[0].nactive, "");
|
||||
expect_zu_eq(0, psset.stats.slabs[0].ndirty, "");
|
||||
|
||||
expect_zu_eq(1, psset.stats.slabs[1].npageslabs, "");
|
||||
expect_zu_eq(HUGEPAGE_PAGES, psset.stats.slabs[1].nactive, "");
|
||||
expect_zu_eq(0, psset.stats.slabs[1].ndirty, "");
|
||||
|
||||
test_psset_dehugify(&psset, &alloc[0]);
|
||||
|
||||
/* And back from huge to nonhuge after dehugification. */
|
||||
expect_zu_eq(1, psset.stats.slabs[0].npageslabs, "");
|
||||
expect_zu_eq(HUGEPAGE_PAGES, psset.stats.slabs[0].nactive, "");
|
||||
expect_zu_eq(0, psset.stats.slabs[0].ndirty, "");
|
||||
|
||||
expect_zu_eq(0, psset.stats.slabs[1].npageslabs, "");
|
||||
expect_zu_eq(0, psset.stats.slabs[1].nactive, "");
|
||||
expect_zu_eq(0, psset.stats.slabs[1].ndirty, "");
|
||||
|
||||
for (ssize_t i = HUGEPAGE_PAGES - 1; i > 0; i--) {
|
||||
test_psset_dalloc(&psset, &alloc[i]);
|
||||
|
||||
expect_zu_eq(1, psset.stats.slabs[0].npageslabs, "");
|
||||
expect_zu_eq(i, psset.stats.slabs[0].nactive, "");
|
||||
expect_zu_eq(HUGEPAGE_PAGES - i, psset.stats.slabs[0].ndirty, "");
|
||||
|
||||
expect_zu_eq(0, psset.stats.slabs[1].npageslabs, "");
|
||||
expect_zu_eq(0, psset.stats.slabs[1].nactive, "");
|
||||
expect_zu_eq(0, psset.stats.slabs[1].ndirty, "");
|
||||
}
|
||||
test_psset_dalloc(&psset, &alloc[0]);
|
||||
|
||||
for (int huge = 0; huge < PSSET_NHUGE; huge++) {
|
||||
expect_zu_eq(0, psset.stats.slabs[huge].npageslabs, "");
|
||||
expect_zu_eq(0, psset.stats.slabs[huge].nactive, "");
|
||||
expect_zu_eq(0, psset.stats.slabs[huge].ndirty, "");
|
||||
}
|
||||
}
|
||||
TEST_END
|
||||
|
||||
static void
|
||||
stats_expect_empty(psset_bin_stats_t *stats) {
|
||||
assert_zu_eq(0, stats->npageslabs,
|
||||
|
|
@ -379,7 +540,9 @@ stats_expect(psset_t *psset, size_t nactive) {
|
|||
expect_zu_eq(nactive, psset_nactive(psset), "");
|
||||
}
|
||||
|
||||
TEST_BEGIN(test_stats) {
|
||||
TEST_BEGIN(test_stats_fullness) {
|
||||
test_skip_if(!config_stats);
|
||||
|
||||
bool err;
|
||||
|
||||
hpdata_t pageslab;
|
||||
|
|
@ -739,7 +902,9 @@ main(void) {
|
|||
test_reuse,
|
||||
test_evict,
|
||||
test_multi_pageslab,
|
||||
test_stats,
|
||||
test_stats_merged,
|
||||
test_stats_huge,
|
||||
test_stats_fullness,
|
||||
test_oldest_fit,
|
||||
test_insert_remove,
|
||||
test_purge_prefers_nonhuge,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue