aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2013-10-23 03:45:50 -0400
committerIngo Molnar <mingo@kernel.org>2013-10-23 03:45:50 -0400
commitaa30a2e03a453aad9fd96c3f2d4a82c3497674e5 (patch)
treea92563031fdb2ebec7f7866d0707df38174214ec /tools
parent9536c8d2da8059b00775bd9c5a84816b608cf6f4 (diff)
parent5dbb6e81d85e55ee2b4cf523c1738e16f63e5400 (diff)
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo: * Convert callchain children list to rbtree, greatly reducing the time taken for callchain processing, from Namhyung Kim. * Add --max-stack option to limit callchain stack scan in 'top' and 'report', improving callchain processing when reducing the stack depth is an option, from Waiman Long. * Compare dso's also when comparing symbols, to avoid grouping together symbols with the same name but on different DSOs, fix from Namhyung Kim. * 'perf trace' now can can use a 'perf probe' wannabe tracepoint to hook into the userspace -> kernel pathname copy so that it can map fds to pathnames without reading /proc/pid/fd/ symlinks. From Arnaldo Carvalho de Melo. * 'perf trace' now emits hints as to why tracing is not possible, helping the user to setup the system to allow tracing in the desired permission granularity, telling if the problem is due to debugfs not being mounted or with not enough permission for !root, /proc/sys/kernel/perf_event_paranoit value, etc. From Arnaldo Carvalho de Melo. * Add missing 'mmap2' in evsel debug print, from Adrian Hunter. * Add missing decrement in id sample parsing, not a fix per se, just to avoid a problem whem somebody adds another field, from Adrian Hunter. * Improve write_output error message in 'perf record', from Adrian Hunter. * Add missing sample flush for piped events, fix from Adrian Hunter. * Add missing members to perf_event__attr_swap(), fix from Adrian Hunter. * Assorted fixes for 32-bit build, from Adrian Hunter * Print addr by default for BTS in 'perf script', from Adrian Juntmer * Separating data file properties from session, code reorganization from Jiri Olsa. * Show error in 'perf list' if tracepoints not available, from Pekka Enberg. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/Documentation/perf-report.txt8
-rw-r--r--tools/perf/Documentation/perf-top.txt8
-rw-r--r--tools/perf/Documentation/perf-trace.txt4
-rw-r--r--tools/perf/Makefile.perf1
-rw-r--r--tools/perf/bench/numa.c4
-rw-r--r--tools/perf/builtin-annotate.c11
-rw-r--r--tools/perf/builtin-buildid-cache.c8
-rw-r--r--tools/perf/builtin-buildid-list.c11
-rw-r--r--tools/perf/builtin-diff.c19
-rw-r--r--tools/perf/builtin-evlist.c7
-rw-r--r--tools/perf/builtin-inject.c7
-rw-r--r--tools/perf/builtin-kmem.c7
-rw-r--r--tools/perf/builtin-kvm.c13
-rw-r--r--tools/perf/builtin-lock.c7
-rw-r--r--tools/perf/builtin-mem.c9
-rw-r--r--tools/perf/builtin-record.c80
-rw-r--r--tools/perf/builtin-report.c40
-rw-r--r--tools/perf/builtin-sched.c6
-rw-r--r--tools/perf/builtin-script.c21
-rw-r--r--tools/perf/builtin-timechart.c10
-rw-r--r--tools/perf/builtin-top.c16
-rw-r--r--tools/perf/builtin-trace.c196
-rw-r--r--tools/perf/config/feature-checks/test-on-exit.c1
-rw-r--r--tools/perf/perf.h1
-rw-r--r--tools/perf/util/callchain.c147
-rw-r--r--tools/perf/util/callchain.h11
-rw-r--r--tools/perf/util/data.c120
-rw-r--r--tools/perf/util/data.h48
-rw-r--r--tools/perf/util/evlist.c159
-rw-r--r--tools/perf/util/evlist.h3
-rw-r--r--tools/perf/util/evsel.c2
-rw-r--r--tools/perf/util/header.c22
-rw-r--r--tools/perf/util/machine.c14
-rw-r--r--tools/perf/util/machine.h3
-rw-r--r--tools/perf/util/parse-events.c4
-rw-r--r--tools/perf/util/scripting-engines/trace-event-perl.c2
-rw-r--r--tools/perf/util/session.c139
-rw-r--r--tools/perf/util/session.h11
-rw-r--r--tools/perf/util/sort.c10
-rw-r--r--tools/perf/util/top.h1
-rw-r--r--tools/perf/util/util.c17
-rw-r--r--tools/perf/util/util.h2
42 files changed, 834 insertions, 376 deletions
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index be5ad87b6c3d..10a279871251 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -141,6 +141,14 @@ OPTIONS
141 141
142 Default: fractal,0.5,callee,function. 142 Default: fractal,0.5,callee,function.
143 143
144--max-stack::
145 Set the stack depth limit when parsing the callchain, anything
146 beyond the specified depth will be ignored. This is a trade-off
147 between information loss and faster processing especially for
148 workloads that can have a very long callchain stack.
149
150 Default: 127
151
144-G:: 152-G::
145--inverted:: 153--inverted::
146 alias for inverted caller based call graph. 154 alias for inverted caller based call graph.
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt
index f65777c1f723..c16a09e2f182 100644
--- a/tools/perf/Documentation/perf-top.txt
+++ b/tools/perf/Documentation/perf-top.txt
@@ -158,6 +158,14 @@ Default is to monitor all CPUS.
158 158
159 Default: fractal,0.5,callee. 159 Default: fractal,0.5,callee.
160 160
161--max-stack::
162 Set the stack depth limit when parsing the callchain, anything
163 beyond the specified depth will be ignored. This is a trade-off
164 between information loss and faster processing especially for
165 workloads that can have a very long callchain stack.
166
167 Default: 127
168
161--ignore-callees=<regex>:: 169--ignore-callees=<regex>::
162 Ignore callees of the function(s) matching the given regex. 170 Ignore callees of the function(s) matching the given regex.
163 This has the effect of collecting the callers of each such 171 This has the effect of collecting the callers of each such
diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt
index 54139c6457f8..7b0497f95a75 100644
--- a/tools/perf/Documentation/perf-trace.txt
+++ b/tools/perf/Documentation/perf-trace.txt
@@ -97,6 +97,10 @@ the thread executes on the designated CPUs. Default is to monitor all CPUs.
97 Show a summary of syscalls by thread with min, max, and average times (in 97 Show a summary of syscalls by thread with min, max, and average times (in
98 msec) and relative stddev. 98 msec) and relative stddev.
99 99
100--tool_stats::
101 Show tool stats such as number of times fd->pathname was discovered thru
102 hooking the open syscall return + vfs_getname or via reading /proc/pid/fd, etc.
103
100SEE ALSO 104SEE ALSO
101-------- 105--------
102linkperf:perf-record[1], linkperf:perf-script[1] 106linkperf:perf-record[1], linkperf:perf-script[1]
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index c873e039aafb..326a26e5fc1c 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -365,6 +365,7 @@ LIB_OBJS += $(OUTPUT)util/vdso.o
365LIB_OBJS += $(OUTPUT)util/stat.o 365LIB_OBJS += $(OUTPUT)util/stat.o
366LIB_OBJS += $(OUTPUT)util/record.o 366LIB_OBJS += $(OUTPUT)util/record.o
367LIB_OBJS += $(OUTPUT)util/srcline.o 367LIB_OBJS += $(OUTPUT)util/srcline.o
368LIB_OBJS += $(OUTPUT)util/data.o
368 369
369LIB_OBJS += $(OUTPUT)ui/setup.o 370LIB_OBJS += $(OUTPUT)ui/setup.o
370LIB_OBJS += $(OUTPUT)ui/helpline.o 371LIB_OBJS += $(OUTPUT)ui/helpline.o
diff --git a/tools/perf/bench/numa.c b/tools/perf/bench/numa.c
index 64fa01cfc34d..d4c83c60b9b2 100644
--- a/tools/perf/bench/numa.c
+++ b/tools/perf/bench/numa.c
@@ -1120,7 +1120,7 @@ static void *worker_thread(void *__tdata)
1120 /* Check whether our max runtime timed out: */ 1120 /* Check whether our max runtime timed out: */
1121 if (g->p.nr_secs) { 1121 if (g->p.nr_secs) {
1122 timersub(&stop, &start0, &diff); 1122 timersub(&stop, &start0, &diff);
1123 if (diff.tv_sec >= g->p.nr_secs) { 1123 if ((u32)diff.tv_sec >= g->p.nr_secs) {
1124 g->stop_work = true; 1124 g->stop_work = true;
1125 break; 1125 break;
1126 } 1126 }
@@ -1167,7 +1167,7 @@ static void *worker_thread(void *__tdata)
1167 runtime_ns_max += diff.tv_usec * 1000; 1167 runtime_ns_max += diff.tv_usec * 1000;
1168 1168
1169 if (details >= 0) { 1169 if (details >= 0) {
1170 printf(" #%2d / %2d: %14.2lf nsecs/op [val: %016lx]\n", 1170 printf(" #%2d / %2d: %14.2lf nsecs/op [val: %016"PRIx64"]\n",
1171 process_nr, thread_nr, runtime_ns_max / bytes_done, val); 1171 process_nr, thread_nr, runtime_ns_max / bytes_done, val);
1172 } 1172 }
1173 fflush(stdout); 1173 fflush(stdout);
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 94f9a8e78117..03cfa592071f 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -28,6 +28,7 @@
28#include "util/hist.h" 28#include "util/hist.h"
29#include "util/session.h" 29#include "util/session.h"
30#include "util/tool.h" 30#include "util/tool.h"
31#include "util/data.h"
31#include "arch/common.h" 32#include "arch/common.h"
32 33
33#include <dlfcn.h> 34#include <dlfcn.h>
@@ -199,9 +200,13 @@ static int __cmd_annotate(struct perf_annotate *ann)
199 struct perf_session *session; 200 struct perf_session *session;
200 struct perf_evsel *pos; 201 struct perf_evsel *pos;
201 u64 total_nr_samples; 202 u64 total_nr_samples;
203 struct perf_data_file file = {
204 .path = input_name,
205 .mode = PERF_DATA_MODE_READ,
206 .force = ann->force,
207 };
202 208
203 session = perf_session__new(input_name, O_RDONLY, 209 session = perf_session__new(&file, false, &ann->tool);
204 ann->force, false, &ann->tool);
205 if (session == NULL) 210 if (session == NULL)
206 return -ENOMEM; 211 return -ENOMEM;
207 212
@@ -254,7 +259,7 @@ static int __cmd_annotate(struct perf_annotate *ann)
254 } 259 }
255 260
256 if (total_nr_samples == 0) { 261 if (total_nr_samples == 0) {
257 ui__error("The %s file has no samples!\n", session->filename); 262 ui__error("The %s file has no samples!\n", file.path);
258 goto out_delete; 263 goto out_delete;
259 } 264 }
260 265
diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c
index 8140b7b249fa..cfede86161d8 100644
--- a/tools/perf/builtin-buildid-cache.c
+++ b/tools/perf/builtin-buildid-cache.c
@@ -221,8 +221,12 @@ static bool dso__missing_buildid_cache(struct dso *dso, int parm __maybe_unused)
221 221
222static int build_id_cache__fprintf_missing(const char *filename, bool force, FILE *fp) 222static int build_id_cache__fprintf_missing(const char *filename, bool force, FILE *fp)
223{ 223{
224 struct perf_session *session = perf_session__new(filename, O_RDONLY, 224 struct perf_data_file file = {
225 force, false, NULL); 225 .path = filename,
226 .mode = PERF_DATA_MODE_READ,
227 .force = force,
228 };
229 struct perf_session *session = perf_session__new(&file, false, NULL);
226 if (session == NULL) 230 if (session == NULL)
227 return -1; 231 return -1;
228 232
diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c
index e74366a13218..ed3873b3e238 100644
--- a/tools/perf/builtin-buildid-list.c
+++ b/tools/perf/builtin-buildid-list.c
@@ -15,6 +15,7 @@
15#include "util/parse-options.h" 15#include "util/parse-options.h"
16#include "util/session.h" 16#include "util/session.h"
17#include "util/symbol.h" 17#include "util/symbol.h"
18#include "util/data.h"
18 19
19static int sysfs__fprintf_build_id(FILE *fp) 20static int sysfs__fprintf_build_id(FILE *fp)
20{ 21{
@@ -52,6 +53,11 @@ static bool dso__skip_buildid(struct dso *dso, int with_hits)
52static int perf_session__list_build_ids(bool force, bool with_hits) 53static int perf_session__list_build_ids(bool force, bool with_hits)
53{ 54{
54 struct perf_session *session; 55 struct perf_session *session;
56 struct perf_data_file file = {
57 .path = input_name,
58 .mode = PERF_DATA_MODE_READ,
59 .force = force,
60 };
55 61
56 symbol__elf_init(); 62 symbol__elf_init();
57 /* 63 /*
@@ -60,15 +66,14 @@ static int perf_session__list_build_ids(bool force, bool with_hits)
60 if (filename__fprintf_build_id(input_name, stdout)) 66 if (filename__fprintf_build_id(input_name, stdout))
61 goto out; 67 goto out;
62 68
63 session = perf_session__new(input_name, O_RDONLY, force, false, 69 session = perf_session__new(&file, false, &build_id__mark_dso_hit_ops);
64 &build_id__mark_dso_hit_ops);
65 if (session == NULL) 70 if (session == NULL)
66 return -1; 71 return -1;
67 /* 72 /*
68 * in pipe-mode, the only way to get the buildids is to parse 73 * in pipe-mode, the only way to get the buildids is to parse
69 * the record stream. Buildids are stored as RECORD_HEADER_BUILD_ID 74 * the record stream. Buildids are stored as RECORD_HEADER_BUILD_ID
70 */ 75 */
71 if (with_hits || session->fd_pipe) 76 if (with_hits || perf_data_file__is_pipe(&file))
72 perf_session__process_events(session, &build_id__mark_dso_hit_ops); 77 perf_session__process_events(session, &build_id__mark_dso_hit_ops);
73 78
74 perf_session__fprintf_dsos_buildid(session, stdout, dso__skip_buildid, with_hits); 79 perf_session__fprintf_dsos_buildid(session, stdout, dso__skip_buildid, with_hits);
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index 2a78dc806c39..419d27dd708b 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -16,6 +16,7 @@
16#include "util/sort.h" 16#include "util/sort.h"
17#include "util/symbol.h" 17#include "util/symbol.h"
18#include "util/util.h" 18#include "util/util.h"
19#include "util/data.h"
19 20
20#include <stdlib.h> 21#include <stdlib.h>
21#include <math.h> 22#include <math.h>
@@ -42,7 +43,7 @@ struct diff_hpp_fmt {
42 43
43struct data__file { 44struct data__file {
44 struct perf_session *session; 45 struct perf_session *session;
45 const char *file; 46 struct perf_data_file file;
46 int idx; 47 int idx;
47 struct hists *hists; 48 struct hists *hists;
48 struct diff_hpp_fmt fmt[PERF_HPP_DIFF__MAX_INDEX]; 49 struct diff_hpp_fmt fmt[PERF_HPP_DIFF__MAX_INDEX];
@@ -601,7 +602,7 @@ static void data__fprintf(void)
601 602
602 data__for_each_file(i, d) 603 data__for_each_file(i, d)
603 fprintf(stdout, "# [%d] %s %s\n", 604 fprintf(stdout, "# [%d] %s %s\n",
604 d->idx, d->file, 605 d->idx, d->file.path,
605 !d->idx ? "(Baseline)" : ""); 606 !d->idx ? "(Baseline)" : "");
606 607
607 fprintf(stdout, "#\n"); 608 fprintf(stdout, "#\n");
@@ -663,17 +664,16 @@ static int __cmd_diff(void)
663 int ret = -EINVAL, i; 664 int ret = -EINVAL, i;
664 665
665 data__for_each_file(i, d) { 666 data__for_each_file(i, d) {
666 d->session = perf_session__new(d->file, O_RDONLY, force, 667 d->session = perf_session__new(&d->file, false, &tool);
667 false, &tool);
668 if (!d->session) { 668 if (!d->session) {
669 pr_err("Failed to open %s\n", d->file); 669 pr_err("Failed to open %s\n", d->file.path);
670 ret = -ENOMEM; 670 ret = -ENOMEM;
671 goto out_delete; 671 goto out_delete;
672 } 672 }
673 673
674 ret = perf_session__process_events(d->session, &tool); 674 ret = perf_session__process_events(d->session, &tool);
675 if (ret) { 675 if (ret) {
676 pr_err("Failed to process %s\n", d->file); 676 pr_err("Failed to process %s\n", d->file.path);
677 goto out_delete; 677 goto out_delete;
678 } 678 }
679 679
@@ -1016,7 +1016,12 @@ static int data_init(int argc, const char **argv)
1016 return -ENOMEM; 1016 return -ENOMEM;
1017 1017
1018 data__for_each_file(i, d) { 1018 data__for_each_file(i, d) {
1019 d->file = use_default ? defaults[i] : argv[i]; 1019 struct perf_data_file *file = &d->file;
1020
1021 file->path = use_default ? defaults[i] : argv[i];
1022 file->mode = PERF_DATA_MODE_READ,
1023 file->force = force,
1024
1020 d->idx = i; 1025 d->idx = i;
1021 } 1026 }
1022 1027
diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c
index 05bd9dfe875c..20b0f12763b0 100644
--- a/tools/perf/builtin-evlist.c
+++ b/tools/perf/builtin-evlist.c
@@ -14,13 +14,18 @@
14#include "util/parse-events.h" 14#include "util/parse-events.h"
15#include "util/parse-options.h" 15#include "util/parse-options.h"
16#include "util/session.h" 16#include "util/session.h"
17#include "util/data.h"
17 18
18static int __cmd_evlist(const char *file_name, struct perf_attr_details *details) 19static int __cmd_evlist(const char *file_name, struct perf_attr_details *details)
19{ 20{
20 struct perf_session *session; 21 struct perf_session *session;
21 struct perf_evsel *pos; 22 struct perf_evsel *pos;
23 struct perf_data_file file = {
24 .path = file_name,
25 .mode = PERF_DATA_MODE_READ,
26 };
22 27
23 session = perf_session__new(file_name, O_RDONLY, 0, false, NULL); 28 session = perf_session__new(&file, 0, NULL);
24 if (session == NULL) 29 if (session == NULL)
25 return -ENOMEM; 30 return -ENOMEM;
26 31
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index f51a9637f69b..4aa6d7850bcc 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -15,6 +15,7 @@
15#include "util/tool.h" 15#include "util/tool.h"
16#include "util/debug.h" 16#include "util/debug.h"
17#include "util/build-id.h" 17#include "util/build-id.h"
18#include "util/data.h"
18 19
19#include "util/parse-options.h" 20#include "util/parse-options.h"
20 21
@@ -345,6 +346,10 @@ static int __cmd_inject(struct perf_inject *inject)
345{ 346{
346 struct perf_session *session; 347 struct perf_session *session;
347 int ret = -EINVAL; 348 int ret = -EINVAL;
349 struct perf_data_file file = {
350 .path = inject->input_name,
351 .mode = PERF_DATA_MODE_READ,
352 };
348 353
349 signal(SIGINT, sig_handler); 354 signal(SIGINT, sig_handler);
350 355
@@ -355,7 +360,7 @@ static int __cmd_inject(struct perf_inject *inject)
355 inject->tool.tracing_data = perf_event__repipe_tracing_data; 360 inject->tool.tracing_data = perf_event__repipe_tracing_data;
356 } 361 }
357 362
358 session = perf_session__new(inject->input_name, O_RDONLY, false, true, &inject->tool); 363 session = perf_session__new(&file, true, &inject->tool);
359 if (session == NULL) 364 if (session == NULL)
360 return -ENOMEM; 365 return -ENOMEM;
361 366
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 9b5f077fee5b..1126382659a9 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -13,6 +13,7 @@
13 13
14#include "util/parse-options.h" 14#include "util/parse-options.h"
15#include "util/trace-event.h" 15#include "util/trace-event.h"
16#include "util/data.h"
16 17
17#include "util/debug.h" 18#include "util/debug.h"
18 19
@@ -486,8 +487,12 @@ static int __cmd_kmem(void)
486 { "kmem:kfree", perf_evsel__process_free_event, }, 487 { "kmem:kfree", perf_evsel__process_free_event, },
487 { "kmem:kmem_cache_free", perf_evsel__process_free_event, }, 488 { "kmem:kmem_cache_free", perf_evsel__process_free_event, },
488 }; 489 };
490 struct perf_data_file file = {
491 .path = input_name,
492 .mode = PERF_DATA_MODE_READ,
493 };
489 494
490 session = perf_session__new(input_name, O_RDONLY, 0, false, &perf_kmem); 495 session = perf_session__new(&file, false, &perf_kmem);
491 if (session == NULL) 496 if (session == NULL)
492 return -ENOMEM; 497 return -ENOMEM;
493 498
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
index cfa0b7979914..188bb29b373f 100644
--- a/tools/perf/builtin-kvm.c
+++ b/tools/perf/builtin-kvm.c
@@ -17,6 +17,7 @@
17#include "util/tool.h" 17#include "util/tool.h"
18#include "util/stat.h" 18#include "util/stat.h"
19#include "util/top.h" 19#include "util/top.h"
20#include "util/data.h"
20 21
21#include <sys/prctl.h> 22#include <sys/prctl.h>
22#include <sys/timerfd.h> 23#include <sys/timerfd.h>
@@ -1215,10 +1216,13 @@ static int read_events(struct perf_kvm_stat *kvm)
1215 .comm = perf_event__process_comm, 1216 .comm = perf_event__process_comm,
1216 .ordered_samples = true, 1217 .ordered_samples = true,
1217 }; 1218 };
1219 struct perf_data_file file = {
1220 .path = input_name,
1221 .mode = PERF_DATA_MODE_READ,
1222 };
1218 1223
1219 kvm->tool = eops; 1224 kvm->tool = eops;
1220 kvm->session = perf_session__new(kvm->file_name, O_RDONLY, 0, false, 1225 kvm->session = perf_session__new(&file, false, &kvm->tool);
1221 &kvm->tool);
1222 if (!kvm->session) { 1226 if (!kvm->session) {
1223 pr_err("Initializing perf session failed\n"); 1227 pr_err("Initializing perf session failed\n");
1224 return -EINVAL; 1228 return -EINVAL;
@@ -1450,6 +1454,9 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
1450 "perf kvm stat live [<options>]", 1454 "perf kvm stat live [<options>]",
1451 NULL 1455 NULL
1452 }; 1456 };
1457 struct perf_data_file file = {
1458 .mode = PERF_DATA_MODE_WRITE,
1459 };
1453 1460
1454 1461
1455 /* event handling */ 1462 /* event handling */
@@ -1514,7 +1521,7 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
1514 /* 1521 /*
1515 * perf session 1522 * perf session
1516 */ 1523 */
1517 kvm->session = perf_session__new(NULL, O_WRONLY, false, false, &kvm->tool); 1524 kvm->session = perf_session__new(&file, false, &kvm->tool);
1518 if (kvm->session == NULL) { 1525 if (kvm->session == NULL) {
1519 err = -ENOMEM; 1526 err = -ENOMEM;
1520 goto out; 1527 goto out;
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index 6a9076f165f4..33c7253295b9 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -15,6 +15,7 @@
15#include "util/debug.h" 15#include "util/debug.h"
16#include "util/session.h" 16#include "util/session.h"
17#include "util/tool.h" 17#include "util/tool.h"
18#include "util/data.h"
18 19
19#include <sys/types.h> 20#include <sys/types.h>
20#include <sys/prctl.h> 21#include <sys/prctl.h>
@@ -853,8 +854,12 @@ static int __cmd_report(bool display_info)
853 .comm = perf_event__process_comm, 854 .comm = perf_event__process_comm,
854 .ordered_samples = true, 855 .ordered_samples = true,
855 }; 856 };
857 struct perf_data_file file = {
858 .path = input_name,
859 .mode = PERF_DATA_MODE_READ,
860 };
856 861
857 session = perf_session__new(input_name, O_RDONLY, 0, false, &eops); 862 session = perf_session__new(&file, false, &eops);
858 if (!session) { 863 if (!session) {
859 pr_err("Initializing perf session failed\n"); 864 pr_err("Initializing perf session failed\n");
860 return -ENOMEM; 865 return -ENOMEM;
diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c
index 253133a6251d..31c00f186da1 100644
--- a/tools/perf/builtin-mem.c
+++ b/tools/perf/builtin-mem.c
@@ -5,6 +5,7 @@
5#include "util/trace-event.h" 5#include "util/trace-event.h"
6#include "util/tool.h" 6#include "util/tool.h"
7#include "util/session.h" 7#include "util/session.h"
8#include "util/data.h"
8 9
9#define MEM_OPERATION_LOAD "load" 10#define MEM_OPERATION_LOAD "load"
10#define MEM_OPERATION_STORE "store" 11#define MEM_OPERATION_STORE "store"
@@ -119,10 +120,14 @@ static int process_sample_event(struct perf_tool *tool,
119 120
120static int report_raw_events(struct perf_mem *mem) 121static int report_raw_events(struct perf_mem *mem)
121{ 122{
123 struct perf_data_file file = {
124 .path = input_name,
125 .mode = PERF_DATA_MODE_READ,
126 };
122 int err = -EINVAL; 127 int err = -EINVAL;
123 int ret; 128 int ret;
124 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 129 struct perf_session *session = perf_session__new(&file, false,
125 0, false, &mem->tool); 130 &mem->tool);
126 131
127 if (session == NULL) 132 if (session == NULL)
128 return -ENOMEM; 133 return -ENOMEM;
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 92ca5419073b..ab8d15e6e8cc 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -24,6 +24,7 @@
24#include "util/symbol.h" 24#include "util/symbol.h"
25#include "util/cpumap.h" 25#include "util/cpumap.h"
26#include "util/thread_map.h" 26#include "util/thread_map.h"
27#include "util/data.h"
27 28
28#include <unistd.h> 29#include <unistd.h>
29#include <sched.h> 30#include <sched.h>
@@ -65,11 +66,10 @@ struct perf_record {
65 struct perf_tool tool; 66 struct perf_tool tool;
66 struct perf_record_opts opts; 67 struct perf_record_opts opts;
67 u64 bytes_written; 68 u64 bytes_written;
68 const char *output_name; 69 struct perf_data_file file;
69 struct perf_evlist *evlist; 70 struct perf_evlist *evlist;
70 struct perf_session *session; 71 struct perf_session *session;
71 const char *progname; 72 const char *progname;
72 int output;
73 int realtime_prio; 73 int realtime_prio;
74 bool no_buildid; 74 bool no_buildid;
75 bool no_buildid_cache; 75 bool no_buildid_cache;
@@ -84,11 +84,13 @@ static void advance_output(struct perf_record *rec, size_t size)
84 84
85static int write_output(struct perf_record *rec, void *buf, size_t size) 85static int write_output(struct perf_record *rec, void *buf, size_t size)
86{ 86{
87 struct perf_data_file *file = &rec->file;
88
87 while (size) { 89 while (size) {
88 int ret = write(rec->output, buf, size); 90 int ret = write(file->fd, buf, size);
89 91
90 if (ret < 0) { 92 if (ret < 0) {
91 pr_err("failed to write\n"); 93 pr_err("failed to write perf data, error: %m\n");
92 return -1; 94 return -1;
93 } 95 }
94 96
@@ -248,13 +250,14 @@ out:
248 250
249static int process_buildids(struct perf_record *rec) 251static int process_buildids(struct perf_record *rec)
250{ 252{
251 u64 size = lseek(rec->output, 0, SEEK_CUR); 253 struct perf_data_file *file = &rec->file;
254 struct perf_session *session = rec->session;
252 255
256 u64 size = lseek(file->fd, 0, SEEK_CUR);
253 if (size == 0) 257 if (size == 0)
254 return 0; 258 return 0;
255 259
256 rec->session->fd = rec->output; 260 return __perf_session__process_events(session, rec->post_processing_offset,
257 return __perf_session__process_events(rec->session, rec->post_processing_offset,
258 size - rec->post_processing_offset, 261 size - rec->post_processing_offset,
259 size, &build_id__mark_dso_hit_ops); 262 size, &build_id__mark_dso_hit_ops);
260} 263}
@@ -262,17 +265,18 @@ static int process_buildids(struct perf_record *rec)
262static void perf_record__exit(int status, void *arg) 265static void perf_record__exit(int status, void *arg)
263{ 266{
264 struct perf_record *rec = arg; 267 struct perf_record *rec = arg;
268 struct perf_data_file *file = &rec->file;
265 269
266 if (status != 0) 270 if (status != 0)
267 return; 271 return;
268 272
269 if (!rec->opts.pipe_output) { 273 if (!file->is_pipe) {
270 rec->session->header.data_size += rec->bytes_written; 274 rec->session->header.data_size += rec->bytes_written;
271 275
272 if (!rec->no_buildid) 276 if (!rec->no_buildid)
273 process_buildids(rec); 277 process_buildids(rec);
274 perf_session__write_header(rec->session, rec->evlist, 278 perf_session__write_header(rec->session, rec->evlist,
275 rec->output, true); 279 file->fd, true);
276 perf_session__delete(rec->session); 280 perf_session__delete(rec->session);
277 perf_evlist__delete(rec->evlist); 281 perf_evlist__delete(rec->evlist);
278 symbol__exit(); 282 symbol__exit();
@@ -340,16 +344,14 @@ out:
340 344
341static int __cmd_record(struct perf_record *rec, int argc, const char **argv) 345static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
342{ 346{
343 struct stat st; 347 int err, feat;
344 int flags;
345 int err, output, feat;
346 unsigned long waking = 0; 348 unsigned long waking = 0;
347 const bool forks = argc > 0; 349 const bool forks = argc > 0;
348 struct machine *machine; 350 struct machine *machine;
349 struct perf_tool *tool = &rec->tool; 351 struct perf_tool *tool = &rec->tool;
350 struct perf_record_opts *opts = &rec->opts; 352 struct perf_record_opts *opts = &rec->opts;
351 struct perf_evlist *evsel_list = rec->evlist; 353 struct perf_evlist *evsel_list = rec->evlist;
352 const char *output_name = rec->output_name; 354 struct perf_data_file *file = &rec->file;
353 struct perf_session *session; 355 struct perf_session *session;
354 bool disabled = false; 356 bool disabled = false;
355 357
@@ -361,39 +363,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
361 signal(SIGUSR1, sig_handler); 363 signal(SIGUSR1, sig_handler);
362 signal(SIGTERM, sig_handler); 364 signal(SIGTERM, sig_handler);
363 365
364 if (!output_name) { 366 session = perf_session__new(file, false, NULL);
365 if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode))
366 opts->pipe_output = true;
367 else
368 rec->output_name = output_name = "perf.data";
369 }
370 if (output_name) {
371 if (!strcmp(output_name, "-"))
372 opts->pipe_output = true;
373 else if (!stat(output_name, &st) && st.st_size) {
374 char oldname[PATH_MAX];
375 snprintf(oldname, sizeof(oldname), "%s.old",
376 output_name);
377 unlink(oldname);
378 rename(output_name, oldname);
379 }
380 }
381
382 flags = O_CREAT|O_RDWR|O_TRUNC;
383
384 if (opts->pipe_output)
385 output = STDOUT_FILENO;
386 else
387 output = open(output_name, flags, S_IRUSR | S_IWUSR);
388 if (output < 0) {
389 perror("failed to create output file");
390 return -1;
391 }
392
393 rec->output = output;
394
395 session = perf_session__new(output_name, O_WRONLY,
396 true, false, NULL);
397 if (session == NULL) { 367 if (session == NULL) {
398 pr_err("Not enough memory for reading perf file header\n"); 368 pr_err("Not enough memory for reading perf file header\n");
399 return -1; 369 return -1;
@@ -415,7 +385,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
415 385
416 if (forks) { 386 if (forks) {
417 err = perf_evlist__prepare_workload(evsel_list, &opts->target, 387 err = perf_evlist__prepare_workload(evsel_list, &opts->target,
418 argv, opts->pipe_output, 388 argv, file->is_pipe,
419 true); 389 true);
420 if (err < 0) { 390 if (err < 0) {
421 pr_err("Couldn't run the workload!\n"); 391 pr_err("Couldn't run the workload!\n");
@@ -436,13 +406,13 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
436 */ 406 */
437 on_exit(perf_record__exit, rec); 407 on_exit(perf_record__exit, rec);
438 408
439 if (opts->pipe_output) { 409 if (file->is_pipe) {
440 err = perf_header__write_pipe(output); 410 err = perf_header__write_pipe(file->fd);
441 if (err < 0) 411 if (err < 0)
442 goto out_delete_session; 412 goto out_delete_session;
443 } else { 413 } else {
444 err = perf_session__write_header(session, evsel_list, 414 err = perf_session__write_header(session, evsel_list,
445 output, false); 415 file->fd, false);
446 if (err < 0) 416 if (err < 0)
447 goto out_delete_session; 417 goto out_delete_session;
448 } 418 }
@@ -455,11 +425,11 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
455 goto out_delete_session; 425 goto out_delete_session;
456 } 426 }
457 427
458 rec->post_processing_offset = lseek(output, 0, SEEK_CUR); 428 rec->post_processing_offset = lseek(file->fd, 0, SEEK_CUR);
459 429
460 machine = &session->machines.host; 430 machine = &session->machines.host;
461 431
462 if (opts->pipe_output) { 432 if (file->is_pipe) {
463 err = perf_event__synthesize_attrs(tool, session, 433 err = perf_event__synthesize_attrs(tool, session,
464 process_synthesized_event); 434 process_synthesized_event);
465 if (err < 0) { 435 if (err < 0) {
@@ -476,7 +446,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
476 * return this more properly and also 446 * return this more properly and also
477 * propagate errors that now are calling die() 447 * propagate errors that now are calling die()
478 */ 448 */
479 err = perf_event__synthesize_tracing_data(tool, output, evsel_list, 449 err = perf_event__synthesize_tracing_data(tool, file->fd, evsel_list,
480 process_synthesized_event); 450 process_synthesized_event);
481 if (err <= 0) { 451 if (err <= 0) {
482 pr_err("Couldn't record tracing data.\n"); 452 pr_err("Couldn't record tracing data.\n");
@@ -583,7 +553,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
583 fprintf(stderr, 553 fprintf(stderr,
584 "[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n", 554 "[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
585 (double)rec->bytes_written / 1024.0 / 1024.0, 555 (double)rec->bytes_written / 1024.0 / 1024.0,
586 output_name, 556 file->path,
587 rec->bytes_written / 24); 557 rec->bytes_written / 24);
588 558
589 return 0; 559 return 0;
@@ -845,7 +815,7 @@ const struct option record_options[] = {
845 OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu", 815 OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu",
846 "list of cpus to monitor"), 816 "list of cpus to monitor"),
847 OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"), 817 OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
848 OPT_STRING('o', "output", &record.output_name, "file", 818 OPT_STRING('o', "output", &record.file.path, "file",
849 "output file name"), 819 "output file name"),
850 OPT_BOOLEAN('i', "no-inherit", &record.opts.no_inherit, 820 OPT_BOOLEAN('i', "no-inherit", &record.opts.no_inherit,
851 "child tasks do not inherit counters"), 821 "child tasks do not inherit counters"),
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 21b5c2f54c2a..81addcabb356 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -33,6 +33,7 @@
33#include "util/thread.h" 33#include "util/thread.h"
34#include "util/sort.h" 34#include "util/sort.h"
35#include "util/hist.h" 35#include "util/hist.h"
36#include "util/data.h"
36#include "arch/common.h" 37#include "arch/common.h"
37 38
38#include <dlfcn.h> 39#include <dlfcn.h>
@@ -48,6 +49,7 @@ struct perf_report {
48 bool show_threads; 49 bool show_threads;
49 bool inverted_callchain; 50 bool inverted_callchain;
50 bool mem_mode; 51 bool mem_mode;
52 int max_stack;
51 struct perf_read_values show_threads_values; 53 struct perf_read_values show_threads_values;
52 const char *pretty_printing_style; 54 const char *pretty_printing_style;
53 const char *cpu_list; 55 const char *cpu_list;
@@ -89,7 +91,8 @@ static int perf_report__add_mem_hist_entry(struct perf_tool *tool,
89 if ((sort__has_parent || symbol_conf.use_callchain) && 91 if ((sort__has_parent || symbol_conf.use_callchain) &&
90 sample->callchain) { 92 sample->callchain) {
91 err = machine__resolve_callchain(machine, evsel, al->thread, 93 err = machine__resolve_callchain(machine, evsel, al->thread,
92 sample, &parent, al); 94 sample, &parent, al,
95 rep->max_stack);
93 if (err) 96 if (err)
94 return err; 97 return err;
95 } 98 }
@@ -180,7 +183,8 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool,
180 if ((sort__has_parent || symbol_conf.use_callchain) 183 if ((sort__has_parent || symbol_conf.use_callchain)
181 && sample->callchain) { 184 && sample->callchain) {
182 err = machine__resolve_callchain(machine, evsel, al->thread, 185 err = machine__resolve_callchain(machine, evsel, al->thread,
183 sample, &parent, al); 186 sample, &parent, al,
187 rep->max_stack);
184 if (err) 188 if (err)
185 return err; 189 return err;
186 } 190 }
@@ -243,18 +247,21 @@ out:
243 return err; 247 return err;
244} 248}
245 249
246static int perf_evsel__add_hist_entry(struct perf_evsel *evsel, 250static int perf_evsel__add_hist_entry(struct perf_tool *tool,
251 struct perf_evsel *evsel,
247 struct addr_location *al, 252 struct addr_location *al,
248 struct perf_sample *sample, 253 struct perf_sample *sample,
249 struct machine *machine) 254 struct machine *machine)
250{ 255{
256 struct perf_report *rep = container_of(tool, struct perf_report, tool);
251 struct symbol *parent = NULL; 257 struct symbol *parent = NULL;
252 int err = 0; 258 int err = 0;
253 struct hist_entry *he; 259 struct hist_entry *he;
254 260
255 if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) { 261 if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) {
256 err = machine__resolve_callchain(machine, evsel, al->thread, 262 err = machine__resolve_callchain(machine, evsel, al->thread,
257 sample, &parent, al); 263 sample, &parent, al,
264 rep->max_stack);
258 if (err) 265 if (err)
259 return err; 266 return err;
260 } 267 }
@@ -331,7 +338,8 @@ static int process_sample_event(struct perf_tool *tool,
331 if (al.map != NULL) 338 if (al.map != NULL)
332 al.map->dso->hit = 1; 339 al.map->dso->hit = 1;
333 340
334 ret = perf_evsel__add_hist_entry(evsel, &al, sample, machine); 341 ret = perf_evsel__add_hist_entry(tool, evsel, &al, sample,
342 machine);
335 if (ret < 0) 343 if (ret < 0)
336 pr_debug("problem incrementing symbol period, skipping event\n"); 344 pr_debug("problem incrementing symbol period, skipping event\n");
337 } 345 }
@@ -367,8 +375,9 @@ static int perf_report__setup_sample_type(struct perf_report *rep)
367{ 375{
368 struct perf_session *self = rep->session; 376 struct perf_session *self = rep->session;
369 u64 sample_type = perf_evlist__combined_sample_type(self->evlist); 377 u64 sample_type = perf_evlist__combined_sample_type(self->evlist);
378 bool is_pipe = perf_data_file__is_pipe(self->file);
370 379
371 if (!self->fd_pipe && !(sample_type & PERF_SAMPLE_CALLCHAIN)) { 380 if (!is_pipe && !(sample_type & PERF_SAMPLE_CALLCHAIN)) {
372 if (sort__has_parent) { 381 if (sort__has_parent) {
373 ui__error("Selected --sort parent, but no " 382 ui__error("Selected --sort parent, but no "
374 "callchain data. Did you call " 383 "callchain data. Did you call "
@@ -391,7 +400,7 @@ static int perf_report__setup_sample_type(struct perf_report *rep)
391 } 400 }
392 401
393 if (sort__mode == SORT_MODE__BRANCH) { 402 if (sort__mode == SORT_MODE__BRANCH) {
394 if (!self->fd_pipe && 403 if (!is_pipe &&
395 !(sample_type & PERF_SAMPLE_BRANCH_STACK)) { 404 !(sample_type & PERF_SAMPLE_BRANCH_STACK)) {
396 ui__error("Selected -b but no branch data. " 405 ui__error("Selected -b but no branch data. "
397 "Did you call perf record without -b?\n"); 406 "Did you call perf record without -b?\n");
@@ -487,6 +496,7 @@ static int __cmd_report(struct perf_report *rep)
487 struct map *kernel_map; 496 struct map *kernel_map;
488 struct kmap *kernel_kmap; 497 struct kmap *kernel_kmap;
489 const char *help = "For a higher level overview, try: perf report --sort comm,dso"; 498 const char *help = "For a higher level overview, try: perf report --sort comm,dso";
499 struct perf_data_file *file = session->file;
490 500
491 signal(SIGINT, sig_handler); 501 signal(SIGINT, sig_handler);
492 502
@@ -571,7 +581,7 @@ static int __cmd_report(struct perf_report *rep)
571 return 0; 581 return 0;
572 582
573 if (nr_samples == 0) { 583 if (nr_samples == 0) {
574 ui__error("The %s file has no samples!\n", session->filename); 584 ui__error("The %s file has no samples!\n", file->path);
575 return 0; 585 return 0;
576 } 586 }
577 587
@@ -769,6 +779,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
769 .ordered_samples = true, 779 .ordered_samples = true,
770 .ordering_requires_timestamps = true, 780 .ordering_requires_timestamps = true,
771 }, 781 },
782 .max_stack = PERF_MAX_STACK_DEPTH,
772 .pretty_printing_style = "normal", 783 .pretty_printing_style = "normal",
773 }; 784 };
774 const struct option options[] = { 785 const struct option options[] = {
@@ -809,6 +820,10 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
809 OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent[,print_limit],call_order", 820 OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent[,print_limit],call_order",
810 "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold, optional print limit, callchain order, key (function or address). " 821 "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold, optional print limit, callchain order, key (function or address). "
811 "Default: fractal,0.5,callee,function", &parse_callchain_opt, callchain_default_opt), 822 "Default: fractal,0.5,callee,function", &parse_callchain_opt, callchain_default_opt),
823 OPT_INTEGER(0, "max-stack", &report.max_stack,
824 "Set the maximum stack depth when parsing the callchain, "
825 "anything beyond the specified depth will be ignored. "
826 "Default: " __stringify(PERF_MAX_STACK_DEPTH)),
812 OPT_BOOLEAN('G', "inverted", &report.inverted_callchain, 827 OPT_BOOLEAN('G', "inverted", &report.inverted_callchain,
813 "alias for inverted call graph"), 828 "alias for inverted call graph"),
814 OPT_CALLBACK(0, "ignore-callees", NULL, "regex", 829 OPT_CALLBACK(0, "ignore-callees", NULL, "regex",
@@ -857,6 +872,9 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
857 "Don't show entries under that percent", parse_percent_limit), 872 "Don't show entries under that percent", parse_percent_limit),
858 OPT_END() 873 OPT_END()
859 }; 874 };
875 struct perf_data_file file = {
876 .mode = PERF_DATA_MODE_READ,
877 };
860 878
861 perf_config(perf_report_config, &report); 879 perf_config(perf_report_config, &report);
862 880
@@ -886,9 +904,11 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
886 perf_hpp__init(); 904 perf_hpp__init();
887 } 905 }
888 906
907 file.path = input_name;
908 file.force = report.force;
909
889repeat: 910repeat:
890 session = perf_session__new(input_name, O_RDONLY, 911 session = perf_session__new(&file, false, &report.tool);
891 report.force, false, &report.tool);
892 if (session == NULL) 912 if (session == NULL)
893 return -ENOMEM; 913 return -ENOMEM;
894 914
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index d8c51b2f263f..5a46b102eb08 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -1446,8 +1446,12 @@ static int perf_sched__read_events(struct perf_sched *sched,
1446 { "sched:sched_migrate_task", process_sched_migrate_task_event, }, 1446 { "sched:sched_migrate_task", process_sched_migrate_task_event, },
1447 }; 1447 };
1448 struct perf_session *session; 1448 struct perf_session *session;
1449 struct perf_data_file file = {
1450 .path = input_name,
1451 .mode = PERF_DATA_MODE_READ,
1452 };
1449 1453
1450 session = perf_session__new(input_name, O_RDONLY, 0, false, &sched->tool); 1454 session = perf_session__new(&file, false, &sched->tool);
1451 if (session == NULL) { 1455 if (session == NULL) {
1452 pr_debug("No Memory for session\n"); 1456 pr_debug("No Memory for session\n");
1453 return -1; 1457 return -1;
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 9c333ff3dfeb..27de6068049d 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -15,6 +15,7 @@
15#include "util/evlist.h" 15#include "util/evlist.h"
16#include "util/evsel.h" 16#include "util/evsel.h"
17#include "util/sort.h" 17#include "util/sort.h"
18#include "util/data.h"
18#include <linux/bitmap.h> 19#include <linux/bitmap.h>
19 20
20static char const *script_name; 21static char const *script_name;
@@ -409,7 +410,9 @@ static void print_sample_bts(union perf_event *event,
409 printf(" => "); 410 printf(" => ");
410 411
411 /* print branch_to information */ 412 /* print branch_to information */
412 if (PRINT_FIELD(ADDR)) 413 if (PRINT_FIELD(ADDR) ||
414 ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) &&
415 !output[attr->type].user_set))
413 print_sample_addr(event, sample, machine, thread, attr); 416 print_sample_addr(event, sample, machine, thread, attr);
414 417
415 printf("\n"); 418 printf("\n");
@@ -1113,10 +1116,14 @@ int find_scripts(char **scripts_array, char **scripts_path_array)
1113 char scripts_path[MAXPATHLEN], lang_path[MAXPATHLEN]; 1116 char scripts_path[MAXPATHLEN], lang_path[MAXPATHLEN];
1114 DIR *scripts_dir, *lang_dir; 1117 DIR *scripts_dir, *lang_dir;
1115 struct perf_session *session; 1118 struct perf_session *session;
1119 struct perf_data_file file = {
1120 .path = input_name,
1121 .mode = PERF_DATA_MODE_READ,
1122 };
1116 char *temp; 1123 char *temp;
1117 int i = 0; 1124 int i = 0;
1118 1125
1119 session = perf_session__new(input_name, O_RDONLY, 0, false, NULL); 1126 session = perf_session__new(&file, false, NULL);
1120 if (!session) 1127 if (!session)
1121 return -1; 1128 return -1;
1122 1129
@@ -1317,12 +1324,17 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1317 "perf script [<options>] <top-script> [script-args]", 1324 "perf script [<options>] <top-script> [script-args]",
1318 NULL 1325 NULL
1319 }; 1326 };
1327 struct perf_data_file file = {
1328 .mode = PERF_DATA_MODE_READ,
1329 };
1320 1330
1321 setup_scripting(); 1331 setup_scripting();
1322 1332
1323 argc = parse_options(argc, argv, options, script_usage, 1333 argc = parse_options(argc, argv, options, script_usage,
1324 PARSE_OPT_STOP_AT_NON_OPTION); 1334 PARSE_OPT_STOP_AT_NON_OPTION);
1325 1335
1336 file.path = input_name;
1337
1326 if (argc > 1 && !strncmp(argv[0], "rec", strlen("rec"))) { 1338 if (argc > 1 && !strncmp(argv[0], "rec", strlen("rec"))) {
1327 rec_script_path = get_script_path(argv[1], RECORD_SUFFIX); 1339 rec_script_path = get_script_path(argv[1], RECORD_SUFFIX);
1328 if (!rec_script_path) 1340 if (!rec_script_path)
@@ -1486,8 +1498,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1486 if (!script_name) 1498 if (!script_name)
1487 setup_pager(); 1499 setup_pager();
1488 1500
1489 session = perf_session__new(input_name, O_RDONLY, 0, false, 1501 session = perf_session__new(&file, false, &perf_script);
1490 &perf_script);
1491 if (session == NULL) 1502 if (session == NULL)
1492 return -ENOMEM; 1503 return -ENOMEM;
1493 1504
@@ -1514,7 +1525,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1514 return -1; 1525 return -1;
1515 } 1526 }
1516 1527
1517 input = open(session->filename, O_RDONLY); /* input_name */ 1528 input = open(file.path, O_RDONLY); /* input_name */
1518 if (input < 0) { 1529 if (input < 0) {
1519 perror("failed to open file"); 1530 perror("failed to open file");
1520 return -1; 1531 return -1;
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index c2e02319347a..e11c61d9bda4 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -36,6 +36,7 @@
36#include "util/session.h" 36#include "util/session.h"
37#include "util/svghelper.h" 37#include "util/svghelper.h"
38#include "util/tool.h" 38#include "util/tool.h"
39#include "util/data.h"
39 40
40#define SUPPORT_OLD_POWER_EVENTS 1 41#define SUPPORT_OLD_POWER_EVENTS 1
41#define PWR_EVENT_EXIT -1 42#define PWR_EVENT_EXIT -1
@@ -990,8 +991,13 @@ static int __cmd_timechart(const char *output_name)
990 { "power:power_frequency", process_sample_power_frequency }, 991 { "power:power_frequency", process_sample_power_frequency },
991#endif 992#endif
992 }; 993 };
993 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 994 struct perf_data_file file = {
994 0, false, &perf_timechart); 995 .path = input_name,
996 .mode = PERF_DATA_MODE_READ,
997 };
998
999 struct perf_session *session = perf_session__new(&file, false,
1000 &perf_timechart);
995 int ret = -EINVAL; 1001 int ret = -EINVAL;
996 1002
997 if (session == NULL) 1003 if (session == NULL)
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 65c49b2f51c1..386d83324a8d 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -770,7 +770,8 @@ static void perf_event__process_sample(struct perf_tool *tool,
770 sample->callchain) { 770 sample->callchain) {
771 err = machine__resolve_callchain(machine, evsel, 771 err = machine__resolve_callchain(machine, evsel,
772 al.thread, sample, 772 al.thread, sample,
773 &parent, &al); 773 &parent, &al,
774 top->max_stack);
774 if (err) 775 if (err)
775 return; 776 return;
776 } 777 }
@@ -929,11 +930,8 @@ static int __cmd_top(struct perf_top *top)
929 struct perf_record_opts *opts = &top->record_opts; 930 struct perf_record_opts *opts = &top->record_opts;
930 pthread_t thread; 931 pthread_t thread;
931 int ret; 932 int ret;
932 /* 933
933 * FIXME: perf_session__new should allow passing a O_MMAP, so that all this 934 top->session = perf_session__new(NULL, false, NULL);
934 * mmap reading, etc is encapsulated in it. Use O_WRONLY for now.
935 */
936 top->session = perf_session__new(NULL, O_WRONLY, false, false, NULL);
937 if (top->session == NULL) 935 if (top->session == NULL)
938 return -ENOMEM; 936 return -ENOMEM;
939 937
@@ -1050,10 +1048,11 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1050 .user_freq = UINT_MAX, 1048 .user_freq = UINT_MAX,
1051 .user_interval = ULLONG_MAX, 1049 .user_interval = ULLONG_MAX,
1052 .freq = 4000, /* 4 KHz */ 1050 .freq = 4000, /* 4 KHz */
1053 .target = { 1051 .target = {
1054 .uses_mmap = true, 1052 .uses_mmap = true,
1055 }, 1053 },
1056 }, 1054 },
1055 .max_stack = PERF_MAX_STACK_DEPTH,
1057 .sym_pcnt_filter = 5, 1056 .sym_pcnt_filter = 5,
1058 }; 1057 };
1059 struct perf_record_opts *opts = &top.record_opts; 1058 struct perf_record_opts *opts = &top.record_opts;
@@ -1112,6 +1111,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1112 OPT_CALLBACK_DEFAULT('G', "call-graph", &top.record_opts, 1111 OPT_CALLBACK_DEFAULT('G', "call-graph", &top.record_opts,
1113 "mode[,dump_size]", record_callchain_help, 1112 "mode[,dump_size]", record_callchain_help,
1114 &parse_callchain_opt, "fp"), 1113 &parse_callchain_opt, "fp"),
1114 OPT_INTEGER(0, "max-stack", &top.max_stack,
1115 "Set the maximum stack depth when parsing the callchain. "
1116 "Default: " __stringify(PERF_MAX_STACK_DEPTH)),
1115 OPT_CALLBACK(0, "ignore-callees", NULL, "regex", 1117 OPT_CALLBACK(0, "ignore-callees", NULL, "regex",
1116 "ignore callees of these functions in call graphs", 1118 "ignore callees of these functions in call graphs",
1117 report_parse_ignore_callees_opt), 1119 report_parse_ignore_callees_opt),
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index d0f91fe755a3..fa620bc1db69 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -951,7 +951,10 @@ fail:
951 951
952struct trace { 952struct trace {
953 struct perf_tool tool; 953 struct perf_tool tool;
954 int audit_machine; 954 struct {
955 int machine;
956 int open_id;
957 } audit;
955 struct { 958 struct {
956 int max; 959 int max;
957 struct syscall *table; 960 struct syscall *table;
@@ -965,40 +968,24 @@ struct trace {
965 struct strlist *ev_qualifier; 968 struct strlist *ev_qualifier;
966 bool not_ev_qualifier; 969 bool not_ev_qualifier;
967 bool live; 970 bool live;
971 const char *last_vfs_getname;
968 struct intlist *tid_list; 972 struct intlist *tid_list;
969 struct intlist *pid_list; 973 struct intlist *pid_list;
970 bool sched; 974 bool sched;
971 bool multiple_threads; 975 bool multiple_threads;
972 bool summary; 976 bool summary;
973 bool show_comm; 977 bool show_comm;
978 bool show_tool_stats;
974 double duration_filter; 979 double duration_filter;
975 double runtime_ms; 980 double runtime_ms;
981 struct {
982 u64 vfs_getname, proc_getname;
983 } stats;
976}; 984};
977 985
978static int thread__read_fd_path(struct thread *thread, int fd) 986static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
979{ 987{
980 struct thread_trace *ttrace = thread->priv; 988 struct thread_trace *ttrace = thread->priv;
981 char linkname[PATH_MAX], pathname[PATH_MAX];
982 struct stat st;
983 int ret;
984
985 if (thread->pid_ == thread->tid) {
986 scnprintf(linkname, sizeof(linkname),
987 "/proc/%d/fd/%d", thread->pid_, fd);
988 } else {
989 scnprintf(linkname, sizeof(linkname),
990 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
991 }
992
993 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
994 return -1;
995
996 ret = readlink(linkname, pathname, sizeof(pathname));
997
998 if (ret < 0 || ret > st.st_size)
999 return -1;
1000
1001 pathname[ret] = '\0';
1002 989
1003 if (fd > ttrace->paths.max) { 990 if (fd > ttrace->paths.max) {
1004 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *)); 991 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
@@ -1022,7 +1009,34 @@ static int thread__read_fd_path(struct thread *thread, int fd)
1022 return ttrace->paths.table[fd] != NULL ? 0 : -1; 1009 return ttrace->paths.table[fd] != NULL ? 0 : -1;
1023} 1010}
1024 1011
1025static const char *thread__fd_path(struct thread *thread, int fd, bool live) 1012static int thread__read_fd_path(struct thread *thread, int fd)
1013{
1014 char linkname[PATH_MAX], pathname[PATH_MAX];
1015 struct stat st;
1016 int ret;
1017
1018 if (thread->pid_ == thread->tid) {
1019 scnprintf(linkname, sizeof(linkname),
1020 "/proc/%d/fd/%d", thread->pid_, fd);
1021 } else {
1022 scnprintf(linkname, sizeof(linkname),
1023 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1024 }
1025
1026 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1027 return -1;
1028
1029 ret = readlink(linkname, pathname, sizeof(pathname));
1030
1031 if (ret < 0 || ret > st.st_size)
1032 return -1;
1033
1034 pathname[ret] = '\0';
1035 return trace__set_fd_pathname(thread, fd, pathname);
1036}
1037
1038static const char *thread__fd_path(struct thread *thread, int fd,
1039 struct trace *trace)
1026{ 1040{
1027 struct thread_trace *ttrace = thread->priv; 1041 struct thread_trace *ttrace = thread->priv;
1028 1042
@@ -1032,9 +1046,13 @@ static const char *thread__fd_path(struct thread *thread, int fd, bool live)
1032 if (fd < 0) 1046 if (fd < 0)
1033 return NULL; 1047 return NULL;
1034 1048
1035 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL) && 1049 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL))
1036 (!live || thread__read_fd_path(thread, fd))) 1050 if (!trace->live)
1037 return NULL; 1051 return NULL;
1052 ++trace->stats.proc_getname;
1053 if (thread__read_fd_path(thread, fd)) {
1054 return NULL;
1055 }
1038 1056
1039 return ttrace->paths.table[fd]; 1057 return ttrace->paths.table[fd];
1040} 1058}
@@ -1044,7 +1062,7 @@ static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1044{ 1062{
1045 int fd = arg->val; 1063 int fd = arg->val;
1046 size_t printed = scnprintf(bf, size, "%d", fd); 1064 size_t printed = scnprintf(bf, size, "%d", fd);
1047 const char *path = thread__fd_path(arg->thread, fd, arg->trace->live); 1065 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
1048 1066
1049 if (path) 1067 if (path)
1050 printed += scnprintf(bf + printed, size - printed, "<%s>", path); 1068 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
@@ -1080,10 +1098,12 @@ static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1080} 1098}
1081 1099
1082static bool done = false; 1100static bool done = false;
1101static bool interrupted = false;
1083 1102
1084static void sig_handler(int sig __maybe_unused) 1103static void sig_handler(int sig)
1085{ 1104{
1086 done = true; 1105 done = true;
1106 interrupted = sig == SIGINT;
1087} 1107}
1088 1108
1089static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread, 1109static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
@@ -1181,7 +1201,7 @@ static int trace__read_syscall_info(struct trace *trace, int id)
1181{ 1201{
1182 char tp_name[128]; 1202 char tp_name[128];
1183 struct syscall *sc; 1203 struct syscall *sc;
1184 const char *name = audit_syscall_to_name(id, trace->audit_machine); 1204 const char *name = audit_syscall_to_name(id, trace->audit.machine);
1185 1205
1186 if (name == NULL) 1206 if (name == NULL)
1187 return -1; 1207 return -1;
@@ -1445,6 +1465,12 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
1445 1465
1446 ret = perf_evsel__intval(evsel, sample, "ret"); 1466 ret = perf_evsel__intval(evsel, sample, "ret");
1447 1467
1468 if (id == trace->audit.open_id && ret >= 0 && trace->last_vfs_getname) {
1469 trace__set_fd_pathname(thread, ret, trace->last_vfs_getname);
1470 trace->last_vfs_getname = NULL;
1471 ++trace->stats.vfs_getname;
1472 }
1473
1448 ttrace = thread->priv; 1474 ttrace = thread->priv;
1449 1475
1450 ttrace->exit_time = sample->time; 1476 ttrace->exit_time = sample->time;
@@ -1489,6 +1515,13 @@ out:
1489 return 0; 1515 return 0;
1490} 1516}
1491 1517
1518static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
1519 struct perf_sample *sample)
1520{
1521 trace->last_vfs_getname = perf_evsel__rawptr(evsel, sample, "pathname");
1522 return 0;
1523}
1524
1492static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel, 1525static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
1493 struct perf_sample *sample) 1526 struct perf_sample *sample)
1494{ 1527{
@@ -1611,6 +1644,22 @@ static int trace__record(int argc, const char **argv)
1611 1644
1612static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp); 1645static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
1613 1646
1647static void perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
1648{
1649 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname",
1650 evlist->nr_entries);
1651 if (evsel == NULL)
1652 return;
1653
1654 if (perf_evsel__field(evsel, "pathname") == NULL) {
1655 perf_evsel__delete(evsel);
1656 return;
1657 }
1658
1659 evsel->handler.func = trace__vfs_getname;
1660 perf_evlist__add(evlist, evsel);
1661}
1662
1614static int trace__run(struct trace *trace, int argc, const char **argv) 1663static int trace__run(struct trace *trace, int argc, const char **argv)
1615{ 1664{
1616 struct perf_evlist *evlist = perf_evlist__new(); 1665 struct perf_evlist *evlist = perf_evlist__new();
@@ -1630,6 +1679,8 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
1630 perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_exit", trace__sys_exit)) 1679 perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_exit", trace__sys_exit))
1631 goto out_error_tp; 1680 goto out_error_tp;
1632 1681
1682 perf_evlist__add_vfs_getname(evlist);
1683
1633 if (trace->sched && 1684 if (trace->sched &&
1634 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime", 1685 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
1635 trace__sched_stat_runtime)) 1686 trace__sched_stat_runtime))
@@ -1662,10 +1713,8 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
1662 } 1713 }
1663 1714
1664 err = perf_evlist__open(evlist); 1715 err = perf_evlist__open(evlist);
1665 if (err < 0) { 1716 if (err < 0)
1666 fprintf(trace->output, "Couldn't create the events: %s\n", strerror(errno)); 1717 goto out_error_open;
1667 goto out_delete_maps;
1668 }
1669 1718
1670 err = perf_evlist__mmap(evlist, UINT_MAX, false); 1719 err = perf_evlist__mmap(evlist, UINT_MAX, false);
1671 if (err < 0) { 1720 if (err < 0) {
@@ -1722,26 +1771,35 @@ again:
1722 handler = evsel->handler.func; 1771 handler = evsel->handler.func;
1723 handler(trace, evsel, &sample); 1772 handler(trace, evsel, &sample);
1724 1773
1725 if (done) 1774 if (interrupted)
1726 goto out_unmap_evlist; 1775 goto out_disable;
1727 } 1776 }
1728 } 1777 }
1729 1778
1730 if (trace->nr_events == before) { 1779 if (trace->nr_events == before) {
1731 if (done) 1780 int timeout = done ? 100 : -1;
1732 goto out_unmap_evlist;
1733 1781
1734 poll(evlist->pollfd, evlist->nr_fds, -1); 1782 if (poll(evlist->pollfd, evlist->nr_fds, timeout) > 0)
1783 goto again;
1784 } else {
1785 goto again;
1735 } 1786 }
1736 1787
1737 if (done) 1788out_disable:
1738 perf_evlist__disable(evlist); 1789 perf_evlist__disable(evlist);
1739 1790
1740 goto again; 1791 if (!err) {
1792 if (trace->summary)
1793 trace__fprintf_thread_summary(trace, trace->output);
1741 1794
1742out_unmap_evlist: 1795 if (trace->show_tool_stats) {
1743 if (!err && trace->summary) 1796 fprintf(trace->output, "Stats:\n "
1744 trace__fprintf_thread_summary(trace, trace->output); 1797 " vfs_getname : %" PRIu64 "\n"
1798 " proc_getname: %" PRIu64 "\n",
1799 trace->stats.vfs_getname,
1800 trace->stats.proc_getname);
1801 }
1802 }
1745 1803
1746 perf_evlist__munmap(evlist); 1804 perf_evlist__munmap(evlist);
1747out_close_evlist: 1805out_close_evlist:
@@ -1753,38 +1811,33 @@ out_delete_evlist:
1753out: 1811out:
1754 trace->live = false; 1812 trace->live = false;
1755 return err; 1813 return err;
1814{
1815 char errbuf[BUFSIZ];
1816
1756out_error_tp: 1817out_error_tp:
1757 switch(errno) { 1818 perf_evlist__strerror_tp(evlist, errno, errbuf, sizeof(errbuf));
1758 case ENOENT: 1819 goto out_error;
1759 fputs("Error:\tUnable to find debugfs\n" 1820
1760 "Hint:\tWas your kernel was compiled with debugfs support?\n" 1821out_error_open:
1761 "Hint:\tIs the debugfs filesystem mounted?\n" 1822 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
1762 "Hint:\tTry 'sudo mount -t debugfs nodev /sys/kernel/debug'\n", 1823
1763 trace->output); 1824out_error:
1764 break; 1825 fprintf(trace->output, "%s\n", errbuf);
1765 case EACCES:
1766 fprintf(trace->output,
1767 "Error:\tNo permissions to read %s/tracing/events/raw_syscalls\n"
1768 "Hint:\tTry 'sudo mount -o remount,mode=755 %s'\n",
1769 debugfs_mountpoint, debugfs_mountpoint);
1770 break;
1771 default: {
1772 char bf[256];
1773 fprintf(trace->output, "Can't trace: %s\n",
1774 strerror_r(errno, bf, sizeof(bf)));
1775 }
1776 break;
1777 }
1778 goto out_delete_evlist; 1826 goto out_delete_evlist;
1779} 1827}
1828}
1780 1829
1781static int trace__replay(struct trace *trace) 1830static int trace__replay(struct trace *trace)
1782{ 1831{
1783 const struct perf_evsel_str_handler handlers[] = { 1832 const struct perf_evsel_str_handler handlers[] = {
1784 { "raw_syscalls:sys_enter", trace__sys_enter, }, 1833 { "raw_syscalls:sys_enter", trace__sys_enter, },
1785 { "raw_syscalls:sys_exit", trace__sys_exit, }, 1834 { "raw_syscalls:sys_exit", trace__sys_exit, },
1835 { "probe:vfs_getname", trace__vfs_getname, },
1836 };
1837 struct perf_data_file file = {
1838 .path = input_name,
1839 .mode = PERF_DATA_MODE_READ,
1786 }; 1840 };
1787
1788 struct perf_session *session; 1841 struct perf_session *session;
1789 int err = -1; 1842 int err = -1;
1790 1843
@@ -1807,8 +1860,7 @@ static int trace__replay(struct trace *trace)
1807 if (symbol__init() < 0) 1860 if (symbol__init() < 0)
1808 return -1; 1861 return -1;
1809 1862
1810 session = perf_session__new(input_name, O_RDONLY, 0, false, 1863 session = perf_session__new(&file, false, &trace->tool);
1811 &trace->tool);
1812 if (session == NULL) 1864 if (session == NULL)
1813 return -ENOMEM; 1865 return -ENOMEM;
1814 1866
@@ -1992,7 +2044,10 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
1992 NULL 2044 NULL
1993 }; 2045 };
1994 struct trace trace = { 2046 struct trace trace = {
1995 .audit_machine = audit_detect_machine(), 2047 .audit = {
2048 .machine = audit_detect_machine(),
2049 .open_id = audit_name_to_syscall("open", trace.audit.machine),
2050 },
1996 .syscalls = { 2051 .syscalls = {
1997 . max = -1, 2052 . max = -1,
1998 }, 2053 },
@@ -2014,6 +2069,7 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2014 const struct option trace_options[] = { 2069 const struct option trace_options[] = {
2015 OPT_BOOLEAN(0, "comm", &trace.show_comm, 2070 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2016 "show the thread COMM next to its id"), 2071 "show the thread COMM next to its id"),
2072 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
2017 OPT_STRING('e', "expr", &ev_qualifier_str, "expr", 2073 OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
2018 "list of events to trace"), 2074 "list of events to trace"),
2019 OPT_STRING('o', "output", &output_name, "file", "output file name"), 2075 OPT_STRING('o', "output", &output_name, "file", "output file name"),
diff --git a/tools/perf/config/feature-checks/test-on-exit.c b/tools/perf/config/feature-checks/test-on-exit.c
index 8f64ed3a58d9..8e88b16e6ded 100644
--- a/tools/perf/config/feature-checks/test-on-exit.c
+++ b/tools/perf/config/feature-checks/test-on-exit.c
@@ -1,4 +1,5 @@
1#include <stdio.h> 1#include <stdio.h>
2#include <stdlib.h>
2 3
3static void exit_fn(int status, void *__data) 4static void exit_fn(int status, void *__data)
4{ 5{
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 84502e88488b..f61c230beec4 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -220,7 +220,6 @@ struct perf_record_opts {
220 bool no_delay; 220 bool no_delay;
221 bool no_inherit; 221 bool no_inherit;
222 bool no_samples; 222 bool no_samples;
223 bool pipe_output;
224 bool raw_samples; 223 bool raw_samples;
225 bool sample_address; 224 bool sample_address;
226 bool sample_weight; 225 bool sample_weight;
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index 482f68081cd8..e3970e3eaacf 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -21,12 +21,6 @@
21 21
22__thread struct callchain_cursor callchain_cursor; 22__thread struct callchain_cursor callchain_cursor;
23 23
24#define chain_for_each_child(child, parent) \
25 list_for_each_entry(child, &parent->children, siblings)
26
27#define chain_for_each_child_safe(child, next, parent) \
28 list_for_each_entry_safe(child, next, &parent->children, siblings)
29
30static void 24static void
31rb_insert_callchain(struct rb_root *root, struct callchain_node *chain, 25rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
32 enum chain_mode mode) 26 enum chain_mode mode)
@@ -71,10 +65,16 @@ static void
71__sort_chain_flat(struct rb_root *rb_root, struct callchain_node *node, 65__sort_chain_flat(struct rb_root *rb_root, struct callchain_node *node,
72 u64 min_hit) 66 u64 min_hit)
73{ 67{
68 struct rb_node *n;
74 struct callchain_node *child; 69 struct callchain_node *child;
75 70
76 chain_for_each_child(child, node) 71 n = rb_first(&node->rb_root_in);
72 while (n) {
73 child = rb_entry(n, struct callchain_node, rb_node_in);
74 n = rb_next(n);
75
77 __sort_chain_flat(rb_root, child, min_hit); 76 __sort_chain_flat(rb_root, child, min_hit);
77 }
78 78
79 if (node->hit && node->hit >= min_hit) 79 if (node->hit && node->hit >= min_hit)
80 rb_insert_callchain(rb_root, node, CHAIN_FLAT); 80 rb_insert_callchain(rb_root, node, CHAIN_FLAT);
@@ -94,11 +94,16 @@ sort_chain_flat(struct rb_root *rb_root, struct callchain_root *root,
94static void __sort_chain_graph_abs(struct callchain_node *node, 94static void __sort_chain_graph_abs(struct callchain_node *node,
95 u64 min_hit) 95 u64 min_hit)
96{ 96{
97 struct rb_node *n;
97 struct callchain_node *child; 98 struct callchain_node *child;
98 99
99 node->rb_root = RB_ROOT; 100 node->rb_root = RB_ROOT;
101 n = rb_first(&node->rb_root_in);
102
103 while (n) {
104 child = rb_entry(n, struct callchain_node, rb_node_in);
105 n = rb_next(n);
100 106
101 chain_for_each_child(child, node) {
102 __sort_chain_graph_abs(child, min_hit); 107 __sort_chain_graph_abs(child, min_hit);
103 if (callchain_cumul_hits(child) >= min_hit) 108 if (callchain_cumul_hits(child) >= min_hit)
104 rb_insert_callchain(&node->rb_root, child, 109 rb_insert_callchain(&node->rb_root, child,
@@ -117,13 +122,18 @@ sort_chain_graph_abs(struct rb_root *rb_root, struct callchain_root *chain_root,
117static void __sort_chain_graph_rel(struct callchain_node *node, 122static void __sort_chain_graph_rel(struct callchain_node *node,
118 double min_percent) 123 double min_percent)
119{ 124{
125 struct rb_node *n;
120 struct callchain_node *child; 126 struct callchain_node *child;
121 u64 min_hit; 127 u64 min_hit;
122 128
123 node->rb_root = RB_ROOT; 129 node->rb_root = RB_ROOT;
124 min_hit = ceil(node->children_hit * min_percent); 130 min_hit = ceil(node->children_hit * min_percent);
125 131
126 chain_for_each_child(child, node) { 132 n = rb_first(&node->rb_root_in);
133 while (n) {
134 child = rb_entry(n, struct callchain_node, rb_node_in);
135 n = rb_next(n);
136
127 __sort_chain_graph_rel(child, min_percent); 137 __sort_chain_graph_rel(child, min_percent);
128 if (callchain_cumul_hits(child) >= min_hit) 138 if (callchain_cumul_hits(child) >= min_hit)
129 rb_insert_callchain(&node->rb_root, child, 139 rb_insert_callchain(&node->rb_root, child,
@@ -173,19 +183,26 @@ create_child(struct callchain_node *parent, bool inherit_children)
173 return NULL; 183 return NULL;
174 } 184 }
175 new->parent = parent; 185 new->parent = parent;
176 INIT_LIST_HEAD(&new->children);
177 INIT_LIST_HEAD(&new->val); 186 INIT_LIST_HEAD(&new->val);
178 187
179 if (inherit_children) { 188 if (inherit_children) {
180 struct callchain_node *next; 189 struct rb_node *n;
190 struct callchain_node *child;
191
192 new->rb_root_in = parent->rb_root_in;
193 parent->rb_root_in = RB_ROOT;
181 194
182 list_splice(&parent->children, &new->children); 195 n = rb_first(&new->rb_root_in);
183 INIT_LIST_HEAD(&parent->children); 196 while (n) {
197 child = rb_entry(n, struct callchain_node, rb_node_in);
198 child->parent = new;
199 n = rb_next(n);
200 }
184 201
185 chain_for_each_child(next, new) 202 /* make it the first child */
186 next->parent = new; 203 rb_link_node(&new->rb_node_in, NULL, &parent->rb_root_in.rb_node);
204 rb_insert_color(&new->rb_node_in, &parent->rb_root_in);
187 } 205 }
188 list_add_tail(&new->siblings, &parent->children);
189 206
190 return new; 207 return new;
191} 208}
@@ -223,7 +240,7 @@ fill_node(struct callchain_node *node, struct callchain_cursor *cursor)
223 } 240 }
224} 241}
225 242
226static void 243static struct callchain_node *
227add_child(struct callchain_node *parent, 244add_child(struct callchain_node *parent,
228 struct callchain_cursor *cursor, 245 struct callchain_cursor *cursor,
229 u64 period) 246 u64 period)
@@ -235,6 +252,19 @@ add_child(struct callchain_node *parent,
235 252
236 new->children_hit = 0; 253 new->children_hit = 0;
237 new->hit = period; 254 new->hit = period;
255 return new;
256}
257
258static s64 match_chain(struct callchain_cursor_node *node,
259 struct callchain_list *cnode)
260{
261 struct symbol *sym = node->sym;
262
263 if (cnode->ms.sym && sym &&
264 callchain_param.key == CCKEY_FUNCTION)
265 return cnode->ms.sym->start - sym->start;
266 else
267 return cnode->ip - node->ip;
238} 268}
239 269
240/* 270/*
@@ -272,9 +302,33 @@ split_add_child(struct callchain_node *parent,
272 302
273 /* create a new child for the new branch if any */ 303 /* create a new child for the new branch if any */
274 if (idx_total < cursor->nr) { 304 if (idx_total < cursor->nr) {
305 struct callchain_node *first;
306 struct callchain_list *cnode;
307 struct callchain_cursor_node *node;
308 struct rb_node *p, **pp;
309
275 parent->hit = 0; 310 parent->hit = 0;
276 add_child(parent, cursor, period);
277 parent->children_hit += period; 311 parent->children_hit += period;
312
313 node = callchain_cursor_current(cursor);
314 new = add_child(parent, cursor, period);
315
316 /*
317 * This is second child since we moved parent's children
318 * to new (first) child above.
319 */
320 p = parent->rb_root_in.rb_node;
321 first = rb_entry(p, struct callchain_node, rb_node_in);
322 cnode = list_first_entry(&first->val, struct callchain_list,
323 list);
324
325 if (match_chain(node, cnode) < 0)
326 pp = &p->rb_left;
327 else
328 pp = &p->rb_right;
329
330 rb_link_node(&new->rb_node_in, p, pp);
331 rb_insert_color(&new->rb_node_in, &parent->rb_root_in);
278 } else { 332 } else {
279 parent->hit = period; 333 parent->hit = period;
280 } 334 }
@@ -291,16 +345,40 @@ append_chain_children(struct callchain_node *root,
291 u64 period) 345 u64 period)
292{ 346{
293 struct callchain_node *rnode; 347 struct callchain_node *rnode;
348 struct callchain_cursor_node *node;
349 struct rb_node **p = &root->rb_root_in.rb_node;
350 struct rb_node *parent = NULL;
351
352 node = callchain_cursor_current(cursor);
353 if (!node)
354 return;
294 355
295 /* lookup in childrens */ 356 /* lookup in childrens */
296 chain_for_each_child(rnode, root) { 357 while (*p) {
297 unsigned int ret = append_chain(rnode, cursor, period); 358 s64 ret;
359 struct callchain_list *cnode;
298 360
299 if (!ret) 361 parent = *p;
362 rnode = rb_entry(parent, struct callchain_node, rb_node_in);
363 cnode = list_first_entry(&rnode->val, struct callchain_list,
364 list);
365
366 /* just check first entry */
367 ret = match_chain(node, cnode);
368 if (ret == 0) {
369 append_chain(rnode, cursor, period);
300 goto inc_children_hit; 370 goto inc_children_hit;
371 }
372
373 if (ret < 0)
374 p = &parent->rb_left;
375 else
376 p = &parent->rb_right;
301 } 377 }
302 /* nothing in children, add to the current node */ 378 /* nothing in children, add to the current node */
303 add_child(root, cursor, period); 379 rnode = add_child(root, cursor, period);
380 rb_link_node(&rnode->rb_node_in, parent, p);
381 rb_insert_color(&rnode->rb_node_in, &root->rb_root_in);
304 382
305inc_children_hit: 383inc_children_hit:
306 root->children_hit += period; 384 root->children_hit += period;
@@ -325,28 +403,20 @@ append_chain(struct callchain_node *root,
325 */ 403 */
326 list_for_each_entry(cnode, &root->val, list) { 404 list_for_each_entry(cnode, &root->val, list) {
327 struct callchain_cursor_node *node; 405 struct callchain_cursor_node *node;
328 struct symbol *sym;
329 406
330 node = callchain_cursor_current(cursor); 407 node = callchain_cursor_current(cursor);
331 if (!node) 408 if (!node)
332 break; 409 break;
333 410
334 sym = node->sym; 411 if (match_chain(node, cnode) != 0)
335
336 if (cnode->ms.sym && sym &&
337 callchain_param.key == CCKEY_FUNCTION) {
338 if (cnode->ms.sym->start != sym->start)
339 break;
340 } else if (cnode->ip != node->ip)
341 break; 412 break;
342 413
343 if (!found) 414 found = true;
344 found = true;
345 415
346 callchain_cursor_advance(cursor); 416 callchain_cursor_advance(cursor);
347 } 417 }
348 418
349 /* matches not, relay on the parent */ 419 /* matches not, relay no the parent */
350 if (!found) { 420 if (!found) {
351 cursor->curr = curr_snap; 421 cursor->curr = curr_snap;
352 cursor->pos = start; 422 cursor->pos = start;
@@ -395,8 +465,9 @@ merge_chain_branch(struct callchain_cursor *cursor,
395 struct callchain_node *dst, struct callchain_node *src) 465 struct callchain_node *dst, struct callchain_node *src)
396{ 466{
397 struct callchain_cursor_node **old_last = cursor->last; 467 struct callchain_cursor_node **old_last = cursor->last;
398 struct callchain_node *child, *next_child; 468 struct callchain_node *child;
399 struct callchain_list *list, *next_list; 469 struct callchain_list *list, *next_list;
470 struct rb_node *n;
400 int old_pos = cursor->nr; 471 int old_pos = cursor->nr;
401 int err = 0; 472 int err = 0;
402 473
@@ -412,12 +483,16 @@ merge_chain_branch(struct callchain_cursor *cursor,
412 append_chain_children(dst, cursor, src->hit); 483 append_chain_children(dst, cursor, src->hit);
413 } 484 }
414 485
415 chain_for_each_child_safe(child, next_child, src) { 486 n = rb_first(&src->rb_root_in);
487 while (n) {
488 child = container_of(n, struct callchain_node, rb_node_in);
489 n = rb_next(n);
490 rb_erase(&child->rb_node_in, &src->rb_root_in);
491
416 err = merge_chain_branch(cursor, dst, child); 492 err = merge_chain_branch(cursor, dst, child);
417 if (err) 493 if (err)
418 break; 494 break;
419 495
420 list_del(&child->siblings);
421 free(child); 496 free(child);
422 } 497 }
423 498
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index 2b585bc308cf..7bb36022377f 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -21,11 +21,11 @@ enum chain_order {
21 21
22struct callchain_node { 22struct callchain_node {
23 struct callchain_node *parent; 23 struct callchain_node *parent;
24 struct list_head siblings;
25 struct list_head children;
26 struct list_head val; 24 struct list_head val;
27 struct rb_node rb_node; /* to sort nodes in an rbtree */ 25 struct rb_node rb_node_in; /* to insert nodes in an rbtree */
28 struct rb_root rb_root; /* sorted tree of children */ 26 struct rb_node rb_node; /* to sort nodes in an output tree */
27 struct rb_root rb_root_in; /* input tree of children */
28 struct rb_root rb_root; /* sorted output tree of children */
29 unsigned int val_nr; 29 unsigned int val_nr;
30 u64 hit; 30 u64 hit;
31 u64 children_hit; 31 u64 children_hit;
@@ -86,13 +86,12 @@ extern __thread struct callchain_cursor callchain_cursor;
86 86
87static inline void callchain_init(struct callchain_root *root) 87static inline void callchain_init(struct callchain_root *root)
88{ 88{
89 INIT_LIST_HEAD(&root->node.siblings);
90 INIT_LIST_HEAD(&root->node.children);
91 INIT_LIST_HEAD(&root->node.val); 89 INIT_LIST_HEAD(&root->node.val);
92 90
93 root->node.parent = NULL; 91 root->node.parent = NULL;
94 root->node.hit = 0; 92 root->node.hit = 0;
95 root->node.children_hit = 0; 93 root->node.children_hit = 0;
94 root->node.rb_root_in = RB_ROOT;
96 root->max_depth = 0; 95 root->max_depth = 0;
97} 96}
98 97
diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c
new file mode 100644
index 000000000000..7d09faf85cf1
--- /dev/null
+++ b/tools/perf/util/data.c
@@ -0,0 +1,120 @@
1#include <linux/compiler.h>
2#include <linux/kernel.h>
3#include <sys/types.h>
4#include <sys/stat.h>
5#include <unistd.h>
6#include <string.h>
7
8#include "data.h"
9#include "util.h"
10
11static bool check_pipe(struct perf_data_file *file)
12{
13 struct stat st;
14 bool is_pipe = false;
15 int fd = perf_data_file__is_read(file) ?
16 STDIN_FILENO : STDOUT_FILENO;
17
18 if (!file->path) {
19 if (!fstat(fd, &st) && S_ISFIFO(st.st_mode))
20 is_pipe = true;
21 } else {
22 if (!strcmp(file->path, "-"))
23 is_pipe = true;
24 }
25
26 if (is_pipe)
27 file->fd = fd;
28
29 return file->is_pipe = is_pipe;
30}
31
32static int check_backup(struct perf_data_file *file)
33{
34 struct stat st;
35
36 if (!stat(file->path, &st) && st.st_size) {
37 /* TODO check errors properly */
38 char oldname[PATH_MAX];
39 snprintf(oldname, sizeof(oldname), "%s.old",
40 file->path);
41 unlink(oldname);
42 rename(file->path, oldname);
43 }
44
45 return 0;
46}
47
48static int open_file_read(struct perf_data_file *file)
49{
50 struct stat st;
51 int fd;
52
53 fd = open(file->path, O_RDONLY);
54 if (fd < 0) {
55 int err = errno;
56
57 pr_err("failed to open %s: %s", file->path, strerror(err));
58 if (err == ENOENT && !strcmp(file->path, "perf.data"))
59 pr_err(" (try 'perf record' first)");
60 pr_err("\n");
61 return -err;
62 }
63
64 if (fstat(fd, &st) < 0)
65 goto out_close;
66
67 if (!file->force && st.st_uid && (st.st_uid != geteuid())) {
68 pr_err("file %s not owned by current user or root\n",
69 file->path);
70 goto out_close;
71 }
72
73 if (!st.st_size) {
74 pr_info("zero-sized file (%s), nothing to do!\n",
75 file->path);
76 goto out_close;
77 }
78
79 file->size = st.st_size;
80 return fd;
81
82 out_close:
83 close(fd);
84 return -1;
85}
86
87static int open_file_write(struct perf_data_file *file)
88{
89 if (check_backup(file))
90 return -1;
91
92 return open(file->path, O_CREAT|O_RDWR|O_TRUNC, S_IRUSR|S_IWUSR);
93}
94
95static int open_file(struct perf_data_file *file)
96{
97 int fd;
98
99 fd = perf_data_file__is_read(file) ?
100 open_file_read(file) : open_file_write(file);
101
102 file->fd = fd;
103 return fd < 0 ? -1 : 0;
104}
105
106int perf_data_file__open(struct perf_data_file *file)
107{
108 if (check_pipe(file))
109 return 0;
110
111 if (!file->path)
112 file->path = "perf.data";
113
114 return open_file(file);
115}
116
117void perf_data_file__close(struct perf_data_file *file)
118{
119 close(file->fd);
120}
diff --git a/tools/perf/util/data.h b/tools/perf/util/data.h
new file mode 100644
index 000000000000..8c2df80152a5
--- /dev/null
+++ b/tools/perf/util/data.h
@@ -0,0 +1,48 @@
1#ifndef __PERF_DATA_H
2#define __PERF_DATA_H
3
4#include <stdbool.h>
5
6enum perf_data_mode {
7 PERF_DATA_MODE_WRITE,
8 PERF_DATA_MODE_READ,
9};
10
11struct perf_data_file {
12 const char *path;
13 int fd;
14 bool is_pipe;
15 bool force;
16 unsigned long size;
17 enum perf_data_mode mode;
18};
19
20static inline bool perf_data_file__is_read(struct perf_data_file *file)
21{
22 return file->mode == PERF_DATA_MODE_READ;
23}
24
25static inline bool perf_data_file__is_write(struct perf_data_file *file)
26{
27 return file->mode == PERF_DATA_MODE_WRITE;
28}
29
30static inline int perf_data_file__is_pipe(struct perf_data_file *file)
31{
32 return file->is_pipe;
33}
34
35static inline int perf_data_file__fd(struct perf_data_file *file)
36{
37 return file->fd;
38}
39
40static inline unsigned long perf_data_file__size(struct perf_data_file *file)
41{
42 return file->size;
43}
44
45int perf_data_file__open(struct perf_data_file *file);
46void perf_data_file__close(struct perf_data_file *file);
47
48#endif /* __PERF_DATA_H */
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index cb9523f50a37..85c4c80bcac8 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -608,9 +608,36 @@ static int __perf_evlist__mmap(struct perf_evlist *evlist,
608 return 0; 608 return 0;
609} 609}
610 610
611static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, int mask) 611static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,
612 int prot, int mask, int cpu, int thread,
613 int *output)
612{ 614{
613 struct perf_evsel *evsel; 615 struct perf_evsel *evsel;
616
617 list_for_each_entry(evsel, &evlist->entries, node) {
618 int fd = FD(evsel, cpu, thread);
619
620 if (*output == -1) {
621 *output = fd;
622 if (__perf_evlist__mmap(evlist, idx, prot, mask,
623 *output) < 0)
624 return -1;
625 } else {
626 if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, *output) != 0)
627 return -1;
628 }
629
630 if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
631 perf_evlist__id_add_fd(evlist, evsel, cpu, thread, fd) < 0)
632 return -1;
633 }
634
635 return 0;
636}
637
638static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot,
639 int mask)
640{
614 int cpu, thread; 641 int cpu, thread;
615 int nr_cpus = cpu_map__nr(evlist->cpus); 642 int nr_cpus = cpu_map__nr(evlist->cpus);
616 int nr_threads = thread_map__nr(evlist->threads); 643 int nr_threads = thread_map__nr(evlist->threads);
@@ -620,23 +647,9 @@ static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, int m
620 int output = -1; 647 int output = -1;
621 648
622 for (thread = 0; thread < nr_threads; thread++) { 649 for (thread = 0; thread < nr_threads; thread++) {
623 list_for_each_entry(evsel, &evlist->entries, node) { 650 if (perf_evlist__mmap_per_evsel(evlist, cpu, prot, mask,
624 int fd = FD(evsel, cpu, thread); 651 cpu, thread, &output))
625 652 goto out_unmap;
626 if (output == -1) {
627 output = fd;
628 if (__perf_evlist__mmap(evlist, cpu,
629 prot, mask, output) < 0)
630 goto out_unmap;
631 } else {
632 if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, output) != 0)
633 goto out_unmap;
634 }
635
636 if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
637 perf_evlist__id_add_fd(evlist, evsel, cpu, thread, fd) < 0)
638 goto out_unmap;
639 }
640 } 653 }
641 } 654 }
642 655
@@ -648,9 +661,9 @@ out_unmap:
648 return -1; 661 return -1;
649} 662}
650 663
651static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, int mask) 664static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot,
665 int mask)
652{ 666{
653 struct perf_evsel *evsel;
654 int thread; 667 int thread;
655 int nr_threads = thread_map__nr(evlist->threads); 668 int nr_threads = thread_map__nr(evlist->threads);
656 669
@@ -658,23 +671,9 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, in
658 for (thread = 0; thread < nr_threads; thread++) { 671 for (thread = 0; thread < nr_threads; thread++) {
659 int output = -1; 672 int output = -1;
660 673
661 list_for_each_entry(evsel, &evlist->entries, node) { 674 if (perf_evlist__mmap_per_evsel(evlist, thread, prot, mask, 0,
662 int fd = FD(evsel, 0, thread); 675 thread, &output))
663 676 goto out_unmap;
664 if (output == -1) {
665 output = fd;
666 if (__perf_evlist__mmap(evlist, thread,
667 prot, mask, output) < 0)
668 goto out_unmap;
669 } else {
670 if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, output) != 0)
671 goto out_unmap;
672 }
673
674 if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
675 perf_evlist__id_add_fd(evlist, evsel, 0, thread, fd) < 0)
676 goto out_unmap;
677 }
678 } 677 }
679 678
680 return 0; 679 return 0;
@@ -738,20 +737,17 @@ int perf_evlist__parse_mmap_pages(const struct option *opt, const char *str,
738 return 0; 737 return 0;
739} 738}
740 739
741/** perf_evlist__mmap - Create per cpu maps to receive events 740/**
742 * 741 * perf_evlist__mmap - Create mmaps to receive events.
743 * @evlist - list of events 742 * @evlist: list of events
744 * @pages - map length in pages 743 * @pages: map length in pages
745 * @overwrite - overwrite older events? 744 * @overwrite: overwrite older events?
746 *
747 * If overwrite is false the user needs to signal event consuption using:
748 *
749 * struct perf_mmap *m = &evlist->mmap[cpu];
750 * unsigned int head = perf_mmap__read_head(m);
751 * 745 *
752 * perf_mmap__write_tail(m, head) 746 * If @overwrite is %false the user needs to signal event consumption using
747 * perf_mmap__write_tail(). Using perf_evlist__mmap_read() does this
748 * automatically.
753 * 749 *
754 * Using perf_evlist__read_on_cpu does this automatically. 750 * Return: %0 on success, negative error code otherwise.
755 */ 751 */
756int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, 752int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
757 bool overwrite) 753 bool overwrite)
@@ -769,7 +765,7 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
769 765
770 evlist->overwrite = overwrite; 766 evlist->overwrite = overwrite;
771 evlist->mmap_len = perf_evlist__mmap_size(pages); 767 evlist->mmap_len = perf_evlist__mmap_size(pages);
772 pr_debug("mmap size %luB\n", evlist->mmap_len); 768 pr_debug("mmap size %zuB\n", evlist->mmap_len);
773 mask = evlist->mmap_len - page_size - 1; 769 mask = evlist->mmap_len - page_size - 1;
774 770
775 list_for_each_entry(evsel, &evlist->entries, node) { 771 list_for_each_entry(evsel, &evlist->entries, node) {
@@ -1126,3 +1122,66 @@ size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp)
1126 1122
1127 return printed + fprintf(fp, "\n");; 1123 return printed + fprintf(fp, "\n");;
1128} 1124}
1125
1126int perf_evlist__strerror_tp(struct perf_evlist *evlist __maybe_unused,
1127 int err, char *buf, size_t size)
1128{
1129 char sbuf[128];
1130
1131 switch (err) {
1132 case ENOENT:
1133 scnprintf(buf, size, "%s",
1134 "Error:\tUnable to find debugfs\n"
1135 "Hint:\tWas your kernel was compiled with debugfs support?\n"
1136 "Hint:\tIs the debugfs filesystem mounted?\n"
1137 "Hint:\tTry 'sudo mount -t debugfs nodev /sys/kernel/debug'");
1138 break;
1139 case EACCES:
1140 scnprintf(buf, size,
1141 "Error:\tNo permissions to read %s/tracing/events/raw_syscalls\n"
1142 "Hint:\tTry 'sudo mount -o remount,mode=755 %s'\n",
1143 debugfs_mountpoint, debugfs_mountpoint);
1144 break;
1145 default:
1146 scnprintf(buf, size, "%s", strerror_r(err, sbuf, sizeof(sbuf)));
1147 break;
1148 }
1149
1150 return 0;
1151}
1152
1153int perf_evlist__strerror_open(struct perf_evlist *evlist __maybe_unused,
1154 int err, char *buf, size_t size)
1155{
1156 int printed, value;
1157 char sbuf[128], *emsg = strerror_r(err, sbuf, sizeof(sbuf));
1158
1159 switch (err) {
1160 case EACCES:
1161 case EPERM:
1162 printed = scnprintf(buf, size,
1163 "Error:\t%s.\n"
1164 "Hint:\tCheck /proc/sys/kernel/perf_event_paranoid setting.", emsg);
1165
1166 if (filename__read_int("/proc/sys/kernel/perf_event_paranoid", &value))
1167 break;
1168
1169 printed += scnprintf(buf + printed, size - printed, "\nHint:\t");
1170
1171 if (value >= 2) {
1172 printed += scnprintf(buf + printed, size - printed,
1173 "For your workloads it needs to be <= 1\nHint:\t");
1174 }
1175 printed += scnprintf(buf + printed, size - printed,
1176 "For system wide tracing it needs to be set to -1");
1177
1178 printed += scnprintf(buf + printed, size - printed,
1179 ".\nHint:\tThe current value is %d.", value);
1180 break;
1181 default:
1182 scnprintf(buf, size, "%s", emsg);
1183 break;
1184 }
1185
1186 return 0;
1187}
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 722618f84c53..7f8f1aeb9cfe 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -168,6 +168,9 @@ static inline struct perf_evsel *perf_evlist__last(struct perf_evlist *evlist)
168 168
169size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp); 169size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp);
170 170
171int perf_evlist__strerror_tp(struct perf_evlist *evlist, int err, char *buf, size_t size);
172int perf_evlist__strerror_open(struct perf_evlist *evlist, int err, char *buf, size_t size);
173
171static inline unsigned int perf_mmap__read_head(struct perf_mmap *mm) 174static inline unsigned int perf_mmap__read_head(struct perf_mmap *mm)
172{ 175{
173 struct perf_event_mmap_page *pc = mm->base; 176 struct perf_event_mmap_page *pc = mm->base;
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index bfebc1ea3c51..ec0cc1e21c62 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -986,6 +986,7 @@ static size_t perf_event_attr__fprintf(struct perf_event_attr *attr, FILE *fp)
986 ret += PRINT_ATTR2(exclude_host, exclude_guest); 986 ret += PRINT_ATTR2(exclude_host, exclude_guest);
987 ret += PRINT_ATTR2N("excl.callchain_kern", exclude_callchain_kernel, 987 ret += PRINT_ATTR2N("excl.callchain_kern", exclude_callchain_kernel,
988 "excl.callchain_user", exclude_callchain_user); 988 "excl.callchain_user", exclude_callchain_user);
989 ret += PRINT_ATTR_U32(mmap2);
989 990
990 ret += PRINT_ATTR_U32(wakeup_events); 991 ret += PRINT_ATTR_U32(wakeup_events);
991 ret += PRINT_ATTR_U32(wakeup_watermark); 992 ret += PRINT_ATTR_U32(wakeup_watermark);
@@ -1217,6 +1218,7 @@ static int perf_evsel__parse_id_sample(const struct perf_evsel *evsel,
1217 1218
1218 sample->pid = u.val32[0]; 1219 sample->pid = u.val32[0];
1219 sample->tid = u.val32[1]; 1220 sample->tid = u.val32[1];
1221 array--;
1220 } 1222 }
1221 1223
1222 return 0; 1224 return 0;
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index c3e5a3b817ab..26d9520a0c1b 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -22,6 +22,7 @@
22#include "vdso.h" 22#include "vdso.h"
23#include "strbuf.h" 23#include "strbuf.h"
24#include "build-id.h" 24#include "build-id.h"
25#include "data.h"
25 26
26static bool no_buildid_cache = false; 27static bool no_buildid_cache = false;
27 28
@@ -2189,7 +2190,7 @@ int perf_header__fprintf_info(struct perf_session *session, FILE *fp, bool full)
2189{ 2190{
2190 struct header_print_data hd; 2191 struct header_print_data hd;
2191 struct perf_header *header = &session->header; 2192 struct perf_header *header = &session->header;
2192 int fd = session->fd; 2193 int fd = perf_data_file__fd(session->file);
2193 hd.fp = fp; 2194 hd.fp = fp;
2194 hd.full = full; 2195 hd.full = full;
2195 2196
@@ -2650,7 +2651,8 @@ static int perf_header__read_pipe(struct perf_session *session)
2650 struct perf_header *header = &session->header; 2651 struct perf_header *header = &session->header;
2651 struct perf_pipe_file_header f_header; 2652 struct perf_pipe_file_header f_header;
2652 2653
2653 if (perf_file_header__read_pipe(&f_header, header, session->fd, 2654 if (perf_file_header__read_pipe(&f_header, header,
2655 perf_data_file__fd(session->file),
2654 session->repipe) < 0) { 2656 session->repipe) < 0) {
2655 pr_debug("incompatible file format\n"); 2657 pr_debug("incompatible file format\n");
2656 return -EINVAL; 2658 return -EINVAL;
@@ -2751,18 +2753,19 @@ static int perf_evlist__prepare_tracepoint_events(struct perf_evlist *evlist,
2751 2753
2752int perf_session__read_header(struct perf_session *session) 2754int perf_session__read_header(struct perf_session *session)
2753{ 2755{
2756 struct perf_data_file *file = session->file;
2754 struct perf_header *header = &session->header; 2757 struct perf_header *header = &session->header;
2755 struct perf_file_header f_header; 2758 struct perf_file_header f_header;
2756 struct perf_file_attr f_attr; 2759 struct perf_file_attr f_attr;
2757 u64 f_id; 2760 u64 f_id;
2758 int nr_attrs, nr_ids, i, j; 2761 int nr_attrs, nr_ids, i, j;
2759 int fd = session->fd; 2762 int fd = perf_data_file__fd(file);
2760 2763
2761 session->evlist = perf_evlist__new(); 2764 session->evlist = perf_evlist__new();
2762 if (session->evlist == NULL) 2765 if (session->evlist == NULL)
2763 return -ENOMEM; 2766 return -ENOMEM;
2764 2767
2765 if (session->fd_pipe) 2768 if (perf_data_file__is_pipe(file))
2766 return perf_header__read_pipe(session); 2769 return perf_header__read_pipe(session);
2767 2770
2768 if (perf_file_header__read(&f_header, header, fd) < 0) 2771 if (perf_file_header__read(&f_header, header, fd) < 0)
@@ -2777,7 +2780,7 @@ int perf_session__read_header(struct perf_session *session)
2777 if (f_header.data.size == 0) { 2780 if (f_header.data.size == 0) {
2778 pr_warning("WARNING: The %s file's data size field is 0 which is unexpected.\n" 2781 pr_warning("WARNING: The %s file's data size field is 0 which is unexpected.\n"
2779 "Was the 'perf record' command properly terminated?\n", 2782 "Was the 'perf record' command properly terminated?\n",
2780 session->filename); 2783 file->path);
2781 } 2784 }
2782 2785
2783 nr_attrs = f_header.attrs.size / f_header.attr_size; 2786 nr_attrs = f_header.attrs.size / f_header.attr_size;
@@ -2990,18 +2993,19 @@ int perf_event__process_tracing_data(struct perf_tool *tool __maybe_unused,
2990 struct perf_session *session) 2993 struct perf_session *session)
2991{ 2994{
2992 ssize_t size_read, padding, size = event->tracing_data.size; 2995 ssize_t size_read, padding, size = event->tracing_data.size;
2993 off_t offset = lseek(session->fd, 0, SEEK_CUR); 2996 int fd = perf_data_file__fd(session->file);
2997 off_t offset = lseek(fd, 0, SEEK_CUR);
2994 char buf[BUFSIZ]; 2998 char buf[BUFSIZ];
2995 2999
2996 /* setup for reading amidst mmap */ 3000 /* setup for reading amidst mmap */
2997 lseek(session->fd, offset + sizeof(struct tracing_data_event), 3001 lseek(fd, offset + sizeof(struct tracing_data_event),
2998 SEEK_SET); 3002 SEEK_SET);
2999 3003
3000 size_read = trace_report(session->fd, &session->pevent, 3004 size_read = trace_report(fd, &session->pevent,
3001 session->repipe); 3005 session->repipe);
3002 padding = PERF_ALIGN(size_read, sizeof(u64)) - size_read; 3006 padding = PERF_ALIGN(size_read, sizeof(u64)) - size_read;
3003 3007
3004 if (readn(session->fd, buf, padding) < 0) { 3008 if (readn(fd, buf, padding) < 0) {
3005 pr_err("%s: reading input file", __func__); 3009 pr_err("%s: reading input file", __func__);
3006 return -1; 3010 return -1;
3007 } 3011 }
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 6b861aefd99a..ea93425cce95 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -1253,10 +1253,12 @@ static int machine__resolve_callchain_sample(struct machine *machine,
1253 struct thread *thread, 1253 struct thread *thread,
1254 struct ip_callchain *chain, 1254 struct ip_callchain *chain,
1255 struct symbol **parent, 1255 struct symbol **parent,
1256 struct addr_location *root_al) 1256 struct addr_location *root_al,
1257 int max_stack)
1257{ 1258{
1258 u8 cpumode = PERF_RECORD_MISC_USER; 1259 u8 cpumode = PERF_RECORD_MISC_USER;
1259 unsigned int i; 1260 int chain_nr = min(max_stack, (int)chain->nr);
1261 int i;
1260 int err; 1262 int err;
1261 1263
1262 callchain_cursor_reset(&callchain_cursor); 1264 callchain_cursor_reset(&callchain_cursor);
@@ -1266,7 +1268,7 @@ static int machine__resolve_callchain_sample(struct machine *machine,
1266 return 0; 1268 return 0;
1267 } 1269 }
1268 1270
1269 for (i = 0; i < chain->nr; i++) { 1271 for (i = 0; i < chain_nr; i++) {
1270 u64 ip; 1272 u64 ip;
1271 struct addr_location al; 1273 struct addr_location al;
1272 1274
@@ -1338,12 +1340,14 @@ int machine__resolve_callchain(struct machine *machine,
1338 struct thread *thread, 1340 struct thread *thread,
1339 struct perf_sample *sample, 1341 struct perf_sample *sample,
1340 struct symbol **parent, 1342 struct symbol **parent,
1341 struct addr_location *root_al) 1343 struct addr_location *root_al,
1344 int max_stack)
1342{ 1345{
1343 int ret; 1346 int ret;
1344 1347
1345 ret = machine__resolve_callchain_sample(machine, thread, 1348 ret = machine__resolve_callchain_sample(machine, thread,
1346 sample->callchain, parent, root_al); 1349 sample->callchain, parent,
1350 root_al, max_stack);
1347 if (ret) 1351 if (ret)
1348 return ret; 1352 return ret;
1349 1353
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
index d44c09bdc45e..4c1f5d567f54 100644
--- a/tools/perf/util/machine.h
+++ b/tools/perf/util/machine.h
@@ -92,7 +92,8 @@ int machine__resolve_callchain(struct machine *machine,
92 struct thread *thread, 92 struct thread *thread,
93 struct perf_sample *sample, 93 struct perf_sample *sample,
94 struct symbol **parent, 94 struct symbol **parent,
95 struct addr_location *root_al); 95 struct addr_location *root_al,
96 int max_stack);
96 97
97/* 98/*
98 * Default guest kernel is defined by parameter --guestkallsyms 99 * Default guest kernel is defined by parameter --guestkallsyms
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 98125319b158..c90e55cf7e82 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -998,8 +998,10 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob,
998 char evt_path[MAXPATHLEN]; 998 char evt_path[MAXPATHLEN];
999 char dir_path[MAXPATHLEN]; 999 char dir_path[MAXPATHLEN];
1000 1000
1001 if (debugfs_valid_mountpoint(tracing_events_path)) 1001 if (debugfs_valid_mountpoint(tracing_events_path)) {
1002 printf(" [ Tracepoints not available: %s ]\n", strerror(errno));
1002 return; 1003 return;
1004 }
1003 1005
1004 sys_dir = opendir(tracing_events_path); 1006 sys_dir = opendir(tracing_events_path);
1005 if (!sys_dir) 1007 if (!sys_dir)
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
index a85e4ae5f3ac..c0c9795c4f02 100644
--- a/tools/perf/util/scripting-engines/trace-event-perl.c
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -282,7 +282,7 @@ static void perl_process_tracepoint(union perf_event *perf_event __maybe_unused,
282 282
283 event = find_cache_event(evsel); 283 event = find_cache_event(evsel);
284 if (!event) 284 if (!event)
285 die("ug! no event found for type %" PRIu64, evsel->attr.config); 285 die("ug! no event found for type %" PRIu64, (u64)evsel->attr.config);
286 286
287 pid = raw_field_value(event, "common_pid", data); 287 pid = raw_field_value(event, "common_pid", data);
288 288
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index d1e449534b33..854c5aa4db0d 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -16,73 +16,34 @@
16#include "perf_regs.h" 16#include "perf_regs.h"
17#include "vdso.h" 17#include "vdso.h"
18 18
19static int perf_session__open(struct perf_session *self, bool force) 19static int perf_session__open(struct perf_session *self)
20{ 20{
21 struct stat input_stat; 21 struct perf_data_file *file = self->file;
22
23 if (!strcmp(self->filename, "-")) {
24 self->fd_pipe = true;
25 self->fd = STDIN_FILENO;
26
27 if (perf_session__read_header(self) < 0)
28 pr_err("incompatible file format (rerun with -v to learn more)");
29
30 return 0;
31 }
32
33 self->fd = open(self->filename, O_RDONLY);
34 if (self->fd < 0) {
35 int err = errno;
36
37 pr_err("failed to open %s: %s", self->filename, strerror(err));
38 if (err == ENOENT && !strcmp(self->filename, "perf.data"))
39 pr_err(" (try 'perf record' first)");
40 pr_err("\n");
41 return -errno;
42 }
43
44 if (fstat(self->fd, &input_stat) < 0)
45 goto out_close;
46
47 if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
48 pr_err("file %s not owned by current user or root\n",
49 self->filename);
50 goto out_close;
51 }
52
53 if (!input_stat.st_size) {
54 pr_info("zero-sized file (%s), nothing to do!\n",
55 self->filename);
56 goto out_close;
57 }
58 22
59 if (perf_session__read_header(self) < 0) { 23 if (perf_session__read_header(self) < 0) {
60 pr_err("incompatible file format (rerun with -v to learn more)"); 24 pr_err("incompatible file format (rerun with -v to learn more)");
61 goto out_close; 25 return -1;
62 } 26 }
63 27
28 if (perf_data_file__is_pipe(file))
29 return 0;
30
64 if (!perf_evlist__valid_sample_type(self->evlist)) { 31 if (!perf_evlist__valid_sample_type(self->evlist)) {
65 pr_err("non matching sample_type"); 32 pr_err("non matching sample_type");
66 goto out_close; 33 return -1;
67 } 34 }
68 35
69 if (!perf_evlist__valid_sample_id_all(self->evlist)) { 36 if (!perf_evlist__valid_sample_id_all(self->evlist)) {
70 pr_err("non matching sample_id_all"); 37 pr_err("non matching sample_id_all");
71 goto out_close; 38 return -1;
72 } 39 }
73 40
74 if (!perf_evlist__valid_read_format(self->evlist)) { 41 if (!perf_evlist__valid_read_format(self->evlist)) {
75 pr_err("non matching read_format"); 42 pr_err("non matching read_format");
76 goto out_close; 43 return -1;
77 } 44 }
78 45
79 self->size = input_stat.st_size;
80 return 0; 46 return 0;
81
82out_close:
83 close(self->fd);
84 self->fd = -1;
85 return -1;
86} 47}
87 48
88void perf_session__set_id_hdr_size(struct perf_session *session) 49void perf_session__set_id_hdr_size(struct perf_session *session)
@@ -106,39 +67,36 @@ static void perf_session__destroy_kernel_maps(struct perf_session *self)
106 machines__destroy_kernel_maps(&self->machines); 67 machines__destroy_kernel_maps(&self->machines);
107} 68}
108 69
109struct perf_session *perf_session__new(const char *filename, int mode, 70struct perf_session *perf_session__new(struct perf_data_file *file,
110 bool force, bool repipe, 71 bool repipe, struct perf_tool *tool)
111 struct perf_tool *tool)
112{ 72{
113 struct perf_session *self; 73 struct perf_session *self;
114 struct stat st;
115 size_t len;
116
117 if (!filename || !strlen(filename)) {
118 if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode))
119 filename = "-";
120 else
121 filename = "perf.data";
122 }
123 74
124 len = strlen(filename); 75 self = zalloc(sizeof(*self));
125 self = zalloc(sizeof(*self) + len); 76 if (!self)
126
127 if (self == NULL)
128 goto out; 77 goto out;
129 78
130 memcpy(self->filename, filename, len);
131 self->repipe = repipe; 79 self->repipe = repipe;
132 INIT_LIST_HEAD(&self->ordered_samples.samples); 80 INIT_LIST_HEAD(&self->ordered_samples.samples);
133 INIT_LIST_HEAD(&self->ordered_samples.sample_cache); 81 INIT_LIST_HEAD(&self->ordered_samples.sample_cache);
134 INIT_LIST_HEAD(&self->ordered_samples.to_free); 82 INIT_LIST_HEAD(&self->ordered_samples.to_free);
135 machines__init(&self->machines); 83 machines__init(&self->machines);
136 84
137 if (mode == O_RDONLY) { 85 if (file) {
138 if (perf_session__open(self, force) < 0) 86 if (perf_data_file__open(file))
139 goto out_delete; 87 goto out_delete;
140 perf_session__set_id_hdr_size(self); 88
141 } else if (mode == O_WRONLY) { 89 self->file = file;
90
91 if (perf_data_file__is_read(file)) {
92 if (perf_session__open(self) < 0)
93 goto out_close;
94
95 perf_session__set_id_hdr_size(self);
96 }
97 }
98
99 if (!file || perf_data_file__is_write(file)) {
142 /* 100 /*
143 * In O_RDONLY mode this will be performed when reading the 101 * In O_RDONLY mode this will be performed when reading the
144 * kernel MMAP event, in perf_event__process_mmap(). 102 * kernel MMAP event, in perf_event__process_mmap().
@@ -153,10 +111,13 @@ struct perf_session *perf_session__new(const char *filename, int mode,
153 tool->ordered_samples = false; 111 tool->ordered_samples = false;
154 } 112 }
155 113
156out:
157 return self; 114 return self;
158out_delete: 115
116 out_close:
117 perf_data_file__close(file);
118 out_delete:
159 perf_session__delete(self); 119 perf_session__delete(self);
120 out:
160 return NULL; 121 return NULL;
161} 122}
162 123
@@ -193,7 +154,8 @@ void perf_session__delete(struct perf_session *self)
193 perf_session__delete_threads(self); 154 perf_session__delete_threads(self);
194 perf_session_env__delete(&self->header.env); 155 perf_session_env__delete(&self->header.env);
195 machines__exit(&self->machines); 156 machines__exit(&self->machines);
196 close(self->fd); 157 if (self->file)
158 perf_data_file__close(self->file);
197 free(self); 159 free(self);
198 vdso__exit(); 160 vdso__exit();
199} 161}
@@ -453,6 +415,9 @@ void perf_event__attr_swap(struct perf_event_attr *attr)
453 attr->bp_type = bswap_32(attr->bp_type); 415 attr->bp_type = bswap_32(attr->bp_type);
454 attr->bp_addr = bswap_64(attr->bp_addr); 416 attr->bp_addr = bswap_64(attr->bp_addr);
455 attr->bp_len = bswap_64(attr->bp_len); 417 attr->bp_len = bswap_64(attr->bp_len);
418 attr->branch_sample_type = bswap_64(attr->branch_sample_type);
419 attr->sample_regs_user = bswap_64(attr->sample_regs_user);
420 attr->sample_stack_user = bswap_32(attr->sample_stack_user);
456 421
457 swap_bitfield((u8 *) (&attr->read_format + 1), sizeof(u64)); 422 swap_bitfield((u8 *) (&attr->read_format + 1), sizeof(u64));
458} 423}
@@ -1047,6 +1012,7 @@ static int perf_session_deliver_event(struct perf_session *session,
1047static int perf_session__process_user_event(struct perf_session *session, union perf_event *event, 1012static int perf_session__process_user_event(struct perf_session *session, union perf_event *event,
1048 struct perf_tool *tool, u64 file_offset) 1013 struct perf_tool *tool, u64 file_offset)
1049{ 1014{
1015 int fd = perf_data_file__fd(session->file);
1050 int err; 1016 int err;
1051 1017
1052 dump_event(session, event, file_offset, NULL); 1018 dump_event(session, event, file_offset, NULL);
@@ -1060,7 +1026,7 @@ static int perf_session__process_user_event(struct perf_session *session, union
1060 return err; 1026 return err;
1061 case PERF_RECORD_HEADER_TRACING_DATA: 1027 case PERF_RECORD_HEADER_TRACING_DATA:
1062 /* setup for reading amidst mmap */ 1028 /* setup for reading amidst mmap */
1063 lseek(session->fd, file_offset, SEEK_SET); 1029 lseek(fd, file_offset, SEEK_SET);
1064 return tool->tracing_data(tool, event, session); 1030 return tool->tracing_data(tool, event, session);
1065 case PERF_RECORD_HEADER_BUILD_ID: 1031 case PERF_RECORD_HEADER_BUILD_ID:
1066 return tool->build_id(tool, event, session); 1032 return tool->build_id(tool, event, session);
@@ -1186,6 +1152,7 @@ volatile int session_done;
1186static int __perf_session__process_pipe_events(struct perf_session *self, 1152static int __perf_session__process_pipe_events(struct perf_session *self,
1187 struct perf_tool *tool) 1153 struct perf_tool *tool)
1188{ 1154{
1155 int fd = perf_data_file__fd(self->file);
1189 union perf_event *event; 1156 union perf_event *event;
1190 uint32_t size, cur_size = 0; 1157 uint32_t size, cur_size = 0;
1191 void *buf = NULL; 1158 void *buf = NULL;
@@ -1204,7 +1171,7 @@ static int __perf_session__process_pipe_events(struct perf_session *self,
1204 return -errno; 1171 return -errno;
1205more: 1172more:
1206 event = buf; 1173 event = buf;
1207 err = readn(self->fd, event, sizeof(struct perf_event_header)); 1174 err = readn(fd, event, sizeof(struct perf_event_header));
1208 if (err <= 0) { 1175 if (err <= 0) {
1209 if (err == 0) 1176 if (err == 0)
1210 goto done; 1177 goto done;
@@ -1236,7 +1203,7 @@ more:
1236 p += sizeof(struct perf_event_header); 1203 p += sizeof(struct perf_event_header);
1237 1204
1238 if (size - sizeof(struct perf_event_header)) { 1205 if (size - sizeof(struct perf_event_header)) {
1239 err = readn(self->fd, p, size - sizeof(struct perf_event_header)); 1206 err = readn(fd, p, size - sizeof(struct perf_event_header));
1240 if (err <= 0) { 1207 if (err <= 0) {
1241 if (err == 0) { 1208 if (err == 0) {
1242 pr_err("unexpected end of event stream\n"); 1209 pr_err("unexpected end of event stream\n");
@@ -1263,7 +1230,9 @@ more:
1263 if (!session_done()) 1230 if (!session_done())
1264 goto more; 1231 goto more;
1265done: 1232done:
1266 err = 0; 1233 /* do the final flush for ordered samples */
1234 self->ordered_samples.next_flush = ULLONG_MAX;
1235 err = flush_sample_queue(self, tool);
1267out_err: 1236out_err:
1268 free(buf); 1237 free(buf);
1269 perf_session__warn_about_errors(self, tool); 1238 perf_session__warn_about_errors(self, tool);
@@ -1315,6 +1284,7 @@ int __perf_session__process_events(struct perf_session *session,
1315 u64 data_offset, u64 data_size, 1284 u64 data_offset, u64 data_size,
1316 u64 file_size, struct perf_tool *tool) 1285 u64 file_size, struct perf_tool *tool)
1317{ 1286{
1287 int fd = perf_data_file__fd(session->file);
1318 u64 head, page_offset, file_offset, file_pos, progress_next; 1288 u64 head, page_offset, file_offset, file_pos, progress_next;
1319 int err, mmap_prot, mmap_flags, map_idx = 0; 1289 int err, mmap_prot, mmap_flags, map_idx = 0;
1320 size_t mmap_size; 1290 size_t mmap_size;
@@ -1347,7 +1317,7 @@ int __perf_session__process_events(struct perf_session *session,
1347 mmap_flags = MAP_PRIVATE; 1317 mmap_flags = MAP_PRIVATE;
1348 } 1318 }
1349remap: 1319remap:
1350 buf = mmap(NULL, mmap_size, mmap_prot, mmap_flags, session->fd, 1320 buf = mmap(NULL, mmap_size, mmap_prot, mmap_flags, fd,
1351 file_offset); 1321 file_offset);
1352 if (buf == MAP_FAILED) { 1322 if (buf == MAP_FAILED) {
1353 pr_err("failed to mmap file\n"); 1323 pr_err("failed to mmap file\n");
@@ -1392,13 +1362,13 @@ more:
1392 "Processing events..."); 1362 "Processing events...");
1393 } 1363 }
1394 1364
1395 err = 0;
1396 if (session_done()) 1365 if (session_done())
1397 goto out_err; 1366 goto out;
1398 1367
1399 if (file_pos < file_size) 1368 if (file_pos < file_size)
1400 goto more; 1369 goto more;
1401 1370
1371out:
1402 /* do the final flush for ordered samples */ 1372 /* do the final flush for ordered samples */
1403 session->ordered_samples.next_flush = ULLONG_MAX; 1373 session->ordered_samples.next_flush = ULLONG_MAX;
1404 err = flush_sample_queue(session, tool); 1374 err = flush_sample_queue(session, tool);
@@ -1412,16 +1382,17 @@ out_err:
1412int perf_session__process_events(struct perf_session *self, 1382int perf_session__process_events(struct perf_session *self,
1413 struct perf_tool *tool) 1383 struct perf_tool *tool)
1414{ 1384{
1385 u64 size = perf_data_file__size(self->file);
1415 int err; 1386 int err;
1416 1387
1417 if (perf_session__register_idle_thread(self) == NULL) 1388 if (perf_session__register_idle_thread(self) == NULL)
1418 return -ENOMEM; 1389 return -ENOMEM;
1419 1390
1420 if (!self->fd_pipe) 1391 if (!perf_data_file__is_pipe(self->file))
1421 err = __perf_session__process_events(self, 1392 err = __perf_session__process_events(self,
1422 self->header.data_offset, 1393 self->header.data_offset,
1423 self->header.data_size, 1394 self->header.data_size,
1424 self->size, tool); 1395 size, tool);
1425 else 1396 else
1426 err = __perf_session__process_pipe_events(self, tool); 1397 err = __perf_session__process_pipe_events(self, tool);
1427 1398
@@ -1541,7 +1512,8 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event,
1541 if (symbol_conf.use_callchain && sample->callchain) { 1512 if (symbol_conf.use_callchain && sample->callchain) {
1542 1513
1543 if (machine__resolve_callchain(machine, evsel, al.thread, 1514 if (machine__resolve_callchain(machine, evsel, al.thread,
1544 sample, NULL, NULL) != 0) { 1515 sample, NULL, NULL,
1516 PERF_MAX_STACK_DEPTH) != 0) {
1545 if (verbose) 1517 if (verbose)
1546 error("Failed to resolve callchain. Skipping\n"); 1518 error("Failed to resolve callchain. Skipping\n");
1547 return; 1519 return;
@@ -1645,13 +1617,14 @@ int perf_session__cpu_bitmap(struct perf_session *session,
1645void perf_session__fprintf_info(struct perf_session *session, FILE *fp, 1617void perf_session__fprintf_info(struct perf_session *session, FILE *fp,
1646 bool full) 1618 bool full)
1647{ 1619{
1620 int fd = perf_data_file__fd(session->file);
1648 struct stat st; 1621 struct stat st;
1649 int ret; 1622 int ret;
1650 1623
1651 if (session == NULL || fp == NULL) 1624 if (session == NULL || fp == NULL)
1652 return; 1625 return;
1653 1626
1654 ret = fstat(session->fd, &st); 1627 ret = fstat(fd, &st);
1655 if (ret == -1) 1628 if (ret == -1)
1656 return; 1629 return;
1657 1630
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 04bf7373a7e5..27c74d38b868 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -7,6 +7,7 @@
7#include "machine.h" 7#include "machine.h"
8#include "symbol.h" 8#include "symbol.h"
9#include "thread.h" 9#include "thread.h"
10#include "data.h"
10#include <linux/rbtree.h> 11#include <linux/rbtree.h>
11#include <linux/perf_event.h> 12#include <linux/perf_event.h>
12 13
@@ -29,16 +30,13 @@ struct ordered_samples {
29 30
30struct perf_session { 31struct perf_session {
31 struct perf_header header; 32 struct perf_header header;
32 unsigned long size;
33 struct machines machines; 33 struct machines machines;
34 struct perf_evlist *evlist; 34 struct perf_evlist *evlist;
35 struct pevent *pevent; 35 struct pevent *pevent;
36 struct events_stats stats; 36 struct events_stats stats;
37 int fd;
38 bool fd_pipe;
39 bool repipe; 37 bool repipe;
40 struct ordered_samples ordered_samples; 38 struct ordered_samples ordered_samples;
41 char filename[1]; 39 struct perf_data_file *file;
42}; 40};
43 41
44#define PRINT_IP_OPT_IP (1<<0) 42#define PRINT_IP_OPT_IP (1<<0)
@@ -49,9 +47,8 @@ struct perf_session {
49 47
50struct perf_tool; 48struct perf_tool;
51 49
52struct perf_session *perf_session__new(const char *filename, int mode, 50struct perf_session *perf_session__new(struct perf_data_file *file,
53 bool force, bool repipe, 51 bool repipe, struct perf_tool *tool);
54 struct perf_tool *tool);
55void perf_session__delete(struct perf_session *session); 52void perf_session__delete(struct perf_session *session);
56 53
57void perf_event_header__bswap(struct perf_event_header *self); 54void perf_event_header__bswap(struct perf_event_header *self);
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 32c56377e008..1f9821db9e77 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -182,9 +182,19 @@ static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r)
182static int64_t 182static int64_t
183sort__sym_cmp(struct hist_entry *left, struct hist_entry *right) 183sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
184{ 184{
185 int64_t ret;
186
185 if (!left->ms.sym && !right->ms.sym) 187 if (!left->ms.sym && !right->ms.sym)
186 return right->level - left->level; 188 return right->level - left->level;
187 189
190 /*
191 * comparing symbol address alone is not enough since it's a
192 * relative address within a dso.
193 */
194 ret = sort__dso_cmp(left, right);
195 if (ret != 0)
196 return ret;
197
188 return _sort__sym_cmp(left->ms.sym, right->ms.sym); 198 return _sort__sym_cmp(left->ms.sym, right->ms.sym);
189} 199}
190 200
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h
index b554ffc462b6..88cfeaff600b 100644
--- a/tools/perf/util/top.h
+++ b/tools/perf/util/top.h
@@ -24,6 +24,7 @@ struct perf_top {
24 u64 exact_samples; 24 u64 exact_samples;
25 u64 guest_us_samples, guest_kernel_samples; 25 u64 guest_us_samples, guest_kernel_samples;
26 int print_entries, count_filter, delay_secs; 26 int print_entries, count_filter, delay_secs;
27 int max_stack;
27 bool hide_kernel_symbols, hide_user_symbols, zero; 28 bool hide_kernel_symbols, hide_user_symbols, zero;
28 bool use_tui, use_stdio; 29 bool use_tui, use_stdio;
29 bool kptr_restrict_warned; 30 bool kptr_restrict_warned;
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 8dc8cf39f4ed..c25e57b3acb2 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -394,3 +394,20 @@ unsigned long parse_tag_value(const char *str, struct parse_tag *tags)
394 394
395 return (unsigned long) -1; 395 return (unsigned long) -1;
396} 396}
397
398int filename__read_int(const char *filename, int *value)
399{
400 char line[64];
401 int fd = open(filename, O_RDONLY), err = -1;
402
403 if (fd < 0)
404 return -1;
405
406 if (read(fd, line, sizeof(line)) > 0) {
407 *value = atoi(line);
408 err = 0;
409 }
410
411 close(fd);
412 return err;
413}
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 42dfba70fbfc..c8f362daba87 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -305,4 +305,6 @@ struct dso;
305 305
306char *get_srcline(struct dso *dso, unsigned long addr); 306char *get_srcline(struct dso *dso, unsigned long addr);
307void free_srcline(char *srcline); 307void free_srcline(char *srcline);
308
309int filename__read_int(const char *filename, int *value);
308#endif /* GIT_COMPAT_UTIL_H */ 310#endif /* GIT_COMPAT_UTIL_H */