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
25 #include "thread-stack.h"
26 #include "callchain.h"
27 #include "call-path.h"
28 #include "db-export.h"
30 struct deferred_export
{
31 struct list_head node
;
35 static int db_export__deferred(struct db_export
*dbe
)
37 struct deferred_export
*de
;
40 while (!list_empty(&dbe
->deferred
)) {
41 de
= list_entry(dbe
->deferred
.next
, struct deferred_export
,
43 err
= dbe
->export_comm(dbe
, de
->comm
);
53 static void db_export__free_deferred(struct db_export
*dbe
)
55 struct deferred_export
*de
;
57 while (!list_empty(&dbe
->deferred
)) {
58 de
= list_entry(dbe
->deferred
.next
, struct deferred_export
,
65 static int db_export__defer_comm(struct db_export
*dbe
, struct comm
*comm
)
67 struct deferred_export
*de
;
69 de
= zalloc(sizeof(struct deferred_export
));
74 list_add_tail(&de
->node
, &dbe
->deferred
);
79 int db_export__init(struct db_export
*dbe
)
81 memset(dbe
, 0, sizeof(struct db_export
));
82 INIT_LIST_HEAD(&dbe
->deferred
);
86 int db_export__flush(struct db_export
*dbe
)
88 return db_export__deferred(dbe
);
91 void db_export__exit(struct db_export
*dbe
)
93 db_export__free_deferred(dbe
);
94 call_return_processor__free(dbe
->crp
);
98 int db_export__evsel(struct db_export
*dbe
, struct perf_evsel
*evsel
)
103 evsel
->db_id
= ++dbe
->evsel_last_db_id
;
105 if (dbe
->export_evsel
)
106 return dbe
->export_evsel(dbe
, evsel
);
111 int db_export__machine(struct db_export
*dbe
, struct machine
*machine
)
116 machine
->db_id
= ++dbe
->machine_last_db_id
;
118 if (dbe
->export_machine
)
119 return dbe
->export_machine(dbe
, machine
);
124 int db_export__thread(struct db_export
*dbe
, struct thread
*thread
,
125 struct machine
*machine
, struct comm
*comm
)
127 struct thread
*main_thread
;
128 u64 main_thread_db_id
= 0;
134 thread
->db_id
= ++dbe
->thread_last_db_id
;
136 if (thread
->pid_
!= -1) {
137 if (thread
->pid_
== thread
->tid
) {
138 main_thread
= thread
;
140 main_thread
= machine__findnew_thread(machine
,
145 err
= db_export__thread(dbe
, main_thread
, machine
,
150 err
= db_export__comm_thread(dbe
, comm
, thread
);
155 main_thread_db_id
= main_thread
->db_id
;
156 if (main_thread
!= thread
)
157 thread__put(main_thread
);
160 if (dbe
->export_thread
)
161 return dbe
->export_thread(dbe
, thread
, main_thread_db_id
,
167 thread__put(main_thread
);
171 int db_export__comm(struct db_export
*dbe
, struct comm
*comm
,
172 struct thread
*main_thread
)
179 comm
->db_id
= ++dbe
->comm_last_db_id
;
181 if (dbe
->export_comm
) {
182 if (main_thread
->comm_set
)
183 err
= dbe
->export_comm(dbe
, comm
);
185 err
= db_export__defer_comm(dbe
, comm
);
190 return db_export__comm_thread(dbe
, comm
, main_thread
);
193 int db_export__comm_thread(struct db_export
*dbe
, struct comm
*comm
,
194 struct thread
*thread
)
198 db_id
= ++dbe
->comm_thread_last_db_id
;
200 if (dbe
->export_comm_thread
)
201 return dbe
->export_comm_thread(dbe
, db_id
, comm
, thread
);
206 int db_export__dso(struct db_export
*dbe
, struct dso
*dso
,
207 struct machine
*machine
)
212 dso
->db_id
= ++dbe
->dso_last_db_id
;
215 return dbe
->export_dso(dbe
, dso
, machine
);
220 int db_export__symbol(struct db_export
*dbe
, struct symbol
*sym
,
223 u64
*sym_db_id
= symbol__priv(sym
);
228 *sym_db_id
= ++dbe
->symbol_last_db_id
;
230 if (dbe
->export_symbol
)
231 return dbe
->export_symbol(dbe
, sym
, dso
);
236 static int db_ids_from_al(struct db_export
*dbe
, struct addr_location
*al
,
237 u64
*dso_db_id
, u64
*sym_db_id
, u64
*offset
)
242 struct dso
*dso
= al
->map
->dso
;
244 err
= db_export__dso(dbe
, dso
, al
->machine
);
247 *dso_db_id
= dso
->db_id
;
250 al
->sym
= symbol__new(al
->addr
, 0, 0, 0, "unknown");
252 dso__insert_symbol(dso
, al
->sym
);
256 u64
*db_id
= symbol__priv(al
->sym
);
258 err
= db_export__symbol(dbe
, al
->sym
, dso
);
262 *offset
= al
->addr
- al
->sym
->start
;
269 static struct call_path
*call_path_from_sample(struct db_export
*dbe
,
270 struct machine
*machine
,
271 struct thread
*thread
,
272 struct perf_sample
*sample
,
273 struct perf_evsel
*evsel
)
275 u64 kernel_start
= machine__kernel_start(machine
);
276 struct call_path
*current
= &dbe
->cpr
->call_path
;
277 enum chain_order saved_order
= callchain_param
.order
;
280 if (!symbol_conf
.use_callchain
|| !sample
->callchain
)
284 * Since the call path tree must be built starting with the root, we
285 * must use ORDER_CALL for call chain resolution, in order to process
286 * the callchain starting with the root node and ending with the leaf.
288 callchain_param
.order
= ORDER_CALLER
;
289 err
= thread__resolve_callchain(thread
, &callchain_cursor
, evsel
,
290 sample
, NULL
, NULL
, PERF_MAX_STACK_DEPTH
);
292 callchain_param
.order
= saved_order
;
295 callchain_cursor_commit(&callchain_cursor
);
298 struct callchain_cursor_node
*node
;
299 struct addr_location al
;
300 u64 dso_db_id
= 0, sym_db_id
= 0, offset
= 0;
302 memset(&al
, 0, sizeof(al
));
304 node
= callchain_cursor_current(&callchain_cursor
);
308 * Handle export of symbol and dso for this node by
309 * constructing an addr_location struct and then passing it to
310 * db_ids_from_al() to perform the export.
314 al
.machine
= machine
;
317 if (al
.map
&& !al
.sym
)
318 al
.sym
= dso__find_symbol(al
.map
->dso
, al
.addr
);
320 db_ids_from_al(dbe
, &al
, &dso_db_id
, &sym_db_id
, &offset
);
322 /* add node to the call path tree if it doesn't exist */
323 current
= call_path__findnew(dbe
->cpr
, current
,
327 callchain_cursor_advance(&callchain_cursor
);
330 /* Reset the callchain order to its prior value. */
331 callchain_param
.order
= saved_order
;
333 if (current
== &dbe
->cpr
->call_path
) {
334 /* Bail because the callchain was empty. */
341 int db_export__branch_type(struct db_export
*dbe
, u32 branch_type
,
344 if (dbe
->export_branch_type
)
345 return dbe
->export_branch_type(dbe
, branch_type
, name
);
350 int db_export__sample(struct db_export
*dbe
, union perf_event
*event
,
351 struct perf_sample
*sample
, struct perf_evsel
*evsel
,
352 struct addr_location
*al
)
354 struct thread
* thread
= al
->thread
;
355 struct export_sample es
= {
361 struct thread
*main_thread
;
362 struct comm
*comm
= NULL
;
365 err
= db_export__evsel(dbe
, evsel
);
369 err
= db_export__machine(dbe
, al
->machine
);
373 main_thread
= thread__main_thread(al
->machine
, thread
);
375 comm
= machine__thread_exec_comm(al
->machine
, main_thread
);
377 err
= db_export__thread(dbe
, thread
, al
->machine
, comm
);
382 err
= db_export__comm(dbe
, comm
, main_thread
);
385 es
.comm_db_id
= comm
->db_id
;
388 es
.db_id
= ++dbe
->sample_last_db_id
;
390 err
= db_ids_from_al(dbe
, al
, &es
.dso_db_id
, &es
.sym_db_id
, &es
.offset
);
395 struct call_path
*cp
= call_path_from_sample(dbe
, al
->machine
,
399 db_export__call_path(dbe
, cp
);
400 es
.call_path_id
= cp
->db_id
;
404 if ((evsel
->attr
.sample_type
& PERF_SAMPLE_ADDR
) &&
405 sample_addr_correlates_sym(&evsel
->attr
)) {
406 struct addr_location addr_al
;
408 thread__resolve(thread
, &addr_al
, sample
);
409 err
= db_ids_from_al(dbe
, &addr_al
, &es
.addr_dso_db_id
,
410 &es
.addr_sym_db_id
, &es
.addr_offset
);
414 err
= thread_stack__process(thread
, comm
, sample
, al
,
422 if (dbe
->export_sample
)
423 err
= dbe
->export_sample(dbe
, &es
);
426 thread__put(main_thread
);
435 {PERF_IP_FLAG_BRANCH
| PERF_IP_FLAG_CALL
, "call"},
436 {PERF_IP_FLAG_BRANCH
| PERF_IP_FLAG_RETURN
, "return"},
437 {PERF_IP_FLAG_BRANCH
| PERF_IP_FLAG_CONDITIONAL
, "conditional jump"},
438 {PERF_IP_FLAG_BRANCH
, "unconditional jump"},
439 {PERF_IP_FLAG_BRANCH
| PERF_IP_FLAG_CALL
| PERF_IP_FLAG_INTERRUPT
,
440 "software interrupt"},
441 {PERF_IP_FLAG_BRANCH
| PERF_IP_FLAG_RETURN
| PERF_IP_FLAG_INTERRUPT
,
442 "return from interrupt"},
443 {PERF_IP_FLAG_BRANCH
| PERF_IP_FLAG_CALL
| PERF_IP_FLAG_SYSCALLRET
,
445 {PERF_IP_FLAG_BRANCH
| PERF_IP_FLAG_RETURN
| PERF_IP_FLAG_SYSCALLRET
,
446 "return from system call"},
447 {PERF_IP_FLAG_BRANCH
| PERF_IP_FLAG_ASYNC
, "asynchronous branch"},
448 {PERF_IP_FLAG_BRANCH
| PERF_IP_FLAG_CALL
| PERF_IP_FLAG_ASYNC
|
449 PERF_IP_FLAG_INTERRUPT
, "hardware interrupt"},
450 {PERF_IP_FLAG_BRANCH
| PERF_IP_FLAG_TX_ABORT
, "transaction abort"},
451 {PERF_IP_FLAG_BRANCH
| PERF_IP_FLAG_TRACE_BEGIN
, "trace begin"},
452 {PERF_IP_FLAG_BRANCH
| PERF_IP_FLAG_TRACE_END
, "trace end"},
456 int db_export__branch_types(struct db_export
*dbe
)
460 for (i
= 0; branch_types
[i
].name
; i
++) {
461 err
= db_export__branch_type(dbe
, branch_types
[i
].branch_type
,
462 branch_types
[i
].name
);
469 int db_export__call_path(struct db_export
*dbe
, struct call_path
*cp
)
477 err
= db_export__call_path(dbe
, cp
->parent
);
482 cp
->db_id
= ++dbe
->call_path_last_db_id
;
484 if (dbe
->export_call_path
)
485 return dbe
->export_call_path(dbe
, cp
);
490 int db_export__call_return(struct db_export
*dbe
, struct call_return
*cr
)
497 err
= db_export__call_path(dbe
, cr
->cp
);
501 cr
->db_id
= ++dbe
->call_return_last_db_id
;
503 if (dbe
->export_call_return
)
504 return dbe
->export_call_return(dbe
, cr
);