feat: add maui profile command for Android startup tracing#60
Draft
simonrozsival wants to merge 3 commits intodotnet:mainfrom
Draft
feat: add maui profile command for Android startup tracing#60simonrozsival wants to merge 3 commits intodotnet:mainfrom
maui profile command for Android startup tracing#60simonrozsival wants to merge 3 commits intodotnet:mainfrom
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #54
Summary
Adds a new
maui profilecommand that collects a startup.nettracefor a .NET MAUI Android app usingdotnet-trace+dotnet-dsrouter, both invoked viadnxso no pre-installation is required.How it works
Two-phase build approach:
dotnet build)dotnet build -t:RunwithDiagnosticSuspend=true)Tool invocation via
dnx:dnx -y dotnet-dsrouter -- android-emu(orandroidfor physical devices)pid=<N>to stdout on startup — we parse that to get the PIDdnx -y dotnet-trace -- collect --process-id <pid>dotnet tool installrequired; always uses the latest published versionAuto-stop support via
Microsoft.Maui.StartupProfiling:ProjectReference, callStartupProfilingMarker.Complete()at logical startup end[ModuleInitializer]+ EventSource (Microsoft.Maui.StartupProfiling, eventStartupComplete)--stopping-event-provider-name Microsoft.Maui.StartupProfiling --stopping-event-event-name StartupCompleteto auto-stop the traceKey technical notes
--stopping-event-provider-nameonly configures the stop condition — the provider must also be in--providersfor EventPipe to actually deliver events. The command handles this automatically.cpu-samplingprofile is Linux-only in dotnet-trace 9+;dotnet-common,dotnet-sampled-thread-timeis the EventPipe equivalent that works with dsrouter.--providersarg suppresses dotnet-trace's implicit defaults, so we explicitly injectdotnet-common,dotnet-sampled-thread-timewhen a stopping event is configured.Testing
Open the resulting
.nettracein PerfView or Visual Studio Performance Profiler.