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