Merge branch 'perf/core' of ssh://k/pub/scm/linux/kernel/git/acme/linux into perf/core
This commit is contained in:
Коммит
aef29bf20b
|
@ -115,10 +115,10 @@ OPTIONS
|
||||||
-f::
|
-f::
|
||||||
--fields::
|
--fields::
|
||||||
Comma separated list of fields to print. Options are:
|
Comma separated list of fields to print. Options are:
|
||||||
comm, tid, pid, time, cpu, event, trace, sym. Field
|
comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr.
|
||||||
list can be prepended with the type, trace, sw or hw,
|
Field list can be prepended with the type, trace, sw or hw,
|
||||||
to indicate to which event type the field list applies.
|
to indicate to which event type the field list applies.
|
||||||
e.g., -f sw:comm,tid,time,sym and -f trace:time,cpu,trace
|
e.g., -f sw:comm,tid,time,ip,sym and -f trace:time,cpu,trace
|
||||||
|
|
||||||
perf script -f <fields>
|
perf script -f <fields>
|
||||||
|
|
||||||
|
@ -132,17 +132,17 @@ OPTIONS
|
||||||
The arguments are processed in the order received. A later usage can
|
The arguments are processed in the order received. A later usage can
|
||||||
reset a prior request. e.g.:
|
reset a prior request. e.g.:
|
||||||
|
|
||||||
-f trace: -f comm,tid,time,sym
|
-f trace: -f comm,tid,time,ip,sym
|
||||||
|
|
||||||
The first -f suppresses trace events (field list is ""), but then the
|
The first -f suppresses trace events (field list is ""), but then the
|
||||||
second invocation sets the fields to comm,tid,time,sym. In this case a
|
second invocation sets the fields to comm,tid,time,ip,sym. In this case a
|
||||||
warning is given to the user:
|
warning is given to the user:
|
||||||
|
|
||||||
"Overriding previous field request for all events."
|
"Overriding previous field request for all events."
|
||||||
|
|
||||||
Alternativey, consider the order:
|
Alternativey, consider the order:
|
||||||
|
|
||||||
-f comm,tid,time,sym -f trace:
|
-f comm,tid,time,ip,sym -f trace:
|
||||||
|
|
||||||
The first -f sets the fields for all events and the second -f
|
The first -f sets the fields for all events and the second -f
|
||||||
suppresses trace events. The user is given a warning message about
|
suppresses trace events. The user is given a warning message about
|
||||||
|
|
|
@ -30,7 +30,10 @@ enum perf_output_field {
|
||||||
PERF_OUTPUT_CPU = 1U << 4,
|
PERF_OUTPUT_CPU = 1U << 4,
|
||||||
PERF_OUTPUT_EVNAME = 1U << 5,
|
PERF_OUTPUT_EVNAME = 1U << 5,
|
||||||
PERF_OUTPUT_TRACE = 1U << 6,
|
PERF_OUTPUT_TRACE = 1U << 6,
|
||||||
PERF_OUTPUT_SYM = 1U << 7,
|
PERF_OUTPUT_IP = 1U << 7,
|
||||||
|
PERF_OUTPUT_SYM = 1U << 8,
|
||||||
|
PERF_OUTPUT_DSO = 1U << 9,
|
||||||
|
PERF_OUTPUT_ADDR = 1U << 10,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct output_option {
|
struct output_option {
|
||||||
|
@ -44,7 +47,10 @@ struct output_option {
|
||||||
{.str = "cpu", .field = PERF_OUTPUT_CPU},
|
{.str = "cpu", .field = PERF_OUTPUT_CPU},
|
||||||
{.str = "event", .field = PERF_OUTPUT_EVNAME},
|
{.str = "event", .field = PERF_OUTPUT_EVNAME},
|
||||||
{.str = "trace", .field = PERF_OUTPUT_TRACE},
|
{.str = "trace", .field = PERF_OUTPUT_TRACE},
|
||||||
|
{.str = "ip", .field = PERF_OUTPUT_IP},
|
||||||
{.str = "sym", .field = PERF_OUTPUT_SYM},
|
{.str = "sym", .field = PERF_OUTPUT_SYM},
|
||||||
|
{.str = "dso", .field = PERF_OUTPUT_DSO},
|
||||||
|
{.str = "addr", .field = PERF_OUTPUT_ADDR},
|
||||||
};
|
};
|
||||||
|
|
||||||
/* default set to maintain compatibility with current format */
|
/* default set to maintain compatibility with current format */
|
||||||
|
@ -60,7 +66,8 @@ static struct {
|
||||||
|
|
||||||
.fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
|
.fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
|
||||||
PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
|
PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
|
||||||
PERF_OUTPUT_EVNAME | PERF_OUTPUT_SYM,
|
PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |
|
||||||
|
PERF_OUTPUT_SYM | PERF_OUTPUT_DSO,
|
||||||
|
|
||||||
.invalid_fields = PERF_OUTPUT_TRACE,
|
.invalid_fields = PERF_OUTPUT_TRACE,
|
||||||
},
|
},
|
||||||
|
@ -70,7 +77,8 @@ static struct {
|
||||||
|
|
||||||
.fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
|
.fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
|
||||||
PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
|
PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
|
||||||
PERF_OUTPUT_EVNAME | PERF_OUTPUT_SYM,
|
PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |
|
||||||
|
PERF_OUTPUT_SYM | PERF_OUTPUT_DSO,
|
||||||
|
|
||||||
.invalid_fields = PERF_OUTPUT_TRACE,
|
.invalid_fields = PERF_OUTPUT_TRACE,
|
||||||
},
|
},
|
||||||
|
@ -88,7 +96,8 @@ static struct {
|
||||||
|
|
||||||
.fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
|
.fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
|
||||||
PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
|
PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
|
||||||
PERF_OUTPUT_EVNAME | PERF_OUTPUT_SYM,
|
PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |
|
||||||
|
PERF_OUTPUT_SYM | PERF_OUTPUT_DSO,
|
||||||
|
|
||||||
.invalid_fields = PERF_OUTPUT_TRACE,
|
.invalid_fields = PERF_OUTPUT_TRACE,
|
||||||
},
|
},
|
||||||
|
@ -157,9 +166,9 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
|
||||||
!perf_session__has_traces(session, "record -R"))
|
!perf_session__has_traces(session, "record -R"))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (PRINT_FIELD(SYM)) {
|
if (PRINT_FIELD(IP)) {
|
||||||
if (perf_event_attr__check_stype(attr, PERF_SAMPLE_IP, "IP",
|
if (perf_event_attr__check_stype(attr, PERF_SAMPLE_IP, "IP",
|
||||||
PERF_OUTPUT_SYM))
|
PERF_OUTPUT_IP))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (!no_callchain &&
|
if (!no_callchain &&
|
||||||
|
@ -167,6 +176,24 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
|
||||||
symbol_conf.use_callchain = false;
|
symbol_conf.use_callchain = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (PRINT_FIELD(ADDR) &&
|
||||||
|
perf_event_attr__check_stype(attr, PERF_SAMPLE_ADDR, "ADDR",
|
||||||
|
PERF_OUTPUT_ADDR))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (PRINT_FIELD(SYM) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR)) {
|
||||||
|
pr_err("Display of symbols requested but neither sample IP nor "
|
||||||
|
"sample address\nis selected. Hence, no addresses to convert "
|
||||||
|
"to symbols.\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
if (PRINT_FIELD(DSO) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR)) {
|
||||||
|
pr_err("Display of DSO requested but neither sample IP nor "
|
||||||
|
"sample address\nis selected. Hence, no addresses to convert "
|
||||||
|
"to DSO.\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
if ((PRINT_FIELD(PID) || PRINT_FIELD(TID)) &&
|
if ((PRINT_FIELD(PID) || PRINT_FIELD(TID)) &&
|
||||||
perf_event_attr__check_stype(attr, PERF_SAMPLE_TID, "TID",
|
perf_event_attr__check_stype(attr, PERF_SAMPLE_TID, "TID",
|
||||||
PERF_OUTPUT_TID|PERF_OUTPUT_PID))
|
PERF_OUTPUT_TID|PERF_OUTPUT_PID))
|
||||||
|
@ -230,7 +257,7 @@ static void print_sample_start(struct perf_sample *sample,
|
||||||
if (PRINT_FIELD(COMM)) {
|
if (PRINT_FIELD(COMM)) {
|
||||||
if (latency_format)
|
if (latency_format)
|
||||||
printf("%8.8s ", thread->comm);
|
printf("%8.8s ", thread->comm);
|
||||||
else if (PRINT_FIELD(SYM) && symbol_conf.use_callchain)
|
else if (PRINT_FIELD(IP) && symbol_conf.use_callchain)
|
||||||
printf("%s ", thread->comm);
|
printf("%s ", thread->comm);
|
||||||
else
|
else
|
||||||
printf("%16s ", thread->comm);
|
printf("%16s ", thread->comm);
|
||||||
|
@ -271,6 +298,63 @@ static void print_sample_start(struct perf_sample *sample,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool sample_addr_correlates_sym(struct perf_event_attr *attr)
|
||||||
|
{
|
||||||
|
if ((attr->type == PERF_TYPE_SOFTWARE) &&
|
||||||
|
((attr->config == PERF_COUNT_SW_PAGE_FAULTS) ||
|
||||||
|
(attr->config == PERF_COUNT_SW_PAGE_FAULTS_MIN) ||
|
||||||
|
(attr->config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_sample_addr(union perf_event *event,
|
||||||
|
struct perf_sample *sample,
|
||||||
|
struct perf_session *session,
|
||||||
|
struct thread *thread,
|
||||||
|
struct perf_event_attr *attr)
|
||||||
|
{
|
||||||
|
struct addr_location al;
|
||||||
|
u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
|
||||||
|
const char *symname, *dsoname;
|
||||||
|
|
||||||
|
printf("%16" PRIx64, sample->addr);
|
||||||
|
|
||||||
|
if (!sample_addr_correlates_sym(attr))
|
||||||
|
return;
|
||||||
|
|
||||||
|
thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION,
|
||||||
|
event->ip.pid, sample->addr, &al);
|
||||||
|
if (!al.map)
|
||||||
|
thread__find_addr_map(thread, session, cpumode, MAP__VARIABLE,
|
||||||
|
event->ip.pid, sample->addr, &al);
|
||||||
|
|
||||||
|
al.cpu = sample->cpu;
|
||||||
|
al.sym = NULL;
|
||||||
|
|
||||||
|
if (al.map)
|
||||||
|
al.sym = map__find_symbol(al.map, al.addr, NULL);
|
||||||
|
|
||||||
|
if (PRINT_FIELD(SYM)) {
|
||||||
|
if (al.sym && al.sym->name)
|
||||||
|
symname = al.sym->name;
|
||||||
|
else
|
||||||
|
symname = "";
|
||||||
|
|
||||||
|
printf(" %16s", symname);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PRINT_FIELD(DSO)) {
|
||||||
|
if (al.map && al.map->dso && al.map->dso->name)
|
||||||
|
dsoname = al.map->dso->name;
|
||||||
|
else
|
||||||
|
dsoname = "";
|
||||||
|
|
||||||
|
printf(" (%s)", dsoname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void process_event(union perf_event *event __unused,
|
static void process_event(union perf_event *event __unused,
|
||||||
struct perf_sample *sample,
|
struct perf_sample *sample,
|
||||||
struct perf_evsel *evsel,
|
struct perf_evsel *evsel,
|
||||||
|
@ -288,12 +372,16 @@ static void process_event(union perf_event *event __unused,
|
||||||
print_trace_event(sample->cpu, sample->raw_data,
|
print_trace_event(sample->cpu, sample->raw_data,
|
||||||
sample->raw_size);
|
sample->raw_size);
|
||||||
|
|
||||||
if (PRINT_FIELD(SYM)) {
|
if (PRINT_FIELD(ADDR))
|
||||||
|
print_sample_addr(event, sample, session, thread, attr);
|
||||||
|
|
||||||
|
if (PRINT_FIELD(IP)) {
|
||||||
if (!symbol_conf.use_callchain)
|
if (!symbol_conf.use_callchain)
|
||||||
printf(" ");
|
printf(" ");
|
||||||
else
|
else
|
||||||
printf("\n");
|
printf("\n");
|
||||||
perf_session__print_symbols(event, sample, session);
|
perf_session__print_ip(event, sample, session,
|
||||||
|
PRINT_FIELD(SYM), PRINT_FIELD(DSO));
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
@ -985,7 +1073,7 @@ static const struct option options[] = {
|
||||||
OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
|
OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
|
||||||
"Look for files with symbols relative to this directory"),
|
"Look for files with symbols relative to this directory"),
|
||||||
OPT_CALLBACK('f', "fields", NULL, "str",
|
OPT_CALLBACK('f', "fields", NULL, "str",
|
||||||
"comma separated output fields prepend with 'type:'. Valid types: hw,sw,trace,raw. Fields: comm,tid,pid,time,cpu,event,trace,sym",
|
"comma separated output fields prepend with 'type:'. Valid types: hw,sw,trace,raw. Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso,addr",
|
||||||
parse_output_fields),
|
parse_output_fields),
|
||||||
|
|
||||||
OPT_END()
|
OPT_END()
|
||||||
|
|
|
@ -61,6 +61,8 @@
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
|
|
||||||
#define DEFAULT_SEPARATOR " "
|
#define DEFAULT_SEPARATOR " "
|
||||||
|
#define CNTR_NOT_SUPPORTED "<not supported>"
|
||||||
|
#define CNTR_NOT_COUNTED "<not counted>"
|
||||||
|
|
||||||
static struct perf_event_attr default_attrs[] = {
|
static struct perf_event_attr default_attrs[] = {
|
||||||
|
|
||||||
|
@ -448,6 +450,7 @@ static int run_perf_stat(int argc __used, const char **argv)
|
||||||
if (verbose)
|
if (verbose)
|
||||||
ui__warning("%s event is not supported by the kernel.\n",
|
ui__warning("%s event is not supported by the kernel.\n",
|
||||||
event_name(counter));
|
event_name(counter));
|
||||||
|
counter->supported = false;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -466,6 +469,7 @@ static int run_perf_stat(int argc __used, const char **argv)
|
||||||
die("Not all events could be opened.\n");
|
die("Not all events could be opened.\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
counter->supported = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (perf_evlist__set_filters(evsel_list)) {
|
if (perf_evlist__set_filters(evsel_list)) {
|
||||||
|
@ -861,7 +865,7 @@ static void print_counter_aggr(struct perf_evsel *counter)
|
||||||
if (scaled == -1) {
|
if (scaled == -1) {
|
||||||
fprintf(stderr, "%*s%s%*s",
|
fprintf(stderr, "%*s%s%*s",
|
||||||
csv_output ? 0 : 18,
|
csv_output ? 0 : 18,
|
||||||
"<not counted>",
|
counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
|
||||||
csv_sep,
|
csv_sep,
|
||||||
csv_output ? 0 : -24,
|
csv_output ? 0 : -24,
|
||||||
event_name(counter));
|
event_name(counter));
|
||||||
|
@ -914,7 +918,8 @@ static void print_counter(struct perf_evsel *counter)
|
||||||
csv_output ? 0 : -4,
|
csv_output ? 0 : -4,
|
||||||
evsel_list->cpus->map[cpu], csv_sep,
|
evsel_list->cpus->map[cpu], csv_sep,
|
||||||
csv_output ? 0 : 18,
|
csv_output ? 0 : 18,
|
||||||
"<not counted>", csv_sep,
|
counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
|
||||||
|
csv_sep,
|
||||||
csv_output ? 0 : -24,
|
csv_output ? 0 : -24,
|
||||||
event_name(counter));
|
event_name(counter));
|
||||||
|
|
||||||
|
|
|
@ -474,7 +474,7 @@ static int test__basic_mmap(void)
|
||||||
unsigned int nr_events[nsyscalls],
|
unsigned int nr_events[nsyscalls],
|
||||||
expected_nr_events[nsyscalls], i, j;
|
expected_nr_events[nsyscalls], i, j;
|
||||||
struct perf_evsel *evsels[nsyscalls], *evsel;
|
struct perf_evsel *evsels[nsyscalls], *evsel;
|
||||||
int sample_size = perf_sample_size(attr.sample_type);
|
int sample_size = __perf_evsel__sample_size(attr.sample_type);
|
||||||
|
|
||||||
for (i = 0; i < nsyscalls; ++i) {
|
for (i = 0; i < nsyscalls; ++i) {
|
||||||
char name[64];
|
char name[64];
|
||||||
|
|
|
@ -35,22 +35,6 @@ const char *perf_event__name(unsigned int id)
|
||||||
return perf_event__names[id];
|
return perf_event__names[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
int perf_sample_size(u64 sample_type)
|
|
||||||
{
|
|
||||||
u64 mask = sample_type & PERF_SAMPLE_MASK;
|
|
||||||
int size = 0;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < 64; i++) {
|
|
||||||
if (mask & (1ULL << i))
|
|
||||||
size++;
|
|
||||||
}
|
|
||||||
|
|
||||||
size *= sizeof(u64);
|
|
||||||
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct perf_sample synth_sample = {
|
static struct perf_sample synth_sample = {
|
||||||
.pid = -1,
|
.pid = -1,
|
||||||
.tid = -1,
|
.tid = -1,
|
||||||
|
|
|
@ -82,8 +82,6 @@ struct perf_sample {
|
||||||
struct ip_callchain *callchain;
|
struct ip_callchain *callchain;
|
||||||
};
|
};
|
||||||
|
|
||||||
int perf_sample_size(u64 sample_type);
|
|
||||||
|
|
||||||
#define BUILD_ID_SIZE 20
|
#define BUILD_ID_SIZE 20
|
||||||
|
|
||||||
struct build_id_event {
|
struct build_id_event {
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
#include "evlist.h"
|
#include "evlist.h"
|
||||||
#include "evsel.h"
|
#include "evsel.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "debug.h"
|
|
||||||
|
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
|
|
||||||
|
@ -257,19 +256,15 @@ int perf_evlist__alloc_mmap(struct perf_evlist *evlist)
|
||||||
return evlist->mmap != NULL ? 0 : -ENOMEM;
|
return evlist->mmap != NULL ? 0 : -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __perf_evlist__mmap(struct perf_evlist *evlist, struct perf_evsel *evsel,
|
static int __perf_evlist__mmap(struct perf_evlist *evlist,
|
||||||
int idx, int prot, int mask, int fd)
|
int idx, int prot, int mask, int fd)
|
||||||
{
|
{
|
||||||
evlist->mmap[idx].prev = 0;
|
evlist->mmap[idx].prev = 0;
|
||||||
evlist->mmap[idx].mask = mask;
|
evlist->mmap[idx].mask = mask;
|
||||||
evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, prot,
|
evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, prot,
|
||||||
MAP_SHARED, fd, 0);
|
MAP_SHARED, fd, 0);
|
||||||
if (evlist->mmap[idx].base == MAP_FAILED) {
|
if (evlist->mmap[idx].base == MAP_FAILED)
|
||||||
if (evlist->cpus->map[idx] == -1 && evsel->attr.inherit)
|
|
||||||
ui__warning("Inherit is not allowed on per-task "
|
|
||||||
"events using mmap.\n");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
|
||||||
|
|
||||||
perf_evlist__add_pollfd(evlist, fd);
|
perf_evlist__add_pollfd(evlist, fd);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -289,7 +284,7 @@ static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, int m
|
||||||
|
|
||||||
if (output == -1) {
|
if (output == -1) {
|
||||||
output = fd;
|
output = fd;
|
||||||
if (__perf_evlist__mmap(evlist, evsel, cpu,
|
if (__perf_evlist__mmap(evlist, cpu,
|
||||||
prot, mask, output) < 0)
|
prot, mask, output) < 0)
|
||||||
goto out_unmap;
|
goto out_unmap;
|
||||||
} else {
|
} else {
|
||||||
|
@ -329,7 +324,7 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, in
|
||||||
|
|
||||||
if (output == -1) {
|
if (output == -1) {
|
||||||
output = fd;
|
output = fd;
|
||||||
if (__perf_evlist__mmap(evlist, evsel, thread,
|
if (__perf_evlist__mmap(evlist, thread,
|
||||||
prot, mask, output) < 0)
|
prot, mask, output) < 0)
|
||||||
goto out_unmap;
|
goto out_unmap;
|
||||||
} else {
|
} else {
|
||||||
|
@ -460,33 +455,46 @@ int perf_evlist__set_filters(struct perf_evlist *evlist)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 perf_evlist__sample_type(struct perf_evlist *evlist)
|
bool perf_evlist__valid_sample_type(const struct perf_evlist *evlist)
|
||||||
{
|
{
|
||||||
struct perf_evsel *pos;
|
struct perf_evsel *pos, *first;
|
||||||
u64 type = 0;
|
|
||||||
|
|
||||||
list_for_each_entry(pos, &evlist->entries, node) {
|
pos = first = list_entry(evlist->entries.next, struct perf_evsel, node);
|
||||||
if (!type)
|
|
||||||
type = pos->attr.sample_type;
|
list_for_each_entry_continue(pos, &evlist->entries, node) {
|
||||||
else if (type != pos->attr.sample_type)
|
if (first->attr.sample_type != pos->attr.sample_type)
|
||||||
die("non matching sample_type");
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return type;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 perf_evlist__sample_type(const struct perf_evlist *evlist)
|
||||||
|
{
|
||||||
|
struct perf_evsel *first;
|
||||||
|
|
||||||
|
first = list_entry(evlist->entries.next, struct perf_evsel, node);
|
||||||
|
return first->attr.sample_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool perf_evlist__valid_sample_id_all(const struct perf_evlist *evlist)
|
||||||
|
{
|
||||||
|
struct perf_evsel *pos, *first;
|
||||||
|
|
||||||
|
pos = first = list_entry(evlist->entries.next, struct perf_evsel, node);
|
||||||
|
|
||||||
|
list_for_each_entry_continue(pos, &evlist->entries, node) {
|
||||||
|
if (first->attr.sample_id_all != pos->attr.sample_id_all)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool perf_evlist__sample_id_all(const struct perf_evlist *evlist)
|
bool perf_evlist__sample_id_all(const struct perf_evlist *evlist)
|
||||||
{
|
{
|
||||||
bool value = false, first = true;
|
struct perf_evsel *first;
|
||||||
struct perf_evsel *pos;
|
|
||||||
|
|
||||||
list_for_each_entry(pos, &evlist->entries, node) {
|
first = list_entry(evlist->entries.next, struct perf_evsel, node);
|
||||||
if (first) {
|
return first->attr.sample_id_all;
|
||||||
value = pos->attr.sample_id_all;
|
|
||||||
first = false;
|
|
||||||
} else if (value != pos->attr.sample_id_all)
|
|
||||||
die("non matching sample_id_all");
|
|
||||||
}
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,7 +66,9 @@ int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid,
|
||||||
void perf_evlist__delete_maps(struct perf_evlist *evlist);
|
void perf_evlist__delete_maps(struct perf_evlist *evlist);
|
||||||
int perf_evlist__set_filters(struct perf_evlist *evlist);
|
int perf_evlist__set_filters(struct perf_evlist *evlist);
|
||||||
|
|
||||||
u64 perf_evlist__sample_type(struct perf_evlist *evlist);
|
u64 perf_evlist__sample_type(const struct perf_evlist *evlist);
|
||||||
bool perf_evlist__sample_id_all(const struct perf_evlist *evlist);
|
bool perf_evlist__sample_id_all(const const struct perf_evlist *evlist);
|
||||||
|
|
||||||
|
bool perf_evlist__valid_sample_type(const struct perf_evlist *evlist);
|
||||||
|
bool perf_evlist__valid_sample_id_all(const struct perf_evlist *evlist);
|
||||||
#endif /* __PERF_EVLIST_H */
|
#endif /* __PERF_EVLIST_H */
|
||||||
|
|
|
@ -15,6 +15,22 @@
|
||||||
|
|
||||||
#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
|
#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
|
||||||
|
|
||||||
|
int __perf_evsel__sample_size(u64 sample_type)
|
||||||
|
{
|
||||||
|
u64 mask = sample_type & PERF_SAMPLE_MASK;
|
||||||
|
int size = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < 64; i++) {
|
||||||
|
if (mask & (1ULL << i))
|
||||||
|
size++;
|
||||||
|
}
|
||||||
|
|
||||||
|
size *= sizeof(u64);
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
void perf_evsel__init(struct perf_evsel *evsel,
|
void perf_evsel__init(struct perf_evsel *evsel,
|
||||||
struct perf_event_attr *attr, int idx)
|
struct perf_event_attr *attr, int idx)
|
||||||
{
|
{
|
||||||
|
@ -361,6 +377,7 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,
|
||||||
array++;
|
array++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data->addr = 0;
|
||||||
if (type & PERF_SAMPLE_ADDR) {
|
if (type & PERF_SAMPLE_ADDR) {
|
||||||
data->addr = *array;
|
data->addr = *array;
|
||||||
array++;
|
array++;
|
||||||
|
|
|
@ -61,6 +61,7 @@ struct perf_evsel {
|
||||||
off_t id_offset;
|
off_t id_offset;
|
||||||
};
|
};
|
||||||
struct cgroup_sel *cgrp;
|
struct cgroup_sel *cgrp;
|
||||||
|
bool supported;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct cpu_map;
|
struct cpu_map;
|
||||||
|
@ -149,4 +150,11 @@ static inline int perf_evsel__read_scaled(struct perf_evsel *evsel,
|
||||||
return __perf_evsel__read(evsel, ncpus, nthreads, true);
|
return __perf_evsel__read(evsel, ncpus, nthreads, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int __perf_evsel__sample_size(u64 sample_type);
|
||||||
|
|
||||||
|
static inline int perf_evsel__sample_size(struct perf_evsel *evsel)
|
||||||
|
{
|
||||||
|
return __perf_evsel__sample_size(evsel->attr.sample_type);
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* __PERF_EVSEL_H */
|
#endif /* __PERF_EVSEL_H */
|
||||||
|
|
|
@ -247,7 +247,7 @@ struct pyrf_cpu_map {
|
||||||
static int pyrf_cpu_map__init(struct pyrf_cpu_map *pcpus,
|
static int pyrf_cpu_map__init(struct pyrf_cpu_map *pcpus,
|
||||||
PyObject *args, PyObject *kwargs)
|
PyObject *args, PyObject *kwargs)
|
||||||
{
|
{
|
||||||
static char *kwlist[] = { "cpustr", NULL, NULL, };
|
static char *kwlist[] = { "cpustr", NULL };
|
||||||
char *cpustr = NULL;
|
char *cpustr = NULL;
|
||||||
|
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|s",
|
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|s",
|
||||||
|
@ -316,7 +316,7 @@ struct pyrf_thread_map {
|
||||||
static int pyrf_thread_map__init(struct pyrf_thread_map *pthreads,
|
static int pyrf_thread_map__init(struct pyrf_thread_map *pthreads,
|
||||||
PyObject *args, PyObject *kwargs)
|
PyObject *args, PyObject *kwargs)
|
||||||
{
|
{
|
||||||
static char *kwlist[] = { "pid", "tid", NULL, NULL, };
|
static char *kwlist[] = { "pid", "tid", NULL };
|
||||||
int pid = -1, tid = -1;
|
int pid = -1, tid = -1;
|
||||||
|
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ii",
|
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ii",
|
||||||
|
@ -418,7 +418,9 @@ static int pyrf_evsel__init(struct pyrf_evsel *pevsel,
|
||||||
"wakeup_events",
|
"wakeup_events",
|
||||||
"bp_type",
|
"bp_type",
|
||||||
"bp_addr",
|
"bp_addr",
|
||||||
"bp_len", NULL, NULL, };
|
"bp_len",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
u64 sample_period = 0;
|
u64 sample_period = 0;
|
||||||
u32 disabled = 0,
|
u32 disabled = 0,
|
||||||
inherit = 0,
|
inherit = 0,
|
||||||
|
@ -499,7 +501,7 @@ static PyObject *pyrf_evsel__open(struct pyrf_evsel *pevsel,
|
||||||
struct thread_map *threads = NULL;
|
struct thread_map *threads = NULL;
|
||||||
PyObject *pcpus = NULL, *pthreads = NULL;
|
PyObject *pcpus = NULL, *pthreads = NULL;
|
||||||
int group = 0, inherit = 0;
|
int group = 0, inherit = 0;
|
||||||
static char *kwlist[] = {"cpus", "threads", "group", "inherit", NULL, NULL};
|
static char *kwlist[] = { "cpus", "threads", "group", "inherit", NULL };
|
||||||
|
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOii", kwlist,
|
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOii", kwlist,
|
||||||
&pcpus, &pthreads, &group, &inherit))
|
&pcpus, &pthreads, &group, &inherit))
|
||||||
|
@ -582,8 +584,7 @@ static PyObject *pyrf_evlist__mmap(struct pyrf_evlist *pevlist,
|
||||||
PyObject *args, PyObject *kwargs)
|
PyObject *args, PyObject *kwargs)
|
||||||
{
|
{
|
||||||
struct perf_evlist *evlist = &pevlist->evlist;
|
struct perf_evlist *evlist = &pevlist->evlist;
|
||||||
static char *kwlist[] = {"pages", "overwrite",
|
static char *kwlist[] = { "pages", "overwrite", NULL };
|
||||||
NULL, NULL};
|
|
||||||
int pages = 128, overwrite = false;
|
int pages = 128, overwrite = false;
|
||||||
|
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ii", kwlist,
|
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ii", kwlist,
|
||||||
|
@ -603,7 +604,7 @@ static PyObject *pyrf_evlist__poll(struct pyrf_evlist *pevlist,
|
||||||
PyObject *args, PyObject *kwargs)
|
PyObject *args, PyObject *kwargs)
|
||||||
{
|
{
|
||||||
struct perf_evlist *evlist = &pevlist->evlist;
|
struct perf_evlist *evlist = &pevlist->evlist;
|
||||||
static char *kwlist[] = {"timeout", NULL, NULL};
|
static char *kwlist[] = { "timeout", NULL };
|
||||||
int timeout = -1, n;
|
int timeout = -1, n;
|
||||||
|
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i", kwlist, &timeout))
|
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i", kwlist, &timeout))
|
||||||
|
@ -674,7 +675,7 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,
|
||||||
struct perf_evlist *evlist = &pevlist->evlist;
|
struct perf_evlist *evlist = &pevlist->evlist;
|
||||||
union perf_event *event;
|
union perf_event *event;
|
||||||
int sample_id_all = 1, cpu;
|
int sample_id_all = 1, cpu;
|
||||||
static char *kwlist[] = {"sample_id_all", NULL, NULL};
|
static char *kwlist[] = { "cpu", "sample_id_all", NULL };
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|i", kwlist,
|
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|i", kwlist,
|
||||||
|
@ -692,16 +693,14 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,
|
||||||
|
|
||||||
first = list_entry(evlist->entries.next, struct perf_evsel, node);
|
first = list_entry(evlist->entries.next, struct perf_evsel, node);
|
||||||
err = perf_event__parse_sample(event, first->attr.sample_type,
|
err = perf_event__parse_sample(event, first->attr.sample_type,
|
||||||
perf_sample_size(first->attr.sample_type),
|
perf_evsel__sample_size(first),
|
||||||
sample_id_all, &pevent->sample);
|
sample_id_all, &pevent->sample);
|
||||||
if (err) {
|
if (err)
|
||||||
pr_err("Can't parse sample, err = %d\n", err);
|
return PyErr_Format(PyExc_OSError,
|
||||||
goto end;
|
"perf: can't parse sample, err=%d", err);
|
||||||
}
|
|
||||||
|
|
||||||
return pyevent;
|
return pyevent;
|
||||||
}
|
}
|
||||||
end:
|
|
||||||
Py_INCREF(Py_None);
|
Py_INCREF(Py_None);
|
||||||
return Py_None;
|
return Py_None;
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,6 +58,16 @@ static int perf_session__open(struct perf_session *self, bool force)
|
||||||
goto out_close;
|
goto out_close;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!perf_evlist__valid_sample_type(self->evlist)) {
|
||||||
|
pr_err("non matching sample_type");
|
||||||
|
goto out_close;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!perf_evlist__valid_sample_id_all(self->evlist)) {
|
||||||
|
pr_err("non matching sample_id_all");
|
||||||
|
goto out_close;
|
||||||
|
}
|
||||||
|
|
||||||
self->size = input_stat.st_size;
|
self->size = input_stat.st_size;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -97,7 +107,7 @@ out:
|
||||||
void perf_session__update_sample_type(struct perf_session *self)
|
void perf_session__update_sample_type(struct perf_session *self)
|
||||||
{
|
{
|
||||||
self->sample_type = perf_evlist__sample_type(self->evlist);
|
self->sample_type = perf_evlist__sample_type(self->evlist);
|
||||||
self->sample_size = perf_sample_size(self->sample_type);
|
self->sample_size = __perf_evsel__sample_size(self->sample_type);
|
||||||
self->sample_id_all = perf_evlist__sample_id_all(self->evlist);
|
self->sample_id_all = perf_evlist__sample_id_all(self->evlist);
|
||||||
perf_session__id_header_size(self);
|
perf_session__id_header_size(self);
|
||||||
}
|
}
|
||||||
|
@ -698,9 +708,9 @@ static void dump_sample(struct perf_session *session, union perf_event *event,
|
||||||
if (!dump_trace)
|
if (!dump_trace)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
printf("(IP, %d): %d/%d: %#" PRIx64 " period: %" PRIu64 "\n",
|
printf("(IP, %d): %d/%d: %#" PRIx64 " period: %" PRIu64 " addr: %#" PRIx64 "\n",
|
||||||
event->header.misc, sample->pid, sample->tid, sample->ip,
|
event->header.misc, sample->pid, sample->tid, sample->ip,
|
||||||
sample->period);
|
sample->period, sample->addr);
|
||||||
|
|
||||||
if (session->sample_type & PERF_SAMPLE_CALLCHAIN)
|
if (session->sample_type & PERF_SAMPLE_CALLCHAIN)
|
||||||
callchain__printf(sample);
|
callchain__printf(sample);
|
||||||
|
@ -1192,9 +1202,10 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void perf_session__print_symbols(union perf_event *event,
|
void perf_session__print_ip(union perf_event *event,
|
||||||
struct perf_sample *sample,
|
struct perf_sample *sample,
|
||||||
struct perf_session *session)
|
struct perf_session *session,
|
||||||
|
int print_sym, int print_dso)
|
||||||
{
|
{
|
||||||
struct addr_location al;
|
struct addr_location al;
|
||||||
const char *symname, *dsoname;
|
const char *symname, *dsoname;
|
||||||
|
@ -1223,32 +1234,46 @@ void perf_session__print_symbols(union perf_event *event,
|
||||||
if (!node)
|
if (!node)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (node->sym && node->sym->name)
|
printf("\t%16" PRIx64, node->ip);
|
||||||
symname = node->sym->name;
|
if (print_sym) {
|
||||||
else
|
if (node->sym && node->sym->name)
|
||||||
symname = "";
|
symname = node->sym->name;
|
||||||
|
else
|
||||||
|
symname = "";
|
||||||
|
|
||||||
if (node->map && node->map->dso && node->map->dso->name)
|
printf(" %s", symname);
|
||||||
dsoname = node->map->dso->name;
|
}
|
||||||
else
|
if (print_dso) {
|
||||||
dsoname = "";
|
if (node->map && node->map->dso && node->map->dso->name)
|
||||||
|
dsoname = node->map->dso->name;
|
||||||
|
else
|
||||||
|
dsoname = "";
|
||||||
|
|
||||||
printf("\t%16" PRIx64 " %s (%s)\n", node->ip, symname, dsoname);
|
printf(" (%s)", dsoname);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
callchain_cursor_advance(cursor);
|
callchain_cursor_advance(cursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (al.sym && al.sym->name)
|
printf("%16" PRIx64, al.addr);
|
||||||
symname = al.sym->name;
|
if (print_sym) {
|
||||||
else
|
if (al.sym && al.sym->name)
|
||||||
symname = "";
|
symname = al.sym->name;
|
||||||
|
else
|
||||||
|
symname = "";
|
||||||
|
|
||||||
if (al.map && al.map->dso && al.map->dso->name)
|
printf(" %s", symname);
|
||||||
dsoname = al.map->dso->name;
|
}
|
||||||
else
|
|
||||||
dsoname = "";
|
|
||||||
|
|
||||||
printf("%16" PRIx64 " %s (%s)", al.addr, symname, dsoname);
|
if (print_dso) {
|
||||||
|
if (al.map && al.map->dso && al.map->dso->name)
|
||||||
|
dsoname = al.map->dso->name;
|
||||||
|
else
|
||||||
|
dsoname = "";
|
||||||
|
|
||||||
|
printf(" (%s)", dsoname);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -167,8 +167,9 @@ static inline int perf_session__parse_sample(struct perf_session *session,
|
||||||
struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
|
struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
|
||||||
unsigned int type);
|
unsigned int type);
|
||||||
|
|
||||||
void perf_session__print_symbols(union perf_event *event,
|
void perf_session__print_ip(union perf_event *event,
|
||||||
struct perf_sample *sample,
|
struct perf_sample *sample,
|
||||||
struct perf_session *session);
|
struct perf_session *session,
|
||||||
|
int print_sym, int print_dso);
|
||||||
|
|
||||||
#endif /* __PERF_SESSION_H */
|
#endif /* __PERF_SESSION_H */
|
||||||
|
|
Загрузка…
Ссылка в новой задаче