blob: 017ecbb0ec05d4e153afe8d63716683034728283 [file] [log] [blame]
Adrian Hunter0db15b12014-10-23 13:45:13 +03001/*
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"
Adrian Hunter88f50d62014-10-30 16:09:46 +020024#include "thread-stack.h"
Adrian Hunter0db15b12014-10-23 13:45:13 +030025#include "db-export.h"
26
27int db_export__init(struct db_export *dbe)
28{
29 memset(dbe, 0, sizeof(struct db_export));
30 return 0;
31}
32
Adrian Hunter88f50d62014-10-30 16:09:46 +020033void db_export__exit(struct db_export *dbe)
Adrian Hunter0db15b12014-10-23 13:45:13 +030034{
Adrian Hunter88f50d62014-10-30 16:09:46 +020035 call_return_processor__free(dbe->crp);
36 dbe->crp = NULL;
Adrian Hunter0db15b12014-10-23 13:45:13 +030037}
38
39int db_export__evsel(struct db_export *dbe, struct perf_evsel *evsel)
40{
41 if (evsel->db_id)
42 return 0;
43
44 evsel->db_id = ++dbe->evsel_last_db_id;
45
46 if (dbe->export_evsel)
47 return dbe->export_evsel(dbe, evsel);
48
49 return 0;
50}
51
52int db_export__machine(struct db_export *dbe, struct machine *machine)
53{
54 if (machine->db_id)
55 return 0;
56
57 machine->db_id = ++dbe->machine_last_db_id;
58
59 if (dbe->export_machine)
60 return dbe->export_machine(dbe, machine);
61
62 return 0;
63}
64
65int db_export__thread(struct db_export *dbe, struct thread *thread,
66 struct machine *machine, struct comm *comm)
67{
68 u64 main_thread_db_id = 0;
69 int err;
70
71 if (thread->db_id)
72 return 0;
73
74 thread->db_id = ++dbe->thread_last_db_id;
75
76 if (thread->pid_ != -1) {
77 struct thread *main_thread;
78
79 if (thread->pid_ == thread->tid) {
80 main_thread = thread;
81 } else {
82 main_thread = machine__findnew_thread(machine,
83 thread->pid_,
84 thread->pid_);
85 if (!main_thread)
86 return -ENOMEM;
87 err = db_export__thread(dbe, main_thread, machine,
88 comm);
89 if (err)
90 return err;
91 if (comm) {
92 err = db_export__comm_thread(dbe, comm, thread);
93 if (err)
94 return err;
95 }
96 }
97 main_thread_db_id = main_thread->db_id;
98 }
99
100 if (dbe->export_thread)
101 return dbe->export_thread(dbe, thread, main_thread_db_id,
102 machine);
103
104 return 0;
105}
106
107int db_export__comm(struct db_export *dbe, struct comm *comm,
108 struct thread *main_thread)
109{
110 int err;
111
112 if (comm->db_id)
113 return 0;
114
115 comm->db_id = ++dbe->comm_last_db_id;
116
117 if (dbe->export_comm) {
118 err = dbe->export_comm(dbe, comm);
119 if (err)
120 return err;
121 }
122
123 return db_export__comm_thread(dbe, comm, main_thread);
124}
125
126int db_export__comm_thread(struct db_export *dbe, struct comm *comm,
127 struct thread *thread)
128{
129 u64 db_id;
130
131 db_id = ++dbe->comm_thread_last_db_id;
132
133 if (dbe->export_comm_thread)
134 return dbe->export_comm_thread(dbe, db_id, comm, thread);
135
136 return 0;
137}
138
139int db_export__dso(struct db_export *dbe, struct dso *dso,
140 struct machine *machine)
141{
142 if (dso->db_id)
143 return 0;
144
145 dso->db_id = ++dbe->dso_last_db_id;
146
147 if (dbe->export_dso)
148 return dbe->export_dso(dbe, dso, machine);
149
150 return 0;
151}
152
153int db_export__symbol(struct db_export *dbe, struct symbol *sym,
154 struct dso *dso)
155{
156 u64 *sym_db_id = symbol__priv(sym);
157
158 if (*sym_db_id)
159 return 0;
160
161 *sym_db_id = ++dbe->symbol_last_db_id;
162
163 if (dbe->export_symbol)
164 return dbe->export_symbol(dbe, sym, dso);
165
166 return 0;
167}
168
169static struct thread *get_main_thread(struct machine *machine, struct thread *thread)
170{
171 if (thread->pid_ == thread->tid)
172 return thread;
173
174 if (thread->pid_ == -1)
175 return NULL;
176
177 return machine__find_thread(machine, thread->pid_, thread->pid_);
178}
179
180static int db_ids_from_al(struct db_export *dbe, struct addr_location *al,
181 u64 *dso_db_id, u64 *sym_db_id, u64 *offset)
182{
183 int err;
184
185 if (al->map) {
186 struct dso *dso = al->map->dso;
187
188 err = db_export__dso(dbe, dso, al->machine);
189 if (err)
190 return err;
191 *dso_db_id = dso->db_id;
192
193 if (!al->sym) {
194 al->sym = symbol__new(al->addr, 0, 0, "unknown");
195 if (al->sym)
196 symbols__insert(&dso->symbols[al->map->type],
197 al->sym);
198 }
199
200 if (al->sym) {
201 u64 *db_id = symbol__priv(al->sym);
202
203 err = db_export__symbol(dbe, al->sym, dso);
204 if (err)
205 return err;
206 *sym_db_id = *db_id;
207 *offset = al->addr - al->sym->start;
208 }
209 }
210
211 return 0;
212}
213
Adrian Hunterf2bff002014-10-30 16:09:43 +0200214int db_export__branch_type(struct db_export *dbe, u32 branch_type,
215 const char *name)
216{
217 if (dbe->export_branch_type)
218 return dbe->export_branch_type(dbe, branch_type, name);
219
220 return 0;
221}
222
Adrian Hunter0db15b12014-10-23 13:45:13 +0300223int db_export__sample(struct db_export *dbe, union perf_event *event,
224 struct perf_sample *sample, struct perf_evsel *evsel,
225 struct thread *thread, struct addr_location *al)
226{
227 struct export_sample es = {
228 .event = event,
229 .sample = sample,
230 .evsel = evsel,
231 .thread = thread,
232 .al = al,
233 };
234 struct thread *main_thread;
235 struct comm *comm = NULL;
236 int err;
237
238 err = db_export__evsel(dbe, evsel);
239 if (err)
240 return err;
241
242 err = db_export__machine(dbe, al->machine);
243 if (err)
244 return err;
245
246 main_thread = get_main_thread(al->machine, thread);
247 if (main_thread)
248 comm = machine__thread_exec_comm(al->machine, main_thread);
249
250 err = db_export__thread(dbe, thread, al->machine, comm);
251 if (err)
252 return err;
253
254 if (comm) {
255 err = db_export__comm(dbe, comm, main_thread);
256 if (err)
257 return err;
258 es.comm_db_id = comm->db_id;
259 }
260
261 es.db_id = ++dbe->sample_last_db_id;
262
263 err = db_ids_from_al(dbe, al, &es.dso_db_id, &es.sym_db_id, &es.offset);
264 if (err)
265 return err;
266
267 if ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) &&
268 sample_addr_correlates_sym(&evsel->attr)) {
269 struct addr_location addr_al;
270
271 perf_event__preprocess_sample_addr(event, sample, thread, &addr_al);
272 err = db_ids_from_al(dbe, &addr_al, &es.addr_dso_db_id,
273 &es.addr_sym_db_id, &es.addr_offset);
274 if (err)
275 return err;
Adrian Hunter88f50d62014-10-30 16:09:46 +0200276 if (dbe->crp) {
277 err = thread_stack__process(thread, comm, sample, al,
278 &addr_al, es.db_id,
279 dbe->crp);
280 if (err)
281 return err;
282 }
Adrian Hunter0db15b12014-10-23 13:45:13 +0300283 }
284
285 if (dbe->export_sample)
286 return dbe->export_sample(dbe, &es);
287
288 return 0;
289}
Adrian Hunterf2bff002014-10-30 16:09:43 +0200290
291static struct {
292 u32 branch_type;
293 const char *name;
294} branch_types[] = {
295 {0, "no branch"},
296 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL, "call"},
297 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN, "return"},
298 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CONDITIONAL, "conditional jump"},
299 {PERF_IP_FLAG_BRANCH, "unconditional jump"},
300 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_INTERRUPT,
301 "software interrupt"},
302 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN | PERF_IP_FLAG_INTERRUPT,
303 "return from interrupt"},
304 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_SYSCALLRET,
305 "system call"},
306 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN | PERF_IP_FLAG_SYSCALLRET,
307 "return from system call"},
308 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_ASYNC, "asynchronous branch"},
309 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_ASYNC |
310 PERF_IP_FLAG_INTERRUPT, "hardware interrupt"},
311 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TX_ABORT, "transaction abort"},
312 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TRACE_BEGIN, "trace begin"},
313 {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TRACE_END, "trace end"},
314 {0, NULL}
315};
316
317int db_export__branch_types(struct db_export *dbe)
318{
319 int i, err = 0;
320
321 for (i = 0; branch_types[i].name ; i++) {
322 err = db_export__branch_type(dbe, branch_types[i].branch_type,
323 branch_types[i].name);
324 if (err)
325 break;
326 }
327 return err;
328}
Adrian Hunter88f50d62014-10-30 16:09:46 +0200329
330int db_export__call_path(struct db_export *dbe, struct call_path *cp)
331{
332 int err;
333
334 if (cp->db_id)
335 return 0;
336
337 if (cp->parent) {
338 err = db_export__call_path(dbe, cp->parent);
339 if (err)
340 return err;
341 }
342
343 cp->db_id = ++dbe->call_path_last_db_id;
344
345 if (dbe->export_call_path)
346 return dbe->export_call_path(dbe, cp);
347
348 return 0;
349}
350
351int db_export__call_return(struct db_export *dbe, struct call_return *cr)
352{
353 int err;
354
355 if (cr->db_id)
356 return 0;
357
358 err = db_export__call_path(dbe, cr->cp);
359 if (err)
360 return err;
361
362 cr->db_id = ++dbe->call_return_last_db_id;
363
364 if (dbe->export_call_return)
365 return dbe->export_call_return(dbe, cr);
366
367 return 0;
368}