From 047d876dd85e0a5b0c5755b2e070de880382f3d1 Mon Sep 17 00:00:00 2001 From: Tomas Date: Sun, 6 Jun 2021 22:14:57 +0200 Subject: [PATCH 1/3] Expand PerfMap format to support metadata for symbol indexation 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 five metadata entries - output GUID, target OS, target architecture, input assembly names and input assembly MVIDs. I have verified for System.Private.CoreLib and for the composite framework that Crossgen2 and R2RDump produce identical metadata. Thanks Tomas --- .../ILCompiler.Diagnostics/AssemblyInfo.cs | 19 ++++ .../ILCompiler.Diagnostics.csproj | 4 + .../ILCompiler.Diagnostics/PerfMapWriter.cs | 38 +++++++- .../CodeGen/ReadyToRunObjectWriter.cs | 26 +++--- .../Compiler/ReadyToRunCodegenCompilation.cs | 7 +- .../ReadyToRunCodegenCompilationBuilder.cs | 5 +- .../ObjectWriter/OutputInfoBuilder.cs | 17 ++++ .../ObjectWriter/SymbolFileBuilder.cs | 8 +- .../ILCompiler.Reflection.ReadyToRun.csproj | 7 +- .../ReadyToRunReader.cs | 88 ++++++++++++++++++- src/coreclr/tools/aot/crossgen2/Program.cs | 7 +- src/coreclr/tools/r2rdump/R2RDump.cs | 18 +++- src/coreclr/tools/r2rdump/R2RDump.sln | 51 +++++++++++ src/coreclr/tools/r2rdump/TextDumper.cs | 19 ++-- 14 files changed, 266 insertions(+), 48 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 0000000000000..02ff300e617e8 --- /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 8c9419db564aa..8fe3bd1982d47 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 4696bc9e2d18f..7f7e92fac7a84 100644 --- a/src/coreclr/tools/aot/ILCompiler.Diagnostics/PerfMapWriter.cs +++ b/src/coreclr/tools/aot/ILCompiler.Diagnostics/PerfMapWriter.cs @@ -4,11 +4,24 @@ 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 enum PseudoRVA : uint + { + OutputGuid = 0xFFFFFFFF, + TargetOS = 0xFFFFFFFE, + TargetArchitecture = 0xFFFFFFFD, + InputAssemblyName = 0xFFFFFFFC, + InputAssemblyMvid = 0xFFFFFFFB, + } + private TextWriter _writer; private PerfMapWriter(TextWriter writer) @@ -16,11 +29,34 @@ private PerfMapWriter(TextWriter writer) _writer = writer; } - public static void Write(string perfMapFileName, IEnumerable methods) + public static void Write(string perfMapFileName, IEnumerable methods, IEnumerable inputAssemblies, TargetOS targetOS, TargetArchitecture targetArch) { 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); + + uint inputAssemblyIndex = 0; + foreach (AssemblyInfo inputAssembly in orderedInputs) + { + perfMapWriter.WriteLine(inputAssembly.Name, (uint)PseudoRVA.InputAssemblyName, inputAssemblyIndex); + perfMapWriter.WriteLine(inputAssembly.Mvid.ToString(), (uint)PseudoRVA.InputAssemblyMvid, inputAssemblyIndex); + inputAssemblyIndex++; + } + 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 74da51246b620..e7d86b479475a 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/CodeGen/ReadyToRunObjectWriter.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/CodeGen/ReadyToRunObjectWriter.cs @@ -45,6 +45,12 @@ internal class ReadyToRunObjectWriter /// 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. /// @@ -100,11 +106,6 @@ internal class ReadyToRunObjectWriter /// private string _perfMapPath; - /// - /// MVID of the input managed module to embed in the perfmap file name. - /// - private Guid? _perfMapMvid; - /// /// If non-zero, the PE file will be laid out such that it can naturally be mapped with a higher alignment than 4KB. /// This is used to support loading via large pages on Linux. @@ -132,6 +133,7 @@ public NodeInfo(ISymbolNode node, int nodeIndex, int symbolIndex) public ReadyToRunObjectWriter( string objectFilePath, EcmaModule componentModule, + IEnumerable inputFiles, IEnumerable nodes, NodeFactory factory, bool generateMapFile, @@ -140,13 +142,13 @@ public NodeInfo(ISymbolNode node, int nodeIndex, int symbolIndex) string pdbPath, bool generatePerfMapFile, string perfMapPath, - Guid? perfMapMvid, bool generateProfileFile, CallChainProfile callChainProfile, int customPESectionAlignment) { _objectFilePath = objectFilePath; _componentModule = componentModule; + _inputFiles = inputFiles; _nodes = nodes; _nodeFactory = factory; _customPESectionAlignment = customPESectionAlignment; @@ -156,7 +158,6 @@ public NodeInfo(ISymbolNode node, int nodeIndex, int symbolIndex) _pdbPath = pdbPath; _generatePerfMapFile = generatePerfMapFile; _perfMapPath = perfMapPath; - _perfMapMvid = perfMapMvid; bool generateMap = (generateMapFile || generateMapCsvFile); bool generateSymbols = (generatePdbFile || generatePerfMapFile); @@ -329,6 +330,11 @@ public void EmitPortableExecutable() if (_outputInfoBuilder != null) { + foreach (string inputFile in _inputFiles) + { + _outputInfoBuilder.AddInputModule(_nodeFactory.TypeSystemContext.GetModuleFromPath(inputFile)); + } + r2rPeBuilder.AddSections(_outputInfoBuilder); if (_generateMapFile) @@ -361,7 +367,7 @@ public void EmitPortableExecutable() { path = Path.GetDirectoryName(_objectFilePath); } - _symbolFileBuilder.SavePerfMap(path, _objectFilePath, _perfMapMvid); + _symbolFileBuilder.SavePerfMap(path, _objectFilePath, _nodeFactory.Target.OperatingSystem, _nodeFactory.Target.Architecture); } if (_profileFileBuilder != null) @@ -430,6 +436,7 @@ private void EmitObjectData(R2RPEBuilder r2rPeBuilder, ObjectData data, int node public static void EmitObject( string objectFilePath, EcmaModule componentModule, + IEnumerable inputFiles, IEnumerable nodes, NodeFactory factory, bool generateMapFile, @@ -438,7 +445,6 @@ private void EmitObjectData(R2RPEBuilder r2rPeBuilder, ObjectData data, int node string pdbPath, bool generatePerfMapFile, string perfMapPath, - Guid? perfMapMvid, bool generateProfileFile, CallChainProfile callChainProfile, int customPESectionAlignment) @@ -447,6 +453,7 @@ private void EmitObjectData(R2RPEBuilder r2rPeBuilder, ObjectData data, int node ReadyToRunObjectWriter objectWriter = new ReadyToRunObjectWriter( objectFilePath, componentModule, + inputFiles, nodes, factory, generateMapFile: generateMapFile, @@ -455,7 +462,6 @@ private void EmitObjectData(R2RPEBuilder r2rPeBuilder, ObjectData data, int node pdbPath: pdbPath, generatePerfMapFile: generatePerfMapFile, perfMapPath: perfMapPath, - perfMapMvid: perfMapMvid, 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 1dce9f8f67f53..0b23a5577a585 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs @@ -247,7 +247,6 @@ public sealed class ReadyToRunCodegenCompilation : Compilation private readonly string _pdbPath; private readonly bool _generatePerfMapFile; private readonly string _perfMapPath; - private readonly Guid? _perfMapMvid; private readonly bool _generateProfileFile; private readonly Func _printReproInstructions; @@ -283,7 +282,6 @@ public sealed class ReadyToRunCodegenCompilation : Compilation string pdbPath, bool generatePerfMapFile, string perfMapPath, - Guid? perfMapMvid, bool generateProfileFile, int parallelism, ProfileDataManager profileData, @@ -309,7 +307,6 @@ public sealed class ReadyToRunCodegenCompilation : Compilation _pdbPath = pdbPath; _generatePerfMapFile = generatePerfMapFile; _perfMapPath = perfMapPath; - _perfMapMvid = perfMapMvid; _generateProfileFile = generateProfileFile; _customPESectionAlignment = customPESectionAlignment; SymbolNodeFactory = new ReadyToRunSymbolNodeFactory(nodeFactory, verifyTypeAndFieldLayout); @@ -347,6 +344,7 @@ public override void Compile(string outputFile) ReadyToRunObjectWriter.EmitObject( outputFile, componentModule: null, + inputFiles: _inputFiles, nodes, NodeFactory, generateMapFile: _generateMapFile, @@ -355,7 +353,6 @@ public override void Compile(string outputFile) pdbPath: _pdbPath, generatePerfMapFile: _generatePerfMapFile, perfMapPath: _perfMapPath, - perfMapMvid: _perfMapMvid, generateProfileFile: _generateProfileFile, callChainProfile: _profileData.CallChainProfile, _customPESectionAlignment); @@ -427,6 +424,7 @@ private void RewriteComponentFile(string inputFile, string outputFile, string ow ReadyToRunObjectWriter.EmitObject( outputFile, componentModule: inputModule, + inputFiles: new string[] { inputFile }, componentGraph.MarkedNodeList, componentFactory, generateMapFile: false, @@ -435,7 +433,6 @@ private void RewriteComponentFile(string inputFile, string outputFile, string ow pdbPath: null, generatePerfMapFile: false, perfMapPath: null, - perfMapMvid: null, 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 fa4d3182e9afb..1336fb0de4992 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilationBuilder.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilationBuilder.cs @@ -31,7 +31,6 @@ public sealed class ReadyToRunCodegenCompilationBuilder : CompilationBuilder private string _pdbPath; private bool _generatePerfMapFile; private string _perfMapPath; - private Guid? _perfMapMvid; private bool _generateProfileFile; private int _parallelism; Func _printReproInstructions; @@ -156,11 +155,10 @@ public ReadyToRunCodegenCompilationBuilder UsePdbFile(bool generatePdbFile, stri return this; } - public ReadyToRunCodegenCompilationBuilder UsePerfMapFile(bool generatePerfMapFile, string perfMapPath, Guid? inputModuleMvid) + public ReadyToRunCodegenCompilationBuilder UsePerfMapFile(bool generatePerfMapFile, string perfMapPath) { _generatePerfMapFile = generatePerfMapFile; _perfMapPath = perfMapPath; - _perfMapMvid = inputModuleMvid; return this; } @@ -312,7 +310,6 @@ public override ICompilation ToCompilation() pdbPath: _pdbPath, generatePerfMapFile: _generatePerfMapFile, perfMapPath: _perfMapPath, - perfMapMvid: _perfMapMvid, 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 82145e37999da..ca6efc9edb111 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 @@ public OutputSymbol(int sectionIndex, int offset, string name) /// public class OutputInfoBuilder { + private readonly List _inputModules; private readonly List _nodes; private readonly List _symbols; private readonly List
_sections; @@ -117,6 +118,7 @@ public class OutputInfoBuilder public OutputInfoBuilder() { + _inputModules = new List(); _nodes = new List(); _symbols = new List(); _sections = new List
(); @@ -127,6 +129,11 @@ public OutputInfoBuilder() _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 @@ public IEnumerable EnumerateMethods() } } + 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 7ec93572f6fc2..a4fdc4e560b71 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.Text; using System.Threading.Tasks; +using Internal.TypeSystem; using ILCompiler.Diagnostics; namespace ILCompiler.PEWriter @@ -28,12 +29,11 @@ public void SavePdb(string pdbPath, string dllFileName) new PdbWriter(pdbPath, PDBExtraData.None).WritePDBData(dllFileName, _outputInfoBuilder.EnumerateMethods()); } - public void SavePerfMap(string perfMapPath, string dllFileName, Guid? perfMapMvid) + public void SavePerfMap(string perfMapPath, 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 perfMapFileName = Path.Combine(perfMapPath, Path.GetFileNameWithoutExtension(dllFileName) + ".ni.map"); Console.WriteLine("Emitting PerfMap file: {0}", perfMapFileName); - PerfMapWriter.Write(perfMapFileName, _outputInfoBuilder.EnumerateMethods()); + PerfMapWriter.Write(perfMapFileName, _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 1424375efc4e3..0d332d59f91d0 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 f727ed872e03f..821a38f545e20 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.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 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 @@ public IReadOnlyList Methods public sealed class ReadyToRunReader { + public const int GuidByteSize = 16; + private const string SystemModuleName = "System.Private.CoreLib"; /// @@ -176,6 +179,33 @@ public Machine Machine } } + /// + /// 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 /// @@ -188,6 +218,36 @@ public OperatingSystem OperatingSystem } } + /// + /// 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 /// @@ -537,6 +597,12 @@ public IAssemblyMetadata GetGlobalMetadata() 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 @@ public int GetAssemblyIndex(ReadyToRunSection section) } } + 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/Program.cs b/src/coreclr/tools/aot/crossgen2/Program.cs index 2f84f6fb5a7e6..02855120000bd 100644 --- a/src/coreclr/tools/aot/crossgen2/Program.cs +++ b/src/coreclr/tools/aot/crossgen2/Program.cs @@ -517,7 +517,6 @@ private void RunSingleCompilation(Dictionary inFilePaths, Instru List inputModules = new List(); List rootingModules = new List(); - Guid? inputModuleMvid = null; foreach (var inputFile in inFilePaths) { @@ -526,10 +525,6 @@ private void RunSingleCompilation(Dictionary inFilePaths, Instru 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 @@ private void RunSingleCompilation(Dictionary inFilePaths, Instru .UseMapFile(_commandLineOptions.Map) .UseMapCsvFile(_commandLineOptions.MapCsv) .UsePdbFile(_commandLineOptions.Pdb, _commandLineOptions.PdbPath) - .UsePerfMapFile(_commandLineOptions.PerfMap, _commandLineOptions.PerfMapPath, inputModuleMvid) + .UsePerfMapFile(_commandLineOptions.PerfMap, _commandLineOptions.PerfMapPath) .UseProfileFile(jsonProfile != null) .UseParallelism(_commandLineOptions.Parallelism) .UseProfileData(profileDataManager) diff --git a/src/coreclr/tools/r2rdump/R2RDump.cs b/src/coreclr/tools/r2rdump/R2RDump.cs index 8a24273302b56..dc628d9e02af2 100644 --- a/src/coreclr/tools/r2rdump/R2RDump.cs +++ b/src/coreclr/tools/r2rdump/R2RDump.cs @@ -20,6 +20,7 @@ using ILCompiler.Reflection.ReadyToRun; using Internal.Runtime; +using Internal.TypeSystem; namespace R2RDump { @@ -426,8 +427,8 @@ public void Dump(ReadyToRunReader r2r) if (string.IsNullOrEmpty(perfmapPath)) { perfmapPath = Path.ChangeExtension(r2r.Filename, ".map"); - PerfMapWriter.Write(perfmapPath, ProduceDebugInfoMethods(r2r)); } + PerfMapWriter.Write(perfmapPath, ProduceDebugInfoMethods(r2r), ProduceDebugInfoAssemblies(r2r), r2r.TargetOperatingSystem, r2r.TargetArchitecture); } if (standardDump) @@ -457,6 +458,21 @@ IEnumerable ProduceDebugInfoMethods(ReadyToRunReader r2r) } } + 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 6596a597f104a..e8f71beb5a007 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 0e062b88508f9..7ca2b58c77dcd 100644 --- a/src/coreclr/tools/r2rdump/TextDumper.cs +++ b/src/coreclr/tools/r2rdump/TextDumper.cs @@ -7,6 +7,7 @@ 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 @@ internal override void DumpHeader(bool dumpSections) 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 @@ internal override void DumpSectionContents(ReadyToRunSection section) _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: From db9d4e5fc35c8472cbf0642ec66fdbe43c501608 Mon Sep 17 00:00:00 2001 From: Tomas Date: Wed, 30 Jun 2021 01:03:12 +0200 Subject: [PATCH 2/3] Address feedback towards the new perfmap metadata 1) Remove the detailed input assembly / MVID list as superfluous and potentially regressing average perfmap size. This information can be extracted from the composite R2R executable if needed. 2) Rename perfmap extension to "ni.r2rmap" per Brian's PR feedback. I haven't yet addressed the counterpart Arcade / SDK changes, I'll look into them next. Thanks Tomas --- .../aot/ILCompiler.Diagnostics/PerfMapWriter.cs | 14 ++++---------- .../ObjectWriter/SymbolFileBuilder.cs | 2 +- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/src/coreclr/tools/aot/ILCompiler.Diagnostics/PerfMapWriter.cs b/src/coreclr/tools/aot/ILCompiler.Diagnostics/PerfMapWriter.cs index 7f7e92fac7a84..c3c69ff2240bd 100644 --- a/src/coreclr/tools/aot/ILCompiler.Diagnostics/PerfMapWriter.cs +++ b/src/coreclr/tools/aot/ILCompiler.Diagnostics/PerfMapWriter.cs @@ -13,13 +13,14 @@ namespace ILCompiler.Diagnostics { public class PerfMapWriter { + public const int CurrentFormatVersion = 1; + public enum PseudoRVA : uint { OutputGuid = 0xFFFFFFFF, TargetOS = 0xFFFFFFFE, TargetArchitecture = 0xFFFFFFFD, - InputAssemblyName = 0xFFFFFFFC, - InputAssemblyMvid = 0xFFFFFFFB, + FormatVersion = 0xFFFFFFFC, } private TextWriter _writer; @@ -48,14 +49,7 @@ public static void Write(string perfMapFileName, IEnumerable methods perfMapWriter.WriteLine(outputGuid.ToString(), (uint)PseudoRVA.OutputGuid, 0); perfMapWriter.WriteLine(targetOS.ToString(), (uint)PseudoRVA.TargetOS, 0); perfMapWriter.WriteLine(targetArch.ToString(), (uint)PseudoRVA.TargetArchitecture, 0); - - uint inputAssemblyIndex = 0; - foreach (AssemblyInfo inputAssembly in orderedInputs) - { - perfMapWriter.WriteLine(inputAssembly.Name, (uint)PseudoRVA.InputAssemblyName, inputAssemblyIndex); - perfMapWriter.WriteLine(inputAssembly.Mvid.ToString(), (uint)PseudoRVA.InputAssemblyMvid, inputAssemblyIndex); - inputAssemblyIndex++; - } + perfMapWriter.WriteLine(CurrentFormatVersion.ToString(), (uint)PseudoRVA.FormatVersion, 0); foreach (MethodInfo methodInfo in methods) { diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/SymbolFileBuilder.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/SymbolFileBuilder.cs index a4fdc4e560b71..456bc7c8acb6a 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/SymbolFileBuilder.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/SymbolFileBuilder.cs @@ -31,7 +31,7 @@ public void SavePdb(string pdbPath, string dllFileName) public void SavePerfMap(string perfMapPath, string dllFileName, TargetOS targetOS, TargetArchitecture targetArch) { - string perfMapFileName = Path.Combine(perfMapPath, Path.GetFileNameWithoutExtension(dllFileName) + ".ni.map"); + string perfMapFileName = Path.Combine(perfMapPath, Path.GetFileNameWithoutExtension(dllFileName) + ".ni.r2rmap"); Console.WriteLine("Emitting PerfMap file: {0}", perfMapFileName); PerfMapWriter.Write(perfMapFileName, _outputInfoBuilder.EnumerateMethods(), _outputInfoBuilder.EnumerateInputAssemblies(), targetOS, targetArch); } From 85711401514588600900ac31a8a48ab62d28b72c Mon Sep 17 00:00:00 2001 From: Tomas Date: Thu, 1 Jul 2021 19:45:48 +0200 Subject: [PATCH 3/3] Add support for new option --perfmap-format-version Today, two PerfMap formats exist: (0) Legacy format produced by Crossgen1 with {MVID} in the file name. (1) New format produced by Crossgen2 / R2RDump without the {MVID} and with r2rmap extension. I haven't conditioned production of the new metadata, it gets produced even for format version 0 (legacy). I believe this is more useful for starting work on adapting perfmap consumers to use the new metadata. As next step I'll work on SDK and Arcade fixes for support of the new PerfMap format. Once all these changes land in the runtime repo, we can bump up the default format produced by Crossgen2 to 1. Thanks Tomas --- .../ILCompiler.Diagnostics/PerfMapWriter.cs | 9 +++++- .../CodeGen/ReadyToRunObjectWriter.cs | 11 ++++++- .../Compiler/ReadyToRunCodegenCompilation.cs | 5 ++++ .../ReadyToRunCodegenCompilationBuilder.cs | 5 +++- .../ObjectWriter/SymbolFileBuilder.cs | 29 +++++++++++++++++-- .../tools/aot/crossgen2/CommandLineOptions.cs | 5 ++++ src/coreclr/tools/aot/crossgen2/Program.cs | 2 +- .../aot/crossgen2/Properties/Resources.resx | 5 +++- .../tools/r2rdump/CommandLineOptions.cs | 1 + src/coreclr/tools/r2rdump/R2RDump.cs | 10 +++++-- 10 files changed, 72 insertions(+), 10 deletions(-) diff --git a/src/coreclr/tools/aot/ILCompiler.Diagnostics/PerfMapWriter.cs b/src/coreclr/tools/aot/ILCompiler.Diagnostics/PerfMapWriter.cs index c3c69ff2240bd..dd494b9fdcf9a 100644 --- a/src/coreclr/tools/aot/ILCompiler.Diagnostics/PerfMapWriter.cs +++ b/src/coreclr/tools/aot/ILCompiler.Diagnostics/PerfMapWriter.cs @@ -13,6 +13,8 @@ namespace ILCompiler.Diagnostics { public class PerfMapWriter { + public const int LegacyCrossgen1FormatVersion = 0; + public const int CurrentFormatVersion = 1; public enum PseudoRVA : uint @@ -30,8 +32,13 @@ private PerfMapWriter(TextWriter writer) _writer = writer; } - public static void Write(string perfMapFileName, IEnumerable methods, IEnumerable inputAssemblies, TargetOS targetOS, TargetArchitecture targetArch) + 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); diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/CodeGen/ReadyToRunObjectWriter.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/CodeGen/ReadyToRunObjectWriter.cs index e7d86b479475a..6404f77fbac06 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/CodeGen/ReadyToRunObjectWriter.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/CodeGen/ReadyToRunObjectWriter.cs @@ -106,6 +106,11 @@ internal class ReadyToRunObjectWriter /// private string _perfMapPath; + /// + /// Requested version of the perfmap file format + /// + 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. /// This is used to support loading via large pages on Linux. @@ -142,6 +147,7 @@ public NodeInfo(ISymbolNode node, int nodeIndex, int symbolIndex) string pdbPath, bool generatePerfMapFile, string perfMapPath, + int perfMapFormatVersion, bool generateProfileFile, CallChainProfile callChainProfile, int customPESectionAlignment) @@ -158,6 +164,7 @@ public NodeInfo(ISymbolNode node, int nodeIndex, int symbolIndex) _pdbPath = pdbPath; _generatePerfMapFile = generatePerfMapFile; _perfMapPath = perfMapPath; + _perfMapFormatVersion = perfMapFormatVersion; bool generateMap = (generateMapFile || generateMapCsvFile); bool generateSymbols = (generatePdbFile || generatePerfMapFile); @@ -367,7 +374,7 @@ public void EmitPortableExecutable() { path = Path.GetDirectoryName(_objectFilePath); } - _symbolFileBuilder.SavePerfMap(path, _objectFilePath, _nodeFactory.Target.OperatingSystem, _nodeFactory.Target.Architecture); + _symbolFileBuilder.SavePerfMap(path, _perfMapFormatVersion, _objectFilePath, _nodeFactory.Target.OperatingSystem, _nodeFactory.Target.Architecture); } if (_profileFileBuilder != null) @@ -445,6 +452,7 @@ private void EmitObjectData(R2RPEBuilder r2rPeBuilder, ObjectData data, int node string pdbPath, bool generatePerfMapFile, string perfMapPath, + int perfMapFormatVersion, bool generateProfileFile, CallChainProfile callChainProfile, int customPESectionAlignment) @@ -462,6 +470,7 @@ private void EmitObjectData(R2RPEBuilder r2rPeBuilder, ObjectData data, int node pdbPath: pdbPath, generatePerfMapFile: generatePerfMapFile, perfMapPath: perfMapPath, + 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 0b23a5577a585..ac7058bf90dae 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs @@ -247,6 +247,7 @@ public sealed class ReadyToRunCodegenCompilation : Compilation private readonly string _pdbPath; private readonly bool _generatePerfMapFile; private readonly string _perfMapPath; + private readonly int _perfMapFormatVersion; private readonly bool _generateProfileFile; private readonly Func _printReproInstructions; @@ -282,6 +283,7 @@ public sealed class ReadyToRunCodegenCompilation : Compilation string pdbPath, bool generatePerfMapFile, string perfMapPath, + int perfMapFormatVersion, bool generateProfileFile, int parallelism, ProfileDataManager profileData, @@ -307,6 +309,7 @@ public sealed class ReadyToRunCodegenCompilation : Compilation _pdbPath = pdbPath; _generatePerfMapFile = generatePerfMapFile; _perfMapPath = perfMapPath; + _perfMapFormatVersion = perfMapFormatVersion; _generateProfileFile = generateProfileFile; _customPESectionAlignment = customPESectionAlignment; SymbolNodeFactory = new ReadyToRunSymbolNodeFactory(nodeFactory, verifyTypeAndFieldLayout); @@ -353,6 +356,7 @@ public override void Compile(string outputFile) pdbPath: _pdbPath, generatePerfMapFile: _generatePerfMapFile, perfMapPath: _perfMapPath, + perfMapFormatVersion: _perfMapFormatVersion, generateProfileFile: _generateProfileFile, callChainProfile: _profileData.CallChainProfile, _customPESectionAlignment); @@ -433,6 +437,7 @@ private void RewriteComponentFile(string inputFile, string outputFile, string ow pdbPath: null, generatePerfMapFile: false, perfMapPath: 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 1336fb0de4992..c1207a4b5b2f0 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilationBuilder.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilationBuilder.cs @@ -31,6 +31,7 @@ public sealed class ReadyToRunCodegenCompilationBuilder : CompilationBuilder private string _pdbPath; private bool _generatePerfMapFile; private string _perfMapPath; + private int _perfMapFormatVersion; private bool _generateProfileFile; private int _parallelism; Func _printReproInstructions; @@ -155,10 +156,11 @@ public ReadyToRunCodegenCompilationBuilder UsePdbFile(bool generatePdbFile, stri return this; } - public ReadyToRunCodegenCompilationBuilder UsePerfMapFile(bool generatePerfMapFile, string perfMapPath) + public ReadyToRunCodegenCompilationBuilder UsePerfMapFile(bool generatePerfMapFile, string perfMapPath, int perfMapFormatVersion) { _generatePerfMapFile = generatePerfMapFile; _perfMapPath = perfMapPath; + _perfMapFormatVersion = perfMapFormatVersion; return this; } @@ -310,6 +312,7 @@ public override ICompilation ToCompilation() pdbPath: _pdbPath, generatePerfMapFile: _generatePerfMapFile, perfMapPath: _perfMapPath, + perfMapFormatVersion: _perfMapFormatVersion, generateProfileFile: _generateProfileFile, _parallelism, _profileData, diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/SymbolFileBuilder.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/SymbolFileBuilder.cs index 456bc7c8acb6a..8cd0ad481cc6d 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/SymbolFileBuilder.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/SymbolFileBuilder.cs @@ -29,11 +29,34 @@ public void SavePdb(string pdbPath, string dllFileName) new PdbWriter(pdbPath, PDBExtraData.None).WritePDBData(dllFileName, _outputInfoBuilder.EnumerateMethods()); } - public void SavePerfMap(string perfMapPath, string dllFileName, TargetOS targetOS, TargetArchitecture targetArch) + public void SavePerfMap(string perfMapPath, int perfMapFormatVersion, string dllFileName, TargetOS targetOS, TargetArchitecture targetArch) { - string perfMapFileName = Path.Combine(perfMapPath, Path.GetFileNameWithoutExtension(dllFileName) + ".ni.r2rmap"); + 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(), _outputInfoBuilder.EnumerateInputAssemblies(), targetOS, targetArch); + PerfMapWriter.Write(perfMapFileName, perfMapFormatVersion, _outputInfoBuilder.EnumerateMethods(), _outputInfoBuilder.EnumerateInputAssemblies(), targetOS, targetArch); } } } diff --git a/src/coreclr/tools/aot/crossgen2/CommandLineOptions.cs b/src/coreclr/tools/aot/crossgen2/CommandLineOptions.cs index 573b1eb5cb497..c91e615eb73a8 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 @@ internal class CommandLineOptions 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 @@ public CommandLineOptions(string[] args) MibcFilePaths = Array.Empty(); CodegenOptions = Array.Empty(); + PerfMapFormatVersion = DefaultPerfMapFormatVersion; Parallelism = Environment.ProcessorCount; SingleMethodGenericArg = null; @@ -139,6 +143,7 @@ public CommandLineOptions(string[] args) 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 02855120000bd..aeeb9f57bb3c4 100644 --- a/src/coreclr/tools/aot/crossgen2/Program.cs +++ b/src/coreclr/tools/aot/crossgen2/Program.cs @@ -682,7 +682,7 @@ private void RunSingleCompilation(Dictionary inFilePaths, Instru .UseMapFile(_commandLineOptions.Map) .UseMapCsvFile(_commandLineOptions.MapCsv) .UsePdbFile(_commandLineOptions.Pdb, _commandLineOptions.PdbPath) - .UsePerfMapFile(_commandLineOptions.PerfMap, _commandLineOptions.PerfMapPath) + .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 084138ebc7c4d..c031f303e44e0 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 8857cdbae87ac..9a1296bdbd65d 100644 --- a/src/coreclr/tools/r2rdump/CommandLineOptions.cs +++ b/src/coreclr/tools/r2rdump/CommandLineOptions.cs @@ -40,6 +40,7 @@ public static RootCommand RootCommand() 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 dc628d9e02af2..94d71835966e5 100644 --- a/src/coreclr/tools/r2rdump/R2RDump.cs +++ b/src/coreclr/tools/r2rdump/R2RDump.cs @@ -56,6 +56,7 @@ public class DumpOptions : IAssemblyResolver public bool CreatePerfmap { get; set; } public string PerfmapPath { get; set; } + public int PerfmapFormatVersion { get; set; } public FileInfo[] Reference { get; set; } @@ -66,6 +67,11 @@ public class DumpOptions : IAssemblyResolver private SignatureFormattingOptions signatureFormattingOptions; + public DumpOptions() + { + PerfmapFormatVersion = PerfMapWriter.CurrentFormatVersion; + } + /// /// Probing extensions to use when looking up assemblies under reference paths. /// @@ -426,9 +432,9 @@ public void Dump(ReadyToRunReader r2r) string perfmapPath = _options.PerfmapPath; if (string.IsNullOrEmpty(perfmapPath)) { - perfmapPath = Path.ChangeExtension(r2r.Filename, ".map"); + perfmapPath = Path.ChangeExtension(r2r.Filename, ".r2rmap"); } - PerfMapWriter.Write(perfmapPath, ProduceDebugInfoMethods(r2r), ProduceDebugInfoAssemblies(r2r), r2r.TargetOperatingSystem, r2r.TargetArchitecture); + PerfMapWriter.Write(perfmapPath, _options.PerfmapFormatVersion, ProduceDebugInfoMethods(r2r), ProduceDebugInfoAssemblies(r2r), r2r.TargetOperatingSystem, r2r.TargetArchitecture); } if (standardDump)