xref: /kvm-unit-tests/arm/micro-bench.c (revision d0891021d5ad244c99290b4515152a1f997a9404)
1090e1532SShih-Wei Li /*
2090e1532SShih-Wei Li  * Measure the cost of micro level operations.
3090e1532SShih-Wei Li  *
4090e1532SShih-Wei Li  * This test provides support for quantifying the cost of micro level
5090e1532SShih-Wei Li  * operations. To improve precision in the measurements, one should
6090e1532SShih-Wei Li  * consider pinning each VCPU to a specific physical CPU (PCPU) and to
7090e1532SShih-Wei Li  * ensure no other task could run on that PCPU to skew the results.
8090e1532SShih-Wei Li  * This can be achieved by enabling QMP server in the QEMU command in
9090e1532SShih-Wei Li  * unittest.cfg for micro-bench, allowing a client program to get the
10090e1532SShih-Wei Li  * thread_id for each VCPU thread from the QMP server. Based on that
11090e1532SShih-Wei Li  * information, the client program can then pin the corresponding VCPUs to
12090e1532SShih-Wei Li  * dedicated PCPUs and isolate interrupts and tasks from those PCPUs.
13090e1532SShih-Wei Li  *
14090e1532SShih-Wei Li  * Copyright Columbia University
15090e1532SShih-Wei Li  * Author: Shih-Wei Li <shihwei@cs.columbia.edu>
16090e1532SShih-Wei Li  * Author: Christoffer Dall <cdall@cs.columbia.edu>
17090e1532SShih-Wei Li  * Author: Andrew Jones <drjones@redhat.com>
18090e1532SShih-Wei Li  *
19090e1532SShih-Wei Li  * This work is licensed under the terms of the GNU LGPL, version 2.
20090e1532SShih-Wei Li  */
21090e1532SShih-Wei Li #include <libcflat.h>
2230595179SRicardo Koller #include <util.h>
23090e1532SShih-Wei Li #include <asm/gic.h>
240c9afed1SJingyi Wang #include <asm/gic-v3-its.h>
254c77d77bSJingyi Wang #include <asm/timer.h>
26090e1532SShih-Wei Li 
2730595179SRicardo Koller #define QEMU_MMIO_ADDR		0x0a000008
284c77d77bSJingyi Wang 
29090e1532SShih-Wei Li static u32 cntfrq;
30090e1532SShih-Wei Li 
317fc8ebfbSJingyi Wang static volatile bool irq_ready, irq_received;
329c537510SJingyi Wang static int nr_ipi_received;
3330595179SRicardo Koller static unsigned long mmio_addr = QEMU_MMIO_ADDR;
349c537510SJingyi Wang 
35090e1532SShih-Wei Li static void *vgic_dist_base;
36090e1532SShih-Wei Li static void (*write_eoir)(u32 irqstat);
37090e1532SShih-Wei Li 
gic_irq_handler(struct pt_regs * regs)387fc8ebfbSJingyi Wang static void gic_irq_handler(struct pt_regs *regs)
39090e1532SShih-Wei Li {
404c77d77bSJingyi Wang 	u32 irqstat = gic_read_iar();
417fc8ebfbSJingyi Wang 	irq_ready = false;
427fc8ebfbSJingyi Wang 	irq_received = true;
434c77d77bSJingyi Wang 	gic_write_eoir(irqstat);
444c77d77bSJingyi Wang 
45bb4c17e3SNikos Nikoleris 	if (irqstat == TIMER_VTIMER_IRQ) {
464c77d77bSJingyi Wang 		write_sysreg((ARCH_TIMER_CTL_IMASK | ARCH_TIMER_CTL_ENABLE),
474c77d77bSJingyi Wang 			     cntv_ctl_el0);
484c77d77bSJingyi Wang 		isb();
494c77d77bSJingyi Wang 	}
507fc8ebfbSJingyi Wang 	irq_ready = true;
51090e1532SShih-Wei Li }
52090e1532SShih-Wei Li 
gic_secondary_entry(void * data)537fc8ebfbSJingyi Wang static void gic_secondary_entry(void *data)
54090e1532SShih-Wei Li {
557fc8ebfbSJingyi Wang 	install_irq_handler(EL1H_IRQ, gic_irq_handler);
56090e1532SShih-Wei Li 	gic_enable_defaults();
57090e1532SShih-Wei Li 	local_irq_enable();
587fc8ebfbSJingyi Wang 	irq_ready = true;
59090e1532SShih-Wei Li 	while (true)
60090e1532SShih-Wei Li 		cpu_relax();
61090e1532SShih-Wei Li }
62090e1532SShih-Wei Li 
test_init(void)63090e1532SShih-Wei Li static bool test_init(void)
64090e1532SShih-Wei Li {
65090e1532SShih-Wei Li 	int v = gic_init();
66090e1532SShih-Wei Li 
67090e1532SShih-Wei Li 	if (!v) {
68090e1532SShih-Wei Li 		printf("No supported gic present, skipping tests...\n");
69090e1532SShih-Wei Li 		return false;
70090e1532SShih-Wei Li 	}
71090e1532SShih-Wei Li 
72090e1532SShih-Wei Li 	if (nr_cpus < 2) {
73090e1532SShih-Wei Li 		printf("At least two cpus required, skipping tests...\n");
74090e1532SShih-Wei Li 		return false;
75090e1532SShih-Wei Li 	}
76090e1532SShih-Wei Li 
77090e1532SShih-Wei Li 	switch (v) {
78090e1532SShih-Wei Li 	case 2:
79090e1532SShih-Wei Li 		vgic_dist_base = gicv2_dist_base();
80090e1532SShih-Wei Li 		write_eoir = gicv2_write_eoir;
81090e1532SShih-Wei Li 		break;
82090e1532SShih-Wei Li 	case 3:
83090e1532SShih-Wei Li 		vgic_dist_base = gicv3_dist_base();
84090e1532SShih-Wei Li 		write_eoir = gicv3_write_eoir;
85090e1532SShih-Wei Li 		break;
86090e1532SShih-Wei Li 	}
87090e1532SShih-Wei Li 
887fc8ebfbSJingyi Wang 	irq_ready = false;
89090e1532SShih-Wei Li 	gic_enable_defaults();
907fc8ebfbSJingyi Wang 	on_cpu_async(1, gic_secondary_entry, NULL);
91090e1532SShih-Wei Li 
92090e1532SShih-Wei Li 	cntfrq = get_cntfrq();
93090e1532SShih-Wei Li 	printf("Timer Frequency %d Hz (Output in microseconds)\n", cntfrq);
94090e1532SShih-Wei Li 
95090e1532SShih-Wei Li 	return true;
96090e1532SShih-Wei Li }
97090e1532SShih-Wei Li 
gic_prep_common(void)987fc8ebfbSJingyi Wang static void gic_prep_common(void)
99090e1532SShih-Wei Li {
100090e1532SShih-Wei Li 	unsigned tries = 1 << 28;
101090e1532SShih-Wei Li 
1027fc8ebfbSJingyi Wang 	while (!irq_ready && tries--)
103090e1532SShih-Wei Li 		cpu_relax();
1047fc8ebfbSJingyi Wang 	assert(irq_ready);
1057fc8ebfbSJingyi Wang }
1067fc8ebfbSJingyi Wang 
ipi_prep(void)1079c537510SJingyi Wang static bool ipi_prep(void)
1087fc8ebfbSJingyi Wang {
1099c537510SJingyi Wang 	u32 val;
1109c537510SJingyi Wang 
1119c537510SJingyi Wang 	val = readl(vgic_dist_base + GICD_CTLR);
1129c537510SJingyi Wang 	if (readl(vgic_dist_base + GICD_TYPER2) & GICD_TYPER2_nASSGIcap) {
1139c537510SJingyi Wang 		/* nASSGIreq can be changed only when GICD is disabled */
1149c537510SJingyi Wang 		val &= ~GICD_CTLR_ENABLE_G1A;
1159c537510SJingyi Wang 		val &= ~GICD_CTLR_nASSGIreq;
1169c537510SJingyi Wang 		writel(val, vgic_dist_base + GICD_CTLR);
1179c537510SJingyi Wang 		gicv3_dist_wait_for_rwp();
1189c537510SJingyi Wang 
1199c537510SJingyi Wang 		val |= GICD_CTLR_ENABLE_G1A;
1209c537510SJingyi Wang 		writel(val, vgic_dist_base + GICD_CTLR);
1219c537510SJingyi Wang 		gicv3_dist_wait_for_rwp();
1229c537510SJingyi Wang 	}
1239c537510SJingyi Wang 
1249c537510SJingyi Wang 	nr_ipi_received = 0;
1257fc8ebfbSJingyi Wang 	gic_prep_common();
1269c537510SJingyi Wang 	return true;
1279c537510SJingyi Wang }
1289c537510SJingyi Wang 
ipi_hw_prep(void)1299c537510SJingyi Wang static bool ipi_hw_prep(void)
1309c537510SJingyi Wang {
1319c537510SJingyi Wang 	u32 val;
1329c537510SJingyi Wang 
1339c537510SJingyi Wang 	val = readl(vgic_dist_base + GICD_CTLR);
1349c537510SJingyi Wang 	if (readl(vgic_dist_base + GICD_TYPER2) & GICD_TYPER2_nASSGIcap) {
1359c537510SJingyi Wang 		/* nASSGIreq can be changed only when GICD is disabled */
1369c537510SJingyi Wang 		val &= ~GICD_CTLR_ENABLE_G1A;
1379c537510SJingyi Wang 		val |= GICD_CTLR_nASSGIreq;
1389c537510SJingyi Wang 		writel(val, vgic_dist_base + GICD_CTLR);
1399c537510SJingyi Wang 		gicv3_dist_wait_for_rwp();
1409c537510SJingyi Wang 
1419c537510SJingyi Wang 		val |= GICD_CTLR_ENABLE_G1A;
1429c537510SJingyi Wang 		writel(val, vgic_dist_base + GICD_CTLR);
1439c537510SJingyi Wang 		gicv3_dist_wait_for_rwp();
1449c537510SJingyi Wang 	} else {
1459c537510SJingyi Wang 		return false;
1469c537510SJingyi Wang 	}
1479c537510SJingyi Wang 
1489c537510SJingyi Wang 	nr_ipi_received = 0;
1499c537510SJingyi Wang 	gic_prep_common();
1509c537510SJingyi Wang 	return true;
151090e1532SShih-Wei Li }
152090e1532SShih-Wei Li 
ipi_exec(void)153090e1532SShih-Wei Li static void ipi_exec(void)
154090e1532SShih-Wei Li {
155090e1532SShih-Wei Li 	unsigned tries = 1 << 28;
156090e1532SShih-Wei Li 
1577fc8ebfbSJingyi Wang 	irq_received = false;
158090e1532SShih-Wei Li 
159090e1532SShih-Wei Li 	gic_ipi_send_single(1, 1);
160090e1532SShih-Wei Li 
1617fc8ebfbSJingyi Wang 	while (!irq_received && tries--)
162090e1532SShih-Wei Li 		cpu_relax();
163090e1532SShih-Wei Li 
1647fc8ebfbSJingyi Wang 	if (irq_received)
1659c537510SJingyi Wang 		++nr_ipi_received;
1662ca3364bSJingyi Wang 
1679c537510SJingyi Wang 	assert_msg(irq_received, "failed to receive IPI in time, but received %d successfully\n", nr_ipi_received);
168090e1532SShih-Wei Li }
169090e1532SShih-Wei Li 
lpi_prep(void)1700c9afed1SJingyi Wang static bool lpi_prep(void)
1710c9afed1SJingyi Wang {
1720c9afed1SJingyi Wang 	struct its_collection *col1;
1730c9afed1SJingyi Wang 	struct its_device *dev2;
1740c9afed1SJingyi Wang 
1750c9afed1SJingyi Wang 	if (!gicv3_its_base())
1760c9afed1SJingyi Wang 		return false;
1770c9afed1SJingyi Wang 
1780c9afed1SJingyi Wang 	its_enable_defaults();
1790c9afed1SJingyi Wang 	dev2 = its_create_device(2 /* dev id */, 8 /* nb_ites */);
1800c9afed1SJingyi Wang 	col1 = its_create_collection(1 /* col id */, 1 /* target PE */);
1810c9afed1SJingyi Wang 	gicv3_lpi_set_config(8199, LPI_PROP_DEFAULT);
1820c9afed1SJingyi Wang 
1830c9afed1SJingyi Wang 	its_send_mapd_nv(dev2, true);
1840c9afed1SJingyi Wang 	its_send_mapc_nv(col1, true);
1850c9afed1SJingyi Wang 	its_send_invall_nv(col1);
1860c9afed1SJingyi Wang 	its_send_mapti_nv(dev2, 8199 /* lpi id */, 20 /* event id */, col1);
1870c9afed1SJingyi Wang 
1880c9afed1SJingyi Wang 	gic_prep_common();
1890c9afed1SJingyi Wang 	return true;
1900c9afed1SJingyi Wang }
1910c9afed1SJingyi Wang 
lpi_exec(void)1920c9afed1SJingyi Wang static void lpi_exec(void)
1930c9afed1SJingyi Wang {
1940c9afed1SJingyi Wang 	struct its_device *dev2;
1950c9afed1SJingyi Wang 	unsigned tries = 1 << 28;
1960c9afed1SJingyi Wang 	static int received = 0;
1970c9afed1SJingyi Wang 
1980c9afed1SJingyi Wang 	irq_received = false;
1990c9afed1SJingyi Wang 
2000c9afed1SJingyi Wang 	dev2 = its_get_device(2);
2010c9afed1SJingyi Wang 	its_send_int_nv(dev2, 20);
2020c9afed1SJingyi Wang 
2030c9afed1SJingyi Wang 	while (!irq_received && tries--)
2040c9afed1SJingyi Wang 		cpu_relax();
2050c9afed1SJingyi Wang 
2060c9afed1SJingyi Wang 	if (irq_received)
2070c9afed1SJingyi Wang 		++received;
2080c9afed1SJingyi Wang 
2090c9afed1SJingyi Wang 	assert_msg(irq_received, "failed to receive LPI in time, but received %d successfully\n", received);
2100c9afed1SJingyi Wang }
2110c9afed1SJingyi Wang 
timer_prep(void)2124c77d77bSJingyi Wang static bool timer_prep(void)
2134c77d77bSJingyi Wang {
2144c77d77bSJingyi Wang 	gic_enable_defaults();
2154c77d77bSJingyi Wang 	install_irq_handler(EL1H_IRQ, gic_irq_handler);
2164c77d77bSJingyi Wang 	local_irq_enable();
2174c77d77bSJingyi Wang 
218bb4c17e3SNikos Nikoleris 	gic_enable_irq(TIMER_VTIMER_IRQ);
219f58a73afSJingyi Wang 	write_sysreg(ARCH_TIMER_CTL_IMASK | ARCH_TIMER_CTL_ENABLE, cntv_ctl_el0);
2204c77d77bSJingyi Wang 	isb();
2214c77d77bSJingyi Wang 
2224c77d77bSJingyi Wang 	gic_prep_common();
2234c77d77bSJingyi Wang 	return true;
2244c77d77bSJingyi Wang }
2254c77d77bSJingyi Wang 
timer_exec(void)2264c77d77bSJingyi Wang static void timer_exec(void)
2274c77d77bSJingyi Wang {
2284c77d77bSJingyi Wang 	u64 before_timer;
2294c77d77bSJingyi Wang 	u64 timer_10ms;
2304c77d77bSJingyi Wang 	unsigned tries = 1 << 28;
2314c77d77bSJingyi Wang 	static int received = 0;
2324c77d77bSJingyi Wang 
2334c77d77bSJingyi Wang 	irq_received = false;
2344c77d77bSJingyi Wang 
2354c77d77bSJingyi Wang 	before_timer = read_sysreg(cntvct_el0);
2364c77d77bSJingyi Wang 	timer_10ms = cntfrq / 100;
2374c77d77bSJingyi Wang 	write_sysreg(before_timer + timer_10ms, cntv_cval_el0);
2384c77d77bSJingyi Wang 	write_sysreg(ARCH_TIMER_CTL_ENABLE, cntv_ctl_el0);
2394c77d77bSJingyi Wang 	isb();
2404c77d77bSJingyi Wang 
2414c77d77bSJingyi Wang 	while (!irq_received && tries--)
2424c77d77bSJingyi Wang 		cpu_relax();
2434c77d77bSJingyi Wang 
2444c77d77bSJingyi Wang 	if (irq_received)
2454c77d77bSJingyi Wang 		++received;
2464c77d77bSJingyi Wang 
2474c77d77bSJingyi Wang 	assert_msg(irq_received, "failed to receive PPI in time, but received %d successfully\n", received);
2484c77d77bSJingyi Wang }
2494c77d77bSJingyi Wang 
timer_post(uint64_t ntimes,uint64_t * total_ticks)2503a2b5f34SJingyi Wang static void timer_post(uint64_t ntimes, uint64_t *total_ticks)
2513a2b5f34SJingyi Wang {
2523a2b5f34SJingyi Wang 	/*
2533a2b5f34SJingyi Wang 	 * We use a 10msec timer to test the latency of PPI,
2547a84b7b2SThomas Huth 	 * so we subtract the ticks of 10msec to get the
2553a2b5f34SJingyi Wang 	 * actual latency
2563a2b5f34SJingyi Wang 	 */
2573a2b5f34SJingyi Wang 	*total_ticks -= ntimes * (cntfrq / 100);
2583a2b5f34SJingyi Wang }
2593a2b5f34SJingyi Wang 
hvc_exec(void)260090e1532SShih-Wei Li static void hvc_exec(void)
261090e1532SShih-Wei Li {
262090e1532SShih-Wei Li 	asm volatile("mov w0, #0x4b000000; hvc #0" ::: "w0");
263090e1532SShih-Wei Li }
264090e1532SShih-Wei Li 
2650ee5bea5SAndrew Jones static void *userspace_emulated_addr;
2660ee5bea5SAndrew Jones 
mmio_read_user_prep(void)2670ee5bea5SAndrew Jones static bool mmio_read_user_prep(void)
268090e1532SShih-Wei Li {
269090e1532SShih-Wei Li 	/*
27030595179SRicardo Koller 	 * FIXME: We need an MMIO address that we can safely read to test
27130595179SRicardo Koller 	 * exits to userspace. Ideally, the test-dev would provide us this
27230595179SRicardo Koller 	 * address (and one we could write to too), but until it does we
27330595179SRicardo Koller 	 * use a virtio-mmio transport address. FIXME2: We should be getting
27430595179SRicardo Koller 	 * this address (and the future test-dev address) from the devicetree,
27530595179SRicardo Koller 	 * but so far we lazily hardcode it.
276090e1532SShih-Wei Li 	 */
27730595179SRicardo Koller 	userspace_emulated_addr = (void *)ioremap(mmio_addr, sizeof(u32));
2780ee5bea5SAndrew Jones 	return true;
2790ee5bea5SAndrew Jones }
280090e1532SShih-Wei Li 
mmio_read_user_exec(void)2810ee5bea5SAndrew Jones static void mmio_read_user_exec(void)
2820ee5bea5SAndrew Jones {
283090e1532SShih-Wei Li 	readl(userspace_emulated_addr);
284090e1532SShih-Wei Li }
285090e1532SShih-Wei Li 
mmio_read_vgic_exec(void)286090e1532SShih-Wei Li static void mmio_read_vgic_exec(void)
287090e1532SShih-Wei Li {
288090e1532SShih-Wei Li 	readl(vgic_dist_base + GICD_IIDR);
289090e1532SShih-Wei Li }
290090e1532SShih-Wei Li 
eoi_exec(void)291090e1532SShih-Wei Li static void eoi_exec(void)
292090e1532SShih-Wei Li {
293090e1532SShih-Wei Li 	int spurious_id = 1023; /* writes to EOI are ignored */
294090e1532SShih-Wei Li 
295090e1532SShih-Wei Li 	/* Avoid measuring assert(..) in gic_write_eoir */
296090e1532SShih-Wei Li 	write_eoir(spurious_id);
297090e1532SShih-Wei Li }
298090e1532SShih-Wei Li 
299090e1532SShih-Wei Li struct exit_test {
300090e1532SShih-Wei Li 	const char *name;
3019c537510SJingyi Wang 	bool (*prep)(void);
302090e1532SShih-Wei Li 	void (*exec)(void);
3036450d9d6SJingyi Wang 	void (*post)(uint64_t ntimes, uint64_t *total_ticks);
304b8d5a5b0SJingyi Wang 	u32 times;
305090e1532SShih-Wei Li 	bool run;
306090e1532SShih-Wei Li };
307090e1532SShih-Wei Li 
308090e1532SShih-Wei Li static struct exit_test tests[] = {
3096450d9d6SJingyi Wang 	{"hvc",			NULL,			hvc_exec,		NULL,		65536,		true},
3100ee5bea5SAndrew Jones 	{"mmio_read_user",	mmio_read_user_prep,	mmio_read_user_exec,	NULL,		65536,		true},
3116450d9d6SJingyi Wang 	{"mmio_read_vgic",	NULL,			mmio_read_vgic_exec,	NULL,		65536,		true},
3126450d9d6SJingyi Wang 	{"eoi",			NULL,			eoi_exec,		NULL,		65536,		true},
3136450d9d6SJingyi Wang 	{"ipi",			ipi_prep,		ipi_exec,		NULL,		65536,		true},
3146450d9d6SJingyi Wang 	{"ipi_hw",		ipi_hw_prep,		ipi_exec,		NULL,		65536,		true},
3156450d9d6SJingyi Wang 	{"lpi",			lpi_prep,		lpi_exec,		NULL,		65536,		true},
3163a2b5f34SJingyi Wang 	{"timer_10ms",		timer_prep,		timer_exec,		timer_post,	256,		true},
317090e1532SShih-Wei Li };
318090e1532SShih-Wei Li 
319090e1532SShih-Wei Li struct ns_time {
320090e1532SShih-Wei Li 	uint64_t ns;
321090e1532SShih-Wei Li 	uint64_t ns_frac;
322090e1532SShih-Wei Li };
323090e1532SShih-Wei Li 
324090e1532SShih-Wei Li #define PS_PER_SEC (1000 * 1000 * 1000 * 1000UL)
ticks_to_ns_time(uint64_t ticks,struct ns_time * ns_time)325090e1532SShih-Wei Li static void ticks_to_ns_time(uint64_t ticks, struct ns_time *ns_time)
326090e1532SShih-Wei Li {
327090e1532SShih-Wei Li 	uint64_t ps_per_tick = PS_PER_SEC / cntfrq + !!(PS_PER_SEC % cntfrq);
328090e1532SShih-Wei Li 	uint64_t ps;
329090e1532SShih-Wei Li 
330090e1532SShih-Wei Li 	ps = ticks * ps_per_tick;
331090e1532SShih-Wei Li 	ns_time->ns = ps / 1000;
332090e1532SShih-Wei Li 	ns_time->ns_frac = (ps % 1000) / 100;
333090e1532SShih-Wei Li }
334090e1532SShih-Wei Li 
loop_test(struct exit_test * test)335090e1532SShih-Wei Li static void loop_test(struct exit_test *test)
336090e1532SShih-Wei Li {
337b8d5a5b0SJingyi Wang 	uint64_t start, end, total_ticks, ntimes = 0;
338174ddaa5SJingyi Wang 	struct ns_time avg_ns, total_ns = {};
339090e1532SShih-Wei Li 
340174ddaa5SJingyi Wang 	total_ticks = 0;
3419c537510SJingyi Wang 	if (test->prep) {
3429c537510SJingyi Wang 		if(!test->prep()) {
3439c537510SJingyi Wang 			printf("%s test skipped\n", test->name);
3449c537510SJingyi Wang 			return;
3459c537510SJingyi Wang 		}
3469c537510SJingyi Wang 	}
347174ddaa5SJingyi Wang 
348*8074c5c2Sheqiong 	dsb(ish);
349090e1532SShih-Wei Li 	isb();
35062546bebSColton Lewis 	start = read_sysreg(cntvct_el0);
351*8074c5c2Sheqiong 	isb();
352*8074c5c2Sheqiong 	while (ntimes < test->times) {
353090e1532SShih-Wei Li 		test->exec();
354*8074c5c2Sheqiong 
355*8074c5c2Sheqiong 		ntimes++;
356*8074c5c2Sheqiong 	}
357*8074c5c2Sheqiong 	dsb(ish);
358090e1532SShih-Wei Li 	isb();
35962546bebSColton Lewis 	end = read_sysreg(cntvct_el0);
360090e1532SShih-Wei Li 
361*8074c5c2Sheqiong 	total_ticks = end - start;
362090e1532SShih-Wei Li 	ticks_to_ns_time(total_ticks, &total_ns);
363174ddaa5SJingyi Wang 
3646450d9d6SJingyi Wang 	if (test->post) {
3656450d9d6SJingyi Wang 		test->post(ntimes, &total_ticks);
3666450d9d6SJingyi Wang 		ticks_to_ns_time(total_ticks, &total_ns);
3676450d9d6SJingyi Wang 	}
3686450d9d6SJingyi Wang 
369b8d5a5b0SJingyi Wang 	avg_ns.ns = total_ns.ns / ntimes;
370b8d5a5b0SJingyi Wang 	avg_ns.ns_frac = total_ns.ns_frac / ntimes;
371090e1532SShih-Wei Li 
372090e1532SShih-Wei Li 	printf("%-30s%15" PRId64 ".%-15" PRId64 "%15" PRId64 ".%-15" PRId64 "\n",
373090e1532SShih-Wei Li 		test->name, total_ns.ns, total_ns.ns_frac, avg_ns.ns, avg_ns.ns_frac);
374090e1532SShih-Wei Li }
375090e1532SShih-Wei Li 
parse_args(int argc,char ** argv)37630595179SRicardo Koller static void parse_args(int argc, char **argv)
37730595179SRicardo Koller {
37830595179SRicardo Koller 	int i, len;
37930595179SRicardo Koller 	long val;
38030595179SRicardo Koller 
38130595179SRicardo Koller 	for (i = 1; i < argc; ++i) {
38230595179SRicardo Koller 		len = parse_keyval(argv[i], &val);
38330595179SRicardo Koller 		if (len == -1)
38430595179SRicardo Koller 			continue;
38530595179SRicardo Koller 
38630595179SRicardo Koller 		if (strncmp(argv[i], "mmio-addr", len) == 0) {
38730595179SRicardo Koller 			mmio_addr = val;
38830595179SRicardo Koller 			report_info("found mmio_addr=0x%lx", mmio_addr);
38930595179SRicardo Koller 		}
39030595179SRicardo Koller 	}
39130595179SRicardo Koller }
39230595179SRicardo Koller 
main(int argc,char ** argv)393090e1532SShih-Wei Li int main(int argc, char **argv)
394090e1532SShih-Wei Li {
395090e1532SShih-Wei Li 	int i;
396090e1532SShih-Wei Li 
39730595179SRicardo Koller 	parse_args(argc, argv);
39830595179SRicardo Koller 
399090e1532SShih-Wei Li 	if (!test_init())
400090e1532SShih-Wei Li 		return 1;
401090e1532SShih-Wei Li 
402090e1532SShih-Wei Li 	printf("\n%-30s%18s%13s%18s%13s\n", "name", "total ns", "", "avg ns", "");
403090e1532SShih-Wei Li 	for (i = 0 ; i < 92; ++i)
404090e1532SShih-Wei Li 		printf("%c", '-');
405090e1532SShih-Wei Li 	printf("\n");
406090e1532SShih-Wei Li 	for (i = 0; i < ARRAY_SIZE(tests); i++) {
407090e1532SShih-Wei Li 		if (!tests[i].run)
408090e1532SShih-Wei Li 			continue;
409090e1532SShih-Wei Li 		assert(tests[i].name && tests[i].exec);
410090e1532SShih-Wei Li 		loop_test(&tests[i]);
411090e1532SShih-Wei Li 	}
412090e1532SShih-Wei Li 
413090e1532SShih-Wei Li 	return 0;
414090e1532SShih-Wei Li }
415