|
@@ -190,16 +190,30 @@ out:
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
|
+static int process_sample_event(struct perf_tool *tool,
|
|
|
+ union perf_event *event,
|
|
|
+ struct perf_sample *sample,
|
|
|
+ struct perf_evsel *evsel,
|
|
|
+ struct machine *machine)
|
|
|
+{
|
|
|
+ struct record *rec = container_of(tool, struct record, tool);
|
|
|
+
|
|
|
+ rec->samples++;
|
|
|
+
|
|
|
+ return build_id__mark_dso_hit(tool, event, sample, evsel, machine);
|
|
|
+}
|
|
|
+
|
|
|
static int process_buildids(struct record *rec)
|
|
|
{
|
|
|
struct perf_data_file *file = &rec->file;
|
|
|
struct perf_session *session = rec->session;
|
|
|
- u64 start = session->header.data_offset;
|
|
|
|
|
|
- u64 size = lseek(file->fd, 0, SEEK_CUR);
|
|
|
+ u64 size = lseek(perf_data_file__fd(file), 0, SEEK_CUR);
|
|
|
if (size == 0)
|
|
|
return 0;
|
|
|
|
|
|
+ file->size = size;
|
|
|
+
|
|
|
/*
|
|
|
* During this process, it'll load kernel map and replace the
|
|
|
* dso->long_name to a real pathname it found. In this case
|
|
@@ -211,9 +225,7 @@ static int process_buildids(struct record *rec)
|
|
|
*/
|
|
|
symbol_conf.ignore_vmlinux_buildid = true;
|
|
|
|
|
|
- return __perf_session__process_events(session, start,
|
|
|
- size - start,
|
|
|
- size, &build_id__mark_dso_hit_ops);
|
|
|
+ return perf_session__process_events(session, &rec->tool);
|
|
|
}
|
|
|
|
|
|
static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
|
|
@@ -322,6 +334,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
|
|
|
struct perf_data_file *file = &rec->file;
|
|
|
struct perf_session *session;
|
|
|
bool disabled = false, draining = false;
|
|
|
+ int fd;
|
|
|
|
|
|
rec->progname = argv[0];
|
|
|
|
|
@@ -336,6 +349,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
+ fd = perf_data_file__fd(file);
|
|
|
rec->session = session;
|
|
|
|
|
|
record__init_features(rec);
|
|
@@ -360,12 +374,11 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
|
|
|
perf_header__clear_feat(&session->header, HEADER_GROUP_DESC);
|
|
|
|
|
|
if (file->is_pipe) {
|
|
|
- err = perf_header__write_pipe(file->fd);
|
|
|
+ err = perf_header__write_pipe(fd);
|
|
|
if (err < 0)
|
|
|
goto out_child;
|
|
|
} else {
|
|
|
- err = perf_session__write_header(session, rec->evlist,
|
|
|
- file->fd, false);
|
|
|
+ err = perf_session__write_header(session, rec->evlist, fd, false);
|
|
|
if (err < 0)
|
|
|
goto out_child;
|
|
|
}
|
|
@@ -397,7 +410,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
|
|
|
* return this more properly and also
|
|
|
* propagate errors that now are calling die()
|
|
|
*/
|
|
|
- err = perf_event__synthesize_tracing_data(tool, file->fd, rec->evlist,
|
|
|
+ err = perf_event__synthesize_tracing_data(tool, fd, rec->evlist,
|
|
|
process_synthesized_event);
|
|
|
if (err <= 0) {
|
|
|
pr_err("Couldn't record tracing data.\n");
|
|
@@ -504,19 +517,9 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
|
|
|
goto out_child;
|
|
|
}
|
|
|
|
|
|
- if (!quiet) {
|
|
|
+ if (!quiet)
|
|
|
fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
|
|
|
|
|
|
- /*
|
|
|
- * Approximate RIP event size: 24 bytes.
|
|
|
- */
|
|
|
- fprintf(stderr,
|
|
|
- "[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
|
|
|
- (double)rec->bytes_written / 1024.0 / 1024.0,
|
|
|
- file->path,
|
|
|
- rec->bytes_written / 24);
|
|
|
- }
|
|
|
-
|
|
|
out_child:
|
|
|
if (forks) {
|
|
|
int exit_status;
|
|
@@ -535,13 +538,29 @@ out_child:
|
|
|
} else
|
|
|
status = err;
|
|
|
|
|
|
+ /* this will be recalculated during process_buildids() */
|
|
|
+ rec->samples = 0;
|
|
|
+
|
|
|
if (!err && !file->is_pipe) {
|
|
|
rec->session->header.data_size += rec->bytes_written;
|
|
|
|
|
|
if (!rec->no_buildid)
|
|
|
process_buildids(rec);
|
|
|
- perf_session__write_header(rec->session, rec->evlist,
|
|
|
- file->fd, true);
|
|
|
+ perf_session__write_header(rec->session, rec->evlist, fd, true);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!err && !quiet) {
|
|
|
+ char samples[128];
|
|
|
+
|
|
|
+ if (rec->samples)
|
|
|
+ scnprintf(samples, sizeof(samples),
|
|
|
+ " (%" PRIu64 " samples)", rec->samples);
|
|
|
+ else
|
|
|
+ samples[0] = '\0';
|
|
|
+
|
|
|
+ fprintf(stderr, "[ perf record: Captured and wrote %.3f MB %s%s ]\n",
|
|
|
+ perf_data_file__size(file) / 1024.0 / 1024.0,
|
|
|
+ file->path, samples);
|
|
|
}
|
|
|
|
|
|
out_delete_session:
|
|
@@ -720,6 +739,13 @@ static struct record record = {
|
|
|
.default_per_cpu = true,
|
|
|
},
|
|
|
},
|
|
|
+ .tool = {
|
|
|
+ .sample = process_sample_event,
|
|
|
+ .fork = perf_event__process_fork,
|
|
|
+ .comm = perf_event__process_comm,
|
|
|
+ .mmap = perf_event__process_mmap,
|
|
|
+ .mmap2 = perf_event__process_mmap2,
|
|
|
+ },
|
|
|
};
|
|
|
|
|
|
#define CALLCHAIN_HELP "setup and enables call-graph (stack chain/backtrace) recording: "
|