Skip to content

[TENT] Fix metrics recording zero-overhead, MLU sentinel, and parallel-vector contract#2989

Open
staryxchen wants to merge 9 commits into
kvcache-ai:mainfrom
staryxchen:worktree-fix-tent-metrics
Open

[TENT] Fix metrics recording zero-overhead, MLU sentinel, and parallel-vector contract#2989
staryxchen wants to merge 9 commits into
kvcache-ai:mainfrom
staryxchen:worktree-fix-tent-metrics

Conversation

@staryxchen

@staryxchen staryxchen commented Jul 18, 2026

Copy link
Copy Markdown
Collaborator

Description

Fixes six design / correctness issues found while reviewing the TENT metrics system (tent/metrics/), plus a docs sync. Each change is test-driven.

Correctness:

  • Zero-overhead claim was false on the hot path. recordTaskCompletionMetrics called TentMetrics::instance().record* directly (not via macros), so when TENT_METRICS_ENABLED=OFF every task completion still hit no-op stubs. The whole recording block is now #if-gated so the body is empty when disabled, matching the doc claim.
  • MLU sentinel poisoned real data. An infeasible-at-submit deadline was recorded as MLU=5.0 into the tent_deadline_mlu_permille histogram, indistinguishable from a genuine 5x-over-window sample. Replaced with a dedicated tent_deadline_infeasible_total counter.

Simplicity:

  • Unused bytes parameter. recordReadFailed(size_t bytes) / recordWriteFailed(size_t bytes) ignored the argument (failed transfers transfer no bytes). Dropped the parameter and updated all call sites.
  • Parallel-vector ordering contract. histograms_ and histogram_boundaries_ were two vectors whose order had to match by convention; a future contributor updating one without the other would silently produce mislabeled JSON. Collapsed into a single vector<HistogramEntry> pairing each histogram with its boundaries.
  • Runtime-configurable buckets removed. initialize() reassigned histogram_t members mid-flight when the config supplied latency_buckets/size_buckets — a code smell that also produced mismatched JSON labels. Buckets are now fixed at compile time (version-controlled), making observability reproducible. (Net -201 lines.)

Docs / build:

  • Synced metrics.md (added 6 missing metrics, removed the bucket config, corrected the zero-overhead claim, clarified *_requests_total counts success+failure).
  • Moved option(TENT_METRICS_ENABLED) from the leaf metrics CMakeLists to tent/CMakeLists.txt for discoverability.

Module

  • Transfer Engine (mooncake-transfer-engine)
  • Mooncake Store (mooncake-store)
  • Mooncake EP (mooncake-ep)
  • Mooncake PG (mooncake-pg)
  • Integration (mooncake-integration)
  • P2P Store (mooncake-p2p-store)
  • Python Wheel (mooncake-wheel)
  • Common (mooncake-common)
  • Mooncake RL (mooncake-rl)
  • CI/CD
  • Docs
  • Other

Type of Change

  • Bug fix
  • New feature
  • Refactor
  • Breaking change
  • Documentation update
  • Performance improvement
  • Other

How Has This Been Tested?

Three test layers, all green.

Test commands:

# Configure (metrics enabled + tests + tent)
cmake -B build -S mooncake-transfer-engine \
  -DUSE_TENT=ON -DTENT_METRICS_ENABLED=ON -DBUILD_UNIT_TESTS=ON \
  -Dpybind11_INCLUDE_DIR=<extern/pybind11/include>
cmake --build build -j

# Unit + HTTP integration tests
./build/tent/tests/tent_metrics_recording_test      # 9 tests
./build/tent/tests/metrics_config_loader_test        # 26 tests
./build/tent/tests/tent_metrics_http_server_test     # 1 test
./build/tent/tests/causal_chain_test                 # 4 tests (no regression)

# Disabled-build compile check (verifies the #if gates)
cmake -B build_disabled -S mooncake-transfer-engine \
  -DUSE_TENT=ON -DTENT_METRICS_ENABLED=OFF -DBUILD_UNIT_TESTS=ON \
  -Dpybind11_INCLUDE_DIR=<extern/pybind11/include>
cmake --build build_disabled -j --target tent_metrics_recording_test
./build_disabled/tent/tests/tent_metrics_recording_test

Test results:

  • Unit tests pass — recording (9) + config loader (26) + HTTP server (1) + causal chain (4) = 40 tests.
  • Integration tests pass — HTTP endpoints (/metrics, /metrics/json, /health) scraped via coro_http_client; Prometheus/JSON output asserts on counters and histogram buckets.
  • Disabled-build compiles cleanly and the stub test passes (validates the zero-overhead #if gating).

The new test file metrics_recording_test.cpp uses delta-based assertions (snapshot before/after) so it is robust to the TentMetrics singleton's non-resettable counter state, and drives a real TransferEngineImpl with a FakeTransport to exercise the actual recordTaskCompletionMetrics path.

Checklist

  • I have performed a self-review of my own code
  • I have formatted my code using ./scripts/code_format.sh
  • I have run pre-commit on the files touched by this change and all hooks pass (ran on touched files per AGENTS.md guidance; --all-files not run to avoid unrelated edits)
  • I have updated the documentation (if applicable)
  • I have added tests to prove my changes are effective
  • For changes >500 LOC: I have filed an RFC issue — net non-test code change is negative (simplification); the 665-line test file is the bulk of the insertions. Filing left to submitter's judgment.

AI Assistance Disclosure

  • No AI tools were used
  • AI tools were used (specify below)

CodeBuddy (GLM-5.2) was used to implement the fixes, write the tests, and draft this PR. The human submitter has reviewed every changed line and can defend the changes end-to-end.

Add metrics_recording_test.cpp with gtests driving a real
TransferEngineImpl + FakeTransport and asserting on TentMetrics JSON
output (delta-based, robust to singleton state).

Tests covering current behavior:
- CompletedTransferRecordsBytesAndLatency
- FailedTransferCountsFailureNotBytes
- FeasibleDeadlineRecordsMLU
- HistogramJsonBucketsMatchBoundaries (regression guard)

Tests covering behavior introduced by subsequent commits:
- InfeasibleDeadlineRecordsSeparableCounter: a dedicated counter for
  infeasible deadlines so the 5.0 sentinel does not pollute the MLU
  histogram.
- BucketsAreCompileTimeDefaults: buckets are fixed at compile time,
  not config-driven.

Compiles to a stub test when TENT_METRICS_ENABLED=OFF.

Signed-off-by: staryxchen <[email protected]>
The design doc claims compile-time metrics disable yields zero runtime
overhead, but recordTaskCompletionMetrics called TentMetrics::instance()
.recordReadCompleted/recordWriteFailed/recordDeadlineMLU directly (not via
macros), hitting no-op stubs on every task completion when disabled. Wrap
the whole recording block in #if TENT_METRICS_ENABLED so the body is empty
when disabled, matching the doc claim. The inner #if around stage-latency
is removed (now redundant under the outer wrap).

Also drop the unused 'bytes' parameter from recordReadFailed/recordWriteFailed
and the TENT_RECORD_*_FAILED macros: the implementations ignored it (failed
transfers transfer no bytes), so the signature was misleading. Updated all
call sites: ScopedLatencyRecorder::markFailed, transfer_engine_impl.cpp,
tent_metrics_example.cpp, the recording test.

Verified:
- Enabled build: recording tests pass.
- Disabled build: compiles cleanly, stub test passes.

Signed-off-by: staryxchen <[email protected]>
When a transfer's deadline was already in the past at submit, the code
recorded MLU=5.0 into the tent_deadline_mlu_permille histogram as a
sentinel. A genuine MLU of 5.0 (5x over the window) is a real measurement
that lands in the same +Inf bucket, so the two were indistinguishable in
the histogram output -- the sentinel poisoned real data.

Add a separate tent_deadline_infeasible_total counter and
recordDeadlineInfeasible(); the infeasible-at-submit case now increments
the counter and leaves the MLU histogram untouched.

Signed-off-by: staryxchen <[email protected]>
initialize() reassigned histogram_t members mid-flight when the config
supplied latency_buckets/size_buckets -- a code smell (relies on
histogram_t being safely reassignable) that also produced mismatched JSON
labels: histogram_boundaries_ kept the compile-time defaults while the
histogram object's internal buckets changed. Most deployments never change
buckets anyway.

Remove the latency_buckets/size_buckets config knob entirely. Buckets are
now fixed at compile time (version-controlled in kLatencyBuckets etc.),
which is simpler and makes observability reproducible across deployments.

Removed: MetricsConfig fields, config_loader parsing/env-vars/keys,
validateConfig bucket checks, the reassignment block in initialize(), and
the corresponding config_loader unit tests. Updated the recording test to
assert compile-time defaults directly.

Signed-off-by: staryxchen <[email protected]>
histograms_ (vector<histogram_t*>) and histogram_boundaries_
(vector<vector<double>>) were maintained as two parallel vectors whose
ordering had to match by convention. getJsonMetrics() indexed them in
lockstep, so a future contributor adding a histogram to one vector but not
the other would silently produce mislabeled JSON or out-of-bounds reads.

Collapse the two into a single vector<HistogramEntry> where each entry
pairs the histogram pointer with its boundaries pointer. The ordering
contract is structurally eliminated.

Signed-off-by: staryxchen <[email protected]>
Validate the HTTP wiring (handlers, status codes, body content) on top of
the recording assertions. Uses coro_http_client (FetchUrl helper adapted
from mooncake-store/tests/master_metrics_test.cpp) to scrape the real
/metrics, /metrics/json, /health endpoints started by TentMetrics.

Tests:
- PrometheusEndpointExposesAllCounters: GET /metrics returns 200 with
  tent_read_bytes_total, tent_write_bytes_total,
  tent_deadline_infeasible_total, tent_write_latency_us_bucket present.
- JsonEndpointValid: GET /metrics/json returns 200, parseable JSON with
  expected counter and histogram keys.
- HealthEndpointOk: GET /health returns 200 with body "OK".

A retry loop absorbs the brief window between async_start() returning and
the server accepting connections. Tests skip gracefully if the port bind
raced (log-only mode).

Signed-off-by: staryxchen <[email protected]>
Docs:
- Add tent_transport_failover_total, tent_deadline_infeasible_total,
  tent_deadline_mlu_permille, tent_stage_{queue_wait,dispatch,transport}_us
  to the Available Metrics table.
- Remove latency_buckets/size_buckets from config-file and env-var sections
  (the knob was removed); note buckets are now compile-time.
- Document recordTransportFailover/recordDeadlineMLU/recordDeadlineInfeasible/
  recordStageLatency APIs and update FAILED macros to the no-arg form.
- Clarify *_requests_total counts success+failure and *_failures_total
  records no bytes.
- Correct the zero-overhead claim to mention the recordTaskCompletionMetrics
  body is #if-gated.
- Note ylt omits zero-valued counters from Prometheus output.
- Update Adding New Metrics to show the HistogramEntry struct form.

CMake:
- Move option(TENT_METRICS_ENABLED ...) from tent/src/metrics/CMakeLists.txt
  to tent/CMakeLists.txt so the knob is discoverable at the top level. The
  target_compile_definitions stays in the metrics subdirectory. Non-breaking:
  option() honors cache values.

Signed-off-by: staryxchen <[email protected]>
clang-format and cmake-format adjustments on the files modified by the
metrics fixes. No semantic changes.

Signed-off-by: staryxchen <[email protected]>
@github-actions github-actions Bot added documentation Improvements or additions to documentation run-ci Transfer Engine labels Jul 18, 2026
@staryxchen
staryxchen marked this pull request as ready for review July 18, 2026 09:38

@gemini-code-assist gemini-code-assist Bot 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.

Code Review

This pull request refactors the TENT metrics collection system by removing runtime-configurable histogram buckets in favor of fixed compile-time boundaries to ensure reproducible observability. It also introduces a dedicated tent_deadline_infeasible_total counter to prevent infeasible deadlines from polluting the MLU histogram, and updates failed transfer metrics to no longer record bytes. Additionally, a comprehensive test suite (metrics_recording_test.cpp) is added to verify metrics recording and HTTP endpoints. Feedback is provided to optimize vector initialization in TentMetrics::registerMetrics() to ensure that the reserved capacity is utilized and redundant allocations are avoided.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread mooncake-transfer-engine/tent/src/metrics/tent_metrics.cpp Outdated
@codecov-commenter

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

vector::operator=(initializer_list) reallocates to fit the initializer
list exactly, so the preceding reserve(8) calls were dead and the
'avoid reallocation' comment was misleading. registerMetrics() runs once
per initialize() (cold path), so the reserve provided no benefit either
way. Remove the two lines and the comment.

Signed-off-by: staryxchen <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation run-ci Transfer Engine

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants