Skip to content

Commit e3dd985

Browse files
authored
Expand PerfMap format to support metadata for symbol indexation (dotnet#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
1 parent 08a7b23 commit e3dd985

17 files changed

+321
-47
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
6+
namespace ILCompiler.Diagnostics
7+
{
8+
public struct AssemblyInfo
9+
{
10+
public readonly string Name;
11+
public readonly Guid Mvid;
12+
13+
public AssemblyInfo(string name, Guid mvid)
14+
{
15+
Name = name;
16+
Mvid = mvid;
17+
}
18+
}
19+
}

src/coreclr/tools/aot/ILCompiler.Diagnostics/ILCompiler.Diagnostics.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,8 @@
1717
<Configurations>Debug;Release;Checked</Configurations>
1818
</PropertyGroup>
1919

20+
<ItemGroup>
21+
<ProjectReference Include="..\ILCompiler.TypeSystem.ReadyToRun\ILCompiler.TypeSystem.ReadyToRun.csproj" />
22+
</ItemGroup>
23+
2024
</Project>

src/coreclr/tools/aot/ILCompiler.Diagnostics/PerfMapWriter.cs

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,60 @@
44
using System;
55
using System.Collections.Generic;
66
using System.IO;
7+
using System.Linq;
8+
using System.Security.Cryptography;
9+
10+
using Internal.TypeSystem;
711

812
namespace ILCompiler.Diagnostics
913
{
1014
public class PerfMapWriter
1115
{
16+
public const int LegacyCrossgen1FormatVersion = 0;
17+
18+
public const int CurrentFormatVersion = 1;
19+
20+
public enum PseudoRVA : uint
21+
{
22+
OutputGuid = 0xFFFFFFFF,
23+
TargetOS = 0xFFFFFFFE,
24+
TargetArchitecture = 0xFFFFFFFD,
25+
FormatVersion = 0xFFFFFFFC,
26+
}
27+
1228
private TextWriter _writer;
1329

1430
private PerfMapWriter(TextWriter writer)
1531
{
1632
_writer = writer;
1733
}
1834

19-
public static void Write(string perfMapFileName, IEnumerable<MethodInfo> methods)
35+
public static void Write(string perfMapFileName, int perfMapFormatVersion, IEnumerable<MethodInfo> methods, IEnumerable<AssemblyInfo> inputAssemblies, TargetOS targetOS, TargetArchitecture targetArch)
2036
{
37+
if (perfMapFormatVersion > CurrentFormatVersion)
38+
{
39+
throw new NotSupportedException(perfMapFormatVersion.ToString());
40+
}
41+
2142
using (TextWriter writer = new StreamWriter(perfMapFileName))
2243
{
44+
IEnumerable<AssemblyInfo> orderedInputs = inputAssemblies.OrderBy(asm => asm.Name, StringComparer.OrdinalIgnoreCase);
45+
2346
PerfMapWriter perfMapWriter = new PerfMapWriter(writer);
47+
48+
List<byte> inputHash = new List<byte>();
49+
foreach (AssemblyInfo inputAssembly in orderedInputs)
50+
{
51+
inputHash.AddRange(inputAssembly.Mvid.ToByteArray());
52+
}
53+
inputHash.Add((byte)targetOS);
54+
inputHash.Add((byte)targetArch);
55+
Guid outputGuid = new Guid(MD5.HashData(inputHash.ToArray()));
56+
perfMapWriter.WriteLine(outputGuid.ToString(), (uint)PseudoRVA.OutputGuid, 0);
57+
perfMapWriter.WriteLine(targetOS.ToString(), (uint)PseudoRVA.TargetOS, 0);
58+
perfMapWriter.WriteLine(targetArch.ToString(), (uint)PseudoRVA.TargetArchitecture, 0);
59+
perfMapWriter.WriteLine(CurrentFormatVersion.ToString(), (uint)PseudoRVA.FormatVersion, 0);
60+
2461
foreach (MethodInfo methodInfo in methods)
2562
{
2663
if (methodInfo.HotRVA != 0 && methodInfo.HotLength != 0)

src/coreclr/tools/aot/ILCompiler.ReadyToRun/CodeGen/ReadyToRunObjectWriter.cs

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ internal class ReadyToRunObjectWriter
4545
/// </summary>
4646
private readonly EcmaModule _componentModule;
4747

48+
/// <summary>
49+
/// Compilation input files. Input files are emitted as perfmap entries and used
50+
/// to calculate the output GUID of the ReadyToRun executable for symbol indexation.
51+
/// </summary>
52+
private readonly IEnumerable<string> _inputFiles;
53+
4854
/// <summary>
4955
/// Nodes to emit into the output executable as collected by the dependency analysis.
5056
/// </summary>
@@ -101,9 +107,9 @@ internal class ReadyToRunObjectWriter
101107
private string _perfMapPath;
102108

103109
/// <summary>
104-
/// MVID of the input managed module to embed in the perfmap file name.
110+
/// Requested version of the perfmap file format
105111
/// </summary>
106-
private Guid? _perfMapMvid;
112+
private int _perfMapFormatVersion;
107113

108114
/// <summary>
109115
/// 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 @@ public NodeInfo(ISymbolNode node, int nodeIndex, int symbolIndex)
132138
public ReadyToRunObjectWriter(
133139
string objectFilePath,
134140
EcmaModule componentModule,
141+
IEnumerable<string> inputFiles,
135142
IEnumerable<DependencyNode> nodes,
136143
NodeFactory factory,
137144
bool generateMapFile,
@@ -140,13 +147,14 @@ public ReadyToRunObjectWriter(
140147
string pdbPath,
141148
bool generatePerfMapFile,
142149
string perfMapPath,
143-
Guid? perfMapMvid,
150+
int perfMapFormatVersion,
144151
bool generateProfileFile,
145152
CallChainProfile callChainProfile,
146153
int customPESectionAlignment)
147154
{
148155
_objectFilePath = objectFilePath;
149156
_componentModule = componentModule;
157+
_inputFiles = inputFiles;
150158
_nodes = nodes;
151159
_nodeFactory = factory;
152160
_customPESectionAlignment = customPESectionAlignment;
@@ -156,7 +164,7 @@ public ReadyToRunObjectWriter(
156164
_pdbPath = pdbPath;
157165
_generatePerfMapFile = generatePerfMapFile;
158166
_perfMapPath = perfMapPath;
159-
_perfMapMvid = perfMapMvid;
167+
_perfMapFormatVersion = perfMapFormatVersion;
160168

161169
bool generateMap = (generateMapFile || generateMapCsvFile);
162170
bool generateSymbols = (generatePdbFile || generatePerfMapFile);
@@ -329,6 +337,11 @@ public void EmitPortableExecutable()
329337

330338
if (_outputInfoBuilder != null)
331339
{
340+
foreach (string inputFile in _inputFiles)
341+
{
342+
_outputInfoBuilder.AddInputModule(_nodeFactory.TypeSystemContext.GetModuleFromPath(inputFile));
343+
}
344+
332345
r2rPeBuilder.AddSections(_outputInfoBuilder);
333346

334347
if (_generateMapFile)
@@ -361,7 +374,7 @@ public void EmitPortableExecutable()
361374
{
362375
path = Path.GetDirectoryName(_objectFilePath);
363376
}
364-
_symbolFileBuilder.SavePerfMap(path, _objectFilePath, _perfMapMvid);
377+
_symbolFileBuilder.SavePerfMap(path, _perfMapFormatVersion, _objectFilePath, _nodeFactory.Target.OperatingSystem, _nodeFactory.Target.Architecture);
365378
}
366379

367380
if (_profileFileBuilder != null)
@@ -430,6 +443,7 @@ private void EmitObjectData(R2RPEBuilder r2rPeBuilder, ObjectData data, int node
430443
public static void EmitObject(
431444
string objectFilePath,
432445
EcmaModule componentModule,
446+
IEnumerable<string> inputFiles,
433447
IEnumerable<DependencyNode> nodes,
434448
NodeFactory factory,
435449
bool generateMapFile,
@@ -438,7 +452,7 @@ public static void EmitObject(
438452
string pdbPath,
439453
bool generatePerfMapFile,
440454
string perfMapPath,
441-
Guid? perfMapMvid,
455+
int perfMapFormatVersion,
442456
bool generateProfileFile,
443457
CallChainProfile callChainProfile,
444458
int customPESectionAlignment)
@@ -447,6 +461,7 @@ public static void EmitObject(
447461
ReadyToRunObjectWriter objectWriter = new ReadyToRunObjectWriter(
448462
objectFilePath,
449463
componentModule,
464+
inputFiles,
450465
nodes,
451466
factory,
452467
generateMapFile: generateMapFile,
@@ -455,7 +470,7 @@ public static void EmitObject(
455470
pdbPath: pdbPath,
456471
generatePerfMapFile: generatePerfMapFile,
457472
perfMapPath: perfMapPath,
458-
perfMapMvid: perfMapMvid,
473+
perfMapFormatVersion: perfMapFormatVersion,
459474
generateProfileFile: generateProfileFile,
460475
callChainProfile,
461476
customPESectionAlignment);

src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ public sealed class ReadyToRunCodegenCompilation : Compilation
247247
private readonly string _pdbPath;
248248
private readonly bool _generatePerfMapFile;
249249
private readonly string _perfMapPath;
250-
private readonly Guid? _perfMapMvid;
250+
private readonly int _perfMapFormatVersion;
251251
private readonly bool _generateProfileFile;
252252
private readonly Func<MethodDesc, string> _printReproInstructions;
253253

@@ -283,7 +283,7 @@ internal ReadyToRunCodegenCompilation(
283283
string pdbPath,
284284
bool generatePerfMapFile,
285285
string perfMapPath,
286-
Guid? perfMapMvid,
286+
int perfMapFormatVersion,
287287
bool generateProfileFile,
288288
int parallelism,
289289
ProfileDataManager profileData,
@@ -309,7 +309,7 @@ internal ReadyToRunCodegenCompilation(
309309
_pdbPath = pdbPath;
310310
_generatePerfMapFile = generatePerfMapFile;
311311
_perfMapPath = perfMapPath;
312-
_perfMapMvid = perfMapMvid;
312+
_perfMapFormatVersion = perfMapFormatVersion;
313313
_generateProfileFile = generateProfileFile;
314314
_customPESectionAlignment = customPESectionAlignment;
315315
SymbolNodeFactory = new ReadyToRunSymbolNodeFactory(nodeFactory, verifyTypeAndFieldLayout);
@@ -347,6 +347,7 @@ public override void Compile(string outputFile)
347347
ReadyToRunObjectWriter.EmitObject(
348348
outputFile,
349349
componentModule: null,
350+
inputFiles: _inputFiles,
350351
nodes,
351352
NodeFactory,
352353
generateMapFile: _generateMapFile,
@@ -355,7 +356,7 @@ public override void Compile(string outputFile)
355356
pdbPath: _pdbPath,
356357
generatePerfMapFile: _generatePerfMapFile,
357358
perfMapPath: _perfMapPath,
358-
perfMapMvid: _perfMapMvid,
359+
perfMapFormatVersion: _perfMapFormatVersion,
359360
generateProfileFile: _generateProfileFile,
360361
callChainProfile: _profileData.CallChainProfile,
361362
_customPESectionAlignment);
@@ -427,6 +428,7 @@ private void RewriteComponentFile(string inputFile, string outputFile, string ow
427428
ReadyToRunObjectWriter.EmitObject(
428429
outputFile,
429430
componentModule: inputModule,
431+
inputFiles: new string[] { inputFile },
430432
componentGraph.MarkedNodeList,
431433
componentFactory,
432434
generateMapFile: false,
@@ -435,7 +437,7 @@ private void RewriteComponentFile(string inputFile, string outputFile, string ow
435437
pdbPath: null,
436438
generatePerfMapFile: false,
437439
perfMapPath: null,
438-
perfMapMvid: null,
440+
perfMapFormatVersion: _perfMapFormatVersion,
439441
generateProfileFile: false,
440442
_profileData.CallChainProfile,
441443
customPESectionAlignment: 0);

src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilationBuilder.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public sealed class ReadyToRunCodegenCompilationBuilder : CompilationBuilder
3131
private string _pdbPath;
3232
private bool _generatePerfMapFile;
3333
private string _perfMapPath;
34-
private Guid? _perfMapMvid;
34+
private int _perfMapFormatVersion;
3535
private bool _generateProfileFile;
3636
private int _parallelism;
3737
Func<MethodDesc, string> _printReproInstructions;
@@ -156,11 +156,11 @@ public ReadyToRunCodegenCompilationBuilder UsePdbFile(bool generatePdbFile, stri
156156
return this;
157157
}
158158

159-
public ReadyToRunCodegenCompilationBuilder UsePerfMapFile(bool generatePerfMapFile, string perfMapPath, Guid? inputModuleMvid)
159+
public ReadyToRunCodegenCompilationBuilder UsePerfMapFile(bool generatePerfMapFile, string perfMapPath, int perfMapFormatVersion)
160160
{
161161
_generatePerfMapFile = generatePerfMapFile;
162162
_perfMapPath = perfMapPath;
163-
_perfMapMvid = inputModuleMvid;
163+
_perfMapFormatVersion = perfMapFormatVersion;
164164
return this;
165165
}
166166

@@ -312,7 +312,7 @@ public override ICompilation ToCompilation()
312312
pdbPath: _pdbPath,
313313
generatePerfMapFile: _generatePerfMapFile,
314314
perfMapPath: _perfMapPath,
315-
perfMapMvid: _perfMapMvid,
315+
perfMapFormatVersion: _perfMapFormatVersion,
316316
generateProfileFile: _generateProfileFile,
317317
_parallelism,
318318
_profileData,

src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/OutputInfoBuilder.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ public OutputSymbol(int sectionIndex, int offset, string name)
106106
/// </summary>
107107
public class OutputInfoBuilder
108108
{
109+
private readonly List<EcmaModule> _inputModules;
109110
private readonly List<OutputNode> _nodes;
110111
private readonly List<OutputSymbol> _symbols;
111112
private readonly List<Section> _sections;
@@ -117,6 +118,7 @@ public class OutputInfoBuilder
117118

118119
public OutputInfoBuilder()
119120
{
121+
_inputModules = new List<EcmaModule>();
120122
_nodes = new List<OutputNode>();
121123
_symbols = new List<OutputSymbol>();
122124
_sections = new List<Section>();
@@ -127,6 +129,11 @@ public OutputInfoBuilder()
127129
_relocCounts = new Dictionary<RelocType, int>();
128130
}
129131

132+
public void AddInputModule(EcmaModule module)
133+
{
134+
_inputModules.Add(module);
135+
}
136+
130137
public void AddNode(OutputNode node, ISymbolDefinitionNode symbol)
131138
{
132139
_nodes.Add(node);
@@ -197,6 +204,16 @@ public IEnumerable<MethodInfo> EnumerateMethods()
197204
}
198205
}
199206

207+
public IEnumerable<AssemblyInfo> EnumerateInputAssemblies()
208+
{
209+
foreach (EcmaModule inputModule in _inputModules)
210+
{
211+
yield return new AssemblyInfo(
212+
inputModule.Assembly.GetName().Name,
213+
inputModule.MetadataReader.GetGuid(inputModule.MetadataReader.GetModuleDefinition().Mvid));
214+
}
215+
}
216+
200217
private string FormatMethodName(MethodDesc method, TypeNameFormatter typeNameFormatter)
201218
{
202219
StringBuilder output = new StringBuilder();

src/coreclr/tools/aot/ILCompiler.ReadyToRun/ObjectWriter/SymbolFileBuilder.cs

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using System.Text;
99
using System.Threading.Tasks;
1010

11+
using Internal.TypeSystem;
1112
using ILCompiler.Diagnostics;
1213

1314
namespace ILCompiler.PEWriter
@@ -28,12 +29,34 @@ public void SavePdb(string pdbPath, string dllFileName)
2829
new PdbWriter(pdbPath, PDBExtraData.None).WritePDBData(dllFileName, _outputInfoBuilder.EnumerateMethods());
2930
}
3031

31-
public void SavePerfMap(string perfMapPath, string dllFileName, Guid? perfMapMvid)
32+
public void SavePerfMap(string perfMapPath, int perfMapFormatVersion, string dllFileName, TargetOS targetOS, TargetArchitecture targetArch)
3233
{
33-
string mvidComponent = (perfMapMvid.HasValue ? perfMapMvid.Value.ToString() : "composite");
34-
string perfMapFileName = Path.Combine(perfMapPath, Path.GetFileNameWithoutExtension(dllFileName) + ".ni.{" + mvidComponent + "}.map");
34+
string perfMapExtension;
35+
if (perfMapFormatVersion == PerfMapWriter.LegacyCrossgen1FormatVersion)
36+
{
37+
string mvidComponent = null;
38+
foreach (AssemblyInfo inputAssembly in _outputInfoBuilder.EnumerateInputAssemblies())
39+
{
40+
if (mvidComponent == null)
41+
{
42+
mvidComponent = inputAssembly.Mvid.ToString();
43+
}
44+
else
45+
{
46+
mvidComponent = "composite";
47+
break;
48+
}
49+
}
50+
perfMapExtension = ".ni.{" + mvidComponent + "}.map";
51+
}
52+
else
53+
{
54+
perfMapExtension = ".ni.r2rmap";
55+
}
56+
57+
string perfMapFileName = Path.Combine(perfMapPath, Path.GetFileNameWithoutExtension(dllFileName) + perfMapExtension);
3558
Console.WriteLine("Emitting PerfMap file: {0}", perfMapFileName);
36-
PerfMapWriter.Write(perfMapFileName, _outputInfoBuilder.EnumerateMethods());
59+
PerfMapWriter.Write(perfMapFileName, perfMapFormatVersion, _outputInfoBuilder.EnumerateMethods(), _outputInfoBuilder.EnumerateInputAssemblies(), targetOS, targetArch);
3760
}
3861
}
3962
}

0 commit comments

Comments
 (0)