aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdrian Hunter <adrian.hunter@intel.com>2014-10-23 06:45:13 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2014-10-29 08:32:49 -0400
commit0db15b1e84a59e6e1da5fe6e74c35fe52fa29d92 (patch)
tree58834174c0672d033286fd21757091bcbb97ae45
parent7e4772dc99a3ebfc53708eff262f7a8155485e85 (diff)
perf tools: Add facility to export data in database-friendly way
This patch introduces an abstraction for exporting sample data in a database-friendly way. The abstraction does not implement the actual output. A subsequent patch takes this facility into use for extending the script interface. The abstraction is needed because static data like symbols, dsos, comms etc need to be exported only once. That means allocating them a unique identifier and recording it on each structure. The member 'db_id' is used for that. 'db_id' is just a 64-bit sequence number. Exporting centres around the db_export__sample() function which exports the associated data structures if they have not yet been allocated a db_id. Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> Cc: David Ahern <dsahern@gmail.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Jiri Olsa <jolsa@redhat.com> Cc: Namhyung Kim <namhyung@gmail.com> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephane Eranian <eranian@google.com> Link: http://lkml.kernel.org/r/1414061124-26830-6-git-send-email-adrian.hunter@intel.com [ committer note: Stash db_id using symbol_conf.priv_size + symbol__priv() and foo->priv areas ] Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-rw-r--r--tools/perf/Makefile.perf2
-rw-r--r--tools/perf/util/comm.h4
-rw-r--r--tools/perf/util/db-export.c270
-rw-r--r--tools/perf/util/db-export.h86
-rw-r--r--tools/perf/util/dso.h5
-rw-r--r--tools/perf/util/evsel.h2
-rw-r--r--tools/perf/util/machine.h4
-rw-r--r--tools/perf/util/thread.h1
8 files changed, 374 insertions, 0 deletions
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index 9c4ced0fc845..3caf7dab50e8 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -258,6 +258,7 @@ LIB_H += util/annotate.h
258LIB_H += util/cache.h 258LIB_H += util/cache.h
259LIB_H += util/callchain.h 259LIB_H += util/callchain.h
260LIB_H += util/build-id.h 260LIB_H += util/build-id.h
261LIB_H += util/db-export.h
261LIB_H += util/debug.h 262LIB_H += util/debug.h
262LIB_H += util/pmu.h 263LIB_H += util/pmu.h
263LIB_H += util/event.h 264LIB_H += util/event.h
@@ -323,6 +324,7 @@ LIB_OBJS += $(OUTPUT)util/annotate.o
323LIB_OBJS += $(OUTPUT)util/build-id.o 324LIB_OBJS += $(OUTPUT)util/build-id.o
324LIB_OBJS += $(OUTPUT)util/config.o 325LIB_OBJS += $(OUTPUT)util/config.o
325LIB_OBJS += $(OUTPUT)util/ctype.o 326LIB_OBJS += $(OUTPUT)util/ctype.o
327LIB_OBJS += $(OUTPUT)util/db-export.o
326LIB_OBJS += $(OUTPUT)util/pmu.o 328LIB_OBJS += $(OUTPUT)util/pmu.o
327LIB_OBJS += $(OUTPUT)util/environment.o 329LIB_OBJS += $(OUTPUT)util/environment.o
328LIB_OBJS += $(OUTPUT)util/event.o 330LIB_OBJS += $(OUTPUT)util/event.o
diff --git a/tools/perf/util/comm.h b/tools/perf/util/comm.h
index 51c10ab257f8..71c9c39340d4 100644
--- a/tools/perf/util/comm.h
+++ b/tools/perf/util/comm.h
@@ -12,6 +12,10 @@ struct comm {
12 u64 start; 12 u64 start;
13 struct list_head list; 13 struct list_head list;
14 bool exec; 14 bool exec;
15 union { /* Tool specific area */
16 void *priv;
17 u64 db_id;
18 };
15}; 19};
16 20
17void comm__free(struct comm *comm); 21void comm__free(struct comm *comm);
diff --git a/tools/perf/util/db-export.c b/tools/perf/util/db-export.c
new file mode 100644
index 000000000000..be128b075a32
--- /dev/null
+++ b/tools/perf/util/db-export.c
@@ -0,0 +1,270 @@
1/*
2 * db-export.c: Support for exporting data suitable for import to a database
3 * Copyright (c) 2014, Intel Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 */
15
16#include <errno.h>
17
18#include "evsel.h"
19#include "machine.h"
20#include "thread.h"
21#include "comm.h"
22#include "symbol.h"
23#include "event.h"
24#include "db-export.h"
25
26int db_export__init(struct db_export *dbe)
27{
28 memset(dbe, 0, sizeof(struct db_export));
29 return 0;
30}
31
32void db_export__exit(struct db_export *dbe __maybe_unused)
33{
34}
35
36int db_export__evsel(struct db_export *dbe, struct perf_evsel *evsel)
37{
38 if (evsel->db_id)
39 return 0;
40
41 evsel->db_id = ++dbe->evsel_last_db_id;
42
43 if (dbe->export_evsel)
44 return dbe->export_evsel(dbe, evsel);
45
46 return 0;
47}
48
49int db_export__machine(struct db_export *dbe, struct machine *machine)
50{
51 if (machine->db_id)
52 return 0;
53
54 machine->db_id = ++dbe->machine_last_db_id;
55
56 if (dbe->export_machine)
57 return dbe->export_machine(dbe, machine);
58
59 return 0;
60}
61
62int db_export__thread(struct db_export *dbe, struct thread *thread,
63 struct machine *machine, struct comm *comm)
64{
65 u64 main_thread_db_id = 0;
66 int err;
67
68 if (thread->db_id)
69 return 0;
70
71 thread->db_id = ++dbe->thread_last_db_id;
72
73 if (thread->pid_ != -1) {
74 struct thread *main_thread;
75
76 if (thread->pid_ == thread->tid) {
77 main_thread = thread;
78 } else {
79 main_thread = machine__findnew_thread(machine,
80 thread->pid_,
81 thread->pid_);
82 if (!main_thread)
83 return -ENOMEM;
84 err = db_export__thread(dbe, main_thread, machine,
85 comm);
86 if (err)
87 return err;
88 if (comm) {
89 err = db_export__comm_thread(dbe, comm, thread);
90 if (err)
91 return err;
92 }
93 }
94 main_thread_db_id = main_thread->db_id;
95 }
96
97 if (dbe->export_thread)
98 return dbe->export_thread(dbe, thread, main_thread_db_id,
99 machine);
100
101 return 0;
102}
103
104int db_export__comm(struct db_export *dbe, struct comm *comm,
105 struct thread *main_thread)
106{
107 int err;
108
109 if (comm->db_id)
110 return 0;
111
112 comm->db_id = ++dbe->comm_last_db_id;
113
114 if (dbe->export_comm) {
115 err = dbe->export_comm(dbe, comm);
116 if (err)
117 return err;
118 }
119
120 return db_export__comm_thread(dbe, comm, main_thread);
121}
122
123int db_export__comm_thread(struct db_export *dbe, struct comm *comm,
124 struct thread *thread)
125{
126 u64 db_id;
127
128 db_id = ++dbe->comm_thread_last_db_id;
129
130 if (dbe->export_comm_thread)
131 return dbe->export_comm_thread(dbe, db_id, comm, thread);
132
133 return 0;
134}
135
136int db_export__dso(struct db_export *dbe, struct dso *dso,
137 struct machine *machine)
138{
139 if (dso->db_id)
140 return 0;
141
142 dso->db_id = ++dbe->dso_last_db_id;
143
144 if (dbe->export_dso)
145 return dbe->export_dso(dbe, dso, machine);
146
147 return 0;
148}
149
150int db_export__symbol(struct db_export *dbe, struct symbol *sym,
151 struct dso *dso)
152{
153 u64 *sym_db_id = symbol__priv(sym);
154
155 if (*sym_db_id)
156 return 0;
157
158 *sym_db_id = ++dbe->symbol_last_db_id;
159
160 if (dbe->export_symbol)
161 return dbe->export_symbol(dbe, sym, dso);
162
163 return 0;
164}
165
166static struct thread *get_main_thread(struct machine *machine, struct thread *thread)
167{
168 if (thread->pid_ == thread->tid)
169 return thread;
170
171 if (thread->pid_ == -1)
172 return NULL;
173
174 return machine__find_thread(machine, thread->pid_, thread->pid_);
175}
176
177static int db_ids_from_al(struct db_export *dbe, struct addr_location *al,
178 u64 *dso_db_id, u64 *sym_db_id, u64 *offset)
179{
180 int err;
181
182 if (al->map) {
183 struct dso *dso = al->map->dso;
184
185 err = db_export__dso(dbe, dso, al->machine);
186 if (err)
187 return err;
188 *dso_db_id = dso->db_id;
189
190 if (!al->sym) {
191 al->sym = symbol__new(al->addr, 0, 0, "unknown");
192 if (al->sym)
193 symbols__insert(&dso->symbols[al->map->type],
194 al->sym);
195 }
196
197 if (al->sym) {
198 u64 *db_id = symbol__priv(al->sym);
199
200 err = db_export__symbol(dbe, al->sym, dso);
201 if (err)
202 return err;
203 *sym_db_id = *db_id;
204 *offset = al->addr - al->sym->start;
205 }
206 }
207
208 return 0;
209}
210
211int db_export__sample(struct db_export *dbe, union perf_event *event,
212 struct perf_sample *sample, struct perf_evsel *evsel,
213 struct thread *thread, struct addr_location *al)
214{
215 struct export_sample es = {
216 .event = event,
217 .sample = sample,
218 .evsel = evsel,
219 .thread = thread,
220 .al = al,
221 };
222 struct thread *main_thread;
223 struct comm *comm = NULL;
224 int err;
225
226 err = db_export__evsel(dbe, evsel);
227 if (err)
228 return err;
229
230 err = db_export__machine(dbe, al->machine);
231 if (err)
232 return err;
233
234 main_thread = get_main_thread(al->machine, thread);
235 if (main_thread)
236 comm = machine__thread_exec_comm(al->machine, main_thread);
237
238 err = db_export__thread(dbe, thread, al->machine, comm);
239 if (err)
240 return err;
241
242 if (comm) {
243 err = db_export__comm(dbe, comm, main_thread);
244 if (err)
245 return err;
246 es.comm_db_id = comm->db_id;
247 }
248
249 es.db_id = ++dbe->sample_last_db_id;
250
251 err = db_ids_from_al(dbe, al, &es.dso_db_id, &es.sym_db_id, &es.offset);
252 if (err)
253 return err;
254
255 if ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) &&
256 sample_addr_correlates_sym(&evsel->attr)) {
257 struct addr_location addr_al;
258
259 perf_event__preprocess_sample_addr(event, sample, thread, &addr_al);
260 err = db_ids_from_al(dbe, &addr_al, &es.addr_dso_db_id,
261 &es.addr_sym_db_id, &es.addr_offset);
262 if (err)
263 return err;
264 }
265
266 if (dbe->export_sample)
267 return dbe->export_sample(dbe, &es);
268
269 return 0;
270}
diff --git a/tools/perf/util/db-export.h b/tools/perf/util/db-export.h
new file mode 100644
index 000000000000..b3643e8e5750
--- /dev/null
+++ b/tools/perf/util/db-export.h
@@ -0,0 +1,86 @@
1/*
2 * db-export.h: Support for exporting data suitable for import to a database
3 * Copyright (c) 2014, Intel Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 */
15
16#ifndef __PERF_DB_EXPORT_H
17#define __PERF_DB_EXPORT_H
18
19#include <linux/types.h>
20
21struct perf_evsel;
22struct machine;
23struct thread;
24struct comm;
25struct dso;
26struct perf_sample;
27struct addr_location;
28
29struct export_sample {
30 union perf_event *event;
31 struct perf_sample *sample;
32 struct perf_evsel *evsel;
33 struct thread *thread;
34 struct addr_location *al;
35 u64 db_id;
36 u64 comm_db_id;
37 u64 dso_db_id;
38 u64 sym_db_id;
39 u64 offset; /* ip offset from symbol start */
40 u64 addr_dso_db_id;
41 u64 addr_sym_db_id;
42 u64 addr_offset; /* addr offset from symbol start */
43};
44
45struct db_export {
46 int (*export_evsel)(struct db_export *dbe, struct perf_evsel *evsel);
47 int (*export_machine)(struct db_export *dbe, struct machine *machine);
48 int (*export_thread)(struct db_export *dbe, struct thread *thread,
49 u64 main_thread_db_id, struct machine *machine);
50 int (*export_comm)(struct db_export *dbe, struct comm *comm);
51 int (*export_comm_thread)(struct db_export *dbe, u64 db_id,
52 struct comm *comm, struct thread *thread);
53 int (*export_dso)(struct db_export *dbe, struct dso *dso,
54 struct machine *machine);
55 int (*export_symbol)(struct db_export *dbe, struct symbol *sym,
56 struct dso *dso);
57 int (*export_sample)(struct db_export *dbe, struct export_sample *es);
58 u64 evsel_last_db_id;
59 u64 machine_last_db_id;
60 u64 thread_last_db_id;
61 u64 comm_last_db_id;
62 u64 comm_thread_last_db_id;
63 u64 dso_last_db_id;
64 u64 symbol_last_db_id;
65 u64 sample_last_db_id;
66};
67
68int db_export__init(struct db_export *dbe);
69void db_export__exit(struct db_export *dbe);
70int db_export__evsel(struct db_export *dbe, struct perf_evsel *evsel);
71int db_export__machine(struct db_export *dbe, struct machine *machine);
72int db_export__thread(struct db_export *dbe, struct thread *thread,
73 struct machine *machine, struct comm *comm);
74int db_export__comm(struct db_export *dbe, struct comm *comm,
75 struct thread *main_thread);
76int db_export__comm_thread(struct db_export *dbe, struct comm *comm,
77 struct thread *thread);
78int db_export__dso(struct db_export *dbe, struct dso *dso,
79 struct machine *machine);
80int db_export__symbol(struct db_export *dbe, struct symbol *sym,
81 struct dso *dso);
82int db_export__sample(struct db_export *dbe, union perf_event *event,
83 struct perf_sample *sample, struct perf_evsel *evsel,
84 struct thread *thread, struct addr_location *al);
85
86#endif
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index 3c9b391493f9..a316e4af321f 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -139,6 +139,11 @@ struct dso {
139 struct list_head open_entry; 139 struct list_head open_entry;
140 } data; 140 } data;
141 141
142 union { /* Tool specific area */
143 void *priv;
144 u64 db_id;
145 };
146
142 char name[0]; 147 char name[0];
143}; 148};
144 149
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 163c5604e5d1..d3854c4f52e1 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -54,6 +54,7 @@ struct cgroup_sel;
54 * @is_pos: the position (counting backwards) of the event id (PERF_SAMPLE_ID or 54 * @is_pos: the position (counting backwards) of the event id (PERF_SAMPLE_ID or
55 * PERF_SAMPLE_IDENTIFIER) in a non-sample event i.e. if sample_id_all 55 * PERF_SAMPLE_IDENTIFIER) in a non-sample event i.e. if sample_id_all
56 * is used there is an id sample appended to non-sample events 56 * is used there is an id sample appended to non-sample events
57 * @priv: And what is in its containing unnamed union are tool specific
57 */ 58 */
58struct perf_evsel { 59struct perf_evsel {
59 struct list_head node; 60 struct list_head node;
@@ -73,6 +74,7 @@ struct perf_evsel {
73 union { 74 union {
74 void *priv; 75 void *priv;
75 off_t id_offset; 76 off_t id_offset;
77 u64 db_id;
76 }; 78 };
77 struct cgroup_sel *cgrp; 79 struct cgroup_sel *cgrp;
78 void *handler; 80 void *handler;
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
index 88ec74e18cbf..e8b7779a0a3f 100644
--- a/tools/perf/util/machine.h
+++ b/tools/perf/util/machine.h
@@ -40,6 +40,10 @@ struct machine {
40 u64 kernel_start; 40 u64 kernel_start;
41 symbol_filter_t symbol_filter; 41 symbol_filter_t symbol_filter;
42 pid_t *current_tid; 42 pid_t *current_tid;
43 union { /* Tool specific area */
44 void *priv;
45 u64 db_id;
46 };
43}; 47};
44 48
45static inline 49static inline
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 6ef9fe6ff8da..d34cf5c0d0d9 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -23,6 +23,7 @@ struct thread {
23 bool dead; /* if set thread has exited */ 23 bool dead; /* if set thread has exited */
24 struct list_head comm_list; 24 struct list_head comm_list;
25 int comm_len; 25 int comm_len;
26 u64 db_id;
26 27
27 void *priv; 28 void *priv;
28}; 29};