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

Add support for dumping and using precise debug info #61735

Merged
merged 6 commits into from
Nov 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion src/coreclr/jit/codegen.h
Original file line number Diff line number Diff line change
Expand Up @@ -556,11 +556,16 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
void genIPmappingListDisp();
#endif // DEBUG

IPmappingDsc* genCreateIPMapping(IPmappingDscKind kind, const DebugInfo& di, bool isLabel);
void genIPmappingAdd(IPmappingDscKind kind, const DebugInfo& di, bool isLabel);
void genIPmappingAddToFront(IPmappingDscKind kind, const DebugInfo& di, bool isLabel);
void genIPmappingGen();

#ifdef DEBUG
void genDumpPreciseDebugInfo();
void genDumpPreciseDebugInfoInlineTree(FILE* file, InlineContext* context, bool* first);
void genAddPreciseIPMappingHere(const DebugInfo& di);
#endif

void genEnsureCodeEmitted(const DebugInfo& di);

//-------------------------------------------------------------------------
Expand Down
97 changes: 97 additions & 0 deletions src/coreclr/jit/codegencommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,9 @@ CodeGen::CodeGen(Compiler* theCompiler) : CodeGenInterface(theCompiler)
compiler->genIPmappingLast = nullptr;
compiler->genCallSite2DebugInfoMap = nullptr;

compiler->genPreciseIPMappingsHead = nullptr;
compiler->genPreciseIPMappingsTail = nullptr;

/* Assume that we not fully interruptible */

SetInterruptible(false);
Expand Down Expand Up @@ -2446,6 +2449,8 @@ void CodeGen::genEmitUnwindDebugGCandEH()

genIPmappingGen();

INDEBUG(genDumpPreciseDebugInfo());

/* Finalize the Local Var info in terms of generated code */

genSetScopeInfo();
Expand Down Expand Up @@ -10801,6 +10806,98 @@ void CodeGen::genIPmappingGen()
compiler->eeSetLIdone();
}

#ifdef DEBUG
void CodeGen::genDumpPreciseDebugInfoInlineTree(FILE* file, InlineContext* context, bool* first)
{
if (context->GetSibling() != nullptr)
{
genDumpPreciseDebugInfoInlineTree(file, context->GetSibling(), first);
}

if (context->IsSuccess())
{
if (!*first)
{
fprintf(file, ",");
}

*first = false;

fprintf(file, "{\"Ordinal\":%u,", context->GetOrdinal());
fprintf(file, "\"MethodID\":%lld,", (INT64)context->GetCallee());
const char* className;
const char* methodName = compiler->eeGetMethodName(context->GetCallee(), &className);
fprintf(file, "\"MethodName\":\"%s\",", methodName);
fprintf(file, "\"Inlinees\":[");
if (context->GetChild() != nullptr)
{
bool childFirst = true;
genDumpPreciseDebugInfoInlineTree(file, context->GetChild(), &childFirst);
}
fprintf(file, "]}");
}
}

void CodeGen::genDumpPreciseDebugInfo()
{
if (JitConfig.JitDumpPreciseDebugInfoFile() == nullptr)
return;

static CritSecObject s_critSect;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally we don't want the jit to take locks but using one during bring-up like this is ok.

CritSecHolder holder(s_critSect);

FILE* file = _wfopen(JitConfig.JitDumpPreciseDebugInfoFile(), W("a"));
if (file == nullptr)
return;

// MethodID in ETW events are the method handles.
fprintf(file, "{\"MethodID\":%lld,", (INT64)compiler->info.compMethodHnd);
// Print inline tree.
fprintf(file, "\"InlineTree\":");

bool first = true;
genDumpPreciseDebugInfoInlineTree(file, compiler->compInlineContext, &first);
fprintf(file, ",\"Mappings\":[");
first = true;
for (PreciseIPMapping* mapping = compiler->genPreciseIPMappingsHead; mapping != nullptr; mapping = mapping->next)
{
if (!first)
{
fprintf(file, ",");
}

first = false;

fprintf(file, "{\"NativeOffset\":%u,\"InlineContext\":%u,\"ILOffset\":%u}",
mapping->nativeLoc.CodeOffset(GetEmitter()), mapping->debugInfo.GetInlineContext()->GetOrdinal(),
mapping->debugInfo.GetLocation().GetOffset());
}

fprintf(file, "]}\n");

fclose(file);
}

void CodeGen::genAddPreciseIPMappingHere(const DebugInfo& di)
{
PreciseIPMapping* mapping = new (compiler, CMK_DebugInfo) PreciseIPMapping;
mapping->next = nullptr;
mapping->nativeLoc.CaptureLocation(GetEmitter());
mapping->debugInfo = di;

if (compiler->genPreciseIPMappingsTail != nullptr)
{
compiler->genPreciseIPMappingsTail->next = mapping;
}
else
{
compiler->genPreciseIPMappingsHead = mapping;
}

compiler->genPreciseIPMappingsTail = mapping;
}
#endif

/*============================================================================
*
* These are empty stubs to help the late dis-assembler to compile
Expand Down
6 changes: 6 additions & 0 deletions src/coreclr/jit/codegenlinear.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,13 @@ void CodeGen::genCodeForBBlist()
genIPmappingAdd(IPmappingDscKind::Normal, currentDI, firstMapping);
firstMapping = false;
}

#ifdef DEBUG
if ((JitConfig.JitDumpPreciseDebugInfoFile() != nullptr) && ilOffset->gtStmtDI.IsValid())
{
genAddPreciseIPMappingHere(ilOffset->gtStmtDI);
}

assert(ilOffset->gtStmtLastILoffs <= compiler->info.compILCodeSize ||
ilOffset->gtStmtLastILoffs == BAD_IL_OFFSET);

Expand Down
10 changes: 10 additions & 0 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -2535,6 +2535,13 @@ struct IPmappingDsc
bool ipmdIsLabel; // Can this code be a branch label?
};

struct PreciseIPMapping
{
PreciseIPMapping* next;
emitLocation nativeLoc;
DebugInfo debugInfo;
};

/*
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Expand Down Expand Up @@ -8305,6 +8312,9 @@ class Compiler
IPmappingDsc* genIPmappingList;
IPmappingDsc* genIPmappingLast;

PreciseIPMapping* genPreciseIPMappingsHead;
PreciseIPMapping* genPreciseIPMappingsTail;

// Managed RetVal - A side hash table meant to record the mapping from a
// GT_CALL node to its debug info. This info is used to emit sequence points
// that can be used by debugger to determine the native offset at which the
Expand Down
13 changes: 12 additions & 1 deletion src/coreclr/jit/inline.h
Original file line number Diff line number Diff line change
Expand Up @@ -726,6 +726,18 @@ class InlineContext
return m_Parent;
}

// Get the sibling context.
InlineContext* GetSibling() const
{
return m_Sibling;
}

// Get the first child context.
InlineContext* GetChild() const
{
return m_Child;
}

// Get the code pointer for this context.
const BYTE* GetCode() const
{
Expand Down Expand Up @@ -806,7 +818,6 @@ class InlineContext
private:
InlineContext(InlineStrategy* strategy);

private:
InlineStrategy* m_InlineStrategy; // overall strategy
InlineContext* m_Parent; // logical caller (parent)
InlineContext* m_Child; // first child
Expand Down
2 changes: 2 additions & 0 deletions src/coreclr/jit/jitconfigvalues.h
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,8 @@ CONFIG_INTEGER(JitDumpFgConstrained, W("JitDumpFgConstrained"), 1) // 0 == don't
CONFIG_INTEGER(JitDumpFgBlockID, W("JitDumpFgBlockID"), 0) // 0 == display block with bbNum; 1 == display with both
// bbNum and bbID

CONFIG_STRING(JitDumpPreciseDebugInfoFile, W("JitDumpPreciseDebugInfoFile"))

CONFIG_STRING(JitLateDisasmTo, W("JITLateDisasmTo"))
CONFIG_STRING(JitRange, W("JitRange"))
CONFIG_STRING(JitStressModeNames, W("JitStressModeNames")) // Internal Jit stress mode: stress using the given set of
Expand Down
41 changes: 0 additions & 41 deletions src/coreclr/tools/Common/TypeSystem/IL/FlowGraph.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,47 +88,6 @@ public IEnumerable<BasicBlock> LookupRange(int ilOffsetStart, int ilOffsetEnd)
yield return BasicBlocks[i];
}

internal string Dump(Func<BasicBlock, string> getNodeAnnot, Func<(BasicBlock, BasicBlock), string> getEdgeAnnot)
{
var sb = new StringBuilder();
sb.AppendLine("digraph G {");
sb.AppendLine(" forcelabels=true;");
sb.AppendLine();
Dictionary<long, int> bbToIndex = new Dictionary<long, int>();
for (int i = 0; i < BasicBlocks.Count; i++)
bbToIndex.Add(BasicBlocks[i].Start, i);

foreach (BasicBlock bb in BasicBlocks)
{
string label = $"[{bb.Start:x}..{bb.Start + bb.Size:x})\\n{getNodeAnnot(bb)}";
sb.AppendLine($" BB{bbToIndex[bb.Start]} [label=\"{label}\"];");
}

sb.AppendLine();

foreach (BasicBlock bb in BasicBlocks)
{
foreach (BasicBlock tar in bb.Targets)
{
string label = getEdgeAnnot((bb, tar));
string postfix = string.IsNullOrEmpty(label) ? "" : $" [label=\"{label}\"]";
sb.AppendLine($" BB{bbToIndex[bb.Start]} -> BB{bbToIndex[tar.Start]}{postfix};");
}
}

// Write ranks with BFS.
List<BasicBlock> curRank = new List<BasicBlock> { BasicBlocks.Single(bb => bb.Start == 0) };
HashSet<BasicBlock> seen = new HashSet<BasicBlock>(curRank);
while (curRank.Count > 0)
{
sb.AppendLine($" {{rank = same; {string.Concat(curRank.Select(bb => $"BB{bbToIndex[bb.Start]}; "))}}}");
curRank = curRank.SelectMany(bb => bb.Targets).Where(seen.Add).ToList();
}

sb.AppendLine("}");
return sb.ToString();
}

public static FlowGraph Create(MethodIL il)
{
HashSet<int> bbStarts = GetBasicBlockStarts(il);
Expand Down
22 changes: 16 additions & 6 deletions src/coreclr/tools/dotnet-pgo/CommandLineOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ internal class CommandLineOptions

public FileInfo TraceFile;
public FileInfo OutputFileName;
public FileInfo PreciseDebugInfoFile;
public int? Pid;
public string ProcessName;
public PgoFileType? FileType;
Expand All @@ -29,8 +30,7 @@ internal class CommandLineOptions
public bool ValidateOutputFile;
public bool GenerateCallGraph;
public bool Spgo;
public bool SpgoIncludeBlockCounts;
public bool SpgoIncludeEdgeCounts;
public bool IncludeFullGraphs;
public int SpgoMinSamples = 50;
public bool VerboseWarnings;
public jittraceoptions JitTraceOptions;
Expand All @@ -45,6 +45,8 @@ internal class CommandLineOptions
public bool DumpMibc = false;
public FileInfo InputFileToDump;
public List<FileInfo> CompareMibc;
public DirectoryInfo DumpWorstOverlapGraphsTo;
public int DumpWorstOverlapGraphs = -1;
public bool InheritTimestamp;

public string[] HelpArgs = Array.Empty<string>();
Expand Down Expand Up @@ -196,13 +198,15 @@ void HelpOption()
CommonOptions();
CompressedOption();

string preciseDebugInfoFile = null;
syntax.DefineOption(name: "precise-debug-info-file", ref preciseDebugInfoFile, "Name of file of newline separated JSON objects containing precise debug info");
if (preciseDebugInfoFile != null)
PreciseDebugInfoFile = new FileInfo(preciseDebugInfoFile);

syntax.DefineOption(name: "spgo", value: ref Spgo, help: "Base profile on samples in the input. Uses last branch records if available and otherwise raw IP samples.", requireValue: false);
syntax.DefineOption(name: "spgo-with-block-counts", value: ref SpgoIncludeBlockCounts, help: "Include block counts in the written .mibc file. If neither this nor spgo-with-edge-counts are specified, then defaults to true.", requireValue: false);
syntax.DefineOption(name: "spgo-with-edge-counts", value: ref SpgoIncludeEdgeCounts, help: "Include edge counts in the written .mibc file.", requireValue: false);
syntax.DefineOption(name: "spgo-min-samples", value: ref SpgoMinSamples, help: $"The minimum number of total samples a function must have before generating profile data for it with SPGO. Default: {SpgoMinSamples}", requireValue: false);

if (!SpgoIncludeBlockCounts && !SpgoIncludeEdgeCounts)
SpgoIncludeBlockCounts = true;
syntax.DefineOption(name: "include-full-graphs", value: ref IncludeFullGraphs, help: "Include all blocks and edges in the written .mibc file, regardless of profile counts", requireValue: false);

HelpOption();
}
Expand Down Expand Up @@ -305,6 +309,12 @@ void HelpOption()
CompareMibc = DefineFileOptionList(name: "i|input", help: "The input .mibc files to be compared. Specify as --input file1.mibc --input file2.mibc");
if (CompareMibc.Count != 2)
Help = true;

syntax.DefineOption(name: "dump-worst-overlap-graphs", value: ref DumpWorstOverlapGraphs, help: "Number of graphs to dump to .dot format in dump-worst-overlap-graphs-to directory");
string dumpWorstOverlapGraphsTo = null;
syntax.DefineOption(name: "dump-worst-overlap-graphs-to", value: ref dumpWorstOverlapGraphsTo, help: "Number of graphs to dump to .dot format in dump-worst-overlap-graphs-to directory");
if (dumpWorstOverlapGraphsTo != null)
DumpWorstOverlapGraphsTo = new DirectoryInfo(dumpWorstOverlapGraphsTo);
}

if (syntax.ActiveCommand == null)
Expand Down
Loading