]> git.saurik.com Git - apple/xnu.git/blame - tools/tests/darwintests/perf_exit.c
xnu-4570.61.1.tar.gz
[apple/xnu.git] / tools / tests / darwintests / perf_exit.c
CommitLineData
813fb2f6
A
1#ifdef T_NAMESPACE
2#undef T_NAMESPACE
3#endif
4#include <darwintest.h>
5
39037602 6#include <sys/kdebug.h>
5ba3f43e 7#include <ktrace/session.h>
39037602
A
8#include <spawn.h>
9#include <stdio.h>
10#include <stdlib.h>
5ba3f43e 11#include <stdatomic.h>
39037602 12
813fb2f6
A
13T_GLOBAL_META(
14 T_META_NAMESPACE("xnu.perf.exit"),
15 T_META_ASROOT(true),
16 T_META_LTEPHASE(LTE_SINGLEUSER)
17);
18
19// From osfmk/kern/sched.h
20#define BASEPRI_FOREGROUND 47
21#define BASEPRI_USER_INITIATED 37
22#define BASEPRI_UTILITY 20
23#define MAXPRI_THROTTLE 4
39037602
A
24
25// From bsd/sys/proc_internal.h
26#define PID_MAX 99999
27
813fb2f6
A
28#define EXIT_BINARY "perf_exit_proc"
29#define EXIT_BINARY_PATH "./" EXIT_BINARY
30
5ba3f43e
A
31static ktrace_session_t session;
32static dispatch_queue_t spawn_queue;
33static uint64_t *begin_ts;
34static dt_stat_time_t s;
35static bool started_tracing = false;
36
813fb2f6
A
37void run_exit_test(int proc_wired_mem, int thread_priority, int nthreads);
38
5ba3f43e
A
39static void cleanup(void) {
40 free(begin_ts);
41 dt_stat_finalize(s);
42 dispatch_release(spawn_queue);
43 if (started_tracing) {
44 ktrace_end(session, 1);
45 }
46}
47
813fb2f6 48void run_exit_test(int proc_wired_mem, int thread_priority, int nthreads) {
5ba3f43e 49 static atomic_bool ended = false;
39037602 50
5ba3f43e
A
51 s = dt_stat_time_create("time");
52 T_QUIET; T_ASSERT_NOTNULL(s, "created time statistic");
39037602 53
5ba3f43e
A
54 begin_ts = malloc(sizeof(uint64_t) * PID_MAX);
55 T_QUIET; T_ASSERT_NOTNULL(begin_ts, "created pid array");
56
57 T_ATEND(cleanup);
39037602 58
39037602 59 session = ktrace_session_create();
5ba3f43e 60 T_QUIET; T_ASSERT_NOTNULL(session, "created a trace session");
813fb2f6
A
61
62 spawn_queue = dispatch_queue_create("spawn_queue", NULL);
63
39037602 64 ktrace_set_completion_handler(session, ^{
5ba3f43e 65 ktrace_session_destroy(session);
39037602
A
66 T_END;
67 });
68
69 ktrace_set_signal_handler(session);
5ba3f43e 70 ktrace_set_execnames_enabled(session, KTRACE_FEATURE_ENABLED);
39037602 71
5ba3f43e 72 // We are only interested in the process we launched
813fb2f6 73 ktrace_filter_process(session, EXIT_BINARY);
39037602
A
74
75 ktrace_events_single(session, (BSDDBG_CODE(DBG_BSD_EXCP_SC, 1) | DBG_FUNC_START), ^(ktrace_event_t e) {
5ba3f43e
A
76 T_QUIET; T_ASSERT_LE(e->pid, PID_MAX, "valid pid for tracepoint");
77 begin_ts[e->pid] = e->timestamp;
39037602
A
78 });
79 ktrace_events_single(session, (BSDDBG_CODE(DBG_BSD_PROC, BSD_PROC_EXIT) | DBG_FUNC_END), ^(ktrace_event_t e) {
5ba3f43e
A
80 T_QUIET; T_ASSERT_LE(e->pid, PID_MAX, "valid pid for tracepoint");
81
82 if (begin_ts[e->pid] == 0) {
39037602
A
83 return;
84 }
5ba3f43e
A
85 T_QUIET; T_ASSERT_LE(begin_ts[e->pid], e->timestamp, "timestamps are monotonically increasing");
86 dt_stat_mach_time_add(s, e->timestamp - begin_ts[e->pid]);
87
88 if (dt_stat_stable(s)) {
89 ended = true;
39037602
A
90 ktrace_end(session, 1);
91 }
92 });
93
94 int ret = ktrace_start(session, dispatch_get_main_queue());
5ba3f43e
A
95 T_ASSERT_POSIX_ZERO(ret, "starting trace");
96 started_tracing = true;
813fb2f6 97
39037602 98 // Spawn processes continuously until the test is over
39037602 99 dispatch_async(spawn_queue, ^(void) {
813fb2f6
A
100 char priority_buf[32], nthreads_buf[32], mem_buf[32];
101
102 snprintf(priority_buf, 32, "%d", thread_priority);
103 snprintf(nthreads_buf, 32, "%d", nthreads);
104 snprintf(mem_buf, 32, "%d", proc_wired_mem);
105
106 char *args[] = {EXIT_BINARY_PATH, priority_buf, nthreads_buf, mem_buf, NULL};
107 int status;
39037602
A
108 while (!ended) {
109 pid_t pid;
5ba3f43e
A
110 int bret = posix_spawn(&pid, args[0], NULL, NULL, args, NULL);
111 T_QUIET; T_ASSERT_POSIX_ZERO(bret, "spawned process '%s'", args[0]);
112
113 bret = waitpid(pid, &status, 0);
114 T_QUIET; T_ASSERT_POSIX_SUCCESS(bret, "waited for process %d\n", pid);
39037602 115
39037602 116 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
5ba3f43e 117 T_ASSERT_FAIL("child process failed to run");
813fb2f6
A
118
119 // Avoid saturating the CPU with new processes
120 usleep(1);
39037602
A
121 }
122 });
123
124 dispatch_main();
125}
813fb2f6
A
126
127
128T_DECL(exit, "exit(2) time from syscall start to end") {
129 run_exit_test(0, BASEPRI_FOREGROUND, 0);
130}
131
132T_DECL(exit_pri_4, "exit(2) time at priority 4 (throttled)") {
133 run_exit_test(0, MAXPRI_THROTTLE, 0);
134}
135
136T_DECL(exit_pri_20, "exit(2) time at priority 20 (utility)") {
137 run_exit_test(0, BASEPRI_UTILITY, 0);
138}
139
140T_DECL(exit_pri_37, "exit(2) time at priority 37 (user initiated)") {
141 run_exit_test(0, BASEPRI_USER_INITIATED, 0);
142}
143
144T_DECL(exit_10_threads, "exit(2) time with 10 threads") {
145 run_exit_test(0, BASEPRI_FOREGROUND, 10);
146}
147
813fb2f6
A
148T_DECL(exit_1mb, "exit(2) time with 1MB of wired memory") {
149 run_exit_test(10000000, BASEPRI_FOREGROUND, 0);
150}
151
152T_DECL(exit_10mb, "exit(2) time with 10MB of wired memory") {
153 run_exit_test(10000000, BASEPRI_FOREGROUND, 0);
154}
155
5ba3f43e 156T_DECL(exit_100_threads, "exit(2) time with 100 threads", T_META_ENABLED(false), T_META_TIMEOUT(1800)) {
813fb2f6
A
157 run_exit_test(0, BASEPRI_FOREGROUND, 100);
158}
159
5ba3f43e 160T_DECL(exit_1000_threads, "exit(2) time with 1000 threads", T_META_ENABLED(false), T_META_TIMEOUT(1800)) {
813fb2f6
A
161 run_exit_test(0, BASEPRI_FOREGROUND, 1000);
162}
163
5ba3f43e 164T_DECL(exit_100mb, "exit(2) time with 100MB of wired memory", T_META_ENABLED(false), T_META_TIMEOUT(1800)) {
813fb2f6
A
165 run_exit_test(100000000, BASEPRI_FOREGROUND, 0);
166}