aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@redhat.com>2011-03-05 19:40:06 -0500
committerArnaldo Carvalho de Melo <acme@redhat.com>2011-03-06 11:13:40 -0500
commite248de331a452f8771eda6ed4bb30d92c82df28b (patch)
tree7ef04743a7bf7a1da354a3b82536ef32504823d9 /tools/perf/util
parent3d3b5e95997208067c963923db90ed1517565d14 (diff)
perf tools: Improve support for sessions with multiple events
By creating an perf_evlist out of the attributes in the perf.data file header, so that we can use evlists and evsels when reading recorded sessions in addition to when we record sessions. More work is needed to allow tools to allow the user to select which events are wanted when browsing sessions, be it just one or a subset of them, aggregated or showed at the same time but with different indications on the UI to allow seeing workloads thru different views at the same time. But the overall goal/trend is to more uniformly use evsels and evlists. Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Mike Galbraith <efault@gmx.de> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephane Eranian <eranian@google.com> Cc: Tom Zanussi <tzanussi@gmail.com> LKML-Reference: <new-submission> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/util')
-rw-r--r--tools/perf/util/evsel.h2
-rw-r--r--tools/perf/util/header.c31
-rw-r--r--tools/perf/util/header.h2
-rw-r--r--tools/perf/util/hist.c6
-rw-r--r--tools/perf/util/hist.h12
-rw-r--r--tools/perf/util/session.c63
-rw-r--r--tools/perf/util/session.h16
-rw-r--r--tools/perf/util/ui/browsers/hists.c32
8 files changed, 98 insertions, 66 deletions
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index f6fc8f651a25..281b60e5fc7b 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -7,6 +7,7 @@
7#include "types.h" 7#include "types.h"
8#include "xyarray.h" 8#include "xyarray.h"
9#include "cgroup.h" 9#include "cgroup.h"
10#include "hist.h"
10 11
11struct perf_counts_values { 12struct perf_counts_values {
12 union { 13 union {
@@ -51,6 +52,7 @@ struct perf_evsel {
51 struct xyarray *id; 52 struct xyarray *id;
52 struct perf_counts *counts; 53 struct perf_counts *counts;
53 int idx; 54 int idx;
55 struct hists hists;
54 char *name; 56 char *name;
55 void *priv; 57 void *priv;
56 struct cgroup_sel *cgrp; 58 struct cgroup_sel *cgrp;
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 72c124dc5781..108b0db7bbef 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -969,37 +969,6 @@ bool perf_header__sample_id_all(const struct perf_header *header)
969 return value; 969 return value;
970} 970}
971 971
972struct perf_event_attr *
973perf_header__find_attr(u64 id, struct perf_header *header)
974{
975 int i;
976
977 /*
978 * We set id to -1 if the data file doesn't contain sample
979 * ids. This can happen when the data file contains one type
980 * of event and in that case, the header can still store the
981 * event attribute information. Check for this and avoid
982 * walking through the entire list of ids which may be large.
983 */
984 if (id == -1ULL) {
985 if (header->attrs > 0)
986 return &header->attr[0]->attr;
987 return NULL;
988 }
989
990 for (i = 0; i < header->attrs; i++) {
991 struct perf_header_attr *attr = header->attr[i];
992 int j;
993
994 for (j = 0; j < attr->ids; j++) {
995 if (attr->id[j] == id)
996 return &attr->attr;
997 }
998 }
999
1000 return NULL;
1001}
1002
1003int perf_event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id, 972int perf_event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id,
1004 perf_event__handler_t process, 973 perf_event__handler_t process,
1005 struct perf_session *session) 974 struct perf_session *session)
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index f042cebcec1e..2fab13348aab 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -85,8 +85,6 @@ int perf_header_attr__add_id(struct perf_header_attr *self, u64 id);
85 85
86u64 perf_header__sample_type(struct perf_header *header); 86u64 perf_header__sample_type(struct perf_header *header);
87bool perf_header__sample_id_all(const struct perf_header *header); 87bool perf_header__sample_id_all(const struct perf_header *header);
88struct perf_event_attr *
89perf_header__find_attr(u64 id, struct perf_header *header);
90void perf_header__set_feat(struct perf_header *self, int feat); 88void perf_header__set_feat(struct perf_header *self, int feat);
91void perf_header__clear_feat(struct perf_header *self, int feat); 89void perf_header__clear_feat(struct perf_header *self, int feat);
92bool perf_header__has_feat(const struct perf_header *self, int feat); 90bool perf_header__has_feat(const struct perf_header *self, int feat);
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index f7ad6bdbc667..627a02e03c57 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -984,8 +984,12 @@ size_t hists__fprintf_nr_events(struct hists *self, FILE *fp)
984 size_t ret = 0; 984 size_t ret = 0;
985 985
986 for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) { 986 for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) {
987 const char *name = perf_event__name(i); 987 const char *name;
988 988
989 if (self->stats.nr_events[i] == 0)
990 continue;
991
992 name = perf_event__name(i);
989 if (!strcmp(name, "UNKNOWN")) 993 if (!strcmp(name, "UNKNOWN"))
990 continue; 994 continue;
991 995
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 37c79089de09..0d38b435827b 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -42,13 +42,10 @@ enum hist_column {
42}; 42};
43 43
44struct hists { 44struct hists {
45 struct rb_node rb_node;
46 struct rb_root entries; 45 struct rb_root entries;
47 u64 nr_entries; 46 u64 nr_entries;
48 struct events_stats stats; 47 struct events_stats stats;
49 u64 config;
50 u64 event_stream; 48 u64 event_stream;
51 u32 type;
52 u16 col_len[HISTC_NR_COLS]; 49 u16 col_len[HISTC_NR_COLS];
53 /* Best would be to reuse the session callchain cursor */ 50 /* Best would be to reuse the session callchain cursor */
54 struct callchain_cursor callchain_cursor; 51 struct callchain_cursor callchain_cursor;
@@ -87,6 +84,8 @@ u16 hists__col_len(struct hists *self, enum hist_column col);
87void hists__set_col_len(struct hists *self, enum hist_column col, u16 len); 84void hists__set_col_len(struct hists *self, enum hist_column col, u16 len);
88bool hists__new_col_len(struct hists *self, enum hist_column col, u16 len); 85bool hists__new_col_len(struct hists *self, enum hist_column col, u16 len);
89 86
87struct perf_evlist;
88
90#ifdef NO_NEWT_SUPPORT 89#ifdef NO_NEWT_SUPPORT
91static inline int hists__browse(struct hists *self __used, 90static inline int hists__browse(struct hists *self __used,
92 const char *helpline __used, 91 const char *helpline __used,
@@ -95,9 +94,8 @@ static inline int hists__browse(struct hists *self __used,
95 return 0; 94 return 0;
96} 95}
97 96
98static inline int hists__tui_browse_tree(struct rb_root *self __used, 97static inline int hists__tui_browse_tree(struct perf_evlist *evlist __used,
99 const char *help __used, 98 const char *help __used)
100 int evidx __used)
101{ 99{
102 return 0; 100 return 0;
103} 101}
@@ -118,7 +116,7 @@ int hist_entry__tui_annotate(struct hist_entry *self, int evidx);
118#define KEY_LEFT NEWT_KEY_LEFT 116#define KEY_LEFT NEWT_KEY_LEFT
119#define KEY_RIGHT NEWT_KEY_RIGHT 117#define KEY_RIGHT NEWT_KEY_RIGHT
120 118
121int hists__tui_browse_tree(struct rb_root *self, const char *help, int evidx); 119int hists__tui_browse_tree(struct perf_evlist *evlist, const char *help);
122#endif 120#endif
123 121
124unsigned int hists__sort_list_width(struct hists *self); 122unsigned int hists__sort_list_width(struct hists *self);
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index a3a871f7bda3..0d414199889d 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -7,10 +7,52 @@
7#include <sys/types.h> 7#include <sys/types.h>
8#include <sys/mman.h> 8#include <sys/mman.h>
9 9
10#include "evlist.h"
11#include "evsel.h"
10#include "session.h" 12#include "session.h"
11#include "sort.h" 13#include "sort.h"
12#include "util.h" 14#include "util.h"
13 15
16static int perf_session__read_evlist(struct perf_session *session)
17{
18 int i, j;
19
20 session->evlist = perf_evlist__new(NULL, NULL);
21 if (session->evlist == NULL)
22 return -ENOMEM;
23
24 for (i = 0; i < session->header.attrs; ++i) {
25 struct perf_header_attr *hattr = session->header.attr[i];
26 struct perf_evsel *evsel = perf_evsel__new(&hattr->attr, i);
27
28 if (evsel == NULL)
29 goto out_delete_evlist;
30 /*
31 * Do it before so that if perf_evsel__alloc_id fails, this
32 * entry gets purged too at perf_evlist__delete().
33 */
34 perf_evlist__add(session->evlist, evsel);
35 /*
36 * We don't have the cpu and thread maps on the header, so
37 * for allocating the perf_sample_id table we fake 1 cpu and
38 * hattr->ids threads.
39 */
40 if (perf_evsel__alloc_id(evsel, 1, hattr->ids))
41 goto out_delete_evlist;
42
43 for (j = 0; j < hattr->ids; ++j)
44 perf_evlist__id_hash(session->evlist, evsel, 0, j,
45 hattr->id[j]);
46 }
47
48 return 0;
49
50out_delete_evlist:
51 perf_evlist__delete(session->evlist);
52 session->evlist = NULL;
53 return -ENOMEM;
54}
55
14static int perf_session__open(struct perf_session *self, bool force) 56static int perf_session__open(struct perf_session *self, bool force)
15{ 57{
16 struct stat input_stat; 58 struct stat input_stat;
@@ -56,6 +98,11 @@ static int perf_session__open(struct perf_session *self, bool force)
56 goto out_close; 98 goto out_close;
57 } 99 }
58 100
101 if (perf_session__read_evlist(self) < 0) {
102 pr_err("Not enough memory to read the event selector list\n");
103 goto out_close;
104 }
105
59 self->size = input_stat.st_size; 106 self->size = input_stat.st_size;
60 return 0; 107 return 0;
61 108
@@ -141,7 +188,6 @@ struct perf_session *perf_session__new(const char *filename, int mode,
141 memcpy(self->filename, filename, len); 188 memcpy(self->filename, filename, len);
142 self->threads = RB_ROOT; 189 self->threads = RB_ROOT;
143 INIT_LIST_HEAD(&self->dead_threads); 190 INIT_LIST_HEAD(&self->dead_threads);
144 self->hists_tree = RB_ROOT;
145 self->last_match = NULL; 191 self->last_match = NULL;
146 /* 192 /*
147 * On 64bit we can mmap the data file in one go. No need for tiny mmap 193 * On 64bit we can mmap the data file in one go. No need for tiny mmap
@@ -1137,3 +1183,18 @@ size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, FILE *fp,
1137 size_t ret = machine__fprintf_dsos_buildid(&self->host_machine, fp, with_hits); 1183 size_t ret = machine__fprintf_dsos_buildid(&self->host_machine, fp, with_hits);
1138 return ret + machines__fprintf_dsos_buildid(&self->machines, fp, with_hits); 1184 return ret + machines__fprintf_dsos_buildid(&self->machines, fp, with_hits);
1139} 1185}
1186
1187size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp)
1188{
1189 struct perf_evsel *pos;
1190 size_t ret = fprintf(fp, "Aggregated stats:\n");
1191
1192 ret += hists__fprintf_nr_events(&session->hists, fp);
1193
1194 list_for_each_entry(pos, &session->evlist->entries, node) {
1195 ret += fprintf(fp, "%s stats:\n", event_name(pos));
1196 ret += hists__fprintf_nr_events(&pos->hists, fp);
1197 }
1198
1199 return ret;
1200}
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 977b3a1b14aa..05dd7bcb9453 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -34,12 +34,12 @@ struct perf_session {
34 struct thread *last_match; 34 struct thread *last_match;
35 struct machine host_machine; 35 struct machine host_machine;
36 struct rb_root machines; 36 struct rb_root machines;
37 struct rb_root hists_tree; 37 struct perf_evlist *evlist;
38 /* 38 /*
39 * FIXME: should point to the first entry in hists_tree and 39 * FIXME: Need to split this up further, we need global
40 * be a hists instance. Right now its only 'report' 40 * stats + per event stats. 'perf diff' also needs
41 * that is using ->hists_tree while all the rest use 41 * to properly support multiple events in a single
42 * ->hists. 42 * perf.data file.
43 */ 43 */
44 struct hists hists; 44 struct hists hists;
45 u64 sample_type; 45 u64 sample_type;
@@ -151,11 +151,7 @@ size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp);
151size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, 151size_t perf_session__fprintf_dsos_buildid(struct perf_session *self,
152 FILE *fp, bool with_hits); 152 FILE *fp, bool with_hits);
153 153
154static inline 154size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp);
155size_t perf_session__fprintf_nr_events(struct perf_session *self, FILE *fp)
156{
157 return hists__fprintf_nr_events(&self->hists, fp);
158}
159 155
160static inline int perf_session__parse_sample(struct perf_session *session, 156static inline int perf_session__parse_sample(struct perf_session *session,
161 const union perf_event *event, 157 const union perf_event *event,
diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c
index c98e6f81d285..f3af4fe5cdc4 100644
--- a/tools/perf/util/ui/browsers/hists.c
+++ b/tools/perf/util/ui/browsers/hists.c
@@ -7,6 +7,8 @@
7#include <newt.h> 7#include <newt.h>
8#include <linux/rbtree.h> 8#include <linux/rbtree.h>
9 9
10#include "../../evsel.h"
11#include "../../evlist.h"
10#include "../../hist.h" 12#include "../../hist.h"
11#include "../../pstack.h" 13#include "../../pstack.h"
12#include "../../sort.h" 14#include "../../sort.h"
@@ -987,31 +989,33 @@ out:
987 return key; 989 return key;
988} 990}
989 991
990int hists__tui_browse_tree(struct rb_root *self, const char *help, int evidx) 992int hists__tui_browse_tree(struct perf_evlist *evlist, const char *help)
991{ 993{
992 struct rb_node *first = rb_first(self), *nd = first, *next; 994 struct perf_evsel *pos;
993 int key = 0;
994 995
995 while (nd) { 996 pos = list_entry(evlist->entries.next, struct perf_evsel, node);
996 struct hists *hists = rb_entry(nd, struct hists, rb_node); 997 while (pos) {
997 const char *ev_name = __event_name(hists->type, hists->config); 998 struct hists *hists = &pos->hists;
999 const char *ev_name = event_name(pos);
1000 int key = hists__browse(hists, help, ev_name, pos->idx);
998 1001
999 key = hists__browse(hists, help, ev_name, evidx);
1000 switch (key) { 1002 switch (key) {
1001 case NEWT_KEY_TAB: 1003 case NEWT_KEY_TAB:
1002 next = rb_next(nd); 1004 if (pos->node.next == &evlist->entries)
1003 if (next) 1005 pos = list_entry(evlist->entries.next, struct perf_evsel, node);
1004 nd = next; 1006 else
1007 pos = list_entry(pos->node.next, struct perf_evsel, node);
1005 break; 1008 break;
1006 case NEWT_KEY_UNTAB: 1009 case NEWT_KEY_UNTAB:
1007 if (nd == first) 1010 if (pos->node.prev == &evlist->entries)
1008 continue; 1011 pos = list_entry(evlist->entries.prev, struct perf_evsel, node);
1009 nd = rb_prev(nd); 1012 else
1013 pos = list_entry(pos->node.prev, struct perf_evsel, node);
1010 break; 1014 break;
1011 default: 1015 default:
1012 return key; 1016 return key;
1013 } 1017 }
1014 } 1018 }
1015 1019
1016 return key; 1020 return 0;
1017} 1021}