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((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 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 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 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 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 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