aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEuAndreh <eu@euandre.org>2025-01-23 09:54:11 -0300
committerEuAndreh <eu@euandre.org>2025-01-23 11:36:44 -0300
commit5f6607152a96b85f1518028b8f1ee1ef1aefda75 (patch)
treebe54946ddb2510a317322a2660563c83cab2117c
parenttests/stm.go: Turn example into functional test (diff)
downloadstm-5f6607152a96b85f1518028b8f1ee1ef1aefda75.tar.gz
stm-5f6607152a96b85f1518028b8f1ee1ef1aefda75.tar.xz
Move benchmarks from tests/stm.go to tests/benchmarks/*
-rw-r--r--deps.mk180
l---------tests/benchmarks/allow-n/main.go1
-rw-r--r--tests/benchmarks/allow-n/stm.go31
-rw-r--r--tests/benchmarks/atomic-set/stm.go4
l---------tests/benchmarks/deref/main.go1
-rw-r--r--tests/benchmarks/deref/stm.go23
l---------tests/benchmarks/increment-channel/main.go1
-rw-r--r--tests/benchmarks/increment-channel/stm.go35
l---------tests/benchmarks/increment-mutex/main.go1
-rw-r--r--tests/benchmarks/increment-mutex/stm.go43
l---------tests/benchmarks/increment-stm/main.go1
-rw-r--r--tests/benchmarks/increment-stm/stm.go33
l---------tests/benchmarks/int64-add64/main.go1
-rw-r--r--tests/benchmarks/int64-add64/stm.go23
l---------tests/benchmarks/interface-add64/main.go1
-rw-r--r--tests/benchmarks/interface-add64/stm.go23
l---------tests/benchmarks/interface-store/main.go1
-rw-r--r--tests/benchmarks/interface-store/stm.go24
l---------tests/benchmarks/inverted-thundering-herd/main.go1
-rw-r--r--tests/benchmarks/inverted-thundering-herd/stm.go74
l---------tests/benchmarks/ping-pong-4/main.go1
-rw-r--r--tests/benchmarks/ping-pong-4/stm.go64
l---------tests/benchmarks/ping-pong/main.go1
-rw-r--r--tests/benchmarks/ping-pong/stm.go59
l---------tests/benchmarks/read-var-channel/main.go1
-rw-r--r--tests/benchmarks/read-var-channel/stm.go33
l---------tests/benchmarks/read-var-mutex/main.go1
-rw-r--r--tests/benchmarks/read-var-mutex/stm.go35
l---------tests/benchmarks/read-var-stm/main.go1
-rw-r--r--tests/benchmarks/read-var-stm/stm.go32
l---------tests/benchmarks/stdlib-add64/main.go1
-rw-r--r--tests/benchmarks/stdlib-add64/stm.go24
l---------tests/benchmarks/stdlib-value-store/main.go1
-rw-r--r--tests/benchmarks/stdlib-value-store/stm.go25
l---------tests/benchmarks/thundering-herd-cond-var/main.go1
-rw-r--r--tests/benchmarks/thundering-herd-cond-var/stm.go64
l---------tests/benchmarks/thundering-herd/main.go1
-rw-r--r--tests/benchmarks/thundering-herd/stm.go56
l---------tests/benchmarks/value-store/main.go1
-rw-r--r--tests/benchmarks/value-store/stm.go24
l---------tests/benchmarks/wait-n-no-delay/main.go1
-rw-r--r--tests/benchmarks/wait-n-no-delay/stm.go32
-rw-r--r--tests/stm.go405
43 files changed, 977 insertions, 389 deletions
diff --git a/deps.mk b/deps.mk
index 4c45087..bdbc7e0 100644
--- a/deps.mk
+++ b/deps.mk
@@ -1,13 +1,53 @@
libs.go = \
src/stm.go \
+ tests/benchmarks/allow-n/stm.go \
tests/benchmarks/atomic-set/stm.go \
+ tests/benchmarks/deref/stm.go \
+ tests/benchmarks/increment-channel/stm.go \
+ tests/benchmarks/increment-mutex/stm.go \
+ tests/benchmarks/increment-stm/stm.go \
+ tests/benchmarks/int64-add64/stm.go \
+ tests/benchmarks/interface-add64/stm.go \
+ tests/benchmarks/interface-store/stm.go \
+ tests/benchmarks/inverted-thundering-herd/stm.go \
+ tests/benchmarks/ping-pong-4/stm.go \
+ tests/benchmarks/ping-pong/stm.go \
+ tests/benchmarks/read-var-channel/stm.go \
+ tests/benchmarks/read-var-mutex/stm.go \
+ tests/benchmarks/read-var-stm/stm.go \
+ tests/benchmarks/stdlib-add64/stm.go \
+ tests/benchmarks/stdlib-value-store/stm.go \
+ tests/benchmarks/thundering-herd-cond-var/stm.go \
+ tests/benchmarks/thundering-herd/stm.go \
+ tests/benchmarks/value-store/stm.go \
+ tests/benchmarks/wait-n-no-delay/stm.go \
tests/functional/santa-claus/stm.go \
tests/functional/usage/stm.go \
tests/fuzz/api/stm.go \
tests/stm.go \
mains.go = \
+ tests/benchmarks/allow-n/main.go \
tests/benchmarks/atomic-set/main.go \
+ tests/benchmarks/deref/main.go \
+ tests/benchmarks/increment-channel/main.go \
+ tests/benchmarks/increment-mutex/main.go \
+ tests/benchmarks/increment-stm/main.go \
+ tests/benchmarks/int64-add64/main.go \
+ tests/benchmarks/interface-add64/main.go \
+ tests/benchmarks/interface-store/main.go \
+ tests/benchmarks/inverted-thundering-herd/main.go \
+ tests/benchmarks/ping-pong-4/main.go \
+ tests/benchmarks/ping-pong/main.go \
+ tests/benchmarks/read-var-channel/main.go \
+ tests/benchmarks/read-var-mutex/main.go \
+ tests/benchmarks/read-var-stm/main.go \
+ tests/benchmarks/stdlib-add64/main.go \
+ tests/benchmarks/stdlib-value-store/main.go \
+ tests/benchmarks/thundering-herd-cond-var/main.go \
+ tests/benchmarks/thundering-herd/main.go \
+ tests/benchmarks/value-store/main.go \
+ tests/benchmarks/wait-n-no-delay/main.go \
tests/functional/santa-claus/main.go \
tests/functional/usage/main.go \
tests/fuzz/api/main.go \
@@ -28,14 +68,94 @@ fuzz-targets/main.go = \
tests/fuzz/api/main.go \
benchmarks/lib.go = \
+ tests/benchmarks/allow-n/stm.go \
tests/benchmarks/atomic-set/stm.go \
+ tests/benchmarks/deref/stm.go \
+ tests/benchmarks/increment-channel/stm.go \
+ tests/benchmarks/increment-mutex/stm.go \
+ tests/benchmarks/increment-stm/stm.go \
+ tests/benchmarks/int64-add64/stm.go \
+ tests/benchmarks/interface-add64/stm.go \
+ tests/benchmarks/interface-store/stm.go \
+ tests/benchmarks/inverted-thundering-herd/stm.go \
+ tests/benchmarks/ping-pong-4/stm.go \
+ tests/benchmarks/ping-pong/stm.go \
+ tests/benchmarks/read-var-channel/stm.go \
+ tests/benchmarks/read-var-mutex/stm.go \
+ tests/benchmarks/read-var-stm/stm.go \
+ tests/benchmarks/stdlib-add64/stm.go \
+ tests/benchmarks/stdlib-value-store/stm.go \
+ tests/benchmarks/thundering-herd-cond-var/stm.go \
+ tests/benchmarks/thundering-herd/stm.go \
+ tests/benchmarks/value-store/stm.go \
+ tests/benchmarks/wait-n-no-delay/stm.go \
benchmarks/main.go = \
+ tests/benchmarks/allow-n/main.go \
tests/benchmarks/atomic-set/main.go \
+ tests/benchmarks/deref/main.go \
+ tests/benchmarks/increment-channel/main.go \
+ tests/benchmarks/increment-mutex/main.go \
+ tests/benchmarks/increment-stm/main.go \
+ tests/benchmarks/int64-add64/main.go \
+ tests/benchmarks/interface-add64/main.go \
+ tests/benchmarks/interface-store/main.go \
+ tests/benchmarks/inverted-thundering-herd/main.go \
+ tests/benchmarks/ping-pong-4/main.go \
+ tests/benchmarks/ping-pong/main.go \
+ tests/benchmarks/read-var-channel/main.go \
+ tests/benchmarks/read-var-mutex/main.go \
+ tests/benchmarks/read-var-stm/main.go \
+ tests/benchmarks/stdlib-add64/main.go \
+ tests/benchmarks/stdlib-value-store/main.go \
+ tests/benchmarks/thundering-herd-cond-var/main.go \
+ tests/benchmarks/thundering-herd/main.go \
+ tests/benchmarks/value-store/main.go \
+ tests/benchmarks/wait-n-no-delay/main.go \
src/stm.a: src/stm.go
+tests/benchmarks/allow-n/main.a: tests/benchmarks/allow-n/main.go
+tests/benchmarks/allow-n/stm.a: tests/benchmarks/allow-n/stm.go
tests/benchmarks/atomic-set/main.a: tests/benchmarks/atomic-set/main.go
tests/benchmarks/atomic-set/stm.a: tests/benchmarks/atomic-set/stm.go
+tests/benchmarks/deref/main.a: tests/benchmarks/deref/main.go
+tests/benchmarks/deref/stm.a: tests/benchmarks/deref/stm.go
+tests/benchmarks/increment-channel/main.a: tests/benchmarks/increment-channel/main.go
+tests/benchmarks/increment-channel/stm.a: tests/benchmarks/increment-channel/stm.go
+tests/benchmarks/increment-mutex/main.a: tests/benchmarks/increment-mutex/main.go
+tests/benchmarks/increment-mutex/stm.a: tests/benchmarks/increment-mutex/stm.go
+tests/benchmarks/increment-stm/main.a: tests/benchmarks/increment-stm/main.go
+tests/benchmarks/increment-stm/stm.a: tests/benchmarks/increment-stm/stm.go
+tests/benchmarks/int64-add64/main.a: tests/benchmarks/int64-add64/main.go
+tests/benchmarks/int64-add64/stm.a: tests/benchmarks/int64-add64/stm.go
+tests/benchmarks/interface-add64/main.a: tests/benchmarks/interface-add64/main.go
+tests/benchmarks/interface-add64/stm.a: tests/benchmarks/interface-add64/stm.go
+tests/benchmarks/interface-store/main.a: tests/benchmarks/interface-store/main.go
+tests/benchmarks/interface-store/stm.a: tests/benchmarks/interface-store/stm.go
+tests/benchmarks/inverted-thundering-herd/main.a: tests/benchmarks/inverted-thundering-herd/main.go
+tests/benchmarks/inverted-thundering-herd/stm.a: tests/benchmarks/inverted-thundering-herd/stm.go
+tests/benchmarks/ping-pong-4/main.a: tests/benchmarks/ping-pong-4/main.go
+tests/benchmarks/ping-pong-4/stm.a: tests/benchmarks/ping-pong-4/stm.go
+tests/benchmarks/ping-pong/main.a: tests/benchmarks/ping-pong/main.go
+tests/benchmarks/ping-pong/stm.a: tests/benchmarks/ping-pong/stm.go
+tests/benchmarks/read-var-channel/main.a: tests/benchmarks/read-var-channel/main.go
+tests/benchmarks/read-var-channel/stm.a: tests/benchmarks/read-var-channel/stm.go
+tests/benchmarks/read-var-mutex/main.a: tests/benchmarks/read-var-mutex/main.go
+tests/benchmarks/read-var-mutex/stm.a: tests/benchmarks/read-var-mutex/stm.go
+tests/benchmarks/read-var-stm/main.a: tests/benchmarks/read-var-stm/main.go
+tests/benchmarks/read-var-stm/stm.a: tests/benchmarks/read-var-stm/stm.go
+tests/benchmarks/stdlib-add64/main.a: tests/benchmarks/stdlib-add64/main.go
+tests/benchmarks/stdlib-add64/stm.a: tests/benchmarks/stdlib-add64/stm.go
+tests/benchmarks/stdlib-value-store/main.a: tests/benchmarks/stdlib-value-store/main.go
+tests/benchmarks/stdlib-value-store/stm.a: tests/benchmarks/stdlib-value-store/stm.go
+tests/benchmarks/thundering-herd-cond-var/main.a: tests/benchmarks/thundering-herd-cond-var/main.go
+tests/benchmarks/thundering-herd-cond-var/stm.a: tests/benchmarks/thundering-herd-cond-var/stm.go
+tests/benchmarks/thundering-herd/main.a: tests/benchmarks/thundering-herd/main.go
+tests/benchmarks/thundering-herd/stm.a: tests/benchmarks/thundering-herd/stm.go
+tests/benchmarks/value-store/main.a: tests/benchmarks/value-store/main.go
+tests/benchmarks/value-store/stm.a: tests/benchmarks/value-store/stm.go
+tests/benchmarks/wait-n-no-delay/main.a: tests/benchmarks/wait-n-no-delay/main.go
+tests/benchmarks/wait-n-no-delay/stm.a: tests/benchmarks/wait-n-no-delay/stm.go
tests/functional/santa-claus/main.a: tests/functional/santa-claus/main.go
tests/functional/santa-claus/stm.a: tests/functional/santa-claus/stm.go
tests/functional/usage/main.a: tests/functional/usage/main.go
@@ -44,17 +164,77 @@ tests/fuzz/api/main.a: tests/fuzz/api/main.go
tests/fuzz/api/stm.a: tests/fuzz/api/stm.go
tests/main.a: tests/main.go
tests/stm.a: tests/stm.go
+tests/benchmarks/allow-n/main.bin: tests/benchmarks/allow-n/main.a
tests/benchmarks/atomic-set/main.bin: tests/benchmarks/atomic-set/main.a
+tests/benchmarks/deref/main.bin: tests/benchmarks/deref/main.a
+tests/benchmarks/increment-channel/main.bin: tests/benchmarks/increment-channel/main.a
+tests/benchmarks/increment-mutex/main.bin: tests/benchmarks/increment-mutex/main.a
+tests/benchmarks/increment-stm/main.bin: tests/benchmarks/increment-stm/main.a
+tests/benchmarks/int64-add64/main.bin: tests/benchmarks/int64-add64/main.a
+tests/benchmarks/interface-add64/main.bin: tests/benchmarks/interface-add64/main.a
+tests/benchmarks/interface-store/main.bin: tests/benchmarks/interface-store/main.a
+tests/benchmarks/inverted-thundering-herd/main.bin: tests/benchmarks/inverted-thundering-herd/main.a
+tests/benchmarks/ping-pong-4/main.bin: tests/benchmarks/ping-pong-4/main.a
+tests/benchmarks/ping-pong/main.bin: tests/benchmarks/ping-pong/main.a
+tests/benchmarks/read-var-channel/main.bin: tests/benchmarks/read-var-channel/main.a
+tests/benchmarks/read-var-mutex/main.bin: tests/benchmarks/read-var-mutex/main.a
+tests/benchmarks/read-var-stm/main.bin: tests/benchmarks/read-var-stm/main.a
+tests/benchmarks/stdlib-add64/main.bin: tests/benchmarks/stdlib-add64/main.a
+tests/benchmarks/stdlib-value-store/main.bin: tests/benchmarks/stdlib-value-store/main.a
+tests/benchmarks/thundering-herd-cond-var/main.bin: tests/benchmarks/thundering-herd-cond-var/main.a
+tests/benchmarks/thundering-herd/main.bin: tests/benchmarks/thundering-herd/main.a
+tests/benchmarks/value-store/main.bin: tests/benchmarks/value-store/main.a
+tests/benchmarks/wait-n-no-delay/main.bin: tests/benchmarks/wait-n-no-delay/main.a
tests/functional/santa-claus/main.bin: tests/functional/santa-claus/main.a
tests/functional/usage/main.bin: tests/functional/usage/main.a
tests/fuzz/api/main.bin: tests/fuzz/api/main.a
tests/main.bin: tests/main.a
+tests/benchmarks/allow-n/main.bin-check: tests/benchmarks/allow-n/main.bin
tests/benchmarks/atomic-set/main.bin-check: tests/benchmarks/atomic-set/main.bin
+tests/benchmarks/deref/main.bin-check: tests/benchmarks/deref/main.bin
+tests/benchmarks/increment-channel/main.bin-check: tests/benchmarks/increment-channel/main.bin
+tests/benchmarks/increment-mutex/main.bin-check: tests/benchmarks/increment-mutex/main.bin
+tests/benchmarks/increment-stm/main.bin-check: tests/benchmarks/increment-stm/main.bin
+tests/benchmarks/int64-add64/main.bin-check: tests/benchmarks/int64-add64/main.bin
+tests/benchmarks/interface-add64/main.bin-check: tests/benchmarks/interface-add64/main.bin
+tests/benchmarks/interface-store/main.bin-check: tests/benchmarks/interface-store/main.bin
+tests/benchmarks/inverted-thundering-herd/main.bin-check: tests/benchmarks/inverted-thundering-herd/main.bin
+tests/benchmarks/ping-pong-4/main.bin-check: tests/benchmarks/ping-pong-4/main.bin
+tests/benchmarks/ping-pong/main.bin-check: tests/benchmarks/ping-pong/main.bin
+tests/benchmarks/read-var-channel/main.bin-check: tests/benchmarks/read-var-channel/main.bin
+tests/benchmarks/read-var-mutex/main.bin-check: tests/benchmarks/read-var-mutex/main.bin
+tests/benchmarks/read-var-stm/main.bin-check: tests/benchmarks/read-var-stm/main.bin
+tests/benchmarks/stdlib-add64/main.bin-check: tests/benchmarks/stdlib-add64/main.bin
+tests/benchmarks/stdlib-value-store/main.bin-check: tests/benchmarks/stdlib-value-store/main.bin
+tests/benchmarks/thundering-herd-cond-var/main.bin-check: tests/benchmarks/thundering-herd-cond-var/main.bin
+tests/benchmarks/thundering-herd/main.bin-check: tests/benchmarks/thundering-herd/main.bin
+tests/benchmarks/value-store/main.bin-check: tests/benchmarks/value-store/main.bin
+tests/benchmarks/wait-n-no-delay/main.bin-check: tests/benchmarks/wait-n-no-delay/main.bin
tests/functional/santa-claus/main.bin-check: tests/functional/santa-claus/main.bin
tests/functional/usage/main.bin-check: tests/functional/usage/main.bin
tests/fuzz/api/main.bin-check: tests/fuzz/api/main.bin
tests/main.bin-check: tests/main.bin
+tests/benchmarks/allow-n/main.a: tests/benchmarks/allow-n/$(NAME).a
tests/benchmarks/atomic-set/main.a: tests/benchmarks/atomic-set/$(NAME).a
+tests/benchmarks/deref/main.a: tests/benchmarks/deref/$(NAME).a
+tests/benchmarks/increment-channel/main.a: tests/benchmarks/increment-channel/$(NAME).a
+tests/benchmarks/increment-mutex/main.a: tests/benchmarks/increment-mutex/$(NAME).a
+tests/benchmarks/increment-stm/main.a: tests/benchmarks/increment-stm/$(NAME).a
+tests/benchmarks/int64-add64/main.a: tests/benchmarks/int64-add64/$(NAME).a
+tests/benchmarks/interface-add64/main.a: tests/benchmarks/interface-add64/$(NAME).a
+tests/benchmarks/interface-store/main.a: tests/benchmarks/interface-store/$(NAME).a
+tests/benchmarks/inverted-thundering-herd/main.a: tests/benchmarks/inverted-thundering-herd/$(NAME).a
+tests/benchmarks/ping-pong-4/main.a: tests/benchmarks/ping-pong-4/$(NAME).a
+tests/benchmarks/ping-pong/main.a: tests/benchmarks/ping-pong/$(NAME).a
+tests/benchmarks/read-var-channel/main.a: tests/benchmarks/read-var-channel/$(NAME).a
+tests/benchmarks/read-var-mutex/main.a: tests/benchmarks/read-var-mutex/$(NAME).a
+tests/benchmarks/read-var-stm/main.a: tests/benchmarks/read-var-stm/$(NAME).a
+tests/benchmarks/stdlib-add64/main.a: tests/benchmarks/stdlib-add64/$(NAME).a
+tests/benchmarks/stdlib-value-store/main.a: tests/benchmarks/stdlib-value-store/$(NAME).a
+tests/benchmarks/thundering-herd-cond-var/main.a: tests/benchmarks/thundering-herd-cond-var/$(NAME).a
+tests/benchmarks/thundering-herd/main.a: tests/benchmarks/thundering-herd/$(NAME).a
+tests/benchmarks/value-store/main.a: tests/benchmarks/value-store/$(NAME).a
+tests/benchmarks/wait-n-no-delay/main.a: tests/benchmarks/wait-n-no-delay/$(NAME).a
tests/functional/santa-claus/main.a: tests/functional/santa-claus/$(NAME).a
tests/functional/usage/main.a: tests/functional/usage/$(NAME).a
tests/fuzz/api/main.a: tests/fuzz/api/$(NAME).a
diff --git a/tests/benchmarks/allow-n/main.go b/tests/benchmarks/allow-n/main.go
new file mode 120000
index 0000000..f67563d
--- /dev/null
+++ b/tests/benchmarks/allow-n/main.go
@@ -0,0 +1 @@
+../../main.go \ No newline at end of file
diff --git a/tests/benchmarks/allow-n/stm.go b/tests/benchmarks/allow-n/stm.go
new file mode 100644
index 0000000..2b0b342
--- /dev/null
+++ b/tests/benchmarks/allow-n/stm.go
@@ -0,0 +1,31 @@
+package stm
+
+import (
+ "flag"
+ "time"
+ "sync"
+)
+
+
+
+var nFlag = flag.Int(
+ "n",
+ 1_000,
+ "The number of iterations to execute",
+)
+
+func MainTest() {
+ flag.Parse()
+ n := *nFlag
+
+ var wg sync.WaitGroup
+ wg.Add(n)
+ lim := NewLimiter(Every(1*time.Second), 1)
+ for i := 0; i < n; i++ {
+ go func() {
+ lim.AllowN(1)
+ wg.Done()
+ }()
+ }
+ wg.Wait()
+}
diff --git a/tests/benchmarks/atomic-set/stm.go b/tests/benchmarks/atomic-set/stm.go
index 24aa95d..8c8f8c5 100644
--- a/tests/benchmarks/atomic-set/stm.go
+++ b/tests/benchmarks/atomic-set/stm.go
@@ -2,7 +2,6 @@ package stm
import (
"flag"
- "time"
)
@@ -17,7 +16,8 @@ func MainTest() {
flag.Parse()
n := *nFlag
+ v := NewVar(0)
for i := 0; i < n; i++ {
- time.Sleep(time.Millisecond * 1)
+ AtomicSet(v, 0)
}
}
diff --git a/tests/benchmarks/deref/main.go b/tests/benchmarks/deref/main.go
new file mode 120000
index 0000000..f67563d
--- /dev/null
+++ b/tests/benchmarks/deref/main.go
@@ -0,0 +1 @@
+../../main.go \ No newline at end of file
diff --git a/tests/benchmarks/deref/stm.go b/tests/benchmarks/deref/stm.go
new file mode 100644
index 0000000..6854397
--- /dev/null
+++ b/tests/benchmarks/deref/stm.go
@@ -0,0 +1,23 @@
+package stm
+
+import (
+ "flag"
+)
+
+
+
+var nFlag = flag.Int(
+ "n",
+ 1_000,
+ "The number of iterations to execute",
+)
+
+func MainTest() {
+ flag.Parse()
+ n := *nFlag
+
+ v := NewVar(0)
+ for i := 0; i < n; i++ {
+ Deref(v)
+ }
+}
diff --git a/tests/benchmarks/increment-channel/main.go b/tests/benchmarks/increment-channel/main.go
new file mode 120000
index 0000000..f67563d
--- /dev/null
+++ b/tests/benchmarks/increment-channel/main.go
@@ -0,0 +1 @@
+../../main.go \ No newline at end of file
diff --git a/tests/benchmarks/increment-channel/stm.go b/tests/benchmarks/increment-channel/stm.go
new file mode 100644
index 0000000..0d17a86
--- /dev/null
+++ b/tests/benchmarks/increment-channel/stm.go
@@ -0,0 +1,35 @@
+package stm
+
+import (
+ "flag"
+)
+
+
+
+var nFlag = flag.Int(
+ "n",
+ 1_000,
+ "The number of iterations to execute",
+)
+
+func MainTest() {
+ flag.Parse()
+ n := *nFlag
+
+ for i := 0; i < n; i++ {
+ c := make(chan int, 1)
+ c <- 0
+ for i := 0; i < 1000; i++ {
+ go func() {
+ c <- 1 + <-c
+ }()
+ }
+ for {
+ read := <-c
+ if read == 1000 {
+ break
+ }
+ c <- read
+ }
+ }
+}
diff --git a/tests/benchmarks/increment-mutex/main.go b/tests/benchmarks/increment-mutex/main.go
new file mode 120000
index 0000000..f67563d
--- /dev/null
+++ b/tests/benchmarks/increment-mutex/main.go
@@ -0,0 +1 @@
+../../main.go \ No newline at end of file
diff --git a/tests/benchmarks/increment-mutex/stm.go b/tests/benchmarks/increment-mutex/stm.go
new file mode 100644
index 0000000..9a442a5
--- /dev/null
+++ b/tests/benchmarks/increment-mutex/stm.go
@@ -0,0 +1,43 @@
+package stm
+
+import (
+ "flag"
+ "sync"
+)
+
+
+
+var nFlag = flag.Int(
+ "n",
+ 1_000,
+ "The number of iterations to execute",
+)
+
+func MainTest() {
+ flag.Parse()
+ n := *nFlag
+
+ for i := 0; i < n; i++ {
+ v := 0
+ var mu sync.Mutex
+ for i := 0; i < 1000; i++ {
+ go func() {
+ mu.Lock()
+ defer mu.Unlock()
+ v++
+ }()
+ }
+
+ for {
+ var read int
+ func() {
+ mu.Lock()
+ defer mu.Unlock()
+ read = v
+ }()
+ if read == 1000 {
+ break
+ }
+ }
+ }
+}
diff --git a/tests/benchmarks/increment-stm/main.go b/tests/benchmarks/increment-stm/main.go
new file mode 120000
index 0000000..f67563d
--- /dev/null
+++ b/tests/benchmarks/increment-stm/main.go
@@ -0,0 +1 @@
+../../main.go \ No newline at end of file
diff --git a/tests/benchmarks/increment-stm/stm.go b/tests/benchmarks/increment-stm/stm.go
new file mode 100644
index 0000000..9f12eb1
--- /dev/null
+++ b/tests/benchmarks/increment-stm/stm.go
@@ -0,0 +1,33 @@
+package stm
+
+import (
+ "flag"
+)
+
+
+
+var nFlag = flag.Int(
+ "n",
+ 1_000,
+ "The number of iterations to execute",
+)
+
+func MainTest() {
+ flag.Parse()
+ n := *nFlag
+
+ for i := 0; i < n; i++ {
+ // swap 1000 goroutines that each increment v by 1
+ v := NewVar(0)
+ for i := 0; i < 1000; i++ {
+ go Atomically(VoidOperation(func(tx *Tx) {
+ v.Set(tx, v.Get(tx) + 1)
+ }))
+ }
+
+ // wait for v to reach 1000
+ Atomically(VoidOperation(func(tx *Tx) {
+ tx.Assert(v.Get(tx) == 1000)
+ }))
+ }
+}
diff --git a/tests/benchmarks/int64-add64/main.go b/tests/benchmarks/int64-add64/main.go
new file mode 120000
index 0000000..f67563d
--- /dev/null
+++ b/tests/benchmarks/int64-add64/main.go
@@ -0,0 +1 @@
+../../main.go \ No newline at end of file
diff --git a/tests/benchmarks/int64-add64/stm.go b/tests/benchmarks/int64-add64/stm.go
new file mode 100644
index 0000000..8e225c9
--- /dev/null
+++ b/tests/benchmarks/int64-add64/stm.go
@@ -0,0 +1,23 @@
+package stm
+
+import (
+ "flag"
+)
+
+
+
+var nFlag = flag.Int(
+ "n",
+ 1_000,
+ "The number of iterations to execute",
+)
+
+func MainTest() {
+ flag.Parse()
+ n := *nFlag
+
+ v := NewInt64(0)
+ for i := 0; i < n; i++ {
+ v.Add(1)
+ }
+}
diff --git a/tests/benchmarks/interface-add64/main.go b/tests/benchmarks/interface-add64/main.go
new file mode 120000
index 0000000..f67563d
--- /dev/null
+++ b/tests/benchmarks/interface-add64/main.go
@@ -0,0 +1 @@
+../../main.go \ No newline at end of file
diff --git a/tests/benchmarks/interface-add64/stm.go b/tests/benchmarks/interface-add64/stm.go
new file mode 100644
index 0000000..a6e95a3
--- /dev/null
+++ b/tests/benchmarks/interface-add64/stm.go
@@ -0,0 +1,23 @@
+package stm
+
+import (
+ "flag"
+)
+
+
+
+var nFlag = flag.Int(
+ "n",
+ 1_000,
+ "The number of iterations to execute",
+)
+
+func MainTest() {
+ flag.Parse()
+ n := *nFlag
+
+ var v Int[int64] = NewInt64(0)
+ for i := 0; i < n; i++ {
+ v.Add(1)
+ }
+}
diff --git a/tests/benchmarks/interface-store/main.go b/tests/benchmarks/interface-store/main.go
new file mode 120000
index 0000000..f67563d
--- /dev/null
+++ b/tests/benchmarks/interface-store/main.go
@@ -0,0 +1 @@
+../../main.go \ No newline at end of file
diff --git a/tests/benchmarks/interface-store/stm.go b/tests/benchmarks/interface-store/stm.go
new file mode 100644
index 0000000..8e9a36b
--- /dev/null
+++ b/tests/benchmarks/interface-store/stm.go
@@ -0,0 +1,24 @@
+package stm
+
+import (
+ "flag"
+ "fmt"
+)
+
+
+
+var nFlag = flag.Int(
+ "n",
+ 1_000,
+ "The number of iterations to execute",
+)
+
+func MainTest() {
+ flag.Parse()
+ n := *nFlag
+
+ var v Interface[string] = New("hello")
+ for i := 0; i < n; i++ {
+ v.Store(fmt.Sprint(i))
+ }
+}
diff --git a/tests/benchmarks/inverted-thundering-herd/main.go b/tests/benchmarks/inverted-thundering-herd/main.go
new file mode 120000
index 0000000..f67563d
--- /dev/null
+++ b/tests/benchmarks/inverted-thundering-herd/main.go
@@ -0,0 +1 @@
+../../main.go \ No newline at end of file
diff --git a/tests/benchmarks/inverted-thundering-herd/stm.go b/tests/benchmarks/inverted-thundering-herd/stm.go
new file mode 100644
index 0000000..1f240db
--- /dev/null
+++ b/tests/benchmarks/inverted-thundering-herd/stm.go
@@ -0,0 +1,74 @@
+package stm
+
+import (
+ "flag"
+)
+
+
+
+const maxTokens = 25
+
+var nFlag = flag.Int(
+ "n",
+ 1_000,
+ "The number of iterations to execute",
+)
+
+func MainTest() {
+ flag.Parse()
+ n := *nFlag
+
+ for i := 0; i < n; i++ {
+ continue // FIXME
+ done := NewBuiltinEqVar(false)
+ tokens := NewBuiltinEqVar(0)
+ pending := NewVar(NewSet[*Var[bool]]())
+ for i := 0; i < 1000; i++ {
+ ready := NewVar(false)
+ Atomically(VoidOperation(func(tx *Tx) {
+ pending.Set(tx, pending.Get(tx).Add(ready))
+ }))
+ go func() {
+ Atomically(VoidOperation(func(tx *Tx) {
+ tx.Assert(ready.Get(tx))
+ set := pending.Get(tx)
+ if !set.Contains(ready) {
+ panic("couldn't find ourselves in pending")
+ }
+ pending.Set(tx, set.Delete(ready))
+ }))
+ //b.Log("waiter finished")
+ }()
+ }
+ go func() {
+ for Atomically(func(tx *Tx) bool {
+ if done.Get(tx) {
+ return false
+ }
+ tx.Assert(tokens.Get(tx) < maxTokens)
+ tokens.Set(tx, tokens.Get(tx)+1)
+ return true
+ }) {
+ }
+ }()
+ go func() {
+ for Atomically(func(tx *Tx) bool {
+ tx.Assert(tokens.Get(tx) > 0)
+ tokens.Set(tx, tokens.Get(tx)-1)
+ pending.Get(tx).Range(func(ready *Var[bool]) bool {
+ if !ready.Get(tx) {
+ ready.Set(tx, true)
+ return false
+ }
+ return true
+ })
+ return !done.Get(tx)
+ }) {
+ }
+ }()
+ Atomically(VoidOperation(func(tx *Tx) {
+ tx.Assert(pending.Get(tx).(Lenner).Len() == 0)
+ }))
+ AtomicSet(done, true)
+ }
+}
diff --git a/tests/benchmarks/ping-pong-4/main.go b/tests/benchmarks/ping-pong-4/main.go
new file mode 120000
index 0000000..f67563d
--- /dev/null
+++ b/tests/benchmarks/ping-pong-4/main.go
@@ -0,0 +1 @@
+../../main.go \ No newline at end of file
diff --git a/tests/benchmarks/ping-pong-4/stm.go b/tests/benchmarks/ping-pong-4/stm.go
new file mode 100644
index 0000000..467d371
--- /dev/null
+++ b/tests/benchmarks/ping-pong-4/stm.go
@@ -0,0 +1,64 @@
+package stm
+
+import (
+ "flag"
+ "sync"
+)
+
+
+
+func testPingPong(n int, afterHit func(string)) {
+ ball := NewBuiltinEqVar(false)
+ doneVar := NewVar(false)
+ hits := NewVar(0)
+ ready := NewVar(true) // The ball is ready for hitting.
+ var wg sync.WaitGroup
+ bat := func(from, to bool, noise string) {
+ defer wg.Done()
+ for !Atomically(func(tx *Tx) any {
+ if doneVar.Get(tx) {
+ return true
+ }
+ tx.Assert(ready.Get(tx))
+ if ball.Get(tx) == from {
+ ball.Set(tx, to)
+ hits.Set(tx, hits.Get(tx)+1)
+ ready.Set(tx, false)
+ return false
+ }
+ return tx.Retry()
+ }).(bool) {
+ afterHit(noise)
+ AtomicSet(ready, true)
+ }
+ }
+ wg.Add(2)
+ go bat(false, true, "ping!")
+ go bat(true, false, "pong!")
+ Atomically(VoidOperation(func(tx *Tx) {
+ tx.Assert(hits.Get(tx) >= n)
+ doneVar.Set(tx, true)
+ }))
+ wg.Wait()
+}
+
+var nFlag = flag.Int(
+ "n",
+ 1_000,
+ "The number of iterations to execute",
+)
+
+func MainTest() {
+ flag.Parse()
+ n := *nFlag
+
+ var wg sync.WaitGroup
+ wg.Add(n)
+ for i := 0; i < n; i++ {
+ go func() {
+ defer wg.Done()
+ testPingPong(n, func(string) {})
+ }()
+ }
+ wg.Wait()
+}
diff --git a/tests/benchmarks/ping-pong/main.go b/tests/benchmarks/ping-pong/main.go
new file mode 120000
index 0000000..f67563d
--- /dev/null
+++ b/tests/benchmarks/ping-pong/main.go
@@ -0,0 +1 @@
+../../main.go \ No newline at end of file
diff --git a/tests/benchmarks/ping-pong/stm.go b/tests/benchmarks/ping-pong/stm.go
new file mode 100644
index 0000000..6631ea8
--- /dev/null
+++ b/tests/benchmarks/ping-pong/stm.go
@@ -0,0 +1,59 @@
+package stm
+
+import (
+ "flag"
+ "sync"
+)
+
+
+
+func testPingPong(n int, afterHit func(string)) {
+ ball := NewBuiltinEqVar(false)
+ doneVar := NewVar(false)
+ hits := NewVar(0)
+ ready := NewVar(true) // The ball is ready for hitting.
+ var wg sync.WaitGroup
+ bat := func(from, to bool, noise string) {
+ defer wg.Done()
+ for !Atomically(func(tx *Tx) any {
+ if doneVar.Get(tx) {
+ return true
+ }
+ tx.Assert(ready.Get(tx))
+ if ball.Get(tx) == from {
+ ball.Set(tx, to)
+ hits.Set(tx, hits.Get(tx)+1)
+ ready.Set(tx, false)
+ return false
+ }
+ return tx.Retry()
+ }).(bool) {
+ afterHit(noise)
+ AtomicSet(ready, true)
+ }
+ }
+ wg.Add(2)
+ go bat(false, true, "ping!")
+ go bat(true, false, "pong!")
+ Atomically(VoidOperation(func(tx *Tx) {
+ tx.Assert(hits.Get(tx) >= n)
+ doneVar.Set(tx, true)
+ }))
+ wg.Wait()
+}
+
+
+var nFlag = flag.Int(
+ "n",
+ 1_000,
+ "The number of iterations to execute",
+)
+
+func MainTest() {
+ flag.Parse()
+ n := *nFlag
+
+ for i := 0; i < n; i++ {
+ testPingPong(n, func(string) {})
+ }
+}
diff --git a/tests/benchmarks/read-var-channel/main.go b/tests/benchmarks/read-var-channel/main.go
new file mode 120000
index 0000000..f67563d
--- /dev/null
+++ b/tests/benchmarks/read-var-channel/main.go
@@ -0,0 +1 @@
+../../main.go \ No newline at end of file
diff --git a/tests/benchmarks/read-var-channel/stm.go b/tests/benchmarks/read-var-channel/stm.go
new file mode 100644
index 0000000..080aefa
--- /dev/null
+++ b/tests/benchmarks/read-var-channel/stm.go
@@ -0,0 +1,33 @@
+package stm
+
+import (
+ "flag"
+ "sync"
+)
+
+
+
+var nFlag = flag.Int(
+ "n",
+ 1_000,
+ "The number of iterations to execute",
+)
+
+func MainTest() {
+ flag.Parse()
+ n := *nFlag
+
+ for i := 0; i < n; i++ {
+ var wg sync.WaitGroup
+ wg.Add(1000)
+ c := make(chan int)
+ close(c)
+ for i := 0; i < 1000; i++ {
+ go func() {
+ <-c
+ wg.Done()
+ }()
+ }
+ wg.Wait()
+ }
+}
diff --git a/tests/benchmarks/read-var-mutex/main.go b/tests/benchmarks/read-var-mutex/main.go
new file mode 120000
index 0000000..f67563d
--- /dev/null
+++ b/tests/benchmarks/read-var-mutex/main.go
@@ -0,0 +1 @@
+../../main.go \ No newline at end of file
diff --git a/tests/benchmarks/read-var-mutex/stm.go b/tests/benchmarks/read-var-mutex/stm.go
new file mode 100644
index 0000000..12dbf7e
--- /dev/null
+++ b/tests/benchmarks/read-var-mutex/stm.go
@@ -0,0 +1,35 @@
+package stm
+
+import (
+ "flag"
+ "sync"
+)
+
+
+
+var nFlag = flag.Int(
+ "n",
+ 1_000,
+ "The number of iterations to execute",
+)
+
+func MainTest() {
+ flag.Parse()
+ n := *nFlag
+
+ for i := 0; i < n; i++ {
+ var mu sync.Mutex
+ var wg sync.WaitGroup
+ wg.Add(1000)
+ v := 0
+ for i := 0; i < 1000; i++ {
+ go func() {
+ mu.Lock()
+ defer mu.Unlock()
+ _ = v
+ wg.Done()
+ }()
+ }
+ wg.Wait()
+ }
+}
diff --git a/tests/benchmarks/read-var-stm/main.go b/tests/benchmarks/read-var-stm/main.go
new file mode 120000
index 0000000..f67563d
--- /dev/null
+++ b/tests/benchmarks/read-var-stm/main.go
@@ -0,0 +1 @@
+../../main.go \ No newline at end of file
diff --git a/tests/benchmarks/read-var-stm/stm.go b/tests/benchmarks/read-var-stm/stm.go
new file mode 100644
index 0000000..6110bee
--- /dev/null
+++ b/tests/benchmarks/read-var-stm/stm.go
@@ -0,0 +1,32 @@
+package stm
+
+import (
+ "flag"
+ "sync"
+)
+
+
+
+var nFlag = flag.Int(
+ "n",
+ 1_000,
+ "The number of iterations to execute",
+)
+
+func MainTest() {
+ flag.Parse()
+ n := *nFlag
+
+ for i := 0; i < n; i++ {
+ var wg sync.WaitGroup
+ wg.Add(1000)
+ v := NewVar(0)
+ for i := 0; i < 1000; i++ {
+ go func() {
+ Deref(v)
+ wg.Done()
+ }()
+ }
+ wg.Wait()
+ }
+}
diff --git a/tests/benchmarks/stdlib-add64/main.go b/tests/benchmarks/stdlib-add64/main.go
new file mode 120000
index 0000000..f67563d
--- /dev/null
+++ b/tests/benchmarks/stdlib-add64/main.go
@@ -0,0 +1 @@
+../../main.go \ No newline at end of file
diff --git a/tests/benchmarks/stdlib-add64/stm.go b/tests/benchmarks/stdlib-add64/stm.go
new file mode 100644
index 0000000..6a1929c
--- /dev/null
+++ b/tests/benchmarks/stdlib-add64/stm.go
@@ -0,0 +1,24 @@
+package stm
+
+import (
+ "flag"
+ "sync/atomic"
+)
+
+
+
+var nFlag = flag.Int(
+ "n",
+ 1_000,
+ "The number of iterations to execute",
+)
+
+func MainTest() {
+ flag.Parse()
+ n := *nFlag
+
+ var v int64
+ for i := 0; i < n; i++ {
+ atomic.AddInt64(&v, 1)
+ }
+}
diff --git a/tests/benchmarks/stdlib-value-store/main.go b/tests/benchmarks/stdlib-value-store/main.go
new file mode 120000
index 0000000..f67563d
--- /dev/null
+++ b/tests/benchmarks/stdlib-value-store/main.go
@@ -0,0 +1 @@
+../../main.go \ No newline at end of file
diff --git a/tests/benchmarks/stdlib-value-store/stm.go b/tests/benchmarks/stdlib-value-store/stm.go
new file mode 100644
index 0000000..a5d3a01
--- /dev/null
+++ b/tests/benchmarks/stdlib-value-store/stm.go
@@ -0,0 +1,25 @@
+package stm
+
+import (
+ "flag"
+ "fmt"
+ "sync/atomic"
+)
+
+
+
+var nFlag = flag.Int(
+ "n",
+ 1_000,
+ "The number of iterations to execute",
+)
+
+func MainTest() {
+ flag.Parse()
+ n := *nFlag
+
+ v := atomic.Value{}
+ for i := 0; i < n; i++ {
+ v.Store(fmt.Sprint(i))
+ }
+}
diff --git a/tests/benchmarks/thundering-herd-cond-var/main.go b/tests/benchmarks/thundering-herd-cond-var/main.go
new file mode 120000
index 0000000..f67563d
--- /dev/null
+++ b/tests/benchmarks/thundering-herd-cond-var/main.go
@@ -0,0 +1 @@
+../../main.go \ No newline at end of file
diff --git a/tests/benchmarks/thundering-herd-cond-var/stm.go b/tests/benchmarks/thundering-herd-cond-var/stm.go
new file mode 100644
index 0000000..5ebf85b
--- /dev/null
+++ b/tests/benchmarks/thundering-herd-cond-var/stm.go
@@ -0,0 +1,64 @@
+package stm
+
+import (
+ "flag"
+ "sync"
+)
+
+
+
+var nFlag = flag.Int(
+ "n",
+ 1_000,
+ "The number of iterations to execute",
+)
+
+func MainTest() {
+ flag.Parse()
+ n := *nFlag
+
+ const maxTokens = 25
+
+ for i := 0; i < n; i++ {
+ var mu sync.Mutex
+ consumer := sync.NewCond(&mu)
+ generator := sync.NewCond(&mu)
+ done := false
+ tokens := 0
+ var pending sync.WaitGroup
+ for i := 0; i < 1000; i++ {
+ pending.Add(1)
+ go func() {
+ mu.Lock()
+ for {
+ if tokens > 0 {
+ tokens--
+ generator.Signal()
+ break
+ }
+ consumer.Wait()
+ }
+ mu.Unlock()
+ pending.Done()
+ }()
+ }
+ go func() {
+ mu.Lock()
+ for !done {
+ if tokens < maxTokens {
+ tokens++
+ consumer.Signal()
+ } else {
+ generator.Wait()
+ }
+ }
+ mu.Unlock()
+ }()
+ pending.Wait()
+ mu.Lock()
+ done = true
+ generator.Signal()
+ mu.Unlock()
+ }
+
+}
diff --git a/tests/benchmarks/thundering-herd/main.go b/tests/benchmarks/thundering-herd/main.go
new file mode 120000
index 0000000..f67563d
--- /dev/null
+++ b/tests/benchmarks/thundering-herd/main.go
@@ -0,0 +1 @@
+../../main.go \ No newline at end of file
diff --git a/tests/benchmarks/thundering-herd/stm.go b/tests/benchmarks/thundering-herd/stm.go
new file mode 100644
index 0000000..fa31938
--- /dev/null
+++ b/tests/benchmarks/thundering-herd/stm.go
@@ -0,0 +1,56 @@
+package stm
+
+import (
+ "flag"
+)
+
+
+
+var nFlag = flag.Int(
+ "n",
+ 1_000,
+ "The number of iterations to execute",
+)
+
+func MainTest() {
+ flag.Parse()
+ n := *nFlag
+
+ const maxTokens = 25
+ for i := 0; i < n; i++ {
+ done := NewBuiltinEqVar(false)
+ tokens := NewBuiltinEqVar(0)
+ pending := NewBuiltinEqVar(0)
+ for i := 0; i < 1000; i++ {
+ Atomically(VoidOperation(func(tx *Tx) {
+ pending.Set(tx, pending.Get(tx)+1)
+ }))
+ go func() {
+ Atomically(VoidOperation(func(tx *Tx) {
+ t := tokens.Get(tx)
+ if t > 0 {
+ tokens.Set(tx, t-1)
+ pending.Set(tx, pending.Get(tx)-1)
+ } else {
+ tx.Retry()
+ }
+ }))
+ }()
+ }
+ go func() {
+ for Atomically(func(tx *Tx) bool {
+ if done.Get(tx) {
+ return false
+ }
+ tx.Assert(tokens.Get(tx) < maxTokens)
+ tokens.Set(tx, tokens.Get(tx)+1)
+ return true
+ }) {
+ }
+ }()
+ Atomically(VoidOperation(func(tx *Tx) {
+ tx.Assert(pending.Get(tx) == 0)
+ }))
+ AtomicSet(done, true)
+ }
+}
diff --git a/tests/benchmarks/value-store/main.go b/tests/benchmarks/value-store/main.go
new file mode 120000
index 0000000..f67563d
--- /dev/null
+++ b/tests/benchmarks/value-store/main.go
@@ -0,0 +1 @@
+../../main.go \ No newline at end of file
diff --git a/tests/benchmarks/value-store/stm.go b/tests/benchmarks/value-store/stm.go
new file mode 100644
index 0000000..0d85750
--- /dev/null
+++ b/tests/benchmarks/value-store/stm.go
@@ -0,0 +1,24 @@
+package stm
+
+import (
+ "flag"
+ "fmt"
+)
+
+
+
+var nFlag = flag.Int(
+ "n",
+ 1_000,
+ "The number of iterations to execute",
+)
+
+func MainTest() {
+ flag.Parse()
+ n := *nFlag
+
+ v := New("hello")
+ for i := 0; i < n; i++ {
+ v.Store(fmt.Sprint(i))
+ }
+}
diff --git a/tests/benchmarks/wait-n-no-delay/main.go b/tests/benchmarks/wait-n-no-delay/main.go
new file mode 120000
index 0000000..f67563d
--- /dev/null
+++ b/tests/benchmarks/wait-n-no-delay/main.go
@@ -0,0 +1 @@
+../../main.go \ No newline at end of file
diff --git a/tests/benchmarks/wait-n-no-delay/stm.go b/tests/benchmarks/wait-n-no-delay/stm.go
new file mode 100644
index 0000000..97cac9a
--- /dev/null
+++ b/tests/benchmarks/wait-n-no-delay/stm.go
@@ -0,0 +1,32 @@
+package stm
+
+import (
+ "context"
+ "flag"
+ "sync"
+)
+
+
+
+var nFlag = flag.Int(
+ "n",
+ 1_000,
+ "The number of iterations to execute",
+)
+
+func MainTest() {
+ flag.Parse()
+ n := *nFlag
+
+ var wg sync.WaitGroup
+ wg.Add(n)
+ lim := NewLimiter(Limit(n), n)
+ ctx := context.Background()
+ for i := 0; i < n; i++ {
+ go func() {
+ lim.WaitN(ctx, 1)
+ wg.Done()
+ }()
+ }
+ wg.Wait()
+}
diff --git a/tests/stm.go b/tests/stm.go
index 49fcd25..13b375a 100644
--- a/tests/stm.go
+++ b/tests/stm.go
@@ -2,7 +2,6 @@ package stm
import (
"context"
- "fmt"
"math"
"runtime"
"sync"
@@ -15,6 +14,17 @@ import (
+const (
+ d = 100 * time.Millisecond
+)
+
+
+var (
+ t0 = time.Now()
+)
+
+
+
func TestValue(t *testing.T) {
v := New("hello")
g.TAssertEqual("hello", v.Load())
@@ -41,332 +51,6 @@ func TestInt32(t *testing.T) {
g.TAssertEqual(false, v.CompareAndSwap(0, 10))
}
-func BenchmarkInt64Add(b *testing.B) {
- v := NewInt64(0)
- for i := 0; i < b.N; i++ {
- v.Add(1)
- }
-}
-
-func BenchmarkIntInterfaceAdd(b *testing.B) {
- var v Int[int64] = NewInt64(0)
- for i := 0; i < b.N; i++ {
- v.Add(1)
- }
-}
-
-func BenchmarkStdlibInt64Add(b *testing.B) {
- var n int64
- for i := 0; i < b.N; i++ {
- atomic.AddInt64(&n, 1)
- }
-}
-
-func BenchmarkInterfaceStore(b *testing.B) {
- var v Interface[string] = New("hello")
- for i := 0; i < b.N; i++ {
- v.Store(fmt.Sprint(i))
- }
-}
-
-func BenchmarkValueStore(b *testing.B) {
- v := New("hello")
- for i := 0; i < b.N; i++ {
- v.Store(fmt.Sprint(i))
- }
-}
-
-func BenchmarkStdlibValueStore(b *testing.B) {
- v := atomic.Value{}
- for i := 0; i < b.N; i++ {
- v.Store(fmt.Sprint(i))
- }
-}
-
-func BenchmarkDeref(b *testing.B) {
- x := NewVar(0)
- for i := 0; i < b.N; i++ {
- Deref(x)
- }
-}
-
-func BenchmarkAtomicSet(b *testing.B) {
- x := NewVar(0)
- for i := 0; i < b.N; i++ {
- AtomicSet(x, 0)
- }
-}
-
-func BenchmarkIncrementSTM(b *testing.B) {
- for i := 0; i < b.N; i++ {
- // spawn 1000 goroutines that each increment x by 1
- x := NewVar(0)
- for i := 0; i < 1000; i++ {
- go Atomically(VoidOperation(func(tx *Tx) {
- cur := x.Get(tx)
- x.Set(tx, cur+1)
- }))
- }
- // wait for x to reach 1000
- Atomically(VoidOperation(func(tx *Tx) {
- tx.Assert(x.Get(tx) == 1000)
- }))
- }
-}
-
-func BenchmarkIncrementMutex(b *testing.B) {
- for i := 0; i < b.N; i++ {
- var mu sync.Mutex
- x := 0
- for i := 0; i < 1000; i++ {
- go func() {
- mu.Lock()
- x++
- mu.Unlock()
- }()
- }
- for {
- mu.Lock()
- read := x
- mu.Unlock()
- if read == 1000 {
- break
- }
- }
- }
-}
-
-func BenchmarkIncrementChannel(b *testing.B) {
- for i := 0; i < b.N; i++ {
- c := make(chan int, 1)
- c <- 0
- for i := 0; i < 1000; i++ {
- go func() {
- c <- 1 + <-c
- }()
- }
- for {
- read := <-c
- if read == 1000 {
- break
- }
- c <- read
- }
- }
-}
-
-func BenchmarkReadVarSTM(b *testing.B) {
- for i := 0; i < b.N; i++ {
- var wg sync.WaitGroup
- wg.Add(1000)
- x := NewVar(0)
- for i := 0; i < 1000; i++ {
- go func() {
- Deref(x)
- wg.Done()
- }()
- }
- wg.Wait()
- }
-}
-
-func BenchmarkReadVarMutex(b *testing.B) {
- for i := 0; i < b.N; i++ {
- var mu sync.Mutex
- var wg sync.WaitGroup
- wg.Add(1000)
- x := 0
- for i := 0; i < 1000; i++ {
- go func() {
- mu.Lock()
- _ = x
- mu.Unlock()
- wg.Done()
- }()
- }
- wg.Wait()
- }
-}
-
-func BenchmarkReadVarChannel(b *testing.B) {
- for i := 0; i < b.N; i++ {
- var wg sync.WaitGroup
- wg.Add(1000)
- c := make(chan int)
- close(c)
- for i := 0; i < 1000; i++ {
- go func() {
- <-c
- wg.Done()
- }()
- }
- wg.Wait()
- }
-}
-
-func parallelPingPongs(b *testing.B, n int) {
- var wg sync.WaitGroup
- wg.Add(n)
- for i := 0; i < n; i++ {
- go func() {
- defer wg.Done()
- testPingPong(b, b.N, func(string) {})
- }()
- }
- wg.Wait()
-}
-
-func BenchmarkPingPong4(b *testing.B) {
- b.ReportAllocs()
- parallelPingPongs(b, 4)
-}
-
-func BenchmarkPingPong(b *testing.B) {
- b.ReportAllocs()
- parallelPingPongs(b, 1)
-}
-
-const maxTokens = 25
-
-func BenchmarkThunderingHerdCondVar(b *testing.B) {
- for i := 0; i < b.N; i++ {
- var mu sync.Mutex
- consumer := sync.NewCond(&mu)
- generator := sync.NewCond(&mu)
- done := false
- tokens := 0
- var pending sync.WaitGroup
- for i := 0; i < 1000; i++ {
- pending.Add(1)
- go func() {
- mu.Lock()
- for {
- if tokens > 0 {
- tokens--
- generator.Signal()
- break
- }
- consumer.Wait()
- }
- mu.Unlock()
- pending.Done()
- }()
- }
- go func() {
- mu.Lock()
- for !done {
- if tokens < maxTokens {
- tokens++
- consumer.Signal()
- } else {
- generator.Wait()
- }
- }
- mu.Unlock()
- }()
- pending.Wait()
- mu.Lock()
- done = true
- generator.Signal()
- mu.Unlock()
- }
-
-}
-
-func BenchmarkThunderingHerd(b *testing.B) {
- for i := 0; i < b.N; i++ {
- done := NewBuiltinEqVar(false)
- tokens := NewBuiltinEqVar(0)
- pending := NewBuiltinEqVar(0)
- for i := 0; i < 1000; i++ {
- Atomically(VoidOperation(func(tx *Tx) {
- pending.Set(tx, pending.Get(tx)+1)
- }))
- go func() {
- Atomically(VoidOperation(func(tx *Tx) {
- t := tokens.Get(tx)
- if t > 0 {
- tokens.Set(tx, t-1)
- pending.Set(tx, pending.Get(tx)-1)
- } else {
- tx.Retry()
- }
- }))
- }()
- }
- go func() {
- for Atomically(func(tx *Tx) bool {
- if done.Get(tx) {
- return false
- }
- tx.Assert(tokens.Get(tx) < maxTokens)
- tokens.Set(tx, tokens.Get(tx)+1)
- return true
- }) {
- }
- }()
- Atomically(VoidOperation(func(tx *Tx) {
- tx.Assert(pending.Get(tx) == 0)
- }))
- AtomicSet(done, true)
- }
-}
-
-func BenchmarkInvertedThunderingHerd(b *testing.B) {
- for i := 0; i < b.N; i++ {
- done := NewBuiltinEqVar(false)
- tokens := NewBuiltinEqVar(0)
- pending := NewVar(NewSet[*Var[bool]]())
- for i := 0; i < 1000; i++ {
- ready := NewVar(false)
- Atomically(VoidOperation(func(tx *Tx) {
- pending.Set(tx, pending.Get(tx).Add(ready))
- }))
- go func() {
- Atomically(VoidOperation(func(tx *Tx) {
- tx.Assert(ready.Get(tx))
- set := pending.Get(tx)
- if !set.Contains(ready) {
- panic("couldn't find ourselves in pending")
- }
- pending.Set(tx, set.Delete(ready))
- }))
- //b.Log("waiter finished")
- }()
- }
- go func() {
- for Atomically(func(tx *Tx) bool {
- if done.Get(tx) {
- return false
- }
- tx.Assert(tokens.Get(tx) < maxTokens)
- tokens.Set(tx, tokens.Get(tx)+1)
- return true
- }) {
- }
- }()
- go func() {
- for Atomically(func(tx *Tx) bool {
- tx.Assert(tokens.Get(tx) > 0)
- tokens.Set(tx, tokens.Get(tx)-1)
- pending.Get(tx).Range(func(ready *Var[bool]) bool {
- if !ready.Get(tx) {
- ready.Set(tx, true)
- return false
- }
- return true
- })
- return !done.Get(tx)
- }) {
- }
- }()
- Atomically(VoidOperation(func(tx *Tx) {
- tx.Assert(pending.Get(tx).(Lenner).Len() == 0)
- }))
- AtomicSet(done, true)
- }
-}
-
func TestLimit(t *testing.T) {
if Limit(10) == Inf {
t.Errorf("Limit(10) == Inf should be false")
@@ -404,26 +88,6 @@ func TestEvery(t *testing.T) {
}
}
-const (
- d = 100 * time.Millisecond
-)
-
-var (
- t0 = time.Now()
- t1 = t0.Add(time.Duration(1) * d)
- t2 = t0.Add(time.Duration(2) * d)
- t3 = t0.Add(time.Duration(3) * d)
- t4 = t0.Add(time.Duration(4) * d)
- t5 = t0.Add(time.Duration(5) * d)
- t9 = t0.Add(time.Duration(9) * d)
-)
-
-type allow struct {
- t time.Time
- n int
- ok bool
-}
-
//
//func run(t *testing.T, lim *Limiter, allows []allow) {
// for i, allow := range allows {
@@ -576,25 +240,6 @@ func TestLongRunningQPS(t *testing.T) {
}
}
-type request struct {
- t time.Time
- n int
- act time.Time
- ok bool
-}
-
-// dFromDuration converts a duration to a multiple of the global constant d
-func dFromDuration(dur time.Duration) int {
- // Adding a millisecond to be swallowed by the integer division
- // because we don't care about small inaccuracies
- return int((dur + time.Millisecond) / d)
-}
-
-// dSince returns multiples of d since t0
-func dSince(t time.Time) int {
- return dFromDuration(t.Sub(t0))
-}
-
//
//func runReserve(t *testing.T, lim *Limiter, req request) *Reservation {
// return runReserveMax(t, lim, req, InfDuration)
@@ -750,6 +395,13 @@ type wait struct {
nilErr bool
}
+// dFromDuration converts a duration to a multiple of the global constant d
+func dFromDuration(dur time.Duration) int {
+ // Adding a millisecond to be swallowed by the integer division
+ // because we don't care about small inaccuracies
+ return int((dur + time.Millisecond) / d)
+}
+
func runWait(t *testing.T, lim *Limiter, w wait) {
t.Helper()
start := time.Now()
@@ -808,27 +460,6 @@ func TestWaitInf(t *testing.T) {
runWait(t, lim, wait{"exceed-burst-no-error", context.Background(), 3, 0, true})
}
-func BenchmarkAllowN(b *testing.B) {
- lim := NewLimiter(Every(1*time.Second), 1)
- b.ReportAllocs()
- b.ResetTimer()
- b.RunParallel(func(pb *testing.PB) {
- for pb.Next() {
- lim.AllowN(1)
- }
- })
-}
-
-func BenchmarkWaitNNoDelay(b *testing.B) {
- lim := NewLimiter(Limit(b.N), b.N)
- ctx := context.Background()
- b.ReportAllocs()
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- lim.WaitN(ctx, 1)
- }
-}
-
func TestDecrement(t *testing.T) {
x := NewVar(1000)
for i := 0; i < 500; i++ {