Skip to content

Commit

Permalink
Add -repeatCount in superpmi.exe to repeat method compilation (#94503)
Browse files Browse the repository at this point in the history
Passing `-repeatCount N` for some integer `N > 0` will compile
each function `N` times. This is true for each function in the
MCH file, by default, or each one specified by a `-c` argument
or .mcl file.

This can be used to help investigate the JIT throughput for compilation
of a particular function or set of functions.

This is based on #93417.
  • Loading branch information
BruceForstall authored Nov 8, 2023
1 parent ac56247 commit 44bdec3
Show file tree
Hide file tree
Showing 6 changed files with 381 additions and 269 deletions.
59 changes: 50 additions & 9 deletions src/coreclr/tools/superpmi/superpmi-shared/methodcontextreader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -406,18 +406,59 @@ bool MethodContextReader::isValid()
return this->fileHandle != INVALID_HANDLE_VALUE && this->mutex != INVALID_HANDLE_VALUE;
}

double MethodContextReader::PercentComplete()
// Return a measure of "progress" through the method contexts, as follows:
// 1. With a given set of indices, this is the current index array position.
// 2. With a TOC, this is the current method context number.
// 3. Otherwise, it is the current byte offset in the method context file.
// Only useful when compared with `TotalWork()`.
double MethodContextReader::Progress()
{
if (this->hasIndex() && this->hasTOC())
if (this->hasIndex())
{
// Best estimate I can come up with...
return 100.0 * (double)this->curIndexPos / (double)this->IndexCount;
return (double)this->curIndexPos;
}
this->AcquireLock();
__int64 pos = 0;
SetFilePointerEx(this->fileHandle, *(PLARGE_INTEGER)&pos, (PLARGE_INTEGER)&pos, FILE_CURRENT);
this->ReleaseLock();
return 100.0 * (double)pos / (double)this->fileSize;
else if (this->hasTOC())
{
return (double)this->curMCIndex;
}
else
{
this->AcquireLock();
__int64 pos = 0;
SetFilePointerEx(this->fileHandle, *(PLARGE_INTEGER)&pos, (PLARGE_INTEGER)&pos, FILE_CURRENT);
this->ReleaseLock();
return (double)pos;
}
}

// Return a measure of the total amount of work to be done, as follows:
// 1. With a given set of indices, this is the total number of indices to return.
// 2. With a TOC, this is the number of method contexts in the TOC.
// 3. Otherwise, it is the size in bytes of the method context file.
// Only useful when compared with `Progress()`.
double MethodContextReader::TotalWork()
{
if (this->hasIndex())
{
return (double)this->IndexCount;
}
else if (this->hasTOC())
{
return (double)this->tocFile.GetTocCount();
}
else
{
return (double)this->fileSize;
}
}

// Compute a percentage completion value using the previously defined
// Progress() and TotalWork() functions.
// Note that this is not useful to the user as a total percentage complete number
// in the case of small number of methods and a large compile repeat count.
double MethodContextReader::PercentComplete()
{
return 100.0 * Progress() / TotalWork();
}

// Binary search to get this method number from the index
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,9 @@ class MethodContextReader
MethodContextBuffer GetNextMethodContext();
// No C++ exceptions, so the constructor has to always succeed...
bool isValid();

double Progress();
double TotalWork();
double PercentComplete();

// Returns the index of the last MethodContext read by GetNextMethodContext
Expand Down
38 changes: 38 additions & 0 deletions src/coreclr/tools/superpmi/superpmi/commandline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,10 @@ void CommandLine::DumpHelp(const char* program)
printf(" -skipCleanup\n");
printf(" Skip deletion of temporary files created by child SuperPMI processes with -parallel.\n");
printf("\n");
printf(" -repeatCount <repetition count>\n");
printf(" Number of times compilation should repeat for each method context. Usually used when\n");
printf(" trying to measure JIT throughput for a specific set of methods. Default=1.\n");
printf("\n");
printf(" -target <target>\n");
printf(" Used by the assembly differences calculator. This specifies the target\n");
printf(" architecture for cross-compilation. Currently allowed <target> values: x64, x86, arm, arm64\n");
Expand Down Expand Up @@ -526,6 +530,40 @@ bool CommandLine::Parse(int argc, char* argv[], /* OUT */ Options* o)
{
o->skipCleanup = true;
}
else if ((_stricmp(&argv[i][1], "repeatCount") == 0))
{
if (++i >= argc)
{
DumpHelp(argv[0]);
return false;
}

bool isValidRepeatCount = true;
size_t nextlen = strlen(argv[i]);
for (size_t j = 0; j < nextlen; j++)
{
if (!isdigit(argv[i][j]))
{
isValidRepeatCount = false;
break;
}
}
if (isValidRepeatCount)
{
o->repeatCount = atoi(argv[i]);
if (o->repeatCount < 1)
{
isValidRepeatCount = false;
}
}

if (!isValidRepeatCount)
{
LogError("Invalid repeat count specified. Repeat count must be between 1 and INT_MAX.");
DumpHelp(argv[0]);
return false;
}
}
else if ((_strnicmp(&argv[i][1], "stride", argLen) == 0))
{
// "-stride" is an internal switch used by -parallel. Usage is:
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/tools/superpmi/superpmi/commandline.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class CommandLine
int workerCount = -1; // Number of workers to use for /parallel mode. -1 (or 1) means don't use parallel mode.
int indexCount = -1; // If indexCount is -1 and hash points to nullptr it means compile all.
int failureLimit = -1; // Number of failures after which bail out the replay/asmdiffs.
int repeatCount = 1; // Number of times given methods should be compiled.
int* indexes = nullptr;
char* hash = nullptr;
char* methodStatsTypes = nullptr;
Expand Down
18 changes: 11 additions & 7 deletions src/coreclr/tools/superpmi/superpmi/parallelsuperpmi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,14 @@ char* ConstructChildProcessArgs(const CommandLine::Options& o)
bytesWritten += sprintf_s(spmiArgs + bytesWritten, MAX_CMDLINE_SIZE - bytesWritten, " %s %s", arg, s); \
}

// Only pass through an integer argument if it is not the same as the default (which must be specified here).
// (This is a proxy for "did the command-line parser actually parse something for this argument".)
#define ADDARG_INT(i, arg, defaultValue) \
if (i != defaultValue) \
{ \
bytesWritten += sprintf_s(spmiArgs + bytesWritten, MAX_CMDLINE_SIZE - bytesWritten, " %s %d", arg, i); \
}

// We don't pass through:
//
// -parallel
Expand All @@ -438,7 +446,6 @@ char* ConstructChildProcessArgs(const CommandLine::Options& o)
// -diffMetricsSummary
// -failingMCList
// -diffMCList
// -failureLimit
//
// Everything else we need to reconstruct and pass through.
//
Expand All @@ -457,6 +464,8 @@ char* ConstructChildProcessArgs(const CommandLine::Options& o)
ADDARG_STRING(o.hash, "-matchHash");
ADDARG_STRING(o.targetArchitecture, "-target");
ADDARG_STRING(o.compileList, "-compile");
ADDARG_INT(o.failureLimit, "-failureLimit", -1);
ADDARG_INT(o.repeatCount, "-repeatCount", 1);

addJitOptionArgument(o.forceJitOptions, bytesWritten, spmiArgs, "jitoption force");
addJitOptionArgument(o.forceJit2Options, bytesWritten, spmiArgs, "jit2option force");
Expand All @@ -471,6 +480,7 @@ char* ConstructChildProcessArgs(const CommandLine::Options& o)
#undef ADDSTRING
#undef ADDARG_BOOL
#undef ADDARG_STRING
#undef ADDARG_INT

return spmiArgs;
}
Expand Down Expand Up @@ -584,12 +594,6 @@ int doParallelSuperPMI(CommandLine::Options& o)
wd.detailsPath);
}

if (o.failureLimit > 0)
{
bytesWritten += sprintf_s(cmdLine + bytesWritten, MAX_CMDLINE_SIZE - bytesWritten, " -failureLimit %d",
o.failureLimit);
}

bytesWritten += sprintf_s(cmdLine + bytesWritten, MAX_CMDLINE_SIZE - bytesWritten, " -v ewmin %s", spmiArgs);

SECURITY_ATTRIBUTES sa;
Expand Down
Loading

0 comments on commit 44bdec3

Please sign in to comment.