aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorAlexander Yarygin <yarygin@linux.vnet.ibm.com>2014-07-03 10:29:07 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2014-07-16 16:57:33 -0400
commit3be8e2a0a53c3179a44a933614f6a893da0b5c19 (patch)
tree7f2ebeed37634cfcf46244e80ad1c1c90642e389 /tools
parent54c801ff71ba9c9ae41871e226b9d846ff9c6bab (diff)
perf kvm: Add stat support on s390
On s390, the vmexit event has a tree-like structure: between exit_event_begin and exit_event_end several other events may happen and with each of them refining the previous ones. This patch adds a decoder for such events to the generic code and also the files <asm/kvm_perf.h> and kvm-stat.c for s390. Commands 'perf kvm stat record', 'report' and 'live' are supported. Reviewed-by: David Ahern <dsahern@gmail.com> Signed-off-by: Alexander Yarygin <yarygin@linux.vnet.ibm.com> Acked-by: Christian Borntraeger <borntraeger@de.ibm.com> Cc: Christian Borntraeger <borntraeger@de.ibm.com> Cc: Cornelia Huck <cornelia.huck@de.ibm.com> Cc: David Ahern <dsahern@gmail.com> Cc: Ingo Molnar <mingo@kernel.org> Cc: Jiri Olsa <jolsa@redhat.com> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Link: http://lkml.kernel.org/r/1404397747-20939-5-git-send-email-yarygin@linux.vnet.ibm.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/Documentation/perf-kvm.txt16
-rw-r--r--tools/perf/MANIFEST2
-rw-r--r--tools/perf/arch/s390/Makefile2
-rw-r--r--tools/perf/arch/s390/util/kvm-stat.c105
-rw-r--r--tools/perf/builtin-kvm.c52
-rw-r--r--tools/perf/util/kvm-stat.h9
6 files changed, 175 insertions, 11 deletions
diff --git a/tools/perf/Documentation/perf-kvm.txt b/tools/perf/Documentation/perf-kvm.txt
index 52276a6d2b75..6e689dc89a2f 100644
--- a/tools/perf/Documentation/perf-kvm.txt
+++ b/tools/perf/Documentation/perf-kvm.txt
@@ -51,9 +51,9 @@ There are a couple of variants of perf kvm:
51 'perf kvm stat <command>' to run a command and gather performance counter 51 'perf kvm stat <command>' to run a command and gather performance counter
52 statistics. 52 statistics.
53 Especially, perf 'kvm stat record/report' generates a statistical analysis 53 Especially, perf 'kvm stat record/report' generates a statistical analysis
54 of KVM events. Currently, vmexit, mmio and ioport events are supported. 54 of KVM events. Currently, vmexit, mmio (x86 only) and ioport (x86 only)
55 'perf kvm stat record <command>' records kvm events and the events between 55 events are supported. 'perf kvm stat record <command>' records kvm events
56 start and end <command>. 56 and the events between start and end <command>.
57 And this command produces a file which contains tracing results of kvm 57 And this command produces a file which contains tracing results of kvm
58 events. 58 events.
59 59
@@ -103,8 +103,8 @@ STAT REPORT OPTIONS
103 analyze events which occures on this vcpu. (default: all vcpus) 103 analyze events which occures on this vcpu. (default: all vcpus)
104 104
105--event=<value>:: 105--event=<value>::
106 event to be analyzed. Possible values: vmexit, mmio, ioport. 106 event to be analyzed. Possible values: vmexit, mmio (x86 only),
107 (default: vmexit) 107 ioport (x86 only). (default: vmexit)
108-k:: 108-k::
109--key=<value>:: 109--key=<value>::
110 Sorting key. Possible values: sample (default, sort by samples 110 Sorting key. Possible values: sample (default, sort by samples
@@ -138,7 +138,8 @@ STAT LIVE OPTIONS
138 138
139 139
140--event=<value>:: 140--event=<value>::
141 event to be analyzed. Possible values: vmexit, mmio, ioport. 141 event to be analyzed. Possible values: vmexit,
142 mmio (x86 only), ioport (x86 only).
142 (default: vmexit) 143 (default: vmexit)
143 144
144-k:: 145-k::
@@ -147,7 +148,8 @@ STAT LIVE OPTIONS
147 number), time (sort by average time). 148 number), time (sort by average time).
148 149
149--duration=<value>:: 150--duration=<value>::
150 Show events other than HLT that take longer than duration usecs. 151 Show events other than HLT (x86 only) or Wait state (s390 only)
152 that take longer than duration usecs.
151 153
152SEE ALSO 154SEE ALSO
153-------- 155--------
diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST
index 02b485d619cd..344c4d3d0a4a 100644
--- a/tools/perf/MANIFEST
+++ b/tools/perf/MANIFEST
@@ -38,3 +38,5 @@ arch/x86/include/uapi/asm/svm.h
38arch/x86/include/uapi/asm/vmx.h 38arch/x86/include/uapi/asm/vmx.h
39arch/x86/include/uapi/asm/kvm.h 39arch/x86/include/uapi/asm/kvm.h
40arch/x86/include/uapi/asm/kvm_perf.h 40arch/x86/include/uapi/asm/kvm_perf.h
41arch/s390/include/uapi/asm/sie.h
42arch/s390/include/uapi/asm/kvm_perf.h
diff --git a/tools/perf/arch/s390/Makefile b/tools/perf/arch/s390/Makefile
index 744e629797be..798ac7379c5f 100644
--- a/tools/perf/arch/s390/Makefile
+++ b/tools/perf/arch/s390/Makefile
@@ -3,3 +3,5 @@ PERF_HAVE_DWARF_REGS := 1
3LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o 3LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
4endif 4endif
5LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o 5LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o
6HAVE_KVM_STAT_SUPPORT := 1
7LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/kvm-stat.o
diff --git a/tools/perf/arch/s390/util/kvm-stat.c b/tools/perf/arch/s390/util/kvm-stat.c
new file mode 100644
index 000000000000..a5dbc07ec9dc
--- /dev/null
+++ b/tools/perf/arch/s390/util/kvm-stat.c
@@ -0,0 +1,105 @@
1/*
2 * Arch specific functions for perf kvm stat.
3 *
4 * Copyright 2014 IBM Corp.
5 * Author(s): Alexander Yarygin <yarygin@linux.vnet.ibm.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License (version 2 only)
9 * as published by the Free Software Foundation.
10 */
11
12#include "../../util/kvm-stat.h"
13#include <asm/kvm_perf.h>
14
15define_exit_reasons_table(sie_exit_reasons, sie_intercept_code);
16define_exit_reasons_table(sie_icpt_insn_codes, icpt_insn_codes);
17define_exit_reasons_table(sie_sigp_order_codes, sigp_order_codes);
18define_exit_reasons_table(sie_diagnose_codes, diagnose_codes);
19define_exit_reasons_table(sie_icpt_prog_codes, icpt_prog_codes);
20
21static void event_icpt_insn_get_key(struct perf_evsel *evsel,
22 struct perf_sample *sample,
23 struct event_key *key)
24{
25 unsigned long insn;
26
27 insn = perf_evsel__intval(evsel, sample, "instruction");
28 key->key = icpt_insn_decoder(insn);
29 key->exit_reasons = sie_icpt_insn_codes;
30}
31
32static void event_sigp_get_key(struct perf_evsel *evsel,
33 struct perf_sample *sample,
34 struct event_key *key)
35{
36 key->key = perf_evsel__intval(evsel, sample, "order_code");
37 key->exit_reasons = sie_sigp_order_codes;
38}
39
40static void event_diag_get_key(struct perf_evsel *evsel,
41 struct perf_sample *sample,
42 struct event_key *key)
43{
44 key->key = perf_evsel__intval(evsel, sample, "code");
45 key->exit_reasons = sie_diagnose_codes;
46}
47
48static void event_icpt_prog_get_key(struct perf_evsel *evsel,
49 struct perf_sample *sample,
50 struct event_key *key)
51{
52 key->key = perf_evsel__intval(evsel, sample, "code");
53 key->exit_reasons = sie_icpt_prog_codes;
54}
55
56static struct child_event_ops child_events[] = {
57 { .name = "kvm:kvm_s390_intercept_instruction",
58 .get_key = event_icpt_insn_get_key },
59 { .name = "kvm:kvm_s390_handle_sigp",
60 .get_key = event_sigp_get_key },
61 { .name = "kvm:kvm_s390_handle_diag",
62 .get_key = event_diag_get_key },
63 { .name = "kvm:kvm_s390_intercept_prog",
64 .get_key = event_icpt_prog_get_key },
65 { NULL, NULL },
66};
67
68static struct kvm_events_ops exit_events = {
69 .is_begin_event = exit_event_begin,
70 .is_end_event = exit_event_end,
71 .child_ops = child_events,
72 .decode_key = exit_event_decode_key,
73 .name = "VM-EXIT"
74};
75
76const char * const kvm_events_tp[] = {
77 "kvm:kvm_s390_sie_enter",
78 "kvm:kvm_s390_sie_exit",
79 "kvm:kvm_s390_intercept_instruction",
80 "kvm:kvm_s390_handle_sigp",
81 "kvm:kvm_s390_handle_diag",
82 "kvm:kvm_s390_intercept_prog",
83 NULL,
84};
85
86struct kvm_reg_events_ops kvm_reg_events_ops[] = {
87 { .name = "vmexit", .ops = &exit_events },
88 { NULL, NULL },
89};
90
91const char * const kvm_skip_events[] = {
92 "Wait state",
93 NULL,
94};
95
96int cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid)
97{
98 if (strstr(cpuid, "IBM/S390")) {
99 kvm->exit_reasons = sie_exit_reasons;
100 kvm->exit_reasons_isa = "SIE";
101 } else
102 return -ENOTSUP;
103
104 return 0;
105}
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
index fc2d63d3e791..43367eb00510 100644
--- a/tools/perf/builtin-kvm.c
+++ b/tools/perf/builtin-kvm.c
@@ -88,7 +88,7 @@ void exit_event_decode_key(struct perf_kvm_stat *kvm,
88 struct event_key *key, 88 struct event_key *key,
89 char *decode) 89 char *decode)
90{ 90{
91 const char *exit_reason = get_exit_reason(kvm, kvm->exit_reasons, 91 const char *exit_reason = get_exit_reason(kvm, key->exit_reasons,
92 key->key); 92 key->key);
93 93
94 scnprintf(decode, DECODE_STR_LEN, "%s", exit_reason); 94 scnprintf(decode, DECODE_STR_LEN, "%s", exit_reason);
@@ -261,6 +261,43 @@ static bool update_kvm_event(struct kvm_event *event, int vcpu_id,
261 return true; 261 return true;
262} 262}
263 263
264static bool is_child_event(struct perf_kvm_stat *kvm,
265 struct perf_evsel *evsel,
266 struct perf_sample *sample,
267 struct event_key *key)
268{
269 struct child_event_ops *child_ops;
270
271 child_ops = kvm->events_ops->child_ops;
272
273 if (!child_ops)
274 return false;
275
276 for (; child_ops->name; child_ops++) {
277 if (!strcmp(evsel->name, child_ops->name)) {
278 child_ops->get_key(evsel, sample, key);
279 return true;
280 }
281 }
282
283 return false;
284}
285
286static bool handle_child_event(struct perf_kvm_stat *kvm,
287 struct vcpu_event_record *vcpu_record,
288 struct event_key *key,
289 struct perf_sample *sample __maybe_unused)
290{
291 struct kvm_event *event = NULL;
292
293 if (key->key != INVALID_KEY)
294 event = find_create_kvm_event(kvm, key);
295
296 vcpu_record->last_event = event;
297
298 return true;
299}
300
264static bool skip_event(const char *event) 301static bool skip_event(const char *event)
265{ 302{
266 const char * const *skip_events; 303 const char * const *skip_events;
@@ -361,7 +398,8 @@ static bool handle_kvm_event(struct perf_kvm_stat *kvm,
361 struct perf_sample *sample) 398 struct perf_sample *sample)
362{ 399{
363 struct vcpu_event_record *vcpu_record; 400 struct vcpu_event_record *vcpu_record;
364 struct event_key key = {.key = INVALID_KEY}; 401 struct event_key key = { .key = INVALID_KEY,
402 .exit_reasons = kvm->exit_reasons };
365 403
366 vcpu_record = per_vcpu_record(thread, evsel, sample); 404 vcpu_record = per_vcpu_record(thread, evsel, sample);
367 if (!vcpu_record) 405 if (!vcpu_record)
@@ -375,6 +413,9 @@ static bool handle_kvm_event(struct perf_kvm_stat *kvm,
375 if (kvm->events_ops->is_begin_event(evsel, sample, &key)) 413 if (kvm->events_ops->is_begin_event(evsel, sample, &key))
376 return handle_begin_event(kvm, vcpu_record, &key, sample->time); 414 return handle_begin_event(kvm, vcpu_record, &key, sample->time);
377 415
416 if (is_child_event(kvm, evsel, sample, &key))
417 return handle_child_event(kvm, vcpu_record, &key, sample);
418
378 if (kvm->events_ops->is_end_event(evsel, sample, &key)) 419 if (kvm->events_ops->is_end_event(evsel, sample, &key))
379 return handle_end_event(kvm, vcpu_record, &key, sample); 420 return handle_end_event(kvm, vcpu_record, &key, sample);
380 421
@@ -1143,7 +1184,8 @@ kvm_events_report(struct perf_kvm_stat *kvm, int argc, const char **argv)
1143{ 1184{
1144 const struct option kvm_events_report_options[] = { 1185 const struct option kvm_events_report_options[] = {
1145 OPT_STRING(0, "event", &kvm->report_event, "report event", 1186 OPT_STRING(0, "event", &kvm->report_event, "report event",
1146 "event for reporting: vmexit, mmio, ioport"), 1187 "event for reporting: vmexit, "
1188 "mmio (x86 only), ioport (x86 only)"),
1147 OPT_INTEGER(0, "vcpu", &kvm->trace_vcpu, 1189 OPT_INTEGER(0, "vcpu", &kvm->trace_vcpu,
1148 "vcpu id to report"), 1190 "vcpu id to report"),
1149 OPT_STRING('k', "key", &kvm->sort_key, "sort-key", 1191 OPT_STRING('k', "key", &kvm->sort_key, "sort-key",
@@ -1249,7 +1291,9 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
1249 "key for sorting: sample(sort by samples number)" 1291 "key for sorting: sample(sort by samples number)"
1250 " time (sort by avg time)"), 1292 " time (sort by avg time)"),
1251 OPT_U64(0, "duration", &kvm->duration, 1293 OPT_U64(0, "duration", &kvm->duration,
1252 "show events other than HALT that take longer than duration usecs"), 1294 "show events other than"
1295 " HLT (x86 only) or Wait state (s390 only)"
1296 " that take longer than duration usecs"),
1253 OPT_END() 1297 OPT_END()
1254 }; 1298 };
1255 const char * const live_usage[] = { 1299 const char * const live_usage[] = {
diff --git a/tools/perf/util/kvm-stat.h b/tools/perf/util/kvm-stat.h
index ba937caa28ac..0b5a8cd2ee79 100644
--- a/tools/perf/util/kvm-stat.h
+++ b/tools/perf/util/kvm-stat.h
@@ -12,6 +12,7 @@ struct event_key {
12 #define INVALID_KEY (~0ULL) 12 #define INVALID_KEY (~0ULL)
13 u64 key; 13 u64 key;
14 int info; 14 int info;
15 struct exit_reasons_table *exit_reasons;
15}; 16};
16 17
17struct kvm_event_stats { 18struct kvm_event_stats {
@@ -41,12 +42,20 @@ struct kvm_event_key {
41 42
42struct perf_kvm_stat; 43struct perf_kvm_stat;
43 44
45struct child_event_ops {
46 void (*get_key)(struct perf_evsel *evsel,
47 struct perf_sample *sample,
48 struct event_key *key);
49 const char *name;
50};
51
44struct kvm_events_ops { 52struct kvm_events_ops {
45 bool (*is_begin_event)(struct perf_evsel *evsel, 53 bool (*is_begin_event)(struct perf_evsel *evsel,
46 struct perf_sample *sample, 54 struct perf_sample *sample,
47 struct event_key *key); 55 struct event_key *key);
48 bool (*is_end_event)(struct perf_evsel *evsel, 56 bool (*is_end_event)(struct perf_evsel *evsel,
49 struct perf_sample *sample, struct event_key *key); 57 struct perf_sample *sample, struct event_key *key);
58 struct child_event_ops *child_ops;
50 void (*decode_key)(struct perf_kvm_stat *kvm, struct event_key *key, 59 void (*decode_key)(struct perf_kvm_stat *kvm, struct event_key *key,
51 char *decode); 60 char *decode);
52 const char *name; 61 const char *name;