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