-
Notifications
You must be signed in to change notification settings - Fork 50
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[stm][bench] Ref log optimization + benchmarks (#885)
Introduces an initial set of benchmarks for the STM module and optimizes ref log usage. I was surprised by how well optimized ZIO's STM is :) [Benchmark results](https://jmh.morethan.io/?source=https://gist.githubusercontent.com/fwbrasil/308dc726e9a4f5913170d7d49f7a2dcf/raw/19d284bd0fff6556f83a408db993d4f814b56a89/jmh-result.json): ![image](https://github.com/user-attachments/assets/bd9de6ea-ef6a-4cdd-bb75-4868df583a26)
- Loading branch information
Showing
12 changed files
with
304 additions
and
55 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
72 changes: 72 additions & 0 deletions
72
kyo-bench/src/main/scala/kyo/bench/TMapMultiKeyBench.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
package kyo.bench | ||
|
||
class TMapMultiKeyBench(parallelism: Int) extends Bench.ForkOnly(parallelism): | ||
|
||
def this() = this(Runtime.getRuntime().availableProcessors() * 2) | ||
|
||
def catsBench() = | ||
import cats.effect.* | ||
import cats.syntax.all.* | ||
import io.github.timwspence.cats.stm.* | ||
|
||
STM.runtime[IO].flatMap { stm => | ||
for | ||
ref <- stm.commit(stm.TVar.of(Map.empty[Int, Int])) | ||
_ <- | ||
(0 until parallelism).map { i => | ||
stm.commit { | ||
for | ||
map <- ref.get | ||
_ <- ref.set(map.updated(i, map.getOrElse(i, 0) + 1)) | ||
yield () | ||
} | ||
}.toList.parSequence_ | ||
results <- stm.commit(ref.get.map(_.values.sum)) | ||
yield results | ||
} | ||
end catsBench | ||
|
||
override def kyoBenchFiber() = | ||
import kyo.* | ||
|
||
for | ||
map <- TMap.initNow[Int, Int]() | ||
_ <- | ||
Async.parallelUnbounded( | ||
(0 until parallelism).map { i => | ||
STM.run { | ||
for | ||
current <- map.get(i) | ||
_ <- map.put(i, current.getOrElse(0) + 1) | ||
yield () | ||
} | ||
} | ||
) | ||
results <- STM.run(map.snapshot) | ||
yield results.values.sum | ||
end for | ||
end kyoBenchFiber | ||
|
||
def zioBench() = | ||
import zio.* | ||
import zio.stm.* | ||
|
||
for | ||
map <- TMap.empty[Int, Int].commit | ||
_ <- | ||
ZIO.collectAllParDiscard( | ||
(0 until parallelism).map { i => | ||
STM.atomically { | ||
for | ||
current <- map.get(i) | ||
_ <- map.put(i, current.getOrElse(0) + 1) | ||
yield () | ||
} | ||
} | ||
) | ||
results <- map.toMap.commit | ||
yield results.values.sum | ||
end for | ||
end zioBench | ||
|
||
end TMapMultiKeyBench |
70 changes: 70 additions & 0 deletions
70
kyo-bench/src/main/scala/kyo/bench/TMapSingleKeyBench.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
package kyo.bench | ||
|
||
class TMapSingleKeyBench(parallelism: Int) extends Bench.ForkOnly(parallelism): | ||
|
||
def this() = this(Runtime.getRuntime().availableProcessors() * 2) | ||
|
||
def catsBench() = | ||
import cats.effect.* | ||
import cats.syntax.all.* | ||
import io.github.timwspence.cats.stm.* | ||
|
||
STM.runtime[IO].flatMap { stm => | ||
for | ||
ref <- stm.commit(stm.TVar.of(Map.empty[Int, Int])) | ||
_ <- Seq.fill(parallelism)( | ||
stm.commit { | ||
for | ||
map <- ref.get | ||
current = map.getOrElse(0, 0) | ||
_ <- ref.set(map.updated(0, current + 1)) | ||
yield () | ||
} | ||
).parSequence_ | ||
result <- stm.commit(ref.get.map(_.getOrElse(0, 0))) | ||
yield result | ||
} | ||
end catsBench | ||
|
||
override def kyoBenchFiber() = | ||
import kyo.* | ||
|
||
for | ||
map <- TMap.initNow[Int, Int]() | ||
_ <- Async.parallelUnbounded( | ||
Seq.fill(parallelism)( | ||
STM.run { | ||
for | ||
current <- map.get(0) | ||
_ <- map.put(0, current.getOrElse(0) + 1) | ||
yield () | ||
} | ||
) | ||
) | ||
result <- STM.run(map.get(0)) | ||
yield result.getOrElse(0) | ||
end for | ||
end kyoBenchFiber | ||
|
||
def zioBench() = | ||
import zio.* | ||
import zio.stm.* | ||
|
||
for | ||
map <- TMap.empty[Int, Int].commit | ||
_ <- ZIO.collectAllParDiscard( | ||
Seq.fill(parallelism)( | ||
STM.atomically { | ||
for | ||
current <- map.get(0) | ||
_ <- map.put(0, current.getOrElse(0) + 1) | ||
yield () | ||
} | ||
) | ||
) | ||
result <- map.get(0).commit | ||
yield result.getOrElse(0) | ||
end for | ||
end zioBench | ||
|
||
end TMapSingleKeyBench |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package kyo.bench | ||
|
||
import java.util.concurrent.locks.LockSupport | ||
|
||
class TRefMultiBench(parallelism: Int) extends Bench.ForkOnly(parallelism): | ||
|
||
def this() = this(Runtime.getRuntime().availableProcessors() * 2) | ||
|
||
def catsBench() = | ||
import cats.effect.* | ||
import cats.syntax.all.* | ||
import io.github.timwspence.cats.stm.* | ||
|
||
STM.runtime[IO].flatMap { stm => | ||
for | ||
refs <- stm.commit(Seq.fill(parallelism)(stm.TVar.of(0)).sequence) | ||
_ <- refs.map(ref => stm.commit(ref.modify(_ + 1))).parSequence_ | ||
result <- stm.commit(refs.traverse(_.get).map(_.sum)) | ||
yield result | ||
} | ||
end catsBench | ||
|
||
override def kyoBenchFiber() = | ||
import kyo.* | ||
|
||
for | ||
refs <- Kyo.fill(parallelism)(TRef.initNow(0)) | ||
_ <- Async.parallelUnbounded(refs.map(ref => STM.run(ref.update(_ + 1)))) | ||
result <- STM.run(Kyo.foreach(refs)(_.get).map(_.sum)) | ||
yield result | ||
end for | ||
end kyoBenchFiber | ||
|
||
def zioBench() = | ||
import zio.* | ||
import zio.stm.* | ||
|
||
for | ||
refs <- ZIO.collectAll(Seq.fill(parallelism)(TRef.make(0).commit)) | ||
_ <- ZIO.collectAllParDiscard(refs.map(_.update(_ + 1).commit)) | ||
result <- STM.collectAll(refs.map(_.get)).map(_.sum).commit | ||
yield result | ||
end for | ||
end zioBench | ||
end TRefMultiBench |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package kyo.bench | ||
|
||
import java.util.concurrent.locks.LockSupport | ||
|
||
class TRefSingleBench(parallelism: Int) extends Bench.ForkOnly(parallelism): | ||
|
||
def this() = this(Runtime.getRuntime().availableProcessors() * 2) | ||
|
||
def catsBench() = | ||
import cats.effect.* | ||
import cats.syntax.all.* | ||
import io.github.timwspence.cats.stm.* | ||
|
||
STM.runtime[IO].flatMap { stm => | ||
for | ||
ref <- stm.commit(stm.TVar.of(0)) | ||
_ <- Seq.fill(parallelism)( | ||
stm.commit(ref.modify(_ + 1)) | ||
).parSequence_ | ||
result <- stm.commit(ref.get) | ||
yield result | ||
} | ||
end catsBench | ||
|
||
override def kyoBenchFiber() = | ||
import kyo.* | ||
|
||
for | ||
ref <- TRef.initNow(0) | ||
_ <- Async.parallelUnbounded(Seq.fill(parallelism)(STM.run(ref.update(_ + 1)))) | ||
result <- STM.run(ref.get) | ||
yield result | ||
end for | ||
end kyoBenchFiber | ||
|
||
def zioBench() = | ||
import zio.* | ||
import zio.stm.* | ||
|
||
for | ||
ref <- TRef.make(0).commit | ||
_ <- ZIO.collectAllParDiscard(Seq.fill(parallelism)(ref.update(_ + 1).commit)) | ||
result <- ref.get.commit | ||
yield result | ||
end for | ||
end zioBench | ||
end TRefSingleBench |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.