aboutsummaryrefslogtreecommitdiff
path: root/examples/redis-unstable/deps/jemalloc/test/analyze
diff options
context:
space:
mode:
Diffstat (limited to 'examples/redis-unstable/deps/jemalloc/test/analyze')
-rw-r--r--examples/redis-unstable/deps/jemalloc/test/analyze/prof_bias.c60
-rw-r--r--examples/redis-unstable/deps/jemalloc/test/analyze/rand.c276
-rw-r--r--examples/redis-unstable/deps/jemalloc/test/analyze/sizes.c53
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
26static void
27mock_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
35static void
36do_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
46int
47main(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
41static void
42fill(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
48static void
49collect_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
61static void
62print_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
89static void
90bucket_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
109typedef struct uniform_gen_arg_s uniform_gen_arg_t;
110struct uniform_gen_arg_s {
111 uint64_t state;
112 const unsigned lg_range;
113};
114
115static uint64_t
116uniform_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
121TEST_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}
158TEST_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 */
170static double
171fill_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
196static size_t
197round_to_nearest(const double x) {
198 return (size_t)(x + .5);
199}
200
201static void
202fill_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
211static uint64_t
212prof_sample_gen(void *opaque) {
213 return prof_sample_new_event_wait((tsd_t *)opaque) - 1;
214}
215
216#endif /* JEMALLOC_PROF */
217
218TEST_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}
267TEST_END
268
269/******************************************************************************/
270
271int
272main(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
12static void
13do_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
31int
32main() {
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}