8000 Optimize Ref.Atomic by hearnadam · Pull Request #9500 · zio/zio · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Optimize Ref.Atomic #9500

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 1, 2025
Merged

Optimize Ref.Atomic #9500

merged 2 commits into from
Feb 1, 2025

Conversation

hearnadam
Copy link
Collaborator
@hearnadam hearnadam commented Jan 26, 2025
  1. Initialize the UnsafeAPI with the AtomicRef class to avoid pointer chasing within UnsafeAPI methods, as well as allocated space
  2. reuse implementations from AtomicRef where possible - reducing generated bytecode size

Benchmark shows minor improvement, but it's just using update:

https://jmh.morethan.io/?gists=a2e47cdd533e03f456ad1210fefd7172,07a439a09644cedac645fedaf3fe8de6

I don't have time to add other benchmarks now, but I suspect this will be an improvement all around.

Other notes:

  • I marked Ref and SubscriptionRef as sealed, which should be binary compatible...
  • I removed the usage of .get in toString. I think it's unnecessary and not suspended, so probably not worth exposing.

@hearnadam hearnadam requested a review from kyri-petrou January 26, 2025 04:14
current
}
def getAndSet(a: A)(implicit unsafe: Unsafe): A =
ref.asInstanceOf[AtomicReference[A]].getAndSet(a)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unfortunately the asInstanceOf is necessary as the implicit unsafe will cause the compiler to choose UnsafeAPI#method.

8000
import zio.test._

object RefSpec extends ZIOBaseSpec {

def spec = suite("RefSpec")(
suite("Atomic")(
test("race") {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was race once implemented with Ref?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤷

@hearnadam
Copy link
Collaborator Author

filter with: ProblemFilters.exclude[MissingFieldProblem]("zio.Ref.Atomic") It looks like this will fail Mima checks - @kyri-petrou since this was private[zio] can we bypass this?


def modify[B](f: A => (B, A))(implicit unsafe: Unsafe): B = {
var loop = true
var b: B = null.asInstanceOf[B]
while (loop) {
val current = value.get
val current = ref.asInstanceOf[AtomicReference[A]].get
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could this whole fn be written as:

def modify(f) =
  var b = null
  ref.updateAndGet: a =>
    tup = f(a)
    b = tup._1
    tup._2
  b

?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This implementation is more efficient. In fact one would argue the most efficient would be to use weakCompareAndSet but I think we can leave that one as is for now

@kyri-petrou
Copy link
Contributor

filter with: ProblemFilters.exclude[MissingFieldProblem]("zio.Ref.Atomic") It looks like this will fail Mima checks - @kyri-petrou since this was private[zio] can we bypass this?

How about adding a method like this, would it still cause mima to fail? I think even if it does it might be better to have it as there is a small chance that we're accessing the underlying AtomicReference in some zio-* library for performance reasons:

@deprecated(...)
private[zio] def value: AtomicReference[A] = unsafe.asInstanceOf[AtomicReference[A]]

@@ -41,7 +41,8 @@ object ThreadLocalBridge {

private class FiberRefTrackingSupervisor extends Supervisor[Unit] {

private val trackedRefs: Ref.Atomic[Set[(FiberRef[_], Any => Unit)]] = Ref.Atomic(new AtomicReference(Set.empty))
Copy link
Contributor
@kyri-petrou kyri-petrou Jan 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hopefully we were not using the apply method like this in other zio-* libraries 😰

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could introduce an apply method that gets the initial state from the AtomicRef. Is that preferable?

@hearnadam hearnadam merged commit a2b58da into zio:series/2.x Feb 1, 2025
18 checks passed
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
0