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