1 #include <darwintest.h>
2 #include <dispatch/dispatch.h>
5 #include <ktrace_private.h>
6 #include <kperf/kperf.h>
7 #include <kperfdata/kpdecode.h>
8 #include <os/assumes.h>
10 #include <sys/sysctl.h>
12 #include "kperf_helpers.h"
14 #define PERF_STK_KHDR UINT32_C(0x25020014)
15 #define PERF_STK_UHDR UINT32_C(0x25020018)
19 #define KDEBUG_TRIGGER_TIMEOUT_NS (10 * NSEC_PER_SEC)
21 #define NON_TRIGGER_CLASS UINT8_C(0xfd)
22 #define NON_TRIGGER_SUBCLASS UINT8_C(0xff)
23 #define NON_TRIGGER_CODE UINT8_C(0xff)
25 #define NON_TRIGGER_EVENT \
26 (KDBG_EVENTID(NON_TRIGGER_CLASS, NON_TRIGGER_SUBCLASS, NON_TRIGGER_CODE))
29 expect_kdebug_trigger(const char *filter_desc
, const uint32_t *debugids
,
30 unsigned int n_debugids
)
32 __block
int missing_kernel_stacks
= 0;
33 __block
int missing_user_stacks
= 0;
35 kperf_kdebug_filter_t filter
;
37 s
= ktrace_session_create();
38 T_QUIET
; T_ASSERT_NOTNULL(s
, NULL
);
40 ktrace_events_single(s
, PERF_STK_KHDR
, ^(struct trace_point
*tp
) {
41 missing_kernel_stacks
--;
42 T_LOG("saw kernel stack with %lu frames, flags = %#lx", tp
->arg2
,
45 ktrace_events_single(s
, PERF_STK_UHDR
, ^(struct trace_point
*tp
) {
46 missing_user_stacks
--;
47 T_LOG("saw user stack with %lu frames, flags = %#lx", tp
->arg2
,
51 for (unsigned int i
= 0; i
< n_debugids
; i
++) {
52 ktrace_events_single(s
, debugids
[i
], ^(struct trace_point
*tp
) {
53 missing_kernel_stacks
++;
54 missing_user_stacks
++;
55 T_LOG("saw event with debugid 0x%" PRIx32
, tp
->debugid
);
59 ktrace_events_single(s
, NON_TRIGGER_EVENT
,
60 ^(__unused
struct trace_point
*tp
)
65 ktrace_set_completion_handler(s
, ^{
66 T_EXPECT_LE(missing_kernel_stacks
, 0, NULL
);
67 T_EXPECT_LE(missing_user_stacks
, 0, NULL
);
69 ktrace_session_destroy(s
);
77 (void)kperf_action_count_set(1);
78 T_ASSERT_POSIX_SUCCESS(kperf_action_samplers_set(1,
79 KPERF_SAMPLER_KSTACK
| KPERF_SAMPLER_USTACK
), NULL
);
81 filter
= kperf_kdebug_filter_create();
82 T_ASSERT_NOTNULL(filter
, NULL
);
84 T_ASSERT_POSIX_SUCCESS(kperf_kdebug_action_set(1), NULL
);
85 T_ASSERT_POSIX_SUCCESS(kperf_kdebug_filter_add_desc(filter
, filter_desc
),
87 T_ASSERT_POSIX_SUCCESS(kperf_kdebug_filter_set(filter
), NULL
);
88 kperf_kdebug_filter_destroy(filter
);
90 T_ASSERT_POSIX_SUCCESS(kperf_sample_set(1), NULL
);
92 T_ASSERT_POSIX_ZERO(ktrace_start(s
, dispatch_get_main_queue()), NULL
);
94 /* trace the triggering debugids */
96 for (unsigned int i
= 0; i
< n_debugids
; i
++) {
97 T_ASSERT_POSIX_SUCCESS(kdebug_trace(debugids
[i
], 0, 0, 0, 0), NULL
);
100 T_ASSERT_POSIX_SUCCESS(kdebug_trace(NON_TRIGGER_EVENT
, 0, 0, 0, 0), NULL
);
102 dispatch_after(dispatch_time(DISPATCH_TIME_NOW
, KDEBUG_TRIGGER_TIMEOUT_NS
),
103 dispatch_get_main_queue(), ^(void)
109 #define TRIGGER_CLASS UINT8_C(0xfe)
110 #define TRIGGER_CLASS_END UINT8_C(0xfd)
111 #define TRIGGER_SUBCLASS UINT8_C(0xff)
112 #define TRIGGER_CODE UINT8_C(0)
113 #define TRIGGER_DEBUGID \
114 (KDBG_EVENTID(TRIGGER_CLASS, TRIGGER_SUBCLASS, TRIGGER_CODE))
116 T_DECL(kdebug_trigger_classes
, "test that kdebug trigger samples on classes",
119 const uint32_t class_debugids
[] = {
120 KDBG_EVENTID(TRIGGER_CLASS
, 1, 1),
121 KDBG_EVENTID(TRIGGER_CLASS
, 2, 1),
122 KDBG_EVENTID(TRIGGER_CLASS_END
, 1, 1) | DBG_FUNC_END
,
123 KDBG_EVENTID(TRIGGER_CLASS_END
, 2, 1) | DBG_FUNC_END
,
126 expect_kdebug_trigger("C0xfe,C0xfdr", class_debugids
,
127 sizeof(class_debugids
) / sizeof(class_debugids
[0]));
131 T_DECL(kdebug_trigger_subclasses
,
132 "test that kdebug trigger samples on subclasses",
135 const uint32_t subclass_debugids
[] = {
136 KDBG_EVENTID(TRIGGER_CLASS
, TRIGGER_SUBCLASS
, 0),
137 KDBG_EVENTID(TRIGGER_CLASS
, TRIGGER_SUBCLASS
, 1),
138 KDBG_EVENTID(TRIGGER_CLASS_END
, TRIGGER_SUBCLASS
, 0) | DBG_FUNC_END
,
139 KDBG_EVENTID(TRIGGER_CLASS_END
, TRIGGER_SUBCLASS
, 1) | DBG_FUNC_END
142 expect_kdebug_trigger("S0xfeff,S0xfdffr", subclass_debugids
,
143 sizeof(subclass_debugids
) / sizeof(subclass_debugids
[0]));
147 T_DECL(kdebug_trigger_debugids
, "test that kdebug trigger samples on debugids",
150 const uint32_t debugids
[] = {
154 expect_kdebug_trigger("D0xfeff0000", debugids
,
155 sizeof(debugids
) / sizeof(debugids
[0]));
160 * TODO Set a single function specifier filter, expect not to trigger of all
161 * events from that class.
164 T_DECL(kdbg_callstacks
, "test that the kdbg_callstacks samples on syscalls",
168 __block
bool saw_user_stack
= false;
170 s
= ktrace_session_create();
171 T_ASSERT_NOTNULL(s
, NULL
);
174 * Make sure BSD events are traced in order to trigger samples on syscalls.
176 ktrace_events_class(s
, DBG_BSD
,
177 ^void(__unused
struct trace_point
*tp
) {});
179 ktrace_events_single(s
, PERF_STK_UHDR
, ^(__unused
struct trace_point
*tp
) {
180 saw_user_stack
= true;
184 ktrace_set_completion_handler(s
, ^{
185 ktrace_session_destroy(s
);
187 T_EXPECT_TRUE(saw_user_stack
,
188 "saw user stack after configuring kdbg_callstacks");
191 * Ensure user stacks are not sampled after resetting kdbg_callstacks.
193 ktrace_session_t s_after
= ktrace_session_create();
194 T_ASSERT_NOTNULL(s_after
, NULL
);
196 #pragma clang diagnostic push
197 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
198 T_ASSERT_POSIX_SUCCESS(kperf_kdbg_callstacks_set(0), NULL
);
199 #pragma clang diagnostic pop
201 ktrace_events_class(s_after
, DBG_BSD
,
202 ^void(__unused
struct trace_point
*tp
) {});
204 __block
bool saw_extra_stack
= false;
206 ktrace_events_single(s_after
, PERF_STK_UHDR
,
207 ^(__unused
struct trace_point
*tp
)
209 saw_extra_stack
= true;
210 ktrace_end(s_after
, 1);
213 ktrace_set_completion_handler(s_after
, ^(void) {
214 ktrace_session_destroy(s_after
);
215 T_EXPECT_FALSE(saw_extra_stack
,
216 "saw user stack after disabling kdbg_callstacks)");
221 T_ASSERT_POSIX_ZERO(ktrace_start(s_after
, dispatch_get_main_queue()),
224 dispatch_after(dispatch_time(DISPATCH_TIME_NOW
, 1 * NSEC_PER_SEC
),
225 dispatch_get_main_queue(), ^(void)
227 ktrace_end(s_after
, 1);
231 #pragma clang diagnostic push
232 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
233 T_ASSERT_POSIX_SUCCESS(kperf_kdbg_callstacks_set(1), NULL
);
234 #pragma clang diagnostic pop
236 T_ASSERT_POSIX_ZERO(ktrace_start(s
, dispatch_get_main_queue()), NULL
);
238 dispatch_after(dispatch_time(DISPATCH_TIME_NOW
, 10 * NSEC_PER_SEC
),
239 dispatch_get_main_queue(), ^(void)
251 #define STACKS_WAIT_DURATION_NS (3 * NSEC_PER_SEC)
254 expect_stacks_traced(void (^cb
)(void))
258 s
= ktrace_session_create();
259 T_QUIET
; T_ASSERT_NOTNULL(s
, "ktrace_session_create");
261 __block
unsigned int user_stacks
= 0;
262 __block
unsigned int kernel_stacks
= 0;
264 ktrace_events_single(s
, PERF_STK_UHDR
, ^(__unused
struct trace_point
*tp
) {
267 ktrace_events_single(s
, PERF_STK_KHDR
, ^(__unused
struct trace_point
*tp
) {
271 ktrace_set_completion_handler(s
, ^(void) {
272 ktrace_session_destroy(s
);
273 T_EXPECT_GT(user_stacks
, 0U, NULL
);
274 T_EXPECT_GT(kernel_stacks
, 0U, NULL
);
278 T_QUIET
; T_ASSERT_POSIX_SUCCESS(kperf_sample_set(1), NULL
);
280 T_ASSERT_POSIX_ZERO(ktrace_start(s
, dispatch_get_main_queue()), NULL
);
282 dispatch_after(dispatch_time(DISPATCH_TIME_NOW
, STACKS_WAIT_DURATION_NS
),
283 dispatch_get_main_queue(), ^(void)
290 T_DECL(pet
, "test that PET mode samples kernel and user stacks",
293 configure_kperf_stacks_timer(-1, 10);
294 T_ASSERT_POSIX_SUCCESS(kperf_timer_pet_set(0), NULL
);
296 expect_stacks_traced(^(void) {
303 T_DECL(lightweight_pet
,
304 "test that lightweight PET mode samples kernel and user stacks",
309 configure_kperf_stacks_timer(-1, 10);
310 T_ASSERT_POSIX_SUCCESS(sysctlbyname("kperf.lightweight_pet", NULL
, NULL
,
311 &set
, sizeof(set
)), NULL
);
312 T_ASSERT_POSIX_SUCCESS(kperf_timer_pet_set(0), NULL
);
314 expect_stacks_traced(^(void) {