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: %d\n", table[i]); 133 } 134 135 return report_summary(); 136 } 137