From c87f2013c02ab8a4bac092765423220b8bdf0634 Mon Sep 17 00:00:00 2001
From: MastahSenpai <26342994+ii64@users.noreply.github.com>
Date: Mon, 24 Jan 2022 15:19:14 +0700
Subject: [PATCH 01/14] feat(opcode): new opcode on Linux 5.16rc

Signed-off-by: MastahSenpai <26342994+ii64@users.noreply.github.com>
---
 const_value.go      |  7 ++++
 queue/queue.go      | 22 ++++++------
 queue/queue_test.go | 84 +++++++++++++++++++++++++++++++++++++++++++--
 ring_entry.go       | 15 ++++++--
 sysnum.go           | 21 +++++++-----
 5 files changed, 125 insertions(+), 24 deletions(-)

diff --git a/const_value.go b/const_value.go
index 2cc0f2e..0eaa353 100644
--- a/const_value.go
+++ b/const_value.go
@@ -84,6 +84,13 @@ const (
 	IORING_OP_SYMLINKAT
 	IORING_OP_LINKAT
 
+	// 5.16rc
+	IORING_OP_GETDENTS
+	IORING_OP_FSETXATTR
+	IORING_OP_SETXATTR
+	IORING_OP_FGETXATTR
+	IORING_OP_GETXATTR
+
 	/* this goes last, obviously */
 	IORING_OP_LAST
 )
diff --git a/queue/queue.go b/queue/queue.go
index 19538df..9538764 100644
--- a/queue/queue.go
+++ b/queue/queue.go
@@ -63,7 +63,7 @@ func (q *Queue) _getSQEntry() *gouring.SQEntry {
 	head := atomic.LoadUint32(q.sq.Head())
 	next := q.sqeTail + 1
 	if (next - head) <= atomic.LoadUint32(q.sq.RingEntries()) {
-		sqe := q.sq.Get(q.sqeTail & atomic.LoadUint32(q.sq.RingMask()))
+		sqe := q.sq.Get(q.sqeTail & (*q.sq.RingMask()))
 		q.sqeTail = next
 		sqe.Reset()
 		return sqe
@@ -77,7 +77,7 @@ func (q *Queue) GetSQEntry() (sqe *gouring.SQEntry) {
 		if sqe != nil {
 			return
 		}
-		runtime.Gosched()
+		// runtime.Gosched()
 	}
 }
 
@@ -86,23 +86,23 @@ func (q *Queue) sqFallback(d uint32) {
 }
 
 func (q *Queue) sqFlush() uint32 {
+	khead := atomic.LoadUint32(q.sq.Head())
+	ktail := atomic.LoadUint32(q.sq.Tail())
 	if q.sqeHead == q.sqeTail {
-		return atomic.LoadUint32(q.sq.Tail()) - atomic.LoadUint32(q.sq.Head())
+		return ktail - khead
 	}
 
-	ktail := atomic.LoadUint32(q.sq.Tail())
 	for toSubmit := q.sqeTail - q.sqeHead; toSubmit > 0; toSubmit-- {
 		*q.sq.Array().Get(ktail & (*q.sq.RingMask())) = q.sqeHead & (*q.sq.RingMask())
 		ktail++
 		q.sqeHead++
 	}
-
 	atomic.StoreUint32(q.sq.Tail(), ktail)
-	return ktail - *q.sq.Head()
+	return ktail - khead
 }
 
 func (q *Queue) isNeedEnter(flags *uint32) bool {
-	if (q.ring.Params().Features & gouring.IORING_SETUP_SQPOLL) > 0 {
+	if (q.ring.Params().Flags & gouring.IORING_SETUP_SQPOLL) == 0 {
 		return true
 	}
 	if q.sq.IsNeedWakeup() {
@@ -139,9 +139,9 @@ func (q *Queue) SubmitAndWait(waitNr uint) (ret int, err error) {
 //
 
 func (q *Queue) cqPeek() (cqe *gouring.CQEntry) {
-	head := atomic.LoadUint32(q.cq.Head())
-	if head != atomic.LoadUint32(q.cq.Tail()) {
-		cqe = q.cq.Get(head & atomic.LoadUint32(q.cq.RingMask()))
+	khead := atomic.LoadUint32(q.cq.Head())
+	if khead != atomic.LoadUint32(q.cq.Tail()) {
+		cqe = q.cq.Get(khead & atomic.LoadUint32(q.cq.RingMask()))
 	}
 	return
 }
@@ -180,7 +180,7 @@ func (q *Queue) GetCQEntryWait(wait bool, waitNr uint) (cqe *gouring.CQEntry, er
 		}
 
 		if q.sq.IsCQOverflow() {
-			_, err = q.ring.Enter(0, waitNr, gouring.IORING_ENTER_GETEVENTS, nil)
+			_, err = q.ring.Enter(0, 0, gouring.IORING_ENTER_GETEVENTS, nil)
 			if err != nil {
 				return
 			}
diff --git a/queue/queue_test.go b/queue/queue_test.go
index 893698c..a835e94 100644
--- a/queue/queue_test.go
+++ b/queue/queue_test.go
@@ -7,6 +7,7 @@ import (
 	"syscall"
 	"testing"
 	"time"
+	"unsafe"
 
 	"github.com/ii64/gouring"
 	"github.com/stretchr/testify/assert"
@@ -43,7 +44,13 @@ func TestQueue(t *testing.T) {
 
 	// create new queue
 	q := New(ring)
-	defer q.Close()
+	defer func() {
+		err := q.Close()
+		assert.NoError(t, err, "close queue")
+	}()
+
+	//
+
 	go func() {
 		for i, b := range btests {
 			sqe := q.GetSQEntry()
@@ -85,7 +92,12 @@ func TestQueuePolling(t *testing.T) {
 	}()
 
 	q := New(ring)
-	defer q.Close()
+	defer func() {
+		err := q.Close()
+		assert.NoError(t, err, "close queue")
+	}()
+
+	// test data
 
 	var tb = []byte("write me on stdout\n")
 	var tu uint64 = 0xfafa
@@ -117,3 +129,71 @@ func TestQueuePolling(t *testing.T) {
 		t.Fail()
 	}
 }
+
+//
+
+var (
+	Entries = 512
+	ring    *gouring.Ring
+	q       *Queue
+)
+
+func init() {
+	var err error
+	ring, err = gouring.New(uint(Entries), nil)
+	if err != nil {
+		panic(err)
+	}
+	q = New(ring)
+}
+
+func BenchmarkQueueBatchingNOP(b *testing.B) {
+	var sqe *gouring.SQEntry
+	for j := 0; j < b.N; j++ {
+		for i := 0; i < Entries; i++ {
+			sqe = q.GetSQEntry()
+			sqe.Opcode = gouring.IORING_OP_NOP
+			sqe.UserData = uint64(i)
+		}
+		n, err := q.SubmitAndWait(uint(Entries))
+		assert.NoError(b, err, "submit")
+		assert.Equal(b, Entries, n, "submit result entries")
+		for i := 0; i < Entries; i++ {
+			v := uint64(i)
+			cqe, err := q.GetCQEntry(true)
+			assert.NoError(b, err, "cqe wait error")
+			assert.Equal(b, int32(0), cqe.Res)
+			assert.Equal(b, v, cqe.UserData)
+		}
+	}
+}
+
+//
+
+var (
+	_sqe    StructTest
+	_sz_sqe = unsafe.Sizeof(_sqe)
+	_sqe_mm = make([]byte, _sz_sqe)
+
+	m = &StructTest{}
+)
+
+type StructTest = gouring.SQEntry
+
+func BenchmarkSetPtrVal(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		*m = _sqe
+	}
+}
+
+func BenchmarkSetPtrValEmpty(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		*m = StructTest{}
+	}
+}
+
+func BenchmarkSetPtrCpy(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		copy(*(*[]byte)(unsafe.Pointer(m)), _sqe_mm)
+	}
+}
diff --git a/ring_entry.go b/ring_entry.go
index f63c8ad..c47e33f 100644
--- a/ring_entry.go
+++ b/ring_entry.go
@@ -37,7 +37,9 @@ type SQEntry struct {
 
 	splice_fd_in__file_index int32 // union { __s32 splice_fd_in, __u32 file_index }
 
-	pad2 [2]uint64
+	addr3 uint64
+
+	pad2 [1]uint64
 }
 
 func (sqe *SQEntry) Offset() *uint64 {
@@ -84,10 +86,17 @@ func (sqe *SQEntry) FileIndex() *uint32 {
 	return (*uint32)(unsafe.Pointer(&sqe.splice_fd_in__file_index))
 }
 
+func (sqe *SQEntry) Addr3() *uint64 {
+	return (*uint64)(unsafe.Pointer(&sqe.addr3))
+}
+func (sqe *SQEntry) SetAddr3(v interface{}) {
+	*sqe.Addr3() = (uint64)(reflect.ValueOf(v).Pointer())
+}
+
 //
 
 func (sqe *SQEntry) Reset() {
-	*sqe = _sqe
+	*sqe = SQEntry{}
 }
 
 //-- CQEntry
@@ -99,5 +108,5 @@ type CQEntry struct {
 }
 
 func (cqe *CQEntry) Reset() {
-	*cqe = _cqe
+	*cqe = CQEntry{}
 }
diff --git a/sysnum.go b/sysnum.go
index 80f7479..8b0abfb 100644
--- a/sysnum.go
+++ b/sysnum.go
@@ -6,14 +6,14 @@ import (
 )
 
 const (
+	// uring syscall no.
+
 	SYS_IO_URING_SETUP    = 425
 	SYS_IO_URING_ENTER    = 426
 	SYS_IO_URING_REGISTER = 427
 )
 
-//go:linkname errnoErr syscall.errnoErr
-func errnoErr(e syscall.Errno) error
-
+// SQOffsets represents submission queue
 type SQOffsets struct {
 	Head        uint32
 	Tail        uint32
@@ -26,6 +26,7 @@ type SQOffsets struct {
 	Resv2       uint64
 }
 
+// CQOffsets represents completion queue
 type CQOffsets struct {
 	Head        uint32
 	Tail        uint32
@@ -38,6 +39,7 @@ type CQOffsets struct {
 	Resv2       uint64
 }
 
+// IOUringParams io_uring_setup params
 type IOUringParams struct {
 	SQEntries    uint32                // sq_entries
 	CQEntries    uint32                // cq_entries
@@ -54,33 +56,36 @@ type IOUringParams struct {
 }
 
 //go:inline
-func io_uring_setup(entries uint, params *IOUringParams) (fd int, err error) {
+func io_uring_setup(entries uint, params *IOUringParams) (ret int, err error) {
 	r1, _, e1 := syscall.Syscall(SYS_IO_URING_SETUP, uintptr(entries), uintptr(unsafe.Pointer(params)), 0)
-	fd = int(r1)
+	ret = int(r1)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = syscall.Errno(e1)
 	}
 	return
 }
 
+//go:inline
 func io_uring_enter(ringFd int, toSubmit uint, minComplete uint, flags uint, sig *Sigset_t) (ret int, err error) {
 	return io_uring_enter2(ringFd, toSubmit, minComplete, flags, sig, NSIG/8)
 }
 
+//go:inline
 func io_uring_enter2(ringFd int, toSubmit uint, minComplete uint, flags uint, sig *Sigset_t, sz int) (ret int, err error) {
 	r1, _, e1 := syscall.Syscall6(SYS_IO_URING_ENTER, uintptr(ringFd), uintptr(toSubmit), uintptr(minComplete), uintptr(flags), uintptr(unsafe.Pointer(sig)), uintptr(sz))
 	ret = int(r1)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = syscall.Errno(e1)
 	}
 	return
 }
 
+//go:inline
 func io_uring_register(ringFd int, opcode uint /*const*/, arg uintptr, nrArgs uint) (ret int, err error) {
 	r1, _, e1 := syscall.Syscall6(SYS_IO_URING_REGISTER, uintptr(ringFd), uintptr(opcode), arg, uintptr(nrArgs), 0, 0)
 	ret = int(r1)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = syscall.Errno(e1)
 	}
 	return
 }

From 06809873b53ccda93577778c06122948659ba37b Mon Sep 17 00:00:00 2001
From: MastahSenpai <26342994+ii64@users.noreply.github.com>
Date: Tue, 25 Jan 2022 02:24:01 +0700
Subject: [PATCH 02/14] fix: queue sqpoll mode returns zero submission

Signed-off-by: MastahSenpai <26342994+ii64@users.noreply.github.com>
---
 queue/helper.go     |  1 +
 queue/queue.go      |  5 +++-
 queue/queue_test.go | 62 ++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 66 insertions(+), 2 deletions(-)
 create mode 100644 queue/helper.go

diff --git a/queue/helper.go b/queue/helper.go
new file mode 100644
index 0000000..c969bad
--- /dev/null
+++ b/queue/helper.go
@@ -0,0 +1 @@
+package queue
diff --git a/queue/queue.go b/queue/queue.go
index 9538764..fd14a29 100644
--- a/queue/queue.go
+++ b/queue/queue.go
@@ -88,6 +88,8 @@ func (q *Queue) sqFallback(d uint32) {
 func (q *Queue) sqFlush() uint32 {
 	khead := atomic.LoadUint32(q.sq.Head())
 	ktail := atomic.LoadUint32(q.sq.Tail())
+
+	// if sq head equals sq tail
 	if q.sqeHead == q.sqeTail {
 		return ktail - khead
 	}
@@ -106,7 +108,7 @@ func (q *Queue) isNeedEnter(flags *uint32) bool {
 		return true
 	}
 	if q.sq.IsNeedWakeup() {
-		*flags |= gouring.IORING_SQ_NEED_WAKEUP
+		*flags |= gouring.IORING_ENTER_SQ_WAKEUP
 		return true
 	}
 	return false
@@ -125,6 +127,7 @@ func (q *Queue) SubmitAndWait(waitNr uint) (ret int, err error) {
 
 	var flags uint32
 	if !q.isNeedEnter(&flags) || submitted == 0 {
+		ret = int(submitted)
 		return
 	}
 
diff --git a/queue/queue_test.go b/queue/queue_test.go
index a835e94..529d107 100644
--- a/queue/queue_test.go
+++ b/queue/queue_test.go
@@ -26,6 +26,66 @@ func mkdata(i int) []byte {
 	return []byte("queue pls" + strings.Repeat("!", i) + fmt.Sprintf("%d", i) + "\n")
 }
 
+func TestQueueSQPoll(t *testing.T) {
+	ring, err := gouring.New(256, &gouring.IOUringParams{
+		Flags:        gouring.IORING_SETUP_SQPOLL,
+		SQThreadIdle: 70 * 1000,
+	})
+	assert.NoError(t, err, "create ring")
+	defer func() {
+		err := ring.Close()
+		assert.NoError(t, err, "close ring")
+	}()
+
+	N := 64 + 64
+	var wg sync.WaitGroup
+	btests := [][]byte{}
+	for i := 0; i < N; i++ {
+		btests = append(btests, mkdata(i))
+	}
+	wg.Add(N)
+
+	// create new queue
+	q := New(ring)
+	defer func() {
+		err := q.Close()
+		assert.NoError(t, err, "close queue")
+	}()
+
+	//
+
+	go func() {
+		for i, b := range btests {
+			sqe := q.GetSQEntry()
+			sqe.UserData = uint64(i)
+			// sqe.Flags = gouring.IOSQE_IO_DRAIN
+			write(sqe, syscall.Stdout, b)
+			if (i+1)%2 == 0 {
+				n, err := q.Submit()
+				assert.NoError(t, err, "queue submit")
+				// assert.Equal(t, 2, n, "submit count mismatch") // may varies due to kernel thread consumng submission queue process time
+				fmt.Printf("submitted %d\n", n)
+			}
+		}
+	}()
+	go func() {
+		q.Run(true, func(cqe *gouring.CQEntry) (err error) {
+			defer wg.Done()
+			fmt.Printf("cqe: %+#v\n", cqe)
+			assert.Condition(t, func() (success bool) {
+				return cqe.UserData < uint64(len(btests))
+			}, "userdata is set with the btest index")
+			assert.Conditionf(t, func() (success bool) {
+				return len(btests[cqe.UserData]) == int(cqe.Res)
+			}, "OP_WRITE result mismatch: %+#v", cqe)
+
+			return nil
+		})
+	}()
+
+	wg.Wait()
+}
+
 func TestQueue(t *testing.T) {
 	ring, err := gouring.New(256, nil)
 	assert.NoError(t, err, "create ring")
@@ -60,7 +120,7 @@ func TestQueue(t *testing.T) {
 			if (i+1)%2 == 0 {
 				n, err := q.Submit()
 				assert.NoError(t, err, "queue submit")
-				assert.Equal(t, n, 2, "submit count mismatch")
+				assert.Equal(t, 2, n, "submit count mismatch")
 				fmt.Printf("submitted %d\n", n)
 			}
 		}

From 6fb11e879dbea17749c97afe6d9d1796a4b0d7f4 Mon Sep 17 00:00:00 2001
From: MastahSenpai <26342994+ii64@users.noreply.github.com>
Date: Wed, 26 Jan 2022 01:16:08 +0700
Subject: [PATCH 03/14] docs: add graph difference sqpoll

Signed-off-by: MastahSenpai <26342994+ii64@users.noreply.github.com>
---
 README.md           |  28 +-
 assets/nosqpoll.svg | 454 +++++++++++++++++++++++
 assets/sqpoll.svg   | 864 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 1343 insertions(+), 3 deletions(-)
 create mode 100644 assets/nosqpoll.svg
 create mode 100644 assets/sqpoll.svg

diff --git a/README.md b/README.md
index 875a5de..640b286 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,8 @@
 # gouring
 
 
-[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
-[![Go Reference](https://pkg.go.dev/badge/github.com/ii64/gouring.svg)](https://pkg.go.dev/github.com/ii64/gouring)
+[![License: MIT][1]](LICENSE)
+[![Go Reference][2]](https://pkg.go.dev/github.com/ii64/gouring)
 
 Low-level io uring library
 
@@ -75,5 +75,27 @@ if err != nil {
 }
 ```
 
+## Graph
+
+> Check out test script [here](https://gist.github.com/ii64/3a4e8f5c689bb65b2fb9c5f2b1a5904d)
+
+<table><tr><td>
+
+![graph sqpoll][3]
+
+</td><td>
+
+![graph non sqpoll][4]
+
+</td></tr></table>
+
+
+
 ### Referece
-[github.com/iceber/iouring-go](https://github.com/iceber/iouring-go)
\ No newline at end of file
+[github.com/iceber/iouring-go](https://github.com/iceber/iouring-go)
+
+
+[1]: https://img.shields.io/badge/License-MIT-yellow.svg
+[2]: https://pkg.go.dev/badge/github.com/ii64/gouring.svg
+[3]: assets/sqpoll.svg
+[4]: assets/nosqpoll.svg
\ No newline at end of file
diff --git a/assets/nosqpoll.svg b/assets/nosqpoll.svg
new file mode 100644
index 0000000..6dafc97
--- /dev/null
+++ b/assets/nosqpoll.svg
@@ -0,0 +1,454 @@
+<svg width="771pt" height="1023pt" viewBox="5.42577 -3.63378 770.5 1023" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 1019)">
+<title>prf</title>
+<polygon fill="white" stroke="transparent" points="-4,4 -4,-1019 766.5,-1019 766.5,4 -4,4"></polygon>
+<!-- N1 -->
+<g id="node1" class="node">
+<title>N1</title>
+<g id="a_node1"><a xlink:title="main.main (34.23s)">
+<polygon fill="#edd5d5" stroke="#b20000" points="706.5,-928 576.5,-928 576.5,-868 706.5,-868 706.5,-928"></polygon>
+<text text-anchor="middle" x="641.5" y="-914.4" font-family="Times,serif" font-size="12.00">main</text>
+<text text-anchor="middle" x="641.5" y="-901.4" font-family="Times,serif" font-size="12.00">main</text>
+<text text-anchor="middle" x="641.5" y="-888.4" font-family="Times,serif" font-size="12.00">1.29s (3.77%)</text>
+<text text-anchor="middle" x="641.5" y="-875.4" font-family="Times,serif" font-size="12.00">of 34.23s (99.94%)</text>
+</a>
+</g>
+</g>
+<!-- N8 -->
+<g id="node8" class="node">
+<title>N8</title>
+<g id="a_node8"><a xlink:title="github.com/ii64/gouring/queue.(*Queue).GetSQEntry (3.51s)">
+<polygon fill="#ede7e0" stroke="#b28457" points="454,-802 339,-802 339,-734 454,-734 454,-802"></polygon>
+<text text-anchor="middle" x="396.5" y="-789.2" font-family="Times,serif" font-size="11.00">queue</text>
+<text text-anchor="middle" x="396.5" y="-777.2" font-family="Times,serif" font-size="11.00">(*Queue)</text>
+<text text-anchor="middle" x="396.5" y="-765.2" font-family="Times,serif" font-size="11.00">GetSQEntry</text>
+<text text-anchor="middle" x="396.5" y="-753.2" font-family="Times,serif" font-size="11.00">0.38s (1.11%)</text>
+<text text-anchor="middle" x="396.5" y="-741.2" font-family="Times,serif" font-size="11.00">of 3.51s (10.25%)</text>
+</a>
+</g>
+</g>
+<!-- N1&#45;&gt;N8 -->
+<g id="edge11" class="edge">
+<title>N1-&gt;N8</title>
+<g id="a_edge11"><a xlink:title="main.main -> github.com/ii64/gouring/queue.(*Queue).GetSQEntry (3.51s)">
+<path fill="none" stroke="#b28457" d="M576.19,-877.79C554.42,-870.33 530.41,-860.94 509.5,-850 487.14,-838.3 464.19,-822.65 444.87,-808.22"></path>
+<polygon fill="#b28457" stroke="#b28457" points="446.91,-805.37 436.82,-802.12 442.68,-810.95 446.91,-805.37"></polygon>
+</a>
+</g>
+<g id="a_edge11-label"><a xlink:title="main.main -> github.com/ii64/gouring/queue.(*Queue).GetSQEntry (3.51s)">
+<text text-anchor="middle" x="531.5" y="-831.3" font-family="Times,serif" font-size="14.00"> 3.51s</text>
+</a>
+</g>
+</g>
+<!-- N14 -->
+<g id="node14" class="node">
+<title>N14</title>
+<g id="a_node14"><a xlink:title="github.com/ii64/gouring/queue.(*Queue).GetCQEntry (5.63s)">
+<polygon fill="#ede1d9" stroke="#b25d1f" points="571,-797 472,-797 472,-739 571,-739 571,-797"></polygon>
+<text text-anchor="middle" x="521.5" y="-785.8" font-family="Times,serif" font-size="9.00">queue</text>
+<text text-anchor="middle" x="521.5" y="-775.8" font-family="Times,serif" font-size="9.00">(*Queue)</text>
+<text text-anchor="middle" x="521.5" y="-765.8" font-family="Times,serif" font-size="9.00">GetCQEntry</text>
+<text text-anchor="middle" x="521.5" y="-755.8" font-family="Times,serif" font-size="9.00">0.03s (0.088%)</text>
+<text text-anchor="middle" x="521.5" y="-745.8" font-family="Times,serif" font-size="9.00">of 5.63s (16.44%)</text>
+</a>
+</g>
+</g>
+<!-- N1&#45;&gt;N14 -->
+<g id="edge9" class="edge">
+<title>N1-&gt;N14</title>
+<g id="a_edge9"><a xlink:title="main.main -> github.com/ii64/gouring/queue.(*Queue).GetCQEntry (5.63s)">
+<path fill="none" stroke="#b25d1f" d="M602.2,-868C595.37,-862.32 588.53,-856.19 582.5,-850 569.26,-836.4 556.35,-819.88 545.84,-805.32"></path>
+<polygon fill="#b25d1f" stroke="#b25d1f" points="548.59,-803.14 539.95,-797.01 542.88,-807.19 548.59,-803.14"></polygon>
+</a>
+</g>
+<g id="a_edge9-label"><a xlink:title="main.main -> github.com/ii64/gouring/queue.(*Queue).GetCQEntry (5.63s)">
+<text text-anchor="middle" x="610" y="-838.8" font-family="Times,serif" font-size="14.00"> 5.63s</text>
+<text text-anchor="middle" x="610" y="-823.8" font-family="Times,serif" font-size="14.00"> (inline)</text>
+</a>
+</g>
+</g>
+<!-- N15 -->
+<g id="node15" class="node">
+<title>N15</title>
+<g id="a_node15"><a xlink:title="github.com/ii64/gouring/queue.(*Queue).Submit (23.80s)">
+<polygon fill="#edd7d5" stroke="#b21200" points="694,-797 589,-797 589,-739 694,-739 694,-797"></polygon>
+<text text-anchor="middle" x="641.5" y="-785.8" font-family="Times,serif" font-size="9.00">queue</text>
+<text text-anchor="middle" x="641.5" y="-775.8" font-family="Times,serif" font-size="9.00">(*Queue)</text>
+<text text-anchor="middle" x="641.5" y="-765.8" font-family="Times,serif" font-size="9.00">Submit</text>
+<text text-anchor="middle" x="641.5" y="-755.8" font-family="Times,serif" font-size="9.00">0.01s (0.029%)</text>
+<text text-anchor="middle" x="641.5" y="-745.8" font-family="Times,serif" font-size="9.00">of 23.80s (69.49%)</text>
+</a>
+</g>
+</g>
+<!-- N1&#45;&gt;N15 -->
+<g id="edge2" class="edge">
+<title>N1-&gt;N15</title>
+<g id="a_edge2"><a xlink:title="main.main -> github.com/ii64/gouring/queue.(*Queue).Submit (23.80s)">
+<path fill="none" stroke="#b21200" stroke-width="4" d="M641.5,-867.95C641.5,-849.95 641.5,-826.62 641.5,-807.13"></path>
+<polygon fill="#b21200" stroke="#b21200" stroke-width="4" points="645,-807.05 641.5,-797.05 638,-807.05 645,-807.05"></polygon>
+</a>
+</g>
+<g id="a_edge2-label"><a xlink:title="main.main -> github.com/ii64/gouring/queue.(*Queue).Submit (23.80s)">
+<text text-anchor="middle" x="669" y="-838.8" font-family="Times,serif" font-size="14.00"> 23.80s</text>
+<text text-anchor="middle" x="669" y="-823.8" font-family="Times,serif" font-size="14.00"> (inline)</text>
+</a>
+</g>
+</g>
+<!-- N2 -->
+<g id="node2" class="node">
+<title>N2</title>
+<g id="a_node2"><a xlink:title="syscall.Syscall6 (22.68s)">
+<polygon fill="#edd8d5" stroke="#b21400" points="762.5,-112 520.5,-112 520.5,0 762.5,0 762.5,-112"></polygon>
+<text text-anchor="middle" x="641.5" y="-88.8" font-family="Times,serif" font-size="24.00">syscall</text>
+<text text-anchor="middle" x="641.5" y="-62.8" font-family="Times,serif" font-size="24.00">Syscall6</text>
+<text text-anchor="middle" x="641.5" y="-36.8" font-family="Times,serif" font-size="24.00">22.53s (65.78%)</text>
+<text text-anchor="middle" x="641.5" y="-10.8" font-family="Times,serif" font-size="24.00">of 22.68s (66.22%)</text>
+</a>
+</g>
+</g>
+<!-- N3 -->
+<g id="node3" class="node">
+<title>N3</title>
+<g id="a_node3"><a xlink:title="runtime.main (34.23s)">
+<polygon fill="#edd5d5" stroke="#b20000" points="691.5,-1015 591.5,-1015 591.5,-979 691.5,-979 691.5,-1015"></polygon>
+<text text-anchor="middle" x="641.5" y="-1004.1" font-family="Times,serif" font-size="8.00">runtime</text>
+<text text-anchor="middle" x="641.5" y="-995.1" font-family="Times,serif" font-size="8.00">main</text>
+<text text-anchor="middle" x="641.5" y="-986.1" font-family="Times,serif" font-size="8.00">0 of 34.23s (99.94%)</text>
+</a>
+</g>
+</g>
+<!-- N3&#45;&gt;N1 -->
+<g id="edge1" class="edge">
+<title>N3-&gt;N1</title>
+<g id="a_edge1"><a xlink:title="runtime.main -> main.main (34.23s)">
+<path fill="none" stroke="#b20000" stroke-width="5" d="M641.5,-978.66C641.5,-967.54 641.5,-952.64 641.5,-938.73"></path>
+<polygon fill="#b20000" stroke="#b20000" stroke-width="5" points="645.88,-938.37 641.5,-928.37 637.13,-938.37 645.88,-938.37"></polygon>
+</a>
+</g>
+<g id="a_edge1-label"><a xlink:title="runtime.main -> main.main (34.23s)">
+<text text-anchor="middle" x="668" y="-949.8" font-family="Times,serif" font-size="14.00"> 34.23s</text>
+</a>
+</g>
+</g>
+<!-- N4 -->
+<g id="node4" class="node">
+<title>N4</title>
+<g id="a_node4"><a xlink:title="github.com/ii64/gouring/queue.(*Queue).GetCQEntryWait (5.60s)">
+<polygon fill="#ede1d9" stroke="#b25d20" points="573,-683 422,-683 422,-590 573,-590 573,-683"></polygon>
+<text text-anchor="middle" x="497.5" y="-667" font-family="Times,serif" font-size="15.00">queue</text>
+<text text-anchor="middle" x="497.5" y="-650" font-family="Times,serif" font-size="15.00">(*Queue)</text>
+<text text-anchor="middle" x="497.5" y="-633" font-family="Times,serif" font-size="15.00">GetCQEntryWait</text>
+<text text-anchor="middle" x="497.5" y="-616" font-family="Times,serif" font-size="15.00">4.31s (12.58%)</text>
+<text text-anchor="middle" x="497.5" y="-599" font-family="Times,serif" font-size="15.00">of 5.60s (16.35%)</text>
+</a>
+</g>
+</g>
+<!-- N10 -->
+<g id="node10" class="node">
+<title>N10</title>
+<g id="a_node10"><a xlink:title="github.com/ii64/gouring/queue.(*Queue).cqPeek (0.71s)">
+<polygon fill="#edecea" stroke="#b2ac9f" points="221.5,-515.5 127.5,-515.5 127.5,-459.5 221.5,-459.5 221.5,-515.5"></polygon>
+<text text-anchor="middle" x="174.5" y="-502.7" font-family="Times,serif" font-size="11.00">queue</text>
+<text text-anchor="middle" x="174.5" y="-490.7" font-family="Times,serif" font-size="11.00">(*Queue)</text>
+<text text-anchor="middle" x="174.5" y="-478.7" font-family="Times,serif" font-size="11.00">cqPeek</text>
+<text text-anchor="middle" x="174.5" y="-466.7" font-family="Times,serif" font-size="11.00">0.71s (2.07%)</text>
+</a>
+</g>
+</g>
+<!-- N4&#45;&gt;N10 -->
+<g id="edge15" class="edge">
+<title>N4-&gt;N10</title>
+<g id="a_edge15"><a xlink:title="github.com/ii64/gouring/queue.(*Queue).GetCQEntryWait -> github.com/ii64/gouring/queue.(*Queue).cqPeek (0.71s)">
+<path fill="none" stroke="#b2ac9f" d="M421.63,-593.19C418.58,-592.03 415.53,-590.96 412.5,-590 350.61,-570.34 326.59,-598.93 267.5,-572 242.97,-560.82 220.34,-540.82 203.55,-523.2"></path>
+<polygon fill="#b2ac9f" stroke="#b2ac9f" points="206.08,-520.79 196.72,-515.83 200.95,-525.54 206.08,-520.79"></polygon>
+</a>
+</g>
+<g id="a_edge15-label"><a xlink:title="github.com/ii64/gouring/queue.(*Queue).GetCQEntryWait -> github.com/ii64/gouring/queue.(*Queue).cqPeek (0.71s)">
+<text text-anchor="middle" x="295" y="-560.8" font-family="Times,serif" font-size="14.00"> 0.71s</text>
+<text text-anchor="middle" x="295" y="-545.8" font-family="Times,serif" font-size="14.00"> (inline)</text>
+</a>
+</g>
+</g>
+<!-- N11 -->
+<g id="node11" class="node">
+<title>N11</title>
+<g id="a_node11"><a xlink:title="github.com/ii64/gouring/queue.(*Queue).precheck (0.31s)">
+<polygon fill="#edecec" stroke="#b2b0aa" points="323.5,-513.5 239.5,-513.5 239.5,-461.5 323.5,-461.5 323.5,-513.5"></polygon>
+<text text-anchor="middle" x="281.5" y="-501.5" font-family="Times,serif" font-size="10.00">queue</text>
+<text text-anchor="middle" x="281.5" y="-490.5" font-family="Times,serif" font-size="10.00">(*Queue)</text>
+<text text-anchor="middle" x="281.5" y="-479.5" font-family="Times,serif" font-size="10.00">precheck</text>
+<text text-anchor="middle" x="281.5" y="-468.5" font-family="Times,serif" font-size="10.00">0.31s (0.91%)</text>
+</a>
+</g>
+</g>
+<!-- N4&#45;&gt;N11 -->
+<g id="edge16" class="edge">
+<title>N4-&gt;N11</title>
+<g id="a_edge16"><a xlink:title="github.com/ii64/gouring/queue.(*Queue).GetCQEntryWait -> github.com/ii64/gouring/queue.(*Queue).precheck (0.31s)">
+<path fill="none" stroke="#b2b0aa" d="M421.8,-594.19C418.68,-592.73 415.57,-591.33 412.5,-590 389.68,-580.1 380.4,-585.5 359.5,-572 338.88,-558.68 319.97,-538.73 305.93,-521.67"></path>
+<polygon fill="#b2b0aa" stroke="#b2b0aa" points="308.43,-519.18 299.45,-513.56 302.96,-523.56 308.43,-519.18"></polygon>
+</a>
+</g>
+<g id="a_edge16-label"><a xlink:title="github.com/ii64/gouring/queue.(*Queue).GetCQEntryWait -> github.com/ii64/gouring/queue.(*Queue).precheck (0.31s)">
+<text text-anchor="middle" x="387" y="-560.8" font-family="Times,serif" font-size="14.00"> 0.31s</text>
+<text text-anchor="middle" x="387" y="-545.8" font-family="Times,serif" font-size="14.00"> (inline)</text>
+</a>
+</g>
+</g>
+<!-- N12 -->
+<g id="node12" class="node">
+<title>N12</title>
+<g id="a_node12"><a xlink:title="github.com/ii64/gouring/queue.(*Queue).cqAdvance (0.27s)">
+<polygon fill="#edecec" stroke="#b2b0ab" points="438,-519 341,-519 341,-456 438,-456 438,-519"></polygon>
+<text text-anchor="middle" x="389.5" y="-507" font-family="Times,serif" font-size="10.00">queue</text>
+<text text-anchor="middle" x="389.5" y="-496" font-family="Times,serif" font-size="10.00">(*Queue)</text>
+<text text-anchor="middle" x="389.5" y="-485" font-family="Times,serif" font-size="10.00">cqAdvance</text>
+<text text-anchor="middle" x="389.5" y="-474" font-family="Times,serif" font-size="10.00">0.26s (0.76%)</text>
+<text text-anchor="middle" x="389.5" y="-463" font-family="Times,serif" font-size="10.00">of 0.27s (0.79%)</text>
+</a>
+</g>
+</g>
+<!-- N4&#45;&gt;N12 -->
+<g id="edge17" class="edge">
+<title>N4-&gt;N12</title>
+<g id="a_edge17"><a xlink:title="github.com/ii64/gouring/queue.(*Queue).GetCQEntryWait -> github.com/ii64/gouring/queue.(*Queue).cqAdvance (0.27s)">
+<path fill="none" stroke="#b2b0ab" d="M451.11,-589.88C445.96,-584.05 440.97,-578.01 436.5,-572 426.49,-558.53 417.07,-542.7 409.33,-528.47"></path>
+<polygon fill="#b2b0ab" stroke="#b2b0ab" points="412.28,-526.58 404.5,-519.4 406.1,-529.87 412.28,-526.58"></polygon>
+</a>
+</g>
+<g id="a_edge17-label"><a xlink:title="github.com/ii64/gouring/queue.(*Queue).GetCQEntryWait -> github.com/ii64/gouring/queue.(*Queue).cqAdvance (0.27s)">
+<text text-anchor="middle" x="464" y="-560.8" font-family="Times,serif" font-size="14.00"> 0.27s</text>
+<text text-anchor="middle" x="464" y="-545.8" font-family="Times,serif" font-size="14.00"> (inline)</text>
+</a>
+</g>
+</g>
+<!-- N5 -->
+<g id="node5" class="node">
+<title>N5</title>
+<g id="a_node5"><a xlink:title="github.com/ii64/gouring/queue.(*Queue).SubmitAndWait (23.79s)">
+<polygon fill="#edd7d5" stroke="#b21200" points="691.5,-658.5 591.5,-658.5 591.5,-614.5 691.5,-614.5 691.5,-658.5"></polygon>
+<text text-anchor="middle" x="641.5" y="-648.1" font-family="Times,serif" font-size="8.00">queue</text>
+<text text-anchor="middle" x="641.5" y="-639.1" font-family="Times,serif" font-size="8.00">(*Queue)</text>
+<text text-anchor="middle" x="641.5" y="-630.1" font-family="Times,serif" font-size="8.00">SubmitAndWait</text>
+<text text-anchor="middle" x="641.5" y="-621.1" font-family="Times,serif" font-size="8.00">0 of 23.79s (69.46%)</text>
+</a>
+</g>
+</g>
+<!-- N9 -->
+<g id="node9" class="node">
+<title>N9</title>
+<g id="a_node9"><a xlink:title="github.com/ii64/gouring/queue.(*Queue).sqFlush (1.07s)">
+<polygon fill="#edebe9" stroke="#b2a896" points="571,-524 456,-524 456,-451 571,-451 571,-524"></polygon>
+<text text-anchor="middle" x="513.5" y="-510.4" font-family="Times,serif" font-size="12.00">queue</text>
+<text text-anchor="middle" x="513.5" y="-497.4" font-family="Times,serif" font-size="12.00">(*Queue)</text>
+<text text-anchor="middle" x="513.5" y="-484.4" font-family="Times,serif" font-size="12.00">sqFlush</text>
+<text text-anchor="middle" x="513.5" y="-471.4" font-family="Times,serif" font-size="12.00">0.92s (2.69%)</text>
+<text text-anchor="middle" x="513.5" y="-458.4" font-family="Times,serif" font-size="12.00">of 1.07s (3.12%)</text>
+</a>
+</g>
+</g>
+<!-- N5&#45;&gt;N9 -->
+<g id="edge14" class="edge">
+<title>N5-&gt;N9</title>
+<g id="a_edge14"><a xlink:title="github.com/ii64/gouring/queue.(*Queue).SubmitAndWait -> github.com/ii64/gouring/queue.(*Queue).sqFlush (1.07s)">
+<path fill="none" stroke="#b2a896" d="M623.16,-614.44C604.54,-593.05 575.15,-559.3 551.48,-532.12"></path>
+<polygon fill="#b2a896" stroke="#b2a896" points="553.87,-529.53 544.66,-524.28 548.59,-534.12 553.87,-529.53"></polygon>
+</a>
+</g>
+<g id="a_edge14-label"><a xlink:title="github.com/ii64/gouring/queue.(*Queue).SubmitAndWait -> github.com/ii64/gouring/queue.(*Queue).sqFlush (1.07s)">
+<text text-anchor="middle" x="607.5" y="-553.3" font-family="Times,serif" font-size="14.00"> 1.07s</text>
+</a>
+</g>
+</g>
+<!-- N13 -->
+<g id="node13" class="node">
+<title>N13</title>
+<g id="a_node13"><a xlink:title="github.com/ii64/gouring.(*Ring).Enter (22.72s)">
+<polygon fill="#edd8d5" stroke="#b21400" points="694,-516.5 589,-516.5 589,-458.5 694,-458.5 694,-516.5"></polygon>
+<text text-anchor="middle" x="641.5" y="-505.3" font-family="Times,serif" font-size="9.00">gouring</text>
+<text text-anchor="middle" x="641.5" y="-495.3" font-family="Times,serif" font-size="9.00">(*Ring)</text>
+<text text-anchor="middle" x="641.5" y="-485.3" font-family="Times,serif" font-size="9.00">Enter</text>
+<text text-anchor="middle" x="641.5" y="-475.3" font-family="Times,serif" font-size="9.00">0.03s (0.088%)</text>
+<text text-anchor="middle" x="641.5" y="-465.3" font-family="Times,serif" font-size="9.00">of 22.72s (66.34%)</text>
+</a>
+</g>
+</g>
+<!-- N5&#45;&gt;N13 -->
+<g id="edge4" class="edge">
+<title>N5-&gt;N13</title>
+<g id="a_edge4"><a xlink:title="github.com/ii64/gouring/queue.(*Queue).SubmitAndWait -> github.com/ii64/gouring.(*Ring).Enter (22.72s)">
+<path fill="none" stroke="#b21400" stroke-width="4" d="M641.5,-614.44C641.5,-591.63 641.5,-554.77 641.5,-526.8"></path>
+<polygon fill="#b21400" stroke="#b21400" stroke-width="4" points="645,-526.57 641.5,-516.57 638,-526.57 645,-526.57"></polygon>
+</a>
+</g>
+<g id="a_edge4-label"><a xlink:title="github.com/ii64/gouring/queue.(*Queue).SubmitAndWait -> github.com/ii64/gouring.(*Ring).Enter (22.72s)">
+<text text-anchor="middle" x="668" y="-553.3" font-family="Times,serif" font-size="14.00"> 22.72s</text>
+</a>
+</g>
+</g>
+<!-- N6 -->
+<g id="node6" class="node">
+<title>N6</title>
+<g id="a_node6"><a xlink:title="github.com/ii64/gouring/queue.(*Queue)._getSQEntry (3.13s)">
+<polygon fill="#ede7e2" stroke="#b28a60" points="404,-675.5 279,-675.5 279,-597.5 404,-597.5 404,-675.5"></polygon>
+<text text-anchor="middle" x="341.5" y="-661.1" font-family="Times,serif" font-size="13.00">queue</text>
+<text text-anchor="middle" x="341.5" y="-647.1" font-family="Times,serif" font-size="13.00">(*Queue)</text>
+<text text-anchor="middle" x="341.5" y="-633.1" font-family="Times,serif" font-size="13.00">_getSQEntry</text>
+<text text-anchor="middle" x="341.5" y="-619.1" font-family="Times,serif" font-size="13.00">1.68s (4.91%)</text>
+<text text-anchor="middle" x="341.5" y="-605.1" font-family="Times,serif" font-size="13.00">of 3.13s (9.14%)</text>
+</a>
+</g>
+</g>
+<!-- N7 -->
+<g id="node7" class="node">
+<title>N7</title>
+<g id="a_node7"><a xlink:title="github.com/ii64/gouring.(*SQEntry).Reset (1.45s)">
+<polygon fill="#edebe8" stroke="#b2a38c" points="109,-519.5 0,-519.5 0,-455.5 109,-455.5 109,-519.5"></polygon>
+<text text-anchor="middle" x="54.5" y="-505.1" font-family="Times,serif" font-size="13.00">gouring</text>
+<text text-anchor="middle" x="54.5" y="-491.1" font-family="Times,serif" font-size="13.00">(*SQEntry)</text>
+<text text-anchor="middle" x="54.5" y="-477.1" font-family="Times,serif" font-size="13.00">Reset</text>
+<text text-anchor="middle" x="54.5" y="-463.1" font-family="Times,serif" font-size="13.00">1.45s (4.23%)</text>
+</a>
+</g>
+</g>
+<!-- N6&#45;&gt;N7 -->
+<g id="edge13" class="edge">
+<title>N6-&gt;N7</title>
+<g id="a_edge13"><a xlink:title="github.com/ii64/gouring/queue.(*Queue)._getSQEntry -> github.com/ii64/gouring.(*SQEntry).Reset (1.45s)">
+<path fill="none" stroke="#b2a38c" d="M278.83,-630.69C228.64,-624.13 158.59,-608.63 108.5,-572 93.36,-560.93 81.34,-544.21 72.52,-528.63"></path>
+<polygon fill="#b2a38c" stroke="#b2a38c" points="75.51,-526.8 67.7,-519.64 69.34,-530.11 75.51,-526.8"></polygon>
+</a>
+</g>
+<g id="a_edge13-label"><a xlink:title="github.com/ii64/gouring/queue.(*Queue)._getSQEntry -> github.com/ii64/gouring.(*SQEntry).Reset (1.45s)">
+<text text-anchor="middle" x="130.5" y="-553.3" font-family="Times,serif" font-size="14.00"> 1.45s</text>
+</a>
+</g>
+</g>
+<!-- N8&#45;&gt;N6 -->
+<g id="edge12" class="edge">
+<title>N8-&gt;N6</title>
+<g id="a_edge12"><a xlink:title="github.com/ii64/gouring/queue.(*Queue).GetSQEntry -> github.com/ii64/gouring/queue.(*Queue)._getSQEntry (3.13s)">
+<path fill="none" stroke="#b28a60" d="M382.48,-733.99C376.2,-719.2 368.68,-701.49 361.8,-685.29"></path>
+<polygon fill="#b28a60" stroke="#b28a60" points="364.97,-683.8 357.84,-675.97 358.53,-686.54 364.97,-683.8"></polygon>
+</a>
+</g>
+<g id="a_edge12-label"><a xlink:title="github.com/ii64/gouring/queue.(*Queue).GetSQEntry -> github.com/ii64/gouring/queue.(*Queue)._getSQEntry (3.13s)">
+<text text-anchor="middle" x="396.5" y="-704.8" font-family="Times,serif" font-size="14.00"> 3.13s</text>
+</a>
+</g>
+</g>
+<!-- N17 -->
+<g id="node17" class="node">
+<title>N17</title>
+<g id="a_node17"><a xlink:title="github.com/ii64/gouring.enter (22.69s)">
+<polygon fill="#edd8d5" stroke="#b21400" points="691.5,-400 591.5,-400 591.5,-364 691.5,-364 691.5,-400"></polygon>
+<text text-anchor="middle" x="641.5" y="-389.1" font-family="Times,serif" font-size="8.00">gouring</text>
+<text text-anchor="middle" x="641.5" y="-380.1" font-family="Times,serif" font-size="8.00">enter</text>
+<text text-anchor="middle" x="641.5" y="-371.1" font-family="Times,serif" font-size="8.00">0 of 22.69s (66.25%)</text>
+</a>
+</g>
+</g>
+<!-- N13&#45;&gt;N17 -->
+<g id="edge5" class="edge">
+<title>N13-&gt;N17</title>
+<g id="a_edge5"><a xlink:title="github.com/ii64/gouring.(*Ring).Enter -> github.com/ii64/gouring.enter (22.69s)">
+<path fill="none" stroke="#b21400" stroke-width="4" d="M641.5,-458.49C641.5,-443.46 641.5,-425.02 641.5,-410.13"></path>
+<polygon fill="#b21400" stroke="#b21400" stroke-width="4" points="645,-410.01 641.5,-400.01 638,-410.01 645,-410.01"></polygon>
+</a>
+</g>
+<g id="a_edge5-label"><a xlink:title="github.com/ii64/gouring.(*Ring).Enter -> github.com/ii64/gouring.enter (22.69s)">
+<text text-anchor="middle" x="668" y="-421.8" font-family="Times,serif" font-size="14.00"> 22.69s</text>
+</a>
+</g>
+</g>
+<!-- N14&#45;&gt;N4 -->
+<g id="edge10" class="edge">
+<title>N14-&gt;N4</title>
+<g id="a_edge10"><a xlink:title="github.com/ii64/gouring/queue.(*Queue).GetCQEntry -> github.com/ii64/gouring/queue.(*Queue).GetCQEntryWait (5.60s)">
+<path fill="none" stroke="#b25d20" d="M516.29,-738.9C513.82,-725.54 510.76,-709.07 507.84,-693.32"></path>
+<polygon fill="#b25d20" stroke="#b25d20" points="511.22,-692.3 505.95,-683.11 504.33,-693.58 511.22,-692.3"></polygon>
+</a>
+</g>
+<g id="a_edge10-label"><a xlink:title="github.com/ii64/gouring/queue.(*Queue).GetCQEntry -> github.com/ii64/gouring/queue.(*Queue).GetCQEntryWait (5.60s)">
+<text text-anchor="middle" x="534.5" y="-704.8" font-family="Times,serif" font-size="14.00"> 5.60s</text>
+</a>
+</g>
+</g>
+<!-- N15&#45;&gt;N5 -->
+<g id="edge3" class="edge">
+<title>N15-&gt;N5</title>
+<g id="a_edge3"><a xlink:title="github.com/ii64/gouring/queue.(*Queue).Submit -> github.com/ii64/gouring/queue.(*Queue).SubmitAndWait (23.79s)">
+<path fill="none" stroke="#b21200" stroke-width="4" d="M641.5,-738.9C641.5,-718.28 641.5,-690.27 641.5,-668.91"></path>
+<polygon fill="#b21200" stroke="#b21200" stroke-width="4" points="645,-668.73 641.5,-658.73 638,-668.73 645,-668.73"></polygon>
+</a>
+</g>
+<g id="a_edge3-label"><a xlink:title="github.com/ii64/gouring/queue.(*Queue).Submit -> github.com/ii64/gouring/queue.(*Queue).SubmitAndWait (23.79s)">
+<text text-anchor="middle" x="668" y="-704.8" font-family="Times,serif" font-size="14.00"> 23.79s</text>
+</a>
+</g>
+</g>
+<!-- N16 -->
+<g id="node16" class="node">
+<title>N16</title>
+<g id="a_node16"><a xlink:title="github.com/ii64/gouring.io_uring_enter2 (22.69s)">
+<polygon fill="#edd8d5" stroke="#b21400" points="694,-211 589,-211 589,-163 694,-163 694,-211"></polygon>
+<text text-anchor="middle" x="641.5" y="-199.8" font-family="Times,serif" font-size="9.00">gouring</text>
+<text text-anchor="middle" x="641.5" y="-189.8" font-family="Times,serif" font-size="9.00">io_uring_enter2</text>
+<text text-anchor="middle" x="641.5" y="-179.8" font-family="Times,serif" font-size="9.00">0.01s (0.029%)</text>
+<text text-anchor="middle" x="641.5" y="-169.8" font-family="Times,serif" font-size="9.00">of 22.69s (66.25%)</text>
+</a>
+</g>
+</g>
+<!-- N16&#45;&gt;N2 -->
+<g id="edge8" class="edge">
+<title>N16-&gt;N2</title>
+<g id="a_edge8"><a xlink:title="github.com/ii64/gouring.io_uring_enter2 -> syscall.Syscall6 (22.68s)">
+<path fill="none" stroke="#b21400" stroke-width="4" d="M641.5,-162.94C641.5,-151.4 641.5,-136.79 641.5,-122.13"></path>
+<polygon fill="#b21400" stroke="#b21400" stroke-width="4" points="645,-122.02 641.5,-112.02 638,-122.02 645,-122.02"></polygon>
+</a>
+</g>
+<g id="a_edge8-label"><a xlink:title="github.com/ii64/gouring.io_uring_enter2 -> syscall.Syscall6 (22.68s)">
+<text text-anchor="middle" x="668" y="-133.8" font-family="Times,serif" font-size="14.00"> 22.68s</text>
+</a>
+</g>
+</g>
+<!-- N18 -->
+<g id="node18" class="node">
+<title>N18</title>
+<g id="a_node18"><a xlink:title="github.com/ii64/gouring.io_uring_enter (22.69s)">
+<polygon fill="#edd8d5" stroke="#b21400" points="691.5,-298 591.5,-298 591.5,-262 691.5,-262 691.5,-298"></polygon>
+<text text-anchor="middle" x="641.5" y="-287.1" font-family="Times,serif" font-size="8.00">gouring</text>
+<text text-anchor="middle" x="641.5" y="-278.1" font-family="Times,serif" font-size="8.00">io_uring_enter</text>
+<text text-anchor="middle" x="641.5" y="-269.1" font-family="Times,serif" font-size="8.00">0 of 22.69s (66.25%)</text>
+</a>
+</g>
+</g>
+<!-- N17&#45;&gt;N18 -->
+<g id="edge6" class="edge">
+<title>N17-&gt;N18</title>
+<g id="a_edge6"><a xlink:title="github.com/ii64/gouring.enter -> github.com/ii64/gouring.io_uring_enter (22.69s)">
+<path fill="none" stroke="#b21400" stroke-width="4" d="M641.5,-363.58C641.5,-348.38 641.5,-326.07 641.5,-308.46"></path>
+<polygon fill="#b21400" stroke="#b21400" stroke-width="4" points="645,-308.22 641.5,-298.22 638,-308.22 645,-308.22"></polygon>
+</a>
+</g>
+<g id="a_edge6-label"><a xlink:title="github.com/ii64/gouring.enter -> github.com/ii64/gouring.io_uring_enter (22.69s)">
+<text text-anchor="middle" x="669" y="-334.8" font-family="Times,serif" font-size="14.00"> 22.69s</text>
+<text text-anchor="middle" x="669" y="-319.8" font-family="Times,serif" font-size="14.00"> (inline)</text>
+</a>
+</g>
+</g>
+<!-- N18&#45;&gt;N16 -->
+<g id="edge7" class="edge">
+<title>N18-&gt;N16</title>
+<g id="a_edge7"><a xlink:title="github.com/ii64/gouring.io_uring_enter -> github.com/ii64/gouring.io_uring_enter2 (22.69s)">
+<path fill="none" stroke="#b21400" stroke-width="4" d="M641.5,-261.88C641.5,-250.48 641.5,-235.11 641.5,-221.34"></path>
+<polygon fill="#b21400" stroke="#b21400" stroke-width="4" points="645,-221.22 641.5,-211.22 638,-221.22 645,-221.22"></polygon>
+</a>
+</g>
+<g id="a_edge7-label"><a xlink:title="github.com/ii64/gouring.io_uring_enter -> github.com/ii64/gouring.io_uring_enter2 (22.69s)">
+<text text-anchor="middle" x="668" y="-232.8" font-family="Times,serif" font-size="14.00"> 22.69s</text>
+</a>
+</g>
+</g>
+</g>
+</svg>
\ No newline at end of file
diff --git a/assets/sqpoll.svg b/assets/sqpoll.svg
new file mode 100644
index 0000000..79f6fb5
--- /dev/null
+++ b/assets/sqpoll.svg
@@ -0,0 +1,864 @@
+<svg width="1728pt" height="1233pt" viewBox="0.00 0.00 1728.00 1233.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 1229)">
+<title>prf</title>
+<polygon fill="white" stroke="transparent" points="-4,4 -4,-1229 1724,-1229 1724,4 -4,4"></polygon>
+<!-- N1 -->
+<g id="node1" class="node">
+<title>N1</title>
+<g id="a_node1"><a xlink:title="main.main (18.94s)">
+<polygon fill="#eddad5" stroke="#b22600" points="274.5,-1106 68.5,-1106 68.5,-1010 274.5,-1010 274.5,-1106"></polygon>
+<text text-anchor="middle" x="171.5" y="-1086" font-family="Times,serif" font-size="20.00">main</text>
+<text text-anchor="middle" x="171.5" y="-1064" font-family="Times,serif" font-size="20.00">main</text>
+<text text-anchor="middle" x="171.5" y="-1042" font-family="Times,serif" font-size="20.00">2.21s (5.24%)</text>
+<text text-anchor="middle" x="171.5" y="-1020" font-family="Times,serif" font-size="20.00">of 18.94s (44.88%)</text>
+</a>
+</g>
+</g>
+<!-- N8 -->
+<g id="node8" class="node">
+<title>N8</title>
+<g id="a_node8"><a xlink:title="github.com/ii64/gouring/queue.(*Queue).GetSQEntry (8.68s)">
+<polygon fill="#edded5" stroke="#b24300" points="285,-944 58,-944 58,-806 285,-806 285,-944"></polygon>
+<text text-anchor="middle" x="171.5" y="-920.8" font-family="Times,serif" font-size="24.00">queue</text>
+<text text-anchor="middle" x="171.5" y="-894.8" font-family="Times,serif" font-size="24.00">(*Queue)</text>
+<text text-anchor="middle" x="171.5" y="-868.8" font-family="Times,serif" font-size="24.00">GetSQEntry</text>
+<text text-anchor="middle" x="171.5" y="-842.8" font-family="Times,serif" font-size="24.00">4.12s (9.76%)</text>
+<text text-anchor="middle" x="171.5" y="-816.8" font-family="Times,serif" font-size="24.00">of 8.68s (20.57%)</text>
+</a>
+</g>
+</g>
+<!-- N1&#45;&gt;N8 -->
+<g id="edge5" class="edge">
+<title>N1-&gt;N8</title>
+<g id="a_edge5"><a xlink:title="main.main -> github.com/ii64/gouring/queue.(*Queue).GetSQEntry (8.68s)">
+<path fill="none" stroke="#b24300" stroke-width="2" d="M171.5,-1009.92C171.5,-992.96 171.5,-973.33 171.5,-954.43"></path>
+<polygon fill="#b24300" stroke="#b24300" stroke-width="2" points="175,-954.32 171.5,-944.32 168,-954.32 175,-954.32"></polygon>
+</a>
+</g>
+<g id="a_edge5-label"><a xlink:title="main.main -> github.com/ii64/gouring/queue.(*Queue).GetSQEntry (8.68s)">
+<text text-anchor="middle" x="193.5" y="-973.3" font-family="Times,serif" font-size="14.00"> 8.68s</text>
+</a>
+</g>
+</g>
+<!-- N30 -->
+<g id="node30" class="node">
+<title>N30</title>
+<g id="a_node30"><a xlink:title="github.com/ii64/gouring/queue.(*Queue).GetCQEntry (6s)">
+<polygon fill="#ede3dc" stroke="#b26b33" points="391.5,-904 303.5,-904 303.5,-846 391.5,-846 391.5,-904"></polygon>
+<text text-anchor="middle" x="347.5" y="-892.8" font-family="Times,serif" font-size="9.00">queue</text>
+<text text-anchor="middle" x="347.5" y="-882.8" font-family="Times,serif" font-size="9.00">(*Queue)</text>
+<text text-anchor="middle" x="347.5" y="-872.8" font-family="Times,serif" font-size="9.00">GetCQEntry</text>
+<text text-anchor="middle" x="347.5" y="-862.8" font-family="Times,serif" font-size="9.00">0.01s (0.024%)</text>
+<text text-anchor="middle" x="347.5" y="-852.8" font-family="Times,serif" font-size="9.00">of 6s (14.22%)</text>
+</a>
+</g>
+</g>
+<!-- N1&#45;&gt;N30 -->
+<g id="edge7" class="edge">
+<title>N1-&gt;N30</title>
+<g id="a_edge7"><a xlink:title="main.main -> github.com/ii64/gouring/queue.(*Queue).GetCQEntry (6s)">
+<path fill="none" stroke="#b26b33" d="M226.04,-1009.75C247.74,-990.12 272.5,-966.66 293.5,-944 302.64,-934.14 311.96,-922.9 320.23,-912.44"></path>
+<polygon fill="#b26b33" stroke="#b26b33" points="323.22,-914.29 326.61,-904.25 317.7,-909.99 323.22,-914.29"></polygon>
+</a>
+</g>
+<g id="a_edge7-label"><a xlink:title="main.main -> github.com/ii64/gouring/queue.(*Queue).GetCQEntry (6s)">
+<text text-anchor="middle" x="303" y="-980.8" font-family="Times,serif" font-size="14.00"> 6s</text>
+<text text-anchor="middle" x="303" y="-965.8" font-family="Times,serif" font-size="14.00"> (inline)</text>
+</a>
+</g>
+</g>
+<!-- N33 -->
+<g id="node33" class="node">
+<title>N33</title>
+<g id="a_node33"><a xlink:title="github.com/ii64/gouring/queue.(*Queue).Submit (2.05s)">
+<polygon fill="#edeae7" stroke="#b2a187" points="586,-897 497,-897 497,-853 586,-853 586,-897"></polygon>
+<text text-anchor="middle" x="541.5" y="-886.6" font-family="Times,serif" font-size="8.00">queue</text>
+<text text-anchor="middle" x="541.5" y="-877.6" font-family="Times,serif" font-size="8.00">(*Queue)</text>
+<text text-anchor="middle" x="541.5" y="-868.6" font-family="Times,serif" font-size="8.00">Submit</text>
+<text text-anchor="middle" x="541.5" y="-859.6" font-family="Times,serif" font-size="8.00">0 of 2.05s (4.86%)</text>
+</a>
+</g>
+</g>
+<!-- N1&#45;&gt;N33 -->
+<g id="edge20" class="edge">
+<title>N1-&gt;N33</title>
+<g id="a_edge20"><a xlink:title="main.main -> github.com/ii64/gouring/queue.(*Queue).Submit (2.05s)">
+<path fill="none" stroke="#b2a187" d="M274.55,-1018.29C294.64,-1010.07 315.39,-1001.12 334.5,-992 392.69,-964.24 457.11,-927.06 498.38,-902.36"></path>
+<polygon fill="#b2a187" stroke="#b2a187" points="500.31,-905.28 507.08,-897.13 496.71,-899.28 500.31,-905.28"></polygon>
+</a>
+</g>
+<g id="a_edge20-label"><a xlink:title="main.main -> github.com/ii64/gouring/queue.(*Queue).Submit (2.05s)">
+<text text-anchor="middle" x="421" y="-980.8" font-family="Times,serif" font-size="14.00"> 2.05s</text>
+<text text-anchor="middle" x="421" y="-965.8" font-family="Times,serif" font-size="14.00"> (inline)</text>
+</a>
+</g>
+</g>
+<!-- N2 -->
+<g id="node2" class="node">
+<title>N2</title>
+<g id="a_node2"><a xlink:title="runtime.goschedImpl (21.46s)">
+<polygon fill="#edd9d5" stroke="#b22000" points="1335.5,-909 1183.5,-909 1183.5,-841 1335.5,-841 1335.5,-909"></polygon>
+<text text-anchor="middle" x="1259.5" y="-893.8" font-family="Times,serif" font-size="14.00">runtime</text>
+<text text-anchor="middle" x="1259.5" y="-878.8" font-family="Times,serif" font-size="14.00">goschedImpl</text>
+<text text-anchor="middle" x="1259.5" y="-863.8" font-family="Times,serif" font-size="14.00">0.51s (1.21%)</text>
+<text text-anchor="middle" x="1259.5" y="-848.8" font-family="Times,serif" font-size="14.00">of 21.46s (50.85%)</text>
+</a>
+</g>
+</g>
+<!-- N3 -->
+<g id="node3" class="node">
+<title>N3</title>
+<g id="a_node3"><a xlink:title="runtime.schedule (13.81s)">
+<polygon fill="#eddcd5" stroke="#b23200" points="1353.5,-730 1165.5,-730 1165.5,-642 1353.5,-642 1353.5,-730"></polygon>
+<text text-anchor="middle" x="1259.5" y="-711.6" font-family="Times,serif" font-size="18.00">runtime</text>
+<text text-anchor="middle" x="1259.5" y="-691.6" font-family="Times,serif" font-size="18.00">schedule</text>
+<text text-anchor="middle" x="1259.5" y="-671.6" font-family="Times,serif" font-size="18.00">1.51s (3.58%)</text>
+<text text-anchor="middle" x="1259.5" y="-651.6" font-family="Times,serif" font-size="18.00">of 13.81s (32.73%)</text>
+</a>
+</g>
+</g>
+<!-- N2&#45;&gt;N3 -->
+<g id="edge4" class="edge">
+<title>N2-&gt;N3</title>
+<g id="a_edge4"><a xlink:title="runtime.goschedImpl -> runtime.schedule (13.80s)">
+<path fill="none" stroke="#b23200" stroke-width="2" d="M1259.5,-841C1259.5,-813.18 1259.5,-772.85 1259.5,-740.43"></path>
+<polygon fill="#b23200" stroke="#b23200" stroke-width="2" points="1263,-740.22 1259.5,-730.22 1256,-740.22 1263,-740.22"></polygon>
+</a>
+</g>
+<g id="a_edge4-label"><a xlink:title="runtime.goschedImpl -> runtime.schedule (13.80s)">
+<text text-anchor="middle" x="1286" y="-776.8" font-family="Times,serif" font-size="14.00"> 13.80s</text>
+</a>
+</g>
+</g>
+<!-- N7 -->
+<g id="node7" class="node">
+<title>N7</title>
+<g id="a_node7"><a xlink:title="runtime.casgstatus (5.16s)">
+<polygon fill="#ede5de" stroke="#b27845" points="885.5,-387 671.5,-387 671.5,-283 885.5,-283 885.5,-387"></polygon>
+<text text-anchor="middle" x="778.5" y="-365.4" font-family="Times,serif" font-size="22.00">runtime</text>
+<text text-anchor="middle" x="778.5" y="-341.4" font-family="Times,serif" font-size="22.00">casgstatus</text>
+<text text-anchor="middle" x="778.5" y="-317.4" font-family="Times,serif" font-size="22.00">3.11s (7.37%)</text>
+<text text-anchor="middle" x="778.5" y="-293.4" font-family="Times,serif" font-size="22.00">of 5.16s (12.23%)</text>
+</a>
+</g>
+</g>
+<!-- N2&#45;&gt;N7 -->
+<g id="edge15" class="edge">
+<title>N2-&gt;N7</title>
+<g id="a_edge15"><a xlink:title="runtime.goschedImpl -> runtime.casgstatus (2.75s)">
+<path fill="none" stroke="#b29878" d="M1183.06,-845.07C1076.14,-800.14 885.21,-702.64 797.5,-551 770.64,-504.56 767.88,-442.82 770.67,-397.41"></path>
+<polygon fill="#b29878" stroke="#b29878" points="774.16,-397.63 771.38,-387.41 767.18,-397.13 774.16,-397.63"></polygon>
+</a>
+</g>
+<g id="a_edge15-label"><a xlink:title="runtime.goschedImpl -> runtime.casgstatus (2.75s)">
+<text text-anchor="middle" x="848.5" y="-580.3" font-family="Times,serif" font-size="14.00"> 2.75s</text>
+</a>
+</g>
+</g>
+<!-- N16 -->
+<g id="node16" class="node">
+<title>N16</title>
+<g id="a_node16"><a xlink:title="runtime.unlock (3.78s)">
+<polygon fill="#ede7e2" stroke="#b28b62" points="1488,-361 1391,-361 1391,-309 1488,-309 1488,-361"></polygon>
+<text text-anchor="middle" x="1439.5" y="-349" font-family="Times,serif" font-size="10.00">runtime</text>
+<text text-anchor="middle" x="1439.5" y="-338" font-family="Times,serif" font-size="10.00">unlock</text>
+<text text-anchor="middle" x="1439.5" y="-327" font-family="Times,serif" font-size="10.00">0.06s (0.14%)</text>
+<text text-anchor="middle" x="1439.5" y="-316" font-family="Times,serif" font-size="10.00">of 3.78s (8.96%)</text>
+</a>
+</g>
+</g>
+<!-- N2&#45;&gt;N16 -->
+<g id="edge18" class="edge">
+<title>N2-&gt;N16</title>
+<g id="a_edge18"><a xlink:title="runtime.goschedImpl -> runtime.unlock (2.06s)">
+<path fill="none" stroke="#b2a086" d="M1296.12,-840.94C1318.53,-818.75 1345.97,-787.67 1362.5,-755 1431.41,-618.76 1420.6,-571.62 1438.5,-420 1440.37,-404.15 1440.83,-386.5 1440.73,-371.49"></path>
+<polygon fill="#b2a086" stroke="#b2a086" points="1444.23,-371.03 1440.58,-361.08 1437.23,-371.13 1444.23,-371.03"></polygon>
+</a>
+</g>
+<g id="a_edge18-label"><a xlink:title="runtime.goschedImpl -> runtime.unlock (2.06s)">
+<text text-anchor="middle" x="1450" y="-587.8" font-family="Times,serif" font-size="14.00"> 2.06s</text>
+<text text-anchor="middle" x="1450" y="-572.8" font-family="Times,serif" font-size="14.00"> (inline)</text>
+</a>
+</g>
+</g>
+<!-- N19 -->
+<g id="node19" class="node">
+<title>N19</title>
+<g id="a_node19"><a xlink:title="runtime.lock (3.09s)">
+<polygon fill="#ede9e4" stroke="#b29471" points="1617,-353 1528,-353 1528,-317 1617,-317 1617,-353"></polygon>
+<text text-anchor="middle" x="1572.5" y="-342.1" font-family="Times,serif" font-size="8.00">runtime</text>
+<text text-anchor="middle" x="1572.5" y="-333.1" font-family="Times,serif" font-size="8.00">lock</text>
+<text text-anchor="middle" x="1572.5" y="-324.1" font-family="Times,serif" font-size="8.00">0 of 3.09s (7.32%)</text>
+</a>
+</g>
+</g>
+<!-- N2&#45;&gt;N19 -->
+<g id="edge17" class="edge">
+<title>N2-&gt;N19</title>
+<g id="a_edge17"><a xlink:title="runtime.goschedImpl -> runtime.lock (2.06s)">
+<path fill="none" stroke="#b2a086" d="M1308.95,-840.76C1338.74,-818.94 1375.93,-788.34 1402.5,-755 1503.24,-628.57 1551.91,-434.42 1567.09,-363.31"></path>
+<polygon fill="#b2a086" stroke="#b2a086" points="1570.56,-363.86 1569.17,-353.35 1563.7,-362.43 1570.56,-363.86"></polygon>
+</a>
+</g>
+<g id="a_edge17-label"><a xlink:title="runtime.goschedImpl -> runtime.lock (2.06s)">
+<text text-anchor="middle" x="1526.5" y="-580.3" font-family="Times,serif" font-size="14.00"> 2.06s</text>
+</a>
+</g>
+</g>
+<!-- N6 -->
+<g id="node6" class="node">
+<title>N6</title>
+<g id="a_node6"><a xlink:title="runtime.findrunnable (6.46s)">
+<polygon fill="#ede2da" stroke="#b26429" points="1340.5,-534.5 1178.5,-534.5 1178.5,-454.5 1340.5,-454.5 1340.5,-534.5"></polygon>
+<text text-anchor="middle" x="1259.5" y="-517.7" font-family="Times,serif" font-size="16.00">runtime</text>
+<text text-anchor="middle" x="1259.5" y="-499.7" font-family="Times,serif" font-size="16.00">findrunnable</text>
+<text text-anchor="middle" x="1259.5" y="-481.7" font-family="Times,serif" font-size="16.00">1s (2.37%)</text>
+<text text-anchor="middle" x="1259.5" y="-463.7" font-family="Times,serif" font-size="16.00">of 6.46s (15.31%)</text>
+</a>
+</g>
+</g>
+<!-- N3&#45;&gt;N6 -->
+<g id="edge6" class="edge">
+<title>N3-&gt;N6</title>
+<g id="a_edge6"><a xlink:title="runtime.schedule -> runtime.findrunnable (6.46s)">
+<path fill="none" stroke="#b26429" d="M1259.5,-642C1259.5,-613.18 1259.5,-575.15 1259.5,-545.06"></path>
+<polygon fill="#b26429" stroke="#b26429" points="1263,-544.78 1259.5,-534.78 1256,-544.78 1263,-544.78"></polygon>
+</a>
+</g>
+<g id="a_edge6-label"><a xlink:title="runtime.schedule -> runtime.findrunnable (6.46s)">
+<text text-anchor="middle" x="1281.5" y="-580.3" font-family="Times,serif" font-size="14.00"> 6.46s</text>
+</a>
+</g>
+</g>
+<!-- N13 -->
+<g id="node13" class="node">
+<title>N13</title>
+<g id="a_node13"><a xlink:title="runtime.execute (4.68s)">
+<polygon fill="#ede6df" stroke="#b27f4f" points="1000.5,-542.5 806.5,-542.5 806.5,-446.5 1000.5,-446.5 1000.5,-542.5"></polygon>
+<text text-anchor="middle" x="903.5" y="-522.5" font-family="Times,serif" font-size="20.00">runtime</text>
+<text text-anchor="middle" x="903.5" y="-500.5" font-family="Times,serif" font-size="20.00">execute</text>
+<text text-anchor="middle" x="903.5" y="-478.5" font-family="Times,serif" font-size="20.00">2.20s (5.21%)</text>
+<text text-anchor="middle" x="903.5" y="-456.5" font-family="Times,serif" font-size="20.00">of 4.68s (11.09%)</text>
+</a>
+</g>
+</g>
+<!-- N3&#45;&gt;N13 -->
+<g id="edge9" class="edge">
+<title>N3-&gt;N13</title>
+<g id="a_edge9"><a xlink:title="runtime.schedule -> runtime.execute (4.68s)">
+<path fill="none" stroke="#b27f4f" d="M1165.46,-671.84C1107.4,-660.12 1033.71,-638.45 978.5,-599 960.97,-586.47 945.94,-568.56 934.05,-551.14"></path>
+<polygon fill="#b27f4f" stroke="#b27f4f" points="936.89,-549.09 928.46,-542.66 931.04,-552.94 936.89,-549.09"></polygon>
+</a>
+</g>
+<g id="a_edge9-label"><a xlink:title="runtime.schedule -> runtime.execute (4.68s)">
+<text text-anchor="middle" x="1000.5" y="-580.3" font-family="Times,serif" font-size="14.00"> 4.68s</text>
+</a>
+</g>
+</g>
+<!-- N15 -->
+<g id="node15" class="node">
+<title>N15</title>
+<g id="a_node15"><a xlink:title="runtime.checkTimers (2.02s)">
+<polygon fill="#edeae7" stroke="#b2a187" points="1055.5,-375 903.5,-375 903.5,-295 1055.5,-295 1055.5,-375"></polygon>
+<text text-anchor="middle" x="979.5" y="-358.2" font-family="Times,serif" font-size="16.00">runtime</text>
+<text text-anchor="middle" x="979.5" y="-340.2" font-family="Times,serif" font-size="16.00">checkTimers</text>
+<text text-anchor="middle" x="979.5" y="-322.2" font-family="Times,serif" font-size="16.00">0.88s (2.09%)</text>
+<text text-anchor="middle" x="979.5" y="-304.2" font-family="Times,serif" font-size="16.00">of 2.02s (4.79%)</text>
+</a>
+</g>
+</g>
+<!-- N3&#45;&gt;N15 -->
+<g id="edge30" class="edge">
+<title>N3-&gt;N15</title>
+<g id="a_edge30"><a xlink:title="runtime.schedule -> runtime.checkTimers (0.89s)">
+<path fill="none" stroke="#b2ac9f" d="M1165.72,-642C1126.04,-619.74 1082.23,-589.16 1052.5,-551 1042.02,-537.55 1012.37,-444.1 994.24,-384.91"></path>
+<polygon fill="#b2ac9f" stroke="#b2ac9f" points="997.49,-383.55 991.22,-375.01 990.79,-385.59 997.49,-383.55"></polygon>
+</a>
+</g>
+<g id="a_edge30-label"><a xlink:title="runtime.schedule -> runtime.checkTimers (0.89s)">
+<text text-anchor="middle" x="1074.5" y="-490.8" font-family="Times,serif" font-size="14.00"> 0.89s</text>
+</a>
+</g>
+</g>
+<!-- N24 -->
+<g id="node24" class="node">
+<title>N24</title>
+<g id="a_node24"><a xlink:title="runtime.runqget (0.45s)">
+<polygon fill="#edeceb" stroke="#b2b0a8" points="1189.5,-361.5 1073.5,-361.5 1073.5,-308.5 1189.5,-308.5 1189.5,-361.5"></polygon>
+<text text-anchor="middle" x="1131.5" y="-346.3" font-family="Times,serif" font-size="14.00">runtime</text>
+<text text-anchor="middle" x="1131.5" y="-331.3" font-family="Times,serif" font-size="14.00">runqget</text>
+<text text-anchor="middle" x="1131.5" y="-316.3" font-family="Times,serif" font-size="14.00">0.45s (1.07%)</text>
+</a>
+</g>
+</g>
+<!-- N3&#45;&gt;N24 -->
+<g id="edge35" class="edge">
+<title>N3-&gt;N24</title>
+<g id="a_edge35"><a xlink:title="runtime.schedule -> runtime.runqget (0.20s)">
+<path fill="none" stroke="#b2b1ae" d="M1201.55,-641.9C1174,-618.21 1143.27,-586.44 1125.5,-551 1096.17,-492.5 1095.18,-469.45 1106.5,-405 1108.49,-393.66 1112.19,-381.73 1116.14,-371.04"></path>
+<polygon fill="#b2b1ae" stroke="#b2b1ae" points="1119.44,-372.21 1119.8,-361.63 1112.92,-369.68 1119.44,-372.21"></polygon>
+</a>
+</g>
+<g id="a_edge35-label"><a xlink:title="runtime.schedule -> runtime.runqget (0.20s)">
+<text text-anchor="middle" x="1147.5" y="-490.8" font-family="Times,serif" font-size="14.00"> 0.20s</text>
+</a>
+</g>
+</g>
+<!-- N4 -->
+<g id="node4" class="node">
+<title>N4</title>
+<g id="a_node4"><a xlink:title="runtime.mcall (22.18s)">
+<polygon fill="#edd9d5" stroke="#b21f00" points="1335.5,-1225 1183.5,-1225 1183.5,-1157 1335.5,-1157 1335.5,-1225"></polygon>
+<text text-anchor="middle" x="1259.5" y="-1209.8" font-family="Times,serif" font-size="14.00">runtime</text>
+<text text-anchor="middle" x="1259.5" y="-1194.8" font-family="Times,serif" font-size="14.00">mcall</text>
+<text text-anchor="middle" x="1259.5" y="-1179.8" font-family="Times,serif" font-size="14.00">0.41s (0.97%)</text>
+<text text-anchor="middle" x="1259.5" y="-1164.8" font-family="Times,serif" font-size="14.00">of 22.18s (52.56%)</text>
+</a>
+</g>
+</g>
+<!-- N21 -->
+<g id="node21" class="node">
+<title>N21</title>
+<g id="a_node21"><a xlink:title="runtime.gosched_m (21.76s)">
+<polygon fill="#edd9d5" stroke="#b22000" points="1330.5,-1090 1188.5,-1090 1188.5,-1026 1330.5,-1026 1330.5,-1090"></polygon>
+<text text-anchor="middle" x="1259.5" y="-1075.6" font-family="Times,serif" font-size="13.00">runtime</text>
+<text text-anchor="middle" x="1259.5" y="-1061.6" font-family="Times,serif" font-size="13.00">gosched_m</text>
+<text text-anchor="middle" x="1259.5" y="-1047.6" font-family="Times,serif" font-size="13.00">0.30s (0.71%)</text>
+<text text-anchor="middle" x="1259.5" y="-1033.6" font-family="Times,serif" font-size="13.00">of 21.76s (51.56%)</text>
+</a>
+</g>
+</g>
+<!-- N4&#45;&gt;N21 -->
+<g id="edge1" class="edge">
+<title>N4-&gt;N21</title>
+<g id="a_edge1"><a xlink:title="runtime.mcall -> runtime.gosched_m (21.76s)">
+<path fill="none" stroke="#b22000" stroke-width="3" d="M1259.5,-1156.94C1259.5,-1139.76 1259.5,-1118.58 1259.5,-1100.32"></path>
+<polygon fill="#b22000" stroke="#b22000" stroke-width="3" points="1263,-1100.24 1259.5,-1090.24 1256,-1100.24 1263,-1100.24"></polygon>
+</a>
+</g>
+<g id="a_edge1-label"><a xlink:title="runtime.mcall -> runtime.gosched_m (21.76s)">
+<text text-anchor="middle" x="1286" y="-1127.8" font-family="Times,serif" font-size="14.00"> 21.76s</text>
+</a>
+</g>
+</g>
+<!-- N5 -->
+<g id="node5" class="node">
+<title>N5</title>
+<g id="a_node5"><a xlink:title="runtime.main (18.94s)">
+<polygon fill="#eddad5" stroke="#b22600" points="221.5,-1209 121.5,-1209 121.5,-1173 221.5,-1173 221.5,-1209"></polygon>
+<text text-anchor="middle" x="171.5" y="-1198.1" font-family="Times,serif" font-size="8.00">runtime</text>
+<text text-anchor="middle" x="171.5" y="-1189.1" font-family="Times,serif" font-size="8.00">main</text>
+<text text-anchor="middle" x="171.5" y="-1180.1" font-family="Times,serif" font-size="8.00">0 of 18.94s (44.88%)</text>
+</a>
+</g>
+</g>
+<!-- N5&#45;&gt;N1 -->
+<g id="edge3" class="edge">
+<title>N5-&gt;N1</title>
+<g id="a_edge3"><a xlink:title="runtime.main -> main.main (18.94s)">
+<path fill="none" stroke="#b22600" stroke-width="3" d="M171.5,-1172.87C171.5,-1158.4 171.5,-1136.8 171.5,-1116.29"></path>
+<polygon fill="#b22600" stroke="#b22600" stroke-width="3" points="175,-1116.03 171.5,-1106.03 168,-1116.03 175,-1116.03"></polygon>
+</a>
+</g>
+<g id="a_edge3-label"><a xlink:title="runtime.main -> main.main (18.94s)">
+<text text-anchor="middle" x="198" y="-1127.8" font-family="Times,serif" font-size="14.00"> 18.94s</text>
+</a>
+</g>
+</g>
+<!-- N6&#45;&gt;N15 -->
+<g id="edge28" class="edge">
+<title>N6-&gt;N15</title>
+<g id="a_edge28"><a xlink:title="runtime.findrunnable -> runtime.checkTimers (1.13s)">
+<path fill="none" stroke="#b2aa9a" d="M1193.85,-454.49C1184.06,-448.87 1174.05,-443.22 1164.5,-438 1120.72,-414.07 1108.14,-411.18 1064.5,-387 1060.58,-384.83 1056.59,-382.57 1052.56,-380.27"></path>
+<polygon fill="#b2aa9a" stroke="#b2aa9a" points="1054.15,-377.15 1043.74,-375.18 1050.65,-383.21 1054.15,-377.15"></polygon>
+</a>
+</g>
+<g id="a_edge28-label"><a xlink:title="runtime.findrunnable -> runtime.checkTimers (1.13s)">
+<text text-anchor="middle" x="1150.5" y="-408.8" font-family="Times,serif" font-size="14.00"> 1.13s</text>
+</a>
+</g>
+</g>
+<!-- N6&#45;&gt;N16 -->
+<g id="edge24" class="edge">
+<title>N6-&gt;N16</title>
+<g id="a_edge24"><a xlink:title="runtime.findrunnable -> runtime.unlock (1.68s)">
+<path fill="none" stroke="#b2a48e" d="M1282.11,-454.25C1293.74,-437.04 1309.31,-417.87 1327.5,-405 1348.49,-390.14 1360.22,-399.85 1382.5,-387 1391.56,-381.78 1400.44,-374.94 1408.39,-367.98"></path>
+<polygon fill="#b2a48e" stroke="#b2a48e" points="1410.98,-370.35 1416.01,-361.03 1406.26,-365.18 1410.98,-370.35"></polygon>
+</a>
+</g>
+<g id="a_edge24-label"><a xlink:title="runtime.findrunnable -> runtime.unlock (1.68s)">
+<text text-anchor="middle" x="1349.5" y="-408.8" font-family="Times,serif" font-size="14.00"> 1.68s</text>
+</a>
+</g>
+</g>
+<!-- N6&#45;&gt;N19 -->
+<g id="edge29" class="edge">
+<title>N6-&gt;N19</title>
+<g id="a_edge29"><a xlink:title="runtime.findrunnable -> runtime.lock (1.01s)">
+<path fill="none" stroke="#b2ab9d" d="M1340.55,-461.43C1387.4,-441.86 1446.9,-415.23 1497.5,-387 1512.39,-378.69 1528.1,-368.29 1541.28,-359.05"></path>
+<polygon fill="#b2ab9d" stroke="#b2ab9d" points="1543.41,-361.82 1549.53,-353.18 1539.35,-356.12 1543.41,-361.82"></polygon>
+</a>
+</g>
+<g id="a_edge29-label"><a xlink:title="runtime.findrunnable -> runtime.lock (1.01s)">
+<text text-anchor="middle" x="1481.5" y="-408.8" font-family="Times,serif" font-size="14.00"> 1.01s</text>
+</a>
+</g>
+</g>
+<!-- N20 -->
+<g id="node20" class="node">
+<title>N20</title>
+<g id="a_node20"><a xlink:title="runtime.globrunqget (1.39s)">
+<polygon fill="#edebe9" stroke="#b2a795" points="1373,-379 1208,-379 1208,-291 1373,-291 1373,-379"></polygon>
+<text text-anchor="middle" x="1290.5" y="-360.6" font-family="Times,serif" font-size="18.00">runtime</text>
+<text text-anchor="middle" x="1290.5" y="-340.6" font-family="Times,serif" font-size="18.00">globrunqget</text>
+<text text-anchor="middle" x="1290.5" y="-320.6" font-family="Times,serif" font-size="18.00">1.34s (3.18%)</text>
+<text text-anchor="middle" x="1290.5" y="-300.6" font-family="Times,serif" font-size="18.00">of 1.39s (3.29%)</text>
+</a>
+</g>
+</g>
+<!-- N6&#45;&gt;N20 -->
+<g id="edge25" class="edge">
+<title>N6-&gt;N20</title>
+<g id="a_edge25"><a xlink:title="runtime.findrunnable -> runtime.globrunqget (1.38s)">
+<path fill="none" stroke="#b2a895" d="M1256.62,-454.36C1256.34,-438.84 1257.09,-420.93 1260.5,-405 1261.64,-399.65 1263.22,-394.21 1265.05,-388.84"></path>
+<polygon fill="#b2a895" stroke="#b2a895" points="1268.39,-389.89 1268.58,-379.3 1261.82,-387.46 1268.39,-389.89"></polygon>
+</a>
+</g>
+<g id="a_edge25-label"><a xlink:title="runtime.findrunnable -> runtime.globrunqget (1.38s)">
+<text text-anchor="middle" x="1282.5" y="-408.8" font-family="Times,serif" font-size="14.00"> 1.38s</text>
+</a>
+</g>
+</g>
+<!-- N6&#45;&gt;N24 -->
+<g id="edge32" class="edge">
+<title>N6-&gt;N24</title>
+<g id="a_edge32"><a xlink:title="runtime.findrunnable -> runtime.runqget (0.25s)">
+<path fill="none" stroke="#b2b1ad" d="M1227.53,-454.16C1206.37,-428.13 1178.93,-394.36 1158.8,-369.59"></path>
+<polygon fill="#b2b1ad" stroke="#b2b1ad" points="1161.29,-367.11 1152.27,-361.56 1155.86,-371.53 1161.29,-367.11"></polygon>
+</a>
+</g>
+<g id="a_edge32-label"><a xlink:title="runtime.findrunnable -> runtime.runqget (0.25s)">
+<text text-anchor="middle" x="1221.5" y="-408.8" font-family="Times,serif" font-size="14.00"> 0.25s</text>
+</a>
+</g>
+</g>
+<!-- N10 -->
+<g id="node10" class="node">
+<title>N10</title>
+<g id="a_node10"><a xlink:title="runtime.nanotime (2.97s)">
+<polygon fill="#ede9e4" stroke="#b29673" points="864,-217 693,-217 693,-137 864,-137 864,-217"></polygon>
+<text text-anchor="middle" x="778.5" y="-195.4" font-family="Times,serif" font-size="22.00">runtime</text>
+<text text-anchor="middle" x="778.5" y="-171.4" font-family="Times,serif" font-size="22.00">nanotime</text>
+<text text-anchor="middle" x="778.5" y="-147.4" font-family="Times,serif" font-size="22.00">2.97s (7.04%)</text>
+</a>
+</g>
+</g>
+<!-- N7&#45;&gt;N10 -->
+<g id="edge22" class="edge">
+<title>N7-&gt;N10</title>
+<g id="a_edge22"><a xlink:title="runtime.casgstatus -> runtime.nanotime (1.83s)">
+<path fill="none" stroke="#b2a38b" d="M778.5,-282.92C778.5,-265.09 778.5,-245.13 778.5,-227.44"></path>
+<polygon fill="#b2a38b" stroke="#b2a38b" points="782,-227.31 778.5,-217.32 775,-227.32 782,-227.31"></polygon>
+</a>
+</g>
+<g id="a_edge22-label"><a xlink:title="runtime.casgstatus -> runtime.nanotime (1.83s)">
+<text text-anchor="middle" x="806" y="-253.8" font-family="Times,serif" font-size="14.00"> 1.83s</text>
+<text text-anchor="middle" x="806" y="-238.8" font-family="Times,serif" font-size="14.00"> (inline)</text>
+</a>
+</g>
+</g>
+<!-- N28 -->
+<g id="node28" class="node">
+<title>N28</title>
+<g id="a_node28"><a xlink:title="runtime.(*timeHistogram).record (0.22s)">
+<polygon fill="#ededec" stroke="#b2b1ad" points="674.5,-207 552.5,-207 552.5,-147 674.5,-147 674.5,-207"></polygon>
+<text text-anchor="middle" x="613.5" y="-193.4" font-family="Times,serif" font-size="12.00">runtime</text>
+<text text-anchor="middle" x="613.5" y="-180.4" font-family="Times,serif" font-size="12.00">(*timeHistogram)</text>
+<text text-anchor="middle" x="613.5" y="-167.4" font-family="Times,serif" font-size="12.00">record</text>
+<text text-anchor="middle" x="613.5" y="-154.4" font-family="Times,serif" font-size="12.00">0.22s (0.52%)</text>
+</a>
+</g>
+</g>
+<!-- N7&#45;&gt;N28 -->
+<g id="edge34" class="edge">
+<title>N7-&gt;N28</title>
+<g id="a_edge34"><a xlink:title="runtime.casgstatus -> runtime.(*timeHistogram).record (0.22s)">
+<path fill="none" stroke="#b2b1ad" d="M724.47,-282.92C700.76,-260.5 673.48,-234.71 651.9,-214.3"></path>
+<polygon fill="#b2b1ad" stroke="#b2b1ad" points="654.19,-211.65 644.52,-207.33 649.38,-216.74 654.19,-211.65"></polygon>
+</a>
+</g>
+<g id="a_edge34-label"><a xlink:title="runtime.casgstatus -> runtime.(*timeHistogram).record (0.22s)">
+<text text-anchor="middle" x="729" y="-253.8" font-family="Times,serif" font-size="14.00"> 0.22s</text>
+<text text-anchor="middle" x="729" y="-238.8" font-family="Times,serif" font-size="14.00"> (inline)</text>
+</a>
+</g>
+</g>
+<!-- N12 -->
+<g id="node12" class="node">
+<title>N12</title>
+<g id="a_node12"><a xlink:title="github.com/ii64/gouring/queue.(*Queue)._getSQEntry (4.56s)">
+<polygon fill="#ede6e0" stroke="#b28152" points="215.5,-750 1.5,-750 1.5,-622 215.5,-622 215.5,-750"></polygon>
+<text text-anchor="middle" x="108.5" y="-728.4" font-family="Times,serif" font-size="22.00">queue</text>
+<text text-anchor="middle" x="108.5" y="-704.4" font-family="Times,serif" font-size="22.00">(*Queue)</text>
+<text text-anchor="middle" x="108.5" y="-680.4" font-family="Times,serif" font-size="22.00">_getSQEntry</text>
+<text text-anchor="middle" x="108.5" y="-656.4" font-family="Times,serif" font-size="22.00">2.83s (6.71%)</text>
+<text text-anchor="middle" x="108.5" y="-632.4" font-family="Times,serif" font-size="22.00">of 4.56s (10.81%)</text>
+</a>
+</g>
+</g>
+<!-- N8&#45;&gt;N12 -->
+<g id="edge10" class="edge">
+<title>N8-&gt;N12</title>
+<g id="a_edge10"><a xlink:title="github.com/ii64/gouring/queue.(*Queue).GetSQEntry -> github.com/ii64/gouring/queue.(*Queue)._getSQEntry (4.56s)">
+<path fill="none" stroke="#b28152" d="M148.58,-805.96C143.53,-790.97 138.16,-775.03 133.05,-759.86"></path>
+<polygon fill="#b28152" stroke="#b28152" points="136.24,-758.37 129.73,-750.02 129.61,-760.61 136.24,-758.37"></polygon>
+</a>
+</g>
+<g id="a_edge10-label"><a xlink:title="github.com/ii64/gouring/queue.(*Queue).GetSQEntry -> github.com/ii64/gouring/queue.(*Queue)._getSQEntry (4.56s)">
+<text text-anchor="middle" x="164.5" y="-776.8" font-family="Times,serif" font-size="14.00"> 4.56s</text>
+</a>
+</g>
+</g>
+<!-- N9 -->
+<g id="node9" class="node">
+<title>N9</title>
+<g id="a_node9"><a xlink:title="github.com/ii64/gouring/queue.(*Queue).GetCQEntryWait (5.99s)">
+<polygon fill="#ede3dc" stroke="#b26b33" points="461,-755 234,-755 234,-617 461,-617 461,-755"></polygon>
+<text text-anchor="middle" x="347.5" y="-731.8" font-family="Times,serif" font-size="24.00">queue</text>
+<text text-anchor="middle" x="347.5" y="-705.8" font-family="Times,serif" font-size="24.00">(*Queue)</text>
+<text text-anchor="middle" x="347.5" y="-679.8" font-family="Times,serif" font-size="24.00">GetCQEntryWait</text>
+<text text-anchor="middle" x="347.5" y="-653.8" font-family="Times,serif" font-size="24.00">3.83s (9.08%)</text>
+<text text-anchor="middle" x="347.5" y="-627.8" font-family="Times,serif" font-size="24.00">of 5.99s (14.19%)</text>
+</a>
+</g>
+</g>
+<!-- N23 -->
+<g id="node23" class="node">
+<title>N23</title>
+<g id="a_node23"><a xlink:title="github.com/ii64/gouring/queue.(*Queue).cqPeek (1.16s)">
+<polygon fill="#edece9" stroke="#b2aa99" points="301.5,-536.5 167.5,-536.5 167.5,-452.5 301.5,-452.5 301.5,-536.5"></polygon>
+<text text-anchor="middle" x="234.5" y="-518.9" font-family="Times,serif" font-size="17.00">queue</text>
+<text text-anchor="middle" x="234.5" y="-499.9" font-family="Times,serif" font-size="17.00">(*Queue)</text>
+<text text-anchor="middle" x="234.5" y="-480.9" font-family="Times,serif" font-size="17.00">cqPeek</text>
+<text text-anchor="middle" x="234.5" y="-461.9" font-family="Times,serif" font-size="17.00">1.16s (2.75%)</text>
+</a>
+</g>
+</g>
+<!-- N9&#45;&gt;N23 -->
+<g id="edge26" class="edge">
+<title>N9-&gt;N23</title>
+<g id="a_edge26"><a xlink:title="github.com/ii64/gouring/queue.(*Queue).GetCQEntryWait -> github.com/ii64/gouring/queue.(*Queue).cqPeek (1.16s)">
+<path fill="none" stroke="#b2aa99" d="M306.86,-616.85C292.79,-593.26 277.3,-567.27 264.26,-545.42"></path>
+<polygon fill="#b2aa99" stroke="#b2aa99" points="267.16,-543.43 259.03,-536.63 261.14,-547.02 267.16,-543.43"></polygon>
+</a>
+</g>
+<g id="a_edge26-label"><a xlink:title="github.com/ii64/gouring/queue.(*Queue).GetCQEntryWait -> github.com/ii64/gouring/queue.(*Queue).cqPeek (1.16s)">
+<text text-anchor="middle" x="322" y="-587.8" font-family="Times,serif" font-size="14.00"> 1.16s</text>
+<text text-anchor="middle" x="322" y="-572.8" font-family="Times,serif" font-size="14.00"> (inline)</text>
+</a>
+</g>
+</g>
+<!-- N25 -->
+<g id="node25" class="node">
+<title>N25</title>
+<g id="a_node25"><a xlink:title="github.com/ii64/gouring.SQRing.IsCQOverflow (0.59s)">
+<polygon fill="#edeceb" stroke="#b2afa6" points="441.5,-532.5 319.5,-532.5 319.5,-456.5 441.5,-456.5 441.5,-532.5"></polygon>
+<text text-anchor="middle" x="380.5" y="-516.5" font-family="Times,serif" font-size="15.00">gouring</text>
+<text text-anchor="middle" x="380.5" y="-499.5" font-family="Times,serif" font-size="15.00">SQRing</text>
+<text text-anchor="middle" x="380.5" y="-482.5" font-family="Times,serif" font-size="15.00">IsCQOverflow</text>
+<text text-anchor="middle" x="380.5" y="-465.5" font-family="Times,serif" font-size="15.00">0.59s (1.40%)</text>
+</a>
+</g>
+</g>
+<!-- N9&#45;&gt;N25 -->
+<g id="edge31" class="edge">
+<title>N9-&gt;N25</title>
+<g id="a_edge31"><a xlink:title="github.com/ii64/gouring/queue.(*Queue).GetCQEntryWait -> github.com/ii64/gouring.SQRing.IsCQOverflow (0.59s)">
+<path fill="none" stroke="#b2afa6" d="M359.37,-616.85C363.66,-592.19 368.41,-564.92 372.32,-542.48"></path>
+<polygon fill="#b2afa6" stroke="#b2afa6" points="375.78,-542.99 374.05,-532.54 368.89,-541.79 375.78,-542.99"></polygon>
+</a>
+</g>
+<g id="a_edge31-label"><a xlink:title="github.com/ii64/gouring/queue.(*Queue).GetCQEntryWait -> github.com/ii64/gouring.SQRing.IsCQOverflow (0.59s)">
+<text text-anchor="middle" x="395" y="-587.8" font-family="Times,serif" font-size="14.00"> 0.59s</text>
+<text text-anchor="middle" x="395" y="-572.8" font-family="Times,serif" font-size="14.00"> (inline)</text>
+</a>
+</g>
+</g>
+<!-- N27 -->
+<g id="node27" class="node">
+<title>N27</title>
+<g id="a_node27"><a xlink:title="github.com/ii64/gouring/queue.(*Queue).cqAdvance (0.24s)">
+<polygon fill="#ededec" stroke="#b2b1ad" points="559,-524.5 460,-524.5 460,-464.5 559,-464.5 559,-524.5"></polygon>
+<text text-anchor="middle" x="509.5" y="-510.9" font-family="Times,serif" font-size="12.00">queue</text>
+<text text-anchor="middle" x="509.5" y="-497.9" font-family="Times,serif" font-size="12.00">(*Queue)</text>
+<text text-anchor="middle" x="509.5" y="-484.9" font-family="Times,serif" font-size="12.00">cqAdvance</text>
+<text text-anchor="middle" x="509.5" y="-471.9" font-family="Times,serif" font-size="12.00">0.24s (0.57%)</text>
+</a>
+</g>
+</g>
+<!-- N9&#45;&gt;N27 -->
+<g id="edge33" class="edge">
+<title>N9-&gt;N27</title>
+<g id="a_edge33"><a xlink:title="github.com/ii64/gouring/queue.(*Queue).GetCQEntryWait -> github.com/ii64/gouring/queue.(*Queue).cqAdvance (0.24s)">
+<path fill="none" stroke="#b2b1ad" d="M410.88,-616.84C416.21,-610.85 421.48,-604.85 426.5,-599 444.96,-577.5 464.85,-552.75 480.53,-532.85"></path>
+<polygon fill="#b2b1ad" stroke="#b2b1ad" points="483.33,-534.95 486.76,-524.92 477.83,-530.63 483.33,-534.95"></polygon>
+</a>
+</g>
+<g id="a_edge33-label"><a xlink:title="github.com/ii64/gouring/queue.(*Queue).GetCQEntryWait -> github.com/ii64/gouring/queue.(*Queue).cqAdvance (0.24s)">
+<text text-anchor="middle" x="478" y="-587.8" font-family="Times,serif" font-size="14.00"> 0.24s</text>
+<text text-anchor="middle" x="478" y="-572.8" font-family="Times,serif" font-size="14.00"> (inline)</text>
+</a>
+</g>
+</g>
+<!-- N11 -->
+<g id="node11" class="node">
+<title>N11</title>
+<g id="a_node11"><a xlink:title="runtime.unlock2 (3.69s)">
+<polygon fill="#ede8e2" stroke="#b28c64" points="1530.5,-86 1348.5,-86 1348.5,0 1530.5,0 1530.5,-86"></polygon>
+<text text-anchor="middle" x="1439.5" y="-62.8" font-family="Times,serif" font-size="24.00">runtime</text>
+<text text-anchor="middle" x="1439.5" y="-36.8" font-family="Times,serif" font-size="24.00">unlock2</text>
+<text text-anchor="middle" x="1439.5" y="-10.8" font-family="Times,serif" font-size="24.00">3.69s (8.74%)</text>
+</a>
+</g>
+</g>
+<!-- N18 -->
+<g id="node18" class="node">
+<title>N18</title>
+<g id="a_node18"><a xlink:title="github.com/ii64/gouring.(*SQEntry).Reset (1.73s)">
+<polygon fill="#edebe8" stroke="#b2a48d" points="149,-540.5 0,-540.5 0,-448.5 149,-448.5 149,-540.5"></polygon>
+<text text-anchor="middle" x="74.5" y="-521.3" font-family="Times,serif" font-size="19.00">gouring</text>
+<text text-anchor="middle" x="74.5" y="-500.3" font-family="Times,serif" font-size="19.00">(*SQEntry)</text>
+<text text-anchor="middle" x="74.5" y="-479.3" font-family="Times,serif" font-size="19.00">Reset</text>
+<text text-anchor="middle" x="74.5" y="-458.3" font-family="Times,serif" font-size="19.00">1.73s (4.10%)</text>
+</a>
+</g>
+</g>
+<!-- N12&#45;&gt;N18 -->
+<g id="edge23" class="edge">
+<title>N12-&gt;N18</title>
+<g id="a_edge23"><a xlink:title="github.com/ii64/gouring/queue.(*Queue)._getSQEntry -> github.com/ii64/gouring.(*SQEntry).Reset (1.73s)">
+<path fill="none" stroke="#b2a48d" d="M97.18,-621.9C93.04,-598.84 88.4,-572.95 84.39,-550.64"></path>
+<polygon fill="#b2a48d" stroke="#b2a48d" points="87.81,-549.88 82.6,-540.66 80.92,-551.12 87.81,-549.88"></polygon>
+</a>
+</g>
+<g id="a_edge23-label"><a xlink:title="github.com/ii64/gouring/queue.(*Queue)._getSQEntry -> github.com/ii64/gouring.(*SQEntry).Reset (1.73s)">
+<text text-anchor="middle" x="115.5" y="-580.3" font-family="Times,serif" font-size="14.00"> 1.73s</text>
+</a>
+</g>
+</g>
+<!-- N13&#45;&gt;N7 -->
+<g id="edge16" class="edge">
+<title>N13-&gt;N7</title>
+<g id="a_edge16"><a xlink:title="runtime.execute -> runtime.casgstatus (2.41s)">
+<path fill="none" stroke="#b29c7f" d="M866,-446.24C853.27,-430.2 838.88,-412.08 825.5,-395.22"></path>
+<polygon fill="#b29c7f" stroke="#b29c7f" points="827.99,-392.72 819.03,-387.06 822.5,-397.07 827.99,-392.72"></polygon>
+</a>
+</g>
+<g id="a_edge16-label"><a xlink:title="runtime.execute -> runtime.casgstatus (2.41s)">
+<text text-anchor="middle" x="867.5" y="-408.8" font-family="Times,serif" font-size="14.00"> 2.41s</text>
+</a>
+</g>
+</g>
+<!-- N14 -->
+<g id="node14" class="node">
+<title>N14</title>
+<g id="a_node14"><a xlink:title="runtime.lock2 (3.08s)">
+<polygon fill="#ede9e4" stroke="#b29471" points="1720,-83 1549,-83 1549,-3 1720,-3 1720,-83"></polygon>
+<text text-anchor="middle" x="1634.5" y="-61.4" font-family="Times,serif" font-size="22.00">runtime</text>
+<text text-anchor="middle" x="1634.5" y="-37.4" font-family="Times,serif" font-size="22.00">lock2</text>
+<text text-anchor="middle" x="1634.5" y="-13.4" font-family="Times,serif" font-size="22.00">3.08s (7.30%)</text>
+</a>
+</g>
+</g>
+<!-- N15&#45;&gt;N10 -->
+<g id="edge27" class="edge">
+<title>N15-&gt;N10</title>
+<g id="a_edge27"><a xlink:title="runtime.checkTimers -> runtime.nanotime (1.14s)">
+<path fill="none" stroke="#b2aa9a" d="M929.04,-294.84C901.08,-273.14 866.19,-246.06 837.04,-223.44"></path>
+<polygon fill="#b2aa9a" stroke="#b2aa9a" points="839.03,-220.55 828.98,-217.18 834.74,-226.08 839.03,-220.55"></polygon>
+</a>
+</g>
+<g id="a_edge27-label"><a xlink:title="runtime.checkTimers -> runtime.nanotime (1.14s)">
+<text text-anchor="middle" x="913" y="-253.8" font-family="Times,serif" font-size="14.00"> 1.14s</text>
+<text text-anchor="middle" x="913" y="-238.8" font-family="Times,serif" font-size="14.00"> (inline)</text>
+</a>
+</g>
+</g>
+<!-- N29 -->
+<g id="node29" class="node">
+<title>N29</title>
+<g id="a_node29"><a xlink:title="runtime.unlockWithRank (3.72s)">
+<polygon fill="#ede8e2" stroke="#b28c63" points="1489.5,-203 1389.5,-203 1389.5,-151 1489.5,-151 1489.5,-203"></polygon>
+<text text-anchor="middle" x="1439.5" y="-191" font-family="Times,serif" font-size="10.00">runtime</text>
+<text text-anchor="middle" x="1439.5" y="-180" font-family="Times,serif" font-size="10.00">unlockWithRank</text>
+<text text-anchor="middle" x="1439.5" y="-169" font-family="Times,serif" font-size="10.00">0.03s (0.071%)</text>
+<text text-anchor="middle" x="1439.5" y="-158" font-family="Times,serif" font-size="10.00">of 3.72s (8.82%)</text>
+</a>
+</g>
+</g>
+<!-- N16&#45;&gt;N29 -->
+<g id="edge11" class="edge">
+<title>N16-&gt;N29</title>
+<g id="a_edge11"><a xlink:title="runtime.unlock -> runtime.unlockWithRank (3.72s)">
+<path fill="none" stroke="#b28c63" d="M1439.5,-308.94C1439.5,-283.01 1439.5,-242.31 1439.5,-213.17"></path>
+<polygon fill="#b28c63" stroke="#b28c63" points="1443,-213 1439.5,-203 1436,-213 1443,-213"></polygon>
+</a>
+</g>
+<g id="a_edge11-label"><a xlink:title="runtime.unlock -> runtime.unlockWithRank (3.72s)">
+<text text-anchor="middle" x="1461.5" y="-246.3" font-family="Times,serif" font-size="14.00"> 3.72s</text>
+</a>
+</g>
+</g>
+<!-- N17 -->
+<g id="node17" class="node">
+<title>N17</title>
+<g id="a_node17"><a xlink:title="github.com/ii64/gouring/queue.(*Queue).sqFlush (2.04s)">
+<polygon fill="#edeae7" stroke="#b2a187" points="750,-551 577,-551 577,-438 750,-438 750,-551"></polygon>
+<text text-anchor="middle" x="663.5" y="-531.8" font-family="Times,serif" font-size="19.00">queue</text>
+<text text-anchor="middle" x="663.5" y="-510.8" font-family="Times,serif" font-size="19.00">(*Queue)</text>
+<text text-anchor="middle" x="663.5" y="-489.8" font-family="Times,serif" font-size="19.00">sqFlush</text>
+<text text-anchor="middle" x="663.5" y="-468.8" font-family="Times,serif" font-size="19.00">1.86s (4.41%)</text>
+<text text-anchor="middle" x="663.5" y="-447.8" font-family="Times,serif" font-size="19.00">of 2.04s (4.83%)</text>
+</a>
+</g>
+</g>
+<!-- N31 -->
+<g id="node31" class="node">
+<title>N31</title>
+<g id="a_node31"><a xlink:title="runtime.lockWithRank (3.09s)">
+<polygon fill="#ede9e4" stroke="#b29471" points="1641,-201 1548,-201 1548,-153 1641,-153 1641,-201"></polygon>
+<text text-anchor="middle" x="1594.5" y="-189.8" font-family="Times,serif" font-size="9.00">runtime</text>
+<text text-anchor="middle" x="1594.5" y="-179.8" font-family="Times,serif" font-size="9.00">lockWithRank</text>
+<text text-anchor="middle" x="1594.5" y="-169.8" font-family="Times,serif" font-size="9.00">0.01s (0.024%)</text>
+<text text-anchor="middle" x="1594.5" y="-159.8" font-family="Times,serif" font-size="9.00">of 3.09s (7.32%)</text>
+</a>
+</g>
+</g>
+<!-- N19&#45;&gt;N31 -->
+<g id="edge13" class="edge">
+<title>N19-&gt;N31</title>
+<g id="a_edge13"><a xlink:title="runtime.lock -> runtime.lockWithRank (3.09s)">
+<path fill="none" stroke="#b29471" d="M1574.94,-316.71C1578.51,-291.41 1585.22,-243.8 1589.78,-211.5"></path>
+<polygon fill="#b29471" stroke="#b29471" points="1593.3,-211.58 1591.23,-201.19 1586.37,-210.6 1593.3,-211.58"></polygon>
+</a>
+</g>
+<g id="a_edge13-label"><a xlink:title="runtime.lock -> runtime.lockWithRank (3.09s)">
+<text text-anchor="middle" x="1613" y="-253.8" font-family="Times,serif" font-size="14.00"> 3.09s</text>
+<text text-anchor="middle" x="1613" y="-238.8" font-family="Times,serif" font-size="14.00"> (inline)</text>
+</a>
+</g>
+</g>
+<!-- N21&#45;&gt;N2 -->
+<g id="edge2" class="edge">
+<title>N21-&gt;N2</title>
+<g id="a_edge2"><a xlink:title="runtime.gosched_m -> runtime.goschedImpl (21.46s)">
+<path fill="none" stroke="#b22000" stroke-width="3" d="M1259.5,-1025.88C1259.5,-996.52 1259.5,-952.21 1259.5,-919.38"></path>
+<polygon fill="#b22000" stroke="#b22000" stroke-width="3" points="1263,-919.16 1259.5,-909.16 1256,-919.16 1263,-919.16"></polygon>
+</a>
+</g>
+<g id="a_edge2-label"><a xlink:title="runtime.gosched_m -> runtime.goschedImpl (21.46s)">
+<text text-anchor="middle" x="1286" y="-973.3" font-family="Times,serif" font-size="14.00"> 21.46s</text>
+</a>
+</g>
+</g>
+<!-- N22 -->
+<g id="node22" class="node">
+<title>N22</title>
+<g id="a_node22"><a xlink:title="runtime.nanotime1 (0.81s)">
+<polygon fill="#edecea" stroke="#b2ada1" points="1485,-1222 1354,-1222 1354,-1160 1485,-1160 1485,-1222"></polygon>
+<text text-anchor="middle" x="1419.5" y="-1205.2" font-family="Times,serif" font-size="16.00">runtime</text>
+<text text-anchor="middle" x="1419.5" y="-1187.2" font-family="Times,serif" font-size="16.00">nanotime1</text>
+<text text-anchor="middle" x="1419.5" y="-1169.2" font-family="Times,serif" font-size="16.00">0.81s (1.92%)</text>
+</a>
+</g>
+</g>
+<!-- N26 -->
+<g id="node26" class="node">
+<title>N26</title>
+<g id="a_node26"><a xlink:title="gogo (0.26s)">
+<polygon fill="#edecec" stroke="#b2b1ad" points="1612,-1209 1503,-1209 1503,-1173 1612,-1173 1612,-1209"></polygon>
+<text text-anchor="middle" x="1557.5" y="-1194.6" font-family="Times,serif" font-size="13.00">gogo</text>
+<text text-anchor="middle" x="1557.5" y="-1180.6" font-family="Times,serif" font-size="13.00">0.26s (0.62%)</text>
+</a>
+</g>
+</g>
+<!-- N29&#45;&gt;N11 -->
+<g id="edge12" class="edge">
+<title>N29-&gt;N11</title>
+<g id="a_edge12"><a xlink:title="runtime.unlockWithRank -> runtime.unlock2 (3.69s)">
+<path fill="none" stroke="#b28c64" d="M1439.5,-150.86C1439.5,-135.46 1439.5,-115.17 1439.5,-96.41"></path>
+<polygon fill="#b28c64" stroke="#b28c64" points="1443,-96.18 1439.5,-86.18 1436,-96.18 1443,-96.18"></polygon>
+</a>
+</g>
+<g id="a_edge12-label"><a xlink:title="runtime.unlockWithRank -> runtime.unlock2 (3.69s)">
+<text text-anchor="middle" x="1461.5" y="-107.8" font-family="Times,serif" font-size="14.00"> 3.69s</text>
+</a>
+</g>
+</g>
+<!-- N30&#45;&gt;N9 -->
+<g id="edge8" class="edge">
+<title>N30-&gt;N9</title>
+<g id="a_edge8"><a xlink:title="github.com/ii64/gouring/queue.(*Queue).GetCQEntry -> github.com/ii64/gouring/queue.(*Queue).GetCQEntryWait (5.99s)">
+<path fill="none" stroke="#b26b33" d="M347.5,-845.6C347.5,-824.31 347.5,-794.07 347.5,-765.7"></path>
+<polygon fill="#b26b33" stroke="#b26b33" points="351,-765.35 347.5,-755.35 344,-765.35 351,-765.35"></polygon>
+</a>
+</g>
+<g id="a_edge8-label"><a xlink:title="github.com/ii64/gouring/queue.(*Queue).GetCQEntry -> github.com/ii64/gouring/queue.(*Queue).GetCQEntryWait (5.99s)">
+<text text-anchor="middle" x="369.5" y="-776.8" font-family="Times,serif" font-size="14.00"> 5.99s</text>
+</a>
+</g>
+</g>
+<!-- N31&#45;&gt;N14 -->
+<g id="edge14" class="edge">
+<title>N31-&gt;N14</title>
+<g id="a_edge14"><a xlink:title="runtime.lockWithRank -> runtime.lock2 (3.08s)">
+<path fill="none" stroke="#b29471" d="M1601.56,-152.7C1606.57,-136.17 1613.48,-113.36 1619.68,-92.91"></path>
+<polygon fill="#b29471" stroke="#b29471" points="1623.1,-93.68 1622.65,-83.09 1616.4,-91.65 1623.1,-93.68"></polygon>
+</a>
+</g>
+<g id="a_edge14-label"><a xlink:title="runtime.lockWithRank -> runtime.lock2 (3.08s)">
+<text text-anchor="middle" x="1637.5" y="-107.8" font-family="Times,serif" font-size="14.00"> 3.08s</text>
+</a>
+</g>
+</g>
+<!-- N32 -->
+<g id="node32" class="node">
+<title>N32</title>
+<g id="a_node32"><a xlink:title="github.com/ii64/gouring/queue.(*Queue).SubmitAndWait (2.05s)">
+<polygon fill="#edeae7" stroke="#b2a187" points="680,-715 587,-715 587,-657 680,-657 680,-715"></polygon>
+<text text-anchor="middle" x="633.5" y="-703.8" font-family="Times,serif" font-size="9.00">queue</text>
+<text text-anchor="middle" x="633.5" y="-693.8" font-family="Times,serif" font-size="9.00">(*Queue)</text>
+<text text-anchor="middle" x="633.5" y="-683.8" font-family="Times,serif" font-size="9.00">SubmitAndWait</text>
+<text text-anchor="middle" x="633.5" y="-673.8" font-family="Times,serif" font-size="9.00">0.01s (0.024%)</text>
+<text text-anchor="middle" x="633.5" y="-663.8" font-family="Times,serif" font-size="9.00">of 2.05s (4.86%)</text>
+</a>
+</g>
+</g>
+<!-- N32&#45;&gt;N17 -->
+<g id="edge21" class="edge">
+<title>N32-&gt;N17</title>
+<g id="a_edge21"><a xlink:title="github.com/ii64/gouring/queue.(*Queue).SubmitAndWait -> github.com/ii64/gouring/queue.(*Queue).sqFlush (2.04s)">
+<path fill="none" stroke="#b2a187" d="M637.99,-656.63C641.98,-631.46 647.95,-593.73 653.11,-561.11"></path>
+<polygon fill="#b2a187" stroke="#b2a187" points="656.58,-561.59 654.69,-551.16 649.67,-560.49 656.58,-561.59"></polygon>
+</a>
+</g>
+<g id="a_edge21-label"><a xlink:title="github.com/ii64/gouring/queue.(*Queue).SubmitAndWait -> github.com/ii64/gouring/queue.(*Queue).sqFlush (2.04s)">
+<text text-anchor="middle" x="673.5" y="-580.3" font-family="Times,serif" font-size="14.00"> 2.04s</text>
+</a>
+</g>
+</g>
+<!-- N33&#45;&gt;N32 -->
+<g id="edge19" class="edge">
+<title>N33-&gt;N32</title>
+<g id="a_edge19"><a xlink:title="github.com/ii64/gouring/queue.(*Queue).Submit -> github.com/ii64/gouring/queue.(*Queue).SubmitAndWait (2.05s)">
+<path fill="none" stroke="#b2a187" d="M551.87,-852.91C567.17,-821.83 595.99,-763.23 614.97,-724.66"></path>
+<polygon fill="#b2a187" stroke="#b2a187" points="618.3,-725.83 619.57,-715.31 612.02,-722.74 618.3,-725.83"></polygon>
+</a>
+</g>
+<g id="a_edge19-label"><a xlink:title="github.com/ii64/gouring/queue.(*Queue).Submit -> github.com/ii64/gouring/queue.(*Queue).SubmitAndWait (2.05s)">
+<text text-anchor="middle" x="612.5" y="-776.8" font-family="Times,serif" font-size="14.00"> 2.05s</text>
+</a>
+</g>
+</g>
+</g>
+</svg>
\ No newline at end of file

From 5937800f05317d18f14de94dc8163c54dc516410 Mon Sep 17 00:00:00 2001
From: MastahSenpai <26342994+ii64@users.noreply.github.com>
Date: Wed, 26 Jan 2022 01:20:07 +0700
Subject: [PATCH 04/14] fix(perf): direct field access

Signed-off-by: MastahSenpai <26342994+ii64@users.noreply.github.com>
---
 core.go      |   8 ++---
 core_test.go |  21 +++++------
 mem_util.go  |  46 ++++++++++++++++--------
 ring.go      | 100 ++++++++-------------------------------------------
 4 files changed, 60 insertions(+), 115 deletions(-)

diff --git a/core.go b/core.go
index 6735081..924aaed 100644
--- a/core.go
+++ b/core.go
@@ -61,10 +61,10 @@ func (r *Ring) Fd() int {
 	return r.fd
 }
 
-func (r *Ring) SQ() *SQRing {
-	return &r.sq
+func (r *Ring) SQ() SQRing {
+	return r.sq
 }
 
-func (r *Ring) CQ() *CQRing {
-	return &r.cq
+func (r *Ring) CQ() CQRing {
+	return r.cq
 }
diff --git a/core_test.go b/core_test.go
index 8205090..43fe1a6 100644
--- a/core_test.go
+++ b/core_test.go
@@ -23,10 +23,11 @@ func TestCore(t *testing.T) {
 	sq := ring.SQ()
 	n := 5
 	for i := 0; i < n; i++ {
-		sqTail := *sq.Tail()
-		sqIdx := sqTail & *sq.RingMask()
+		sqTail := *sq.Tail
+		sqIdx := sqTail & *sq.RingMask
 
-		sqe := sq.Get(sqIdx)
+		sqe := &sq.Event[sqIdx]
+		sqe.Reset()
 
 		m := mkdata(i)
 
@@ -37,8 +38,8 @@ func TestCore(t *testing.T) {
 		sqe.SetOffset(0)
 		sqe.SetAddr(&m[0])
 
-		*sq.Array().Get(sqIdx) = *sq.Head() & *sq.RingMask()
-		*sq.Tail()++
+		*sq.Array.Get(sqIdx) = *sq.Head & *sq.RingMask
+		*sq.Tail++
 
 		done, err := ring.Enter(1, 1, IORING_ENTER_GETEVENTS, nil)
 		assert.NoError(t, err, "ring enter")
@@ -47,13 +48,13 @@ func TestCore(t *testing.T) {
 
 	// get cq
 	cq := ring.CQ()
-	for i := 0; i < int(*cq.Tail()); i++ {
-		cqHead := *cq.Head()
-		cqIdx := cqHead & *cq.RingMask()
+	for i := 0; i < int(*cq.Tail); i++ {
+		cqHead := *cq.Head
+		cqIdx := cqHead & *cq.RingMask
 
-		cqe := cq.Get(cqIdx)
+		cqe := cq.Event[cqIdx]
 
-		*cq.Head()++
+		*cq.Head++
 		t.Logf("CQE %+#v", cqe)
 	}
 
diff --git a/mem_util.go b/mem_util.go
index 1ca0a28..0459cb5 100644
--- a/mem_util.go
+++ b/mem_util.go
@@ -1,6 +1,8 @@
 package gouring
 
 import (
+	"fmt"
+	"reflect"
 	"syscall"
 	"unsafe"
 
@@ -68,15 +70,14 @@ func setup(r *Ring, entries uint, parmas *IOUringParams) (ringFd int, err error)
 	r.sqRingPtr = sqRingPtr
 	r.cqRingPtr = cqRingPtr
 
-	//
+	// SQ
 
-	// address Go's ring with base+offset allocated
-	sq.head = sqRingPtr + uintptr(p.SQOff.Head)
-	sq.tail = sqRingPtr + uintptr(p.SQOff.Tail)
-	sq.ringMask = sqRingPtr + uintptr(p.SQOff.RingMask)
-	sq.ringEntries = sqRingPtr + uintptr(p.SQOff.RingEntries)
-	sq.flags = sqRingPtr + uintptr(p.SQOff.Flags)
-	sq.array = uint32Array(sqRingPtr + uintptr(p.SQOff.Array))
+	sq.Head = (*uint32)(unsafe.Pointer(sqRingPtr + uintptr(p.SQOff.Head)))
+	sq.Tail = (*uint32)(unsafe.Pointer(sqRingPtr + uintptr(p.SQOff.Tail)))
+	sq.RingMask = (*uint32)(unsafe.Pointer(sqRingPtr + uintptr(p.SQOff.RingMask)))
+	sq.RingEntries = (*uint32)(unsafe.Pointer(sqRingPtr + uintptr(p.SQOff.RingEntries)))
+	sq.Flags = (*uint32)(unsafe.Pointer(sqRingPtr + uintptr(p.SQOff.Flags)))
+	sq.Array = uint32Array(sqRingPtr + uintptr(p.SQOff.Array)) // non fixed array size, controlled by ring mask
 	r.sqesPtr, err = mmap(0, uintptr(p.SQEntries*uint32(_sz_sqe)),
 		syscall.PROT_READ|syscall.PROT_WRITE,
 		syscall.MAP_SHARED|syscall.MAP_POPULATE,
@@ -85,15 +86,30 @@ func setup(r *Ring, entries uint, parmas *IOUringParams) (ringFd int, err error)
 		err = errors.Wrap(err, "mmap sqes")
 		return
 	}
-	sq.sqes = sqeArray(r.sqesPtr)
 
-	//
+	sq.Event = *(*[]SQEntry)(unsafe.Pointer(&reflect.SliceHeader{
+		Data: r.sqesPtr,
+		Len:  int(p.SQEntries),
+		Cap:  int(p.SQEntries),
+	}))
 
-	cq.head = cqRingPtr + uintptr(p.CQOff.Head)
-	cq.tail = cqRingPtr + uintptr(p.CQOff.Tail)
-	cq.ringMask = cqRingPtr + uintptr(p.CQOff.RingMask)
-	cq.ringEntries = cqRingPtr + uintptr(p.CQOff.RingEntries)
-	cq.cqes = cqeArray(cqRingPtr + uintptr(p.CQOff.CQEs))
+	fmt.Printf("insp %+#v %+#v\n", len(sq.Event), cap(sq.Event))
+
+	// CQ
+
+	cq.Head = (*uint32)(unsafe.Pointer(cqRingPtr + uintptr(p.CQOff.Head)))
+	cq.Tail = (*uint32)(unsafe.Pointer(cqRingPtr + uintptr(p.CQOff.Tail)))
+	cq.RingMask = (*uint32)(unsafe.Pointer(cqRingPtr + uintptr(p.CQOff.RingMask)))
+	cq.RingEntries = (*uint32)(unsafe.Pointer(cqRingPtr + uintptr(p.CQOff.RingEntries)))
+	cqesPtr := cqRingPtr + uintptr(p.CQOff.CQEs)
+
+	cq.Event = *(*[]CQEntry)(unsafe.Pointer(&reflect.SliceHeader{
+		Data: cqesPtr,
+		Len:  int(p.CQEntries),
+		Cap:  int(p.CQEntries),
+	}))
+
+	fmt.Printf("insp %+#v %+#v\n", len(cq.Event), cap(cq.Event))
 
 	return
 }
diff --git a/ring.go b/ring.go
index 4ad7e3b..e9b0f03 100644
--- a/ring.go
+++ b/ring.go
@@ -20,48 +20,20 @@ type Ring struct {
 //-- SQ
 
 type SQRing struct {
-	head        uintptr
-	tail        uintptr
-	ringMask    uintptr
-	ringEntries uintptr
-	flags       uintptr
-	array       uint32Array
-	sqes        sqeArray
-}
-
-func (sq SQRing) Get(idx uint32) *SQEntry {
-	if uintptr(idx) >= uintptr(*sq.RingEntries()) {
-		return nil
-	}
-	return sq.sqes.Get(uintptr(idx))
-}
-func (sq SQRing) Head() *uint32 {
-	return (*uint32)(unsafe.Pointer(sq.head))
-}
-func (sq SQRing) Tail() *uint32 {
-	return (*uint32)(unsafe.Pointer(sq.tail))
-}
-func (sq SQRing) RingMask() *uint32 {
-	return (*uint32)(unsafe.Pointer(sq.ringMask))
-}
-func (sq SQRing) RingEntries() *uint32 {
-	return (*uint32)(unsafe.Pointer(sq.ringEntries))
-}
-func (sq SQRing) Flags() *uint32 {
-	return (*uint32)(unsafe.Pointer(sq.flags))
-}
-func (sq SQRing) Array() uint32Array {
-	return sq.array
-}
-func (sq SQRing) Event() sqeArray {
-	return sq.sqes
+	Head        *uint32
+	Tail        *uint32
+	RingMask    *uint32
+	RingEntries *uint32
+	Flags       *uint32
+	Array       uint32Array
+	Event       []SQEntry
 }
 
 func (sq SQRing) IsCQOverflow() bool {
-	return atomic.LoadUint32(sq.Flags())&IORING_SQ_CQ_OVERFLOW > 0
+	return atomic.LoadUint32(sq.Flags)&IORING_SQ_CQ_OVERFLOW > 0
 }
 func (sq SQRing) IsNeedWakeup() bool {
-	return atomic.LoadUint32(sq.Flags())&IORING_SQ_NEED_WAKEUP > 0
+	return atomic.LoadUint32(sq.Flags)&IORING_SQ_NEED_WAKEUP > 0
 }
 
 //
@@ -75,57 +47,13 @@ func (a uint32Array) Set(idx uint32, v uint32) {
 	atomic.StoreUint32(a.Get(idx), v)
 }
 
-type sqeArray uintptr
-
-func (sa sqeArray) Get(idx uintptr) *SQEntry {
-	return (*SQEntry)(unsafe.Pointer(uintptr(sa) + idx*_sz_sqe))
-}
-
-func (sa sqeArray) Set(idx uintptr, v SQEntry) {
-	*sa.Get(idx) = v
-}
-
 //
 //-- CQ
 
 type CQRing struct {
-	head        uintptr
-	tail        uintptr
-	ringMask    uintptr
-	ringEntries uintptr
-	cqes        cqeArray
-}
-
-func (cq CQRing) Get(idx uint32) *CQEntry {
-	if uintptr(idx) >= uintptr(*cq.RingEntries()) { // avoid lookup overflow
-		return nil
-	}
-	return cq.cqes.Get(uintptr(idx))
-}
-func (cq CQRing) Head() *uint32 {
-	return (*uint32)(unsafe.Pointer(cq.head))
-}
-func (cq CQRing) Tail() *uint32 {
-	return (*uint32)(unsafe.Pointer(cq.tail))
-}
-func (cq CQRing) RingMask() *uint32 {
-	return (*uint32)(unsafe.Pointer(cq.ringMask))
-}
-func (cq CQRing) RingEntries() *uint32 {
-	return (*uint32)(unsafe.Pointer(cq.ringEntries))
-}
-func (cq CQRing) Event() cqeArray {
-	return cq.cqes
-}
-
-//
-
-type cqeArray uintptr
-
-func (ca cqeArray) Get(idx uintptr) *CQEntry {
-	return (*CQEntry)(unsafe.Pointer(uintptr(ca) + idx*_sz_cqe))
-}
-
-func (ca cqeArray) Set(idx uintptr, v CQEntry) {
-	*ca.Get(idx) = v
+	Head        *uint32
+	Tail        *uint32
+	RingMask    *uint32
+	RingEntries *uint32
+	Event       []CQEntry
 }

From 67636d3ab2e479d34df14ee39f19409fcc60133d Mon Sep 17 00:00:00 2001
From: MastahSenpai <26342994+ii64@users.noreply.github.com>
Date: Wed, 26 Jan 2022 01:21:13 +0700
Subject: [PATCH 05/14] fix(perf): direct field access

Signed-off-by: MastahSenpai <26342994+ii64@users.noreply.github.com>
---
 queue/queue.go | 40 +++++++++++++++++++++-------------------
 1 file changed, 21 insertions(+), 19 deletions(-)

diff --git a/queue/queue.go b/queue/queue.go
index fd14a29..7c14876 100644
--- a/queue/queue.go
+++ b/queue/queue.go
@@ -20,8 +20,8 @@ type QueueCQEHandler func(cqe *gouring.CQEntry) (err error)
 
 type Queue struct {
 	ring *gouring.Ring
-	sq   *gouring.SQRing
-	cq   *gouring.CQRing
+	sq   gouring.SQRing
+	cq   gouring.CQRing
 
 	sqeHead uint32
 	sqeTail uint32
@@ -59,11 +59,12 @@ func (q *Queue) precheck() error {
 
 //
 
+// SQEntry ptr returned is passed by value
 func (q *Queue) _getSQEntry() *gouring.SQEntry {
-	head := atomic.LoadUint32(q.sq.Head())
+	head := atomic.LoadUint32(q.sq.Head)
 	next := q.sqeTail + 1
-	if (next - head) <= atomic.LoadUint32(q.sq.RingEntries()) {
-		sqe := q.sq.Get(q.sqeTail & (*q.sq.RingMask()))
+	if (next - head) <= atomic.LoadUint32(q.sq.RingEntries) {
+		sqe := &q.sq.Event[q.sqeTail&(*q.sq.RingMask)]
 		q.sqeTail = next
 		sqe.Reset()
 		return sqe
@@ -77,7 +78,8 @@ func (q *Queue) GetSQEntry() (sqe *gouring.SQEntry) {
 		if sqe != nil {
 			return
 		}
-		// runtime.Gosched()
+
+		runtime.Gosched()
 	}
 }
 
@@ -86,8 +88,8 @@ func (q *Queue) sqFallback(d uint32) {
 }
 
 func (q *Queue) sqFlush() uint32 {
-	khead := atomic.LoadUint32(q.sq.Head())
-	ktail := atomic.LoadUint32(q.sq.Tail())
+	khead := atomic.LoadUint32(q.sq.Head)
+	ktail := atomic.LoadUint32(q.sq.Tail)
 
 	// if sq head equals sq tail
 	if q.sqeHead == q.sqeTail {
@@ -95,11 +97,11 @@ func (q *Queue) sqFlush() uint32 {
 	}
 
 	for toSubmit := q.sqeTail - q.sqeHead; toSubmit > 0; toSubmit-- {
-		*q.sq.Array().Get(ktail & (*q.sq.RingMask())) = q.sqeHead & (*q.sq.RingMask())
+		*q.sq.Array.Get(ktail & (*q.sq.RingMask)) = q.sqeHead & (*q.sq.RingMask)
 		ktail++
 		q.sqeHead++
 	}
-	atomic.StoreUint32(q.sq.Tail(), ktail)
+	atomic.StoreUint32(q.sq.Tail, ktail)
 	return ktail - khead
 }
 
@@ -142,16 +144,16 @@ func (q *Queue) SubmitAndWait(waitNr uint) (ret int, err error) {
 //
 
 func (q *Queue) cqPeek() (cqe *gouring.CQEntry) {
-	khead := atomic.LoadUint32(q.cq.Head())
-	if khead != atomic.LoadUint32(q.cq.Tail()) {
-		cqe = q.cq.Get(khead & atomic.LoadUint32(q.cq.RingMask()))
+	khead := atomic.LoadUint32(q.cq.Head)
+	if khead != atomic.LoadUint32(q.cq.Tail) {
+		cqe = &q.cq.Event[khead&atomic.LoadUint32(q.cq.RingMask)]
 	}
 	return
 }
 
 func (q *Queue) cqAdvance(d uint32) {
 	if d != 0 {
-		atomic.AddUint32(q.cq.Head(), d) // mark readed
+		atomic.AddUint32(q.cq.Head, d) // mark readed
 	}
 }
 
@@ -165,7 +167,7 @@ func (q *Queue) GetCQEntryWait(wait bool, waitNr uint) (cqe *gouring.CQEntry, er
 	if err = q.precheck(); err != nil {
 		return
 	}
-	var tryPeeks int
+	// var tryPeeks int
 	for {
 		if cqe = q.cqPeek(); cqe != nil {
 			q.cqAdvance(1)
@@ -190,10 +192,10 @@ func (q *Queue) GetCQEntryWait(wait bool, waitNr uint) (cqe *gouring.CQEntry, er
 			continue
 		}
 
-		if tryPeeks++; tryPeeks < 3 {
-			runtime.Gosched()
-			continue
-		}
+		// if tryPeeks++; tryPeeks < 3 {
+		runtime.Gosched()
+		// continue
+		// }
 		// implement interrupt
 	}
 }

From 375c7b76d2ca6efc75b34a609e19c03d3dea9d55 Mon Sep 17 00:00:00 2001
From: MastahSenpai <26342994+ii64@users.noreply.github.com>
Date: Wed, 26 Jan 2022 01:24:23 +0700
Subject: [PATCH 06/14] docs: graph image description

Signed-off-by: MastahSenpai <26342994+ii64@users.noreply.github.com>
---
 README.md | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 640b286..0a8c501 100644
--- a/README.md
+++ b/README.md
@@ -79,7 +79,9 @@ if err != nil {
 
 > Check out test script [here](https://gist.github.com/ii64/3a4e8f5c689bb65b2fb9c5f2b1a5904d)
 
-<table><tr><td>
+<table><tr>
+<td>SQPOLL</td><td>non-SQPOLL</td>
+</tr><tr><td>
 
 ![graph sqpoll][3]
 

From b8dab73acf4fb46a2df841d304dcad2face3a41a Mon Sep 17 00:00:00 2001
From: Nugraha <26342994+ii64@users.noreply.github.com>
Date: Wed, 9 Feb 2022 20:00:10 +0700
Subject: [PATCH 07/14] chore: add readme link, comment

Signed-off-by: Nugraha <26342994+ii64@users.noreply.github.com>
---
 README.md     |  5 ++--
 mem_util.go   |  4 +++
 ring_entry.go | 68 ++++++++++++++++++++++++++++++++++++++++++++-------
 3 files changed, 66 insertions(+), 11 deletions(-)

diff --git a/README.md b/README.md
index 0a8c501..1edc816 100644
--- a/README.md
+++ b/README.md
@@ -77,7 +77,7 @@ if err != nil {
 
 ## Graph
 
-> Check out test script [here](https://gist.github.com/ii64/3a4e8f5c689bb65b2fb9c5f2b1a5904d)
+> Check out test script [here][5]
 
 <table><tr>
 <td>SQPOLL</td><td>non-SQPOLL</td>
@@ -100,4 +100,5 @@ if err != nil {
 [1]: https://img.shields.io/badge/License-MIT-yellow.svg
 [2]: https://pkg.go.dev/badge/github.com/ii64/gouring.svg
 [3]: assets/sqpoll.svg
-[4]: assets/nosqpoll.svg
\ No newline at end of file
+[4]: assets/nosqpoll.svg
+[5]: https://gist.github.com/ii64/3a4e8f5c689bb65b2fb9c5f2b1a5904d
\ No newline at end of file
diff --git a/mem_util.go b/mem_util.go
index 0459cb5..8107e2b 100644
--- a/mem_util.go
+++ b/mem_util.go
@@ -20,6 +20,7 @@ func mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int6
 //go:linkname munmap syscall.munmap
 func munmap(addr uintptr, length uintptr) (err error)
 
+// io uring setup
 func setup(r *Ring, entries uint, parmas *IOUringParams) (ringFd int, err error) {
 	var sq = &r.sq
 	var cq = &r.cq
@@ -114,6 +115,7 @@ func setup(r *Ring, entries uint, parmas *IOUringParams) (ringFd int, err error)
 	return
 }
 
+// io uring unsetup
 func unsetup(r *Ring) (err error) {
 	if r.sqesPtr != 0 {
 		if err = munmap(r.sqesPtr, uintptr(r.params.SQEntries)); err != nil {
@@ -135,6 +137,7 @@ func unsetup(r *Ring) (err error) {
 	return
 }
 
+// io uring register fd
 func register(r *Ring, opcode UringRegisterOpcode, arg uintptr, nrArg uint) (ret int, err error) {
 	if ret, err = io_uring_register(r.fd, opcode, arg, nrArg); err != nil {
 		err = errors.Wrap(err, "io_uring_register")
@@ -143,6 +146,7 @@ func register(r *Ring, opcode UringRegisterOpcode, arg uintptr, nrArg uint) (ret
 	return
 }
 
+// io uirng enter
 func enter(r *Ring, toSubmit, minComplete uint, flags UringEnterFlag, sig *Sigset_t) (ret int, err error) {
 	if ret, err = io_uring_enter(r.fd, toSubmit, minComplete, uint(flags), sig); err != nil {
 		err = errors.Wrap(err, "io_uring_enter")
diff --git a/ring_entry.go b/ring_entry.go
index c47e33f..64565dc 100644
--- a/ring_entry.go
+++ b/ring_entry.go
@@ -17,29 +17,79 @@ var (
 //-- SQEntry
 
 type SQEntry struct {
+	// type of operation for this sqe
 	Opcode UringOpcode
-	Flags  UringSQEFlag
+
+	// IOSQE_ flags
+	Flags UringSQEFlag
+
+	// ioprio for the request
 	Ioprio uint16
-	Fd     int32
 
-	off__addr2          uint64 // union { off, addr2 }
-	addr__splice_off_in uint64 // union { addr, splice_off_in }
+	// file descriptor to do IO on
+	Fd int32
 
+	/* union {
+	  off,            // offset into file
+	  addr2;
+	} */
+	off__addr2 uint64
+
+	/* union {
+	  addr,           // pointer to buffer or iovecs
+	  splice_off_in
+	} */
+	addr__splice_off_in uint64
+
+	// buffer size or number iovecs
 	Len uint32
 
-	opcode__flags_events uint32 // union of events and flags for opcode
+	/* union of events and flags for Opcode
+	union {
+		__kernel_rwf_t	rw_flags;
+		__u32		fsync_flags;
+		__u16		poll_events;	  // compatibility
+		__u32		poll32_events;	  // word-reversed for BE
+		__u32		sync_range_flags;
+		__u32		msg_flags;
+		__u32		timeout_flags;
+		__u32		accept_flags;
+		__u32		cancel_flags;
+		__u32		open_flags;
+		__u32		statx_flags;
+		__u32		fadvise_advice;
+		__u32		splice_flags;
+		__u32		rename_flags;
+		__u32		unlink_flags;
+		__u32		hardlink_flags;
+		__u32		xattr_flags;
+	} */
+	opcode__flags_events uint32
 
+	// data to be passed back at completion time
 	UserData uint64
 
-	buf__index_group uint16 // union {buf_index, buf_group}
+	/* pack this to avoid bogus arm OABI complaints
+	union {
+		// index into fixed buffers, if used
+		__u16	buf_index;
+		// for grouped buffer selection
+		__u16	buf_group;
+	} __attribute__((packed)); */
+	buf__index_group uint16
 
+	// personality to use, if used
 	Personality uint16
 
-	splice_fd_in__file_index int32 // union { __s32 splice_fd_in, __u32 file_index }
+	/* -
+	union {
+		__s32	splice_fd_in;
+		__u32	file_index;
+	} */
+	splice_fd_in__file_index int32
 
 	addr3 uint64
-
-	pad2 [1]uint64
+	pad2  [1]uint64
 }
 
 func (sqe *SQEntry) Offset() *uint64 {

From 860871629cce7a27bd8b0655608853db6e3a59f1 Mon Sep 17 00:00:00 2001
From: Nugraha <26342994+ii64@users.noreply.github.com>
Date: Thu, 10 Feb 2022 00:53:05 +0700
Subject: [PATCH 08/14] feat: ring with options

Signed-off-by: Nugraha <26342994+ii64@users.noreply.github.com>
---
 core.go    | 17 +++++++++++++++--
 options.go | 12 ++++++++++++
 2 files changed, 27 insertions(+), 2 deletions(-)
 create mode 100644 options.go

diff --git a/core.go b/core.go
index 924aaed..7c5758a 100644
--- a/core.go
+++ b/core.go
@@ -6,11 +6,17 @@ import (
 	"github.com/pkg/errors"
 )
 
-func New(entries uint, params *IOUringParams) (*Ring, error) {
+func New(entries uint, params *IOUringParams, options ...Option) (*Ring, error) {
 	r := &Ring{}
 	if params != nil {
-		r.params = *params
+		r.params = *params // copy
 	}
+
+	// option reconfiguring
+	for _, opt := range options {
+		opt(&r.params)
+	}
+
 	var err error
 	if r.fd, err = setup(r, entries, &r.params); err != nil {
 		err = errors.Wrap(err, "setup")
@@ -19,6 +25,7 @@ func New(entries uint, params *IOUringParams) (*Ring, error) {
 	return r, nil
 }
 
+// Close ring
 func (r *Ring) Close() (err error) {
 	if err = unsetup(r); err != nil {
 		err = errors.Wrap(err, "close")
@@ -33,6 +40,7 @@ func (r *Ring) Close() (err error) {
 	return
 }
 
+// Register
 func (r *Ring) Register(opcode UringRegisterOpcode, arg uintptr, nrArg uint) (ret int, err error) {
 	ret, err = register(r, opcode, arg, nrArg)
 	if err != nil {
@@ -42,6 +50,7 @@ func (r *Ring) Register(opcode UringRegisterOpcode, arg uintptr, nrArg uint) (re
 	return
 }
 
+// Enter
 func (r *Ring) Enter(toSubmit, minComplete uint, flags UringEnterFlag, sig *Sigset_t) (ret int, err error) {
 	ret, err = enter(r, toSubmit, minComplete, flags, sig)
 	if err != nil {
@@ -53,18 +62,22 @@ func (r *Ring) Enter(toSubmit, minComplete uint, flags UringEnterFlag, sig *Sigs
 
 //
 
+// Params
 func (r *Ring) Params() *IOUringParams {
 	return &r.params
 }
 
+// Fd of io uring
 func (r *Ring) Fd() int {
 	return r.fd
 }
 
+// SQ Ring
 func (r *Ring) SQ() SQRing {
 	return r.sq
 }
 
+// CQ Ring
 func (r *Ring) CQ() CQRing {
 	return r.cq
 }
diff --git a/options.go b/options.go
new file mode 100644
index 0000000..7b92259
--- /dev/null
+++ b/options.go
@@ -0,0 +1,12 @@
+package gouring
+
+// Option
+type Option func(p *IOUringParams)
+
+// SQThread option
+func SQThread(cpu, idleMS uint32) Option {
+	return func(p *IOUringParams) {
+		p.SQThreadCPU = cpu
+		p.SQThreadIdle = idleMS
+	}
+}

From 76ea6c66e80b187798f6873a8595c2f5d6d535f3 Mon Sep 17 00:00:00 2001
From: Nugraha <26342994+ii64@users.noreply.github.com>
Date: Thu, 10 Feb 2022 00:55:02 +0700
Subject: [PATCH 09/14] feat(syscall): simplify sq initialization

Signed-off-by: Nugraha <26342994+ii64@users.noreply.github.com>
---
 syscall/epoll.go   | 15 +++++++++++
 syscall/helper.go  |  9 +++++++
 syscall/io.go      | 64 ++++++++++++++++++++++++++++++++++++++++++++++
 syscall/io_test.go | 16 ++++++++++++
 4 files changed, 104 insertions(+)
 create mode 100644 syscall/epoll.go
 create mode 100644 syscall/helper.go
 create mode 100644 syscall/io.go
 create mode 100644 syscall/io_test.go

diff --git a/syscall/epoll.go b/syscall/epoll.go
new file mode 100644
index 0000000..6845624
--- /dev/null
+++ b/syscall/epoll.go
@@ -0,0 +1,15 @@
+package syscall
+
+import (
+	"syscall"
+
+	"github.com/ii64/gouring"
+)
+
+var _ = syscall.EpollCtl
+
+// EpollCtl
+func EpollCtl(sqe *gouring.SQEntry, epfd int, op int, fd int, event *syscall.EpollEvent) (err error) {
+	sqe.Opcode = gouring.IORING_OP_EPOLL_CTL
+	return nil
+}
diff --git a/syscall/helper.go b/syscall/helper.go
new file mode 100644
index 0000000..3cc57ba
--- /dev/null
+++ b/syscall/helper.go
@@ -0,0 +1,9 @@
+package syscall
+
+import (
+	"syscall"
+	_ "unsafe"
+)
+
+//go:linkname anyToSockaddr syscall.anyToSockaddr
+func anyToSockaddr(rsa *syscall.RawSockaddrAny) (syscall.Sockaddr, error)
diff --git a/syscall/io.go b/syscall/io.go
new file mode 100644
index 0000000..bd74af2
--- /dev/null
+++ b/syscall/io.go
@@ -0,0 +1,64 @@
+package syscall
+
+import (
+	"syscall"
+	"unsafe"
+
+	"github.com/ii64/gouring"
+)
+
+var (
+	_ = syscall.Accept
+
+	_ = syscall.Read
+	_ = syscall.Write
+
+	_ = syscall.Close
+)
+
+// Accept
+func Accept(sqe *gouring.SQEntry, lisFd int, raw *syscall.RawSockaddrAny) {
+	sqe.Opcode = gouring.IORING_OP_ACCEPT
+	sqe.Fd = int32(lisFd)
+	var len uintptr = syscall.SizeofSockaddrAny
+	*sqe.Addr2() = uint64(uintptr(unsafe.Pointer(&len)))
+	*sqe.Addr() = uint64(uintptr(unsafe.Pointer(raw)))
+}
+
+// Read
+func Read(sqe *gouring.SQEntry, fd int, b []byte) {
+	sqe.Opcode = gouring.IORING_OP_READ
+	sqe.Fd = int32(fd)
+	sqe.Len = uint32(len(b))
+	*sqe.Addr() = uint64(uintptr(unsafe.Pointer(&b[0])))
+}
+
+// Readv
+func Readv(sqe *gouring.SQEntry, fd int, iovs []syscall.Iovec) {
+	sqe.Opcode = gouring.IORING_OP_READV
+	sqe.Fd = int32(fd)
+	sqe.Len = uint32(len(iovs))
+	*sqe.Addr() = uint64(uintptr(unsafe.Pointer(&iovs[0])))
+}
+
+// Write
+func Write(sqe *gouring.SQEntry, fd int, b []byte) {
+	sqe.Opcode = gouring.IORING_OP_WRITE
+	sqe.Fd = int32(fd)
+	sqe.Len = uint32(len(b))
+	*sqe.Addr() = uint64(uintptr(unsafe.Pointer(&b[0])))
+}
+
+// Writev
+func Writev(sqe *gouring.SQEntry, fd int, iovs []syscall.Iovec) {
+	sqe.Opcode = gouring.IORING_OP_WRITEV
+	sqe.Fd = int32(fd)
+	sqe.Len = uint32(len(iovs))
+	*sqe.Addr() = uint64(uintptr(unsafe.Pointer(&iovs[0])))
+}
+
+// Close
+func Close(sqe *gouring.SQEntry, fd int) {
+	sqe.Opcode = gouring.IORING_OP_CLOSE
+	sqe.Fd = int32(fd)
+}
diff --git a/syscall/io_test.go b/syscall/io_test.go
new file mode 100644
index 0000000..c22e688
--- /dev/null
+++ b/syscall/io_test.go
@@ -0,0 +1,16 @@
+package syscall
+
+import (
+	"syscall"
+	"testing"
+	"unsafe"
+)
+
+func TestAccept(t *testing.T) {
+
+	var raw syscall.RawSockaddrAny
+
+	t.Logf("%d\n", unsafe.Sizeof(raw))
+
+	t.Fail()
+}

From 0d089ce00d8668e1d42cefb3249f66d6242332d1 Mon Sep 17 00:00:00 2001
From: Nugraha <26342994+ii64@users.noreply.github.com>
Date: Thu, 10 Feb 2022 01:48:41 +0700
Subject: [PATCH 10/14] chore: clean prints

Signed-off-by: Nugraha <26342994+ii64@users.noreply.github.com>
---
 mem_util.go | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/mem_util.go b/mem_util.go
index 8107e2b..7128c3c 100644
--- a/mem_util.go
+++ b/mem_util.go
@@ -1,7 +1,6 @@
 package gouring
 
 import (
-	"fmt"
 	"reflect"
 	"syscall"
 	"unsafe"
@@ -94,8 +93,6 @@ func setup(r *Ring, entries uint, parmas *IOUringParams) (ringFd int, err error)
 		Cap:  int(p.SQEntries),
 	}))
 
-	fmt.Printf("insp %+#v %+#v\n", len(sq.Event), cap(sq.Event))
-
 	// CQ
 
 	cq.Head = (*uint32)(unsafe.Pointer(cqRingPtr + uintptr(p.CQOff.Head)))
@@ -110,8 +107,6 @@ func setup(r *Ring, entries uint, parmas *IOUringParams) (ringFd int, err error)
 		Cap:  int(p.CQEntries),
 	}))
 
-	fmt.Printf("insp %+#v %+#v\n", len(cq.Event), cap(cq.Event))
-
 	return
 }
 

From c232c10e247c85c2a830d953dabb7766b7b467e8 Mon Sep 17 00:00:00 2001
From: Nugraha <26342994+ii64@users.noreply.github.com>
Date: Thu, 10 Feb 2022 01:49:12 +0700
Subject: [PATCH 11/14] chore: test code

Signed-off-by: Nugraha <26342994+ii64@users.noreply.github.com>
---
 syscall/io_test.go | 160 +++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 155 insertions(+), 5 deletions(-)

diff --git a/syscall/io_test.go b/syscall/io_test.go
index c22e688..b67ee5c 100644
--- a/syscall/io_test.go
+++ b/syscall/io_test.go
@@ -1,16 +1,166 @@
 package syscall
 
 import (
+	"bytes"
+	"fmt"
+	"os"
 	"syscall"
 	"testing"
-	"unsafe"
+	"time"
+
+	"github.com/ii64/gouring"
+	"github.com/ii64/gouring/queue"
+	"github.com/stretchr/testify/assert"
 )
 
-func TestAccept(t *testing.T) {
+func initRing(t *testing.T) (ring *gouring.Ring, q *queue.Queue, cq chan *gouring.CQEntry) {
+	ring, err := gouring.New(128, nil)
+	if err != nil {
+		panic(err)
+	}
+	q = queue.New(ring)
 
-	var raw syscall.RawSockaddrAny
+	cq = make(chan *gouring.CQEntry)
 
-	t.Logf("%d\n", unsafe.Sizeof(raw))
+	go q.RunPoll(true, 1, func(cqe *gouring.CQEntry) (err error) {
+		fmt.Printf("got cqe: %+#v\n", cqe)
+		cq <- cqe
+		return nil
+	})
 
-	t.Fail()
+	go func() {
+		<-time.After(5 * time.Second)
+		t.Logf("timeout")
+		t.Fail()
+	}()
+	return
+}
+
+// func TestAccept(t *testing.T) {
+// 	sqe := q.GetSQEntry()
+// }
+
+func TestRead(t *testing.T) {
+	ring, q, cq := initRing(t)
+	defer q.Close()
+	defer ring.Close()
+
+	var f *os.File
+	var err error
+	f, err = os.Open("/dev/urandom")
+	assert.NoError(t, err, "urandom")
+	fd := f.Fd()
+	defer f.Close()
+
+	b := make([]byte, 25)
+	ud := uint64(gouring.IORING_OP_READ)
+	sqe := q.GetSQEntry()
+	Read(sqe, int(fd), b)
+	sqe.UserData = ud
+
+	ret, err := q.Submit()
+	assert.NoError(t, err)
+	assert.Equal(t, 1, ret, "mismatch submit return value")
+
+	cqe := <-cq
+	assert.Equal(t, ud, cqe.UserData)
+	assert.Equal(t, len(b), int(cqe.Res))
+}
+
+func TestReadv(t *testing.T) {
+	ring, q, cq := initRing(t)
+	defer q.Close()
+	defer ring.Close()
+
+	var f *os.File
+	var err error
+	f, err = os.Open("/dev/urandom")
+	assert.NoError(t, err, "urandom")
+	fd := f.Fd()
+	defer f.Close()
+
+	bs := [][]byte{}
+	bN := 25
+	iovs := []syscall.Iovec{}
+	iovN := 5
+	for i := 0; i < iovN; i++ {
+		b := make([]byte, bN)
+		bs = append(bs, b)
+		iovs = append(iovs, syscall.Iovec{
+			Base: &b[0],
+			Len:  uint64(len(b)),
+		})
+	}
+
+	ud := uint64(gouring.IORING_OP_READV)
+	sqe := q.GetSQEntry()
+	Readv(sqe, int(fd), iovs)
+	sqe.UserData = ud
+
+	ret, err := q.Submit()
+	assert.NoError(t, err)
+	assert.Equal(t, 1, ret, "mismatch submit return value")
+
+	cqe := <-cq
+	assert.Equal(t, ud, cqe.UserData)
+	assert.Equal(t, bN*iovN, int(cqe.Res))
+
+	eb := make([]byte, bN)
+	for i := 0; i < iovN; i++ {
+		if bytes.Compare(bs[i], eb) == 0 {
+			assert.NotEqual(t, eb, bs[i], "read urandom")
+		}
+	}
+}
+
+func TestWrite(t *testing.T) {
+	ring, q, cq := initRing(t)
+	defer q.Close()
+	defer ring.Close()
+
+	wr := "hello"
+	ud := uint64(gouring.IORING_OP_WRITE)
+	sqe := q.GetSQEntry()
+	Write(sqe, syscall.Stdout, []byte(wr))
+	sqe.UserData = ud
+
+	ret, err := q.Submit()
+	assert.NoError(t, err)
+	assert.Equal(t, 1, ret, "mismatch submit return value")
+
+	cqe := <-cq
+	assert.Equal(t, ud, cqe.UserData)
+	assert.Equal(t, len(wr), int(cqe.Res))
+}
+
+func TestWritev(t *testing.T) {
+	ring, q, cq := initRing(t)
+	defer q.Close()
+	defer ring.Close()
+
+	wr := "hello\n"
+	bs := [][]byte{}
+	iovs := []syscall.Iovec{}
+	iovN := 5
+	for i := 0; i < iovN; i++ {
+		b := []byte(wr)
+		bs = append(bs, b)
+		iovs = append(iovs, syscall.Iovec{
+			Base: &b[0],
+			Len:  uint64(len(b)),
+		})
+	}
+
+	ud := uint64(gouring.IORING_OP_WRITEV)
+	sqe := q.GetSQEntry()
+	Writev(sqe, syscall.Stdout, iovs)
+	sqe.UserData = ud
+
+	ret, err := q.Submit()
+	assert.NoError(t, err)
+	assert.Equal(t, 1, ret, "mismatch submit retrun value")
+
+	cqe := <-cq
+	assert.Equal(t, ud, cqe.UserData)
+	assert.Equal(t, len(wr)*iovN, int(cqe.Res))
 }

From 50fd85fabcca883750e32fef5a2a3daf1634c0cd Mon Sep 17 00:00:00 2001
From: Nugraha <26342994+ii64@users.noreply.github.com>
Date: Thu, 10 Feb 2022 02:16:53 +0700
Subject: [PATCH 12/14] feat(syscall): add madvise, epollctl

Signed-off-by: Nugraha <26342994+ii64@users.noreply.github.com>
---
 syscall/epoll.go  |  8 ++++++--
 syscall/helper.go |  2 ++
 syscall/mem.go    | 25 +++++++++++++++++++++++++
 3 files changed, 33 insertions(+), 2 deletions(-)
 create mode 100644 syscall/mem.go

diff --git a/syscall/epoll.go b/syscall/epoll.go
index 6845624..cbc4b6b 100644
--- a/syscall/epoll.go
+++ b/syscall/epoll.go
@@ -2,6 +2,7 @@ package syscall
 
 import (
 	"syscall"
+	"unsafe"
 
 	"github.com/ii64/gouring"
 )
@@ -9,7 +10,10 @@ import (
 var _ = syscall.EpollCtl
 
 // EpollCtl
-func EpollCtl(sqe *gouring.SQEntry, epfd int, op int, fd int, event *syscall.EpollEvent) (err error) {
+func EpollCtl(sqe *gouring.SQEntry, epfd int, op int, fd int, event *syscall.EpollEvent) {
 	sqe.Opcode = gouring.IORING_OP_EPOLL_CTL
-	return nil
+	sqe.Fd = int32(epfd)
+	*sqe.Addr() = uint64(uintptr(unsafe.Pointer(event)))
+	sqe.Len = uint32(op)
+	*sqe.Offset() = uint64(fd)
 }
diff --git a/syscall/helper.go b/syscall/helper.go
index 3cc57ba..d33a49b 100644
--- a/syscall/helper.go
+++ b/syscall/helper.go
@@ -5,5 +5,7 @@ import (
 	_ "unsafe"
 )
 
+var _zero uintptr
+
 //go:linkname anyToSockaddr syscall.anyToSockaddr
 func anyToSockaddr(rsa *syscall.RawSockaddrAny) (syscall.Sockaddr, error)
diff --git a/syscall/mem.go b/syscall/mem.go
new file mode 100644
index 0000000..fbfc536
--- /dev/null
+++ b/syscall/mem.go
@@ -0,0 +1,25 @@
+package syscall
+
+import (
+	"syscall"
+	"unsafe"
+
+	"github.com/ii64/gouring"
+)
+
+var _ = syscall.Madvise
+
+// Madvise
+func Madvise(sqe *gouring.SQEntry, b []byte, advice int) {
+	var ptr unsafe.Pointer
+	if len(b) > 0 {
+		ptr = unsafe.Pointer(&b[0])
+	} else {
+		ptr = unsafe.Pointer(&_zero)
+	}
+	sqe.Opcode = gouring.IORING_OP_MADVISE
+	sqe.Fd = -1
+	*sqe.Addr() = uint64(uintptr(ptr))
+	sqe.Len = uint32(len(b))
+	*sqe.Offset() = 0
+}

From 04750112b39dc2554ebb2d555e6d6dbaf6fe2d5d Mon Sep 17 00:00:00 2001
From: Nugraha <26342994+ii64@users.noreply.github.com>
Date: Fri, 11 Feb 2022 19:51:12 +0700
Subject: [PATCH 13/14] fix(opcode): remove getdents and xattr opcode

https://github.com/ii64/gouring/pull/1/commits/c87f2013c02ab8a4bac092765423220b8bdf0634

Ref:
https://github.com/axboe/liburing/commit/918d8061ffdfdf253806a1e8e141c71644e678bd

Signed-off-by: Nugraha <26342994+ii64@users.noreply.github.com>
---
 const_value.go | 7 -------
 1 file changed, 7 deletions(-)

diff --git a/const_value.go b/const_value.go
index 0eaa353..2cc0f2e 100644
--- a/const_value.go
+++ b/const_value.go
@@ -84,13 +84,6 @@ const (
 	IORING_OP_SYMLINKAT
 	IORING_OP_LINKAT
 
-	// 5.16rc
-	IORING_OP_GETDENTS
-	IORING_OP_FSETXATTR
-	IORING_OP_SETXATTR
-	IORING_OP_FGETXATTR
-	IORING_OP_GETXATTR
-
 	/* this goes last, obviously */
 	IORING_OP_LAST
 )

From 6140a6ea1d38adb5a8a61990d117e0894b3692be Mon Sep 17 00:00:00 2001
From: Nugraha <26342994+ii64@users.noreply.github.com>
Date: Fri, 11 Feb 2022 19:54:24 +0700
Subject: [PATCH 14/14] fix: SQThread option should add IORING_SETUP_SQPOLL

Signed-off-by: Nugraha <26342994+ii64@users.noreply.github.com>
---
 options.go | 1 +
 1 file changed, 1 insertion(+)

diff --git a/options.go b/options.go
index 7b92259..80a111d 100644
--- a/options.go
+++ b/options.go
@@ -8,5 +8,6 @@ func SQThread(cpu, idleMS uint32) Option {
 	return func(p *IOUringParams) {
 		p.SQThreadCPU = cpu
 		p.SQThreadIdle = idleMS
+		p.Flags |= IORING_SETUP_SQPOLL
 	}
 }