He-Pin opened a new pull request, #3091:
URL: https://github.com/apache/pekko/pull/3091

   ### Motivation
   
   `Source.actorRef` used `getEagerStageActor` which creates a `(ActorRef, 
Any)` Tuple2 (~24 bytes) per message via the StageActor FunctionRef lambda, 
even though the sender is never used. Additionally, when the buffer is empty 
and downstream has demand, elements went through an unnecessary enqueue→dequeue 
round-trip. A separate correctness issue existed where `StageActor.localCell` 
could throw `IllegalStateException` on the first materialization of a fresh 
ActorSystem due to an `UnstartedCell` race.
   
   Inspired by 
[akka.net#8263](https://github.com/akkadotnet/akka.net/pull/8263) which 
achieved -35% latency / +53% throughput on the same code path.
   
   ### Modification
   
   1. **Fix UnstartedCell race** (`GraphStage.scala`): `StageActor.localCell` 
now handles `UnstartedCell` by force-starting the supervisor via 
`Ask(Identify)`. This is a global fix — all stages using 
`getStageActor`/`getEagerStageActor` benefit.
   
   2. **Direct-push fast path** (`ActorRefSource.scala`): When the buffer is 
empty and downstream has demand, elements are pushed directly without going 
through the buffer, eliminating the enqueue→dequeue overhead.
   
   3. **Bypass StageActor** (`ActorRefSource.scala`): Replace 
`getEagerStageActor` with a direct `FunctionRef` on the supervisor's 
`ActorCell`, using a message-only `AsyncCallback[Any]` — no tuple boxing. 
PoisonPill/Kill are intercepted at the FunctionRef level.
   
   4. **Shared cell resolution**: Extracted `resolveSupervisorCell` on 
`GraphStageLogic` to eliminate duplicated cell resolution logic.
   
   5. **JMH benchmarks**: Added `ActorRefSourceBenchmark` with two targeted 
measurements:
      - `no_buffer` (buffer=0): isolates FunctionRef+AsyncCallback path cost
      - `pingpong` (buffer=1, sync send-wait): 100% direct-path hits
   
   ### Result
   
   Benchmark results (10 iterations, 5 warmup, same machine):
   
   | Benchmark | Before | After | Δ |
   |-----------|-------:|------:|---:|
   | no_buffer (buffer=0) | 18.0M ±0.5M | **19.5M ±1.0M** | **+8.3%** |
   | pingpong (buffer=1, sync) | 883K ±34K | **988K ±29K** | **+11.9%** |
   
   Both benchmarks show statistically significant improvement (99.9% CI 
non-overlapping). Per-element allocation reduced by ~24 bytes (Tuple2 
elimination).
   
   ### Tests
   
   - `ActorRefSourceSpec`: 18/18 (incl. 5 new regression tests)
     - UnstartedCell startup race
     - Direct-push fast path
     - PoisonPill ignored for T=Any
     - Kill ignored for T=Any
     - Post-completion message routing
   - `StageActorRefSpec`: 11/11 (no regressions)
   - `ActorRefBackpressureSourceSpec`: 5/5 (no regressions)
   
   ### References
   
   Refs https://github.com/akkadotnet/akka.net/pull/8263


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to