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:	Sun,  2 Feb 2014 22:39:10 +0100
From:	Jiri Olsa <jolsa@...hat.com>
To:	linux-kernel@...r.kernel.org
Cc:	Jiri Olsa <jolsa@...hat.com>,
	Corey Ashford <cjashfor@...ux.vnet.ibm.com>,
	Frederic Weisbecker <fweisbec@...il.com>,
	Ingo Molnar <mingo@...e.hu>,
	Namhyung Kim <namhyung@...nel.org>,
	Paul Mackerras <paulus@...ba.org>,
	Peter Zijlstra <a.p.zijlstra@...llo.nl>,
	Arnaldo Carvalho de Melo <acme@...hat.com>,
	David Ahern <dsahern@...il.com>
Subject: [PATCH 22/22] perf tools: Add support for tracepoint fields

Adding '--tp' option for report command to show
tracepoint related info. Use can specify following
switches:
   - fields: shows separated tracepoint fields
   - format: shows tracepoints 'print fmt' in single column
             (This is default if no switch is given.)

  $ perf report --tp --no-children
  Samples: 4K of event 'sched:sched_switch', Event count (approx.): 4788
   Overhead          Command      Shared Object          Symbol  Print fmt
  +  26.27%          swapper  [kernel.kallsyms]  [k] __schedule  swapper/2:0 [120] R ==> offlineimap:22134 [120]
  +  26.27%      offlineimap  [kernel.kallsyms]  [k] __schedule  offlineimap:22134 [120] S ==> swapper/2:0 [120]
  -   8.15%          swapper  [kernel.kallsyms]  [k] __schedule  swapper/3:0 [120] R ==> offlineimap:22134 [120]
       __schedule
       schedule_preempt_disabled
       cpu_startup_entry
       start_secondary
  +   8.15%      offlineimap  [kernel.kallsyms]  [k] __schedule  offlineimap:22134 [120] S ==> swapper/3:0 [120]

  $ perf report --tp=fields --no-children
  Samples: 4K of event 'sched:sched_switch', Event count (approx.): 4788
    Overhead          Command      Shared Object          Symbol                       prev_comm    prev_pid   prev_prio          prev_state                       next_comm    next_pid   next_prio
  +   26.27%          swapper  [kernel.kallsyms]  [k] __schedule                       swapper/2           0         120                   0                     offlineimap       22134         120
  +   26.27%      offlineimap  [kernel.kallsyms]  [k] __schedule                     offlineimap       22134         120                   1                       swapper/2           0         120
  -    8.15%          swapper  [kernel.kallsyms]  [k] __schedule                       swapper/3           0         120                   0                     offlineimap       22134         120
       __schedule
       schedule_preempt_disabled
       cpu_startup_entry
       start_secondary
  +    8.15%      offlineimap  [kernel.kallsyms]  [k] __schedule                     offlineimap       22134         120                   1                       swapper/3           0         120

Signed-off-by: Jiri Olsa <jolsa@...hat.com>
Cc: Corey Ashford <cjashfor@...ux.vnet.ibm.com>
Cc: Frederic Weisbecker <fweisbec@...il.com>
Cc: Ingo Molnar <mingo@...e.hu>
Cc: Namhyung Kim <namhyung@...nel.org>
Cc: Paul Mackerras <paulus@...ba.org>
Cc: Peter Zijlstra <a.p.zijlstra@...llo.nl>
Cc: Arnaldo Carvalho de Melo <acme@...hat.com>
Cc: David Ahern <dsahern@...il.com>
---
 tools/perf/Documentation/perf-report.txt |   6 +
 tools/perf/Makefile.perf                 |   1 +
 tools/perf/builtin-report.c              |  15 ++
 tools/perf/util/report-tp.c              | 244 +++++++++++++++++++++++++++++++
 tools/perf/util/report-tp.h              |  18 +++
 5 files changed, 284 insertions(+)
 create mode 100644 tools/perf/util/report-tp.c
 create mode 100644 tools/perf/util/report-tp.h

diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 36eb187..ae1a0cf 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -263,6 +263,12 @@ OPTIONS
 --header-only::
 	Show only perf.data header (forces --stdio).
 
+--tp=::
+	Show tracepoint related info, following switches are supported:
+	- fields: shows separated tracepoint fields
+	- format: shows tracepoints 'print fmt' in single column
+		  (This is default if no switch is given.)
+
 SEE ALSO
 --------
 linkperf:perf-stat[1], linkperf:perf-annotate[1]
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index 7257e7e..baccf1d 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -373,6 +373,7 @@ LIB_OBJS += $(OUTPUT)util/stat.o
 LIB_OBJS += $(OUTPUT)util/record.o
 LIB_OBJS += $(OUTPUT)util/srcline.o
 LIB_OBJS += $(OUTPUT)util/data.o
+LIB_OBJS += $(OUTPUT)util/report-tp.o
 
 LIB_OBJS += $(OUTPUT)ui/setup.o
 LIB_OBJS += $(OUTPUT)ui/helpline.o
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 0938c4e..a46bdc9 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -35,6 +35,7 @@
 #include "util/hist.h"
 #include "util/data.h"
 #include "arch/common.h"
+#include "util/report-tp.h"
 
 #include <dlfcn.h>
 #include <linux/bitmap.h>
@@ -664,6 +665,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
 		"perf report [<options>]",
 		NULL
 	};
+	enum report_tp_mode tp_mode;
 	struct report report = {
 		.tool = {
 			.sample		 = process_sample_event,
@@ -779,6 +781,9 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
 	OPT_CALLBACK(0, "percentage", NULL, "relative|absolute",
 		     "how to display percentage of filtered entries", parse_percentage),
 	OPT_BOOLEAN(0, "list", &symbol_conf.show_list, "Show events list"),
+	OPT_CALLBACK_DEFAULT(0, "tp", &tp_mode, "fields,[format]", NULL,
+			     &report_tp_parse_mode, "format"),
+
 	OPT_END()
 	};
 	struct perf_data_file file = {
@@ -924,6 +929,16 @@ repeat:
 	if (symbol_conf.show_list)
 		sort__setup_list();
 
+	if (tp_mode != REPORT_TO_MODE__NONE) {
+		ret = perf_evlist__add_tp_sort_entries(session->evlist,
+						       tp_mode);
+		if (ret) {
+			pr_err("failed to add tracepoints sort entries\n");
+			goto error;
+		}
+		report.raw_info = true;
+	}
+
 	ret = __cmd_report(&report);
 	if (ret == K_SWITCH_INPUT_DATA) {
 		perf_session__delete(session);
diff --git a/tools/perf/util/report-tp.c b/tools/perf/util/report-tp.c
new file mode 100644
index 0000000..9608fd2
--- /dev/null
+++ b/tools/perf/util/report-tp.c
@@ -0,0 +1,244 @@
+#include <traceevent/event-parse.h>
+#include "evlist.h"
+#include "evsel.h"
+#include "sort.h"
+#include "report-tp.h"
+
+struct tp_sort_entry {
+	union {
+		struct format_field	*field;
+		struct event_format	*format;
+	};
+	struct sort_entry se;
+};
+
+#define tp_sort_entry(se) \
+	container_of(se, struct tp_sort_entry, se)
+
+int report_tp_parse_mode(const struct option *opt,
+			 const char *str, int unset)
+{
+	int *tp_mode = opt->value;
+
+	if (unset) {
+		*tp_mode = REPORT_TO_MODE__NONE;
+		return 0;
+	}
+
+	if (!str || !strcmp(str, "fields"))
+		*tp_mode = REPORT_TO_MODE__FIELDS;
+	else if (!strcmp(str, "format"))
+		*tp_mode = REPORT_TO_MODE__FORMAT;
+
+	return 0;
+}
+
+static int64_t field_sort_entry__cmp(struct sort_entry *se,
+				     struct hist_entry *left,
+				     struct hist_entry *right)
+{
+	struct tp_sort_entry *field_se = tp_sort_entry(se);
+	struct raw_info *raw_left = left->raw_info;
+	struct raw_info *raw_right = right->raw_info;
+
+	return pevent_field_cmp(field_se->field, field_se->field,
+				raw_left->data, raw_left->size,
+				raw_right->data, raw_right->size);
+}
+
+static int field_sort_entry__snprintf(struct sort_entry *se,
+				   bool selected __maybe_unused,
+				   struct hist_entry *he,
+				   char *bf, size_t size,
+				   unsigned int width)
+{
+	struct tp_sort_entry *field_se = tp_sort_entry(se);
+	struct raw_info *raw = he->raw_info;
+	struct trace_seq s;
+	int n;
+
+	trace_seq_init(&s);
+
+	pevent_field_info(&s, field_se->field, raw->data, raw->size, false);
+	n = scnprintf(bf, size, "%*s", width, s.buffer);
+	trace_seq_destroy(&s);
+	return n;
+}
+
+static struct tp_sort_entry*
+field_sort_entry__new(struct format_field *field, int width_idx)
+{
+	struct tp_sort_entry *field_se = zalloc(sizeof(*field_se));
+
+	if (field_se) {
+		INIT_LIST_HEAD(&field_se->se.list);
+		field_se->se.se_header		= strdup(field->name);
+		field_se->se.se_cmp		= field_sort_entry__cmp;
+		field_se->se.se_snprintf	= field_sort_entry__snprintf;
+		field_se->se.se_width_idx	= width_idx;
+		field_se->field			= field;
+	}
+
+	return field_se;
+}
+
+static int perf_format_field__width(struct format_field *field)
+{
+	int len = field->size * 2 + 2 /* '0x' */;
+
+	if (field->flags & FIELD_IS_ARRAY)
+		len = 30;
+
+	return len;
+}
+
+static int add_tp_field_entries(struct perf_evsel *evsel)
+{
+	struct format_field **fields, **iter;
+	struct hists *hists = &evsel->hists;
+	struct tp_sort_entry *field_se;
+	int width, width_idx = HISTC_NR_COLS;
+	int ret = -1;
+
+	fields = iter = pevent_event_fields(evsel->tp_format);
+	if (!fields)
+		return 0;
+
+	while (*iter) {
+		field_se = field_sort_entry__new(*iter, width_idx);
+		if (!field_se)
+			goto out;
+
+		if (hists__alloc_col_len(hists, width_idx + 1))
+			goto out;
+
+		width = perf_format_field__width(*iter);
+		hists__set_col_len(hists, width_idx, width);
+
+		hists__sort_entry_add(hists, &field_se->se);
+
+		width_idx++;
+		iter++;
+	}
+
+	ret = 0;
+
+ out:
+	free(fields);
+	return ret;
+}
+
+static int64_t format_sort_entry__cmp(struct sort_entry *se,
+				      struct hist_entry *left,
+				      struct hist_entry *right)
+{
+	struct tp_sort_entry *format_se = tp_sort_entry(se);
+	struct raw_info *raw_left = left->raw_info;
+	struct raw_info *raw_right = right->raw_info;
+	struct format_field **fields, **iter;
+	int ret = 0;
+
+	fields = iter = pevent_event_fields(format_se->format);
+	if (!fields)
+		return 0;
+
+	while (*iter) {
+		struct format_field *field = *iter;
+
+		ret = pevent_field_cmp(field, field,
+				       raw_left->data, raw_left->size,
+				       raw_right->data, raw_right->size);
+		if (ret)
+			break;
+
+		iter++;
+	}
+
+	free(fields);
+	return ret;
+}
+
+static int format_sort_entry__snprintf(struct sort_entry *se,
+				       bool selected __maybe_unused,
+				       struct hist_entry *he,
+				       char *bf, size_t size,
+				       unsigned int width)
+{
+	struct tp_sort_entry *format_se = tp_sort_entry(se);
+	struct raw_info *raw = he->raw_info;
+	struct pevent_record record;
+	struct trace_seq s;
+	int n;
+
+	trace_seq_init(&s);
+
+	memset(&record, 0, sizeof(record));
+	record.cpu  = he->cpu;
+	record.size = raw->size;
+	record.data = raw->data;
+
+	pevent_event_info(&s, format_se->format, &record);
+	n = scnprintf(bf, size, "%*s", width, s.buffer);
+	trace_seq_destroy(&s);
+	return n;
+}
+
+static int add_tp_format_entry(struct perf_evsel *evsel)
+{
+	struct tp_sort_entry *format_se = zalloc(sizeof(*format_se));
+	struct hists *hists = &evsel->hists;
+	int width_idx = HISTC_NR_COLS;
+
+	if (!format_se)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&format_se->se.list);
+	format_se->se.se_header		= "Print fmt";
+	format_se->se.se_cmp		= format_sort_entry__cmp;
+	format_se->se.se_snprintf	= format_sort_entry__snprintf;
+	format_se->se.se_width_idx	= width_idx;
+	format_se->format		= evsel->tp_format;
+
+	if (hists__alloc_col_len(hists, width_idx + 1)) {
+		free(format_se);
+		return -ENOMEM;
+	}
+
+	hists__set_col_len(hists, width_idx, 9);
+	hists__sort_entry_add(hists, &format_se->se);
+	return 0;
+}
+
+static bool perf_evsel__is_tracepoint(struct perf_evsel *evsel)
+{
+	return evsel->attr.type == PERF_TYPE_TRACEPOINT;
+}
+
+int perf_evlist__add_tp_sort_entries(struct perf_evlist *evlist,
+				     enum report_tp_mode mode)
+{
+	struct perf_evsel *evsel;
+	int ret = 0;
+
+	list_for_each_entry(evsel, &evlist->entries, node) {
+		if (!perf_evsel__is_tracepoint(evsel))
+			continue;
+
+		switch (mode) {
+		case REPORT_TO_MODE__FIELDS:
+			ret = add_tp_field_entries(evsel);
+			break;
+		case REPORT_TO_MODE__FORMAT:
+			ret = add_tp_format_entry(evsel);
+			break;
+		case REPORT_TO_MODE__NONE:
+		default:
+			BUG_ON(1);
+		}
+
+		if (ret)
+			break;
+	}
+
+	return ret;
+}
diff --git a/tools/perf/util/report-tp.h b/tools/perf/util/report-tp.h
new file mode 100644
index 0000000..e131982
--- /dev/null
+++ b/tools/perf/util/report-tp.h
@@ -0,0 +1,18 @@
+#ifndef PERF_REPORT_TP_H
+#define PERF_REPORT_TP_H
+
+#include "parse-options.h"
+
+enum report_tp_mode {
+	REPORT_TO_MODE__NONE,
+	REPORT_TO_MODE__FIELDS,
+	REPORT_TO_MODE__FORMAT,
+};
+
+int perf_evlist__add_tp_sort_entries(struct perf_evlist *evlist,
+				     enum report_tp_mode mode);
+
+int report_tp_parse_mode(const struct option *opt,
+			 const char *str, int unset);
+
+#endif /* PERF_REPORT_TP_H */
-- 
1.8.3.1

--
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

Powered by Openwall GNU/*/Linux Powered by OpenVZ