diff options
| author | Paul Buetow <paul@buetow.org> | 2026-02-21 19:42:40 +0200 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-02-21 19:42:40 +0200 |
| commit | 5234ae813b60b823bc984ca8862f078ed4fe71a6 (patch) | |
| tree | 6264c667c31c443fe7ecb59b3346fbd713bf2523 /integrationtests/cmd/ioworkload | |
| parent | 4253a94b9bcb03c3c59e37a05ac006e79dfdc8bf (diff) | |
Add io_uring integration tests and workload scenarios
Implement iouring_test.go with tests for io_uring_setup, io_uring_enter,
and io_uring_register tracepoints. Add corresponding workload scenarios
using raw syscalls (425, 426, 427) since Go stdlib doesn't wrap io_uring
on amd64.
- iouring-setup: creates io_uring instance via io_uring_setup(2)
- iouring-enter: creates ring, calls io_uring_enter(2) with zero ops
- iouring-register: creates ring, calls io_uring_register(2) with PROBE
Task #343
Amp-Thread-ID: https://ampcode.com/threads/T-019c8149-2aa6-75fb-88f3-dd6bd3a2b654
Co-authored-by: Amp <amp@ampcode.com>
Diffstat (limited to 'integrationtests/cmd/ioworkload')
| -rw-r--r-- | integrationtests/cmd/ioworkload/scenarios.go | 89 |
1 files changed, 89 insertions, 0 deletions
diff --git a/integrationtests/cmd/ioworkload/scenarios.go b/integrationtests/cmd/ioworkload/scenarios.go index c4583e9..06e202d 100644 --- a/integrationtests/cmd/ioworkload/scenarios.go +++ b/integrationtests/cmd/ioworkload/scenarios.go @@ -54,6 +54,9 @@ var scenarios = map[string]func() error{ "sync-sync-file-range": syncSyncFileRange, "truncate-basic": truncateBasic, "truncate-ftruncate": truncateFtruncate, + "iouring-setup": iouringSetup, + "iouring-enter": iouringEnter, + "iouring-register": iouringRegister, } func makeTempDir(prefix string) (string, func(), error) { @@ -1487,3 +1490,89 @@ func openByHandleAtSyscall(mountFD int, handle []byte, flags int) (int, error) { } return int(fd), nil } + +const ( + sysIoUringSetup = 425 + sysIoUringEnter = 426 + sysIoUringRegister = 427 + + // io_uring_params struct size: 10 x uint32 + io_sqring_offsets(40) + io_cqring_offsets(40) = 120 bytes. + ioUringParamsSize = 120 + + ioringRegisterProbe = 8 // IORING_REGISTER_PROBE +) + +// iouringSetup creates an io_uring instance via io_uring_setup(2) and closes the fd. +func iouringSetup() error { + fd, err := ioUringSetupRing(1) + if err != nil { + return err + } + return syscall.Close(fd) +} + +// iouringEnter creates an io_uring instance, then calls io_uring_enter(2) +// with zero submissions/completions to exercise the enter tracepoint. +func iouringEnter() error { + fd, err := ioUringSetupRing(1) + if err != nil { + return err + } + defer syscall.Close(fd) + + _, _, errno := syscall.Syscall6( + sysIoUringEnter, + uintptr(fd), + 0, // to_submit + 0, // min_complete + 0, // flags + 0, // sig + 0, // sz + ) + if errno != 0 { + return fmt.Errorf("io_uring_enter: %w", errno) + } + return nil +} + +// iouringRegister creates an io_uring instance, then calls io_uring_register(2) +// with IORING_REGISTER_PROBE to exercise the register tracepoint. +func iouringRegister() error { + fd, err := ioUringSetupRing(1) + if err != nil { + return err + } + defer syscall.Close(fd) + + // io_uring_probe header is 16 bytes; we don't need probe_op entries. + var probeBuf [16]byte + _, _, errno := syscall.Syscall6( + sysIoUringRegister, + uintptr(fd), + ioringRegisterProbe, + uintptr(unsafe.Pointer(&probeBuf[0])), + 0, // nr_args (0 ops requested) + 0, 0, + ) + runtime.KeepAlive(probeBuf) + if errno != 0 { + return fmt.Errorf("io_uring_register: %w", errno) + } + return nil +} + +// ioUringSetupRing calls io_uring_setup(2) and returns the ring fd. +func ioUringSetupRing(entries uint32) (int, error) { + var params [ioUringParamsSize]byte + fd, _, errno := syscall.Syscall( + sysIoUringSetup, + uintptr(entries), + uintptr(unsafe.Pointer(¶ms[0])), + 0, + ) + runtime.KeepAlive(params) + if errno != 0 { + return 0, fmt.Errorf("io_uring_setup: %w", errno) + } + return int(fd), nil +} |
