fix(sdk/metric): keep concurrent float sums consistent - #8848
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #8848 +/- ##
=====================================
Coverage 88.5% 88.5%
=====================================
Files 331 331
Lines 21012 21037 +25
=====================================
+ Hits 18602 18626 +24
- Misses 2410 2411 +1
🚀 New features to boost your workflow:
|
|
Addressed in 7d19e3b. Added an atomic fractional-write generation that increments after every successful fractional CAS and is validated alongside nFloatBits and writerState during load. This rejects ABA snapshots where a negative fractional write restores the prior bit pattern. Added TestAtomicCounterLoadConcurrentSnapshotCancellation for the .5, 1, 1, -.5 sequence, and updated the subnormal fixture to model its three individual writes. Local verification: go test ./... in sdk/metric, targeted aggregate tests, targeted aggregate -race, go vet, and git diff --check all pass. The new head has restarted hosted CI; please take another look when convenient. |
|
Follow-up in 74fbb54 bounds the cancellation stress loop to 1,000,000 sequences. The previous 10,000,000 iteration count exceeded the repository's 60s per-test timeout under hosted -race; the hosted failure was a timeout, not a race report. The same Makefile target now passes locally: make test/./sdk/metric ARGS=-race TIMEOUT=60, and the full sdk/metric module race suite passes. The ABA coverage remains unchanged. |
MrAlias
left a comment
There was a problem hiding this comment.
The generation change resolves the ABA issue from my earlier review. I missed a separate progress constraint in the original approach: cumulative collection still needs to complete while measurements continue.
|
Follow-up for the collection-progress feedback:
Local evidence: |
…er-snapshot # Conflicts: # CHANGELOG.md
|
Resolved the |
|
I have concerns with the writer-side spinning ( Alternative: Follow
|
…er-snapshot # Conflicts: # CHANGELOG.md
|
Thanks for the detailed performance analysis. I agree that yielding on an application-recording path is an undesirable tradeoff. I checked the current ownership before changing the design: Could you confirm which scope you prefer?
I will keep the current approved branch unchanged until that boundary is clear, rather than replace the hot path with a broader design without confirmation. |
Fixes #8779
The float64 metric sum counter keeps whole and fractional values in separate atomics. Cumulative collection can combine values from different points in time and export a sum that was never observed.
The generation validation added in the earlier revision rejects fractional ABA snapshots, but waiting for all fractional writers to become idle can prevent collection from completing while measurements continue. This update keeps the lock-free snapshot fast path. After three unsuccessful attempts, a float64 load serializes fallback collectors, freezes new fractional writes, waits only for writes that had already entered, captures a stable fractional value with the integer atomic, and then releases writers. Whole-number additions retain the existing integer atomic fast path.
Tests:
make test/./sdk/metric ARGS=-race TIMEOUT=60go test -timeout 60s -race ./internal/aggregate -run '^TestAtomicCounterLoadMakesProgressWithFractionalContention$' -count=100fromsdk/metricgo vet ./internal/aggregatefromsdk/metricmake precommitcompletes generation, module tidy, lint, README, and module verification locally. Its test stage stops atbridge/opentracingTestBridgeTracer_ExtractAndInject_gRPCwith a gRPC server-preface EOF; the same failure is reproducible on the prior upstream baseline and is unrelated to this change.Benchmarking on Apple M4 Pro with
GOMAXPROCS=8reports 0 B/op and 0 allocs/op for all existing atomic-counter benchmarks. The added concurrent fractional-add benchmark also reports 0 B/op and 0 allocs/op across ten samples.