1 #include "test/jemalloc_test.h" 2 3 #define STRINGIFY_HELPER(x) #x 4 #define STRINGIFY(x) STRINGIFY_HELPER(x) 5 6 TEST_BEGIN(test_stats_summary) { 7 size_t sz, allocated, active, resident, mapped; 8 int expected = config_stats ? 0 : ENOENT; 9 10 sz = sizeof(size_t); 11 expect_d_eq(mallctl("stats.allocated", (void *)&allocated, &sz, NULL, 12 0), expected, "Unexpected mallctl() result"); 13 expect_d_eq(mallctl("stats.active", (void *)&active, &sz, NULL, 0), 14 expected, "Unexpected mallctl() result"); 15 expect_d_eq(mallctl("stats.resident", (void *)&resident, &sz, NULL, 0), 16 expected, "Unexpected mallctl() result"); 17 expect_d_eq(mallctl("stats.mapped", (void *)&mapped, &sz, NULL, 0), 18 expected, "Unexpected mallctl() result"); 19 20 if (config_stats) { 21 expect_zu_le(allocated, active, 22 "allocated should be no larger than active"); 23 expect_zu_lt(active, resident, 24 "active should be less than resident"); 25 expect_zu_lt(active, mapped, 26 "active should be less than mapped"); 27 } 28 } 29 TEST_END 30 31 TEST_BEGIN(test_stats_large) { 32 void *p; 33 uint64_t epoch; 34 size_t allocated; 35 uint64_t nmalloc, ndalloc, nrequests; 36 size_t sz; 37 int expected = config_stats ? 0 : ENOENT; 38 39 p = mallocx(SC_SMALL_MAXCLASS + 1, MALLOCX_ARENA(0)); 40 expect_ptr_not_null(p, "Unexpected mallocx() failure"); 41 42 expect_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, sizeof(epoch)), 43 0, "Unexpected mallctl() failure"); 44 45 sz = sizeof(size_t); 46 expect_d_eq(mallctl("stats.arenas.0.large.allocated", 47 (void *)&allocated, &sz, NULL, 0), expected, 48 "Unexpected mallctl() result"); 49 sz = sizeof(uint64_t); 50 expect_d_eq(mallctl("stats.arenas.0.large.nmalloc", (void *)&nmalloc, 51 &sz, NULL, 0), expected, "Unexpected mallctl() result"); 52 expect_d_eq(mallctl("stats.arenas.0.large.ndalloc", (void *)&ndalloc, 53 &sz, NULL, 0), expected, "Unexpected mallctl() result"); 54 expect_d_eq(mallctl("stats.arenas.0.large.nrequests", 55 (void *)&nrequests, &sz, NULL, 0), expected, 56 "Unexpected mallctl() result"); 57 58 if (config_stats) { 59 expect_zu_gt(allocated, 0, 60 "allocated should be greater than zero"); 61 expect_u64_ge(nmalloc, ndalloc, 62 "nmalloc should be at least as large as ndalloc"); 63 expect_u64_le(nmalloc, nrequests, 64 "nmalloc should no larger than nrequests"); 65 } 66 67 dallocx(p, 0); 68 } 69 TEST_END 70 71 TEST_BEGIN(test_stats_arenas_summary) { 72 void *little, *large; 73 uint64_t epoch; 74 size_t sz; 75 int expected = config_stats ? 0 : ENOENT; 76 size_t mapped; 77 uint64_t dirty_npurge, dirty_nmadvise, dirty_purged; 78 uint64_t muzzy_npurge, muzzy_nmadvise, muzzy_purged; 79 80 little = mallocx(SC_SMALL_MAXCLASS, MALLOCX_ARENA(0)); 81 expect_ptr_not_null(little, "Unexpected mallocx() failure"); 82 large = mallocx((1U << SC_LG_LARGE_MINCLASS), 83 MALLOCX_ARENA(0)); 84 expect_ptr_not_null(large, "Unexpected mallocx() failure"); 85 86 dallocx(little, 0); 87 dallocx(large, 0); 88 89 expect_d_eq(mallctl("thread.tcache.flush", NULL, NULL, NULL, 0), 90 opt_tcache ? 0 : EFAULT, "Unexpected mallctl() result"); 91 expect_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0, 92 "Unexpected mallctl() failure"); 93 94 expect_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, sizeof(epoch)), 95 0, "Unexpected mallctl() failure"); 96 97 sz = sizeof(size_t); 98 expect_d_eq(mallctl("stats.arenas.0.mapped", (void *)&mapped, &sz, NULL, 99 0), expected, "Unexepected mallctl() result"); 100 101 sz = sizeof(uint64_t); 102 expect_d_eq(mallctl("stats.arenas.0.dirty_npurge", 103 (void *)&dirty_npurge, &sz, NULL, 0), expected, 104 "Unexepected mallctl() result"); 105 expect_d_eq(mallctl("stats.arenas.0.dirty_nmadvise", 106 (void *)&dirty_nmadvise, &sz, NULL, 0), expected, 107 "Unexepected mallctl() result"); 108 expect_d_eq(mallctl("stats.arenas.0.dirty_purged", 109 (void *)&dirty_purged, &sz, NULL, 0), expected, 110 "Unexepected mallctl() result"); 111 expect_d_eq(mallctl("stats.arenas.0.muzzy_npurge", 112 (void *)&muzzy_npurge, &sz, NULL, 0), expected, 113 "Unexepected mallctl() result"); 114 expect_d_eq(mallctl("stats.arenas.0.muzzy_nmadvise", 115 (void *)&muzzy_nmadvise, &sz, NULL, 0), expected, 116 "Unexepected mallctl() result"); 117 expect_d_eq(mallctl("stats.arenas.0.muzzy_purged", 118 (void *)&muzzy_purged, &sz, NULL, 0), expected, 119 "Unexepected mallctl() result"); 120 121 if (config_stats) { 122 if (!is_background_thread_enabled() && !opt_hpa) { 123 expect_u64_gt(dirty_npurge + muzzy_npurge, 0, 124 "At least one purge should have occurred"); 125 } 126 expect_u64_le(dirty_nmadvise, dirty_purged, 127 "dirty_nmadvise should be no greater than dirty_purged"); 128 expect_u64_le(muzzy_nmadvise, muzzy_purged, 129 "muzzy_nmadvise should be no greater than muzzy_purged"); 130 } 131 } 132 TEST_END 133 134 void * 135 thd_start(void *arg) { 136 return NULL; 137 } 138 139 static void 140 no_lazy_lock(void) { 141 thd_t thd; 142 143 thd_create(&thd, thd_start, NULL); 144 thd_join(thd, NULL); 145 } 146 147 TEST_BEGIN(test_stats_arenas_small) { 148 void *p; 149 size_t sz, allocated; 150 uint64_t epoch, nmalloc, ndalloc, nrequests; 151 int expected = config_stats ? 0 : ENOENT; 152 153 no_lazy_lock(); /* Lazy locking would dodge tcache testing. */ 154 155 p = mallocx(SC_SMALL_MAXCLASS, MALLOCX_ARENA(0)); 156 expect_ptr_not_null(p, "Unexpected mallocx() failure"); 157 158 expect_d_eq(mallctl("thread.tcache.flush", NULL, NULL, NULL, 0), 159 opt_tcache ? 0 : EFAULT, "Unexpected mallctl() result"); 160 161 expect_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, sizeof(epoch)), 162 0, "Unexpected mallctl() failure"); 163 164 sz = sizeof(size_t); 165 expect_d_eq(mallctl("stats.arenas.0.small.allocated", 166 (void *)&allocated, &sz, NULL, 0), expected, 167 "Unexpected mallctl() result"); 168 sz = sizeof(uint64_t); 169 expect_d_eq(mallctl("stats.arenas.0.small.nmalloc", (void *)&nmalloc, 170 &sz, NULL, 0), expected, "Unexpected mallctl() result"); 171 expect_d_eq(mallctl("stats.arenas.0.small.ndalloc", (void *)&ndalloc, 172 &sz, NULL, 0), expected, "Unexpected mallctl() result"); 173 expect_d_eq(mallctl("stats.arenas.0.small.nrequests", 174 (void *)&nrequests, &sz, NULL, 0), expected, 175 "Unexpected mallctl() result"); 176 177 if (config_stats) { 178 expect_zu_gt(allocated, 0, 179 "allocated should be greater than zero"); 180 expect_u64_gt(nmalloc, 0, 181 "nmalloc should be no greater than zero"); 182 expect_u64_ge(nmalloc, ndalloc, 183 "nmalloc should be at least as large as ndalloc"); 184 expect_u64_gt(nrequests, 0, 185 "nrequests should be greater than zero"); 186 } 187 188 dallocx(p, 0); 189 } 190 TEST_END 191 192 TEST_BEGIN(test_stats_arenas_large) { 193 void *p; 194 size_t sz, allocated; 195 uint64_t epoch, nmalloc, ndalloc; 196 int expected = config_stats ? 0 : ENOENT; 197 198 p = mallocx((1U << SC_LG_LARGE_MINCLASS), MALLOCX_ARENA(0)); 199 expect_ptr_not_null(p, "Unexpected mallocx() failure"); 200 201 expect_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, sizeof(epoch)), 202 0, "Unexpected mallctl() failure"); 203 204 sz = sizeof(size_t); 205 expect_d_eq(mallctl("stats.arenas.0.large.allocated", 206 (void *)&allocated, &sz, NULL, 0), expected, 207 "Unexpected mallctl() result"); 208 sz = sizeof(uint64_t); 209 expect_d_eq(mallctl("stats.arenas.0.large.nmalloc", (void *)&nmalloc, 210 &sz, NULL, 0), expected, "Unexpected mallctl() result"); 211 expect_d_eq(mallctl("stats.arenas.0.large.ndalloc", (void *)&ndalloc, 212 &sz, NULL, 0), expected, "Unexpected mallctl() result"); 213 214 if (config_stats) { 215 expect_zu_gt(allocated, 0, 216 "allocated should be greater than zero"); 217 expect_u64_gt(nmalloc, 0, 218 "nmalloc should be greater than zero"); 219 expect_u64_ge(nmalloc, ndalloc, 220 "nmalloc should be at least as large as ndalloc"); 221 } 222 223 dallocx(p, 0); 224 } 225 TEST_END 226 227 static void 228 gen_mallctl_str(char *cmd, char *name, unsigned arena_ind) { 229 sprintf(cmd, "stats.arenas.%u.bins.0.%s", arena_ind, name); 230 } 231 232 TEST_BEGIN(test_stats_arenas_bins) { 233 void *p; 234 size_t sz, curslabs, curregs, nonfull_slabs; 235 uint64_t epoch, nmalloc, ndalloc, nrequests, nfills, nflushes; 236 uint64_t nslabs, nreslabs; 237 int expected = config_stats ? 0 : ENOENT; 238 239 /* Make sure allocation below isn't satisfied by tcache. */ 240 expect_d_eq(mallctl("thread.tcache.flush", NULL, NULL, NULL, 0), 241 opt_tcache ? 0 : EFAULT, "Unexpected mallctl() result"); 242 243 unsigned arena_ind, old_arena_ind; 244 sz = sizeof(unsigned); 245 expect_d_eq(mallctl("arenas.create", (void *)&arena_ind, &sz, NULL, 0), 246 0, "Arena creation failure"); 247 sz = sizeof(arena_ind); 248 expect_d_eq(mallctl("thread.arena", (void *)&old_arena_ind, &sz, 249 (void *)&arena_ind, sizeof(arena_ind)), 0, 250 "Unexpected mallctl() failure"); 251 252 p = malloc(bin_infos[0].reg_size); 253 expect_ptr_not_null(p, "Unexpected malloc() failure"); 254 255 expect_d_eq(mallctl("thread.tcache.flush", NULL, NULL, NULL, 0), 256 opt_tcache ? 0 : EFAULT, "Unexpected mallctl() result"); 257 258 expect_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, sizeof(epoch)), 259 0, "Unexpected mallctl() failure"); 260 261 char cmd[128]; 262 sz = sizeof(uint64_t); 263 gen_mallctl_str(cmd, "nmalloc", arena_ind); 264 expect_d_eq(mallctl(cmd, (void *)&nmalloc, &sz, NULL, 0), expected, 265 "Unexpected mallctl() result"); 266 gen_mallctl_str(cmd, "ndalloc", arena_ind); 267 expect_d_eq(mallctl(cmd, (void *)&ndalloc, &sz, NULL, 0), expected, 268 "Unexpected mallctl() result"); 269 gen_mallctl_str(cmd, "nrequests", arena_ind); 270 expect_d_eq(mallctl(cmd, (void *)&nrequests, &sz, NULL, 0), expected, 271 "Unexpected mallctl() result"); 272 sz = sizeof(size_t); 273 gen_mallctl_str(cmd, "curregs", arena_ind); 274 expect_d_eq(mallctl(cmd, (void *)&curregs, &sz, NULL, 0), expected, 275 "Unexpected mallctl() result"); 276 277 sz = sizeof(uint64_t); 278 gen_mallctl_str(cmd, "nfills", arena_ind); 279 expect_d_eq(mallctl(cmd, (void *)&nfills, &sz, NULL, 0), expected, 280 "Unexpected mallctl() result"); 281 gen_mallctl_str(cmd, "nflushes", arena_ind); 282 expect_d_eq(mallctl(cmd, (void *)&nflushes, &sz, NULL, 0), expected, 283 "Unexpected mallctl() result"); 284 285 gen_mallctl_str(cmd, "nslabs", arena_ind); 286 expect_d_eq(mallctl(cmd, (void *)&nslabs, &sz, NULL, 0), expected, 287 "Unexpected mallctl() result"); 288 gen_mallctl_str(cmd, "nreslabs", arena_ind); 289 expect_d_eq(mallctl(cmd, (void *)&nreslabs, &sz, NULL, 0), expected, 290 "Unexpected mallctl() result"); 291 sz = sizeof(size_t); 292 gen_mallctl_str(cmd, "curslabs", arena_ind); 293 expect_d_eq(mallctl(cmd, (void *)&curslabs, &sz, NULL, 0), expected, 294 "Unexpected mallctl() result"); 295 gen_mallctl_str(cmd, "nonfull_slabs", arena_ind); 296 expect_d_eq(mallctl(cmd, (void *)&nonfull_slabs, &sz, NULL, 0), 297 expected, "Unexpected mallctl() result"); 298 299 if (config_stats) { 300 expect_u64_gt(nmalloc, 0, 301 "nmalloc should be greater than zero"); 302 expect_u64_ge(nmalloc, ndalloc, 303 "nmalloc should be at least as large as ndalloc"); 304 expect_u64_gt(nrequests, 0, 305 "nrequests should be greater than zero"); 306 expect_zu_gt(curregs, 0, 307 "allocated should be greater than zero"); 308 if (opt_tcache) { 309 expect_u64_gt(nfills, 0, 310 "At least one fill should have occurred"); 311 expect_u64_gt(nflushes, 0, 312 "At least one flush should have occurred"); 313 } 314 expect_u64_gt(nslabs, 0, 315 "At least one slab should have been allocated"); 316 expect_zu_gt(curslabs, 0, 317 "At least one slab should be currently allocated"); 318 expect_zu_eq(nonfull_slabs, 0, 319 "slabs_nonfull should be empty"); 320 } 321 322 dallocx(p, 0); 323 } 324 TEST_END 325 326 TEST_BEGIN(test_stats_arenas_lextents) { 327 void *p; 328 uint64_t epoch, nmalloc, ndalloc; 329 size_t curlextents, sz, hsize; 330 int expected = config_stats ? 0 : ENOENT; 331 332 sz = sizeof(size_t); 333 expect_d_eq(mallctl("arenas.lextent.0.size", (void *)&hsize, &sz, NULL, 334 0), 0, "Unexpected mallctl() failure"); 335 336 p = mallocx(hsize, MALLOCX_ARENA(0)); 337 expect_ptr_not_null(p, "Unexpected mallocx() failure"); 338 339 expect_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, sizeof(epoch)), 340 0, "Unexpected mallctl() failure"); 341 342 sz = sizeof(uint64_t); 343 expect_d_eq(mallctl("stats.arenas.0.lextents.0.nmalloc", 344 (void *)&nmalloc, &sz, NULL, 0), expected, 345 "Unexpected mallctl() result"); 346 expect_d_eq(mallctl("stats.arenas.0.lextents.0.ndalloc", 347 (void *)&ndalloc, &sz, NULL, 0), expected, 348 "Unexpected mallctl() result"); 349 sz = sizeof(size_t); 350 expect_d_eq(mallctl("stats.arenas.0.lextents.0.curlextents", 351 (void *)&curlextents, &sz, NULL, 0), expected, 352 "Unexpected mallctl() result"); 353 354 if (config_stats) { 355 expect_u64_gt(nmalloc, 0, 356 "nmalloc should be greater than zero"); 357 expect_u64_ge(nmalloc, ndalloc, 358 "nmalloc should be at least as large as ndalloc"); 359 expect_u64_gt(curlextents, 0, 360 "At least one extent should be currently allocated"); 361 } 362 363 dallocx(p, 0); 364 } 365 TEST_END 366 367 static void 368 test_tcache_bytes_for_usize(size_t usize) { 369 uint64_t epoch; 370 size_t tcache_bytes, tcache_stashed_bytes; 371 size_t sz = sizeof(tcache_bytes); 372 373 void *ptr = mallocx(usize, 0); 374 375 expect_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, sizeof(epoch)), 376 0, "Unexpected mallctl() failure"); 377 assert_d_eq(mallctl( 378 "stats.arenas." STRINGIFY(MALLCTL_ARENAS_ALL) ".tcache_bytes", 379 &tcache_bytes, &sz, NULL, 0), 0, "Unexpected mallctl failure"); 380 assert_d_eq(mallctl( 381 "stats.arenas." STRINGIFY(MALLCTL_ARENAS_ALL) 382 ".tcache_stashed_bytes", &tcache_stashed_bytes, &sz, NULL, 0), 0, 383 "Unexpected mallctl failure"); 384 size_t tcache_bytes_before = tcache_bytes + tcache_stashed_bytes; 385 dallocx(ptr, 0); 386 387 expect_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, sizeof(epoch)), 388 0, "Unexpected mallctl() failure"); 389 assert_d_eq(mallctl( 390 "stats.arenas." STRINGIFY(MALLCTL_ARENAS_ALL) ".tcache_bytes", 391 &tcache_bytes, &sz, NULL, 0), 0, "Unexpected mallctl failure"); 392 assert_d_eq(mallctl( 393 "stats.arenas." STRINGIFY(MALLCTL_ARENAS_ALL) 394 ".tcache_stashed_bytes", &tcache_stashed_bytes, &sz, NULL, 0), 0, 395 "Unexpected mallctl failure"); 396 size_t tcache_bytes_after = tcache_bytes + tcache_stashed_bytes; 397 assert_zu_eq(tcache_bytes_after - tcache_bytes_before, 398 usize, "Incorrectly attributed a free"); 399 } 400 401 TEST_BEGIN(test_stats_tcache_bytes_small) { 402 test_skip_if(!config_stats); 403 test_skip_if(!opt_tcache); 404 test_skip_if(opt_tcache_max < SC_SMALL_MAXCLASS); 405 406 test_tcache_bytes_for_usize(SC_SMALL_MAXCLASS); 407 } 408 TEST_END 409 410 TEST_BEGIN(test_stats_tcache_bytes_large) { 411 test_skip_if(!config_stats); 412 test_skip_if(!opt_tcache); 413 test_skip_if(opt_tcache_max < SC_LARGE_MINCLASS); 414 415 test_tcache_bytes_for_usize(SC_LARGE_MINCLASS); 416 } 417 TEST_END 418 419 int 420 main(void) { 421 return test_no_reentrancy( 422 test_stats_summary, 423 test_stats_large, 424 test_stats_arenas_summary, 425 test_stats_arenas_small, 426 test_stats_arenas_large, 427 test_stats_arenas_bins, 428 test_stats_arenas_lextents, 429 test_stats_tcache_bytes_small, 430 test_stats_tcache_bytes_large); 431 } 432