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>
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.
};
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:
.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,
},
.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),
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) {
.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,
},
.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,
[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[] = {
PERF_RECORD_STAT_ROUND = 77,
PERF_RECORD_EVENT_UPDATE = 78,
PERF_RECORD_TIME_CONV = 79,
+ PERF_RECORD_HEADER_FEATURE = 80,
PERF_RECORD_HEADER_MAX
};
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;
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);
#include "data.h"
#include <api/fs/fs.h>
#include "asm/bug.h"
+#include "tool.h"
#include "sane_ctype.h"
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)
{
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);
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)
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;
}
cpu_map,
stat_config,
stat,
- stat_round;
+ stat_round,
+ feature;
event_op3 auxtrace;
bool ordered_events;
bool ordering_requires_timestamps;