diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 55d15ad5..eaa8215b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -85,3 +85,5 @@ jobs: run: sudo apt-get install clang libstdc++-12-dev libgc-dev - name: Test run: sbt rootNative/test + - name: Stress Test with Lower Memory + run: env GC_MAXIMUM_HEAP_SIZE=512M sbt 'rootNative/testOnly StressTest' diff --git a/build.sbt b/build.sbt index 52bd51f2..24f3e351 100644 --- a/build.sbt +++ b/build.sbt @@ -5,22 +5,28 @@ ThisBuild / scalaVersion := "3.3.1" lazy val root = crossProject(JVMPlatform, NativePlatform) - .crossType(CrossType.Full) - .in(file(".")) - .settings(Seq( - name := "Gears", - organization := "ch.epfl.lamp", - version := "0.1.0-SNAPSHOT", - testFrameworks += new TestFramework("munit.Framework") - )) - .jvmSettings(Seq( - javaOptions += "--version 21", - libraryDependencies += "org.scalameta" %% "munit" % "1.0.0-M10" % Test - )) - .nativeSettings(Seq( - nativeConfig ~= { c => - c.withMultithreadingSupport(true) - .withGC(GC.boehm) // immix doesn't work yet - }, - libraryDependencies += "org.scalameta" %%% "munit" % "1.0.0-M10+15-3940023e-SNAPSHOT" % Test - )) + .crossType(CrossType.Full) + .in(file(".")) + .settings( + Seq( + name := "Gears", + organization := "ch.epfl.lamp", + version := "0.1.0-SNAPSHOT", + testFrameworks += new TestFramework("munit.Framework") + ) + ) + .jvmSettings( + Seq( + javaOptions += "--version 21", + libraryDependencies += "org.scalameta" %% "munit" % "1.0.0-M10" % Test + ) + ) + .nativeSettings( + Seq( + nativeConfig ~= { c => + c.withMultithreadingSupport(true) + .withGC(GC.boehm) + }, + libraryDependencies += "org.scalameta" %%% "munit" % "1.0.0-M10+16-4e2ab919-SNAPSHOT" % Test + ) + ) diff --git a/dependencies/munit b/dependencies/munit index 3940023e..4e2ab919 160000 --- a/dependencies/munit +++ b/dependencies/munit @@ -1 +1 @@ -Subproject commit 3940023e5a3c07673611f561b57e043fb9ac51ec +Subproject commit 4e2ab919efd31595ccf0df7cf518655d8d2de40c diff --git a/dependencies/scala-native b/dependencies/scala-native index f4b9078c..20a7ccd0 160000 --- a/dependencies/scala-native +++ b/dependencies/scala-native @@ -1 +1 @@ -Subproject commit f4b9078c6c96dade366518f037d8f47048d2a4f3 +Subproject commit 20a7ccd09db10a34058c7a453dea56c2e00ca712 diff --git a/shared/src/test/scala/Stress.scala b/shared/src/test/scala/Stress.scala new file mode 100644 index 00000000..ddc71733 --- /dev/null +++ b/shared/src/test/scala/Stress.scala @@ -0,0 +1,45 @@ +import gears.async.{Async, Future, AsyncSupport, uninterruptible} +import gears.async.AsyncOperations.* +import gears.async.default.given +import gears.async.Future.MutableCollector +import java.util.concurrent.atomic.AtomicInteger +import gears.async.Timer +import scala.concurrent.duration._ + +class StressTest extends munit.FunSuite: + test("survives a stress test that hammers on creating futures") { + val total = 200_000L + Seq[Long](1, 2, 4, 16, 10000).foreach: parallelism => + val k = AtomicInteger(0) + def compute(using Async) = + k.incrementAndGet() + Async.blocking: + val collector = MutableCollector((1L to parallelism).map(_ => Future { compute })*) + var sum = 0L + for i <- parallelism + 1 to total do + sum += collector.results.read().right.get.await + collector += Future { compute } + for i <- 1L to parallelism do sum += collector.results.read().right.get.await + assertEquals(sum, total * (total + 1) / 2) + } + + test("survives a stress test that hammers on suspending") { + val total = 100_000L + val parallelism = 5000L + Async.blocking: + val sleepy = + val timer = Timer(1.second) + Future { timer.run() } + timer.src + val k = AtomicInteger(0) + def compute(using Async) = + sleepy.awaitResult + k.incrementAndGet() + val collector = MutableCollector((1L to parallelism).map(_ => Future { compute })*) + var sum = 0L + for i <- parallelism + 1 to total do + sum += collector.results.read().right.get.await + collector += Future { compute } + for i <- 1L to parallelism do sum += collector.results.read().right.get.await + assertEquals(sum, total * (total + 1) / 2) + }