summaryrefslogtreecommitdiff
path: root/tools/perf
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/Documentation/perf-config.txt2
-rw-r--r--tools/perf/Makefile2
-rw-r--r--tools/perf/arch/arm/util/cs-etm.c127
-rw-r--r--tools/perf/arch/s390/util/machine.c23
-rw-r--r--tools/perf/bench/numa.c10
-rw-r--r--tools/perf/builtin-help.c2
-rw-r--r--tools/perf/builtin-kmem.c1
-rw-r--r--tools/perf/builtin-probe.c10
-rw-r--r--tools/perf/builtin-report.c5
-rw-r--r--tools/perf/builtin-stat.c5
-rw-r--r--tools/perf/builtin-top.c5
-rwxr-xr-xtools/perf/check-headers.sh1
-rw-r--r--tools/perf/perf.h2
-rw-r--r--tools/perf/pmu-events/jevents.c11
-rw-r--r--tools/perf/tests/evsel-tp-sched.c7
-rw-r--r--tools/perf/tests/mmap-thread-lookup.c2
-rw-r--r--tools/perf/tests/openat-syscall-all-cpus.c4
-rw-r--r--tools/perf/tests/task-exit.c1
-rw-r--r--tools/perf/ui/browsers/hists.c1
-rw-r--r--tools/perf/ui/tui/helpline.c2
-rw-r--r--tools/perf/util/build-id.c1
-rw-r--r--tools/perf/util/config.c3
-rw-r--r--tools/perf/util/data-convert-bt.c2
-rw-r--r--tools/perf/util/dwarf-aux.c80
-rw-r--r--tools/perf/util/dwarf-aux.h3
-rw-r--r--tools/perf/util/evsel.c9
-rw-r--r--tools/perf/util/header.c15
-rw-r--r--tools/perf/util/hist.c6
-rw-r--r--tools/perf/util/hist.h4
-rw-r--r--tools/perf/util/intel-pt-decoder/intel-pt-decoder.c51
-rw-r--r--tools/perf/util/jitdump.c6
-rw-r--r--tools/perf/util/llvm-utils.c6
-rw-r--r--tools/perf/util/machine.c7
-rw-r--r--tools/perf/util/machine.h2
-rw-r--r--tools/perf/util/map.c5
-rw-r--r--tools/perf/util/parse-events.c1
-rw-r--r--tools/perf/util/perf_regs.h2
-rw-r--r--tools/perf/util/probe-finder.c80
-rw-r--r--tools/perf/util/stat.c17
-rw-r--r--tools/perf/util/stat.h1
-rw-r--r--tools/perf/util/strbuf.c1
-rw-r--r--tools/perf/util/symbol-elf.c2
-rw-r--r--tools/perf/util/symbol.c21
-rw-r--r--tools/perf/util/symbol.h2
-rw-r--r--tools/perf/util/thread.c12
-rw-r--r--tools/perf/util/util.h1
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"