1 #include "test/jemalloc_test.h" 2 3 #include "jemalloc/internal/util.h" 4 5 TEST_BEGIN(test_mallctl_errors) { 6 uint64_t epoch; 7 size_t sz; 8 9 assert_d_eq(mallctl("no_such_name", NULL, NULL, NULL, 0), ENOENT, 10 "mallctl() should return ENOENT for non-existent names"); 11 12 assert_d_eq(mallctl("version", NULL, NULL, "0.0.0", strlen("0.0.0")), 13 EPERM, "mallctl() should return EPERM on attempt to write " 14 "read-only value"); 15 16 assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, 17 sizeof(epoch)-1), EINVAL, 18 "mallctl() should return EINVAL for input size mismatch"); 19 assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, 20 sizeof(epoch)+1), EINVAL, 21 "mallctl() should return EINVAL for input size mismatch"); 22 23 sz = sizeof(epoch)-1; 24 assert_d_eq(mallctl("epoch", (void *)&epoch, &sz, NULL, 0), EINVAL, 25 "mallctl() should return EINVAL for output size mismatch"); 26 sz = sizeof(epoch)+1; 27 assert_d_eq(mallctl("epoch", (void *)&epoch, &sz, NULL, 0), EINVAL, 28 "mallctl() should return EINVAL for output size mismatch"); 29 } 30 TEST_END 31 32 TEST_BEGIN(test_mallctlnametomib_errors) { 33 size_t mib[1]; 34 size_t miblen; 35 36 miblen = sizeof(mib)/sizeof(size_t); 37 assert_d_eq(mallctlnametomib("no_such_name", mib, &miblen), ENOENT, 38 "mallctlnametomib() should return ENOENT for non-existent names"); 39 } 40 TEST_END 41 42 TEST_BEGIN(test_mallctlbymib_errors) { 43 uint64_t epoch; 44 size_t sz; 45 size_t mib[1]; 46 size_t miblen; 47 48 miblen = sizeof(mib)/sizeof(size_t); 49 assert_d_eq(mallctlnametomib("version", mib, &miblen), 0, 50 "Unexpected mallctlnametomib() failure"); 51 52 assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, "0.0.0", 53 strlen("0.0.0")), EPERM, "mallctl() should return EPERM on " 54 "attempt to write read-only value"); 55 56 miblen = sizeof(mib)/sizeof(size_t); 57 assert_d_eq(mallctlnametomib("epoch", mib, &miblen), 0, 58 "Unexpected mallctlnametomib() failure"); 59 60 assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, (void *)&epoch, 61 sizeof(epoch)-1), EINVAL, 62 "mallctlbymib() should return EINVAL for input size mismatch"); 63 assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, (void *)&epoch, 64 sizeof(epoch)+1), EINVAL, 65 "mallctlbymib() should return EINVAL for input size mismatch"); 66 67 sz = sizeof(epoch)-1; 68 assert_d_eq(mallctlbymib(mib, miblen, (void *)&epoch, &sz, NULL, 0), 69 EINVAL, 70 "mallctlbymib() should return EINVAL for output size mismatch"); 71 sz = sizeof(epoch)+1; 72 assert_d_eq(mallctlbymib(mib, miblen, (void *)&epoch, &sz, NULL, 0), 73 EINVAL, 74 "mallctlbymib() should return EINVAL for output size mismatch"); 75 } 76 TEST_END 77 78 TEST_BEGIN(test_mallctl_read_write) { 79 uint64_t old_epoch, new_epoch; 80 size_t sz = sizeof(old_epoch); 81 82 /* Blind. */ 83 assert_d_eq(mallctl("epoch", NULL, NULL, NULL, 0), 0, 84 "Unexpected mallctl() failure"); 85 assert_zu_eq(sz, sizeof(old_epoch), "Unexpected output size"); 86 87 /* Read. */ 88 assert_d_eq(mallctl("epoch", (void *)&old_epoch, &sz, NULL, 0), 0, 89 "Unexpected mallctl() failure"); 90 assert_zu_eq(sz, sizeof(old_epoch), "Unexpected output size"); 91 92 /* Write. */ 93 assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&new_epoch, 94 sizeof(new_epoch)), 0, "Unexpected mallctl() failure"); 95 assert_zu_eq(sz, sizeof(old_epoch), "Unexpected output size"); 96 97 /* Read+write. */ 98 assert_d_eq(mallctl("epoch", (void *)&old_epoch, &sz, 99 (void *)&new_epoch, sizeof(new_epoch)), 0, 100 "Unexpected mallctl() failure"); 101 assert_zu_eq(sz, sizeof(old_epoch), "Unexpected output size"); 102 } 103 TEST_END 104 105 TEST_BEGIN(test_mallctlnametomib_short_mib) { 106 size_t mib[4]; 107 size_t miblen; 108 109 miblen = 3; 110 mib[3] = 42; 111 assert_d_eq(mallctlnametomib("arenas.bin.0.nregs", mib, &miblen), 0, 112 "Unexpected mallctlnametomib() failure"); 113 assert_zu_eq(miblen, 3, "Unexpected mib output length"); 114 assert_zu_eq(mib[3], 42, 115 "mallctlnametomib() wrote past the end of the input mib"); 116 } 117 TEST_END 118 119 TEST_BEGIN(test_mallctl_config) { 120 #define TEST_MALLCTL_CONFIG(config, t) do { \ 121 t oldval; \ 122 size_t sz = sizeof(oldval); \ 123 assert_d_eq(mallctl("config."#config, (void *)&oldval, &sz, \ 124 NULL, 0), 0, "Unexpected mallctl() failure"); \ 125 assert_b_eq(oldval, config_##config, "Incorrect config value"); \ 126 assert_zu_eq(sz, sizeof(oldval), "Unexpected output size"); \ 127 } while (0) 128 129 TEST_MALLCTL_CONFIG(cache_oblivious, bool); 130 TEST_MALLCTL_CONFIG(debug, bool); 131 TEST_MALLCTL_CONFIG(fill, bool); 132 TEST_MALLCTL_CONFIG(lazy_lock, bool); 133 TEST_MALLCTL_CONFIG(malloc_conf, const char *); 134 TEST_MALLCTL_CONFIG(prof, bool); 135 TEST_MALLCTL_CONFIG(prof_libgcc, bool); 136 TEST_MALLCTL_CONFIG(prof_libunwind, bool); 137 TEST_MALLCTL_CONFIG(stats, bool); 138 TEST_MALLCTL_CONFIG(utrace, bool); 139 TEST_MALLCTL_CONFIG(xmalloc, bool); 140 141 #undef TEST_MALLCTL_CONFIG 142 } 143 TEST_END 144 145 TEST_BEGIN(test_mallctl_opt) { 146 bool config_always = true; 147 148 #define TEST_MALLCTL_OPT(t, opt, config) do { \ 149 t oldval; \ 150 size_t sz = sizeof(oldval); \ 151 int expected = config_##config ? 0 : ENOENT; \ 152 int result = mallctl("opt."#opt, (void *)&oldval, &sz, NULL, \ 153 0); \ 154 assert_d_eq(result, expected, \ 155 "Unexpected mallctl() result for opt."#opt); \ 156 assert_zu_eq(sz, sizeof(oldval), "Unexpected output size"); \ 157 } while (0) 158 159 TEST_MALLCTL_OPT(bool, abort, always); 160 TEST_MALLCTL_OPT(bool, abort_conf, always); 161 TEST_MALLCTL_OPT(const char *, metadata_thp, always); 162 TEST_MALLCTL_OPT(bool, retain, always); 163 TEST_MALLCTL_OPT(const char *, dss, always); 164 TEST_MALLCTL_OPT(unsigned, narenas, always); 165 TEST_MALLCTL_OPT(const char *, percpu_arena, always); 166 TEST_MALLCTL_OPT(bool, background_thread, always); 167 TEST_MALLCTL_OPT(ssize_t, dirty_decay_ms, always); 168 TEST_MALLCTL_OPT(ssize_t, muzzy_decay_ms, always); 169 TEST_MALLCTL_OPT(bool, stats_print, always); 170 TEST_MALLCTL_OPT(const char *, junk, fill); 171 TEST_MALLCTL_OPT(bool, zero, fill); 172 TEST_MALLCTL_OPT(bool, utrace, utrace); 173 TEST_MALLCTL_OPT(bool, xmalloc, xmalloc); 174 TEST_MALLCTL_OPT(bool, tcache, always); 175 TEST_MALLCTL_OPT(size_t, lg_extent_max_active_fit, always); 176 TEST_MALLCTL_OPT(size_t, lg_tcache_max, always); 177 TEST_MALLCTL_OPT(const char *, thp, always); 178 TEST_MALLCTL_OPT(bool, prof, prof); 179 TEST_MALLCTL_OPT(const char *, prof_prefix, prof); 180 TEST_MALLCTL_OPT(bool, prof_active, prof); 181 TEST_MALLCTL_OPT(ssize_t, lg_prof_sample, prof); 182 TEST_MALLCTL_OPT(bool, prof_accum, prof); 183 TEST_MALLCTL_OPT(ssize_t, lg_prof_interval, prof); 184 TEST_MALLCTL_OPT(bool, prof_gdump, prof); 185 TEST_MALLCTL_OPT(bool, prof_final, prof); 186 TEST_MALLCTL_OPT(bool, prof_leak, prof); 187 188 #undef TEST_MALLCTL_OPT 189 } 190 TEST_END 191 192 TEST_BEGIN(test_manpage_example) { 193 unsigned nbins, i; 194 size_t mib[4]; 195 size_t len, miblen; 196 197 len = sizeof(nbins); 198 assert_d_eq(mallctl("arenas.nbins", (void *)&nbins, &len, NULL, 0), 0, 199 "Unexpected mallctl() failure"); 200 201 miblen = 4; 202 assert_d_eq(mallctlnametomib("arenas.bin.0.size", mib, &miblen), 0, 203 "Unexpected mallctlnametomib() failure"); 204 for (i = 0; i < nbins; i++) { 205 size_t bin_size; 206 207 mib[2] = i; 208 len = sizeof(bin_size); 209 assert_d_eq(mallctlbymib(mib, miblen, (void *)&bin_size, &len, 210 NULL, 0), 0, "Unexpected mallctlbymib() failure"); 211 /* Do something with bin_size... */ 212 } 213 } 214 TEST_END 215 216 TEST_BEGIN(test_tcache_none) { 217 test_skip_if(!opt_tcache); 218 219 /* Allocate p and q. */ 220 void *p0 = mallocx(42, 0); 221 assert_ptr_not_null(p0, "Unexpected mallocx() failure"); 222 void *q = mallocx(42, 0); 223 assert_ptr_not_null(q, "Unexpected mallocx() failure"); 224 225 /* Deallocate p and q, but bypass the tcache for q. */ 226 dallocx(p0, 0); 227 dallocx(q, MALLOCX_TCACHE_NONE); 228 229 /* Make sure that tcache-based allocation returns p, not q. */ 230 void *p1 = mallocx(42, 0); 231 assert_ptr_not_null(p1, "Unexpected mallocx() failure"); 232 assert_ptr_eq(p0, p1, "Expected tcache to allocate cached region"); 233 234 /* Clean up. */ 235 dallocx(p1, MALLOCX_TCACHE_NONE); 236 } 237 TEST_END 238 239 TEST_BEGIN(test_tcache) { 240 #define NTCACHES 10 241 unsigned tis[NTCACHES]; 242 void *ps[NTCACHES]; 243 void *qs[NTCACHES]; 244 unsigned i; 245 size_t sz, psz, qsz; 246 247 psz = 42; 248 qsz = nallocx(psz, 0) + 1; 249 250 /* Create tcaches. */ 251 for (i = 0; i < NTCACHES; i++) { 252 sz = sizeof(unsigned); 253 assert_d_eq(mallctl("tcache.create", (void *)&tis[i], &sz, NULL, 254 0), 0, "Unexpected mallctl() failure, i=%u", i); 255 } 256 257 /* Exercise tcache ID recycling. */ 258 for (i = 0; i < NTCACHES; i++) { 259 assert_d_eq(mallctl("tcache.destroy", NULL, NULL, 260 (void *)&tis[i], sizeof(unsigned)), 0, 261 "Unexpected mallctl() failure, i=%u", i); 262 } 263 for (i = 0; i < NTCACHES; i++) { 264 sz = sizeof(unsigned); 265 assert_d_eq(mallctl("tcache.create", (void *)&tis[i], &sz, NULL, 266 0), 0, "Unexpected mallctl() failure, i=%u", i); 267 } 268 269 /* Flush empty tcaches. */ 270 for (i = 0; i < NTCACHES; i++) { 271 assert_d_eq(mallctl("tcache.flush", NULL, NULL, (void *)&tis[i], 272 sizeof(unsigned)), 0, "Unexpected mallctl() failure, i=%u", 273 i); 274 } 275 276 /* Cache some allocations. */ 277 for (i = 0; i < NTCACHES; i++) { 278 ps[i] = mallocx(psz, MALLOCX_TCACHE(tis[i])); 279 assert_ptr_not_null(ps[i], "Unexpected mallocx() failure, i=%u", 280 i); 281 dallocx(ps[i], MALLOCX_TCACHE(tis[i])); 282 283 qs[i] = mallocx(qsz, MALLOCX_TCACHE(tis[i])); 284 assert_ptr_not_null(qs[i], "Unexpected mallocx() failure, i=%u", 285 i); 286 dallocx(qs[i], MALLOCX_TCACHE(tis[i])); 287 } 288 289 /* Verify that tcaches allocate cached regions. */ 290 for (i = 0; i < NTCACHES; i++) { 291 void *p0 = ps[i]; 292 ps[i] = mallocx(psz, MALLOCX_TCACHE(tis[i])); 293 assert_ptr_not_null(ps[i], "Unexpected mallocx() failure, i=%u", 294 i); 295 assert_ptr_eq(ps[i], p0, 296 "Expected mallocx() to allocate cached region, i=%u", i); 297 } 298 299 /* Verify that reallocation uses cached regions. */ 300 for (i = 0; i < NTCACHES; i++) { 301 void *q0 = qs[i]; 302 qs[i] = rallocx(ps[i], qsz, MALLOCX_TCACHE(tis[i])); 303 assert_ptr_not_null(qs[i], "Unexpected rallocx() failure, i=%u", 304 i); 305 assert_ptr_eq(qs[i], q0, 306 "Expected rallocx() to allocate cached region, i=%u", i); 307 /* Avoid undefined behavior in case of test failure. */ 308 if (qs[i] == NULL) { 309 qs[i] = ps[i]; 310 } 311 } 312 for (i = 0; i < NTCACHES; i++) { 313 dallocx(qs[i], MALLOCX_TCACHE(tis[i])); 314 } 315 316 /* Flush some non-empty tcaches. */ 317 for (i = 0; i < NTCACHES/2; i++) { 318 assert_d_eq(mallctl("tcache.flush", NULL, NULL, (void *)&tis[i], 319 sizeof(unsigned)), 0, "Unexpected mallctl() failure, i=%u", 320 i); 321 } 322 323 /* Destroy tcaches. */ 324 for (i = 0; i < NTCACHES; i++) { 325 assert_d_eq(mallctl("tcache.destroy", NULL, NULL, 326 (void *)&tis[i], sizeof(unsigned)), 0, 327 "Unexpected mallctl() failure, i=%u", i); 328 } 329 } 330 TEST_END 331 332 TEST_BEGIN(test_thread_arena) { 333 unsigned old_arena_ind, new_arena_ind, narenas; 334 335 const char *opa; 336 size_t sz = sizeof(opa); 337 assert_d_eq(mallctl("opt.percpu_arena", (void *)&opa, &sz, NULL, 0), 0, 338 "Unexpected mallctl() failure"); 339 340 sz = sizeof(unsigned); 341 assert_d_eq(mallctl("arenas.narenas", (void *)&narenas, &sz, NULL, 0), 342 0, "Unexpected mallctl() failure"); 343 assert_u_eq(narenas, opt_narenas, "Number of arenas incorrect"); 344 345 if (strcmp(opa, "disabled") == 0) { 346 new_arena_ind = narenas - 1; 347 assert_d_eq(mallctl("thread.arena", (void *)&old_arena_ind, &sz, 348 (void *)&new_arena_ind, sizeof(unsigned)), 0, 349 "Unexpected mallctl() failure"); 350 new_arena_ind = 0; 351 assert_d_eq(mallctl("thread.arena", (void *)&old_arena_ind, &sz, 352 (void *)&new_arena_ind, sizeof(unsigned)), 0, 353 "Unexpected mallctl() failure"); 354 } else { 355 assert_d_eq(mallctl("thread.arena", (void *)&old_arena_ind, &sz, 356 NULL, 0), 0, "Unexpected mallctl() failure"); 357 new_arena_ind = percpu_arena_ind_limit(opt_percpu_arena) - 1; 358 if (old_arena_ind != new_arena_ind) { 359 assert_d_eq(mallctl("thread.arena", 360 (void *)&old_arena_ind, &sz, (void *)&new_arena_ind, 361 sizeof(unsigned)), EPERM, "thread.arena ctl " 362 "should not be allowed with percpu arena"); 363 } 364 } 365 } 366 TEST_END 367 368 TEST_BEGIN(test_arena_i_initialized) { 369 unsigned narenas, i; 370 size_t sz; 371 size_t mib[3]; 372 size_t miblen = sizeof(mib) / sizeof(size_t); 373 bool initialized; 374 375 sz = sizeof(narenas); 376 assert_d_eq(mallctl("arenas.narenas", (void *)&narenas, &sz, NULL, 0), 377 0, "Unexpected mallctl() failure"); 378 379 assert_d_eq(mallctlnametomib("arena.0.initialized", mib, &miblen), 0, 380 "Unexpected mallctlnametomib() failure"); 381 for (i = 0; i < narenas; i++) { 382 mib[1] = i; 383 sz = sizeof(initialized); 384 assert_d_eq(mallctlbymib(mib, miblen, &initialized, &sz, NULL, 385 0), 0, "Unexpected mallctl() failure"); 386 } 387 388 mib[1] = MALLCTL_ARENAS_ALL; 389 sz = sizeof(initialized); 390 assert_d_eq(mallctlbymib(mib, miblen, &initialized, &sz, NULL, 0), 0, 391 "Unexpected mallctl() failure"); 392 assert_true(initialized, 393 "Merged arena statistics should always be initialized"); 394 395 /* Equivalent to the above but using mallctl() directly. */ 396 sz = sizeof(initialized); 397 assert_d_eq(mallctl( 398 "arena." STRINGIFY(MALLCTL_ARENAS_ALL) ".initialized", 399 (void *)&initialized, &sz, NULL, 0), 0, 400 "Unexpected mallctl() failure"); 401 assert_true(initialized, 402 "Merged arena statistics should always be initialized"); 403 } 404 TEST_END 405 406 TEST_BEGIN(test_arena_i_dirty_decay_ms) { 407 ssize_t dirty_decay_ms, orig_dirty_decay_ms, prev_dirty_decay_ms; 408 size_t sz = sizeof(ssize_t); 409 410 assert_d_eq(mallctl("arena.0.dirty_decay_ms", 411 (void *)&orig_dirty_decay_ms, &sz, NULL, 0), 0, 412 "Unexpected mallctl() failure"); 413 414 dirty_decay_ms = -2; 415 assert_d_eq(mallctl("arena.0.dirty_decay_ms", NULL, NULL, 416 (void *)&dirty_decay_ms, sizeof(ssize_t)), EFAULT, 417 "Unexpected mallctl() success"); 418 419 dirty_decay_ms = 0x7fffffff; 420 assert_d_eq(mallctl("arena.0.dirty_decay_ms", NULL, NULL, 421 (void *)&dirty_decay_ms, sizeof(ssize_t)), 0, 422 "Unexpected mallctl() failure"); 423 424 for (prev_dirty_decay_ms = dirty_decay_ms, dirty_decay_ms = -1; 425 dirty_decay_ms < 20; prev_dirty_decay_ms = dirty_decay_ms, 426 dirty_decay_ms++) { 427 ssize_t old_dirty_decay_ms; 428 429 assert_d_eq(mallctl("arena.0.dirty_decay_ms", 430 (void *)&old_dirty_decay_ms, &sz, (void *)&dirty_decay_ms, 431 sizeof(ssize_t)), 0, "Unexpected mallctl() failure"); 432 assert_zd_eq(old_dirty_decay_ms, prev_dirty_decay_ms, 433 "Unexpected old arena.0.dirty_decay_ms"); 434 } 435 } 436 TEST_END 437 438 TEST_BEGIN(test_arena_i_muzzy_decay_ms) { 439 ssize_t muzzy_decay_ms, orig_muzzy_decay_ms, prev_muzzy_decay_ms; 440 size_t sz = sizeof(ssize_t); 441 442 assert_d_eq(mallctl("arena.0.muzzy_decay_ms", 443 (void *)&orig_muzzy_decay_ms, &sz, NULL, 0), 0, 444 "Unexpected mallctl() failure"); 445 446 muzzy_decay_ms = -2; 447 assert_d_eq(mallctl("arena.0.muzzy_decay_ms", NULL, NULL, 448 (void *)&muzzy_decay_ms, sizeof(ssize_t)), EFAULT, 449 "Unexpected mallctl() success"); 450 451 muzzy_decay_ms = 0x7fffffff; 452 assert_d_eq(mallctl("arena.0.muzzy_decay_ms", NULL, NULL, 453 (void *)&muzzy_decay_ms, sizeof(ssize_t)), 0, 454 "Unexpected mallctl() failure"); 455 456 for (prev_muzzy_decay_ms = muzzy_decay_ms, muzzy_decay_ms = -1; 457 muzzy_decay_ms < 20; prev_muzzy_decay_ms = muzzy_decay_ms, 458 muzzy_decay_ms++) { 459 ssize_t old_muzzy_decay_ms; 460 461 assert_d_eq(mallctl("arena.0.muzzy_decay_ms", 462 (void *)&old_muzzy_decay_ms, &sz, (void *)&muzzy_decay_ms, 463 sizeof(ssize_t)), 0, "Unexpected mallctl() failure"); 464 assert_zd_eq(old_muzzy_decay_ms, prev_muzzy_decay_ms, 465 "Unexpected old arena.0.muzzy_decay_ms"); 466 } 467 } 468 TEST_END 469 470 TEST_BEGIN(test_arena_i_purge) { 471 unsigned narenas; 472 size_t sz = sizeof(unsigned); 473 size_t mib[3]; 474 size_t miblen = 3; 475 476 assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0, 477 "Unexpected mallctl() failure"); 478 479 assert_d_eq(mallctl("arenas.narenas", (void *)&narenas, &sz, NULL, 0), 480 0, "Unexpected mallctl() failure"); 481 assert_d_eq(mallctlnametomib("arena.0.purge", mib, &miblen), 0, 482 "Unexpected mallctlnametomib() failure"); 483 mib[1] = narenas; 484 assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, NULL, 0), 0, 485 "Unexpected mallctlbymib() failure"); 486 487 mib[1] = MALLCTL_ARENAS_ALL; 488 assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, NULL, 0), 0, 489 "Unexpected mallctlbymib() failure"); 490 } 491 TEST_END 492 493 TEST_BEGIN(test_arena_i_decay) { 494 unsigned narenas; 495 size_t sz = sizeof(unsigned); 496 size_t mib[3]; 497 size_t miblen = 3; 498 499 assert_d_eq(mallctl("arena.0.decay", NULL, NULL, NULL, 0), 0, 500 "Unexpected mallctl() failure"); 501 502 assert_d_eq(mallctl("arenas.narenas", (void *)&narenas, &sz, NULL, 0), 503 0, "Unexpected mallctl() failure"); 504 assert_d_eq(mallctlnametomib("arena.0.decay", mib, &miblen), 0, 505 "Unexpected mallctlnametomib() failure"); 506 mib[1] = narenas; 507 assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, NULL, 0), 0, 508 "Unexpected mallctlbymib() failure"); 509 510 mib[1] = MALLCTL_ARENAS_ALL; 511 assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, NULL, 0), 0, 512 "Unexpected mallctlbymib() failure"); 513 } 514 TEST_END 515 516 TEST_BEGIN(test_arena_i_dss) { 517 const char *dss_prec_old, *dss_prec_new; 518 size_t sz = sizeof(dss_prec_old); 519 size_t mib[3]; 520 size_t miblen; 521 522 miblen = sizeof(mib)/sizeof(size_t); 523 assert_d_eq(mallctlnametomib("arena.0.dss", mib, &miblen), 0, 524 "Unexpected mallctlnametomib() error"); 525 526 dss_prec_new = "disabled"; 527 assert_d_eq(mallctlbymib(mib, miblen, (void *)&dss_prec_old, &sz, 528 (void *)&dss_prec_new, sizeof(dss_prec_new)), 0, 529 "Unexpected mallctl() failure"); 530 assert_str_ne(dss_prec_old, "primary", 531 "Unexpected default for dss precedence"); 532 533 assert_d_eq(mallctlbymib(mib, miblen, (void *)&dss_prec_new, &sz, 534 (void *)&dss_prec_old, sizeof(dss_prec_old)), 0, 535 "Unexpected mallctl() failure"); 536 537 assert_d_eq(mallctlbymib(mib, miblen, (void *)&dss_prec_old, &sz, NULL, 538 0), 0, "Unexpected mallctl() failure"); 539 assert_str_ne(dss_prec_old, "primary", 540 "Unexpected value for dss precedence"); 541 542 mib[1] = narenas_total_get(); 543 dss_prec_new = "disabled"; 544 assert_d_eq(mallctlbymib(mib, miblen, (void *)&dss_prec_old, &sz, 545 (void *)&dss_prec_new, sizeof(dss_prec_new)), 0, 546 "Unexpected mallctl() failure"); 547 assert_str_ne(dss_prec_old, "primary", 548 "Unexpected default for dss precedence"); 549 550 assert_d_eq(mallctlbymib(mib, miblen, (void *)&dss_prec_new, &sz, 551 (void *)&dss_prec_old, sizeof(dss_prec_new)), 0, 552 "Unexpected mallctl() failure"); 553 554 assert_d_eq(mallctlbymib(mib, miblen, (void *)&dss_prec_old, &sz, NULL, 555 0), 0, "Unexpected mallctl() failure"); 556 assert_str_ne(dss_prec_old, "primary", 557 "Unexpected value for dss precedence"); 558 } 559 TEST_END 560 561 TEST_BEGIN(test_arena_i_retain_grow_limit) { 562 size_t old_limit, new_limit, default_limit; 563 size_t mib[3]; 564 size_t miblen; 565 566 bool retain_enabled; 567 size_t sz = sizeof(retain_enabled); 568 assert_d_eq(mallctl("opt.retain", &retain_enabled, &sz, NULL, 0), 569 0, "Unexpected mallctl() failure"); 570 test_skip_if(!retain_enabled); 571 572 sz = sizeof(default_limit); 573 miblen = sizeof(mib)/sizeof(size_t); 574 assert_d_eq(mallctlnametomib("arena.0.retain_grow_limit", mib, &miblen), 575 0, "Unexpected mallctlnametomib() error"); 576 577 assert_d_eq(mallctlbymib(mib, miblen, &default_limit, &sz, NULL, 0), 0, 578 "Unexpected mallctl() failure"); 579 assert_zu_eq(default_limit, sz_pind2sz(EXTENT_GROW_MAX_PIND), 580 "Unexpected default for retain_grow_limit"); 581 582 new_limit = PAGE - 1; 583 assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, &new_limit, 584 sizeof(new_limit)), EFAULT, "Unexpected mallctl() success"); 585 586 new_limit = PAGE + 1; 587 assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, &new_limit, 588 sizeof(new_limit)), 0, "Unexpected mallctl() failure"); 589 assert_d_eq(mallctlbymib(mib, miblen, &old_limit, &sz, NULL, 0), 0, 590 "Unexpected mallctl() failure"); 591 assert_zu_eq(old_limit, PAGE, 592 "Unexpected value for retain_grow_limit"); 593 594 /* Expect grow less than psize class 10. */ 595 new_limit = sz_pind2sz(10) - 1; 596 assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, &new_limit, 597 sizeof(new_limit)), 0, "Unexpected mallctl() failure"); 598 assert_d_eq(mallctlbymib(mib, miblen, &old_limit, &sz, NULL, 0), 0, 599 "Unexpected mallctl() failure"); 600 assert_zu_eq(old_limit, sz_pind2sz(9), 601 "Unexpected value for retain_grow_limit"); 602 603 /* Restore to default. */ 604 assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, &default_limit, 605 sizeof(default_limit)), 0, "Unexpected mallctl() failure"); 606 } 607 TEST_END 608 609 TEST_BEGIN(test_arenas_dirty_decay_ms) { 610 ssize_t dirty_decay_ms, orig_dirty_decay_ms, prev_dirty_decay_ms; 611 size_t sz = sizeof(ssize_t); 612 613 assert_d_eq(mallctl("arenas.dirty_decay_ms", 614 (void *)&orig_dirty_decay_ms, &sz, NULL, 0), 0, 615 "Unexpected mallctl() failure"); 616 617 dirty_decay_ms = -2; 618 assert_d_eq(mallctl("arenas.dirty_decay_ms", NULL, NULL, 619 (void *)&dirty_decay_ms, sizeof(ssize_t)), EFAULT, 620 "Unexpected mallctl() success"); 621 622 dirty_decay_ms = 0x7fffffff; 623 assert_d_eq(mallctl("arenas.dirty_decay_ms", NULL, NULL, 624 (void *)&dirty_decay_ms, sizeof(ssize_t)), 0, 625 "Expected mallctl() failure"); 626 627 for (prev_dirty_decay_ms = dirty_decay_ms, dirty_decay_ms = -1; 628 dirty_decay_ms < 20; prev_dirty_decay_ms = dirty_decay_ms, 629 dirty_decay_ms++) { 630 ssize_t old_dirty_decay_ms; 631 632 assert_d_eq(mallctl("arenas.dirty_decay_ms", 633 (void *)&old_dirty_decay_ms, &sz, (void *)&dirty_decay_ms, 634 sizeof(ssize_t)), 0, "Unexpected mallctl() failure"); 635 assert_zd_eq(old_dirty_decay_ms, prev_dirty_decay_ms, 636 "Unexpected old arenas.dirty_decay_ms"); 637 } 638 } 639 TEST_END 640 641 TEST_BEGIN(test_arenas_muzzy_decay_ms) { 642 ssize_t muzzy_decay_ms, orig_muzzy_decay_ms, prev_muzzy_decay_ms; 643 size_t sz = sizeof(ssize_t); 644 645 assert_d_eq(mallctl("arenas.muzzy_decay_ms", 646 (void *)&orig_muzzy_decay_ms, &sz, NULL, 0), 0, 647 "Unexpected mallctl() failure"); 648 649 muzzy_decay_ms = -2; 650 assert_d_eq(mallctl("arenas.muzzy_decay_ms", NULL, NULL, 651 (void *)&muzzy_decay_ms, sizeof(ssize_t)), EFAULT, 652 "Unexpected mallctl() success"); 653 654 muzzy_decay_ms = 0x7fffffff; 655 assert_d_eq(mallctl("arenas.muzzy_decay_ms", NULL, NULL, 656 (void *)&muzzy_decay_ms, sizeof(ssize_t)), 0, 657 "Expected mallctl() failure"); 658 659 for (prev_muzzy_decay_ms = muzzy_decay_ms, muzzy_decay_ms = -1; 660 muzzy_decay_ms < 20; prev_muzzy_decay_ms = muzzy_decay_ms, 661 muzzy_decay_ms++) { 662 ssize_t old_muzzy_decay_ms; 663 664 assert_d_eq(mallctl("arenas.muzzy_decay_ms", 665 (void *)&old_muzzy_decay_ms, &sz, (void *)&muzzy_decay_ms, 666 sizeof(ssize_t)), 0, "Unexpected mallctl() failure"); 667 assert_zd_eq(old_muzzy_decay_ms, prev_muzzy_decay_ms, 668 "Unexpected old arenas.muzzy_decay_ms"); 669 } 670 } 671 TEST_END 672 673 TEST_BEGIN(test_arenas_constants) { 674 #define TEST_ARENAS_CONSTANT(t, name, expected) do { \ 675 t name; \ 676 size_t sz = sizeof(t); \ 677 assert_d_eq(mallctl("arenas."#name, (void *)&name, &sz, NULL, \ 678 0), 0, "Unexpected mallctl() failure"); \ 679 assert_zu_eq(name, expected, "Incorrect "#name" size"); \ 680 } while (0) 681 682 TEST_ARENAS_CONSTANT(size_t, quantum, QUANTUM); 683 TEST_ARENAS_CONSTANT(size_t, page, PAGE); 684 TEST_ARENAS_CONSTANT(unsigned, nbins, NBINS); 685 TEST_ARENAS_CONSTANT(unsigned, nlextents, NSIZES - NBINS); 686 687 #undef TEST_ARENAS_CONSTANT 688 } 689 TEST_END 690 691 TEST_BEGIN(test_arenas_bin_constants) { 692 #define TEST_ARENAS_BIN_CONSTANT(t, name, expected) do { \ 693 t name; \ 694 size_t sz = sizeof(t); \ 695 assert_d_eq(mallctl("arenas.bin.0."#name, (void *)&name, &sz, \ 696 NULL, 0), 0, "Unexpected mallctl() failure"); \ 697 assert_zu_eq(name, expected, "Incorrect "#name" size"); \ 698 } while (0) 699 700 TEST_ARENAS_BIN_CONSTANT(size_t, size, bin_infos[0].reg_size); 701 TEST_ARENAS_BIN_CONSTANT(uint32_t, nregs, bin_infos[0].nregs); 702 TEST_ARENAS_BIN_CONSTANT(size_t, slab_size, 703 bin_infos[0].slab_size); 704 705 #undef TEST_ARENAS_BIN_CONSTANT 706 } 707 TEST_END 708 709 TEST_BEGIN(test_arenas_lextent_constants) { 710 #define TEST_ARENAS_LEXTENT_CONSTANT(t, name, expected) do { \ 711 t name; \ 712 size_t sz = sizeof(t); \ 713 assert_d_eq(mallctl("arenas.lextent.0."#name, (void *)&name, \ 714 &sz, NULL, 0), 0, "Unexpected mallctl() failure"); \ 715 assert_zu_eq(name, expected, "Incorrect "#name" size"); \ 716 } while (0) 717 718 TEST_ARENAS_LEXTENT_CONSTANT(size_t, size, LARGE_MINCLASS); 719 720 #undef TEST_ARENAS_LEXTENT_CONSTANT 721 } 722 TEST_END 723 724 TEST_BEGIN(test_arenas_create) { 725 unsigned narenas_before, arena, narenas_after; 726 size_t sz = sizeof(unsigned); 727 728 assert_d_eq(mallctl("arenas.narenas", (void *)&narenas_before, &sz, 729 NULL, 0), 0, "Unexpected mallctl() failure"); 730 assert_d_eq(mallctl("arenas.create", (void *)&arena, &sz, NULL, 0), 0, 731 "Unexpected mallctl() failure"); 732 assert_d_eq(mallctl("arenas.narenas", (void *)&narenas_after, &sz, NULL, 733 0), 0, "Unexpected mallctl() failure"); 734 735 assert_u_eq(narenas_before+1, narenas_after, 736 "Unexpected number of arenas before versus after extension"); 737 assert_u_eq(arena, narenas_after-1, "Unexpected arena index"); 738 } 739 TEST_END 740 741 TEST_BEGIN(test_arenas_lookup) { 742 unsigned arena, arena1; 743 void *ptr; 744 size_t sz = sizeof(unsigned); 745 746 assert_d_eq(mallctl("arenas.create", (void *)&arena, &sz, NULL, 0), 0, 747 "Unexpected mallctl() failure"); 748 ptr = mallocx(42, MALLOCX_ARENA(arena) | MALLOCX_TCACHE_NONE); 749 assert_ptr_not_null(ptr, "Unexpected mallocx() failure"); 750 assert_d_eq(mallctl("arenas.lookup", &arena1, &sz, &ptr, sizeof(ptr)), 751 0, "Unexpected mallctl() failure"); 752 assert_u_eq(arena, arena1, "Unexpected arena index"); 753 dallocx(ptr, 0); 754 } 755 TEST_END 756 757 TEST_BEGIN(test_stats_arenas) { 758 #define TEST_STATS_ARENAS(t, name) do { \ 759 t name; \ 760 size_t sz = sizeof(t); \ 761 assert_d_eq(mallctl("stats.arenas.0."#name, (void *)&name, &sz, \ 762 NULL, 0), 0, "Unexpected mallctl() failure"); \ 763 } while (0) 764 765 TEST_STATS_ARENAS(unsigned, nthreads); 766 TEST_STATS_ARENAS(const char *, dss); 767 TEST_STATS_ARENAS(ssize_t, dirty_decay_ms); 768 TEST_STATS_ARENAS(ssize_t, muzzy_decay_ms); 769 TEST_STATS_ARENAS(size_t, pactive); 770 TEST_STATS_ARENAS(size_t, pdirty); 771 772 #undef TEST_STATS_ARENAS 773 } 774 TEST_END 775 776 int 777 main(void) { 778 return test( 779 test_mallctl_errors, 780 test_mallctlnametomib_errors, 781 test_mallctlbymib_errors, 782 test_mallctl_read_write, 783 test_mallctlnametomib_short_mib, 784 test_mallctl_config, 785 test_mallctl_opt, 786 test_manpage_example, 787 test_tcache_none, 788 test_tcache, 789 test_thread_arena, 790 test_arena_i_initialized, 791 test_arena_i_dirty_decay_ms, 792 test_arena_i_muzzy_decay_ms, 793 test_arena_i_purge, 794 test_arena_i_decay, 795 test_arena_i_dss, 796 test_arena_i_retain_grow_limit, 797 test_arenas_dirty_decay_ms, 798 test_arenas_muzzy_decay_ms, 799 test_arenas_constants, 800 test_arenas_bin_constants, 801 test_arenas_lextent_constants, 802 test_arenas_create, 803 test_arenas_lookup, 804 test_stats_arenas); 805 } 806