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:
Linus Torvalds 2022-02-17 10:06:09 -08:00
Родитель edbd6c628e 31ded1535e
Коммит 2dd3a8a139
16 изменённых файлов: 77 добавлений и 32 удалений

Просмотреть файл

@ -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;