kvm-stat.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. #include "../../util/kvm-stat.h"
  2. #include <asm/kvm_perf.h>
  3. define_exit_reasons_table(vmx_exit_reasons, VMX_EXIT_REASONS);
  4. define_exit_reasons_table(svm_exit_reasons, SVM_EXIT_REASONS);
  5. static struct kvm_events_ops exit_events = {
  6. .is_begin_event = exit_event_begin,
  7. .is_end_event = exit_event_end,
  8. .decode_key = exit_event_decode_key,
  9. .name = "VM-EXIT"
  10. };
  11. /*
  12. * For the mmio events, we treat:
  13. * the time of MMIO write: kvm_mmio(KVM_TRACE_MMIO_WRITE...) -> kvm_entry
  14. * the time of MMIO read: kvm_exit -> kvm_mmio(KVM_TRACE_MMIO_READ...).
  15. */
  16. static void mmio_event_get_key(struct perf_evsel *evsel, struct perf_sample *sample,
  17. struct event_key *key)
  18. {
  19. key->key = perf_evsel__intval(evsel, sample, "gpa");
  20. key->info = perf_evsel__intval(evsel, sample, "type");
  21. }
  22. #define KVM_TRACE_MMIO_READ_UNSATISFIED 0
  23. #define KVM_TRACE_MMIO_READ 1
  24. #define KVM_TRACE_MMIO_WRITE 2
  25. static bool mmio_event_begin(struct perf_evsel *evsel,
  26. struct perf_sample *sample, struct event_key *key)
  27. {
  28. /* MMIO read begin event in kernel. */
  29. if (kvm_exit_event(evsel))
  30. return true;
  31. /* MMIO write begin event in kernel. */
  32. if (!strcmp(evsel->name, "kvm:kvm_mmio") &&
  33. perf_evsel__intval(evsel, sample, "type") == KVM_TRACE_MMIO_WRITE) {
  34. mmio_event_get_key(evsel, sample, key);
  35. return true;
  36. }
  37. return false;
  38. }
  39. static bool mmio_event_end(struct perf_evsel *evsel, struct perf_sample *sample,
  40. struct event_key *key)
  41. {
  42. /* MMIO write end event in kernel. */
  43. if (kvm_entry_event(evsel))
  44. return true;
  45. /* MMIO read end event in kernel.*/
  46. if (!strcmp(evsel->name, "kvm:kvm_mmio") &&
  47. perf_evsel__intval(evsel, sample, "type") == KVM_TRACE_MMIO_READ) {
  48. mmio_event_get_key(evsel, sample, key);
  49. return true;
  50. }
  51. return false;
  52. }
  53. static void mmio_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused,
  54. struct event_key *key,
  55. char *decode)
  56. {
  57. scnprintf(decode, DECODE_STR_LEN, "%#lx:%s",
  58. (unsigned long)key->key,
  59. key->info == KVM_TRACE_MMIO_WRITE ? "W" : "R");
  60. }
  61. static struct kvm_events_ops mmio_events = {
  62. .is_begin_event = mmio_event_begin,
  63. .is_end_event = mmio_event_end,
  64. .decode_key = mmio_event_decode_key,
  65. .name = "MMIO Access"
  66. };
  67. /* The time of emulation pio access is from kvm_pio to kvm_entry. */
  68. static void ioport_event_get_key(struct perf_evsel *evsel,
  69. struct perf_sample *sample,
  70. struct event_key *key)
  71. {
  72. key->key = perf_evsel__intval(evsel, sample, "port");
  73. key->info = perf_evsel__intval(evsel, sample, "rw");
  74. }
  75. static bool ioport_event_begin(struct perf_evsel *evsel,
  76. struct perf_sample *sample,
  77. struct event_key *key)
  78. {
  79. if (!strcmp(evsel->name, "kvm:kvm_pio")) {
  80. ioport_event_get_key(evsel, sample, key);
  81. return true;
  82. }
  83. return false;
  84. }
  85. static bool ioport_event_end(struct perf_evsel *evsel,
  86. struct perf_sample *sample __maybe_unused,
  87. struct event_key *key __maybe_unused)
  88. {
  89. return kvm_entry_event(evsel);
  90. }
  91. static void ioport_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused,
  92. struct event_key *key,
  93. char *decode)
  94. {
  95. scnprintf(decode, DECODE_STR_LEN, "%#llx:%s",
  96. (unsigned long long)key->key,
  97. key->info ? "POUT" : "PIN");
  98. }
  99. static struct kvm_events_ops ioport_events = {
  100. .is_begin_event = ioport_event_begin,
  101. .is_end_event = ioport_event_end,
  102. .decode_key = ioport_event_decode_key,
  103. .name = "IO Port Access"
  104. };
  105. const char * const kvm_events_tp[] = {
  106. "kvm:kvm_entry",
  107. "kvm:kvm_exit",
  108. "kvm:kvm_mmio",
  109. "kvm:kvm_pio",
  110. NULL,
  111. };
  112. struct kvm_reg_events_ops kvm_reg_events_ops[] = {
  113. { .name = "vmexit", .ops = &exit_events },
  114. { .name = "mmio", .ops = &mmio_events },
  115. { .name = "ioport", .ops = &ioport_events },
  116. { NULL, NULL },
  117. };
  118. const char * const kvm_skip_events[] = {
  119. "HLT",
  120. NULL,
  121. };
  122. int cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid)
  123. {
  124. if (strstr(cpuid, "Intel")) {
  125. kvm->exit_reasons = vmx_exit_reasons;
  126. kvm->exit_reasons_isa = "VMX";
  127. } else if (strstr(cpuid, "AMD")) {
  128. kvm->exit_reasons = svm_exit_reasons;
  129. kvm->exit_reasons_isa = "SVM";
  130. } else
  131. return -ENOTSUP;
  132. return 0;
  133. }