mallctl.c revision 1.1.1.1.14.1 1 1.1 christos #include "test/jemalloc_test.h"
2 1.1 christos
3 1.1.1.1.14.1 perseant #include "jemalloc/internal/ctl.h"
4 1.1.1.1.14.1 perseant #include "jemalloc/internal/hook.h"
5 1.1 christos #include "jemalloc/internal/util.h"
6 1.1 christos
7 1.1 christos TEST_BEGIN(test_mallctl_errors) {
8 1.1 christos uint64_t epoch;
9 1.1 christos size_t sz;
10 1.1 christos
11 1.1.1.1.14.1 perseant expect_d_eq(mallctl("no_such_name", NULL, NULL, NULL, 0), ENOENT,
12 1.1 christos "mallctl() should return ENOENT for non-existent names");
13 1.1 christos
14 1.1.1.1.14.1 perseant expect_d_eq(mallctl("version", NULL, NULL, "0.0.0", strlen("0.0.0")),
15 1.1 christos EPERM, "mallctl() should return EPERM on attempt to write "
16 1.1 christos "read-only value");
17 1.1 christos
18 1.1.1.1.14.1 perseant expect_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch,
19 1.1 christos sizeof(epoch)-1), EINVAL,
20 1.1 christos "mallctl() should return EINVAL for input size mismatch");
21 1.1.1.1.14.1 perseant expect_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch,
22 1.1 christos sizeof(epoch)+1), EINVAL,
23 1.1 christos "mallctl() should return EINVAL for input size mismatch");
24 1.1 christos
25 1.1 christos sz = sizeof(epoch)-1;
26 1.1.1.1.14.1 perseant expect_d_eq(mallctl("epoch", (void *)&epoch, &sz, NULL, 0), EINVAL,
27 1.1 christos "mallctl() should return EINVAL for output size mismatch");
28 1.1 christos sz = sizeof(epoch)+1;
29 1.1.1.1.14.1 perseant expect_d_eq(mallctl("epoch", (void *)&epoch, &sz, NULL, 0), EINVAL,
30 1.1 christos "mallctl() should return EINVAL for output size mismatch");
31 1.1 christos }
32 1.1 christos TEST_END
33 1.1 christos
34 1.1 christos TEST_BEGIN(test_mallctlnametomib_errors) {
35 1.1 christos size_t mib[1];
36 1.1 christos size_t miblen;
37 1.1 christos
38 1.1 christos miblen = sizeof(mib)/sizeof(size_t);
39 1.1.1.1.14.1 perseant expect_d_eq(mallctlnametomib("no_such_name", mib, &miblen), ENOENT,
40 1.1 christos "mallctlnametomib() should return ENOENT for non-existent names");
41 1.1 christos }
42 1.1 christos TEST_END
43 1.1 christos
44 1.1 christos TEST_BEGIN(test_mallctlbymib_errors) {
45 1.1 christos uint64_t epoch;
46 1.1 christos size_t sz;
47 1.1 christos size_t mib[1];
48 1.1 christos size_t miblen;
49 1.1 christos
50 1.1 christos miblen = sizeof(mib)/sizeof(size_t);
51 1.1.1.1.14.1 perseant expect_d_eq(mallctlnametomib("version", mib, &miblen), 0,
52 1.1 christos "Unexpected mallctlnametomib() failure");
53 1.1 christos
54 1.1.1.1.14.1 perseant expect_d_eq(mallctlbymib(mib, miblen, NULL, NULL, "0.0.0",
55 1.1 christos strlen("0.0.0")), EPERM, "mallctl() should return EPERM on "
56 1.1 christos "attempt to write read-only value");
57 1.1 christos
58 1.1 christos miblen = sizeof(mib)/sizeof(size_t);
59 1.1.1.1.14.1 perseant expect_d_eq(mallctlnametomib("epoch", mib, &miblen), 0,
60 1.1 christos "Unexpected mallctlnametomib() failure");
61 1.1 christos
62 1.1.1.1.14.1 perseant expect_d_eq(mallctlbymib(mib, miblen, NULL, NULL, (void *)&epoch,
63 1.1 christos sizeof(epoch)-1), EINVAL,
64 1.1 christos "mallctlbymib() should return EINVAL for input size mismatch");
65 1.1.1.1.14.1 perseant expect_d_eq(mallctlbymib(mib, miblen, NULL, NULL, (void *)&epoch,
66 1.1 christos sizeof(epoch)+1), EINVAL,
67 1.1 christos "mallctlbymib() should return EINVAL for input size mismatch");
68 1.1 christos
69 1.1 christos sz = sizeof(epoch)-1;
70 1.1.1.1.14.1 perseant expect_d_eq(mallctlbymib(mib, miblen, (void *)&epoch, &sz, NULL, 0),
71 1.1 christos EINVAL,
72 1.1 christos "mallctlbymib() should return EINVAL for output size mismatch");
73 1.1 christos sz = sizeof(epoch)+1;
74 1.1.1.1.14.1 perseant expect_d_eq(mallctlbymib(mib, miblen, (void *)&epoch, &sz, NULL, 0),
75 1.1 christos EINVAL,
76 1.1 christos "mallctlbymib() should return EINVAL for output size mismatch");
77 1.1 christos }
78 1.1 christos TEST_END
79 1.1 christos
80 1.1 christos TEST_BEGIN(test_mallctl_read_write) {
81 1.1 christos uint64_t old_epoch, new_epoch;
82 1.1 christos size_t sz = sizeof(old_epoch);
83 1.1 christos
84 1.1 christos /* Blind. */
85 1.1.1.1.14.1 perseant expect_d_eq(mallctl("epoch", NULL, NULL, NULL, 0), 0,
86 1.1 christos "Unexpected mallctl() failure");
87 1.1.1.1.14.1 perseant expect_zu_eq(sz, sizeof(old_epoch), "Unexpected output size");
88 1.1 christos
89 1.1 christos /* Read. */
90 1.1.1.1.14.1 perseant expect_d_eq(mallctl("epoch", (void *)&old_epoch, &sz, NULL, 0), 0,
91 1.1 christos "Unexpected mallctl() failure");
92 1.1.1.1.14.1 perseant expect_zu_eq(sz, sizeof(old_epoch), "Unexpected output size");
93 1.1 christos
94 1.1 christos /* Write. */
95 1.1.1.1.14.1 perseant expect_d_eq(mallctl("epoch", NULL, NULL, (void *)&new_epoch,
96 1.1 christos sizeof(new_epoch)), 0, "Unexpected mallctl() failure");
97 1.1.1.1.14.1 perseant expect_zu_eq(sz, sizeof(old_epoch), "Unexpected output size");
98 1.1 christos
99 1.1 christos /* Read+write. */
100 1.1.1.1.14.1 perseant expect_d_eq(mallctl("epoch", (void *)&old_epoch, &sz,
101 1.1 christos (void *)&new_epoch, sizeof(new_epoch)), 0,
102 1.1 christos "Unexpected mallctl() failure");
103 1.1.1.1.14.1 perseant expect_zu_eq(sz, sizeof(old_epoch), "Unexpected output size");
104 1.1 christos }
105 1.1 christos TEST_END
106 1.1 christos
107 1.1 christos TEST_BEGIN(test_mallctlnametomib_short_mib) {
108 1.1 christos size_t mib[4];
109 1.1 christos size_t miblen;
110 1.1 christos
111 1.1 christos miblen = 3;
112 1.1 christos mib[3] = 42;
113 1.1.1.1.14.1 perseant expect_d_eq(mallctlnametomib("arenas.bin.0.nregs", mib, &miblen), 0,
114 1.1 christos "Unexpected mallctlnametomib() failure");
115 1.1.1.1.14.1 perseant expect_zu_eq(miblen, 3, "Unexpected mib output length");
116 1.1.1.1.14.1 perseant expect_zu_eq(mib[3], 42,
117 1.1 christos "mallctlnametomib() wrote past the end of the input mib");
118 1.1 christos }
119 1.1 christos TEST_END
120 1.1 christos
121 1.1.1.1.14.1 perseant TEST_BEGIN(test_mallctlnametomib_short_name) {
122 1.1.1.1.14.1 perseant size_t mib[4];
123 1.1.1.1.14.1 perseant size_t miblen;
124 1.1.1.1.14.1 perseant
125 1.1.1.1.14.1 perseant miblen = 4;
126 1.1.1.1.14.1 perseant mib[3] = 42;
127 1.1.1.1.14.1 perseant expect_d_eq(mallctlnametomib("arenas.bin.0", mib, &miblen), 0,
128 1.1.1.1.14.1 perseant "Unexpected mallctlnametomib() failure");
129 1.1.1.1.14.1 perseant expect_zu_eq(miblen, 3, "Unexpected mib output length");
130 1.1.1.1.14.1 perseant expect_zu_eq(mib[3], 42,
131 1.1.1.1.14.1 perseant "mallctlnametomib() wrote past the end of the input mib");
132 1.1.1.1.14.1 perseant }
133 1.1.1.1.14.1 perseant TEST_END
134 1.1.1.1.14.1 perseant
135 1.1.1.1.14.1 perseant TEST_BEGIN(test_mallctlmibnametomib) {
136 1.1.1.1.14.1 perseant size_t mib[4];
137 1.1.1.1.14.1 perseant size_t miblen = 4;
138 1.1.1.1.14.1 perseant uint32_t result, result_ref;
139 1.1.1.1.14.1 perseant size_t len_result = sizeof(uint32_t);
140 1.1.1.1.14.1 perseant
141 1.1.1.1.14.1 perseant tsd_t *tsd = tsd_fetch();
142 1.1.1.1.14.1 perseant
143 1.1.1.1.14.1 perseant /* Error cases */
144 1.1.1.1.14.1 perseant assert_d_eq(ctl_mibnametomib(tsd, mib, 0, "bob", &miblen), ENOENT, "");
145 1.1.1.1.14.1 perseant assert_zu_eq(miblen, 4, "");
146 1.1.1.1.14.1 perseant assert_d_eq(ctl_mibnametomib(tsd, mib, 0, "9999", &miblen), ENOENT, "");
147 1.1.1.1.14.1 perseant assert_zu_eq(miblen, 4, "");
148 1.1.1.1.14.1 perseant
149 1.1.1.1.14.1 perseant /* Valid case. */
150 1.1.1.1.14.1 perseant assert_d_eq(ctl_mibnametomib(tsd, mib, 0, "arenas", &miblen), 0, "");
151 1.1.1.1.14.1 perseant assert_zu_eq(miblen, 1, "");
152 1.1.1.1.14.1 perseant miblen = 4;
153 1.1.1.1.14.1 perseant assert_d_eq(ctl_mibnametomib(tsd, mib, 1, "bin", &miblen), 0, "");
154 1.1.1.1.14.1 perseant assert_zu_eq(miblen, 2, "");
155 1.1.1.1.14.1 perseant expect_d_eq(mallctlbymib(mib, miblen, &result, &len_result, NULL, 0),
156 1.1.1.1.14.1 perseant ENOENT, "mallctlbymib() should fail on partial path");
157 1.1.1.1.14.1 perseant
158 1.1.1.1.14.1 perseant /* Error cases. */
159 1.1.1.1.14.1 perseant miblen = 4;
160 1.1.1.1.14.1 perseant assert_d_eq(ctl_mibnametomib(tsd, mib, 2, "bob", &miblen), ENOENT, "");
161 1.1.1.1.14.1 perseant assert_zu_eq(miblen, 4, "");
162 1.1.1.1.14.1 perseant assert_d_eq(ctl_mibnametomib(tsd, mib, 2, "9999", &miblen), ENOENT, "");
163 1.1.1.1.14.1 perseant assert_zu_eq(miblen, 4, "");
164 1.1.1.1.14.1 perseant
165 1.1.1.1.14.1 perseant /* Valid case. */
166 1.1.1.1.14.1 perseant assert_d_eq(ctl_mibnametomib(tsd, mib, 2, "0", &miblen), 0, "");
167 1.1.1.1.14.1 perseant assert_zu_eq(miblen, 3, "");
168 1.1.1.1.14.1 perseant expect_d_eq(mallctlbymib(mib, miblen, &result, &len_result, NULL, 0),
169 1.1.1.1.14.1 perseant ENOENT, "mallctlbymib() should fail on partial path");
170 1.1.1.1.14.1 perseant
171 1.1.1.1.14.1 perseant /* Error cases. */
172 1.1.1.1.14.1 perseant miblen = 4;
173 1.1.1.1.14.1 perseant assert_d_eq(ctl_mibnametomib(tsd, mib, 3, "bob", &miblen), ENOENT, "");
174 1.1.1.1.14.1 perseant assert_zu_eq(miblen, 4, "");
175 1.1.1.1.14.1 perseant assert_d_eq(ctl_mibnametomib(tsd, mib, 3, "9999", &miblen), ENOENT, "");
176 1.1.1.1.14.1 perseant assert_zu_eq(miblen, 4, "");
177 1.1.1.1.14.1 perseant
178 1.1.1.1.14.1 perseant /* Valid case. */
179 1.1.1.1.14.1 perseant assert_d_eq(ctl_mibnametomib(tsd, mib, 3, "nregs", &miblen), 0, "");
180 1.1.1.1.14.1 perseant assert_zu_eq(miblen, 4, "");
181 1.1.1.1.14.1 perseant assert_d_eq(mallctlbymib(mib, miblen, &result, &len_result, NULL, 0),
182 1.1.1.1.14.1 perseant 0, "Unexpected mallctlbymib() failure");
183 1.1.1.1.14.1 perseant assert_d_eq(mallctl("arenas.bin.0.nregs", &result_ref, &len_result,
184 1.1.1.1.14.1 perseant NULL, 0), 0, "Unexpected mallctl() failure");
185 1.1.1.1.14.1 perseant expect_zu_eq(result, result_ref,
186 1.1.1.1.14.1 perseant "mallctlbymib() and mallctl() returned different result");
187 1.1.1.1.14.1 perseant }
188 1.1.1.1.14.1 perseant TEST_END
189 1.1.1.1.14.1 perseant
190 1.1.1.1.14.1 perseant TEST_BEGIN(test_mallctlbymibname) {
191 1.1.1.1.14.1 perseant size_t mib[4];
192 1.1.1.1.14.1 perseant size_t miblen = 4;
193 1.1.1.1.14.1 perseant uint32_t result, result_ref;
194 1.1.1.1.14.1 perseant size_t len_result = sizeof(uint32_t);
195 1.1.1.1.14.1 perseant
196 1.1.1.1.14.1 perseant tsd_t *tsd = tsd_fetch();
197 1.1.1.1.14.1 perseant
198 1.1.1.1.14.1 perseant /* Error cases. */
199 1.1.1.1.14.1 perseant
200 1.1.1.1.14.1 perseant assert_d_eq(mallctlnametomib("arenas", mib, &miblen), 0,
201 1.1.1.1.14.1 perseant "Unexpected mallctlnametomib() failure");
202 1.1.1.1.14.1 perseant assert_zu_eq(miblen, 1, "");
203 1.1.1.1.14.1 perseant
204 1.1.1.1.14.1 perseant miblen = 4;
205 1.1.1.1.14.1 perseant assert_d_eq(ctl_bymibname(tsd, mib, 1, "bin.0", &miblen,
206 1.1.1.1.14.1 perseant &result, &len_result, NULL, 0), ENOENT, "");
207 1.1.1.1.14.1 perseant miblen = 4;
208 1.1.1.1.14.1 perseant assert_d_eq(ctl_bymibname(tsd, mib, 1, "bin.0.bob", &miblen,
209 1.1.1.1.14.1 perseant &result, &len_result, NULL, 0), ENOENT, "");
210 1.1.1.1.14.1 perseant assert_zu_eq(miblen, 4, "");
211 1.1.1.1.14.1 perseant
212 1.1.1.1.14.1 perseant /* Valid cases. */
213 1.1.1.1.14.1 perseant
214 1.1.1.1.14.1 perseant assert_d_eq(mallctl("arenas.bin.0.nregs", &result_ref, &len_result,
215 1.1.1.1.14.1 perseant NULL, 0), 0, "Unexpected mallctl() failure");
216 1.1.1.1.14.1 perseant miblen = 4;
217 1.1.1.1.14.1 perseant
218 1.1.1.1.14.1 perseant assert_d_eq(ctl_bymibname(tsd, mib, 0, "arenas.bin.0.nregs", &miblen,
219 1.1.1.1.14.1 perseant &result, &len_result, NULL, 0), 0, "");
220 1.1.1.1.14.1 perseant assert_zu_eq(miblen, 4, "");
221 1.1.1.1.14.1 perseant expect_zu_eq(result, result_ref, "Unexpected result");
222 1.1.1.1.14.1 perseant
223 1.1.1.1.14.1 perseant assert_d_eq(ctl_bymibname(tsd, mib, 1, "bin.0.nregs", &miblen, &result,
224 1.1.1.1.14.1 perseant &len_result, NULL, 0), 0, "");
225 1.1.1.1.14.1 perseant assert_zu_eq(miblen, 4, "");
226 1.1.1.1.14.1 perseant expect_zu_eq(result, result_ref, "Unexpected result");
227 1.1.1.1.14.1 perseant
228 1.1.1.1.14.1 perseant assert_d_eq(ctl_bymibname(tsd, mib, 2, "0.nregs", &miblen, &result,
229 1.1.1.1.14.1 perseant &len_result, NULL, 0), 0, "");
230 1.1.1.1.14.1 perseant assert_zu_eq(miblen, 4, "");
231 1.1.1.1.14.1 perseant expect_zu_eq(result, result_ref, "Unexpected result");
232 1.1.1.1.14.1 perseant
233 1.1.1.1.14.1 perseant assert_d_eq(ctl_bymibname(tsd, mib, 3, "nregs", &miblen, &result,
234 1.1.1.1.14.1 perseant &len_result, NULL, 0), 0, "");
235 1.1.1.1.14.1 perseant assert_zu_eq(miblen, 4, "");
236 1.1.1.1.14.1 perseant expect_zu_eq(result, result_ref, "Unexpected result");
237 1.1.1.1.14.1 perseant }
238 1.1.1.1.14.1 perseant TEST_END
239 1.1.1.1.14.1 perseant
240 1.1 christos TEST_BEGIN(test_mallctl_config) {
241 1.1 christos #define TEST_MALLCTL_CONFIG(config, t) do { \
242 1.1 christos t oldval; \
243 1.1 christos size_t sz = sizeof(oldval); \
244 1.1.1.1.14.1 perseant expect_d_eq(mallctl("config."#config, (void *)&oldval, &sz, \
245 1.1 christos NULL, 0), 0, "Unexpected mallctl() failure"); \
246 1.1.1.1.14.1 perseant expect_b_eq(oldval, config_##config, "Incorrect config value"); \
247 1.1.1.1.14.1 perseant expect_zu_eq(sz, sizeof(oldval), "Unexpected output size"); \
248 1.1 christos } while (0)
249 1.1 christos
250 1.1 christos TEST_MALLCTL_CONFIG(cache_oblivious, bool);
251 1.1 christos TEST_MALLCTL_CONFIG(debug, bool);
252 1.1 christos TEST_MALLCTL_CONFIG(fill, bool);
253 1.1 christos TEST_MALLCTL_CONFIG(lazy_lock, bool);
254 1.1 christos TEST_MALLCTL_CONFIG(malloc_conf, const char *);
255 1.1 christos TEST_MALLCTL_CONFIG(prof, bool);
256 1.1 christos TEST_MALLCTL_CONFIG(prof_libgcc, bool);
257 1.1 christos TEST_MALLCTL_CONFIG(prof_libunwind, bool);
258 1.1 christos TEST_MALLCTL_CONFIG(stats, bool);
259 1.1 christos TEST_MALLCTL_CONFIG(utrace, bool);
260 1.1 christos TEST_MALLCTL_CONFIG(xmalloc, bool);
261 1.1 christos
262 1.1 christos #undef TEST_MALLCTL_CONFIG
263 1.1 christos }
264 1.1 christos TEST_END
265 1.1 christos
266 1.1 christos TEST_BEGIN(test_mallctl_opt) {
267 1.1 christos bool config_always = true;
268 1.1 christos
269 1.1 christos #define TEST_MALLCTL_OPT(t, opt, config) do { \
270 1.1 christos t oldval; \
271 1.1 christos size_t sz = sizeof(oldval); \
272 1.1 christos int expected = config_##config ? 0 : ENOENT; \
273 1.1 christos int result = mallctl("opt."#opt, (void *)&oldval, &sz, NULL, \
274 1.1 christos 0); \
275 1.1.1.1.14.1 perseant expect_d_eq(result, expected, \
276 1.1 christos "Unexpected mallctl() result for opt."#opt); \
277 1.1.1.1.14.1 perseant expect_zu_eq(sz, sizeof(oldval), "Unexpected output size"); \
278 1.1 christos } while (0)
279 1.1 christos
280 1.1 christos TEST_MALLCTL_OPT(bool, abort, always);
281 1.1 christos TEST_MALLCTL_OPT(bool, abort_conf, always);
282 1.1.1.1.14.1 perseant TEST_MALLCTL_OPT(bool, cache_oblivious, always);
283 1.1.1.1.14.1 perseant TEST_MALLCTL_OPT(bool, trust_madvise, always);
284 1.1.1.1.14.1 perseant TEST_MALLCTL_OPT(bool, confirm_conf, always);
285 1.1 christos TEST_MALLCTL_OPT(const char *, metadata_thp, always);
286 1.1 christos TEST_MALLCTL_OPT(bool, retain, always);
287 1.1 christos TEST_MALLCTL_OPT(const char *, dss, always);
288 1.1.1.1.14.1 perseant TEST_MALLCTL_OPT(bool, hpa, always);
289 1.1.1.1.14.1 perseant TEST_MALLCTL_OPT(size_t, hpa_slab_max_alloc, always);
290 1.1.1.1.14.1 perseant TEST_MALLCTL_OPT(size_t, hpa_sec_nshards, always);
291 1.1.1.1.14.1 perseant TEST_MALLCTL_OPT(size_t, hpa_sec_max_alloc, always);
292 1.1.1.1.14.1 perseant TEST_MALLCTL_OPT(size_t, hpa_sec_max_bytes, always);
293 1.1.1.1.14.1 perseant TEST_MALLCTL_OPT(size_t, hpa_sec_bytes_after_flush, always);
294 1.1.1.1.14.1 perseant TEST_MALLCTL_OPT(size_t, hpa_sec_batch_fill_extra, always);
295 1.1 christos TEST_MALLCTL_OPT(unsigned, narenas, always);
296 1.1 christos TEST_MALLCTL_OPT(const char *, percpu_arena, always);
297 1.1.1.1.14.1 perseant TEST_MALLCTL_OPT(size_t, oversize_threshold, always);
298 1.1 christos TEST_MALLCTL_OPT(bool, background_thread, always);
299 1.1 christos TEST_MALLCTL_OPT(ssize_t, dirty_decay_ms, always);
300 1.1 christos TEST_MALLCTL_OPT(ssize_t, muzzy_decay_ms, always);
301 1.1 christos TEST_MALLCTL_OPT(bool, stats_print, always);
302 1.1.1.1.14.1 perseant TEST_MALLCTL_OPT(const char *, stats_print_opts, always);
303 1.1.1.1.14.1 perseant TEST_MALLCTL_OPT(int64_t, stats_interval, always);
304 1.1.1.1.14.1 perseant TEST_MALLCTL_OPT(const char *, stats_interval_opts, always);
305 1.1 christos TEST_MALLCTL_OPT(const char *, junk, fill);
306 1.1 christos TEST_MALLCTL_OPT(bool, zero, fill);
307 1.1 christos TEST_MALLCTL_OPT(bool, utrace, utrace);
308 1.1 christos TEST_MALLCTL_OPT(bool, xmalloc, xmalloc);
309 1.1 christos TEST_MALLCTL_OPT(bool, tcache, always);
310 1.1 christos TEST_MALLCTL_OPT(size_t, lg_extent_max_active_fit, always);
311 1.1.1.1.14.1 perseant TEST_MALLCTL_OPT(size_t, tcache_max, always);
312 1.1 christos TEST_MALLCTL_OPT(const char *, thp, always);
313 1.1.1.1.14.1 perseant TEST_MALLCTL_OPT(const char *, zero_realloc, always);
314 1.1 christos TEST_MALLCTL_OPT(bool, prof, prof);
315 1.1 christos TEST_MALLCTL_OPT(const char *, prof_prefix, prof);
316 1.1 christos TEST_MALLCTL_OPT(bool, prof_active, prof);
317 1.1 christos TEST_MALLCTL_OPT(ssize_t, lg_prof_sample, prof);
318 1.1 christos TEST_MALLCTL_OPT(bool, prof_accum, prof);
319 1.1 christos TEST_MALLCTL_OPT(ssize_t, lg_prof_interval, prof);
320 1.1 christos TEST_MALLCTL_OPT(bool, prof_gdump, prof);
321 1.1 christos TEST_MALLCTL_OPT(bool, prof_final, prof);
322 1.1 christos TEST_MALLCTL_OPT(bool, prof_leak, prof);
323 1.1.1.1.14.1 perseant TEST_MALLCTL_OPT(bool, prof_leak_error, prof);
324 1.1.1.1.14.1 perseant TEST_MALLCTL_OPT(ssize_t, prof_recent_alloc_max, prof);
325 1.1.1.1.14.1 perseant TEST_MALLCTL_OPT(bool, prof_stats, prof);
326 1.1.1.1.14.1 perseant TEST_MALLCTL_OPT(bool, prof_sys_thread_name, prof);
327 1.1.1.1.14.1 perseant TEST_MALLCTL_OPT(ssize_t, lg_san_uaf_align, uaf_detection);
328 1.1 christos
329 1.1 christos #undef TEST_MALLCTL_OPT
330 1.1 christos }
331 1.1 christos TEST_END
332 1.1 christos
333 1.1 christos TEST_BEGIN(test_manpage_example) {
334 1.1 christos unsigned nbins, i;
335 1.1 christos size_t mib[4];
336 1.1 christos size_t len, miblen;
337 1.1 christos
338 1.1 christos len = sizeof(nbins);
339 1.1.1.1.14.1 perseant expect_d_eq(mallctl("arenas.nbins", (void *)&nbins, &len, NULL, 0), 0,
340 1.1 christos "Unexpected mallctl() failure");
341 1.1 christos
342 1.1 christos miblen = 4;
343 1.1.1.1.14.1 perseant expect_d_eq(mallctlnametomib("arenas.bin.0.size", mib, &miblen), 0,
344 1.1 christos "Unexpected mallctlnametomib() failure");
345 1.1 christos for (i = 0; i < nbins; i++) {
346 1.1 christos size_t bin_size;
347 1.1 christos
348 1.1 christos mib[2] = i;
349 1.1 christos len = sizeof(bin_size);
350 1.1.1.1.14.1 perseant expect_d_eq(mallctlbymib(mib, miblen, (void *)&bin_size, &len,
351 1.1 christos NULL, 0), 0, "Unexpected mallctlbymib() failure");
352 1.1 christos /* Do something with bin_size... */
353 1.1 christos }
354 1.1 christos }
355 1.1 christos TEST_END
356 1.1 christos
357 1.1 christos TEST_BEGIN(test_tcache_none) {
358 1.1 christos test_skip_if(!opt_tcache);
359 1.1 christos
360 1.1 christos /* Allocate p and q. */
361 1.1 christos void *p0 = mallocx(42, 0);
362 1.1.1.1.14.1 perseant expect_ptr_not_null(p0, "Unexpected mallocx() failure");
363 1.1 christos void *q = mallocx(42, 0);
364 1.1.1.1.14.1 perseant expect_ptr_not_null(q, "Unexpected mallocx() failure");
365 1.1 christos
366 1.1 christos /* Deallocate p and q, but bypass the tcache for q. */
367 1.1 christos dallocx(p0, 0);
368 1.1 christos dallocx(q, MALLOCX_TCACHE_NONE);
369 1.1 christos
370 1.1 christos /* Make sure that tcache-based allocation returns p, not q. */
371 1.1 christos void *p1 = mallocx(42, 0);
372 1.1.1.1.14.1 perseant expect_ptr_not_null(p1, "Unexpected mallocx() failure");
373 1.1.1.1.14.1 perseant if (!opt_prof && !san_uaf_detection_enabled()) {
374 1.1.1.1.14.1 perseant expect_ptr_eq(p0, p1,
375 1.1.1.1.14.1 perseant "Expected tcache to allocate cached region");
376 1.1.1.1.14.1 perseant }
377 1.1 christos
378 1.1 christos /* Clean up. */
379 1.1 christos dallocx(p1, MALLOCX_TCACHE_NONE);
380 1.1 christos }
381 1.1 christos TEST_END
382 1.1 christos
383 1.1 christos TEST_BEGIN(test_tcache) {
384 1.1 christos #define NTCACHES 10
385 1.1 christos unsigned tis[NTCACHES];
386 1.1 christos void *ps[NTCACHES];
387 1.1 christos void *qs[NTCACHES];
388 1.1 christos unsigned i;
389 1.1 christos size_t sz, psz, qsz;
390 1.1 christos
391 1.1 christos psz = 42;
392 1.1 christos qsz = nallocx(psz, 0) + 1;
393 1.1 christos
394 1.1 christos /* Create tcaches. */
395 1.1 christos for (i = 0; i < NTCACHES; i++) {
396 1.1 christos sz = sizeof(unsigned);
397 1.1.1.1.14.1 perseant expect_d_eq(mallctl("tcache.create", (void *)&tis[i], &sz, NULL,
398 1.1 christos 0), 0, "Unexpected mallctl() failure, i=%u", i);
399 1.1 christos }
400 1.1 christos
401 1.1 christos /* Exercise tcache ID recycling. */
402 1.1 christos for (i = 0; i < NTCACHES; i++) {
403 1.1.1.1.14.1 perseant expect_d_eq(mallctl("tcache.destroy", NULL, NULL,
404 1.1 christos (void *)&tis[i], sizeof(unsigned)), 0,
405 1.1 christos "Unexpected mallctl() failure, i=%u", i);
406 1.1 christos }
407 1.1 christos for (i = 0; i < NTCACHES; i++) {
408 1.1 christos sz = sizeof(unsigned);
409 1.1.1.1.14.1 perseant expect_d_eq(mallctl("tcache.create", (void *)&tis[i], &sz, NULL,
410 1.1 christos 0), 0, "Unexpected mallctl() failure, i=%u", i);
411 1.1 christos }
412 1.1 christos
413 1.1 christos /* Flush empty tcaches. */
414 1.1 christos for (i = 0; i < NTCACHES; i++) {
415 1.1.1.1.14.1 perseant expect_d_eq(mallctl("tcache.flush", NULL, NULL, (void *)&tis[i],
416 1.1 christos sizeof(unsigned)), 0, "Unexpected mallctl() failure, i=%u",
417 1.1 christos i);
418 1.1 christos }
419 1.1 christos
420 1.1 christos /* Cache some allocations. */
421 1.1 christos for (i = 0; i < NTCACHES; i++) {
422 1.1 christos ps[i] = mallocx(psz, MALLOCX_TCACHE(tis[i]));
423 1.1.1.1.14.1 perseant expect_ptr_not_null(ps[i], "Unexpected mallocx() failure, i=%u",
424 1.1 christos i);
425 1.1 christos dallocx(ps[i], MALLOCX_TCACHE(tis[i]));
426 1.1 christos
427 1.1 christos qs[i] = mallocx(qsz, MALLOCX_TCACHE(tis[i]));
428 1.1.1.1.14.1 perseant expect_ptr_not_null(qs[i], "Unexpected mallocx() failure, i=%u",
429 1.1 christos i);
430 1.1 christos dallocx(qs[i], MALLOCX_TCACHE(tis[i]));
431 1.1 christos }
432 1.1 christos
433 1.1 christos /* Verify that tcaches allocate cached regions. */
434 1.1 christos for (i = 0; i < NTCACHES; i++) {
435 1.1 christos void *p0 = ps[i];
436 1.1 christos ps[i] = mallocx(psz, MALLOCX_TCACHE(tis[i]));
437 1.1.1.1.14.1 perseant expect_ptr_not_null(ps[i], "Unexpected mallocx() failure, i=%u",
438 1.1 christos i);
439 1.1.1.1.14.1 perseant if (!san_uaf_detection_enabled()) {
440 1.1.1.1.14.1 perseant expect_ptr_eq(ps[i], p0, "Expected mallocx() to "
441 1.1.1.1.14.1 perseant "allocate cached region, i=%u", i);
442 1.1.1.1.14.1 perseant }
443 1.1 christos }
444 1.1 christos
445 1.1 christos /* Verify that reallocation uses cached regions. */
446 1.1 christos for (i = 0; i < NTCACHES; i++) {
447 1.1 christos void *q0 = qs[i];
448 1.1 christos qs[i] = rallocx(ps[i], qsz, MALLOCX_TCACHE(tis[i]));
449 1.1.1.1.14.1 perseant expect_ptr_not_null(qs[i], "Unexpected rallocx() failure, i=%u",
450 1.1 christos i);
451 1.1.1.1.14.1 perseant if (!san_uaf_detection_enabled()) {
452 1.1.1.1.14.1 perseant expect_ptr_eq(qs[i], q0, "Expected rallocx() to "
453 1.1.1.1.14.1 perseant "allocate cached region, i=%u", i);
454 1.1.1.1.14.1 perseant }
455 1.1 christos /* Avoid undefined behavior in case of test failure. */
456 1.1 christos if (qs[i] == NULL) {
457 1.1 christos qs[i] = ps[i];
458 1.1 christos }
459 1.1 christos }
460 1.1 christos for (i = 0; i < NTCACHES; i++) {
461 1.1 christos dallocx(qs[i], MALLOCX_TCACHE(tis[i]));
462 1.1 christos }
463 1.1 christos
464 1.1 christos /* Flush some non-empty tcaches. */
465 1.1 christos for (i = 0; i < NTCACHES/2; i++) {
466 1.1.1.1.14.1 perseant expect_d_eq(mallctl("tcache.flush", NULL, NULL, (void *)&tis[i],
467 1.1 christos sizeof(unsigned)), 0, "Unexpected mallctl() failure, i=%u",
468 1.1 christos i);
469 1.1 christos }
470 1.1 christos
471 1.1 christos /* Destroy tcaches. */
472 1.1 christos for (i = 0; i < NTCACHES; i++) {
473 1.1.1.1.14.1 perseant expect_d_eq(mallctl("tcache.destroy", NULL, NULL,
474 1.1 christos (void *)&tis[i], sizeof(unsigned)), 0,
475 1.1 christos "Unexpected mallctl() failure, i=%u", i);
476 1.1 christos }
477 1.1 christos }
478 1.1 christos TEST_END
479 1.1 christos
480 1.1 christos TEST_BEGIN(test_thread_arena) {
481 1.1 christos unsigned old_arena_ind, new_arena_ind, narenas;
482 1.1 christos
483 1.1 christos const char *opa;
484 1.1 christos size_t sz = sizeof(opa);
485 1.1.1.1.14.1 perseant expect_d_eq(mallctl("opt.percpu_arena", (void *)&opa, &sz, NULL, 0), 0,
486 1.1 christos "Unexpected mallctl() failure");
487 1.1 christos
488 1.1 christos sz = sizeof(unsigned);
489 1.1.1.1.14.1 perseant expect_d_eq(mallctl("arenas.narenas", (void *)&narenas, &sz, NULL, 0),
490 1.1 christos 0, "Unexpected mallctl() failure");
491 1.1.1.1.14.1 perseant if (opt_oversize_threshold != 0) {
492 1.1.1.1.14.1 perseant narenas--;
493 1.1.1.1.14.1 perseant }
494 1.1.1.1.14.1 perseant expect_u_eq(narenas, opt_narenas, "Number of arenas incorrect");
495 1.1 christos
496 1.1 christos if (strcmp(opa, "disabled") == 0) {
497 1.1 christos new_arena_ind = narenas - 1;
498 1.1.1.1.14.1 perseant expect_d_eq(mallctl("thread.arena", (void *)&old_arena_ind, &sz,
499 1.1 christos (void *)&new_arena_ind, sizeof(unsigned)), 0,
500 1.1 christos "Unexpected mallctl() failure");
501 1.1 christos new_arena_ind = 0;
502 1.1.1.1.14.1 perseant expect_d_eq(mallctl("thread.arena", (void *)&old_arena_ind, &sz,
503 1.1 christos (void *)&new_arena_ind, sizeof(unsigned)), 0,
504 1.1 christos "Unexpected mallctl() failure");
505 1.1 christos } else {
506 1.1.1.1.14.1 perseant expect_d_eq(mallctl("thread.arena", (void *)&old_arena_ind, &sz,
507 1.1 christos NULL, 0), 0, "Unexpected mallctl() failure");
508 1.1 christos new_arena_ind = percpu_arena_ind_limit(opt_percpu_arena) - 1;
509 1.1 christos if (old_arena_ind != new_arena_ind) {
510 1.1.1.1.14.1 perseant expect_d_eq(mallctl("thread.arena",
511 1.1 christos (void *)&old_arena_ind, &sz, (void *)&new_arena_ind,
512 1.1 christos sizeof(unsigned)), EPERM, "thread.arena ctl "
513 1.1 christos "should not be allowed with percpu arena");
514 1.1 christos }
515 1.1 christos }
516 1.1 christos }
517 1.1 christos TEST_END
518 1.1 christos
519 1.1 christos TEST_BEGIN(test_arena_i_initialized) {
520 1.1 christos unsigned narenas, i;
521 1.1 christos size_t sz;
522 1.1 christos size_t mib[3];
523 1.1 christos size_t miblen = sizeof(mib) / sizeof(size_t);
524 1.1 christos bool initialized;
525 1.1 christos
526 1.1 christos sz = sizeof(narenas);
527 1.1.1.1.14.1 perseant expect_d_eq(mallctl("arenas.narenas", (void *)&narenas, &sz, NULL, 0),
528 1.1 christos 0, "Unexpected mallctl() failure");
529 1.1 christos
530 1.1.1.1.14.1 perseant expect_d_eq(mallctlnametomib("arena.0.initialized", mib, &miblen), 0,
531 1.1 christos "Unexpected mallctlnametomib() failure");
532 1.1 christos for (i = 0; i < narenas; i++) {
533 1.1 christos mib[1] = i;
534 1.1 christos sz = sizeof(initialized);
535 1.1.1.1.14.1 perseant expect_d_eq(mallctlbymib(mib, miblen, &initialized, &sz, NULL,
536 1.1 christos 0), 0, "Unexpected mallctl() failure");
537 1.1 christos }
538 1.1 christos
539 1.1 christos mib[1] = MALLCTL_ARENAS_ALL;
540 1.1 christos sz = sizeof(initialized);
541 1.1.1.1.14.1 perseant expect_d_eq(mallctlbymib(mib, miblen, &initialized, &sz, NULL, 0), 0,
542 1.1 christos "Unexpected mallctl() failure");
543 1.1.1.1.14.1 perseant expect_true(initialized,
544 1.1 christos "Merged arena statistics should always be initialized");
545 1.1 christos
546 1.1 christos /* Equivalent to the above but using mallctl() directly. */
547 1.1 christos sz = sizeof(initialized);
548 1.1.1.1.14.1 perseant expect_d_eq(mallctl(
549 1.1 christos "arena." STRINGIFY(MALLCTL_ARENAS_ALL) ".initialized",
550 1.1 christos (void *)&initialized, &sz, NULL, 0), 0,
551 1.1 christos "Unexpected mallctl() failure");
552 1.1.1.1.14.1 perseant expect_true(initialized,
553 1.1 christos "Merged arena statistics should always be initialized");
554 1.1 christos }
555 1.1 christos TEST_END
556 1.1 christos
557 1.1 christos TEST_BEGIN(test_arena_i_dirty_decay_ms) {
558 1.1 christos ssize_t dirty_decay_ms, orig_dirty_decay_ms, prev_dirty_decay_ms;
559 1.1 christos size_t sz = sizeof(ssize_t);
560 1.1 christos
561 1.1.1.1.14.1 perseant expect_d_eq(mallctl("arena.0.dirty_decay_ms",
562 1.1 christos (void *)&orig_dirty_decay_ms, &sz, NULL, 0), 0,
563 1.1 christos "Unexpected mallctl() failure");
564 1.1 christos
565 1.1 christos dirty_decay_ms = -2;
566 1.1.1.1.14.1 perseant expect_d_eq(mallctl("arena.0.dirty_decay_ms", NULL, NULL,
567 1.1 christos (void *)&dirty_decay_ms, sizeof(ssize_t)), EFAULT,
568 1.1 christos "Unexpected mallctl() success");
569 1.1 christos
570 1.1 christos dirty_decay_ms = 0x7fffffff;
571 1.1.1.1.14.1 perseant expect_d_eq(mallctl("arena.0.dirty_decay_ms", NULL, NULL,
572 1.1 christos (void *)&dirty_decay_ms, sizeof(ssize_t)), 0,
573 1.1 christos "Unexpected mallctl() failure");
574 1.1 christos
575 1.1 christos for (prev_dirty_decay_ms = dirty_decay_ms, dirty_decay_ms = -1;
576 1.1 christos dirty_decay_ms < 20; prev_dirty_decay_ms = dirty_decay_ms,
577 1.1 christos dirty_decay_ms++) {
578 1.1 christos ssize_t old_dirty_decay_ms;
579 1.1 christos
580 1.1.1.1.14.1 perseant expect_d_eq(mallctl("arena.0.dirty_decay_ms",
581 1.1 christos (void *)&old_dirty_decay_ms, &sz, (void *)&dirty_decay_ms,
582 1.1 christos sizeof(ssize_t)), 0, "Unexpected mallctl() failure");
583 1.1.1.1.14.1 perseant expect_zd_eq(old_dirty_decay_ms, prev_dirty_decay_ms,
584 1.1 christos "Unexpected old arena.0.dirty_decay_ms");
585 1.1 christos }
586 1.1 christos }
587 1.1 christos TEST_END
588 1.1 christos
589 1.1 christos TEST_BEGIN(test_arena_i_muzzy_decay_ms) {
590 1.1 christos ssize_t muzzy_decay_ms, orig_muzzy_decay_ms, prev_muzzy_decay_ms;
591 1.1 christos size_t sz = sizeof(ssize_t);
592 1.1 christos
593 1.1.1.1.14.1 perseant expect_d_eq(mallctl("arena.0.muzzy_decay_ms",
594 1.1 christos (void *)&orig_muzzy_decay_ms, &sz, NULL, 0), 0,
595 1.1 christos "Unexpected mallctl() failure");
596 1.1 christos
597 1.1 christos muzzy_decay_ms = -2;
598 1.1.1.1.14.1 perseant expect_d_eq(mallctl("arena.0.muzzy_decay_ms", NULL, NULL,
599 1.1 christos (void *)&muzzy_decay_ms, sizeof(ssize_t)), EFAULT,
600 1.1 christos "Unexpected mallctl() success");
601 1.1 christos
602 1.1 christos muzzy_decay_ms = 0x7fffffff;
603 1.1.1.1.14.1 perseant expect_d_eq(mallctl("arena.0.muzzy_decay_ms", NULL, NULL,
604 1.1 christos (void *)&muzzy_decay_ms, sizeof(ssize_t)), 0,
605 1.1 christos "Unexpected mallctl() failure");
606 1.1 christos
607 1.1 christos for (prev_muzzy_decay_ms = muzzy_decay_ms, muzzy_decay_ms = -1;
608 1.1 christos muzzy_decay_ms < 20; prev_muzzy_decay_ms = muzzy_decay_ms,
609 1.1 christos muzzy_decay_ms++) {
610 1.1 christos ssize_t old_muzzy_decay_ms;
611 1.1 christos
612 1.1.1.1.14.1 perseant expect_d_eq(mallctl("arena.0.muzzy_decay_ms",
613 1.1 christos (void *)&old_muzzy_decay_ms, &sz, (void *)&muzzy_decay_ms,
614 1.1 christos sizeof(ssize_t)), 0, "Unexpected mallctl() failure");
615 1.1.1.1.14.1 perseant expect_zd_eq(old_muzzy_decay_ms, prev_muzzy_decay_ms,
616 1.1 christos "Unexpected old arena.0.muzzy_decay_ms");
617 1.1 christos }
618 1.1 christos }
619 1.1 christos TEST_END
620 1.1 christos
621 1.1 christos TEST_BEGIN(test_arena_i_purge) {
622 1.1 christos unsigned narenas;
623 1.1 christos size_t sz = sizeof(unsigned);
624 1.1 christos size_t mib[3];
625 1.1 christos size_t miblen = 3;
626 1.1 christos
627 1.1.1.1.14.1 perseant expect_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0,
628 1.1 christos "Unexpected mallctl() failure");
629 1.1 christos
630 1.1.1.1.14.1 perseant expect_d_eq(mallctl("arenas.narenas", (void *)&narenas, &sz, NULL, 0),
631 1.1 christos 0, "Unexpected mallctl() failure");
632 1.1.1.1.14.1 perseant expect_d_eq(mallctlnametomib("arena.0.purge", mib, &miblen), 0,
633 1.1 christos "Unexpected mallctlnametomib() failure");
634 1.1 christos mib[1] = narenas;
635 1.1.1.1.14.1 perseant expect_d_eq(mallctlbymib(mib, miblen, NULL, NULL, NULL, 0), 0,
636 1.1 christos "Unexpected mallctlbymib() failure");
637 1.1 christos
638 1.1 christos mib[1] = MALLCTL_ARENAS_ALL;
639 1.1.1.1.14.1 perseant expect_d_eq(mallctlbymib(mib, miblen, NULL, NULL, NULL, 0), 0,
640 1.1 christos "Unexpected mallctlbymib() failure");
641 1.1 christos }
642 1.1 christos TEST_END
643 1.1 christos
644 1.1 christos TEST_BEGIN(test_arena_i_decay) {
645 1.1 christos unsigned narenas;
646 1.1 christos size_t sz = sizeof(unsigned);
647 1.1 christos size_t mib[3];
648 1.1 christos size_t miblen = 3;
649 1.1 christos
650 1.1.1.1.14.1 perseant expect_d_eq(mallctl("arena.0.decay", NULL, NULL, NULL, 0), 0,
651 1.1 christos "Unexpected mallctl() failure");
652 1.1 christos
653 1.1.1.1.14.1 perseant expect_d_eq(mallctl("arenas.narenas", (void *)&narenas, &sz, NULL, 0),
654 1.1 christos 0, "Unexpected mallctl() failure");
655 1.1.1.1.14.1 perseant expect_d_eq(mallctlnametomib("arena.0.decay", mib, &miblen), 0,
656 1.1 christos "Unexpected mallctlnametomib() failure");
657 1.1 christos mib[1] = narenas;
658 1.1.1.1.14.1 perseant expect_d_eq(mallctlbymib(mib, miblen, NULL, NULL, NULL, 0), 0,
659 1.1 christos "Unexpected mallctlbymib() failure");
660 1.1 christos
661 1.1 christos mib[1] = MALLCTL_ARENAS_ALL;
662 1.1.1.1.14.1 perseant expect_d_eq(mallctlbymib(mib, miblen, NULL, NULL, NULL, 0), 0,
663 1.1 christos "Unexpected mallctlbymib() failure");
664 1.1 christos }
665 1.1 christos TEST_END
666 1.1 christos
667 1.1 christos TEST_BEGIN(test_arena_i_dss) {
668 1.1 christos const char *dss_prec_old, *dss_prec_new;
669 1.1 christos size_t sz = sizeof(dss_prec_old);
670 1.1 christos size_t mib[3];
671 1.1 christos size_t miblen;
672 1.1 christos
673 1.1 christos miblen = sizeof(mib)/sizeof(size_t);
674 1.1.1.1.14.1 perseant expect_d_eq(mallctlnametomib("arena.0.dss", mib, &miblen), 0,
675 1.1 christos "Unexpected mallctlnametomib() error");
676 1.1 christos
677 1.1 christos dss_prec_new = "disabled";
678 1.1.1.1.14.1 perseant expect_d_eq(mallctlbymib(mib, miblen, (void *)&dss_prec_old, &sz,
679 1.1 christos (void *)&dss_prec_new, sizeof(dss_prec_new)), 0,
680 1.1 christos "Unexpected mallctl() failure");
681 1.1.1.1.14.1 perseant expect_str_ne(dss_prec_old, "primary",
682 1.1 christos "Unexpected default for dss precedence");
683 1.1 christos
684 1.1.1.1.14.1 perseant expect_d_eq(mallctlbymib(mib, miblen, (void *)&dss_prec_new, &sz,
685 1.1 christos (void *)&dss_prec_old, sizeof(dss_prec_old)), 0,
686 1.1 christos "Unexpected mallctl() failure");
687 1.1 christos
688 1.1.1.1.14.1 perseant expect_d_eq(mallctlbymib(mib, miblen, (void *)&dss_prec_old, &sz, NULL,
689 1.1 christos 0), 0, "Unexpected mallctl() failure");
690 1.1.1.1.14.1 perseant expect_str_ne(dss_prec_old, "primary",
691 1.1 christos "Unexpected value for dss precedence");
692 1.1 christos
693 1.1 christos mib[1] = narenas_total_get();
694 1.1 christos dss_prec_new = "disabled";
695 1.1.1.1.14.1 perseant expect_d_eq(mallctlbymib(mib, miblen, (void *)&dss_prec_old, &sz,
696 1.1 christos (void *)&dss_prec_new, sizeof(dss_prec_new)), 0,
697 1.1 christos "Unexpected mallctl() failure");
698 1.1.1.1.14.1 perseant expect_str_ne(dss_prec_old, "primary",
699 1.1 christos "Unexpected default for dss precedence");
700 1.1 christos
701 1.1.1.1.14.1 perseant expect_d_eq(mallctlbymib(mib, miblen, (void *)&dss_prec_new, &sz,
702 1.1 christos (void *)&dss_prec_old, sizeof(dss_prec_new)), 0,
703 1.1 christos "Unexpected mallctl() failure");
704 1.1 christos
705 1.1.1.1.14.1 perseant expect_d_eq(mallctlbymib(mib, miblen, (void *)&dss_prec_old, &sz, NULL,
706 1.1 christos 0), 0, "Unexpected mallctl() failure");
707 1.1.1.1.14.1 perseant expect_str_ne(dss_prec_old, "primary",
708 1.1 christos "Unexpected value for dss precedence");
709 1.1 christos }
710 1.1 christos TEST_END
711 1.1 christos
712 1.1 christos TEST_BEGIN(test_arena_i_retain_grow_limit) {
713 1.1 christos size_t old_limit, new_limit, default_limit;
714 1.1 christos size_t mib[3];
715 1.1 christos size_t miblen;
716 1.1 christos
717 1.1 christos bool retain_enabled;
718 1.1 christos size_t sz = sizeof(retain_enabled);
719 1.1.1.1.14.1 perseant expect_d_eq(mallctl("opt.retain", &retain_enabled, &sz, NULL, 0),
720 1.1 christos 0, "Unexpected mallctl() failure");
721 1.1 christos test_skip_if(!retain_enabled);
722 1.1 christos
723 1.1 christos sz = sizeof(default_limit);
724 1.1 christos miblen = sizeof(mib)/sizeof(size_t);
725 1.1.1.1.14.1 perseant expect_d_eq(mallctlnametomib("arena.0.retain_grow_limit", mib, &miblen),
726 1.1 christos 0, "Unexpected mallctlnametomib() error");
727 1.1 christos
728 1.1.1.1.14.1 perseant expect_d_eq(mallctlbymib(mib, miblen, &default_limit, &sz, NULL, 0), 0,
729 1.1 christos "Unexpected mallctl() failure");
730 1.1.1.1.14.1 perseant expect_zu_eq(default_limit, SC_LARGE_MAXCLASS,
731 1.1 christos "Unexpected default for retain_grow_limit");
732 1.1 christos
733 1.1 christos new_limit = PAGE - 1;
734 1.1.1.1.14.1 perseant expect_d_eq(mallctlbymib(mib, miblen, NULL, NULL, &new_limit,
735 1.1 christos sizeof(new_limit)), EFAULT, "Unexpected mallctl() success");
736 1.1 christos
737 1.1 christos new_limit = PAGE + 1;
738 1.1.1.1.14.1 perseant expect_d_eq(mallctlbymib(mib, miblen, NULL, NULL, &new_limit,
739 1.1 christos sizeof(new_limit)), 0, "Unexpected mallctl() failure");
740 1.1.1.1.14.1 perseant expect_d_eq(mallctlbymib(mib, miblen, &old_limit, &sz, NULL, 0), 0,
741 1.1 christos "Unexpected mallctl() failure");
742 1.1.1.1.14.1 perseant expect_zu_eq(old_limit, PAGE,
743 1.1 christos "Unexpected value for retain_grow_limit");
744 1.1 christos
745 1.1 christos /* Expect grow less than psize class 10. */
746 1.1 christos new_limit = sz_pind2sz(10) - 1;
747 1.1.1.1.14.1 perseant expect_d_eq(mallctlbymib(mib, miblen, NULL, NULL, &new_limit,
748 1.1 christos sizeof(new_limit)), 0, "Unexpected mallctl() failure");
749 1.1.1.1.14.1 perseant expect_d_eq(mallctlbymib(mib, miblen, &old_limit, &sz, NULL, 0), 0,
750 1.1 christos "Unexpected mallctl() failure");
751 1.1.1.1.14.1 perseant expect_zu_eq(old_limit, sz_pind2sz(9),
752 1.1 christos "Unexpected value for retain_grow_limit");
753 1.1 christos
754 1.1 christos /* Restore to default. */
755 1.1.1.1.14.1 perseant expect_d_eq(mallctlbymib(mib, miblen, NULL, NULL, &default_limit,
756 1.1 christos sizeof(default_limit)), 0, "Unexpected mallctl() failure");
757 1.1 christos }
758 1.1 christos TEST_END
759 1.1 christos
760 1.1 christos TEST_BEGIN(test_arenas_dirty_decay_ms) {
761 1.1 christos ssize_t dirty_decay_ms, orig_dirty_decay_ms, prev_dirty_decay_ms;
762 1.1 christos size_t sz = sizeof(ssize_t);
763 1.1 christos
764 1.1.1.1.14.1 perseant expect_d_eq(mallctl("arenas.dirty_decay_ms",
765 1.1 christos (void *)&orig_dirty_decay_ms, &sz, NULL, 0), 0,
766 1.1 christos "Unexpected mallctl() failure");
767 1.1 christos
768 1.1 christos dirty_decay_ms = -2;
769 1.1.1.1.14.1 perseant expect_d_eq(mallctl("arenas.dirty_decay_ms", NULL, NULL,
770 1.1 christos (void *)&dirty_decay_ms, sizeof(ssize_t)), EFAULT,
771 1.1 christos "Unexpected mallctl() success");
772 1.1 christos
773 1.1 christos dirty_decay_ms = 0x7fffffff;
774 1.1.1.1.14.1 perseant expect_d_eq(mallctl("arenas.dirty_decay_ms", NULL, NULL,
775 1.1 christos (void *)&dirty_decay_ms, sizeof(ssize_t)), 0,
776 1.1 christos "Expected mallctl() failure");
777 1.1 christos
778 1.1 christos for (prev_dirty_decay_ms = dirty_decay_ms, dirty_decay_ms = -1;
779 1.1 christos dirty_decay_ms < 20; prev_dirty_decay_ms = dirty_decay_ms,
780 1.1 christos dirty_decay_ms++) {
781 1.1 christos ssize_t old_dirty_decay_ms;
782 1.1 christos
783 1.1.1.1.14.1 perseant expect_d_eq(mallctl("arenas.dirty_decay_ms",
784 1.1 christos (void *)&old_dirty_decay_ms, &sz, (void *)&dirty_decay_ms,
785 1.1 christos sizeof(ssize_t)), 0, "Unexpected mallctl() failure");
786 1.1.1.1.14.1 perseant expect_zd_eq(old_dirty_decay_ms, prev_dirty_decay_ms,
787 1.1 christos "Unexpected old arenas.dirty_decay_ms");
788 1.1 christos }
789 1.1 christos }
790 1.1 christos TEST_END
791 1.1 christos
792 1.1 christos TEST_BEGIN(test_arenas_muzzy_decay_ms) {
793 1.1 christos ssize_t muzzy_decay_ms, orig_muzzy_decay_ms, prev_muzzy_decay_ms;
794 1.1 christos size_t sz = sizeof(ssize_t);
795 1.1 christos
796 1.1.1.1.14.1 perseant expect_d_eq(mallctl("arenas.muzzy_decay_ms",
797 1.1 christos (void *)&orig_muzzy_decay_ms, &sz, NULL, 0), 0,
798 1.1 christos "Unexpected mallctl() failure");
799 1.1 christos
800 1.1 christos muzzy_decay_ms = -2;
801 1.1.1.1.14.1 perseant expect_d_eq(mallctl("arenas.muzzy_decay_ms", NULL, NULL,
802 1.1 christos (void *)&muzzy_decay_ms, sizeof(ssize_t)), EFAULT,
803 1.1 christos "Unexpected mallctl() success");
804 1.1 christos
805 1.1 christos muzzy_decay_ms = 0x7fffffff;
806 1.1.1.1.14.1 perseant expect_d_eq(mallctl("arenas.muzzy_decay_ms", NULL, NULL,
807 1.1 christos (void *)&muzzy_decay_ms, sizeof(ssize_t)), 0,
808 1.1 christos "Expected mallctl() failure");
809 1.1 christos
810 1.1 christos for (prev_muzzy_decay_ms = muzzy_decay_ms, muzzy_decay_ms = -1;
811 1.1 christos muzzy_decay_ms < 20; prev_muzzy_decay_ms = muzzy_decay_ms,
812 1.1 christos muzzy_decay_ms++) {
813 1.1 christos ssize_t old_muzzy_decay_ms;
814 1.1 christos
815 1.1.1.1.14.1 perseant expect_d_eq(mallctl("arenas.muzzy_decay_ms",
816 1.1 christos (void *)&old_muzzy_decay_ms, &sz, (void *)&muzzy_decay_ms,
817 1.1 christos sizeof(ssize_t)), 0, "Unexpected mallctl() failure");
818 1.1.1.1.14.1 perseant expect_zd_eq(old_muzzy_decay_ms, prev_muzzy_decay_ms,
819 1.1 christos "Unexpected old arenas.muzzy_decay_ms");
820 1.1 christos }
821 1.1 christos }
822 1.1 christos TEST_END
823 1.1 christos
824 1.1 christos TEST_BEGIN(test_arenas_constants) {
825 1.1 christos #define TEST_ARENAS_CONSTANT(t, name, expected) do { \
826 1.1 christos t name; \
827 1.1 christos size_t sz = sizeof(t); \
828 1.1.1.1.14.1 perseant expect_d_eq(mallctl("arenas."#name, (void *)&name, &sz, NULL, \
829 1.1 christos 0), 0, "Unexpected mallctl() failure"); \
830 1.1.1.1.14.1 perseant expect_zu_eq(name, expected, "Incorrect "#name" size"); \
831 1.1 christos } while (0)
832 1.1 christos
833 1.1 christos TEST_ARENAS_CONSTANT(size_t, quantum, QUANTUM);
834 1.1 christos TEST_ARENAS_CONSTANT(size_t, page, PAGE);
835 1.1.1.1.14.1 perseant TEST_ARENAS_CONSTANT(unsigned, nbins, SC_NBINS);
836 1.1.1.1.14.1 perseant TEST_ARENAS_CONSTANT(unsigned, nlextents, SC_NSIZES - SC_NBINS);
837 1.1 christos
838 1.1 christos #undef TEST_ARENAS_CONSTANT
839 1.1 christos }
840 1.1 christos TEST_END
841 1.1 christos
842 1.1 christos TEST_BEGIN(test_arenas_bin_constants) {
843 1.1 christos #define TEST_ARENAS_BIN_CONSTANT(t, name, expected) do { \
844 1.1 christos t name; \
845 1.1 christos size_t sz = sizeof(t); \
846 1.1.1.1.14.1 perseant expect_d_eq(mallctl("arenas.bin.0."#name, (void *)&name, &sz, \
847 1.1 christos NULL, 0), 0, "Unexpected mallctl() failure"); \
848 1.1.1.1.14.1 perseant expect_zu_eq(name, expected, "Incorrect "#name" size"); \
849 1.1 christos } while (0)
850 1.1 christos
851 1.1 christos TEST_ARENAS_BIN_CONSTANT(size_t, size, bin_infos[0].reg_size);
852 1.1 christos TEST_ARENAS_BIN_CONSTANT(uint32_t, nregs, bin_infos[0].nregs);
853 1.1 christos TEST_ARENAS_BIN_CONSTANT(size_t, slab_size,
854 1.1 christos bin_infos[0].slab_size);
855 1.1.1.1.14.1 perseant TEST_ARENAS_BIN_CONSTANT(uint32_t, nshards, bin_infos[0].n_shards);
856 1.1 christos
857 1.1 christos #undef TEST_ARENAS_BIN_CONSTANT
858 1.1 christos }
859 1.1 christos TEST_END
860 1.1 christos
861 1.1 christos TEST_BEGIN(test_arenas_lextent_constants) {
862 1.1 christos #define TEST_ARENAS_LEXTENT_CONSTANT(t, name, expected) do { \
863 1.1 christos t name; \
864 1.1 christos size_t sz = sizeof(t); \
865 1.1.1.1.14.1 perseant expect_d_eq(mallctl("arenas.lextent.0."#name, (void *)&name, \
866 1.1 christos &sz, NULL, 0), 0, "Unexpected mallctl() failure"); \
867 1.1.1.1.14.1 perseant expect_zu_eq(name, expected, "Incorrect "#name" size"); \
868 1.1 christos } while (0)
869 1.1 christos
870 1.1.1.1.14.1 perseant TEST_ARENAS_LEXTENT_CONSTANT(size_t, size,
871 1.1.1.1.14.1 perseant SC_LARGE_MINCLASS);
872 1.1 christos
873 1.1 christos #undef TEST_ARENAS_LEXTENT_CONSTANT
874 1.1 christos }
875 1.1 christos TEST_END
876 1.1 christos
877 1.1 christos TEST_BEGIN(test_arenas_create) {
878 1.1 christos unsigned narenas_before, arena, narenas_after;
879 1.1 christos size_t sz = sizeof(unsigned);
880 1.1 christos
881 1.1.1.1.14.1 perseant expect_d_eq(mallctl("arenas.narenas", (void *)&narenas_before, &sz,
882 1.1 christos NULL, 0), 0, "Unexpected mallctl() failure");
883 1.1.1.1.14.1 perseant expect_d_eq(mallctl("arenas.create", (void *)&arena, &sz, NULL, 0), 0,
884 1.1 christos "Unexpected mallctl() failure");
885 1.1.1.1.14.1 perseant expect_d_eq(mallctl("arenas.narenas", (void *)&narenas_after, &sz, NULL,
886 1.1 christos 0), 0, "Unexpected mallctl() failure");
887 1.1 christos
888 1.1.1.1.14.1 perseant expect_u_eq(narenas_before+1, narenas_after,
889 1.1 christos "Unexpected number of arenas before versus after extension");
890 1.1.1.1.14.1 perseant expect_u_eq(arena, narenas_after-1, "Unexpected arena index");
891 1.1 christos }
892 1.1 christos TEST_END
893 1.1 christos
894 1.1 christos TEST_BEGIN(test_arenas_lookup) {
895 1.1 christos unsigned arena, arena1;
896 1.1 christos void *ptr;
897 1.1 christos size_t sz = sizeof(unsigned);
898 1.1 christos
899 1.1.1.1.14.1 perseant expect_d_eq(mallctl("arenas.create", (void *)&arena, &sz, NULL, 0), 0,
900 1.1 christos "Unexpected mallctl() failure");
901 1.1 christos ptr = mallocx(42, MALLOCX_ARENA(arena) | MALLOCX_TCACHE_NONE);
902 1.1.1.1.14.1 perseant expect_ptr_not_null(ptr, "Unexpected mallocx() failure");
903 1.1.1.1.14.1 perseant expect_d_eq(mallctl("arenas.lookup", &arena1, &sz, &ptr, sizeof(ptr)),
904 1.1 christos 0, "Unexpected mallctl() failure");
905 1.1.1.1.14.1 perseant expect_u_eq(arena, arena1, "Unexpected arena index");
906 1.1 christos dallocx(ptr, 0);
907 1.1 christos }
908 1.1 christos TEST_END
909 1.1 christos
910 1.1.1.1.14.1 perseant TEST_BEGIN(test_prof_active) {
911 1.1.1.1.14.1 perseant /*
912 1.1.1.1.14.1 perseant * If config_prof is off, then the test for prof_active in
913 1.1.1.1.14.1 perseant * test_mallctl_opt was already enough.
914 1.1.1.1.14.1 perseant */
915 1.1.1.1.14.1 perseant test_skip_if(!config_prof);
916 1.1.1.1.14.1 perseant test_skip_if(opt_prof);
917 1.1.1.1.14.1 perseant
918 1.1.1.1.14.1 perseant bool active, old;
919 1.1.1.1.14.1 perseant size_t len = sizeof(bool);
920 1.1.1.1.14.1 perseant
921 1.1.1.1.14.1 perseant active = true;
922 1.1.1.1.14.1 perseant expect_d_eq(mallctl("prof.active", NULL, NULL, &active, len), ENOENT,
923 1.1.1.1.14.1 perseant "Setting prof_active to true should fail when opt_prof is off");
924 1.1.1.1.14.1 perseant old = true;
925 1.1.1.1.14.1 perseant expect_d_eq(mallctl("prof.active", &old, &len, &active, len), ENOENT,
926 1.1.1.1.14.1 perseant "Setting prof_active to true should fail when opt_prof is off");
927 1.1.1.1.14.1 perseant expect_true(old, "old value should not be touched when mallctl fails");
928 1.1.1.1.14.1 perseant active = false;
929 1.1.1.1.14.1 perseant expect_d_eq(mallctl("prof.active", NULL, NULL, &active, len), 0,
930 1.1.1.1.14.1 perseant "Setting prof_active to false should succeed when opt_prof is off");
931 1.1.1.1.14.1 perseant expect_d_eq(mallctl("prof.active", &old, &len, &active, len), 0,
932 1.1.1.1.14.1 perseant "Setting prof_active to false should succeed when opt_prof is off");
933 1.1.1.1.14.1 perseant expect_false(old, "prof_active should be false when opt_prof is off");
934 1.1.1.1.14.1 perseant }
935 1.1.1.1.14.1 perseant TEST_END
936 1.1.1.1.14.1 perseant
937 1.1 christos TEST_BEGIN(test_stats_arenas) {
938 1.1 christos #define TEST_STATS_ARENAS(t, name) do { \
939 1.1 christos t name; \
940 1.1 christos size_t sz = sizeof(t); \
941 1.1.1.1.14.1 perseant expect_d_eq(mallctl("stats.arenas.0."#name, (void *)&name, &sz, \
942 1.1 christos NULL, 0), 0, "Unexpected mallctl() failure"); \
943 1.1 christos } while (0)
944 1.1 christos
945 1.1 christos TEST_STATS_ARENAS(unsigned, nthreads);
946 1.1 christos TEST_STATS_ARENAS(const char *, dss);
947 1.1 christos TEST_STATS_ARENAS(ssize_t, dirty_decay_ms);
948 1.1 christos TEST_STATS_ARENAS(ssize_t, muzzy_decay_ms);
949 1.1 christos TEST_STATS_ARENAS(size_t, pactive);
950 1.1 christos TEST_STATS_ARENAS(size_t, pdirty);
951 1.1 christos
952 1.1 christos #undef TEST_STATS_ARENAS
953 1.1 christos }
954 1.1 christos TEST_END
955 1.1 christos
956 1.1.1.1.14.1 perseant static void
957 1.1.1.1.14.1 perseant alloc_hook(void *extra, UNUSED hook_alloc_t type, UNUSED void *result,
958 1.1.1.1.14.1 perseant UNUSED uintptr_t result_raw, UNUSED uintptr_t args_raw[3]) {
959 1.1.1.1.14.1 perseant *(bool *)extra = true;
960 1.1.1.1.14.1 perseant }
961 1.1.1.1.14.1 perseant
962 1.1.1.1.14.1 perseant static void
963 1.1.1.1.14.1 perseant dalloc_hook(void *extra, UNUSED hook_dalloc_t type,
964 1.1.1.1.14.1 perseant UNUSED void *address, UNUSED uintptr_t args_raw[3]) {
965 1.1.1.1.14.1 perseant *(bool *)extra = true;
966 1.1.1.1.14.1 perseant }
967 1.1.1.1.14.1 perseant
968 1.1.1.1.14.1 perseant TEST_BEGIN(test_hooks) {
969 1.1.1.1.14.1 perseant bool hook_called = false;
970 1.1.1.1.14.1 perseant hooks_t hooks = {&alloc_hook, &dalloc_hook, NULL, &hook_called};
971 1.1.1.1.14.1 perseant void *handle = NULL;
972 1.1.1.1.14.1 perseant size_t sz = sizeof(handle);
973 1.1.1.1.14.1 perseant int err = mallctl("experimental.hooks.install", &handle, &sz, &hooks,
974 1.1.1.1.14.1 perseant sizeof(hooks));
975 1.1.1.1.14.1 perseant expect_d_eq(err, 0, "Hook installation failed");
976 1.1.1.1.14.1 perseant expect_ptr_ne(handle, NULL, "Hook installation gave null handle");
977 1.1.1.1.14.1 perseant void *ptr = mallocx(1, 0);
978 1.1.1.1.14.1 perseant expect_true(hook_called, "Alloc hook not called");
979 1.1.1.1.14.1 perseant hook_called = false;
980 1.1.1.1.14.1 perseant free(ptr);
981 1.1.1.1.14.1 perseant expect_true(hook_called, "Free hook not called");
982 1.1.1.1.14.1 perseant
983 1.1.1.1.14.1 perseant err = mallctl("experimental.hooks.remove", NULL, NULL, &handle,
984 1.1.1.1.14.1 perseant sizeof(handle));
985 1.1.1.1.14.1 perseant expect_d_eq(err, 0, "Hook removal failed");
986 1.1.1.1.14.1 perseant hook_called = false;
987 1.1.1.1.14.1 perseant ptr = mallocx(1, 0);
988 1.1.1.1.14.1 perseant free(ptr);
989 1.1.1.1.14.1 perseant expect_false(hook_called, "Hook called after removal");
990 1.1.1.1.14.1 perseant }
991 1.1.1.1.14.1 perseant TEST_END
992 1.1.1.1.14.1 perseant
993 1.1.1.1.14.1 perseant TEST_BEGIN(test_hooks_exhaustion) {
994 1.1.1.1.14.1 perseant bool hook_called = false;
995 1.1.1.1.14.1 perseant hooks_t hooks = {&alloc_hook, &dalloc_hook, NULL, &hook_called};
996 1.1.1.1.14.1 perseant
997 1.1.1.1.14.1 perseant void *handle;
998 1.1.1.1.14.1 perseant void *handles[HOOK_MAX];
999 1.1.1.1.14.1 perseant size_t sz = sizeof(handle);
1000 1.1.1.1.14.1 perseant int err;
1001 1.1.1.1.14.1 perseant for (int i = 0; i < HOOK_MAX; i++) {
1002 1.1.1.1.14.1 perseant handle = NULL;
1003 1.1.1.1.14.1 perseant err = mallctl("experimental.hooks.install", &handle, &sz,
1004 1.1.1.1.14.1 perseant &hooks, sizeof(hooks));
1005 1.1.1.1.14.1 perseant expect_d_eq(err, 0, "Error installation hooks");
1006 1.1.1.1.14.1 perseant expect_ptr_ne(handle, NULL, "Got NULL handle");
1007 1.1.1.1.14.1 perseant handles[i] = handle;
1008 1.1.1.1.14.1 perseant }
1009 1.1.1.1.14.1 perseant err = mallctl("experimental.hooks.install", &handle, &sz, &hooks,
1010 1.1.1.1.14.1 perseant sizeof(hooks));
1011 1.1.1.1.14.1 perseant expect_d_eq(err, EAGAIN, "Should have failed hook installation");
1012 1.1.1.1.14.1 perseant for (int i = 0; i < HOOK_MAX; i++) {
1013 1.1.1.1.14.1 perseant err = mallctl("experimental.hooks.remove", NULL, NULL,
1014 1.1.1.1.14.1 perseant &handles[i], sizeof(handles[i]));
1015 1.1.1.1.14.1 perseant expect_d_eq(err, 0, "Hook removal failed");
1016 1.1.1.1.14.1 perseant }
1017 1.1.1.1.14.1 perseant /* Insertion failed, but then we removed some; it should work now. */
1018 1.1.1.1.14.1 perseant handle = NULL;
1019 1.1.1.1.14.1 perseant err = mallctl("experimental.hooks.install", &handle, &sz, &hooks,
1020 1.1.1.1.14.1 perseant sizeof(hooks));
1021 1.1.1.1.14.1 perseant expect_d_eq(err, 0, "Hook insertion failed");
1022 1.1.1.1.14.1 perseant expect_ptr_ne(handle, NULL, "Got NULL handle");
1023 1.1.1.1.14.1 perseant err = mallctl("experimental.hooks.remove", NULL, NULL, &handle,
1024 1.1.1.1.14.1 perseant sizeof(handle));
1025 1.1.1.1.14.1 perseant expect_d_eq(err, 0, "Hook removal failed");
1026 1.1.1.1.14.1 perseant }
1027 1.1.1.1.14.1 perseant TEST_END
1028 1.1.1.1.14.1 perseant
1029 1.1.1.1.14.1 perseant TEST_BEGIN(test_thread_idle) {
1030 1.1.1.1.14.1 perseant /*
1031 1.1.1.1.14.1 perseant * We're cheating a little bit in this test, and inferring things about
1032 1.1.1.1.14.1 perseant * implementation internals (like tcache details). We have to;
1033 1.1.1.1.14.1 perseant * thread.idle has no guaranteed effects. We need stats to make these
1034 1.1.1.1.14.1 perseant * inferences.
1035 1.1.1.1.14.1 perseant */
1036 1.1.1.1.14.1 perseant test_skip_if(!config_stats);
1037 1.1.1.1.14.1 perseant
1038 1.1.1.1.14.1 perseant int err;
1039 1.1.1.1.14.1 perseant size_t sz;
1040 1.1.1.1.14.1 perseant size_t miblen;
1041 1.1.1.1.14.1 perseant
1042 1.1.1.1.14.1 perseant bool tcache_enabled = false;
1043 1.1.1.1.14.1 perseant sz = sizeof(tcache_enabled);
1044 1.1.1.1.14.1 perseant err = mallctl("thread.tcache.enabled", &tcache_enabled, &sz, NULL, 0);
1045 1.1.1.1.14.1 perseant expect_d_eq(err, 0, "");
1046 1.1.1.1.14.1 perseant test_skip_if(!tcache_enabled);
1047 1.1.1.1.14.1 perseant
1048 1.1.1.1.14.1 perseant size_t tcache_max;
1049 1.1.1.1.14.1 perseant sz = sizeof(tcache_max);
1050 1.1.1.1.14.1 perseant err = mallctl("arenas.tcache_max", &tcache_max, &sz, NULL, 0);
1051 1.1.1.1.14.1 perseant expect_d_eq(err, 0, "");
1052 1.1.1.1.14.1 perseant test_skip_if(tcache_max == 0);
1053 1.1.1.1.14.1 perseant
1054 1.1.1.1.14.1 perseant unsigned arena_ind;
1055 1.1.1.1.14.1 perseant sz = sizeof(arena_ind);
1056 1.1.1.1.14.1 perseant err = mallctl("thread.arena", &arena_ind, &sz, NULL, 0);
1057 1.1.1.1.14.1 perseant expect_d_eq(err, 0, "");
1058 1.1.1.1.14.1 perseant
1059 1.1.1.1.14.1 perseant /* We're going to do an allocation of size 1, which we know is small. */
1060 1.1.1.1.14.1 perseant size_t mib[5];
1061 1.1.1.1.14.1 perseant miblen = sizeof(mib)/sizeof(mib[0]);
1062 1.1.1.1.14.1 perseant err = mallctlnametomib("stats.arenas.0.small.ndalloc", mib, &miblen);
1063 1.1.1.1.14.1 perseant expect_d_eq(err, 0, "");
1064 1.1.1.1.14.1 perseant mib[2] = arena_ind;
1065 1.1.1.1.14.1 perseant
1066 1.1.1.1.14.1 perseant /*
1067 1.1.1.1.14.1 perseant * This alloc and dalloc should leave something in the tcache, in a
1068 1.1.1.1.14.1 perseant * small size's cache bin.
1069 1.1.1.1.14.1 perseant */
1070 1.1.1.1.14.1 perseant void *ptr = mallocx(1, 0);
1071 1.1.1.1.14.1 perseant dallocx(ptr, 0);
1072 1.1.1.1.14.1 perseant
1073 1.1.1.1.14.1 perseant uint64_t epoch;
1074 1.1.1.1.14.1 perseant err = mallctl("epoch", NULL, NULL, &epoch, sizeof(epoch));
1075 1.1.1.1.14.1 perseant expect_d_eq(err, 0, "");
1076 1.1.1.1.14.1 perseant
1077 1.1.1.1.14.1 perseant uint64_t small_dalloc_pre_idle;
1078 1.1.1.1.14.1 perseant sz = sizeof(small_dalloc_pre_idle);
1079 1.1.1.1.14.1 perseant err = mallctlbymib(mib, miblen, &small_dalloc_pre_idle, &sz, NULL, 0);
1080 1.1.1.1.14.1 perseant expect_d_eq(err, 0, "");
1081 1.1.1.1.14.1 perseant
1082 1.1.1.1.14.1 perseant err = mallctl("thread.idle", NULL, NULL, NULL, 0);
1083 1.1.1.1.14.1 perseant expect_d_eq(err, 0, "");
1084 1.1.1.1.14.1 perseant
1085 1.1.1.1.14.1 perseant err = mallctl("epoch", NULL, NULL, &epoch, sizeof(epoch));
1086 1.1.1.1.14.1 perseant expect_d_eq(err, 0, "");
1087 1.1.1.1.14.1 perseant
1088 1.1.1.1.14.1 perseant uint64_t small_dalloc_post_idle;
1089 1.1.1.1.14.1 perseant sz = sizeof(small_dalloc_post_idle);
1090 1.1.1.1.14.1 perseant err = mallctlbymib(mib, miblen, &small_dalloc_post_idle, &sz, NULL, 0);
1091 1.1.1.1.14.1 perseant expect_d_eq(err, 0, "");
1092 1.1.1.1.14.1 perseant
1093 1.1.1.1.14.1 perseant expect_u64_lt(small_dalloc_pre_idle, small_dalloc_post_idle,
1094 1.1.1.1.14.1 perseant "Purge didn't flush the tcache");
1095 1.1.1.1.14.1 perseant }
1096 1.1.1.1.14.1 perseant TEST_END
1097 1.1.1.1.14.1 perseant
1098 1.1.1.1.14.1 perseant TEST_BEGIN(test_thread_peak) {
1099 1.1.1.1.14.1 perseant test_skip_if(!config_stats);
1100 1.1.1.1.14.1 perseant
1101 1.1.1.1.14.1 perseant /*
1102 1.1.1.1.14.1 perseant * We don't commit to any stable amount of accuracy for peak tracking
1103 1.1.1.1.14.1 perseant * (in practice, when this test was written, we made sure to be within
1104 1.1.1.1.14.1 perseant * 100k). But 10MB is big for more or less any definition of big.
1105 1.1.1.1.14.1 perseant */
1106 1.1.1.1.14.1 perseant size_t big_size = 10 * 1024 * 1024;
1107 1.1.1.1.14.1 perseant size_t small_size = 256;
1108 1.1.1.1.14.1 perseant
1109 1.1.1.1.14.1 perseant void *ptr;
1110 1.1.1.1.14.1 perseant int err;
1111 1.1.1.1.14.1 perseant size_t sz;
1112 1.1.1.1.14.1 perseant uint64_t peak;
1113 1.1.1.1.14.1 perseant sz = sizeof(uint64_t);
1114 1.1.1.1.14.1 perseant
1115 1.1.1.1.14.1 perseant err = mallctl("thread.peak.reset", NULL, NULL, NULL, 0);
1116 1.1.1.1.14.1 perseant expect_d_eq(err, 0, "");
1117 1.1.1.1.14.1 perseant ptr = mallocx(SC_SMALL_MAXCLASS, 0);
1118 1.1.1.1.14.1 perseant err = mallctl("thread.peak.read", &peak, &sz, NULL, 0);
1119 1.1.1.1.14.1 perseant expect_d_eq(err, 0, "");
1120 1.1.1.1.14.1 perseant expect_u64_eq(peak, SC_SMALL_MAXCLASS, "Missed an update");
1121 1.1.1.1.14.1 perseant free(ptr);
1122 1.1.1.1.14.1 perseant err = mallctl("thread.peak.read", &peak, &sz, NULL, 0);
1123 1.1.1.1.14.1 perseant expect_d_eq(err, 0, "");
1124 1.1.1.1.14.1 perseant expect_u64_eq(peak, SC_SMALL_MAXCLASS, "Freeing changed peak");
1125 1.1.1.1.14.1 perseant ptr = mallocx(big_size, 0);
1126 1.1.1.1.14.1 perseant free(ptr);
1127 1.1.1.1.14.1 perseant /*
1128 1.1.1.1.14.1 perseant * The peak should have hit big_size in the last two lines, even though
1129 1.1.1.1.14.1 perseant * the net allocated bytes has since dropped back down to zero. We
1130 1.1.1.1.14.1 perseant * should have noticed the peak change without having down any mallctl
1131 1.1.1.1.14.1 perseant * calls while net allocated bytes was high.
1132 1.1.1.1.14.1 perseant */
1133 1.1.1.1.14.1 perseant err = mallctl("thread.peak.read", &peak, &sz, NULL, 0);
1134 1.1.1.1.14.1 perseant expect_d_eq(err, 0, "");
1135 1.1.1.1.14.1 perseant expect_u64_ge(peak, big_size, "Missed a peak change.");
1136 1.1.1.1.14.1 perseant
1137 1.1.1.1.14.1 perseant /* Allocate big_size, but using small allocations. */
1138 1.1.1.1.14.1 perseant size_t nallocs = big_size / small_size;
1139 1.1.1.1.14.1 perseant void **ptrs = calloc(nallocs, sizeof(void *));
1140 1.1.1.1.14.1 perseant err = mallctl("thread.peak.reset", NULL, NULL, NULL, 0);
1141 1.1.1.1.14.1 perseant expect_d_eq(err, 0, "");
1142 1.1.1.1.14.1 perseant err = mallctl("thread.peak.read", &peak, &sz, NULL, 0);
1143 1.1.1.1.14.1 perseant expect_d_eq(err, 0, "");
1144 1.1.1.1.14.1 perseant expect_u64_eq(0, peak, "Missed a reset.");
1145 1.1.1.1.14.1 perseant for (size_t i = 0; i < nallocs; i++) {
1146 1.1.1.1.14.1 perseant ptrs[i] = mallocx(small_size, 0);
1147 1.1.1.1.14.1 perseant }
1148 1.1.1.1.14.1 perseant for (size_t i = 0; i < nallocs; i++) {
1149 1.1.1.1.14.1 perseant free(ptrs[i]);
1150 1.1.1.1.14.1 perseant }
1151 1.1.1.1.14.1 perseant err = mallctl("thread.peak.read", &peak, &sz, NULL, 0);
1152 1.1.1.1.14.1 perseant expect_d_eq(err, 0, "");
1153 1.1.1.1.14.1 perseant /*
1154 1.1.1.1.14.1 perseant * We don't guarantee exactness; make sure we're within 10% of the peak,
1155 1.1.1.1.14.1 perseant * though.
1156 1.1.1.1.14.1 perseant */
1157 1.1.1.1.14.1 perseant expect_u64_ge(peak, nallocx(small_size, 0) * nallocs * 9 / 10,
1158 1.1.1.1.14.1 perseant "Missed some peak changes.");
1159 1.1.1.1.14.1 perseant expect_u64_le(peak, nallocx(small_size, 0) * nallocs * 11 / 10,
1160 1.1.1.1.14.1 perseant "Overcounted peak changes.");
1161 1.1.1.1.14.1 perseant free(ptrs);
1162 1.1.1.1.14.1 perseant }
1163 1.1.1.1.14.1 perseant TEST_END
1164 1.1.1.1.14.1 perseant
1165 1.1.1.1.14.1 perseant typedef struct activity_test_data_s activity_test_data_t;
1166 1.1.1.1.14.1 perseant struct activity_test_data_s {
1167 1.1.1.1.14.1 perseant uint64_t obtained_alloc;
1168 1.1.1.1.14.1 perseant uint64_t obtained_dalloc;
1169 1.1.1.1.14.1 perseant };
1170 1.1.1.1.14.1 perseant
1171 1.1.1.1.14.1 perseant static void
1172 1.1.1.1.14.1 perseant activity_test_callback(void *uctx, uint64_t alloc, uint64_t dalloc) {
1173 1.1.1.1.14.1 perseant activity_test_data_t *test_data = (activity_test_data_t *)uctx;
1174 1.1.1.1.14.1 perseant test_data->obtained_alloc = alloc;
1175 1.1.1.1.14.1 perseant test_data->obtained_dalloc = dalloc;
1176 1.1.1.1.14.1 perseant }
1177 1.1.1.1.14.1 perseant
1178 1.1.1.1.14.1 perseant TEST_BEGIN(test_thread_activity_callback) {
1179 1.1.1.1.14.1 perseant test_skip_if(!config_stats);
1180 1.1.1.1.14.1 perseant
1181 1.1.1.1.14.1 perseant const size_t big_size = 10 * 1024 * 1024;
1182 1.1.1.1.14.1 perseant void *ptr;
1183 1.1.1.1.14.1 perseant int err;
1184 1.1.1.1.14.1 perseant size_t sz;
1185 1.1.1.1.14.1 perseant
1186 1.1.1.1.14.1 perseant uint64_t *allocatedp;
1187 1.1.1.1.14.1 perseant uint64_t *deallocatedp;
1188 1.1.1.1.14.1 perseant sz = sizeof(allocatedp);
1189 1.1.1.1.14.1 perseant err = mallctl("thread.allocatedp", &allocatedp, &sz, NULL, 0);
1190 1.1.1.1.14.1 perseant assert_d_eq(0, err, "");
1191 1.1.1.1.14.1 perseant err = mallctl("thread.deallocatedp", &deallocatedp, &sz, NULL, 0);
1192 1.1.1.1.14.1 perseant assert_d_eq(0, err, "");
1193 1.1.1.1.14.1 perseant
1194 1.1.1.1.14.1 perseant activity_callback_thunk_t old_thunk = {(activity_callback_t)111,
1195 1.1.1.1.14.1 perseant (void *)222};
1196 1.1.1.1.14.1 perseant
1197 1.1.1.1.14.1 perseant activity_test_data_t test_data = {333, 444};
1198 1.1.1.1.14.1 perseant activity_callback_thunk_t new_thunk =
1199 1.1.1.1.14.1 perseant {&activity_test_callback, &test_data};
1200 1.1.1.1.14.1 perseant
1201 1.1.1.1.14.1 perseant sz = sizeof(old_thunk);
1202 1.1.1.1.14.1 perseant err = mallctl("experimental.thread.activity_callback", &old_thunk, &sz,
1203 1.1.1.1.14.1 perseant &new_thunk, sizeof(new_thunk));
1204 1.1.1.1.14.1 perseant assert_d_eq(0, err, "");
1205 1.1.1.1.14.1 perseant
1206 1.1.1.1.14.1 perseant expect_true(old_thunk.callback == NULL, "Callback already installed");
1207 1.1.1.1.14.1 perseant expect_true(old_thunk.uctx == NULL, "Callback data already installed");
1208 1.1.1.1.14.1 perseant
1209 1.1.1.1.14.1 perseant ptr = mallocx(big_size, 0);
1210 1.1.1.1.14.1 perseant expect_u64_eq(test_data.obtained_alloc, *allocatedp, "");
1211 1.1.1.1.14.1 perseant expect_u64_eq(test_data.obtained_dalloc, *deallocatedp, "");
1212 1.1.1.1.14.1 perseant
1213 1.1.1.1.14.1 perseant free(ptr);
1214 1.1.1.1.14.1 perseant expect_u64_eq(test_data.obtained_alloc, *allocatedp, "");
1215 1.1.1.1.14.1 perseant expect_u64_eq(test_data.obtained_dalloc, *deallocatedp, "");
1216 1.1.1.1.14.1 perseant
1217 1.1.1.1.14.1 perseant sz = sizeof(old_thunk);
1218 1.1.1.1.14.1 perseant new_thunk = (activity_callback_thunk_t){ NULL, NULL };
1219 1.1.1.1.14.1 perseant err = mallctl("experimental.thread.activity_callback", &old_thunk, &sz,
1220 1.1.1.1.14.1 perseant &new_thunk, sizeof(new_thunk));
1221 1.1.1.1.14.1 perseant assert_d_eq(0, err, "");
1222 1.1.1.1.14.1 perseant
1223 1.1.1.1.14.1 perseant expect_true(old_thunk.callback == &activity_test_callback, "");
1224 1.1.1.1.14.1 perseant expect_true(old_thunk.uctx == &test_data, "");
1225 1.1.1.1.14.1 perseant
1226 1.1.1.1.14.1 perseant /* Inserting NULL should have turned off tracking. */
1227 1.1.1.1.14.1 perseant test_data.obtained_alloc = 333;
1228 1.1.1.1.14.1 perseant test_data.obtained_dalloc = 444;
1229 1.1.1.1.14.1 perseant ptr = mallocx(big_size, 0);
1230 1.1.1.1.14.1 perseant free(ptr);
1231 1.1.1.1.14.1 perseant expect_u64_eq(333, test_data.obtained_alloc, "");
1232 1.1.1.1.14.1 perseant expect_u64_eq(444, test_data.obtained_dalloc, "");
1233 1.1.1.1.14.1 perseant }
1234 1.1.1.1.14.1 perseant TEST_END
1235 1.1.1.1.14.1 perseant
1236 1.1 christos int
1237 1.1 christos main(void) {
1238 1.1 christos return test(
1239 1.1 christos test_mallctl_errors,
1240 1.1 christos test_mallctlnametomib_errors,
1241 1.1 christos test_mallctlbymib_errors,
1242 1.1 christos test_mallctl_read_write,
1243 1.1 christos test_mallctlnametomib_short_mib,
1244 1.1.1.1.14.1 perseant test_mallctlnametomib_short_name,
1245 1.1.1.1.14.1 perseant test_mallctlmibnametomib,
1246 1.1.1.1.14.1 perseant test_mallctlbymibname,
1247 1.1 christos test_mallctl_config,
1248 1.1 christos test_mallctl_opt,
1249 1.1 christos test_manpage_example,
1250 1.1 christos test_tcache_none,
1251 1.1 christos test_tcache,
1252 1.1 christos test_thread_arena,
1253 1.1 christos test_arena_i_initialized,
1254 1.1 christos test_arena_i_dirty_decay_ms,
1255 1.1 christos test_arena_i_muzzy_decay_ms,
1256 1.1 christos test_arena_i_purge,
1257 1.1 christos test_arena_i_decay,
1258 1.1 christos test_arena_i_dss,
1259 1.1 christos test_arena_i_retain_grow_limit,
1260 1.1 christos test_arenas_dirty_decay_ms,
1261 1.1 christos test_arenas_muzzy_decay_ms,
1262 1.1 christos test_arenas_constants,
1263 1.1 christos test_arenas_bin_constants,
1264 1.1 christos test_arenas_lextent_constants,
1265 1.1 christos test_arenas_create,
1266 1.1 christos test_arenas_lookup,
1267 1.1.1.1.14.1 perseant test_prof_active,
1268 1.1.1.1.14.1 perseant test_stats_arenas,
1269 1.1.1.1.14.1 perseant test_hooks,
1270 1.1.1.1.14.1 perseant test_hooks_exhaustion,
1271 1.1.1.1.14.1 perseant test_thread_idle,
1272 1.1.1.1.14.1 perseant test_thread_peak,
1273 1.1.1.1.14.1 perseant test_thread_activity_callback);
1274 1.1 christos }
1275