Skip to content

Commit

Permalink
JIT: Add some convenience classes for node count JIT metrics, and add…
Browse files Browse the repository at this point in the history
… automatic dumping from compShutdown (#92112)

- Add a NodeCounts class that can be used to easily record the count of
  node types seen
- Add a DumpOnShutdown class that can be used to easily register either
  a Histogram class or NodeCounts class to be dumped as part of
  Compiler::compShutdown
  • Loading branch information
jakobbotsch authored Sep 22, 2023
1 parent df24c25 commit e51acb5
Show file tree
Hide file tree
Showing 4 changed files with 180 additions and 25 deletions.
4 changes: 4 additions & 0 deletions src/coreclr/jit/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1744,6 +1744,10 @@ void Compiler::compShutdown()
#endif // DEBUG
jitprintf(" NYI: %u\n", fatal_NYI);
#endif // MEASURE_FATAL

#if CALL_ARG_STATS || COUNT_BASIC_BLOCKS || COUNT_LOOPS || EMITTER_STATS || MEASURE_NODE_SIZE || MEASURE_MEM_ALLOC
DumpOnShutdown::DumpAll();
#endif
}

/*****************************************************************************
Expand Down
86 changes: 86 additions & 0 deletions src/coreclr/jit/compiler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,92 @@ inline bool Compiler::jitIsBetweenInclusive(unsigned value, unsigned start, unsi
return start <= value && value <= end;
}

#define HISTOGRAM_MAX_SIZE_COUNT 64

#if CALL_ARG_STATS || COUNT_BASIC_BLOCKS || COUNT_LOOPS || EMITTER_STATS || MEASURE_NODE_SIZE || MEASURE_MEM_ALLOC

class Dumpable
{
public:
virtual void dump(FILE* output) = 0;
};

// Helper class to record and display a histogram of different values.
// Usage like:
// static unsigned s_buckets[] = { 1, 2, 5, 10, 0 }; // Must have terminating 0
// static Histogram s_histogram(s_buckets);
// ...
// s_histogram.record(someValue);
//
// The histogram can later be dumped with the dump function, or automatically
// be dumped on shutdown of the JIT library using the DumpOnShutdown helper
// class (see below). It will display how many recorded values fell into each
// of the buckets (<= 1, <= 2, <= 5, <= 10, > 10).
class Histogram : public Dumpable
{
public:
Histogram(const unsigned* const sizeTable);

void dump(FILE* output);
void record(unsigned size);

private:
unsigned m_sizeCount;
const unsigned* const m_sizeTable;
LONG m_counts[HISTOGRAM_MAX_SIZE_COUNT];
};

// Helper class to record and display counts of node types. Use like:
// static NodeCounts s_nodeCounts;
// ...
// s_nodeCounts.record(someNode->gtOper);
//
// The node counts can later be dumped with the dump function, or automatically
// be dumped on shutdown of the JIT library using the DumpOnShutdown helper
// class (see below). It will display output such as:
// LCL_VAR : 62221
// CNS_INT : 42139
// COMMA : 623
// CAST : 460
// ADD : 397
// RSH : 72
// NEG : 5
// UDIV : 1
//
class NodeCounts : public Dumpable
{
public:
NodeCounts() : m_counts()
{
}

void dump(FILE* output);
void record(genTreeOps oper);

private:
LONG m_counts[GT_COUNT];
};

// Helper class to register a Histogram or NodeCounts instance to automatically
// be output to jitstdout when the JIT library is shutdown. Example usage:
//
// static NodeCounts s_nodeCounts;
// static DumpOnShutdown d("Bounds check index node types", &s_nodeCounts);
// ...
// s_nodeCounts.record(...);
//
// Useful for quick ad-hoc investigations without having to manually go add
// code into Compiler::compShutdown and expose the Histogram/NodeCount to that
// function.
class DumpOnShutdown
{
public:
DumpOnShutdown(const char* name, Dumpable* histogram);
static void DumpAll();
};

#endif // CALL_ARG_STATS || COUNT_BASIC_BLOCKS || COUNT_LOOPS || EMITTER_STATS || MEASURE_NODE_SIZE

/******************************************************************************************
* Return the EH descriptor for the given region index.
*/
Expand Down
22 changes: 0 additions & 22 deletions src/coreclr/jit/jit.h
Original file line number Diff line number Diff line change
Expand Up @@ -710,28 +710,6 @@ inline size_t unsigned_abs(__int64 x)

/*****************************************************************************/

#define HISTOGRAM_MAX_SIZE_COUNT 64

#if CALL_ARG_STATS || COUNT_BASIC_BLOCKS || COUNT_LOOPS || EMITTER_STATS || MEASURE_NODE_SIZE || MEASURE_MEM_ALLOC

class Histogram
{
public:
Histogram(const unsigned* const sizeTable);

void dump(FILE* output);
void record(unsigned size);

private:
unsigned m_sizeCount;
const unsigned* const m_sizeTable;
unsigned m_counts[HISTOGRAM_MAX_SIZE_COUNT];
};

#endif // CALL_ARG_STATS || COUNT_BASIC_BLOCKS || COUNT_LOOPS || EMITTER_STATS || MEASURE_NODE_SIZE

/*****************************************************************************/

#include "error.h"

/*****************************************************************************/
Expand Down
93 changes: 90 additions & 3 deletions src/coreclr/jit/utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
#endif

#include "opcode.h"
#include "jitstd/algorithm.h"

/*****************************************************************************/

Expand Down Expand Up @@ -979,9 +980,9 @@ void Histogram::dump(FILE* output)
fprintf(output, "%7u", m_sizeTable[i]);
}

c += m_counts[i];
c += static_cast<unsigned>(m_counts[i]);

fprintf(output, " ===> %7u count (%3u%% of total)\n", m_counts[i], (int)(100.0 * c / t));
fprintf(output, " ===> %7u count (%3u%% of total)\n", static_cast<unsigned>(m_counts[i]), (int)(100.0 * c / t));
}
}

Expand All @@ -996,7 +997,93 @@ void Histogram::record(unsigned size)
}
}

m_counts[i]++;
InterlockedAdd(&m_counts[i], 1);
}

void NodeCounts::dump(FILE* output)
{
struct Entry
{
genTreeOps oper;
unsigned count;
};

Entry sorted[GT_COUNT];
for (int i = 0; i < GT_COUNT; i++)
{
sorted[i].oper = static_cast<genTreeOps>(i);
sorted[i].count = static_cast<unsigned>(m_counts[i]);
}

jitstd::sort(sorted, sorted + ArrLen(sorted), [](const Entry& lhs, const Entry& rhs) {
if (lhs.count > rhs.count)
{
return true;
}

if (lhs.count < rhs.count)
{
return false;
}

return static_cast<unsigned>(lhs.oper) < static_cast<unsigned>(rhs.oper);
});

for (const Entry& entry : sorted)
{
if (entry.count == 0)
{
break;
}

fprintf(output, "%-20s : %7u\n", GenTree::OpName(entry.oper), entry.count);
}
}

void NodeCounts::record(genTreeOps oper)
{
assert(oper < GT_COUNT);
InterlockedAdd(&m_counts[oper], 1);
}

struct DumpOnShutdownEntry
{
const char* Name;
Dumpable* Dumpable;
};

static DumpOnShutdownEntry s_dumpOnShutdown[16];

DumpOnShutdown::DumpOnShutdown(const char* name, Dumpable* dumpable)
{
for (DumpOnShutdownEntry& entry : s_dumpOnShutdown)
{
if ((entry.Name == nullptr) && (entry.Dumpable == nullptr))
{
entry.Name = name;
entry.Dumpable = dumpable;
return;
}
}

assert(!"No space left in table");
}

void DumpOnShutdown::DumpAll()
{
for (const DumpOnShutdownEntry& entry : s_dumpOnShutdown)
{
if (entry.Name != nullptr)
{
jitprintf("%s\n", entry.Name);
}

if (entry.Dumpable != nullptr)
{
entry.Dumpable->dump(jitstdout());
jitprintf("\n");
}
}
}

#endif // CALL_ARG_STATS || COUNT_BASIC_BLOCKS || COUNT_LOOPS || EMITTER_STATS || MEASURE_NODE_SIZE
Expand Down

0 comments on commit e51acb5

Please sign in to comment.