We’re pleased to announce the support for .NET Profile Guided AOT (PG-AOT) for the Uno Platform, which allows the creation of faster and smaller apps. When compared with the Full AOT support we’ve added support for last year, the package size is cut in half. It provides better performance with the Mixed Mode support we announced support for earlier by making a smarter use of the IL Interpreter.
We’ve updated the Uno Calculator, the Uno Playground, the XAML Controls Gallery, the RayTracer benchmark and the Roslyn Quoter applications using PG-AOT. These size improvements allow for these apps to run on Safari for iOS.
About Uno Platform
For those new to Uno Platform – it enables for creation of single-source C# and XAML apps which run natively on iOS and Android, macOS and Web via WebAssembly. Uno Platform is Open Source (Apache 2.0) and available on GitHub. To learn more about Uno Platform, see how it works, or create a small sample app.
What is .NET AOT ?
The .NET runtime supports three modes of execution:
- Interpreter, where the .NET assemblies are executed IL opcode by opcode using a WebAssembly compiled interpreter, as WebAssembly does not yet support JIT (Just in Time) compilation. This allows for a very small package size as there is only the .NET runtime and original assemblies to be transferred over the wire to the browser. But this mode is also quite slow, as the runtime must interpret every IL opcode present in the app’s assemblies. It’s generally 30 times slower than WebAssembly compiled code.
- Full Ahead of Time (AOT) compiled code, where the.NET assemblies are compiled down to actual WebAssembly bytecode. In this mode, there’s no more IL code to execute, and assemblies are stripped of their method bodies. The generated code is a lot faster to execute than through the interpreter but is also very large.
- Mixed Mode, which takes a balanced approach to generate AOT code for parts of the application and use the interpreter for others. This approach allows to reduce the package size significantly while keeping important parts of the application performant.
Up until recently, the Mixed Mode was having the ability to choose which part of the code to compile to WebAssembly at the assembly level. This meant that for application that used a small portion of an assembly and wanted to have good performance, the whole assembly had to be AOT compiled as well.
This could cause lots of trouble to run on Safari for iOS, as there’s a hard limit on the size of WebAssembly modules that can be loaded.
Introducing Profile Guided AOT (PG-AOT)
This compilation and runtime mode allow for the AOT engine to selectively optimize methods to WebAssembly by recording which methods are used, and keep the rest as interpreted. This gives a very good balance when choosing between performance and payload size. It also has the advantage of reducing the build time, as less code needs to be compiled down to WebAssembly.
This feature is used in two passes:
- The first pass needs the creation of a profiled interpreter build, which records any methods invoked during the profiling session.
- The second pass rebuilds the application using the Mixed AOT/Interpreter mode augmented by the recording created during the first pass.
In the example above, using AOT for the about menu may not be particularly interesting as it is not executed often.
This mode gives very good results, where the RayTracer sample goes from an uncompressed size of 5.5MB down to 2.9MB.
For the Uno Playground, the results are quite interesting as well:The startup time for the playground is also divided by two when using PG-AOT when compared with the interpreter-based version.
Another aspect of using this mode when compared to FullAOT is that there’s less code to compile and load in the browser, resulting in faster load time. This is particularly visible in the Uno Calculator which was updated to use PG-AOT.
The choice between execution modes can be viewed as follows:
Where each mode has its strengths and weaknesses.
How does PG-AOT compare to Xamarin.Android’s Custom Startup Tracing?
Xamarin has been providing the Custom Startup Tracing feature in recent builds, and this allows for significantly smaller applications.
While both features share the same profiled execution technique, the biggest difference with .NET’s PG-AOT is the fact that Android can executed JIT (Just in Time) compiled code. JIT code can run at decent native speed, which is why tracing only the startup of an application makes sense on Android. In the case of the Uno Calculator, the size of the application is also cut in half and the startup time is a bit faster.
With WebAssembly, where JITing code is not supported, profiling more than the startup of the application is a good choice to get better performance throughout the application, keeping lots of less used or unused code running through the interpreter. Having UI Tests automatically run through the application and generate a PG-AOT profile when the application is about to be released can be a good strategy to get an up-to-date profile.
How to use Profile Guided AOT in Uno Platform Applications
An up-to-date content of this section can be found in the Uno.Wasm.Boostrap documentation.
Note that using PG-AOT requires the use of WSL on Windows.
- Install the latest experimental Uno.Wasm.Bootstrap and Uno.Wasm.Bootstrap.DevServer nuget packages. You will need to setup WSL.
- In your Wasm csproj, add the following:
<WasmShellGenerateAOTProfile>true</WasmShellGenerateAOTProfile>
- Run the application once, without the debugger (e.g. Ctrl+F5)
- Navigate throughout the application in high usage places.
- Once done, either:
- Press the Alt+Shift+P key sequence
- Run App.saveProfile() in the Javacript debugger
- Download the aot.profile file next to the csproj file
- Comment the WasmShellGenerateAOTProfile line
- Add the following lines:
<ItemGroup> <WasmShellEnableAotProfile Include="aot.profile" /> </ItemGroup>
- Make sure that Mixed mode is enabled:
<WasmShellMonoRuntimeExecutionMode>InterpreterAndAOT</WasmShellMonoRuntimeExecutionMode>
- Build you application again
Note that the AOT profile is a snapshot of the current set of assemblies and methods in your application. If that set changes significantly, you’ll need to re-create the AOT profile to get optimal results.
Next Steps
We hope you will take advantage of these new benefits to your Uno Apps. Or, if you are new to Uno Platform please give it a try via our official Getting Started tutorial.
Jerome Laban, on behalf of Uno Platform team