From: Jim Cromie <jim.cromie@gmail.com>
To: igt-dev@lists.freedesktop.org
Cc: Jim Cromie <jim.cromie@gmail.com>, Gemini CLI <gemini-cli@google.com>
Subject: [PATCH] lib: implement systemic timeout scaling via IGT_TIMEOUT_MULTIPLIER
Date: Thu, 19 Feb 2026 11:52:27 -0700 [thread overview]
Message-ID: <20260219185227.1278271-1-jim.cromie@gmail.com> (raw)
IGT contains numerous hardcoded timing assertions and poll timeouts
(e.g., 150ms in kms_sysfs_edid_timing and 1s in prime_busy) that
appear to be tuned for bare-metal execution.
Specifically, DRM-CI testing of DRM_USE_DYNAMIC_DEBUG=y patchset
triggers spurious timeouts, because toggling the static-keys under
numerous drm_*dbg() callsites takes far longer than just changing the
single word under /sys/module/drm/parameters/debug.
So this patch introduces a "Time Dilator" system to globally scale the
suite's sensitivity, making it adjustable to varying environments. It
adds a global igt_timeout_multiplier, automatically initialized from
the IGT_TIMEOUT_MULTIPLIER environment variable via a library
constructor in lib/igt_poll.c.
The system scales timing in two directions:
1. Clock Dilation: igt_nsec_elapsed() is patched to divide actual
elapsed time by the multiplier. This makes internal test logic
perceive time as moving slower, allowing existing assertions to
pass even when wall-clock duration is longer.
2. Wait Scaling: Standard poll() and ppoll() calls are intercepted via
variadic macros and redirected to wrappers that multiply the
requested timeout duration.
I considered 2 different "dilations" for these, to allow separate
tailoring of the 2 timeout flavors, but had no strong basis to do so,
and it felt like "too many knobs". That said, it might be appropriate
to dilate *only* for drm.debug (/sys/module/drm/parameters/debug)
adjustments.
This should allow at least IGT tests to be adjusted for environmental
variations and kernel configurations, without requiring manual source
modifications for every hardcoded constant.
Assisted-by: Gemini CLI <gemini-cli@google.com>
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
---
lib/igt_core.c | 7 +++++--
lib/igt_core.h | 8 ++++++++
lib/igt_poll.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++++
lib/meson.build | 6 ++++--
4 files changed, 67 insertions(+), 4 deletions(-)
create mode 100644 lib/igt_poll.c
diff --git a/lib/igt_core.c b/lib/igt_core.c
index 3ee670a41..8a1a07ff6 100644
--- a/lib/igt_core.c
+++ b/lib/igt_core.c
@@ -748,6 +748,7 @@ error:
uint64_t igt_nsec_elapsed(struct timespec *start)
{
struct timespec now;
+ uint64_t elapsed;
igt_gettime(&now);
if ((start->tv_sec | start->tv_nsec) == 0) {
@@ -755,8 +756,10 @@ uint64_t igt_nsec_elapsed(struct timespec *start)
return 0;
}
- return ((now.tv_nsec - start->tv_nsec) +
- (uint64_t)NSEC_PER_SEC*(now.tv_sec - start->tv_sec));
+ elapsed = ((now.tv_nsec - start->tv_nsec) +
+ (uint64_t)NSEC_PER_SEC*(now.tv_sec - start->tv_sec));
+
+ return elapsed / igt_timeout_multiplier;
}
void __igt_assert_in_outer_scope(void)
diff --git a/lib/igt_core.h b/lib/igt_core.h
index 6845f853c..4538375ff 100644
--- a/lib/igt_core.h
+++ b/lib/igt_core.h
@@ -44,6 +44,7 @@
#include <stdarg.h>
#include <getopt.h>
#include <unistd.h>
+#include <poll.h>
#ifdef __FreeBSD__
#include "igt_freebsd.h"
@@ -53,6 +54,13 @@
#define IGT_LOG_DOMAIN (NULL)
#endif
+extern double igt_timeout_multiplier;
+int igt_poll(struct pollfd *fds, nfds_t nfds, int timeout);
+int igt_ppoll(struct pollfd *fds, nfds_t nfds,
+ const struct timespec *tmo_p, const sigset_t *sigmask);
+#define poll(...) igt_poll(__VA_ARGS__)
+#define ppoll(...) igt_ppoll(__VA_ARGS__)
+
#ifndef STATIC_ANALYSIS_BUILD
#if defined(__clang_analyzer__) || defined(__COVERITY__) || defined(__KLOCWORK__)
diff --git a/lib/igt_poll.c b/lib/igt_poll.c
new file mode 100644
index 000000000..d94fc902d
--- /dev/null
+++ b/lib/igt_poll.c
@@ -0,0 +1,50 @@
+#include <poll.h>
+#include <time.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include "igt_core.h"
+
+#undef poll
+#undef ppoll
+
+double igt_timeout_multiplier = 1.0;
+
+static void igt_timeout_multiplier_init(void) __attribute__((constructor));
+static void igt_timeout_multiplier_init(void)
+{
+ const char *env = getenv("IGT_TIMEOUT_MULTIPLIER");
+ if (env) {
+ igt_timeout_multiplier = atof(env);
+ if (igt_timeout_multiplier <= 0.0)
+ igt_timeout_multiplier = 1.0;
+ }
+}
+
+int igt_poll(struct pollfd *fds, nfds_t nfds, int timeout)
+{
+ int old_timeout = timeout;
+
+ if (timeout > 0)
+ timeout = (int)(timeout * igt_timeout_multiplier);
+
+ if (igt_timeout_multiplier != 1.0 && old_timeout > 0)
+ igt_debug("igt_poll: scaling timeout %dms -> %dms\n", old_timeout, timeout);
+
+ return poll(fds, nfds, timeout);
+}
+
+int igt_ppoll(struct pollfd *fds, nfds_t nfds,
+ const struct timespec *tmo_p, const sigset_t *sigmask)
+{
+ struct timespec scaled_tmo;
+
+ if (tmo_p) {
+ uint64_t nsec = (uint64_t)tmo_p->tv_sec * NSEC_PER_SEC + tmo_p->tv_nsec;
+ nsec *= igt_timeout_multiplier;
+ scaled_tmo.tv_sec = nsec / NSEC_PER_SEC;
+ scaled_tmo.tv_nsec = nsec % NSEC_PER_SEC;
+ tmo_p = &scaled_tmo;
+ }
+
+ return ppoll(fds, nfds, tmo_p, sigmask);
+}
diff --git a/lib/meson.build b/lib/meson.build
index ea721ecf7..fb7e83543 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -97,6 +97,7 @@ lib_sources = [
'igt_core.c',
'igt_dir.c',
'igt_draw.c',
+ 'igt_poll.c',
'igt_list.c',
'igt_map.c',
'igt_panel.c',
@@ -328,7 +329,7 @@ lib_igt_chipset = declare_dependency(link_with : lin_igt_chipset_build,
include_directories : inc)
lib_igt_perf_build = static_library('igt_perf',
- ['igt_perf.c'],
+ ['igt_perf.c', 'igt_poll.c'],
include_directories : inc)
lib_igt_perf = declare_dependency(link_with : lib_igt_perf_build,
@@ -347,6 +348,7 @@ lib_igt_device_scan_build = static_library('igt_device_scan',
'igt_tools_stub.c',
'intel_device_info.c',
'intel_cmds_info.c',
+ 'igt_poll.c',
],
dependencies : scan_dep,
include_directories : inc)
@@ -362,7 +364,7 @@ lib_igt_drm_clients = declare_dependency(link_with : lib_igt_drm_clients_build,
include_directories : inc)
lib_igt_drm_fdinfo_build = static_library('igt_drm_fdinfo',
- ['igt_drm_fdinfo.c'],
+ ['igt_drm_fdinfo.c', 'igt_poll.c'],
include_directories : inc)
lib_igt_drm_fdinfo = declare_dependency(link_with : lib_igt_drm_fdinfo_build,
--
2.53.0
next reply other threads:[~2026-02-19 18:52 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-02-19 18:52 Jim Cromie [this message]
2026-02-19 19:47 ` ✓ Xe.CI.BAT: success for lib: implement systemic timeout scaling via IGT_TIMEOUT_MULTIPLIER Patchwork
2026-02-19 20:02 ` ✓ i915.CI.BAT: " Patchwork
2026-02-19 21:48 ` ✗ Xe.CI.FULL: failure " Patchwork
2026-02-20 2:10 ` ✗ i915.CI.Full: " Patchwork
2026-03-16 19:17 ` [PATCH] " Kamil Konieczny
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=20260219185227.1278271-1-jim.cromie@gmail.com \
--to=jim.cromie@gmail.com \
--cc=gemini-cli@google.com \
--cc=igt-dev@lists.freedesktop.org \
/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