perf tools: Add support for PERF_SAMPLE_IDENTIFIER
Enable parsing of samples with sample format bit PERF_SAMPLE_IDENTIFIER. In addition, if the kernel supports it, prefer it to selecting PERF_SAMPLE_ID thereby allowing non-matching sample types. Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> Cc: David Ahern <dsahern@gmail.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Ingo Molnar <mingo@kernel.org> Cc: Jiri Olsa <jolsa@redhat.com> Cc: Mike Galbraith <efault@gmx.de> Cc: Namhyung Kim <namhyung@gmail.com> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephane Eranian <eranian@google.com> Link: http://lkml.kernel.org/r/1377591794-30553-8-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
faf967068e
commit
75562573ba
9 changed files with 310 additions and 22 deletions
|
@ -365,7 +365,7 @@ static int process_read_event(struct perf_tool *tool,
|
||||||
static int perf_report__setup_sample_type(struct perf_report *rep)
|
static int perf_report__setup_sample_type(struct perf_report *rep)
|
||||||
{
|
{
|
||||||
struct perf_session *self = rep->session;
|
struct perf_session *self = rep->session;
|
||||||
u64 sample_type = perf_evlist__sample_type(self->evlist);
|
u64 sample_type = perf_evlist__combined_sample_type(self->evlist);
|
||||||
|
|
||||||
if (!self->fd_pipe && !(sample_type & PERF_SAMPLE_CALLCHAIN)) {
|
if (!self->fd_pipe && !(sample_type & PERF_SAMPLE_CALLCHAIN)) {
|
||||||
if (sort__has_parent) {
|
if (sort__has_parent) {
|
||||||
|
|
|
@ -72,7 +72,7 @@ int test__basic_mmap(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
evsels[i]->attr.wakeup_events = 1;
|
evsels[i]->attr.wakeup_events = 1;
|
||||||
perf_evsel__set_sample_id(evsels[i]);
|
perf_evsel__set_sample_id(evsels[i], false);
|
||||||
|
|
||||||
perf_evlist__add(evlist, evsels[i]);
|
perf_evlist__add(evlist, evsels[i]);
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,8 @@ struct read_event {
|
||||||
(PERF_SAMPLE_IP | PERF_SAMPLE_TID | \
|
(PERF_SAMPLE_IP | PERF_SAMPLE_TID | \
|
||||||
PERF_SAMPLE_TIME | PERF_SAMPLE_ADDR | \
|
PERF_SAMPLE_TIME | PERF_SAMPLE_ADDR | \
|
||||||
PERF_SAMPLE_ID | PERF_SAMPLE_STREAM_ID | \
|
PERF_SAMPLE_ID | PERF_SAMPLE_STREAM_ID | \
|
||||||
PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD)
|
PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD | \
|
||||||
|
PERF_SAMPLE_IDENTIFIER)
|
||||||
|
|
||||||
struct sample_event {
|
struct sample_event {
|
||||||
struct perf_event_header header;
|
struct perf_event_header header;
|
||||||
|
|
|
@ -49,6 +49,21 @@ struct perf_evlist *perf_evlist__new(void)
|
||||||
return evlist;
|
return evlist;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* perf_evlist__set_id_pos - set the positions of event ids.
|
||||||
|
* @evlist: selected event list
|
||||||
|
*
|
||||||
|
* Events with compatible sample types all have the same id_pos
|
||||||
|
* and is_pos. For convenience, put a copy on evlist.
|
||||||
|
*/
|
||||||
|
void perf_evlist__set_id_pos(struct perf_evlist *evlist)
|
||||||
|
{
|
||||||
|
struct perf_evsel *first = perf_evlist__first(evlist);
|
||||||
|
|
||||||
|
evlist->id_pos = first->id_pos;
|
||||||
|
evlist->is_pos = first->is_pos;
|
||||||
|
}
|
||||||
|
|
||||||
static void perf_evlist__purge(struct perf_evlist *evlist)
|
static void perf_evlist__purge(struct perf_evlist *evlist)
|
||||||
{
|
{
|
||||||
struct perf_evsel *pos, *n;
|
struct perf_evsel *pos, *n;
|
||||||
|
@ -79,15 +94,20 @@ void perf_evlist__delete(struct perf_evlist *evlist)
|
||||||
void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry)
|
void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry)
|
||||||
{
|
{
|
||||||
list_add_tail(&entry->node, &evlist->entries);
|
list_add_tail(&entry->node, &evlist->entries);
|
||||||
++evlist->nr_entries;
|
if (!evlist->nr_entries++)
|
||||||
|
perf_evlist__set_id_pos(evlist);
|
||||||
}
|
}
|
||||||
|
|
||||||
void perf_evlist__splice_list_tail(struct perf_evlist *evlist,
|
void perf_evlist__splice_list_tail(struct perf_evlist *evlist,
|
||||||
struct list_head *list,
|
struct list_head *list,
|
||||||
int nr_entries)
|
int nr_entries)
|
||||||
{
|
{
|
||||||
|
bool set_id_pos = !evlist->nr_entries;
|
||||||
|
|
||||||
list_splice_tail(list, &evlist->entries);
|
list_splice_tail(list, &evlist->entries);
|
||||||
evlist->nr_entries += nr_entries;
|
evlist->nr_entries += nr_entries;
|
||||||
|
if (set_id_pos)
|
||||||
|
perf_evlist__set_id_pos(evlist);
|
||||||
}
|
}
|
||||||
|
|
||||||
void __perf_evlist__set_leader(struct list_head *list)
|
void __perf_evlist__set_leader(struct list_head *list)
|
||||||
|
@ -349,6 +369,55 @@ struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int perf_evlist__event2id(struct perf_evlist *evlist,
|
||||||
|
union perf_event *event, u64 *id)
|
||||||
|
{
|
||||||
|
const u64 *array = event->sample.array;
|
||||||
|
ssize_t n;
|
||||||
|
|
||||||
|
n = (event->header.size - sizeof(event->header)) >> 3;
|
||||||
|
|
||||||
|
if (event->header.type == PERF_RECORD_SAMPLE) {
|
||||||
|
if (evlist->id_pos >= n)
|
||||||
|
return -1;
|
||||||
|
*id = array[evlist->id_pos];
|
||||||
|
} else {
|
||||||
|
if (evlist->is_pos > n)
|
||||||
|
return -1;
|
||||||
|
n -= evlist->is_pos;
|
||||||
|
*id = array[n];
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct perf_evsel *perf_evlist__event2evsel(struct perf_evlist *evlist,
|
||||||
|
union perf_event *event)
|
||||||
|
{
|
||||||
|
struct hlist_head *head;
|
||||||
|
struct perf_sample_id *sid;
|
||||||
|
int hash;
|
||||||
|
u64 id;
|
||||||
|
|
||||||
|
if (evlist->nr_entries == 1)
|
||||||
|
return perf_evlist__first(evlist);
|
||||||
|
|
||||||
|
if (perf_evlist__event2id(evlist, event, &id))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Synthesized events have an id of zero */
|
||||||
|
if (!id)
|
||||||
|
return perf_evlist__first(evlist);
|
||||||
|
|
||||||
|
hash = hash_64(id, PERF_EVLIST__HLIST_BITS);
|
||||||
|
head = &evlist->heads[hash];
|
||||||
|
|
||||||
|
hlist_for_each_entry(sid, head, node) {
|
||||||
|
if (sid->id == id)
|
||||||
|
return sid->evsel;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
|
union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
|
||||||
{
|
{
|
||||||
struct perf_mmap *md = &evlist->mmap[idx];
|
struct perf_mmap *md = &evlist->mmap[idx];
|
||||||
|
@ -659,20 +728,40 @@ int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter)
|
||||||
|
|
||||||
bool perf_evlist__valid_sample_type(struct perf_evlist *evlist)
|
bool perf_evlist__valid_sample_type(struct perf_evlist *evlist)
|
||||||
{
|
{
|
||||||
struct perf_evsel *first = perf_evlist__first(evlist), *pos = first;
|
struct perf_evsel *pos;
|
||||||
|
|
||||||
list_for_each_entry_continue(pos, &evlist->entries, node) {
|
if (evlist->nr_entries == 1)
|
||||||
if (first->attr.sample_type != pos->attr.sample_type)
|
return true;
|
||||||
|
|
||||||
|
if (evlist->id_pos < 0 || evlist->is_pos < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
list_for_each_entry(pos, &evlist->entries, node) {
|
||||||
|
if (pos->id_pos != evlist->id_pos ||
|
||||||
|
pos->is_pos != evlist->is_pos)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 perf_evlist__sample_type(struct perf_evlist *evlist)
|
u64 __perf_evlist__combined_sample_type(struct perf_evlist *evlist)
|
||||||
{
|
{
|
||||||
struct perf_evsel *first = perf_evlist__first(evlist);
|
struct perf_evsel *evsel;
|
||||||
return first->attr.sample_type;
|
|
||||||
|
if (evlist->combined_sample_type)
|
||||||
|
return evlist->combined_sample_type;
|
||||||
|
|
||||||
|
list_for_each_entry(evsel, &evlist->entries, node)
|
||||||
|
evlist->combined_sample_type |= evsel->attr.sample_type;
|
||||||
|
|
||||||
|
return evlist->combined_sample_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 perf_evlist__combined_sample_type(struct perf_evlist *evlist)
|
||||||
|
{
|
||||||
|
evlist->combined_sample_type = 0;
|
||||||
|
return __perf_evlist__combined_sample_type(evlist);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool perf_evlist__valid_read_format(struct perf_evlist *evlist)
|
bool perf_evlist__valid_read_format(struct perf_evlist *evlist)
|
||||||
|
@ -727,6 +816,9 @@ u16 perf_evlist__id_hdr_size(struct perf_evlist *evlist)
|
||||||
|
|
||||||
if (sample_type & PERF_SAMPLE_CPU)
|
if (sample_type & PERF_SAMPLE_CPU)
|
||||||
size += sizeof(data->cpu) * 2;
|
size += sizeof(data->cpu) * 2;
|
||||||
|
|
||||||
|
if (sample_type & PERF_SAMPLE_IDENTIFIER)
|
||||||
|
size += sizeof(data->id);
|
||||||
out:
|
out:
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
@ -885,7 +977,10 @@ int perf_evlist__start_workload(struct perf_evlist *evlist)
|
||||||
int perf_evlist__parse_sample(struct perf_evlist *evlist, union perf_event *event,
|
int perf_evlist__parse_sample(struct perf_evlist *evlist, union perf_event *event,
|
||||||
struct perf_sample *sample)
|
struct perf_sample *sample)
|
||||||
{
|
{
|
||||||
struct perf_evsel *evsel = perf_evlist__first(evlist);
|
struct perf_evsel *evsel = perf_evlist__event2evsel(evlist, event);
|
||||||
|
|
||||||
|
if (!evsel)
|
||||||
|
return -EFAULT;
|
||||||
return perf_evsel__parse_sample(evsel, event, sample);
|
return perf_evsel__parse_sample(evsel, event, sample);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,9 @@ struct perf_evlist {
|
||||||
int nr_fds;
|
int nr_fds;
|
||||||
int nr_mmaps;
|
int nr_mmaps;
|
||||||
int mmap_len;
|
int mmap_len;
|
||||||
|
int id_pos;
|
||||||
|
int is_pos;
|
||||||
|
u64 combined_sample_type;
|
||||||
struct {
|
struct {
|
||||||
int cork_fd;
|
int cork_fd;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
@ -85,6 +88,8 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx);
|
||||||
int perf_evlist__open(struct perf_evlist *evlist);
|
int perf_evlist__open(struct perf_evlist *evlist);
|
||||||
void perf_evlist__close(struct perf_evlist *evlist);
|
void perf_evlist__close(struct perf_evlist *evlist);
|
||||||
|
|
||||||
|
void perf_evlist__set_id_pos(struct perf_evlist *evlist);
|
||||||
|
bool perf_can_sample_identifier(void);
|
||||||
void perf_evlist__config(struct perf_evlist *evlist,
|
void perf_evlist__config(struct perf_evlist *evlist,
|
||||||
struct perf_record_opts *opts);
|
struct perf_record_opts *opts);
|
||||||
|
|
||||||
|
@ -121,7 +126,8 @@ void __perf_evlist__set_leader(struct list_head *list);
|
||||||
void perf_evlist__set_leader(struct perf_evlist *evlist);
|
void perf_evlist__set_leader(struct perf_evlist *evlist);
|
||||||
|
|
||||||
u64 perf_evlist__read_format(struct perf_evlist *evlist);
|
u64 perf_evlist__read_format(struct perf_evlist *evlist);
|
||||||
u64 perf_evlist__sample_type(struct perf_evlist *evlist);
|
u64 __perf_evlist__combined_sample_type(struct perf_evlist *evlist);
|
||||||
|
u64 perf_evlist__combined_sample_type(struct perf_evlist *evlist);
|
||||||
bool perf_evlist__sample_id_all(struct perf_evlist *evlist);
|
bool perf_evlist__sample_id_all(struct perf_evlist *evlist);
|
||||||
u16 perf_evlist__id_hdr_size(struct perf_evlist *evlist);
|
u16 perf_evlist__id_hdr_size(struct perf_evlist *evlist);
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ static struct {
|
||||||
|
|
||||||
#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
|
#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
|
||||||
|
|
||||||
static int __perf_evsel__sample_size(u64 sample_type)
|
int __perf_evsel__sample_size(u64 sample_type)
|
||||||
{
|
{
|
||||||
u64 mask = sample_type & PERF_SAMPLE_MASK;
|
u64 mask = sample_type & PERF_SAMPLE_MASK;
|
||||||
int size = 0;
|
int size = 0;
|
||||||
|
@ -47,6 +47,72 @@ static int __perf_evsel__sample_size(u64 sample_type)
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __perf_evsel__calc_id_pos - calculate id_pos.
|
||||||
|
* @sample_type: sample type
|
||||||
|
*
|
||||||
|
* This function returns the position of the event id (PERF_SAMPLE_ID or
|
||||||
|
* PERF_SAMPLE_IDENTIFIER) in a sample event i.e. in the array of struct
|
||||||
|
* sample_event.
|
||||||
|
*/
|
||||||
|
static int __perf_evsel__calc_id_pos(u64 sample_type)
|
||||||
|
{
|
||||||
|
int idx = 0;
|
||||||
|
|
||||||
|
if (sample_type & PERF_SAMPLE_IDENTIFIER)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!(sample_type & PERF_SAMPLE_ID))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (sample_type & PERF_SAMPLE_IP)
|
||||||
|
idx += 1;
|
||||||
|
|
||||||
|
if (sample_type & PERF_SAMPLE_TID)
|
||||||
|
idx += 1;
|
||||||
|
|
||||||
|
if (sample_type & PERF_SAMPLE_TIME)
|
||||||
|
idx += 1;
|
||||||
|
|
||||||
|
if (sample_type & PERF_SAMPLE_ADDR)
|
||||||
|
idx += 1;
|
||||||
|
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __perf_evsel__calc_is_pos - calculate is_pos.
|
||||||
|
* @sample_type: sample type
|
||||||
|
*
|
||||||
|
* This function returns the position (counting backwards) of the event id
|
||||||
|
* (PERF_SAMPLE_ID or PERF_SAMPLE_IDENTIFIER) in a non-sample event i.e. if
|
||||||
|
* sample_id_all is used there is an id sample appended to non-sample events.
|
||||||
|
*/
|
||||||
|
static int __perf_evsel__calc_is_pos(u64 sample_type)
|
||||||
|
{
|
||||||
|
int idx = 1;
|
||||||
|
|
||||||
|
if (sample_type & PERF_SAMPLE_IDENTIFIER)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (!(sample_type & PERF_SAMPLE_ID))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (sample_type & PERF_SAMPLE_CPU)
|
||||||
|
idx += 1;
|
||||||
|
|
||||||
|
if (sample_type & PERF_SAMPLE_STREAM_ID)
|
||||||
|
idx += 1;
|
||||||
|
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void perf_evsel__calc_id_pos(struct perf_evsel *evsel)
|
||||||
|
{
|
||||||
|
evsel->id_pos = __perf_evsel__calc_id_pos(evsel->attr.sample_type);
|
||||||
|
evsel->is_pos = __perf_evsel__calc_is_pos(evsel->attr.sample_type);
|
||||||
|
}
|
||||||
|
|
||||||
void hists__init(struct hists *hists)
|
void hists__init(struct hists *hists)
|
||||||
{
|
{
|
||||||
memset(hists, 0, sizeof(*hists));
|
memset(hists, 0, sizeof(*hists));
|
||||||
|
@ -63,6 +129,7 @@ void __perf_evsel__set_sample_bit(struct perf_evsel *evsel,
|
||||||
if (!(evsel->attr.sample_type & bit)) {
|
if (!(evsel->attr.sample_type & bit)) {
|
||||||
evsel->attr.sample_type |= bit;
|
evsel->attr.sample_type |= bit;
|
||||||
evsel->sample_size += sizeof(u64);
|
evsel->sample_size += sizeof(u64);
|
||||||
|
perf_evsel__calc_id_pos(evsel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,12 +139,19 @@ void __perf_evsel__reset_sample_bit(struct perf_evsel *evsel,
|
||||||
if (evsel->attr.sample_type & bit) {
|
if (evsel->attr.sample_type & bit) {
|
||||||
evsel->attr.sample_type &= ~bit;
|
evsel->attr.sample_type &= ~bit;
|
||||||
evsel->sample_size -= sizeof(u64);
|
evsel->sample_size -= sizeof(u64);
|
||||||
|
perf_evsel__calc_id_pos(evsel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void perf_evsel__set_sample_id(struct perf_evsel *evsel)
|
void perf_evsel__set_sample_id(struct perf_evsel *evsel,
|
||||||
|
bool can_sample_identifier)
|
||||||
{
|
{
|
||||||
perf_evsel__set_sample_bit(evsel, ID);
|
if (can_sample_identifier) {
|
||||||
|
perf_evsel__reset_sample_bit(evsel, ID);
|
||||||
|
perf_evsel__set_sample_bit(evsel, IDENTIFIER);
|
||||||
|
} else {
|
||||||
|
perf_evsel__set_sample_bit(evsel, ID);
|
||||||
|
}
|
||||||
evsel->attr.read_format |= PERF_FORMAT_ID;
|
evsel->attr.read_format |= PERF_FORMAT_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,6 +164,7 @@ void perf_evsel__init(struct perf_evsel *evsel,
|
||||||
INIT_LIST_HEAD(&evsel->node);
|
INIT_LIST_HEAD(&evsel->node);
|
||||||
hists__init(&evsel->hists);
|
hists__init(&evsel->hists);
|
||||||
evsel->sample_size = __perf_evsel__sample_size(attr->sample_type);
|
evsel->sample_size = __perf_evsel__sample_size(attr->sample_type);
|
||||||
|
perf_evsel__calc_id_pos(evsel);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx)
|
struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx)
|
||||||
|
@ -509,7 +584,7 @@ void perf_evsel__config(struct perf_evsel *evsel,
|
||||||
* We need ID even in case of single event, because
|
* We need ID even in case of single event, because
|
||||||
* PERF_SAMPLE_READ process ID specific data.
|
* PERF_SAMPLE_READ process ID specific data.
|
||||||
*/
|
*/
|
||||||
perf_evsel__set_sample_id(evsel);
|
perf_evsel__set_sample_id(evsel, false);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Apply group format only if we belong to group
|
* Apply group format only if we belong to group
|
||||||
|
@ -1088,6 +1163,11 @@ static int perf_evsel__parse_id_sample(const struct perf_evsel *evsel,
|
||||||
array += ((event->header.size -
|
array += ((event->header.size -
|
||||||
sizeof(event->header)) / sizeof(u64)) - 1;
|
sizeof(event->header)) / sizeof(u64)) - 1;
|
||||||
|
|
||||||
|
if (type & PERF_SAMPLE_IDENTIFIER) {
|
||||||
|
sample->id = *array;
|
||||||
|
array--;
|
||||||
|
}
|
||||||
|
|
||||||
if (type & PERF_SAMPLE_CPU) {
|
if (type & PERF_SAMPLE_CPU) {
|
||||||
u.val64 = *array;
|
u.val64 = *array;
|
||||||
if (swapped) {
|
if (swapped) {
|
||||||
|
@ -1184,6 +1264,12 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
|
||||||
if (evsel->sample_size + sizeof(event->header) > event->header.size)
|
if (evsel->sample_size + sizeof(event->header) > event->header.size)
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
|
data->id = -1ULL;
|
||||||
|
if (type & PERF_SAMPLE_IDENTIFIER) {
|
||||||
|
data->id = *array;
|
||||||
|
array++;
|
||||||
|
}
|
||||||
|
|
||||||
if (type & PERF_SAMPLE_IP) {
|
if (type & PERF_SAMPLE_IP) {
|
||||||
data->ip = *array;
|
data->ip = *array;
|
||||||
array++;
|
array++;
|
||||||
|
@ -1214,7 +1300,6 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
|
||||||
array++;
|
array++;
|
||||||
}
|
}
|
||||||
|
|
||||||
data->id = -1ULL;
|
|
||||||
if (type & PERF_SAMPLE_ID) {
|
if (type & PERF_SAMPLE_ID) {
|
||||||
data->id = *array;
|
data->id = *array;
|
||||||
array++;
|
array++;
|
||||||
|
@ -1396,6 +1481,11 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type,
|
||||||
|
|
||||||
array = event->sample.array;
|
array = event->sample.array;
|
||||||
|
|
||||||
|
if (type & PERF_SAMPLE_IDENTIFIER) {
|
||||||
|
*array = sample->id;
|
||||||
|
array++;
|
||||||
|
}
|
||||||
|
|
||||||
if (type & PERF_SAMPLE_IP) {
|
if (type & PERF_SAMPLE_IP) {
|
||||||
*array = sample->ip;
|
*array = sample->ip;
|
||||||
array++;
|
array++;
|
||||||
|
@ -1584,6 +1674,7 @@ static int sample_type__fprintf(FILE *fp, bool *first, u64 value)
|
||||||
bit_name(READ), bit_name(CALLCHAIN), bit_name(ID), bit_name(CPU),
|
bit_name(READ), bit_name(CALLCHAIN), bit_name(ID), bit_name(CPU),
|
||||||
bit_name(PERIOD), bit_name(STREAM_ID), bit_name(RAW),
|
bit_name(PERIOD), bit_name(STREAM_ID), bit_name(RAW),
|
||||||
bit_name(BRANCH_STACK), bit_name(REGS_USER), bit_name(STACK_USER),
|
bit_name(BRANCH_STACK), bit_name(REGS_USER), bit_name(STACK_USER),
|
||||||
|
bit_name(IDENTIFIER),
|
||||||
{ .name = NULL, }
|
{ .name = NULL, }
|
||||||
};
|
};
|
||||||
#undef bit_name
|
#undef bit_name
|
||||||
|
|
|
@ -48,6 +48,12 @@ struct perf_sample_id {
|
||||||
* @name - Can be set to retain the original event name passed by the user,
|
* @name - Can be set to retain the original event name passed by the user,
|
||||||
* so that when showing results in tools such as 'perf stat', we
|
* so that when showing results in tools such as 'perf stat', we
|
||||||
* show the name used, not some alias.
|
* show the name used, not some alias.
|
||||||
|
* @id_pos: the position of the event id (PERF_SAMPLE_ID or
|
||||||
|
* PERF_SAMPLE_IDENTIFIER) in a sample event i.e. in the array of
|
||||||
|
* struct sample_event
|
||||||
|
* @is_pos: the position (counting backwards) of the event id (PERF_SAMPLE_ID or
|
||||||
|
* PERF_SAMPLE_IDENTIFIER) in a non-sample event i.e. if sample_id_all
|
||||||
|
* is used there is an id sample appended to non-sample events
|
||||||
*/
|
*/
|
||||||
struct perf_evsel {
|
struct perf_evsel {
|
||||||
struct list_head node;
|
struct list_head node;
|
||||||
|
@ -74,6 +80,8 @@ struct perf_evsel {
|
||||||
} handler;
|
} handler;
|
||||||
struct cpu_map *cpus;
|
struct cpu_map *cpus;
|
||||||
unsigned int sample_size;
|
unsigned int sample_size;
|
||||||
|
int id_pos;
|
||||||
|
int is_pos;
|
||||||
bool supported;
|
bool supported;
|
||||||
bool needs_swap;
|
bool needs_swap;
|
||||||
/* parse modifier helper */
|
/* parse modifier helper */
|
||||||
|
@ -104,6 +112,9 @@ void perf_evsel__delete(struct perf_evsel *evsel);
|
||||||
void perf_evsel__config(struct perf_evsel *evsel,
|
void perf_evsel__config(struct perf_evsel *evsel,
|
||||||
struct perf_record_opts *opts);
|
struct perf_record_opts *opts);
|
||||||
|
|
||||||
|
int __perf_evsel__sample_size(u64 sample_type);
|
||||||
|
void perf_evsel__calc_id_pos(struct perf_evsel *evsel);
|
||||||
|
|
||||||
bool perf_evsel__is_cache_op_valid(u8 type, u8 op);
|
bool perf_evsel__is_cache_op_valid(u8 type, u8 op);
|
||||||
|
|
||||||
#define PERF_EVSEL__MAX_ALIASES 8
|
#define PERF_EVSEL__MAX_ALIASES 8
|
||||||
|
@ -142,7 +153,8 @@ void __perf_evsel__reset_sample_bit(struct perf_evsel *evsel,
|
||||||
#define perf_evsel__reset_sample_bit(evsel, bit) \
|
#define perf_evsel__reset_sample_bit(evsel, bit) \
|
||||||
__perf_evsel__reset_sample_bit(evsel, PERF_SAMPLE_##bit)
|
__perf_evsel__reset_sample_bit(evsel, PERF_SAMPLE_##bit)
|
||||||
|
|
||||||
void perf_evsel__set_sample_id(struct perf_evsel *evsel);
|
void perf_evsel__set_sample_id(struct perf_evsel *evsel,
|
||||||
|
bool use_sample_identifier);
|
||||||
|
|
||||||
int perf_evsel__set_filter(struct perf_evsel *evsel, int ncpus, int nthreads,
|
int perf_evsel__set_filter(struct perf_evsel *evsel, int ncpus, int nthreads,
|
||||||
const char *filter);
|
const char *filter);
|
||||||
|
|
|
@ -1,11 +1,83 @@
|
||||||
#include "evlist.h"
|
#include "evlist.h"
|
||||||
#include "evsel.h"
|
#include "evsel.h"
|
||||||
#include "cpumap.h"
|
#include "cpumap.h"
|
||||||
|
#include "parse-events.h"
|
||||||
|
|
||||||
|
typedef void (*setup_probe_fn_t)(struct perf_evsel *evsel);
|
||||||
|
|
||||||
|
static int perf_do_probe_api(setup_probe_fn_t fn, int cpu, const char *str)
|
||||||
|
{
|
||||||
|
struct perf_evlist *evlist;
|
||||||
|
struct perf_evsel *evsel;
|
||||||
|
int err = -EAGAIN, fd;
|
||||||
|
|
||||||
|
evlist = perf_evlist__new();
|
||||||
|
if (!evlist)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
if (parse_events(evlist, str))
|
||||||
|
goto out_delete;
|
||||||
|
|
||||||
|
evsel = perf_evlist__first(evlist);
|
||||||
|
|
||||||
|
fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, 0);
|
||||||
|
if (fd < 0)
|
||||||
|
goto out_delete;
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
fn(evsel);
|
||||||
|
|
||||||
|
fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, 0);
|
||||||
|
if (fd < 0) {
|
||||||
|
if (errno == EINVAL)
|
||||||
|
err = -EINVAL;
|
||||||
|
goto out_delete;
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
err = 0;
|
||||||
|
|
||||||
|
out_delete:
|
||||||
|
perf_evlist__delete(evlist);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool perf_probe_api(setup_probe_fn_t fn)
|
||||||
|
{
|
||||||
|
const char *try[] = {"cycles:u", "instructions:u", "cpu-clock", NULL};
|
||||||
|
struct cpu_map *cpus;
|
||||||
|
int cpu, ret, i = 0;
|
||||||
|
|
||||||
|
cpus = cpu_map__new(NULL);
|
||||||
|
if (!cpus)
|
||||||
|
return false;
|
||||||
|
cpu = cpus->map[0];
|
||||||
|
cpu_map__delete(cpus);
|
||||||
|
|
||||||
|
do {
|
||||||
|
ret = perf_do_probe_api(fn, cpu, try[i++]);
|
||||||
|
if (!ret)
|
||||||
|
return true;
|
||||||
|
} while (ret == -EAGAIN && try[i]);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void perf_probe_sample_identifier(struct perf_evsel *evsel)
|
||||||
|
{
|
||||||
|
evsel->attr.sample_type |= PERF_SAMPLE_IDENTIFIER;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool perf_can_sample_identifier(void)
|
||||||
|
{
|
||||||
|
return perf_probe_api(perf_probe_sample_identifier);
|
||||||
|
}
|
||||||
|
|
||||||
void perf_evlist__config(struct perf_evlist *evlist,
|
void perf_evlist__config(struct perf_evlist *evlist,
|
||||||
struct perf_record_opts *opts)
|
struct perf_record_opts *opts)
|
||||||
{
|
{
|
||||||
struct perf_evsel *evsel;
|
struct perf_evsel *evsel;
|
||||||
|
bool use_sample_identifier = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set the evsel leader links before we configure attributes,
|
* Set the evsel leader links before we configure attributes,
|
||||||
* since some might depend on this info.
|
* since some might depend on this info.
|
||||||
|
@ -16,10 +88,21 @@ void perf_evlist__config(struct perf_evlist *evlist,
|
||||||
if (evlist->cpus->map[0] < 0)
|
if (evlist->cpus->map[0] < 0)
|
||||||
opts->no_inherit = true;
|
opts->no_inherit = true;
|
||||||
|
|
||||||
list_for_each_entry(evsel, &evlist->entries, node) {
|
list_for_each_entry(evsel, &evlist->entries, node)
|
||||||
perf_evsel__config(evsel, opts);
|
perf_evsel__config(evsel, opts);
|
||||||
|
|
||||||
if (evlist->nr_entries > 1)
|
if (evlist->nr_entries > 1) {
|
||||||
perf_evsel__set_sample_id(evsel);
|
struct perf_evsel *first = perf_evlist__first(evlist);
|
||||||
|
|
||||||
|
list_for_each_entry(evsel, &evlist->entries, node) {
|
||||||
|
if (evsel->attr.sample_type == first->attr.sample_type)
|
||||||
|
continue;
|
||||||
|
use_sample_identifier = perf_can_sample_identifier();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
list_for_each_entry(evsel, &evlist->entries, node)
|
||||||
|
perf_evsel__set_sample_id(evsel, use_sample_identifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
perf_evlist__set_id_pos(evlist);
|
||||||
}
|
}
|
||||||
|
|
|
@ -739,7 +739,7 @@ static void perf_session__print_tstamp(struct perf_session *session,
|
||||||
union perf_event *event,
|
union perf_event *event,
|
||||||
struct perf_sample *sample)
|
struct perf_sample *sample)
|
||||||
{
|
{
|
||||||
u64 sample_type = perf_evlist__sample_type(session->evlist);
|
u64 sample_type = __perf_evlist__combined_sample_type(session->evlist);
|
||||||
|
|
||||||
if (event->header.type != PERF_RECORD_SAMPLE &&
|
if (event->header.type != PERF_RECORD_SAMPLE &&
|
||||||
!perf_evlist__sample_id_all(session->evlist)) {
|
!perf_evlist__sample_id_all(session->evlist)) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue