xref: /kvm-unit-tests/x86/kvmclock_test.c (revision 4f0202c011f4bee95a55c839cf71bebdcf4877a5)
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         atomic_t ncpus;           /* number of cpu in the test*/
21         int check;                /* check cycle ? */
22 };
23 
24 struct test_info ti[4];
25 
26 static void wallclock_test(void *data)
27 {
28         int *p_err = data;
29         long ksec, offset;
30         struct timespec ts;
31 
32         kvm_get_wallclock(&ts);
33         ksec = ts.tv_sec;
34 
35         offset = ksec - sec;
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 
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         atomic_dec(&hv_test_info->ncpus);
82 }
83 
84 static int cycle_test(int ncpus, int check, struct test_info *ti)
85 {
86         int i;
87         unsigned long long begin, end;
88 
89         begin = rdtsc();
90 
91         atomic_set(&ti->ncpus, ncpus);
92         ti->check = check;
93         for (i = ncpus - 1; i >= 0; i--)
94                 on_cpu_async(i, kvm_clock_test, (void *)ti);
95 
96         /* Wait for the end of other vcpu */
97         while(atomic_read(&ti->ncpus))
98                 ;
99 
100         end = rdtsc();
101 
102         printf("Total vcpus: %d\n", ncpus);
103         printf("Test  loops: %ld\n", loops);
104         if (check == 1) {
105                 printf("Total warps:  %lld\n", ti->warps);
106                 printf("Total stalls: %lld\n", ti->stalls);
107                 printf("Worst warp:   %lld\n", ti->worst);
108         } else
109                 printf("TSC cycles:  %lld\n", end - begin);
110 
111         return ti->warps ? 1 : 0;
112 }
113 
114 int main(int ac, char **av)
115 {
116         int nerr = 0;
117         int ncpus;
118         int i;
119 
120         if (ac > 1)
121                 loops = atol(av[1]);
122         if (ac > 2)
123                 sec = atol(av[2]);
124         if (ac > 3)
125                 threshold = atol(av[3]);
126 
127         smp_init();
128 
129         ncpus = cpu_count();
130         if (ncpus > MAX_CPU)
131                 ncpus = MAX_CPU;
132         for (i = 0; i < ncpus; ++i)
133                 on_cpu(i, kvm_clock_init, (void *)0);
134 
135         if (ac > 2) {
136                 printf("Wallclock test, threshold %ld\n", threshold);
137                 printf("Seconds get from host:     %ld\n", sec);
138                 for (i = 0; i < ncpus; ++i)
139                         on_cpu(i, wallclock_test, &nerr);
140         }
141 
142         printf("Check the stability of raw cycle ...\n");
143         pvclock_set_flags(PVCLOCK_TSC_STABLE_BIT
144                           | PVCLOCK_RAW_CYCLE_BIT);
145         if (cycle_test(ncpus, 1, &ti[0]))
146                 printf("Raw cycle is not stable\n");
147         else
148                 printf("Raw cycle is stable\n");
149 
150         pvclock_set_flags(PVCLOCK_TSC_STABLE_BIT);
151         printf("Monotonic cycle test:\n");
152         nerr += cycle_test(ncpus, 1, &ti[1]);
153 
154         printf("Measure the performance of raw cycle ...\n");
155         pvclock_set_flags(PVCLOCK_TSC_STABLE_BIT
156                           | PVCLOCK_RAW_CYCLE_BIT);
157         cycle_test(ncpus, 0, &ti[2]);
158 
159         printf("Measure the performance of adjusted cycle ...\n");
160         pvclock_set_flags(PVCLOCK_TSC_STABLE_BIT);
161         cycle_test(ncpus, 0, &ti[3]);
162 
163         for (i = 0; i < ncpus; ++i)
164                 on_cpu(i, kvm_clock_clear, (void *)0);
165 
166         return nerr > 0 ? 1 : 0;
167 }
168