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