mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2024-12-29 09:12:07 +00:00
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:
commit
8c25c44764
@ -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>
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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];
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
},
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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 */
|
||||
|
@ -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++)
|
||||
|
@ -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;
|
||||
|
@ -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))
|
||||
|
@ -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++;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user