Commit 03724b2e authored by Andi Kleen's avatar Andi Kleen Committed by Arnaldo Carvalho de Melo

perf record: Allow to limit number of reported perf.data files

When doing long term recording and waiting for some event to snapshot
on, we often only care about the last minute or so.

The --switch-output command line option supports rotating the perf.data
file when the size exceeds a threshold. But the disk would still be
filled with unnecessary old files.

Add a new option to only keep a number of rotated files, so that the
disk space usage can be limited.
Signed-off-by: default avatarAndi Kleen <ak@linux.intel.com>
Acked-by: default avatarJiri Olsa <jolsa@kernel.org>
LPU-Reference: 20190314225002.30108-3-andi@firstfloor.org
Link: https://lkml.kernel.org/n/tip-y5u2lik0ragt4vlktz6qc9ks@git.kernel.orgSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 6f40b2a5
...@@ -495,6 +495,10 @@ overhead. You can still switch them on with: ...@@ -495,6 +495,10 @@ overhead. You can still switch them on with:
--switch-output --no-no-buildid --no-no-buildid-cache --switch-output --no-no-buildid --no-no-buildid-cache
--switch-max-files=N::
When rotating perf.data with --switch-output, only keep N files.
--dry-run:: --dry-run::
Parse options then exit. --dry-run can be used to detect errors in cmdline Parse options then exit. --dry-run can be used to detect errors in cmdline
options. options.
......
...@@ -62,6 +62,9 @@ struct switch_output { ...@@ -62,6 +62,9 @@ struct switch_output {
unsigned long time; unsigned long time;
const char *str; const char *str;
bool set; bool set;
char **filenames;
int num_files;
int cur_file;
}; };
struct record { struct record {
...@@ -892,6 +895,7 @@ record__switch_output(struct record *rec, bool at_exit) ...@@ -892,6 +895,7 @@ record__switch_output(struct record *rec, bool at_exit)
{ {
struct perf_data *data = &rec->data; struct perf_data *data = &rec->data;
int fd, err; int fd, err;
char *new_filename;
/* Same Size: "2015122520103046"*/ /* Same Size: "2015122520103046"*/
char timestamp[] = "InvalidTimestamp"; char timestamp[] = "InvalidTimestamp";
...@@ -912,7 +916,7 @@ record__switch_output(struct record *rec, bool at_exit) ...@@ -912,7 +916,7 @@ record__switch_output(struct record *rec, bool at_exit)
fd = perf_data__switch(data, timestamp, fd = perf_data__switch(data, timestamp,
rec->session->header.data_offset, rec->session->header.data_offset,
at_exit); at_exit, &new_filename);
if (fd >= 0 && !at_exit) { if (fd >= 0 && !at_exit) {
rec->bytes_written = 0; rec->bytes_written = 0;
rec->session->header.data_size = 0; rec->session->header.data_size = 0;
...@@ -922,6 +926,21 @@ record__switch_output(struct record *rec, bool at_exit) ...@@ -922,6 +926,21 @@ record__switch_output(struct record *rec, bool at_exit)
fprintf(stderr, "[ perf record: Dump %s.%s ]\n", fprintf(stderr, "[ perf record: Dump %s.%s ]\n",
data->path, timestamp); data->path, timestamp);
if (rec->switch_output.num_files) {
int n = rec->switch_output.cur_file + 1;
if (n >= rec->switch_output.num_files)
n = 0;
rec->switch_output.cur_file = n;
if (rec->switch_output.filenames[n]) {
remove(rec->switch_output.filenames[n]);
free(rec->switch_output.filenames[n]);
}
rec->switch_output.filenames[n] = new_filename;
} else {
free(new_filename);
}
/* Output tracking events */ /* Output tracking events */
if (!at_exit) { if (!at_exit) {
record__synthesize(rec, false); record__synthesize(rec, false);
...@@ -1973,6 +1992,8 @@ static struct option __record_options[] = { ...@@ -1973,6 +1992,8 @@ static struct option __record_options[] = {
&record.switch_output.set, "signal,size,time", &record.switch_output.set, "signal,size,time",
"Switch output when receive SIGUSR2 or cross size,time threshold", "Switch output when receive SIGUSR2 or cross size,time threshold",
"signal"), "signal"),
OPT_INTEGER(0, "switch-max-files", &record.switch_output.num_files,
"Limit number of switch output generated files"),
OPT_BOOLEAN(0, "dry-run", &dry_run, OPT_BOOLEAN(0, "dry-run", &dry_run,
"Parse options then exit"), "Parse options then exit"),
#ifdef HAVE_AIO_SUPPORT #ifdef HAVE_AIO_SUPPORT
...@@ -2059,6 +2080,13 @@ int cmd_record(int argc, const char **argv) ...@@ -2059,6 +2080,13 @@ int cmd_record(int argc, const char **argv)
alarm(rec->switch_output.time); alarm(rec->switch_output.time);
} }
if (rec->switch_output.num_files) {
rec->switch_output.filenames = calloc(sizeof(char *),
rec->switch_output.num_files);
if (!rec->switch_output.filenames)
return -EINVAL;
}
/* /*
* Allow aliases to facilitate the lookup of symbols for address * Allow aliases to facilitate the lookup of symbols for address
* filters. Refer to auxtrace_parse_filters(). * filters. Refer to auxtrace_parse_filters().
......
...@@ -361,9 +361,9 @@ ssize_t perf_data__write(struct perf_data *data, ...@@ -361,9 +361,9 @@ ssize_t perf_data__write(struct perf_data *data,
int perf_data__switch(struct perf_data *data, int perf_data__switch(struct perf_data *data,
const char *postfix, const char *postfix,
size_t pos, bool at_exit) size_t pos, bool at_exit,
char **new_filepath)
{ {
char *new_filepath;
int ret; int ret;
if (check_pipe(data)) if (check_pipe(data))
...@@ -371,15 +371,15 @@ int perf_data__switch(struct perf_data *data, ...@@ -371,15 +371,15 @@ int perf_data__switch(struct perf_data *data,
if (perf_data__is_read(data)) if (perf_data__is_read(data))
return -EINVAL; return -EINVAL;
if (asprintf(&new_filepath, "%s.%s", data->path, postfix) < 0) if (asprintf(new_filepath, "%s.%s", data->path, postfix) < 0)
return -ENOMEM; return -ENOMEM;
/* /*
* Only fire a warning, don't return error, continue fill * Only fire a warning, don't return error, continue fill
* original file. * original file.
*/ */
if (rename(data->path, new_filepath)) if (rename(data->path, *new_filepath))
pr_warning("Failed to rename %s to %s\n", data->path, new_filepath); pr_warning("Failed to rename %s to %s\n", data->path, *new_filepath);
if (!at_exit) { if (!at_exit) {
close(data->file.fd); close(data->file.fd);
...@@ -396,7 +396,6 @@ int perf_data__switch(struct perf_data *data, ...@@ -396,7 +396,6 @@ int perf_data__switch(struct perf_data *data,
} }
ret = data->file.fd; ret = data->file.fd;
out: out:
free(new_filepath);
return ret; return ret;
} }
......
...@@ -70,7 +70,7 @@ ssize_t perf_data_file__write(struct perf_data_file *file, ...@@ -70,7 +70,7 @@ ssize_t perf_data_file__write(struct perf_data_file *file,
*/ */
int perf_data__switch(struct perf_data *data, int perf_data__switch(struct perf_data *data,
const char *postfix, const char *postfix,
size_t pos, bool at_exit); size_t pos, bool at_exit, char **new_filepath);
int perf_data__create_dir(struct perf_data *data, int nr); int perf_data__create_dir(struct perf_data *data, int nr);
int perf_data__open_dir(struct perf_data *data); int perf_data__open_dir(struct perf_data *data);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment