From 25e599231fde71d89bf6186389a3982f830d8f6e Mon Sep 17 00:00:00 2001
From: Nugraha <richiisei@gmail.com>
Date: Thu, 7 Jul 2022 23:23:00 +0700
Subject: [PATCH] all: use constant for sizeof, add bench test

Signed-off-by: Nugraha <richiisei@gmail.com>
---
 hdr_struct.go       |  2 +-
 uring_bench_test.go | 77 +++++++++++++++++++++++++++++++++++++++++++++
 uring_test.go       | 19 +++++++++++
 3 files changed, 97 insertions(+), 1 deletion(-)
 create mode 100644 uring_bench_test.go

diff --git a/hdr_struct.go b/hdr_struct.go
index 7eaafcd..61d73ae 100644
--- a/hdr_struct.go
+++ b/hdr_struct.go
@@ -2,7 +2,7 @@ package gouring
 
 import "unsafe"
 
-var (
+const (
 	SizeofUnsigned   = unsafe.Sizeof(uint32(0))
 	SizeofUint32     = unsafe.Sizeof(uint32(0))
 	SizeofIoUringSqe = unsafe.Sizeof(IoUringSqe{})
diff --git a/uring_bench_test.go b/uring_bench_test.go
new file mode 100644
index 0000000..77af447
--- /dev/null
+++ b/uring_bench_test.go
@@ -0,0 +1,77 @@
+package gouring
+
+import (
+	"context"
+	"syscall"
+	"testing"
+)
+
+func BenchmarkQueueNop(b *testing.B) {
+	type opt struct {
+		name    string
+		entries uint32
+		p       IoUringParams
+	}
+
+	ts := []opt{
+		{"def-256", 256, IoUringParams{Flags: 0}},
+		{"sqpoll-256-4-10000", 256, IoUringParams{Flags: IORING_SETUP_SQPOLL, SqThreadCpu: 8, SqThreadIdle: 10_000}},
+	}
+
+	consumer := func(h *IoUring, ctx context.Context, count int) {
+		var cqe *IoUringCqe
+		var err error
+		for i := 0; i < count; i++ {
+			if ctx.Err() != nil {
+				return
+			}
+			err = h.WaitCQE(&cqe)
+			if err == syscall.EINTR {
+				continue // ignore INTR
+			} else if err != nil {
+				panic(err)
+			}
+			if cqe.Res < 0 {
+				panic(syscall.Errno(-cqe.Res))
+			}
+		}
+	}
+
+	for _, tc := range ts {
+		b.Run(tc.name, func(b *testing.B) {
+			h := testNewIoUringWithParam(b, tc.entries, &tc.p)
+			defer h.Close()
+			var (
+				j         uint32
+				sqe       *IoUringSqe
+				err       error
+				submitted int
+			)
+
+			ctx, cancel := context.WithCancel(context.Background())
+			defer cancel()
+
+			b.ResetTimer()
+			for i := 0; i < b.N; i++ {
+				for j = 0; j < tc.entries; j++ {
+					for {
+						// sqe could be nil if SQ is already full so we spin until we got one
+						sqe = h.GetSQE()
+						if sqe != nil {
+							break
+						}
+					}
+					PrepNop(sqe)
+					sqe.UserData = uint64(i + int(j))
+				}
+				submitted, err = h.Submit()
+				if err != nil {
+					panic(err)
+				}
+				consumer(h, ctx, submitted)
+			}
+			b.StopTimer()
+		})
+
+	}
+}
diff --git a/uring_test.go b/uring_test.go
index 3b2e0d8..44d548c 100644
--- a/uring_test.go
+++ b/uring_test.go
@@ -9,6 +9,25 @@ import (
 	"github.com/stretchr/testify/require"
 )
 
+type genericTestingT interface {
+	assert.TestingT
+	require.TestingT
+}
+
+func testNewIoUring(t genericTestingT, entries uint32, flags uint32) *IoUring {
+	h, err := New(entries, flags)
+	require.NoError(t, err)
+	require.NotNil(t, h)
+	return h
+}
+
+func testNewIoUringWithParam(t genericTestingT, entries uint32, p *IoUringParams) *IoUring {
+	h, err := NewWithParams(entries, p)
+	require.NoError(t, err)
+	require.NotNil(t, h)
+	return h
+}
+
 func TestRingWrapper(t *testing.T) {
 	h := testNewIoUring(t, 256, 0)
 	defer h.Close()