[PATCH v4] perf record: Add support for limit perf output file size
The patch adds a new option to limit the output file size, then based on it, we can create a wrapper of the perf command that uses the option to avoid exhausting the disk space by the unconscious user. In order to make the perf.data parsable, we just limit the sample data size, since the perf.data consists of many headers and sample data and other data, the actual size of the recorded file will bigger than the setting value. Testing it: # ./perf record -a -g --max-size=10M Couldn't synthesize bpf events. WARNING: The perf data has already reached the limit, stop recording! [ perf record: Woken up 30 times to write data ] [ perf record: Captured and wrote 10.233 MB perf.data (175650 samples) ] Terminated # ls -lh perf.data -rw--- 1 root root 11M Jul 17 14:01 perf.data # ./perf record -a -g --max-size=10K WARNING: The perf data has already reached the limit, stop recording! Couldn't synthesize bpf events. [ perf record: Woken up 0 times to write data ] [ perf record: Captured and wrote 1.824 MB perf.data (67 samples) ] Terminated # ls -lh perf.data -rw--- 1 root root 1.9M Jul 17 14:05 perf.data Signed-off-by: Jiwei Sun --- v4 changes: - Just show one WARNING message after reached the limit. v3 changes: - add a test result - add the new option to tools/perf/Documentation/perf-record.txt v2 changes: - make patch based on latest Arnaldo's perf/core, - display warning message when reached the limit. --- tools/perf/Documentation/perf-record.txt | 4 +++ tools/perf/builtin-record.c | 42 2 files changed, 46 insertions(+) diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index c6f9f31b6039..f1c6113fbc82 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt @@ -571,6 +571,10 @@ config terms. For example: 'cycles/overwrite/' and 'instructions/no-overwrite/'. Implies --tail-synthesize. +--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 48600c90cc7e..30904d2a3407 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -91,6 +91,7 @@ struct record { struct switch_outputswitch_output; unsigned long long samples; cpu_set_t affinity_mask; + unsigned long output_max_size;/* = 0: unlimited */ }; static volatile int auxtrace_record__snapshot_started; @@ -120,6 +121,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) { @@ -132,6 +139,12 @@ static int record__write(struct record *rec, struct mmap *map __maybe_unused, rec->bytes_written += size; + if (record__output_max_size_exceeded(rec)) { + WARN_ONCE(1, "WARNING: The perf data has already reached " +"the limit, stop recording!\n"); + raise(SIGTERM); + } + if (switch_output_size(rec)) trigger_hit(&switch_output_trigger); @@ -1936,6 +1949,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) @@ -2262,6 +2302,8 @@ static struct option __record_options[] = { "n", "Compressed records using specified level (default: 1 - fastest compression, 22 - greatest compression)",
[PATCH v4] perf record: Add support for limit perf output file size
The patch adds a new option to limit the output file size, then based on it, we can create a wrapper of the perf command that uses the option to avoid exhausting the disk space by the unconscious user. In order to make the perf.data parsable, we just limit the sample data size, since the perf.data consists of many headers and sample data and other data, the actual size of the recorded file will bigger than the setting value. Testing it: # ./perf record -a -g --max-size=10M Couldn't synthesize bpf events. WARNING: The perf data has already reached the limit, stop recording! [ perf record: Woken up 30 times to write data ] [ perf record: Captured and wrote 10.233 MB perf.data (175650 samples) ] Terminated # ls -lh perf.data -rw--- 1 root root 11M Jul 17 14:01 perf.data # ./perf record -a -g --max-size=10K WARNING: The perf data has already reached the limit, stop recording! Couldn't synthesize bpf events. [ perf record: Woken up 0 times to write data ] [ perf record: Captured and wrote 1.824 MB perf.data (67 samples) ] Terminated # ls -lh perf.data -rw--- 1 root root 1.9M Jul 17 14:05 perf.data Signed-off-by: Jiwei Sun --- v4 changes: - Just show one WARNING message after reached the limit. v3 changes: - add a test result - add the new option to tools/perf/Documentation/perf-record.txt v2 changes: - make patch based on latest Arnaldo's perf/core, - display warning message when reached the limit. --- tools/perf/Documentation/perf-record.txt | 4 +++ tools/perf/builtin-record.c | 42 2 files changed, 46 insertions(+) diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index 15e0fa87241b..918a0844cbcf 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt @@ -564,6 +564,10 @@ config terms. For example: 'cycles/overwrite/' and 'instructions/no-overwrite/'. Implies --tail-synthesize. +--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 8779cee58185..8c49dce3abd8 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -86,6 +86,7 @@ struct record { struct switch_outputswitch_output; unsigned long long samples; cpu_set_t affinity_mask; + unsigned long output_max_size;/* = 0: unlimited */ }; static volatile int auxtrace_record__snapshot_started; @@ -115,6 +116,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 perf_mmap *map __maybe_unused, void *bf, size_t size) { @@ -127,6 +134,12 @@ static int record__write(struct record *rec, struct perf_mmap *map __maybe_unuse rec->bytes_written += size; + if (record__output_max_size_exceeded(rec)) { + WARN_ONCE(1, "WARNING: The perf data has already reached " +"the limit, stop recording!\n"); + raise(SIGTERM); + } + if (switch_output_size(rec)) trigger_hit(&switch_output_trigger); @@ -1902,6 +1915,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) @@ -2228,6 +2268,8 @@ static struct option __record_options[] = { "n", "Compressed records using specified level (default: 1 - fastest compression, 22 - greatest compression)&quo
Re: [PATCH v4] perf record: Add support for limit perf output file size
Hello Arnaldo & Jirka, Do you have any other suggestions regarding the patch? Any suggestions are welcome. Thank you very much. Regards, Jiwei On 2019e9409f25f% 15:06, Jiwei Sun wrote: > The patch adds a new option to limit the output file size, then based > on it, we can create a wrapper of the perf command that uses the option > to avoid exhausting the disk space by the unconscious user. > > In order to make the perf.data parsable, we just limit the sample data > size, since the perf.data consists of many headers and sample data and > other data, the actual size of the recorded file will bigger than the > setting value. > > Testing it: > > # ./perf record -a -g --max-size=10M > Couldn't synthesize bpf events. > WARNING: The perf data has already reached the limit, stop recording! > [ perf record: Woken up 30 times to write data ] > [ perf record: Captured and wrote 10.233 MB perf.data (175650 samples) ] > Terminated > > # ls -lh perf.data > -rw--- 1 root root 11M Jul 17 14:01 perf.data > > # ./perf record -a -g --max-size=10K > WARNING: The perf data has already reached the limit, stop recording! > Couldn't synthesize bpf events. > [ perf record: Woken up 0 times to write data ] > [ perf record: Captured and wrote 1.824 MB perf.data (67 samples) ] > Terminated > > # ls -lh perf.data > -rw--- 1 root root 1.9M Jul 17 14:05 perf.data > > Signed-off-by: Jiwei Sun > --- > v4 changes: > - Just show one WARNING message after reached the limit. > > v3 changes: > - add a test result > - add the new option to tools/perf/Documentation/perf-record.txt > > v2 changes: > - make patch based on latest Arnaldo's perf/core, > - display warning message when reached the limit. > --- > tools/perf/Documentation/perf-record.txt | 4 +++ > tools/perf/builtin-record.c | 42 > 2 files changed, 46 insertions(+) > > diff --git a/tools/perf/Documentation/perf-record.txt > b/tools/perf/Documentation/perf-record.txt > index c6f9f31b6039..f1c6113fbc82 100644 > --- a/tools/perf/Documentation/perf-record.txt > +++ b/tools/perf/Documentation/perf-record.txt > @@ -571,6 +571,10 @@ config terms. For example: 'cycles/overwrite/' and > 'instructions/no-overwrite/'. > > Implies --tail-synthesize. > > +--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 48600c90cc7e..30904d2a3407 100644 > --- a/tools/perf/builtin-record.c > +++ b/tools/perf/builtin-record.c > @@ -91,6 +91,7 @@ struct record { > struct switch_outputswitch_output; > unsigned long long samples; > cpu_set_t affinity_mask; > + unsigned long output_max_size;/* = 0: unlimited */ > }; > > static volatile int auxtrace_record__snapshot_started; > @@ -120,6 +121,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) > { > @@ -132,6 +139,12 @@ static int record__write(struct record *rec, struct mmap > *map __maybe_unused, > > rec->bytes_written += size; > > + if (record__output_max_size_exceeded(rec)) { > + WARN_ONCE(1, "WARNING: The perf data has already reached " > + "the limit, stop recording!\n"); > + raise(SIGTERM); > + } > + > if (switch_output_size(rec)) > trigger_hit(&switch_output_trigger); > > @@ -1936,6 +1949,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 }
Re: [PATCH v4] perf record: Add support for limit perf output file size
Hi Jirka, On 2019e9410f21f% 21:41, Jiri Olsa wrote: > On Wed, Sep 25, 2019 at 03:06:37PM +0800, Jiwei Sun wrote: > > SNIP > >> 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 48600c90cc7e..30904d2a3407 100644 >> --- a/tools/perf/builtin-record.c >> +++ b/tools/perf/builtin-record.c >> @@ -91,6 +91,7 @@ struct record { >> struct switch_outputswitch_output; >> unsigned long long samples; >> cpu_set_t affinity_mask; >> +unsigned long output_max_size;/* = 0: unlimited */ >> }; >> >> static volatile int auxtrace_record__snapshot_started; >> @@ -120,6 +121,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) >> { >> @@ -132,6 +139,12 @@ static int record__write(struct record *rec, struct >> mmap *map __maybe_unused, >> >> rec->bytes_written += size; >> >> +if (record__output_max_size_exceeded(rec)) { >> +WARN_ONCE(1, "WARNING: The perf data has already reached " >> + "the limit, stop recording!\n"); > > I think the message whouldn't be a warning, the user asked for > that, maybe something more like: > > [ perf record: perf size limit reached (XXMB), stopping session ] > >> +raise(SIGTERM); > > could we just set 'done = 1' what's the benefit in killing perf? Thanks for your suggestions. Yes, if just set "done == 1" is more efficient and more concise. And I will modify it and the output format, and then send a v5 patch. Thanks again. Regards, Jiwei > > thanks, > jirka > >
[PATCH] perf record: Add support for limit perf output file size
The patch adds a new option to limit the output file size, then based on it, we can create a wrapper of the perf command that uses the option to avoid exhausting the disk space by the unconscious user. Signed-off-by: Jiwei Sun --- tools/perf/builtin-record.c | 39 + 1 file changed, 39 insertions(+) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 882285fb9f64..28a03929166d 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -81,6 +81,7 @@ struct record { booltimestamp_boundary; struct switch_outputswitch_output; unsigned long long samples; + unsigned long output_max_size;/* = 0: unlimited */ }; static volatile int auxtrace_record__snapshot_started; @@ -106,6 +107,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 perf_mmap *map __maybe_unused, void *bf, size_t size) { @@ -118,6 +125,9 @@ static int record__write(struct record *rec, struct perf_mmap *map __maybe_unuse rec->bytes_written += size; + if (record__output_max_size_exceeded(rec)) + raise(SIGTERM); + if (switch_output_size(rec)) trigger_hit(&switch_output_trigger); @@ -1639,6 +1649,33 @@ static int parse_clockid(const struct option *opt, const char *str, int unset) return -1; } +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) @@ -1946,6 +1983,8 @@ static struct option __record_options[] = { &nr_cblocks_default, "n", "Use control blocks in asynchronous trace writing mode (default: 1, max: 4)", record__aio_parse), #endif + OPT_CALLBACK(0, "output-max-size", &record.output_max_size, +"size", "Output file maximum size", parse_output_max_size), OPT_END() }; -- 2.20.1
[PATCH]spi: pl022: add a message state STATE_TIMEOUT for timeout transfer
When transfer timeout, give -EAGAIN to the message's status, and it can make the spi device driver choose repeated transimation or not. And if transfer timeout, output some useful information for tracing the issue. Signed-off-by: Jiwei Sun --- drivers/spi/spi-pl022.c | 30 +- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index 0c793e31d60f..26684178786f 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c @@ -253,6 +253,7 @@ #define STATE_RUNNING ((void *) 1) #define STATE_DONE ((void *) 2) #define STATE_ERROR((void *) -1) +#define STATE_TIMEOUT ((void *) -2) /* * SSP State - Whether Enabled or Disabled @@ -1484,6 +1485,30 @@ static void do_interrupt_dma_transfer(struct pl022 *pl022) writew(irqflags, SSP_IMSC(pl022->virtbase)); } +static void print_current_status(struct pl022 *pl022) +{ + u32 read_cr0; + u16 read_cr1, read_dmacr, read_sr; + + if (pl022->vendor->extended_cr) + read_cr0 = readl(SSP_CR0(pl022->virtbase)); + else + read_cr0 = readw(SSP_CR0(pl022->virtbase)); + read_cr1 = readw(SSP_CR1(pl022->virtbase)); + read_dmacr = readw(SSP_DMACR(pl022->virtbase)); + read_sr = readw(SSP_SR(pl022->virtbase)); + + dev_warn(&pl022->adev->dev, "spi-pl022 CR0: %x\n", read_cr0); + dev_warn(&pl022->adev->dev, "spi-pl022 CR1: %x\n", read_cr1); + dev_warn(&pl022->adev->dev, "spi-pl022 DMACR: %x\n", read_dmacr); + dev_warn(&pl022->adev->dev, "spi-pl022 SR: %x\n", read_sr); + dev_warn(&pl022->adev->dev, + "spi-pl022 exp_fifo_level/fifodepth: %u/%d\n", + pl022->exp_fifo_level, + pl022->vendor->fifodepth); + +} + static void do_polling_transfer(struct pl022 *pl022) { struct spi_message *message = NULL; @@ -1535,7 +1560,8 @@ static void do_polling_transfer(struct pl022 *pl022) if (time_after(time, timeout)) { dev_warn(&pl022->adev->dev, "%s: timeout!\n", __func__); - message->state = STATE_ERROR; + message->state = STATE_TIMEOUT; + print_current_status(pl022); goto out; } cpu_relax(); @@ -1553,6 +1579,8 @@ static void do_polling_transfer(struct pl022 *pl022) /* Handle end of message */ if (message->state == STATE_DONE) message->status = 0; + else if (message->state == STATE_TIMEOUT) + message->status = -EAGAIN; else message->status = -EIO; -- 2.20.1
[PATCH v3] perf record: Add support for limit perf output file size
The patch adds a new option to limit the output file size, then based on it, we can create a wrapper of the perf command that uses the option to avoid exhausting the disk space by the unconscious user. Testing it: # ./perf record -a --max-size 100M Couldn't synthesize bpf events. WARNING: The perf data has already reached the limit, stop recording! WARNING: The perf data has already reached the limit, stop recording! WARNING: The perf data has already reached the limit, stop recording! WARNING: The perf data has already reached the limit, stop recording! WARNING: The perf data has already reached the limit, stop recording! WARNING: The perf data has already reached the limit, stop recording! WARNING: The perf data has already reached the limit, stop recording! WARNING: The perf data has already reached the limit, stop recording! [ perf record: Woken up 392 times to write data ] [ perf record: Captured and wrote 100.104 MB perf.data (2128267 samples) ] Terminated # ls -lh perf.data -rw--- 1 root root 101M Mar 11 14:48 perf.data Signed-off-by: Jiwei Sun --- v3 changes: - add a test result - add the new option to tools/perf/Documentation/perf-record.txt v2 changes: - make patch based on latest Arnaldo's perf/core, - display warning message when reached the limit. --- tools/perf/Documentation/perf-record.txt | 3 ++ tools/perf/builtin-record.c | 42 2 files changed, 45 insertions(+) diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index 8f0c2be34848..731dcfabe7fa 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt @@ -524,6 +524,9 @@ config terms. For example: 'cycles/overwrite/' and 'instructions/no-overwrite/'. Implies --tail-synthesize. +--max-size:: +Limit the output data max size. + 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 a468d882e74f..fe0e87781841 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -83,6 +83,7 @@ struct record { struct switch_outputswitch_output; unsigned long long samples; cpu_set_t affinity_mask; + unsigned long output_max_size;/* = 0: unlimited */ }; static volatile int auxtrace_record__snapshot_started; @@ -112,6 +113,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 perf_mmap *map __maybe_unused, void *bf, size_t size) { @@ -124,6 +131,12 @@ static int record__write(struct record *rec, struct perf_mmap *map __maybe_unuse rec->bytes_written += size; + if (record__output_max_size_exceeded(rec)) { + pr_warning("WARNING: The perf data has already reached " + "the limit, stop recording!\n"); + raise(SIGTERM); + } + if (switch_output_size(rec)) trigger_hit(&switch_output_trigger); @@ -1672,6 +1685,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) @@ -1983,6 +2023,8 @@ static struct option __record_options[] = { OPT_CALLBACK(0, "affinity", &record.opts, "node|cpu", "Set affinity mask of trace reading thread to NUMA node cpu mask or cpu of processed mmap buffer", record__parse_affinity), + OPT_CALLBACK(0, "max-size", &record.output_max_size, +"size", "Limit the maximum size of the output file", parse_output_max_size), OPT_END() }; -- 2.20.1
Re: [PATCH] perf record: Add support for limit perf output file size
Hi Jirka, On 02/21/2019 05:56 PM, Jiri Olsa wrote: > On Thu, Feb 21, 2019 at 02:44:19PM +0800, Jiwei Sun wrote: >> The patch adds a new option to limit the output file size, then based >> on it, we can create a wrapper of the perf command that uses the option >> to avoid exhausting the disk space by the unconscious user. >> >> Signed-off-by: Jiwei Sun >> --- >> tools/perf/builtin-record.c | 39 + >> 1 file changed, 39 insertions(+) >> >> diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c >> index 882285fb9f64..28a03929166d 100644 >> --- a/tools/perf/builtin-record.c >> +++ b/tools/perf/builtin-record.c >> @@ -81,6 +81,7 @@ struct record { >> booltimestamp_boundary; >> struct switch_outputswitch_output; >> unsigned long long samples; >> +unsigned long output_max_size;/* = 0: unlimited */ > > please rebase to latest Arnaldo's perf/core, > there are new fields in here now OK, thanks for your response, and I will send a v2 patch based on the branch perf/core. > >> }; >> >> static volatile int auxtrace_record__snapshot_started; >> @@ -106,6 +107,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 perf_mmap *map >> __maybe_unused, >> void *bf, size_t size) >> { >> @@ -118,6 +125,9 @@ static int record__write(struct record *rec, struct >> perf_mmap *map __maybe_unuse >> >> rec->bytes_written += size; >> >> +if (record__output_max_size_exceeded(rec)) >> +raise(SIGTERM); > > perhaps display some message saying we reached the limit > > other than that looks good to me OK, I will add some warning message in the v2 patch. Thanks, Regards, Jiwei > > thanks, > jirka > > >> + >> if (switch_output_size(rec)) >> trigger_hit(&switch_output_trigger); >> >> @@ -1639,6 +1649,33 @@ static int parse_clockid(const struct option *opt, >> const char *str, int unset) >> return -1; >> } >> >> +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) >> @@ -1946,6 +1983,8 @@ static struct option __record_options[] = { >> &nr_cblocks_default, "n", "Use control blocks in >> asynchronous trace writing mode (default: 1, max: 4)", >> record__aio_parse), >> #endif >> +OPT_CALLBACK(0, "output-max-size", &record.output_max_size, >> + "size", "Output file maximum size", parse_output_max_size), >> OPT_END() >> }; >> >> -- >> 2.20.1 >> >
[PATCH v2] perf record: Add support for limit perf output file size
The patch adds a new option to limit the output file size, then based on it, we can create a wrapper of the perf command that uses the option to avoid exhausting the disk space by the unconscious user. Signed-off-by: Jiwei Sun --- v2 changes: - make patch based on latest Arnaldo's perf/core, - display warning message when reached the limit. --- tools/perf/builtin-record.c | 42 + 1 file changed, 42 insertions(+) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 6c3719ac901d..dc3648c0816d 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -83,6 +83,7 @@ struct record { struct switch_outputswitch_output; unsigned long long samples; cpu_set_t affinity_mask; + unsigned long output_max_size;/* = 0: unlimited */ }; static volatile int auxtrace_record__snapshot_started; @@ -112,6 +113,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 perf_mmap *map __maybe_unused, void *bf, size_t size) { @@ -124,6 +131,12 @@ static int record__write(struct record *rec, struct perf_mmap *map __maybe_unuse rec->bytes_written += size; + if (record__output_max_size_exceeded(rec)) { + pr_warning("WARNING: The perf data has already reached " + "the limit, stop recording!\n"); + raise(SIGTERM); + } + if (switch_output_size(rec)) trigger_hit(&switch_output_trigger); @@ -1671,6 +1684,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) @@ -1982,6 +2022,8 @@ static struct option __record_options[] = { OPT_CALLBACK(0, "affinity", &record.opts, "node|cpu", "Set affinity mask of trace reading thread to NUMA node cpu mask or cpu of processed mmap buffer", record__parse_affinity), + OPT_CALLBACK(0, "output-max-size", &record.output_max_size, +"size", "Output file maximum size", parse_output_max_size), OPT_END() }; -- 2.20.1
Re: [PATCH v2] perf record: Add support for limit perf output file size
Hi Arnaldo, On 02/22/2019 10:53 PM, Arnaldo Carvalho de Melo wrote: > Em Fri, Feb 22, 2019 at 03:19:04PM +0800, Jiwei Sun escreveu: >> The patch adds a new option to limit the output file size, then based >> on it, we can create a wrapper of the perf command that uses the option >> to avoid exhausting the disk space by the unconscious user. >> >> Signed-off-by: Jiwei Sun >> --- >> v2 changes: > > Please do a v3 adding this new option to > tools/perf/Documentation/perf-record.txt > > Please also rename it to --max-size-output, because then we coudl use: > > perf record --max-size-output > > or: > > perf record --max-size > > or even: > > perf record --max saving typing :-) > > Also please show it in use, i.e. the output of it working. Thanks for your advice, I will modify the patch and send a v3. Thanks, Regards, Jiwei > > > - Arnaldo > >> - make patch based on latest Arnaldo's perf/core, >> - display warning message when reached the limit. >> --- >> tools/perf/builtin-record.c | 42 + >> 1 file changed, 42 insertions(+) >> >> diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c >> index 6c3719ac901d..dc3648c0816d 100644 >> --- a/tools/perf/builtin-record.c >> +++ b/tools/perf/builtin-record.c >> @@ -83,6 +83,7 @@ struct record { >> struct switch_outputswitch_output; >> unsigned long long samples; >> cpu_set_t affinity_mask; >> +unsigned long output_max_size;/* = 0: unlimited */ >> }; >> >> static volatile int auxtrace_record__snapshot_started; >> @@ -112,6 +113,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 perf_mmap *map >> __maybe_unused, >> void *bf, size_t size) >> { >> @@ -124,6 +131,12 @@ static int record__write(struct record *rec, struct >> perf_mmap *map __maybe_unuse >> >> rec->bytes_written += size; >> >> +if (record__output_max_size_exceeded(rec)) { >> +pr_warning("WARNING: The perf data has already reached " >> + "the limit, stop recording!\n"); >> +raise(SIGTERM); >> +} >> + >> if (switch_output_size(rec)) >> trigger_hit(&switch_output_trigger); >> >> @@ -1671,6 +1684,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) >> @@ -1982,6 +2022,8 @@ static struct option __record_options[] = { >> OPT_CALLBACK(0, "affinity", &record.opts, "node|cpu", >> "Set affinity mask of trace reading thread to NUMA node >> cpu mask or cpu of processed mmap buffer", >> record__parse_affinity), >> +OPT_CALLBACK(0, "output-max-size", &record.output_max_size, >> + "size", "Output file maximum size", parse_output_max_size), >> OPT_END() >> }; >> >> -- >> 2.20.1 >
[PATCH] rtc: adjust the next alarm expiring time to avoid a softlockups.
cted stalls on CPUs/tasks: [ 29.934096] 2-: (20935 ticks this GP) idle=f4a/1/4611686018427387904 softirq=754/754 fqs=4704 [ 29.934096] (detected by 3, t=21019 jiffies, g=55, c=54, q=42) [ 29.934096] Sending NMI from CPU 3 to CPUs 2: [ 29.948423] NMI backtrace for cpu 2 [ 29.948423] CPU: 2 PID: 49 Comm: kworker/2:1 Not tainted 4.16.0 #5 [ 29.948423] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011 [ 29.952553] Workqueue: events rtc_timer_do_work [ 29.952553] RIP: 0010:__wake_up_common+0x0/0x120 [ 29.952553] RSP: 0018:9db0801abcf0 EFLAGS: 0046 [ 29.952553] RAX: 0292 RBX: 8dfb869feb88 RCX: [ 29.952553] RDX: 0001 RSI: 0001 RDI: 8dfb869feb88 [ 29.952553] RBP: 0001 R08: R09: 9db0801abcf8 [ 29.952553] R10: 0010 R11: 0001 R12: 0292 [ 29.952553] R13: 0001 R14: R15: [ 29.952553] FS: () GS:8dfb87d0() knlGS: [ 29.952553] CS: 0010 DS: ES: CR0: 80050033 [ 29.952553] CR2: 7fff0ee7a9f0 CR3: 062b2000 CR4: 06e0 [ 29.952553] DR0: DR1: DR2: [ 29.952553] DR3: DR6: DR7: [ 29.952553] Call Trace: [ 29.952553] __wake_up_common_lock+0x65/0x90 [ 29.952553] rtc_handle_legacy_irq+0x91/0xb0 [ 29.952553] rtc_timer_do_work+0xcc/0x200 [ 29.952553] process_one_work+0x136/0x330 [ 29.952553] worker_thread+0x3f/0x3b0 [ 29.952553] kthread+0xf0/0x130 [ 29.952553] ? process_one_work+0x330/0x330 [ 29.952553] ? kthread_bind+0x10/0x10 [ 29.952553] ? call_usermodehelper_exec_async+0x10f/0x110 [ 29.952553] ret_from_fork+0x35/0x40 [ 29.952553] Code: 90 90 90 90 90 90 90 90 90 90 90 48 8d 47 08 c7 07 00 00 00 00 48 89 47 08 48 89 47 10 c3 66 66 66 66 2e 0f 1f 84 00 00 00 00 00 <41> 57 41 56 4d 89 c6 41 55 41 54 55 4c 89 cd 53 48 83 ec 10 4d [ 29.952553] INFO: NMI handler (nmi_cpu_backtrace_handler) took too long to run: 6.037 msecs The root cause is as following. When the hardware clock's time is modified later than the periodic alarm clock's expire time, the rtc_timer_do_work's loop may spend a long time to process. In order to avoid the case, we can adjust the next expire time to equating to "now + period". Signed-off-by: Jiwei Sun --- drivers/rtc/interface.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index 672b192..d76eceb 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -877,6 +877,9 @@ void rtc_timer_do_work(struct work_struct *work) /* Re-add/fwd periodic timers */ if (ktime_to_ns(timer->period)) { + if (now - next->expires > timer->period) + timer->node.expires = now; + timer->node.expires = ktime_add(timer->node.expires, timer->period); timer->enabled = 1; -- 1.9.1
Re: [PATCH] MIPS: reset all task's asid to 0 after asid_cache(cpu) overflows
On 03/06/2017 04:34 PM, Sergei Shtylyov wrote: > On 3/6/2017 10:21 AM, jsun4 wrote: > >>>> If asid_cache(cpu) overflows, there may be two tasks with the same >>>> asid. It is a risk that the two different tasks may have the same >>>> address space. >>>> >>>> A process will update its asid to newer version only when switch_mm() >>>> is called and matches the following condition: >>>> if ((cpu_context(cpu, next) ^ asid_cache(cpu)) >>>> & asid_version_mask(cpu)) >>>> get_new_mmu_context(next, cpu); >>>> If asid_cache(cpu) overflows, cpu_context(cpu,next) and asid_cache(cpu) >>>> will be reset to asid_first_version(cpu), and start a new cycle. It >>>> can result in two tasks that have the same ASID in the process list. >>>> >>>> For example, in CONFIG_CPU_MIPS32_R2, task named A's asid on CPU1 is >>>> 0x100, and has been sleeping and been not scheduled. After a long period >>>> of time, another running task named B's asid on CPU1 is 0x, and >>>> asid cached in the CPU1 is 0x too, next task named C is forked, >>>> when schedule from B to C on CPU1, asid_cache(cpu) will overflow, so C's >>>> asid on CPU1 will be 0x100 according to get_new_mmu_context(). A's asid >>>> is the same as C, if now A is rescheduled on CPU1, A's asid is not able >>>> to renew according to 'if' clause, and the local TLB entry can't be >>>> flushed too, A's address space will be the same as C. >>>> >>>> If asid_cache(cpu) overflows, all of user space task's asid on this CPU >>>> are able to set a invalid value (such as 0), it will avoid the risk. >>>> >>>> Signed-off-by: Jiwei Sun >>>> --- >>>> arch/mips/include/asm/mmu_context.h | 9 - >>>> 1 file changed, 8 insertions(+), 1 deletion(-) >>>> >>>> diff --git a/arch/mips/include/asm/mmu_context.h >>>> b/arch/mips/include/asm/mmu_context.h >>>> index ddd57ad..1f60efc 100644 >>>> --- a/arch/mips/include/asm/mmu_context.h >>>> +++ b/arch/mips/include/asm/mmu_context.h >>>> @@ -108,8 +108,15 @@ static inline void enter_lazy_tlb(struct mm_struct >>>> *mm, struct task_struct *tsk) >>>> #else >>>> local_flush_tlb_all();/* start new asid cycle */ >>>> #endif >>>> -if (!asid)/* fix version if needed */ >>>> +if (!asid) {/* fix version if needed */ >>>> +struct task_struct *p; >>>> + >>>> +for_each_process(p) { >>>> +if ((p->mm)) >>> >>>Why double parens? >> >> At the beginning, the code was written as following >> if ((p->mm) && (p->mm != mm)) >> cpu_context(cpu, p->mm) = 0; >> >> Because cpu_context(cpu,mm) will be changed to asid_first_version(cpu) after >> 'for' loop, >> and in order to improve the efficiency of the loop, I deleted "&& (p->mm != >> mm)", >> but I forgot to delete the redundant parentheses. > >Note that parens around 'p->mm' were never needed. And neither around the > right operand of &&. You are right, I will pay attention to similar problems next time. Thanks for your reminder. Best regards, Jiwei > >> Thanks, >> Best regards, >> Jiwei > > MBR, Sergei >
[PATCH] MIPS: reset all task's asid to 0 after asid_cache(cpu) overflows
If asid_cache(cpu) overflows, there may be two tasks with the same asid. It is a risk that the two different tasks may have the same address space. A process will update its asid to newer version only when switch_mm() is called and matches the following condition: if ((cpu_context(cpu, next) ^ asid_cache(cpu)) & asid_version_mask(cpu)) get_new_mmu_context(next, cpu); If asid_cache(cpu) overflows, cpu_context(cpu,next) and asid_cache(cpu) will be reset to asid_first_version(cpu), and start a new cycle. It can result in two tasks that have the same ASID in the process list. For example, in CONFIG_CPU_MIPS32_R2, task named A's asid on CPU1 is 0x100, and has been sleeping and been not scheduled. After a long period of time, another running task named B's asid on CPU1 is 0x, and asid cached in the CPU1 is 0x too, next task named C is forked, when schedule from B to C on CPU1, asid_cache(cpu) will overflow, so C's asid on CPU1 will be 0x100 according to get_new_mmu_context(). A's asid is the same as C, if now A is rescheduled on CPU1, A's asid is not able to renew according to 'if' clause, and the local TLB entry can't be flushed too, A's address space will be the same as C. If asid_cache(cpu) overflows, all of user space task's asid on this CPU are able to set a invalid value (such as 0), it will avoid the risk. Signed-off-by: Jiwei Sun --- arch/mips/include/asm/mmu_context.h | 9 - 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/mips/include/asm/mmu_context.h b/arch/mips/include/asm/mmu_context.h index ddd57ad..1f60efc 100644 --- a/arch/mips/include/asm/mmu_context.h +++ b/arch/mips/include/asm/mmu_context.h @@ -108,8 +108,15 @@ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) #else local_flush_tlb_all(); /* start new asid cycle */ #endif - if (!asid) /* fix version if needed */ + if (!asid) {/* fix version if needed */ + struct task_struct *p; + + for_each_process(p) { + if ((p->mm)) + cpu_context(cpu, p->mm) = 0; + } asid = asid_first_version(cpu); + } } cpu_context(cpu, mm) = asid_cache(cpu) = asid; -- 1.9.1