]> asedeno.scripts.mit.edu Git - linux.git/blob - tools/perf/util/db-export.c
34cf197fe74f577db3e3b944a8f1855d56d35c79
[linux.git] / tools / perf / util / db-export.c
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 "evsel.h"
11 #include "machine.h"
12 #include "thread.h"
13 #include "comm.h"
14 #include "symbol.h"
15 #include "map.h"
16 #include "event.h"
17 #include "thread-stack.h"
18 #include "callchain.h"
19 #include "call-path.h"
20 #include "db-export.h"
21 #include <linux/zalloc.h>
22
23 int db_export__init(struct db_export *dbe)
24 {
25         memset(dbe, 0, sizeof(struct db_export));
26         return 0;
27 }
28
29 void db_export__exit(struct db_export *dbe)
30 {
31         call_return_processor__free(dbe->crp);
32         dbe->crp = NULL;
33 }
34
35 int db_export__evsel(struct db_export *dbe, struct perf_evsel *evsel)
36 {
37         if (evsel->db_id)
38                 return 0;
39
40         evsel->db_id = ++dbe->evsel_last_db_id;
41
42         if (dbe->export_evsel)
43                 return dbe->export_evsel(dbe, evsel);
44
45         return 0;
46 }
47
48 int db_export__machine(struct db_export *dbe, struct machine *machine)
49 {
50         if (machine->db_id)
51                 return 0;
52
53         machine->db_id = ++dbe->machine_last_db_id;
54
55         if (dbe->export_machine)
56                 return dbe->export_machine(dbe, machine);
57
58         return 0;
59 }
60
61 int db_export__thread(struct db_export *dbe, struct thread *thread,
62                       struct machine *machine, struct comm *comm)
63 {
64         struct thread *main_thread;
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                 if (thread->pid_ == thread->tid) {
75                         main_thread = thread;
76                 } else {
77                         main_thread = machine__findnew_thread(machine,
78                                                               thread->pid_,
79                                                               thread->pid_);
80                         if (!main_thread)
81                                 return -ENOMEM;
82                         err = db_export__thread(dbe, main_thread, machine,
83                                                 comm);
84                         if (err)
85                                 goto out_put;
86                         if (comm) {
87                                 err = db_export__comm_thread(dbe, comm, thread);
88                                 if (err)
89                                         goto out_put;
90                         }
91                 }
92                 main_thread_db_id = main_thread->db_id;
93                 if (main_thread != thread)
94                         thread__put(main_thread);
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 out_put:
104         thread__put(main_thread);
105         return err;
106 }
107
108 int db_export__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         comm->db_id = ++dbe->comm_last_db_id;
117
118         if (dbe->export_comm) {
119                 err = dbe->export_comm(dbe, comm);
120                 if (err)
121                         return err;
122         }
123
124         return db_export__comm_thread(dbe, comm, main_thread);
125 }
126
127 int db_export__comm_thread(struct db_export *dbe, struct comm *comm,
128                            struct thread *thread)
129 {
130         u64 db_id;
131
132         db_id = ++dbe->comm_thread_last_db_id;
133
134         if (dbe->export_comm_thread)
135                 return dbe->export_comm_thread(dbe, db_id, comm, thread);
136
137         return 0;
138 }
139
140 int db_export__dso(struct db_export *dbe, struct dso *dso,
141                    struct machine *machine)
142 {
143         if (dso->db_id)
144                 return 0;
145
146         dso->db_id = ++dbe->dso_last_db_id;
147
148         if (dbe->export_dso)
149                 return dbe->export_dso(dbe, dso, machine);
150
151         return 0;
152 }
153
154 int db_export__symbol(struct db_export *dbe, struct symbol *sym,
155                       struct dso *dso)
156 {
157         u64 *sym_db_id = symbol__priv(sym);
158
159         if (*sym_db_id)
160                 return 0;
161
162         *sym_db_id = ++dbe->symbol_last_db_id;
163
164         if (dbe->export_symbol)
165                 return dbe->export_symbol(dbe, sym, dso);
166
167         return 0;
168 }
169
170 static int db_ids_from_al(struct db_export *dbe, struct addr_location *al,
171                           u64 *dso_db_id, u64 *sym_db_id, u64 *offset)
172 {
173         int err;
174
175         if (al->map) {
176                 struct dso *dso = al->map->dso;
177
178                 err = db_export__dso(dbe, dso, al->machine);
179                 if (err)
180                         return err;
181                 *dso_db_id = dso->db_id;
182
183                 if (!al->sym) {
184                         al->sym = symbol__new(al->addr, 0, 0, 0, "unknown");
185                         if (al->sym)
186                                 dso__insert_symbol(dso, al->sym);
187                 }
188
189                 if (al->sym) {
190                         u64 *db_id = symbol__priv(al->sym);
191
192                         err = db_export__symbol(dbe, al->sym, dso);
193                         if (err)
194                                 return err;
195                         *sym_db_id = *db_id;
196                         *offset = al->addr - al->sym->start;
197                 }
198         }
199
200         return 0;
201 }
202
203 static struct call_path *call_path_from_sample(struct db_export *dbe,
204                                                struct machine *machine,
205                                                struct thread *thread,
206                                                struct perf_sample *sample,
207                                                struct perf_evsel *evsel)
208 {
209         u64 kernel_start = machine__kernel_start(machine);
210         struct call_path *current = &dbe->cpr->call_path;
211         enum chain_order saved_order = callchain_param.order;
212         int err;
213
214         if (!symbol_conf.use_callchain || !sample->callchain)
215                 return NULL;
216
217         /*
218          * Since the call path tree must be built starting with the root, we
219          * must use ORDER_CALL for call chain resolution, in order to process
220          * the callchain starting with the root node and ending with the leaf.
221          */
222         callchain_param.order = ORDER_CALLER;
223         err = thread__resolve_callchain(thread, &callchain_cursor, evsel,
224                                         sample, NULL, NULL, PERF_MAX_STACK_DEPTH);
225         if (err) {
226                 callchain_param.order = saved_order;
227                 return NULL;
228         }
229         callchain_cursor_commit(&callchain_cursor);
230
231         while (1) {
232                 struct callchain_cursor_node *node;
233                 struct addr_location al;
234                 u64 dso_db_id = 0, sym_db_id = 0, offset = 0;
235
236                 memset(&al, 0, sizeof(al));
237
238                 node = callchain_cursor_current(&callchain_cursor);
239                 if (!node)
240                         break;
241                 /*
242                  * Handle export of symbol and dso for this node by
243                  * constructing an addr_location struct and then passing it to
244                  * db_ids_from_al() to perform the export.
245                  */
246                 al.sym = node->sym;
247                 al.map = node->map;
248                 al.machine = machine;
249                 al.addr = node->ip;
250
251                 if (al.map && !al.sym)
252                         al.sym = dso__find_symbol(al.map->dso, al.addr);
253
254                 db_ids_from_al(dbe, &al, &dso_db_id, &sym_db_id, &offset);
255
256                 /* add node to the call path tree if it doesn't exist */
257                 current = call_path__findnew(dbe->cpr, current,
258                                              al.sym, node->ip,
259                                              kernel_start);
260
261                 callchain_cursor_advance(&callchain_cursor);
262         }
263
264         /* Reset the callchain order to its prior value. */
265         callchain_param.order = saved_order;
266
267         if (current == &dbe->cpr->call_path) {
268                 /* Bail because the callchain was empty. */
269                 return NULL;
270         }
271
272         return current;
273 }
274
275 int db_export__branch_type(struct db_export *dbe, u32 branch_type,
276                            const char *name)
277 {
278         if (dbe->export_branch_type)
279                 return dbe->export_branch_type(dbe, branch_type, name);
280
281         return 0;
282 }
283
284 int db_export__sample(struct db_export *dbe, union perf_event *event,
285                       struct perf_sample *sample, struct perf_evsel *evsel,
286                       struct addr_location *al)
287 {
288         struct thread* thread = al->thread;
289         struct export_sample es = {
290                 .event = event,
291                 .sample = sample,
292                 .evsel = evsel,
293                 .al = al,
294         };
295         struct thread *main_thread;
296         struct comm *comm = NULL;
297         int err;
298
299         err = db_export__evsel(dbe, evsel);
300         if (err)
301                 return err;
302
303         err = db_export__machine(dbe, al->machine);
304         if (err)
305                 return err;
306
307         main_thread = thread__main_thread(al->machine, thread);
308         if (main_thread)
309                 comm = machine__thread_exec_comm(al->machine, main_thread);
310
311         err = db_export__thread(dbe, thread, al->machine, comm);
312         if (err)
313                 goto out_put;
314
315         if (comm) {
316                 err = db_export__comm(dbe, comm, main_thread);
317                 if (err)
318                         goto out_put;
319                 es.comm_db_id = comm->db_id;
320         }
321
322         es.db_id = ++dbe->sample_last_db_id;
323
324         err = db_ids_from_al(dbe, al, &es.dso_db_id, &es.sym_db_id, &es.offset);
325         if (err)
326                 goto out_put;
327
328         if (dbe->cpr) {
329                 struct call_path *cp = call_path_from_sample(dbe, al->machine,
330                                                              thread, sample,
331                                                              evsel);
332                 if (cp) {
333                         db_export__call_path(dbe, cp);
334                         es.call_path_id = cp->db_id;
335                 }
336         }
337
338         if ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) &&
339             sample_addr_correlates_sym(&evsel->attr)) {
340                 struct addr_location addr_al;
341
342                 thread__resolve(thread, &addr_al, sample);
343                 err = db_ids_from_al(dbe, &addr_al, &es.addr_dso_db_id,
344                                      &es.addr_sym_db_id, &es.addr_offset);
345                 if (err)
346                         goto out_put;
347                 if (dbe->crp) {
348                         err = thread_stack__process(thread, comm, sample, al,
349                                                     &addr_al, es.db_id,
350                                                     dbe->crp);
351                         if (err)
352                                 goto out_put;
353                 }
354         }
355
356         if (dbe->export_sample)
357                 err = dbe->export_sample(dbe, &es);
358
359 out_put:
360         thread__put(main_thread);
361         return err;
362 }
363
364 static struct {
365         u32 branch_type;
366         const char *name;
367 } branch_types[] = {
368         {0, "no branch"},
369         {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL, "call"},
370         {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN, "return"},
371         {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CONDITIONAL, "conditional jump"},
372         {PERF_IP_FLAG_BRANCH, "unconditional jump"},
373         {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_INTERRUPT,
374          "software interrupt"},
375         {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN | PERF_IP_FLAG_INTERRUPT,
376          "return from interrupt"},
377         {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_SYSCALLRET,
378          "system call"},
379         {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN | PERF_IP_FLAG_SYSCALLRET,
380          "return from system call"},
381         {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_ASYNC, "asynchronous branch"},
382         {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_ASYNC |
383          PERF_IP_FLAG_INTERRUPT, "hardware interrupt"},
384         {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TX_ABORT, "transaction abort"},
385         {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TRACE_BEGIN, "trace begin"},
386         {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TRACE_END, "trace end"},
387         {0, NULL}
388 };
389
390 int db_export__branch_types(struct db_export *dbe)
391 {
392         int i, err = 0;
393
394         for (i = 0; branch_types[i].name ; i++) {
395                 err = db_export__branch_type(dbe, branch_types[i].branch_type,
396                                              branch_types[i].name);
397                 if (err)
398                         break;
399         }
400
401         /* Add trace begin / end variants */
402         for (i = 0; branch_types[i].name ; i++) {
403                 const char *name = branch_types[i].name;
404                 u32 type = branch_types[i].branch_type;
405                 char buf[64];
406
407                 if (type == PERF_IP_FLAG_BRANCH ||
408                     (type & (PERF_IP_FLAG_TRACE_BEGIN | PERF_IP_FLAG_TRACE_END)))
409                         continue;
410
411                 snprintf(buf, sizeof(buf), "trace begin / %s", name);
412                 err = db_export__branch_type(dbe, type | PERF_IP_FLAG_TRACE_BEGIN, buf);
413                 if (err)
414                         break;
415
416                 snprintf(buf, sizeof(buf), "%s / trace end", name);
417                 err = db_export__branch_type(dbe, type | PERF_IP_FLAG_TRACE_END, buf);
418                 if (err)
419                         break;
420         }
421
422         return err;
423 }
424
425 int db_export__call_path(struct db_export *dbe, struct call_path *cp)
426 {
427         int err;
428
429         if (cp->db_id)
430                 return 0;
431
432         if (cp->parent) {
433                 err = db_export__call_path(dbe, cp->parent);
434                 if (err)
435                         return err;
436         }
437
438         cp->db_id = ++dbe->call_path_last_db_id;
439
440         if (dbe->export_call_path)
441                 return dbe->export_call_path(dbe, cp);
442
443         return 0;
444 }
445
446 int db_export__call_return(struct db_export *dbe, struct call_return *cr,
447                            u64 *parent_db_id)
448 {
449         int err;
450
451         err = db_export__call_path(dbe, cr->cp);
452         if (err)
453                 return err;
454
455         if (!cr->db_id)
456                 cr->db_id = ++dbe->call_return_last_db_id;
457
458         if (parent_db_id) {
459                 if (!*parent_db_id)
460                         *parent_db_id = ++dbe->call_return_last_db_id;
461                 cr->parent_db_id = *parent_db_id;
462         }
463
464         if (dbe->export_call_return)
465                 return dbe->export_call_return(dbe, cr);
466
467         return 0;
468 }