|
@@ -56,6 +56,7 @@ struct record {
|
|
bool no_buildid_cache;
|
|
bool no_buildid_cache;
|
|
bool no_buildid_cache_set;
|
|
bool no_buildid_cache_set;
|
|
bool buildid_all;
|
|
bool buildid_all;
|
|
|
|
+ bool timestamp_filename;
|
|
unsigned long long samples;
|
|
unsigned long long samples;
|
|
};
|
|
};
|
|
|
|
|
|
@@ -125,7 +126,43 @@ out:
|
|
static volatile int done;
|
|
static volatile int done;
|
|
static volatile int signr = -1;
|
|
static volatile int signr = -1;
|
|
static volatile int child_finished;
|
|
static volatile int child_finished;
|
|
-static volatile int auxtrace_snapshot_enabled;
|
|
|
|
|
|
+
|
|
|
|
+static volatile enum {
|
|
|
|
+ AUXTRACE_SNAPSHOT_OFF = -1,
|
|
|
|
+ AUXTRACE_SNAPSHOT_DISABLED = 0,
|
|
|
|
+ AUXTRACE_SNAPSHOT_ENABLED = 1,
|
|
|
|
+} auxtrace_snapshot_state = AUXTRACE_SNAPSHOT_OFF;
|
|
|
|
+
|
|
|
|
+static inline void
|
|
|
|
+auxtrace_snapshot_on(void)
|
|
|
|
+{
|
|
|
|
+ auxtrace_snapshot_state = AUXTRACE_SNAPSHOT_DISABLED;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static inline void
|
|
|
|
+auxtrace_snapshot_enable(void)
|
|
|
|
+{
|
|
|
|
+ if (auxtrace_snapshot_state == AUXTRACE_SNAPSHOT_OFF)
|
|
|
|
+ return;
|
|
|
|
+ auxtrace_snapshot_state = AUXTRACE_SNAPSHOT_ENABLED;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static inline void
|
|
|
|
+auxtrace_snapshot_disable(void)
|
|
|
|
+{
|
|
|
|
+ if (auxtrace_snapshot_state == AUXTRACE_SNAPSHOT_OFF)
|
|
|
|
+ return;
|
|
|
|
+ auxtrace_snapshot_state = AUXTRACE_SNAPSHOT_DISABLED;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static inline bool
|
|
|
|
+auxtrace_snapshot_is_enabled(void)
|
|
|
|
+{
|
|
|
|
+ if (auxtrace_snapshot_state == AUXTRACE_SNAPSHOT_OFF)
|
|
|
|
+ return false;
|
|
|
|
+ return auxtrace_snapshot_state == AUXTRACE_SNAPSHOT_ENABLED;
|
|
|
|
+}
|
|
|
|
+
|
|
static volatile int auxtrace_snapshot_err;
|
|
static volatile int auxtrace_snapshot_err;
|
|
static volatile int auxtrace_record__snapshot_started;
|
|
static volatile int auxtrace_record__snapshot_started;
|
|
|
|
|
|
@@ -249,7 +286,7 @@ static void record__read_auxtrace_snapshot(struct record *rec)
|
|
} else {
|
|
} else {
|
|
auxtrace_snapshot_err = auxtrace_record__snapshot_finish(rec->itr);
|
|
auxtrace_snapshot_err = auxtrace_record__snapshot_finish(rec->itr);
|
|
if (!auxtrace_snapshot_err)
|
|
if (!auxtrace_snapshot_err)
|
|
- auxtrace_snapshot_enabled = 1;
|
|
|
|
|
|
+ auxtrace_snapshot_enable();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -495,6 +532,37 @@ record__finish_output(struct record *rec)
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int
|
|
|
|
+record__switch_output(struct record *rec, bool at_exit)
|
|
|
|
+{
|
|
|
|
+ struct perf_data_file *file = &rec->file;
|
|
|
|
+ int fd, err;
|
|
|
|
+
|
|
|
|
+ /* Same Size: "2015122520103046"*/
|
|
|
|
+ char timestamp[] = "InvalidTimestamp";
|
|
|
|
+
|
|
|
|
+ rec->samples = 0;
|
|
|
|
+ record__finish_output(rec);
|
|
|
|
+ err = fetch_current_timestamp(timestamp, sizeof(timestamp));
|
|
|
|
+ if (err) {
|
|
|
|
+ pr_err("Failed to get current timestamp\n");
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fd = perf_data_file__switch(file, timestamp,
|
|
|
|
+ rec->session->header.data_offset,
|
|
|
|
+ at_exit);
|
|
|
|
+ if (fd >= 0 && !at_exit) {
|
|
|
|
+ rec->bytes_written = 0;
|
|
|
|
+ rec->session->header.data_size = 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (!quiet)
|
|
|
|
+ fprintf(stderr, "[ perf record: Dump %s.%s ]\n",
|
|
|
|
+ file->path, timestamp);
|
|
|
|
+ return fd;
|
|
|
|
+}
|
|
|
|
+
|
|
static volatile int workload_exec_errno;
|
|
static volatile int workload_exec_errno;
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -615,10 +683,13 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
|
|
signal(SIGCHLD, sig_handler);
|
|
signal(SIGCHLD, sig_handler);
|
|
signal(SIGINT, sig_handler);
|
|
signal(SIGINT, sig_handler);
|
|
signal(SIGTERM, sig_handler);
|
|
signal(SIGTERM, sig_handler);
|
|
- if (rec->opts.auxtrace_snapshot_mode)
|
|
|
|
|
|
+
|
|
|
|
+ if (rec->opts.auxtrace_snapshot_mode) {
|
|
signal(SIGUSR2, snapshot_sig_handler);
|
|
signal(SIGUSR2, snapshot_sig_handler);
|
|
- else
|
|
|
|
|
|
+ auxtrace_snapshot_on();
|
|
|
|
+ } else {
|
|
signal(SIGUSR2, SIG_IGN);
|
|
signal(SIGUSR2, SIG_IGN);
|
|
|
|
+ }
|
|
|
|
|
|
session = perf_session__new(file, false, tool);
|
|
session = perf_session__new(file, false, tool);
|
|
if (session == NULL) {
|
|
if (session == NULL) {
|
|
@@ -744,12 +815,12 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
|
|
perf_evlist__enable(rec->evlist);
|
|
perf_evlist__enable(rec->evlist);
|
|
}
|
|
}
|
|
|
|
|
|
- auxtrace_snapshot_enabled = 1;
|
|
|
|
|
|
+ auxtrace_snapshot_enable();
|
|
for (;;) {
|
|
for (;;) {
|
|
unsigned long long hits = rec->samples;
|
|
unsigned long long hits = rec->samples;
|
|
|
|
|
|
if (record__mmap_read_all(rec) < 0) {
|
|
if (record__mmap_read_all(rec) < 0) {
|
|
- auxtrace_snapshot_enabled = 0;
|
|
|
|
|
|
+ auxtrace_snapshot_disable();
|
|
err = -1;
|
|
err = -1;
|
|
goto out_child;
|
|
goto out_child;
|
|
}
|
|
}
|
|
@@ -787,12 +858,12 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
|
|
* disable events in this case.
|
|
* disable events in this case.
|
|
*/
|
|
*/
|
|
if (done && !disabled && !target__none(&opts->target)) {
|
|
if (done && !disabled && !target__none(&opts->target)) {
|
|
- auxtrace_snapshot_enabled = 0;
|
|
|
|
|
|
+ auxtrace_snapshot_disable();
|
|
perf_evlist__disable(rec->evlist);
|
|
perf_evlist__disable(rec->evlist);
|
|
disabled = true;
|
|
disabled = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- auxtrace_snapshot_enabled = 0;
|
|
|
|
|
|
+ auxtrace_snapshot_disable();
|
|
|
|
|
|
if (forks && workload_exec_errno) {
|
|
if (forks && workload_exec_errno) {
|
|
char msg[STRERR_BUFSIZE];
|
|
char msg[STRERR_BUFSIZE];
|
|
@@ -826,11 +897,22 @@ out_child:
|
|
/* this will be recalculated during process_buildids() */
|
|
/* this will be recalculated during process_buildids() */
|
|
rec->samples = 0;
|
|
rec->samples = 0;
|
|
|
|
|
|
- if (!err)
|
|
|
|
- record__finish_output(rec);
|
|
|
|
|
|
+ if (!err) {
|
|
|
|
+ if (!rec->timestamp_filename) {
|
|
|
|
+ record__finish_output(rec);
|
|
|
|
+ } else {
|
|
|
|
+ fd = record__switch_output(rec, true);
|
|
|
|
+ if (fd < 0) {
|
|
|
|
+ status = fd;
|
|
|
|
+ goto out_delete_session;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
|
|
if (!err && !quiet) {
|
|
if (!err && !quiet) {
|
|
char samples[128];
|
|
char samples[128];
|
|
|
|
+ const char *postfix = rec->timestamp_filename ?
|
|
|
|
+ ".<timestamp>" : "";
|
|
|
|
|
|
if (rec->samples && !rec->opts.full_auxtrace)
|
|
if (rec->samples && !rec->opts.full_auxtrace)
|
|
scnprintf(samples, sizeof(samples),
|
|
scnprintf(samples, sizeof(samples),
|
|
@@ -838,9 +920,9 @@ out_child:
|
|
else
|
|
else
|
|
samples[0] = '\0';
|
|
samples[0] = '\0';
|
|
|
|
|
|
- fprintf(stderr, "[ perf record: Captured and wrote %.3f MB %s%s ]\n",
|
|
|
|
|
|
+ fprintf(stderr, "[ perf record: Captured and wrote %.3f MB %s%s%s ]\n",
|
|
perf_data_file__size(file) / 1024.0 / 1024.0,
|
|
perf_data_file__size(file) / 1024.0 / 1024.0,
|
|
- file->path, samples);
|
|
|
|
|
|
+ file->path, postfix, samples);
|
|
}
|
|
}
|
|
|
|
|
|
out_delete_session:
|
|
out_delete_session:
|
|
@@ -1210,6 +1292,8 @@ struct option __record_options[] = {
|
|
"file", "vmlinux pathname"),
|
|
"file", "vmlinux pathname"),
|
|
OPT_BOOLEAN(0, "buildid-all", &record.buildid_all,
|
|
OPT_BOOLEAN(0, "buildid-all", &record.buildid_all,
|
|
"Record build-id of all DSOs regardless of hits"),
|
|
"Record build-id of all DSOs regardless of hits"),
|
|
|
|
+ OPT_BOOLEAN(0, "timestamp-filename", &record.timestamp_filename,
|
|
|
|
+ "append timestamp to output filename"),
|
|
OPT_END()
|
|
OPT_END()
|
|
};
|
|
};
|
|
|
|
|
|
@@ -1358,9 +1442,9 @@ out_symbol_exit:
|
|
|
|
|
|
static void snapshot_sig_handler(int sig __maybe_unused)
|
|
static void snapshot_sig_handler(int sig __maybe_unused)
|
|
{
|
|
{
|
|
- if (!auxtrace_snapshot_enabled)
|
|
|
|
|
|
+ if (!auxtrace_snapshot_is_enabled())
|
|
return;
|
|
return;
|
|
- auxtrace_snapshot_enabled = 0;
|
|
|
|
|
|
+ auxtrace_snapshot_disable();
|
|
auxtrace_snapshot_err = auxtrace_record__snapshot_start(record.itr);
|
|
auxtrace_snapshot_err = auxtrace_record__snapshot_start(record.itr);
|
|
auxtrace_record__snapshot_started = 1;
|
|
auxtrace_record__snapshot_started = 1;
|
|
}
|
|
}
|