Skip to content
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

=act Make Behavior.start tailrec. #28905

Closed
wants to merge 1 commit into from
Closed

Conversation

He-Pin
Copy link
Member

@He-Pin He-Pin commented Apr 8, 2020

Make it a tailrec and using a depth limit to it.

// that deep, and if they are it's most likely a bug which will be seen as StackOverflowError
if (maxDepth > 8192) {
Copy link
Member Author

Choose a reason for hiding this comment

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

just hard code this for safety

@akka-ci akka-ci added validating PR is currently being validated by Jenkins tested PR that was successfully built and tested by Jenkins and removed validating PR is currently being validated by Jenkins labels Apr 8, 2020
@akka-ci
Copy link

akka-ci commented Apr 8, 2020

Test PASSed.

@akka-ci akka-ci added validating PR is currently being validated by Jenkins and removed tested PR that was successfully built and tested by Jenkins labels Apr 8, 2020
@akka-ci akka-ci added tested PR that was successfully built and tested by Jenkins and removed validating PR is currently being validated by Jenkins labels Apr 8, 2020
@akka-ci
Copy link

akka-ci commented Apr 8, 2020

Test PASSed.

@akka-ci akka-ci added validating PR is currently being validated by Jenkins tested PR that was successfully built and tested by Jenkins and removed tested PR that was successfully built and tested by Jenkins validating PR is currently being validated by Jenkins labels Apr 8, 2020
@akka-ci
Copy link

akka-ci commented Apr 8, 2020

Test PASSed.

def internalStart(
behavior: Behavior[T],
ctx: TypedActorContext[T],
interceptorsStack: List[InterceptorImpl[T, Any]] = Nil,
Copy link
Member

@johanandren johanandren Apr 8, 2020

Choose a reason for hiding this comment

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

Not really a big improvement replacing the thread stack with our own, with another limit, is it?

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 think we can adjust the max depth and it's more consistent when error occur, isn't it?
Different environments have different Xss configs.

Copy link
Member

Choose a reason for hiding this comment

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

I don't expect that we will ever see a stack overflow here even with small stacks, if the behavior stack grows so much that it does hit the max stack size it will be because of a bug, for example when each interpreted message adds a new interceptor somehow.

I think the comment that it should/could be tailrec was perhaps misleading

maxDepth: Int = 0): Behavior[T] = {
// normal stack of interceptors and similar shouldn't be
// that deep, and if they are it's most likely a bug which will be seen as StackOverflowError
if (maxDepth > 8192) {
Copy link
Member Author

@He-Pin He-Pin Apr 8, 2020

Choose a reason for hiding this comment

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

This number can be adjusted.

Copy link
Member

Choose a reason for hiding this comment

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

But how is 8192 chosen? And how would that be adjusted?

I don't think we should have a fixed magical number. We never know in which JVM this will run. And having it adjustable by the user seems to me a leaked abstraction.

Copy link
Member

@octonato octonato Apr 8, 2020

Choose a reason for hiding this comment

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

ah ok, I should have search before commenting. 8192 is the deault StackOverflow size.

Not true what I wrote here. My question still then relevant. Why 8192? The issue is memory, not amount of nesting.

Copy link
Member Author

Choose a reason for hiding this comment

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

@renatocaval For myself,I want to remove the limit of depth too, but as a PR, I think it would be great to simulate it's previous behavior.
I just pick up 8192 randomly because we do not know how many frames can be there before it throws a StackOverflowError.

// note that this can't be @tailrec, but normal stack of interceptors and similar shouldn't be
// that deep, and if they are it's most likely a bug which will be seen as StackOverflowError

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 bring this up for discussion, thanks for your inputs.

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 have updated this and removed the maxDepth as it can only be a bug when OOM.

@akka-ci akka-ci added validating PR is currently being validated by Jenkins tested PR that was successfully built and tested by Jenkins and removed tested PR that was successfully built and tested by Jenkins validating PR is currently being validated by Jenkins labels Apr 8, 2020
@akka-ci
Copy link

akka-ci commented Apr 8, 2020

Test PASSed.

}
internalStart(behavior, ctx)
Copy link
Member

Choose a reason for hiding this comment

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

Isn't this similar to the attempt in #27364 ?
It's replacing the stack with a collection. I'm not sure there are any advantages of doing that.

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 have forgotten that. I came up with this once I read in detail of the Behavior code. With this change, it will work more concisely, at least it doesn't harm, isn't it? Different deploy environments XSS configs various too.

Copy link
Member

Choose a reason for hiding this comment

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

I ran a temporary benchmark comparing the two and this is about 30% slower.

BEFORE:

[info] Benchmark                                               (batchSize)    (dispatcher)                                         (mailbox)  (tpt)   Mode  Cnt        Score        Error   Units
[info] TypedActorBenchmark.start                                        50  fjp-dispatcher  akka.dispatch.SingleConsumerOnlyUnboundedMailbox     50  thrpt    6  8048211,084 ± 156294,353   ops/s

AFTER:

[info] Benchmark                                               (batchSize)    (dispatcher)                                         (mailbox)  (tpt)   Mode  Cnt        Score        Error   Units
[info] TypedActorBenchmark.start                                        50  fjp-dispatcher  akka.dispatch.SingleConsumerOnlyUnboundedMailbox     50  thrpt    6  5772894,593 ± 257261,651   ops/s

Used the following in TypedActorBenchmark:

  private val behv: Behavior[Start] =
    Behaviors
      .supervise[Start] {
        Behaviors.setup[Start] { _ =>
          Behaviors.withMdc(Map.empty[String, String]) {
            Behaviors.receiveMessage[Start](_ => Behaviors.same)
          }
        }
      }
      .onFailure[Exception](SupervisorStrategy.restart)

  def startSupervisor(iteration: Int): Behavior[Start] =
    Behaviors.receive { (ctx, msg) =>
      msg match {
        case Start(respondTo) =>
          val startNanoTime = System.nanoTime()

          var i = 0
          while (i < iteration) {
            Behavior.start(behv, ctx)
            i += 1
          }

          respondTo ! Completed(startNanoTime)
          Behaviors.same
      }
    }

  @Benchmark
  @OperationsPerInvocation(iterations)
  def start(): Unit = {
    Await.result(system.ask(Start), timeout)
  }

Copy link
Member Author

Choose a reason for hiding this comment

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

Then it's not worth it.

@akka-ci akka-ci added the validating PR is currently being validated by Jenkins label Apr 12, 2020
@akka-ci akka-ci added tested PR that was successfully built and tested by Jenkins and removed tested PR that was successfully built and tested by Jenkins validating PR is currently being validated by Jenkins labels Apr 12, 2020
@akka-ci
Copy link

akka-ci commented Apr 12, 2020

Test PASSed.

@patriknw
Copy link
Member

Closing this because I don't think it is an improvement over status quo.

@patriknw patriknw closed this Apr 27, 2020
@patriknw
Copy link
Member

but thanks anyway

@He-Pin
Copy link
Member Author

He-Pin commented Apr 27, 2020

The performance is always critical for Akka, let's keep this in mind once we do encounter any problem later.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
tested PR that was successfully built and tested by Jenkins
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants