xref: /kvm-unit-tests/x86/kvmclock_test.c (revision 31e68df7c38220f4144a45b8e3d1663f6348ee7e)
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