feat: support Android and iOS simulator startup profiling in maui profile#60
Conversation
Adds a new top-level `maui profile` command that collects a startup .nettrace for a .NET MAUI Android app using dotnet-trace + dotnet-dsrouter. ## What's new ### `maui profile` command (ProfileCommand.cs) - Two-phase build: compile-only phase 1, then deploy+launch in phase 2 so the APK is built once and the trace collector starts before the app. - Starts dotnet-trace with `--dsrouter android-emu` (emulator) or `--dsrouter android` (physical device) for startup tracing. - Passes `DiagnosticSuspend=true` and `--resume-runtime` so the beginning of app startup is never missed. - Supports `--stopping-event-provider-name` / `--stopping-event-event-name` for automatic stop when the app signals startup is complete. - Automatically injects `dotnet-common,dotnet-sampled-thread-time` profiles alongside the stopping event provider so runtime and CPU-sampling events are still collected (specifying `--providers` alone would suppress the dotnet-trace defaults). - Clears inherited MSBuild SDK env vars before spawning child builds to prevent SDK version pollution when invoked via `dotnet run`. - Resolves macOS `/tmp` symlinks to avoid MAUI SourceGen MAUIG1001 errors. ### `Microsoft.Maui.StartupProfiling` helper package - Tiny opt-in assembly: add the NuGet reference and call `StartupProfilingMarker.Complete()` at the logical end of startup. - `[ModuleInitializer]` pre-registers the EventSource provider so dotnet-trace sees it before any user code runs. - `MAUI_STARTUP_PROFILING_AUTO_EXIT=1` env var causes the app to call `Environment.Exit(0)` after emitting the marker — useful in CI. - `IsProfilingSession` property lets apps skip work that skews traces. ### ProcessRunner changes - Added `environmentVariablesToRemove` parameter to strip inherited env vars before spawning subprocesses. ### Diagnostic improvements - `SpectreOutputFormatter` now shows native error output in error messages. - New error codes for prerequisite and config validation failures. ## Key technical notes - `--profile cpu-sampling` is incompatible with `--dsrouter` (Linux kernel perf only); `dotnet-sampled-thread-time` uses EventPipe and works. - `--stopping-event-provider-name` configures the stop condition but does NOT add the provider to the EventPipe session; `--providers` must also include it explicitly for events to be delivered. - Default collection (dotnet-common + dotnet-sampled-thread-time) must be injected explicitly whenever `--providers` is specified, because any `--providers` arg suppresses the implicit defaults. Closes dotnet#54 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…SDK) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
eng/Common.props packs the repo-root README into every package at '/README.md'. The StartupProfiling project also includes its own README at the same path, causing NU5118 (treated as error in CI via --ci). Suppress NU5118 so the package-specific README is used. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds an Android-first maui profile workflow to the CLI, including a build-time injected startup marker helper and orchestration of dotnet-dsrouter + dotnet-trace for startup tracing output (nettrace / speedscope).
Changes:
- Introduces a new
profiletop-level CLI command with Android device selection, Release-by-default builds, and trace collection orchestration. - Adds a new
Microsoft.Maui.StartupProfilinghelper package plus MSBuild injection assets to auto-register an EventSource and emit a startup-complete marker. - Improves CLI error presentation by printing captured native/tool output when available, and extends ProcessRunner to remove inherited environment variables.
Reviewed changes
Copilot reviewed 15 out of 15 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/Cli/Microsoft.Maui.StartupProfiling/StartupProfilingMarker.cs | Adds public marker API, module initializer, diagnostics logging, and exit-control channel logic. |
| src/Cli/Microsoft.Maui.StartupProfiling/StartupProfilingEventSource.cs | Adds EventSource provider and events used for stopping-event integration. |
| src/Cli/Microsoft.Maui.StartupProfiling/README.md | Documents helper package usage and environment variables. |
| src/Cli/Microsoft.Maui.StartupProfiling/Microsoft.Maui.StartupProfiling.csproj | New packable helper library project for the injected marker. |
| src/Cli/Microsoft.Maui.Cli/Utils/ProcessRunner.cs | Adds support for removing inherited environment variables before process start. |
| src/Cli/Microsoft.Maui.Cli/Program.cs | Registers the new profile command at the CLI root. |
| src/Cli/Microsoft.Maui.Cli/Output/SpectreOutputFormatter.cs | Displays NativeError details under CLI errors when present. |
| src/Cli/Microsoft.Maui.Cli/Microsoft.Maui.Cli.csproj | References the helper project and ships MSBuild injection assets alongside the tool. |
| src/Cli/Microsoft.Maui.Cli/Errors/ErrorCodes.cs | Adds a new diagnostics tooling error code. |
| src/Cli/Microsoft.Maui.Cli/Commands/ProfileCommand.cs | Implements the maui profile command, device/TFM/format resolution, and trace/dsrouter orchestration. |
| src/Cli/Microsoft.Maui.Cli/Build/MauiStartupProfilingInjection.targets | MSBuild targets to inject the helper assembly/source and Android env vars into the app build. |
| src/Cli/Microsoft.Maui.Cli/Build/MauiStartupProfiling.AutoInitialize.cs | Injected bootstrap that detects first UI readiness and signals startup complete. |
| src/Cli/Microsoft.Maui.Cli.UnitTests/ProfileCommandTests.cs | Adds unit tests for option defaults, argument building, and resolver behaviors. |
| src/Cli/Cli.slnf | Adds the new helper project to the CLI solution filter. |
| MauiLabs.slnx | Adds the new helper project to the repo solution. |
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add elapsed timers to Spectre status spinners, route cancellations through a shared handler so Ctrl+C reports as Cancelled, and keep trace stderr quiet unless verbose mode is enabled. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Enable iOS simulator device discovery and startup tracing in the profile command, add retry handling for iOS diagnostics startup races, and default simulator runs to Debug because it produces reliable traces while Release remains experimental. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Restore Release as the default iOS profiling configuration and prefer installed dotnet-trace/dotnet-dsrouter tools when available so simulator tracing follows the MAUI guidance again. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Allow maui profile validation to accept setups where one required diagnostics tool is installed globally and the other is resolved from the NuGet cache, matching the actual runtime resolution behavior. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
maui profile command for Android startup tracingmaui profile command for startup tracing
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
maui profile command for startup tracingCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jonathanpeppers
left a comment
There was a problem hiding this comment.
Simplification suggestions for the profiling commands:
-
Use dotnet-trace --dsrouter android|android-emu|ios|ios-sim instead of manually launching dotnet-dsrouter as a separate process. This should allow removing DotnetDsrouterRunner.cs, ProfileTransportConfiguration, the server-server/server-client branching in ResolveProfileTransport(), dsrouter PID tracking, and the StartTraceAfterLaunch retry logic that differs between Android and iOS.
-
Drop -p:AndroidEnableProfiler=true — the code already passes -p:EnableDiagnostics=true (cross-platform) in AppendDiagnosticArguments, so the Android-specific property in BuildLaunchArguments is redundant.
-
Use -p:Device={device.Id} instead of the platform-specific -p:AdbTarget=-s {device.Id} (Android) and -p:_DeviceName=:v2:udid={device.Id} (iOS). -p:Device is cross-platform and initializes the platform-specific properties automatically.
Use runtime-owned EventPipe for Android/CoreCLR startup runs, simplify the attach path with dotnet-trace --dsrouter, and align the flow with the verified TestDummy MIBC results. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Resolve device-manager conflicts and keep the startup profiling changes aligned with the latest main branch updates. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Closes #54
Summary
This PR adds a new
maui profile startupflow for collecting startup traces from MAUI apps.The goal is to make startup profiling easy to use from the CLI: build the app, launch it on the selected target, collect the trace, and save the result in a format you can inspect right away.
How to use it
Interactive:
Similarly to
dotnet run, this will show pickers for the TFM, target device and the output format.Android:
iOS simulator:
What this PR adds
maui profile startupsupport for MAUI app startup tracesnettraceandspeedscopeoutput optionsNotes