aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2016-05-07 00:49:28 -0400
committerIngo Molnar <mingo@kernel.org>2016-05-07 00:49:28 -0400
commitea7c28518943b26a85d73cd76acd03b71962cb18 (patch)
tree51106d348d0778b7b00d2b8212a9854497d7f47f
parentc0edb7467c3d21b213ff734bfe810d81d2c6ed61 (diff)
parentd5d71e86d226abe7e08df5763127ed2bd07649a1 (diff)
Merge tag 'perf-core-for-mingo-20160506' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo: User visible changes: - Fix ordering of kernel/user entries in 'caller' mode, where the kernel and user parts were being correctly inverted but kept in place wrt each other, i.e. 'callee' (k1, k2, u3, u4) became 'caller' (k2, k1, u4, u3) when it should be 'caller' (u4, u3, k2, k1) (Chris Phlipot) - In 'perf trace' don't print the raw arg syscall args for a syscall that has no arguments, like gettid(). This was happening because just checking if the syscall args list is NULL may mean that there are no args (e.g.: gettid) or that there is no tracepoint info (e.g.: clone) (Arnaldo Carvalho de Melo) - Add extra output of counter values with 'perf stat -vv' (Andi Kleen) Infrastructure changes: - Expose callchain db export via the python API (Chris Phlipot) Code reorganization: - Move some more syscall arg beautifiers from the 'perf trace' main file to separate files in tools/perf/trace/beauty/, to reduce the main file line count (Arnaldo Carvalho de Melo) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--tools/perf/builtin-stat.c8
-rw-r--r--tools/perf/builtin-trace.c165
-rw-r--r--tools/perf/scripts/python/export-to-postgresql.py47
-rw-r--r--tools/perf/trace/beauty/futex_op.c44
-rw-r--r--tools/perf/trace/beauty/open_flags.c56
-rw-r--r--tools/perf/trace/beauty/signum.c53
-rw-r--r--tools/perf/util/Build1
-rw-r--r--tools/perf/util/call-path.c122
-rw-r--r--tools/perf/util/call-path.h77
-rw-r--r--tools/perf/util/db-export.c85
-rw-r--r--tools/perf/util/db-export.h3
-rw-r--r--tools/perf/util/machine.c56
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c36
-rw-r--r--tools/perf/util/thread-stack.c139
-rw-r--r--tools/perf/util/thread-stack.h31
15 files changed, 575 insertions, 348 deletions
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 1f19f2f999c8..5645a8361de6 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -298,6 +298,14 @@ static int read_counter(struct perf_evsel *counter)
298 return -1; 298 return -1;
299 } 299 }
300 } 300 }
301
302 if (verbose > 1) {
303 fprintf(stat_config.output,
304 "%s: %d: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n",
305 perf_evsel__name(counter),
306 cpu,
307 count->val, count->ena, count->run);
308 }
301 } 309 }
302 } 310 }
303 311
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 66aa2a00414b..709963740f9a 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -40,7 +40,6 @@
40 40
41#include <libaudit.h> /* FIXME: Still needed for audit_errno_to_name */ 41#include <libaudit.h> /* FIXME: Still needed for audit_errno_to_name */
42#include <stdlib.h> 42#include <stdlib.h>
43#include <linux/futex.h>
44#include <linux/err.h> 43#include <linux/err.h>
45#include <linux/seccomp.h> 44#include <linux/seccomp.h>
46#include <linux/filter.h> 45#include <linux/filter.h>
@@ -401,49 +400,6 @@ static size_t syscall_arg__scnprintf_flock(char *bf, size_t size,
401 400
402#define SCA_FLOCK syscall_arg__scnprintf_flock 401#define SCA_FLOCK syscall_arg__scnprintf_flock
403 402
404static size_t syscall_arg__scnprintf_futex_op(char *bf, size_t size, struct syscall_arg *arg)
405{
406 enum syscall_futex_args {
407 SCF_UADDR = (1 << 0),
408 SCF_OP = (1 << 1),
409 SCF_VAL = (1 << 2),
410 SCF_TIMEOUT = (1 << 3),
411 SCF_UADDR2 = (1 << 4),
412 SCF_VAL3 = (1 << 5),
413 };
414 int op = arg->val;
415 int cmd = op & FUTEX_CMD_MASK;
416 size_t printed = 0;
417
418 switch (cmd) {
419#define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
420 P_FUTEX_OP(WAIT); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
421 P_FUTEX_OP(WAKE); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
422 P_FUTEX_OP(FD); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
423 P_FUTEX_OP(REQUEUE); arg->mask |= SCF_VAL3|SCF_TIMEOUT; break;
424 P_FUTEX_OP(CMP_REQUEUE); arg->mask |= SCF_TIMEOUT; break;
425 P_FUTEX_OP(CMP_REQUEUE_PI); arg->mask |= SCF_TIMEOUT; break;
426 P_FUTEX_OP(WAKE_OP); break;
427 P_FUTEX_OP(LOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
428 P_FUTEX_OP(UNLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
429 P_FUTEX_OP(TRYLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
430 P_FUTEX_OP(WAIT_BITSET); arg->mask |= SCF_UADDR2; break;
431 P_FUTEX_OP(WAKE_BITSET); arg->mask |= SCF_UADDR2; break;
432 P_FUTEX_OP(WAIT_REQUEUE_PI); break;
433 default: printed = scnprintf(bf, size, "%#x", cmd); break;
434 }
435
436 if (op & FUTEX_PRIVATE_FLAG)
437 printed += scnprintf(bf + printed, size - printed, "|PRIV");
438
439 if (op & FUTEX_CLOCK_REALTIME)
440 printed += scnprintf(bf + printed, size - printed, "|CLKRT");
441
442 return printed;
443}
444
445#define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
446
447static const char *bpf_cmd[] = { 403static const char *bpf_cmd[] = {
448 "MAP_CREATE", "MAP_LOOKUP_ELEM", "MAP_UPDATE_ELEM", "MAP_DELETE_ELEM", 404 "MAP_CREATE", "MAP_LOOKUP_ELEM", "MAP_UPDATE_ELEM", "MAP_DELETE_ELEM",
449 "MAP_GET_NEXT_KEY", "PROG_LOAD", 405 "MAP_GET_NEXT_KEY", "PROG_LOAD",
@@ -542,62 +498,6 @@ static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
542 498
543#define SCA_FILENAME syscall_arg__scnprintf_filename 499#define SCA_FILENAME syscall_arg__scnprintf_filename
544 500
545static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
546 struct syscall_arg *arg)
547{
548 int printed = 0, flags = arg->val;
549
550 if (!(flags & O_CREAT))
551 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
552
553 if (flags == 0)
554 return scnprintf(bf, size, "RDONLY");
555#define P_FLAG(n) \
556 if (flags & O_##n) { \
557 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
558 flags &= ~O_##n; \
559 }
560
561 P_FLAG(APPEND);
562 P_FLAG(ASYNC);
563 P_FLAG(CLOEXEC);
564 P_FLAG(CREAT);
565 P_FLAG(DIRECT);
566 P_FLAG(DIRECTORY);
567 P_FLAG(EXCL);
568 P_FLAG(LARGEFILE);
569 P_FLAG(NOATIME);
570 P_FLAG(NOCTTY);
571#ifdef O_NONBLOCK
572 P_FLAG(NONBLOCK);
573#elif O_NDELAY
574 P_FLAG(NDELAY);
575#endif
576#ifdef O_PATH
577 P_FLAG(PATH);
578#endif
579 P_FLAG(RDWR);
580#ifdef O_DSYNC
581 if ((flags & O_SYNC) == O_SYNC)
582 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
583 else {
584 P_FLAG(DSYNC);
585 }
586#else
587 P_FLAG(SYNC);
588#endif
589 P_FLAG(TRUNC);
590 P_FLAG(WRONLY);
591#undef P_FLAG
592
593 if (flags)
594 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
595
596 return printed;
597}
598
599#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
600
601static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size, 501static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
602 struct syscall_arg *arg) 502 struct syscall_arg *arg)
603{ 503{
@@ -621,59 +521,6 @@ static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
621 521
622#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags 522#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
623 523
624static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
625{
626 int sig = arg->val;
627
628 switch (sig) {
629#define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
630 P_SIGNUM(HUP);
631 P_SIGNUM(INT);
632 P_SIGNUM(QUIT);
633 P_SIGNUM(ILL);
634 P_SIGNUM(TRAP);
635 P_SIGNUM(ABRT);
636 P_SIGNUM(BUS);
637 P_SIGNUM(FPE);
638 P_SIGNUM(KILL);
639 P_SIGNUM(USR1);
640 P_SIGNUM(SEGV);
641 P_SIGNUM(USR2);
642 P_SIGNUM(PIPE);
643 P_SIGNUM(ALRM);
644 P_SIGNUM(TERM);
645 P_SIGNUM(CHLD);
646 P_SIGNUM(CONT);
647 P_SIGNUM(STOP);
648 P_SIGNUM(TSTP);
649 P_SIGNUM(TTIN);
650 P_SIGNUM(TTOU);
651 P_SIGNUM(URG);
652 P_SIGNUM(XCPU);
653 P_SIGNUM(XFSZ);
654 P_SIGNUM(VTALRM);
655 P_SIGNUM(PROF);
656 P_SIGNUM(WINCH);
657 P_SIGNUM(IO);
658 P_SIGNUM(PWR);
659 P_SIGNUM(SYS);
660#ifdef SIGEMT
661 P_SIGNUM(EMT);
662#endif
663#ifdef SIGSTKFLT
664 P_SIGNUM(STKFLT);
665#endif
666#ifdef SIGSWI
667 P_SIGNUM(SWI);
668#endif
669 default: break;
670 }
671
672 return scnprintf(bf, size, "%#x", sig);
673}
674
675#define SCA_SIGNUM syscall_arg__scnprintf_signum
676
677#if defined(__i386__) || defined(__x86_64__) 524#if defined(__i386__) || defined(__x86_64__)
678/* 525/*
679 * FIXME: Make this available to all arches. 526 * FIXME: Make this available to all arches.
@@ -787,12 +634,15 @@ static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
787 .arg_parm = { [arg] = &strarray__##array, } 634 .arg_parm = { [arg] = &strarray__##array, }
788 635
789#include "trace/beauty/eventfd.c" 636#include "trace/beauty/eventfd.c"
790#include "trace/beauty/pid.c" 637#include "trace/beauty/futex_op.c"
791#include "trace/beauty/mmap.c" 638#include "trace/beauty/mmap.c"
792#include "trace/beauty/mode_t.c" 639#include "trace/beauty/mode_t.c"
793#include "trace/beauty/msg_flags.c" 640#include "trace/beauty/msg_flags.c"
641#include "trace/beauty/open_flags.c"
794#include "trace/beauty/perf_event_open.c" 642#include "trace/beauty/perf_event_open.c"
643#include "trace/beauty/pid.c"
795#include "trace/beauty/sched_policy.c" 644#include "trace/beauty/sched_policy.c"
645#include "trace/beauty/signum.c"
796#include "trace/beauty/socket_type.c" 646#include "trace/beauty/socket_type.c"
797#include "trace/beauty/waitid_options.c" 647#include "trace/beauty/waitid_options.c"
798 648
@@ -1606,7 +1456,12 @@ static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
1606 "%ld", val); 1456 "%ld", val);
1607 } 1457 }
1608 } 1458 }
1609 } else { 1459 } else if (IS_ERR(sc->tp_format)) {
1460 /*
1461 * If we managed to read the tracepoint /format file, then we
1462 * may end up not having any args, like with gettid(), so only
1463 * print the raw args when we didn't manage to read it.
1464 */
1610 int i = 0; 1465 int i = 0;
1611 1466
1612 while (i < 6) { 1467 while (i < 6) {
diff --git a/tools/perf/scripts/python/export-to-postgresql.py b/tools/perf/scripts/python/export-to-postgresql.py
index 6f0ca6873c17..7656ff8aa066 100644
--- a/tools/perf/scripts/python/export-to-postgresql.py
+++ b/tools/perf/scripts/python/export-to-postgresql.py
@@ -223,11 +223,14 @@ sys.path.append(os.environ['PERF_EXEC_PATH'] + \
223 223
224perf_db_export_mode = True 224perf_db_export_mode = True
225perf_db_export_calls = False 225perf_db_export_calls = False
226perf_db_export_callchains = False
227
226 228
227def usage(): 229def usage():
228 print >> sys.stderr, "Usage is: export-to-postgresql.py <database name> [<columns>] [<calls>]" 230 print >> sys.stderr, "Usage is: export-to-postgresql.py <database name> [<columns>] [<calls>] [<callchains>]"
229 print >> sys.stderr, "where: columns 'all' or 'branches'" 231 print >> sys.stderr, "where: columns 'all' or 'branches'"
230 print >> sys.stderr, " calls 'calls' => create calls table" 232 print >> sys.stderr, " calls 'calls' => create calls and call_paths table"
233 print >> sys.stderr, " callchains 'callchains' => create call_paths table"
231 raise Exception("Too few arguments") 234 raise Exception("Too few arguments")
232 235
233if (len(sys.argv) < 2): 236if (len(sys.argv) < 2):
@@ -245,9 +248,11 @@ if columns not in ("all", "branches"):
245 248
246branches = (columns == "branches") 249branches = (columns == "branches")
247 250
248if (len(sys.argv) >= 4): 251for i in range(3,len(sys.argv)):
249 if (sys.argv[3] == "calls"): 252 if (sys.argv[i] == "calls"):
250 perf_db_export_calls = True 253 perf_db_export_calls = True
254 elif (sys.argv[i] == "callchains"):
255 perf_db_export_callchains = True
251 else: 256 else:
252 usage() 257 usage()
253 258
@@ -358,14 +363,16 @@ else:
358 'transaction bigint,' 363 'transaction bigint,'
359 'data_src bigint,' 364 'data_src bigint,'
360 'branch_type integer,' 365 'branch_type integer,'
361 'in_tx boolean)') 366 'in_tx boolean,'
367 'call_path_id bigint)')
362 368
363if perf_db_export_calls: 369if perf_db_export_calls or perf_db_export_callchains:
364 do_query(query, 'CREATE TABLE call_paths (' 370 do_query(query, 'CREATE TABLE call_paths ('
365 'id bigint NOT NULL,' 371 'id bigint NOT NULL,'
366 'parent_id bigint,' 372 'parent_id bigint,'
367 'symbol_id bigint,' 373 'symbol_id bigint,'
368 'ip bigint)') 374 'ip bigint)')
375if perf_db_export_calls:
369 do_query(query, 'CREATE TABLE calls (' 376 do_query(query, 'CREATE TABLE calls ('
370 'id bigint NOT NULL,' 377 'id bigint NOT NULL,'
371 'thread_id bigint,' 378 'thread_id bigint,'
@@ -427,7 +434,7 @@ do_query(query, 'CREATE VIEW comm_threads_view AS '
427 '(SELECT tid FROM threads WHERE id = thread_id) AS tid' 434 '(SELECT tid FROM threads WHERE id = thread_id) AS tid'
428 ' FROM comm_threads') 435 ' FROM comm_threads')
429 436
430if perf_db_export_calls: 437if perf_db_export_calls or perf_db_export_callchains:
431 do_query(query, 'CREATE VIEW call_paths_view AS ' 438 do_query(query, 'CREATE VIEW call_paths_view AS '
432 'SELECT ' 439 'SELECT '
433 'c.id,' 440 'c.id,'
@@ -443,6 +450,7 @@ if perf_db_export_calls:
443 '(SELECT dso_id FROM symbols WHERE id = p.symbol_id) AS parent_dso_id,' 450 '(SELECT dso_id FROM symbols WHERE id = p.symbol_id) AS parent_dso_id,'
444 '(SELECT dso FROM symbols_view WHERE id = p.symbol_id) AS parent_dso_short_name' 451 '(SELECT dso FROM symbols_view WHERE id = p.symbol_id) AS parent_dso_short_name'
445 ' FROM call_paths c INNER JOIN call_paths p ON p.id = c.parent_id') 452 ' FROM call_paths c INNER JOIN call_paths p ON p.id = c.parent_id')
453if perf_db_export_calls:
446 do_query(query, 'CREATE VIEW calls_view AS ' 454 do_query(query, 'CREATE VIEW calls_view AS '
447 'SELECT ' 455 'SELECT '
448 'calls.id,' 456 'calls.id,'
@@ -540,8 +548,9 @@ dso_file = open_output_file("dso_table.bin")
540symbol_file = open_output_file("symbol_table.bin") 548symbol_file = open_output_file("symbol_table.bin")
541branch_type_file = open_output_file("branch_type_table.bin") 549branch_type_file = open_output_file("branch_type_table.bin")
542sample_file = open_output_file("sample_table.bin") 550sample_file = open_output_file("sample_table.bin")
543if perf_db_export_calls: 551if perf_db_export_calls or perf_db_export_callchains:
544 call_path_file = open_output_file("call_path_table.bin") 552 call_path_file = open_output_file("call_path_table.bin")
553if perf_db_export_calls:
545 call_file = open_output_file("call_table.bin") 554 call_file = open_output_file("call_table.bin")
546 555
547def trace_begin(): 556def trace_begin():
@@ -553,8 +562,8 @@ def trace_begin():
553 comm_table(0, "unknown") 562 comm_table(0, "unknown")
554 dso_table(0, 0, "unknown", "unknown", "") 563 dso_table(0, 0, "unknown", "unknown", "")
555 symbol_table(0, 0, 0, 0, 0, "unknown") 564 symbol_table(0, 0, 0, 0, 0, "unknown")
556 sample_table(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) 565 sample_table(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
557 if perf_db_export_calls: 566 if perf_db_export_calls or perf_db_export_callchains:
558 call_path_table(0, 0, 0, 0) 567 call_path_table(0, 0, 0, 0)
559 568
560unhandled_count = 0 569unhandled_count = 0
@@ -570,8 +579,9 @@ def trace_end():
570 copy_output_file(symbol_file, "symbols") 579 copy_output_file(symbol_file, "symbols")
571 copy_output_file(branch_type_file, "branch_types") 580 copy_output_file(branch_type_file, "branch_types")
572 copy_output_file(sample_file, "samples") 581 copy_output_file(sample_file, "samples")
573 if perf_db_export_calls: 582 if perf_db_export_calls or perf_db_export_callchains:
574 copy_output_file(call_path_file, "call_paths") 583 copy_output_file(call_path_file, "call_paths")
584 if perf_db_export_calls:
575 copy_output_file(call_file, "calls") 585 copy_output_file(call_file, "calls")
576 586
577 print datetime.datetime.today(), "Removing intermediate files..." 587 print datetime.datetime.today(), "Removing intermediate files..."
@@ -584,8 +594,9 @@ def trace_end():
584 remove_output_file(symbol_file) 594 remove_output_file(symbol_file)
585 remove_output_file(branch_type_file) 595 remove_output_file(branch_type_file)
586 remove_output_file(sample_file) 596 remove_output_file(sample_file)
587 if perf_db_export_calls: 597 if perf_db_export_calls or perf_db_export_callchains:
588 remove_output_file(call_path_file) 598 remove_output_file(call_path_file)
599 if perf_db_export_calls:
589 remove_output_file(call_file) 600 remove_output_file(call_file)
590 os.rmdir(output_dir_name) 601 os.rmdir(output_dir_name)
591 print datetime.datetime.today(), "Adding primary keys" 602 print datetime.datetime.today(), "Adding primary keys"
@@ -598,8 +609,9 @@ def trace_end():
598 do_query(query, 'ALTER TABLE symbols ADD PRIMARY KEY (id)') 609 do_query(query, 'ALTER TABLE symbols ADD PRIMARY KEY (id)')
599 do_query(query, 'ALTER TABLE branch_types ADD PRIMARY KEY (id)') 610 do_query(query, 'ALTER TABLE branch_types ADD PRIMARY KEY (id)')
600 do_query(query, 'ALTER TABLE samples ADD PRIMARY KEY (id)') 611 do_query(query, 'ALTER TABLE samples ADD PRIMARY KEY (id)')
601 if perf_db_export_calls: 612 if perf_db_export_calls or perf_db_export_callchains:
602 do_query(query, 'ALTER TABLE call_paths ADD PRIMARY KEY (id)') 613 do_query(query, 'ALTER TABLE call_paths ADD PRIMARY KEY (id)')
614 if perf_db_export_calls:
603 do_query(query, 'ALTER TABLE calls ADD PRIMARY KEY (id)') 615 do_query(query, 'ALTER TABLE calls ADD PRIMARY KEY (id)')
604 616
605 print datetime.datetime.today(), "Adding foreign keys" 617 print datetime.datetime.today(), "Adding foreign keys"
@@ -622,10 +634,11 @@ def trace_end():
622 'ADD CONSTRAINT symbolfk FOREIGN KEY (symbol_id) REFERENCES symbols (id),' 634 'ADD CONSTRAINT symbolfk FOREIGN KEY (symbol_id) REFERENCES symbols (id),'
623 'ADD CONSTRAINT todsofk FOREIGN KEY (to_dso_id) REFERENCES dsos (id),' 635 'ADD CONSTRAINT todsofk FOREIGN KEY (to_dso_id) REFERENCES dsos (id),'
624 'ADD CONSTRAINT tosymbolfk FOREIGN KEY (to_symbol_id) REFERENCES symbols (id)') 636 'ADD CONSTRAINT tosymbolfk FOREIGN KEY (to_symbol_id) REFERENCES symbols (id)')
625 if perf_db_export_calls: 637 if perf_db_export_calls or perf_db_export_callchains:
626 do_query(query, 'ALTER TABLE call_paths ' 638 do_query(query, 'ALTER TABLE call_paths '
627 'ADD CONSTRAINT parentfk FOREIGN KEY (parent_id) REFERENCES call_paths (id),' 639 'ADD CONSTRAINT parentfk FOREIGN KEY (parent_id) REFERENCES call_paths (id),'
628 'ADD CONSTRAINT symbolfk FOREIGN KEY (symbol_id) REFERENCES symbols (id)') 640 'ADD CONSTRAINT symbolfk FOREIGN KEY (symbol_id) REFERENCES symbols (id)')
641 if perf_db_export_calls:
629 do_query(query, 'ALTER TABLE calls ' 642 do_query(query, 'ALTER TABLE calls '
630 'ADD CONSTRAINT threadfk FOREIGN KEY (thread_id) REFERENCES threads (id),' 643 'ADD CONSTRAINT threadfk FOREIGN KEY (thread_id) REFERENCES threads (id),'
631 'ADD CONSTRAINT commfk FOREIGN KEY (comm_id) REFERENCES comms (id),' 644 'ADD CONSTRAINT commfk FOREIGN KEY (comm_id) REFERENCES comms (id),'
@@ -693,11 +706,11 @@ def branch_type_table(branch_type, name, *x):
693 value = struct.pack(fmt, 2, 4, branch_type, n, name) 706 value = struct.pack(fmt, 2, 4, branch_type, n, name)
694 branch_type_file.write(value) 707 branch_type_file.write(value)
695 708
696def sample_table(sample_id, evsel_id, machine_id, thread_id, comm_id, dso_id, symbol_id, sym_offset, ip, time, cpu, to_dso_id, to_symbol_id, to_sym_offset, to_ip, period, weight, transaction, data_src, branch_type, in_tx, *x): 709def sample_table(sample_id, evsel_id, machine_id, thread_id, comm_id, dso_id, symbol_id, sym_offset, ip, time, cpu, to_dso_id, to_symbol_id, to_sym_offset, to_ip, period, weight, transaction, data_src, branch_type, in_tx, call_path_id, *x):
697 if branches: 710 if branches:
698 value = struct.pack("!hiqiqiqiqiqiqiqiqiqiqiiiqiqiqiqiiiB", 17, 8, sample_id, 8, evsel_id, 8, machine_id, 8, thread_id, 8, comm_id, 8, dso_id, 8, symbol_id, 8, sym_offset, 8, ip, 8, time, 4, cpu, 8, to_dso_id, 8, to_symbol_id, 8, to_sym_offset, 8, to_ip, 4, branch_type, 1, in_tx) 711 value = struct.pack("!hiqiqiqiqiqiqiqiqiqiqiiiqiqiqiqiiiBiq", 18, 8, sample_id, 8, evsel_id, 8, machine_id, 8, thread_id, 8, comm_id, 8, dso_id, 8, symbol_id, 8, sym_offset, 8, ip, 8, time, 4, cpu, 8, to_dso_id, 8, to_symbol_id, 8, to_sym_offset, 8, to_ip, 4, branch_type, 1, in_tx, 8, call_path_id)
699 else: 712 else:
700 value = struct.pack("!hiqiqiqiqiqiqiqiqiqiqiiiqiqiqiqiqiqiqiqiiiB", 21, 8, sample_id, 8, evsel_id, 8, machine_id, 8, thread_id, 8, comm_id, 8, dso_id, 8, symbol_id, 8, sym_offset, 8, ip, 8, time, 4, cpu, 8, to_dso_id, 8, to_symbol_id, 8, to_sym_offset, 8, to_ip, 8, period, 8, weight, 8, transaction, 8, data_src, 4, branch_type, 1, in_tx) 713 value = struct.pack("!hiqiqiqiqiqiqiqiqiqiqiiiqiqiqiqiqiqiqiqiiiBiq", 22, 8, sample_id, 8, evsel_id, 8, machine_id, 8, thread_id, 8, comm_id, 8, dso_id, 8, symbol_id, 8, sym_offset, 8, ip, 8, time, 4, cpu, 8, to_dso_id, 8, to_symbol_id, 8, to_sym_offset, 8, to_ip, 8, period, 8, weight, 8, transaction, 8, data_src, 4, branch_type, 1, in_tx, 8, call_path_id)
701 sample_file.write(value) 714 sample_file.write(value)
702 715
703def call_path_table(cp_id, parent_id, symbol_id, ip, *x): 716def call_path_table(cp_id, parent_id, symbol_id, ip, *x):
diff --git a/tools/perf/trace/beauty/futex_op.c b/tools/perf/trace/beauty/futex_op.c
new file mode 100644
index 000000000000..e2476211f22d
--- /dev/null
+++ b/tools/perf/trace/beauty/futex_op.c
@@ -0,0 +1,44 @@
1#include <linux/futex.h>
2
3static size_t syscall_arg__scnprintf_futex_op(char *bf, size_t size, struct syscall_arg *arg)
4{
5 enum syscall_futex_args {
6 SCF_UADDR = (1 << 0),
7 SCF_OP = (1 << 1),
8 SCF_VAL = (1 << 2),
9 SCF_TIMEOUT = (1 << 3),
10 SCF_UADDR2 = (1 << 4),
11 SCF_VAL3 = (1 << 5),
12 };
13 int op = arg->val;
14 int cmd = op & FUTEX_CMD_MASK;
15 size_t printed = 0;
16
17 switch (cmd) {
18#define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
19 P_FUTEX_OP(WAIT); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
20 P_FUTEX_OP(WAKE); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
21 P_FUTEX_OP(FD); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
22 P_FUTEX_OP(REQUEUE); arg->mask |= SCF_VAL3|SCF_TIMEOUT; break;
23 P_FUTEX_OP(CMP_REQUEUE); arg->mask |= SCF_TIMEOUT; break;
24 P_FUTEX_OP(CMP_REQUEUE_PI); arg->mask |= SCF_TIMEOUT; break;
25 P_FUTEX_OP(WAKE_OP); break;
26 P_FUTEX_OP(LOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
27 P_FUTEX_OP(UNLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
28 P_FUTEX_OP(TRYLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
29 P_FUTEX_OP(WAIT_BITSET); arg->mask |= SCF_UADDR2; break;
30 P_FUTEX_OP(WAKE_BITSET); arg->mask |= SCF_UADDR2; break;
31 P_FUTEX_OP(WAIT_REQUEUE_PI); break;
32 default: printed = scnprintf(bf, size, "%#x", cmd); break;
33 }
34
35 if (op & FUTEX_PRIVATE_FLAG)
36 printed += scnprintf(bf + printed, size - printed, "|PRIV");
37
38 if (op & FUTEX_CLOCK_REALTIME)
39 printed += scnprintf(bf + printed, size - printed, "|CLKRT");
40
41 return printed;
42}
43
44#define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
diff --git a/tools/perf/trace/beauty/open_flags.c b/tools/perf/trace/beauty/open_flags.c
new file mode 100644
index 000000000000..0f3679e0cdcf
--- /dev/null
+++ b/tools/perf/trace/beauty/open_flags.c
@@ -0,0 +1,56 @@
1
2static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
3 struct syscall_arg *arg)
4{
5 int printed = 0, flags = arg->val;
6
7 if (!(flags & O_CREAT))
8 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
9
10 if (flags == 0)
11 return scnprintf(bf, size, "RDONLY");
12#define P_FLAG(n) \
13 if (flags & O_##n) { \
14 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
15 flags &= ~O_##n; \
16 }
17
18 P_FLAG(APPEND);
19 P_FLAG(ASYNC);
20 P_FLAG(CLOEXEC);
21 P_FLAG(CREAT);
22 P_FLAG(DIRECT);
23 P_FLAG(DIRECTORY);
24 P_FLAG(EXCL);
25 P_FLAG(LARGEFILE);
26 P_FLAG(NOATIME);
27 P_FLAG(NOCTTY);
28#ifdef O_NONBLOCK
29 P_FLAG(NONBLOCK);
30#elif O_NDELAY
31 P_FLAG(NDELAY);
32#endif
33#ifdef O_PATH
34 P_FLAG(PATH);
35#endif
36 P_FLAG(RDWR);
37#ifdef O_DSYNC
38 if ((flags & O_SYNC) == O_SYNC)
39 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
40 else {
41 P_FLAG(DSYNC);
42 }
43#else
44 P_FLAG(SYNC);
45#endif
46 P_FLAG(TRUNC);
47 P_FLAG(WRONLY);
48#undef P_FLAG
49
50 if (flags)
51 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
52
53 return printed;
54}
55
56#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
diff --git a/tools/perf/trace/beauty/signum.c b/tools/perf/trace/beauty/signum.c
new file mode 100644
index 000000000000..d3b0b1fab077
--- /dev/null
+++ b/tools/perf/trace/beauty/signum.c
@@ -0,0 +1,53 @@
1
2static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
3{
4 int sig = arg->val;
5
6 switch (sig) {
7#define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
8 P_SIGNUM(HUP);
9 P_SIGNUM(INT);
10 P_SIGNUM(QUIT);
11 P_SIGNUM(ILL);
12 P_SIGNUM(TRAP);
13 P_SIGNUM(ABRT);
14 P_SIGNUM(BUS);
15 P_SIGNUM(FPE);
16 P_SIGNUM(KILL);
17 P_SIGNUM(USR1);
18 P_SIGNUM(SEGV);
19 P_SIGNUM(USR2);
20 P_SIGNUM(PIPE);
21 P_SIGNUM(ALRM);
22 P_SIGNUM(TERM);
23 P_SIGNUM(CHLD);
24 P_SIGNUM(CONT);
25 P_SIGNUM(STOP);
26 P_SIGNUM(TSTP);
27 P_SIGNUM(TTIN);
28 P_SIGNUM(TTOU);
29 P_SIGNUM(URG);
30 P_SIGNUM(XCPU);
31 P_SIGNUM(XFSZ);
32 P_SIGNUM(VTALRM);
33 P_SIGNUM(PROF);
34 P_SIGNUM(WINCH);
35 P_SIGNUM(IO);
36 P_SIGNUM(PWR);
37 P_SIGNUM(SYS);
38#ifdef SIGEMT
39 P_SIGNUM(EMT);
40#endif
41#ifdef SIGSTKFLT
42 P_SIGNUM(STKFLT);
43#endif
44#ifdef SIGSWI
45 P_SIGNUM(SWI);
46#endif
47 default: break;
48 }
49
50 return scnprintf(bf, size, "%#x", sig);
51}
52
53#define SCA_SIGNUM syscall_arg__scnprintf_signum
diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index 90229a88f969..027bb2b89d7f 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -74,6 +74,7 @@ libperf-y += srcline.o
74libperf-y += data.o 74libperf-y += data.o
75libperf-y += tsc.o 75libperf-y += tsc.o
76libperf-y += cloexec.o 76libperf-y += cloexec.o
77libperf-y += call-path.o
77libperf-y += thread-stack.o 78libperf-y += thread-stack.o
78libperf-$(CONFIG_AUXTRACE) += auxtrace.o 79libperf-$(CONFIG_AUXTRACE) += auxtrace.o
79libperf-$(CONFIG_AUXTRACE) += intel-pt-decoder/ 80libperf-$(CONFIG_AUXTRACE) += intel-pt-decoder/
diff --git a/tools/perf/util/call-path.c b/tools/perf/util/call-path.c
new file mode 100644
index 000000000000..904a17052e38
--- /dev/null
+++ b/tools/perf/util/call-path.c
@@ -0,0 +1,122 @@
1/*
2 * call-path.h: Manipulate a tree data structure containing function call paths
3 * Copyright (c) 2014, Intel Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 */
15
16#include <linux/rbtree.h>
17#include <linux/list.h>
18
19#include "util.h"
20#include "call-path.h"
21
22static void call_path__init(struct call_path *cp, struct call_path *parent,
23 struct symbol *sym, u64 ip, bool in_kernel)
24{
25 cp->parent = parent;
26 cp->sym = sym;
27 cp->ip = sym ? 0 : ip;
28 cp->db_id = 0;
29 cp->in_kernel = in_kernel;
30 RB_CLEAR_NODE(&cp->rb_node);
31 cp->children = RB_ROOT;
32}
33
34struct call_path_root *call_path_root__new(void)
35{
36 struct call_path_root *cpr;
37
38 cpr = zalloc(sizeof(struct call_path_root));
39 if (!cpr)
40 return NULL;
41 call_path__init(&cpr->call_path, NULL, NULL, 0, false);
42 INIT_LIST_HEAD(&cpr->blocks);
43 return cpr;
44}
45
46void call_path_root__free(struct call_path_root *cpr)
47{
48 struct call_path_block *pos, *n;
49
50 list_for_each_entry_safe(pos, n, &cpr->blocks, node) {
51 list_del(&pos->node);
52 free(pos);
53 }
54 free(cpr);
55}
56
57static struct call_path *call_path__new(struct call_path_root *cpr,
58 struct call_path *parent,
59 struct symbol *sym, u64 ip,
60 bool in_kernel)
61{
62 struct call_path_block *cpb;
63 struct call_path *cp;
64 size_t n;
65
66 if (cpr->next < cpr->sz) {
67 cpb = list_last_entry(&cpr->blocks, struct call_path_block,
68 node);
69 } else {
70 cpb = zalloc(sizeof(struct call_path_block));
71 if (!cpb)
72 return NULL;
73 list_add_tail(&cpb->node, &cpr->blocks);
74 cpr->sz += CALL_PATH_BLOCK_SIZE;
75 }
76
77 n = cpr->next++ & CALL_PATH_BLOCK_MASK;
78 cp = &cpb->cp[n];
79
80 call_path__init(cp, parent, sym, ip, in_kernel);
81
82 return cp;
83}
84
85struct call_path *call_path__findnew(struct call_path_root *cpr,
86 struct call_path *parent,
87 struct symbol *sym, u64 ip, u64 ks)
88{
89 struct rb_node **p;
90 struct rb_node *node_parent = NULL;
91 struct call_path *cp;
92 bool in_kernel = ip >= ks;
93
94 if (sym)
95 ip = 0;
96
97 if (!parent)
98 return call_path__new(cpr, parent, sym, ip, in_kernel);
99
100 p = &parent->children.rb_node;
101 while (*p != NULL) {
102 node_parent = *p;
103 cp = rb_entry(node_parent, struct call_path, rb_node);
104
105 if (cp->sym == sym && cp->ip == ip)
106 return cp;
107
108 if (sym < cp->sym || (sym == cp->sym && ip < cp->ip))
109 p = &(*p)->rb_left;
110 else
111 p = &(*p)->rb_right;
112 }
113
114 cp = call_path__new(cpr, parent, sym, ip, in_kernel);
115 if (!cp)
116 return NULL;
117
118 rb_link_node(&cp->rb_node, node_parent, p);
119 rb_insert_color(&cp->rb_node, &parent->children);
120
121 return cp;
122}
diff --git a/tools/perf/util/call-path.h b/tools/perf/util/call-path.h
new file mode 100644
index 000000000000..477f6d03b659
--- /dev/null
+++ b/tools/perf/util/call-path.h
@@ -0,0 +1,77 @@
1/*
2 * call-path.h: Manipulate a tree data structure containing function call paths
3 * Copyright (c) 2014, Intel Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 */
15
16#ifndef __PERF_CALL_PATH_H
17#define __PERF_CALL_PATH_H
18
19#include <sys/types.h>
20
21#include <linux/types.h>
22#include <linux/rbtree.h>
23
24/**
25 * struct call_path - node in list of calls leading to a function call.
26 * @parent: call path to the parent function call
27 * @sym: symbol of function called
28 * @ip: only if sym is null, the ip of the function
29 * @db_id: id used for db-export
30 * @in_kernel: whether function is a in the kernel
31 * @rb_node: node in parent's tree of called functions
32 * @children: tree of call paths of functions called
33 *
34 * In combination with the call_return structure, the call_path structure
35 * defines a context-sensitve call-graph.
36 */
37struct call_path {
38 struct call_path *parent;
39 struct symbol *sym;
40 u64 ip;
41 u64 db_id;
42 bool in_kernel;
43 struct rb_node rb_node;
44 struct rb_root children;
45};
46
47#define CALL_PATH_BLOCK_SHIFT 8
48#define CALL_PATH_BLOCK_SIZE (1 << CALL_PATH_BLOCK_SHIFT)
49#define CALL_PATH_BLOCK_MASK (CALL_PATH_BLOCK_SIZE - 1)
50
51struct call_path_block {
52 struct call_path cp[CALL_PATH_BLOCK_SIZE];
53 struct list_head node;
54};
55
56/**
57 * struct call_path_root - root of all call paths.
58 * @call_path: root call path
59 * @blocks: list of blocks to store call paths
60 * @next: next free space
61 * @sz: number of spaces
62 */
63struct call_path_root {
64 struct call_path call_path;
65 struct list_head blocks;
66 size_t next;
67 size_t sz;
68};
69
70struct call_path_root *call_path_root__new(void);
71void call_path_root__free(struct call_path_root *cpr);
72
73struct call_path *call_path__findnew(struct call_path_root *cpr,
74 struct call_path *parent,
75 struct symbol *sym, u64 ip, u64 ks);
76
77#endif
diff --git a/tools/perf/util/db-export.c b/tools/perf/util/db-export.c
index 049438d51b9a..f8e3057ae3b1 100644
--- a/tools/perf/util/db-export.c
+++ b/tools/perf/util/db-export.c
@@ -23,6 +23,8 @@
23#include "event.h" 23#include "event.h"
24#include "util.h" 24#include "util.h"
25#include "thread-stack.h" 25#include "thread-stack.h"
26#include "callchain.h"
27#include "call-path.h"
26#include "db-export.h" 28#include "db-export.h"
27 29
28struct deferred_export { 30struct deferred_export {
@@ -276,6 +278,79 @@ static int db_ids_from_al(struct db_export *dbe, struct addr_location *al,
276 return 0; 278 return 0;
277} 279}
278 280
281static struct call_path *call_path_from_sample(struct db_export *dbe,
282 struct machine *machine,
283 struct thread *thread,
284 struct perf_sample *sample,
285 struct perf_evsel *evsel)
286{
287 u64 kernel_start = machine__kernel_start(machine);
288 struct call_path *current = &dbe->cpr->call_path;
289 enum chain_order saved_order = callchain_param.order;
290 int err;
291
292 if (!symbol_conf.use_callchain || !sample->callchain)
293 return NULL;
294
295 /*
296 * Since the call path tree must be built starting with the root, we
297 * must use ORDER_CALL for call chain resolution, in order to process
298 * the callchain starting with the root node and ending with the leaf.
299 */
300 callchain_param.order = ORDER_CALLER;
301 err = thread__resolve_callchain(thread, &callchain_cursor, evsel,
302 sample, NULL, NULL,
303 sysctl_perf_event_max_stack);
304 if (err) {
305 callchain_param.order = saved_order;
306 return NULL;
307 }
308 callchain_cursor_commit(&callchain_cursor);
309
310 while (1) {
311 struct callchain_cursor_node *node;
312 struct addr_location al;
313 u64 dso_db_id = 0, sym_db_id = 0, offset = 0;
314
315 memset(&al, 0, sizeof(al));
316
317 node = callchain_cursor_current(&callchain_cursor);
318 if (!node)
319 break;
320 /*
321 * Handle export of symbol and dso for this node by
322 * constructing an addr_location struct and then passing it to
323 * db_ids_from_al() to perform the export.
324 */
325 al.sym = node->sym;
326 al.map = node->map;
327 al.machine = machine;
328 if (al.map)
329 al.addr = al.map->map_ip(al.map, node->ip);
330 else
331 al.addr = node->ip;
332
333 db_ids_from_al(dbe, &al, &dso_db_id, &sym_db_id, &offset);
334
335 /* add node to the call path tree if it doesn't exist */
336 current = call_path__findnew(dbe->cpr, current,
337 al.sym, node->ip,
338 kernel_start);
339
340 callchain_cursor_advance(&callchain_cursor);
341 }
342
343 /* Reset the callchain order to its prior value. */
344 callchain_param.order = saved_order;
345
346 if (current == &dbe->cpr->call_path) {
347 /* Bail because the callchain was empty. */
348 return NULL;
349 }
350
351 return current;
352}
353
279int db_export__branch_type(struct db_export *dbe, u32 branch_type, 354int db_export__branch_type(struct db_export *dbe, u32 branch_type,
280 const char *name) 355 const char *name)
281{ 356{
@@ -329,6 +404,16 @@ int db_export__sample(struct db_export *dbe, union perf_event *event,
329 if (err) 404 if (err)
330 goto out_put; 405 goto out_put;
331 406
407 if (dbe->cpr) {
408 struct call_path *cp = call_path_from_sample(dbe, al->machine,
409 thread, sample,
410 evsel);
411 if (cp) {
412 db_export__call_path(dbe, cp);
413 es.call_path_id = cp->db_id;
414 }
415 }
416
332 if ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) && 417 if ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) &&
333 sample_addr_correlates_sym(&evsel->attr)) { 418 sample_addr_correlates_sym(&evsel->attr)) {
334 struct addr_location addr_al; 419 struct addr_location addr_al;
diff --git a/tools/perf/util/db-export.h b/tools/perf/util/db-export.h
index 25e22fd76aca..67bc6b8ad2d6 100644
--- a/tools/perf/util/db-export.h
+++ b/tools/perf/util/db-export.h
@@ -27,6 +27,7 @@ struct dso;
27struct perf_sample; 27struct perf_sample;
28struct addr_location; 28struct addr_location;
29struct call_return_processor; 29struct call_return_processor;
30struct call_path_root;
30struct call_path; 31struct call_path;
31struct call_return; 32struct call_return;
32 33
@@ -43,6 +44,7 @@ struct export_sample {
43 u64 addr_dso_db_id; 44 u64 addr_dso_db_id;
44 u64 addr_sym_db_id; 45 u64 addr_sym_db_id;
45 u64 addr_offset; /* addr offset from symbol start */ 46 u64 addr_offset; /* addr offset from symbol start */
47 u64 call_path_id;
46}; 48};
47 49
48struct db_export { 50struct db_export {
@@ -64,6 +66,7 @@ struct db_export {
64 int (*export_call_return)(struct db_export *dbe, 66 int (*export_call_return)(struct db_export *dbe,
65 struct call_return *cr); 67 struct call_return *cr);
66 struct call_return_processor *crp; 68 struct call_return_processor *crp;
69 struct call_path_root *cpr;
67 u64 evsel_last_db_id; 70 u64 evsel_last_db_id;
68 u64 machine_last_db_id; 71 u64 machine_last_db_id;
69 u64 thread_last_db_id; 72 u64 thread_last_db_id;
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 8c7bf4dbd479..639a2903065e 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -1817,8 +1817,6 @@ static int thread__resolve_callchain_sample(struct thread *thread,
1817 int skip_idx = -1; 1817 int skip_idx = -1;
1818 int first_call = 0; 1818 int first_call = 0;
1819 1819
1820 callchain_cursor_reset(cursor);
1821
1822 if (perf_evsel__has_branch_callstack(evsel)) { 1820 if (perf_evsel__has_branch_callstack(evsel)) {
1823 err = resolve_lbr_callchain_sample(thread, cursor, sample, parent, 1821 err = resolve_lbr_callchain_sample(thread, cursor, sample, parent,
1824 root_al, max_stack); 1822 root_al, max_stack);
@@ -1929,20 +1927,12 @@ static int unwind_entry(struct unwind_entry *entry, void *arg)
1929 entry->map, entry->sym); 1927 entry->map, entry->sym);
1930} 1928}
1931 1929
1932int thread__resolve_callchain(struct thread *thread, 1930static int thread__resolve_callchain_unwind(struct thread *thread,
1933 struct callchain_cursor *cursor, 1931 struct callchain_cursor *cursor,
1934 struct perf_evsel *evsel, 1932 struct perf_evsel *evsel,
1935 struct perf_sample *sample, 1933 struct perf_sample *sample,
1936 struct symbol **parent, 1934 int max_stack)
1937 struct addr_location *root_al,
1938 int max_stack)
1939{ 1935{
1940 int ret = thread__resolve_callchain_sample(thread, cursor, evsel,
1941 sample, parent,
1942 root_al, max_stack);
1943 if (ret)
1944 return ret;
1945
1946 /* Can we do dwarf post unwind? */ 1936 /* Can we do dwarf post unwind? */
1947 if (!((evsel->attr.sample_type & PERF_SAMPLE_REGS_USER) && 1937 if (!((evsel->attr.sample_type & PERF_SAMPLE_REGS_USER) &&
1948 (evsel->attr.sample_type & PERF_SAMPLE_STACK_USER))) 1938 (evsel->attr.sample_type & PERF_SAMPLE_STACK_USER)))
@@ -1955,7 +1945,43 @@ int thread__resolve_callchain(struct thread *thread,
1955 1945
1956 return unwind__get_entries(unwind_entry, cursor, 1946 return unwind__get_entries(unwind_entry, cursor,
1957 thread, sample, max_stack); 1947 thread, sample, max_stack);
1948}
1958 1949
1950int thread__resolve_callchain(struct thread *thread,
1951 struct callchain_cursor *cursor,
1952 struct perf_evsel *evsel,
1953 struct perf_sample *sample,
1954 struct symbol **parent,
1955 struct addr_location *root_al,
1956 int max_stack)
1957{
1958 int ret = 0;
1959
1960 callchain_cursor_reset(&callchain_cursor);
1961
1962 if (callchain_param.order == ORDER_CALLEE) {
1963 ret = thread__resolve_callchain_sample(thread, cursor,
1964 evsel, sample,
1965 parent, root_al,
1966 max_stack);
1967 if (ret)
1968 return ret;
1969 ret = thread__resolve_callchain_unwind(thread, cursor,
1970 evsel, sample,
1971 max_stack);
1972 } else {
1973 ret = thread__resolve_callchain_unwind(thread, cursor,
1974 evsel, sample,
1975 max_stack);
1976 if (ret)
1977 return ret;
1978 ret = thread__resolve_callchain_sample(thread, cursor,
1979 evsel, sample,
1980 parent, root_al,
1981 max_stack);
1982 }
1983
1984 return ret;
1959} 1985}
1960 1986
1961int machine__for_each_thread(struct machine *machine, 1987int machine__for_each_thread(struct machine *machine,
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index 525eb49e7ba6..091bce67844c 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -41,6 +41,7 @@
41#include "../thread-stack.h" 41#include "../thread-stack.h"
42#include "../trace-event.h" 42#include "../trace-event.h"
43#include "../machine.h" 43#include "../machine.h"
44#include "../call-path.h"
44#include "thread_map.h" 45#include "thread_map.h"
45#include "cpumap.h" 46#include "cpumap.h"
46#include "stat.h" 47#include "stat.h"
@@ -681,7 +682,7 @@ static int python_export_sample(struct db_export *dbe,
681 struct tables *tables = container_of(dbe, struct tables, dbe); 682 struct tables *tables = container_of(dbe, struct tables, dbe);
682 PyObject *t; 683 PyObject *t;
683 684
684 t = tuple_new(21); 685 t = tuple_new(22);
685 686
686 tuple_set_u64(t, 0, es->db_id); 687 tuple_set_u64(t, 0, es->db_id);
687 tuple_set_u64(t, 1, es->evsel->db_id); 688 tuple_set_u64(t, 1, es->evsel->db_id);
@@ -704,6 +705,7 @@ static int python_export_sample(struct db_export *dbe,
704 tuple_set_u64(t, 18, es->sample->data_src); 705 tuple_set_u64(t, 18, es->sample->data_src);
705 tuple_set_s32(t, 19, es->sample->flags & PERF_BRANCH_MASK); 706 tuple_set_s32(t, 19, es->sample->flags & PERF_BRANCH_MASK);
706 tuple_set_s32(t, 20, !!(es->sample->flags & PERF_IP_FLAG_IN_TX)); 707 tuple_set_s32(t, 20, !!(es->sample->flags & PERF_IP_FLAG_IN_TX));
708 tuple_set_u64(t, 21, es->call_path_id);
707 709
708 call_object(tables->sample_handler, t, "sample_table"); 710 call_object(tables->sample_handler, t, "sample_table");
709 711
@@ -998,8 +1000,10 @@ static void set_table_handlers(struct tables *tables)
998{ 1000{
999 const char *perf_db_export_mode = "perf_db_export_mode"; 1001 const char *perf_db_export_mode = "perf_db_export_mode";
1000 const char *perf_db_export_calls = "perf_db_export_calls"; 1002 const char *perf_db_export_calls = "perf_db_export_calls";
1001 PyObject *db_export_mode, *db_export_calls; 1003 const char *perf_db_export_callchains = "perf_db_export_callchains";
1004 PyObject *db_export_mode, *db_export_calls, *db_export_callchains;
1002 bool export_calls = false; 1005 bool export_calls = false;
1006 bool export_callchains = false;
1003 int ret; 1007 int ret;
1004 1008
1005 memset(tables, 0, sizeof(struct tables)); 1009 memset(tables, 0, sizeof(struct tables));
@@ -1016,6 +1020,7 @@ static void set_table_handlers(struct tables *tables)
1016 if (!ret) 1020 if (!ret)
1017 return; 1021 return;
1018 1022
1023 /* handle export calls */
1019 tables->dbe.crp = NULL; 1024 tables->dbe.crp = NULL;
1020 db_export_calls = PyDict_GetItemString(main_dict, perf_db_export_calls); 1025 db_export_calls = PyDict_GetItemString(main_dict, perf_db_export_calls);
1021 if (db_export_calls) { 1026 if (db_export_calls) {
@@ -1033,6 +1038,33 @@ static void set_table_handlers(struct tables *tables)
1033 Py_FatalError("failed to create calls processor"); 1038 Py_FatalError("failed to create calls processor");
1034 } 1039 }
1035 1040
1041 /* handle export callchains */
1042 tables->dbe.cpr = NULL;
1043 db_export_callchains = PyDict_GetItemString(main_dict,
1044 perf_db_export_callchains);
1045 if (db_export_callchains) {
1046 ret = PyObject_IsTrue(db_export_callchains);
1047 if (ret == -1)
1048 handler_call_die(perf_db_export_callchains);
1049 export_callchains = !!ret;
1050 }
1051
1052 if (export_callchains) {
1053 /*
1054 * Attempt to use the call path root from the call return
1055 * processor, if the call return processor is in use. Otherwise,
1056 * we allocate a new call path root. This prevents exporting
1057 * duplicate call path ids when both are in use simultaniously.
1058 */
1059 if (tables->dbe.crp)
1060 tables->dbe.cpr = tables->dbe.crp->cpr;
1061 else
1062 tables->dbe.cpr = call_path_root__new();
1063
1064 if (!tables->dbe.cpr)
1065 Py_FatalError("failed to create calls processor");
1066 }
1067
1036 tables->db_export_mode = true; 1068 tables->db_export_mode = true;
1037 /* 1069 /*
1038 * Reserve per symbol space for symbol->db_id via symbol__priv() 1070 * Reserve per symbol space for symbol->db_id via symbol__priv()
diff --git a/tools/perf/util/thread-stack.c b/tools/perf/util/thread-stack.c
index 679688e70ae7..825086aa9a08 100644
--- a/tools/perf/util/thread-stack.c
+++ b/tools/perf/util/thread-stack.c
@@ -22,44 +22,9 @@
22#include "debug.h" 22#include "debug.h"
23#include "symbol.h" 23#include "symbol.h"
24#include "comm.h" 24#include "comm.h"
25#include "call-path.h"
25#include "thread-stack.h" 26#include "thread-stack.h"
26 27
27#define CALL_PATH_BLOCK_SHIFT 8
28#define CALL_PATH_BLOCK_SIZE (1 << CALL_PATH_BLOCK_SHIFT)
29#define CALL_PATH_BLOCK_MASK (CALL_PATH_BLOCK_SIZE - 1)
30
31struct call_path_block {
32 struct call_path cp[CALL_PATH_BLOCK_SIZE];
33 struct list_head node;
34};
35
36/**
37 * struct call_path_root - root of all call paths.
38 * @call_path: root call path
39 * @blocks: list of blocks to store call paths
40 * @next: next free space
41 * @sz: number of spaces
42 */
43struct call_path_root {
44 struct call_path call_path;
45 struct list_head blocks;
46 size_t next;
47 size_t sz;
48};
49
50/**
51 * struct call_return_processor - provides a call-back to consume call-return
52 * information.
53 * @cpr: call path root
54 * @process: call-back that accepts call/return information
55 * @data: anonymous data for call-back
56 */
57struct call_return_processor {
58 struct call_path_root *cpr;
59 int (*process)(struct call_return *cr, void *data);
60 void *data;
61};
62
63#define STACK_GROWTH 2048 28#define STACK_GROWTH 2048
64 29
65/** 30/**
@@ -335,108 +300,6 @@ void thread_stack__sample(struct thread *thread, struct ip_callchain *chain,
335 chain->ips[i] = thread->ts->stack[thread->ts->cnt - i].ret_addr; 300 chain->ips[i] = thread->ts->stack[thread->ts->cnt - i].ret_addr;
336} 301}
337 302
338static void call_path__init(struct call_path *cp, struct call_path *parent,
339 struct symbol *sym, u64 ip, bool in_kernel)
340{
341 cp->parent = parent;
342 cp->sym = sym;
343 cp->ip = sym ? 0 : ip;
344 cp->db_id = 0;
345 cp->in_kernel = in_kernel;
346 RB_CLEAR_NODE(&cp->rb_node);
347 cp->children = RB_ROOT;
348}
349
350static struct call_path_root *call_path_root__new(void)
351{
352 struct call_path_root *cpr;
353
354 cpr = zalloc(sizeof(struct call_path_root));
355 if (!cpr)
356 return NULL;
357 call_path__init(&cpr->call_path, NULL, NULL, 0, false);
358 INIT_LIST_HEAD(&cpr->blocks);
359 return cpr;
360}
361
362static void call_path_root__free(struct call_path_root *cpr)
363{
364 struct call_path_block *pos, *n;
365
366 list_for_each_entry_safe(pos, n, &cpr->blocks, node) {
367 list_del(&pos->node);
368 free(pos);
369 }
370 free(cpr);
371}
372
373static struct call_path *call_path__new(struct call_path_root *cpr,
374 struct call_path *parent,
375 struct symbol *sym, u64 ip,
376 bool in_kernel)
377{
378 struct call_path_block *cpb;
379 struct call_path *cp;
380 size_t n;
381
382 if (cpr->next < cpr->sz) {
383 cpb = list_last_entry(&cpr->blocks, struct call_path_block,
384 node);
385 } else {
386 cpb = zalloc(sizeof(struct call_path_block));
387 if (!cpb)
388 return NULL;
389 list_add_tail(&cpb->node, &cpr->blocks);
390 cpr->sz += CALL_PATH_BLOCK_SIZE;
391 }
392
393 n = cpr->next++ & CALL_PATH_BLOCK_MASK;
394 cp = &cpb->cp[n];
395
396 call_path__init(cp, parent, sym, ip, in_kernel);
397
398 return cp;
399}
400
401static struct call_path *call_path__findnew(struct call_path_root *cpr,
402 struct call_path *parent,
403 struct symbol *sym, u64 ip, u64 ks)
404{
405 struct rb_node **p;
406 struct rb_node *node_parent = NULL;
407 struct call_path *cp;
408 bool in_kernel = ip >= ks;
409
410 if (sym)
411 ip = 0;
412
413 if (!parent)
414 return call_path__new(cpr, parent, sym, ip, in_kernel);
415
416 p = &parent->children.rb_node;
417 while (*p != NULL) {
418 node_parent = *p;
419 cp = rb_entry(node_parent, struct call_path, rb_node);
420
421 if (cp->sym == sym && cp->ip == ip)
422 return cp;
423
424 if (sym < cp->sym || (sym == cp->sym && ip < cp->ip))
425 p = &(*p)->rb_left;
426 else
427 p = &(*p)->rb_right;
428 }
429
430 cp = call_path__new(cpr, parent, sym, ip, in_kernel);
431 if (!cp)
432 return NULL;
433
434 rb_link_node(&cp->rb_node, node_parent, p);
435 rb_insert_color(&cp->rb_node, &parent->children);
436
437 return cp;
438}
439
440struct call_return_processor * 303struct call_return_processor *
441call_return_processor__new(int (*process)(struct call_return *cr, void *data), 304call_return_processor__new(int (*process)(struct call_return *cr, void *data),
442 void *data) 305 void *data)
diff --git a/tools/perf/util/thread-stack.h b/tools/perf/util/thread-stack.h
index e1528f1374c3..ad44c7944b8e 100644
--- a/tools/perf/util/thread-stack.h
+++ b/tools/perf/util/thread-stack.h
@@ -19,17 +19,16 @@
19#include <sys/types.h> 19#include <sys/types.h>
20 20
21#include <linux/types.h> 21#include <linux/types.h>
22#include <linux/rbtree.h>
23 22
24struct thread; 23struct thread;
25struct comm; 24struct comm;
26struct ip_callchain; 25struct ip_callchain;
27struct symbol; 26struct symbol;
28struct dso; 27struct dso;
29struct call_return_processor;
30struct comm; 28struct comm;
31struct perf_sample; 29struct perf_sample;
32struct addr_location; 30struct addr_location;
31struct call_path;
33 32
34/* 33/*
35 * Call/Return flags. 34 * Call/Return flags.
@@ -69,26 +68,16 @@ struct call_return {
69}; 68};
70 69
71/** 70/**
72 * struct call_path - node in list of calls leading to a function call. 71 * struct call_return_processor - provides a call-back to consume call-return
73 * @parent: call path to the parent function call 72 * information.
74 * @sym: symbol of function called 73 * @cpr: call path root
75 * @ip: only if sym is null, the ip of the function 74 * @process: call-back that accepts call/return information
76 * @db_id: id used for db-export 75 * @data: anonymous data for call-back
77 * @in_kernel: whether function is a in the kernel
78 * @rb_node: node in parent's tree of called functions
79 * @children: tree of call paths of functions called
80 *
81 * In combination with the call_return structure, the call_path structure
82 * defines a context-sensitve call-graph.
83 */ 76 */
84struct call_path { 77struct call_return_processor {
85 struct call_path *parent; 78 struct call_path_root *cpr;
86 struct symbol *sym; 79 int (*process)(struct call_return *cr, void *data);
87 u64 ip; 80 void *data;
88 u64 db_id;
89 bool in_kernel;
90 struct rb_node rb_node;
91 struct rb_root children;
92}; 81};
93 82
94int thread_stack__event(struct thread *thread, u32 flags, u64 from_ip, 83int thread_stack__event(struct thread *thread, u32 flags, u64 from_ip,