Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for Android "Profiled AOT" in .NET 6 #56989

Closed
jonathanpeppers opened this issue Aug 6, 2021 · 11 comments
Closed

Support for Android "Profiled AOT" in .NET 6 #56989

jonathanpeppers opened this issue Aug 6, 2021 · 11 comments

Comments

@jonathanpeppers
Copy link
Member

jonathanpeppers commented Aug 6, 2021

This feature in Xamarin.Android is also known as "Startup Tracing":

https://devblogs.microsoft.com/xamarin/faster-android-startup-times-with-startup-tracing/

Yet another name for this might be "profile guided optimization".

For .NET 6, we'd like users be able to do something like the following in Release builds:

<RunAOTCompilation>true</RunAOTCompilation>
<UseProfiledAOT>true</UseProfiledAOT>

This would use a built-in profile that the Android workload provides as well as the .NET MAUI workload. Recording a custom profile for a developer's app is probably not something we need in .NET 6. However, the Android & .NET MAUI teams would need to be able to record profiles. .NET MAUI's startup path is still quite a bit in flux, so ideally we would be automate the creation of the built-in MAUI profile.

There are a few pieces missing from dotnet/runtime at the moment:

  1. libmono-profiler-aot.so
  2. aprofutil
  3. MonoAOTCompiler.AotProfilePath only accepts 1 value:

/// <summary>
/// File to use for profile-guided optimization, *only* the methods described in the file will be AOT compiled.
/// </summary>
public string? AotProfilePath { get; set; }

For .NET 6, I think we can take a simple approach:

  1. Build & ship libmono-profiler-aot.so in the Android runtime packs.
  2. The Android workload can ship a aprofutil from mono/mono. We can emit warnings that mention recording custom AOT profiles is an experimental feature.
  3. We can emit profile-only,profile=foo.aprof for %(AotArguments) in the Android MSBuild targets until there is a different way.

These would get us by for now.

In the long run, recording custom AOT profiles might be something that dotnet-trace / diagnostics should support.

@dotnet-issue-labeler dotnet-issue-labeler bot added area-Diagnostics-coreclr untriaged New issue has not been triaged by the area owner labels Aug 6, 2021
@ghost
Copy link

ghost commented Aug 6, 2021

Tagging subscribers to this area: @tommcdon
See info in area-owners.md if you want to be subscribed.

Issue Details

This feature in Xamarin.Android is also known as "Startup Tracing":

https://devblogs.microsoft.com/xamarin/faster-android-startup-times-with-startup-tracing/

Yet another name for this might be "profile guided optimization".

For .NET 6, we'd like users be able to do something like the following in Release builds:

<RunAOTCompilation>true</RunAOTCompilation>
<UseProfiledAOT>true</UseProfiledAOT>

This would use a built-in profile that the Android workload provides as well as the .NET MAUI workload. Recording a custom profile for a developer's app is probably not something we need in .NET 6. However, the Android & .NET MAUI teams would need to be able to record profiles. .NET MAUI's startup path is still quite a bit in flux at the moment, so ideally we would be automate the creation of the built-in MAUI profile.

There are a few pieces missing from dotnet/runtime at the moment:

  1. libmono-profiler-aot.so
  2. aprofutil
  3. MonoAOTCompiler.AotProfilePath only accepts 1 value:

/// <summary>
/// File to use for profile-guided optimization, *only* the methods described in the file will be AOT compiled.
/// </summary>
public string? AotProfilePath { get; set; }

For .NET 6, I think we can take a simple approach:

  1. Build & ship libmono-profiler-aot.so in the Android runtime packs.
  2. The Android workload can ship a aprofutil from mono/mono. We can emit warnings that mention recording custom AOT profiles is an experimental feature.
  3. We can emit, profile-only,profile=foo.aprof for %(AotArguments) in the Android MSBuild targets until there is a different way.

These would get us by for now.

In the long run, recording custom AOT profiles might be something that dotnet-trace / diagnostics should support.

Author: jonathanpeppers
Assignees: -
Labels:

area-Diagnostics-coreclr, untriaged

Milestone: -

@ghost
Copy link

ghost commented Aug 6, 2021

Tagging subscribers to this area:
See info in area-owners.md if you want to be subscribed.

Issue Details

This feature in Xamarin.Android is also known as "Startup Tracing":

https://devblogs.microsoft.com/xamarin/faster-android-startup-times-with-startup-tracing/

Yet another name for this might be "profile guided optimization".

For .NET 6, we'd like users be able to do something like the following in Release builds:

<RunAOTCompilation>true</RunAOTCompilation>
<UseProfiledAOT>true</UseProfiledAOT>

This would use a built-in profile that the Android workload provides as well as the .NET MAUI workload. Recording a custom profile for a developer's app is probably not something we need in .NET 6. However, the Android & .NET MAUI teams would need to be able to record profiles. .NET MAUI's startup path is still quite a bit in flux at the moment, so ideally we would be automate the creation of the built-in MAUI profile.

There are a few pieces missing from dotnet/runtime at the moment:

  1. libmono-profiler-aot.so
  2. aprofutil
  3. MonoAOTCompiler.AotProfilePath only accepts 1 value:

/// <summary>
/// File to use for profile-guided optimization, *only* the methods described in the file will be AOT compiled.
/// </summary>
public string? AotProfilePath { get; set; }

For .NET 6, I think we can take a simple approach:

  1. Build & ship libmono-profiler-aot.so in the Android runtime packs.
  2. The Android workload can ship a aprofutil from mono/mono. We can emit warnings that mention recording custom AOT profiles is an experimental feature.
  3. We can emit, profile-only,profile=foo.aprof for %(AotArguments) in the Android MSBuild targets until there is a different way.

These would get us by for now.

In the long run, recording custom AOT profiles might be something that dotnet-trace / diagnostics should support.

Author: jonathanpeppers
Assignees: -
Labels:

untriaged, area-VM-meta-mono

Milestone: -

@akoeplinger akoeplinger added area-Tracing-mono and removed untriaged New issue has not been triaged by the area owner area-VM-meta-mono labels Aug 6, 2021
@akoeplinger akoeplinger added this to the 6.0.0 milestone Aug 6, 2021
@akoeplinger
Copy link
Member

akoeplinger commented Aug 6, 2021

So we need to do two things:

jonathanpeppers added a commit to jonathanpeppers/xamarin-android that referenced this issue Aug 6, 2021
Fixes: dotnet#6053

This is still WIP. Still a few pieces missing on the dotnet/runtime to
enable this:

dotnet/runtime#56989

We will need a `libmono-profiler-aot.so` from dotnet/runtime to be
able to record AOT profiles.

For now, I could:

1. Use the `startup.aotprofile` we're already shipping in "legacy"
   Xamarin.Android.
2. Pass this in when `$(AndroidEnableProfiledAot)` is `true`.

~~ Results ~~

All tests:

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

| Test                |      AOT time | Profiled AOT time |  AOT apk size | Profiled AOT apk size |
| ------------------- | ------------: | ----------------: | ------------: | --------------------: |
| [HelloAndroid][1]   |  00:00:00.246 |      00:00:00.288 |    12,151,755 |             9,161,675 |
| [HelloMaui][2]      |  00:00:00.619 |      00:00:01.131 |    43,442,233 |            19,992,633 |

From these results, we see that Profiled AOT is AOT'ing *some* of the
assemblies.

We are not getting the best startup time yet, because some methods are
still using the JIT:

    08-06 14:12:34.985 30817 30817 D Mono    : AOT: FOUND method Android.Runtime.JNIEnv:NewGlobalRef (intptr) [0x7ae3c8c620 - 0x7ae3c8c6a0 0x7ae3c9849c]
    08-06 14:12:34.985 30817 30817 D Mono    : AOT: NOT FOUND: intptr:op_Explicit (intptr).
    08-06 14:12:34.985 30817 30817 D Mono    : AOT: NOT FOUND: intptr:op_Explicit (int).
    08-06 14:12:34.986 30817 30817 D Mono    : AOT: FOUND method System.WeakReference`1:.ctor (T,bool) [0x7ae3d8c580 - 0x7ae3d8c5d0 0x7ae3ddaec1]
    08-06 14:12:34.986 30817 30817 D Mono    : AOT: FOUND method System.WeakReference`1:Create (T,bool) [0x7ae3d8c4c0 - 0x7ae3d8c580 0x7ae3ddaebd]
    08-06 14:12:34.986 30817 30817 D Mono    : AOT: NOT FOUND: System.Runtime.InteropServices.GCHandle:Alloc (object,System.Runtime.InteropServices.GCHandleType).
    08-06 14:12:34.986 30817 30817 D Mono    : AOT: NOT FOUND: System.Runtime.InteropServices.GCHandle:Alloc (object,System.Runtime.InteropServices.GCHandleType).
    08-06 14:12:34.986 30817 30817 D Mono    : AOT: NOT FOUND: System.Runtime.InteropServices.GCHandle:.ctor (object,System.Runtime.InteropServices.GCHandleType).

Overall, seems promising, though.

[0]: store.google.com/us/product/pixel_5_specs?hl=en-US
[1]: dotnet/maui-samples@7144604/HelloAndroid
[2]: dotnet/maui-samples@7144604/HelloMaui
jonathanpeppers added a commit to jonathanpeppers/runtime that referenced this issue Aug 10, 2021
Fixes part of: dotnet#56989

The Android workload needs to be able to pass in multiple AOT profiles
to the `<MonoAOTCompiler/>` MSBuild task. We plan on shipping a
default profile in the Android workload, as well as the MAUI workload.
.NET MAUI would have two profiles when using profiled AOT.

Adding `profile-only`, and then multiple `profile` arguments is
currently working in legacy Xamarin.Android:

https://github.com/xamarin/xamarin-android/blob/77895e2a03ed91fdf3729cde54501f91e7d1a36f/src/Xamarin.Android.Build.Tasks/Tasks/GetAotArguments.cs#L256-L260

Either a single property or item group can be passed in for
`AotProfilePath` now. I avoided changing the name, as it looks like it
might be used by wasm.
@steveisok
Copy link
Member

So we need to do two things:

  • enable build of libmono-profiler-aot.so in mono.proj (it's already done for Browser)

I'm assuming we would want to include this file in the aot pack, correct?

@jonathanpeppers
Copy link
Member Author

@steveisok it could got in the AOT pack, but you would need an item group like this:

<ItemGroup>
<MonoAotCrossCompiler Include="$(MSBuildThisFileDirectory)..\tools\mono-aot-cross${ExeSuffix}" RuntimeIdentifier="${TargetRid}" />
</ItemGroup>

Then the Android workload could include this file in apps when needed.

akoeplinger pushed a commit that referenced this issue Aug 11, 2021
* [MonoAOTCompiler] accept more than one AotProfilePath

Fixes part of: #56989

The Android workload needs to be able to pass in multiple AOT profiles
to the `<MonoAOTCompiler/>` MSBuild task. We plan on shipping a
default profile in the Android workload, as well as the MAUI workload.
.NET MAUI would have two profiles when using profiled AOT.

Adding `profile-only`, and then multiple `profile` arguments is
currently working in legacy Xamarin.Android:

https://github.com/xamarin/xamarin-android/blob/77895e2a03ed91fdf3729cde54501f91e7d1a36f/src/Xamarin.Android.Build.Tasks/Tasks/GetAotArguments.cs#L256-L260

Either a single property or item group can be passed in for
`AotProfilePath` now. I avoided changing the name, as it looks like it
might be used by wasm.

* Update src/tasks/AotCompilerTask/MonoAOTCompiler.cs

Co-authored-by: Ankit Jain <radical@gmail.com>

Co-authored-by: Ankit Jain <radical@gmail.com>
jonathanpeppers added a commit to jonathanpeppers/xamarin-android that referenced this issue Aug 12, 2021
Fixes: dotnet#6053

This is still WIP. Still a few pieces missing on the dotnet/runtime to
enable this:

dotnet/runtime#56989

We will need a `libmono-profiler-aot.so` from dotnet/runtime to be
able to record AOT profiles.

For now, I could:

1. Use the `startup.aotprofile` we're already shipping in "legacy"
   Xamarin.Android.
2. Pass this in when `$(AndroidEnableProfiledAot)` is `true`.

~~ Results ~~

All tests:

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

| Test                |      AOT time | Profiled AOT time |  AOT apk size | Profiled AOT apk size |
| ------------------- | ------------: | ----------------: | ------------: | --------------------: |
| [HelloAndroid][1]   |  00:00:00.246 |      00:00:00.288 |    12,151,755 |             9,161,675 |
| [HelloMaui][2]      |  00:00:00.619 |      00:00:01.131 |    43,442,233 |            19,992,633 |

From these results, we see that Profiled AOT is AOT'ing *some* of the
assemblies.

We are not getting the best startup time yet, because some methods are
still using the JIT:

    08-06 14:12:34.985 30817 30817 D Mono    : AOT: FOUND method Android.Runtime.JNIEnv:NewGlobalRef (intptr) [0x7ae3c8c620 - 0x7ae3c8c6a0 0x7ae3c9849c]
    08-06 14:12:34.985 30817 30817 D Mono    : AOT: NOT FOUND: intptr:op_Explicit (intptr).
    08-06 14:12:34.985 30817 30817 D Mono    : AOT: NOT FOUND: intptr:op_Explicit (int).
    08-06 14:12:34.986 30817 30817 D Mono    : AOT: FOUND method System.WeakReference`1:.ctor (T,bool) [0x7ae3d8c580 - 0x7ae3d8c5d0 0x7ae3ddaec1]
    08-06 14:12:34.986 30817 30817 D Mono    : AOT: FOUND method System.WeakReference`1:Create (T,bool) [0x7ae3d8c4c0 - 0x7ae3d8c580 0x7ae3ddaebd]
    08-06 14:12:34.986 30817 30817 D Mono    : AOT: NOT FOUND: System.Runtime.InteropServices.GCHandle:Alloc (object,System.Runtime.InteropServices.GCHandleType).
    08-06 14:12:34.986 30817 30817 D Mono    : AOT: NOT FOUND: System.Runtime.InteropServices.GCHandle:Alloc (object,System.Runtime.InteropServices.GCHandleType).
    08-06 14:12:34.986 30817 30817 D Mono    : AOT: NOT FOUND: System.Runtime.InteropServices.GCHandle:.ctor (object,System.Runtime.InteropServices.GCHandleType).

Overall, seems promising, though.

[0]: store.google.com/us/product/pixel_5_specs?hl=en-US
[1]: dotnet/maui-samples@7144604/HelloAndroid
[2]: dotnet/maui-samples@7144604/HelloMaui
@jonathanpeppers
Copy link
Member Author

@steveisok I'm able to build a libmono-profiler-aot.so that works successfully:

When you're around next week, let's discuss what I need to do to finish this.

I'm having trouble building the AOT packs, such as:

https://github.com/dotnet/runtime/blob/main/src/installer/pkg/sfx/Microsoft.NETCore.App/Microsoft.NETCore.App.MonoCrossAOT.sfxproj

$ ./build.sh mono.aotcross -os android -c Release -bl -pack
...
monoaotcross.proj(32,7): error MSB4184: The expression """.Substring(0, -1)" cannot be evaluated. Length cannot be less than zero. (Parameter 'length')

I'm probably doing something wrong.

@akoeplinger
Copy link
Member

@jonathanpeppers looks like you need to pass /p:MonoCrossAOTTargetOS=Android

@jonathanpeppers
Copy link
Member Author

Thanks, I ended up using:

$ ./build.sh mono+packs -os android -c Release -bl -p:MonoCrossAOTTargetOS=Android

I might be able to finish now, I'll give a try.

@jonathanpeppers
Copy link
Member Author

jonathanpeppers commented Aug 13, 2021

I got libmono-profiler-aot.so added to the Microsoft.NETCore.App.Runtime.AOT.[host-rid].Cross.[target-rid] packs, and added a new item group for its path.

But the problem is these packs are only imported when $(RunAOTCompilation) is true:

<ImportGroup Condition="'$(TargetPlatformIdentifier)' == 'android' and '$(RunAOTCompilation)' == 'true'">
<Import Project="Sdk.props" Sdk="Microsoft.NETCore.App.Runtime.AOT.Cross.android-x86" />
<Import Project="Sdk.props" Sdk="Microsoft.NETCore.App.Runtime.AOT.Cross.android-x64" />
<Import Project="Sdk.props" Sdk="Microsoft.NETCore.App.Runtime.AOT.Cross.android-arm" />
<Import Project="Sdk.props" Sdk="Microsoft.NETCore.App.Runtime.AOT.Cross.android-arm64" />
</ImportGroup>

When users record a profile, they won't be using AOT. Generally you just run a Debug build to record a profile, and $(RunAOTCompilation) would be blank.

Should I add this file to the runtime packs instead? And I would add something to exclude it in the Android workload for most builds? Similar to a Mono component, I guess?

jonathanpeppers added a commit to jonathanpeppers/xamarin-android that referenced this issue Aug 13, 2021
Fixes: dotnet#6053

This is still WIP. Still a few pieces missing on the dotnet/runtime to
enable this:

dotnet/runtime#56989

We will need a `libmono-profiler-aot.so` from dotnet/runtime to be
able to record AOT profiles.

For now, I could:

1. Use the `startup.aotprofile` we're already shipping in "legacy"
   Xamarin.Android.
2. Pass this in when `$(AndroidEnableProfiledAot)` is `true`.

~~ Results ~~

All tests:

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

| Test                |      AOT time | Profiled AOT time |  AOT apk size | Profiled AOT apk size |
| ------------------- | ------------: | ----------------: | ------------: | --------------------: |
| [HelloAndroid][1]   |  00:00:00.246 |      00:00:00.288 |    12,151,755 |             9,161,675 |
| [HelloMaui][2]      |  00:00:00.619 |      00:00:01.131 |    43,442,233 |            19,992,633 |

From these results, we see that Profiled AOT is AOT'ing *some* of the
assemblies.

We are not getting the best startup time yet, because some methods are
still using the JIT:

    08-06 14:12:34.985 30817 30817 D Mono    : AOT: FOUND method Android.Runtime.JNIEnv:NewGlobalRef (intptr) [0x7ae3c8c620 - 0x7ae3c8c6a0 0x7ae3c9849c]
    08-06 14:12:34.985 30817 30817 D Mono    : AOT: NOT FOUND: intptr:op_Explicit (intptr).
    08-06 14:12:34.985 30817 30817 D Mono    : AOT: NOT FOUND: intptr:op_Explicit (int).
    08-06 14:12:34.986 30817 30817 D Mono    : AOT: FOUND method System.WeakReference`1:.ctor (T,bool) [0x7ae3d8c580 - 0x7ae3d8c5d0 0x7ae3ddaec1]
    08-06 14:12:34.986 30817 30817 D Mono    : AOT: FOUND method System.WeakReference`1:Create (T,bool) [0x7ae3d8c4c0 - 0x7ae3d8c580 0x7ae3ddaebd]
    08-06 14:12:34.986 30817 30817 D Mono    : AOT: NOT FOUND: System.Runtime.InteropServices.GCHandle:Alloc (object,System.Runtime.InteropServices.GCHandleType).
    08-06 14:12:34.986 30817 30817 D Mono    : AOT: NOT FOUND: System.Runtime.InteropServices.GCHandle:Alloc (object,System.Runtime.InteropServices.GCHandleType).
    08-06 14:12:34.986 30817 30817 D Mono    : AOT: NOT FOUND: System.Runtime.InteropServices.GCHandle:.ctor (object,System.Runtime.InteropServices.GCHandleType).

Overall, seems promising, though.

[0]: store.google.com/us/product/pixel_5_specs?hl=en-US
[1]: dotnet/maui-samples@7144604/HelloAndroid
[2]: dotnet/maui-samples@7144604/HelloMaui
jonathanpeppers added a commit to jonathanpeppers/xamarin-android that referenced this issue Aug 16, 2021
Fixes: dotnet#6053

This is still WIP. Still a few pieces missing on the dotnet/runtime to
enable this:

dotnet/runtime#56989

We will need a `libmono-profiler-aot.so` from dotnet/runtime to be
able to record AOT profiles.

For now, I could:

1. Use the `startup.aotprofile` we're already shipping in "legacy"
   Xamarin.Android.
2. Pass this in when `$(AndroidEnableProfiledAot)` is `true`.

~~ Results ~~

All tests:

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

| Test                |      AOT time | Profiled AOT time |  AOT apk size | Profiled AOT apk size |
| ------------------- | ------------: | ----------------: | ------------: | --------------------: |
| [HelloAndroid][1]   |  00:00:00.246 |      00:00:00.288 |    12,151,755 |             9,161,675 |
| [HelloMaui][2]      |  00:00:00.619 |      00:00:01.131 |    43,442,233 |            19,992,633 |

From these results, we see that Profiled AOT is AOT'ing *some* of the
assemblies.

We are not getting the best startup time yet, because some methods are
still using the JIT:

    08-06 14:12:34.985 30817 30817 D Mono    : AOT: FOUND method Android.Runtime.JNIEnv:NewGlobalRef (intptr) [0x7ae3c8c620 - 0x7ae3c8c6a0 0x7ae3c9849c]
    08-06 14:12:34.985 30817 30817 D Mono    : AOT: NOT FOUND: intptr:op_Explicit (intptr).
    08-06 14:12:34.985 30817 30817 D Mono    : AOT: NOT FOUND: intptr:op_Explicit (int).
    08-06 14:12:34.986 30817 30817 D Mono    : AOT: FOUND method System.WeakReference`1:.ctor (T,bool) [0x7ae3d8c580 - 0x7ae3d8c5d0 0x7ae3ddaec1]
    08-06 14:12:34.986 30817 30817 D Mono    : AOT: FOUND method System.WeakReference`1:Create (T,bool) [0x7ae3d8c4c0 - 0x7ae3d8c580 0x7ae3ddaebd]
    08-06 14:12:34.986 30817 30817 D Mono    : AOT: NOT FOUND: System.Runtime.InteropServices.GCHandle:Alloc (object,System.Runtime.InteropServices.GCHandleType).
    08-06 14:12:34.986 30817 30817 D Mono    : AOT: NOT FOUND: System.Runtime.InteropServices.GCHandle:Alloc (object,System.Runtime.InteropServices.GCHandleType).
    08-06 14:12:34.986 30817 30817 D Mono    : AOT: NOT FOUND: System.Runtime.InteropServices.GCHandle:.ctor (object,System.Runtime.InteropServices.GCHandleType).

Overall, seems promising, though.

[0]: store.google.com/us/product/pixel_5_specs?hl=en-US
[1]: dotnet/maui-samples@7144604/HelloAndroid
[2]: dotnet/maui-samples@7144604/HelloMaui
@ghost ghost added the in-pr There is an active PR which will close this issue when it is merged label Aug 16, 2021
jonathanpeppers added a commit to jonathanpeppers/runtime that referenced this issue Aug 16, 2021
Context: dotnet/android#6171
Fixes: dotnet#56989

In order for the Android workload to be able to record
`.aotprof`/`.aotprofile` files, we need `libmono-profiler-aot.so`
to be available. Down the road this feature could be provided by the
Mono diagnostics component, but will probably not happen in .NET 6.

These changes build `libmono-profiler-aot.so` for Android, and includes
it in the `Microsoft.NETCore.App.Runtime.Mono.android-*` runtime packs.
In the Android workload's MSBuild targets we exclude this native library
unless the app is configured to record an AOT profile.

I also included in `CMakeLists.txt`:

    target_compile_definitions(mono-profiler-aot PRIVATE -DMONO_DLL_EXPORT)

Otherwise, the AOT profiler cannot be loaded:

    08-12 16:01:39.817  3003  3003 I monodroid-assembly: Trying to load shared library '/data/app/com.microsoft.net6.helloandroid-4u8tNHoPAh4zSZMaf2FsnA==/lib/x86_64/libmono-profiler-aot.so'
    08-12 16:01:39.818  3003  3003 W monodroid: Looking for profiler init symbol 'mono_profiler_init_aot'? 0x0
    08-12 16:01:39.818  3003  3003 W monodroid: The 'aot' profiler wasn't found in the main executable nor could it be loaded from 'libmono-profiler-aot.so'.

With these changes, I can successfully record an AOT profile on Android:

    Reading from '127.0.0.1:9999'...
    Read 4096 bytes...
    ...
    Read 2671 bytes...
    Read total 72303 bytes...
    Summary:
            Modules:          8
            Types:          197
            Methods:        910
    Going to write the profile to 'custom.aprof'

When using the profile, I get improved startup times:

    08-12 16:56:33.940  1624  1874 I ActivityTaskManager: Displayed com.microsoft.net6.helloandroid/crc6490bfc84a0f5dff7a.MainActivity: +217ms
jonathanpeppers added a commit to jonathanpeppers/xamarin-android that referenced this issue Sep 1, 2021
Fixes: dotnet#6053

This is still WIP. Still a few pieces missing on the dotnet/runtime to
enable this:

dotnet/runtime#56989

We will need a `libmono-profiler-aot.so` from dotnet/runtime to be
able to record AOT profiles.

For now, I could:

1. Use the `startup.aotprofile` we're already shipping in "legacy"
   Xamarin.Android.
2. Pass this in when `$(AndroidEnableProfiledAot)` is `true`.

~~ Results ~~

All tests:

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

| Test                |      AOT time | Profiled AOT time |  AOT apk size | Profiled AOT apk size |
| ------------------- | ------------: | ----------------: | ------------: | --------------------: |
| [HelloAndroid][1]   |  00:00:00.246 |      00:00:00.288 |    12,151,755 |             9,161,675 |
| [HelloMaui][2]      |  00:00:00.619 |      00:00:01.131 |    43,442,233 |            19,992,633 |

From these results, we see that Profiled AOT is AOT'ing *some* of the
assemblies.

We are not getting the best startup time yet, because some methods are
still using the JIT:

    08-06 14:12:34.985 30817 30817 D Mono    : AOT: FOUND method Android.Runtime.JNIEnv:NewGlobalRef (intptr) [0x7ae3c8c620 - 0x7ae3c8c6a0 0x7ae3c9849c]
    08-06 14:12:34.985 30817 30817 D Mono    : AOT: NOT FOUND: intptr:op_Explicit (intptr).
    08-06 14:12:34.985 30817 30817 D Mono    : AOT: NOT FOUND: intptr:op_Explicit (int).
    08-06 14:12:34.986 30817 30817 D Mono    : AOT: FOUND method System.WeakReference`1:.ctor (T,bool) [0x7ae3d8c580 - 0x7ae3d8c5d0 0x7ae3ddaec1]
    08-06 14:12:34.986 30817 30817 D Mono    : AOT: FOUND method System.WeakReference`1:Create (T,bool) [0x7ae3d8c4c0 - 0x7ae3d8c580 0x7ae3ddaebd]
    08-06 14:12:34.986 30817 30817 D Mono    : AOT: NOT FOUND: System.Runtime.InteropServices.GCHandle:Alloc (object,System.Runtime.InteropServices.GCHandleType).
    08-06 14:12:34.986 30817 30817 D Mono    : AOT: NOT FOUND: System.Runtime.InteropServices.GCHandle:Alloc (object,System.Runtime.InteropServices.GCHandleType).
    08-06 14:12:34.986 30817 30817 D Mono    : AOT: NOT FOUND: System.Runtime.InteropServices.GCHandle:.ctor (object,System.Runtime.InteropServices.GCHandleType).

Overall, seems promising, though.

[0]: store.google.com/us/product/pixel_5_specs?hl=en-US
[1]: dotnet/maui-samples@7144604/HelloAndroid
[2]: dotnet/maui-samples@7144604/HelloMaui
@steveisok steveisok modified the milestones: 6.0.0, 7.0.0 Sep 27, 2021
@steveisok
Copy link
Member

Moving the milestone to .NET 7 as we plan on trying to streamline w/ diagnostics.

@ghost ghost removed the in-pr There is an active PR which will close this issue when it is merged label Oct 12, 2021
jonpryor pushed a commit to dotnet/android that referenced this issue May 5, 2022
Context: dotnet/runtime#56989
Context: dotnet/runtime#68734
Context: dotnet/runtime#68914
Context: dotnet/runtime#68701

Changes: dotnet/installer@04e40fa...c7afae6

	% git diff --shortstat 04e40fa9...c7afae69
	 98 files changed, 1788 insertions(+), 1191 deletions(-)

Changes: dotnet/runtime@a21b9a2...c5d40c9

	% git diff --shortstat a21b9a2d...c5d40c9e
	 28347 files changed, 1609359 insertions(+), 1066473 deletions(-)

Changes: dotnet/linker@01c4f59...04c49c9

	% git diff --shortstat 01c4f590...04c49c9d
	 577 files changed, 28039 insertions(+), 10835 deletions(-)

Updates to build with the .NET 7 SDK and use the runtime specified by
the SDK.  We no longer use different SDK & runtime versions.

This produces a 7.0.100 Android workload.

After this is merged we should be able to enable Maestro to consume
future .NET 7 builds from dotnet/installer/main.

~~ Known Issues ~~

AOT+LLVM crashes on startup:

  * dotnet/runtime#68914

Xamarin.Build.Download hits a breaking change with `ZipEntry`:

  * dotnet/runtime#68734
  * xamarin/XamarinComponents#1368

illink outputs different MVIDs per architecture:

  * dotnet/linker#2203
  * dotnet/runtime#67660

Size of `libmonosgen-2.0.so` regressed:

  * dotnet/runtime#68330
  * dotnet/runtime#68354

Newer .NET 7 builds crash on startup:

  * dotnet/runtime#68701
  * This is worked around by *disabling* lazy loading of AOT'd
    assemblies 6dc426f.
  * TODO: re-enable once we get a fixed .NET 7 runtime.

TODO: We can't yet push to the `dotnet7` feed. Working on this.

Co-authored-by: Jonathan Peppers <jonathan.peppers@microsoft.com>
Co-authored-by: Peter Collins <pecolli@microsoft.com>
@steveisok
Copy link
Member

In .NET 7, with #70194, #70851, and #68571, we have a replacement for libmono-profiler-aot.so and aprofutil.

@ghost ghost locked as resolved and limited conversation to collaborators Sep 1, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants