perf record: Add finished init event
In preparation for recording sideband events in a virtual machine guest so
that they can be injected into a host perf.data file.
This is needed to enable injecting events after the initial synthesized
user events (that have an all zero id sample) but before regular events.
Committer notes:
Add entry about PERF_RECORD_FINISHED_INIT to
tools/perf/Documentation/perf.data-file-format.txt.
Committer testing:
Before:
# perf report -D | grep FINISHED
0 0x5910 [0x8]: PERF_RECORD_FINISHED_ROUND
FINISHED_ROUND events: 1 ( 0.5%)
#
After:
# perf record -- sleep 1
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.020 MB perf.data (7 samples) ]
# perf report -D | grep FINISHED
0 0x5068 [0x8]: PERF_RECORD_FINISHED_INIT: unhandled!
0 0x5390 [0x8]: PERF_RECORD_FINISHED_ROUND
FINISHED_ROUND events: 1 ( 0.5%)
FINISHED_INIT events: 1 ( 0.5%)
#
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Acked-by: Ian Rogers <irogers@google.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Link: https://lore.kernel.org/r/20220610113316.6682-5-adrian.hunter@intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
committed by
Arnaldo Carvalho de Melo
parent
61110883a0
commit
3812d29877
@@ -389,6 +389,7 @@ enum perf_user_event_type { /* above any possible kernel type */
|
||||
PERF_RECORD_TIME_CONV = 79,
|
||||
PERF_RECORD_HEADER_FEATURE = 80,
|
||||
PERF_RECORD_COMPRESSED = 81,
|
||||
PERF_RECORD_FINISHED_INIT = 82,
|
||||
PERF_RECORD_HEADER_MAX
|
||||
};
|
||||
|
||||
|
||||
@@ -607,6 +607,16 @@ struct compressed_event {
|
||||
char data[];
|
||||
};
|
||||
|
||||
PERF_RECORD_FINISHED_INIT = 82,
|
||||
|
||||
Marks the end of records for the system, pre-existing threads in system wide
|
||||
sessions, etc. Those are the ones prefixed PERF_RECORD_USER_*.
|
||||
|
||||
This is used, for instance, to 'perf inject' events after init and before
|
||||
regular events, those emitted by the kernel, to support combining guest and
|
||||
host records.
|
||||
|
||||
|
||||
The header is followed by compressed data frame that can be decompressed
|
||||
into array of perf trace records. The size of the entire compressed event
|
||||
record including the header is limited by the max value of header.size.
|
||||
|
||||
@@ -1059,6 +1059,7 @@ int cmd_inject(int argc, const char **argv)
|
||||
.stat = perf_event__repipe_op2_synth,
|
||||
.stat_round = perf_event__repipe_op2_synth,
|
||||
.feature = perf_event__repipe_op2_synth,
|
||||
.finished_init = perf_event__repipe_op2_synth,
|
||||
.compressed = perf_event__repipe_op4_synth,
|
||||
.auxtrace = perf_event__repipe_auxtrace,
|
||||
},
|
||||
|
||||
@@ -1388,6 +1388,11 @@ static struct perf_event_header finished_round_event = {
|
||||
.type = PERF_RECORD_FINISHED_ROUND,
|
||||
};
|
||||
|
||||
static struct perf_event_header finished_init_event = {
|
||||
.size = sizeof(struct perf_event_header),
|
||||
.type = PERF_RECORD_FINISHED_INIT,
|
||||
};
|
||||
|
||||
static void record__adjust_affinity(struct record *rec, struct mmap *map)
|
||||
{
|
||||
if (rec->opts.affinity != PERF_AFFINITY_SYS &&
|
||||
@@ -1696,6 +1701,14 @@ static int record__synthesize_workload(struct record *rec, bool tail)
|
||||
return err;
|
||||
}
|
||||
|
||||
static int write_finished_init(struct record *rec, bool tail)
|
||||
{
|
||||
if (rec->opts.tail_synthesize != tail)
|
||||
return 0;
|
||||
|
||||
return record__write(rec, NULL, &finished_init_event, sizeof(finished_init_event));
|
||||
}
|
||||
|
||||
static int record__synthesize(struct record *rec, bool tail);
|
||||
|
||||
static int
|
||||
@@ -1710,6 +1723,8 @@ record__switch_output(struct record *rec, bool at_exit)
|
||||
|
||||
record__aio_mmap_read_sync(rec);
|
||||
|
||||
write_finished_init(rec, true);
|
||||
|
||||
record__synthesize(rec, true);
|
||||
if (target__none(&rec->opts.target))
|
||||
record__synthesize_workload(rec, true);
|
||||
@@ -1764,6 +1779,7 @@ record__switch_output(struct record *rec, bool at_exit)
|
||||
*/
|
||||
if (target__none(&rec->opts.target))
|
||||
record__synthesize_workload(rec, false);
|
||||
write_finished_init(rec, false);
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
@@ -2419,6 +2435,15 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
|
||||
trigger_ready(&auxtrace_snapshot_trigger);
|
||||
trigger_ready(&switch_output_trigger);
|
||||
perf_hooks__invoke_record_start();
|
||||
|
||||
/*
|
||||
* Must write FINISHED_INIT so it will be seen after all other
|
||||
* synthesized user events, but before any regular events.
|
||||
*/
|
||||
err = write_finished_init(rec, false);
|
||||
if (err < 0)
|
||||
goto out_child;
|
||||
|
||||
for (;;) {
|
||||
unsigned long long hits = thread->samples;
|
||||
|
||||
@@ -2563,6 +2588,8 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
|
||||
fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n",
|
||||
record__waking(rec));
|
||||
|
||||
write_finished_init(rec, true);
|
||||
|
||||
if (target__none(&rec->opts.target))
|
||||
record__synthesize_workload(rec, true);
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ static const char *perf_event__names[] = {
|
||||
[PERF_RECORD_TIME_CONV] = "TIME_CONV",
|
||||
[PERF_RECORD_HEADER_FEATURE] = "FEATURE",
|
||||
[PERF_RECORD_COMPRESSED] = "COMPRESSED",
|
||||
[PERF_RECORD_FINISHED_INIT] = "FINISHED_INIT",
|
||||
};
|
||||
|
||||
const char *perf_event__name(unsigned int id)
|
||||
|
||||
@@ -562,6 +562,8 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
|
||||
tool->feature = process_event_op2_stub;
|
||||
if (tool->compressed == NULL)
|
||||
tool->compressed = perf_session__process_compressed_event;
|
||||
if (tool->finished_init == NULL)
|
||||
tool->finished_init = process_event_op2_stub;
|
||||
}
|
||||
|
||||
static void swap_sample_id_all(union perf_event *event, void *data)
|
||||
@@ -1706,6 +1708,8 @@ static s64 perf_session__process_user_event(struct perf_session *session,
|
||||
if (err)
|
||||
dump_event(session->evlist, event, file_offset, &sample, file_path);
|
||||
return err;
|
||||
case PERF_RECORD_FINISHED_INIT:
|
||||
return tool->finished_init(session, event);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -76,7 +76,8 @@ struct perf_tool {
|
||||
stat_config,
|
||||
stat,
|
||||
stat_round,
|
||||
feature;
|
||||
feature,
|
||||
finished_init;
|
||||
event_op4 compressed;
|
||||
event_op3 auxtrace;
|
||||
bool ordered_events;
|
||||
|
||||
Reference in New Issue
Block a user