Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * db-export.c: Support for exporting data suitable for import to a database
0004  * Copyright (c) 2014, Intel Corporation.
0005  */
0006 
0007 #include <errno.h>
0008 #include <stdlib.h>
0009 
0010 #include "dso.h"
0011 #include "evsel.h"
0012 #include "machine.h"
0013 #include "thread.h"
0014 #include "comm.h"
0015 #include "symbol.h"
0016 #include "map.h"
0017 #include "event.h"
0018 #include "thread-stack.h"
0019 #include "callchain.h"
0020 #include "call-path.h"
0021 #include "db-export.h"
0022 #include <linux/zalloc.h>
0023 
0024 int db_export__init(struct db_export *dbe)
0025 {
0026     memset(dbe, 0, sizeof(struct db_export));
0027     return 0;
0028 }
0029 
0030 void db_export__exit(struct db_export *dbe)
0031 {
0032     call_return_processor__free(dbe->crp);
0033     dbe->crp = NULL;
0034 }
0035 
0036 int db_export__evsel(struct db_export *dbe, struct evsel *evsel)
0037 {
0038     if (evsel->db_id)
0039         return 0;
0040 
0041     evsel->db_id = ++dbe->evsel_last_db_id;
0042 
0043     if (dbe->export_evsel)
0044         return dbe->export_evsel(dbe, evsel);
0045 
0046     return 0;
0047 }
0048 
0049 int db_export__machine(struct db_export *dbe, struct machine *machine)
0050 {
0051     if (machine->db_id)
0052         return 0;
0053 
0054     machine->db_id = ++dbe->machine_last_db_id;
0055 
0056     if (dbe->export_machine)
0057         return dbe->export_machine(dbe, machine);
0058 
0059     return 0;
0060 }
0061 
0062 int db_export__thread(struct db_export *dbe, struct thread *thread,
0063               struct machine *machine, struct thread *main_thread)
0064 {
0065     u64 main_thread_db_id = 0;
0066 
0067     if (thread->db_id)
0068         return 0;
0069 
0070     thread->db_id = ++dbe->thread_last_db_id;
0071 
0072     if (main_thread)
0073         main_thread_db_id = main_thread->db_id;
0074 
0075     if (dbe->export_thread)
0076         return dbe->export_thread(dbe, thread, main_thread_db_id,
0077                       machine);
0078 
0079     return 0;
0080 }
0081 
0082 static int __db_export__comm(struct db_export *dbe, struct comm *comm,
0083                  struct thread *thread)
0084 {
0085     comm->db_id = ++dbe->comm_last_db_id;
0086 
0087     if (dbe->export_comm)
0088         return dbe->export_comm(dbe, comm, thread);
0089 
0090     return 0;
0091 }
0092 
0093 int db_export__comm(struct db_export *dbe, struct comm *comm,
0094             struct thread *thread)
0095 {
0096     if (comm->db_id)
0097         return 0;
0098 
0099     return __db_export__comm(dbe, comm, thread);
0100 }
0101 
0102 /*
0103  * Export the "exec" comm. The "exec" comm is the program / application command
0104  * name at the time it first executes. It is used to group threads for the same
0105  * program. Note that the main thread pid (or thread group id tgid) cannot be
0106  * used because it does not change when a new program is exec'ed.
0107  */
0108 int db_export__exec_comm(struct db_export *dbe, struct comm *comm,
0109              struct thread *main_thread)
0110 {
0111     int err;
0112 
0113     if (comm->db_id)
0114         return 0;
0115 
0116     err = __db_export__comm(dbe, comm, main_thread);
0117     if (err)
0118         return err;
0119 
0120     /*
0121      * Record the main thread for this comm. Note that the main thread can
0122      * have many "exec" comms because there will be a new one every time it
0123      * exec's. An "exec" comm however will only ever have 1 main thread.
0124      * That is different to any other threads for that same program because
0125      * exec() will effectively kill them, so the relationship between the
0126      * "exec" comm and non-main threads is 1-to-1. That is why
0127      * db_export__comm_thread() is called here for the main thread, but it
0128      * is called for non-main threads when they are exported.
0129      */
0130     return db_export__comm_thread(dbe, comm, main_thread);
0131 }
0132 
0133 int db_export__comm_thread(struct db_export *dbe, struct comm *comm,
0134                struct thread *thread)
0135 {
0136     u64 db_id;
0137 
0138     db_id = ++dbe->comm_thread_last_db_id;
0139 
0140     if (dbe->export_comm_thread)
0141         return dbe->export_comm_thread(dbe, db_id, comm, thread);
0142 
0143     return 0;
0144 }
0145 
0146 int db_export__dso(struct db_export *dbe, struct dso *dso,
0147            struct machine *machine)
0148 {
0149     if (dso->db_id)
0150         return 0;
0151 
0152     dso->db_id = ++dbe->dso_last_db_id;
0153 
0154     if (dbe->export_dso)
0155         return dbe->export_dso(dbe, dso, machine);
0156 
0157     return 0;
0158 }
0159 
0160 int db_export__symbol(struct db_export *dbe, struct symbol *sym,
0161               struct dso *dso)
0162 {
0163     u64 *sym_db_id = symbol__priv(sym);
0164 
0165     if (*sym_db_id)
0166         return 0;
0167 
0168     *sym_db_id = ++dbe->symbol_last_db_id;
0169 
0170     if (dbe->export_symbol)
0171         return dbe->export_symbol(dbe, sym, dso);
0172 
0173     return 0;
0174 }
0175 
0176 static int db_ids_from_al(struct db_export *dbe, struct addr_location *al,
0177               u64 *dso_db_id, u64 *sym_db_id, u64 *offset)
0178 {
0179     int err;
0180 
0181     if (al->map) {
0182         struct dso *dso = al->map->dso;
0183 
0184         err = db_export__dso(dbe, dso, al->maps->machine);
0185         if (err)
0186             return err;
0187         *dso_db_id = dso->db_id;
0188 
0189         if (!al->sym) {
0190             al->sym = symbol__new(al->addr, 0, 0, 0, "unknown");
0191             if (al->sym)
0192                 dso__insert_symbol(dso, al->sym);
0193         }
0194 
0195         if (al->sym) {
0196             u64 *db_id = symbol__priv(al->sym);
0197 
0198             err = db_export__symbol(dbe, al->sym, dso);
0199             if (err)
0200                 return err;
0201             *sym_db_id = *db_id;
0202             *offset = al->addr - al->sym->start;
0203         }
0204     }
0205 
0206     return 0;
0207 }
0208 
0209 static struct call_path *call_path_from_sample(struct db_export *dbe,
0210                            struct machine *machine,
0211                            struct thread *thread,
0212                            struct perf_sample *sample,
0213                            struct evsel *evsel)
0214 {
0215     u64 kernel_start = machine__kernel_start(machine);
0216     struct call_path *current = &dbe->cpr->call_path;
0217     enum chain_order saved_order = callchain_param.order;
0218     int err;
0219 
0220     if (!symbol_conf.use_callchain || !sample->callchain)
0221         return NULL;
0222 
0223     /*
0224      * Since the call path tree must be built starting with the root, we
0225      * must use ORDER_CALL for call chain resolution, in order to process
0226      * the callchain starting with the root node and ending with the leaf.
0227      */
0228     callchain_param.order = ORDER_CALLER;
0229     err = thread__resolve_callchain(thread, &callchain_cursor, evsel,
0230                     sample, NULL, NULL, PERF_MAX_STACK_DEPTH);
0231     if (err) {
0232         callchain_param.order = saved_order;
0233         return NULL;
0234     }
0235     callchain_cursor_commit(&callchain_cursor);
0236 
0237     while (1) {
0238         struct callchain_cursor_node *node;
0239         struct addr_location al;
0240         u64 dso_db_id = 0, sym_db_id = 0, offset = 0;
0241 
0242         memset(&al, 0, sizeof(al));
0243 
0244         node = callchain_cursor_current(&callchain_cursor);
0245         if (!node)
0246             break;
0247         /*
0248          * Handle export of symbol and dso for this node by
0249          * constructing an addr_location struct and then passing it to
0250          * db_ids_from_al() to perform the export.
0251          */
0252         al.sym = node->ms.sym;
0253         al.map = node->ms.map;
0254         al.maps = thread->maps;
0255         al.addr = node->ip;
0256 
0257         if (al.map && !al.sym)
0258             al.sym = dso__find_symbol(al.map->dso, al.addr);
0259 
0260         db_ids_from_al(dbe, &al, &dso_db_id, &sym_db_id, &offset);
0261 
0262         /* add node to the call path tree if it doesn't exist */
0263         current = call_path__findnew(dbe->cpr, current,
0264                          al.sym, node->ip,
0265                          kernel_start);
0266 
0267         callchain_cursor_advance(&callchain_cursor);
0268     }
0269 
0270     /* Reset the callchain order to its prior value. */
0271     callchain_param.order = saved_order;
0272 
0273     if (current == &dbe->cpr->call_path) {
0274         /* Bail because the callchain was empty. */
0275         return NULL;
0276     }
0277 
0278     return current;
0279 }
0280 
0281 int db_export__branch_type(struct db_export *dbe, u32 branch_type,
0282                const char *name)
0283 {
0284     if (dbe->export_branch_type)
0285         return dbe->export_branch_type(dbe, branch_type, name);
0286 
0287     return 0;
0288 }
0289 
0290 static int db_export__threads(struct db_export *dbe, struct thread *thread,
0291                   struct thread *main_thread,
0292                   struct machine *machine, struct comm **comm_ptr)
0293 {
0294     struct comm *comm = NULL;
0295     struct comm *curr_comm;
0296     int err;
0297 
0298     if (main_thread) {
0299         /*
0300          * A thread has a reference to the main thread, so export the
0301          * main thread first.
0302          */
0303         err = db_export__thread(dbe, main_thread, machine, main_thread);
0304         if (err)
0305             return err;
0306         /*
0307          * Export comm before exporting the non-main thread because
0308          * db_export__comm_thread() can be called further below.
0309          */
0310         comm = machine__thread_exec_comm(machine, main_thread);
0311         if (comm) {
0312             err = db_export__exec_comm(dbe, comm, main_thread);
0313             if (err)
0314                 return err;
0315             *comm_ptr = comm;
0316         }
0317     }
0318 
0319     if (thread != main_thread) {
0320         /*
0321          * For a non-main thread, db_export__comm_thread() must be
0322          * called only if thread has not previously been exported.
0323          */
0324         bool export_comm_thread = comm && !thread->db_id;
0325 
0326         err = db_export__thread(dbe, thread, machine, main_thread);
0327         if (err)
0328             return err;
0329 
0330         if (export_comm_thread) {
0331             err = db_export__comm_thread(dbe, comm, thread);
0332             if (err)
0333                 return err;
0334         }
0335     }
0336 
0337     curr_comm = thread__comm(thread);
0338     if (curr_comm)
0339         return db_export__comm(dbe, curr_comm, thread);
0340 
0341     return 0;
0342 }
0343 
0344 int db_export__sample(struct db_export *dbe, union perf_event *event,
0345               struct perf_sample *sample, struct evsel *evsel,
0346               struct addr_location *al, struct addr_location *addr_al)
0347 {
0348     struct thread *thread = al->thread;
0349     struct export_sample es = {
0350         .event = event,
0351         .sample = sample,
0352         .evsel = evsel,
0353         .al = al,
0354     };
0355     struct thread *main_thread;
0356     struct comm *comm = NULL;
0357     int err;
0358 
0359     err = db_export__evsel(dbe, evsel);
0360     if (err)
0361         return err;
0362 
0363     err = db_export__machine(dbe, al->maps->machine);
0364     if (err)
0365         return err;
0366 
0367     main_thread = thread__main_thread(al->maps->machine, thread);
0368 
0369     err = db_export__threads(dbe, thread, main_thread, al->maps->machine, &comm);
0370     if (err)
0371         goto out_put;
0372 
0373     if (comm)
0374         es.comm_db_id = comm->db_id;
0375 
0376     es.db_id = ++dbe->sample_last_db_id;
0377 
0378     err = db_ids_from_al(dbe, al, &es.dso_db_id, &es.sym_db_id, &es.offset);
0379     if (err)
0380         goto out_put;
0381 
0382     if (dbe->cpr) {
0383         struct call_path *cp = call_path_from_sample(dbe, al->maps->machine,
0384                                  thread, sample,
0385                                  evsel);
0386         if (cp) {
0387             db_export__call_path(dbe, cp);
0388             es.call_path_id = cp->db_id;
0389         }
0390     }
0391 
0392     if (addr_al) {
0393         err = db_ids_from_al(dbe, addr_al, &es.addr_dso_db_id,
0394                      &es.addr_sym_db_id, &es.addr_offset);
0395         if (err)
0396             goto out_put;
0397         if (dbe->crp) {
0398             err = thread_stack__process(thread, comm, sample, al,
0399                             addr_al, es.db_id,
0400                             dbe->crp);
0401             if (err)
0402                 goto out_put;
0403         }
0404     }
0405 
0406     if (dbe->export_sample)
0407         err = dbe->export_sample(dbe, &es);
0408 
0409 out_put:
0410     thread__put(main_thread);
0411     return err;
0412 }
0413 
0414 static struct {
0415     u32 branch_type;
0416     const char *name;
0417 } branch_types[] = {
0418     {0, "no branch"},
0419     {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL, "call"},
0420     {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN, "return"},
0421     {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CONDITIONAL, "conditional jump"},
0422     {PERF_IP_FLAG_BRANCH, "unconditional jump"},
0423     {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_INTERRUPT,
0424      "software interrupt"},
0425     {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN | PERF_IP_FLAG_INTERRUPT,
0426      "return from interrupt"},
0427     {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_SYSCALLRET,
0428      "system call"},
0429     {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN | PERF_IP_FLAG_SYSCALLRET,
0430      "return from system call"},
0431     {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_ASYNC, "asynchronous branch"},
0432     {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_ASYNC |
0433      PERF_IP_FLAG_INTERRUPT, "hardware interrupt"},
0434     {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TX_ABORT, "transaction abort"},
0435     {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TRACE_BEGIN, "trace begin"},
0436     {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TRACE_END, "trace end"},
0437     {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_VMENTRY, "vm entry"},
0438     {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_VMEXIT, "vm exit"},
0439     {0, NULL}
0440 };
0441 
0442 int db_export__branch_types(struct db_export *dbe)
0443 {
0444     int i, err = 0;
0445 
0446     for (i = 0; branch_types[i].name ; i++) {
0447         err = db_export__branch_type(dbe, branch_types[i].branch_type,
0448                          branch_types[i].name);
0449         if (err)
0450             break;
0451     }
0452 
0453     /* Add trace begin / end variants */
0454     for (i = 0; branch_types[i].name ; i++) {
0455         const char *name = branch_types[i].name;
0456         u32 type = branch_types[i].branch_type;
0457         char buf[64];
0458 
0459         if (type == PERF_IP_FLAG_BRANCH ||
0460             (type & (PERF_IP_FLAG_TRACE_BEGIN | PERF_IP_FLAG_TRACE_END)))
0461             continue;
0462 
0463         snprintf(buf, sizeof(buf), "trace begin / %s", name);
0464         err = db_export__branch_type(dbe, type | PERF_IP_FLAG_TRACE_BEGIN, buf);
0465         if (err)
0466             break;
0467 
0468         snprintf(buf, sizeof(buf), "%s / trace end", name);
0469         err = db_export__branch_type(dbe, type | PERF_IP_FLAG_TRACE_END, buf);
0470         if (err)
0471             break;
0472     }
0473 
0474     return err;
0475 }
0476 
0477 int db_export__call_path(struct db_export *dbe, struct call_path *cp)
0478 {
0479     int err;
0480 
0481     if (cp->db_id)
0482         return 0;
0483 
0484     if (cp->parent) {
0485         err = db_export__call_path(dbe, cp->parent);
0486         if (err)
0487             return err;
0488     }
0489 
0490     cp->db_id = ++dbe->call_path_last_db_id;
0491 
0492     if (dbe->export_call_path)
0493         return dbe->export_call_path(dbe, cp);
0494 
0495     return 0;
0496 }
0497 
0498 int db_export__call_return(struct db_export *dbe, struct call_return *cr,
0499                u64 *parent_db_id)
0500 {
0501     int err;
0502 
0503     err = db_export__call_path(dbe, cr->cp);
0504     if (err)
0505         return err;
0506 
0507     if (!cr->db_id)
0508         cr->db_id = ++dbe->call_return_last_db_id;
0509 
0510     if (parent_db_id) {
0511         if (!*parent_db_id)
0512             *parent_db_id = ++dbe->call_return_last_db_id;
0513         cr->parent_db_id = *parent_db_id;
0514     }
0515 
0516     if (dbe->export_call_return)
0517         return dbe->export_call_return(dbe, cr);
0518 
0519     return 0;
0520 }
0521 
0522 static int db_export__pid_tid(struct db_export *dbe, struct machine *machine,
0523                   pid_t pid, pid_t tid, u64 *db_id,
0524                   struct comm **comm_ptr, bool *is_idle)
0525 {
0526     struct thread *thread = machine__find_thread(machine, pid, tid);
0527     struct thread *main_thread;
0528     int err = 0;
0529 
0530     if (!thread || !thread->comm_set)
0531         goto out_put;
0532 
0533     *is_idle = !thread->pid_ && !thread->tid;
0534 
0535     main_thread = thread__main_thread(machine, thread);
0536 
0537     err = db_export__threads(dbe, thread, main_thread, machine, comm_ptr);
0538 
0539     *db_id = thread->db_id;
0540 
0541     thread__put(main_thread);
0542 out_put:
0543     thread__put(thread);
0544 
0545     return err;
0546 }
0547 
0548 int db_export__switch(struct db_export *dbe, union perf_event *event,
0549               struct perf_sample *sample, struct machine *machine)
0550 {
0551     bool out = event->header.misc & PERF_RECORD_MISC_SWITCH_OUT;
0552     bool out_preempt = out &&
0553         (event->header.misc & PERF_RECORD_MISC_SWITCH_OUT_PREEMPT);
0554     int flags = out | (out_preempt << 1);
0555     bool is_idle_a = false, is_idle_b = false;
0556     u64 th_a_id = 0, th_b_id = 0;
0557     u64 comm_out_id, comm_in_id;
0558     struct comm *comm_a = NULL;
0559     struct comm *comm_b = NULL;
0560     u64 th_out_id, th_in_id;
0561     u64 db_id;
0562     int err;
0563 
0564     err = db_export__machine(dbe, machine);
0565     if (err)
0566         return err;
0567 
0568     err = db_export__pid_tid(dbe, machine, sample->pid, sample->tid,
0569                  &th_a_id, &comm_a, &is_idle_a);
0570     if (err)
0571         return err;
0572 
0573     if (event->header.type == PERF_RECORD_SWITCH_CPU_WIDE) {
0574         pid_t pid = event->context_switch.next_prev_pid;
0575         pid_t tid = event->context_switch.next_prev_tid;
0576 
0577         err = db_export__pid_tid(dbe, machine, pid, tid, &th_b_id,
0578                      &comm_b, &is_idle_b);
0579         if (err)
0580             return err;
0581     }
0582 
0583     /*
0584      * Do not export if both threads are unknown (i.e. not being traced),
0585      * or one is unknown and the other is the idle task.
0586      */
0587     if ((!th_a_id || is_idle_a) && (!th_b_id || is_idle_b))
0588         return 0;
0589 
0590     db_id = ++dbe->context_switch_last_db_id;
0591 
0592     if (out) {
0593         th_out_id   = th_a_id;
0594         th_in_id    = th_b_id;
0595         comm_out_id = comm_a ? comm_a->db_id : 0;
0596         comm_in_id  = comm_b ? comm_b->db_id : 0;
0597     } else {
0598         th_out_id   = th_b_id;
0599         th_in_id    = th_a_id;
0600         comm_out_id = comm_b ? comm_b->db_id : 0;
0601         comm_in_id  = comm_a ? comm_a->db_id : 0;
0602     }
0603 
0604     if (dbe->export_context_switch)
0605         return dbe->export_context_switch(dbe, db_id, machine, sample,
0606                           th_out_id, comm_out_id,
0607                           th_in_id, comm_in_id, flags);
0608     return 0;
0609 }