Skip to content

Commit 97f8feb

Browse files
authored
Merge pull request #4201 from durban/wip/multithreaded-wstp
Add support for Native multithreaded execution
2 parents 3b2ba0e + c33d887 commit 97f8feb

81 files changed

Lines changed: 1591 additions & 1315 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.cirrus.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,16 @@ jvm_highcore_task:
1010
script: sbt '++ 2.13' testsJVM/test ioAppTestsJVM/test
1111
- name: JVM high-core-count 3
1212
script: sbt '++ 3' testsJVM/test ioAppTestsJVM/test
13+
14+
native_highcore_task:
15+
only_if: $CIRRUS_TAG != '' || $CIRRUS_PR != ''
16+
required_pr_labels: Cirrus Native
17+
container:
18+
dockerfile: .cirrus/Dockerfile
19+
cpu: 8
20+
memory: 16G
21+
matrix:
22+
- name: Native high-core-count 2.13
23+
script: sbt '++ 2.13' testsNative/test ioAppTestsNative/test
24+
- name: Native high-core-count 3
25+
script: sbt '++ 3' testsNative/test ioAppTestsNative/test

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -670,5 +670,5 @@ jobs:
670670
- name: Submit Dependencies
671671
uses: scalacenter/sbt-dependency-submission@v2
672672
with:
673-
modules-ignore: cats-effect-benchmarks_3 cats-effect-benchmarks_2.12 cats-effect-benchmarks_2.13 cats-effect_3 cats-effect_2.12 cats-effect_2.13 cats-effect-example_sjs1_3 cats-effect-example_sjs1_2.12 cats-effect-example_sjs1_2.13 rootjs_3 rootjs_2.12 rootjs_2.13 ioapptestsnative_3 ioapptestsnative_2.12 ioapptestsnative_2.13 cats-effect-graalvm-example_3 cats-effect-graalvm-example_2.12 cats-effect-graalvm-example_2.13 cats-effect-tests_sjs1_3 cats-effect-tests_sjs1_2.12 cats-effect-tests_sjs1_2.13 rootjvm_3 rootjvm_2.12 rootjvm_2.13 rootnative_3 rootnative_2.12 rootnative_2.13 cats-effect-example_native0.4_3 cats-effect-example_native0.4_2.12 cats-effect-example_native0.4_2.13 cats-effect-example_3 cats-effect-example_2.12 cats-effect-example_2.13 cats-effect-tests_3 cats-effect-tests_2.12 cats-effect-tests_2.13 ioapptestsjvm_3 ioapptestsjvm_2.12 ioapptestsjvm_2.13 ioapptestsjs_3 ioapptestsjs_2.12 ioapptestsjs_2.13 cats-effect-tests_native0.4_3 cats-effect-tests_native0.4_2.12 cats-effect-tests_native0.4_2.13
673+
modules-ignore: cats-effect-benchmarks_3 cats-effect-benchmarks_2.12 cats-effect-benchmarks_2.13 cats-effect_3 cats-effect_2.12 cats-effect_2.13 cats-effect-example_sjs1_3 cats-effect-example_sjs1_2.12 cats-effect-example_sjs1_2.13 rootjs_3 rootjs_2.12 rootjs_2.13 ioapptestsnative_3 ioapptestsnative_2.12 ioapptestsnative_2.13 cats-effect-graalvm-example_3 cats-effect-graalvm-example_2.12 cats-effect-graalvm-example_2.13 cats-effect-tests_sjs1_3 cats-effect-tests_sjs1_2.12 cats-effect-tests_sjs1_2.13 rootjvm_3 rootjvm_2.12 rootjvm_2.13 rootnative_3 rootnative_2.12 rootnative_2.13 cats-effect-example_native0.5_3 cats-effect-example_native0.5_2.12 cats-effect-example_native0.5_2.13 cats-effect-example_3 cats-effect-example_2.12 cats-effect-example_2.13 cats-effect-tests_3 cats-effect-tests_2.12 cats-effect-tests_2.13 ioapptestsjvm_3 ioapptestsjvm_2.12 ioapptestsjvm_2.13 ioapptestsjs_3 ioapptestsjs_2.12 ioapptestsjs_2.13 cats-effect-tests_native0.5_3 cats-effect-tests_native0.5_2.12 cats-effect-tests_native0.5_2.13
674674
configs-ignore: test scala-tool scala-doc-tool test-internal

build.sbt

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,14 @@ import org.openqa.selenium.firefox.{FirefoxOptions, FirefoxProfile}
2323
import org.scalajs.jsenv.nodejs.NodeJSEnv
2424
import org.scalajs.jsenv.selenium.SeleniumJSEnv
2525
import sbtcrossproject.CrossProject
26+
import scala.scalanative.build._
2627

2728
import JSEnv._
2829

30+
lazy val inCI = Option(System.getenv("CI")).contains("true")
31+
2932
// sbt-git workarounds
30-
ThisBuild / useConsoleForROGit := !Option(System.getenv("CI")).contains("true")
33+
ThisBuild / useConsoleForROGit := !inCI
3134

3235
ThisBuild / git.gitUncommittedChanges := {
3336
if ((ThisBuild / githubIsWorkflowBuild).value) {
@@ -40,7 +43,7 @@ ThisBuild / git.gitUncommittedChanges := {
4043
}
4144
}
4245

43-
ThisBuild / tlBaseVersion := "3.6"
46+
ThisBuild / tlBaseVersion := "3.7"
4447
ThisBuild / tlUntaggedAreSnapshots := false
4548

4649
ThisBuild / organization := "org.typelevel"
@@ -322,13 +325,13 @@ ThisBuild / autoAPIMappings := true
322325

323326
ThisBuild / Test / testOptions += Tests.Argument("+l")
324327

325-
val CatsVersion = "2.11.0"
326-
val CatsMtlVersion = "1.3.1"
327-
val ScalaCheckVersion = "1.17.1"
328-
val CoopVersion = "1.2.0"
329-
val MUnitVersion = "1.0.0-M11"
330-
val MUnitScalaCheckVersion = "1.0.0-M11"
331-
val DisciplineMUnitVersion = "2.0.0-M3"
328+
val CatsVersion = "2.12.0"
329+
val CatsMtlVersion = "1.5.0"
330+
val ScalaCheckVersion = "1.18.1"
331+
val CoopVersion = "1.3.0"
332+
val MUnitVersion = "1.1.0"
333+
val MUnitScalaCheckVersion = "1.1.0"
334+
val DisciplineMUnitVersion = "2.0.0"
332335

333336
val MacrotaskExecutorVersion = "1.1.1"
334337

@@ -358,6 +361,17 @@ Global / tlCommandAliases ++= Map(
358361
)
359362
)
360363

364+
lazy val nativeTestSettings = Seq(
365+
nativeConfig ~= { c => // TODO: remove this when it seems to work
366+
c.withSourceLevelDebuggingConfig(_.enableAll) // enable generation of debug information
367+
.withOptimize(false) // disable Scala Native optimizer
368+
.withMode(Mode.debug) // compile using LLVM without optimizations
369+
.withCompileOptions(c.compileOptions ++ Seq("-gdwarf-4"))
370+
},
371+
envVars ++= { if (inCI) Map("GC_MAXIMUM_HEAP_SIZE" -> "8g") else Map.empty[String, String] },
372+
parallelExecution := !inCI
373+
)
374+
361375
val jsProjects: Seq[ProjectReference] =
362376
Seq(
363377
kernel.js,
@@ -441,7 +455,7 @@ lazy val kernel = crossProject(JSPlatform, JVMPlatform, NativePlatform)
441455
libraryDependencies += "org.scala-js" %%% "scala-js-macrotask-executor" % MacrotaskExecutorVersion % Test
442456
)
443457
.nativeSettings(
444-
libraryDependencies += "io.github.cquiroz" %%% "scala-java-time" % "2.5.0"
458+
libraryDependencies += "io.github.cquiroz" %%% "scala-java-time" % "2.6.0"
445459
)
446460

447461
/**
@@ -887,7 +901,12 @@ lazy val core = crossProject(JSPlatform, JVMPlatform, NativePlatform)
887901
ProblemFilters.exclude[MissingClassProblem](
888902
"cats.effect.metrics.JsCpuStarvationMetrics"),
889903
ProblemFilters.exclude[MissingClassProblem](
890-
"cats.effect.metrics.JsCpuStarvationMetrics$")
904+
"cats.effect.metrics.JsCpuStarvationMetrics$"),
905+
// all package-private classes; introduced when we made Native multithreaded
906+
ProblemFilters.exclude[MissingClassProblem]("cats.effect.unsafe.FiberExecutor"),
907+
ProblemFilters.exclude[IncompatibleMethTypeProblem](
908+
"cats.effect.unsafe.FiberMonitorImpl.this"),
909+
ProblemFilters.exclude[MissingClassProblem]("cats.effect.unsafe.FiberMonitorPlatform")
891910
)
892911
},
893912
mimaBinaryIssueFilters ++= {
@@ -944,6 +963,7 @@ lazy val testkit = crossProject(JSPlatform, JVMPlatform, NativePlatform)
944963
"org.scalacheck" %%% "scalacheck" % ScalaCheckVersion
945964
)
946965
)
966+
.nativeSettings(nativeTestSettings)
947967

948968
/**
949969
* Unit tests for the core project, utilizing the support provided by testkit.
@@ -975,7 +995,8 @@ lazy val tests: CrossProject = crossProject(JSPlatform, JVMPlatform, NativePlatf
975995
Test / javaOptions += "-Dcats.effect.trackFiberContext=true"
976996
)
977997
.nativeSettings(
978-
Compile / mainClass := Some("catseffect.examples.NativeRunner")
998+
Compile / mainClass := Some("catseffect.examples.NativeRunner"),
999+
nativeTestSettings
9791000
)
9801001

9811002
def configureIOAppTests(p: Project): Project =
@@ -986,7 +1007,7 @@ def configureIOAppTests(p: Project): Project =
9861007
buildInfoPackage := "cats.effect",
9871008
buildInfoKeys ++= Seq(
9881009
"jsRunner" -> (tests.js / Compile / fastOptJS / artifactPath).value,
989-
"nativeRunner" -> (tests.native / Compile / nativeLink / artifactPath).value
1010+
"nativeRunner" -> (tests.native / Compile / crossTarget).value / (tests.native / Compile / moduleName).value
9901011
)
9911012
)
9921013

core/js/src/main/scala/cats/effect/unsafe/BatchingMacrotaskExecutor.scala

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,7 @@ import scala.scalajs.{js, LinkingInfo}
3939
private[effect] final class BatchingMacrotaskExecutor(
4040
batchSize: Int,
4141
reportFailure0: Throwable => Unit
42-
) extends ExecutionContextExecutor
43-
with FiberExecutor {
42+
) extends ExecutionContextExecutor {
4443

4544
private[this] val queueMicrotask: js.Function1[js.Function0[Any], Any] =
4645
if (js.typeOf(js.Dynamic.global.queueMicrotask) == "function")

core/js-native/src/main/scala/cats/effect/unsafe/FiberMonitor.scala renamed to core/js/src/main/scala/cats/effect/unsafe/FiberMonitor.scala

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
package cats.effect
1818
package unsafe
1919

20+
import scala.concurrent.ExecutionContext
21+
import scala.scalajs.{js, LinkingInfo}
22+
2023
private[effect] sealed abstract class FiberMonitor extends FiberMonitorShared {
2124

2225
/**
@@ -41,8 +44,8 @@ private[effect] sealed abstract class FiberMonitor extends FiberMonitorShared {
4144

4245
private final class FiberMonitorImpl(
4346
// A reference to the compute pool of the `IORuntime` in which this suspended fiber bag
44-
// operates. `null` if the compute pool of the `IORuntime` is not a `FiberExecutor`.
45-
private[this] val compute: FiberExecutor
47+
// operates. `null` if the compute pool of the `IORuntime` is not a `BatchingMacrotaskExecutor`.
48+
private[this] val compute: BatchingMacrotaskExecutor
4649
) extends FiberMonitor {
4750
private[this] val bag = new WeakBag[IOFiber[?]]()
4851

@@ -92,4 +95,26 @@ private final class NoOpFiberMonitor extends FiberMonitor {
9295
def liveFiberSnapshot(print: String => Unit): Unit = ()
9396
}
9497

95-
private[effect] object FiberMonitor extends FiberMonitorPlatform
98+
private[effect] object FiberMonitor {
99+
def apply(compute: ExecutionContext): FiberMonitor = {
100+
if (LinkingInfo.developmentMode && weakRefsAvailable) {
101+
if (compute.isInstanceOf[BatchingMacrotaskExecutor]) {
102+
val bmec = compute.asInstanceOf[BatchingMacrotaskExecutor]
103+
new FiberMonitorImpl(bmec)
104+
} else {
105+
new FiberMonitorImpl(null)
106+
}
107+
} else {
108+
new NoOpFiberMonitor()
109+
}
110+
}
111+
112+
private[this] final val Undefined = "undefined"
113+
114+
/**
115+
* Feature-tests for all the required, well, features :)
116+
*/
117+
private[unsafe] def weakRefsAvailable: Boolean =
118+
js.typeOf(js.Dynamic.global.WeakRef) != Undefined &&
119+
js.typeOf(js.Dynamic.global.FinalizationRegistry) != Undefined
120+
}

core/js/src/main/scala/cats/effect/unsafe/FiberMonitorPlatform.scala

Lines changed: 0 additions & 45 deletions
This file was deleted.

core/js-native/src/main/scala/cats/effect/unsafe/WorkStealingThreadPool.scala renamed to core/js/src/main/scala/cats/effect/unsafe/WorkStealingThreadPool.scala

File renamed without changes.

core/js-native/src/main/scala/cats/effect/unsafe/metrics/IORuntimeMetricsCompanionPlatform.scala renamed to core/js/src/main/scala/cats/effect/unsafe/metrics/IORuntimeMetricsCompanionPlatform.scala

File renamed without changes.

core/js-native/src/main/scala/cats/effect/unsafe/metrics/IORuntimeMetricsPlatform.scala renamed to core/js/src/main/scala/cats/effect/unsafe/metrics/IORuntimeMetricsPlatform.scala

File renamed without changes.

core/jvm/src/main/scala/cats/effect/IOPlatform.scala renamed to core/jvm-native/src/main/scala/cats/effect/IOPlatform.scala

File renamed without changes.

0 commit comments

Comments
 (0)