Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/jolsa/perf into perf/core
Pull perf/core improvements and fixes from Jiri Olsa: . Update attr test with PERF_FLAG_FD_CLOEXEC flag (Jiri Olsa) . Enable close-on-exec flag on perf file descriptor (Yann Droneaud) Signed-off-by: Jiri Olsa <jolsa@kernel.org> Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
@@ -376,6 +376,7 @@ LIB_OBJS += $(OUTPUT)util/record.o
|
|||||||
LIB_OBJS += $(OUTPUT)util/srcline.o
|
LIB_OBJS += $(OUTPUT)util/srcline.o
|
||||||
LIB_OBJS += $(OUTPUT)util/data.o
|
LIB_OBJS += $(OUTPUT)util/data.o
|
||||||
LIB_OBJS += $(OUTPUT)util/tsc.o
|
LIB_OBJS += $(OUTPUT)util/tsc.o
|
||||||
|
LIB_OBJS += $(OUTPUT)util/cloexec.o
|
||||||
|
|
||||||
LIB_OBJS += $(OUTPUT)ui/setup.o
|
LIB_OBJS += $(OUTPUT)ui/setup.o
|
||||||
LIB_OBJS += $(OUTPUT)ui/helpline.o
|
LIB_OBJS += $(OUTPUT)ui/helpline.o
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include "../util/util.h"
|
#include "../util/util.h"
|
||||||
#include "../util/parse-options.h"
|
#include "../util/parse-options.h"
|
||||||
#include "../util/header.h"
|
#include "../util/header.h"
|
||||||
|
#include "../util/cloexec.h"
|
||||||
#include "bench.h"
|
#include "bench.h"
|
||||||
#include "mem-memcpy-arch.h"
|
#include "mem-memcpy-arch.h"
|
||||||
|
|
||||||
@@ -83,7 +84,8 @@ static struct perf_event_attr cycle_attr = {
|
|||||||
|
|
||||||
static void init_cycle(void)
|
static void init_cycle(void)
|
||||||
{
|
{
|
||||||
cycle_fd = sys_perf_event_open(&cycle_attr, getpid(), -1, -1, 0);
|
cycle_fd = sys_perf_event_open(&cycle_attr, getpid(), -1, -1,
|
||||||
|
perf_event_open_cloexec_flag());
|
||||||
|
|
||||||
if (cycle_fd < 0 && errno == ENOSYS)
|
if (cycle_fd < 0 && errno == ENOSYS)
|
||||||
die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
|
die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include "../util/util.h"
|
#include "../util/util.h"
|
||||||
#include "../util/parse-options.h"
|
#include "../util/parse-options.h"
|
||||||
#include "../util/header.h"
|
#include "../util/header.h"
|
||||||
|
#include "../util/cloexec.h"
|
||||||
#include "bench.h"
|
#include "bench.h"
|
||||||
#include "mem-memset-arch.h"
|
#include "mem-memset-arch.h"
|
||||||
|
|
||||||
@@ -83,7 +84,8 @@ static struct perf_event_attr cycle_attr = {
|
|||||||
|
|
||||||
static void init_cycle(void)
|
static void init_cycle(void)
|
||||||
{
|
{
|
||||||
cycle_fd = sys_perf_event_open(&cycle_attr, getpid(), -1, -1, 0);
|
cycle_fd = sys_perf_event_open(&cycle_attr, getpid(), -1, -1,
|
||||||
|
perf_event_open_cloexec_flag());
|
||||||
|
|
||||||
if (cycle_fd < 0 && errno == ENOSYS)
|
if (cycle_fd < 0 && errno == ENOSYS)
|
||||||
die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
|
die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include "util/header.h"
|
#include "util/header.h"
|
||||||
#include "util/session.h"
|
#include "util/session.h"
|
||||||
#include "util/tool.h"
|
#include "util/tool.h"
|
||||||
|
#include "util/cloexec.h"
|
||||||
|
|
||||||
#include "util/parse-options.h"
|
#include "util/parse-options.h"
|
||||||
#include "util/trace-event.h"
|
#include "util/trace-event.h"
|
||||||
@@ -434,7 +435,8 @@ static int self_open_counters(void)
|
|||||||
attr.type = PERF_TYPE_SOFTWARE;
|
attr.type = PERF_TYPE_SOFTWARE;
|
||||||
attr.config = PERF_COUNT_SW_TASK_CLOCK;
|
attr.config = PERF_COUNT_SW_TASK_CLOCK;
|
||||||
|
|
||||||
fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
|
fd = sys_perf_event_open(&attr, 0, -1, -1,
|
||||||
|
perf_event_open_cloexec_flag());
|
||||||
|
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
pr_err("Error: sys_perf_event_open() syscall returned "
|
pr_err("Error: sys_perf_event_open() syscall returned "
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
[event]
|
[event]
|
||||||
fd=1
|
fd=1
|
||||||
group_fd=-1
|
group_fd=-1
|
||||||
flags=0
|
# 0 or PERF_FLAG_FD_CLOEXEC flag
|
||||||
|
flags=0|8
|
||||||
cpu=*
|
cpu=*
|
||||||
type=0|1
|
type=0|1
|
||||||
size=96
|
size=96
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
[event]
|
[event]
|
||||||
fd=1
|
fd=1
|
||||||
group_fd=-1
|
group_fd=-1
|
||||||
flags=0
|
# 0 or PERF_FLAG_FD_CLOEXEC flag
|
||||||
|
flags=0|8
|
||||||
cpu=*
|
cpu=*
|
||||||
type=0
|
type=0
|
||||||
size=96
|
size=96
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
#include "tests.h"
|
#include "tests.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "perf.h"
|
#include "perf.h"
|
||||||
|
#include "cloexec.h"
|
||||||
|
|
||||||
static int fd1;
|
static int fd1;
|
||||||
static int fd2;
|
static int fd2;
|
||||||
@@ -78,7 +79,8 @@ static int bp_event(void *fn, int setup_signal)
|
|||||||
pe.exclude_kernel = 1;
|
pe.exclude_kernel = 1;
|
||||||
pe.exclude_hv = 1;
|
pe.exclude_hv = 1;
|
||||||
|
|
||||||
fd = sys_perf_event_open(&pe, 0, -1, -1, 0);
|
fd = sys_perf_event_open(&pe, 0, -1, -1,
|
||||||
|
perf_event_open_cloexec_flag());
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
pr_debug("failed opening event %llx\n", pe.config);
|
pr_debug("failed opening event %llx\n", pe.config);
|
||||||
return TEST_FAIL;
|
return TEST_FAIL;
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
#include "tests.h"
|
#include "tests.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "perf.h"
|
#include "perf.h"
|
||||||
|
#include "cloexec.h"
|
||||||
|
|
||||||
static int overflows;
|
static int overflows;
|
||||||
|
|
||||||
@@ -91,7 +92,8 @@ int test__bp_signal_overflow(void)
|
|||||||
pe.exclude_kernel = 1;
|
pe.exclude_kernel = 1;
|
||||||
pe.exclude_hv = 1;
|
pe.exclude_hv = 1;
|
||||||
|
|
||||||
fd = sys_perf_event_open(&pe, 0, -1, -1, 0);
|
fd = sys_perf_event_open(&pe, 0, -1, -1,
|
||||||
|
perf_event_open_cloexec_flag());
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
pr_debug("failed opening event %llx\n", pe.config);
|
pr_debug("failed opening event %llx\n", pe.config);
|
||||||
return TEST_FAIL;
|
return TEST_FAIL;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include "perf.h"
|
#include "perf.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "tests.h"
|
#include "tests.h"
|
||||||
|
#include "cloexec.h"
|
||||||
|
|
||||||
#if defined(__x86_64__) || defined(__i386__)
|
#if defined(__x86_64__) || defined(__i386__)
|
||||||
|
|
||||||
@@ -104,7 +105,8 @@ static int __test__rdpmc(void)
|
|||||||
sa.sa_sigaction = segfault_handler;
|
sa.sa_sigaction = segfault_handler;
|
||||||
sigaction(SIGSEGV, &sa, NULL);
|
sigaction(SIGSEGV, &sa, NULL);
|
||||||
|
|
||||||
fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
|
fd = sys_perf_event_open(&attr, 0, -1, -1,
|
||||||
|
perf_event_open_cloexec_flag());
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
pr_err("Error: sys_perf_event_open() syscall returned "
|
pr_err("Error: sys_perf_event_open() syscall returned "
|
||||||
"with %d (%s)\n", fd, strerror(errno));
|
"with %d (%s)\n", fd, strerror(errno));
|
||||||
|
|||||||
57
tools/perf/util/cloexec.c
Normal file
57
tools/perf/util/cloexec.c
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
#include "util.h"
|
||||||
|
#include "../perf.h"
|
||||||
|
#include "cloexec.h"
|
||||||
|
#include "asm/bug.h"
|
||||||
|
|
||||||
|
static unsigned long flag = PERF_FLAG_FD_CLOEXEC;
|
||||||
|
|
||||||
|
static int perf_flag_probe(void)
|
||||||
|
{
|
||||||
|
/* use 'safest' configuration as used in perf_evsel__fallback() */
|
||||||
|
struct perf_event_attr attr = {
|
||||||
|
.type = PERF_COUNT_SW_CPU_CLOCK,
|
||||||
|
.config = PERF_COUNT_SW_CPU_CLOCK,
|
||||||
|
};
|
||||||
|
int fd;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
/* check cloexec flag */
|
||||||
|
fd = sys_perf_event_open(&attr, 0, -1, -1,
|
||||||
|
PERF_FLAG_FD_CLOEXEC);
|
||||||
|
err = errno;
|
||||||
|
|
||||||
|
if (fd >= 0) {
|
||||||
|
close(fd);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
WARN_ONCE(err != EINVAL,
|
||||||
|
"perf_event_open(..., PERF_FLAG_FD_CLOEXEC) failed with unexpected error %d (%s)\n",
|
||||||
|
err, strerror(err));
|
||||||
|
|
||||||
|
/* not supported, confirm error related to PERF_FLAG_FD_CLOEXEC */
|
||||||
|
fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
|
||||||
|
err = errno;
|
||||||
|
|
||||||
|
if (WARN_ONCE(fd < 0,
|
||||||
|
"perf_event_open(..., 0) failed unexpectedly with error %d (%s)\n",
|
||||||
|
err, strerror(err)))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long perf_event_open_cloexec_flag(void)
|
||||||
|
{
|
||||||
|
static bool probed;
|
||||||
|
|
||||||
|
if (!probed) {
|
||||||
|
if (perf_flag_probe() <= 0)
|
||||||
|
flag = 0;
|
||||||
|
probed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return flag;
|
||||||
|
}
|
||||||
6
tools/perf/util/cloexec.h
Normal file
6
tools/perf/util/cloexec.h
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#ifndef __PERF_CLOEXEC_H
|
||||||
|
#define __PERF_CLOEXEC_H
|
||||||
|
|
||||||
|
unsigned long perf_event_open_cloexec_flag(void);
|
||||||
|
|
||||||
|
#endif /* __PERF_CLOEXEC_H */
|
||||||
@@ -29,6 +29,7 @@ static struct {
|
|||||||
bool sample_id_all;
|
bool sample_id_all;
|
||||||
bool exclude_guest;
|
bool exclude_guest;
|
||||||
bool mmap2;
|
bool mmap2;
|
||||||
|
bool cloexec;
|
||||||
} perf_missing_features;
|
} perf_missing_features;
|
||||||
|
|
||||||
#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
|
#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
|
||||||
@@ -994,7 +995,7 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
|
|||||||
struct thread_map *threads)
|
struct thread_map *threads)
|
||||||
{
|
{
|
||||||
int cpu, thread;
|
int cpu, thread;
|
||||||
unsigned long flags = 0;
|
unsigned long flags = PERF_FLAG_FD_CLOEXEC;
|
||||||
int pid = -1, err;
|
int pid = -1, err;
|
||||||
enum { NO_CHANGE, SET_TO_MAX, INCREASED_MAX } set_rlimit = NO_CHANGE;
|
enum { NO_CHANGE, SET_TO_MAX, INCREASED_MAX } set_rlimit = NO_CHANGE;
|
||||||
|
|
||||||
@@ -1003,11 +1004,13 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
if (evsel->cgrp) {
|
if (evsel->cgrp) {
|
||||||
flags = PERF_FLAG_PID_CGROUP;
|
flags |= PERF_FLAG_PID_CGROUP;
|
||||||
pid = evsel->cgrp->fd;
|
pid = evsel->cgrp->fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
fallback_missing_features:
|
fallback_missing_features:
|
||||||
|
if (perf_missing_features.cloexec)
|
||||||
|
flags &= ~(unsigned long)PERF_FLAG_FD_CLOEXEC;
|
||||||
if (perf_missing_features.mmap2)
|
if (perf_missing_features.mmap2)
|
||||||
evsel->attr.mmap2 = 0;
|
evsel->attr.mmap2 = 0;
|
||||||
if (perf_missing_features.exclude_guest)
|
if (perf_missing_features.exclude_guest)
|
||||||
@@ -1076,7 +1079,10 @@ try_fallback:
|
|||||||
if (err != -EINVAL || cpu > 0 || thread > 0)
|
if (err != -EINVAL || cpu > 0 || thread > 0)
|
||||||
goto out_close;
|
goto out_close;
|
||||||
|
|
||||||
if (!perf_missing_features.mmap2 && evsel->attr.mmap2) {
|
if (!perf_missing_features.cloexec && (flags & PERF_FLAG_FD_CLOEXEC)) {
|
||||||
|
perf_missing_features.cloexec = true;
|
||||||
|
goto fallback_missing_features;
|
||||||
|
} else if (!perf_missing_features.mmap2 && evsel->attr.mmap2) {
|
||||||
perf_missing_features.mmap2 = true;
|
perf_missing_features.mmap2 = true;
|
||||||
goto fallback_missing_features;
|
goto fallback_missing_features;
|
||||||
} else if (!perf_missing_features.exclude_guest &&
|
} else if (!perf_missing_features.exclude_guest &&
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "parse-events.h"
|
#include "parse-events.h"
|
||||||
#include <api/fs/fs.h>
|
#include <api/fs/fs.h>
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "cloexec.h"
|
||||||
|
|
||||||
typedef void (*setup_probe_fn_t)(struct perf_evsel *evsel);
|
typedef void (*setup_probe_fn_t)(struct perf_evsel *evsel);
|
||||||
|
|
||||||
@@ -11,6 +12,7 @@ static int perf_do_probe_api(setup_probe_fn_t fn, int cpu, const char *str)
|
|||||||
{
|
{
|
||||||
struct perf_evlist *evlist;
|
struct perf_evlist *evlist;
|
||||||
struct perf_evsel *evsel;
|
struct perf_evsel *evsel;
|
||||||
|
unsigned long flags = perf_event_open_cloexec_flag();
|
||||||
int err = -EAGAIN, fd;
|
int err = -EAGAIN, fd;
|
||||||
|
|
||||||
evlist = perf_evlist__new();
|
evlist = perf_evlist__new();
|
||||||
@@ -22,14 +24,14 @@ static int perf_do_probe_api(setup_probe_fn_t fn, int cpu, const char *str)
|
|||||||
|
|
||||||
evsel = perf_evlist__first(evlist);
|
evsel = perf_evlist__first(evlist);
|
||||||
|
|
||||||
fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, 0);
|
fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, flags);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
goto out_delete;
|
goto out_delete;
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
||||||
fn(evsel);
|
fn(evsel);
|
||||||
|
|
||||||
fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, 0);
|
fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, flags);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
if (errno == EINVAL)
|
if (errno == EINVAL)
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
@@ -219,7 +221,8 @@ bool perf_evlist__can_select_event(struct perf_evlist *evlist, const char *str)
|
|||||||
cpu = evlist->cpus->map[0];
|
cpu = evlist->cpus->map[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, 0);
|
fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1,
|
||||||
|
perf_event_open_cloexec_flag());
|
||||||
if (fd >= 0) {
|
if (fd >= 0) {
|
||||||
close(fd);
|
close(fd);
|
||||||
ret = true;
|
ret = true;
|
||||||
|
|||||||
Reference in New Issue
Block a user