Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial PDB / PerfMap support in Crossgen2 + System.Private.CoreLib switchover to use Crossgen2 #47019

Merged
merged 9 commits into from
Jan 16, 2021
31 changes: 13 additions & 18 deletions src/coreclr/crossgen-corelib.proj
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
AfterTargets="Build">
<PropertyGroup>
<!-- Default for using Crossgen2 when not set externally -->
<UseCrossgen2 Condition="'$(UseCrossgen2)' == ''">false</UseCrossgen2>
<UseCrossgen2 Condition="'$(UseCrossgen2)' == ''">true</UseCrossgen2>

<OSPlatformConfig>$(TargetOS).$(TargetArchitecture).$(Configuration)</OSPlatformConfig>
<RootBinDir>$([MSBuild]::NormalizeDirectory('$(RepoRoot)', 'artifacts'))</RootBinDir>
Expand Down Expand Up @@ -65,27 +65,22 @@
<CrossGenDllCmd>$(CrossGenDllCmd) $(CoreLibInputPath)</CrossGenDllCmd>
</PropertyGroup>

<PropertyGroup Condition="$(BuildPdb)">
<CrossGenDllCmd>$(CrossGenDllCmd) --pdb --pdb-path:$([MSBuild]::NormalizePath('$(BinDir)', 'PDB'))</CrossGenDllCmd>
</PropertyGroup>

<PropertyGroup Condition="$(BuildPerfMap)">
<CrossGenDllCmd>$(CrossGenDllCmd) --perfmap --perfmap-path:$(BinDir)</CrossGenDllCmd>
</PropertyGroup>

<PropertyGroup Condition="'$(UseCrossgen2)' != 'true'">
<VsSetupCmd>call $([MSBuild]::NormalizePath('$(RepoRoot)', 'src', 'coreclr', 'setup_vs_tools.cmd')) &amp;&amp;</VsSetupCmd>

<CrossGenDllCmd>$(CrossGen1Cmd) /out "$(CoreLibOutputPath)"</CrossGenDllCmd>
<CrossGenDllCmd>$(CrossGenDllCmd) "$(CoreLibInputPath)"</CrossGenDllCmd>
</PropertyGroup>

<!-- For now we're using Crossgen1 for generating the perf map as Crossgen2 doesn't yet implement it: -->
<!-- https://github.com/dotnet/runtime/issues/44123 -->
<PropertyGroup Condition="$(BuildPerfMap)">
<CrossGenPerfMapCmd>$(CrossGen1Cmd) /CreatePerfMap "$(BinDir)"</CrossGenPerfMapCmd>
<CrossGenPerfMapCmd>$(CrossGenPerfMapCmd) "$(CoreLibOutputPath)"</CrossGenPerfMapCmd>
</PropertyGroup>

<PropertyGroup Condition="$(BuildPdb)">
<CrossGenPdbCmd>$(DotNetCli) $([MSBuild]::NormalizePath('$(BinDir)', 'r2rdump', 'r2rdump.dll'))</CrossGenPdbCmd>
<CrossGenPdbCmd>$(CrossGenPdbCmd) --create-pdb</CrossGenPdbCmd>
<CrossGenPdbCmd>$(CrossGenPdbCmd) --pdb-path:$([MSBuild]::NormalizePath('$(BinDir)', 'PDB'))</CrossGenPdbCmd>
<CrossGenPdbCmd>$(CrossGenPdbCmd) --in:$(CoreLibOutputPath)</CrossGenPdbCmd>
</PropertyGroup>

<PropertyGroup Condition="$(BuildPdb) and '$(UseCrossgen2)' != 'true'">
<VsSetupCmd>call $([MSBuild]::NormalizePath('$(RepoRoot)', 'src', 'coreclr', 'setup_vs_tools.cmd')) &amp;&amp;</VsSetupCmd>

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

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

<Exec Condition="$(BuildPdb)" Command="$(CrossGenPdbCmd)" />
<Exec Condition="$(BuildPdb) and '$(CrossGenPdbCmd)' != ''" Command="$(CrossGenPdbCmd)" />

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

<Exec Condition="$(BuildPerfMap)" Command="$(CrossGenPerfMapCmd)" />
<Exec Condition="$(BuildPerfMap) and '$(CrossGenPerfMapCmd)' != ''" Command="$(CrossGenPerfMapCmd)" />

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

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<AssemblyName>ILCompiler.Diagnostics</AssemblyName>
<OutputType>Library</OutputType>
<IsDotNetFrameworkProductAssembly>true</IsDotNetFrameworkProductAssembly>
<TargetFramework>$(NetCoreAppToolCurrent)</TargetFramework>
<DefineConstants>READYTORUN;$(DefineConstants)</DefineConstants>
<Platforms>x64;x86;arm;arm64</Platforms>
<PlatformTarget>AnyCPU</PlatformTarget>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>

<!-- We're binplacing these into an existing publish layout so that F5 build in VS updates
the same bits tests expect to see in artifacts/crossgen2. That way we never need to wonder which
binaries are up to date and which are stale. -->
<GenerateDependencyFile>false</GenerateDependencyFile>
<Configurations>Debug;Release;Checked</Configurations>
</PropertyGroup>

</Project>
16 changes: 16 additions & 0 deletions src/coreclr/tools/aot/ILCompiler.Diagnostics/MethodInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace ILCompiler.Diagnostics
{
public struct MethodInfo
{
public string AssemblyName;
public uint MethodToken;
public uint HotRVA;
public uint HotLength;
public string Name;
public uint ColdRVA;
public uint ColdLength;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

using Microsoft.DiaSymReader;

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

struct MethodInfo
{
public string AssemblyName;
public uint MethodToken;
public uint HotRVA;
public string Name;
public uint ColdRVA;
}

interface IModuleData
{
IEnumerable<MethodInfo> Methods { get; }
}

public enum SymChecksumType : byte
{
None = 0, // indicates no checksum is available
Expand Down Expand Up @@ -85,7 +71,7 @@ public bool Equals(SymDocument other)
}
}

class PdbWriter
public class PdbWriter
{
string _pdbPath;
PDBExtraData _pdbExtraData;
Expand Down Expand Up @@ -204,26 +190,33 @@ private void WritePDBDataHelper(string dllPath, IEnumerable<MethodInfo> methods)
throw new NotImplementedException();
}

string dllNameWithoutExtension = Path.GetFileNameWithoutExtension(dllPath);
_pdbFilePath = Path.Combine(_pdbPath, dllNameWithoutExtension + ".pdb");

string originalDllPath = dllPath;

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

_ngenWriter = CreateNGenWriter(dllPath, _pdbPath + "\\");
// Delete any preexisting PDB file upfront otherwise CreateNGenWriter silently opens it
File.Delete(_pdbFilePath);

_ngenWriter = CreateNGenWriter(dllPath, _pdbFilePath);

{
// PDB file is now created. Get its path and initialize _pdbFilePath so the PDB file
// can be deleted if we don't make it successfully to the end
// PDB file is now created. Get its path and update _pdbFilePath so the PDB file
// can be deleted if we don't make it successfully to the end.
StringBuilder pdbFilePathBuilder = new StringBuilder();
pdbFilePathBuilder.Capacity = 1024;
_ngenWriter.QueryPDBNameExW(pdbFilePathBuilder, new IntPtr(pdbFilePathBuilder.Capacity));
Expand Down
43 changes: 43 additions & 0 deletions src/coreclr/tools/aot/ILCompiler.Diagnostics/PerfMapWriter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;
using System.IO;

namespace ILCompiler.Diagnostics
{
public class PerfMapWriter
{
private TextWriter _writer;

private PerfMapWriter(TextWriter writer)
{
_writer = writer;
}

public static void Write(string perfMapFileName, IEnumerable<MethodInfo> methods)
{
using (TextWriter writer = new StreamWriter(perfMapFileName))
{
PerfMapWriter perfMapWriter = new PerfMapWriter(writer);
foreach (MethodInfo methodInfo in methods)
{
if (methodInfo.HotRVA != 0 && methodInfo.HotLength != 0)
{
perfMapWriter.WriteLine(methodInfo.Name, methodInfo.HotRVA, methodInfo.HotLength);
}
if (methodInfo.ColdRVA != 0 && methodInfo.ColdLength != 0)
{
perfMapWriter.WriteLine(methodInfo.Name, methodInfo.ColdRVA, methodInfo.ColdLength);
}
}
}
}

private void WriteLine(string methodName, uint rva, uint length)
{
_writer.WriteLine($@"{rva:X8} {length:X2} {methodName}");
}
}
}
Loading