From 1c9d4fcacc4b8eed97b4da3943b869e1107d4d16 Mon Sep 17 00:00:00 2001 From: Arman Bilge Date: Thu, 29 Jun 2023 01:51:42 +0000 Subject: [PATCH 1/3] Optimize `liveTraces()` on JS --- .../unsafe/BatchingMacrotaskExecutor.scala | 18 ++++------ .../cats/effect/unsafe/JSArrayQueue.scala | 21 ++++++++++++ .../cats/effect/unsafe/JSArrayQueueSpec.scala | 33 ++++++++++++++++++- 3 files changed, 59 insertions(+), 13 deletions(-) diff --git a/core/js/src/main/scala/cats/effect/unsafe/BatchingMacrotaskExecutor.scala b/core/js/src/main/scala/cats/effect/unsafe/BatchingMacrotaskExecutor.scala index d550d2c389..f56123cfec 100644 --- a/core/js/src/main/scala/cats/effect/unsafe/BatchingMacrotaskExecutor.scala +++ b/core/js/src/main/scala/cats/effect/unsafe/BatchingMacrotaskExecutor.scala @@ -62,17 +62,11 @@ private[effect] final class BatchingMacrotaskExecutor( var i = 0 while (i < batchSize && !fibers.isEmpty()) { val fiber = fibers.take() - - if (LinkingInfo.developmentMode) - if (fiberBag ne null) - fiberBag -= fiber - try fiber.run() catch { case t if NonFatal(t) => reportFailure(t) case t: Throwable => IOFiber.onFatalFailure(t) } - i += 1 } @@ -99,10 +93,6 @@ private[effect] final class BatchingMacrotaskExecutor( * batch. */ def schedule(fiber: IOFiber[_]): Unit = { - if (LinkingInfo.developmentMode) - if (fiberBag ne null) - fiberBag += fiber - fibers.offer(fiber) if (needsReschedule) { @@ -116,8 +106,12 @@ private[effect] final class BatchingMacrotaskExecutor( def reportFailure(t: Throwable): Unit = reportFailure0(t) - def liveTraces(): Map[IOFiber[_], Trace] = - fiberBag.iterator.filterNot(_.isDone).map(f => f -> f.captureTrace()).toMap + def liveTraces(): Map[IOFiber[_], Trace] = { + val traces = Map.newBuilder[IOFiber[_], Trace] + fibers.foreach(f => if (!f.isDone) traces += f -> f.captureTrace()) + fiberBag.foreach(f => if (!f.isDone) traces += f -> f.captureTrace()) + traces.result() + } @inline private[this] def monitor(runnable: Runnable): Runnable = if (LinkingInfo.developmentMode) diff --git a/core/js/src/main/scala/cats/effect/unsafe/JSArrayQueue.scala b/core/js/src/main/scala/cats/effect/unsafe/JSArrayQueue.scala index 65505f1b61..ead6c6979e 100644 --- a/core/js/src/main/scala/cats/effect/unsafe/JSArrayQueue.scala +++ b/core/js/src/main/scala/cats/effect/unsafe/JSArrayQueue.scala @@ -69,4 +69,25 @@ private final class JSArrayQueue[A] { } } + @inline def foreach(f: A => Unit): Unit = + if (empty) () + else if (startIndex < endIndex) { // consecutive in middle of buffer + var i = startIndex + while (i < endIndex) { + f(buffer(i)) + i += 1 + } + } else { // split across tail and init of buffer + var i = startIndex + while (i < buffer.length) { + f(buffer(i)) + i += 1 + } + i = 0 + while (i < endIndex) { + f(buffer(i)) + i += 1 + } + } + } diff --git a/tests/js/src/test/scala/cats/effect/unsafe/JSArrayQueueSpec.scala b/tests/js/src/test/scala/cats/effect/unsafe/JSArrayQueueSpec.scala index e52a54a624..d28c9f20e9 100644 --- a/tests/js/src/test/scala/cats/effect/unsafe/JSArrayQueueSpec.scala +++ b/tests/js/src/test/scala/cats/effect/unsafe/JSArrayQueueSpec.scala @@ -20,7 +20,7 @@ package unsafe import org.scalacheck.Prop.forAll import org.specs2.ScalaCheck -import scala.collection.mutable.ListBuffer +import scala.collection.mutable.{ArrayDeque, ListBuffer} class JSArrayQueueSpec extends BaseSpec with ScalaCheck { @@ -41,6 +41,37 @@ class JSArrayQueueSpec extends BaseSpec with ScalaCheck { taken.toList must beEqualTo(stuff.flatten) } } + + "iterate over contents in foreach" in { + forAll { (stuff: List[Option[Int]]) => + val queue = new JSArrayQueue[Int] + val shadow = new ArrayDeque[Int] + + def checkContents() = { + val builder = List.newBuilder[Int] + queue.foreach(builder += _) + builder.result() must beEqualTo(shadow.toList) + } + + checkContents() + + stuff.foreach { + case Some(i) => + queue.offer(i) + shadow.append(i) + checkContents() + case None => + if (!shadow.isEmpty) { + val got = queue.take() + val expected = shadow.removeHead() + got must beEqualTo(expected) + checkContents() + } + } + + true must beTrue + } + } } } From 1f3ca6e07bd6b53e7d6780d4d2d192784206e268 Mon Sep 17 00:00:00 2001 From: Arman Bilge Date: Thu, 29 Jun 2023 02:08:03 +0000 Subject: [PATCH 2/3] Fix 2.12 compile --- .../test/scala/cats/effect/unsafe/JSArrayQueueSpec.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/js/src/test/scala/cats/effect/unsafe/JSArrayQueueSpec.scala b/tests/js/src/test/scala/cats/effect/unsafe/JSArrayQueueSpec.scala index d28c9f20e9..ade4d40d03 100644 --- a/tests/js/src/test/scala/cats/effect/unsafe/JSArrayQueueSpec.scala +++ b/tests/js/src/test/scala/cats/effect/unsafe/JSArrayQueueSpec.scala @@ -20,7 +20,7 @@ package unsafe import org.scalacheck.Prop.forAll import org.specs2.ScalaCheck -import scala.collection.mutable.{ArrayDeque, ListBuffer} +import scala.collection.mutable.{ListBuffer, Queue} class JSArrayQueueSpec extends BaseSpec with ScalaCheck { @@ -45,7 +45,7 @@ class JSArrayQueueSpec extends BaseSpec with ScalaCheck { "iterate over contents in foreach" in { forAll { (stuff: List[Option[Int]]) => val queue = new JSArrayQueue[Int] - val shadow = new ArrayDeque[Int] + val shadow = new Queue[Int] def checkContents() = { val builder = List.newBuilder[Int] @@ -58,12 +58,12 @@ class JSArrayQueueSpec extends BaseSpec with ScalaCheck { stuff.foreach { case Some(i) => queue.offer(i) - shadow.append(i) + shadow.enqueue(i) checkContents() case None => if (!shadow.isEmpty) { val got = queue.take() - val expected = shadow.removeHead() + val expected = shadow.dequeue() got must beEqualTo(expected) checkContents() } From 5a3a942a66a47136deb7a649b8b366ddfb40fa0b Mon Sep 17 00:00:00 2001 From: Arman Bilge Date: Sat, 1 Jul 2023 07:57:17 -0700 Subject: [PATCH 3/3] ok ok --- .../js/src/test/scala/cats/effect/unsafe/JSArrayQueueSpec.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/js/src/test/scala/cats/effect/unsafe/JSArrayQueueSpec.scala b/tests/js/src/test/scala/cats/effect/unsafe/JSArrayQueueSpec.scala index ade4d40d03..df0b7edd52 100644 --- a/tests/js/src/test/scala/cats/effect/unsafe/JSArrayQueueSpec.scala +++ b/tests/js/src/test/scala/cats/effect/unsafe/JSArrayQueueSpec.scala @@ -69,7 +69,7 @@ class JSArrayQueueSpec extends BaseSpec with ScalaCheck { } } - true must beTrue + ok } } }