1*43a90889SApple OSS Distributions // Copyright (c) 2017-2021 Apple Inc. All rights reserved.
2*43a90889SApple OSS Distributions
3*43a90889SApple OSS Distributions #include <darwintest.h>
4*43a90889SApple OSS Distributions #include <darwintest_utils.h>
5*43a90889SApple OSS Distributions #include <dispatch/dispatch.h>
6*43a90889SApple OSS Distributions #include <inttypes.h>
7*43a90889SApple OSS Distributions #include <ktrace/session.h>
8*43a90889SApple OSS Distributions #include <ktrace/private.h>
9*43a90889SApple OSS Distributions #include <sys/kdebug.h>
10*43a90889SApple OSS Distributions #include <sys/syscall.h>
11*43a90889SApple OSS Distributions #include <kperf/kpc.h>
12*43a90889SApple OSS Distributions #include <kperf/kperf.h>
13*43a90889SApple OSS Distributions #include <kperfdata/kpdecode.h>
14*43a90889SApple OSS Distributions #include <os/assumes.h>
15*43a90889SApple OSS Distributions #include <stdint.h>
16*43a90889SApple OSS Distributions #include <sys/sysctl.h>
17*43a90889SApple OSS Distributions
18*43a90889SApple OSS Distributions #include "kperf_helpers.h"
19*43a90889SApple OSS Distributions #include "ktrace_helpers.h"
20*43a90889SApple OSS Distributions #include "ktrace_meta.h"
21*43a90889SApple OSS Distributions #include "../drop_priv.h"
22*43a90889SApple OSS Distributions
23*43a90889SApple OSS Distributions
24*43a90889SApple OSS Distributions
25*43a90889SApple OSS Distributions #define MAX_CPUS 64
26*43a90889SApple OSS Distributions #define MAX_THREADS 64
27*43a90889SApple OSS Distributions
28*43a90889SApple OSS Distributions volatile static bool running_threads = true;
29*43a90889SApple OSS Distributions
30*43a90889SApple OSS Distributions static void *
spinning_thread(void * semp)31*43a90889SApple OSS Distributions spinning_thread(void *semp)
32*43a90889SApple OSS Distributions {
33*43a90889SApple OSS Distributions T_QUIET;
34*43a90889SApple OSS Distributions T_ASSERT_NOTNULL(semp, "semaphore passed to thread should not be NULL");
35*43a90889SApple OSS Distributions dispatch_semaphore_signal(*(dispatch_semaphore_t *)semp);
36*43a90889SApple OSS Distributions
37*43a90889SApple OSS Distributions while (running_threads) {
38*43a90889SApple OSS Distributions ;
39*43a90889SApple OSS Distributions }
40*43a90889SApple OSS Distributions return NULL;
41*43a90889SApple OSS Distributions }
42*43a90889SApple OSS Distributions
43*43a90889SApple OSS Distributions #define PERF_STK_KHDR UINT32_C(0x25020014)
44*43a90889SApple OSS Distributions #define PERF_STK_UHDR UINT32_C(0x25020018)
45*43a90889SApple OSS Distributions #define PERF_TMR_FIRE KDBG_EVENTID(DBG_PERF, 3, 0)
46*43a90889SApple OSS Distributions #define PERF_TMR_HNDLR KDBG_EVENTID(DBG_PERF, 3, 2)
47*43a90889SApple OSS Distributions #define PERF_TMR_PEND KDBG_EVENTID(DBG_PERF, 3, 3)
48*43a90889SApple OSS Distributions #define PERF_TMR_SKIP KDBG_EVENTID(DBG_PERF, 3, 4)
49*43a90889SApple OSS Distributions #define PERF_KPC_CONFIG KDBG_EVENTID(DBG_PERF, 6, 4)
50*43a90889SApple OSS Distributions #define PERF_KPC_REG KDBG_EVENTID(DBG_PERF, 6, 5)
51*43a90889SApple OSS Distributions #define PERF_KPC_REG32 KDBG_EVENTID(DBG_PERF, 6, 7)
52*43a90889SApple OSS Distributions #define PERF_INSTR_DATA KDBG_EVENTID(DBG_PERF, 1, 17)
53*43a90889SApple OSS Distributions #define PERF_EVENT KDBG_EVENTID(DBG_PERF, 0, 0)
54*43a90889SApple OSS Distributions #define PERF_DISPLABEL KDBG_EVENTID(DBG_PERF, 1, 23)
55*43a90889SApple OSS Distributions #define PERF_DISPSAMPLE KDBG_EVENTID(DBG_PERF, 1, 10)
56*43a90889SApple OSS Distributions
57*43a90889SApple OSS Distributions #define SCHED_DISPATCH KDBG_EVENTID(DBG_MACH, DBG_MACH_SCHED, MACH_DISPATCH)
58*43a90889SApple OSS Distributions #define SCHED_SWITCH KDBG_EVENTID(DBG_MACH, DBG_MACH_SCHED, MACH_SCHED)
59*43a90889SApple OSS Distributions #define SCHED_HANDOFF KDBG_EVENTID(DBG_MACH, DBG_MACH_SCHED, MACH_STACK_HANDOFF)
60*43a90889SApple OSS Distributions #define SCHED_IDLE KDBG_EVENTID(DBG_MACH, DBG_MACH_SCHED, MACH_IDLE)
61*43a90889SApple OSS Distributions
62*43a90889SApple OSS Distributions #define MP_CPUS_CALL UINT32_C(0x1900004)
63*43a90889SApple OSS Distributions
64*43a90889SApple OSS Distributions #define DISPATCH_AFTER_EVENT UINT32_C(0xfefffffc)
65*43a90889SApple OSS Distributions #define TIMEOUT_SECS 10
66*43a90889SApple OSS Distributions
67*43a90889SApple OSS Distributions #define TIMER_PERIOD_NS (1 * NSEC_PER_MSEC)
68*43a90889SApple OSS Distributions
69*43a90889SApple OSS Distributions static void
start_tracing_with_timeout(ktrace_session_t s,unsigned int timeout_secs)70*43a90889SApple OSS Distributions start_tracing_with_timeout(ktrace_session_t s, unsigned int timeout_secs)
71*43a90889SApple OSS Distributions {
72*43a90889SApple OSS Distributions // Only set the timeout after we've seen an event that was traced by us.
73*43a90889SApple OSS Distributions // This helps set a reasonable timeout after we're guaranteed to get a
74*43a90889SApple OSS Distributions // few events.
75*43a90889SApple OSS Distributions dispatch_queue_t q = dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0);
76*43a90889SApple OSS Distributions
77*43a90889SApple OSS Distributions ktrace_events_single(s, DISPATCH_AFTER_EVENT,
78*43a90889SApple OSS Distributions ^(__unused struct trace_point *tp)
79*43a90889SApple OSS Distributions {
80*43a90889SApple OSS Distributions T_LOG("arming timer to stop tracing after %d seconds", timeout_secs);
81*43a90889SApple OSS Distributions dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
82*43a90889SApple OSS Distributions timeout_secs * NSEC_PER_SEC), q, ^{
83*43a90889SApple OSS Distributions T_LOG("ending tracing due to timeout");
84*43a90889SApple OSS Distributions ktrace_end(s, 0);
85*43a90889SApple OSS Distributions });
86*43a90889SApple OSS Distributions });
87*43a90889SApple OSS Distributions ktrace_set_collection_interval(s, 100);
88*43a90889SApple OSS Distributions
89*43a90889SApple OSS Distributions T_ASSERT_POSIX_ZERO(ktrace_start(s, q), "start ktrace");
90*43a90889SApple OSS Distributions
91*43a90889SApple OSS Distributions kdebug_trace(DISPATCH_AFTER_EVENT, 0, 0, 0, 0);
92*43a90889SApple OSS Distributions T_LOG("trace point emitted");
93*43a90889SApple OSS Distributions }
94*43a90889SApple OSS Distributions
95*43a90889SApple OSS Distributions static void
configure_kperf_timer_samplers(uint64_t period_ns,uint32_t samplers)96*43a90889SApple OSS Distributions configure_kperf_timer_samplers(uint64_t period_ns, uint32_t samplers)
97*43a90889SApple OSS Distributions {
98*43a90889SApple OSS Distributions T_SETUPBEGIN;
99*43a90889SApple OSS Distributions
100*43a90889SApple OSS Distributions (void)kperf_action_count_set(1);
101*43a90889SApple OSS Distributions T_QUIET;
102*43a90889SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(kperf_action_samplers_set(1, samplers),
103*43a90889SApple OSS Distributions NULL);
104*43a90889SApple OSS Distributions (void)kperf_timer_count_set(1);
105*43a90889SApple OSS Distributions T_QUIET;
106*43a90889SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(kperf_timer_period_set(0,
107*43a90889SApple OSS Distributions kperf_ns_to_ticks(period_ns)), NULL);
108*43a90889SApple OSS Distributions T_QUIET;
109*43a90889SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(kperf_timer_action_set(0, 1), NULL);
110*43a90889SApple OSS Distributions
111*43a90889SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(kperf_sample_set(1), "start kperf sampling");
112*43a90889SApple OSS Distributions
113*43a90889SApple OSS Distributions T_SETUPEND;
114*43a90889SApple OSS Distributions }
115*43a90889SApple OSS Distributions
116*43a90889SApple OSS Distributions static double
timestamp_secs(ktrace_session_t s,uint64_t timestamp)117*43a90889SApple OSS Distributions timestamp_secs(ktrace_session_t s, uint64_t timestamp)
118*43a90889SApple OSS Distributions {
119*43a90889SApple OSS Distributions uint64_t ns = 0;
120*43a90889SApple OSS Distributions T_QUIET;
121*43a90889SApple OSS Distributions T_ASSERT_POSIX_ZERO(ktrace_convert_timestamp_to_nanoseconds(s, timestamp,
122*43a90889SApple OSS Distributions &ns), NULL);
123*43a90889SApple OSS Distributions return (double)ns / NSEC_PER_SEC;
124*43a90889SApple OSS Distributions }
125*43a90889SApple OSS Distributions
126*43a90889SApple OSS Distributions #pragma mark - timers
127*43a90889SApple OSS Distributions
128*43a90889SApple OSS Distributions // Ensure that kperf is correctly sampling CPUs that are actively scheduling by
129*43a90889SApple OSS Distributions // bringing up threads and ensuring that threads on-core are sampled by each
130*43a90889SApple OSS Distributions // timer fire.
131*43a90889SApple OSS Distributions
132*43a90889SApple OSS Distributions T_DECL(kperf_sample_active_cpus,
133*43a90889SApple OSS Distributions "make sure that kperf samples all active CPUs",
134*43a90889SApple OSS Distributions T_META_TAG_VM_NOT_ELIGIBLE)
135*43a90889SApple OSS Distributions {
136*43a90889SApple OSS Distributions start_controlling_ktrace();
137*43a90889SApple OSS Distributions
138*43a90889SApple OSS Distributions T_SETUPBEGIN;
139*43a90889SApple OSS Distributions
140*43a90889SApple OSS Distributions int ncpus = dt_ncpu();
141*43a90889SApple OSS Distributions T_QUIET;
142*43a90889SApple OSS Distributions T_ASSERT_LT(ncpus, MAX_CPUS,
143*43a90889SApple OSS Distributions "only supports up to %d CPUs", MAX_CPUS);
144*43a90889SApple OSS Distributions T_LOG("found %d CPUs", ncpus);
145*43a90889SApple OSS Distributions
146*43a90889SApple OSS Distributions int nthreads = ncpus - 1;
147*43a90889SApple OSS Distributions T_QUIET;
148*43a90889SApple OSS Distributions T_ASSERT_LT(nthreads, MAX_THREADS,
149*43a90889SApple OSS Distributions "only supports up to %d threads", MAX_THREADS);
150*43a90889SApple OSS Distributions
151*43a90889SApple OSS Distributions static pthread_t threads[MAX_THREADS];
152*43a90889SApple OSS Distributions
153*43a90889SApple OSS Distributions ktrace_session_t s = ktrace_session_create();
154*43a90889SApple OSS Distributions T_QUIET; T_WITH_ERRNO; T_ASSERT_NOTNULL(s, "ktrace_session_create");
155*43a90889SApple OSS Distributions ktrace_set_collection_interval(s, 100);
156*43a90889SApple OSS Distributions
157*43a90889SApple OSS Distributions __block uint64_t nfires = 0;
158*43a90889SApple OSS Distributions __block uint64_t nsamples = 0;
159*43a90889SApple OSS Distributions static uint64_t idle_tids[MAX_CPUS] = { 0 };
160*43a90889SApple OSS Distributions __block double sum_saturation = 0;
161*43a90889SApple OSS Distributions __block uint64_t last_nsamples = 0;
162*43a90889SApple OSS Distributions
163*43a90889SApple OSS Distributions // As a test debugging aid, take an additonal argument that specifies the
164*43a90889SApple OSS Distributions // number of fires to stop tracing after. This also turns on additional
165*43a90889SApple OSS Distributions // logging of scheduler trace events.
166*43a90889SApple OSS Distributions int stopafter = 0;
167*43a90889SApple OSS Distributions if (argc > 0) {
168*43a90889SApple OSS Distributions stopafter = atoi(argv[0]);
169*43a90889SApple OSS Distributions if (stopafter < 0) {
170*43a90889SApple OSS Distributions T_ASSERT_FAIL("argument must be positive");
171*43a90889SApple OSS Distributions }
172*43a90889SApple OSS Distributions }
173*43a90889SApple OSS Distributions
174*43a90889SApple OSS Distributions static uint64_t first_timestamp = 0;
175*43a90889SApple OSS Distributions static uint64_t last_timestamp = 0;
176*43a90889SApple OSS Distributions ktrace_events_any(s, ^(struct trace_point *tp) {
177*43a90889SApple OSS Distributions if (first_timestamp == 0) {
178*43a90889SApple OSS Distributions first_timestamp = tp->timestamp;
179*43a90889SApple OSS Distributions }
180*43a90889SApple OSS Distributions last_timestamp = tp->timestamp;
181*43a90889SApple OSS Distributions });
182*43a90889SApple OSS Distributions
183*43a90889SApple OSS Distributions ktrace_set_completion_handler(s, ^{
184*43a90889SApple OSS Distributions T_LOG("stopping threads");
185*43a90889SApple OSS Distributions
186*43a90889SApple OSS Distributions running_threads = false;
187*43a90889SApple OSS Distributions
188*43a90889SApple OSS Distributions for (int i = 0; i < nthreads; i++) {
189*43a90889SApple OSS Distributions T_QUIET;
190*43a90889SApple OSS Distributions T_ASSERT_POSIX_ZERO(pthread_join(threads[i], NULL), NULL);
191*43a90889SApple OSS Distributions }
192*43a90889SApple OSS Distributions
193*43a90889SApple OSS Distributions double saturation = sum_saturation / nfires * 100;
194*43a90889SApple OSS Distributions
195*43a90889SApple OSS Distributions T_LOG("over %.1f seconds, saw %" PRIu64 " timer fires, %" PRIu64
196*43a90889SApple OSS Distributions " samples, %g samples/fire, %.2f%% saturation",
197*43a90889SApple OSS Distributions timestamp_secs(s, last_timestamp - first_timestamp), nfires,
198*43a90889SApple OSS Distributions nsamples, (double)nsamples / (double)nfires, saturation);
199*43a90889SApple OSS Distributions T_ASSERT_GT(saturation, 95.0,
200*43a90889SApple OSS Distributions "saw reasonable percentage of full samples");
201*43a90889SApple OSS Distributions
202*43a90889SApple OSS Distributions T_END;
203*43a90889SApple OSS Distributions });
204*43a90889SApple OSS Distributions
205*43a90889SApple OSS Distributions // Track which threads are running on each CPU.
206*43a90889SApple OSS Distributions static uint64_t tids_on_cpu[MAX_CPUS] = { 0 };
207*43a90889SApple OSS Distributions void (^switch_cb)(struct trace_point *, const char *name) =
208*43a90889SApple OSS Distributions ^(struct trace_point *tp, const char *name) {
209*43a90889SApple OSS Distributions uint64_t new_thread = tp->arg2;
210*43a90889SApple OSS Distributions
211*43a90889SApple OSS Distributions if (idle_tids[tp->cpuid] != new_thread) {
212*43a90889SApple OSS Distributions tids_on_cpu[tp->cpuid] = new_thread;
213*43a90889SApple OSS Distributions }
214*43a90889SApple OSS Distributions
215*43a90889SApple OSS Distributions if (stopafter) {
216*43a90889SApple OSS Distributions T_LOG("%.7g: %s on %d: %llx", timestamp_secs(s, tp->timestamp),
217*43a90889SApple OSS Distributions name, tp->cpuid, tp->arg2);
218*43a90889SApple OSS Distributions }
219*43a90889SApple OSS Distributions };
220*43a90889SApple OSS Distributions
221*43a90889SApple OSS Distributions ktrace_events_single(s, SCHED_SWITCH, ^(struct trace_point *tp) {
222*43a90889SApple OSS Distributions switch_cb(tp, "switch");
223*43a90889SApple OSS Distributions });
224*43a90889SApple OSS Distributions ktrace_events_single(s, SCHED_HANDOFF, ^(struct trace_point *tp) {
225*43a90889SApple OSS Distributions switch_cb(tp, "hndoff");
226*43a90889SApple OSS Distributions });
227*43a90889SApple OSS Distributions
228*43a90889SApple OSS Distributions // Determine the thread IDs of the idle threads on each CPU.
229*43a90889SApple OSS Distributions ktrace_events_single(s, SCHED_IDLE, ^(struct trace_point *tp) {
230*43a90889SApple OSS Distributions if (tp->debugid & DBG_FUNC_END) {
231*43a90889SApple OSS Distributions return;
232*43a90889SApple OSS Distributions }
233*43a90889SApple OSS Distributions tids_on_cpu[tp->cpuid] = 0;
234*43a90889SApple OSS Distributions idle_tids[tp->cpuid] = tp->threadid;
235*43a90889SApple OSS Distributions if (stopafter) {
236*43a90889SApple OSS Distributions T_LOG("%.7g: idle on %d: %llx", timestamp_secs(s, tp->timestamp),
237*43a90889SApple OSS Distributions tp->cpuid, tp->threadid);
238*43a90889SApple OSS Distributions }
239*43a90889SApple OSS Distributions });
240*43a90889SApple OSS Distributions
241*43a90889SApple OSS Distributions // On each timer fire, go through all the cores and mark any threads
242*43a90889SApple OSS Distributions // that should be sampled.
243*43a90889SApple OSS Distributions
244*43a90889SApple OSS Distributions __block int last_fire_cpu = -1;
245*43a90889SApple OSS Distributions static bool sample_missing[MAX_CPUS] = { false };
246*43a90889SApple OSS Distributions static uint64_t tids_snap[MAX_CPUS] = { 0 };
247*43a90889SApple OSS Distributions __block int nexpected = 0;
248*43a90889SApple OSS Distributions __block int nextra = 0;
249*43a90889SApple OSS Distributions __block int nidles = 0;
250*43a90889SApple OSS Distributions
251*43a90889SApple OSS Distributions ktrace_events_single(s, PERF_TMR_FIRE, ^(struct trace_point *tp) {
252*43a90889SApple OSS Distributions T_QUIET; T_ASSERT_EQ((tp->debugid & DBG_FUNC_START), 0,
253*43a90889SApple OSS Distributions "no timer fire start events are allowed");
254*43a90889SApple OSS Distributions int last_expected = nexpected;
255*43a90889SApple OSS Distributions nfires++;
256*43a90889SApple OSS Distributions
257*43a90889SApple OSS Distributions nexpected = 0;
258*43a90889SApple OSS Distributions for (int i = 0; i < ncpus; i++) {
259*43a90889SApple OSS Distributions if (sample_missing[i]) {
260*43a90889SApple OSS Distributions T_LOG("missed sample on CPU %d for thread %#llx from "
261*43a90889SApple OSS Distributions "timer on CPU %d (expected %d samples)",
262*43a90889SApple OSS Distributions tp->cpuid, tids_snap[i], last_fire_cpu, last_expected);
263*43a90889SApple OSS Distributions sample_missing[i] = false;
264*43a90889SApple OSS Distributions }
265*43a90889SApple OSS Distributions
266*43a90889SApple OSS Distributions if (tids_on_cpu[i] != 0) {
267*43a90889SApple OSS Distributions tids_snap[i] = tids_on_cpu[i];
268*43a90889SApple OSS Distributions sample_missing[i] = true;
269*43a90889SApple OSS Distributions nexpected++;
270*43a90889SApple OSS Distributions }
271*43a90889SApple OSS Distributions }
272*43a90889SApple OSS Distributions if (stopafter) {
273*43a90889SApple OSS Distributions T_LOG("%.7g: FIRE on %d: %d extra, %d idles",
274*43a90889SApple OSS Distributions timestamp_secs(s, tp->timestamp), tp->cpuid, nextra, nidles);
275*43a90889SApple OSS Distributions }
276*43a90889SApple OSS Distributions
277*43a90889SApple OSS Distributions if (nfires == 1) {
278*43a90889SApple OSS Distributions return;
279*43a90889SApple OSS Distributions }
280*43a90889SApple OSS Distributions
281*43a90889SApple OSS Distributions if (last_expected == 0) {
282*43a90889SApple OSS Distributions sum_saturation += 1;
283*43a90889SApple OSS Distributions } else {
284*43a90889SApple OSS Distributions sum_saturation += (double)(nsamples - last_nsamples) /
285*43a90889SApple OSS Distributions last_expected;
286*43a90889SApple OSS Distributions }
287*43a90889SApple OSS Distributions last_nsamples = nsamples;
288*43a90889SApple OSS Distributions nextra = 0;
289*43a90889SApple OSS Distributions nidles = 0;
290*43a90889SApple OSS Distributions
291*43a90889SApple OSS Distributions T_QUIET;
292*43a90889SApple OSS Distributions T_ASSERT_LT((int)tp->cpuid, ncpus,
293*43a90889SApple OSS Distributions "timer fire should not occur on an IOP");
294*43a90889SApple OSS Distributions last_fire_cpu = (int)tp->cpuid;
295*43a90889SApple OSS Distributions
296*43a90889SApple OSS Distributions if (stopafter && (uint64_t)stopafter == nfires) {
297*43a90889SApple OSS Distributions ktrace_end(s, 1);
298*43a90889SApple OSS Distributions }
299*43a90889SApple OSS Distributions });
300*43a90889SApple OSS Distributions
301*43a90889SApple OSS Distributions // On the timer handler for each CPU, unset the missing sample bitmap.
302*43a90889SApple OSS Distributions
303*43a90889SApple OSS Distributions ktrace_events_single(s, PERF_TMR_HNDLR, ^(struct trace_point *tp) {
304*43a90889SApple OSS Distributions nsamples++;
305*43a90889SApple OSS Distributions if ((int)tp->cpuid > ncpus) {
306*43a90889SApple OSS Distributions // Skip IOPs; they're not scheduling any relevant threads.
307*43a90889SApple OSS Distributions return;
308*43a90889SApple OSS Distributions }
309*43a90889SApple OSS Distributions
310*43a90889SApple OSS Distributions if (!sample_missing[tp->cpuid] && idle_tids[tp->cpuid] != 0) {
311*43a90889SApple OSS Distributions T_LOG("sampled additional thread %llx on CPU %d", tp->threadid,
312*43a90889SApple OSS Distributions tp->cpuid);
313*43a90889SApple OSS Distributions nextra++;
314*43a90889SApple OSS Distributions }
315*43a90889SApple OSS Distributions if (tp->threadid == idle_tids[tp->cpuid]) {
316*43a90889SApple OSS Distributions T_LOG("sampled idle thread on CPU %d", tp->cpuid);
317*43a90889SApple OSS Distributions nidles++;
318*43a90889SApple OSS Distributions }
319*43a90889SApple OSS Distributions sample_missing[tp->cpuid] = false;
320*43a90889SApple OSS Distributions });
321*43a90889SApple OSS Distributions
322*43a90889SApple OSS Distributions configure_kperf_timer_samplers(TIMER_PERIOD_NS, KPERF_SAMPLER_KSTACK);
323*43a90889SApple OSS Distributions
324*43a90889SApple OSS Distributions T_SETUPEND;
325*43a90889SApple OSS Distributions
326*43a90889SApple OSS Distributions start_tracing_with_timeout(s, TIMEOUT_SECS);
327*43a90889SApple OSS Distributions
328*43a90889SApple OSS Distributions // Create threads to bring up all of the CPUs.
329*43a90889SApple OSS Distributions
330*43a90889SApple OSS Distributions dispatch_semaphore_t thread_spinning = dispatch_semaphore_create(0);
331*43a90889SApple OSS Distributions
332*43a90889SApple OSS Distributions for (int i = 0; i < nthreads; i++) {
333*43a90889SApple OSS Distributions T_QUIET;
334*43a90889SApple OSS Distributions T_ASSERT_POSIX_ZERO(
335*43a90889SApple OSS Distributions pthread_create(&threads[i], NULL, &spinning_thread,
336*43a90889SApple OSS Distributions &thread_spinning), NULL);
337*43a90889SApple OSS Distributions dispatch_semaphore_wait(thread_spinning, DISPATCH_TIME_FOREVER);
338*43a90889SApple OSS Distributions }
339*43a90889SApple OSS Distributions
340*43a90889SApple OSS Distributions T_LOG("spun up %d thread%s", nthreads, nthreads == 1 ? "" : "s");
341*43a90889SApple OSS Distributions
342*43a90889SApple OSS Distributions dispatch_main();
343*43a90889SApple OSS Distributions }
344*43a90889SApple OSS Distributions
345*43a90889SApple OSS Distributions #define FIRES_THRESHOLD (5000)
346*43a90889SApple OSS Distributions
347*43a90889SApple OSS Distributions T_DECL(kperf_timer_fires_enough_times,
348*43a90889SApple OSS Distributions "ensure the correct number of timers fire in a period of time",
349*43a90889SApple OSS Distributions T_META_TAG_VM_NOT_ELIGIBLE)
350*43a90889SApple OSS Distributions {
351*43a90889SApple OSS Distributions start_controlling_ktrace();
352*43a90889SApple OSS Distributions
353*43a90889SApple OSS Distributions dispatch_semaphore_t thread_spinning = dispatch_semaphore_create(0);
354*43a90889SApple OSS Distributions
355*43a90889SApple OSS Distributions ktrace_session_t s = ktrace_session_create();
356*43a90889SApple OSS Distributions T_QUIET; T_WITH_ERRNO; T_ASSERT_NOTNULL(s, "ktrace_session_create");
357*43a90889SApple OSS Distributions ktrace_set_collection_interval(s, 100);
358*43a90889SApple OSS Distributions
359*43a90889SApple OSS Distributions __block uint64_t nfires = 0;
360*43a90889SApple OSS Distributions __block uint64_t first_fire_ns = 0;
361*43a90889SApple OSS Distributions __block uint64_t last_fire_ns = 0;
362*43a90889SApple OSS Distributions
363*43a90889SApple OSS Distributions int ncpus = dt_ncpu();
364*43a90889SApple OSS Distributions
365*43a90889SApple OSS Distributions ktrace_events_single(s, PERF_TMR_FIRE, ^(struct trace_point *tp) {
366*43a90889SApple OSS Distributions nfires++;
367*43a90889SApple OSS Distributions if (first_fire_ns == 0) {
368*43a90889SApple OSS Distributions ktrace_convert_timestamp_to_nanoseconds(s, tp->timestamp,
369*43a90889SApple OSS Distributions &first_fire_ns);
370*43a90889SApple OSS Distributions }
371*43a90889SApple OSS Distributions ktrace_convert_timestamp_to_nanoseconds(s, tp->timestamp,
372*43a90889SApple OSS Distributions &last_fire_ns);
373*43a90889SApple OSS Distributions
374*43a90889SApple OSS Distributions T_QUIET; T_ASSERT_LT((int)tp->cpuid, ncpus,
375*43a90889SApple OSS Distributions "timer fire should not occur on an IOP");
376*43a90889SApple OSS Distributions if (nfires >= FIRES_THRESHOLD) {
377*43a90889SApple OSS Distributions ktrace_end(s, 1);
378*43a90889SApple OSS Distributions }
379*43a90889SApple OSS Distributions });
380*43a90889SApple OSS Distributions
381*43a90889SApple OSS Distributions configure_kperf_timer_samplers(TIMER_PERIOD_NS, KPERF_SAMPLER_KSTACK);
382*43a90889SApple OSS Distributions
383*43a90889SApple OSS Distributions pthread_t thread;
384*43a90889SApple OSS Distributions T_QUIET;
385*43a90889SApple OSS Distributions T_ASSERT_POSIX_ZERO(pthread_create(&thread, NULL, &spinning_thread,
386*43a90889SApple OSS Distributions &thread_spinning), NULL);
387*43a90889SApple OSS Distributions dispatch_semaphore_wait(thread_spinning, DISPATCH_TIME_FOREVER);
388*43a90889SApple OSS Distributions
389*43a90889SApple OSS Distributions ktrace_set_completion_handler(s, ^{
390*43a90889SApple OSS Distributions running_threads = false;
391*43a90889SApple OSS Distributions
392*43a90889SApple OSS Distributions double duration_secs = (double)(last_fire_ns - first_fire_ns) /
393*43a90889SApple OSS Distributions NSEC_PER_SEC;
394*43a90889SApple OSS Distributions T_LOG("stopping thread after %.2f seconds", duration_secs);
395*43a90889SApple OSS Distributions
396*43a90889SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(pthread_join(thread, NULL), NULL);
397*43a90889SApple OSS Distributions
398*43a90889SApple OSS Distributions T_LOG("saw %" PRIu64 " timer fires (%g fires/second)", nfires,
399*43a90889SApple OSS Distributions (double)nfires / (double)duration_secs);
400*43a90889SApple OSS Distributions double expected_nfires = duration_secs * NSEC_PER_SEC / TIMER_PERIOD_NS;
401*43a90889SApple OSS Distributions T_LOG("expecting %g timer fires", expected_nfires);
402*43a90889SApple OSS Distributions double nfires_seen_pct = expected_nfires / nfires * 100;
403*43a90889SApple OSS Distributions T_ASSERT_GT(nfires_seen_pct, 95.0,
404*43a90889SApple OSS Distributions "saw reasonable number of missed timer fires");
405*43a90889SApple OSS Distributions T_ASSERT_LT(nfires_seen_pct, 105.0,
406*43a90889SApple OSS Distributions "saw reasonable number of extra timer fires");
407*43a90889SApple OSS Distributions
408*43a90889SApple OSS Distributions T_END;
409*43a90889SApple OSS Distributions });
410*43a90889SApple OSS Distributions
411*43a90889SApple OSS Distributions start_tracing_with_timeout(s, TIMEOUT_SECS);
412*43a90889SApple OSS Distributions
413*43a90889SApple OSS Distributions dispatch_main();
414*43a90889SApple OSS Distributions }
415*43a90889SApple OSS Distributions
416*43a90889SApple OSS Distributions // kperf_timer_not_oversampling ensures that the profiling timer fires are
417*43a90889SApple OSS Distributions // spaced apart by the programmed timer period. Otherwise, tools that rely on
418*43a90889SApple OSS Distributions // sample count as a proxy for CPU usage will over-estimate.
419*43a90889SApple OSS Distributions
420*43a90889SApple OSS Distributions #define FIRE_PERIOD_THRESHOLD_NS \
421*43a90889SApple OSS Distributions (TIMER_PERIOD_NS - (uint64_t)(TIMER_PERIOD_NS * 0.05))
422*43a90889SApple OSS Distributions
423*43a90889SApple OSS Distributions struct cirq {
424*43a90889SApple OSS Distributions unsigned int nslots;
425*43a90889SApple OSS Distributions unsigned int tail_slot;
426*43a90889SApple OSS Distributions unsigned int slot_size;
427*43a90889SApple OSS Distributions };
428*43a90889SApple OSS Distributions
429*43a90889SApple OSS Distributions #define CIRQ_INIT(TYPE, NSLOTS) \
430*43a90889SApple OSS Distributions (struct cirq){ \
431*43a90889SApple OSS Distributions .nslots = NSLOTS, .tail_slot = 0, .slot_size = sizeof(TYPE), \
432*43a90889SApple OSS Distributions }
433*43a90889SApple OSS Distributions
434*43a90889SApple OSS Distributions static inline void *
cirq_get(struct cirq * cq,unsigned int i)435*43a90889SApple OSS Distributions cirq_get(struct cirq *cq, unsigned int i)
436*43a90889SApple OSS Distributions {
437*43a90889SApple OSS Distributions return (char *)cq + sizeof(*cq) + (cq->slot_size * i);
438*43a90889SApple OSS Distributions }
439*43a90889SApple OSS Distributions
440*43a90889SApple OSS Distributions static void *
cirq_top(void * vcq)441*43a90889SApple OSS Distributions cirq_top(void *vcq)
442*43a90889SApple OSS Distributions {
443*43a90889SApple OSS Distributions struct cirq *cq = vcq;
444*43a90889SApple OSS Distributions unsigned int tail_slot = cq->tail_slot;
445*43a90889SApple OSS Distributions unsigned int top_slot = (tail_slot > 0 ? tail_slot : cq->nslots) - 1;
446*43a90889SApple OSS Distributions return cirq_get(cq, top_slot);
447*43a90889SApple OSS Distributions }
448*43a90889SApple OSS Distributions
449*43a90889SApple OSS Distributions static void *
cirq_push(void * vcq)450*43a90889SApple OSS Distributions cirq_push(void *vcq)
451*43a90889SApple OSS Distributions {
452*43a90889SApple OSS Distributions struct cirq *cq = vcq;
453*43a90889SApple OSS Distributions unsigned int tail_slot = cq->tail_slot;
454*43a90889SApple OSS Distributions unsigned int next_slot = tail_slot == cq->nslots - 1 ? 0 : tail_slot + 1;
455*43a90889SApple OSS Distributions cq->tail_slot = next_slot;
456*43a90889SApple OSS Distributions return cirq_get(cq, tail_slot);
457*43a90889SApple OSS Distributions }
458*43a90889SApple OSS Distributions
459*43a90889SApple OSS Distributions static void
460*43a90889SApple OSS Distributions cirq_for(void *vcq, void (^iter)(void *elt))
461*43a90889SApple OSS Distributions {
462*43a90889SApple OSS Distributions struct cirq *cq = vcq;
463*43a90889SApple OSS Distributions for (unsigned int i = cq->tail_slot; i < cq->nslots; i++) {
464*43a90889SApple OSS Distributions iter(cirq_get(cq, i));
465*43a90889SApple OSS Distributions }
466*43a90889SApple OSS Distributions for (unsigned int i = 0; i < cq->tail_slot; i++) {
467*43a90889SApple OSS Distributions iter(cirq_get(cq, i));
468*43a90889SApple OSS Distributions }
469*43a90889SApple OSS Distributions }
470*43a90889SApple OSS Distributions
471*43a90889SApple OSS Distributions #define HISTORY_LEN 5
472*43a90889SApple OSS Distributions
473*43a90889SApple OSS Distributions struct instval {
474*43a90889SApple OSS Distributions uint64_t iv_instant_ns;
475*43a90889SApple OSS Distributions uint64_t iv_val;
476*43a90889SApple OSS Distributions };
477*43a90889SApple OSS Distributions
478*43a90889SApple OSS Distributions struct cirq_instval {
479*43a90889SApple OSS Distributions struct cirq cq;
480*43a90889SApple OSS Distributions struct instval elts[HISTORY_LEN];
481*43a90889SApple OSS Distributions };
482*43a90889SApple OSS Distributions
483*43a90889SApple OSS Distributions struct cirq_u64 {
484*43a90889SApple OSS Distributions struct cirq cq;
485*43a90889SApple OSS Distributions uint64_t elts[HISTORY_LEN];
486*43a90889SApple OSS Distributions };
487*43a90889SApple OSS Distributions
488*43a90889SApple OSS Distributions struct cpu_oversample {
489*43a90889SApple OSS Distributions struct cirq_instval timer_latencies;
490*43a90889SApple OSS Distributions struct cirq_instval fire_latencies;
491*43a90889SApple OSS Distributions };
492*43a90889SApple OSS Distributions
493*43a90889SApple OSS Distributions static void
cpu_oversample_log(struct cpu_oversample * cpu,unsigned int cpuid)494*43a90889SApple OSS Distributions cpu_oversample_log(struct cpu_oversample *cpu, unsigned int cpuid)
495*43a90889SApple OSS Distributions {
496*43a90889SApple OSS Distributions T_LOG("CPU %d timer latencies:", cpuid);
497*43a90889SApple OSS Distributions __block int i = -HISTORY_LEN;
498*43a90889SApple OSS Distributions cirq_for(&cpu->timer_latencies, ^(void *viv) {
499*43a90889SApple OSS Distributions struct instval *iv = viv;
500*43a90889SApple OSS Distributions T_LOG("\t%llu timer latency %d: %llu", iv->iv_instant_ns, i,
501*43a90889SApple OSS Distributions iv->iv_val);
502*43a90889SApple OSS Distributions i++;
503*43a90889SApple OSS Distributions });
504*43a90889SApple OSS Distributions
505*43a90889SApple OSS Distributions T_LOG("CPU %d fire latencies:", cpuid);
506*43a90889SApple OSS Distributions i = -HISTORY_LEN;
507*43a90889SApple OSS Distributions cirq_for(&cpu->fire_latencies, ^(void *viv) {
508*43a90889SApple OSS Distributions struct instval *iv = viv;
509*43a90889SApple OSS Distributions T_LOG("\t%llu fire latency %d: %llu", iv->iv_instant_ns, i, iv->iv_val);
510*43a90889SApple OSS Distributions i++;
511*43a90889SApple OSS Distributions });
512*43a90889SApple OSS Distributions }
513*43a90889SApple OSS Distributions
514*43a90889SApple OSS Distributions T_DECL(kperf_timer_not_oversampling,
515*43a90889SApple OSS Distributions "ensure that time between fires is long enough",
516*43a90889SApple OSS Distributions T_META_TAG_VM_NOT_ELIGIBLE)
517*43a90889SApple OSS Distributions {
518*43a90889SApple OSS Distributions start_controlling_ktrace();
519*43a90889SApple OSS Distributions
520*43a90889SApple OSS Distributions ktrace_session_t s = ktrace_session_create();
521*43a90889SApple OSS Distributions T_QUIET; T_WITH_ERRNO; T_ASSERT_NOTNULL(s, "ktrace_session_create");
522*43a90889SApple OSS Distributions // Try not to perturb the system with more work.
523*43a90889SApple OSS Distributions ktrace_set_collection_interval(s, 1000);
524*43a90889SApple OSS Distributions __block uint64_t nfires = 0;
525*43a90889SApple OSS Distributions __block uint64_t first_fire_ns = 0;
526*43a90889SApple OSS Distributions __block uint64_t last_fire_ns = 0;
527*43a90889SApple OSS Distributions __block unsigned int last_fire_cpuid = 0;
528*43a90889SApple OSS Distributions
529*43a90889SApple OSS Distributions int ncpus = dt_ncpu();
530*43a90889SApple OSS Distributions T_QUIET; T_ASSERT_GT(ncpus, 0, "should see positive number of CPUs");
531*43a90889SApple OSS Distributions
532*43a90889SApple OSS Distributions struct cpu_oversample *per_cpu = calloc((unsigned int)ncpus,
533*43a90889SApple OSS Distributions sizeof(per_cpu[0]));
534*43a90889SApple OSS Distributions T_QUIET; T_WITH_ERRNO;
535*43a90889SApple OSS Distributions T_ASSERT_NOTNULL(per_cpu, "allocated timer latency tracking");
536*43a90889SApple OSS Distributions for (int i = 0; i < ncpus; i++) {
537*43a90889SApple OSS Distributions per_cpu[i].timer_latencies.cq = CIRQ_INIT(struct instval, HISTORY_LEN);
538*43a90889SApple OSS Distributions per_cpu[i].fire_latencies.cq = CIRQ_INIT(struct instval, HISTORY_LEN);
539*43a90889SApple OSS Distributions }
540*43a90889SApple OSS Distributions
541*43a90889SApple OSS Distributions __block bool in_stackshot = false;
542*43a90889SApple OSS Distributions __block uint64_t last_stackshot_ns = 0;
543*43a90889SApple OSS Distributions
544*43a90889SApple OSS Distributions // Stackshots are the primary source of interrupt latency on the system.
545*43a90889SApple OSS Distributions ktrace_events_single(s, KDBG_EVENTID(DBG_BSD, DBG_BSD_EXCP_SC,
546*43a90889SApple OSS Distributions SYS_stack_snapshot_with_config), ^(struct trace_point *tp) {
547*43a90889SApple OSS Distributions bool start = tp->debugid & DBG_FUNC_START;
548*43a90889SApple OSS Distributions uint64_t cur_ns = relns_from_abs(s, tp->timestamp);
549*43a90889SApple OSS Distributions T_LOG("%llu: %s stackshot syscall from process %s",
550*43a90889SApple OSS Distributions cur_ns, start ? "start" : "finish", tp->command);
551*43a90889SApple OSS Distributions in_stackshot = start;
552*43a90889SApple OSS Distributions if (!start) {
553*43a90889SApple OSS Distributions last_stackshot_ns = cur_ns;
554*43a90889SApple OSS Distributions }
555*43a90889SApple OSS Distributions });
556*43a90889SApple OSS Distributions
557*43a90889SApple OSS Distributions struct cirq_u64 *fire_times = calloc(1, sizeof(*fire_times));
558*43a90889SApple OSS Distributions T_ASSERT_NOTNULL(fire_times, "allocated fire time tracking");
559*43a90889SApple OSS Distributions fire_times->cq = CIRQ_INIT(uint64_t, HISTORY_LEN);
560*43a90889SApple OSS Distributions
561*43a90889SApple OSS Distributions // Track the decrementer's latency values to find any unexpectedly long
562*43a90889SApple OSS Distributions // interrupt latencies that could affect the firing cadence.
563*43a90889SApple OSS Distributions ktrace_events_single(s, DECR_TRAP_LATENCY,
564*43a90889SApple OSS Distributions ^(struct trace_point *tp) {
565*43a90889SApple OSS Distributions uint64_t cur_ns = relns_from_abs(s, tp->timestamp);
566*43a90889SApple OSS Distributions uint64_t latency_ns = ns_from_abs(s, 0 - tp->arg1);
567*43a90889SApple OSS Distributions struct instval *latency = cirq_push(&per_cpu[tp->cpuid].timer_latencies);
568*43a90889SApple OSS Distributions latency->iv_instant_ns = cur_ns;
569*43a90889SApple OSS Distributions latency->iv_val = latency_ns;
570*43a90889SApple OSS Distributions });
571*43a90889SApple OSS Distributions
572*43a90889SApple OSS Distributions ktrace_events_single(s, PERF_TMR_FIRE, ^(struct trace_point *tp) {
573*43a90889SApple OSS Distributions T_QUIET; T_ASSERT_LT((int)tp->cpuid, ncpus,
574*43a90889SApple OSS Distributions "timer fire should not occur on an IOP");
575*43a90889SApple OSS Distributions
576*43a90889SApple OSS Distributions nfires++;
577*43a90889SApple OSS Distributions uint64_t cur_ns = relns_from_abs(s, tp->timestamp);
578*43a90889SApple OSS Distributions uint64_t *fire_ns = cirq_push(fire_times);
579*43a90889SApple OSS Distributions *fire_ns = cur_ns;
580*43a90889SApple OSS Distributions
581*43a90889SApple OSS Distributions struct cpu_oversample *cur_cpu = &per_cpu[tp->cpuid];
582*43a90889SApple OSS Distributions struct instval *last_timer_latency = cirq_top(
583*43a90889SApple OSS Distributions &cur_cpu->timer_latencies);
584*43a90889SApple OSS Distributions uint64_t timer_latency_ns = last_timer_latency->iv_val;
585*43a90889SApple OSS Distributions
586*43a90889SApple OSS Distributions if (first_fire_ns == 0) {
587*43a90889SApple OSS Distributions first_fire_ns = cur_ns;
588*43a90889SApple OSS Distributions } else {
589*43a90889SApple OSS Distributions struct cpu_oversample *last_cpu = &per_cpu[last_fire_cpuid];
590*43a90889SApple OSS Distributions struct instval *last_latency = cirq_top(&last_cpu->fire_latencies);
591*43a90889SApple OSS Distributions uint64_t last_fire_latency_ns = last_latency->iv_val;
592*43a90889SApple OSS Distributions
593*43a90889SApple OSS Distributions if (timer_latency_ns > TIMER_PERIOD_NS / 4) {
594*43a90889SApple OSS Distributions T_LOG("%llu: long timer latency at fire: %llu", cur_ns,
595*43a90889SApple OSS Distributions timer_latency_ns);
596*43a90889SApple OSS Distributions }
597*43a90889SApple OSS Distributions
598*43a90889SApple OSS Distributions // Long interrupt latencies will cause the timer to miss its fire
599*43a90889SApple OSS Distributions // time and report a fire past when it should have, making the next
600*43a90889SApple OSS Distributions // period too short. Keep track of the latency as a leeway
601*43a90889SApple OSS Distributions // adjustment for the subsequent fire.
602*43a90889SApple OSS Distributions uint64_t fire_period_ns = cur_ns - last_fire_ns;
603*43a90889SApple OSS Distributions uint64_t fire_period_adj_ns = fire_period_ns +
604*43a90889SApple OSS Distributions last_fire_latency_ns + timer_latency_ns;
605*43a90889SApple OSS Distributions // Within 5% is still a valid period -- adjust this for running in
606*43a90889SApple OSS Distributions // potentially-noisy automation.
607*43a90889SApple OSS Distributions uint64_t fire_period_pct_adj_ns = fire_period_adj_ns +
608*43a90889SApple OSS Distributions FIRE_PERIOD_THRESHOLD_NS / 20;
609*43a90889SApple OSS Distributions if (fire_period_adj_ns < FIRE_PERIOD_THRESHOLD_NS &&
610*43a90889SApple OSS Distributions fire_period_pct_adj_ns >= FIRE_PERIOD_THRESHOLD_NS) {
611*43a90889SApple OSS Distributions T_LOG("ignoring period of %llu within 5%% of expected %llu",
612*43a90889SApple OSS Distributions fire_period_adj_ns, fire_period_pct_adj_ns);
613*43a90889SApple OSS Distributions }
614*43a90889SApple OSS Distributions bool too_short = fire_period_pct_adj_ns < FIRE_PERIOD_THRESHOLD_NS;
615*43a90889SApple OSS Distributions if (too_short) {
616*43a90889SApple OSS Distributions T_LOG("%llu: period of timer fire %llu is %llu + %llu + %llu = "
617*43a90889SApple OSS Distributions "%llu < %llu",
618*43a90889SApple OSS Distributions cur_ns, nfires, fire_period_ns, last_fire_latency_ns,
619*43a90889SApple OSS Distributions timer_latency_ns, fire_period_adj_ns,
620*43a90889SApple OSS Distributions FIRE_PERIOD_THRESHOLD_NS);
621*43a90889SApple OSS Distributions
622*43a90889SApple OSS Distributions T_LOG("short profile timer fired on CPU %d", tp->cpuid);
623*43a90889SApple OSS Distributions cpu_oversample_log(cur_cpu, tp->cpuid);
624*43a90889SApple OSS Distributions
625*43a90889SApple OSS Distributions if (cur_cpu == last_cpu) {
626*43a90889SApple OSS Distributions T_LOG("fired back-to-back on CPU %d", tp->cpuid);
627*43a90889SApple OSS Distributions } else {
628*43a90889SApple OSS Distributions T_LOG("previous profile timer fired on CPU %d",
629*43a90889SApple OSS Distributions last_fire_cpuid);
630*43a90889SApple OSS Distributions cpu_oversample_log(last_cpu, last_fire_cpuid);
631*43a90889SApple OSS Distributions }
632*43a90889SApple OSS Distributions
633*43a90889SApple OSS Distributions T_LOG("profile timer fires:");
634*43a90889SApple OSS Distributions cirq_for(fire_times, ^(void *vu64) {
635*43a90889SApple OSS Distributions T_LOG("\tfire: %llu", *(uint64_t *)vu64);
636*43a90889SApple OSS Distributions });
637*43a90889SApple OSS Distributions if (nfires < (unsigned int)ncpus) {
638*43a90889SApple OSS Distributions T_LOG("ignoring timer fire %llu as context may be missing",
639*43a90889SApple OSS Distributions nfires);
640*43a90889SApple OSS Distributions } else {
641*43a90889SApple OSS Distributions if (in_stackshot) {
642*43a90889SApple OSS Distributions T_LOG("skipping assertion because stackshot is "
643*43a90889SApple OSS Distributions "happening");
644*43a90889SApple OSS Distributions } else if (last_stackshot_ns != 0 &&
645*43a90889SApple OSS Distributions cur_ns > last_stackshot_ns &&
646*43a90889SApple OSS Distributions cur_ns - last_stackshot_ns < TIMER_PERIOD_NS) {
647*43a90889SApple OSS Distributions T_LOG("skipping assertion because stackshot happened "
648*43a90889SApple OSS Distributions "%" PRIu64 "ns ago",
649*43a90889SApple OSS Distributions cur_ns - last_stackshot_ns);
650*43a90889SApple OSS Distributions } else {
651*43a90889SApple OSS Distributions T_ASSERT_FAIL("profiling period is shorter than "
652*43a90889SApple OSS Distributions "expected with no stackshot interference");
653*43a90889SApple OSS Distributions }
654*43a90889SApple OSS Distributions }
655*43a90889SApple OSS Distributions }
656*43a90889SApple OSS Distributions
657*43a90889SApple OSS Distributions struct instval *latency = cirq_push(&cur_cpu->fire_latencies);
658*43a90889SApple OSS Distributions latency->iv_instant_ns = cur_ns;
659*43a90889SApple OSS Distributions latency->iv_val = timer_latency_ns;
660*43a90889SApple OSS Distributions
661*43a90889SApple OSS Distributions // Snapshot this timer fire's interrupt latency, so the next one
662*43a90889SApple OSS Distributions // can make an adjustment to the period.
663*43a90889SApple OSS Distributions last_fire_latency_ns = timer_latency_ns;
664*43a90889SApple OSS Distributions }
665*43a90889SApple OSS Distributions last_fire_ns = cur_ns;
666*43a90889SApple OSS Distributions last_fire_cpuid = tp->cpuid;
667*43a90889SApple OSS Distributions
668*43a90889SApple OSS Distributions if (nfires >= FIRES_THRESHOLD) {
669*43a90889SApple OSS Distributions ktrace_end(s, 1);
670*43a90889SApple OSS Distributions }
671*43a90889SApple OSS Distributions });
672*43a90889SApple OSS Distributions
673*43a90889SApple OSS Distributions configure_kperf_timer_samplers(TIMER_PERIOD_NS, KPERF_SAMPLER_TINFO);
674*43a90889SApple OSS Distributions
675*43a90889SApple OSS Distributions ktrace_set_completion_handler(s, ^{
676*43a90889SApple OSS Distributions double duration_secs = (double)(last_fire_ns - first_fire_ns) /
677*43a90889SApple OSS Distributions NSEC_PER_SEC;
678*43a90889SApple OSS Distributions T_LOG("stopping trace after %.2f seconds", duration_secs);
679*43a90889SApple OSS Distributions
680*43a90889SApple OSS Distributions T_PASS("saw %" PRIu64 " timer fires (%g fires/second) without "
681*43a90889SApple OSS Distributions "oversampling", nfires, (double)nfires / (double)duration_secs);
682*43a90889SApple OSS Distributions
683*43a90889SApple OSS Distributions T_END;
684*43a90889SApple OSS Distributions });
685*43a90889SApple OSS Distributions
686*43a90889SApple OSS Distributions start_tracing_with_timeout(s, 5);
687*43a90889SApple OSS Distributions
688*43a90889SApple OSS Distributions // Get all CPUs out of idle.
689*43a90889SApple OSS Distributions uint64_t *counts = kpc_counterbuf_alloc();
690*43a90889SApple OSS Distributions (void)kpc_get_cpu_counters(true,KPC_CLASS_CONFIGURABLE_MASK, NULL, counts);
691*43a90889SApple OSS Distributions free(counts);
692*43a90889SApple OSS Distributions
693*43a90889SApple OSS Distributions dispatch_main();
694*43a90889SApple OSS Distributions }
695*43a90889SApple OSS Distributions
696*43a90889SApple OSS Distributions T_DECL(kperf_timer_stress, "repeatedly enable and disable timers",
697*43a90889SApple OSS Distributions T_META_TAG_VM_NOT_ELIGIBLE)
698*43a90889SApple OSS Distributions {
699*43a90889SApple OSS Distributions start_controlling_ktrace();
700*43a90889SApple OSS Distributions
701*43a90889SApple OSS Distributions const int niters = 500;
702*43a90889SApple OSS Distributions for (int i = 0; i < niters; i++) {
703*43a90889SApple OSS Distributions configure_kperf_stacks_timer(-1, 1, true);
704*43a90889SApple OSS Distributions T_QUIET;
705*43a90889SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(kperf_sample_set(1), "start kperf sampling");
706*43a90889SApple OSS Distributions usleep(2000);
707*43a90889SApple OSS Distributions kperf_reset();
708*43a90889SApple OSS Distributions }
709*43a90889SApple OSS Distributions T_LOG("configured kperf with a timer %d times", niters);
710*43a90889SApple OSS Distributions }
711*43a90889SApple OSS Distributions
712*43a90889SApple OSS Distributions #pragma mark - kdebug triggers
713*43a90889SApple OSS Distributions
714*43a90889SApple OSS Distributions #define KDEBUG_TRIGGER_TIMEOUT_NS (10 * NSEC_PER_SEC)
715*43a90889SApple OSS Distributions
716*43a90889SApple OSS Distributions #define NON_TRIGGER_CLASS UINT32_C(0xfd)
717*43a90889SApple OSS Distributions #define NON_TRIGGER_SUBCLASS UINT32_C(0xff)
718*43a90889SApple OSS Distributions #define NON_TRIGGER_CODE UINT32_C(0xff)
719*43a90889SApple OSS Distributions
720*43a90889SApple OSS Distributions #define NON_TRIGGER_EVENT \
721*43a90889SApple OSS Distributions (KDBG_EVENTID(NON_TRIGGER_CLASS, NON_TRIGGER_SUBCLASS, \
722*43a90889SApple OSS Distributions NON_TRIGGER_CODE))
723*43a90889SApple OSS Distributions
724*43a90889SApple OSS Distributions static void
expect_kdebug_trigger(const char * filter_desc,const uint32_t * debugids,unsigned int n_debugids)725*43a90889SApple OSS Distributions expect_kdebug_trigger(const char *filter_desc, const uint32_t *debugids,
726*43a90889SApple OSS Distributions unsigned int n_debugids)
727*43a90889SApple OSS Distributions {
728*43a90889SApple OSS Distributions __block int missing_kernel_stacks = 0;
729*43a90889SApple OSS Distributions __block int missing_user_stacks = 0;
730*43a90889SApple OSS Distributions ktrace_session_t s;
731*43a90889SApple OSS Distributions kperf_kdebug_filter_t filter;
732*43a90889SApple OSS Distributions
733*43a90889SApple OSS Distributions s = ktrace_session_create();
734*43a90889SApple OSS Distributions T_QUIET; T_WITH_ERRNO; T_ASSERT_NOTNULL(s, "ktrace_session_create");
735*43a90889SApple OSS Distributions ktrace_set_collection_interval(s, 100);
736*43a90889SApple OSS Distributions
737*43a90889SApple OSS Distributions ktrace_events_single(s, PERF_STK_KHDR, ^(struct trace_point *tp) {
738*43a90889SApple OSS Distributions missing_kernel_stacks--;
739*43a90889SApple OSS Distributions T_LOG("saw kernel stack with %" PRIu64 " frames, flags = %#"
740*43a90889SApple OSS Distributions PRIx64, tp->arg2, tp->arg1);
741*43a90889SApple OSS Distributions });
742*43a90889SApple OSS Distributions ktrace_events_single(s, PERF_STK_UHDR, ^(struct trace_point *tp) {
743*43a90889SApple OSS Distributions missing_user_stacks--;
744*43a90889SApple OSS Distributions T_LOG("saw user stack with %" PRIu64 " frames, flags = %#"
745*43a90889SApple OSS Distributions PRIx64, tp->arg2, tp->arg1);
746*43a90889SApple OSS Distributions });
747*43a90889SApple OSS Distributions
748*43a90889SApple OSS Distributions for (unsigned int i = 0; i < n_debugids; i++) {
749*43a90889SApple OSS Distributions ktrace_events_single(s, debugids[i], ^(struct trace_point *tp) {
750*43a90889SApple OSS Distributions missing_kernel_stacks++;
751*43a90889SApple OSS Distributions missing_user_stacks++;
752*43a90889SApple OSS Distributions T_LOG("saw event with debugid 0x%" PRIx32, tp->debugid);
753*43a90889SApple OSS Distributions });
754*43a90889SApple OSS Distributions }
755*43a90889SApple OSS Distributions
756*43a90889SApple OSS Distributions ktrace_events_single(s, NON_TRIGGER_EVENT,
757*43a90889SApple OSS Distributions ^(__unused struct trace_point *tp)
758*43a90889SApple OSS Distributions {
759*43a90889SApple OSS Distributions ktrace_end(s, 0);
760*43a90889SApple OSS Distributions });
761*43a90889SApple OSS Distributions
762*43a90889SApple OSS Distributions ktrace_set_completion_handler(s, ^{
763*43a90889SApple OSS Distributions T_EXPECT_LE(missing_kernel_stacks, 0, NULL);
764*43a90889SApple OSS Distributions T_EXPECT_LE(missing_user_stacks, 0, NULL);
765*43a90889SApple OSS Distributions
766*43a90889SApple OSS Distributions ktrace_session_destroy(s);
767*43a90889SApple OSS Distributions T_END;
768*43a90889SApple OSS Distributions });
769*43a90889SApple OSS Distributions
770*43a90889SApple OSS Distributions kperf_reset();
771*43a90889SApple OSS Distributions
772*43a90889SApple OSS Distributions (void)kperf_action_count_set(1);
773*43a90889SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(kperf_action_samplers_set(1,
774*43a90889SApple OSS Distributions KPERF_SAMPLER_KSTACK | KPERF_SAMPLER_USTACK), NULL);
775*43a90889SApple OSS Distributions
776*43a90889SApple OSS Distributions filter = kperf_kdebug_filter_create();
777*43a90889SApple OSS Distributions T_ASSERT_NOTNULL(filter, NULL);
778*43a90889SApple OSS Distributions
779*43a90889SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(kperf_kdebug_action_set(1), NULL);
780*43a90889SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(kperf_kdebug_filter_add_desc(filter, filter_desc),
781*43a90889SApple OSS Distributions NULL);
782*43a90889SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(kperf_kdebug_filter_set(filter), NULL);
783*43a90889SApple OSS Distributions kperf_kdebug_filter_destroy(filter);
784*43a90889SApple OSS Distributions
785*43a90889SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(kperf_sample_set(1), NULL);
786*43a90889SApple OSS Distributions
787*43a90889SApple OSS Distributions T_ASSERT_POSIX_ZERO(ktrace_start(s, dispatch_get_main_queue()), NULL);
788*43a90889SApple OSS Distributions
789*43a90889SApple OSS Distributions // Trace the triggering events.
790*43a90889SApple OSS Distributions
791*43a90889SApple OSS Distributions for (unsigned int i = 0; i < n_debugids; i++) {
792*43a90889SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(kdebug_trace(debugids[i], 0, 0, 0, 0), NULL);
793*43a90889SApple OSS Distributions }
794*43a90889SApple OSS Distributions
795*43a90889SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(kdebug_trace(NON_TRIGGER_EVENT, 0, 0, 0, 0), NULL);
796*43a90889SApple OSS Distributions
797*43a90889SApple OSS Distributions dispatch_after(dispatch_time(DISPATCH_TIME_NOW, KDEBUG_TRIGGER_TIMEOUT_NS),
798*43a90889SApple OSS Distributions dispatch_get_main_queue(), ^(void)
799*43a90889SApple OSS Distributions {
800*43a90889SApple OSS Distributions ktrace_end(s, 1);
801*43a90889SApple OSS Distributions });
802*43a90889SApple OSS Distributions }
803*43a90889SApple OSS Distributions
804*43a90889SApple OSS Distributions #define TRIGGER_CLASS UINT32_C(0xfe)
805*43a90889SApple OSS Distributions #define TRIGGER_CLASS_END UINT32_C(0xfd)
806*43a90889SApple OSS Distributions #define TRIGGER_SUBCLASS UINT32_C(0xff)
807*43a90889SApple OSS Distributions #define TRIGGER_CODE UINT32_C(0)
808*43a90889SApple OSS Distributions #define TRIGGER_DEBUGID \
809*43a90889SApple OSS Distributions (KDBG_EVENTID(TRIGGER_CLASS, TRIGGER_SUBCLASS, TRIGGER_CODE))
810*43a90889SApple OSS Distributions
811*43a90889SApple OSS Distributions T_DECL(kperf_kdebug_trigger_classes,
812*43a90889SApple OSS Distributions "test that kdebug trigger samples on classes",
813*43a90889SApple OSS Distributions T_META_TAG_VM_PREFERRED)
814*43a90889SApple OSS Distributions {
815*43a90889SApple OSS Distributions start_controlling_ktrace();
816*43a90889SApple OSS Distributions
817*43a90889SApple OSS Distributions const uint32_t class_debugids[] = {
818*43a90889SApple OSS Distributions KDBG_EVENTID(TRIGGER_CLASS, 1, 1),
819*43a90889SApple OSS Distributions KDBG_EVENTID(TRIGGER_CLASS, 2, 1),
820*43a90889SApple OSS Distributions KDBG_EVENTID(TRIGGER_CLASS_END, 1, 1) | DBG_FUNC_END,
821*43a90889SApple OSS Distributions KDBG_EVENTID(TRIGGER_CLASS_END, 2, 1) | DBG_FUNC_END,
822*43a90889SApple OSS Distributions };
823*43a90889SApple OSS Distributions
824*43a90889SApple OSS Distributions expect_kdebug_trigger("C0xfe,C0xfdr", class_debugids,
825*43a90889SApple OSS Distributions sizeof(class_debugids) / sizeof(class_debugids[0]));
826*43a90889SApple OSS Distributions dispatch_main();
827*43a90889SApple OSS Distributions }
828*43a90889SApple OSS Distributions
829*43a90889SApple OSS Distributions T_DECL(kperf_kdebug_trigger_subclasses,
830*43a90889SApple OSS Distributions "test that kdebug trigger samples on subclasses",
831*43a90889SApple OSS Distributions T_META_TAG_VM_PREFERRED)
832*43a90889SApple OSS Distributions {
833*43a90889SApple OSS Distributions start_controlling_ktrace();
834*43a90889SApple OSS Distributions
835*43a90889SApple OSS Distributions const uint32_t subclass_debugids[] = {
836*43a90889SApple OSS Distributions KDBG_EVENTID(TRIGGER_CLASS, TRIGGER_SUBCLASS, 0),
837*43a90889SApple OSS Distributions KDBG_EVENTID(TRIGGER_CLASS, TRIGGER_SUBCLASS, 1),
838*43a90889SApple OSS Distributions KDBG_EVENTID(TRIGGER_CLASS_END, TRIGGER_SUBCLASS, 0) | DBG_FUNC_END,
839*43a90889SApple OSS Distributions KDBG_EVENTID(TRIGGER_CLASS_END, TRIGGER_SUBCLASS, 1) | DBG_FUNC_END
840*43a90889SApple OSS Distributions };
841*43a90889SApple OSS Distributions
842*43a90889SApple OSS Distributions expect_kdebug_trigger("S0xfeff,S0xfdffr", subclass_debugids,
843*43a90889SApple OSS Distributions sizeof(subclass_debugids) / sizeof(subclass_debugids[0]));
844*43a90889SApple OSS Distributions dispatch_main();
845*43a90889SApple OSS Distributions }
846*43a90889SApple OSS Distributions
847*43a90889SApple OSS Distributions T_DECL(kperf_kdebug_trigger_debugids,
848*43a90889SApple OSS Distributions "test that kdebug trigger samples on debugids",
849*43a90889SApple OSS Distributions T_META_TAG_VM_PREFERRED)
850*43a90889SApple OSS Distributions {
851*43a90889SApple OSS Distributions start_controlling_ktrace();
852*43a90889SApple OSS Distributions
853*43a90889SApple OSS Distributions const uint32_t debugids[] = {
854*43a90889SApple OSS Distributions TRIGGER_DEBUGID
855*43a90889SApple OSS Distributions };
856*43a90889SApple OSS Distributions
857*43a90889SApple OSS Distributions expect_kdebug_trigger("D0xfeff0000", debugids,
858*43a90889SApple OSS Distributions sizeof(debugids) / sizeof(debugids[0]));
859*43a90889SApple OSS Distributions dispatch_main();
860*43a90889SApple OSS Distributions }
861*43a90889SApple OSS Distributions
862*43a90889SApple OSS Distributions // TODO Set a single function specifier filter, expect not to trigger of all
863*43a90889SApple OSS Distributions // events from that class.
864*43a90889SApple OSS Distributions
865*43a90889SApple OSS Distributions static void
reset_kperf(void)866*43a90889SApple OSS Distributions reset_kperf(void)
867*43a90889SApple OSS Distributions {
868*43a90889SApple OSS Distributions (void)kperf_reset();
869*43a90889SApple OSS Distributions (void)sysctlbyname("kperf.debug_level", NULL, NULL, &(int){ 0 },
870*43a90889SApple OSS Distributions sizeof(int));
871*43a90889SApple OSS Distributions }
872*43a90889SApple OSS Distributions
873*43a90889SApple OSS Distributions T_DECL(kperf_kdbg_callstacks,
874*43a90889SApple OSS Distributions "test that the kdbg_callstacks samples on syscalls",
875*43a90889SApple OSS Distributions T_META_TAG_VM_PREFERRED)
876*43a90889SApple OSS Distributions {
877*43a90889SApple OSS Distributions start_controlling_ktrace();
878*43a90889SApple OSS Distributions
879*43a90889SApple OSS Distributions ktrace_session_t s;
880*43a90889SApple OSS Distributions __block bool saw_user_stack = false;
881*43a90889SApple OSS Distributions
882*43a90889SApple OSS Distributions s = ktrace_session_create();
883*43a90889SApple OSS Distributions T_QUIET; T_WITH_ERRNO; T_ASSERT_NOTNULL(s, "ktrace_session_create");
884*43a90889SApple OSS Distributions ktrace_set_collection_interval(s, 100);
885*43a90889SApple OSS Distributions
886*43a90889SApple OSS Distributions // Make sure BSD events are traced in order to trigger samples on syscalls.
887*43a90889SApple OSS Distributions ktrace_events_class(s, DBG_BSD, ^void (__unused struct trace_point *tp) {});
888*43a90889SApple OSS Distributions
889*43a90889SApple OSS Distributions ktrace_events_single(s, PERF_STK_UHDR, ^(__unused struct trace_point *tp) {
890*43a90889SApple OSS Distributions saw_user_stack = true;
891*43a90889SApple OSS Distributions ktrace_end(s, 1);
892*43a90889SApple OSS Distributions });
893*43a90889SApple OSS Distributions
894*43a90889SApple OSS Distributions ktrace_set_completion_handler(s, ^{
895*43a90889SApple OSS Distributions ktrace_session_destroy(s);
896*43a90889SApple OSS Distributions
897*43a90889SApple OSS Distributions T_EXPECT_TRUE(saw_user_stack,
898*43a90889SApple OSS Distributions "saw user stack after configuring kdbg_callstacks");
899*43a90889SApple OSS Distributions T_END;
900*43a90889SApple OSS Distributions });
901*43a90889SApple OSS Distributions
902*43a90889SApple OSS Distributions #pragma clang diagnostic push
903*43a90889SApple OSS Distributions #pragma clang diagnostic ignored "-Wdeprecated-declarations"
904*43a90889SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(kperf_kdbg_callstacks_set(1), NULL);
905*43a90889SApple OSS Distributions #pragma clang diagnostic pop
906*43a90889SApple OSS Distributions T_ATEND(reset_kperf);
907*43a90889SApple OSS Distributions
908*43a90889SApple OSS Distributions T_ASSERT_POSIX_ZERO(ktrace_start(s, dispatch_get_main_queue()), NULL);
909*43a90889SApple OSS Distributions
910*43a90889SApple OSS Distributions dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 10 * NSEC_PER_SEC),
911*43a90889SApple OSS Distributions dispatch_get_main_queue(), ^(void) {
912*43a90889SApple OSS Distributions ktrace_end(s, 1);
913*43a90889SApple OSS Distributions });
914*43a90889SApple OSS Distributions
915*43a90889SApple OSS Distributions dispatch_main();
916*43a90889SApple OSS Distributions }
917*43a90889SApple OSS Distributions
918*43a90889SApple OSS Distributions #pragma mark - PET
919*43a90889SApple OSS Distributions
920*43a90889SApple OSS Distributions #define STACKS_WAIT_DURATION_NS (3 * NSEC_PER_SEC)
921*43a90889SApple OSS Distributions
922*43a90889SApple OSS Distributions static void
923*43a90889SApple OSS Distributions expect_stacks_traced(void (^setup)(ktrace_session_t s), void (^complete)(void))
924*43a90889SApple OSS Distributions {
925*43a90889SApple OSS Distributions ktrace_session_t s;
926*43a90889SApple OSS Distributions
927*43a90889SApple OSS Distributions s = ktrace_session_create();
928*43a90889SApple OSS Distributions T_QUIET; T_WITH_ERRNO; T_ASSERT_NOTNULL(s, "ktrace_session_create");
929*43a90889SApple OSS Distributions ktrace_set_collection_interval(s, 100);
930*43a90889SApple OSS Distributions if (setup) {
931*43a90889SApple OSS Distributions setup(s);
932*43a90889SApple OSS Distributions }
933*43a90889SApple OSS Distributions
934*43a90889SApple OSS Distributions __block unsigned int user_stacks = 0;
935*43a90889SApple OSS Distributions __block unsigned int kernel_stacks = 0;
936*43a90889SApple OSS Distributions
937*43a90889SApple OSS Distributions ktrace_events_single(s, PERF_STK_UHDR, ^(__unused struct trace_point *tp) {
938*43a90889SApple OSS Distributions user_stacks++;
939*43a90889SApple OSS Distributions });
940*43a90889SApple OSS Distributions ktrace_events_single(s, PERF_STK_KHDR, ^(__unused struct trace_point *tp) {
941*43a90889SApple OSS Distributions kernel_stacks++;
942*43a90889SApple OSS Distributions });
943*43a90889SApple OSS Distributions
944*43a90889SApple OSS Distributions ktrace_set_completion_handler(s, ^(void) {
945*43a90889SApple OSS Distributions ktrace_session_destroy(s);
946*43a90889SApple OSS Distributions T_EXPECT_GT(user_stacks, 0U, NULL);
947*43a90889SApple OSS Distributions T_EXPECT_GT(kernel_stacks, 0U, NULL);
948*43a90889SApple OSS Distributions complete();
949*43a90889SApple OSS Distributions });
950*43a90889SApple OSS Distributions
951*43a90889SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(kperf_sample_set(1), NULL);
952*43a90889SApple OSS Distributions
953*43a90889SApple OSS Distributions T_ASSERT_POSIX_ZERO(ktrace_start(s, dispatch_get_main_queue()), NULL);
954*43a90889SApple OSS Distributions
955*43a90889SApple OSS Distributions dispatch_after(dispatch_time(DISPATCH_TIME_NOW, STACKS_WAIT_DURATION_NS),
956*43a90889SApple OSS Distributions dispatch_get_main_queue(), ^(void)
957*43a90889SApple OSS Distributions {
958*43a90889SApple OSS Distributions kperf_reset();
959*43a90889SApple OSS Distributions ktrace_end(s, 0);
960*43a90889SApple OSS Distributions });
961*43a90889SApple OSS Distributions }
962*43a90889SApple OSS Distributions
963*43a90889SApple OSS Distributions T_DECL(kperf_pet, "test that PET mode samples kernel and user stacks",
964*43a90889SApple OSS Distributions T_META_TAG_VM_PREFERRED)
965*43a90889SApple OSS Distributions {
966*43a90889SApple OSS Distributions start_controlling_ktrace();
967*43a90889SApple OSS Distributions
968*43a90889SApple OSS Distributions configure_kperf_stacks_timer(-1, 10, false);
969*43a90889SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(kperf_timer_pet_set(0), NULL);
970*43a90889SApple OSS Distributions
971*43a90889SApple OSS Distributions expect_stacks_traced(NULL, ^(void) {
972*43a90889SApple OSS Distributions T_END;
973*43a90889SApple OSS Distributions });
974*43a90889SApple OSS Distributions
975*43a90889SApple OSS Distributions dispatch_main();
976*43a90889SApple OSS Distributions }
977*43a90889SApple OSS Distributions
978*43a90889SApple OSS Distributions T_DECL(kperf_lightweight_pet,
979*43a90889SApple OSS Distributions "test that lightweight PET mode samples kernel and user stacks",
980*43a90889SApple OSS Distributions T_META_ASROOT(true),
981*43a90889SApple OSS Distributions T_META_TAG_VM_PREFERRED)
982*43a90889SApple OSS Distributions {
983*43a90889SApple OSS Distributions start_controlling_ktrace();
984*43a90889SApple OSS Distributions
985*43a90889SApple OSS Distributions int set = 1;
986*43a90889SApple OSS Distributions
987*43a90889SApple OSS Distributions configure_kperf_stacks_timer(-1, 10, false);
988*43a90889SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(sysctlbyname("kperf.lightweight_pet", NULL, NULL,
989*43a90889SApple OSS Distributions &set, sizeof(set)), NULL);
990*43a90889SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(kperf_timer_pet_set(0), NULL);
991*43a90889SApple OSS Distributions
992*43a90889SApple OSS Distributions expect_stacks_traced(^(ktrace_session_t s) {}, ^(void) {
993*43a90889SApple OSS Distributions T_END;
994*43a90889SApple OSS Distributions });
995*43a90889SApple OSS Distributions
996*43a90889SApple OSS Distributions dispatch_main();
997*43a90889SApple OSS Distributions }
998*43a90889SApple OSS Distributions
999*43a90889SApple OSS Distributions T_DECL(kperf_pet_stress, "repeatedly enable and disable PET mode",
1000*43a90889SApple OSS Distributions T_META_TAG_VM_NOT_ELIGIBLE)
1001*43a90889SApple OSS Distributions {
1002*43a90889SApple OSS Distributions start_controlling_ktrace();
1003*43a90889SApple OSS Distributions
1004*43a90889SApple OSS Distributions const int niters = 500;
1005*43a90889SApple OSS Distributions for (int i = 0; i < niters; i++) {
1006*43a90889SApple OSS Distributions configure_kperf_stacks_timer(-1, 1, true);
1007*43a90889SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(kperf_timer_pet_set(0), NULL);
1008*43a90889SApple OSS Distributions T_QUIET;
1009*43a90889SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(kperf_sample_set(1), "start kperf sampling");
1010*43a90889SApple OSS Distributions usleep(2000);
1011*43a90889SApple OSS Distributions kperf_reset();
1012*43a90889SApple OSS Distributions }
1013*43a90889SApple OSS Distributions
1014*43a90889SApple OSS Distributions T_PASS("configured kperf PET %d times", niters);
1015*43a90889SApple OSS Distributions }
1016*43a90889SApple OSS Distributions
1017*43a90889SApple OSS Distributions #pragma mark - PMCs
1018*43a90889SApple OSS Distributions
1019*43a90889SApple OSS Distributions T_DECL(kperf_pmc_config_only,
1020*43a90889SApple OSS Distributions "shouldn't show PMC config events unless requested",
1021*43a90889SApple OSS Distributions T_META_TAG_VM_NOT_ELIGIBLE)
1022*43a90889SApple OSS Distributions {
1023*43a90889SApple OSS Distributions start_controlling_ktrace();
1024*43a90889SApple OSS Distributions
1025*43a90889SApple OSS Distributions __block bool saw_kpc_config = false;
1026*43a90889SApple OSS Distributions __block bool saw_kpc_reg = false;
1027*43a90889SApple OSS Distributions
1028*43a90889SApple OSS Distributions ktrace_session_t s = ktrace_session_create();
1029*43a90889SApple OSS Distributions T_QUIET; T_WITH_ERRNO; T_ASSERT_NOTNULL(s, "ktrace_session_create");
1030*43a90889SApple OSS Distributions ktrace_set_collection_interval(s, 100);
1031*43a90889SApple OSS Distributions
1032*43a90889SApple OSS Distributions ktrace_events_single(s, PERF_KPC_CONFIG,
1033*43a90889SApple OSS Distributions ^(__unused struct trace_point *tp) {
1034*43a90889SApple OSS Distributions saw_kpc_config = true;
1035*43a90889SApple OSS Distributions });
1036*43a90889SApple OSS Distributions ktrace_events_single(s, PERF_KPC_REG,
1037*43a90889SApple OSS Distributions ^(__unused struct trace_point *tp) {
1038*43a90889SApple OSS Distributions saw_kpc_reg = true;
1039*43a90889SApple OSS Distributions });
1040*43a90889SApple OSS Distributions ktrace_events_single(s, PERF_KPC_REG32,
1041*43a90889SApple OSS Distributions ^(__unused struct trace_point *tp) {
1042*43a90889SApple OSS Distributions saw_kpc_reg = true;
1043*43a90889SApple OSS Distributions });
1044*43a90889SApple OSS Distributions
1045*43a90889SApple OSS Distributions ktrace_set_completion_handler(s, ^{
1046*43a90889SApple OSS Distributions ktrace_session_destroy(s);
1047*43a90889SApple OSS Distributions T_EXPECT_FALSE(saw_kpc_config,
1048*43a90889SApple OSS Distributions "should see no KPC configs without sampler enabled");
1049*43a90889SApple OSS Distributions T_EXPECT_FALSE(saw_kpc_reg,
1050*43a90889SApple OSS Distributions "should see no KPC registers without sampler enabled");
1051*43a90889SApple OSS Distributions T_END;
1052*43a90889SApple OSS Distributions });
1053*43a90889SApple OSS Distributions
1054*43a90889SApple OSS Distributions uint32_t nconfigs = kpc_get_config_count(KPC_CLASS_CONFIGURABLE_MASK);
1055*43a90889SApple OSS Distributions uint64_t *config = calloc(nconfigs, sizeof(*config));
1056*43a90889SApple OSS Distributions config[0] = 0x02;
1057*43a90889SApple OSS Distributions int ret = kpc_set_config(KPC_CLASS_CONFIGURABLE_MASK, config);
1058*43a90889SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(ret, "configured kpc");
1059*43a90889SApple OSS Distributions T_QUIET;
1060*43a90889SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(kpc_set_counting(KPC_CLASS_CONFIGURABLE_MASK),
1061*43a90889SApple OSS Distributions "kpc_set_counting");
1062*43a90889SApple OSS Distributions
1063*43a90889SApple OSS Distributions (void)kperf_action_count_set(1);
1064*43a90889SApple OSS Distributions T_ATEND(reset_kperf);
1065*43a90889SApple OSS Distributions T_QUIET;
1066*43a90889SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(kperf_action_samplers_set(1, KPERF_SAMPLER_PMC_CPU),
1067*43a90889SApple OSS Distributions NULL);
1068*43a90889SApple OSS Distributions
1069*43a90889SApple OSS Distributions (void)kperf_timer_count_set(1);
1070*43a90889SApple OSS Distributions T_QUIET;
1071*43a90889SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(kperf_timer_period_set(0,
1072*43a90889SApple OSS Distributions kperf_ns_to_ticks(TIMER_PERIOD_NS)), NULL);
1073*43a90889SApple OSS Distributions T_QUIET;
1074*43a90889SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(kperf_timer_action_set(0, 1), NULL);
1075*43a90889SApple OSS Distributions
1076*43a90889SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(kperf_sample_set(1), "start kperf sampling");
1077*43a90889SApple OSS Distributions
1078*43a90889SApple OSS Distributions T_ASSERT_POSIX_ZERO(ktrace_start(s, dispatch_get_main_queue()), NULL);
1079*43a90889SApple OSS Distributions
1080*43a90889SApple OSS Distributions dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 10 * NSEC_PER_SEC),
1081*43a90889SApple OSS Distributions dispatch_get_main_queue(), ^(void) {
1082*43a90889SApple OSS Distributions ktrace_end(s, 1);
1083*43a90889SApple OSS Distributions });
1084*43a90889SApple OSS Distributions
1085*43a90889SApple OSS Distributions dispatch_main();
1086*43a90889SApple OSS Distributions }
1087*43a90889SApple OSS Distributions
1088*43a90889SApple OSS Distributions static void
skip_if_monotonic_unsupported(void)1089*43a90889SApple OSS Distributions skip_if_monotonic_unsupported(void)
1090*43a90889SApple OSS Distributions {
1091*43a90889SApple OSS Distributions int r;
1092*43a90889SApple OSS Distributions int supported = 0;
1093*43a90889SApple OSS Distributions size_t supported_size = sizeof(supported);
1094*43a90889SApple OSS Distributions
1095*43a90889SApple OSS Distributions r = sysctlbyname("kern.monotonic.supported", &supported, &supported_size,
1096*43a90889SApple OSS Distributions NULL, 0);
1097*43a90889SApple OSS Distributions if (r < 0) {
1098*43a90889SApple OSS Distributions T_WITH_ERRNO;
1099*43a90889SApple OSS Distributions T_SKIP("could not find \"kern.monotonic.supported\" sysctl");
1100*43a90889SApple OSS Distributions }
1101*43a90889SApple OSS Distributions
1102*43a90889SApple OSS Distributions if (!supported) {
1103*43a90889SApple OSS Distributions T_SKIP("monotonic is not supported on this platform");
1104*43a90889SApple OSS Distributions }
1105*43a90889SApple OSS Distributions }
1106*43a90889SApple OSS Distributions
1107*43a90889SApple OSS Distributions #define INSTRS_CYCLES_UPPER 500
1108*43a90889SApple OSS Distributions #define INSTRS_CYCLES_LOWER 50
1109*43a90889SApple OSS Distributions
1110*43a90889SApple OSS Distributions T_DECL(kperf_sample_instrs_cycles,
1111*43a90889SApple OSS Distributions "ensure instructions and cycles are sampled",
1112*43a90889SApple OSS Distributions T_META_TAG_VM_NOT_ELIGIBLE)
1113*43a90889SApple OSS Distributions {
1114*43a90889SApple OSS Distributions T_SETUPBEGIN;
1115*43a90889SApple OSS Distributions
1116*43a90889SApple OSS Distributions skip_if_monotonic_unsupported();
1117*43a90889SApple OSS Distributions start_controlling_ktrace();
1118*43a90889SApple OSS Distributions
1119*43a90889SApple OSS Distributions ktrace_session_t sess = ktrace_session_create();
1120*43a90889SApple OSS Distributions T_QUIET; T_WITH_ERRNO; T_ASSERT_NOTNULL(sess, "ktrace_session_create");
1121*43a90889SApple OSS Distributions ktrace_set_collection_interval(sess, 100);
1122*43a90889SApple OSS Distributions
1123*43a90889SApple OSS Distributions __block uint64_t ninstrs_cycles = 0;
1124*43a90889SApple OSS Distributions __block uint64_t nzeroes = 0;
1125*43a90889SApple OSS Distributions ktrace_events_single(sess, PERF_INSTR_DATA,
1126*43a90889SApple OSS Distributions ^(__unused struct trace_point *tp) {
1127*43a90889SApple OSS Distributions ninstrs_cycles++;
1128*43a90889SApple OSS Distributions if (tp->arg1 == 0) {
1129*43a90889SApple OSS Distributions T_LOG("%llx (%s)\n", tp->threadid, tp->command);
1130*43a90889SApple OSS Distributions nzeroes++;
1131*43a90889SApple OSS Distributions }
1132*43a90889SApple OSS Distributions if (ninstrs_cycles >= INSTRS_CYCLES_UPPER) {
1133*43a90889SApple OSS Distributions ktrace_end(sess, 1);
1134*43a90889SApple OSS Distributions }
1135*43a90889SApple OSS Distributions });
1136*43a90889SApple OSS Distributions
1137*43a90889SApple OSS Distributions ktrace_set_collection_interval(sess, 200);
1138*43a90889SApple OSS Distributions
1139*43a90889SApple OSS Distributions ktrace_set_completion_handler(sess, ^{
1140*43a90889SApple OSS Distributions T_EXPECT_GE(ninstrs_cycles, (uint64_t)INSTRS_CYCLES_LOWER,
1141*43a90889SApple OSS Distributions "saw enough instructions and cycles events");
1142*43a90889SApple OSS Distributions T_EXPECT_EQ(nzeroes, UINT64_C(0),
1143*43a90889SApple OSS Distributions "saw no events with 0 instructions");
1144*43a90889SApple OSS Distributions T_END;
1145*43a90889SApple OSS Distributions });
1146*43a90889SApple OSS Distributions
1147*43a90889SApple OSS Distributions (void)kperf_action_count_set(1);
1148*43a90889SApple OSS Distributions T_ATEND(reset_kperf);
1149*43a90889SApple OSS Distributions T_QUIET;
1150*43a90889SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(kperf_action_samplers_set(1,
1151*43a90889SApple OSS Distributions KPERF_SAMPLER_TH_INSTRS_CYCLES), NULL);
1152*43a90889SApple OSS Distributions
1153*43a90889SApple OSS Distributions (void)kperf_timer_count_set(1);
1154*43a90889SApple OSS Distributions T_QUIET;
1155*43a90889SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(kperf_timer_period_set(0,
1156*43a90889SApple OSS Distributions kperf_ns_to_ticks(TIMER_PERIOD_NS)), NULL);
1157*43a90889SApple OSS Distributions T_QUIET;
1158*43a90889SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(kperf_timer_action_set(0, 1), NULL);
1159*43a90889SApple OSS Distributions
1160*43a90889SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(kperf_sample_set(1), "start kperf sampling");
1161*43a90889SApple OSS Distributions
1162*43a90889SApple OSS Distributions T_ASSERT_POSIX_ZERO(ktrace_start(sess, dispatch_get_main_queue()),
1163*43a90889SApple OSS Distributions NULL);
1164*43a90889SApple OSS Distributions
1165*43a90889SApple OSS Distributions T_SETUPEND;
1166*43a90889SApple OSS Distributions
1167*43a90889SApple OSS Distributions dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 10 * NSEC_PER_SEC),
1168*43a90889SApple OSS Distributions dispatch_get_main_queue(), ^(void) {
1169*43a90889SApple OSS Distributions ktrace_end(sess, 1);
1170*43a90889SApple OSS Distributions });
1171*43a90889SApple OSS Distributions
1172*43a90889SApple OSS Distributions dispatch_main();
1173*43a90889SApple OSS Distributions }
1174*43a90889SApple OSS Distributions
1175*43a90889SApple OSS Distributions #define UNCOMMON_EVENTID 0xfeedfac0
1176*43a90889SApple OSS Distributions #define LABEL "this_is_a_test_label_that_is_very_long_and_will_be_truncated" \
1177*43a90889SApple OSS Distributions "_but_needs_some_more_length_for_good_measure"
1178*43a90889SApple OSS Distributions #define MAX_LABEL_LEN 64
1179*43a90889SApple OSS Distributions static_assert(sizeof(LABEL) > MAX_LABEL_LEN,
1180*43a90889SApple OSS Distributions "should be larger than the max length of a label");
1181*43a90889SApple OSS Distributions
1182*43a90889SApple OSS Distributions T_DECL(kperf_dispatch_labels, "ensure dispatch queue labels are sampled",
1183*43a90889SApple OSS Distributions T_META_TAG_VM_PREFERRED)
1184*43a90889SApple OSS Distributions {
1185*43a90889SApple OSS Distributions T_SETUPBEGIN;
1186*43a90889SApple OSS Distributions start_controlling_ktrace();
1187*43a90889SApple OSS Distributions ktrace_session_t sess = ktrace_session_create();
1188*43a90889SApple OSS Distributions ktrace_set_collection_interval(sess, 200);
1189*43a90889SApple OSS Distributions
1190*43a90889SApple OSS Distributions /*
1191*43a90889SApple OSS Distributions * Expect to see the label that was sampled by kperf.
1192*43a90889SApple OSS Distributions */
1193*43a90889SApple OSS Distributions __block uint64_t nlabels = 0;
1194*43a90889SApple OSS Distributions char obs_label[MAX_LABEL_LEN + 1] = {};
1195*43a90889SApple OSS Distributions char *obs_label_b = obs_label;
1196*43a90889SApple OSS Distributions char exp_label[MAX_LABEL_LEN + 1] = {};
1197*43a90889SApple OSS Distributions strlcpy(exp_label, LABEL, sizeof(exp_label));
1198*43a90889SApple OSS Distributions char *exp_label_b = exp_label;
1199*43a90889SApple OSS Distributions
1200*43a90889SApple OSS Distributions ktrace_events_single(sess, PERF_DISPLABEL, ^(struct trace_point *tp) {
1201*43a90889SApple OSS Distributions nlabels++;
1202*43a90889SApple OSS Distributions size_t argsize = ktrace_is_kernel_64_bit(sess) ? 8 : 4;
1203*43a90889SApple OSS Distributions strncat(obs_label_b, (char *)&tp->arg1, argsize);
1204*43a90889SApple OSS Distributions strncat(obs_label_b, (char *)&tp->arg2, argsize);
1205*43a90889SApple OSS Distributions strncat(obs_label_b, (char *)&tp->arg3, argsize);
1206*43a90889SApple OSS Distributions strncat(obs_label_b, (char *)&tp->arg4, argsize);
1207*43a90889SApple OSS Distributions if (tp->debugid & DBG_FUNC_END) {
1208*43a90889SApple OSS Distributions ktrace_end(sess, 1);
1209*43a90889SApple OSS Distributions }
1210*43a90889SApple OSS Distributions });
1211*43a90889SApple OSS Distributions ktrace_events_single(sess, PERF_DISPSAMPLE, ^(struct trace_point *tp) {
1212*43a90889SApple OSS Distributions if (tp->debugid & DBG_FUNC_END) {
1213*43a90889SApple OSS Distributions T_LOG("ending sample event returned %d (%s)",
1214*43a90889SApple OSS Distributions (int)tp->arg1, strerror((int)tp->arg1));
1215*43a90889SApple OSS Distributions }
1216*43a90889SApple OSS Distributions });
1217*43a90889SApple OSS Distributions ktrace_events_single(sess, UNCOMMON_EVENTID,
1218*43a90889SApple OSS Distributions ^(__unused struct trace_point *tp) {
1219*43a90889SApple OSS Distributions T_LOG("saw triggering event");
1220*43a90889SApple OSS Distributions });
1221*43a90889SApple OSS Distributions ktrace_set_completion_handler(sess, ^{
1222*43a90889SApple OSS Distributions T_EXPECT_GT(nlabels, 0ULL, "saw %" PRIu64
1223*43a90889SApple OSS Distributions " dispatch queue label events", nlabels);
1224*43a90889SApple OSS Distributions T_EXPECT_EQ_STR(obs_label_b, exp_label_b, "label string is correct");
1225*43a90889SApple OSS Distributions T_END;
1226*43a90889SApple OSS Distributions });
1227*43a90889SApple OSS Distributions
1228*43a90889SApple OSS Distributions /*
1229*43a90889SApple OSS Distributions * Set up kperf to log a dispatch queue label when an uncommon event ID
1230*43a90889SApple OSS Distributions * is traced.
1231*43a90889SApple OSS Distributions */
1232*43a90889SApple OSS Distributions (void)sysctlbyname("kperf.debug_level", NULL, NULL, &(int){ 2 }, sizeof(int));
1233*43a90889SApple OSS Distributions (void)kperf_action_count_set(1);
1234*43a90889SApple OSS Distributions T_ATEND(reset_kperf);
1235*43a90889SApple OSS Distributions T_QUIET;
1236*43a90889SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(kperf_action_samplers_set(1,
1237*43a90889SApple OSS Distributions KPERF_SAMPLER_TH_DISPATCH), NULL);
1238*43a90889SApple OSS Distributions (void)kperf_kdebug_action_set(1);
1239*43a90889SApple OSS Distributions kperf_kdebug_filter_t kdfilt = kperf_kdebug_filter_create();
1240*43a90889SApple OSS Distributions T_QUIET;
1241*43a90889SApple OSS Distributions T_ASSERT_NOTNULL(kdfilt, "create kdebug filter for kperf");
1242*43a90889SApple OSS Distributions T_QUIET;
1243*43a90889SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(
1244*43a90889SApple OSS Distributions kperf_kdebug_filter_add_debugid(kdfilt, UNCOMMON_EVENTID),
1245*43a90889SApple OSS Distributions "add debugid to filter on");
1246*43a90889SApple OSS Distributions T_QUIET;
1247*43a90889SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(
1248*43a90889SApple OSS Distributions kperf_kdebug_filter_set(kdfilt), "set filter for kperf");
1249*43a90889SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(kperf_sample_set(1), "start kperf sampling");
1250*43a90889SApple OSS Distributions
1251*43a90889SApple OSS Distributions T_ASSERT_POSIX_ZERO(ktrace_start(sess, dispatch_get_main_queue()),
1252*43a90889SApple OSS Distributions NULL);
1253*43a90889SApple OSS Distributions
1254*43a90889SApple OSS Distributions /*
1255*43a90889SApple OSS Distributions * Create the queue and emit the sampling event from it.
1256*43a90889SApple OSS Distributions */
1257*43a90889SApple OSS Distributions dispatch_queue_t testq = dispatch_queue_create(LABEL, 0);
1258*43a90889SApple OSS Distributions T_ASSERT_NOTNULL(testq, "created queue with label: " LABEL);
1259*43a90889SApple OSS Distributions dispatch_async(testq, ^{
1260*43a90889SApple OSS Distributions kdebug_trace(UNCOMMON_EVENTID, 0, 0, 0, 0);
1261*43a90889SApple OSS Distributions sleep(10);
1262*43a90889SApple OSS Distributions });
1263*43a90889SApple OSS Distributions
1264*43a90889SApple OSS Distributions T_SETUPEND;
1265*43a90889SApple OSS Distributions
1266*43a90889SApple OSS Distributions dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC),
1267*43a90889SApple OSS Distributions dispatch_get_main_queue(), ^(void) {
1268*43a90889SApple OSS Distributions ktrace_end(sess, 1);
1269*43a90889SApple OSS Distributions });
1270*43a90889SApple OSS Distributions
1271*43a90889SApple OSS Distributions dispatch_main();
1272*43a90889SApple OSS Distributions }
1273*43a90889SApple OSS Distributions
1274*43a90889SApple OSS Distributions T_HELPER_DECL(kperf_blessed_helper,
1275*43a90889SApple OSS Distributions "drop priviliges and attempt to configure kperf")
1276*43a90889SApple OSS Distributions {
1277*43a90889SApple OSS Distributions drop_priv();
1278*43a90889SApple OSS Distributions (void)kperf_action_count_set(1);
1279*43a90889SApple OSS Distributions errno = 0;
1280*43a90889SApple OSS Distributions int ret = kperf_lazy_wait_action_set(1);
1281*43a90889SApple OSS Distributions int error = errno;
1282*43a90889SApple OSS Distributions exit(ret != 0 ? (error == 0) ? EINVAL : error : 0);
1283*43a90889SApple OSS Distributions }
1284*43a90889SApple OSS Distributions
1285*43a90889SApple OSS Distributions static pid_t
spawn_bless_helper(void)1286*43a90889SApple OSS Distributions spawn_bless_helper(void)
1287*43a90889SApple OSS Distributions {
1288*43a90889SApple OSS Distributions char test_path[MAXPATHLEN] = { 0 };
1289*43a90889SApple OSS Distributions int ret = proc_pidpath(getpid(), test_path, MAXPATHLEN);
1290*43a90889SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "query path for current process");
1291*43a90889SApple OSS Distributions T_LOG("spawning helper tool at %s", test_path);
1292*43a90889SApple OSS Distributions char *child_argv[] = { test_path, "-n", "kperf_blessed_helper", NULL };
1293*43a90889SApple OSS Distributions pid_t child_pid = -1;
1294*43a90889SApple OSS Distributions int error = dt_launch_tool(&child_pid, child_argv, true, NULL, NULL);
1295*43a90889SApple OSS Distributions T_ASSERT_POSIX_ZERO(error, "spawned child with pid %d", child_pid);
1296*43a90889SApple OSS Distributions T_QUIET; T_ASSERT_GT(child_pid, 0, "child pid is valid");
1297*43a90889SApple OSS Distributions return child_pid;
1298*43a90889SApple OSS Distributions }
1299*43a90889SApple OSS Distributions
1300*43a90889SApple OSS Distributions static int
test_child_process(pid_t child_pid)1301*43a90889SApple OSS Distributions test_child_process(pid_t child_pid)
1302*43a90889SApple OSS Distributions {
1303*43a90889SApple OSS Distributions int ret = kill(child_pid, SIGCONT);
1304*43a90889SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(ret, "continuing child process");
1305*43a90889SApple OSS Distributions int status = 0;
1306*43a90889SApple OSS Distributions ret = waitpid(child_pid, &status, 0);
1307*43a90889SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(ret, "waited on child process");
1308*43a90889SApple OSS Distributions return status;
1309*43a90889SApple OSS Distributions }
1310*43a90889SApple OSS Distributions
1311*43a90889SApple OSS Distributions T_DECL(kperf_unblessed_refusal,
1312*43a90889SApple OSS Distributions "check that an unblessed child cannot access ktrace",
1313*43a90889SApple OSS Distributions T_META_TAG_VM_PREFERRED)
1314*43a90889SApple OSS Distributions {
1315*43a90889SApple OSS Distributions T_SETUPBEGIN;
1316*43a90889SApple OSS Distributions pid_t child_pid = spawn_bless_helper();
1317*43a90889SApple OSS Distributions T_SETUPEND;
1318*43a90889SApple OSS Distributions int status = test_child_process(child_pid);
1319*43a90889SApple OSS Distributions int exit_status = WEXITSTATUS(status);
1320*43a90889SApple OSS Distributions T_EXPECT_NE(exit_status, 0, "child failed to access ktrace with %d (%s)",
1321*43a90889SApple OSS Distributions exit_status, exit_status == 0 ? "ok" : strerror(exit_status));
1322*43a90889SApple OSS Distributions }
1323*43a90889SApple OSS Distributions
1324*43a90889SApple OSS Distributions T_DECL(kperf_blessed_ownership, "check that a blessed child can access ktrace",
1325*43a90889SApple OSS Distributions T_META_TAG_VM_PREFERRED)
1326*43a90889SApple OSS Distributions {
1327*43a90889SApple OSS Distributions T_LOG("parent pid is %d\n", getpid());
1328*43a90889SApple OSS Distributions T_SETUPBEGIN;
1329*43a90889SApple OSS Distributions pid_t child_pid = spawn_bless_helper();
1330*43a90889SApple OSS Distributions T_SETUPEND;
1331*43a90889SApple OSS Distributions int ret = kperf_bless_set(child_pid);
1332*43a90889SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(ret, "blessed child with pid %d", child_pid);
1333*43a90889SApple OSS Distributions int status = test_child_process(child_pid);
1334*43a90889SApple OSS Distributions int exit_status = WEXITSTATUS(status);
1335*43a90889SApple OSS Distributions T_EXPECT_EQ(exit_status, 0, "child status was %d (%s)", exit_status,
1336*43a90889SApple OSS Distributions exit_status == 0 ? "ok" : strerror(exit_status));
1337*43a90889SApple OSS Distributions ret = kperf_bless_set(-1);
1338*43a90889SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(ret, "removed blessing from child");
1339*43a90889SApple OSS Distributions }
1340*43a90889SApple OSS Distributions
1341