From nobody Fri Jun 19 07:59:59 2026 Received: from mail-qk1-f180.google.com (mail-qk1-f180.google.com [209.85.222.180]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id F0313224F3 for ; Sun, 26 Apr 2026 18:28:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=209.85.222.180 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777228112; cv=pass; b=mt2xgP1zm8FbX/tgEdFRsYDbDuTcIwYcgsdF856oibfPH4RisOFdq5od1Pei4QCoch37Qv0vW/T+8QYnmV9qmO8Zp0++FBC9Pg2yA12ELEwt1l5FZEhqDQLm+3wroFz5Odql1vsClo/+9RDWz202fjEX+El/rIaVOimTTCZOilw= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777228112; c=relaxed/simple; bh=bZxa5rYplJEHw4K1VezKxprhBb/qoyZ5XgwwH46y188=; h=MIME-Version:From:Date:Message-ID:Subject:To:Content-Type; b=eLy0YUYj/lF5OvIbtaJEG+ModHBBfJGpASu059Y4J6BeblHLD0pXnGmoODgN6cYgb6M4ErdIlLDmYb4p8gOtKxKUWEbs3CtZvQoSH59n9UuPJDt2kFNkBvZ/sZzUwgTJy9jeGdK4Pu/2LEbMWL9UUCDre+F8BMDUMlkcRqY1RH4= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=r+WadnQS; arc=pass smtp.client-ip=209.85.222.180 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="r+WadnQS" Received: by mail-qk1-f180.google.com with SMTP id af79cd13be357-8f15e900586so164436785a.1 for ; Sun, 26 Apr 2026 11:28:30 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1777228110; cv=none; d=google.com; s=arc-20240605; b=I+sdvRIrLyoweWtTGGIGjlkvjOS1EusC8eguKfGH4DRW6tFri6ERONt5pFsArbE6OD lPDCUNSskDJOgak43rIZjTHFlCgAkpC3EC9u4BPR7xDzM+iLMG4kkNqnMaf3GtSy86Oz G9cQ9bD+JIZSXbELEfxi1jkrNnCW3hVggu7X4Ml2ZT7ktJxvLitzgDhOnzWUaOeo8yKg i4/NRTIL0W7OE/QtfjE7Wjf0eVPqKCFzTIj0r7FLSOaupgFUT5S5ji/sH0G09fBnCrJe UzgQFOHcaxvwruT3zJUHlmrWg1GWDJGBYZe3J3g70WENjN1kMafLwvx4wnERdyXN/qYj 7fXg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=to:subject:message-id:date:from:mime-version:dkim-signature; bh=+H1DGKeH8lW96puZlUUqlUfBLwewfnuo31EhIuV813U=; fh=l8KZoeQC9ZSX3nO6YcNCnrQudn0WnCO0YafeZhU/xOU=; b=iQnTPNWTvCKWNAVGH42OS9WZeONsHgObrQLTwZUM4eigBy8BpAMs9Iio6LhbyI0QJA QJKYhM7FP2jFC6AwMnseewJNB49Oafi4F6Z6hOYlvnJG9aY2GwQhzE8V1ZHhhT6wrpGG WFbOD3BRwRZLK/4oFh0+aYomHD6qun4bjRE/d8omG8yP/X7aSMqmtFuzoNkGdZVfrzFZ TzYjRfwjgYl9QbJCAh3O9YV+imrXSRpXWO4Vgw4TiSUBJktM2EVcqt9AqzzCGi+Q0HGD fINV5h2Tn3vbRsPS9fv2Lijx86n67tg5SAvVGzUttdMUF7TEutgX50DvhB2BI0QZG9Mw 4Btw==; darn=vger.kernel.org ARC-Authentication-Results: i=1; mx.google.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1777228110; x=1777832910; darn=vger.kernel.org; h=to:subject:message-id:date:from:mime-version:from:to:cc:subject :date:message-id:reply-to; bh=+H1DGKeH8lW96puZlUUqlUfBLwewfnuo31EhIuV813U=; b=r+WadnQSdhV8USIYUymSGYlKTZ0waraYEMp8lmuNTGACDrx8Tm3jFbWnGyw0jpVMet mzYV5bE9+38PqRCIxEWHa0+NQQODp1rQR460cTxUORP+17lalFGAf00rVuTWo0o7JQOg ld44qYKAWUHgfXWW49tN0pPqGb5FinaJNKWzlJqV7O2YXZHWo4o5jlpvo1/6eb1SztYq vcTXYixwc2g5q1KB6XCExKamX0mrFmNY+6L2DWwS9/n8Ant0qNJeYZpskrWb6CoEOo+E FSlPod+TqWB4yx6RTTSFo/3TklniFpisrvrckMD4aqia3NzV4Ugg7KddWgMn1k58u7KF BnZQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1777228110; x=1777832910; h=to:subject:message-id:date:from:mime-version:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=+H1DGKeH8lW96puZlUUqlUfBLwewfnuo31EhIuV813U=; b=oFow4KXf75NLO50BtamTS4jggDtTakuho1jLwM/y1+GEK1NvKLp8Ssdr6X2bDNOQke EfkfbGqPbyBAWYgiWa991//5CZHP/FnnJyQ4RmJCNWHwtBq8+JyXceid3ZAjqIlmkWYx unUg157NPpblFgGhPagKsGogrTL90v62s9VB+FqLVnraWLXXsgE+aKzk9PzYzZdvJ+RU cZHvf6WXEFFkq2ooDqe/ehssRLB0Qy52IBHAPEcGb6IU8M2+GDsXhO/zKSmJlhycDxb9 bhOqM+l+HXIX7VZvgU1JYuk0ybG8FCPCJey93Xo1YU3gDhSdco9J95p1zIyEexBkJk/E QpEA== X-Forwarded-Encrypted: i=1; AFNElJ9wl5Aoo2F6sN4LQLaKIIcEt3QR9GSQ2JLurU3G0RCauXYWXpM3GHZt4cXkl+UebSH7Vf5DHXob5ZOkTRk=@vger.kernel.org X-Gm-Message-State: AOJu0YzktF0Mjf3N0YVBQClKaCrFkMkge0mX2UJGJ/Pm7QQ1ejV9yoyB Ag3NyPLga1lD58KrdlKaGSYRcg+npoJOa1AQwBB8fbgo7Ggc29BwpuFWYuW8CLxJ7spfc54CbS1 gfK1oirallMO+TS5Zcn2Ep0ZcTf02eHFUuuuf0EU2Bg== X-Gm-Gg: AeBDiet149luM6oe4L1AqvRVBHwn7j0PUTxgURMQSgL0yaIOfYZOq2MH+2dsoLUP1Rp 2hxZ98abLwPu1/yHZMYyerRjqlgRPdorLpZk7IrIKtO1zK1joiUmI5FpM4C1w8ODbP4oVEvJEOk uDiGsg+wIJ1B6xTiuK7D30zmIydAX6fBUc/m0WRma1oByfeD/zCdq2UPGt2mf6qwfiyo9YJfrxi q8cqiXM8sLwHxNdycq1b3C8RN6cnACRafHRfT/dCOUaxFBF/KdHYlbgJ1SCiAMo7yphf2ulGVas WfyDOT3Dvj89qpKNAWybD5RGClUssZ4K+2M1SeT+kZNhcnzayIFWgABHChuUgghRe9UkUyCyBgQ +qtJ1liMUhvAYsmtrmeoULWogj5mVsJZv0OKVcMo7O487wwaGrNIXEO/2cU/twb0JQVg= X-Received: by 2002:ac8:594c:0:b0:50d:9f02:86c7 with SMTP id d75a77b69052e-50e3682ee36mr605333871cf.13.1777228109679; Sun, 26 Apr 2026 11:28:29 -0700 (PDT) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Malcom Gilbert Date: Sun, 26 Apr 2026 13:28:18 -0500 X-Gm-Features: AQROBzDDy5YxLmbGvHKT7On3n4h5TNO028j-V4Da_rCLuvSzxmqvNslAOlOnHoE Message-ID: Subject: [PATCH] perf: add timerfd timeout exit-code handling To: linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Assisted-by: OpenAI:gpt-5.3-codex-spark Signed-off-by: Malcom Gilbert --- 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=3D:: +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 #endif +#ifdef HAVE_TIMERFD_SUPPORT +#include +#endif #include #include #include @@ -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 =3D {}; + int fd; + int pos; + + if (!rec->opts.timeout) + return 0; + + fd =3D 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 =3D rec->opts.timeout; + + if (timerfd_settime(fd, 0, &new_value, NULL) !=3D 0) { + pr_err("Failed to start timeout timer, error: %m\n"); + close(fd); + return -1; + } + + /* Recv all timer expirations in one-shot mode. */ + pos =3D fdarray__add(&thread->pollfd, fd, POLLIN, fdarray_flag__nonfilter= able); + if (pos < 0) { + pr_err("Failed to add timeout timerfd to poll list\n"); + close(fd); + return pos; + } + + rec->timeout_fd =3D fd; + rec->timeout_pos =3D pos; + + return 0; +#endif +} + +static int record__process_timeout_event(struct record *rec) +{ + uint64_t expirations; + int pos =3D rec->timeout_pos; + struct pollfd *timeout_pollfd; + + if (!thread || !thread->pollfd.entries || pos < 0) + return 0; + if (pos >=3D thread->pollfd.nr) + return 0; + + timeout_pollfd =3D &thread->pollfd.entries[pos]; + if (!(timeout_pollfd->revents & POLLIN)) + return 0; + + if (read(rec->timeout_fd, &expirations, sizeof(expirations)) < 0) { + if (errno =3D=3D EAGAIN) + return 0; + pr_err("failed to read timeout timerfd, error: %m\n"); + return -1; + } + (void)expirations; + + rec->timed_out =3D true; + done =3D 1; + + return 0; +} + static void record__sig_exit(void) { if (signr =3D=3D -1) @@ -2438,6 +2515,9 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) float ratio =3D 0; enum evlist_ctl_cmd cmd =3D EVLIST_CTL_CMD_UNSUPPORTED; struct perf_env *env; + rec->timeout_fd =3D -1; + rec->timeout_pos =3D -1; + rec->timed_out =3D 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 =3D 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 =3D record__update_evlist_pollfd_from_thread(rec, rec->evlist, thread= ); if (err) goto out_child; + + err =3D 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 +=3D off_cpu_write(rec->session); + if (rec->timed_out) { + signr =3D -1; + status =3D 124; + } record__read_lost_samples(rec); /* this will be recalculated during process_buildids() */ @@ -3639,6 +3731,8 @@ static struct option __record_options[] =3D { "\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=3Dall", 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