Implement two-phase decay-based purging.
Split decay-based purging into two phases, the first of which uses lazy purging to convert dirty pages to "muzzy", and the second of which uses forced purging, decommit, or unmapping to convert pages to clean or destroy them altogether. Not all operating systems support lazy purging, yet the application may provide extent hooks that implement lazy purging, so care must be taken to dynamically omit the first phase when necessary. The mallctl interfaces change as follows: - opt.decay_time --> opt.{dirty,muzzy}_decay_time - arena.<i>.decay_time --> arena.<i>.{dirty,muzzy}_decay_time - arenas.decay_time --> arenas.{dirty,muzzy}_decay_time - stats.arenas.<i>.pdirty --> stats.arenas.<i>.p{dirty,muzzy} - stats.arenas.<i>.{npurge,nmadvise,purged} --> stats.arenas.<i>.{dirty,muzzy}_{npurge,nmadvise,purged} This resolves #521.
This commit is contained in:
@@ -161,7 +161,8 @@ TEST_BEGIN(test_mallctl_opt) {
|
||||
TEST_MALLCTL_OPT(const char *, dss, always);
|
||||
TEST_MALLCTL_OPT(unsigned, narenas, always);
|
||||
TEST_MALLCTL_OPT(const char *, percpu_arena, always);
|
||||
TEST_MALLCTL_OPT(ssize_t, decay_time, always);
|
||||
TEST_MALLCTL_OPT(ssize_t, dirty_decay_time, always);
|
||||
TEST_MALLCTL_OPT(ssize_t, muzzy_decay_time, always);
|
||||
TEST_MALLCTL_OPT(bool, stats_print, always);
|
||||
TEST_MALLCTL_OPT(const char *, junk, fill);
|
||||
TEST_MALLCTL_OPT(bool, zero, fill);
|
||||
@@ -401,32 +402,68 @@ TEST_BEGIN(test_arena_i_initialized) {
|
||||
}
|
||||
TEST_END
|
||||
|
||||
TEST_BEGIN(test_arena_i_decay_time) {
|
||||
ssize_t decay_time, orig_decay_time, prev_decay_time;
|
||||
TEST_BEGIN(test_arena_i_dirty_decay_time) {
|
||||
ssize_t dirty_decay_time, orig_dirty_decay_time, prev_dirty_decay_time;
|
||||
size_t sz = sizeof(ssize_t);
|
||||
|
||||
assert_d_eq(mallctl("arena.0.decay_time", (void *)&orig_decay_time, &sz,
|
||||
NULL, 0), 0, "Unexpected mallctl() failure");
|
||||
|
||||
decay_time = -2;
|
||||
assert_d_eq(mallctl("arena.0.decay_time", NULL, NULL,
|
||||
(void *)&decay_time, sizeof(ssize_t)), EFAULT,
|
||||
"Unexpected mallctl() success");
|
||||
|
||||
decay_time = 0x7fffffff;
|
||||
assert_d_eq(mallctl("arena.0.decay_time", NULL, NULL,
|
||||
(void *)&decay_time, sizeof(ssize_t)), 0,
|
||||
assert_d_eq(mallctl("arena.0.dirty_decay_time",
|
||||
(void *)&orig_dirty_decay_time, &sz, NULL, 0), 0,
|
||||
"Unexpected mallctl() failure");
|
||||
|
||||
for (prev_decay_time = decay_time, decay_time = -1;
|
||||
decay_time < 20; prev_decay_time = decay_time, decay_time++) {
|
||||
ssize_t old_decay_time;
|
||||
dirty_decay_time = -2;
|
||||
assert_d_eq(mallctl("arena.0.dirty_decay_time", NULL, NULL,
|
||||
(void *)&dirty_decay_time, sizeof(ssize_t)), EFAULT,
|
||||
"Unexpected mallctl() success");
|
||||
|
||||
assert_d_eq(mallctl("arena.0.decay_time", (void *)&old_decay_time,
|
||||
&sz, (void *)&decay_time, sizeof(ssize_t)), 0,
|
||||
dirty_decay_time = 0x7fffffff;
|
||||
assert_d_eq(mallctl("arena.0.dirty_decay_time", NULL, NULL,
|
||||
(void *)&dirty_decay_time, sizeof(ssize_t)), 0,
|
||||
"Unexpected mallctl() failure");
|
||||
|
||||
for (prev_dirty_decay_time = dirty_decay_time, dirty_decay_time = -1;
|
||||
dirty_decay_time < 20; prev_dirty_decay_time = dirty_decay_time,
|
||||
dirty_decay_time++) {
|
||||
ssize_t old_dirty_decay_time;
|
||||
|
||||
assert_d_eq(mallctl("arena.0.dirty_decay_time",
|
||||
(void *)&old_dirty_decay_time, &sz,
|
||||
(void *)&dirty_decay_time, sizeof(ssize_t)), 0,
|
||||
"Unexpected mallctl() failure");
|
||||
assert_zd_eq(old_decay_time, prev_decay_time,
|
||||
"Unexpected old arena.0.decay_time");
|
||||
assert_zd_eq(old_dirty_decay_time, prev_dirty_decay_time,
|
||||
"Unexpected old arena.0.dirty_decay_time");
|
||||
}
|
||||
}
|
||||
TEST_END
|
||||
|
||||
TEST_BEGIN(test_arena_i_muzzy_decay_time) {
|
||||
ssize_t muzzy_decay_time, orig_muzzy_decay_time, prev_muzzy_decay_time;
|
||||
size_t sz = sizeof(ssize_t);
|
||||
|
||||
assert_d_eq(mallctl("arena.0.muzzy_decay_time",
|
||||
(void *)&orig_muzzy_decay_time, &sz, NULL, 0), 0,
|
||||
"Unexpected mallctl() failure");
|
||||
|
||||
muzzy_decay_time = -2;
|
||||
assert_d_eq(mallctl("arena.0.muzzy_decay_time", NULL, NULL,
|
||||
(void *)&muzzy_decay_time, sizeof(ssize_t)), EFAULT,
|
||||
"Unexpected mallctl() success");
|
||||
|
||||
muzzy_decay_time = 0x7fffffff;
|
||||
assert_d_eq(mallctl("arena.0.muzzy_decay_time", NULL, NULL,
|
||||
(void *)&muzzy_decay_time, sizeof(ssize_t)), 0,
|
||||
"Unexpected mallctl() failure");
|
||||
|
||||
for (prev_muzzy_decay_time = muzzy_decay_time, muzzy_decay_time = -1;
|
||||
muzzy_decay_time < 20; prev_muzzy_decay_time = muzzy_decay_time,
|
||||
muzzy_decay_time++) {
|
||||
ssize_t old_muzzy_decay_time;
|
||||
|
||||
assert_d_eq(mallctl("arena.0.muzzy_decay_time",
|
||||
(void *)&old_muzzy_decay_time, &sz,
|
||||
(void *)&muzzy_decay_time, sizeof(ssize_t)), 0,
|
||||
"Unexpected mallctl() failure");
|
||||
assert_zd_eq(old_muzzy_decay_time, prev_muzzy_decay_time,
|
||||
"Unexpected old arena.0.muzzy_decay_time");
|
||||
}
|
||||
}
|
||||
TEST_END
|
||||
@@ -522,32 +559,68 @@ TEST_BEGIN(test_arena_i_dss) {
|
||||
}
|
||||
TEST_END
|
||||
|
||||
TEST_BEGIN(test_arenas_decay_time) {
|
||||
ssize_t decay_time, orig_decay_time, prev_decay_time;
|
||||
TEST_BEGIN(test_arenas_dirty_decay_time) {
|
||||
ssize_t dirty_decay_time, orig_dirty_decay_time, prev_dirty_decay_time;
|
||||
size_t sz = sizeof(ssize_t);
|
||||
|
||||
assert_d_eq(mallctl("arenas.decay_time", (void *)&orig_decay_time, &sz,
|
||||
NULL, 0), 0, "Unexpected mallctl() failure");
|
||||
assert_d_eq(mallctl("arenas.dirty_decay_time",
|
||||
(void *)&orig_dirty_decay_time, &sz, NULL, 0), 0,
|
||||
"Unexpected mallctl() failure");
|
||||
|
||||
decay_time = -2;
|
||||
assert_d_eq(mallctl("arenas.decay_time", NULL, NULL,
|
||||
(void *)&decay_time, sizeof(ssize_t)), EFAULT,
|
||||
dirty_decay_time = -2;
|
||||
assert_d_eq(mallctl("arenas.dirty_decay_time", NULL, NULL,
|
||||
(void *)&dirty_decay_time, sizeof(ssize_t)), EFAULT,
|
||||
"Unexpected mallctl() success");
|
||||
|
||||
decay_time = 0x7fffffff;
|
||||
assert_d_eq(mallctl("arenas.decay_time", NULL, NULL,
|
||||
(void *)&decay_time, sizeof(ssize_t)), 0,
|
||||
dirty_decay_time = 0x7fffffff;
|
||||
assert_d_eq(mallctl("arenas.dirty_decay_time", NULL, NULL,
|
||||
(void *)&dirty_decay_time, sizeof(ssize_t)), 0,
|
||||
"Expected mallctl() failure");
|
||||
|
||||
for (prev_decay_time = decay_time, decay_time = -1;
|
||||
decay_time < 20; prev_decay_time = decay_time, decay_time++) {
|
||||
ssize_t old_decay_time;
|
||||
for (prev_dirty_decay_time = dirty_decay_time, dirty_decay_time = -1;
|
||||
dirty_decay_time < 20; prev_dirty_decay_time = dirty_decay_time,
|
||||
dirty_decay_time++) {
|
||||
ssize_t old_dirty_decay_time;
|
||||
|
||||
assert_d_eq(mallctl("arenas.decay_time",
|
||||
(void *)&old_decay_time, &sz, (void *)&decay_time,
|
||||
sizeof(ssize_t)), 0, "Unexpected mallctl() failure");
|
||||
assert_zd_eq(old_decay_time, prev_decay_time,
|
||||
"Unexpected old arenas.decay_time");
|
||||
assert_d_eq(mallctl("arenas.dirty_decay_time",
|
||||
(void *)&old_dirty_decay_time, &sz,
|
||||
(void *)&dirty_decay_time, sizeof(ssize_t)), 0,
|
||||
"Unexpected mallctl() failure");
|
||||
assert_zd_eq(old_dirty_decay_time, prev_dirty_decay_time,
|
||||
"Unexpected old arenas.dirty_decay_time");
|
||||
}
|
||||
}
|
||||
TEST_END
|
||||
|
||||
TEST_BEGIN(test_arenas_muzzy_decay_time) {
|
||||
ssize_t muzzy_decay_time, orig_muzzy_decay_time, prev_muzzy_decay_time;
|
||||
size_t sz = sizeof(ssize_t);
|
||||
|
||||
assert_d_eq(mallctl("arenas.muzzy_decay_time",
|
||||
(void *)&orig_muzzy_decay_time, &sz, NULL, 0), 0,
|
||||
"Unexpected mallctl() failure");
|
||||
|
||||
muzzy_decay_time = -2;
|
||||
assert_d_eq(mallctl("arenas.muzzy_decay_time", NULL, NULL,
|
||||
(void *)&muzzy_decay_time, sizeof(ssize_t)), EFAULT,
|
||||
"Unexpected mallctl() success");
|
||||
|
||||
muzzy_decay_time = 0x7fffffff;
|
||||
assert_d_eq(mallctl("arenas.muzzy_decay_time", NULL, NULL,
|
||||
(void *)&muzzy_decay_time, sizeof(ssize_t)), 0,
|
||||
"Expected mallctl() failure");
|
||||
|
||||
for (prev_muzzy_decay_time = muzzy_decay_time, muzzy_decay_time = -1;
|
||||
muzzy_decay_time < 20; prev_muzzy_decay_time = muzzy_decay_time,
|
||||
muzzy_decay_time++) {
|
||||
ssize_t old_muzzy_decay_time;
|
||||
|
||||
assert_d_eq(mallctl("arenas.muzzy_decay_time",
|
||||
(void *)&old_muzzy_decay_time, &sz,
|
||||
(void *)&muzzy_decay_time, sizeof(ssize_t)), 0,
|
||||
"Unexpected mallctl() failure");
|
||||
assert_zd_eq(old_muzzy_decay_time, prev_muzzy_decay_time,
|
||||
"Unexpected old arenas.muzzy_decay_time");
|
||||
}
|
||||
}
|
||||
TEST_END
|
||||
@@ -630,7 +703,8 @@ TEST_BEGIN(test_stats_arenas) {
|
||||
|
||||
TEST_STATS_ARENAS(unsigned, nthreads);
|
||||
TEST_STATS_ARENAS(const char *, dss);
|
||||
TEST_STATS_ARENAS(ssize_t, decay_time);
|
||||
TEST_STATS_ARENAS(ssize_t, dirty_decay_time);
|
||||
TEST_STATS_ARENAS(ssize_t, muzzy_decay_time);
|
||||
TEST_STATS_ARENAS(size_t, pactive);
|
||||
TEST_STATS_ARENAS(size_t, pdirty);
|
||||
|
||||
@@ -653,11 +727,13 @@ main(void) {
|
||||
test_tcache,
|
||||
test_thread_arena,
|
||||
test_arena_i_initialized,
|
||||
test_arena_i_decay_time,
|
||||
test_arena_i_dirty_decay_time,
|
||||
test_arena_i_muzzy_decay_time,
|
||||
test_arena_i_purge,
|
||||
test_arena_i_decay,
|
||||
test_arena_i_dss,
|
||||
test_arenas_decay_time,
|
||||
test_arenas_dirty_decay_time,
|
||||
test_arenas_muzzy_decay_time,
|
||||
test_arenas_constants,
|
||||
test_arenas_bin_constants,
|
||||
test_arenas_lextent_constants,
|
||||
|
Reference in New Issue
Block a user