Skip to content

fix(test): make the disk-txmap throughput floor an order-of-magnitude gate - #1707

Open
icellan wants to merge 1 commit into
release/v0.15from
fix/disktxmap-throughput-floor-v0.15
Open

fix(test): make the disk-txmap throughput floor an order-of-magnitude gate#1707
icellan wants to merge 1 commit into
release/v0.15from
fix/disktxmap-throughput-floor-v0.15

Conversation

@icellan

@icellan icellan commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Backport of the assertion change in 25c0f2c43 (#1051 / #1058), which release/v0.15 never received.

TestDiskTxMap_ExistenceLayerThroughput gates on >1M ops/sec under -race. The CI runners land below that — 970482 then 910122 ops/sec on two consecutive runs of the same commit — so the test job fails on every PR targeting this branch, #1705 included.

The 1M figure becomes an informational log; the hard assertion drops to a 100k floor. That still fails on an order-of-magnitude regression (an accidental lock serialising the existence layer, say) without gating on runner speed.

services/blockassembly/subtreeprocessor/disk_tx_map_benchmark_test.go is now byte-identical to main.

Local: go test -race -run TestDiskTxMap_ExistenceLayerThroughput passes, 6249184 ops/sec.

🤖 Generated with Claude Code

… gate

Backport of the assertion change in 25c0f2c (#1051 / #1058), which
release/v0.15 never received.

TestDiskTxMap_ExistenceLayerThroughput gates on >1M ops/sec under -race.
The CI runners land below that: 970482 and 910122 ops/sec on two
consecutive runs of the same commit, so the job fails on every PR
targeting this branch.

The 1M figure becomes an informational log and the hard assertion drops
to a 100k floor, which still fails on an order-of-magnitude regression
such as a lock serialising the existence layer, without gating on runner
speed. The file is now byte-identical to main.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings September 9, 2026 08:04
@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

🤖 Claude Code Review

Status: Complete

Current Review:

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

The change is isolated to a test threshold adjustment; the only remaining feedback is a minor in-comment numeric inconsistency.

Pull request overview

This PR backports a test-only change on release/v0.15 to deflake TestDiskTxMap_ExistenceLayerThroughput by converting the previous hard >1M ops/sec assertion (under -race) into an informational target plus a lower hard floor that still detects order-of-magnitude regressions.

Changes:

  • Replace the hard >1M ops/sec gate with an informational 1M target log and a hard 100k ops/sec floor.
  • Improve the inline rationale in the test to document CI runner variability under -race.

Changed:

  • services/blockassembly/subtreeprocessor/disk_tx_map_benchmark_test.go: relax throughput assertion to avoid CI flakes while keeping a regression-detection floor.

Tested:

  • Not run here (code review only).

Risks / Notes:

  • One comment’s numeric rationale (“~35x below…”) appears inconsistent with the values cited in the same block and should be adjusted for accuracy.
File summaries
File Description
services/blockassembly/subtreeprocessor/disk_tx_map_benchmark_test.go Updates throughput gating logic to prevent -race CI flakiness while preserving detection of major performance regressions.
Review details
  • Files reviewed: 1/1 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +296 to +298
// package. A generous 100k floor (10x below target, ~35x below a measured slow CI
// run) still fails the run on an order-of-magnitude regression — e.g. an accidental
// lock serialising the existence layer — without reintroducing runner-speed flakes.
@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Benchmark Comparison Report

Baseline: main (unknown)

Current: PR-1707 (454da65)

Summary

  • Regressions: 0
  • Improvements: 0
  • Unchanged: 130
  • Significance level: p < 0.05
All benchmark results (sec/op)
Benchmark Baseline Current Change p-value
_NewBlockFromBytes-4 1.726µ 1.773µ ~ 0.100
SplitSyncedParentMap_SetIfNotExists/256_buckets-4 64.07n 61.94n ~ 0.100
SplitSyncedParentMap_SetIfNotExists/16_buckets-4 63.98n 61.92n ~ 0.100
SplitSyncedParentMap_SetIfNotExists/1_bucket-4 64.28n 61.74n ~ 0.100
SplitSyncedParentMap_ConcurrentSetIfNotExists/256_buckets... 29.96n 30.70n ~ 0.400
SplitSyncedParentMap_ConcurrentSetIfNotExists/16_buckets_... 52.60n 53.30n ~ 0.700
SplitSyncedParentMap_ConcurrentSetIfNotExists/1_bucket_pa... 105.8n 105.9n ~ 0.500
MiningCandidate_Stringify_Short-4 224.4n 262.0n ~ 0.100
MiningCandidate_Stringify_Long-4 1.533µ 1.947µ ~ 0.100
MiningSolution_Stringify-4 765.3n 1021.0n ~ 0.100
BlockInfo_MarshalJSON-4 1.591µ 1.822µ ~ 0.100
NewFromBytes-4 129.2n 129.6n ~ 0.800
AddTxBatchColumnar_Validation-4 2.077µ 2.504µ ~ 0.100
OffsetValidationLoop-4 635.7n 638.3n ~ 0.700
Mine_EasyDifficulty-4 62.44µ 60.45µ ~ 1.000
Mine_WithAddress-4 6.968µ 6.909µ ~ 0.200
BlockAssembler_AddTx-4 0.02974n 0.02224n ~ 0.100
AddNode-4 10.96 11.00 ~ 1.000
AddNodeWithMap-4 11.37 11.41 ~ 1.000
DirectSubtreeAdd/4_per_subtree-4 45.86n 48.90n ~ 0.100
DirectSubtreeAdd/64_per_subtree-4 23.10n 23.15n ~ 0.700
DirectSubtreeAdd/256_per_subtree-4 21.87n 21.89n ~ 0.800
DirectSubtreeAdd/1024_per_subtree-4 20.90n 20.94n ~ 1.000
DirectSubtreeAdd/2048_per_subtree-4 20.51n 20.58n ~ 0.100
SubtreeProcessorAdd/4_per_subtree-4 193.6n 358.5n ~ 0.100
SubtreeProcessorAdd/64_per_subtree-4 194.7n 350.1n ~ 0.100
SubtreeProcessorAdd/256_per_subtree-4 188.7n 390.0n ~ 0.100
SubtreeProcessorAdd/1024_per_subtree-4 176.4n 399.1n ~ 0.100
SubtreeProcessorAdd/2048_per_subtree-4 178.5n 364.6n ~ 0.100
SubtreeProcessorRotate/4_per_subtree-4 179.6n 352.3n ~ 0.100
SubtreeProcessorRotate/64_per_subtree-4 179.1n 416.1n ~ 0.100
SubtreeProcessorRotate/256_per_subtree-4 180.5n 367.7n ~ 0.100
SubtreeProcessorRotate/1024_per_subtree-4 180.4n 346.3n ~ 0.100
SubtreeNodeAddOnly/4_per_subtree-4 43.83n 46.65n ~ 0.100
SubtreeNodeAddOnly/64_per_subtree-4 28.36n 28.41n ~ 0.200
SubtreeNodeAddOnly/256_per_subtree-4 27.62n 27.80n ~ 0.700
SubtreeNodeAddOnly/1024_per_subtree-4 27.03n 26.93n ~ 0.100
SubtreeCreationOnly/4_per_subtree-4 88.41n 113.00n ~ 0.100
SubtreeCreationOnly/64_per_subtree-4 314.4n 371.0n ~ 0.100
SubtreeCreationOnly/256_per_subtree-4 1.028µ 1.093µ ~ 0.100
SubtreeCreationOnly/1024_per_subtree-4 3.244µ 4.000µ ~ 0.100
SubtreeCreationOnly/2048_per_subtree-4 5.681µ 7.025µ ~ 0.100
SubtreeProcessorOverheadBreakdown/64_per_subtree-4 180.9n 250.8n ~ 0.100
SubtreeProcessorOverheadBreakdown/1024_per_subtree-4 178.5n 257.7n ~ 0.100
ParallelGetAndSetIfNotExists/1k_nodes-4 7.574m 10.687m ~ 0.100
ParallelGetAndSetIfNotExists/10k_nodes-4 10.97m 13.80m ~ 0.100
ParallelGetAndSetIfNotExists/50k_nodes-4 13.12m 16.62m ~ 0.100
ParallelGetAndSetIfNotExists/100k_nodes-4 15.66m 19.68m ~ 0.100
SequentialGetAndSetIfNotExists/1k_nodes-4 7.455m 11.069m ~ 0.100
SequentialGetAndSetIfNotExists/10k_nodes-4 12.31m 15.08m ~ 0.100
SequentialGetAndSetIfNotExists/50k_nodes-4 19.17m 20.96m ~ 0.100
SequentialGetAndSetIfNotExists/100k_nodes-4 25.25m 24.91m ~ 0.100
ProcessOwnBlockSubtreeNodesParallel/1k_nodes-4 9.332m 8.886m ~ 1.000
ProcessOwnBlockSubtreeNodesParallel/10k_nodes-4 13.28m 17.47m ~ 0.100
ProcessOwnBlockSubtreeNodesParallel/100k_nodes-4 15.48m 17.41m ~ 0.700
ProcessOwnBlockSubtreeNodesSequential/1k_nodes-4 14.37m 10.84m ~ 0.700
ProcessOwnBlockSubtreeNodesSequential/10k_nodes-4 25.31m 14.99m ~ 0.100
ProcessOwnBlockSubtreeNodesSequential/100k_nodes-4 48.33m 48.05m ~ 0.700
DiskTxMap_SetIfNotExists-4 3.571µ 3.483µ ~ 0.700
DiskTxMap_SetIfNotExists_Parallel-4 3.157µ 3.515µ ~ 0.200
DiskTxMap_ExistenceOnly-4 267.7n 248.7n ~ 1.000
Queue-4 182.8n 175.7n ~ 0.100
AtomicPointer-4 7.339n 7.343n ~ 1.000
TxMapSetIfNotExists-4 45.09n 45.49n ~ 0.700
TxMapSetIfNotExistsDuplicate-4 45.51n 45.62n ~ 0.700
ChannelSendReceive-4 559.2n 562.1n ~ 0.200
CalcBlockWork-4 505.3n 517.9n ~ 0.100
CalculateWork-4 681.1n 697.0n ~ 0.400
CheckOldBlockIDs/on-chain-prefetch/1000-4 58.11µ 61.32µ ~ 0.100
CheckOldBlockIDs/on-chain-prefetch/10000-4 520.3µ 446.2µ ~ 0.700
BuildBlockLocatorString_Helpers/Size_10-4 1.392µ 1.428µ ~ 0.100
BuildBlockLocatorString_Helpers/Size_100-4 13.20µ 13.71µ ~ 0.100
BuildBlockLocatorString_Helpers/Size_1000-4 130.2µ 135.5µ ~ 0.100
CatchupWithHeaderCache-4 107.3m 105.4m ~ 0.100
_prepareTxsPerLevel-4 414.0m 414.3m ~ 1.000
_prepareTxsPerLevelOrdered-4 3.668m 4.477m ~ 0.100
_prepareTxsPerLevel_Comparison/Original-4 412.0m 414.3m ~ 0.400
_prepareTxsPerLevel_Comparison/Optimized-4 3.691m 4.032m ~ 0.100
SubtreeSizes/10k_tx_4_per_subtree-4 1.500m 1.433m ~ 1.000
SubtreeSizes/10k_tx_16_per_subtree-4 333.4µ 336.6µ ~ 1.000
SubtreeSizes/10k_tx_64_per_subtree-4 78.98µ 78.92µ ~ 0.400
SubtreeSizes/10k_tx_256_per_subtree-4 19.77µ 19.54µ ~ 0.400
SubtreeSizes/10k_tx_512_per_subtree-4 9.711µ 9.710µ ~ 0.700
SubtreeSizes/10k_tx_1024_per_subtree-4 4.836µ 4.842µ ~ 1.000
SubtreeSizes/10k_tx_2k_per_subtree-4 2.360µ 2.397µ ~ 0.100
BlockSizeScaling/10k_tx_64_per_subtree-4 75.18µ 76.62µ ~ 0.100
BlockSizeScaling/10k_tx_256_per_subtree-4 19.06µ 19.29µ ~ 0.200
BlockSizeScaling/10k_tx_1024_per_subtree-4 4.687µ 4.766µ ~ 0.200
BlockSizeScaling/50k_tx_64_per_subtree-4 394.8µ 395.6µ ~ 0.700
BlockSizeScaling/50k_tx_256_per_subtree-4 95.98µ 97.22µ ~ 0.700
BlockSizeScaling/50k_tx_1024_per_subtree-4 23.11µ 23.84µ ~ 0.100
SubtreeAllocations/small_subtrees_exists_check-4 161.7µ 158.9µ ~ 0.400
SubtreeAllocations/small_subtrees_data_fetch-4 165.5µ 167.2µ ~ 1.000
SubtreeAllocations/small_subtrees_full_validation-4 325.6µ 333.3µ ~ 0.100
SubtreeAllocations/medium_subtrees_exists_check-4 9.340µ 9.281µ ~ 0.700
SubtreeAllocations/medium_subtrees_data_fetch-4 9.648µ 9.883µ ~ 0.200
SubtreeAllocations/medium_subtrees_full_validation-4 19.06µ 19.32µ ~ 0.100
SubtreeAllocations/large_subtrees_exists_check-4 2.247µ 2.230µ ~ 0.700
SubtreeAllocations/large_subtrees_data_fetch-4 2.309µ 2.486µ ~ 0.100
SubtreeAllocations/large_subtrees_full_validation-4 4.752µ 5.080µ ~ 0.100
_BufferPoolAllocation/16KB-4 5.211µ 3.872µ ~ 0.700
_BufferPoolAllocation/32KB-4 8.599µ 9.014µ ~ 0.700
_BufferPoolAllocation/64KB-4 16.78µ 21.96µ ~ 0.100
_BufferPoolAllocation/128KB-4 32.52µ 36.80µ ~ 0.100
_BufferPoolAllocation/512KB-4 93.26µ 128.01µ ~ 0.100
_BufferPoolConcurrent/32KB-4 18.59µ 19.16µ ~ 0.100
_BufferPoolConcurrent/64KB-4 30.63µ 30.31µ ~ 0.700
_BufferPoolConcurrent/512KB-4 146.7µ 151.4µ ~ 0.100
_SubtreeDeserializationWithBufferSizes/16KB-4 610.6µ 630.3µ ~ 0.100
_SubtreeDeserializationWithBufferSizes/32KB-4 587.0µ 622.0µ ~ 0.100
_SubtreeDeserializationWithBufferSizes/64KB-4 587.7µ 616.8µ ~ 0.400
_SubtreeDeserializationWithBufferSizes/128KB-4 586.4µ 613.2µ ~ 0.100
_SubtreeDeserializationWithBufferSizes/512KB-4 595.0µ 605.0µ ~ 0.700
_SubtreeDataDeserializationWithBufferSizes/16KB-4 36.62m 36.98m ~ 0.400
_SubtreeDataDeserializationWithBufferSizes/32KB-4 36.65m 36.93m ~ 0.400
_SubtreeDataDeserializationWithBufferSizes/64KB-4 36.26m 36.77m ~ 0.700
_SubtreeDataDeserializationWithBufferSizes/128KB-4 36.20m 36.40m ~ 0.100
_SubtreeDataDeserializationWithBufferSizes/512KB-4 36.08m 36.67m ~ 0.100
_PooledVsNonPooled/Pooled-4 832.0n 833.8n ~ 0.700
_PooledVsNonPooled/NonPooled-4 7.989µ 8.329µ ~ 0.100
_MemoryFootprint/Current_512KB_32concurrent-4 7.281µ 7.232µ ~ 0.700
_MemoryFootprint/Proposed_32KB_32concurrent-4 9.484µ 9.904µ ~ 0.100
_MemoryFootprint/Alternative_64KB_32concurrent-4 9.349µ 9.494µ ~ 0.400
StoreBlock_Sequential/BelowCSVHeight-4 332.2µ 322.4µ ~ 0.700
StoreBlock_Sequential/AboveCSVHeight-4 337.9µ 315.3µ ~ 0.700
GetUtxoHashes-4 261.4n 267.6n ~ 0.100
GetUtxoHashes_ManyOutputs-4 45.86µ 46.31µ ~ 0.700
_NewMetaDataFromBytes-4 276.2n 244.3n ~ 0.100
_Bytes-4 390.4n 406.3n ~ 0.100
_MetaBytes-4 136.3n 139.5n ~ 0.100

Threshold: >10% with p < 0.05 | Generated: 2026-09-09 08:21 UTC

@oskarszoon oskarszoon left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The trade is right and it's disclosed in the comment rather than buried, so this should land. #1051 checks out — ~953k on a 16-core runner against a 1M floor, and the 32-core runner it currently passes on is meant to be temporary, so the flake is imminent rather than hypothetical.

Measured the remaining sensitivity, since an order-of-magnitude floor can easily end up gating nothing. M3 Max, -count=1:

  • without -race: 23.1M–29.6M ops/sec — 231x–296x above the 100k floor
  • with -race: 3.49M–6.03M ops/sec — 35x–60x above it

So it catches a collapse (an accidental lock serialising the existence layer) and nothing smaller. That matches what the title and comment claim. No flakes in 8 runs, none close to the floor. Timing mechanics are unaffected by the diff and correct — setup outside the timed region, fixed op count over wall-clock.

One nit, in the justification rather than the code: disk_tx_map_benchmark_test.go:296-298 says the floor is "10x below target, ~35x below a measured slow CI run". The 10x is right, but 953k/100k is 9.5x, not 35x — 35x is the race-mode local figure (3.49M/100k). Two different measurement conditions read as one. Worth fixing so the reasoning behind the constant stays auditable.

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