public inbox for linux-perf-users@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] perf: add timerfd timeout exit-code handling
@ 2026-04-26 18:28 Malcom Gilbert
  2026-04-27  5:48 ` Namhyung Kim
  0 siblings, 1 reply; 3+ messages in thread
From: Malcom Gilbert @ 2026-04-26 18:28 UTC (permalink / raw)
  To: linux-perf-users, linux-kernel

Assisted-by: OpenAI:gpt-5.3-codex-spark
Signed-off-by: Malcom Gilbert <malcomgilbert@gmail.com>
---
 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

^ permalink raw reply related	[flat|nested] 3+ messages in thread
[parent not found: <CAJ_TQUz0kNV-pUzrcNM7ou3xjPdOU73z+qBAWmP7GUW2BRvpHA@mail.gmail.com>]

end of thread, other threads:[~2026-04-27  5:48 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-26 18:28 [PATCH] perf: add timerfd timeout exit-code handling Malcom Gilbert
2026-04-27  5:48 ` Namhyung Kim
     [not found] <CAJ_TQUz0kNV-pUzrcNM7ou3xjPdOU73z+qBAWmP7GUW2BRvpHA@mail.gmail.com>
2026-04-26 18:58 ` Ian Rogers

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox