# romcp MicroProfiler preview

`studio_profile` provides `status` and `snapshot` actions through the v3 plugin. Snapshot analyzes at most `maxFrames` recent frames (1–256, default 64) from the existing MicroProfiler buffer. It does not enable, pause, disable, resize, or show the profiler.

The adapter requires the official LibMP ModuleScript beside `Profiler` inside the plugin. It deliberately does not discover or execute arbitrary game modules. LibMP is not bundled yet: its public repository/release was inspected, but no redistribution license was found there. This is a packaging question to resolve before the release, not evidence that Roblox prohibits use. In this checkout, status therefore reports the missing dependency until a developer installs it into a local plugin build.

## Report contract

Reports include CPU/GPU frame interval distributions in milliseconds, sample counts, nearest-rank p50/p95/p99, mean and maximum, up to eight worst CPU frames, capture size, data-format version, skipped earlier frames, observed absolute-frame gaps, and separate paused/incomplete/invalid/missing-GPU counts. No samples means `{ count: 0 }`, not invented zero timings. Missing GPU timestamps do not invalidate an otherwise usable CPU frame.

The `scopes` report ranks up to 20 named CPU timers by inclusive duration, combining only complete enter/exit pairs contained within individual valid frames. Nested and parallel work overlap and must not be summed as total CPU usage. Timer labels are not verified script paths. Unmatched exits, abandoned enters, invalid frames, GPU events, capture stitching, and invalid stack states are excluded rather than assigned invented durations. Cross-frame scopes are deliberately omitted from this first analyzer.

Scope analysis stops at 50,000 iterator entries and reports `limitReached`; it caps nesting at 128 and distinct paired timers at 512. Exceeding those latter limits makes the scope report unavailable while preserving frame metrics. Names are limited to 200 Unicode characters. `omittedTimers` reports ranked timers excluded from the returned top 20. Iterator failures produce an unavailable scope status; disposal is attempted before session disposal, and a disposal failure propagates to `cleanupRequired`.

The report is not a per-script cost breakdown. CPU and GPU intervals overlap; they must not be summed. Exclusive-time calculation, counter trend analysis, controlled capture lifecycle, raw artifact retrieval, scenario comparison, public HTTP/SDK routes, and a profiling UI remain unfinished. Profiler overhead is not measured.

Production reads preflight the engine buffer size and allocate at most 16 MiB. The selected frame range is bounded independently. A buffer changing during the read can fail parsing; the adapter does not silently retry another sample. Sessions are disposed after success and failure, and cleanup failures remain visible. Concurrent snapshots in the plugin process are rejected. No profiler settings are changed, so no restoration is claimed.

## Dependency evidence

Official release asset inspected: `LibMP.luau`, GitHub asset ID `456813947`, 5,098,733 bytes, published June 24, 2026 under the mutable `latest` release tag. SHA-256 verified locally:

`ab9579e592e8751386a01537152f2b739cc7942ce565d3c11337cddaa250d231`

The development download lives under ignored `.tmp/LibMP.luau` and is not in the plugin/package. Do not rely on the mutable tag without verifying the digest when reproducing this investigation.

Primary references: [official library and setup](https://github.com/Roblox/libmp), [API reference](https://github.com/Roblox/libmp/blob/main/docs/api-reference.md), [official releases](https://github.com/Roblox/libmp/releases).

## Validation

`pnpm test:profiler` executes the production analyzer with simulated LibMP sessions in Luau. It verifies CPU/GPU clock conversion, percentile math, frame exclusions and gaps, bounds, empty data, disposal failures, concurrent calls, and unavailable backends. Scope fixtures additionally cover nested and parallel pairs, cross-frame omissions, iterator disposal, and the entry budget. These fixtures do not establish compatibility with a valid real recording; scope timing and frame timing both still require that validation.

Live Studio `0.737.0.7371584` exposes MicroProfilerService and ScriptProfilerService. An earlier read-only `GetDataSize(0)` probe returned a 367,216-byte buffer. No LibMP module was installed in ReplicatedStorage.

On September 7, a read-only transfer from the connected VehicleRuntime window saved a 273,944-byte buffer to ignored `.tmp/live-profile.gprx`. Its SHA-256 is `e78c067b49fe7f68c499a6bb8a03d5113ad5e6d42113e11ba805320fbcc15dd8`. The checksum-pinned LibMP release successfully opened it with data-format version 65536. The production analyzer reported zero available frames, empty CPU/GPU samples, unavailable scopes, and successful session disposal. This verifies a real engine buffer can be transferred and opened, and that empty data is not fabricated into timings. It does not validate timing calculations or scope iteration against populated capture data. No playtest, profiler control changes, or game-instance mutations were performed for this capture.

The checksum-verified release now initializes successfully in Lune's offline environment with library/data-format versions both `65536`. `lune run tests/plugin/libmp-runtime.luau <LibMP.luau>` verifies that malformed buffers are rejected and session memory returns to baseline. A later live transfer attempt could not run because Studio had disconnected; no capture file was received.

## Offline development command

From the repository root, run `lune run scripts/analyze-profile.luau <capture.gprx> <LibMP.luau> [maxFrames]`. The command verifies the library checksum before loading it, bounds capture size and frame count, uses the production analyzer, disposes the session, and prints a JSON report. The input must be a compatible binary recording; HTML profiler dumps are not accepted as an equivalent format. LibMP remains a separate download. This development script is not yet a packaged CLI command or HTTP import route.

The real library's initialization, malformed-input rejection, and opening of an empty-frame engine buffer have been tested. A populated recording is still required to validate real frame and scope analysis. The offline command preserves scope-disposal failures as well as session-disposal failures in `cleanupRequired`.
