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

JIT: Add some convenience classes for node count JIT metrics, and automatic dumping from compShutdown #92112

Merged
merged 4 commits into from
Sep 22, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
4 changes: 4 additions & 0 deletions src/coreclr/jit/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1746,6 +1746,10 @@ void Compiler::compShutdown()
#endif // DEBUG
fprintf(fout, " 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(fout);
#endif
}

/*****************************************************************************
Expand Down
47 changes: 47 additions & 0 deletions src/coreclr/jit/compiler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,53 @@ 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;
};

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;
unsigned m_counts[HISTOGRAM_MAX_SIZE_COUNT];
};

class NodeCounts : public Dumpable
{
public:
NodeCounts() : m_counts()
{
}

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

private:
unsigned m_counts[GT_COUNT];
};

class DumpOnShutdown
{
public:
DumpOnShutdown(const char* name, Dumpable* histogram);
static void DumpAll(FILE* output);
};

#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
85 changes: 85 additions & 0 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 @@ -999,6 +1000,90 @@ void Histogram::record(unsigned size)
m_counts[i]++;
}

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 = 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);
m_counts[oper]++;
Copy link
Member

Choose a reason for hiding this comment

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

Should this do an interlocked add?

Copy link
Member

Choose a reason for hiding this comment

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

Maybe that would depend on whether this class is instantiated as global, or as a member of Compiler?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, for good measure it should be interlocked add. NodeCounts is meant to be used as a static field (like Histogram) so you can collect stats for multiple compilations, so it can be racing with other threads, although I expect we mainly use it through SPMI where it won't due to the way parallelization works there.

Looks like Histogram should also be changed to use an interlocked add.

}

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;
break;
}
}
Copy link
Member

Choose a reason for hiding this comment

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

Maybe add an assert that the DumpOnShutdownEntry table isn't all full?

Copy link
Member Author

Choose a reason for hiding this comment

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

Will do.

}

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

if (entry.Dumpable != nullptr)
{
entry.Dumpable->dump(fout);
fprintf(fout, "\n");
}
}
}

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

/*****************************************************************************
Expand Down