1*a325d9c4SApple OSS Distributions /*
2*a325d9c4SApple OSS Distributions * Must come before including darwintest.h
3*a325d9c4SApple OSS Distributions */
4*a325d9c4SApple OSS Distributions #ifdef T_NAMESPACE
5*a325d9c4SApple OSS Distributions #undef T_NAMESPACE
6*a325d9c4SApple OSS Distributions #endif /* defined(T_NAMESPACE) */
7*a325d9c4SApple OSS Distributions
8*a325d9c4SApple OSS Distributions #include <darwintest.h>
9*a325d9c4SApple OSS Distributions #include <fcntl.h>
10*a325d9c4SApple OSS Distributions #include <inttypes.h>
11*a325d9c4SApple OSS Distributions #ifndef PRIVATE
12*a325d9c4SApple OSS Distributions /*
13*a325d9c4SApple OSS Distributions * Need new CPU families.
14*a325d9c4SApple OSS Distributions */
15*a325d9c4SApple OSS Distributions #define PRIVATE
16*a325d9c4SApple OSS Distributions #include <mach/machine.h>
17*a325d9c4SApple OSS Distributions #undef PRIVATE
18*a325d9c4SApple OSS Distributions #else /* !defined(PRIVATE) */
19*a325d9c4SApple OSS Distributions #include <mach/machine.h>
20*a325d9c4SApple OSS Distributions #endif /* defined(PRIVATE) */
21*a325d9c4SApple OSS Distributions #include <ktrace.h>
22*a325d9c4SApple OSS Distributions #include <mach/mach.h>
23*a325d9c4SApple OSS Distributions #include <stdint.h>
24*a325d9c4SApple OSS Distributions #include <System/sys/guarded.h>
25*a325d9c4SApple OSS Distributions #include <System/sys/monotonic.h>
26*a325d9c4SApple OSS Distributions #include <sys/ioctl.h>
27*a325d9c4SApple OSS Distributions #include <sys/kdebug.h>
28*a325d9c4SApple OSS Distributions #include <sys/sysctl.h>
29*a325d9c4SApple OSS Distributions #include <unistd.h>
30*a325d9c4SApple OSS Distributions
31*a325d9c4SApple OSS Distributions T_GLOBAL_META(
32*a325d9c4SApple OSS Distributions T_META_NAMESPACE("xnu.monotonic"),
33*a325d9c4SApple OSS Distributions T_META_CHECK_LEAKS(false)
34*a325d9c4SApple OSS Distributions );
35*a325d9c4SApple OSS Distributions
36*a325d9c4SApple OSS Distributions static void
skip_if_unsupported(void)37*a325d9c4SApple OSS Distributions skip_if_unsupported(void)
38*a325d9c4SApple OSS Distributions {
39*a325d9c4SApple OSS Distributions int r;
40*a325d9c4SApple OSS Distributions int supported = 0;
41*a325d9c4SApple OSS Distributions size_t supported_size = sizeof(supported);
42*a325d9c4SApple OSS Distributions
43*a325d9c4SApple OSS Distributions r = sysctlbyname("kern.monotonic.supported", &supported, &supported_size,
44*a325d9c4SApple OSS Distributions NULL, 0);
45*a325d9c4SApple OSS Distributions if (r < 0) {
46*a325d9c4SApple OSS Distributions T_WITH_ERRNO;
47*a325d9c4SApple OSS Distributions T_SKIP("could not find \"kern.monotonic.supported\" sysctl");
48*a325d9c4SApple OSS Distributions }
49*a325d9c4SApple OSS Distributions
50*a325d9c4SApple OSS Distributions if (!supported) {
51*a325d9c4SApple OSS Distributions T_SKIP("monotonic is not supported on this platform");
52*a325d9c4SApple OSS Distributions }
53*a325d9c4SApple OSS Distributions }
54*a325d9c4SApple OSS Distributions
55*a325d9c4SApple OSS Distributions static void
check_fixed_counts(uint64_t counts[2][2])56*a325d9c4SApple OSS Distributions check_fixed_counts(uint64_t counts[2][2])
57*a325d9c4SApple OSS Distributions {
58*a325d9c4SApple OSS Distributions T_QUIET;
59*a325d9c4SApple OSS Distributions T_EXPECT_GT(counts[0][0], UINT64_C(0), "instructions are larger than 0");
60*a325d9c4SApple OSS Distributions T_QUIET;
61*a325d9c4SApple OSS Distributions T_EXPECT_GT(counts[0][1], UINT64_C(0), "cycles are larger than 0");
62*a325d9c4SApple OSS Distributions
63*a325d9c4SApple OSS Distributions T_EXPECT_GT(counts[1][0], counts[0][0], "instructions increase monotonically");
64*a325d9c4SApple OSS Distributions T_EXPECT_GT(counts[1][1], counts[0][1], "cycles increase monotonically");
65*a325d9c4SApple OSS Distributions }
66*a325d9c4SApple OSS Distributions
67*a325d9c4SApple OSS Distributions T_DECL(core_fixed_thread_self, "check the current thread's fixed counters",
68*a325d9c4SApple OSS Distributions T_META_ASROOT(true))
69*a325d9c4SApple OSS Distributions {
70*a325d9c4SApple OSS Distributions int err;
71*a325d9c4SApple OSS Distributions extern int thread_selfcounts(int type, void *buf, size_t nbytes);
72*a325d9c4SApple OSS Distributions uint64_t counts[2][2];
73*a325d9c4SApple OSS Distributions
74*a325d9c4SApple OSS Distributions T_SETUPBEGIN;
75*a325d9c4SApple OSS Distributions skip_if_unsupported();
76*a325d9c4SApple OSS Distributions T_SETUPEND;
77*a325d9c4SApple OSS Distributions
78*a325d9c4SApple OSS Distributions err = thread_selfcounts(1, &counts[0], sizeof(counts[0]));
79*a325d9c4SApple OSS Distributions T_ASSERT_POSIX_ZERO(err, "thread_selfcounts");
80*a325d9c4SApple OSS Distributions err = thread_selfcounts(1, &counts[1], sizeof(counts[1]));
81*a325d9c4SApple OSS Distributions T_ASSERT_POSIX_ZERO(err, "thread_selfcounts");
82*a325d9c4SApple OSS Distributions
83*a325d9c4SApple OSS Distributions check_fixed_counts(counts);
84*a325d9c4SApple OSS Distributions }
85*a325d9c4SApple OSS Distributions
86*a325d9c4SApple OSS Distributions T_DECL(core_fixed_task, "check that task counting is working",
87*a325d9c4SApple OSS Distributions T_META_ASROOT(true))
88*a325d9c4SApple OSS Distributions {
89*a325d9c4SApple OSS Distributions task_t task = mach_task_self();
90*a325d9c4SApple OSS Distributions kern_return_t kr;
91*a325d9c4SApple OSS Distributions mach_msg_type_number_t size = TASK_INSPECT_BASIC_COUNTS_COUNT;
92*a325d9c4SApple OSS Distributions uint64_t counts[2][2];
93*a325d9c4SApple OSS Distributions
94*a325d9c4SApple OSS Distributions skip_if_unsupported();
95*a325d9c4SApple OSS Distributions
96*a325d9c4SApple OSS Distributions kr = task_inspect(task, TASK_INSPECT_BASIC_COUNTS,
97*a325d9c4SApple OSS Distributions (task_inspect_info_t)&counts[0], &size);
98*a325d9c4SApple OSS Distributions T_ASSERT_MACH_SUCCESS(kr,
99*a325d9c4SApple OSS Distributions "task_inspect(... TASK_INSPECT_BASIC_COUNTS ...)");
100*a325d9c4SApple OSS Distributions
101*a325d9c4SApple OSS Distributions size = TASK_INSPECT_BASIC_COUNTS_COUNT;
102*a325d9c4SApple OSS Distributions kr = task_inspect(task, TASK_INSPECT_BASIC_COUNTS,
103*a325d9c4SApple OSS Distributions (task_inspect_info_t)&counts[1], &size);
104*a325d9c4SApple OSS Distributions T_ASSERT_MACH_SUCCESS(kr,
105*a325d9c4SApple OSS Distributions "task_inspect(... TASK_INSPECT_BASIC_COUNTS ...)");
106*a325d9c4SApple OSS Distributions
107*a325d9c4SApple OSS Distributions check_fixed_counts(counts);
108*a325d9c4SApple OSS Distributions }
109*a325d9c4SApple OSS Distributions
110*a325d9c4SApple OSS Distributions T_DECL(core_fixed_kdebug, "check that the kdebug macros for monotonic work",
111*a325d9c4SApple OSS Distributions T_META_ASROOT(true))
112*a325d9c4SApple OSS Distributions {
113*a325d9c4SApple OSS Distributions __block bool saw_events = false;
114*a325d9c4SApple OSS Distributions ktrace_session_t s;
115*a325d9c4SApple OSS Distributions int r;
116*a325d9c4SApple OSS Distributions int set = 1;
117*a325d9c4SApple OSS Distributions
118*a325d9c4SApple OSS Distributions T_SETUPBEGIN;
119*a325d9c4SApple OSS Distributions skip_if_unsupported();
120*a325d9c4SApple OSS Distributions
121*a325d9c4SApple OSS Distributions s = ktrace_session_create();
122*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(s, "ktrace_session_create");
123*a325d9c4SApple OSS Distributions
124*a325d9c4SApple OSS Distributions ktrace_events_single_paired(s,
125*a325d9c4SApple OSS Distributions KDBG_EVENTID(DBG_MONOTONIC, DBG_MT_TMPCPU, 0x3fff),
126*a325d9c4SApple OSS Distributions ^(struct trace_point *start, struct trace_point *end)
127*a325d9c4SApple OSS Distributions {
128*a325d9c4SApple OSS Distributions uint64_t counts[2][2];
129*a325d9c4SApple OSS Distributions
130*a325d9c4SApple OSS Distributions saw_events = true;
131*a325d9c4SApple OSS Distributions
132*a325d9c4SApple OSS Distributions counts[0][0] = start->arg1;
133*a325d9c4SApple OSS Distributions counts[0][1] = start->arg2;
134*a325d9c4SApple OSS Distributions counts[1][0] = end->arg1;
135*a325d9c4SApple OSS Distributions counts[1][1] = end->arg2;
136*a325d9c4SApple OSS Distributions
137*a325d9c4SApple OSS Distributions check_fixed_counts(counts);
138*a325d9c4SApple OSS Distributions });
139*a325d9c4SApple OSS Distributions
140*a325d9c4SApple OSS Distributions ktrace_set_completion_handler(s, ^{
141*a325d9c4SApple OSS Distributions T_ASSERT_TRUE(saw_events, "should see monotonic kdebug events");
142*a325d9c4SApple OSS Distributions T_END;
143*a325d9c4SApple OSS Distributions });
144*a325d9c4SApple OSS Distributions T_SETUPEND;
145*a325d9c4SApple OSS Distributions
146*a325d9c4SApple OSS Distributions T_ASSERT_POSIX_ZERO(ktrace_start(s,
147*a325d9c4SApple OSS Distributions dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0)), NULL);
148*a325d9c4SApple OSS Distributions
149*a325d9c4SApple OSS Distributions r = sysctlbyname("kern.monotonic.kdebug_test", NULL, NULL, &set,
150*a325d9c4SApple OSS Distributions sizeof(set));
151*a325d9c4SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(r,
152*a325d9c4SApple OSS Distributions "sysctlbyname(\"kern.monotonic.kdebug_test\", ...)");
153*a325d9c4SApple OSS Distributions
154*a325d9c4SApple OSS Distributions ktrace_end(s, 0);
155*a325d9c4SApple OSS Distributions dispatch_main();
156*a325d9c4SApple OSS Distributions }
157*a325d9c4SApple OSS Distributions
158*a325d9c4SApple OSS Distributions static void *
spin_thread_self_counts(__unused void * arg)159*a325d9c4SApple OSS Distributions spin_thread_self_counts(__unused void *arg)
160*a325d9c4SApple OSS Distributions {
161*a325d9c4SApple OSS Distributions extern int thread_selfcounts(int, void *, size_t);
162*a325d9c4SApple OSS Distributions uint64_t counts[2] = { 0 };
163*a325d9c4SApple OSS Distributions while (true) {
164*a325d9c4SApple OSS Distributions (void)thread_selfcounts(1, &counts, sizeof(counts));
165*a325d9c4SApple OSS Distributions }
166*a325d9c4SApple OSS Distributions }
167*a325d9c4SApple OSS Distributions
168*a325d9c4SApple OSS Distributions static void *
spin_task_inspect(__unused void * arg)169*a325d9c4SApple OSS Distributions spin_task_inspect(__unused void *arg)
170*a325d9c4SApple OSS Distributions {
171*a325d9c4SApple OSS Distributions task_t task = mach_task_self();
172*a325d9c4SApple OSS Distributions uint64_t counts[2] = { 0 };
173*a325d9c4SApple OSS Distributions unsigned int size = 0;
174*a325d9c4SApple OSS Distributions while (true) {
175*a325d9c4SApple OSS Distributions size = (unsigned int)sizeof(counts);
176*a325d9c4SApple OSS Distributions (void)task_inspect(task, TASK_INSPECT_BASIC_COUNTS,
177*a325d9c4SApple OSS Distributions (task_inspect_info_t)&counts[0], &size);
178*a325d9c4SApple OSS Distributions /*
179*a325d9c4SApple OSS Distributions * Not realistic for a process to see count values with the high bit
180*a325d9c4SApple OSS Distributions * set, but kernel pointers will be that high.
181*a325d9c4SApple OSS Distributions */
182*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_LT(counts[0], 1ULL << 63,
183*a325d9c4SApple OSS Distributions "check for valid count entry 1");
184*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_LT(counts[1], 1ULL << 63,
185*a325d9c4SApple OSS Distributions "check for valid count entry 2");
186*a325d9c4SApple OSS Distributions }
187*a325d9c4SApple OSS Distributions }
188*a325d9c4SApple OSS Distributions
189*a325d9c4SApple OSS Distributions T_DECL(core_fixed_stack_leak_race,
190*a325d9c4SApple OSS Distributions "ensure no stack data is leaked by TASK_INSPECT_BASIC_COUNTS")
191*a325d9c4SApple OSS Distributions {
192*a325d9c4SApple OSS Distributions T_SETUPBEGIN;
193*a325d9c4SApple OSS Distributions
194*a325d9c4SApple OSS Distributions int ncpus = 0;
195*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(sysctlbyname("hw.logicalcpu_max", &ncpus,
196*a325d9c4SApple OSS Distributions &(size_t){ sizeof(ncpus) }, NULL, 0), "get number of CPUs");
197*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_GT(ncpus, 0, "got non-zero number of CPUs");
198*a325d9c4SApple OSS Distributions pthread_t *threads = calloc((unsigned long)ncpus, sizeof(*threads));
199*a325d9c4SApple OSS Distributions
200*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(threads, "allocated space for threads");
201*a325d9c4SApple OSS Distributions
202*a325d9c4SApple OSS Distributions T_LOG("creating %d threads to attempt to race around task counts", ncpus);
203*a325d9c4SApple OSS Distributions /*
204*a325d9c4SApple OSS Distributions * Have half the threads hammering thread_self_counts and the other half
205*a325d9c4SApple OSS Distributions * trying to get an error to occur inside TASK_INSPECT_BASIC_COUNTS and see
206*a325d9c4SApple OSS Distributions * uninitialized kernel memory.
207*a325d9c4SApple OSS Distributions */
208*a325d9c4SApple OSS Distributions for (int i = 0; i < ncpus; i++) {
209*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(pthread_create(&threads[i], NULL,
210*a325d9c4SApple OSS Distributions i & 1 ? spin_task_inspect : spin_thread_self_counts, NULL),
211*a325d9c4SApple OSS Distributions NULL);
212*a325d9c4SApple OSS Distributions }
213*a325d9c4SApple OSS Distributions
214*a325d9c4SApple OSS Distributions T_SETUPEND;
215*a325d9c4SApple OSS Distributions
216*a325d9c4SApple OSS Distributions sleep(10);
217*a325d9c4SApple OSS Distributions T_PASS("ending test after 10 seconds");
218*a325d9c4SApple OSS Distributions }
219*a325d9c4SApple OSS Distributions
220*a325d9c4SApple OSS Distributions static void
perf_sysctl_deltas(const char * sysctl_name,const char * stat_name)221*a325d9c4SApple OSS Distributions perf_sysctl_deltas(const char *sysctl_name, const char *stat_name)
222*a325d9c4SApple OSS Distributions {
223*a325d9c4SApple OSS Distributions uint64_t deltas[2];
224*a325d9c4SApple OSS Distributions size_t deltas_size;
225*a325d9c4SApple OSS Distributions int r;
226*a325d9c4SApple OSS Distributions
227*a325d9c4SApple OSS Distributions T_SETUPBEGIN;
228*a325d9c4SApple OSS Distributions skip_if_unsupported();
229*a325d9c4SApple OSS Distributions
230*a325d9c4SApple OSS Distributions dt_stat_t instrs = dt_stat_create("instructions", "%s_instrs",
231*a325d9c4SApple OSS Distributions stat_name);
232*a325d9c4SApple OSS Distributions dt_stat_t cycles = dt_stat_create("cycles", "%s_cycles", stat_name);
233*a325d9c4SApple OSS Distributions T_SETUPEND;
234*a325d9c4SApple OSS Distributions
235*a325d9c4SApple OSS Distributions while (!dt_stat_stable(instrs) || !dt_stat_stable(cycles)) {
236*a325d9c4SApple OSS Distributions deltas_size = sizeof(deltas);
237*a325d9c4SApple OSS Distributions r = sysctlbyname(sysctl_name, deltas, &deltas_size, NULL, 0);
238*a325d9c4SApple OSS Distributions T_QUIET;
239*a325d9c4SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(r, "sysctlbyname(\"%s\", ...)", sysctl_name);
240*a325d9c4SApple OSS Distributions dt_stat_add(instrs, (double)deltas[0]);
241*a325d9c4SApple OSS Distributions dt_stat_add(cycles, (double)deltas[1]);
242*a325d9c4SApple OSS Distributions }
243*a325d9c4SApple OSS Distributions
244*a325d9c4SApple OSS Distributions dt_stat_finalize(instrs);
245*a325d9c4SApple OSS Distributions dt_stat_finalize(cycles);
246*a325d9c4SApple OSS Distributions }
247*a325d9c4SApple OSS Distributions
248*a325d9c4SApple OSS Distributions T_DECL(perf_core_fixed_cpu, "test the performance of fixed CPU counter access",
249*a325d9c4SApple OSS Distributions T_META_ASROOT(true), T_META_TAG_PERF)
250*a325d9c4SApple OSS Distributions {
251*a325d9c4SApple OSS Distributions perf_sysctl_deltas("kern.monotonic.fixed_cpu_perf", "fixed_cpu_counters");
252*a325d9c4SApple OSS Distributions }
253*a325d9c4SApple OSS Distributions
254*a325d9c4SApple OSS Distributions T_DECL(perf_core_fixed_thread, "test the performance of fixed thread counter access",
255*a325d9c4SApple OSS Distributions T_META_ASROOT(true), T_META_TAG_PERF)
256*a325d9c4SApple OSS Distributions {
257*a325d9c4SApple OSS Distributions perf_sysctl_deltas("kern.monotonic.fixed_thread_perf",
258*a325d9c4SApple OSS Distributions "fixed_thread_counters");
259*a325d9c4SApple OSS Distributions }
260*a325d9c4SApple OSS Distributions
261*a325d9c4SApple OSS Distributions T_DECL(perf_core_fixed_task, "test the performance of fixed task counter access",
262*a325d9c4SApple OSS Distributions T_META_ASROOT(true), T_META_TAG_PERF)
263*a325d9c4SApple OSS Distributions {
264*a325d9c4SApple OSS Distributions perf_sysctl_deltas("kern.monotonic.fixed_task_perf", "fixed_task_counters");
265*a325d9c4SApple OSS Distributions }
266*a325d9c4SApple OSS Distributions
267*a325d9c4SApple OSS Distributions T_DECL(perf_core_fixed_thread_self, "test the performance of thread self counts",
268*a325d9c4SApple OSS Distributions T_META_TAG_PERF)
269*a325d9c4SApple OSS Distributions {
270*a325d9c4SApple OSS Distributions extern int thread_selfcounts(int type, void *buf, size_t nbytes);
271*a325d9c4SApple OSS Distributions uint64_t counts[2][2];
272*a325d9c4SApple OSS Distributions
273*a325d9c4SApple OSS Distributions T_SETUPBEGIN;
274*a325d9c4SApple OSS Distributions dt_stat_t instrs = dt_stat_create("fixed_thread_self_instrs", "instructions");
275*a325d9c4SApple OSS Distributions dt_stat_t cycles = dt_stat_create("fixed_thread_self_cycles", "cycles");
276*a325d9c4SApple OSS Distributions
277*a325d9c4SApple OSS Distributions skip_if_unsupported();
278*a325d9c4SApple OSS Distributions T_SETUPEND;
279*a325d9c4SApple OSS Distributions
280*a325d9c4SApple OSS Distributions while (!dt_stat_stable(instrs) || !dt_stat_stable(cycles)) {
281*a325d9c4SApple OSS Distributions int r1, r2;
282*a325d9c4SApple OSS Distributions
283*a325d9c4SApple OSS Distributions r1 = thread_selfcounts(1, &counts[0], sizeof(counts[0]));
284*a325d9c4SApple OSS Distributions r2 = thread_selfcounts(1, &counts[1], sizeof(counts[1]));
285*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(r1, "__thread_selfcounts");
286*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(r2, "__thread_selfcounts");
287*a325d9c4SApple OSS Distributions
288*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_GT(counts[1][0], counts[0][0],
289*a325d9c4SApple OSS Distributions "instructions increase monotonically");
290*a325d9c4SApple OSS Distributions dt_stat_add(instrs, counts[1][0] - counts[0][0]);
291*a325d9c4SApple OSS Distributions
292*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_GT(counts[1][1], counts[0][1],
293*a325d9c4SApple OSS Distributions "cycles increase monotonically");
294*a325d9c4SApple OSS Distributions dt_stat_add(cycles, counts[1][1] - counts[0][1]);
295*a325d9c4SApple OSS Distributions }
296*a325d9c4SApple OSS Distributions
297*a325d9c4SApple OSS Distributions dt_stat_finalize(instrs);
298*a325d9c4SApple OSS Distributions dt_stat_finalize(cycles);
299*a325d9c4SApple OSS Distributions }
300