Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Alexander Yarygin and committed by
Arnaldo Carvalho de Melo
3be8e2a0 54c801ff

+201 -11
+1
arch/s390/include/uapi/asm/Kbuild
··· 16 16 header-y += ipcbuf.h 17 17 header-y += kvm.h 18 18 header-y += kvm_para.h 19 + header-y += kvm_perf.h 19 20 header-y += kvm_virtio.h 20 21 header-y += mman.h 21 22 header-y += monwriter.h
+25
arch/s390/include/uapi/asm/kvm_perf.h
··· 1 + /* 2 + * Definitions for perf-kvm on s390 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 + #ifndef __LINUX_KVM_PERF_S390_H 13 + #define __LINUX_KVM_PERF_S390_H 14 + 15 + #include <asm/sie.h> 16 + 17 + #define DECODE_STR_LEN 40 18 + 19 + #define VCPU_ID "id" 20 + 21 + #define KVM_ENTRY_TRACE "kvm:kvm_s390_sie_enter" 22 + #define KVM_EXIT_TRACE "kvm:kvm_s390_sie_exit" 23 + #define KVM_EXIT_REASON "icptcode" 24 + 25 + #endif
+9 -7
tools/perf/Documentation/perf-kvm.txt
··· 51 51 'perf kvm stat <command>' to run a command and gather performance counter 52 52 statistics. 53 53 Especially, perf 'kvm stat record/report' generates a statistical analysis 54 - of KVM events. Currently, vmexit, mmio and ioport events are supported. 55 - 'perf kvm stat record <command>' records kvm events and the events between 56 - start and end <command>. 54 + of KVM events. Currently, vmexit, mmio (x86 only) and ioport (x86 only) 55 + events are supported. 'perf kvm stat record <command>' records kvm events 56 + and the events between start and end <command>. 57 57 And this command produces a file which contains tracing results of kvm 58 58 events. 59 59 ··· 103 103 analyze events which occures on this vcpu. (default: all vcpus) 104 104 105 105 --event=<value>:: 106 - event to be analyzed. Possible values: vmexit, mmio, ioport. 107 - (default: vmexit) 106 + event to be analyzed. Possible values: vmexit, mmio (x86 only), 107 + ioport (x86 only). (default: vmexit) 108 108 -k:: 109 109 --key=<value>:: 110 110 Sorting key. Possible values: sample (default, sort by samples ··· 138 138 139 139 140 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 143 (default: vmexit) 143 144 144 145 -k:: ··· 148 147 number), time (sort by average time). 149 148 150 149 --duration=<value>:: 151 - Show events other than HLT that take longer than duration usecs. 150 + Show events other than HLT (x86 only) or Wait state (s390 only) 151 + that take longer than duration usecs. 152 152 153 153 SEE ALSO 154 154 --------
+2
tools/perf/MANIFEST
··· 38 38 arch/x86/include/uapi/asm/vmx.h 39 39 arch/x86/include/uapi/asm/kvm.h 40 40 arch/x86/include/uapi/asm/kvm_perf.h 41 + arch/s390/include/uapi/asm/sie.h 42 + arch/s390/include/uapi/asm/kvm_perf.h
+2
tools/perf/arch/s390/Makefile
··· 3 3 LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o 4 4 endif 5 5 LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o 6 + HAVE_KVM_STAT_SUPPORT := 1 7 + LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/kvm-stat.o
+105
tools/perf/arch/s390/util/kvm-stat.c
··· 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 + 15 + define_exit_reasons_table(sie_exit_reasons, sie_intercept_code); 16 + define_exit_reasons_table(sie_icpt_insn_codes, icpt_insn_codes); 17 + define_exit_reasons_table(sie_sigp_order_codes, sigp_order_codes); 18 + define_exit_reasons_table(sie_diagnose_codes, diagnose_codes); 19 + define_exit_reasons_table(sie_icpt_prog_codes, icpt_prog_codes); 20 + 21 + static 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 + 32 + static 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 + 40 + static 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 + 48 + static 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 + 56 + static 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 + 68 + static 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 + 76 + const 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 + 86 + struct kvm_reg_events_ops kvm_reg_events_ops[] = { 87 + { .name = "vmexit", .ops = &exit_events }, 88 + { NULL, NULL }, 89 + }; 90 + 91 + const char * const kvm_skip_events[] = { 92 + "Wait state", 93 + NULL, 94 + }; 95 + 96 + int 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 + }
+48 -4
tools/perf/builtin-kvm.c
··· 88 88 struct event_key *key, 89 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 92 key->key); 93 93 94 94 scnprintf(decode, DECODE_STR_LEN, "%s", exit_reason); ··· 261 261 return true; 262 262 } 263 263 264 + static 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 + 286 + static 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 + 264 301 static bool skip_event(const char *event) 265 302 { 266 303 const char * const *skip_events; ··· 398 361 struct perf_sample *sample) 399 362 { 400 363 struct vcpu_event_record *vcpu_record; 401 - struct event_key key = {.key = INVALID_KEY}; 364 + struct event_key key = { .key = INVALID_KEY, 365 + .exit_reasons = kvm->exit_reasons }; 402 366 403 367 vcpu_record = per_vcpu_record(thread, evsel, sample); 404 368 if (!vcpu_record) ··· 412 374 413 375 if (kvm->events_ops->is_begin_event(evsel, sample, &key)) 414 376 return handle_begin_event(kvm, vcpu_record, &key, sample->time); 377 + 378 + if (is_child_event(kvm, evsel, sample, &key)) 379 + return handle_child_event(kvm, vcpu_record, &key, sample); 415 380 416 381 if (kvm->events_ops->is_end_event(evsel, sample, &key)) 417 382 return handle_end_event(kvm, vcpu_record, &key, sample); ··· 1184 1143 { 1185 1144 const struct option kvm_events_report_options[] = { 1186 1145 OPT_STRING(0, "event", &kvm->report_event, "report event", 1187 - "event for reporting: vmexit, mmio, ioport"), 1146 + "event for reporting: vmexit, " 1147 + "mmio (x86 only), ioport (x86 only)"), 1188 1148 OPT_INTEGER(0, "vcpu", &kvm->trace_vcpu, 1189 1149 "vcpu id to report"), 1190 1150 OPT_STRING('k', "key", &kvm->sort_key, "sort-key", ··· 1291 1249 "key for sorting: sample(sort by samples number)" 1292 1250 " time (sort by avg time)"), 1293 1251 OPT_U64(0, "duration", &kvm->duration, 1294 - "show events other than HALT that take longer than duration usecs"), 1252 + "show events other than" 1253 + " HLT (x86 only) or Wait state (s390 only)" 1254 + " that take longer than duration usecs"), 1295 1255 OPT_END() 1296 1256 }; 1297 1257 const char * const live_usage[] = {
+9
tools/perf/util/kvm-stat.h
··· 12 12 #define INVALID_KEY (~0ULL) 13 13 u64 key; 14 14 int info; 15 + struct exit_reasons_table *exit_reasons; 15 16 }; 16 17 17 18 struct kvm_event_stats { ··· 42 41 43 42 struct perf_kvm_stat; 44 43 44 + struct child_event_ops { 45 + void (*get_key)(struct perf_evsel *evsel, 46 + struct perf_sample *sample, 47 + struct event_key *key); 48 + const char *name; 49 + }; 50 + 45 51 struct kvm_events_ops { 46 52 bool (*is_begin_event)(struct perf_evsel *evsel, 47 53 struct perf_sample *sample, 48 54 struct event_key *key); 49 55 bool (*is_end_event)(struct perf_evsel *evsel, 50 56 struct perf_sample *sample, struct event_key *key); 57 + struct child_event_ops *child_ops; 51 58 void (*decode_key)(struct perf_kvm_stat *kvm, struct event_key *key, 52 59 char *decode); 53 60 const char *name;