1 1.1 christos #include "test/jemalloc_test.h" 2 1.1 christos 3 1.1 christos #include "jemalloc/internal/hpa.h" 4 1.1 christos #include "jemalloc/internal/nstime.h" 5 1.1 christos 6 1.1 christos #define SHARD_IND 111 7 1.1 christos 8 1.1 christos #define ALLOC_MAX (HUGEPAGE) 9 1.1 christos 10 1.1 christos typedef struct test_data_s test_data_t; 11 1.1 christos struct test_data_s { 12 1.1 christos /* 13 1.1 christos * Must be the first member -- we convert back and forth between the 14 1.1 christos * test_data_t and the hpa_shard_t; 15 1.1 christos */ 16 1.1 christos hpa_shard_t shard; 17 1.1 christos hpa_central_t central; 18 1.1 christos base_t *base; 19 1.1 christos edata_cache_t shard_edata_cache; 20 1.1 christos 21 1.1 christos emap_t emap; 22 1.1 christos }; 23 1.1 christos 24 1.1 christos static hpa_shard_opts_t test_hpa_shard_opts_aggressive = { 25 1.1 christos /* slab_max_alloc */ 26 1.1 christos HUGEPAGE, 27 1.1 christos /* hugification_threshold */ 28 1.1 christos 0.9 * HUGEPAGE, 29 1.1 christos /* dirty_mult */ 30 1.1 christos FXP_INIT_PERCENT(11), 31 1.1 christos /* deferral_allowed */ 32 1.1 christos true, 33 1.1 christos /* hugify_delay_ms */ 34 1.1 christos 0, 35 1.1 christos /* hugify_sync */ 36 1.1 christos false, 37 1.1 christos /* min_purge_interval_ms */ 38 1.1 christos 5, 39 1.1 christos /* experimental_max_purge_nhp */ 40 1.1 christos -1, 41 1.1 christos /* purge_threshold */ 42 1.1 christos HUGEPAGE - 5 * PAGE, 43 1.1 christos /* min_purge_delay_ms */ 44 1.1 christos 10, 45 1.1 christos /* hugify_style */ 46 1.1 christos hpa_hugify_style_eager}; 47 1.1 christos 48 1.1 christos static hpa_shard_t * 49 1.1 christos create_test_data(const hpa_hooks_t *hooks, hpa_shard_opts_t *opts) { 50 1.1 christos bool err; 51 1.1 christos base_t *base = base_new(TSDN_NULL, /* ind */ SHARD_IND, 52 1.1 christos &ehooks_default_extent_hooks, /* metadata_use_hooks */ true); 53 1.1 christos assert_ptr_not_null(base, ""); 54 1.1 christos 55 1.1 christos test_data_t *test_data = malloc(sizeof(test_data_t)); 56 1.1 christos assert_ptr_not_null(test_data, ""); 57 1.1 christos 58 1.1 christos test_data->base = base; 59 1.1 christos 60 1.1 christos err = edata_cache_init(&test_data->shard_edata_cache, base); 61 1.1 christos assert_false(err, ""); 62 1.1 christos 63 1.1 christos err = emap_init(&test_data->emap, test_data->base, /* zeroed */ false); 64 1.1 christos assert_false(err, ""); 65 1.1 christos 66 1.1 christos err = hpa_central_init(&test_data->central, test_data->base, hooks); 67 1.1 christos assert_false(err, ""); 68 1.1 christos sec_opts_t sec_opts; 69 1.1 christos sec_opts.nshards = 0; 70 1.1 christos tsdn_t *tsdn = tsd_tsdn(tsd_fetch()); 71 1.1 christos err = hpa_shard_init(tsdn, &test_data->shard, &test_data->central, 72 1.1 christos &test_data->emap, test_data->base, &test_data->shard_edata_cache, 73 1.1 christos SHARD_IND, opts, &sec_opts); 74 1.1 christos assert_false(err, ""); 75 1.1 christos 76 1.1 christos return (hpa_shard_t *)test_data; 77 1.1 christos } 78 1.1 christos 79 1.1 christos static void 80 1.1 christos destroy_test_data(hpa_shard_t *shard) { 81 1.1 christos test_data_t *test_data = (test_data_t *)shard; 82 1.1 christos base_delete(TSDN_NULL, test_data->base); 83 1.1 christos free(test_data); 84 1.1 christos } 85 1.1 christos 86 1.1 christos static uintptr_t defer_bump_ptr = HUGEPAGE * 123; 87 1.1 christos static void * 88 1.1 christos defer_test_map(size_t size) { 89 1.1 christos void *result = (void *)defer_bump_ptr; 90 1.1 christos defer_bump_ptr += size; 91 1.1 christos return result; 92 1.1 christos } 93 1.1 christos 94 1.1 christos static void 95 1.1 christos defer_test_unmap(void *ptr, size_t size) { 96 1.1 christos (void)ptr; 97 1.1 christos (void)size; 98 1.1 christos } 99 1.1 christos 100 1.1 christos static size_t ndefer_purge_calls = 0; 101 1.1 christos static size_t npurge_size = 0; 102 1.1 christos static void 103 1.1 christos defer_test_purge(void *ptr, size_t size) { 104 1.1 christos (void)ptr; 105 1.1 christos npurge_size = size; 106 1.1 christos ++ndefer_purge_calls; 107 1.1 christos } 108 1.1 christos 109 1.1 christos static bool defer_vectorized_purge_called = false; 110 1.1 christos static bool 111 1.1 christos defer_vectorized_purge(void *vec, size_t vlen, size_t nbytes) { 112 1.1 christos (void)vec; 113 1.1 christos (void)nbytes; 114 1.1 christos ++ndefer_purge_calls; 115 1.1 christos defer_vectorized_purge_called = true; 116 1.1 christos return false; 117 1.1 christos } 118 1.1 christos 119 1.1 christos static size_t ndefer_hugify_calls = 0; 120 1.1 christos static bool 121 1.1 christos defer_test_hugify(void *ptr, size_t size, bool sync) { 122 1.1 christos ++ndefer_hugify_calls; 123 1.1 christos return false; 124 1.1 christos } 125 1.1 christos 126 1.1 christos static size_t ndefer_dehugify_calls = 0; 127 1.1 christos static void 128 1.1 christos defer_test_dehugify(void *ptr, size_t size) { 129 1.1 christos ++ndefer_dehugify_calls; 130 1.1 christos } 131 1.1 christos 132 1.1 christos static nstime_t defer_curtime; 133 1.1 christos static void 134 1.1 christos defer_test_curtime(nstime_t *r_time, bool first_reading) { 135 1.1 christos *r_time = defer_curtime; 136 1.1 christos } 137 1.1 christos 138 1.1 christos static uint64_t 139 1.1 christos defer_test_ms_since(nstime_t *past_time) { 140 1.1 christos return (nstime_ns(&defer_curtime) - nstime_ns(past_time)) / 1000 / 1000; 141 1.1 christos } 142 1.1 christos 143 1.1 christos TEST_BEGIN(test_hpa_hugify_style_none_huge_no_syscall_thp_always) { 144 1.1 christos test_skip_if(!hpa_supported() || (opt_process_madvise_max_batch != 0)); 145 1.1 christos 146 1.1 christos hpa_hooks_t hooks; 147 1.1 christos hooks.map = &defer_test_map; 148 1.1 christos hooks.unmap = &defer_test_unmap; 149 1.1 christos hooks.purge = &defer_test_purge; 150 1.1 christos hooks.hugify = &defer_test_hugify; 151 1.1 christos hooks.dehugify = &defer_test_dehugify; 152 1.1 christos hooks.curtime = &defer_test_curtime; 153 1.1 christos hooks.ms_since = &defer_test_ms_since; 154 1.1 christos hooks.vectorized_purge = &defer_vectorized_purge; 155 1.1 christos 156 1.1 christos hpa_shard_opts_t opts = test_hpa_shard_opts_aggressive; 157 1.1 christos opts.deferral_allowed = true; 158 1.1 christos opts.purge_threshold = PAGE; 159 1.1 christos opts.min_purge_delay_ms = 0; 160 1.1 christos opts.hugification_threshold = HUGEPAGE * 0.25; 161 1.1 christos opts.dirty_mult = FXP_INIT_PERCENT(10); 162 1.1 christos opts.hugify_style = hpa_hugify_style_none; 163 1.1 christos opts.min_purge_interval_ms = 0; 164 1.1 christos opts.hugify_delay_ms = 0; 165 1.1 christos 166 1.1 christos hpa_shard_t *shard = create_test_data(&hooks, &opts); 167 1.1 christos bool deferred_work_generated = false; 168 1.1 christos /* Current time = 10ms */ 169 1.1 christos nstime_init(&defer_curtime, 10 * 1000 * 1000); 170 1.1 christos 171 1.1 christos /* Fake that system is in thp_always mode */ 172 1.1 christos system_thp_mode_t old_mode = init_system_thp_mode; 173 1.1 christos init_system_thp_mode = system_thp_mode_always; 174 1.1 christos 175 1.1 christos tsdn_t *tsdn = tsd_tsdn(tsd_fetch()); 176 1.1 christos enum { NALLOCS = HUGEPAGE_PAGES }; 177 1.1 christos edata_t *edatas[NALLOCS]; 178 1.1 christos ndefer_purge_calls = 0; 179 1.1 christos for (int i = 0; i < NALLOCS / 2; i++) { 180 1.1 christos edatas[i] = pai_alloc(tsdn, &shard->pai, PAGE, PAGE, false, 181 1.1 christos false, false, &deferred_work_generated); 182 1.1 christos expect_ptr_not_null(edatas[i], "Unexpected null edata"); 183 1.1 christos } 184 1.1 christos hpdata_t *ps = psset_pick_alloc(&shard->psset, PAGE); 185 1.1 christos expect_true(hpdata_huge_get(ps), 186 1.1 christos "Page should be huge because thp=always and hugify_style is none"); 187 1.1 christos 188 1.1 christos ndefer_hugify_calls = 0; 189 1.1 christos ndefer_purge_calls = 0; 190 1.1 christos hpa_shard_do_deferred_work(tsdn, shard); 191 1.1 christos expect_zu_eq(ndefer_hugify_calls, 0, "style=none, no syscall"); 192 1.1 christos expect_zu_eq(ndefer_dehugify_calls, 0, "style=none, no syscall"); 193 1.1 christos expect_zu_eq(ndefer_purge_calls, 1, "purge should happen"); 194 1.1 christos 195 1.1 christos destroy_test_data(shard); 196 1.1 christos init_system_thp_mode = old_mode; 197 1.1 christos } 198 1.1 christos TEST_END 199 1.1 christos 200 1.1 christos int 201 1.1 christos main(void) { 202 1.1 christos return test_no_reentrancy( 203 1.1 christos test_hpa_hugify_style_none_huge_no_syscall_thp_always); 204 1.1 christos } 205