kvm-stat.c 4.2 KB

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