aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--tools/perf/Documentation/perf-record.txt7
-rw-r--r--tools/perf/Documentation/perf-script.txt20
-rw-r--r--tools/perf/builtin-annotate.c2
-rw-r--r--tools/perf/builtin-diff.c12
-rw-r--r--tools/perf/builtin-record.c7
-rw-r--r--tools/perf/config/Makefile2
-rw-r--r--tools/perf/perf.c36
-rwxr-xr-xtools/perf/scripts/python/bin/stackcollapse-record8
-rwxr-xr-xtools/perf/scripts/python/bin/stackcollapse-report3
-rwxr-xr-xtools/perf/scripts/python/stackcollapse.py127
-rw-r--r--tools/perf/tests/hists_link.c4
-rw-r--r--tools/perf/util/cache.h9
-rw-r--r--tools/perf/util/config.c2
-rw-r--r--tools/perf/util/evsel.c23
-rw-r--r--tools/perf/util/hist.c34
-rw-r--r--tools/perf/util/hist.h14
-rw-r--r--tools/perf/util/llvm-utils.c42
-rw-r--r--tools/perf/util/llvm-utils.h5
-rw-r--r--tools/perf/util/path.c65
20 files changed, 251 insertions, 173 deletions
diff --git a/Makefile b/Makefile
index b409076c7c18..4a1fe88d6839 100644
--- a/Makefile
+++ b/Makefile
@@ -1038,7 +1038,7 @@ ifdef CONFIG_STACK_VALIDATION
1038 ifeq ($(has_libelf),1) 1038 ifeq ($(has_libelf),1)
1039 objtool_target := tools/objtool FORCE 1039 objtool_target := tools/objtool FORCE
1040 else 1040 else
1041 $(warning "Cannot use CONFIG_STACK_VALIDATION, please install libelf-dev or elfutils-libelf-devel") 1041 $(warning "Cannot use CONFIG_STACK_VALIDATION, please install libelf-dev, libelf-devel or elfutils-libelf-devel")
1042 SKIP_STACK_VALIDATION := 1 1042 SKIP_STACK_VALIDATION := 1
1043 export SKIP_STACK_VALIDATION 1043 export SKIP_STACK_VALIDATION
1044 endif 1044 endif
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index 8dbee832abd9..5b46b1d1a37c 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -360,6 +360,13 @@ particular perf.data snapshot should be kept or not.
360 360
361Implies --timestamp-filename, --no-buildid and --no-buildid-cache. 361Implies --timestamp-filename, --no-buildid and --no-buildid-cache.
362 362
363--dry-run::
364Parse options then exit. --dry-run can be used to detect errors in cmdline
365options.
366
367'perf record --dry-run -e' can act as a BPF script compiler if llvm.dump-obj
368in config file is set to true.
369
363SEE ALSO 370SEE ALSO
364-------- 371--------
365linkperf:perf-stat[1], linkperf:perf-list[1] 372linkperf:perf-stat[1], linkperf:perf-list[1]
diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt
index 4fc44c75263f..4f34379ebd77 100644
--- a/tools/perf/Documentation/perf-script.txt
+++ b/tools/perf/Documentation/perf-script.txt
@@ -119,13 +119,13 @@ OPTIONS
119 srcline, period, iregs, brstack, brstacksym, flags. 119 srcline, period, iregs, brstack, brstacksym, flags.
120 Field list can be prepended with the type, trace, sw or hw, 120 Field list can be prepended with the type, trace, sw or hw,
121 to indicate to which event type the field list applies. 121 to indicate to which event type the field list applies.
122 e.g., -f sw:comm,tid,time,ip,sym and -f trace:time,cpu,trace 122 e.g., -F sw:comm,tid,time,ip,sym and -F trace:time,cpu,trace
123 123
124 perf script -f <fields> 124 perf script -F <fields>
125 125
126 is equivalent to: 126 is equivalent to:
127 127
128 perf script -f trace:<fields> -f sw:<fields> -f hw:<fields> 128 perf script -F trace:<fields> -F sw:<fields> -F hw:<fields>
129 129
130 i.e., the specified fields apply to all event types if the type string 130 i.e., the specified fields apply to all event types if the type string
131 is not given. 131 is not given.
@@ -133,9 +133,9 @@ OPTIONS
133 The arguments are processed in the order received. A later usage can 133 The arguments are processed in the order received. A later usage can
134 reset a prior request. e.g.: 134 reset a prior request. e.g.:
135 135
136 -f trace: -f comm,tid,time,ip,sym 136 -F trace: -F comm,tid,time,ip,sym
137 137
138 The first -f suppresses trace events (field list is ""), but then the 138 The first -F suppresses trace events (field list is ""), but then the
139 second invocation sets the fields to comm,tid,time,ip,sym. In this case a 139 second invocation sets the fields to comm,tid,time,ip,sym. In this case a
140 warning is given to the user: 140 warning is given to the user:
141 141
@@ -143,9 +143,9 @@ OPTIONS
143 143
144 Alternatively, consider the order: 144 Alternatively, consider the order:
145 145
146 -f comm,tid,time,ip,sym -f trace: 146 -F comm,tid,time,ip,sym -F trace:
147 147
148 The first -f sets the fields for all events and the second -f 148 The first -F sets the fields for all events and the second -F
149 suppresses trace events. The user is given a warning message about 149 suppresses trace events. The user is given a warning message about
150 the override, and the result of the above is that only S/W and H/W 150 the override, and the result of the above is that only S/W and H/W
151 events are displayed with the given fields. 151 events are displayed with the given fields.
@@ -154,14 +154,14 @@ OPTIONS
154 event type, a message is displayed to the user that the option is 154 event type, a message is displayed to the user that the option is
155 ignored for that type. For example: 155 ignored for that type. For example:
156 156
157 $ perf script -f comm,tid,trace 157 $ perf script -F comm,tid,trace
158 'trace' not valid for hardware events. Ignoring. 158 'trace' not valid for hardware events. Ignoring.
159 'trace' not valid for software events. Ignoring. 159 'trace' not valid for software events. Ignoring.
160 160
161 Alternatively, if the type is given an invalid field is specified it 161 Alternatively, if the type is given an invalid field is specified it
162 is an error. For example: 162 is an error. For example:
163 163
164 perf script -v -f sw:comm,tid,trace 164 perf script -v -F sw:comm,tid,trace
165 'trace' not valid for software events. 165 'trace' not valid for software events.
166 166
167 At this point usage is displayed, and perf-script exits. 167 At this point usage is displayed, and perf-script exits.
@@ -173,7 +173,7 @@ OPTIONS
173 respectively. 173 respectively.
174 174
175 Finally, a user may not set fields to none for all event types. 175 Finally, a user may not set fields to none for all event types.
176 i.e., -f "" is not allowed. 176 i.e., -F "" is not allowed.
177 177
178 The brstack output includes branch related information with raw addresses using the 178 The brstack output includes branch related information with raw addresses using the
179 /v/v/v/v/ syntax in the following order: 179 /v/v/v/v/ syntax in the following order:
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 25c81734a950..a2324e1892aa 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -75,7 +75,7 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel,
75 sample->period = 1; 75 sample->period = 1;
76 sample->weight = 1; 76 sample->weight = 1;
77 77
78 he = __hists__add_entry(hists, al, NULL, NULL, NULL, sample, true); 78 he = hists__add_entry(hists, al, NULL, NULL, NULL, sample, true);
79 if (he == NULL) 79 if (he == NULL)
80 return -ENOMEM; 80 return -ENOMEM;
81 81
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index 7f628f9c2fb4..8b6735f35179 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -310,16 +310,6 @@ static int formula_fprintf(struct hist_entry *he, struct hist_entry *pair,
310 return -1; 310 return -1;
311} 311}
312 312
313static int hists__add_entry(struct hists *hists,
314 struct addr_location *al,
315 struct perf_sample *sample)
316{
317 if (__hists__add_entry(hists, al, NULL, NULL, NULL,
318 sample, true) != NULL)
319 return 0;
320 return -ENOMEM;
321}
322
323static int diff__process_sample_event(struct perf_tool *tool __maybe_unused, 313static int diff__process_sample_event(struct perf_tool *tool __maybe_unused,
324 union perf_event *event, 314 union perf_event *event,
325 struct perf_sample *sample, 315 struct perf_sample *sample,
@@ -336,7 +326,7 @@ static int diff__process_sample_event(struct perf_tool *tool __maybe_unused,
336 return -1; 326 return -1;
337 } 327 }
338 328
339 if (hists__add_entry(hists, &al, sample)) { 329 if (!hists__add_entry(hists, &al, NULL, NULL, NULL, sample, true)) {
340 pr_warning("problem incrementing symbol period, skipping event\n"); 330 pr_warning("problem incrementing symbol period, skipping event\n");
341 goto out_put; 331 goto out_put;
342 } 332 }
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index d4cf1b0c88f9..b1304ebc8779 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -1274,6 +1274,8 @@ static struct record record = {
1274const char record_callchain_help[] = CALLCHAIN_RECORD_HELP 1274const char record_callchain_help[] = CALLCHAIN_RECORD_HELP
1275 "\n\t\t\t\tDefault: fp"; 1275 "\n\t\t\t\tDefault: fp";
1276 1276
1277static bool dry_run;
1278
1277/* 1279/*
1278 * XXX Will stay a global variable till we fix builtin-script.c to stop messing 1280 * XXX Will stay a global variable till we fix builtin-script.c to stop messing
1279 * with it and switch to use the library functions in perf_evlist that came 1281 * with it and switch to use the library functions in perf_evlist that came
@@ -1393,6 +1395,8 @@ struct option __record_options[] = {
1393 "append timestamp to output filename"), 1395 "append timestamp to output filename"),
1394 OPT_BOOLEAN(0, "switch-output", &record.switch_output, 1396 OPT_BOOLEAN(0, "switch-output", &record.switch_output,
1395 "Switch output when receive SIGUSR2"), 1397 "Switch output when receive SIGUSR2"),
1398 OPT_BOOLEAN(0, "dry-run", &dry_run,
1399 "Parse options then exit"),
1396 OPT_END() 1400 OPT_END()
1397}; 1401};
1398 1402
@@ -1462,6 +1466,9 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
1462 if (err) 1466 if (err)
1463 return err; 1467 return err;
1464 1468
1469 if (dry_run)
1470 return 0;
1471
1465 err = bpf__setup_stdout(rec->evlist); 1472 err = bpf__setup_stdout(rec->evlist);
1466 if (err) { 1473 if (err) {
1467 bpf__strerror_setup_stdout(rec->evlist, err, errbuf, sizeof(errbuf)); 1474 bpf__strerror_setup_stdout(rec->evlist, err, errbuf, sizeof(errbuf));
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
index 80018feb99c0..534c81176f6c 100644
--- a/tools/perf/config/Makefile
+++ b/tools/perf/config/Makefile
@@ -257,7 +257,7 @@ else
257 LIBC_SUPPORT := 1 257 LIBC_SUPPORT := 1
258 endif 258 endif
259 ifeq ($(LIBC_SUPPORT),1) 259 ifeq ($(LIBC_SUPPORT),1)
260 msg := $(warning No libelf found, disables 'probe' tool and BPF support in 'perf record', please install elfutils-libelf-devel/libelf-dev); 260 msg := $(warning No libelf found, disables 'probe' tool and BPF support in 'perf record', please install libelf-dev, libelf-devel or elfutils-libelf-devel);
261 261
262 NO_LIBELF := 1 262 NO_LIBELF := 1
263 NO_DWARF := 1 263 NO_DWARF := 1
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 15982cee5ef3..634bf7c6c477 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -139,8 +139,6 @@ struct option options[] = {
139 OPT_ARGUMENT("html-path", "html-path"), 139 OPT_ARGUMENT("html-path", "html-path"),
140 OPT_ARGUMENT("paginate", "paginate"), 140 OPT_ARGUMENT("paginate", "paginate"),
141 OPT_ARGUMENT("no-pager", "no-pager"), 141 OPT_ARGUMENT("no-pager", "no-pager"),
142 OPT_ARGUMENT("perf-dir", "perf-dir"),
143 OPT_ARGUMENT("work-tree", "work-tree"),
144 OPT_ARGUMENT("debugfs-dir", "debugfs-dir"), 142 OPT_ARGUMENT("debugfs-dir", "debugfs-dir"),
145 OPT_ARGUMENT("buildid-dir", "buildid-dir"), 143 OPT_ARGUMENT("buildid-dir", "buildid-dir"),
146 OPT_ARGUMENT("list-cmds", "list-cmds"), 144 OPT_ARGUMENT("list-cmds", "list-cmds"),
@@ -200,35 +198,6 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
200 use_pager = 0; 198 use_pager = 0;
201 if (envchanged) 199 if (envchanged)
202 *envchanged = 1; 200 *envchanged = 1;
203 } else if (!strcmp(cmd, "--perf-dir")) {
204 if (*argc < 2) {
205 fprintf(stderr, "No directory given for --perf-dir.\n");
206 usage(perf_usage_string);
207 }
208 setenv(PERF_DIR_ENVIRONMENT, (*argv)[1], 1);
209 if (envchanged)
210 *envchanged = 1;
211 (*argv)++;
212 (*argc)--;
213 handled++;
214 } else if (!prefixcmp(cmd, CMD_PERF_DIR)) {
215 setenv(PERF_DIR_ENVIRONMENT, cmd + strlen(CMD_PERF_DIR), 1);
216 if (envchanged)
217 *envchanged = 1;
218 } else if (!strcmp(cmd, "--work-tree")) {
219 if (*argc < 2) {
220 fprintf(stderr, "No directory given for --work-tree.\n");
221 usage(perf_usage_string);
222 }
223 setenv(PERF_WORK_TREE_ENVIRONMENT, (*argv)[1], 1);
224 if (envchanged)
225 *envchanged = 1;
226 (*argv)++;
227 (*argc)--;
228 } else if (!prefixcmp(cmd, CMD_WORK_TREE)) {
229 setenv(PERF_WORK_TREE_ENVIRONMENT, cmd + strlen(CMD_WORK_TREE), 1);
230 if (envchanged)
231 *envchanged = 1;
232 } else if (!strcmp(cmd, "--debugfs-dir")) { 201 } else if (!strcmp(cmd, "--debugfs-dir")) {
233 if (*argc < 2) { 202 if (*argc < 2) {
234 fprintf(stderr, "No directory given for --debugfs-dir.\n"); 203 fprintf(stderr, "No directory given for --debugfs-dir.\n");
@@ -363,11 +332,6 @@ const char perf_version_string[] = PERF_VERSION;
363 332
364#define RUN_SETUP (1<<0) 333#define RUN_SETUP (1<<0)
365#define USE_PAGER (1<<1) 334#define USE_PAGER (1<<1)
366/*
367 * require working tree to be present -- anything uses this needs
368 * RUN_SETUP for reading from the configuration file.
369 */
370#define NEED_WORK_TREE (1<<2)
371 335
372static int run_builtin(struct cmd_struct *p, int argc, const char **argv) 336static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
373{ 337{
diff --git a/tools/perf/scripts/python/bin/stackcollapse-record b/tools/perf/scripts/python/bin/stackcollapse-record
new file mode 100755
index 000000000000..9d8f9f0f3a17
--- /dev/null
+++ b/tools/perf/scripts/python/bin/stackcollapse-record
@@ -0,0 +1,8 @@
1#!/bin/sh
2
3#
4# stackcollapse.py can cover all type of perf samples including
5# the tracepoints, so no special record requirements, just record what
6# you want to analyze.
7#
8perf record "$@"
diff --git a/tools/perf/scripts/python/bin/stackcollapse-report b/tools/perf/scripts/python/bin/stackcollapse-report
new file mode 100755
index 000000000000..356b9656393d
--- /dev/null
+++ b/tools/perf/scripts/python/bin/stackcollapse-report
@@ -0,0 +1,3 @@
1#!/bin/sh
2# description: produce callgraphs in short form for scripting use
3perf script -s "$PERF_EXEC_PATH"/scripts/python/stackcollapse.py -- "$@"
diff --git a/tools/perf/scripts/python/stackcollapse.py b/tools/perf/scripts/python/stackcollapse.py
new file mode 100755
index 000000000000..a2dfcda41ae6
--- /dev/null
+++ b/tools/perf/scripts/python/stackcollapse.py
@@ -0,0 +1,127 @@
1#!/usr/bin/perl -w
2#
3# stackcollapse.py - format perf samples with one line per distinct call stack
4#
5# This script's output has two space-separated fields. The first is a semicolon
6# separated stack including the program name (from the "comm" field) and the
7# function names from the call stack. The second is a count:
8#
9# swapper;start_kernel;rest_init;cpu_idle;default_idle;native_safe_halt 2
10#
11# The file is sorted according to the first field.
12#
13# Input may be created and processed using:
14#
15# perf record -a -g -F 99 sleep 60
16# perf script report stackcollapse > out.stacks-folded
17#
18# (perf script record stackcollapse works too).
19#
20# Written by Paolo Bonzini <pbonzini@redhat.com>
21# Based on Brendan Gregg's stackcollapse-perf.pl script.
22
23import os
24import sys
25from collections import defaultdict
26from optparse import OptionParser, make_option
27
28sys.path.append(os.environ['PERF_EXEC_PATH'] + \
29 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
30
31from perf_trace_context import *
32from Core import *
33from EventClass import *
34
35# command line parsing
36
37option_list = [
38 # formatting options for the bottom entry of the stack
39 make_option("--include-tid", dest="include_tid",
40 action="store_true", default=False,
41 help="include thread id in stack"),
42 make_option("--include-pid", dest="include_pid",
43 action="store_true", default=False,
44 help="include process id in stack"),
45 make_option("--no-comm", dest="include_comm",
46 action="store_false", default=True,
47 help="do not separate stacks according to comm"),
48 make_option("--tidy-java", dest="tidy_java",
49 action="store_true", default=False,
50 help="beautify Java signatures"),
51 make_option("--kernel", dest="annotate_kernel",
52 action="store_true", default=False,
53 help="annotate kernel functions with _[k]")
54]
55
56parser = OptionParser(option_list=option_list)
57(opts, args) = parser.parse_args()
58
59if len(args) != 0:
60 parser.error("unexpected command line argument")
61if opts.include_tid and not opts.include_comm:
62 parser.error("requesting tid but not comm is invalid")
63if opts.include_pid and not opts.include_comm:
64 parser.error("requesting pid but not comm is invalid")
65
66# event handlers
67
68lines = defaultdict(lambda: 0)
69
70def process_event(param_dict):
71 def tidy_function_name(sym, dso):
72 if sym is None:
73 sym = '[unknown]'
74
75 sym = sym.replace(';', ':')
76 if opts.tidy_java:
77 # the original stackcollapse-perf.pl script gives the
78 # example of converting this:
79 # Lorg/mozilla/javascript/MemberBox;.<init>(Ljava/lang/reflect/Method;)V
80 # to this:
81 # org/mozilla/javascript/MemberBox:.init
82 sym = sym.replace('<', '')
83 sym = sym.replace('>', '')
84 if sym[0] == 'L' and sym.find('/'):
85 sym = sym[1:]
86 try:
87 sym = sym[:sym.index('(')]
88 except ValueError:
89 pass
90
91 if opts.annotate_kernel and dso == '[kernel.kallsyms]':
92 return sym + '_[k]'
93 else:
94 return sym
95
96 stack = list()
97 if 'callchain' in param_dict:
98 for entry in param_dict['callchain']:
99 entry.setdefault('sym', dict())
100 entry['sym'].setdefault('name', None)
101 entry.setdefault('dso', None)
102 stack.append(tidy_function_name(entry['sym']['name'],
103 entry['dso']))
104 else:
105 param_dict.setdefault('symbol', None)
106 param_dict.setdefault('dso', None)
107 stack.append(tidy_function_name(param_dict['symbol'],
108 param_dict['dso']))
109
110 if opts.include_comm:
111 comm = param_dict["comm"].replace(' ', '_')
112 sep = "-"
113 if opts.include_pid:
114 comm = comm + sep + str(param_dict['sample']['pid'])
115 sep = "/"
116 if opts.include_tid:
117 comm = comm + sep + str(param_dict['sample']['tid'])
118 stack.append(comm)
119
120 stack_string = ';'.join(reversed(stack))
121 lines[stack_string] = lines[stack_string] + 1
122
123def trace_end():
124 list = lines.keys()
125 list.sort()
126 for stack in list:
127 print "%s %d" % (stack, lines[stack])
diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c
index acf5a1301c07..6f96ca4d4fc0 100644
--- a/tools/perf/tests/hists_link.c
+++ b/tools/perf/tests/hists_link.c
@@ -84,7 +84,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
84 if (machine__resolve(machine, &al, &sample) < 0) 84 if (machine__resolve(machine, &al, &sample) < 0)
85 goto out; 85 goto out;
86 86
87 he = __hists__add_entry(hists, &al, NULL, 87 he = hists__add_entry(hists, &al, NULL,
88 NULL, NULL, &sample, true); 88 NULL, NULL, &sample, true);
89 if (he == NULL) { 89 if (he == NULL) {
90 addr_location__put(&al); 90 addr_location__put(&al);
@@ -103,7 +103,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
103 if (machine__resolve(machine, &al, &sample) < 0) 103 if (machine__resolve(machine, &al, &sample) < 0)
104 goto out; 104 goto out;
105 105
106 he = __hists__add_entry(hists, &al, NULL, 106 he = hists__add_entry(hists, &al, NULL,
107 NULL, NULL, &sample, true); 107 NULL, NULL, &sample, true);
108 if (he == NULL) { 108 if (he == NULL) {
109 addr_location__put(&al); 109 addr_location__put(&al);
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h
index 0d814bb74661..369f382eedb6 100644
--- a/tools/perf/util/cache.h
+++ b/tools/perf/util/cache.h
@@ -11,14 +11,9 @@
11#include <linux/string.h> 11#include <linux/string.h>
12 12
13#define CMD_EXEC_PATH "--exec-path" 13#define CMD_EXEC_PATH "--exec-path"
14#define CMD_PERF_DIR "--perf-dir="
15#define CMD_WORK_TREE "--work-tree="
16#define CMD_DEBUGFS_DIR "--debugfs-dir=" 14#define CMD_DEBUGFS_DIR "--debugfs-dir="
17 15
18#define PERF_DIR_ENVIRONMENT "PERF_DIR"
19#define PERF_WORK_TREE_ENVIRONMENT "PERF_WORK_TREE"
20#define EXEC_PATH_ENVIRONMENT "PERF_EXEC_PATH" 16#define EXEC_PATH_ENVIRONMENT "PERF_EXEC_PATH"
21#define DEFAULT_PERF_DIR_ENVIRONMENT ".perf"
22#define PERF_DEBUGFS_ENVIRONMENT "PERF_DEBUGFS_DIR" 17#define PERF_DEBUGFS_ENVIRONMENT "PERF_DEBUGFS_DIR"
23#define PERF_TRACEFS_ENVIRONMENT "PERF_TRACEFS_DIR" 18#define PERF_TRACEFS_ENVIRONMENT "PERF_TRACEFS_DIR"
24#define PERF_PAGER_ENVIRONMENT "PERF_PAGER" 19#define PERF_PAGER_ENVIRONMENT "PERF_PAGER"
@@ -32,7 +27,6 @@ int perf_config_int(const char *, const char *);
32u64 perf_config_u64(const char *, const char *); 27u64 perf_config_u64(const char *, const char *);
33int perf_config_bool(const char *, const char *); 28int perf_config_bool(const char *, const char *);
34int config_error_nonbool(const char *); 29int config_error_nonbool(const char *);
35const char *perf_config_dirname(const char *, const char *);
36const char *perf_etc_perfconfig(void); 30const char *perf_etc_perfconfig(void);
37 31
38char *alias_lookup(const char *alias); 32char *alias_lookup(const char *alias);
@@ -45,9 +39,6 @@ static inline int is_absolute_path(const char *path)
45 return path[0] == '/'; 39 return path[0] == '/';
46} 40}
47 41
48char *strip_path_suffix(const char *path, const char *suffix);
49
50char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2))); 42char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
51char *perf_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
52 43
53#endif /* __PERF_CACHE_H */ 44#endif /* __PERF_CACHE_H */
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
index 31e09a4e8862..d15c59267644 100644
--- a/tools/perf/util/config.c
+++ b/tools/perf/util/config.c
@@ -372,7 +372,7 @@ int perf_config_bool(const char *name, const char *value)
372 return !!perf_config_bool_or_int(name, value, &discard); 372 return !!perf_config_bool_or_int(name, value, &discard);
373} 373}
374 374
375const char *perf_config_dirname(const char *name, const char *value) 375static const char *perf_config_dirname(const char *name, const char *value)
376{ 376{
377 if (!name) 377 if (!name)
378 return NULL; 378 return NULL;
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 9b2e3e624efe..1d8f2bbd38a7 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -1389,8 +1389,11 @@ fallback_missing_features:
1389 if (perf_missing_features.lbr_flags) 1389 if (perf_missing_features.lbr_flags)
1390 evsel->attr.branch_sample_type &= ~(PERF_SAMPLE_BRANCH_NO_FLAGS | 1390 evsel->attr.branch_sample_type &= ~(PERF_SAMPLE_BRANCH_NO_FLAGS |
1391 PERF_SAMPLE_BRANCH_NO_CYCLES); 1391 PERF_SAMPLE_BRANCH_NO_CYCLES);
1392 if (perf_missing_features.write_backward) 1392 if (perf_missing_features.write_backward) {
1393 if (evsel->overwrite)
1394 return -EINVAL;
1393 evsel->attr.write_backward = false; 1395 evsel->attr.write_backward = false;
1396 }
1394retry_sample_id: 1397retry_sample_id:
1395 if (perf_missing_features.sample_id_all) 1398 if (perf_missing_features.sample_id_all)
1396 evsel->attr.sample_id_all = 0; 1399 evsel->attr.sample_id_all = 0;
@@ -1453,12 +1456,6 @@ retry_open:
1453 err = -EINVAL; 1456 err = -EINVAL;
1454 goto out_close; 1457 goto out_close;
1455 } 1458 }
1456
1457 if (evsel->overwrite &&
1458 perf_missing_features.write_backward) {
1459 err = -EINVAL;
1460 goto out_close;
1461 }
1462 } 1459 }
1463 } 1460 }
1464 1461
@@ -1496,7 +1493,10 @@ try_fallback:
1496 * Must probe features in the order they were added to the 1493 * Must probe features in the order they were added to the
1497 * perf_event_attr interface. 1494 * perf_event_attr interface.
1498 */ 1495 */
1499 if (!perf_missing_features.clockid_wrong && evsel->attr.use_clockid) { 1496 if (!perf_missing_features.write_backward && evsel->attr.write_backward) {
1497 perf_missing_features.write_backward = true;
1498 goto fallback_missing_features;
1499 } else if (!perf_missing_features.clockid_wrong && evsel->attr.use_clockid) {
1500 perf_missing_features.clockid_wrong = true; 1500 perf_missing_features.clockid_wrong = true;
1501 goto fallback_missing_features; 1501 goto fallback_missing_features;
1502 } else if (!perf_missing_features.clockid && evsel->attr.use_clockid) { 1502 } else if (!perf_missing_features.clockid && evsel->attr.use_clockid) {
@@ -1521,12 +1521,7 @@ try_fallback:
1521 PERF_SAMPLE_BRANCH_NO_FLAGS))) { 1521 PERF_SAMPLE_BRANCH_NO_FLAGS))) {
1522 perf_missing_features.lbr_flags = true; 1522 perf_missing_features.lbr_flags = true;
1523 goto fallback_missing_features; 1523 goto fallback_missing_features;
1524 } else if (!perf_missing_features.write_backward &&
1525 evsel->attr.write_backward) {
1526 perf_missing_features.write_backward = true;
1527 goto fallback_missing_features;
1528 } 1524 }
1529
1530out_close: 1525out_close:
1531 do { 1526 do {
1532 while (--thread >= 0) { 1527 while (--thread >= 0) {
@@ -2409,6 +2404,8 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target,
2409 "We found oprofile daemon running, please stop it and try again."); 2404 "We found oprofile daemon running, please stop it and try again.");
2410 break; 2405 break;
2411 case EINVAL: 2406 case EINVAL:
2407 if (evsel->overwrite && perf_missing_features.write_backward)
2408 return scnprintf(msg, size, "Reading from overwrite event is not supported by this kernel.");
2412 if (perf_missing_features.clockid) 2409 if (perf_missing_features.clockid)
2413 return scnprintf(msg, size, "clockid feature not supported."); 2410 return scnprintf(msg, size, "clockid feature not supported.");
2414 if (perf_missing_features.clockid_wrong) 2411 if (perf_missing_features.clockid_wrong)
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 2515cfdb7365..d2647b1d82c0 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -531,13 +531,13 @@ out:
531 return he; 531 return he;
532} 532}
533 533
534struct hist_entry *__hists__add_entry(struct hists *hists, 534struct hist_entry *hists__add_entry(struct hists *hists,
535 struct addr_location *al, 535 struct addr_location *al,
536 struct symbol *sym_parent, 536 struct symbol *sym_parent,
537 struct branch_info *bi, 537 struct branch_info *bi,
538 struct mem_info *mi, 538 struct mem_info *mi,
539 struct perf_sample *sample, 539 struct perf_sample *sample,
540 bool sample_self) 540 bool sample_self)
541{ 541{
542 struct hist_entry entry = { 542 struct hist_entry entry = {
543 .thread = al->thread, 543 .thread = al->thread,
@@ -622,8 +622,8 @@ iter_add_single_mem_entry(struct hist_entry_iter *iter, struct addr_location *al
622 */ 622 */
623 sample->period = cost; 623 sample->period = cost;
624 624
625 he = __hists__add_entry(hists, al, iter->parent, NULL, mi, 625 he = hists__add_entry(hists, al, iter->parent, NULL, mi,
626 sample, true); 626 sample, true);
627 if (!he) 627 if (!he)
628 return -ENOMEM; 628 return -ENOMEM;
629 629
@@ -727,8 +727,8 @@ iter_add_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *a
727 sample->period = 1; 727 sample->period = 1;
728 sample->weight = bi->flags.cycles ? bi->flags.cycles : 1; 728 sample->weight = bi->flags.cycles ? bi->flags.cycles : 1;
729 729
730 he = __hists__add_entry(hists, al, iter->parent, &bi[i], NULL, 730 he = hists__add_entry(hists, al, iter->parent, &bi[i], NULL,
731 sample, true); 731 sample, true);
732 if (he == NULL) 732 if (he == NULL)
733 return -ENOMEM; 733 return -ENOMEM;
734 734
@@ -764,8 +764,8 @@ iter_add_single_normal_entry(struct hist_entry_iter *iter, struct addr_location
764 struct perf_sample *sample = iter->sample; 764 struct perf_sample *sample = iter->sample;
765 struct hist_entry *he; 765 struct hist_entry *he;
766 766
767 he = __hists__add_entry(evsel__hists(evsel), al, iter->parent, NULL, NULL, 767 he = hists__add_entry(evsel__hists(evsel), al, iter->parent, NULL, NULL,
768 sample, true); 768 sample, true);
769 if (he == NULL) 769 if (he == NULL)
770 return -ENOMEM; 770 return -ENOMEM;
771 771
@@ -825,8 +825,8 @@ iter_add_single_cumulative_entry(struct hist_entry_iter *iter,
825 struct hist_entry *he; 825 struct hist_entry *he;
826 int err = 0; 826 int err = 0;
827 827
828 he = __hists__add_entry(hists, al, iter->parent, NULL, NULL, 828 he = hists__add_entry(hists, al, iter->parent, NULL, NULL,
829 sample, true); 829 sample, true);
830 if (he == NULL) 830 if (he == NULL)
831 return -ENOMEM; 831 return -ENOMEM;
832 832
@@ -900,8 +900,8 @@ iter_add_next_cumulative_entry(struct hist_entry_iter *iter,
900 } 900 }
901 } 901 }
902 902
903 he = __hists__add_entry(evsel__hists(evsel), al, iter->parent, NULL, NULL, 903 he = hists__add_entry(evsel__hists(evsel), al, iter->parent, NULL, NULL,
904 sample, false); 904 sample, false);
905 if (he == NULL) 905 if (he == NULL)
906 return -ENOMEM; 906 return -ENOMEM;
907 907
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index a19112872ff9..0a03e08be503 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -120,13 +120,13 @@ extern const struct hist_iter_ops hist_iter_branch;
120extern const struct hist_iter_ops hist_iter_mem; 120extern const struct hist_iter_ops hist_iter_mem;
121extern const struct hist_iter_ops hist_iter_cumulative; 121extern const struct hist_iter_ops hist_iter_cumulative;
122 122
123struct hist_entry *__hists__add_entry(struct hists *hists, 123struct hist_entry *hists__add_entry(struct hists *hists,
124 struct addr_location *al, 124 struct addr_location *al,
125 struct symbol *parent, 125 struct symbol *parent,
126 struct branch_info *bi, 126 struct branch_info *bi,
127 struct mem_info *mi, 127 struct mem_info *mi,
128 struct perf_sample *sample, 128 struct perf_sample *sample,
129 bool sample_self); 129 bool sample_self);
130int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al, 130int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al,
131 int max_stack_depth, void *arg); 131 int max_stack_depth, void *arg);
132 132
diff --git a/tools/perf/util/llvm-utils.c b/tools/perf/util/llvm-utils.c
index 33071d6159bc..878a566763c3 100644
--- a/tools/perf/util/llvm-utils.c
+++ b/tools/perf/util/llvm-utils.c
@@ -42,6 +42,8 @@ int perf_llvm_config(const char *var, const char *value)
42 llvm_param.kbuild_dir = strdup(value); 42 llvm_param.kbuild_dir = strdup(value);
43 else if (!strcmp(var, "kbuild-opts")) 43 else if (!strcmp(var, "kbuild-opts"))
44 llvm_param.kbuild_opts = strdup(value); 44 llvm_param.kbuild_opts = strdup(value);
45 else if (!strcmp(var, "dump-obj"))
46 llvm_param.dump_obj = !!perf_config_bool(var, value);
45 else 47 else
46 return -1; 48 return -1;
47 llvm_param.user_set_param = true; 49 llvm_param.user_set_param = true;
@@ -326,6 +328,42 @@ get_kbuild_opts(char **kbuild_dir, char **kbuild_include_opts)
326 pr_debug("include option is set to %s\n", *kbuild_include_opts); 328 pr_debug("include option is set to %s\n", *kbuild_include_opts);
327} 329}
328 330
331static void
332dump_obj(const char *path, void *obj_buf, size_t size)
333{
334 char *obj_path = strdup(path);
335 FILE *fp;
336 char *p;
337
338 if (!obj_path) {
339 pr_warning("WARNING: No enough memory, skip object dumping\n");
340 return;
341 }
342
343 p = strrchr(obj_path, '.');
344 if (!p || (strcmp(p, ".c") != 0)) {
345 pr_warning("WARNING: invalid llvm source path: '%s', skip object dumping\n",
346 obj_path);
347 goto out;
348 }
349
350 p[1] = 'o';
351 fp = fopen(obj_path, "wb");
352 if (!fp) {
353 pr_warning("WARNING: failed to open '%s': %s, skip object dumping\n",
354 obj_path, strerror(errno));
355 goto out;
356 }
357
358 pr_info("LLVM: dumping %s\n", obj_path);
359 if (fwrite(obj_buf, size, 1, fp) != 1)
360 pr_warning("WARNING: failed to write to file '%s': %s, skip object dumping\n",
361 obj_path, strerror(errno));
362 fclose(fp);
363out:
364 free(obj_path);
365}
366
329int llvm__compile_bpf(const char *path, void **p_obj_buf, 367int llvm__compile_bpf(const char *path, void **p_obj_buf,
330 size_t *p_obj_buf_sz) 368 size_t *p_obj_buf_sz)
331{ 369{
@@ -411,6 +449,10 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf,
411 449
412 free(kbuild_dir); 450 free(kbuild_dir);
413 free(kbuild_include_opts); 451 free(kbuild_include_opts);
452
453 if (llvm_param.dump_obj)
454 dump_obj(path, obj_buf, obj_buf_sz);
455
414 if (!p_obj_buf) 456 if (!p_obj_buf)
415 free(obj_buf); 457 free(obj_buf);
416 else 458 else
diff --git a/tools/perf/util/llvm-utils.h b/tools/perf/util/llvm-utils.h
index 23b9a743fe72..9f501cef06a1 100644
--- a/tools/perf/util/llvm-utils.h
+++ b/tools/perf/util/llvm-utils.h
@@ -30,6 +30,11 @@ struct llvm_param {
30 */ 30 */
31 const char *kbuild_opts; 31 const char *kbuild_opts;
32 /* 32 /*
33 * Default is false. If set to true, write compiling result
34 * to object file.
35 */
36 bool dump_obj;
37 /*
33 * Default is false. If one of the above fields is set by user 38 * Default is false. If one of the above fields is set by user
34 * explicitly then user_set_llvm is set to true. This is used 39 * explicitly then user_set_llvm is set to true. This is used
35 * for perf test. If user doesn't set anything in .perfconfig 40 * for perf test. If user doesn't set anything in .perfconfig
diff --git a/tools/perf/util/path.c b/tools/perf/util/path.c
index 3bf6bf82ff2d..cff8bf0f87e8 100644
--- a/tools/perf/util/path.c
+++ b/tools/perf/util/path.c
@@ -14,14 +14,8 @@
14 14
15static char bad_path[] = "/bad-path/"; 15static char bad_path[] = "/bad-path/";
16/* 16/*
17 * Two hacks: 17 * One hack:
18 */ 18 */
19
20static const char *get_perf_dir(void)
21{
22 return ".";
23}
24
25static char *get_pathname(void) 19static char *get_pathname(void)
26{ 20{
27 static char pathname_array[4][PATH_MAX]; 21 static char pathname_array[4][PATH_MAX];
@@ -54,60 +48,3 @@ char *mkpath(const char *fmt, ...)
54 return bad_path; 48 return bad_path;
55 return cleanup_path(pathname); 49 return cleanup_path(pathname);
56} 50}
57
58char *perf_path(const char *fmt, ...)
59{
60 const char *perf_dir = get_perf_dir();
61 char *pathname = get_pathname();
62 va_list args;
63 unsigned len;
64
65 len = strlen(perf_dir);
66 if (len > PATH_MAX-100)
67 return bad_path;
68 memcpy(pathname, perf_dir, len);
69 if (len && perf_dir[len-1] != '/')
70 pathname[len++] = '/';
71 va_start(args, fmt);
72 len += vsnprintf(pathname + len, PATH_MAX - len, fmt, args);
73 va_end(args);
74 if (len >= PATH_MAX)
75 return bad_path;
76 return cleanup_path(pathname);
77}
78
79/* strip arbitrary amount of directory separators at end of path */
80static inline int chomp_trailing_dir_sep(const char *path, int len)
81{
82 while (len && is_dir_sep(path[len - 1]))
83 len--;
84 return len;
85}
86
87/*
88 * If path ends with suffix (complete path components), returns the
89 * part before suffix (sans trailing directory separators).
90 * Otherwise returns NULL.
91 */
92char *strip_path_suffix(const char *path, const char *suffix)
93{
94 int path_len = strlen(path), suffix_len = strlen(suffix);
95
96 while (suffix_len) {
97 if (!path_len)
98 return NULL;
99
100 if (is_dir_sep(path[path_len - 1])) {
101 if (!is_dir_sep(suffix[suffix_len - 1]))
102 return NULL;
103 path_len = chomp_trailing_dir_sep(path, path_len);
104 suffix_len = chomp_trailing_dir_sep(suffix, suffix_len);
105 }
106 else if (path[--path_len] != suffix[--suffix_len])
107 return NULL;
108 }
109
110 if (path_len && !is_dir_sep(path[path_len - 1]))
111 return NULL;
112 return strndup(path, chomp_trailing_dir_sep(path, path_len));
113}