1 1.1 christos #include "test/jemalloc_test.h" 2 1.1 christos 3 1.1.1.2 christos #include "jemalloc/internal/prof_data.h" 4 1.1.1.2 christos #include "jemalloc/internal/prof_sys.h" 5 1.1.1.2 christos 6 1.1 christos static int 7 1.1.1.2 christos prof_dump_open_file_intercept(const char *filename, int mode) { 8 1.1 christos int fd; 9 1.1 christos 10 1.1 christos fd = open("/dev/null", O_WRONLY); 11 1.1 christos assert_d_ne(fd, -1, "Unexpected open() failure"); 12 1.1 christos 13 1.1 christos return fd; 14 1.1 christos } 15 1.1 christos 16 1.1 christos static void 17 1.1 christos set_prof_active(bool active) { 18 1.1.1.2 christos expect_d_eq(mallctl("prof.active", NULL, NULL, (void *)&active, 19 1.1 christos sizeof(active)), 0, "Unexpected mallctl failure"); 20 1.1 christos } 21 1.1 christos 22 1.1 christos static size_t 23 1.1 christos get_lg_prof_sample(void) { 24 1.1.1.2 christos size_t ret; 25 1.1 christos size_t sz = sizeof(size_t); 26 1.1 christos 27 1.1.1.2 christos expect_d_eq(mallctl("prof.lg_sample", (void *)&ret, &sz, NULL, 0), 0, 28 1.1 christos "Unexpected mallctl failure while reading profiling sample rate"); 29 1.1.1.2 christos return ret; 30 1.1 christos } 31 1.1 christos 32 1.1 christos static void 33 1.1.1.2 christos do_prof_reset(size_t lg_prof_sample_input) { 34 1.1.1.2 christos expect_d_eq(mallctl("prof.reset", NULL, NULL, 35 1.1.1.2 christos (void *)&lg_prof_sample_input, sizeof(size_t)), 0, 36 1.1 christos "Unexpected mallctl failure while resetting profile data"); 37 1.1.1.2 christos expect_zu_eq(lg_prof_sample_input, get_lg_prof_sample(), 38 1.1 christos "Expected profile sample rate change"); 39 1.1 christos } 40 1.1 christos 41 1.1 christos TEST_BEGIN(test_prof_reset_basic) { 42 1.1.1.2 christos size_t lg_prof_sample_orig, lg_prof_sample_cur, lg_prof_sample_next; 43 1.1 christos size_t sz; 44 1.1 christos unsigned i; 45 1.1 christos 46 1.1 christos test_skip_if(!config_prof); 47 1.1 christos 48 1.1 christos sz = sizeof(size_t); 49 1.1.1.2 christos expect_d_eq(mallctl("opt.lg_prof_sample", (void *)&lg_prof_sample_orig, 50 1.1 christos &sz, NULL, 0), 0, 51 1.1 christos "Unexpected mallctl failure while reading profiling sample rate"); 52 1.1.1.2 christos expect_zu_eq(lg_prof_sample_orig, 0, 53 1.1 christos "Unexpected profiling sample rate"); 54 1.1.1.2 christos lg_prof_sample_cur = get_lg_prof_sample(); 55 1.1.1.2 christos expect_zu_eq(lg_prof_sample_orig, lg_prof_sample_cur, 56 1.1 christos "Unexpected disagreement between \"opt.lg_prof_sample\" and " 57 1.1 christos "\"prof.lg_sample\""); 58 1.1 christos 59 1.1 christos /* Test simple resets. */ 60 1.1 christos for (i = 0; i < 2; i++) { 61 1.1.1.2 christos expect_d_eq(mallctl("prof.reset", NULL, NULL, NULL, 0), 0, 62 1.1 christos "Unexpected mallctl failure while resetting profile data"); 63 1.1.1.2 christos lg_prof_sample_cur = get_lg_prof_sample(); 64 1.1.1.2 christos expect_zu_eq(lg_prof_sample_orig, lg_prof_sample_cur, 65 1.1 christos "Unexpected profile sample rate change"); 66 1.1 christos } 67 1.1 christos 68 1.1 christos /* Test resets with prof.lg_sample changes. */ 69 1.1 christos lg_prof_sample_next = 1; 70 1.1 christos for (i = 0; i < 2; i++) { 71 1.1 christos do_prof_reset(lg_prof_sample_next); 72 1.1.1.2 christos lg_prof_sample_cur = get_lg_prof_sample(); 73 1.1.1.2 christos expect_zu_eq(lg_prof_sample_cur, lg_prof_sample_next, 74 1.1 christos "Expected profile sample rate change"); 75 1.1 christos lg_prof_sample_next = lg_prof_sample_orig; 76 1.1 christos } 77 1.1 christos 78 1.1 christos /* Make sure the test code restored prof.lg_sample. */ 79 1.1.1.2 christos lg_prof_sample_cur = get_lg_prof_sample(); 80 1.1.1.2 christos expect_zu_eq(lg_prof_sample_orig, lg_prof_sample_cur, 81 1.1 christos "Unexpected disagreement between \"opt.lg_prof_sample\" and " 82 1.1 christos "\"prof.lg_sample\""); 83 1.1 christos } 84 1.1 christos TEST_END 85 1.1 christos 86 1.1 christos TEST_BEGIN(test_prof_reset_cleanup) { 87 1.1 christos test_skip_if(!config_prof); 88 1.1 christos 89 1.1 christos set_prof_active(true); 90 1.1 christos 91 1.1.1.2 christos expect_zu_eq(prof_bt_count(), 0, "Expected 0 backtraces"); 92 1.1.1.2 christos void *p = mallocx(1, 0); 93 1.1.1.2 christos expect_ptr_not_null(p, "Unexpected mallocx() failure"); 94 1.1.1.2 christos expect_zu_eq(prof_bt_count(), 1, "Expected 1 backtrace"); 95 1.1.1.2 christos 96 1.1.1.2 christos prof_cnt_t cnt_all; 97 1.1.1.2 christos prof_cnt_all(&cnt_all); 98 1.1.1.2 christos expect_u64_eq(cnt_all.curobjs, 1, "Expected 1 allocation"); 99 1.1 christos 100 1.1.1.2 christos expect_d_eq(mallctl("prof.reset", NULL, NULL, NULL, 0), 0, 101 1.1 christos "Unexpected error while resetting heap profile data"); 102 1.1.1.2 christos prof_cnt_all(&cnt_all); 103 1.1.1.2 christos expect_u64_eq(cnt_all.curobjs, 0, "Expected 0 allocations"); 104 1.1.1.2 christos expect_zu_eq(prof_bt_count(), 1, "Expected 1 backtrace"); 105 1.1 christos 106 1.1 christos dallocx(p, 0); 107 1.1.1.2 christos expect_zu_eq(prof_bt_count(), 0, "Expected 0 backtraces"); 108 1.1 christos 109 1.1 christos set_prof_active(false); 110 1.1 christos } 111 1.1 christos TEST_END 112 1.1 christos 113 1.1 christos #define NTHREADS 4 114 1.1 christos #define NALLOCS_PER_THREAD (1U << 13) 115 1.1 christos #define OBJ_RING_BUF_COUNT 1531 116 1.1 christos #define RESET_INTERVAL (1U << 10) 117 1.1 christos #define DUMP_INTERVAL 3677 118 1.1 christos static void * 119 1.1 christos thd_start(void *varg) { 120 1.1 christos unsigned thd_ind = *(unsigned *)varg; 121 1.1 christos unsigned i; 122 1.1 christos void *objs[OBJ_RING_BUF_COUNT]; 123 1.1 christos 124 1.1 christos memset(objs, 0, sizeof(objs)); 125 1.1 christos 126 1.1 christos for (i = 0; i < NALLOCS_PER_THREAD; i++) { 127 1.1 christos if (i % RESET_INTERVAL == 0) { 128 1.1.1.2 christos expect_d_eq(mallctl("prof.reset", NULL, NULL, NULL, 0), 129 1.1 christos 0, "Unexpected error while resetting heap profile " 130 1.1 christos "data"); 131 1.1 christos } 132 1.1 christos 133 1.1 christos if (i % DUMP_INTERVAL == 0) { 134 1.1.1.2 christos expect_d_eq(mallctl("prof.dump", NULL, NULL, NULL, 0), 135 1.1 christos 0, "Unexpected error while dumping heap profile"); 136 1.1 christos } 137 1.1 christos 138 1.1 christos { 139 1.1 christos void **pp = &objs[i % OBJ_RING_BUF_COUNT]; 140 1.1 christos if (*pp != NULL) { 141 1.1 christos dallocx(*pp, 0); 142 1.1 christos *pp = NULL; 143 1.1 christos } 144 1.1 christos *pp = btalloc(1, thd_ind*NALLOCS_PER_THREAD + i); 145 1.1.1.2 christos expect_ptr_not_null(*pp, 146 1.1 christos "Unexpected btalloc() failure"); 147 1.1 christos } 148 1.1 christos } 149 1.1 christos 150 1.1 christos /* Clean up any remaining objects. */ 151 1.1 christos for (i = 0; i < OBJ_RING_BUF_COUNT; i++) { 152 1.1 christos void **pp = &objs[i % OBJ_RING_BUF_COUNT]; 153 1.1 christos if (*pp != NULL) { 154 1.1 christos dallocx(*pp, 0); 155 1.1 christos *pp = NULL; 156 1.1 christos } 157 1.1 christos } 158 1.1 christos 159 1.1 christos return NULL; 160 1.1 christos } 161 1.1 christos 162 1.1 christos TEST_BEGIN(test_prof_reset) { 163 1.1 christos size_t lg_prof_sample_orig; 164 1.1 christos thd_t thds[NTHREADS]; 165 1.1 christos unsigned thd_args[NTHREADS]; 166 1.1 christos unsigned i; 167 1.1 christos size_t bt_count, tdata_count; 168 1.1 christos 169 1.1 christos test_skip_if(!config_prof); 170 1.1 christos 171 1.1 christos bt_count = prof_bt_count(); 172 1.1.1.2 christos expect_zu_eq(bt_count, 0, 173 1.1 christos "Unexpected pre-existing tdata structures"); 174 1.1 christos tdata_count = prof_tdata_count(); 175 1.1 christos 176 1.1 christos lg_prof_sample_orig = get_lg_prof_sample(); 177 1.1 christos do_prof_reset(5); 178 1.1 christos 179 1.1 christos set_prof_active(true); 180 1.1 christos 181 1.1 christos for (i = 0; i < NTHREADS; i++) { 182 1.1 christos thd_args[i] = i; 183 1.1 christos thd_create(&thds[i], thd_start, (void *)&thd_args[i]); 184 1.1 christos } 185 1.1 christos for (i = 0; i < NTHREADS; i++) { 186 1.1 christos thd_join(thds[i], NULL); 187 1.1 christos } 188 1.1 christos 189 1.1.1.2 christos expect_zu_eq(prof_bt_count(), bt_count, 190 1.1 christos "Unexpected bactrace count change"); 191 1.1.1.2 christos expect_zu_eq(prof_tdata_count(), tdata_count, 192 1.1 christos "Unexpected remaining tdata structures"); 193 1.1 christos 194 1.1 christos set_prof_active(false); 195 1.1 christos 196 1.1 christos do_prof_reset(lg_prof_sample_orig); 197 1.1 christos } 198 1.1 christos TEST_END 199 1.1 christos #undef NTHREADS 200 1.1 christos #undef NALLOCS_PER_THREAD 201 1.1 christos #undef OBJ_RING_BUF_COUNT 202 1.1 christos #undef RESET_INTERVAL 203 1.1 christos #undef DUMP_INTERVAL 204 1.1 christos 205 1.1 christos /* Test sampling at the same allocation site across resets. */ 206 1.1 christos #define NITER 10 207 1.1 christos TEST_BEGIN(test_xallocx) { 208 1.1 christos size_t lg_prof_sample_orig; 209 1.1 christos unsigned i; 210 1.1 christos void *ptrs[NITER]; 211 1.1 christos 212 1.1 christos test_skip_if(!config_prof); 213 1.1 christos 214 1.1 christos lg_prof_sample_orig = get_lg_prof_sample(); 215 1.1 christos set_prof_active(true); 216 1.1 christos 217 1.1 christos /* Reset profiling. */ 218 1.1 christos do_prof_reset(0); 219 1.1 christos 220 1.1 christos for (i = 0; i < NITER; i++) { 221 1.1 christos void *p; 222 1.1 christos size_t sz, nsz; 223 1.1 christos 224 1.1 christos /* Reset profiling. */ 225 1.1 christos do_prof_reset(0); 226 1.1 christos 227 1.1 christos /* Allocate small object (which will be promoted). */ 228 1.1 christos p = ptrs[i] = mallocx(1, 0); 229 1.1.1.2 christos expect_ptr_not_null(p, "Unexpected mallocx() failure"); 230 1.1 christos 231 1.1 christos /* Reset profiling. */ 232 1.1 christos do_prof_reset(0); 233 1.1 christos 234 1.1 christos /* Perform successful xallocx(). */ 235 1.1 christos sz = sallocx(p, 0); 236 1.1.1.2 christos expect_zu_eq(xallocx(p, sz, 0, 0), sz, 237 1.1 christos "Unexpected xallocx() failure"); 238 1.1 christos 239 1.1 christos /* Perform unsuccessful xallocx(). */ 240 1.1 christos nsz = nallocx(sz+1, 0); 241 1.1.1.2 christos expect_zu_eq(xallocx(p, nsz, 0, 0), sz, 242 1.1 christos "Unexpected xallocx() success"); 243 1.1 christos } 244 1.1 christos 245 1.1 christos for (i = 0; i < NITER; i++) { 246 1.1 christos /* dallocx. */ 247 1.1 christos dallocx(ptrs[i], 0); 248 1.1 christos } 249 1.1 christos 250 1.1 christos set_prof_active(false); 251 1.1 christos do_prof_reset(lg_prof_sample_orig); 252 1.1 christos } 253 1.1 christos TEST_END 254 1.1 christos #undef NITER 255 1.1 christos 256 1.1 christos int 257 1.1 christos main(void) { 258 1.1 christos /* Intercept dumping prior to running any tests. */ 259 1.1.1.2 christos prof_dump_open_file = prof_dump_open_file_intercept; 260 1.1 christos 261 1.1 christos return test_no_reentrancy( 262 1.1 christos test_prof_reset_basic, 263 1.1 christos test_prof_reset_cleanup, 264 1.1 christos test_prof_reset, 265 1.1 christos test_xallocx); 266 1.1 christos } 267