xref: /xnu-8796.101.5/tests/perf_exit.c (revision aca3beaa3dfbd42498b42c5e5ce20a938e6554e5)
1*aca3beaaSApple OSS Distributions #ifdef T_NAMESPACE
2*aca3beaaSApple OSS Distributions #undef T_NAMESPACE
3*aca3beaaSApple OSS Distributions #endif
4*aca3beaaSApple OSS Distributions #include <darwintest.h>
5*aca3beaaSApple OSS Distributions #include <darwintest_utils.h>
6*aca3beaaSApple OSS Distributions 
7*aca3beaaSApple OSS Distributions #include <sys/kdebug.h>
8*aca3beaaSApple OSS Distributions #include <ktrace/session.h>
9*aca3beaaSApple OSS Distributions #include <spawn.h>
10*aca3beaaSApple OSS Distributions #include <stdio.h>
11*aca3beaaSApple OSS Distributions #include <stdlib.h>
12*aca3beaaSApple OSS Distributions #include <stdatomic.h>
13*aca3beaaSApple OSS Distributions 
14*aca3beaaSApple OSS Distributions T_GLOBAL_META(
15*aca3beaaSApple OSS Distributions 	T_META_NAMESPACE("xnu.perf"),
16*aca3beaaSApple OSS Distributions 	T_META_ASROOT(true),
17*aca3beaaSApple OSS Distributions 	T_META_LTEPHASE(LTE_SINGLEUSER),
18*aca3beaaSApple OSS Distributions 	T_META_TAG_PERF
19*aca3beaaSApple OSS Distributions 	);
20*aca3beaaSApple OSS Distributions #if TARGET_OS_WATCH
21*aca3beaaSApple OSS Distributions #define TEST_TIMEOUT 3600 * (NSEC_PER_SEC)
22*aca3beaaSApple OSS Distributions #else
23*aca3beaaSApple OSS Distributions #define TEST_TIMEOUT 1800 * (NSEC_PER_SEC)
24*aca3beaaSApple OSS Distributions #endif
25*aca3beaaSApple OSS Distributions // From bsd/sys/proc_internal.h
26*aca3beaaSApple OSS Distributions #define PID_MAX 99999
27*aca3beaaSApple OSS Distributions 
28*aca3beaaSApple OSS Distributions #define EXIT_BINARY "perf_exit_proc"
29*aca3beaaSApple OSS Distributions #define EXIT_BINARY_PATH "./" EXIT_BINARY
30*aca3beaaSApple OSS Distributions 
31*aca3beaaSApple OSS Distributions #define NEXT_CASE_EVENTID (0xfedcbb00)
32*aca3beaaSApple OSS Distributions 
33*aca3beaaSApple OSS Distributions struct test_case {
34*aca3beaaSApple OSS Distributions 	int wired_mem;
35*aca3beaaSApple OSS Distributions 	int threads;
36*aca3beaaSApple OSS Distributions };
37*aca3beaaSApple OSS Distributions 
38*aca3beaaSApple OSS Distributions static struct test_case test_cases[] = {
39*aca3beaaSApple OSS Distributions 	{0, 0},
40*aca3beaaSApple OSS Distributions 	{0, 10},
41*aca3beaaSApple OSS Distributions 	{1000000, 0},
42*aca3beaaSApple OSS Distributions #if !TARGET_OS_WATCH
43*aca3beaaSApple OSS Distributions 	{10000000, 0}
44*aca3beaaSApple OSS Distributions #endif
45*aca3beaaSApple OSS Distributions };
46*aca3beaaSApple OSS Distributions 
47*aca3beaaSApple OSS Distributions #define TEST_CASES_COUNT (sizeof(test_cases) / sizeof(struct test_case))
48*aca3beaaSApple OSS Distributions 
49*aca3beaaSApple OSS Distributions static _Atomic int producer_i, consumer_i;
50*aca3beaaSApple OSS Distributions 
51*aca3beaaSApple OSS Distributions static ktrace_session_t session;
52*aca3beaaSApple OSS Distributions 
53*aca3beaaSApple OSS Distributions static dispatch_queue_t spawn_queue, processing_queue;
54*aca3beaaSApple OSS Distributions 
55*aca3beaaSApple OSS Distributions static uint64_t *begin_ts;
56*aca3beaaSApple OSS Distributions static dt_stat_time_t s;
57*aca3beaaSApple OSS Distributions static _Atomic bool tracing_on = false;
58*aca3beaaSApple OSS Distributions 
59*aca3beaaSApple OSS Distributions void run_exit_test(int proc_wired_mem, int nthreads);
60*aca3beaaSApple OSS Distributions 
61*aca3beaaSApple OSS Distributions static void
cleanup(void)62*aca3beaaSApple OSS Distributions cleanup(void)
63*aca3beaaSApple OSS Distributions {
64*aca3beaaSApple OSS Distributions 	free(begin_ts);
65*aca3beaaSApple OSS Distributions 	dispatch_release(spawn_queue);
66*aca3beaaSApple OSS Distributions 	dispatch_release(processing_queue);
67*aca3beaaSApple OSS Distributions 	if (tracing_on) {
68*aca3beaaSApple OSS Distributions 		ktrace_end(session, 1);
69*aca3beaaSApple OSS Distributions 	}
70*aca3beaaSApple OSS Distributions }
71*aca3beaaSApple OSS Distributions 
72*aca3beaaSApple OSS Distributions static dt_stat_time_t
create_stat(int proc_wired_mem,int nthreads)73*aca3beaaSApple OSS Distributions create_stat(int proc_wired_mem, int nthreads)
74*aca3beaaSApple OSS Distributions {
75*aca3beaaSApple OSS Distributions 	dt_stat_time_t dst = dt_stat_time_create("time");
76*aca3beaaSApple OSS Distributions 	T_ASSERT_NOTNULL(dst, "created time statistic");
77*aca3beaaSApple OSS Distributions 
78*aca3beaaSApple OSS Distributions 	dt_stat_set_variable((dt_stat_t)dst, "proc_threads", nthreads);
79*aca3beaaSApple OSS Distributions 	dt_stat_set_variable((dt_stat_t)dst, "proc_wired_mem", proc_wired_mem);
80*aca3beaaSApple OSS Distributions 
81*aca3beaaSApple OSS Distributions 	return dst;
82*aca3beaaSApple OSS Distributions }
83*aca3beaaSApple OSS Distributions 
84*aca3beaaSApple OSS Distributions T_DECL(exit, "exit(2) time from syscall start to end", T_META_TIMEOUT(TEST_TIMEOUT)) {
85*aca3beaaSApple OSS Distributions 	s = create_stat(test_cases[consumer_i].wired_mem, test_cases[consumer_i].threads);
86*aca3beaaSApple OSS Distributions 
87*aca3beaaSApple OSS Distributions 	begin_ts = malloc(sizeof(uint64_t) * PID_MAX);
88*aca3beaaSApple OSS Distributions 	T_ASSERT_NOTNULL(begin_ts, "created pid array");
89*aca3beaaSApple OSS Distributions 
90*aca3beaaSApple OSS Distributions 	T_ATEND(cleanup);
91*aca3beaaSApple OSS Distributions 
92*aca3beaaSApple OSS Distributions 	session = ktrace_session_create();
93*aca3beaaSApple OSS Distributions 	T_ASSERT_NOTNULL(session, "created a trace session");
94*aca3beaaSApple OSS Distributions 
95*aca3beaaSApple OSS Distributions 	spawn_queue = dispatch_queue_create("com.apple.perf_exit.spawn_queue", NULL);
96*aca3beaaSApple OSS Distributions 	processing_queue = dispatch_queue_create("com.apple.perf_exit.processing_queue", NULL);
97*aca3beaaSApple OSS Distributions 
98*aca3beaaSApple OSS Distributions 	ktrace_set_completion_handler(session, ^{
99*aca3beaaSApple OSS Distributions 		T_ASSERT_EQ(consumer_i, TEST_CASES_COUNT, "ran all the test cases");
100*aca3beaaSApple OSS Distributions 		dispatch_sync(spawn_queue, ^(void) {
101*aca3beaaSApple OSS Distributions 			tracing_on = false;
102*aca3beaaSApple OSS Distributions 		});
103*aca3beaaSApple OSS Distributions 		ktrace_session_destroy(session);
104*aca3beaaSApple OSS Distributions 		T_END;
105*aca3beaaSApple OSS Distributions 	});
106*aca3beaaSApple OSS Distributions 
107*aca3beaaSApple OSS Distributions 	ktrace_set_signal_handler(session);
108*aca3beaaSApple OSS Distributions 	ktrace_set_execnames_enabled(session, KTRACE_FEATURE_ENABLED);
109*aca3beaaSApple OSS Distributions 
110*aca3beaaSApple OSS Distributions 	// We are only interested in the processes we launched and ourselves
111*aca3beaaSApple OSS Distributions 	ktrace_filter_process(session, EXIT_BINARY);
112*aca3beaaSApple OSS Distributions 	ktrace_filter_process(session, "perf_exit");
113*aca3beaaSApple OSS Distributions 
114*aca3beaaSApple OSS Distributions 	ktrace_events_single(session, NEXT_CASE_EVENTID, ^(__unused ktrace_event_t e) {
115*aca3beaaSApple OSS Distributions 		consumer_i++;
116*aca3beaaSApple OSS Distributions 		dt_stat_finalize(s);
117*aca3beaaSApple OSS Distributions 		if (consumer_i >= TEST_CASES_COUNT) {
118*aca3beaaSApple OSS Distributions 		        ktrace_end(session, 1);
119*aca3beaaSApple OSS Distributions 		} else {
120*aca3beaaSApple OSS Distributions 		        s = create_stat(test_cases[consumer_i].wired_mem, test_cases[consumer_i].threads);
121*aca3beaaSApple OSS Distributions 		}
122*aca3beaaSApple OSS Distributions 	});
123*aca3beaaSApple OSS Distributions 
124*aca3beaaSApple OSS Distributions 	ktrace_events_single(session, (BSDDBG_CODE(DBG_BSD_EXCP_SC, 1) | DBG_FUNC_START), ^(ktrace_event_t e) {
125*aca3beaaSApple OSS Distributions 		T_QUIET; T_ASSERT_LE(e->pid, PID_MAX, "pid %d is valid in start tracepoint", e->pid);
126*aca3beaaSApple OSS Distributions 		begin_ts[e->pid] = e->timestamp;
127*aca3beaaSApple OSS Distributions 	});
128*aca3beaaSApple OSS Distributions 
129*aca3beaaSApple OSS Distributions 	ktrace_events_single(session, (BSDDBG_CODE(DBG_BSD_PROC, BSD_PROC_EXIT) | DBG_FUNC_END), ^(ktrace_event_t e) {
130*aca3beaaSApple OSS Distributions 		T_ASSERT_LE(e->pid, PID_MAX, "pid %d is valid in end tracepoint", e->pid);
131*aca3beaaSApple OSS Distributions 
132*aca3beaaSApple OSS Distributions 		if (begin_ts[e->pid] == 0) {
133*aca3beaaSApple OSS Distributions 		        return;
134*aca3beaaSApple OSS Distributions 		}
135*aca3beaaSApple OSS Distributions 
136*aca3beaaSApple OSS Distributions 		T_QUIET; T_ASSERT_LE(begin_ts[e->pid], e->timestamp, "timestamps are monotonically increasing");
137*aca3beaaSApple OSS Distributions 		dt_stat_mach_time_add(s, e->timestamp - begin_ts[e->pid]);
138*aca3beaaSApple OSS Distributions 
139*aca3beaaSApple OSS Distributions 
140*aca3beaaSApple OSS Distributions 		if (dt_stat_stable(s) && producer_i == consumer_i) {
141*aca3beaaSApple OSS Distributions 		        dispatch_sync(spawn_queue, ^(void) {
142*aca3beaaSApple OSS Distributions 				producer_i++;
143*aca3beaaSApple OSS Distributions 				T_ASSERT_POSIX_ZERO(kdebug_trace(NEXT_CASE_EVENTID, producer_i, 0, 0, 0), "kdebug_trace returns 0");
144*aca3beaaSApple OSS Distributions 			});
145*aca3beaaSApple OSS Distributions 		}
146*aca3beaaSApple OSS Distributions 	});
147*aca3beaaSApple OSS Distributions 
148*aca3beaaSApple OSS Distributions 	int ret = ktrace_start(session, processing_queue);
149*aca3beaaSApple OSS Distributions 	T_ASSERT_POSIX_ZERO(ret, "starting trace");
150*aca3beaaSApple OSS Distributions 	tracing_on = true;
151*aca3beaaSApple OSS Distributions 
152*aca3beaaSApple OSS Distributions 	// Spawn processes continuously until the test is over
153*aca3beaaSApple OSS Distributions 
154*aca3beaaSApple OSS Distributions 	__block void (^spawn_process)(void) = Block_copy(^(void) {
155*aca3beaaSApple OSS Distributions 		char nthreads_buf[32], mem_buf[32];
156*aca3beaaSApple OSS Distributions 
157*aca3beaaSApple OSS Distributions 		if (producer_i >= TEST_CASES_COUNT || !tracing_on) {
158*aca3beaaSApple OSS Distributions 		        return;
159*aca3beaaSApple OSS Distributions 		}
160*aca3beaaSApple OSS Distributions 
161*aca3beaaSApple OSS Distributions 		snprintf(nthreads_buf, 32, "%d", test_cases[producer_i].threads);
162*aca3beaaSApple OSS Distributions 		snprintf(mem_buf, 32, "%d", test_cases[producer_i].wired_mem);
163*aca3beaaSApple OSS Distributions 
164*aca3beaaSApple OSS Distributions 		char *args[] = {EXIT_BINARY_PATH, nthreads_buf, mem_buf, NULL};
165*aca3beaaSApple OSS Distributions 		int status;
166*aca3beaaSApple OSS Distributions 
167*aca3beaaSApple OSS Distributions 		pid_t pid;
168*aca3beaaSApple OSS Distributions 		int bret = posix_spawn(&pid, args[0], NULL, NULL, args, NULL);
169*aca3beaaSApple OSS Distributions 		T_ASSERT_POSIX_ZERO(bret, "spawned process with pid %d (threads=%s mem=%s)", pid, nthreads_buf, mem_buf);
170*aca3beaaSApple OSS Distributions 
171*aca3beaaSApple OSS Distributions 		bret = waitpid(pid, &status, 0);
172*aca3beaaSApple OSS Distributions 		T_QUIET; T_ASSERT_POSIX_SUCCESS(bret, "waited for process %d\n", pid);
173*aca3beaaSApple OSS Distributions 
174*aca3beaaSApple OSS Distributions 		if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
175*aca3beaaSApple OSS Distributions 		        T_ASSERT_FAIL("child process failed to run");
176*aca3beaaSApple OSS Distributions 		}
177*aca3beaaSApple OSS Distributions 
178*aca3beaaSApple OSS Distributions 		// Avoid saturating the CPU with new processes
179*aca3beaaSApple OSS Distributions 		usleep(1000);
180*aca3beaaSApple OSS Distributions 
181*aca3beaaSApple OSS Distributions 		dispatch_async(spawn_queue, spawn_process);
182*aca3beaaSApple OSS Distributions 	});
183*aca3beaaSApple OSS Distributions 
184*aca3beaaSApple OSS Distributions 	dispatch_async(spawn_queue, spawn_process);
185*aca3beaaSApple OSS Distributions 
186*aca3beaaSApple OSS Distributions 	dispatch_after(dispatch_time(DISPATCH_TIME_NOW, TEST_TIMEOUT), dispatch_get_main_queue(), ^{
187*aca3beaaSApple OSS Distributions 		ktrace_end(session, 0);
188*aca3beaaSApple OSS Distributions 	});
189*aca3beaaSApple OSS Distributions 
190*aca3beaaSApple OSS Distributions 	dispatch_main();
191*aca3beaaSApple OSS Distributions }
192