diff --git a/benchmarks/scala-stm/src/main/scala/org/renaissance/scala/stm/Philosophers.scala b/benchmarks/scala-stm/src/main/scala/org/renaissance/scala/stm/Philosophers.scala index 7d3a3b04..3cddb5c2 100644 --- a/benchmarks/scala-stm/src/main/scala/org/renaissance/scala/stm/Philosophers.scala +++ b/benchmarks/scala-stm/src/main/scala/org/renaissance/scala/stm/Philosophers.scala @@ -19,7 +19,13 @@ import org.renaissance.License defaultValue = "500000", summary = "Number of meals consumed by each philosopher thread" ) -@Configuration(name = "test", settings = Array("meal_count = 500")) +@Parameter( + name = "block_meal_count", + defaultValue = "4096", + summary = + "Number of meals representing a block of progress. Determines determines the frequency of camera scans. Must be a power of two." +) +@Configuration(name = "test", settings = Array("meal_count = 500", "block_meal_count = 8")) @Configuration(name = "jmh") final class Philosophers extends Benchmark { @@ -28,17 +34,33 @@ final class Philosophers extends Benchmark { private var threadCountParam: Int = _ + /** Number of meals consumed by each Philosopher thread. */ + private var mealCountParam: Int = _ + /** - * Number of meals consumed by each Philosopher thread. + * Number of meals representing a block of progress which determines + * the frequency of camera scans. Must be power of two to enable + * efficient checking. */ - private var mealCountParam: Int = _ + private var blockMealCountParam: Int = _ override def setUpBeforeAll(c: BenchmarkContext): Unit = { + def isPowerOfTwo(n: Int): Boolean = if (n <= 0) false else (n & (n - 1)) == 0 + threadCountParam = c.parameter("thread_count").toPositiveInteger mealCountParam = c.parameter("meal_count").toPositiveInteger + + blockMealCountParam = c.parameter("block_meal_count").toPositiveInteger + if (!isPowerOfTwo(blockMealCountParam)) { + throw new IllegalArgumentException( + s"the 'block_meal_count' parameter is not a power of two: $blockMealCountParam" + ) + } } - private def validate(forkOwners: Seq[Option[String]], mealsEaten: Seq[Int]): Unit = { + private def validate(result: (Seq[Option[String]], Seq[Int], Int)): Unit = { + val (forkOwners, mealsEaten, scanCount) = result + // All forks should be available, i.e., not owned by anyone. for (i <- 0 until threadCountParam) { Assert.assertEquals(None, forkOwners(i), s"owner of fork %i") @@ -48,13 +70,21 @@ final class Philosophers extends Benchmark { for (i <- 0 until threadCountParam) { Assert.assertEquals(mealCountParam, mealsEaten(i), s"meals eaten by philosopher $i") } + + // The camera performed the expected number of scans. + val expectedScanCount = mealCountParam / blockMealCountParam + Assert.assertEquals(expectedScanCount, scanCount, "camera scans") } override def run(c: BenchmarkContext): BenchmarkResult = { - val (forkOwners, mealsEaten) = RealityShowPhilosophers.run(mealCountParam, threadCountParam) + val result = RealityShowPhilosophers.run( + mealCountParam, + threadCountParam, + blockMealCountParam + ) () => { - validate(forkOwners, mealsEaten) + validate(result) } } diff --git a/benchmarks/scala-stm/src/main/scala/org/renaissance/scala/stm/RealityShowPhilosophers.scala b/benchmarks/scala-stm/src/main/scala/org/renaissance/scala/stm/RealityShowPhilosophers.scala index 5dc997da..ae869262 100644 --- a/benchmarks/scala-stm/src/main/scala/org/renaissance/scala/stm/RealityShowPhilosophers.scala +++ b/benchmarks/scala-stm/src/main/scala/org/renaissance/scala/stm/RealityShowPhilosophers.scala @@ -160,9 +160,13 @@ object RealityShowPhilosophers { } } - def run(mealCount: Int, philosopherCount: Int): (Seq[Option[String]], Seq[Int]) = { + def run( + mealCount: Int, + philosopherCount: Int, + blockMealCount: Int + ): (Seq[Option[String]], Seq[Int], Int) = { val forks = Array.tabulate(philosopherCount) { i => new Fork(s"fork-$i") } - val controller = new CameraController(philosopherCount, 1 << 12) + val controller = new CameraController(philosopherCount, blockMealCount) val philosophers = Array.tabulate(philosopherCount) { i => new PhilosopherThread( s"philosopher-$i", @@ -184,6 +188,7 @@ object RealityShowPhilosophers { camera.join() // Collect fork owners and meals eaten for validation. - camera.stateSnapshot + val (forkOwners, mealsEaten) = camera.stateSnapshot + (forkOwners, mealsEaten, camera.images.length) } }