2 * db-export.c: Support for exporting data suitable for import to a database
3 * Copyright (c) 2014, Intel Corporation.
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.
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
26 #include "thread-stack.h"
27 #include "callchain.h"
28 #include "call-path.h"
29 #include "db-export.h"
31 struct deferred_export
{
32 struct list_head node
;
36 static int db_export__deferred(struct db_export
*dbe
)
38 struct deferred_export
*de
;
41 while (!list_empty(&dbe
->deferred
)) {
42 de
= list_entry(dbe
->deferred
.next
, struct deferred_export
,
44 err
= dbe
->export_comm(dbe
, de
->comm
);
54 static void db_export__free_deferred(struct db_export
*dbe
)
56 struct deferred_export
*de
;
58 while (!list_empty(&dbe
->deferred
)) {
59 de
= list_entry(dbe
->deferred
.next
, struct deferred_export
,
66 static int db_export__defer_comm(struct db_export
*dbe
, struct comm
*comm
)
68 struct deferred_export
*de
;
70 de
= zalloc(sizeof(struct deferred_export
));
75 list_add_tail(&de
->node
, &dbe
->deferred
);
80 int db_export__init(struct db_export
*dbe
)
82 memset(dbe
, 0, sizeof(struct db_export
));
83 INIT_LIST_HEAD(&dbe
->deferred
);
87 int db_export__flush(struct db_export
*dbe
)
89 return db_export__deferred(dbe
);
92 void db_export__exit(struct db_export
*dbe
)
94 db_export__free_deferred(dbe
);
95 call_return_processor__free(dbe
->crp
);
99 int db_export__evsel(struct db_export
*dbe
, struct perf_evsel
*evsel
)
104 evsel
->db_id
= ++dbe
->evsel_last_db_id
;
106 if (dbe
->export_evsel
)
107 return dbe
->export_evsel(dbe
, evsel
);
112 int db_export__machine(struct db_export
*dbe
, struct machine
*machine
)
117 machine
->db_id
= ++dbe
->machine_last_db_id
;
119 if (dbe
->export_machine
)
120 return dbe
->export_machine(dbe
, machine
);
125 int db_export__thread(struct db_export
*dbe
, struct thread
*thread
,
126 struct machine
*machine
, struct comm
*comm
)
128 struct thread
*main_thread
;
129 u64 main_thread_db_id
= 0;
135 thread
->db_id
= ++dbe
->thread_last_db_id
;
137 if (thread
->pid_
!= -1) {
138 if (thread
->pid_
== thread
->tid
) {
139 main_thread
= thread
;
141 main_thread
= machine__findnew_thread(machine
,
146 err
= db_export__thread(dbe
, main_thread
, machine
,
151 err
= db_export__comm_thread(dbe
, comm
, thread
);
156 main_thread_db_id
= main_thread
->db_id
;
157 if (main_thread
!= thread
)
158 thread__put(main_thread
);
161 if (dbe
->export_thread
)
162 return dbe
->export_thread(dbe
, thread
, main_thread_db_id
,
168 thread__put(main_thread
);
172 int db_export__comm(struct db_export
*dbe
, struct comm
*comm
,
173 struct thread
*main_thread
)
180 comm
->db_id
= ++dbe
->comm_last_db_id
;
182 if (dbe
->export_comm
) {
183 if (main_thread
->comm_set
)
184 err
= dbe
->export_comm(dbe
, comm
);
186 err
= db_export__defer_comm(dbe
, comm
);
191 return db_export__comm_thread(dbe
, comm
, main_thread
);
194 int db_export__comm_thread(struct db_export
*dbe
, struct comm
*comm
,
195 struct thread
*thread
)
199 db_id
= ++dbe
->comm_thread_last_db_id
;
201 if (dbe
->export_comm_thread
)
202 return dbe
->export_comm_thread(dbe
, db_id
, comm
, thread
);
207 int db_export__dso(struct db_export
*dbe
, struct dso
*dso
,
208 struct machine
*machine
)
213 dso
->db_id
= ++dbe
->dso_last_db_id
;
216 return dbe
->export_dso(dbe
, dso
, machine
);
221 int db_export__symbol(struct db_export
*dbe
, struct symbol
*sym
,
224 u64
*sym_db_id
= symbol__priv(sym
);
229 *sym_db_id
= ++dbe
->symbol_last_db_id
;
231 if (dbe
->export_symbol
)
232 return dbe
->export_symbol(dbe
, sym
, dso
);
237 static int db_ids_from_al(struct db_export
*dbe
, struct addr_location
*al
,
238 u64
*dso_db_id
, u64
*sym_db_id
, u64
*offset
)
243 struct dso
*dso
= al
->map
->dso
;
245 err
= db_export__dso(dbe
, dso
, al
->machine
);
248 *dso_db_id
= dso
->db_id
;
251 al
->sym
= symbol__new(al
->addr
, 0, 0, 0, "unknown");
253 dso__insert_symbol(dso
, al
->sym
);
257 u64
*db_id
= symbol__priv(al
->sym
);
259 err
= db_export__symbol(dbe
, al
->sym
, dso
);
263 *offset
= al
->addr
- al
->sym
->start
;
270 static struct call_path
*call_path_from_sample(struct db_export
*dbe
,
271 struct machine
*machine
,
272 struct thread
*thread
,
273 struct perf_sample
*sample
,
274 struct perf_evsel
*evsel
)
276 u64 kernel_start
= machine__kernel_start(machine
);
277 struct call_path
*current
= &dbe
->cpr
->call_path
;
278 enum chain_order saved_order
= callchain_param
.order
;
281 if (!symbol_conf
.use_callchain
|| !sample
->callchain
)
285 * Since the call path tree must be built starting with the root, we
286 * must use ORDER_CALL for call chain resolution, in order to process
287 * the callchain starting with the root node and ending with the leaf.
289 callchain_param
.order
= ORDER_CALLER
;
290 err
= thread__resolve_callchain(thread
, &callchain_cursor
, evsel
,
291 sample
, NULL
, NULL
, PERF_MAX_STACK_DEPTH
);
293 callchain_param
.order
= saved_order
;
296 callchain_cursor_commit(&callchain_cursor
);
299 struct callchain_cursor_node
*node
;
300 struct addr_location al
;
301 u64 dso_db_id
= 0, sym_db_id
= 0, offset
= 0;
303 memset(&al
, 0, sizeof(al
));
305 node
= callchain_cursor_current(&callchain_cursor
);
309 * Handle export of symbol and dso for this node by
310 * constructing an addr_location struct and then passing it to
311 * db_ids_from_al() to perform the export.
315 al
.machine
= machine
;
318 if (al
.map
&& !al
.sym
)
319 al
.sym
= dso__find_symbol(al
.map
->dso
, al
.addr
);
321 db_ids_from_al(dbe
, &al
, &dso_db_id
, &sym_db_id
, &offset
);
323 /* add node to the call path tree if it doesn't exist */
324 current
= call_path__findnew(dbe
->cpr
, current
,
328 callchain_cursor_advance(&callchain_cursor
);
331 /* Reset the callchain order to its prior value. */
332 callchain_param
.order
= saved_order
;
334 if (current
== &dbe
->cpr
->call_path
) {
335 /* Bail because the callchain was empty. */
342 int db_export__branch_type(struct db_export
*dbe
, u32 branch_type
,
345 if (dbe
->export_branch_type
)
346 return dbe
->export_branch_type(dbe
, branch_type
, name
);
351 int db_export__sample(struct db_export
*dbe
, union perf_event
*event
,
352 struct perf_sample
*sample
, struct perf_evsel
*evsel
,
353 struct addr_location
*al
)
355 struct thread
* thread
= al
->thread
;
356 struct export_sample es
= {
362 struct thread
*main_thread
;
363 struct comm
*comm
= NULL
;
366 err
= db_export__evsel(dbe
, evsel
);
370 err
= db_export__machine(dbe
, al
->machine
);
374 main_thread
= thread__main_thread(al
->machine
, thread
);
376 comm
= machine__thread_exec_comm(al
->machine
, main_thread
);
378 err
= db_export__thread(dbe
, thread
, al
->machine
, comm
);
383 err
= db_export__comm(dbe
, comm
, main_thread
);
386 es
.comm_db_id
= comm
->db_id
;
389 es
.db_id
= ++dbe
->sample_last_db_id
;
391 err
= db_ids_from_al(dbe
, al
, &es
.dso_db_id
, &es
.sym_db_id
, &es
.offset
);
396 struct call_path
*cp
= call_path_from_sample(dbe
, al
->machine
,
400 db_export__call_path(dbe
, cp
);
401 es
.call_path_id
= cp
->db_id
;
405 if ((evsel
->attr
.sample_type
& PERF_SAMPLE_ADDR
) &&
406 sample_addr_correlates_sym(&evsel
->attr
)) {
407 struct addr_location addr_al
;
409 thread__resolve(thread
, &addr_al
, sample
);
410 err
= db_ids_from_al(dbe
, &addr_al
, &es
.addr_dso_db_id
,
411 &es
.addr_sym_db_id
, &es
.addr_offset
);
415 err
= thread_stack__process(thread
, comm
, sample
, al
,
423 if (dbe
->export_sample
)
424 err
= dbe
->export_sample(dbe
, &es
);
427 thread__put(main_thread
);
436 {PERF_IP_FLAG_BRANCH
| PERF_IP_FLAG_CALL
, "call"},
437 {PERF_IP_FLAG_BRANCH
| PERF_IP_FLAG_RETURN
, "return"},
438 {PERF_IP_FLAG_BRANCH
| PERF_IP_FLAG_CONDITIONAL
, "conditional jump"},
439 {PERF_IP_FLAG_BRANCH
, "unconditional jump"},
440 {PERF_IP_FLAG_BRANCH
| PERF_IP_FLAG_CALL
| PERF_IP_FLAG_INTERRUPT
,
441 "software interrupt"},
442 {PERF_IP_FLAG_BRANCH
| PERF_IP_FLAG_RETURN
| PERF_IP_FLAG_INTERRUPT
,
443 "return from interrupt"},
444 {PERF_IP_FLAG_BRANCH
| PERF_IP_FLAG_CALL
| PERF_IP_FLAG_SYSCALLRET
,
446 {PERF_IP_FLAG_BRANCH
| PERF_IP_FLAG_RETURN
| PERF_IP_FLAG_SYSCALLRET
,
447 "return from system call"},
448 {PERF_IP_FLAG_BRANCH
| PERF_IP_FLAG_ASYNC
, "asynchronous branch"},
449 {PERF_IP_FLAG_BRANCH
| PERF_IP_FLAG_CALL
| PERF_IP_FLAG_ASYNC
|
450 PERF_IP_FLAG_INTERRUPT
, "hardware interrupt"},
451 {PERF_IP_FLAG_BRANCH
| PERF_IP_FLAG_TX_ABORT
, "transaction abort"},
452 {PERF_IP_FLAG_BRANCH
| PERF_IP_FLAG_TRACE_BEGIN
, "trace begin"},
453 {PERF_IP_FLAG_BRANCH
| PERF_IP_FLAG_TRACE_END
, "trace end"},
457 int db_export__branch_types(struct db_export
*dbe
)
461 for (i
= 0; branch_types
[i
].name
; i
++) {
462 err
= db_export__branch_type(dbe
, branch_types
[i
].branch_type
,
463 branch_types
[i
].name
);
468 /* Add trace begin / end variants */
469 for (i
= 0; branch_types
[i
].name
; i
++) {
470 const char *name
= branch_types
[i
].name
;
471 u32 type
= branch_types
[i
].branch_type
;
474 if (type
== PERF_IP_FLAG_BRANCH
||
475 (type
& (PERF_IP_FLAG_TRACE_BEGIN
| PERF_IP_FLAG_TRACE_END
)))
478 snprintf(buf
, sizeof(buf
), "trace begin / %s", name
);
479 err
= db_export__branch_type(dbe
, type
| PERF_IP_FLAG_TRACE_BEGIN
, buf
);
483 snprintf(buf
, sizeof(buf
), "%s / trace end", name
);
484 err
= db_export__branch_type(dbe
, type
| PERF_IP_FLAG_TRACE_END
, buf
);
492 int db_export__call_path(struct db_export
*dbe
, struct call_path
*cp
)
500 err
= db_export__call_path(dbe
, cp
->parent
);
505 cp
->db_id
= ++dbe
->call_path_last_db_id
;
507 if (dbe
->export_call_path
)
508 return dbe
->export_call_path(dbe
, cp
);
513 int db_export__call_return(struct db_export
*dbe
, struct call_return
*cr
,
518 err
= db_export__call_path(dbe
, cr
->cp
);
523 cr
->db_id
= ++dbe
->call_return_last_db_id
;
527 *parent_db_id
= ++dbe
->call_return_last_db_id
;
528 cr
->parent_db_id
= *parent_db_id
;
531 if (dbe
->export_call_return
)
532 return dbe
->export_call_return(dbe
, cr
);