Spaces:
Runtime error
Runtime error
| long loops = DEFAULT_TEST_LOOPS; | |
| long sec = 0; | |
| long threshold = DEFAULT_THRESHOLD; | |
| struct test_info { | |
| struct spinlock lock; | |
| u64 warps; /* warp count */ | |
| u64 stalls; /* stall count */ | |
| long long worst; /* worst warp */ | |
| volatile cycle_t last; /* last cycle seen by test */ | |
| int check; /* check cycle ? */ | |
| }; | |
| struct test_info ti[4]; | |
| static void wallclock_test(void *data) | |
| { | |
| int *p_err = data; | |
| long ksec, offset; | |
| struct timespec ts; | |
| kvm_get_wallclock(&ts); | |
| ksec = ts.tv_sec; | |
| offset = ksec - sec; | |
| printf("Raw nanoseconds value from kvmclock: %" PRIu64 " (cpu %d)\n", kvm_clock_read(), smp_id()); | |
| printf("Seconds get from kvmclock: %ld (cpu %d, offset: %ld)\n", ksec, smp_id(), offset); | |
| if (offset > threshold || offset < -threshold) { | |
| printf("offset too large!\n"); | |
| (*p_err)++; | |
| } | |
| } | |
| static void kvm_clock_test(void *data) | |
| { | |
| struct test_info *hv_test_info = (struct test_info *)data; | |
| long i, check = hv_test_info->check; | |
| for (i = 0; i < loops; i++){ | |
| cycle_t t0, t1; | |
| long long delta; | |
| if (check == 0) { | |
| kvm_clock_read(); | |
| continue; | |
| } | |
| spin_lock(&hv_test_info->lock); | |
| t1 = kvm_clock_read(); | |
| t0 = hv_test_info->last; | |
| hv_test_info->last = kvm_clock_read(); | |
| spin_unlock(&hv_test_info->lock); | |
| delta = t1 - t0; | |
| if (delta < 0) { | |
| spin_lock(&hv_test_info->lock); | |
| ++hv_test_info->warps; | |
| if (delta < hv_test_info->worst){ | |
| hv_test_info->worst = delta; | |
| printf("Worst warp %lld\n", hv_test_info->worst); | |
| } | |
| spin_unlock(&hv_test_info->lock); | |
| } | |
| if (delta == 0) | |
| ++hv_test_info->stalls; | |
| if (!((unsigned long)i & 31)) | |
| asm volatile("rep; nop"); | |
| } | |
| } | |
| static int cycle_test(int check, struct test_info *ti) | |
| { | |
| unsigned long long begin, end; | |
| begin = rdtsc(); | |
| ti->check = check; | |
| on_cpus(kvm_clock_test, ti); | |
| end = rdtsc(); | |
| printf("Total vcpus: %d\n", cpu_count()); | |
| printf("Test loops: %ld\n", loops); | |
| if (check == 1) { | |
| printf("Total warps: %" PRId64 "\n", ti->warps); | |
| printf("Total stalls: %" PRId64 "\n", ti->stalls); | |
| printf("Worst warp: %lld\n", ti->worst); | |
| } else | |
| printf("TSC cycles: %lld\n", end - begin); | |
| return ti->warps ? 1 : 0; | |
| } | |
| int main(int ac, char **av) | |
| { | |
| int nerr = 0; | |
| int ncpus; | |
| int i; | |
| if (ac > 1) | |
| loops = atol(av[1]); | |
| if (ac > 2) | |
| sec = atol(av[2]); | |
| if (ac > 3) | |
| threshold = atol(av[3]); | |
| smp_init(); | |
| ncpus = cpu_count(); | |
| if (ncpus > MAX_CPU) | |
| report_abort("number cpus exceeds %d", MAX_CPU); | |
| on_cpus(kvm_clock_init, NULL); | |
| if (ac > 2) { | |
| printf("Wallclock test, threshold %ld\n", threshold); | |
| printf("Seconds get from host: %ld\n", sec); | |
| for (i = 0; i < ncpus; ++i) | |
| on_cpu(i, wallclock_test, &nerr); | |
| } | |
| printf("Check the stability of raw cycle ...\n"); | |
| pvclock_set_flags(PVCLOCK_TSC_STABLE_BIT | |
| | PVCLOCK_RAW_CYCLE_BIT); | |
| if (cycle_test(1, &ti[0])) | |
| printf("Raw cycle is not stable\n"); | |
| else | |
| printf("Raw cycle is stable\n"); | |
| pvclock_set_flags(PVCLOCK_TSC_STABLE_BIT); | |
| printf("Monotonic cycle test:\n"); | |
| nerr += cycle_test(1, &ti[1]); | |
| printf("Measure the performance of raw cycle ...\n"); | |
| pvclock_set_flags(PVCLOCK_TSC_STABLE_BIT | |
| | PVCLOCK_RAW_CYCLE_BIT); | |
| cycle_test(0, &ti[2]); | |
| printf("Measure the performance of adjusted cycle ...\n"); | |
| pvclock_set_flags(PVCLOCK_TSC_STABLE_BIT); | |
| cycle_test(0, &ti[3]); | |
| on_cpus(kvm_clock_clear, NULL); | |
| return nerr > 0 ? 1 : 0; | |
| } | |