Skip to content

Commit fd6d5fd

Browse files
authored
[Docs][tests] Add Mono Profiled AOT Functional Test and doc (#90959)
* [Android][Test] Add Profiled AOT Functional Test * [docs][mono] Add profiled aot on mono docs * Address feedback * Attempt to fix build * Profile only with .mibc
1 parent 0c4329b commit fd6d5fd

File tree

9 files changed

+112
-0
lines changed

9 files changed

+112
-0
lines changed

docs/design/mono/profiled-aot.md

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
Profiled Ahead-Of-Time Compilation on Mono
2+
===
3+
4+
# Background
5+
6+
Mobile applications built using .NET typically leverage the Mono runtime to load and execute native machine code. The native machine code is generated from common intermediate language (CIL) assemblies using the Mono compiler with a variety of compilation strategies available including ahead-of-time (AOT) compilation, just-in-time (JIT) compilation, and interpreter. In addition to these strategies, .NET 7 introduced Profiled Ahead-Of-Time Compilation on Mono, a combination of AOT compilation and profile-guided-optimization (PGO) that leverages "profiles" to select which CIL code to AOT rather than an all-or-nothing approach. These profiles are obtained through [tracing](https://github.com/dotnet/runtime/blob/main/docs/design/mono/diagnostics-tracing.md) previous runs of an application, and the resulting trace is analyzed by the [dotnet-pgo tool](https://github.com/dotnet/runtime/blob/main/docs/design/features/dotnet-pgo.md) to generate a profile that tells the Mono AOT Compiler which methods to AOT.
7+
8+
# How it works
9+
10+
The advantages of Profiled AOT stem from its flexibility to AOT select code paths, leaving the rest to be compiled on the fly by the JIT compiler or Mono Interpreter. With an analysis of an application's trace, a record capturing a sequence of events during the application's execution, profiles can be generated to tailor optimizations for each application and environment. For example, profiles may target frequently executed (hot) code paths, minimizing the amount of runtime compilations and reducing application size, which are especially important in environments where full AOT compilation would strain storage space. Moreover, profiles may target startup code to optimize startup performance.
11+
12+
Within .NET, traces can be collected by [diagnostic tooling](https://learn.microsoft.com/en-us/dotnet/core/diagnostics/eventpipe#tools-that-use-eventpipe) that use the [EventPipe](https://learn.microsoft.com/en-us/dotnet/core/diagnostics/eventpipe) runtime component. [Existing diagnostic tooling only supports `NamedPipes`/`UnixDomainSockets`](https://github.com/dotnet/runtime/blob/main/docs/design/mono/diagnostics-tracing.md), so the [diagnostics tool dotnet-dsrouter](https://learn.microsoft.com/en-us/dotnet/core/diagnostics/dotnet-dsrouter) is required to bridge the EventPipe-based diagnostic tooling with .NET applications on mobile platforms and other remote sandboxed environments.
13+
14+
Events collected by EventPipe-based diagnostic tooling are emitted with a `.nettrace` file format. Among the [various events supported by Mono runtime](https://github.com/dotnet/runtime/blob/main/src/mono/mono/eventpipe/gen-eventing-event-inc.lst), [method jitting and method loading](https://github.com/dotnet/runtime/blob/096b2499fe6939d635c35edaa607a180eb578fbb/src/mono/mono/eventpipe/gen-eventing-event-inc.lst#L39-L41) are crucial to [inform the Mono AOT Compiler what methods to AOT](https://github.com/dotnet/runtime/blob/6b67caaedfbfeaf7707478e50ccc9e8bc929e591/src/mono/mono/mini/aot-compiler.c#L13818-L13880). To collect a trace containing such events, it is imperative that dotnet-trace is provided either the appropriate [event provider](https://learn.microsoft.com/en-us/dotnet/core/diagnostics/well-known-event-providers) with [keyword flags](https://github.com/dotnet/runtime/blob/c59aef7622c9a2499abb1b7d262ed0c90f4b0c7f/src/coreclr/vm/ClrEtwAll.man#L14-L92) through `--providers` or the appropriate list of keywords through `--clrevents`. That way, the [events relevant to the keywords are captured](https://github.com/dotnet/runtime/blob/c59aef7622c9a2499abb1b7d262ed0c90f4b0c7f/src/coreclr/vm/ClrEtwAll.man#L3133). In the example workflows below, `--providers Microsoft-Windows-DotNETRuntime:0x1F000080018:5` is used.
15+
16+
Profiles [ingested by the Mono AOT Compiler](https://github.com/dotnet/runtime/blob/6b67caaedfbfeaf7707478e50ccc9e8bc929e591/src/tasks/AotCompilerTask/MonoAOTCompiler.cs#L174) are generated through .NET runtime's [`dotnet-pgo` tool](https://github.com/dotnet/runtime/blob/main/docs/design/features/dotnet-pgo.md). As such, profiles passed to the Mono AOT Compiler are expected to adhere to the [`.mibc` file format](https://github.com/dotnet/runtime/blob/main/src/coreclr/tools/dotnet-pgo/dotnet-pgo-experiment.md#mibc-file-format). The Mono AOT Compiler [reads `.mibc` profiles](https://github.com/dotnet/runtime/blob/c59aef7622c9a2499abb1b7d262ed0c90f4b0c7f/src/mono/mono/mini/aot-compiler.c#L14085-L14162) to determine [which methods to AOT](https://github.com/dotnet/runtime/blob/6b67caaedfbfeaf7707478e50ccc9e8bc929e591/src/mono/mono/mini/aot-compiler.c#L13818-L13880) when compiling CIL assemblies.
17+
18+
# Example Workflows
19+
20+
## Android -- Running through the [Android Profiled AOT Functional Test](https://github.com/dotnet/runtime/tree/main/src/tests/FunctionalTests/Android/Device_Emulator/AOT_PROFILED)
21+
22+
### Requirements:
23+
- [Prerequisites](https://github.com/dotnet/runtime/blob/main/docs/workflow/testing/libraries/testing-android.md#prerequisites)
24+
- [Building mono and libs](https://github.com/dotnet/runtime/blob/main/docs/workflow/testing/libraries/testing-android.md#building-libs-and-tests-for-android)
25+
- [dotnet-dsrouter](https://learn.microsoft.com/en-us/dotnet/core/diagnostics/dotnet-dsrouter)
26+
- [dotnet-trace](https://learn.microsoft.com/en-us/dotnet/core/diagnostics/dotnet-trace)
27+
28+
### Tracing (if not using provided .nettrace/.mibc files)
29+
(informational) [Understanding diagnostics_tracing runtime component](https://github.com/dotnet/runtime/blob/main/docs/design/mono/diagnostics-tracing.md)
30+
31+
1. Startup dotnet-dsrouter to bridge device/emulator with diagnostic tooling either in a separate window or launch background instance with a `&` at the end.
32+
```C#
33+
dotnet-dsrouter client-server -tcps 127.0.0.1:9001 -ipcc ~/myport --verbose debug
34+
```
35+
36+
2. Startup dotnet-trace tool to collect a .nettrace in a separate window
37+
```C#
38+
dotnet-trace collect --providers Microsoft-Windows-DotNETRuntime:0x1F000080018:5 --diagnostic-port ~/myport
39+
```
40+
41+
3. Run the Android application enabling `RuntimeComponents` + `DiagnosticPorts` and disabling `NetTraceFilePath` + `ProfiledAOTProfilePaths` in the `.csproj`. These properties are consumed in the Android [build](https://github.com/dotnet/runtime/blob/main/src/mono/msbuild/android/build/AndroidBuild.targets).
42+
```Shell
43+
./dotnet.sh build /t:Test /p:TargetOS=android /p:TargetArchitecture=arm64 /p:Configuration=Debug src/tests/FunctionalTests/Android/Device_Emulator/AOT_PROFILED/Android.Device_Emulator.Aot_Profiled.Test.csproj
44+
```
45+
46+
### Profiled AOT
47+
48+
1. Run the Android application supplying either the default or your own `.nettrace file` in `NetTraceFilePath` and/or `.mibc files` in `ProfiledAOTProfilePaths` and disabling `RuntimeComponents` + `DiagnosticPorts` in the `.csproj`. These properties are consumed in the Android [build](https://github.com/dotnet/runtime/blob/main/src/mono/msbuild/android/build/AndroidBuild.targets).
49+
```Shell
50+
./dotnet.sh build /t:Test /p:TargetOS=android /p:TargetArchitecture=arm64 /p:Configuration=Debug src/tests/FunctionalTests/Android/Device_Emulator/AOT_PROFILED/Android.Device_Emulator.Aot_Profiled.Test.csproj
51+
```

src/libraries/tests.proj

+12
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,13 @@
238238
<ProjectExclusions Include="$(RepoRoot)\src\tests\FunctionalTests\Android\Device_Emulator\AOT\Android.Device_Emulator.Aot.Test.csproj" />
239239
</ItemGroup>
240240

241+
<ItemGroup Condition="'$(TargetOS)' == 'android'">
242+
<ProjectExclusions Include="$(MSBuildThisFileDirectory)*/tests/**/*.Tests.csproj" />
243+
<ProjectExclusions Include="$(RepoRoot)/src/tests/FunctionalTests/**/*.Test.csproj" />
244+
<ProjectExclusions Include="$(RepoRoot)/src/mono/sample/Android/AndroidSampleApp.csproj" />
245+
<ProjectExclusions Remove="$(RepoRoot)/src/tests/FunctionalTests/Android/Device_Emulator/AOT_PROFILED/Android.Device_Emulator.Aot_Profiled.Test.csproj" />
246+
</ItemGroup>
247+
241248
<ItemGroup Condition="'$(TargetOS)' == 'ios' and '$(RunDisablediOSTests)' != 'true'">
242249
<ProjectExclusions Include="$(MSBuildThisFileDirectory)*\tests\**\*.Tests.csproj" />
243250
</ItemGroup>
@@ -629,6 +636,11 @@
629636
BuildInParallel="false" />
630637
</ItemGroup>
631638

639+
<ItemGroup Condition="'$(ArchiveTests)' == 'true' and '$(TargetOS)' == 'android'">
640+
<ProjectReference Include="$(RepoRoot)\src\tests\FunctionalTests\Android\Device_Emulator\AOT_PROFILED\**\*.Test.csproj"
641+
Exclude="@(ProjectExclusions)" />
642+
</ItemGroup>
643+
632644

633645
<ItemGroup Condition="'$(ArchiveTests)' == 'true' and ('$(TargetOS)' == 'ios' or '$(TargetOS)' == 'tvos') and '$(UseNativeAOTRuntime)' == 'true'">
634646
<ProjectReference Include="$(RepoRoot)\src\tests\FunctionalTests\$(TargetOS)\Device\**\*.Test.csproj"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<OutputType>Exe</OutputType>
4+
<MonoForceInterpreter>false</MonoForceInterpreter>
5+
<RunAOTCompilation>true</RunAOTCompilation>
6+
<AOTWithLibraryFiles>true</AOTWithLibraryFiles>
7+
<TestRuntime>true</TestRuntime>
8+
<TargetFramework>$(NetCoreAppCurrent)</TargetFramework>
9+
<MainLibraryFileName>Android.Device_Emulator.Aot_Profiled.Test.dll</MainLibraryFileName>
10+
<ExpectedExitCode>42</ExpectedExitCode>
11+
<EnableAggressiveTrimming>true</EnableAggressiveTrimming>
12+
</PropertyGroup>
13+
14+
<!-- Tracing -->
15+
<PropertyGroup>
16+
<!-- <RuntimeComponents>diagnostics_tracing</RuntimeComponents> -->
17+
<!-- <DiagnosticPorts>127.0.0.1:9000,suspend</DiagnosticPorts> -->
18+
</PropertyGroup>
19+
20+
<!-- Profiled AOT with .nettrace -->
21+
<PropertyGroup>
22+
<!-- <NetTraceFilePath Condition="'$(Configuration)' == 'Release'">$(MSBuildThisFileDirectory)\test_release.nettrace</NetTraceFilePath> -->
23+
<!-- <NetTraceFilePath Condition="'$(Configuration)' == 'Debug'">$(MSBuildThisFileDirectory)\test_debug.nettrace</NetTraceFilePath> -->
24+
</PropertyGroup>
25+
26+
<!-- Profiled AOT with .mibc-->
27+
<PropertyGroup>
28+
<ProfiledAOTProfilePaths Condition="'$(Configuration)' == 'Release'">$(MSBuildThisFileDirectory)\test_release.mibc</ProfiledAOTProfilePaths>
29+
<ProfiledAOTProfilePaths Condition="'$(Configuration)' == 'Debug'">$(MSBuildThisFileDirectory)\test_debug.mibc</ProfiledAOTProfilePaths>
30+
</PropertyGroup>
31+
32+
<ItemGroup>
33+
<Compile Include="Program.cs" />
34+
</ItemGroup>
35+
</Project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
6+
public static class Program
7+
{
8+
public static int Main()
9+
{
10+
Console.WriteLine("Hello, Android!"); // logcat
11+
return 42;
12+
}
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
See [Profiled Ahead-Of-Time Compilation on Mono](/docs/design/mono/profiled-aot.md#android----running-through-the-android-profiled-aot-functional-test)

0 commit comments

Comments
 (0)