perf/core improvements and fixes
. Improve listing of accessible enum perf probe variables, from Hyeoncheol Lee. . Don't stop the build if the audit libraries are not installed, fix from Namhyung Kim. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.14 (GNU/Linux) iQIcBAABAgAGBQJQZLyTAAoJENZQFvNTUqpAfgMQAIHFPCA2AHLzQae1kr6ApoXi 4hwhT8MyvI6Rnaj19vlOjthxk8Ynjkx+5ZiNtYxy+K6aJvQ7ZgsmS6q9//oRdJx0 //7zgRz29pmvq0ZOkd3lktyi77mrL6euVIIt53J2c1pjoExxN4KRiJ2QIYUsyBvL YsG7RXjuh3cACEZ+KMytxFFdbdXTGSicMmF4a5py5kuRydkuCZjmujt25N4Bzlrs jDxjLhXDBi14Dk0OXy2yUeTthAAa96kYIkJAetbduzbOricmfMHhMRgIGfQk2/K1 QirrcbTZApZ78YBjbq1EAdNf6lSaTEA5YIG/NZBS6N2tTeHXi4meXzM6ke+Lb2J1 42Gpy3xVDOkcG93Wgd4m1EO5x5E2kYhdJuYqUKf4jFl5b4qXCkX3qrllu2Tu4D46 rr/V3FcItyzmuEclCZFcKrVefoy8vC5Kg1/szQ7C+c1anuO6cNTLMy68lTqb8wx/ bnhuPmLS79dYdtDuKNwS9uTsFJD98U7GrIOW074GYV5o2mqdC/VyGWIIxL/vMlxo 6AgWKmDTKvNa63n4fwkM+CDucJTk8pqFbrtAnq+yvr0JlypDEJqpM/0u5tZizrGc dScjB4YwtC17s3VjWGszwExtjxC39j+YXF0aFKkbxgYAUEHMefZuJ7Pxu9TDZ2BF P/A/ggGw5nUIDNn2FHmL =98/I -----END PGP SIGNATURE----- Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo: * Improve listing of accessible enum perf probe variables, from Hyeoncheol Lee. * Don't stop the build if the audit libraries are not installed, fix from Namhyung Kim. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
commit
1d787d37c8
53
tools/perf/Documentation/perf-trace.txt
Normal file
53
tools/perf/Documentation/perf-trace.txt
Normal file
@ -0,0 +1,53 @@
|
||||
perf-trace(1)
|
||||
=============
|
||||
|
||||
NAME
|
||||
----
|
||||
perf-trace - strace inspired tool
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'perf trace'
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
This command will show the events associated with the target, initially
|
||||
syscalls, but other system events like pagefaults, task lifetime events,
|
||||
scheduling events, etc.
|
||||
|
||||
Initially this is a live mode only tool, but eventually will work with
|
||||
perf.data files like the other tools, allowing a detached 'record' from
|
||||
analysis phases.
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
|
||||
--all-cpus::
|
||||
System-wide collection from all CPUs.
|
||||
|
||||
-p::
|
||||
--pid=::
|
||||
Record events on existing process ID (comma separated list).
|
||||
|
||||
--tid=::
|
||||
Record events on existing thread ID (comma separated list).
|
||||
|
||||
--uid=::
|
||||
Record events in threads owned by uid. Name or number.
|
||||
|
||||
--no-inherit::
|
||||
Child tasks do not inherit counters.
|
||||
|
||||
--mmap-pages=::
|
||||
Number of mmap data pages. Must be a power of two.
|
||||
|
||||
--cpu::
|
||||
Collect samples only on the list of CPUs provided. Multiple CPUs can be provided as a
|
||||
comma-separated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2.
|
||||
In per-thread mode with inheritance mode on (default), Events are captured only when
|
||||
the thread executes on the designated CPUs. Default is to monitor all CPUs.
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
linkperf:perf-record[1], linkperf:perf-script[1]
|
@ -559,6 +559,19 @@ else
|
||||
LIB_OBJS += $(OUTPUT)util/unwind.o
|
||||
endif
|
||||
|
||||
ifdef NO_LIBAUDIT
|
||||
BASIC_CFLAGS += -DNO_LIBAUDIT_SUPPORT
|
||||
else
|
||||
FLAGS_LIBAUDIT = $(ALL_CFLAGS) $(ALL_LDFLAGS) -laudit
|
||||
ifneq ($(call try-cc,$(SOURCE_LIBAUDIT),$(FLAGS_LIBAUDIT)),y)
|
||||
msg := $(warning No libaudit.h found, disables 'trace' tool, please install audit-libs-devel or libaudit-dev);
|
||||
BASIC_CFLAGS += -DNO_LIBAUDIT_SUPPORT
|
||||
else
|
||||
BUILTIN_OBJS += $(OUTPUT)builtin-trace.o
|
||||
EXTLIBS += -laudit
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef NO_NEWT
|
||||
BASIC_CFLAGS += -DNO_NEWT_SUPPORT
|
||||
else
|
||||
|
@ -320,7 +320,7 @@ try_again:
|
||||
}
|
||||
}
|
||||
|
||||
if (perf_evlist__set_filters(evlist)) {
|
||||
if (perf_evlist__apply_filters(evlist)) {
|
||||
error("failed to set filter with %d (%s)\n", errno,
|
||||
strerror(errno));
|
||||
rc = -1;
|
||||
|
@ -478,7 +478,7 @@ static int run_perf_stat(int argc __maybe_unused, const char **argv)
|
||||
counter->supported = true;
|
||||
}
|
||||
|
||||
if (perf_evlist__set_filters(evsel_list)) {
|
||||
if (perf_evlist__apply_filters(evsel_list)) {
|
||||
error("failed to set filter with %d (%s)\n", errno,
|
||||
strerror(errno));
|
||||
return -1;
|
||||
|
@ -564,7 +564,7 @@ static int test__basic_mmap(void)
|
||||
goto out_munmap;
|
||||
}
|
||||
|
||||
err = perf_evlist__parse_sample(evlist, event, &sample, false);
|
||||
err = perf_evlist__parse_sample(evlist, event, &sample);
|
||||
if (err) {
|
||||
pr_err("Can't parse sample, err = %d\n", err);
|
||||
goto out_munmap;
|
||||
@ -781,7 +781,7 @@ static int test__PERF_RECORD(void)
|
||||
if (type < PERF_RECORD_MAX)
|
||||
nr_events[type]++;
|
||||
|
||||
err = perf_evlist__parse_sample(evlist, event, &sample, false);
|
||||
err = perf_evlist__parse_sample(evlist, event, &sample);
|
||||
if (err < 0) {
|
||||
if (verbose)
|
||||
perf_event__fprintf(event, stderr);
|
||||
@ -1289,6 +1289,118 @@ static int perf_evsel__tp_sched_test(void)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int test__syscall_open_tp_fields(void)
|
||||
{
|
||||
struct perf_record_opts opts = {
|
||||
.target = {
|
||||
.uid = UINT_MAX,
|
||||
.uses_mmap = true,
|
||||
},
|
||||
.no_delay = true,
|
||||
.freq = 1,
|
||||
.mmap_pages = 256,
|
||||
.raw_samples = true,
|
||||
};
|
||||
const char *filename = "/etc/passwd";
|
||||
int flags = O_RDONLY | O_DIRECTORY;
|
||||
struct perf_evlist *evlist = perf_evlist__new(NULL, NULL);
|
||||
struct perf_evsel *evsel;
|
||||
int err = -1, i, nr_events = 0, nr_polls = 0;
|
||||
|
||||
if (evlist == NULL) {
|
||||
pr_debug("%s: perf_evlist__new\n", __func__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
evsel = perf_evsel__newtp("syscalls", "sys_enter_open", 0);
|
||||
if (evsel == NULL) {
|
||||
pr_debug("%s: perf_evsel__newtp\n", __func__);
|
||||
goto out_delete_evlist;
|
||||
}
|
||||
|
||||
perf_evlist__add(evlist, evsel);
|
||||
|
||||
err = perf_evlist__create_maps(evlist, &opts.target);
|
||||
if (err < 0) {
|
||||
pr_debug("%s: perf_evlist__create_maps\n", __func__);
|
||||
goto out_delete_evlist;
|
||||
}
|
||||
|
||||
perf_evsel__config(evsel, &opts, evsel);
|
||||
|
||||
evlist->threads->map[0] = getpid();
|
||||
|
||||
err = perf_evlist__open(evlist);
|
||||
if (err < 0) {
|
||||
pr_debug("perf_evlist__open: %s\n", strerror(errno));
|
||||
goto out_delete_evlist;
|
||||
}
|
||||
|
||||
err = perf_evlist__mmap(evlist, UINT_MAX, false);
|
||||
if (err < 0) {
|
||||
pr_debug("perf_evlist__mmap: %s\n", strerror(errno));
|
||||
goto out_delete_evlist;
|
||||
}
|
||||
|
||||
perf_evlist__enable(evlist);
|
||||
|
||||
/*
|
||||
* Generate the event:
|
||||
*/
|
||||
open(filename, flags);
|
||||
|
||||
while (1) {
|
||||
int before = nr_events;
|
||||
|
||||
for (i = 0; i < evlist->nr_mmaps; i++) {
|
||||
union perf_event *event;
|
||||
|
||||
while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
|
||||
const u32 type = event->header.type;
|
||||
int tp_flags;
|
||||
struct perf_sample sample;
|
||||
|
||||
++nr_events;
|
||||
|
||||
if (type != PERF_RECORD_SAMPLE)
|
||||
continue;
|
||||
|
||||
err = perf_evsel__parse_sample(evsel, event, &sample);
|
||||
if (err) {
|
||||
pr_err("Can't parse sample, err = %d\n", err);
|
||||
goto out_munmap;
|
||||
}
|
||||
|
||||
tp_flags = perf_evsel__intval(evsel, &sample, "flags");
|
||||
|
||||
if (flags != tp_flags) {
|
||||
pr_debug("%s: Expected flags=%#x, got %#x\n",
|
||||
__func__, flags, tp_flags);
|
||||
goto out_munmap;
|
||||
}
|
||||
|
||||
goto out_ok;
|
||||
}
|
||||
}
|
||||
|
||||
if (nr_events == before)
|
||||
poll(evlist->pollfd, evlist->nr_fds, 10);
|
||||
|
||||
if (++nr_polls > 5) {
|
||||
pr_debug("%s: no events!\n", __func__);
|
||||
goto out_munmap;
|
||||
}
|
||||
}
|
||||
out_ok:
|
||||
err = 0;
|
||||
out_munmap:
|
||||
perf_evlist__munmap(evlist);
|
||||
out_delete_evlist:
|
||||
perf_evlist__delete(evlist);
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct test {
|
||||
const char *desc;
|
||||
int (*func)(void);
|
||||
@ -1339,6 +1451,10 @@ static struct test {
|
||||
.desc = "Check parsing of sched tracepoints fields",
|
||||
.func = perf_evsel__tp_sched_test,
|
||||
},
|
||||
{
|
||||
.desc = "Generate and check syscalls:sys_enter_open event fields",
|
||||
.func = test__syscall_open_tp_fields,
|
||||
},
|
||||
{
|
||||
.func = NULL,
|
||||
},
|
||||
|
@ -823,7 +823,7 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx)
|
||||
int ret;
|
||||
|
||||
while ((event = perf_evlist__mmap_read(top->evlist, idx)) != NULL) {
|
||||
ret = perf_evlist__parse_sample(top->evlist, event, &sample, false);
|
||||
ret = perf_evlist__parse_sample(top->evlist, event, &sample);
|
||||
if (ret) {
|
||||
pr_err("Can't parse sample, err = %d\n", ret);
|
||||
continue;
|
||||
|
310
tools/perf/builtin-trace.c
Normal file
310
tools/perf/builtin-trace.c
Normal file
@ -0,0 +1,310 @@
|
||||
#include "builtin.h"
|
||||
#include "util/evlist.h"
|
||||
#include "util/parse-options.h"
|
||||
#include "util/thread_map.h"
|
||||
#include "event-parse.h"
|
||||
|
||||
#include <libaudit.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static struct syscall_fmt {
|
||||
const char *name;
|
||||
const char *alias;
|
||||
bool errmsg;
|
||||
bool timeout;
|
||||
} syscall_fmts[] = {
|
||||
{ .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
|
||||
{ .name = "fstat", .errmsg = true, .alias = "newfstat", },
|
||||
{ .name = "fstatat", .errmsg = true, .alias = "newfstatat", },
|
||||
{ .name = "futex", .errmsg = true, },
|
||||
{ .name = "poll", .errmsg = true, .timeout = true, },
|
||||
{ .name = "ppoll", .errmsg = true, .timeout = true, },
|
||||
{ .name = "read", .errmsg = true, },
|
||||
{ .name = "recvfrom", .errmsg = true, },
|
||||
{ .name = "select", .errmsg = true, .timeout = true, },
|
||||
{ .name = "stat", .errmsg = true, .alias = "newstat", },
|
||||
};
|
||||
|
||||
static int syscall_fmt__cmp(const void *name, const void *fmtp)
|
||||
{
|
||||
const struct syscall_fmt *fmt = fmtp;
|
||||
return strcmp(name, fmt->name);
|
||||
}
|
||||
|
||||
static struct syscall_fmt *syscall_fmt__find(const char *name)
|
||||
{
|
||||
const int nmemb = ARRAY_SIZE(syscall_fmts);
|
||||
return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
|
||||
}
|
||||
|
||||
struct syscall {
|
||||
struct event_format *tp_format;
|
||||
const char *name;
|
||||
struct syscall_fmt *fmt;
|
||||
};
|
||||
|
||||
struct trace {
|
||||
int audit_machine;
|
||||
struct {
|
||||
int max;
|
||||
struct syscall *table;
|
||||
} syscalls;
|
||||
struct perf_record_opts opts;
|
||||
};
|
||||
|
||||
static int trace__read_syscall_info(struct trace *trace, int id)
|
||||
{
|
||||
char tp_name[128];
|
||||
struct syscall *sc;
|
||||
|
||||
if (id > trace->syscalls.max) {
|
||||
struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
|
||||
|
||||
if (nsyscalls == NULL)
|
||||
return -1;
|
||||
|
||||
if (trace->syscalls.max != -1) {
|
||||
memset(nsyscalls + trace->syscalls.max + 1, 0,
|
||||
(id - trace->syscalls.max) * sizeof(*sc));
|
||||
} else {
|
||||
memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
|
||||
}
|
||||
|
||||
trace->syscalls.table = nsyscalls;
|
||||
trace->syscalls.max = id;
|
||||
}
|
||||
|
||||
sc = trace->syscalls.table + id;
|
||||
sc->name = audit_syscall_to_name(id, trace->audit_machine);
|
||||
if (sc->name == NULL)
|
||||
return -1;
|
||||
|
||||
sc->fmt = syscall_fmt__find(sc->name);
|
||||
|
||||
snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
|
||||
sc->tp_format = event_format__new("syscalls", tp_name);
|
||||
|
||||
if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
|
||||
snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
|
||||
sc->tp_format = event_format__new("syscalls", tp_name);
|
||||
}
|
||||
|
||||
return sc->tp_format != NULL ? 0 : -1;
|
||||
}
|
||||
|
||||
static size_t syscall__fprintf_args(struct syscall *sc, unsigned long *args, FILE *fp)
|
||||
{
|
||||
int i = 0;
|
||||
size_t printed = 0;
|
||||
|
||||
if (sc->tp_format != NULL) {
|
||||
struct format_field *field;
|
||||
|
||||
for (field = sc->tp_format->format.fields->next; field; field = field->next) {
|
||||
printed += fprintf(fp, "%s%s: %ld", printed ? ", " : "",
|
||||
field->name, args[i++]);
|
||||
}
|
||||
} else {
|
||||
while (i < 6) {
|
||||
printed += fprintf(fp, "%sarg%d: %ld", printed ? ", " : "", i, args[i]);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
return printed;
|
||||
}
|
||||
|
||||
static int trace__run(struct trace *trace)
|
||||
{
|
||||
struct perf_evlist *evlist = perf_evlist__new(NULL, NULL);
|
||||
struct perf_evsel *evsel, *evsel_enter, *evsel_exit;
|
||||
int err = -1, i, nr_events = 0, before;
|
||||
|
||||
if (evlist == NULL) {
|
||||
printf("Not enough memory to run!\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
evsel_enter = perf_evsel__newtp("raw_syscalls", "sys_enter", 0);
|
||||
if (evsel_enter == NULL) {
|
||||
printf("Couldn't read the raw_syscalls:sys_enter tracepoint information!\n");
|
||||
goto out_delete_evlist;
|
||||
}
|
||||
|
||||
perf_evlist__add(evlist, evsel_enter);
|
||||
|
||||
evsel_exit = perf_evsel__newtp("raw_syscalls", "sys_exit", 1);
|
||||
if (evsel_exit == NULL) {
|
||||
printf("Couldn't read the raw_syscalls:sys_exit tracepoint information!\n");
|
||||
goto out_delete_evlist;
|
||||
}
|
||||
|
||||
perf_evlist__add(evlist, evsel_exit);
|
||||
|
||||
err = perf_evlist__create_maps(evlist, &trace->opts.target);
|
||||
if (err < 0) {
|
||||
printf("Problems parsing the target to trace, check your options!\n");
|
||||
goto out_delete_evlist;
|
||||
}
|
||||
|
||||
perf_evlist__config_attrs(evlist, &trace->opts);
|
||||
|
||||
err = perf_evlist__open(evlist);
|
||||
if (err < 0) {
|
||||
printf("Couldn't create the events: %s\n", strerror(errno));
|
||||
goto out_delete_evlist;
|
||||
}
|
||||
|
||||
err = perf_evlist__mmap(evlist, UINT_MAX, false);
|
||||
if (err < 0) {
|
||||
printf("Couldn't mmap the events: %s\n", strerror(errno));
|
||||
goto out_delete_evlist;
|
||||
}
|
||||
|
||||
perf_evlist__enable(evlist);
|
||||
again:
|
||||
before = nr_events;
|
||||
|
||||
for (i = 0; i < evlist->nr_mmaps; i++) {
|
||||
union perf_event *event;
|
||||
|
||||
while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
|
||||
const u32 type = event->header.type;
|
||||
struct syscall *sc;
|
||||
struct perf_sample sample;
|
||||
int id;
|
||||
|
||||
++nr_events;
|
||||
|
||||
switch (type) {
|
||||
case PERF_RECORD_SAMPLE:
|
||||
break;
|
||||
case PERF_RECORD_LOST:
|
||||
printf("LOST %" PRIu64 " events!\n", event->lost.lost);
|
||||
continue;
|
||||
default:
|
||||
printf("Unexpected %s event, skipping...\n",
|
||||
perf_event__name(type));
|
||||
continue;
|
||||
}
|
||||
|
||||
err = perf_evlist__parse_sample(evlist, event, &sample);
|
||||
if (err) {
|
||||
printf("Can't parse sample, err = %d, skipping...\n", err);
|
||||
continue;
|
||||
}
|
||||
|
||||
evsel = perf_evlist__id2evsel(evlist, sample.id);
|
||||
if (evsel == NULL) {
|
||||
printf("Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
|
||||
continue;
|
||||
}
|
||||
|
||||
id = perf_evsel__intval(evsel, &sample, "id");
|
||||
if (id < 0) {
|
||||
printf("Invalid syscall %d id, skipping...\n", id);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
|
||||
trace__read_syscall_info(trace, id))
|
||||
continue;
|
||||
|
||||
if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
|
||||
continue;
|
||||
|
||||
sc = &trace->syscalls.table[id];
|
||||
|
||||
if (evlist->threads->map[0] == -1 || evlist->threads->nr > 1)
|
||||
printf("%d ", sample.tid);
|
||||
|
||||
if (evsel == evsel_enter) {
|
||||
void *args = perf_evsel__rawptr(evsel, &sample, "args");
|
||||
|
||||
printf("%s(", sc->name);
|
||||
syscall__fprintf_args(sc, args, stdout);
|
||||
} else if (evsel == evsel_exit) {
|
||||
int ret = perf_evsel__intval(evsel, &sample, "ret");
|
||||
|
||||
if (ret < 0 && sc->fmt && sc->fmt->errmsg) {
|
||||
char bf[256];
|
||||
const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
|
||||
*e = audit_errno_to_name(-ret);
|
||||
|
||||
printf(") = -1 %s %s", e, emsg);
|
||||
} else if (ret == 0 && sc->fmt && sc->fmt->timeout)
|
||||
printf(") = 0 Timeout");
|
||||
else
|
||||
printf(") = %d", ret);
|
||||
|
||||
putchar('\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nr_events == before)
|
||||
poll(evlist->pollfd, evlist->nr_fds, -1);
|
||||
|
||||
goto again;
|
||||
|
||||
out_delete_evlist:
|
||||
perf_evlist__delete(evlist);
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
{
|
||||
const char * const trace_usage[] = {
|
||||
"perf trace [<options>]",
|
||||
NULL
|
||||
};
|
||||
struct trace trace = {
|
||||
.audit_machine = audit_detect_machine(),
|
||||
.syscalls = {
|
||||
. max = -1,
|
||||
},
|
||||
.opts = {
|
||||
.target = {
|
||||
.uid = UINT_MAX,
|
||||
.uses_mmap = true,
|
||||
},
|
||||
.user_freq = UINT_MAX,
|
||||
.user_interval = ULLONG_MAX,
|
||||
.no_delay = true,
|
||||
.mmap_pages = 1024,
|
||||
},
|
||||
};
|
||||
const struct option trace_options[] = {
|
||||
OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
|
||||
"trace events on existing process id"),
|
||||
OPT_STRING(0, "tid", &trace.opts.target.tid, "tid",
|
||||
"trace events on existing thread id"),
|
||||
OPT_BOOLEAN(0, "all-cpus", &trace.opts.target.system_wide,
|
||||
"system-wide collection from all CPUs"),
|
||||
OPT_STRING(0, "cpu", &trace.opts.target.cpu_list, "cpu",
|
||||
"list of cpus to monitor"),
|
||||
OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
|
||||
"child tasks do not inherit counters"),
|
||||
OPT_UINTEGER(0, "mmap-pages", &trace.opts.mmap_pages,
|
||||
"number of mmap data pages"),
|
||||
OPT_STRING(0, "uid", &trace.opts.target.uid_str, "user",
|
||||
"user to profile"),
|
||||
OPT_END()
|
||||
};
|
||||
int err;
|
||||
|
||||
argc = parse_options(argc, argv, trace_options, trace_usage, 0);
|
||||
if (argc)
|
||||
usage_with_options(trace_usage, trace_options);
|
||||
|
||||
err = perf_target__parse_uid(&trace.opts.target);
|
||||
if (err) {
|
||||
char bf[BUFSIZ];
|
||||
perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
|
||||
printf("%s", bf);
|
||||
return err;
|
||||
}
|
||||
|
||||
return trace__run(&trace);
|
||||
}
|
@ -34,6 +34,7 @@ extern int cmd_kmem(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_lock(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_kvm(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_test(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_trace(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_inject(int argc, const char **argv, const char *prefix);
|
||||
|
||||
extern int find_scripts(char **scripts_array, char **scripts_path_array);
|
||||
|
@ -17,6 +17,7 @@ perf-report mainporcelain common
|
||||
perf-stat mainporcelain common
|
||||
perf-timechart mainporcelain common
|
||||
perf-top mainporcelain common
|
||||
perf-trace mainporcelain common
|
||||
perf-script mainporcelain common
|
||||
perf-probe mainporcelain full
|
||||
perf-kmem mainporcelain common
|
||||
|
@ -193,3 +193,14 @@ int main(void)
|
||||
}
|
||||
endef
|
||||
endif
|
||||
|
||||
ifndef NO_LIBAUDIT
|
||||
define SOURCE_LIBAUDIT
|
||||
#include <libaudit.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
return audit_open();
|
||||
}
|
||||
endef
|
||||
endif
|
@ -55,6 +55,9 @@ static struct cmd_struct commands[] = {
|
||||
{ "lock", cmd_lock, 0 },
|
||||
{ "kvm", cmd_kvm, 0 },
|
||||
{ "test", cmd_test, 0 },
|
||||
#ifndef NO_LIBAUDIT_SUPPORT
|
||||
{ "trace", cmd_trace, 0 },
|
||||
#endif
|
||||
{ "inject", cmd_inject, 0 },
|
||||
};
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
#define __PERF_CPUMAP_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
struct cpu_map {
|
||||
int nr;
|
||||
@ -14,4 +15,14 @@ void cpu_map__delete(struct cpu_map *map);
|
||||
struct cpu_map *cpu_map__read(FILE *file);
|
||||
size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp);
|
||||
|
||||
static inline int cpu_map__nr(const struct cpu_map *map)
|
||||
{
|
||||
return map ? map->nr : 1;
|
||||
}
|
||||
|
||||
static inline bool cpu_map__all(const struct cpu_map *map)
|
||||
{
|
||||
return map ? map->map[0] == -1 : true;
|
||||
}
|
||||
|
||||
#endif /* __PERF_CPUMAP_H */
|
||||
|
@ -804,6 +804,8 @@ int die_get_typename(Dwarf_Die *vr_die, char *buf, int len)
|
||||
tmp = "union ";
|
||||
else if (tag == DW_TAG_structure_type)
|
||||
tmp = "struct ";
|
||||
else if (tag == DW_TAG_enumeration_type)
|
||||
tmp = "enum ";
|
||||
/* Write a base name */
|
||||
ret = snprintf(buf, len, "%s%s", tmp, dwarf_diename(&type));
|
||||
return (ret >= len) ? -E2BIG : ret;
|
||||
|
@ -304,7 +304,7 @@ void perf_evlist__enable(struct perf_evlist *evlist)
|
||||
int cpu, thread;
|
||||
struct perf_evsel *pos;
|
||||
|
||||
for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
|
||||
for (cpu = 0; cpu < cpu_map__nr(evlist->cpus); cpu++) {
|
||||
list_for_each_entry(pos, &evlist->entries, node) {
|
||||
for (thread = 0; thread < evlist->threads->nr; thread++)
|
||||
ioctl(FD(pos, cpu, thread),
|
||||
@ -315,7 +315,7 @@ void perf_evlist__enable(struct perf_evlist *evlist)
|
||||
|
||||
static int perf_evlist__alloc_pollfd(struct perf_evlist *evlist)
|
||||
{
|
||||
int nfds = evlist->cpus->nr * evlist->threads->nr * evlist->nr_entries;
|
||||
int nfds = cpu_map__nr(evlist->cpus) * evlist->threads->nr * evlist->nr_entries;
|
||||
evlist->pollfd = malloc(sizeof(struct pollfd) * nfds);
|
||||
return evlist->pollfd != NULL ? 0 : -ENOMEM;
|
||||
}
|
||||
@ -475,8 +475,8 @@ void perf_evlist__munmap(struct perf_evlist *evlist)
|
||||
|
||||
static int perf_evlist__alloc_mmap(struct perf_evlist *evlist)
|
||||
{
|
||||
evlist->nr_mmaps = evlist->cpus->nr;
|
||||
if (evlist->cpus->map[0] == -1)
|
||||
evlist->nr_mmaps = cpu_map__nr(evlist->cpus);
|
||||
if (cpu_map__all(evlist->cpus))
|
||||
evlist->nr_mmaps = evlist->threads->nr;
|
||||
evlist->mmap = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap));
|
||||
return evlist->mmap != NULL ? 0 : -ENOMEM;
|
||||
@ -622,11 +622,11 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
|
||||
list_for_each_entry(evsel, &evlist->entries, node) {
|
||||
if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
|
||||
evsel->sample_id == NULL &&
|
||||
perf_evsel__alloc_id(evsel, cpus->nr, threads->nr) < 0)
|
||||
perf_evsel__alloc_id(evsel, cpu_map__nr(cpus), threads->nr) < 0)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (evlist->cpus->map[0] == -1)
|
||||
if (cpu_map__all(cpus))
|
||||
return perf_evlist__mmap_per_thread(evlist, prot, mask);
|
||||
|
||||
return perf_evlist__mmap_per_cpu(evlist, prot, mask);
|
||||
@ -666,32 +666,39 @@ void perf_evlist__delete_maps(struct perf_evlist *evlist)
|
||||
evlist->threads = NULL;
|
||||
}
|
||||
|
||||
int perf_evlist__set_filters(struct perf_evlist *evlist)
|
||||
int perf_evlist__apply_filters(struct perf_evlist *evlist)
|
||||
{
|
||||
const struct thread_map *threads = evlist->threads;
|
||||
const struct cpu_map *cpus = evlist->cpus;
|
||||
struct perf_evsel *evsel;
|
||||
char *filter;
|
||||
int thread;
|
||||
int cpu;
|
||||
int err;
|
||||
int fd;
|
||||
int err = 0;
|
||||
const int ncpus = cpu_map__nr(evlist->cpus),
|
||||
nthreads = evlist->threads->nr;
|
||||
|
||||
list_for_each_entry(evsel, &evlist->entries, node) {
|
||||
filter = evsel->filter;
|
||||
if (!filter)
|
||||
if (evsel->filter == NULL)
|
||||
continue;
|
||||
for (cpu = 0; cpu < cpus->nr; cpu++) {
|
||||
for (thread = 0; thread < threads->nr; thread++) {
|
||||
fd = FD(evsel, cpu, thread);
|
||||
err = ioctl(fd, PERF_EVENT_IOC_SET_FILTER, filter);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
err = perf_evsel__set_filter(evsel, ncpus, nthreads, evsel->filter);
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter)
|
||||
{
|
||||
struct perf_evsel *evsel;
|
||||
int err = 0;
|
||||
const int ncpus = cpu_map__nr(evlist->cpus),
|
||||
nthreads = evlist->threads->nr;
|
||||
|
||||
list_for_each_entry(evsel, &evlist->entries, node) {
|
||||
err = perf_evsel__set_filter(evsel, ncpus, nthreads, filter);
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
bool perf_evlist__valid_sample_type(struct perf_evlist *evlist)
|
||||
@ -884,10 +891,10 @@ int perf_evlist__start_workload(struct perf_evlist *evlist)
|
||||
}
|
||||
|
||||
int perf_evlist__parse_sample(struct perf_evlist *evlist, union perf_event *event,
|
||||
struct perf_sample *sample, bool swapped)
|
||||
struct perf_sample *sample)
|
||||
{
|
||||
struct perf_evsel *evsel = perf_evlist__first(evlist);
|
||||
return perf_evsel__parse_sample(evsel, event, sample, swapped);
|
||||
return perf_evsel__parse_sample(evsel, event, sample);
|
||||
}
|
||||
|
||||
size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp)
|
||||
|
@ -72,6 +72,8 @@ int perf_evlist__set_tracepoints_handlers(struct perf_evlist *evlist,
|
||||
#define perf_evlist__set_tracepoints_handlers_array(evlist, array) \
|
||||
perf_evlist__set_tracepoints_handlers(evlist, array, ARRAY_SIZE(array))
|
||||
|
||||
int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter);
|
||||
|
||||
struct perf_evsel *
|
||||
perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id);
|
||||
|
||||
@ -115,7 +117,7 @@ static inline void perf_evlist__set_maps(struct perf_evlist *evlist,
|
||||
int perf_evlist__create_maps(struct perf_evlist *evlist,
|
||||
struct perf_target *target);
|
||||
void perf_evlist__delete_maps(struct perf_evlist *evlist);
|
||||
int perf_evlist__set_filters(struct perf_evlist *evlist);
|
||||
int perf_evlist__apply_filters(struct perf_evlist *evlist);
|
||||
|
||||
void __perf_evlist__set_leader(struct list_head *list);
|
||||
void perf_evlist__set_leader(struct perf_evlist *evlist);
|
||||
@ -125,7 +127,7 @@ bool perf_evlist__sample_id_all(struct perf_evlist *evlist);
|
||||
u16 perf_evlist__id_hdr_size(struct perf_evlist *evlist);
|
||||
|
||||
int perf_evlist__parse_sample(struct perf_evlist *evlist, union perf_event *event,
|
||||
struct perf_sample *sample, bool swapped);
|
||||
struct perf_sample *sample);
|
||||
|
||||
bool perf_evlist__valid_sample_type(struct perf_evlist *evlist);
|
||||
bool perf_evlist__valid_sample_id_all(struct perf_evlist *evlist);
|
||||
|
@ -70,7 +70,7 @@ struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx)
|
||||
return evsel;
|
||||
}
|
||||
|
||||
static struct event_format *event_format__new(const char *sys, const char *name)
|
||||
struct event_format *event_format__new(const char *sys, const char *name)
|
||||
{
|
||||
int fd, n;
|
||||
char *filename;
|
||||
@ -117,21 +117,28 @@ struct perf_evsel *perf_evsel__newtp(const char *sys, const char *name, int idx)
|
||||
|
||||
if (evsel != NULL) {
|
||||
struct perf_event_attr attr = {
|
||||
.type = PERF_TYPE_TRACEPOINT,
|
||||
.type = PERF_TYPE_TRACEPOINT,
|
||||
.sample_type = (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME |
|
||||
PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD),
|
||||
};
|
||||
|
||||
if (asprintf(&evsel->name, "%s:%s", sys, name) < 0)
|
||||
goto out_free;
|
||||
|
||||
evsel->tp_format = event_format__new(sys, name);
|
||||
if (evsel->tp_format == NULL)
|
||||
goto out_free;
|
||||
|
||||
event_attr_init(&attr);
|
||||
attr.config = evsel->tp_format->id;
|
||||
attr.sample_period = 1;
|
||||
perf_evsel__init(evsel, &attr, idx);
|
||||
evsel->name = evsel->tp_format->name;
|
||||
}
|
||||
|
||||
return evsel;
|
||||
|
||||
out_free:
|
||||
free(evsel->name);
|
||||
free(evsel);
|
||||
return NULL;
|
||||
}
|
||||
@ -501,6 +508,24 @@ int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
|
||||
return evsel->fd != NULL ? 0 : -ENOMEM;
|
||||
}
|
||||
|
||||
int perf_evsel__set_filter(struct perf_evsel *evsel, int ncpus, int nthreads,
|
||||
const char *filter)
|
||||
{
|
||||
int cpu, thread;
|
||||
|
||||
for (cpu = 0; cpu < ncpus; cpu++) {
|
||||
for (thread = 0; thread < nthreads; thread++) {
|
||||
int fd = FD(evsel, cpu, thread),
|
||||
err = ioctl(fd, PERF_EVENT_IOC_SET_FILTER, filter);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads)
|
||||
{
|
||||
evsel->sample_id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id));
|
||||
@ -562,10 +587,8 @@ void perf_evsel__delete(struct perf_evsel *evsel)
|
||||
perf_evsel__exit(evsel);
|
||||
close_cgroup(evsel->cgrp);
|
||||
free(evsel->group_name);
|
||||
if (evsel->tp_format && evsel->name == evsel->tp_format->name) {
|
||||
evsel->name = NULL;
|
||||
if (evsel->tp_format)
|
||||
pevent_free_format(evsel->tp_format);
|
||||
}
|
||||
free(evsel->name);
|
||||
free(evsel);
|
||||
}
|
||||
@ -763,11 +786,13 @@ int perf_evsel__open_per_thread(struct perf_evsel *evsel,
|
||||
return __perf_evsel__open(evsel, &empty_cpu_map.map, threads);
|
||||
}
|
||||
|
||||
static int perf_event__parse_id_sample(const union perf_event *event, u64 type,
|
||||
struct perf_sample *sample,
|
||||
bool swapped)
|
||||
static int perf_evsel__parse_id_sample(const struct perf_evsel *evsel,
|
||||
const union perf_event *event,
|
||||
struct perf_sample *sample)
|
||||
{
|
||||
u64 type = evsel->attr.sample_type;
|
||||
const u64 *array = event->sample.array;
|
||||
bool swapped = evsel->needs_swap;
|
||||
union u64_swap u;
|
||||
|
||||
array += ((event->header.size -
|
||||
@ -828,10 +853,11 @@ static bool sample_overlap(const union perf_event *event,
|
||||
}
|
||||
|
||||
int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
|
||||
struct perf_sample *data, bool swapped)
|
||||
struct perf_sample *data)
|
||||
{
|
||||
u64 type = evsel->attr.sample_type;
|
||||
u64 regs_user = evsel->attr.sample_regs_user;
|
||||
bool swapped = evsel->needs_swap;
|
||||
const u64 *array;
|
||||
|
||||
/*
|
||||
@ -848,7 +874,7 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
|
||||
if (event->header.type != PERF_RECORD_SAMPLE) {
|
||||
if (!evsel->attr.sample_id_all)
|
||||
return 0;
|
||||
return perf_event__parse_id_sample(event, type, data, swapped);
|
||||
return perf_evsel__parse_id_sample(evsel, event, data);
|
||||
}
|
||||
|
||||
array = event->sample.array;
|
||||
@ -1078,7 +1104,7 @@ struct format_field *perf_evsel__field(struct perf_evsel *evsel, const char *nam
|
||||
return pevent_find_field(evsel->tp_format, name);
|
||||
}
|
||||
|
||||
char *perf_evsel__strval(struct perf_evsel *evsel, struct perf_sample *sample,
|
||||
void *perf_evsel__rawptr(struct perf_evsel *evsel, struct perf_sample *sample,
|
||||
const char *name)
|
||||
{
|
||||
struct format_field *field = perf_evsel__field(evsel, name);
|
||||
@ -1101,13 +1127,43 @@ u64 perf_evsel__intval(struct perf_evsel *evsel, struct perf_sample *sample,
|
||||
const char *name)
|
||||
{
|
||||
struct format_field *field = perf_evsel__field(evsel, name);
|
||||
u64 val;
|
||||
void *ptr;
|
||||
u64 value;
|
||||
|
||||
if (!field)
|
||||
return 0;
|
||||
|
||||
val = pevent_read_number(evsel->tp_format->pevent,
|
||||
sample->raw_data + field->offset, field->size);
|
||||
return val;
|
||||
ptr = sample->raw_data + field->offset;
|
||||
|
||||
switch (field->size) {
|
||||
case 1:
|
||||
return *(u8 *)ptr;
|
||||
case 2:
|
||||
value = *(u16 *)ptr;
|
||||
break;
|
||||
case 4:
|
||||
value = *(u32 *)ptr;
|
||||
break;
|
||||
case 8:
|
||||
value = *(u64 *)ptr;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!evsel->needs_swap)
|
||||
return value;
|
||||
|
||||
switch (field->size) {
|
||||
case 2:
|
||||
return bswap_16(value);
|
||||
case 4:
|
||||
return bswap_32(value);
|
||||
case 8:
|
||||
return bswap_64(value);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -69,6 +69,7 @@ struct perf_evsel {
|
||||
struct cpu_map *cpus;
|
||||
unsigned int sample_size;
|
||||
bool supported;
|
||||
bool needs_swap;
|
||||
/* parse modifier helper */
|
||||
int exclude_GH;
|
||||
struct perf_evsel *leader;
|
||||
@ -82,6 +83,9 @@ struct perf_record_opts;
|
||||
|
||||
struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx);
|
||||
struct perf_evsel *perf_evsel__newtp(const char *sys, const char *name, int idx);
|
||||
|
||||
struct event_format *event_format__new(const char *sys, const char *name);
|
||||
|
||||
void perf_evsel__init(struct perf_evsel *evsel,
|
||||
struct perf_event_attr *attr, int idx);
|
||||
void perf_evsel__exit(struct perf_evsel *evsel);
|
||||
@ -114,6 +118,9 @@ void perf_evsel__free_fd(struct perf_evsel *evsel);
|
||||
void perf_evsel__free_id(struct perf_evsel *evsel);
|
||||
void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
|
||||
|
||||
int perf_evsel__set_filter(struct perf_evsel *evsel, int ncpus, int nthreads,
|
||||
const char *filter);
|
||||
|
||||
int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
|
||||
struct cpu_map *cpus);
|
||||
int perf_evsel__open_per_thread(struct perf_evsel *evsel,
|
||||
@ -124,11 +131,18 @@ void perf_evsel__close(struct perf_evsel *evsel, int ncpus, int nthreads);
|
||||
|
||||
struct perf_sample;
|
||||
|
||||
char *perf_evsel__strval(struct perf_evsel *evsel, struct perf_sample *sample,
|
||||
void *perf_evsel__rawptr(struct perf_evsel *evsel, struct perf_sample *sample,
|
||||
const char *name);
|
||||
u64 perf_evsel__intval(struct perf_evsel *evsel, struct perf_sample *sample,
|
||||
const char *name);
|
||||
|
||||
static inline char *perf_evsel__strval(struct perf_evsel *evsel,
|
||||
struct perf_sample *sample,
|
||||
const char *name)
|
||||
{
|
||||
return perf_evsel__rawptr(evsel, sample, name);
|
||||
}
|
||||
|
||||
struct format_field;
|
||||
|
||||
struct format_field *perf_evsel__field(struct perf_evsel *evsel, const char *name);
|
||||
@ -205,7 +219,7 @@ static inline int perf_evsel__read_scaled(struct perf_evsel *evsel,
|
||||
void hists__init(struct hists *hists);
|
||||
|
||||
int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
|
||||
struct perf_sample *sample, bool swapped);
|
||||
struct perf_sample *sample);
|
||||
|
||||
static inline struct perf_evsel *perf_evsel__next(struct perf_evsel *evsel)
|
||||
{
|
||||
|
@ -1256,8 +1256,10 @@ read_event_desc(struct perf_header *ph, int fd)
|
||||
if (ret != (ssize_t)sizeof(nr))
|
||||
goto error;
|
||||
|
||||
if (ph->needs_swap)
|
||||
if (ph->needs_swap) {
|
||||
nr = bswap_32(nr);
|
||||
evsel->needs_swap = true;
|
||||
}
|
||||
|
||||
evsel->name = do_read_string(fd, ph);
|
||||
|
||||
@ -2626,6 +2628,8 @@ int perf_session__read_header(struct perf_session *session, int fd)
|
||||
|
||||
if (evsel == NULL)
|
||||
goto out_delete_evlist;
|
||||
|
||||
evsel->needs_swap = header->needs_swap;
|
||||
/*
|
||||
* Do it before so that if perf_evsel__alloc_id fails, this
|
||||
* entry gets purged too at perf_evlist__delete().
|
||||
|
@ -410,8 +410,13 @@ static bool hists__collapse_insert_entry(struct hists *hists __maybe_unused,
|
||||
cmp = hist_entry__collapse(iter, he);
|
||||
|
||||
if (!cmp) {
|
||||
iter->period += he->period;
|
||||
iter->nr_events += he->nr_events;
|
||||
iter->period += he->period;
|
||||
iter->period_sys += he->period_sys;
|
||||
iter->period_us += he->period_us;
|
||||
iter->period_guest_sys += he->period_guest_sys;
|
||||
iter->period_guest_us += he->period_guest_us;
|
||||
iter->nr_events += he->nr_events;
|
||||
|
||||
if (symbol_conf.use_callchain) {
|
||||
callchain_cursor_reset(&callchain_cursor);
|
||||
callchain_merge(&callchain_cursor,
|
||||
|
@ -356,42 +356,28 @@ int parse_events_add_cache(struct list_head **list, int *idx,
|
||||
return add_event(list, idx, &attr, name);
|
||||
}
|
||||
|
||||
static int add_tracepoint(struct list_head **list, int *idx,
|
||||
static int add_tracepoint(struct list_head **listp, int *idx,
|
||||
char *sys_name, char *evt_name)
|
||||
{
|
||||
struct perf_event_attr attr;
|
||||
char name[MAX_NAME_LEN];
|
||||
char evt_path[MAXPATHLEN];
|
||||
char id_buf[4];
|
||||
u64 id;
|
||||
int fd;
|
||||
struct perf_evsel *evsel;
|
||||
struct list_head *list = *listp;
|
||||
|
||||
snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", tracing_events_path,
|
||||
sys_name, evt_name);
|
||||
|
||||
fd = open(evt_path, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
if (read(fd, id_buf, sizeof(id_buf)) < 0) {
|
||||
close(fd);
|
||||
return -1;
|
||||
if (!list) {
|
||||
list = malloc(sizeof(*list));
|
||||
if (!list)
|
||||
return -ENOMEM;
|
||||
INIT_LIST_HEAD(list);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
id = atoll(id_buf);
|
||||
evsel = perf_evsel__newtp(sys_name, evt_name, (*idx)++);
|
||||
if (!evsel) {
|
||||
free(list);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
memset(&attr, 0, sizeof(attr));
|
||||
attr.config = id;
|
||||
attr.type = PERF_TYPE_TRACEPOINT;
|
||||
attr.sample_type |= PERF_SAMPLE_RAW;
|
||||
attr.sample_type |= PERF_SAMPLE_TIME;
|
||||
attr.sample_type |= PERF_SAMPLE_CPU;
|
||||
attr.sample_type |= PERF_SAMPLE_PERIOD;
|
||||
attr.sample_period = 1;
|
||||
|
||||
snprintf(name, MAX_NAME_LEN, "%s:%s", sys_name, evt_name);
|
||||
return add_event(list, idx, &attr, name);
|
||||
list_add_tail(&evsel->node, list);
|
||||
*listp = list;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_tracepoint_multi(struct list_head **list, int *idx,
|
||||
|
@ -805,7 +805,7 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,
|
||||
if (pyevent == NULL)
|
||||
return PyErr_NoMemory();
|
||||
|
||||
err = perf_evlist__parse_sample(evlist, event, &pevent->sample, false);
|
||||
err = perf_evlist__parse_sample(evlist, event, &pevent->sample);
|
||||
if (err)
|
||||
return PyErr_Format(PyExc_OSError,
|
||||
"perf: can't parse sample, err=%d", err);
|
||||
|
@ -722,8 +722,7 @@ static int flush_sample_queue(struct perf_session *s,
|
||||
if (iter->timestamp > limit)
|
||||
break;
|
||||
|
||||
ret = perf_evlist__parse_sample(s->evlist, iter->event, &sample,
|
||||
s->header.needs_swap);
|
||||
ret = perf_evlist__parse_sample(s->evlist, iter->event, &sample);
|
||||
if (ret)
|
||||
pr_err("Can't parse sample, err = %d\n", ret);
|
||||
else {
|
||||
@ -1174,8 +1173,7 @@ static int perf_session__process_event(struct perf_session *session,
|
||||
/*
|
||||
* For all kernel events we get the sample data
|
||||
*/
|
||||
ret = perf_evlist__parse_sample(session->evlist, event, &sample,
|
||||
session->header.needs_swap);
|
||||
ret = perf_evlist__parse_sample(session->evlist, event, &sample);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user