root/tools/perf/util/db-export.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. db_export__init
  2. db_export__exit
  3. db_export__evsel
  4. db_export__machine
  5. db_export__thread
  6. __db_export__comm
  7. db_export__comm
  8. db_export__exec_comm
  9. db_export__comm_thread
  10. db_export__dso
  11. db_export__symbol
  12. db_ids_from_al
  13. call_path_from_sample
  14. db_export__branch_type
  15. db_export__threads
  16. db_export__sample
  17. db_export__branch_types
  18. db_export__call_path
  19. db_export__call_return
  20. db_export__pid_tid
  21. db_export__switch

   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(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)
  68                 return 0;
  69 
  70         thread->db_id = ++dbe->thread_last_db_id;
  71 
  72         if (main_thread)
  73                 main_thread_db_id = main_thread->db_id;
  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, 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, 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 = al->map->dso;
 183 
 184                 err = db_export__dso(dbe, dso, al->machine);
 185                 if (err)
 186                         return err;
 187                 *dso_db_id = dso->db_id;
 188 
 189                 if (!al->sym) {
 190                         al->sym = symbol__new(al->addr, 0, 0, 0, "unknown");
 191                         if (al->sym)
 192                                 dso__insert_symbol(dso, al->sym);
 193                 }
 194 
 195                 if (al->sym) {
 196                         u64 *db_id = symbol__priv(al->sym);
 197 
 198                         err = db_export__symbol(dbe, 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         int err;
 219 
 220         if (!symbol_conf.use_callchain || !sample->callchain)
 221                 return NULL;
 222 
 223         /*
 224          * Since the call path tree must be built starting with the root, we
 225          * must use ORDER_CALL for call chain resolution, in order to process
 226          * the callchain starting with the root node and ending with the leaf.
 227          */
 228         callchain_param.order = ORDER_CALLER;
 229         err = thread__resolve_callchain(thread, &callchain_cursor, evsel,
 230                                         sample, NULL, NULL, PERF_MAX_STACK_DEPTH);
 231         if (err) {
 232                 callchain_param.order = saved_order;
 233                 return NULL;
 234         }
 235         callchain_cursor_commit(&callchain_cursor);
 236 
 237         while (1) {
 238                 struct callchain_cursor_node *node;
 239                 struct addr_location al;
 240                 u64 dso_db_id = 0, sym_db_id = 0, offset = 0;
 241 
 242                 memset(&al, 0, sizeof(al));
 243 
 244                 node = callchain_cursor_current(&callchain_cursor);
 245                 if (!node)
 246                         break;
 247                 /*
 248                  * Handle export of symbol and dso for this node by
 249                  * constructing an addr_location struct and then passing it to
 250                  * db_ids_from_al() to perform the export.
 251                  */
 252                 al.sym = node->sym;
 253                 al.map = node->map;
 254                 al.machine = machine;
 255                 al.addr = node->ip;
 256 
 257                 if (al.map && !al.sym)
 258                         al.sym = dso__find_symbol(al.map->dso, al.addr);
 259 
 260                 db_ids_from_al(dbe, &al, &dso_db_id, &sym_db_id, &offset);
 261 
 262                 /* add node to the call path tree if it doesn't exist */
 263                 current = call_path__findnew(dbe->cpr, current,
 264                                              al.sym, node->ip,
 265                                              kernel_start);
 266 
 267                 callchain_cursor_advance(&callchain_cursor);
 268         }
 269 
 270         /* Reset the callchain order to its prior value. */
 271         callchain_param.order = saved_order;
 272 
 273         if (current == &dbe->cpr->call_path) {
 274                 /* Bail because the callchain was empty. */
 275                 return NULL;
 276         }
 277 
 278         return current;
 279 }
 280 
 281 int db_export__branch_type(struct db_export *dbe, u32 branch_type,
 282                            const char *name)
 283 {
 284         if (dbe->export_branch_type)
 285                 return dbe->export_branch_type(dbe, branch_type, name);
 286 
 287         return 0;
 288 }
 289 
 290 static int db_export__threads(struct db_export *dbe, struct thread *thread,
 291                               struct thread *main_thread,
 292                               struct machine *machine, struct comm **comm_ptr)
 293 {
 294         struct comm *comm = NULL;
 295         struct comm *curr_comm;
 296         int err;
 297 
 298         if (main_thread) {
 299                 /*
 300                  * A thread has a reference to the main thread, so export the
 301                  * main thread first.
 302                  */
 303                 err = db_export__thread(dbe, main_thread, machine, main_thread);
 304                 if (err)
 305                         return err;
 306                 /*
 307                  * Export comm before exporting the non-main thread because
 308                  * db_export__comm_thread() can be called further below.
 309                  */
 310                 comm = machine__thread_exec_comm(machine, main_thread);
 311                 if (comm) {
 312                         err = db_export__exec_comm(dbe, comm, main_thread);
 313                         if (err)
 314                                 return err;
 315                         *comm_ptr = comm;
 316                 }
 317         }
 318 
 319         if (thread != main_thread) {
 320                 /*
 321                  * For a non-main thread, db_export__comm_thread() must be
 322                  * called only if thread has not previously been exported.
 323                  */
 324                 bool export_comm_thread = comm && !thread->db_id;
 325 
 326                 err = db_export__thread(dbe, thread, machine, main_thread);
 327                 if (err)
 328                         return err;
 329 
 330                 if (export_comm_thread) {
 331                         err = db_export__comm_thread(dbe, comm, thread);
 332                         if (err)
 333                                 return err;
 334                 }
 335         }
 336 
 337         curr_comm = thread__comm(thread);
 338         if (curr_comm)
 339                 return db_export__comm(dbe, curr_comm, thread);
 340 
 341         return 0;
 342 }
 343 
 344 int db_export__sample(struct db_export *dbe, union perf_event *event,
 345                       struct perf_sample *sample, struct evsel *evsel,
 346                       struct addr_location *al)
 347 {
 348         struct thread *thread = al->thread;
 349         struct export_sample es = {
 350                 .event = event,
 351                 .sample = sample,
 352                 .evsel = evsel,
 353                 .al = al,
 354         };
 355         struct thread *main_thread;
 356         struct comm *comm = NULL;
 357         int err;
 358 
 359         err = db_export__evsel(dbe, evsel);
 360         if (err)
 361                 return err;
 362 
 363         err = db_export__machine(dbe, al->machine);
 364         if (err)
 365                 return err;
 366 
 367         main_thread = thread__main_thread(al->machine, thread);
 368 
 369         err = db_export__threads(dbe, thread, main_thread, al->machine, &comm);
 370         if (err)
 371                 goto out_put;
 372 
 373         if (comm)
 374                 es.comm_db_id = comm->db_id;
 375 
 376         es.db_id = ++dbe->sample_last_db_id;
 377 
 378         err = db_ids_from_al(dbe, al, &es.dso_db_id, &es.sym_db_id, &es.offset);
 379         if (err)
 380                 goto out_put;
 381 
 382         if (dbe->cpr) {
 383                 struct call_path *cp = call_path_from_sample(dbe, al->machine,
 384                                                              thread, sample,
 385                                                              evsel);
 386                 if (cp) {
 387                         db_export__call_path(dbe, cp);
 388                         es.call_path_id = cp->db_id;
 389                 }
 390         }
 391 
 392         if ((evsel->core.attr.sample_type & PERF_SAMPLE_ADDR) &&
 393             sample_addr_correlates_sym(&evsel->core.attr)) {
 394                 struct addr_location addr_al;
 395 
 396                 thread__resolve(thread, &addr_al, sample);
 397                 err = db_ids_from_al(dbe, &addr_al, &es.addr_dso_db_id,
 398                                      &es.addr_sym_db_id, &es.addr_offset);
 399                 if (err)
 400                         goto out_put;
 401                 if (dbe->crp) {
 402                         err = thread_stack__process(thread, comm, sample, al,
 403                                                     &addr_al, es.db_id,
 404                                                     dbe->crp);
 405                         if (err)
 406                                 goto out_put;
 407                 }
 408         }
 409 
 410         if (dbe->export_sample)
 411                 err = dbe->export_sample(dbe, &es);
 412 
 413 out_put:
 414         thread__put(main_thread);
 415         return err;
 416 }
 417 
 418 static struct {
 419         u32 branch_type;
 420         const char *name;
 421 } branch_types[] = {
 422         {0, "no branch"},
 423         {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL, "call"},
 424         {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN, "return"},
 425         {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CONDITIONAL, "conditional jump"},
 426         {PERF_IP_FLAG_BRANCH, "unconditional jump"},
 427         {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_INTERRUPT,
 428          "software interrupt"},
 429         {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN | PERF_IP_FLAG_INTERRUPT,
 430          "return from interrupt"},
 431         {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_SYSCALLRET,
 432          "system call"},
 433         {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN | PERF_IP_FLAG_SYSCALLRET,
 434          "return from system call"},
 435         {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_ASYNC, "asynchronous branch"},
 436         {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_ASYNC |
 437          PERF_IP_FLAG_INTERRUPT, "hardware interrupt"},
 438         {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TX_ABORT, "transaction abort"},
 439         {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TRACE_BEGIN, "trace begin"},
 440         {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TRACE_END, "trace end"},
 441         {0, NULL}
 442 };
 443 
 444 int db_export__branch_types(struct db_export *dbe)
 445 {
 446         int i, err = 0;
 447 
 448         for (i = 0; branch_types[i].name ; i++) {
 449                 err = db_export__branch_type(dbe, branch_types[i].branch_type,
 450                                              branch_types[i].name);
 451                 if (err)
 452                         break;
 453         }
 454 
 455         /* Add trace begin / end variants */
 456         for (i = 0; branch_types[i].name ; i++) {
 457                 const char *name = branch_types[i].name;
 458                 u32 type = branch_types[i].branch_type;
 459                 char buf[64];
 460 
 461                 if (type == PERF_IP_FLAG_BRANCH ||
 462                     (type & (PERF_IP_FLAG_TRACE_BEGIN | PERF_IP_FLAG_TRACE_END)))
 463                         continue;
 464 
 465                 snprintf(buf, sizeof(buf), "trace begin / %s", name);
 466                 err = db_export__branch_type(dbe, type | PERF_IP_FLAG_TRACE_BEGIN, buf);
 467                 if (err)
 468                         break;
 469 
 470                 snprintf(buf, sizeof(buf), "%s / trace end", name);
 471                 err = db_export__branch_type(dbe, type | PERF_IP_FLAG_TRACE_END, buf);
 472                 if (err)
 473                         break;
 474         }
 475 
 476         return err;
 477 }
 478 
 479 int db_export__call_path(struct db_export *dbe, struct call_path *cp)
 480 {
 481         int err;
 482 
 483         if (cp->db_id)
 484                 return 0;
 485 
 486         if (cp->parent) {
 487                 err = db_export__call_path(dbe, cp->parent);
 488                 if (err)
 489                         return err;
 490         }
 491 
 492         cp->db_id = ++dbe->call_path_last_db_id;
 493 
 494         if (dbe->export_call_path)
 495                 return dbe->export_call_path(dbe, cp);
 496 
 497         return 0;
 498 }
 499 
 500 int db_export__call_return(struct db_export *dbe, struct call_return *cr,
 501                            u64 *parent_db_id)
 502 {
 503         int err;
 504 
 505         err = db_export__call_path(dbe, cr->cp);
 506         if (err)
 507                 return err;
 508 
 509         if (!cr->db_id)
 510                 cr->db_id = ++dbe->call_return_last_db_id;
 511 
 512         if (parent_db_id) {
 513                 if (!*parent_db_id)
 514                         *parent_db_id = ++dbe->call_return_last_db_id;
 515                 cr->parent_db_id = *parent_db_id;
 516         }
 517 
 518         if (dbe->export_call_return)
 519                 return dbe->export_call_return(dbe, cr);
 520 
 521         return 0;
 522 }
 523 
 524 static int db_export__pid_tid(struct db_export *dbe, struct machine *machine,
 525                               pid_t pid, pid_t tid, u64 *db_id,
 526                               struct comm **comm_ptr, bool *is_idle)
 527 {
 528         struct thread *thread = machine__find_thread(machine, pid, tid);
 529         struct thread *main_thread;
 530         int err = 0;
 531 
 532         if (!thread || !thread->comm_set)
 533                 goto out_put;
 534 
 535         *is_idle = !thread->pid_ && !thread->tid;
 536 
 537         main_thread = thread__main_thread(machine, thread);
 538 
 539         err = db_export__threads(dbe, thread, main_thread, machine, comm_ptr);
 540 
 541         *db_id = thread->db_id;
 542 
 543         thread__put(main_thread);
 544 out_put:
 545         thread__put(thread);
 546 
 547         return err;
 548 }
 549 
 550 int db_export__switch(struct db_export *dbe, union perf_event *event,
 551                       struct perf_sample *sample, struct machine *machine)
 552 {
 553         bool out = event->header.misc & PERF_RECORD_MISC_SWITCH_OUT;
 554         bool out_preempt = out &&
 555                 (event->header.misc & PERF_RECORD_MISC_SWITCH_OUT_PREEMPT);
 556         int flags = out | (out_preempt << 1);
 557         bool is_idle_a = false, is_idle_b = false;
 558         u64 th_a_id = 0, th_b_id = 0;
 559         u64 comm_out_id, comm_in_id;
 560         struct comm *comm_a = NULL;
 561         struct comm *comm_b = NULL;
 562         u64 th_out_id, th_in_id;
 563         u64 db_id;
 564         int err;
 565 
 566         err = db_export__machine(dbe, machine);
 567         if (err)
 568                 return err;
 569 
 570         err = db_export__pid_tid(dbe, machine, sample->pid, sample->tid,
 571                                  &th_a_id, &comm_a, &is_idle_a);
 572         if (err)
 573                 return err;
 574 
 575         if (event->header.type == PERF_RECORD_SWITCH_CPU_WIDE) {
 576                 pid_t pid = event->context_switch.next_prev_pid;
 577                 pid_t tid = event->context_switch.next_prev_tid;
 578 
 579                 err = db_export__pid_tid(dbe, machine, pid, tid, &th_b_id,
 580                                          &comm_b, &is_idle_b);
 581                 if (err)
 582                         return err;
 583         }
 584 
 585         /*
 586          * Do not export if both threads are unknown (i.e. not being traced),
 587          * or one is unknown and the other is the idle task.
 588          */
 589         if ((!th_a_id || is_idle_a) && (!th_b_id || is_idle_b))
 590                 return 0;
 591 
 592         db_id = ++dbe->context_switch_last_db_id;
 593 
 594         if (out) {
 595                 th_out_id   = th_a_id;
 596                 th_in_id    = th_b_id;
 597                 comm_out_id = comm_a ? comm_a->db_id : 0;
 598                 comm_in_id  = comm_b ? comm_b->db_id : 0;
 599         } else {
 600                 th_out_id   = th_b_id;
 601                 th_in_id    = th_a_id;
 602                 comm_out_id = comm_b ? comm_b->db_id : 0;
 603                 comm_in_id  = comm_a ? comm_a->db_id : 0;
 604         }
 605 
 606         if (dbe->export_context_switch)
 607                 return dbe->export_context_switch(dbe, db_id, machine, sample,
 608                                                   th_out_id, comm_out_id,
 609                                                   th_in_id, comm_in_id, flags);
 610         return 0;
 611 }

/* [<][>][^][v][top][bottom][index][help] */