Commit 9ede473c authored by Jiri Olsa's avatar Jiri Olsa Committed by Arnaldo Carvalho de Melo

perf tools: Add support for parsing PERF_SAMPLE_READ sample type

Adding support to parse out the PERF_SAMPLE_READ sample bits.  The code
contains both single and group format specification.

This code parse out and prepare PERF_SAMPLE_READ data into the
perf_sample struct. It will be used for group leader sampling feature
comming in shortly.
Signed-off-by: default avatarJiri Olsa <jolsa@redhat.com>
Acked-by: default avatarNamhyung Kim <namhyung@kernel.org>
Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/n/tip-0tgdoln5rwk3wocshb442cl3@git.kernel.orgSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent e2b5abe0
...@@ -80,6 +80,23 @@ struct stack_dump { ...@@ -80,6 +80,23 @@ struct stack_dump {
char *data; char *data;
}; };
struct sample_read_value {
u64 value;
u64 id;
};
struct sample_read {
u64 time_enabled;
u64 time_running;
union {
struct {
u64 nr;
struct sample_read_value *values;
} group;
struct sample_read_value one;
};
};
struct perf_sample { struct perf_sample {
u64 ip; u64 ip;
u32 pid, tid; u32 pid, tid;
...@@ -97,6 +114,7 @@ struct perf_sample { ...@@ -97,6 +114,7 @@ struct perf_sample {
struct branch_stack *branch_stack; struct branch_stack *branch_stack;
struct regs_dump user_regs; struct regs_dump user_regs;
struct stack_dump user_stack; struct stack_dump user_stack;
struct sample_read read;
}; };
#define PERF_MEM_DATA_SRC_NONE \ #define PERF_MEM_DATA_SRC_NONE \
......
...@@ -676,6 +676,32 @@ u64 perf_evlist__sample_type(struct perf_evlist *evlist) ...@@ -676,6 +676,32 @@ u64 perf_evlist__sample_type(struct perf_evlist *evlist)
return first->attr.sample_type; return first->attr.sample_type;
} }
bool perf_evlist__valid_read_format(struct perf_evlist *evlist)
{
struct perf_evsel *first = perf_evlist__first(evlist), *pos = first;
u64 read_format = first->attr.read_format;
u64 sample_type = first->attr.sample_type;
list_for_each_entry_continue(pos, &evlist->entries, node) {
if (read_format != pos->attr.read_format)
return false;
}
/* PERF_SAMPLE_READ imples PERF_FORMAT_ID. */
if ((sample_type & PERF_SAMPLE_READ) &&
!(read_format & PERF_FORMAT_ID)) {
return false;
}
return true;
}
u64 perf_evlist__read_format(struct perf_evlist *evlist)
{
struct perf_evsel *first = perf_evlist__first(evlist);
return first->attr.read_format;
}
u16 perf_evlist__id_hdr_size(struct perf_evlist *evlist) u16 perf_evlist__id_hdr_size(struct perf_evlist *evlist)
{ {
struct perf_evsel *first = perf_evlist__first(evlist); struct perf_evsel *first = perf_evlist__first(evlist);
......
...@@ -118,6 +118,7 @@ int perf_evlist__apply_filters(struct perf_evlist *evlist); ...@@ -118,6 +118,7 @@ int perf_evlist__apply_filters(struct perf_evlist *evlist);
void __perf_evlist__set_leader(struct list_head *list); 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__sample_type(struct perf_evlist *evlist); u64 perf_evlist__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);
...@@ -127,6 +128,7 @@ int perf_evlist__parse_sample(struct perf_evlist *evlist, union perf_event *even ...@@ -127,6 +128,7 @@ int perf_evlist__parse_sample(struct perf_evlist *evlist, union perf_event *even
bool perf_evlist__valid_sample_type(struct perf_evlist *evlist); bool perf_evlist__valid_sample_type(struct perf_evlist *evlist);
bool perf_evlist__valid_sample_id_all(struct perf_evlist *evlist); bool perf_evlist__valid_sample_id_all(struct perf_evlist *evlist);
bool perf_evlist__valid_read_format(struct perf_evlist *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,
......
...@@ -1096,8 +1096,34 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, ...@@ -1096,8 +1096,34 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
} }
if (type & PERF_SAMPLE_READ) { if (type & PERF_SAMPLE_READ) {
fprintf(stderr, "PERF_SAMPLE_READ is unsupported for now\n"); u64 read_format = evsel->attr.read_format;
return -1;
if (read_format & PERF_FORMAT_GROUP)
data->read.group.nr = *array;
else
data->read.one.value = *array;
array++;
if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) {
data->read.time_enabled = *array;
array++;
}
if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) {
data->read.time_running = *array;
array++;
}
/* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */
if (read_format & PERF_FORMAT_GROUP) {
data->read.group.values = (struct sample_read_value *) array;
array = (void *) array + data->read.group.nr *
sizeof(struct sample_read_value);
} else {
data->read.one.id = *array;
array++;
}
} }
if (type & PERF_SAMPLE_CALLCHAIN) { if (type & PERF_SAMPLE_CALLCHAIN) {
......
...@@ -71,6 +71,11 @@ static int perf_session__open(struct perf_session *self, bool force) ...@@ -71,6 +71,11 @@ static int perf_session__open(struct perf_session *self, bool force)
goto out_close; goto out_close;
} }
if (!perf_evlist__valid_read_format(self->evlist)) {
pr_err("non matching read_format");
goto out_close;
}
self->size = input_stat.st_size; self->size = input_stat.st_size;
return 0; return 0;
...@@ -749,6 +754,36 @@ static void perf_session__print_tstamp(struct perf_session *session, ...@@ -749,6 +754,36 @@ static void perf_session__print_tstamp(struct perf_session *session,
printf("%" PRIu64 " ", sample->time); printf("%" PRIu64 " ", sample->time);
} }
static void sample_read__printf(struct perf_sample *sample, u64 read_format)
{
printf("... sample_read:\n");
if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
printf("...... time enabled %016" PRIx64 "\n",
sample->read.time_enabled);
if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
printf("...... time running %016" PRIx64 "\n",
sample->read.time_running);
if (read_format & PERF_FORMAT_GROUP) {
u64 i;
printf(".... group nr %" PRIu64 "\n", sample->read.group.nr);
for (i = 0; i < sample->read.group.nr; i++) {
struct sample_read_value *value;
value = &sample->read.group.values[i];
printf("..... id %016" PRIx64
", value %016" PRIx64 "\n",
value->id, value->value);
}
} else
printf("..... id %016" PRIx64 ", value %016" PRIx64 "\n",
sample->read.one.id, sample->read.one.value);
}
static void dump_event(struct perf_session *session, union perf_event *event, static void dump_event(struct perf_session *session, union perf_event *event,
u64 file_offset, struct perf_sample *sample) u64 file_offset, struct perf_sample *sample)
{ {
...@@ -798,6 +833,9 @@ static void dump_sample(struct perf_evsel *evsel, union perf_event *event, ...@@ -798,6 +833,9 @@ static void dump_sample(struct perf_evsel *evsel, union perf_event *event,
if (sample_type & PERF_SAMPLE_DATA_SRC) if (sample_type & PERF_SAMPLE_DATA_SRC)
printf(" . data_src: 0x%"PRIx64"\n", sample->data_src); printf(" . data_src: 0x%"PRIx64"\n", sample->data_src);
if (sample_type & PERF_SAMPLE_READ)
sample_read__printf(sample, evsel->attr.read_format);
} }
static struct machine * static struct machine *
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment