diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 86680d6e20c91e..111c6488df073f 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -2916,6 +2916,13 @@ class ICorStaticInfo uint32_t numMappings // [IN] Number of rich mappings ) = 0; + // Report back some metadata about the compilation to the EE -- for + // example, metrics about the compilation. + virtual void reportMetadata( + const char* key, + const void* value, + size_t length) = 0; + /*-------------------------- Misc ---------------------------------------*/ // Used to allocate memory that needs to handed to the EE. diff --git a/src/coreclr/inc/icorjitinfoimpl_generated.h b/src/coreclr/inc/icorjitinfoimpl_generated.h index 8dd993f5b47829..46c0c817bad07d 100644 --- a/src/coreclr/inc/icorjitinfoimpl_generated.h +++ b/src/coreclr/inc/icorjitinfoimpl_generated.h @@ -438,6 +438,11 @@ void reportRichMappings( ICorDebugInfo::RichOffsetMapping* mappings, uint32_t numMappings) override; +void reportMetadata( + const char* key, + const void* value, + size_t length) override; + void* allocateArray( size_t cBytes) override; diff --git a/src/coreclr/inc/jiteeversionguid.h b/src/coreclr/inc/jiteeversionguid.h index 6355fc20dd0fd5..646f1b169330a2 100644 --- a/src/coreclr/inc/jiteeversionguid.h +++ b/src/coreclr/inc/jiteeversionguid.h @@ -43,11 +43,11 @@ typedef const GUID *LPCGUID; #define GUID_DEFINED #endif // !GUID_DEFINED -constexpr GUID JITEEVersionIdentifier = { /* 0fb71692-0ee6-4914-88a8-6446e45f23e8 */ - 0x0fb71692, - 0x0ee6, - 0x4914, - {0x88, 0xa8, 0x64, 0x46, 0xe4, 0x5f, 0x23, 0xe8} +constexpr GUID JITEEVersionIdentifier = { /* 1f30d12b-38f1-4f1e-a08a-831def882aa4 */ + 0x1f30d12b, + 0x38f1, + 0x4f1e, + {0xa0, 0x8a, 0x83, 0x1d, 0xef, 0x88, 0x2a, 0xa4} }; ////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/coreclr/jit/CMakeLists.txt b/src/coreclr/jit/CMakeLists.txt index aa660321075890..ae08a27e4c00aa 100644 --- a/src/coreclr/jit/CMakeLists.txt +++ b/src/coreclr/jit/CMakeLists.txt @@ -137,6 +137,7 @@ set( JIT_SOURCES jitconfig.cpp jiteh.cpp jithashtable.cpp + jitmetadata.cpp lclmorph.cpp lclvars.cpp likelyclass.cpp @@ -334,6 +335,8 @@ set( JIT_HEADERS jitexpandarray.h jitgcinfo.h jithashtable.h + jitmetadata.h + jitmetadatalist.h jitpch.h jitstd.h lir.h diff --git a/src/coreclr/jit/ICorJitInfo_names_generated.h b/src/coreclr/jit/ICorJitInfo_names_generated.h index 5fe1f716d474b8..3908d4bcdc4be2 100644 --- a/src/coreclr/jit/ICorJitInfo_names_generated.h +++ b/src/coreclr/jit/ICorJitInfo_names_generated.h @@ -108,6 +108,7 @@ DEF_CLR_API(setBoundaries) DEF_CLR_API(getVars) DEF_CLR_API(setVars) DEF_CLR_API(reportRichMappings) +DEF_CLR_API(reportMetadata) DEF_CLR_API(allocateArray) DEF_CLR_API(freeArray) DEF_CLR_API(getArgNext) diff --git a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp index cae9b5d7b39e59..1205512fabff0f 100644 --- a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp +++ b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp @@ -1028,6 +1028,16 @@ void WrapICorJitInfo::reportRichMappings( API_LEAVE(reportRichMappings); } +void WrapICorJitInfo::reportMetadata( + const char* key, + const void* value, + size_t length) +{ + API_ENTER(reportMetadata); + wrapHnd->reportMetadata(key, value, length); + API_LEAVE(reportMetadata); +} + void* WrapICorJitInfo::allocateArray( size_t cBytes) { diff --git a/src/coreclr/jit/codegencommon.cpp b/src/coreclr/jit/codegencommon.cpp index 825837fe45ef50..29b911f3160e5b 100644 --- a/src/coreclr/jit/codegencommon.cpp +++ b/src/coreclr/jit/codegencommon.cpp @@ -315,10 +315,8 @@ void CodeGen::genPrepForCompiler() } } VarSetOps::AssignNoCopy(compiler, genLastLiveSet, VarSetOps::MakeEmpty(compiler)); - genLastLiveMask = RBM_NONE; -#ifdef DEBUG - compiler->fgBBcountAtCodegen = compiler->fgBBcount; -#endif + genLastLiveMask = RBM_NONE; + compiler->Metrics.BasicBlocksAtCodegen = compiler->fgBBcount; } //------------------------------------------------------------------------ @@ -2042,7 +2040,7 @@ void CodeGen::genEmitMachineCode() printf("; Total bytes of code %d, prolog size %d, PerfScore %.2f, instruction count %d, allocated bytes for " "code %d", - codeSize, prologSize, compiler->info.compPerfScore, instrCount, + codeSize, prologSize, compiler->Metrics.PerfScore, instrCount, GetEmitter()->emitTotalHotCodeSize + GetEmitter()->emitTotalColdCodeSize); if (dspMetrics) diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index b0518aca33f796..c1417c974a71bc 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -1793,9 +1793,13 @@ void Compiler::compInit(ArenaAllocator* pAlloc, info.compMethodName = eeGetMethodName(methodHnd); info.compClassName = eeGetClassName(info.compClassHnd); info.compFullName = eeGetMethodFullName(methodHnd); - info.compPerfScore = 0.0; info.compMethodSuperPMIIndex = g_jitHost->getIntConfigValue(W("SuperPMIMethodContextNumber"), -1); + + if (!compIsForInlining()) + { + JitMetadata::report(this, JitMetadata::MethodFullName, info.compFullName, strlen(info.compFullName)); + } #endif // defined(DEBUG) || defined(LATE_DISASM) || DUMP_FLOWGRAPHS #if defined(DEBUG) @@ -1863,9 +1867,7 @@ void Compiler::compInit(ArenaAllocator* pAlloc, // // Initialize all the per-method statistics gathering data structures. // - - optLoopsCloned = 0; - + CLANG_FORMAT_COMMENT_ANCHOR; #if LOOP_HOIST_STATS m_loopsConsidered = 0; m_curLoopHasHoistedExpression = false; @@ -1965,6 +1967,8 @@ void Compiler::compInit(ArenaAllocator* pAlloc, compUsesThrowHelper = false; m_preferredInitCctor = CORINFO_HELP_UNDEF; + + new (&Metrics, jitstd::placement_t()) JitMetrics(); } /***************************************************************************** @@ -5212,7 +5216,7 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl #ifdef DEBUG if (JitConfig.JitMetrics() > 0) { - sprintf_s(metricPart, 128, ", perfScore=%.2f, numCse=%u", info.compPerfScore, optCSEcount); + sprintf_s(metricPart, 128, ", perfScore=%.2f, numCse=%u", Metrics.PerfScore, optCSEcount); } #endif @@ -5416,7 +5420,7 @@ PhaseStatus Compiler::placeLoopAlignInstructions() { block->SetFlags(BBF_LOOP_ALIGN); BitVecOps::AddElemD(&loopTraits, alignedLoops, loop->GetIndex()); - INDEBUG(loopAlignCandidates++); + Metrics.LoopAlignmentCandidates++; BasicBlock* prev = block->Prev(); // shouldAlignLoop should have guaranteed these properties. @@ -5465,7 +5469,7 @@ PhaseStatus Compiler::placeLoopAlignInstructions() } } - JITDUMP("Found %u candidates for loop alignment\n", loopAlignCandidates); + JITDUMP("Found %d candidates for loop alignment\n", Metrics.LoopAlignmentCandidates); return madeChanges ? PhaseStatus::MODIFIED_EVERYTHING : PhaseStatus::MODIFIED_NOTHING; } @@ -6438,6 +6442,8 @@ void Compiler::compCompileFinish() compArenaAllocator->finishMemStats(); memAllocHist.record((unsigned)((compArenaAllocator->getTotalBytesAllocated() + 1023) / 1024)); memUsedHist.record((unsigned)((compArenaAllocator->getTotalBytesUsed() + 1023) / 1024)); + + Metrics.BytesAllocated = (int64_t)compArenaAllocator->getTotalBytesUsed(); } #ifdef DEBUG @@ -6621,7 +6627,7 @@ void Compiler::compCompileFinish() printf(" %3d |", optCallCount); printf(" %3d |", optIndirectCallCount); - printf(" %3d |", fgBBcountAtCodegen); + printf(" %3d |", Metrics.BasicBlocksAtCodegen); printf(" %3d |", lvaCount); if (opts.MinOpts()) @@ -6634,13 +6640,13 @@ void Compiler::compCompileFinish() printf(" %3d |", optCSEcount); } - if (info.compPerfScore < 9999.995) + if (Metrics.PerfScore < 9999.995) { - printf(" %7.2f |", info.compPerfScore); + printf(" %7.2f |", Metrics.PerfScore); } else { - printf(" %7.0f |", info.compPerfScore); + printf(" %7.0f |", Metrics.PerfScore); } printf(" %4d |", info.compMethodInfo->ILCodeSize); @@ -6651,9 +6657,13 @@ void Compiler::compCompileFinish() printf(""); // in our logic this causes a flush } + JITDUMP("Final metrics:\n"); + Metrics.report(this); + DBEXEC(verbose, Metrics.dump()); + if (verbose) { - printf("****** DONE compiling %s\n", info.compFullName); + printf("\n****** DONE compiling %s\n", info.compFullName); printf(""); // in our logic this causes a flush } @@ -7146,6 +7156,13 @@ int Compiler::compCompileHelper(CORINFO_MODULE_HANDLE classPtr, opts.disAsm = false; } +#ifdef DEBUG + { + const char* tieringName = compGetTieringName(true); + JitMetadata::report(this, JitMetadata::TieringName, tieringName, strlen(tieringName)); + } +#endif + #if COUNT_BASIC_BLOCKS bbCntTable.record(fgBBcount); @@ -9074,12 +9091,12 @@ void JitTimer::PrintCsvMethodStats(Compiler* comp) fprintf(s_csvFile, "%u,", comp->info.compILCodeSize); fprintf(s_csvFile, "%u,", comp->fgBBcount); fprintf(s_csvFile, "%u,", comp->opts.MinOpts()); - fprintf(s_csvFile, "%u,", comp->optNumNaturalLoopsFound); - fprintf(s_csvFile, "%u,", comp->optLoopsCloned); + fprintf(s_csvFile, "%d,", comp->Metrics.LoopsFoundDuringOpts); + fprintf(s_csvFile, "%d,", comp->Metrics.LoopsCloned); #if FEATURE_LOOP_ALIGN #ifdef DEBUG - fprintf(s_csvFile, "%u,", comp->loopAlignCandidates); - fprintf(s_csvFile, "%u,", comp->loopsAligned); + fprintf(s_csvFile, "%d,", comp->Metrics.LoopAlignmentCandidates); + fprintf(s_csvFile, "%d,", comp->Metrics.LoopsAligned); #endif // DEBUG #endif // FEATURE_LOOP_ALIGN unsigned __int64 totCycles = 0; diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 10a47eb729fa0b..14108f0b252a68 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -65,6 +65,8 @@ inline var_types genActualType(T value); #include "simd.h" #include "simdashwintrinsic.h" +#include "jitmetadata.h" + /***************************************************************************** * Forward declarations */ @@ -4960,7 +4962,6 @@ class Compiler unsigned fgEdgeCount; // # of control flow edges between the BBs unsigned fgBBcount; // # of BBs in the method (in the linked list that starts with fgFirstBB) #ifdef DEBUG - unsigned fgBBcountAtCodegen; // # of BBs in the method at the start of codegen jitstd::vector* fgBBOrder; // ordered vector of BBs #endif // Used as a quick check for whether loop alignment should look for natural loops. @@ -4989,7 +4990,6 @@ class Compiler // 2. All loop exits where bbIsHandlerBeg(exit) is false have only loop predecessors. // bool optLoopsCanonical; - unsigned optNumNaturalLoopsFound; // Number of natural loops found in the loop finding phase bool fgBBVarSetsInited; @@ -6833,16 +6833,11 @@ class Compiler public: bool fgHasLoops; -#ifdef DEBUG - unsigned loopAlignCandidates; // number of candidates identified by placeLoopAlignInstructions - unsigned loopsAligned; // number of loops actually aligned -#endif // DEBUG protected: unsigned optCallCount; // number of calls made in the method unsigned optIndirectCallCount; // number of virtual, interface and indirect calls made in the method unsigned optNativeCallCount; // number of Pinvoke/Native calls made in the method - unsigned optLoopsCloned; // number of loops cloned in the current method. #ifdef DEBUG void optCheckPreds(); @@ -10147,7 +10142,6 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX const char* compMethodName; const char* compClassName; const char* compFullName; - double compPerfScore; int compMethodSuperPMIIndex; // useful when debugging under SuperPMI #endif // defined(DEBUG) || defined(LATE_DISASM) || DUMP_FLOWGRAPHS @@ -10608,6 +10602,8 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX static EnregisterStats s_enregisterStats; #endif // TRACK_ENREG_STATS + JitMetrics Metrics; + bool compIsForInlining() const; bool compDonotInline(); diff --git a/src/coreclr/jit/emit.cpp b/src/coreclr/jit/emit.cpp index d3ac84e7919a1d..ecbfe659be1034 100644 --- a/src/coreclr/jit/emit.cpp +++ b/src/coreclr/jit/emit.cpp @@ -4393,7 +4393,7 @@ size_t emitter::emitIssue1Instr(insGroup* ig, instrDesc* id, BYTE** dp) float insExeCost = insEvaluateExecutionCost(id); // All compPerfScore calculations must be performed using doubles double insPerfScore = (double)(ig->igWeight / (double)BB_UNITY_WEIGHT) * insExeCost; - emitComp->info.compPerfScore += insPerfScore; + emitComp->Metrics.PerfScore += insPerfScore; ig->igPerfScore += insPerfScore; #endif // defined(DEBUG) || defined(LATE_DISASM) diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp index 9e80da3bfaf9ab..d429f0d261f7a2 100644 --- a/src/coreclr/jit/emitxarch.cpp +++ b/src/coreclr/jit/emitxarch.cpp @@ -12475,10 +12475,10 @@ BYTE* emitter::emitOutputAlign(insGroup* ig, instrDesc* id, BYTE* dst) assert(paddingToAdd == paddingNeeded); } } - - emitComp->loopsAligned++; #endif + emitComp->Metrics.LoopsAligned++; + #ifdef DEBUG // Under STRESS_EMITTER, if this is the 'align' before the 'jmp' instruction, // then add "int3" instruction. Since int3 takes 1 byte, we would only add diff --git a/src/coreclr/jit/fgbasic.cpp b/src/coreclr/jit/fgbasic.cpp index 3800e2ffe89d94..d30e58ce0f03c7 100644 --- a/src/coreclr/jit/fgbasic.cpp +++ b/src/coreclr/jit/fgbasic.cpp @@ -49,8 +49,7 @@ void Compiler::fgInit() fgBBcount = 0; #ifdef DEBUG - fgBBcountAtCodegen = 0; - fgBBOrder = nullptr; + fgBBOrder = nullptr; #endif // DEBUG fgMightHaveNaturalLoops = false; diff --git a/src/coreclr/jit/jitmetadata.cpp b/src/coreclr/jit/jitmetadata.cpp new file mode 100644 index 00000000000000..905cdb7317d8bb --- /dev/null +++ b/src/coreclr/jit/jitmetadata.cpp @@ -0,0 +1,100 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#include "jitpch.h" +#include "jitmetadata.h" + +#ifdef DEBUG + +//------------------------------------------------------------------------ +// JitMetadata::report: Report metadata back to the EE. +// +// Parameters: +// comp - Compiler instance +// key - Key name of metadata +// data - Pointer to the value to report back +// +void JitMetadata::report(Compiler* comp, const char* key, const void* data, size_t length) +{ + comp->info.compCompHnd->reportMetadata(key, data, length); +} + +//------------------------------------------------------------------------ +// reportValue: Report a specific value back to the EE. +// +// Parameters: +// comp - Compiler instance +// key - The key +// value - Value to report back +// +template +static void reportValue(Compiler* comp, const char* key, T value) +{ + JitMetadata::report(comp, key, &value, sizeof(value)); +} + +//------------------------------------------------------------------------ +// JitMetrics::report: Report all metrics and their values back to the EE. +// +// Parameters: +// comp - Compiler instance +// +void JitMetrics::report(Compiler* comp) +{ +#define JITMETADATAINFO(name, type, flags) +#define JITMETADATAMETRIC(name, type, flags) reportValue(comp, #name, name); +#include "jitmetadatalist.h" +} + +//------------------------------------------------------------------------ +// printMetric: Print a double metric value to jitstdout. +// +// Parameters: +// value - The value +// +static void printMetric(double value) +{ + printf("%f", value); +} + +//------------------------------------------------------------------------ +// printMetric: Print an int metric value to jitstdout. +// +// Parameters: +// value - The value +// +static void printMetric(int value) +{ + printf("%d", value); +} + +//------------------------------------------------------------------------ +// printMetric: Print an int64_t metric value to jitstdout. +// +// Parameters: +// value - The value +// +static void printMetric(int64_t value) +{ + printf("%lld", value); +} + +//------------------------------------------------------------------------ +// JitMetrics::dump: Print the values of all metrics to jitstdout. +// +void JitMetrics::dump() +{ + int nameMaxWidth = 0; +#define JITMETADATAINFO(name, type, flags) +#define JITMETADATAMETRIC(name, type, flags) nameMaxWidth = max(nameMaxWidth, (int)strlen(#name)); +#include "jitmetadatalist.h" + +#define JITMETADATAINFO(name, type, flags) +#define JITMETADATAMETRIC(name, type, flags) \ + printf("%-*s: ", nameMaxWidth + 5, #name); \ + printMetric(name); \ + printf("\n"); +#include "jitmetadatalist.h" +} + +#endif diff --git a/src/coreclr/jit/jitmetadata.h b/src/coreclr/jit/jitmetadata.h new file mode 100644 index 00000000000000..3b4b324497cc21 --- /dev/null +++ b/src/coreclr/jit/jitmetadata.h @@ -0,0 +1,26 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#pragma once + +class Compiler; + +class JitMetadata +{ +public: +#define JITMETADATA(name, type, flags) static constexpr const char* name = #name; +#include "jitmetadatalist.h" + + static void report(Compiler* comp, const char* name, const void* data, size_t length); +}; + +class JitMetrics +{ +public: +#define JITMETADATAINFO(name, type, flags) +#define JITMETADATAMETRIC(name, type, flags) type name = 0; +#include "jitmetadatalist.h" + + void report(Compiler* comp); + void dump(); +}; diff --git a/src/coreclr/jit/jitmetadatalist.h b/src/coreclr/jit/jitmetadatalist.h new file mode 100644 index 00000000000000..8b69644d1a8fba --- /dev/null +++ b/src/coreclr/jit/jitmetadatalist.h @@ -0,0 +1,49 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// clang-format off + +#ifdef JITMETADATA +#define JITMETADATAINFO(name, type, flags) JITMETADATA(name, type, flags) +#define JITMETADATAMETRIC(name, type, flags) JITMETADATA(name, type, flags) +#endif + +#if !defined(JITMETADATAINFO) || !defined(JITMETADATAMETRIC) +#error Define JITMETADATAINFO and JITMETADATAMETRIC before including this file. +#endif + +// 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. + +// Name, type flags +JITMETADATAINFO(MethodFullName, const char*, 0) +JITMETADATAINFO(TieringName, const char*, 0) +JITMETADATAMETRIC(PhysicallyPromotedFields, int, 0) +JITMETADATAMETRIC(LoopsFoundDuringOpts, int, 0) +JITMETADATAMETRIC(LoopsCloned, int, 0) +JITMETADATAMETRIC(LoopsUnrolled, int, 0) +JITMETADATAMETRIC(LoopAlignmentCandidates, int, 0) +JITMETADATAMETRIC(LoopsAligned, int, 0) +JITMETADATAMETRIC(VarsInSsa, int, 0) +JITMETADATAMETRIC(HoistedExpressions, int, 0) +JITMETADATAMETRIC(RedundantBranchesEliminated, int, JIT_METADATA_HIGHER_IS_BETTER) +JITMETADATAMETRIC(JumpThreadingsPerformed, int, JIT_METADATA_HIGHER_IS_BETTER) +JITMETADATAMETRIC(CseCount, int, 0) +JITMETADATAMETRIC(BasicBlocksAtCodegen, int, 0) +JITMETADATAMETRIC(PerfScore, double, JIT_METADATA_LOWER_IS_BETTER) +JITMETADATAMETRIC(BytesAllocated, int64_t, JIT_METADATA_LOWER_IS_BETTER) + +#undef JITMETADATA +#undef JITMETADATAINFO +#undef JITMETADATAMETRIC + +// clang-format on diff --git a/src/coreclr/jit/loopcloning.cpp b/src/coreclr/jit/loopcloning.cpp index ca4c2572fa41d9..96cd8bff015939 100644 --- a/src/coreclr/jit/loopcloning.cpp +++ b/src/coreclr/jit/loopcloning.cpp @@ -2955,19 +2955,19 @@ PhaseStatus Compiler::optCloneLoops() #endif #endif - assert(optLoopsCloned == 0); // It should be initialized, but not yet changed. + assert(Metrics.LoopsCloned == 0); // It should be initialized, but not yet changed. for (FlowGraphNaturalLoop* loop : m_loops->InReversePostOrder()) { if (context.GetLoopOptInfo(loop->GetIndex()) != nullptr) { - optLoopsCloned++; + Metrics.LoopsCloned++; context.OptimizeConditions(loop->GetIndex() DEBUGARG(verbose)); context.OptimizeBlockConditions(loop->GetIndex() DEBUGARG(verbose)); optCloneLoop(loop, &context); } } - if (optLoopsCloned > 0) + if (Metrics.LoopsCloned > 0) { fgInvalidateDfsTree(); m_dfsTree = fgComputeDfs(); @@ -2986,7 +2986,7 @@ PhaseStatus Compiler::optCloneLoops() #ifdef DEBUG if (verbose) { - printf("Loops cloned: %d\n", optLoopsCloned); + printf("Loops cloned: %d\n", Metrics.LoopsCloned); printf("Loops statically optimized: %d\n", optStaticallyOptimizedLoops); printf("After loop cloning:\n"); fgDispBasicBlocks(/*dumpTrees*/ true); diff --git a/src/coreclr/jit/lsra.cpp b/src/coreclr/jit/lsra.cpp index 04ca6149c9fc36..9ca1d59ed7a5e2 100644 --- a/src/coreclr/jit/lsra.cpp +++ b/src/coreclr/jit/lsra.cpp @@ -10096,7 +10096,7 @@ void LinearScan::dumpLsraStatsCsv(FILE* file) { fprintf(file, ",%u", sumStats[statIndex]); } - fprintf(file, ",%.2f\n", compiler->info.compPerfScore); + fprintf(file, ",%.2f\n", compiler->Metrics.PerfScore); } // ----------------------------------------------------------- diff --git a/src/coreclr/jit/optcse.cpp b/src/coreclr/jit/optcse.cpp index e4b3c9faeff4fb..8c888db5de7c6d 100644 --- a/src/coreclr/jit/optcse.cpp +++ b/src/coreclr/jit/optcse.cpp @@ -4370,6 +4370,7 @@ void CSE_HeuristicCommon::PerformCSE(CSE_Candidate* successfulCandidate) // Record that we created a new LclVar for use as a CSE temp m_addCSEcount++; m_pCompiler->optCSEcount++; + m_pCompiler->Metrics.CseCount++; // Walk all references to this CSE, adding an assignment // to the CSE temp to all defs and changing all refs to diff --git a/src/coreclr/jit/optimizer.cpp b/src/coreclr/jit/optimizer.cpp index e2f1d335e21277..287aab0160727c 100644 --- a/src/coreclr/jit/optimizer.cpp +++ b/src/coreclr/jit/optimizer.cpp @@ -21,13 +21,7 @@ void Compiler::optInit() { fgHasLoops = false; - optLoopsCanonical = false; - optNumNaturalLoopsFound = 0; - -#ifdef DEBUG - loopAlignCandidates = 0; - loopsAligned = 0; -#endif + optLoopsCanonical = false; /* Keep track of the number of calls and indirect calls made by this method */ optCallCount = 0; @@ -1300,6 +1294,8 @@ PhaseStatus Compiler::optUnrollLoops() { assert(anyIRchange); + Metrics.LoopsUnrolled += unrollCount; + #ifdef DEBUG if (verbose) { @@ -2670,7 +2666,7 @@ PhaseStatus Compiler::optFindLoopsPhase() optFindAndScaleGeneralLoopBlocks(); } - optNumNaturalLoopsFound = (unsigned)m_loops->NumLoops(); + Metrics.LoopsFoundDuringOpts = (int)m_loops->NumLoops(); return PhaseStatus::MODIFIED_EVERYTHING; } @@ -5147,6 +5143,8 @@ void Compiler::optHoistCandidate(GenTree* tree, // Record the hoisted expression in hoistCtxt hoistCtxt->GetHoistedInCurLoop(this)->Set(tree->gtVNPair.GetLiberal(), true); + + Metrics.HoistedExpressions++; } bool Compiler::optVNIsLoopInvariant(ValueNum vn, FlowGraphNaturalLoop* loop, VNSet* loopVnInvariantCache) diff --git a/src/coreclr/jit/promotion.cpp b/src/coreclr/jit/promotion.cpp index f66748633a69e3..2f7b1e0b31372c 100644 --- a/src/coreclr/jit/promotion.cpp +++ b/src/coreclr/jit/promotion.cpp @@ -1205,6 +1205,8 @@ class LocalsUseVisitor : public GenTreeVisitor } } + m_compiler->Metrics.PhysicallyPromotedFields += totalNumPromotions; + if (totalNumPromotions <= 0) { return false; diff --git a/src/coreclr/jit/redundantbranchopts.cpp b/src/coreclr/jit/redundantbranchopts.cpp index 3ea6142de4cd3f..9dd9a2959e76a3 100644 --- a/src/coreclr/jit/redundantbranchopts.cpp +++ b/src/coreclr/jit/redundantbranchopts.cpp @@ -927,6 +927,7 @@ bool Compiler::optRedundantBranch(BasicBlock* const block) JITDUMP("\nRedundant branch opt in " FMT_BB ":\n", block->bbNum); fgMorphBlockStmt(block, stmt DEBUGARG(__FUNCTION__)); + Metrics.RedundantBranchesEliminated++; return true; } @@ -1683,6 +1684,7 @@ bool Compiler::optJumpThreadCore(JumpThreadInfo& jti) // We optimized. // + Metrics.JumpThreadingsPerformed++; fgModified = true; return true; } diff --git a/src/coreclr/jit/ssabuilder.cpp b/src/coreclr/jit/ssabuilder.cpp index 2072591bcd5a9a..fb8b33aa313294 100644 --- a/src/coreclr/jit/ssabuilder.cpp +++ b/src/coreclr/jit/ssabuilder.cpp @@ -1181,6 +1181,7 @@ void SsaBuilder::RenameVariables() { JITDUMP("*************** In SsaBuilder::RenameVariables()\n"); + m_pCompiler->Metrics.VarsInSsa = 0; // The first thing we do is treat parameters and must-init variables as if they have a // virtual definition before entry -- they start out at SSA name 1. for (unsigned lclNum = 0; lclNum < m_pCompiler->lvaCount; lclNum++) @@ -1190,6 +1191,8 @@ void SsaBuilder::RenameVariables() continue; } + m_pCompiler->Metrics.VarsInSsa++; + LclVarDsc* varDsc = m_pCompiler->lvaGetDesc(lclNum); assert(varDsc->lvTracked); diff --git a/src/coreclr/scripts/superpmi.py b/src/coreclr/scripts/superpmi.py index baca765929ce4c..29e3801147500a 100644 --- a/src/coreclr/scripts/superpmi.py +++ b/src/coreclr/scripts/superpmi.py @@ -22,6 +22,7 @@ import datetime import locale import logging +import math import os import multiprocessing import platform @@ -1807,10 +1808,10 @@ def compute_pct(base, diff): else: return 0.0 -def format_pct(pct): +def format_pct(pct, num_decimals = 2): plus_if_positive = "+" if pct > 0 else "" - text = "{}{:.2f}%".format(plus_if_positive, pct) + text = "{}{:.{prec}f}%".format(plus_if_positive, pct, prec=num_decimals) if pct != 0: color = "red" if pct > 0 else "green" return html_color(color, text) @@ -1865,8 +1866,9 @@ def aggregate_diff_metrics(details): """ base_minopts = {"Successful compiles": 0, "Missing compiles": 0, "Failing compiles": 0, - "Contexts with diffs": 0, "Diffed code bytes": 0, "Diff executed instructions": 0, - "Diffed contexts": 0} + "Contexts with diffs": 0, "Diffed code bytes": 0, + "Diffed PerfScore" : 0.0, "Relative PerfScore Geomean": 0.0, + "Diff executed instructions": 0, "Diffed contexts": 0} base_fullopts = base_minopts.copy() diff_minopts = base_minopts.copy() @@ -1910,6 +1912,16 @@ def aggregate_diff_metrics(details): base_dict["Diff executed instructions"] += base_insts diff_dict["Diff executed instructions"] += diff_insts + base_perfscore = float(row["Base PerfScore"]) + diff_perfscore = float(row["Diff PerfScore"]) + base_dict["Diffed PerfScore"] += base_perfscore + diff_dict["Diffed PerfScore"] += diff_perfscore + + if base_perfscore > 0: + log_relative_perfscore = math.log(diff_perfscore / base_perfscore) + base_dict["Relative PerfScore Geomean"] += log_relative_perfscore + diff_dict["Relative PerfScore Geomean"] += log_relative_perfscore + base_dict["Diffed contexts"] += 1 diff_dict["Diffed contexts"] += 1 @@ -1925,6 +1937,18 @@ def aggregate_diff_metrics(details): for k in diff_overall.keys(): diff_overall[k] += diff_fullopts[k] + for d in [base_overall, base_minopts, base_fullopts, diff_overall, diff_minopts, diff_fullopts]: + sum_of_logs = d["Relative PerfScore Geomean"] + if d["Diffed contexts"] > 0: + d["Relative PerfScore Geomean"] = math.exp(sum_of_logs / d["Diffed contexts"]) + else: + d["Relative PerfScore Geomean"] = 1 + + if d["Contexts with diffs"] > 0: + d["Relative PerfScore Geomean (Diffs)"] = math.exp(sum_of_logs / d["Contexts with diffs"]) + else: + d["Relative PerfScore Geomean (Diffs)"] = 1 + return ({"Overall": base_overall, "MinOpts": base_minopts, "FullOpts": base_fullopts}, {"Overall": diff_overall, "MinOpts": diff_minopts, "FullOpts": diff_fullopts}) @@ -2266,6 +2290,21 @@ def create_exception(): logging.info("Total bytes of diff: {}".format(diff_bytes)) delta_bytes = diff_bytes - base_bytes logging.info("Total bytes of delta: {} ({:.2%} of base)".format(delta_bytes, delta_bytes / base_bytes)) + logging.info("") + + base_perfscore = base_metrics["Overall"]["Diffed PerfScore"] + diff_perfscore = diff_metrics["Overall"]["Diffed PerfScore"] + logging.info("Total PerfScore of base: {}".format(base_perfscore)) + logging.info("Total PerfScore of diff: {}".format(diff_perfscore)) + delta_perfscore = diff_perfscore - base_perfscore + logging.info("Total PerfScore of delta: {} ({:.2%} of base)".format(delta_perfscore, delta_perfscore / base_perfscore)) + logging.info("") + + relative_perfscore_geomean = diff_metrics["Overall"]["Relative PerfScore Geomean"] + logging.info("Relative PerfScore Geomean: {:.4%}".format(relative_perfscore_geomean - 1)) + relative_perfscore_geomean_diffs = diff_metrics["Overall"]["Relative PerfScore Geomean (Diffs)"] + logging.info("Relative PerfScore Geomean (Diffs): {:.4%}".format(relative_perfscore_geomean_diffs - 1)) + logging.info("") try: current_text_diff = text_differences.get_nowait() @@ -2290,6 +2329,10 @@ def create_exception(): if self.coreclr_args.metrics: for metric in self.coreclr_args.metrics: command += [ "--metrics", metric ] + + if self.coreclr_args.metrics == ["PerfScore"]: + command += [ "--override-total-base-metric", str(base_perfscore), "--override-total-diff-metric", str(diff_perfscore) ] + elif base_bytes is not None and diff_bytes is not None: command += [ "--override-total-base-metric", str(base_bytes), "--override-total-diff-metric", str(diff_bytes) ] @@ -2493,19 +2536,20 @@ def write_pivot_section(row): sum_diff = sum(diff_metrics[row]["Diffed code bytes"] for (_, _, diff_metrics, _, _, _) in asm_diffs) with DetailsSection(write_fh, "{} ({} bytes)".format(row, format_delta(sum_base, sum_diff))): - write_fh.write("|Collection|Base size (bytes)|Diff size (bytes)|\n") - write_fh.write("|---|--:|--:|\n") + write_fh.write("|Collection|Base size (bytes)|Diff size (bytes)|PerfScore in Diffs\n") + write_fh.write("|---|--:|--:|--:|\n") for (mch_file, base_metrics, diff_metrics, _, _, _) in asm_diffs: # Exclude this particular row? if not has_diffs(diff_metrics[row]): continue - write_fh.write("|{}|{:,d}|{}|\n".format( + write_fh.write("|{}|{:,d}|{}|{}|\n".format( mch_file, base_metrics[row]["Diffed code bytes"], format_delta( base_metrics[row]["Diffed code bytes"], - diff_metrics[row]["Diffed code bytes"]))) + diff_metrics[row]["Diffed code bytes"]), + format_pct(diff_metrics[row]["Relative PerfScore Geomean (Diffs)"] * 100 - 100))) write_top_context_section() write_pivot_section("Overall") @@ -2524,26 +2568,27 @@ def write_pivot_section(row): with DetailsSection(write_fh, "Details"): if any_diffs: write_fh.write("#### Improvements/regressions per collection\n\n") - write_fh.write("|Collection|Contexts with diffs|Improvements|Regressions|Same size|Improvements (bytes)|Regressions (bytes)|\n") - write_fh.write("|---|--:|--:|--:|--:|--:|--:|\n") + write_fh.write("|Collection|Contexts with diffs|Improvements|Regressions|Same size|Improvements (bytes)|Regressions (bytes)|PerfScore Overall (FullOpts)|\n") + write_fh.write("|---|--:|--:|--:|--:|--:|--:|--:|\n") - def write_row(name, diffs): + def write_row(name, diffs, perfscore_geomean): base_diff_sizes = [(int(r["Base size"]), int(r["Diff size"])) for r in diffs] (num_improvements, num_regressions, num_same, byte_improvements, byte_regressions) = calculate_improvements_regressions(base_diff_sizes) - write_fh.write("|{}|{:,d}|{}|{}|{}|{}|{}|\n".format( + write_fh.write("|{}|{:,d}|{}|{}|{}|{}|{}|{}|\n".format( name, len(diffs), html_color("green", "{:,d}".format(num_improvements)), html_color("red", "{:,d}".format(num_regressions)), html_color("blue", "{:,d}".format(num_same)), html_color("green", "-{:,d}".format(byte_improvements)), - html_color("red", "+{:,d}".format(byte_regressions)))) + html_color("red", "+{:,d}".format(byte_regressions)), + "" if perfscore_geomean is None else format_pct(perfscore_geomean, 4))) - for (mch_file, _, _, diffs, _, _) in asm_diffs: - write_row(mch_file, diffs) + for (mch_file, _, diff_metrics, diffs, _, _) in asm_diffs: + write_row(mch_file, diffs, diff_metrics["FullOpts"]["Relative PerfScore Geomean"] * 100 - 100) if len(asm_diffs) > 1: - write_row("", [r for (_, _, _, diffs, _, _) in asm_diffs for r in diffs]) + write_row("", [r for (_, _, _, diffs, _, _) in asm_diffs for r in diffs], None) write_fh.write("\n---\n\n") @@ -2668,7 +2713,7 @@ def pick_contexts_to_disassemble(self, diffs): # If there are non-default metrics then we need to disassemble # everything so that jit-analyze can handle those. - if self.coreclr_args.metrics is not None: + if self.coreclr_args.metrics is not None and self.coreclr_args.metrics != ["PerfScore"]: contexts = diffs examples = [] else: @@ -2686,22 +2731,29 @@ def display_subset(message, subset): smallest_contexts = sorted(diffs, key=lambda r: int(r["Context size"]))[:20] display_subset("Smallest {} contexts with binary differences:", smallest_contexts) - # Order by byte-wise improvement, largest improvements first - by_diff_size = sorted(diffs, key=lambda r: int(r["Diff size"]) - int(r["Base size"])) - # 20 top improvements, byte-wise - top_improvements_bytes = by_diff_size[:20] - # 20 top regressions, byte-wise - top_regressions_bytes = by_diff_size[-20:] + if self.coreclr_args.metrics is None: + base_metric_name = "Base size" + diff_metric_name = "Diff size" + else: + base_metric_name = "Base PerfScore" + diff_metric_name = "Diff PerfScore" + + # Order by improvement, largest improvements first + by_diff = sorted(diffs, key=lambda r: float(r[diff_metric_name]) - float(r[base_metric_name])) + # 20 top improvements + top_improvements = by_diff[:20] + # 20 top regressions + top_regressions = by_diff[-20:] - display_subset("Top {} improvements, byte-wise:", top_improvements_bytes) - display_subset("Top {} regressions, byte-wise:", top_regressions_bytes) + display_subset("Top {} improvements:", top_improvements) + display_subset("Top {} regressions:", top_regressions) # Order by percentage-wise size improvement, largest improvements first def diff_pct(r): - base = int(r["Base size"]) + base = float(r[base_metric_name]) if base == 0: return 0 - diff = int(r["Diff size"]) + diff = float(r[diff_metric_name]) return (diff - base) / base by_diff_size_pct = sorted(diffs, key=diff_pct) @@ -2723,7 +2775,7 @@ def diff_pct(r): example_improvements = by_diff_size_pct_examples[:3] example_regressions = by_diff_size_pct_examples[3:][-3:] - contexts = smallest_contexts + top_improvements_bytes + top_regressions_bytes + top_improvements_pct + top_regressions_pct + smallest_zero_size_contexts + example_improvements + example_regressions + contexts = smallest_contexts + top_improvements + top_regressions + top_improvements_pct + top_regressions_pct + smallest_zero_size_contexts + example_improvements + example_regressions examples = example_improvements + example_regressions final_contexts_indices = list(set(int(r["Context"]) for r in contexts)) diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index 2e72a18def7713..4d291954fe4272 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -3156,6 +3156,12 @@ private void reportRichMappings(InlineTreeNode* inlineTree, uint numInlineTree, Marshal.FreeHGlobal((IntPtr)mappings); } +#pragma warning disable CA1822 // Mark members as static + private void reportMetadata(byte* key, void* value, nuint length) +#pragma warning restore CA1822 // Mark members as static + { + } + #pragma warning disable CA1822 // Mark members as static private void* allocateArray(UIntPtr cBytes) #pragma warning restore CA1822 // Mark members as static diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs index 13844628bb8639..7789862f5074a1 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs @@ -1547,6 +1547,20 @@ private static void _reportRichMappings(IntPtr thisHandle, IntPtr* ppException, } } + [UnmanagedCallersOnly] + private static void _reportMetadata(IntPtr thisHandle, IntPtr* ppException, byte* key, void* value, UIntPtr length) + { + var _this = GetThis(thisHandle); + try + { + _this.reportMetadata(key, value, length); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + [UnmanagedCallersOnly] private static void* _allocateArray(IntPtr thisHandle, IntPtr* ppException, UIntPtr cBytes) { @@ -2551,7 +2565,7 @@ private static uint _getJitFlags(IntPtr thisHandle, IntPtr* ppException, CORJIT_ private static IntPtr GetUnmanagedCallbacks() { - void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 172); + void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 173); callbacks[0] = (delegate* unmanaged)&_isIntrinsic; callbacks[1] = (delegate* unmanaged)&_notifyMethodInfoUsage; @@ -2657,74 +2671,75 @@ private static IntPtr GetUnmanagedCallbacks() callbacks[101] = (delegate* unmanaged)&_getVars; callbacks[102] = (delegate* unmanaged)&_setVars; callbacks[103] = (delegate* unmanaged)&_reportRichMappings; - callbacks[104] = (delegate* unmanaged)&_allocateArray; - callbacks[105] = (delegate* unmanaged)&_freeArray; - callbacks[106] = (delegate* unmanaged)&_getArgNext; - callbacks[107] = (delegate* unmanaged)&_getArgType; - callbacks[108] = (delegate* unmanaged)&_getExactClasses; - callbacks[109] = (delegate* unmanaged)&_getArgClass; - callbacks[110] = (delegate* unmanaged)&_getHFAType; - callbacks[111] = (delegate* unmanaged)&_runWithErrorTrap; - callbacks[112] = (delegate* unmanaged)&_runWithSPMIErrorTrap; - callbacks[113] = (delegate* unmanaged)&_getEEInfo; - callbacks[114] = (delegate* unmanaged)&_getJitTimeLogFilename; - callbacks[115] = (delegate* unmanaged)&_getMethodDefFromMethod; - callbacks[116] = (delegate* unmanaged)&_printMethodName; - callbacks[117] = (delegate* unmanaged)&_getMethodNameFromMetadata; - callbacks[118] = (delegate* unmanaged)&_getMethodHash; - callbacks[119] = (delegate* unmanaged)&_getSystemVAmd64PassStructInRegisterDescriptor; - callbacks[120] = (delegate* unmanaged)&_getLoongArch64PassStructInRegisterFlags; - callbacks[121] = (delegate* unmanaged)&_getRISCV64PassStructInRegisterFlags; - callbacks[122] = (delegate* unmanaged)&_getThreadTLSIndex; - callbacks[123] = (delegate* unmanaged)&_getAddrOfCaptureThreadGlobal; - callbacks[124] = (delegate* unmanaged)&_getHelperFtn; - callbacks[125] = (delegate* unmanaged)&_getFunctionEntryPoint; - callbacks[126] = (delegate* unmanaged)&_getFunctionFixedEntryPoint; - callbacks[127] = (delegate* unmanaged)&_getMethodSync; - callbacks[128] = (delegate* unmanaged)&_getLazyStringLiteralHelper; - callbacks[129] = (delegate* unmanaged)&_embedModuleHandle; - callbacks[130] = (delegate* unmanaged)&_embedClassHandle; - callbacks[131] = (delegate* unmanaged)&_embedMethodHandle; - callbacks[132] = (delegate* unmanaged)&_embedFieldHandle; - callbacks[133] = (delegate* unmanaged)&_embedGenericHandle; - callbacks[134] = (delegate* unmanaged)&_getLocationOfThisType; - callbacks[135] = (delegate* unmanaged)&_getAddressOfPInvokeTarget; - callbacks[136] = (delegate* unmanaged)&_GetCookieForPInvokeCalliSig; - callbacks[137] = (delegate* unmanaged)&_canGetCookieForPInvokeCalliSig; - callbacks[138] = (delegate* unmanaged)&_getJustMyCodeHandle; - callbacks[139] = (delegate* unmanaged)&_GetProfilingHandle; - callbacks[140] = (delegate* unmanaged)&_getCallInfo; - callbacks[141] = (delegate* unmanaged)&_getClassDomainID; - callbacks[142] = (delegate* unmanaged)&_getStaticFieldContent; - callbacks[143] = (delegate* unmanaged)&_getObjectContent; - callbacks[144] = (delegate* unmanaged)&_getStaticFieldCurrentClass; - callbacks[145] = (delegate* unmanaged)&_getVarArgsHandle; - callbacks[146] = (delegate* unmanaged)&_canGetVarArgsHandle; - callbacks[147] = (delegate* unmanaged)&_constructStringLiteral; - callbacks[148] = (delegate* unmanaged)&_emptyStringLiteral; - callbacks[149] = (delegate* unmanaged)&_getFieldThreadLocalStoreID; - callbacks[150] = (delegate* unmanaged)&_GetDelegateCtor; - callbacks[151] = (delegate* unmanaged)&_MethodCompileComplete; - callbacks[152] = (delegate* unmanaged)&_getTailCallHelpers; - callbacks[153] = (delegate* unmanaged)&_convertPInvokeCalliToCall; - callbacks[154] = (delegate* unmanaged)&_notifyInstructionSetUsage; - callbacks[155] = (delegate* unmanaged)&_updateEntryPointForTailCall; - callbacks[156] = (delegate* unmanaged)&_allocMem; - callbacks[157] = (delegate* unmanaged)&_reserveUnwindInfo; - callbacks[158] = (delegate* unmanaged)&_allocUnwindInfo; - callbacks[159] = (delegate* unmanaged)&_allocGCInfo; - callbacks[160] = (delegate* unmanaged)&_setEHcount; - callbacks[161] = (delegate* unmanaged)&_setEHinfo; - callbacks[162] = (delegate* unmanaged)&_logMsg; - callbacks[163] = (delegate* unmanaged)&_doAssert; - callbacks[164] = (delegate* unmanaged)&_reportFatalError; - callbacks[165] = (delegate* unmanaged)&_getPgoInstrumentationResults; - callbacks[166] = (delegate* unmanaged)&_allocPgoInstrumentationBySchema; - callbacks[167] = (delegate* unmanaged)&_recordCallSite; - callbacks[168] = (delegate* unmanaged)&_recordRelocation; - callbacks[169] = (delegate* unmanaged)&_getRelocTypeHint; - callbacks[170] = (delegate* unmanaged)&_getExpectedTargetArchitecture; - callbacks[171] = (delegate* unmanaged)&_getJitFlags; + callbacks[104] = (delegate* unmanaged)&_reportMetadata; + callbacks[105] = (delegate* unmanaged)&_allocateArray; + callbacks[106] = (delegate* unmanaged)&_freeArray; + callbacks[107] = (delegate* unmanaged)&_getArgNext; + callbacks[108] = (delegate* unmanaged)&_getArgType; + callbacks[109] = (delegate* unmanaged)&_getExactClasses; + callbacks[110] = (delegate* unmanaged)&_getArgClass; + callbacks[111] = (delegate* unmanaged)&_getHFAType; + callbacks[112] = (delegate* unmanaged)&_runWithErrorTrap; + callbacks[113] = (delegate* unmanaged)&_runWithSPMIErrorTrap; + callbacks[114] = (delegate* unmanaged)&_getEEInfo; + callbacks[115] = (delegate* unmanaged)&_getJitTimeLogFilename; + callbacks[116] = (delegate* unmanaged)&_getMethodDefFromMethod; + callbacks[117] = (delegate* unmanaged)&_printMethodName; + callbacks[118] = (delegate* unmanaged)&_getMethodNameFromMetadata; + callbacks[119] = (delegate* unmanaged)&_getMethodHash; + callbacks[120] = (delegate* unmanaged)&_getSystemVAmd64PassStructInRegisterDescriptor; + callbacks[121] = (delegate* unmanaged)&_getLoongArch64PassStructInRegisterFlags; + callbacks[122] = (delegate* unmanaged)&_getRISCV64PassStructInRegisterFlags; + callbacks[123] = (delegate* unmanaged)&_getThreadTLSIndex; + callbacks[124] = (delegate* unmanaged)&_getAddrOfCaptureThreadGlobal; + callbacks[125] = (delegate* unmanaged)&_getHelperFtn; + callbacks[126] = (delegate* unmanaged)&_getFunctionEntryPoint; + callbacks[127] = (delegate* unmanaged)&_getFunctionFixedEntryPoint; + callbacks[128] = (delegate* unmanaged)&_getMethodSync; + callbacks[129] = (delegate* unmanaged)&_getLazyStringLiteralHelper; + callbacks[130] = (delegate* unmanaged)&_embedModuleHandle; + callbacks[131] = (delegate* unmanaged)&_embedClassHandle; + callbacks[132] = (delegate* unmanaged)&_embedMethodHandle; + callbacks[133] = (delegate* unmanaged)&_embedFieldHandle; + callbacks[134] = (delegate* unmanaged)&_embedGenericHandle; + callbacks[135] = (delegate* unmanaged)&_getLocationOfThisType; + callbacks[136] = (delegate* unmanaged)&_getAddressOfPInvokeTarget; + callbacks[137] = (delegate* unmanaged)&_GetCookieForPInvokeCalliSig; + callbacks[138] = (delegate* unmanaged)&_canGetCookieForPInvokeCalliSig; + callbacks[139] = (delegate* unmanaged)&_getJustMyCodeHandle; + callbacks[140] = (delegate* unmanaged)&_GetProfilingHandle; + callbacks[141] = (delegate* unmanaged)&_getCallInfo; + callbacks[142] = (delegate* unmanaged)&_getClassDomainID; + callbacks[143] = (delegate* unmanaged)&_getStaticFieldContent; + callbacks[144] = (delegate* unmanaged)&_getObjectContent; + callbacks[145] = (delegate* unmanaged)&_getStaticFieldCurrentClass; + callbacks[146] = (delegate* unmanaged)&_getVarArgsHandle; + callbacks[147] = (delegate* unmanaged)&_canGetVarArgsHandle; + callbacks[148] = (delegate* unmanaged)&_constructStringLiteral; + callbacks[149] = (delegate* unmanaged)&_emptyStringLiteral; + callbacks[150] = (delegate* unmanaged)&_getFieldThreadLocalStoreID; + callbacks[151] = (delegate* unmanaged)&_GetDelegateCtor; + callbacks[152] = (delegate* unmanaged)&_MethodCompileComplete; + callbacks[153] = (delegate* unmanaged)&_getTailCallHelpers; + callbacks[154] = (delegate* unmanaged)&_convertPInvokeCalliToCall; + callbacks[155] = (delegate* unmanaged)&_notifyInstructionSetUsage; + callbacks[156] = (delegate* unmanaged)&_updateEntryPointForTailCall; + callbacks[157] = (delegate* unmanaged)&_allocMem; + callbacks[158] = (delegate* unmanaged)&_reserveUnwindInfo; + callbacks[159] = (delegate* unmanaged)&_allocUnwindInfo; + callbacks[160] = (delegate* unmanaged)&_allocGCInfo; + callbacks[161] = (delegate* unmanaged)&_setEHcount; + callbacks[162] = (delegate* unmanaged)&_setEHinfo; + callbacks[163] = (delegate* unmanaged)&_logMsg; + callbacks[164] = (delegate* unmanaged)&_doAssert; + callbacks[165] = (delegate* unmanaged)&_reportFatalError; + callbacks[166] = (delegate* unmanaged)&_getPgoInstrumentationResults; + callbacks[167] = (delegate* unmanaged)&_allocPgoInstrumentationBySchema; + callbacks[168] = (delegate* unmanaged)&_recordCallSite; + callbacks[169] = (delegate* unmanaged)&_recordRelocation; + callbacks[170] = (delegate* unmanaged)&_getRelocTypeHint; + callbacks[171] = (delegate* unmanaged)&_getExpectedTargetArchitecture; + callbacks[172] = (delegate* unmanaged)&_getJitFlags; return (IntPtr)callbacks; } diff --git a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt index 3407e4e3a87c9a..fda65c03b9ab17 100644 --- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt +++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt @@ -266,6 +266,7 @@ FUNCTIONS void getVars(CORINFO_METHOD_HANDLE ftn, uint32_t* cVars, ICorDebugInfo::ILVarInfo** vars, bool* extendOthers) void setVars(CORINFO_METHOD_HANDLE ftn, uint32_t cVars, ICorDebugInfo::NativeVarInfo* vars) void reportRichMappings(ICorDebugInfo::InlineTreeNode* inlineTreeNodes, uint32_t numInlineTreeNodes, ICorDebugInfo::RichOffsetMapping* mappings, uint32_t numMappings) + void reportMetadata(const char* key, const void* value, size_t length) void*allocateArray(size_t cBytes); void freeArray(void*array); CORINFO_ARG_LIST_HANDLE getArgNext(CORINFO_ARG_LIST_HANDLE args); diff --git a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h index 5d659488b29257..3723b57aa4d8e2 100644 --- a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h +++ b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h @@ -115,6 +115,7 @@ struct JitInterfaceCallbacks void (* getVars)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_METHOD_HANDLE ftn, uint32_t* cVars, ICorDebugInfo::ILVarInfo** vars, bool* extendOthers); void (* setVars)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_METHOD_HANDLE ftn, uint32_t cVars, ICorDebugInfo::NativeVarInfo* vars); void (* reportRichMappings)(void * thisHandle, CorInfoExceptionClass** ppException, ICorDebugInfo::InlineTreeNode* inlineTreeNodes, uint32_t numInlineTreeNodes, ICorDebugInfo::RichOffsetMapping* mappings, uint32_t numMappings); + void (* reportMetadata)(void * thisHandle, CorInfoExceptionClass** ppException, const char* key, const void* value, size_t length); void* (* allocateArray)(void * thisHandle, CorInfoExceptionClass** ppException, size_t cBytes); void (* freeArray)(void * thisHandle, CorInfoExceptionClass** ppException, void* array); CORINFO_ARG_LIST_HANDLE (* getArgNext)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_ARG_LIST_HANDLE args); @@ -1214,6 +1215,16 @@ class JitInterfaceWrapper : public ICorJitInfo if (pException != nullptr) throw pException; } + virtual void reportMetadata( + const char* key, + const void* value, + size_t length) +{ + CorInfoExceptionClass* pException = nullptr; + _callbacks->reportMetadata(_thisHandle, &pException, key, value, length); + if (pException != nullptr) throw pException; +} + virtual void* allocateArray( size_t cBytes) { diff --git a/src/coreclr/tools/superpmi/superpmi-shared/compileresult.cpp b/src/coreclr/tools/superpmi/superpmi-shared/compileresult.cpp index 3c6653c41a1c3a..ec6e88684060b2 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/compileresult.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/compileresult.cpp @@ -32,7 +32,13 @@ CompileResult::CompileResult() allocGCInfoDets.retval = nullptr; allocGCInfoDets.size = 0; + MethodFullName = nullptr; + TieringName = nullptr; memoryTracker = nullptr; + +#define JITMETADATAINFO(name, type, flags) +#define JITMETADATAMETRIC(name, type, flags) name = 0; +#include "jitmetadatalist.h" } CompileResult::~CompileResult() diff --git a/src/coreclr/tools/superpmi/superpmi-shared/compileresult.h b/src/coreclr/tools/superpmi/superpmi-shared/compileresult.h index b7be4dcd89279e..72415f1d38f595 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/compileresult.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/compileresult.h @@ -121,6 +121,8 @@ class CompileResult void dmpSetVars(DWORD key, const Agnostic_SetVars& value); bool repSetVars(CORINFO_METHOD_HANDLE* ftn, ULONG32* cVars, ICorDebugInfo::NativeVarInfo** vars); + void recMetadata(const char* key, const void* value); + void recSetPatchpointInfo(PatchpointInfo* patchpointInfo); void dmpSetPatchpointInfo(DWORD key, const Agnostic_SetPatchpointInfo& value); bool repSetPatchpointInfo(PatchpointInfo** patchpointInfo); @@ -215,6 +217,15 @@ class CompileResult #define DENSELWM(map, value) DenseLightWeightMap* map; #include "crlwmlist.h" +#define JITMETADATAINFO(name, type, flags) +#define JITMETADATAMETRIC(name, type, flags) type name; +#include "jitmetadatalist.h" + + // Reported method full name from JIT (not available with release JIT) + const char* MethodFullName; + // Reported compilation tier from JIT + const char* TieringName; + // not persisted to disk. public: LightWeightMap* CallTargetTypes; diff --git a/src/coreclr/tools/superpmi/superpmi-shared/jitmetadatalist.h b/src/coreclr/tools/superpmi/superpmi-shared/jitmetadatalist.h new file mode 100644 index 00000000000000..f43f4300d73a1a --- /dev/null +++ b/src/coreclr/tools/superpmi/superpmi-shared/jitmetadatalist.h @@ -0,0 +1 @@ +#include "../../../jit/jitmetadatalist.h" diff --git a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp index 47c50535e450f1..0cbcfb2df1b0b1 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp @@ -1193,6 +1193,12 @@ void interceptor_ICJI::reportRichMappings(ICorDebugInfo::InlineTreeNode* inli original_ICorJitInfo->reportRichMappings(inlineTreeNodes, numInlineTreeNodes, mappings, numMappings); } +void interceptor_ICJI::reportMetadata(const char* key, const void* value, size_t length) +{ + mc->cr->AddCall("reportMetadata"); + original_ICorJitInfo->reportMetadata(key, value, length); +} + /*-------------------------- Misc ---------------------------------------*/ // Used to allocate memory that needs to handed to the EE. // For eg, use this to allocated memory for reporting debug info, diff --git a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp index 0f69dfae4a08c6..d3fe993b94765b 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp @@ -845,6 +845,15 @@ void interceptor_ICJI::reportRichMappings( original_ICorJitInfo->reportRichMappings(inlineTreeNodes, numInlineTreeNodes, mappings, numMappings); } +void interceptor_ICJI::reportMetadata( + const char* key, + const void* value, + size_t length) +{ + mcs->AddCall("reportMetadata"); + original_ICorJitInfo->reportMetadata(key, value, length); +} + void* interceptor_ICJI::allocateArray( size_t cBytes) { diff --git a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp index 02bef7b549aca0..f3cdc4ff8ce636 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp @@ -741,6 +741,14 @@ void interceptor_ICJI::reportRichMappings( original_ICorJitInfo->reportRichMappings(inlineTreeNodes, numInlineTreeNodes, mappings, numMappings); } +void interceptor_ICJI::reportMetadata( + const char* key, + const void* value, + size_t length) +{ + original_ICorJitInfo->reportMetadata(key, value, length); +} + void* interceptor_ICJI::allocateArray( size_t cBytes) { diff --git a/src/coreclr/tools/superpmi/superpmi/fileio.cpp b/src/coreclr/tools/superpmi/superpmi/fileio.cpp index ed16485a038e8a..e26723de6e3e1e 100644 --- a/src/coreclr/tools/superpmi/superpmi/fileio.cpp +++ b/src/coreclr/tools/superpmi/superpmi/fileio.cpp @@ -27,10 +27,7 @@ bool FileWriter::Printf(const char* fmt, ...) } else { - DWORD numWritten; - bool result = - WriteFile(m_file.Get(), pBuffer, static_cast(printed), &numWritten, nullptr) && - (numWritten == static_cast(printed)); + bool result = Print(pBuffer, static_cast(printed)); if (pBuffer != stackBuffer) delete[] pBuffer; @@ -41,6 +38,75 @@ bool FileWriter::Printf(const char* fmt, ...) } } +bool FileWriter::Print(const char* value, size_t numChars) +{ + DWORD numWritten; + bool result = + WriteFile(m_file.Get(), value, static_cast(numChars), &numWritten, nullptr) && + (numWritten == static_cast(numChars)); + return result; +} + +bool FileWriter::Print(const char* value) +{ + return Print(value, strlen(value)); +} + +bool FileWriter::Print(int value) +{ + return Printf("%d", value); +} + +bool FileWriter::Print(int64_t value) +{ + return Printf("%lld", value); +} + +bool FileWriter::Print(double value) +{ + return Printf("%f", value); +} + +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; + } +} + bool FileWriter::CreateNew(const char* path, FileWriter* fw) { FileHandle handle(CreateFile(path, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr)); diff --git a/src/coreclr/tools/superpmi/superpmi/fileio.h b/src/coreclr/tools/superpmi/superpmi/fileio.h index a88e74d6ee00c5..4a1434f972598a 100644 --- a/src/coreclr/tools/superpmi/superpmi/fileio.h +++ b/src/coreclr/tools/superpmi/superpmi/fileio.h @@ -93,6 +93,12 @@ class FileWriter { } + bool Print(const char* value, size_t numChars); + bool Print(const char* value); + bool Print(int value); + bool Print(int64_t value); + bool Print(double value); + bool PrintQuotedCsvField(const char* value); bool Printf(const char* fmt, ...); static bool CreateNew(const char* path, FileWriter* fw); diff --git a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp index 15c17173abdda4..2c0b79bab4fcd9 100644 --- a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp @@ -1027,6 +1027,37 @@ void MyICJI::reportRichMappings( freeArray(mappings); } +void MyICJI::reportMetadata(const char* key, const void* value, size_t length) +{ + jitInstance->mc->cr->AddCall("reportMetadata"); + + if (strcmp(key, "MethodFullName") == 0) + { + char* buf = static_cast(jitInstance->mc->cr->allocateMemory(length + 1)); + memcpy(buf, value, length + 1); + jitInstance->mc->cr->MethodFullName = buf; + return; + } + + if (strcmp(key, "TieringName") == 0) + { + char* buf = static_cast(jitInstance->mc->cr->allocateMemory(length + 1)); + memcpy(buf, value, length + 1); + jitInstance->mc->cr->TieringName = buf; + return; + } + +#define JITMETADATAINFO(name, type, flags) +#define JITMETADATAMETRIC(name, type, flags) \ + if ((strcmp(key, #name) == 0) && (length == sizeof(type))) \ + { \ + memcpy(&jitInstance->mc->cr->name, value, sizeof(type)); \ + return; \ + } + +#include "jitmetadatalist.h" +} + /*-------------------------- Misc ---------------------------------------*/ // Used to allocate memory that needs to handed to the EE. diff --git a/src/coreclr/tools/superpmi/superpmi/jitinstance.cpp b/src/coreclr/tools/superpmi/superpmi/jitinstance.cpp index 7c55db51af20cf..8eb0e69e8b2e5b 100644 --- a/src/coreclr/tools/superpmi/superpmi/jitinstance.cpp +++ b/src/coreclr/tools/superpmi/superpmi/jitinstance.cpp @@ -459,6 +459,7 @@ ReplayResults JitInstance::CompileMethod(MethodContext* MethodToCompile, int mcI } mc->cr->secondsToCompile = stj.GetSeconds(); + param.results.CompileResults = mc->cr; UINT64 insCountAfter = 0; Instrumentor_GetInsCount(&insCountAfter); diff --git a/src/coreclr/tools/superpmi/superpmi/jitinstance.h b/src/coreclr/tools/superpmi/superpmi/jitinstance.h index 03e283c1d5b62d..b13fe46d641f40 100644 --- a/src/coreclr/tools/superpmi/superpmi/jitinstance.h +++ b/src/coreclr/tools/superpmi/superpmi/jitinstance.h @@ -22,6 +22,7 @@ struct ReplayResults bool IsMinOpts = false; uint32_t NumCodeBytes = 0; uint64_t NumExecutedInstructions = 0; + CompileResult* CompileResults = nullptr; }; class JitInstance diff --git a/src/coreclr/tools/superpmi/superpmi/superpmi.cpp b/src/coreclr/tools/superpmi/superpmi/superpmi.cpp index 4ac03d18ce9a6d..f0b4b76fcc1c19 100644 --- a/src/coreclr/tools/superpmi/superpmi/superpmi.cpp +++ b/src/coreclr/tools/superpmi/superpmi/superpmi.cpp @@ -137,42 +137,81 @@ static const char* ResultToString(ReplayResult result) } } -static bool PrintDiffsCsvHeader(FileWriter& fw) +static void PrintDiffsCsvHeader(FileWriter& fw) { - return fw.Printf("Context,Context size,Base result,Diff result,MinOpts,Has diff,Base size,Diff size,Base instructions,Diff instructions\n"); + fw.Print("Context,Context size,Method full name,Tier name,Base result,Diff result,MinOpts,Has diff,Base size,Diff size,Base instructions,Diff instructions"); + +#define JITMETADATAINFO(name, type, flags) +#define JITMETADATAMETRIC(name, type, flags) fw.Print(",Base " #name ",Diff " #name); + +#include "jitmetadatalist.h" + + fw.Print("\n"); } -static bool PrintDiffsCsvRow( +static void PrintDiffsCsvRow( FileWriter& fw, int context, uint32_t contextSize, const ReplayResults& baseRes, const ReplayResults& diffRes, bool hasDiff) { - return fw.Printf("%d,%u,%s,%s,%s,%s,%u,%u,%lld,%lld\n", - context, contextSize, + fw.Printf("%d,%u,", context, contextSize); + fw.PrintQuotedCsvField(baseRes.CompileResults->MethodFullName == nullptr ? "" : baseRes.CompileResults->MethodFullName); + fw.Printf( + ",%s,%s,%s,%s,%s,%u,%u,%lld,%lld", + baseRes.CompileResults->TieringName == nullptr ? "" : baseRes.CompileResults->TieringName, ResultToString(baseRes.Result), ResultToString(diffRes.Result), baseRes.IsMinOpts ? "True" : "False", hasDiff ? "True" : "False", baseRes.NumCodeBytes, diffRes.NumCodeBytes, baseRes.NumExecutedInstructions, diffRes.NumExecutedInstructions); + +#define JITMETADATAINFO(name, type, flags) +#define JITMETADATAMETRIC(name, type, flags) \ + fw.Print(","); \ + fw.Print(baseRes.CompileResults->name); \ + fw.Print(","); \ + fw.Print(diffRes.CompileResults->name); + +#include "jitmetadatalist.h" + + fw.Print("\n"); } -static bool PrintReplayCsvHeader(FileWriter& fw) +static void PrintReplayCsvHeader(FileWriter& fw) { - return fw.Printf("Context,Context size,Result,MinOpts,Size,Instructions\n"); + fw.Printf("Context,Context size,Method full name,Tier name,Result,MinOpts,Size,Instructions"); + +#define JITMETADATAINFO(name, type, flags) +#define JITMETADATAMETRIC(name, type, flags) fw.Print("," #name); + +#include "jitmetadatalist.h" + + fw.Print("\n"); } -static bool PrintReplayCsvRow( +static void PrintReplayCsvRow( FileWriter& fw, int context, uint32_t contextSize, const ReplayResults& res) { - return fw.Printf("%d,%u,%s,%s,%u,%lld\n", - context, contextSize, + fw.Printf("%d,%u,", context, contextSize); + fw.PrintQuotedCsvField(res.CompileResults->MethodFullName == nullptr ? "" : res.CompileResults->MethodFullName); + fw.Printf(",%s,%s,%s,%u,%lld", + res.CompileResults->TieringName == nullptr ? "" : res.CompileResults->TieringName, ResultToString(res.Result), res.IsMinOpts ? "True" : "False", res.NumCodeBytes, res.NumExecutedInstructions); + +#define JITMETADATAINFO(name, type, flags) +#define JITMETADATAMETRIC(name, type, flags) \ + fw.Print(","); \ + fw.Print(res.CompileResults->name); + +#include "jitmetadatalist.h" + + fw.Print("\n"); } // Run superpmi. The return value is as follows: diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 62d69c0fe4ef98..a2146482a2fc02 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -10956,6 +10956,22 @@ void CEEJitInfo::reportRichMappings( EE_TO_JIT_TRANSITION(); } +void CEEJitInfo::reportMetadata( + const char* key, + const void* value, + size_t length) +{ + CONTRACTL { + NOTHROW; + GC_NOTRIGGER; + MODE_PREEMPTIVE; + } CONTRACTL_END; + + JIT_TO_EE_TRANSITION_LEAF(); + + EE_TO_JIT_TRANSITION_LEAF(); +} + void CEEJitInfo::setPatchpointInfo(PatchpointInfo* patchpointInfo) { CONTRACTL { @@ -14421,6 +14437,12 @@ void CEEInfo::reportRichMappings( UNREACHABLE(); // only called on derived class. } +void CEEInfo::reportMetadata(const char* key, const void* value, size_t length) +{ + LIMITED_METHOD_CONTRACT; + UNREACHABLE(); // only called on derived class. +} + void CEEInfo::setPatchpointInfo(PatchpointInfo* patchpointInfo) { LIMITED_METHOD_CONTRACT; diff --git a/src/coreclr/vm/jitinterface.h b/src/coreclr/vm/jitinterface.h index 1708a05df5e314..63666b46552cf9 100644 --- a/src/coreclr/vm/jitinterface.h +++ b/src/coreclr/vm/jitinterface.h @@ -897,6 +897,8 @@ class CEEJitInfo : public CEEInfo ICorDebugInfo::RichOffsetMapping* mappings, uint32_t numMappings) override final; + void reportMetadata(const char* key, const void* value, size_t length) override final; + void* getHelperFtn(CorInfoHelpFunc ftnNum, /* IN */ void ** ppIndirection) override final; /* OUT */ static PCODE getHelperFtnStatic(CorInfoHelpFunc ftnNum);