perf tools fixes for v5.14: 1st batch

- Skip invalid hybrid PMU on hybrid systems when the atom (little) CPUs are offlined.
 
 - Fix 'perf test' problems related to the recently added hybrid (BIG/little) code.
 
 - Split ARM's coresight (hw tracing) decode by aux records to avoid fatal decoding errors.
 
 - Fix add event failure in 'perf probe' when running 32-bit perf in a 64-bit kernel.
 
 - Fix 'perf sched record' failure when CONFIG_SCHEDSTATS is not set.
 
 - Fix memory and refcount leaks detected by ASAn when running 'perf test', should be
   clean of warnings now.
 
 - Remove broken definition of __LITTLE_ENDIAN from tools' linux/kconfig.h, which was
   breaking the build in some systems.
 
 - Cast PTHREAD_STACK_MIN to int as it may turn into 'long sysconf(__SC_THREAD_STACK_MIN_VALUE),
   breaking the build in some systems.
 
 - Fix libperf build error with LIBPFM4=1.
 
 - Sync UAPI files changed by the memfd_secret new syscall.
 
 Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYIAB0WIQR2GiIUctdOfX2qHhGyPKLppCJ+JwUCYPR8OgAKCRCyPKLppCJ+
 J9vSAQDBCAvQiZQvOC8tgvUV8CIRorB/O43HOiX1pEUCVCdPRgEA0WGIbfjH3bMj
 zYOpXRpDag5iAVvn3DmpJ38laXJexQI=
 =0t/C
 -----END PGP SIGNATURE-----

Merge tag 'perf-tools-fixes-for-v5.14-2021-07-18' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux

Pull perf tools fixes from Arnaldo Carvalho de Melo:

 - Skip invalid hybrid PMU on hybrid systems when the atom (little) CPUs
   are offlined.

 - Fix 'perf test' problems related to the recently added hybrid
   (BIG/little) code.

 - Split ARM's coresight (hw tracing) decode by aux records to avoid
   fatal decoding errors.

 - Fix add event failure in 'perf probe' when running 32-bit perf in a
   64-bit kernel.

 - Fix 'perf sched record' failure when CONFIG_SCHEDSTATS is not set.

 - Fix memory and refcount leaks detected by ASAn when running 'perf
   test', should be clean of warnings now.

 - Remove broken definition of __LITTLE_ENDIAN from tools'
   linux/kconfig.h, which was breaking the build in some systems.

 - Cast PTHREAD_STACK_MIN to int as it may turn into 'long
   sysconf(__SC_THREAD_STACK_MIN_VALUE), breaking the build in some
   systems.

 - Fix libperf build error with LIBPFM4=1.

 - Sync UAPI files changed by the memfd_secret new syscall.

* tag 'perf-tools-fixes-for-v5.14-2021-07-18' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux: (35 commits)
  perf sched: Fix record failure when CONFIG_SCHEDSTATS is not set
  perf probe: Fix add event failure when running 32-bit perf in a 64-bit kernel
  perf data: Close all files in close_dir()
  perf probe-file: Delete namelist in del_events() on the error path
  perf test bpf: Free obj_buf
  perf trace: Free strings in trace__parse_events_option()
  perf trace: Free syscall tp fields in evsel->priv
  perf trace: Free syscall->arg_fmt
  perf trace: Free malloc'd trace fields on exit
  perf lzma: Close lzma stream on exit
  perf script: Fix memory 'threads' and 'cpus' leaks on exit
  perf script: Release zstd data
  perf session: Cleanup trace_event
  perf inject: Close inject.output on exit
  perf report: Free generated help strings for sort option
  perf env: Fix memory leak of cpu_pmu_caps
  perf test maps__merge_in: Fix memory leak of maps
  perf dso: Fix memory leak in dso__new_map()
  perf test event_update: Fix memory leak of unit
  perf test event_update: Fix memory leak of evlist
  ...
This commit is contained in:
Linus Torvalds 2021-07-18 12:20:27 -07:00
commit 8c25c44764
36 changed files with 391 additions and 98 deletions

View File

@ -20,5 +20,6 @@
#define __ARCH_WANT_SET_GET_RLIMIT
#define __ARCH_WANT_TIME32_SYSCALLS
#define __ARCH_WANT_SYS_CLONE3
#define __ARCH_WANT_MEMFD_SECRET
#include <asm-generic/unistd.h>

View File

@ -4,12 +4,6 @@
/* CONFIG_CC_VERSION_TEXT (Do not delete this comment. See help in Kconfig) */
#ifdef CONFIG_CPU_BIG_ENDIAN
#define __BIG_ENDIAN 4321
#else
#define __LITTLE_ENDIAN 1234
#endif
#define __ARG_PLACEHOLDER_1 0,
#define __take_second_arg(__ignored, val, ...) val

View File

@ -873,8 +873,13 @@ __SYSCALL(__NR_landlock_add_rule, sys_landlock_add_rule)
#define __NR_landlock_restrict_self 446
__SYSCALL(__NR_landlock_restrict_self, sys_landlock_restrict_self)
#ifdef __ARCH_WANT_MEMFD_SECRET
#define __NR_memfd_secret 447
__SYSCALL(__NR_memfd_secret, sys_memfd_secret)
#endif
#undef __NR_syscalls
#define __NR_syscalls 447
#define __NR_syscalls 448
/*
* 32 bit systems traditionally used different

View File

@ -368,6 +368,7 @@
444 common landlock_create_ruleset sys_landlock_create_ruleset
445 common landlock_add_rule sys_landlock_add_rule
446 common landlock_restrict_self sys_landlock_restrict_self
447 common memfd_secret sys_memfd_secret
#
# Due to a historical design error, certain syscalls are numbered differently

View File

@ -361,9 +361,10 @@ static struct dso *findnew_dso(int pid, int tid, const char *filename,
dso = machine__findnew_dso_id(machine, filename, id);
}
if (dso)
if (dso) {
nsinfo__put(dso->nsinfo);
dso->nsinfo = nsi;
else
} else
nsinfo__put(nsi);
thread__put(thread);
@ -992,8 +993,10 @@ int cmd_inject(int argc, const char **argv)
data.path = inject.input_name;
inject.session = perf_session__new(&data, inject.output.is_pipe, &inject.tool);
if (IS_ERR(inject.session))
return PTR_ERR(inject.session);
if (IS_ERR(inject.session)) {
ret = PTR_ERR(inject.session);
goto out_close_output;
}
if (zstd_init(&(inject.session->zstd_data), 0) < 0)
pr_warning("Decompression initialization failed.\n");
@ -1035,6 +1038,8 @@ int cmd_inject(int argc, const char **argv)
out_delete:
zstd_fini(&(inject.session->zstd_data));
perf_session__delete(inject.session);
out_close_output:
perf_data__close(&inject.output);
free(inject.itrace_synth_opts.vm_tm_corr_args);
return ret;
}

View File

@ -1175,6 +1175,8 @@ int cmd_report(int argc, const char **argv)
.annotation_opts = annotation__default_options,
.skip_empty = true,
};
char *sort_order_help = sort_help("sort by key(s):");
char *field_order_help = sort_help("output field(s): overhead period sample ");
const struct option options[] = {
OPT_STRING('i', "input", &input_name, "file",
"input file name"),
@ -1209,9 +1211,9 @@ int cmd_report(int argc, const char **argv)
OPT_BOOLEAN(0, "header-only", &report.header_only,
"Show only data header."),
OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
sort_help("sort by key(s):")),
sort_order_help),
OPT_STRING('F', "fields", &field_order, "key[,keys...]",
sort_help("output field(s): overhead period sample ")),
field_order_help),
OPT_BOOLEAN(0, "show-cpu-utilization", &symbol_conf.show_cpu_utilization,
"Show sample percentage for different cpu modes"),
OPT_BOOLEAN_FLAG(0, "showcpuutilization", &symbol_conf.show_cpu_utilization,
@ -1344,11 +1346,11 @@ int cmd_report(int argc, const char **argv)
char sort_tmp[128];
if (ret < 0)
return ret;
goto exit;
ret = perf_config(report__config, &report);
if (ret)
return ret;
goto exit;
argc = parse_options(argc, argv, options, report_usage, 0);
if (argc) {
@ -1362,8 +1364,10 @@ int cmd_report(int argc, const char **argv)
report.symbol_filter_str = argv[0];
}
if (annotate_check_args(&report.annotation_opts) < 0)
return -EINVAL;
if (annotate_check_args(&report.annotation_opts) < 0) {
ret = -EINVAL;
goto exit;
}
if (report.mmaps_mode)
report.tasks_mode = true;
@ -1377,12 +1381,14 @@ int cmd_report(int argc, const char **argv)
if (symbol_conf.vmlinux_name &&
access(symbol_conf.vmlinux_name, R_OK)) {
pr_err("Invalid file: %s\n", symbol_conf.vmlinux_name);
return -EINVAL;
ret = -EINVAL;
goto exit;
}
if (symbol_conf.kallsyms_name &&
access(symbol_conf.kallsyms_name, R_OK)) {
pr_err("Invalid file: %s\n", symbol_conf.kallsyms_name);
return -EINVAL;
ret = -EINVAL;
goto exit;
}
if (report.inverted_callchain)
@ -1406,12 +1412,14 @@ int cmd_report(int argc, const char **argv)
repeat:
session = perf_session__new(&data, false, &report.tool);
if (IS_ERR(session))
return PTR_ERR(session);
if (IS_ERR(session)) {
ret = PTR_ERR(session);
goto exit;
}
ret = evswitch__init(&report.evswitch, session->evlist, stderr);
if (ret)
return ret;
goto exit;
if (zstd_init(&(session->zstd_data), 0) < 0)
pr_warning("Decompression initialization failed. Reported data may be incomplete.\n");
@ -1646,5 +1654,8 @@ int cmd_report(int argc, const char **argv)
zstd_fini(&(session->zstd_data));
perf_session__delete(session);
exit:
free(sort_order_help);
free(field_order_help);
return ret;
}

View File

@ -670,7 +670,7 @@ static void create_tasks(struct perf_sched *sched)
err = pthread_attr_init(&attr);
BUG_ON(err);
err = pthread_attr_setstacksize(&attr,
(size_t) max(16 * 1024, PTHREAD_STACK_MIN));
(size_t) max(16 * 1024, (int)PTHREAD_STACK_MIN));
BUG_ON(err);
err = pthread_mutex_lock(&sched->start_work_mutex);
BUG_ON(err);
@ -3335,6 +3335,16 @@ static void setup_sorting(struct perf_sched *sched, const struct option *options
sort_dimension__add("pid", &sched->cmp_pid);
}
static bool schedstat_events_exposed(void)
{
/*
* Select "sched:sched_stat_wait" event to check
* whether schedstat tracepoints are exposed.
*/
return IS_ERR(trace_event__tp_format("sched", "sched_stat_wait")) ?
false : true;
}
static int __cmd_record(int argc, const char **argv)
{
unsigned int rec_argc, i, j;
@ -3346,21 +3356,33 @@ static int __cmd_record(int argc, const char **argv)
"-m", "1024",
"-c", "1",
"-e", "sched:sched_switch",
"-e", "sched:sched_stat_wait",
"-e", "sched:sched_stat_sleep",
"-e", "sched:sched_stat_iowait",
"-e", "sched:sched_stat_runtime",
"-e", "sched:sched_process_fork",
"-e", "sched:sched_wakeup_new",
"-e", "sched:sched_migrate_task",
};
/*
* The tracepoints trace_sched_stat_{wait, sleep, iowait}
* are not exposed to user if CONFIG_SCHEDSTATS is not set,
* to prevent "perf sched record" execution failure, determine
* whether to record schedstat events according to actual situation.
*/
const char * const schedstat_args[] = {
"-e", "sched:sched_stat_wait",
"-e", "sched:sched_stat_sleep",
"-e", "sched:sched_stat_iowait",
};
unsigned int schedstat_argc = schedstat_events_exposed() ?
ARRAY_SIZE(schedstat_args) : 0;
struct tep_event *waking_event;
/*
* +2 for either "-e", "sched:sched_wakeup" or
* "-e", "sched:sched_waking"
*/
rec_argc = ARRAY_SIZE(record_args) + 2 + argc - 1;
rec_argc = ARRAY_SIZE(record_args) + 2 + schedstat_argc + argc - 1;
rec_argv = calloc(rec_argc + 1, sizeof(char *));
if (rec_argv == NULL)
@ -3376,6 +3398,9 @@ static int __cmd_record(int argc, const char **argv)
else
rec_argv[i++] = strdup("sched:sched_wakeup");
for (j = 0; j < schedstat_argc; j++)
rec_argv[i++] = strdup(schedstat_args[j]);
for (j = 1; j < (unsigned int)argc; j++, i++)
rec_argv[i] = argv[j];

View File

@ -2601,6 +2601,12 @@ static void perf_script__exit_per_event_dump_stats(struct perf_script *script)
}
}
static void perf_script__exit(struct perf_script *script)
{
perf_thread_map__put(script->threads);
perf_cpu_map__put(script->cpus);
}
static int __cmd_script(struct perf_script *script)
{
int ret;
@ -4143,8 +4149,10 @@ int cmd_script(int argc, const char **argv)
zfree(&script.ptime_range);
}
zstd_fini(&(session->zstd_data));
evlist__free_stats(session->evlist);
perf_session__delete(session);
perf_script__exit(&script);
if (script_started)
cleanup_scripting();

View File

@ -2445,9 +2445,6 @@ int cmd_stat(int argc, const char **argv)
evlist__check_cpu_maps(evsel_list);
if (perf_pmu__has_hybrid())
stat_config.no_merge = true;
/*
* Initialize thread_map with comm names,
* so we could print it out on output.

View File

@ -2266,6 +2266,14 @@ static void *syscall__augmented_args(struct syscall *sc, struct perf_sample *sam
return augmented_args;
}
static void syscall__exit(struct syscall *sc)
{
if (!sc)
return;
free(sc->arg_fmt);
}
static int trace__sys_enter(struct trace *trace, struct evsel *evsel,
union perf_event *event __maybe_unused,
struct perf_sample *sample)
@ -3095,6 +3103,21 @@ static struct evsel *evsel__new_pgfault(u64 config)
return evsel;
}
static void evlist__free_syscall_tp_fields(struct evlist *evlist)
{
struct evsel *evsel;
evlist__for_each_entry(evlist, evsel) {
struct evsel_trace *et = evsel->priv;
if (!et || !evsel->tp_format || strcmp(evsel->tp_format->system, "syscalls"))
continue;
free(et->fmt);
free(et);
}
}
static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
{
const u32 type = event->header.type;
@ -4130,7 +4153,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
out_delete_evlist:
trace__symbols__exit(trace);
evlist__free_syscall_tp_fields(evlist);
evlist__delete(evlist);
cgroup__put(trace->cgroup);
trace->evlist = NULL;
@ -4636,6 +4659,9 @@ static int trace__parse_events_option(const struct option *opt, const char *str,
err = parse_events_option(&o, lists[0], 0);
}
out:
free(strace_groups_dir);
free(lists[0]);
free(lists[1]);
if (sep)
*sep = ',';
@ -4701,6 +4727,21 @@ static int trace__config(const char *var, const char *value, void *arg)
return err;
}
static void trace__exit(struct trace *trace)
{
int i;
strlist__delete(trace->ev_qualifier);
free(trace->ev_qualifier_ids.entries);
if (trace->syscalls.table) {
for (i = 0; i <= trace->sctbl->syscalls.max_id; i++)
syscall__exit(&trace->syscalls.table[i]);
free(trace->syscalls.table);
}
syscalltbl__delete(trace->sctbl);
zfree(&trace->perfconfig_events);
}
int cmd_trace(int argc, const char **argv)
{
const char *trace_usage[] = {
@ -5135,6 +5176,6 @@ int cmd_trace(int argc, const char **argv)
if (output_name != NULL)
fclose(trace.output);
out:
zfree(&trace.perfconfig_events);
trace__exit(&trace);
return err;
}

View File

@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/epoll.h>
#include <sys/types.h>
#include <sys/stat.h>
@ -276,6 +277,7 @@ static int __test__bpf(int idx)
}
out:
free(obj_buf);
bpf__clear();
return ret;
}

View File

@ -88,6 +88,7 @@ int test__event_update(struct test *test __maybe_unused, int subtest __maybe_unu
struct evsel *evsel;
struct event_name tmp;
struct evlist *evlist = evlist__new_default();
char *unit = strdup("KRAVA");
TEST_ASSERT_VAL("failed to get evlist", evlist);
@ -98,7 +99,7 @@ int test__event_update(struct test *test __maybe_unused, int subtest __maybe_unu
perf_evlist__id_add(&evlist->core, &evsel->core, 0, 0, 123);
evsel->unit = strdup("KRAVA");
evsel->unit = unit;
TEST_ASSERT_VAL("failed to synthesize attr update unit",
!perf_event__synthesize_event_update_unit(NULL, evsel, process_event_unit));
@ -118,6 +119,7 @@ int test__event_update(struct test *test __maybe_unused, int subtest __maybe_unu
TEST_ASSERT_VAL("failed to synthesize attr update cpus",
!perf_event__synthesize_event_update_cpus(&tmp.tool, evsel, process_event_cpus));
perf_cpu_map__put(evsel->core.own_cpus);
free(unit);
evlist__delete(evlist);
return 0;
}

View File

@ -5,6 +5,7 @@
#include "tests.h"
#include "debug.h"
#include "pmu.h"
#include "pmu-hybrid.h"
#include <errno.h>
#include <linux/kernel.h>
@ -102,7 +103,7 @@ int test__perf_evsel__roundtrip_name_test(struct test *test __maybe_unused, int
{
int err = 0, ret = 0;
if (perf_pmu__has_hybrid())
if (perf_pmu__has_hybrid() && perf_pmu__hybrid_mounted("cpu_atom"))
return perf_evsel__name_array_test(evsel__hw_names, 2);
err = perf_evsel__name_array_test(evsel__hw_names, 1);

View File

@ -116,5 +116,7 @@ int test__maps__merge_in(struct test *t __maybe_unused, int subtest __maybe_unus
ret = check_maps(merged3, ARRAY_SIZE(merged3), &maps);
TEST_ASSERT_VAL("merge check failed", !ret);
maps__exit(&maps);
return TEST_OK;
}

View File

@ -6,6 +6,7 @@
#include "tests.h"
#include "debug.h"
#include "pmu.h"
#include "pmu-hybrid.h"
#include <dirent.h>
#include <errno.h>
#include <sys/types.h>
@ -1596,6 +1597,13 @@ static int test__hybrid_raw1(struct evlist *evlist)
{
struct evsel *evsel = evlist__first(evlist);
if (!perf_pmu__hybrid_mounted("cpu_atom")) {
TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries);
TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type);
TEST_ASSERT_VAL("wrong config", 0x1a == evsel->core.attr.config);
return 0;
}
TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries);
TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type);
TEST_ASSERT_VAL("wrong config", 0x1a == evsel->core.attr.config);
@ -1620,13 +1628,9 @@ static int test__hybrid_cache_event(struct evlist *evlist)
{
struct evsel *evsel = evlist__first(evlist);
TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries);
TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries);
TEST_ASSERT_VAL("wrong type", PERF_TYPE_HW_CACHE == evsel->core.attr.type);
TEST_ASSERT_VAL("wrong config", 0x2 == (evsel->core.attr.config & 0xffffffff));
evsel = evsel__next(evsel);
TEST_ASSERT_VAL("wrong type", PERF_TYPE_HW_CACHE == evsel->core.attr.type);
TEST_ASSERT_VAL("wrong config", 0x10002 == (evsel->core.attr.config & 0xffffffff));
return 0;
}
@ -2028,7 +2032,7 @@ static struct evlist_test test__hybrid_events[] = {
.id = 7,
},
{
.name = "cpu_core/LLC-loads/,cpu_atom/LLC-load-misses/",
.name = "cpu_core/LLC-loads/",
.check = test__hybrid_cache_event,
.id = 8,
},

View File

@ -21,6 +21,7 @@
#include "mmap.h"
#include "tests.h"
#include "pmu.h"
#include "pmu-hybrid.h"
#define CHECK__(x) { \
while ((x) < 0) { \
@ -93,7 +94,7 @@ int test__perf_time_to_tsc(struct test *test __maybe_unused, int subtest __maybe
* For hybrid "cycles:u", it creates two events.
* Init the second evsel here.
*/
if (perf_pmu__has_hybrid()) {
if (perf_pmu__has_hybrid() && perf_pmu__hybrid_mounted("cpu_atom")) {
evsel = evsel__next(evsel);
evsel->core.attr.comm = 1;
evsel->core.attr.disabled = 1;

View File

@ -61,6 +61,7 @@ static int session_write_header(char *path)
TEST_ASSERT_VAL("failed to write header",
!perf_session__write_header(session, session->evlist, data.file.fd, true));
evlist__delete(session->evlist);
perf_session__delete(session);
return 0;

View File

@ -2683,6 +2683,172 @@ static u64 *cs_etm__create_meta_blk(u64 *buff_in, int *buff_in_offset,
return metadata;
}
/**
* Puts a fragment of an auxtrace buffer into the auxtrace queues based
* on the bounds of aux_event, if it matches with the buffer that's at
* file_offset.
*
* Normally, whole auxtrace buffers would be added to the queue. But we
* want to reset the decoder for every PERF_RECORD_AUX event, and the decoder
* is reset across each buffer, so splitting the buffers up in advance has
* the same effect.
*/
static int cs_etm__queue_aux_fragment(struct perf_session *session, off_t file_offset, size_t sz,
struct perf_record_aux *aux_event, struct perf_sample *sample)
{
int err;
char buf[PERF_SAMPLE_MAX_SIZE];
union perf_event *auxtrace_event_union;
struct perf_record_auxtrace *auxtrace_event;
union perf_event auxtrace_fragment;
__u64 aux_offset, aux_size;
struct cs_etm_auxtrace *etm = container_of(session->auxtrace,
struct cs_etm_auxtrace,
auxtrace);
/*
* There should be a PERF_RECORD_AUXTRACE event at the file_offset that we got
* from looping through the auxtrace index.
*/
err = perf_session__peek_event(session, file_offset, buf,
PERF_SAMPLE_MAX_SIZE, &auxtrace_event_union, NULL);
if (err)
return err;
auxtrace_event = &auxtrace_event_union->auxtrace;
if (auxtrace_event->header.type != PERF_RECORD_AUXTRACE)
return -EINVAL;
if (auxtrace_event->header.size < sizeof(struct perf_record_auxtrace) ||
auxtrace_event->header.size != sz) {
return -EINVAL;
}
/*
* In per-thread mode, CPU is set to -1, but TID will be set instead. See
* auxtrace_mmap_params__set_idx(). Return 'not found' if neither CPU nor TID match.
*/
if ((auxtrace_event->cpu == (__u32) -1 && auxtrace_event->tid != sample->tid) ||
auxtrace_event->cpu != sample->cpu)
return 1;
if (aux_event->flags & PERF_AUX_FLAG_OVERWRITE) {
/*
* Clamp size in snapshot mode. The buffer size is clamped in
* __auxtrace_mmap__read() for snapshots, so the aux record size doesn't reflect
* the buffer size.
*/
aux_size = min(aux_event->aux_size, auxtrace_event->size);
/*
* In this mode, the head also points to the end of the buffer so aux_offset
* needs to have the size subtracted so it points to the beginning as in normal mode
*/
aux_offset = aux_event->aux_offset - aux_size;
} else {
aux_size = aux_event->aux_size;
aux_offset = aux_event->aux_offset;
}
if (aux_offset >= auxtrace_event->offset &&
aux_offset + aux_size <= auxtrace_event->offset + auxtrace_event->size) {
/*
* If this AUX event was inside this buffer somewhere, create a new auxtrace event
* based on the sizes of the aux event, and queue that fragment.
*/
auxtrace_fragment.auxtrace = *auxtrace_event;
auxtrace_fragment.auxtrace.size = aux_size;
auxtrace_fragment.auxtrace.offset = aux_offset;
file_offset += aux_offset - auxtrace_event->offset + auxtrace_event->header.size;
pr_debug3("CS ETM: Queue buffer size: %#"PRI_lx64" offset: %#"PRI_lx64
" tid: %d cpu: %d\n", aux_size, aux_offset, sample->tid, sample->cpu);
return auxtrace_queues__add_event(&etm->queues, session, &auxtrace_fragment,
file_offset, NULL);
}
/* Wasn't inside this buffer, but there were no parse errors. 1 == 'not found' */
return 1;
}
static int cs_etm__queue_aux_records_cb(struct perf_session *session, union perf_event *event,
u64 offset __maybe_unused, void *data __maybe_unused)
{
struct perf_sample sample;
int ret;
struct auxtrace_index_entry *ent;
struct auxtrace_index *auxtrace_index;
struct evsel *evsel;
size_t i;
/* Don't care about any other events, we're only queuing buffers for AUX events */
if (event->header.type != PERF_RECORD_AUX)
return 0;
if (event->header.size < sizeof(struct perf_record_aux))
return -EINVAL;
/* Truncated Aux records can have 0 size and shouldn't result in anything being queued. */
if (!event->aux.aux_size)
return 0;
/*
* Parse the sample, we need the sample_id_all data that comes after the event so that the
* CPU or PID can be matched to an AUXTRACE buffer's CPU or PID.
*/
evsel = evlist__event2evsel(session->evlist, event);
if (!evsel)
return -EINVAL;
ret = evsel__parse_sample(evsel, event, &sample);
if (ret)
return ret;
/*
* Loop through the auxtrace index to find the buffer that matches up with this aux event.
*/
list_for_each_entry(auxtrace_index, &session->auxtrace_index, list) {
for (i = 0; i < auxtrace_index->nr; i++) {
ent = &auxtrace_index->entries[i];
ret = cs_etm__queue_aux_fragment(session, ent->file_offset,
ent->sz, &event->aux, &sample);
/*
* Stop search on error or successful values. Continue search on
* 1 ('not found')
*/
if (ret != 1)
return ret;
}
}
/*
* Couldn't find the buffer corresponding to this aux record, something went wrong. Warn but
* don't exit with an error because it will still be possible to decode other aux records.
*/
pr_err("CS ETM: Couldn't find auxtrace buffer for aux_offset: %#"PRI_lx64
" tid: %d cpu: %d\n", event->aux.aux_offset, sample.tid, sample.cpu);
return 0;
}
static int cs_etm__queue_aux_records(struct perf_session *session)
{
struct auxtrace_index *index = list_first_entry_or_null(&session->auxtrace_index,
struct auxtrace_index, list);
if (index && index->nr > 0)
return perf_session__peek_events(session, session->header.data_offset,
session->header.data_size,
cs_etm__queue_aux_records_cb, NULL);
/*
* We would get here if there are no entries in the index (either no auxtrace
* buffers or no index at all). Fail silently as there is the possibility of
* queueing them in cs_etm__process_auxtrace_event() if etm->data_queued is still
* false.
*
* In that scenario, buffers will not be split by AUX records.
*/
return 0;
}
int cs_etm__process_auxtrace_info(union perf_event *event,
struct perf_session *session)
{
@ -2883,7 +3049,7 @@ int cs_etm__process_auxtrace_info(union perf_event *event,
if (err)
goto err_delete_thread;
err = auxtrace_queues__process_index(&etm->queues, session);
err = cs_etm__queue_aux_records(session);
if (err)
goto err_delete_thread;

View File

@ -20,7 +20,7 @@
static void close_dir(struct perf_data_file *files, int nr)
{
while (--nr >= 1) {
while (--nr >= 0) {
close(files[nr].fd);
zfree(&files[nr].path);
}

View File

@ -1154,8 +1154,10 @@ struct map *dso__new_map(const char *name)
struct map *map = NULL;
struct dso *dso = dso__new(name);
if (dso)
if (dso) {
map = map__new2(0, dso);
dso__put(dso);
}
return map;
}

View File

@ -113,14 +113,14 @@ static Dwarf_Line *cu_getsrc_die(Dwarf_Die *cu_die, Dwarf_Addr addr)
*
* Find a line number and file name for @addr in @cu_die.
*/
int cu_find_lineinfo(Dwarf_Die *cu_die, unsigned long addr,
const char **fname, int *lineno)
int cu_find_lineinfo(Dwarf_Die *cu_die, Dwarf_Addr addr,
const char **fname, int *lineno)
{
Dwarf_Line *line;
Dwarf_Die die_mem;
Dwarf_Addr faddr;
if (die_find_realfunc(cu_die, (Dwarf_Addr)addr, &die_mem)
if (die_find_realfunc(cu_die, addr, &die_mem)
&& die_entrypc(&die_mem, &faddr) == 0 &&
faddr == addr) {
*fname = dwarf_decl_file(&die_mem);
@ -128,7 +128,7 @@ int cu_find_lineinfo(Dwarf_Die *cu_die, unsigned long addr,
goto out;
}
line = cu_getsrc_die(cu_die, (Dwarf_Addr)addr);
line = cu_getsrc_die(cu_die, addr);
if (line && dwarf_lineno(line, lineno) == 0) {
*fname = dwarf_linesrc(line, NULL, NULL);
if (!*fname)

View File

@ -19,7 +19,7 @@ const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname);
const char *cu_get_comp_dir(Dwarf_Die *cu_die);
/* Get a line number and file name for given address */
int cu_find_lineinfo(Dwarf_Die *cudie, unsigned long addr,
int cu_find_lineinfo(Dwarf_Die *cudie, Dwarf_Addr addr,
const char **fname, int *lineno);
/* Walk on functions at given address */

View File

@ -186,10 +186,12 @@ void perf_env__exit(struct perf_env *env)
zfree(&env->cpuid);
zfree(&env->cmdline);
zfree(&env->cmdline_argv);
zfree(&env->sibling_dies);
zfree(&env->sibling_cores);
zfree(&env->sibling_threads);
zfree(&env->pmu_mappings);
zfree(&env->cpu);
zfree(&env->cpu_pmu_caps);
zfree(&env->numa_map);
for (i = 0; i < env->nr_numa_nodes; i++)

View File

@ -69,7 +69,7 @@ int lzma_decompress_to_file(const char *input, int output_fd)
if (ferror(infile)) {
pr_err("lzma: read error: %s\n", strerror(errno));
goto err_fclose;
goto err_lzma_end;
}
if (feof(infile))
@ -83,7 +83,7 @@ int lzma_decompress_to_file(const char *input, int output_fd)
if (writen(output_fd, buf_out, write_size) != write_size) {
pr_err("lzma: write error: %s\n", strerror(errno));
goto err_fclose;
goto err_lzma_end;
}
strm.next_out = buf_out;
@ -95,11 +95,13 @@ int lzma_decompress_to_file(const char *input, int output_fd)
break;
pr_err("lzma: failed %s\n", lzma_strerror(ret));
goto err_fclose;
goto err_lzma_end;
}
}
err = 0;
err_lzma_end:
lzma_end(&strm);
err_fclose:
fclose(infile);
return err;

View File

@ -192,6 +192,8 @@ struct map *map__new(struct machine *machine, u64 start, u64 len,
if (!(prot & PROT_EXEC))
dso__set_loaded(dso);
}
nsinfo__put(dso->nsinfo);
dso->nsinfo = nsi;
if (build_id__is_defined(bid))

View File

@ -99,7 +99,7 @@ int parse_libpfm_events_option(const struct option *opt, const char *str,
grp_leader = evsel;
if (grp_evt > -1) {
evsel->leader = grp_leader;
evsel__set_leader(evsel, grp_leader);
grp_leader->core.nr_members++;
grp_evt++;
}

View File

@ -950,6 +950,13 @@ static struct perf_pmu *pmu_lookup(const char *name)
LIST_HEAD(format);
LIST_HEAD(aliases);
__u32 type;
bool is_hybrid = perf_pmu__hybrid_mounted(name);
/*
* Check pmu name for hybrid and the pmu may be invalid in sysfs
*/
if (!strncmp(name, "cpu_", 4) && !is_hybrid)
return NULL;
/*
* The pmu data we store & need consists of the pmu
@ -978,7 +985,7 @@ static struct perf_pmu *pmu_lookup(const char *name)
pmu->is_uncore = pmu_is_uncore(name);
if (pmu->is_uncore)
pmu->id = pmu_id(name);
pmu->is_hybrid = perf_pmu__hybrid_mounted(name);
pmu->is_hybrid = is_hybrid;
pmu->max_precise = pmu_max_precise(name);
pmu_add_cpu_aliases(&aliases, pmu);
pmu_add_sys_aliases(&aliases, pmu);

View File

@ -179,8 +179,10 @@ struct map *get_target_map(const char *target, struct nsinfo *nsi, bool user)
struct map *map;
map = dso__new_map(target);
if (map && map->dso)
if (map && map->dso) {
nsinfo__put(map->dso->nsinfo);
map->dso->nsinfo = nsinfo__get(nsi);
}
return map;
} else {
return kernel_get_module_map(target);
@ -237,8 +239,8 @@ static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs)
clear_probe_trace_event(tevs + i);
}
static bool kprobe_blacklist__listed(unsigned long address);
static bool kprobe_warn_out_range(const char *symbol, unsigned long address)
static bool kprobe_blacklist__listed(u64 address);
static bool kprobe_warn_out_range(const char *symbol, u64 address)
{
struct map *map;
bool ret = false;
@ -398,8 +400,7 @@ static int find_alternative_probe_point(struct debuginfo *dinfo,
pr_debug("Symbol %s address found : %" PRIx64 "\n",
pp->function, address);
ret = debuginfo__find_probe_point(dinfo, (unsigned long)address,
result);
ret = debuginfo__find_probe_point(dinfo, address, result);
if (ret <= 0)
ret = (!ret) ? -ENOENT : ret;
else {
@ -587,7 +588,7 @@ static void debuginfo_cache__exit(void)
}
static int get_text_start_address(const char *exec, unsigned long *address,
static int get_text_start_address(const char *exec, u64 *address,
struct nsinfo *nsi)
{
Elf *elf;
@ -632,7 +633,7 @@ static int find_perf_probe_point_from_dwarf(struct probe_trace_point *tp,
bool is_kprobe)
{
struct debuginfo *dinfo = NULL;
unsigned long stext = 0;
u64 stext = 0;
u64 addr = tp->address;
int ret = -ENOENT;
@ -660,8 +661,7 @@ static int find_perf_probe_point_from_dwarf(struct probe_trace_point *tp,
dinfo = debuginfo_cache__open(tp->module, verbose <= 0);
if (dinfo)
ret = debuginfo__find_probe_point(dinfo,
(unsigned long)addr, pp);
ret = debuginfo__find_probe_point(dinfo, addr, pp);
else
ret = -ENOENT;
@ -676,7 +676,7 @@ static int find_perf_probe_point_from_dwarf(struct probe_trace_point *tp,
/* Adjust symbol name and address */
static int post_process_probe_trace_point(struct probe_trace_point *tp,
struct map *map, unsigned long offs)
struct map *map, u64 offs)
{
struct symbol *sym;
u64 addr = tp->address - offs;
@ -719,7 +719,7 @@ post_process_offline_probe_trace_events(struct probe_trace_event *tevs,
int ntevs, const char *pathname)
{
struct map *map;
unsigned long stext = 0;
u64 stext = 0;
int i, ret = 0;
/* Prepare a map for offline binary */
@ -745,7 +745,7 @@ static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs,
struct nsinfo *nsi)
{
int i, ret = 0;
unsigned long stext = 0;
u64 stext = 0;
if (!exec)
return 0;
@ -790,7 +790,7 @@ post_process_module_probe_trace_events(struct probe_trace_event *tevs,
mod_name = find_module_name(module);
for (i = 0; i < ntevs; i++) {
ret = post_process_probe_trace_point(&tevs[i].point,
map, (unsigned long)text_offs);
map, text_offs);
if (ret < 0)
break;
tevs[i].point.module =
@ -1534,7 +1534,7 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
* so tmp[1] should always valid (but could be '\0').
*/
if (tmp && !strncmp(tmp, "0x", 2)) {
pp->abs_address = strtoul(pp->function, &tmp, 0);
pp->abs_address = strtoull(pp->function, &tmp, 0);
if (*tmp != '\0') {
semantic_error("Invalid absolute address.\n");
return -EINVAL;
@ -1909,7 +1909,7 @@ int parse_probe_trace_command(const char *cmd, struct probe_trace_event *tev)
argv[i] = NULL;
argc -= 1;
} else
tp->address = strtoul(fmt1_str, NULL, 0);
tp->address = strtoull(fmt1_str, NULL, 0);
} else {
/* Only the symbol-based probe has offset */
tp->symbol = strdup(fmt1_str);
@ -2155,7 +2155,7 @@ synthesize_uprobe_trace_def(struct probe_trace_point *tp, struct strbuf *buf)
return -EINVAL;
/* Use the tp->address for uprobes */
err = strbuf_addf(buf, "%s:0x%lx", tp->module, tp->address);
err = strbuf_addf(buf, "%s:0x%" PRIx64, tp->module, tp->address);
if (err >= 0 && tp->ref_ctr_offset) {
if (!uprobe_ref_ctr_is_supported())
@ -2170,7 +2170,7 @@ synthesize_kprobe_trace_def(struct probe_trace_point *tp, struct strbuf *buf)
{
if (!strncmp(tp->symbol, "0x", 2)) {
/* Absolute address. See try_to_find_absolute_address() */
return strbuf_addf(buf, "%s%s0x%lx", tp->module ?: "",
return strbuf_addf(buf, "%s%s0x%" PRIx64, tp->module ?: "",
tp->module ? ":" : "", tp->address);
} else {
return strbuf_addf(buf, "%s%s%s+%lu", tp->module ?: "",
@ -2269,7 +2269,7 @@ static int convert_to_perf_probe_point(struct probe_trace_point *tp,
pp->function = strdup(tp->symbol);
pp->offset = tp->offset;
} else {
ret = e_snprintf(buf, 128, "0x%" PRIx64, (u64)tp->address);
ret = e_snprintf(buf, 128, "0x%" PRIx64, tp->address);
if (ret < 0)
return ret;
pp->function = strdup(buf);
@ -2450,8 +2450,8 @@ void clear_probe_trace_event(struct probe_trace_event *tev)
struct kprobe_blacklist_node {
struct list_head list;
unsigned long start;
unsigned long end;
u64 start;
u64 end;
char *symbol;
};
@ -2496,7 +2496,7 @@ static int kprobe_blacklist__load(struct list_head *blacklist)
}
INIT_LIST_HEAD(&node->list);
list_add_tail(&node->list, blacklist);
if (sscanf(buf, "0x%lx-0x%lx", &node->start, &node->end) != 2) {
if (sscanf(buf, "0x%" PRIx64 "-0x%" PRIx64, &node->start, &node->end) != 2) {
ret = -EINVAL;
break;
}
@ -2512,7 +2512,7 @@ static int kprobe_blacklist__load(struct list_head *blacklist)
ret = -ENOMEM;
break;
}
pr_debug2("Blacklist: 0x%lx-0x%lx, %s\n",
pr_debug2("Blacklist: 0x%" PRIx64 "-0x%" PRIx64 ", %s\n",
node->start, node->end, node->symbol);
ret++;
}
@ -2524,8 +2524,7 @@ static int kprobe_blacklist__load(struct list_head *blacklist)
}
static struct kprobe_blacklist_node *
kprobe_blacklist__find_by_address(struct list_head *blacklist,
unsigned long address)
kprobe_blacklist__find_by_address(struct list_head *blacklist, u64 address)
{
struct kprobe_blacklist_node *node;
@ -2553,7 +2552,7 @@ static void kprobe_blacklist__release(void)
kprobe_blacklist__delete(&kprobe_blacklist);
}
static bool kprobe_blacklist__listed(unsigned long address)
static bool kprobe_blacklist__listed(u64 address)
{
return !!kprobe_blacklist__find_by_address(&kprobe_blacklist, address);
}
@ -3221,7 +3220,7 @@ static int try_to_find_absolute_address(struct perf_probe_event *pev,
* In __add_probe_trace_events, a NULL symbol is interpreted as
* invalid.
*/
if (asprintf(&tp->symbol, "0x%lx", tp->address) < 0)
if (asprintf(&tp->symbol, "0x%" PRIx64, tp->address) < 0)
goto errout;
/* For kprobe, check range */
@ -3232,7 +3231,7 @@ static int try_to_find_absolute_address(struct perf_probe_event *pev,
goto errout;
}
if (asprintf(&tp->realname, "abs_%lx", tp->address) < 0)
if (asprintf(&tp->realname, "abs_%" PRIx64, tp->address) < 0)
goto errout;
if (pev->target) {

View File

@ -33,7 +33,7 @@ struct probe_trace_point {
char *module; /* Module name */
unsigned long offset; /* Offset from symbol */
unsigned long ref_ctr_offset; /* SDT reference counter offset */
unsigned long address; /* Actual address of the trace point */
u64 address; /* Actual address of the trace point */
bool retprobe; /* Return probe flag */
};
@ -70,7 +70,7 @@ struct perf_probe_point {
bool retprobe; /* Return probe flag */
char *lazy_line; /* Lazy matching pattern */
unsigned long offset; /* Offset from function entry */
unsigned long abs_address; /* Absolute address of the point */
u64 abs_address; /* Absolute address of the point */
};
/* Perf probe probing argument field chain */

View File

@ -377,11 +377,11 @@ int probe_file__del_events(int fd, struct strfilter *filter)
ret = probe_file__get_events(fd, filter, namelist);
if (ret < 0)
return ret;
goto out;
ret = probe_file__del_strlist(fd, namelist);
out:
strlist__delete(namelist);
return ret;
}

View File

@ -668,7 +668,7 @@ static int convert_to_trace_point(Dwarf_Die *sp_die, Dwfl_Module *mod,
}
tp->offset = (unsigned long)(paddr - eaddr);
tp->address = (unsigned long)paddr;
tp->address = paddr;
tp->symbol = strdup(symbol);
if (!tp->symbol)
return -ENOMEM;
@ -1707,7 +1707,7 @@ int debuginfo__get_text_offset(struct debuginfo *dbg, Dwarf_Addr *offs,
}
/* Reverse search */
int debuginfo__find_probe_point(struct debuginfo *dbg, unsigned long addr,
int debuginfo__find_probe_point(struct debuginfo *dbg, u64 addr,
struct perf_probe_point *ppt)
{
Dwarf_Die cudie, spdie, indie;
@ -1720,14 +1720,14 @@ int debuginfo__find_probe_point(struct debuginfo *dbg, unsigned long addr,
addr += baseaddr;
/* Find cu die */
if (!dwarf_addrdie(dbg->dbg, (Dwarf_Addr)addr, &cudie)) {
pr_warning("Failed to find debug information for address %lx\n",
pr_warning("Failed to find debug information for address %" PRIx64 "\n",
addr);
ret = -EINVAL;
goto end;
}
/* Find a corresponding line (filename and lineno) */
cu_find_lineinfo(&cudie, addr, &fname, &lineno);
cu_find_lineinfo(&cudie, (Dwarf_Addr)addr, &fname, &lineno);
/* Don't care whether it failed or not */
/* Find a corresponding function (name, baseline and baseaddr) */
@ -1742,7 +1742,7 @@ int debuginfo__find_probe_point(struct debuginfo *dbg, unsigned long addr,
}
fname = dwarf_decl_file(&spdie);
if (addr == (unsigned long)baseaddr) {
if (addr == baseaddr) {
/* Function entry - Relative line number is 0 */
lineno = baseline;
goto post;
@ -1788,7 +1788,7 @@ int debuginfo__find_probe_point(struct debuginfo *dbg, unsigned long addr,
if (lineno)
ppt->line = lineno - baseline;
else if (basefunc) {
ppt->offset = addr - (unsigned long)baseaddr;
ppt->offset = addr - baseaddr;
func = basefunc;
}
@ -1828,8 +1828,7 @@ static int line_range_add_line(const char *src, unsigned int lineno,
}
static int line_range_walk_cb(const char *fname, int lineno,
Dwarf_Addr addr __maybe_unused,
void *data)
Dwarf_Addr addr, void *data)
{
struct line_finder *lf = data;
const char *__fname;

View File

@ -46,7 +46,7 @@ int debuginfo__find_trace_events(struct debuginfo *dbg,
struct probe_trace_event **tevs);
/* Find a perf_probe_point from debuginfo */
int debuginfo__find_probe_point(struct debuginfo *dbg, unsigned long addr,
int debuginfo__find_probe_point(struct debuginfo *dbg, u64 addr,
struct perf_probe_point *ppt);
int debuginfo__get_text_offset(struct debuginfo *dbg, Dwarf_Addr *offs,

View File

@ -306,6 +306,7 @@ void perf_session__delete(struct perf_session *session)
evlist__delete(session->evlist);
perf_data__close(session->data);
}
trace_event__cleanup(&session->tevent);
free(session);
}

View File

@ -3370,7 +3370,7 @@ static void add_hpp_sort_string(struct strbuf *sb, struct hpp_dimension *s, int
add_key(sb, s[i].name, llen);
}
const char *sort_help(const char *prefix)
char *sort_help(const char *prefix)
{
struct strbuf sb;
char *s;

View File

@ -302,7 +302,7 @@ void reset_output_field(void);
void sort__setup_elide(FILE *fp);
void perf_hpp__set_elide(int idx, bool elide);
const char *sort_help(const char *prefix);
char *sort_help(const char *prefix);
int report_parse_ignore_callees_opt(const struct option *opt, const char *arg, int unset);

View File

@ -596,6 +596,18 @@ static void collect_all_aliases(struct perf_stat_config *config, struct evsel *c
}
}
static bool is_uncore(struct evsel *evsel)
{
struct perf_pmu *pmu = evsel__find_pmu(evsel);
return pmu && pmu->is_uncore;
}
static bool hybrid_uniquify(struct evsel *evsel)
{
return perf_pmu__has_hybrid() && !is_uncore(evsel);
}
static bool collect_data(struct perf_stat_config *config, struct evsel *counter,
void (*cb)(struct perf_stat_config *config, struct evsel *counter, void *data,
bool first),
@ -604,7 +616,7 @@ static bool collect_data(struct perf_stat_config *config, struct evsel *counter,
if (counter->merged_stat)
return false;
cb(config, counter, data, true);
if (config->no_merge)
if (config->no_merge || hybrid_uniquify(counter))
uniquify_event_name(counter);
else if (counter->auto_merge_stats)
collect_all_aliases(config, counter, cb, data);