xref: /kvm-unit-tests/x86/kvmclock_test.c (revision fd5d3dc60d413d77a93da79e65cc945aeb87cf4d)
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 = cpu_count();
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         if (ncpus > MAX_CPU)
134                 ncpus = MAX_CPU;
135         for (i = 0; i < ncpus; ++i)
136                 on_cpu(i, kvm_clock_init, (void *)0);
137 
138         if (ac > 2)
139                 nerr += wallclock_test(sec, threshold);
140 
141         printf("Check the stability of raw cycle ...\n");
142         pvclock_set_flags(PVCLOCK_TSC_STABLE_BIT
143                           | PVCLOCK_RAW_CYCLE_BIT);
144         if (cycle_test(ncpus, loops, 1, &ti[0]))
145                 printf("Raw cycle is not stable\n");
146         else
147                 printf("Raw cycle is stable\n");
148 
149         pvclock_set_flags(PVCLOCK_TSC_STABLE_BIT);
150         printf("Monotonic cycle test:\n");
151         nerr += cycle_test(ncpus, loops, 1, &ti[1]);
152 
153         printf("Measure the performance of raw cycle ...\n");
154         pvclock_set_flags(PVCLOCK_TSC_STABLE_BIT
155                           | PVCLOCK_RAW_CYCLE_BIT);
156         cycle_test(ncpus, loops, 0, &ti[2]);
157 
158         printf("Measure the performance of adjusted cycle ...\n");
159         pvclock_set_flags(PVCLOCK_TSC_STABLE_BIT);
160         cycle_test(ncpus, loops, 0, &ti[3]);
161 
162         for (i = 0; i < ncpus; ++i)
163                 on_cpu(i, kvm_clock_clear, (void *)0);
164 
165         return nerr > 0 ? 1 : 0;
166 }
167