2019-07-21 13:24:21 +02:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
2019-07-21 13:24:48 +02:00
|
|
|
#include <errno.h>
|
2019-07-21 13:24:49 +02:00
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/syscall.h>
|
2019-07-21 13:24:21 +02:00
|
|
|
#include <perf/evsel.h>
|
2019-07-21 13:24:49 +02:00
|
|
|
#include <perf/cpumap.h>
|
|
|
|
#include <perf/threadmap.h>
|
2019-07-21 13:24:21 +02:00
|
|
|
#include <linux/list.h>
|
|
|
|
#include <internal/evsel.h>
|
2019-07-21 13:24:33 +02:00
|
|
|
#include <linux/zalloc.h>
|
2019-07-21 13:24:36 +02:00
|
|
|
#include <stdlib.h>
|
2019-07-21 13:24:48 +02:00
|
|
|
#include <internal/xyarray.h>
|
2019-07-21 13:24:49 +02:00
|
|
|
#include <internal/cpumap.h>
|
2021-04-14 11:07:37 -05:00
|
|
|
#include <internal/mmap.h>
|
2019-07-21 13:24:49 +02:00
|
|
|
#include <internal/threadmap.h>
|
2019-07-21 13:24:51 +02:00
|
|
|
#include <internal/lib.h>
|
2019-07-21 13:24:48 +02:00
|
|
|
#include <linux/string.h>
|
2019-07-21 13:24:52 +02:00
|
|
|
#include <sys/ioctl.h>
|
2021-04-14 11:07:37 -05:00
|
|
|
#include <sys/mman.h>
|
2021-07-06 17:17:03 +02:00
|
|
|
#include <asm/bug.h>
|
2019-07-21 13:24:24 +02:00
|
|
|
|
2021-07-06 17:16:59 +02:00
|
|
|
void perf_evsel__init(struct perf_evsel *evsel, struct perf_event_attr *attr,
|
|
|
|
int idx)
|
2019-07-21 13:24:24 +02:00
|
|
|
{
|
|
|
|
INIT_LIST_HEAD(&evsel->node);
|
2019-07-21 13:24:29 +02:00
|
|
|
evsel->attr = *attr;
|
2021-07-06 17:16:59 +02:00
|
|
|
evsel->idx = idx;
|
2021-07-06 17:17:00 +02:00
|
|
|
evsel->leader = evsel;
|
2019-07-21 13:24:24 +02:00
|
|
|
}
|
2019-07-21 13:24:33 +02:00
|
|
|
|
|
|
|
struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr)
|
|
|
|
{
|
|
|
|
struct perf_evsel *evsel = zalloc(sizeof(*evsel));
|
|
|
|
|
|
|
|
if (evsel != NULL)
|
2021-07-06 17:16:59 +02:00
|
|
|
perf_evsel__init(evsel, attr, 0);
|
2019-07-21 13:24:33 +02:00
|
|
|
|
|
|
|
return evsel;
|
|
|
|
}
|
2019-07-21 13:24:36 +02:00
|
|
|
|
|
|
|
void perf_evsel__delete(struct perf_evsel *evsel)
|
|
|
|
{
|
|
|
|
free(evsel);
|
|
|
|
}
|
2019-07-21 13:24:48 +02:00
|
|
|
|
2022-01-04 22:13:30 -08:00
|
|
|
#define FD(_evsel, _cpu_map_idx, _thread) \
|
|
|
|
((int *)xyarray__entry(_evsel->fd, _cpu_map_idx, _thread))
|
|
|
|
#define MMAP(_evsel, _cpu_map_idx, _thread) \
|
|
|
|
(_evsel->mmap ? ((struct perf_mmap *) xyarray__entry(_evsel->mmap, _cpu_map_idx, _thread)) \
|
|
|
|
: NULL)
|
2019-07-21 13:24:48 +02:00
|
|
|
|
|
|
|
int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
|
|
|
|
{
|
|
|
|
evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int));
|
|
|
|
|
|
|
|
if (evsel->fd) {
|
2022-01-04 22:13:30 -08:00
|
|
|
int idx, thread;
|
|
|
|
|
|
|
|
for (idx = 0; idx < ncpus; idx++) {
|
2019-07-21 13:24:48 +02:00
|
|
|
for (thread = 0; thread < nthreads; thread++) {
|
2022-01-04 22:13:30 -08:00
|
|
|
int *fd = FD(evsel, idx, thread);
|
libperf evsel: Make use of FD robust.
FD uses xyarray__entry that may return NULL if an index is out of
bounds. If NULL is returned then a segv happens as FD unconditionally
dereferences the pointer. This was happening in a case of with perf
iostat as shown below. The fix is to make FD an "int*" rather than an
int and handle the NULL case as either invalid input or a closed fd.
$ sudo gdb --args perf stat --iostat list
...
Breakpoint 1, perf_evsel__alloc_fd (evsel=0x5555560951a0, ncpus=1, nthreads=1) at evsel.c:50
50 {
(gdb) bt
#0 perf_evsel__alloc_fd (evsel=0x5555560951a0, ncpus=1, nthreads=1) at evsel.c:50
#1 0x000055555585c188 in evsel__open_cpu (evsel=0x5555560951a0, cpus=0x555556093410,
threads=0x555556086fb0, start_cpu=0, end_cpu=1) at util/evsel.c:1792
#2 0x000055555585cfb2 in evsel__open (evsel=0x5555560951a0, cpus=0x0, threads=0x555556086fb0)
at util/evsel.c:2045
#3 0x000055555585d0db in evsel__open_per_thread (evsel=0x5555560951a0, threads=0x555556086fb0)
at util/evsel.c:2065
#4 0x00005555558ece64 in create_perf_stat_counter (evsel=0x5555560951a0,
config=0x555555c34700 <stat_config>, target=0x555555c2f1c0 <target>, cpu=0) at util/stat.c:590
#5 0x000055555578e927 in __run_perf_stat (argc=1, argv=0x7fffffffe4a0, run_idx=0)
at builtin-stat.c:833
#6 0x000055555578f3c6 in run_perf_stat (argc=1, argv=0x7fffffffe4a0, run_idx=0)
at builtin-stat.c:1048
#7 0x0000555555792ee5 in cmd_stat (argc=1, argv=0x7fffffffe4a0) at builtin-stat.c:2534
#8 0x0000555555835ed3 in run_builtin (p=0x555555c3f540 <commands+288>, argc=3,
argv=0x7fffffffe4a0) at perf.c:313
#9 0x0000555555836154 in handle_internal_command (argc=3, argv=0x7fffffffe4a0) at perf.c:365
#10 0x000055555583629f in run_argv (argcp=0x7fffffffe2ec, argv=0x7fffffffe2e0) at perf.c:409
#11 0x0000555555836692 in main (argc=3, argv=0x7fffffffe4a0) at perf.c:539
...
(gdb) c
Continuing.
Error:
The sys_perf_event_open() syscall returned with 22 (Invalid argument) for event (uncore_iio_0/event=0x83,umask=0x04,ch_mask=0xF,fc_mask=0x07/).
/bin/dmesg | grep -i perf may provide additional information.
Program received signal SIGSEGV, Segmentation fault.
0x00005555559b03ea in perf_evsel__close_fd_cpu (evsel=0x5555560951a0, cpu=1) at evsel.c:166
166 if (FD(evsel, cpu, thread) >= 0)
v3. fixes a bug in perf_evsel__run_ioctl where the sense of a branch was
backward.
Signed-off-by: Ian Rogers <irogers@google.com>
Acked-by: Jiri Olsa <jolsa@redhat.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lore.kernel.org/lkml/20210918054440.2350466-1-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-09-17 22:44:40 -07:00
|
|
|
|
|
|
|
if (fd)
|
|
|
|
*fd = -1;
|
2019-07-21 13:24:48 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return evsel->fd != NULL ? 0 : -ENOMEM;
|
|
|
|
}
|
2019-07-21 13:24:49 +02:00
|
|
|
|
2021-04-14 11:07:37 -05:00
|
|
|
static int perf_evsel__alloc_mmap(struct perf_evsel *evsel, int ncpus, int nthreads)
|
|
|
|
{
|
|
|
|
evsel->mmap = xyarray__new(ncpus, nthreads, sizeof(struct perf_mmap));
|
|
|
|
|
|
|
|
return evsel->mmap != NULL ? 0 : -ENOMEM;
|
|
|
|
}
|
|
|
|
|
2019-07-21 13:24:49 +02:00
|
|
|
static int
|
|
|
|
sys_perf_event_open(struct perf_event_attr *attr,
|
2022-01-04 22:13:51 -08:00
|
|
|
pid_t pid, struct perf_cpu cpu, int group_fd,
|
2019-07-21 13:24:49 +02:00
|
|
|
unsigned long flags)
|
|
|
|
{
|
2022-01-04 22:13:51 -08:00
|
|
|
return syscall(__NR_perf_event_open, attr, pid, cpu.cpu, group_fd, flags);
|
2019-07-21 13:24:49 +02:00
|
|
|
}
|
|
|
|
|
2022-01-04 22:13:30 -08:00
|
|
|
static int get_group_fd(struct perf_evsel *evsel, int cpu_map_idx, int thread, int *group_fd)
|
2021-07-06 17:17:03 +02:00
|
|
|
{
|
|
|
|
struct perf_evsel *leader = evsel->leader;
|
libperf evsel: Make use of FD robust.
FD uses xyarray__entry that may return NULL if an index is out of
bounds. If NULL is returned then a segv happens as FD unconditionally
dereferences the pointer. This was happening in a case of with perf
iostat as shown below. The fix is to make FD an "int*" rather than an
int and handle the NULL case as either invalid input or a closed fd.
$ sudo gdb --args perf stat --iostat list
...
Breakpoint 1, perf_evsel__alloc_fd (evsel=0x5555560951a0, ncpus=1, nthreads=1) at evsel.c:50
50 {
(gdb) bt
#0 perf_evsel__alloc_fd (evsel=0x5555560951a0, ncpus=1, nthreads=1) at evsel.c:50
#1 0x000055555585c188 in evsel__open_cpu (evsel=0x5555560951a0, cpus=0x555556093410,
threads=0x555556086fb0, start_cpu=0, end_cpu=1) at util/evsel.c:1792
#2 0x000055555585cfb2 in evsel__open (evsel=0x5555560951a0, cpus=0x0, threads=0x555556086fb0)
at util/evsel.c:2045
#3 0x000055555585d0db in evsel__open_per_thread (evsel=0x5555560951a0, threads=0x555556086fb0)
at util/evsel.c:2065
#4 0x00005555558ece64 in create_perf_stat_counter (evsel=0x5555560951a0,
config=0x555555c34700 <stat_config>, target=0x555555c2f1c0 <target>, cpu=0) at util/stat.c:590
#5 0x000055555578e927 in __run_perf_stat (argc=1, argv=0x7fffffffe4a0, run_idx=0)
at builtin-stat.c:833
#6 0x000055555578f3c6 in run_perf_stat (argc=1, argv=0x7fffffffe4a0, run_idx=0)
at builtin-stat.c:1048
#7 0x0000555555792ee5 in cmd_stat (argc=1, argv=0x7fffffffe4a0) at builtin-stat.c:2534
#8 0x0000555555835ed3 in run_builtin (p=0x555555c3f540 <commands+288>, argc=3,
argv=0x7fffffffe4a0) at perf.c:313
#9 0x0000555555836154 in handle_internal_command (argc=3, argv=0x7fffffffe4a0) at perf.c:365
#10 0x000055555583629f in run_argv (argcp=0x7fffffffe2ec, argv=0x7fffffffe2e0) at perf.c:409
#11 0x0000555555836692 in main (argc=3, argv=0x7fffffffe4a0) at perf.c:539
...
(gdb) c
Continuing.
Error:
The sys_perf_event_open() syscall returned with 22 (Invalid argument) for event (uncore_iio_0/event=0x83,umask=0x04,ch_mask=0xF,fc_mask=0x07/).
/bin/dmesg | grep -i perf may provide additional information.
Program received signal SIGSEGV, Segmentation fault.
0x00005555559b03ea in perf_evsel__close_fd_cpu (evsel=0x5555560951a0, cpu=1) at evsel.c:166
166 if (FD(evsel, cpu, thread) >= 0)
v3. fixes a bug in perf_evsel__run_ioctl where the sense of a branch was
backward.
Signed-off-by: Ian Rogers <irogers@google.com>
Acked-by: Jiri Olsa <jolsa@redhat.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lore.kernel.org/lkml/20210918054440.2350466-1-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-09-17 22:44:40 -07:00
|
|
|
int *fd;
|
2021-07-06 17:17:03 +02:00
|
|
|
|
2021-07-09 14:52:16 -03:00
|
|
|
if (evsel == leader) {
|
|
|
|
*group_fd = -1;
|
|
|
|
return 0;
|
|
|
|
}
|
2021-07-06 17:17:03 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Leader must be already processed/open,
|
|
|
|
* if not it's a bug.
|
|
|
|
*/
|
2021-07-09 14:52:16 -03:00
|
|
|
if (!leader->fd)
|
|
|
|
return -ENOTCONN;
|
2021-07-06 17:17:03 +02:00
|
|
|
|
2022-01-04 22:13:30 -08:00
|
|
|
fd = FD(leader, cpu_map_idx, thread);
|
libperf evsel: Make use of FD robust.
FD uses xyarray__entry that may return NULL if an index is out of
bounds. If NULL is returned then a segv happens as FD unconditionally
dereferences the pointer. This was happening in a case of with perf
iostat as shown below. The fix is to make FD an "int*" rather than an
int and handle the NULL case as either invalid input or a closed fd.
$ sudo gdb --args perf stat --iostat list
...
Breakpoint 1, perf_evsel__alloc_fd (evsel=0x5555560951a0, ncpus=1, nthreads=1) at evsel.c:50
50 {
(gdb) bt
#0 perf_evsel__alloc_fd (evsel=0x5555560951a0, ncpus=1, nthreads=1) at evsel.c:50
#1 0x000055555585c188 in evsel__open_cpu (evsel=0x5555560951a0, cpus=0x555556093410,
threads=0x555556086fb0, start_cpu=0, end_cpu=1) at util/evsel.c:1792
#2 0x000055555585cfb2 in evsel__open (evsel=0x5555560951a0, cpus=0x0, threads=0x555556086fb0)
at util/evsel.c:2045
#3 0x000055555585d0db in evsel__open_per_thread (evsel=0x5555560951a0, threads=0x555556086fb0)
at util/evsel.c:2065
#4 0x00005555558ece64 in create_perf_stat_counter (evsel=0x5555560951a0,
config=0x555555c34700 <stat_config>, target=0x555555c2f1c0 <target>, cpu=0) at util/stat.c:590
#5 0x000055555578e927 in __run_perf_stat (argc=1, argv=0x7fffffffe4a0, run_idx=0)
at builtin-stat.c:833
#6 0x000055555578f3c6 in run_perf_stat (argc=1, argv=0x7fffffffe4a0, run_idx=0)
at builtin-stat.c:1048
#7 0x0000555555792ee5 in cmd_stat (argc=1, argv=0x7fffffffe4a0) at builtin-stat.c:2534
#8 0x0000555555835ed3 in run_builtin (p=0x555555c3f540 <commands+288>, argc=3,
argv=0x7fffffffe4a0) at perf.c:313
#9 0x0000555555836154 in handle_internal_command (argc=3, argv=0x7fffffffe4a0) at perf.c:365
#10 0x000055555583629f in run_argv (argcp=0x7fffffffe2ec, argv=0x7fffffffe2e0) at perf.c:409
#11 0x0000555555836692 in main (argc=3, argv=0x7fffffffe4a0) at perf.c:539
...
(gdb) c
Continuing.
Error:
The sys_perf_event_open() syscall returned with 22 (Invalid argument) for event (uncore_iio_0/event=0x83,umask=0x04,ch_mask=0xF,fc_mask=0x07/).
/bin/dmesg | grep -i perf may provide additional information.
Program received signal SIGSEGV, Segmentation fault.
0x00005555559b03ea in perf_evsel__close_fd_cpu (evsel=0x5555560951a0, cpu=1) at evsel.c:166
166 if (FD(evsel, cpu, thread) >= 0)
v3. fixes a bug in perf_evsel__run_ioctl where the sense of a branch was
backward.
Signed-off-by: Ian Rogers <irogers@google.com>
Acked-by: Jiri Olsa <jolsa@redhat.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lore.kernel.org/lkml/20210918054440.2350466-1-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-09-17 22:44:40 -07:00
|
|
|
if (fd == NULL || *fd == -1)
|
2021-07-09 14:52:16 -03:00
|
|
|
return -EBADF;
|
|
|
|
|
libperf evsel: Make use of FD robust.
FD uses xyarray__entry that may return NULL if an index is out of
bounds. If NULL is returned then a segv happens as FD unconditionally
dereferences the pointer. This was happening in a case of with perf
iostat as shown below. The fix is to make FD an "int*" rather than an
int and handle the NULL case as either invalid input or a closed fd.
$ sudo gdb --args perf stat --iostat list
...
Breakpoint 1, perf_evsel__alloc_fd (evsel=0x5555560951a0, ncpus=1, nthreads=1) at evsel.c:50
50 {
(gdb) bt
#0 perf_evsel__alloc_fd (evsel=0x5555560951a0, ncpus=1, nthreads=1) at evsel.c:50
#1 0x000055555585c188 in evsel__open_cpu (evsel=0x5555560951a0, cpus=0x555556093410,
threads=0x555556086fb0, start_cpu=0, end_cpu=1) at util/evsel.c:1792
#2 0x000055555585cfb2 in evsel__open (evsel=0x5555560951a0, cpus=0x0, threads=0x555556086fb0)
at util/evsel.c:2045
#3 0x000055555585d0db in evsel__open_per_thread (evsel=0x5555560951a0, threads=0x555556086fb0)
at util/evsel.c:2065
#4 0x00005555558ece64 in create_perf_stat_counter (evsel=0x5555560951a0,
config=0x555555c34700 <stat_config>, target=0x555555c2f1c0 <target>, cpu=0) at util/stat.c:590
#5 0x000055555578e927 in __run_perf_stat (argc=1, argv=0x7fffffffe4a0, run_idx=0)
at builtin-stat.c:833
#6 0x000055555578f3c6 in run_perf_stat (argc=1, argv=0x7fffffffe4a0, run_idx=0)
at builtin-stat.c:1048
#7 0x0000555555792ee5 in cmd_stat (argc=1, argv=0x7fffffffe4a0) at builtin-stat.c:2534
#8 0x0000555555835ed3 in run_builtin (p=0x555555c3f540 <commands+288>, argc=3,
argv=0x7fffffffe4a0) at perf.c:313
#9 0x0000555555836154 in handle_internal_command (argc=3, argv=0x7fffffffe4a0) at perf.c:365
#10 0x000055555583629f in run_argv (argcp=0x7fffffffe2ec, argv=0x7fffffffe2e0) at perf.c:409
#11 0x0000555555836692 in main (argc=3, argv=0x7fffffffe4a0) at perf.c:539
...
(gdb) c
Continuing.
Error:
The sys_perf_event_open() syscall returned with 22 (Invalid argument) for event (uncore_iio_0/event=0x83,umask=0x04,ch_mask=0xF,fc_mask=0x07/).
/bin/dmesg | grep -i perf may provide additional information.
Program received signal SIGSEGV, Segmentation fault.
0x00005555559b03ea in perf_evsel__close_fd_cpu (evsel=0x5555560951a0, cpu=1) at evsel.c:166
166 if (FD(evsel, cpu, thread) >= 0)
v3. fixes a bug in perf_evsel__run_ioctl where the sense of a branch was
backward.
Signed-off-by: Ian Rogers <irogers@google.com>
Acked-by: Jiri Olsa <jolsa@redhat.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lore.kernel.org/lkml/20210918054440.2350466-1-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-09-17 22:44:40 -07:00
|
|
|
*group_fd = *fd;
|
2021-07-09 14:52:16 -03:00
|
|
|
|
|
|
|
return 0;
|
2021-07-06 17:17:03 +02:00
|
|
|
}
|
|
|
|
|
2019-07-21 13:24:49 +02:00
|
|
|
int perf_evsel__open(struct perf_evsel *evsel, struct perf_cpu_map *cpus,
|
|
|
|
struct perf_thread_map *threads)
|
|
|
|
{
|
2022-01-04 22:13:51 -08:00
|
|
|
struct perf_cpu cpu;
|
|
|
|
int idx, thread, err = 0;
|
2019-07-21 13:24:49 +02:00
|
|
|
|
|
|
|
if (cpus == NULL) {
|
|
|
|
static struct perf_cpu_map *empty_cpu_map;
|
|
|
|
|
|
|
|
if (empty_cpu_map == NULL) {
|
2023-11-28 22:01:58 -08:00
|
|
|
empty_cpu_map = perf_cpu_map__new_any_cpu();
|
2019-07-21 13:24:49 +02:00
|
|
|
if (empty_cpu_map == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
cpus = empty_cpu_map;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (threads == NULL) {
|
|
|
|
static struct perf_thread_map *empty_thread_map;
|
|
|
|
|
|
|
|
if (empty_thread_map == NULL) {
|
|
|
|
empty_thread_map = perf_thread_map__new_dummy();
|
|
|
|
if (empty_thread_map == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
threads = empty_thread_map;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (evsel->fd == NULL &&
|
2022-01-21 20:58:10 -08:00
|
|
|
perf_evsel__alloc_fd(evsel, perf_cpu_map__nr(cpus), threads->nr) < 0)
|
2019-07-21 13:24:49 +02:00
|
|
|
return -ENOMEM;
|
|
|
|
|
2022-01-04 22:13:30 -08:00
|
|
|
perf_cpu_map__for_each_cpu(cpu, idx, cpus) {
|
2019-07-21 13:24:49 +02:00
|
|
|
for (thread = 0; thread < threads->nr; thread++) {
|
libperf evsel: Make use of FD robust.
FD uses xyarray__entry that may return NULL if an index is out of
bounds. If NULL is returned then a segv happens as FD unconditionally
dereferences the pointer. This was happening in a case of with perf
iostat as shown below. The fix is to make FD an "int*" rather than an
int and handle the NULL case as either invalid input or a closed fd.
$ sudo gdb --args perf stat --iostat list
...
Breakpoint 1, perf_evsel__alloc_fd (evsel=0x5555560951a0, ncpus=1, nthreads=1) at evsel.c:50
50 {
(gdb) bt
#0 perf_evsel__alloc_fd (evsel=0x5555560951a0, ncpus=1, nthreads=1) at evsel.c:50
#1 0x000055555585c188 in evsel__open_cpu (evsel=0x5555560951a0, cpus=0x555556093410,
threads=0x555556086fb0, start_cpu=0, end_cpu=1) at util/evsel.c:1792
#2 0x000055555585cfb2 in evsel__open (evsel=0x5555560951a0, cpus=0x0, threads=0x555556086fb0)
at util/evsel.c:2045
#3 0x000055555585d0db in evsel__open_per_thread (evsel=0x5555560951a0, threads=0x555556086fb0)
at util/evsel.c:2065
#4 0x00005555558ece64 in create_perf_stat_counter (evsel=0x5555560951a0,
config=0x555555c34700 <stat_config>, target=0x555555c2f1c0 <target>, cpu=0) at util/stat.c:590
#5 0x000055555578e927 in __run_perf_stat (argc=1, argv=0x7fffffffe4a0, run_idx=0)
at builtin-stat.c:833
#6 0x000055555578f3c6 in run_perf_stat (argc=1, argv=0x7fffffffe4a0, run_idx=0)
at builtin-stat.c:1048
#7 0x0000555555792ee5 in cmd_stat (argc=1, argv=0x7fffffffe4a0) at builtin-stat.c:2534
#8 0x0000555555835ed3 in run_builtin (p=0x555555c3f540 <commands+288>, argc=3,
argv=0x7fffffffe4a0) at perf.c:313
#9 0x0000555555836154 in handle_internal_command (argc=3, argv=0x7fffffffe4a0) at perf.c:365
#10 0x000055555583629f in run_argv (argcp=0x7fffffffe2ec, argv=0x7fffffffe2e0) at perf.c:409
#11 0x0000555555836692 in main (argc=3, argv=0x7fffffffe4a0) at perf.c:539
...
(gdb) c
Continuing.
Error:
The sys_perf_event_open() syscall returned with 22 (Invalid argument) for event (uncore_iio_0/event=0x83,umask=0x04,ch_mask=0xF,fc_mask=0x07/).
/bin/dmesg | grep -i perf may provide additional information.
Program received signal SIGSEGV, Segmentation fault.
0x00005555559b03ea in perf_evsel__close_fd_cpu (evsel=0x5555560951a0, cpu=1) at evsel.c:166
166 if (FD(evsel, cpu, thread) >= 0)
v3. fixes a bug in perf_evsel__run_ioctl where the sense of a branch was
backward.
Signed-off-by: Ian Rogers <irogers@google.com>
Acked-by: Jiri Olsa <jolsa@redhat.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lore.kernel.org/lkml/20210918054440.2350466-1-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-09-17 22:44:40 -07:00
|
|
|
int fd, group_fd, *evsel_fd;
|
|
|
|
|
2022-01-04 22:13:30 -08:00
|
|
|
evsel_fd = FD(evsel, idx, thread);
|
2022-06-08 22:23:52 -07:00
|
|
|
if (evsel_fd == NULL) {
|
|
|
|
err = -EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
2021-07-06 17:17:03 +02:00
|
|
|
|
2022-01-04 22:13:30 -08:00
|
|
|
err = get_group_fd(evsel, idx, thread, &group_fd);
|
2021-07-09 14:52:16 -03:00
|
|
|
if (err < 0)
|
2022-06-08 22:23:52 -07:00
|
|
|
goto out;
|
2019-07-21 13:24:49 +02:00
|
|
|
|
|
|
|
fd = sys_perf_event_open(&evsel->attr,
|
|
|
|
threads->map[thread].pid,
|
2022-01-04 22:13:30 -08:00
|
|
|
cpu, group_fd, 0);
|
2019-07-21 13:24:49 +02:00
|
|
|
|
2022-06-08 22:23:52 -07:00
|
|
|
if (fd < 0) {
|
|
|
|
err = -errno;
|
|
|
|
goto out;
|
|
|
|
}
|
2019-07-21 13:24:49 +02:00
|
|
|
|
libperf evsel: Make use of FD robust.
FD uses xyarray__entry that may return NULL if an index is out of
bounds. If NULL is returned then a segv happens as FD unconditionally
dereferences the pointer. This was happening in a case of with perf
iostat as shown below. The fix is to make FD an "int*" rather than an
int and handle the NULL case as either invalid input or a closed fd.
$ sudo gdb --args perf stat --iostat list
...
Breakpoint 1, perf_evsel__alloc_fd (evsel=0x5555560951a0, ncpus=1, nthreads=1) at evsel.c:50
50 {
(gdb) bt
#0 perf_evsel__alloc_fd (evsel=0x5555560951a0, ncpus=1, nthreads=1) at evsel.c:50
#1 0x000055555585c188 in evsel__open_cpu (evsel=0x5555560951a0, cpus=0x555556093410,
threads=0x555556086fb0, start_cpu=0, end_cpu=1) at util/evsel.c:1792
#2 0x000055555585cfb2 in evsel__open (evsel=0x5555560951a0, cpus=0x0, threads=0x555556086fb0)
at util/evsel.c:2045
#3 0x000055555585d0db in evsel__open_per_thread (evsel=0x5555560951a0, threads=0x555556086fb0)
at util/evsel.c:2065
#4 0x00005555558ece64 in create_perf_stat_counter (evsel=0x5555560951a0,
config=0x555555c34700 <stat_config>, target=0x555555c2f1c0 <target>, cpu=0) at util/stat.c:590
#5 0x000055555578e927 in __run_perf_stat (argc=1, argv=0x7fffffffe4a0, run_idx=0)
at builtin-stat.c:833
#6 0x000055555578f3c6 in run_perf_stat (argc=1, argv=0x7fffffffe4a0, run_idx=0)
at builtin-stat.c:1048
#7 0x0000555555792ee5 in cmd_stat (argc=1, argv=0x7fffffffe4a0) at builtin-stat.c:2534
#8 0x0000555555835ed3 in run_builtin (p=0x555555c3f540 <commands+288>, argc=3,
argv=0x7fffffffe4a0) at perf.c:313
#9 0x0000555555836154 in handle_internal_command (argc=3, argv=0x7fffffffe4a0) at perf.c:365
#10 0x000055555583629f in run_argv (argcp=0x7fffffffe2ec, argv=0x7fffffffe2e0) at perf.c:409
#11 0x0000555555836692 in main (argc=3, argv=0x7fffffffe4a0) at perf.c:539
...
(gdb) c
Continuing.
Error:
The sys_perf_event_open() syscall returned with 22 (Invalid argument) for event (uncore_iio_0/event=0x83,umask=0x04,ch_mask=0xF,fc_mask=0x07/).
/bin/dmesg | grep -i perf may provide additional information.
Program received signal SIGSEGV, Segmentation fault.
0x00005555559b03ea in perf_evsel__close_fd_cpu (evsel=0x5555560951a0, cpu=1) at evsel.c:166
166 if (FD(evsel, cpu, thread) >= 0)
v3. fixes a bug in perf_evsel__run_ioctl where the sense of a branch was
backward.
Signed-off-by: Ian Rogers <irogers@google.com>
Acked-by: Jiri Olsa <jolsa@redhat.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lore.kernel.org/lkml/20210918054440.2350466-1-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-09-17 22:44:40 -07:00
|
|
|
*evsel_fd = fd;
|
2019-07-21 13:24:49 +02:00
|
|
|
}
|
|
|
|
}
|
2022-06-08 22:23:52 -07:00
|
|
|
out:
|
|
|
|
if (err)
|
|
|
|
perf_evsel__close(evsel);
|
2019-07-21 13:24:49 +02:00
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
2019-07-21 13:24:50 +02:00
|
|
|
|
2022-01-04 22:13:30 -08:00
|
|
|
static void perf_evsel__close_fd_cpu(struct perf_evsel *evsel, int cpu_map_idx)
|
2019-11-20 16:15:16 -08:00
|
|
|
{
|
|
|
|
int thread;
|
|
|
|
|
|
|
|
for (thread = 0; thread < xyarray__max_y(evsel->fd); ++thread) {
|
2022-01-04 22:13:30 -08:00
|
|
|
int *fd = FD(evsel, cpu_map_idx, thread);
|
libperf evsel: Make use of FD robust.
FD uses xyarray__entry that may return NULL if an index is out of
bounds. If NULL is returned then a segv happens as FD unconditionally
dereferences the pointer. This was happening in a case of with perf
iostat as shown below. The fix is to make FD an "int*" rather than an
int and handle the NULL case as either invalid input or a closed fd.
$ sudo gdb --args perf stat --iostat list
...
Breakpoint 1, perf_evsel__alloc_fd (evsel=0x5555560951a0, ncpus=1, nthreads=1) at evsel.c:50
50 {
(gdb) bt
#0 perf_evsel__alloc_fd (evsel=0x5555560951a0, ncpus=1, nthreads=1) at evsel.c:50
#1 0x000055555585c188 in evsel__open_cpu (evsel=0x5555560951a0, cpus=0x555556093410,
threads=0x555556086fb0, start_cpu=0, end_cpu=1) at util/evsel.c:1792
#2 0x000055555585cfb2 in evsel__open (evsel=0x5555560951a0, cpus=0x0, threads=0x555556086fb0)
at util/evsel.c:2045
#3 0x000055555585d0db in evsel__open_per_thread (evsel=0x5555560951a0, threads=0x555556086fb0)
at util/evsel.c:2065
#4 0x00005555558ece64 in create_perf_stat_counter (evsel=0x5555560951a0,
config=0x555555c34700 <stat_config>, target=0x555555c2f1c0 <target>, cpu=0) at util/stat.c:590
#5 0x000055555578e927 in __run_perf_stat (argc=1, argv=0x7fffffffe4a0, run_idx=0)
at builtin-stat.c:833
#6 0x000055555578f3c6 in run_perf_stat (argc=1, argv=0x7fffffffe4a0, run_idx=0)
at builtin-stat.c:1048
#7 0x0000555555792ee5 in cmd_stat (argc=1, argv=0x7fffffffe4a0) at builtin-stat.c:2534
#8 0x0000555555835ed3 in run_builtin (p=0x555555c3f540 <commands+288>, argc=3,
argv=0x7fffffffe4a0) at perf.c:313
#9 0x0000555555836154 in handle_internal_command (argc=3, argv=0x7fffffffe4a0) at perf.c:365
#10 0x000055555583629f in run_argv (argcp=0x7fffffffe2ec, argv=0x7fffffffe2e0) at perf.c:409
#11 0x0000555555836692 in main (argc=3, argv=0x7fffffffe4a0) at perf.c:539
...
(gdb) c
Continuing.
Error:
The sys_perf_event_open() syscall returned with 22 (Invalid argument) for event (uncore_iio_0/event=0x83,umask=0x04,ch_mask=0xF,fc_mask=0x07/).
/bin/dmesg | grep -i perf may provide additional information.
Program received signal SIGSEGV, Segmentation fault.
0x00005555559b03ea in perf_evsel__close_fd_cpu (evsel=0x5555560951a0, cpu=1) at evsel.c:166
166 if (FD(evsel, cpu, thread) >= 0)
v3. fixes a bug in perf_evsel__run_ioctl where the sense of a branch was
backward.
Signed-off-by: Ian Rogers <irogers@google.com>
Acked-by: Jiri Olsa <jolsa@redhat.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lore.kernel.org/lkml/20210918054440.2350466-1-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-09-17 22:44:40 -07:00
|
|
|
|
|
|
|
if (fd && *fd >= 0) {
|
|
|
|
close(*fd);
|
|
|
|
*fd = -1;
|
|
|
|
}
|
2019-11-20 16:15:16 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-21 13:24:50 +02:00
|
|
|
void perf_evsel__close_fd(struct perf_evsel *evsel)
|
|
|
|
{
|
2022-01-04 22:13:30 -08:00
|
|
|
for (int idx = 0; idx < xyarray__max_x(evsel->fd); idx++)
|
|
|
|
perf_evsel__close_fd_cpu(evsel, idx);
|
2019-07-21 13:24:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void perf_evsel__free_fd(struct perf_evsel *evsel)
|
|
|
|
{
|
|
|
|
xyarray__delete(evsel->fd);
|
|
|
|
evsel->fd = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void perf_evsel__close(struct perf_evsel *evsel)
|
|
|
|
{
|
|
|
|
if (evsel->fd == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
perf_evsel__close_fd(evsel);
|
|
|
|
perf_evsel__free_fd(evsel);
|
|
|
|
}
|
2019-07-21 13:24:51 +02:00
|
|
|
|
2022-01-04 22:13:30 -08:00
|
|
|
void perf_evsel__close_cpu(struct perf_evsel *evsel, int cpu_map_idx)
|
2019-11-20 16:15:16 -08:00
|
|
|
{
|
|
|
|
if (evsel->fd == NULL)
|
|
|
|
return;
|
|
|
|
|
2022-01-04 22:13:30 -08:00
|
|
|
perf_evsel__close_fd_cpu(evsel, cpu_map_idx);
|
2019-11-20 16:15:16 -08:00
|
|
|
}
|
|
|
|
|
2021-04-14 11:07:37 -05:00
|
|
|
void perf_evsel__munmap(struct perf_evsel *evsel)
|
|
|
|
{
|
2022-01-04 22:13:30 -08:00
|
|
|
int idx, thread;
|
2021-04-14 11:07:37 -05:00
|
|
|
|
|
|
|
if (evsel->fd == NULL || evsel->mmap == NULL)
|
|
|
|
return;
|
|
|
|
|
2022-01-04 22:13:30 -08:00
|
|
|
for (idx = 0; idx < xyarray__max_x(evsel->fd); idx++) {
|
2021-04-14 11:07:37 -05:00
|
|
|
for (thread = 0; thread < xyarray__max_y(evsel->fd); thread++) {
|
2022-01-04 22:13:30 -08:00
|
|
|
int *fd = FD(evsel, idx, thread);
|
2021-04-14 11:07:37 -05:00
|
|
|
|
libperf evsel: Make use of FD robust.
FD uses xyarray__entry that may return NULL if an index is out of
bounds. If NULL is returned then a segv happens as FD unconditionally
dereferences the pointer. This was happening in a case of with perf
iostat as shown below. The fix is to make FD an "int*" rather than an
int and handle the NULL case as either invalid input or a closed fd.
$ sudo gdb --args perf stat --iostat list
...
Breakpoint 1, perf_evsel__alloc_fd (evsel=0x5555560951a0, ncpus=1, nthreads=1) at evsel.c:50
50 {
(gdb) bt
#0 perf_evsel__alloc_fd (evsel=0x5555560951a0, ncpus=1, nthreads=1) at evsel.c:50
#1 0x000055555585c188 in evsel__open_cpu (evsel=0x5555560951a0, cpus=0x555556093410,
threads=0x555556086fb0, start_cpu=0, end_cpu=1) at util/evsel.c:1792
#2 0x000055555585cfb2 in evsel__open (evsel=0x5555560951a0, cpus=0x0, threads=0x555556086fb0)
at util/evsel.c:2045
#3 0x000055555585d0db in evsel__open_per_thread (evsel=0x5555560951a0, threads=0x555556086fb0)
at util/evsel.c:2065
#4 0x00005555558ece64 in create_perf_stat_counter (evsel=0x5555560951a0,
config=0x555555c34700 <stat_config>, target=0x555555c2f1c0 <target>, cpu=0) at util/stat.c:590
#5 0x000055555578e927 in __run_perf_stat (argc=1, argv=0x7fffffffe4a0, run_idx=0)
at builtin-stat.c:833
#6 0x000055555578f3c6 in run_perf_stat (argc=1, argv=0x7fffffffe4a0, run_idx=0)
at builtin-stat.c:1048
#7 0x0000555555792ee5 in cmd_stat (argc=1, argv=0x7fffffffe4a0) at builtin-stat.c:2534
#8 0x0000555555835ed3 in run_builtin (p=0x555555c3f540 <commands+288>, argc=3,
argv=0x7fffffffe4a0) at perf.c:313
#9 0x0000555555836154 in handle_internal_command (argc=3, argv=0x7fffffffe4a0) at perf.c:365
#10 0x000055555583629f in run_argv (argcp=0x7fffffffe2ec, argv=0x7fffffffe2e0) at perf.c:409
#11 0x0000555555836692 in main (argc=3, argv=0x7fffffffe4a0) at perf.c:539
...
(gdb) c
Continuing.
Error:
The sys_perf_event_open() syscall returned with 22 (Invalid argument) for event (uncore_iio_0/event=0x83,umask=0x04,ch_mask=0xF,fc_mask=0x07/).
/bin/dmesg | grep -i perf may provide additional information.
Program received signal SIGSEGV, Segmentation fault.
0x00005555559b03ea in perf_evsel__close_fd_cpu (evsel=0x5555560951a0, cpu=1) at evsel.c:166
166 if (FD(evsel, cpu, thread) >= 0)
v3. fixes a bug in perf_evsel__run_ioctl where the sense of a branch was
backward.
Signed-off-by: Ian Rogers <irogers@google.com>
Acked-by: Jiri Olsa <jolsa@redhat.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lore.kernel.org/lkml/20210918054440.2350466-1-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-09-17 22:44:40 -07:00
|
|
|
if (fd == NULL || *fd < 0)
|
2021-04-14 11:07:37 -05:00
|
|
|
continue;
|
|
|
|
|
2022-01-04 22:13:30 -08:00
|
|
|
perf_mmap__munmap(MMAP(evsel, idx, thread));
|
2021-04-14 11:07:37 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
xyarray__delete(evsel->mmap);
|
|
|
|
evsel->mmap = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
int perf_evsel__mmap(struct perf_evsel *evsel, int pages)
|
|
|
|
{
|
2022-01-04 22:13:30 -08:00
|
|
|
int ret, idx, thread;
|
2021-04-14 11:07:37 -05:00
|
|
|
struct perf_mmap_param mp = {
|
|
|
|
.prot = PROT_READ | PROT_WRITE,
|
|
|
|
.mask = (pages * page_size) - 1,
|
|
|
|
};
|
|
|
|
|
|
|
|
if (evsel->fd == NULL || evsel->mmap)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (perf_evsel__alloc_mmap(evsel, xyarray__max_x(evsel->fd), xyarray__max_y(evsel->fd)) < 0)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2022-01-04 22:13:30 -08:00
|
|
|
for (idx = 0; idx < xyarray__max_x(evsel->fd); idx++) {
|
2021-04-14 11:07:37 -05:00
|
|
|
for (thread = 0; thread < xyarray__max_y(evsel->fd); thread++) {
|
2022-01-04 22:13:30 -08:00
|
|
|
int *fd = FD(evsel, idx, thread);
|
libperf evsel: Make use of FD robust.
FD uses xyarray__entry that may return NULL if an index is out of
bounds. If NULL is returned then a segv happens as FD unconditionally
dereferences the pointer. This was happening in a case of with perf
iostat as shown below. The fix is to make FD an "int*" rather than an
int and handle the NULL case as either invalid input or a closed fd.
$ sudo gdb --args perf stat --iostat list
...
Breakpoint 1, perf_evsel__alloc_fd (evsel=0x5555560951a0, ncpus=1, nthreads=1) at evsel.c:50
50 {
(gdb) bt
#0 perf_evsel__alloc_fd (evsel=0x5555560951a0, ncpus=1, nthreads=1) at evsel.c:50
#1 0x000055555585c188 in evsel__open_cpu (evsel=0x5555560951a0, cpus=0x555556093410,
threads=0x555556086fb0, start_cpu=0, end_cpu=1) at util/evsel.c:1792
#2 0x000055555585cfb2 in evsel__open (evsel=0x5555560951a0, cpus=0x0, threads=0x555556086fb0)
at util/evsel.c:2045
#3 0x000055555585d0db in evsel__open_per_thread (evsel=0x5555560951a0, threads=0x555556086fb0)
at util/evsel.c:2065
#4 0x00005555558ece64 in create_perf_stat_counter (evsel=0x5555560951a0,
config=0x555555c34700 <stat_config>, target=0x555555c2f1c0 <target>, cpu=0) at util/stat.c:590
#5 0x000055555578e927 in __run_perf_stat (argc=1, argv=0x7fffffffe4a0, run_idx=0)
at builtin-stat.c:833
#6 0x000055555578f3c6 in run_perf_stat (argc=1, argv=0x7fffffffe4a0, run_idx=0)
at builtin-stat.c:1048
#7 0x0000555555792ee5 in cmd_stat (argc=1, argv=0x7fffffffe4a0) at builtin-stat.c:2534
#8 0x0000555555835ed3 in run_builtin (p=0x555555c3f540 <commands+288>, argc=3,
argv=0x7fffffffe4a0) at perf.c:313
#9 0x0000555555836154 in handle_internal_command (argc=3, argv=0x7fffffffe4a0) at perf.c:365
#10 0x000055555583629f in run_argv (argcp=0x7fffffffe2ec, argv=0x7fffffffe2e0) at perf.c:409
#11 0x0000555555836692 in main (argc=3, argv=0x7fffffffe4a0) at perf.c:539
...
(gdb) c
Continuing.
Error:
The sys_perf_event_open() syscall returned with 22 (Invalid argument) for event (uncore_iio_0/event=0x83,umask=0x04,ch_mask=0xF,fc_mask=0x07/).
/bin/dmesg | grep -i perf may provide additional information.
Program received signal SIGSEGV, Segmentation fault.
0x00005555559b03ea in perf_evsel__close_fd_cpu (evsel=0x5555560951a0, cpu=1) at evsel.c:166
166 if (FD(evsel, cpu, thread) >= 0)
v3. fixes a bug in perf_evsel__run_ioctl where the sense of a branch was
backward.
Signed-off-by: Ian Rogers <irogers@google.com>
Acked-by: Jiri Olsa <jolsa@redhat.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lore.kernel.org/lkml/20210918054440.2350466-1-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-09-17 22:44:40 -07:00
|
|
|
struct perf_mmap *map;
|
2022-01-04 22:13:51 -08:00
|
|
|
struct perf_cpu cpu = perf_cpu_map__cpu(evsel->cpus, idx);
|
2021-04-14 11:07:37 -05:00
|
|
|
|
libperf evsel: Make use of FD robust.
FD uses xyarray__entry that may return NULL if an index is out of
bounds. If NULL is returned then a segv happens as FD unconditionally
dereferences the pointer. This was happening in a case of with perf
iostat as shown below. The fix is to make FD an "int*" rather than an
int and handle the NULL case as either invalid input or a closed fd.
$ sudo gdb --args perf stat --iostat list
...
Breakpoint 1, perf_evsel__alloc_fd (evsel=0x5555560951a0, ncpus=1, nthreads=1) at evsel.c:50
50 {
(gdb) bt
#0 perf_evsel__alloc_fd (evsel=0x5555560951a0, ncpus=1, nthreads=1) at evsel.c:50
#1 0x000055555585c188 in evsel__open_cpu (evsel=0x5555560951a0, cpus=0x555556093410,
threads=0x555556086fb0, start_cpu=0, end_cpu=1) at util/evsel.c:1792
#2 0x000055555585cfb2 in evsel__open (evsel=0x5555560951a0, cpus=0x0, threads=0x555556086fb0)
at util/evsel.c:2045
#3 0x000055555585d0db in evsel__open_per_thread (evsel=0x5555560951a0, threads=0x555556086fb0)
at util/evsel.c:2065
#4 0x00005555558ece64 in create_perf_stat_counter (evsel=0x5555560951a0,
config=0x555555c34700 <stat_config>, target=0x555555c2f1c0 <target>, cpu=0) at util/stat.c:590
#5 0x000055555578e927 in __run_perf_stat (argc=1, argv=0x7fffffffe4a0, run_idx=0)
at builtin-stat.c:833
#6 0x000055555578f3c6 in run_perf_stat (argc=1, argv=0x7fffffffe4a0, run_idx=0)
at builtin-stat.c:1048
#7 0x0000555555792ee5 in cmd_stat (argc=1, argv=0x7fffffffe4a0) at builtin-stat.c:2534
#8 0x0000555555835ed3 in run_builtin (p=0x555555c3f540 <commands+288>, argc=3,
argv=0x7fffffffe4a0) at perf.c:313
#9 0x0000555555836154 in handle_internal_command (argc=3, argv=0x7fffffffe4a0) at perf.c:365
#10 0x000055555583629f in run_argv (argcp=0x7fffffffe2ec, argv=0x7fffffffe2e0) at perf.c:409
#11 0x0000555555836692 in main (argc=3, argv=0x7fffffffe4a0) at perf.c:539
...
(gdb) c
Continuing.
Error:
The sys_perf_event_open() syscall returned with 22 (Invalid argument) for event (uncore_iio_0/event=0x83,umask=0x04,ch_mask=0xF,fc_mask=0x07/).
/bin/dmesg | grep -i perf may provide additional information.
Program received signal SIGSEGV, Segmentation fault.
0x00005555559b03ea in perf_evsel__close_fd_cpu (evsel=0x5555560951a0, cpu=1) at evsel.c:166
166 if (FD(evsel, cpu, thread) >= 0)
v3. fixes a bug in perf_evsel__run_ioctl where the sense of a branch was
backward.
Signed-off-by: Ian Rogers <irogers@google.com>
Acked-by: Jiri Olsa <jolsa@redhat.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lore.kernel.org/lkml/20210918054440.2350466-1-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-09-17 22:44:40 -07:00
|
|
|
if (fd == NULL || *fd < 0)
|
2021-04-14 11:07:37 -05:00
|
|
|
continue;
|
|
|
|
|
2022-01-04 22:13:30 -08:00
|
|
|
map = MMAP(evsel, idx, thread);
|
2021-04-14 11:07:37 -05:00
|
|
|
perf_mmap__init(map, NULL, false, NULL);
|
|
|
|
|
2022-01-04 22:13:31 -08:00
|
|
|
ret = perf_mmap__mmap(map, &mp, *fd, cpu);
|
2021-04-14 11:07:37 -05:00
|
|
|
if (ret) {
|
|
|
|
perf_evsel__munmap(evsel);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-01-04 22:13:30 -08:00
|
|
|
void *perf_evsel__mmap_base(struct perf_evsel *evsel, int cpu_map_idx, int thread)
|
2021-04-14 11:07:37 -05:00
|
|
|
{
|
2022-01-04 22:13:30 -08:00
|
|
|
int *fd = FD(evsel, cpu_map_idx, thread);
|
libperf evsel: Make use of FD robust.
FD uses xyarray__entry that may return NULL if an index is out of
bounds. If NULL is returned then a segv happens as FD unconditionally
dereferences the pointer. This was happening in a case of with perf
iostat as shown below. The fix is to make FD an "int*" rather than an
int and handle the NULL case as either invalid input or a closed fd.
$ sudo gdb --args perf stat --iostat list
...
Breakpoint 1, perf_evsel__alloc_fd (evsel=0x5555560951a0, ncpus=1, nthreads=1) at evsel.c:50
50 {
(gdb) bt
#0 perf_evsel__alloc_fd (evsel=0x5555560951a0, ncpus=1, nthreads=1) at evsel.c:50
#1 0x000055555585c188 in evsel__open_cpu (evsel=0x5555560951a0, cpus=0x555556093410,
threads=0x555556086fb0, start_cpu=0, end_cpu=1) at util/evsel.c:1792
#2 0x000055555585cfb2 in evsel__open (evsel=0x5555560951a0, cpus=0x0, threads=0x555556086fb0)
at util/evsel.c:2045
#3 0x000055555585d0db in evsel__open_per_thread (evsel=0x5555560951a0, threads=0x555556086fb0)
at util/evsel.c:2065
#4 0x00005555558ece64 in create_perf_stat_counter (evsel=0x5555560951a0,
config=0x555555c34700 <stat_config>, target=0x555555c2f1c0 <target>, cpu=0) at util/stat.c:590
#5 0x000055555578e927 in __run_perf_stat (argc=1, argv=0x7fffffffe4a0, run_idx=0)
at builtin-stat.c:833
#6 0x000055555578f3c6 in run_perf_stat (argc=1, argv=0x7fffffffe4a0, run_idx=0)
at builtin-stat.c:1048
#7 0x0000555555792ee5 in cmd_stat (argc=1, argv=0x7fffffffe4a0) at builtin-stat.c:2534
#8 0x0000555555835ed3 in run_builtin (p=0x555555c3f540 <commands+288>, argc=3,
argv=0x7fffffffe4a0) at perf.c:313
#9 0x0000555555836154 in handle_internal_command (argc=3, argv=0x7fffffffe4a0) at perf.c:365
#10 0x000055555583629f in run_argv (argcp=0x7fffffffe2ec, argv=0x7fffffffe2e0) at perf.c:409
#11 0x0000555555836692 in main (argc=3, argv=0x7fffffffe4a0) at perf.c:539
...
(gdb) c
Continuing.
Error:
The sys_perf_event_open() syscall returned with 22 (Invalid argument) for event (uncore_iio_0/event=0x83,umask=0x04,ch_mask=0xF,fc_mask=0x07/).
/bin/dmesg | grep -i perf may provide additional information.
Program received signal SIGSEGV, Segmentation fault.
0x00005555559b03ea in perf_evsel__close_fd_cpu (evsel=0x5555560951a0, cpu=1) at evsel.c:166
166 if (FD(evsel, cpu, thread) >= 0)
v3. fixes a bug in perf_evsel__run_ioctl where the sense of a branch was
backward.
Signed-off-by: Ian Rogers <irogers@google.com>
Acked-by: Jiri Olsa <jolsa@redhat.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lore.kernel.org/lkml/20210918054440.2350466-1-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-09-17 22:44:40 -07:00
|
|
|
|
2022-01-04 22:13:30 -08:00
|
|
|
if (fd == NULL || *fd < 0 || MMAP(evsel, cpu_map_idx, thread) == NULL)
|
2021-04-14 11:07:37 -05:00
|
|
|
return NULL;
|
|
|
|
|
2022-01-04 22:13:30 -08:00
|
|
|
return MMAP(evsel, cpu_map_idx, thread)->base;
|
2021-04-14 11:07:37 -05:00
|
|
|
}
|
|
|
|
|
2019-07-21 13:24:51 +02:00
|
|
|
int perf_evsel__read_size(struct perf_evsel *evsel)
|
|
|
|
{
|
|
|
|
u64 read_format = evsel->attr.read_format;
|
|
|
|
int entry = sizeof(u64); /* value */
|
|
|
|
int size = 0;
|
|
|
|
int nr = 1;
|
|
|
|
|
|
|
|
if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
|
|
|
|
size += sizeof(u64);
|
|
|
|
|
|
|
|
if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
|
|
|
|
size += sizeof(u64);
|
|
|
|
|
|
|
|
if (read_format & PERF_FORMAT_ID)
|
|
|
|
entry += sizeof(u64);
|
|
|
|
|
2022-08-18 17:36:42 -07:00
|
|
|
if (read_format & PERF_FORMAT_LOST)
|
|
|
|
entry += sizeof(u64);
|
|
|
|
|
2019-07-21 13:24:51 +02:00
|
|
|
if (read_format & PERF_FORMAT_GROUP) {
|
|
|
|
nr = evsel->nr_members;
|
|
|
|
size += sizeof(u64);
|
|
|
|
}
|
|
|
|
|
|
|
|
size += entry * nr;
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2022-08-18 17:36:42 -07:00
|
|
|
/* This only reads values for the leader */
|
|
|
|
static int perf_evsel__read_group(struct perf_evsel *evsel, int cpu_map_idx,
|
|
|
|
int thread, struct perf_counts_values *count)
|
|
|
|
{
|
|
|
|
size_t size = perf_evsel__read_size(evsel);
|
|
|
|
int *fd = FD(evsel, cpu_map_idx, thread);
|
|
|
|
u64 read_format = evsel->attr.read_format;
|
|
|
|
u64 *data;
|
|
|
|
int idx = 1;
|
|
|
|
|
|
|
|
if (fd == NULL || *fd < 0)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
data = calloc(1, size);
|
|
|
|
if (data == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
if (readn(*fd, data, size) <= 0) {
|
|
|
|
free(data);
|
|
|
|
return -errno;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This reads only the leader event intentionally since we don't have
|
|
|
|
* perf counts values for sibling events.
|
|
|
|
*/
|
|
|
|
if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
|
|
|
|
count->ena = data[idx++];
|
|
|
|
if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
|
|
|
|
count->run = data[idx++];
|
|
|
|
|
|
|
|
/* value is always available */
|
|
|
|
count->val = data[idx++];
|
|
|
|
if (read_format & PERF_FORMAT_ID)
|
|
|
|
count->id = data[idx++];
|
|
|
|
if (read_format & PERF_FORMAT_LOST)
|
|
|
|
count->lost = data[idx++];
|
|
|
|
|
|
|
|
free(data);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The perf read format is very flexible. It needs to set the proper
|
|
|
|
* values according to the read format.
|
|
|
|
*/
|
|
|
|
static void perf_evsel__adjust_values(struct perf_evsel *evsel, u64 *buf,
|
|
|
|
struct perf_counts_values *count)
|
|
|
|
{
|
|
|
|
u64 read_format = evsel->attr.read_format;
|
|
|
|
int n = 0;
|
|
|
|
|
|
|
|
count->val = buf[n++];
|
|
|
|
|
|
|
|
if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
|
|
|
|
count->ena = buf[n++];
|
|
|
|
|
|
|
|
if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
|
|
|
|
count->run = buf[n++];
|
|
|
|
|
|
|
|
if (read_format & PERF_FORMAT_ID)
|
|
|
|
count->id = buf[n++];
|
|
|
|
|
|
|
|
if (read_format & PERF_FORMAT_LOST)
|
|
|
|
count->lost = buf[n++];
|
|
|
|
}
|
|
|
|
|
2022-01-04 22:13:30 -08:00
|
|
|
int perf_evsel__read(struct perf_evsel *evsel, int cpu_map_idx, int thread,
|
2019-07-21 13:24:51 +02:00
|
|
|
struct perf_counts_values *count)
|
|
|
|
{
|
|
|
|
size_t size = perf_evsel__read_size(evsel);
|
2022-01-04 22:13:30 -08:00
|
|
|
int *fd = FD(evsel, cpu_map_idx, thread);
|
2022-08-18 17:36:42 -07:00
|
|
|
u64 read_format = evsel->attr.read_format;
|
|
|
|
struct perf_counts_values buf;
|
2019-07-21 13:24:51 +02:00
|
|
|
|
|
|
|
memset(count, 0, sizeof(*count));
|
|
|
|
|
libperf evsel: Make use of FD robust.
FD uses xyarray__entry that may return NULL if an index is out of
bounds. If NULL is returned then a segv happens as FD unconditionally
dereferences the pointer. This was happening in a case of with perf
iostat as shown below. The fix is to make FD an "int*" rather than an
int and handle the NULL case as either invalid input or a closed fd.
$ sudo gdb --args perf stat --iostat list
...
Breakpoint 1, perf_evsel__alloc_fd (evsel=0x5555560951a0, ncpus=1, nthreads=1) at evsel.c:50
50 {
(gdb) bt
#0 perf_evsel__alloc_fd (evsel=0x5555560951a0, ncpus=1, nthreads=1) at evsel.c:50
#1 0x000055555585c188 in evsel__open_cpu (evsel=0x5555560951a0, cpus=0x555556093410,
threads=0x555556086fb0, start_cpu=0, end_cpu=1) at util/evsel.c:1792
#2 0x000055555585cfb2 in evsel__open (evsel=0x5555560951a0, cpus=0x0, threads=0x555556086fb0)
at util/evsel.c:2045
#3 0x000055555585d0db in evsel__open_per_thread (evsel=0x5555560951a0, threads=0x555556086fb0)
at util/evsel.c:2065
#4 0x00005555558ece64 in create_perf_stat_counter (evsel=0x5555560951a0,
config=0x555555c34700 <stat_config>, target=0x555555c2f1c0 <target>, cpu=0) at util/stat.c:590
#5 0x000055555578e927 in __run_perf_stat (argc=1, argv=0x7fffffffe4a0, run_idx=0)
at builtin-stat.c:833
#6 0x000055555578f3c6 in run_perf_stat (argc=1, argv=0x7fffffffe4a0, run_idx=0)
at builtin-stat.c:1048
#7 0x0000555555792ee5 in cmd_stat (argc=1, argv=0x7fffffffe4a0) at builtin-stat.c:2534
#8 0x0000555555835ed3 in run_builtin (p=0x555555c3f540 <commands+288>, argc=3,
argv=0x7fffffffe4a0) at perf.c:313
#9 0x0000555555836154 in handle_internal_command (argc=3, argv=0x7fffffffe4a0) at perf.c:365
#10 0x000055555583629f in run_argv (argcp=0x7fffffffe2ec, argv=0x7fffffffe2e0) at perf.c:409
#11 0x0000555555836692 in main (argc=3, argv=0x7fffffffe4a0) at perf.c:539
...
(gdb) c
Continuing.
Error:
The sys_perf_event_open() syscall returned with 22 (Invalid argument) for event (uncore_iio_0/event=0x83,umask=0x04,ch_mask=0xF,fc_mask=0x07/).
/bin/dmesg | grep -i perf may provide additional information.
Program received signal SIGSEGV, Segmentation fault.
0x00005555559b03ea in perf_evsel__close_fd_cpu (evsel=0x5555560951a0, cpu=1) at evsel.c:166
166 if (FD(evsel, cpu, thread) >= 0)
v3. fixes a bug in perf_evsel__run_ioctl where the sense of a branch was
backward.
Signed-off-by: Ian Rogers <irogers@google.com>
Acked-by: Jiri Olsa <jolsa@redhat.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lore.kernel.org/lkml/20210918054440.2350466-1-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-09-17 22:44:40 -07:00
|
|
|
if (fd == NULL || *fd < 0)
|
2019-07-21 13:24:51 +02:00
|
|
|
return -EINVAL;
|
|
|
|
|
2022-08-18 17:36:42 -07:00
|
|
|
if (read_format & PERF_FORMAT_GROUP)
|
|
|
|
return perf_evsel__read_group(evsel, cpu_map_idx, thread, count);
|
|
|
|
|
2022-01-04 22:13:30 -08:00
|
|
|
if (MMAP(evsel, cpu_map_idx, thread) &&
|
2022-08-18 17:36:42 -07:00
|
|
|
!(read_format & (PERF_FORMAT_ID | PERF_FORMAT_LOST)) &&
|
2022-01-04 22:13:30 -08:00
|
|
|
!perf_mmap__read_self(MMAP(evsel, cpu_map_idx, thread), count))
|
libperf: Add support for user space counter access
x86 and arm64 can both support direct access of event counters in
userspace. The access sequence is less than trivial and currently exists
in perf test code (tools/perf/arch/x86/tests/rdpmc.c) with copies in
projects such as PAPI and libpfm4.
In order to support userspace access, an event must be mmapped first
with perf_evsel__mmap(). Then subsequent calls to perf_evsel__read()
will use the fast path (assuming the arch supports it).
Committer notes:
Added a '__maybe_unused' attribute to the read_perf_counter() argument
to fix the build on arches other than x86_64 and arm.
Committer testing:
Building and running the libperf tests in verbose mode (V=1) now shows
those "loop = N, count = N" extra lines, testing user space counter
access.
# make V=1 -C tools/lib/perf tests
make: Entering directory '/home/acme/git/perf/tools/lib/perf'
make -f /home/acme/git/perf/tools/build/Makefile.build dir=. obj=libperf
make -C /home/acme/git/perf/tools/lib/api/ O= libapi.a
make -f /home/acme/git/perf/tools/build/Makefile.build dir=./fd obj=libapi
make -f /home/acme/git/perf/tools/build/Makefile.build dir=./fs obj=libapi
make -C tests
gcc -I/home/acme/git/perf/tools/lib/perf/include -I/home/acme/git/perf/tools/include -I/home/acme/git/perf/tools/lib -g -Wall -o test-cpumap-a test-cpumap.c ../libperf.a /home/acme/git/perf/tools/lib/api/libapi.a
gcc -I/home/acme/git/perf/tools/lib/perf/include -I/home/acme/git/perf/tools/include -I/home/acme/git/perf/tools/lib -g -Wall -o test-threadmap-a test-threadmap.c ../libperf.a /home/acme/git/perf/tools/lib/api/libapi.a
gcc -I/home/acme/git/perf/tools/lib/perf/include -I/home/acme/git/perf/tools/include -I/home/acme/git/perf/tools/lib -g -Wall -o test-evlist-a test-evlist.c ../libperf.a /home/acme/git/perf/tools/lib/api/libapi.a
gcc -I/home/acme/git/perf/tools/lib/perf/include -I/home/acme/git/perf/tools/include -I/home/acme/git/perf/tools/lib -g -Wall -o test-evsel-a test-evsel.c ../libperf.a /home/acme/git/perf/tools/lib/api/libapi.a
gcc -I/home/acme/git/perf/tools/lib/perf/include -I/home/acme/git/perf/tools/include -I/home/acme/git/perf/tools/lib -g -Wall -L.. -o test-cpumap-so test-cpumap.c /home/acme/git/perf/tools/lib/api/libapi.a -lperf
gcc -I/home/acme/git/perf/tools/lib/perf/include -I/home/acme/git/perf/tools/include -I/home/acme/git/perf/tools/lib -g -Wall -L.. -o test-threadmap-so test-threadmap.c /home/acme/git/perf/tools/lib/api/libapi.a -lperf
gcc -I/home/acme/git/perf/tools/lib/perf/include -I/home/acme/git/perf/tools/include -I/home/acme/git/perf/tools/lib -g -Wall -L.. -o test-evlist-so test-evlist.c /home/acme/git/perf/tools/lib/api/libapi.a -lperf
gcc -I/home/acme/git/perf/tools/lib/perf/include -I/home/acme/git/perf/tools/include -I/home/acme/git/perf/tools/lib -g -Wall -L.. -o test-evsel-so test-evsel.c /home/acme/git/perf/tools/lib/api/libapi.a -lperf
make -C tests run
running static:
- running test-cpumap.c...OK
- running test-threadmap.c...OK
- running test-evlist.c...OK
- running test-evsel.c...
loop = 65536, count = 333926
loop = 131072, count = 655781
loop = 262144, count = 1311141
loop = 524288, count = 2630126
loop = 1048576, count = 5256955
loop = 65536, count = 524594
loop = 131072, count = 1058916
loop = 262144, count = 2097458
loop = 524288, count = 4205429
loop = 1048576, count = 8406606
OK
running dynamic:
- running test-cpumap.c...OK
- running test-threadmap.c...OK
- running test-evlist.c...OK
- running test-evsel.c...
loop = 65536, count = 328102
loop = 131072, count = 655782
loop = 262144, count = 1317494
loop = 524288, count = 2627851
loop = 1048576, count = 5255187
loop = 65536, count = 524601
loop = 131072, count = 1048923
loop = 262144, count = 2107917
loop = 524288, count = 4194606
loop = 1048576, count = 8409322
OK
make: Leaving directory '/home/acme/git/perf/tools/lib/perf'
#
Signed-off-by: Rob Herring <robh@kernel.org>
Acked-by: Jiri Olsa <jolsa@redhat.com>
Acked-by: Namhyung Kim <namhyung@kernel.org>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Itaru Kitayama <itaru.kitayama@gmail.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Will Deacon <will@kernel.org>
Link: http://lore.kernel.org/lkml/20210414155412.3697605-4-robh@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2021-04-14 11:07:39 -05:00
|
|
|
return 0;
|
|
|
|
|
2022-08-18 17:36:42 -07:00
|
|
|
if (readn(*fd, buf.values, size) <= 0)
|
2019-07-21 13:24:51 +02:00
|
|
|
return -errno;
|
|
|
|
|
2022-08-18 17:36:42 -07:00
|
|
|
perf_evsel__adjust_values(evsel, buf.values, count);
|
2019-07-21 13:24:51 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2019-07-21 13:24:52 +02:00
|
|
|
|
2022-04-22 19:23:42 +03:00
|
|
|
static int perf_evsel__ioctl(struct perf_evsel *evsel, int ioc, void *arg,
|
|
|
|
int cpu_map_idx, int thread)
|
|
|
|
{
|
|
|
|
int *fd = FD(evsel, cpu_map_idx, thread);
|
|
|
|
|
|
|
|
if (fd == NULL || *fd < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return ioctl(*fd, ioc, arg);
|
|
|
|
}
|
|
|
|
|
2019-07-21 13:24:52 +02:00
|
|
|
static int perf_evsel__run_ioctl(struct perf_evsel *evsel,
|
2019-11-20 16:15:21 -08:00
|
|
|
int ioc, void *arg,
|
2022-01-04 22:13:30 -08:00
|
|
|
int cpu_map_idx)
|
2019-07-21 13:24:52 +02:00
|
|
|
{
|
2019-11-20 16:15:21 -08:00
|
|
|
int thread;
|
2019-07-21 13:24:52 +02:00
|
|
|
|
2019-11-20 16:15:21 -08:00
|
|
|
for (thread = 0; thread < xyarray__max_y(evsel->fd); thread++) {
|
2022-04-22 19:23:42 +03:00
|
|
|
int err = perf_evsel__ioctl(evsel, ioc, arg, cpu_map_idx, thread);
|
2019-07-21 13:24:52 +02:00
|
|
|
|
2019-11-20 16:15:21 -08:00
|
|
|
if (err)
|
|
|
|
return err;
|
2019-07-21 13:24:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-01-04 22:13:30 -08:00
|
|
|
int perf_evsel__enable_cpu(struct perf_evsel *evsel, int cpu_map_idx)
|
2019-11-20 16:15:21 -08:00
|
|
|
{
|
2022-01-04 22:13:30 -08:00
|
|
|
return perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_ENABLE, NULL, cpu_map_idx);
|
2019-11-20 16:15:21 -08:00
|
|
|
}
|
|
|
|
|
2022-05-06 15:25:40 +03:00
|
|
|
int perf_evsel__enable_thread(struct perf_evsel *evsel, int thread)
|
|
|
|
{
|
|
|
|
struct perf_cpu cpu __maybe_unused;
|
|
|
|
int idx;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
perf_cpu_map__for_each_cpu(cpu, idx, evsel->cpus) {
|
|
|
|
err = perf_evsel__ioctl(evsel, PERF_EVENT_IOC_ENABLE, NULL, idx, thread);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-07-21 13:24:52 +02:00
|
|
|
int perf_evsel__enable(struct perf_evsel *evsel)
|
|
|
|
{
|
2019-11-20 16:15:21 -08:00
|
|
|
int i;
|
|
|
|
int err = 0;
|
|
|
|
|
|
|
|
for (i = 0; i < xyarray__max_x(evsel->fd) && !err; i++)
|
|
|
|
err = perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_ENABLE, NULL, i);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2022-01-04 22:13:30 -08:00
|
|
|
int perf_evsel__disable_cpu(struct perf_evsel *evsel, int cpu_map_idx)
|
2019-11-20 16:15:21 -08:00
|
|
|
{
|
2022-01-04 22:13:30 -08:00
|
|
|
return perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_DISABLE, NULL, cpu_map_idx);
|
2019-07-21 13:24:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int perf_evsel__disable(struct perf_evsel *evsel)
|
|
|
|
{
|
2019-11-20 16:15:21 -08:00
|
|
|
int i;
|
|
|
|
int err = 0;
|
|
|
|
|
|
|
|
for (i = 0; i < xyarray__max_x(evsel->fd) && !err; i++)
|
|
|
|
err = perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_DISABLE, NULL, i);
|
|
|
|
return err;
|
2019-07-21 13:24:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int perf_evsel__apply_filter(struct perf_evsel *evsel, const char *filter)
|
|
|
|
{
|
2019-11-20 16:15:21 -08:00
|
|
|
int err = 0, i;
|
|
|
|
|
2022-01-21 20:58:10 -08:00
|
|
|
for (i = 0; i < perf_cpu_map__nr(evsel->cpus) && !err; i++)
|
2019-11-20 16:15:21 -08:00
|
|
|
err = perf_evsel__run_ioctl(evsel,
|
2019-07-21 13:24:52 +02:00
|
|
|
PERF_EVENT_IOC_SET_FILTER,
|
2019-11-20 16:15:21 -08:00
|
|
|
(void *)filter, i);
|
|
|
|
return err;
|
2019-07-21 13:24:52 +02:00
|
|
|
}
|
2019-07-21 13:24:54 +02:00
|
|
|
|
|
|
|
struct perf_cpu_map *perf_evsel__cpus(struct perf_evsel *evsel)
|
|
|
|
{
|
|
|
|
return evsel->cpus;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct perf_thread_map *perf_evsel__threads(struct perf_evsel *evsel)
|
|
|
|
{
|
|
|
|
return evsel->threads;
|
|
|
|
}
|
2019-07-21 13:24:57 +02:00
|
|
|
|
|
|
|
struct perf_event_attr *perf_evsel__attr(struct perf_evsel *evsel)
|
|
|
|
{
|
|
|
|
return &evsel->attr;
|
|
|
|
}
|
2019-09-03 10:34:29 +02:00
|
|
|
|
|
|
|
int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads)
|
|
|
|
{
|
|
|
|
if (ncpus == 0 || nthreads == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
evsel->sample_id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id));
|
|
|
|
if (evsel->sample_id == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
evsel->id = zalloc(ncpus * nthreads * sizeof(u64));
|
|
|
|
if (evsel->id == NULL) {
|
|
|
|
xyarray__delete(evsel->sample_id);
|
|
|
|
evsel->sample_id = NULL;
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void perf_evsel__free_id(struct perf_evsel *evsel)
|
|
|
|
{
|
|
|
|
xyarray__delete(evsel->sample_id);
|
|
|
|
evsel->sample_id = NULL;
|
|
|
|
zfree(&evsel->id);
|
|
|
|
evsel->ids = 0;
|
|
|
|
}
|
2021-11-09 17:58:29 +09:00
|
|
|
|
|
|
|
void perf_counts_values__scale(struct perf_counts_values *count,
|
|
|
|
bool scale, __s8 *pscaled)
|
|
|
|
{
|
|
|
|
s8 scaled = 0;
|
|
|
|
|
|
|
|
if (scale) {
|
|
|
|
if (count->run == 0) {
|
|
|
|
scaled = -1;
|
|
|
|
count->val = 0;
|
|
|
|
} else if (count->run < count->ena) {
|
|
|
|
scaled = 1;
|
|
|
|
count->val = (u64)((double)count->val * count->ena / count->run);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pscaled)
|
|
|
|
*pscaled = scaled;
|
|
|
|
}
|