summaryrefslogtreecommitdiff
path: root/cmd/ioworkload
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-05-30 10:49:46 +0300
committerPaul Buetow <paul@buetow.org>2026-05-30 10:49:46 +0300
commitee3a7106a724dc193589ab652ef21503ba291562 (patch)
tree4d5d0f2b75e085880f7f560de1546337aa2c14ce /cmd/ioworkload
parent5e334d33b3ddc3e308455262577c461835939bc7 (diff)
fix(sleep): record sentinel for TIMER_ABSTIME clock_nanosleep (a20)
clock_nanosleep with the TIMER_ABSTIME flag passes an ABSOLUTE wakeup time in the request timespec, not a relative duration. The generated BPF sleep handler computed requested_ns = tv_sec*1e9 + tv_nsec unconditionally, so absolute sleeps exported a bogus multi-decade "sleep duration" in CSV/parquet/stream. generateExtraSleep now carries an optional flags-argument expression per sleep syscall. For clock_nanosleep the generated handler checks args[1] & TIMER_ABSTIME (value 1) and only computes the relative duration when the flag is clear; absolute sleeps keep the existing -1 sentinel (same value used for null/unreadable timespec pointers). nanosleep is always relative and stays unconditional (no flags arg). - Regenerated internal/c/generated_tracepoints.c (mage generate idempotent). - Added codegen tests asserting the TIMER_ABSTIME guard for clock_nanosleep and its absence for nanosleep. - Extended the ioworkload sleep scenario to issue an absolute clock_nanosleep and the sleep parquet integration test to assert it is reported as -1. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Diffstat (limited to 'cmd/ioworkload')
-rw-r--r--cmd/ioworkload/scenario_sleep.go34
1 files changed, 32 insertions, 2 deletions
diff --git a/cmd/ioworkload/scenario_sleep.go b/cmd/ioworkload/scenario_sleep.go
index bb6c5a4..c004c4b 100644
--- a/cmd/ioworkload/scenario_sleep.go
+++ b/cmd/ioworkload/scenario_sleep.go
@@ -21,17 +21,47 @@ func sleepSyscalls() error {
if err := callClockNanosleep(3_000_000); err != nil {
return err
}
+ // Also exercise the TIMER_ABSTIME (absolute) path so the tracer's
+ // absolute-sleep handling is covered: the request timespec here is an
+ // absolute CLOCK_MONOTONIC wakeup time, not a relative duration, so the
+ // tracer must NOT report it as a sleep duration (see task a20).
+ if err := callClockNanosleepAbs(2_000_000); err != nil {
+ return err
+ }
}
return nil
}
+// callClockNanosleep issues a relative clock_nanosleep (flags = 0), sleeping for
+// requestedNs nanoseconds.
func callClockNanosleep(requestedNs int64) error {
req := unix.Timespec{Sec: requestedNs / 1_000_000_000, Nsec: requestedNs % 1_000_000_000}
+ return invokeClockNanosleep(0, &req)
+}
+
+// callClockNanosleepAbs issues an absolute clock_nanosleep (flags =
+// TIMER_ABSTIME). The request timespec is an absolute CLOCK_MONOTONIC wakeup
+// time computed as "now + aheadNs", so the call blocks for roughly aheadNs but
+// the request value itself is a multi-decade absolute timestamp, not a
+// duration.
+func callClockNanosleepAbs(aheadNs int64) error {
+ var now unix.Timespec
+ if err := unix.ClockGettime(unix.CLOCK_MONOTONIC, &now); err != nil {
+ return fmt.Errorf("clock_gettime: %w", err)
+ }
+ target := now.Nano() + aheadNs
+ req := unix.Timespec{Sec: target / 1_000_000_000, Nsec: target % 1_000_000_000}
+ return invokeClockNanosleep(unix.TIMER_ABSTIME, &req)
+}
+
+// invokeClockNanosleep is the shared raw clock_nanosleep syscall wrapper used by
+// both the relative and absolute callers.
+func invokeClockNanosleep(flags uintptr, req *unix.Timespec) error {
_, _, errno := syscall.RawSyscall6(
unix.SYS_CLOCK_NANOSLEEP,
uintptr(unix.CLOCK_MONOTONIC),
- 0,
- uintptr(unsafe.Pointer(&req)),
+ flags,
+ uintptr(unsafe.Pointer(req)),
0,
0,
0,