Re: [PATCH 4/4] perf kvm: Add stat support on s390
From: Christian Borntraeger
Date: Mon Jul 07 2014 - 10:12:12 EST
On 03/07/14 16:29, Alexander Yarygin wrote:
> 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.
>
> Signed-off-by: Alexander Yarygin <yarygin@xxxxxxxxxxxxxxxxxx>
Acked-by: Christian Borntraeger <borntraeger@xxxxxxxxxx>
Would be good if Paolo and David could ack the KVM/perf parts.
Then this should also go into next merge window.
> ---
> arch/s390/include/uapi/asm/Kbuild | 1 +
> arch/s390/include/uapi/asm/kvm_perf.h | 25 ++++++++
> tools/perf/Documentation/perf-kvm.txt | 10 ++--
> tools/perf/MANIFEST | 2 +
> tools/perf/arch/s390/Makefile | 2 +
> tools/perf/arch/s390/util/kvm-stat.c | 105 +++++++++++++++++++++++++++++++++
> tools/perf/builtin-kvm.c | 52 ++++++++++++++--
> tools/perf/util/kvm-stat.h | 9 +++
> 8 files changed, 198 insertions(+), 8 deletions(-)
> create mode 100644 arch/s390/include/uapi/asm/kvm_perf.h
> create mode 100644 tools/perf/arch/s390/util/kvm-stat.c
>
> diff --git a/arch/s390/include/uapi/asm/Kbuild b/arch/s390/include/uapi/asm/Kbuild
> index 6a9a9eb..0e2b54d 100644
> --- a/arch/s390/include/uapi/asm/Kbuild
> +++ b/arch/s390/include/uapi/asm/Kbuild
> @@ -16,6 +16,7 @@ header-y += ioctls.h
> header-y += ipcbuf.h
> header-y += kvm.h
> header-y += kvm_para.h
> +header-y += kvm_perf.h
> header-y += kvm_virtio.h
> header-y += mman.h
> header-y += monwriter.h
> diff --git a/arch/s390/include/uapi/asm/kvm_perf.h b/arch/s390/include/uapi/asm/kvm_perf.h
> new file mode 100644
> index 0000000..3972827
> --- /dev/null
> +++ b/arch/s390/include/uapi/asm/kvm_perf.h
> @@ -0,0 +1,25 @@
> +/*
> + * Definitions for perf-kvm on s390
> + *
> + * Copyright 2014 IBM Corp.
> + * Author(s): Alexander Yarygin <yarygin@xxxxxxxxxxxxxxxxxx>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License (version 2 only)
> + * as published by the Free Software Foundation.
> + */
> +
> +#ifndef __LINUX_KVM_PERF_S390_H
> +#define __LINUX_KVM_PERF_S390_H
> +
> +#include <asm/sie.h>
> +
> +#define DECODE_STR_LEN 40
> +
> +#define VCPU_ID "id"
> +
> +#define KVM_ENTRY_TRACE "kvm:kvm_s390_sie_enter"
> +#define KVM_EXIT_TRACE "kvm:kvm_s390_sie_exit"
> +#define KVM_EXIT_REASON "icptcode"
> +
> +#endif
> diff --git a/tools/perf/Documentation/perf-kvm.txt b/tools/perf/Documentation/perf-kvm.txt
> index 52276a6..abf2925 100644
> --- a/tools/perf/Documentation/perf-kvm.txt
> +++ b/tools/perf/Documentation/perf-kvm.txt
> @@ -103,8 +103,8 @@ STAT REPORT OPTIONS
> analyze events which occures on this vcpu. (default: all vcpus)
>
> --event=<value>::
> - event to be analyzed. Possible values: vmexit, mmio, ioport.
> - (default: vmexit)
> + event to be analyzed. Possible values: vmexit, mmio (x86 only),
> + ioport (x86 only). (default: vmexit)
> -k::
> --key=<value>::
> Sorting key. Possible values: sample (default, sort by samples
> @@ -138,7 +138,8 @@ STAT LIVE OPTIONS
>
>
> --event=<value>::
> - event to be analyzed. Possible values: vmexit, mmio, ioport.
> + event to be analyzed. Possible values: vmexit,
> + mmio (x86 only), ioport (x86 only).
> (default: vmexit)
>
> -k::
> @@ -147,7 +148,8 @@ STAT LIVE OPTIONS
> number), time (sort by average time).
>
> --duration=<value>::
> - Show events other than HLT that take longer than duration usecs.
> + Show events other than HLT (x86 only) or Wait state (s390 only)
> + that take longer than duration usecs.
>
> SEE ALSO
> --------
> diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST
> index 02b485d..344c4d3 100644
> --- a/tools/perf/MANIFEST
> +++ b/tools/perf/MANIFEST
> @@ -38,3 +38,5 @@ arch/x86/include/uapi/asm/svm.h
> arch/x86/include/uapi/asm/vmx.h
> arch/x86/include/uapi/asm/kvm.h
> arch/x86/include/uapi/asm/kvm_perf.h
> +arch/s390/include/uapi/asm/sie.h
> +arch/s390/include/uapi/asm/kvm_perf.h
> diff --git a/tools/perf/arch/s390/Makefile b/tools/perf/arch/s390/Makefile
> index 744e629..798ac73 100644
> --- a/tools/perf/arch/s390/Makefile
> +++ b/tools/perf/arch/s390/Makefile
> @@ -3,3 +3,5 @@ PERF_HAVE_DWARF_REGS := 1
> LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
> endif
> LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o
> +HAVE_KVM_STAT_SUPPORT := 1
> +LIB_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 0000000..a5dbc07
> --- /dev/null
> +++ b/tools/perf/arch/s390/util/kvm-stat.c
> @@ -0,0 +1,105 @@
> +/*
> + * Arch specific functions for perf kvm stat.
> + *
> + * Copyright 2014 IBM Corp.
> + * Author(s): Alexander Yarygin <yarygin@xxxxxxxxxxxxxxxxxx>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License (version 2 only)
> + * as published by the Free Software Foundation.
> + */
> +
> +#include "../../util/kvm-stat.h"
> +#include <asm/kvm_perf.h>
> +
> +define_exit_reasons_table(sie_exit_reasons, sie_intercept_code);
> +define_exit_reasons_table(sie_icpt_insn_codes, icpt_insn_codes);
> +define_exit_reasons_table(sie_sigp_order_codes, sigp_order_codes);
> +define_exit_reasons_table(sie_diagnose_codes, diagnose_codes);
> +define_exit_reasons_table(sie_icpt_prog_codes, icpt_prog_codes);
> +
> +static void event_icpt_insn_get_key(struct perf_evsel *evsel,
> + struct perf_sample *sample,
> + struct event_key *key)
> +{
> + unsigned long insn;
> +
> + insn = perf_evsel__intval(evsel, sample, "instruction");
> + key->key = icpt_insn_decoder(insn);
> + key->exit_reasons = sie_icpt_insn_codes;
> +}
> +
> +static void event_sigp_get_key(struct perf_evsel *evsel,
> + struct perf_sample *sample,
> + struct event_key *key)
> +{
> + key->key = perf_evsel__intval(evsel, sample, "order_code");
> + key->exit_reasons = sie_sigp_order_codes;
> +}
> +
> +static void event_diag_get_key(struct perf_evsel *evsel,
> + struct perf_sample *sample,
> + struct event_key *key)
> +{
> + key->key = perf_evsel__intval(evsel, sample, "code");
> + key->exit_reasons = sie_diagnose_codes;
> +}
> +
> +static void event_icpt_prog_get_key(struct perf_evsel *evsel,
> + struct perf_sample *sample,
> + struct event_key *key)
> +{
> + key->key = perf_evsel__intval(evsel, sample, "code");
> + key->exit_reasons = sie_icpt_prog_codes;
> +}
> +
> +static struct child_event_ops child_events[] = {
> + { .name = "kvm:kvm_s390_intercept_instruction",
> + .get_key = event_icpt_insn_get_key },
> + { .name = "kvm:kvm_s390_handle_sigp",
> + .get_key = event_sigp_get_key },
> + { .name = "kvm:kvm_s390_handle_diag",
> + .get_key = event_diag_get_key },
> + { .name = "kvm:kvm_s390_intercept_prog",
> + .get_key = event_icpt_prog_get_key },
> + { NULL, NULL },
> +};
> +
> +static struct kvm_events_ops exit_events = {
> + .is_begin_event = exit_event_begin,
> + .is_end_event = exit_event_end,
> + .child_ops = child_events,
> + .decode_key = exit_event_decode_key,
> + .name = "VM-EXIT"
> +};
> +
> +const char * const kvm_events_tp[] = {
> + "kvm:kvm_s390_sie_enter",
> + "kvm:kvm_s390_sie_exit",
> + "kvm:kvm_s390_intercept_instruction",
> + "kvm:kvm_s390_handle_sigp",
> + "kvm:kvm_s390_handle_diag",
> + "kvm:kvm_s390_intercept_prog",
> + NULL,
> +};
> +
> +struct kvm_reg_events_ops kvm_reg_events_ops[] = {
> + { .name = "vmexit", .ops = &exit_events },
> + { NULL, NULL },
> +};
> +
> +const char * const kvm_skip_events[] = {
> + "Wait state",
> + NULL,
> +};
> +
> +int cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid)
> +{
> + if (strstr(cpuid, "IBM/S390")) {
> + kvm->exit_reasons = sie_exit_reasons;
> + kvm->exit_reasons_isa = "SIE";
> + } else
> + return -ENOTSUP;
> +
> + return 0;
> +}
> diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
> index fc2d63d..43367eb 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,
> struct event_key *key,
> char *decode)
> {
> - const char *exit_reason = get_exit_reason(kvm, kvm->exit_reasons,
> + const char *exit_reason = get_exit_reason(kvm, key->exit_reasons,
> key->key);
>
> scnprintf(decode, DECODE_STR_LEN, "%s", exit_reason);
> @@ -261,6 +261,43 @@ static bool update_kvm_event(struct kvm_event *event, int vcpu_id,
> return true;
> }
>
> +static bool is_child_event(struct perf_kvm_stat *kvm,
> + struct perf_evsel *evsel,
> + struct perf_sample *sample,
> + struct event_key *key)
> +{
> + struct child_event_ops *child_ops;
> +
> + child_ops = kvm->events_ops->child_ops;
> +
> + if (!child_ops)
> + return false;
> +
> + for (; child_ops->name; child_ops++) {
> + if (!strcmp(evsel->name, child_ops->name)) {
> + child_ops->get_key(evsel, sample, key);
> + return true;
> + }
> + }
> +
> + return false;
> +}
> +
> +static bool handle_child_event(struct perf_kvm_stat *kvm,
> + struct vcpu_event_record *vcpu_record,
> + struct event_key *key,
> + struct perf_sample *sample __maybe_unused)
> +{
> + struct kvm_event *event = NULL;
> +
> + if (key->key != INVALID_KEY)
> + event = find_create_kvm_event(kvm, key);
> +
> + vcpu_record->last_event = event;
> +
> + return true;
> +}
> +
> static bool skip_event(const char *event)
> {
> const char * const *skip_events;
> @@ -361,7 +398,8 @@ static bool handle_kvm_event(struct perf_kvm_stat *kvm,
> struct perf_sample *sample)
> {
> struct vcpu_event_record *vcpu_record;
> - struct event_key key = {.key = INVALID_KEY};
> + struct event_key key = { .key = INVALID_KEY,
> + .exit_reasons = kvm->exit_reasons };
>
> vcpu_record = per_vcpu_record(thread, evsel, sample);
> if (!vcpu_record)
> @@ -375,6 +413,9 @@ static bool handle_kvm_event(struct perf_kvm_stat *kvm,
> if (kvm->events_ops->is_begin_event(evsel, sample, &key))
> return handle_begin_event(kvm, vcpu_record, &key, sample->time);
>
> + if (is_child_event(kvm, evsel, sample, &key))
> + return handle_child_event(kvm, vcpu_record, &key, sample);
> +
> if (kvm->events_ops->is_end_event(evsel, sample, &key))
> return handle_end_event(kvm, vcpu_record, &key, sample);
>
> @@ -1143,7 +1184,8 @@ kvm_events_report(struct perf_kvm_stat *kvm, int argc, const char **argv)
> {
> const struct option kvm_events_report_options[] = {
> OPT_STRING(0, "event", &kvm->report_event, "report event",
> - "event for reporting: vmexit, mmio, ioport"),
> + "event for reporting: vmexit, "
> + "mmio (x86 only), ioport (x86 only)"),
> OPT_INTEGER(0, "vcpu", &kvm->trace_vcpu,
> "vcpu id to report"),
> OPT_STRING('k', "key", &kvm->sort_key, "sort-key",
> @@ -1249,7 +1291,9 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
> "key for sorting: sample(sort by samples number)"
> " time (sort by avg time)"),
> OPT_U64(0, "duration", &kvm->duration,
> - "show events other than HALT that take longer than duration usecs"),
> + "show events other than"
> + " HLT (x86 only) or Wait state (s390 only)"
> + " that take longer than duration usecs"),
> OPT_END()
> };
> const char * const live_usage[] = {
> diff --git a/tools/perf/util/kvm-stat.h b/tools/perf/util/kvm-stat.h
> index ba937ca..0b5a8cd 100644
> --- a/tools/perf/util/kvm-stat.h
> +++ b/tools/perf/util/kvm-stat.h
> @@ -12,6 +12,7 @@ struct event_key {
> #define INVALID_KEY (~0ULL)
> u64 key;
> int info;
> + struct exit_reasons_table *exit_reasons;
> };
>
> struct kvm_event_stats {
> @@ -41,12 +42,20 @@ struct kvm_event_key {
>
> struct perf_kvm_stat;
>
> +struct child_event_ops {
> + void (*get_key)(struct perf_evsel *evsel,
> + struct perf_sample *sample,
> + struct event_key *key);
> + const char *name;
> +};
> +
> struct kvm_events_ops {
> bool (*is_begin_event)(struct perf_evsel *evsel,
> struct perf_sample *sample,
> struct event_key *key);
> bool (*is_end_event)(struct perf_evsel *evsel,
> struct perf_sample *sample, struct event_key *key);
> + struct child_event_ops *child_ops;
> void (*decode_key)(struct perf_kvm_stat *kvm, struct event_key *key,
> char *decode);
> const char *name;
>
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/