From 12f1887fd56bbd5eebb82ff3e389a61e73192962 Mon Sep 17 00:00:00 2001 From: kyri-petrou <67301607+kyri-petrou@users.noreply.github.com> Date: Fri, 16 May 2025 18:17:22 -0600 Subject: [PATCH] [ZScheduler] Store pointers to mutable references in stack memory to avoid fetching them from the heap --- .../main/scala/zio/internal/ZScheduler.scala | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/core/jvm-native/src/main/scala/zio/internal/ZScheduler.scala b/core/jvm-native/src/main/scala/zio/internal/ZScheduler.scala index 725ec50e73aa..e6a22715d3f4 100644 --- a/core/jvm-native/src/main/scala/zio/internal/ZScheduler.scala +++ b/core/jvm-native/src/main/scala/zio/internal/ZScheduler.scala @@ -29,7 +29,7 @@ import scala.collection.mutable * applications. Inspired by "Making the Tokio Scheduler 10X Faster" by Carl * Lerche. [[https://tokio.rs/blog/2019-10-scheduler]] */ -private final class ZScheduler(autoBlocking: Boolean) extends Executor { +private final class ZScheduler(autoBlocking: Boolean) extends Executor { parent => import Trace.{empty => emptyTrace} import ZScheduler.{poolSize, workerOrNull} @@ -266,14 +266,23 @@ private final class ZScheduler(autoBlocking: Boolean) extends Executor { private[this] def makeWorker(): ZScheduler.Worker = new ZScheduler.Worker { self => - override val submittedLocations = makeLocations() + override val submittedLocations: ZScheduler.Locations = makeLocations() + + final override def run(): Unit = { + // Store parent mutable object references in stack memory to avoid fetching it from the heap every time + val globalQueue = parent.globalQueue + val workers = parent.workers + val state = parent.state + val cache = parent.cache + val idle = parent.idle + val poolSize = ZScheduler.poolSize - override def run(): Unit = { var currentBlocking = false var currentOpCount = 0L val random = ThreadLocalRandom.current var runnable = null.asInstanceOf[Runnable] var searching = false + while (!isInterrupted) { currentBlocking = blocking val currentNextRunnable = nextRunnable @@ -321,7 +330,7 @@ private final class ZScheduler(autoBlocking: Boolean) extends Executor { currentBlocking = blocking if (currentBlocking) { val runnables = localQueue.pollUpTo(256) - if (runnables.nonEmpty) { + if (!runnables.isEmpty) { globalQueue.offerAll(runnables, random) } } @@ -388,7 +397,7 @@ private final class ZScheduler(autoBlocking: Boolean) extends Executor { // NOTE: Synchronized block in case the supervisor attempts to mark the worker as blocking at the same time // as an external call - def markAsBlocking(): Unit = synchronized { + final def markAsBlocking(): Unit = synchronized { if (blocking) () else { blocking = true