Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1350275 > unrolled thread
| Started by | Namhyung Kim <namhyung@kernel.org> |
|---|---|
| First post | 2016-03-04 16:10 +0100 |
| Last post | 2016-03-07 13:50 +0100 |
| Articles | 17 — 4 participants |
Back to article view | Back to linux.kernel
[PATCHSET 0/8] perf tools: Support multiple keys in a single hierarchy level (v2) Namhyung Kim <namhyung@kernel.org> - 2016-03-04 16:10 +0100
[PATCH v2 1/8] perf tools: Add level field to struct perf_hpp_fmt Namhyung Kim <namhyung@kernel.org> - 2016-03-04 16:10 +0100
[tip:perf/core] perf hists: Add level field to struct perf_hpp_fmt tip-bot for Namhyung Kim <tipbot@zytor.com> - 2016-03-08 11:40 +0100
[PATCH v2 7/8] perf hists browser: Use hierarchy hpp list Namhyung Kim <namhyung@kernel.org> - 2016-03-04 16:10 +0100
[PATCH v2 5/8] perf tools: Fix indent for multiple hierarchy sort key Namhyung Kim <namhyung@kernel.org> - 2016-03-04 16:10 +0100
[PATCH v2 2/8] perf tools: Introduce perf_hpp__setup_hists_formats() Namhyung Kim <namhyung@kernel.org> - 2016-03-04 16:10 +0100
Re: [PATCH v2 2/8] perf tools: Introduce perf_hpp__setup_hists_formats() Arnaldo Carvalho de Melo <acme@kernel.org> - 2016-03-04 23:00 +0100
Re: [PATCH v2 2/8] perf tools: Introduce perf_hpp__setup_hists_formats() Arnaldo Carvalho de Melo <acme@kernel.org> - 2016-03-04 23:00 +0100
Re: [PATCH v2 2/8] perf tools: Introduce perf_hpp__setup_hists_formats() Namhyung Kim <namhyung@kernel.org> - 2016-03-07 13:50 +0100
Re: [PATCH v2 2/8] perf tools: Introduce perf_hpp__setup_hists_formats() Namhyung Kim <namhyung@kernel.org> - 2016-03-07 15:00 +0100
Re: [PATCH v2 2/8] perf tools: Introduce perf_hpp__setup_hists_formats() Jiri Olsa <jolsa@redhat.com> - 2016-03-06 19:50 +0100
Re: [PATCH v2 2/8] perf tools: Introduce perf_hpp__setup_hists_formats() Namhyung Kim <namhyung@kernel.org> - 2016-03-07 14:10 +0100
Re: [PATCH v2 2/8] perf tools: Introduce perf_hpp__setup_hists_formats() Jiri Olsa <jolsa@redhat.com> - 2016-03-07 14:20 +0100
[PATCH v2 8/8] perf report: Use hierarchy hpp list on gtk Namhyung Kim <namhyung@kernel.org> - 2016-03-04 16:10 +0100
[PATCH v2 4/8] perf tools: Support multiple sort keys in a hierarchy level Namhyung Kim <namhyung@kernel.org> - 2016-03-04 16:10 +0100
Re: [PATCH v2 4/8] perf tools: Support multiple sort keys in a hierarchy level Arnaldo Carvalho de Melo <acme@kernel.org> - 2016-03-04 22:50 +0100
Re: [PATCH v2 4/8] perf tools: Support multiple sort keys in a hierarchy level Namhyung Kim <namhyung@kernel.org> - 2016-03-07 13:50 +0100
| From | Namhyung Kim <namhyung@kernel.org> |
|---|---|
| Date | 2016-03-04 16:10 +0100 |
| Subject | [PATCHSET 0/8] perf tools: Support multiple keys in a single hierarchy level (v2) |
| Message-ID | <r8ZwB-8vJ-11@gated-at.bofh.it> |
Hello,
This implements what Arnaldo suggested in previous discussion of
hierarchy patchset [1]. Originally each level in a hierarchy can have
a single sort key in it, but with this patches it's possible to have
more than one sort keys using a syntax similar to event grouping. I
added the struct perf_hpp_list_node and carry it to group output
formats (hpp_fmt) in a single level.
* Changes from v1)
- use '{ }' to group sort keys (Arnaldo)
- cleanup hpp_list_node creation (Jiri)
Example below shows how 4 sort keys are used for 2 levels. As you can
see, the first level shows pid and comm of previous (switched) task
and the second level shows pid and comm of next task.
$ perf report --hierarchy -s '{prev_pid,prev_comm},{next_pid,next_comm}' \
--percent-limit 1 -i perf.data.sched
...
# Overhead prev_pid+prev_comm / next_pid+next_comm
# ........... .......................................
#
22.36% 0 swapper/0
9.48% 17773 transmission-gt
5.25% 109 kworker/0:1H
1.53% 6524 Xephyr
21.39% 17773 transmission-gt
9.52% 0 swapper/0
9.04% 0 swapper/2
1.78% 0 swapper/3
It's available on the 'perf/hierarchy-multi-v2' branch in my tree
git://git.kernel.org/pub/scm/linux/kernel/git/namhyung/linux-perf.git
Any feedbacks are welcome
Thanks,
Namhyung
[1] https://lkml.org/lkml/2016/2/24/1041
Namhyung Kim (8):
perf tools: Add level field to struct perf_hpp_fmt
perf tools: Introduce perf_hpp__setup_hists_formats()
perf tools: Use own hpp_list for hierarchy mode
perf tools: Support multiple sort keys in a hierarchy
perf tools: Fix indent for multiple hierarchy sort key
perf report: Use hierarchy hpp list on stdio
perf hists browser: Use hierarchy hpp list
perf report: Use hierarchy hpp list on gtk
tools/perf/ui/browsers/hists.c | 147 +++++++++++++++++++----------------
tools/perf/ui/gtk/hists.c | 73 +++++++++++-------
tools/perf/ui/hist.c | 67 ++++++++++++++++
tools/perf/ui/stdio/hist.c | 171 +++++++++++++++++++++--------------------
tools/perf/util/hist.c | 81 +++++++++++++------
tools/perf/util/hist.h | 12 +++
tools/perf/util/sort.c | 123 ++++++++++++++++++++---------
tools/perf/util/sort.h | 1 +
8 files changed, 438 insertions(+), 237 deletions(-)
--
2.7.1
*** BLURB HERE ***
Namhyung Kim (8):
perf tools: Add level field to struct perf_hpp_fmt
perf tools: Introduce perf_hpp__setup_hists_formats()
perf tools: Use own hpp_list for hierarchy mode
perf tools: Support multiple sort keys in a hierarchy level
perf tools: Fix indent for multiple hierarchy sort key
perf report: Use hierarchy hpp list on stdio
perf hists browser: Use hierarchy hpp list
perf report: Use hierarchy hpp list on gtk
tools/perf/ui/browsers/hists.c | 147 +++++++++++++++++++----------------
tools/perf/ui/gtk/hists.c | 73 +++++++++++-------
tools/perf/ui/hist.c | 66 ++++++++++++++++
tools/perf/ui/stdio/hist.c | 171 +++++++++++++++++++++--------------------
tools/perf/util/hist.c | 81 +++++++++++++------
tools/perf/util/hist.h | 13 ++++
tools/perf/util/sort.c | 146 +++++++++++++++++++++++++----------
tools/perf/util/sort.h | 1 +
8 files changed, 455 insertions(+), 243 deletions(-)
--
2.7.2
[toc] | [next] | [standalone]
| From | Namhyung Kim <namhyung@kernel.org> |
|---|---|
| Date | 2016-03-04 16:10 +0100 |
| Subject | [PATCH v2 1/8] perf tools: Add level field to struct perf_hpp_fmt |
| Message-ID | <r8ZwC-8vJ-31@gated-at.bofh.it> |
| In reply to | #1350275 |
The level field is to distinguish levels in the hierarchy mode.
Currently each column (perf_hpp_fmt) has a different level.
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
---
tools/perf/util/hist.h | 1 +
tools/perf/util/sort.c | 74 ++++++++++++++++++++++++++++----------------------
2 files changed, 42 insertions(+), 33 deletions(-)
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index da5e50586bfd..f4ef513527ba 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -233,6 +233,7 @@ struct perf_hpp_fmt {
int len;
int user_len;
int idx;
+ int level;
};
struct perf_hpp_list {
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 4380a2858802..ab6eb7ca8c60 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -1544,7 +1544,7 @@ static void hse_free(struct perf_hpp_fmt *fmt)
}
static struct hpp_sort_entry *
-__sort_dimension__alloc_hpp(struct sort_dimension *sd)
+__sort_dimension__alloc_hpp(struct sort_dimension *sd, int level)
{
struct hpp_sort_entry *hse;
@@ -1572,6 +1572,7 @@ __sort_dimension__alloc_hpp(struct sort_dimension *sd)
hse->hpp.elide = false;
hse->hpp.len = 0;
hse->hpp.user_len = 0;
+ hse->hpp.level = level;
return hse;
}
@@ -1581,7 +1582,8 @@ static void hpp_free(struct perf_hpp_fmt *fmt)
free(fmt);
}
-static struct perf_hpp_fmt *__hpp_dimension__alloc_hpp(struct hpp_dimension *hd)
+static struct perf_hpp_fmt *__hpp_dimension__alloc_hpp(struct hpp_dimension *hd,
+ int level)
{
struct perf_hpp_fmt *fmt;
@@ -1590,6 +1592,7 @@ static struct perf_hpp_fmt *__hpp_dimension__alloc_hpp(struct hpp_dimension *hd)
INIT_LIST_HEAD(&fmt->list);
INIT_LIST_HEAD(&fmt->sort_list);
fmt->free = hpp_free;
+ fmt->level = level;
}
return fmt;
@@ -1611,9 +1614,9 @@ int hist_entry__filter(struct hist_entry *he, int type, const void *arg)
return hse->se->se_filter(he, type, arg);
}
-static int __sort_dimension__add_hpp_sort(struct sort_dimension *sd)
+static int __sort_dimension__add_hpp_sort(struct sort_dimension *sd, int level)
{
- struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
+ struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd, level);
if (hse == NULL)
return -1;
@@ -1625,7 +1628,7 @@ static int __sort_dimension__add_hpp_sort(struct sort_dimension *sd)
static int __sort_dimension__add_hpp_output(struct perf_hpp_list *list,
struct sort_dimension *sd)
{
- struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
+ struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd, 0);
if (hse == NULL)
return -1;
@@ -1868,7 +1871,8 @@ static void hde_free(struct perf_hpp_fmt *fmt)
}
static struct hpp_dynamic_entry *
-__alloc_dynamic_entry(struct perf_evsel *evsel, struct format_field *field)
+__alloc_dynamic_entry(struct perf_evsel *evsel, struct format_field *field,
+ int level)
{
struct hpp_dynamic_entry *hde;
@@ -1899,6 +1903,7 @@ __alloc_dynamic_entry(struct perf_evsel *evsel, struct format_field *field)
hde->hpp.elide = false;
hde->hpp.len = 0;
hde->hpp.user_len = 0;
+ hde->hpp.level = level;
return hde;
}
@@ -1974,11 +1979,11 @@ static struct perf_evsel *find_evsel(struct perf_evlist *evlist, char *event_nam
static int __dynamic_dimension__add(struct perf_evsel *evsel,
struct format_field *field,
- bool raw_trace)
+ bool raw_trace, int level)
{
struct hpp_dynamic_entry *hde;
- hde = __alloc_dynamic_entry(evsel, field);
+ hde = __alloc_dynamic_entry(evsel, field, level);
if (hde == NULL)
return -ENOMEM;
@@ -1988,14 +1993,14 @@ static int __dynamic_dimension__add(struct perf_evsel *evsel,
return 0;
}
-static int add_evsel_fields(struct perf_evsel *evsel, bool raw_trace)
+static int add_evsel_fields(struct perf_evsel *evsel, bool raw_trace, int level)
{
int ret;
struct format_field *field;
field = evsel->tp_format->format.fields;
while (field) {
- ret = __dynamic_dimension__add(evsel, field, raw_trace);
+ ret = __dynamic_dimension__add(evsel, field, raw_trace, level);
if (ret < 0)
return ret;
@@ -2004,7 +2009,8 @@ static int add_evsel_fields(struct perf_evsel *evsel, bool raw_trace)
return 0;
}
-static int add_all_dynamic_fields(struct perf_evlist *evlist, bool raw_trace)
+static int add_all_dynamic_fields(struct perf_evlist *evlist, bool raw_trace,
+ int level)
{
int ret;
struct perf_evsel *evsel;
@@ -2013,7 +2019,7 @@ static int add_all_dynamic_fields(struct perf_evlist *evlist, bool raw_trace)
if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
continue;
- ret = add_evsel_fields(evsel, raw_trace);
+ ret = add_evsel_fields(evsel, raw_trace, level);
if (ret < 0)
return ret;
}
@@ -2021,7 +2027,7 @@ static int add_all_dynamic_fields(struct perf_evlist *evlist, bool raw_trace)
}
static int add_all_matching_fields(struct perf_evlist *evlist,
- char *field_name, bool raw_trace)
+ char *field_name, bool raw_trace, int level)
{
int ret = -ESRCH;
struct perf_evsel *evsel;
@@ -2035,14 +2041,15 @@ static int add_all_matching_fields(struct perf_evlist *evlist,
if (field == NULL)
continue;
- ret = __dynamic_dimension__add(evsel, field, raw_trace);
+ ret = __dynamic_dimension__add(evsel, field, raw_trace, level);
if (ret < 0)
break;
}
return ret;
}
-static int add_dynamic_entry(struct perf_evlist *evlist, const char *tok)
+static int add_dynamic_entry(struct perf_evlist *evlist, const char *tok,
+ int level)
{
char *str, *event_name, *field_name, *opt_name;
struct perf_evsel *evsel;
@@ -2072,12 +2079,12 @@ static int add_dynamic_entry(struct perf_evlist *evlist, const char *tok)
}
if (!strcmp(field_name, "trace_fields")) {
- ret = add_all_dynamic_fields(evlist, raw_trace);
+ ret = add_all_dynamic_fields(evlist, raw_trace, level);
goto out;
}
if (event_name == NULL) {
- ret = add_all_matching_fields(evlist, field_name, raw_trace);
+ ret = add_all_matching_fields(evlist, field_name, raw_trace, level);
goto out;
}
@@ -2095,7 +2102,7 @@ static int add_dynamic_entry(struct perf_evlist *evlist, const char *tok)
}
if (!strcmp(field_name, "*")) {
- ret = add_evsel_fields(evsel, raw_trace);
+ ret = add_evsel_fields(evsel, raw_trace, level);
} else {
field = pevent_find_any_field(evsel->tp_format, field_name);
if (field == NULL) {
@@ -2104,7 +2111,7 @@ static int add_dynamic_entry(struct perf_evlist *evlist, const char *tok)
return -ENOENT;
}
- ret = __dynamic_dimension__add(evsel, field, raw_trace);
+ ret = __dynamic_dimension__add(evsel, field, raw_trace, level);
}
out:
@@ -2112,12 +2119,12 @@ out:
return ret;
}
-static int __sort_dimension__add(struct sort_dimension *sd)
+static int __sort_dimension__add(struct sort_dimension *sd, int level)
{
if (sd->taken)
return 0;
- if (__sort_dimension__add_hpp_sort(sd) < 0)
+ if (__sort_dimension__add_hpp_sort(sd, level) < 0)
return -1;
if (sd->entry->se_collapse)
@@ -2128,14 +2135,14 @@ static int __sort_dimension__add(struct sort_dimension *sd)
return 0;
}
-static int __hpp_dimension__add(struct hpp_dimension *hd)
+static int __hpp_dimension__add(struct hpp_dimension *hd, int level)
{
struct perf_hpp_fmt *fmt;
if (hd->taken)
return 0;
- fmt = __hpp_dimension__alloc_hpp(hd);
+ fmt = __hpp_dimension__alloc_hpp(hd, level);
if (!fmt)
return -1;
@@ -2165,7 +2172,7 @@ static int __hpp_dimension__add_output(struct perf_hpp_list *list,
if (hd->taken)
return 0;
- fmt = __hpp_dimension__alloc_hpp(hd);
+ fmt = __hpp_dimension__alloc_hpp(hd, 0);
if (!fmt)
return -1;
@@ -2180,8 +2187,8 @@ int hpp_dimension__add_output(unsigned col)
return __hpp_dimension__add_output(&perf_hpp_list, &hpp_sort_dimensions[col]);
}
-static int sort_dimension__add(const char *tok,
- struct perf_evlist *evlist __maybe_unused)
+static int sort_dimension__add(const char *tok, struct perf_evlist *evlist,
+ int level)
{
unsigned int i;
@@ -2220,7 +2227,7 @@ static int sort_dimension__add(const char *tok,
sort__has_thread = 1;
}
- return __sort_dimension__add(sd);
+ return __sort_dimension__add(sd, level);
}
for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
@@ -2229,7 +2236,7 @@ static int sort_dimension__add(const char *tok,
if (strncasecmp(tok, hd->name, strlen(tok)))
continue;
- return __hpp_dimension__add(hd);
+ return __hpp_dimension__add(hd, level);
}
for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
@@ -2244,7 +2251,7 @@ static int sort_dimension__add(const char *tok,
if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
sort__has_sym = 1;
- __sort_dimension__add(sd);
+ __sort_dimension__add(sd, level);
return 0;
}
@@ -2260,11 +2267,11 @@ static int sort_dimension__add(const char *tok,
if (sd->entry == &sort_mem_daddr_sym)
sort__has_sym = 1;
- __sort_dimension__add(sd);
+ __sort_dimension__add(sd, level);
return 0;
}
- if (!add_dynamic_entry(evlist, tok))
+ if (!add_dynamic_entry(evlist, tok, level))
return 0;
return -ESRCH;
@@ -2274,10 +2281,11 @@ static int setup_sort_list(char *str, struct perf_evlist *evlist)
{
char *tmp, *tok;
int ret = 0;
+ int level = 0;
for (tok = strtok_r(str, ", ", &tmp);
tok; tok = strtok_r(NULL, ", ", &tmp)) {
- ret = sort_dimension__add(tok, evlist);
+ ret = sort_dimension__add(tok, evlist, level++);
if (ret == -EINVAL) {
error("Invalid --sort key: `%s'", tok);
break;
@@ -2667,7 +2675,7 @@ int setup_sorting(struct perf_evlist *evlist)
return err;
if (parent_pattern != default_parent_pattern) {
- err = sort_dimension__add("parent", evlist);
+ err = sort_dimension__add("parent", evlist, -1);
if (err < 0)
return err;
}
--
2.7.2
[toc] | [prev] | [next] | [standalone]
| From | tip-bot for Namhyung Kim <tipbot@zytor.com> |
|---|---|
| Date | 2016-03-08 11:40 +0100 |
| Subject | [tip:perf/core] perf hists: Add level field to struct perf_hpp_fmt |
| Message-ID | <randw-84x-25@gated-at.bofh.it> |
| In reply to | #1350279 |
Commit-ID: 4b633eba14627bcb1ef5c7a498e7dc308cd6a5d6
Gitweb: http://git.kernel.org/tip/4b633eba14627bcb1ef5c7a498e7dc308cd6a5d6
Author: Namhyung Kim <namhyung@kernel.org>
AuthorDate: Mon, 7 Mar 2016 16:44:43 -0300
Committer: Ingo Molnar <mingo@kernel.org>
CommitDate: Tue, 8 Mar 2016 10:11:18 +0100
perf hists: Add level field to struct perf_hpp_fmt
The level field is to distinguish levels in the hierarchy mode.
Currently each column (perf_hpp_fmt) has a different level.
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Wang Nan <wangnan0@huawei.com>
Link: http://lkml.kernel.org/r/1457103582-28396-2-git-send-email-namhyung@kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
---
tools/perf/util/hist.h | 1 +
tools/perf/util/sort.c | 74 ++++++++++++++++++++++++++++----------------------
2 files changed, 42 insertions(+), 33 deletions(-)
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index da5e505..f4ef513 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -233,6 +233,7 @@ struct perf_hpp_fmt {
int len;
int user_len;
int idx;
+ int level;
};
struct perf_hpp_list {
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 4380a28..ab6eb7c 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -1544,7 +1544,7 @@ static void hse_free(struct perf_hpp_fmt *fmt)
}
static struct hpp_sort_entry *
-__sort_dimension__alloc_hpp(struct sort_dimension *sd)
+__sort_dimension__alloc_hpp(struct sort_dimension *sd, int level)
{
struct hpp_sort_entry *hse;
@@ -1572,6 +1572,7 @@ __sort_dimension__alloc_hpp(struct sort_dimension *sd)
hse->hpp.elide = false;
hse->hpp.len = 0;
hse->hpp.user_len = 0;
+ hse->hpp.level = level;
return hse;
}
@@ -1581,7 +1582,8 @@ static void hpp_free(struct perf_hpp_fmt *fmt)
free(fmt);
}
-static struct perf_hpp_fmt *__hpp_dimension__alloc_hpp(struct hpp_dimension *hd)
+static struct perf_hpp_fmt *__hpp_dimension__alloc_hpp(struct hpp_dimension *hd,
+ int level)
{
struct perf_hpp_fmt *fmt;
@@ -1590,6 +1592,7 @@ static struct perf_hpp_fmt *__hpp_dimension__alloc_hpp(struct hpp_dimension *hd)
INIT_LIST_HEAD(&fmt->list);
INIT_LIST_HEAD(&fmt->sort_list);
fmt->free = hpp_free;
+ fmt->level = level;
}
return fmt;
@@ -1611,9 +1614,9 @@ int hist_entry__filter(struct hist_entry *he, int type, const void *arg)
return hse->se->se_filter(he, type, arg);
}
-static int __sort_dimension__add_hpp_sort(struct sort_dimension *sd)
+static int __sort_dimension__add_hpp_sort(struct sort_dimension *sd, int level)
{
- struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
+ struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd, level);
if (hse == NULL)
return -1;
@@ -1625,7 +1628,7 @@ static int __sort_dimension__add_hpp_sort(struct sort_dimension *sd)
static int __sort_dimension__add_hpp_output(struct perf_hpp_list *list,
struct sort_dimension *sd)
{
- struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
+ struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd, 0);
if (hse == NULL)
return -1;
@@ -1868,7 +1871,8 @@ static void hde_free(struct perf_hpp_fmt *fmt)
}
static struct hpp_dynamic_entry *
-__alloc_dynamic_entry(struct perf_evsel *evsel, struct format_field *field)
+__alloc_dynamic_entry(struct perf_evsel *evsel, struct format_field *field,
+ int level)
{
struct hpp_dynamic_entry *hde;
@@ -1899,6 +1903,7 @@ __alloc_dynamic_entry(struct perf_evsel *evsel, struct format_field *field)
hde->hpp.elide = false;
hde->hpp.len = 0;
hde->hpp.user_len = 0;
+ hde->hpp.level = level;
return hde;
}
@@ -1974,11 +1979,11 @@ static struct perf_evsel *find_evsel(struct perf_evlist *evlist, char *event_nam
static int __dynamic_dimension__add(struct perf_evsel *evsel,
struct format_field *field,
- bool raw_trace)
+ bool raw_trace, int level)
{
struct hpp_dynamic_entry *hde;
- hde = __alloc_dynamic_entry(evsel, field);
+ hde = __alloc_dynamic_entry(evsel, field, level);
if (hde == NULL)
return -ENOMEM;
@@ -1988,14 +1993,14 @@ static int __dynamic_dimension__add(struct perf_evsel *evsel,
return 0;
}
-static int add_evsel_fields(struct perf_evsel *evsel, bool raw_trace)
+static int add_evsel_fields(struct perf_evsel *evsel, bool raw_trace, int level)
{
int ret;
struct format_field *field;
field = evsel->tp_format->format.fields;
while (field) {
- ret = __dynamic_dimension__add(evsel, field, raw_trace);
+ ret = __dynamic_dimension__add(evsel, field, raw_trace, level);
if (ret < 0)
return ret;
@@ -2004,7 +2009,8 @@ static int add_evsel_fields(struct perf_evsel *evsel, bool raw_trace)
return 0;
}
-static int add_all_dynamic_fields(struct perf_evlist *evlist, bool raw_trace)
+static int add_all_dynamic_fields(struct perf_evlist *evlist, bool raw_trace,
+ int level)
{
int ret;
struct perf_evsel *evsel;
@@ -2013,7 +2019,7 @@ static int add_all_dynamic_fields(struct perf_evlist *evlist, bool raw_trace)
if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
continue;
- ret = add_evsel_fields(evsel, raw_trace);
+ ret = add_evsel_fields(evsel, raw_trace, level);
if (ret < 0)
return ret;
}
@@ -2021,7 +2027,7 @@ static int add_all_dynamic_fields(struct perf_evlist *evlist, bool raw_trace)
}
static int add_all_matching_fields(struct perf_evlist *evlist,
- char *field_name, bool raw_trace)
+ char *field_name, bool raw_trace, int level)
{
int ret = -ESRCH;
struct perf_evsel *evsel;
@@ -2035,14 +2041,15 @@ static int add_all_matching_fields(struct perf_evlist *evlist,
if (field == NULL)
continue;
- ret = __dynamic_dimension__add(evsel, field, raw_trace);
+ ret = __dynamic_dimension__add(evsel, field, raw_trace, level);
if (ret < 0)
break;
}
return ret;
}
-static int add_dynamic_entry(struct perf_evlist *evlist, const char *tok)
+static int add_dynamic_entry(struct perf_evlist *evlist, const char *tok,
+ int level)
{
char *str, *event_name, *field_name, *opt_name;
struct perf_evsel *evsel;
@@ -2072,12 +2079,12 @@ static int add_dynamic_entry(struct perf_evlist *evlist, const char *tok)
}
if (!strcmp(field_name, "trace_fields")) {
- ret = add_all_dynamic_fields(evlist, raw_trace);
+ ret = add_all_dynamic_fields(evlist, raw_trace, level);
goto out;
}
if (event_name == NULL) {
- ret = add_all_matching_fields(evlist, field_name, raw_trace);
+ ret = add_all_matching_fields(evlist, field_name, raw_trace, level);
goto out;
}
@@ -2095,7 +2102,7 @@ static int add_dynamic_entry(struct perf_evlist *evlist, const char *tok)
}
if (!strcmp(field_name, "*")) {
- ret = add_evsel_fields(evsel, raw_trace);
+ ret = add_evsel_fields(evsel, raw_trace, level);
} else {
field = pevent_find_any_field(evsel->tp_format, field_name);
if (field == NULL) {
@@ -2104,7 +2111,7 @@ static int add_dynamic_entry(struct perf_evlist *evlist, const char *tok)
return -ENOENT;
}
- ret = __dynamic_dimension__add(evsel, field, raw_trace);
+ ret = __dynamic_dimension__add(evsel, field, raw_trace, level);
}
out:
@@ -2112,12 +2119,12 @@ out:
return ret;
}
-static int __sort_dimension__add(struct sort_dimension *sd)
+static int __sort_dimension__add(struct sort_dimension *sd, int level)
{
if (sd->taken)
return 0;
- if (__sort_dimension__add_hpp_sort(sd) < 0)
+ if (__sort_dimension__add_hpp_sort(sd, level) < 0)
return -1;
if (sd->entry->se_collapse)
@@ -2128,14 +2135,14 @@ static int __sort_dimension__add(struct sort_dimension *sd)
return 0;
}
-static int __hpp_dimension__add(struct hpp_dimension *hd)
+static int __hpp_dimension__add(struct hpp_dimension *hd, int level)
{
struct perf_hpp_fmt *fmt;
if (hd->taken)
return 0;
- fmt = __hpp_dimension__alloc_hpp(hd);
+ fmt = __hpp_dimension__alloc_hpp(hd, level);
if (!fmt)
return -1;
@@ -2165,7 +2172,7 @@ static int __hpp_dimension__add_output(struct perf_hpp_list *list,
if (hd->taken)
return 0;
- fmt = __hpp_dimension__alloc_hpp(hd);
+ fmt = __hpp_dimension__alloc_hpp(hd, 0);
if (!fmt)
return -1;
@@ -2180,8 +2187,8 @@ int hpp_dimension__add_output(unsigned col)
return __hpp_dimension__add_output(&perf_hpp_list, &hpp_sort_dimensions[col]);
}
-static int sort_dimension__add(const char *tok,
- struct perf_evlist *evlist __maybe_unused)
+static int sort_dimension__add(const char *tok, struct perf_evlist *evlist,
+ int level)
{
unsigned int i;
@@ -2220,7 +2227,7 @@ static int sort_dimension__add(const char *tok,
sort__has_thread = 1;
}
- return __sort_dimension__add(sd);
+ return __sort_dimension__add(sd, level);
}
for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
@@ -2229,7 +2236,7 @@ static int sort_dimension__add(const char *tok,
if (strncasecmp(tok, hd->name, strlen(tok)))
continue;
- return __hpp_dimension__add(hd);
+ return __hpp_dimension__add(hd, level);
}
for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
@@ -2244,7 +2251,7 @@ static int sort_dimension__add(const char *tok,
if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
sort__has_sym = 1;
- __sort_dimension__add(sd);
+ __sort_dimension__add(sd, level);
return 0;
}
@@ -2260,11 +2267,11 @@ static int sort_dimension__add(const char *tok,
if (sd->entry == &sort_mem_daddr_sym)
sort__has_sym = 1;
- __sort_dimension__add(sd);
+ __sort_dimension__add(sd, level);
return 0;
}
- if (!add_dynamic_entry(evlist, tok))
+ if (!add_dynamic_entry(evlist, tok, level))
return 0;
return -ESRCH;
@@ -2274,10 +2281,11 @@ static int setup_sort_list(char *str, struct perf_evlist *evlist)
{
char *tmp, *tok;
int ret = 0;
+ int level = 0;
for (tok = strtok_r(str, ", ", &tmp);
tok; tok = strtok_r(NULL, ", ", &tmp)) {
- ret = sort_dimension__add(tok, evlist);
+ ret = sort_dimension__add(tok, evlist, level++);
if (ret == -EINVAL) {
error("Invalid --sort key: `%s'", tok);
break;
@@ -2667,7 +2675,7 @@ int setup_sorting(struct perf_evlist *evlist)
return err;
if (parent_pattern != default_parent_pattern) {
- err = sort_dimension__add("parent", evlist);
+ err = sort_dimension__add("parent", evlist, -1);
if (err < 0)
return err;
}
[toc] | [prev] | [next] | [standalone]
| From | Namhyung Kim <namhyung@kernel.org> |
|---|---|
| Date | 2016-03-04 16:10 +0100 |
| Subject | [PATCH v2 7/8] perf hists browser: Use hierarchy hpp list |
| Message-ID | <r8ZwC-8vJ-37@gated-at.bofh.it> |
| In reply to | #1350275 |
Now hpp formats are linked using perf_hpp_list_node when hierarchy is
enabled. Like in stdio, use this info to print entries with multiple
sort keys in a single hierarchy properly.
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
---
tools/perf/ui/browsers/hists.c | 81 +++++++++++++++++++++++-------------------
1 file changed, 45 insertions(+), 36 deletions(-)
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index 2f02ce79bd9d..e0e217ec856b 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -1289,6 +1289,7 @@ static int hist_browser__show_hierarchy_entry(struct hist_browser *browser,
off_t row_offset = entry->row_offset;
bool first = true;
struct perf_hpp_fmt *fmt;
+ struct perf_hpp_list_node *fmt_node;
struct hpp_arg arg = {
.b = &browser->b,
.current_entry = current_entry,
@@ -1320,7 +1321,10 @@ static int hist_browser__show_hierarchy_entry(struct hist_browser *browser,
ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
width -= level * HIERARCHY_INDENT;
- hists__for_each_format(entry->hists, fmt) {
+ /* the first hpp_list_node is for overhead columns */
+ fmt_node = list_first_entry(&entry->hists->hpp_formats,
+ struct perf_hpp_list_node, list);
+ perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
char s[2048];
struct perf_hpp hpp = {
.buf = s,
@@ -1332,10 +1336,6 @@ static int hist_browser__show_hierarchy_entry(struct hist_browser *browser,
column++ < browser->b.horiz_scroll)
continue;
- if (perf_hpp__is_sort_entry(fmt) ||
- perf_hpp__is_dynamic_entry(fmt))
- break;
-
if (current_entry && browser->b.navkeypressed) {
ui_browser__set_color(&browser->b,
HE_COLORSET_SELECTED);
@@ -1444,6 +1444,7 @@ static int hist_browser__show_no_entry(struct hist_browser *browser,
int column = 0;
int ret;
struct perf_hpp_fmt *fmt;
+ struct perf_hpp_list_node *fmt_node;
int indent = browser->hists->nr_hpp_node - 2;
if (current_entry) {
@@ -1461,15 +1462,14 @@ static int hist_browser__show_no_entry(struct hist_browser *browser,
ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
width -= level * HIERARCHY_INDENT;
- hists__for_each_format(browser->hists, fmt) {
+ /* the first hpp_list_node is for overhead columns */
+ fmt_node = list_first_entry(&browser->hists->hpp_formats,
+ struct perf_hpp_list_node, list);
+ perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
if (perf_hpp__should_skip(fmt, browser->hists) ||
column++ < browser->b.horiz_scroll)
continue;
- if (perf_hpp__is_sort_entry(fmt) ||
- perf_hpp__is_dynamic_entry(fmt))
- break;
-
ret = fmt->width(fmt, NULL, hists_to_evsel(browser->hists));
if (first) {
@@ -1551,22 +1551,23 @@ static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *brows
.size = size,
};
struct perf_hpp_fmt *fmt;
+ struct perf_hpp_list_node *fmt_node;
size_t ret = 0;
int column = 0;
int indent = hists->nr_hpp_node - 2;
- bool first = true;
+ bool first_node, first_col;
ret = scnprintf(buf, size, " ");
if (advance_hpp_check(&dummy_hpp, ret))
return ret;
- hists__for_each_format(hists, fmt) {
+ /* the first hpp_list_node is for overhead columns */
+ fmt_node = list_first_entry(&hists->hpp_formats,
+ struct perf_hpp_list_node, list);
+ perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
if (column++ < browser->b.horiz_scroll)
continue;
- if (perf_hpp__is_sort_entry(fmt) || perf_hpp__is_dynamic_entry(fmt))
- break;
-
ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
if (advance_hpp_check(&dummy_hpp, ret))
break;
@@ -1581,34 +1582,42 @@ static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *brows
if (advance_hpp_check(&dummy_hpp, ret))
return ret;
- hists__for_each_format(hists, fmt) {
- char *start;
-
- if (!perf_hpp__is_sort_entry(fmt) && !perf_hpp__is_dynamic_entry(fmt))
- continue;
- if (perf_hpp__should_skip(fmt, hists))
- continue;
-
- if (first) {
- first = false;
- } else {
+ first_node = true;
+ list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {
+ if (!first_node) {
ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " / ");
if (advance_hpp_check(&dummy_hpp, ret))
break;
}
+ first_node = false;
- ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
- dummy_hpp.buf[ret] = '\0';
- rtrim(dummy_hpp.buf);
+ first_col = true;
+ perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
+ char *start;
- start = ltrim(dummy_hpp.buf);
- ret = strlen(start);
+ if (perf_hpp__should_skip(fmt, hists))
+ continue;
- if (start != dummy_hpp.buf)
- memmove(dummy_hpp.buf, start, ret + 1);
+ if (!first_col) {
+ ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "+");
+ if (advance_hpp_check(&dummy_hpp, ret))
+ break;
+ }
+ first_col = false;
- if (advance_hpp_check(&dummy_hpp, ret))
- break;
+ ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
+ dummy_hpp.buf[ret] = '\0';
+ rtrim(dummy_hpp.buf);
+
+ start = ltrim(dummy_hpp.buf);
+ ret = strlen(start);
+
+ if (start != dummy_hpp.buf)
+ memmove(dummy_hpp.buf, start, ret + 1);
+
+ if (advance_hpp_check(&dummy_hpp, ret))
+ break;
+ }
}
return ret;
@@ -1676,7 +1685,7 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser)
break;
if (h->has_no_entry) {
- hist_browser__show_no_entry(hb, row, h->depth);
+ hist_browser__show_no_entry(hb, row, h->depth + 1);
row++;
}
} else {
--
2.7.2
[toc] | [prev] | [next] | [standalone]
| From | Namhyung Kim <namhyung@kernel.org> |
|---|---|
| Date | 2016-03-04 16:10 +0100 |
| Subject | [PATCH v2 5/8] perf tools: Fix indent for multiple hierarchy sort key |
| Message-ID | <r8ZwD-8vJ-49@gated-at.bofh.it> |
| In reply to | #1350275 |
When multiple sort keys are used in a single hierarchy, it should indent
using number of hierarchy levels instead of number of sort keys.
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
---
tools/perf/ui/browsers/hists.c | 23 ++++++++++-------------
tools/perf/ui/hist.c | 1 +
tools/perf/ui/stdio/hist.c | 26 +++++++++++---------------
tools/perf/util/hist.h | 1 +
4 files changed, 23 insertions(+), 28 deletions(-)
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index 928b4825b752..2f02ce79bd9d 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -1280,7 +1280,7 @@ static int hist_browser__show_entry(struct hist_browser *browser,
static int hist_browser__show_hierarchy_entry(struct hist_browser *browser,
struct hist_entry *entry,
unsigned short row,
- int level, int nr_sort_keys)
+ int level)
{
int printed = 0;
int width = browser->b.width;
@@ -1294,7 +1294,7 @@ static int hist_browser__show_hierarchy_entry(struct hist_browser *browser,
.current_entry = current_entry,
};
int column = 0;
- int hierarchy_indent = (nr_sort_keys - 1) * HIERARCHY_INDENT;
+ int hierarchy_indent = (entry->hists->nr_hpp_node - 2) * HIERARCHY_INDENT;
if (current_entry) {
browser->he_selection = entry;
@@ -1436,8 +1436,7 @@ show_callchain:
}
static int hist_browser__show_no_entry(struct hist_browser *browser,
- unsigned short row,
- int level, int nr_sort_keys)
+ unsigned short row, int level)
{
int width = browser->b.width;
bool current_entry = ui_browser__is_current_entry(&browser->b, row);
@@ -1445,6 +1444,7 @@ static int hist_browser__show_no_entry(struct hist_browser *browser,
int column = 0;
int ret;
struct perf_hpp_fmt *fmt;
+ int indent = browser->hists->nr_hpp_node - 2;
if (current_entry) {
browser->he_selection = NULL;
@@ -1485,8 +1485,8 @@ static int hist_browser__show_no_entry(struct hist_browser *browser,
width -= ret;
}
- ui_browser__write_nstring(&browser->b, "", nr_sort_keys * HIERARCHY_INDENT);
- width -= nr_sort_keys * HIERARCHY_INDENT;
+ ui_browser__write_nstring(&browser->b, "", indent * HIERARCHY_INDENT);
+ width -= indent * HIERARCHY_INDENT;
if (column >= browser->b.horiz_scroll) {
char buf[32];
@@ -1553,7 +1553,7 @@ static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *brows
struct perf_hpp_fmt *fmt;
size_t ret = 0;
int column = 0;
- int nr_sort_keys = hists->nr_sort_keys;
+ int indent = hists->nr_hpp_node - 2;
bool first = true;
ret = scnprintf(buf, size, " ");
@@ -1577,7 +1577,7 @@ static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *brows
}
ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "%*s",
- (nr_sort_keys - 1) * HIERARCHY_INDENT, "");
+ indent * HIERARCHY_INDENT, "");
if (advance_hpp_check(&dummy_hpp, ret))
return ret;
@@ -1645,7 +1645,6 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser)
u16 header_offset = 0;
struct rb_node *nd;
struct hist_browser *hb = container_of(browser, struct hist_browser, b);
- int nr_sort = hb->hists->nr_sort_keys;
if (hb->show_headers) {
hist_browser__show_headers(hb);
@@ -1672,14 +1671,12 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser)
if (symbol_conf.report_hierarchy) {
row += hist_browser__show_hierarchy_entry(hb, h, row,
- h->depth,
- nr_sort);
+ h->depth);
if (row == browser->rows)
break;
if (h->has_no_entry) {
- hist_browser__show_no_entry(hb, row, h->depth,
- nr_sort);
+ hist_browser__show_no_entry(hb, row, h->depth);
row++;
}
} else {
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
index 2958658d98e7..82c052870a74 100644
--- a/tools/perf/ui/hist.c
+++ b/tools/perf/ui/hist.c
@@ -740,6 +740,7 @@ static int add_hierarchy_fmt(struct hists *hists, struct perf_hpp_fmt *fmt)
INIT_LIST_HEAD(&node->hpp.fields);
INIT_LIST_HEAD(&node->hpp.sorts);
+ hists->nr_hpp_node++;
list_add_tail(&node->list, &hists->hpp_formats);
}
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
index 073642a63cc9..543d7137cc0c 100644
--- a/tools/perf/ui/stdio/hist.c
+++ b/tools/perf/ui/stdio/hist.c
@@ -412,7 +412,7 @@ static int hist_entry__snprintf(struct hist_entry *he, struct perf_hpp *hpp)
static int hist_entry__hierarchy_fprintf(struct hist_entry *he,
struct perf_hpp *hpp,
- int nr_sort_key, struct hists *hists,
+ struct hists *hists,
FILE *fp)
{
const char *sep = symbol_conf.field_sep;
@@ -453,7 +453,7 @@ static int hist_entry__hierarchy_fprintf(struct hist_entry *he,
if (!sep)
ret = scnprintf(hpp->buf, hpp->size, "%*s",
- (nr_sort_key - 1) * HIERARCHY_INDENT, "");
+ (hists->nr_hpp_node - 2) * HIERARCHY_INDENT, "");
advance_hpp(hpp, ret);
printed += fprintf(fp, "%s", buf);
@@ -504,12 +504,8 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size,
if (size == 0 || size > bfsz)
size = hpp.size = bfsz;
- if (symbol_conf.report_hierarchy) {
- int nr_sort = hists->nr_sort_keys;
-
- return hist_entry__hierarchy_fprintf(he, &hpp, nr_sort,
- hists, fp);
- }
+ if (symbol_conf.report_hierarchy)
+ return hist_entry__hierarchy_fprintf(he, &hpp, hists, fp);
hist_entry__snprintf(he, &hpp);
@@ -521,29 +517,29 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size,
return ret;
}
-static int print_hierarchy_indent(const char *sep, int nr_sort,
+static int print_hierarchy_indent(const char *sep, int indent,
const char *line, FILE *fp)
{
- if (sep != NULL || nr_sort < 1)
+ if (sep != NULL || indent < 2)
return 0;
- return fprintf(fp, "%-.*s", (nr_sort - 1) * HIERARCHY_INDENT, line);
+ return fprintf(fp, "%-.*s", (indent - 2) * HIERARCHY_INDENT, line);
}
static int print_hierarchy_header(struct hists *hists, struct perf_hpp *hpp,
const char *sep, FILE *fp)
{
bool first = true;
- int nr_sort;
+ int indent;
int depth;
unsigned width = 0;
unsigned header_width = 0;
struct perf_hpp_fmt *fmt;
- nr_sort = hists->nr_sort_keys;
+ indent = hists->nr_hpp_node;
/* preserve max indent depth for column headers */
- print_hierarchy_indent(sep, nr_sort, spaces, fp);
+ print_hierarchy_indent(sep, indent, spaces, fp);
hists__for_each_format(hists, fmt) {
if (perf_hpp__is_sort_entry(fmt) || perf_hpp__is_dynamic_entry(fmt))
@@ -582,7 +578,7 @@ static int print_hierarchy_header(struct hists *hists, struct perf_hpp *hpp,
fprintf(fp, "\n# ");
/* preserve max indent depth for initial dots */
- print_hierarchy_indent(sep, nr_sort, dots, fp);
+ print_hierarchy_indent(sep, indent, dots, fp);
first = true;
hists__for_each_format(hists, fmt) {
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 3cab9dc20822..71fd0cf161fb 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -80,6 +80,7 @@ struct hists {
struct perf_hpp_list *hpp_list;
struct list_head hpp_formats;
int nr_sort_keys;
+ int nr_hpp_node;
};
struct hist_entry_iter;
--
2.7.2
[toc] | [prev] | [next] | [standalone]
| From | Namhyung Kim <namhyung@kernel.org> |
|---|---|
| Date | 2016-03-04 16:10 +0100 |
| Subject | [PATCH v2 2/8] perf tools: Introduce perf_hpp__setup_hists_formats() |
| Message-ID | <r8ZwD-8vJ-51@gated-at.bofh.it> |
| In reply to | #1350275 |
The perf_hpp__setup_hists_formats() is to build hists-specific output
formats (and sort keys). Currently it's only used in order to build the
output format in a hierarchy with same sort keys, but it could be used
with different sort keys in non-hierarchy mode later.
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
---
tools/perf/ui/hist.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++
tools/perf/util/hist.c | 12 ++++++++++
tools/perf/util/hist.h | 11 +++++++++
tools/perf/util/sort.c | 32 +++++++++++++++++++++++++
4 files changed, 120 insertions(+)
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
index 7c0585c146e1..2958658d98e7 100644
--- a/tools/perf/ui/hist.c
+++ b/tools/perf/ui/hist.c
@@ -5,6 +5,7 @@
#include "../util/util.h"
#include "../util/sort.h"
#include "../util/evsel.h"
+#include "../util/evlist.h"
/* hist period print (hpp) functions */
@@ -715,3 +716,67 @@ void perf_hpp__set_user_width(const char *width_list_str)
break;
}
}
+
+static int add_hierarchy_fmt(struct hists *hists, struct perf_hpp_fmt *fmt)
+{
+ struct perf_hpp_list_node *node = NULL;
+ struct perf_hpp_fmt *fmt_copy;
+ bool found = false;
+
+ list_for_each_entry(node, &hists->hpp_formats, list) {
+ if (node->level == fmt->level) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ node = malloc(sizeof(*node));
+ if (node == NULL)
+ return -1;
+
+ node->level = fmt->level;
+
+ INIT_LIST_HEAD(&node->hpp.fields);
+ INIT_LIST_HEAD(&node->hpp.sorts);
+
+ list_add_tail(&node->list, &hists->hpp_formats);
+ }
+
+ fmt_copy = perf_hpp_fmt__dup(fmt);
+ if (fmt_copy == NULL)
+ return -1;
+
+ list_add_tail(&fmt_copy->list, &node->hpp.fields);
+ list_add_tail(&fmt_copy->sort_list, &node->hpp.sorts);
+
+ return 0;
+}
+
+int perf_hpp__setup_hists_formats(struct perf_hpp_list *list,
+ struct perf_evlist *evlist)
+{
+ struct perf_evsel *evsel;
+ struct perf_hpp_fmt *fmt;
+ struct hists *hists;
+ int ret;
+
+ if (!symbol_conf.report_hierarchy)
+ return 0;
+
+ evlist__for_each(evlist, evsel) {
+ hists = evsel__hists(evsel);
+
+ perf_hpp_list__for_each_sort_list(list, fmt) {
+ if (perf_hpp__is_dynamic_entry(fmt) &&
+ !perf_hpp__defined_dynamic_entry(fmt, hists))
+ continue;
+
+ ret = add_hierarchy_fmt(hists, fmt);
+ if (ret < 0)
+ return ret;
+ }
+ }
+
+ return 0;
+}
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 4b8b67bc0cd8..83e98f420fe7 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -2105,6 +2105,7 @@ int __hists__init(struct hists *hists, struct perf_hpp_list *hpp_list)
pthread_mutex_init(&hists->lock, NULL);
hists->socket_filter = -1;
hists->hpp_list = hpp_list;
+ INIT_LIST_HEAD(&hists->hpp_formats);
return 0;
}
@@ -2133,8 +2134,19 @@ static void hists__delete_all_entries(struct hists *hists)
static void hists_evsel__exit(struct perf_evsel *evsel)
{
struct hists *hists = evsel__hists(evsel);
+ struct perf_hpp_fmt *fmt, *pos;
+ struct perf_hpp_list_node *node;
hists__delete_all_entries(hists);
+
+ list_for_each_entry(node, &hists->hpp_formats, list) {
+ perf_hpp_list__for_each_format_safe(&node->hpp, fmt, pos) {
+ list_del(&fmt->list);
+ free(fmt);
+ }
+ list_del(&node->list);
+ free(node);
+ }
}
static int hists_evsel__init(struct perf_evsel *evsel)
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index f4ef513527ba..3cab9dc20822 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -78,6 +78,7 @@ struct hists {
u16 col_len[HISTC_NR_COLS];
int socket_filter;
struct perf_hpp_list *hpp_list;
+ struct list_head hpp_formats;
int nr_sort_keys;
};
@@ -244,6 +245,12 @@ struct perf_hpp_list {
extern struct perf_hpp_list perf_hpp_list;
+struct perf_hpp_list_node {
+ struct list_head list;
+ struct perf_hpp_list hpp;
+ int level;
+};
+
void perf_hpp_list__column_register(struct perf_hpp_list *list,
struct perf_hpp_fmt *format);
void perf_hpp_list__register_sort_field(struct perf_hpp_list *list,
@@ -299,6 +306,8 @@ void perf_hpp__cancel_cumulate(void);
void perf_hpp__setup_output_field(struct perf_hpp_list *list);
void perf_hpp__reset_output_field(struct perf_hpp_list *list);
void perf_hpp__append_sort_keys(struct perf_hpp_list *list);
+int perf_hpp__setup_hists_formats(struct perf_hpp_list *list,
+ struct perf_evlist *evlist);
bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format);
@@ -308,6 +317,8 @@ bool perf_hpp__is_trace_entry(struct perf_hpp_fmt *fmt);
bool perf_hpp__is_srcline_entry(struct perf_hpp_fmt *fmt);
bool perf_hpp__is_srcfile_entry(struct perf_hpp_fmt *fmt);
+struct perf_hpp_fmt *perf_hpp_fmt__dup(struct perf_hpp_fmt *fmt);
+
int hist_entry__filter(struct hist_entry *he, int type, const void *arg);
static inline bool perf_hpp__should_skip(struct perf_hpp_fmt *format,
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index ab6eb7ca8c60..71d45d147376 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -1908,6 +1908,34 @@ __alloc_dynamic_entry(struct perf_evsel *evsel, struct format_field *field,
return hde;
}
+struct perf_hpp_fmt *perf_hpp_fmt__dup(struct perf_hpp_fmt *fmt)
+{
+ struct perf_hpp_fmt *new_fmt = NULL;
+
+ if (perf_hpp__is_sort_entry(fmt)) {
+ struct hpp_sort_entry *hse, *new_hse;
+
+ hse = container_of(fmt, struct hpp_sort_entry, hpp);
+ new_hse = memdup(hse, sizeof(*hse));
+ if (new_hse)
+ new_fmt = &new_hse->hpp;
+ } else if (perf_hpp__is_dynamic_entry(fmt)) {
+ struct hpp_dynamic_entry *hde, *new_hde;
+
+ hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
+ new_hde = memdup(hde, sizeof(*hde));
+ if (new_hde)
+ new_fmt = &new_hde->hpp;
+ } else {
+ new_fmt = memdup(fmt, sizeof(*fmt));
+ }
+
+ INIT_LIST_HEAD(&new_fmt->list);
+ INIT_LIST_HEAD(&new_fmt->sort_list);
+
+ return new_fmt;
+}
+
static int parse_field_name(char *str, char **event, char **field, char **opt)
{
char *event_name, *field_name, *opt_name;
@@ -2700,6 +2728,10 @@ int setup_sorting(struct perf_evlist *evlist)
/* and then copy output fields to sort keys */
perf_hpp__append_sort_keys(&perf_hpp_list);
+ /* setup hists-specific output fields */
+ if (perf_hpp__setup_hists_formats(&perf_hpp_list, evlist) < 0)
+ return -1;
+
return 0;
}
--
2.7.2
[toc] | [prev] | [next] | [standalone]
| From | Arnaldo Carvalho de Melo <acme@kernel.org> |
|---|---|
| Date | 2016-03-04 23:00 +0100 |
| Subject | Re: [PATCH v2 2/8] perf tools: Introduce perf_hpp__setup_hists_formats() |
| Message-ID | <r95Vo-4KG-15@gated-at.bofh.it> |
| In reply to | #1350290 |
Em Fri, Mar 04, 2016 at 11:59:36PM +0900, Namhyung Kim escreveu:
> The perf_hpp__setup_hists_formats() is to build hists-specific output
> formats (and sort keys). Currently it's only used in order to build the
> output format in a hierarchy with same sort keys, but it could be used
> with different sort keys in non-hierarchy mode later.
After applying this one:
[root@jouet ~]# perf top --hierarchy # press 'q' to exit and get this:
perf: Segmentation fault
-------- backtrace --------
perf[0x54b60b]
/lib64/libc.so.6(+0x34b20)[0x7fb7e06e9b20]
perf[0x4e9780]
perf(perf_evsel__delete+0x20)[0x498450]
perf(perf_evlist__delete+0x182)[0x48fbe2]
perf(cmd_top+0xc93)[0x440893]
perf[0x481c01]
perf(main+0x67a)[0x423dea]
/lib64/libc.so.6(__libc_start_main+0xf0)[0x7fb7e06d5580]
perf(_start+0x29)[0x423f09]
[0x0]
[root@jouet ~]#
rebuild it with DEBUG=1, run it on gdb, press 'q' to exit 'perf top':
(gdb) run top --stdio --hierarchy
Program received signal SIGSEGV, Segmentation fault.
0x000000000051632b in hists_evsel__exit (evsel=0x19b95b0) at util/hist.c:2143
2143 perf_hpp_list__for_each_format_safe(&node->hpp, fmt, pos) {
Missing separate debuginfos, use: dnf debuginfo-install bzip2-libs-1.0.6-19.fc23.x86_64 glibc-2.22-10.fc23.x86_64 libunwind-1.1-10.fc23.x86_64 nss-softokn-freebl-3.22.0-1.0.fc23.x86_64 numactl-libs-2.0.10-3.fc23.x86_64 perl-libs-5.22.1-350.fc23.x86_64 python-libs-2.7.10-8.fc23.x86_64 slang-2.3.0-4.fc23.x86_64
(gdb) bt
#0 0x000000000051632b in hists_evsel__exit (evsel=0x19b95b0) at util/hist.c:2143
#1 0x00000000004b5a2c in perf_evsel__exit (evsel=0x19b95b0) at util/evsel.c:1094
#2 0x00000000004b5a6a in perf_evsel__delete (evsel=0x19b95b0) at util/evsel.c:1099
#3 0x00000000004adf5d in perf_evlist__purge (evlist=0x19b8b90) at util/evlist.c:115
#4 0x00000000004ae090 in perf_evlist__delete (evlist=0x19b8b90) at util/evlist.c:135
#5 0x0000000000446547 in cmd_top (argc=0, argv=0x7fffffffe310, prefix=0x0) at builtin-top.c:1346
#6 0x000000000049e614 in run_builtin (p=0x90f5e0 <commands+288>, argc=3, argv=0x7fffffffe310) at perf.c:390
#7 0x000000000049e87c in handle_internal_command (argc=3, argv=0x7fffffffe310) at perf.c:451
#8 0x000000000049e9c1 in run_argv (argcp=0x7fffffffe16c, argv=0x7fffffffe160) at perf.c:497
#9 0x000000000049ed67 in main (argc=3, argv=0x7fffffffe310) at perf.c:624
(gdb)
[toc] | [prev] | [next] | [standalone]
| From | Arnaldo Carvalho de Melo <acme@kernel.org> |
|---|---|
| Date | 2016-03-04 23:00 +0100 |
| Subject | Re: [PATCH v2 2/8] perf tools: Introduce perf_hpp__setup_hists_formats() |
| Message-ID | <r95Vo-4KG-19@gated-at.bofh.it> |
| In reply to | #1350633 |
Em Fri, Mar 04, 2016 at 06:58:22PM -0300, Arnaldo Carvalho de Melo escreveu:
> Em Fri, Mar 04, 2016 at 11:59:36PM +0900, Namhyung Kim escreveu:
> > The perf_hpp__setup_hists_formats() is to build hists-specific output
> > formats (and sort keys). Currently it's only used in order to build the
> > output format in a hierarchy with same sort keys, but it could be used
> > with different sort keys in non-hierarchy mode later.
>
> After applying this one:
> rebuild it with DEBUG=1, run it on gdb, press 'q' to exit 'perf top':
> (gdb) run top --stdio --hierarchy
> Program received signal SIGSEGV, Segmentation fault.
> 0x000000000051632b in hists_evsel__exit (evsel=0x19b95b0) at util/hist.c:2143
> 2143 perf_hpp_list__for_each_format_safe(&node->hpp, fmt, pos) {
> Missing separate debuginfos, use: dnf debuginfo-install bzip2-libs-1.0.6-19.fc23.x86_64 glibc-2.22-10.fc23.x86_64 libunwind-1.1-10.fc23.x86_64 nss-softokn-freebl-3.22.0-1.0.fc23.x86_64 numactl-libs-2.0.10-3.fc23.x86_64 perl-libs-5.22.1-350.fc23.x86_64 python-libs-2.7.10-8.fc23.x86_64 slang-2.3.0-4.fc23.x86_64
Please continue from acme/perf/core, the first patch is there already.
Thanks,
- Arnaldo
[toc] | [prev] | [next] | [standalone]
| From | Namhyung Kim <namhyung@kernel.org> |
|---|---|
| Date | 2016-03-07 13:50 +0100 |
| Subject | Re: [PATCH v2 2/8] perf tools: Introduce perf_hpp__setup_hists_formats() |
| Message-ID | <ra2LN-2Ud-13@gated-at.bofh.it> |
| In reply to | #1350634 |
On Fri, Mar 04, 2016 at 06:59:23PM -0300, Arnaldo Carvalho de Melo wrote:
> Em Fri, Mar 04, 2016 at 06:58:22PM -0300, Arnaldo Carvalho de Melo escreveu:
> > Em Fri, Mar 04, 2016 at 11:59:36PM +0900, Namhyung Kim escreveu:
> > > The perf_hpp__setup_hists_formats() is to build hists-specific output
> > > formats (and sort keys). Currently it's only used in order to build the
> > > output format in a hierarchy with same sort keys, but it could be used
> > > with different sort keys in non-hierarchy mode later.
> >
> > After applying this one:
>
> > rebuild it with DEBUG=1, run it on gdb, press 'q' to exit 'perf top':
>
> > (gdb) run top --stdio --hierarchy
> > Program received signal SIGSEGV, Segmentation fault.
> > 0x000000000051632b in hists_evsel__exit (evsel=0x19b95b0) at util/hist.c:2143
> > 2143 perf_hpp_list__for_each_format_safe(&node->hpp, fmt, pos) {
> > Missing separate debuginfos, use: dnf debuginfo-install bzip2-libs-1.0.6-19.fc23.x86_64 glibc-2.22-10.fc23.x86_64 libunwind-1.1-10.fc23.x86_64 nss-softokn-freebl-3.22.0-1.0.fc23.x86_64 numactl-libs-2.0.10-3.fc23.x86_64 perl-libs-5.22.1-350.fc23.x86_64 python-libs-2.7.10-8.fc23.x86_64 slang-2.3.0-4.fc23.x86_64
>
> Please continue from acme/perf/core, the first patch is there already.
OK, I'll take a look at the problem.
Thanks,
Namhyung
[toc] | [prev] | [next] | [standalone]
| From | Namhyung Kim <namhyung@kernel.org> |
|---|---|
| Date | 2016-03-07 15:00 +0100 |
| Subject | Re: [PATCH v2 2/8] perf tools: Introduce perf_hpp__setup_hists_formats() |
| Message-ID | <ra3Rv-3xE-1@gated-at.bofh.it> |
| In reply to | #1350633 |
On Fri, Mar 04, 2016 at 06:58:22PM -0300, Arnaldo Carvalho de Melo wrote:
> Em Fri, Mar 04, 2016 at 11:59:36PM +0900, Namhyung Kim escreveu:
> > The perf_hpp__setup_hists_formats() is to build hists-specific output
> > formats (and sort keys). Currently it's only used in order to build the
> > output format in a hierarchy with same sort keys, but it could be used
> > with different sort keys in non-hierarchy mode later.
>
> After applying this one:
>
> [root@jouet ~]# perf top --hierarchy # press 'q' to exit and get this:
> perf: Segmentation fault
> -------- backtrace --------
> perf[0x54b60b]
> /lib64/libc.so.6(+0x34b20)[0x7fb7e06e9b20]
> perf[0x4e9780]
> perf(perf_evsel__delete+0x20)[0x498450]
> perf(perf_evlist__delete+0x182)[0x48fbe2]
> perf(cmd_top+0xc93)[0x440893]
> perf[0x481c01]
> perf(main+0x67a)[0x423dea]
> /lib64/libc.so.6(__libc_start_main+0xf0)[0x7fb7e06d5580]
> perf(_start+0x29)[0x423f09]
> [0x0]
> [root@jouet ~]#
>
> rebuild it with DEBUG=1, run it on gdb, press 'q' to exit 'perf top':
>
> (gdb) run top --stdio --hierarchy
> Program received signal SIGSEGV, Segmentation fault.
> 0x000000000051632b in hists_evsel__exit (evsel=0x19b95b0) at util/hist.c:2143
> 2143 perf_hpp_list__for_each_format_safe(&node->hpp, fmt, pos) {
> Missing separate debuginfos, use: dnf debuginfo-install bzip2-libs-1.0.6-19.fc23.x86_64 glibc-2.22-10.fc23.x86_64 libunwind-1.1-10.fc23.x86_64 nss-softokn-freebl-3.22.0-1.0.fc23.x86_64 numactl-libs-2.0.10-3.fc23.x86_64 perl-libs-5.22.1-350.fc23.x86_64 python-libs-2.7.10-8.fc23.x86_64 slang-2.3.0-4.fc23.x86_64
> (gdb) bt
> #0 0x000000000051632b in hists_evsel__exit (evsel=0x19b95b0) at util/hist.c:2143
> #1 0x00000000004b5a2c in perf_evsel__exit (evsel=0x19b95b0) at util/evsel.c:1094
> #2 0x00000000004b5a6a in perf_evsel__delete (evsel=0x19b95b0) at util/evsel.c:1099
> #3 0x00000000004adf5d in perf_evlist__purge (evlist=0x19b8b90) at util/evlist.c:115
> #4 0x00000000004ae090 in perf_evlist__delete (evlist=0x19b8b90) at util/evlist.c:135
> #5 0x0000000000446547 in cmd_top (argc=0, argv=0x7fffffffe310, prefix=0x0) at builtin-top.c:1346
> #6 0x000000000049e614 in run_builtin (p=0x90f5e0 <commands+288>, argc=3, argv=0x7fffffffe310) at perf.c:390
> #7 0x000000000049e87c in handle_internal_command (argc=3, argv=0x7fffffffe310) at perf.c:451
> #8 0x000000000049e9c1 in run_argv (argcp=0x7fffffffe16c, argv=0x7fffffffe160) at perf.c:497
> #9 0x000000000049ed67 in main (argc=3, argv=0x7fffffffe310) at perf.c:624
> (gdb)
Nah, it was silly of me to use list_for_each_entry() for deletion..
Will send a fix soon.
Thanks,
Namhyung
[toc] | [prev] | [next] | [standalone]
| From | Jiri Olsa <jolsa@redhat.com> |
|---|---|
| Date | 2016-03-06 19:50 +0100 |
| Subject | Re: [PATCH v2 2/8] perf tools: Introduce perf_hpp__setup_hists_formats() |
| Message-ID | <r9LUC-oi-11@gated-at.bofh.it> |
| In reply to | #1350290 |
On Fri, Mar 04, 2016 at 11:59:36PM +0900, Namhyung Kim wrote:
SNIP
>
> @@ -2133,8 +2134,19 @@ static void hists__delete_all_entries(struct hists *hists)
> static void hists_evsel__exit(struct perf_evsel *evsel)
> {
> struct hists *hists = evsel__hists(evsel);
> + struct perf_hpp_fmt *fmt, *pos;
> + struct perf_hpp_list_node *node;
>
> hists__delete_all_entries(hists);
> +
> + list_for_each_entry(node, &hists->hpp_formats, list) {
> + perf_hpp_list__for_each_format_safe(&node->hpp, fmt, pos) {
> + list_del(&fmt->list);
> + free(fmt);
> + }
> + list_del(&node->list);
> + free(node);
> + }
> }
>
> static int hists_evsel__init(struct perf_evsel *evsel)
> diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
> index f4ef513527ba..3cab9dc20822 100644
> --- a/tools/perf/util/hist.h
> +++ b/tools/perf/util/hist.h
> @@ -78,6 +78,7 @@ struct hists {
> u16 col_len[HISTC_NR_COLS];
> int socket_filter;
> struct perf_hpp_list *hpp_list;
> + struct list_head hpp_formats;
I've been thinking.. should hpp_formats and hpp_list be merged? something like:
struct perf_hpp_list {
struct list_head nodes;
int levels;
}
sturct perf_hpp_list_node {
int level;
struct list_head fields;
struct list_head sorts;
int nr_sort_keys;
};
it seems wrong to me that your hierarchy code and current one
got in separate paths.. we could have the new hierarchy support
struct above being used in current non-hierarchy code just
by using single level
I haven't thought all this through.. just an idea ;-)
thanks,
jirka
[toc] | [prev] | [next] | [standalone]
| From | Namhyung Kim <namhyung@kernel.org> |
|---|---|
| Date | 2016-03-07 14:10 +0100 |
| Subject | Re: [PATCH v2 2/8] perf tools: Introduce perf_hpp__setup_hists_formats() |
| Message-ID | <ra358-3fU-13@gated-at.bofh.it> |
| In reply to | #1351168 |
On Sun, Mar 06, 2016 at 07:43:25PM +0100, Jiri Olsa wrote:
> On Fri, Mar 04, 2016 at 11:59:36PM +0900, Namhyung Kim wrote:
>
> SNIP
>
> >
> > @@ -2133,8 +2134,19 @@ static void hists__delete_all_entries(struct hists *hists)
> > static void hists_evsel__exit(struct perf_evsel *evsel)
> > {
> > struct hists *hists = evsel__hists(evsel);
> > + struct perf_hpp_fmt *fmt, *pos;
> > + struct perf_hpp_list_node *node;
> >
> > hists__delete_all_entries(hists);
> > +
> > + list_for_each_entry(node, &hists->hpp_formats, list) {
> > + perf_hpp_list__for_each_format_safe(&node->hpp, fmt, pos) {
> > + list_del(&fmt->list);
> > + free(fmt);
> > + }
> > + list_del(&node->list);
> > + free(node);
> > + }
> > }
> >
> > static int hists_evsel__init(struct perf_evsel *evsel)
> > diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
> > index f4ef513527ba..3cab9dc20822 100644
> > --- a/tools/perf/util/hist.h
> > +++ b/tools/perf/util/hist.h
> > @@ -78,6 +78,7 @@ struct hists {
> > u16 col_len[HISTC_NR_COLS];
> > int socket_filter;
> > struct perf_hpp_list *hpp_list;
> > + struct list_head hpp_formats;
>
> I've been thinking.. should hpp_formats and hpp_list be merged? something like:
>
> struct perf_hpp_list {
> struct list_head nodes;
> int levels;
> }
>
> sturct perf_hpp_list_node {
> int level;
> struct list_head fields;
> struct list_head sorts;
> int nr_sort_keys;
> };
>
> it seems wrong to me that your hierarchy code and current one
> got in separate paths.. we could have the new hierarchy support
> struct above being used in current non-hierarchy code just
> by using single level
>
> I haven't thought all this through.. just an idea ;-)
Yes, I also think that we need to converge on the same data structure
eventually. But I think it's too intrusive to be merged at once.
Also keeping up with the latest perf changes is a PITA. ;-)
So I decided to use it on the hierarchy first, and get tested in the
wild for some time. After that we can convert the non-hierarchy code
to use same path and data structure gradually IMHO.
Thanks,
Namhyung
[toc] | [prev] | [next] | [standalone]
| From | Jiri Olsa <jolsa@redhat.com> |
|---|---|
| Date | 2016-03-07 14:20 +0100 |
| Subject | Re: [PATCH v2 2/8] perf tools: Introduce perf_hpp__setup_hists_formats() |
| Message-ID | <ra3eP-3jo-11@gated-at.bofh.it> |
| In reply to | #1351595 |
On Mon, Mar 07, 2016 at 09:59:34PM +0900, Namhyung Kim wrote:
> On Sun, Mar 06, 2016 at 07:43:25PM +0100, Jiri Olsa wrote:
> > On Fri, Mar 04, 2016 at 11:59:36PM +0900, Namhyung Kim wrote:
> >
> > SNIP
> >
> > >
> > > @@ -2133,8 +2134,19 @@ static void hists__delete_all_entries(struct hists *hists)
> > > static void hists_evsel__exit(struct perf_evsel *evsel)
> > > {
> > > struct hists *hists = evsel__hists(evsel);
> > > + struct perf_hpp_fmt *fmt, *pos;
> > > + struct perf_hpp_list_node *node;
> > >
> > > hists__delete_all_entries(hists);
> > > +
> > > + list_for_each_entry(node, &hists->hpp_formats, list) {
> > > + perf_hpp_list__for_each_format_safe(&node->hpp, fmt, pos) {
> > > + list_del(&fmt->list);
> > > + free(fmt);
> > > + }
> > > + list_del(&node->list);
> > > + free(node);
> > > + }
> > > }
> > >
> > > static int hists_evsel__init(struct perf_evsel *evsel)
> > > diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
> > > index f4ef513527ba..3cab9dc20822 100644
> > > --- a/tools/perf/util/hist.h
> > > +++ b/tools/perf/util/hist.h
> > > @@ -78,6 +78,7 @@ struct hists {
> > > u16 col_len[HISTC_NR_COLS];
> > > int socket_filter;
> > > struct perf_hpp_list *hpp_list;
> > > + struct list_head hpp_formats;
> >
> > I've been thinking.. should hpp_formats and hpp_list be merged? something like:
> >
> > struct perf_hpp_list {
> > struct list_head nodes;
> > int levels;
> > }
> >
> > sturct perf_hpp_list_node {
> > int level;
> > struct list_head fields;
> > struct list_head sorts;
> > int nr_sort_keys;
> > };
> >
> > it seems wrong to me that your hierarchy code and current one
> > got in separate paths.. we could have the new hierarchy support
> > struct above being used in current non-hierarchy code just
> > by using single level
> >
> > I haven't thought all this through.. just an idea ;-)
>
> Yes, I also think that we need to converge on the same data structure
> eventually. But I think it's too intrusive to be merged at once.
> Also keeping up with the latest perf changes is a PITA. ;-)
heh, amen ;-)
>
> So I decided to use it on the hierarchy first, and get tested in the
> wild for some time. After that we can convert the non-hierarchy code
> to use same path and data structure gradually IMHO.
ok, let's keep it in mind at least..
thanks.
jirka
[toc] | [prev] | [next] | [standalone]
| From | Namhyung Kim <namhyung@kernel.org> |
|---|---|
| Date | 2016-03-04 16:10 +0100 |
| Subject | [PATCH v2 8/8] perf report: Use hierarchy hpp list on gtk |
| Message-ID | <r8ZwD-8vJ-63@gated-at.bofh.it> |
| In reply to | #1350275 |
Now hpp formats are linked using perf_hpp_list_node when hierarchy is
enabled. Like in stdio, use this info to print entries with multiple
sort keys in a single hierarchy properly.
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
---
tools/perf/ui/gtk/hists.c | 55 ++++++++++++++++++++++++++++-------------------
1 file changed, 33 insertions(+), 22 deletions(-)
diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c
index 4534e2d7669c..bd9bf7e343b1 100644
--- a/tools/perf/ui/gtk/hists.c
+++ b/tools/perf/ui/gtk/hists.c
@@ -407,7 +407,9 @@ static void perf_gtk__add_hierarchy_entries(struct hists *hists,
struct rb_node *node;
struct hist_entry *he;
struct perf_hpp_fmt *fmt;
+ struct perf_hpp_list_node *fmt_node;
u64 total = hists__total_period(hists);
+ int size;
for (node = rb_first(root); node; node = rb_next(node)) {
GtkTreeIter iter;
@@ -425,11 +427,11 @@ static void perf_gtk__add_hierarchy_entries(struct hists *hists,
gtk_tree_store_append(store, &iter, parent);
col_idx = 0;
- hists__for_each_format(hists, fmt) {
- if (perf_hpp__is_sort_entry(fmt) ||
- perf_hpp__is_dynamic_entry(fmt))
- break;
+ /* the first hpp_list_node is for overhead columns */
+ fmt_node = list_first_entry(&hists->hpp_formats,
+ struct perf_hpp_list_node, list);
+ perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
if (fmt->color)
fmt->color(fmt, hpp, he);
else
@@ -439,6 +441,7 @@ static void perf_gtk__add_hierarchy_entries(struct hists *hists,
}
bf = hpp->buf;
+ size = hpp->size;
perf_hpp_list__for_each_format(he->hpp_list, fmt) {
int ret;
@@ -451,9 +454,12 @@ static void perf_gtk__add_hierarchy_entries(struct hists *hists,
advance_hpp(hpp, ret + 2);
}
- gtk_tree_store_set(store, &iter, col_idx, rtrim(bf), -1);
+ gtk_tree_store_set(store, &iter, col_idx, ltrim(rtrim(bf)), -1);
if (!he->leaf) {
+ hpp->buf = bf;
+ hpp->size = size;
+
perf_gtk__add_hierarchy_entries(hists, &he->hroot_out,
store, &iter, hpp,
min_pcnt);
@@ -486,6 +492,7 @@ static void perf_gtk__show_hierarchy(GtkWidget *window, struct hists *hists,
float min_pcnt)
{
struct perf_hpp_fmt *fmt;
+ struct perf_hpp_list_node *fmt_node;
GType col_types[MAX_COLUMNS];
GtkCellRenderer *renderer;
GtkTreeStore *store;
@@ -494,7 +501,7 @@ static void perf_gtk__show_hierarchy(GtkWidget *window, struct hists *hists,
int nr_cols = 0;
char s[512];
char buf[512];
- bool first = true;
+ bool first_node, first_col;
struct perf_hpp hpp = {
.buf = s,
.size = sizeof(s),
@@ -514,11 +521,11 @@ static void perf_gtk__show_hierarchy(GtkWidget *window, struct hists *hists,
renderer = gtk_cell_renderer_text_new();
col_idx = 0;
- hists__for_each_format(hists, fmt) {
- if (perf_hpp__is_sort_entry(fmt) ||
- perf_hpp__is_dynamic_entry(fmt))
- break;
+ /* the first hpp_list_node is for overhead columns */
+ fmt_node = list_first_entry(&hists->hpp_formats,
+ struct perf_hpp_list_node, list);
+ perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
-1, fmt->name,
renderer, "markup",
@@ -527,20 +534,24 @@ static void perf_gtk__show_hierarchy(GtkWidget *window, struct hists *hists,
/* construct merged column header since sort keys share single column */
buf[0] = '\0';
- hists__for_each_format(hists ,fmt) {
- if (!perf_hpp__is_sort_entry(fmt) &&
- !perf_hpp__is_dynamic_entry(fmt))
- continue;
- if (perf_hpp__should_skip(fmt, hists))
- continue;
-
- if (first)
- first = false;
- else
+ first_node = true;
+ list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {
+ if (!first_node)
strcat(buf, " / ");
+ first_node = false;
- fmt->header(fmt, &hpp, hists_to_evsel(hists));
- strcat(buf, rtrim(hpp.buf));
+ first_col = true;
+ perf_hpp_list__for_each_format(&fmt_node->hpp ,fmt) {
+ if (perf_hpp__should_skip(fmt, hists))
+ continue;
+
+ if (!first_col)
+ strcat(buf, "+");
+ first_col = false;
+
+ fmt->header(fmt, &hpp, hists_to_evsel(hists));
+ strcat(buf, ltrim(rtrim(hpp.buf)));
+ }
}
gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
--
2.7.2
[toc] | [prev] | [next] | [standalone]
| From | Namhyung Kim <namhyung@kernel.org> |
|---|---|
| Date | 2016-03-04 16:10 +0100 |
| Subject | [PATCH v2 4/8] perf tools: Support multiple sort keys in a hierarchy level |
| Message-ID | <r8ZwE-8vJ-71@gated-at.bofh.it> |
| In reply to | #1350275 |
This implements having multiple sort keys in a single hierarchy level.
Originally only single sort key is supported for each level, but now
using the group syntax with '{ }', it can set more than one sort key in
one level. Note that now it needs to quote in order to prevent shell
interpretation.
For example:
$ perf report --hierarchy -s '{comm,dso},sym'
...
# Overhead Command / Shared Object / Symbol
# .............. ..........................................
#
48.67% swapper [kernel.vmlinux]
34.42% [k] intel_idle
1.30% [k] __tick_nohz_idle_enter
1.03% [k] cpuidle_reflect
8.87% firefox libpthread-2.22.so
6.60% [.] __GI___libc_recvmsg
1.18% [.] pthread_cond_signal@@GLIBC_2.3.2
1.09% [.] 0x000000000000ff4b
6.11% Xorg libc-2.22.so
5.27% [.] __memcpy_sse2_unaligned
In the above example, the command name and the shared object name are
shown on the same line but the symbol name is on the different line.
Since the first two are grouped by '{}', they are in the same level.
Suggested-by: Arnaldo Carvalho de Melo <acme@kernel.org>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
---
tools/perf/util/sort.c | 42 ++++++++++++++++++++++++++++++++----------
1 file changed, 32 insertions(+), 10 deletions(-)
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 71d45d147376..041f236379e0 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -2310,18 +2310,40 @@ static int setup_sort_list(char *str, struct perf_evlist *evlist)
char *tmp, *tok;
int ret = 0;
int level = 0;
+ int next_level = 1;
+ bool in_group = false;
+
+ do {
+ tok = str;
+ tmp = strpbrk(str, "{}, ");
+ if (tmp) {
+ if (in_group)
+ next_level = level;
+ else
+ next_level = level + 1;
+
+ if (*tmp == '{')
+ in_group = true;
+ else if (*tmp == '}')
+ in_group = false;
+
+ *tmp = '\0';
+ str = tmp + 1;
+ }
- for (tok = strtok_r(str, ", ", &tmp);
- tok; tok = strtok_r(NULL, ", ", &tmp)) {
- ret = sort_dimension__add(tok, evlist, level++);
- if (ret == -EINVAL) {
- error("Invalid --sort key: `%s'", tok);
- break;
- } else if (ret == -ESRCH) {
- error("Unknown --sort key: `%s'", tok);
- break;
+ if (*tok) {
+ ret = sort_dimension__add(tok, evlist, level);
+ if (ret == -EINVAL) {
+ error("Invalid --sort key: `%s'", tok);
+ break;
+ } else if (ret == -ESRCH) {
+ error("Unknown --sort key: `%s'", tok);
+ break;
+ }
}
- }
+
+ level = next_level;
+ } while (tmp);
return ret;
}
--
2.7.2
[toc] | [prev] | [next] | [standalone]
| From | Arnaldo Carvalho de Melo <acme@kernel.org> |
|---|---|
| Date | 2016-03-04 22:50 +0100 |
| Subject | Re: [PATCH v2 4/8] perf tools: Support multiple sort keys in a hierarchy level |
| Message-ID | <r95LI-4GI-11@gated-at.bofh.it> |
| In reply to | #1350299 |
Em Fri, Mar 04, 2016 at 11:59:38PM +0900, Namhyung Kim escreveu:
> This implements having multiple sort keys in a single hierarchy level.
> +++ b/tools/perf/util/sort.c
> @@ -2310,18 +2310,40 @@ static int setup_sort_list(char *str, struct perf_evlist *evlist)
> char *tmp, *tok;
> int ret = 0;
> int level = 0;
> + int next_level = 1;
> + bool in_group = false;
> +
> + do {
> + tok = str;
> + tmp = strpbrk(str, "{}, ");
Ok, I'll test this, but since we use lex/yacc for parsing event
descriptions, perhaps we should use it here as well? Or do you think
we're stopping at this level of complexity (I doubt) :-)
> + if (tmp) {
> + if (in_group)
> + next_level = level;
> + else
> + next_level = level + 1;
> +
> + if (*tmp == '{')
> + in_group = true;
> + else if (*tmp == '}')
> + in_group = false;
> +
> + *tmp = '\0';
> + str = tmp + 1;
> + }
>
> - for (tok = strtok_r(str, ", ", &tmp);
> - tok; tok = strtok_r(NULL, ", ", &tmp)) {
> - ret = sort_dimension__add(tok, evlist, level++);
> - if (ret == -EINVAL) {
> - error("Invalid --sort key: `%s'", tok);
> - break;
> - } else if (ret == -ESRCH) {
> - error("Unknown --sort key: `%s'", tok);
> - break;
> + if (*tok) {
> + ret = sort_dimension__add(tok, evlist, level);
> + if (ret == -EINVAL) {
> + error("Invalid --sort key: `%s'", tok);
> + break;
> + } else if (ret == -ESRCH) {
> + error("Unknown --sort key: `%s'", tok);
> + break;
> + }
> }
> - }
> +
> + level = next_level;
> + } while (tmp);
>
> return ret;
> }
> --
> 2.7.2
[toc] | [prev] | [next] | [standalone]
| From | Namhyung Kim <namhyung@kernel.org> |
|---|---|
| Date | 2016-03-07 13:50 +0100 |
| Subject | Re: [PATCH v2 4/8] perf tools: Support multiple sort keys in a hierarchy level |
| Message-ID | <ra2LM-2Ud-1@gated-at.bofh.it> |
| In reply to | #1350624 |
Hi Arnaldo,
On Fri, Mar 04, 2016 at 06:48:48PM -0300, Arnaldo Carvalho de Melo wrote:
> Em Fri, Mar 04, 2016 at 11:59:38PM +0900, Namhyung Kim escreveu:
> > This implements having multiple sort keys in a single hierarchy level.
>
> > +++ b/tools/perf/util/sort.c
> > @@ -2310,18 +2310,40 @@ static int setup_sort_list(char *str, struct perf_evlist *evlist)
> > char *tmp, *tok;
> > int ret = 0;
> > int level = 0;
> > + int next_level = 1;
> > + bool in_group = false;
> > +
> > + do {
> > + tok = str;
> > + tmp = strpbrk(str, "{}, ");
>
> Ok, I'll test this, but since we use lex/yacc for parsing event
> descriptions, perhaps we should use it here as well? Or do you think
> we're stopping at this level of complexity (I doubt) :-)
I'm not sure how the syntax of sort keys will become more complex.
But I don't think we should use lex/yacc at this level of complexity
Thanks,
Namhyung
>
> > + if (tmp) {
> > + if (in_group)
> > + next_level = level;
> > + else
> > + next_level = level + 1;
> > +
> > + if (*tmp == '{')
> > + in_group = true;
> > + else if (*tmp == '}')
> > + in_group = false;
> > +
> > + *tmp = '\0';
> > + str = tmp + 1;
> > + }
> >
> > - for (tok = strtok_r(str, ", ", &tmp);
> > - tok; tok = strtok_r(NULL, ", ", &tmp)) {
> > - ret = sort_dimension__add(tok, evlist, level++);
> > - if (ret == -EINVAL) {
> > - error("Invalid --sort key: `%s'", tok);
> > - break;
> > - } else if (ret == -ESRCH) {
> > - error("Unknown --sort key: `%s'", tok);
> > - break;
> > + if (*tok) {
> > + ret = sort_dimension__add(tok, evlist, level);
> > + if (ret == -EINVAL) {
> > + error("Invalid --sort key: `%s'", tok);
> > + break;
> > + } else if (ret == -ESRCH) {
> > + error("Unknown --sort key: `%s'", tok);
> > + break;
> > + }
> > }
> > - }
> > +
> > + level = next_level;
> > + } while (tmp);
> >
> > return ret;
> > }
> > --
> > 2.7.2
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web