File size: 4,672 Bytes
8df6da4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#include "libcflat.h"
#include "smp.h"
#include "atomic.h"
#include "processor.h"
#include "kvmclock.h"

#define DEFAULT_TEST_LOOPS 100000000L
#define DEFAULT_THRESHOLD  5L

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;
}