Skip to content

Commit ea4f5f2

Browse files
authored
Initial PDB / PerfMap support in Crossgen2 + System.Private.CoreLib switchover to use Crossgen2 (#47019)
I have moved the PDB writer code to a new assembly ILCompiler.Diagnostics so that it can be reused by Crossgen2. I have also added an initial trivial implementation of the PerfMap writer. Thanks Tomas
1 parent 3aa65f2 commit ea4f5f2

28 files changed

+753
-252
lines changed

src/coreclr/crossgen-corelib.proj

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
AfterTargets="Build">
99
<PropertyGroup>
1010
<!-- Default for using Crossgen2 when not set externally -->
11-
<UseCrossgen2 Condition="'$(UseCrossgen2)' == ''">false</UseCrossgen2>
11+
<UseCrossgen2 Condition="'$(UseCrossgen2)' == ''">true</UseCrossgen2>
1212

1313
<OSPlatformConfig>$(TargetOS).$(TargetArchitecture).$(Configuration)</OSPlatformConfig>
1414
<RootBinDir>$([MSBuild]::NormalizeDirectory('$(RepoRoot)', 'artifacts'))</RootBinDir>
@@ -65,27 +65,22 @@
6565
<CrossGenDllCmd>$(CrossGenDllCmd) $(CoreLibInputPath)</CrossGenDllCmd>
6666
</PropertyGroup>
6767

68+
<PropertyGroup Condition="$(BuildPdb)">
69+
<CrossGenDllCmd>$(CrossGenDllCmd) --pdb --pdb-path:$([MSBuild]::NormalizePath('$(BinDir)', 'PDB'))</CrossGenDllCmd>
70+
</PropertyGroup>
71+
72+
<PropertyGroup Condition="$(BuildPerfMap)">
73+
<CrossGenDllCmd>$(CrossGenDllCmd) --perfmap --perfmap-path:$(BinDir)</CrossGenDllCmd>
74+
</PropertyGroup>
75+
6876
<PropertyGroup Condition="'$(UseCrossgen2)' != 'true'">
77+
<VsSetupCmd>call $([MSBuild]::NormalizePath('$(RepoRoot)', 'src', 'coreclr', 'setup_vs_tools.cmd')) &amp;&amp;</VsSetupCmd>
78+
6979
<CrossGenDllCmd>$(CrossGen1Cmd) /out "$(CoreLibOutputPath)"</CrossGenDllCmd>
7080
<CrossGenDllCmd>$(CrossGenDllCmd) "$(CoreLibInputPath)"</CrossGenDllCmd>
71-
</PropertyGroup>
7281

73-
<!-- For now we're using Crossgen1 for generating the perf map as Crossgen2 doesn't yet implement it: -->
74-
<!-- https://github.com/dotnet/runtime/issues/44123 -->
75-
<PropertyGroup Condition="$(BuildPerfMap)">
7682
<CrossGenPerfMapCmd>$(CrossGen1Cmd) /CreatePerfMap "$(BinDir)"</CrossGenPerfMapCmd>
7783
<CrossGenPerfMapCmd>$(CrossGenPerfMapCmd) "$(CoreLibOutputPath)"</CrossGenPerfMapCmd>
78-
</PropertyGroup>
79-
80-
<PropertyGroup Condition="$(BuildPdb)">
81-
<CrossGenPdbCmd>$(DotNetCli) $([MSBuild]::NormalizePath('$(BinDir)', 'r2rdump', 'r2rdump.dll'))</CrossGenPdbCmd>
82-
<CrossGenPdbCmd>$(CrossGenPdbCmd) --create-pdb</CrossGenPdbCmd>
83-
<CrossGenPdbCmd>$(CrossGenPdbCmd) --pdb-path:$([MSBuild]::NormalizePath('$(BinDir)', 'PDB'))</CrossGenPdbCmd>
84-
<CrossGenPdbCmd>$(CrossGenPdbCmd) --in:$(CoreLibOutputPath)</CrossGenPdbCmd>
85-
</PropertyGroup>
86-
87-
<PropertyGroup Condition="$(BuildPdb) and '$(UseCrossgen2)' != 'true'">
88-
<VsSetupCmd>call $([MSBuild]::NormalizePath('$(RepoRoot)', 'src', 'coreclr', 'setup_vs_tools.cmd')) &amp;&amp;</VsSetupCmd>
8984

9085
<CrossGenPdbCmd>$(VsSetupCmd) $(CrossGen1Cmd) /CreatePdb "$([MSBuild]::NormalizePath('$(BinDir)', 'PDB'))"</CrossGenPdbCmd>
9186
<CrossGenPdbCmd>$(CrossGenPdbCmd) "$(CoreLibOutputPath)"</CrossGenPdbCmd>
@@ -97,11 +92,11 @@
9792

9893
<Message Condition="$(BuildPdb)" Importance="High" Text="$(CrossGenPdbCmd)" />
9994

100-
<Exec Condition="$(BuildPdb)" Command="$(CrossGenPdbCmd)" />
95+
<Exec Condition="$(BuildPdb) and '$(CrossGenPdbCmd)' != ''" Command="$(CrossGenPdbCmd)" />
10196

10297
<Message Condition="$(BuildPerfMap)" Importance="High" Text="$(CrossGenPerfMapCmd)" />
10398

104-
<Exec Condition="$(BuildPerfMap)" Command="$(CrossGenPerfMapCmd)" />
99+
<Exec Condition="$(BuildPerfMap) and '$(CrossGenPerfMapCmd)' != ''" Command="$(CrossGenPerfMapCmd)" />
105100

106101
<Copy Condition="!$(BuildDll)" SourceFiles="$(CoreLibInputPath)" DestinationFiles="$(CoreLibOutputPath)" UseHardlinksIfPossible="true" />
107102

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<AssemblyName>ILCompiler.Diagnostics</AssemblyName>
5+
<OutputType>Library</OutputType>
6+
<IsDotNetFrameworkProductAssembly>true</IsDotNetFrameworkProductAssembly>
7+
<TargetFramework>$(NetCoreAppToolCurrent)</TargetFramework>
8+
<DefineConstants>READYTORUN;$(DefineConstants)</DefineConstants>
9+
<Platforms>x64;x86;arm;arm64</Platforms>
10+
<PlatformTarget>AnyCPU</PlatformTarget>
11+
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
12+
13+
<!-- We're binplacing these into an existing publish layout so that F5 build in VS updates
14+
the same bits tests expect to see in artifacts/crossgen2. That way we never need to wonder which
15+
binaries are up to date and which are stale. -->
16+
<GenerateDependencyFile>false</GenerateDependencyFile>
17+
<Configurations>Debug;Release;Checked</Configurations>
18+
</PropertyGroup>
19+
20+
</Project>
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
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+
namespace ILCompiler.Diagnostics
5+
{
6+
public struct MethodInfo
7+
{
8+
public string AssemblyName;
9+
public uint MethodToken;
10+
public uint HotRVA;
11+
public uint HotLength;
12+
public string Name;
13+
public uint ColdRVA;
14+
public uint ColdLength;
15+
}
16+
}

src/coreclr/tools/r2rdump/PdbWriter.cs renamed to src/coreclr/tools/aot/ILCompiler.Diagnostics/PdbWriter.cs

Lines changed: 15 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
using Microsoft.DiaSymReader;
1212

13-
namespace ILCompiler.PdbWriter
13+
namespace ILCompiler.Diagnostics
1414
{
1515
// NGEN always generates PDBs with public symbols lists (so tools can map IP ranges to
1616
// methods). This bitmask indicates what extra info should be added to the PDB
@@ -23,20 +23,6 @@ public enum PDBExtraData
2323
kPDBLines = 0x00000001,
2424
};
2525

26-
struct MethodInfo
27-
{
28-
public string AssemblyName;
29-
public uint MethodToken;
30-
public uint HotRVA;
31-
public string Name;
32-
public uint ColdRVA;
33-
}
34-
35-
interface IModuleData
36-
{
37-
IEnumerable<MethodInfo> Methods { get; }
38-
}
39-
4026
public enum SymChecksumType : byte
4127
{
4228
None = 0, // indicates no checksum is available
@@ -85,7 +71,7 @@ public bool Equals(SymDocument other)
8571
}
8672
}
8773

88-
class PdbWriter
74+
public class PdbWriter
8975
{
9076
string _pdbPath;
9177
PDBExtraData _pdbExtraData;
@@ -204,26 +190,33 @@ private void WritePDBDataHelper(string dllPath, IEnumerable<MethodInfo> methods)
204190
throw new NotImplementedException();
205191
}
206192

193+
string dllNameWithoutExtension = Path.GetFileNameWithoutExtension(dllPath);
194+
_pdbFilePath = Path.Combine(_pdbPath, dllNameWithoutExtension + ".pdb");
195+
207196
string originalDllPath = dllPath;
208197

209198
// Currently DiaSymReader does not work properly generating NGEN PDBS unless
210199
// the DLL whose PDB is being generated ends in .ni.*. Unfortunately, readyToRun
211200
// images do not follow this convention and end up producing bad PDBS. To fix
212201
// this (without changing diasymreader.dll which ships indepdendently of .NET Core)
213-
// we copy the file to somethign with this convention before generating the PDB
202+
// we copy the file to something with this convention before generating the PDB
214203
// and delete it when we are done.
215204
if (!dllPath.EndsWith(".ni.dll", StringComparison.OrdinalIgnoreCase) && !dllPath.EndsWith(".ni.exe", StringComparison.OrdinalIgnoreCase))
216205
{
217-
_tempSourceDllName = Path.Combine(Path.GetDirectoryName(dllPath), Path.GetFileNameWithoutExtension(dllPath) + ".ni" + Path.GetExtension(dllPath));
218-
File.Copy(dllPath, _tempSourceDllName);
206+
_tempSourceDllName = Path.Combine(Path.GetDirectoryName(dllPath), dllNameWithoutExtension + ".ni" + Path.GetExtension(dllPath));
207+
File.Copy(dllPath, _tempSourceDllName, overwrite: true);
219208
dllPath = _tempSourceDllName;
209+
_pdbFilePath = Path.Combine(_pdbPath, dllNameWithoutExtension + ".ni.pdb");
220210
}
221211

222-
_ngenWriter = CreateNGenWriter(dllPath, _pdbPath + "\\");
212+
// Delete any preexisting PDB file upfront otherwise CreateNGenWriter silently opens it
213+
File.Delete(_pdbFilePath);
214+
215+
_ngenWriter = CreateNGenWriter(dllPath, _pdbFilePath);
223216

224217
{
225-
// PDB file is now created. Get its path and initialize _pdbFilePath so the PDB file
226-
// can be deleted if we don't make it successfully to the end
218+
// PDB file is now created. Get its path and update _pdbFilePath so the PDB file
219+
// can be deleted if we don't make it successfully to the end.
227220
StringBuilder pdbFilePathBuilder = new StringBuilder();
228221
pdbFilePathBuilder.Capacity = 1024;
229222
_ngenWriter.QueryPDBNameExW(pdbFilePathBuilder, new IntPtr(pdbFilePathBuilder.Capacity));
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
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+
using System.Collections.Generic;
6+
using System.IO;
7+
8+
namespace ILCompiler.Diagnostics
9+
{
10+
public class PerfMapWriter
11+
{
12+
private TextWriter _writer;
13+
14+
private PerfMapWriter(TextWriter writer)
15+
{
16+
_writer = writer;
17+
}
18+
19+
public static void Write(string perfMapFileName, IEnumerable<MethodInfo> methods)
20+
{
21+
using (TextWriter writer = new StreamWriter(perfMapFileName))
22+
{
23+
PerfMapWriter perfMapWriter = new PerfMapWriter(writer);
24+
foreach (MethodInfo methodInfo in methods)
25+
{
26+
if (methodInfo.HotRVA != 0 && methodInfo.HotLength != 0)
27+
{
28+
perfMapWriter.WriteLine(methodInfo.Name, methodInfo.HotRVA, methodInfo.HotLength);
29+
}
30+
if (methodInfo.ColdRVA != 0 && methodInfo.ColdLength != 0)
31+
{
32+
perfMapWriter.WriteLine(methodInfo.Name, methodInfo.ColdRVA, methodInfo.ColdLength);
33+
}
34+
}
35+
}
36+
}
37+
38+
private void WriteLine(string methodName, uint rva, uint length)
39+
{
40+
_writer.WriteLine($@"{rva:X8} {length:X2} {methodName}");
41+
}
42+
}
43+
}

0 commit comments

Comments
 (0)