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