Skip to content

Commit

Permalink
perf tools: Add feature header record to pipe-mode
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
David Carrillo-Cisneros authored and Arnaldo Carvalho de Melo committed Jul 19, 2017
1 parent 114f709 commit e9def1b
Show file tree
Hide file tree
Showing 12 changed files with 141 additions and 3 deletions.
10 changes: 8 additions & 2 deletions tools/perf/Documentation/perf.data-file-format.txt
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,11 @@ struct auxtrace_error_event {
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

Define the event attributes with their IDs.
Expand All @@ -422,8 +427,9 @@ struct perf_pipe_file_header {
};

The information about attrs, data, and event_types is instead in the
synthesized events PERF_RECORD_ATTR, PERF_RECORD_HEADER_TRACING_DATA and
PERF_RECORD_HEADER_EVENT_TYPE that are generated by perf record in pipe-mode.
synthesized events PERF_RECORD_ATTR, PERF_RECORD_HEADER_TRACING_DATA,
PERF_RECORD_HEADER_EVENT_TYPE, and PERF_RECORD_HEADER_FEATURE
that are generated by perf record in pipe-mode.


References:
Expand Down
1 change: 1 addition & 0 deletions tools/perf/builtin-annotate.c
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,7 @@ int cmd_annotate(int argc, const char **argv)
.namespaces = perf_event__process_namespaces,
.attr = perf_event__process_attr,
.build_id = perf_event__process_build_id,
.feature = perf_event__process_feature,
.ordered_events = true,
.ordering_requires_timestamps = true,
},
Expand Down
1 change: 1 addition & 0 deletions tools/perf/builtin-inject.c
Original file line number Diff line number Diff line change
Expand Up @@ -770,6 +770,7 @@ int cmd_inject(int argc, const char **argv)
.finished_round = perf_event__repipe_oe_synth,
.build_id = perf_event__repipe_op2_synth,
.id_index = perf_event__repipe_op2_synth,
.feature = perf_event__repipe_op2_synth,
},
.input_name = "-",
.samples = LIST_HEAD_INIT(inject.samples),
Expand Down
7 changes: 7 additions & 0 deletions tools/perf/builtin-record.c
Original file line number Diff line number Diff line change
Expand Up @@ -799,6 +799,13 @@ static int record__synthesize(struct record *rec, bool tail)
return 0;

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,
process_synthesized_event);
if (err < 0) {
Expand Down
1 change: 1 addition & 0 deletions tools/perf/builtin-report.c
Original file line number Diff line number Diff line change
Expand Up @@ -718,6 +718,7 @@ int cmd_report(int argc, const char **argv)
.id_index = perf_event__process_id_index,
.auxtrace_info = perf_event__process_auxtrace_info,
.auxtrace = perf_event__process_auxtrace,
.feature = perf_event__process_feature,
.ordered_events = true,
.ordering_requires_timestamps = true,
},
Expand Down
1 change: 1 addition & 0 deletions tools/perf/builtin-script.c
Original file line number Diff line number Diff line change
Expand Up @@ -2682,6 +2682,7 @@ int cmd_script(int argc, const char **argv)
.attr = process_attr,
.event_update = perf_event__process_event_update,
.tracing_data = perf_event__process_tracing_data,
.feature = perf_event__process_feature,
.build_id = perf_event__process_build_id,
.id_index = perf_event__process_id_index,
.auxtrace_info = perf_event__process_auxtrace_info,
Expand Down
1 change: 1 addition & 0 deletions tools/perf/util/event.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ static const char *perf_event__names[] = {
[PERF_RECORD_STAT_ROUND] = "STAT_ROUND",
[PERF_RECORD_EVENT_UPDATE] = "EVENT_UPDATE",
[PERF_RECORD_TIME_CONV] = "TIME_CONV",
[PERF_RECORD_HEADER_FEATURE] = "FEATURE",
};

static const char *perf_ns__names[] = {
Expand Down
8 changes: 8 additions & 0 deletions tools/perf/util/event.h
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ enum perf_user_event_type { /* above any possible kernel type */
PERF_RECORD_STAT_ROUND = 77,
PERF_RECORD_EVENT_UPDATE = 78,
PERF_RECORD_TIME_CONV = 79,
PERF_RECORD_HEADER_FEATURE = 80,
PERF_RECORD_HEADER_MAX
};

Expand Down Expand Up @@ -609,6 +610,12 @@ struct time_conv_event {
u64 time_zero;
};

struct feature_event {
struct perf_event_header header;
u64 feat_id;
char data[];
};

union perf_event {
struct perf_event_header header;
struct mmap_event mmap;
Expand Down Expand Up @@ -639,6 +646,7 @@ union perf_event {
struct stat_event stat;
struct stat_round_event stat_round;
struct time_conv_event time_conv;
struct feature_event feat;
};

void perf_event__print_totals(void);
Expand Down
98 changes: 98 additions & 0 deletions tools/perf/util/header.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include "data.h"
#include <api/fs/fs.h>
#include "asm/bug.h"
#include "tool.h"

#include "sane_ctype.h"

Expand Down Expand Up @@ -2982,6 +2983,103 @@ int perf_event__synthesize_attr(struct perf_tool *tool,
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 *
event_update_event__new(size_t size, u64 type, u64 id)
{
Expand Down
9 changes: 9 additions & 0 deletions tools/perf/util/header.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_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,
struct perf_event_attr *attr, u32 ids, u64 *id,
perf_event__handler_t process);
Expand Down
4 changes: 4 additions & 0 deletions tools/perf/util/session.c
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,8 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
tool->stat_round = process_stat_round_stub;
if (tool->time_conv == NULL)
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)
Expand Down Expand Up @@ -1371,6 +1373,8 @@ static s64 perf_session__process_user_event(struct perf_session *session,
case PERF_RECORD_TIME_CONV:
session->time_conv = event->time_conv;
return tool->time_conv(tool, event, session);
case PERF_RECORD_HEADER_FEATURE:
return tool->feature(tool, event, session);
default:
return -EINVAL;
}
Expand Down
3 changes: 2 additions & 1 deletion tools/perf/util/tool.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ struct perf_tool {
cpu_map,
stat_config,
stat,
stat_round;
stat_round,
feature;
event_op3 auxtrace;
bool ordered_events;
bool ordering_requires_timestamps;
Expand Down

0 comments on commit e9def1b

Please sign in to comment.