summaryrefslogtreecommitdiff
path: root/integrationtests/cmd/ioworkload/scenario_iouring.go
diff options
context:
space:
mode:
Diffstat (limited to 'integrationtests/cmd/ioworkload/scenario_iouring.go')
-rw-r--r--integrationtests/cmd/ioworkload/scenario_iouring.go129
1 files changed, 129 insertions, 0 deletions
diff --git a/integrationtests/cmd/ioworkload/scenario_iouring.go b/integrationtests/cmd/ioworkload/scenario_iouring.go
new file mode 100644
index 0000000..b1aac4e
--- /dev/null
+++ b/integrationtests/cmd/ioworkload/scenario_iouring.go
@@ -0,0 +1,129 @@
+package main
+
+import (
+ "fmt"
+ "runtime"
+ "syscall"
+ "unsafe"
+)
+
+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
+}
+
+// iouringEnterEbadf calls io_uring_enter on an invalid fd.
+// The syscall fails with EBADF, but ior captures the enter_io_uring_enter tracepoint.
+func iouringEnterEbadf() error {
+ _, _, errno := syscall.Syscall6(
+ sysIoUringEnter,
+ 99999, // invalid fd
+ 0, // to_submit
+ 0, // min_complete
+ 0, // flags
+ 0, // sig
+ 0, // sz
+ )
+ if errno == 0 {
+ return fmt.Errorf("expected EBADF, but io_uring_enter succeeded")
+ }
+ return nil
+}
+
+// iouringRegisterEbadf calls io_uring_register on an invalid fd.
+// The syscall fails with EBADF, but ior captures the enter_io_uring_register tracepoint.
+func iouringRegisterEbadf() error {
+ _, _, errno := syscall.Syscall6(
+ sysIoUringRegister,
+ 99999, // invalid fd
+ ioringRegisterProbe,
+ 0, // arg (NULL)
+ 0, // nr_args
+ 0, 0,
+ )
+ if errno == 0 {
+ return fmt.Errorf("expected EBADF, but io_uring_register succeeded")
+ }
+ 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(&params[0])),
+ 0,
+ )
+ runtime.KeepAlive(params)
+ if errno != 0 {
+ return 0, fmt.Errorf("io_uring_setup: %w", errno)
+ }
+ return int(fd), nil
+}