1 #include "libcflat.h"
2 #include "smp.h"
3 #include "atomic.h"
4 #include "processor.h"
5 #include "kvmclock.h"
6
7 #define DEFAULT_TEST_LOOPS 100000000L
8 #define DEFAULT_THRESHOLD 5L
9
10 long loops = DEFAULT_TEST_LOOPS;
11 long sec = 0;
12 long threshold = DEFAULT_THRESHOLD;
13
14 struct test_info {
15 struct spinlock lock;
16 u64 warps; /* warp count */
17 u64 stalls; /* stall count */
18 long long worst; /* worst warp */
19 volatile cycle_t last; /* last cycle seen by test */
20 int check; /* check cycle ? */
21 };
22
23 struct test_info ti[4];
24
wallclock_test(void * data)25 static void wallclock_test(void *data)
26 {
27 int *p_err = data;
28 long ksec, offset;
29 struct timespec ts;
30
31 kvm_get_wallclock(&ts);
32 ksec = ts.tv_sec;
33
34 offset = ksec - sec;
35 printf("Raw nanoseconds value from kvmclock: %" PRIu64 " (cpu %d)\n", kvm_clock_read(), smp_id());
36 printf("Seconds get from kvmclock: %ld (cpu %d, offset: %ld)\n", ksec, smp_id(), offset);
37
38 if (offset > threshold || offset < -threshold) {
39 printf("offset too large!\n");
40 (*p_err)++;
41 }
42 }
43
kvm_clock_test(void * data)44 static void kvm_clock_test(void *data)
45 {
46 struct test_info *hv_test_info = (struct test_info *)data;
47 long i, check = hv_test_info->check;
48
49 for (i = 0; i < loops; i++){
50 cycle_t t0, t1;
51 long long delta;
52
53 if (check == 0) {
54 kvm_clock_read();
55 continue;
56 }
57
58 spin_lock(&hv_test_info->lock);
59 t1 = kvm_clock_read();
60 t0 = hv_test_info->last;
61 hv_test_info->last = kvm_clock_read();
62 spin_unlock(&hv_test_info->lock);
63
64 delta = t1 - t0;
65 if (delta < 0) {
66 spin_lock(&hv_test_info->lock);
67 ++hv_test_info->warps;
68 if (delta < hv_test_info->worst){
69 hv_test_info->worst = delta;
70 printf("Worst warp %lld\n", hv_test_info->worst);
71 }
72 spin_unlock(&hv_test_info->lock);
73 }
74 if (delta == 0)
75 ++hv_test_info->stalls;
76
77 if (!((unsigned long)i & 31))
78 asm volatile("rep; nop");
79 }
80 }
81
cycle_test(int check,struct test_info * ti)82 static int cycle_test(int check, struct test_info *ti)
83 {
84 unsigned long long begin, end;
85
86 begin = rdtsc();
87
88 ti->check = check;
89 on_cpus(kvm_clock_test, ti);
90
91 end = rdtsc();
92
93 printf("Total vcpus: %d\n", cpu_count());
94 printf("Test loops: %ld\n", loops);
95 if (check == 1) {
96 printf("Total warps: %" PRId64 "\n", ti->warps);
97 printf("Total stalls: %" PRId64 "\n", ti->stalls);
98 printf("Worst warp: %lld\n", ti->worst);
99 } else
100 printf("TSC cycles: %lld\n", end - begin);
101
102 return ti->warps ? 1 : 0;
103 }
104
main(int ac,char ** av)105 int main(int ac, char **av)
106 {
107 int nerr = 0;
108 int ncpus;
109 int i;
110
111 if (ac > 1)
112 loops = atol(av[1]);
113 if (ac > 2)
114 sec = atol(av[2]);
115 if (ac > 3)
116 threshold = atol(av[3]);
117
118 ncpus = cpu_count();
119 if (ncpus > MAX_CPU)
120 report_abort("number cpus exceeds %d", MAX_CPU);
121
122 on_cpus(kvm_clock_init, NULL);
123
124 if (ac > 2) {
125 printf("Wallclock test, threshold %ld\n", threshold);
126 printf("Seconds get from host: %ld\n", sec);
127 for (i = 0; i < ncpus; ++i)
128 on_cpu(i, wallclock_test, &nerr);
129 }
130
131 printf("Check the stability of raw cycle ...\n");
132 pvclock_set_flags(PVCLOCK_TSC_STABLE_BIT
133 | PVCLOCK_RAW_CYCLE_BIT);
134 if (cycle_test(1, &ti[0]))
135 printf("Raw cycle is not stable\n");
136 else
137 printf("Raw cycle is stable\n");
138
139 pvclock_set_flags(PVCLOCK_TSC_STABLE_BIT);
140 printf("Monotonic cycle test:\n");
141 nerr += cycle_test(1, &ti[1]);
142
143 printf("Measure the performance of raw cycle ...\n");
144 pvclock_set_flags(PVCLOCK_TSC_STABLE_BIT
145 | PVCLOCK_RAW_CYCLE_BIT);
146 cycle_test(0, &ti[2]);
147
148 printf("Measure the performance of adjusted cycle ...\n");
149 pvclock_set_flags(PVCLOCK_TSC_STABLE_BIT);
150 cycle_test(0, &ti[3]);
151
152 on_cpus(kvm_clock_clear, NULL);
153
154 return nerr > 0 ? 1 : 0;
155 }
156