Skip to content

Commit dadb377

Browse files
[One .NET] fix libmono-profiler-aot.so recording (#6680)
Context: dotnet/maui#4355 Context: https://github.com/jonathanpeppers/android-profiled-aot Context: #6171 Context: 3e699d6 I found that when I went to update the .NET MAUI AOT profile in 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 # no error After some digging, it turned out that *appending* `,` to the [`_SetAotProfilingPropsOnDevice` target's `<Exec/>`][0] fixed it: "$(AdbToolPath)adb" $(AdbTarget) shell setprop debug.mono.profile aot:port=$(AndroidAotProfilerPort), What happened was we "lost" a `,` somewhere in #6171, likely in: * 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. [0]: https://github.com/xamarin/xamarin-android/blob/b7a368a27667c69117f64be81050403f2d5c8560/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Application.targets#L45
1 parent 84f31d5 commit dadb377

File tree

5 files changed

+62
-16
lines changed

5 files changed

+62
-16
lines changed

build-tools/automation/azure-pipelines.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ variables:
4343
- name: RunAllTests
4444
value: $[or(eq(variables['XA.RunAllTests'], true), eq(variables['IsMonoBranch'], true))]
4545
- name: DotNetNUnitCategories
46-
value: '& TestCategory != DotNetIgnore & TestCategory != HybridAOT & TestCategory != ProfiledAOT & TestCategory != MkBundle & TestCategory != MonoSymbolicate & TestCategory != PackagesConfig & TestCategory != StaticProject & TestCategory != Debugger & TestCategory != SystemApplication'
46+
value: '& TestCategory != DotNetIgnore & TestCategory != HybridAOT & TestCategory != MkBundle & TestCategory != MonoSymbolicate & TestCategory != PackagesConfig & TestCategory != StaticProject & TestCategory != Debugger & TestCategory != SystemApplication'
4747
- ${{ if eq(variables['Build.DefinitionName'], 'Xamarin.Android-Private') }}:
4848
- group: AzureDevOps-Artifact-Feeds-Pats
4949
- group: DotNet-MSRC-Storage

src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ They run in a context of an inner build with a single $(RuntimeIdentifier).
6666
<Output PropertyName="_LdFlags" TaskParameter="LdFlags" />
6767
<Output ItemName="_MonoAOTAssemblies" TaskParameter="ResolvedAssemblies" />
6868
</GetAotAssemblies>
69+
<ItemGroup Condition=" '$(AndroidExtraAotOptions)' != '' ">
70+
<_MonoAOTAssemblies Update="@(_MonoAOTAssemblies)" ProcessArguments="$(AndroidExtraAotOptions)" />
71+
</ItemGroup>
6972
<PropertyGroup>
7073
<_MonoAOTCompilerPath>@(MonoAotCrossCompiler->WithMetadataValue('RuntimeIdentifier', '$(RuntimeIdentifier)'))</_MonoAOTCompilerPath>
7174
<_LLVMPath Condition=" '$(EnableLLVM)' == 'true' ">$([System.IO.Path]::GetDirectoryName ('$(_MonoAOTCompilerPath)'))</_LLVMPath>

src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AotTests.cs

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,13 @@ public void TearDown ()
5050
Directory.Delete (SdkWithSpacesPath, recursive: true);
5151
}
5252

53+
void AssertProfiledAotBuildMessages(ProjectBuilder b)
54+
{
55+
string filename = Builder.UseDotNet ? "dotnet" : "startup";
56+
StringAssertEx.ContainsRegex (@$"Using profile data file.*{filename}\.aotprofile", b.LastBuildOutput, "Should use default AOT profile", RegexOptions.IgnoreCase);
57+
StringAssertEx.ContainsRegex (@$"Method.*emitted at", b.LastBuildOutput, "Should contain verbose AOT compiler output", RegexOptions.IgnoreCase);
58+
}
59+
5360
[Test, Category ("SmokeTests"), Category ("ProfiledAOT")]
5461
public void BuildBasicApplicationReleaseProfiledAot ()
5562
{
@@ -58,11 +65,9 @@ public void BuildBasicApplicationReleaseProfiledAot ()
5865
AndroidEnableProfiledAot = true,
5966
};
6067
proj.SetProperty (proj.ActiveConfigurationProperties, "AndroidExtraAotOptions", "--verbose");
61-
using (var b = CreateApkBuilder (Path.Combine ("temp", TestName))) {
62-
Assert.IsTrue (b.Build (proj), "Build should have succeeded.");
63-
StringAssertEx.ContainsRegex (@"\[aot-compiler stdout\] Using profile data file.*build.Xamarin.Android.startup\.aotprofile", b.LastBuildOutput, "Should use default AOT profile", RegexOptions.IgnoreCase);
64-
StringAssertEx.ContainsRegex (@"\[aot-compiler stdout\] Method.*emitted at", b.LastBuildOutput, "Should contain verbose AOT compiler output", RegexOptions.IgnoreCase);
65-
}
68+
using var b = CreateApkBuilder ();
69+
Assert.IsTrue (b.Build (proj), "Build should have succeeded.");
70+
AssertProfiledAotBuildMessages (b);
6671
}
6772

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

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

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

105108
static object [] AotChecks () => new object [] {

src/monodroid/jni/monodroid-glue.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1686,6 +1686,7 @@ MonodroidRuntime::set_profile_options ()
16861686
.append (AOT_EXT);
16871687

16881688
value
1689+
.append (",")
16891690
.append (OUTPUT_ARG)
16901691
.append (output_path.get (), output_path.length ());
16911692
}

tests/MSBuildDeviceIntegration/Tests/AotProfileTests.cs

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
using NUnit.Framework;
1+
using NUnit.Framework;
22
using System;
33
using System.IO;
4+
using System.Net;
45
using Xamarin.ProjectTools;
56

67
namespace Xamarin.Android.Build.Tests
@@ -26,6 +27,7 @@ public void BuildBasicApplicationAndAotProfileIt ()
2627
IsRelease = true,
2728
};
2829
proj.SetAndroidSupportedAbis ("armeabi-v7a", "x86");
30+
AddDotNetProfilerNativeLibraries (proj);
2931
var port = 9000 + new Random ().Next (1000);
3032
proj.SetProperty ("AndroidAotProfilerPort", port.ToString ());
3133
proj.AndroidManifest = string.Format (PermissionManifest, proj.PackageName);
@@ -35,10 +37,47 @@ public void BuildBasicApplicationAndAotProfileIt ()
3537
WaitForAppBuiltForOlderAndroidWarning (proj.PackageName, Path.Combine (Root, b.ProjectDirectory, "oldsdk-logcat.log"));
3638
System.Threading.Thread.Sleep (5000);
3739
b.BuildLogFile = "build2.log";
40+
41+
// Need execute permission
42+
if (Builder.UseDotNet && !IsWindows) {
43+
var aprofutil = Path.Combine (Root, b.ProjectDirectory, "aprofutil");
44+
RunProcess ("chmod", $"u+x {aprofutil}");
45+
}
46+
3847
Assert.IsTrue (b.RunTarget (proj, "FinishAotProfiling", doNotCleanupOnUpdate: true), "Run of FinishAotProfiling should have succeeded.");
3948
var customProfile = Path.Combine (Root, projDirectory, "custom.aprof");
4049
FileAssert.Exists (customProfile);
4150
}
4251
}
52+
53+
void AddDotNetProfilerNativeLibraries (XamarinAndroidApplicationProject proj)
54+
{
55+
// TODO: only needed in .NET 6+
56+
// See https://github.com/dotnet/runtime/issues/56989
57+
if (!Builder.UseDotNet)
58+
return;
59+
60+
// Files are built from dotnet/runtime & stored at:
61+
const string github = "https://github.com/jonathanpeppers/android-profiled-aot";
62+
63+
proj.Sources.Add (new BuildItem ("None", "aprofutil") {
64+
WebContent = $"{github}/raw/main/binaries/aprofutil"
65+
});
66+
proj.Sources.Add (new BuildItem ("None", "aprofutil.exe") {
67+
WebContent = $"{github}/raw/main/binaries/aprofutil.exe"
68+
});
69+
proj.Sources.Add (new BuildItem ("None", "Mono.Profiler.Log.dll") {
70+
WebContent = $"{github}/raw/main/binaries/Mono.Profiler.Log.dll"
71+
});
72+
proj.SetProperty ("AProfUtilToolPath", "$(MSBuildThisFileDirectory)");
73+
74+
foreach (var rid in proj.GetProperty (KnownProperties.RuntimeIdentifiers).Split (';')) {
75+
//NOTE: each rid has the same file name, so using WebClient directly
76+
var bytes = new WebClient ().DownloadData ($"{github}/raw/main/binaries/{rid}/libmono-profiler-aot.so");
77+
proj.Sources.Add (new AndroidItem.AndroidNativeLibrary ($"{rid}\\libmono-profiler-aot.so") {
78+
BinaryContent = () => bytes,
79+
});
80+
}
81+
}
4382
}
4483
}

0 commit comments

Comments
 (0)