aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/Documentation/perf-buildid-cache.txt2
-rw-r--r--tools/perf/Documentation/perf-list.txt13
-rw-r--r--tools/perf/Documentation/perf-mem.txt9
-rw-r--r--tools/perf/Documentation/perf-record.txt19
-rw-r--r--tools/perf/Documentation/perf-script.txt28
-rw-r--r--tools/perf/Documentation/perf-stat.txt20
-rw-r--r--tools/perf/bench/futex.h13
-rw-r--r--tools/perf/builtin-buildid-cache.c4
-rw-r--r--tools/perf/builtin-diff.c248
-rw-r--r--tools/perf/builtin-inject.c5
-rw-r--r--tools/perf/builtin-mem.c131
-rw-r--r--tools/perf/builtin-record.c70
-rw-r--r--tools/perf/builtin-report.c16
-rw-r--r--tools/perf/builtin-stat.c2
-rw-r--r--tools/perf/builtin-top.c2
-rw-r--r--tools/perf/builtin-trace.c106
-rw-r--r--tools/perf/config/Makefile6
-rw-r--r--tools/perf/config/feature-checks/Makefile4
-rw-r--r--tools/perf/config/feature-checks/test-all.c5
-rw-r--r--tools/perf/config/feature-checks/test-pthread-attr-setaffinity-np.c14
-rw-r--r--tools/perf/scripts/perl/Perf-Trace-Util/Context.c5
-rw-r--r--tools/perf/tests/attr.py1
-rw-r--r--tools/perf/tests/hists_cumulate.c2
-rw-r--r--tools/perf/tests/hists_output.c2
-rw-r--r--tools/perf/tests/make1
-rw-r--r--tools/perf/tests/parse-events.c60
-rw-r--r--tools/perf/tests/sample-parsing.c2
-rw-r--r--tools/perf/ui/browsers/annotate.c3
-rw-r--r--tools/perf/ui/hist.c12
-rw-r--r--tools/perf/ui/progress.h4
-rw-r--r--tools/perf/ui/tui/helpline.c3
-rw-r--r--tools/perf/ui/tui/setup.c3
-rw-r--r--tools/perf/util/annotate.c20
-rw-r--r--tools/perf/util/color.c126
-rw-r--r--tools/perf/util/color.h2
-rw-r--r--tools/perf/util/dso.c6
-rw-r--r--tools/perf/util/dso.h1
-rw-r--r--tools/perf/util/evlist.c27
-rw-r--r--tools/perf/util/evlist.h1
-rw-r--r--tools/perf/util/evsel.c4
-rw-r--r--tools/perf/util/header.c2
-rw-r--r--tools/perf/util/hist.c48
-rw-r--r--tools/perf/util/hist.h11
-rw-r--r--tools/perf/util/map.h16
-rw-r--r--tools/perf/util/parse-events.c27
-rw-r--r--tools/perf/util/parse-events.h3
-rw-r--r--tools/perf/util/parse-events.l1
-rw-r--r--tools/perf/util/parse-events.y26
-rw-r--r--tools/perf/util/parse-options.c2
-rw-r--r--tools/perf/util/pmu.c102
-rw-r--r--tools/perf/util/probe-event.c34
-rw-r--r--tools/perf/util/python.c2
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c2
-rw-r--r--tools/perf/util/session.c8
-rw-r--r--tools/perf/util/session.h3
-rw-r--r--tools/perf/util/sort.c37
-rw-r--r--tools/perf/util/symbol-elf.c13
-rw-r--r--tools/perf/util/symbol.c33
-rw-r--r--tools/perf/util/symbol.h1
-rw-r--r--tools/perf/util/unwind-libunwind.c31
60 files changed, 880 insertions, 524 deletions
diff --git a/tools/perf/Documentation/perf-buildid-cache.txt b/tools/perf/Documentation/perf-buildid-cache.txt
index fd77d81ea748..0294c57b1f5e 100644
--- a/tools/perf/Documentation/perf-buildid-cache.txt
+++ b/tools/perf/Documentation/perf-buildid-cache.txt
@@ -38,7 +38,7 @@ OPTIONS
38--remove=:: 38--remove=::
39 Remove specified file from the cache. 39 Remove specified file from the cache.
40-M:: 40-M::
41--missing=:: 41--missing=::
42 List missing build ids in the cache for the specified file. 42 List missing build ids in the cache for the specified file.
43-u:: 43-u::
44--update:: 44--update::
diff --git a/tools/perf/Documentation/perf-list.txt b/tools/perf/Documentation/perf-list.txt
index cbb4f743d921..3e2aec94f806 100644
--- a/tools/perf/Documentation/perf-list.txt
+++ b/tools/perf/Documentation/perf-list.txt
@@ -89,6 +89,19 @@ raw encoding of 0x1A8 can be used:
89You should refer to the processor specific documentation for getting these 89You should refer to the processor specific documentation for getting these
90details. Some of them are referenced in the SEE ALSO section below. 90details. Some of them are referenced in the SEE ALSO section below.
91 91
92PARAMETERIZED EVENTS
93--------------------
94
95Some pmu events listed by 'perf-list' will be displayed with '?' in them. For
96example:
97
98 hv_gpci/dtbp_ptitc,phys_processor_idx=?/
99
100This means that when provided as an event, a value for '?' must
101also be supplied. For example:
102
103 perf stat -C 0 -e 'hv_gpci/dtbp_ptitc,phys_processor_idx=0x2/' ...
104
92OPTIONS 105OPTIONS
93------- 106-------
94 107
diff --git a/tools/perf/Documentation/perf-mem.txt b/tools/perf/Documentation/perf-mem.txt
index 1d78a4064da4..43310d8661fe 100644
--- a/tools/perf/Documentation/perf-mem.txt
+++ b/tools/perf/Documentation/perf-mem.txt
@@ -12,11 +12,12 @@ SYNOPSIS
12 12
13DESCRIPTION 13DESCRIPTION
14----------- 14-----------
15"perf mem -t <TYPE> record" runs a command and gathers memory operation data 15"perf mem record" runs a command and gathers memory operation data
16from it, into perf.data. Perf record options are accepted and are passed through. 16from it, into perf.data. Perf record options are accepted and are passed through.
17 17
18"perf mem -t <TYPE> report" displays the result. It invokes perf report with the 18"perf mem report" displays the result. It invokes perf report with the
19right set of options to display a memory access profile. 19right set of options to display a memory access profile. By default, loads
20and stores are sampled. Use the -t option to limit to loads or stores.
20 21
21Note that on Intel systems the memory latency reported is the use-latency, 22Note that on Intel systems the memory latency reported is the use-latency,
22not the pure load (or store latency). Use latency includes any pipeline 23not the pure load (or store latency). Use latency includes any pipeline
@@ -29,7 +30,7 @@ OPTIONS
29 30
30-t:: 31-t::
31--type=:: 32--type=::
32 Select the memory operation type: load or store (default: load) 33 Select the memory operation type: load or store (default: load,store)
33 34
34-D:: 35-D::
35--dump-raw-samples=:: 36--dump-raw-samples=::
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index af9a54ece024..31e977459c51 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -33,12 +33,27 @@ OPTIONS
33 - a raw PMU event (eventsel+umask) in the form of rNNN where NNN is a 33 - a raw PMU event (eventsel+umask) in the form of rNNN where NNN is a
34 hexadecimal event descriptor. 34 hexadecimal event descriptor.
35 35
36 - a hardware breakpoint event in the form of '\mem:addr[:access]' 36 - a symbolically formed PMU event like 'pmu/param1=0x3,param2/' where
37 'param1', 'param2', etc are defined as formats for the PMU in
38 /sys/bus/event_sources/devices/<pmu>/format/*.
39
40 - a symbolically formed event like 'pmu/config=M,config1=N,config3=K/'
41
42 where M, N, K are numbers (in decimal, hex, octal format). Acceptable
43 values for each of 'config', 'config1' and 'config2' are defined by
44 corresponding entries in /sys/bus/event_sources/devices/<pmu>/format/*
45 param1 and param2 are defined as formats for the PMU in:
46 /sys/bus/event_sources/devices/<pmu>/format/*
47
48 - a hardware breakpoint event in the form of '\mem:addr[/len][:access]'
37 where addr is the address in memory you want to break in. 49 where addr is the address in memory you want to break in.
38 Access is the memory access type (read, write, execute) it can 50 Access is the memory access type (read, write, execute) it can
39 be passed as follows: '\mem:addr[:[r][w][x]]'. 51 be passed as follows: '\mem:addr[:[r][w][x]]'. len is the range,
52 number of bytes from specified addr, which the breakpoint will cover.
40 If you want to profile read-write accesses in 0x1000, just set 53 If you want to profile read-write accesses in 0x1000, just set
41 'mem:0x1000:rw'. 54 'mem:0x1000:rw'.
55 If you want to profile write accesses in [0x1000~1008), just set
56 'mem:0x1000/8:w'.
42 57
43--filter=<filter>:: 58--filter=<filter>::
44 Event filter. 59 Event filter.
diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt
index 21494806c0ab..a21eec05bc42 100644
--- a/tools/perf/Documentation/perf-script.txt
+++ b/tools/perf/Documentation/perf-script.txt
@@ -125,46 +125,46 @@ OPTIONS
125 is equivalent to: 125 is equivalent to:
126 126
127 perf script -f trace:<fields> -f sw:<fields> -f hw:<fields> 127 perf script -f trace:<fields> -f sw:<fields> -f hw:<fields>
128 128
129 i.e., the specified fields apply to all event types if the type string 129 i.e., the specified fields apply to all event types if the type string
130 is not given. 130 is not given.
131 131
132 The arguments are processed in the order received. A later usage can 132 The arguments are processed in the order received. A later usage can
133 reset a prior request. e.g.: 133 reset a prior request. e.g.:
134 134
135 -f trace: -f comm,tid,time,ip,sym 135 -f trace: -f comm,tid,time,ip,sym
136 136
137 The first -f suppresses trace events (field list is ""), but then the 137 The first -f suppresses trace events (field list is ""), but then the
138 second invocation sets the fields to comm,tid,time,ip,sym. In this case a 138 second invocation sets the fields to comm,tid,time,ip,sym. In this case a
139 warning is given to the user: 139 warning is given to the user:
140 140
141 "Overriding previous field request for all events." 141 "Overriding previous field request for all events."
142 142
143 Alternatively, 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
147 The first -f sets the fields for all events and the second -f 147 The first -f sets the fields for all events and the second -f
148 suppresses trace events. The user is given a warning message about 148 suppresses trace events. The user is given a warning message about
149 the override, and the result of the above is that only S/W and H/W 149 the override, and the result of the above is that only S/W and H/W
150 events are displayed with the given fields. 150 events are displayed with the given fields.
151 151
152 For the 'wildcard' option if a user selected field is invalid for an 152 For the 'wildcard' option if a user selected field is invalid for an
153 event type, a message is displayed to the user that the option is 153 event type, a message is displayed to the user that the option is
154 ignored for that type. For example: 154 ignored for that type. For example:
155 155
156 $ perf script -f comm,tid,trace 156 $ perf script -f comm,tid,trace
157 'trace' not valid for hardware events. Ignoring. 157 'trace' not valid for hardware events. Ignoring.
158 'trace' not valid for software events. Ignoring. 158 'trace' not valid for software events. Ignoring.
159 159
160 Alternatively, if the type is given an invalid field is specified it 160 Alternatively, if the type is given an invalid field is specified it
161 is an error. For example: 161 is an error. For example:
162 162
163 perf script -v -f sw:comm,tid,trace 163 perf script -v -f sw:comm,tid,trace
164 'trace' not valid for software events. 164 'trace' not valid for software events.
165 165
166 At this point usage is displayed, and perf-script exits. 166 At this point usage is displayed, and perf-script exits.
167 167
168 Finally, a user may not set fields to none for all event types. 168 Finally, a user may not set fields to none for all event types.
169 i.e., -f "" is not allowed. 169 i.e., -f "" is not allowed.
170 170
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt
index 29ee857c09c6..04e150d83e7d 100644
--- a/tools/perf/Documentation/perf-stat.txt
+++ b/tools/perf/Documentation/perf-stat.txt
@@ -25,10 +25,22 @@ OPTIONS
25 25
26-e:: 26-e::
27--event=:: 27--event=::
28 Select the PMU event. Selection can be a symbolic event name 28 Select the PMU event. Selection can be:
29 (use 'perf list' to list all events) or a raw PMU 29
30 event (eventsel+umask) in the form of rNNN where NNN is a 30 - a symbolic event name (use 'perf list' to list all events)
31 hexadecimal event descriptor. 31
32 - a raw PMU event (eventsel+umask) in the form of rNNN where NNN is a
33 hexadecimal event descriptor.
34
35 - a symbolically formed event like 'pmu/param1=0x3,param2/' where
36 param1 and param2 are defined as formats for the PMU in
37 /sys/bus/event_sources/devices/<pmu>/format/*
38
39 - a symbolically formed event like 'pmu/config=M,config1=N,config2=K/'
40 where M, N, K are numbers (in decimal, hex, octal format).
41 Acceptable values for each of 'config', 'config1' and 'config2'
42 parameters are defined by corresponding entries in
43 /sys/bus/event_sources/devices/<pmu>/format/*
32 44
33-i:: 45-i::
34--no-inherit:: 46--no-inherit::
diff --git a/tools/perf/bench/futex.h b/tools/perf/bench/futex.h
index 71f2844cf97f..7ed22ff1e1ac 100644
--- a/tools/perf/bench/futex.h
+++ b/tools/perf/bench/futex.h
@@ -68,4 +68,17 @@ futex_cmp_requeue(u_int32_t *uaddr, u_int32_t val, u_int32_t *uaddr2, int nr_wak
68 val, opflags); 68 val, opflags);
69} 69}
70 70
71#ifndef HAVE_PTHREAD_ATTR_SETAFFINITY_NP
72#include <pthread.h>
73static inline int pthread_attr_setaffinity_np(pthread_attr_t *attr,
74 size_t cpusetsize,
75 cpu_set_t *cpuset)
76{
77 attr = attr;
78 cpusetsize = cpusetsize;
79 cpuset = cpuset;
80 return 0;
81}
82#endif
83
71#endif /* _FUTEX_H */ 84#endif /* _FUTEX_H */
diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c
index 77d5cae54c6a..50e6b66aea1f 100644
--- a/tools/perf/builtin-buildid-cache.c
+++ b/tools/perf/builtin-buildid-cache.c
@@ -236,10 +236,10 @@ static bool dso__missing_buildid_cache(struct dso *dso, int parm __maybe_unused)
236 if (errno == ENOENT) 236 if (errno == ENOENT)
237 return false; 237 return false;
238 238
239 pr_warning("Problems with %s file, consider removing it from the cache\n", 239 pr_warning("Problems with %s file, consider removing it from the cache\n",
240 filename); 240 filename);
241 } else if (memcmp(dso->build_id, build_id, sizeof(dso->build_id))) { 241 } else if (memcmp(dso->build_id, build_id, sizeof(dso->build_id))) {
242 pr_warning("Problems with %s file, consider removing it from the cache\n", 242 pr_warning("Problems with %s file, consider removing it from the cache\n",
243 filename); 243 filename);
244 } 244 }
245 245
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index 1fd96c13f199..74aada554b12 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -390,6 +390,15 @@ static void perf_evlist__collapse_resort(struct perf_evlist *evlist)
390 } 390 }
391} 391}
392 392
393static struct data__file *fmt_to_data_file(struct perf_hpp_fmt *fmt)
394{
395 struct diff_hpp_fmt *dfmt = container_of(fmt, struct diff_hpp_fmt, fmt);
396 void *ptr = dfmt - dfmt->idx;
397 struct data__file *d = container_of(ptr, struct data__file, fmt);
398
399 return d;
400}
401
393static struct hist_entry* 402static struct hist_entry*
394get_pair_data(struct hist_entry *he, struct data__file *d) 403get_pair_data(struct hist_entry *he, struct data__file *d)
395{ 404{
@@ -407,8 +416,7 @@ get_pair_data(struct hist_entry *he, struct data__file *d)
407static struct hist_entry* 416static struct hist_entry*
408get_pair_fmt(struct hist_entry *he, struct diff_hpp_fmt *dfmt) 417get_pair_fmt(struct hist_entry *he, struct diff_hpp_fmt *dfmt)
409{ 418{
410 void *ptr = dfmt - dfmt->idx; 419 struct data__file *d = fmt_to_data_file(&dfmt->fmt);
411 struct data__file *d = container_of(ptr, struct data__file, fmt);
412 420
413 return get_pair_data(he, d); 421 return get_pair_data(he, d);
414} 422}
@@ -430,7 +438,7 @@ static void hists__baseline_only(struct hists *hists)
430 next = rb_next(&he->rb_node_in); 438 next = rb_next(&he->rb_node_in);
431 if (!hist_entry__next_pair(he)) { 439 if (!hist_entry__next_pair(he)) {
432 rb_erase(&he->rb_node_in, root); 440 rb_erase(&he->rb_node_in, root);
433 hist_entry__free(he); 441 hist_entry__delete(he);
434 } 442 }
435 } 443 }
436} 444}
@@ -448,26 +456,30 @@ static void hists__precompute(struct hists *hists)
448 next = rb_first(root); 456 next = rb_first(root);
449 while (next != NULL) { 457 while (next != NULL) {
450 struct hist_entry *he, *pair; 458 struct hist_entry *he, *pair;
459 struct data__file *d;
460 int i;
451 461
452 he = rb_entry(next, struct hist_entry, rb_node_in); 462 he = rb_entry(next, struct hist_entry, rb_node_in);
453 next = rb_next(&he->rb_node_in); 463 next = rb_next(&he->rb_node_in);
454 464
455 pair = get_pair_data(he, &data__files[sort_compute]); 465 data__for_each_file_new(i, d) {
456 if (!pair) 466 pair = get_pair_data(he, d);
457 continue; 467 if (!pair)
468 continue;
458 469
459 switch (compute) { 470 switch (compute) {
460 case COMPUTE_DELTA: 471 case COMPUTE_DELTA:
461 compute_delta(he, pair); 472 compute_delta(he, pair);
462 break; 473 break;
463 case COMPUTE_RATIO: 474 case COMPUTE_RATIO:
464 compute_ratio(he, pair); 475 compute_ratio(he, pair);
465 break; 476 break;
466 case COMPUTE_WEIGHTED_DIFF: 477 case COMPUTE_WEIGHTED_DIFF:
467 compute_wdiff(he, pair); 478 compute_wdiff(he, pair);
468 break; 479 break;
469 default: 480 default:
470 BUG_ON(1); 481 BUG_ON(1);
482 }
471 } 483 }
472 } 484 }
473} 485}
@@ -517,7 +529,7 @@ __hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right,
517 529
518static int64_t 530static int64_t
519hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right, 531hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right,
520 int c) 532 int c, int sort_idx)
521{ 533{
522 bool pairs_left = hist_entry__has_pairs(left); 534 bool pairs_left = hist_entry__has_pairs(left);
523 bool pairs_right = hist_entry__has_pairs(right); 535 bool pairs_right = hist_entry__has_pairs(right);
@@ -529,8 +541,8 @@ hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right,
529 if (!pairs_left || !pairs_right) 541 if (!pairs_left || !pairs_right)
530 return pairs_left ? -1 : 1; 542 return pairs_left ? -1 : 1;
531 543
532 p_left = get_pair_data(left, &data__files[sort_compute]); 544 p_left = get_pair_data(left, &data__files[sort_idx]);
533 p_right = get_pair_data(right, &data__files[sort_compute]); 545 p_right = get_pair_data(right, &data__files[sort_idx]);
534 546
535 if (!p_left && !p_right) 547 if (!p_left && !p_right)
536 return 0; 548 return 0;
@@ -546,90 +558,102 @@ hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right,
546} 558}
547 559
548static int64_t 560static int64_t
549hist_entry__cmp_nop(struct hist_entry *left __maybe_unused, 561hist_entry__cmp_compute_idx(struct hist_entry *left, struct hist_entry *right,
562 int c, int sort_idx)
563{
564 struct hist_entry *p_right, *p_left;
565
566 p_left = get_pair_data(left, &data__files[sort_idx]);
567 p_right = get_pair_data(right, &data__files[sort_idx]);
568
569 if (!p_left && !p_right)
570 return 0;
571
572 if (!p_left || !p_right)
573 return p_left ? -1 : 1;
574
575 if (c != COMPUTE_DELTA) {
576 /*
577 * The delta can be computed without the baseline, but
578 * others are not. Put those entries which have no
579 * values below.
580 */
581 if (left->dummy && right->dummy)
582 return 0;
583
584 if (left->dummy || right->dummy)
585 return left->dummy ? 1 : -1;
586 }
587
588 return __hist_entry__cmp_compute(p_left, p_right, c);
589}
590
591static int64_t
592hist_entry__cmp_nop(struct perf_hpp_fmt *fmt __maybe_unused,
593 struct hist_entry *left __maybe_unused,
550 struct hist_entry *right __maybe_unused) 594 struct hist_entry *right __maybe_unused)
551{ 595{
552 return 0; 596 return 0;
553} 597}
554 598
555static int64_t 599static int64_t
556hist_entry__cmp_baseline(struct hist_entry *left, struct hist_entry *right) 600hist_entry__cmp_baseline(struct perf_hpp_fmt *fmt __maybe_unused,
601 struct hist_entry *left, struct hist_entry *right)
557{ 602{
558 if (sort_compute)
559 return 0;
560
561 if (left->stat.period == right->stat.period) 603 if (left->stat.period == right->stat.period)
562 return 0; 604 return 0;
563 return left->stat.period > right->stat.period ? 1 : -1; 605 return left->stat.period > right->stat.period ? 1 : -1;
564} 606}
565 607
566static int64_t 608static int64_t
567hist_entry__cmp_delta(struct hist_entry *left, struct hist_entry *right) 609hist_entry__cmp_delta(struct perf_hpp_fmt *fmt,
610 struct hist_entry *left, struct hist_entry *right)
568{ 611{
569 return hist_entry__cmp_compute(right, left, COMPUTE_DELTA); 612 struct data__file *d = fmt_to_data_file(fmt);
613
614 return hist_entry__cmp_compute(right, left, COMPUTE_DELTA, d->idx);
570} 615}
571 616
572static int64_t 617static int64_t
573hist_entry__cmp_ratio(struct hist_entry *left, struct hist_entry *right) 618hist_entry__cmp_ratio(struct perf_hpp_fmt *fmt,
619 struct hist_entry *left, struct hist_entry *right)
574{ 620{
575 return hist_entry__cmp_compute(right, left, COMPUTE_RATIO); 621 struct data__file *d = fmt_to_data_file(fmt);
622
623 return hist_entry__cmp_compute(right, left, COMPUTE_RATIO, d->idx);
576} 624}
577 625
578static int64_t 626static int64_t
579hist_entry__cmp_wdiff(struct hist_entry *left, struct hist_entry *right) 627hist_entry__cmp_wdiff(struct perf_hpp_fmt *fmt,
628 struct hist_entry *left, struct hist_entry *right)
580{ 629{
581 return hist_entry__cmp_compute(right, left, COMPUTE_WEIGHTED_DIFF); 630 struct data__file *d = fmt_to_data_file(fmt);
631
632 return hist_entry__cmp_compute(right, left, COMPUTE_WEIGHTED_DIFF, d->idx);
582} 633}
583 634
584static void insert_hist_entry_by_compute(struct rb_root *root, 635static int64_t
585 struct hist_entry *he, 636hist_entry__cmp_delta_idx(struct perf_hpp_fmt *fmt __maybe_unused,
586 int c) 637 struct hist_entry *left, struct hist_entry *right)
587{ 638{
588 struct rb_node **p = &root->rb_node; 639 return hist_entry__cmp_compute_idx(right, left, COMPUTE_DELTA,
589 struct rb_node *parent = NULL; 640 sort_compute);
590 struct hist_entry *iter;
591
592 while (*p != NULL) {
593 parent = *p;
594 iter = rb_entry(parent, struct hist_entry, rb_node);
595 if (hist_entry__cmp_compute(he, iter, c) < 0)
596 p = &(*p)->rb_left;
597 else
598 p = &(*p)->rb_right;
599 }
600
601 rb_link_node(&he->rb_node, parent, p);
602 rb_insert_color(&he->rb_node, root);
603} 641}
604 642
605static void hists__compute_resort(struct hists *hists) 643static int64_t
644hist_entry__cmp_ratio_idx(struct perf_hpp_fmt *fmt __maybe_unused,
645 struct hist_entry *left, struct hist_entry *right)
606{ 646{
607 struct rb_root *root; 647 return hist_entry__cmp_compute_idx(right, left, COMPUTE_RATIO,
608 struct rb_node *next; 648 sort_compute);
609 649}
610 if (sort__need_collapse)
611 root = &hists->entries_collapsed;
612 else
613 root = hists->entries_in;
614
615 hists->entries = RB_ROOT;
616 next = rb_first(root);
617
618 hists__reset_stats(hists);
619 hists__reset_col_len(hists);
620
621 while (next != NULL) {
622 struct hist_entry *he;
623
624 he = rb_entry(next, struct hist_entry, rb_node_in);
625 next = rb_next(&he->rb_node_in);
626
627 insert_hist_entry_by_compute(&hists->entries, he, compute);
628 hists__inc_stats(hists, he);
629 650
630 if (!he->filtered) 651static int64_t
631 hists__calc_col_len(hists, he); 652hist_entry__cmp_wdiff_idx(struct perf_hpp_fmt *fmt __maybe_unused,
632 } 653 struct hist_entry *left, struct hist_entry *right)
654{
655 return hist_entry__cmp_compute_idx(right, left, COMPUTE_WEIGHTED_DIFF,
656 sort_compute);
633} 657}
634 658
635static void hists__process(struct hists *hists) 659static void hists__process(struct hists *hists)
@@ -637,12 +661,8 @@ static void hists__process(struct hists *hists)
637 if (show_baseline_only) 661 if (show_baseline_only)
638 hists__baseline_only(hists); 662 hists__baseline_only(hists);
639 663
640 if (sort_compute) { 664 hists__precompute(hists);
641 hists__precompute(hists); 665 hists__output_resort(hists, NULL);
642 hists__compute_resort(hists);
643 } else {
644 hists__output_resort(hists, NULL);
645 }
646 666
647 hists__fprintf(hists, true, 0, 0, 0, stdout); 667 hists__fprintf(hists, true, 0, 0, 0, stdout);
648} 668}
@@ -841,7 +861,7 @@ static int __hpp__color_compare(struct perf_hpp_fmt *fmt,
841 char pfmt[20] = " "; 861 char pfmt[20] = " ";
842 862
843 if (!pair) 863 if (!pair)
844 goto dummy_print; 864 goto no_print;
845 865
846 switch (comparison_method) { 866 switch (comparison_method) {
847 case COMPUTE_DELTA: 867 case COMPUTE_DELTA:
@@ -850,8 +870,6 @@ static int __hpp__color_compare(struct perf_hpp_fmt *fmt,
850 else 870 else
851 diff = compute_delta(he, pair); 871 diff = compute_delta(he, pair);
852 872
853 if (fabs(diff) < 0.01)
854 goto dummy_print;
855 scnprintf(pfmt, 20, "%%%+d.2f%%%%", dfmt->header_width - 1); 873 scnprintf(pfmt, 20, "%%%+d.2f%%%%", dfmt->header_width - 1);
856 return percent_color_snprintf(hpp->buf, hpp->size, 874 return percent_color_snprintf(hpp->buf, hpp->size,
857 pfmt, diff); 875 pfmt, diff);
@@ -883,6 +901,9 @@ static int __hpp__color_compare(struct perf_hpp_fmt *fmt,
883 } 901 }
884dummy_print: 902dummy_print:
885 return scnprintf(hpp->buf, hpp->size, "%*s", 903 return scnprintf(hpp->buf, hpp->size, "%*s",
904 dfmt->header_width, "N/A");
905no_print:
906 return scnprintf(hpp->buf, hpp->size, "%*s",
886 dfmt->header_width, pfmt); 907 dfmt->header_width, pfmt);
887} 908}
888 909
@@ -932,14 +953,15 @@ hpp__entry_pair(struct hist_entry *he, struct hist_entry *pair,
932 else 953 else
933 diff = compute_delta(he, pair); 954 diff = compute_delta(he, pair);
934 955
935 if (fabs(diff) >= 0.01) 956 scnprintf(buf, size, "%+4.2F%%", diff);
936 scnprintf(buf, size, "%+4.2F%%", diff);
937 break; 957 break;
938 958
939 case PERF_HPP_DIFF__RATIO: 959 case PERF_HPP_DIFF__RATIO:
940 /* No point for ratio number if we are dummy.. */ 960 /* No point for ratio number if we are dummy.. */
941 if (he->dummy) 961 if (he->dummy) {
962 scnprintf(buf, size, "N/A");
942 break; 963 break;
964 }
943 965
944 if (pair->diff.computed) 966 if (pair->diff.computed)
945 ratio = pair->diff.period_ratio; 967 ratio = pair->diff.period_ratio;
@@ -952,8 +974,10 @@ hpp__entry_pair(struct hist_entry *he, struct hist_entry *pair,
952 974
953 case PERF_HPP_DIFF__WEIGHTED_DIFF: 975 case PERF_HPP_DIFF__WEIGHTED_DIFF:
954 /* No point for wdiff number if we are dummy.. */ 976 /* No point for wdiff number if we are dummy.. */
955 if (he->dummy) 977 if (he->dummy) {
978 scnprintf(buf, size, "N/A");
956 break; 979 break;
980 }
957 981
958 if (pair->diff.computed) 982 if (pair->diff.computed)
959 wdiff = pair->diff.wdiff; 983 wdiff = pair->diff.wdiff;
@@ -1105,9 +1129,10 @@ static void data__hpp_register(struct data__file *d, int idx)
1105 perf_hpp__register_sort_field(fmt); 1129 perf_hpp__register_sort_field(fmt);
1106} 1130}
1107 1131
1108static void ui_init(void) 1132static int ui_init(void)
1109{ 1133{
1110 struct data__file *d; 1134 struct data__file *d;
1135 struct perf_hpp_fmt *fmt;
1111 int i; 1136 int i;
1112 1137
1113 data__for_each_file(i, d) { 1138 data__for_each_file(i, d) {
@@ -1137,6 +1162,46 @@ static void ui_init(void)
1137 data__hpp_register(d, i ? PERF_HPP_DIFF__PERIOD : 1162 data__hpp_register(d, i ? PERF_HPP_DIFF__PERIOD :
1138 PERF_HPP_DIFF__PERIOD_BASELINE); 1163 PERF_HPP_DIFF__PERIOD_BASELINE);
1139 } 1164 }
1165
1166 if (!sort_compute)
1167 return 0;
1168
1169 /*
1170 * Prepend an fmt to sort on columns at 'sort_compute' first.
1171 * This fmt is added only to the sort list but not to the
1172 * output fields list.
1173 *
1174 * Note that this column (data) can be compared twice - one
1175 * for this 'sort_compute' fmt and another for the normal
1176 * diff_hpp_fmt. But it shouldn't a problem as most entries
1177 * will be sorted out by first try or baseline and comparing
1178 * is not a costly operation.
1179 */
1180 fmt = zalloc(sizeof(*fmt));
1181 if (fmt == NULL) {
1182 pr_err("Memory allocation failed\n");
1183 return -1;
1184 }
1185
1186 fmt->cmp = hist_entry__cmp_nop;
1187 fmt->collapse = hist_entry__cmp_nop;
1188
1189 switch (compute) {
1190 case COMPUTE_DELTA:
1191 fmt->sort = hist_entry__cmp_delta_idx;
1192 break;
1193 case COMPUTE_RATIO:
1194 fmt->sort = hist_entry__cmp_ratio_idx;
1195 break;
1196 case COMPUTE_WEIGHTED_DIFF:
1197 fmt->sort = hist_entry__cmp_wdiff_idx;
1198 break;
1199 default:
1200 BUG_ON(1);
1201 }
1202
1203 list_add(&fmt->sort_list, &perf_hpp__sort_list);
1204 return 0;
1140} 1205}
1141 1206
1142static int data_init(int argc, const char **argv) 1207static int data_init(int argc, const char **argv)
@@ -1202,7 +1267,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)
1202 if (data_init(argc, argv) < 0) 1267 if (data_init(argc, argv) < 0)
1203 return -1; 1268 return -1;
1204 1269
1205 ui_init(); 1270 if (ui_init() < 0)
1271 return -1;
1206 1272
1207 sort__mode = SORT_MODE__DIFF; 1273 sort__mode = SORT_MODE__DIFF;
1208 1274
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 84df2deed988..a13641e066f5 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -343,6 +343,7 @@ static int __cmd_inject(struct perf_inject *inject)
343 int ret = -EINVAL; 343 int ret = -EINVAL;
344 struct perf_session *session = inject->session; 344 struct perf_session *session = inject->session;
345 struct perf_data_file *file_out = &inject->output; 345 struct perf_data_file *file_out = &inject->output;
346 int fd = perf_data_file__fd(file_out);
346 347
347 signal(SIGINT, sig_handler); 348 signal(SIGINT, sig_handler);
348 349
@@ -376,7 +377,7 @@ static int __cmd_inject(struct perf_inject *inject)
376 } 377 }
377 378
378 if (!file_out->is_pipe) 379 if (!file_out->is_pipe)
379 lseek(file_out->fd, session->header.data_offset, SEEK_SET); 380 lseek(fd, session->header.data_offset, SEEK_SET);
380 381
381 ret = perf_session__process_events(session, &inject->tool); 382 ret = perf_session__process_events(session, &inject->tool);
382 383
@@ -385,7 +386,7 @@ static int __cmd_inject(struct perf_inject *inject)
385 perf_header__set_feat(&session->header, 386 perf_header__set_feat(&session->header,
386 HEADER_BUILD_ID); 387 HEADER_BUILD_ID);
387 session->header.data_size = inject->bytes_written; 388 session->header.data_size = inject->bytes_written;
388 perf_session__write_header(session, session->evlist, file_out->fd, true); 389 perf_session__write_header(session, session->evlist, fd, true);
389 } 390 }
390 391
391 return ret; 392 return ret;
diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c
index 24db6ffe2957..9b5663950a4d 100644
--- a/tools/perf/builtin-mem.c
+++ b/tools/perf/builtin-mem.c
@@ -7,44 +7,47 @@
7#include "util/session.h" 7#include "util/session.h"
8#include "util/data.h" 8#include "util/data.h"
9 9
10#define MEM_OPERATION_LOAD "load" 10#define MEM_OPERATION_LOAD 0x1
11#define MEM_OPERATION_STORE "store" 11#define MEM_OPERATION_STORE 0x2
12
13static const char *mem_operation = MEM_OPERATION_LOAD;
14 12
15struct perf_mem { 13struct perf_mem {
16 struct perf_tool tool; 14 struct perf_tool tool;
17 char const *input_name; 15 char const *input_name;
18 bool hide_unresolved; 16 bool hide_unresolved;
19 bool dump_raw; 17 bool dump_raw;
18 int operation;
20 const char *cpu_list; 19 const char *cpu_list;
21 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); 20 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
22}; 21};
23 22
24static int __cmd_record(int argc, const char **argv) 23static int __cmd_record(int argc, const char **argv, struct perf_mem *mem)
25{ 24{
26 int rec_argc, i = 0, j; 25 int rec_argc, i = 0, j;
27 const char **rec_argv; 26 const char **rec_argv;
28 char event[64];
29 int ret; 27 int ret;
30 28
31 rec_argc = argc + 4; 29 rec_argc = argc + 7; /* max number of arguments */
32 rec_argv = calloc(rec_argc + 1, sizeof(char *)); 30 rec_argv = calloc(rec_argc + 1, sizeof(char *));
33 if (!rec_argv) 31 if (!rec_argv)
34 return -1; 32 return -1;
35 33
36 rec_argv[i++] = strdup("record"); 34 rec_argv[i++] = "record";
37 if (!strcmp(mem_operation, MEM_OPERATION_LOAD))
38 rec_argv[i++] = strdup("-W");
39 rec_argv[i++] = strdup("-d");
40 rec_argv[i++] = strdup("-e");
41 35
42 if (strcmp(mem_operation, MEM_OPERATION_LOAD)) 36 if (mem->operation & MEM_OPERATION_LOAD)
43 sprintf(event, "cpu/mem-stores/pp"); 37 rec_argv[i++] = "-W";
44 else 38
45 sprintf(event, "cpu/mem-loads/pp"); 39 rec_argv[i++] = "-d";
40
41 if (mem->operation & MEM_OPERATION_LOAD) {
42 rec_argv[i++] = "-e";
43 rec_argv[i++] = "cpu/mem-loads/pp";
44 }
45
46 if (mem->operation & MEM_OPERATION_STORE) {
47 rec_argv[i++] = "-e";
48 rec_argv[i++] = "cpu/mem-stores/pp";
49 }
46 50
47 rec_argv[i++] = strdup(event);
48 for (j = 1; j < argc; j++, i++) 51 for (j = 1; j < argc; j++, i++)
49 rec_argv[i] = argv[j]; 52 rec_argv[i] = argv[j];
50 53
@@ -162,17 +165,17 @@ static int report_events(int argc, const char **argv, struct perf_mem *mem)
162 if (!rep_argv) 165 if (!rep_argv)
163 return -1; 166 return -1;
164 167
165 rep_argv[i++] = strdup("report"); 168 rep_argv[i++] = "report";
166 rep_argv[i++] = strdup("--mem-mode"); 169 rep_argv[i++] = "--mem-mode";
167 rep_argv[i++] = strdup("-n"); /* display number of samples */ 170 rep_argv[i++] = "-n"; /* display number of samples */
168 171
169 /* 172 /*
170 * there is no weight (cost) associated with stores, so don't print 173 * there is no weight (cost) associated with stores, so don't print
171 * the column 174 * the column
172 */ 175 */
173 if (strcmp(mem_operation, MEM_OPERATION_LOAD)) 176 if (!(mem->operation & MEM_OPERATION_LOAD))
174 rep_argv[i++] = strdup("--sort=mem,sym,dso,symbol_daddr," 177 rep_argv[i++] = "--sort=mem,sym,dso,symbol_daddr,"
175 "dso_daddr,tlb,locked"); 178 "dso_daddr,tlb,locked";
176 179
177 for (j = 1; j < argc; j++, i++) 180 for (j = 1; j < argc; j++, i++)
178 rep_argv[i] = argv[j]; 181 rep_argv[i] = argv[j];
@@ -182,6 +185,75 @@ static int report_events(int argc, const char **argv, struct perf_mem *mem)
182 return ret; 185 return ret;
183} 186}
184 187
188struct mem_mode {
189 const char *name;
190 int mode;
191};
192
193#define MEM_OPT(n, m) \
194 { .name = n, .mode = (m) }
195
196#define MEM_END { .name = NULL }
197
198static const struct mem_mode mem_modes[]={
199 MEM_OPT("load", MEM_OPERATION_LOAD),
200 MEM_OPT("store", MEM_OPERATION_STORE),
201 MEM_END
202};
203
204static int
205parse_mem_ops(const struct option *opt, const char *str, int unset)
206{
207 int *mode = (int *)opt->value;
208 const struct mem_mode *m;
209 char *s, *os = NULL, *p;
210 int ret = -1;
211
212 if (unset)
213 return 0;
214
215 /* str may be NULL in case no arg is passed to -t */
216 if (str) {
217 /* because str is read-only */
218 s = os = strdup(str);
219 if (!s)
220 return -1;
221
222 /* reset mode */
223 *mode = 0;
224
225 for (;;) {
226 p = strchr(s, ',');
227 if (p)
228 *p = '\0';
229
230 for (m = mem_modes; m->name; m++) {
231 if (!strcasecmp(s, m->name))
232 break;
233 }
234 if (!m->name) {
235 fprintf(stderr, "unknown sampling op %s,"
236 " check man page\n", s);
237 goto error;
238 }
239
240 *mode |= m->mode;
241
242 if (!p)
243 break;
244
245 s = p + 1;
246 }
247 }
248 ret = 0;
249
250 if (*mode == 0)
251 *mode = MEM_OPERATION_LOAD;
252error:
253 free(os);
254 return ret;
255}
256
185int cmd_mem(int argc, const char **argv, const char *prefix __maybe_unused) 257int cmd_mem(int argc, const char **argv, const char *prefix __maybe_unused)
186{ 258{
187 struct stat st; 259 struct stat st;
@@ -197,10 +269,15 @@ int cmd_mem(int argc, const char **argv, const char *prefix __maybe_unused)
197 .ordered_events = true, 269 .ordered_events = true,
198 }, 270 },
199 .input_name = "perf.data", 271 .input_name = "perf.data",
272 /*
273 * default to both load an store sampling
274 */
275 .operation = MEM_OPERATION_LOAD | MEM_OPERATION_STORE,
200 }; 276 };
201 const struct option mem_options[] = { 277 const struct option mem_options[] = {
202 OPT_STRING('t', "type", &mem_operation, 278 OPT_CALLBACK('t', "type", &mem.operation,
203 "type", "memory operations(load/store)"), 279 "type", "memory operations(load,store) Default load,store",
280 parse_mem_ops),
204 OPT_BOOLEAN('D', "dump-raw-samples", &mem.dump_raw, 281 OPT_BOOLEAN('D', "dump-raw-samples", &mem.dump_raw,
205 "dump raw samples in ASCII"), 282 "dump raw samples in ASCII"),
206 OPT_BOOLEAN('U', "hide-unresolved", &mem.hide_unresolved, 283 OPT_BOOLEAN('U', "hide-unresolved", &mem.hide_unresolved,
@@ -225,7 +302,7 @@ int cmd_mem(int argc, const char **argv, const char *prefix __maybe_unused)
225 argc = parse_options_subcommand(argc, argv, mem_options, mem_subcommands, 302 argc = parse_options_subcommand(argc, argv, mem_options, mem_subcommands,
226 mem_usage, PARSE_OPT_STOP_AT_NON_OPTION); 303 mem_usage, PARSE_OPT_STOP_AT_NON_OPTION);
227 304
228 if (!argc || !(strncmp(argv[0], "rec", 3) || mem_operation)) 305 if (!argc || !(strncmp(argv[0], "rec", 3) || mem.operation))
229 usage_with_options(mem_usage, mem_options); 306 usage_with_options(mem_usage, mem_options);
230 307
231 if (!mem.input_name || !strlen(mem.input_name)) { 308 if (!mem.input_name || !strlen(mem.input_name)) {
@@ -236,7 +313,7 @@ int cmd_mem(int argc, const char **argv, const char *prefix __maybe_unused)
236 } 313 }
237 314
238 if (!strncmp(argv[0], "rec", 3)) 315 if (!strncmp(argv[0], "rec", 3))
239 return __cmd_record(argc, argv); 316 return __cmd_record(argc, argv, &mem);
240 else if (!strncmp(argv[0], "rep", 3)) 317 else if (!strncmp(argv[0], "rep", 3))
241 return report_events(argc, argv, &mem); 318 return report_events(argc, argv, &mem);
242 else 319 else
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 8648c6d3003d..404ab3434052 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -190,16 +190,30 @@ out:
190 return rc; 190 return rc;
191} 191}
192 192
193static int process_sample_event(struct perf_tool *tool,
194 union perf_event *event,
195 struct perf_sample *sample,
196 struct perf_evsel *evsel,
197 struct machine *machine)
198{
199 struct record *rec = container_of(tool, struct record, tool);
200
201 rec->samples++;
202
203 return build_id__mark_dso_hit(tool, event, sample, evsel, machine);
204}
205
193static int process_buildids(struct record *rec) 206static int process_buildids(struct record *rec)
194{ 207{
195 struct perf_data_file *file = &rec->file; 208 struct perf_data_file *file = &rec->file;
196 struct perf_session *session = rec->session; 209 struct perf_session *session = rec->session;
197 u64 start = session->header.data_offset;
198 210
199 u64 size = lseek(file->fd, 0, SEEK_CUR); 211 u64 size = lseek(perf_data_file__fd(file), 0, SEEK_CUR);
200 if (size == 0) 212 if (size == 0)
201 return 0; 213 return 0;
202 214
215 file->size = size;
216
203 /* 217 /*
204 * During this process, it'll load kernel map and replace the 218 * During this process, it'll load kernel map and replace the
205 * dso->long_name to a real pathname it found. In this case 219 * dso->long_name to a real pathname it found. In this case
@@ -211,9 +225,7 @@ static int process_buildids(struct record *rec)
211 */ 225 */
212 symbol_conf.ignore_vmlinux_buildid = true; 226 symbol_conf.ignore_vmlinux_buildid = true;
213 227
214 return __perf_session__process_events(session, start, 228 return perf_session__process_events(session, &rec->tool);
215 size - start,
216 size, &build_id__mark_dso_hit_ops);
217} 229}
218 230
219static void perf_event__synthesize_guest_os(struct machine *machine, void *data) 231static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
@@ -322,6 +334,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
322 struct perf_data_file *file = &rec->file; 334 struct perf_data_file *file = &rec->file;
323 struct perf_session *session; 335 struct perf_session *session;
324 bool disabled = false, draining = false; 336 bool disabled = false, draining = false;
337 int fd;
325 338
326 rec->progname = argv[0]; 339 rec->progname = argv[0];
327 340
@@ -336,6 +349,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
336 return -1; 349 return -1;
337 } 350 }
338 351
352 fd = perf_data_file__fd(file);
339 rec->session = session; 353 rec->session = session;
340 354
341 record__init_features(rec); 355 record__init_features(rec);
@@ -360,12 +374,11 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
360 perf_header__clear_feat(&session->header, HEADER_GROUP_DESC); 374 perf_header__clear_feat(&session->header, HEADER_GROUP_DESC);
361 375
362 if (file->is_pipe) { 376 if (file->is_pipe) {
363 err = perf_header__write_pipe(file->fd); 377 err = perf_header__write_pipe(fd);
364 if (err < 0) 378 if (err < 0)
365 goto out_child; 379 goto out_child;
366 } else { 380 } else {
367 err = perf_session__write_header(session, rec->evlist, 381 err = perf_session__write_header(session, rec->evlist, fd, false);
368 file->fd, false);
369 if (err < 0) 382 if (err < 0)
370 goto out_child; 383 goto out_child;
371 } 384 }
@@ -397,7 +410,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
397 * return this more properly and also 410 * return this more properly and also
398 * propagate errors that now are calling die() 411 * propagate errors that now are calling die()
399 */ 412 */
400 err = perf_event__synthesize_tracing_data(tool, file->fd, rec->evlist, 413 err = perf_event__synthesize_tracing_data(tool, fd, rec->evlist,
401 process_synthesized_event); 414 process_synthesized_event);
402 if (err <= 0) { 415 if (err <= 0) {
403 pr_err("Couldn't record tracing data.\n"); 416 pr_err("Couldn't record tracing data.\n");
@@ -504,19 +517,9 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
504 goto out_child; 517 goto out_child;
505 } 518 }
506 519
507 if (!quiet) { 520 if (!quiet)
508 fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking); 521 fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
509 522
510 /*
511 * Approximate RIP event size: 24 bytes.
512 */
513 fprintf(stderr,
514 "[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
515 (double)rec->bytes_written / 1024.0 / 1024.0,
516 file->path,
517 rec->bytes_written / 24);
518 }
519
520out_child: 523out_child:
521 if (forks) { 524 if (forks) {
522 int exit_status; 525 int exit_status;
@@ -535,13 +538,29 @@ out_child:
535 } else 538 } else
536 status = err; 539 status = err;
537 540
541 /* this will be recalculated during process_buildids() */
542 rec->samples = 0;
543
538 if (!err && !file->is_pipe) { 544 if (!err && !file->is_pipe) {
539 rec->session->header.data_size += rec->bytes_written; 545 rec->session->header.data_size += rec->bytes_written;
540 546
541 if (!rec->no_buildid) 547 if (!rec->no_buildid)
542 process_buildids(rec); 548 process_buildids(rec);
543 perf_session__write_header(rec->session, rec->evlist, 549 perf_session__write_header(rec->session, rec->evlist, fd, true);
544 file->fd, true); 550 }
551
552 if (!err && !quiet) {
553 char samples[128];
554
555 if (rec->samples)
556 scnprintf(samples, sizeof(samples),
557 " (%" PRIu64 " samples)", rec->samples);
558 else
559 samples[0] = '\0';
560
561 fprintf(stderr, "[ perf record: Captured and wrote %.3f MB %s%s ]\n",
562 perf_data_file__size(file) / 1024.0 / 1024.0,
563 file->path, samples);
545 } 564 }
546 565
547out_delete_session: 566out_delete_session:
@@ -720,6 +739,13 @@ static struct record record = {
720 .default_per_cpu = true, 739 .default_per_cpu = true,
721 }, 740 },
722 }, 741 },
742 .tool = {
743 .sample = process_sample_event,
744 .fork = perf_event__process_fork,
745 .comm = perf_event__process_comm,
746 .mmap = perf_event__process_mmap,
747 .mmap2 = perf_event__process_mmap2,
748 },
723}; 749};
724 750
725#define CALLCHAIN_HELP "setup and enables call-graph (stack chain/backtrace) recording: " 751#define CALLCHAIN_HELP "setup and enables call-graph (stack chain/backtrace) recording: "
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 072ae8ad67fc..2f91094e228b 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -86,17 +86,6 @@ static int report__config(const char *var, const char *value, void *cb)
86 return perf_default_config(var, value, cb); 86 return perf_default_config(var, value, cb);
87} 87}
88 88
89static void report__inc_stats(struct report *rep, struct hist_entry *he)
90{
91 /*
92 * The @he is either of a newly created one or an existing one
93 * merging current sample. We only want to count a new one so
94 * checking ->nr_events being 1.
95 */
96 if (he->stat.nr_events == 1)
97 rep->nr_entries++;
98}
99
100static int hist_iter__report_callback(struct hist_entry_iter *iter, 89static int hist_iter__report_callback(struct hist_entry_iter *iter,
101 struct addr_location *al, bool single, 90 struct addr_location *al, bool single,
102 void *arg) 91 void *arg)
@@ -108,8 +97,6 @@ static int hist_iter__report_callback(struct hist_entry_iter *iter,
108 struct mem_info *mi; 97 struct mem_info *mi;
109 struct branch_info *bi; 98 struct branch_info *bi;
110 99
111 report__inc_stats(rep, he);
112
113 if (!ui__has_annotation()) 100 if (!ui__has_annotation())
114 return 0; 101 return 0;
115 102
@@ -499,6 +486,9 @@ static int __cmd_report(struct report *rep)
499 486
500 report__warn_kptr_restrict(rep); 487 report__warn_kptr_restrict(rep);
501 488
489 evlist__for_each(session->evlist, pos)
490 rep->nr_entries += evsel__hists(pos)->nr_entries;
491
502 if (use_browser == 0) { 492 if (use_browser == 0) {
503 if (verbose > 3) 493 if (verbose > 3)
504 perf_session__fprintf(session, stdout); 494 perf_session__fprintf(session, stdout);
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 891086376381..e598e4e98170 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -1730,7 +1730,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1730 "detailed run - start a lot of events"), 1730 "detailed run - start a lot of events"),
1731 OPT_BOOLEAN('S', "sync", &sync_run, 1731 OPT_BOOLEAN('S', "sync", &sync_run,
1732 "call sync() before starting a run"), 1732 "call sync() before starting a run"),
1733 OPT_CALLBACK_NOOPT('B', "big-num", NULL, NULL, 1733 OPT_CALLBACK_NOOPT('B', "big-num", NULL, NULL,
1734 "print large numbers with thousands\' separators", 1734 "print large numbers with thousands\' separators",
1735 stat__set_big_num), 1735 stat__set_big_num),
1736 OPT_STRING('C', "cpu", &target.cpu_list, "cpu", 1736 OPT_STRING('C', "cpu", &target.cpu_list, "cpu",
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 616f0fcb4701..c4c7eac69de4 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -165,7 +165,7 @@ static void ui__warn_map_erange(struct map *map, struct symbol *sym, u64 ip)
165 err ? "[unknown]" : uts.release, perf_version_string); 165 err ? "[unknown]" : uts.release, perf_version_string);
166 if (use_browser <= 0) 166 if (use_browser <= 0)
167 sleep(5); 167 sleep(5);
168 168
169 map->erange_warned = true; 169 map->erange_warned = true;
170} 170}
171 171
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index badfabc6a01f..7e935f1083ec 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -929,66 +929,66 @@ static struct syscall_fmt {
929 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, }, 929 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
930 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), }, 930 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
931 { .name = "close", .errmsg = true, 931 { .name = "close", .errmsg = true,
932 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, }, 932 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
933 { .name = "connect", .errmsg = true, }, 933 { .name = "connect", .errmsg = true, },
934 { .name = "dup", .errmsg = true, 934 { .name = "dup", .errmsg = true,
935 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, 935 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
936 { .name = "dup2", .errmsg = true, 936 { .name = "dup2", .errmsg = true,
937 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, 937 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
938 { .name = "dup3", .errmsg = true, 938 { .name = "dup3", .errmsg = true,
939 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, 939 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
940 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), }, 940 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
941 { .name = "eventfd2", .errmsg = true, 941 { .name = "eventfd2", .errmsg = true,
942 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, }, 942 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
943 { .name = "faccessat", .errmsg = true, 943 { .name = "faccessat", .errmsg = true,
944 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, }, 944 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
945 { .name = "fadvise64", .errmsg = true, 945 { .name = "fadvise64", .errmsg = true,
946 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, 946 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
947 { .name = "fallocate", .errmsg = true, 947 { .name = "fallocate", .errmsg = true,
948 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, 948 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
949 { .name = "fchdir", .errmsg = true, 949 { .name = "fchdir", .errmsg = true,
950 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, 950 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
951 { .name = "fchmod", .errmsg = true, 951 { .name = "fchmod", .errmsg = true,
952 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, 952 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
953 { .name = "fchmodat", .errmsg = true, 953 { .name = "fchmodat", .errmsg = true,
954 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, }, 954 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
955 { .name = "fchown", .errmsg = true, 955 { .name = "fchown", .errmsg = true,
956 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, 956 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
957 { .name = "fchownat", .errmsg = true, 957 { .name = "fchownat", .errmsg = true,
958 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, }, 958 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
959 { .name = "fcntl", .errmsg = true, 959 { .name = "fcntl", .errmsg = true,
960 .arg_scnprintf = { [0] = SCA_FD, /* fd */ 960 .arg_scnprintf = { [0] = SCA_FD, /* fd */
961 [1] = SCA_STRARRAY, /* cmd */ }, 961 [1] = SCA_STRARRAY, /* cmd */ },
962 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, }, 962 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
963 { .name = "fdatasync", .errmsg = true, 963 { .name = "fdatasync", .errmsg = true,
964 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, 964 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
965 { .name = "flock", .errmsg = true, 965 { .name = "flock", .errmsg = true,
966 .arg_scnprintf = { [0] = SCA_FD, /* fd */ 966 .arg_scnprintf = { [0] = SCA_FD, /* fd */
967 [1] = SCA_FLOCK, /* cmd */ }, }, 967 [1] = SCA_FLOCK, /* cmd */ }, },
968 { .name = "fsetxattr", .errmsg = true, 968 { .name = "fsetxattr", .errmsg = true,
969 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, 969 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
970 { .name = "fstat", .errmsg = true, .alias = "newfstat", 970 { .name = "fstat", .errmsg = true, .alias = "newfstat",
971 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, 971 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
972 { .name = "fstatat", .errmsg = true, .alias = "newfstatat", 972 { .name = "fstatat", .errmsg = true, .alias = "newfstatat",
973 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, }, 973 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
974 { .name = "fstatfs", .errmsg = true, 974 { .name = "fstatfs", .errmsg = true,
975 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, 975 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
976 { .name = "fsync", .errmsg = true, 976 { .name = "fsync", .errmsg = true,
977 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, 977 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
978 { .name = "ftruncate", .errmsg = true, 978 { .name = "ftruncate", .errmsg = true,
979 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, 979 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
980 { .name = "futex", .errmsg = true, 980 { .name = "futex", .errmsg = true,
981 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, }, 981 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
982 { .name = "futimesat", .errmsg = true, 982 { .name = "futimesat", .errmsg = true,
983 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, }, 983 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
984 { .name = "getdents", .errmsg = true, 984 { .name = "getdents", .errmsg = true,
985 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, 985 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
986 { .name = "getdents64", .errmsg = true, 986 { .name = "getdents64", .errmsg = true,
987 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, 987 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
988 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), }, 988 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
989 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), }, 989 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
990 { .name = "ioctl", .errmsg = true, 990 { .name = "ioctl", .errmsg = true,
991 .arg_scnprintf = { [0] = SCA_FD, /* fd */ 991 .arg_scnprintf = { [0] = SCA_FD, /* fd */
992#if defined(__i386__) || defined(__x86_64__) 992#if defined(__i386__) || defined(__x86_64__)
993/* 993/*
994 * FIXME: Make this available to all arches. 994 * FIXME: Make this available to all arches.
@@ -1002,7 +1002,7 @@ static struct syscall_fmt {
1002 { .name = "kill", .errmsg = true, 1002 { .name = "kill", .errmsg = true,
1003 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, }, 1003 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
1004 { .name = "linkat", .errmsg = true, 1004 { .name = "linkat", .errmsg = true,
1005 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, }, 1005 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
1006 { .name = "lseek", .errmsg = true, 1006 { .name = "lseek", .errmsg = true,
1007 .arg_scnprintf = { [0] = SCA_FD, /* fd */ 1007 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1008 [2] = SCA_STRARRAY, /* whence */ }, 1008 [2] = SCA_STRARRAY, /* whence */ },
@@ -1012,9 +1012,9 @@ static struct syscall_fmt {
1012 .arg_scnprintf = { [0] = SCA_HEX, /* start */ 1012 .arg_scnprintf = { [0] = SCA_HEX, /* start */
1013 [2] = SCA_MADV_BHV, /* behavior */ }, }, 1013 [2] = SCA_MADV_BHV, /* behavior */ }, },
1014 { .name = "mkdirat", .errmsg = true, 1014 { .name = "mkdirat", .errmsg = true,
1015 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, }, 1015 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
1016 { .name = "mknodat", .errmsg = true, 1016 { .name = "mknodat", .errmsg = true,
1017 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, }, 1017 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
1018 { .name = "mlock", .errmsg = true, 1018 { .name = "mlock", .errmsg = true,
1019 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, }, 1019 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
1020 { .name = "mlockall", .errmsg = true, 1020 { .name = "mlockall", .errmsg = true,
@@ -1036,9 +1036,9 @@ static struct syscall_fmt {
1036 { .name = "munmap", .errmsg = true, 1036 { .name = "munmap", .errmsg = true,
1037 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, }, 1037 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
1038 { .name = "name_to_handle_at", .errmsg = true, 1038 { .name = "name_to_handle_at", .errmsg = true,
1039 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, }, 1039 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
1040 { .name = "newfstatat", .errmsg = true, 1040 { .name = "newfstatat", .errmsg = true,
1041 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, }, 1041 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
1042 { .name = "open", .errmsg = true, 1042 { .name = "open", .errmsg = true,
1043 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, }, 1043 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
1044 { .name = "open_by_handle_at", .errmsg = true, 1044 { .name = "open_by_handle_at", .errmsg = true,
@@ -1052,20 +1052,20 @@ static struct syscall_fmt {
1052 { .name = "poll", .errmsg = true, .timeout = true, }, 1052 { .name = "poll", .errmsg = true, .timeout = true, },
1053 { .name = "ppoll", .errmsg = true, .timeout = true, }, 1053 { .name = "ppoll", .errmsg = true, .timeout = true, },
1054 { .name = "pread", .errmsg = true, .alias = "pread64", 1054 { .name = "pread", .errmsg = true, .alias = "pread64",
1055 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, 1055 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1056 { .name = "preadv", .errmsg = true, .alias = "pread", 1056 { .name = "preadv", .errmsg = true, .alias = "pread",
1057 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, 1057 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1058 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), }, 1058 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
1059 { .name = "pwrite", .errmsg = true, .alias = "pwrite64", 1059 { .name = "pwrite", .errmsg = true, .alias = "pwrite64",
1060 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, 1060 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1061 { .name = "pwritev", .errmsg = true, 1061 { .name = "pwritev", .errmsg = true,
1062 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, 1062 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1063 { .name = "read", .errmsg = true, 1063 { .name = "read", .errmsg = true,
1064 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, 1064 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1065 { .name = "readlinkat", .errmsg = true, 1065 { .name = "readlinkat", .errmsg = true,
1066 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, }, 1066 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
1067 { .name = "readv", .errmsg = true, 1067 { .name = "readv", .errmsg = true,
1068 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, 1068 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1069 { .name = "recvfrom", .errmsg = true, 1069 { .name = "recvfrom", .errmsg = true,
1070 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, }, 1070 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
1071 { .name = "recvmmsg", .errmsg = true, 1071 { .name = "recvmmsg", .errmsg = true,
@@ -1073,7 +1073,7 @@ static struct syscall_fmt {
1073 { .name = "recvmsg", .errmsg = true, 1073 { .name = "recvmsg", .errmsg = true,
1074 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, }, 1074 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
1075 { .name = "renameat", .errmsg = true, 1075 { .name = "renameat", .errmsg = true,
1076 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, }, 1076 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
1077 { .name = "rt_sigaction", .errmsg = true, 1077 { .name = "rt_sigaction", .errmsg = true,
1078 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, }, 1078 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
1079 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), }, 1079 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
@@ -1091,7 +1091,7 @@ static struct syscall_fmt {
1091 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), }, 1091 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
1092 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), }, 1092 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
1093 { .name = "shutdown", .errmsg = true, 1093 { .name = "shutdown", .errmsg = true,
1094 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, 1094 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1095 { .name = "socket", .errmsg = true, 1095 { .name = "socket", .errmsg = true,
1096 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */ 1096 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1097 [1] = SCA_SK_TYPE, /* type */ }, 1097 [1] = SCA_SK_TYPE, /* type */ },
@@ -1102,7 +1102,7 @@ static struct syscall_fmt {
1102 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, }, 1102 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
1103 { .name = "stat", .errmsg = true, .alias = "newstat", }, 1103 { .name = "stat", .errmsg = true, .alias = "newstat", },
1104 { .name = "symlinkat", .errmsg = true, 1104 { .name = "symlinkat", .errmsg = true,
1105 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, }, 1105 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
1106 { .name = "tgkill", .errmsg = true, 1106 { .name = "tgkill", .errmsg = true,
1107 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, }, 1107 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
1108 { .name = "tkill", .errmsg = true, 1108 { .name = "tkill", .errmsg = true,
@@ -1113,9 +1113,9 @@ static struct syscall_fmt {
1113 { .name = "utimensat", .errmsg = true, 1113 { .name = "utimensat", .errmsg = true,
1114 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */ }, }, 1114 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */ }, },
1115 { .name = "write", .errmsg = true, 1115 { .name = "write", .errmsg = true,
1116 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, 1116 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1117 { .name = "writev", .errmsg = true, 1117 { .name = "writev", .errmsg = true,
1118 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, 1118 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
1119}; 1119};
1120 1120
1121static int syscall_fmt__cmp(const void *name, const void *fmtp) 1121static int syscall_fmt__cmp(const void *name, const void *fmtp)
@@ -1191,7 +1191,7 @@ static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
1191 1191
1192 if (thread__priv(thread) == NULL) 1192 if (thread__priv(thread) == NULL)
1193 thread__set_priv(thread, thread_trace__new()); 1193 thread__set_priv(thread, thread_trace__new());
1194 1194
1195 if (thread__priv(thread) == NULL) 1195 if (thread__priv(thread) == NULL)
1196 goto fail; 1196 goto fail;
1197 1197
@@ -2056,23 +2056,24 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
2056 if (trace->trace_syscalls && 2056 if (trace->trace_syscalls &&
2057 perf_evlist__add_syscall_newtp(evlist, trace__sys_enter, 2057 perf_evlist__add_syscall_newtp(evlist, trace__sys_enter,
2058 trace__sys_exit)) 2058 trace__sys_exit))
2059 goto out_error_tp; 2059 goto out_error_raw_syscalls;
2060 2060
2061 if (trace->trace_syscalls) 2061 if (trace->trace_syscalls)
2062 perf_evlist__add_vfs_getname(evlist); 2062 perf_evlist__add_vfs_getname(evlist);
2063 2063
2064 if ((trace->trace_pgfaults & TRACE_PFMAJ) && 2064 if ((trace->trace_pgfaults & TRACE_PFMAJ) &&
2065 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MAJ)) 2065 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MAJ)) {
2066 goto out_error_tp; 2066 goto out_error_mem;
2067 }
2067 2068
2068 if ((trace->trace_pgfaults & TRACE_PFMIN) && 2069 if ((trace->trace_pgfaults & TRACE_PFMIN) &&
2069 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MIN)) 2070 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MIN))
2070 goto out_error_tp; 2071 goto out_error_mem;
2071 2072
2072 if (trace->sched && 2073 if (trace->sched &&
2073 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime", 2074 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2074 trace__sched_stat_runtime)) 2075 trace__sched_stat_runtime))
2075 goto out_error_tp; 2076 goto out_error_sched_stat_runtime;
2076 2077
2077 err = perf_evlist__create_maps(evlist, &trace->opts.target); 2078 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2078 if (err < 0) { 2079 if (err < 0) {
@@ -2202,8 +2203,12 @@ out:
2202{ 2203{
2203 char errbuf[BUFSIZ]; 2204 char errbuf[BUFSIZ];
2204 2205
2205out_error_tp: 2206out_error_sched_stat_runtime:
2206 perf_evlist__strerror_tp(evlist, errno, errbuf, sizeof(errbuf)); 2207 debugfs__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
2208 goto out_error;
2209
2210out_error_raw_syscalls:
2211 debugfs__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
2207 goto out_error; 2212 goto out_error;
2208 2213
2209out_error_mmap: 2214out_error_mmap:
@@ -2217,6 +2222,9 @@ out_error:
2217 fprintf(trace->output, "%s\n", errbuf); 2222 fprintf(trace->output, "%s\n", errbuf);
2218 goto out_delete_evlist; 2223 goto out_delete_evlist;
2219} 2224}
2225out_error_mem:
2226 fprintf(trace->output, "Not enough memory to run!\n");
2227 goto out_delete_evlist;
2220} 2228}
2221 2229
2222static int trace__replay(struct trace *trace) 2230static int trace__replay(struct trace *trace)
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
index 648e31ff4021..cc224080b525 100644
--- a/tools/perf/config/Makefile
+++ b/tools/perf/config/Makefile
@@ -198,6 +198,7 @@ CORE_FEATURE_TESTS = \
198 libpython-version \ 198 libpython-version \
199 libslang \ 199 libslang \
200 libunwind \ 200 libunwind \
201 pthread-attr-setaffinity-np \
201 stackprotector-all \ 202 stackprotector-all \
202 timerfd \ 203 timerfd \
203 libdw-dwarf-unwind \ 204 libdw-dwarf-unwind \
@@ -226,6 +227,7 @@ VF_FEATURE_TESTS = \
226 libelf-getphdrnum \ 227 libelf-getphdrnum \
227 libelf-mmap \ 228 libelf-mmap \
228 libpython-version \ 229 libpython-version \
230 pthread-attr-setaffinity-np \
229 stackprotector-all \ 231 stackprotector-all \
230 timerfd \ 232 timerfd \
231 libunwind-debug-frame \ 233 libunwind-debug-frame \
@@ -301,6 +303,10 @@ ifeq ($(feature-sync-compare-and-swap), 1)
301 CFLAGS += -DHAVE_SYNC_COMPARE_AND_SWAP_SUPPORT 303 CFLAGS += -DHAVE_SYNC_COMPARE_AND_SWAP_SUPPORT
302endif 304endif
303 305
306ifeq ($(feature-pthread-attr-setaffinity-np), 1)
307 CFLAGS += -DHAVE_PTHREAD_ATTR_SETAFFINITY_NP
308endif
309
304ifndef NO_BIONIC 310ifndef NO_BIONIC
305 $(call feature_check,bionic) 311 $(call feature_check,bionic)
306 ifeq ($(feature-bionic), 1) 312 ifeq ($(feature-bionic), 1)
diff --git a/tools/perf/config/feature-checks/Makefile b/tools/perf/config/feature-checks/Makefile
index 53f19b5dbc37..42ac05aaf8ac 100644
--- a/tools/perf/config/feature-checks/Makefile
+++ b/tools/perf/config/feature-checks/Makefile
@@ -25,6 +25,7 @@ FILES= \
25 test-libslang.bin \ 25 test-libslang.bin \
26 test-libunwind.bin \ 26 test-libunwind.bin \
27 test-libunwind-debug-frame.bin \ 27 test-libunwind-debug-frame.bin \
28 test-pthread-attr-setaffinity-np.bin \
28 test-stackprotector-all.bin \ 29 test-stackprotector-all.bin \
29 test-timerfd.bin \ 30 test-timerfd.bin \
30 test-libdw-dwarf-unwind.bin \ 31 test-libdw-dwarf-unwind.bin \
@@ -47,6 +48,9 @@ test-all.bin:
47test-hello.bin: 48test-hello.bin:
48 $(BUILD) 49 $(BUILD)
49 50
51test-pthread-attr-setaffinity-np.bin:
52 $(BUILD) -Werror -lpthread
53
50test-stackprotector-all.bin: 54test-stackprotector-all.bin:
51 $(BUILD) -Werror -fstack-protector-all 55 $(BUILD) -Werror -fstack-protector-all
52 56
diff --git a/tools/perf/config/feature-checks/test-all.c b/tools/perf/config/feature-checks/test-all.c
index 652e0098eba6..6d4d09323922 100644
--- a/tools/perf/config/feature-checks/test-all.c
+++ b/tools/perf/config/feature-checks/test-all.c
@@ -97,6 +97,10 @@
97# include "test-zlib.c" 97# include "test-zlib.c"
98#undef main 98#undef main
99 99
100#define main main_test_pthread_attr_setaffinity_np
101# include "test-pthread_attr_setaffinity_np.c"
102#undef main
103
100int main(int argc, char *argv[]) 104int main(int argc, char *argv[])
101{ 105{
102 main_test_libpython(); 106 main_test_libpython();
@@ -121,6 +125,7 @@ int main(int argc, char *argv[])
121 main_test_libdw_dwarf_unwind(); 125 main_test_libdw_dwarf_unwind();
122 main_test_sync_compare_and_swap(argc, argv); 126 main_test_sync_compare_and_swap(argc, argv);
123 main_test_zlib(); 127 main_test_zlib();
128 main_test_pthread_attr_setaffinity_np();
124 129
125 return 0; 130 return 0;
126} 131}
diff --git a/tools/perf/config/feature-checks/test-pthread-attr-setaffinity-np.c b/tools/perf/config/feature-checks/test-pthread-attr-setaffinity-np.c
new file mode 100644
index 000000000000..0a0d3ecb4e8a
--- /dev/null
+++ b/tools/perf/config/feature-checks/test-pthread-attr-setaffinity-np.c
@@ -0,0 +1,14 @@
1#include <stdint.h>
2#include <pthread.h>
3
4int main(void)
5{
6 int ret = 0;
7 pthread_attr_t thread_attr;
8
9 pthread_attr_init(&thread_attr);
10 /* don't care abt exact args, just the API itself in libpthread */
11 ret = pthread_attr_setaffinity_np(&thread_attr, 0, NULL);
12
13 return ret;
14}
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/Context.c b/tools/perf/scripts/perl/Perf-Trace-Util/Context.c
index 790ceba6ad3f..28431d1bbcf5 100644
--- a/tools/perf/scripts/perl/Perf-Trace-Util/Context.c
+++ b/tools/perf/scripts/perl/Perf-Trace-Util/Context.c
@@ -5,7 +5,10 @@
5 * ANY CHANGES MADE HERE WILL BE LOST! 5 * ANY CHANGES MADE HERE WILL BE LOST!
6 * 6 *
7 */ 7 */
8 8#include <stdbool.h>
9#ifndef HAS_BOOL
10# define HAS_BOOL 1
11#endif
9#line 1 "Context.xs" 12#line 1 "Context.xs"
10/* 13/*
11 * Context.xs. XS interfaces for perf script. 14 * Context.xs. XS interfaces for perf script.
diff --git a/tools/perf/tests/attr.py b/tools/perf/tests/attr.py
index c9b4b6269b51..1091bd47adfd 100644
--- a/tools/perf/tests/attr.py
+++ b/tools/perf/tests/attr.py
@@ -104,7 +104,6 @@ class Event(dict):
104 continue 104 continue
105 if not self.compare_data(self[t], other[t]): 105 if not self.compare_data(self[t], other[t]):
106 log.warning("expected %s=%s, got %s" % (t, self[t], other[t])) 106 log.warning("expected %s=%s, got %s" % (t, self[t], other[t]))
107
108 107
109# Test file description needs to have following sections: 108# Test file description needs to have following sections:
110# [config] 109# [config]
diff --git a/tools/perf/tests/hists_cumulate.c b/tools/perf/tests/hists_cumulate.c
index 8d110dec393e..18619966454c 100644
--- a/tools/perf/tests/hists_cumulate.c
+++ b/tools/perf/tests/hists_cumulate.c
@@ -140,7 +140,7 @@ static void del_hist_entries(struct hists *hists)
140 he = rb_entry(node, struct hist_entry, rb_node); 140 he = rb_entry(node, struct hist_entry, rb_node);
141 rb_erase(node, root_out); 141 rb_erase(node, root_out);
142 rb_erase(&he->rb_node_in, root_in); 142 rb_erase(&he->rb_node_in, root_in);
143 hist_entry__free(he); 143 hist_entry__delete(he);
144 } 144 }
145} 145}
146 146
diff --git a/tools/perf/tests/hists_output.c b/tools/perf/tests/hists_output.c
index f5547610da02..b52c9faea224 100644
--- a/tools/perf/tests/hists_output.c
+++ b/tools/perf/tests/hists_output.c
@@ -106,7 +106,7 @@ static void del_hist_entries(struct hists *hists)
106 he = rb_entry(node, struct hist_entry, rb_node); 106 he = rb_entry(node, struct hist_entry, rb_node);
107 rb_erase(node, root_out); 107 rb_erase(node, root_out);
108 rb_erase(&he->rb_node_in, root_in); 108 rb_erase(&he->rb_node_in, root_in);
109 hist_entry__free(he); 109 hist_entry__delete(he);
110 } 110 }
111} 111}
112 112
diff --git a/tools/perf/tests/make b/tools/perf/tests/make
index 69a71ff84e01..75709d2b17b4 100644
--- a/tools/perf/tests/make
+++ b/tools/perf/tests/make
@@ -222,7 +222,6 @@ tarpkg:
222 @cmd="$(PERF)/tests/perf-targz-src-pkg $(PERF)"; \ 222 @cmd="$(PERF)/tests/perf-targz-src-pkg $(PERF)"; \
223 echo "- $@: $$cmd" && echo $$cmd > $@ && \ 223 echo "- $@: $$cmd" && echo $$cmd > $@ && \
224 ( eval $$cmd ) >> $@ 2>&1 224 ( eval $$cmd ) >> $@ 2>&1
225
226 225
227all: $(run) $(run_O) tarpkg 226all: $(run) $(run_O) tarpkg
228 @echo OK 227 @echo OK
diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c
index 7f2f51f93619..1cdab0ce00e2 100644
--- a/tools/perf/tests/parse-events.c
+++ b/tools/perf/tests/parse-events.c
@@ -1145,6 +1145,49 @@ static int test__pinned_group(struct perf_evlist *evlist)
1145 return 0; 1145 return 0;
1146} 1146}
1147 1147
1148static int test__checkevent_breakpoint_len(struct perf_evlist *evlist)
1149{
1150 struct perf_evsel *evsel = perf_evlist__first(evlist);
1151
1152 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
1153 TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type);
1154 TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
1155 TEST_ASSERT_VAL("wrong bp_type", (HW_BREAKPOINT_R | HW_BREAKPOINT_W) ==
1156 evsel->attr.bp_type);
1157 TEST_ASSERT_VAL("wrong bp_len", HW_BREAKPOINT_LEN_1 ==
1158 evsel->attr.bp_len);
1159
1160 return 0;
1161}
1162
1163static int test__checkevent_breakpoint_len_w(struct perf_evlist *evlist)
1164{
1165 struct perf_evsel *evsel = perf_evlist__first(evlist);
1166
1167 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
1168 TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type);
1169 TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
1170 TEST_ASSERT_VAL("wrong bp_type", HW_BREAKPOINT_W ==
1171 evsel->attr.bp_type);
1172 TEST_ASSERT_VAL("wrong bp_len", HW_BREAKPOINT_LEN_2 ==
1173 evsel->attr.bp_len);
1174
1175 return 0;
1176}
1177
1178static int
1179test__checkevent_breakpoint_len_rw_modifier(struct perf_evlist *evlist)
1180{
1181 struct perf_evsel *evsel = perf_evlist__first(evlist);
1182
1183 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
1184 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
1185 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
1186 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
1187
1188 return test__checkevent_breakpoint_rw(evlist);
1189}
1190
1148static int count_tracepoints(void) 1191static int count_tracepoints(void)
1149{ 1192{
1150 char events_path[PATH_MAX]; 1193 char events_path[PATH_MAX];
@@ -1420,6 +1463,21 @@ static struct evlist_test test__events[] = {
1420 .check = test__pinned_group, 1463 .check = test__pinned_group,
1421 .id = 41, 1464 .id = 41,
1422 }, 1465 },
1466 {
1467 .name = "mem:0/1",
1468 .check = test__checkevent_breakpoint_len,
1469 .id = 42,
1470 },
1471 {
1472 .name = "mem:0/2:w",
1473 .check = test__checkevent_breakpoint_len_w,
1474 .id = 43,
1475 },
1476 {
1477 .name = "mem:0/4:rw:u",
1478 .check = test__checkevent_breakpoint_len_rw_modifier,
1479 .id = 44
1480 },
1423#if defined(__s390x__) 1481#if defined(__s390x__)
1424 { 1482 {
1425 .name = "kvm-s390:kvm_s390_create_vm", 1483 .name = "kvm-s390:kvm_s390_create_vm",
@@ -1471,7 +1529,7 @@ static int test_event(struct evlist_test *e)
1471 } else { 1529 } else {
1472 ret = e->check(evlist); 1530 ret = e->check(evlist);
1473 } 1531 }
1474 1532
1475 perf_evlist__delete(evlist); 1533 perf_evlist__delete(evlist);
1476 1534
1477 return ret; 1535 return ret;
diff --git a/tools/perf/tests/sample-parsing.c b/tools/perf/tests/sample-parsing.c
index 4908c648a597..30c02181e78b 100644
--- a/tools/perf/tests/sample-parsing.c
+++ b/tools/perf/tests/sample-parsing.c
@@ -110,7 +110,7 @@ static bool samples_same(const struct perf_sample *s1,
110 110
111 if (type & PERF_SAMPLE_STACK_USER) { 111 if (type & PERF_SAMPLE_STACK_USER) {
112 COMP(user_stack.size); 112 COMP(user_stack.size);
113 if (memcmp(s1->user_stack.data, s1->user_stack.data, 113 if (memcmp(s1->user_stack.data, s2->user_stack.data,
114 s1->user_stack.size)) { 114 s1->user_stack.size)) {
115 pr_debug("Samples differ at 'user_stack'\n"); 115 pr_debug("Samples differ at 'user_stack'\n");
116 return false; 116 return false;
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c
index 1e0a2fd80115..9d32e3c0cfee 100644
--- a/tools/perf/ui/browsers/annotate.c
+++ b/tools/perf/ui/browsers/annotate.c
@@ -517,7 +517,7 @@ static bool annotate_browser__jump(struct annotate_browser *browser)
517 } 517 }
518 518
519 annotate_browser__set_top(browser, dl, idx); 519 annotate_browser__set_top(browser, dl, idx);
520 520
521 return true; 521 return true;
522} 522}
523 523
@@ -867,7 +867,6 @@ static void annotate_browser__mark_jump_targets(struct annotate_browser *browser
867 867
868 ++browser->nr_jumps; 868 ++browser->nr_jumps;
869 } 869 }
870
871} 870}
872 871
873static inline int width_jumps(int n) 872static inline int width_jumps(int n)
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
index 482adae3cc44..25d608394d74 100644
--- a/tools/perf/ui/hist.c
+++ b/tools/perf/ui/hist.c
@@ -285,7 +285,8 @@ static int hpp__entry_##_type(struct perf_hpp_fmt *fmt, \
285} 285}
286 286
287#define __HPP_SORT_FN(_type, _field) \ 287#define __HPP_SORT_FN(_type, _field) \
288static int64_t hpp__sort_##_type(struct hist_entry *a, struct hist_entry *b) \ 288static int64_t hpp__sort_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \
289 struct hist_entry *a, struct hist_entry *b) \
289{ \ 290{ \
290 return __hpp__sort(a, b, he_get_##_field); \ 291 return __hpp__sort(a, b, he_get_##_field); \
291} 292}
@@ -312,7 +313,8 @@ static int hpp__entry_##_type(struct perf_hpp_fmt *fmt, \
312} 313}
313 314
314#define __HPP_SORT_ACC_FN(_type, _field) \ 315#define __HPP_SORT_ACC_FN(_type, _field) \
315static int64_t hpp__sort_##_type(struct hist_entry *a, struct hist_entry *b) \ 316static int64_t hpp__sort_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \
317 struct hist_entry *a, struct hist_entry *b) \
316{ \ 318{ \
317 return __hpp__sort_acc(a, b, he_get_acc_##_field); \ 319 return __hpp__sort_acc(a, b, he_get_acc_##_field); \
318} 320}
@@ -331,7 +333,8 @@ static int hpp__entry_##_type(struct perf_hpp_fmt *fmt, \
331} 333}
332 334
333#define __HPP_SORT_RAW_FN(_type, _field) \ 335#define __HPP_SORT_RAW_FN(_type, _field) \
334static int64_t hpp__sort_##_type(struct hist_entry *a, struct hist_entry *b) \ 336static int64_t hpp__sort_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \
337 struct hist_entry *a, struct hist_entry *b) \
335{ \ 338{ \
336 return __hpp__sort(a, b, he_get_raw_##_field); \ 339 return __hpp__sort(a, b, he_get_raw_##_field); \
337} 340}
@@ -361,7 +364,8 @@ HPP_PERCENT_ACC_FNS(overhead_acc, period)
361HPP_RAW_FNS(samples, nr_events) 364HPP_RAW_FNS(samples, nr_events)
362HPP_RAW_FNS(period, period) 365HPP_RAW_FNS(period, period)
363 366
364static int64_t hpp__nop_cmp(struct hist_entry *a __maybe_unused, 367static int64_t hpp__nop_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
368 struct hist_entry *a __maybe_unused,
365 struct hist_entry *b __maybe_unused) 369 struct hist_entry *b __maybe_unused)
366{ 370{
367 return 0; 371 return 0;
diff --git a/tools/perf/ui/progress.h b/tools/perf/ui/progress.h
index f34f89eb607c..717d39d3052b 100644
--- a/tools/perf/ui/progress.h
+++ b/tools/perf/ui/progress.h
@@ -4,12 +4,12 @@
4#include <linux/types.h> 4#include <linux/types.h>
5 5
6void ui_progress__finish(void); 6void ui_progress__finish(void);
7 7
8struct ui_progress { 8struct ui_progress {
9 const char *title; 9 const char *title;
10 u64 curr, next, step, total; 10 u64 curr, next, step, total;
11}; 11};
12 12
13void ui_progress__init(struct ui_progress *p, u64 total, const char *title); 13void ui_progress__init(struct ui_progress *p, u64 total, const char *title);
14void ui_progress__update(struct ui_progress *p, u64 adv); 14void ui_progress__update(struct ui_progress *p, u64 adv);
15 15
diff --git a/tools/perf/ui/tui/helpline.c b/tools/perf/ui/tui/helpline.c
index 1c8b9afd5d6e..88f5143a5981 100644
--- a/tools/perf/ui/tui/helpline.c
+++ b/tools/perf/ui/tui/helpline.c
@@ -9,6 +9,7 @@
9#include "../libslang.h" 9#include "../libslang.h"
10 10
11char ui_helpline__last_msg[1024]; 11char ui_helpline__last_msg[1024];
12bool tui_helpline__set;
12 13
13static void tui_helpline__pop(void) 14static void tui_helpline__pop(void)
14{ 15{
@@ -35,6 +36,8 @@ static int tui_helpline__show(const char *format, va_list ap)
35 sizeof(ui_helpline__last_msg) - backlog, format, ap); 36 sizeof(ui_helpline__last_msg) - backlog, format, ap);
36 backlog += ret; 37 backlog += ret;
37 38
39 tui_helpline__set = true;
40
38 if (ui_helpline__last_msg[backlog - 1] == '\n') { 41 if (ui_helpline__last_msg[backlog - 1] == '\n') {
39 ui_helpline__puts(ui_helpline__last_msg); 42 ui_helpline__puts(ui_helpline__last_msg);
40 SLsmg_refresh(); 43 SLsmg_refresh();
diff --git a/tools/perf/ui/tui/setup.c b/tools/perf/ui/tui/setup.c
index 3c38f25b1695..b77e1d771363 100644
--- a/tools/perf/ui/tui/setup.c
+++ b/tools/perf/ui/tui/setup.c
@@ -17,6 +17,7 @@
17static volatile int ui__need_resize; 17static volatile int ui__need_resize;
18 18
19extern struct perf_error_ops perf_tui_eops; 19extern struct perf_error_ops perf_tui_eops;
20extern bool tui_helpline__set;
20 21
21extern void hist_browser__init_hpp(void); 22extern void hist_browser__init_hpp(void);
22 23
@@ -159,7 +160,7 @@ out:
159 160
160void ui__exit(bool wait_for_ok) 161void ui__exit(bool wait_for_ok)
161{ 162{
162 if (wait_for_ok) 163 if (wait_for_ok && tui_helpline__set)
163 ui__question_window("Fatal Error", 164 ui__question_window("Fatal Error",
164 ui_helpline__last_msg, 165 ui_helpline__last_msg,
165 "Press any key...", 0); 166 "Press any key...", 0);
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 79999ceaf2be..61bf9128e1f2 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -177,14 +177,17 @@ static int lock__parse(struct ins_operands *ops)
177 goto out_free_ops; 177 goto out_free_ops;
178 178
179 ops->locked.ins = ins__find(name); 179 ops->locked.ins = ins__find(name);
180 free(name);
181
180 if (ops->locked.ins == NULL) 182 if (ops->locked.ins == NULL)
181 goto out_free_ops; 183 goto out_free_ops;
182 184
183 if (!ops->locked.ins->ops) 185 if (!ops->locked.ins->ops)
184 return 0; 186 return 0;
185 187
186 if (ops->locked.ins->ops->parse) 188 if (ops->locked.ins->ops->parse &&
187 ops->locked.ins->ops->parse(ops->locked.ops); 189 ops->locked.ins->ops->parse(ops->locked.ops) < 0)
190 goto out_free_ops;
188 191
189 return 0; 192 return 0;
190 193
@@ -208,6 +211,13 @@ static int lock__scnprintf(struct ins *ins, char *bf, size_t size,
208 211
209static void lock__delete(struct ins_operands *ops) 212static void lock__delete(struct ins_operands *ops)
210{ 213{
214 struct ins *ins = ops->locked.ins;
215
216 if (ins && ins->ops->free)
217 ins->ops->free(ops->locked.ops);
218 else
219 ins__delete(ops->locked.ops);
220
211 zfree(&ops->locked.ops); 221 zfree(&ops->locked.ops);
212 zfree(&ops->target.raw); 222 zfree(&ops->target.raw);
213 zfree(&ops->target.name); 223 zfree(&ops->target.name);
@@ -229,7 +239,7 @@ static int mov__parse(struct ins_operands *ops)
229 *s = '\0'; 239 *s = '\0';
230 ops->source.raw = strdup(ops->raw); 240 ops->source.raw = strdup(ops->raw);
231 *s = ','; 241 *s = ',';
232 242
233 if (ops->source.raw == NULL) 243 if (ops->source.raw == NULL)
234 return -1; 244 return -1;
235 245
@@ -531,8 +541,8 @@ static void disasm_line__init_ins(struct disasm_line *dl)
531 if (!dl->ins->ops) 541 if (!dl->ins->ops)
532 return; 542 return;
533 543
534 if (dl->ins->ops->parse) 544 if (dl->ins->ops->parse && dl->ins->ops->parse(&dl->ops) < 0)
535 dl->ins->ops->parse(&dl->ops); 545 dl->ins = NULL;
536} 546}
537 547
538static int disasm_line__parse(char *line, char **namep, char **rawp) 548static int disasm_line__parse(char *line, char **namep, char **rawp)
diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c
index f4654183d391..55355b3d4f85 100644
--- a/tools/perf/util/color.c
+++ b/tools/perf/util/color.c
@@ -5,132 +5,6 @@
5 5
6int perf_use_color_default = -1; 6int perf_use_color_default = -1;
7 7
8static int parse_color(const char *name, int len)
9{
10 static const char * const color_names[] = {
11 "normal", "black", "red", "green", "yellow",
12 "blue", "magenta", "cyan", "white"
13 };
14 char *end;
15 int i;
16
17 for (i = 0; i < (int)ARRAY_SIZE(color_names); i++) {
18 const char *str = color_names[i];
19 if (!strncasecmp(name, str, len) && !str[len])
20 return i - 1;
21 }
22 i = strtol(name, &end, 10);
23 if (end - name == len && i >= -1 && i <= 255)
24 return i;
25 return -2;
26}
27
28static int parse_attr(const char *name, int len)
29{
30 static const int attr_values[] = { 1, 2, 4, 5, 7 };
31 static const char * const attr_names[] = {
32 "bold", "dim", "ul", "blink", "reverse"
33 };
34 unsigned int i;
35
36 for (i = 0; i < ARRAY_SIZE(attr_names); i++) {
37 const char *str = attr_names[i];
38 if (!strncasecmp(name, str, len) && !str[len])
39 return attr_values[i];
40 }
41 return -1;
42}
43
44void color_parse(const char *value, const char *var, char *dst)
45{
46 color_parse_mem(value, strlen(value), var, dst);
47}
48
49void color_parse_mem(const char *value, int value_len, const char *var,
50 char *dst)
51{
52 const char *ptr = value;
53 int len = value_len;
54 int attr = -1;
55 int fg = -2;
56 int bg = -2;
57
58 if (!strncasecmp(value, "reset", len)) {
59 strcpy(dst, PERF_COLOR_RESET);
60 return;
61 }
62
63 /* [fg [bg]] [attr] */
64 while (len > 0) {
65 const char *word = ptr;
66 int val, wordlen = 0;
67
68 while (len > 0 && !isspace(word[wordlen])) {
69 wordlen++;
70 len--;
71 }
72
73 ptr = word + wordlen;
74 while (len > 0 && isspace(*ptr)) {
75 ptr++;
76 len--;
77 }
78
79 val = parse_color(word, wordlen);
80 if (val >= -1) {
81 if (fg == -2) {
82 fg = val;
83 continue;
84 }
85 if (bg == -2) {
86 bg = val;
87 continue;
88 }
89 goto bad;
90 }
91 val = parse_attr(word, wordlen);
92 if (val < 0 || attr != -1)
93 goto bad;
94 attr = val;
95 }
96
97 if (attr >= 0 || fg >= 0 || bg >= 0) {
98 int sep = 0;
99
100 *dst++ = '\033';
101 *dst++ = '[';
102 if (attr >= 0) {
103 *dst++ = '0' + attr;
104 sep++;
105 }
106 if (fg >= 0) {
107 if (sep++)
108 *dst++ = ';';
109 if (fg < 8) {
110 *dst++ = '3';
111 *dst++ = '0' + fg;
112 } else {
113 dst += sprintf(dst, "38;5;%d", fg);
114 }
115 }
116 if (bg >= 0) {
117 if (sep++)
118 *dst++ = ';';
119 if (bg < 8) {
120 *dst++ = '4';
121 *dst++ = '0' + bg;
122 } else {
123 dst += sprintf(dst, "48;5;%d", bg);
124 }
125 }
126 *dst++ = 'm';
127 }
128 *dst = 0;
129 return;
130bad:
131 die("bad color value '%.*s' for variable '%s'", value_len, value, var);
132}
133
134int perf_config_colorbool(const char *var, const char *value, int stdout_is_tty) 8int perf_config_colorbool(const char *var, const char *value, int stdout_is_tty)
135{ 9{
136 if (value) { 10 if (value) {
diff --git a/tools/perf/util/color.h b/tools/perf/util/color.h
index 0a594b8a0c26..38146f922c54 100644
--- a/tools/perf/util/color.h
+++ b/tools/perf/util/color.h
@@ -30,8 +30,6 @@ extern int perf_use_color_default;
30int perf_color_default_config(const char *var, const char *value, void *cb); 30int perf_color_default_config(const char *var, const char *value, void *cb);
31 31
32int perf_config_colorbool(const char *var, const char *value, int stdout_is_tty); 32int perf_config_colorbool(const char *var, const char *value, int stdout_is_tty);
33void color_parse(const char *value, const char *var, char *dst);
34void color_parse_mem(const char *value, int len, const char *var, char *dst);
35int color_vsnprintf(char *bf, size_t size, const char *color, 33int color_vsnprintf(char *bf, size_t size, const char *color,
36 const char *fmt, va_list args); 34 const char *fmt, va_list args);
37int color_vfprintf(FILE *fp, const char *color, const char *fmt, va_list args); 35int color_vfprintf(FILE *fp, const char *color, const char *fmt, va_list args);
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index 45be944d450a..c2f7d3b90966 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -532,12 +532,8 @@ dso_cache__read(struct dso *dso, u64 offset, u8 *data, ssize_t size)
532 break; 532 break;
533 533
534 cache_offset = offset & DSO__DATA_CACHE_MASK; 534 cache_offset = offset & DSO__DATA_CACHE_MASK;
535 ret = -EINVAL;
536 535
537 if (-1 == lseek(dso->data.fd, cache_offset, SEEK_SET)) 536 ret = pread(dso->data.fd, cache->data, DSO__DATA_CACHE_SIZE, cache_offset);
538 break;
539
540 ret = read(dso->data.fd, cache->data, DSO__DATA_CACHE_SIZE);
541 if (ret <= 0) 537 if (ret <= 0)
542 break; 538 break;
543 539
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index 3782c82c6e44..ced92841ff97 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -139,6 +139,7 @@ struct dso {
139 u32 status_seen; 139 u32 status_seen;
140 size_t file_size; 140 size_t file_size;
141 struct list_head open_entry; 141 struct list_head open_entry;
142 u64 frame_offset;
142 } data; 143 } data;
143 144
144 union { /* Tool specific area */ 145 union { /* Tool specific area */
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index cbab1fb77b1d..28b8ce86bf12 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -1436,33 +1436,6 @@ size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp)
1436 return printed + fprintf(fp, "\n"); 1436 return printed + fprintf(fp, "\n");
1437} 1437}
1438 1438
1439int perf_evlist__strerror_tp(struct perf_evlist *evlist __maybe_unused,
1440 int err, char *buf, size_t size)
1441{
1442 char sbuf[128];
1443
1444 switch (err) {
1445 case ENOENT:
1446 scnprintf(buf, size, "%s",
1447 "Error:\tUnable to find debugfs\n"
1448 "Hint:\tWas your kernel was compiled with debugfs support?\n"
1449 "Hint:\tIs the debugfs filesystem mounted?\n"
1450 "Hint:\tTry 'sudo mount -t debugfs nodev /sys/kernel/debug'");
1451 break;
1452 case EACCES:
1453 scnprintf(buf, size,
1454 "Error:\tNo permissions to read %s/tracing/events/raw_syscalls\n"
1455 "Hint:\tTry 'sudo mount -o remount,mode=755 %s'\n",
1456 debugfs_mountpoint, debugfs_mountpoint);
1457 break;
1458 default:
1459 scnprintf(buf, size, "%s", strerror_r(err, sbuf, sizeof(sbuf)));
1460 break;
1461 }
1462
1463 return 0;
1464}
1465
1466int perf_evlist__strerror_open(struct perf_evlist *evlist __maybe_unused, 1439int perf_evlist__strerror_open(struct perf_evlist *evlist __maybe_unused,
1467 int err, char *buf, size_t size) 1440 int err, char *buf, size_t size)
1468{ 1441{
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 0ba93f67ab94..c94a9e03ecf1 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -183,7 +183,6 @@ static inline struct perf_evsel *perf_evlist__last(struct perf_evlist *evlist)
183 183
184size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp); 184size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp);
185 185
186int perf_evlist__strerror_tp(struct perf_evlist *evlist, int err, char *buf, size_t size);
187int perf_evlist__strerror_open(struct perf_evlist *evlist, int err, char *buf, size_t size); 186int perf_evlist__strerror_open(struct perf_evlist *evlist, int err, char *buf, size_t size);
188int perf_evlist__strerror_mmap(struct perf_evlist *evlist, int err, char *buf, size_t size); 187int perf_evlist__strerror_mmap(struct perf_evlist *evlist, int err, char *buf, size_t size);
189 188
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 1e90c8557ede..ea51a90e20a0 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -709,6 +709,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
709 if (opts->sample_weight) 709 if (opts->sample_weight)
710 perf_evsel__set_sample_bit(evsel, WEIGHT); 710 perf_evsel__set_sample_bit(evsel, WEIGHT);
711 711
712 attr->task = track;
712 attr->mmap = track; 713 attr->mmap = track;
713 attr->mmap2 = track && !perf_missing_features.mmap2; 714 attr->mmap2 = track && !perf_missing_features.mmap2;
714 attr->comm = track; 715 attr->comm = track;
@@ -797,6 +798,9 @@ int perf_evsel__enable(struct perf_evsel *evsel, int ncpus, int nthreads)
797 798
798int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads) 799int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads)
799{ 800{
801 if (ncpus == 0 || nthreads == 0)
802 return 0;
803
800 if (evsel->system_wide) 804 if (evsel->system_wide)
801 nthreads = 1; 805 nthreads = 1;
802 806
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index b20e40c74468..1f407f7352a7 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -2237,6 +2237,7 @@ static int check_magic_endian(u64 magic, uint64_t hdr_sz,
2237 * - unique number to identify actual perf.data files 2237 * - unique number to identify actual perf.data files
2238 * - encode endianness of file 2238 * - encode endianness of file
2239 */ 2239 */
2240 ph->version = PERF_HEADER_VERSION_2;
2240 2241
2241 /* check magic number with one endianness */ 2242 /* check magic number with one endianness */
2242 if (magic == __perf_magic2) 2243 if (magic == __perf_magic2)
@@ -2247,7 +2248,6 @@ static int check_magic_endian(u64 magic, uint64_t hdr_sz,
2247 return -1; 2248 return -1;
2248 2249
2249 ph->needs_swap = true; 2250 ph->needs_swap = true;
2250 ph->version = PERF_HEADER_VERSION_2;
2251 2251
2252 return 0; 2252 return 0;
2253} 2253}
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 182395546ddc..70b48a65064c 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -241,6 +241,20 @@ static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
241 return he->stat.period == 0; 241 return he->stat.period == 0;
242} 242}
243 243
244static void hists__delete_entry(struct hists *hists, struct hist_entry *he)
245{
246 rb_erase(&he->rb_node, &hists->entries);
247
248 if (sort__need_collapse)
249 rb_erase(&he->rb_node_in, &hists->entries_collapsed);
250
251 --hists->nr_entries;
252 if (!he->filtered)
253 --hists->nr_non_filtered_entries;
254
255 hist_entry__delete(he);
256}
257
244void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel) 258void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel)
245{ 259{
246 struct rb_node *next = rb_first(&hists->entries); 260 struct rb_node *next = rb_first(&hists->entries);
@@ -258,16 +272,7 @@ void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel)
258 (zap_kernel && n->level != '.') || 272 (zap_kernel && n->level != '.') ||
259 hists__decay_entry(hists, n)) && 273 hists__decay_entry(hists, n)) &&
260 !n->used) { 274 !n->used) {
261 rb_erase(&n->rb_node, &hists->entries); 275 hists__delete_entry(hists, n);
262
263 if (sort__need_collapse)
264 rb_erase(&n->rb_node_in, &hists->entries_collapsed);
265
266 --hists->nr_entries;
267 if (!n->filtered)
268 --hists->nr_non_filtered_entries;
269
270 hist_entry__free(n);
271 } 276 }
272 } 277 }
273} 278}
@@ -281,16 +286,7 @@ void hists__delete_entries(struct hists *hists)
281 n = rb_entry(next, struct hist_entry, rb_node); 286 n = rb_entry(next, struct hist_entry, rb_node);
282 next = rb_next(&n->rb_node); 287 next = rb_next(&n->rb_node);
283 288
284 rb_erase(&n->rb_node, &hists->entries); 289 hists__delete_entry(hists, n);
285
286 if (sort__need_collapse)
287 rb_erase(&n->rb_node_in, &hists->entries_collapsed);
288
289 --hists->nr_entries;
290 if (!n->filtered)
291 --hists->nr_non_filtered_entries;
292
293 hist_entry__free(n);
294 } 290 }
295} 291}
296 292
@@ -433,6 +429,8 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
433 if (!he) 429 if (!he)
434 return NULL; 430 return NULL;
435 431
432 hists->nr_entries++;
433
436 rb_link_node(&he->rb_node_in, parent, p); 434 rb_link_node(&he->rb_node_in, parent, p);
437 rb_insert_color(&he->rb_node_in, hists->entries_in); 435 rb_insert_color(&he->rb_node_in, hists->entries_in);
438out: 436out:
@@ -915,7 +913,7 @@ hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
915 if (perf_hpp__should_skip(fmt)) 913 if (perf_hpp__should_skip(fmt))
916 continue; 914 continue;
917 915
918 cmp = fmt->cmp(left, right); 916 cmp = fmt->cmp(fmt, left, right);
919 if (cmp) 917 if (cmp)
920 break; 918 break;
921 } 919 }
@@ -933,7 +931,7 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
933 if (perf_hpp__should_skip(fmt)) 931 if (perf_hpp__should_skip(fmt))
934 continue; 932 continue;
935 933
936 cmp = fmt->collapse(left, right); 934 cmp = fmt->collapse(fmt, left, right);
937 if (cmp) 935 if (cmp)
938 break; 936 break;
939 } 937 }
@@ -941,7 +939,7 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
941 return cmp; 939 return cmp;
942} 940}
943 941
944void hist_entry__free(struct hist_entry *he) 942void hist_entry__delete(struct hist_entry *he)
945{ 943{
946 zfree(&he->branch_info); 944 zfree(&he->branch_info);
947 zfree(&he->mem_info); 945 zfree(&he->mem_info);
@@ -981,7 +979,7 @@ static bool hists__collapse_insert_entry(struct hists *hists __maybe_unused,
981 iter->callchain, 979 iter->callchain,
982 he->callchain); 980 he->callchain);
983 } 981 }
984 hist_entry__free(he); 982 hist_entry__delete(he);
985 return false; 983 return false;
986 } 984 }
987 985
@@ -1063,7 +1061,7 @@ static int hist_entry__sort(struct hist_entry *a, struct hist_entry *b)
1063 if (perf_hpp__should_skip(fmt)) 1061 if (perf_hpp__should_skip(fmt))
1064 continue; 1062 continue;
1065 1063
1066 cmp = fmt->sort(a, b); 1064 cmp = fmt->sort(fmt, a, b);
1067 if (cmp) 1065 if (cmp)
1068 break; 1066 break;
1069 } 1067 }
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 46bd50344f85..2b690d028907 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -119,7 +119,7 @@ int64_t hist_entry__collapse(struct hist_entry *left, struct hist_entry *right);
119int hist_entry__transaction_len(void); 119int hist_entry__transaction_len(void);
120int hist_entry__sort_snprintf(struct hist_entry *he, char *bf, size_t size, 120int hist_entry__sort_snprintf(struct hist_entry *he, char *bf, size_t size,
121 struct hists *hists); 121 struct hists *hists);
122void hist_entry__free(struct hist_entry *); 122void hist_entry__delete(struct hist_entry *he);
123 123
124void hists__output_resort(struct hists *hists, struct ui_progress *prog); 124void hists__output_resort(struct hists *hists, struct ui_progress *prog);
125void hists__collapse_resort(struct hists *hists, struct ui_progress *prog); 125void hists__collapse_resort(struct hists *hists, struct ui_progress *prog);
@@ -195,9 +195,12 @@ struct perf_hpp_fmt {
195 struct hist_entry *he); 195 struct hist_entry *he);
196 int (*entry)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, 196 int (*entry)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
197 struct hist_entry *he); 197 struct hist_entry *he);
198 int64_t (*cmp)(struct hist_entry *a, struct hist_entry *b); 198 int64_t (*cmp)(struct perf_hpp_fmt *fmt,
199 int64_t (*collapse)(struct hist_entry *a, struct hist_entry *b); 199 struct hist_entry *a, struct hist_entry *b);
200 int64_t (*sort)(struct hist_entry *a, struct hist_entry *b); 200 int64_t (*collapse)(struct perf_hpp_fmt *fmt,
201 struct hist_entry *a, struct hist_entry *b);
202 int64_t (*sort)(struct perf_hpp_fmt *fmt,
203 struct hist_entry *a, struct hist_entry *b);
201 204
202 struct list_head list; 205 struct list_head list;
203 struct list_head sort_list; 206 struct list_head sort_list;
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index 6951a9d42339..0e42438b1e59 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -116,6 +116,22 @@ struct thread;
116#define map__for_each_symbol(map, pos, n) \ 116#define map__for_each_symbol(map, pos, n) \
117 dso__for_each_symbol(map->dso, pos, n, map->type) 117 dso__for_each_symbol(map->dso, pos, n, map->type)
118 118
119/* map__for_each_symbol_with_name - iterate over the symbols in the given map
120 * that have the given name
121 *
122 * @map: the 'struct map *' in which symbols itereated
123 * @sym_name: the symbol name
124 * @pos: the 'struct symbol *' to use as a loop cursor
125 * @filter: to use when loading the DSO
126 */
127#define __map__for_each_symbol_by_name(map, sym_name, pos, filter) \
128 for (pos = map__find_symbol_by_name(map, sym_name, filter); \
129 pos && strcmp(pos->name, sym_name) == 0; \
130 pos = symbol__next_by_name(pos))
131
132#define map__for_each_symbol_by_name(map, sym_name, pos) \
133 __map__for_each_symbol_by_name(map, sym_name, (pos), NULL)
134
119typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym); 135typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
120 136
121void map__init(struct map *map, enum map_type type, 137void map__init(struct map *map, enum map_type type,
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 77b43fe43d55..7f8ec6ce2823 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -526,7 +526,7 @@ do { \
526} 526}
527 527
528int parse_events_add_breakpoint(struct list_head *list, int *idx, 528int parse_events_add_breakpoint(struct list_head *list, int *idx,
529 void *ptr, char *type) 529 void *ptr, char *type, u64 len)
530{ 530{
531 struct perf_event_attr attr; 531 struct perf_event_attr attr;
532 532
@@ -536,14 +536,15 @@ int parse_events_add_breakpoint(struct list_head *list, int *idx,
536 if (parse_breakpoint_type(type, &attr)) 536 if (parse_breakpoint_type(type, &attr))
537 return -EINVAL; 537 return -EINVAL;
538 538
539 /* 539 /* Provide some defaults if len is not specified */
540 * We should find a nice way to override the access length 540 if (!len) {
541 * Provide some defaults for now 541 if (attr.bp_type == HW_BREAKPOINT_X)
542 */ 542 len = sizeof(long);
543 if (attr.bp_type == HW_BREAKPOINT_X) 543 else
544 attr.bp_len = sizeof(long); 544 len = HW_BREAKPOINT_LEN_4;
545 else 545 }
546 attr.bp_len = HW_BREAKPOINT_LEN_4; 546
547 attr.bp_len = len;
547 548
548 attr.type = PERF_TYPE_BREAKPOINT; 549 attr.type = PERF_TYPE_BREAKPOINT;
549 attr.sample_period = 1; 550 attr.sample_period = 1;
@@ -1121,7 +1122,7 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob,
1121 return; 1122 return;
1122 1123
1123 for_each_subsystem(sys_dir, sys_dirent, sys_next) { 1124 for_each_subsystem(sys_dir, sys_dirent, sys_next) {
1124 if (subsys_glob != NULL && 1125 if (subsys_glob != NULL &&
1125 !strglobmatch(sys_dirent.d_name, subsys_glob)) 1126 !strglobmatch(sys_dirent.d_name, subsys_glob))
1126 continue; 1127 continue;
1127 1128
@@ -1132,7 +1133,7 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob,
1132 continue; 1133 continue;
1133 1134
1134 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) { 1135 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) {
1135 if (event_glob != NULL && 1136 if (event_glob != NULL &&
1136 !strglobmatch(evt_dirent.d_name, event_glob)) 1137 !strglobmatch(evt_dirent.d_name, event_glob))
1137 continue; 1138 continue;
1138 1139
@@ -1305,7 +1306,7 @@ static void print_symbol_events(const char *event_glob, unsigned type,
1305 1306
1306 for (i = 0; i < max; i++, syms++) { 1307 for (i = 0; i < max; i++, syms++) {
1307 1308
1308 if (event_glob != NULL && 1309 if (event_glob != NULL &&
1309 !(strglobmatch(syms->symbol, event_glob) || 1310 !(strglobmatch(syms->symbol, event_glob) ||
1310 (syms->alias && strglobmatch(syms->alias, event_glob)))) 1311 (syms->alias && strglobmatch(syms->alias, event_glob))))
1311 continue; 1312 continue;
@@ -1366,7 +1367,7 @@ void print_events(const char *event_glob, bool name_only)
1366 printf("\n"); 1367 printf("\n");
1367 1368
1368 printf(" %-50s [%s]\n", 1369 printf(" %-50s [%s]\n",
1369 "mem:<addr>[:access]", 1370 "mem:<addr>[/len][:access]",
1370 event_type_descriptors[PERF_TYPE_BREAKPOINT]); 1371 event_type_descriptors[PERF_TYPE_BREAKPOINT]);
1371 printf("\n"); 1372 printf("\n");
1372 } 1373 }
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index db2cf78ff0f3..ff6e1fa4111e 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -71,6 +71,7 @@ struct parse_events_term {
71 int type_val; 71 int type_val;
72 int type_term; 72 int type_term;
73 struct list_head list; 73 struct list_head list;
74 bool used;
74}; 75};
75 76
76struct parse_events_evlist { 77struct parse_events_evlist {
@@ -104,7 +105,7 @@ int parse_events_add_numeric(struct list_head *list, int *idx,
104int parse_events_add_cache(struct list_head *list, int *idx, 105int parse_events_add_cache(struct list_head *list, int *idx,
105 char *type, char *op_result1, char *op_result2); 106 char *type, char *op_result1, char *op_result2);
106int parse_events_add_breakpoint(struct list_head *list, int *idx, 107int parse_events_add_breakpoint(struct list_head *list, int *idx,
107 void *ptr, char *type); 108 void *ptr, char *type, u64 len);
108int parse_events_add_pmu(struct list_head *list, int *idx, 109int parse_events_add_pmu(struct list_head *list, int *idx,
109 char *pmu , struct list_head *head_config); 110 char *pmu , struct list_head *head_config);
110enum perf_pmu_event_symbol_type 111enum perf_pmu_event_symbol_type
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l
index 906630bbf8eb..94eacb6c1ef7 100644
--- a/tools/perf/util/parse-events.l
+++ b/tools/perf/util/parse-events.l
@@ -159,6 +159,7 @@ branch_type { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE
159<mem>{ 159<mem>{
160{modifier_bp} { return str(yyscanner, PE_MODIFIER_BP); } 160{modifier_bp} { return str(yyscanner, PE_MODIFIER_BP); }
161: { return ':'; } 161: { return ':'; }
162"/" { return '/'; }
162{num_dec} { return value(yyscanner, 10); } 163{num_dec} { return value(yyscanner, 10); }
163{num_hex} { return value(yyscanner, 16); } 164{num_hex} { return value(yyscanner, 16); }
164 /* 165 /*
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index 93c4c9fbc922..72def077dbbf 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -326,6 +326,28 @@ PE_NAME_CACHE_TYPE
326} 326}
327 327
328event_legacy_mem: 328event_legacy_mem:
329PE_PREFIX_MEM PE_VALUE '/' PE_VALUE ':' PE_MODIFIER_BP sep_dc
330{
331 struct parse_events_evlist *data = _data;
332 struct list_head *list;
333
334 ALLOC_LIST(list);
335 ABORT_ON(parse_events_add_breakpoint(list, &data->idx,
336 (void *) $2, $6, $4));
337 $$ = list;
338}
339|
340PE_PREFIX_MEM PE_VALUE '/' PE_VALUE sep_dc
341{
342 struct parse_events_evlist *data = _data;
343 struct list_head *list;
344
345 ALLOC_LIST(list);
346 ABORT_ON(parse_events_add_breakpoint(list, &data->idx,
347 (void *) $2, NULL, $4));
348 $$ = list;
349}
350|
329PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc 351PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
330{ 352{
331 struct parse_events_evlist *data = _data; 353 struct parse_events_evlist *data = _data;
@@ -333,7 +355,7 @@ PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
333 355
334 ALLOC_LIST(list); 356 ALLOC_LIST(list);
335 ABORT_ON(parse_events_add_breakpoint(list, &data->idx, 357 ABORT_ON(parse_events_add_breakpoint(list, &data->idx,
336 (void *) $2, $4)); 358 (void *) $2, $4, 0));
337 $$ = list; 359 $$ = list;
338} 360}
339| 361|
@@ -344,7 +366,7 @@ PE_PREFIX_MEM PE_VALUE sep_dc
344 366
345 ALLOC_LIST(list); 367 ALLOC_LIST(list);
346 ABORT_ON(parse_events_add_breakpoint(list, &data->idx, 368 ABORT_ON(parse_events_add_breakpoint(list, &data->idx,
347 (void *) $2, NULL)); 369 (void *) $2, NULL, 0));
348 $$ = list; 370 $$ = list;
349} 371}
350 372
diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c
index f62dee7bd924..4a015f77e2b5 100644
--- a/tools/perf/util/parse-options.c
+++ b/tools/perf/util/parse-options.c
@@ -46,7 +46,7 @@ static int get_value(struct parse_opt_ctx_t *p,
46 return opterror(opt, "is not usable", flags); 46 return opterror(opt, "is not usable", flags);
47 47
48 if (opt->flags & PARSE_OPT_EXCLUSIVE) { 48 if (opt->flags & PARSE_OPT_EXCLUSIVE) {
49 if (p->excl_opt) { 49 if (p->excl_opt && p->excl_opt != opt) {
50 char msg[128]; 50 char msg[128];
51 51
52 if (((flags & OPT_SHORT) && p->excl_opt->short_name) || 52 if (((flags & OPT_SHORT) && p->excl_opt->short_name) ||
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 5c9c4947cfb4..48411674da0f 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -551,31 +551,68 @@ static void pmu_format_value(unsigned long *format, __u64 value, __u64 *v,
551} 551}
552 552
553/* 553/*
554 * Term is a string term, and might be a param-term. Try to look up it's value
555 * in the remaining terms.
556 * - We have a term like "base-or-format-term=param-term",
557 * - We need to find the value supplied for "param-term" (with param-term named
558 * in a config string) later on in the term list.
559 */
560static int pmu_resolve_param_term(struct parse_events_term *term,
561 struct list_head *head_terms,
562 __u64 *value)
563{
564 struct parse_events_term *t;
565
566 list_for_each_entry(t, head_terms, list) {
567 if (t->type_val == PARSE_EVENTS__TERM_TYPE_NUM) {
568 if (!strcmp(t->config, term->config)) {
569 t->used = true;
570 *value = t->val.num;
571 return 0;
572 }
573 }
574 }
575
576 if (verbose)
577 printf("Required parameter '%s' not specified\n", term->config);
578
579 return -1;
580}
581
582/*
554 * Setup one of config[12] attr members based on the 583 * Setup one of config[12] attr members based on the
555 * user input data - term parameter. 584 * user input data - term parameter.
556 */ 585 */
557static int pmu_config_term(struct list_head *formats, 586static int pmu_config_term(struct list_head *formats,
558 struct perf_event_attr *attr, 587 struct perf_event_attr *attr,
559 struct parse_events_term *term, 588 struct parse_events_term *term,
589 struct list_head *head_terms,
560 bool zero) 590 bool zero)
561{ 591{
562 struct perf_pmu_format *format; 592 struct perf_pmu_format *format;
563 __u64 *vp; 593 __u64 *vp;
594 __u64 val;
595
596 /*
597 * If this is a parameter we've already used for parameterized-eval,
598 * skip it in normal eval.
599 */
600 if (term->used)
601 return 0;
564 602
565 /* 603 /*
566 * Support only for hardcoded and numnerial terms.
567 * Hardcoded terms should be already in, so nothing 604 * Hardcoded terms should be already in, so nothing
568 * to be done for them. 605 * to be done for them.
569 */ 606 */
570 if (parse_events__is_hardcoded_term(term)) 607 if (parse_events__is_hardcoded_term(term))
571 return 0; 608 return 0;
572 609
573 if (term->type_val != PARSE_EVENTS__TERM_TYPE_NUM)
574 return -EINVAL;
575
576 format = pmu_find_format(formats, term->config); 610 format = pmu_find_format(formats, term->config);
577 if (!format) 611 if (!format) {
612 if (verbose)
613 printf("Invalid event/parameter '%s'\n", term->config);
578 return -EINVAL; 614 return -EINVAL;
615 }
579 616
580 switch (format->value) { 617 switch (format->value) {
581 case PERF_PMU_FORMAT_VALUE_CONFIG: 618 case PERF_PMU_FORMAT_VALUE_CONFIG:
@@ -592,11 +629,25 @@ static int pmu_config_term(struct list_head *formats,
592 } 629 }
593 630
594 /* 631 /*
595 * XXX If we ever decide to go with string values for 632 * Either directly use a numeric term, or try to translate string terms
596 * non-hardcoded terms, here's the place to translate 633 * using event parameters.
597 * them into value.
598 */ 634 */
599 pmu_format_value(format->bits, term->val.num, vp, zero); 635 if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM)
636 val = term->val.num;
637 else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) {
638 if (strcmp(term->val.str, "?")) {
639 if (verbose)
640 pr_info("Invalid sysfs entry %s=%s\n",
641 term->config, term->val.str);
642 return -EINVAL;
643 }
644
645 if (pmu_resolve_param_term(term, head_terms, &val))
646 return -EINVAL;
647 } else
648 return -EINVAL;
649
650 pmu_format_value(format->bits, val, vp, zero);
600 return 0; 651 return 0;
601} 652}
602 653
@@ -607,9 +658,10 @@ int perf_pmu__config_terms(struct list_head *formats,
607{ 658{
608 struct parse_events_term *term; 659 struct parse_events_term *term;
609 660
610 list_for_each_entry(term, head_terms, list) 661 list_for_each_entry(term, head_terms, list) {
611 if (pmu_config_term(formats, attr, term, zero)) 662 if (pmu_config_term(formats, attr, term, head_terms, zero))
612 return -EINVAL; 663 return -EINVAL;
664 }
613 665
614 return 0; 666 return 0;
615} 667}
@@ -767,10 +819,36 @@ void perf_pmu__set_format(unsigned long *bits, long from, long to)
767 set_bit(b, bits); 819 set_bit(b, bits);
768} 820}
769 821
822static int sub_non_neg(int a, int b)
823{
824 if (b > a)
825 return 0;
826 return a - b;
827}
828
770static char *format_alias(char *buf, int len, struct perf_pmu *pmu, 829static char *format_alias(char *buf, int len, struct perf_pmu *pmu,
771 struct perf_pmu_alias *alias) 830 struct perf_pmu_alias *alias)
772{ 831{
773 snprintf(buf, len, "%s/%s/", pmu->name, alias->name); 832 struct parse_events_term *term;
833 int used = snprintf(buf, len, "%s/%s", pmu->name, alias->name);
834
835 list_for_each_entry(term, &alias->terms, list) {
836 if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR)
837 used += snprintf(buf + used, sub_non_neg(len, used),
838 ",%s=%s", term->config,
839 term->val.str);
840 }
841
842 if (sub_non_neg(len, used) > 0) {
843 buf[used] = '/';
844 used++;
845 }
846 if (sub_non_neg(len, used) > 0) {
847 buf[used] = '\0';
848 used++;
849 } else
850 buf[len - 1] = '\0';
851
774 return buf; 852 return buf;
775} 853}
776 854
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 94a717bf007d..919937eb0be2 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -446,7 +446,7 @@ static int post_process_probe_trace_events(struct probe_trace_event *tevs,
446 } 446 }
447 447
448 for (i = 0; i < ntevs; i++) { 448 for (i = 0; i < ntevs; i++) {
449 if (tevs[i].point.address) { 449 if (tevs[i].point.address && !tevs[i].point.retprobe) {
450 tmp = strdup(reloc_sym->name); 450 tmp = strdup(reloc_sym->name);
451 if (!tmp) 451 if (!tmp)
452 return -ENOMEM; 452 return -ENOMEM;
@@ -2193,18 +2193,17 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
2193 return ret; 2193 return ret;
2194} 2194}
2195 2195
2196static char *looking_function_name; 2196static int find_probe_functions(struct map *map, char *name)
2197static int num_matched_functions;
2198
2199static int probe_function_filter(struct map *map __maybe_unused,
2200 struct symbol *sym)
2201{ 2197{
2202 if ((sym->binding == STB_GLOBAL || sym->binding == STB_LOCAL) && 2198 int found = 0;
2203 strcmp(looking_function_name, sym->name) == 0) { 2199 struct symbol *sym;
2204 num_matched_functions++; 2200
2205 return 0; 2201 map__for_each_symbol_by_name(map, name, sym) {
2202 if (sym->binding == STB_GLOBAL || sym->binding == STB_LOCAL)
2203 found++;
2206 } 2204 }
2207 return 1; 2205
2206 return found;
2208} 2207}
2209 2208
2210#define strdup_or_goto(str, label) \ 2209#define strdup_or_goto(str, label) \
@@ -2222,10 +2221,10 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev,
2222 struct kmap *kmap = NULL; 2221 struct kmap *kmap = NULL;
2223 struct ref_reloc_sym *reloc_sym = NULL; 2222 struct ref_reloc_sym *reloc_sym = NULL;
2224 struct symbol *sym; 2223 struct symbol *sym;
2225 struct rb_node *nd;
2226 struct probe_trace_event *tev; 2224 struct probe_trace_event *tev;
2227 struct perf_probe_point *pp = &pev->point; 2225 struct perf_probe_point *pp = &pev->point;
2228 struct probe_trace_point *tp; 2226 struct probe_trace_point *tp;
2227 int num_matched_functions;
2229 int ret, i; 2228 int ret, i;
2230 2229
2231 /* Init maps of given executable or kernel */ 2230 /* Init maps of given executable or kernel */
@@ -2242,10 +2241,8 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev,
2242 * Load matched symbols: Since the different local symbols may have 2241 * Load matched symbols: Since the different local symbols may have
2243 * same name but different addresses, this lists all the symbols. 2242 * same name but different addresses, this lists all the symbols.
2244 */ 2243 */
2245 num_matched_functions = 0; 2244 num_matched_functions = find_probe_functions(map, pp->function);
2246 looking_function_name = pp->function; 2245 if (num_matched_functions == 0) {
2247 ret = map__load(map, probe_function_filter);
2248 if (ret || num_matched_functions == 0) {
2249 pr_err("Failed to find symbol %s in %s\n", pp->function, 2246 pr_err("Failed to find symbol %s in %s\n", pp->function,
2250 target ? : "kernel"); 2247 target ? : "kernel");
2251 ret = -ENOENT; 2248 ret = -ENOENT;
@@ -2257,7 +2254,7 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev,
2257 goto out; 2254 goto out;
2258 } 2255 }
2259 2256
2260 if (!pev->uprobes) { 2257 if (!pev->uprobes && !pp->retprobe) {
2261 kmap = map__kmap(map); 2258 kmap = map__kmap(map);
2262 reloc_sym = kmap->ref_reloc_sym; 2259 reloc_sym = kmap->ref_reloc_sym;
2263 if (!reloc_sym) { 2260 if (!reloc_sym) {
@@ -2275,7 +2272,8 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev,
2275 } 2272 }
2276 2273
2277 ret = 0; 2274 ret = 0;
2278 map__for_each_symbol(map, sym, nd) { 2275
2276 map__for_each_symbol_by_name(map, pp->function, sym) {
2279 tev = (*tevs) + ret; 2277 tev = (*tevs) + ret;
2280 tp = &tev->point; 2278 tp = &tev->point;
2281 if (ret == num_matched_functions) { 2279 if (ret == num_matched_functions) {
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index 3dda85ca50c1..d906d0ad5d40 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -768,7 +768,7 @@ static PyObject *pyrf_evlist__get_pollfd(struct pyrf_evlist *pevlist,
768 Py_DECREF(file); 768 Py_DECREF(file);
769 goto free_list; 769 goto free_list;
770 } 770 }
771 771
772 Py_DECREF(file); 772 Py_DECREF(file);
773 } 773 }
774 774
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index d808a328f4dc..0c815a40a6e8 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -89,7 +89,7 @@ static void handler_call_die(const char *handler_name)
89 89
90/* 90/*
91 * Insert val into into the dictionary and decrement the reference counter. 91 * Insert val into into the dictionary and decrement the reference counter.
92 * This is necessary for dictionaries since PyDict_SetItemString() does not 92 * This is necessary for dictionaries since PyDict_SetItemString() does not
93 * steal a reference, as opposed to PyTuple_SetItem(). 93 * steal a reference, as opposed to PyTuple_SetItem().
94 */ 94 */
95static void pydict_set_item_string_decref(PyObject *dict, const char *key, PyObject *val) 95static void pydict_set_item_string_decref(PyObject *dict, const char *key, PyObject *val)
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 5f0e05a76c05..0baf75f12b7c 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -274,7 +274,7 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
274 if (tool->id_index == NULL) 274 if (tool->id_index == NULL)
275 tool->id_index = process_id_index_stub; 275 tool->id_index = process_id_index_stub;
276} 276}
277 277
278static void swap_sample_id_all(union perf_event *event, void *data) 278static void swap_sample_id_all(union perf_event *event, void *data)
279{ 279{
280 void *end = (void *) event + event->header.size; 280 void *end = (void *) event + event->header.size;
@@ -1251,9 +1251,9 @@ fetch_mmaped_event(struct perf_session *session,
1251#define NUM_MMAPS 128 1251#define NUM_MMAPS 128
1252#endif 1252#endif
1253 1253
1254int __perf_session__process_events(struct perf_session *session, 1254static int __perf_session__process_events(struct perf_session *session,
1255 u64 data_offset, u64 data_size, 1255 u64 data_offset, u64 data_size,
1256 u64 file_size, struct perf_tool *tool) 1256 u64 file_size, struct perf_tool *tool)
1257{ 1257{
1258 int fd = perf_data_file__fd(session->file); 1258 int fd = perf_data_file__fd(session->file);
1259 u64 head, page_offset, file_offset, file_pos, size; 1259 u64 head, page_offset, file_offset, file_pos, size;
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index dc26ebf60fe4..6d663dc76404 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -49,9 +49,6 @@ int perf_session__peek_event(struct perf_session *session, off_t file_offset,
49 union perf_event **event_ptr, 49 union perf_event **event_ptr,
50 struct perf_sample *sample); 50 struct perf_sample *sample);
51 51
52int __perf_session__process_events(struct perf_session *session,
53 u64 data_offset, u64 data_size, u64 size,
54 struct perf_tool *tool);
55int perf_session__process_events(struct perf_session *session, 52int perf_session__process_events(struct perf_session *session,
56 struct perf_tool *tool); 53 struct perf_tool *tool);
57 54
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 9139dda9f9a3..7a39c1ed8d37 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -1304,6 +1304,37 @@ static int __sort__hpp_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1304 return hse->se->se_snprintf(he, hpp->buf, hpp->size, len); 1304 return hse->se->se_snprintf(he, hpp->buf, hpp->size, len);
1305} 1305}
1306 1306
1307static int64_t __sort__hpp_cmp(struct perf_hpp_fmt *fmt,
1308 struct hist_entry *a, struct hist_entry *b)
1309{
1310 struct hpp_sort_entry *hse;
1311
1312 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1313 return hse->se->se_cmp(a, b);
1314}
1315
1316static int64_t __sort__hpp_collapse(struct perf_hpp_fmt *fmt,
1317 struct hist_entry *a, struct hist_entry *b)
1318{
1319 struct hpp_sort_entry *hse;
1320 int64_t (*collapse_fn)(struct hist_entry *, struct hist_entry *);
1321
1322 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1323 collapse_fn = hse->se->se_collapse ?: hse->se->se_cmp;
1324 return collapse_fn(a, b);
1325}
1326
1327static int64_t __sort__hpp_sort(struct perf_hpp_fmt *fmt,
1328 struct hist_entry *a, struct hist_entry *b)
1329{
1330 struct hpp_sort_entry *hse;
1331 int64_t (*sort_fn)(struct hist_entry *, struct hist_entry *);
1332
1333 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1334 sort_fn = hse->se->se_sort ?: hse->se->se_cmp;
1335 return sort_fn(a, b);
1336}
1337
1307static struct hpp_sort_entry * 1338static struct hpp_sort_entry *
1308__sort_dimension__alloc_hpp(struct sort_dimension *sd) 1339__sort_dimension__alloc_hpp(struct sort_dimension *sd)
1309{ 1340{
@@ -1322,9 +1353,9 @@ __sort_dimension__alloc_hpp(struct sort_dimension *sd)
1322 hse->hpp.entry = __sort__hpp_entry; 1353 hse->hpp.entry = __sort__hpp_entry;
1323 hse->hpp.color = NULL; 1354 hse->hpp.color = NULL;
1324 1355
1325 hse->hpp.cmp = sd->entry->se_cmp; 1356 hse->hpp.cmp = __sort__hpp_cmp;
1326 hse->hpp.collapse = sd->entry->se_collapse ? : sd->entry->se_cmp; 1357 hse->hpp.collapse = __sort__hpp_collapse;
1327 hse->hpp.sort = sd->entry->se_sort ? : hse->hpp.collapse; 1358 hse->hpp.sort = __sort__hpp_sort;
1328 1359
1329 INIT_LIST_HEAD(&hse->hpp.list); 1360 INIT_LIST_HEAD(&hse->hpp.list);
1330 INIT_LIST_HEAD(&hse->hpp.sort_list); 1361 INIT_LIST_HEAD(&hse->hpp.sort_list);
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index 06fcd1bf98b6..b24f9d8727a8 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -574,13 +574,16 @@ static int decompress_kmodule(struct dso *dso, const char *name,
574 const char *ext = strrchr(name, '.'); 574 const char *ext = strrchr(name, '.');
575 char tmpbuf[] = "/tmp/perf-kmod-XXXXXX"; 575 char tmpbuf[] = "/tmp/perf-kmod-XXXXXX";
576 576
577 if ((type != DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP && 577 if (type != DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP &&
578 type != DSO_BINARY_TYPE__GUEST_KMODULE_COMP) || 578 type != DSO_BINARY_TYPE__GUEST_KMODULE_COMP &&
579 type != dso->symtab_type) 579 type != DSO_BINARY_TYPE__BUILD_ID_CACHE)
580 return -1; 580 return -1;
581 581
582 if (!ext || !is_supported_compression(ext + 1)) 582 if (!ext || !is_supported_compression(ext + 1)) {
583 return -1; 583 ext = strrchr(dso->name, '.');
584 if (!ext || !is_supported_compression(ext + 1))
585 return -1;
586 }
584 587
585 fd = mkstemp(tmpbuf); 588 fd = mkstemp(tmpbuf);
586 if (fd < 0) 589 if (fd < 0)
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index c24c5b83156c..a69066865a55 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -396,6 +396,7 @@ static struct symbol *symbols__find_by_name(struct rb_root *symbols,
396 const char *name) 396 const char *name)
397{ 397{
398 struct rb_node *n; 398 struct rb_node *n;
399 struct symbol_name_rb_node *s;
399 400
400 if (symbols == NULL) 401 if (symbols == NULL)
401 return NULL; 402 return NULL;
@@ -403,7 +404,6 @@ static struct symbol *symbols__find_by_name(struct rb_root *symbols,
403 n = symbols->rb_node; 404 n = symbols->rb_node;
404 405
405 while (n) { 406 while (n) {
406 struct symbol_name_rb_node *s;
407 int cmp; 407 int cmp;
408 408
409 s = rb_entry(n, struct symbol_name_rb_node, rb_node); 409 s = rb_entry(n, struct symbol_name_rb_node, rb_node);
@@ -414,10 +414,24 @@ static struct symbol *symbols__find_by_name(struct rb_root *symbols,
414 else if (cmp > 0) 414 else if (cmp > 0)
415 n = n->rb_right; 415 n = n->rb_right;
416 else 416 else
417 return &s->sym; 417 break;
418 } 418 }
419 419
420 return NULL; 420 if (n == NULL)
421 return NULL;
422
423 /* return first symbol that has same name (if any) */
424 for (n = rb_prev(n); n; n = rb_prev(n)) {
425 struct symbol_name_rb_node *tmp;
426
427 tmp = rb_entry(n, struct symbol_name_rb_node, rb_node);
428 if (strcmp(tmp->sym.name, s->sym.name))
429 break;
430
431 s = tmp;
432 }
433
434 return &s->sym;
421} 435}
422 436
423struct symbol *dso__find_symbol(struct dso *dso, 437struct symbol *dso__find_symbol(struct dso *dso,
@@ -436,6 +450,17 @@ struct symbol *dso__next_symbol(struct symbol *sym)
436 return symbols__next(sym); 450 return symbols__next(sym);
437} 451}
438 452
453struct symbol *symbol__next_by_name(struct symbol *sym)
454{
455 struct symbol_name_rb_node *s = container_of(sym, struct symbol_name_rb_node, sym);
456 struct rb_node *n = rb_next(&s->rb_node);
457
458 return n ? &rb_entry(n, struct symbol_name_rb_node, rb_node)->sym : NULL;
459}
460
461 /*
462 * Teturns first symbol that matched with @name.
463 */
439struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, 464struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
440 const char *name) 465 const char *name)
441{ 466{
@@ -660,7 +685,7 @@ static int dso__split_kallsyms(struct dso *dso, struct map *map, u64 delta,
660 struct machine *machine = kmaps->machine; 685 struct machine *machine = kmaps->machine;
661 struct map *curr_map = map; 686 struct map *curr_map = map;
662 struct symbol *pos; 687 struct symbol *pos;
663 int count = 0, moved = 0; 688 int count = 0, moved = 0;
664 struct rb_root *root = &dso->symbols[map->type]; 689 struct rb_root *root = &dso->symbols[map->type];
665 struct rb_node *next = rb_first(root); 690 struct rb_node *next = rb_first(root);
666 int kernel_range = 0; 691 int kernel_range = 0;
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 9d602e9c6f59..1650dcb3a67b 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -231,6 +231,7 @@ struct symbol *dso__find_symbol(struct dso *dso, enum map_type type,
231 u64 addr); 231 u64 addr);
232struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, 232struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
233 const char *name); 233 const char *name);
234struct symbol *symbol__next_by_name(struct symbol *sym);
234 235
235struct symbol *dso__first_symbol(struct dso *dso, enum map_type type); 236struct symbol *dso__first_symbol(struct dso *dso, enum map_type type);
236struct symbol *dso__next_symbol(struct symbol *sym); 237struct symbol *dso__next_symbol(struct symbol *sym);
diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c
index 6edf535f65c2..e3c40a520a25 100644
--- a/tools/perf/util/unwind-libunwind.c
+++ b/tools/perf/util/unwind-libunwind.c
@@ -266,14 +266,17 @@ static int read_unwind_spec_eh_frame(struct dso *dso, struct machine *machine,
266 u64 *fde_count) 266 u64 *fde_count)
267{ 267{
268 int ret = -EINVAL, fd; 268 int ret = -EINVAL, fd;
269 u64 offset; 269 u64 offset = dso->data.frame_offset;
270 270
271 fd = dso__data_fd(dso, machine); 271 if (offset == 0) {
272 if (fd < 0) 272 fd = dso__data_fd(dso, machine);
273 return -EINVAL; 273 if (fd < 0)
274 return -EINVAL;
274 275
275 /* Check the .eh_frame section for unwinding info */ 276 /* Check the .eh_frame section for unwinding info */
276 offset = elf_section_offset(fd, ".eh_frame_hdr"); 277 offset = elf_section_offset(fd, ".eh_frame_hdr");
278 dso->data.frame_offset = offset;
279 }
277 280
278 if (offset) 281 if (offset)
279 ret = unwind_spec_ehframe(dso, machine, offset, 282 ret = unwind_spec_ehframe(dso, machine, offset,
@@ -287,14 +290,20 @@ static int read_unwind_spec_eh_frame(struct dso *dso, struct machine *machine,
287static int read_unwind_spec_debug_frame(struct dso *dso, 290static int read_unwind_spec_debug_frame(struct dso *dso,
288 struct machine *machine, u64 *offset) 291 struct machine *machine, u64 *offset)
289{ 292{
290 int fd = dso__data_fd(dso, machine); 293 int fd;
294 u64 ofs = dso->data.frame_offset;
291 295
292 if (fd < 0) 296 if (ofs == 0) {
293 return -EINVAL; 297 fd = dso__data_fd(dso, machine);
298 if (fd < 0)
299 return -EINVAL;
294 300
295 /* Check the .debug_frame section for unwinding info */ 301 /* Check the .debug_frame section for unwinding info */
296 *offset = elf_section_offset(fd, ".debug_frame"); 302 ofs = elf_section_offset(fd, ".debug_frame");
303 dso->data.frame_offset = ofs;
304 }
297 305
306 *offset = ofs;
298 if (*offset) 307 if (*offset)
299 return 0; 308 return 0;
300 309