docs/design/mono/profiled-aot.md
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 previous runs of an application, and the resulting trace is analyzed by the dotnet-pgo tool to generate a profile that tells the Mono AOT Compiler which methods to AOT.
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.
Within .NET, traces can be collected by diagnostic tooling that use the EventPipe runtime component. Existing diagnostic tooling only supports NamedPipes/UnixDomainSockets, so the diagnostics tool dotnet-dsrouter is required to bridge the EventPipe-based diagnostic tooling with .NET applications on mobile platforms and other remote sandboxed environments.
Events collected by EventPipe-based diagnostic tooling are emitted with a .nettrace file format. Among the various events supported by Mono runtime, method jitting and method loading are crucial to inform the Mono AOT Compiler what methods to AOT. To collect a trace containing such events, it is imperative that dotnet-trace is provided either the appropriate event provider with keyword flags through --providers or the appropriate list of keywords through --clrevents. That way, the events relevant to the keywords are captured. In the example workflows below, --providers Microsoft-Windows-DotNETRuntime:0x1F000080018:5 is used.
Profiles ingested by the Mono AOT Compiler are generated through .NET runtime's dotnet-pgo tool. As such, profiles passed to the Mono AOT Compiler are expected to adhere to the .mibc file format. The Mono AOT Compiler reads .mibc profiles to determine which methods to AOT when compiling CIL assemblies.
The Mono AOT Compiler can directly ingest .mibc profiles to AOT compile methods contained within the profile. As the Mono AOT Compiler already had logic to AOT compile profile methods (from the legacy mono profiler), resolving MonoMethods from the .mibc profile and adding them for compilation was sufficient.
As the .mibc profile is a Portable Executable (PE) file, the Mono AOT Compiler leverages several mono methods to resolve the profile data as MonoMethods by:
.mibc profile as a MonoImage to load the AssemblyDictionary as a MonoMethod.AssemblyDictionary's IL instructions to discover tokens corresponding to mibcGroupMethods within the profile.mibcGroupMethod discovered as a MonoMethod.mibcGroupmethod's IL instructions to discover tokens corresponding to method/type tokens within the mibcGroupMethod.MethodRef and MethodSpec tokens as MonoMethods corresponding to the actual method to be profile AOT'd, and inserting them into the profile methods hash table.(informational) Understanding diagnostics_tracing runtime component
& at the end.dotnet-dsrouter client-server -tcps 127.0.0.1:9001 -ipcc ~/myport --verbose debug
dotnet-trace collect --providers Microsoft-Windows-DotNETRuntime:0x1F000080018:5 --diagnostic-port ~/myport
RuntimeComponents + DiagnosticPorts and disabling NetTraceFilePath + ProfiledAOTProfilePaths in the .csproj. These properties are consumed in the Android build../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
.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../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