aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2014-10-16 01:15:45 -0400
committerIngo Molnar <mingo@kernel.org>2014-10-16 01:15:45 -0400
commit71c62b24fe88e4d3f5470207426e94345ca94c83 (patch)
tree2e2abafb2a325803af41de4f50a399c06c270c7a /tools
parentec4212d88a77eb6caec10777ddd629b702a5ebbd (diff)
parent673d659f5c5918b7ddbafebf1f129c9eb82973b4 (diff)
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/urgent
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo: User visible changes: * Add a visual cue for toggle zeroing of samples in 'perf top' (Taeung Song) * Fix for double free in 'perf stat' when using some specific invalid command line combo (Yasser Shalabi) Infrastructure changes: * Add option to copy events when queuing for sorting across cpu buffers and enable it for 'perf kvm stat live', to avoid having events left in the queue pointing to the ring buffer be rewritten in high volume sessions. (Alexander Yarygin, improving work done by David Ahern): * Document sysfs events/ interfaces (Cody P Schafer) * Add support to new style format of kernel PMU event. (Kan Liang) * Fix typos in perf/Documentation (Masanari Iida) * Improve callchains when using libunwind (Namhyung Kim) 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-diff.txt6
-rw-r--r--tools/perf/Documentation/perf-kvm.txt4
-rw-r--r--tools/perf/Documentation/perf-list.txt2
-rw-r--r--tools/perf/Documentation/perf-record.txt2
-rw-r--r--tools/perf/Documentation/perf-script-perl.txt4
-rw-r--r--tools/perf/Documentation/perf-script-python.txt6
-rw-r--r--tools/perf/Documentation/perf-script.txt2
-rw-r--r--tools/perf/Documentation/perf-test.txt2
-rw-r--r--tools/perf/Documentation/perf-trace.txt2
-rw-r--r--tools/perf/builtin-kvm.c7
-rw-r--r--tools/perf/builtin-report.c7
-rw-r--r--tools/perf/builtin-trace.c16
-rw-r--r--tools/perf/tests/dwarf-unwind.c3
-rw-r--r--tools/perf/tests/parse-events.c36
-rw-r--r--tools/perf/ui/browsers/hists.c32
-rw-r--r--tools/perf/util/evlist.c1
-rw-r--r--tools/perf/util/include/linux/string.h1
-rw-r--r--tools/perf/util/ordered-events.c49
-rw-r--r--tools/perf/util/ordered-events.h10
-rw-r--r--tools/perf/util/parse-events.c133
-rw-r--r--tools/perf/util/parse-events.h14
-rw-r--r--tools/perf/util/parse-events.l30
-rw-r--r--tools/perf/util/parse-events.y40
-rw-r--r--tools/perf/util/pmu.c10
-rw-r--r--tools/perf/util/pmu.h10
-rw-r--r--tools/perf/util/session.c5
-rw-r--r--tools/perf/util/string.c24
-rw-r--r--tools/perf/util/thread.c6
-rw-r--r--tools/perf/util/unwind-libunwind.c37
-rw-r--r--tools/perf/util/unwind.h17
30 files changed, 411 insertions, 107 deletions
diff --git a/tools/perf/Documentation/perf-diff.txt b/tools/perf/Documentation/perf-diff.txt
index b3b8abae62b8..e463caa3eb49 100644
--- a/tools/perf/Documentation/perf-diff.txt
+++ b/tools/perf/Documentation/perf-diff.txt
@@ -196,10 +196,10 @@ If specified the 'Weighted diff' column is displayed with value 'd' computed as:
196 196
197 - period being the hist entry period value 197 - period being the hist entry period value
198 198
199 - WEIGHT-A/WEIGHT-B being user suplied weights in the the '-c' option 199 - WEIGHT-A/WEIGHT-B being user supplied weights in the the '-c' option
200 behind ':' separator like '-c wdiff:1,2'. 200 behind ':' separator like '-c wdiff:1,2'.
201 - WIEGHT-A being the weight of the data file 201 - WEIGHT-A being the weight of the data file
202 - WIEGHT-B being the weight of the baseline data file 202 - WEIGHT-B being the weight of the baseline data file
203 203
204SEE ALSO 204SEE ALSO
205-------- 205--------
diff --git a/tools/perf/Documentation/perf-kvm.txt b/tools/perf/Documentation/perf-kvm.txt
index 6e689dc89a2f..6252e776009c 100644
--- a/tools/perf/Documentation/perf-kvm.txt
+++ b/tools/perf/Documentation/perf-kvm.txt
@@ -100,7 +100,7 @@ OPTIONS
100STAT REPORT OPTIONS 100STAT REPORT OPTIONS
101------------------- 101-------------------
102--vcpu=<value>:: 102--vcpu=<value>::
103 analyze events which occures on this vcpu. (default: all vcpus) 103 analyze events which occur on this vcpu. (default: all vcpus)
104 104
105--event=<value>:: 105--event=<value>::
106 event to be analyzed. Possible values: vmexit, mmio (x86 only), 106 event to be analyzed. Possible values: vmexit, mmio (x86 only),
@@ -134,7 +134,7 @@ STAT LIVE OPTIONS
134 Analyze events only for given process ID(s) (comma separated list). 134 Analyze events only for given process ID(s) (comma separated list).
135 135
136--vcpu=<value>:: 136--vcpu=<value>::
137 analyze events which occures on this vcpu. (default: all vcpus) 137 analyze events which occur on this vcpu. (default: all vcpus)
138 138
139 139
140--event=<value>:: 140--event=<value>::
diff --git a/tools/perf/Documentation/perf-list.txt b/tools/perf/Documentation/perf-list.txt
index 6fce6a622206..cbb4f743d921 100644
--- a/tools/perf/Documentation/perf-list.txt
+++ b/tools/perf/Documentation/perf-list.txt
@@ -19,7 +19,7 @@ various perf commands with the -e option.
19EVENT MODIFIERS 19EVENT MODIFIERS
20--------------- 20---------------
21 21
22Events can optionally have a modifer by appending a colon and one or 22Events can optionally have a modifier by appending a colon and one or
23more modifiers. Modifiers allow the user to restrict the events to be 23more modifiers. Modifiers allow the user to restrict the events to be
24counted. The following modifiers exist: 24counted. The following modifiers exist:
25 25
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index d460049cae8e..398f8d53bd6d 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -146,7 +146,7 @@ the thread executes on the designated CPUs. Default is to monitor all CPUs.
146 146
147-N:: 147-N::
148--no-buildid-cache:: 148--no-buildid-cache::
149Do not update the builid cache. This saves some overhead in situations 149Do not update the buildid cache. This saves some overhead in situations
150where the information in the perf.data file (which includes buildids) 150where the information in the perf.data file (which includes buildids)
151is sufficient. 151is sufficient.
152 152
diff --git a/tools/perf/Documentation/perf-script-perl.txt b/tools/perf/Documentation/perf-script-perl.txt
index d00bef231340..dfbb506d2c34 100644
--- a/tools/perf/Documentation/perf-script-perl.txt
+++ b/tools/perf/Documentation/perf-script-perl.txt
@@ -181,8 +181,8 @@ strings for flag and symbolic fields. These correspond to the strings
181and values parsed from the 'print fmt' fields of the event format 181and values parsed from the 'print fmt' fields of the event format
182files: 182files:
183 183
184 flag_str($event_name, $field_name, $field_value) - returns the string represention corresponding to $field_value for the flag field $field_name of event $event_name 184 flag_str($event_name, $field_name, $field_value) - returns the string representation corresponding to $field_value for the flag field $field_name of event $event_name
185 symbol_str($event_name, $field_name, $field_value) - returns the string represention corresponding to $field_value for the symbolic field $field_name of event $event_name 185 symbol_str($event_name, $field_name, $field_value) - returns the string representation corresponding to $field_value for the symbolic field $field_name of event $event_name
186 186
187Perf::Trace::Context Module 187Perf::Trace::Context Module
188~~~~~~~~~~~~~~~~~~~~~~~~~~~ 188~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/tools/perf/Documentation/perf-script-python.txt b/tools/perf/Documentation/perf-script-python.txt
index 9f1f054b8432..54acba221558 100644
--- a/tools/perf/Documentation/perf-script-python.txt
+++ b/tools/perf/Documentation/perf-script-python.txt
@@ -263,7 +263,7 @@ and having the counts we've tallied as values.
263 263
264The print_syscall_totals() function iterates over the entries in the 264The print_syscall_totals() function iterates over the entries in the
265dictionary and displays a line for each entry containing the syscall 265dictionary and displays a line for each entry containing the syscall
266name (the dictonary keys contain the syscall ids, which are passed to 266name (the dictionary keys contain the syscall ids, which are passed to
267the Util function syscall_name(), which translates the raw syscall 267the Util function syscall_name(), which translates the raw syscall
268numbers to the corresponding syscall name strings). The output is 268numbers to the corresponding syscall name strings). The output is
269displayed after all the events in the trace have been processed, by 269displayed after all the events in the trace have been processed, by
@@ -576,8 +576,8 @@ strings for flag and symbolic fields. These correspond to the strings
576and values parsed from the 'print fmt' fields of the event format 576and values parsed from the 'print fmt' fields of the event format
577files: 577files:
578 578
579 flag_str(event_name, field_name, field_value) - returns the string represention corresponding to field_value for the flag field field_name of event event_name 579 flag_str(event_name, field_name, field_value) - returns the string representation corresponding to field_value for the flag field field_name of event event_name
580 symbol_str(event_name, field_name, field_value) - returns the string represention corresponding to field_value for the symbolic field field_name of event event_name 580 symbol_str(event_name, field_name, field_value) - returns the string representation corresponding to field_value for the symbolic field field_name of event event_name
581 581
582The *autodict* function returns a special kind of Python 582The *autodict* function returns a special kind of Python
583dictionary that implements Perl's 'autovivifying' hashes in Python 583dictionary that implements Perl's 'autovivifying' hashes in Python
diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt
index 05f9a0a6784c..5a0160d359a1 100644
--- a/tools/perf/Documentation/perf-script.txt
+++ b/tools/perf/Documentation/perf-script.txt
@@ -140,7 +140,7 @@ OPTIONS
140 140
141 "Overriding previous field request for all events." 141 "Overriding previous field request for all events."
142 142
143 Alternativey, consider the order: 143 Alternatively, consider the order:
144 144
145 -f comm,tid,time,ip,sym -f trace: 145 -f comm,tid,time,ip,sym -f trace:
146 146
diff --git a/tools/perf/Documentation/perf-test.txt b/tools/perf/Documentation/perf-test.txt
index d1d3e5121f89..31a5c3ea7f74 100644
--- a/tools/perf/Documentation/perf-test.txt
+++ b/tools/perf/Documentation/perf-test.txt
@@ -25,7 +25,7 @@ OPTIONS
25------- 25-------
26-s:: 26-s::
27--skip:: 27--skip::
28 Tests to skip (comma separater numeric list). 28 Tests to skip (comma separated numeric list).
29 29
30-v:: 30-v::
31--verbose:: 31--verbose::
diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt
index 02aac831bdd9..7e1b1f2bb83c 100644
--- a/tools/perf/Documentation/perf-trace.txt
+++ b/tools/perf/Documentation/perf-trace.txt
@@ -20,7 +20,7 @@ scheduling events, etc.
20This is a live mode tool in addition to working with perf.data files like 20This is a live mode tool in addition to working with perf.data files like
21the other perf tools. Files can be generated using the 'perf record' command 21the other perf tools. Files can be generated using the 'perf record' command
22but the session needs to include the raw_syscalls events (-e 'raw_syscalls:*'). 22but the session needs to include the raw_syscalls events (-e 'raw_syscalls:*').
23Alernatively, the 'perf trace record' can be used as a shortcut to 23Alternatively, 'perf trace record' can be used as a shortcut to
24automatically include the raw_syscalls events when writing events to a file. 24automatically include the raw_syscalls events when writing events to a file.
25 25
26The following options apply to perf trace; options to perf trace record are 26The following options apply to perf trace; options to perf trace record are
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
index 460a4ce9c044..b65eb0507b38 100644
--- a/tools/perf/builtin-kvm.c
+++ b/tools/perf/builtin-kvm.c
@@ -376,7 +376,7 @@ struct vcpu_event_record *per_vcpu_record(struct thread *thread,
376 struct perf_sample *sample) 376 struct perf_sample *sample)
377{ 377{
378 /* Only kvm_entry records vcpu id. */ 378 /* Only kvm_entry records vcpu id. */
379 if (!thread->priv && kvm_entry_event(evsel)) { 379 if (!thread__priv(thread) && kvm_entry_event(evsel)) {
380 struct vcpu_event_record *vcpu_record; 380 struct vcpu_event_record *vcpu_record;
381 381
382 vcpu_record = zalloc(sizeof(*vcpu_record)); 382 vcpu_record = zalloc(sizeof(*vcpu_record));
@@ -386,10 +386,10 @@ struct vcpu_event_record *per_vcpu_record(struct thread *thread,
386 } 386 }
387 387
388 vcpu_record->vcpu_id = perf_evsel__intval(evsel, sample, VCPU_ID); 388 vcpu_record->vcpu_id = perf_evsel__intval(evsel, sample, VCPU_ID);
389 thread->priv = vcpu_record; 389 thread__set_priv(thread, vcpu_record);
390 } 390 }
391 391
392 return thread->priv; 392 return thread__priv(thread);
393} 393}
394 394
395static bool handle_kvm_event(struct perf_kvm_stat *kvm, 395static bool handle_kvm_event(struct perf_kvm_stat *kvm,
@@ -1358,6 +1358,7 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
1358 } 1358 }
1359 kvm->session->evlist = kvm->evlist; 1359 kvm->session->evlist = kvm->evlist;
1360 perf_session__set_id_hdr_size(kvm->session); 1360 perf_session__set_id_hdr_size(kvm->session);
1361 ordered_events__set_copy_on_queue(&kvm->session->ordered_events, true);
1361 machine__synthesize_threads(&kvm->session->machines.host, &kvm->opts.target, 1362 machine__synthesize_threads(&kvm->session->machines.host, &kvm->opts.target,
1362 kvm->evlist->threads, false); 1363 kvm->evlist->threads, false);
1363 err = kvm_live_open_events(kvm); 1364 err = kvm_live_open_events(kvm);
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 2cfc4b93991f..140a6cd88351 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -257,6 +257,13 @@ static int report__setup_sample_type(struct report *rep)
257 } 257 }
258 } 258 }
259 259
260 if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain) {
261 if ((sample_type & PERF_SAMPLE_REGS_USER) &&
262 (sample_type & PERF_SAMPLE_STACK_USER))
263 callchain_param.record_mode = CALLCHAIN_DWARF;
264 else
265 callchain_param.record_mode = CALLCHAIN_FP;
266 }
260 return 0; 267 return 0;
261} 268}
262 269
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 09bcf2393910..fb126459b134 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -1189,13 +1189,13 @@ static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
1189 if (thread == NULL) 1189 if (thread == NULL)
1190 goto fail; 1190 goto fail;
1191 1191
1192 if (thread->priv == NULL) 1192 if (thread__priv(thread) == NULL)
1193 thread->priv = thread_trace__new(); 1193 thread__set_priv(thread, thread_trace__new());
1194 1194
1195 if (thread->priv == NULL) 1195 if (thread__priv(thread) == NULL)
1196 goto fail; 1196 goto fail;
1197 1197
1198 ttrace = thread->priv; 1198 ttrace = thread__priv(thread);
1199 ++ttrace->nr_events; 1199 ++ttrace->nr_events;
1200 1200
1201 return ttrace; 1201 return ttrace;
@@ -1248,7 +1248,7 @@ struct trace {
1248 1248
1249static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname) 1249static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
1250{ 1250{
1251 struct thread_trace *ttrace = thread->priv; 1251 struct thread_trace *ttrace = thread__priv(thread);
1252 1252
1253 if (fd > ttrace->paths.max) { 1253 if (fd > ttrace->paths.max) {
1254 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *)); 1254 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
@@ -1301,7 +1301,7 @@ static int thread__read_fd_path(struct thread *thread, int fd)
1301static const char *thread__fd_path(struct thread *thread, int fd, 1301static const char *thread__fd_path(struct thread *thread, int fd,
1302 struct trace *trace) 1302 struct trace *trace)
1303{ 1303{
1304 struct thread_trace *ttrace = thread->priv; 1304 struct thread_trace *ttrace = thread__priv(thread);
1305 1305
1306 if (ttrace == NULL) 1306 if (ttrace == NULL)
1307 return NULL; 1307 return NULL;
@@ -1338,7 +1338,7 @@ static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1338{ 1338{
1339 int fd = arg->val; 1339 int fd = arg->val;
1340 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg); 1340 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
1341 struct thread_trace *ttrace = arg->thread->priv; 1341 struct thread_trace *ttrace = thread__priv(arg->thread);
1342 1342
1343 if (ttrace && fd >= 0 && fd <= ttrace->paths.max) 1343 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1344 zfree(&ttrace->paths.table[fd]); 1344 zfree(&ttrace->paths.table[fd]);
@@ -2381,7 +2381,7 @@ static int trace__fprintf_one_thread(struct thread *thread, void *priv)
2381 FILE *fp = data->fp; 2381 FILE *fp = data->fp;
2382 size_t printed = data->printed; 2382 size_t printed = data->printed;
2383 struct trace *trace = data->trace; 2383 struct trace *trace = data->trace;
2384 struct thread_trace *ttrace = thread->priv; 2384 struct thread_trace *ttrace = thread__priv(thread);
2385 double ratio; 2385 double ratio;
2386 2386
2387 if (ttrace == NULL) 2387 if (ttrace == NULL)
diff --git a/tools/perf/tests/dwarf-unwind.c b/tools/perf/tests/dwarf-unwind.c
index 96adb730b744..fc25e57f4a5d 100644
--- a/tools/perf/tests/dwarf-unwind.c
+++ b/tools/perf/tests/dwarf-unwind.c
@@ -9,6 +9,7 @@
9#include "perf_regs.h" 9#include "perf_regs.h"
10#include "map.h" 10#include "map.h"
11#include "thread.h" 11#include "thread.h"
12#include "callchain.h"
12 13
13static int mmap_handler(struct perf_tool *tool __maybe_unused, 14static int mmap_handler(struct perf_tool *tool __maybe_unused,
14 union perf_event *event, 15 union perf_event *event,
@@ -120,6 +121,8 @@ int test__dwarf_unwind(void)
120 return -1; 121 return -1;
121 } 122 }
122 123
124 callchain_param.record_mode = CALLCHAIN_DWARF;
125
123 if (init_live_machine(machine)) { 126 if (init_live_machine(machine)) {
124 pr_err("Could not init machine\n"); 127 pr_err("Could not init machine\n");
125 goto out; 128 goto out;
diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c
index 5941927a4b7f..7f2f51f93619 100644
--- a/tools/perf/tests/parse-events.c
+++ b/tools/perf/tests/parse-events.c
@@ -457,6 +457,36 @@ static int test__checkevent_pmu_events(struct perf_evlist *evlist)
457 return 0; 457 return 0;
458} 458}
459 459
460
461static int test__checkevent_pmu_events_mix(struct perf_evlist *evlist)
462{
463 struct perf_evsel *evsel = perf_evlist__first(evlist);
464
465 /* pmu-event:u */
466 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
467 TEST_ASSERT_VAL("wrong exclude_user",
468 !evsel->attr.exclude_user);
469 TEST_ASSERT_VAL("wrong exclude_kernel",
470 evsel->attr.exclude_kernel);
471 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
472 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
473 TEST_ASSERT_VAL("wrong pinned", !evsel->attr.pinned);
474
475 /* cpu/pmu-event/u*/
476 evsel = perf_evsel__next(evsel);
477 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
478 TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
479 TEST_ASSERT_VAL("wrong exclude_user",
480 !evsel->attr.exclude_user);
481 TEST_ASSERT_VAL("wrong exclude_kernel",
482 evsel->attr.exclude_kernel);
483 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
484 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
485 TEST_ASSERT_VAL("wrong pinned", !evsel->attr.pinned);
486
487 return 0;
488}
489
460static int test__checkterms_simple(struct list_head *terms) 490static int test__checkterms_simple(struct list_head *terms)
461{ 491{
462 struct parse_events_term *term; 492 struct parse_events_term *term;
@@ -1554,6 +1584,12 @@ static int test_pmu_events(void)
1554 e.check = test__checkevent_pmu_events; 1584 e.check = test__checkevent_pmu_events;
1555 1585
1556 ret = test_event(&e); 1586 ret = test_event(&e);
1587 if (ret)
1588 break;
1589 snprintf(name, MAX_NAME, "%s:u,cpu/event=%s/u", ent->d_name, ent->d_name);
1590 e.name = name;
1591 e.check = test__checkevent_pmu_events_mix;
1592 ret = test_event(&e);
1557#undef MAX_NAME 1593#undef MAX_NAME
1558 } 1594 }
1559 1595
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index 68eab9ea1634..cfb976b3de3a 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -35,7 +35,9 @@ struct hist_browser {
35 35
36extern void hist_browser__init_hpp(void); 36extern void hist_browser__init_hpp(void);
37 37
38static int hists__browser_title(struct hists *hists, char *bf, size_t size); 38static int hists__browser_title(struct hists *hists,
39 struct hist_browser_timer *hbt,
40 char *bf, size_t size);
39static void hist_browser__update_nr_entries(struct hist_browser *hb); 41static void hist_browser__update_nr_entries(struct hist_browser *hb);
40 42
41static struct rb_node *hists__filter_entries(struct rb_node *nd, 43static struct rb_node *hists__filter_entries(struct rb_node *nd,
@@ -390,7 +392,7 @@ static int hist_browser__run(struct hist_browser *browser,
390 browser->b.entries = &browser->hists->entries; 392 browser->b.entries = &browser->hists->entries;
391 browser->b.nr_entries = hist_browser__nr_entries(browser); 393 browser->b.nr_entries = hist_browser__nr_entries(browser);
392 394
393 hists__browser_title(browser->hists, title, sizeof(title)); 395 hists__browser_title(browser->hists, hbt, title, sizeof(title));
394 396
395 if (ui_browser__show(&browser->b, title, 397 if (ui_browser__show(&browser->b, title,
396 "Press '?' for help on key bindings") < 0) 398 "Press '?' for help on key bindings") < 0)
@@ -417,7 +419,8 @@ static int hist_browser__run(struct hist_browser *browser,
417 ui_browser__warn_lost_events(&browser->b); 419 ui_browser__warn_lost_events(&browser->b);
418 } 420 }
419 421
420 hists__browser_title(browser->hists, title, sizeof(title)); 422 hists__browser_title(browser->hists,
423 hbt, title, sizeof(title));
421 ui_browser__show_title(&browser->b, title); 424 ui_browser__show_title(&browser->b, title);
422 continue; 425 continue;
423 } 426 }
@@ -1204,7 +1207,15 @@ static struct thread *hist_browser__selected_thread(struct hist_browser *browser
1204 return browser->he_selection->thread; 1207 return browser->he_selection->thread;
1205} 1208}
1206 1209
1207static int hists__browser_title(struct hists *hists, char *bf, size_t size) 1210/* Check whether the browser is for 'top' or 'report' */
1211static inline bool is_report_browser(void *timer)
1212{
1213 return timer == NULL;
1214}
1215
1216static int hists__browser_title(struct hists *hists,
1217 struct hist_browser_timer *hbt,
1218 char *bf, size_t size)
1208{ 1219{
1209 char unit; 1220 char unit;
1210 int printed; 1221 int printed;
@@ -1258,6 +1269,13 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size)
1258 if (dso) 1269 if (dso)
1259 printed += scnprintf(bf + printed, size - printed, 1270 printed += scnprintf(bf + printed, size - printed,
1260 ", DSO: %s", dso->short_name); 1271 ", DSO: %s", dso->short_name);
1272 if (!is_report_browser(hbt)) {
1273 struct perf_top *top = hbt->arg;
1274
1275 if (top->zero)
1276 printed += scnprintf(bf + printed, size - printed, " [z]");
1277 }
1278
1261 return printed; 1279 return printed;
1262} 1280}
1263 1281
@@ -1269,12 +1287,6 @@ static inline void free_popup_options(char **options, int n)
1269 zfree(&options[i]); 1287 zfree(&options[i]);
1270} 1288}
1271 1289
1272/* Check whether the browser is for 'top' or 'report' */
1273static inline bool is_report_browser(void *timer)
1274{
1275 return timer == NULL;
1276}
1277
1278/* 1290/*
1279 * Only runtime switching of perf data file will make "input_name" point 1291 * Only runtime switching of perf data file will make "input_name" point
1280 * to a malloced buffer. So add "is_input_name_malloced" flag to decide 1292 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index b4b54d84e9b0..3c9e77d6b4c2 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -1003,6 +1003,7 @@ int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target)
1003 1003
1004out_delete_threads: 1004out_delete_threads:
1005 thread_map__delete(evlist->threads); 1005 thread_map__delete(evlist->threads);
1006 evlist->threads = NULL;
1006 return -1; 1007 return -1;
1007} 1008}
1008 1009
diff --git a/tools/perf/util/include/linux/string.h b/tools/perf/util/include/linux/string.h
index 97a800738226..6f19c548ecc0 100644
--- a/tools/perf/util/include/linux/string.h
+++ b/tools/perf/util/include/linux/string.h
@@ -1,4 +1,3 @@
1#include <string.h> 1#include <string.h>
2 2
3void *memdup(const void *src, size_t len); 3void *memdup(const void *src, size_t len);
4int str_append(char **s, int *len, const char *a);
diff --git a/tools/perf/util/ordered-events.c b/tools/perf/util/ordered-events.c
index 706ce1a66169..fd4be94125fb 100644
--- a/tools/perf/util/ordered-events.c
+++ b/tools/perf/util/ordered-events.c
@@ -1,5 +1,6 @@
1#include <linux/list.h> 1#include <linux/list.h>
2#include <linux/compiler.h> 2#include <linux/compiler.h>
3#include <linux/string.h>
3#include "ordered-events.h" 4#include "ordered-events.h"
4#include "evlist.h" 5#include "evlist.h"
5#include "session.h" 6#include "session.h"
@@ -57,11 +58,45 @@ static void queue_event(struct ordered_events *oe, struct ordered_event *new)
57 } 58 }
58} 59}
59 60
61static union perf_event *__dup_event(struct ordered_events *oe,
62 union perf_event *event)
63{
64 union perf_event *new_event = NULL;
65
66 if (oe->cur_alloc_size < oe->max_alloc_size) {
67 new_event = memdup(event, event->header.size);
68 if (new_event)
69 oe->cur_alloc_size += event->header.size;
70 }
71
72 return new_event;
73}
74
75static union perf_event *dup_event(struct ordered_events *oe,
76 union perf_event *event)
77{
78 return oe->copy_on_queue ? __dup_event(oe, event) : event;
79}
80
81static void free_dup_event(struct ordered_events *oe, union perf_event *event)
82{
83 if (oe->copy_on_queue) {
84 oe->cur_alloc_size -= event->header.size;
85 free(event);
86 }
87}
88
60#define MAX_SAMPLE_BUFFER (64 * 1024 / sizeof(struct ordered_event)) 89#define MAX_SAMPLE_BUFFER (64 * 1024 / sizeof(struct ordered_event))
61static struct ordered_event *alloc_event(struct ordered_events *oe) 90static struct ordered_event *alloc_event(struct ordered_events *oe,
91 union perf_event *event)
62{ 92{
63 struct list_head *cache = &oe->cache; 93 struct list_head *cache = &oe->cache;
64 struct ordered_event *new = NULL; 94 struct ordered_event *new = NULL;
95 union perf_event *new_event;
96
97 new_event = dup_event(oe, event);
98 if (!new_event)
99 return NULL;
65 100
66 if (!list_empty(cache)) { 101 if (!list_empty(cache)) {
67 new = list_entry(cache->next, struct ordered_event, list); 102 new = list_entry(cache->next, struct ordered_event, list);
@@ -74,8 +109,10 @@ static struct ordered_event *alloc_event(struct ordered_events *oe)
74 size_t size = MAX_SAMPLE_BUFFER * sizeof(*new); 109 size_t size = MAX_SAMPLE_BUFFER * sizeof(*new);
75 110
76 oe->buffer = malloc(size); 111 oe->buffer = malloc(size);
77 if (!oe->buffer) 112 if (!oe->buffer) {
113 free_dup_event(oe, new_event);
78 return NULL; 114 return NULL;
115 }
79 116
80 pr("alloc size %" PRIu64 "B (+%zu), max %" PRIu64 "B\n", 117 pr("alloc size %" PRIu64 "B (+%zu), max %" PRIu64 "B\n",
81 oe->cur_alloc_size, size, oe->max_alloc_size); 118 oe->cur_alloc_size, size, oe->max_alloc_size);
@@ -90,15 +127,17 @@ static struct ordered_event *alloc_event(struct ordered_events *oe)
90 pr("allocation limit reached %" PRIu64 "B\n", oe->max_alloc_size); 127 pr("allocation limit reached %" PRIu64 "B\n", oe->max_alloc_size);
91 } 128 }
92 129
130 new->event = new_event;
93 return new; 131 return new;
94} 132}
95 133
96struct ordered_event * 134struct ordered_event *
97ordered_events__new(struct ordered_events *oe, u64 timestamp) 135ordered_events__new(struct ordered_events *oe, u64 timestamp,
136 union perf_event *event)
98{ 137{
99 struct ordered_event *new; 138 struct ordered_event *new;
100 139
101 new = alloc_event(oe); 140 new = alloc_event(oe, event);
102 if (new) { 141 if (new) {
103 new->timestamp = timestamp; 142 new->timestamp = timestamp;
104 queue_event(oe, new); 143 queue_event(oe, new);
@@ -111,6 +150,7 @@ void ordered_events__delete(struct ordered_events *oe, struct ordered_event *eve
111{ 150{
112 list_move(&event->list, &oe->cache); 151 list_move(&event->list, &oe->cache);
113 oe->nr_events--; 152 oe->nr_events--;
153 free_dup_event(oe, event->event);
114} 154}
115 155
116static int __ordered_events__flush(struct perf_session *s, 156static int __ordered_events__flush(struct perf_session *s,
@@ -240,6 +280,7 @@ void ordered_events__free(struct ordered_events *oe)
240 280
241 event = list_entry(oe->to_free.next, struct ordered_event, list); 281 event = list_entry(oe->to_free.next, struct ordered_event, list);
242 list_del(&event->list); 282 list_del(&event->list);
283 free_dup_event(oe, event->event);
243 free(event); 284 free(event);
244 } 285 }
245} 286}
diff --git a/tools/perf/util/ordered-events.h b/tools/perf/util/ordered-events.h
index 3b2f20542a01..7b8f9b011f38 100644
--- a/tools/perf/util/ordered-events.h
+++ b/tools/perf/util/ordered-events.h
@@ -34,9 +34,11 @@ struct ordered_events {
34 int buffer_idx; 34 int buffer_idx;
35 unsigned int nr_events; 35 unsigned int nr_events;
36 enum oe_flush last_flush_type; 36 enum oe_flush last_flush_type;
37 bool copy_on_queue;
37}; 38};
38 39
39struct ordered_event *ordered_events__new(struct ordered_events *oe, u64 timestamp); 40struct ordered_event *ordered_events__new(struct ordered_events *oe, u64 timestamp,
41 union perf_event *event);
40void ordered_events__delete(struct ordered_events *oe, struct ordered_event *event); 42void ordered_events__delete(struct ordered_events *oe, struct ordered_event *event);
41int ordered_events__flush(struct perf_session *s, struct perf_tool *tool, 43int ordered_events__flush(struct perf_session *s, struct perf_tool *tool,
42 enum oe_flush how); 44 enum oe_flush how);
@@ -48,4 +50,10 @@ void ordered_events__set_alloc_size(struct ordered_events *oe, u64 size)
48{ 50{
49 oe->max_alloc_size = size; 51 oe->max_alloc_size = size;
50} 52}
53
54static inline
55void ordered_events__set_copy_on_queue(struct ordered_events *oe, bool copy)
56{
57 oe->copy_on_queue = copy;
58}
51#endif /* __ORDERED_EVENTS_H */ 59#endif /* __ORDERED_EVENTS_H */
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index d76aa30cb1fb..c659a3ca1283 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -6,7 +6,7 @@
6#include "parse-options.h" 6#include "parse-options.h"
7#include "parse-events.h" 7#include "parse-events.h"
8#include "exec_cmd.h" 8#include "exec_cmd.h"
9#include "linux/string.h" 9#include "string.h"
10#include "symbol.h" 10#include "symbol.h"
11#include "cache.h" 11#include "cache.h"
12#include "header.h" 12#include "header.h"
@@ -30,6 +30,15 @@ extern int parse_events_debug;
30#endif 30#endif
31int parse_events_parse(void *data, void *scanner); 31int parse_events_parse(void *data, void *scanner);
32 32
33static struct perf_pmu_event_symbol *perf_pmu_events_list;
34/*
35 * The variable indicates the number of supported pmu event symbols.
36 * 0 means not initialized and ready to init
37 * -1 means failed to init, don't try anymore
38 * >0 is the number of supported pmu event symbols
39 */
40static int perf_pmu_events_list_num;
41
33static struct event_symbol event_symbols_hw[PERF_COUNT_HW_MAX] = { 42static struct event_symbol event_symbols_hw[PERF_COUNT_HW_MAX] = {
34 [PERF_COUNT_HW_CPU_CYCLES] = { 43 [PERF_COUNT_HW_CPU_CYCLES] = {
35 .symbol = "cpu-cycles", 44 .symbol = "cpu-cycles",
@@ -863,30 +872,111 @@ int parse_events_name(struct list_head *list, char *name)
863 return 0; 872 return 0;
864} 873}
865 874
866static int parse_events__scanner(const char *str, void *data, int start_token); 875static int
876comp_pmu(const void *p1, const void *p2)
877{
878 struct perf_pmu_event_symbol *pmu1 = (struct perf_pmu_event_symbol *) p1;
879 struct perf_pmu_event_symbol *pmu2 = (struct perf_pmu_event_symbol *) p2;
867 880
868static int parse_events_fixup(int ret, const char *str, void *data, 881 return strcmp(pmu1->symbol, pmu2->symbol);
869 int start_token) 882}
883
884static void perf_pmu__parse_cleanup(void)
870{ 885{
871 char *o = strdup(str); 886 if (perf_pmu_events_list_num > 0) {
872 char *s = NULL; 887 struct perf_pmu_event_symbol *p;
873 char *t = o; 888 int i;
874 char *p; 889
890 for (i = 0; i < perf_pmu_events_list_num; i++) {
891 p = perf_pmu_events_list + i;
892 free(p->symbol);
893 }
894 free(perf_pmu_events_list);
895 perf_pmu_events_list = NULL;
896 perf_pmu_events_list_num = 0;
897 }
898}
899
900#define SET_SYMBOL(str, stype) \
901do { \
902 p->symbol = str; \
903 if (!p->symbol) \
904 goto err; \
905 p->type = stype; \
906} while (0)
907
908/*
909 * Read the pmu events list from sysfs
910 * Save it into perf_pmu_events_list
911 */
912static void perf_pmu__parse_init(void)
913{
914
915 struct perf_pmu *pmu = NULL;
916 struct perf_pmu_alias *alias;
875 int len = 0; 917 int len = 0;
876 918
877 if (!o) 919 pmu = perf_pmu__find("cpu");
878 return ret; 920 if ((pmu == NULL) || list_empty(&pmu->aliases)) {
879 while ((p = strsep(&t, ",")) != NULL) { 921 perf_pmu_events_list_num = -1;
880 if (s) 922 return;
881 str_append(&s, &len, ",");
882 str_append(&s, &len, "cpu/");
883 str_append(&s, &len, p);
884 str_append(&s, &len, "/");
885 } 923 }
886 free(o); 924 list_for_each_entry(alias, &pmu->aliases, list) {
887 if (!s) 925 if (strchr(alias->name, '-'))
888 return -ENOMEM; 926 len++;
889 return parse_events__scanner(s, data, start_token); 927 len++;
928 }
929 perf_pmu_events_list = malloc(sizeof(struct perf_pmu_event_symbol) * len);
930 if (!perf_pmu_events_list)
931 return;
932 perf_pmu_events_list_num = len;
933
934 len = 0;
935 list_for_each_entry(alias, &pmu->aliases, list) {
936 struct perf_pmu_event_symbol *p = perf_pmu_events_list + len;
937 char *tmp = strchr(alias->name, '-');
938
939 if (tmp != NULL) {
940 SET_SYMBOL(strndup(alias->name, tmp - alias->name),
941 PMU_EVENT_SYMBOL_PREFIX);
942 p++;
943 SET_SYMBOL(strdup(++tmp), PMU_EVENT_SYMBOL_SUFFIX);
944 len += 2;
945 } else {
946 SET_SYMBOL(strdup(alias->name), PMU_EVENT_SYMBOL);
947 len++;
948 }
949 }
950 qsort(perf_pmu_events_list, len,
951 sizeof(struct perf_pmu_event_symbol), comp_pmu);
952
953 return;
954err:
955 perf_pmu__parse_cleanup();
956}
957
958enum perf_pmu_event_symbol_type
959perf_pmu__parse_check(const char *name)
960{
961 struct perf_pmu_event_symbol p, *r;
962
963 /* scan kernel pmu events from sysfs if needed */
964 if (perf_pmu_events_list_num == 0)
965 perf_pmu__parse_init();
966 /*
967 * name "cpu" could be prefix of cpu-cycles or cpu// events.
968 * cpu-cycles has been handled by hardcode.
969 * So it must be cpu// events, not kernel pmu event.
970 */
971 if ((perf_pmu_events_list_num <= 0) || !strcmp(name, "cpu"))
972 return PMU_EVENT_SYMBOL_ERR;
973
974 p.symbol = strdup(name);
975 r = bsearch(&p, perf_pmu_events_list,
976 (size_t) perf_pmu_events_list_num,
977 sizeof(struct perf_pmu_event_symbol), comp_pmu);
978 free(p.symbol);
979 return r ? r->type : PMU_EVENT_SYMBOL_ERR;
890} 980}
891 981
892static int parse_events__scanner(const char *str, void *data, int start_token) 982static int parse_events__scanner(const char *str, void *data, int start_token)
@@ -909,8 +999,6 @@ static int parse_events__scanner(const char *str, void *data, int start_token)
909 parse_events__flush_buffer(buffer, scanner); 999 parse_events__flush_buffer(buffer, scanner);
910 parse_events__delete_buffer(buffer, scanner); 1000 parse_events__delete_buffer(buffer, scanner);
911 parse_events_lex_destroy(scanner); 1001 parse_events_lex_destroy(scanner);
912 if (ret && !strchr(str, '/'))
913 ret = parse_events_fixup(ret, str, data, start_token);
914 return ret; 1002 return ret;
915} 1003}
916 1004
@@ -945,6 +1033,7 @@ int parse_events(struct perf_evlist *evlist, const char *str)
945 int ret; 1033 int ret;
946 1034
947 ret = parse_events__scanner(str, &data, PE_START_EVENTS); 1035 ret = parse_events__scanner(str, &data, PE_START_EVENTS);
1036 perf_pmu__parse_cleanup();
948 if (!ret) { 1037 if (!ret) {
949 int entries = data.idx - evlist->nr_entries; 1038 int entries = data.idx - evlist->nr_entries;
950 perf_evlist__splice_list_tail(evlist, &data.list, entries); 1039 perf_evlist__splice_list_tail(evlist, &data.list, entries);
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index df094b4ed5ed..db2cf78ff0f3 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -35,6 +35,18 @@ extern int parse_filter(const struct option *opt, const char *str, int unset);
35 35
36#define EVENTS_HELP_MAX (128*1024) 36#define EVENTS_HELP_MAX (128*1024)
37 37
38enum perf_pmu_event_symbol_type {
39 PMU_EVENT_SYMBOL_ERR, /* not a PMU EVENT */
40 PMU_EVENT_SYMBOL, /* normal style PMU event */
41 PMU_EVENT_SYMBOL_PREFIX, /* prefix of pre-suf style event */
42 PMU_EVENT_SYMBOL_SUFFIX, /* suffix of pre-suf style event */
43};
44
45struct perf_pmu_event_symbol {
46 char *symbol;
47 enum perf_pmu_event_symbol_type type;
48};
49
38enum { 50enum {
39 PARSE_EVENTS__TERM_TYPE_NUM, 51 PARSE_EVENTS__TERM_TYPE_NUM,
40 PARSE_EVENTS__TERM_TYPE_STR, 52 PARSE_EVENTS__TERM_TYPE_STR,
@@ -95,6 +107,8 @@ int parse_events_add_breakpoint(struct list_head *list, int *idx,
95 void *ptr, char *type); 107 void *ptr, char *type);
96int parse_events_add_pmu(struct list_head *list, int *idx, 108int parse_events_add_pmu(struct list_head *list, int *idx,
97 char *pmu , struct list_head *head_config); 109 char *pmu , struct list_head *head_config);
110enum perf_pmu_event_symbol_type
111perf_pmu__parse_check(const char *name);
98void parse_events__set_leader(char *name, struct list_head *list); 112void parse_events__set_leader(char *name, struct list_head *list);
99void parse_events_update_lists(struct list_head *list_event, 113void parse_events_update_lists(struct list_head *list_event,
100 struct list_head *list_all); 114 struct list_head *list_all);
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l
index 343299575b30..906630bbf8eb 100644
--- a/tools/perf/util/parse-events.l
+++ b/tools/perf/util/parse-events.l
@@ -51,6 +51,24 @@ static int str(yyscan_t scanner, int token)
51 return token; 51 return token;
52} 52}
53 53
54static int pmu_str_check(yyscan_t scanner)
55{
56 YYSTYPE *yylval = parse_events_get_lval(scanner);
57 char *text = parse_events_get_text(scanner);
58
59 yylval->str = strdup(text);
60 switch (perf_pmu__parse_check(text)) {
61 case PMU_EVENT_SYMBOL_PREFIX:
62 return PE_PMU_EVENT_PRE;
63 case PMU_EVENT_SYMBOL_SUFFIX:
64 return PE_PMU_EVENT_SUF;
65 case PMU_EVENT_SYMBOL:
66 return PE_KERNEL_PMU_EVENT;
67 default:
68 return PE_NAME;
69 }
70}
71
54static int sym(yyscan_t scanner, int type, int config) 72static int sym(yyscan_t scanner, int type, int config)
55{ 73{
56 YYSTYPE *yylval = parse_events_get_lval(scanner); 74 YYSTYPE *yylval = parse_events_get_lval(scanner);
@@ -178,6 +196,16 @@ alignment-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_AL
178emulation-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS); } 196emulation-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS); }
179dummy { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_DUMMY); } 197dummy { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_DUMMY); }
180 198
199 /*
200 * We have to handle the kernel PMU event cycles-ct/cycles-t/mem-loads/mem-stores separately.
201 * Because the prefix cycles is mixed up with cpu-cycles.
202 * loads and stores are mixed up with cache event
203 */
204cycles-ct { return str(yyscanner, PE_KERNEL_PMU_EVENT); }
205cycles-t { return str(yyscanner, PE_KERNEL_PMU_EVENT); }
206mem-loads { return str(yyscanner, PE_KERNEL_PMU_EVENT); }
207mem-stores { return str(yyscanner, PE_KERNEL_PMU_EVENT); }
208
181L1-dcache|l1-d|l1d|L1-data | 209L1-dcache|l1-d|l1d|L1-data |
182L1-icache|l1-i|l1i|L1-instruction | 210L1-icache|l1-i|l1i|L1-instruction |
183LLC|L2 | 211LLC|L2 |
@@ -199,7 +227,7 @@ r{num_raw_hex} { return raw(yyscanner); }
199{num_hex} { return value(yyscanner, 16); } 227{num_hex} { return value(yyscanner, 16); }
200 228
201{modifier_event} { return str(yyscanner, PE_MODIFIER_EVENT); } 229{modifier_event} { return str(yyscanner, PE_MODIFIER_EVENT); }
202{name} { return str(yyscanner, PE_NAME); } 230{name} { return pmu_str_check(yyscanner); }
203"/" { BEGIN(config); return '/'; } 231"/" { BEGIN(config); return '/'; }
204- { return '-'; } 232- { return '-'; }
205, { BEGIN(event); return ','; } 233, { BEGIN(event); return ','; }
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index 55fab6ad609a..93c4c9fbc922 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -47,6 +47,7 @@ static inc_group_count(struct list_head *list,
47%token PE_NAME_CACHE_TYPE PE_NAME_CACHE_OP_RESULT 47%token PE_NAME_CACHE_TYPE PE_NAME_CACHE_OP_RESULT
48%token PE_PREFIX_MEM PE_PREFIX_RAW PE_PREFIX_GROUP 48%token PE_PREFIX_MEM PE_PREFIX_RAW PE_PREFIX_GROUP
49%token PE_ERROR 49%token PE_ERROR
50%token PE_PMU_EVENT_PRE PE_PMU_EVENT_SUF PE_KERNEL_PMU_EVENT
50%type <num> PE_VALUE 51%type <num> PE_VALUE
51%type <num> PE_VALUE_SYM_HW 52%type <num> PE_VALUE_SYM_HW
52%type <num> PE_VALUE_SYM_SW 53%type <num> PE_VALUE_SYM_SW
@@ -58,6 +59,7 @@ static inc_group_count(struct list_head *list,
58%type <str> PE_MODIFIER_EVENT 59%type <str> PE_MODIFIER_EVENT
59%type <str> PE_MODIFIER_BP 60%type <str> PE_MODIFIER_BP
60%type <str> PE_EVENT_NAME 61%type <str> PE_EVENT_NAME
62%type <str> PE_PMU_EVENT_PRE PE_PMU_EVENT_SUF PE_KERNEL_PMU_EVENT
61%type <num> value_sym 63%type <num> value_sym
62%type <head> event_config 64%type <head> event_config
63%type <term> event_term 65%type <term> event_term
@@ -220,6 +222,44 @@ PE_NAME '/' '/'
220 ABORT_ON(parse_events_add_pmu(list, &data->idx, $1, NULL)); 222 ABORT_ON(parse_events_add_pmu(list, &data->idx, $1, NULL));
221 $$ = list; 223 $$ = list;
222} 224}
225|
226PE_KERNEL_PMU_EVENT sep_dc
227{
228 struct parse_events_evlist *data = _data;
229 struct list_head *head;
230 struct parse_events_term *term;
231 struct list_head *list;
232
233 ALLOC_LIST(head);
234 ABORT_ON(parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER,
235 $1, 1));
236 list_add_tail(&term->list, head);
237
238 ALLOC_LIST(list);
239 ABORT_ON(parse_events_add_pmu(list, &data->idx, "cpu", head));
240 parse_events__free_terms(head);
241 $$ = list;
242}
243|
244PE_PMU_EVENT_PRE '-' PE_PMU_EVENT_SUF sep_dc
245{
246 struct parse_events_evlist *data = _data;
247 struct list_head *head;
248 struct parse_events_term *term;
249 struct list_head *list;
250 char pmu_name[128];
251 snprintf(&pmu_name, 128, "%s-%s", $1, $3);
252
253 ALLOC_LIST(head);
254 ABORT_ON(parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER,
255 &pmu_name, 1));
256 list_add_tail(&term->list, head);
257
258 ALLOC_LIST(list);
259 ABORT_ON(parse_events_add_pmu(list, &data->idx, "cpu", head));
260 parse_events__free_terms(head);
261 $$ = list;
262}
223 263
224value_sym: 264value_sym:
225PE_VALUE_SYM_HW 265PE_VALUE_SYM_HW
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 93a41ca96b8e..e243ad962a4d 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -12,16 +12,6 @@
12#include "parse-events.h" 12#include "parse-events.h"
13#include "cpumap.h" 13#include "cpumap.h"
14 14
15#define UNIT_MAX_LEN 31 /* max length for event unit name */
16
17struct perf_pmu_alias {
18 char *name;
19 struct list_head terms; /* HEAD struct parse_events_term -> list */
20 struct list_head list; /* ELEM */
21 char unit[UNIT_MAX_LEN+1];
22 double scale;
23};
24
25struct perf_pmu_format { 15struct perf_pmu_format {
26 char *name; 16 char *name;
27 int value; 17 int value;
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index fe90a012c003..fe9dfbee8eed 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -30,6 +30,16 @@ struct perf_pmu_info {
30 double scale; 30 double scale;
31}; 31};
32 32
33#define UNIT_MAX_LEN 31 /* max length for event unit name */
34
35struct perf_pmu_alias {
36 char *name;
37 struct list_head terms; /* HEAD struct parse_events_term -> list */
38 struct list_head list; /* ELEM */
39 char unit[UNIT_MAX_LEN+1];
40 double scale;
41};
42
33struct perf_pmu *perf_pmu__find(const char *name); 43struct perf_pmu *perf_pmu__find(const char *name);
34int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, 44int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
35 struct list_head *head_terms); 45 struct list_head *head_terms);
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 896bac73ea08..6702ac28754b 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -532,17 +532,16 @@ int perf_session_queue_event(struct perf_session *s, union perf_event *event,
532 return -EINVAL; 532 return -EINVAL;
533 } 533 }
534 534
535 new = ordered_events__new(oe, timestamp); 535 new = ordered_events__new(oe, timestamp, event);
536 if (!new) { 536 if (!new) {
537 ordered_events__flush(s, tool, OE_FLUSH__HALF); 537 ordered_events__flush(s, tool, OE_FLUSH__HALF);
538 new = ordered_events__new(oe, timestamp); 538 new = ordered_events__new(oe, timestamp, event);
539 } 539 }
540 540
541 if (!new) 541 if (!new)
542 return -ENOMEM; 542 return -ENOMEM;
543 543
544 new->file_offset = file_offset; 544 new->file_offset = file_offset;
545 new->event = event;
546 return 0; 545 return 0;
547} 546}
548 547
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
index d87767f76903..6afd6106ceb5 100644
--- a/tools/perf/util/string.c
+++ b/tools/perf/util/string.c
@@ -357,27 +357,3 @@ void *memdup(const void *src, size_t len)
357 357
358 return p; 358 return p;
359} 359}
360
361/**
362 * str_append - reallocate string and append another
363 * @s: pointer to string pointer
364 * @len: pointer to len (initialized)
365 * @a: string to append.
366 */
367int str_append(char **s, int *len, const char *a)
368{
369 int olen = *s ? strlen(*s) : 0;
370 int nlen = olen + strlen(a) + 1;
371 if (*len < nlen) {
372 *len = *len * 2;
373 if (*len < nlen)
374 *len = nlen;
375 *s = realloc(*s, *len);
376 if (!*s)
377 return -ENOMEM;
378 if (olen == 0)
379 **s = 0;
380 }
381 strcat(*s, a);
382 return 0;
383}
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index a9df7f2c6dc9..2b7b2d91c016 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -7,6 +7,7 @@
7#include "util.h" 7#include "util.h"
8#include "debug.h" 8#include "debug.h"
9#include "comm.h" 9#include "comm.h"
10#include "unwind.h"
10 11
11int thread__init_map_groups(struct thread *thread, struct machine *machine) 12int thread__init_map_groups(struct thread *thread, struct machine *machine)
12{ 13{
@@ -37,6 +38,9 @@ struct thread *thread__new(pid_t pid, pid_t tid)
37 thread->cpu = -1; 38 thread->cpu = -1;
38 INIT_LIST_HEAD(&thread->comm_list); 39 INIT_LIST_HEAD(&thread->comm_list);
39 40
41 if (unwind__prepare_access(thread) < 0)
42 goto err_thread;
43
40 comm_str = malloc(32); 44 comm_str = malloc(32);
41 if (!comm_str) 45 if (!comm_str)
42 goto err_thread; 46 goto err_thread;
@@ -48,6 +52,7 @@ struct thread *thread__new(pid_t pid, pid_t tid)
48 goto err_thread; 52 goto err_thread;
49 53
50 list_add(&comm->list, &thread->comm_list); 54 list_add(&comm->list, &thread->comm_list);
55
51 } 56 }
52 57
53 return thread; 58 return thread;
@@ -69,6 +74,7 @@ void thread__delete(struct thread *thread)
69 list_del(&comm->list); 74 list_del(&comm->list);
70 comm__free(comm); 75 comm__free(comm);
71 } 76 }
77 unwind__finish_access(thread);
72 78
73 free(thread); 79 free(thread);
74} 80}
diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c
index 92b56db52471..e060386165c5 100644
--- a/tools/perf/util/unwind-libunwind.c
+++ b/tools/perf/util/unwind-libunwind.c
@@ -24,6 +24,7 @@
24#include <linux/list.h> 24#include <linux/list.h>
25#include <libunwind.h> 25#include <libunwind.h>
26#include <libunwind-ptrace.h> 26#include <libunwind-ptrace.h>
27#include "callchain.h"
27#include "thread.h" 28#include "thread.h"
28#include "session.h" 29#include "session.h"
29#include "perf_regs.h" 30#include "perf_regs.h"
@@ -525,12 +526,12 @@ static unw_accessors_t accessors = {
525 .get_proc_name = get_proc_name, 526 .get_proc_name = get_proc_name,
526}; 527};
527 528
528static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb, 529int unwind__prepare_access(struct thread *thread)
529 void *arg, int max_stack)
530{ 530{
531 unw_addr_space_t addr_space; 531 unw_addr_space_t addr_space;
532 unw_cursor_t c; 532
533 int ret; 533 if (callchain_param.record_mode != CALLCHAIN_DWARF)
534 return 0;
534 535
535 addr_space = unw_create_addr_space(&accessors, 0); 536 addr_space = unw_create_addr_space(&accessors, 0);
536 if (!addr_space) { 537 if (!addr_space) {
@@ -538,6 +539,33 @@ static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
538 return -ENOMEM; 539 return -ENOMEM;
539 } 540 }
540 541
542 thread__set_priv(thread, addr_space);
543
544 return 0;
545}
546
547void unwind__finish_access(struct thread *thread)
548{
549 unw_addr_space_t addr_space;
550
551 if (callchain_param.record_mode != CALLCHAIN_DWARF)
552 return;
553
554 addr_space = thread__priv(thread);
555 unw_destroy_addr_space(addr_space);
556}
557
558static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
559 void *arg, int max_stack)
560{
561 unw_addr_space_t addr_space;
562 unw_cursor_t c;
563 int ret;
564
565 addr_space = thread__priv(ui->thread);
566 if (addr_space == NULL)
567 return -1;
568
541 ret = unw_init_remote(&c, addr_space, ui); 569 ret = unw_init_remote(&c, addr_space, ui);
542 if (ret) 570 if (ret)
543 display_error(ret); 571 display_error(ret);
@@ -549,7 +577,6 @@ static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
549 ret = ip ? entry(ip, ui->thread, ui->machine, cb, arg) : 0; 577 ret = ip ? entry(ip, ui->thread, ui->machine, cb, arg) : 0;
550 } 578 }
551 579
552 unw_destroy_addr_space(addr_space);
553 return ret; 580 return ret;
554} 581}
555 582
diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h
index f03061260b4e..c17c4855bdbc 100644
--- a/tools/perf/util/unwind.h
+++ b/tools/perf/util/unwind.h
@@ -4,6 +4,7 @@
4#include <linux/types.h> 4#include <linux/types.h>
5#include "event.h" 5#include "event.h"
6#include "symbol.h" 6#include "symbol.h"
7#include "thread.h"
7 8
8struct unwind_entry { 9struct unwind_entry {
9 struct map *map; 10 struct map *map;
@@ -21,6 +22,15 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
21/* libunwind specific */ 22/* libunwind specific */
22#ifdef HAVE_LIBUNWIND_SUPPORT 23#ifdef HAVE_LIBUNWIND_SUPPORT
23int libunwind__arch_reg_id(int regnum); 24int libunwind__arch_reg_id(int regnum);
25int unwind__prepare_access(struct thread *thread);
26void unwind__finish_access(struct thread *thread);
27#else
28static inline int unwind__prepare_access(struct thread *thread __maybe_unused)
29{
30 return 0;
31}
32
33static inline void unwind__finish_access(struct thread *thread __maybe_unused) {}
24#endif 34#endif
25#else 35#else
26static inline int 36static inline int
@@ -33,5 +43,12 @@ unwind__get_entries(unwind_entry_cb_t cb __maybe_unused,
33{ 43{
34 return 0; 44 return 0;
35} 45}
46
47static inline int unwind__prepare_access(struct thread *thread __maybe_unused)
48{
49 return 0;
50}
51
52static inline void unwind__finish_access(struct thread *thread __maybe_unused) {}
36#endif /* HAVE_DWARF_UNWIND_SUPPORT */ 53#endif /* HAVE_DWARF_UNWIND_SUPPORT */
37#endif /* __UNWIND_H */ 54#endif /* __UNWIND_H */