xref: /kvm-unit-tests/x86/tscdeadline_latency.c (revision b006d7eb9c64ed1046041c4eb3c4077be11d8a3d)
1 /*
2  * qemu command line | grep latency | cut -f 2 -d ":" > latency
3  *
4  * In octave:
5  * load latency
6  * min(latency)
7  * max(latency)
8  * mean(latency)
9  * hist(latency, 50)
10  */
11 
12 /*
13  * for host tracing of breakmax option:
14  *
15  * # cd /sys/kernel/debug/tracing/
16  * # echo x86-tsc > trace_clock
17  * # echo "kvm_exit kvm_entry kvm_msr" > set_event
18  * # echo "sched_switch $extratracepoints" >> set_event
19  * # echo apic_timer_fn > set_ftrace_filter
20  * # echo "function" > current_tracer
21  */
22 
23 #include "libcflat.h"
24 #include "apic.h"
25 #include "vm.h"
26 #include "smp.h"
27 #include "desc.h"
28 #include "isr.h"
29 #include "msr.h"
30 
31 static void test_lapic_existence(void)
32 {
33     u32 lvr;
34 
35     lvr = apic_read(APIC_LVR);
36     printf("apic version: %x\n", lvr);
37     report("apic existence", (u16)lvr == 0x14);
38 }
39 
40 #define TSC_DEADLINE_TIMER_MODE (2 << 17)
41 #define TSC_DEADLINE_TIMER_VECTOR 0xef
42 #define MSR_IA32_TSC            0x00000010
43 #define MSR_IA32_TSCDEADLINE    0x000006e0
44 
45 static int tdt_count;
46 u64 exptime;
47 int delta;
48 #define TABLE_SIZE 10000
49 u64 table[TABLE_SIZE];
50 volatile int table_idx;
51 volatile int hitmax = 0;
52 int breakmax = 0;
53 
54 static void tsc_deadline_timer_isr(isr_regs_t *regs)
55 {
56     u64 now = rdtsc();
57     ++tdt_count;
58 
59     if (table_idx < TABLE_SIZE && tdt_count > 1)
60         table[table_idx++] = now - exptime;
61 
62     if (breakmax && tdt_count > 1 && (now - exptime) > breakmax) {
63         hitmax = 1;
64         apic_write(APIC_EOI, 0);
65         return;
66     }
67 
68     exptime = now+delta;
69     wrmsr(MSR_IA32_TSCDEADLINE, now+delta);
70     apic_write(APIC_EOI, 0);
71 }
72 
73 static void start_tsc_deadline_timer(void)
74 {
75     handle_irq(TSC_DEADLINE_TIMER_VECTOR, tsc_deadline_timer_isr);
76     irq_enable();
77 
78     wrmsr(MSR_IA32_TSCDEADLINE, rdmsr(MSR_IA32_TSC)+delta);
79     asm volatile ("nop");
80 }
81 
82 static int enable_tsc_deadline_timer(void)
83 {
84     uint32_t lvtt;
85 
86     if (cpuid(1).c & (1 << 24)) {
87         lvtt = TSC_DEADLINE_TIMER_MODE | TSC_DEADLINE_TIMER_VECTOR;
88         apic_write(APIC_LVTT, lvtt);
89         start_tsc_deadline_timer();
90         return 1;
91     } else {
92         return 0;
93     }
94 }
95 
96 static void test_tsc_deadline_timer(void)
97 {
98     if(enable_tsc_deadline_timer()) {
99         printf("tsc deadline timer enabled\n");
100     } else {
101         printf("tsc deadline timer not detected, aborting\n");
102         abort();
103     }
104 }
105 
106 int main(int argc, char **argv)
107 {
108     int i, size;
109 
110     setup_vm();
111     smp_init();
112     setup_idt();
113 
114     test_lapic_existence();
115 
116     mask_pic_interrupts();
117 
118     delta = argc <= 1 ? 200000 : atol(argv[1]);
119     size = argc <= 2 ? TABLE_SIZE : atol(argv[2]);
120     breakmax = argc <= 3 ? 0 : atol(argv[3]);
121     printf("breakmax=%d\n", breakmax);
122     test_tsc_deadline_timer();
123     irq_enable();
124 
125     do {
126         asm volatile("hlt");
127     } while (!hitmax && table_idx < size);
128 
129     for (i = 0; i < table_idx; i++) {
130         if (hitmax && i == table_idx-1)
131             printf("hit max: %d < ", breakmax);
132         printf("latency: %" PRId64 "\n", table[i]);
133     }
134 
135     return report_summary();
136 }
137