decentraland / decentraland/unity-explorer

MCP: expose Current-scene runtime metrics (tick + traffic) with bottleneck diagnosis

Open
#9,623 1 comment 0 reactions 0 assignees View on GitHub
3-low feature performance sdk
Dominant language
C#
Stars
23
Forks
17
Avg merge
2d 14h
Merged PRs (30d)
94

Description

## Summary

Follow-up to #9457. Expose the **"Current scene"** debug widget's runtime data — scene tick health + scene↔client traffic — over the embedded MCP server, and add a rule-based **bottleneck diagnosis** with optimization suggestions so agents and creators get a "what's slow and what to do about it" answer, not just raw counters.

## Background

#9457 added the "Scene content" widget + `get_scene_content_stats` / `get_scene_content_breakdown` / `get_performance_stats` MCP tools. The sibling **"Current scene"** widget (`DebugViewCurrentSceneSystem`) shows a different set of metrics, all read from `SceneRuntimeMetrics` (thread-safe `SampledCounter`s):

- **Tick health** — Real tick FPS, Min/Max FPS (last 256 ticks), Hiccups (ticks > 50 ms), tick-FPS chart.
- **From scene** — Bytes total, Bytes/s, Msgs total, Msgs/s, Msgs/call min/max, Msg hiccups.
- **To scene** — same set (bytes & messages the client sends *to* the scene).

### Gap vs. what MCP already exposes

`get_performance_stats` already reports a tick-FPS summary, but only over a ~2 s render-sampling window, and it exposes **none** of the scene↔client traffic. The traffic metrics are currently only visible in this widget.

## Proposed tool — `get_scene_runtime_metrics`

Read-only. Returns the whole "Current scene" widget as structured JSON, **instantly** (counters are already accumulated and thread-safe, so no sampling window is needed). Reuses `SampledCounter.ComputeStats(...)` — the same math the widget uses — so the two can't drift.

```
{ tick: { realFps, minFps, maxFps, hiccups, samples, targetFps },
fromScene: { bytesTotal, messagesTotal,
bytesPerTick: { avg, min, max },
messagesPerTick: { avg, min, max, hiccups } },
toScene: { ...same... },
diagnosis: { verdict, summary, signals: [ { metric, value, severity, suggestion } ] } }
```

## Bottleneck diagnosis (rule-based)

A handful of explicit, documented thresholds (constants) map the metrics to a bottleneck class + a targeted suggestion. Each rule names the metric that tripped:

| Symptom | Bottleneck class | Suggestion |
|---|---|---|
| `realFps` ≪ `targetFps` **+** high msgs/tick from scene | `tick-bound-chatty` | Emitting ~N updates/tick — dirty-check; stop re-writing unchanged components |
| `realFps` below target, traffic normal | `tick-bound-logic` | Profile scene `onUpdate`; move work off the hot path / spread across ticks |
| `minFps` ≪ `realFps` or `hiccups > 0` | `hitching` | K ticks > 50 ms — avoid per-tick allocations, precompute |
| Tick FPS healthy, render FPS low | `render-bound` | Not a scene-logic bottleneck — check `get_scene_content_breakdown` (triangles / draw calls / textures over budget) |
| `messagesToScene` extreme | `input-flood` | Client sending N events/tick; usually fine unless paired with tick drops |
| all within budget | `healthy` | — |

Example summary: *"Tick-bound: scene at 18/30 fps while emitting ~240 msgs/tick — likely writing components that haven't changed. Dirty-check before writing."*

### Caveats
- It's a **heuristic**, not a profiler — it points at the right subsystem, phrased as "likely / consider". The tool description must say so.
- This tool only sees tick + traffic (scene-side/CPU). A **GPU/render** bottleneck (tick healthy, render FPS low) is explicitly handed off to `get_performance_stats` + `get_scene_content_breakdown` rather than diagnosed here.

## Open design decisions (resolve when picked up)

1. **Traffic rates** — instant-only (totals + per-tick averages from the ring), or an optional `sampleSeconds` that diffs totals over a window for true per-second rates (like `get_performance_stats` holds to sample)?
2. **Diagnosis scope** — keep it scene-CPU/traffic-only and hand off GPU cases, or build a bigger **aggregator** that also samples render FPS and ranks scene-CPU vs GPU vs content in one call?
3. **Surface parity** — MCP tool only, or also feed the diagnosis into the creator-facing Scene Stats panel / Current-scene widget?

## Definition of done
- [ ] `get_scene_runtime_metrics` MCP tool returning tick + both traffic directions, instant.
- [ ] Rule-based `diagnosis` field with documented thresholds and per-signal suggestions.
- [ ] Reuses `SampledCounter.ComputeStats` (no metric math duplicated from the widget).
- [ ] Tests: output-schema ↔ payload parity, no-scene error path, a couple of diagnosis rule cases.
- [ ] `docs/mcp-automation.md` tool catalog + "Interpreting the numbers" updated.
- [ ] (Optional) `reference/performance-debugging.md` in `decentraland/sdk-skills` updated to cover the new tool.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.