perf tools: Add feature header record to pipe-mode
Add header record types to pipe-mode, reusing the functions used in file-mode and leveraging the new struct feat_fd. For alignment, check that synthesized events don't exceed pagesize. Add the perf_event__synthesize_feature event call back to process the new header records. Before this patch: $ perf record -o - -e cycles sleep 1 | perf report --stdio --header [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.000 MB - ] ... After this patch: $ perf record -o - -e cycles sleep 1 | perf report --stdio --header # ======== # captured on: Mon May 22 16:33:43 2017 # ======== # # hostname : my_hostname # os release : 4.11.0-dbx-up_perf # perf version : 4.11.rc6.g6277c80 # arch : x86_64 # nrcpus online : 72 # nrcpus avail : 72 # cpudesc : Intel(R) Xeon(R) CPU E5-2696 v3 @ 2.30GHz # cpuid : GenuineIntel,6,63,2 # total memory : 263457192 kB # cmdline : /root/perf record -o - -e cycles -c 100000 sleep 1 # HEADER_CPU_TOPOLOGY info available, use -I to display # HEADER_NUMA_TOPOLOGY info available, use -I to display # pmu mappings: intel_bts = 6, uncore_imc_4 = 22, uncore_sbox_1 = 47, uncore_cbox_5 = 33, uncore_ha_0 = 16, uncore_cbox [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.000 MB - ] ... Support added for the subcommands: report, inject, annotate and script. Signed-off-by: David Carrillo-Cisneros <davidcc@google.com> Acked-by: David Ahern <dsahern@gmail.com> Acked-by: Jiri Olsa <jolsa@kernel.org> Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com> Cc: Andi Kleen <ak@linux.intel.com> Cc: He Kuang <hekuang@huawei.com> Cc: Masami Hiramatsu <mhiramat@kernel.org> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Paul Turner <pjt@google.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Simon Que <sque@chromium.org> Cc: Stephane Eranian <eranian@google.com> Cc: Wang Nan <wangnan0@huawei.com> Link: http://lkml.kernel.org/r/20170718042549.145161-16-davidcc@google.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
114f709e01
commit
e9def1b2e7
|
@ -398,6 +398,11 @@ struct auxtrace_error_event {
|
||||||
char msg[MAX_AUXTRACE_ERROR_MSG];
|
char msg[MAX_AUXTRACE_ERROR_MSG];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
PERF_RECORD_HEADER_FEATURE = 80,
|
||||||
|
|
||||||
|
Describes a header feature. These are records used in pipe-mode that
|
||||||
|
contain information that otherwise would be in perf.data file's header.
|
||||||
|
|
||||||
Event types
|
Event types
|
||||||
|
|
||||||
Define the event attributes with their IDs.
|
Define the event attributes with their IDs.
|
||||||
|
@ -422,8 +427,9 @@ struct perf_pipe_file_header {
|
||||||
};
|
};
|
||||||
|
|
||||||
The information about attrs, data, and event_types is instead in the
|
The information about attrs, data, and event_types is instead in the
|
||||||
synthesized events PERF_RECORD_ATTR, PERF_RECORD_HEADER_TRACING_DATA and
|
synthesized events PERF_RECORD_ATTR, PERF_RECORD_HEADER_TRACING_DATA,
|
||||||
PERF_RECORD_HEADER_EVENT_TYPE that are generated by perf record in pipe-mode.
|
PERF_RECORD_HEADER_EVENT_TYPE, and PERF_RECORD_HEADER_FEATURE
|
||||||
|
that are generated by perf record in pipe-mode.
|
||||||
|
|
||||||
|
|
||||||
References:
|
References:
|
||||||
|
|
|
@ -397,6 +397,7 @@ int cmd_annotate(int argc, const char **argv)
|
||||||
.namespaces = perf_event__process_namespaces,
|
.namespaces = perf_event__process_namespaces,
|
||||||
.attr = perf_event__process_attr,
|
.attr = perf_event__process_attr,
|
||||||
.build_id = perf_event__process_build_id,
|
.build_id = perf_event__process_build_id,
|
||||||
|
.feature = perf_event__process_feature,
|
||||||
.ordered_events = true,
|
.ordered_events = true,
|
||||||
.ordering_requires_timestamps = true,
|
.ordering_requires_timestamps = true,
|
||||||
},
|
},
|
||||||
|
|
|
@ -770,6 +770,7 @@ int cmd_inject(int argc, const char **argv)
|
||||||
.finished_round = perf_event__repipe_oe_synth,
|
.finished_round = perf_event__repipe_oe_synth,
|
||||||
.build_id = perf_event__repipe_op2_synth,
|
.build_id = perf_event__repipe_op2_synth,
|
||||||
.id_index = perf_event__repipe_op2_synth,
|
.id_index = perf_event__repipe_op2_synth,
|
||||||
|
.feature = perf_event__repipe_op2_synth,
|
||||||
},
|
},
|
||||||
.input_name = "-",
|
.input_name = "-",
|
||||||
.samples = LIST_HEAD_INIT(inject.samples),
|
.samples = LIST_HEAD_INIT(inject.samples),
|
||||||
|
|
|
@ -799,6 +799,13 @@ static int record__synthesize(struct record *rec, bool tail)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (file->is_pipe) {
|
if (file->is_pipe) {
|
||||||
|
err = perf_event__synthesize_features(
|
||||||
|
tool, session, rec->evlist, process_synthesized_event);
|
||||||
|
if (err < 0) {
|
||||||
|
pr_err("Couldn't synthesize features.\n");
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
err = perf_event__synthesize_attrs(tool, session,
|
err = perf_event__synthesize_attrs(tool, session,
|
||||||
process_synthesized_event);
|
process_synthesized_event);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
|
|
|
@ -718,6 +718,7 @@ int cmd_report(int argc, const char **argv)
|
||||||
.id_index = perf_event__process_id_index,
|
.id_index = perf_event__process_id_index,
|
||||||
.auxtrace_info = perf_event__process_auxtrace_info,
|
.auxtrace_info = perf_event__process_auxtrace_info,
|
||||||
.auxtrace = perf_event__process_auxtrace,
|
.auxtrace = perf_event__process_auxtrace,
|
||||||
|
.feature = perf_event__process_feature,
|
||||||
.ordered_events = true,
|
.ordered_events = true,
|
||||||
.ordering_requires_timestamps = true,
|
.ordering_requires_timestamps = true,
|
||||||
},
|
},
|
||||||
|
|
|
@ -2682,6 +2682,7 @@ int cmd_script(int argc, const char **argv)
|
||||||
.attr = process_attr,
|
.attr = process_attr,
|
||||||
.event_update = perf_event__process_event_update,
|
.event_update = perf_event__process_event_update,
|
||||||
.tracing_data = perf_event__process_tracing_data,
|
.tracing_data = perf_event__process_tracing_data,
|
||||||
|
.feature = perf_event__process_feature,
|
||||||
.build_id = perf_event__process_build_id,
|
.build_id = perf_event__process_build_id,
|
||||||
.id_index = perf_event__process_id_index,
|
.id_index = perf_event__process_id_index,
|
||||||
.auxtrace_info = perf_event__process_auxtrace_info,
|
.auxtrace_info = perf_event__process_auxtrace_info,
|
||||||
|
|
|
@ -57,6 +57,7 @@ static const char *perf_event__names[] = {
|
||||||
[PERF_RECORD_STAT_ROUND] = "STAT_ROUND",
|
[PERF_RECORD_STAT_ROUND] = "STAT_ROUND",
|
||||||
[PERF_RECORD_EVENT_UPDATE] = "EVENT_UPDATE",
|
[PERF_RECORD_EVENT_UPDATE] = "EVENT_UPDATE",
|
||||||
[PERF_RECORD_TIME_CONV] = "TIME_CONV",
|
[PERF_RECORD_TIME_CONV] = "TIME_CONV",
|
||||||
|
[PERF_RECORD_HEADER_FEATURE] = "FEATURE",
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char *perf_ns__names[] = {
|
static const char *perf_ns__names[] = {
|
||||||
|
|
|
@ -244,6 +244,7 @@ enum perf_user_event_type { /* above any possible kernel type */
|
||||||
PERF_RECORD_STAT_ROUND = 77,
|
PERF_RECORD_STAT_ROUND = 77,
|
||||||
PERF_RECORD_EVENT_UPDATE = 78,
|
PERF_RECORD_EVENT_UPDATE = 78,
|
||||||
PERF_RECORD_TIME_CONV = 79,
|
PERF_RECORD_TIME_CONV = 79,
|
||||||
|
PERF_RECORD_HEADER_FEATURE = 80,
|
||||||
PERF_RECORD_HEADER_MAX
|
PERF_RECORD_HEADER_MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -609,6 +610,12 @@ struct time_conv_event {
|
||||||
u64 time_zero;
|
u64 time_zero;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct feature_event {
|
||||||
|
struct perf_event_header header;
|
||||||
|
u64 feat_id;
|
||||||
|
char data[];
|
||||||
|
};
|
||||||
|
|
||||||
union perf_event {
|
union perf_event {
|
||||||
struct perf_event_header header;
|
struct perf_event_header header;
|
||||||
struct mmap_event mmap;
|
struct mmap_event mmap;
|
||||||
|
@ -639,6 +646,7 @@ union perf_event {
|
||||||
struct stat_event stat;
|
struct stat_event stat;
|
||||||
struct stat_round_event stat_round;
|
struct stat_round_event stat_round;
|
||||||
struct time_conv_event time_conv;
|
struct time_conv_event time_conv;
|
||||||
|
struct feature_event feat;
|
||||||
};
|
};
|
||||||
|
|
||||||
void perf_event__print_totals(void);
|
void perf_event__print_totals(void);
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#include "data.h"
|
#include "data.h"
|
||||||
#include <api/fs/fs.h>
|
#include <api/fs/fs.h>
|
||||||
#include "asm/bug.h"
|
#include "asm/bug.h"
|
||||||
|
#include "tool.h"
|
||||||
|
|
||||||
#include "sane_ctype.h"
|
#include "sane_ctype.h"
|
||||||
|
|
||||||
|
@ -2982,6 +2983,103 @@ int perf_event__synthesize_attr(struct perf_tool *tool,
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int perf_event__synthesize_features(struct perf_tool *tool,
|
||||||
|
struct perf_session *session,
|
||||||
|
struct perf_evlist *evlist,
|
||||||
|
perf_event__handler_t process)
|
||||||
|
{
|
||||||
|
struct perf_header *header = &session->header;
|
||||||
|
struct feat_fd ff;
|
||||||
|
struct feature_event *fe;
|
||||||
|
size_t sz, sz_hdr;
|
||||||
|
int feat, ret;
|
||||||
|
|
||||||
|
sz_hdr = sizeof(fe->header);
|
||||||
|
sz = sizeof(union perf_event);
|
||||||
|
/* get a nice alignment */
|
||||||
|
sz = PERF_ALIGN(sz, page_size);
|
||||||
|
|
||||||
|
memset(&ff, 0, sizeof(ff));
|
||||||
|
|
||||||
|
ff.buf = malloc(sz);
|
||||||
|
if (!ff.buf)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
ff.size = sz - sz_hdr;
|
||||||
|
|
||||||
|
for_each_set_bit(feat, header->adds_features, HEADER_FEAT_BITS) {
|
||||||
|
if (!feat_ops[feat].synthesize) {
|
||||||
|
pr_debug("No record header feature for header :%d\n", feat);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ff.offset = sizeof(*fe);
|
||||||
|
|
||||||
|
ret = feat_ops[feat].write(&ff, evlist);
|
||||||
|
if (ret || ff.offset <= (ssize_t)sizeof(*fe)) {
|
||||||
|
pr_debug("Error writing feature\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* ff.buf may have changed due to realloc in do_write() */
|
||||||
|
fe = ff.buf;
|
||||||
|
memset(fe, 0, sizeof(*fe));
|
||||||
|
|
||||||
|
fe->feat_id = feat;
|
||||||
|
fe->header.type = PERF_RECORD_HEADER_FEATURE;
|
||||||
|
fe->header.size = ff.offset;
|
||||||
|
|
||||||
|
ret = process(tool, ff.buf, NULL, NULL);
|
||||||
|
if (ret) {
|
||||||
|
free(ff.buf);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(ff.buf);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int perf_event__process_feature(struct perf_tool *tool,
|
||||||
|
union perf_event *event,
|
||||||
|
struct perf_session *session __maybe_unused)
|
||||||
|
{
|
||||||
|
struct feat_fd ff = { .fd = 0 };
|
||||||
|
struct feature_event *fe = (struct feature_event *)event;
|
||||||
|
int type = fe->header.type;
|
||||||
|
u64 feat = fe->feat_id;
|
||||||
|
|
||||||
|
if (type < 0 || type >= PERF_RECORD_HEADER_MAX) {
|
||||||
|
pr_warning("invalid record type %d in pipe-mode\n", type);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (feat == HEADER_RESERVED || feat > HEADER_LAST_FEATURE) {
|
||||||
|
pr_warning("invalid record type %d in pipe-mode\n", type);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!feat_ops[feat].process)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ff.buf = (void *)fe->data;
|
||||||
|
ff.size = event->header.size - sizeof(event->header);
|
||||||
|
ff.ph = &session->header;
|
||||||
|
|
||||||
|
if (feat_ops[feat].process(&ff, NULL))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (!feat_ops[feat].print || !tool->show_feat_hdr)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!feat_ops[feat].full_only ||
|
||||||
|
tool->show_feat_hdr >= SHOW_FEAT_HEADER_FULL_INFO) {
|
||||||
|
feat_ops[feat].print(&ff, stdout);
|
||||||
|
} else {
|
||||||
|
fprintf(stdout, "# %s info available, use -I to display\n",
|
||||||
|
feat_ops[feat].name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static struct event_update_event *
|
static struct event_update_event *
|
||||||
event_update_event__new(size_t size, u64 type, u64 id)
|
event_update_event__new(size_t size, u64 type, u64 id)
|
||||||
{
|
{
|
||||||
|
|
|
@ -101,6 +101,15 @@ int perf_header__process_sections(struct perf_header *header, int fd,
|
||||||
|
|
||||||
int perf_header__fprintf_info(struct perf_session *s, FILE *fp, bool full);
|
int perf_header__fprintf_info(struct perf_session *s, FILE *fp, bool full);
|
||||||
|
|
||||||
|
int perf_event__synthesize_features(struct perf_tool *tool,
|
||||||
|
struct perf_session *session,
|
||||||
|
struct perf_evlist *evlist,
|
||||||
|
perf_event__handler_t process);
|
||||||
|
|
||||||
|
int perf_event__process_feature(struct perf_tool *tool,
|
||||||
|
union perf_event *event,
|
||||||
|
struct perf_session *session);
|
||||||
|
|
||||||
int perf_event__synthesize_attr(struct perf_tool *tool,
|
int perf_event__synthesize_attr(struct perf_tool *tool,
|
||||||
struct perf_event_attr *attr, u32 ids, u64 *id,
|
struct perf_event_attr *attr, u32 ids, u64 *id,
|
||||||
perf_event__handler_t process);
|
perf_event__handler_t process);
|
||||||
|
|
|
@ -428,6 +428,8 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
|
||||||
tool->stat_round = process_stat_round_stub;
|
tool->stat_round = process_stat_round_stub;
|
||||||
if (tool->time_conv == NULL)
|
if (tool->time_conv == NULL)
|
||||||
tool->time_conv = process_event_op2_stub;
|
tool->time_conv = process_event_op2_stub;
|
||||||
|
if (tool->feature == NULL)
|
||||||
|
tool->feature = process_event_op2_stub;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void swap_sample_id_all(union perf_event *event, void *data)
|
static void swap_sample_id_all(union perf_event *event, void *data)
|
||||||
|
@ -1371,6 +1373,8 @@ static s64 perf_session__process_user_event(struct perf_session *session,
|
||||||
case PERF_RECORD_TIME_CONV:
|
case PERF_RECORD_TIME_CONV:
|
||||||
session->time_conv = event->time_conv;
|
session->time_conv = event->time_conv;
|
||||||
return tool->time_conv(tool, event, session);
|
return tool->time_conv(tool, event, session);
|
||||||
|
case PERF_RECORD_HEADER_FEATURE:
|
||||||
|
return tool->feature(tool, event, session);
|
||||||
default:
|
default:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,7 +69,8 @@ struct perf_tool {
|
||||||
cpu_map,
|
cpu_map,
|
||||||
stat_config,
|
stat_config,
|
||||||
stat,
|
stat,
|
||||||
stat_round;
|
stat_round,
|
||||||
|
feature;
|
||||||
event_op3 auxtrace;
|
event_op3 auxtrace;
|
||||||
bool ordered_events;
|
bool ordered_events;
|
||||||
bool ordering_requires_timestamps;
|
bool ordering_requires_timestamps;
|
||||||
|
|
Loading…
Reference in New Issue