aboutsummaryrefslogtreecommitdiff
path: root/tests/benchmarks
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 /tests/benchmarks
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/*
Diffstat (limited to 'tests/benchmarks')
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
41 files changed, 779 insertions, 2 deletions
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()
+}