Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@kyri-petrou
Copy link
Contributor

Hey Kyo team πŸ‘‹ Let me start by saying that I'm a huge fan of the work you've been doing, and that I've been following a lot of it from the sidelines. Also really looking forward to trying out the new kyo-scheduler now that it's been made into a separate module and cross compiled for Scala 2 as well!

So just a small introduction: I've been actively contributing to Caliban for quite some time now, but since the departure of Adam from Ziverge I've been actively contributing / maintaining zio and other zio-* libraries; which brings me to why I'm opening this PR. We'll be soon releasing ZIO 2.1.0 (hopefully no more than 1-2 more RC versions before we pull the trigger). The 2.1.0 version has a fully redesigned fiber runtime, and had some very extensive optimizations done to improve fork-join performance. While the benchmarks in the ZIO repo show some significant improvements, I would like to see how it also performs in external benchmarks and whether we might have any regressions in areas that we're not capturing well.

If it's okay with you, would you mind to update the zio version in your benchmarks to the latest RC to see how it performs and compares against the 2.0.x version and the rest of the Scala effect libraries in your benchmarks?

@hearnadam hearnadam merged commit b547e02 into getkyo:main Apr 27, 2024
@kyri-petrou kyri-petrou deleted the update-zio-version branch April 27, 2024 15:30
@fwbrasil
Copy link
Collaborator

Thank you @kyri-petrou! Yes, please feel free to submit library upgrades and even new benchmarks, especially if they show areas that Kyo doesn't perform well!

We have similar benchmarks to the one you used for the optimization but with some important differences that can influence performance. I've prepared a PR with a port of ZIO's benchmark: #304.

What is the FiberRoots config? Could we enable it for all ZIO benchmarks?

@fwbrasil
Copy link
Collaborator

I was trying to check how ZIO performs with Kyo's scheduler but I'm having trouble to configure it. My failed attempt so far:

        @Benchmark
        def forkZio(): T = zio.Unsafe.unsafe(implicit u =>
            val exec = new ZioKyoExecutor
            zio.Runtime.unsafe.fromLayer(zio.Runtime.setExecutor(exec) ++ zio.Runtime.setBlockingExecutor(exec))
                .run(zio.ZIO.yieldNow.flatMap(_ => zioBench())).getOrThrow()
        )

I also wanted to remove this configuration from the hot path of the benchmark execution and put the runtime in a pre-initialized val to reduce overhead but the requirement of an Unsafe evidence doesn't seem to allow that.

@hearnadam
Copy link
Collaborator

You can use Unsafe.unsafe{ } directly to remove the unsafe requirement.

@kyri-petrou
Copy link
Contributor Author

@fwbrasil I think the best way to

I also wanted to remove this configuration from the hot path of the benchmark execution and put the runtime in a pre-initialized val to reduce overhead but the requirement of an Unsafe evidence doesn't seem to allow that.

I think the best way to do this would be something along these lines:

import kyo.scheduler.Scheduler as KyoScheduler
import zio.*

object ZioRunner {
  private given Unsafe = Unsafe.unsafe(identity)

  private val kExecutorLayer = Runtime.setExecutor(Executor.fromJavaExecutor(KyoScheduler.get.asExecutor))
  private val rt             = Runtime.unsafe.fromLayer(kExecutorLayer).unsafe

  def run[A](f: ZIO[Any, Throwable, A]) = rt.run(f).getOrThrowFiberFailure()
}

Note that in Scala 3 you could also do this (notice it's unsafely instead of unsafe, which uses a context function)

def run[A](f: ZIO[Any, Throwable, A]) = Unsafe.unsafely(rt.run(f).getOrThrowFiberFailure())

@kyri-petrou
Copy link
Contributor Author

kyri-petrou commented Apr 30, 2024

What is the FiberRoots config? Could we enable it for all ZIO benchmarks?

@fwbrasil The FiberRoots is a runtime flag, and it's enabled by default in the ZIO runtime. It adds an considerable overhead to fork-join performance, but it's required for tracking fibers that have been forked in the global scope.

The tracking of fibers is mostly necessary for being able to interrupt them safely and await for their completion when the application exits

@fwbrasil
Copy link
Collaborator

fwbrasil commented May 1, 2024

@kyri-petrou Thanks for the tips! I used a similar approach to set the executor in #306. There's a performance regression I still have to investigate.

About FiberRoots, it seems a good optimization opportunity! Weak references have some GC impact because objects survive an extra GC cycle and a global collection pointing to fibers can limit scalability. Loom for example doesn't enable thread dumps for virtual threads by default.

For safe closing of resources, maybe you could track the resources themselves instead of all fibers since it's typically a much smaller set? For fiber dumps, the scheduler itself should already have a reference to all active fibers but that would have a compromise of not reporting suspended fibers.

@kyri-petrou
Copy link
Contributor Author

kyri-petrou commented May 2, 2024

@fwbrasil thanks for the recommendations! I agree that FiberRoots is something that could potentially be redesigned or potentially be turned off by default. Also, I'm not even entirely sure whether having resources forked in the global scope is actually even a use-case; perhaps it's not. Personally, for projects at $WORK I have FiberRoots disabled πŸ˜….

By the way zio v2.1.0-RC4 was just released where I added a very convenient method for disabling runtime flags.
You can try disabling FiberRoots in your benchmarks by creating a new Runtime as:

Unsafe.unsafely {
  Runtime.unsafe.fromLayer(Runtime.disableFlags(RuntimeFlag.FiberRoots)).unsafe
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants