DWORD result;
};
-struct Agnostic_GetLikelyClass
-{
- DWORDLONG ftnHnd;
- DWORDLONG baseHnd;
- DWORD ilOffset;
-};
-
-struct Agnostic_GetLikelyClassResult
-{
- DWORDLONG classHnd;
- DWORD likelihood;
- DWORD numberOfClasses;
-};
-
struct Agnostic_GetProfilingHandle
{
DWORD bHookFunction;
LWM(GetJitTimeLogFilename, DWORD, DWORD)
LWM(GetJustMyCodeHandle, DWORDLONG, DLDL)
LWM(GetLazyStringLiteralHelper, DWORDLONG, DWORD)
-LWM(GetLikelyClass, Agnostic_GetLikelyClass, Agnostic_GetLikelyClassResult)
LWM(GetLocationOfThisType, DWORDLONG, Agnostic_CORINFO_LOOKUP_KIND)
LWM(IsJitIntrinsic, DWORDLONG, DWORD)
LWM(GetMethodAttribs, DWORDLONG, DWORD)
return result;
}
-void MethodContext::recGetLikelyClass(CORINFO_METHOD_HANDLE ftnHnd, CORINFO_CLASS_HANDLE baseHnd, UINT32 ilOffset, CORINFO_CLASS_HANDLE result, UINT32* pLikelihood, UINT32* pNumberOfClasses)
-{
- if (GetLikelyClass == nullptr)
- GetLikelyClass = new LightWeightMap<Agnostic_GetLikelyClass, Agnostic_GetLikelyClassResult>();
-
- Agnostic_GetLikelyClass key;
- ZeroMemory(&key, sizeof(Agnostic_GetLikelyClass));
-
- key.ftnHnd = CastHandle(ftnHnd);
- key.baseHnd = CastHandle(baseHnd);
- key.ilOffset = (DWORD) ilOffset;
-
- Agnostic_GetLikelyClassResult value;
- ZeroMemory(&value, sizeof(Agnostic_GetLikelyClassResult));
- value.classHnd = CastHandle(result);
- value.likelihood = *pLikelihood;
- value.numberOfClasses = *pNumberOfClasses;
-
- GetLikelyClass->Add(key, value);
- DEBUG_REC(dmpGetLikelyClass(key, value));
-}
-void MethodContext::dmpGetLikelyClass(const Agnostic_GetLikelyClass& key, const Agnostic_GetLikelyClassResult& value)
-{
- printf("GetLikelyClass key ftn-%016llX base-%016llX il-%u, class-%016llX likelihood-%u numberOfClasses-%u",
- key.ftnHnd, key.baseHnd, key.ilOffset, value.classHnd, value.likelihood, value.numberOfClasses);
-}
-CORINFO_CLASS_HANDLE MethodContext::repGetLikelyClass(CORINFO_METHOD_HANDLE ftnHnd, CORINFO_CLASS_HANDLE baseHnd, UINT32 ilOffset, UINT32* pLikelihood, UINT32* pNumberOfClasses)
-{
- Agnostic_GetLikelyClass key;
- ZeroMemory(&key, sizeof(Agnostic_GetLikelyClass));
- key.ftnHnd = CastHandle(ftnHnd);
- key.baseHnd = CastHandle(baseHnd);
- key.ilOffset = (DWORD) ilOffset;
-
- Agnostic_GetLikelyClassResult value = GetLikelyClass->Get(key);
- DEBUG_REP(dmpGetLikelyClass(key, value));
-
- *pLikelihood = value.likelihood;
- *pNumberOfClasses = value.numberOfClasses;
- return (CORINFO_CLASS_HANDLE) value.classHnd;
-}
-
void MethodContext::recMergeClasses(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2, CORINFO_CLASS_HANDLE result)
{
if (MergeClasses == nullptr)
void dmpGetPgoInstrumentationResults(DWORDLONG key, const Agnostic_GetPgoInstrumentationResults& value);
HRESULT repGetPgoInstrumentationResults(CORINFO_METHOD_HANDLE ftnHnd, ICorJitInfo::PgoInstrumentationSchema** pSchema, UINT32* pCountSchemaItems, BYTE** pInstrumentationData);
- void recGetLikelyClass(CORINFO_METHOD_HANDLE ftnHnd, CORINFO_CLASS_HANDLE baseHnd, UINT32 ilOffset, CORINFO_CLASS_HANDLE classHnd, UINT32* pLikelihood, UINT32* pNumberOfClasses);
- void dmpGetLikelyClass(const Agnostic_GetLikelyClass& key, const Agnostic_GetLikelyClassResult& value);
- CORINFO_CLASS_HANDLE repGetLikelyClass(CORINFO_METHOD_HANDLE ftnHnd, CORINFO_CLASS_HANDLE baseHnd, UINT32 ilOffset, UINT32* pLikelihood, UINT32* pNumberOfClasses);
-
void recMergeClasses(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2, CORINFO_CLASS_HANDLE result);
void dmpMergeClasses(DLDL key, DWORDLONG value);
CORINFO_CLASS_HANDLE repMergeClasses(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2);
Packet_GetJitFlags = 154, // Added 2/3/2016
Packet_GetJitTimeLogFilename = 67,
Packet_GetJustMyCodeHandle = 68,
- Packet_GetLikelyClass = 182, // Added 9/27/2020
+ Retired10 = 182, // Added 9/27/2020 // was Packet_GetLikelyClass
Packet_GetLocationOfThisType = 69,
Packet_IsJitIntrinsic = 192,
Packet_GetMethodAttribs = 70,
return temp;
}
-// Get the likely implementing class for a virtual call or interface call made by ftnHnd
-// at the indicated IL offset. baseHnd is the interface class or base class for the method
-// being called.
-CORINFO_CLASS_HANDLE interceptor_ICJI::getLikelyClass(CORINFO_METHOD_HANDLE ftnHnd,
- CORINFO_CLASS_HANDLE baseHnd,
- uint32_t ilOffset,
- uint32_t* pLikelihood,
- uint32_t* pNumberOfClasses)
-{
- mc->cr->AddCall("getLikelyClass");
- CORINFO_CLASS_HANDLE result = original_ICorJitInfo->getLikelyClass(ftnHnd, baseHnd, ilOffset, pLikelihood, pNumberOfClasses);
- mc->recGetLikelyClass(ftnHnd, baseHnd, ilOffset, result, pLikelihood, pNumberOfClasses);
- return result;
-}
-
// Associates a native call site, identified by its offset in the native code stream, with
// the signature information and method handle the JIT used to lay out the call site. If
// the call site has no signature information (e.g. a helper call) or has no method handle
return original_ICorJitInfo->allocPgoInstrumentationBySchema(ftnHnd, pSchema, countSchemaItems, pInstrumentationData);
}
-CORINFO_CLASS_HANDLE interceptor_ICJI::getLikelyClass(
- CORINFO_METHOD_HANDLE ftnHnd,
- CORINFO_CLASS_HANDLE baseHnd,
- uint32_t ilOffset,
- uint32_t* pLikelihood,
- uint32_t* pNumberOfClasses)
-{
- mcs->AddCall("getLikelyClass");
- return original_ICorJitInfo->getLikelyClass(ftnHnd, baseHnd, ilOffset, pLikelihood, pNumberOfClasses);
-}
-
void interceptor_ICJI::recordCallSite(
uint32_t instrOffset,
CORINFO_SIG_INFO* callSig,
return original_ICorJitInfo->allocPgoInstrumentationBySchema(ftnHnd, pSchema, countSchemaItems, pInstrumentationData);
}
-CORINFO_CLASS_HANDLE interceptor_ICJI::getLikelyClass(
- CORINFO_METHOD_HANDLE ftnHnd,
- CORINFO_CLASS_HANDLE baseHnd,
- uint32_t ilOffset,
- uint32_t* pLikelihood,
- uint32_t* pNumberOfClasses)
-{
- return original_ICorJitInfo->getLikelyClass(ftnHnd, baseHnd, ilOffset, pLikelihood, pNumberOfClasses);
-}
-
void interceptor_ICJI::recordCallSite(
uint32_t instrOffset,
CORINFO_SIG_INFO* callSig,
return jitInstance->mc->repGetPgoInstrumentationResults(ftnHnd, pSchema, pCountSchemaItems, pInstrumentationData);
}
-// Get the likely implementing class for a virtual call or interface call made by ftnHnd
-// at the indicated IL offset. baseHnd is the interface class or base class for the method
-// being called.
-CORINFO_CLASS_HANDLE MyICJI::getLikelyClass(CORINFO_METHOD_HANDLE ftnHnd,
- CORINFO_CLASS_HANDLE baseHnd,
- uint32_t ilOffset,
- uint32_t* pLikelihood,
- uint32_t* pNumberOfClasses)
-{
- jitInstance->mc->cr->AddCall("getLikelyClass");
- return jitInstance->mc->repGetLikelyClass(ftnHnd, baseHnd, ilOffset, pLikelihood, pNumberOfClasses);
-}
-
// Associates a native call site, identified by its offset in the native code stream, with
// the signature information and method handle the JIT used to lay out the call site. If
// the call site has no signature information (e.g. a helper call) or has no method handle
Version = (DescriptorMin * 4) | None, // Version is encoded in the Other field of the schema
NumRuns = (DescriptorMin * 5) | None, // Number of runs is encoded in the Other field of the schema
EdgeIntCount = (DescriptorMin * 6) | FourByte, // 4 byte edge counter, using unsigned 4 byte int
+ GetLikelyClass = (DescriptorMin * 7) | TypeHandle, // Compressed get likely class data
};
struct PgoInstrumentationSchema
int32_t Other;
};
+#define DEFAULT_UNKNOWN_TYPEHANDLE 1
+#define UNKNOWN_TYPEHANDLE_MIN 1
+#define UNKNOWN_TYPEHANDLE_MAX 33
+
+ static inline bool IsUnknownTypeHandle(intptr_t typeHandle)
+ {
+ return ((typeHandle >= UNKNOWN_TYPEHANDLE_MIN) && (typeHandle <= UNKNOWN_TYPEHANDLE_MAX));
+ }
+
// get profile information to be used for optimizing a current method. The format
// of the buffer is the same as the format the JIT passes to allocPgoInstrumentationBySchema.
virtual JITINTERFACE_HRESULT getPgoInstrumentationResults(
uint8_t ** pInstrumentationData // OUT: `*pInstrumentationData` is set to the address of the instrumentation data.
) = 0;
- // Get the likely implementing class for a virtual call or interface call made by ftnHnd
- // at the indicated IL offset. baseHnd is the interface class or base class for the method
- // being called. May returns NULL.
- //
- // pLikelihood is the estimated percent chance that the class at runtime is the class
- // returned by this method. A well-estimated monomorphic call site will return a likelihood
- // of 100.
- //
- // pNumberOfClasses is the estimated number of different classes seen at the site.
- // A well-estimated monomorphic call site will return 1.
- virtual CORINFO_CLASS_HANDLE getLikelyClass(
- CORINFO_METHOD_HANDLE ftnHnd,
- CORINFO_CLASS_HANDLE baseHnd,
- uint32_t ilOffset,
- uint32_t * pLikelihood, // OUT, estimated likelihood of the class (0...100)
- uint32_t * pNumberOfClasses // OUT, estimated number of possible classes
- ) = 0;
-
// Associates a native call site, identified by its offset in the native code stream, with
// the signature information and method handle the JIT used to lay out the call site. If
// the call site has no signature information (e.g. a helper call) or has no method handle
uint32_t countSchemaItems,
uint8_t** pInstrumentationData) override;
-CORINFO_CLASS_HANDLE getLikelyClass(
- CORINFO_METHOD_HANDLE ftnHnd,
- CORINFO_CLASS_HANDLE baseHnd,
- uint32_t ilOffset,
- uint32_t* pLikelihood,
- uint32_t* pNumberOfClasses) override;
-
void recordCallSite(
uint32_t instrOffset,
CORINFO_SIG_INFO* callSig,
#define GUID_DEFINED
#endif // !GUID_DEFINED
-constexpr GUID JITEEVersionIdentifier = { /* a33f2f79-dd8d-49dd-b4c3-ac86f34f6a87 */
- 0xa33f2f79,
- 0xdd8d,
- 0x49dd,
- {0xb4, 0xc3, 0xac, 0x86, 0xf3, 0x4f, 0x6a, 0x87}
+constexpr GUID JITEEVersionIdentifier = { /* 12234eca-dfc2-48bc-a320-6155cf25ce17 */
+ 0x12234eca,
+ 0xdfc2,
+ 0x48bc,
+ {0xa3, 0x20, 0x61, 0x55, 0xcf, 0x25, 0xce, 0x17}
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifdef FEATURE_PGO
-#define DEFAULT_UNKNOWN_TYPEHANDLE 1
-#define UNKNOWN_TYPEHANDLE_MIN 1
-#define UNKNOWN_TYPEHANDLE_MAX 32
-
inline bool AddTypeHandleToUnknownTypeHandleMask(INT_PTR typeHandle, uint32_t *unknownTypeHandleMask)
{
uint32_t bitMask = (uint32_t)(1 << (typeHandle - UNKNOWN_TYPEHANDLE_MIN));
return result;
}
-inline bool IsUnknownTypeHandle(INT_PTR typeHandle)
-{
- return ((typeHandle >= UNKNOWN_TYPEHANDLE_MIN) && (typeHandle <= UNKNOWN_TYPEHANDLE_MAX));
-}
-
inline INT_PTR HashToPgoUnknownTypeHandle(uint32_t hash)
{
// Map from a 32bit hash to the 32 different unknown type handle values
jittelemetry.cpp
lclmorph.cpp
lclvars.cpp
+ likelyclass.cpp
lir.cpp
liveness.cpp
loopcloning.cpp
getJit
jitStartup
+getLikelyClass
EXPORTS
getJit
jitStartup
+ getLikelyClass
DEF_CLR_API(reportFatalError)
DEF_CLR_API(getPgoInstrumentationResults)
DEF_CLR_API(allocPgoInstrumentationBySchema)
-DEF_CLR_API(getLikelyClass)
DEF_CLR_API(recordCallSite)
DEF_CLR_API(recordRelocation)
DEF_CLR_API(getRelocTypeHint)
return temp;
}
-CORINFO_CLASS_HANDLE WrapICorJitInfo::getLikelyClass(
- CORINFO_METHOD_HANDLE ftnHnd,
- CORINFO_CLASS_HANDLE baseHnd,
- uint32_t ilOffset,
- uint32_t* pLikelihood,
- uint32_t* pNumberOfClasses)
-{
- API_ENTER(getLikelyClass);
- CORINFO_CLASS_HANDLE temp = wrapHnd->getLikelyClass(ftnHnd, baseHnd, ilOffset, pLikelihood, pNumberOfClasses);
- API_LEAVE(getLikelyClass);
- return temp;
-}
-
void WrapICorJitInfo::recordCallSite(
uint32_t instrOffset,
CORINFO_SIG_INFO* callSig,
// See if there's a likely guess for the class.
//
- const unsigned likelihoodThreshold = isInterface ? 25 : 30;
- unsigned likelihood = 0;
- unsigned numberOfClasses = 0;
+ const unsigned likelihoodThreshold = isInterface ? 25 : 30;
+ unsigned likelihood = 0;
+ unsigned numberOfClasses = 0;
+
CORINFO_CLASS_HANDLE likelyClass =
- info.compCompHnd->getLikelyClass(info.compMethodHnd, baseClass, ilOffset, &likelihood, &numberOfClasses);
+ getLikelyClass(fgPgoSchema, fgPgoSchemaCount, fgPgoData, ilOffset, &likelihood, &numberOfClasses);
if (likelyClass == NO_CLASS_HANDLE)
{
#endif // !defined(DEBUG)
+extern "C" CORINFO_CLASS_HANDLE WINAPI getLikelyClass(ICorJitInfo::PgoInstrumentationSchema* schema,
+ UINT32 countSchemaItems,
+ BYTE* pInstrumentationData,
+ int32_t ilOffset,
+ UINT32* pLikelihood,
+ UINT32* pNumberOfClasses);
+
/*****************************************************************************/
#endif //_JIT_H_
/*****************************************************************************/
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+/*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XX XX
+XX Likely Class Processing XX
+XX XX
+XX Parses Pgo data to find the most likely class in use at a given XX
+XX IL offset in a method. Used by both the JIT, and by crossgen XX
+XX XX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+*/
+
+#include "jitpch.h"
+#ifdef _MSC_VER
+#pragma hdrstop
+#endif
+
+#ifndef DLLEXPORT
+#define DLLEXPORT
+#endif // !DLLEXPORT
+
+// Data item in class profile histogram
+//
+struct LikelyClassHistogramEntry
+{
+ // Class that was observed at runtime
+ INT_PTR m_mt; // This may be an "unknown type handle"
+ // Number of observations in the table
+ unsigned m_count;
+};
+
+// Summarizes a ClassProfile table by forming a Histogram
+
+//
+struct LikelyClassHistogram
+{
+ LikelyClassHistogram(uint32_t histogramCount, INT_PTR* histogramEntries, unsigned entryCount);
+
+ // Sum of counts from all entries in the histogram. This includes "unknown" entries which are not captured in
+ // m_histogram
+ unsigned m_totalCount;
+ // Rough guess at count of unknown types
+ unsigned m_unknownTypes;
+ // Histogram entries, in no particular order.
+ LikelyClassHistogramEntry m_histogram[64];
+ UINT32 countHistogramElements = 0;
+
+ LikelyClassHistogramEntry HistogramEntryAt(unsigned index)
+ {
+ return m_histogram[index];
+ }
+};
+
+LikelyClassHistogram::LikelyClassHistogram(uint32_t histogramCount, INT_PTR* histogramEntries, unsigned entryCount)
+{
+ m_unknownTypes = 0;
+ m_totalCount = 0;
+ uint32_t unknownTypeHandleMask = 0;
+
+ for (unsigned k = 0; k < entryCount; k++)
+ {
+ if (histogramEntries[k] == 0)
+ {
+ continue;
+ }
+
+ m_totalCount++;
+
+ INT_PTR currentEntry = histogramEntries[k];
+
+ bool found = false;
+ unsigned h = 0;
+ for (; h < countHistogramElements; h++)
+ {
+ if (m_histogram[h].m_mt == currentEntry)
+ {
+ m_histogram[h].m_count++;
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ if (countHistogramElements >= _countof(m_histogram))
+ {
+ continue;
+ }
+ LikelyClassHistogramEntry newEntry;
+ newEntry.m_mt = currentEntry;
+ newEntry.m_count = 1;
+ m_histogram[countHistogramElements++] = newEntry;
+ }
+ }
+}
+
+// This is used by the devirtualization logic below, and by crossgen2 when producing the R2R image (to reduce the size
+// cost of carrying the type histogram)
+extern "C" DLLEXPORT CORINFO_CLASS_HANDLE WINAPI getLikelyClass(ICorJitInfo::PgoInstrumentationSchema* schema,
+ UINT32 countSchemaItems,
+ BYTE* pInstrumentationData,
+ int32_t ilOffset,
+ UINT32* pLikelihood,
+ UINT32* pNumberOfClasses)
+{
+ *pLikelihood = 0;
+ *pNumberOfClasses = 0;
+
+ if (schema == NULL)
+ return NULL;
+
+ for (COUNT_T i = 0; i < countSchemaItems; i++)
+ {
+ if (schema[i].ILOffset != (int32_t)ilOffset)
+ continue;
+
+ if ((schema[i].InstrumentationKind == ICorJitInfo::PgoInstrumentationKind::GetLikelyClass) &&
+ (schema[i].Count == 1))
+ {
+ *pNumberOfClasses = (UINT32)schema[i].Other >> 8;
+ *pLikelihood = (UINT32)(schema[i].Other && 0xFF);
+ INT_PTR result = *(INT_PTR*)(pInstrumentationData + schema[i + 1].Offset);
+ if (ICorJitInfo::IsUnknownTypeHandle(result))
+ return NULL;
+ else
+ return (CORINFO_CLASS_HANDLE)result;
+ }
+
+ if ((schema[i].InstrumentationKind == ICorJitInfo::PgoInstrumentationKind::TypeHandleHistogramCount) &&
+ (schema[i].Count == 1) && ((i + 1) < countSchemaItems) &&
+ (schema[i + 1].InstrumentationKind == ICorJitInfo::PgoInstrumentationKind::TypeHandleHistogramTypeHandle))
+ {
+ // Form a histogram
+ //
+ LikelyClassHistogram h(*(uint32_t*)(pInstrumentationData + schema[i].Offset),
+ (INT_PTR*)(pInstrumentationData + schema[i + 1].Offset), schema[i + 1].Count);
+
+ // Use histogram count as number of classes estimate
+ //
+ *pNumberOfClasses = (uint32_t)h.countHistogramElements + h.m_unknownTypes;
+
+ // Report back what we've learned
+ // (perhaps, use count to augment likelihood?)
+ //
+ switch (*pNumberOfClasses)
+ {
+ case 0:
+ {
+ return NULL;
+ }
+ break;
+
+ case 1:
+ {
+ if (ICorJitInfo::IsUnknownTypeHandle(h.HistogramEntryAt(0).m_mt))
+ {
+ return NULL;
+ }
+ *pLikelihood = 100;
+ return (CORINFO_CLASS_HANDLE)h.HistogramEntryAt(0).m_mt;
+ }
+ break;
+
+ case 2:
+ {
+ if ((h.HistogramEntryAt(0).m_count >= h.HistogramEntryAt(1).m_count) &&
+ !ICorJitInfo::IsUnknownTypeHandle(h.HistogramEntryAt(0).m_mt))
+ {
+ *pLikelihood = (100 * h.HistogramEntryAt(0).m_count) / h.m_totalCount;
+ return (CORINFO_CLASS_HANDLE)h.HistogramEntryAt(0).m_mt;
+ }
+ else if (!ICorJitInfo::IsUnknownTypeHandle(h.HistogramEntryAt(1).m_mt))
+ {
+ *pLikelihood = (100 * h.HistogramEntryAt(1).m_count) / h.m_totalCount;
+ return (CORINFO_CLASS_HANDLE)h.HistogramEntryAt(1).m_mt;
+ }
+ else
+ {
+ return NULL;
+ }
+ }
+ break;
+
+ default:
+ {
+ // Find maximum entry and return it
+ //
+ unsigned maxKnownIndex = 0;
+ unsigned maxKnownCount = 0;
+
+ for (unsigned m = 0; m < h.countHistogramElements; m++)
+ {
+ if ((h.HistogramEntryAt(m).m_count > maxKnownCount) &&
+ !ICorJitInfo::IsUnknownTypeHandle(h.HistogramEntryAt(m).m_mt))
+ {
+ maxKnownIndex = m;
+ maxKnownCount = h.HistogramEntryAt(m).m_count;
+ }
+ }
+
+ if (maxKnownCount > 0)
+ {
+ *pLikelihood = (100 * maxKnownCount) / h.m_totalCount;
+ ;
+ return (CORINFO_CLASS_HANDLE)h.HistogramEntryAt(maxKnownIndex).m_mt;
+ }
+
+ return NULL;
+ }
+ break;
+ }
+ }
+ }
+
+ // Failed to find histogram data for this method
+ //
+ return NULL;
+}
}
[UnmanagedCallersOnly]
- static CORINFO_CLASS_STRUCT_* _getLikelyClass(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftnHnd, CORINFO_CLASS_STRUCT_* baseHnd, uint ilOffset, uint* pLikelihood, uint* pNumberOfClasses)
- {
- var _this = GetThis(thisHandle);
- try
- {
- return _this.getLikelyClass(ftnHnd, baseHnd, ilOffset, ref *pLikelihood, ref *pNumberOfClasses);
- }
- catch (Exception ex)
- {
- *ppException = _this.AllocException(ex);
- return default;
- }
- }
-
- [UnmanagedCallersOnly]
static void _recordCallSite(IntPtr thisHandle, IntPtr* ppException, uint instrOffset, CORINFO_SIG_INFO* callSig, CORINFO_METHOD_STRUCT_* methodHandle)
{
var _this = GetThis(thisHandle);
static IntPtr GetUnmanagedCallbacks()
{
- void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 173);
+ void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 172);
callbacks[0] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, byte>)&_isJitIntrinsic;
callbacks[1] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, uint>)&_getMethodAttribs;
callbacks[164] = (delegate* unmanaged<IntPtr, IntPtr*, CorJitResult, void>)&_reportFatalError;
callbacks[165] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, PgoInstrumentationSchema**, uint*, byte**, HRESULT>)&_getPgoInstrumentationResults;
callbacks[166] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, PgoInstrumentationSchema*, uint, byte**, HRESULT>)&_allocPgoInstrumentationBySchema;
- callbacks[167] = (delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_CLASS_STRUCT_*, uint, uint*, uint*, CORINFO_CLASS_STRUCT_*>)&_getLikelyClass;
- callbacks[168] = (delegate* unmanaged<IntPtr, IntPtr*, uint, CORINFO_SIG_INFO*, CORINFO_METHOD_STRUCT_*, void>)&_recordCallSite;
- callbacks[169] = (delegate* unmanaged<IntPtr, IntPtr*, void*, void*, ushort, ushort, int, void>)&_recordRelocation;
- callbacks[170] = (delegate* unmanaged<IntPtr, IntPtr*, void*, ushort>)&_getRelocTypeHint;
- callbacks[171] = (delegate* unmanaged<IntPtr, IntPtr*, uint>)&_getExpectedTargetArchitecture;
- callbacks[172] = (delegate* unmanaged<IntPtr, IntPtr*, CORJIT_FLAGS*, uint, uint>)&_getJitFlags;
+ callbacks[167] = (delegate* unmanaged<IntPtr, IntPtr*, uint, CORINFO_SIG_INFO*, CORINFO_METHOD_STRUCT_*, void>)&_recordCallSite;
+ callbacks[168] = (delegate* unmanaged<IntPtr, IntPtr*, void*, void*, ushort, ushort, int, void>)&_recordRelocation;
+ callbacks[169] = (delegate* unmanaged<IntPtr, IntPtr*, void*, ushort>)&_getRelocTypeHint;
+ callbacks[170] = (delegate* unmanaged<IntPtr, IntPtr*, uint>)&_getExpectedTargetArchitecture;
+ callbacks[171] = (delegate* unmanaged<IntPtr, IntPtr*, CORJIT_FLAGS*, uint, uint>)&_getJitFlags;
return (IntPtr)callbacks;
}
[DllImport(JitLibrary)]
private extern static IntPtr getJit();
+ [DllImport(JitLibrary)]
+ private extern static IntPtr getLikelyClass(PgoInstrumentationSchema* schema, uint countSchemaItems, byte*pInstrumentationData, int ilOffset, out uint pLikelihood, out uint pNumberOfClasses);
+
[DllImport(JitSupportLibrary)]
private extern static IntPtr GetJitHost(IntPtr configProvider);
private CORINFO_MODULE_STRUCT_* _methodScope; // Needed to resolve CORINFO_EH_CLAUSE tokens
+ public static IEnumerable<PgoSchemaElem> ConvertTypeHandleHistogramsToCompactTypeHistogramFormat(PgoSchemaElem[] pgoData, CompilationModuleGroup compilationModuleGroup)
+ {
+ bool hasTypeHistogram = false;
+ foreach (var elem in pgoData)
+ {
+ if (elem.InstrumentationKind == PgoInstrumentationKind.TypeHandleHistogramCount)
+ {
+ // found histogram
+ hasTypeHistogram = true;
+ break;
+ }
+ }
+ if (!hasTypeHistogram)
+ {
+ foreach (var elem in pgoData)
+ {
+ yield return elem;
+ }
+ }
+ else
+ {
+ int currentObjectIndex = 0x1000000; // This needs to be a somewhat large non-zero number, so that the jit does not confuse it with NULL, or any other special value.
+ Dictionary<object, IntPtr> objectToHandle = new Dictionary<object, IntPtr>();
+ Dictionary<IntPtr, object> handleToObject = new Dictionary<IntPtr, object>();
+
+ ComputeJitPgoInstrumentationSchema(LocalObjectToHandle, pgoData, out var nativeSchema, out var instrumentationData);
+
+ for (int i = 0; i < (pgoData.Length); i++)
+ {
+ if (pgoData[i].InstrumentationKind == PgoInstrumentationKind.TypeHandleHistogramCount)
+ {
+ PgoSchemaElem? newElem = ComputeLikelyClass(i, handleToObject, nativeSchema, instrumentationData, compilationModuleGroup);
+ if (newElem.HasValue)
+ {
+ yield return newElem.Value;
+ }
+ i++; // The histogram is two entries long, so skip an extra entry
+ continue;
+ }
+ yield return pgoData[i];
+ }
+
+ IntPtr LocalObjectToHandle(object input)
+ {
+ if (objectToHandle.TryGetValue(input, out var result))
+ {
+ return result;
+ }
+ result = new IntPtr(currentObjectIndex++);
+ objectToHandle.Add(input, result);
+ handleToObject.Add(result, input);
+ return result;
+ }
+ }
+ }
+
+ private static PgoSchemaElem? ComputeLikelyClass(int index, Dictionary<IntPtr, object> handleToObject, PgoInstrumentationSchema[] nativeSchema, byte[] instrumentationData, CompilationModuleGroup compilationModuleGroup)
+ {
+ // getLikelyClass will use two entries from the native schema table. There must be at least two present to avoid ovberruning the buffer
+ if (index > (nativeSchema.Length - 2))
+ return null;
+
+ fixed(PgoInstrumentationSchema* pSchema = &nativeSchema[index])
+ {
+ fixed(byte* pInstrumentationData = &instrumentationData[0])
+ {
+ IntPtr classType = getLikelyClass(pSchema, 2, pInstrumentationData, nativeSchema[index].ILOffset, out uint likelihood, out uint numberOfClasses);
+
+ if (classType != IntPtr.Zero)
+ {
+ TypeDesc type = (TypeDesc)handleToObject[classType];
+#if READYTORUN
+ if (compilationModuleGroup.VersionsWithType(type))
+#endif
+ {
+ PgoSchemaElem likelyClassElem = new PgoSchemaElem();
+ likelyClassElem.InstrumentationKind = PgoInstrumentationKind.GetLikelyClass;
+ likelyClassElem.ILOffset = nativeSchema[index].ILOffset;
+ likelyClassElem.Count = 1;
+ likelyClassElem.Other = (int)(likelihood | (numberOfClasses << 8));
+ likelyClassElem.DataObject = new TypeSystemEntityOrUnknown[] { new TypeSystemEntityOrUnknown(type) };
+ return likelyClassElem;
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
private void CompileMethodInternal(IMethodNode methodCodeNodeNeedingCode, MethodIL methodIL)
{
// methodIL must not be null
MethodDesc decl = HandleToObject(info->virtualMethod);
Debug.Assert(!decl.HasInstantiation);
- if (info->context != null)
+ if ((info->context != null) && decl.OwningType.IsInterface)
{
TypeDesc ownerTypeDesc = typeFromContext(info->context);
if (decl.OwningType != ownerTypeDesc)
private CORINFO_MODULE_STRUCT_* embedModuleHandle(CORINFO_MODULE_STRUCT_* handle, ref void* ppIndirection)
{ throw new NotImplementedException("embedModuleHandle"); }
- private CORINFO_CLASS_STRUCT_* embedClassHandle(CORINFO_CLASS_STRUCT_* handle, ref void* ppIndirection)
- { throw new NotImplementedException("embedClassHandle"); }
private CORINFO_FIELD_STRUCT_* embedFieldHandle(CORINFO_FIELD_STRUCT_* handle, ref void* ppIndirection)
{ throw new NotImplementedException("embedFieldHandle"); }
return _compilation.ProfileData[method]?.SchemaData;
}
+ public static void ComputeJitPgoInstrumentationSchema(Func<object, IntPtr> objectToHandle, PgoSchemaElem[] pgoResultsSchemas, out PgoInstrumentationSchema[] nativeSchemas, out byte[] instrumentationData)
+ {
+ nativeSchemas = new PgoInstrumentationSchema[pgoResultsSchemas.Length];
+ MemoryStream msInstrumentationData = new MemoryStream();
+ BinaryWriter bwInstrumentationData = new BinaryWriter(msInstrumentationData);
+ for (int i = 0; i < nativeSchemas.Length; i++)
+ {
+ if ((bwInstrumentationData.BaseStream.Position % 8) == 4)
+ {
+ bwInstrumentationData.Write(0);
+ }
+
+ Debug.Assert((bwInstrumentationData.BaseStream.Position % 8) == 0);
+ nativeSchemas[i].Offset = new IntPtr(checked((int)bwInstrumentationData.BaseStream.Position));
+ nativeSchemas[i].ILOffset = pgoResultsSchemas[i].ILOffset;
+ nativeSchemas[i].Count = pgoResultsSchemas[i].Count;
+ nativeSchemas[i].Other = pgoResultsSchemas[i].Other;
+ nativeSchemas[i].InstrumentationKind = (PgoInstrumentationKind)pgoResultsSchemas[i].InstrumentationKind;
+
+ if (pgoResultsSchemas[i].DataObject == null)
+ {
+ bwInstrumentationData.Write(pgoResultsSchemas[i].DataLong);
+ }
+ else
+ {
+ object dataObject = pgoResultsSchemas[i].DataObject;
+ if (dataObject is int[] intArray)
+ {
+ foreach (int intVal in intArray)
+ bwInstrumentationData.Write(intVal);
+ }
+ else if (dataObject is long[] longArray)
+ {
+ foreach (long longVal in longArray)
+ bwInstrumentationData.Write(longVal);
+ }
+ else if (dataObject is TypeSystemEntityOrUnknown[] typeArray)
+ {
+ foreach (TypeSystemEntityOrUnknown typeVal in typeArray)
+ {
+ IntPtr ptrVal = IntPtr.Zero;
+ if (typeVal.AsType != null)
+ ptrVal = (IntPtr)objectToHandle(typeVal.AsType);
+ else
+ {
+ // The "Unknown types are the values from 1-33
+ ptrVal = new IntPtr((typeVal.AsUnknown % 32) + 1);
+ }
+
+ if (IntPtr.Size == 4)
+ bwInstrumentationData.Write((int)ptrVal);
+ else
+ bwInstrumentationData.Write((long)ptrVal);
+ }
+ }
+ }
+ }
+
+ bwInstrumentationData.Flush();
+
+ instrumentationData = msInstrumentationData.ToArray();
+ }
+
private HRESULT getPgoInstrumentationResults(CORINFO_METHOD_STRUCT_* ftnHnd, ref PgoInstrumentationSchema* pSchema, ref uint countSchemaItems, byte** pInstrumentationData)
{
MethodDesc methodDesc = HandleToObject(ftnHnd);
}
else
{
- PgoInstrumentationSchema[] nativeSchemas = new PgoInstrumentationSchema[pgoResultsSchemas.Length];
- MemoryStream msInstrumentationData = new MemoryStream();
- BinaryWriter bwInstrumentationData = new BinaryWriter(msInstrumentationData);
- for (int i = 0; i < nativeSchemas.Length; i++)
- {
- if ((bwInstrumentationData.BaseStream.Position % 8) == 4)
- {
- bwInstrumentationData.Write(0);
- }
-
- Debug.Assert((bwInstrumentationData.BaseStream.Position % 8) == 0);
- nativeSchemas[i].Offset = new IntPtr(checked((int)bwInstrumentationData.BaseStream.Position));
- nativeSchemas[i].ILOffset = pgoResultsSchemas[i].ILOffset;
- nativeSchemas[i].Count = pgoResultsSchemas[i].Count;
- nativeSchemas[i].Other = pgoResultsSchemas[i].Other;
- nativeSchemas[i].InstrumentationKind = (PgoInstrumentationKind)pgoResultsSchemas[i].InstrumentationKind;
-
- if (pgoResultsSchemas[i].DataObject == null)
- {
- bwInstrumentationData.Write(pgoResultsSchemas[i].DataLong);
- }
- else
- {
- object dataObject = pgoResultsSchemas[i].DataObject;
- if (dataObject is int[] intArray)
- {
- foreach (int intVal in intArray)
- bwInstrumentationData.Write(intVal);
- }
- else if (dataObject is long[] longArray)
- {
- foreach (long longVal in longArray)
- bwInstrumentationData.Write(longVal);
- }
- else if (dataObject is TypeSystemEntityOrUnknown[] typeArray)
- {
- foreach (TypeSystemEntityOrUnknown typeVal in typeArray)
- {
- IntPtr ptrVal = IntPtr.Zero;
- if (typeVal.AsType != null)
- ptrVal = (IntPtr)ObjectToHandle(typeVal.AsType);
- else
- {
- // The "Unknown types are the values from 1-33
- ptrVal = new IntPtr((typeVal.AsUnknown % 32) + 1);
- }
-
- if (IntPtr.Size == 4)
- bwInstrumentationData.Write((int)ptrVal);
- else
- bwInstrumentationData.Write((long)ptrVal);
- }
- }
- }
- }
+ ComputeJitPgoInstrumentationSchema(ObjectToHandle, pgoResultsSchemas, out var nativeSchemas, out var instrumentationData);
- bwInstrumentationData.Flush();
- pgoResults.pInstrumentationData = (byte*)GetPin(msInstrumentationData.ToArray());
+ pgoResults.pInstrumentationData = (byte*)GetPin(instrumentationData);
pgoResults.countSchemaItems = (uint)nativeSchemas.Length;
pgoResults.pSchema = (PgoInstrumentationSchema*)GetPin(nativeSchemas);
pgoResults.hr = HRESULT.S_OK;
void reportFatalError(CorJitResult result)
JITINTERFACE_HRESULT getPgoInstrumentationResults(CORINFO_METHOD_HANDLE ftnHnd, ICorJitInfo::PgoInstrumentationSchema** pSchema, uint32_t* pCountSchemaItems, uint8_t**pInstrumentationData)
JITINTERFACE_HRESULT allocPgoInstrumentationBySchema(CORINFO_METHOD_HANDLE ftnHnd, ICorJitInfo::PgoInstrumentationSchema* pSchema, uint32_t countSchemaItems, uint8_t** pInstrumentationData)
- CORINFO_CLASS_HANDLE getLikelyClass(CORINFO_METHOD_HANDLE ftnHnd, CORINFO_CLASS_HANDLE baseHnd, uint32_t ilOffset, uint32_t* pLikelihood, uint32_t* pNumberOfClasses)
void recordCallSite(uint32_t instrOffset, CORINFO_SIG_INFO* callSig, CORINFO_METHOD_HANDLE methodHandle)
void recordRelocation(void* location, void* target, uint16_t fRelocType, uint16_t slotNum, int32_t addlDelta)
uint16_t getRelocTypeHint(void* target)
Version = (DescriptorMin * 4) | None, // Version is encoded in the Other field of the schema
NumRuns = (DescriptorMin * 5) | None, // Number of runs is encoded in the Other field of the schema
EdgeIntCount = (DescriptorMin * 6) | FourByte, // 4 byte edge counter, using unsigned 4 byte int
+ GetLikelyClass = (DescriptorMin * 7) | TypeHandle, // Compressed get likely class data
}
public interface IPgoSchemaDataLoader<TType>
public override int GetHashCode() => _data.GetHashCode();
public override bool Equals(object obj) => obj is TypeSystemEntityOrUnknown other && other.Equals(this);
+
+ public override string ToString()
+ {
+ if (_data == null)
+ {
+ return "null";
+ }
+
+ if ((_data is int))
+ {
+ return $"UnknownType({(int)_data})";
+ }
+
+ return _data.ToString();
+ }
}
}
foreach (MethodDesc method in _instrumentationDataMethods)
{
pgoEmitter.Clear();
- PgoProcessor.EncodePgoData(_profileDataManager[method].SchemaData, pgoEmitter, false);
+ PgoProcessor.EncodePgoData(CorInfoImpl.ConvertTypeHandleHistogramsToCompactTypeHistogramFormat(_profileDataManager[method].SchemaData, factory.CompilationModuleGroup), pgoEmitter, false);
// In composite R2R format, always enforce owning type to let us share generic instantiations among modules
EcmaMethod typicalMethod = (EcmaMethod)method.GetTypicalMethodDefinition();
}
}
+ private CORINFO_CLASS_STRUCT_* embedClassHandle(CORINFO_CLASS_STRUCT_* handle, ref void* ppIndirection)
+ {
+ TypeDesc type = HandleToObject(handle);
+ if (!_compilation.CompilationModuleGroup.VersionsWithType(type))
+ throw new RequiresRuntimeJitException(type.ToString());
+
+ Import typeHandleImport = (Import)_compilation.SymbolNodeFactory.CreateReadyToRunHelper(ReadyToRunHelperId.TypeHandle, type);
+ Debug.Assert(typeHandleImport.RepresentsIndirectionCell);
+ ppIndirection = (void*)ObjectToHandle(typeHandleImport);
+ return null;
+ }
+
private void embedGenericHandle(ref CORINFO_RESOLVED_TOKEN pResolvedToken, bool fEmbedParent, ref CORINFO_GENERICHANDLE_RESULT pResult)
{
ceeInfoEmbedGenericHandle(ref pResolvedToken, fEmbedParent, ref pResult);
return 0;
}
- private CORINFO_CLASS_STRUCT_* getLikelyClass(CORINFO_METHOD_STRUCT_* ftnHnd, CORINFO_CLASS_STRUCT_* baseHnd, uint IlOffset, ref uint pLikelihood, ref uint pNumberOfClasses)
- {
- return null;
- }
-
private void getAddressOfPInvokeTarget(CORINFO_METHOD_STRUCT_* method, ref CORINFO_CONST_LOOKUP pLookup)
{
MethodDesc methodDesc = HandleToObject(method);
void (* reportFatalError)(void * thisHandle, CorInfoExceptionClass** ppException, CorJitResult result);
JITINTERFACE_HRESULT (* getPgoInstrumentationResults)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_METHOD_HANDLE ftnHnd, ICorJitInfo::PgoInstrumentationSchema** pSchema, uint32_t* pCountSchemaItems, uint8_t** pInstrumentationData);
JITINTERFACE_HRESULT (* allocPgoInstrumentationBySchema)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_METHOD_HANDLE ftnHnd, ICorJitInfo::PgoInstrumentationSchema* pSchema, uint32_t countSchemaItems, uint8_t** pInstrumentationData);
- CORINFO_CLASS_HANDLE (* getLikelyClass)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_METHOD_HANDLE ftnHnd, CORINFO_CLASS_HANDLE baseHnd, uint32_t ilOffset, uint32_t* pLikelihood, uint32_t* pNumberOfClasses);
void (* recordCallSite)(void * thisHandle, CorInfoExceptionClass** ppException, uint32_t instrOffset, CORINFO_SIG_INFO* callSig, CORINFO_METHOD_HANDLE methodHandle);
void (* recordRelocation)(void * thisHandle, CorInfoExceptionClass** ppException, void* location, void* target, uint16_t fRelocType, uint16_t slotNum, int32_t addlDelta);
uint16_t (* getRelocTypeHint)(void * thisHandle, CorInfoExceptionClass** ppException, void* target);
return temp;
}
- virtual CORINFO_CLASS_HANDLE getLikelyClass(
- CORINFO_METHOD_HANDLE ftnHnd,
- CORINFO_CLASS_HANDLE baseHnd,
- uint32_t ilOffset,
- uint32_t* pLikelihood,
- uint32_t* pNumberOfClasses)
-{
- CorInfoExceptionClass* pException = nullptr;
- CORINFO_CLASS_HANDLE temp = _callbacks->getLikelyClass(_thisHandle, &pException, ftnHnd, baseHnd, ilOffset, pLikelihood, pNumberOfClasses);
- if (pException != nullptr) throw pException;
- return temp;
-}
-
virtual void recordCallSite(
uint32_t instrOffset,
CORINFO_SIG_INFO* callSig,
return hr;
}
-CORINFO_CLASS_HANDLE CEEJitInfo::getLikelyClass(
- CORINFO_METHOD_HANDLE ftnHnd,
- CORINFO_CLASS_HANDLE baseHnd,
- uint32_t ilOffset,
- uint32_t * pLikelihood,
- uint32_t * pNumberOfClasses
-)
-{
- CONTRACTL {
- THROWS;
- GC_TRIGGERS;
- MODE_PREEMPTIVE;
- } CONTRACTL_END;
-
- CORINFO_CLASS_HANDLE result = NULL;
- *pLikelihood = 0;
- *pNumberOfClasses = 0;
-
- JIT_TO_EE_TRANSITION();
-
-#ifdef FEATURE_PGO
-
- // Query the PGO manager's per call site class profile.
- //
- MethodDesc* pMD = (MethodDesc*)ftnHnd;
- unsigned codeSize = 0;
- if (pMD->IsDynamicMethod())
- {
- unsigned stackSize, ehSize;
- CorInfoOptions options;
- DynamicResolver * pResolver = m_pMethodBeingCompiled->AsDynamicMethodDesc()->GetResolver();
- pResolver->GetCodeInfo(&codeSize, &stackSize, &options, &ehSize);
- }
- else if (pMD->HasILHeader())
- {
- COR_ILMETHOD_DECODER decoder(pMD->GetILHeader());
- codeSize = decoder.GetCodeSize();
- }
-
- result = PgoManager::getLikelyClass(pMD, codeSize, ilOffset, pLikelihood, pNumberOfClasses);
-
-#endif
-
- EE_TO_JIT_TRANSITION();
-
- return result;
-}
-
void CEEJitInfo::allocMem (
uint32_t hotCodeSize, /* IN */
uint32_t coldCodeSize, /* IN */
UNREACHABLE_RET(); // only called on derived class.
}
-CORINFO_CLASS_HANDLE CEEInfo::getLikelyClass(
- CORINFO_METHOD_HANDLE ftnHnd,
- CORINFO_CLASS_HANDLE baseHnd,
- uint32_t ilOffset,
- uint32_t* pLikelihood,
- uint32_t* pNumberOfCases
-)
-{
- LIMITED_METHOD_CONTRACT;
- UNREACHABLE_RET(); // only called on derived class.
-}
-
void CEEInfo::recordCallSite(
uint32_t instrOffset, /* IN */
CORINFO_SIG_INFO * callSig, /* IN */
uint8_t**pInstrumentationData /* OUT */
) override final;
- CORINFO_CLASS_HANDLE getLikelyClass(
- CORINFO_METHOD_HANDLE ftnHnd,
- CORINFO_CLASS_HANDLE baseHnd,
- uint32_t ilOffset,
- uint32_t * pLikelihood,
- uint32_t * pNumberOfClasses
- ) override final;
-
void recordCallSite(
uint32_t instrOffset, /* IN */
CORINFO_SIG_INFO * callSig, /* IN */
const char* const PgoManager::s_EightByte = "%u %u\n";
const char* const PgoManager::s_TypeHandle = "TypeHandle: %s\n";
-// Data item in class profile histogram
-//
-struct HistogramEntry
-{
- // Class that was observed at runtime
- INT_PTR m_mt; // This may be an "unknown type handle"
- // Number of observations in the table
- unsigned m_count;
-};
-
-// Summarizes a ClassProfile table by forming a Histogram
-//
-struct Histogram
-{
- Histogram(uint32_t histogramCount, INT_PTR* histogramEntries, unsigned entryCount);
-
- // Sum of counts from all entries in the histogram. This includes "unknown" entries which are not captured in m_histogram
- unsigned m_totalCount;
- // Rough guess at count of unknown types
- unsigned m_unknownTypes;
- // Histogram entries, in no particular order.
- // The first m_count of these will be valid.
- StackSArray<HistogramEntry> m_histogram;
-};
-
-Histogram::Histogram(uint32_t histogramCount, INT_PTR* histogramEntries, unsigned entryCount)
-{
- m_unknownTypes = 0;
- m_totalCount = 0;
- uint32_t unknownTypeHandleMask = 0;
-
- for (unsigned k = 0; k < entryCount; k++)
- {
- if (histogramEntries[k] == 0)
- {
- continue;
- }
-
- m_totalCount++;
-
- INT_PTR currentEntry = histogramEntries[k];
-
- bool found = false;
- unsigned h = 0;
- for(; h < m_histogram.GetCount(); h++)
- {
- if (m_histogram[h].m_mt == currentEntry)
- {
- m_histogram[h].m_count++;
- found = true;
- break;
- }
- }
-
- if (!found)
- {
- HistogramEntry newEntry;
- newEntry.m_mt = currentEntry;
- newEntry.m_count = 1;
- m_histogram.Append(newEntry);
- }
- }
-}
PtrSHash<PgoManager::Header, PgoManager::CodeAndMethodHash> PgoManager::s_textFormatPgoData;
CrstStatic PgoManager::s_pgoMgrLock;
{
INT_PTR* typeHandleValueAddress = (INT_PTR*)(found->GetData() + schema->Offset + iEntry * InstrumentationKindToSize(schema->InstrumentationKind));
INT_PTR initialTypeHandleValue = VolatileLoad(typeHandleValueAddress);
- if (((initialTypeHandleValue & 1) == 1) && !IsUnknownTypeHandle(initialTypeHandleValue))
+ if (((initialTypeHandleValue & 1) == 1) && !ICorJitInfo::IsUnknownTypeHandle(initialTypeHandleValue))
{
INT_PTR newPtr = 0;
TypeHandle th;
}
}
-// See if there is a class profile for this method at the indicated il Offset.
-// If so, return the most frequently seen class, along with the likelihood that
-// it was the class seen, and the total number of classes seen.
-//
-// Return NULL if there is no profile data to be found.
-//
-CORINFO_CLASS_HANDLE PgoManager::getLikelyClass(MethodDesc* pMD, unsigned ilSize, unsigned ilOffset, UINT32* pLikelihood, UINT32* pNumberOfClasses)
-{
- *pLikelihood = 0;
- *pNumberOfClasses = 0;
-
- NewArrayHolder<BYTE> allocatedData;
- ICorJitInfo::PgoInstrumentationSchema* schema;
- BYTE* pInstrumentationData;
- UINT32 cSchema;
- HRESULT hr = getPgoInstrumentationResults(pMD, &allocatedData, &schema, &cSchema, &pInstrumentationData);
-
- // Failed to find any sort of profile data for this method
- //
- if (FAILED(hr))
- {
- return NULL;
- }
-
- // TODO This logic should be moved to the JIT
- for (COUNT_T i = 0; i < cSchema; i++)
- {
- if (schema[i].ILOffset != (int32_t)ilOffset)
- continue;
-
- if ((schema[i].InstrumentationKind == ICorJitInfo::PgoInstrumentationKind::TypeHandleHistogramCount) &&
- (schema[i].Count == 1) &&
- ((i + 1) < cSchema) &&
- (schema[i + 1].InstrumentationKind == ICorJitInfo::PgoInstrumentationKind::TypeHandleHistogramTypeHandle))
- {
- // Form a histogram
- //
- Histogram h(*(uint32_t*)(pInstrumentationData + schema[i].Offset), (INT_PTR*)(pInstrumentationData + schema[i + 1].Offset), schema[i + 1].Count);
-
- // Use histogram count as number of classes estimate
- //
- *pNumberOfClasses = h.m_histogram.GetCount() + h.m_unknownTypes;
-
- // Report back what we've learned
- // (perhaps, use count to augment likelihood?)
- //
- switch (*pNumberOfClasses)
- {
- case 0:
- {
- return NULL;
- }
- break;
-
- case 1:
- {
- if (IsUnknownTypeHandle(h.m_histogram[0].m_mt))
- {
- return NULL;
- }
- *pLikelihood = 100;
- return (CORINFO_CLASS_HANDLE)h.m_histogram[0].m_mt;
- }
- break;
-
- case 2:
- {
- if ((h.m_histogram[0].m_count >= h.m_histogram[1].m_count) && !IsUnknownTypeHandle(h.m_histogram[0].m_mt))
- {
- *pLikelihood = (100 * h.m_histogram[0].m_count) / h.m_totalCount;
- return (CORINFO_CLASS_HANDLE)h.m_histogram[0].m_mt;
- }
- else if (!IsUnknownTypeHandle(h.m_histogram[1].m_mt))
- {
- *pLikelihood = (100 * h.m_histogram[1].m_count) / h.m_totalCount;
- return (CORINFO_CLASS_HANDLE)h.m_histogram[1].m_mt;
- }
- else
- {
- return NULL;
- }
- }
- break;
-
- default:
- {
- // Find maximum entry and return it
- //
- unsigned maxKnownIndex = 0;
- unsigned maxKnownCount = 0;
-
- for (unsigned m = 0; m < h.m_histogram.GetCount(); m++)
- {
- if ((h.m_histogram[m].m_count > maxKnownCount) && !IsUnknownTypeHandle(h.m_histogram[m].m_mt))
- {
- maxKnownIndex = m;
- maxKnownCount = h.m_histogram[m].m_count;
- }
- }
-
- if (maxKnownCount > 0)
- {
- *pLikelihood = (100 * maxKnownCount) / h.m_totalCount;;
- return (CORINFO_CLASS_HANDLE)h.m_histogram[maxKnownIndex].m_mt;
- }
-
- return NULL;
- }
- break;
- }
-
- }
- }
-
- // Failed to find histogram data for this method
- //
- return NULL;
-}
-
#else
// Stub version for !FEATURE_PGO builds
// Stub version for !FEATURE_PGO builds
//
-CORINFO_CLASS_HANDLE PgoManager::getLikelyClass(MethodDesc* pMD, unsigned ilSize, unsigned ilOffset, UINT32* pLikelihood, UINT32* pNumberOfClasses)
-{
- *pLikelihood = 0;
- *pNumberOfClasses = 0;
- return NULL;
-}
-
void PgoManager::CreatePgoManager(PgoManager** ppMgr, bool loaderAllocator)
{
*ppMgr = NULL;
static void CreatePgoManager(PgoManager* volatile* ppPgoManager, bool loaderAllocator);
- // Retrieve the most likely class for a particular call
- static CORINFO_CLASS_HANDLE getLikelyClass(MethodDesc* pMD, unsigned ilSize, unsigned ilOffset, UINT32* pLikelihood, UINT32* pNumberOfClasses);
-
// Verify address in bounds
static void VerifyAddress(void* address);
return pgoResults->m_hr;
}
-CORINFO_CLASS_HANDLE ZapInfo::getLikelyClass(
- CORINFO_METHOD_HANDLE ftnHnd,
- CORINFO_CLASS_HANDLE baseHnd,
- UINT32 ilOffset,
- UINT32* pLikelihood,
- UINT32* pNumberOfClasses)
-{
- return NULL;
-}
-
void ZapInfo::allocMem(
uint32_t hotCodeSize, /* IN */
uint32_t coldCodeSize, /* IN */