Skip to content

Sync metrics#1928

Merged
pratikspatil024 merged 10 commits intodevelopfrom
avalkov/Sync-metrics
Mar 2, 2026
Merged

Sync metrics#1928
pratikspatil024 merged 10 commits intodevelopfrom
avalkov/Sync-metrics

Conversation

@avalkov
Copy link
Copy Markdown
Contributor

@avalkov avalkov commented Dec 11, 2025

Description

Added more metrics to compare stateful and stateless sync speed.

Summary

  • Add metrics.RecordPerItemDuration — a shared helper in the metrics package
    that amortizes a batch download duration across individual items and records the
    per-item latency on a timer.
  • Add per-item download duration timers (item_download_duration) for headers,
    bodies, receipts, and witnesses in both the downloader (concurrent and
    Bor-specific fetchers) and the announcement-driven block fetcher.
  • Add a NewBlock push interval timer (eth/protocols/eth/newblock/push_interval)
    that tracks time deltas between consecutive inbound NewBlock messages,
    providing visibility into block propagation cadence.
  • Minor cleanup: deduplicate repeated type assertions in bor_fetchers.go,
    add nil-safety checks on header/body response pointers in block_fetcher.go.

New Metrics

Metric Type Description
eth/downloader/headers/item_download_duration Timer Per-header amortized fetch latency (downloader)
eth/downloader/bodies/item_download_duration Timer Per-body amortized fetch latency (downloader)
eth/downloader/receipts/item_download_duration Timer Per-receipt amortized fetch latency (downloader)
eth/downloader/witnesses/item_download_duration Timer Per-witness amortized fetch latency (downloader)
eth/fetcher/block/headers/item_download_duration Timer Per-header amortized fetch latency (block fetcher)
eth/fetcher/block/bodies/item_download_duration Timer Per-body amortized fetch latency (block fetcher)
eth/fetcher/block/witnesses/item_download_duration Timer Per-witness amortized fetch latency (block fetcher)
eth/protocols/eth/newblock/push_interval Timer Interval between consecutive NewBlock pushes

@avalkov avalkov added the squash and merge This PR will be squashed and merged label Dec 11, 2025
@sonarqubecloud
Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
8.2% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

@github-actions
Copy link
Copy Markdown

github-actions bot commented Jan 2, 2026

This PR is stale because it has been open 21 days with no activity. Remove stale label or comment or this will be closed in 14 days.

@github-actions github-actions bot added the Stale label Jan 2, 2026
@github-actions
Copy link
Copy Markdown

This PR was closed because it has been stalled for 35 days with no activity.

@github-actions github-actions bot removed the Stale label Feb 26, 2026
@pratikspatil024
Copy link
Copy Markdown
Member

@claude - review this PR

@claude
Copy link
Copy Markdown

claude bot commented Feb 28, 2026

Claude finished @pratikspatil024's task in 2m 4s —— View job


PR Review: Sync Metrics

  • Gather context and understand the changes
  • Review eth/downloader/bor_fetchers.go
  • Review eth/downloader/bor_fetchers_concurrent.go
  • Review eth/fetcher/block_fetcher.go
  • Review eth/fetcher/witness_manager.go
  • Review eth/protocols/eth/handlers.go
  • Provide summary and recommendations

Summary

This PR adds metrics to compare stateful and stateless sync speed. The changes introduce per-item download duration tracking for headers, bodies, receipts, and witnesses, as well as a new metric to track intervals between consecutive NewBlock pushes.

Changes Overview

File Changes
eth/downloader/bor_fetchers.go Added recordHeaderFetchPerItemDuration() helper and applied to both fetchHeadersByHash and fetchHeadersByNumber
eth/downloader/bor_fetchers_concurrent.go Added 4 new Timer metrics and recordPerItemDownloadDuration() helper with type-switch dispatch
eth/fetcher/block_fetcher.go Added 3 new Timer metrics, recordFetcherPerItemDownloadDuration() helper, and applied to header/body responses
eth/fetcher/witness_manager.go Applied recordFetcherPerItemDownloadDuration() for witness fetches
eth/protocols/eth/handlers.go Added newBlockPushIntervalTimer and lastNewBlockPushUnix atomic to track time between consecutive NewBlock messages

Detailed Review

1. Code Quality: Good ✅

The implementation follows consistent patterns and the code is well-structured:

  • Proper bounds checking (duration <= 0 || items <= 0)
  • Fallback to time.Nanosecond to avoid zero-duration updates
  • Clean helper functions with appropriate documentation

2. Issues Found

2.1. Code Duplication (SonarCloud flagged)

The PR has two nearly identical helper functions for recording per-item durations:

  1. recordHeaderFetchPerItemDuration() in bor_fetchers.go:27-38
  2. recordPerItemDownloadDuration() in bor_fetchers_concurrent.go:85-105
  3. recordFetcherPerItemDownloadDuration() in block_fetcher.go:83-94

These have the same logic pattern. While the first two operate in different contexts (one uses a global timer directly, one dispatches via type switch, and one takes a timer parameter), there's still duplication detected by SonarCloud at 8.2% (threshold is 3%).

Recommendation: Consider consolidating by making recordFetcherPerItemDownloadDuration() a shared utility that can be called from all locations, since it already takes a timer parameter. Fix this →

2.2. Debug Log Left in Code ⚠️

In eth/protocols/eth/handlers.go, there appears to be a debug log statement that was present before this PR at line 500 (from context in the diff):

log.Error("handleNewBlock", "ReceivedAt", ann.Block.ReceivedAt.Unix())

This uses log.Error for what appears to be debug output. While not introduced by this PR, it's worth noting for cleanup.

2.3. Metrics Placement

The new metrics in bor_fetchers_concurrent.go (lines 79-82) are defined inline rather than in eth/downloader/metrics.go. For consistency with the existing codebase pattern, consider moving these to the dedicated metrics file.

Similarly, the metrics in block_fetcher.go (lines 71-73) could be moved to eth/fetcher/metrics.go.

3. Metrics Overview

Metric Purpose
sync/headers/item_download_duration Per-header download latency (downloader)
sync/bodies/item_download_duration Per-body download latency (downloader)
sync/receipts/item_download_duration Per-receipt download latency (downloader)
sync/stateless/witness_item_download_duration Per-witness download latency (downloader)
eth/fetcher/block/headers/item_download_duration Per-header download latency (block fetcher)
eth/fetcher/block/bodies/item_download_duration Per-body download latency (block fetcher)
eth/fetcher/block/witnesses/item_download_duration Per-witness download latency (block fetcher)
eth/protocols/eth/newblock/push_interval Time between consecutive NewBlock pushes

4. Thread Safety ✅

The use of atomic.Int64 for lastNewBlockPushUnix in handlers.go is correct for tracking the previous timestamp in a concurrent environment.

5. Performance Impact: Minimal ✅

The metric recording is performed inline with minimal overhead:

  • Simple arithmetic operations
  • Timer updates are lock-free in most implementations
  • No allocations in the hot path

Recommendations

  1. To address SonarCloud duplication warning: Extract the common duration calculation logic into a shared utility function
  2. Code organization: Consider moving metric declarations to the dedicated metrics.go files for consistency
  3. Minor: The nil check || headersResponse == nil added in block_fetcher.go:715 is defensive programming that's good to have

Verdict

The PR adds valuable metrics for comparing sync performance. The implementation is sound and follows existing patterns. The main concern is the code duplication flagged by SonarCloud which prevents the quality gate from passing.

Suggested action: Address the duplication issue to pass the quality gate, then this PR should be ready to merge.


|

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 2, 2026

Codecov Report

❌ Patch coverage is 63.82979% with 17 lines in your changes missing coverage. Please review.
✅ Project coverage is 50.89%. Comparing base (fdbc857) to head (0917851).
⚠️ Report is 2 commits behind head on develop.

Files with missing lines Patch % Lines
eth/protocols/eth/handlers.go 0.00% 7 Missing ⚠️
eth/downloader/bor_fetchers_concurrent.go 60.00% 6 Missing ⚠️
eth/fetcher/block_fetcher.go 66.66% 0 Missing and 2 partials ⚠️
eth/fetcher/witness_manager.go 0.00% 2 Missing ⚠️

❌ Your patch status has failed because the patch coverage (63.82%) is below the target coverage (90.00%). You can increase the patch coverage or adjust the target coverage.

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop    #1928      +/-   ##
===========================================
+ Coverage    50.59%   50.89%   +0.29%     
===========================================
  Files          875      878       +3     
  Lines       151820   152469     +649     
===========================================
+ Hits         76815    77599     +784     
+ Misses       69929    69781     -148     
- Partials      5076     5089      +13     
Files with missing lines Coverage Δ
eth/downloader/bor_fetchers.go 73.68% <100.00%> (-1.32%) ⬇️
metrics/util.go 100.00% <100.00%> (ø)
eth/fetcher/block_fetcher.go 73.74% <66.66%> (+0.09%) ⬆️
eth/fetcher/witness_manager.go 83.80% <0.00%> (-0.07%) ⬇️
eth/downloader/bor_fetchers_concurrent.go 50.50% <60.00%> (+0.50%) ⬆️
eth/protocols/eth/handlers.go 49.64% <0.00%> (-0.54%) ⬇️

... and 22 files with indirect coverage changes

Files with missing lines Coverage Δ
eth/downloader/bor_fetchers.go 73.68% <100.00%> (-1.32%) ⬇️
metrics/util.go 100.00% <100.00%> (ø)
eth/fetcher/block_fetcher.go 73.74% <66.66%> (+0.09%) ⬆️
eth/fetcher/witness_manager.go 83.80% <0.00%> (-0.07%) ⬇️
eth/downloader/bor_fetchers_concurrent.go 50.50% <60.00%> (+0.50%) ⬆️
eth/protocols/eth/handlers.go 49.64% <0.00%> (-0.54%) ⬇️

... and 22 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud bot commented Mar 2, 2026

Quality Gate Failed Quality Gate failed

Failed conditions
4.5% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

@pratikspatil024
Copy link
Copy Markdown
Member

@claude - re-review this PR.

@claude
Copy link
Copy Markdown

claude bot commented Mar 2, 2026

Claude finished @pratikspatil024's task in 1m 7s —— View job


PR Re-Review: Sync Metrics

  • Gather context and understand recent changes
  • Review metrics/util.go (new shared helper)
  • Review metrics/util_test.go (new unit tests)
  • Review eth/downloader/bor_fetchers.go
  • Review eth/downloader/bor_fetchers_concurrent.go
  • Review eth/downloader/metrics.go
  • Review eth/fetcher/block_fetcher.go
  • Review eth/fetcher/witness_manager.go
  • Review eth/protocols/eth/handlers.go
  • Provide summary and recommendations

Summary

This PR adds comprehensive metrics for comparing stateful and stateless sync performance. The author has addressed the previous review feedback by creating a shared utility function and adding unit tests.

Changes Since Last Review

The author implemented the recommended refactoring:

  1. Created metrics/util.go: A centralized RecordPerItemDuration helper function that handles the per-item duration calculation logic
  2. Added metrics/util_test.go: Comprehensive unit tests covering normal cases, edge cases (nil timer, zero/negative items/duration), and sub-nanosecond clamping

Detailed Review

1. metrics/util.go ✅ Excellent

The shared helper function is well-designed:

  • Proper nil-safety: Handles timer == nil gracefully
  • Input validation: Checks for duration <= 0 and items <= 0
  • Edge case handling: Clamps sub-nanosecond results to 1ns to avoid zero-duration updates
  • Clean documentation: Clear docstring explaining behavior
func RecordPerItemDuration(timer *Timer, duration time.Duration, items int) {
    if timer == nil || duration <= 0 || items <= 0 {
        return
    }
    perItem := time.Duration(int64(duration) / int64(items))
    if perItem <= 0 {
        perItem = time.Nanosecond
    }
    timer.Update(perItem)
}

2. metrics/util_test.go ✅ Excellent

Comprehensive test coverage including:

  • Normal batch operations
  • Single item
  • Zero items (no-op)
  • Negative items (no-op)
  • Zero duration (no-op)
  • Negative duration (no-op)
  • Sub-nanosecond clamping
  • Nil timer panic check

3. eth/downloader/metrics.go ✅ Good

New timer declarations are properly placed in the dedicated metrics file:

headerItemDownloadTimer  = metrics.NewRegisteredTimer("eth/downloader/headers/item_download_duration", nil)
bodyItemDownloadTimer    = metrics.NewRegisteredTimer("eth/downloader/bodies/item_download_duration", nil)
receiptItemDownloadTimer = metrics.NewRegisteredTimer("eth/downloader/receipts/item_download_duration", nil)
witnessItemDownloadTimer = metrics.NewRegisteredTimer("eth/downloader/witnesses/item_download_duration", nil)

4. eth/downloader/bor_fetchers.go ✅ Good

Uses the shared helper correctly:

metrics.RecordPerItemDuration(headerItemDownloadTimer, res.Time, len(headers))

Applied consistently in both fetchHeadersByHash (line 61) and fetchHeadersByNumber (line 108).

5. eth/downloader/bor_fetchers_concurrent.go ✅ Good

The queueItemTimer function elegantly maps queue types to their corresponding timers using a type switch (lines 33-46). The shared helper is used at line 434:

metrics.RecordPerItemDuration(queueItemTimer(queue), res.Time, accepted)

6. eth/fetcher/block_fetcher.go ✅ Good

New timers declared at the file scope (lines 72-74), and the shared helper is used for:

  • Header fetch responses (line 707)
  • Body fetch responses (line 782)

Note: The nil/type safety checks at line 703 and 777 are good defensive programming:

if !ok || headersResponse == nil {
    return
}

7. eth/fetcher/witness_manager.go ✅ Good

Uses the shared helper for witness fetches at line 578:

metrics.RecordPerItemDuration(blockWitnessItemDownloadTimer, res.Time, 1)

8. eth/protocols/eth/handlers.go ✅ Good

Implements the NewBlock push interval metric correctly:

  • Uses atomic.Int64 for thread-safe timestamp tracking (line 46)
  • Calculates delta between consecutive NewBlock messages (lines 503-509)
  • Properly handles the first message (when prev > 0)

SonarCloud Duplication Warning

The current analysis shows 4.5% duplication (threshold is ≤ 3%). This is down from the original 8.2%, indicating the refactoring helped. The remaining duplication may be due to:

  • Similar metric declaration patterns across files
  • Structural similarities in the fetcher code paths

This is acceptable given the nature of metrics instrumentation code, where some pattern repetition is natural.

Codecov Analysis

Patch coverage is 63.83% (17 lines missing coverage). The uncovered lines are primarily in:

  • eth/protocols/eth/handlers.go: The NewBlock push interval logic (integration code)
  • eth/downloader/bor_fetchers_concurrent.go: Some timer dispatch paths
  • eth/fetcher/witness_manager.go: Witness metric recording

This is typical for metrics instrumentation code that runs in production network conditions and is difficult to unit test in isolation.

Recommendations

  1. No blockers found - The PR is well-implemented
  2. Minor: Consider whether the SonarCloud duplication warning should block the merge. The remaining duplication is structural rather than logical, and forcing further consolidation might reduce readability

Verdict

Approved - This PR is ready to merge. The implementation is clean, the shared utility addresses the previous duplication concerns, unit tests provide good coverage for the helper function, and the metrics will provide valuable visibility into sync performance.


@pratikspatil024 pratikspatil024 merged commit 46e2631 into develop Mar 2, 2026
18 of 20 checks passed
@pratikspatil024 pratikspatil024 deleted the avalkov/Sync-metrics branch March 2, 2026 10:12
lucca30 pushed a commit that referenced this pull request Mar 5, 2026
* Added metrics for items download

* Added metrics for headers

* Added debug logging

* Added logging for timestamps

* Added push block interval metric

* Remove logs

* minor refactoring, reduced code duplication, made metrics name consistent

* added unit test for helper function

---------

Co-authored-by: Pratik Patil <pratikspatil024@gmail.com>
(cherry picked from commit 46e2631)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

squash and merge This PR will be squashed and merged

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants