1 // Copyright 2021 (c) Apple Inc. All rights reserved.
2
3 #include <darwintest.h>
4 #include <inttypes.h>
5 #include <mach/coalition.h>
6 #include <stdint.h>
7 #include <sys/coalition.h>
8 #include <sys/sysctl.h>
9 #include <libproc.h>
10 #include <unistd.h>
11
12 #include "test_utils.h"
13
14 T_GLOBAL_META(
15 T_META_RADAR_COMPONENT_NAME("xnu"),
16 T_META_RADAR_COMPONENT_VERSION("RM"),
17 T_META_OWNER("mwidmann"),
18 T_META_RUN_CONCURRENTLY(true),
19 T_META_ASROOT(true),
20 T_META_CHECK_LEAKS(false));
21
22 static void
skip_if_monotonic_unsupported(void)23 skip_if_monotonic_unsupported(void)
24 {
25 int r;
26 int supported = 0;
27 size_t supported_size = sizeof(supported);
28
29 r = sysctlbyname("kern.monotonic.supported", &supported, &supported_size,
30 NULL, 0);
31 if (r < 0) {
32 T_WITH_ERRNO;
33 T_SKIP("could not find \"kern.monotonic.supported\" sysctl");
34 }
35
36 if (!supported) {
37 T_SKIP("monotonic is not supported on this platform");
38 }
39 }
40
41 // Don't rely on FastSim's CPMU to produce reliable data.
42 // In particular, S3_2_C15_C1_0 (instructions retired) seems to be zero on some devices (rdar://143157256).
43 static void
skip_if_fastsim(void)44 skip_if_fastsim(void)
45 {
46 char buffer[64] = "";
47 size_t buffer_size = sizeof(buffer);
48
49 int r = sysctlbyname("hw.targettype", buffer, &buffer_size, NULL, 0);
50 if (r < 0) {
51 T_WITH_ERRNO;
52 T_SKIP("could not find \"hw.targettype\" sysctl");
53 }
54
55 if (strstr(buffer, "sim") != NULL) {
56 T_SKIP("CPU performance counters are unreliable on FastSim");
57 }
58 }
59
60 T_DECL(coalition_resource_info_counters,
61 "ensure that coalition resource info produces valid counter data", T_META_TAG_VM_NOT_ELIGIBLE)
62 {
63 skip_if_monotonic_unsupported();
64 skip_if_fastsim();
65
66 T_SETUPBEGIN;
67
68 struct proc_pidcoalitioninfo idinfo = {};
69 int ret = proc_pidinfo(getpid(), PROC_PIDCOALITIONINFO, 0,
70 &idinfo, sizeof(idinfo));
71 T_ASSERT_POSIX_SUCCESS(ret, "proc_pidinfo(... PROC_PIDCOALITIONINFO ...)");
72
73 uint64_t resid = idinfo.coalition_id[COALITION_TYPE_RESOURCE];
74
75 struct coalition_resource_usage coalusage[2] = {};
76 ret = coalition_info_resource_usage(resid, &coalusage[0],
77 sizeof(coalusage[0]));
78 T_ASSERT_POSIX_SUCCESS(ret, "coalition_info_resource_usage()");
79
80 T_SETUPEND;
81
82 T_EXPECT_GT(coalusage[0].cpu_instructions, UINT64_C(0),
83 "instruction count is non-zero");
84 T_EXPECT_GT(coalusage[0].cpu_cycles, UINT64_C(0),
85 "cycle count is non-zero");
86
87 sleep(1);
88
89 T_SETUPBEGIN;
90 ret = coalition_info_resource_usage(resid, &coalusage[1],
91 sizeof(coalusage[1]));
92 T_ASSERT_POSIX_SUCCESS(ret, "coalition_info_resource_usage()");
93 T_SETUPEND;
94
95 T_EXPECT_GE(coalusage[1].cpu_instructions, coalusage[0].cpu_instructions,
96 "instruction count is monotonically increasing (+%" PRIu64 ")",
97 coalusage[1].cpu_instructions - coalusage[0].cpu_instructions);
98 T_EXPECT_GE(coalusage[1].cpu_cycles, coalusage[0].cpu_cycles,
99 "cycle count is monotonically increasing (+%" PRIu64 ")",
100 coalusage[1].cpu_cycles - coalusage[0].cpu_cycles);
101 }
102
103 T_DECL(coalition_resource_info_kernel_ptime_sane,
104 "ensure that coalition resource info for the kernel has a sane P-CPU time", T_META_TAG_VM_PREFERRED)
105 {
106 T_SETUPBEGIN;
107 struct proc_pidcoalitioninfo idinfo = {};
108 int ret = proc_pidinfo(0, PROC_PIDCOALITIONINFO, 0, &idinfo,
109 sizeof(idinfo));
110 T_ASSERT_POSIX_SUCCESS(ret, "proc_pidinfo(... PROC_PIDCOALITIONINFO ...)");
111
112 uint64_t resid = idinfo.coalition_id[COALITION_TYPE_RESOURCE];
113
114 struct coalition_resource_usage coalusage = {};
115 ret = coalition_info_resource_usage(resid, &coalusage,
116 sizeof(coalusage));
117 T_ASSERT_POSIX_SUCCESS(ret, "coalition_info_resource_usage()");
118 T_SETUPEND;
119
120 uint64_t non_ptime = coalusage.cpu_time - coalusage.cpu_ptime;
121 T_LOG("CPU time = %llu, P-CPU time = %llu (non-P-CPU time = %llu/%.2g%%)",
122 coalusage.cpu_time, coalusage.cpu_ptime, non_ptime,
123 (double)non_ptime / (double)coalusage.cpu_time * 100.0);
124 T_EXPECT_GT(coalusage.cpu_time, UINT64_C(0), "CPU time is non-zero");
125 T_EXPECT_GT(coalusage.cpu_time, coalusage.cpu_ptime,
126 "P-CPU time is <= CPU time");
127 }
128