-
Notifications
You must be signed in to change notification settings - Fork 4.9k
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 a unified mechanism to track metadata/metrics about the compilation #98653
Conversation
Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch Issue DetailsAdds a JIT-EE API to report metadata back to the EE side about the JIT compilation, and adds support for saving these metrics as part of SPMI runs. Switches a number of adhoc metrics to use this scheme. Fix #52877
|
…ilation Adds a JIT-EE API to report metadata back to the EE side about the JIT compilation, and adds support for saving these metrics as part of SPMI runs. Switches a number of adhoc metrics to use this scheme.
047f268
to
a06d6ed
Compare
bool FileWriter::PrintQuotedCsvField(const char* value) | ||
{ | ||
size_t numQuotes = 0; | ||
for (const char* p = value; *p != '\0'; p++) | ||
{ | ||
if (*p == '"') | ||
{ | ||
numQuotes++; | ||
} | ||
} | ||
|
||
if (numQuotes == 0) | ||
{ | ||
return Printf("\"%s\"", value); | ||
} | ||
else | ||
{ | ||
size_t len = 2 + strlen(value) + numQuotes; | ||
char* buffer = new char[len]; | ||
|
||
size_t index = 0; | ||
buffer[index++] = '"'; | ||
for (const char* p = value; *p != '\0'; p++) | ||
{ | ||
if (*p == '"') | ||
{ | ||
buffer[index++] = '"'; | ||
} | ||
buffer[index++] = *p; | ||
} | ||
|
||
buffer[index++] = '"'; | ||
assert(index == len); | ||
|
||
bool result = Print(buffer, len); | ||
delete[] buffer; | ||
return result; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oddly there's a function with full name
System.Xml.Xsl.CompiledQuery.Query:<xsl:template match="Class">(System.Xml.Xsl.Runtime.XmlQueryRuntime,System.Xml.XPath.XPathNavigator,double,double,System.Collections.Generic.IList`1[System.Xml.XPath.XPathNavigator])
in libraries_tests.run, so I had to add this support.
@@ -95,7 +95,7 @@ DLLEXPORT int __cdecl _vsnprintf_s ( | |||
retvalue = vsnprintf(string, sizeInBytes, format, ap); | |||
string[sizeInBytes - 1] = '\0'; | |||
/* we allow truncation if count == _TRUNCATE */ | |||
if (retvalue > (int)sizeInBytes && count == _TRUNCATE) | |||
if (retvalue >= (int)sizeInBytes && count == _TRUNCATE) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will submit this fix separately... it should have a unit test added as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cc @dotnet/jit-contrib PTAL @BruceForstall @AndyAyersMS Here is an example for how the new SPMI report looks. I added the "PerfScore in Diffs" column to the main result tables and a "PerfScore Overall (FullOpts)" column in the "Details" tables. The former one specifies the geomean computed over the relative perfscore in every context with diffs; the latter one is the geomean computed over the relative perfscore for all contexts. In other words, the one shown in the main table can be interpreted as "when my optimization kicks in, how much does it affect perf score". The one in the details is more of a "what is the overall impact". |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Some questions/suggestions.
One additional question: should the metadata info list / schema be statically known (defined in a header file), or dynamic? (clients don't know all the metadata names/types, except maybe by convention, beforehand)
JITMETADATAMETRIC(LoopsAligned, int, 0) | ||
JITMETADATAMETRIC(VarsInSsa, int, 0) | ||
JITMETADATAMETRIC(HoistedExpressions, int, 0) | ||
JITMETADATAMETRIC(RedundantBranchesEliminated, int, JIT_METADATA_HIGHER_IS_BETTER) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are the flags used anywhere? Where is JIT_METADATA_HIGHER_IS_BETTER
defined? It seems odd to include this file in superpmi source code but not have this defined there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They aren't yet, but my plan was to use this to automatically colorize the metrics in the report (once I add that support). Indeed I haven't defined the enum anywhere yet (and it'll probably only end up being define in superpmi and not the JIT).
JITMETADATAINFO(MethodFullName, const char*, 0) | ||
JITMETADATAINFO(TieringName, const char*, 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the difference between JITMETADATAINFO
and JITMETADATAMETRIC
? (Document above).
Also, the answers to MethodFullName and TieringName are hard coded in SPMI playback. Should that be noted somewhere?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added this comment above:
// List of metadata that the JIT can report. There are two categories:
//
// - JITMETADATAINFO: General info that can be of any type and that cannot be
// aggregated in straightforward ways. These properties are not handled
// automatically; the JIT must explicitly report them using
// JitMetadata::report, and the SPMI side needs to manually handle (or ignore)
// them in ICorJitInfo::reportMetadata.
//
// - JITMETADATAMETRIC: Metrics which are numeric types (currently int, double
// and int64_t types supported). Their reporting is handled automatically and
// they will be propagated all the way into SPMI replay/diff results.
src/coreclr/jit/jitmetadata.cpp
Outdated
// | ||
void JitMetadata::report(Compiler* comp, JitMetadataName name, const void* data) | ||
{ | ||
comp->info.compCompHnd->reportMetadata(getName(name), data); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should the report
functions do nothing if RunningSuperPmiReplay()
is false? (I guess the VM does nothing anyway)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I figured that we should just let it be up to the EE. If the EE wants to do something with the information then that's up to them. (Also, we don't check for SPMI in release JITs)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, Bruce has already covered anything I'd have commented on.
I would like to update JitMetrics to use a variant of this, but there are some vector-valued things there. Hmm.
I really want the SPMI side to be able to know what metrics to expect beforehand, just because it simplifies things in the csv handling and also allows e.g. superpmi.py to query metadata about the metrics separately, like the "higher is better" info. There may also be other kinds of metadata about the metrics in the future (for example, some metrics make sense to aggregate as sums/averages, while some other metrics may make more sense to aggregate as min/max). I'd like to be able to have one place to define all of this and automatically have it propagate all the way into superpmi.py -- and I was trying to make jitmetadatalist.h that place. Initially I was going to add a new method to the host interface to be able to get the information about the metrics dynamically. For example, then the JIT side would be the only place we used jitmetadatalist.h, to report this information back. It would probably be slightly more flexible than the current approach, which has some downsides. For example, in the current approach if you change the type of a metric then running superpmi.exe with an old JIT will make it misinterpret the metric data as the new type when the old JIT is reports the old type. However, it seemed much easier to just use jitmetadatalist.h from SPMI always, and I would expect the problematic changes to jitmetadatalist.h to be rare (and if we need to make them we always have the hammer of updating the JIT-EE GUID).
I added a |
Adds a JIT-EE API to report metadata back to the EE side about the JIT compilation, and adds support for saving these metrics as part of SPMI runs. Switches a number of adhoc metrics to use this scheme, and also adds a few new ones.
The metadata is currently only reported with checked JITs.
Also adds support for fast perfscore diffs, and adds perfscore into the reports generated by
superpmi.py asmdiffs
.Fix #52877
As future work we should include the metrics as part of the generated diffs report. I think we can do that automatically with relatively little effort. We also may want some variant of
superpmi.py replay
which just collects the metrics into a report.The system also reports back the method full name and the tiering name as metadata. We can use this in the future to improve the analysis (in particular, grouping repeated diffs in methods of the same full name + tiering name).
For Andy's use case we may consider reporting the metrics back to the EE even in release builds (maybe only under
JitMetrics
or something else that SPMI could set).