1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
|
#include "test/jemalloc_test.h"
#include "jemalloc/internal/ctl.h"
static void
arena_mallctl(const char *mallctl_str, unsigned arena, void *oldp,
size_t *oldlen, void *newp, size_t newlen) {
int err;
char buf[100];
malloc_snprintf(buf, sizeof(buf), mallctl_str, arena);
err = mallctl(buf, oldp, oldlen, newp, newlen);
expect_d_eq(0, err, "Mallctl failed; %s", buf);
}
TEST_BEGIN(test_oversize_threshold_get_set) {
int err;
size_t old_threshold;
size_t new_threshold;
size_t threshold_sz = sizeof(old_threshold);
unsigned arena;
size_t arena_sz = sizeof(arena);
err = mallctl("arenas.create", (void *)&arena, &arena_sz, NULL, 0);
expect_d_eq(0, err, "Arena creation failed");
/* Just a write. */
new_threshold = 1024 * 1024;
arena_mallctl("arena.%u.oversize_threshold", arena, NULL, NULL,
&new_threshold, threshold_sz);
/* Read and write */
new_threshold = 2 * 1024 * 1024;
arena_mallctl("arena.%u.oversize_threshold", arena, &old_threshold,
&threshold_sz, &new_threshold, threshold_sz);
expect_zu_eq(1024 * 1024, old_threshold, "Should have read old value");
/* Just a read */
arena_mallctl("arena.%u.oversize_threshold", arena, &old_threshold,
&threshold_sz, NULL, 0);
expect_zu_eq(2 * 1024 * 1024, old_threshold, "Should have read old value");
}
TEST_END
static size_t max_purged = 0;
static bool
purge_forced_record_max(extent_hooks_t* hooks, void *addr, size_t sz,
size_t offset, size_t length, unsigned arena_ind) {
if (length > max_purged) {
max_purged = length;
}
return false;
}
static bool
dalloc_record_max(extent_hooks_t *extent_hooks, void *addr, size_t sz,
bool comitted, unsigned arena_ind) {
if (sz > max_purged) {
max_purged = sz;
}
return false;
}
extent_hooks_t max_recording_extent_hooks;
TEST_BEGIN(test_oversize_threshold) {
max_recording_extent_hooks = ehooks_default_extent_hooks;
max_recording_extent_hooks.purge_forced = &purge_forced_record_max;
max_recording_extent_hooks.dalloc = &dalloc_record_max;
extent_hooks_t *extent_hooks = &max_recording_extent_hooks;
int err;
unsigned arena;
size_t arena_sz = sizeof(arena);
err = mallctl("arenas.create", (void *)&arena, &arena_sz, NULL, 0);
expect_d_eq(0, err, "Arena creation failed");
arena_mallctl("arena.%u.extent_hooks", arena, NULL, NULL, &extent_hooks,
sizeof(extent_hooks));
/*
* This test will fundamentally race with purging, since we're going to
* check the dirty stats to see if our oversized allocation got purged.
* We don't want other purging to happen accidentally. We can't just
* disable purging entirely, though, since that will also disable
* oversize purging. Just set purging intervals to be very large.
*/
ssize_t decay_ms = 100 * 1000;
ssize_t decay_ms_sz = sizeof(decay_ms);
arena_mallctl("arena.%u.dirty_decay_ms", arena, NULL, NULL, &decay_ms,
decay_ms_sz);
arena_mallctl("arena.%u.muzzy_decay_ms", arena, NULL, NULL, &decay_ms,
decay_ms_sz);
/* Clean everything out. */
arena_mallctl("arena.%u.purge", arena, NULL, NULL, NULL, 0);
max_purged = 0;
/* Set threshold to 1MB. */
size_t threshold = 1024 * 1024;
size_t threshold_sz = sizeof(threshold);
arena_mallctl("arena.%u.oversize_threshold", arena, NULL, NULL,
&threshold, threshold_sz);
/* Allocating and freeing half a megabyte should leave them dirty. */
void *ptr = mallocx(512 * 1024, MALLOCX_ARENA(arena));
dallocx(ptr, MALLOCX_TCACHE_NONE);
if (!is_background_thread_enabled()) {
expect_zu_lt(max_purged, 512 * 1024, "Expected no 512k purge");
}
/* Purge again to reset everything out. */
arena_mallctl("arena.%u.purge", arena, NULL, NULL, NULL, 0);
max_purged = 0;
/*
* Allocating and freeing 2 megabytes should have them purged because of
* the oversize threshold.
*/
ptr = mallocx(2 * 1024 * 1024, MALLOCX_ARENA(arena));
dallocx(ptr, MALLOCX_TCACHE_NONE);
expect_zu_ge(max_purged, 2 * 1024 * 1024, "Expected a 2MB purge");
}
TEST_END
int
main(void) {
return test_no_reentrancy(
test_oversize_threshold_get_set,
test_oversize_threshold);
}
|