Fix MAUI Android Inner Loop startup measurement to use logcat Displayed time#5184
Closed
davidnguyen-tech wants to merge 15 commits intonguyendav/maui-android-innerloopfrom
Closed
Fix MAUI Android Inner Loop startup measurement to use logcat Displayed time#5184davidnguyen-tech wants to merge 15 commits intonguyendav/maui-android-innerloopfrom
davidnguyen-tech wants to merge 15 commits intonguyendav/maui-android-innerloopfrom
Conversation
TargetFrameworks and SupportedOSPlatformVersion are now defined in the .proj PropertyGroup where all build configuration is visible. setup_helix.py just passes through PERFLAB_MSBUILD_ARGS unchanged. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove PERFLAB_MSBUILD_ARGS env var from setup_helix.py. The .proj now passes _MSBuildArgs directly to both setup_helix.py (for workload/restore) and test.py (for build) through their own argument contracts. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Environment variables set via os.environ in Python don't persist across && shell chains. Move DOTNET_ROOT, PATH, ANDROID_HOME, JAVA_HOME, and other env vars to the .proj PreCommands where set/export makes them available to all chained commands. Uses ;-separated PreCommands format consistent with the Helix SDK convention (DotNetCli.targets, XHarnessRunner.targets). Windows PATH separators escaped as %3B to avoid being split as command separators. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The --edit-src and --edit-dest values contain semicolons that bash interprets as command separators on Linux, truncating the test.py command line. Quoting these values fixes the emulator job failures. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The Helix SDK decodes %3B in $(HelixPreCommands) but not in per-work-item <PreCommands> metadata. On Windows, this caused PATH to contain literal %3B instead of semicolons, breaking tool resolution. Follow the same pattern as DotNetCli.targets and XHarnessRunner.targets. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
!$(IsPosixShell) fails with MSB4100 when the property is empty. Use quoted string comparison instead: '$(IsPosixShell)' == 'true' Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Extract setup_helix.py invocation from the chained Command (setup_helix.py && test.py) into a dedicated <PreCommands> element for each HelixWorkItem. This leverages the Helix SDK's execution order — PreCommands runs before Command in the same shell session — giving clearer separation of setup vs. test execution. The setup_helix.py call contains no semicolons, so there is no %3B encoding concern for per-item PreCommands. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The Helix SDK's AddDotNetSdk target (triggered by IncludeXHarnessCli) appends DOTNET_ROOT and PATH pointing to .NET 8.0 during target execution. When our env var overrides were in a PropertyGroup, they were evaluated during property evaluation (earlier), so the SDK's values won — last set/export wins. Moving the env var exports into a Target with AfterTargets="AddXHarnessCli" ensures our .NET 11 SDK paths are appended after the SDK's .NET 8.0 paths, so our values take precedence. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…Targets Having both BeforeTargets="CoreTest" and AfterTargets="AddXHarnessCli" causes MSBuild to schedule the target through BeforeTargets import order, which places it BEFORE AddDotNetSdk. The result is that AddDotNetSdk's .NET 8.0 env vars come after ours and win. Removing BeforeTargets="CoreTest" forces MSBuild to schedule purely through the AfterTargets chain, guaranteeing it runs after both AddDotNetSdk and AddXHarnessCli. It still runs before CoreTest because AddXHarnessCli itself has BeforeTargets="CoreTest". Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…caping Move env var exports (DOTNET_ROOT, PATH, ANDROID_HOME, etc.) from the OverrideDotnetCliRoot MSBuild Target into per-item <PreCommands> metadata on each HelixWorkItem. Per-item PreCommands run AFTER $(HelixPreCommands) in the same shell session, so they naturally override the Helix SDK's AddDotNetSdk values without needing Target ordering (AfterTargets). For Windows PATH values, use ;; (double semicolons) which the Helix SDK's SplitCommands() method treats as literal semicolons (single ; is a command separator). Linux PATH uses : as separator so no escaping is needed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…adability Move the long inline env var strings from per-item <PreCommands> into _WindowsEnvVars and _LinuxEnvVars MSBuild properties. This improves readability and fixes an ordering bug: env vars now come BEFORE setup_helix.py so that PATH (including adb) is available when setup_helix.py runs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…guarantee Switch measure_startup() from am-start stdout TotalTime/WaitTime to logcat Displayed time as the primary timing source, matching the proven DEVICESTARTUP pattern. The old approach captured time to initial window draw (runtime-agnostic, ~3s), while logcat Displayed time captures full app rendering including framework initialization (runtime-dependent, Mono ~6s vs CoreCLR ~9s). Also fix cold start guarantee: remove -S flag from am start-activity, add separate force-stop + 3s delay before each start, and add LaunchState: COLD verification. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add --startup-iterations CLI argument (default=3) for configurable multi- iteration startup measurement. Each first-deploy now captures 3 startup data points for statistical reliability. Incremental iterations keep 1 measurement per cycle (the incremental loop itself provides multiple points). Add post-startup runtime validation that checks logcat for Mono/CoreCLR markers and logs whether the expected runtime loaded (diagnostic only). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Make logcat grep commands tolerant of non-zero exit codes (grep exits 1 when no matches found, which would crash RunCommand before fallback logic could execute). Add WaitTime as secondary fallback after TotalTime for Android 14+ compatibility where TotalTime may be absent. 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.
Problem
Mono and CoreCLR startup times were nearly identical
Root Cause
The previous implementation used
am start -Wstdout TotalTime/WaitTime which captures only the initial window draw time. This is runtime-agnostic and doesn't reflect the full app rendering, which is where runtime differences manifest. Additionally, there was no cold start guarantee.