aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/Documentation/perf-stat.txt3
-rw-r--r--tools/perf/arch/powerpc/util/skip-callchain-idx.c2
-rw-r--r--tools/perf/arch/x86/entry/syscalls/syscall_64.tbl2
-rw-r--r--tools/perf/bench/numa.c5
-rw-r--r--tools/perf/builtin-annotate.c11
-rw-r--r--tools/perf/builtin-c2c.c10
-rw-r--r--tools/perf/builtin-report.c3
-rw-r--r--tools/perf/builtin-script.c42
-rw-r--r--tools/perf/builtin-stat.c48
-rw-r--r--tools/perf/tests/parse-events.c25
-rw-r--r--tools/perf/tests/topology.c1
-rw-r--r--tools/perf/ui/gtk/hists.c2
-rw-r--r--tools/perf/util/c++/clang.cpp11
-rw-r--r--tools/perf/util/header.c12
-rw-r--r--tools/perf/util/hist.c12
-rw-r--r--tools/perf/util/hist.h4
-rw-r--r--tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c2
-rw-r--r--tools/perf/util/parse-events.y5
-rw-r--r--tools/perf/util/pmu.c99
-rw-r--r--tools/perf/util/sort.h4
20 files changed, 250 insertions, 53 deletions
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt
index 5dfe102fb5b5..b10a90b6a718 100644
--- a/tools/perf/Documentation/perf-stat.txt
+++ b/tools/perf/Documentation/perf-stat.txt
@@ -178,6 +178,9 @@ Print count deltas for fixed number of times.
178This option should be used together with "-I" option. 178This option should be used together with "-I" option.
179 example: 'perf stat -I 1000 --interval-count 2 -e cycles -a' 179 example: 'perf stat -I 1000 --interval-count 2 -e cycles -a'
180 180
181--interval-clear::
182Clear the screen before next interval.
183
181--timeout msecs:: 184--timeout msecs::
182Stop the 'perf stat' session and print count deltas after N milliseconds (minimum: 10 ms). 185Stop the 'perf stat' session and print count deltas after N milliseconds (minimum: 10 ms).
183This option is not supported with the "-I" option. 186This option is not supported with the "-I" option.
diff --git a/tools/perf/arch/powerpc/util/skip-callchain-idx.c b/tools/perf/arch/powerpc/util/skip-callchain-idx.c
index 3598b8b75d27..ef5d59a5742e 100644
--- a/tools/perf/arch/powerpc/util/skip-callchain-idx.c
+++ b/tools/perf/arch/powerpc/util/skip-callchain-idx.c
@@ -243,7 +243,7 @@ int arch_skip_callchain_idx(struct thread *thread, struct ip_callchain *chain)
243 u64 ip; 243 u64 ip;
244 u64 skip_slot = -1; 244 u64 skip_slot = -1;
245 245
246 if (chain->nr < 3) 246 if (!chain || chain->nr < 3)
247 return skip_slot; 247 return skip_slot;
248 248
249 ip = chain->ips[2]; 249 ip = chain->ips[2];
diff --git a/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl b/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl
index 4dfe42666d0c..f0b1709a5ffb 100644
--- a/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl
+++ b/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl
@@ -341,6 +341,8 @@
341330 common pkey_alloc __x64_sys_pkey_alloc 341330 common pkey_alloc __x64_sys_pkey_alloc
342331 common pkey_free __x64_sys_pkey_free 342331 common pkey_free __x64_sys_pkey_free
343332 common statx __x64_sys_statx 343332 common statx __x64_sys_statx
344333 common io_pgetevents __x64_sys_io_pgetevents
345334 common rseq __x64_sys_rseq
344 346
345# 347#
346# x32-specific system call numbers start at 512 to avoid cache impact 348# x32-specific system call numbers start at 512 to avoid cache impact
diff --git a/tools/perf/bench/numa.c b/tools/perf/bench/numa.c
index 63eb49082774..44195514b19e 100644
--- a/tools/perf/bench/numa.c
+++ b/tools/perf/bench/numa.c
@@ -1098,7 +1098,7 @@ static void *worker_thread(void *__tdata)
1098 u8 *global_data; 1098 u8 *global_data;
1099 u8 *process_data; 1099 u8 *process_data;
1100 u8 *thread_data; 1100 u8 *thread_data;
1101 u64 bytes_done; 1101 u64 bytes_done, secs;
1102 long work_done; 1102 long work_done;
1103 u32 l; 1103 u32 l;
1104 struct rusage rusage; 1104 struct rusage rusage;
@@ -1254,7 +1254,8 @@ static void *worker_thread(void *__tdata)
1254 timersub(&stop, &start0, &diff); 1254 timersub(&stop, &start0, &diff);
1255 td->runtime_ns = diff.tv_sec * NSEC_PER_SEC; 1255 td->runtime_ns = diff.tv_sec * NSEC_PER_SEC;
1256 td->runtime_ns += diff.tv_usec * NSEC_PER_USEC; 1256 td->runtime_ns += diff.tv_usec * NSEC_PER_USEC;
1257 td->speed_gbs = bytes_done / (td->runtime_ns / NSEC_PER_SEC) / 1e9; 1257 secs = td->runtime_ns / NSEC_PER_SEC;
1258 td->speed_gbs = secs ? bytes_done / secs / 1e9 : 0;
1258 1259
1259 getrusage(RUSAGE_THREAD, &rusage); 1260 getrusage(RUSAGE_THREAD, &rusage);
1260 td->system_time_ns = rusage.ru_stime.tv_sec * NSEC_PER_SEC; 1261 td->system_time_ns = rusage.ru_stime.tv_sec * NSEC_PER_SEC;
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 5eb22cc56363..8180319285af 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -283,6 +283,15 @@ out_put:
283 return ret; 283 return ret;
284} 284}
285 285
286static int process_feature_event(struct perf_tool *tool,
287 union perf_event *event,
288 struct perf_session *session)
289{
290 if (event->feat.feat_id < HEADER_LAST_FEATURE)
291 return perf_event__process_feature(tool, event, session);
292 return 0;
293}
294
286static int hist_entry__tty_annotate(struct hist_entry *he, 295static int hist_entry__tty_annotate(struct hist_entry *he,
287 struct perf_evsel *evsel, 296 struct perf_evsel *evsel,
288 struct perf_annotate *ann) 297 struct perf_annotate *ann)
@@ -471,7 +480,7 @@ int cmd_annotate(int argc, const char **argv)
471 .attr = perf_event__process_attr, 480 .attr = perf_event__process_attr,
472 .build_id = perf_event__process_build_id, 481 .build_id = perf_event__process_build_id,
473 .tracing_data = perf_event__process_tracing_data, 482 .tracing_data = perf_event__process_tracing_data,
474 .feature = perf_event__process_feature, 483 .feature = process_feature_event,
475 .ordered_events = true, 484 .ordered_events = true,
476 .ordering_requires_timestamps = true, 485 .ordering_requires_timestamps = true,
477 }, 486 },
diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c
index 307b3594525f..6a8738f7ead3 100644
--- a/tools/perf/builtin-c2c.c
+++ b/tools/perf/builtin-c2c.c
@@ -56,16 +56,16 @@ struct c2c_hist_entry {
56 56
57 struct compute_stats cstats; 57 struct compute_stats cstats;
58 58
59 unsigned long paddr;
60 unsigned long paddr_cnt;
61 bool paddr_zero;
62 char *nodestr;
63
59 /* 64 /*
60 * must be at the end, 65 * must be at the end,
61 * because of its callchain dynamic entry 66 * because of its callchain dynamic entry
62 */ 67 */
63 struct hist_entry he; 68 struct hist_entry he;
64
65 unsigned long paddr;
66 unsigned long paddr_cnt;
67 bool paddr_zero;
68 char *nodestr;
69}; 69};
70 70
71static char const *coalesce_default = "pid,iaddr"; 71static char const *coalesce_default = "pid,iaddr";
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index cdb5b6949832..c04dc7b53797 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -217,7 +217,8 @@ static int process_feature_event(struct perf_tool *tool,
217 } 217 }
218 218
219 /* 219 /*
220 * All features are received, we can force the 220 * (feat_id = HEADER_LAST_FEATURE) is the end marker which
221 * means all features are received, now we can force the
221 * group if needed. 222 * group if needed.
222 */ 223 */
223 setup_forced_leader(rep, session->evlist); 224 setup_forced_leader(rep, session->evlist);
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index b3bf35512d21..568ddfac3213 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -180,6 +180,18 @@ static struct {
180 PERF_OUTPUT_EVNAME | PERF_OUTPUT_TRACE 180 PERF_OUTPUT_EVNAME | PERF_OUTPUT_TRACE
181 }, 181 },
182 182
183 [PERF_TYPE_HW_CACHE] = {
184 .user_set = false,
185
186 .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
187 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
188 PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |
189 PERF_OUTPUT_SYM | PERF_OUTPUT_SYMOFFSET |
190 PERF_OUTPUT_DSO | PERF_OUTPUT_PERIOD,
191
192 .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT,
193 },
194
183 [PERF_TYPE_RAW] = { 195 [PERF_TYPE_RAW] = {
184 .user_set = false, 196 .user_set = false,
185 197
@@ -1822,6 +1834,7 @@ static int process_attr(struct perf_tool *tool, union perf_event *event,
1822 struct perf_evlist *evlist; 1834 struct perf_evlist *evlist;
1823 struct perf_evsel *evsel, *pos; 1835 struct perf_evsel *evsel, *pos;
1824 int err; 1836 int err;
1837 static struct perf_evsel_script *es;
1825 1838
1826 err = perf_event__process_attr(tool, event, pevlist); 1839 err = perf_event__process_attr(tool, event, pevlist);
1827 if (err) 1840 if (err)
@@ -1830,6 +1843,19 @@ static int process_attr(struct perf_tool *tool, union perf_event *event,
1830 evlist = *pevlist; 1843 evlist = *pevlist;
1831 evsel = perf_evlist__last(*pevlist); 1844 evsel = perf_evlist__last(*pevlist);
1832 1845
1846 if (!evsel->priv) {
1847 if (scr->per_event_dump) {
1848 evsel->priv = perf_evsel_script__new(evsel,
1849 scr->session->data);
1850 } else {
1851 es = zalloc(sizeof(*es));
1852 if (!es)
1853 return -ENOMEM;
1854 es->fp = stdout;
1855 evsel->priv = es;
1856 }
1857 }
1858
1833 if (evsel->attr.type >= PERF_TYPE_MAX && 1859 if (evsel->attr.type >= PERF_TYPE_MAX &&
1834 evsel->attr.type != PERF_TYPE_SYNTH) 1860 evsel->attr.type != PERF_TYPE_SYNTH)
1835 return 0; 1861 return 0;
@@ -3018,6 +3044,15 @@ int process_cpu_map_event(struct perf_tool *tool __maybe_unused,
3018 return set_maps(script); 3044 return set_maps(script);
3019} 3045}
3020 3046
3047static int process_feature_event(struct perf_tool *tool,
3048 union perf_event *event,
3049 struct perf_session *session)
3050{
3051 if (event->feat.feat_id < HEADER_LAST_FEATURE)
3052 return perf_event__process_feature(tool, event, session);
3053 return 0;
3054}
3055
3021#ifdef HAVE_AUXTRACE_SUPPORT 3056#ifdef HAVE_AUXTRACE_SUPPORT
3022static int perf_script__process_auxtrace_info(struct perf_tool *tool, 3057static int perf_script__process_auxtrace_info(struct perf_tool *tool,
3023 union perf_event *event, 3058 union perf_event *event,
@@ -3062,7 +3097,7 @@ int cmd_script(int argc, const char **argv)
3062 .attr = process_attr, 3097 .attr = process_attr,
3063 .event_update = perf_event__process_event_update, 3098 .event_update = perf_event__process_event_update,
3064 .tracing_data = perf_event__process_tracing_data, 3099 .tracing_data = perf_event__process_tracing_data,
3065 .feature = perf_event__process_feature, 3100 .feature = process_feature_event,
3066 .build_id = perf_event__process_build_id, 3101 .build_id = perf_event__process_build_id,
3067 .id_index = perf_event__process_id_index, 3102 .id_index = perf_event__process_id_index,
3068 .auxtrace_info = perf_script__process_auxtrace_info, 3103 .auxtrace_info = perf_script__process_auxtrace_info,
@@ -3113,8 +3148,9 @@ int cmd_script(int argc, const char **argv)
3113 "+field to add and -field to remove." 3148 "+field to add and -field to remove."
3114 "Valid types: hw,sw,trace,raw,synth. " 3149 "Valid types: hw,sw,trace,raw,synth. "
3115 "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso," 3150 "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso,"
3116 "addr,symoff,period,iregs,uregs,brstack,brstacksym,flags," 3151 "addr,symoff,srcline,period,iregs,uregs,brstack,"
3117 "bpf-output,callindent,insn,insnlen,brstackinsn,synth,phys_addr", 3152 "brstacksym,flags,bpf-output,brstackinsn,brstackoff,"
3153 "callindent,insn,insnlen,synth,phys_addr,metric,misc",
3118 parse_output_fields), 3154 parse_output_fields),
3119 OPT_BOOLEAN('a', "all-cpus", &system_wide, 3155 OPT_BOOLEAN('a', "all-cpus", &system_wide,
3120 "system-wide collection from all CPUs"), 3156 "system-wide collection from all CPUs"),
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 096ccb25c11f..22547a490e1f 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -65,6 +65,7 @@
65#include "util/tool.h" 65#include "util/tool.h"
66#include "util/string2.h" 66#include "util/string2.h"
67#include "util/metricgroup.h" 67#include "util/metricgroup.h"
68#include "util/top.h"
68#include "asm/bug.h" 69#include "asm/bug.h"
69 70
70#include <linux/time64.h> 71#include <linux/time64.h>
@@ -144,6 +145,8 @@ static struct target target = {
144 145
145typedef int (*aggr_get_id_t)(struct cpu_map *m, int cpu); 146typedef int (*aggr_get_id_t)(struct cpu_map *m, int cpu);
146 147
148#define METRIC_ONLY_LEN 20
149
147static int run_count = 1; 150static int run_count = 1;
148static bool no_inherit = false; 151static bool no_inherit = false;
149static volatile pid_t child_pid = -1; 152static volatile pid_t child_pid = -1;
@@ -173,6 +176,7 @@ static struct cpu_map *aggr_map;
173static aggr_get_id_t aggr_get_id; 176static aggr_get_id_t aggr_get_id;
174static bool append_file; 177static bool append_file;
175static bool interval_count; 178static bool interval_count;
179static bool interval_clear;
176static const char *output_name; 180static const char *output_name;
177static int output_fd; 181static int output_fd;
178static int print_free_counters_hint; 182static int print_free_counters_hint;
@@ -180,6 +184,7 @@ static int print_mixed_hw_group_error;
180static u64 *walltime_run; 184static u64 *walltime_run;
181static bool ru_display = false; 185static bool ru_display = false;
182static struct rusage ru_data; 186static struct rusage ru_data;
187static unsigned int metric_only_len = METRIC_ONLY_LEN;
183 188
184struct perf_stat { 189struct perf_stat {
185 bool record; 190 bool record;
@@ -967,8 +972,6 @@ static void print_metric_csv(void *ctx,
967 fprintf(out, "%s%s%s%s", csv_sep, vals, csv_sep, unit); 972 fprintf(out, "%s%s%s%s", csv_sep, vals, csv_sep, unit);
968} 973}
969 974
970#define METRIC_ONLY_LEN 20
971
972/* Filter out some columns that don't work well in metrics only mode */ 975/* Filter out some columns that don't work well in metrics only mode */
973 976
974static bool valid_only_metric(const char *unit) 977static bool valid_only_metric(const char *unit)
@@ -999,22 +1002,20 @@ static void print_metric_only(void *ctx, const char *color, const char *fmt,
999{ 1002{
1000 struct outstate *os = ctx; 1003 struct outstate *os = ctx;
1001 FILE *out = os->fh; 1004 FILE *out = os->fh;
1002 int n; 1005 char buf[1024], str[1024];
1003 char buf[1024]; 1006 unsigned mlen = metric_only_len;
1004 unsigned mlen = METRIC_ONLY_LEN;
1005 1007
1006 if (!valid_only_metric(unit)) 1008 if (!valid_only_metric(unit))
1007 return; 1009 return;
1008 unit = fixunit(buf, os->evsel, unit); 1010 unit = fixunit(buf, os->evsel, unit);
1009 if (color)
1010 n = color_fprintf(out, color, fmt, val);
1011 else
1012 n = fprintf(out, fmt, val);
1013 if (n > METRIC_ONLY_LEN)
1014 n = METRIC_ONLY_LEN;
1015 if (mlen < strlen(unit)) 1011 if (mlen < strlen(unit))
1016 mlen = strlen(unit) + 1; 1012 mlen = strlen(unit) + 1;
1017 fprintf(out, "%*s", mlen - n, ""); 1013
1014 if (color)
1015 mlen += strlen(color) + sizeof(PERF_COLOR_RESET) - 1;
1016
1017 color_snprintf(str, sizeof(str), color ?: "", fmt, val);
1018 fprintf(out, "%*s ", mlen, str);
1018} 1019}
1019 1020
1020static void print_metric_only_csv(void *ctx, const char *color __maybe_unused, 1021static void print_metric_only_csv(void *ctx, const char *color __maybe_unused,
@@ -1054,7 +1055,7 @@ static void print_metric_header(void *ctx, const char *color __maybe_unused,
1054 if (csv_output) 1055 if (csv_output)
1055 fprintf(os->fh, "%s%s", unit, csv_sep); 1056 fprintf(os->fh, "%s%s", unit, csv_sep);
1056 else 1057 else
1057 fprintf(os->fh, "%-*s ", METRIC_ONLY_LEN, unit); 1058 fprintf(os->fh, "%*s ", metric_only_len, unit);
1058} 1059}
1059 1060
1060static void nsec_printout(int id, int nr, struct perf_evsel *evsel, double avg) 1061static void nsec_printout(int id, int nr, struct perf_evsel *evsel, double avg)
@@ -1704,9 +1705,12 @@ static void print_interval(char *prefix, struct timespec *ts)
1704 FILE *output = stat_config.output; 1705 FILE *output = stat_config.output;
1705 static int num_print_interval; 1706 static int num_print_interval;
1706 1707
1708 if (interval_clear)
1709 puts(CONSOLE_CLEAR);
1710
1707 sprintf(prefix, "%6lu.%09lu%s", ts->tv_sec, ts->tv_nsec, csv_sep); 1711 sprintf(prefix, "%6lu.%09lu%s", ts->tv_sec, ts->tv_nsec, csv_sep);
1708 1712
1709 if (num_print_interval == 0 && !csv_output) { 1713 if ((num_print_interval == 0 && !csv_output) || interval_clear) {
1710 switch (stat_config.aggr_mode) { 1714 switch (stat_config.aggr_mode) {
1711 case AGGR_SOCKET: 1715 case AGGR_SOCKET:
1712 fprintf(output, "# time socket cpus"); 1716 fprintf(output, "# time socket cpus");
@@ -1719,7 +1723,7 @@ static void print_interval(char *prefix, struct timespec *ts)
1719 fprintf(output, " counts %*s events\n", unit_width, "unit"); 1723 fprintf(output, " counts %*s events\n", unit_width, "unit");
1720 break; 1724 break;
1721 case AGGR_NONE: 1725 case AGGR_NONE:
1722 fprintf(output, "# time CPU"); 1726 fprintf(output, "# time CPU ");
1723 if (!metric_only) 1727 if (!metric_only)
1724 fprintf(output, " counts %*s events\n", unit_width, "unit"); 1728 fprintf(output, " counts %*s events\n", unit_width, "unit");
1725 break; 1729 break;
@@ -1738,7 +1742,7 @@ static void print_interval(char *prefix, struct timespec *ts)
1738 } 1742 }
1739 } 1743 }
1740 1744
1741 if (num_print_interval == 0 && metric_only) 1745 if ((num_print_interval == 0 && metric_only) || interval_clear)
1742 print_metric_headers(" ", true); 1746 print_metric_headers(" ", true);
1743 if (++num_print_interval == 25) 1747 if (++num_print_interval == 25)
1744 num_print_interval = 0; 1748 num_print_interval = 0;
@@ -2057,6 +2061,8 @@ static const struct option stat_options[] = {
2057 "(overhead is possible for values <= 100ms)"), 2061 "(overhead is possible for values <= 100ms)"),
2058 OPT_INTEGER(0, "interval-count", &stat_config.times, 2062 OPT_INTEGER(0, "interval-count", &stat_config.times,
2059 "print counts for fixed number of times"), 2063 "print counts for fixed number of times"),
2064 OPT_BOOLEAN(0, "interval-clear", &interval_clear,
2065 "clear screen in between new interval"),
2060 OPT_UINTEGER(0, "timeout", &stat_config.timeout, 2066 OPT_UINTEGER(0, "timeout", &stat_config.timeout,
2061 "stop workload and print counts after a timeout period in ms (>= 10ms)"), 2067 "stop workload and print counts after a timeout period in ms (>= 10ms)"),
2062 OPT_SET_UINT(0, "per-socket", &stat_config.aggr_mode, 2068 OPT_SET_UINT(0, "per-socket", &stat_config.aggr_mode,
@@ -2436,14 +2442,13 @@ static int add_default_attributes(void)
2436 (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | 2442 (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) |
2437 (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, 2443 (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) },
2438}; 2444};
2445 struct parse_events_error errinfo;
2439 2446
2440 /* Set attrs if no event is selected and !null_run: */ 2447 /* Set attrs if no event is selected and !null_run: */
2441 if (null_run) 2448 if (null_run)
2442 return 0; 2449 return 0;
2443 2450
2444 if (transaction_run) { 2451 if (transaction_run) {
2445 struct parse_events_error errinfo;
2446
2447 if (pmu_have_event("cpu", "cycles-ct") && 2452 if (pmu_have_event("cpu", "cycles-ct") &&
2448 pmu_have_event("cpu", "el-start")) 2453 pmu_have_event("cpu", "el-start"))
2449 err = parse_events(evsel_list, transaction_attrs, 2454 err = parse_events(evsel_list, transaction_attrs,
@@ -2454,6 +2459,7 @@ static int add_default_attributes(void)
2454 &errinfo); 2459 &errinfo);
2455 if (err) { 2460 if (err) {
2456 fprintf(stderr, "Cannot set up transaction events\n"); 2461 fprintf(stderr, "Cannot set up transaction events\n");
2462 parse_events_print_error(&errinfo, transaction_attrs);
2457 return -1; 2463 return -1;
2458 } 2464 }
2459 return 0; 2465 return 0;
@@ -2479,10 +2485,11 @@ static int add_default_attributes(void)
2479 pmu_have_event("msr", "smi")) { 2485 pmu_have_event("msr", "smi")) {
2480 if (!force_metric_only) 2486 if (!force_metric_only)
2481 metric_only = true; 2487 metric_only = true;
2482 err = parse_events(evsel_list, smi_cost_attrs, NULL); 2488 err = parse_events(evsel_list, smi_cost_attrs, &errinfo);
2483 } else { 2489 } else {
2484 fprintf(stderr, "To measure SMI cost, it needs " 2490 fprintf(stderr, "To measure SMI cost, it needs "
2485 "msr/aperf/, msr/smi/ and cpu/cycles/ support\n"); 2491 "msr/aperf/, msr/smi/ and cpu/cycles/ support\n");
2492 parse_events_print_error(&errinfo, smi_cost_attrs);
2486 return -1; 2493 return -1;
2487 } 2494 }
2488 if (err) { 2495 if (err) {
@@ -2517,12 +2524,13 @@ static int add_default_attributes(void)
2517 if (topdown_attrs[0] && str) { 2524 if (topdown_attrs[0] && str) {
2518 if (warn) 2525 if (warn)
2519 arch_topdown_group_warn(); 2526 arch_topdown_group_warn();
2520 err = parse_events(evsel_list, str, NULL); 2527 err = parse_events(evsel_list, str, &errinfo);
2521 if (err) { 2528 if (err) {
2522 fprintf(stderr, 2529 fprintf(stderr,
2523 "Cannot set up top down events %s: %d\n", 2530 "Cannot set up top down events %s: %d\n",
2524 str, err); 2531 str, err);
2525 free(str); 2532 free(str);
2533 parse_events_print_error(&errinfo, str);
2526 return -1; 2534 return -1;
2527 } 2535 }
2528 } else { 2536 } else {
diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c
index 7d4077068454..61211918bfba 100644
--- a/tools/perf/tests/parse-events.c
+++ b/tools/perf/tests/parse-events.c
@@ -1309,6 +1309,11 @@ static int test__checkevent_config_cache(struct perf_evlist *evlist)
1309 return 0; 1309 return 0;
1310} 1310}
1311 1311
1312static bool test__intel_pt_valid(void)
1313{
1314 return !!perf_pmu__find("intel_pt");
1315}
1316
1312static int test__intel_pt(struct perf_evlist *evlist) 1317static int test__intel_pt(struct perf_evlist *evlist)
1313{ 1318{
1314 struct perf_evsel *evsel = perf_evlist__first(evlist); 1319 struct perf_evsel *evsel = perf_evlist__first(evlist);
@@ -1375,6 +1380,7 @@ struct evlist_test {
1375 const char *name; 1380 const char *name;
1376 __u32 type; 1381 __u32 type;
1377 const int id; 1382 const int id;
1383 bool (*valid)(void);
1378 int (*check)(struct perf_evlist *evlist); 1384 int (*check)(struct perf_evlist *evlist);
1379}; 1385};
1380 1386
@@ -1648,6 +1654,7 @@ static struct evlist_test test__events[] = {
1648 }, 1654 },
1649 { 1655 {
1650 .name = "intel_pt//u", 1656 .name = "intel_pt//u",
1657 .valid = test__intel_pt_valid,
1651 .check = test__intel_pt, 1658 .check = test__intel_pt,
1652 .id = 52, 1659 .id = 52,
1653 }, 1660 },
@@ -1686,17 +1693,24 @@ static struct terms_test test__terms[] = {
1686 1693
1687static int test_event(struct evlist_test *e) 1694static int test_event(struct evlist_test *e)
1688{ 1695{
1696 struct parse_events_error err = { .idx = 0, };
1689 struct perf_evlist *evlist; 1697 struct perf_evlist *evlist;
1690 int ret; 1698 int ret;
1691 1699
1700 if (e->valid && !e->valid()) {
1701 pr_debug("... SKIP");
1702 return 0;
1703 }
1704
1692 evlist = perf_evlist__new(); 1705 evlist = perf_evlist__new();
1693 if (evlist == NULL) 1706 if (evlist == NULL)
1694 return -ENOMEM; 1707 return -ENOMEM;
1695 1708
1696 ret = parse_events(evlist, e->name, NULL); 1709 ret = parse_events(evlist, e->name, &err);
1697 if (ret) { 1710 if (ret) {
1698 pr_debug("failed to parse event '%s', err %d\n", 1711 pr_debug("failed to parse event '%s', err %d, str '%s'\n",
1699 e->name, ret); 1712 e->name, ret, err.str);
1713 parse_events_print_error(&err, e->name);
1700 } else { 1714 } else {
1701 ret = e->check(evlist); 1715 ret = e->check(evlist);
1702 } 1716 }
@@ -1714,10 +1728,11 @@ static int test_events(struct evlist_test *events, unsigned cnt)
1714 for (i = 0; i < cnt; i++) { 1728 for (i = 0; i < cnt; i++) {
1715 struct evlist_test *e = &events[i]; 1729 struct evlist_test *e = &events[i];
1716 1730
1717 pr_debug("running test %d '%s'\n", e->id, e->name); 1731 pr_debug("running test %d '%s'", e->id, e->name);
1718 ret1 = test_event(e); 1732 ret1 = test_event(e);
1719 if (ret1) 1733 if (ret1)
1720 ret2 = ret1; 1734 ret2 = ret1;
1735 pr_debug("\n");
1721 } 1736 }
1722 1737
1723 return ret2; 1738 return ret2;
@@ -1799,7 +1814,7 @@ static int test_pmu_events(void)
1799 } 1814 }
1800 1815
1801 while (!ret && (ent = readdir(dir))) { 1816 while (!ret && (ent = readdir(dir))) {
1802 struct evlist_test e; 1817 struct evlist_test e = { .id = 0, };
1803 char name[2 * NAME_MAX + 1 + 12 + 3]; 1818 char name[2 * NAME_MAX + 1 + 12 + 3];
1804 1819
1805 /* Names containing . are special and cannot be used directly */ 1820 /* Names containing . are special and cannot be used directly */
diff --git a/tools/perf/tests/topology.c b/tools/perf/tests/topology.c
index 40e30a26b23c..9497d02f69e6 100644
--- a/tools/perf/tests/topology.c
+++ b/tools/perf/tests/topology.c
@@ -45,6 +45,7 @@ static int session_write_header(char *path)
45 45
46 perf_header__set_feat(&session->header, HEADER_CPU_TOPOLOGY); 46 perf_header__set_feat(&session->header, HEADER_CPU_TOPOLOGY);
47 perf_header__set_feat(&session->header, HEADER_NRCPUS); 47 perf_header__set_feat(&session->header, HEADER_NRCPUS);
48 perf_header__set_feat(&session->header, HEADER_ARCH);
48 49
49 session->header.data_size += DATA_SIZE; 50 session->header.data_size += DATA_SIZE;
50 51
diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c
index b085f1b3e34d..4ab663ec3e5e 100644
--- a/tools/perf/ui/gtk/hists.c
+++ b/tools/perf/ui/gtk/hists.c
@@ -382,7 +382,7 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
382 gtk_tree_store_set(store, &iter, col_idx++, s, -1); 382 gtk_tree_store_set(store, &iter, col_idx++, s, -1);
383 } 383 }
384 384
385 if (hists__has_callchains(hists) && 385 if (hist_entry__has_callchains(h) &&
386 symbol_conf.use_callchain && hists__has(hists, sym)) { 386 symbol_conf.use_callchain && hists__has(hists, sym)) {
387 if (callchain_param.mode == CHAIN_GRAPH_REL) 387 if (callchain_param.mode == CHAIN_GRAPH_REL)
388 total = symbol_conf.cumulate_callchain ? 388 total = symbol_conf.cumulate_callchain ?
diff --git a/tools/perf/util/c++/clang.cpp b/tools/perf/util/c++/clang.cpp
index bf31ceab33bd..89512504551b 100644
--- a/tools/perf/util/c++/clang.cpp
+++ b/tools/perf/util/c++/clang.cpp
@@ -146,8 +146,15 @@ getBPFObjectFromModule(llvm::Module *Module)
146 raw_svector_ostream ostream(*Buffer); 146 raw_svector_ostream ostream(*Buffer);
147 147
148 legacy::PassManager PM; 148 legacy::PassManager PM;
149 if (TargetMachine->addPassesToEmitFile(PM, ostream, 149 bool NotAdded;
150 TargetMachine::CGFT_ObjectFile)) { 150#if CLANG_VERSION_MAJOR < 7
151 NotAdded = TargetMachine->addPassesToEmitFile(PM, ostream,
152 TargetMachine::CGFT_ObjectFile);
153#else
154 NotAdded = TargetMachine->addPassesToEmitFile(PM, ostream, nullptr,
155 TargetMachine::CGFT_ObjectFile);
156#endif
157 if (NotAdded) {
151 llvm::errs() << "TargetMachine can't emit a file of this type\n"; 158 llvm::errs() << "TargetMachine can't emit a file of this type\n";
152 return std::unique_ptr<llvm::SmallVectorImpl<char>>(nullptr);; 159 return std::unique_ptr<llvm::SmallVectorImpl<char>>(nullptr);;
153 } 160 }
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 540cd2dcd3e7..653ff65aa2c3 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -2129,6 +2129,7 @@ static int process_cpu_topology(struct feat_fd *ff, void *data __maybe_unused)
2129 int cpu_nr = ff->ph->env.nr_cpus_avail; 2129 int cpu_nr = ff->ph->env.nr_cpus_avail;
2130 u64 size = 0; 2130 u64 size = 0;
2131 struct perf_header *ph = ff->ph; 2131 struct perf_header *ph = ff->ph;
2132 bool do_core_id_test = true;
2132 2133
2133 ph->env.cpu = calloc(cpu_nr, sizeof(*ph->env.cpu)); 2134 ph->env.cpu = calloc(cpu_nr, sizeof(*ph->env.cpu));
2134 if (!ph->env.cpu) 2135 if (!ph->env.cpu)
@@ -2183,6 +2184,13 @@ static int process_cpu_topology(struct feat_fd *ff, void *data __maybe_unused)
2183 return 0; 2184 return 0;
2184 } 2185 }
2185 2186
2187 /* On s390 the socket_id number is not related to the numbers of cpus.
2188 * The socket_id number might be higher than the numbers of cpus.
2189 * This depends on the configuration.
2190 */
2191 if (ph->env.arch && !strncmp(ph->env.arch, "s390", 4))
2192 do_core_id_test = false;
2193
2186 for (i = 0; i < (u32)cpu_nr; i++) { 2194 for (i = 0; i < (u32)cpu_nr; i++) {
2187 if (do_read_u32(ff, &nr)) 2195 if (do_read_u32(ff, &nr))
2188 goto free_cpu; 2196 goto free_cpu;
@@ -2192,7 +2200,7 @@ static int process_cpu_topology(struct feat_fd *ff, void *data __maybe_unused)
2192 if (do_read_u32(ff, &nr)) 2200 if (do_read_u32(ff, &nr))
2193 goto free_cpu; 2201 goto free_cpu;
2194 2202
2195 if (nr != (u32)-1 && nr > (u32)cpu_nr) { 2203 if (do_core_id_test && nr != (u32)-1 && nr > (u32)cpu_nr) {
2196 pr_debug("socket_id number is too big." 2204 pr_debug("socket_id number is too big."
2197 "You may need to upgrade the perf tool.\n"); 2205 "You may need to upgrade the perf tool.\n");
2198 goto free_cpu; 2206 goto free_cpu;
@@ -3456,7 +3464,7 @@ int perf_event__process_feature(struct perf_tool *tool,
3456 pr_warning("invalid record type %d in pipe-mode\n", type); 3464 pr_warning("invalid record type %d in pipe-mode\n", type);
3457 return 0; 3465 return 0;
3458 } 3466 }
3459 if (feat == HEADER_RESERVED || feat > HEADER_LAST_FEATURE) { 3467 if (feat == HEADER_RESERVED || feat >= HEADER_LAST_FEATURE) {
3460 pr_warning("invalid record type %d in pipe-mode\n", type); 3468 pr_warning("invalid record type %d in pipe-mode\n", type);
3461 return -1; 3469 return -1;
3462 } 3470 }
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 52e8fda93a47..828cb9794c76 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -370,9 +370,11 @@ void hists__delete_entries(struct hists *hists)
370 370
371static int hist_entry__init(struct hist_entry *he, 371static int hist_entry__init(struct hist_entry *he,
372 struct hist_entry *template, 372 struct hist_entry *template,
373 bool sample_self) 373 bool sample_self,
374 size_t callchain_size)
374{ 375{
375 *he = *template; 376 *he = *template;
377 he->callchain_size = callchain_size;
376 378
377 if (symbol_conf.cumulate_callchain) { 379 if (symbol_conf.cumulate_callchain) {
378 he->stat_acc = malloc(sizeof(he->stat)); 380 he->stat_acc = malloc(sizeof(he->stat));
@@ -473,7 +475,7 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template,
473 475
474 he = ops->new(callchain_size); 476 he = ops->new(callchain_size);
475 if (he) { 477 if (he) {
476 err = hist_entry__init(he, template, sample_self); 478 err = hist_entry__init(he, template, sample_self, callchain_size);
477 if (err) { 479 if (err) {
478 ops->free(he); 480 ops->free(he);
479 he = NULL; 481 he = NULL;
@@ -619,9 +621,11 @@ __hists__add_entry(struct hists *hists,
619 .raw_data = sample->raw_data, 621 .raw_data = sample->raw_data,
620 .raw_size = sample->raw_size, 622 .raw_size = sample->raw_size,
621 .ops = ops, 623 .ops = ops,
622 }; 624 }, *he = hists__findnew_entry(hists, &entry, al, sample_self);
623 625
624 return hists__findnew_entry(hists, &entry, al, sample_self); 626 if (!hists->has_callchains && he && he->callchain_size != 0)
627 hists->has_callchains = true;
628 return he;
625} 629}
626 630
627struct hist_entry *hists__add_entry(struct hists *hists, 631struct hist_entry *hists__add_entry(struct hists *hists,
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 06607c434949..73049f7f0f60 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -85,6 +85,7 @@ struct hists {
85 struct events_stats stats; 85 struct events_stats stats;
86 u64 event_stream; 86 u64 event_stream;
87 u16 col_len[HISTC_NR_COLS]; 87 u16 col_len[HISTC_NR_COLS];
88 bool has_callchains;
88 int socket_filter; 89 int socket_filter;
89 struct perf_hpp_list *hpp_list; 90 struct perf_hpp_list *hpp_list;
90 struct list_head hpp_formats; 91 struct list_head hpp_formats;
@@ -222,8 +223,7 @@ static inline struct hists *evsel__hists(struct perf_evsel *evsel)
222 223
223static __pure inline bool hists__has_callchains(struct hists *hists) 224static __pure inline bool hists__has_callchains(struct hists *hists)
224{ 225{
225 const struct perf_evsel *evsel = hists_to_evsel(hists); 226 return hists->has_callchains;
226 return evsel__has_callchain(evsel);
227} 227}
228 228
229int hists__init(void); 229int hists__init(void);
diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c
index ba4c9dd18643..d426761a549d 100644
--- a/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c
+++ b/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c
@@ -366,7 +366,7 @@ static int intel_pt_get_cyc(unsigned int byte, const unsigned char *buf,
366 if (len < offs) 366 if (len < offs)
367 return INTEL_PT_NEED_MORE_BYTES; 367 return INTEL_PT_NEED_MORE_BYTES;
368 byte = buf[offs++]; 368 byte = buf[offs++];
369 payload |= (byte >> 1) << shift; 369 payload |= ((uint64_t)byte >> 1) << shift;
370 } 370 }
371 371
372 packet->type = INTEL_PT_CYC; 372 packet->type = INTEL_PT_CYC;
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index 155d2570274f..da8fe57691b8 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -227,11 +227,16 @@ event_def: event_pmu |
227event_pmu: 227event_pmu:
228PE_NAME opt_pmu_config 228PE_NAME opt_pmu_config
229{ 229{
230 struct parse_events_state *parse_state = _parse_state;
231 struct parse_events_error *error = parse_state->error;
230 struct list_head *list, *orig_terms, *terms; 232 struct list_head *list, *orig_terms, *terms;
231 233
232 if (parse_events_copy_term_list($2, &orig_terms)) 234 if (parse_events_copy_term_list($2, &orig_terms))
233 YYABORT; 235 YYABORT;
234 236
237 if (error)
238 error->idx = @1.first_column;
239
235 ALLOC_LIST(list); 240 ALLOC_LIST(list);
236 if (parse_events_add_pmu(_parse_state, list, $1, $2, false, false)) { 241 if (parse_events_add_pmu(_parse_state, list, $1, $2, false, false)) {
237 struct perf_pmu *pmu = NULL; 242 struct perf_pmu *pmu = NULL;
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index d2fb597c9a8c..3ba6a1742f91 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -234,6 +234,74 @@ static int perf_pmu__parse_snapshot(struct perf_pmu_alias *alias,
234 return 0; 234 return 0;
235} 235}
236 236
237static void perf_pmu_assign_str(char *name, const char *field, char **old_str,
238 char **new_str)
239{
240 if (!*old_str)
241 goto set_new;
242
243 if (*new_str) { /* Have new string, check with old */
244 if (strcasecmp(*old_str, *new_str))
245 pr_debug("alias %s differs in field '%s'\n",
246 name, field);
247 zfree(old_str);
248 } else /* Nothing new --> keep old string */
249 return;
250set_new:
251 *old_str = *new_str;
252 *new_str = NULL;
253}
254
255static void perf_pmu_update_alias(struct perf_pmu_alias *old,
256 struct perf_pmu_alias *newalias)
257{
258 perf_pmu_assign_str(old->name, "desc", &old->desc, &newalias->desc);
259 perf_pmu_assign_str(old->name, "long_desc", &old->long_desc,
260 &newalias->long_desc);
261 perf_pmu_assign_str(old->name, "topic", &old->topic, &newalias->topic);
262 perf_pmu_assign_str(old->name, "metric_expr", &old->metric_expr,
263 &newalias->metric_expr);
264 perf_pmu_assign_str(old->name, "metric_name", &old->metric_name,
265 &newalias->metric_name);
266 perf_pmu_assign_str(old->name, "value", &old->str, &newalias->str);
267 old->scale = newalias->scale;
268 old->per_pkg = newalias->per_pkg;
269 old->snapshot = newalias->snapshot;
270 memcpy(old->unit, newalias->unit, sizeof(old->unit));
271}
272
273/* Delete an alias entry. */
274static void perf_pmu_free_alias(struct perf_pmu_alias *newalias)
275{
276 zfree(&newalias->name);
277 zfree(&newalias->desc);
278 zfree(&newalias->long_desc);
279 zfree(&newalias->topic);
280 zfree(&newalias->str);
281 zfree(&newalias->metric_expr);
282 zfree(&newalias->metric_name);
283 parse_events_terms__purge(&newalias->terms);
284 free(newalias);
285}
286
287/* Merge an alias, search in alias list. If this name is already
288 * present merge both of them to combine all information.
289 */
290static bool perf_pmu_merge_alias(struct perf_pmu_alias *newalias,
291 struct list_head *alist)
292{
293 struct perf_pmu_alias *a;
294
295 list_for_each_entry(a, alist, list) {
296 if (!strcasecmp(newalias->name, a->name)) {
297 perf_pmu_update_alias(a, newalias);
298 perf_pmu_free_alias(newalias);
299 return true;
300 }
301 }
302 return false;
303}
304
237static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name, 305static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
238 char *desc, char *val, 306 char *desc, char *val,
239 char *long_desc, char *topic, 307 char *long_desc, char *topic,
@@ -241,9 +309,11 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
241 char *metric_expr, 309 char *metric_expr,
242 char *metric_name) 310 char *metric_name)
243{ 311{
312 struct parse_events_term *term;
244 struct perf_pmu_alias *alias; 313 struct perf_pmu_alias *alias;
245 int ret; 314 int ret;
246 int num; 315 int num;
316 char newval[256];
247 317
248 alias = malloc(sizeof(*alias)); 318 alias = malloc(sizeof(*alias));
249 if (!alias) 319 if (!alias)
@@ -262,6 +332,27 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
262 return ret; 332 return ret;
263 } 333 }
264 334
335 /* Scan event and remove leading zeroes, spaces, newlines, some
336 * platforms have terms specified as
337 * event=0x0091 (read from files ../<PMU>/events/<FILE>
338 * and terms specified as event=0x91 (read from JSON files).
339 *
340 * Rebuild string to make alias->str member comparable.
341 */
342 memset(newval, 0, sizeof(newval));
343 ret = 0;
344 list_for_each_entry(term, &alias->terms, list) {
345 if (ret)
346 ret += scnprintf(newval + ret, sizeof(newval) - ret,
347 ",");
348 if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM)
349 ret += scnprintf(newval + ret, sizeof(newval) - ret,
350 "%s=%#x", term->config, term->val.num);
351 else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR)
352 ret += scnprintf(newval + ret, sizeof(newval) - ret,
353 "%s=%s", term->config, term->val.str);
354 }
355
265 alias->name = strdup(name); 356 alias->name = strdup(name);
266 if (dir) { 357 if (dir) {
267 /* 358 /*
@@ -285,9 +376,10 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
285 snprintf(alias->unit, sizeof(alias->unit), "%s", unit); 376 snprintf(alias->unit, sizeof(alias->unit), "%s", unit);
286 } 377 }
287 alias->per_pkg = perpkg && sscanf(perpkg, "%d", &num) == 1 && num == 1; 378 alias->per_pkg = perpkg && sscanf(perpkg, "%d", &num) == 1 && num == 1;
288 alias->str = strdup(val); 379 alias->str = strdup(newval);
289 380
290 list_add_tail(&alias->list, list); 381 if (!perf_pmu_merge_alias(alias, list))
382 list_add_tail(&alias->list, list);
291 383
292 return 0; 384 return 0;
293} 385}
@@ -303,6 +395,9 @@ static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FI
303 395
304 buf[ret] = 0; 396 buf[ret] = 0;
305 397
398 /* Remove trailing newline from sysfs file */
399 rtrim(buf);
400
306 return __perf_pmu__new_alias(list, dir, name, NULL, buf, NULL, NULL, NULL, 401 return __perf_pmu__new_alias(list, dir, name, NULL, buf, NULL, NULL, NULL,
307 NULL, NULL, NULL); 402 NULL, NULL, NULL);
308} 403}
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 7cf2d5cc038e..8bf302cafcec 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -112,6 +112,8 @@ struct hist_entry {
112 112
113 char level; 113 char level;
114 u8 filtered; 114 u8 filtered;
115
116 u16 callchain_size;
115 union { 117 union {
116 /* 118 /*
117 * Since perf diff only supports the stdio output, TUI 119 * Since perf diff only supports the stdio output, TUI
@@ -153,7 +155,7 @@ struct hist_entry {
153 155
154static __pure inline bool hist_entry__has_callchains(struct hist_entry *he) 156static __pure inline bool hist_entry__has_callchains(struct hist_entry *he)
155{ 157{
156 return hists__has_callchains(he->hists); 158 return he->callchain_size != 0;
157} 159}
158 160
159static inline bool hist_entry__has_pairs(struct hist_entry *he) 161static inline bool hist_entry__has_pairs(struct hist_entry *he)