xref: /kvm-unit-tests/x86/kvmclock_test.c (revision 09b22d11ed03a97adc5f7394a76958fffd953788)
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 struct test_info {
11         struct spinlock lock;
12         long loops;               /* test loops */
13         u64 warps;                /* warp count */
14         u64 stalls;               /* stall count */
15         long long worst;          /* worst warp */
16         volatile cycle_t last;    /* last cycle seen by test */
17         atomic_t ncpus;           /* number of cpu in the test*/
18         int check;                /* check cycle ? */
19 };
20 
21 struct test_info ti[4];
22 
23 static int wallclock_test(long sec, long threshold)
24 {
25         long ksec, offset;
26         struct timespec ts;
27 
28         printf("Wallclock test, threshold %ld\n", threshold);
29         kvm_get_wallclock(&ts);
30         ksec = ts.tv_sec;
31 
32         offset = ksec - sec;
33         printf("Seconds get from host:     %ld\n", sec);
34         printf("Seconds get from kvmclock: %ld\n", ksec);
35         printf("Offset:                    %ld\n", offset);
36 
37         if (offset > threshold || offset < -threshold) {
38                 printf("offset too large!\n");
39                 return 1;
40         }
41 
42         return 0;
43 }
44 
45 static void kvm_clock_test(void *data)
46 {
47         struct test_info *hv_test_info = (struct test_info *)data;
48         long i, check = hv_test_info->check;
49 
50         for (i = 0; i < hv_test_info->loops; i++){
51                 cycle_t t0, t1;
52                 long long delta;
53 
54                 if (check == 0) {
55                         kvm_clock_read();
56                         continue;
57                 }
58 
59                 spin_lock(&hv_test_info->lock);
60                 t1 = kvm_clock_read();
61                 t0 = hv_test_info->last;
62                 hv_test_info->last = kvm_clock_read();
63                 spin_unlock(&hv_test_info->lock);
64 
65                 delta = t1 - t0;
66                 if (delta < 0) {
67                         spin_lock(&hv_test_info->lock);
68                         ++hv_test_info->warps;
69                         if (delta < hv_test_info->worst){
70                                 hv_test_info->worst = delta;
71                                 printf("Worst warp %lld %\n", hv_test_info->worst);
72                         }
73                         spin_unlock(&hv_test_info->lock);
74                 }
75                 if (delta == 0)
76                         ++hv_test_info->stalls;
77 
78                 if (!((unsigned long)i & 31))
79                         asm volatile("rep; nop");
80         }
81 
82         atomic_dec(&hv_test_info->ncpus);
83 }
84 
85 static int cycle_test(int ncpus, long loops, int check, struct test_info *ti)
86 {
87         int i;
88         unsigned long long begin, end;
89 
90         begin = rdtsc();
91 
92         atomic_set(&ti->ncpus, ncpus);
93         ti->loops = loops;
94         ti->check = check;
95         for (i = ncpus - 1; i >= 0; i--)
96                 on_cpu_async(i, kvm_clock_test, (void *)ti);
97 
98         /* Wait for the end of other vcpu */
99         while(atomic_read(&ti->ncpus))
100                 ;
101 
102         end = rdtsc();
103 
104         printf("Total vcpus: %d\n", ncpus);
105         printf("Test  loops: %ld\n", ti->loops);
106         if (check == 1) {
107                 printf("Total warps:  %lld\n", ti->warps);
108                 printf("Total stalls: %lld\n", ti->stalls);
109                 printf("Worst warp:   %lld\n", ti->worst);
110         } else
111                 printf("TSC cycles:  %lld\n", end - begin);
112 
113         return ti->warps ? 1 : 0;
114 }
115 
116 int main(int ac, char **av)
117 {
118         int ncpus;
119         int nerr = 0, i;
120         long loops = DEFAULT_TEST_LOOPS;
121         long sec = 0;
122         long threshold = DEFAULT_THRESHOLD;
123 
124         if (ac > 1)
125                 loops = atol(av[1]);
126         if (ac > 2)
127                 sec = atol(av[2]);
128         if (ac > 3)
129                 threshold = atol(av[3]);
130 
131         smp_init();
132 
133         ncpus = cpu_count();
134         if (ncpus > MAX_CPU)
135                 ncpus = MAX_CPU;
136         for (i = 0; i < ncpus; ++i)
137                 on_cpu(i, kvm_clock_init, (void *)0);
138 
139         if (ac > 2)
140                 nerr += wallclock_test(sec, threshold);
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, loops, 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, loops, 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, loops, 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, loops, 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