xref: /kvm-unit-tests/x86/kvmclock_test.c (revision b8e0826efe0ba0b79fadbb2ea53c28d98afa943d)
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("Raw nanoseconds value from kvmclock: %" PRIu64 " (cpu %d)\n", kvm_clock_read(), smp_id());
37         printf("Seconds get from kvmclock: %ld (cpu %d, offset: %ld)\n", ksec, smp_id(), offset);
38 
39         if (offset > threshold || offset < -threshold) {
40                 printf("offset too large!\n");
41                 (*p_err)++;
42         }
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 < 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, 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->check = check;
94         for (i = ncpus - 1; i >= 0; i--)
95                 on_cpu_async(i, kvm_clock_test, (void *)ti);
96 
97         /* Wait for the end of other vcpu */
98         while(atomic_read(&ti->ncpus))
99                 ;
100 
101         end = rdtsc();
102 
103         printf("Total vcpus: %d\n", ncpus);
104         printf("Test  loops: %ld\n", loops);
105         if (check == 1) {
106                 printf("Total warps:  %" PRId64 "\n", ti->warps);
107                 printf("Total stalls: %" PRId64 "\n", ti->stalls);
108                 printf("Worst warp:   %lld\n", ti->worst);
109         } else
110                 printf("TSC cycles:  %lld\n", end - begin);
111 
112         return ti->warps ? 1 : 0;
113 }
114 
115 int main(int ac, char **av)
116 {
117         int nerr = 0;
118         int ncpus;
119         int i;
120 
121         if (ac > 1)
122                 loops = atol(av[1]);
123         if (ac > 2)
124                 sec = atol(av[2]);
125         if (ac > 3)
126                 threshold = atol(av[3]);
127 
128         smp_init();
129 
130         ncpus = cpu_count();
131         if (ncpus > MAX_CPU)
132                 ncpus = MAX_CPU;
133         for (i = 0; i < ncpus; ++i)
134                 on_cpu(i, kvm_clock_init, (void *)0);
135 
136         if (ac > 2) {
137                 printf("Wallclock test, threshold %ld\n", threshold);
138                 printf("Seconds get from host:     %ld\n", sec);
139                 for (i = 0; i < ncpus; ++i)
140                         on_cpu(i, wallclock_test, &nerr);
141         }
142 
143         printf("Check the stability of raw cycle ...\n");
144         pvclock_set_flags(PVCLOCK_TSC_STABLE_BIT
145                           | PVCLOCK_RAW_CYCLE_BIT);
146         if (cycle_test(ncpus, 1, &ti[0]))
147                 printf("Raw cycle is not stable\n");
148         else
149                 printf("Raw cycle is stable\n");
150 
151         pvclock_set_flags(PVCLOCK_TSC_STABLE_BIT);
152         printf("Monotonic cycle test:\n");
153         nerr += cycle_test(ncpus, 1, &ti[1]);
154 
155         printf("Measure the performance of raw cycle ...\n");
156         pvclock_set_flags(PVCLOCK_TSC_STABLE_BIT
157                           | PVCLOCK_RAW_CYCLE_BIT);
158         cycle_test(ncpus, 0, &ti[2]);
159 
160         printf("Measure the performance of adjusted cycle ...\n");
161         pvclock_set_flags(PVCLOCK_TSC_STABLE_BIT);
162         cycle_test(ncpus, 0, &ti[3]);
163 
164         for (i = 0; i < ncpus; ++i)
165                 on_cpu(i, kvm_clock_clear, (void *)0);
166 
167         return nerr > 0 ? 1 : 0;
168 }
169