diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index 8a4506113d9fb7..ebcba1f95513d7 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt @@ -574,6 +574,10 @@ Implies --tail-synthesize. --kcore:: Make a copy of /proc/kcore and place it into a directory with the perf data file. +--max-size=:: +Limit the sample data max size, is expected to be a number with +appended unit character - B/K/M/G + SEE ALSO -------- linkperf:perf-stat[1], linkperf:perf-list[1] diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index f6664bb08b26fc..b95c000c1ed9b2 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -94,8 +94,11 @@ struct record { struct switch_output switch_output; unsigned long long samples; cpu_set_t affinity_mask; + unsigned long output_max_size; /* = 0: unlimited */ }; +static volatile int done; + static volatile int auxtrace_record__snapshot_started; static DEFINE_TRIGGER(auxtrace_snapshot_trigger); static DEFINE_TRIGGER(switch_output_trigger); @@ -123,6 +126,12 @@ static bool switch_output_time(struct record *rec) trigger_is_ready(&switch_output_trigger); } +static bool record__output_max_size_exceeded(struct record *rec) +{ + return rec->output_max_size && + (rec->bytes_written >= rec->output_max_size); +} + static int record__write(struct record *rec, struct mmap *map __maybe_unused, void *bf, size_t size) { @@ -135,6 +144,13 @@ static int record__write(struct record *rec, struct mmap *map __maybe_unused, rec->bytes_written += size; + if (record__output_max_size_exceeded(rec) && !done) { + fprintf(stderr, "[ perf record: perf size limit reached (%" PRIu64 " KB)," + " stopping session ]\n", + rec->bytes_written >> 10); + done = 1; + } + if (switch_output_size(rec)) trigger_hit(&switch_output_trigger); @@ -499,7 +515,6 @@ static int record__pushfn(struct mmap *map, void *to, void *bf, size_t size) return record__write(rec, map, bf, size); } -static volatile int done; static volatile int signr = -1; static volatile int child_finished; @@ -1984,6 +1999,33 @@ static int record__parse_affinity(const struct option *opt, const char *str, int return 0; } +static int parse_output_max_size(const struct option *opt, + const char *str, int unset) +{ + unsigned long *s = (unsigned long *)opt->value; + static struct parse_tag tags_size[] = { + { .tag = 'B', .mult = 1 }, + { .tag = 'K', .mult = 1 << 10 }, + { .tag = 'M', .mult = 1 << 20 }, + { .tag = 'G', .mult = 1 << 30 }, + { .tag = 0 }, + }; + unsigned long val; + + if (unset) { + *s = 0; + return 0; + } + + val = parse_tag_value(str, tags_size); + if (val != (unsigned long) -1) { + *s = val; + return 0; + } + + return -1; +} + static int record__parse_mmap_pages(const struct option *opt, const char *str, int unset __maybe_unused) @@ -2311,6 +2353,8 @@ static struct option __record_options[] = { "n", "Compressed records using specified level (default: 1 - fastest compression, 22 - greatest compression)", record__parse_comp_level), #endif + OPT_CALLBACK(0, "max-size", &record.output_max_size, + "size", "Limit the maximum size of the output file", parse_output_max_size), OPT_END() };