kvm-stat.c 4.3 KB

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