From: Wanpeng Li <wanpeng.li@xxxxxxxxxxx> Add APIC Timer periodic/oneshot mode latency test. Cc: Paolo Bonzini <pbonzini@xxxxxxxxxx> Cc: Radim Krčmář <rkrcmar@xxxxxxxxxx> Signed-off-by: Wanpeng Li <wanpeng.li@xxxxxxxxxxx> --- x86/Makefile.x86_64 | 1 + x86/apic_timer_latency.c | 125 +++++++++++++++++++++++++++++++++++++++++++++++ x86/unittests.cfg | 6 +++ 3 files changed, 132 insertions(+) create mode 100644 x86/apic_timer_latency.c diff --git a/x86/Makefile.x86_64 b/x86/Makefile.x86_64 index e166911..c9eda46 100644 --- a/x86/Makefile.x86_64 +++ b/x86/Makefile.x86_64 @@ -14,6 +14,7 @@ tests = $(TEST_DIR)/access.flat $(TEST_DIR)/apic.flat \ tests += $(TEST_DIR)/svm.flat tests += $(TEST_DIR)/vmx.flat tests += $(TEST_DIR)/tscdeadline_latency.flat +tests += $(TEST_DIR)/apic_timer_latency.flat include $(TEST_DIR)/Makefile.common diff --git a/x86/apic_timer_latency.c b/x86/apic_timer_latency.c new file mode 100644 index 0000000..4dd285f --- /dev/null +++ b/x86/apic_timer_latency.c @@ -0,0 +1,125 @@ +/* + * 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); +} + +static int tdt_count; +u64 exptime; +int delta; +int mode; +#define TABLE_SIZE 100000 +u64 table[TABLE_SIZE]; +volatile int table_idx; +volatile int hitmax = 0; +int breakmax = 0; +#define APIC_LVT_TIMER_ONE_SHOT (0) +#define APIC_LVT_TIMER_VECTOR (0xee) + +static void apic_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; + + if (mode == APIC_LVT_TIMER_ONE_SHOT) + /* Set "Initial Counter Register", which starts the timer */ + apic_write(APIC_TMICT, delta); + + apic_write(APIC_EOI, 0); +} + +static void test_apic_timer(int mode) +{ + handle_irq(APIC_LVT_TIMER_VECTOR, apic_timer_isr); + irq_enable(); + + /* Periodic mode */ + apic_write(APIC_LVTT, mode | APIC_LVT_TIMER_VECTOR); + /* Divider == 1 */ + apic_write(APIC_TDCR, 0x0000000b); + apic_write(APIC_TMICT, delta); +} + +int main(int argc, char **argv) +{ + int i, size; + u64 count = 0; + + setup_vm(); + smp_init(); + setup_idt(); + + test_lapic_existence(); + + mask_pic_interrupts(); + + mode = argc <= 1 ? APIC_LVT_TIMER_PERIODIC : atol(argv[1]); + delta = argc <= 2 ? 0x100000 : atol(argv[2]); + size = argc <= 3 ? TABLE_SIZE : atol(argv[3]); + breakmax = argc <= 4 ? 0 : atol(argv[4]); + printf("breakmax=%d\n", breakmax); + if (mode == APIC_LVT_TIMER_PERIODIC) + printf("APIC Timer Periodic Mode\n"); + else if (mode == APIC_LVT_TIMER_ONE_SHOT) + printf("APIC Timer Oneshot Mode\n"); + test_apic_timer(mode); + 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); + count += table[i]; + printf("latency: %" PRId64 "\n", table[i]); + } + + printf("average latency = %lu\n", count/size); + return report_summary(); +} diff --git a/x86/unittests.cfg b/x86/unittests.cfg index 7242517..e055ce1 100644 --- a/x86/unittests.cfg +++ b/x86/unittests.cfg @@ -32,6 +32,12 @@ extra_params = -cpu qemu64,+x2apic,+tsc-deadline arch = x86_64 timeout = 30 +[apic_timer_latency] +file = apic_timer_latency.flat +smp = 1 +arch = x86_64 +timeout = 30 + [ioapic] file = ioapic.flat extra_params = -cpu qemu64 -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html