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