summaryrefslogtreecommitdiffstats
path: root/deps/jemalloc/test/unit/oversize_threshold.c
blob: 44a8f76a44e35e0e5887a49d983efeadfa1d6a12 (plain)
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);
}