xref: /kvm-unit-tests/x86/tscdeadline_latency.c (revision b006d7eb9c64ed1046041c4eb3c4077be11d8a3d)
1d482c497SMarcelo Tosatti /*
2d482c497SMarcelo Tosatti  * qemu command line | grep latency | cut -f 2 -d ":" > latency
3d482c497SMarcelo Tosatti  *
4d482c497SMarcelo Tosatti  * In octave:
5d482c497SMarcelo Tosatti  * load latency
66d7f1387SMarcelo Tosatti  * min(latency)
76d7f1387SMarcelo Tosatti  * max(latency)
86d7f1387SMarcelo Tosatti  * mean(latency)
9d482c497SMarcelo Tosatti  * hist(latency, 50)
10d482c497SMarcelo Tosatti  */
11d482c497SMarcelo Tosatti 
1224ce2536SMarcelo Tosatti /*
1324ce2536SMarcelo Tosatti  * for host tracing of breakmax option:
1424ce2536SMarcelo Tosatti  *
1524ce2536SMarcelo Tosatti  * # cd /sys/kernel/debug/tracing/
1624ce2536SMarcelo Tosatti  * # echo x86-tsc > trace_clock
1724ce2536SMarcelo Tosatti  * # echo "kvm_exit kvm_entry kvm_msr" > set_event
1824ce2536SMarcelo Tosatti  * # echo "sched_switch $extratracepoints" >> set_event
1924ce2536SMarcelo Tosatti  * # echo apic_timer_fn > set_ftrace_filter
2024ce2536SMarcelo Tosatti  * # echo "function" > current_tracer
2124ce2536SMarcelo Tosatti  */
2224ce2536SMarcelo Tosatti 
23d482c497SMarcelo Tosatti #include "libcflat.h"
24d482c497SMarcelo Tosatti #include "apic.h"
25d482c497SMarcelo Tosatti #include "vm.h"
26d482c497SMarcelo Tosatti #include "smp.h"
27d482c497SMarcelo Tosatti #include "desc.h"
28d482c497SMarcelo Tosatti #include "isr.h"
29d482c497SMarcelo Tosatti #include "msr.h"
30d482c497SMarcelo Tosatti 
31d482c497SMarcelo Tosatti static void test_lapic_existence(void)
32d482c497SMarcelo Tosatti {
33d482c497SMarcelo Tosatti     u32 lvr;
34d482c497SMarcelo Tosatti 
35d482c497SMarcelo Tosatti     lvr = apic_read(APIC_LVR);
36d482c497SMarcelo Tosatti     printf("apic version: %x\n", lvr);
37d482c497SMarcelo Tosatti     report("apic existence", (u16)lvr == 0x14);
38d482c497SMarcelo Tosatti }
39d482c497SMarcelo Tosatti 
40d482c497SMarcelo Tosatti #define TSC_DEADLINE_TIMER_MODE (2 << 17)
41d482c497SMarcelo Tosatti #define TSC_DEADLINE_TIMER_VECTOR 0xef
42d482c497SMarcelo Tosatti #define MSR_IA32_TSC            0x00000010
43d482c497SMarcelo Tosatti #define MSR_IA32_TSCDEADLINE    0x000006e0
44d482c497SMarcelo Tosatti 
45d482c497SMarcelo Tosatti static int tdt_count;
46d482c497SMarcelo Tosatti u64 exptime;
47d482c497SMarcelo Tosatti int delta;
48d482c497SMarcelo Tosatti #define TABLE_SIZE 10000
49d482c497SMarcelo Tosatti u64 table[TABLE_SIZE];
50d482c497SMarcelo Tosatti volatile int table_idx;
5124ce2536SMarcelo Tosatti volatile int hitmax = 0;
5224ce2536SMarcelo Tosatti int breakmax = 0;
53d482c497SMarcelo Tosatti 
54d482c497SMarcelo Tosatti static void tsc_deadline_timer_isr(isr_regs_t *regs)
55d482c497SMarcelo Tosatti {
56d482c497SMarcelo Tosatti     u64 now = rdtsc();
57d482c497SMarcelo Tosatti     ++tdt_count;
58d482c497SMarcelo Tosatti 
59d482c497SMarcelo Tosatti     if (table_idx < TABLE_SIZE && tdt_count > 1)
60d482c497SMarcelo Tosatti         table[table_idx++] = now - exptime;
61d482c497SMarcelo Tosatti 
6224ce2536SMarcelo Tosatti     if (breakmax && tdt_count > 1 && (now - exptime) > breakmax) {
6324ce2536SMarcelo Tosatti         hitmax = 1;
6424ce2536SMarcelo Tosatti         apic_write(APIC_EOI, 0);
6524ce2536SMarcelo Tosatti         return;
6624ce2536SMarcelo Tosatti     }
6724ce2536SMarcelo Tosatti 
68d482c497SMarcelo Tosatti     exptime = now+delta;
69d482c497SMarcelo Tosatti     wrmsr(MSR_IA32_TSCDEADLINE, now+delta);
70d482c497SMarcelo Tosatti     apic_write(APIC_EOI, 0);
71d482c497SMarcelo Tosatti }
72d482c497SMarcelo Tosatti 
73d482c497SMarcelo Tosatti static void start_tsc_deadline_timer(void)
74d482c497SMarcelo Tosatti {
75d482c497SMarcelo Tosatti     handle_irq(TSC_DEADLINE_TIMER_VECTOR, tsc_deadline_timer_isr);
76d482c497SMarcelo Tosatti     irq_enable();
77d482c497SMarcelo Tosatti 
78d482c497SMarcelo Tosatti     wrmsr(MSR_IA32_TSCDEADLINE, rdmsr(MSR_IA32_TSC)+delta);
79d482c497SMarcelo Tosatti     asm volatile ("nop");
80d482c497SMarcelo Tosatti }
81d482c497SMarcelo Tosatti 
82d482c497SMarcelo Tosatti static int enable_tsc_deadline_timer(void)
83d482c497SMarcelo Tosatti {
84d482c497SMarcelo Tosatti     uint32_t lvtt;
85d482c497SMarcelo Tosatti 
86d482c497SMarcelo Tosatti     if (cpuid(1).c & (1 << 24)) {
87d482c497SMarcelo Tosatti         lvtt = TSC_DEADLINE_TIMER_MODE | TSC_DEADLINE_TIMER_VECTOR;
88d482c497SMarcelo Tosatti         apic_write(APIC_LVTT, lvtt);
89d482c497SMarcelo Tosatti         start_tsc_deadline_timer();
90d482c497SMarcelo Tosatti         return 1;
91d482c497SMarcelo Tosatti     } else {
92d482c497SMarcelo Tosatti         return 0;
93d482c497SMarcelo Tosatti     }
94d482c497SMarcelo Tosatti }
95d482c497SMarcelo Tosatti 
96d482c497SMarcelo Tosatti static void test_tsc_deadline_timer(void)
97d482c497SMarcelo Tosatti {
98d482c497SMarcelo Tosatti     if(enable_tsc_deadline_timer()) {
99d482c497SMarcelo Tosatti         printf("tsc deadline timer enabled\n");
100d482c497SMarcelo Tosatti     } else {
101a2b7c499SAndrew Jones         printf("tsc deadline timer not detected, aborting\n");
102a2b7c499SAndrew Jones         abort();
103d482c497SMarcelo Tosatti     }
104d482c497SMarcelo Tosatti }
105d482c497SMarcelo Tosatti 
1063dea272fSPaolo Bonzini int main(int argc, char **argv)
107d482c497SMarcelo Tosatti {
1083dea272fSPaolo Bonzini     int i, size;
109d482c497SMarcelo Tosatti 
110d482c497SMarcelo Tosatti     setup_vm();
111d482c497SMarcelo Tosatti     smp_init();
112d482c497SMarcelo Tosatti     setup_idt();
113d482c497SMarcelo Tosatti 
114d482c497SMarcelo Tosatti     test_lapic_existence();
115d482c497SMarcelo Tosatti 
116d482c497SMarcelo Tosatti     mask_pic_interrupts();
117d482c497SMarcelo Tosatti 
1183dea272fSPaolo Bonzini     delta = argc <= 1 ? 200000 : atol(argv[1]);
11924ce2536SMarcelo Tosatti     size = argc <= 2 ? TABLE_SIZE : atol(argv[2]);
12024ce2536SMarcelo Tosatti     breakmax = argc <= 3 ? 0 : atol(argv[3]);
12124ce2536SMarcelo Tosatti     printf("breakmax=%d\n", breakmax);
122d482c497SMarcelo Tosatti     test_tsc_deadline_timer();
123d482c497SMarcelo Tosatti     irq_enable();
124d482c497SMarcelo Tosatti 
125d482c497SMarcelo Tosatti     do {
126d482c497SMarcelo Tosatti         asm volatile("hlt");
12724ce2536SMarcelo Tosatti     } while (!hitmax && table_idx < size);
128d482c497SMarcelo Tosatti 
12924ce2536SMarcelo Tosatti     for (i = 0; i < table_idx; i++) {
13024ce2536SMarcelo Tosatti         if (hitmax && i == table_idx-1)
13124ce2536SMarcelo Tosatti             printf("hit max: %d < ", breakmax);
132*b006d7ebSAndrew Jones         printf("latency: %" PRId64 "\n", table[i]);
13324ce2536SMarcelo Tosatti     }
134d482c497SMarcelo Tosatti 
135d482c497SMarcelo Tosatti     return report_summary();
136d482c497SMarcelo Tosatti }
137