diff options
Diffstat (limited to 'examples/redis-unstable/deps/jemalloc/test/analyze')
3 files changed, 389 insertions, 0 deletions
diff --git a/examples/redis-unstable/deps/jemalloc/test/analyze/prof_bias.c b/examples/redis-unstable/deps/jemalloc/test/analyze/prof_bias.c new file mode 100644 index 0000000..a96ca94 --- /dev/null +++ b/examples/redis-unstable/deps/jemalloc/test/analyze/prof_bias.c | |||
| @@ -0,0 +1,60 @@ | |||
| 1 | #include "test/jemalloc_test.h" | ||
| 2 | |||
| 3 | /* | ||
| 4 | * This is a helper utility, only meant to be run manually (and, for example, | ||
| 5 | * doesn't check for failures, try to skip execution in non-prof modes, etc.). | ||
| 6 | * It runs, allocates objects of two different sizes from the same stack trace, | ||
| 7 | * and exits. | ||
| 8 | * | ||
| 9 | * The idea is that some human operator will run it like: | ||
| 10 | * MALLOC_CONF="prof:true,prof_final:true" test/analyze/prof_bias | ||
| 11 | * and manually inspect the results. | ||
| 12 | * | ||
| 13 | * The results should be: | ||
| 14 | * jeprof --text test/analyze/prof_bias --inuse_space jeprof.<pid>.0.f.heap: | ||
| 15 | * around 1024 MB | ||
| 16 | * jeprof --text test/analyze/prof_bias --inuse_objects jeprof.<pid>.0.f.heap: | ||
| 17 | * around 33554448 = 16 + 32 * 1024 * 1024 | ||
| 18 | * | ||
| 19 | * And, if prof_accum is on: | ||
| 20 | * jeprof --text test/analyze/prof_bias --alloc_space jeprof.<pid>.0.f.heap: | ||
| 21 | * around 2048 MB | ||
| 22 | * jeprof --text test/analyze/prof_bias --alloc_objects jeprof.<pid>.0.f.heap: | ||
| 23 | * around 67108896 = 2 * (16 + 32 * 1024 * 1024) | ||
| 24 | */ | ||
| 25 | |||
| 26 | static void | ||
| 27 | mock_backtrace(void **vec, unsigned *len, unsigned max_len) { | ||
| 28 | *len = 4; | ||
| 29 | vec[0] = (void *)0x111; | ||
| 30 | vec[1] = (void *)0x222; | ||
| 31 | vec[2] = (void *)0x333; | ||
| 32 | vec[3] = (void *)0x444; | ||
| 33 | } | ||
| 34 | |||
| 35 | static void | ||
| 36 | do_allocs(size_t sz, size_t cnt, bool do_frees) { | ||
| 37 | for (size_t i = 0; i < cnt; i++) { | ||
| 38 | void *ptr = mallocx(sz, 0); | ||
| 39 | assert_ptr_not_null(ptr, "Unexpected mallocx failure"); | ||
| 40 | if (do_frees) { | ||
| 41 | dallocx(ptr, 0); | ||
| 42 | } | ||
| 43 | } | ||
| 44 | } | ||
| 45 | |||
| 46 | int | ||
| 47 | main(void) { | ||
| 48 | size_t lg_prof_sample_local = 19; | ||
| 49 | int err = mallctl("prof.reset", NULL, NULL, | ||
| 50 | (void *)&lg_prof_sample_local, sizeof(lg_prof_sample_local)); | ||
| 51 | assert(err == 0); | ||
| 52 | |||
| 53 | prof_backtrace_hook_set(mock_backtrace); | ||
| 54 | do_allocs(16, 32 * 1024 * 1024, /* do_frees */ true); | ||
| 55 | do_allocs(32 * 1024* 1024, 16, /* do_frees */ true); | ||
| 56 | do_allocs(16, 32 * 1024 * 1024, /* do_frees */ false); | ||
| 57 | do_allocs(32 * 1024* 1024, 16, /* do_frees */ false); | ||
| 58 | |||
| 59 | return 0; | ||
| 60 | } | ||
diff --git a/examples/redis-unstable/deps/jemalloc/test/analyze/rand.c b/examples/redis-unstable/deps/jemalloc/test/analyze/rand.c new file mode 100644 index 0000000..bb20b06 --- /dev/null +++ b/examples/redis-unstable/deps/jemalloc/test/analyze/rand.c | |||
| @@ -0,0 +1,276 @@ | |||
| 1 | #include "test/jemalloc_test.h" | ||
| 2 | |||
| 3 | /******************************************************************************/ | ||
| 4 | |||
| 5 | /* | ||
| 6 | * General purpose tool for examining random number distributions. | ||
| 7 | * | ||
| 8 | * Input - | ||
| 9 | * (a) a random number generator, and | ||
| 10 | * (b) the buckets: | ||
| 11 | * (1) number of buckets, | ||
| 12 | * (2) width of each bucket, in log scale, | ||
| 13 | * (3) expected mean and stddev of the count of random numbers in each | ||
| 14 | * bucket, and | ||
| 15 | * (c) number of iterations to invoke the generator. | ||
| 16 | * | ||
| 17 | * The program generates the specified amount of random numbers, and assess how | ||
| 18 | * well they conform to the expectations: for each bucket, output - | ||
| 19 | * (a) the (given) expected mean and stddev, | ||
| 20 | * (b) the actual count and any interesting level of deviation: | ||
| 21 | * (1) ~68% buckets should show no interesting deviation, meaning a | ||
| 22 | * deviation less than stddev from the expectation; | ||
| 23 | * (2) ~27% buckets should show '+' / '-', meaning a deviation in the range | ||
| 24 | * of [stddev, 2 * stddev) from the expectation; | ||
| 25 | * (3) ~4% buckets should show '++' / '--', meaning a deviation in the | ||
| 26 | * range of [2 * stddev, 3 * stddev) from the expectation; and | ||
| 27 | * (4) less than 0.3% buckets should show more than two '+'s / '-'s. | ||
| 28 | * | ||
| 29 | * Technical remarks: | ||
| 30 | * (a) The generator is expected to output uint64_t numbers, so you might need | ||
| 31 | * to define a wrapper. | ||
| 32 | * (b) The buckets must be of equal width and the lowest bucket starts at | ||
| 33 | * [0, 2^lg_bucket_width - 1). | ||
| 34 | * (c) Any generated number >= n_bucket * 2^lg_bucket_width will be counted | ||
| 35 | * towards the last bucket; the expected mean and stddev provided should | ||
| 36 | * also reflect that. | ||
| 37 | * (d) The number of iterations is advised to be determined so that the bucket | ||
| 38 | * with the minimal expected proportion gets a sufficient count. | ||
| 39 | */ | ||
| 40 | |||
| 41 | static void | ||
| 42 | fill(size_t a[], const size_t n, const size_t k) { | ||
| 43 | for (size_t i = 0; i < n; ++i) { | ||
| 44 | a[i] = k; | ||
| 45 | } | ||
| 46 | } | ||
| 47 | |||
| 48 | static void | ||
| 49 | collect_buckets(uint64_t (*gen)(void *), void *opaque, size_t buckets[], | ||
| 50 | const size_t n_bucket, const size_t lg_bucket_width, const size_t n_iter) { | ||
| 51 | for (size_t i = 0; i < n_iter; ++i) { | ||
| 52 | uint64_t num = gen(opaque); | ||
| 53 | uint64_t bucket_id = num >> lg_bucket_width; | ||
| 54 | if (bucket_id >= n_bucket) { | ||
| 55 | bucket_id = n_bucket - 1; | ||
| 56 | } | ||
| 57 | ++buckets[bucket_id]; | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | static void | ||
| 62 | print_buckets(const size_t buckets[], const size_t means[], | ||
| 63 | const size_t stddevs[], const size_t n_bucket) { | ||
| 64 | for (size_t i = 0; i < n_bucket; ++i) { | ||
| 65 | malloc_printf("%zu:\tmean = %zu,\tstddev = %zu,\tbucket = %zu", | ||
| 66 | i, means[i], stddevs[i], buckets[i]); | ||
| 67 | |||
| 68 | /* Make sure there's no overflow. */ | ||
| 69 | assert(buckets[i] + stddevs[i] >= stddevs[i]); | ||
| 70 | assert(means[i] + stddevs[i] >= stddevs[i]); | ||
| 71 | |||
| 72 | if (buckets[i] + stddevs[i] <= means[i]) { | ||
| 73 | malloc_write(" "); | ||
| 74 | for (size_t t = means[i] - buckets[i]; t >= stddevs[i]; | ||
| 75 | t -= stddevs[i]) { | ||
| 76 | malloc_write("-"); | ||
| 77 | } | ||
| 78 | } else if (buckets[i] >= means[i] + stddevs[i]) { | ||
| 79 | malloc_write(" "); | ||
| 80 | for (size_t t = buckets[i] - means[i]; t >= stddevs[i]; | ||
| 81 | t -= stddevs[i]) { | ||
| 82 | malloc_write("+"); | ||
| 83 | } | ||
| 84 | } | ||
| 85 | malloc_write("\n"); | ||
| 86 | } | ||
| 87 | } | ||
| 88 | |||
| 89 | static void | ||
| 90 | bucket_analysis(uint64_t (*gen)(void *), void *opaque, size_t buckets[], | ||
| 91 | const size_t means[], const size_t stddevs[], const size_t n_bucket, | ||
| 92 | const size_t lg_bucket_width, const size_t n_iter) { | ||
| 93 | for (size_t i = 1; i <= 3; ++i) { | ||
| 94 | malloc_printf("round %zu\n", i); | ||
| 95 | fill(buckets, n_bucket, 0); | ||
| 96 | collect_buckets(gen, opaque, buckets, n_bucket, | ||
| 97 | lg_bucket_width, n_iter); | ||
| 98 | print_buckets(buckets, means, stddevs, n_bucket); | ||
| 99 | } | ||
| 100 | } | ||
| 101 | |||
| 102 | /* (Recommended) minimal bucket mean. */ | ||
| 103 | #define MIN_BUCKET_MEAN 10000 | ||
| 104 | |||
| 105 | /******************************************************************************/ | ||
| 106 | |||
| 107 | /* Uniform random number generator. */ | ||
| 108 | |||
| 109 | typedef struct uniform_gen_arg_s uniform_gen_arg_t; | ||
| 110 | struct uniform_gen_arg_s { | ||
| 111 | uint64_t state; | ||
| 112 | const unsigned lg_range; | ||
| 113 | }; | ||
| 114 | |||
| 115 | static uint64_t | ||
| 116 | uniform_gen(void *opaque) { | ||
| 117 | uniform_gen_arg_t *arg = (uniform_gen_arg_t *)opaque; | ||
| 118 | return prng_lg_range_u64(&arg->state, arg->lg_range); | ||
| 119 | } | ||
| 120 | |||
| 121 | TEST_BEGIN(test_uniform) { | ||
| 122 | #define LG_N_BUCKET 5 | ||
| 123 | #define N_BUCKET (1 << LG_N_BUCKET) | ||
| 124 | |||
| 125 | #define QUOTIENT_CEIL(n, d) (((n) - 1) / (d) + 1) | ||
| 126 | |||
| 127 | const unsigned lg_range_test = 25; | ||
| 128 | |||
| 129 | /* | ||
| 130 | * Mathematical tricks to guarantee that both mean and stddev are | ||
| 131 | * integers, and that the minimal bucket mean is at least | ||
| 132 | * MIN_BUCKET_MEAN. | ||
| 133 | */ | ||
| 134 | const size_t q = 1 << QUOTIENT_CEIL(LG_CEIL(QUOTIENT_CEIL( | ||
| 135 | MIN_BUCKET_MEAN, N_BUCKET * (N_BUCKET - 1))), 2); | ||
| 136 | const size_t stddev = (N_BUCKET - 1) * q; | ||
| 137 | const size_t mean = N_BUCKET * stddev * q; | ||
| 138 | const size_t n_iter = N_BUCKET * mean; | ||
| 139 | |||
| 140 | size_t means[N_BUCKET]; | ||
| 141 | fill(means, N_BUCKET, mean); | ||
| 142 | size_t stddevs[N_BUCKET]; | ||
| 143 | fill(stddevs, N_BUCKET, stddev); | ||
| 144 | |||
| 145 | uniform_gen_arg_t arg = {(uint64_t)(uintptr_t)&lg_range_test, | ||
| 146 | lg_range_test}; | ||
| 147 | size_t buckets[N_BUCKET]; | ||
| 148 | assert_zu_ge(lg_range_test, LG_N_BUCKET, ""); | ||
| 149 | const size_t lg_bucket_width = lg_range_test - LG_N_BUCKET; | ||
| 150 | |||
| 151 | bucket_analysis(uniform_gen, &arg, buckets, means, stddevs, | ||
| 152 | N_BUCKET, lg_bucket_width, n_iter); | ||
| 153 | |||
| 154 | #undef LG_N_BUCKET | ||
| 155 | #undef N_BUCKET | ||
| 156 | #undef QUOTIENT_CEIL | ||
| 157 | } | ||
| 158 | TEST_END | ||
| 159 | |||
| 160 | /******************************************************************************/ | ||
| 161 | |||
| 162 | /* Geometric random number generator; compiled only when prof is on. */ | ||
| 163 | |||
| 164 | #ifdef JEMALLOC_PROF | ||
| 165 | |||
| 166 | /* | ||
| 167 | * Fills geometric proportions and returns the minimal proportion. See | ||
| 168 | * comments in test_prof_sample for explanations for n_divide. | ||
| 169 | */ | ||
| 170 | static double | ||
| 171 | fill_geometric_proportions(double proportions[], const size_t n_bucket, | ||
| 172 | const size_t n_divide) { | ||
| 173 | assert(n_bucket > 0); | ||
| 174 | assert(n_divide > 0); | ||
| 175 | double x = 1.; | ||
| 176 | for (size_t i = 0; i < n_bucket; ++i) { | ||
| 177 | if (i == n_bucket - 1) { | ||
| 178 | proportions[i] = x; | ||
| 179 | } else { | ||
| 180 | double y = x * exp(-1. / n_divide); | ||
| 181 | proportions[i] = x - y; | ||
| 182 | x = y; | ||
| 183 | } | ||
| 184 | } | ||
| 185 | /* | ||
| 186 | * The minimal proportion is the smaller one of the last two | ||
| 187 | * proportions for geometric distribution. | ||
| 188 | */ | ||
| 189 | double min_proportion = proportions[n_bucket - 1]; | ||
| 190 | if (n_bucket >= 2 && proportions[n_bucket - 2] < min_proportion) { | ||
| 191 | min_proportion = proportions[n_bucket - 2]; | ||
| 192 | } | ||
| 193 | return min_proportion; | ||
| 194 | } | ||
| 195 | |||
| 196 | static size_t | ||
| 197 | round_to_nearest(const double x) { | ||
| 198 | return (size_t)(x + .5); | ||
| 199 | } | ||
| 200 | |||
| 201 | static void | ||
| 202 | fill_references(size_t means[], size_t stddevs[], const double proportions[], | ||
| 203 | const size_t n_bucket, const size_t n_iter) { | ||
| 204 | for (size_t i = 0; i < n_bucket; ++i) { | ||
| 205 | double x = n_iter * proportions[i]; | ||
| 206 | means[i] = round_to_nearest(x); | ||
| 207 | stddevs[i] = round_to_nearest(sqrt(x * (1. - proportions[i]))); | ||
| 208 | } | ||
| 209 | } | ||
| 210 | |||
| 211 | static uint64_t | ||
| 212 | prof_sample_gen(void *opaque) { | ||
| 213 | return prof_sample_new_event_wait((tsd_t *)opaque) - 1; | ||
| 214 | } | ||
| 215 | |||
| 216 | #endif /* JEMALLOC_PROF */ | ||
| 217 | |||
| 218 | TEST_BEGIN(test_prof_sample) { | ||
| 219 | test_skip_if(!config_prof); | ||
| 220 | #ifdef JEMALLOC_PROF | ||
| 221 | |||
| 222 | /* Number of divisions within [0, mean). */ | ||
| 223 | #define LG_N_DIVIDE 3 | ||
| 224 | #define N_DIVIDE (1 << LG_N_DIVIDE) | ||
| 225 | |||
| 226 | /* Coverage of buckets in terms of multiples of mean. */ | ||
| 227 | #define LG_N_MULTIPLY 2 | ||
| 228 | #define N_GEO_BUCKET (N_DIVIDE << LG_N_MULTIPLY) | ||
| 229 | |||
| 230 | test_skip_if(!opt_prof); | ||
| 231 | |||
| 232 | size_t lg_prof_sample_test = 25; | ||
| 233 | |||
| 234 | size_t lg_prof_sample_orig = lg_prof_sample; | ||
| 235 | assert_d_eq(mallctl("prof.reset", NULL, NULL, &lg_prof_sample_test, | ||
| 236 | sizeof(size_t)), 0, ""); | ||
| 237 | malloc_printf("lg_prof_sample = %zu\n", lg_prof_sample_test); | ||
| 238 | |||
| 239 | double proportions[N_GEO_BUCKET + 1]; | ||
| 240 | const double min_proportion = fill_geometric_proportions(proportions, | ||
| 241 | N_GEO_BUCKET + 1, N_DIVIDE); | ||
| 242 | const size_t n_iter = round_to_nearest(MIN_BUCKET_MEAN / | ||
| 243 | min_proportion); | ||
| 244 | size_t means[N_GEO_BUCKET + 1]; | ||
| 245 | size_t stddevs[N_GEO_BUCKET + 1]; | ||
| 246 | fill_references(means, stddevs, proportions, N_GEO_BUCKET + 1, n_iter); | ||
| 247 | |||
| 248 | tsd_t *tsd = tsd_fetch(); | ||
| 249 | assert_ptr_not_null(tsd, ""); | ||
| 250 | size_t buckets[N_GEO_BUCKET + 1]; | ||
| 251 | assert_zu_ge(lg_prof_sample, LG_N_DIVIDE, ""); | ||
| 252 | const size_t lg_bucket_width = lg_prof_sample - LG_N_DIVIDE; | ||
| 253 | |||
| 254 | bucket_analysis(prof_sample_gen, tsd, buckets, means, stddevs, | ||
| 255 | N_GEO_BUCKET + 1, lg_bucket_width, n_iter); | ||
| 256 | |||
| 257 | assert_d_eq(mallctl("prof.reset", NULL, NULL, &lg_prof_sample_orig, | ||
| 258 | sizeof(size_t)), 0, ""); | ||
| 259 | |||
| 260 | #undef LG_N_DIVIDE | ||
| 261 | #undef N_DIVIDE | ||
| 262 | #undef LG_N_MULTIPLY | ||
| 263 | #undef N_GEO_BUCKET | ||
| 264 | |||
| 265 | #endif /* JEMALLOC_PROF */ | ||
| 266 | } | ||
| 267 | TEST_END | ||
| 268 | |||
| 269 | /******************************************************************************/ | ||
| 270 | |||
| 271 | int | ||
| 272 | main(void) { | ||
| 273 | return test_no_reentrancy( | ||
| 274 | test_uniform, | ||
| 275 | test_prof_sample); | ||
| 276 | } | ||
diff --git a/examples/redis-unstable/deps/jemalloc/test/analyze/sizes.c b/examples/redis-unstable/deps/jemalloc/test/analyze/sizes.c new file mode 100644 index 0000000..44c9de5 --- /dev/null +++ b/examples/redis-unstable/deps/jemalloc/test/analyze/sizes.c | |||
| @@ -0,0 +1,53 @@ | |||
| 1 | #include "test/jemalloc_test.h" | ||
| 2 | |||
| 3 | #include <stdio.h> | ||
| 4 | |||
| 5 | /* | ||
| 6 | * Print the sizes of various important core data structures. OK, I guess this | ||
| 7 | * isn't really a "stress" test, but it does give useful information about | ||
| 8 | * low-level performance characteristics, as the other things in this directory | ||
| 9 | * do. | ||
| 10 | */ | ||
| 11 | |||
| 12 | static void | ||
| 13 | do_print(const char *name, size_t sz_bytes) { | ||
| 14 | const char *sizes[] = {"bytes", "KB", "MB", "GB", "TB", "PB", "EB", | ||
| 15 | "ZB"}; | ||
| 16 | size_t sizes_max = sizeof(sizes)/sizeof(sizes[0]); | ||
| 17 | |||
| 18 | size_t ind = 0; | ||
| 19 | double sz = sz_bytes; | ||
| 20 | while (sz >= 1024 && ind < sizes_max - 1) { | ||
| 21 | sz /= 1024; | ||
| 22 | ind++; | ||
| 23 | } | ||
| 24 | if (ind == 0) { | ||
| 25 | printf("%-20s: %zu bytes\n", name, sz_bytes); | ||
| 26 | } else { | ||
| 27 | printf("%-20s: %f %s\n", name, sz, sizes[ind]); | ||
| 28 | } | ||
| 29 | } | ||
| 30 | |||
| 31 | int | ||
| 32 | main() { | ||
| 33 | #define P(type) \ | ||
| 34 | do_print(#type, sizeof(type)) | ||
| 35 | P(arena_t); | ||
| 36 | P(arena_stats_t); | ||
| 37 | P(base_t); | ||
| 38 | P(decay_t); | ||
| 39 | P(edata_t); | ||
| 40 | P(ecache_t); | ||
| 41 | P(eset_t); | ||
| 42 | P(malloc_mutex_t); | ||
| 43 | P(prof_tctx_t); | ||
| 44 | P(prof_gctx_t); | ||
| 45 | P(prof_tdata_t); | ||
| 46 | P(rtree_t); | ||
| 47 | P(rtree_leaf_elm_t); | ||
| 48 | P(slab_data_t); | ||
| 49 | P(tcache_t); | ||
| 50 | P(tcache_slow_t); | ||
| 51 | P(tsd_t); | ||
| 52 | #undef P | ||
| 53 | } | ||
