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