From: Namhyung Kim <namhyung@kernel.org>
To: Malcom Gilbert <malcomgilbert@gmail.com>
Cc: linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH] perf: add timerfd timeout exit-code handling
Date: Sun, 26 Apr 2026 22:48:09 -0700 [thread overview]
Message-ID: <ae74mZg8HDYGJThA@google.com> (raw)
In-Reply-To: <CAJ_TQUzM+JXDy4xo4TgeWBL7f6QA0muLxQ8kEv_0hRw6NqrmZQ@mail.gmail.com>
Hello,
On Sun, Apr 26, 2026 at 01:28:18PM -0500, Malcom Gilbert wrote:
> Assisted-by: OpenAI:gpt-5.3-codex-spark
> Signed-off-by: Malcom Gilbert <malcomgilbert@gmail.com>
Looks like this patch or your system has a problem with indentation.
Please fix.
Thanks,
Namhyung
> ---
> tools/perf/Documentation/perf-record.txt | 4 +
> tools/perf/builtin-record.c | 94 ++++++++++++++++++++++++
> tools/perf/util/record.h | 1 +
> 3 files changed, 99 insertions(+)
>
> diff --git a/tools/perf/Documentation/perf-record.txt
> b/tools/perf/Documentation/perf-record.txt
> index 178f483140ed..ea48f96fe11a 100644
> --- a/tools/perf/Documentation/perf-record.txt
> +++ b/tools/perf/Documentation/perf-record.txt
> @@ -554,6 +554,10 @@ When processing pre-existing threads
> /proc/XXX/mmap, it may take a long time,
> because the file may be huge. A time out is needed in such cases.
> This option sets the time out limit. The default value is 500 ms.
>
> +--timeout=<seconds>::
> +Stop recording after the given number of seconds.
> +If `perf record` stops from timeout, it exits with status 124.
> +
> --switch-events::
> Record context switch events i.e. events of type PERF_RECORD_SWITCH or
> PERF_RECORD_SWITCH_CPU_WIDE. In some cases (e.g. Intel PT, CoreSight
> or Arm SPE)
> diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
> index 4a5eba498c02..e666d1d475a4 100644
> --- a/tools/perf/builtin-record.c
> +++ b/tools/perf/builtin-record.c
> @@ -71,6 +71,9 @@
> #ifdef HAVE_EVENTFD_SUPPORT
> #include <sys/eventfd.h>
> #endif
> +#ifdef HAVE_TIMERFD_SUPPORT
> +#include <sys/timerfd.h>
> +#endif
> #include <sys/mman.h>
> #include <sys/wait.h>
> #include <sys/types.h>
> @@ -154,6 +157,9 @@ struct pollfd_index_map {
> struct record {
> struct perf_tool tool;
> struct record_opts opts;
> + int timeout_fd;
> + int timeout_pos;
> + bool timed_out;
> u64 bytes_written;
> u64 thread_bytes_written;
> struct perf_data data;
> @@ -721,6 +727,77 @@ static void sigsegv_handler(int sig)
> sighandler_dump_stack(sig);
> }
>
> +static int record__setup_timeout(struct record *rec)
> +{
> +#ifndef HAVE_TIMERFD_SUPPORT
> + pr_err("perf record --timeout is not supported on this platform\n");
> + return -1;
> +#else
> + struct itimerspec new_value = {};
> + int fd;
> + int pos;
> +
> + if (!rec->opts.timeout)
> + return 0;
> +
> + fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
> + if (fd < 0) {
> + pr_err("Failed to create timeout timerfd, error: %m\n");
> + return -1;
> + }
> +
> + new_value.it_value.tv_sec = rec->opts.timeout;
> +
> + if (timerfd_settime(fd, 0, &new_value, NULL) != 0) {
> + pr_err("Failed to start timeout timer, error: %m\n");
> + close(fd);
> + return -1;
> + }
> +
> + /* Recv all timer expirations in one-shot mode. */
> + pos = fdarray__add(&thread->pollfd, fd, POLLIN, fdarray_flag__nonfilterable);
> + if (pos < 0) {
> + pr_err("Failed to add timeout timerfd to poll list\n");
> + close(fd);
> + return pos;
> + }
> +
> + rec->timeout_fd = fd;
> + rec->timeout_pos = pos;
> +
> + return 0;
> +#endif
> +}
> +
> +static int record__process_timeout_event(struct record *rec)
> +{
> + uint64_t expirations;
> + int pos = rec->timeout_pos;
> + struct pollfd *timeout_pollfd;
> +
> + if (!thread || !thread->pollfd.entries || pos < 0)
> + return 0;
> + if (pos >= thread->pollfd.nr)
> + return 0;
> +
> + timeout_pollfd = &thread->pollfd.entries[pos];
> + if (!(timeout_pollfd->revents & POLLIN))
> + return 0;
> +
> + if (read(rec->timeout_fd, &expirations, sizeof(expirations)) < 0) {
> + if (errno == EAGAIN)
> + return 0;
> + pr_err("failed to read timeout timerfd, error: %m\n");
> + return -1;
> + }
> + (void)expirations;
> +
> + rec->timed_out = true;
> + done = 1;
> +
> + return 0;
> +}
> +
> static void record__sig_exit(void)
> {
> if (signr == -1)
> @@ -2438,6 +2515,9 @@ static int __cmd_record(struct record *rec, int
> argc, const char **argv)
> float ratio = 0;
> enum evlist_ctl_cmd cmd = EVLIST_CTL_CMD_UNSUPPORTED;
> struct perf_env *env;
> + rec->timeout_fd = -1;
> + rec->timeout_pos = -1;
> + rec->timed_out = false;
>
> atexit(record__sig_exit);
> signal(SIGCHLD, sig_handler);
> @@ -2647,6 +2727,10 @@ static int __cmd_record(struct record *rec, int
> argc, const char **argv)
> if (rec->off_cpu)
> evlist__enable_evsel(rec->evlist, (char *)OFFCPU_EVENT);
>
> + err = record__setup_timeout(rec);
> + if (err)
> + goto out_child;
> +
> /*
> * Let the child rip
> */
> @@ -2814,6 +2898,10 @@ static int __cmd_record(struct record *rec, int
> argc, const char **argv)
> err = record__update_evlist_pollfd_from_thread(rec, rec->evlist, thread);
> if (err)
> goto out_child;
> +
> + err = record__process_timeout_event(rec);
> + if (err)
> + goto out_child;
> }
>
> if (evlist__ctlfd_process(rec->evlist, &cmd) > 0) {
> @@ -2919,6 +3007,10 @@ static int __cmd_record(struct record *rec, int
> argc, const char **argv)
>
> if (rec->off_cpu)
> rec->bytes_written += off_cpu_write(rec->session);
> + if (rec->timed_out) {
> + signr = -1;
> + status = 124;
> + }
>
> record__read_lost_samples(rec);
> /* this will be recalculated during process_buildids() */
> @@ -3639,6 +3731,8 @@ static struct option __record_options[] = {
> "\t\t\t Optionally send control command completion ('ack\\n')
> to ack-fd descriptor.\n"
> "\t\t\t Alternatively, ctl-fifo / ack-fifo will be opened and
> used as ctl-fd / ack-fd.",
> parse_control_option),
> + OPT_UINTEGER(0, "timeout", &record.opts.timeout,
> + "Stop recording after the given number of seconds"),
> OPT_CALLBACK(0, "synth", &record.opts, "no|all|task|mmap|cgroup",
> "Fine-tune event synthesis: default=all", parse_record_synth_option),
> OPT_STRING_OPTARG_SET(0, "debuginfod", &record.debuginfod.urls,
> diff --git a/tools/perf/util/record.h b/tools/perf/util/record.h
> index 93627c9a7338..576513ed3b60 100644
> --- a/tools/perf/util/record.h
> +++ b/tools/perf/util/record.h
> @@ -80,6 +80,7 @@ struct record_opts {
> int ctl_fd_ack;
> bool ctl_fd_close;
> int synth;
> + unsigned int timeout;
> int threads_spec;
> const char *threads_user_spec;
> u64 off_cpu_thresh_ns;
> --
> 2.43.0
>
>
> Malcom
next prev parent reply other threads:[~2026-04-27 5:48 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-26 18:28 [PATCH] perf: add timerfd timeout exit-code handling Malcom Gilbert
2026-04-27 5:48 ` Namhyung Kim [this message]
[not found] <CAJ_TQUz0kNV-pUzrcNM7ou3xjPdOU73z+qBAWmP7GUW2BRvpHA@mail.gmail.com>
2026-04-26 18:58 ` Ian Rogers
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=ae74mZg8HDYGJThA@google.com \
--to=namhyung@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-perf-users@vger.kernel.org \
--cc=malcomgilbert@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox