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