Skip to content

Commit

Permalink
[One .NET] Support consuming AOT profiles (#6171)
Browse files Browse the repository at this point in the history
Fixes: #6053

Context: https://github.com/jonathanpeppers/android-profiled-aot

This enables the ability to set:

	<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
	  <RunAOTCompilation>true</RunAOTCompilation>
	  <AndroidEnableProfiledAot>true</AndroidEnableProfiledAot>
	</PropertyGroup>

Add a default `dotnet.aotprofile` which will be passed to the
`<MonoAOTCompiler/>` MSBuild task.

There will not be a way to "record" profiles in the Android workload
in .NET 6. This is because it relies on legacy Mono infrastructure
that is not implemented in .NET 6.

I created a Github repo for recording profiles, where I committed the
necessary binaries such as `aprofutil` and `libmono-profiler-aot.so`:

  * https://github.com/jonathanpeppers/android-profiled-aot

I recorded a `dotnet.aotprofile` with the contents:

	Modules:
	    6799590C-2963-4835-AEDC-20C67D875132 System.Private.CoreLib
	    2CC403AF-60DC-48A9-9B69-FF254277AEA0 Mono.Android
	    92FF7068-2EA9-4681-B340-44E91077417A Java.Interop
	    008C0F24-5014-4D41-AAB9-DDFCEA59E171 Xamarin.Google.Android.Material
	    7CEE6098-BE9F-4043-B35A-B8B0684EF0CB Xamarin.AndroidX.AppCompat
	    20D1FBB8-829A-4618-8E82-8047C8827EA8 Xamarin.AndroidX.Fragment
	    CC363D7A-9CDB-4999-9E10-279412B14A1B Xamarin.AndroidX.Activity
	    21CF52B7-0256-4838-848C-DA026B2F1789 Xamarin.AndroidX.Core
	    D1DE5607-BC27-45FC-93EC-0542C787E5FF Xamarin.AndroidX.DrawerLayout
	Summary:
	    Modules:          9
	    Types:          229
	    Methods:      1,010

`AndroidApp1` is the `Navigation Drawer App` template from "legacy"
Xamarin.Android.  I ported this template to .NET 6 and dropped usage
of Xamarin.Essentials. I thought this was a good target for a default
profile, because of its heavy usage of AndroidX and Google Material.

In a future PR, I will add a default AOT profile for .NET MAUI to be
shipped inside the `maui` workload.

~~ Results ~~

All tests:

 1. Were running on a [Google Pixel 5][0], and
 2. Enabled two architectures, arm64 and x86, and
 3. **JIT time** was average of 10 runs with `-c Release`, no AOT
 4. **AOT time** was average of 10 runs with `-c Release
    -p:RunAOTCompilation=true`, with the`Activity: Displayed` time
 5. **Profiled AOT time** was average of 10 runs with `-c Release
    -p:RunAOTCompilation=true -p:AndroidEnableProfiledAot=true` with
    the `Activity: Displayed` time.

|                                     |    [AndroidApp1][1] |     [MauiApp1][2] |
| ----------------------------------: | ------------------: | ----------------: |
|                JIT startup time (s) |   00:00.4387        | 00:01.4205        |
|          AOT startup time (vs. JIT) |   00:00.3317 ( 76%) | 00:00.7285 ( 51%) |
| Profiled AOT startup time (vs. JIT) |   00:00.3093 ( 71%) | 00:00.7098 ( 50%) |
|                 JIT `.apk` size (B) |    9,155,954        | 17,435,225        |
|           AOT `.apk` size (vs. JIT) |   12,755,672 (139%) | 44,751,651 (257%) |
|  Profiled AOT `.apk` size (vs. JIT) |    9,777,880 (107%) | 23,210,787 (133%) |

[0]: store.google.com/us/product/pixel_5_specs?hl=en-US
[1]: jonathanpeppers/android-profiled-aot@e48c6df/AndroidApp1
[2]: jonathanpeppers/android-profiled-aot@e48c6df/MauiApp1

Co-authored-by: Marek Habersack <grendel@twistedcode.net>
  • Loading branch information
jonathanpeppers and grendello committed Sep 2, 2021
1 parent 8fa383d commit 3e699d6
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 4 deletions.
1 change: 1 addition & 0 deletions build-tools/create-packs/Microsoft.Android.Sdk.proj
Expand Up @@ -76,6 +76,7 @@ core workload SDK packs imported by WorkloadManifest.targets.
<_PackageFiles Include="$(XamarinAndroidSourcePath)src\Xamarin.Android.Build.Tasks\Microsoft.Android.Sdk\Sdk\**" PackagePath="Sdk" />
<_PackageFiles Include="$(XamarinAndroidSourcePath)src\Microsoft.Android.Sdk.ILLink\PreserveLists\**" PackagePath="PreserveLists" />
<_PackageFiles Include="$(XamarinAndroidSourcePath)src\Xamarin.Android.Build.Tasks\Microsoft.Android.Sdk\targets\**" PackagePath="targets" />
<_PackageFiles Include="$(XamarinAndroidSourcePath)src\Xamarin.Android.Build.Tasks\dotnet.aotprofile" PackagePath="targets" />
<_PackageFiles Include="$(IntermediateOutputPath)UnixFilePermissions.xml" PackagePath="data" Condition=" '$(HostOS)' != 'Windows' " />
<None Include="$(MSBuildThisFileDirectory)SignList.xml" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
Expand Down
Expand Up @@ -69,11 +69,13 @@ They run in a context of an inner build with a single $(RuntimeIdentifier).
TempDirectory="$([MSBuild]::EnsureTrailingSlash($(_AotOutputDirectory)))%(FileName)"
AotArguments="$(_AotArguments),temp-path=$([System.IO.Path]::GetFullPath(%(_MonoAOTAssemblies.TempDirectory)))"
/>
<AndroidAotProfile Include="$(MSBuildThisFileDirectory)dotnet.aotprofile" Condition=" '$(AndroidEnableProfiledAot)' == 'true' and '$(AndroidUseDefaultAotProfile)' != 'false' " />
</ItemGroup>
<MakeDir Directories="$(IntermediateOutputPath)aot\;@(_MonoAOTAssemblies->'%(TempDirectory)')" />
<MonoAOTCompiler
Assemblies="@(_MonoAOTAssemblies)"
CompilerBinaryPath="$(_MonoAOTCompilerPath)"
AotProfilePath="@(AndroidAotProfile->'%(FullPath)')"
DisableParallelAot="$(_DisableParallelAot)"
LibraryFormat="So"
Mode="$(AndroidAotMode)"
Expand Down
Expand Up @@ -48,8 +48,8 @@ Copyright (C) 2019 Microsoft Corporation. All rights reserved.
DependsOnTargets="$(_BeginAotProfilingDependsOnTargets)">
</Target>
<Target Name="FinishAotProfiling"
DependsOnTargets="_ResolveSdks">
DependsOnTargets="_ResolveSdks;_ResolveMonoAndroidSdks">
<Exec Command="&quot;$(AdbToolPath)adb&quot; $(AdbTarget) forward tcp:$(AndroidAotProfilerPort) tcp:$(AndroidAotProfilerPort)" />
<Exec Command="&quot;$(MonoAndroidBinDirectory)aprofutil&quot; $(AProfUtilExtraOptions) -s -v -p $(AndroidAotProfilerPort) -o &quot;$(AndroidAotCustomProfilePath)&quot;" />
<Exec Command="&quot;$(AProfUtilToolPath)aprofutil&quot; $(AProfUtilExtraOptions) -s -v -p $(AndroidAotProfilerPort) -o &quot;$(AndroidAotCustomProfilePath)&quot;" />
</Target>
</Project>
Expand Up @@ -727,6 +727,11 @@ because xbuild doesn't support framework reference assemblies.
/>
</CreateProperty>

<!-- We should slowly port all the <CreateProperty/> calls to <PropertyGroup/> here -->
<PropertyGroup>
<AProfUtilToolPath Condition=" '$(AProfUtilToolPath)' == '' ">$(MonoAndroidBinDirectory)</AProfUtilToolPath>
</PropertyGroup>

<!-- Get the defined constants for this API Level -->
<GetAndroidDefineConstants AndroidApiLevel="$(_AndroidApiLevel)" ProductVersion="$(MonoAndroidVersion)">
<Output TaskParameter="AndroidDefineConstants" ItemName="AndroidDefineConstants" />
Expand Down
Binary file added src/Xamarin.Android.Build.Tasks/dotnet.aotprofile
Binary file not shown.
48 changes: 46 additions & 2 deletions src/monodroid/jni/monodroid-glue.cc
Expand Up @@ -1582,8 +1582,52 @@ MonodroidRuntime::set_profile_options ()
value.assign (prop_value);
}

// setenv(3) makes copies of its arguments
setenv ("DOTNET_DiagnosticPorts", value.get (), 1);
// NET6+ supports only the AOT Mono profiler, if the prefix is absent or different than 'aot:' we consider the
// property to contain value for the dotnet tracing profiler.
constexpr char AOT_PREFIX[] = "aot:";
if (!value.starts_with (AOT_PREFIX)) {
// setenv(3) makes copies of its arguments
setenv ("DOTNET_DiagnosticPorts", value.get (), 1);
return;
}

constexpr char OUTPUT_ARG[] = "output=";
constexpr size_t OUTPUT_ARG_LEN = sizeof(OUTPUT_ARG) - 1;
constexpr size_t start_index = sizeof(AOT_PREFIX); // one char past ':'

dynamic_local_string<SENSIBLE_PATH_MAX> output_path;
bool have_output_arg = false;
string_segment param;

while (value.next_token (start_index, ',', param)) {
dynamic_local_string<SENSIBLE_PATH_MAX> temp;
temp.assign (param.start (), param.length ());
if (!param.starts_with (OUTPUT_ARG)) {
continue;
}

output_path.assign (param.start () + OUTPUT_ARG_LEN, param.length () - OUTPUT_ARG_LEN);
have_output_arg = true;
break;
}

if (!have_output_arg) {
constexpr char PROFILE_FILE_NAME_PREFIX[] = "profile.";
constexpr char AOT_EXT[] = "aotprofile";

output_path
.assign_c (androidSystem.get_override_dir (0))
.append (MONODROID_PATH_SEPARATOR)
.append (PROFILE_FILE_NAME_PREFIX)
.append (AOT_EXT);

value
.append (OUTPUT_ARG)
.append (output_path.get (), output_path.length ());
}

log_warn (LOG_DEFAULT, "Initializing profiler with options: %s", value.get ());
debug.monodroid_profiler_load (androidSystem.get_runtime_libdir (), value.get (), output_path.get ());
}
#else // def NET6
inline void
Expand Down

0 comments on commit 3e699d6

Please sign in to comment.