tscdeadline_latency.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  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. * for host tracing of breakmax option:
  13. *
  14. * # cd /sys/kernel/debug/tracing/
  15. * # echo x86-tsc > trace_clock
  16. * # echo "kvm_exit kvm_entry kvm_msr" > set_event
  17. * # echo "sched_switch $extratracepoints" >> set_event
  18. * # echo apic_timer_fn > set_ftrace_filter
  19. * # echo "function" > current_tracer
  20. */
  21. #include "libcflat.h"
  22. #include "apic.h"
  23. #include "vm.h"
  24. #include "smp.h"
  25. #include "desc.h"
  26. #include "isr.h"
  27. #include "msr.h"
  28. static void test_lapic_existence(void)
  29. {
  30. u32 lvr;
  31. lvr = apic_read(APIC_LVR);
  32. printf("apic version: %x\n", lvr);
  33. report("apic existence", (u16)lvr == 0x14);
  34. }
  35. #define TSC_DEADLINE_TIMER_VECTOR 0xef
  36. static int tdt_count;
  37. u64 exptime;
  38. int delta;
  39. #define TABLE_SIZE 10000
  40. u64 table[TABLE_SIZE];
  41. volatile int table_idx;
  42. volatile int hitmax = 0;
  43. int breakmax = 0;
  44. static void tsc_deadline_timer_isr(isr_regs_t *regs)
  45. {
  46. u64 now = rdtsc();
  47. ++tdt_count;
  48. if (table_idx < TABLE_SIZE && tdt_count > 1)
  49. table[table_idx++] = now - exptime;
  50. if (breakmax && tdt_count > 1 && (now - exptime) > breakmax) {
  51. hitmax = 1;
  52. apic_write(APIC_EOI, 0);
  53. return;
  54. }
  55. exptime = now+delta;
  56. wrmsr(MSR_IA32_TSCDEADLINE, now+delta);
  57. apic_write(APIC_EOI, 0);
  58. }
  59. static void start_tsc_deadline_timer(void)
  60. {
  61. handle_irq(TSC_DEADLINE_TIMER_VECTOR, tsc_deadline_timer_isr);
  62. irq_enable();
  63. wrmsr(MSR_IA32_TSCDEADLINE, rdmsr(MSR_IA32_TSC)+delta);
  64. asm volatile ("nop");
  65. }
  66. static int enable_tsc_deadline_timer(void)
  67. {
  68. uint32_t lvtt;
  69. if (cpuid(1).c & (1 << 24)) {
  70. lvtt = APIC_LVT_TIMER_TSCDEADLINE | TSC_DEADLINE_TIMER_VECTOR;
  71. apic_write(APIC_LVTT, lvtt);
  72. start_tsc_deadline_timer();
  73. return 1;
  74. } else {
  75. return 0;
  76. }
  77. }
  78. static void test_tsc_deadline_timer(void)
  79. {
  80. if(enable_tsc_deadline_timer()) {
  81. printf("tsc deadline timer enabled\n");
  82. } else {
  83. printf("tsc deadline timer not detected, aborting\n");
  84. abort();
  85. }
  86. }
  87. int main(int argc, char **argv)
  88. {
  89. int i, size;
  90. setup_vm();
  91. smp_init();
  92. test_lapic_existence();
  93. mask_pic_interrupts();
  94. delta = argc <= 1 ? 200000 : atol(argv[1]);
  95. size = argc <= 2 ? TABLE_SIZE : atol(argv[2]);
  96. breakmax = argc <= 3 ? 0 : atol(argv[3]);
  97. printf("breakmax=%d\n", breakmax);
  98. test_tsc_deadline_timer();
  99. irq_enable();
  100. do {
  101. asm volatile("hlt");
  102. } while (!hitmax && table_idx < size);
  103. for (i = 0; i < table_idx; i++) {
  104. if (hitmax && i == table_idx-1)
  105. printf("hit max: %d < ", breakmax);
  106. printf("latency: %" PRId64 "\n", table[i]);
  107. }
  108. return report_summary();
  109. }