lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Mon, 07 Jul 2014 16:11:57 +0200
From:	Christian Borntraeger <borntraeger@...ibm.com>
To:	Alexander Yarygin <yarygin@...ux.vnet.ibm.com>,
	Jiri Olsa <jolsa@...hat.com>
CC:	David Ahern <dsahern@...il.com>,
	Peter Zijlstra <a.p.zijlstra@...llo.nl>,
	Paul Mackerras <paulus@...ba.org>,
	Ingo Molnar <mingo@...nel.org>,
	Arnaldo Carvalho de Melo <acme@...nel.com>,
	Cornelia Huck <cornelia.huck@...ibm.com>,
	linux-kernel@...r.kernel.org
Subject: Re: [PATCH 4/4] perf kvm: Add stat support on s390

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@...ux.vnet.ibm.com>

Acked-by: Christian Borntraeger <borntraeger@...ibm.com>
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@...ux.vnet.ibm.com>
> + *
> + * 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@...ux.vnet.ibm.com>
> + *
> + * 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@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists