Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull perf fixes from Thomas Gleixner:
"A pile of perf updates:

Kernel side:

- Remove an incorrect warning in uprobe_init_insn() when
insn_get_length() fails. The error return code is handled at the
call site.

- Move the inline keyword to the right place in the perf ringbuffer
code to address a W=1 build warning.

Tooling:

perf stat:

- Fix metric column header display alignment

- Improve error messages for default attributes, providing better
output for error in command line.

- Add --interval-clear option, to provide a 'watch' like printing

perf script:

- Show hw-cache events too

perf c2c:

- Fix data dependency problem in layout of 'struct c2c_hist_entry'

Core:

- Do not blindly assume that 'struct perf_evsel' can be obtained via
a straight forward container_of() as there are call sites which
hand in a plain 'struct hist' which is not part of a container.

- Fix error index in the PMU event parser, so that error messages can
point to the problematic token"

* 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
perf/core: Move the inline keyword at the beginning of the function declaration
uprobes/x86: Remove incorrect WARN_ON() in uprobe_init_insn()
perf script: Show hw-cache events
perf c2c: Keep struct hist_entry at the end of struct c2c_hist_entry
perf stat: Add event parsing error handling to add_default_attributes
perf stat: Allow to specify specific metric column len
perf stat: Fix metric column header display alignment
perf stat: Use only color_fprintf call in print_metric_only
perf stat: Add --interval-clear option
perf tools: Fix error index for pmu event parser
perf hists: Reimplement hists__has_callchains()
perf hists browser gtk: Use hist_entry__has_callchains()
perf hists: Make hist_entry__has_callchains() work with 'perf c2c'
perf hists: Save the callchain_size in struct hist_entry

+71 -37
+1 -1
arch/x86/kernel/uprobes.c
··· 293 293 insn_init(insn, auprobe->insn, sizeof(auprobe->insn), x86_64); 294 294 /* has the side-effect of processing the entire instruction */ 295 295 insn_get_length(insn); 296 - if (WARN_ON_ONCE(!insn_complete(insn))) 296 + if (!insn_complete(insn)) 297 297 return -ENOEXEC; 298 298 299 299 if (is_prefix_bad(insn))
+3 -3
kernel/events/ring_buffer.c
··· 103 103 preempt_enable(); 104 104 } 105 105 106 - static bool __always_inline 106 + static __always_inline bool 107 107 ring_buffer_has_space(unsigned long head, unsigned long tail, 108 108 unsigned long data_size, unsigned int size, 109 109 bool backward) ··· 114 114 return CIRC_SPACE(tail, head, data_size) >= size; 115 115 } 116 116 117 - static int __always_inline 117 + static __always_inline int 118 118 __perf_output_begin(struct perf_output_handle *handle, 119 119 struct perf_event *event, unsigned int size, 120 120 bool backward) ··· 414 414 } 415 415 EXPORT_SYMBOL_GPL(perf_aux_output_begin); 416 416 417 - static bool __always_inline rb_need_aux_wakeup(struct ring_buffer *rb) 417 + static __always_inline bool rb_need_aux_wakeup(struct ring_buffer *rb) 418 418 { 419 419 if (rb->aux_overwrite) 420 420 return false;
+3
tools/perf/Documentation/perf-stat.txt
··· 178 178 This option should be used together with "-I" option. 179 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 184 --timeout msecs:: 182 185 Stop the 'perf stat' session and print count deltas after N milliseconds (minimum: 10 ms). 183 186 This option is not supported with the "-I" option.
+5 -5
tools/perf/builtin-c2c.c
··· 56 56 57 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 65 * must be at the end, 61 66 * because of its callchain dynamic entry 62 67 */ 63 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 71 static char const *coalesce_default = "pid,iaddr";
+12
tools/perf/builtin-script.c
··· 180 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 195 [PERF_TYPE_RAW] = { 184 196 .user_set = false, 185 197
+28 -20
tools/perf/builtin-stat.c
··· 65 65 #include "util/tool.h" 66 66 #include "util/string2.h" 67 67 #include "util/metricgroup.h" 68 + #include "util/top.h" 68 69 #include "asm/bug.h" 69 70 70 71 #include <linux/time64.h> ··· 145 144 146 145 typedef int (*aggr_get_id_t)(struct cpu_map *m, int cpu); 147 146 147 + #define METRIC_ONLY_LEN 20 148 + 148 149 static int run_count = 1; 149 150 static bool no_inherit = false; 150 151 static volatile pid_t child_pid = -1; ··· 176 173 static aggr_get_id_t aggr_get_id; 177 174 static bool append_file; 178 175 static bool interval_count; 176 + static bool interval_clear; 179 177 static const char *output_name; 180 178 static int output_fd; 181 179 static int print_free_counters_hint; ··· 184 180 static u64 *walltime_run; 185 181 static bool ru_display = false; 186 182 static struct rusage ru_data; 183 + static unsigned int metric_only_len = METRIC_ONLY_LEN; 187 184 188 185 struct perf_stat { 189 186 bool record; ··· 972 967 fprintf(out, "%s%s%s%s", csv_sep, vals, csv_sep, unit); 973 968 } 974 969 975 - #define METRIC_ONLY_LEN 20 976 - 977 970 /* Filter out some columns that don't work well in metrics only mode */ 978 971 979 972 static bool valid_only_metric(const char *unit) ··· 1002 999 { 1003 1000 struct outstate *os = ctx; 1004 1001 FILE *out = os->fh; 1005 - int n; 1006 - char buf[1024]; 1007 - unsigned mlen = METRIC_ONLY_LEN; 1002 + char buf[1024], str[1024]; 1003 + unsigned mlen = metric_only_len; 1008 1004 1009 1005 if (!valid_only_metric(unit)) 1010 1006 return; 1011 1007 unit = fixunit(buf, os->evsel, unit); 1012 - if (color) 1013 - n = color_fprintf(out, color, fmt, val); 1014 - else 1015 - n = fprintf(out, fmt, val); 1016 - if (n > METRIC_ONLY_LEN) 1017 - n = METRIC_ONLY_LEN; 1018 1008 if (mlen < strlen(unit)) 1019 1009 mlen = strlen(unit) + 1; 1020 - fprintf(out, "%*s", mlen - n, ""); 1010 + 1011 + if (color) 1012 + mlen += strlen(color) + sizeof(PERF_COLOR_RESET) - 1; 1013 + 1014 + color_snprintf(str, sizeof(str), color ?: "", fmt, val); 1015 + fprintf(out, "%*s ", mlen, str); 1021 1016 } 1022 1017 1023 1018 static void print_metric_only_csv(void *ctx, const char *color __maybe_unused, ··· 1055 1054 if (csv_output) 1056 1055 fprintf(os->fh, "%s%s", unit, csv_sep); 1057 1056 else 1058 - fprintf(os->fh, "%-*s ", METRIC_ONLY_LEN, unit); 1057 + fprintf(os->fh, "%*s ", metric_only_len, unit); 1059 1058 } 1060 1059 1061 1060 static void nsec_printout(int id, int nr, struct perf_evsel *evsel, double avg) ··· 1705 1704 FILE *output = stat_config.output; 1706 1705 static int num_print_interval; 1707 1706 1707 + if (interval_clear) 1708 + puts(CONSOLE_CLEAR); 1709 + 1708 1710 sprintf(prefix, "%6lu.%09lu%s", ts->tv_sec, ts->tv_nsec, csv_sep); 1709 1711 1710 - if (num_print_interval == 0 && !csv_output) { 1712 + if ((num_print_interval == 0 && !csv_output) || interval_clear) { 1711 1713 switch (stat_config.aggr_mode) { 1712 1714 case AGGR_SOCKET: 1713 1715 fprintf(output, "# time socket cpus"); ··· 1723 1719 fprintf(output, " counts %*s events\n", unit_width, "unit"); 1724 1720 break; 1725 1721 case AGGR_NONE: 1726 - fprintf(output, "# time CPU"); 1722 + fprintf(output, "# time CPU "); 1727 1723 if (!metric_only) 1728 1724 fprintf(output, " counts %*s events\n", unit_width, "unit"); 1729 1725 break; ··· 1742 1738 } 1743 1739 } 1744 1740 1745 - if (num_print_interval == 0 && metric_only) 1741 + if ((num_print_interval == 0 && metric_only) || interval_clear) 1746 1742 print_metric_headers(" ", true); 1747 1743 if (++num_print_interval == 25) 1748 1744 num_print_interval = 0; ··· 2061 2057 "(overhead is possible for values <= 100ms)"), 2062 2058 OPT_INTEGER(0, "interval-count", &stat_config.times, 2063 2059 "print counts for fixed number of times"), 2060 + OPT_BOOLEAN(0, "interval-clear", &interval_clear, 2061 + "clear screen in between new interval"), 2064 2062 OPT_UINTEGER(0, "timeout", &stat_config.timeout, 2065 2063 "stop workload and print counts after a timeout period in ms (>= 10ms)"), 2066 2064 OPT_SET_UINT(0, "per-socket", &stat_config.aggr_mode, ··· 2442 2436 (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | 2443 2437 (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, 2444 2438 }; 2439 + struct parse_events_error errinfo; 2445 2440 2446 2441 /* Set attrs if no event is selected and !null_run: */ 2447 2442 if (null_run) 2448 2443 return 0; 2449 2444 2450 2445 if (transaction_run) { 2451 - struct parse_events_error errinfo; 2452 - 2453 2446 if (pmu_have_event("cpu", "cycles-ct") && 2454 2447 pmu_have_event("cpu", "el-start")) 2455 2448 err = parse_events(evsel_list, transaction_attrs, ··· 2459 2454 &errinfo); 2460 2455 if (err) { 2461 2456 fprintf(stderr, "Cannot set up transaction events\n"); 2457 + parse_events_print_error(&errinfo, transaction_attrs); 2462 2458 return -1; 2463 2459 } 2464 2460 return 0; ··· 2485 2479 pmu_have_event("msr", "smi")) { 2486 2480 if (!force_metric_only) 2487 2481 metric_only = true; 2488 - err = parse_events(evsel_list, smi_cost_attrs, NULL); 2482 + err = parse_events(evsel_list, smi_cost_attrs, &errinfo); 2489 2483 } else { 2490 2484 fprintf(stderr, "To measure SMI cost, it needs " 2491 2485 "msr/aperf/, msr/smi/ and cpu/cycles/ support\n"); 2486 + parse_events_print_error(&errinfo, smi_cost_attrs); 2492 2487 return -1; 2493 2488 } 2494 2489 if (err) { ··· 2524 2517 if (topdown_attrs[0] && str) { 2525 2518 if (warn) 2526 2519 arch_topdown_group_warn(); 2527 - err = parse_events(evsel_list, str, NULL); 2520 + err = parse_events(evsel_list, str, &errinfo); 2528 2521 if (err) { 2529 2522 fprintf(stderr, 2530 2523 "Cannot set up top down events %s: %d\n", 2531 2524 str, err); 2532 2525 free(str); 2526 + parse_events_print_error(&errinfo, str); 2533 2527 return -1; 2534 2528 } 2535 2529 } else {
+1 -1
tools/perf/ui/gtk/hists.c
··· 382 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 386 symbol_conf.use_callchain && hists__has(hists, sym)) { 387 387 if (callchain_param.mode == CHAIN_GRAPH_REL) 388 388 total = symbol_conf.cumulate_callchain ?
+8 -4
tools/perf/util/hist.c
··· 370 370 371 371 static int hist_entry__init(struct hist_entry *he, 372 372 struct hist_entry *template, 373 - bool sample_self) 373 + bool sample_self, 374 + size_t callchain_size) 374 375 { 375 376 *he = *template; 377 + he->callchain_size = callchain_size; 376 378 377 379 if (symbol_conf.cumulate_callchain) { 378 380 he->stat_acc = malloc(sizeof(he->stat)); ··· 475 473 476 474 he = ops->new(callchain_size); 477 475 if (he) { 478 - err = hist_entry__init(he, template, sample_self); 476 + err = hist_entry__init(he, template, sample_self, callchain_size); 479 477 if (err) { 480 478 ops->free(he); 481 479 he = NULL; ··· 621 619 .raw_data = sample->raw_data, 622 620 .raw_size = sample->raw_size, 623 621 .ops = ops, 624 - }; 622 + }, *he = hists__findnew_entry(hists, &entry, al, sample_self); 625 623 626 - return hists__findnew_entry(hists, &entry, al, sample_self); 624 + if (!hists->has_callchains && he && he->callchain_size != 0) 625 + hists->has_callchains = true; 626 + return he; 627 627 } 628 628 629 629 struct hist_entry *hists__add_entry(struct hists *hists,
+2 -2
tools/perf/util/hist.h
··· 85 85 struct events_stats stats; 86 86 u64 event_stream; 87 87 u16 col_len[HISTC_NR_COLS]; 88 + bool has_callchains; 88 89 int socket_filter; 89 90 struct perf_hpp_list *hpp_list; 90 91 struct list_head hpp_formats; ··· 223 222 224 223 static __pure inline bool hists__has_callchains(struct hists *hists) 225 224 { 226 - const struct perf_evsel *evsel = hists_to_evsel(hists); 227 - return evsel__has_callchain(evsel); 225 + return hists->has_callchains; 228 226 } 229 227 230 228 int hists__init(void);
+5
tools/perf/util/parse-events.y
··· 227 227 event_pmu: 228 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 232 struct list_head *list, *orig_terms, *terms; 231 233 232 234 if (parse_events_copy_term_list($2, &orig_terms)) 233 235 YYABORT; 236 + 237 + if (error) 238 + error->idx = @1.first_column; 234 239 235 240 ALLOC_LIST(list); 236 241 if (parse_events_add_pmu(_parse_state, list, $1, $2, false, false)) {
+3 -1
tools/perf/util/sort.h
··· 112 112 113 113 char level; 114 114 u8 filtered; 115 + 116 + u16 callchain_size; 115 117 union { 116 118 /* 117 119 * Since perf diff only supports the stdio output, TUI ··· 155 153 156 154 static __pure inline bool hist_entry__has_callchains(struct hist_entry *he) 157 155 { 158 - return hists__has_callchains(he->hists); 156 + return he->callchain_size != 0; 159 157 } 160 158 161 159 static inline bool hist_entry__has_pairs(struct hist_entry *he)