Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
- name: Set up Dart
uses: dart-lang/setup-dart@v1
with:
sdk: 3.11.4
sdk: 3.13.1

- name: Show tool versions
run: |
Expand Down Expand Up @@ -68,7 +68,7 @@ jobs:
- name: Set up Dart
uses: dart-lang/setup-dart@v1
with:
sdk: 3.11.4
sdk: 3.13.1

- name: Show tool versions
run: |
Expand Down
43 changes: 42 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ It intentionally does not use the DevTools Flutter or web UI.

## Fast Start

Requires Dart 3.13 or later (before Dart 4). The region-marking helper also
requires Dart 3.13, so Flutter apps using it need a Flutter SDK that bundles
Dart 3.13 or later. The profiler itself remains a pure-Dart CLI/MCP tool.

Install the CLI once:

```bash
Expand Down Expand Up @@ -277,6 +281,14 @@ await profileRegion(
Human output is designed for terminal scanning. JSON output is designed for
automation and AI agents.

`run --json` reserves stdout for the JSON result and forwards target logs from
both streams to stderr. Use `--no-forward-output` to suppress target logs:

```bash
devtools-profiler run --json -- dart run bin/main.dart \
> profile.json 2> target.log
```

Use human output while exploring:

```bash
Expand Down Expand Up @@ -304,6 +316,25 @@ devtools-profiler summarize \
JSON responses include a `cliCommand` field for the command that can reproduce
the same analysis selection.

Positional arguments accept session ids in addition to file paths, making it
quick to reference stored runs by their id (listed by `devtools-profiler
profiles`):

```bash
devtools-profiler summarize 0712060003-8c410
devtools-profiler compare 0712060003-8c410 0711235455-ebfb3
devtools-profiler trends session-a session-b session-c
devtools-profiler inspect --method Parser.parseFile 0712060003-8c410
devtools-profiler inspect-classes --class String 0712060003-8c410
```

Check for regressions against a known-good baseline (exits 1 on regression):

```bash
devtools-profiler regress path/to/baseline-session
devtools-profiler regress --warn-only 0712060003-8c410
```

Important result sections:

- `overallProfile`: the whole run from process start to process exit.
Expand Down Expand Up @@ -574,7 +605,10 @@ Commands:
`--duration`.
- `summarize <path>` summarizes a session directory or profile artifact.
- `explain <path>` explains likely hotspots in one selected profile.
- `compare <baseline> <current>` compares two profiles or sessions.
- `compare <baseline> <current>` compares two profiles or sessions. Also
accepts 3+ positional args for multi-compare aligned hotspot tables.
- `regress <baseline> [current]` compares current against a baseline and
exits with code 1 when regressions are found. Use `--warn-only` to exit 0.
- `trends <path>...` analyzes a sequence of profiles or sessions.
- `inspect <path>` inspects one method in one profile.
- `inspect-classes <path>` inspects memory classes in one profile.
Expand All @@ -585,12 +619,15 @@ Commands:
Common presentation flags:

- `--json` emits structured JSON instead of human output.
- `--csv` outputs compact CSV tables instead of formatted terminal output.
- `--call-tree` includes a top-down call tree.
- `--expand` is an alias for `--call-tree`.
- `--bottom-up` includes a bottom-up call tree.
- `--method-table` includes a DevTools-style method table.
- `--hide-sdk` hides Dart and Flutter SDK frames.
- `--hide-runtime-helpers` hides common profiler/runtime helper packages.
- `--collapse-async` collapses all `dart:async` frames into a single
"async overhead" entry in summary tables.
- `--include-package <prefix>` keeps only matching package prefixes. May be
repeated.
- `--exclude-package <prefix>` excludes matching package prefixes. May be
Expand Down Expand Up @@ -628,6 +665,7 @@ Common presentation flags:

Path arguments accepted by read/analyze commands:

- a session id (listed by `devtools-profiler profiles`)
- a session directory
- a region `summary.json`
- a raw `cpu_profile.json`
Expand Down Expand Up @@ -765,3 +803,6 @@ dart test packages/devtools_profiler_cli
dart test packages/devtools_region_profiler
dart test packages/devtools_profiler_protocol
```

All four test suites must pass before publishing. Current totals:
The test suites cover all four packages.
99 changes: 99 additions & 0 deletions packages/devtools_profiler_cli/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,104 @@
# Changelog

## 0.6.0

- Allowed Artisanal releases from 0.6.0 up to, but not including, 1.0.0.
- Implemented `profiles --json` with structured empty results, session metadata,
and explicit listing counts and truncation.
- Validated replay, trend, and output-format options before execution.
- Kept replay output capturable and skipped animation for redirected hosts.
- Unified session-directory resolution and preferred existing artifact paths.
- Clarified annotation granularity and allocation/CPU correlation semantics.
- Fixed unlimited annotation output and aligned run/attach text with JSON.
- Added an opt-in `browse` terminal UI for searchable stored sessions and
explicit baseline/current region selection, summary previews, and command
export. Redirected hosts cannot enter terminal mode.
- Matched multi-run CPU frames by name, kind, and location instead of name
alone; missing entries no longer claim a function was eliminated.
- Corrected default pairwise comparison order: previous run is the baseline,
newest run is current.
- Rebuilt multi-run frame lists before filtering/alignment and applied row
limits after alignment. Added MCP `profile_compare.paths` support.
- Added aligned nullable rows to multi-run JSON and trend JSON. Multi-run CSV
now includes kind/location columns and blank cells for missing observations.
- Aligned the MCP implementation version with the CLI release and required
core 0.6.0 for the improved artifact reader and capture lifecycle.
- Improved saved-profile frame names and CPU isolate/thread metadata through the
shared core reader, for CLI and MCP workflows.
- Finalized in-flight region captures before terminating duration-limited runs.
- Kept `run --json` stdout parseable by forwarding target logs to stderr;
`--no-forward-output` still suppresses them.
- Shared complete CPU call paths across top-down, bottom-up, and method-table
presentation for both CLI and MCP, before applying output limits.
- Required Dart 3.13 or later and refreshed dependencies, including artisanal
0.6 and dart_mcp 0.5.2 (remaining on the supported 0.5.x line).

## 0.5.2

- Updated the CLI release to use core 0.5.2, fixing profiling from AOT bundles
installed with `dart install`.

## 0.5.1

- Updated the CLI release to use `devtools_profiler_core` 0.5.1, including
reliable completion of interrupted CPU and memory profile captures.

## 0.5.0

- Added `replay` command that animates through stored CPU samples as a
live flame chart. Shows time-windowed frame samples with visual bars.
Use `--window` to control the time slice, `--speed` for playback rate,
and `--top` for number of frames shown.
- Added `annotate` command that shows per-file hotspot breakdowns with
sample counts, percentages, and visual bars. Use `--file` to filter to
one source file, `--top` and `--min-samples` to control output.
Package URIs are resolved via package_config.json.
- Added `lineForFunction()` helper to extract line numbers from VM
profile function data.

- Positional arguments can now be session ids in addition to file paths.
Commands like `summarize`, `compare`, `explain`, `trends`, `inspect`,
`search-methods`, `inspect-classes`, and `compare-method` first try to
match a positional argument against stored session ids before falling
back to file-path treatment.
- Improved error output when an artifact is not found — a tip now suggests
`devtools-profiler profiles` to list available sessions or to pass a
session id as a positional argument.
- Added `--csv` flag for compact machine-readable table output. Supports
`summarize`, `compare`, `trends`, and multi-compare modes.
- Added `--last N` flag to `trends` for analyzing the N most recent stored
sessions without specifying explicit paths.
- Added `--collapse-async` flag that replaces individual `dart:async` frames
with categorized entries grouped by async type (normal completions, error
completions, listener dispatch, microtask scheduling, zone overhead).
When raw CPU samples are available, async cost is further attributed to
the first non-async caller in the stack, producing actionable entries like
`async (await _runFrame)` that show which calling function triggered the
async cost.
- Added what-if async removal estimation to `--collapse-async`: when raw
CPU samples are available, the profiler estimates how much time could be
saved by converting specific functions from async to sync. Warnings appear
for functions where normal completions dominate the async cost, making
them prime candidates for sync conversion.
- Multi-compare mode: `compare` now accepts 3+ positional arguments and
produces an aligned hotspot table showing each method's self-percentage
across all sessions, with "eliminated" for absent entries.
- Added `isAsyncOverhead` getter to `ProfileFrame` for identifying
`dart:async` frames.
- Added `regress` command that compares the current profile against a
known-good baseline and reports regressions. Exits with code 1 when
regressions are found. Use `--warn-only` to always exit 0.
Examples:

```bash
devtools-profiler regress path/to/baseline
devtools-profiler regress 0712060003-8c410 0711235455-ebfb3
devtools-profiler regress --warn-only path/to/baseline
```
Comment thread
coderabbitai[bot] marked this conversation as resolved.

- Updated `--csv` output: now also supports the multi-compare mode and
the `regress` command.

## 0.4.0

- Added `profiles` command that lists stored profiling sessions in a
Expand Down
112 changes: 112 additions & 0 deletions packages/devtools_profiler_cli/INTERACTIVE_ANALYSIS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# Interactive analysis proposal

Status: initial summary browser and shared frame alignment implemented.
The remaining items below are a roadmap, not shipped capabilities.

The first implementation uses the core runtime and Style's cell-aware clipping,
with a vertically stacked list/preview and a scrollable details mode. It
deliberately does not load raw samples, auto-match region names, or introduce a
widget framework. Full filtered analysis is available through the exported
comparison command. Multi-run CLI/MCP analysis rebuilds raw frames when
available and preserves missing observations across output formats.

## Recommendation

Add an explicit `browse` command for stored sessions, using Artisanal's
core TEA runtime. Keep existing one-shot commands as the primary scripting
interface. Do not automatically enter raw mode when a command lacks arguments.

A session browser with a comparison preview is a better first step than a
full live dashboard: it addresses session selection and cross-run investigation
without adding capture lifecycle state to the UI.

## Existing foundations

- `profiles` already discovers sessions and supports compact/extended listings.
- `compare` supports two-run and multi-run comparisons.
- `compare-method`, `trends --last N`, and `regress` provide drill-down and
regression workflows.
- Shared presentation preparation already supplies CLI and MCP analysis.
- Current terminal rendering uses Artisanal Console tables and definition lists.

Reuse session discovery and prepared analysis; do not parse rendered text or
spawn the CLI recursively from the browser.

## Relevant Artisanal 0.6 capabilities

The installed package's changelog documents:

- Shared command-palette matching, stable item IDs, viewport windows, and
`CommandPaletteOverlay` / `CommandPaletteComponent`: useful for searchable
session and action selection.
- `FrameView` and `FrameLayout`: positioned panes with fixed, percentage, and
weighted-fill sizing; suitable for a session list and comparison preview.
- Focused runtime, layout, style, and charting imports: no need to add the
widget framework for this small UI.
- Charting primitives, including sparklines and histograms: useful for repeated
measurements, provided exact values and units remain visible.
- Capability-aware Console operations and corrected non-interactive behavior:
useful for a static rendering refresh independently of a TUI.

These are available capabilities, not claims that the profiler uses them today.

## First browser slice

1. Discover session summaries without loading every raw CPU artifact.
2. Search by session ID, command, and directory.
3. Select a baseline and current run explicitly; show their roles at all times.
4. Choose whole-session or matching named regions. Region IDs are run-local;
repeated names require disambiguation, not silent first-match selection.
5. Preview duration, sample count, memory deltas, warnings, and hotspot changes.
6. Offer method inspection and an exact reproducible one-shot command.

Use a two-pane layout on wide terminals and one pane with a details toggle on
narrow terminals. Support keyboard-only navigation, visible key hints,
Escape/back, Ctrl+C/quit, resizing, and terminal restoration after errors.
Refuse non-TTY input/output with an actionable one-shot alternative.
Never consume MCP stdin or emit terminal escapes into JSON/CSV output.

Cache only selected prepared artifacts with a bounded policy. Discard stale
asynchronous results after selection changes; rendering must not perform I/O.

## Comparison correctness before decoration

The old multi-run terminal table keyed frames by display name and labeled
missing entries "eliminated", even though its input was top-frame lists.
This is now corrected through shared core alignment, used by terminal, CSV,
JSON, MCP, and the browser. Exact locations are retained rather than guessing
cross-checkout equivalence.

Recommended semantics:

- Match by canonical function identity including location, not name alone.
Normalize checkout roots/package versions deliberately and test collisions.
- Distinguish "not in selected top frames", "not sampled", and unavailable data.
Do not infer zero cost from any of them.
- Compute comparisons from complete filtered data; limit only displayed rows.
- Show percentage-point changes separately from estimated sampled CPU time.
Neither is elapsed wall time or a direct throughput measurement.
- Warn about different sample periods, capture durations, region scopes,
filters, SDK/build modes, or incomplete isolate coverage when known.
Unknown capture metadata must remain unknown, not assumed compatible.
- For repeated benchmarks, group comparable workloads and show sample size,
median and dispersion before introducing statistical regression claims.
A fixed capture-window duration is not itself a benchmark performance metric.

New analysis semantics belong in core and must remain accessible via MCP.

## Delivery and validation

1. Shared cross-run comparison correctness with fixtures for truncated top
lists, same-name functions, missing data, and different capture settings.
2. Static rendering refresh: compact metric header, explicit baseline/current
labels, units, signed deltas, and bounded terminal widths.
3. Read-only browser reusing those models and renderers.
4. Repeated-run grouping and distribution summaries after capture metadata and
comparability rules are defined.

Test plain/no-color and Unicode output, narrow and wide layouts, JSON/CSV
isolation, and deterministic keyboard navigation. Exercise a real PTY for
resize, cancellation, interrupted artifact loading, and terminal restoration.
Benchmark discovery with many sessions and memory usage with large CPU
artifacts; do not load all samples just to paint a session list.
Loading
Loading