From e3dd9857748814c2d56672838657a367b70c2452 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Tom=C3=A1=C5=A1=20Rylek?= Date: Fri, 2 Jul 2021 01:17:59 +0200 Subject: [PATCH] Expand PerfMap format to support metadata for symbol indexation (#53792) I have expanded the PerfMap format produced by Crossgen2 and R2RDump to produce metadata in form of pseudo-symbol records with high addresses. In this version I have implemented four metadata entries - output GUID, target OS, target architecture and perfmap format version number. I have verified for System.Private.CoreLib and for the composite framework that Crossgen2 and R2RDump produce identical metadata. To facilitate a smooth transition to the new perfmap format, in accordance with Juan's suggestion I have introduced a new command-line option to explicitly specify the perfmap format revision. As of today, 0 corresponds to the legacy Crossgen1-style output where the perfmap file name includes the {MVID} section, perfmap format #1 corresponds to current Crossgen2 with its new naming scheme. As of today there are no differences in the file content. Thanks Tomas --- .../aot/ILCompiler.Diagnostics/AssemblyInfo.cs | 19 +++++ .../ILCompiler.Diagnostics.csproj | 4 + .../aot/ILCompiler.Diagnostics/PerfMapWriter.cs | 39 +++++++++- .../CodeGen/ReadyToRunObjectWriter.cs | 29 +++++-- .../Compiler/ReadyToRunCodegenCompilation.cs | 12 +-- .../ReadyToRunCodegenCompilationBuilder.cs | 8 +- .../ObjectWriter/OutputInfoBuilder.cs | 17 +++++ .../ObjectWriter/SymbolFileBuilder.cs | 31 +++++++- .../ILCompiler.Reflection.ReadyToRun.csproj | 7 +- .../ReadyToRunReader.cs | 88 +++++++++++++++++++++- .../tools/aot/crossgen2/CommandLineOptions.cs | 5 ++ src/coreclr/tools/aot/crossgen2/Program.cs | 7 +- .../tools/aot/crossgen2/Properties/Resources.resx | 5 +- src/coreclr/tools/r2rdump/CommandLineOptions.cs | 1 + src/coreclr/tools/r2rdump/R2RDump.cs | 26 ++++++- src/coreclr/tools/r2rdump/R2RDump.sln | 51 +++++++++++++ src/coreclr/tools/r2rdump/TextDumper.cs | 19 ++--- 17 files changed, 321 insertions(+), 47 deletions(-) create mode 100644 src/coreclr/tools/aot/ILCompiler.Diagnostics/AssemblyInfo.cs diff --git a/src/coreclr/tools/aot/ILCompiler.Diagnostics/AssemblyInfo.cs b/src/coreclr/tools/aot/ILCompiler.Diagnostics/AssemblyInfo.cs new file mode 100644 index 0000000..02ff300 --- /dev/null +++ b/src/coreclr/tools/aot/ILCompiler.Diagnostics/AssemblyInfo.cs @@ -0,0 +1,19 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +namespace ILCompiler.Diagnostics +{ + public struct AssemblyInfo + { + public readonly string Name; + public readonly Guid Mvid; + + public AssemblyInfo(string name, Guid mvid) + { + Name = name; + Mvid = mvid; + } + } +} diff --git a/src/coreclr/tools/aot/ILCompiler.Diagnostics/ILCompiler.Diagnostics.csproj b/src/coreclr/tools/aot/ILCompiler.Diagnostics/ILCompiler.Diagnostics.csproj index 8c9419d..8fe3bd19 100644 --- a/src/coreclr/tools/aot/ILCompiler.Diagnostics/ILCompiler.Diagnostics.csproj +++ b/src/coreclr/tools/aot/ILCompiler.Diagnostics/ILCompiler.Diagnostics.csproj @@ -17,4 +17,8 @@ Debug;Release;Checked + + + + diff --git a/src/coreclr/tools/aot/ILCompiler.Diagnostics/PerfMapWriter.cs b/src/coreclr/tools/aot/ILCompiler.Diagnostics/PerfMapWriter.cs index 4696bc9..dd494b9 100644 --- a/src/coreclr/tools/aot/ILCompiler.Diagnostics/PerfMapWriter.cs +++ b/src/coreclr/tools/aot/ILCompiler.Diagnostics/PerfMapWriter.cs @@ -4,11 +4,27 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; +using System.Security.Cryptography; + +using Internal.TypeSystem; namespace ILCompiler.Diagnostics { public class PerfMapWriter { + public const int LegacyCrossgen1FormatVersion = 0; + + public const int CurrentFormatVersion = 1; + + public enum PseudoRVA : uint + { + OutputGuid = 0xFFFFFFFF, + TargetOS = 0xFFFFFFFE, + TargetArchitecture = 0xFFFFFFFD, + FormatVersion = 0xFFFFFFFC, + } + private TextWriter _writer; private PerfMapWriter(TextWriter writer) @@ -16,11 +32,32 @@ namespace ILCompiler.Diagnostics _writer = writer; } - public static void Write(string perfMapFileName, IEnumerable methods) + public static void Write(string perfMapFileName, int perfMapFormatVersion, IEnumerable methods, IEnumerable inputAssemblies, TargetOS targetOS, TargetArchitecture targetArch) { + if (perfMapFormatVersion > CurrentFormatVersion) + { + throw new NotSupportedException(perfMapFormatVersion.ToString()); + } + using (TextWriter writer = new StreamWriter(perfMapFileName)) { + IEnumerable orderedInputs = inputAssemblies.OrderBy(asm => asm.Name, StringComparer.OrdinalIgnoreCase); + PerfMapWriter perfMapWriter = new PerfMapWriter(writer); + + List inputHash = new List(); + foreach (AssemblyInfo inputAssembly in orderedInputs) + { + inputHash.AddRange(inputAssembly.Mvid.ToByteArray()); + } + inputHash.Add((byte)targetOS); + inputHash.Add((byte)targetArch); + Guid outputGuid = new Guid(MD5.HashData(inputHash.ToArray())); + perfMapWriter.WriteLine(outputGuid.ToString(), (uint)PseudoRVA.OutputGuid, 0); + perfMapWriter.WriteLine(targetOS.ToString(), (uint)PseudoRVA.TargetOS, 0); + perfMapWriter.WriteLine(targetArch.ToString(), (uint)PseudoRVA.TargetArchitecture, 0); + perfMapWriter.WriteLine(CurrentFormatVersion.ToString(), (uint)PseudoRVA.FormatVersion, 0); + foreach (MethodInfo methodInfo in methods) { if (methodInfo.HotRVA != 0 && methodInfo.HotLength != 0) diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/CodeGen/ReadyToRunObjectWriter.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/CodeGen/ReadyToRunObjectWriter.cs index 74da512..6404f77 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/CodeGen/ReadyToRunObjectWriter.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/CodeGen/ReadyToRunObjectWriter.cs @@ -46,6 +46,12 @@ namespace ILCompiler.DependencyAnalysis private readonly EcmaModule _componentModule; /// + /// Compilation input files. Input files are emitted as perfmap entries and used + /// to calculate the output GUID of the ReadyToRun executable for symbol indexation. + /// + private readonly IEnumerable _inputFiles; + + /// /// Nodes to emit into the output executable as collected by the dependency analysis. /// private readonly IEnumerable _nodes; @@ -101,9 +107,9 @@ namespace ILCompiler.DependencyAnalysis private string _perfMapPath; /// - /// MVID of the input managed module to embed in the perfmap file name. + /// Requested version of the perfmap file format /// - private Guid? _perfMapMvid; + private int _perfMapFormatVersion; /// /// If non-zero, the PE file will be laid out such that it can naturally be mapped with a higher alignment than 4KB. @@ -132,6 +138,7 @@ namespace ILCompiler.DependencyAnalysis public ReadyToRunObjectWriter( string objectFilePath, EcmaModule componentModule, + IEnumerable inputFiles, IEnumerable nodes, NodeFactory factory, bool generateMapFile, @@ -140,13 +147,14 @@ namespace ILCompiler.DependencyAnalysis string pdbPath, bool generatePerfMapFile, string perfMapPath, - Guid? perfMapMvid, + int perfMapFormatVersion, bool generateProfileFile, CallChainProfile callChainProfile, int customPESectionAlignment) { _objectFilePath = objectFilePath; _componentModule = componentModule; + _inputFiles = inputFiles; _nodes = nodes; _nodeFactory = factory; _customPESectionAlignment = customPESectionAlignment; @@ -156,7 +164,7 @@ namespace ILCompiler.DependencyAnalysis _pdbPath = pdbPath; _generatePerfMapFile = generatePerfMapFile; _perfMapPath = perfMapPath; - _perfMapMvid = perfMapMvid; + _perfMapFormatVersion = perfMapFormatVersion; bool generateMap = (generateMapFile || generateMapCsvFile); bool generateSymbols = (generatePdbFile || generatePerfMapFile); @@ -329,6 +337,11 @@ namespace ILCompiler.DependencyAnalysis if (_outputInfoBuilder != null) { + foreach (string inputFile in _inputFiles) + { + _outputInfoBuilder.AddInputModule(_nodeFactory.TypeSystemContext.GetModuleFromPath(inputFile)); + } + r2rPeBuilder.AddSections(_outputInfoBuilder); if (_generateMapFile) @@ -361,7 +374,7 @@ namespace ILCompiler.DependencyAnalysis { path = Path.GetDirectoryName(_objectFilePath); } - _symbolFileBuilder.SavePerfMap(path, _objectFilePath, _perfMapMvid); + _symbolFileBuilder.SavePerfMap(path, _perfMapFormatVersion, _objectFilePath, _nodeFactory.Target.OperatingSystem, _nodeFactory.Target.Architecture); } if (_profileFileBuilder != null) @@ -430,6 +443,7 @@ namespace ILCompiler.DependencyAnalysis public static void EmitObject( string objectFilePath, EcmaModule componentModule, + IEnumerable inputFiles, IEnumerable nodes, NodeFactory factory, bool generateMapFile, @@ -438,7 +452,7 @@ namespace ILCompiler.DependencyAnalysis string pdbPath, bool generatePerfMapFile, string perfMapPath, - Guid? perfMapMvid, + int perfMapFormatVersion, bool generateProfileFile, CallChainProfile callChainProfile, int customPESectionAlignment) @@ -447,6 +461,7 @@ namespace ILCompiler.DependencyAnalysis ReadyToRunObjectWriter objectWriter = new ReadyToRunObjectWriter( objectFilePath, componentModule, + inputFiles, nodes, factory, generateMapFile: generateMapFile, @@ -455,7 +470,7 @@ namespace ILCompiler.DependencyAnalysis pdbPath: pdbPath, generatePerfMapFile: generatePerfMapFile, perfMapPath: perfMapPath, - perfMapMvid: perfMapMvid, + perfMapFormatVersion: perfMapFormatVersion, generateProfileFile: generateProfileFile, callChainProfile, customPESectionAlignment); diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs index 1dce9f8..ac7058b 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs @@ -247,7 +247,7 @@ namespace ILCompiler private readonly string _pdbPath; private readonly bool _generatePerfMapFile; private readonly string _perfMapPath; - private readonly Guid? _perfMapMvid; + private readonly int _perfMapFormatVersion; private readonly bool _generateProfileFile; private readonly Func _printReproInstructions; @@ -283,7 +283,7 @@ namespace ILCompiler string pdbPath, bool generatePerfMapFile, string perfMapPath, - Guid? perfMapMvid, + int perfMapFormatVersion, bool generateProfileFile, int parallelism, ProfileDataManager profileData, @@ -309,7 +309,7 @@ namespace ILCompiler _pdbPath = pdbPath; _generatePerfMapFile = generatePerfMapFile; _perfMapPath = perfMapPath; - _perfMapMvid = perfMapMvid; + _perfMapFormatVersion = perfMapFormatVersion; _generateProfileFile = generateProfileFile; _customPESectionAlignment = customPESectionAlignment; SymbolNodeFactory = new ReadyToRunSymbolNodeFactory(nodeFactory, verifyTypeAndFieldLayout); @@ -347,6 +347,7 @@ namespace ILCompiler ReadyToRunObjectWriter.EmitObject( outputFile, componentModule: null, + inputFiles: _inputFiles, nodes, NodeFactory, generateMapFile: _generateMapFile, @@ -355,7 +356,7 @@ namespace ILCompiler pdbPath: _pdbPath, generatePerfMapFile: _generatePerfMapFile, perfMapPath: _perfMapPath, - perfMapMvid: _perfMapMvid, + perfMapFormatVersion: _perfMapFormatVersion, generateProfileFile: _generateProfileFile, callChainProfile: _profileData.CallChainProfile, _customPESectionAlignment); @@ -427,6 +428,7 @@ namespace ILCompiler ReadyToRunObjectWriter.EmitObject( outputFile, componentModule: inputModule, + inputFiles: new string[] { inputFile }, componentGraph.MarkedNodeList, componentFactory, generateMapFile: false, @@ -435,7 +437,7 @@ namespace ILCompiler pdbPath: null, generatePerfMapFile: false, perfMapPath: null, - perfMapMvid: null, + perfMapFormatVersion: _perfMapFormatVersion, generateProfileFile: false, _profileData.CallChainProfile, customPESectionAlignment: 0); diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilationBuilder.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilationBuilder.cs index fa4d318..c1207a4 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilationBuilder.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilationBuilder.cs @@ -31,7 +31,7 @@ namespace ILCompiler private string _pdbPath; private bool _generatePerfMapFile; private string _perfMapPath; - private Guid? _perfMapMvid; + private int _perfMapFormatVersion; private bool _generateProfileFile; private int _parallelism; Func _printReproInstructions; @@ -156,11 +156,11 @@ namespace ILCompiler return this; } - public ReadyToRunCodegenCompilationBuilder UsePerfMapFile(bool generatePerfMapFile, string perfMapPath, Guid? inputModuleMvid) + public ReadyToRunCodegenCompilationBuilder UsePerfMapFile(bool generatePerfMapFile, string perfMapPath, int perfMapFormatVersion) { _generatePerfMapFile = generatePerfMapFile; _perfMapPath = perfMapPath; - _perfMapMvid = inputModuleMvid; + _perfMapFormatVersion = perfMapFormatVersion; return this; } @@ -312,7 +312,7 @@ namespace ILCompiler pdbPath: _pdbPath, generatePerfMapFile: _generatePerfMapFile, perfMapPath: _perfMapPath, - perfMapMvid: _perfMapMvid, + perfMapFormatVersion: _perfMapFormatVersion, generateProfileFile: _generateProfileFile, _parallelism, _profileData, diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/OutputInfoBuilder.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/OutputInfoBuilder.cs index 82145e3..ca6efc9 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/OutputInfoBuilder.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/OutputInfoBuilder.cs @@ -106,6 +106,7 @@ namespace ILCompiler.PEWriter /// public class OutputInfoBuilder { + private readonly List _inputModules; private readonly List _nodes; private readonly List _symbols; private readonly List
_sections; @@ -117,6 +118,7 @@ namespace ILCompiler.PEWriter public OutputInfoBuilder() { + _inputModules = new List(); _nodes = new List(); _symbols = new List(); _sections = new List
(); @@ -127,6 +129,11 @@ namespace ILCompiler.PEWriter _relocCounts = new Dictionary(); } + public void AddInputModule(EcmaModule module) + { + _inputModules.Add(module); + } + public void AddNode(OutputNode node, ISymbolDefinitionNode symbol) { _nodes.Add(node); @@ -197,6 +204,16 @@ namespace ILCompiler.PEWriter } } + public IEnumerable EnumerateInputAssemblies() + { + foreach (EcmaModule inputModule in _inputModules) + { + yield return new AssemblyInfo( + inputModule.Assembly.GetName().Name, + inputModule.MetadataReader.GetGuid(inputModule.MetadataReader.GetModuleDefinition().Mvid)); + } + } + private string FormatMethodName(MethodDesc method, TypeNameFormatter typeNameFormatter) { StringBuilder output = new StringBuilder(); diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/SymbolFileBuilder.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/SymbolFileBuilder.cs index 7ec9357..8cd0ad4 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/SymbolFileBuilder.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/SymbolFileBuilder.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; +using Internal.TypeSystem; using ILCompiler.Diagnostics; namespace ILCompiler.PEWriter @@ -28,12 +29,34 @@ namespace ILCompiler.PEWriter new PdbWriter(pdbPath, PDBExtraData.None).WritePDBData(dllFileName, _outputInfoBuilder.EnumerateMethods()); } - public void SavePerfMap(string perfMapPath, string dllFileName, Guid? perfMapMvid) + public void SavePerfMap(string perfMapPath, int perfMapFormatVersion, string dllFileName, TargetOS targetOS, TargetArchitecture targetArch) { - string mvidComponent = (perfMapMvid.HasValue ? perfMapMvid.Value.ToString() : "composite"); - string perfMapFileName = Path.Combine(perfMapPath, Path.GetFileNameWithoutExtension(dllFileName) + ".ni.{" + mvidComponent + "}.map"); + string perfMapExtension; + if (perfMapFormatVersion == PerfMapWriter.LegacyCrossgen1FormatVersion) + { + string mvidComponent = null; + foreach (AssemblyInfo inputAssembly in _outputInfoBuilder.EnumerateInputAssemblies()) + { + if (mvidComponent == null) + { + mvidComponent = inputAssembly.Mvid.ToString(); + } + else + { + mvidComponent = "composite"; + break; + } + } + perfMapExtension = ".ni.{" + mvidComponent + "}.map"; + } + else + { + perfMapExtension = ".ni.r2rmap"; + } + + string perfMapFileName = Path.Combine(perfMapPath, Path.GetFileNameWithoutExtension(dllFileName) + perfMapExtension); Console.WriteLine("Emitting PerfMap file: {0}", perfMapFileName); - PerfMapWriter.Write(perfMapFileName, _outputInfoBuilder.EnumerateMethods()); + PerfMapWriter.Write(perfMapFileName, perfMapFormatVersion, _outputInfoBuilder.EnumerateMethods(), _outputInfoBuilder.EnumerateInputAssemblies(), targetOS, targetArch); } } } diff --git a/src/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/ILCompiler.Reflection.ReadyToRun.csproj b/src/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/ILCompiler.Reflection.ReadyToRun.csproj index 1424375..0d332d5 100644 --- a/src/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/ILCompiler.Reflection.ReadyToRun.csproj +++ b/src/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/ILCompiler.Reflection.ReadyToRun.csproj @@ -7,7 +7,7 @@ AnyCPU Open true - netstandard2.0 + $(NetCoreAppToolCurrent) false 8002,NU1701 win-x64;win-x86 @@ -27,6 +27,9 @@ - + + + + diff --git a/src/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/ReadyToRunReader.cs b/src/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/ReadyToRunReader.cs index f727ed8..821a38f 100644 --- a/src/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/ReadyToRunReader.cs +++ b/src/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/ReadyToRunReader.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; using System.IO; +using System.Linq; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; using System.Reflection.PortableExecutable; @@ -15,9 +16,9 @@ using System.Text; using Internal.CorConstants; using Internal.Runtime; using Internal.ReadyToRunConstants; +using Internal.TypeSystem; using Debug = System.Diagnostics.Debug; -using System.Linq; namespace ILCompiler.Reflection.ReadyToRun { @@ -79,6 +80,8 @@ namespace ILCompiler.Reflection.ReadyToRun public sealed class ReadyToRunReader { + public const int GuidByteSize = 16; + private const string SystemModuleName = "System.Private.CoreLib"; /// @@ -177,6 +180,33 @@ namespace ILCompiler.Reflection.ReadyToRun } /// + /// Conversion of the PE machine ID to TargetArchitecture used by TargetDetails. + /// + public TargetArchitecture TargetArchitecture + { + get + { + switch (Machine) + { + case Machine.I386: + return TargetArchitecture.X86; + + case Machine.Amd64: + return TargetArchitecture.X64; + + case Machine.ArmThumb2: + return TargetArchitecture.ARM; + + case Machine.Arm64: + return TargetArchitecture.ARM64; + + default: + throw new NotImplementedException(_machine.ToString()); + } + } + } + + /// /// Targeting operating system for the R2R executable /// public OperatingSystem OperatingSystem @@ -189,6 +219,36 @@ namespace ILCompiler.Reflection.ReadyToRun } /// + /// Targeting operating system converted to the enumeration used by TargetDetails. + /// + public TargetOS TargetOperatingSystem + { + get + { + switch (OperatingSystem) + { + case OperatingSystem.Windows: + return TargetOS.Windows; + + case OperatingSystem.Linux: + return TargetOS.Linux; + + case OperatingSystem.Apple: + return TargetOS.OSX; + + case OperatingSystem.FreeBSD: + return TargetOS.FreeBSD; + + case OperatingSystem.NetBSD: + return TargetOS.FreeBSD; + + default: + throw new NotImplementedException(OperatingSystem.ToString()); + } + } + } + + /// /// Targeting processor architecture of the R2R executable /// public Architecture Architecture @@ -537,6 +597,12 @@ namespace ILCompiler.Reflection.ReadyToRun return (_composite ? null : _assemblyCache[0]); } + public string GetGlobalAssemblyName() + { + MetadataReader mdReader = GetGlobalMetadata().MetadataReader; + return mdReader.GetString(mdReader.GetAssemblyDefinition().Name); + } + private unsafe void EnsureHeader() { if (_readyToRunHeader != null) @@ -1087,6 +1153,26 @@ namespace ILCompiler.Reflection.ReadyToRun } } + public Guid GetAssemblyMvid(int assemblyIndex) + { + EnsureHeader(); + if (_composite) + { + if (!ReadyToRunHeader.Sections.TryGetValue(ReadyToRunSectionType.ManifestAssemblyMvids, out ReadyToRunSection mvidSection)) + { + return Guid.Empty; + } + int mvidOffset = GetOffset(mvidSection.RelativeVirtualAddress) + GuidByteSize * assemblyIndex; + return new Guid(new ReadOnlySpan(Image, mvidOffset, ReadyToRunReader.GuidByteSize)); + } + else + { + Debug.Assert(assemblyIndex == 0); + MetadataReader mdReader = GetGlobalMetadata().MetadataReader; + return mdReader.GetGuid(mdReader.GetModuleDefinition().Mvid); + } + } + /// /// Iterates through a native hashtable to get all RIDs /// diff --git a/src/coreclr/tools/aot/crossgen2/CommandLineOptions.cs b/src/coreclr/tools/aot/crossgen2/CommandLineOptions.cs index 573b1eb..c91e615 100644 --- a/src/coreclr/tools/aot/crossgen2/CommandLineOptions.cs +++ b/src/coreclr/tools/aot/crossgen2/CommandLineOptions.cs @@ -12,6 +12,8 @@ namespace ILCompiler { internal class CommandLineOptions { + public const int DefaultPerfMapFormatVersion = 0; + public bool Help; public string HelpText; @@ -56,6 +58,7 @@ namespace ILCompiler public string PdbPath; public bool PerfMap; public string PerfMapPath; + public int PerfMapFormatVersion; public int Parallelism; public int CustomPESectionAlignment; public string MethodLayout; @@ -81,6 +84,7 @@ namespace ILCompiler MibcFilePaths = Array.Empty(); CodegenOptions = Array.Empty(); + PerfMapFormatVersion = DefaultPerfMapFormatVersion; Parallelism = Environment.ProcessorCount; SingleMethodGenericArg = null; @@ -139,6 +143,7 @@ namespace ILCompiler syntax.DefineOption("pdb-path", ref PdbPath, SR.PdbFilePathOption); syntax.DefineOption("perfmap", ref PerfMap, SR.PerfMapFileOption); syntax.DefineOption("perfmap-path", ref PerfMapPath, SR.PerfMapFilePathOption); + syntax.DefineOption("perfmap-format-version", ref PerfMapFormatVersion, SR.PerfMapFormatVersionOption); syntax.DefineOption("method-layout", ref MethodLayout, SR.MethodLayoutOption); syntax.DefineOption("file-layout", ref FileLayout, SR.FileLayoutOption); diff --git a/src/coreclr/tools/aot/crossgen2/Program.cs b/src/coreclr/tools/aot/crossgen2/Program.cs index 2f84f6f..aeeb9f5 100644 --- a/src/coreclr/tools/aot/crossgen2/Program.cs +++ b/src/coreclr/tools/aot/crossgen2/Program.cs @@ -517,7 +517,6 @@ namespace ILCompiler List inputModules = new List(); List rootingModules = new List(); - Guid? inputModuleMvid = null; foreach (var inputFile in inFilePaths) { @@ -526,10 +525,6 @@ namespace ILCompiler rootingModules.Add(module); versionBubbleModulesHash.Add(module); - if (!_commandLineOptions.Composite && !inputModuleMvid.HasValue) - { - inputModuleMvid = module.MetadataReader.GetGuid(module.MetadataReader.GetModuleDefinition().Mvid); - } if (!_commandLineOptions.CompositeOrInputBubble) { @@ -687,7 +682,7 @@ namespace ILCompiler .UseMapFile(_commandLineOptions.Map) .UseMapCsvFile(_commandLineOptions.MapCsv) .UsePdbFile(_commandLineOptions.Pdb, _commandLineOptions.PdbPath) - .UsePerfMapFile(_commandLineOptions.PerfMap, _commandLineOptions.PerfMapPath, inputModuleMvid) + .UsePerfMapFile(_commandLineOptions.PerfMap, _commandLineOptions.PerfMapPath, _commandLineOptions.PerfMapFormatVersion) .UseProfileFile(jsonProfile != null) .UseParallelism(_commandLineOptions.Parallelism) .UseProfileData(profileDataManager) diff --git a/src/coreclr/tools/aot/crossgen2/Properties/Resources.resx b/src/coreclr/tools/aot/crossgen2/Properties/Resources.resx index 084138e..c031f30 100644 --- a/src/coreclr/tools/aot/crossgen2/Properties/Resources.resx +++ b/src/coreclr/tools/aot/crossgen2/Properties/Resources.resx @@ -345,4 +345,7 @@ Explicit specification of the PerfMap file path - + + Explicitly request a particular PerfMap format version + + \ No newline at end of file diff --git a/src/coreclr/tools/r2rdump/CommandLineOptions.cs b/src/coreclr/tools/r2rdump/CommandLineOptions.cs index 8857cdb..9a1296b 100644 --- a/src/coreclr/tools/r2rdump/CommandLineOptions.cs +++ b/src/coreclr/tools/r2rdump/CommandLineOptions.cs @@ -40,6 +40,7 @@ namespace R2RDump command.AddOption(new Option(new[] { "--pdb-path" }, "PDB output path for --create-pdb")); command.AddOption(new Option(new[] { "--create-perfmap" }, "Create PerfMap")); command.AddOption(new Option(new[] { "--perfmap-path" }, "PerfMap output path for --create-perfmap")); + command.AddOption(new Option(new[] { "--perfmap-format-version" }, "PerfMap format version for --create-perfmap")); return command; } } diff --git a/src/coreclr/tools/r2rdump/R2RDump.cs b/src/coreclr/tools/r2rdump/R2RDump.cs index 8a24273..94d7183 100644 --- a/src/coreclr/tools/r2rdump/R2RDump.cs +++ b/src/coreclr/tools/r2rdump/R2RDump.cs @@ -20,6 +20,7 @@ using ILCompiler.Diagnostics; using ILCompiler.Reflection.ReadyToRun; using Internal.Runtime; +using Internal.TypeSystem; namespace R2RDump { @@ -55,6 +56,7 @@ namespace R2RDump public bool CreatePerfmap { get; set; } public string PerfmapPath { get; set; } + public int PerfmapFormatVersion { get; set; } public FileInfo[] Reference { get; set; } @@ -65,6 +67,11 @@ namespace R2RDump private SignatureFormattingOptions signatureFormattingOptions; + public DumpOptions() + { + PerfmapFormatVersion = PerfMapWriter.CurrentFormatVersion; + } + /// /// Probing extensions to use when looking up assemblies under reference paths. /// @@ -425,9 +432,9 @@ namespace R2RDump string perfmapPath = _options.PerfmapPath; if (string.IsNullOrEmpty(perfmapPath)) { - perfmapPath = Path.ChangeExtension(r2r.Filename, ".map"); - PerfMapWriter.Write(perfmapPath, ProduceDebugInfoMethods(r2r)); + perfmapPath = Path.ChangeExtension(r2r.Filename, ".r2rmap"); } + PerfMapWriter.Write(perfmapPath, _options.PerfmapFormatVersion, ProduceDebugInfoMethods(r2r), ProduceDebugInfoAssemblies(r2r), r2r.TargetOperatingSystem, r2r.TargetArchitecture); } if (standardDump) @@ -457,6 +464,21 @@ namespace R2RDump } } + IEnumerable ProduceDebugInfoAssemblies(ReadyToRunReader r2r) + { + if (r2r.Composite) + { + foreach (KeyValuePair kvpRefAssembly in r2r.ManifestReferenceAssemblies.OrderBy(kvp => kvp.Key, StringComparer.OrdinalIgnoreCase)) + { + yield return new AssemblyInfo(kvpRefAssembly.Key, r2r.GetAssemblyMvid(kvpRefAssembly.Value)); + } + } + else + { + yield return new AssemblyInfo(r2r.GetGlobalAssemblyName(), r2r.GetAssemblyMvid(0)); + } + } + /// /// Returns true if the name, signature or id of method matches query /// diff --git a/src/coreclr/tools/r2rdump/R2RDump.sln b/src/coreclr/tools/r2rdump/R2RDump.sln index 6596a59..e8f71be 100644 --- a/src/coreclr/tools/r2rdump/R2RDump.sln +++ b/src/coreclr/tools/r2rdump/R2RDump.sln @@ -8,38 +8,89 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ILCompiler.Reflection.Ready EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ILCompiler.Diagnostics", "..\aot\ILCompiler.Diagnostics\ILCompiler.Diagnostics.csproj", "{4E9512BA-F963-472A-B689-37D4D32456F3}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ILCompiler.TypeSystem.ReadyToRun", "..\aot\ILCompiler.TypeSystem.ReadyToRun\ILCompiler.TypeSystem.ReadyToRun.csproj", "{F9CC5645-9E5D-41EE-ACD3-120F661DDA51}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution + Checked|Any CPU = Checked|Any CPU + Checked|x64 = Checked|x64 + Checked|x86 = Checked|x86 Debug|Any CPU = Debug|Any CPU Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU Release|x64 = Release|x64 + Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution + {00CCF6D0-5905-428E-A2A2-2A6D09D8C257}.Checked|Any CPU.ActiveCfg = Release|Any CPU + {00CCF6D0-5905-428E-A2A2-2A6D09D8C257}.Checked|Any CPU.Build.0 = Release|Any CPU + {00CCF6D0-5905-428E-A2A2-2A6D09D8C257}.Checked|x64.ActiveCfg = Release|x64 + {00CCF6D0-5905-428E-A2A2-2A6D09D8C257}.Checked|x64.Build.0 = Release|x64 + {00CCF6D0-5905-428E-A2A2-2A6D09D8C257}.Checked|x86.ActiveCfg = Debug|x86 + {00CCF6D0-5905-428E-A2A2-2A6D09D8C257}.Checked|x86.Build.0 = Debug|x86 {00CCF6D0-5905-428E-A2A2-2A6D09D8C257}.Debug|Any CPU.ActiveCfg = Debug|x64 {00CCF6D0-5905-428E-A2A2-2A6D09D8C257}.Debug|Any CPU.Build.0 = Debug|x64 {00CCF6D0-5905-428E-A2A2-2A6D09D8C257}.Debug|x64.ActiveCfg = Debug|x64 {00CCF6D0-5905-428E-A2A2-2A6D09D8C257}.Debug|x64.Build.0 = Debug|x64 + {00CCF6D0-5905-428E-A2A2-2A6D09D8C257}.Debug|x86.ActiveCfg = Debug|x86 + {00CCF6D0-5905-428E-A2A2-2A6D09D8C257}.Debug|x86.Build.0 = Debug|x86 {00CCF6D0-5905-428E-A2A2-2A6D09D8C257}.Release|Any CPU.ActiveCfg = Release|Any CPU {00CCF6D0-5905-428E-A2A2-2A6D09D8C257}.Release|Any CPU.Build.0 = Release|Any CPU {00CCF6D0-5905-428E-A2A2-2A6D09D8C257}.Release|x64.ActiveCfg = Release|x64 {00CCF6D0-5905-428E-A2A2-2A6D09D8C257}.Release|x64.Build.0 = Release|x64 + {00CCF6D0-5905-428E-A2A2-2A6D09D8C257}.Release|x86.ActiveCfg = Release|x86 + {00CCF6D0-5905-428E-A2A2-2A6D09D8C257}.Release|x86.Build.0 = Release|x86 + {E2A577E5-7AF3-49B3-BA78-7071B75ED64B}.Checked|Any CPU.ActiveCfg = Release|Any CPU + {E2A577E5-7AF3-49B3-BA78-7071B75ED64B}.Checked|Any CPU.Build.0 = Release|Any CPU + {E2A577E5-7AF3-49B3-BA78-7071B75ED64B}.Checked|x64.ActiveCfg = Release|x64 + {E2A577E5-7AF3-49B3-BA78-7071B75ED64B}.Checked|x64.Build.0 = Release|x64 + {E2A577E5-7AF3-49B3-BA78-7071B75ED64B}.Checked|x86.ActiveCfg = Release|Any CPU + {E2A577E5-7AF3-49B3-BA78-7071B75ED64B}.Checked|x86.Build.0 = Release|Any CPU {E2A577E5-7AF3-49B3-BA78-7071B75ED64B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E2A577E5-7AF3-49B3-BA78-7071B75ED64B}.Debug|Any CPU.Build.0 = Debug|Any CPU {E2A577E5-7AF3-49B3-BA78-7071B75ED64B}.Debug|x64.ActiveCfg = Debug|x64 {E2A577E5-7AF3-49B3-BA78-7071B75ED64B}.Debug|x64.Build.0 = Debug|x64 + {E2A577E5-7AF3-49B3-BA78-7071B75ED64B}.Debug|x86.ActiveCfg = Debug|Any CPU + {E2A577E5-7AF3-49B3-BA78-7071B75ED64B}.Debug|x86.Build.0 = Debug|Any CPU {E2A577E5-7AF3-49B3-BA78-7071B75ED64B}.Release|Any CPU.ActiveCfg = Release|Any CPU {E2A577E5-7AF3-49B3-BA78-7071B75ED64B}.Release|Any CPU.Build.0 = Release|Any CPU {E2A577E5-7AF3-49B3-BA78-7071B75ED64B}.Release|x64.ActiveCfg = Release|x64 {E2A577E5-7AF3-49B3-BA78-7071B75ED64B}.Release|x64.Build.0 = Release|x64 + {E2A577E5-7AF3-49B3-BA78-7071B75ED64B}.Release|x86.ActiveCfg = Release|Any CPU + {E2A577E5-7AF3-49B3-BA78-7071B75ED64B}.Release|x86.Build.0 = Release|Any CPU + {4E9512BA-F963-472A-B689-37D4D32456F3}.Checked|Any CPU.ActiveCfg = Checked|x86 + {4E9512BA-F963-472A-B689-37D4D32456F3}.Checked|x64.ActiveCfg = Checked|x64 + {4E9512BA-F963-472A-B689-37D4D32456F3}.Checked|x64.Build.0 = Checked|x64 + {4E9512BA-F963-472A-B689-37D4D32456F3}.Checked|x86.ActiveCfg = Checked|x86 + {4E9512BA-F963-472A-B689-37D4D32456F3}.Checked|x86.Build.0 = Checked|x86 {4E9512BA-F963-472A-B689-37D4D32456F3}.Debug|Any CPU.ActiveCfg = Debug|x64 {4E9512BA-F963-472A-B689-37D4D32456F3}.Debug|Any CPU.Build.0 = Debug|x64 {4E9512BA-F963-472A-B689-37D4D32456F3}.Debug|x64.ActiveCfg = Debug|x64 {4E9512BA-F963-472A-B689-37D4D32456F3}.Debug|x64.Build.0 = Debug|x64 + {4E9512BA-F963-472A-B689-37D4D32456F3}.Debug|x86.ActiveCfg = Debug|x86 + {4E9512BA-F963-472A-B689-37D4D32456F3}.Debug|x86.Build.0 = Debug|x86 {4E9512BA-F963-472A-B689-37D4D32456F3}.Release|Any CPU.ActiveCfg = Release|Any CPU {4E9512BA-F963-472A-B689-37D4D32456F3}.Release|Any CPU.Build.0 = Release|Any CPU {4E9512BA-F963-472A-B689-37D4D32456F3}.Release|x64.ActiveCfg = Release|Any CPU {4E9512BA-F963-472A-B689-37D4D32456F3}.Release|x64.Build.0 = Release|Any CPU + {4E9512BA-F963-472A-B689-37D4D32456F3}.Release|x86.ActiveCfg = Release|x86 + {4E9512BA-F963-472A-B689-37D4D32456F3}.Release|x86.Build.0 = Release|x86 + {F9CC5645-9E5D-41EE-ACD3-120F661DDA51}.Checked|Any CPU.ActiveCfg = Checked|x86 + {F9CC5645-9E5D-41EE-ACD3-120F661DDA51}.Checked|x64.ActiveCfg = Checked|x64 + {F9CC5645-9E5D-41EE-ACD3-120F661DDA51}.Checked|x64.Build.0 = Checked|x64 + {F9CC5645-9E5D-41EE-ACD3-120F661DDA51}.Checked|x86.ActiveCfg = Checked|x86 + {F9CC5645-9E5D-41EE-ACD3-120F661DDA51}.Checked|x86.Build.0 = Checked|x86 + {F9CC5645-9E5D-41EE-ACD3-120F661DDA51}.Debug|Any CPU.ActiveCfg = Debug|x86 + {F9CC5645-9E5D-41EE-ACD3-120F661DDA51}.Debug|x64.ActiveCfg = Debug|x64 + {F9CC5645-9E5D-41EE-ACD3-120F661DDA51}.Debug|x64.Build.0 = Debug|x64 + {F9CC5645-9E5D-41EE-ACD3-120F661DDA51}.Debug|x86.ActiveCfg = Debug|x86 + {F9CC5645-9E5D-41EE-ACD3-120F661DDA51}.Debug|x86.Build.0 = Debug|x86 + {F9CC5645-9E5D-41EE-ACD3-120F661DDA51}.Release|Any CPU.ActiveCfg = Release|x86 + {F9CC5645-9E5D-41EE-ACD3-120F661DDA51}.Release|x64.ActiveCfg = Release|x64 + {F9CC5645-9E5D-41EE-ACD3-120F661DDA51}.Release|x64.Build.0 = Release|x64 + {F9CC5645-9E5D-41EE-ACD3-120F661DDA51}.Release|x86.ActiveCfg = Release|x86 + {F9CC5645-9E5D-41EE-ACD3-120F661DDA51}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/coreclr/tools/r2rdump/TextDumper.cs b/src/coreclr/tools/r2rdump/TextDumper.cs index 0e062b8..7ca2b58 100644 --- a/src/coreclr/tools/r2rdump/TextDumper.cs +++ b/src/coreclr/tools/r2rdump/TextDumper.cs @@ -7,6 +7,7 @@ using System.IO; using System.Linq; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; +using System.Runtime.CompilerServices; using System.Reflection.PortableExecutable; using System.Text; @@ -18,8 +19,6 @@ namespace R2RDump { class TextDumper : Dumper { - private const int GuidByteSize = 16; - public TextDumper(ReadyToRunReader r2r, TextWriter writer, Disassembler disassembler, DumpOptions options) : base(r2r, writer, disassembler, options) { @@ -90,14 +89,8 @@ namespace R2RDump int assemblyIndex = 0; foreach (string assemblyName in _r2r.ManifestReferenceAssemblies.OrderBy(kvp => kvp.Value).Select(kvp => kvp.Key)) { - string dividerName = $@"Component Assembly [{assemblyIndex}]: {assemblyName}"; - if (_r2r.ReadyToRunHeader.Sections.TryGetValue(ReadyToRunSectionType.ManifestAssemblyMvids, out ReadyToRunSection mvidSection)) - { - int mvidOffset = _r2r.GetOffset(mvidSection.RelativeVirtualAddress) + GuidByteSize * assemblyIndex; - Guid mvid = new Guid(new ReadOnlySpan(_r2r.Image, mvidOffset, GuidByteSize)); - dividerName += $@" - MVID {mvid:b}"; - } - WriteDivider(dividerName); + Guid mvid = _r2r.GetAssemblyMvid(assemblyIndex); + WriteDivider($@"Component Assembly [{assemblyIndex}]: {assemblyName} - MVID {mvid:b}"); ReadyToRunCoreHeader assemblyHeader = _r2r.ReadyToRunAssemblyHeaders[assemblyIndex]; foreach (ReadyToRunSection section in NormalizedSections(assemblyHeader)) { @@ -513,12 +506,10 @@ namespace R2RDump _writer.WriteLine("Composite executable: {0}", ownerCompositeExecutable.ToEscapedString()); break; case ReadyToRunSectionType.ManifestAssemblyMvids: - int mvidOffset = _r2r.GetOffset(section.RelativeVirtualAddress); - int mvidCount = section.Size / GuidByteSize; + int mvidCount = section.Size / ReadyToRunReader.GuidByteSize; for (int mvidIndex = 0; mvidIndex < mvidCount; mvidIndex++) { - Guid mvid = new Guid(new Span(_r2r.Image, mvidOffset + GuidByteSize * mvidIndex, GuidByteSize)); - _writer.WriteLine("MVID[{0}] = {1:b}", mvidIndex, mvid); + _writer.WriteLine("MVID[{0}] = {1:b}", mvidIndex, _r2r.GetAssemblyMvid(mvidIndex)); } break; default: -- 2.7.4