Commit bcf6edcd authored by Xiao Guangrong's avatar Xiao Guangrong Committed by Arnaldo Carvalho de Melo

perf kvm: Events analysis tool

Add 'perf kvm stat' support to analyze kvm vmexit/mmio/ioport smartly

Usage:
- kvm stat
  run a command and gather performance counter statistics, it is the alias of
  perf stat

- trace kvm events:
  perf kvm stat record, or, if other tracepoints are interesting as well, we
  can append the events like this:
  perf kvm stat record -e timer:* -a

  If many guests are running, we can track the specified guest by using -p or
  --pid, -a is used to track events generated by all guests.

- show the result:
  perf kvm stat report

The output example is following:
13005
13059

total 2 guests are running on the host

Then, track the guest whose pid is 13059:
^C[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.253 MB perf.data.guest (~11065 samples) ]

See the vmexit events:

Analyze events for all VCPUs:

             VM-EXIT    Samples  Samples%     Time%         Avg time

         APIC_ACCESS        460    70.55%     0.01%     22.44us ( +-   1.75% )
                 HLT         93    14.26%    99.98% 832077.26us ( +-  10.42% )
  EXTERNAL_INTERRUPT         64     9.82%     0.00%     35.35us ( +-  14.21% )
   PENDING_INTERRUPT         24     3.68%     0.00%      9.29us ( +-  31.39% )
           CR_ACCESS          7     1.07%     0.00%      8.12us ( +-   5.76% )
      IO_INSTRUCTION          3     0.46%     0.00%     18.00us ( +-  11.79% )
       EXCEPTION_NMI          1     0.15%     0.00%      5.83us ( +-   -nan% )

Total Samples:652, Total events handled time:77396109.80us.

See the mmio events:

Analyze events for all VCPUs:

         MMIO Access    Samples  Samples%     Time%         Avg time

        0xfee00380:W        387    84.31%    79.28%      8.29us ( +-   3.32% )
        0xfee00300:W         24     5.23%     9.96%     16.79us ( +-   1.97% )
        0xfee00300:R         24     5.23%     7.83%     13.20us ( +-   3.00% )
        0xfee00310:W         24     5.23%     2.93%      4.94us ( +-   3.84% )

Total Samples:459, Total events handled time:4044.59us.

See the ioport event:

Analyze events for all VCPUs:

      IO Port Access    Samples  Samples%     Time%         Avg time

         0xc050:POUT          3   100.00%   100.00%     13.75us ( +-  10.83% )

Total Samples:3, Total events handled time:41.26us.

And, --vcpu is used to track the specified vcpu and --key is used to sort the
result:

Analyze events for VCPU 0:

             VM-EXIT    Samples  Samples%     Time%         Avg time

                 HLT         27    13.85%    99.97% 405790.24us ( +-  12.70% )
  EXTERNAL_INTERRUPT         13     6.67%     0.00%     27.94us ( +-  22.26% )
         APIC_ACCESS        146    74.87%     0.03%     21.69us ( +-   2.91% )
      IO_INSTRUCTION          2     1.03%     0.00%     17.77us ( +-  20.56% )
           CR_ACCESS          2     1.03%     0.00%      8.55us ( +-   6.47% )
   PENDING_INTERRUPT          5     2.56%     0.00%      6.27us ( +-   3.94% )

Total Samples:195, Total events handled time:10959950.90us.
Signed-off-by: default avatarDong Hao <haodong@linux.vnet.ibm.com>
Signed-off-by: default avatarRunzhen Wang <runzhen@linux.vnet.ibm.com>
[ Dong Hao <haodong@linux.vnet.ibm.com>
  Runzhen Wang <runzhen@linux.vnet.ibm.com>:
     - rebase it on current acme's tree
     - fix the compiling-error on i386 ]
Signed-off-by: default avatarXiao Guangrong <xiaoguangrong@linux.vnet.ibm.com>
Acked-by: default avatarDavid Ahern <dsahern@gmail.com>
Cc: Avi Kivity <avi@redhat.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Marcelo Tosatti <mtosatti@redhat.com>
Cc: kvm@vger.kernel.org
Cc: Runzhen Wang <runzhen@linux.vnet.ibm.com>
Link: http://lkml.kernel.org/r/1347870675-31495-4-git-send-email-haodong@linux.vnet.ibm.comSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 26bf264e
...@@ -12,7 +12,7 @@ SYNOPSIS ...@@ -12,7 +12,7 @@ SYNOPSIS
[--guestkallsyms=<path> --guestmodules=<path> | --guestvmlinux=<path>]] [--guestkallsyms=<path> --guestmodules=<path> | --guestvmlinux=<path>]]
{top|record|report|diff|buildid-list} {top|record|report|diff|buildid-list}
'perf kvm' [--host] [--guest] [--guestkallsyms=<path> --guestmodules=<path> 'perf kvm' [--host] [--guest] [--guestkallsyms=<path> --guestmodules=<path>
| --guestvmlinux=<path>] {top|record|report|diff|buildid-list} | --guestvmlinux=<path>] {top|record|report|diff|buildid-list|stat}
DESCRIPTION DESCRIPTION
----------- -----------
...@@ -38,6 +38,18 @@ There are a couple of variants of perf kvm: ...@@ -38,6 +38,18 @@ There are a couple of variants of perf kvm:
so that other tools can be used to fetch packages with matching symbol tables so that other tools can be used to fetch packages with matching symbol tables
for use by perf report. for use by perf report.
'perf kvm stat <command>' to run a command and gather performance counter
statistics.
Especially, perf 'kvm stat record/report' generates a statistical analysis
of KVM events. Currently, vmexit, mmio and ioport events are supported.
'perf kvm stat record <command>' records kvm events and the events between
start and end <command>.
And this command produces a file which contains tracing results of kvm
events.
'perf kvm stat report' reports statistical data which includes events
handled time, samples, and so on.
OPTIONS OPTIONS
------- -------
-i:: -i::
...@@ -68,7 +80,21 @@ OPTIONS ...@@ -68,7 +80,21 @@ OPTIONS
--guestvmlinux=<path>:: --guestvmlinux=<path>::
Guest os kernel vmlinux. Guest os kernel vmlinux.
STAT REPORT OPTIONS
-------------------
--vcpu=<value>::
analyze events which occures on this vcpu. (default: all vcpus)
--events=<value>::
events to be analyzed. Possible values: vmexit, mmio, ioport.
(default: vmexit)
-k::
--key=<value>::
Sorting key. Possible values: sample (default, sort by samples
number), time (sort by average time).
SEE ALSO SEE ALSO
-------- --------
linkperf:perf-top[1], linkperf:perf-record[1], linkperf:perf-report[1], linkperf:perf-top[1], linkperf:perf-record[1], linkperf:perf-report[1],
linkperf:perf-diff[1], linkperf:perf-buildid-list[1] linkperf:perf-diff[1], linkperf:perf-buildid-list[1],
linkperf:perf-stat[1]
...@@ -16,3 +16,6 @@ arch/*/lib/memset*.S ...@@ -16,3 +16,6 @@ arch/*/lib/memset*.S
include/linux/poison.h include/linux/poison.h
include/linux/magic.h include/linux/magic.h
include/linux/hw_breakpoint.h include/linux/hw_breakpoint.h
arch/x86/include/asm/svm.h
arch/x86/include/asm/vmx.h
arch/x86/include/asm/kvm_host.h
This diff is collapsed.
...@@ -1673,6 +1673,11 @@ static int process_build_id(struct perf_file_section *section, ...@@ -1673,6 +1673,11 @@ static int process_build_id(struct perf_file_section *section,
return 0; return 0;
} }
static char *read_cpuid(struct perf_header *ph, int fd)
{
return do_read_string(fd, ph);
}
static struct perf_evsel * static struct perf_evsel *
perf_evlist__find_by_index(struct perf_evlist *evlist, int idx) perf_evlist__find_by_index(struct perf_evlist *evlist, int idx)
{ {
...@@ -1726,6 +1731,7 @@ process_event_desc(struct perf_file_section *section __maybe_unused, ...@@ -1726,6 +1731,7 @@ process_event_desc(struct perf_file_section *section __maybe_unused,
struct feature_ops { struct feature_ops {
int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist); int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist);
void (*print)(struct perf_header *h, int fd, FILE *fp); void (*print)(struct perf_header *h, int fd, FILE *fp);
char *(*read)(struct perf_header *h, int fd);
int (*process)(struct perf_file_section *section, int (*process)(struct perf_file_section *section,
struct perf_header *h, int feat, int fd, void *data); struct perf_header *h, int feat, int fd, void *data);
const char *name; const char *name;
...@@ -1740,6 +1746,9 @@ struct feature_ops { ...@@ -1740,6 +1746,9 @@ struct feature_ops {
#define FEAT_OPF(n, func) \ #define FEAT_OPF(n, func) \
[n] = { .name = #n, .write = write_##func, .print = print_##func, \ [n] = { .name = #n, .write = write_##func, .print = print_##func, \
.full_only = true } .full_only = true }
#define FEAT_OPA_R(n, func) \
[n] = { .name = #n, .write = write_##func, .print = print_##func, \
.read = read_##func }
/* feature_ops not implemented: */ /* feature_ops not implemented: */
#define print_tracing_data NULL #define print_tracing_data NULL
...@@ -1754,7 +1763,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = { ...@@ -1754,7 +1763,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
FEAT_OPA(HEADER_ARCH, arch), FEAT_OPA(HEADER_ARCH, arch),
FEAT_OPA(HEADER_NRCPUS, nrcpus), FEAT_OPA(HEADER_NRCPUS, nrcpus),
FEAT_OPA(HEADER_CPUDESC, cpudesc), FEAT_OPA(HEADER_CPUDESC, cpudesc),
FEAT_OPA(HEADER_CPUID, cpuid), FEAT_OPA_R(HEADER_CPUID, cpuid),
FEAT_OPA(HEADER_TOTAL_MEM, total_mem), FEAT_OPA(HEADER_TOTAL_MEM, total_mem),
FEAT_OPP(HEADER_EVENT_DESC, event_desc), FEAT_OPP(HEADER_EVENT_DESC, event_desc),
FEAT_OPA(HEADER_CMDLINE, cmdline), FEAT_OPA(HEADER_CMDLINE, cmdline),
...@@ -1809,6 +1818,54 @@ int perf_header__fprintf_info(struct perf_session *session, FILE *fp, bool full) ...@@ -1809,6 +1818,54 @@ int perf_header__fprintf_info(struct perf_session *session, FILE *fp, bool full)
return 0; return 0;
} }
struct header_read_data {
int feat;
char *result;
};
static int perf_file_section__read_feature(struct perf_file_section *section,
struct perf_header *ph,
int feat, int fd, void *data)
{
struct header_read_data *hd = data;
if (feat != hd->feat)
return 0;
if (lseek(fd, section->offset, SEEK_SET) == (off_t)-1) {
pr_debug("Failed to lseek to %" PRIu64 " offset for feature "
"%d, continuing...\n", section->offset, feat);
return 0;
}
if (feat >= HEADER_LAST_FEATURE) {
pr_warning("unknown feature %d\n", feat);
return 0;
}
if (!feat_ops[feat].read) {
pr_warning("read is not supported for feature %d\n", feat);
return 0;
}
hd->result = feat_ops[feat].read(ph, fd);
return 0;
}
char *perf_header__read_feature(struct perf_session *session, int feat)
{
struct perf_header *header = &session->header;
struct header_read_data hd;
int fd = session->fd;
hd.feat = feat;
hd.result = NULL;
perf_header__process_sections(header, fd, &hd,
perf_file_section__read_feature);
return hd.result;
}
static int do_write_feat(int fd, struct perf_header *h, int type, static int do_write_feat(int fd, struct perf_header *h, int type,
struct perf_file_section **p, struct perf_file_section **p,
struct perf_evlist *evlist) struct perf_evlist *evlist)
......
...@@ -94,6 +94,7 @@ int perf_header__process_sections(struct perf_header *header, int fd, ...@@ -94,6 +94,7 @@ int perf_header__process_sections(struct perf_header *header, int fd,
int feat, int fd, void *data)); int feat, int fd, void *data));
int perf_header__fprintf_info(struct perf_session *s, FILE *fp, bool full); int perf_header__fprintf_info(struct perf_session *s, FILE *fp, bool full);
char *perf_header__read_feature(struct perf_session *session, int feat);
int build_id_cache__add_s(const char *sbuild_id, const char *debugdir, int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
const char *name, bool is_kallsyms, bool is_vdso); const char *name, bool is_kallsyms, bool is_vdso);
......
...@@ -16,6 +16,8 @@ struct thread { ...@@ -16,6 +16,8 @@ struct thread {
bool comm_set; bool comm_set;
char *comm; char *comm;
int comm_len; int comm_len;
void *priv;
}; };
struct machine; struct machine;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment