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