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: %ld (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