]>
Commit | Line | Data |
---|---|---|
0a7de745 A |
1 | #include <darwintest.h> |
2 | #include <inttypes.h> | |
3 | #if __arm64__ | |
4 | #include <mach/arm/processor_info.h> | |
5 | #endif /* __arm64__ */ | |
6 | #include <mach/mach.h> | |
7 | #include <stdlib.h> | |
8 | #include <unistd.h> | |
9 | ||
cb323159 A |
10 | T_GLOBAL_META(T_META_ASROOT(true), |
11 | T_META_RUN_CONCURRENTLY(true)); | |
0a7de745 A |
12 | |
13 | T_DECL(processor_cpu_stat64, | |
14 | "ensure 64-bit processor statistics are reported correctly", | |
15 | T_META_NAMESPACE("xnu.arm")) | |
16 | { | |
17 | #if !__arm64__ | |
18 | T_SKIP("processor statistics only available on ARM"); | |
19 | #else /* !__arm64__ */ | |
20 | host_t host = mach_host_self(); | |
21 | host_t priv_port = MACH_PORT_NULL; | |
22 | ||
23 | kern_return_t kr = host_get_host_priv_port(host, &priv_port); | |
24 | T_QUIET; | |
25 | T_ASSERT_MACH_SUCCESS(kr, "host_get_host_priv_port"); | |
26 | T_QUIET; | |
27 | T_ASSERT_NE(priv_port, MACH_PORT_NULL, "valid host priv port"); | |
28 | ||
29 | processor_port_array_t cpu_ports = NULL; | |
30 | mach_msg_type_number_t cpu_count = 0; | |
31 | kr = host_processors(priv_port, &cpu_ports, &cpu_count); | |
32 | T_QUIET; | |
33 | T_ASSERT_MACH_SUCCESS(kr, "host_processors"); | |
34 | T_QUIET; | |
35 | T_ASSERT_NOTNULL(cpu_ports, "valid processor port array"); | |
36 | T_QUIET; | |
37 | T_ASSERT_GT(cpu_count, (mach_msg_type_number_t)0, | |
38 | "non-zero CPU count"); | |
39 | ||
40 | T_LOG("found %d CPUs", cpu_count); | |
41 | ||
42 | struct processor_cpu_stat64 *prestats = calloc(cpu_count, | |
43 | sizeof(*prestats)); | |
44 | T_WITH_ERRNO; | |
45 | T_QUIET; | |
46 | T_ASSERT_NOTNULL(prestats, "allocate space for stats (pre)"); | |
47 | memset(prestats, 0xff, cpu_count * sizeof(*prestats)); | |
48 | ||
49 | for (int i = 0; i < (int)cpu_count; i++) { | |
0a7de745 A |
50 | mach_msg_type_number_t info_count = PROCESSOR_CPU_STAT64_COUNT; |
51 | kr = processor_info(cpu_ports[i], PROCESSOR_CPU_STAT64, &host, | |
52 | (processor_info_t)&prestats[i], &info_count); | |
53 | T_ASSERT_MACH_SUCCESS(kr, | |
54 | "processor_info(%d, PROCESSOR_CPU_STAT64, ...)", i); | |
55 | ||
56 | T_QUIET; | |
57 | T_ASSERT_EQ(info_count, PROCESSOR_CPU_STAT64_COUNT, | |
58 | "received enough CPU statistics"); | |
59 | } | |
60 | ||
61 | sleep(1); | |
62 | ||
63 | struct processor_cpu_stat64 *poststats = calloc(cpu_count - 1, | |
64 | sizeof(*poststats)); | |
65 | T_WITH_ERRNO; | |
66 | T_QUIET; | |
67 | T_ASSERT_NOTNULL(poststats, "allocate space for stats (post)"); | |
68 | ||
69 | for (int i = 0; i < (int)cpu_count; i++) { | |
70 | mach_msg_type_number_t info_count = PROCESSOR_CPU_STAT64_COUNT; | |
71 | kr = processor_info(cpu_ports[i], PROCESSOR_CPU_STAT64, &host, | |
72 | (processor_info_t)&poststats[i], &info_count); | |
73 | T_ASSERT_MACH_SUCCESS(kr, | |
74 | "processor_info(%d, PROCESSOR_CPU_STAT64, ...)", i); | |
75 | ||
76 | T_QUIET; | |
77 | T_ASSERT_EQ(info_count, PROCESSOR_CPU_STAT64_COUNT, | |
78 | "received enough CPU statistics"); | |
79 | } | |
80 | ||
81 | for (int i = 0; i < (int)cpu_count; i++) { | |
82 | #define CHECK_STAT_FIELD(field) \ | |
83 | T_EXPECT_GE(poststats[i].field, prestats[i].field, \ | |
84 | "CPU %d's " #field " is monotonically increasing (+%" PRIu64 \ | |
85 | ")", i, poststats[i].field - prestats[i].field) | |
86 | ||
87 | CHECK_STAT_FIELD(irq_ex_cnt); | |
88 | CHECK_STAT_FIELD(ipi_cnt); | |
89 | CHECK_STAT_FIELD(timer_cnt); | |
90 | CHECK_STAT_FIELD(undef_ex_cnt); | |
91 | CHECK_STAT_FIELD(unaligned_cnt); | |
92 | CHECK_STAT_FIELD(vfp_cnt); | |
93 | CHECK_STAT_FIELD(vfp_shortv_cnt); | |
94 | CHECK_STAT_FIELD(data_ex_cnt); | |
95 | CHECK_STAT_FIELD(instr_ex_cnt); | |
96 | CHECK_STAT_FIELD(pmi_cnt); | |
97 | ||
98 | #undef CHECK_STAT_FIELD | |
99 | } | |
100 | ||
101 | free(prestats); | |
102 | free(poststats); | |
103 | #endif /* __arm64__ */ | |
104 | } |