133 lines
2.8 KiB
C
133 lines
2.8 KiB
C
/*
|
|
* 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();
|
|
}
|