Skip to content

rppgrpc: client reactors post the first read before StartCall - #764

Open
daixtrose wants to merge 6 commits into
AlexInLog:v2from
daixtrose:fix/762-rppgrpc-init-order
Open

daixtrose wants to merge 6 commits into
AlexInLog:v2from
daixtrose:fix/762-rppgrpc-init-order

Conversation

@daixtrose

@daixtrose daixtrose commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #762.

client_bidi_reactor::init() and client_read_reactor::init() call StartCall() and then post the first StartRead() from the caller's thread. If the call ends at once (connection refused, deadline, cancelled context), gRPC can finish it on its own threads right after StartCall() and run OnDone(), which does delete this, while init() is still running. The read then runs on a freed reactor or on a call that has already ended.

Change. init() posts the first read before StartCall(). The gRPC callback API allows this (client_callback.h at v1.51.1):

Activate the RPC and initiate any reads or writes that have been Start'ed before this call.

Initiate a read operation (or post it for later initiation if StartCall has not yet been invoked).

With this order init() starts no operation after StartCall(), so no hold is needed (L291-L293):

Holds are needed if (and only if) this stream has operations that take place on it after StartCall but from outside one of the reactions (OnReadDone, etc).

AddHold()/RemoveHold() around init() would also be correct. I chose the reorder because it needs no extra calls or state.

client_write_reactor::init() only calls StartCall(), so it has no such window. Writes are a related case. For the bidi and write reactors, the doc comments and the doxygen example now emit the first value before init(); gRPC posts it until the call starts, and the existing tests already use this order. A write posted after init() from outside a reaction still needs a hold under the gRPC rules (L301-L312). Adding one would change when OnDone can run, so it is not part of this PR.

Test. New case in test_async_client.cpp, "async client reactor: call that ends during init()": 300 calls per reactor type on the in-process channel, each with its context cancelled before init(). Results with AddressSanitizer (GCC 14.2, gRPC 1.51.1, Debian trixie):

before after
new test case AddressSanitizer error in 10 of 10 runs (8 heap-use-after-free, 2 unknown-crash) 10 of 10 runs pass
reproducer from #762 (read reactor, 2000 calls to a closed port) heap-use-after-free in 10 of 10 runs 10 of 10 runs clean
read and bidi reactors, refused and cancelled calls, 3 runs each AddressSanitizer error in 12 of 12 runs 12 of 12 runs clean

The rest of test_async_client passes as well. I built these tests against the system gRPC rather than through the conan setup, and did not run the repository's CI presets.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Improved handling of client calls cancelled before startup, helping ensure they still report completion reliably.
  • Documentation
    • Clarified when to send initial requests and how reactor lifecycle and external writes can affect call completion.
  • Examples
    • Updated client reactor examples to send initial requests before starting the call.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Important

Review skipped

Review was skipped as selected files did not have any reviewable changes.

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: dd970c6b-c243-42c1-a342-30dd0ecee402
Commits

Reviewing files that changed from the base of the PR and between 9eee7c8 and 44e6834.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

No actionable comments were generated in the recent review.

ℹ️ Recent review info
⚙️ Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 04c6f14e-ba77-458b-830e-677be818bf7a
📥 Commits

Reviewing files that changed from the base of the PR and between 3163483 and 6a76aab.

📒 Files selected for processing: 3
  • src/examples/rppgrpc/doxygen/client_reactor.cpp
  • src/extensions/rppgrpc/rppgrpc/client_reactor.hpp
  • src/tests/rppgrpc/test_async_client.cpp

Included review availability: This review used your included allowance. Your plan provides up to 2 included reviews per hour; 0 remain after this review.

Walkthrough

Bidirectional and read reactors now post their initial operations before StartCall(). Documentation and examples describe posting initial values before init(). A regression test exercises cancelled calls for three reactor types.

Changes: Client reactor startup

Layer / File(s) Summary
Reactor startup and lifecycle
src/extensions/rppgrpc/rppgrpc/client_reactor.hpp
Bidirectional and read reactors post the first read before StartCall(). The documentation describes possible reactor deletion after init() and warns about races from external emissions without a gRPC hold.
Usage examples and cancellation coverage
src/examples/rppgrpc/doxygen/client_reactor.cpp, src/tests/rppgrpc/test_async_client.cpp
The bidirectional and write examples post initial requests before init(). The regression test runs 300 cancelled calls per reactor type and checks for a terminal observable notification within five seconds.

Priority: Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix · Severity of issue fixed: Medium

Suggested reviewers: alexinlog

Merge Risk: Minimal · up to 6a76a

The startup change and updated examples have no identified merge-blocking issue. Normal validation can proceed.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 3 functions across 3 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title names the primary change: client reactors in rppgrpc now post the first read before StartCall, which matches the changes to client_bidi_reactor::init() and client_read_reactor::init() and th…
Linked Issues check Passed Direct issue #762 requires preventing reactor use after StartCall() in the read and bidi reactor initialization paths. client_read_reactor::init() and client_bidi_reactor::init() now post the fi…
Out of Scope Changes check Passed The changed files stay within issue #762. The header and Doxygen changes document the safe initialization order and the gRPC hold requirement. The test adds regression coverage for call completion dur…
Full details: Title check

Explanation

The title names the primary change: client reactors in rppgrpc now post the first read before StartCall, which matches the changes to client_bidi_reactor::init() and client_read_reactor::init() and the linked issue #762 about a heap-use-after-free in client_read_reactor::init(). It is short, specific, and free of noise. The title does not mention the test addition or the documentation updates, which is acceptable because it need not cover every detail.

Full details: Linked Issues check

Explanation

Direct issue #762 requires preventing reactor use after StartCall() in the read and bidi reactor initialization paths. client_read_reactor::init() and client_bidi_reactor::init() now post the first read before StartCall(), and StartCall() is the final reactor use in each method. The added test covers cancelled calls during init() for the read, bidi, and write reactor types and waits for terminal notification. The documentation and Doxygen example match the required pre-init() ordering. Issue #762 only identifies later external writes as a suspected related case, so the lack of a new hold for those writes is not an unmet requirement.

Full details: Out of Scope Changes check

Explanation

The changed files stay within issue #762. The header and Doxygen changes document the safe initialization order and the gRPC hold requirement. The test adds regression coverage for call completion during init(). The write-reactor test case provides related coverage without changing write initialization behavior. No unrelated production behavior or unrelated feature is shown.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

A rabbit posts a read before the call,
Then waits for StartCall() to begin it all.
Three hundred calls through cancel’s chilly night,
Each sends a terminal sign in sight.
The burrow rests; the reactors finish right.

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown
Contributor

BENCHMARK RESULTS (AUTOGENERATED)

ci-ubuntu-gcc

General

name rxcpp rpp prev rpp ratio rpp no optimization
Subscribe empty callbacks to empty observable 320.60 ns 1.56 ns 1.87 ns 0.83 1.10 ns
Subscribe empty callbacks to empty observable via pipe operator 309.75 ns 1.56 ns 1.87 ns 0.83 1.09 ns

Sources

name rxcpp rpp prev rpp ratio rpp no optimization
from array of 1 - create + subscribe + immediate 699.33 ns 0.31 ns 0.31 ns 1.00 0.27 ns
from array of 1 - create + subscribe + current_thread 1051.94 ns 3.45 ns 3.45 ns 1.00 2.74 ns
concat_as_source of just(1 immediate) create + subscribe 2259.16 ns 114.54 ns 128.23 ns 0.89 94.99 ns
defer from array of 1 - defer + create + subscribe + immediate 740.17 ns 0.31 ns 0.31 ns 1.00 0.27 ns
interval - interval + take(3) + subscribe + immediate 2144.28 ns 59.70 ns 59.66 ns 1.00 50.11 ns
interval - interval + take(3) + subscribe + current_thread 3050.96 ns 32.76 ns 32.72 ns 1.00 29.20 ns
from array of 1 - create + as_blocking + subscribe + new_thread 35885.71 ns 33311.22 ns 34766.46 ns 0.96 27306.19 ns
from array of 1000 - create + as_blocking + subscribe + new_thread 44805.38 ns 55782.26 ns 56094.37 ns 0.99 44053.19 ns
concat_as_source of just(1 immediate) and just(1,2 immediate)create + subscribe 3564.73 ns 142.20 ns 148.33 ns 0.96 132.91 ns

Filtering Operators

name rxcpp rpp prev rpp ratio rpp no optimization
immediate_just+take(1)+subscribe 1084.56 ns 0.31 ns 0.31 ns 1.00 0.27 ns
immediate_just+filter(true)+subscribe 850.51 ns 0.31 ns 0.31 ns 1.00 0.27 ns
immediate_just(1,2)+skip(1)+subscribe 1015.42 ns 0.31 ns 0.31 ns 1.00 0.27 ns
immediate_just(1,1,2)+distinct_until_changed()+subscribe 891.78 ns 0.31 ns 0.31 ns 1.00 0.27 ns
immediate_just(1,2)+first()+subscribe 1265.15 ns 0.31 ns 0.31 ns 1.00 0.27 ns
immediate_just(1,2)+last()+subscribe 948.26 ns 0.31 ns 0.31 ns 1.00 0.27 ns
immediate_just+take_last(1)+subscribe 1121.27 ns 18.05 ns 18.05 ns 1.00 15.28 ns
immediate_just(1,2,3)+element_at(1)+subscribe 838.81 ns 0.31 ns 0.31 ns 1.00 0.27 ns

Schedulers

name rxcpp rpp prev rpp ratio rpp no optimization
immediate scheduler create worker + schedule 264.14 ns 0.62 ns 1.56 ns 0.40 0.54 ns
current_thread scheduler create worker + schedule 377.88 ns 4.98 ns 4.98 ns 1.00 3.82 ns
current_thread scheduler create worker + schedule + recursive schedule 820.94 ns 61.31 ns 62.68 ns 0.98 52.29 ns

Transforming Operators

name rxcpp rpp prev rpp ratio rpp no optimization
immediate_just+map(v*2)+subscribe 846.11 ns 0.31 ns 0.31 ns 1.00 0.27 ns
immediate_just+scan(10, std::plus)+subscribe 917.09 ns 0.31 ns 0.31 ns 1.00 0.27 ns
immediate_just+flat_map(immediate_just(v*2))+subscribe 2347.62 ns 120.19 ns 139.91 ns 0.86 154.36 ns
immediate_just+buffer(2)+subscribe 1563.92 ns 13.70 ns 13.72 ns 1.00 15.84 ns
immediate_just+window(2)+subscribe + subscsribe inner 2465.18 ns 1309.86 ns 1360.01 ns 0.96 1051.23 ns

Conditional Operators

name rxcpp rpp prev rpp ratio rpp no optimization
immediate_just+take_while(false)+subscribe 845.07 ns - - 0.00 -
immediate_just+take_while(true)+subscribe 843.75 ns 0.31 ns 0.31 ns 1.00 0.27 ns

Utility Operators

name rxcpp rpp prev rpp ratio rpp no optimization
immediate_just(1)+subscribe_on(immediate)+subscribe 2006.76 ns 0.31 ns 0.31 ns 1.00 0.27 ns

Combining Operators

name rxcpp rpp prev rpp ratio rpp no optimization
immediate_just(immediate_just(1), immediate_just(1)) + merge() + subscribe 3425.04 ns 164.50 ns 157.06 ns 1.05 169.45 ns
immediate_just(1) + merge_with(immediate_just(2)) + subscribe 3692.58 ns 156.38 ns 162.67 ns 0.96 158.04 ns
immediate_just(1) + with_latest_from(immediate_just(2)) + subscribe - 149.40 ns 145.78 ns 1.02 131.53 ns
immediate_just(immediate_just(1),immediate_just(1)) + switch_on_next() + subscribe 3546.45 ns 480.85 ns 418.19 ns 1.15 342.56 ns
immediate_just(1) + zip(immediate_just(2)) + subscribe 2202.34 ns 229.39 ns 225.02 ns 1.02 203.01 ns
immediate_just(immediate_just(1), immediate_just(1)) + concat() + subscribe 3232.94 ns 228.91 ns 239.71 ns 0.95 229.88 ns

Subjects

name rxcpp rpp prev rpp ratio rpp no optimization
publish_subject with 1 observer - on_next 34.85 ns 14.81 ns 14.79 ns 1.00 12.94 ns
subscribe 100 observers to publish_subject 201779.60 ns 17498.20 ns 17755.66 ns 0.99 16059.24 ns
100 on_next to 100 observers to publish_subject 28890.05 ns 19969.39 ns 20388.50 ns 0.98 22791.94 ns

Scenarios

name rxcpp rpp prev rpp ratio rpp no optimization
basic sample 1409.76 ns 13.39 ns 13.38 ns 1.00 18.94 ns
basic sample with immediate scheduler 1432.75 ns 5.60 ns 5.59 ns 1.00 12.05 ns
mix operators with disposables and without disposables 6382.27 ns 1439.21 ns 1464.13 ns 0.98 1482.32 ns
single disposable and looooooong indentity chain 24157.51 ns 1117.13 ns 1074.46 ns 1.04 3849.36 ns

Aggregating Operators

name rxcpp rpp prev rpp ratio rpp no optimization
immediate_just+reduce(10, std::plus)+subscribe 927.95 ns 0.31 ns 0.31 ns 1.00 0.27 ns

Error Handling Operators

name rxcpp rpp prev rpp ratio rpp no optimization
create(on_next(1), on_error())+on_error_resume_next(immediate_just(2)))+subscribe 2068.33 ns 981.99 ns 1010.45 ns 0.97 762.94 ns
create(on_error())+retry(1)+subscribe 594.24 ns 114.18 ns 131.00 ns 0.87 101.26 ns

ci-macos

General

name rxcpp rpp prev rpp ratio rpp no optimization
Subscribe empty callbacks to empty observable 571.79 ns 0.54 ns 0.49 ns 1.09 0.54 ns
Subscribe empty callbacks to empty observable via pipe operator 402.51 ns 0.57 ns 0.50 ns 1.13 0.51 ns

Sources

name rxcpp rpp prev rpp ratio rpp no optimization
from array of 1 - create + subscribe + immediate 885.42 ns 0.35 ns 0.34 ns 1.03 0.31 ns
from array of 1 - create + subscribe + current_thread 1298.15 ns 4.29 ns 3.93 ns 1.09 3.89 ns
concat_as_source of just(1 immediate) create + subscribe 2941.94 ns 210.73 ns 183.10 ns 1.15 233.43 ns
defer from array of 1 - defer + create + subscribe + immediate 1011.85 ns 0.47 ns 0.36 ns 1.33 0.35 ns
interval - interval + take(3) + subscribe + immediate 2732.14 ns 78.41 ns 59.16 ns 1.33 59.41 ns
interval - interval + take(3) + subscribe + current_thread 3347.10 ns 37.89 ns 36.01 ns 1.05 35.65 ns
from array of 1 - create + as_blocking + subscribe + new_thread 47876.91 ns 44243.04 ns 26443.10 ns 1.67 45123.09 ns
from array of 1000 - create + as_blocking + subscribe + new_thread 50960.53 ns 57382.26 ns 31683.33 ns 1.81 32998.50 ns
concat_as_source of just(1 immediate) and just(1,2 immediate)create + subscribe 5422.33 ns 294.29 ns 200.32 ns 1.47 210.45 ns

Filtering Operators

name rxcpp rpp prev rpp ratio rpp no optimization
immediate_just+take(1)+subscribe 1246.78 ns 0.51 ns 0.35 ns 1.46 0.42 ns
immediate_just+filter(true)+subscribe 1338.47 ns 0.45 ns 0.46 ns 0.99 0.39 ns
immediate_just(1,2)+skip(1)+subscribe 1863.47 ns 0.52 ns 0.40 ns 1.32 0.46 ns
immediate_just(1,1,2)+distinct_until_changed()+subscribe 1098.92 ns 0.47 ns 0.37 ns 1.27 0.37 ns
immediate_just(1,2)+first()+subscribe 1545.41 ns 0.54 ns 0.39 ns 1.38 0.39 ns
immediate_just(1,2)+last()+subscribe 2264.80 ns 1.08 ns 1.01 ns 1.07 1.07 ns
immediate_just+take_last(1)+subscribe 2381.79 ns 0.45 ns 0.41 ns 1.10 0.39 ns
immediate_just(1,2,3)+element_at(1)+subscribe 972.95 ns 0.52 ns 0.37 ns 1.38 0.34 ns

Schedulers

name rxcpp rpp prev rpp ratio rpp no optimization
immediate scheduler create worker + schedule 721.11 ns 0.65 ns 0.56 ns 1.16 0.59 ns
current_thread scheduler create worker + schedule 850.05 ns 4.82 ns 4.42 ns 1.09 4.52 ns
current_thread scheduler create worker + schedule + recursive schedule 826.22 ns 73.07 ns 71.56 ns 1.02 76.40 ns

Transforming Operators

name rxcpp rpp prev rpp ratio rpp no optimization
immediate_just+map(v*2)+subscribe 963.18 ns 4.52 ns 3.23 ns 1.40 3.30 ns
immediate_just+scan(10, std::plus)+subscribe 2219.26 ns 0.41 ns 0.36 ns 1.15 0.38 ns
immediate_just+flat_map(immediate_just(v*2))+subscribe 4010.38 ns 287.69 ns 209.37 ns 1.37 244.00 ns
immediate_just+buffer(2)+subscribe 2561.78 ns 16.43 ns 17.13 ns 0.96 22.40 ns
immediate_just+window(2)+subscribe + subscsribe inner 2251.15 ns 2574.25 ns 1148.06 ns 2.24 1475.93 ns

Conditional Operators

name rxcpp rpp prev rpp ratio rpp no optimization
immediate_just+take_while(false)+subscribe 1152.60 ns - - 0.00 -
immediate_just+take_while(true)+subscribe 1612.84 ns 0.56 ns 0.39 ns 1.45 0.40 ns

Utility Operators

name rxcpp rpp prev rpp ratio rpp no optimization
immediate_just(1)+subscribe_on(immediate)+subscribe 2309.51 ns 2.67 ns 1.94 ns 1.37 2.35 ns

Combining Operators

name rxcpp rpp prev rpp ratio rpp no optimization
immediate_just(immediate_just(1), immediate_just(1)) + merge() + subscribe 3205.01 ns 296.66 ns 230.48 ns 1.29 339.87 ns
immediate_just(1) + merge_with(immediate_just(2)) + subscribe 4211.93 ns 241.60 ns 207.75 ns 1.16 248.22 ns
immediate_just(1) + with_latest_from(immediate_just(2)) + subscribe - 409.58 ns 214.98 ns 1.91 264.76 ns
immediate_just(immediate_just(1),immediate_just(1)) + switch_on_next() + subscribe 3849.69 ns 665.16 ns 505.87 ns 1.31 623.92 ns
immediate_just(1) + zip(immediate_just(2)) + subscribe 3899.66 ns 331.24 ns 292.92 ns 1.13 364.17 ns
immediate_just(immediate_just(1), immediate_just(1)) + concat() + subscribe 3420.67 ns 349.93 ns 322.01 ns 1.09 388.28 ns

Subjects

name rxcpp rpp prev rpp ratio rpp no optimization
publish_subject with 1 observer - on_next 237.58 ns 50.55 ns 23.40 ns 2.16 23.64 ns
subscribe 100 observers to publish_subject 134709.00 ns 138083.00 ns 19641.53 ns 7.03 16178.08 ns
100 on_next to 100 observers to publish_subject 80413.71 ns 15805.80 ns 12055.55 ns 1.31 14686.93 ns

Scenarios

name rxcpp rpp prev rpp ratio rpp no optimization
basic sample 1483.15 ns 11.14 ns 11.76 ns 0.95 28.75 ns
basic sample with immediate scheduler 2102.64 ns 8.20 ns 6.53 ns 1.26 9.09 ns
mix operators with disposables and without disposables 13245.16 ns 1821.47 ns 1547.47 ns 1.18 1876.25 ns
single disposable and looooooong indentity chain 25903.41 ns 2300.42 ns 2184.15 ns 1.05 4515.64 ns

Aggregating Operators

name rxcpp rpp prev rpp ratio rpp no optimization
immediate_just+reduce(10, std::plus)+subscribe 1481.74 ns 0.40 ns 0.36 ns 1.09 0.38 ns

Error Handling Operators

name rxcpp rpp prev rpp ratio rpp no optimization
create(on_next(1), on_error())+on_error_resume_next(immediate_just(2)))+subscribe 15109.76 ns 3097.22 ns 3500.00 ns 0.88 3644.15 ns
create(on_error())+retry(1)+subscribe 1415.15 ns 209.67 ns 204.52 ns 1.03 195.08 ns

ci-ubuntu-clang

General

name rxcpp rpp prev rpp ratio rpp no optimization
Subscribe empty callbacks to empty observable 165.36 ns 0.31 ns 0.65 ns 0.47 1.56 ns
Subscribe empty callbacks to empty observable via pipe operator 161.39 ns 0.32 ns 0.64 ns 0.50 1.56 ns

Sources

name rxcpp rpp prev rpp ratio rpp no optimization
from array of 1 - create + subscribe + immediate 316.92 ns 0.22 ns 0.31 ns 0.71 0.31 ns
from array of 1 - create + subscribe + current_thread 458.35 ns 1.72 ns 4.04 ns 0.43 4.04 ns
concat_as_source of just(1 immediate) create + subscribe 3062.09 ns 170.18 ns 130.66 ns 1.30 132.14 ns
defer from array of 1 - defer + create + subscribe + immediate 1043.66 ns 0.22 ns 0.31 ns 0.71 0.31 ns
interval - interval + take(3) + subscribe + immediate 3115.72 ns 41.37 ns 58.73 ns 0.70 59.18 ns
interval - interval + take(3) + subscribe + current_thread 4482.62 ns 22.35 ns 31.10 ns 0.72 31.76 ns
from array of 1 - create + as_blocking + subscribe + new_thread 14399.09 ns 13593.06 ns 35051.18 ns 0.39 33765.67 ns
from array of 1000 - create + as_blocking + subscribe + new_thread 17068.82 ns 15701.75 ns 41557.71 ns 0.38 40605.72 ns
concat_as_source of just(1 immediate) and just(1,2 immediate)create + subscribe 4481.38 ns 201.49 ns 148.81 ns 1.35 149.13 ns

Filtering Operators

name rxcpp rpp prev rpp ratio rpp no optimization
immediate_just+take(1)+subscribe 1514.64 ns 0.22 ns 0.31 ns 0.71 0.31 ns
immediate_just+filter(true)+subscribe 1181.12 ns 0.23 ns 0.31 ns 0.73 0.31 ns
immediate_just(1,2)+skip(1)+subscribe 1452.96 ns 0.22 ns 0.31 ns 0.71 0.31 ns
immediate_just(1,1,2)+distinct_until_changed()+subscribe 1157.33 ns 0.22 ns 0.32 ns 0.70 0.33 ns
immediate_just(1,2)+first()+subscribe 1822.41 ns 0.22 ns 0.31 ns 0.72 0.31 ns
immediate_just(1,2)+last()+subscribe 1354.40 ns 0.22 ns 0.31 ns 0.71 0.31 ns
immediate_just+take_last(1)+subscribe 1575.58 ns 0.22 ns 0.31 ns 0.71 0.31 ns
immediate_just(1,2,3)+element_at(1)+subscribe 1160.72 ns 0.22 ns 0.31 ns 0.71 0.31 ns

Schedulers

name rxcpp rpp prev rpp ratio rpp no optimization
immediate scheduler create worker + schedule 411.95 ns 0.44 ns 1.55 ns 0.28 0.64 ns
current_thread scheduler create worker + schedule 499.17 ns 1.87 ns 4.04 ns 0.46 4.05 ns
current_thread scheduler create worker + schedule + recursive schedule 1157.67 ns 36.94 ns 57.71 ns 0.64 65.62 ns

Transforming Operators

name rxcpp rpp prev rpp ratio rpp no optimization
immediate_just+map(v*2)+subscribe 1397.08 ns 0.25 ns 0.31 ns 0.81 0.31 ns
immediate_just+scan(10, std::plus)+subscribe 1314.12 ns 0.30 ns 0.62 ns 0.48 0.33 ns
immediate_just+flat_map(immediate_just(v*2))+subscribe 2916.33 ns 183.34 ns 139.26 ns 1.32 137.02 ns
immediate_just+buffer(2)+subscribe 1523.83 ns 6.60 ns 14.00 ns 0.47 14.63 ns
immediate_just+window(2)+subscribe + subscsribe inner 2678.01 ns 1141.47 ns 900.95 ns 1.27 932.00 ns

Conditional Operators

name rxcpp rpp prev rpp ratio rpp no optimization
immediate_just+take_while(false)+subscribe 2269.86 ns - - 0.00 -
immediate_just+take_while(true)+subscribe 1453.29 ns 0.38 ns 0.31 ns 1.22 0.31 ns

Utility Operators

name rxcpp rpp prev rpp ratio rpp no optimization
immediate_just(1)+subscribe_on(immediate)+subscribe 2641.92 ns 0.22 ns 0.31 ns 0.72 0.31 ns

Combining Operators

name rxcpp rpp prev rpp ratio rpp no optimization
immediate_just(immediate_just(1), immediate_just(1)) + merge() + subscribe 4320.62 ns 211.11 ns 164.06 ns 1.29 155.81 ns
immediate_just(1) + merge_with(immediate_just(2)) + subscribe 5022.75 ns 212.39 ns 143.64 ns 1.48 141.36 ns
immediate_just(1) + with_latest_from(immediate_just(2)) + subscribe - 193.24 ns 143.37 ns 1.35 138.79 ns
immediate_just(immediate_just(1),immediate_just(1)) + switch_on_next() + subscribe 5871.55 ns 596.81 ns 381.48 ns 1.56 377.88 ns
immediate_just(1) + zip(immediate_just(2)) + subscribe 2874.70 ns 258.08 ns 216.27 ns 1.19 203.35 ns
immediate_just(immediate_just(1), immediate_just(1)) + concat() + subscribe 4213.97 ns 314.16 ns 226.57 ns 1.39 224.93 ns

Subjects

name rxcpp rpp prev rpp ratio rpp no optimization
publish_subject with 1 observer - on_next 71.34 ns 29.47 ns 19.24 ns 1.53 22.93 ns
subscribe 100 observers to publish_subject 238252.80 ns 22566.11 ns 17385.22 ns 1.30 17479.69 ns
100 on_next to 100 observers to publish_subject 29699.29 ns 14270.96 ns 20315.86 ns 0.70 20333.22 ns

Scenarios

name rxcpp rpp prev rpp ratio rpp no optimization
basic sample 1645.67 ns 7.42 ns 11.51 ns 0.64 20.84 ns
basic sample with immediate scheduler 1634.10 ns 2.21 ns 5.91 ns 0.37 6.53 ns
mix operators with disposables and without disposables 7274.91 ns 1304.95 ns 1192.77 ns 1.09 1491.58 ns
single disposable and looooooong indentity chain 21304.48 ns 1392.67 ns 1250.01 ns 1.11 4638.32 ns

Aggregating Operators

name rxcpp rpp prev rpp ratio rpp no optimization
immediate_just+reduce(10, std::plus)+subscribe 1371.14 ns 0.22 ns 0.31 ns 0.71 0.31 ns

Error Handling Operators

name rxcpp rpp prev rpp ratio rpp no optimization
create(on_next(1), on_error())+on_error_resume_next(immediate_just(2)))+subscribe 2048.23 ns 736.39 ns 1183.77 ns 0.62 1177.26 ns
create(on_error())+retry(1)+subscribe 860.54 ns 186.58 ns 138.49 ns 1.35 139.35 ns

ci-windows

General

name rxcpp rpp prev rpp ratio rpp no optimization
Subscribe empty callbacks to empty observable 556.07 ns 2.16 ns 2.16 ns 1.00 1.85 ns
Subscribe empty callbacks to empty observable via pipe operator 572.10 ns 2.16 ns 2.16 ns 1.00 1.85 ns

Sources

name rxcpp rpp prev rpp ratio rpp no optimization
from array of 1 - create + subscribe + immediate 1155.57 ns 4.93 ns 4.94 ns 1.00 5.55 ns
from array of 1 - create + subscribe + current_thread 1419.82 ns 15.75 ns 15.74 ns 1.00 15.45 ns
concat_as_source of just(1 immediate) create + subscribe 3696.46 ns 174.60 ns 174.62 ns 1.00 178.05 ns
defer from array of 1 - defer + create + subscribe + immediate 1180.65 ns 5.24 ns 5.24 ns 1.00 5.24 ns
interval - interval + take(3) + subscribe + immediate 3736.36 ns 139.81 ns 139.74 ns 1.00 142.29 ns
interval - interval + take(3) + subscribe + current_thread 3460.30 ns 60.15 ns 59.86 ns 1.00 62.80 ns
from array of 1 - create + as_blocking + subscribe + new_thread 123175.00 ns 118700.00 ns 120400.00 ns 0.99 119788.89 ns
from array of 1000 - create + as_blocking + subscribe + new_thread 132655.56 ns 135675.00 ns 136975.00 ns 0.99 137275.00 ns
concat_as_source of just(1 immediate) and just(1,2 immediate)create + subscribe 5329.67 ns 206.57 ns 201.39 ns 1.03 215.13 ns

Filtering Operators

name rxcpp rpp prev rpp ratio rpp no optimization
immediate_just+take(1)+subscribe 1818.86 ns 19.42 ns 19.42 ns 1.00 21.36 ns
immediate_just+filter(true)+subscribe 1610.58 ns 18.50 ns 18.51 ns 1.00 21.59 ns
immediate_just(1,2)+skip(1)+subscribe 2008.80 ns 17.89 ns 17.91 ns 1.00 21.60 ns
immediate_just(1,1,2)+distinct_until_changed()+subscribe 1328.95 ns 20.67 ns 20.68 ns 1.00 26.86 ns
immediate_just(1,2)+first()+subscribe 2372.16 ns 18.20 ns 18.21 ns 1.00 19.43 ns
immediate_just(1,2)+last()+subscribe 1464.98 ns 19.13 ns 19.15 ns 1.00 22.84 ns
immediate_just+take_last(1)+subscribe 2023.02 ns 64.85 ns 64.93 ns 1.00 70.17 ns
immediate_just(1,2,3)+element_at(1)+subscribe 1622.12 ns 20.97 ns 20.98 ns 1.00 21.63 ns

Schedulers

name rxcpp rpp prev rpp ratio rpp no optimization
immediate scheduler create worker + schedule 477.39 ns 4.32 ns 4.32 ns 1.00 4.32 ns
current_thread scheduler create worker + schedule 648.68 ns 11.11 ns 11.11 ns 1.00 11.11 ns
current_thread scheduler create worker + schedule + recursive schedule 1079.50 ns 103.96 ns 101.36 ns 1.03 103.12 ns

Transforming Operators

name rxcpp rpp prev rpp ratio rpp no optimization
immediate_just+map(v*2)+subscribe 1328.23 ns 18.80 ns 18.80 ns 1.00 21.63 ns
immediate_just+scan(10, std::plus)+subscribe 1422.12 ns 20.96 ns 20.96 ns 1.00 23.80 ns
immediate_just+flat_map(immediate_just(v*2))+subscribe 3837.33 ns 186.30 ns 185.11 ns 1.01 223.46 ns
immediate_just+buffer(2)+subscribe 2291.50 ns 64.26 ns 63.51 ns 1.01 72.33 ns
immediate_just+window(2)+subscribe + subscsribe inner 3974.07 ns 1216.92 ns 1192.15 ns 1.02 1226.57 ns

Conditional Operators

name rxcpp rpp prev rpp ratio rpp no optimization
immediate_just+take_while(false)+subscribe 1305.28 ns 17.57 ns 17.57 ns 1.00 19.13 ns
immediate_just+take_while(true)+subscribe 1329.92 ns 18.50 ns 18.50 ns 1.00 21.60 ns

Utility Operators

name rxcpp rpp prev rpp ratio rpp no optimization
immediate_just(1)+subscribe_on(immediate)+subscribe 3205.02 ns 11.10 ns 11.11 ns 1.00 11.11 ns

Combining Operators

name rxcpp rpp prev rpp ratio rpp no optimization
immediate_just(immediate_just(1), immediate_just(1)) + merge() + subscribe 5054.46 ns 197.43 ns 195.27 ns 1.01 222.13 ns
immediate_just(1) + merge_with(immediate_just(2)) + subscribe 5710.11 ns 186.78 ns 178.89 ns 1.04 204.81 ns
immediate_just(1) + with_latest_from(immediate_just(2)) + subscribe - 195.15 ns 194.65 ns 1.00 199.56 ns
immediate_just(immediate_just(1),immediate_just(1)) + switch_on_next() + subscribe 6119.16 ns 444.60 ns 443.65 ns 1.00 489.05 ns
immediate_just(1) + zip(immediate_just(2)) + subscribe 3865.37 ns 538.25 ns 519.56 ns 1.04 516.04 ns
immediate_just(immediate_just(1), immediate_just(1)) + concat() + subscribe 4853.97 ns 314.42 ns 314.38 ns 1.00 325.14 ns

Subjects

name rxcpp rpp prev rpp ratio rpp no optimization
publish_subject with 1 observer - on_next 36.72 ns 29.42 ns 29.27 ns 1.01 30.01 ns
subscribe 100 observers to publish_subject 264250.00 ns 25013.33 ns 25450.00 ns 0.98 24830.23 ns
100 on_next to 100 observers to publish_subject 51881.82 ns 35939.39 ns 35922.58 ns 1.00 32997.22 ns

Scenarios

name rxcpp rpp prev rpp ratio rpp no optimization
basic sample 1853.25 ns 96.57 ns 96.80 ns 1.00 112.11 ns
basic sample with immediate scheduler 1857.89 ns 66.73 ns 68.51 ns 0.97 82.35 ns
mix operators with disposables and without disposables 9381.75 ns 1787.22 ns 1797.99 ns 0.99 2439.19 ns
single disposable and looooooong indentity chain 25641.46 ns 1655.18 ns 1630.37 ns 1.02 6267.21 ns

Aggregating Operators

name rxcpp rpp prev rpp ratio rpp no optimization
immediate_just+reduce(10, std::plus)+subscribe 1458.16 ns 19.11 ns 19.11 ns 1.00 22.83 ns

Error Handling Operators

name rxcpp rpp prev rpp ratio rpp no optimization
create(on_next(1), on_error())+on_error_resume_next(immediate_just(2)))+subscribe 1896.36 ns 357.24 ns 353.06 ns 1.01 380.86 ns
create(on_error())+retry(1)+subscribe 1721.11 ns 138.15 ns 137.92 ns 1.00 139.85 ns

This branch has not been deployed

No deployments
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.

rppgrpc: client_read_reactor::init() touches the reactor after StartCall(), heap-use-after-free when the call ends at once

2 participants