aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/perf_event.h12
-rw-r--r--kernel/perf_event.c15
-rw-r--r--tools/perf/Documentation/perf-diff.txt55
-rw-r--r--tools/perf/Documentation/perf-probe.txt3
-rw-r--r--tools/perf/Documentation/perf-report.txt4
-rw-r--r--tools/perf/Documentation/perf-trace.txt27
-rw-r--r--tools/perf/Makefile4
-rw-r--r--tools/perf/builtin-annotate.c66
-rw-r--r--tools/perf/builtin-buildid-list.c4
-rw-r--r--tools/perf/builtin-diff.c248
-rw-r--r--tools/perf/builtin-kmem.c64
-rw-r--r--tools/perf/builtin-probe.c141
-rw-r--r--tools/perf/builtin-record.c141
-rw-r--r--tools/perf/builtin-report.c723
-rw-r--r--tools/perf/builtin-sched.c93
-rw-r--r--tools/perf/builtin-timechart.c59
-rw-r--r--tools/perf/builtin-top.c45
-rw-r--r--tools/perf/builtin-trace.c349
-rw-r--r--tools/perf/builtin.h1
-rw-r--r--tools/perf/command-list.txt1
-rw-r--r--tools/perf/perf.c1
-rw-r--r--tools/perf/scripts/perl/bin/check-perf-trace-report1
-rw-r--r--tools/perf/scripts/perl/bin/rw-by-file-report4
-rw-r--r--tools/perf/scripts/perl/bin/rw-by-pid-report1
-rw-r--r--tools/perf/scripts/perl/bin/wakeup-latency-report1
-rw-r--r--tools/perf/scripts/perl/bin/workqueue-stats-report1
-rw-r--r--tools/perf/scripts/perl/rw-by-file.pl5
-rw-r--r--tools/perf/util/data_map.c96
-rw-r--r--tools/perf/util/data_map.h29
-rw-r--r--tools/perf/util/event.c142
-rw-r--r--tools/perf/util/event.h36
-rw-r--r--tools/perf/util/header.c2
-rw-r--r--tools/perf/util/hist.c518
-rw-r--r--tools/perf/util/hist.h55
-rw-r--r--tools/perf/util/map.c18
-rw-r--r--tools/perf/util/probe-event.c207
-rw-r--r--tools/perf/util/probe-event.h11
-rw-r--r--tools/perf/util/probe-finder.c4
-rw-r--r--tools/perf/util/probe-finder.h3
-rw-r--r--tools/perf/util/session.c84
-rw-r--r--tools/perf/util/session.h45
-rw-r--r--tools/perf/util/sort.c26
-rw-r--r--tools/perf/util/sort.h12
-rw-r--r--tools/perf/util/string.c25
-rw-r--r--tools/perf/util/string.h2
-rw-r--r--tools/perf/util/strlist.c6
-rw-r--r--tools/perf/util/strlist.h41
-rw-r--r--tools/perf/util/symbol.c144
-rw-r--r--tools/perf/util/symbol.h34
-rw-r--r--tools/perf/util/thread.c37
-rw-r--r--tools/perf/util/thread.h16
-rw-r--r--tools/perf/util/trace-event-perl.c42
-rw-r--r--tools/perf/util/trace-event.h2
53 files changed, 2293 insertions, 1413 deletions
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index da7bdc23f279..c66b34f75eea 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -211,17 +211,11 @@ struct perf_event_attr {
211 __u32 wakeup_watermark; /* bytes before wakeup */ 211 __u32 wakeup_watermark; /* bytes before wakeup */
212 }; 212 };
213 213
214 struct { /* Hardware breakpoint info */
215 __u64 bp_addr;
216 __u32 bp_type;
217 __u32 bp_len;
218 __u64 __bp_reserved_1;
219 __u64 __bp_reserved_2;
220 };
221
222 __u32 __reserved_2; 214 __u32 __reserved_2;
223 215
224 __u64 __reserved_3; 216 __u64 bp_addr;
217 __u32 bp_type;
218 __u32 bp_len;
225}; 219};
226 220
227/* 221/*
diff --git a/kernel/perf_event.c b/kernel/perf_event.c
index 9052d6c8c9fd..8ab86988bd24 100644
--- a/kernel/perf_event.c
+++ b/kernel/perf_event.c
@@ -782,6 +782,9 @@ static void __perf_install_in_context(void *info)
782 782
783 add_event_to_ctx(event, ctx); 783 add_event_to_ctx(event, ctx);
784 784
785 if (event->cpu != -1 && event->cpu != smp_processor_id())
786 goto unlock;
787
785 /* 788 /*
786 * Don't put the event on if it is disabled or if 789 * Don't put the event on if it is disabled or if
787 * it is in a group and the group isn't on. 790 * it is in a group and the group isn't on.
@@ -925,6 +928,9 @@ static void __perf_event_enable(void *info)
925 goto unlock; 928 goto unlock;
926 __perf_event_mark_enabled(event, ctx); 929 __perf_event_mark_enabled(event, ctx);
927 930
931 if (event->cpu != -1 && event->cpu != smp_processor_id())
932 goto unlock;
933
928 /* 934 /*
929 * If the event is in a group and isn't the group leader, 935 * If the event is in a group and isn't the group leader,
930 * then don't put it on unless the group is on. 936 * then don't put it on unless the group is on.
@@ -1595,15 +1601,12 @@ static struct perf_event_context *find_get_context(pid_t pid, int cpu)
1595 unsigned long flags; 1601 unsigned long flags;
1596 int err; 1602 int err;
1597 1603
1598 /* 1604 if (pid == -1 && cpu != -1) {
1599 * If cpu is not a wildcard then this is a percpu event:
1600 */
1601 if (cpu != -1) {
1602 /* Must be root to operate on a CPU event: */ 1605 /* Must be root to operate on a CPU event: */
1603 if (perf_paranoid_cpu() && !capable(CAP_SYS_ADMIN)) 1606 if (perf_paranoid_cpu() && !capable(CAP_SYS_ADMIN))
1604 return ERR_PTR(-EACCES); 1607 return ERR_PTR(-EACCES);
1605 1608
1606 if (cpu < 0 || cpu > num_possible_cpus()) 1609 if (cpu < 0 || cpu >= nr_cpumask_bits)
1607 return ERR_PTR(-EINVAL); 1610 return ERR_PTR(-EINVAL);
1608 1611
1609 /* 1612 /*
@@ -4564,7 +4567,7 @@ static int perf_copy_attr(struct perf_event_attr __user *uattr,
4564 if (attr->type >= PERF_TYPE_MAX) 4567 if (attr->type >= PERF_TYPE_MAX)
4565 return -EINVAL; 4568 return -EINVAL;
4566 4569
4567 if (attr->__reserved_1 || attr->__reserved_2 || attr->__reserved_3) 4570 if (attr->__reserved_1 || attr->__reserved_2)
4568 return -EINVAL; 4571 return -EINVAL;
4569 4572
4570 if (attr->sample_type & ~(PERF_SAMPLE_MAX-1)) 4573 if (attr->sample_type & ~(PERF_SAMPLE_MAX-1))
diff --git a/tools/perf/Documentation/perf-diff.txt b/tools/perf/Documentation/perf-diff.txt
new file mode 100644
index 000000000000..8974e208cba6
--- /dev/null
+++ b/tools/perf/Documentation/perf-diff.txt
@@ -0,0 +1,55 @@
1perf-diff(1)
2==============
3
4NAME
5----
6perf-diff - Read two perf.data files and display the differential profile
7
8SYNOPSIS
9--------
10[verse]
11'perf diff' [oldfile] [newfile]
12
13DESCRIPTION
14-----------
15This command displays the performance difference amongst two perf.data files
16captured via perf record.
17
18If no parameters are passed it will assume perf.data.old and perf.data.
19
20OPTIONS
21-------
22-d::
23--dsos=::
24 Only consider symbols in these dsos. CSV that understands
25 file://filename entries.
26
27-C::
28--comms=::
29 Only consider symbols in these comms. CSV that understands
30 file://filename entries.
31
32-S::
33--symbols=::
34 Only consider these symbols. CSV that understands
35 file://filename entries.
36
37-s::
38--sort=::
39 Sort by key(s): pid, comm, dso, symbol.
40
41-t::
42--field-separator=::
43
44 Use a special separator character and don't pad with spaces, replacing
45 all occurances of this separator in symbol names (and other output)
46 with a '.' character, that thus it's the only non valid separator.
47
48-v::
49--verbose::
50 Be verbose, for instance, show the raw counts in addition to the
51 diff.
52
53SEE ALSO
54--------
55linkperf:perf-record[1]
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 8fa6bf99fcb5..250e391b4bc8 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -49,8 +49,9 @@ PROBE SYNTAX
49------------ 49------------
50Probe points are defined by following syntax. 50Probe points are defined by following syntax.
51 51
52 "FUNC[+OFFS|:RLN|%return][@SRC]|SRC:ALN [ARG ...]" 52 "[EVENT=]FUNC[+OFFS|:RLN|%return][@SRC]|SRC:ALN [ARG ...]"
53 53
54'EVENT' specifies the name of new event, if omitted, it will be set the name of the probed function. Currently, event group name is set as 'probe'.
54'FUNC' specifies a probed function name, and it may have one of the following options; '+OFFS' is the offset from function entry address in bytes, 'RLN' is the relative-line number from function entry line, and '%return' means that it probes function return. In addition, 'SRC' specifies a source file which has that function. 55'FUNC' specifies a probed function name, and it may have one of the following options; '+OFFS' is the offset from function entry address in bytes, 'RLN' is the relative-line number from function entry line, and '%return' means that it probes function return. In addition, 'SRC' specifies a source file which has that function.
55It is also possible to specify a probe point by the source line number by using 'SRC:ALN' syntax, where 'SRC' is the source file path and 'ALN' is the line number. 56It is also possible to specify a probe point by the source line number by using 'SRC:ALN' syntax, where 'SRC' is the source file path and 'ALN' is the line number.
56'ARG' specifies the arguments of this probe point. You can use the name of local variable, or kprobe-tracer argument format (e.g. $retval, %ax, etc). 57'ARG' specifies the arguments of this probe point. You can use the name of local variable, or kprobe-tracer argument format (e.g. $retval, %ax, etc).
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 9dccb180b7af..abfabe9147a4 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -39,6 +39,10 @@ OPTIONS
39 Only consider these symbols. CSV that understands 39 Only consider these symbols. CSV that understands
40 file://filename entries. 40 file://filename entries.
41 41
42-s::
43--sort=::
44 Sort by key(s): pid, comm, dso, symbol, parent.
45
42-w:: 46-w::
43--field-width=:: 47--field-width=::
44 Force each column width to the provided list, for large terminal 48 Force each column width to the provided list, for large terminal
diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt
index 07065efa60e0..60e5900da483 100644
--- a/tools/perf/Documentation/perf-trace.txt
+++ b/tools/perf/Documentation/perf-trace.txt
@@ -8,18 +8,43 @@ perf-trace - Read perf.data (created by perf record) and display trace output
8SYNOPSIS 8SYNOPSIS
9-------- 9--------
10[verse] 10[verse]
11'perf trace' [-i <file> | --input=file] symbol_name 11'perf trace' {record <script> | report <script> [args] }
12 12
13DESCRIPTION 13DESCRIPTION
14----------- 14-----------
15This command reads the input file and displays the trace recorded. 15This command reads the input file and displays the trace recorded.
16 16
17There are several variants of perf trace:
18
19 'perf trace' to see a detailed trace of the workload that was
20 recorded.
21
22 'perf trace record <script>' to record the events required for 'perf
23 trace report'. <script> is the name displayed in the output of
24 'perf trace --list' i.e. the actual script name minus any language
25 extension.
26
27 'perf trace report <script>' to run and display the results of
28 <script>. <script> is the name displayed in the output of 'perf
29 trace --list' i.e. the actual script name minus any language
30 extension. The perf.data output from a previous run of 'perf trace
31 record <script>' is used and should be present for this command to
32 succeed.
33
17OPTIONS 34OPTIONS
18------- 35-------
19-D:: 36-D::
20--dump-raw-trace=:: 37--dump-raw-trace=::
21 Display verbose dump of the trace data. 38 Display verbose dump of the trace data.
22 39
40-L::
41--Latency=::
42 Show latency attributes (irqs/preemption disabled, etc).
43
44-l::
45--list=::
46 Display a list of available trace scripts.
47
23-s:: 48-s::
24--script=:: 49--script=::
25 Process trace data with the given script ([lang]:script[.ext]). 50 Process trace data with the given script ([lang]:script[.ext]).
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 406999668cab..7814dbbd401d 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -370,7 +370,6 @@ LIB_H += util/values.h
370LIB_H += util/sort.h 370LIB_H += util/sort.h
371LIB_H += util/hist.h 371LIB_H += util/hist.h
372LIB_H += util/thread.h 372LIB_H += util/thread.h
373LIB_H += util/data_map.h
374LIB_H += util/probe-finder.h 373LIB_H += util/probe-finder.h
375LIB_H += util/probe-event.h 374LIB_H += util/probe-event.h
376 375
@@ -428,6 +427,7 @@ BUILTIN_OBJS += bench/sched-messaging.o
428BUILTIN_OBJS += bench/sched-pipe.o 427BUILTIN_OBJS += bench/sched-pipe.o
429BUILTIN_OBJS += bench/mem-memcpy.o 428BUILTIN_OBJS += bench/mem-memcpy.o
430 429
430BUILTIN_OBJS += builtin-diff.o
431BUILTIN_OBJS += builtin-help.o 431BUILTIN_OBJS += builtin-help.o
432BUILTIN_OBJS += builtin-sched.o 432BUILTIN_OBJS += builtin-sched.o
433BUILTIN_OBJS += builtin-buildid-list.o 433BUILTIN_OBJS += builtin-buildid-list.o
@@ -996,8 +996,6 @@ install: all
996 $(INSTALL) scripts/perl/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace' 996 $(INSTALL) scripts/perl/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'
997 $(INSTALL) scripts/perl/*.pl -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl' 997 $(INSTALL) scripts/perl/*.pl -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl'
998 $(INSTALL) scripts/perl/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin' 998 $(INSTALL) scripts/perl/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'
999 $(INSTALL) scripts/perl/Perf-Trace-Util/Makefile.PL -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util'
1000 $(INSTALL) scripts/perl/Perf-Trace-Util/README -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util'
1001ifdef BUILT_INS 999ifdef BUILT_INS
1002 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' 1000 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
1003 $(INSTALL) $(BUILT_INS) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' 1001 $(INSTALL) $(BUILT_INS) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 21a78d30d53d..593ff25006de 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -26,7 +26,6 @@
26#include "util/sort.h" 26#include "util/sort.h"
27#include "util/hist.h" 27#include "util/hist.h"
28#include "util/session.h" 28#include "util/session.h"
29#include "util/data_map.h"
30 29
31static char const *input_name = "perf.data"; 30static char const *input_name = "perf.data";
32 31
@@ -52,11 +51,6 @@ struct sym_priv {
52 struct sym_ext *ext; 51 struct sym_ext *ext;
53}; 52};
54 53
55static struct symbol_conf symbol_conf = {
56 .priv_size = sizeof(struct sym_priv),
57 .try_vmlinux_path = true,
58};
59
60static const char *sym_hist_filter; 54static const char *sym_hist_filter;
61 55
62static int symbol_filter(struct map *map __used, struct symbol *sym) 56static int symbol_filter(struct map *map __used, struct symbol *sym)
@@ -122,30 +116,32 @@ static void hist_hit(struct hist_entry *he, u64 ip)
122 h->ip[offset]); 116 h->ip[offset]);
123} 117}
124 118
125static int hist_entry__add(struct addr_location *al, u64 count) 119static int perf_session__add_hist_entry(struct perf_session *self,
120 struct addr_location *al, u64 count)
126{ 121{
127 bool hit; 122 bool hit;
128 struct hist_entry *he = __hist_entry__add(al, NULL, count, &hit); 123 struct hist_entry *he = __perf_session__add_hist_entry(self, al, NULL,
124 count, &hit);
129 if (he == NULL) 125 if (he == NULL)
130 return -ENOMEM; 126 return -ENOMEM;
131 hist_hit(he, al->addr); 127 hist_hit(he, al->addr);
132 return 0; 128 return 0;
133} 129}
134 130
135static int process_sample_event(event_t *event) 131static int process_sample_event(event_t *event, struct perf_session *session)
136{ 132{
137 struct addr_location al; 133 struct addr_location al;
138 134
139 dump_printf("(IP, %d): %d: %p\n", event->header.misc, 135 dump_printf("(IP, %d): %d: %p\n", event->header.misc,
140 event->ip.pid, (void *)(long)event->ip.ip); 136 event->ip.pid, (void *)(long)event->ip.ip);
141 137
142 if (event__preprocess_sample(event, &al, symbol_filter) < 0) { 138 if (event__preprocess_sample(event, session, &al, symbol_filter) < 0) {
143 fprintf(stderr, "problem processing %d event, skipping it.\n", 139 fprintf(stderr, "problem processing %d event, skipping it.\n",
144 event->header.type); 140 event->header.type);
145 return -1; 141 return -1;
146 } 142 }
147 143
148 if (hist_entry__add(&al, 1)) { 144 if (!al.filtered && perf_session__add_hist_entry(session, &al, 1)) {
149 fprintf(stderr, "problem incrementing symbol count, " 145 fprintf(stderr, "problem incrementing symbol count, "
150 "skipping event\n"); 146 "skipping event\n");
151 return -1; 147 return -1;
@@ -429,11 +425,11 @@ static void annotate_sym(struct hist_entry *he)
429 free_source_line(he, len); 425 free_source_line(he, len);
430} 426}
431 427
432static void find_annotations(void) 428static void perf_session__find_annotations(struct perf_session *self)
433{ 429{
434 struct rb_node *nd; 430 struct rb_node *nd;
435 431
436 for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) { 432 for (nd = rb_first(&self->hists); nd; nd = rb_next(nd)) {
437 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); 433 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
438 struct sym_priv *priv; 434 struct sym_priv *priv;
439 435
@@ -454,7 +450,7 @@ static void find_annotations(void)
454 } 450 }
455} 451}
456 452
457static struct perf_file_handler file_handler = { 453static struct perf_event_ops event_ops = {
458 .process_sample_event = process_sample_event, 454 .process_sample_event = process_sample_event,
459 .process_mmap_event = event__process_mmap, 455 .process_mmap_event = event__process_mmap,
460 .process_comm_event = event__process_comm, 456 .process_comm_event = event__process_comm,
@@ -463,17 +459,14 @@ static struct perf_file_handler file_handler = {
463 459
464static int __cmd_annotate(void) 460static int __cmd_annotate(void)
465{ 461{
466 struct perf_session *session = perf_session__new(input_name, O_RDONLY, force);
467 struct thread *idle;
468 int ret; 462 int ret;
463 struct perf_session *session;
469 464
465 session = perf_session__new(input_name, O_RDONLY, force);
470 if (session == NULL) 466 if (session == NULL)
471 return -ENOMEM; 467 return -ENOMEM;
472 468
473 idle = register_idle_thread(); 469 ret = perf_session__process_events(session, &event_ops);
474 register_perf_file_handler(&file_handler);
475
476 ret = perf_session__process_events(session, 0, &event__cwdlen, &event__cwd);
477 if (ret) 470 if (ret)
478 goto out_delete; 471 goto out_delete;
479 472
@@ -483,15 +476,14 @@ static int __cmd_annotate(void)
483 } 476 }
484 477
485 if (verbose > 3) 478 if (verbose > 3)
486 threads__fprintf(stdout); 479 perf_session__fprintf(session, stdout);
487 480
488 if (verbose > 2) 481 if (verbose > 2)
489 dsos__fprintf(stdout); 482 dsos__fprintf(stdout);
490 483
491 collapse__resort(); 484 perf_session__collapse_resort(session);
492 output__resort(event__total[0]); 485 perf_session__output_resort(session, session->event_total[0]);
493 486 perf_session__find_annotations(session);
494 find_annotations();
495out_delete: 487out_delete:
496 perf_session__delete(session); 488 perf_session__delete(session);
497 489
@@ -524,29 +516,17 @@ static const struct option options[] = {
524 OPT_END() 516 OPT_END()
525}; 517};
526 518
527static void setup_sorting(void) 519int cmd_annotate(int argc, const char **argv, const char *prefix __used)
528{ 520{
529 char *tmp, *tok, *str = strdup(sort_order); 521 argc = parse_options(argc, argv, options, annotate_usage, 0);
530
531 for (tok = strtok_r(str, ", ", &tmp);
532 tok; tok = strtok_r(NULL, ", ", &tmp)) {
533 if (sort_dimension__add(tok) < 0) {
534 error("Unknown --sort key: `%s'", tok);
535 usage_with_options(annotate_usage, options);
536 }
537 }
538 522
539 free(str); 523 symbol_conf.priv_size = sizeof(struct sym_priv);
540} 524 symbol_conf.try_vmlinux_path = true;
541 525
542int cmd_annotate(int argc, const char **argv, const char *prefix __used) 526 if (symbol__init() < 0)
543{
544 if (symbol__init(&symbol_conf) < 0)
545 return -1; 527 return -1;
546 528
547 argc = parse_options(argc, argv, options, annotate_usage, 0); 529 setup_sorting(annotate_usage, options);
548
549 setup_sorting();
550 530
551 if (argc) { 531 if (argc) {
552 /* 532 /*
diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c
index bfd16a1594e4..e693e6777af5 100644
--- a/tools/perf/builtin-buildid-list.c
+++ b/tools/perf/builtin-buildid-list.c
@@ -9,7 +9,6 @@
9#include "builtin.h" 9#include "builtin.h"
10#include "perf.h" 10#include "perf.h"
11#include "util/cache.h" 11#include "util/cache.h"
12#include "util/data_map.h"
13#include "util/debug.h" 12#include "util/debug.h"
14#include "util/parse-options.h" 13#include "util/parse-options.h"
15#include "util/session.h" 14#include "util/session.h"
@@ -55,8 +54,9 @@ static int perf_file_section__process_buildids(struct perf_file_section *self,
55static int __cmd_buildid_list(void) 54static int __cmd_buildid_list(void)
56{ 55{
57 int err = -1; 56 int err = -1;
58 struct perf_session *session = perf_session__new(input_name, O_RDONLY, force); 57 struct perf_session *session;
59 58
59 session = perf_session__new(input_name, O_RDONLY, force);
60 if (session == NULL) 60 if (session == NULL)
61 return -1; 61 return -1;
62 62
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
new file mode 100644
index 000000000000..4d33b55d5584
--- /dev/null
+++ b/tools/perf/builtin-diff.c
@@ -0,0 +1,248 @@
1/*
2 * builtin-diff.c
3 *
4 * Builtin diff command: Analyze two perf.data input files, look up and read
5 * DSOs and symbol information, sort them and produce a diff.
6 */
7#include "builtin.h"
8
9#include "util/debug.h"
10#include "util/event.h"
11#include "util/hist.h"
12#include "util/session.h"
13#include "util/sort.h"
14#include "util/symbol.h"
15#include "util/util.h"
16
17#include <stdlib.h>
18
19static char const *input_old = "perf.data.old",
20 *input_new = "perf.data";
21static char diff__default_sort_order[] = "dso,symbol";
22static int force;
23static bool show_displacement;
24
25static int perf_session__add_hist_entry(struct perf_session *self,
26 struct addr_location *al, u64 count)
27{
28 bool hit;
29 struct hist_entry *he = __perf_session__add_hist_entry(self, al, NULL,
30 count, &hit);
31 if (he == NULL)
32 return -ENOMEM;
33
34 if (hit)
35 he->count += count;
36
37 return 0;
38}
39
40static int diff__process_sample_event(event_t *event, struct perf_session *session)
41{
42 struct addr_location al;
43 struct sample_data data = { .period = 1, };
44
45 dump_printf("(IP, %d): %d: %p\n", event->header.misc,
46 event->ip.pid, (void *)(long)event->ip.ip);
47
48 if (event__preprocess_sample(event, session, &al, NULL) < 0) {
49 pr_warning("problem processing %d event, skipping it.\n",
50 event->header.type);
51 return -1;
52 }
53
54 if (al.filtered)
55 return 0;
56
57 event__parse_sample(event, session->sample_type, &data);
58
59 if (al.sym && perf_session__add_hist_entry(session, &al, data.period)) {
60 pr_warning("problem incrementing symbol count, skipping event\n");
61 return -1;
62 }
63
64 session->events_stats.total += data.period;
65 return 0;
66}
67
68static struct perf_event_ops event_ops = {
69 .process_sample_event = diff__process_sample_event,
70 .process_mmap_event = event__process_mmap,
71 .process_comm_event = event__process_comm,
72 .process_exit_event = event__process_task,
73 .process_fork_event = event__process_task,
74 .process_lost_event = event__process_lost,
75};
76
77static void perf_session__insert_hist_entry_by_name(struct rb_root *root,
78 struct hist_entry *he)
79{
80 struct rb_node **p = &root->rb_node;
81 struct rb_node *parent = NULL;
82 struct hist_entry *iter;
83
84 while (*p != NULL) {
85 int cmp;
86 parent = *p;
87 iter = rb_entry(parent, struct hist_entry, rb_node);
88
89 cmp = strcmp(he->map->dso->name, iter->map->dso->name);
90 if (cmp > 0)
91 p = &(*p)->rb_left;
92 else if (cmp < 0)
93 p = &(*p)->rb_right;
94 else {
95 cmp = strcmp(he->sym->name, iter->sym->name);
96 if (cmp > 0)
97 p = &(*p)->rb_left;
98 else
99 p = &(*p)->rb_right;
100 }
101 }
102
103 rb_link_node(&he->rb_node, parent, p);
104 rb_insert_color(&he->rb_node, root);
105}
106
107static void perf_session__resort_by_name(struct perf_session *self)
108{
109 unsigned long position = 1;
110 struct rb_root tmp = RB_ROOT;
111 struct rb_node *next = rb_first(&self->hists);
112
113 while (next != NULL) {
114 struct hist_entry *n = rb_entry(next, struct hist_entry, rb_node);
115
116 next = rb_next(&n->rb_node);
117 rb_erase(&n->rb_node, &self->hists);
118 n->position = position++;
119 perf_session__insert_hist_entry_by_name(&tmp, n);
120 }
121
122 self->hists = tmp;
123}
124
125static struct hist_entry *
126perf_session__find_hist_entry_by_name(struct perf_session *self,
127 struct hist_entry *he)
128{
129 struct rb_node *n = self->hists.rb_node;
130
131 while (n) {
132 struct hist_entry *iter = rb_entry(n, struct hist_entry, rb_node);
133 int cmp = strcmp(he->map->dso->name, iter->map->dso->name);
134
135 if (cmp > 0)
136 n = n->rb_left;
137 else if (cmp < 0)
138 n = n->rb_right;
139 else {
140 cmp = strcmp(he->sym->name, iter->sym->name);
141 if (cmp > 0)
142 n = n->rb_left;
143 else if (cmp < 0)
144 n = n->rb_right;
145 else
146 return iter;
147 }
148 }
149
150 return NULL;
151}
152
153static void perf_session__match_hists(struct perf_session *old_session,
154 struct perf_session *new_session)
155{
156 struct rb_node *nd;
157
158 perf_session__resort_by_name(old_session);
159
160 for (nd = rb_first(&new_session->hists); nd; nd = rb_next(nd)) {
161 struct hist_entry *pos = rb_entry(nd, struct hist_entry, rb_node);
162 pos->pair = perf_session__find_hist_entry_by_name(old_session, pos);
163 }
164}
165
166static int __cmd_diff(void)
167{
168 int ret, i;
169 struct perf_session *session[2];
170
171 session[0] = perf_session__new(input_old, O_RDONLY, force);
172 session[1] = perf_session__new(input_new, O_RDONLY, force);
173 if (session[0] == NULL || session[1] == NULL)
174 return -ENOMEM;
175
176 for (i = 0; i < 2; ++i) {
177 ret = perf_session__process_events(session[i], &event_ops);
178 if (ret)
179 goto out_delete;
180 perf_session__output_resort(session[i], session[i]->events_stats.total);
181 }
182
183 perf_session__match_hists(session[0], session[1]);
184 perf_session__fprintf_hists(session[1], session[0],
185 show_displacement, stdout);
186out_delete:
187 for (i = 0; i < 2; ++i)
188 perf_session__delete(session[i]);
189 return ret;
190}
191
192static const char *const diff_usage[] = {
193 "perf diff [<options>] [old_file] [new_file]",
194};
195
196static const struct option options[] = {
197 OPT_BOOLEAN('v', "verbose", &verbose,
198 "be more verbose (show symbol address, etc)"),
199 OPT_BOOLEAN('m', "displacement", &show_displacement,
200 "Show position displacement relative to baseline"),
201 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
202 "dump raw trace in ASCII"),
203 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
204 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
205 "load module symbols - WARNING: use only with -k and LIVE kernel"),
206 OPT_BOOLEAN('P', "full-paths", &event_ops.full_paths,
207 "Don't shorten the pathnames taking into account the cwd"),
208 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
209 "only consider symbols in these dsos"),
210 OPT_STRING('C', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
211 "only consider symbols in these comms"),
212 OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
213 "only consider these symbols"),
214 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
215 "sort by key(s): pid, comm, dso, symbol, parent"),
216 OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator",
217 "separator for columns, no spaces will be added between "
218 "columns '.' is reserved."),
219 OPT_END()
220};
221
222int cmd_diff(int argc, const char **argv, const char *prefix __used)
223{
224 sort_order = diff__default_sort_order;
225 argc = parse_options(argc, argv, options, diff_usage, 0);
226 if (argc) {
227 if (argc > 2)
228 usage_with_options(diff_usage, options);
229 if (argc == 2) {
230 input_old = argv[0];
231 input_new = argv[1];
232 } else
233 input_new = argv[0];
234 }
235
236 symbol_conf.exclude_other = false;
237 if (symbol__init() < 0)
238 return -1;
239
240 setup_sorting(diff_usage, options);
241 setup_pager();
242
243 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", NULL);
244 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", NULL);
245 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", NULL);
246
247 return __cmd_diff();
248}
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 2071d2485913..fc21ad79dd83 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -12,7 +12,6 @@
12#include "util/trace-event.h" 12#include "util/trace-event.h"
13 13
14#include "util/debug.h" 14#include "util/debug.h"
15#include "util/data_map.h"
16 15
17#include <linux/rbtree.h> 16#include <linux/rbtree.h>
18 17
@@ -21,8 +20,6 @@ typedef int (*sort_fn_t)(struct alloc_stat *, struct alloc_stat *);
21 20
22static char const *input_name = "perf.data"; 21static char const *input_name = "perf.data";
23 22
24static u64 sample_type;
25
26static int alloc_flag; 23static int alloc_flag;
27static int caller_flag; 24static int caller_flag;
28 25
@@ -312,7 +309,7 @@ process_raw_event(event_t *raw_event __used, void *data,
312 } 309 }
313} 310}
314 311
315static int process_sample_event(event_t *event) 312static int process_sample_event(event_t *event, struct perf_session *session)
316{ 313{
317 struct sample_data data; 314 struct sample_data data;
318 struct thread *thread; 315 struct thread *thread;
@@ -322,7 +319,7 @@ static int process_sample_event(event_t *event)
322 data.cpu = -1; 319 data.cpu = -1;
323 data.period = 1; 320 data.period = 1;
324 321
325 event__parse_sample(event, sample_type, &data); 322 event__parse_sample(event, session->sample_type, &data);
326 323
327 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", 324 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n",
328 event->header.misc, 325 event->header.misc,
@@ -330,7 +327,7 @@ static int process_sample_event(event_t *event)
330 (void *)(long)data.ip, 327 (void *)(long)data.ip,
331 (long long)data.period); 328 (long long)data.period);
332 329
333 thread = threads__findnew(event->ip.pid); 330 thread = perf_session__findnew(session, event->ip.pid);
334 if (thread == NULL) { 331 if (thread == NULL) {
335 pr_debug("problem processing %d event, skipping it.\n", 332 pr_debug("problem processing %d event, skipping it.\n",
336 event->header.type); 333 event->header.type);
@@ -345,11 +342,9 @@ static int process_sample_event(event_t *event)
345 return 0; 342 return 0;
346} 343}
347 344
348static int sample_type_check(u64 type) 345static int sample_type_check(struct perf_session *session)
349{ 346{
350 sample_type = type; 347 if (!(session->sample_type & PERF_SAMPLE_RAW)) {
351
352 if (!(sample_type & PERF_SAMPLE_RAW)) {
353 fprintf(stderr, 348 fprintf(stderr,
354 "No trace sample to read. Did you call perf record " 349 "No trace sample to read. Did you call perf record "
355 "without -R?"); 350 "without -R?");
@@ -359,28 +354,12 @@ static int sample_type_check(u64 type)
359 return 0; 354 return 0;
360} 355}
361 356
362static struct perf_file_handler file_handler = { 357static struct perf_event_ops event_ops = {
363 .process_sample_event = process_sample_event, 358 .process_sample_event = process_sample_event,
364 .process_comm_event = event__process_comm, 359 .process_comm_event = event__process_comm,
365 .sample_type_check = sample_type_check, 360 .sample_type_check = sample_type_check,
366}; 361};
367 362
368static int read_events(void)
369{
370 int err;
371 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0);
372
373 if (session == NULL)
374 return -ENOMEM;
375
376 register_idle_thread();
377 register_perf_file_handler(&file_handler);
378
379 err = perf_session__process_events(session, 0, &event__cwdlen, &event__cwd);
380 perf_session__delete(session);
381 return err;
382}
383
384static double fragmentation(unsigned long n_req, unsigned long n_alloc) 363static double fragmentation(unsigned long n_req, unsigned long n_alloc)
385{ 364{
386 if (n_alloc == 0) 365 if (n_alloc == 0)
@@ -389,7 +368,8 @@ static double fragmentation(unsigned long n_req, unsigned long n_alloc)
389 return 100.0 - (100.0 * n_req / n_alloc); 368 return 100.0 - (100.0 * n_req / n_alloc);
390} 369}
391 370
392static void __print_result(struct rb_root *root, int n_lines, int is_caller) 371static void __print_result(struct rb_root *root, struct perf_session *session,
372 int n_lines, int is_caller)
393{ 373{
394 struct rb_node *next; 374 struct rb_node *next;
395 375
@@ -410,7 +390,7 @@ static void __print_result(struct rb_root *root, int n_lines, int is_caller)
410 if (is_caller) { 390 if (is_caller) {
411 addr = data->call_site; 391 addr = data->call_site;
412 if (!raw_ip) 392 if (!raw_ip)
413 sym = map_groups__find_function(kmaps, addr, NULL); 393 sym = map_groups__find_function(&session->kmaps, session, addr, NULL);
414 } else 394 } else
415 addr = data->ptr; 395 addr = data->ptr;
416 396
@@ -451,12 +431,12 @@ static void print_summary(void)
451 printf("Cross CPU allocations: %lu/%lu\n", nr_cross_allocs, nr_allocs); 431 printf("Cross CPU allocations: %lu/%lu\n", nr_cross_allocs, nr_allocs);
452} 432}
453 433
454static void print_result(void) 434static void print_result(struct perf_session *session)
455{ 435{
456 if (caller_flag) 436 if (caller_flag)
457 __print_result(&root_caller_sorted, caller_lines, 1); 437 __print_result(&root_caller_sorted, session, caller_lines, 1);
458 if (alloc_flag) 438 if (alloc_flag)
459 __print_result(&root_alloc_sorted, alloc_lines, 0); 439 __print_result(&root_alloc_sorted, session, alloc_lines, 0);
460 print_summary(); 440 print_summary();
461} 441}
462 442
@@ -524,12 +504,20 @@ static void sort_result(void)
524 504
525static int __cmd_kmem(void) 505static int __cmd_kmem(void)
526{ 506{
507 int err;
508 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0);
509 if (session == NULL)
510 return -ENOMEM;
511
527 setup_pager(); 512 setup_pager();
528 read_events(); 513 err = perf_session__process_events(session, &event_ops);
514 if (err != 0)
515 goto out_delete;
529 sort_result(); 516 sort_result();
530 print_result(); 517 print_result(session);
531 518out_delete:
532 return 0; 519 perf_session__delete(session);
520 return err;
533} 521}
534 522
535static const char * const kmem_usage[] = { 523static const char * const kmem_usage[] = {
@@ -778,13 +766,13 @@ static int __cmd_record(int argc, const char **argv)
778 766
779int cmd_kmem(int argc, const char **argv, const char *prefix __used) 767int cmd_kmem(int argc, const char **argv, const char *prefix __used)
780{ 768{
781 symbol__init(0);
782
783 argc = parse_options(argc, argv, kmem_options, kmem_usage, 0); 769 argc = parse_options(argc, argv, kmem_options, kmem_usage, 0);
784 770
785 if (!argc) 771 if (!argc)
786 usage_with_options(kmem_usage, kmem_options); 772 usage_with_options(kmem_usage, kmem_options);
787 773
774 symbol__init();
775
788 if (!strncmp(argv[0], "rec", 3)) { 776 if (!strncmp(argv[0], "rec", 3)) {
789 return __cmd_record(argc, argv); 777 return __cmd_record(argc, argv);
790 } else if (!strcmp(argv[0], "stat")) { 778 } else if (!strcmp(argv[0], "stat")) {
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index 5a47c1e11f77..7e741f54d798 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -38,34 +38,29 @@
38#include "util/strlist.h" 38#include "util/strlist.h"
39#include "util/event.h" 39#include "util/event.h"
40#include "util/debug.h" 40#include "util/debug.h"
41#include "util/symbol.h"
42#include "util/thread.h"
43#include "util/session.h"
41#include "util/parse-options.h" 44#include "util/parse-options.h"
42#include "util/parse-events.h" /* For debugfs_path */ 45#include "util/parse-events.h" /* For debugfs_path */
43#include "util/probe-finder.h" 46#include "util/probe-finder.h"
44#include "util/probe-event.h" 47#include "util/probe-event.h"
45 48
46/* Default vmlinux search paths */
47#define NR_SEARCH_PATH 4
48const char *default_search_path[NR_SEARCH_PATH] = {
49"/lib/modules/%s/build/vmlinux", /* Custom build kernel */
50"/usr/lib/debug/lib/modules/%s/vmlinux", /* Red Hat debuginfo */
51"/boot/vmlinux-debug-%s", /* Ubuntu */
52"./vmlinux", /* CWD */
53};
54
55#define MAX_PATH_LEN 256 49#define MAX_PATH_LEN 256
56#define MAX_PROBES 128 50#define MAX_PROBES 128
57 51
58/* Session management structure */ 52/* Session management structure */
59static struct { 53static struct {
60 char *vmlinux; 54 bool need_dwarf;
61 char *release; 55 bool list_events;
62 int need_dwarf; 56 bool force_add;
63 int nr_probe; 57 int nr_probe;
64 struct probe_point probes[MAX_PROBES]; 58 struct probe_point probes[MAX_PROBES];
65 struct strlist *dellist; 59 struct strlist *dellist;
60 struct perf_session *psession;
61 struct map *kmap;
66} session; 62} session;
67 63
68static bool listing;
69 64
70/* Parse an event definition. Note that any error must die. */ 65/* Parse an event definition. Note that any error must die. */
71static void parse_probe_event(const char *str) 66static void parse_probe_event(const char *str)
@@ -77,7 +72,7 @@ static void parse_probe_event(const char *str)
77 die("Too many probes (> %d) are specified.", MAX_PROBES); 72 die("Too many probes (> %d) are specified.", MAX_PROBES);
78 73
79 /* Parse perf-probe event into probe_point */ 74 /* Parse perf-probe event into probe_point */
80 session.need_dwarf = parse_perf_probe_event(str, pp); 75 parse_perf_probe_event(str, pp, &session.need_dwarf);
81 76
82 pr_debug("%d arguments\n", pp->nr_args); 77 pr_debug("%d arguments\n", pp->nr_args);
83} 78}
@@ -120,34 +115,26 @@ static int opt_del_probe_event(const struct option *opt __used,
120 return 0; 115 return 0;
121} 116}
122 117
118/* Currently just checking function name from symbol map */
119static void evaluate_probe_point(struct probe_point *pp)
120{
121 struct symbol *sym;
122 sym = map__find_symbol_by_name(session.kmap, pp->function,
123 session.psession, NULL);
124 if (!sym)
125 die("Kernel symbol \'%s\' not found - probe not added.",
126 pp->function);
127}
128
123#ifndef NO_LIBDWARF 129#ifndef NO_LIBDWARF
124static int open_default_vmlinux(void) 130static int open_vmlinux(void)
125{ 131{
126 struct utsname uts; 132 if (map__load(session.kmap, session.psession, NULL) < 0) {
127 char fname[MAX_PATH_LEN]; 133 pr_debug("Failed to load kernel map.\n");
128 int fd, ret, i; 134 return -EINVAL;
129
130 ret = uname(&uts);
131 if (ret) {
132 pr_debug("uname() failed.\n");
133 return -errno;
134 }
135 session.release = uts.release;
136 for (i = 0; i < NR_SEARCH_PATH; i++) {
137 ret = snprintf(fname, MAX_PATH_LEN,
138 default_search_path[i], session.release);
139 if (ret >= MAX_PATH_LEN || ret < 0) {
140 pr_debug("Filename(%d,%s) is too long.\n", i,
141 uts.release);
142 errno = E2BIG;
143 return -E2BIG;
144 }
145 pr_debug("try to open %s\n", fname);
146 fd = open(fname, O_RDONLY);
147 if (fd >= 0)
148 break;
149 } 135 }
150 return fd; 136 pr_debug("Try to open %s\n", session.kmap->dso->long_name);
137 return open(session.kmap->dso->long_name, O_RDONLY);
151} 138}
152#endif 139#endif
153 140
@@ -163,21 +150,22 @@ static const struct option options[] = {
163 OPT_BOOLEAN('v', "verbose", &verbose, 150 OPT_BOOLEAN('v', "verbose", &verbose,
164 "be more verbose (show parsed arguments, etc)"), 151 "be more verbose (show parsed arguments, etc)"),
165#ifndef NO_LIBDWARF 152#ifndef NO_LIBDWARF
166 OPT_STRING('k', "vmlinux", &session.vmlinux, "file", 153 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
167 "vmlinux/module pathname"), 154 "file", "vmlinux pathname"),
168#endif 155#endif
169 OPT_BOOLEAN('l', "list", &listing, "list up current probe events"), 156 OPT_BOOLEAN('l', "list", &session.list_events,
157 "list up current probe events"),
170 OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.", 158 OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.",
171 opt_del_probe_event), 159 opt_del_probe_event),
172 OPT_CALLBACK('a', "add", NULL, 160 OPT_CALLBACK('a', "add", NULL,
173#ifdef NO_LIBDWARF 161#ifdef NO_LIBDWARF
174 "FUNC[+OFFS|%return] [ARG ...]", 162 "[EVENT=]FUNC[+OFFS|%return] [ARG ...]",
175#else 163#else
176 "FUNC[+OFFS|%return|:RLN][@SRC]|SRC:ALN [ARG ...]", 164 "[EVENT=]FUNC[+OFFS|%return|:RLN][@SRC]|SRC:ALN [ARG ...]",
177#endif 165#endif
178 "probe point definition, where\n" 166 "probe point definition, where\n"
179 "\t\tGRP:\tGroup name (optional)\n" 167 "\t\tGROUP:\tGroup name (optional)\n"
180 "\t\tNAME:\tEvent name\n" 168 "\t\tEVENT:\tEvent name\n"
181 "\t\tFUNC:\tFunction name\n" 169 "\t\tFUNC:\tFunction name\n"
182 "\t\tOFFS:\tOffset from function entry (in byte)\n" 170 "\t\tOFFS:\tOffset from function entry (in byte)\n"
183 "\t\t%return:\tPut the probe at function return\n" 171 "\t\t%return:\tPut the probe at function return\n"
@@ -191,6 +179,8 @@ static const struct option options[] = {
191#endif 179#endif
192 "\t\t\tkprobe-tracer argument format.)\n", 180 "\t\t\tkprobe-tracer argument format.)\n",
193 opt_add_probe_event), 181 opt_add_probe_event),
182 OPT_BOOLEAN('f', "force", &session.force_add, "forcibly add events"
183 " with existing name"),
194 OPT_END() 184 OPT_END()
195}; 185};
196 186
@@ -204,13 +194,18 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
204 194
205 argc = parse_options(argc, argv, options, probe_usage, 195 argc = parse_options(argc, argv, options, probe_usage,
206 PARSE_OPT_STOP_AT_NON_OPTION); 196 PARSE_OPT_STOP_AT_NON_OPTION);
207 if (argc > 0) 197 if (argc > 0) {
198 if (strcmp(argv[0], "-") == 0) {
199 pr_warning(" Error: '-' is not supported.\n");
200 usage_with_options(probe_usage, options);
201 }
208 parse_probe_event_argv(argc, argv); 202 parse_probe_event_argv(argc, argv);
203 }
209 204
210 if ((session.nr_probe == 0 && !session.dellist && !listing)) 205 if ((!session.nr_probe && !session.dellist && !session.list_events))
211 usage_with_options(probe_usage, options); 206 usage_with_options(probe_usage, options);
212 207
213 if (listing) { 208 if (session.list_events) {
214 if (session.nr_probe != 0 || session.dellist) { 209 if (session.nr_probe != 0 || session.dellist) {
215 pr_warning(" Error: Don't use --list with" 210 pr_warning(" Error: Don't use --list with"
216 " --add/--del.\n"); 211 " --add/--del.\n");
@@ -227,17 +222,28 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
227 return 0; 222 return 0;
228 } 223 }
229 224
225 /* Initialize symbol maps for vmlinux */
226 symbol_conf.sort_by_name = true;
227 if (symbol_conf.vmlinux_name == NULL)
228 symbol_conf.try_vmlinux_path = true;
229 if (symbol__init() < 0)
230 die("Failed to init symbol map.");
231 session.psession = perf_session__new(NULL, O_WRONLY, false);
232 if (session.psession == NULL)
233 die("Failed to init perf_session.");
234 session.kmap = map_groups__find_by_name(&session.psession->kmaps,
235 MAP__FUNCTION,
236 "[kernel.kallsyms]");
237 if (!session.kmap)
238 die("Could not find kernel map.\n");
239
230 if (session.need_dwarf) 240 if (session.need_dwarf)
231#ifdef NO_LIBDWARF 241#ifdef NO_LIBDWARF
232 die("Debuginfo-analysis is not supported"); 242 die("Debuginfo-analysis is not supported");
233#else /* !NO_LIBDWARF */ 243#else /* !NO_LIBDWARF */
234 pr_debug("Some probes require debuginfo.\n"); 244 pr_debug("Some probes require debuginfo.\n");
235 245
236 if (session.vmlinux) { 246 fd = open_vmlinux();
237 pr_debug("Try to open %s.", session.vmlinux);
238 fd = open(session.vmlinux, O_RDONLY);
239 } else
240 fd = open_default_vmlinux();
241 if (fd < 0) { 247 if (fd < 0) {
242 if (session.need_dwarf) 248 if (session.need_dwarf)
243 die("Could not open debuginfo file."); 249 die("Could not open debuginfo file.");
@@ -255,15 +261,22 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
255 261
256 lseek(fd, SEEK_SET, 0); 262 lseek(fd, SEEK_SET, 0);
257 ret = find_probepoint(fd, pp); 263 ret = find_probepoint(fd, pp);
258 if (ret < 0) { 264 if (ret > 0)
259 if (session.need_dwarf) 265 continue;
260 die("Could not analyze debuginfo."); 266 if (ret == 0) { /* No error but failed to find probe point. */
261 267 synthesize_perf_probe_point(pp);
262 pr_warning("An error occurred in debuginfo analysis. Try to use symbols.\n"); 268 die("Probe point '%s' not found. - probe not added.",
263 break; 269 pp->probes[0]);
270 }
271 /* Error path */
272 if (session.need_dwarf) {
273 if (ret == -ENOENT)
274 pr_warning("No dwarf info found in the vmlinux - please rebuild with CONFIG_DEBUG_INFO=y.\n");
275 die("Could not analyze debuginfo.");
264 } 276 }
265 if (ret == 0) /* No error but failed to find probe point. */ 277 pr_debug("An error occurred in debuginfo analysis."
266 die("No probe point found."); 278 " Try to use symbols.\n");
279 break;
267 } 280 }
268 close(fd); 281 close(fd);
269 282
@@ -276,6 +289,7 @@ end_dwarf:
276 if (pp->found) /* This probe is already found. */ 289 if (pp->found) /* This probe is already found. */
277 continue; 290 continue;
278 291
292 evaluate_probe_point(pp);
279 ret = synthesize_trace_kprobe_event(pp); 293 ret = synthesize_trace_kprobe_event(pp);
280 if (ret == -E2BIG) 294 if (ret == -E2BIG)
281 die("probe point definition becomes too long."); 295 die("probe point definition becomes too long.");
@@ -284,7 +298,8 @@ end_dwarf:
284 } 298 }
285 299
286 /* Settng up probe points */ 300 /* Settng up probe points */
287 add_trace_kprobe_events(session.probes, session.nr_probe); 301 add_trace_kprobe_events(session.probes, session.nr_probe,
302 session.force_add);
288 return 0; 303 return 0;
289} 304}
290 305
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 4decbd14eaed..63136d0534d4 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -123,7 +123,8 @@ static void write_event(event_t *buf, size_t size)
123 write_output(buf, size); 123 write_output(buf, size);
124} 124}
125 125
126static int process_synthesized_event(event_t *event) 126static int process_synthesized_event(event_t *event,
127 struct perf_session *self __used)
127{ 128{
128 write_event(event, event->header.size); 129 write_event(event, event->header.size);
129 return 0; 130 return 0;
@@ -277,7 +278,7 @@ static void create_counter(int counter, int cpu, pid_t pid)
277 278
278 attr->mmap = track; 279 attr->mmap = track;
279 attr->comm = track; 280 attr->comm = track;
280 attr->inherit = (cpu < 0) && inherit; 281 attr->inherit = inherit;
281 attr->disabled = 1; 282 attr->disabled = 1;
282 283
283try_again: 284try_again:
@@ -401,7 +402,7 @@ static void atexit_header(void)
401 perf_header__write(&session->header, output, true); 402 perf_header__write(&session->header, output, true);
402} 403}
403 404
404static int __cmd_record(int argc, const char **argv) 405static int __cmd_record(int argc __used, const char **argv)
405{ 406{
406 int i, counter; 407 int i, counter;
407 struct stat st; 408 struct stat st;
@@ -409,6 +410,8 @@ static int __cmd_record(int argc, const char **argv)
409 int flags; 410 int flags;
410 int err; 411 int err;
411 unsigned long waking = 0; 412 unsigned long waking = 0;
413 int child_ready_pipe[2], go_pipe[2];
414 char buf;
412 415
413 page_size = sysconf(_SC_PAGE_SIZE); 416 page_size = sysconf(_SC_PAGE_SIZE);
414 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); 417 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
@@ -419,11 +422,25 @@ static int __cmd_record(int argc, const char **argv)
419 signal(SIGCHLD, sig_handler); 422 signal(SIGCHLD, sig_handler);
420 signal(SIGINT, sig_handler); 423 signal(SIGINT, sig_handler);
421 424
425 if (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0) {
426 perror("failed to create pipes");
427 exit(-1);
428 }
429
422 if (!stat(output_name, &st) && st.st_size) { 430 if (!stat(output_name, &st) && st.st_size) {
423 if (!force && !append_file) { 431 if (!force) {
424 fprintf(stderr, "Error, output file %s exists, use -A to append or -f to overwrite.\n", 432 if (!append_file) {
425 output_name); 433 pr_err("Error, output file %s exists, use -A "
426 exit(-1); 434 "to append or -f to overwrite.\n",
435 output_name);
436 exit(-1);
437 }
438 } else {
439 char oldname[PATH_MAX];
440 snprintf(oldname, sizeof(oldname), "%s.old",
441 output_name);
442 unlink(oldname);
443 rename(output_name, oldname);
427 } 444 }
428 } else { 445 } else {
429 append_file = 0; 446 append_file = 0;
@@ -466,19 +483,65 @@ static int __cmd_record(int argc, const char **argv)
466 483
467 atexit(atexit_header); 484 atexit(atexit_header);
468 485
469 if (!system_wide) { 486 if (target_pid == -1) {
470 pid = target_pid; 487 pid = fork();
471 if (pid == -1) 488 if (pid < 0) {
472 pid = getpid(); 489 perror("failed to fork");
490 exit(-1);
491 }
473 492
474 open_counters(profile_cpu, pid); 493 if (!pid) {
475 } else { 494 close(child_ready_pipe[0]);
476 if (profile_cpu != -1) { 495 close(go_pipe[1]);
477 open_counters(profile_cpu, target_pid); 496 fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);
478 } else { 497
479 for (i = 0; i < nr_cpus; i++) 498 /*
480 open_counters(i, target_pid); 499 * Do a dummy execvp to get the PLT entry resolved,
500 * so we avoid the resolver overhead on the real
501 * execvp call.
502 */
503 execvp("", (char **)argv);
504
505 /*
506 * Tell the parent we're ready to go
507 */
508 close(child_ready_pipe[1]);
509
510 /*
511 * Wait until the parent tells us to go.
512 */
513 if (read(go_pipe[0], &buf, 1) == -1)
514 perror("unable to read pipe");
515
516 execvp(argv[0], (char **)argv);
517
518 perror(argv[0]);
519 exit(-1);
481 } 520 }
521
522 child_pid = pid;
523
524 if (!system_wide)
525 target_pid = pid;
526
527 close(child_ready_pipe[1]);
528 close(go_pipe[0]);
529 /*
530 * wait for child to settle
531 */
532 if (read(child_ready_pipe[0], &buf, 1) == -1) {
533 perror("unable to read pipe");
534 exit(-1);
535 }
536 close(child_ready_pipe[0]);
537 }
538
539
540 if ((!system_wide && !inherit) || profile_cpu != -1) {
541 open_counters(profile_cpu, target_pid);
542 } else {
543 for (i = 0; i < nr_cpus; i++)
544 open_counters(i, target_pid);
482 } 545 }
483 546
484 if (file_new) { 547 if (file_new) {
@@ -488,33 +551,10 @@ static int __cmd_record(int argc, const char **argv)
488 } 551 }
489 552
490 if (!system_wide) 553 if (!system_wide)
491 event__synthesize_thread(pid, process_synthesized_event); 554 event__synthesize_thread(pid, process_synthesized_event,
555 session);
492 else 556 else
493 event__synthesize_threads(process_synthesized_event); 557 event__synthesize_threads(process_synthesized_event, session);
494
495 if (target_pid == -1 && argc) {
496 pid = fork();
497 if (pid < 0)
498 die("failed to fork");
499
500 if (!pid) {
501 if (execvp(argv[0], (char **)argv)) {
502 perror(argv[0]);
503 exit(-1);
504 }
505 } else {
506 /*
507 * Wait a bit for the execv'ed child to appear
508 * and be updated in /proc
509 * FIXME: Do you know a less heuristical solution?
510 */
511 usleep(1000);
512 event__synthesize_thread(pid,
513 process_synthesized_event);
514 }
515
516 child_pid = pid;
517 }
518 558
519 if (realtime_prio) { 559 if (realtime_prio) {
520 struct sched_param param; 560 struct sched_param param;
@@ -526,6 +566,11 @@ static int __cmd_record(int argc, const char **argv)
526 } 566 }
527 } 567 }
528 568
569 /*
570 * Let the child rip
571 */
572 close(go_pipe[1]);
573
529 for (;;) { 574 for (;;) {
530 int hits = samples; 575 int hits = samples;
531 576
@@ -620,13 +665,13 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
620{ 665{
621 int counter; 666 int counter;
622 667
623 symbol__init(0);
624
625 argc = parse_options(argc, argv, options, record_usage, 668 argc = parse_options(argc, argv, options, record_usage,
626 PARSE_OPT_STOP_AT_NON_OPTION); 669 PARSE_OPT_STOP_AT_NON_OPTION);
627 if (!argc && target_pid == -1 && !system_wide) 670 if (!argc && target_pid == -1 && (!system_wide || profile_cpu == -1))
628 usage_with_options(record_usage, options); 671 usage_with_options(record_usage, options);
629 672
673 symbol__init();
674
630 if (!nr_counters) { 675 if (!nr_counters) {
631 nr_counters = 1; 676 nr_counters = 1;
632 attrs[0].type = PERF_TYPE_HARDWARE; 677 attrs[0].type = PERF_TYPE_HARDWARE;
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index e2ec49a9b731..e50a6b10ee6f 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -27,467 +27,41 @@
27#include "util/parse-options.h" 27#include "util/parse-options.h"
28#include "util/parse-events.h" 28#include "util/parse-events.h"
29 29
30#include "util/data_map.h"
31#include "util/thread.h" 30#include "util/thread.h"
32#include "util/sort.h" 31#include "util/sort.h"
33#include "util/hist.h" 32#include "util/hist.h"
34 33
35static char const *input_name = "perf.data"; 34static char const *input_name = "perf.data";
36 35
37static char *dso_list_str, *comm_list_str, *sym_list_str,
38 *col_width_list_str;
39static struct strlist *dso_list, *comm_list, *sym_list;
40
41static int force; 36static int force;
42 37
43static int full_paths;
44static int show_nr_samples;
45
46static int show_threads; 38static int show_threads;
47static struct perf_read_values show_threads_values; 39static struct perf_read_values show_threads_values;
48 40
49static char default_pretty_printing_style[] = "normal"; 41static char default_pretty_printing_style[] = "normal";
50static char *pretty_printing_style = default_pretty_printing_style; 42static char *pretty_printing_style = default_pretty_printing_style;
51 43
52static int exclude_other = 1;
53
54static char callchain_default_opt[] = "fractal,0.5"; 44static char callchain_default_opt[] = "fractal,0.5";
55 45
56static struct perf_session *session; 46static int perf_session__add_hist_entry(struct perf_session *self,
57 47 struct addr_location *al,
58static u64 sample_type; 48 struct ip_callchain *chain, u64 count)
59
60struct symbol_conf symbol_conf;
61
62
63static size_t
64callchain__fprintf_left_margin(FILE *fp, int left_margin)
65{
66 int i;
67 int ret;
68
69 ret = fprintf(fp, " ");
70
71 for (i = 0; i < left_margin; i++)
72 ret += fprintf(fp, " ");
73
74 return ret;
75}
76
77static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask,
78 int left_margin)
79{
80 int i;
81 size_t ret = 0;
82
83 ret += callchain__fprintf_left_margin(fp, left_margin);
84
85 for (i = 0; i < depth; i++)
86 if (depth_mask & (1 << i))
87 ret += fprintf(fp, "| ");
88 else
89 ret += fprintf(fp, " ");
90
91 ret += fprintf(fp, "\n");
92
93 return ret;
94}
95static size_t
96ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain, int depth,
97 int depth_mask, int count, u64 total_samples,
98 int hits, int left_margin)
99{
100 int i;
101 size_t ret = 0;
102
103 ret += callchain__fprintf_left_margin(fp, left_margin);
104 for (i = 0; i < depth; i++) {
105 if (depth_mask & (1 << i))
106 ret += fprintf(fp, "|");
107 else
108 ret += fprintf(fp, " ");
109 if (!count && i == depth - 1) {
110 double percent;
111
112 percent = hits * 100.0 / total_samples;
113 ret += percent_color_fprintf(fp, "--%2.2f%%-- ", percent);
114 } else
115 ret += fprintf(fp, "%s", " ");
116 }
117 if (chain->sym)
118 ret += fprintf(fp, "%s\n", chain->sym->name);
119 else
120 ret += fprintf(fp, "%p\n", (void *)(long)chain->ip);
121
122 return ret;
123}
124
125static struct symbol *rem_sq_bracket;
126static struct callchain_list rem_hits;
127
128static void init_rem_hits(void)
129{
130 rem_sq_bracket = malloc(sizeof(*rem_sq_bracket) + 6);
131 if (!rem_sq_bracket) {
132 fprintf(stderr, "Not enough memory to display remaining hits\n");
133 return;
134 }
135
136 strcpy(rem_sq_bracket->name, "[...]");
137 rem_hits.sym = rem_sq_bracket;
138}
139
140static size_t
141__callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
142 u64 total_samples, int depth, int depth_mask,
143 int left_margin)
144{
145 struct rb_node *node, *next;
146 struct callchain_node *child;
147 struct callchain_list *chain;
148 int new_depth_mask = depth_mask;
149 u64 new_total;
150 u64 remaining;
151 size_t ret = 0;
152 int i;
153
154 if (callchain_param.mode == CHAIN_GRAPH_REL)
155 new_total = self->children_hit;
156 else
157 new_total = total_samples;
158
159 remaining = new_total;
160
161 node = rb_first(&self->rb_root);
162 while (node) {
163 u64 cumul;
164
165 child = rb_entry(node, struct callchain_node, rb_node);
166 cumul = cumul_hits(child);
167 remaining -= cumul;
168
169 /*
170 * The depth mask manages the output of pipes that show
171 * the depth. We don't want to keep the pipes of the current
172 * level for the last child of this depth.
173 * Except if we have remaining filtered hits. They will
174 * supersede the last child
175 */
176 next = rb_next(node);
177 if (!next && (callchain_param.mode != CHAIN_GRAPH_REL || !remaining))
178 new_depth_mask &= ~(1 << (depth - 1));
179
180 /*
181 * But we keep the older depth mask for the line seperator
182 * to keep the level link until we reach the last child
183 */
184 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask,
185 left_margin);
186 i = 0;
187 list_for_each_entry(chain, &child->val, list) {
188 if (chain->ip >= PERF_CONTEXT_MAX)
189 continue;
190 ret += ipchain__fprintf_graph(fp, chain, depth,
191 new_depth_mask, i++,
192 new_total,
193 cumul,
194 left_margin);
195 }
196 ret += __callchain__fprintf_graph(fp, child, new_total,
197 depth + 1,
198 new_depth_mask | (1 << depth),
199 left_margin);
200 node = next;
201 }
202
203 if (callchain_param.mode == CHAIN_GRAPH_REL &&
204 remaining && remaining != new_total) {
205
206 if (!rem_sq_bracket)
207 return ret;
208
209 new_depth_mask &= ~(1 << (depth - 1));
210
211 ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
212 new_depth_mask, 0, new_total,
213 remaining, left_margin);
214 }
215
216 return ret;
217}
218
219
220static size_t
221callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
222 u64 total_samples, int left_margin)
223{
224 struct callchain_list *chain;
225 bool printed = false;
226 int i = 0;
227 int ret = 0;
228
229 list_for_each_entry(chain, &self->val, list) {
230 if (chain->ip >= PERF_CONTEXT_MAX)
231 continue;
232
233 if (!i++ && sort__first_dimension == SORT_SYM)
234 continue;
235
236 if (!printed) {
237 ret += callchain__fprintf_left_margin(fp, left_margin);
238 ret += fprintf(fp, "|\n");
239 ret += callchain__fprintf_left_margin(fp, left_margin);
240 ret += fprintf(fp, "---");
241
242 left_margin += 3;
243 printed = true;
244 } else
245 ret += callchain__fprintf_left_margin(fp, left_margin);
246
247 if (chain->sym)
248 ret += fprintf(fp, " %s\n", chain->sym->name);
249 else
250 ret += fprintf(fp, " %p\n", (void *)(long)chain->ip);
251 }
252
253 ret += __callchain__fprintf_graph(fp, self, total_samples, 1, 1, left_margin);
254
255 return ret;
256}
257
258static size_t
259callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
260 u64 total_samples)
261{
262 struct callchain_list *chain;
263 size_t ret = 0;
264
265 if (!self)
266 return 0;
267
268 ret += callchain__fprintf_flat(fp, self->parent, total_samples);
269
270
271 list_for_each_entry(chain, &self->val, list) {
272 if (chain->ip >= PERF_CONTEXT_MAX)
273 continue;
274 if (chain->sym)
275 ret += fprintf(fp, " %s\n", chain->sym->name);
276 else
277 ret += fprintf(fp, " %p\n",
278 (void *)(long)chain->ip);
279 }
280
281 return ret;
282}
283
284static size_t
285hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
286 u64 total_samples, int left_margin)
287{
288 struct rb_node *rb_node;
289 struct callchain_node *chain;
290 size_t ret = 0;
291
292 rb_node = rb_first(&self->sorted_chain);
293 while (rb_node) {
294 double percent;
295
296 chain = rb_entry(rb_node, struct callchain_node, rb_node);
297 percent = chain->hit * 100.0 / total_samples;
298 switch (callchain_param.mode) {
299 case CHAIN_FLAT:
300 ret += percent_color_fprintf(fp, " %6.2f%%\n",
301 percent);
302 ret += callchain__fprintf_flat(fp, chain, total_samples);
303 break;
304 case CHAIN_GRAPH_ABS: /* Falldown */
305 case CHAIN_GRAPH_REL:
306 ret += callchain__fprintf_graph(fp, chain, total_samples,
307 left_margin);
308 case CHAIN_NONE:
309 default:
310 break;
311 }
312 ret += fprintf(fp, "\n");
313 rb_node = rb_next(rb_node);
314 }
315
316 return ret;
317}
318
319static size_t
320hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
321{
322 struct sort_entry *se;
323 size_t ret;
324
325 if (exclude_other && !self->parent)
326 return 0;
327
328 if (total_samples)
329 ret = percent_color_fprintf(fp,
330 field_sep ? "%.2f" : " %6.2f%%",
331 (self->count * 100.0) / total_samples);
332 else
333 ret = fprintf(fp, field_sep ? "%lld" : "%12lld ", self->count);
334
335 if (show_nr_samples) {
336 if (field_sep)
337 fprintf(fp, "%c%lld", *field_sep, self->count);
338 else
339 fprintf(fp, "%11lld", self->count);
340 }
341
342 list_for_each_entry(se, &hist_entry__sort_list, list) {
343 if (se->elide)
344 continue;
345
346 fprintf(fp, "%s", field_sep ?: " ");
347 ret += se->print(fp, self, se->width ? *se->width : 0);
348 }
349
350 ret += fprintf(fp, "\n");
351
352 if (callchain) {
353 int left_margin = 0;
354
355 if (sort__first_dimension == SORT_COMM) {
356 se = list_first_entry(&hist_entry__sort_list, typeof(*se),
357 list);
358 left_margin = se->width ? *se->width : 0;
359 left_margin -= thread__comm_len(self->thread);
360 }
361
362 hist_entry_callchain__fprintf(fp, self, total_samples,
363 left_margin);
364 }
365
366 return ret;
367}
368
369/*
370 *
371 */
372
373static void dso__calc_col_width(struct dso *self)
374{
375 if (!col_width_list_str && !field_sep &&
376 (!dso_list || strlist__has_entry(dso_list, self->name))) {
377 unsigned int slen = strlen(self->name);
378 if (slen > dsos__col_width)
379 dsos__col_width = slen;
380 }
381
382 self->slen_calculated = 1;
383}
384
385static void thread__comm_adjust(struct thread *self)
386{
387 char *comm = self->comm;
388
389 if (!col_width_list_str && !field_sep &&
390 (!comm_list || strlist__has_entry(comm_list, comm))) {
391 unsigned int slen = strlen(comm);
392
393 if (slen > comms__col_width) {
394 comms__col_width = slen;
395 threads__col_width = slen + 6;
396 }
397 }
398}
399
400static int thread__set_comm_adjust(struct thread *self, const char *comm)
401{
402 int ret = thread__set_comm(self, comm);
403
404 if (ret)
405 return ret;
406
407 thread__comm_adjust(self);
408
409 return 0;
410}
411
412static int call__match(struct symbol *sym)
413{
414 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
415 return 1;
416
417 return 0;
418}
419
420static struct symbol **resolve_callchain(struct thread *thread,
421 struct ip_callchain *chain,
422 struct symbol **parent)
423{
424 u8 cpumode = PERF_RECORD_MISC_USER;
425 struct symbol **syms = NULL;
426 unsigned int i;
427
428 if (callchain) {
429 syms = calloc(chain->nr, sizeof(*syms));
430 if (!syms) {
431 fprintf(stderr, "Can't allocate memory for symbols\n");
432 exit(-1);
433 }
434 }
435
436 for (i = 0; i < chain->nr; i++) {
437 u64 ip = chain->ips[i];
438 struct addr_location al;
439
440 if (ip >= PERF_CONTEXT_MAX) {
441 switch (ip) {
442 case PERF_CONTEXT_HV:
443 cpumode = PERF_RECORD_MISC_HYPERVISOR; break;
444 case PERF_CONTEXT_KERNEL:
445 cpumode = PERF_RECORD_MISC_KERNEL; break;
446 case PERF_CONTEXT_USER:
447 cpumode = PERF_RECORD_MISC_USER; break;
448 default:
449 break;
450 }
451 continue;
452 }
453
454 thread__find_addr_location(thread, cpumode, MAP__FUNCTION,
455 ip, &al, NULL);
456 if (al.sym != NULL) {
457 if (sort__has_parent && !*parent &&
458 call__match(al.sym))
459 *parent = al.sym;
460 if (!callchain)
461 break;
462 syms[i] = al.sym;
463 }
464 }
465
466 return syms;
467}
468
469/*
470 * collect histogram counts
471 */
472
473static int hist_entry__add(struct addr_location *al,
474 struct ip_callchain *chain, u64 count)
475{ 49{
476 struct symbol **syms = NULL, *parent = NULL; 50 struct symbol **syms = NULL, *parent = NULL;
477 bool hit; 51 bool hit;
478 struct hist_entry *he; 52 struct hist_entry *he;
479 53
480 if ((sort__has_parent || callchain) && chain) 54 if ((sort__has_parent || symbol_conf.use_callchain) && chain)
481 syms = resolve_callchain(al->thread, chain, &parent); 55 syms = perf_session__resolve_callchain(self, al->thread,
482 56 chain, &parent);
483 he = __hist_entry__add(al, parent, count, &hit); 57 he = __perf_session__add_hist_entry(self, al, parent, count, &hit);
484 if (he == NULL) 58 if (he == NULL)
485 return -ENOMEM; 59 return -ENOMEM;
486 60
487 if (hit) 61 if (hit)
488 he->count += count; 62 he->count += count;
489 63
490 if (callchain) { 64 if (symbol_conf.use_callchain) {
491 if (!hit) 65 if (!hit)
492 callchain_init(&he->callchain); 66 callchain_init(&he->callchain);
493 append_chain(&he->callchain, chain, syms); 67 append_chain(&he->callchain, chain, syms);
@@ -497,100 +71,6 @@ static int hist_entry__add(struct addr_location *al,
497 return 0; 71 return 0;
498} 72}
499 73
500static size_t output__fprintf(FILE *fp, u64 total_samples)
501{
502 struct hist_entry *pos;
503 struct sort_entry *se;
504 struct rb_node *nd;
505 size_t ret = 0;
506 unsigned int width;
507 char *col_width = col_width_list_str;
508 int raw_printing_style;
509
510 raw_printing_style = !strcmp(pretty_printing_style, "raw");
511
512 init_rem_hits();
513
514 fprintf(fp, "# Samples: %Ld\n", (u64)total_samples);
515 fprintf(fp, "#\n");
516
517 fprintf(fp, "# Overhead");
518 if (show_nr_samples) {
519 if (field_sep)
520 fprintf(fp, "%cSamples", *field_sep);
521 else
522 fputs(" Samples ", fp);
523 }
524 list_for_each_entry(se, &hist_entry__sort_list, list) {
525 if (se->elide)
526 continue;
527 if (field_sep) {
528 fprintf(fp, "%c%s", *field_sep, se->header);
529 continue;
530 }
531 width = strlen(se->header);
532 if (se->width) {
533 if (col_width_list_str) {
534 if (col_width) {
535 *se->width = atoi(col_width);
536 col_width = strchr(col_width, ',');
537 if (col_width)
538 ++col_width;
539 }
540 }
541 width = *se->width = max(*se->width, width);
542 }
543 fprintf(fp, " %*s", width, se->header);
544 }
545 fprintf(fp, "\n");
546
547 if (field_sep)
548 goto print_entries;
549
550 fprintf(fp, "# ........");
551 if (show_nr_samples)
552 fprintf(fp, " ..........");
553 list_for_each_entry(se, &hist_entry__sort_list, list) {
554 unsigned int i;
555
556 if (se->elide)
557 continue;
558
559 fprintf(fp, " ");
560 if (se->width)
561 width = *se->width;
562 else
563 width = strlen(se->header);
564 for (i = 0; i < width; i++)
565 fprintf(fp, ".");
566 }
567 fprintf(fp, "\n");
568
569 fprintf(fp, "#\n");
570
571print_entries:
572 for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) {
573 pos = rb_entry(nd, struct hist_entry, rb_node);
574 ret += hist_entry__fprintf(fp, pos, total_samples);
575 }
576
577 if (sort_order == default_sort_order &&
578 parent_pattern == default_parent_pattern) {
579 fprintf(fp, "#\n");
580 fprintf(fp, "# (For a higher level overview, try: perf report --sort comm,dso)\n");
581 fprintf(fp, "#\n");
582 }
583 fprintf(fp, "\n");
584
585 free(rem_sq_bracket);
586
587 if (show_threads)
588 perf_read_values_display(fp, &show_threads_values,
589 raw_printing_style);
590
591 return ret;
592}
593
594static int validate_chain(struct ip_callchain *chain, event_t *event) 74static int validate_chain(struct ip_callchain *chain, event_t *event)
595{ 75{
596 unsigned int chain_size; 76 unsigned int chain_size;
@@ -604,17 +84,12 @@ static int validate_chain(struct ip_callchain *chain, event_t *event)
604 return 0; 84 return 0;
605} 85}
606 86
607static int process_sample_event(event_t *event) 87static int process_sample_event(event_t *event, struct perf_session *session)
608{ 88{
609 struct sample_data data; 89 struct sample_data data = { .period = 1, };
610 int cpumode;
611 struct addr_location al; 90 struct addr_location al;
612 struct thread *thread;
613
614 memset(&data, 0, sizeof(data));
615 data.period = 1;
616 91
617 event__parse_sample(event, sample_type, &data); 92 event__parse_sample(event, session->sample_type, &data);
618 93
619 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", 94 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n",
620 event->header.misc, 95 event->header.misc,
@@ -622,7 +97,7 @@ static int process_sample_event(event_t *event)
622 (void *)(long)data.ip, 97 (void *)(long)data.ip,
623 (long long)data.period); 98 (long long)data.period);
624 99
625 if (sample_type & PERF_SAMPLE_CALLCHAIN) { 100 if (session->sample_type & PERF_SAMPLE_CALLCHAIN) {
626 unsigned int i; 101 unsigned int i;
627 102
628 dump_printf("... chain: nr:%Lu\n", data.callchain->nr); 103 dump_printf("... chain: nr:%Lu\n", data.callchain->nr);
@@ -640,65 +115,25 @@ static int process_sample_event(event_t *event)
640 } 115 }
641 } 116 }
642 117
643 thread = threads__findnew(data.pid); 118 if (event__preprocess_sample(event, session, &al, NULL) < 0) {
644 if (thread == NULL) { 119 fprintf(stderr, "problem processing %d event, skipping it.\n",
645 pr_debug("problem processing %d event, skipping it.\n",
646 event->header.type); 120 event->header.type);
647 return -1; 121 return -1;
648 } 122 }
649 123
650 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); 124 if (al.filtered)
651
652 if (comm_list && !strlist__has_entry(comm_list, thread->comm))
653 return 0;
654
655 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
656
657 thread__find_addr_location(thread, cpumode,
658 MAP__FUNCTION, data.ip, &al, NULL);
659 /*
660 * We have to do this here as we may have a dso with no symbol hit that
661 * has a name longer than the ones with symbols sampled.
662 */
663 if (al.map && !sort_dso.elide && !al.map->dso->slen_calculated)
664 dso__calc_col_width(al.map->dso);
665
666 if (dso_list &&
667 (!al.map || !al.map->dso ||
668 !(strlist__has_entry(dso_list, al.map->dso->short_name) ||
669 (al.map->dso->short_name != al.map->dso->long_name &&
670 strlist__has_entry(dso_list, al.map->dso->long_name)))))
671 return 0;
672
673 if (sym_list && al.sym && !strlist__has_entry(sym_list, al.sym->name))
674 return 0; 125 return 0;
675 126
676 if (hist_entry__add(&al, data.callchain, data.period)) { 127 if (perf_session__add_hist_entry(session, &al, data.callchain, data.period)) {
677 pr_debug("problem incrementing symbol count, skipping event\n"); 128 pr_debug("problem incrementing symbol count, skipping event\n");
678 return -1; 129 return -1;
679 } 130 }
680 131
681 event__stats.total += data.period; 132 session->events_stats.total += data.period;
682
683 return 0; 133 return 0;
684} 134}
685 135
686static int process_comm_event(event_t *event) 136static int process_read_event(event_t *event, struct perf_session *session __used)
687{
688 struct thread *thread = threads__findnew(event->comm.pid);
689
690 dump_printf(": %s:%d\n", event->comm.comm, event->comm.pid);
691
692 if (thread == NULL ||
693 thread__set_comm_adjust(thread, event->comm.comm)) {
694 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
695 return -1;
696 }
697
698 return 0;
699}
700
701static int process_read_event(event_t *event)
702{ 137{
703 struct perf_event_attr *attr; 138 struct perf_event_attr *attr;
704 139
@@ -721,25 +156,23 @@ static int process_read_event(event_t *event)
721 return 0; 156 return 0;
722} 157}
723 158
724static int sample_type_check(u64 type) 159static int sample_type_check(struct perf_session *session)
725{ 160{
726 sample_type = type; 161 if (!(session->sample_type & PERF_SAMPLE_CALLCHAIN)) {
727
728 if (!(sample_type & PERF_SAMPLE_CALLCHAIN)) {
729 if (sort__has_parent) { 162 if (sort__has_parent) {
730 fprintf(stderr, "selected --sort parent, but no" 163 fprintf(stderr, "selected --sort parent, but no"
731 " callchain data. Did you call" 164 " callchain data. Did you call"
732 " perf record without -g?\n"); 165 " perf record without -g?\n");
733 return -1; 166 return -1;
734 } 167 }
735 if (callchain) { 168 if (symbol_conf.use_callchain) {
736 fprintf(stderr, "selected -g but no callchain data." 169 fprintf(stderr, "selected -g but no callchain data."
737 " Did you call perf record without" 170 " Did you call perf record without"
738 " -g?\n"); 171 " -g?\n");
739 return -1; 172 return -1;
740 } 173 }
741 } else if (callchain_param.mode != CHAIN_NONE && !callchain) { 174 } else if (callchain_param.mode != CHAIN_NONE && !symbol_conf.use_callchain) {
742 callchain = 1; 175 symbol_conf.use_callchain = true;
743 if (register_callchain_param(&callchain_param) < 0) { 176 if (register_callchain_param(&callchain_param) < 0) {
744 fprintf(stderr, "Can't register callchain" 177 fprintf(stderr, "Can't register callchain"
745 " params\n"); 178 " params\n");
@@ -750,10 +183,10 @@ static int sample_type_check(u64 type)
750 return 0; 183 return 0;
751} 184}
752 185
753static struct perf_file_handler file_handler = { 186static struct perf_event_ops event_ops = {
754 .process_sample_event = process_sample_event, 187 .process_sample_event = process_sample_event,
755 .process_mmap_event = event__process_mmap, 188 .process_mmap_event = event__process_mmap,
756 .process_comm_event = process_comm_event, 189 .process_comm_event = event__process_comm,
757 .process_exit_event = event__process_task, 190 .process_exit_event = event__process_task,
758 .process_fork_event = event__process_task, 191 .process_fork_event = event__process_task,
759 .process_lost_event = event__process_lost, 192 .process_lost_event = event__process_lost,
@@ -764,23 +197,17 @@ static struct perf_file_handler file_handler = {
764 197
765static int __cmd_report(void) 198static int __cmd_report(void)
766{ 199{
767 struct thread *idle;
768 int ret; 200 int ret;
201 struct perf_session *session;
769 202
770 session = perf_session__new(input_name, O_RDONLY, force); 203 session = perf_session__new(input_name, O_RDONLY, force);
771 if (session == NULL) 204 if (session == NULL)
772 return -ENOMEM; 205 return -ENOMEM;
773 206
774 idle = register_idle_thread();
775 thread__comm_adjust(idle);
776
777 if (show_threads) 207 if (show_threads)
778 perf_read_values_init(&show_threads_values); 208 perf_read_values_init(&show_threads_values);
779 209
780 register_perf_file_handler(&file_handler); 210 ret = perf_session__process_events(session, &event_ops);
781
782 ret = perf_session__process_events(session, full_paths,
783 &event__cwdlen, &event__cwd);
784 if (ret) 211 if (ret)
785 goto out_delete; 212 goto out_delete;
786 213
@@ -790,17 +217,25 @@ static int __cmd_report(void)
790 } 217 }
791 218
792 if (verbose > 3) 219 if (verbose > 3)
793 threads__fprintf(stdout); 220 perf_session__fprintf(session, stdout);
794 221
795 if (verbose > 2) 222 if (verbose > 2)
796 dsos__fprintf(stdout); 223 dsos__fprintf(stdout);
797 224
798 collapse__resort(); 225 perf_session__collapse_resort(session);
799 output__resort(event__stats.total); 226 perf_session__output_resort(session, session->events_stats.total);
800 output__fprintf(stdout, event__stats.total); 227 fprintf(stdout, "# Samples: %ld\n#\n", session->events_stats.total);
228 perf_session__fprintf_hists(session, NULL, false, stdout);
229 if (sort_order == default_sort_order &&
230 parent_pattern == default_parent_pattern)
231 fprintf(stdout, "#\n# (For a higher level overview, try: perf report --sort comm,dso)\n#\n");
801 232
802 if (show_threads) 233 if (show_threads) {
234 bool raw_printing_style = !strcmp(pretty_printing_style, "raw");
235 perf_read_values_display(stdout, &show_threads_values,
236 raw_printing_style);
803 perf_read_values_destroy(&show_threads_values); 237 perf_read_values_destroy(&show_threads_values);
238 }
804out_delete: 239out_delete:
805 perf_session__delete(session); 240 perf_session__delete(session);
806 return ret; 241 return ret;
@@ -813,7 +248,7 @@ parse_callchain_opt(const struct option *opt __used, const char *arg,
813 char *tok; 248 char *tok;
814 char *endptr; 249 char *endptr;
815 250
816 callchain = 1; 251 symbol_conf.use_callchain = true;
817 252
818 if (!arg) 253 if (!arg)
819 return 0; 254 return 0;
@@ -834,7 +269,7 @@ parse_callchain_opt(const struct option *opt __used, const char *arg,
834 269
835 else if (!strncmp(tok, "none", strlen(arg))) { 270 else if (!strncmp(tok, "none", strlen(arg))) {
836 callchain_param.mode = CHAIN_NONE; 271 callchain_param.mode = CHAIN_NONE;
837 callchain = 0; 272 symbol_conf.use_callchain = true;
838 273
839 return 0; 274 return 0;
840 } 275 }
@@ -877,7 +312,7 @@ static const struct option options[] = {
877 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), 312 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
878 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, 313 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
879 "load module symbols - WARNING: use only with -k and LIVE kernel"), 314 "load module symbols - WARNING: use only with -k and LIVE kernel"),
880 OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples, 315 OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
881 "Show a column with the number of samples"), 316 "Show a column with the number of samples"),
882 OPT_BOOLEAN('T', "threads", &show_threads, 317 OPT_BOOLEAN('T', "threads", &show_threads,
883 "Show per-thread event counters"), 318 "Show per-thread event counters"),
@@ -885,78 +320,46 @@ static const struct option options[] = {
885 "pretty printing style key: normal raw"), 320 "pretty printing style key: normal raw"),
886 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 321 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
887 "sort by key(s): pid, comm, dso, symbol, parent"), 322 "sort by key(s): pid, comm, dso, symbol, parent"),
888 OPT_BOOLEAN('P', "full-paths", &full_paths, 323 OPT_BOOLEAN('P', "full-paths", &event_ops.full_paths,
889 "Don't shorten the pathnames taking into account the cwd"), 324 "Don't shorten the pathnames taking into account the cwd"),
890 OPT_STRING('p', "parent", &parent_pattern, "regex", 325 OPT_STRING('p', "parent", &parent_pattern, "regex",
891 "regex filter to identify parent, see: '--sort parent'"), 326 "regex filter to identify parent, see: '--sort parent'"),
892 OPT_BOOLEAN('x', "exclude-other", &exclude_other, 327 OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other,
893 "Only display entries with parent-match"), 328 "Only display entries with parent-match"),
894 OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent", 329 OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent",
895 "Display callchains using output_type and min percent threshold. " 330 "Display callchains using output_type and min percent threshold. "
896 "Default: fractal,0.5", &parse_callchain_opt, callchain_default_opt), 331 "Default: fractal,0.5", &parse_callchain_opt, callchain_default_opt),
897 OPT_STRING('d', "dsos", &dso_list_str, "dso[,dso...]", 332 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
898 "only consider symbols in these dsos"), 333 "only consider symbols in these dsos"),
899 OPT_STRING('C', "comms", &comm_list_str, "comm[,comm...]", 334 OPT_STRING('C', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
900 "only consider symbols in these comms"), 335 "only consider symbols in these comms"),
901 OPT_STRING('S', "symbols", &sym_list_str, "symbol[,symbol...]", 336 OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
902 "only consider these symbols"), 337 "only consider these symbols"),
903 OPT_STRING('w', "column-widths", &col_width_list_str, 338 OPT_STRING('w', "column-widths", &symbol_conf.col_width_list_str,
904 "width[,width...]", 339 "width[,width...]",
905 "don't try to adjust column width, use these fixed values"), 340 "don't try to adjust column width, use these fixed values"),
906 OPT_STRING('t', "field-separator", &field_sep, "separator", 341 OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator",
907 "separator for columns, no spaces will be added between " 342 "separator for columns, no spaces will be added between "
908 "columns '.' is reserved."), 343 "columns '.' is reserved."),
909 OPT_END() 344 OPT_END()
910}; 345};
911 346
912static void setup_sorting(void) 347int cmd_report(int argc, const char **argv, const char *prefix __used)
913{ 348{
914 char *tmp, *tok, *str = strdup(sort_order); 349 argc = parse_options(argc, argv, options, report_usage, 0);
915
916 for (tok = strtok_r(str, ", ", &tmp);
917 tok; tok = strtok_r(NULL, ", ", &tmp)) {
918 if (sort_dimension__add(tok) < 0) {
919 error("Unknown --sort key: `%s'", tok);
920 usage_with_options(report_usage, options);
921 }
922 }
923
924 free(str);
925}
926 350
927static void setup_list(struct strlist **list, const char *list_str, 351 setup_pager();
928 struct sort_entry *se, const char *list_name,
929 FILE *fp)
930{
931 if (list_str) {
932 *list = strlist__new(true, list_str);
933 if (!*list) {
934 fprintf(stderr, "problems parsing %s list\n",
935 list_name);
936 exit(129);
937 }
938 if (strlist__nr_entries(*list) == 1) {
939 fprintf(fp, "# %s: %s\n", list_name,
940 strlist__entry(*list, 0)->s);
941 se->elide = true;
942 }
943 }
944}
945 352
946int cmd_report(int argc, const char **argv, const char *prefix __used) 353 if (symbol__init() < 0)
947{
948 if (symbol__init(&symbol_conf) < 0)
949 return -1; 354 return -1;
950 355
951 argc = parse_options(argc, argv, options, report_usage, 0); 356 setup_sorting(report_usage, options);
952
953 setup_sorting();
954 357
955 if (parent_pattern != default_parent_pattern) { 358 if (parent_pattern != default_parent_pattern) {
956 sort_dimension__add("parent"); 359 sort_dimension__add("parent");
957 sort_parent.elide = 1; 360 sort_parent.elide = 1;
958 } else 361 } else
959 exclude_other = 0; 362 symbol_conf.exclude_other = false;
960 363
961 /* 364 /*
962 * Any (unrecognized) arguments left? 365 * Any (unrecognized) arguments left?
@@ -964,17 +367,9 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
964 if (argc) 367 if (argc)
965 usage_with_options(report_usage, options); 368 usage_with_options(report_usage, options);
966 369
967 setup_pager(); 370 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", stdout);
968 371 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout);
969 setup_list(&dso_list, dso_list_str, &sort_dso, "dso", stdout); 372 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout);
970 setup_list(&comm_list, comm_list_str, &sort_comm, "comm", stdout);
971 setup_list(&sym_list, sym_list_str, &sort_sym, "symbol", stdout);
972
973 if (field_sep && *field_sep == '.') {
974 fputs("'.' is the only non valid --field-separator argument\n",
975 stderr);
976 exit(129);
977 }
978 373
979 return __cmd_report(); 374 return __cmd_report();
980} 375}
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index 65021fe1361e..80209df6cfe8 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -12,7 +12,6 @@
12#include "util/trace-event.h" 12#include "util/trace-event.h"
13 13
14#include "util/debug.h" 14#include "util/debug.h"
15#include "util/data_map.h"
16 15
17#include <sys/prctl.h> 16#include <sys/prctl.h>
18 17
@@ -22,8 +21,6 @@
22 21
23static char const *input_name = "perf.data"; 22static char const *input_name = "perf.data";
24 23
25static u64 sample_type;
26
27static char default_sort_order[] = "avg, max, switch, runtime"; 24static char default_sort_order[] = "avg, max, switch, runtime";
28static char *sort_order = default_sort_order; 25static char *sort_order = default_sort_order;
29 26
@@ -731,18 +728,21 @@ struct trace_migrate_task_event {
731 728
732struct trace_sched_handler { 729struct trace_sched_handler {
733 void (*switch_event)(struct trace_switch_event *, 730 void (*switch_event)(struct trace_switch_event *,
731 struct perf_session *,
734 struct event *, 732 struct event *,
735 int cpu, 733 int cpu,
736 u64 timestamp, 734 u64 timestamp,
737 struct thread *thread); 735 struct thread *thread);
738 736
739 void (*runtime_event)(struct trace_runtime_event *, 737 void (*runtime_event)(struct trace_runtime_event *,
738 struct perf_session *,
740 struct event *, 739 struct event *,
741 int cpu, 740 int cpu,
742 u64 timestamp, 741 u64 timestamp,
743 struct thread *thread); 742 struct thread *thread);
744 743
745 void (*wakeup_event)(struct trace_wakeup_event *, 744 void (*wakeup_event)(struct trace_wakeup_event *,
745 struct perf_session *,
746 struct event *, 746 struct event *,
747 int cpu, 747 int cpu,
748 u64 timestamp, 748 u64 timestamp,
@@ -755,6 +755,7 @@ struct trace_sched_handler {
755 struct thread *thread); 755 struct thread *thread);
756 756
757 void (*migrate_task_event)(struct trace_migrate_task_event *, 757 void (*migrate_task_event)(struct trace_migrate_task_event *,
758 struct perf_session *session,
758 struct event *, 759 struct event *,
759 int cpu, 760 int cpu,
760 u64 timestamp, 761 u64 timestamp,
@@ -764,6 +765,7 @@ struct trace_sched_handler {
764 765
765static void 766static void
766replay_wakeup_event(struct trace_wakeup_event *wakeup_event, 767replay_wakeup_event(struct trace_wakeup_event *wakeup_event,
768 struct perf_session *session __used,
767 struct event *event, 769 struct event *event,
768 int cpu __used, 770 int cpu __used,
769 u64 timestamp __used, 771 u64 timestamp __used,
@@ -790,6 +792,7 @@ static u64 cpu_last_switched[MAX_CPUS];
790 792
791static void 793static void
792replay_switch_event(struct trace_switch_event *switch_event, 794replay_switch_event(struct trace_switch_event *switch_event,
795 struct perf_session *session __used,
793 struct event *event, 796 struct event *event,
794 int cpu, 797 int cpu,
795 u64 timestamp, 798 u64 timestamp,
@@ -1023,6 +1026,7 @@ add_sched_in_event(struct work_atoms *atoms, u64 timestamp)
1023 1026
1024static void 1027static void
1025latency_switch_event(struct trace_switch_event *switch_event, 1028latency_switch_event(struct trace_switch_event *switch_event,
1029 struct perf_session *session,
1026 struct event *event __used, 1030 struct event *event __used,
1027 int cpu, 1031 int cpu,
1028 u64 timestamp, 1032 u64 timestamp,
@@ -1046,8 +1050,8 @@ latency_switch_event(struct trace_switch_event *switch_event,
1046 die("hm, delta: %Ld < 0 ?\n", delta); 1050 die("hm, delta: %Ld < 0 ?\n", delta);
1047 1051
1048 1052
1049 sched_out = threads__findnew(switch_event->prev_pid); 1053 sched_out = perf_session__findnew(session, switch_event->prev_pid);
1050 sched_in = threads__findnew(switch_event->next_pid); 1054 sched_in = perf_session__findnew(session, switch_event->next_pid);
1051 1055
1052 out_events = thread_atoms_search(&atom_root, sched_out, &cmp_pid); 1056 out_events = thread_atoms_search(&atom_root, sched_out, &cmp_pid);
1053 if (!out_events) { 1057 if (!out_events) {
@@ -1075,12 +1079,13 @@ latency_switch_event(struct trace_switch_event *switch_event,
1075 1079
1076static void 1080static void
1077latency_runtime_event(struct trace_runtime_event *runtime_event, 1081latency_runtime_event(struct trace_runtime_event *runtime_event,
1082 struct perf_session *session,
1078 struct event *event __used, 1083 struct event *event __used,
1079 int cpu, 1084 int cpu,
1080 u64 timestamp, 1085 u64 timestamp,
1081 struct thread *this_thread __used) 1086 struct thread *this_thread __used)
1082{ 1087{
1083 struct thread *thread = threads__findnew(runtime_event->pid); 1088 struct thread *thread = perf_session__findnew(session, runtime_event->pid);
1084 struct work_atoms *atoms = thread_atoms_search(&atom_root, thread, &cmp_pid); 1089 struct work_atoms *atoms = thread_atoms_search(&atom_root, thread, &cmp_pid);
1085 1090
1086 BUG_ON(cpu >= MAX_CPUS || cpu < 0); 1091 BUG_ON(cpu >= MAX_CPUS || cpu < 0);
@@ -1097,6 +1102,7 @@ latency_runtime_event(struct trace_runtime_event *runtime_event,
1097 1102
1098static void 1103static void
1099latency_wakeup_event(struct trace_wakeup_event *wakeup_event, 1104latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
1105 struct perf_session *session,
1100 struct event *__event __used, 1106 struct event *__event __used,
1101 int cpu __used, 1107 int cpu __used,
1102 u64 timestamp, 1108 u64 timestamp,
@@ -1110,7 +1116,7 @@ latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
1110 if (!wakeup_event->success) 1116 if (!wakeup_event->success)
1111 return; 1117 return;
1112 1118
1113 wakee = threads__findnew(wakeup_event->pid); 1119 wakee = perf_session__findnew(session, wakeup_event->pid);
1114 atoms = thread_atoms_search(&atom_root, wakee, &cmp_pid); 1120 atoms = thread_atoms_search(&atom_root, wakee, &cmp_pid);
1115 if (!atoms) { 1121 if (!atoms) {
1116 thread_atoms_insert(wakee); 1122 thread_atoms_insert(wakee);
@@ -1144,6 +1150,7 @@ latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
1144 1150
1145static void 1151static void
1146latency_migrate_task_event(struct trace_migrate_task_event *migrate_task_event, 1152latency_migrate_task_event(struct trace_migrate_task_event *migrate_task_event,
1153 struct perf_session *session,
1147 struct event *__event __used, 1154 struct event *__event __used,
1148 int cpu __used, 1155 int cpu __used,
1149 u64 timestamp, 1156 u64 timestamp,
@@ -1159,7 +1166,7 @@ latency_migrate_task_event(struct trace_migrate_task_event *migrate_task_event,
1159 if (profile_cpu == -1) 1166 if (profile_cpu == -1)
1160 return; 1167 return;
1161 1168
1162 migrant = threads__findnew(migrate_task_event->pid); 1169 migrant = perf_session__findnew(session, migrate_task_event->pid);
1163 atoms = thread_atoms_search(&atom_root, migrant, &cmp_pid); 1170 atoms = thread_atoms_search(&atom_root, migrant, &cmp_pid);
1164 if (!atoms) { 1171 if (!atoms) {
1165 thread_atoms_insert(migrant); 1172 thread_atoms_insert(migrant);
@@ -1354,7 +1361,7 @@ static void sort_lat(void)
1354static struct trace_sched_handler *trace_handler; 1361static struct trace_sched_handler *trace_handler;
1355 1362
1356static void 1363static void
1357process_sched_wakeup_event(void *data, 1364process_sched_wakeup_event(void *data, struct perf_session *session,
1358 struct event *event, 1365 struct event *event,
1359 int cpu __used, 1366 int cpu __used,
1360 u64 timestamp __used, 1367 u64 timestamp __used,
@@ -1371,7 +1378,8 @@ process_sched_wakeup_event(void *data,
1371 FILL_FIELD(wakeup_event, cpu, event, data); 1378 FILL_FIELD(wakeup_event, cpu, event, data);
1372 1379
1373 if (trace_handler->wakeup_event) 1380 if (trace_handler->wakeup_event)
1374 trace_handler->wakeup_event(&wakeup_event, event, cpu, timestamp, thread); 1381 trace_handler->wakeup_event(&wakeup_event, session, event,
1382 cpu, timestamp, thread);
1375} 1383}
1376 1384
1377/* 1385/*
@@ -1389,6 +1397,7 @@ static char next_shortname2 = '0';
1389 1397
1390static void 1398static void
1391map_switch_event(struct trace_switch_event *switch_event, 1399map_switch_event(struct trace_switch_event *switch_event,
1400 struct perf_session *session,
1392 struct event *event __used, 1401 struct event *event __used,
1393 int this_cpu, 1402 int this_cpu,
1394 u64 timestamp, 1403 u64 timestamp,
@@ -1416,8 +1425,8 @@ map_switch_event(struct trace_switch_event *switch_event,
1416 die("hm, delta: %Ld < 0 ?\n", delta); 1425 die("hm, delta: %Ld < 0 ?\n", delta);
1417 1426
1418 1427
1419 sched_out = threads__findnew(switch_event->prev_pid); 1428 sched_out = perf_session__findnew(session, switch_event->prev_pid);
1420 sched_in = threads__findnew(switch_event->next_pid); 1429 sched_in = perf_session__findnew(session, switch_event->next_pid);
1421 1430
1422 curr_thread[this_cpu] = sched_in; 1431 curr_thread[this_cpu] = sched_in;
1423 1432
@@ -1467,7 +1476,7 @@ map_switch_event(struct trace_switch_event *switch_event,
1467 1476
1468 1477
1469static void 1478static void
1470process_sched_switch_event(void *data, 1479process_sched_switch_event(void *data, struct perf_session *session,
1471 struct event *event, 1480 struct event *event,
1472 int this_cpu, 1481 int this_cpu,
1473 u64 timestamp __used, 1482 u64 timestamp __used,
@@ -1494,13 +1503,14 @@ process_sched_switch_event(void *data,
1494 nr_context_switch_bugs++; 1503 nr_context_switch_bugs++;
1495 } 1504 }
1496 if (trace_handler->switch_event) 1505 if (trace_handler->switch_event)
1497 trace_handler->switch_event(&switch_event, event, this_cpu, timestamp, thread); 1506 trace_handler->switch_event(&switch_event, session, event,
1507 this_cpu, timestamp, thread);
1498 1508
1499 curr_pid[this_cpu] = switch_event.next_pid; 1509 curr_pid[this_cpu] = switch_event.next_pid;
1500} 1510}
1501 1511
1502static void 1512static void
1503process_sched_runtime_event(void *data, 1513process_sched_runtime_event(void *data, struct perf_session *session,
1504 struct event *event, 1514 struct event *event,
1505 int cpu __used, 1515 int cpu __used,
1506 u64 timestamp __used, 1516 u64 timestamp __used,
@@ -1514,7 +1524,7 @@ process_sched_runtime_event(void *data,
1514 FILL_FIELD(runtime_event, vruntime, event, data); 1524 FILL_FIELD(runtime_event, vruntime, event, data);
1515 1525
1516 if (trace_handler->runtime_event) 1526 if (trace_handler->runtime_event)
1517 trace_handler->runtime_event(&runtime_event, event, cpu, timestamp, thread); 1527 trace_handler->runtime_event(&runtime_event, session, event, cpu, timestamp, thread);
1518} 1528}
1519 1529
1520static void 1530static void
@@ -1534,7 +1544,8 @@ process_sched_fork_event(void *data,
1534 FILL_FIELD(fork_event, child_pid, event, data); 1544 FILL_FIELD(fork_event, child_pid, event, data);
1535 1545
1536 if (trace_handler->fork_event) 1546 if (trace_handler->fork_event)
1537 trace_handler->fork_event(&fork_event, event, cpu, timestamp, thread); 1547 trace_handler->fork_event(&fork_event, event,
1548 cpu, timestamp, thread);
1538} 1549}
1539 1550
1540static void 1551static void
@@ -1548,7 +1559,7 @@ process_sched_exit_event(struct event *event,
1548} 1559}
1549 1560
1550static void 1561static void
1551process_sched_migrate_task_event(void *data, 1562process_sched_migrate_task_event(void *data, struct perf_session *session,
1552 struct event *event, 1563 struct event *event,
1553 int cpu __used, 1564 int cpu __used,
1554 u64 timestamp __used, 1565 u64 timestamp __used,
@@ -1564,12 +1575,13 @@ process_sched_migrate_task_event(void *data,
1564 FILL_FIELD(migrate_task_event, cpu, event, data); 1575 FILL_FIELD(migrate_task_event, cpu, event, data);
1565 1576
1566 if (trace_handler->migrate_task_event) 1577 if (trace_handler->migrate_task_event)
1567 trace_handler->migrate_task_event(&migrate_task_event, event, cpu, timestamp, thread); 1578 trace_handler->migrate_task_event(&migrate_task_event, session,
1579 event, cpu, timestamp, thread);
1568} 1580}
1569 1581
1570static void 1582static void
1571process_raw_event(event_t *raw_event __used, void *data, 1583process_raw_event(event_t *raw_event __used, struct perf_session *session,
1572 int cpu, u64 timestamp, struct thread *thread) 1584 void *data, int cpu, u64 timestamp, struct thread *thread)
1573{ 1585{
1574 struct event *event; 1586 struct event *event;
1575 int type; 1587 int type;
@@ -1579,27 +1591,27 @@ process_raw_event(event_t *raw_event __used, void *data,
1579 event = trace_find_event(type); 1591 event = trace_find_event(type);
1580 1592
1581 if (!strcmp(event->name, "sched_switch")) 1593 if (!strcmp(event->name, "sched_switch"))
1582 process_sched_switch_event(data, event, cpu, timestamp, thread); 1594 process_sched_switch_event(data, session, event, cpu, timestamp, thread);
1583 if (!strcmp(event->name, "sched_stat_runtime")) 1595 if (!strcmp(event->name, "sched_stat_runtime"))
1584 process_sched_runtime_event(data, event, cpu, timestamp, thread); 1596 process_sched_runtime_event(data, session, event, cpu, timestamp, thread);
1585 if (!strcmp(event->name, "sched_wakeup")) 1597 if (!strcmp(event->name, "sched_wakeup"))
1586 process_sched_wakeup_event(data, event, cpu, timestamp, thread); 1598 process_sched_wakeup_event(data, session, event, cpu, timestamp, thread);
1587 if (!strcmp(event->name, "sched_wakeup_new")) 1599 if (!strcmp(event->name, "sched_wakeup_new"))
1588 process_sched_wakeup_event(data, event, cpu, timestamp, thread); 1600 process_sched_wakeup_event(data, session, event, cpu, timestamp, thread);
1589 if (!strcmp(event->name, "sched_process_fork")) 1601 if (!strcmp(event->name, "sched_process_fork"))
1590 process_sched_fork_event(data, event, cpu, timestamp, thread); 1602 process_sched_fork_event(data, event, cpu, timestamp, thread);
1591 if (!strcmp(event->name, "sched_process_exit")) 1603 if (!strcmp(event->name, "sched_process_exit"))
1592 process_sched_exit_event(event, cpu, timestamp, thread); 1604 process_sched_exit_event(event, cpu, timestamp, thread);
1593 if (!strcmp(event->name, "sched_migrate_task")) 1605 if (!strcmp(event->name, "sched_migrate_task"))
1594 process_sched_migrate_task_event(data, event, cpu, timestamp, thread); 1606 process_sched_migrate_task_event(data, session, event, cpu, timestamp, thread);
1595} 1607}
1596 1608
1597static int process_sample_event(event_t *event) 1609static int process_sample_event(event_t *event, struct perf_session *session)
1598{ 1610{
1599 struct sample_data data; 1611 struct sample_data data;
1600 struct thread *thread; 1612 struct thread *thread;
1601 1613
1602 if (!(sample_type & PERF_SAMPLE_RAW)) 1614 if (!(session->sample_type & PERF_SAMPLE_RAW))
1603 return 0; 1615 return 0;
1604 1616
1605 memset(&data, 0, sizeof(data)); 1617 memset(&data, 0, sizeof(data));
@@ -1607,7 +1619,7 @@ static int process_sample_event(event_t *event)
1607 data.cpu = -1; 1619 data.cpu = -1;
1608 data.period = -1; 1620 data.period = -1;
1609 1621
1610 event__parse_sample(event, sample_type, &data); 1622 event__parse_sample(event, session->sample_type, &data);
1611 1623
1612 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", 1624 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n",
1613 event->header.misc, 1625 event->header.misc,
@@ -1615,7 +1627,7 @@ static int process_sample_event(event_t *event)
1615 (void *)(long)data.ip, 1627 (void *)(long)data.ip,
1616 (long long)data.period); 1628 (long long)data.period);
1617 1629
1618 thread = threads__findnew(data.pid); 1630 thread = perf_session__findnew(session, data.pid);
1619 if (thread == NULL) { 1631 if (thread == NULL) {
1620 pr_debug("problem processing %d event, skipping it.\n", 1632 pr_debug("problem processing %d event, skipping it.\n",
1621 event->header.type); 1633 event->header.type);
@@ -1627,12 +1639,13 @@ static int process_sample_event(event_t *event)
1627 if (profile_cpu != -1 && profile_cpu != (int)data.cpu) 1639 if (profile_cpu != -1 && profile_cpu != (int)data.cpu)
1628 return 0; 1640 return 0;
1629 1641
1630 process_raw_event(event, data.raw_data, data.cpu, data.time, thread); 1642 process_raw_event(event, session, data.raw_data, data.cpu, data.time, thread);
1631 1643
1632 return 0; 1644 return 0;
1633} 1645}
1634 1646
1635static int process_lost_event(event_t *event __used) 1647static int process_lost_event(event_t *event __used,
1648 struct perf_session *session __used)
1636{ 1649{
1637 nr_lost_chunks++; 1650 nr_lost_chunks++;
1638 nr_lost_events += event->lost.lost; 1651 nr_lost_events += event->lost.lost;
@@ -1640,11 +1653,9 @@ static int process_lost_event(event_t *event __used)
1640 return 0; 1653 return 0;
1641} 1654}
1642 1655
1643static int sample_type_check(u64 type) 1656static int sample_type_check(struct perf_session *session __used)
1644{ 1657{
1645 sample_type = type; 1658 if (!(session->sample_type & PERF_SAMPLE_RAW)) {
1646
1647 if (!(sample_type & PERF_SAMPLE_RAW)) {
1648 fprintf(stderr, 1659 fprintf(stderr,
1649 "No trace sample to read. Did you call perf record " 1660 "No trace sample to read. Did you call perf record "
1650 "without -R?"); 1661 "without -R?");
@@ -1654,7 +1665,7 @@ static int sample_type_check(u64 type)
1654 return 0; 1665 return 0;
1655} 1666}
1656 1667
1657static struct perf_file_handler file_handler = { 1668static struct perf_event_ops event_ops = {
1658 .process_sample_event = process_sample_event, 1669 .process_sample_event = process_sample_event,
1659 .process_comm_event = event__process_comm, 1670 .process_comm_event = event__process_comm,
1660 .process_lost_event = process_lost_event, 1671 .process_lost_event = process_lost_event,
@@ -1665,14 +1676,10 @@ static int read_events(void)
1665{ 1676{
1666 int err; 1677 int err;
1667 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0); 1678 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0);
1668
1669 if (session == NULL) 1679 if (session == NULL)
1670 return -ENOMEM; 1680 return -ENOMEM;
1671 1681
1672 register_idle_thread(); 1682 err = perf_session__process_events(session, &event_ops);
1673 register_perf_file_handler(&file_handler);
1674
1675 err = perf_session__process_events(session, 0, &event__cwdlen, &event__cwd);
1676 perf_session__delete(session); 1683 perf_session__delete(session);
1677 return err; 1684 return err;
1678} 1685}
@@ -1904,7 +1911,7 @@ int cmd_sched(int argc, const char **argv, const char *prefix __used)
1904 if (!strcmp(argv[0], "trace")) 1911 if (!strcmp(argv[0], "trace"))
1905 return cmd_trace(argc, argv, prefix); 1912 return cmd_trace(argc, argv, prefix);
1906 1913
1907 symbol__init(0); 1914 symbol__init();
1908 if (!strncmp(argv[0], "rec", 3)) { 1915 if (!strncmp(argv[0], "rec", 3)) {
1909 return __cmd_record(argc, argv); 1916 return __cmd_record(argc, argv);
1910 } else if (!strncmp(argv[0], "lat", 3)) { 1917 } else if (!strncmp(argv[0], "lat", 3)) {
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index 759dd2b35fdb..a589a43112d6 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -30,15 +30,12 @@
30#include "util/parse-options.h" 30#include "util/parse-options.h"
31#include "util/parse-events.h" 31#include "util/parse-events.h"
32#include "util/event.h" 32#include "util/event.h"
33#include "util/data_map.h" 33#include "util/session.h"
34#include "util/svghelper.h" 34#include "util/svghelper.h"
35 35
36static char const *input_name = "perf.data"; 36static char const *input_name = "perf.data";
37static char const *output_name = "output.svg"; 37static char const *output_name = "output.svg";
38 38
39
40static u64 sample_type;
41
42static unsigned int numcpus; 39static unsigned int numcpus;
43static u64 min_freq; /* Lowest CPU frequency seen */ 40static u64 min_freq; /* Lowest CPU frequency seen */
44static u64 max_freq; /* Highest CPU frequency seen */ 41static u64 max_freq; /* Highest CPU frequency seen */
@@ -281,21 +278,19 @@ static int cpus_cstate_state[MAX_CPUS];
281static u64 cpus_pstate_start_times[MAX_CPUS]; 278static u64 cpus_pstate_start_times[MAX_CPUS];
282static u64 cpus_pstate_state[MAX_CPUS]; 279static u64 cpus_pstate_state[MAX_CPUS];
283 280
284static int 281static int process_comm_event(event_t *event, struct perf_session *session __used)
285process_comm_event(event_t *event)
286{ 282{
287 pid_set_comm(event->comm.pid, event->comm.comm); 283 pid_set_comm(event->comm.pid, event->comm.comm);
288 return 0; 284 return 0;
289} 285}
290static int 286
291process_fork_event(event_t *event) 287static int process_fork_event(event_t *event, struct perf_session *session __used)
292{ 288{
293 pid_fork(event->fork.pid, event->fork.ppid, event->fork.time); 289 pid_fork(event->fork.pid, event->fork.ppid, event->fork.time);
294 return 0; 290 return 0;
295} 291}
296 292
297static int 293static int process_exit_event(event_t *event, struct perf_session *session __used)
298process_exit_event(event_t *event)
299{ 294{
300 pid_exit(event->fork.pid, event->fork.time); 295 pid_exit(event->fork.pid, event->fork.time);
301 return 0; 296 return 0;
@@ -480,17 +475,16 @@ static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te)
480} 475}
481 476
482 477
483static int 478static int process_sample_event(event_t *event, struct perf_session *session)
484process_sample_event(event_t *event)
485{ 479{
486 struct sample_data data; 480 struct sample_data data;
487 struct trace_entry *te; 481 struct trace_entry *te;
488 482
489 memset(&data, 0, sizeof(data)); 483 memset(&data, 0, sizeof(data));
490 484
491 event__parse_sample(event, sample_type, &data); 485 event__parse_sample(event, session->sample_type, &data);
492 486
493 if (sample_type & PERF_SAMPLE_TIME) { 487 if (session->sample_type & PERF_SAMPLE_TIME) {
494 if (!first_time || first_time > data.time) 488 if (!first_time || first_time > data.time)
495 first_time = data.time; 489 first_time = data.time;
496 if (last_time < data.time) 490 if (last_time < data.time)
@@ -498,7 +492,7 @@ process_sample_event(event_t *event)
498 } 492 }
499 493
500 te = (void *)data.raw_data; 494 te = (void *)data.raw_data;
501 if (sample_type & PERF_SAMPLE_RAW && data.raw_size > 0) { 495 if (session->sample_type & PERF_SAMPLE_RAW && data.raw_size > 0) {
502 char *event_str; 496 char *event_str;
503 struct power_entry *pe; 497 struct power_entry *pe;
504 498
@@ -575,16 +569,16 @@ static void end_sample_processing(void)
575 } 569 }
576} 570}
577 571
578static u64 sample_time(event_t *event) 572static u64 sample_time(event_t *event, const struct perf_session *session)
579{ 573{
580 int cursor; 574 int cursor;
581 575
582 cursor = 0; 576 cursor = 0;
583 if (sample_type & PERF_SAMPLE_IP) 577 if (session->sample_type & PERF_SAMPLE_IP)
584 cursor++; 578 cursor++;
585 if (sample_type & PERF_SAMPLE_TID) 579 if (session->sample_type & PERF_SAMPLE_TID)
586 cursor++; 580 cursor++;
587 if (sample_type & PERF_SAMPLE_TIME) 581 if (session->sample_type & PERF_SAMPLE_TIME)
588 return event->sample.array[cursor]; 582 return event->sample.array[cursor];
589 return 0; 583 return 0;
590} 584}
@@ -594,8 +588,7 @@ static u64 sample_time(event_t *event)
594 * We first queue all events, sorted backwards by insertion. 588 * We first queue all events, sorted backwards by insertion.
595 * The order will get flipped later. 589 * The order will get flipped later.
596 */ 590 */
597static int 591static int queue_sample_event(event_t *event, struct perf_session *session)
598queue_sample_event(event_t *event)
599{ 592{
600 struct sample_wrapper *copy, *prev; 593 struct sample_wrapper *copy, *prev;
601 int size; 594 int size;
@@ -609,7 +602,7 @@ queue_sample_event(event_t *event)
609 memset(copy, 0, size); 602 memset(copy, 0, size);
610 603
611 copy->next = NULL; 604 copy->next = NULL;
612 copy->timestamp = sample_time(event); 605 copy->timestamp = sample_time(event, session);
613 606
614 memcpy(&copy->data, event, event->sample.header.size); 607 memcpy(&copy->data, event, event->sample.header.size);
615 608
@@ -1021,7 +1014,7 @@ static void write_svg_file(const char *filename)
1021 svg_close(); 1014 svg_close();
1022} 1015}
1023 1016
1024static void process_samples(void) 1017static void process_samples(struct perf_session *session)
1025{ 1018{
1026 struct sample_wrapper *cursor; 1019 struct sample_wrapper *cursor;
1027 event_t *event; 1020 event_t *event;
@@ -1032,15 +1025,13 @@ static void process_samples(void)
1032 while (cursor) { 1025 while (cursor) {
1033 event = (void *)&cursor->data; 1026 event = (void *)&cursor->data;
1034 cursor = cursor->next; 1027 cursor = cursor->next;
1035 process_sample_event(event); 1028 process_sample_event(event, session);
1036 } 1029 }
1037} 1030}
1038 1031
1039static int sample_type_check(u64 type) 1032static int sample_type_check(struct perf_session *session)
1040{ 1033{
1041 sample_type = type; 1034 if (!(session->sample_type & PERF_SAMPLE_RAW)) {
1042
1043 if (!(sample_type & PERF_SAMPLE_RAW)) {
1044 fprintf(stderr, "No trace samples found in the file.\n" 1035 fprintf(stderr, "No trace samples found in the file.\n"
1045 "Have you used 'perf timechart record' to record it?\n"); 1036 "Have you used 'perf timechart record' to record it?\n");
1046 return -1; 1037 return -1;
@@ -1049,7 +1040,7 @@ static int sample_type_check(u64 type)
1049 return 0; 1040 return 0;
1050} 1041}
1051 1042
1052static struct perf_file_handler file_handler = { 1043static struct perf_event_ops event_ops = {
1053 .process_comm_event = process_comm_event, 1044 .process_comm_event = process_comm_event,
1054 .process_fork_event = process_fork_event, 1045 .process_fork_event = process_fork_event,
1055 .process_exit_event = process_exit_event, 1046 .process_exit_event = process_exit_event,
@@ -1065,13 +1056,11 @@ static int __cmd_timechart(void)
1065 if (session == NULL) 1056 if (session == NULL)
1066 return -ENOMEM; 1057 return -ENOMEM;
1067 1058
1068 register_perf_file_handler(&file_handler); 1059 ret = perf_session__process_events(session, &event_ops);
1069
1070 ret = perf_session__process_events(session, 0, &event__cwdlen, &event__cwd);
1071 if (ret) 1060 if (ret)
1072 goto out_delete; 1061 goto out_delete;
1073 1062
1074 process_samples(); 1063 process_samples(session);
1075 1064
1076 end_sample_processing(); 1065 end_sample_processing();
1077 1066
@@ -1148,11 +1137,11 @@ static const struct option options[] = {
1148 1137
1149int cmd_timechart(int argc, const char **argv, const char *prefix __used) 1138int cmd_timechart(int argc, const char **argv, const char *prefix __used)
1150{ 1139{
1151 symbol__init(0);
1152
1153 argc = parse_options(argc, argv, options, timechart_usage, 1140 argc = parse_options(argc, argv, options, timechart_usage,
1154 PARSE_OPT_STOP_AT_NON_OPTION); 1141 PARSE_OPT_STOP_AT_NON_OPTION);
1155 1142
1143 symbol__init();
1144
1156 if (argc && !strncmp(argv[0], "rec", 3)) 1145 if (argc && !strncmp(argv[0], "rec", 3))
1157 return __cmd_record(argc, argv); 1146 return __cmd_record(argc, argv);
1158 else if (argc) 1147 else if (argc)
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index e0a374d0e43a..ddc584b64871 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -20,8 +20,9 @@
20 20
21#include "perf.h" 21#include "perf.h"
22 22
23#include "util/symbol.h"
24#include "util/color.h" 23#include "util/color.h"
24#include "util/session.h"
25#include "util/symbol.h"
25#include "util/thread.h" 26#include "util/thread.h"
26#include "util/util.h" 27#include "util/util.h"
27#include <linux/rbtree.h> 28#include <linux/rbtree.h>
@@ -79,7 +80,6 @@ static int dump_symtab = 0;
79static bool hide_kernel_symbols = false; 80static bool hide_kernel_symbols = false;
80static bool hide_user_symbols = false; 81static bool hide_user_symbols = false;
81static struct winsize winsize; 82static struct winsize winsize;
82struct symbol_conf symbol_conf;
83 83
84/* 84/*
85 * Source 85 * Source
@@ -926,7 +926,8 @@ static int symbol_filter(struct map *map, struct symbol *sym)
926 return 0; 926 return 0;
927} 927}
928 928
929static void event__process_sample(const event_t *self, int counter) 929static void event__process_sample(const event_t *self,
930 struct perf_session *session, int counter)
930{ 931{
931 u64 ip = self->ip.ip; 932 u64 ip = self->ip.ip;
932 struct sym_entry *syme; 933 struct sym_entry *syme;
@@ -946,8 +947,8 @@ static void event__process_sample(const event_t *self, int counter)
946 return; 947 return;
947 } 948 }
948 949
949 if (event__preprocess_sample(self, &al, symbol_filter) < 0 || 950 if (event__preprocess_sample(self, session, &al, symbol_filter) < 0 ||
950 al.sym == NULL) 951 al.sym == NULL || al.filtered)
951 return; 952 return;
952 953
953 syme = symbol__priv(al.sym); 954 syme = symbol__priv(al.sym);
@@ -965,14 +966,14 @@ static void event__process_sample(const event_t *self, int counter)
965 } 966 }
966} 967}
967 968
968static int event__process(event_t *event) 969static int event__process(event_t *event, struct perf_session *session)
969{ 970{
970 switch (event->header.type) { 971 switch (event->header.type) {
971 case PERF_RECORD_COMM: 972 case PERF_RECORD_COMM:
972 event__process_comm(event); 973 event__process_comm(event, session);
973 break; 974 break;
974 case PERF_RECORD_MMAP: 975 case PERF_RECORD_MMAP:
975 event__process_mmap(event); 976 event__process_mmap(event, session);
976 break; 977 break;
977 default: 978 default:
978 break; 979 break;
@@ -999,7 +1000,8 @@ static unsigned int mmap_read_head(struct mmap_data *md)
999 return head; 1000 return head;
1000} 1001}
1001 1002
1002static void mmap_read_counter(struct mmap_data *md) 1003static void perf_session__mmap_read_counter(struct perf_session *self,
1004 struct mmap_data *md)
1003{ 1005{
1004 unsigned int head = mmap_read_head(md); 1006 unsigned int head = mmap_read_head(md);
1005 unsigned int old = md->prev; 1007 unsigned int old = md->prev;
@@ -1052,9 +1054,9 @@ static void mmap_read_counter(struct mmap_data *md)
1052 } 1054 }
1053 1055
1054 if (event->header.type == PERF_RECORD_SAMPLE) 1056 if (event->header.type == PERF_RECORD_SAMPLE)
1055 event__process_sample(event, md->counter); 1057 event__process_sample(event, self, md->counter);
1056 else 1058 else
1057 event__process(event); 1059 event__process(event, self);
1058 old += size; 1060 old += size;
1059 } 1061 }
1060 1062
@@ -1064,13 +1066,13 @@ static void mmap_read_counter(struct mmap_data *md)
1064static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS]; 1066static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS];
1065static struct mmap_data mmap_array[MAX_NR_CPUS][MAX_COUNTERS]; 1067static struct mmap_data mmap_array[MAX_NR_CPUS][MAX_COUNTERS];
1066 1068
1067static void mmap_read(void) 1069static void perf_session__mmap_read(struct perf_session *self)
1068{ 1070{
1069 int i, counter; 1071 int i, counter;
1070 1072
1071 for (i = 0; i < nr_cpus; i++) { 1073 for (i = 0; i < nr_cpus; i++) {
1072 for (counter = 0; counter < nr_counters; counter++) 1074 for (counter = 0; counter < nr_counters; counter++)
1073 mmap_read_counter(&mmap_array[i][counter]); 1075 perf_session__mmap_read_counter(self, &mmap_array[i][counter]);
1074 } 1076 }
1075} 1077}
1076 1078
@@ -1155,11 +1157,18 @@ static int __cmd_top(void)
1155 pthread_t thread; 1157 pthread_t thread;
1156 int i, counter; 1158 int i, counter;
1157 int ret; 1159 int ret;
1160 /*
1161 * FIXME: perf_session__new should allow passing a O_MMAP, so that all this
1162 * mmap reading, etc is encapsulated in it. Use O_WRONLY for now.
1163 */
1164 struct perf_session *session = perf_session__new(NULL, O_WRONLY, false);
1165 if (session == NULL)
1166 return -ENOMEM;
1158 1167
1159 if (target_pid != -1) 1168 if (target_pid != -1)
1160 event__synthesize_thread(target_pid, event__process); 1169 event__synthesize_thread(target_pid, event__process, session);
1161 else 1170 else
1162 event__synthesize_threads(event__process); 1171 event__synthesize_threads(event__process, session);
1163 1172
1164 for (i = 0; i < nr_cpus; i++) { 1173 for (i = 0; i < nr_cpus; i++) {
1165 group_fd = -1; 1174 group_fd = -1;
@@ -1170,7 +1179,7 @@ static int __cmd_top(void)
1170 /* Wait for a minimal set of events before starting the snapshot */ 1179 /* Wait for a minimal set of events before starting the snapshot */
1171 poll(event_array, nr_poll, 100); 1180 poll(event_array, nr_poll, 100);
1172 1181
1173 mmap_read(); 1182 perf_session__mmap_read(session);
1174 1183
1175 if (pthread_create(&thread, NULL, display_thread, NULL)) { 1184 if (pthread_create(&thread, NULL, display_thread, NULL)) {
1176 printf("Could not create display thread.\n"); 1185 printf("Could not create display thread.\n");
@@ -1190,7 +1199,7 @@ static int __cmd_top(void)
1190 while (1) { 1199 while (1) {
1191 int hits = samples; 1200 int hits = samples;
1192 1201
1193 mmap_read(); 1202 perf_session__mmap_read(session);
1194 1203
1195 if (hits == samples) 1204 if (hits == samples)
1196 ret = poll(event_array, nr_poll, 100); 1205 ret = poll(event_array, nr_poll, 100);
@@ -1273,7 +1282,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1273 (nr_counters + 1) * sizeof(unsigned long)); 1282 (nr_counters + 1) * sizeof(unsigned long));
1274 if (symbol_conf.vmlinux_name == NULL) 1283 if (symbol_conf.vmlinux_name == NULL)
1275 symbol_conf.try_vmlinux_path = true; 1284 symbol_conf.try_vmlinux_path = true;
1276 if (symbol__init(&symbol_conf) < 0) 1285 if (symbol__init() < 0)
1277 return -1; 1286 return -1;
1278 1287
1279 if (delay_secs < 1) 1288 if (delay_secs < 1)
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 0756664666f1..e2285e28720f 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -12,7 +12,9 @@
12static char const *script_name; 12static char const *script_name;
13static char const *generate_script_lang; 13static char const *generate_script_lang;
14 14
15static int default_start_script(const char *script __attribute((unused))) 15static int default_start_script(const char *script __unused,
16 int argc __unused,
17 const char **argv __unused)
16{ 18{
17 return 0; 19 return 0;
18} 20}
@@ -22,7 +24,7 @@ static int default_stop_script(void)
22 return 0; 24 return 0;
23} 25}
24 26
25static int default_generate_script(const char *outfile __attribute ((unused))) 27static int default_generate_script(const char *outfile __unused)
26{ 28{
27 return 0; 29 return 0;
28} 30}
@@ -57,15 +59,11 @@ static int cleanup_scripting(void)
57#include "util/debug.h" 59#include "util/debug.h"
58 60
59#include "util/trace-event.h" 61#include "util/trace-event.h"
60#include "util/data_map.h"
61#include "util/exec_cmd.h" 62#include "util/exec_cmd.h"
62 63
63static char const *input_name = "perf.data"; 64static char const *input_name = "perf.data";
64 65
65static struct perf_session *session; 66static int process_sample_event(event_t *event, struct perf_session *session)
66static u64 sample_type;
67
68static int process_sample_event(event_t *event)
69{ 67{
70 struct sample_data data; 68 struct sample_data data;
71 struct thread *thread; 69 struct thread *thread;
@@ -75,7 +73,7 @@ static int process_sample_event(event_t *event)
75 data.cpu = -1; 73 data.cpu = -1;
76 data.period = 1; 74 data.period = 1;
77 75
78 event__parse_sample(event, sample_type, &data); 76 event__parse_sample(event, session->sample_type, &data);
79 77
80 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", 78 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n",
81 event->header.misc, 79 event->header.misc,
@@ -83,14 +81,14 @@ static int process_sample_event(event_t *event)
83 (void *)(long)data.ip, 81 (void *)(long)data.ip,
84 (long long)data.period); 82 (long long)data.period);
85 83
86 thread = threads__findnew(event->ip.pid); 84 thread = perf_session__findnew(session, event->ip.pid);
87 if (thread == NULL) { 85 if (thread == NULL) {
88 pr_debug("problem processing %d event, skipping it.\n", 86 pr_debug("problem processing %d event, skipping it.\n",
89 event->header.type); 87 event->header.type);
90 return -1; 88 return -1;
91 } 89 }
92 90
93 if (sample_type & PERF_SAMPLE_RAW) { 91 if (session->sample_type & PERF_SAMPLE_RAW) {
94 /* 92 /*
95 * FIXME: better resolve from pid from the struct trace_entry 93 * FIXME: better resolve from pid from the struct trace_entry
96 * field, although it should be the same than this perf 94 * field, although it should be the same than this perf
@@ -100,16 +98,14 @@ static int process_sample_event(event_t *event)
100 data.raw_size, 98 data.raw_size,
101 data.time, thread->comm); 99 data.time, thread->comm);
102 } 100 }
103 event__stats.total += data.period;
104 101
102 session->events_stats.total += data.period;
105 return 0; 103 return 0;
106} 104}
107 105
108static int sample_type_check(u64 type) 106static int sample_type_check(struct perf_session *session)
109{ 107{
110 sample_type = type; 108 if (!(session->sample_type & PERF_SAMPLE_RAW)) {
111
112 if (!(sample_type & PERF_SAMPLE_RAW)) {
113 fprintf(stderr, 109 fprintf(stderr,
114 "No trace sample to read. Did you call perf record " 110 "No trace sample to read. Did you call perf record "
115 "without -R?"); 111 "without -R?");
@@ -119,26 +115,15 @@ static int sample_type_check(u64 type)
119 return 0; 115 return 0;
120} 116}
121 117
122static struct perf_file_handler file_handler = { 118static struct perf_event_ops event_ops = {
123 .process_sample_event = process_sample_event, 119 .process_sample_event = process_sample_event,
124 .process_comm_event = event__process_comm, 120 .process_comm_event = event__process_comm,
125 .sample_type_check = sample_type_check, 121 .sample_type_check = sample_type_check,
126}; 122};
127 123
128static int __cmd_trace(void) 124static int __cmd_trace(struct perf_session *session)
129{ 125{
130 int err; 126 return perf_session__process_events(session, &event_ops);
131
132 session = perf_session__new(input_name, O_RDONLY, 0);
133 if (session == NULL)
134 return -ENOMEM;
135
136 register_idle_thread();
137 register_perf_file_handler(&file_handler);
138
139 err = perf_session__process_events(session, 0, &event__cwdlen, &event__cwd);
140 perf_session__delete(session);
141 return err;
142} 127}
143 128
144struct script_spec { 129struct script_spec {
@@ -289,6 +274,244 @@ static int parse_scriptname(const struct option *opt __used,
289 return 0; 274 return 0;
290} 275}
291 276
277#define for_each_lang(scripts_dir, lang_dirent, lang_next) \
278 while (!readdir_r(scripts_dir, &lang_dirent, &lang_next) && \
279 lang_next) \
280 if (lang_dirent.d_type == DT_DIR && \
281 (strcmp(lang_dirent.d_name, ".")) && \
282 (strcmp(lang_dirent.d_name, "..")))
283
284#define for_each_script(lang_dir, script_dirent, script_next) \
285 while (!readdir_r(lang_dir, &script_dirent, &script_next) && \
286 script_next) \
287 if (script_dirent.d_type != DT_DIR)
288
289
290#define RECORD_SUFFIX "-record"
291#define REPORT_SUFFIX "-report"
292
293struct script_desc {
294 struct list_head node;
295 char *name;
296 char *half_liner;
297 char *args;
298};
299
300LIST_HEAD(script_descs);
301
302static struct script_desc *script_desc__new(const char *name)
303{
304 struct script_desc *s = zalloc(sizeof(*s));
305
306 if (s != NULL)
307 s->name = strdup(name);
308
309 return s;
310}
311
312static void script_desc__delete(struct script_desc *s)
313{
314 free(s->name);
315 free(s);
316}
317
318static void script_desc__add(struct script_desc *s)
319{
320 list_add_tail(&s->node, &script_descs);
321}
322
323static struct script_desc *script_desc__find(const char *name)
324{
325 struct script_desc *s;
326
327 list_for_each_entry(s, &script_descs, node)
328 if (strcasecmp(s->name, name) == 0)
329 return s;
330 return NULL;
331}
332
333static struct script_desc *script_desc__findnew(const char *name)
334{
335 struct script_desc *s = script_desc__find(name);
336
337 if (s)
338 return s;
339
340 s = script_desc__new(name);
341 if (!s)
342 goto out_delete_desc;
343
344 script_desc__add(s);
345
346 return s;
347
348out_delete_desc:
349 script_desc__delete(s);
350
351 return NULL;
352}
353
354static char *ends_with(char *str, const char *suffix)
355{
356 size_t suffix_len = strlen(suffix);
357 char *p = str;
358
359 if (strlen(str) > suffix_len) {
360 p = str + strlen(str) - suffix_len;
361 if (!strncmp(p, suffix, suffix_len))
362 return p;
363 }
364
365 return NULL;
366}
367
368static char *ltrim(char *str)
369{
370 int len = strlen(str);
371
372 while (len && isspace(*str)) {
373 len--;
374 str++;
375 }
376
377 return str;
378}
379
380static int read_script_info(struct script_desc *desc, const char *filename)
381{
382 char line[BUFSIZ], *p;
383 FILE *fp;
384
385 fp = fopen(filename, "r");
386 if (!fp)
387 return -1;
388
389 while (fgets(line, sizeof(line), fp)) {
390 p = ltrim(line);
391 if (strlen(p) == 0)
392 continue;
393 if (*p != '#')
394 continue;
395 p++;
396 if (strlen(p) && *p == '!')
397 continue;
398
399 p = ltrim(p);
400 if (strlen(p) && p[strlen(p) - 1] == '\n')
401 p[strlen(p) - 1] = '\0';
402
403 if (!strncmp(p, "description:", strlen("description:"))) {
404 p += strlen("description:");
405 desc->half_liner = strdup(ltrim(p));
406 continue;
407 }
408
409 if (!strncmp(p, "args:", strlen("args:"))) {
410 p += strlen("args:");
411 desc->args = strdup(ltrim(p));
412 continue;
413 }
414 }
415
416 fclose(fp);
417
418 return 0;
419}
420
421static int list_available_scripts(const struct option *opt __used,
422 const char *s __used, int unset __used)
423{
424 struct dirent *script_next, *lang_next, script_dirent, lang_dirent;
425 char scripts_path[MAXPATHLEN];
426 DIR *scripts_dir, *lang_dir;
427 char script_path[MAXPATHLEN];
428 char lang_path[MAXPATHLEN];
429 struct script_desc *desc;
430 char first_half[BUFSIZ];
431 char *script_root;
432 char *str;
433
434 snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path());
435
436 scripts_dir = opendir(scripts_path);
437 if (!scripts_dir)
438 return -1;
439
440 for_each_lang(scripts_dir, lang_dirent, lang_next) {
441 snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path,
442 lang_dirent.d_name);
443 lang_dir = opendir(lang_path);
444 if (!lang_dir)
445 continue;
446
447 for_each_script(lang_dir, script_dirent, script_next) {
448 script_root = strdup(script_dirent.d_name);
449 str = ends_with(script_root, REPORT_SUFFIX);
450 if (str) {
451 *str = '\0';
452 desc = script_desc__findnew(script_root);
453 snprintf(script_path, MAXPATHLEN, "%s/%s",
454 lang_path, script_dirent.d_name);
455 read_script_info(desc, script_path);
456 }
457 free(script_root);
458 }
459 }
460
461 fprintf(stdout, "List of available trace scripts:\n");
462 list_for_each_entry(desc, &script_descs, node) {
463 sprintf(first_half, "%s %s", desc->name,
464 desc->args ? desc->args : "");
465 fprintf(stdout, " %-36s %s\n", first_half,
466 desc->half_liner ? desc->half_liner : "");
467 }
468
469 exit(0);
470}
471
472static char *get_script_path(const char *script_root, const char *suffix)
473{
474 struct dirent *script_next, *lang_next, script_dirent, lang_dirent;
475 char scripts_path[MAXPATHLEN];
476 char script_path[MAXPATHLEN];
477 DIR *scripts_dir, *lang_dir;
478 char lang_path[MAXPATHLEN];
479 char *str, *__script_root;
480 char *path = NULL;
481
482 snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path());
483
484 scripts_dir = opendir(scripts_path);
485 if (!scripts_dir)
486 return NULL;
487
488 for_each_lang(scripts_dir, lang_dirent, lang_next) {
489 snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path,
490 lang_dirent.d_name);
491 lang_dir = opendir(lang_path);
492 if (!lang_dir)
493 continue;
494
495 for_each_script(lang_dir, script_dirent, script_next) {
496 __script_root = strdup(script_dirent.d_name);
497 str = ends_with(__script_root, suffix);
498 if (str) {
499 *str = '\0';
500 if (strcmp(__script_root, script_root))
501 continue;
502 snprintf(script_path, MAXPATHLEN, "%s/%s",
503 lang_path, script_dirent.d_name);
504 path = strdup(script_path);
505 free(__script_root);
506 break;
507 }
508 free(__script_root);
509 }
510 }
511
512 return path;
513}
514
292static const char * const annotate_usage[] = { 515static const char * const annotate_usage[] = {
293 "perf trace [<options>] <command>", 516 "perf trace [<options>] <command>",
294 NULL 517 NULL
@@ -299,8 +522,10 @@ static const struct option options[] = {
299 "dump raw trace in ASCII"), 522 "dump raw trace in ASCII"),
300 OPT_BOOLEAN('v', "verbose", &verbose, 523 OPT_BOOLEAN('v', "verbose", &verbose,
301 "be more verbose (show symbol address, etc)"), 524 "be more verbose (show symbol address, etc)"),
302 OPT_BOOLEAN('l', "latency", &latency_format, 525 OPT_BOOLEAN('L', "Latency", &latency_format,
303 "show latency attributes (irqs/preemption disabled, etc)"), 526 "show latency attributes (irqs/preemption disabled, etc)"),
527 OPT_CALLBACK_NOOPT('l', "list", NULL, NULL, "list available scripts",
528 list_available_scripts),
304 OPT_CALLBACK('s', "script", NULL, "name", 529 OPT_CALLBACK('s', "script", NULL, "name",
305 "script file name (lang:script name, script name, or *)", 530 "script file name (lang:script name, script name, or *)",
306 parse_scriptname), 531 parse_scriptname),
@@ -312,24 +537,61 @@ static const struct option options[] = {
312 537
313int cmd_trace(int argc, const char **argv, const char *prefix __used) 538int cmd_trace(int argc, const char **argv, const char *prefix __used)
314{ 539{
315 int err; 540 struct perf_session *session;
541 const char *suffix = NULL;
542 const char **__argv;
543 char *script_path;
544 int i, err;
545
546 if (argc >= 2 && strncmp(argv[1], "rec", strlen("rec")) == 0) {
547 if (argc < 3) {
548 fprintf(stderr,
549 "Please specify a record script\n");
550 return -1;
551 }
552 suffix = RECORD_SUFFIX;
553 }
316 554
317 symbol__init(0); 555 if (argc >= 2 && strncmp(argv[1], "rep", strlen("rep")) == 0) {
556 if (argc < 3) {
557 fprintf(stderr,
558 "Please specify a report script\n");
559 return -1;
560 }
561 suffix = REPORT_SUFFIX;
562 }
318 563
319 setup_scripting(); 564 if (suffix) {
565 script_path = get_script_path(argv[2], suffix);
566 if (!script_path) {
567 fprintf(stderr, "script not found\n");
568 return -1;
569 }
320 570
321 argc = parse_options(argc, argv, options, annotate_usage, 0); 571 __argv = malloc((argc + 1) * sizeof(const char *));
322 if (argc) { 572 __argv[0] = "/bin/sh";
323 /* 573 __argv[1] = script_path;
324 * Special case: if there's an argument left then assume tha 574 for (i = 3; i < argc; i++)
325 * it's a symbol filter: 575 __argv[i - 1] = argv[i];
326 */ 576 __argv[argc - 1] = NULL;
327 if (argc > 1) 577
328 usage_with_options(annotate_usage, options); 578 execvp("/bin/sh", (char **)__argv);
579 exit(-1);
329 } 580 }
330 581
582 setup_scripting();
583
584 argc = parse_options(argc, argv, options, annotate_usage,
585 PARSE_OPT_STOP_AT_NON_OPTION);
586
587 if (symbol__init() < 0)
588 return -1;
331 setup_pager(); 589 setup_pager();
332 590
591 session = perf_session__new(input_name, O_RDONLY, 0);
592 if (session == NULL)
593 return -ENOMEM;
594
333 if (generate_script_lang) { 595 if (generate_script_lang) {
334 struct stat perf_stat; 596 struct stat perf_stat;
335 597
@@ -362,13 +624,14 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used)
362 } 624 }
363 625
364 if (script_name) { 626 if (script_name) {
365 err = scripting_ops->start_script(script_name); 627 err = scripting_ops->start_script(script_name, argc, argv);
366 if (err) 628 if (err)
367 goto out; 629 goto out;
368 } 630 }
369 631
370 err = __cmd_trace(); 632 err = __cmd_trace(session);
371 633
634 perf_session__delete(session);
372 cleanup_scripting(); 635 cleanup_scripting();
373out: 636out:
374 return err; 637 return err;
diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h
index a3d8bf65f26c..18035b1f16c7 100644
--- a/tools/perf/builtin.h
+++ b/tools/perf/builtin.h
@@ -17,6 +17,7 @@ extern int check_pager_config(const char *cmd);
17extern int cmd_annotate(int argc, const char **argv, const char *prefix); 17extern int cmd_annotate(int argc, const char **argv, const char *prefix);
18extern int cmd_bench(int argc, const char **argv, const char *prefix); 18extern int cmd_bench(int argc, const char **argv, const char *prefix);
19extern int cmd_buildid_list(int argc, const char **argv, const char *prefix); 19extern int cmd_buildid_list(int argc, const char **argv, const char *prefix);
20extern int cmd_diff(int argc, const char **argv, const char *prefix);
20extern int cmd_help(int argc, const char **argv, const char *prefix); 21extern int cmd_help(int argc, const char **argv, const char *prefix);
21extern int cmd_sched(int argc, const char **argv, const char *prefix); 22extern int cmd_sched(int argc, const char **argv, const char *prefix);
22extern int cmd_list(int argc, const char **argv, const char *prefix); 23extern int cmd_list(int argc, const char **argv, const char *prefix);
diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt
index 02b09ea17a3e..71dc7c3fe7b2 100644
--- a/tools/perf/command-list.txt
+++ b/tools/perf/command-list.txt
@@ -5,6 +5,7 @@
5perf-annotate mainporcelain common 5perf-annotate mainporcelain common
6perf-bench mainporcelain common 6perf-bench mainporcelain common
7perf-buildid-list mainporcelain common 7perf-buildid-list mainporcelain common
8perf-diff mainporcelain common
8perf-list mainporcelain common 9perf-list mainporcelain common
9perf-sched mainporcelain common 10perf-sched mainporcelain common
10perf-record mainporcelain common 11perf-record mainporcelain common
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index cf64049bc9bd..873e55fab375 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -286,6 +286,7 @@ static void handle_internal_command(int argc, const char **argv)
286 const char *cmd = argv[0]; 286 const char *cmd = argv[0];
287 static struct cmd_struct commands[] = { 287 static struct cmd_struct commands[] = {
288 { "buildid-list", cmd_buildid_list, 0 }, 288 { "buildid-list", cmd_buildid_list, 0 },
289 { "diff", cmd_diff, 0 },
289 { "help", cmd_help, 0 }, 290 { "help", cmd_help, 0 },
290 { "list", cmd_list, 0 }, 291 { "list", cmd_list, 0 },
291 { "record", cmd_record, 0 }, 292 { "record", cmd_record, 0 },
diff --git a/tools/perf/scripts/perl/bin/check-perf-trace-report b/tools/perf/scripts/perl/bin/check-perf-trace-report
index 89948b015020..7fc4a033dd49 100644
--- a/tools/perf/scripts/perl/bin/check-perf-trace-report
+++ b/tools/perf/scripts/perl/bin/check-perf-trace-report
@@ -1,4 +1,5 @@
1#!/bin/bash 1#!/bin/bash
2# description: useless but exhaustive test script
2perf trace -s ~/libexec/perf-core/scripts/perl/check-perf-trace.pl 3perf trace -s ~/libexec/perf-core/scripts/perl/check-perf-trace.pl
3 4
4 5
diff --git a/tools/perf/scripts/perl/bin/rw-by-file-report b/tools/perf/scripts/perl/bin/rw-by-file-report
index f5dcf9cb5bd2..eddb9ccce6a5 100644
--- a/tools/perf/scripts/perl/bin/rw-by-file-report
+++ b/tools/perf/scripts/perl/bin/rw-by-file-report
@@ -1,5 +1,7 @@
1#!/bin/bash 1#!/bin/bash
2perf trace -s ~/libexec/perf-core/scripts/perl/rw-by-file.pl 2# description: r/w activity for a program, by file
3# args: <comm>
4perf trace -s ~/libexec/perf-core/scripts/perl/rw-by-file.pl $1
3 5
4 6
5 7
diff --git a/tools/perf/scripts/perl/bin/rw-by-pid-report b/tools/perf/scripts/perl/bin/rw-by-pid-report
index cea16f78a3a2..7f44c25cc857 100644
--- a/tools/perf/scripts/perl/bin/rw-by-pid-report
+++ b/tools/perf/scripts/perl/bin/rw-by-pid-report
@@ -1,4 +1,5 @@
1#!/bin/bash 1#!/bin/bash
2# description: system-wide r/w activity
2perf trace -s ~/libexec/perf-core/scripts/perl/rw-by-pid.pl 3perf trace -s ~/libexec/perf-core/scripts/perl/rw-by-pid.pl
3 4
4 5
diff --git a/tools/perf/scripts/perl/bin/wakeup-latency-report b/tools/perf/scripts/perl/bin/wakeup-latency-report
index 85769dc456eb..fce3adcb3249 100644
--- a/tools/perf/scripts/perl/bin/wakeup-latency-report
+++ b/tools/perf/scripts/perl/bin/wakeup-latency-report
@@ -1,4 +1,5 @@
1#!/bin/bash 1#!/bin/bash
2# description: system-wide min/max/avg wakeup latency
2perf trace -s ~/libexec/perf-core/scripts/perl/wakeup-latency.pl 3perf trace -s ~/libexec/perf-core/scripts/perl/wakeup-latency.pl
3 4
4 5
diff --git a/tools/perf/scripts/perl/bin/workqueue-stats-report b/tools/perf/scripts/perl/bin/workqueue-stats-report
index aa68435be926..71cfbd182fb9 100644
--- a/tools/perf/scripts/perl/bin/workqueue-stats-report
+++ b/tools/perf/scripts/perl/bin/workqueue-stats-report
@@ -1,4 +1,5 @@
1#!/bin/bash 1#!/bin/bash
2# description: workqueue stats (ins/exe/create/destroy)
2perf trace -s ~/libexec/perf-core/scripts/perl/workqueue-stats.pl 3perf trace -s ~/libexec/perf-core/scripts/perl/workqueue-stats.pl
3 4
4 5
diff --git a/tools/perf/scripts/perl/rw-by-file.pl b/tools/perf/scripts/perl/rw-by-file.pl
index 61f91561d848..2a39097687b9 100644
--- a/tools/perf/scripts/perl/rw-by-file.pl
+++ b/tools/perf/scripts/perl/rw-by-file.pl
@@ -18,8 +18,9 @@ use lib "./Perf-Trace-Util/lib";
18use Perf::Trace::Core; 18use Perf::Trace::Core;
19use Perf::Trace::Util; 19use Perf::Trace::Util;
20 20
21# change this to the comm of the program you're interested in 21my $usage = "perf trace -s rw-by-file.pl <comm>\n";
22my $for_comm = "perf"; 22
23my $for_comm = shift or die $usage;
23 24
24my %reads; 25my %reads;
25my %writes; 26my %writes;
diff --git a/tools/perf/util/data_map.c b/tools/perf/util/data_map.c
index 6d46dda53a29..b557b836de3d 100644
--- a/tools/perf/util/data_map.c
+++ b/tools/perf/util/data_map.c
@@ -1,20 +1,17 @@
1#include "data_map.h"
2#include "symbol.h" 1#include "symbol.h"
3#include "util.h" 2#include "util.h"
4#include "debug.h" 3#include "debug.h"
4#include "thread.h"
5#include "session.h"
5 6
6 7static int process_event_stub(event_t *event __used,
7static struct perf_file_handler *curr_handler; 8 struct perf_session *session __used)
8static unsigned long mmap_window = 32;
9static char __cwd[PATH_MAX];
10
11static int process_event_stub(event_t *event __used)
12{ 9{
13 dump_printf(": unhandled!\n"); 10 dump_printf(": unhandled!\n");
14 return 0; 11 return 0;
15} 12}
16 13
17void register_perf_file_handler(struct perf_file_handler *handler) 14static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
18{ 15{
19 if (!handler->process_sample_event) 16 if (!handler->process_sample_event)
20 handler->process_sample_event = process_event_stub; 17 handler->process_sample_event = process_event_stub;
@@ -34,8 +31,6 @@ void register_perf_file_handler(struct perf_file_handler *handler)
34 handler->process_throttle_event = process_event_stub; 31 handler->process_throttle_event = process_event_stub;
35 if (!handler->process_unthrottle_event) 32 if (!handler->process_unthrottle_event)
36 handler->process_unthrottle_event = process_event_stub; 33 handler->process_unthrottle_event = process_event_stub;
37
38 curr_handler = handler;
39} 34}
40 35
41static const char *event__name[] = { 36static const char *event__name[] = {
@@ -61,8 +56,9 @@ void event__print_totals(void)
61 event__name[i], event__total[i]); 56 event__name[i], event__total[i]);
62} 57}
63 58
64static int 59static int process_event(event_t *event, struct perf_session *session,
65process_event(event_t *event, unsigned long offset, unsigned long head) 60 struct perf_event_ops *ops,
61 unsigned long offset, unsigned long head)
66{ 62{
67 trace_event(event); 63 trace_event(event);
68 64
@@ -77,25 +73,25 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
77 73
78 switch (event->header.type) { 74 switch (event->header.type) {
79 case PERF_RECORD_SAMPLE: 75 case PERF_RECORD_SAMPLE:
80 return curr_handler->process_sample_event(event); 76 return ops->process_sample_event(event, session);
81 case PERF_RECORD_MMAP: 77 case PERF_RECORD_MMAP:
82 return curr_handler->process_mmap_event(event); 78 return ops->process_mmap_event(event, session);
83 case PERF_RECORD_COMM: 79 case PERF_RECORD_COMM:
84 return curr_handler->process_comm_event(event); 80 return ops->process_comm_event(event, session);
85 case PERF_RECORD_FORK: 81 case PERF_RECORD_FORK:
86 return curr_handler->process_fork_event(event); 82 return ops->process_fork_event(event, session);
87 case PERF_RECORD_EXIT: 83 case PERF_RECORD_EXIT:
88 return curr_handler->process_exit_event(event); 84 return ops->process_exit_event(event, session);
89 case PERF_RECORD_LOST: 85 case PERF_RECORD_LOST:
90 return curr_handler->process_lost_event(event); 86 return ops->process_lost_event(event, session);
91 case PERF_RECORD_READ: 87 case PERF_RECORD_READ:
92 return curr_handler->process_read_event(event); 88 return ops->process_read_event(event, session);
93 case PERF_RECORD_THROTTLE: 89 case PERF_RECORD_THROTTLE:
94 return curr_handler->process_throttle_event(event); 90 return ops->process_throttle_event(event, session);
95 case PERF_RECORD_UNTHROTTLE: 91 case PERF_RECORD_UNTHROTTLE:
96 return curr_handler->process_unthrottle_event(event); 92 return ops->process_unthrottle_event(event, session);
97 default: 93 default:
98 curr_handler->total_unknown++; 94 ops->total_unknown++;
99 return -1; 95 return -1;
100 } 96 }
101} 97}
@@ -129,44 +125,58 @@ out:
129 return err; 125 return err;
130} 126}
131 127
128static struct thread *perf_session__register_idle_thread(struct perf_session *self)
129{
130 struct thread *thread = perf_session__findnew(self, 0);
131
132 if (!thread || thread__set_comm(thread, "swapper")) {
133 pr_err("problem inserting idle task.\n");
134 thread = NULL;
135 }
136
137 return thread;
138}
139
132int perf_session__process_events(struct perf_session *self, 140int perf_session__process_events(struct perf_session *self,
133 int full_paths, int *cwdlen, char **cwd) 141 struct perf_event_ops *ops)
134{ 142{
135 int err; 143 int err;
136 unsigned long head, shift; 144 unsigned long head, shift;
137 unsigned long offset = 0; 145 unsigned long offset = 0;
138 size_t page_size; 146 size_t page_size;
139 u64 sample_type;
140 event_t *event; 147 event_t *event;
141 uint32_t size; 148 uint32_t size;
142 char *buf; 149 char *buf;
143 150
144 if (curr_handler == NULL) { 151 if (perf_session__register_idle_thread(self) == NULL)
145 pr_debug("Forgot to register perf file handler\n"); 152 return -ENOMEM;
146 return -EINVAL; 153
147 } 154 perf_event_ops__fill_defaults(ops);
148 155
149 page_size = getpagesize(); 156 page_size = getpagesize();
150 157
151 head = self->header.data_offset; 158 head = self->header.data_offset;
152 sample_type = perf_header__sample_type(&self->header); 159 self->sample_type = perf_header__sample_type(&self->header);
153 160
154 err = -EINVAL; 161 err = -EINVAL;
155 if (curr_handler->sample_type_check && 162 if (ops->sample_type_check && ops->sample_type_check(self) < 0)
156 curr_handler->sample_type_check(sample_type) < 0)
157 goto out_err; 163 goto out_err;
158 164
159 if (!full_paths) { 165 if (!ops->full_paths) {
160 if (getcwd(__cwd, sizeof(__cwd)) == NULL) { 166 char bf[PATH_MAX];
161 pr_err("failed to get the current directory\n"); 167
168 if (getcwd(bf, sizeof(bf)) == NULL) {
162 err = -errno; 169 err = -errno;
170out_getcwd_err:
171 pr_err("failed to get the current directory\n");
163 goto out_err; 172 goto out_err;
164 } 173 }
165 *cwd = __cwd; 174 self->cwd = strdup(bf);
166 *cwdlen = strlen(*cwd); 175 if (self->cwd == NULL) {
167 } else { 176 err = -ENOMEM;
168 *cwd = NULL; 177 goto out_getcwd_err;
169 *cwdlen = 0; 178 }
179 self->cwdlen = strlen(self->cwd);
170 } 180 }
171 181
172 shift = page_size * (head / page_size); 182 shift = page_size * (head / page_size);
@@ -174,7 +184,7 @@ int perf_session__process_events(struct perf_session *self,
174 head -= shift; 184 head -= shift;
175 185
176remap: 186remap:
177 buf = mmap(NULL, page_size * mmap_window, PROT_READ, 187 buf = mmap(NULL, page_size * self->mmap_window, PROT_READ,
178 MAP_SHARED, self->fd, offset); 188 MAP_SHARED, self->fd, offset);
179 if (buf == MAP_FAILED) { 189 if (buf == MAP_FAILED) {
180 pr_err("failed to mmap file\n"); 190 pr_err("failed to mmap file\n");
@@ -189,12 +199,12 @@ more:
189 if (!size) 199 if (!size)
190 size = 8; 200 size = 8;
191 201
192 if (head + event->header.size >= page_size * mmap_window) { 202 if (head + event->header.size >= page_size * self->mmap_window) {
193 int munmap_ret; 203 int munmap_ret;
194 204
195 shift = page_size * (head / page_size); 205 shift = page_size * (head / page_size);
196 206
197 munmap_ret = munmap(buf, page_size * mmap_window); 207 munmap_ret = munmap(buf, page_size * self->mmap_window);
198 assert(munmap_ret == 0); 208 assert(munmap_ret == 0);
199 209
200 offset += shift; 210 offset += shift;
@@ -209,7 +219,7 @@ more:
209 (void *)(long)event->header.size, 219 (void *)(long)event->header.size,
210 event->header.type); 220 event->header.type);
211 221
212 if (!size || process_event(event, offset, head) < 0) { 222 if (!size || process_event(event, self, ops, offset, head) < 0) {
213 223
214 dump_printf("%p [%p]: skipping unknown header type: %d\n", 224 dump_printf("%p [%p]: skipping unknown header type: %d\n",
215 (void *)(offset + head), 225 (void *)(offset + head),
diff --git a/tools/perf/util/data_map.h b/tools/perf/util/data_map.h
deleted file mode 100644
index 98c5b823388c..000000000000
--- a/tools/perf/util/data_map.h
+++ /dev/null
@@ -1,29 +0,0 @@
1#ifndef __PERF_DATAMAP_H
2#define __PERF_DATAMAP_H
3
4#include "event.h"
5#include "header.h"
6#include "session.h"
7
8typedef int (*event_type_handler_t)(event_t *);
9
10struct perf_file_handler {
11 event_type_handler_t process_sample_event;
12 event_type_handler_t process_mmap_event;
13 event_type_handler_t process_comm_event;
14 event_type_handler_t process_fork_event;
15 event_type_handler_t process_exit_event;
16 event_type_handler_t process_lost_event;
17 event_type_handler_t process_read_event;
18 event_type_handler_t process_throttle_event;
19 event_type_handler_t process_unthrottle_event;
20 int (*sample_type_check)(u64 sample_type);
21 unsigned long total_unknown;
22};
23
24void register_perf_file_handler(struct perf_file_handler *handler);
25int perf_session__process_events(struct perf_session *self,
26 int full_paths, int *cwdlen, char **cwd);
27int perf_header__read_build_ids(int input, u64 offset, u64 file_size);
28
29#endif
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index ba0de90cd3d4..bb0fd6da2d56 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -1,11 +1,16 @@
1#include <linux/types.h> 1#include <linux/types.h>
2#include "event.h" 2#include "event.h"
3#include "debug.h" 3#include "debug.h"
4#include "session.h"
5#include "sort.h"
4#include "string.h" 6#include "string.h"
7#include "strlist.h"
5#include "thread.h" 8#include "thread.h"
6 9
7static pid_t event__synthesize_comm(pid_t pid, int full, 10static pid_t event__synthesize_comm(pid_t pid, int full,
8 int (*process)(event_t *event)) 11 int (*process)(event_t *event,
12 struct perf_session *session),
13 struct perf_session *session)
9{ 14{
10 event_t ev; 15 event_t ev;
11 char filename[PATH_MAX]; 16 char filename[PATH_MAX];
@@ -54,7 +59,7 @@ out_race:
54 if (!full) { 59 if (!full) {
55 ev.comm.tid = pid; 60 ev.comm.tid = pid;
56 61
57 process(&ev); 62 process(&ev, session);
58 goto out_fclose; 63 goto out_fclose;
59 } 64 }
60 65
@@ -72,7 +77,7 @@ out_race:
72 77
73 ev.comm.tid = pid; 78 ev.comm.tid = pid;
74 79
75 process(&ev); 80 process(&ev, session);
76 } 81 }
77 closedir(tasks); 82 closedir(tasks);
78 83
@@ -86,7 +91,9 @@ out_failure:
86} 91}
87 92
88static int event__synthesize_mmap_events(pid_t pid, pid_t tgid, 93static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
89 int (*process)(event_t *event)) 94 int (*process)(event_t *event,
95 struct perf_session *session),
96 struct perf_session *session)
90{ 97{
91 char filename[PATH_MAX]; 98 char filename[PATH_MAX];
92 FILE *fp; 99 FILE *fp;
@@ -141,7 +148,7 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
141 ev.mmap.pid = tgid; 148 ev.mmap.pid = tgid;
142 ev.mmap.tid = pid; 149 ev.mmap.tid = pid;
143 150
144 process(&ev); 151 process(&ev, session);
145 } 152 }
146 } 153 }
147 154
@@ -149,15 +156,20 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
149 return 0; 156 return 0;
150} 157}
151 158
152int event__synthesize_thread(pid_t pid, int (*process)(event_t *event)) 159int event__synthesize_thread(pid_t pid,
160 int (*process)(event_t *event,
161 struct perf_session *session),
162 struct perf_session *session)
153{ 163{
154 pid_t tgid = event__synthesize_comm(pid, 1, process); 164 pid_t tgid = event__synthesize_comm(pid, 1, process, session);
155 if (tgid == -1) 165 if (tgid == -1)
156 return -1; 166 return -1;
157 return event__synthesize_mmap_events(pid, tgid, process); 167 return event__synthesize_mmap_events(pid, tgid, process, session);
158} 168}
159 169
160void event__synthesize_threads(int (*process)(event_t *event)) 170void event__synthesize_threads(int (*process)(event_t *event,
171 struct perf_session *session),
172 struct perf_session *session)
161{ 173{
162 DIR *proc; 174 DIR *proc;
163 struct dirent dirent, *next; 175 struct dirent dirent, *next;
@@ -171,24 +183,47 @@ void event__synthesize_threads(int (*process)(event_t *event))
171 if (*end) /* only interested in proper numerical dirents */ 183 if (*end) /* only interested in proper numerical dirents */
172 continue; 184 continue;
173 185
174 event__synthesize_thread(pid, process); 186 event__synthesize_thread(pid, process, session);
175 } 187 }
176 188
177 closedir(proc); 189 closedir(proc);
178} 190}
179 191
180char *event__cwd; 192static void thread__comm_adjust(struct thread *self)
181int event__cwdlen; 193{
194 char *comm = self->comm;
182 195
183struct events_stats event__stats; 196 if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
197 (!symbol_conf.comm_list ||
198 strlist__has_entry(symbol_conf.comm_list, comm))) {
199 unsigned int slen = strlen(comm);
184 200
185int event__process_comm(event_t *self) 201 if (slen > comms__col_width) {
202 comms__col_width = slen;
203 threads__col_width = slen + 6;
204 }
205 }
206}
207
208static int thread__set_comm_adjust(struct thread *self, const char *comm)
186{ 209{
187 struct thread *thread = threads__findnew(self->comm.pid); 210 int ret = thread__set_comm(self, comm);
211
212 if (ret)
213 return ret;
214
215 thread__comm_adjust(self);
216
217 return 0;
218}
219
220int event__process_comm(event_t *self, struct perf_session *session)
221{
222 struct thread *thread = perf_session__findnew(session, self->comm.pid);
188 223
189 dump_printf(": %s:%d\n", self->comm.comm, self->comm.pid); 224 dump_printf(": %s:%d\n", self->comm.comm, self->comm.pid);
190 225
191 if (thread == NULL || thread__set_comm(thread, self->comm.comm)) { 226 if (thread == NULL || thread__set_comm_adjust(thread, self->comm.comm)) {
192 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); 227 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
193 return -1; 228 return -1;
194 } 229 }
@@ -196,18 +231,18 @@ int event__process_comm(event_t *self)
196 return 0; 231 return 0;
197} 232}
198 233
199int event__process_lost(event_t *self) 234int event__process_lost(event_t *self, struct perf_session *session)
200{ 235{
201 dump_printf(": id:%Ld: lost:%Ld\n", self->lost.id, self->lost.lost); 236 dump_printf(": id:%Ld: lost:%Ld\n", self->lost.id, self->lost.lost);
202 event__stats.lost += self->lost.lost; 237 session->events_stats.lost += self->lost.lost;
203 return 0; 238 return 0;
204} 239}
205 240
206int event__process_mmap(event_t *self) 241int event__process_mmap(event_t *self, struct perf_session *session)
207{ 242{
208 struct thread *thread = threads__findnew(self->mmap.pid); 243 struct thread *thread = perf_session__findnew(session, self->mmap.pid);
209 struct map *map = map__new(&self->mmap, MAP__FUNCTION, 244 struct map *map = map__new(&self->mmap, MAP__FUNCTION,
210 event__cwd, event__cwdlen); 245 session->cwd, session->cwdlen);
211 246
212 dump_printf(" %d/%d: [%p(%p) @ %p]: %s\n", 247 dump_printf(" %d/%d: [%p(%p) @ %p]: %s\n",
213 self->mmap.pid, self->mmap.tid, 248 self->mmap.pid, self->mmap.tid,
@@ -224,10 +259,10 @@ int event__process_mmap(event_t *self)
224 return 0; 259 return 0;
225} 260}
226 261
227int event__process_task(event_t *self) 262int event__process_task(event_t *self, struct perf_session *session)
228{ 263{
229 struct thread *thread = threads__findnew(self->fork.pid); 264 struct thread *thread = perf_session__findnew(session, self->fork.pid);
230 struct thread *parent = threads__findnew(self->fork.ppid); 265 struct thread *parent = perf_session__findnew(session, self->fork.ppid);
231 266
232 dump_printf("(%d:%d):(%d:%d)\n", self->fork.pid, self->fork.tid, 267 dump_printf("(%d:%d):(%d:%d)\n", self->fork.pid, self->fork.tid,
233 self->fork.ppid, self->fork.ptid); 268 self->fork.ppid, self->fork.ptid);
@@ -249,7 +284,8 @@ int event__process_task(event_t *self)
249 return 0; 284 return 0;
250} 285}
251 286
252void thread__find_addr_location(struct thread *self, u8 cpumode, 287void thread__find_addr_location(struct thread *self,
288 struct perf_session *session, u8 cpumode,
253 enum map_type type, u64 addr, 289 enum map_type type, u64 addr,
254 struct addr_location *al, 290 struct addr_location *al,
255 symbol_filter_t filter) 291 symbol_filter_t filter)
@@ -261,7 +297,7 @@ void thread__find_addr_location(struct thread *self, u8 cpumode,
261 297
262 if (cpumode & PERF_RECORD_MISC_KERNEL) { 298 if (cpumode & PERF_RECORD_MISC_KERNEL) {
263 al->level = 'k'; 299 al->level = 'k';
264 mg = kmaps; 300 mg = &session->kmaps;
265 } else if (cpumode & PERF_RECORD_MISC_USER) 301 } else if (cpumode & PERF_RECORD_MISC_USER)
266 al->level = '.'; 302 al->level = '.';
267 else { 303 else {
@@ -282,33 +318,73 @@ try_again:
282 * "[vdso]" dso, but for now lets use the old trick of looking 318 * "[vdso]" dso, but for now lets use the old trick of looking
283 * in the whole kernel symbol list. 319 * in the whole kernel symbol list.
284 */ 320 */
285 if ((long long)al->addr < 0 && mg != kmaps) { 321 if ((long long)al->addr < 0 && mg != &session->kmaps) {
286 mg = kmaps; 322 mg = &session->kmaps;
287 goto try_again; 323 goto try_again;
288 } 324 }
289 al->sym = NULL; 325 al->sym = NULL;
290 } else { 326 } else {
291 al->addr = al->map->map_ip(al->map, al->addr); 327 al->addr = al->map->map_ip(al->map, al->addr);
292 al->sym = map__find_symbol(al->map, al->addr, filter); 328 al->sym = map__find_symbol(al->map, session, al->addr, filter);
293 } 329 }
294} 330}
295 331
296int event__preprocess_sample(const event_t *self, struct addr_location *al, 332static void dso__calc_col_width(struct dso *self)
297 symbol_filter_t filter) 333{
334 if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
335 (!symbol_conf.dso_list ||
336 strlist__has_entry(symbol_conf.dso_list, self->name))) {
337 unsigned int slen = strlen(self->name);
338 if (slen > dsos__col_width)
339 dsos__col_width = slen;
340 }
341
342 self->slen_calculated = 1;
343}
344
345int event__preprocess_sample(const event_t *self, struct perf_session *session,
346 struct addr_location *al, symbol_filter_t filter)
298{ 347{
299 u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 348 u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
300 struct thread *thread = threads__findnew(self->ip.pid); 349 struct thread *thread = perf_session__findnew(session, self->ip.pid);
301 350
302 if (thread == NULL) 351 if (thread == NULL)
303 return -1; 352 return -1;
304 353
354 if (symbol_conf.comm_list &&
355 !strlist__has_entry(symbol_conf.comm_list, thread->comm))
356 goto out_filtered;
357
305 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); 358 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
306 359
307 thread__find_addr_location(thread, cpumode, MAP__FUNCTION, 360 thread__find_addr_location(thread, session, cpumode, MAP__FUNCTION,
308 self->ip.ip, al, filter); 361 self->ip.ip, al, filter);
309 dump_printf(" ...... dso: %s\n", 362 dump_printf(" ...... dso: %s\n",
310 al->map ? al->map->dso->long_name : 363 al->map ? al->map->dso->long_name :
311 al->level == 'H' ? "[hypervisor]" : "<not found>"); 364 al->level == 'H' ? "[hypervisor]" : "<not found>");
365 /*
366 * We have to do this here as we may have a dso with no symbol hit that
367 * has a name longer than the ones with symbols sampled.
368 */
369 if (al->map && !sort_dso.elide && !al->map->dso->slen_calculated)
370 dso__calc_col_width(al->map->dso);
371
372 if (symbol_conf.dso_list &&
373 (!al->map || !al->map->dso ||
374 !(strlist__has_entry(symbol_conf.dso_list, al->map->dso->short_name) ||
375 (al->map->dso->short_name != al->map->dso->long_name &&
376 strlist__has_entry(symbol_conf.dso_list, al->map->dso->long_name)))))
377 goto out_filtered;
378
379 if (symbol_conf.sym_list && al->sym &&
380 !strlist__has_entry(symbol_conf.sym_list, al->sym->name))
381 goto out_filtered;
382
383 al->filtered = false;
384 return 0;
385
386out_filtered:
387 al->filtered = true;
312 return 0; 388 return 0;
313} 389}
314 390
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 51a96c2effde..8027309b0422 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -149,29 +149,35 @@ void map__delete(struct map *self);
149struct map *map__clone(struct map *self); 149struct map *map__clone(struct map *self);
150int map__overlap(struct map *l, struct map *r); 150int map__overlap(struct map *l, struct map *r);
151size_t map__fprintf(struct map *self, FILE *fp); 151size_t map__fprintf(struct map *self, FILE *fp);
152struct symbol *map__find_symbol(struct map *self, u64 addr, 152
153 symbol_filter_t filter); 153struct perf_session;
154
155int map__load(struct map *self, struct perf_session *session,
156 symbol_filter_t filter);
157struct symbol *map__find_symbol(struct map *self, struct perf_session *session,
158 u64 addr, symbol_filter_t filter);
154struct symbol *map__find_symbol_by_name(struct map *self, const char *name, 159struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
160 struct perf_session *session,
155 symbol_filter_t filter); 161 symbol_filter_t filter);
156void map__fixup_start(struct map *self); 162void map__fixup_start(struct map *self);
157void map__fixup_end(struct map *self); 163void map__fixup_end(struct map *self);
158 164
159int event__synthesize_thread(pid_t pid, int (*process)(event_t *event)); 165int event__synthesize_thread(pid_t pid,
160void event__synthesize_threads(int (*process)(event_t *event)); 166 int (*process)(event_t *event,
161 167 struct perf_session *session),
162extern char *event__cwd; 168 struct perf_session *session);
163extern int event__cwdlen; 169void event__synthesize_threads(int (*process)(event_t *event,
164extern struct events_stats event__stats; 170 struct perf_session *session),
165extern unsigned long event__total[PERF_RECORD_MAX]; 171 struct perf_session *session);
166 172
167int event__process_comm(event_t *self); 173int event__process_comm(event_t *self, struct perf_session *session);
168int event__process_lost(event_t *self); 174int event__process_lost(event_t *self, struct perf_session *session);
169int event__process_mmap(event_t *self); 175int event__process_mmap(event_t *self, struct perf_session *session);
170int event__process_task(event_t *self); 176int event__process_task(event_t *self, struct perf_session *session);
171 177
172struct addr_location; 178struct addr_location;
173int event__preprocess_sample(const event_t *self, struct addr_location *al, 179int event__preprocess_sample(const event_t *self, struct perf_session *session,
174 symbol_filter_t filter); 180 struct addr_location *al, symbol_filter_t filter);
175int event__parse_sample(event_t *event, u64 type, struct sample_data *data); 181int event__parse_sample(event_t *event, u64 type, struct sample_data *data);
176 182
177#endif /* __PERF_RECORD_H */ 183#endif /* __PERF_RECORD_H */
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index f2e8d8715111..8a0bca55106f 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -8,8 +8,8 @@
8#include "header.h" 8#include "header.h"
9#include "../perf.h" 9#include "../perf.h"
10#include "trace-event.h" 10#include "trace-event.h"
11#include "session.h"
11#include "symbol.h" 12#include "symbol.h"
12#include "data_map.h"
13#include "debug.h" 13#include "debug.h"
14 14
15/* 15/*
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 0ebf6ee16caa..e8daf5ca6fd2 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -1,9 +1,7 @@
1#include "hist.h" 1#include "hist.h"
2 2#include "session.h"
3struct rb_root hist; 3#include "sort.h"
4struct rb_root collapse_hists; 4#include <math.h>
5struct rb_root output_hists;
6int callchain;
7 5
8struct callchain_param callchain_param = { 6struct callchain_param callchain_param = {
9 .mode = CHAIN_GRAPH_REL, 7 .mode = CHAIN_GRAPH_REL,
@@ -14,11 +12,12 @@ struct callchain_param callchain_param = {
14 * histogram, sorted on item, collects counts 12 * histogram, sorted on item, collects counts
15 */ 13 */
16 14
17struct hist_entry *__hist_entry__add(struct addr_location *al, 15struct hist_entry *__perf_session__add_hist_entry(struct perf_session *self,
18 struct symbol *sym_parent, 16 struct addr_location *al,
19 u64 count, bool *hit) 17 struct symbol *sym_parent,
18 u64 count, bool *hit)
20{ 19{
21 struct rb_node **p = &hist.rb_node; 20 struct rb_node **p = &self->hists.rb_node;
22 struct rb_node *parent = NULL; 21 struct rb_node *parent = NULL;
23 struct hist_entry *he; 22 struct hist_entry *he;
24 struct hist_entry entry = { 23 struct hist_entry entry = {
@@ -54,7 +53,7 @@ struct hist_entry *__hist_entry__add(struct addr_location *al,
54 return NULL; 53 return NULL;
55 *he = entry; 54 *he = entry;
56 rb_link_node(&he->rb_node, parent, p); 55 rb_link_node(&he->rb_node, parent, p);
57 rb_insert_color(&he->rb_node, &hist); 56 rb_insert_color(&he->rb_node, &self->hists);
58 *hit = false; 57 *hit = false;
59 return he; 58 return he;
60} 59}
@@ -102,9 +101,9 @@ void hist_entry__free(struct hist_entry *he)
102 * collapse the histogram 101 * collapse the histogram
103 */ 102 */
104 103
105void collapse__insert_entry(struct hist_entry *he) 104static void collapse__insert_entry(struct rb_root *root, struct hist_entry *he)
106{ 105{
107 struct rb_node **p = &collapse_hists.rb_node; 106 struct rb_node **p = &root->rb_node;
108 struct rb_node *parent = NULL; 107 struct rb_node *parent = NULL;
109 struct hist_entry *iter; 108 struct hist_entry *iter;
110 int64_t cmp; 109 int64_t cmp;
@@ -128,38 +127,45 @@ void collapse__insert_entry(struct hist_entry *he)
128 } 127 }
129 128
130 rb_link_node(&he->rb_node, parent, p); 129 rb_link_node(&he->rb_node, parent, p);
131 rb_insert_color(&he->rb_node, &collapse_hists); 130 rb_insert_color(&he->rb_node, root);
132} 131}
133 132
134void collapse__resort(void) 133void perf_session__collapse_resort(struct perf_session *self)
135{ 134{
135 struct rb_root tmp;
136 struct rb_node *next; 136 struct rb_node *next;
137 struct hist_entry *n; 137 struct hist_entry *n;
138 138
139 if (!sort__need_collapse) 139 if (!sort__need_collapse)
140 return; 140 return;
141 141
142 next = rb_first(&hist); 142 tmp = RB_ROOT;
143 next = rb_first(&self->hists);
144
143 while (next) { 145 while (next) {
144 n = rb_entry(next, struct hist_entry, rb_node); 146 n = rb_entry(next, struct hist_entry, rb_node);
145 next = rb_next(&n->rb_node); 147 next = rb_next(&n->rb_node);
146 148
147 rb_erase(&n->rb_node, &hist); 149 rb_erase(&n->rb_node, &self->hists);
148 collapse__insert_entry(n); 150 collapse__insert_entry(&tmp, n);
149 } 151 }
152
153 self->hists = tmp;
150} 154}
151 155
152/* 156/*
153 * reverse the map, sort on count. 157 * reverse the map, sort on count.
154 */ 158 */
155 159
156void output__insert_entry(struct hist_entry *he, u64 min_callchain_hits) 160static void perf_session__insert_output_hist_entry(struct rb_root *root,
161 struct hist_entry *he,
162 u64 min_callchain_hits)
157{ 163{
158 struct rb_node **p = &output_hists.rb_node; 164 struct rb_node **p = &root->rb_node;
159 struct rb_node *parent = NULL; 165 struct rb_node *parent = NULL;
160 struct hist_entry *iter; 166 struct hist_entry *iter;
161 167
162 if (callchain) 168 if (symbol_conf.use_callchain)
163 callchain_param.sort(&he->sorted_chain, &he->callchain, 169 callchain_param.sort(&he->sorted_chain, &he->callchain,
164 min_callchain_hits, &callchain_param); 170 min_callchain_hits, &callchain_param);
165 171
@@ -174,29 +180,483 @@ void output__insert_entry(struct hist_entry *he, u64 min_callchain_hits)
174 } 180 }
175 181
176 rb_link_node(&he->rb_node, parent, p); 182 rb_link_node(&he->rb_node, parent, p);
177 rb_insert_color(&he->rb_node, &output_hists); 183 rb_insert_color(&he->rb_node, root);
178} 184}
179 185
180void output__resort(u64 total_samples) 186void perf_session__output_resort(struct perf_session *self, u64 total_samples)
181{ 187{
188 struct rb_root tmp;
182 struct rb_node *next; 189 struct rb_node *next;
183 struct hist_entry *n; 190 struct hist_entry *n;
184 struct rb_root *tree = &hist;
185 u64 min_callchain_hits; 191 u64 min_callchain_hits;
186 192
187 min_callchain_hits = 193 min_callchain_hits =
188 total_samples * (callchain_param.min_percent / 100); 194 total_samples * (callchain_param.min_percent / 100);
189 195
190 if (sort__need_collapse) 196 tmp = RB_ROOT;
191 tree = &collapse_hists; 197 next = rb_first(&self->hists);
192
193 next = rb_first(tree);
194 198
195 while (next) { 199 while (next) {
196 n = rb_entry(next, struct hist_entry, rb_node); 200 n = rb_entry(next, struct hist_entry, rb_node);
197 next = rb_next(&n->rb_node); 201 next = rb_next(&n->rb_node);
198 202
199 rb_erase(&n->rb_node, tree); 203 rb_erase(&n->rb_node, &self->hists);
200 output__insert_entry(n, min_callchain_hits); 204 perf_session__insert_output_hist_entry(&tmp, n,
205 min_callchain_hits);
206 }
207
208 self->hists = tmp;
209}
210
211static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin)
212{
213 int i;
214 int ret = fprintf(fp, " ");
215
216 for (i = 0; i < left_margin; i++)
217 ret += fprintf(fp, " ");
218
219 return ret;
220}
221
222static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask,
223 int left_margin)
224{
225 int i;
226 size_t ret = callchain__fprintf_left_margin(fp, left_margin);
227
228 for (i = 0; i < depth; i++)
229 if (depth_mask & (1 << i))
230 ret += fprintf(fp, "| ");
231 else
232 ret += fprintf(fp, " ");
233
234 ret += fprintf(fp, "\n");
235
236 return ret;
237}
238
239static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain,
240 int depth, int depth_mask, int count,
241 u64 total_samples, int hits,
242 int left_margin)
243{
244 int i;
245 size_t ret = 0;
246
247 ret += callchain__fprintf_left_margin(fp, left_margin);
248 for (i = 0; i < depth; i++) {
249 if (depth_mask & (1 << i))
250 ret += fprintf(fp, "|");
251 else
252 ret += fprintf(fp, " ");
253 if (!count && i == depth - 1) {
254 double percent;
255
256 percent = hits * 100.0 / total_samples;
257 ret += percent_color_fprintf(fp, "--%2.2f%%-- ", percent);
258 } else
259 ret += fprintf(fp, "%s", " ");
260 }
261 if (chain->sym)
262 ret += fprintf(fp, "%s\n", chain->sym->name);
263 else
264 ret += fprintf(fp, "%p\n", (void *)(long)chain->ip);
265
266 return ret;
267}
268
269static struct symbol *rem_sq_bracket;
270static struct callchain_list rem_hits;
271
272static void init_rem_hits(void)
273{
274 rem_sq_bracket = malloc(sizeof(*rem_sq_bracket) + 6);
275 if (!rem_sq_bracket) {
276 fprintf(stderr, "Not enough memory to display remaining hits\n");
277 return;
278 }
279
280 strcpy(rem_sq_bracket->name, "[...]");
281 rem_hits.sym = rem_sq_bracket;
282}
283
284static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
285 u64 total_samples, int depth,
286 int depth_mask, int left_margin)
287{
288 struct rb_node *node, *next;
289 struct callchain_node *child;
290 struct callchain_list *chain;
291 int new_depth_mask = depth_mask;
292 u64 new_total;
293 u64 remaining;
294 size_t ret = 0;
295 int i;
296
297 if (callchain_param.mode == CHAIN_GRAPH_REL)
298 new_total = self->children_hit;
299 else
300 new_total = total_samples;
301
302 remaining = new_total;
303
304 node = rb_first(&self->rb_root);
305 while (node) {
306 u64 cumul;
307
308 child = rb_entry(node, struct callchain_node, rb_node);
309 cumul = cumul_hits(child);
310 remaining -= cumul;
311
312 /*
313 * The depth mask manages the output of pipes that show
314 * the depth. We don't want to keep the pipes of the current
315 * level for the last child of this depth.
316 * Except if we have remaining filtered hits. They will
317 * supersede the last child
318 */
319 next = rb_next(node);
320 if (!next && (callchain_param.mode != CHAIN_GRAPH_REL || !remaining))
321 new_depth_mask &= ~(1 << (depth - 1));
322
323 /*
324 * But we keep the older depth mask for the line seperator
325 * to keep the level link until we reach the last child
326 */
327 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask,
328 left_margin);
329 i = 0;
330 list_for_each_entry(chain, &child->val, list) {
331 if (chain->ip >= PERF_CONTEXT_MAX)
332 continue;
333 ret += ipchain__fprintf_graph(fp, chain, depth,
334 new_depth_mask, i++,
335 new_total,
336 cumul,
337 left_margin);
338 }
339 ret += __callchain__fprintf_graph(fp, child, new_total,
340 depth + 1,
341 new_depth_mask | (1 << depth),
342 left_margin);
343 node = next;
344 }
345
346 if (callchain_param.mode == CHAIN_GRAPH_REL &&
347 remaining && remaining != new_total) {
348
349 if (!rem_sq_bracket)
350 return ret;
351
352 new_depth_mask &= ~(1 << (depth - 1));
353
354 ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
355 new_depth_mask, 0, new_total,
356 remaining, left_margin);
357 }
358
359 return ret;
360}
361
362static size_t callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
363 u64 total_samples, int left_margin)
364{
365 struct callchain_list *chain;
366 bool printed = false;
367 int i = 0;
368 int ret = 0;
369
370 list_for_each_entry(chain, &self->val, list) {
371 if (chain->ip >= PERF_CONTEXT_MAX)
372 continue;
373
374 if (!i++ && sort__first_dimension == SORT_SYM)
375 continue;
376
377 if (!printed) {
378 ret += callchain__fprintf_left_margin(fp, left_margin);
379 ret += fprintf(fp, "|\n");
380 ret += callchain__fprintf_left_margin(fp, left_margin);
381 ret += fprintf(fp, "---");
382
383 left_margin += 3;
384 printed = true;
385 } else
386 ret += callchain__fprintf_left_margin(fp, left_margin);
387
388 if (chain->sym)
389 ret += fprintf(fp, " %s\n", chain->sym->name);
390 else
391 ret += fprintf(fp, " %p\n", (void *)(long)chain->ip);
392 }
393
394 ret += __callchain__fprintf_graph(fp, self, total_samples, 1, 1, left_margin);
395
396 return ret;
397}
398
399static size_t callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
400 u64 total_samples)
401{
402 struct callchain_list *chain;
403 size_t ret = 0;
404
405 if (!self)
406 return 0;
407
408 ret += callchain__fprintf_flat(fp, self->parent, total_samples);
409
410
411 list_for_each_entry(chain, &self->val, list) {
412 if (chain->ip >= PERF_CONTEXT_MAX)
413 continue;
414 if (chain->sym)
415 ret += fprintf(fp, " %s\n", chain->sym->name);
416 else
417 ret += fprintf(fp, " %p\n",
418 (void *)(long)chain->ip);
419 }
420
421 return ret;
422}
423
424static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
425 u64 total_samples, int left_margin)
426{
427 struct rb_node *rb_node;
428 struct callchain_node *chain;
429 size_t ret = 0;
430
431 rb_node = rb_first(&self->sorted_chain);
432 while (rb_node) {
433 double percent;
434
435 chain = rb_entry(rb_node, struct callchain_node, rb_node);
436 percent = chain->hit * 100.0 / total_samples;
437 switch (callchain_param.mode) {
438 case CHAIN_FLAT:
439 ret += percent_color_fprintf(fp, " %6.2f%%\n",
440 percent);
441 ret += callchain__fprintf_flat(fp, chain, total_samples);
442 break;
443 case CHAIN_GRAPH_ABS: /* Falldown */
444 case CHAIN_GRAPH_REL:
445 ret += callchain__fprintf_graph(fp, chain, total_samples,
446 left_margin);
447 case CHAIN_NONE:
448 default:
449 break;
450 }
451 ret += fprintf(fp, "\n");
452 rb_node = rb_next(rb_node);
453 }
454
455 return ret;
456}
457
458static size_t hist_entry__fprintf(struct hist_entry *self,
459 struct perf_session *session,
460 struct perf_session *pair_session,
461 bool show_displacement,
462 long displacement, FILE *fp)
463{
464 struct sort_entry *se;
465 u64 count, total;
466 const char *sep = symbol_conf.field_sep;
467 size_t ret;
468
469 if (symbol_conf.exclude_other && !self->parent)
470 return 0;
471
472 if (pair_session) {
473 count = self->pair ? self->pair->count : 0;
474 total = pair_session->events_stats.total;
475 } else {
476 count = self->count;
477 total = session->events_stats.total;
478 }
479
480 if (total)
481 ret = percent_color_fprintf(fp, sep ? "%.2f" : " %6.2f%%",
482 (count * 100.0) / total);
483 else
484 ret = fprintf(fp, sep ? "%lld" : "%12lld ", count);
485
486 if (symbol_conf.show_nr_samples) {
487 if (sep)
488 fprintf(fp, "%c%lld", *sep, count);
489 else
490 fprintf(fp, "%11lld", count);
491 }
492
493 if (pair_session) {
494 char bf[32];
495 double old_percent = 0, new_percent = 0, diff;
496
497 if (total > 0)
498 old_percent = (count * 100.0) / total;
499 if (session->events_stats.total > 0)
500 new_percent = (self->count * 100.0) / session->events_stats.total;
501
502 diff = new_percent - old_percent;
503
504 if (fabs(diff) >= 0.01)
505 snprintf(bf, sizeof(bf), "%+4.2F%%", diff);
506 else
507 snprintf(bf, sizeof(bf), " ");
508
509 if (sep)
510 ret += fprintf(fp, "%c%s", *sep, bf);
511 else
512 ret += fprintf(fp, "%11.11s", bf);
513
514 if (show_displacement) {
515 if (displacement)
516 snprintf(bf, sizeof(bf), "%+4ld", displacement);
517 else
518 snprintf(bf, sizeof(bf), " ");
519
520 if (sep)
521 fprintf(fp, "%c%s", *sep, bf);
522 else
523 fprintf(fp, "%6.6s", bf);
524 }
525 }
526
527 list_for_each_entry(se, &hist_entry__sort_list, list) {
528 if (se->elide)
529 continue;
530
531 fprintf(fp, "%s", sep ?: " ");
532 ret += se->print(fp, self, se->width ? *se->width : 0);
533 }
534
535 ret += fprintf(fp, "\n");
536
537 if (symbol_conf.use_callchain) {
538 int left_margin = 0;
539
540 if (sort__first_dimension == SORT_COMM) {
541 se = list_first_entry(&hist_entry__sort_list, typeof(*se),
542 list);
543 left_margin = se->width ? *se->width : 0;
544 left_margin -= thread__comm_len(self->thread);
545 }
546
547 hist_entry_callchain__fprintf(fp, self, session->events_stats.total,
548 left_margin);
549 }
550
551 return ret;
552}
553
554size_t perf_session__fprintf_hists(struct perf_session *self,
555 struct perf_session *pair,
556 bool show_displacement, FILE *fp)
557{
558 struct sort_entry *se;
559 struct rb_node *nd;
560 size_t ret = 0;
561 unsigned long position = 1;
562 long displacement = 0;
563 unsigned int width;
564 const char *sep = symbol_conf.field_sep;
565 char *col_width = symbol_conf.col_width_list_str;
566
567 init_rem_hits();
568
569 fprintf(fp, "# %s", pair ? "Baseline" : "Overhead");
570
571 if (symbol_conf.show_nr_samples) {
572 if (sep)
573 fprintf(fp, "%cSamples", *sep);
574 else
575 fputs(" Samples ", fp);
576 }
577
578 if (pair) {
579 if (sep)
580 ret += fprintf(fp, "%cDelta", *sep);
581 else
582 ret += fprintf(fp, " Delta ");
583
584 if (show_displacement) {
585 if (sep)
586 ret += fprintf(fp, "%cDisplacement", *sep);
587 else
588 ret += fprintf(fp, " Displ");
589 }
590 }
591
592 list_for_each_entry(se, &hist_entry__sort_list, list) {
593 if (se->elide)
594 continue;
595 if (sep) {
596 fprintf(fp, "%c%s", *sep, se->header);
597 continue;
598 }
599 width = strlen(se->header);
600 if (se->width) {
601 if (symbol_conf.col_width_list_str) {
602 if (col_width) {
603 *se->width = atoi(col_width);
604 col_width = strchr(col_width, ',');
605 if (col_width)
606 ++col_width;
607 }
608 }
609 width = *se->width = max(*se->width, width);
610 }
611 fprintf(fp, " %*s", width, se->header);
612 }
613 fprintf(fp, "\n");
614
615 if (sep)
616 goto print_entries;
617
618 fprintf(fp, "# ........");
619 if (symbol_conf.show_nr_samples)
620 fprintf(fp, " ..........");
621 if (pair) {
622 fprintf(fp, " ..........");
623 if (show_displacement)
624 fprintf(fp, " .....");
625 }
626 list_for_each_entry(se, &hist_entry__sort_list, list) {
627 unsigned int i;
628
629 if (se->elide)
630 continue;
631
632 fprintf(fp, " ");
633 if (se->width)
634 width = *se->width;
635 else
636 width = strlen(se->header);
637 for (i = 0; i < width; i++)
638 fprintf(fp, ".");
639 }
640
641 fprintf(fp, "\n#\n");
642
643print_entries:
644 for (nd = rb_first(&self->hists); nd; nd = rb_next(nd)) {
645 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
646
647 if (show_displacement) {
648 if (h->pair != NULL)
649 displacement = ((long)h->pair->position -
650 (long)position);
651 else
652 displacement = 0;
653 ++position;
654 }
655 ret += hist_entry__fprintf(h, self, pair, show_displacement,
656 displacement, fp);
201 } 657 }
658
659 free(rem_sq_bracket);
660
661 return ret;
202} 662}
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 3020db0c9292..e5f99b24048b 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -1,50 +1,27 @@
1#ifndef __PERF_HIST_H 1#ifndef __PERF_HIST_H
2#define __PERF_HIST_H 2#define __PERF_HIST_H
3#include "../builtin.h"
4 3
5#include "util.h" 4#include <linux/types.h>
6
7#include "color.h"
8#include <linux/list.h>
9#include "cache.h"
10#include <linux/rbtree.h>
11#include "symbol.h"
12#include "string.h"
13#include "callchain.h" 5#include "callchain.h"
14#include "strlist.h"
15#include "values.h"
16
17#include "../perf.h"
18#include "debug.h"
19#include "header.h"
20
21#include "parse-options.h"
22#include "parse-events.h"
23 6
24#include "thread.h"
25#include "sort.h"
26
27extern struct rb_root hist;
28extern struct rb_root collapse_hists;
29extern struct rb_root output_hists;
30extern int callchain;
31extern struct callchain_param callchain_param; 7extern struct callchain_param callchain_param;
32extern unsigned long total;
33extern unsigned long total_mmap;
34extern unsigned long total_comm;
35extern unsigned long total_fork;
36extern unsigned long total_unknown;
37extern unsigned long total_lost;
38 8
39struct hist_entry *__hist_entry__add(struct addr_location *al, 9struct perf_session;
40 struct symbol *parent, 10struct hist_entry;
41 u64 count, bool *hit); 11struct addr_location;
12struct symbol;
13
14struct hist_entry *__perf_session__add_hist_entry(struct perf_session *self,
15 struct addr_location *al,
16 struct symbol *parent,
17 u64 count, bool *hit);
42extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *); 18extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *);
43extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *); 19extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *);
44extern void hist_entry__free(struct hist_entry *); 20void hist_entry__free(struct hist_entry *);
45extern void collapse__insert_entry(struct hist_entry *);
46extern void collapse__resort(void);
47extern void output__insert_entry(struct hist_entry *, u64);
48extern void output__resort(u64);
49 21
22void perf_session__output_resort(struct perf_session *self, u64 total_samples);
23void perf_session__collapse_resort(struct perf_session *self);
24size_t perf_session__fprintf_hists(struct perf_session *self,
25 struct perf_session *pair,
26 bool show_displacement, FILE *fp);
50#endif /* __PERF_HIST_H */ 27#endif /* __PERF_HIST_H */
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 76bdca640a9b..c4d55a0da2ea 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -104,11 +104,16 @@ void map__fixup_end(struct map *self)
104 104
105#define DSO__DELETED "(deleted)" 105#define DSO__DELETED "(deleted)"
106 106
107static int map__load(struct map *self, symbol_filter_t filter) 107int map__load(struct map *self, struct perf_session *session,
108 symbol_filter_t filter)
108{ 109{
109 const char *name = self->dso->long_name; 110 const char *name = self->dso->long_name;
110 int nr = dso__load(self->dso, self, filter); 111 int nr;
111 112
113 if (dso__loaded(self->dso, self->type))
114 return 0;
115
116 nr = dso__load(self->dso, self, session, filter);
112 if (nr < 0) { 117 if (nr < 0) {
113 if (self->dso->has_build_id) { 118 if (self->dso->has_build_id) {
114 char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 119 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
@@ -143,19 +148,20 @@ static int map__load(struct map *self, symbol_filter_t filter)
143 return 0; 148 return 0;
144} 149}
145 150
146struct symbol *map__find_symbol(struct map *self, u64 addr, 151struct symbol *map__find_symbol(struct map *self, struct perf_session *session,
147 symbol_filter_t filter) 152 u64 addr, symbol_filter_t filter)
148{ 153{
149 if (!dso__loaded(self->dso, self->type) && map__load(self, filter) < 0) 154 if (map__load(self, session, filter) < 0)
150 return NULL; 155 return NULL;
151 156
152 return dso__find_symbol(self->dso, self->type, addr); 157 return dso__find_symbol(self->dso, self->type, addr);
153} 158}
154 159
155struct symbol *map__find_symbol_by_name(struct map *self, const char *name, 160struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
161 struct perf_session *session,
156 symbol_filter_t filter) 162 symbol_filter_t filter)
157{ 163{
158 if (!dso__loaded(self->dso, self->type) && map__load(self, filter) < 0) 164 if (map__load(self, session, filter) < 0)
159 return NULL; 165 return NULL;
160 166
161 if (!dso__sorted_by_name(self->dso, self->type)) 167 if (!dso__sorted_by_name(self->dso, self->type))
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index d14a4585bcaf..2ca62154f79b 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -69,10 +69,23 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
69 char c, nc = 0; 69 char c, nc = 0;
70 /* 70 /*
71 * <Syntax> 71 * <Syntax>
72 * perf probe SRC:LN 72 * perf probe [EVENT=]SRC:LN
73 * perf probe FUNC[+OFFS|%return][@SRC] 73 * perf probe [EVENT=]FUNC[+OFFS|%return][@SRC]
74 *
75 * TODO:Group name support
74 */ 76 */
75 77
78 ptr = strchr(arg, '=');
79 if (ptr) { /* Event name */
80 *ptr = '\0';
81 tmp = ptr + 1;
82 ptr = strchr(arg, ':');
83 if (ptr) /* Group name is not supported yet. */
84 semantic_error("Group name is not supported yet.");
85 pp->event = strdup(arg);
86 arg = tmp;
87 }
88
76 ptr = strpbrk(arg, ":+@%"); 89 ptr = strpbrk(arg, ":+@%");
77 if (ptr) { 90 if (ptr) {
78 nc = *ptr; 91 nc = *ptr;
@@ -150,10 +163,13 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
150} 163}
151 164
152/* Parse perf-probe event definition */ 165/* Parse perf-probe event definition */
153int parse_perf_probe_event(const char *str, struct probe_point *pp) 166void parse_perf_probe_event(const char *str, struct probe_point *pp,
167 bool *need_dwarf)
154{ 168{
155 char **argv; 169 char **argv;
156 int argc, i, need_dwarf = 0; 170 int argc, i;
171
172 *need_dwarf = false;
157 173
158 argv = argv_split(str, &argc); 174 argv = argv_split(str, &argc);
159 if (!argv) 175 if (!argv)
@@ -164,7 +180,7 @@ int parse_perf_probe_event(const char *str, struct probe_point *pp)
164 /* Parse probe point */ 180 /* Parse probe point */
165 parse_perf_probe_probepoint(argv[0], pp); 181 parse_perf_probe_probepoint(argv[0], pp);
166 if (pp->file || pp->line) 182 if (pp->file || pp->line)
167 need_dwarf = 1; 183 *need_dwarf = true;
168 184
169 /* Copy arguments and ensure return probe has no C argument */ 185 /* Copy arguments and ensure return probe has no C argument */
170 pp->nr_args = argc - 1; 186 pp->nr_args = argc - 1;
@@ -177,17 +193,15 @@ int parse_perf_probe_event(const char *str, struct probe_point *pp)
177 if (pp->retprobe) 193 if (pp->retprobe)
178 semantic_error("You can't specify local" 194 semantic_error("You can't specify local"
179 " variable for kretprobe"); 195 " variable for kretprobe");
180 need_dwarf = 1; 196 *need_dwarf = true;
181 } 197 }
182 } 198 }
183 199
184 argv_free(argv); 200 argv_free(argv);
185 return need_dwarf;
186} 201}
187 202
188/* Parse kprobe_events event into struct probe_point */ 203/* Parse kprobe_events event into struct probe_point */
189void parse_trace_kprobe_event(const char *str, char **group, char **event, 204void parse_trace_kprobe_event(const char *str, struct probe_point *pp)
190 struct probe_point *pp)
191{ 205{
192 char pr; 206 char pr;
193 char *p; 207 char *p;
@@ -203,18 +217,17 @@ void parse_trace_kprobe_event(const char *str, char **group, char **event,
203 217
204 /* Scan event and group name. */ 218 /* Scan event and group name. */
205 ret = sscanf(argv[0], "%c:%a[^/ \t]/%a[^ \t]", 219 ret = sscanf(argv[0], "%c:%a[^/ \t]/%a[^ \t]",
206 &pr, (float *)(void *)group, (float *)(void *)event); 220 &pr, (float *)(void *)&pp->group,
221 (float *)(void *)&pp->event);
207 if (ret != 3) 222 if (ret != 3)
208 semantic_error("Failed to parse event name: %s", argv[0]); 223 semantic_error("Failed to parse event name: %s", argv[0]);
209 pr_debug("Group:%s Event:%s probe:%c\n", *group, *event, pr); 224 pr_debug("Group:%s Event:%s probe:%c\n", pp->group, pp->event, pr);
210
211 if (!pp)
212 goto end;
213 225
214 pp->retprobe = (pr == 'r'); 226 pp->retprobe = (pr == 'r');
215 227
216 /* Scan function name and offset */ 228 /* Scan function name and offset */
217 ret = sscanf(argv[1], "%a[^+]+%d", (float *)(void *)&pp->function, &pp->offset); 229 ret = sscanf(argv[1], "%a[^+]+%d", (float *)(void *)&pp->function,
230 &pp->offset);
218 if (ret == 1) 231 if (ret == 1)
219 pp->offset = 0; 232 pp->offset = 0;
220 233
@@ -233,15 +246,15 @@ void parse_trace_kprobe_event(const char *str, char **group, char **event,
233 die("Failed to copy argument."); 246 die("Failed to copy argument.");
234 } 247 }
235 248
236end:
237 argv_free(argv); 249 argv_free(argv);
238} 250}
239 251
240int synthesize_perf_probe_event(struct probe_point *pp) 252/* Synthesize only probe point (not argument) */
253int synthesize_perf_probe_point(struct probe_point *pp)
241{ 254{
242 char *buf; 255 char *buf;
243 char offs[64] = "", line[64] = ""; 256 char offs[64] = "", line[64] = "";
244 int i, len, ret; 257 int ret;
245 258
246 pp->probes[0] = buf = zalloc(MAX_CMDLEN); 259 pp->probes[0] = buf = zalloc(MAX_CMDLEN);
247 if (!buf) 260 if (!buf)
@@ -262,10 +275,24 @@ int synthesize_perf_probe_event(struct probe_point *pp)
262 offs, pp->retprobe ? "%return" : "", line); 275 offs, pp->retprobe ? "%return" : "", line);
263 else 276 else
264 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", pp->file, line); 277 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", pp->file, line);
265 if (ret <= 0) 278 if (ret <= 0) {
266 goto error; 279error:
267 len = ret; 280 free(pp->probes[0]);
281 pp->probes[0] = NULL;
282 }
283 return ret;
284}
268 285
286int synthesize_perf_probe_event(struct probe_point *pp)
287{
288 char *buf;
289 int i, len, ret;
290
291 len = synthesize_perf_probe_point(pp);
292 if (len < 0)
293 return 0;
294
295 buf = pp->probes[0];
269 for (i = 0; i < pp->nr_args; i++) { 296 for (i = 0; i < pp->nr_args; i++) {
270 ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s", 297 ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s",
271 pp->args[i]); 298 pp->args[i]);
@@ -278,6 +305,7 @@ int synthesize_perf_probe_event(struct probe_point *pp)
278 return pp->found; 305 return pp->found;
279error: 306error:
280 free(pp->probes[0]); 307 free(pp->probes[0]);
308 pp->probes[0] = NULL;
281 309
282 return ret; 310 return ret;
283} 311}
@@ -307,6 +335,7 @@ int synthesize_trace_kprobe_event(struct probe_point *pp)
307 return pp->found; 335 return pp->found;
308error: 336error:
309 free(pp->probes[0]); 337 free(pp->probes[0]);
338 pp->probes[0] = NULL;
310 339
311 return ret; 340 return ret;
312} 341}
@@ -366,6 +395,10 @@ static void clear_probe_point(struct probe_point *pp)
366{ 395{
367 int i; 396 int i;
368 397
398 if (pp->event)
399 free(pp->event);
400 if (pp->group)
401 free(pp->group);
369 if (pp->function) 402 if (pp->function)
370 free(pp->function); 403 free(pp->function);
371 if (pp->file) 404 if (pp->file)
@@ -380,13 +413,15 @@ static void clear_probe_point(struct probe_point *pp)
380} 413}
381 414
382/* Show an event */ 415/* Show an event */
383static void show_perf_probe_event(const char *group, const char *event, 416static void show_perf_probe_event(const char *event, const char *place,
384 const char *place, struct probe_point *pp) 417 struct probe_point *pp)
385{ 418{
386 int i; 419 int i, ret;
387 char buf[128]; 420 char buf[128];
388 421
389 e_snprintf(buf, 128, "%s:%s", group, event); 422 ret = e_snprintf(buf, 128, "%s:%s", pp->group, event);
423 if (ret < 0)
424 die("Failed to copy event: %s", strerror(-ret));
390 printf(" %-40s (on %s", buf, place); 425 printf(" %-40s (on %s", buf, place);
391 426
392 if (pp->nr_args > 0) { 427 if (pp->nr_args > 0) {
@@ -400,9 +435,7 @@ static void show_perf_probe_event(const char *group, const char *event,
400/* List up current perf-probe events */ 435/* List up current perf-probe events */
401void show_perf_probe_events(void) 436void show_perf_probe_events(void)
402{ 437{
403 unsigned int i; 438 int fd;
404 int fd, nr;
405 char *group, *event;
406 struct probe_point pp; 439 struct probe_point pp;
407 struct strlist *rawlist; 440 struct strlist *rawlist;
408 struct str_node *ent; 441 struct str_node *ent;
@@ -411,18 +444,12 @@ void show_perf_probe_events(void)
411 rawlist = get_trace_kprobe_event_rawlist(fd); 444 rawlist = get_trace_kprobe_event_rawlist(fd);
412 close(fd); 445 close(fd);
413 446
414 for (i = 0; i < strlist__nr_entries(rawlist); i++) { 447 strlist__for_each(ent, rawlist) {
415 ent = strlist__entry(rawlist, i); 448 parse_trace_kprobe_event(ent->s, &pp);
416 parse_trace_kprobe_event(ent->s, &group, &event, &pp);
417 /* Synthesize only event probe point */ 449 /* Synthesize only event probe point */
418 nr = pp.nr_args; 450 synthesize_perf_probe_point(&pp);
419 pp.nr_args = 0;
420 synthesize_perf_probe_event(&pp);
421 pp.nr_args = nr;
422 /* Show an event */ 451 /* Show an event */
423 show_perf_probe_event(group, event, pp.probes[0], &pp); 452 show_perf_probe_event(pp.event, pp.probes[0], &pp);
424 free(group);
425 free(event);
426 clear_probe_point(&pp); 453 clear_probe_point(&pp);
427 } 454 }
428 455
@@ -432,26 +459,25 @@ void show_perf_probe_events(void)
432/* Get current perf-probe event names */ 459/* Get current perf-probe event names */
433static struct strlist *get_perf_event_names(int fd, bool include_group) 460static struct strlist *get_perf_event_names(int fd, bool include_group)
434{ 461{
435 unsigned int i;
436 char *group, *event;
437 char buf[128]; 462 char buf[128];
438 struct strlist *sl, *rawlist; 463 struct strlist *sl, *rawlist;
439 struct str_node *ent; 464 struct str_node *ent;
465 struct probe_point pp;
440 466
467 memset(&pp, 0, sizeof(pp));
441 rawlist = get_trace_kprobe_event_rawlist(fd); 468 rawlist = get_trace_kprobe_event_rawlist(fd);
442 469
443 sl = strlist__new(true, NULL); 470 sl = strlist__new(true, NULL);
444 for (i = 0; i < strlist__nr_entries(rawlist); i++) { 471 strlist__for_each(ent, rawlist) {
445 ent = strlist__entry(rawlist, i); 472 parse_trace_kprobe_event(ent->s, &pp);
446 parse_trace_kprobe_event(ent->s, &group, &event, NULL);
447 if (include_group) { 473 if (include_group) {
448 if (e_snprintf(buf, 128, "%s:%s", group, event) < 0) 474 if (e_snprintf(buf, 128, "%s:%s", pp.group,
475 pp.event) < 0)
449 die("Failed to copy group:event name."); 476 die("Failed to copy group:event name.");
450 strlist__add(sl, buf); 477 strlist__add(sl, buf);
451 } else 478 } else
452 strlist__add(sl, event); 479 strlist__add(sl, pp.event);
453 free(group); 480 clear_probe_point(&pp);
454 free(event);
455 } 481 }
456 482
457 strlist__delete(rawlist); 483 strlist__delete(rawlist);
@@ -470,7 +496,7 @@ static void write_trace_kprobe_event(int fd, const char *buf)
470} 496}
471 497
472static void get_new_event_name(char *buf, size_t len, const char *base, 498static void get_new_event_name(char *buf, size_t len, const char *base,
473 struct strlist *namelist) 499 struct strlist *namelist, bool allow_suffix)
474{ 500{
475 int i, ret; 501 int i, ret;
476 502
@@ -481,6 +507,12 @@ static void get_new_event_name(char *buf, size_t len, const char *base,
481 if (!strlist__has_entry(namelist, buf)) 507 if (!strlist__has_entry(namelist, buf))
482 return; 508 return;
483 509
510 if (!allow_suffix) {
511 pr_warning("Error: event \"%s\" already exists. "
512 "(Use -f to force duplicates.)\n", base);
513 die("Can't add new event.");
514 }
515
484 /* Try to add suffix */ 516 /* Try to add suffix */
485 for (i = 1; i < MAX_EVENT_INDEX; i++) { 517 for (i = 1; i < MAX_EVENT_INDEX; i++) {
486 ret = e_snprintf(buf, len, "%s_%d", base, i); 518 ret = e_snprintf(buf, len, "%s_%d", base, i);
@@ -493,13 +525,15 @@ static void get_new_event_name(char *buf, size_t len, const char *base,
493 die("Too many events are on the same function."); 525 die("Too many events are on the same function.");
494} 526}
495 527
496void add_trace_kprobe_events(struct probe_point *probes, int nr_probes) 528void add_trace_kprobe_events(struct probe_point *probes, int nr_probes,
529 bool force_add)
497{ 530{
498 int i, j, fd; 531 int i, j, fd;
499 struct probe_point *pp; 532 struct probe_point *pp;
500 char buf[MAX_CMDLEN]; 533 char buf[MAX_CMDLEN];
501 char event[64]; 534 char event[64];
502 struct strlist *namelist; 535 struct strlist *namelist;
536 bool allow_suffix;
503 537
504 fd = open_kprobe_events(O_RDWR, O_APPEND); 538 fd = open_kprobe_events(O_RDWR, O_APPEND);
505 /* Get current event names */ 539 /* Get current event names */
@@ -507,21 +541,35 @@ void add_trace_kprobe_events(struct probe_point *probes, int nr_probes)
507 541
508 for (j = 0; j < nr_probes; j++) { 542 for (j = 0; j < nr_probes; j++) {
509 pp = probes + j; 543 pp = probes + j;
544 if (!pp->event)
545 pp->event = strdup(pp->function);
546 if (!pp->group)
547 pp->group = strdup(PERFPROBE_GROUP);
548 DIE_IF(!pp->event || !pp->group);
549 /* If force_add is true, suffix search is allowed */
550 allow_suffix = force_add;
510 for (i = 0; i < pp->found; i++) { 551 for (i = 0; i < pp->found; i++) {
511 /* Get an unused new event name */ 552 /* Get an unused new event name */
512 get_new_event_name(event, 64, pp->function, namelist); 553 get_new_event_name(event, 64, pp->event, namelist,
554 allow_suffix);
513 snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s\n", 555 snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s\n",
514 pp->retprobe ? 'r' : 'p', 556 pp->retprobe ? 'r' : 'p',
515 PERFPROBE_GROUP, event, 557 pp->group, event,
516 pp->probes[i]); 558 pp->probes[i]);
517 write_trace_kprobe_event(fd, buf); 559 write_trace_kprobe_event(fd, buf);
518 printf("Added new event:\n"); 560 printf("Added new event:\n");
519 /* Get the first parameter (probe-point) */ 561 /* Get the first parameter (probe-point) */
520 sscanf(pp->probes[i], "%s", buf); 562 sscanf(pp->probes[i], "%s", buf);
521 show_perf_probe_event(PERFPROBE_GROUP, event, 563 show_perf_probe_event(event, buf, pp);
522 buf, pp);
523 /* Add added event name to namelist */ 564 /* Add added event name to namelist */
524 strlist__add(namelist, event); 565 strlist__add(namelist, event);
566 /*
567 * Probes after the first probe which comes from same
568 * user input are always allowed to add suffix, because
569 * there might be several addresses corresponding to
570 * one code line.
571 */
572 allow_suffix = true;
525 } 573 }
526 } 574 }
527 /* Show how to use the event. */ 575 /* Show how to use the event. */
@@ -532,29 +580,55 @@ void add_trace_kprobe_events(struct probe_point *probes, int nr_probes)
532 close(fd); 580 close(fd);
533} 581}
534 582
583static void __del_trace_kprobe_event(int fd, struct str_node *ent)
584{
585 char *p;
586 char buf[128];
587
588 /* Convert from perf-probe event to trace-kprobe event */
589 if (e_snprintf(buf, 128, "-:%s", ent->s) < 0)
590 die("Failed to copy event.");
591 p = strchr(buf + 2, ':');
592 if (!p)
593 die("Internal error: %s should have ':' but not.", ent->s);
594 *p = '/';
595
596 write_trace_kprobe_event(fd, buf);
597 printf("Remove event: %s\n", ent->s);
598}
599
535static void del_trace_kprobe_event(int fd, const char *group, 600static void del_trace_kprobe_event(int fd, const char *group,
536 const char *event, struct strlist *namelist) 601 const char *event, struct strlist *namelist)
537{ 602{
538 char buf[128]; 603 char buf[128];
604 struct str_node *ent, *n;
605 int found = 0;
539 606
540 if (e_snprintf(buf, 128, "%s:%s", group, event) < 0) 607 if (e_snprintf(buf, 128, "%s:%s", group, event) < 0)
541 die("Failed to copy event."); 608 die("Failed to copy event.");
542 if (!strlist__has_entry(namelist, buf)) {
543 pr_warning("Warning: event \"%s\" is not found.\n", buf);
544 return;
545 }
546 /* Convert from perf-probe event to trace-kprobe event */
547 if (e_snprintf(buf, 128, "-:%s/%s", group, event) < 0)
548 die("Failed to copy event.");
549 609
550 write_trace_kprobe_event(fd, buf); 610 if (strpbrk(buf, "*?")) { /* Glob-exp */
551 printf("Remove event: %s:%s\n", group, event); 611 strlist__for_each_safe(ent, n, namelist)
612 if (strglobmatch(ent->s, buf)) {
613 found++;
614 __del_trace_kprobe_event(fd, ent);
615 strlist__remove(namelist, ent);
616 }
617 } else {
618 ent = strlist__find(namelist, buf);
619 if (ent) {
620 found++;
621 __del_trace_kprobe_event(fd, ent);
622 strlist__remove(namelist, ent);
623 }
624 }
625 if (found == 0)
626 pr_info("Info: event \"%s\" does not exist, could not remove it.\n", buf);
552} 627}
553 628
554void del_trace_kprobe_events(struct strlist *dellist) 629void del_trace_kprobe_events(struct strlist *dellist)
555{ 630{
556 int fd; 631 int fd;
557 unsigned int i;
558 const char *group, *event; 632 const char *group, *event;
559 char *p, *str; 633 char *p, *str;
560 struct str_node *ent; 634 struct str_node *ent;
@@ -564,20 +638,21 @@ void del_trace_kprobe_events(struct strlist *dellist)
564 /* Get current event names */ 638 /* Get current event names */
565 namelist = get_perf_event_names(fd, true); 639 namelist = get_perf_event_names(fd, true);
566 640
567 for (i = 0; i < strlist__nr_entries(dellist); i++) { 641 strlist__for_each(ent, dellist) {
568 ent = strlist__entry(dellist, i);
569 str = strdup(ent->s); 642 str = strdup(ent->s);
570 if (!str) 643 if (!str)
571 die("Failed to copy event."); 644 die("Failed to copy event.");
645 pr_debug("Parsing: %s\n", str);
572 p = strchr(str, ':'); 646 p = strchr(str, ':');
573 if (p) { 647 if (p) {
574 group = str; 648 group = str;
575 *p = '\0'; 649 *p = '\0';
576 event = p + 1; 650 event = p + 1;
577 } else { 651 } else {
578 group = PERFPROBE_GROUP; 652 group = "*";
579 event = str; 653 event = str;
580 } 654 }
655 pr_debug("Group: %s, Event: %s\n", group, event);
581 del_trace_kprobe_event(fd, group, event, namelist); 656 del_trace_kprobe_event(fd, group, event, namelist);
582 free(str); 657 free(str);
583 } 658 }
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index f752159124ae..7f1d499118c0 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -1,15 +1,18 @@
1#ifndef _PROBE_EVENT_H 1#ifndef _PROBE_EVENT_H
2#define _PROBE_EVENT_H 2#define _PROBE_EVENT_H
3 3
4#include <stdbool.h>
4#include "probe-finder.h" 5#include "probe-finder.h"
5#include "strlist.h" 6#include "strlist.h"
6 7
7extern int parse_perf_probe_event(const char *str, struct probe_point *pp); 8extern void parse_perf_probe_event(const char *str, struct probe_point *pp,
9 bool *need_dwarf);
10extern int synthesize_perf_probe_point(struct probe_point *pp);
8extern int synthesize_perf_probe_event(struct probe_point *pp); 11extern int synthesize_perf_probe_event(struct probe_point *pp);
9extern void parse_trace_kprobe_event(const char *str, char **group, 12extern void parse_trace_kprobe_event(const char *str, struct probe_point *pp);
10 char **event, struct probe_point *pp);
11extern int synthesize_trace_kprobe_event(struct probe_point *pp); 13extern int synthesize_trace_kprobe_event(struct probe_point *pp);
12extern void add_trace_kprobe_events(struct probe_point *probes, int nr_probes); 14extern void add_trace_kprobe_events(struct probe_point *probes, int nr_probes,
15 bool force_add);
13extern void del_trace_kprobe_events(struct strlist *dellist); 16extern void del_trace_kprobe_events(struct strlist *dellist);
14extern void show_perf_probe_events(void); 17extern void show_perf_probe_events(void);
15 18
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 4585f1d86792..4b852c0d16a5 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -687,10 +687,8 @@ int find_probepoint(int fd, struct probe_point *pp)
687 struct probe_finder pf = {.pp = pp}; 687 struct probe_finder pf = {.pp = pp};
688 688
689 ret = dwarf_init(fd, DW_DLC_READ, 0, 0, &__dw_debug, &__dw_error); 689 ret = dwarf_init(fd, DW_DLC_READ, 0, 0, &__dw_debug, &__dw_error);
690 if (ret != DW_DLV_OK) { 690 if (ret != DW_DLV_OK)
691 pr_warning("No dwarf info found in the vmlinux - please rebuild with CONFIG_DEBUG_INFO.\n");
692 return -ENOENT; 691 return -ENOENT;
693 }
694 692
695 pp->found = 0; 693 pp->found = 0;
696 while (++cu_number) { 694 while (++cu_number) {
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index bdebca6697d2..5e4050ce2963 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -12,6 +12,9 @@ static inline int is_c_varname(const char *name)
12} 12}
13 13
14struct probe_point { 14struct probe_point {
15 char *event; /* Event name */
16 char *group; /* Event group */
17
15 /* Inputs */ 18 /* Inputs */
16 char *file; /* File name */ 19 char *file; /* File name */
17 int line; /* Line number */ 20 int line; /* Line number */
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 707ce1cb1621..ce3a6c8abe76 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -4,6 +4,7 @@
4#include <sys/types.h> 4#include <sys/types.h>
5 5
6#include "session.h" 6#include "session.h"
7#include "sort.h"
7#include "util.h" 8#include "util.h"
8 9
9static int perf_session__open(struct perf_session *self, bool force) 10static int perf_session__open(struct perf_session *self, bool force)
@@ -50,31 +51,100 @@ out_close:
50 51
51struct perf_session *perf_session__new(const char *filename, int mode, bool force) 52struct perf_session *perf_session__new(const char *filename, int mode, bool force)
52{ 53{
53 size_t len = strlen(filename) + 1; 54 size_t len = filename ? strlen(filename) + 1 : 0;
54 struct perf_session *self = zalloc(sizeof(*self) + len); 55 struct perf_session *self = zalloc(sizeof(*self) + len);
55 56
56 if (self == NULL) 57 if (self == NULL)
57 goto out; 58 goto out;
58 59
59 if (perf_header__init(&self->header) < 0) 60 if (perf_header__init(&self->header) < 0)
60 goto out_delete; 61 goto out_free;
61 62
62 memcpy(self->filename, filename, len); 63 memcpy(self->filename, filename, len);
64 self->threads = RB_ROOT;
65 self->last_match = NULL;
66 self->mmap_window = 32;
67 self->cwd = NULL;
68 self->cwdlen = 0;
69 map_groups__init(&self->kmaps);
70
71 if (perf_session__create_kernel_maps(self) < 0)
72 goto out_delete;
63 73
64 if (mode == O_RDONLY && perf_session__open(self, force) < 0) { 74 if (mode == O_RDONLY && perf_session__open(self, force) < 0)
65 perf_session__delete(self); 75 goto out_delete;
66 self = NULL;
67 }
68out: 76out:
69 return self; 77 return self;
70out_delete: 78out_free:
71 free(self); 79 free(self);
72 return NULL; 80 return NULL;
81out_delete:
82 perf_session__delete(self);
83 return NULL;
73} 84}
74 85
75void perf_session__delete(struct perf_session *self) 86void perf_session__delete(struct perf_session *self)
76{ 87{
77 perf_header__exit(&self->header); 88 perf_header__exit(&self->header);
78 close(self->fd); 89 close(self->fd);
90 free(self->cwd);
79 free(self); 91 free(self);
80} 92}
93
94static bool symbol__match_parent_regex(struct symbol *sym)
95{
96 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
97 return 1;
98
99 return 0;
100}
101
102struct symbol **perf_session__resolve_callchain(struct perf_session *self,
103 struct thread *thread,
104 struct ip_callchain *chain,
105 struct symbol **parent)
106{
107 u8 cpumode = PERF_RECORD_MISC_USER;
108 struct symbol **syms = NULL;
109 unsigned int i;
110
111 if (symbol_conf.use_callchain) {
112 syms = calloc(chain->nr, sizeof(*syms));
113 if (!syms) {
114 fprintf(stderr, "Can't allocate memory for symbols\n");
115 exit(-1);
116 }
117 }
118
119 for (i = 0; i < chain->nr; i++) {
120 u64 ip = chain->ips[i];
121 struct addr_location al;
122
123 if (ip >= PERF_CONTEXT_MAX) {
124 switch (ip) {
125 case PERF_CONTEXT_HV:
126 cpumode = PERF_RECORD_MISC_HYPERVISOR; break;
127 case PERF_CONTEXT_KERNEL:
128 cpumode = PERF_RECORD_MISC_KERNEL; break;
129 case PERF_CONTEXT_USER:
130 cpumode = PERF_RECORD_MISC_USER; break;
131 default:
132 break;
133 }
134 continue;
135 }
136
137 thread__find_addr_location(thread, self, cpumode,
138 MAP__FUNCTION, ip, &al, NULL);
139 if (al.sym != NULL) {
140 if (sort__has_parent && !*parent &&
141 symbol__match_parent_regex(al.sym))
142 *parent = al.sym;
143 if (!symbol_conf.use_callchain)
144 break;
145 syms[i] = al.sym;
146 }
147 }
148
149 return syms;
150}
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index f3699c8c8ed4..32eaa1bada06 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -1,16 +1,61 @@
1#ifndef __PERF_SESSION_H 1#ifndef __PERF_SESSION_H
2#define __PERF_SESSION_H 2#define __PERF_SESSION_H
3 3
4#include "event.h"
4#include "header.h" 5#include "header.h"
6#include "thread.h"
7#include <linux/rbtree.h>
8#include "../../../include/linux/perf_event.h"
9
10struct ip_callchain;
11struct thread;
12struct symbol;
5 13
6struct perf_session { 14struct perf_session {
7 struct perf_header header; 15 struct perf_header header;
8 unsigned long size; 16 unsigned long size;
17 unsigned long mmap_window;
18 struct map_groups kmaps;
19 struct rb_root threads;
20 struct thread *last_match;
21 struct events_stats events_stats;
22 unsigned long event_total[PERF_RECORD_MAX];
23 struct rb_root hists;
24 u64 sample_type;
9 int fd; 25 int fd;
26 int cwdlen;
27 char *cwd;
10 char filename[0]; 28 char filename[0];
11}; 29};
12 30
31typedef int (*event_op)(event_t *self, struct perf_session *session);
32
33struct perf_event_ops {
34 event_op process_sample_event;
35 event_op process_mmap_event;
36 event_op process_comm_event;
37 event_op process_fork_event;
38 event_op process_exit_event;
39 event_op process_lost_event;
40 event_op process_read_event;
41 event_op process_throttle_event;
42 event_op process_unthrottle_event;
43 int (*sample_type_check)(struct perf_session *session);
44 unsigned long total_unknown;
45 bool full_paths;
46};
47
13struct perf_session *perf_session__new(const char *filename, int mode, bool force); 48struct perf_session *perf_session__new(const char *filename, int mode, bool force);
14void perf_session__delete(struct perf_session *self); 49void perf_session__delete(struct perf_session *self);
15 50
51int perf_session__process_events(struct perf_session *self,
52 struct perf_event_ops *event_ops);
53
54struct symbol **perf_session__resolve_callchain(struct perf_session *self,
55 struct thread *thread,
56 struct ip_callchain *chain,
57 struct symbol **parent);
58
59int perf_header__read_build_ids(int input, u64 offset, u64 file_size);
60
16#endif /* __PERF_SESSION_H */ 61#endif /* __PERF_SESSION_H */
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index b490354d1b23..cb0f327de9e8 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -288,3 +288,29 @@ int sort_dimension__add(const char *tok)
288 288
289 return -ESRCH; 289 return -ESRCH;
290} 290}
291
292void setup_sorting(const char * const usagestr[], const struct option *opts)
293{
294 char *tmp, *tok, *str = strdup(sort_order);
295
296 for (tok = strtok_r(str, ", ", &tmp);
297 tok; tok = strtok_r(NULL, ", ", &tmp)) {
298 if (sort_dimension__add(tok) < 0) {
299 error("Unknown --sort key: `%s'", tok);
300 usage_with_options(usagestr, opts);
301 }
302 }
303
304 free(str);
305}
306
307void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list,
308 const char *list_name, FILE *fp)
309{
310 if (list && strlist__nr_entries(list) == 1) {
311 if (fp != NULL)
312 fprintf(fp, "# %s: %s\n", list_name,
313 strlist__entry(list, 0)->s);
314 self->elide = true;
315 }
316}
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 333e664ff45f..753f9ea99fb0 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -49,9 +49,13 @@ struct hist_entry {
49 struct symbol *sym; 49 struct symbol *sym;
50 u64 ip; 50 u64 ip;
51 char level; 51 char level;
52 struct symbol *parent; 52 struct symbol *parent;
53 struct callchain_node callchain; 53 struct callchain_node callchain;
54 struct rb_root sorted_chain; 54 union {
55 unsigned long position;
56 struct hist_entry *pair;
57 struct rb_root sorted_chain;
58 };
55}; 59};
56 60
57enum sort_type { 61enum sort_type {
@@ -81,6 +85,8 @@ struct sort_entry {
81extern struct sort_entry sort_thread; 85extern struct sort_entry sort_thread;
82extern struct list_head hist_entry__sort_list; 86extern struct list_head hist_entry__sort_list;
83 87
88void setup_sorting(const char * const usagestr[], const struct option *opts);
89
84extern int repsep_fprintf(FILE *fp, const char *fmt, ...); 90extern int repsep_fprintf(FILE *fp, const char *fmt, ...);
85extern size_t sort__thread_print(FILE *, struct hist_entry *, unsigned int); 91extern size_t sort__thread_print(FILE *, struct hist_entry *, unsigned int);
86extern size_t sort__comm_print(FILE *, struct hist_entry *, unsigned int); 92extern size_t sort__comm_print(FILE *, struct hist_entry *, unsigned int);
@@ -95,5 +101,7 @@ extern int64_t sort__sym_cmp(struct hist_entry *, struct hist_entry *);
95extern int64_t sort__parent_cmp(struct hist_entry *, struct hist_entry *); 101extern int64_t sort__parent_cmp(struct hist_entry *, struct hist_entry *);
96extern size_t sort__parent_print(FILE *, struct hist_entry *, unsigned int); 102extern size_t sort__parent_print(FILE *, struct hist_entry *, unsigned int);
97extern int sort_dimension__add(const char *); 103extern int sort_dimension__add(const char *);
104void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list,
105 const char *list_name, FILE *fp);
98 106
99#endif /* __PERF_SORT_H */ 107#endif /* __PERF_SORT_H */
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
index f24a8cc933d5..5352d7dccc61 100644
--- a/tools/perf/util/string.c
+++ b/tools/perf/util/string.c
@@ -226,3 +226,28 @@ fail:
226 argv_free(argv); 226 argv_free(argv);
227 return NULL; 227 return NULL;
228} 228}
229
230/* Glob expression pattern matching */
231bool strglobmatch(const char *str, const char *pat)
232{
233 while (*str && *pat && *pat != '*') {
234 if (*pat == '?') {
235 str++;
236 pat++;
237 } else
238 if (*str++ != *pat++)
239 return false;
240 }
241 /* Check wild card */
242 if (*pat == '*') {
243 while (*pat == '*')
244 pat++;
245 if (!*pat) /* Tail wild card matches all */
246 return true;
247 while (*str)
248 if (strglobmatch(str++, pat))
249 return true;
250 }
251 return !*str && !*pat;
252}
253
diff --git a/tools/perf/util/string.h b/tools/perf/util/string.h
index bfecec265a1a..02ede58c54b4 100644
--- a/tools/perf/util/string.h
+++ b/tools/perf/util/string.h
@@ -1,6 +1,7 @@
1#ifndef __PERF_STRING_H_ 1#ifndef __PERF_STRING_H_
2#define __PERF_STRING_H_ 2#define __PERF_STRING_H_
3 3
4#include <stdbool.h>
4#include "types.h" 5#include "types.h"
5 6
6int hex2u64(const char *ptr, u64 *val); 7int hex2u64(const char *ptr, u64 *val);
@@ -8,6 +9,7 @@ char *strxfrchar(char *s, char from, char to);
8s64 perf_atoll(const char *str); 9s64 perf_atoll(const char *str);
9char **argv_split(const char *str, int *argcp); 10char **argv_split(const char *str, int *argcp);
10void argv_free(char **argv); 11void argv_free(char **argv);
12bool strglobmatch(const char *str, const char *pat);
11 13
12#define _STR(x) #x 14#define _STR(x) #x
13#define STR(x) _STR(x) 15#define STR(x) _STR(x)
diff --git a/tools/perf/util/strlist.c b/tools/perf/util/strlist.c
index 7ad38171dc2b..6783a2043555 100644
--- a/tools/perf/util/strlist.c
+++ b/tools/perf/util/strlist.c
@@ -102,7 +102,7 @@ void strlist__remove(struct strlist *self, struct str_node *sn)
102 str_node__delete(sn, self->dupstr); 102 str_node__delete(sn, self->dupstr);
103} 103}
104 104
105bool strlist__has_entry(struct strlist *self, const char *entry) 105struct str_node *strlist__find(struct strlist *self, const char *entry)
106{ 106{
107 struct rb_node **p = &self->entries.rb_node; 107 struct rb_node **p = &self->entries.rb_node;
108 struct rb_node *parent = NULL; 108 struct rb_node *parent = NULL;
@@ -120,10 +120,10 @@ bool strlist__has_entry(struct strlist *self, const char *entry)
120 else if (rc < 0) 120 else if (rc < 0)
121 p = &(*p)->rb_right; 121 p = &(*p)->rb_right;
122 else 122 else
123 return true; 123 return sn;
124 } 124 }
125 125
126 return false; 126 return NULL;
127} 127}
128 128
129static int strlist__parse_list_entry(struct strlist *self, const char *s) 129static int strlist__parse_list_entry(struct strlist *self, const char *s)
diff --git a/tools/perf/util/strlist.h b/tools/perf/util/strlist.h
index cb4659306d7b..3ba839007d2c 100644
--- a/tools/perf/util/strlist.h
+++ b/tools/perf/util/strlist.h
@@ -23,7 +23,12 @@ int strlist__load(struct strlist *self, const char *filename);
23int strlist__add(struct strlist *self, const char *str); 23int strlist__add(struct strlist *self, const char *str);
24 24
25struct str_node *strlist__entry(const struct strlist *self, unsigned int idx); 25struct str_node *strlist__entry(const struct strlist *self, unsigned int idx);
26bool strlist__has_entry(struct strlist *self, const char *entry); 26struct str_node *strlist__find(struct strlist *self, const char *entry);
27
28static inline bool strlist__has_entry(struct strlist *self, const char *entry)
29{
30 return strlist__find(self, entry) != NULL;
31}
27 32
28static inline bool strlist__empty(const struct strlist *self) 33static inline bool strlist__empty(const struct strlist *self)
29{ 34{
@@ -35,5 +40,39 @@ static inline unsigned int strlist__nr_entries(const struct strlist *self)
35 return self->nr_entries; 40 return self->nr_entries;
36} 41}
37 42
43/* For strlist iteration */
44static inline struct str_node *strlist__first(struct strlist *self)
45{
46 struct rb_node *rn = rb_first(&self->entries);
47 return rn ? rb_entry(rn, struct str_node, rb_node) : NULL;
48}
49static inline struct str_node *strlist__next(struct str_node *sn)
50{
51 struct rb_node *rn;
52 if (!sn)
53 return NULL;
54 rn = rb_next(&sn->rb_node);
55 return rn ? rb_entry(rn, struct str_node, rb_node) : NULL;
56}
57
58/**
59 * strlist_for_each - iterate over a strlist
60 * @pos: the &struct str_node to use as a loop cursor.
61 * @self: the &struct strlist for loop.
62 */
63#define strlist__for_each(pos, self) \
64 for (pos = strlist__first(self); pos; pos = strlist__next(pos))
65
66/**
67 * strlist_for_each_safe - iterate over a strlist safe against removal of
68 * str_node
69 * @pos: the &struct str_node to use as a loop cursor.
70 * @n: another &struct str_node to use as temporary storage.
71 * @self: the &struct strlist for loop.
72 */
73#define strlist__for_each_safe(pos, n, self) \
74 for (pos = strlist__first(self), n = strlist__next(pos); pos;\
75 pos = n, n = strlist__next(n))
76
38int strlist__parse_list(struct strlist *self, const char *s); 77int strlist__parse_list(struct strlist *self, const char *s);
39#endif /* __PERF_STRLIST_H */ 78#endif /* __PERF_STRLIST_H */
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index d3d9fed74f1d..ab92763edb03 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -1,5 +1,7 @@
1#include "util.h" 1#include "util.h"
2#include "../perf.h" 2#include "../perf.h"
3#include "session.h"
4#include "sort.h"
3#include "string.h" 5#include "string.h"
4#include "symbol.h" 6#include "symbol.h"
5#include "thread.h" 7#include "thread.h"
@@ -31,19 +33,16 @@ enum dso_origin {
31static void dsos__add(struct list_head *head, struct dso *dso); 33static void dsos__add(struct list_head *head, struct dso *dso);
32static struct map *map__new2(u64 start, struct dso *dso, enum map_type type); 34static struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
33static int dso__load_kernel_sym(struct dso *self, struct map *map, 35static int dso__load_kernel_sym(struct dso *self, struct map *map,
34 struct map_groups *mg, symbol_filter_t filter); 36 struct perf_session *session, symbol_filter_t filter);
35unsigned int symbol__priv_size;
36static int vmlinux_path__nr_entries; 37static int vmlinux_path__nr_entries;
37static char **vmlinux_path; 38static char **vmlinux_path;
38 39
39static struct symbol_conf symbol_conf__defaults = { 40struct symbol_conf symbol_conf = {
41 .exclude_other = true,
40 .use_modules = true, 42 .use_modules = true,
41 .try_vmlinux_path = true, 43 .try_vmlinux_path = true,
42}; 44};
43 45
44static struct map_groups kmaps_mem;
45struct map_groups *kmaps = &kmaps_mem;
46
47bool dso__loaded(const struct dso *self, enum map_type type) 46bool dso__loaded(const struct dso *self, enum map_type type)
48{ 47{
49 return self->loaded & (1 << type); 48 return self->loaded & (1 << type);
@@ -132,13 +131,13 @@ static void map_groups__fixup_end(struct map_groups *self)
132static struct symbol *symbol__new(u64 start, u64 len, const char *name) 131static struct symbol *symbol__new(u64 start, u64 len, const char *name)
133{ 132{
134 size_t namelen = strlen(name) + 1; 133 size_t namelen = strlen(name) + 1;
135 struct symbol *self = zalloc(symbol__priv_size + 134 struct symbol *self = zalloc(symbol_conf.priv_size +
136 sizeof(*self) + namelen); 135 sizeof(*self) + namelen);
137 if (self == NULL) 136 if (self == NULL)
138 return NULL; 137 return NULL;
139 138
140 if (symbol__priv_size) 139 if (symbol_conf.priv_size)
141 self = ((void *)self) + symbol__priv_size; 140 self = ((void *)self) + symbol_conf.priv_size;
142 141
143 self->start = start; 142 self->start = start;
144 self->end = len ? start + len - 1 : start; 143 self->end = len ? start + len - 1 : start;
@@ -152,7 +151,7 @@ static struct symbol *symbol__new(u64 start, u64 len, const char *name)
152 151
153static void symbol__delete(struct symbol *self) 152static void symbol__delete(struct symbol *self)
154{ 153{
155 free(((void *)self) - symbol__priv_size); 154 free(((void *)self) - symbol_conf.priv_size);
156} 155}
157 156
158static size_t symbol__fprintf(struct symbol *self, FILE *fp) 157static size_t symbol__fprintf(struct symbol *self, FILE *fp)
@@ -456,7 +455,7 @@ out_failure:
456 * the original ELF section names vmlinux have. 455 * the original ELF section names vmlinux have.
457 */ 456 */
458static int dso__split_kallsyms(struct dso *self, struct map *map, 457static int dso__split_kallsyms(struct dso *self, struct map *map,
459 struct map_groups *mg, symbol_filter_t filter) 458 struct perf_session *session, symbol_filter_t filter)
460{ 459{
461 struct map *curr_map = map; 460 struct map *curr_map = map;
462 struct symbol *pos; 461 struct symbol *pos;
@@ -473,13 +472,13 @@ static int dso__split_kallsyms(struct dso *self, struct map *map,
473 472
474 module = strchr(pos->name, '\t'); 473 module = strchr(pos->name, '\t');
475 if (module) { 474 if (module) {
476 if (!mg->use_modules) 475 if (!symbol_conf.use_modules)
477 goto discard_symbol; 476 goto discard_symbol;
478 477
479 *module++ = '\0'; 478 *module++ = '\0';
480 479
481 if (strcmp(self->name, module)) { 480 if (strcmp(self->name, module)) {
482 curr_map = map_groups__find_by_name(mg, map->type, module); 481 curr_map = map_groups__find_by_name(&session->kmaps, map->type, module);
483 if (curr_map == NULL) { 482 if (curr_map == NULL) {
484 pr_debug("/proc/{kallsyms,modules} " 483 pr_debug("/proc/{kallsyms,modules} "
485 "inconsistency!\n"); 484 "inconsistency!\n");
@@ -510,7 +509,7 @@ static int dso__split_kallsyms(struct dso *self, struct map *map,
510 } 509 }
511 510
512 curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; 511 curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
513 map_groups__insert(mg, curr_map); 512 map_groups__insert(&session->kmaps, curr_map);
514 ++kernel_range; 513 ++kernel_range;
515 } 514 }
516 515
@@ -531,7 +530,7 @@ discard_symbol: rb_erase(&pos->rb_node, root);
531 530
532 531
533static int dso__load_kallsyms(struct dso *self, struct map *map, 532static int dso__load_kallsyms(struct dso *self, struct map *map,
534 struct map_groups *mg, symbol_filter_t filter) 533 struct perf_session *session, symbol_filter_t filter)
535{ 534{
536 if (dso__load_all_kallsyms(self, map) < 0) 535 if (dso__load_all_kallsyms(self, map) < 0)
537 return -1; 536 return -1;
@@ -539,14 +538,7 @@ static int dso__load_kallsyms(struct dso *self, struct map *map,
539 symbols__fixup_end(&self->symbols[map->type]); 538 symbols__fixup_end(&self->symbols[map->type]);
540 self->origin = DSO__ORIG_KERNEL; 539 self->origin = DSO__ORIG_KERNEL;
541 540
542 return dso__split_kallsyms(self, map, mg, filter); 541 return dso__split_kallsyms(self, map, session, filter);
543}
544
545size_t kernel_maps__fprintf(FILE *fp)
546{
547 size_t printed = fprintf(fp, "Kernel maps:\n");
548 printed += map_groups__fprintf_maps(kmaps, fp);
549 return printed + fprintf(fp, "END kernel maps\n");
550} 542}
551 543
552static int dso__load_perf_map(struct dso *self, struct map *map, 544static int dso__load_perf_map(struct dso *self, struct map *map,
@@ -873,7 +865,7 @@ static bool elf_sec__is_a(GElf_Shdr *self, Elf_Data *secstrs, enum map_type type
873} 865}
874 866
875static int dso__load_sym(struct dso *self, struct map *map, 867static int dso__load_sym(struct dso *self, struct map *map,
876 struct map_groups *mg, const char *name, int fd, 868 struct perf_session *session, const char *name, int fd,
877 symbol_filter_t filter, int kernel, int kmodule) 869 symbol_filter_t filter, int kernel, int kmodule)
878{ 870{
879 struct map *curr_map = map; 871 struct map *curr_map = map;
@@ -977,7 +969,7 @@ static int dso__load_sym(struct dso *self, struct map *map,
977 snprintf(dso_name, sizeof(dso_name), 969 snprintf(dso_name, sizeof(dso_name),
978 "%s%s", self->short_name, section_name); 970 "%s%s", self->short_name, section_name);
979 971
980 curr_map = map_groups__find_by_name(mg, map->type, dso_name); 972 curr_map = map_groups__find_by_name(&session->kmaps, map->type, dso_name);
981 if (curr_map == NULL) { 973 if (curr_map == NULL) {
982 u64 start = sym.st_value; 974 u64 start = sym.st_value;
983 975
@@ -996,7 +988,7 @@ static int dso__load_sym(struct dso *self, struct map *map,
996 curr_map->map_ip = identity__map_ip; 988 curr_map->map_ip = identity__map_ip;
997 curr_map->unmap_ip = identity__map_ip; 989 curr_map->unmap_ip = identity__map_ip;
998 curr_dso->origin = DSO__ORIG_KERNEL; 990 curr_dso->origin = DSO__ORIG_KERNEL;
999 map_groups__insert(kmaps, curr_map); 991 map_groups__insert(&session->kmaps, curr_map);
1000 dsos__add(&dsos__kernel, curr_dso); 992 dsos__add(&dsos__kernel, curr_dso);
1001 } else 993 } else
1002 curr_dso = curr_map->dso; 994 curr_dso = curr_map->dso;
@@ -1211,7 +1203,8 @@ char dso__symtab_origin(const struct dso *self)
1211 return origin[self->origin]; 1203 return origin[self->origin];
1212} 1204}
1213 1205
1214int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) 1206int dso__load(struct dso *self, struct map *map, struct perf_session *session,
1207 symbol_filter_t filter)
1215{ 1208{
1216 int size = PATH_MAX; 1209 int size = PATH_MAX;
1217 char *name; 1210 char *name;
@@ -1222,7 +1215,7 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
1222 dso__set_loaded(self, map->type); 1215 dso__set_loaded(self, map->type);
1223 1216
1224 if (self->kernel) 1217 if (self->kernel)
1225 return dso__load_kernel_sym(self, map, kmaps, filter); 1218 return dso__load_kernel_sym(self, map, session, filter);
1226 1219
1227 name = malloc(size); 1220 name = malloc(size);
1228 if (!name) 1221 if (!name)
@@ -1323,7 +1316,7 @@ struct map *map_groups__find_by_name(struct map_groups *self,
1323 return NULL; 1316 return NULL;
1324} 1317}
1325 1318
1326static int dsos__set_modules_path_dir(char *dirname) 1319static int perf_session__set_modules_path_dir(struct perf_session *self, char *dirname)
1327{ 1320{
1328 struct dirent *dent; 1321 struct dirent *dent;
1329 DIR *dir = opendir(dirname); 1322 DIR *dir = opendir(dirname);
@@ -1343,7 +1336,7 @@ static int dsos__set_modules_path_dir(char *dirname)
1343 1336
1344 snprintf(path, sizeof(path), "%s/%s", 1337 snprintf(path, sizeof(path), "%s/%s",
1345 dirname, dent->d_name); 1338 dirname, dent->d_name);
1346 if (dsos__set_modules_path_dir(path) < 0) 1339 if (perf_session__set_modules_path_dir(self, path) < 0)
1347 goto failure; 1340 goto failure;
1348 } else { 1341 } else {
1349 char *dot = strrchr(dent->d_name, '.'), 1342 char *dot = strrchr(dent->d_name, '.'),
@@ -1357,7 +1350,7 @@ static int dsos__set_modules_path_dir(char *dirname)
1357 (int)(dot - dent->d_name), dent->d_name); 1350 (int)(dot - dent->d_name), dent->d_name);
1358 1351
1359 strxfrchar(dso_name, '-', '_'); 1352 strxfrchar(dso_name, '-', '_');
1360 map = map_groups__find_by_name(kmaps, MAP__FUNCTION, dso_name); 1353 map = map_groups__find_by_name(&self->kmaps, MAP__FUNCTION, dso_name);
1361 if (map == NULL) 1354 if (map == NULL)
1362 continue; 1355 continue;
1363 1356
@@ -1377,7 +1370,7 @@ failure:
1377 return -1; 1370 return -1;
1378} 1371}
1379 1372
1380static int dsos__set_modules_path(void) 1373static int perf_session__set_modules_path(struct perf_session *self)
1381{ 1374{
1382 struct utsname uts; 1375 struct utsname uts;
1383 char modules_path[PATH_MAX]; 1376 char modules_path[PATH_MAX];
@@ -1388,7 +1381,7 @@ static int dsos__set_modules_path(void)
1388 snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel", 1381 snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel",
1389 uts.release); 1382 uts.release);
1390 1383
1391 return dsos__set_modules_path_dir(modules_path); 1384 return perf_session__set_modules_path_dir(self, modules_path);
1392} 1385}
1393 1386
1394/* 1387/*
@@ -1410,7 +1403,7 @@ static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
1410 return self; 1403 return self;
1411} 1404}
1412 1405
1413static int map_groups__create_module_maps(struct map_groups *self) 1406static int perf_session__create_module_maps(struct perf_session *self)
1414{ 1407{
1415 char *line = NULL; 1408 char *line = NULL;
1416 size_t n; 1409 size_t n;
@@ -1467,14 +1460,14 @@ static int map_groups__create_module_maps(struct map_groups *self)
1467 dso->has_build_id = true; 1460 dso->has_build_id = true;
1468 1461
1469 dso->origin = DSO__ORIG_KMODULE; 1462 dso->origin = DSO__ORIG_KMODULE;
1470 map_groups__insert(self, map); 1463 map_groups__insert(&self->kmaps, map);
1471 dsos__add(&dsos__kernel, dso); 1464 dsos__add(&dsos__kernel, dso);
1472 } 1465 }
1473 1466
1474 free(line); 1467 free(line);
1475 fclose(file); 1468 fclose(file);
1476 1469
1477 return dsos__set_modules_path(); 1470 return perf_session__set_modules_path(self);
1478 1471
1479out_delete_line: 1472out_delete_line:
1480 free(line); 1473 free(line);
@@ -1483,7 +1476,7 @@ out_failure:
1483} 1476}
1484 1477
1485static int dso__load_vmlinux(struct dso *self, struct map *map, 1478static int dso__load_vmlinux(struct dso *self, struct map *map,
1486 struct map_groups *mg, 1479 struct perf_session *session,
1487 const char *vmlinux, symbol_filter_t filter) 1480 const char *vmlinux, symbol_filter_t filter)
1488{ 1481{
1489 int err = -1, fd; 1482 int err = -1, fd;
@@ -1517,14 +1510,14 @@ static int dso__load_vmlinux(struct dso *self, struct map *map,
1517 return -1; 1510 return -1;
1518 1511
1519 dso__set_loaded(self, map->type); 1512 dso__set_loaded(self, map->type);
1520 err = dso__load_sym(self, map, mg, self->long_name, fd, filter, 1, 0); 1513 err = dso__load_sym(self, map, session, self->long_name, fd, filter, 1, 0);
1521 close(fd); 1514 close(fd);
1522 1515
1523 return err; 1516 return err;
1524} 1517}
1525 1518
1526static int dso__load_kernel_sym(struct dso *self, struct map *map, 1519static int dso__load_kernel_sym(struct dso *self, struct map *map,
1527 struct map_groups *mg, symbol_filter_t filter) 1520 struct perf_session *session, symbol_filter_t filter)
1528{ 1521{
1529 int err; 1522 int err;
1530 bool is_kallsyms; 1523 bool is_kallsyms;
@@ -1534,7 +1527,7 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
1534 pr_debug("Looking at the vmlinux_path (%d entries long)\n", 1527 pr_debug("Looking at the vmlinux_path (%d entries long)\n",
1535 vmlinux_path__nr_entries); 1528 vmlinux_path__nr_entries);
1536 for (i = 0; i < vmlinux_path__nr_entries; ++i) { 1529 for (i = 0; i < vmlinux_path__nr_entries; ++i) {
1537 err = dso__load_vmlinux(self, map, mg, 1530 err = dso__load_vmlinux(self, map, session,
1538 vmlinux_path[i], filter); 1531 vmlinux_path[i], filter);
1539 if (err > 0) { 1532 if (err > 0) {
1540 pr_debug("Using %s for symbols\n", 1533 pr_debug("Using %s for symbols\n",
@@ -1550,12 +1543,12 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
1550 if (is_kallsyms) 1543 if (is_kallsyms)
1551 goto do_kallsyms; 1544 goto do_kallsyms;
1552 1545
1553 err = dso__load_vmlinux(self, map, mg, self->long_name, filter); 1546 err = dso__load_vmlinux(self, map, session, self->long_name, filter);
1554 if (err <= 0) { 1547 if (err <= 0) {
1555 pr_info("The file %s cannot be used, " 1548 pr_info("The file %s cannot be used, "
1556 "trying to use /proc/kallsyms...", self->long_name); 1549 "trying to use /proc/kallsyms...", self->long_name);
1557do_kallsyms: 1550do_kallsyms:
1558 err = dso__load_kallsyms(self, map, mg, filter); 1551 err = dso__load_kallsyms(self, map, session, filter);
1559 if (err > 0 && !is_kallsyms) 1552 if (err > 0 && !is_kallsyms)
1560 dso__set_long_name(self, strdup("[kernel.kallsyms]")); 1553 dso__set_long_name(self, strdup("[kernel.kallsyms]"));
1561 } 1554 }
@@ -1748,32 +1741,69 @@ out_fail:
1748 return -1; 1741 return -1;
1749} 1742}
1750 1743
1751int symbol__init(struct symbol_conf *conf) 1744static int setup_list(struct strlist **list, const char *list_str,
1745 const char *list_name)
1752{ 1746{
1753 const struct symbol_conf *pconf = conf ?: &symbol_conf__defaults; 1747 if (list_str == NULL)
1748 return 0;
1749
1750 *list = strlist__new(true, list_str);
1751 if (!*list) {
1752 pr_err("problems parsing %s list\n", list_name);
1753 return -1;
1754 }
1755 return 0;
1756}
1754 1757
1758int symbol__init(void)
1759{
1755 elf_version(EV_CURRENT); 1760 elf_version(EV_CURRENT);
1756 symbol__priv_size = pconf->priv_size; 1761 if (symbol_conf.sort_by_name)
1757 if (pconf->sort_by_name) 1762 symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) -
1758 symbol__priv_size += (sizeof(struct symbol_name_rb_node) - 1763 sizeof(struct symbol));
1759 sizeof(struct symbol));
1760 map_groups__init(kmaps);
1761 1764
1762 if (pconf->try_vmlinux_path && vmlinux_path__init() < 0) 1765 if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0)
1763 return -1; 1766 return -1;
1764 1767
1765 if (map_groups__create_kernel_maps(kmaps, pconf->vmlinux_name) < 0) { 1768 if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') {
1766 vmlinux_path__exit(); 1769 pr_err("'.' is the only non valid --field-separator argument\n");
1767 return -1; 1770 return -1;
1768 } 1771 }
1769 1772
1770 kmaps->use_modules = pconf->use_modules; 1773 if (setup_list(&symbol_conf.dso_list,
1771 if (pconf->use_modules && map_groups__create_module_maps(kmaps) < 0) 1774 symbol_conf.dso_list_str, "dso") < 0)
1772 pr_debug("Failed to load list of modules in use, " 1775 return -1;
1773 "continuing...\n"); 1776
1777 if (setup_list(&symbol_conf.comm_list,
1778 symbol_conf.comm_list_str, "comm") < 0)
1779 goto out_free_dso_list;
1780
1781 if (setup_list(&symbol_conf.sym_list,
1782 symbol_conf.sym_list_str, "symbol") < 0)
1783 goto out_free_comm_list;
1784
1785 return 0;
1786
1787out_free_dso_list:
1788 strlist__delete(symbol_conf.dso_list);
1789out_free_comm_list:
1790 strlist__delete(symbol_conf.comm_list);
1791 return -1;
1792}
1793
1794int perf_session__create_kernel_maps(struct perf_session *self)
1795{
1796 if (map_groups__create_kernel_maps(&self->kmaps,
1797 symbol_conf.vmlinux_name) < 0)
1798 return -1;
1799
1800 if (symbol_conf.use_modules &&
1801 perf_session__create_module_maps(self) < 0)
1802 pr_debug("Failed to load list of modules for session %s, "
1803 "continuing...\n", self->filename);
1774 /* 1804 /*
1775 * Now that we have all the maps created, just set the ->end of them: 1805 * Now that we have all the maps created, just set the ->end of them:
1776 */ 1806 */
1777 map_groups__fixup_end(kmaps); 1807 map_groups__fixup_end(&self->kmaps);
1778 return 0; 1808 return 0;
1779} 1809}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index cf99f88adf39..8aded2356f79 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -49,19 +49,32 @@ struct symbol {
49 char name[0]; 49 char name[0];
50}; 50};
51 51
52struct strlist;
53
52struct symbol_conf { 54struct symbol_conf {
53 unsigned short priv_size; 55 unsigned short priv_size;
54 bool try_vmlinux_path, 56 bool try_vmlinux_path,
55 use_modules, 57 use_modules,
56 sort_by_name; 58 sort_by_name,
57 const char *vmlinux_name; 59 show_nr_samples,
60 use_callchain,
61 exclude_other;
62 const char *vmlinux_name,
63 *field_sep;
64 char *dso_list_str,
65 *comm_list_str,
66 *sym_list_str,
67 *col_width_list_str;
68 struct strlist *dso_list,
69 *comm_list,
70 *sym_list;
58}; 71};
59 72
60extern unsigned int symbol__priv_size; 73extern struct symbol_conf symbol_conf;
61 74
62static inline void *symbol__priv(struct symbol *self) 75static inline void *symbol__priv(struct symbol *self)
63{ 76{
64 return ((void *)self) - symbol__priv_size; 77 return ((void *)self) - symbol_conf.priv_size;
65} 78}
66 79
67struct addr_location { 80struct addr_location {
@@ -70,6 +83,7 @@ struct addr_location {
70 struct symbol *sym; 83 struct symbol *sym;
71 u64 addr; 84 u64 addr;
72 char level; 85 char level;
86 bool filtered;
73}; 87};
74 88
75struct dso { 89struct dso {
@@ -98,8 +112,11 @@ bool dso__sorted_by_name(const struct dso *self, enum map_type type);
98 112
99void dso__sort_by_name(struct dso *self, enum map_type type); 113void dso__sort_by_name(struct dso *self, enum map_type type);
100 114
115struct perf_session;
116
101struct dso *dsos__findnew(const char *name); 117struct dso *dsos__findnew(const char *name);
102int dso__load(struct dso *self, struct map *map, symbol_filter_t filter); 118int dso__load(struct dso *self, struct map *map, struct perf_session *session,
119 symbol_filter_t filter);
103void dsos__fprintf(FILE *fp); 120void dsos__fprintf(FILE *fp);
104size_t dsos__fprintf_buildid(FILE *fp); 121size_t dsos__fprintf_buildid(FILE *fp);
105 122
@@ -116,12 +133,9 @@ int sysfs__read_build_id(const char *filename, void *bf, size_t size);
116bool dsos__read_build_ids(void); 133bool dsos__read_build_ids(void);
117int build_id__sprintf(u8 *self, int len, char *bf); 134int build_id__sprintf(u8 *self, int len, char *bf);
118 135
119size_t kernel_maps__fprintf(FILE *fp); 136int symbol__init(void);
120 137int perf_session__create_kernel_maps(struct perf_session *self);
121int symbol__init(struct symbol_conf *conf);
122 138
123struct map_groups;
124struct map_groups *kmaps;
125extern struct list_head dsos__user, dsos__kernel; 139extern struct list_head dsos__user, dsos__kernel;
126extern struct dso *vdso; 140extern struct dso *vdso;
127#endif /* __PERF_SYMBOL */ 141#endif /* __PERF_SYMBOL */
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index b68a00ea4121..4a08dcf50b68 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -2,13 +2,11 @@
2#include <stdlib.h> 2#include <stdlib.h>
3#include <stdio.h> 3#include <stdio.h>
4#include <string.h> 4#include <string.h>
5#include "session.h"
5#include "thread.h" 6#include "thread.h"
6#include "util.h" 7#include "util.h"
7#include "debug.h" 8#include "debug.h"
8 9
9static struct rb_root threads;
10static struct thread *last_match;
11
12void map_groups__init(struct map_groups *self) 10void map_groups__init(struct map_groups *self)
13{ 11{
14 int i; 12 int i;
@@ -122,9 +120,9 @@ static size_t thread__fprintf(struct thread *self, FILE *fp)
122 map_groups__fprintf(&self->mg, fp); 120 map_groups__fprintf(&self->mg, fp);
123} 121}
124 122
125struct thread *threads__findnew(pid_t pid) 123struct thread *perf_session__findnew(struct perf_session *self, pid_t pid)
126{ 124{
127 struct rb_node **p = &threads.rb_node; 125 struct rb_node **p = &self->threads.rb_node;
128 struct rb_node *parent = NULL; 126 struct rb_node *parent = NULL;
129 struct thread *th; 127 struct thread *th;
130 128
@@ -133,15 +131,15 @@ struct thread *threads__findnew(pid_t pid)
133 * so most of the time we dont have to look up 131 * so most of the time we dont have to look up
134 * the full rbtree: 132 * the full rbtree:
135 */ 133 */
136 if (last_match && last_match->pid == pid) 134 if (self->last_match && self->last_match->pid == pid)
137 return last_match; 135 return self->last_match;
138 136
139 while (*p != NULL) { 137 while (*p != NULL) {
140 parent = *p; 138 parent = *p;
141 th = rb_entry(parent, struct thread, rb_node); 139 th = rb_entry(parent, struct thread, rb_node);
142 140
143 if (th->pid == pid) { 141 if (th->pid == pid) {
144 last_match = th; 142 self->last_match = th;
145 return th; 143 return th;
146 } 144 }
147 145
@@ -154,25 +152,13 @@ struct thread *threads__findnew(pid_t pid)
154 th = thread__new(pid); 152 th = thread__new(pid);
155 if (th != NULL) { 153 if (th != NULL) {
156 rb_link_node(&th->rb_node, parent, p); 154 rb_link_node(&th->rb_node, parent, p);
157 rb_insert_color(&th->rb_node, &threads); 155 rb_insert_color(&th->rb_node, &self->threads);
158 last_match = th; 156 self->last_match = th;
159 } 157 }
160 158
161 return th; 159 return th;
162} 160}
163 161
164struct thread *register_idle_thread(void)
165{
166 struct thread *thread = threads__findnew(0);
167
168 if (!thread || thread__set_comm(thread, "swapper")) {
169 fprintf(stderr, "problem inserting idle task.\n");
170 exit(-1);
171 }
172
173 return thread;
174}
175
176static void map_groups__remove_overlappings(struct map_groups *self, 162static void map_groups__remove_overlappings(struct map_groups *self,
177 struct map *map) 163 struct map *map)
178{ 164{
@@ -281,12 +267,12 @@ int thread__fork(struct thread *self, struct thread *parent)
281 return 0; 267 return 0;
282} 268}
283 269
284size_t threads__fprintf(FILE *fp) 270size_t perf_session__fprintf(struct perf_session *self, FILE *fp)
285{ 271{
286 size_t ret = 0; 272 size_t ret = 0;
287 struct rb_node *nd; 273 struct rb_node *nd;
288 274
289 for (nd = rb_first(&threads); nd; nd = rb_next(nd)) { 275 for (nd = rb_first(&self->threads); nd; nd = rb_next(nd)) {
290 struct thread *pos = rb_entry(nd, struct thread, rb_node); 276 struct thread *pos = rb_entry(nd, struct thread, rb_node);
291 277
292 ret += thread__fprintf(pos, fp); 278 ret += thread__fprintf(pos, fp);
@@ -296,13 +282,14 @@ size_t threads__fprintf(FILE *fp)
296} 282}
297 283
298struct symbol *map_groups__find_symbol(struct map_groups *self, 284struct symbol *map_groups__find_symbol(struct map_groups *self,
285 struct perf_session *session,
299 enum map_type type, u64 addr, 286 enum map_type type, u64 addr,
300 symbol_filter_t filter) 287 symbol_filter_t filter)
301{ 288{
302 struct map *map = map_groups__find(self, type, addr); 289 struct map *map = map_groups__find(self, type, addr);
303 290
304 if (map != NULL) 291 if (map != NULL)
305 return map__find_symbol(map, map->map_ip(map, addr), filter); 292 return map__find_symbol(map, session, map->map_ip(map, addr), filter);
306 293
307 return NULL; 294 return NULL;
308} 295}
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 1751802a09ba..c206f72c8881 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -8,7 +8,6 @@
8struct map_groups { 8struct map_groups {
9 struct rb_root maps[MAP__NR_TYPES]; 9 struct rb_root maps[MAP__NR_TYPES];
10 struct list_head removed_maps[MAP__NR_TYPES]; 10 struct list_head removed_maps[MAP__NR_TYPES];
11 bool use_modules;
12}; 11};
13 12
14struct thread { 13struct thread {
@@ -23,12 +22,11 @@ struct thread {
23void map_groups__init(struct map_groups *self); 22void map_groups__init(struct map_groups *self);
24int thread__set_comm(struct thread *self, const char *comm); 23int thread__set_comm(struct thread *self, const char *comm);
25int thread__comm_len(struct thread *self); 24int thread__comm_len(struct thread *self);
26struct thread *threads__findnew(pid_t pid); 25struct thread *perf_session__findnew(struct perf_session *self, pid_t pid);
27struct thread *register_idle_thread(void);
28void thread__insert_map(struct thread *self, struct map *map); 26void thread__insert_map(struct thread *self, struct map *map);
29int thread__fork(struct thread *self, struct thread *parent); 27int thread__fork(struct thread *self, struct thread *parent);
30size_t map_groups__fprintf_maps(struct map_groups *self, FILE *fp); 28size_t map_groups__fprintf_maps(struct map_groups *self, FILE *fp);
31size_t threads__fprintf(FILE *fp); 29size_t perf_session__fprintf(struct perf_session *self, FILE *fp);
32 30
33void maps__insert(struct rb_root *maps, struct map *map); 31void maps__insert(struct rb_root *maps, struct map *map);
34struct map *maps__find(struct rb_root *maps, u64 addr); 32struct map *maps__find(struct rb_root *maps, u64 addr);
@@ -50,19 +48,21 @@ static inline struct map *thread__find_map(struct thread *self,
50 return self ? map_groups__find(&self->mg, type, addr) : NULL; 48 return self ? map_groups__find(&self->mg, type, addr) : NULL;
51} 49}
52 50
53void thread__find_addr_location(struct thread *self, u8 cpumode, 51void thread__find_addr_location(struct thread *self,
52 struct perf_session *session, u8 cpumode,
54 enum map_type type, u64 addr, 53 enum map_type type, u64 addr,
55 struct addr_location *al, 54 struct addr_location *al,
56 symbol_filter_t filter); 55 symbol_filter_t filter);
57struct symbol *map_groups__find_symbol(struct map_groups *self, 56struct symbol *map_groups__find_symbol(struct map_groups *self,
57 struct perf_session *session,
58 enum map_type type, u64 addr, 58 enum map_type type, u64 addr,
59 symbol_filter_t filter); 59 symbol_filter_t filter);
60 60
61static inline struct symbol * 61static inline struct symbol *
62map_groups__find_function(struct map_groups *self, u64 addr, 62map_groups__find_function(struct map_groups *self, struct perf_session *session,
63 symbol_filter_t filter) 63 u64 addr, symbol_filter_t filter)
64{ 64{
65 return map_groups__find_symbol(self, MAP__FUNCTION, addr, filter); 65 return map_groups__find_symbol(self, session, MAP__FUNCTION, addr, filter);
66} 66}
67 67
68struct map *map_groups__find_by_name(struct map_groups *self, 68struct map *map_groups__find_by_name(struct map_groups *self,
diff --git a/tools/perf/util/trace-event-perl.c b/tools/perf/util/trace-event-perl.c
index a5ffe60db5d6..6d6d76b8a21e 100644
--- a/tools/perf/util/trace-event-perl.c
+++ b/tools/perf/util/trace-event-perl.c
@@ -267,7 +267,7 @@ int common_lock_depth(struct scripting_context *context)
267} 267}
268 268
269static void perl_process_event(int cpu, void *data, 269static void perl_process_event(int cpu, void *data,
270 int size __attribute((unused)), 270 int size __unused,
271 unsigned long long nsecs, char *comm) 271 unsigned long long nsecs, char *comm)
272{ 272{
273 struct format_field *field; 273 struct format_field *field;
@@ -359,28 +359,46 @@ static void run_start_sub(void)
359/* 359/*
360 * Start trace script 360 * Start trace script
361 */ 361 */
362static int perl_start_script(const char *script) 362static int perl_start_script(const char *script, int argc, const char **argv)
363{ 363{
364 const char *command_line[2] = { "", NULL }; 364 const char **command_line;
365 int i, err = 0;
365 366
367 command_line = malloc((argc + 2) * sizeof(const char *));
368 command_line[0] = "";
366 command_line[1] = script; 369 command_line[1] = script;
370 for (i = 2; i < argc + 2; i++)
371 command_line[i] = argv[i - 2];
367 372
368 my_perl = perl_alloc(); 373 my_perl = perl_alloc();
369 perl_construct(my_perl); 374 perl_construct(my_perl);
370 375
371 if (perl_parse(my_perl, xs_init, 2, (char **)command_line, 376 if (perl_parse(my_perl, xs_init, argc + 2, (char **)command_line,
372 (char **)NULL)) 377 (char **)NULL)) {
373 return -1; 378 err = -1;
379 goto error;
380 }
374 381
375 perl_run(my_perl); 382 if (perl_run(my_perl)) {
376 if (SvTRUE(ERRSV)) 383 err = -1;
377 return -1; 384 goto error;
385 }
386
387 if (SvTRUE(ERRSV)) {
388 err = -1;
389 goto error;
390 }
378 391
379 run_start_sub(); 392 run_start_sub();
380 393
394 free(command_line);
381 fprintf(stderr, "perf trace started with Perl script %s\n\n", script); 395 fprintf(stderr, "perf trace started with Perl script %s\n\n", script);
382
383 return 0; 396 return 0;
397error:
398 perl_free(my_perl);
399 free(command_line);
400
401 return err;
384} 402}
385 403
386/* 404/*
@@ -579,7 +597,9 @@ static void print_unsupported_msg(void)
579 "\n etc.\n"); 597 "\n etc.\n");
580} 598}
581 599
582static int perl_start_script_unsupported(const char *script __unused) 600static int perl_start_script_unsupported(const char *script __unused,
601 int argc __unused,
602 const char **argv __unused)
583{ 603{
584 print_unsupported_msg(); 604 print_unsupported_msg();
585 605
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index 81698d5e6503..6ad405620c9b 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -270,7 +270,7 @@ enum trace_flag_type {
270 270
271struct scripting_ops { 271struct scripting_ops {
272 const char *name; 272 const char *name;
273 int (*start_script) (const char *); 273 int (*start_script) (const char *script, int argc, const char **argv);
274 int (*stop_script) (void); 274 int (*stop_script) (void);
275 void (*process_event) (int cpu, void *data, int size, 275 void (*process_event) (int cpu, void *data, int size,
276 unsigned long long nsecs, char *comm); 276 unsigned long long nsecs, char *comm);