diff --git a/src/coreclr/gcinfo/gcinfoencoder.cpp b/src/coreclr/gcinfo/gcinfoencoder.cpp index 0abf65047b8d9..fb2f06a80c44a 100644 --- a/src/coreclr/gcinfo/gcinfoencoder.cpp +++ b/src/coreclr/gcinfo/gcinfoencoder.cpp @@ -462,6 +462,7 @@ GcInfoEncoder::GcInfoEncoder( m_pCallSiteSizes = NULL; m_NumCallSites = 0; #endif + m_BlockSize = 0; m_GSCookieStackSlot = NO_GS_COOKIE; m_GSCookieValidRangeStart = 0; @@ -2576,9 +2577,14 @@ BYTE* GcInfoEncoder::Emit() void * GcInfoEncoder::eeAllocGCInfo (size_t blockSize) { + m_BlockSize = blockSize; return m_pCorJitInfo->allocGCInfo(blockSize); } +size_t GcInfoEncoder::GetEncodedGCInfoSize() const +{ + return m_BlockSize; +} BitStreamWriter::BitStreamWriter( IAllocator* pAllocator ) { diff --git a/src/coreclr/inc/gcinfoencoder.h b/src/coreclr/inc/gcinfoencoder.h index b3199a1a95616..0cf7f67800b9c 100644 --- a/src/coreclr/inc/gcinfoencoder.h +++ b/src/coreclr/inc/gcinfoencoder.h @@ -468,6 +468,12 @@ class GcInfoEncoder // BYTE* Emit(); + // + // Return the size in bytes of the constructed GC info. This is the size passed + // to the VM via `allocGCInfo`. It is only valid after `Emit` is called. + // + size_t GetEncodedGCInfoSize() const; + private: friend struct CompareLifetimeTransitionsByOffsetThenSlot; @@ -534,6 +540,8 @@ class GcInfoEncoder UINT32 m_NumCallSites; #endif // PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED + size_t m_BlockSize; // The byte size passed to the `allocGCInfo` call + void GrowSlotTable(); void WriteSlotStateVector(BitStreamWriter &writer, const BitArray& vector); diff --git a/src/coreclr/jit/codegenarmarch.cpp b/src/coreclr/jit/codegenarmarch.cpp index 99220ca4be928..57d71faae0e9e 100644 --- a/src/coreclr/jit/codegenarmarch.cpp +++ b/src/coreclr/jit/codegenarmarch.cpp @@ -4138,7 +4138,7 @@ void CodeGen::genCreateAndStoreGCInfo(unsigned codeSize, // GC Encoder automatically puts the GC info in the right spot using ICorJitInfo::allocGCInfo(size_t) // let's save the values anyway for debugging purposes compiler->compInfoBlkAddr = gcInfoEncoder->Emit(); - compiler->compInfoBlkSize = 0; // not exposed by the GCEncoder interface + compiler->compInfoBlkSize = gcInfoEncoder->GetEncodedGCInfoSize(); } // clang-format off diff --git a/src/coreclr/jit/codegencommon.cpp b/src/coreclr/jit/codegencommon.cpp index bc0bda41152af..d24402987c77a 100644 --- a/src/coreclr/jit/codegencommon.cpp +++ b/src/coreclr/jit/codegencommon.cpp @@ -2288,6 +2288,7 @@ void CodeGen::genEmitUnwindDebugGCandEH() // Create and store the GC info for this method. genCreateAndStoreGCInfo(codeSize, prologSize, epilogSize DEBUGARG(codePtr)); + compiler->Metrics.GCInfoBytes = compiler->compInfoBlkSize; /* Tell the emitter that we're done with this function */ @@ -2420,6 +2421,7 @@ void CodeGen::genReportEH() // Tell the VM how many EH clauses to expect. compiler->eeSetEHcount(EHCount); + compiler->Metrics.EHClauseCount = (int)EHCount; struct EHClauseInfo { diff --git a/src/coreclr/jit/codegenloongarch64.cpp b/src/coreclr/jit/codegenloongarch64.cpp index 7d7be01add9ef..b47b3fcdcf2e6 100644 --- a/src/coreclr/jit/codegenloongarch64.cpp +++ b/src/coreclr/jit/codegenloongarch64.cpp @@ -6488,7 +6488,7 @@ void CodeGen::genCreateAndStoreGCInfo(unsigned codeSize, // GC Encoder automatically puts the GC info in the right spot using ICorJitInfo::allocGCInfo(size_t) // let's save the values anyway for debugging purposes compiler->compInfoBlkAddr = gcInfoEncoder->Emit(); - compiler->compInfoBlkSize = 0; // not exposed by the GCEncoder interface + compiler->compInfoBlkSize = gcInfoEncoder->GetEncodedGCInfoSize(); } //------------------------------------------------------------------------ diff --git a/src/coreclr/jit/codegenriscv64.cpp b/src/coreclr/jit/codegenriscv64.cpp index ef61b0e56da8d..c06497a5abc0d 100644 --- a/src/coreclr/jit/codegenriscv64.cpp +++ b/src/coreclr/jit/codegenriscv64.cpp @@ -6488,7 +6488,7 @@ void CodeGen::genCreateAndStoreGCInfo(unsigned codeSize, // GC Encoder automatically puts the GC info in the right spot using ICorJitInfo::allocGCInfo(size_t) // let's save the values anyway for debugging purposes compiler->compInfoBlkAddr = gcInfoEncoder->Emit(); - compiler->compInfoBlkSize = 0; // not exposed by the GCEncoder interface + compiler->compInfoBlkSize = gcInfoEncoder->GetEncodedGCInfoSize(); } //------------------------------------------------------------------------ diff --git a/src/coreclr/jit/codegenxarch.cpp b/src/coreclr/jit/codegenxarch.cpp index c622304e1a8e9..6428c2d91369b 100644 --- a/src/coreclr/jit/codegenxarch.cpp +++ b/src/coreclr/jit/codegenxarch.cpp @@ -8880,7 +8880,7 @@ void CodeGen::genCreateAndStoreGCInfoX64(unsigned codeSize, unsigned prologSize // GC Encoder automatically puts the GC info in the right spot using ICorJitInfo::allocGCInfo(size_t) // let's save the values anyway for debugging purposes compiler->compInfoBlkAddr = gcInfoEncoder->Emit(); - compiler->compInfoBlkSize = 0; // not exposed by the GCEncoder interface + compiler->compInfoBlkSize = gcInfoEncoder->GetEncodedGCInfoSize(); } #endif // !JIT32_GCENCODER diff --git a/src/coreclr/jit/jitmetadatalist.h b/src/coreclr/jit/jitmetadatalist.h index 51ef3c8104464..412b88a391911 100644 --- a/src/coreclr/jit/jitmetadatalist.h +++ b/src/coreclr/jit/jitmetadatalist.h @@ -27,6 +27,8 @@ // Name, type flags JITMETADATAINFO(MethodFullName, const char*, 0) JITMETADATAINFO(TieringName, const char*, 0) +JITMETADATAMETRIC(GCInfoBytes, int64_t, JIT_METADATA_LOWER_IS_BETTER) +JITMETADATAMETRIC(EHClauseCount, int, 0) JITMETADATAMETRIC(PhysicallyPromotedFields, int, 0) JITMETADATAMETRIC(LoopsFoundDuringOpts, int, 0) JITMETADATAMETRIC(LoopsCloned, int, 0) diff --git a/src/coreclr/tools/superpmi/superpmi/jitinstance.cpp b/src/coreclr/tools/superpmi/superpmi/jitinstance.cpp index 2f085b2610d86..0058fd558af27 100644 --- a/src/coreclr/tools/superpmi/superpmi/jitinstance.cpp +++ b/src/coreclr/tools/superpmi/superpmi/jitinstance.cpp @@ -410,7 +410,13 @@ ReplayResults JitInstance::CompileMethod(MethodContext* MethodToCompile, int mcI pParam->pThis->mc->cr->recMessageLog(jitResult == CORJIT_OK ? "Successful Compile" : "Successful Compile (BADCODE)"); - pParam->results.NumCodeBytes = NCodeSizeBlock; + pParam->results.NumCodeBytes = NCodeSizeBlock; + + // Extract the GCInfo size. + size_t size; + void* retval_unused; + pParam->pThis->mc->cr->repAllocGCInfo(&size, &retval_unused); + pParam->results.NumGCInfoBytes = size; } else { diff --git a/src/coreclr/tools/superpmi/superpmi/jitinstance.h b/src/coreclr/tools/superpmi/superpmi/jitinstance.h index b13fe46d641f4..9f65e2424b99c 100644 --- a/src/coreclr/tools/superpmi/superpmi/jitinstance.h +++ b/src/coreclr/tools/superpmi/superpmi/jitinstance.h @@ -21,6 +21,7 @@ struct ReplayResults ReplayResult Result = ReplayResult::Success; bool IsMinOpts = false; uint32_t NumCodeBytes = 0; + size_t NumGCInfoBytes = 0; uint64_t NumExecutedInstructions = 0; CompileResult* CompileResults = nullptr; }; diff --git a/src/coreclr/tools/superpmi/superpmi/superpmi.cpp b/src/coreclr/tools/superpmi/superpmi/superpmi.cpp index 012c433977282..5e9ae5ac6f57f 100644 --- a/src/coreclr/tools/superpmi/superpmi/superpmi.cpp +++ b/src/coreclr/tools/superpmi/superpmi/superpmi.cpp @@ -139,7 +139,7 @@ static const char* ResultToString(ReplayResult result) static void PrintDiffsCsvHeader(FileWriter& fw) { - 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"); + fw.Print("Context,Context size,Method full name,Tier name,Base result,Diff result,MinOpts,Has diff,Base size,Diff size,Base GCInfo size,Diff GCInfo size,Base instructions,Diff instructions"); #define JITMETADATAINFO(name, type, flags) #define JITMETADATAMETRIC(name, type, flags) fw.Print(",Base " #name ",Diff " #name); @@ -159,12 +159,13 @@ static void PrintDiffsCsvRow( 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", + ",%s,%s,%s,%s,%s,%u,%u,%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, + (uint32_t)baseRes.NumGCInfoBytes, (uint32_t)diffRes.NumGCInfoBytes, baseRes.NumExecutedInstructions, diffRes.NumExecutedInstructions); #define JITMETADATAINFO(name, type, flags) @@ -181,7 +182,7 @@ static void PrintDiffsCsvRow( static void PrintReplayCsvHeader(FileWriter& fw) { - fw.Printf("Context,Context size,Method full name,Tier name,Result,MinOpts,Size,Instructions"); + fw.Printf("Context,Context size,Method full name,Tier name,Result,MinOpts,Size,GCInfo size,Instructions"); #define JITMETADATAINFO(name, type, flags) #define JITMETADATAMETRIC(name, type, flags) fw.Print("," #name); @@ -198,11 +199,11 @@ static void PrintReplayCsvRow( { fw.Printf("%d,%u,", context, contextSize); fw.PrintQuotedCsvField(res.CompileResults->MethodFullName == nullptr ? "" : res.CompileResults->MethodFullName); - fw.Printf(",%s,%s,%s,%u,%lld", + fw.Printf(",%s,%s,%s,%u,%u,%lld", res.CompileResults->TieringName == nullptr ? "" : res.CompileResults->TieringName, ResultToString(res.Result), res.IsMinOpts ? "True" : "False", - res.NumCodeBytes, res.NumExecutedInstructions); + res.NumCodeBytes, (uint32_t)res.NumGCInfoBytes, res.NumExecutedInstructions); #define JITMETADATAINFO(name, type, flags) #define JITMETADATAMETRIC(name, type, flags) \