Skip to content

Commit

Permalink
[One .NET] fix libmono-profiler-aot.so recording
Browse files Browse the repository at this point in the history
I found when I went to update the AOT profile in .NET MAUI:

https://github.com/jonathanpeppers/android-profiled-aot
dotnet/maui#4355

The profiler crashed with:

    01-27 11:10:16.119 28922 28922 W monodroid: Creating public update directory: `/data/user/0/com.androidaot.MauiApp1/files/.__override__`
    ...
    01-27 11:10:16.119 28922 28922 W monodroid: Initializing profiler with options: aot:port=9999output=/data/user/0/com.androidaot.MauiApp1/files/.__override__/profile.aotprofile
    01-27 11:10:16.119 28922 28922 W monodroid: Looking for profiler init symbol 'mono_profiler_init_aot'? 0x7325b6355c
    01-27 11:10:16.119 28922 28922 E mono-prof: Could not create AOT profiler output file 'output.aotprofile': Read-only file system

But the directory was writeable?

    adb shell run-as com.androidaot.MauiApp1 touch files/.__override__/foo

After some digging, it turned out appending `,` to this line fixed the
issue:

https://github.com/xamarin/xamarin-android/blob/b7a368a27667c69117f64be81050403f2d5c8560/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Application.targets#L45

What happened was we lost a `,` somewhere in this commit:

xamarin@f73a323

To fix this:

1. Prepend a `,`

2. I found a way to actually enable tests for Profiled AOT in .NET 6
   by downloading binaries from my Github repo.

In enabling the `ProfiledAOT` category for .NET 6, I found that this
setting wasn't working:

    <AndroidExtraAotOptions>--verbose</AndroidExtraAotOptions>

I updated `%(_MonoAOTAssemblies.ProcessArguments)` to solve this.
  • Loading branch information
jonathanpeppers committed Jan 31, 2022
1 parent 67718cf commit 1890174
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 16 deletions.
2 changes: 1 addition & 1 deletion build-tools/automation/azure-pipelines.yaml
Expand Up @@ -43,7 +43,7 @@ variables:
- name: RunAllTests
value: $[or(eq(variables['XA.RunAllTests'], true), eq(variables['IsMonoBranch'], true))]
- name: DotNetNUnitCategories
value: '& TestCategory != DotNetIgnore & TestCategory != HybridAOT & TestCategory != ProfiledAOT & TestCategory != MkBundle & TestCategory != MonoSymbolicate & TestCategory != PackagesConfig & TestCategory != StaticProject & TestCategory != Debugger & TestCategory != SystemApplication'
value: '& TestCategory != DotNetIgnore & TestCategory != HybridAOT & TestCategory != MkBundle & TestCategory != MonoSymbolicate & TestCategory != PackagesConfig & TestCategory != StaticProject & TestCategory != Debugger & TestCategory != SystemApplication'
- ${{ if eq(variables['Build.DefinitionName'], 'Xamarin.Android-Private') }}:
- group: AzureDevOps-Artifact-Feeds-Pats
- group: DotNet-MSRC-Storage
Expand Down
Expand Up @@ -66,6 +66,9 @@ They run in a context of an inner build with a single $(RuntimeIdentifier).
<Output PropertyName="_LdFlags" TaskParameter="LdFlags" />
<Output ItemName="_MonoAOTAssemblies" TaskParameter="ResolvedAssemblies" />
</GetAotAssemblies>
<ItemGroup Condition=" '$(AndroidExtraAotOptions)' != '' ">
<_MonoAOTAssemblies Update="@(_MonoAOTAssemblies)" ProcessArguments="$(AndroidExtraAotOptions)" />
</ItemGroup>
<PropertyGroup>
<_MonoAOTCompilerPath>@(MonoAotCrossCompiler->WithMetadataValue('RuntimeIdentifier', '$(RuntimeIdentifier)'))</_MonoAOTCompilerPath>
<_LLVMPath Condition=" '$(EnableLLVM)' == 'true' ">$([System.IO.Path]::GetDirectoryName ('$(_MonoAOTCompilerPath)'))</_LLVMPath>
Expand Down
Expand Up @@ -50,6 +50,13 @@ public void TearDown ()
Directory.Delete (SdkWithSpacesPath, recursive: true);
}

void AssertProfiledAotBuildMessages(ProjectBuilder b)
{
string filename = Builder.UseDotNet ? "dotnet" : "startup";
StringAssertEx.ContainsRegex (@$"Using profile data file.*{filename}\.aotprofile", b.LastBuildOutput, "Should use default AOT profile", RegexOptions.IgnoreCase);
StringAssertEx.ContainsRegex (@$"Method.*emitted at", b.LastBuildOutput, "Should contain verbose AOT compiler output", RegexOptions.IgnoreCase);
}

[Test, Category ("SmokeTests"), Category ("ProfiledAOT")]
public void BuildBasicApplicationReleaseProfiledAot ()
{
Expand All @@ -58,11 +65,9 @@ public void BuildBasicApplicationReleaseProfiledAot ()
AndroidEnableProfiledAot = true,
};
proj.SetProperty (proj.ActiveConfigurationProperties, "AndroidExtraAotOptions", "--verbose");
using (var b = CreateApkBuilder (Path.Combine ("temp", TestName))) {
Assert.IsTrue (b.Build (proj), "Build should have succeeded.");
StringAssertEx.ContainsRegex (@"\[aot-compiler stdout\] Using profile data file.*build.Xamarin.Android.startup\.aotprofile", b.LastBuildOutput, "Should use default AOT profile", RegexOptions.IgnoreCase);
StringAssertEx.ContainsRegex (@"\[aot-compiler stdout\] Method.*emitted at", b.LastBuildOutput, "Should contain verbose AOT compiler output", RegexOptions.IgnoreCase);
}
using var b = CreateApkBuilder ();
Assert.IsTrue (b.Build (proj), "Build should have succeeded.");
AssertProfiledAotBuildMessages (b);
}

[Test, Category ("SmokeTests"), Category ("ProfiledAOT")]
Expand All @@ -81,11 +86,9 @@ public void BuildBasicApplicationReleaseWithCustomAotProfile ()
}
proj.OtherBuildItems.Add (new BuildItem ("AndroidAotProfile", "custom.aotprofile") { BinaryContent = () => custom_aot_profile });

using (var b = CreateApkBuilder (Path.Combine ("temp", TestName))) {
Assert.IsTrue (b.Build (proj), "Build should have succeeded.");
StringAssertEx.ContainsRegex (@"\[aot-compiler stdout\] Using profile data file.*custom\.aotprofile", b.LastBuildOutput, "Should use custom AOT profile", RegexOptions.IgnoreCase);
StringAssertEx.ContainsRegex (@"\[aot-compiler stdout\] Method.*emitted at", b.LastBuildOutput, "Should contain verbose AOT compiler output", RegexOptions.IgnoreCase);
}
using var b = CreateApkBuilder ();
Assert.IsTrue (b.Build (proj), "Build should have succeeded.");
AssertProfiledAotBuildMessages (b);
}

[Test, Category ("ProfiledAOT")]
Expand All @@ -96,10 +99,10 @@ public void BuildBasicApplicationReleaseProfiledAotWithoutDefaultProfile ()
AndroidEnableProfiledAot = true,
};
proj.SetProperty (proj.ActiveConfigurationProperties, "AndroidUseDefaultAotProfile", "false");
using (var b = CreateApkBuilder (Path.Combine ("temp", TestName))) {
Assert.IsTrue (b.Build (proj), "Build should have succeeded.");
StringAssertEx.DoesNotContainRegex (@"\[aot-compiler stdout\] Using profile data file.*build.Xamarin.Android.startup.*\.aotprofile", b.LastBuildOutput, "Should not use default AOT profile", RegexOptions.IgnoreCase);
}
using var b = CreateApkBuilder ();
Assert.IsTrue (b.Build (proj), "Build should have succeeded.");
string filename = Builder.UseDotNet ? "dotnet" : "startup";
StringAssertEx.DoesNotContainRegex (@$"Using profile data file.*{filename}\.aotprofile", b.LastBuildOutput, "Should not use default AOT profile", RegexOptions.IgnoreCase);
}

static object [] AotChecks () => new object [] {
Expand Down
1 change: 1 addition & 0 deletions src/monodroid/jni/monodroid-glue.cc
Expand Up @@ -1686,6 +1686,7 @@ MonodroidRuntime::set_profile_options ()
.append (AOT_EXT);

value
.append (",")
.append (OUTPUT_ARG)
.append (output_path.get (), output_path.length ());
}
Expand Down
32 changes: 31 additions & 1 deletion tests/MSBuildDeviceIntegration/Tests/AotProfileTests.cs
@@ -1,6 +1,7 @@
using NUnit.Framework;
using NUnit.Framework;
using System;
using System.IO;
using System.Net;
using Xamarin.ProjectTools;

namespace Xamarin.Android.Build.Tests
Expand All @@ -26,6 +27,7 @@ public void BuildBasicApplicationAndAotProfileIt ()
IsRelease = true,
};
proj.SetAndroidSupportedAbis ("armeabi-v7a", "x86");
AddDotNetProfilerNativeLibraries (proj);
var port = 9000 + new Random ().Next (1000);
proj.SetProperty ("AndroidAotProfilerPort", port.ToString ());
proj.AndroidManifest = string.Format (PermissionManifest, proj.PackageName);
Expand All @@ -40,5 +42,33 @@ public void BuildBasicApplicationAndAotProfileIt ()
FileAssert.Exists (customProfile);
}
}

void AddDotNetProfilerNativeLibraries (XamarinAndroidApplicationProject proj)
{
// TODO: only needed in .NET 6+
// See https://github.com/dotnet/runtime/issues/56989
if (!Builder.UseDotNet)
return;

// Files are built from dotnet/runtime & stored at:
const string github = "https://github.com/jonathanpeppers/android-profiled-aot";

string extension = IsWindows ? ".exe" : "";
proj.Sources.Add (new BuildItem ("None", $"aprofutil{extension}") {
WebContent = $"{github}/raw/main/binaries/aprofutil{extension}"
});
proj.Sources.Add (new BuildItem ("None", "Mono.Profiler.Log.dll") {
WebContent = $"{github}/raw/main/binaries/Mono.Profiler.Log.dll"
});
proj.SetProperty ("AProfUtilToolPath", "$(MSBuildThisFileDirectory)");

foreach (var rid in proj.GetProperty (KnownProperties.RuntimeIdentifiers).Split (';')) {
//NOTE: each rid has the same file name, so using WebClient directly
var bytes = new WebClient ().DownloadData ($"{github}/raw/main/binaries/{rid}/libmono-profiler-aot.so");
proj.Sources.Add (new AndroidItem.AndroidNativeLibrary ($"{rid}\\libmono-profiler-aot.so") {
BinaryContent = () => bytes,
});
}
}
}
}

0 comments on commit 1890174

Please sign in to comment.