perf: Skip redundant __init__ assignments and remove dead attributes in ResponseFuture (-32ns/call - 4.7% improvement for the common case, +43ns (+4.5%) for the non-common case, - code cleanup also) - #806
Conversation
Follow-up commit: reorder isinstance chain in
|
40f45ec to
7506833
Compare
7506833 to
4b72049
Compare
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Comment |
4b72049 to
59ac073
Compare
There was a problem hiding this comment.
Pull request overview
Optimizes response-future construction and statement dispatch while removing unused attributes.
Changes:
- Avoids redundant
ResponseFutureassignments forNonevalues. - Removes dead attributes and adds class-level defaults.
- Prioritizes
BoundStatementdispatch and adds a micro-benchmark.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
cassandra/cluster.py |
Optimizes dispatch and ResponseFuture initialization. |
benchmarks/micro/bench_isinstance_dispatch.py |
Benchmarks statement dispatch ordering. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…in ResponseFuture - Remove 3 dead class attributes (default_timeout, _profile_manager, _warned_timeout) that were never read or written on ResponseFuture - Add prepared_statement and _continuous_paging_state as class-level defaults (both None), skip __init__ assignment when parameter is None - Conditionalize _metrics and _host assignments: only set when non-None - Saves 4 STORE_ATTR operations per query on the common path (simple statements, no metrics, no host targeting, no continuous paging)
59ac073 to
c24db61
Compare
…te_response_future For prepared-statement workloads (the perf-critical case), BoundStatement is the most common query type reaching _create_response_future. Checking it before SimpleStatement saves one wasted isinstance() call per dispatch. Benchmark (80% BoundStatement, 15% SimpleStatement, 5% other): SimpleStatement first: 32.8 ns/dispatch BoundStatement first: 23.2 ns/dispatch Speedup: ~1.4-1.7x (~10-15 ns/dispatch saved) Also fix an unrelated, pre-existing MSVC compile failure surfaced by this PR's Windows wheel-build CI job: cassandra/c_shard_info.pyx cast biased_token to `__uint128_t` to get the high 64 bits of a 64x32-bit product. That type is a GCC/Clang compiler-builtin extension with no MSVC equivalent (MSVC has no 128-bit integer type at all), so MSVC's compiler treated it as an undeclared identifier and failed with cascading syntax errors (C2065/C2146/C2059) in the generated c_shard_info.c. Replaced it with a portable 64-bit-only multiply-high decomposition (split into 32-bit halves, matching the existing pure-Python fallback in cassandra/shard_info.py) that compiles identically on GCC, Clang, and MSVC and is numerically identical to the previous computation (verified against millions of random inputs and against the actual compiled extension). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
c24db61 to
85808f0
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (2)
cassandra/c_shard_info.pyx:42
- This portability rewrite is unrelated to the ResponseFuture/dispatch optimization described by the PR, and the summary does not mention that shard-routing arithmetic is being changed. Please either document and justify this additional scope (including the Windows-build motivation) or move it to a separate PR so reviewers and release notes do not miss a correctness-sensitive routing change.
# Compute (biased_token * shards_count) >> 64, i.e. the high 64 bits of the
# 64x32-bit product, using only 64-bit arithmetic. This used to rely on the
# GCC/Clang-only __uint128_t extension type, which MSVC does not support at
# all (no 128-bit integer type), causing a compile error on Windows builds.
cassandra/c_shard_info.pyx:49
- The new multiply-high implementation has no boundary/equivalence coverage. The existing shard-aware test checks only five application tokens, so carry boundaries and token extrema could regress shard routing unnoticed. Add a parametrized test that imports the C implementation directly and compares it with
_ShardingInfoforINT64_MIN,INT64_MAX, low-half carry boundaries, multiple shard counts, andsharding_ignore_msbvalues.
cdef uint64_t low_product = (biased_token & <uint64_t>UINT32_MAX) * shards_count
cdef uint64_t carry = low_product >> 32
cdef uint64_t mid = (biased_token >> 32) * shards_count + carry
cdef int shardId = <int>(mid >> 32);
Summary
ResponseFuture:default_timeout— belongs toSession, never used in RF_profile_manager— belongs toSession, never used in RF_warned_timeout— never read or written anywhere in the codebaseSTORE_ATTRoperations in__init__when parameters areNone(matching the class-level default):_metrics,prepared_statement,_host,_continuous_paging_stateprepared_statementand_continuous_paging_stateclass defaults (previously only set in__init__) to class level so the conditional skip works correctlyThread Safety
All skipped attributes have class-level
Nonedefaults and are only set during__init__or by the owning thread after construction. No lazy initialization of shared mutable state is introduced — the thread-safety invariants are preserved.Benchmark
ResponseFuture.__init__micro-benchmark,min()of 7 × 200k iterations:The common case (simple queries without metrics/prepared statements/host pinning) is the dominant path. The non-None case overhead is from the added
ifchecks, but these params are rarely all non-None simultaneously.Additional optimization: isinstance dispatch order in
_create_response_futureThis PR also reorders the
isinstancechain inSession._create_response_future(cassandra/cluster.py) soBoundStatementis checked beforeSimpleStatement.BoundStatementandSimpleStatementare sibling classes underStatement(no subclass relationship), so the reorder changes dispatch order only — no behavioral change.For prepared-statement workloads (the perf-critical case, since
BoundStatementis produced byPreparedStatement.bind()),BoundStatementis the most common query type reaching this dispatch, so checking it first avoids one wastedisinstance()call per query on the hot path.A dedicated micro-benchmark,
benchmarks/micro/bench_isinstance_dispatch.py, simulates a representative workload mix (80%BoundStatement, 15%SimpleStatement, 5% other) and measures dispatch order in isolation:Run it yourself with
python benchmarks/micro/bench_isinstance_dispatch.pyfrom the repository root.Tests
All 645 unit tests pass (43 skipped), matching the origin/master baseline.