1
0
Fork 0
mirror of https://github.com/VSadov/Satori.git synced 2025-06-09 17:44:48 +09:00

[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>
This commit is contained in:
Steve Pfister 2022-08-04 10:02:13 -07:00 committed by GitHub
parent c8e6d67eee
commit 209c040d26
Signed by: github
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 626 additions and 351 deletions

View file

@ -115,7 +115,8 @@
<MonoAOTCompilerTasksAssemblyPath>$([MSBuild]::NormalizePath('$(MonoAOTCompilerDir)', 'MonoAOTCompiler.dll'))</MonoAOTCompilerTasksAssemblyPath>
<MonoTargetsTasksAssemblyPath>$([MSBuild]::NormalizePath('$(MonoTargetsTasksDir)', 'MonoTargetsTasks.dll'))</MonoTargetsTasksAssemblyPath>
<TestExclusionListTasksAssemblyPath>$([MSBuild]::NormalizePath('$(TestExclusionListTasksDir)', 'TestExclusionListTasks.dll'))</TestExclusionListTasksAssemblyPath>
<ILAsmToolPath Condition="'$(DotNetBuildFromSource)' == 'true' or '$(BuildArchitecture)' == 's390x' or '$(BuildArchitecture)' == 'ppc64le'">$([MSBuild]::NormalizeDirectory('$(ArtifactsBinDir)', 'coreclr', '$(TargetOS).$(TargetArchitecture).$(Configuration)'))</ILAsmToolPath>
<CoreCLRToolPath>$([MSBuild]::NormalizeDirectory('$(ArtifactsBinDir)', 'coreclr', '$(TargetOS).$(TargetArchitecture).$(Configuration)'))</CoreCLRToolPath>
<ILAsmToolPath Condition="'$(DotNetBuildFromSource)' == 'true' or '$(BuildArchitecture)' == 's390x' or '$(BuildArchitecture)' == 'ppc64le'">$(CoreCLRToolPath)</ILAsmToolPath>
</PropertyGroup>
<PropertyGroup Label="CalculateConfiguration">

View file

@ -61,7 +61,7 @@
<DefaultMonoSubsets Condition="'$(MonoAOTEnableLLVM)' == 'true' and '$(MonoAOTLLVMDir)' == ''">mono.llvm+</DefaultMonoSubsets>
<DefaultMonoSubsets Condition="'$(TargetOS)' == 'Browser'">$(DefaultMonoSubsets)mono.wasmruntime+</DefaultMonoSubsets>
<DefaultMonoSubsets Condition="'$(MonoCrossAOTTargetOS)' != ''">$(DefaultMonoSubsets)mono.aotcross+</DefaultMonoSubsets>
<DefaultMonoSubsets>$(DefaultMonoSubsets)mono.runtime+mono.corelib+mono.packages+</DefaultMonoSubsets>
<DefaultMonoSubsets>$(DefaultMonoSubsets)mono.runtime+mono.corelib+mono.packages+mono.tools+</DefaultMonoSubsets>
<DefaultMonoSubsets Condition="'$(TargetsMobile)' != 'true'">$(DefaultMonoSubsets)host+</DefaultMonoSubsets>
<DefaultLibrariesSubsets Condition="'$(BuildTargetFramework)' == '$(NetCoreAppCurrent)' or
@ -136,6 +136,7 @@
<SubsetName Include="Mono.AotCross" Description="The cross-compiler runtime for Mono AOT." />
<SubsetName Include="Mono.CoreLib" Description="The managed System.Private.CoreLib library for Mono." />
<SubsetName Include="Mono.Packages" Description="The projects that produce NuGet packages for the Mono runtime." />
<SubsetName Include="Mono.Tools" Description="Tooling that helps support Mono development and testing." />
<SubsetName Include="Mono.WasmRuntime" Description="The WebAssembly runtime." />
<SubsetName Include="Mono.MsCorDbi" Description="The implementation of ICorDebug interface." />
<SubsetName Include="Mono.Workloads" OnDemand="true" Description="Builds the installers and the insertion metadata for Blazor workloads." />
@ -358,6 +359,10 @@
<ProjectToBuild Include="$(MonoProjectRoot)System.Private.CoreLib\System.Private.CoreLib.csproj" Category="mono" />
</ItemGroup>
<ItemGroup Condition="$(_subset.Contains('+mono.tools+'))">
<ProjectToBuild Include="$(CoreClrProjectRoot)tools\dotnet-pgo\dotnet-pgo.csproj;" Category="mono" />
</ItemGroup>
<ItemGroup Condition="$(_subset.Contains('+mono.workloads+'))">
<ProjectToBuild Include="$(WorkloadsProjectRoot)\workloads.csproj" Category="mono" />
</ItemGroup>

View file

@ -0,0 +1,74 @@
<Project>
<PropertyGroup>
<BundleTestAppTargets>$(BundleTestAppTargets);BundleTestAndroidApp</BundleTestAppTargets>
</PropertyGroup>
<Import Project="$(MonoProjectRoot)\msbuild\android\build\AndroidApp.props" />
<Import Project="$(MonoProjectRoot)\msbuild\android\build\AndroidApp.InTree.targets" />
<PropertyGroup>
<AndroidBuildAppDependsOn>PrepareForAndroidBuildApp;$(AndroidBuildAppDependsOn);_CopyTestArchive</AndroidBuildAppDependsOn>
<BundleTestAndroidAppDependsOn>AndroidBuildApp</BundleTestAndroidAppDependsOn>
</PropertyGroup>
<!-- Target that kicks off the whole test build and run flow -->
<Target Name="BundleTestAndroidApp" DependsOnTargets="$(BundleTestAndroidAppDependsOn)" />
<Target Name="PrepareForAndroidBuildApp">
<Error Condition="!Exists('$(MicrosoftNetCoreAppRuntimePackRidDir)')" Text="MicrosoftNetCoreAppRuntimePackRidDir=$(MicrosoftNetCoreAppRuntimePackRidDir) doesn't exist" />
<WriteLinesToFile File="$(PublishDir)xunit-excludes.txt" Lines="$(XunitExcludesTxtFileContent)" Overwrite="true" />
<PropertyGroup>
<MainLibraryFileName Condition="'$(MainLibraryFileName)' == ''">AndroidTestRunner.dll</MainLibraryFileName>
<AndroidAppDir>$(PublishDir)</AndroidAppDir>
<AndroidAppBundleDir>$(BundleDir)</AndroidAppBundleDir>
</PropertyGroup>
<ItemGroup>
<AndroidEnv Condition="'$(XUnitSingleThreadedMode)' == 'true'" Include="XUNIT_SINGLE_THREADED">
<Value>1</Value>
</AndroidEnv>
<AndroidEnv Condition="'$(XUnitUseRandomizedTestOrderer)' == 'true'" Include="XUNIT_RANDOM_ORDER_SEED">
<Value>1883302047</Value>
</AndroidEnv>
<AndroidEnv Condition="'$(XUnitSingleThreadedMode)' == 'true'" Include="XUNIT_VERBOSE">
<Value>1</Value>
</AndroidEnv>
</ItemGroup>
<ItemGroup>
<AndroidAssembliesToBundle Include="@(NativeLibraries->'$(PublishDir)%(Identity)')">
<_InternalForceInterpret>true</_InternalForceInterpret>
<_IsNative>true</_IsNative>
</AndroidAssembliesToBundle>
<_PublishAssemblies Include="$(PublishDir)\**\*.dll" Exclude="$(PublishDir)\**\*.resources.dll" />
<_SatelliteAssemblies Include="$(PublishDir)\**\*.resources.dll" />
<AndroidAssembliesToBundle Include="@(_PublishAssemblies)">
<_InternalForceInterpret Condition="'$(UseMonoJustInterp)' == 'true' and '%(FileName)%(Extension)' != 'System.Private.CoreLib.dll'">true</_InternalForceInterpret>
<_IsNative>false</_IsNative>
</AndroidAssembliesToBundle>
<AndroidNativeFilesToBundle Include="$(PublishDir)\**\*.*" Exclude="$(PublishDir)\*.dll" />
</ItemGroup>
</Target>
<Target Name="_CopyTestArchive"
Condition="'$(ArchiveTests)' == 'true' and '$(IgnoreForCI)' != 'true'">
<Error Condition="'$(TestArchiveTestsDir)' == ''" Text="TestArchiveTestsDir property to archive the test folder must be set." />
<Message Importance="High" Text="PackageId: $(ApkPackageId)"/>
<Message Importance="High" Text="Instrumentation: net.dot.MonoRunner"/>
<Message Importance="High" Text="Apk: $(ApkBundlePath)"/>
<Copy SourceFiles="$(ApkBundlePath)"
DestinationFolder="$(TestArchiveTestsDir)"
SkipUnchangedFiles="true"
Condition="'$(ArchiveTests)' == 'true' and '$(IgnoreForCI)' != 'true'" />
</Target>
</Project>

View file

@ -8,7 +8,6 @@
<RunScriptOutputPath>$([MSBuild]::NormalizePath('$(BundleDir)', '$(RunScriptOutputName)'))</RunScriptOutputPath>
<PublishingTestsRun>true</PublishingTestsRun>
<BundleTestAppTargets>BundleTestAndroidApp</BundleTestAppTargets>
<PublishTestAsSelfContainedDependsOn>Publish</PublishTestAsSelfContainedDependsOn>
</PropertyGroup>
@ -16,6 +15,11 @@
<RunAOTCompilation Condition="'$(TargetOS)' == 'iOS' or '$(TargetOS)' == 'tvOS'">true</RunAOTCompilation>
</PropertyGroup>
<PropertyGroup>
<DotnetPgoToolDir>$([MSBuild]::NormalizeDirectory('$(CoreCLRToolPath)', 'dotnet-pgo'))</DotnetPgoToolDir>
<DotnetPgoToolPath>$([MSBuild]::NormalizePath('$(DotnetPgoToolDir)', 'dotnet-pgo'))</DotnetPgoToolPath>
</PropertyGroup>
<PropertyGroup Condition="'$(EnableAggressiveTrimming)' == 'true' or '$(EnableSoftTrimming)' == 'true'">
<PublishTrimmed>true</PublishTrimmed>
<!-- Suppress linker warnings as these are tests -->
@ -39,6 +43,10 @@
<AdditionalXHarnessArguments Condition="'$(ExpectedExitCode)' != ''">$(AdditionalXHarnessArguments) --expected-exit-code $(ExpectedExitCode)</AdditionalXHarnessArguments>
</PropertyGroup>
<PropertyGroup>
<DiagnosticPorts Condition="'$(DiagnosticStartupMode)' != ''">$(DiagnosticPorts),$(DiagnosticStartupMode)</DiagnosticPorts>
</PropertyGroup>
<PropertyGroup Condition="'$(TargetOS)' == 'Android'">
<!-- The -arg flag for xharness passes the arguments along to the instrumentation app -->
<AdditionalXHarnessArguments Condition="'$(XUnitMethodName)' != ''">$(AdditionalXHarnessArguments) --arg=-m=$(XUnitMethodName)</AdditionalXHarnessArguments>
@ -55,9 +63,8 @@
<Compile Include="$(RepoRoot)src\libraries\Common\tests\Tests\RandomizedTestOrderAssemblyInfo.cs" />
</ItemGroup>
<UsingTask Condition="'$(RunAOTCompilation)' == 'true'" TaskName="MonoAOTCompiler" AssemblyFile="$(MonoAOTCompilerTasksAssemblyPath)" />
<Import Condition="'$(RunAOTCompilation)' == 'true'" Project="$(MonoAOTCompilerDir)MonoAOTCompiler.props" />
<Import Project="$(MSBuildThisFileDirectory)tests.android.targets"
Condition="'$(TargetOS)' == 'Android'" />
<Import Project="$(MSBuildThisFileDirectory)tests.ioslike.targets"
Condition="'$(TargetsAppleMobile)' == 'true'" />
<Import Project="$(MSBuildThisFileDirectory)tests.wasm.targets"
@ -67,115 +74,6 @@
<_MobileIntermediateOutputPath>$(IntermediateOutputPath)mobile</_MobileIntermediateOutputPath>
</PropertyGroup>
<UsingTask TaskName="RuntimeConfigParserTask"
AssemblyFile="$(MonoTargetsTasksAssemblyPath)"
Condition="'$(MonoTargetsTasksAssemblyPath)' != ''" />
<Target Name="GenerateRuntimeConfig" Condition="'$(TargetOS)' != 'Browser'"
Inputs="$(PublishDir)$(AssemblyName).runtimeconfig.json"
Outputs="$(PublishDir)runtimeconfig.bin">
<PropertyGroup>
<RuntimeConfigFilePath>$(PublishDir)$(AssemblyName).runtimeconfig.json</RuntimeConfigFilePath>
<ParsedRuntimeConfigFilePath>$(PublishDir)runtimeconfig.bin</ParsedRuntimeConfigFilePath>
</PropertyGroup>
<ItemGroup>
<RuntimeConfigReservedProperties Include="RUNTIME_IDENTIFIER"/>
<RuntimeConfigReservedProperties Include="APP_CONTEXT_BASE_DIRECTORY"/>
</ItemGroup>
<!-- Parse runtimeconfig.template.json file -->
<RuntimeConfigParserTask
RuntimeConfigFile="$(RuntimeConfigFilePath)"
OutputFile="$(ParsedRuntimeConfigFilePath)"
RuntimeConfigReservedProperties="@(RuntimeConfigReservedProperties)">
</RuntimeConfigParserTask>
</Target>
<!-- Generate a self-contained app bundle for Android with tests. -->
<UsingTask Condition="'$(TargetOS)' == 'Android'"
TaskName="AndroidAppBuilderTask"
AssemblyFile="$(AndroidAppBuilderTasksAssemblyPath)" />
<Target Condition="'$(TargetOS)' == 'Android'" Name="BundleTestAndroidApp" DependsOnTargets="GenerateRuntimeConfig">
<Error Condition="!Exists('$(MicrosoftNetCoreAppRuntimePackRidDir)')" Text="MicrosoftNetCoreAppRuntimePackRidDir=$(MicrosoftNetCoreAppRuntimePackRidDir) doesn't exist" />
<PropertyGroup>
<AndroidAbi Condition="'$(TargetArchitecture)' == 'arm64'">arm64-v8a</AndroidAbi>
<AndroidAbi Condition="'$(TargetArchitecture)' == 'arm'">armeabi-v7a</AndroidAbi>
<AndroidAbi Condition="'$(TargetArchitecture)' == 'x64'">x86_64</AndroidAbi>
<AndroidAbi Condition="'$(TargetArchitecture)' == 'x86'">x86</AndroidAbi>
<MainLibraryFileName Condition="'$(MainLibraryFileName)' == ''">AndroidTestRunner.dll</MainLibraryFileName>
</PropertyGroup>
<ItemGroup>
<_AndroidEnv Condition="'$(XUnitSingleThreadedMode)' == 'true'" Include="XUNIT_SINGLE_THREADED">
<Value>1</Value>
</_AndroidEnv>
<_AndroidEnv Condition="'$(XUnitUseRandomizedTestOrderer)' == 'true'" Include="XUNIT_RANDOM_ORDER_SEED">
<Value>1883302047</Value>
</_AndroidEnv>
<_AndroidEnv Condition="'$(XUnitSingleThreadedMode)' == 'true'" Include="XUNIT_VERBOSE">
<Value>1</Value>
</_AndroidEnv>
</ItemGroup>
<ItemGroup Condition="'$(RunAOTCompilation)' == 'true'">
<AotInputAssemblies Include="$(PublishDir)\*.dll">
<AotArguments>@(MonoAOTCompilerDefaultAotArguments, ';')</AotArguments>
<ProcessArguments>@(MonoAOTCompilerDefaultProcessArguments, ';')</ProcessArguments>
</AotInputAssemblies>
</ItemGroup>
<WriteLinesToFile File="$(PublishDir)xunit-excludes.txt" Lines="$(XunitExcludesTxtFileContent)" Overwrite="true" />
<MakeDir Directories="$(_MobileIntermediateOutputPath)"
Condition="'$(RunAOTCompilation)' == 'true'"/>
<RemoveDir Directories="$(BundleDir)" />
<MonoAOTCompiler Condition="'$(RunAOTCompilation)' == 'true'"
CompilerBinaryPath="@(MonoAotCrossCompiler->WithMetadataValue('RuntimeIdentifier','$(TargetOS.ToLowerInvariant())-$(TargetArchitecture.ToLowerInvariant())'))"
OutputDir="$(_MobileIntermediateOutputPath)"
Mode="Full"
OutputType="AsmOnly"
Assemblies="@(AotInputAssemblies)"
AotModulesTablePath="$(BundleDir)\modules.c"
IntermediateOutputPath="$(IntermediateOutputPath)"
UseLLVM="$(MonoEnableLLVM)"
LLVMPath="$(MonoAotCrossDir)">
<Output TaskParameter="CompiledAssemblies" ItemName="BundleAssemblies" />
</MonoAOTCompiler>
<AndroidAppBuilderTask
RuntimeIdentifier="$(RuntimeIdentifier)"
ProjectName="$(AssemblyName)"
MonoRuntimeHeaders="$(MicrosoftNetCoreAppRuntimePackNativeDir)include\mono-2.0"
Assemblies="@(BundleAssemblies)"
MainLibraryFileName="$(MainLibraryFileName)"
IncludeNetworkSecurityConfig="$(IncludeNetworkSecurityConfig)"
EnvironmentVariables="@(_AndroidEnv)"
ForceAOT="$(RunAOTCompilation)"
ForceInterpreter="$(MonoForceInterpreter)"
RuntimeComponents="$(RuntimeComponents)"
DiagnosticPorts="$(DiagnosticPorts)"
StripDebugSymbols="False"
OutputDir="$(BundleDir)"
AppDir="$(PublishDir)">
<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)"/>
<Copy SourceFiles="$(ApkBundlePath)"
DestinationFolder="$(TestArchiveTestsDir)"
SkipUnchangedFiles="true"
Condition="'$(ArchiveTests)' == 'true' and '$(IgnoreForCI)' != 'true'" />
</Target>
<!-- This .targets file is also imported by the runtime Trimming tests, and we want to be able to manually configure trimming in them so this
should be considered if we ever want to change the Condition of the ConfigureTrimming target -->
<Target Name="ConfigureTrimming" Condition="('$(EnableAggressiveTrimming)' == 'true' or '$(EnableSoftTrimming)' == 'true') And '$(SkipConfigureTrimming)' != 'true'" AfterTargets="AddTestRunnersToPublishedFiles">

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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'">

View file

@ -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)">

View file

@ -38,6 +38,11 @@ public class AndroidAppBuilderTask : Task
/// </summary>
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>
@ -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;

View file

@ -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 + "\")");

View file

@ -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);

View file

@ -111,21 +111,6 @@ public class MonoAOTCompiler : Microsoft.Build.Utilities.Task
/// </summary>
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>
@ -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; }
}

View file

@ -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'" />

View file

@ -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; }
}

View file

@ -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);
}

View file

@ -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);
}
}
}

View file

@ -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>

View file

@ -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();
}
}