diff options
author | Marcel Ziswiler <marcel.ziswiler@toradex.com> | 2020-05-19 23:01:26 +0200 |
---|---|---|
committer | Marcel Ziswiler <marcel.ziswiler@toradex.com> | 2020-05-19 23:37:01 +0200 |
commit | 2ae782ca839e0ee07de37122ddea362adff2e975 (patch) | |
tree | df6b1a190760f51465122ca4c13492d5ac5984c6 /tools/perf | |
parent | 0a8ab17689e628c84a666195bfc6ab85d11cf057 (diff) | |
parent | 0661b3d6cfd774e28a2e2ba90a3d87479e5c399b (diff) |
Merge tag 'v4.9.220' into 4.9-2.3.x-imx
This is the 4.9.220 stable release
Conflicts:
arch/arm/Kconfig.debug
arch/arm/boot/dts/imx7s.dtsi
arch/arm/mach-imx/common.h
arch/arm/mach-imx/cpuidle-imx6q.c
arch/arm/mach-imx/cpuidle-imx6sx.c
arch/arm/mach-imx/suspend-imx6.S
block/blk-core.c
drivers/crypto/caam/caamalg.c
drivers/crypto/mxs-dcp.c
drivers/dma/imx-sdma.c
drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
drivers/input/keyboard/imx_keypad.c
drivers/input/keyboard/snvs_pwrkey.c
drivers/mmc/host/sdhci.c
drivers/net/can/flexcan.c
drivers/net/ethernet/freescale/fec_main.c
drivers/net/phy/phy_device.c
drivers/net/wireless/ath/ath10k/pci.c
drivers/tty/serial/imx.c
drivers/usb/dwc3/gadget.c
drivers/usb/host/xhci.c
include/linux/blkdev.h
include/linux/cpu.h
include/linux/platform_data/dma-imx-sdma.h
kernel/cpu.c
net/wireless/util.c
sound/soc/fsl/Kconfig
sound/soc/fsl/fsl_esai.c
sound/soc/fsl/fsl_sai.c
sound/soc/fsl/imx-sgtl5000.c
Diffstat (limited to 'tools/perf')
46 files changed, 440 insertions, 123 deletions
diff --git a/tools/perf/Documentation/perf-config.txt b/tools/perf/Documentation/perf-config.txt index cb081ac59fd1..bd359a04cb94 100644 --- a/tools/perf/Documentation/perf-config.txt +++ b/tools/perf/Documentation/perf-config.txt @@ -112,7 +112,7 @@ Given a $HOME/.perfconfig like this: [report] # Defaults - sort-order = comm,dso,symbol + sort_order = comm,dso,symbol percent-limit = 0 queue-size = 0 children = true diff --git a/tools/perf/Makefile b/tools/perf/Makefile index cd86fd7b35c4..ebcc0868b99e 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -34,7 +34,7 @@ endif # Only pass canonical directory names as the output directory: # ifneq ($(O),) - FULL_O := $(shell readlink -f $(O) || echo $(O)) + FULL_O := $(shell cd $(PWD); readlink -f $(O) || echo $(O)) endif # diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c index 47d584da5819..f6cff278aa5d 100644 --- a/tools/perf/arch/arm/util/cs-etm.c +++ b/tools/perf/arch/arm/util/cs-etm.c @@ -41,6 +41,8 @@ struct cs_etm_recording { struct auxtrace_record itr; struct perf_pmu *cs_etm_pmu; struct perf_evlist *evlist; + int wrapped_cnt; + bool *wrapped; bool snapshot_mode; size_t snapshot_size; }; @@ -458,16 +460,131 @@ static int cs_etm_info_fill(struct auxtrace_record *itr, return 0; } -static int cs_etm_find_snapshot(struct auxtrace_record *itr __maybe_unused, +static int cs_etm_alloc_wrapped_array(struct cs_etm_recording *ptr, int idx) +{ + bool *wrapped; + int cnt = ptr->wrapped_cnt; + + /* Make @ptr->wrapped as big as @idx */ + while (cnt <= idx) + cnt++; + + /* + * Free'ed in cs_etm_recording_free(). Using realloc() to avoid + * cross compilation problems where the host's system supports + * reallocarray() but not the target. + */ + wrapped = realloc(ptr->wrapped, cnt * sizeof(bool)); + if (!wrapped) + return -ENOMEM; + + wrapped[cnt - 1] = false; + ptr->wrapped_cnt = cnt; + ptr->wrapped = wrapped; + + return 0; +} + +static bool cs_etm_buffer_has_wrapped(unsigned char *buffer, + size_t buffer_size, u64 head) +{ + u64 i, watermark; + u64 *buf = (u64 *)buffer; + size_t buf_size = buffer_size; + + /* + * We want to look the very last 512 byte (chosen arbitrarily) in + * the ring buffer. + */ + watermark = buf_size - 512; + + /* + * @head is continuously increasing - if its value is equal or greater + * than the size of the ring buffer, it has wrapped around. + */ + if (head >= buffer_size) + return true; + + /* + * The value of @head is somewhere within the size of the ring buffer. + * This can be that there hasn't been enough data to fill the ring + * buffer yet or the trace time was so long that @head has numerically + * wrapped around. To find we need to check if we have data at the very + * end of the ring buffer. We can reliably do this because mmap'ed + * pages are zeroed out and there is a fresh mapping with every new + * session. + */ + + /* @head is less than 512 byte from the end of the ring buffer */ + if (head > watermark) + watermark = head; + + /* + * Speed things up by using 64 bit transactions (see "u64 *buf" above) + */ + watermark >>= 3; + buf_size >>= 3; + + /* + * If we find trace data at the end of the ring buffer, @head has + * been there and has numerically wrapped around at least once. + */ + for (i = watermark; i < buf_size; i++) + if (buf[i]) + return true; + + return false; +} + +static int cs_etm_find_snapshot(struct auxtrace_record *itr, int idx, struct auxtrace_mmap *mm, - unsigned char *data __maybe_unused, + unsigned char *data, u64 *head, u64 *old) { + int err; + bool wrapped; + struct cs_etm_recording *ptr = + container_of(itr, struct cs_etm_recording, itr); + + /* + * Allocate memory to keep track of wrapping if this is the first + * time we deal with this *mm. + */ + if (idx >= ptr->wrapped_cnt) { + err = cs_etm_alloc_wrapped_array(ptr, idx); + if (err) + return err; + } + + /* + * Check to see if *head has wrapped around. If it hasn't only the + * amount of data between *head and *old is snapshot'ed to avoid + * bloating the perf.data file with zeros. But as soon as *head has + * wrapped around the entire size of the AUX ring buffer it taken. + */ + wrapped = ptr->wrapped[idx]; + if (!wrapped && cs_etm_buffer_has_wrapped(data, mm->len, *head)) { + wrapped = true; + ptr->wrapped[idx] = true; + } + pr_debug3("%s: mmap index %d old head %zu new head %zu size %zu\n", __func__, idx, (size_t)*old, (size_t)*head, mm->len); - *old = *head; - *head += mm->len; + /* No wrap has occurred, we can just use *head and *old. */ + if (!wrapped) + return 0; + + /* + * *head has wrapped around - adjust *head and *old to pickup the + * entire content of the AUX buffer. + */ + if (*head >= mm->len) { + *old = *head - mm->len; + } else { + *head += mm->len; + *old = *head - mm->len; + } return 0; } @@ -508,6 +625,8 @@ static void cs_etm_recording_free(struct auxtrace_record *itr) { struct cs_etm_recording *ptr = container_of(itr, struct cs_etm_recording, itr); + + zfree(&ptr->wrapped); free(ptr); } diff --git a/tools/perf/arch/s390/util/machine.c b/tools/perf/arch/s390/util/machine.c index b9a95a1a8e69..f4f8aff8a9bb 100644 --- a/tools/perf/arch/s390/util/machine.c +++ b/tools/perf/arch/s390/util/machine.c @@ -4,16 +4,31 @@ #include "util.h" #include "machine.h" #include "api/fs/fs.h" +#include "debug.h" -int arch__fix_module_text_start(u64 *start, const char *name) +int arch__fix_module_text_start(u64 *start, u64 *size, const char *name) { + u64 m_start = *start; char path[PATH_MAX]; snprintf(path, PATH_MAX, "module/%.*s/sections/.text", (int)strlen(name) - 2, name + 1); - - if (sysfs__read_ull(path, (unsigned long long *)start) < 0) - return -1; + if (sysfs__read_ull(path, (unsigned long long *)start) < 0) { + pr_debug2("Using module %s start:%#lx\n", path, m_start); + *start = m_start; + } else { + /* Successful read of the modules segment text start address. + * Calculate difference between module start address + * in memory and module text segment start address. + * For example module load address is 0x3ff8011b000 + * (from /proc/modules) and module text segment start + * address is 0x3ff8011b870 (from file above). + * + * Adjust the module size and subtract the GOT table + * size located at the beginning of the module. + */ + *size -= (*start - m_start); + } return 0; } diff --git a/tools/perf/bench/numa.c b/tools/perf/bench/numa.c index ee9565a033f4..7b364f2926d4 100644 --- a/tools/perf/bench/numa.c +++ b/tools/perf/bench/numa.c @@ -35,6 +35,10 @@ #include <numa.h> #include <numaif.h> +#ifndef RUSAGE_THREAD +# define RUSAGE_THREAD 1 +#endif + /* * Regular printout to the terminal, supressed if -q is specified: */ @@ -369,8 +373,10 @@ static u8 *alloc_data(ssize_t bytes0, int map_flags, /* Allocate and initialize all memory on CPU#0: */ if (init_cpu0) { - orig_mask = bind_to_node(0); - bind_to_memnode(0); + int node = numa_node_of_cpu(0); + + orig_mask = bind_to_node(node); + bind_to_memnode(node); } bytes = bytes0 + HPSIZE; diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c index 3bdb2c78a21b..476e24cf97fa 100644 --- a/tools/perf/builtin-help.c +++ b/tools/perf/builtin-help.c @@ -186,7 +186,7 @@ static void add_man_viewer(const char *name) while (*p) p = &((*p)->next); *p = zalloc(sizeof(**p) + len + 1); - strncpy((*p)->name, name, len); + strcpy((*p)->name, name); } static int supported_man_viewer(const char *name, size_t len) diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index d426dcb18ce9..496a4ca11667 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c @@ -674,6 +674,7 @@ static char *compact_gfp_flags(char *gfp_flags) new = realloc(new_flags, len + strlen(cpt) + 2); if (new == NULL) { free(new_flags); + free(orig_flags); return NULL; } diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index 9a250c71840e..2b420e7a92c0 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c @@ -675,6 +675,16 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) ret = perf_add_probe_events(params.events, params.nevents); if (ret < 0) { + + /* + * When perf_add_probe_events() fails it calls + * cleanup_perf_probe_events(pevs, npevs), i.e. + * cleanup_perf_probe_events(params.events, params.nevents), which + * will call clear_perf_probe_event(), so set nevents to zero + * to avoid cleanup_params() to call clear_perf_probe_event() again + * on the same pevs. + */ + params.nevents = 0; pr_err_with_code(" Error: Failed to add events.", ret); return ret; } diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 6e88460cd13d..0abca8783bb3 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -671,6 +671,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) struct stat st; bool has_br_stack = false; int branch_mode = -1; + int last_key = 0; bool branch_call_mode = false; char callchain_default_opt[] = CALLCHAIN_DEFAULT_OPT; const char * const report_usage[] = { @@ -956,7 +957,8 @@ repeat: else use_browser = 0; - if (setup_sorting(session->evlist) < 0) { + if ((last_key != K_SWITCH_INPUT_DATA) && + (setup_sorting(session->evlist) < 0)) { if (sort_order) parse_options_usage(report_usage, options, "s", 1); if (field_order) @@ -1011,6 +1013,7 @@ repeat: ret = __cmd_report(&report); if (ret == K_SWITCH_INPUT_DATA) { perf_session__delete(session); + last_key = K_SWITCH_INPUT_DATA; goto repeat; } else ret = 0; diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 43d5f35e9074..5cb58f3afa35 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -2564,8 +2564,11 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) fprintf(output, "[ perf stat: executing run #%d ... ]\n", run_idx + 1); + if (run_idx != 0) + perf_evlist__reset_prev_raw_counts(evsel_list); + status = run_perf_stat(argc, argv); - if (forever && status != -1) { + if (forever && status != -1 && !interval) { print_counters(NULL, argc, argv); perf_stat__reset_stats(); } diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index e68c866ae798..cd2900ac473f 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -1323,8 +1323,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) goto out_delete_evlist; symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); - if (symbol__init(NULL) < 0) - return -1; + status = symbol__init(NULL); + if (status < 0) + goto out_delete_evlist; sort__setup_elide(stdout); diff --git a/tools/perf/check-headers.sh b/tools/perf/check-headers.sh index 83fe2202382e..ff38fc63bceb 100755 --- a/tools/perf/check-headers.sh +++ b/tools/perf/check-headers.sh @@ -4,6 +4,7 @@ HEADERS=' include/uapi/linux/fcntl.h include/uapi/linux/perf_event.h include/uapi/linux/stat.h +include/linux/bits.h include/linux/hash.h include/uapi/linux/hw_breakpoint.h arch/x86/include/asm/disabled-features.h diff --git a/tools/perf/perf.h b/tools/perf/perf.h index 8f8d895d5b74..3b9d56125ee2 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h @@ -23,7 +23,7 @@ static inline unsigned long long rdclock(void) } #ifndef MAX_NR_CPUS -#define MAX_NR_CPUS 1024 +#define MAX_NR_CPUS 2048 #endif extern const char *input_name; diff --git a/tools/perf/pmu-events/jevents.c b/tools/perf/pmu-events/jevents.c index 41611d7f9873..0619054bd7a0 100644 --- a/tools/perf/pmu-events/jevents.c +++ b/tools/perf/pmu-events/jevents.c @@ -311,11 +311,12 @@ static struct fixed { const char *name; const char *event; } fixed[] = { - { "inst_retired.any", "event=0xc0" }, - { "inst_retired.any_p", "event=0xc0" }, - { "cpu_clk_unhalted.ref", "event=0x0,umask=0x03" }, - { "cpu_clk_unhalted.thread", "event=0x3c" }, - { "cpu_clk_unhalted.thread_any", "event=0x3c,any=1" }, + { "inst_retired.any", "event=0xc0,period=2000003" }, + { "inst_retired.any_p", "event=0xc0,period=2000003" }, + { "cpu_clk_unhalted.ref", "event=0x0,umask=0x03,period=2000003" }, + { "cpu_clk_unhalted.thread", "event=0x3c,period=2000003" }, + { "cpu_clk_unhalted.core", "event=0x3c,period=2000003" }, + { "cpu_clk_unhalted.thread_any", "event=0x3c,any=1,period=2000003" }, { NULL, NULL}, }; diff --git a/tools/perf/tests/evsel-tp-sched.c b/tools/perf/tests/evsel-tp-sched.c index 66b53f10eb18..b5d0be524655 100644 --- a/tools/perf/tests/evsel-tp-sched.c +++ b/tools/perf/tests/evsel-tp-sched.c @@ -42,7 +42,7 @@ int test__perf_evsel__tp_sched_test(int subtest __maybe_unused) return -1; } - if (perf_evsel__test_field(evsel, "prev_comm", 16, true)) + if (perf_evsel__test_field(evsel, "prev_comm", 16, false)) ret = -1; if (perf_evsel__test_field(evsel, "prev_pid", 4, true)) @@ -54,7 +54,7 @@ int test__perf_evsel__tp_sched_test(int subtest __maybe_unused) if (perf_evsel__test_field(evsel, "prev_state", sizeof(long), true)) ret = -1; - if (perf_evsel__test_field(evsel, "next_comm", 16, true)) + if (perf_evsel__test_field(evsel, "next_comm", 16, false)) ret = -1; if (perf_evsel__test_field(evsel, "next_pid", 4, true)) @@ -72,7 +72,7 @@ int test__perf_evsel__tp_sched_test(int subtest __maybe_unused) return -1; } - if (perf_evsel__test_field(evsel, "comm", 16, true)) + if (perf_evsel__test_field(evsel, "comm", 16, false)) ret = -1; if (perf_evsel__test_field(evsel, "pid", 4, true)) @@ -84,5 +84,6 @@ int test__perf_evsel__tp_sched_test(int subtest __maybe_unused) if (perf_evsel__test_field(evsel, "target_cpu", 4, true)) ret = -1; + perf_evsel__delete(evsel); return ret; } diff --git a/tools/perf/tests/mmap-thread-lookup.c b/tools/perf/tests/mmap-thread-lookup.c index 0c5ce44f723f..e5d6e6584001 100644 --- a/tools/perf/tests/mmap-thread-lookup.c +++ b/tools/perf/tests/mmap-thread-lookup.c @@ -49,7 +49,7 @@ static void *thread_fn(void *arg) { struct thread_data *td = arg; ssize_t ret; - int go; + int go = 0; if (thread_init(td)) return NULL; diff --git a/tools/perf/tests/openat-syscall-all-cpus.c b/tools/perf/tests/openat-syscall-all-cpus.c index c8d9592eb142..75d504e9eeaf 100644 --- a/tools/perf/tests/openat-syscall-all-cpus.c +++ b/tools/perf/tests/openat-syscall-all-cpus.c @@ -38,7 +38,7 @@ int test__openat_syscall_event_on_all_cpus(int subtest __maybe_unused) if (IS_ERR(evsel)) { tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "syscalls", "sys_enter_openat"); pr_debug("%s\n", errbuf); - goto out_thread_map_delete; + goto out_cpu_map_delete; } if (perf_evsel__open(evsel, cpus, threads) < 0) { @@ -112,6 +112,8 @@ out_close_fd: perf_evsel__close_fd(evsel, 1, threads->nr); out_evsel_delete: perf_evsel__delete(evsel); +out_cpu_map_delete: + cpu_map__put(cpus); out_thread_map_delete: thread_map__put(threads); return err; diff --git a/tools/perf/tests/task-exit.c b/tools/perf/tests/task-exit.c index b0d005d295a9..de2ddfe0f7c3 100644 --- a/tools/perf/tests/task-exit.c +++ b/tools/perf/tests/task-exit.c @@ -98,6 +98,7 @@ int test__task_exit(int subtest __maybe_unused) if (perf_evlist__mmap(evlist, 128, true) < 0) { pr_debug("failed to mmap events: %d (%s)\n", errno, str_error_r(errno, sbuf, sizeof(sbuf))); + err = -1; goto out_delete_evlist; } diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index a53fef0c673b..ade6abda9f46 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -2930,6 +2930,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, continue; } + actions->ms.map = map; top = pstack__peek(browser->pstack); if (top == &browser->hists->dso_filter) { /* diff --git a/tools/perf/ui/tui/helpline.c b/tools/perf/ui/tui/helpline.c index 88f5143a5981..3c97e27383a9 100644 --- a/tools/perf/ui/tui/helpline.c +++ b/tools/perf/ui/tui/helpline.c @@ -23,7 +23,7 @@ static void tui_helpline__push(const char *msg) SLsmg_set_color(0); SLsmg_write_nstring((char *)msg, SLtt_Screen_Cols); SLsmg_refresh(); - strncpy(ui_helpline__current, msg, sz)[sz - 1] = '\0'; + strlcpy(ui_helpline__current, msg, sz); } static int tui_helpline__show(const char *format, va_list ap) diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index 993ef2762508..32aab95e1459 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c @@ -176,6 +176,7 @@ char *build_id_cache__linkname(const char *sbuild_id, char *bf, size_t size) return bf; } +/* The caller is responsible to free the returned buffer. */ char *build_id_cache__origname(const char *sbuild_id) { char *linkname; diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c index 18dae745034f..1d66f8eab9f9 100644 --- a/tools/perf/util/config.c +++ b/tools/perf/util/config.c @@ -595,11 +595,10 @@ static int collect_config(const char *var, const char *value, } ret = set_value(item, value); - return ret; out_free: free(key); - return -1; + return ret; } static int perf_config_set__init(struct perf_config_set *set) diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c index 7123f4de32cc..226f4312b8f3 100644 --- a/tools/perf/util/data-convert-bt.c +++ b/tools/perf/util/data-convert-bt.c @@ -265,7 +265,7 @@ static int string_set_value(struct bt_ctf_field *field, const char *string) if (i > 0) strncpy(buffer, string, i); } - strncat(buffer + p, numstr, 4); + memcpy(buffer + p, numstr, 4); p += 3; } } diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c index 41e068e94349..fb4e1d2839c5 100644 --- a/tools/perf/util/dwarf-aux.c +++ b/tools/perf/util/dwarf-aux.c @@ -318,20 +318,50 @@ bool die_is_func_def(Dwarf_Die *dw_die) } /** + * die_entrypc - Returns entry PC (the lowest address) of a DIE + * @dw_die: a DIE + * @addr: where to store entry PC + * + * Since dwarf_entrypc() does not return entry PC if the DIE has only address + * range, we have to use this to retrieve the lowest address from the address + * range attribute. + */ +int die_entrypc(Dwarf_Die *dw_die, Dwarf_Addr *addr) +{ + Dwarf_Addr base, end; + + if (!addr) + return -EINVAL; + + if (dwarf_entrypc(dw_die, addr) == 0) + return 0; + + return dwarf_ranges(dw_die, 0, &base, addr, &end) < 0 ? -ENOENT : 0; +} + +/** * die_is_func_instance - Ensure that this DIE is an instance of a subprogram * @dw_die: a DIE * * Ensure that this DIE is an instance (which has an entry address). - * This returns true if @dw_die is a function instance. If not, you need to - * call die_walk_instances() to find actual instances. + * This returns true if @dw_die is a function instance. If not, the @dw_die + * must be a prototype. You can use die_walk_instances() to find actual + * instances. **/ bool die_is_func_instance(Dwarf_Die *dw_die) { Dwarf_Addr tmp; + Dwarf_Attribute attr_mem; + int tag = dwarf_tag(dw_die); - /* Actually gcc optimizes non-inline as like as inlined */ - return !dwarf_func_inline(dw_die) && dwarf_entrypc(dw_die, &tmp) == 0; + if (tag != DW_TAG_subprogram && + tag != DW_TAG_inlined_subroutine) + return false; + + return dwarf_entrypc(dw_die, &tmp) == 0 || + dwarf_attr(dw_die, DW_AT_ranges, &attr_mem) != NULL; } + /** * die_get_data_member_location - Get the data-member offset * @mb_die: a DIE of a member of a data structure @@ -608,6 +638,9 @@ static int __die_walk_instances_cb(Dwarf_Die *inst, void *data) Dwarf_Die *origin; int tmp; + if (!die_is_func_instance(inst)) + return DIE_FIND_CB_CONTINUE; + attr = dwarf_attr(inst, DW_AT_abstract_origin, &attr_mem); if (attr == NULL) return DIE_FIND_CB_CONTINUE; @@ -679,15 +712,14 @@ static int __die_walk_funclines_cb(Dwarf_Die *in_die, void *data) if (dwarf_tag(in_die) == DW_TAG_inlined_subroutine) { fname = die_get_call_file(in_die); lineno = die_get_call_lineno(in_die); - if (fname && lineno > 0 && dwarf_entrypc(in_die, &addr) == 0) { + if (fname && lineno > 0 && die_entrypc(in_die, &addr) == 0) { lw->retval = lw->callback(fname, lineno, addr, lw->data); if (lw->retval != 0) return DIE_FIND_CB_END; } + if (!lw->recursive) + return DIE_FIND_CB_SIBLING; } - if (!lw->recursive) - /* Don't need to search recursively */ - return DIE_FIND_CB_SIBLING; if (addr) { fname = dwarf_decl_file(in_die); @@ -720,7 +752,7 @@ static int __die_walk_funclines(Dwarf_Die *sp_die, bool recursive, /* Handle function declaration line */ fname = dwarf_decl_file(sp_die); if (fname && dwarf_decl_line(sp_die, &lineno) == 0 && - dwarf_entrypc(sp_die, &addr) == 0) { + die_entrypc(sp_die, &addr) == 0) { lw.retval = callback(fname, lineno, addr, data); if (lw.retval != 0) goto done; @@ -734,6 +766,10 @@ static int __die_walk_culines_cb(Dwarf_Die *sp_die, void *data) { struct __line_walk_param *lw = data; + /* + * Since inlined function can include another inlined function in + * the same file, we need to walk in it recursively. + */ lw->retval = __die_walk_funclines(sp_die, true, lw->callback, lw->data); if (lw->retval != 0) return DWARF_CB_ABORT; @@ -758,11 +794,12 @@ int die_walk_lines(Dwarf_Die *rt_die, line_walk_callback_t callback, void *data) Dwarf_Lines *lines; Dwarf_Line *line; Dwarf_Addr addr; - const char *fname, *decf = NULL; + const char *fname, *decf = NULL, *inf = NULL; int lineno, ret = 0; int decl = 0, inl; Dwarf_Die die_mem, *cu_die; size_t nlines, i; + bool flag; /* Get the CU die */ if (dwarf_tag(rt_die) != DW_TAG_compile_unit) { @@ -793,6 +830,12 @@ int die_walk_lines(Dwarf_Die *rt_die, line_walk_callback_t callback, void *data) "Possible error in debuginfo.\n"); continue; } + /* Skip end-of-sequence */ + if (dwarf_lineendsequence(line, &flag) != 0 || flag) + continue; + /* Skip Non statement line-info */ + if (dwarf_linebeginstatement(line, &flag) != 0 || !flag) + continue; /* Filter lines based on address */ if (rt_die != cu_die) { /* @@ -802,13 +845,21 @@ int die_walk_lines(Dwarf_Die *rt_die, line_walk_callback_t callback, void *data) */ if (!dwarf_haspc(rt_die, addr)) continue; + if (die_find_inlinefunc(rt_die, addr, &die_mem)) { + /* Call-site check */ + inf = die_get_call_file(&die_mem); + if ((inf && !strcmp(inf, decf)) && + die_get_call_lineno(&die_mem) == lineno) + goto found; + dwarf_decl_line(&die_mem, &inl); if (inl != decl || decf != dwarf_decl_file(&die_mem)) continue; } } +found: /* Get source line */ fname = dwarf_linesrc(line, NULL, NULL); @@ -823,8 +874,9 @@ int die_walk_lines(Dwarf_Die *rt_die, line_walk_callback_t callback, void *data) */ if (rt_die != cu_die) /* - * Don't need walk functions recursively, because nested - * inlined functions don't have lines of the specified DIE. + * Don't need walk inlined functions recursively, because + * inner inlined functions don't have the lines of the + * specified function. */ ret = __die_walk_funclines(rt_die, false, callback, data); else { @@ -999,7 +1051,7 @@ static int die_get_var_innermost_scope(Dwarf_Die *sp_die, Dwarf_Die *vr_die, bool first = true; const char *name; - ret = dwarf_entrypc(sp_die, &entry); + ret = die_entrypc(sp_die, &entry); if (ret) return ret; @@ -1062,7 +1114,7 @@ int die_get_var_range(Dwarf_Die *sp_die, Dwarf_Die *vr_die, struct strbuf *buf) bool first = true; const char *name; - ret = dwarf_entrypc(sp_die, &entry); + ret = die_entrypc(sp_die, &entry); if (ret) return ret; diff --git a/tools/perf/util/dwarf-aux.h b/tools/perf/util/dwarf-aux.h index 8ac53bf1ec4e..ee15fac4e1d0 100644 --- a/tools/perf/util/dwarf-aux.h +++ b/tools/perf/util/dwarf-aux.h @@ -41,6 +41,9 @@ int cu_walk_functions_at(Dwarf_Die *cu_die, Dwarf_Addr addr, /* Get DW_AT_linkage_name (should be NULL for C binary) */ const char *die_get_linkage_name(Dwarf_Die *dw_die); +/* Get the lowest PC in DIE (including range list) */ +int die_entrypc(Dwarf_Die *dw_die, Dwarf_Addr *addr); + /* Ensure that this DIE is a subprogram and definition (not declaration) */ bool die_is_func_def(Dwarf_Die *dw_die); diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index f7128c2a6386..758d0108c5a5 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -558,6 +558,9 @@ const char *perf_evsel__name(struct perf_evsel *evsel) { char bf[128]; + if (!evsel) + goto out_unknown; + if (evsel->name) return evsel->name; @@ -594,7 +597,10 @@ const char *perf_evsel__name(struct perf_evsel *evsel) evsel->name = strdup(bf); - return evsel->name ?: "unknown"; + if (evsel->name) + return evsel->name; +out_unknown: + return "unknown"; } const char *perf_evsel__group_name(struct perf_evsel *evsel) @@ -1167,6 +1173,7 @@ void perf_evsel__exit(struct perf_evsel *evsel) { assert(list_empty(&evsel->node)); assert(evsel->evlist == NULL); + perf_evsel__free_counts(evsel); perf_evsel__free_fd(evsel); perf_evsel__free_id(evsel); perf_evsel__free_config_terms(evsel); diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index a11f6760cce8..b3d947b98a7c 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -949,7 +949,7 @@ static int cpu_cache_level__read(struct cpu_cache_level *cache, u32 cpu, u16 lev scnprintf(file, PATH_MAX, "%s/shared_cpu_list", path); if (sysfs__read_str(file, &cache->map, &len)) { - free(cache->map); + free(cache->size); free(cache->type); return -1; } @@ -1008,7 +1008,7 @@ static int build_caches(struct cpu_cache_level caches[], u32 size, u32 *cntp) return 0; } -#define MAX_CACHES 2000 +#define MAX_CACHES (MAX_NR_CPUS * 4) static int write_cache(int fd, struct perf_header *h __maybe_unused, struct perf_evlist *evlist __maybe_unused) @@ -2854,6 +2854,13 @@ int perf_session__read_header(struct perf_session *session) file->path); } + if (f_header.attr_size == 0) { + pr_err("ERROR: The %s file's attr size field is 0 which is unexpected.\n" + "Was the 'perf record' command properly terminated?\n", + file->path); + return -EINVAL; + } + nr_attrs = f_header.attrs.size / f_header.attr_size; lseek(fd, f_header.attrs.offset, SEEK_SET); @@ -2936,7 +2943,7 @@ int perf_event__synthesize_attr(struct perf_tool *tool, size += sizeof(struct perf_event_header); size += ids * sizeof(u64); - ev = malloc(size); + ev = zalloc(size); if (ev == NULL) return -ENOMEM; @@ -3027,7 +3034,7 @@ perf_event__synthesize_event_update_name(struct perf_tool *tool, if (ev == NULL) return -ENOMEM; - strncpy(ev->data, evsel->name, len); + strlcpy(ev->data, evsel->name, len + 1); err = process(tool, (union perf_event*) ev, NULL, NULL); free(ev); return err; diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index ad613ea51434..32f991d28497 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -1027,8 +1027,10 @@ int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al, err = sample__resolve_callchain(iter->sample, &callchain_cursor, &iter->parent, iter->evsel, al, max_stack_depth); - if (err) + if (err) { + map__put(alm); return err; + } err = iter->ops->prepare_entry(iter, al); if (err) @@ -1483,7 +1485,7 @@ int hists__collapse_resort(struct hists *hists, struct ui_progress *prog) return 0; } -static int hist_entry__sort(struct hist_entry *a, struct hist_entry *b) +static int64_t hist_entry__sort(struct hist_entry *a, struct hist_entry *b) { struct hists *hists = a->hists; struct perf_hpp_fmt *fmt; diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 159d616e170b..fdd7a1cb6be9 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -312,10 +312,10 @@ static inline void perf_hpp__prepend_sort_field(struct perf_hpp_fmt *format) list_for_each_entry_safe(format, tmp, &(_list)->sorts, sort_list) #define hists__for_each_format(hists, format) \ - perf_hpp_list__for_each_format((hists)->hpp_list, fmt) + perf_hpp_list__for_each_format((hists)->hpp_list, format) #define hists__for_each_sort_list(hists, format) \ - perf_hpp_list__for_each_sort_list((hists)->hpp_list, fmt) + perf_hpp_list__for_each_sort_list((hists)->hpp_list, format) extern struct perf_hpp_fmt perf_hpp__format[]; diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c index 94764efb0a6a..63fa3a95a1d6 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c @@ -58,6 +58,7 @@ enum intel_pt_pkt_state { INTEL_PT_STATE_NO_IP, INTEL_PT_STATE_ERR_RESYNC, INTEL_PT_STATE_IN_SYNC, + INTEL_PT_STATE_TNT_CONT, INTEL_PT_STATE_TNT, INTEL_PT_STATE_TIP, INTEL_PT_STATE_TIP_PGD, @@ -72,8 +73,9 @@ static inline bool intel_pt_sample_time(enum intel_pt_pkt_state pkt_state) case INTEL_PT_STATE_NO_IP: case INTEL_PT_STATE_ERR_RESYNC: case INTEL_PT_STATE_IN_SYNC: - case INTEL_PT_STATE_TNT: + case INTEL_PT_STATE_TNT_CONT: return true; + case INTEL_PT_STATE_TNT: case INTEL_PT_STATE_TIP: case INTEL_PT_STATE_TIP_PGD: case INTEL_PT_STATE_FUP: @@ -240,19 +242,15 @@ struct intel_pt_decoder *intel_pt_decoder_new(struct intel_pt_params *params) if (!(decoder->tsc_ctc_ratio_n % decoder->tsc_ctc_ratio_d)) decoder->tsc_ctc_mult = decoder->tsc_ctc_ratio_n / decoder->tsc_ctc_ratio_d; - - /* - * Allow for timestamps appearing to backwards because a TSC - * packet has slipped past a MTC packet, so allow 2 MTC ticks - * or ... - */ - decoder->tsc_slip = multdiv(2 << decoder->mtc_shift, - decoder->tsc_ctc_ratio_n, - decoder->tsc_ctc_ratio_d); } - /* ... or 0x100 paranoia */ - if (decoder->tsc_slip < 0x100) - decoder->tsc_slip = 0x100; + + /* + * A TSC packet can slip past MTC packets so that the timestamp appears + * to go backwards. One estimate is that can be up to about 40 CPU + * cycles, which is certainly less than 0x1000 TSC ticks, but accept + * slippage an order of magnitude more to be on the safe side. + */ + decoder->tsc_slip = 0x10000; intel_pt_log("timestamp: mtc_shift %u\n", decoder->mtc_shift); intel_pt_log("timestamp: tsc_ctc_ratio_n %u\n", decoder->tsc_ctc_ratio_n); @@ -860,16 +858,20 @@ static uint64_t intel_pt_next_period(struct intel_pt_decoder *decoder) timestamp = decoder->timestamp + decoder->timestamp_insn_cnt; masked_timestamp = timestamp & decoder->period_mask; if (decoder->continuous_period) { - if (masked_timestamp != decoder->last_masked_timestamp) + if (masked_timestamp > decoder->last_masked_timestamp) return 1; } else { timestamp += 1; masked_timestamp = timestamp & decoder->period_mask; - if (masked_timestamp != decoder->last_masked_timestamp) { + if (masked_timestamp > decoder->last_masked_timestamp) { decoder->last_masked_timestamp = masked_timestamp; decoder->continuous_period = true; } } + + if (masked_timestamp < decoder->last_masked_timestamp) + return decoder->period_ticks; + return decoder->period_ticks - (timestamp - masked_timestamp); } @@ -898,7 +900,10 @@ static void intel_pt_sample_insn(struct intel_pt_decoder *decoder) case INTEL_PT_PERIOD_TICKS: timestamp = decoder->timestamp + decoder->timestamp_insn_cnt; masked_timestamp = timestamp & decoder->period_mask; - decoder->last_masked_timestamp = masked_timestamp; + if (masked_timestamp > decoder->last_masked_timestamp) + decoder->last_masked_timestamp = masked_timestamp; + else + decoder->last_masked_timestamp += decoder->period_ticks; break; case INTEL_PT_PERIOD_NONE: case INTEL_PT_PERIOD_MTC: @@ -1175,7 +1180,9 @@ static int intel_pt_walk_tnt(struct intel_pt_decoder *decoder) return -ENOENT; } decoder->tnt.count -= 1; - if (!decoder->tnt.count) + if (decoder->tnt.count) + decoder->pkt_state = INTEL_PT_STATE_TNT_CONT; + else decoder->pkt_state = INTEL_PT_STATE_IN_SYNC; decoder->tnt.payload <<= 1; decoder->state.from_ip = decoder->ip; @@ -1206,7 +1213,9 @@ static int intel_pt_walk_tnt(struct intel_pt_decoder *decoder) if (intel_pt_insn.branch == INTEL_PT_BR_CONDITIONAL) { decoder->tnt.count -= 1; - if (!decoder->tnt.count) + if (decoder->tnt.count) + decoder->pkt_state = INTEL_PT_STATE_TNT_CONT; + else decoder->pkt_state = INTEL_PT_STATE_IN_SYNC; if (decoder->tnt.payload & BIT63) { decoder->tnt.payload <<= 1; @@ -1226,8 +1235,11 @@ static int intel_pt_walk_tnt(struct intel_pt_decoder *decoder) return 0; } decoder->ip += intel_pt_insn.length; - if (!decoder->tnt.count) + if (!decoder->tnt.count) { + decoder->sample_timestamp = decoder->timestamp; + decoder->sample_insn_cnt = decoder->timestamp_insn_cnt; return -EAGAIN; + } decoder->tnt.payload <<= 1; continue; } @@ -2150,6 +2162,7 @@ const struct intel_pt_state *intel_pt_decode(struct intel_pt_decoder *decoder) err = intel_pt_walk_trace(decoder); break; case INTEL_PT_STATE_TNT: + case INTEL_PT_STATE_TNT_CONT: err = intel_pt_walk_tnt(decoder); if (err == -EAGAIN) err = intel_pt_walk_trace(decoder); diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c index 95f0884aae02..7e2e8aa95467 100644 --- a/tools/perf/util/jitdump.c +++ b/tools/perf/util/jitdump.c @@ -369,7 +369,7 @@ static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr) size_t size; u16 idr_size; const char *sym; - uint32_t count; + uint64_t count; int ret, csize; pid_t pid, tid; struct { @@ -391,7 +391,7 @@ static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr) return -1; filename = event->mmap2.filename; - size = snprintf(filename, PATH_MAX, "%s/jitted-%d-%u.so", + size = snprintf(filename, PATH_MAX, "%s/jitted-%d-%" PRIu64 ".so", jd->dir, pid, count); @@ -493,7 +493,7 @@ static int jit_repipe_code_move(struct jit_buf_desc *jd, union jr_entry *jr) return -1; filename = event->mmap2.filename; - size = snprintf(filename, PATH_MAX, "%s/jitted-%d-%"PRIu64, + size = snprintf(filename, PATH_MAX, "%s/jitted-%d-%" PRIu64 ".so", jd->dir, pid, jr->move.code_index); diff --git a/tools/perf/util/llvm-utils.c b/tools/perf/util/llvm-utils.c index 621f6527b790..4887dd5eb80f 100644 --- a/tools/perf/util/llvm-utils.c +++ b/tools/perf/util/llvm-utils.c @@ -220,14 +220,14 @@ static int detect_kbuild_dir(char **kbuild_dir) const char *prefix_dir = ""; const char *suffix_dir = ""; + /* _UTSNAME_LENGTH is 65 */ + char release[128]; + char *autoconf_path; int err; if (!test_dir) { - /* _UTSNAME_LENGTH is 65 */ - char release[128]; - err = fetch_kernel_version(NULL, release, sizeof(release)); if (err) diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index df85b9efd80f..45ea7a8cd818 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -1074,22 +1074,25 @@ static int machine__set_modules_path(struct machine *machine) return map_groups__set_modules_path_dir(&machine->kmaps, modules_path, 0); } int __weak arch__fix_module_text_start(u64 *start __maybe_unused, + u64 *size __maybe_unused, const char *name __maybe_unused) { return 0; } -static int machine__create_module(void *arg, const char *name, u64 start) +static int machine__create_module(void *arg, const char *name, u64 start, + u64 size) { struct machine *machine = arg; struct map *map; - if (arch__fix_module_text_start(&start, name) < 0) + if (arch__fix_module_text_start(&start, &size, name) < 0) return -1; map = machine__findnew_module_map(machine, start, name); if (map == NULL) return -1; + map->end = start + size; dso__kernel_module_get_build_id(map->dso, machine->root_dir); diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h index 354de6e56109..9b87b8b870ae 100644 --- a/tools/perf/util/machine.h +++ b/tools/perf/util/machine.h @@ -205,7 +205,7 @@ struct symbol *machine__find_kernel_function_by_name(struct machine *machine, struct map *machine__findnew_module_map(struct machine *machine, u64 start, const char *filename); -int arch__fix_module_text_start(u64 *start, const char *name); +int arch__fix_module_text_start(u64 *start, u64 *size, const char *name); int __machine__load_kallsyms(struct machine *machine, const char *filename, enum map_type type, bool no_kcore); diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index c662fef95d14..ab8ebfa2159d 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -1,4 +1,5 @@ #include "symbol.h" +#include <assert.h> #include <errno.h> #include <inttypes.h> #include <limits.h> @@ -87,7 +88,7 @@ static inline bool replace_android_lib(const char *filename, char *newfilename) return true; } - if (!strncmp(filename, "/system/lib/", 11)) { + if (!strncmp(filename, "/system/lib/", 12)) { char *ndk, *app; const char *arch; size_t ndk_length; @@ -716,6 +717,8 @@ static int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp } after->start = map->end; + after->pgoff += map->end - pos->start; + assert(pos->map_ip(pos, map->end) == after->map_ip(after, map->end)); __map_groups__insert(pos->groups, after); if (verbose >= 2) map__fprintf(after, fp); diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 14f111a10650..6193be6d7639 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -2104,6 +2104,7 @@ void print_sdt_events(const char *subsys_glob, const char *event_glob, printf(" %-50s [%s]\n", buf, "SDT event"); free(buf); } + free(path); } else printf(" %-50s [%s]\n", nd->s, "SDT event"); if (nd2) { diff --git a/tools/perf/util/perf_regs.h b/tools/perf/util/perf_regs.h index 679d6e493962..e6324397b295 100644 --- a/tools/perf/util/perf_regs.h +++ b/tools/perf/util/perf_regs.h @@ -26,7 +26,7 @@ int perf_reg_value(u64 *valp, struct regs_dump *regs, int id); static inline const char *perf_reg_name(int id __maybe_unused) { - return NULL; + return "unknown"; } static inline int perf_reg_value(u64 *valp __maybe_unused, diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 0d9d6e0803b8..82e4f158c88e 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -612,38 +612,31 @@ static int convert_to_trace_point(Dwarf_Die *sp_die, Dwfl_Module *mod, const char *function, struct probe_trace_point *tp) { - Dwarf_Addr eaddr, highaddr; + Dwarf_Addr eaddr; GElf_Sym sym; const char *symbol; /* Verify the address is correct */ - if (dwarf_entrypc(sp_die, &eaddr) != 0) { - pr_warning("Failed to get entry address of %s\n", - dwarf_diename(sp_die)); - return -ENOENT; - } - if (dwarf_highpc(sp_die, &highaddr) != 0) { - pr_warning("Failed to get end address of %s\n", - dwarf_diename(sp_die)); - return -ENOENT; - } - if (paddr > highaddr) { - pr_warning("Offset specified is greater than size of %s\n", + if (!dwarf_haspc(sp_die, paddr)) { + pr_warning("Specified offset is out of %s\n", dwarf_diename(sp_die)); return -EINVAL; } - symbol = dwarf_diename(sp_die); - if (!symbol) { - /* Try to get the symbol name from symtab */ + if (dwarf_entrypc(sp_die, &eaddr) == 0) { + /* If the DIE has entrypc, use it. */ + symbol = dwarf_diename(sp_die); + } else { + /* Try to get actual symbol name and address from symtab */ symbol = dwfl_module_addrsym(mod, paddr, &sym, NULL); - if (!symbol) { - pr_warning("Failed to find symbol at 0x%lx\n", - (unsigned long)paddr); - return -ENOENT; - } eaddr = sym.st_value; } + if (!symbol) { + pr_warning("Failed to find symbol at 0x%lx\n", + (unsigned long)paddr); + return -ENOENT; + } + tp->offset = (unsigned long)(paddr - eaddr); tp->address = (unsigned long)paddr; tp->symbol = strdup(symbol); @@ -764,6 +757,16 @@ static int find_best_scope_cb(Dwarf_Die *fn_die, void *data) return 0; } +/* Return innermost DIE */ +static int find_inner_scope_cb(Dwarf_Die *fn_die, void *data) +{ + struct find_scope_param *fsp = data; + + memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die)); + fsp->found = true; + return 1; +} + /* Find an appropriate scope fits to given conditions */ static Dwarf_Die *find_best_scope(struct probe_finder *pf, Dwarf_Die *die_mem) { @@ -775,8 +778,13 @@ static Dwarf_Die *find_best_scope(struct probe_finder *pf, Dwarf_Die *die_mem) .die_mem = die_mem, .found = false, }; + int ret; - cu_walk_functions_at(&pf->cu_die, pf->addr, find_best_scope_cb, &fsp); + ret = cu_walk_functions_at(&pf->cu_die, pf->addr, find_best_scope_cb, + &fsp); + if (!ret && !fsp.found) + cu_walk_functions_at(&pf->cu_die, pf->addr, + find_inner_scope_cb, &fsp); return fsp.found ? die_mem : NULL; } @@ -950,7 +958,7 @@ static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) ret = find_probe_point_lazy(in_die, pf); else { /* Get probe address */ - if (dwarf_entrypc(in_die, &addr) != 0) { + if (die_entrypc(in_die, &addr) != 0) { pr_warning("Failed to get entry address of %s.\n", dwarf_diename(in_die)); return -ENOENT; @@ -1002,7 +1010,7 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) param->retval = find_probe_point_by_line(pf); } else if (die_is_func_instance(sp_die)) { /* Instances always have the entry address */ - dwarf_entrypc(sp_die, &pf->addr); + die_entrypc(sp_die, &pf->addr); /* But in some case the entry address is 0 */ if (pf->addr == 0) { pr_debug("%s has no entry PC. Skipped\n", @@ -1414,6 +1422,18 @@ error: return DIE_FIND_CB_END; } +static bool available_var_finder_overlap(struct available_var_finder *af) +{ + int i; + + for (i = 0; i < af->nvls; i++) { + if (af->pf.addr == af->vls[i].point.address) + return true; + } + return false; + +} + /* Add a found vars into available variables list */ static int add_available_vars(Dwarf_Die *sc_die, struct probe_finder *pf) { @@ -1424,6 +1444,14 @@ static int add_available_vars(Dwarf_Die *sc_die, struct probe_finder *pf) Dwarf_Die die_mem; int ret; + /* + * For some reason (e.g. different column assigned to same address), + * this callback can be called with the address which already passed. + * Ignore it first. + */ + if (available_var_finder_overlap(af)) + return 0; + /* Check number of tevs */ if (af->nvls == af->max_vls) { pr_warning("Too many( > %d) probe point found.\n", af->max_vls); @@ -1567,7 +1595,7 @@ int debuginfo__find_probe_point(struct debuginfo *dbg, unsigned long addr, /* Get function entry information */ func = basefunc = dwarf_diename(&spdie); if (!func || - dwarf_entrypc(&spdie, &baseaddr) != 0 || + die_entrypc(&spdie, &baseaddr) != 0 || dwarf_decl_line(&spdie, &baseline) != 0) { lineno = 0; goto post; @@ -1584,7 +1612,7 @@ int debuginfo__find_probe_point(struct debuginfo *dbg, unsigned long addr, while (die_find_top_inlinefunc(&spdie, (Dwarf_Addr)addr, &indie)) { /* There is an inline function */ - if (dwarf_entrypc(&indie, &_addr) == 0 && + if (die_entrypc(&indie, &_addr) == 0 && _addr == addr) { /* * addr is at an inline function entry. diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c index 39345c2ddfc2..d4f872f1750e 100644 --- a/tools/perf/util/stat.c +++ b/tools/perf/util/stat.c @@ -145,6 +145,15 @@ static void perf_evsel__free_prev_raw_counts(struct perf_evsel *evsel) evsel->prev_raw_counts = NULL; } +static void perf_evsel__reset_prev_raw_counts(struct perf_evsel *evsel) +{ + if (evsel->prev_raw_counts) { + evsel->prev_raw_counts->aggr.val = 0; + evsel->prev_raw_counts->aggr.ena = 0; + evsel->prev_raw_counts->aggr.run = 0; + } +} + static int perf_evsel__alloc_stats(struct perf_evsel *evsel, bool alloc_raw) { int ncpus = perf_evsel__nr_cpus(evsel); @@ -195,6 +204,14 @@ void perf_evlist__reset_stats(struct perf_evlist *evlist) } } +void perf_evlist__reset_prev_raw_counts(struct perf_evlist *evlist) +{ + struct perf_evsel *evsel; + + evlist__for_each_entry(evlist, evsel) + perf_evsel__reset_prev_raw_counts(evsel); +} + static void zero_per_pkg(struct perf_evsel *counter) { if (counter->per_pkg_mask) diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h index c29bb94c48a4..b8845aceac31 100644 --- a/tools/perf/util/stat.h +++ b/tools/perf/util/stat.h @@ -94,6 +94,7 @@ void perf_stat__print_shadow_stats(struct perf_evsel *evsel, int perf_evlist__alloc_stats(struct perf_evlist *evlist, bool alloc_raw); void perf_evlist__free_stats(struct perf_evlist *evlist); void perf_evlist__reset_stats(struct perf_evlist *evlist); +void perf_evlist__reset_prev_raw_counts(struct perf_evlist *evlist); int perf_stat_process_counter(struct perf_stat_config *config, struct perf_evsel *counter); diff --git a/tools/perf/util/strbuf.c b/tools/perf/util/strbuf.c index 842cf3fd9235..d7e5c247c103 100644 --- a/tools/perf/util/strbuf.c +++ b/tools/perf/util/strbuf.c @@ -116,7 +116,6 @@ static int strbuf_addv(struct strbuf *sb, const char *fmt, va_list ap) return ret; } len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap_saved); - va_end(ap_saved); if (len > strbuf_avail(sb)) { pr_debug("this should not happen, your vsnprintf is broken"); va_end(ap_saved); diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index 20ba5a9aeae4..5a50326c8158 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c @@ -1478,7 +1478,7 @@ static int kcore_copy__parse_kallsyms(struct kcore_copy_info *kci, static int kcore_copy__process_modules(void *arg, const char *name __maybe_unused, - u64 start) + u64 start, u64 size __maybe_unused) { struct kcore_copy_info *kci = arg; diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index f199d5b11d76..acde8e489352 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -217,7 +217,8 @@ void __map_groups__fixup_end(struct map_groups *mg, enum map_type type) goto out_unlock; for (next = map__next(curr); next; next = map__next(curr)) { - curr->end = next->start; + if (!curr->end) + curr->end = next->start; curr = next; } @@ -225,7 +226,8 @@ void __map_groups__fixup_end(struct map_groups *mg, enum map_type type) * We still haven't the actual symbols, so guess the * last map final address. */ - curr->end = ~0ULL; + if (!curr->end) + curr->end = ~0ULL; out_unlock: pthread_rwlock_unlock(&maps->lock); @@ -512,7 +514,7 @@ void dso__sort_by_name(struct dso *dso, enum map_type type) int modules__parse(const char *filename, void *arg, int (*process_module)(void *arg, const char *name, - u64 start)) + u64 start, u64 size)) { char *line = NULL; size_t n; @@ -525,8 +527,8 @@ int modules__parse(const char *filename, void *arg, while (1) { char name[PATH_MAX]; - u64 start; - char *sep; + u64 start, size; + char *sep, *endptr; ssize_t line_len; line_len = getline(&line, &n, file); @@ -558,7 +560,11 @@ int modules__parse(const char *filename, void *arg, scnprintf(name, sizeof(name), "[%s]", line); - err = process_module(arg, name, start); + size = strtoul(sep + 1, &endptr, 0); + if (*endptr != ' ' && *endptr != '\t') + continue; + + err = process_module(arg, name, start, size); if (err) break; } @@ -905,7 +911,8 @@ static struct module_info *find_module(const char *name, return NULL; } -static int __read_proc_modules(void *arg, const char *name, u64 start) +static int __read_proc_modules(void *arg, const char *name, u64 start, + u64 size __maybe_unused) { struct rb_root *modules = arg; struct module_info *mi; diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index d964844eb314..833b1be2fb29 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -268,7 +268,7 @@ int filename__read_build_id(const char *filename, void *bf, size_t size); int sysfs__read_build_id(const char *filename, void *bf, size_t size); int modules__parse(const char *filename, void *arg, int (*process_module)(void *arg, const char *name, - u64 start)); + u64 start, u64 size)); int filename__read_debuglink(const char *filename, char *debuglink, size_t size); diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index f5af87f66663..81aee5adc8a2 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -114,14 +114,24 @@ struct comm *thread__comm(const struct thread *thread) struct comm *thread__exec_comm(const struct thread *thread) { - struct comm *comm, *last = NULL; + struct comm *comm, *last = NULL, *second_last = NULL; list_for_each_entry(comm, &thread->comm_list, list) { if (comm->exec) return comm; + second_last = last; last = comm; } + /* + * 'last' with no start time might be the parent's comm of a synthesized + * thread (created by processing a synthesized fork event). For a main + * thread, that is very probably wrong. Prefer a later comm to avoid + * that case. + */ + if (second_last && !last->start && thread->pid_ == thread->tid) + return second_last; + return last; } diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index e72d370889f8..8b39e8086c2d 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -74,7 +74,6 @@ #include <sys/ttydefaults.h> #include <api/fs/tracing_path.h> #include <termios.h> -#include <linux/bitops.h> #include <termios.h> #include "strlist.h" |