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

Skip to content

Conversation

@guizmaii
Copy link
Member

@guizmaii guizmaii commented Dec 11, 2024

I'd like your opinion on these changes. The goal is to try to reduce the number of recursive calls

It'd, for example, benefit this change: #9388

@guizmaii guizmaii force-pushed the FlatMap_less_0 branch 4 times, most recently from 1f5f1ad to 6b6d565 Compare December 11, 2024 12:24
@guizmaii guizmaii requested review from jdegoes and kyri-petrou and removed request for kyri-petrou December 11, 2024 12:28
@guizmaii guizmaii self-assigned this Dec 11, 2024
@guizmaii guizmaii requested a review from kyri-petrou December 11, 2024 12:28
@guizmaii guizmaii marked this pull request as ready for review December 11, 2024 12:28
@guizmaii guizmaii changed the title Optimisation: Eager eval flatmap.first and fold.first when possible Optimisation: Bypass evaluation of flatmap.first and fold.first when possible Dec 11, 2024
@guizmaii guizmaii changed the title Optimisation: Bypass evaluation of flatmap.first and fold.first when possible Optimisation - FiberRuntime: bypass evaluation of flatmap.first and fold.first when possible Dec 11, 2024
@guizmaii guizmaii force-pushed the FlatMap_less_0 branch 2 times, most recently from 303c192 to 06ea1f0 Compare December 11, 2024 12:42
Copy link
Contributor

@kyri-petrou kyri-petrou left a comment

Choose a reason for hiding this comment

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

Some minor comments, but I think this shortcut makes a lot of sense since we have a lot of ZIO methods that return Unit and we compose them in for-comprehensions or using *>. Avoiding the additional method invocation and pushing/popping from the stack should make things noticeably faster for some programs, so thank you πŸ™

Comment on lines 1069 to 1070
else if (first.isInstanceOf[Success[Any]]) cur = flatmap.successK(first.asInstanceOf[Success[Any]].value)
else if (first.isInstanceOf[Failure[Any]]) cur = first
Copy link
Contributor

Choose a reason for hiding this comment

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

I think let's remove these 2 branches. Exit overrides flatMap so unless we construct one somewhere manually with an exit as first then it won't exist. To double-check this I run the ZIO tests with the line below and it wasn't printed at all

if (flatmap.first.isInstanceOf[Success[Any]]) println("flatmap.first is Success")

Copy link
Member Author

Choose a reason for hiding this comment

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

Done

case failure =>
cur = failure
if (null eq result) return null
else {
Copy link
Contributor

Choose a reason for hiding this comment

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

While we're at it, let's remove this else statement. It doesn't make sense since return will exit the method anyways

Copy link
Member Author

Choose a reason for hiding this comment

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

Done

Comment on lines 1105 to 1107
if (first eq ZIO.unit) cur = fold.successK(())
else if (first.isInstanceOf[Success[Any]]) cur = fold.successK(first.asInstanceOf[Success[Any]].value)
else if (first.isInstanceOf[Failure[Any]]) cur = exitFailure(first.asInstanceOf[Failure[Any]].cause)
Copy link
Contributor

Choose a reason for hiding this comment

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

I think let's keep Fold as is to make it easier on the C2 compiler to optimize the branches. I run the ZIO test suite using if (fold.first eq ZIO.unit) println("fold.first is ZIO.unit") and it was printed 50 times only, so perhaps the shortcut here might end up making things worse overall

Copy link
Member Author

Choose a reason for hiding this comment

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

I run the ZIO test suite using if (fold.first eq ZIO.unit) println("fold.first is ZIO.unit") and it was printed 50 times only, so perhaps the shortcut here might end up making things worse overall

Don't you think this might happen more often in a real codebase? πŸ€”
If it's happening 50 times just in the unit tests, I'd expect it more in an actual code, no?

Copy link
Contributor

Choose a reason for hiding this comment

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

If it's happening 50 times just in the unit tests, I'd expect it more in an actual code, no?

I find it a bit hard to believe. There are 2,500 tests (plus nonFlaky annotations) plus the test executor code etc. A single test can contain hundreds/thousands of invocations of the runloop. I find it a bit hard to believe that user code will somehow result in having lots of cases where the this branch would be invoked

Copy link
Member Author

@guizmaii guizmaii Dec 12, 2024

Choose a reason for hiding this comment

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

Fair enough. I made the change

Copy link
Member Author

Choose a reason for hiding this comment

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

It might be interesting to explore (in another PR) optimisation the handling of this kind of case:
image

This is, I think, very common in the ZIO code to use .foldZIO(success = ZIO.successFn, ...)

Don't you think? πŸ€”

Comment on lines 1100 to 1101
@inline def exitFailure(cause: Cause[Any]): ZIO.Erased =
if (shouldInterrupt()) Exit.Failure(cause.stripFailures) else fold.failureK(cause)
Copy link
Contributor

Choose a reason for hiding this comment

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

This comment is redundant because I think we'll end up removing this code, but as a side-note, the @inline annotation doesn't work for Scala 3. So for performance-critical code paths we either shouldn't be using it or we should make it Scala-version specific

Copy link
Member Author

Choose a reason for hiding this comment

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

Removed

@guizmaii guizmaii changed the title Optimisation - FiberRuntime: bypass evaluation of flatmap.first and fold.first when possible Optimisation - FiberRuntime: bypass evaluation of flatmap.first when possible Dec 12, 2024
Comment on lines +1108 to +1110
case f: Failure[Any] =>
val cause = f.cause
if (shouldInterrupt()) cur = Exit.Failure(cause.stripFailures)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why do we need to strip the failure at all?

Copy link
Member Author

Choose a reason for hiding this comment

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

No idea. That's a good question πŸ™‚

Copy link
Contributor

@kyri-petrou kyri-petrou left a comment

Choose a reason for hiding this comment

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

Thanks again πŸ™

@kyri-petrou kyri-petrou merged commit a3f32b0 into series/2.x Dec 13, 2024
18 checks passed
@kyri-petrou kyri-petrou deleted the FlatMap_less_0 branch December 13, 2024 01:38
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