/* * qemu command line | grep latency | cut -f 2 -d ":" > latency * * In octave: * load latency * min(latency) * max(latency) * mean(latency) * hist(latency, 50) */ /* * for host tracing of breakmax option: * * # cd /sys/kernel/debug/tracing/ * # echo x86-tsc > trace_clock * # echo "kvm_exit kvm_entry kvm_msr" > set_event * # echo "sched_switch $extratracepoints" >> set_event * # echo apic_timer_fn > set_ftrace_filter * # echo "function" > current_tracer */ #include "libcflat.h" #include "apic.h" #include "vm.h" #include "smp.h" #include "desc.h" #include "isr.h" #include "msr.h" static void test_lapic_existence(void) { u32 lvr; lvr = apic_read(APIC_LVR); printf("apic version: %x\n", lvr); report("apic existence", (u16)lvr == 0x14); } #define TSC_DEADLINE_TIMER_VECTOR 0xef static int tdt_count; u64 exptime; int delta; #define TABLE_SIZE 10000 u64 table[TABLE_SIZE]; volatile int table_idx; volatile int hitmax = 0; int breakmax = 0; static void tsc_deadline_timer_isr(isr_regs_t *regs) { u64 now = rdtsc(); ++tdt_count; if (table_idx < TABLE_SIZE && tdt_count > 1) table[table_idx++] = now - exptime; if (breakmax && tdt_count > 1 && (now - exptime) > breakmax) { hitmax = 1; apic_write(APIC_EOI, 0); return; } exptime = now+delta; wrmsr(MSR_IA32_TSCDEADLINE, now+delta); apic_write(APIC_EOI, 0); } static void start_tsc_deadline_timer(void) { handle_irq(TSC_DEADLINE_TIMER_VECTOR, tsc_deadline_timer_isr); irq_enable(); wrmsr(MSR_IA32_TSCDEADLINE, rdmsr(MSR_IA32_TSC)+delta); asm volatile ("nop"); } static int enable_tsc_deadline_timer(void) { uint32_t lvtt; if (cpuid(1).c & (1 << 24)) { lvtt = APIC_LVT_TIMER_TSCDEADLINE | TSC_DEADLINE_TIMER_VECTOR; apic_write(APIC_LVTT, lvtt); start_tsc_deadline_timer(); return 1; } else { return 0; } } static void test_tsc_deadline_timer(void) { if(enable_tsc_deadline_timer()) { printf("tsc deadline timer enabled\n"); } else { printf("tsc deadline timer not detected, aborting\n"); abort(); } } int main(int argc, char **argv) { int i, size; setup_vm(); smp_init(); test_lapic_existence(); mask_pic_interrupts(); delta = argc <= 1 ? 200000 : atol(argv[1]); size = argc <= 2 ? TABLE_SIZE : atol(argv[2]); breakmax = argc <= 3 ? 0 : atol(argv[3]); printf("breakmax=%d\n", breakmax); test_tsc_deadline_timer(); irq_enable(); do { asm volatile("hlt"); } while (!hitmax && table_idx < size); for (i = 0; i < table_idx; i++) { if (hitmax && i == table_idx-1) printf("hit max: %d < ", breakmax); printf("latency: %" PRId64 "\n", table[i]); } return report_summary(); }