1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * db-export.c: Support for exporting data suitable for import to a database |
4 | * Copyright (c) 2014, Intel Corporation. |
5 | */ |
6 | |
7 | #include <errno.h> |
8 | #include <stdlib.h> |
9 | |
10 | #include "dso.h" |
11 | #include "evsel.h" |
12 | #include "machine.h" |
13 | #include "thread.h" |
14 | #include "comm.h" |
15 | #include "symbol.h" |
16 | #include "map.h" |
17 | #include "event.h" |
18 | #include "thread-stack.h" |
19 | #include "callchain.h" |
20 | #include "call-path.h" |
21 | #include "db-export.h" |
22 | #include <linux/zalloc.h> |
23 | |
24 | int db_export__init(struct db_export *dbe) |
25 | { |
26 | memset(dbe, 0, sizeof(struct db_export)); |
27 | return 0; |
28 | } |
29 | |
30 | void db_export__exit(struct db_export *dbe) |
31 | { |
32 | call_return_processor__free(crp: dbe->crp); |
33 | dbe->crp = NULL; |
34 | } |
35 | |
36 | int db_export__evsel(struct db_export *dbe, struct 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 | |
49 | int 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 | |
62 | int db_export__thread(struct db_export *dbe, struct thread *thread, |
63 | struct machine *machine, struct thread *main_thread) |
64 | { |
65 | u64 main_thread_db_id = 0; |
66 | |
67 | if (thread__db_id(thread)) |
68 | return 0; |
69 | |
70 | thread__set_db_id(thread, db_id: ++dbe->thread_last_db_id); |
71 | |
72 | if (main_thread) |
73 | main_thread_db_id = thread__db_id(thread: main_thread); |
74 | |
75 | if (dbe->export_thread) |
76 | return dbe->export_thread(dbe, thread, main_thread_db_id, |
77 | machine); |
78 | |
79 | return 0; |
80 | } |
81 | |
82 | static int __db_export__comm(struct db_export *dbe, struct comm *comm, |
83 | struct thread *thread) |
84 | { |
85 | comm->db_id = ++dbe->comm_last_db_id; |
86 | |
87 | if (dbe->export_comm) |
88 | return dbe->export_comm(dbe, comm, thread); |
89 | |
90 | return 0; |
91 | } |
92 | |
93 | int db_export__comm(struct db_export *dbe, struct comm *comm, |
94 | struct thread *thread) |
95 | { |
96 | if (comm->db_id) |
97 | return 0; |
98 | |
99 | return __db_export__comm(dbe, comm, thread); |
100 | } |
101 | |
102 | /* |
103 | * Export the "exec" comm. The "exec" comm is the program / application command |
104 | * name at the time it first executes. It is used to group threads for the same |
105 | * program. Note that the main thread pid (or thread group id tgid) cannot be |
106 | * used because it does not change when a new program is exec'ed. |
107 | */ |
108 | int db_export__exec_comm(struct db_export *dbe, struct comm *comm, |
109 | struct thread *main_thread) |
110 | { |
111 | int err; |
112 | |
113 | if (comm->db_id) |
114 | return 0; |
115 | |
116 | err = __db_export__comm(dbe, comm, thread: main_thread); |
117 | if (err) |
118 | return err; |
119 | |
120 | /* |
121 | * Record the main thread for this comm. Note that the main thread can |
122 | * have many "exec" comms because there will be a new one every time it |
123 | * exec's. An "exec" comm however will only ever have 1 main thread. |
124 | * That is different to any other threads for that same program because |
125 | * exec() will effectively kill them, so the relationship between the |
126 | * "exec" comm and non-main threads is 1-to-1. That is why |
127 | * db_export__comm_thread() is called here for the main thread, but it |
128 | * is called for non-main threads when they are exported. |
129 | */ |
130 | return db_export__comm_thread(dbe, comm, thread: main_thread); |
131 | } |
132 | |
133 | int db_export__comm_thread(struct db_export *dbe, struct comm *comm, |
134 | struct thread *thread) |
135 | { |
136 | u64 db_id; |
137 | |
138 | db_id = ++dbe->comm_thread_last_db_id; |
139 | |
140 | if (dbe->export_comm_thread) |
141 | return dbe->export_comm_thread(dbe, db_id, comm, thread); |
142 | |
143 | return 0; |
144 | } |
145 | |
146 | int db_export__dso(struct db_export *dbe, struct dso *dso, |
147 | struct machine *machine) |
148 | { |
149 | if (dso->db_id) |
150 | return 0; |
151 | |
152 | dso->db_id = ++dbe->dso_last_db_id; |
153 | |
154 | if (dbe->export_dso) |
155 | return dbe->export_dso(dbe, dso, machine); |
156 | |
157 | return 0; |
158 | } |
159 | |
160 | int db_export__symbol(struct db_export *dbe, struct symbol *sym, |
161 | struct dso *dso) |
162 | { |
163 | u64 *sym_db_id = symbol__priv(sym); |
164 | |
165 | if (*sym_db_id) |
166 | return 0; |
167 | |
168 | *sym_db_id = ++dbe->symbol_last_db_id; |
169 | |
170 | if (dbe->export_symbol) |
171 | return dbe->export_symbol(dbe, sym, dso); |
172 | |
173 | return 0; |
174 | } |
175 | |
176 | static int db_ids_from_al(struct db_export *dbe, struct addr_location *al, |
177 | u64 *dso_db_id, u64 *sym_db_id, u64 *offset) |
178 | { |
179 | int err; |
180 | |
181 | if (al->map) { |
182 | struct dso *dso = map__dso(map: al->map); |
183 | |
184 | err = db_export__dso(dbe, dso, machine: maps__machine(maps: al->maps)); |
185 | if (err) |
186 | return err; |
187 | *dso_db_id = dso->db_id; |
188 | |
189 | if (!al->sym) { |
190 | al->sym = symbol__new(start: al->addr, len: 0, binding: 0, type: 0, name: "unknown" ); |
191 | if (al->sym) |
192 | dso__insert_symbol(dso, sym: al->sym); |
193 | } |
194 | |
195 | if (al->sym) { |
196 | u64 *db_id = symbol__priv(sym: al->sym); |
197 | |
198 | err = db_export__symbol(dbe, sym: al->sym, dso); |
199 | if (err) |
200 | return err; |
201 | *sym_db_id = *db_id; |
202 | *offset = al->addr - al->sym->start; |
203 | } |
204 | } |
205 | |
206 | return 0; |
207 | } |
208 | |
209 | static struct call_path *call_path_from_sample(struct db_export *dbe, |
210 | struct machine *machine, |
211 | struct thread *thread, |
212 | struct perf_sample *sample, |
213 | struct evsel *evsel) |
214 | { |
215 | u64 kernel_start = machine__kernel_start(machine); |
216 | struct call_path *current = &dbe->cpr->call_path; |
217 | enum chain_order saved_order = callchain_param.order; |
218 | struct callchain_cursor *cursor; |
219 | int err; |
220 | |
221 | if (!symbol_conf.use_callchain || !sample->callchain) |
222 | return NULL; |
223 | |
224 | /* |
225 | * Since the call path tree must be built starting with the root, we |
226 | * must use ORDER_CALL for call chain resolution, in order to process |
227 | * the callchain starting with the root node and ending with the leaf. |
228 | */ |
229 | callchain_param.order = ORDER_CALLER; |
230 | cursor = get_tls_callchain_cursor(); |
231 | err = thread__resolve_callchain(thread, cursor, evsel, |
232 | sample, NULL, NULL, PERF_MAX_STACK_DEPTH); |
233 | if (err) { |
234 | callchain_param.order = saved_order; |
235 | return NULL; |
236 | } |
237 | callchain_cursor_commit(cursor); |
238 | |
239 | while (1) { |
240 | struct callchain_cursor_node *node; |
241 | struct addr_location al; |
242 | u64 dso_db_id = 0, sym_db_id = 0, offset = 0; |
243 | |
244 | |
245 | node = callchain_cursor_current(cursor); |
246 | if (!node) |
247 | break; |
248 | |
249 | /* |
250 | * Handle export of symbol and dso for this node by |
251 | * constructing an addr_location struct and then passing it to |
252 | * db_ids_from_al() to perform the export. |
253 | */ |
254 | addr_location__init(al: &al); |
255 | al.sym = node->ms.sym; |
256 | al.map = map__get(map: node->ms.map); |
257 | al.maps = maps__get(maps: thread__maps(thread)); |
258 | al.addr = node->ip; |
259 | |
260 | if (al.map && !al.sym) |
261 | al.sym = dso__find_symbol(dso: map__dso(map: al.map), addr: al.addr); |
262 | |
263 | db_ids_from_al(dbe, al: &al, dso_db_id: &dso_db_id, sym_db_id: &sym_db_id, offset: &offset); |
264 | |
265 | /* add node to the call path tree if it doesn't exist */ |
266 | current = call_path__findnew(cpr: dbe->cpr, current, |
267 | sym: al.sym, ip: node->ip, |
268 | ks: kernel_start); |
269 | |
270 | callchain_cursor_advance(cursor); |
271 | addr_location__exit(al: &al); |
272 | } |
273 | |
274 | /* Reset the callchain order to its prior value. */ |
275 | callchain_param.order = saved_order; |
276 | |
277 | if (current == &dbe->cpr->call_path) { |
278 | /* Bail because the callchain was empty. */ |
279 | return NULL; |
280 | } |
281 | |
282 | return current; |
283 | } |
284 | |
285 | int db_export__branch_type(struct db_export *dbe, u32 branch_type, |
286 | const char *name) |
287 | { |
288 | if (dbe->export_branch_type) |
289 | return dbe->export_branch_type(dbe, branch_type, name); |
290 | |
291 | return 0; |
292 | } |
293 | |
294 | static int db_export__threads(struct db_export *dbe, struct thread *thread, |
295 | struct thread *main_thread, |
296 | struct machine *machine, struct comm **comm_ptr) |
297 | { |
298 | struct comm *comm = NULL; |
299 | struct comm *curr_comm; |
300 | int err; |
301 | |
302 | if (main_thread) { |
303 | /* |
304 | * A thread has a reference to the main thread, so export the |
305 | * main thread first. |
306 | */ |
307 | err = db_export__thread(dbe, thread: main_thread, machine, main_thread); |
308 | if (err) |
309 | return err; |
310 | /* |
311 | * Export comm before exporting the non-main thread because |
312 | * db_export__comm_thread() can be called further below. |
313 | */ |
314 | comm = machine__thread_exec_comm(machine, thread: main_thread); |
315 | if (comm) { |
316 | err = db_export__exec_comm(dbe, comm, main_thread); |
317 | if (err) |
318 | return err; |
319 | *comm_ptr = comm; |
320 | } |
321 | } |
322 | |
323 | if (thread != main_thread) { |
324 | /* |
325 | * For a non-main thread, db_export__comm_thread() must be |
326 | * called only if thread has not previously been exported. |
327 | */ |
328 | bool export_comm_thread = comm && !thread__db_id(thread); |
329 | |
330 | err = db_export__thread(dbe, thread, machine, main_thread); |
331 | if (err) |
332 | return err; |
333 | |
334 | if (export_comm_thread) { |
335 | err = db_export__comm_thread(dbe, comm, thread); |
336 | if (err) |
337 | return err; |
338 | } |
339 | } |
340 | |
341 | curr_comm = thread__comm(thread); |
342 | if (curr_comm) |
343 | return db_export__comm(dbe, comm: curr_comm, thread); |
344 | |
345 | return 0; |
346 | } |
347 | |
348 | int db_export__sample(struct db_export *dbe, union perf_event *event, |
349 | struct perf_sample *sample, struct evsel *evsel, |
350 | struct addr_location *al, struct addr_location *addr_al) |
351 | { |
352 | struct thread *thread = al->thread; |
353 | struct export_sample es = { |
354 | .event = event, |
355 | .sample = sample, |
356 | .evsel = evsel, |
357 | .al = al, |
358 | }; |
359 | struct thread *main_thread; |
360 | struct comm *comm = NULL; |
361 | struct machine *machine; |
362 | int err; |
363 | |
364 | err = db_export__evsel(dbe, evsel); |
365 | if (err) |
366 | return err; |
367 | |
368 | machine = maps__machine(maps: al->maps); |
369 | err = db_export__machine(dbe, machine); |
370 | if (err) |
371 | return err; |
372 | |
373 | main_thread = thread__main_thread(machine, thread); |
374 | |
375 | err = db_export__threads(dbe, thread, main_thread, machine, comm_ptr: &comm); |
376 | if (err) |
377 | goto out_put; |
378 | |
379 | if (comm) |
380 | es.comm_db_id = comm->db_id; |
381 | |
382 | es.db_id = ++dbe->sample_last_db_id; |
383 | |
384 | err = db_ids_from_al(dbe, al, dso_db_id: &es.dso_db_id, sym_db_id: &es.sym_db_id, offset: &es.offset); |
385 | if (err) |
386 | goto out_put; |
387 | |
388 | if (dbe->cpr) { |
389 | struct call_path *cp = call_path_from_sample(dbe, machine, |
390 | thread, sample, |
391 | evsel); |
392 | if (cp) { |
393 | db_export__call_path(dbe, cp); |
394 | es.call_path_id = cp->db_id; |
395 | } |
396 | } |
397 | |
398 | if (addr_al) { |
399 | err = db_ids_from_al(dbe, al: addr_al, dso_db_id: &es.addr_dso_db_id, |
400 | sym_db_id: &es.addr_sym_db_id, offset: &es.addr_offset); |
401 | if (err) |
402 | goto out_put; |
403 | if (dbe->crp) { |
404 | err = thread_stack__process(thread, comm, sample, from_al: al, |
405 | to_al: addr_al, ref: es.db_id, |
406 | crp: dbe->crp); |
407 | if (err) |
408 | goto out_put; |
409 | } |
410 | } |
411 | |
412 | if (dbe->export_sample) |
413 | err = dbe->export_sample(dbe, &es); |
414 | |
415 | out_put: |
416 | thread__put(thread: main_thread); |
417 | return err; |
418 | } |
419 | |
420 | static struct { |
421 | u32 branch_type; |
422 | const char *name; |
423 | } branch_types[] = { |
424 | {0, "no branch" }, |
425 | {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL, "call" }, |
426 | {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN, "return" }, |
427 | {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CONDITIONAL, "conditional jump" }, |
428 | {PERF_IP_FLAG_BRANCH, "unconditional jump" }, |
429 | {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_INTERRUPT, |
430 | "software interrupt" }, |
431 | {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN | PERF_IP_FLAG_INTERRUPT, |
432 | "return from interrupt" }, |
433 | {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_SYSCALLRET, |
434 | "system call" }, |
435 | {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN | PERF_IP_FLAG_SYSCALLRET, |
436 | "return from system call" }, |
437 | {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_ASYNC, "asynchronous branch" }, |
438 | {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_ASYNC | |
439 | PERF_IP_FLAG_INTERRUPT, "hardware interrupt" }, |
440 | {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TX_ABORT, "transaction abort" }, |
441 | {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TRACE_BEGIN, "trace begin" }, |
442 | {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TRACE_END, "trace end" }, |
443 | {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_VMENTRY, "vm entry" }, |
444 | {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_VMEXIT, "vm exit" }, |
445 | {0, NULL} |
446 | }; |
447 | |
448 | int db_export__branch_types(struct db_export *dbe) |
449 | { |
450 | int i, err = 0; |
451 | |
452 | for (i = 0; branch_types[i].name ; i++) { |
453 | err = db_export__branch_type(dbe, branch_type: branch_types[i].branch_type, |
454 | name: branch_types[i].name); |
455 | if (err) |
456 | break; |
457 | } |
458 | |
459 | /* Add trace begin / end variants */ |
460 | for (i = 0; branch_types[i].name ; i++) { |
461 | const char *name = branch_types[i].name; |
462 | u32 type = branch_types[i].branch_type; |
463 | char buf[64]; |
464 | |
465 | if (type == PERF_IP_FLAG_BRANCH || |
466 | (type & (PERF_IP_FLAG_TRACE_BEGIN | PERF_IP_FLAG_TRACE_END))) |
467 | continue; |
468 | |
469 | snprintf(buf, size: sizeof(buf), fmt: "trace begin / %s" , name); |
470 | err = db_export__branch_type(dbe, branch_type: type | PERF_IP_FLAG_TRACE_BEGIN, name: buf); |
471 | if (err) |
472 | break; |
473 | |
474 | snprintf(buf, size: sizeof(buf), fmt: "%s / trace end" , name); |
475 | err = db_export__branch_type(dbe, branch_type: type | PERF_IP_FLAG_TRACE_END, name: buf); |
476 | if (err) |
477 | break; |
478 | } |
479 | |
480 | return err; |
481 | } |
482 | |
483 | int db_export__call_path(struct db_export *dbe, struct call_path *cp) |
484 | { |
485 | int err; |
486 | |
487 | if (cp->db_id) |
488 | return 0; |
489 | |
490 | if (cp->parent) { |
491 | err = db_export__call_path(dbe, cp: cp->parent); |
492 | if (err) |
493 | return err; |
494 | } |
495 | |
496 | cp->db_id = ++dbe->call_path_last_db_id; |
497 | |
498 | if (dbe->export_call_path) |
499 | return dbe->export_call_path(dbe, cp); |
500 | |
501 | return 0; |
502 | } |
503 | |
504 | int db_export__call_return(struct db_export *dbe, struct call_return *cr, |
505 | u64 *parent_db_id) |
506 | { |
507 | int err; |
508 | |
509 | err = db_export__call_path(dbe, cp: cr->cp); |
510 | if (err) |
511 | return err; |
512 | |
513 | if (!cr->db_id) |
514 | cr->db_id = ++dbe->call_return_last_db_id; |
515 | |
516 | if (parent_db_id) { |
517 | if (!*parent_db_id) |
518 | *parent_db_id = ++dbe->call_return_last_db_id; |
519 | cr->parent_db_id = *parent_db_id; |
520 | } |
521 | |
522 | if (dbe->export_call_return) |
523 | return dbe->export_call_return(dbe, cr); |
524 | |
525 | return 0; |
526 | } |
527 | |
528 | static int db_export__pid_tid(struct db_export *dbe, struct machine *machine, |
529 | pid_t pid, pid_t tid, u64 *db_id, |
530 | struct comm **comm_ptr, bool *is_idle) |
531 | { |
532 | struct thread *thread = machine__find_thread(machine, pid, tid); |
533 | struct thread *main_thread; |
534 | int err = 0; |
535 | |
536 | if (!thread || !thread__comm_set(thread)) |
537 | goto out_put; |
538 | |
539 | *is_idle = !thread__pid(thread) && !thread__tid(thread); |
540 | |
541 | main_thread = thread__main_thread(machine, thread); |
542 | |
543 | err = db_export__threads(dbe, thread, main_thread, machine, comm_ptr); |
544 | |
545 | *db_id = thread__db_id(thread); |
546 | |
547 | thread__put(thread: main_thread); |
548 | out_put: |
549 | thread__put(thread); |
550 | |
551 | return err; |
552 | } |
553 | |
554 | int db_export__switch(struct db_export *dbe, union perf_event *event, |
555 | struct perf_sample *sample, struct machine *machine) |
556 | { |
557 | bool out = event->header.misc & PERF_RECORD_MISC_SWITCH_OUT; |
558 | bool out_preempt = out && |
559 | (event->header.misc & PERF_RECORD_MISC_SWITCH_OUT_PREEMPT); |
560 | int flags = out | (out_preempt << 1); |
561 | bool is_idle_a = false, is_idle_b = false; |
562 | u64 th_a_id = 0, th_b_id = 0; |
563 | u64 comm_out_id, comm_in_id; |
564 | struct comm *comm_a = NULL; |
565 | struct comm *comm_b = NULL; |
566 | u64 th_out_id, th_in_id; |
567 | u64 db_id; |
568 | int err; |
569 | |
570 | err = db_export__machine(dbe, machine); |
571 | if (err) |
572 | return err; |
573 | |
574 | err = db_export__pid_tid(dbe, machine, pid: sample->pid, tid: sample->tid, |
575 | db_id: &th_a_id, comm_ptr: &comm_a, is_idle: &is_idle_a); |
576 | if (err) |
577 | return err; |
578 | |
579 | if (event->header.type == PERF_RECORD_SWITCH_CPU_WIDE) { |
580 | pid_t pid = event->context_switch.next_prev_pid; |
581 | pid_t tid = event->context_switch.next_prev_tid; |
582 | |
583 | err = db_export__pid_tid(dbe, machine, pid, tid, db_id: &th_b_id, |
584 | comm_ptr: &comm_b, is_idle: &is_idle_b); |
585 | if (err) |
586 | return err; |
587 | } |
588 | |
589 | /* |
590 | * Do not export if both threads are unknown (i.e. not being traced), |
591 | * or one is unknown and the other is the idle task. |
592 | */ |
593 | if ((!th_a_id || is_idle_a) && (!th_b_id || is_idle_b)) |
594 | return 0; |
595 | |
596 | db_id = ++dbe->context_switch_last_db_id; |
597 | |
598 | if (out) { |
599 | th_out_id = th_a_id; |
600 | th_in_id = th_b_id; |
601 | comm_out_id = comm_a ? comm_a->db_id : 0; |
602 | comm_in_id = comm_b ? comm_b->db_id : 0; |
603 | } else { |
604 | th_out_id = th_b_id; |
605 | th_in_id = th_a_id; |
606 | comm_out_id = comm_b ? comm_b->db_id : 0; |
607 | comm_in_id = comm_a ? comm_a->db_id : 0; |
608 | } |
609 | |
610 | if (dbe->export_context_switch) |
611 | return dbe->export_context_switch(dbe, db_id, machine, sample, |
612 | th_out_id, comm_out_id, |
613 | th_in_id, comm_in_id, flags); |
614 | return 0; |
615 | } |
616 | |