summaryrefslogtreecommitdiff
blob: e7cb5efe0e2a2a50a3bf095e34c3fc54d7fe91b4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#include "libcflat.h"
#include "smp.h"

static inline unsigned long long rdtsc()
{
	long long r;

#ifdef __x86_64__
	unsigned a, d;

	asm volatile ("rdtsc" : "=a"(a), "=d"(d));
	r = a | ((long long)d << 32);
#else
	asm volatile ("rdtsc" : "=A"(r));
#endif
	return r;
}

#define GOAL (1ull << 30)

#ifdef __x86_64__
#  define R "r"
#else
#  define R "e"
#endif

static void cpuid(void)
{
	asm volatile ("push %%"R "bx; cpuid; pop %%"R "bx"
		      : : : "eax", "ecx", "edx");
}

static void vmcall(void)
{
	unsigned long a = 0, b, c, d;

	asm volatile ("vmcall" : "+a"(a), "=b"(b), "=c"(c), "=d"(d));
}

static void mov_from_cr8(void)
{
	unsigned long cr8;

	asm volatile ("mov %%cr8, %0" : "=r"(cr8));
}

static void mov_to_cr8(void)
{
	unsigned long cr8 = 0;

	asm volatile ("mov %0, %%cr8" : : "r"(cr8));
}

static int is_smp(void)
{
	return cpu_count() > 1;
}

static void nop(void *junk)
{
}

static void ipi(void)
{
	on_cpu(1, nop, 0);
}

static void ipi_halt(void)
{
	unsigned long long t;

	on_cpu(1, nop, 0);
	t = rdtsc() + 2000;
	while (rdtsc() < t)
		;
}

static struct test {
	void (*func)(void);
	const char *name;
	int (*valid)(void);
} tests[] = {
	{ cpuid, "cpuid", },
	{ vmcall, "vmcall", },
	{ mov_from_cr8, "mov_from_cr8" },
	{ mov_to_cr8, "mov_to_cr8" },
	{ ipi, "ipi", is_smp },
	{ ipi_halt, "ipi+halt", is_smp },
};

static void do_test(struct test *test)
{
	int i;
	unsigned long long t1, t2;
	unsigned iterations = 32;
        void (*func)(void) = test->func;

        if (test->valid && !test->valid()) {
		printf("%s (skipped)\n", test->name);
		return;
	}

	do {
		iterations *= 2;
		t1 = rdtsc();
		for (i = 0; i < iterations; ++i)
			func();
		t2 = rdtsc();
	} while ((t2 - t1) < GOAL);
	printf("%s %d\n", test->name, (int)((t2 - t1) / iterations));
}

#define ARRAY_SIZE(_x) (sizeof(_x) / sizeof((_x)[0]))

int main(void)
{
	int i;

	smp_init();

	for (i = 0; i < ARRAY_SIZE(tests); ++i)
		do_test(&tests[i]);

	return 0;
}