diff options
Diffstat (limited to 'tools/perf')
-rw-r--r-- | tools/perf/Documentation/perf-stat.txt | 3 | ||||
-rw-r--r-- | tools/perf/arch/powerpc/util/skip-callchain-idx.c | 2 | ||||
-rw-r--r-- | tools/perf/arch/x86/entry/syscalls/syscall_64.tbl | 2 | ||||
-rw-r--r-- | tools/perf/bench/numa.c | 5 | ||||
-rw-r--r-- | tools/perf/builtin-annotate.c | 11 | ||||
-rw-r--r-- | tools/perf/builtin-c2c.c | 10 | ||||
-rw-r--r-- | tools/perf/builtin-report.c | 3 | ||||
-rw-r--r-- | tools/perf/builtin-script.c | 42 | ||||
-rw-r--r-- | tools/perf/builtin-stat.c | 48 | ||||
-rw-r--r-- | tools/perf/tests/parse-events.c | 25 | ||||
-rw-r--r-- | tools/perf/tests/topology.c | 1 | ||||
-rw-r--r-- | tools/perf/ui/gtk/hists.c | 2 | ||||
-rw-r--r-- | tools/perf/util/c++/clang.cpp | 11 | ||||
-rw-r--r-- | tools/perf/util/header.c | 12 | ||||
-rw-r--r-- | tools/perf/util/hist.c | 12 | ||||
-rw-r--r-- | tools/perf/util/hist.h | 4 | ||||
-rw-r--r-- | tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c | 2 | ||||
-rw-r--r-- | tools/perf/util/parse-events.y | 5 | ||||
-rw-r--r-- | tools/perf/util/pmu.c | 99 | ||||
-rw-r--r-- | tools/perf/util/sort.h | 4 |
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. | |||
178 | This option should be used together with "-I" option. | 178 | This 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:: | ||
182 | Clear the screen before next interval. | ||
183 | |||
181 | --timeout msecs:: | 184 | --timeout msecs:: |
182 | Stop the 'perf stat' session and print count deltas after N milliseconds (minimum: 10 ms). | 185 | Stop the 'perf stat' session and print count deltas after N milliseconds (minimum: 10 ms). |
183 | This option is not supported with the "-I" option. | 186 | This 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 @@ | |||
341 | 330 common pkey_alloc __x64_sys_pkey_alloc | 341 | 330 common pkey_alloc __x64_sys_pkey_alloc |
342 | 331 common pkey_free __x64_sys_pkey_free | 342 | 331 common pkey_free __x64_sys_pkey_free |
343 | 332 common statx __x64_sys_statx | 343 | 332 common statx __x64_sys_statx |
344 | 333 common io_pgetevents __x64_sys_io_pgetevents | ||
345 | 334 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 | ||
286 | static 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 | |||
286 | static int hist_entry__tty_annotate(struct hist_entry *he, | 295 | static 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 | ||
71 | static char const *coalesce_default = "pid,iaddr"; | 71 | static 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 | ||
3047 | static 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 |
3022 | static int perf_script__process_auxtrace_info(struct perf_tool *tool, | 3057 | static 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 | ||
145 | typedef int (*aggr_get_id_t)(struct cpu_map *m, int cpu); | 146 | typedef int (*aggr_get_id_t)(struct cpu_map *m, int cpu); |
146 | 147 | ||
148 | #define METRIC_ONLY_LEN 20 | ||
149 | |||
147 | static int run_count = 1; | 150 | static int run_count = 1; |
148 | static bool no_inherit = false; | 151 | static bool no_inherit = false; |
149 | static volatile pid_t child_pid = -1; | 152 | static volatile pid_t child_pid = -1; |
@@ -173,6 +176,7 @@ static struct cpu_map *aggr_map; | |||
173 | static aggr_get_id_t aggr_get_id; | 176 | static aggr_get_id_t aggr_get_id; |
174 | static bool append_file; | 177 | static bool append_file; |
175 | static bool interval_count; | 178 | static bool interval_count; |
179 | static bool interval_clear; | ||
176 | static const char *output_name; | 180 | static const char *output_name; |
177 | static int output_fd; | 181 | static int output_fd; |
178 | static int print_free_counters_hint; | 182 | static int print_free_counters_hint; |
@@ -180,6 +184,7 @@ static int print_mixed_hw_group_error; | |||
180 | static u64 *walltime_run; | 184 | static u64 *walltime_run; |
181 | static bool ru_display = false; | 185 | static bool ru_display = false; |
182 | static struct rusage ru_data; | 186 | static struct rusage ru_data; |
187 | static unsigned int metric_only_len = METRIC_ONLY_LEN; | ||
183 | 188 | ||
184 | struct perf_stat { | 189 | struct 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 | ||
974 | static bool valid_only_metric(const char *unit) | 977 | static 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 | ||
1020 | static void print_metric_only_csv(void *ctx, const char *color __maybe_unused, | 1021 | static 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 | ||
1060 | static void nsec_printout(int id, int nr, struct perf_evsel *evsel, double avg) | 1061 | static 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 | ||
1312 | static bool test__intel_pt_valid(void) | ||
1313 | { | ||
1314 | return !!perf_pmu__find("intel_pt"); | ||
1315 | } | ||
1316 | |||
1312 | static int test__intel_pt(struct perf_evlist *evlist) | 1317 | static 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 | ||
1687 | static int test_event(struct evlist_test *e) | 1694 | static 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 | ||
371 | static int hist_entry__init(struct hist_entry *he, | 371 | static 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 | ||
627 | struct hist_entry *hists__add_entry(struct hists *hists, | 631 | struct 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 | ||
223 | static __pure inline bool hists__has_callchains(struct hists *hists) | 224 | static __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 | ||
229 | int hists__init(void); | 229 | int 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 | | |||
227 | event_pmu: | 227 | event_pmu: |
228 | PE_NAME opt_pmu_config | 228 | PE_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 | ||
237 | static 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; | ||
250 | set_new: | ||
251 | *old_str = *new_str; | ||
252 | *new_str = NULL; | ||
253 | } | ||
254 | |||
255 | static 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. */ | ||
274 | static 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 | */ | ||
290 | static 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 | |||
237 | static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name, | 305 | static 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 | ||
154 | static __pure inline bool hist_entry__has_callchains(struct hist_entry *he) | 156 | static __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 | ||
159 | static inline bool hist_entry__has_pairs(struct hist_entry *he) | 161 | static inline bool hist_entry__has_pairs(struct hist_entry *he) |