Add aot-impact-analysis skill for AOT size and startup analysis - #55085
Add aot-impact-analysis skill for AOT size and startup analysis#55085baronfel wants to merge 2 commits into
Conversation
Adds a reusable agent skill that automates the binary-size and startup-performance analysis used when enabling NativeAOT functionality in the dotnet CLI. The skill follows the thin-core + subskill-pages structure: - SKILL.md: thin orchestrator (when to measure, the always-apply rules) - size-analysis.md: before/after dotnet-aot.mstat diff via sizoscope-cli - startup-and-telemetry.md: redist-muxer startup timing + Aspire Dashboard OTel - writing-the-summary.md: assembling the PR-ready impact summary - references/perf-and-otel.md: OTLP env-var contract + aspire otel surface - scripts/: Measure-AotSize.ps1, Measure-AotStartup.ps1, Start-AspireDashboard.ps1 Size methodology mirrors the aot-size-analysis CI workflow; startup is measured through the real redist dotnet.exe muxer (DOTNET_CLI_ENABLEAOT) rather than a standalone host. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds a new reusable GitHub skill (aot-impact-analysis) under .github/skills/ to standardize how contributors measure NativeAOT size impact (via sizoscope-cli on dotnet-aot.mstat) and startup impact (timings through the redist muxer + optional OpenTelemetry capture in Aspire Dashboard) and then assemble a PR-ready summary.
Changes:
- Introduces the
aot-impact-analysisskill orchestrator (SKILL.md) with progressive-disclosure subpages for size, startup/telemetry, and summary writing. - Adds PowerShell scripts to automate size diffing (baseline worktree publish +
sizoscope-cli) and startup timing/telemetry export. - Adds reference documentation for the CLI’s OTLP/exporter environment variable contract and Aspire Dashboard usage.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| .github/skills/aot-impact-analysis/SKILL.md | Skill entry point and “always apply” rules + how to run size/startup. |
| .github/skills/aot-impact-analysis/size-analysis.md | Explains size methodology and how to interpret sizoscope output. |
| .github/skills/aot-impact-analysis/startup-and-telemetry.md | Explains muxer-based startup measurement and Aspire telemetry capture. |
| .github/skills/aot-impact-analysis/writing-the-summary.md | Guidance for composing the PR-ready impact summary. |
| .github/skills/aot-impact-analysis/references/perf-and-otel.md | Documents OTLP env vars and aspire otel query surface. |
| .github/skills/aot-impact-analysis/scripts/Measure-AotSize.ps1 | Automates baseline/PR publish + .mstat diff + Markdown report output. |
| .github/skills/aot-impact-analysis/scripts/Measure-AotStartup.ps1 | Automates managed-vs-AOT timing + optional exporter-on trace capture. |
| .github/skills/aot-impact-analysis/scripts/Start-AspireDashboard.ps1 | Starts Aspire Dashboard via aspire CLI or container fallback. |
| function Find-Native([string]$root, [string]$config, [string]$leaf) { | ||
| if ($leaf -eq 'dotnet-aot.dll') { | ||
| $base = Join-Path $root "artifacts/bin/dotnet-aot/$config" | ||
| } else { | ||
| $base = Join-Path $root "artifacts/obj/dotnet-aot/$config" | ||
| } | ||
| $hit = Get-ChildItem -Path $base -Recurse -Filter $leaf -ErrorAction SilentlyContinue | | ||
| Where-Object { $_.FullName -match 'native' } | Select-Object -First 1 | ||
| if (-not $hit) { throw "Could not find native/$leaf under $base." } | ||
| return $hit.FullName | ||
| } |
| official container image (`mcr.microsoft.com/dotnet/aspire-dashboard`). Either way the dashboard | ||
| exposes: | ||
| * UI http://localhost:18888 | ||
| * OTLP/gRPC http://localhost:4317 (point the CLI's OTEL_EXPORTER_OTLP_ENDPOINT here) | ||
| * OTLP/HTTP http://localhost:4318 |
| Endpoints: UI `http://localhost:18888`, OTLP/gRPC `http://localhost:4317`, | ||
| OTLP/HTTP `http://localhost:4318`. It prefers the `aspire` CLI and falls back to | ||
| the `mcr.microsoft.com/dotnet/aspire-dashboard` container. With the CLI it prints | ||
| a `…/login?t=<token>` URL — pass that whole URL to `aspire otel --dashboard-url`. | ||
|
|
| `Start-AspireDashboard.ps1` runs a standalone dashboard. Default endpoints: | ||
|
|
||
| - UI: `http://localhost:18888` | ||
| - OTLP/gRPC: `http://localhost:4317` -> set `OTEL_EXPORTER_OTLP_ENDPOINT` to this | ||
| - OTLP/HTTP: `http://localhost:4318` | ||
|
|
| Dashboard). All scripts are PowerShell, self-locate the repo root, and use the | ||
| repo-local SDK (`.dotnet/dotnet.exe`); run them from anywhere in the worktree. |
| 2. Adds a **detached git worktree** at the baseline ref beside the repo and | ||
| publishes the same project there, using the current worktree's repo-local SDK | ||
| (`.dotnet/dotnet.exe`). The baseline restore pulls the baseline package set — | ||
| expect a cold restore on first run. |
| function Invoke-Timed([string]$exe, [string]$argline, [hashtable]$env, [int]$count, [int]$warmup) { | ||
| $applied = @{} | ||
| foreach ($k in $env.Keys) { $applied[$k] = [Environment]::GetEnvironmentVariable($k); [Environment]::SetEnvironmentVariable($k, $env[$k]) } | ||
| try { | ||
| $argv = $argline.Split(' ', [StringSplitOptions]::RemoveEmptyEntries) | ||
| for ($i = 0; $i -lt $warmup; $i++) { & $exe @argv *> $null } | ||
| $times = New-Object System.Collections.Generic.List[double] |
Ports the three PowerShell helpers to bash for Linux/macOS shells, keeping the PowerShell versions canonical: - measure-aot-size.sh (<-> Measure-AotSize.ps1) - measure-aot-startup.sh (<-> Measure-AotStartup.ps1) - start-aspire-dashboard.sh (<-> Start-AspireDashboard.ps1) The bash ports mirror the same parameters as --kebab-case flags, write the same Markdown artifacts, and use the same methodology (sizoscope diff vs the fork point; redist-muxer startup timing with DOTNET_CLI_ENABLEAOT; OTLP export to a reachable Aspire Dashboard). Startup percentile math matches the PowerShell implementation; sub-second timing uses bash 5 EPOCHREALTIME or gdate. Scripts are marked executable and pass bash -n. SKILL.md and the subskill pages note the bash forms. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
This file, and the other non-SKILL.md files at the skill root directory, should probably be moved to the references directory as these are on-demand markdown files to supplement the main skill.
| "did startup regress", "profile the AOT entrypoint". | ||
| license: MIT | ||
| metadata: | ||
| portability: repo-local |
|
@mthalman I'm gonna mark this draft - this is waiting on some work from @JeremyKuhne and is pattered off of his jeremykuhne/agent-skills repo so will need more work before it aligns to the SDK repo patterns. |
What
Adds a reusable agent skill,
aot-impact-analysis, that automates the binary-size and startup-performance analysis we run when enabling NativeAOT functionality in the dotnet CLI (e.g. #54970).Structure
Follows a thin-core + subskill-pages layout (modeled on the JeremyKuhne/agent-skills conventions): a small
SKILL.mdthat loads on every trigger, plus sibling pages loaded on demand.SKILL.mdsize-analysis.mddotnet-aot.mstatdiff viasizoscope-clistartup-and-telemetry.mdwriting-the-summary.mdreferences/perf-and-otel.mdaspire otelcommand surfacescripts/Measure-AotSize.ps1,Measure-AotStartup.ps1,Start-AspireDashboard.ps1Notes
aot-size-analysisCI workflow (sizoscope on the per-platformdotnet-aot.mstat, baselined at the fork point).dotnet.exemuxer (DOTNET_CLI_ENABLEAOT), not a standalone host, so it exercises the same dispatch users hit..dotnet/dotnet.exe);SKILL.mdvalidates against.github/skills/ValidateSkill.cs.