Commit e9def1b2 authored by David Carrillo-Cisneros's avatar David Carrillo-Cisneros Committed by Arnaldo Carvalho de Melo

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: default avatarDavid Carrillo-Cisneros <davidcc@google.com>
Acked-by: default avatarDavid Ahern <dsahern@gmail.com>
Acked-by: default avatarJiri 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.comSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 114f709e
...@@ -398,6 +398,11 @@ struct auxtrace_error_event { ...@@ -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 { ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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[] = { ...@@ -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 */ ...@@ -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 { ...@@ -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 { ...@@ -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 @@ ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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, ...@@ -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 { ...@@ -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;
......
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