perf tools fixes for v5.17: 2nd batch
- Fix corrupt inject files when only last branch option is enabled with ARM CoreSight ETM. - Fix use-after-free for realloc(..., 0) in libsubcmd, found by gcc 12. - Defer freeing string after possible strlen() on it in the BPF loader, found by gcc 12. - Avoid early exit in 'perf trace' due SIGCHLD from non-workload processes. - Fix arm64 perf_event_attr 'perf test's wrt --call-graph initialization. - Fix libperf 32-bit build for 'perf test' wrt uint64_t printf. - Fix perf_cpu_map__for_each_cpu macro in libperf, providing access to the CPU iterator. - Sync linux/perf_event.h UAPI with the kernel sources. - Update Jiri Olsa's email address in MAINTAINERS. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> -----BEGIN PGP SIGNATURE----- iHUEABYKAB0WIQR2GiIUctdOfX2qHhGyPKLppCJ+JwUCYg5q1gAKCRCyPKLppCJ+ JxbAAP9P7iIQuXecNop1ye4eLsWHYhBAJPSJdvUHwqpwGRm8HQEA2r+2tRtBcbei 3qgOY0od4Xtw1yji1YmTeQ6jmKFuMQM= =c5Ce -----END PGP SIGNATURE----- Merge tag 'perf-tools-fixes-for-v5.17-2022-02-17' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux Pull perf tools fixes from Arnaldo Carvalho de Melo: - Fix corrupt inject files when only last branch option is enabled with ARM CoreSight ETM - Fix use-after-free for realloc(..., 0) in libsubcmd, found by gcc 12 - Defer freeing string after possible strlen() on it in the BPF loader, found by gcc 12 - Avoid early exit in 'perf trace' due SIGCHLD from non-workload processes - Fix arm64 perf_event_attr 'perf test's wrt --call-graph initialization - Fix libperf 32-bit build for 'perf test' wrt uint64_t printf - Fix perf_cpu_map__for_each_cpu macro in libperf, providing access to the CPU iterator - Sync linux/perf_event.h UAPI with the kernel sources - Update Jiri Olsa's email address in MAINTAINERS * tag 'perf-tools-fixes-for-v5.17-2022-02-17' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux: perf bpf: Defer freeing string after possible strlen() on it perf test: Fix arm64 perf_event_attr tests wrt --call-graph initialization libsubcmd: Fix use-after-free for realloc(..., 0) libperf: Fix perf_cpu_map__for_each_cpu macro perf cs-etm: Fix corrupt inject files when only last branch option is enabled perf cs-etm: No-op refactor of synth opt usage libperf: Fix 32-bit build for tests uint64_t printf tools headers UAPI: Sync linux/perf_event.h with the kernel sources perf trace: Avoid early exit due SIGCHLD from non-workload processes MAINTAINERS: Update Jiri's email address
This commit is contained in:
Коммит
2dd3a8a139
|
@ -15147,7 +15147,7 @@ M: Ingo Molnar <mingo@redhat.com>
|
|||
M: Arnaldo Carvalho de Melo <acme@kernel.org>
|
||||
R: Mark Rutland <mark.rutland@arm.com>
|
||||
R: Alexander Shishkin <alexander.shishkin@linux.intel.com>
|
||||
R: Jiri Olsa <jolsa@redhat.com>
|
||||
R: Jiri Olsa <jolsa@kernel.org>
|
||||
R: Namhyung Kim <namhyung@kernel.org>
|
||||
L: linux-perf-users@vger.kernel.org
|
||||
L: linux-kernel@vger.kernel.org
|
||||
|
|
|
@ -465,6 +465,8 @@ struct perf_event_attr {
|
|||
/*
|
||||
* User provided data if sigtrap=1, passed back to user via
|
||||
* siginfo_t::si_perf_data, e.g. to permit user to identify the event.
|
||||
* Note, siginfo_t::si_perf_data is long-sized, and sig_data will be
|
||||
* truncated accordingly on 32 bit architectures.
|
||||
*/
|
||||
__u64 sig_data;
|
||||
};
|
||||
|
|
|
@ -3,11 +3,7 @@
|
|||
#define __LIBPERF_INTERNAL_CPUMAP_H
|
||||
|
||||
#include <linux/refcount.h>
|
||||
|
||||
/** A wrapper around a CPU to avoid confusion with the perf_cpu_map's map's indices. */
|
||||
struct perf_cpu {
|
||||
int cpu;
|
||||
};
|
||||
#include <perf/cpumap.h>
|
||||
|
||||
/**
|
||||
* A sized, reference counted, sorted array of integers representing CPU
|
||||
|
|
|
@ -7,6 +7,11 @@
|
|||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/** A wrapper around a CPU to avoid confusion with the perf_cpu_map's map's indices. */
|
||||
struct perf_cpu {
|
||||
int cpu;
|
||||
};
|
||||
|
||||
LIBPERF_API struct perf_cpu_map *perf_cpu_map__dummy_new(void);
|
||||
LIBPERF_API struct perf_cpu_map *perf_cpu_map__default_new(void);
|
||||
LIBPERF_API struct perf_cpu_map *perf_cpu_map__new(const char *cpu_list);
|
||||
|
|
|
@ -2,6 +2,7 @@ LIBPERF_0.0.1 {
|
|||
global:
|
||||
libperf_init;
|
||||
perf_cpu_map__dummy_new;
|
||||
perf_cpu_map__default_new;
|
||||
perf_cpu_map__get;
|
||||
perf_cpu_map__put;
|
||||
perf_cpu_map__new;
|
||||
|
|
|
@ -14,6 +14,8 @@ static int libperf_print(enum libperf_print_level level,
|
|||
int test_cpumap(int argc, char **argv)
|
||||
{
|
||||
struct perf_cpu_map *cpus;
|
||||
struct perf_cpu cpu;
|
||||
int idx;
|
||||
|
||||
__T_START;
|
||||
|
||||
|
@ -27,6 +29,15 @@ int test_cpumap(int argc, char **argv)
|
|||
perf_cpu_map__put(cpus);
|
||||
perf_cpu_map__put(cpus);
|
||||
|
||||
cpus = perf_cpu_map__default_new();
|
||||
if (!cpus)
|
||||
return -1;
|
||||
|
||||
perf_cpu_map__for_each_cpu(cpu, idx, cpus)
|
||||
__T("wrong cpu number", cpu.cpu != -1);
|
||||
|
||||
perf_cpu_map__put(cpus);
|
||||
|
||||
__T_END;
|
||||
return tests_failed == 0 ? 0 : -1;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
#define _GNU_SOURCE // needed for sched.h to get sched_[gs]etaffinity and CPU_(ZERO,SET)
|
||||
#include <inttypes.h>
|
||||
#include <sched.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
@ -526,12 +527,12 @@ static int test_stat_multiplexing(void)
|
|||
|
||||
min = counts[0].val;
|
||||
for (i = 0; i < EVENT_NUM; i++) {
|
||||
__T_VERBOSE("Event %2d -- Raw count = %lu, run = %lu, enable = %lu\n",
|
||||
__T_VERBOSE("Event %2d -- Raw count = %" PRIu64 ", run = %" PRIu64 ", enable = %" PRIu64 "\n",
|
||||
i, counts[i].val, counts[i].run, counts[i].ena);
|
||||
|
||||
perf_counts_values__scale(&counts[i], true, &scaled);
|
||||
if (scaled == 1) {
|
||||
__T_VERBOSE("\t Scaled count = %lu (%.2lf%%, %lu/%lu)\n",
|
||||
__T_VERBOSE("\t Scaled count = %" PRIu64 " (%.2lf%%, %" PRIu64 "/%" PRIu64 ")\n",
|
||||
counts[i].val,
|
||||
(double)counts[i].run / (double)counts[i].ena * 100.0,
|
||||
counts[i].run, counts[i].ena);
|
||||
|
|
|
@ -50,15 +50,8 @@ static NORETURN inline void die(const char *err, ...)
|
|||
static inline void *xrealloc(void *ptr, size_t size)
|
||||
{
|
||||
void *ret = realloc(ptr, size);
|
||||
if (!ret && !size)
|
||||
ret = realloc(ptr, 1);
|
||||
if (!ret) {
|
||||
ret = realloc(ptr, size);
|
||||
if (!ret && !size)
|
||||
ret = realloc(ptr, 1);
|
||||
if (!ret)
|
||||
die("Out of memory, realloc failed");
|
||||
}
|
||||
if (!ret)
|
||||
die("Out of memory, realloc failed");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -1536,13 +1536,20 @@ static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
|
|||
return fprintf(fp, " ? ");
|
||||
}
|
||||
|
||||
static pid_t workload_pid = -1;
|
||||
static bool done = false;
|
||||
static bool interrupted = false;
|
||||
|
||||
static void sig_handler(int sig)
|
||||
static void sighandler_interrupt(int sig __maybe_unused)
|
||||
{
|
||||
done = true;
|
||||
interrupted = sig == SIGINT;
|
||||
done = interrupted = true;
|
||||
}
|
||||
|
||||
static void sighandler_chld(int sig __maybe_unused, siginfo_t *info,
|
||||
void *context __maybe_unused)
|
||||
{
|
||||
if (info->si_pid == workload_pid)
|
||||
done = true;
|
||||
}
|
||||
|
||||
static size_t trace__fprintf_comm_tid(struct trace *trace, struct thread *thread, FILE *fp)
|
||||
|
@ -3938,7 +3945,6 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
|
|||
bool draining = false;
|
||||
|
||||
trace->live = true;
|
||||
signal(SIGCHLD, sig_handler);
|
||||
|
||||
if (!trace->raw_augmented_syscalls) {
|
||||
if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
|
||||
|
@ -4018,6 +4024,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
|
|||
fprintf(trace->output, "Couldn't run the workload!\n");
|
||||
goto out_delete_evlist;
|
||||
}
|
||||
workload_pid = evlist->workload.pid;
|
||||
}
|
||||
|
||||
err = evlist__open(evlist);
|
||||
|
@ -4887,10 +4894,16 @@ int cmd_trace(int argc, const char **argv)
|
|||
const char * const trace_subcommands[] = { "record", NULL };
|
||||
int err = -1;
|
||||
char bf[BUFSIZ];
|
||||
struct sigaction sigchld_act;
|
||||
|
||||
signal(SIGSEGV, sighandler_dump_stack);
|
||||
signal(SIGFPE, sighandler_dump_stack);
|
||||
signal(SIGINT, sig_handler);
|
||||
signal(SIGINT, sighandler_interrupt);
|
||||
|
||||
memset(&sigchld_act, 0, sizeof(sigchld_act));
|
||||
sigchld_act.sa_flags = SA_SIGINFO;
|
||||
sigchld_act.sa_sigaction = sighandler_chld;
|
||||
sigaction(SIGCHLD, &sigchld_act, NULL);
|
||||
|
||||
trace.evlist = evlist__new();
|
||||
trace.sctbl = syscalltbl__new();
|
||||
|
|
|
@ -45,8 +45,10 @@ Following tests are defined (with perf commands):
|
|||
perf record -d kill (test-record-data)
|
||||
perf record -F 100 kill (test-record-freq)
|
||||
perf record -g kill (test-record-graph-default)
|
||||
perf record -g kill (test-record-graph-default-aarch64)
|
||||
perf record --call-graph dwarf kill (test-record-graph-dwarf)
|
||||
perf record --call-graph fp kill (test-record-graph-fp)
|
||||
perf record --call-graph fp kill (test-record-graph-fp-aarch64)
|
||||
perf record --group -e cycles,instructions kill (test-record-group)
|
||||
perf record -e '{cycles,instructions}' kill (test-record-group1)
|
||||
perf record -e '{cycles/period=1/,instructions/period=2/}:S' kill (test-record-group2)
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
command = record
|
||||
args = --no-bpf-event -g kill >/dev/null 2>&1
|
||||
ret = 1
|
||||
# arm64 enables registers in the default mode (fp)
|
||||
arch = !aarch64
|
||||
|
||||
[event:base-record]
|
||||
sample_type=295
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
[config]
|
||||
command = record
|
||||
args = --no-bpf-event -g kill >/dev/null 2>&1
|
||||
ret = 1
|
||||
arch = aarch64
|
||||
|
||||
[event:base-record]
|
||||
sample_type=4391
|
||||
sample_regs_user=1073741824
|
|
@ -2,6 +2,8 @@
|
|||
command = record
|
||||
args = --no-bpf-event --call-graph fp kill >/dev/null 2>&1
|
||||
ret = 1
|
||||
# arm64 enables registers in fp mode
|
||||
arch = !aarch64
|
||||
|
||||
[event:base-record]
|
||||
sample_type=295
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
[config]
|
||||
command = record
|
||||
args = --no-bpf-event --call-graph fp kill >/dev/null 2>&1
|
||||
ret = 1
|
||||
arch = aarch64
|
||||
|
||||
[event:base-record]
|
||||
sample_type=4391
|
||||
sample_regs_user=1073741824
|
|
@ -1220,9 +1220,10 @@ bpf__obj_config_map(struct bpf_object *obj,
|
|||
pr_debug("ERROR: Invalid map config option '%s'\n", map_opt);
|
||||
err = -BPF_LOADER_ERRNO__OBJCONF_MAP_OPT;
|
||||
out:
|
||||
free(map_name);
|
||||
if (!err)
|
||||
*key_scan_pos += strlen(map_opt);
|
||||
|
||||
free(map_name);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
@ -50,8 +50,6 @@ struct cs_etm_auxtrace {
|
|||
u8 timeless_decoding;
|
||||
u8 snapshot_mode;
|
||||
u8 data_queued;
|
||||
u8 sample_branches;
|
||||
u8 sample_instructions;
|
||||
|
||||
int num_cpu;
|
||||
u64 latest_kernel_timestamp;
|
||||
|
@ -410,8 +408,8 @@ static void cs_etm__packet_swap(struct cs_etm_auxtrace *etm,
|
|||
{
|
||||
struct cs_etm_packet *tmp;
|
||||
|
||||
if (etm->sample_branches || etm->synth_opts.last_branch ||
|
||||
etm->sample_instructions) {
|
||||
if (etm->synth_opts.branches || etm->synth_opts.last_branch ||
|
||||
etm->synth_opts.instructions) {
|
||||
/*
|
||||
* Swap PACKET with PREV_PACKET: PACKET becomes PREV_PACKET for
|
||||
* the next incoming packet.
|
||||
|
@ -1365,7 +1363,6 @@ static int cs_etm__synth_events(struct cs_etm_auxtrace *etm,
|
|||
err = cs_etm__synth_event(session, &attr, id);
|
||||
if (err)
|
||||
return err;
|
||||
etm->sample_branches = true;
|
||||
etm->branches_sample_type = attr.sample_type;
|
||||
etm->branches_id = id;
|
||||
id += 1;
|
||||
|
@ -1389,7 +1386,6 @@ static int cs_etm__synth_events(struct cs_etm_auxtrace *etm,
|
|||
err = cs_etm__synth_event(session, &attr, id);
|
||||
if (err)
|
||||
return err;
|
||||
etm->sample_instructions = true;
|
||||
etm->instructions_sample_type = attr.sample_type;
|
||||
etm->instructions_id = id;
|
||||
id += 1;
|
||||
|
@ -1420,7 +1416,7 @@ static int cs_etm__sample(struct cs_etm_queue *etmq,
|
|||
tidq->prev_packet->last_instr_taken_branch)
|
||||
cs_etm__update_last_branch_rb(etmq, tidq);
|
||||
|
||||
if (etm->sample_instructions &&
|
||||
if (etm->synth_opts.instructions &&
|
||||
tidq->period_instructions >= etm->instructions_sample_period) {
|
||||
/*
|
||||
* Emit instruction sample periodically
|
||||
|
@ -1503,7 +1499,7 @@ static int cs_etm__sample(struct cs_etm_queue *etmq,
|
|||
}
|
||||
}
|
||||
|
||||
if (etm->sample_branches) {
|
||||
if (etm->synth_opts.branches) {
|
||||
bool generate_sample = false;
|
||||
|
||||
/* Generate sample for tracing on packet */
|
||||
|
@ -1557,6 +1553,7 @@ static int cs_etm__flush(struct cs_etm_queue *etmq,
|
|||
goto swap_packet;
|
||||
|
||||
if (etmq->etm->synth_opts.last_branch &&
|
||||
etmq->etm->synth_opts.instructions &&
|
||||
tidq->prev_packet->sample_type == CS_ETM_RANGE) {
|
||||
u64 addr;
|
||||
|
||||
|
@ -1582,7 +1579,7 @@ static int cs_etm__flush(struct cs_etm_queue *etmq,
|
|||
|
||||
}
|
||||
|
||||
if (etm->sample_branches &&
|
||||
if (etm->synth_opts.branches &&
|
||||
tidq->prev_packet->sample_type == CS_ETM_RANGE) {
|
||||
err = cs_etm__synth_branch_sample(etmq, tidq);
|
||||
if (err)
|
||||
|
@ -1614,6 +1611,7 @@ static int cs_etm__end_block(struct cs_etm_queue *etmq,
|
|||
* the trace.
|
||||
*/
|
||||
if (etmq->etm->synth_opts.last_branch &&
|
||||
etmq->etm->synth_opts.instructions &&
|
||||
tidq->prev_packet->sample_type == CS_ETM_RANGE) {
|
||||
u64 addr;
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче