xref: /kvm-unit-tests/s390x/exittime.c (revision 5bf99cb38621d44b0a7d2204ecd9326b3209ab73)
1*43e2fbf4SNico Boehr /* SPDX-License-Identifier: GPL-2.0-only */
2*43e2fbf4SNico Boehr /*
3*43e2fbf4SNico Boehr  * Measure run time of various instructions. Can be used to find runtime
4*43e2fbf4SNico Boehr  * regressions of instructions which cause exits.
5*43e2fbf4SNico Boehr  *
6*43e2fbf4SNico Boehr  * Copyright IBM Corp. 2022
7*43e2fbf4SNico Boehr  *
8*43e2fbf4SNico Boehr  * Authors:
9*43e2fbf4SNico Boehr  *  Nico Boehr <nrb@linux.ibm.com>
10*43e2fbf4SNico Boehr  */
11*43e2fbf4SNico Boehr #include <libcflat.h>
12*43e2fbf4SNico Boehr #include <smp.h>
13*43e2fbf4SNico Boehr #include <sclp.h>
14*43e2fbf4SNico Boehr #include <hardware.h>
15*43e2fbf4SNico Boehr #include <asm/time.h>
16*43e2fbf4SNico Boehr #include <asm/sigp.h>
17*43e2fbf4SNico Boehr #include <asm/interrupt.h>
18*43e2fbf4SNico Boehr #include <asm/page.h>
19*43e2fbf4SNico Boehr 
20*43e2fbf4SNico Boehr const uint64_t iters_to_normalize_to = 10000;
21*43e2fbf4SNico Boehr char pagebuf[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
22*43e2fbf4SNico Boehr 
test_sigp_sense_running(long destcpu)23*43e2fbf4SNico Boehr static void test_sigp_sense_running(long destcpu)
24*43e2fbf4SNico Boehr {
25*43e2fbf4SNico Boehr 	smp_sigp(destcpu, SIGP_SENSE_RUNNING, 0, NULL);
26*43e2fbf4SNico Boehr }
27*43e2fbf4SNico Boehr 
test_nop(long ignore)28*43e2fbf4SNico Boehr static void test_nop(long ignore)
29*43e2fbf4SNico Boehr {
30*43e2fbf4SNico Boehr 	/* nops don't trap into the hypervisor, so let's test them for reference */
31*43e2fbf4SNico Boehr 	asm volatile(
32*43e2fbf4SNico Boehr 		"nop"
33*43e2fbf4SNico Boehr 		:
34*43e2fbf4SNico Boehr 		:
35*43e2fbf4SNico Boehr 		: "memory"
36*43e2fbf4SNico Boehr 	);
37*43e2fbf4SNico Boehr }
38*43e2fbf4SNico Boehr 
test_diag9c(long destcpu)39*43e2fbf4SNico Boehr static void test_diag9c(long destcpu)
40*43e2fbf4SNico Boehr {
41*43e2fbf4SNico Boehr 	asm volatile(
42*43e2fbf4SNico Boehr 		"diag %[destcpu],0,0x9c"
43*43e2fbf4SNico Boehr 		:
44*43e2fbf4SNico Boehr 		: [destcpu] "d" (destcpu)
45*43e2fbf4SNico Boehr 	);
46*43e2fbf4SNico Boehr }
47*43e2fbf4SNico Boehr 
setup_get_this_cpuaddr(long ignore)48*43e2fbf4SNico Boehr static long setup_get_this_cpuaddr(long ignore)
49*43e2fbf4SNico Boehr {
50*43e2fbf4SNico Boehr 	return stap();
51*43e2fbf4SNico Boehr }
52*43e2fbf4SNico Boehr 
test_diag44(long ignore)53*43e2fbf4SNico Boehr static void test_diag44(long ignore)
54*43e2fbf4SNico Boehr {
55*43e2fbf4SNico Boehr 	asm volatile(
56*43e2fbf4SNico Boehr 		"diag 0,0,0x44"
57*43e2fbf4SNico Boehr 	);
58*43e2fbf4SNico Boehr }
59*43e2fbf4SNico Boehr 
test_stnsm(long ignore)60*43e2fbf4SNico Boehr static void test_stnsm(long ignore)
61*43e2fbf4SNico Boehr {
62*43e2fbf4SNico Boehr 	int out;
63*43e2fbf4SNico Boehr 
64*43e2fbf4SNico Boehr 	asm volatile(
65*43e2fbf4SNico Boehr 		"stnsm %[out],0xff"
66*43e2fbf4SNico Boehr 		: [out] "=Q" (out)
67*43e2fbf4SNico Boehr 	);
68*43e2fbf4SNico Boehr }
69*43e2fbf4SNico Boehr 
test_stosm(long ignore)70*43e2fbf4SNico Boehr static void test_stosm(long ignore)
71*43e2fbf4SNico Boehr {
72*43e2fbf4SNico Boehr 	int out;
73*43e2fbf4SNico Boehr 
74*43e2fbf4SNico Boehr 	asm volatile(
75*43e2fbf4SNico Boehr 		"stosm %[out],0"
76*43e2fbf4SNico Boehr 		: [out] "=Q" (out)
77*43e2fbf4SNico Boehr 	);
78*43e2fbf4SNico Boehr }
79*43e2fbf4SNico Boehr 
setup_ssm(long ignore)80*43e2fbf4SNico Boehr static long setup_ssm(long ignore)
81*43e2fbf4SNico Boehr {
82*43e2fbf4SNico Boehr 	long system_mask = 0;
83*43e2fbf4SNico Boehr 
84*43e2fbf4SNico Boehr 	asm volatile(
85*43e2fbf4SNico Boehr 		"stosm %[system_mask],0"
86*43e2fbf4SNico Boehr 		: [system_mask] "=Q" (system_mask)
87*43e2fbf4SNico Boehr 	);
88*43e2fbf4SNico Boehr 
89*43e2fbf4SNico Boehr 	return system_mask;
90*43e2fbf4SNico Boehr }
91*43e2fbf4SNico Boehr 
test_ssm(long old_system_mask)92*43e2fbf4SNico Boehr static void test_ssm(long old_system_mask)
93*43e2fbf4SNico Boehr {
94*43e2fbf4SNico Boehr 	asm volatile(
95*43e2fbf4SNico Boehr 		"ssm %[old_system_mask]"
96*43e2fbf4SNico Boehr 		:
97*43e2fbf4SNico Boehr 		: [old_system_mask] "Q" (old_system_mask)
98*43e2fbf4SNico Boehr 	);
99*43e2fbf4SNico Boehr }
100*43e2fbf4SNico Boehr 
setup_lctl4(long ignore)101*43e2fbf4SNico Boehr static long setup_lctl4(long ignore)
102*43e2fbf4SNico Boehr {
103*43e2fbf4SNico Boehr 	long ctl4_orig = 0;
104*43e2fbf4SNico Boehr 
105*43e2fbf4SNico Boehr 	asm volatile(
106*43e2fbf4SNico Boehr 		"stctg 4,4,%[ctl4_orig]"
107*43e2fbf4SNico Boehr 		: [ctl4_orig] "=S" (ctl4_orig)
108*43e2fbf4SNico Boehr 	);
109*43e2fbf4SNico Boehr 
110*43e2fbf4SNico Boehr 	return ctl4_orig;
111*43e2fbf4SNico Boehr }
112*43e2fbf4SNico Boehr 
test_lctl4(long ctl4_orig)113*43e2fbf4SNico Boehr static void test_lctl4(long ctl4_orig)
114*43e2fbf4SNico Boehr {
115*43e2fbf4SNico Boehr 	asm volatile(
116*43e2fbf4SNico Boehr 		"lctlg 4,4,%[ctl4_orig]"
117*43e2fbf4SNico Boehr 		:
118*43e2fbf4SNico Boehr 		: [ctl4_orig] "S" (ctl4_orig)
119*43e2fbf4SNico Boehr 	);
120*43e2fbf4SNico Boehr }
121*43e2fbf4SNico Boehr 
test_stpx(long ignore)122*43e2fbf4SNico Boehr static void test_stpx(long ignore)
123*43e2fbf4SNico Boehr {
124*43e2fbf4SNico Boehr 	unsigned int prefix;
125*43e2fbf4SNico Boehr 
126*43e2fbf4SNico Boehr 	asm volatile(
127*43e2fbf4SNico Boehr 		"stpx %[prefix]"
128*43e2fbf4SNico Boehr 		: [prefix] "=Q" (prefix)
129*43e2fbf4SNico Boehr 	);
130*43e2fbf4SNico Boehr }
131*43e2fbf4SNico Boehr 
test_stfl(long ignore)132*43e2fbf4SNico Boehr static void test_stfl(long ignore)
133*43e2fbf4SNico Boehr {
134*43e2fbf4SNico Boehr 	asm volatile(
135*43e2fbf4SNico Boehr 		"stfl 0"
136*43e2fbf4SNico Boehr 		:
137*43e2fbf4SNico Boehr 		:
138*43e2fbf4SNico Boehr 		: "memory"
139*43e2fbf4SNico Boehr 	);
140*43e2fbf4SNico Boehr }
141*43e2fbf4SNico Boehr 
test_epsw(long ignore)142*43e2fbf4SNico Boehr static void test_epsw(long ignore)
143*43e2fbf4SNico Boehr {
144*43e2fbf4SNico Boehr 	long r1, r2;
145*43e2fbf4SNico Boehr 
146*43e2fbf4SNico Boehr 	asm volatile(
147*43e2fbf4SNico Boehr 		"epsw %[r1], %[r2]"
148*43e2fbf4SNico Boehr 		: [r1] "=d" (r1), [r2] "=d" (r2)
149*43e2fbf4SNico Boehr 	);
150*43e2fbf4SNico Boehr }
151*43e2fbf4SNico Boehr 
test_illegal(long ignore)152*43e2fbf4SNico Boehr static void test_illegal(long ignore)
153*43e2fbf4SNico Boehr {
154*43e2fbf4SNico Boehr 	expect_pgm_int();
155*43e2fbf4SNico Boehr 	asm volatile(
156*43e2fbf4SNico Boehr 		".word 0"
157*43e2fbf4SNico Boehr 	);
158*43e2fbf4SNico Boehr 	clear_pgm_int();
159*43e2fbf4SNico Boehr }
160*43e2fbf4SNico Boehr 
setup_servc(long arg)161*43e2fbf4SNico Boehr static long setup_servc(long arg)
162*43e2fbf4SNico Boehr {
163*43e2fbf4SNico Boehr 	memset(pagebuf, 0, PAGE_SIZE);
164*43e2fbf4SNico Boehr 	return arg;
165*43e2fbf4SNico Boehr }
166*43e2fbf4SNico Boehr 
test_servc(long ignore)167*43e2fbf4SNico Boehr static void test_servc(long ignore)
168*43e2fbf4SNico Boehr {
169*43e2fbf4SNico Boehr 	SCCB *sccb = (SCCB *) pagebuf;
170*43e2fbf4SNico Boehr 
171*43e2fbf4SNico Boehr 	sccb->h.length = 8;
172*43e2fbf4SNico Boehr 	servc(0, (unsigned long) sccb);
173*43e2fbf4SNico Boehr }
174*43e2fbf4SNico Boehr 
test_stsi(long fc)175*43e2fbf4SNico Boehr static void test_stsi(long fc)
176*43e2fbf4SNico Boehr {
177*43e2fbf4SNico Boehr 	stsi(pagebuf, fc, 2, 2);
178*43e2fbf4SNico Boehr }
179*43e2fbf4SNico Boehr 
180*43e2fbf4SNico Boehr struct test {
181*43e2fbf4SNico Boehr 	const char *name;
182*43e2fbf4SNico Boehr 	bool supports_tcg;
183*43e2fbf4SNico Boehr 	/*
184*43e2fbf4SNico Boehr 	 * When non-null, will be called once before running the test loop.
185*43e2fbf4SNico Boehr 	 * Its return value will be given as argument to testfunc.
186*43e2fbf4SNico Boehr 	 */
187*43e2fbf4SNico Boehr 	long (*setupfunc)(long arg);
188*43e2fbf4SNico Boehr 	void (*testfunc)(long arg);
189*43e2fbf4SNico Boehr 	long arg;
190*43e2fbf4SNico Boehr 	long iters;
191*43e2fbf4SNico Boehr } const exittime_tests[] = {
192*43e2fbf4SNico Boehr 	{"nop",                   true,  NULL,                   test_nop,                0, 200000 },
193*43e2fbf4SNico Boehr 	{"sigp sense running(0)", true,  NULL,                   test_sigp_sense_running, 0, 20000 },
194*43e2fbf4SNico Boehr 	{"sigp sense running(1)", true,  NULL,                   test_sigp_sense_running, 1, 20000 },
195*43e2fbf4SNico Boehr 	{"diag9c(self)",          false, setup_get_this_cpuaddr, test_diag9c,             0, 2000 },
196*43e2fbf4SNico Boehr 	{"diag9c(0)",             false, NULL,                   test_diag9c,             0, 2000 },
197*43e2fbf4SNico Boehr 	{"diag9c(1)",             false, NULL,                   test_diag9c,             1, 2000 },
198*43e2fbf4SNico Boehr 	{"diag44",                true,  NULL,                   test_diag44,             0, 2000 },
199*43e2fbf4SNico Boehr 	{"stnsm",                 true,  NULL,                   test_stnsm,              0, 200000 },
200*43e2fbf4SNico Boehr 	{"stosm",                 true,  NULL,                   test_stosm,              0, 200000 },
201*43e2fbf4SNico Boehr 	{"ssm",                   true,  setup_ssm,              test_ssm,                0, 200000 },
202*43e2fbf4SNico Boehr 	{"lctl4",                 true,  setup_lctl4,            test_lctl4,              0, 20000 },
203*43e2fbf4SNico Boehr 	{"stpx",                  true,  NULL,                   test_stpx,               0, 2000 },
204*43e2fbf4SNico Boehr 	{"stfl",                  true,  NULL,                   test_stfl,               0, 2000 },
205*43e2fbf4SNico Boehr 	{"epsw",                  true,  NULL,                   test_epsw,               0, 20000 },
206*43e2fbf4SNico Boehr 	{"illegal",               true,  NULL,                   test_illegal,            0, 2000 },
207*43e2fbf4SNico Boehr 	{"servc",                 true,  setup_servc,            test_servc,              0, 2000 },
208*43e2fbf4SNico Boehr 	{"stsi122",               true,  NULL,                   test_stsi,               1, 200 },
209*43e2fbf4SNico Boehr 	{"stsi222",               true,  NULL,                   test_stsi,               2, 200 },
210*43e2fbf4SNico Boehr 	{"stsi322",               true,  NULL,                   test_stsi,               3, 200 },
211*43e2fbf4SNico Boehr };
212*43e2fbf4SNico Boehr 
213*43e2fbf4SNico Boehr struct test_result {
214*43e2fbf4SNico Boehr 	uint64_t total;
215*43e2fbf4SNico Boehr 	uint64_t best;
216*43e2fbf4SNico Boehr 	uint64_t average;
217*43e2fbf4SNico Boehr 	uint64_t worst;
218*43e2fbf4SNico Boehr };
219*43e2fbf4SNico Boehr 
tod_to_us(uint64_t tod)220*43e2fbf4SNico Boehr static uint64_t tod_to_us(uint64_t tod)
221*43e2fbf4SNico Boehr {
222*43e2fbf4SNico Boehr 	return tod >> STCK_SHIFT_US;
223*43e2fbf4SNico Boehr }
224*43e2fbf4SNico Boehr 
tod_to_ns(uint64_t tod)225*43e2fbf4SNico Boehr static uint64_t tod_to_ns(uint64_t tod)
226*43e2fbf4SNico Boehr {
227*43e2fbf4SNico Boehr 	return tod_to_us(tod * 1000);
228*43e2fbf4SNico Boehr }
229*43e2fbf4SNico Boehr 
normalize_iters(uint64_t value_to_normalize,uint64_t iters)230*43e2fbf4SNico Boehr static uint64_t normalize_iters(uint64_t value_to_normalize, uint64_t iters)
231*43e2fbf4SNico Boehr {
232*43e2fbf4SNico Boehr 	return value_to_normalize * iters_to_normalize_to / iters;
233*43e2fbf4SNico Boehr }
234*43e2fbf4SNico Boehr 
report_iteration_result(struct test const * test,struct test_result const * test_result)235*43e2fbf4SNico Boehr static void report_iteration_result(struct test const* test, struct test_result const* test_result)
236*43e2fbf4SNico Boehr {
237*43e2fbf4SNico Boehr 	uint64_t total = tod_to_ns(normalize_iters(test_result->total, test->iters)),
238*43e2fbf4SNico Boehr 		 best = tod_to_ns(normalize_iters(test_result->best, test->iters)),
239*43e2fbf4SNico Boehr 		 average = tod_to_ns(normalize_iters(test_result->average, test->iters)),
240*43e2fbf4SNico Boehr 		 worst = tod_to_ns(normalize_iters(test_result->worst, test->iters));
241*43e2fbf4SNico Boehr 
242*43e2fbf4SNico Boehr 	report_pass(
243*43e2fbf4SNico Boehr 		"total/best/avg/worst %lu.%03lu/%lu.%03lu/%lu.%03lu/%lu.%03lu us",
244*43e2fbf4SNico Boehr 		total / 1000, total % 1000,
245*43e2fbf4SNico Boehr 		best / 1000, best % 1000,
246*43e2fbf4SNico Boehr 		average / 1000, average % 1000,
247*43e2fbf4SNico Boehr 		worst / 1000, worst % 1000
248*43e2fbf4SNico Boehr 	);
249*43e2fbf4SNico Boehr }
250*43e2fbf4SNico Boehr 
main(void)251*43e2fbf4SNico Boehr int main(void)
252*43e2fbf4SNico Boehr {
253*43e2fbf4SNico Boehr 	int i, j, k, testfunc_arg;
254*43e2fbf4SNico Boehr 	const int outer_iters = 100;
255*43e2fbf4SNico Boehr 	struct test const *current_test;
256*43e2fbf4SNico Boehr 	struct test_result result;
257*43e2fbf4SNico Boehr 	uint64_t start, end, elapsed;
258*43e2fbf4SNico Boehr 
259*43e2fbf4SNico Boehr 	report_prefix_push("exittime");
260*43e2fbf4SNico Boehr 	report_info("reporting total/best/avg/worst normalized to %lu iterations", iters_to_normalize_to);
261*43e2fbf4SNico Boehr 
262*43e2fbf4SNico Boehr 	for (i = 0; i < ARRAY_SIZE(exittime_tests); i++) {
263*43e2fbf4SNico Boehr 		current_test = &exittime_tests[i];
264*43e2fbf4SNico Boehr 		result.total = 0;
265*43e2fbf4SNico Boehr 		result.worst = 0;
266*43e2fbf4SNico Boehr 		result.best = -1;
267*43e2fbf4SNico Boehr 		report_prefix_pushf("%s", current_test->name);
268*43e2fbf4SNico Boehr 
269*43e2fbf4SNico Boehr 		if (host_is_tcg() && !current_test->supports_tcg) {
270*43e2fbf4SNico Boehr 			report_skip("not supported under TCG");
271*43e2fbf4SNico Boehr 			report_prefix_pop();
272*43e2fbf4SNico Boehr 			continue;
273*43e2fbf4SNico Boehr 		}
274*43e2fbf4SNico Boehr 
275*43e2fbf4SNico Boehr 		testfunc_arg = current_test->arg;
276*43e2fbf4SNico Boehr 		if (current_test->setupfunc)
277*43e2fbf4SNico Boehr 			testfunc_arg = current_test->setupfunc(testfunc_arg);
278*43e2fbf4SNico Boehr 
279*43e2fbf4SNico Boehr 		for (j = 0; j < outer_iters; j++) {
280*43e2fbf4SNico Boehr 			stckf(&start);
281*43e2fbf4SNico Boehr 			for (k = 0; k < current_test->iters; k++)
282*43e2fbf4SNico Boehr 				current_test->testfunc(testfunc_arg);
283*43e2fbf4SNico Boehr 			stckf(&end);
284*43e2fbf4SNico Boehr 			elapsed = end - start;
285*43e2fbf4SNico Boehr 			result.best = MIN(result.best, elapsed);
286*43e2fbf4SNico Boehr 			result.worst = MAX(result.worst, elapsed);
287*43e2fbf4SNico Boehr 			result.total += elapsed;
288*43e2fbf4SNico Boehr 		}
289*43e2fbf4SNico Boehr 		result.average = result.total / outer_iters;
290*43e2fbf4SNico Boehr 		report_iteration_result(current_test, &result);
291*43e2fbf4SNico Boehr 		report_prefix_pop();
292*43e2fbf4SNico Boehr 	}
293*43e2fbf4SNico Boehr 
294*43e2fbf4SNico Boehr 	report_prefix_pop();
295*43e2fbf4SNico Boehr 	return report_summary();
296*43e2fbf4SNico Boehr }
297