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
test_lapic_existence(void)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((u16)lvr == 0x14, "apic existence");
38 }
39
40 #define TSC_DEADLINE_TIMER_VECTOR 0xef
41
42 static int tdt_count;
43 u64 exptime;
44 int delta;
45 #define TABLE_SIZE 10000
46 u64 table[TABLE_SIZE];
47 volatile int table_idx;
48 volatile int hitmax = 0;
49 int breakmax = 0;
50
tsc_deadline_timer_isr(isr_regs_t * regs)51 static void tsc_deadline_timer_isr(isr_regs_t *regs)
52 {
53 u64 now = rdtsc();
54 ++tdt_count;
55
56 if (table_idx < TABLE_SIZE && tdt_count > 1)
57 table[table_idx++] = now - exptime;
58
59 if (breakmax && tdt_count > 1 && (now - exptime) > breakmax) {
60 hitmax = 1;
61 apic_write(APIC_EOI, 0);
62 return;
63 }
64
65 exptime = now+delta;
66 wrmsr(MSR_IA32_TSCDEADLINE, now+delta);
67 apic_write(APIC_EOI, 0);
68 }
69
start_tsc_deadline_timer(void)70 static void start_tsc_deadline_timer(void)
71 {
72 handle_irq(TSC_DEADLINE_TIMER_VECTOR, tsc_deadline_timer_isr);
73 sti();
74
75 wrmsr(MSR_IA32_TSCDEADLINE, rdmsr(MSR_IA32_TSC)+delta);
76 asm volatile ("nop");
77 }
78
enable_tsc_deadline_timer(void)79 static int enable_tsc_deadline_timer(void)
80 {
81 uint32_t lvtt;
82
83 if (this_cpu_has(X86_FEATURE_TSC_DEADLINE_TIMER)) {
84 lvtt = APIC_LVT_TIMER_TSCDEADLINE | TSC_DEADLINE_TIMER_VECTOR;
85 apic_write(APIC_LVTT, lvtt);
86 start_tsc_deadline_timer();
87 return 1;
88 } else {
89 return 0;
90 }
91 }
92
test_tsc_deadline_timer(void)93 static void test_tsc_deadline_timer(void)
94 {
95 if(enable_tsc_deadline_timer()) {
96 printf("tsc deadline timer enabled\n");
97 } else {
98 printf("tsc deadline timer not detected, aborting\n");
99 abort();
100 }
101 }
102
main(int argc,char ** argv)103 int main(int argc, char **argv)
104 {
105 int i, size;
106
107 setup_vm();
108
109 test_lapic_existence();
110
111 mask_pic_interrupts();
112
113 delta = argc <= 1 ? 200000 : atol(argv[1]);
114 size = argc <= 2 ? TABLE_SIZE : atol(argv[2]);
115 breakmax = argc <= 3 ? 0 : atol(argv[3]);
116 printf("breakmax=%d\n", breakmax);
117 test_tsc_deadline_timer();
118 sti();
119
120 /* The condition might have triggered already, so check before HLT. */
121 while (!hitmax && table_idx < size)
122 asm volatile("hlt");
123
124 for (i = 0; i < table_idx; i++) {
125 if (hitmax && i == table_idx-1)
126 printf("hit max: %d < ", breakmax);
127 printf("latency: %" PRId64 "\n", table[i]);
128 }
129
130 return report_summary();
131 }
132