diff options
author | EuAndreh <eu@euandre.org> | 2025-01-23 09:54:11 -0300 |
---|---|---|
committer | EuAndreh <eu@euandre.org> | 2025-01-23 11:36:44 -0300 |
commit | 5f6607152a96b85f1518028b8f1ee1ef1aefda75 (patch) | |
tree | be54946ddb2510a317322a2660563c83cab2117c | |
parent | tests/stm.go: Turn example into functional test (diff) | |
download | stm-5f6607152a96b85f1518028b8f1ee1ef1aefda75.tar.gz stm-5f6607152a96b85f1518028b8f1ee1ef1aefda75.tar.xz |
Move benchmarks from tests/stm.go to tests/benchmarks/*
43 files changed, 977 insertions, 389 deletions
@@ -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++ { |