diff options
author | Steve Pfister <steveisok@users.noreply.github.com> | 2022-08-04 20:02:13 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-08-04 20:02:13 +0300 |
commit | 209c040d261558d6d58ebf046e39491b22fb28f1 (patch) | |
tree | 54d40b66c52cbc5362dec938bdaffe7fcfa3c9e0 /src | |
parent | c8e6d67eee0c0641a1ddeaff7be88caabd882d82 (diff) |
[Android] Introduce NetTraceToMibcConverter task & streamline testing targets (#72394)
NetTraceToMibcConverter
- Used in profiled AOT scenarios where a .nettrace file is given as input and is converted to a .mibc file that can be fed into the AOT compiler. This previously was in the AotCompiler task, but for clarity purposes is now separated out.
Streamline Android testing targets
- The testing targets function the same, but are now structured similarly to iOS and Wasm.
- Introduced new testing properties to support profiled AOT:
NetTraceFilePath - The path to a .nettrace file that will be converted into a .mibc file and fed into the aot compiler
RuntimeComponents - The list of native components to include in the test app build (diagnostics_tracing)
DiagnosticsPorts - The ip address:port where the runtime will listen when running diagnostic tooling
DiagnosticStartupMode - The mode the runtime will use at startup for diagnostic scenarios. Suspend will halt the app very early and wait, while nosuspend will wait for a connection, but not halt the runtime
Co-authored-by: Mitchell Hwang <16830051+mdh1418@users.noreply.github.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/mono/msbuild/android/build/AndroidApp.InTree.props | 13 | ||||
-rw-r--r-- | src/mono/msbuild/android/build/AndroidApp.InTree.targets | 21 | ||||
-rw-r--r-- | src/mono/msbuild/android/build/AndroidApp.props | 18 | ||||
-rw-r--r-- | src/mono/msbuild/android/build/AndroidApp.targets | 168 | ||||
-rw-r--r-- | src/mono/msbuild/apple/build/AppleApp.targets | 13 | ||||
-rw-r--r-- | src/mono/nuget/Microsoft.NET.Runtime.MonoTargets.Sdk/Sdk/MonoTargetsTasks.props.in | 2 | ||||
-rw-r--r-- | src/tasks/AndroidAppBuilder/AndroidAppBuilder.cs | 6 | ||||
-rw-r--r-- | src/tasks/AndroidAppBuilder/ApkBuilder.cs | 6 | ||||
-rw-r--r-- | src/tasks/AndroidAppBuilder/Templates/monodroid.c | 9 | ||||
-rw-r--r-- | src/tasks/AotCompilerTask/MonoAOTCompiler.cs | 221 | ||||
-rw-r--r-- | src/tasks/AotCompilerTask/MonoAOTCompiler.csproj | 3 | ||||
-rw-r--r-- | src/tasks/Common/CompilerCache.cs | 21 | ||||
-rw-r--r-- | src/tasks/Common/FileCache.cs | 93 | ||||
-rw-r--r-- | src/tasks/Common/ProxyFile.cs | 56 | ||||
-rw-r--r-- | src/tasks/MonoTargetsTasks/MonoTargetsTasks.csproj | 2 | ||||
-rw-r--r-- | src/tasks/MonoTargetsTasks/NetTraceToMibcConverterTask/NetTraceToMibcConverter.cs | 117 |
16 files changed, 533 insertions, 236 deletions
diff --git a/src/mono/msbuild/android/build/AndroidApp.InTree.props b/src/mono/msbuild/android/build/AndroidApp.InTree.props new file mode 100644 index 00000000000..26fb1647583 --- /dev/null +++ b/src/mono/msbuild/android/build/AndroidApp.InTree.props @@ -0,0 +1,13 @@ +<Project> + <!-- This depends on the root Directory.Build.props imported this file --> + + <Import Project="$(MSBuildThisFileDirectory)AndroidApp.props" /> + <PropertyGroup> + <TargetFramework>$(NetCoreAppCurrent)</TargetFramework> + <EnableTargetingPackDownload>false</EnableTargetingPackDownload> + <EnableRuntimePackDownload>false</EnableRuntimePackDownload> + <PublishTrimmed>true</PublishTrimmed> + <TrimMode>link</TrimMode> + <RunAnalyzers>false</RunAnalyzers> + </PropertyGroup> +</Project> diff --git a/src/mono/msbuild/android/build/AndroidApp.InTree.targets b/src/mono/msbuild/android/build/AndroidApp.InTree.targets new file mode 100644 index 00000000000..2b374f617ae --- /dev/null +++ b/src/mono/msbuild/android/build/AndroidApp.InTree.targets @@ -0,0 +1,21 @@ +<Project> + <!-- This depends on the root Directory.Build.targets imported this file --> + <UsingTask TaskName="MonoAOTCompiler" AssemblyFile="$(MonoAOTCompilerTasksAssemblyPath)" /> + <UsingTask TaskName="NetTraceToMibcConverter" AssemblyFile="$(MonoTargetsTasksAssemblyPath)" /> + <UsingTask TaskName="RuntimeConfigParserTask" AssemblyFile="$(MonoTargetsTasksAssemblyPath)" /> + + <Import Project="$(MSBuildThisFileDirectory)AndroidApp.targets" /> + + <!-- Use local runtime pack --> + <Target Name="UpdateRuntimePack" AfterTargets="ResolveFrameworkReferences"> + <PropertyGroup> + <_LocalMicrosoftNetCoreAppRuntimePackDir>$(MicrosoftNetCoreAppRuntimePackDir)</_LocalMicrosoftNetCoreAppRuntimePackDir> + </PropertyGroup> + <ItemGroup> + <ResolvedRuntimePack PackageDirectory="$(_LocalMicrosoftNetCoreAppRuntimePackDir)" + Condition="'$(_LocalMicrosoftNetCoreAppRuntimePackDir)' != '' and + '%(ResolvedRuntimePack.FrameworkName)' == 'Microsoft.NETCore.App'" /> + </ItemGroup> + <Message Text="Used runtime pack: %(ResolvedRuntimePack.PackageDirectory)" Importance="high" /> + </Target> +</Project> diff --git a/src/mono/msbuild/android/build/AndroidApp.props b/src/mono/msbuild/android/build/AndroidApp.props new file mode 100644 index 00000000000..3e8f62b3e0a --- /dev/null +++ b/src/mono/msbuild/android/build/AndroidApp.props @@ -0,0 +1,18 @@ +<Project> + <PropertyGroup> + <RuntimeIdentifier>$(TargetOS.ToLowerInvariant())-$(TargetArchitecture.ToLowerInvariant())</RuntimeIdentifier> + <UseMonoRuntime>true</UseMonoRuntime> + <UseMonoJustInterp Condition="'$(RunAOTCompilation)' == 'true' and '$(MonoForceInterpreter)' == 'true'">true</UseMonoJustInterp> + + <AndroidBuildAppAfterThisTarget Condition="'$(AndroidBuildAppAfterThisTarget)' == ''">Publish</AndroidBuildAppAfterThisTarget> + <AndroidBuildAppDependsOn> + _InitializeCommonProperties; + _BeforeAndroidBuildApp; + _AndroidResolveReferences; + _AndroidPrepareProfiledAot; + _AndroidAotCompileApp; + _AndroidGenerateAppBundle; + _AfterAndroidBuildApp + </AndroidBuildAppDependsOn> + </PropertyGroup> +</Project>
\ No newline at end of file diff --git a/src/mono/msbuild/android/build/AndroidApp.targets b/src/mono/msbuild/android/build/AndroidApp.targets new file mode 100644 index 00000000000..6fd26641cd1 --- /dev/null +++ b/src/mono/msbuild/android/build/AndroidApp.targets @@ -0,0 +1,168 @@ +<Project> + <UsingTask TaskName="AndroidAppBuilderTask" + AssemblyFile="$(AndroidAppBuilderTasksAssemblyPath)" /> + + <Target Name="AndroidBuildApp" AfterTargets="$(AndroidBuildAppAfterThisTarget)" /> + + <Target Name="_AndroidCoreBuild" BeforeTargets="AndroidBuildApp" DependsOnTargets="$(AndroidBuildAppDependsOn)" /> + + <Target Name="_InitializeCommonProperties"> + <Error Condition="'$(IntermediateOutputPath)' == ''" Text="%24(IntermediateOutputPath) property needs to be set" /> + + <PropertyGroup> + <_MobileIntermediateOutputPath>$([MSBuild]::NormalizeDirectory($(IntermediateOutputPath), 'mobile'))</_MobileIntermediateOutputPath> + </PropertyGroup> + </Target> + + <Target Name="_BeforeAndroidBuildApp"> + <PropertyGroup> + <_AndroidRuntimeConfigFilePath Condition="'$(_AndroidRuntimeConfigFilePath)' == ''">$([MSBuild]::NormalizePath($(AndroidAppDir), '$(AssemblyName).runtimeconfig.json'))</_AndroidRuntimeConfigFilePath> + <_ParsedRuntimeConfigFilePath Condition="'$(_ParsedRuntimeConfigFilePath)' == ''">$([MSBuild]::NormalizePath($(AndroidAppDir), 'runtimeconfig.bin'))</_ParsedRuntimeConfigFilePath> + </PropertyGroup> + + <RemoveDir Directories="$(AndroidAppBundleDir)" /> + </Target> + + <Target Name="_AndroidResolveReferences"> + <ItemGroup> + <_AndroidAssembliesInternal Remove="@(_AndroidAssembliesInternal)" /> + <_AndroidAssembliesInternal Include="@(AndroidAssembliesToBundle)"> + <_InternalForceInterpret>%(AndroidAssembliesToBundle._InternalForceInterpret)</_InternalForceInterpret> + <_IsNative>%(AndroidAssembliesToBundle._IsNative)</_IsNative> + </_AndroidAssembliesInternal> + </ItemGroup> + </Target> + + <Target Name="_AndroidBeforeAotCompileApp"> + <PropertyGroup> + <_AOTMode Condition="'$(UseMonoJustInterp)' != 'true'">Normal</_AOTMode> + <_AOTMode Condition="'$(UseMonoJustInterp)' == 'true'">JustInterp</_AOTMode> + <_AOTMode Condition="'$(ForceFullAOT)' == 'true'">Full</_AOTMode> + </PropertyGroup> + + <ItemGroup> + <MonoAOTCompilerDefaultAotArguments Condition="'$(TargetArchitecture)' == 'arm'" Include="mtriple=armv7-linux-gnueabi" /> + <MonoAOTCompilerDefaultAotArguments Condition="'$(TargetArchitecture)' == 'arm64'" Include="mtriple=aarch64-linux-android" /> + <MonoAOTCompilerDefaultAotArguments Condition="'$(TargetArchitecture)' == 'x86'" Include="mtriple=i686-linux-android" /> + <MonoAOTCompilerDefaultAotArguments Condition="'$(TargetArchitecture)' == 'x64'" Include="mtriple=x86_64-linux-android" /> + + <MonoAOTCompilerDefaultAotArguments Include="static" /> + <MonoAOTCompilerDefaultAotArguments Include="dwarfdebug" /> + + <MonoAOTCompilerDefaultAotArguments Include="nimt-trampolines=2000" /> + <MonoAOTCompilerDefaultAotArguments Include="ntrampolines=10000" /> + <MonoAOTCompilerDefaultAotArguments Include="nrgctx-fetch-trampolines=256" /> + <MonoAOTCompilerDefaultAotArguments Include="ngsharedvt-trampolines=4400" /> + <MonoAOTCompilerDefaultAotArguments Include="nftnptr-arg-trampolines=4000" /> + <MonoAOTCompilerDefaultAotArguments Include="nrgctx-trampolines=31000" /> + </ItemGroup> + + <PropertyGroup> + <AotArguments>@(MonoAOTCompilerDefaultAotArguments, ';')</AotArguments> + <ProcessArguments>@(MonoAOTCompilerDefaultProcessArguments, ';')</ProcessArguments> + </PropertyGroup> + + <ItemGroup> + <_AotInputAssemblies Include="@(_AndroidAssembliesInternal)" + Condition="'%(_AndroidAssembliesInternal._InternalForceInterpret)' != 'true'"> + <AotArguments>$(AotArguments)</AotArguments> + <ProcessArguments>$(ProcessArguments)</ProcessArguments> + </_AotInputAssemblies> + + <_AOT_InternalForceInterpretAssemblies Include="@(_AndroidAssembliesInternal->WithMetadataValue('_InternalForceInterpret', 'true'))" /> + <_AndroidAssembliesInternal Remove="@(_AndroidAssembliesInternal)" /> + </ItemGroup> + + <MakeDir Directories="$(_MobileIntermediateOutputPath)" /> + </Target> + + <Target Name="_AndroidPrepareProfiledAot" + Condition="'$(NetTraceFilePath)' != '' and '$(ForceFullAOT)' != 'true'" + DependsOnTargets="_AndroidBeforeAotCompileApp"> + <PropertyGroup> + <_ToolPath>$([System.IO.Path]::GetDirectoryName('$(DotnetPgoToolPath)'))</_ToolPath> + </PropertyGroup> + + <NetTraceToMibcConverter + ToolPath="$(_ToolPath)" + Assemblies="@(_AotInputAssemblies)" + NetTraceFilePath="$(NetTraceFilePath)" + OutputDir="$(_MobileIntermediateOutputPath)"> + <Output TaskParameter="MibcFilePath" ItemName="ProfiledAOTProfilePaths" /> + </NetTraceToMibcConverter> + </Target> + + <Target Name="_AndroidAotCompileApp" + Condition="'$(RunAOTCompilation)' == 'true'" + DependsOnTargets="_AndroidBeforeAotCompileApp"> + + <ItemGroup> + <ProfiledAOTProfilePaths Include="$(MibcFilePath)" /> + </ItemGroup> + + <MonoAOTCompiler + CompilerBinaryPath="@(MonoAotCrossCompiler->WithMetadataValue('RuntimeIdentifier','$(TargetOS.ToLowerInvariant())-$(TargetArchitecture.ToLowerInvariant())'))" + OutputDir="$(_MobileIntermediateOutputPath)" + Mode="$(_AOTMode)" + OutputType="AsmOnly" + Assemblies="@(_AotInputAssemblies)" + AotModulesTablePath="$(AndroidAppBundleDir)\modules.c" + IntermediateOutputPath="$(_MobileIntermediateOutputPath)" + MibcProfilePath="@(ProfiledAOTProfilePaths)" + UseLLVM="$(MonoEnableLLVM)" + LLVMPath="$(MonoAotCrossDir)"> + <Output TaskParameter="CompiledAssemblies" ItemName="_AndroidAssembliesInternal" /> + </MonoAOTCompiler> + + <ItemGroup> + <_AndroidAssembliesInternal Include="@(_AOT_InternalForceInterpretAssemblies)" /> + </ItemGroup> + </Target> + + <Target Name="_AndroidGenerateAppBundle" DependsOnTargets="_AndroidGenerateRuntimeConfig"> + + <AndroidAppBuilderTask + RuntimeIdentifier="$(RuntimeIdentifier)" + ProjectName="$(AssemblyName)" + MonoRuntimeHeaders="$(MicrosoftNetCoreAppRuntimePackNativeDir)include\mono-2.0" + Assemblies="@(_AndroidAssembliesInternal)" + MainLibraryFileName="$(MainLibraryFileName)" + IncludeNetworkSecurityConfig="$(IncludeNetworkSecurityConfig)" + EnvironmentVariables="@(AndroidEnv)" + ForceAOT="$(RunAOTCompilation)" + ForceFullAOT="$(ForceFullAOT)" + ForceInterpreter="$(MonoForceInterpreter)" + StripDebugSymbols="False" + RuntimeComponents="$(RuntimeComponents)" + DiagnosticPorts="$(DiagnosticPorts)" + OutputDir="$(AndroidAppBundleDir)" + AppDir="$(AndroidAppDir)"> + <Output TaskParameter="ApkPackageId" PropertyName="ApkPackageId" /> + <Output TaskParameter="ApkBundlePath" PropertyName="ApkBundlePath" /> + </AndroidAppBuilderTask> + + <Message Importance="High" Text="PackageId: $(ApkPackageId)"/> + <Message Importance="High" Text="Instrumentation: net.dot.MonoRunner"/> + <Message Importance="High" Text="Apk: $(ApkBundlePath)"/> + </Target> + + <Target Name="_AfterAndroidBuildApp"> + + </Target> + + <Target Name="_AndroidGenerateRuntimeConfig" + Inputs="$(_AndroidRuntimeConfigFilePath)" + Outputs="$(_ParsedRuntimeConfigFilePath)" + Condition="Exists('$(_AndroidRuntimeConfigFilePath)')"> + <ItemGroup> + <_RuntimeConfigReservedProperties Include="RUNTIME_IDENTIFIER"/> + <_RuntimeConfigReservedProperties Include="APP_CONTEXT_BASE_DIRECTORY"/> + </ItemGroup> + + <RuntimeConfigParserTask + RuntimeConfigFile="$(_AndroidRuntimeConfigFilePath)" + OutputFile="$(_ParsedRuntimeConfigFilePath)" + RuntimeConfigReservedProperties="@(_RuntimeConfigReservedProperties)"> + </RuntimeConfigParserTask> + </Target> +</Project>
\ No newline at end of file diff --git a/src/mono/msbuild/apple/build/AppleApp.targets b/src/mono/msbuild/apple/build/AppleApp.targets index a431fe5ce61..470a84edecb 100644 --- a/src/mono/msbuild/apple/build/AppleApp.targets +++ b/src/mono/msbuild/apple/build/AppleApp.targets @@ -24,15 +24,7 @@ <_AppleRuntimeConfigFilePath Condition="'$(_AppleRuntimeConfigFilePath)' == ''">$([MSBuild]::NormalizePath($(AppleAppDir), '$(AssemblyName).runtimeconfig.json'))</_AppleRuntimeConfigFilePath> <_ParsedRuntimeConfigFilePath Condition="'$(_ParsedRuntimeConfigFilePath)' == ''">$([MSBuild]::NormalizePath($(AppleAppDir), 'runtimeconfig.bin'))</_ParsedRuntimeConfigFilePath> </PropertyGroup> - <!--<AppleAppDir Condition="'$(AppleAppDir)' == ''">$(OutputPath)</AppleAppDir> - - <AppleAppBundleDir Condition="'$(AppleAppBundleDir)' == ''">$([MSBuild]::NormalizeDirectory($(OutputPath), 'AppBundle'))</AppleAppBundleDir> - - <MainLibraryFileName Condition="'$(MainLibraryFileName)' == ''">$(TargetFileName)</MainLibraryFileName> - <AppleAppDir>$([MSBuild]::NormalizeDirectory($(AppleAppDir)))</AppleAppDir> - <AppleAppBundleDir>$([MSBuild]::NormalizeDirectory($(AppleAppBundleDir)))</AppleAppBundleDir> ---> <RemoveDir Directories="$(AppleAppBundleDir)" /> </Target> @@ -83,11 +75,6 @@ <ItemGroup> <_AotExcludeAssemblies Include="*System.Runtime.WindowsRuntime.dll" /> - - <DebugTestItem Include="@(_AppleAssembliesInternal)"> - <_InternalForceInterpret>%(_AppleAssembliesInternal._InternalForceInterpret)</_InternalForceInterpret> - <_IsNative>%(_AppleAssembliesInternal._IsNative)</_IsNative> - </DebugTestItem> <_AotInputAssemblies Include="@(_AppleAssembliesInternal)" Condition="'%(_AppleAssembliesInternal._InternalForceInterpret)' != 'true'"> diff --git a/src/mono/nuget/Microsoft.NET.Runtime.MonoTargets.Sdk/Sdk/MonoTargetsTasks.props.in b/src/mono/nuget/Microsoft.NET.Runtime.MonoTargets.Sdk/Sdk/MonoTargetsTasks.props.in index 4ef325f421b..ad5db32cbf5 100644 --- a/src/mono/nuget/Microsoft.NET.Runtime.MonoTargets.Sdk/Sdk/MonoTargetsTasks.props.in +++ b/src/mono/nuget/Microsoft.NET.Runtime.MonoTargets.Sdk/Sdk/MonoTargetsTasks.props.in @@ -7,6 +7,8 @@ <UsingTask TaskName="ILStrip" AssemblyFile="$(MonoTargetsTasksAssemblyPath)" /> <!-- RuntimeConfigParser --> <UsingTask TaskName="RuntimeConfigParserTask" AssemblyFile="$(MonoTargetsTasksAssemblyPath)" /> + <!-- NetTraceToMibcConverter --> + <UsingTask TaskName="NetTraceToMibcConverter" AssemblyFile="$(MonoTargetsTasksAssemblyPath)" /> <!-- Specific instances of JsonToItemsTaskFactory --> <!-- MonoRuntimeComponentManifestReadTask --> <UsingTask TaskName="MonoRuntimeComponentManifestReadTask" TaskFactory="JsonToItemsTaskFactory.JsonToItemsTaskFactory" AssemblyFile="$(MonoTargetsTasksAssemblyPath)"> diff --git a/src/tasks/AndroidAppBuilder/AndroidAppBuilder.cs b/src/tasks/AndroidAppBuilder/AndroidAppBuilder.cs index 66eef2cd542..0f409c1745f 100644 --- a/src/tasks/AndroidAppBuilder/AndroidAppBuilder.cs +++ b/src/tasks/AndroidAppBuilder/AndroidAppBuilder.cs @@ -39,6 +39,11 @@ public class AndroidAppBuilderTask : Task public bool ForceAOT { get; set; } /// <summary> + /// Indicates if we want to AOT all assemblies or not + /// </summary> + public bool ForceFullAOT { get; set; } + + /// <summary> /// Static linked runtime /// </summary> public bool StaticLinkedRuntime { get; set; } @@ -111,6 +116,7 @@ public class AndroidAppBuilderTask : Task apkBuilder.KeyStorePath = KeyStorePath; apkBuilder.ForceInterpreter = ForceInterpreter; apkBuilder.ForceAOT = ForceAOT; + apkBuilder.ForceFullAOT = ForceFullAOT; apkBuilder.EnvironmentVariables = EnvironmentVariables; apkBuilder.StaticLinkedRuntime = StaticLinkedRuntime; apkBuilder.RuntimeComponents = RuntimeComponents; diff --git a/src/tasks/AndroidAppBuilder/ApkBuilder.cs b/src/tasks/AndroidAppBuilder/ApkBuilder.cs index e8eeac67399..4cfc8d0d1ca 100644 --- a/src/tasks/AndroidAppBuilder/ApkBuilder.cs +++ b/src/tasks/AndroidAppBuilder/ApkBuilder.cs @@ -28,6 +28,7 @@ public class ApkBuilder public string? KeyStorePath { get; set; } public bool ForceInterpreter { get; set; } public bool ForceAOT { get; set; } + public bool ForceFullAOT { get; set; } public ITaskItem[] EnvironmentVariables { get; set; } = Array.Empty<ITaskItem>(); public bool InvariantGlobalization { get; set; } public bool EnableRuntimeLogging { get; set; } @@ -342,6 +343,11 @@ public class ApkBuilder } } + if (ForceFullAOT) + { + defines.AppendLine("add_definitions(-DFULL_AOT=1)"); + } + if (!string.IsNullOrEmpty(DiagnosticPorts)) { defines.AppendLine("add_definitions(-DDIAGNOSTIC_PORTS=\"" + DiagnosticPorts + "\")"); diff --git a/src/tasks/AndroidAppBuilder/Templates/monodroid.c b/src/tasks/AndroidAppBuilder/Templates/monodroid.c index 302324efd82..1d8d3f1bd52 100644 --- a/src/tasks/AndroidAppBuilder/Templates/monodroid.c +++ b/src/tasks/AndroidAppBuilder/Templates/monodroid.c @@ -273,9 +273,14 @@ mono_droid_runtime_init (const char* executable, int managed_argc, char* managed LOG_INFO("AOT Enabled"); #if STATIC_AOT register_aot_modules(); -#endif +#endif // STATIC_AOT + +#if FULL_AOT mono_jit_set_aot_mode(MONO_AOT_MODE_FULL); -#endif +#else + mono_jit_set_aot_mode(MONO_AOT_MODE_NORMAL); +#endif // FULL_AOT +#endif // FORCE_INTERPRETER MonoDomain *domain = mono_jit_init_version ("dotnet.android", "mobile"); assert (domain); diff --git a/src/tasks/AotCompilerTask/MonoAOTCompiler.cs b/src/tasks/AotCompilerTask/MonoAOTCompiler.cs index ea18150ac44..291af85bde4 100644 --- a/src/tasks/AotCompilerTask/MonoAOTCompiler.cs +++ b/src/tasks/AotCompilerTask/MonoAOTCompiler.cs @@ -112,21 +112,6 @@ public class MonoAOTCompiler : Microsoft.Build.Utilities.Task public bool UseDwarfDebug { get; set; } /// <summary> - /// Path to Dotnet PGO binary (dotnet-pgo) - /// </summary> - public string? PgoBinaryPath { get; set; } - - /// <summary> - /// NetTrace file to use when invoking dotnet-pgo for - /// </summary> - public string? NetTracePath { get; set; } - - /// <summary> - /// Directory containing all assemblies referenced in a .nettrace collected from a separate device needed by dotnet-pgo. Necessary for mobile platforms. - /// </summary> - public ITaskItem[] ReferenceAssemblyPathsForPGO { get; set; } = Array.Empty<ITaskItem>(); - - /// <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; } @@ -287,31 +272,6 @@ public class MonoAOTCompiler : Microsoft.Build.Utilities.Task if (!Directory.Exists(IntermediateOutputPath)) Directory.CreateDirectory(IntermediateOutputPath); - if (!string.IsNullOrEmpty(NetTracePath)) - { - if (!File.Exists(NetTracePath)) - { - Log.LogError($"{nameof(NetTracePath)}='{NetTracePath}' doesn't exist"); - return false; - } - if (!File.Exists(PgoBinaryPath)) - { - Log.LogError($"NetTracePath was provided, but {nameof(PgoBinaryPath)}='{PgoBinaryPath}' doesn't exist"); - return false; - } - if (ReferenceAssemblyPathsForPGO.Length == 0) - { - Log.LogError($"NetTracePath was provided, but {nameof(ReferenceAssemblyPathsForPGO)} is empty"); - return false; - } - foreach (var refAsmItem in ReferenceAssemblyPathsForPGO) - { - string? fullPath = refAsmItem.GetMetadata("FullPath"); - if (!File.Exists(fullPath)) - throw new LogAsErrorException($"ReferenceAssembly '{fullPath}' doesn't exist"); - } - } - if (AotProfilePath != null) { foreach (var path in AotProfilePath) @@ -438,48 +398,6 @@ public class MonoAOTCompiler : Microsoft.Build.Utilities.Task } } - private bool ProcessNettrace(string netTraceFile) - { - var outputMibcPath = Path.Combine(OutputDir, Path.ChangeExtension(Path.GetFileName(netTraceFile), ".mibc")); - - if (_cache!.Enabled) - { - string hash = Utils.ComputeHash(netTraceFile); - if (!_cache!.UpdateAndCheckHasFileChanged($"-mibc-source-file-{Path.GetFileName(netTraceFile)}", hash)) - { - Log.LogMessage(MessageImportance.Low, $"Skipping generating {outputMibcPath} from {netTraceFile} because source file hasn't changed"); - return true; - } - else - { - Log.LogMessage(MessageImportance.Low, $"Generating {outputMibcPath} from {netTraceFile} because the source file's hash has changed."); - } - } - - StringBuilder pgoArgsStr = new StringBuilder(string.Empty); - pgoArgsStr.Append($"create-mibc"); - pgoArgsStr.Append($" --trace {netTraceFile} "); - foreach (var refAsmItem in ReferenceAssemblyPathsForPGO) - { - string? fullPath = refAsmItem.GetMetadata("FullPath"); - pgoArgsStr.Append($" --reference \"{fullPath}\" "); - } - pgoArgsStr.Append($" --output {outputMibcPath} "); - (int exitCode, string output) = Utils.TryRunProcess(Log, - PgoBinaryPath!, - pgoArgsStr.ToString()); - - if (exitCode != 0) - { - Log.LogError($"dotnet-pgo({PgoBinaryPath}) failed for {netTraceFile}:{output}"); - return false; - } - - MibcProfilePath = MibcProfilePath.Append(outputMibcPath).ToArray(); - Log.LogMessage(MessageImportance.Low, $"Generated {outputMibcPath} from {PgoBinaryPath}"); - return true; - } - private bool ExecuteInternal() { if (!ProcessAndValidateArguments()) @@ -498,9 +416,6 @@ public class MonoAOTCompiler : Microsoft.Build.Utilities.Task _cache = new FileCache(CacheFilePath, Log); - if (!string.IsNullOrEmpty(NetTracePath) && !ProcessNettrace(NetTracePath)) - return false; - List<PrecompileArguments> argsList = new(); foreach (var assemblyItem in _assembliesToCompile) argsList.Add(GetPrecompileArgumentsFor(assemblyItem, monoPaths)); @@ -1150,132 +1065,6 @@ public class MonoAOTCompiler : Microsoft.Build.Utilities.Task } } -internal sealed class FileCache -{ - private CompilerCache? _newCache; - private CompilerCache? _oldCache; - - public bool Enabled { get; } - public TaskLoggingHelper Log { get; } - - public FileCache(string? cacheFilePath, TaskLoggingHelper log) - { - Log = log; - if (string.IsNullOrEmpty(cacheFilePath)) - { - Log.LogMessage(MessageImportance.Low, $"Disabling cache, because CacheFilePath is not set"); - return; - } - - Enabled = true; - if (File.Exists(cacheFilePath)) - { - _oldCache = (CompilerCache?)JsonSerializer.Deserialize(File.ReadAllText(cacheFilePath), - typeof(CompilerCache), - new JsonSerializerOptions()); - } - - _oldCache ??= new(); - _newCache = new(_oldCache.FileHashes); - } - - public bool UpdateAndCheckHasFileChanged(string filePath, string newHash) - { - if (!Enabled) - throw new InvalidOperationException("Cache is not enabled. Make sure the cache file path is set"); - - _newCache!.FileHashes[filePath] = newHash; - return !_oldCache!.FileHashes.TryGetValue(filePath, out string? oldHash) || oldHash != newHash; - } - - public bool ShouldCopy(ProxyFile proxyFile, [NotNullWhen(true)] out string? cause) - { - if (!Enabled) - throw new InvalidOperationException("Cache is not enabled. Make sure the cache file path is set"); - - cause = null; - - string newHash = Utils.ComputeHash(proxyFile.TempFile); - _newCache!.FileHashes[proxyFile.TargetFile] = newHash; - - if (!File.Exists(proxyFile.TargetFile)) - { - cause = $"the output file didn't exist"; - return true; - } - - string? oldHash; - if (!_oldCache!.FileHashes.TryGetValue(proxyFile.TargetFile, out oldHash)) - oldHash = Utils.ComputeHash(proxyFile.TargetFile); - - if (oldHash != newHash) - { - cause = $"hash for the file changed"; - return true; - } - - return false; - } - - public bool Save(string? cacheFilePath) - { - if (!Enabled || string.IsNullOrEmpty(cacheFilePath)) - return false; - - var json = JsonSerializer.Serialize (_newCache, new JsonSerializerOptions { WriteIndented = true }); - File.WriteAllText(cacheFilePath!, json); - return true; - } - - public ProxyFile NewFile(string targetFile) => new ProxyFile(targetFile, this); -} - -internal sealed class ProxyFile -{ - public string TargetFile { get; } - public string TempFile { get; } - private FileCache _cache; - - public ProxyFile(string targetFile, FileCache cache) - { - _cache = cache; - this.TargetFile = targetFile; - this.TempFile = _cache.Enabled ? targetFile + ".tmp" : targetFile; - } - - public bool CopyOutputFileIfChanged() - { - if (!_cache.Enabled) - return true; - - if (!File.Exists(TempFile)) - throw new LogAsErrorException($"Could not find the temporary file {TempFile} for target file {TargetFile}. Look for any errors/warnings generated earlier in the build."); - - try - { - if (!_cache.ShouldCopy(this, out string? cause)) - { - _cache.Log.LogMessage(MessageImportance.Low, $"Skipping copying over {TargetFile} as the contents are unchanged"); - return false; - } - - if (File.Exists(TargetFile)) - File.Delete(TargetFile); - - File.Copy(TempFile, TargetFile); - - _cache.Log.LogMessage(MessageImportance.Low, $"Copying {TempFile} to {TargetFile} because {cause}"); - return true; - } - finally - { - _cache.Log.LogMessage(MessageImportance.Low, $"Deleting temp file {TempFile}"); - File.Delete(TempFile); - } - } - -} - public enum MonoAotMode { Normal, @@ -1306,13 +1095,3 @@ public enum MonoAotModulesTableLanguage C, ObjC } - -internal sealed class CompilerCache -{ - public CompilerCache() => FileHashes = new(); - public CompilerCache(IDictionary<string, string> oldHashes) - => FileHashes = new(oldHashes); - - [JsonPropertyName("file_hashes")] - public ConcurrentDictionary<string, string> FileHashes { get; set; } -} diff --git a/src/tasks/AotCompilerTask/MonoAOTCompiler.csproj b/src/tasks/AotCompilerTask/MonoAOTCompiler.csproj index 87a6349afea..28e5cc265c8 100644 --- a/src/tasks/AotCompilerTask/MonoAOTCompiler.csproj +++ b/src/tasks/AotCompilerTask/MonoAOTCompiler.csproj @@ -18,6 +18,9 @@ </ItemGroup> <ItemGroup> <Compile Include="MonoAOTCompiler.cs" /> + <Compile Include="..\Common\CompilerCache.cs" /> + <Compile Include="..\Common\ProxyFile.cs" /> + <Compile Include="..\Common\FileCache.cs" /> <Compile Include="..\Common\Utils.cs" /> <Compile Include="..\Common\LogAsErrorException.cs" /> <Compile Include="$(RepoRoot)src\libraries\System.Private.CoreLib\src\System\Diagnostics\CodeAnalysis\NullableAttributes.cs" Condition="'$(TargetFrameworkIdentifier)' == '.NETFramework'" /> diff --git a/src/tasks/Common/CompilerCache.cs b/src/tasks/Common/CompilerCache.cs new file mode 100644 index 00000000000..1d281255119 --- /dev/null +++ b/src/tasks/Common/CompilerCache.cs @@ -0,0 +1,21 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Collections.Concurrent; +using System.Text.Json; +using System.Text.Json.Serialization; +using Microsoft.Build.Utilities; + +#nullable enable + +internal sealed class CompilerCache +{ + public CompilerCache() => FileHashes = new(); + public CompilerCache(IDictionary<string, string> oldHashes) + => FileHashes = new(oldHashes); + + [JsonPropertyName("file_hashes")] + public ConcurrentDictionary<string, string> FileHashes { get; set; } +} diff --git a/src/tasks/Common/FileCache.cs b/src/tasks/Common/FileCache.cs new file mode 100644 index 00000000000..5f090693f7c --- /dev/null +++ b/src/tasks/Common/FileCache.cs @@ -0,0 +1,93 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Collections.Concurrent; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Text.Json; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; + +#nullable enable + +internal sealed class FileCache +{ + private CompilerCache? _newCache; + private CompilerCache? _oldCache; + + public bool Enabled { get; } + public TaskLoggingHelper Log { get; } + + public FileCache(string? cacheFilePath, TaskLoggingHelper log) + { + Log = log; + if (string.IsNullOrEmpty(cacheFilePath)) + { + Log.LogMessage(MessageImportance.Low, $"Disabling cache, because CacheFilePath is not set"); + return; + } + + //Enabled = true; + if (File.Exists(cacheFilePath)) + { + _oldCache = (CompilerCache?)JsonSerializer.Deserialize(File.ReadAllText(cacheFilePath), + typeof(CompilerCache), + new JsonSerializerOptions()); + } + + _oldCache ??= new(); + _newCache = new(_oldCache.FileHashes); + } + + public bool UpdateAndCheckHasFileChanged(string filePath, string newHash) + { + if (!Enabled) + throw new InvalidOperationException("Cache is not enabled. Make sure the cache file path is set"); + + _newCache!.FileHashes[filePath] = newHash; + return !_oldCache!.FileHashes.TryGetValue(filePath, out string? oldHash) || oldHash != newHash; + } + + public bool ShouldCopy(ProxyFile proxyFile, [NotNullWhen(true)] out string? cause) + { + if (!Enabled) + throw new InvalidOperationException("Cache is not enabled. Make sure the cache file path is set"); + + cause = null; + + string newHash = Utils.ComputeHash(proxyFile.TempFile); + _newCache!.FileHashes[proxyFile.TargetFile] = newHash; + + if (!File.Exists(proxyFile.TargetFile)) + { + cause = $"the output file didn't exist"; + return true; + } + + string? oldHash; + if (!_oldCache!.FileHashes.TryGetValue(proxyFile.TargetFile, out oldHash)) + oldHash = Utils.ComputeHash(proxyFile.TargetFile); + + if (oldHash != newHash) + { + cause = $"hash for the file changed"; + return true; + } + + return false; + } + + public bool Save(string? cacheFilePath) + { + if (!Enabled || string.IsNullOrEmpty(cacheFilePath)) + return false; + + var json = JsonSerializer.Serialize (_newCache, new JsonSerializerOptions { WriteIndented = true }); + File.WriteAllText(cacheFilePath!, json); + return true; + } + + public ProxyFile NewFile(string targetFile) => new ProxyFile(targetFile, this); +} diff --git a/src/tasks/Common/ProxyFile.cs b/src/tasks/Common/ProxyFile.cs new file mode 100644 index 00000000000..ec38b3eb3c6 --- /dev/null +++ b/src/tasks/Common/ProxyFile.cs @@ -0,0 +1,56 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Collections.Concurrent; +using System.IO; +using System.Text.Json; +using Microsoft.Build.Framework; + +#nullable enable + +internal sealed class ProxyFile +{ + public string TargetFile { get; } + public string TempFile { get; } + private FileCache _cache; + + public ProxyFile(string targetFile, FileCache cache) + { + _cache = cache; + this.TargetFile = targetFile; + this.TempFile = _cache.Enabled ? targetFile + ".tmp" : targetFile; + } + + public bool CopyOutputFileIfChanged() + { + if (!_cache.Enabled) + return true; + + if (!File.Exists(TempFile)) + throw new LogAsErrorException($"Could not find the temporary file {TempFile} for target file {TargetFile}. Look for any errors/warnings generated earlier in the build."); + + try + { + if (!_cache.ShouldCopy(this, out string? cause)) + { + _cache.Log.LogMessage(MessageImportance.Low, $"Skipping copying over {TargetFile} as the contents are unchanged"); + return false; + } + + if (File.Exists(TargetFile)) + File.Delete(TargetFile); + + File.Copy(TempFile, TargetFile); + + _cache.Log.LogMessage(MessageImportance.Low, $"Copying {TempFile} to {TargetFile} because {cause}"); + return true; + } + finally + { + _cache.Log.LogMessage(MessageImportance.Low, $"Deleting temp file {TempFile}"); + File.Delete(TempFile); + } + } +} diff --git a/src/tasks/MonoTargetsTasks/MonoTargetsTasks.csproj b/src/tasks/MonoTargetsTasks/MonoTargetsTasks.csproj index d470c822c08..a37d59c75ec 100644 --- a/src/tasks/MonoTargetsTasks/MonoTargetsTasks.csproj +++ b/src/tasks/MonoTargetsTasks/MonoTargetsTasks.csproj @@ -29,6 +29,8 @@ <Compile Include="..\Common\Utils.cs" /> <Compile Include="RuntimeConfigParser\RuntimeConfigParser.cs" /> <Compile Include="JsonToItemsTaskFactory\JsonToItemsTaskFactory.cs" /> + <Compile Include="NetTraceToMibcConverterTask\NetTraceToMibcConverter.cs" /> + <Compile Include="..\Common\LogAsErrorException.cs" /> <Compile Include="$(RepoRoot)src\libraries\System.Private.CoreLib\src\System\Diagnostics\CodeAnalysis\NullableAttributes.cs" Condition="'$(TargetFrameworkIdentifier)' == '.NETFramework'" /> </ItemGroup> diff --git a/src/tasks/MonoTargetsTasks/NetTraceToMibcConverterTask/NetTraceToMibcConverter.cs b/src/tasks/MonoTargetsTasks/NetTraceToMibcConverterTask/NetTraceToMibcConverter.cs new file mode 100644 index 00000000000..205b115a468 --- /dev/null +++ b/src/tasks/MonoTargetsTasks/NetTraceToMibcConverterTask/NetTraceToMibcConverter.cs @@ -0,0 +1,117 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Collections.Concurrent; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; +using System.Text.Json.Serialization; + +#nullable enable + +public class NetTraceToMibcConverter : ToolTask +{ + /// <summary> + /// List of all assemblies referenced in a .nettrace file. Important when you run traces against an executable on a different machine / device + /// </summary> + [Required] + public ITaskItem[] Assemblies { get; set; } = Array.Empty<ITaskItem>(); + + /// <summary> + /// Path to .nettrace file which should be converted to .mibc + /// </summary> + [Required] + public string NetTraceFilePath { get; set; } = ""; + + /// <summary> + /// Directory where the mibc file will be placed + /// </summary> + [NotNull] + [Required] + public string? OutputDir { get; set; } + + /// <summary> + /// The path to the mibc file generated from the converter. + /// </summary> + [Output] + public string MibcFilePath { get; set; } = ""; + + public override string ToolExe { get; set; } = ""; + + protected override string ToolName { get; } = "NetTraceToMibcConverter"; + + protected override string GenerateFullPathToTool() + { + return ToolPath; + } + + protected override bool ValidateParameters() + { + if (string.IsNullOrEmpty(ToolPath)) + { + Log.LogError($"{nameof(ToolPath)}='{ToolPath}' must be specified."); + return false; + } + + if (string.IsNullOrEmpty(ToolExe)) + { + ToolExe = (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) ? "dotnet-pgo.exe" : "dotnet-pgo"; + } + + string mibcConverterBinaryPath = Path.Combine(ToolPath, ToolExe); + + if (!File.Exists(mibcConverterBinaryPath)) + { + Log.LogError($"{nameof(mibcConverterBinaryPath)}='{mibcConverterBinaryPath}' doesn't exist."); + return false; + } + + if (Assemblies.Length == 0) + { + Log.LogError($"'{nameof(Assemblies)}' is required."); + return false; + } + + if (!File.Exists(NetTraceFilePath)) + { + Log.LogError($"{nameof(NetTraceFilePath)}='{NetTraceFilePath}' doesn't exist"); + return false; + } + + foreach (var asmItem in Assemblies) + { + string? fullPath = asmItem.GetMetadata("FullPath"); + if (!File.Exists(fullPath)) + throw new LogAsErrorException($"Could not find {fullPath} to AOT"); + } + + return !Log.HasLoggedErrors; + } + + protected override string GenerateCommandLineCommands() + { + MibcFilePath = Path.Combine(OutputDir, Path.ChangeExtension(Path.GetFileName(NetTraceFilePath), ".mibc")); + + StringBuilder mibcConverterArgsStr = new StringBuilder("create-mibc"); + mibcConverterArgsStr.Append($" --trace \"{NetTraceFilePath}\" "); + + foreach (var refAsmItem in Assemblies) + { + string? fullPath = refAsmItem.GetMetadata("FullPath"); + mibcConverterArgsStr.Append($" --reference \"{fullPath}\" "); + } + + mibcConverterArgsStr.Append($" --output \"{MibcFilePath}\""); + + return mibcConverterArgsStr.ToString(); + } +} |