1*27b03b36SApple OSS Distributions #include "hvtest_arm64.h"
2*27b03b36SApple OSS Distributions #include "hvtest_guest.h"
3*27b03b36SApple OSS Distributions
4*27b03b36SApple OSS Distributions #include <ptrauth.h>
5*27b03b36SApple OSS Distributions #include <darwintest.h>
6*27b03b36SApple OSS Distributions #include <darwintest_perf.h>
7*27b03b36SApple OSS Distributions #include <mach/mach.h>
8*27b03b36SApple OSS Distributions #include <stdatomic.h>
9*27b03b36SApple OSS Distributions #include <stdlib.h>
10*27b03b36SApple OSS Distributions
11*27b03b36SApple OSS Distributions T_GLOBAL_META(
12*27b03b36SApple OSS Distributions T_META_NAMESPACE("xnu.arm.hv"),
13*27b03b36SApple OSS Distributions T_META_REQUIRES_SYSCTL_EQ("kern.hv_support", 1),
14*27b03b36SApple OSS Distributions // Temporary workaround for not providing an x86_64 slice
15*27b03b36SApple OSS Distributions T_META_REQUIRES_SYSCTL_EQ("hw.optional.arm64", 1),
16*27b03b36SApple OSS Distributions T_META_RADAR_COMPONENT_NAME("xnu"),
17*27b03b36SApple OSS Distributions T_META_RADAR_COMPONENT_VERSION("arm - hypervisor"),
18*27b03b36SApple OSS Distributions T_META_OWNER("p_newman")
19*27b03b36SApple OSS Distributions );
20*27b03b36SApple OSS Distributions
21*27b03b36SApple OSS Distributions #define SET_PC(vcpu, symbol) \
22*27b03b36SApple OSS Distributions { \
23*27b03b36SApple OSS Distributions vcpu_entry_function entry = ptrauth_strip(&symbol, 0); \
24*27b03b36SApple OSS Distributions uint64_t entry_addr = (uintptr_t)entry; \
25*27b03b36SApple OSS Distributions (void)hv_vcpu_set_reg(vcpu, HV_REG_PC, entry_addr); \
26*27b03b36SApple OSS Distributions }
27*27b03b36SApple OSS Distributions
28*27b03b36SApple OSS Distributions // Note that expect_*(), set_reg(), and get_reg() cannot be used in benchmarks,
29*27b03b36SApple OSS Distributions // as the T_ASSERT() checks they perform are severely detrimental to results.
30*27b03b36SApple OSS Distributions //
31*27b03b36SApple OSS Distributions // The helpers below should be used in their place.
32*27b03b36SApple OSS Distributions
33*27b03b36SApple OSS Distributions static void
quick_bump_pc(hv_vcpu_t vcpu,const bool forward)34*27b03b36SApple OSS Distributions quick_bump_pc(hv_vcpu_t vcpu, const bool forward)
35*27b03b36SApple OSS Distributions {
36*27b03b36SApple OSS Distributions uint64_t pc;
37*27b03b36SApple OSS Distributions (void)hv_vcpu_get_reg(vcpu, HV_REG_PC, &pc);
38*27b03b36SApple OSS Distributions pc = forward ? pc + 4 : pc - 4;
39*27b03b36SApple OSS Distributions (void)hv_vcpu_set_reg(vcpu, HV_REG_PC, pc);
40*27b03b36SApple OSS Distributions }
41*27b03b36SApple OSS Distributions
42*27b03b36SApple OSS Distributions static void
vtimer_benchmark(hv_vcpu_t vcpu,hv_vcpu_exit_t * exit)43*27b03b36SApple OSS Distributions vtimer_benchmark(hv_vcpu_t vcpu, hv_vcpu_exit_t *exit)
44*27b03b36SApple OSS Distributions {
45*27b03b36SApple OSS Distributions dt_stat_thread_cycles_t stat = dt_stat_thread_cycles_create(
46*27b03b36SApple OSS Distributions "VTimer interruption");
47*27b03b36SApple OSS Distributions SET_PC(vcpu, spin_vcpu_entry);
48*27b03b36SApple OSS Distributions set_sys_reg(vcpu, HV_SYS_REG_CNTV_CVAL_EL0, 0);
49*27b03b36SApple OSS Distributions set_sys_reg(vcpu, HV_SYS_REG_CNTV_CTL_EL0, 1);
50*27b03b36SApple OSS Distributions // Dry-run twice to ensure that the timer is re-armed.
51*27b03b36SApple OSS Distributions run_to_next_vm_fault(vcpu, exit);
52*27b03b36SApple OSS Distributions T_ASSERT_EQ_UINT(exit->reason, HV_EXIT_REASON_VTIMER_ACTIVATED,
53*27b03b36SApple OSS Distributions "check for timer");
54*27b03b36SApple OSS Distributions hv_vcpu_set_vtimer_mask(vcpu, false);
55*27b03b36SApple OSS Distributions run_to_next_vm_fault(vcpu, exit);
56*27b03b36SApple OSS Distributions T_ASSERT_EQ_UINT(exit->reason, HV_EXIT_REASON_VTIMER_ACTIVATED,
57*27b03b36SApple OSS Distributions "check for timer");
58*27b03b36SApple OSS Distributions hv_vcpu_set_vtimer_mask(vcpu, false);
59*27b03b36SApple OSS Distributions T_STAT_MEASURE_LOOP(stat) {
60*27b03b36SApple OSS Distributions hv_vcpu_run(vcpu);
61*27b03b36SApple OSS Distributions hv_vcpu_set_vtimer_mask(vcpu, false);
62*27b03b36SApple OSS Distributions }
63*27b03b36SApple OSS Distributions dt_stat_finalize(stat);
64*27b03b36SApple OSS Distributions // Disable the timer before running other benchmarks, otherwise they will be
65*27b03b36SApple OSS Distributions // interrupted.
66*27b03b36SApple OSS Distributions set_sys_reg(vcpu, HV_SYS_REG_CNTV_CTL_EL0, 0);
67*27b03b36SApple OSS Distributions }
68*27b03b36SApple OSS Distributions
69*27b03b36SApple OSS Distributions static void
trap_benchmark(dt_stat_thread_cycles_t trap_stat,hv_vcpu_t vcpu,hv_vcpu_exit_t * exit,const uint64_t batch,const bool increment_pc)70*27b03b36SApple OSS Distributions trap_benchmark(dt_stat_thread_cycles_t trap_stat, hv_vcpu_t vcpu,
71*27b03b36SApple OSS Distributions hv_vcpu_exit_t *exit, const uint64_t batch, const bool increment_pc)
72*27b03b36SApple OSS Distributions {
73*27b03b36SApple OSS Distributions while (!dt_stat_stable(trap_stat)) {
74*27b03b36SApple OSS Distributions set_reg(vcpu, HV_REG_X0, batch);
75*27b03b36SApple OSS Distributions dt_stat_token start = dt_stat_thread_cycles_begin(trap_stat);
76*27b03b36SApple OSS Distributions for (uint32_t i = 0; i < batch; i++) {
77*27b03b36SApple OSS Distributions hv_vcpu_run(vcpu);
78*27b03b36SApple OSS Distributions if (increment_pc) {
79*27b03b36SApple OSS Distributions quick_bump_pc(vcpu, true);
80*27b03b36SApple OSS Distributions }
81*27b03b36SApple OSS Distributions }
82*27b03b36SApple OSS Distributions dt_stat_thread_cycles_end_batch(trap_stat, (int)batch, start);
83*27b03b36SApple OSS Distributions expect_hvc(vcpu, exit, 2);
84*27b03b36SApple OSS Distributions }
85*27b03b36SApple OSS Distributions dt_stat_finalize(trap_stat);
86*27b03b36SApple OSS Distributions }
87*27b03b36SApple OSS Distributions
88*27b03b36SApple OSS Distributions static void
mrs_bench_kernel(hv_vcpu_t vcpu,hv_vcpu_exit_t * exit,const char * name)89*27b03b36SApple OSS Distributions mrs_bench_kernel(hv_vcpu_t vcpu, hv_vcpu_exit_t *exit, const char *name)
90*27b03b36SApple OSS Distributions {
91*27b03b36SApple OSS Distributions const uint64_t batch = 1000;
92*27b03b36SApple OSS Distributions SET_PC(vcpu, mrs_actlr_bench_loop);
93*27b03b36SApple OSS Distributions set_control(vcpu, _HV_CONTROL_FIELD_HCR,
94*27b03b36SApple OSS Distributions get_control(vcpu, _HV_CONTROL_FIELD_HCR) & ~HCR_TACR);
95*27b03b36SApple OSS Distributions dt_stat_thread_cycles_t stat = dt_stat_thread_cycles_create(name);
96*27b03b36SApple OSS Distributions while (!dt_stat_stable(stat)) {
97*27b03b36SApple OSS Distributions set_reg(vcpu, HV_REG_X0, batch);
98*27b03b36SApple OSS Distributions dt_stat_token start = dt_stat_thread_cycles_begin(stat);
99*27b03b36SApple OSS Distributions hv_vcpu_run(vcpu);
100*27b03b36SApple OSS Distributions dt_stat_thread_cycles_end_batch(stat, (int)batch, start);
101*27b03b36SApple OSS Distributions T_QUIET; T_ASSERT_EQ_UINT(exit->reason, HV_EXIT_REASON_EXCEPTION,
102*27b03b36SApple OSS Distributions "check for exception");
103*27b03b36SApple OSS Distributions T_QUIET; T_ASSERT_EQ((uint32_t)exit->exception.syndrome >> 26, 0x16,
104*27b03b36SApple OSS Distributions "check for HVC64");
105*27b03b36SApple OSS Distributions }
106*27b03b36SApple OSS Distributions dt_stat_finalize(stat);
107*27b03b36SApple OSS Distributions }
108*27b03b36SApple OSS Distributions
109*27b03b36SApple OSS Distributions static void *
trap_bench_monitor(void * arg __unused,hv_vcpu_t vcpu,hv_vcpu_exit_t * exit)110*27b03b36SApple OSS Distributions trap_bench_monitor(void *arg __unused, hv_vcpu_t vcpu, hv_vcpu_exit_t *exit)
111*27b03b36SApple OSS Distributions {
112*27b03b36SApple OSS Distributions // In all benchmark testcases using quick_run_vcpu(), dry run all guest code
113*27b03b36SApple OSS Distributions // to fault in pages so that run_to_next_vm_fault() isn't needed while
114*27b03b36SApple OSS Distributions // recording measurements.
115*27b03b36SApple OSS Distributions
116*27b03b36SApple OSS Distributions vtimer_benchmark(vcpu, exit);
117*27b03b36SApple OSS Distributions
118*27b03b36SApple OSS Distributions // dry-run hvc_bench_loop
119*27b03b36SApple OSS Distributions SET_PC(vcpu, hvc_bench_loop);
120*27b03b36SApple OSS Distributions set_reg(vcpu, HV_REG_X0, 1);
121*27b03b36SApple OSS Distributions expect_hvc(vcpu, exit, 1);
122*27b03b36SApple OSS Distributions expect_hvc(vcpu, exit, 2);
123*27b03b36SApple OSS Distributions
124*27b03b36SApple OSS Distributions SET_PC(vcpu, hvc_bench_loop);
125*27b03b36SApple OSS Distributions trap_benchmark(dt_stat_thread_cycles_create("HVC handled by VMM"),
126*27b03b36SApple OSS Distributions vcpu, exit, 1000, false);
127*27b03b36SApple OSS Distributions
128*27b03b36SApple OSS Distributions // dry-run data_abort_bench_loop
129*27b03b36SApple OSS Distributions SET_PC(vcpu, data_abort_bench_loop);
130*27b03b36SApple OSS Distributions set_reg(vcpu, HV_REG_X0, 1);
131*27b03b36SApple OSS Distributions expect_trapped_store(vcpu, exit, get_reserved_start());
132*27b03b36SApple OSS Distributions expect_hvc(vcpu, exit, 2);
133*27b03b36SApple OSS Distributions
134*27b03b36SApple OSS Distributions SET_PC(vcpu, data_abort_bench_loop);
135*27b03b36SApple OSS Distributions trap_benchmark(dt_stat_thread_cycles_create("data abort handled by VMM"),
136*27b03b36SApple OSS Distributions vcpu, exit, 1000, true);
137*27b03b36SApple OSS Distributions
138*27b03b36SApple OSS Distributions // dry-run mrs_actlr_bench_loop
139*27b03b36SApple OSS Distributions SET_PC(vcpu, mrs_actlr_bench_loop);
140*27b03b36SApple OSS Distributions set_reg(vcpu, HV_REG_X0, 1);
141*27b03b36SApple OSS Distributions set_control(vcpu, _HV_CONTROL_FIELD_HCR,
142*27b03b36SApple OSS Distributions get_control(vcpu, _HV_CONTROL_FIELD_HCR) & ~HCR_TACR);
143*27b03b36SApple OSS Distributions // Confirm no visible trap from MRS
144*27b03b36SApple OSS Distributions expect_hvc(vcpu, exit, 2);
145*27b03b36SApple OSS Distributions
146*27b03b36SApple OSS Distributions mrs_bench_kernel(vcpu, exit, "MRS trap handled by kernel");
147*27b03b36SApple OSS Distributions
148*27b03b36SApple OSS Distributions SET_PC(vcpu, mrs_actlr_bench_loop);
149*27b03b36SApple OSS Distributions set_reg(vcpu, HV_REG_X0, 1);
150*27b03b36SApple OSS Distributions set_control(vcpu, _HV_CONTROL_FIELD_HCR,
151*27b03b36SApple OSS Distributions get_control(vcpu, _HV_CONTROL_FIELD_HCR) | HCR_TACR);
152*27b03b36SApple OSS Distributions // Confirm MRS trap from test loop
153*27b03b36SApple OSS Distributions expect_exception(vcpu, exit, 0x18);
154*27b03b36SApple OSS Distributions quick_bump_pc(vcpu, true);
155*27b03b36SApple OSS Distributions expect_hvc(vcpu, exit, 2);
156*27b03b36SApple OSS Distributions SET_PC(vcpu, mrs_actlr_bench_loop);
157*27b03b36SApple OSS Distributions trap_benchmark(dt_stat_thread_cycles_create("MRS trap handled by VMM"),
158*27b03b36SApple OSS Distributions vcpu, exit, 1000, true);
159*27b03b36SApple OSS Distributions
160*27b03b36SApple OSS Distributions SET_PC(vcpu, activate_debug);
161*27b03b36SApple OSS Distributions expect_hvc(vcpu, exit, 0);
162*27b03b36SApple OSS Distributions
163*27b03b36SApple OSS Distributions SET_PC(vcpu, hvc_bench_loop);
164*27b03b36SApple OSS Distributions trap_benchmark(dt_stat_thread_cycles_create(
165*27b03b36SApple OSS Distributions "debug-enabled HVC handled by VMM"), vcpu, exit, 1000, false);
166*27b03b36SApple OSS Distributions
167*27b03b36SApple OSS Distributions mrs_bench_kernel(vcpu, exit, "debug-enabled MRS trap handled by kernel");
168*27b03b36SApple OSS Distributions
169*27b03b36SApple OSS Distributions return NULL;
170*27b03b36SApple OSS Distributions }
171*27b03b36SApple OSS Distributions
172*27b03b36SApple OSS Distributions T_DECL(trap_benchmark, "trap-processing benchmark")
173*27b03b36SApple OSS Distributions {
174*27b03b36SApple OSS Distributions vm_setup();
175*27b03b36SApple OSS Distributions pthread_t vcpu_thread = create_vcpu_thread(hvc_bench_loop, 0,
176*27b03b36SApple OSS Distributions trap_bench_monitor, NULL);
177*27b03b36SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(pthread_join(vcpu_thread, NULL), "join vcpu");
178*27b03b36SApple OSS Distributions vm_cleanup();
179*27b03b36SApple OSS Distributions }
180*27b03b36SApple OSS Distributions
181*27b03b36SApple OSS Distributions static semaphore_t sem1;
182*27b03b36SApple OSS Distributions static semaphore_t sem2;
183*27b03b36SApple OSS Distributions static _Atomic uint32_t stage;
184*27b03b36SApple OSS Distributions
185*27b03b36SApple OSS Distributions static void
switch_and_return(bool leader)186*27b03b36SApple OSS Distributions switch_and_return(bool leader)
187*27b03b36SApple OSS Distributions {
188*27b03b36SApple OSS Distributions // wait_semaphore, signal_semaphore
189*27b03b36SApple OSS Distributions (void)semaphore_wait_signal(leader ? sem2 : sem1, leader ? sem1 : sem2);
190*27b03b36SApple OSS Distributions }
191*27b03b36SApple OSS Distributions
192*27b03b36SApple OSS Distributions static void *
vcpu_switch_leader(void * arg __unused,hv_vcpu_t vcpu,hv_vcpu_exit_t * exit)193*27b03b36SApple OSS Distributions vcpu_switch_leader(void *arg __unused, hv_vcpu_t vcpu, hv_vcpu_exit_t *exit)
194*27b03b36SApple OSS Distributions {
195*27b03b36SApple OSS Distributions dt_stat_thread_cycles_t baseline = dt_stat_thread_cycles_create(
196*27b03b36SApple OSS Distributions "baseline VCPU run, no switch");
197*27b03b36SApple OSS Distributions dt_stat_thread_cycles_t thread = dt_stat_thread_cycles_create(
198*27b03b36SApple OSS Distributions "VCPU-thread switch");
199*27b03b36SApple OSS Distributions dt_stat_thread_cycles_t basic = dt_stat_thread_cycles_create(
200*27b03b36SApple OSS Distributions "basic VCPU-VCPU switch");
201*27b03b36SApple OSS Distributions dt_stat_thread_cycles_t baseline_debug = dt_stat_thread_cycles_create(
202*27b03b36SApple OSS Distributions "baseline debug-enabled VCPU run, no switch");
203*27b03b36SApple OSS Distributions dt_stat_thread_cycles_t basic_debug = dt_stat_thread_cycles_create(
204*27b03b36SApple OSS Distributions "basic VCPU <-> debug-enabled VCPU switch");
205*27b03b36SApple OSS Distributions dt_stat_thread_cycles_t debug_debug = dt_stat_thread_cycles_create(
206*27b03b36SApple OSS Distributions "debug-enabled VCPU <-> debug-enabled VCPU switch");
207*27b03b36SApple OSS Distributions
208*27b03b36SApple OSS Distributions bind_to_cpu(0);
209*27b03b36SApple OSS Distributions
210*27b03b36SApple OSS Distributions // Activate minimal VCPU state
211*27b03b36SApple OSS Distributions SET_PC(vcpu, hvc_loop);
212*27b03b36SApple OSS Distributions expect_hvc(vcpu, exit, 0);
213*27b03b36SApple OSS Distributions T_STAT_MEASURE_LOOP(baseline) {
214*27b03b36SApple OSS Distributions hv_vcpu_run(vcpu);
215*27b03b36SApple OSS Distributions }
216*27b03b36SApple OSS Distributions dt_stat_finalize(baseline);
217*27b03b36SApple OSS Distributions
218*27b03b36SApple OSS Distributions T_STAT_MEASURE_LOOP(thread) {
219*27b03b36SApple OSS Distributions hv_vcpu_run(vcpu);
220*27b03b36SApple OSS Distributions switch_and_return(true);
221*27b03b36SApple OSS Distributions }
222*27b03b36SApple OSS Distributions dt_stat_finalize(thread);
223*27b03b36SApple OSS Distributions atomic_store_explicit(&stage, 1, memory_order_relaxed);
224*27b03b36SApple OSS Distributions
225*27b03b36SApple OSS Distributions T_STAT_MEASURE_LOOP(basic) {
226*27b03b36SApple OSS Distributions hv_vcpu_run(vcpu);
227*27b03b36SApple OSS Distributions switch_and_return(true);
228*27b03b36SApple OSS Distributions }
229*27b03b36SApple OSS Distributions dt_stat_finalize(basic);
230*27b03b36SApple OSS Distributions atomic_store_explicit(&stage, 2, memory_order_relaxed);
231*27b03b36SApple OSS Distributions
232*27b03b36SApple OSS Distributions T_STAT_MEASURE_LOOP(basic_debug) {
233*27b03b36SApple OSS Distributions hv_vcpu_run(vcpu);
234*27b03b36SApple OSS Distributions switch_and_return(true);
235*27b03b36SApple OSS Distributions }
236*27b03b36SApple OSS Distributions dt_stat_finalize(basic_debug);
237*27b03b36SApple OSS Distributions atomic_store_explicit(&stage, 3, memory_order_relaxed);
238*27b03b36SApple OSS Distributions
239*27b03b36SApple OSS Distributions SET_PC(vcpu, activate_debug);
240*27b03b36SApple OSS Distributions expect_hvc(vcpu, exit, 0);
241*27b03b36SApple OSS Distributions SET_PC(vcpu, hvc_loop);
242*27b03b36SApple OSS Distributions T_STAT_MEASURE_LOOP(baseline_debug) {
243*27b03b36SApple OSS Distributions hv_vcpu_run(vcpu);
244*27b03b36SApple OSS Distributions }
245*27b03b36SApple OSS Distributions dt_stat_finalize(baseline_debug);
246*27b03b36SApple OSS Distributions
247*27b03b36SApple OSS Distributions T_STAT_MEASURE_LOOP(debug_debug) {
248*27b03b36SApple OSS Distributions hv_vcpu_run(vcpu);
249*27b03b36SApple OSS Distributions switch_and_return(true);
250*27b03b36SApple OSS Distributions }
251*27b03b36SApple OSS Distributions dt_stat_finalize(debug_debug);
252*27b03b36SApple OSS Distributions atomic_store_explicit(&stage, 4, memory_order_relaxed);
253*27b03b36SApple OSS Distributions
254*27b03b36SApple OSS Distributions T_ASSERT_MACH_SUCCESS(semaphore_signal(sem1), "final signal to follower");
255*27b03b36SApple OSS Distributions
256*27b03b36SApple OSS Distributions return NULL;
257*27b03b36SApple OSS Distributions }
258*27b03b36SApple OSS Distributions
259*27b03b36SApple OSS Distributions static void *
vcpu_switch_follower(void * arg __unused,hv_vcpu_t vcpu,hv_vcpu_exit_t * exit)260*27b03b36SApple OSS Distributions vcpu_switch_follower(void *arg __unused, hv_vcpu_t vcpu, hv_vcpu_exit_t *exit)
261*27b03b36SApple OSS Distributions {
262*27b03b36SApple OSS Distributions bind_to_cpu(0);
263*27b03b36SApple OSS Distributions
264*27b03b36SApple OSS Distributions // Don't signal until we've been signaled once.
265*27b03b36SApple OSS Distributions T_ASSERT_MACH_SUCCESS(semaphore_wait(sem1),
266*27b03b36SApple OSS Distributions "wait for first signal from leader");
267*27b03b36SApple OSS Distributions
268*27b03b36SApple OSS Distributions // For a baseline, don't enter the VCPU at all. This should result in a
269*27b03b36SApple OSS Distributions // negligible VCPU switch cost.
270*27b03b36SApple OSS Distributions while (atomic_load_explicit(&stage, memory_order_relaxed) == 0) {
271*27b03b36SApple OSS Distributions switch_and_return(false);
272*27b03b36SApple OSS Distributions }
273*27b03b36SApple OSS Distributions
274*27b03b36SApple OSS Distributions // Enter the VCPU once to activate a minimal amount of state.
275*27b03b36SApple OSS Distributions SET_PC(vcpu, hvc_loop);
276*27b03b36SApple OSS Distributions expect_hvc(vcpu, exit, 0);
277*27b03b36SApple OSS Distributions
278*27b03b36SApple OSS Distributions while (atomic_load_explicit(&stage, memory_order_relaxed) == 1) {
279*27b03b36SApple OSS Distributions hv_vcpu_run(vcpu);
280*27b03b36SApple OSS Distributions switch_and_return(false);
281*27b03b36SApple OSS Distributions }
282*27b03b36SApple OSS Distributions
283*27b03b36SApple OSS Distributions // Use debug state
284*27b03b36SApple OSS Distributions SET_PC(vcpu, activate_debug);
285*27b03b36SApple OSS Distributions expect_hvc(vcpu, exit, 0);
286*27b03b36SApple OSS Distributions SET_PC(vcpu, hvc_loop);
287*27b03b36SApple OSS Distributions
288*27b03b36SApple OSS Distributions while (atomic_load_explicit(&stage, memory_order_relaxed) == 2) {
289*27b03b36SApple OSS Distributions hv_vcpu_run(vcpu);
290*27b03b36SApple OSS Distributions switch_and_return(false);
291*27b03b36SApple OSS Distributions }
292*27b03b36SApple OSS Distributions
293*27b03b36SApple OSS Distributions while (atomic_load_explicit(&stage, memory_order_relaxed) == 3) {
294*27b03b36SApple OSS Distributions hv_vcpu_run(vcpu);
295*27b03b36SApple OSS Distributions switch_and_return(false);
296*27b03b36SApple OSS Distributions }
297*27b03b36SApple OSS Distributions
298*27b03b36SApple OSS Distributions return NULL;
299*27b03b36SApple OSS Distributions }
300*27b03b36SApple OSS Distributions
301*27b03b36SApple OSS Distributions T_DECL(vcpu_switch_benchmark, "vcpu state-switching benchmarks",
302*27b03b36SApple OSS Distributions T_META_BOOTARGS_SET("enable_skstb=1"))
303*27b03b36SApple OSS Distributions {
304*27b03b36SApple OSS Distributions bind_to_cpu(0);
305*27b03b36SApple OSS Distributions
306*27b03b36SApple OSS Distributions T_ASSERT_MACH_SUCCESS(semaphore_create(mach_task_self(), &sem1,
307*27b03b36SApple OSS Distributions SYNC_POLICY_FIFO, 0), "semaphore_create 1");
308*27b03b36SApple OSS Distributions T_ASSERT_MACH_SUCCESS(semaphore_create(mach_task_self(), &sem2,
309*27b03b36SApple OSS Distributions SYNC_POLICY_FIFO, 0), "semaphore_create 2");
310*27b03b36SApple OSS Distributions
311*27b03b36SApple OSS Distributions vm_setup();
312*27b03b36SApple OSS Distributions pthread_t vcpu1_thread = create_vcpu_thread(hvc_loop, 0,
313*27b03b36SApple OSS Distributions vcpu_switch_leader, NULL);
314*27b03b36SApple OSS Distributions pthread_t vcpu2_thread = create_vcpu_thread(hvc_loop, 0,
315*27b03b36SApple OSS Distributions vcpu_switch_follower, NULL);
316*27b03b36SApple OSS Distributions
317*27b03b36SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(pthread_join(vcpu1_thread, NULL), "join vcpu1");
318*27b03b36SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(pthread_join(vcpu2_thread, NULL), "join vcpu2");
319*27b03b36SApple OSS Distributions
320*27b03b36SApple OSS Distributions vm_cleanup();
321*27b03b36SApple OSS Distributions }
322*27b03b36SApple OSS Distributions
323*27b03b36SApple OSS Distributions static void
kernel_trap_loop(const char * desc)324*27b03b36SApple OSS Distributions kernel_trap_loop(const char *desc)
325*27b03b36SApple OSS Distributions {
326*27b03b36SApple OSS Distributions const int batch = 10000;
327*27b03b36SApple OSS Distributions dt_stat_time_t s = dt_stat_time_create(desc);
328*27b03b36SApple OSS Distributions while (!dt_stat_stable(s)) {
329*27b03b36SApple OSS Distributions dt_stat_token start = dt_stat_time_begin(s);
330*27b03b36SApple OSS Distributions for (int i = 0; i < batch; i++) {
331*27b03b36SApple OSS Distributions // We don't care what this does, just that it enters and leaves the
332*27b03b36SApple OSS Distributions // kernel and doesn't interfere with the test.
333*27b03b36SApple OSS Distributions (void)hv_test_trap(TRAP_HV_VCPU_SYSREGS_SYNC, 0);
334*27b03b36SApple OSS Distributions }
335*27b03b36SApple OSS Distributions dt_stat_time_end_batch(s, batch, start);
336*27b03b36SApple OSS Distributions }
337*27b03b36SApple OSS Distributions dt_stat_finalize(s);
338*27b03b36SApple OSS Distributions }
339*27b03b36SApple OSS Distributions
340*27b03b36SApple OSS Distributions static void *
invalidate_monitor(void * arg __unused,hv_vcpu_t vcpu,hv_vcpu_exit_t * exit)341*27b03b36SApple OSS Distributions invalidate_monitor(void *arg __unused, hv_vcpu_t vcpu, hv_vcpu_exit_t *exit)
342*27b03b36SApple OSS Distributions {
343*27b03b36SApple OSS Distributions run_to_next_vm_fault(vcpu, exit);
344*27b03b36SApple OSS Distributions T_ASSERT_EQ_UINT(exit->reason, HV_EXIT_REASON_CANCELED, "vcpu interrupted");
345*27b03b36SApple OSS Distributions return NULL;
346*27b03b36SApple OSS Distributions }
347*27b03b36SApple OSS Distributions
348*27b03b36SApple OSS Distributions T_DECL(icache_inval_bench, "measure perf impact of IC IALLU flood",
349*27b03b36SApple OSS Distributions // Don't run this on hardware without the filters, as the impact could
350*27b03b36SApple OSS Distributions // cause timeouts in the host OS.
351*27b03b36SApple OSS Distributions T_META_REQUIRES_SYSCTL_EQ("hw.optional.ic_inval_filters", 1))
352*27b03b36SApple OSS Distributions {
353*27b03b36SApple OSS Distributions vm_setup();
354*27b03b36SApple OSS Distributions
355*27b03b36SApple OSS Distributions #define inval_vcpus 4
356*27b03b36SApple OSS Distributions pthread_t inval_threads[inval_vcpus];
357*27b03b36SApple OSS Distributions for (uint32_t i = 0; i < inval_vcpus; i++) {
358*27b03b36SApple OSS Distributions inval_threads[i] = create_vcpu_thread(ic_iallu_vcpu_entry, 0,
359*27b03b36SApple OSS Distributions invalidate_monitor, NULL);
360*27b03b36SApple OSS Distributions }
361*27b03b36SApple OSS Distributions
362*27b03b36SApple OSS Distributions kernel_trap_loop("kernel trap while VCPUs executing IC IALLU");
363*27b03b36SApple OSS Distributions
364*27b03b36SApple OSS Distributions hv_vcpu_t inval_vcpu_array[inval_vcpus];
365*27b03b36SApple OSS Distributions for (uint32_t i = 0; i < inval_vcpus; i++) {
366*27b03b36SApple OSS Distributions inval_vcpu_array[i] = i;
367*27b03b36SApple OSS Distributions }
368*27b03b36SApple OSS Distributions T_ASSERT_EQ(hv_vcpus_exit(inval_vcpu_array, inval_vcpus), HV_SUCCESS,
369*27b03b36SApple OSS Distributions "cancel inval vcpus");
370*27b03b36SApple OSS Distributions for (uint32_t i = 0; i < inval_vcpus; i++) {
371*27b03b36SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(pthread_join(inval_threads[i], NULL),
372*27b03b36SApple OSS Distributions "join inval_threads[%u]", i);
373*27b03b36SApple OSS Distributions }
374*27b03b36SApple OSS Distributions
375*27b03b36SApple OSS Distributions // Repeat the test case with the same number of VCPUs, but only spinning to
376*27b03b36SApple OSS Distributions // provide a baseline measurement.
377*27b03b36SApple OSS Distributions for (uint32_t i = 0; i < inval_vcpus; i++) {
378*27b03b36SApple OSS Distributions inval_threads[i] = create_vcpu_thread(spin_vcpu_entry, 0,
379*27b03b36SApple OSS Distributions invalidate_monitor, NULL);
380*27b03b36SApple OSS Distributions }
381*27b03b36SApple OSS Distributions
382*27b03b36SApple OSS Distributions kernel_trap_loop("kernel trap while VCPUs spinning");
383*27b03b36SApple OSS Distributions
384*27b03b36SApple OSS Distributions for (uint32_t i = 0; i < inval_vcpus; i++) {
385*27b03b36SApple OSS Distributions inval_vcpu_array[i] = i;
386*27b03b36SApple OSS Distributions }
387*27b03b36SApple OSS Distributions T_ASSERT_EQ(hv_vcpus_exit(inval_vcpu_array, inval_vcpus), HV_SUCCESS,
388*27b03b36SApple OSS Distributions "cancel inval vcpus");
389*27b03b36SApple OSS Distributions for (uint32_t i = 0; i < inval_vcpus; i++) {
390*27b03b36SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(pthread_join(inval_threads[i], NULL),
391*27b03b36SApple OSS Distributions "join inval_threads[%u]", i);
392*27b03b36SApple OSS Distributions }
393*27b03b36SApple OSS Distributions vm_cleanup();
394*27b03b36SApple OSS Distributions }
395*27b03b36SApple OSS Distributions
396*27b03b36SApple OSS Distributions struct thread_params {
397*27b03b36SApple OSS Distributions uint32_t id;
398*27b03b36SApple OSS Distributions uint32_t iter;
399*27b03b36SApple OSS Distributions pthread_t thread;
400*27b03b36SApple OSS Distributions };
401*27b03b36SApple OSS Distributions
402*27b03b36SApple OSS Distributions static void *
run_cancel_monitor(void * arg,hv_vcpu_t vcpu,hv_vcpu_exit_t * exit __unused)403*27b03b36SApple OSS Distributions run_cancel_monitor(void *arg, hv_vcpu_t vcpu, hv_vcpu_exit_t *exit __unused)
404*27b03b36SApple OSS Distributions {
405*27b03b36SApple OSS Distributions struct thread_params *param = (struct thread_params *)arg;
406*27b03b36SApple OSS Distributions dt_stat_time_t s = dt_stat_time_create("hv_vcpus_exit time vcpu%u",
407*27b03b36SApple OSS Distributions param->id);
408*27b03b36SApple OSS Distributions while (!dt_stat_stable(s)) {
409*27b03b36SApple OSS Distributions dt_stat_token start = dt_stat_time_begin(s);
410*27b03b36SApple OSS Distributions for (uint32_t i = 0; i < param->iter; i++) {
411*27b03b36SApple OSS Distributions hv_vcpus_exit(&vcpu, 1);
412*27b03b36SApple OSS Distributions }
413*27b03b36SApple OSS Distributions dt_stat_time_end_batch(s, (int)param->iter, start);
414*27b03b36SApple OSS Distributions }
415*27b03b36SApple OSS Distributions dt_stat_finalize(s);
416*27b03b36SApple OSS Distributions return NULL;
417*27b03b36SApple OSS Distributions }
418*27b03b36SApple OSS Distributions
419*27b03b36SApple OSS Distributions static void
run_cancel_call(uint32_t vcpu_count,uint32_t iter)420*27b03b36SApple OSS Distributions run_cancel_call(uint32_t vcpu_count, uint32_t iter)
421*27b03b36SApple OSS Distributions {
422*27b03b36SApple OSS Distributions struct thread_params *threads = calloc(vcpu_count, sizeof(*threads));
423*27b03b36SApple OSS Distributions vm_setup();
424*27b03b36SApple OSS Distributions for (uint32_t i = 0; i < vcpu_count; i++) {
425*27b03b36SApple OSS Distributions threads[i].id = i;
426*27b03b36SApple OSS Distributions threads[i].iter = iter;
427*27b03b36SApple OSS Distributions threads[i].thread = create_vcpu_thread(hvc_loop, 0, run_cancel_monitor,
428*27b03b36SApple OSS Distributions &threads[i]);
429*27b03b36SApple OSS Distributions }
430*27b03b36SApple OSS Distributions for (uint32_t i = 0; i < vcpu_count; i++) {
431*27b03b36SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(pthread_join(threads[i].thread, NULL),
432*27b03b36SApple OSS Distributions "join vcpu%u", i);
433*27b03b36SApple OSS Distributions }
434*27b03b36SApple OSS Distributions free(threads);
435*27b03b36SApple OSS Distributions vm_cleanup();
436*27b03b36SApple OSS Distributions }
437*27b03b36SApple OSS Distributions
438*27b03b36SApple OSS Distributions T_DECL(api_benchmarks, "API call parallel performance")
439*27b03b36SApple OSS Distributions {
440*27b03b36SApple OSS Distributions run_cancel_call(1, 1000);
441*27b03b36SApple OSS Distributions run_cancel_call(4, 1000);
442*27b03b36SApple OSS Distributions }
443