Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JIT: pgo/devirt diagnostic improvements #53247

Merged
merged 3 commits into from
May 26, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion src/coreclr/ToolBox/superpmi/mcs/verbdumpmap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@ void DumpMap(int index, MethodContext* mc)
bool hasEdgeProfile = false;
bool hasClassProfile = false;
bool hasLikelyClass = false;
if (mc->hasPgoData(hasEdgeProfile, hasClassProfile, hasLikelyClass))
ICorJitInfo::PgoSource pgoSource = ICorJitInfo::PgoSource::Unknown;
if (mc->hasPgoData(hasEdgeProfile, hasClassProfile, hasLikelyClass, pgoSource))
{
rawFlags |= 1ULL << (EXTRA_JIT_FLAGS::HAS_PGO);

Expand All @@ -108,6 +109,16 @@ void DumpMap(int index, MethodContext* mc)
{
rawFlags |= 1ULL << (EXTRA_JIT_FLAGS::HAS_LIKELY_CLASS);
}

if (pgoSource == ICorJitInfo::PgoSource::Static)
{
rawFlags |= 1ULL << (EXTRA_JIT_FLAGS::HAS_STATIC_PROFILE);
}

if (pgoSource == ICorJitInfo::PgoSource::Dynamic)
{
rawFlags |= 1ULL << (EXTRA_JIT_FLAGS::HAS_DYNAMIC_PROFILE);
}
}

printf(", %s\n", SpmiDumpHelper::DumpJitFlags(rawFlags).c_str());
Expand Down
13 changes: 12 additions & 1 deletion src/coreclr/ToolBox/superpmi/mcs/verbjitflags.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ int verbJitFlags::DoWork(const char* nameOfInput)
bool hasEdgeProfile = false;
bool hasClassProfile = false;
bool hasLikelyClass = false;
if (mc->hasPgoData(hasEdgeProfile, hasClassProfile, hasLikelyClass))
ICorJitInfo::PgoSource pgoSource = ICorJitInfo::PgoSource::Unknown;
if (mc->hasPgoData(hasEdgeProfile, hasClassProfile, hasLikelyClass, pgoSource))
{
rawFlags |= 1ULL << (EXTRA_JIT_FLAGS::HAS_PGO);

Expand All @@ -48,6 +49,16 @@ int verbJitFlags::DoWork(const char* nameOfInput)
{
rawFlags |= 1ULL << (EXTRA_JIT_FLAGS::HAS_LIKELY_CLASS);
}

if (pgoSource == ICorJitInfo::PgoSource::Static)
{
rawFlags |= 1ULL << (EXTRA_JIT_FLAGS::HAS_STATIC_PROFILE);
}

if (pgoSource == ICorJitInfo::PgoSource::Dynamic)
{
rawFlags |= 1ULL << (EXTRA_JIT_FLAGS::HAS_DYNAMIC_PROFILE);
}
}

int index = flagMap.GetIndex(rawFlags);
Expand Down
2 changes: 2 additions & 0 deletions src/coreclr/ToolBox/superpmi/superpmi-shared/agnostic.h
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,7 @@ struct Agnostic_GetPgoInstrumentationResults
DWORD data_index;
DWORD dataByteCount;
DWORD result;
DWORD pgoSource;
};

struct Agnostic_GetProfilingHandle
Expand Down Expand Up @@ -567,6 +568,7 @@ struct Agnostic_ResolveVirtualMethodResult
DWORDLONG devirtualizedMethod;
bool requiresInstMethodTableArg;
DWORDLONG exactContext;
DWORD detail;
};

struct ResolveTokenValue
Expand Down
23 changes: 15 additions & 8 deletions src/coreclr/ToolBox/superpmi/superpmi-shared/methodcontext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3175,14 +3175,15 @@ void MethodContext::recResolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO * info
result.devirtualizedMethod = CastHandle(info->devirtualizedMethod);
result.requiresInstMethodTableArg = info->requiresInstMethodTableArg;
result.exactContext = CastHandle(info->exactContext);
result.detail = (DWORD) info->detail;
ResolveVirtualMethod->Add(key, result);
DEBUG_REC(dmpResolveVirtualMethod(key, result));
}

void MethodContext::dmpResolveVirtualMethod(const Agnostic_ResolveVirtualMethodKey& key, const Agnostic_ResolveVirtualMethodResult& result)
{
printf("ResolveVirtualMethod virtMethod-%016llX, objClass-%016llX, context-%016llX :: returnValue-%d, devirtMethod-%016llX, requiresInstArg-%d, exactContext-%016llX",
key.virtualMethod, key.objClass, key.context, result.returnValue, result.devirtualizedMethod, result.requiresInstMethodTableArg, result.exactContext);
printf("ResolveVirtualMethod virtMethod-%016llX, objClass-%016llX, context-%016llX :: returnValue-%d, devirtMethod-%016llX, requiresInstArg-%d, exactContext-%016llX, detail-%d",
key.virtualMethod, key.objClass, key.context, result.returnValue, result.devirtualizedMethod, result.requiresInstMethodTableArg, result.exactContext, result.detail);
}

bool MethodContext::repResolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO * info)
Expand All @@ -3201,6 +3202,7 @@ bool MethodContext::repResolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO * info
info->devirtualizedMethod = (CORINFO_METHOD_HANDLE) result.devirtualizedMethod;
info->requiresInstMethodTableArg = result.requiresInstMethodTableArg;
info->exactContext = (CORINFO_CONTEXT_HANDLE) result.exactContext;
info->detail = (CORINFO_DEVIRTUALIZATION_DETAIL) result.detail;
return result.returnValue;
}

Expand Down Expand Up @@ -5543,6 +5545,7 @@ void MethodContext::recGetPgoInstrumentationResults(CORINFO_METHOD_HANDLE ftnHnd
ICorJitInfo::PgoInstrumentationSchema** pSchema,
UINT32* pCountSchemaItems,
BYTE** pInstrumentationData,
ICorJitInfo::PgoSource* pPgoSource,
HRESULT result)
{
if (GetPgoInstrumentationResults == nullptr)
Expand Down Expand Up @@ -5571,15 +5574,16 @@ void MethodContext::recGetPgoInstrumentationResults(CORINFO_METHOD_HANDLE ftnHnd
value.data_index = GetPgoInstrumentationResults->AddBuffer((unsigned char*)*pInstrumentationData, (unsigned)maxOffset);
value.dataByteCount = (unsigned)maxOffset;
value.result = (DWORD)result;
value.pgoSource = (DWORD)*pPgoSource;

DWORDLONG key = CastHandle(ftnHnd);
GetPgoInstrumentationResults->Add(key, value);
DEBUG_REC(dmpGetPgoInstrumentationResults(key, value));
}
void MethodContext::dmpGetPgoInstrumentationResults(DWORDLONG key, const Agnostic_GetPgoInstrumentationResults& value)
{
printf("GetPgoInstrumentationResults key ftn-%016llX, value res-%08X schemaCnt-%u profileBufSize-%u schema{",
key, value.result, value.countSchemaItems, value.dataByteCount);
printf("GetPgoInstrumentationResults key ftn-%016llX, value res-%08X schemaCnt-%u profileBufSize-%u source-%u schema{",
key, value.result, value.countSchemaItems, value.dataByteCount, value.pgoSource);

if (value.countSchemaItems > 0)
{
Expand Down Expand Up @@ -5636,7 +5640,8 @@ void MethodContext::dmpGetPgoInstrumentationResults(DWORDLONG key, const Agnosti
HRESULT MethodContext::repGetPgoInstrumentationResults(CORINFO_METHOD_HANDLE ftnHnd,
ICorJitInfo::PgoInstrumentationSchema** pSchema,
UINT32* pCountSchemaItems,
BYTE** pInstrumentationData)
BYTE** pInstrumentationData,
ICorJitInfo::PgoSource* pPgoSource)
{
DWORDLONG key = CastHandle(ftnHnd);
AssertMapAndKeyExist(GetPgoInstrumentationResults, key, ": key %016llX", key);
Expand All @@ -5646,6 +5651,7 @@ HRESULT MethodContext::repGetPgoInstrumentationResults(CORINFO_METHOD_HANDLE ftn

*pCountSchemaItems = (UINT32)tempValue.countSchemaItems;
*pInstrumentationData = (BYTE*)GetPgoInstrumentationResults->GetBuffer(tempValue.data_index);
*pPgoSource = (ICorJitInfo::PgoSource)tempValue.pgoSource;

ICorJitInfo::PgoInstrumentationSchema* pOutSchema = (ICorJitInfo::PgoInstrumentationSchema*)AllocJitTempBuffer(tempValue.countSchemaItems * sizeof(ICorJitInfo::PgoInstrumentationSchema));

Expand Down Expand Up @@ -6814,7 +6820,8 @@ int MethodContext::dumpMethodIdentityInfoToBuffer(char* buff, int len, bool igno
ICorJitInfo::PgoInstrumentationSchema* schema = nullptr;
UINT32 schemaCount = 0;
BYTE* schemaData = nullptr;
HRESULT pgoHR = repGetPgoInstrumentationResults(pInfo->ftn, &schema, &schemaCount, &schemaData);
ICorJitInfo::PgoSource pgoSource = ICorJitInfo::PgoSource::Unknown;
HRESULT pgoHR = repGetPgoInstrumentationResults(pInfo->ftn, &schema, &schemaCount, &schemaData, &pgoSource);

size_t minOffset = (size_t) ~0;
size_t maxOffset = 0;
Expand Down Expand Up @@ -6902,7 +6909,7 @@ int MethodContext::dumpMD5HashToBuffer(BYTE* pBuffer, int bufLen, char* hash, in
return m_hash.HashBuffer(pBuffer, bufLen, hash, hashLen);
}

bool MethodContext::hasPgoData(bool& hasEdgeProfile, bool& hasClassProfile, bool& hasLikelyClass)
bool MethodContext::hasPgoData(bool& hasEdgeProfile, bool& hasClassProfile, bool& hasLikelyClass, ICorJitInfo::PgoSource& pgoSource)
{
hasEdgeProfile = false;
hasClassProfile = false;
Expand All @@ -6919,7 +6926,7 @@ bool MethodContext::hasPgoData(bool& hasEdgeProfile, bool& hasClassProfile, bool
ICorJitInfo::PgoInstrumentationSchema* schema = nullptr;
UINT32 schemaCount = 0;
BYTE* schemaData = nullptr;
HRESULT pgoHR = repGetPgoInstrumentationResults(info.ftn, &schema, &schemaCount, &schemaData);
HRESULT pgoHR = repGetPgoInstrumentationResults(info.ftn, &schema, &schemaCount, &schemaData, &pgoSource);

if (SUCCEEDED(pgoHR))
{
Expand Down
12 changes: 8 additions & 4 deletions src/coreclr/ToolBox/superpmi/superpmi-shared/methodcontext.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ enum EXTRA_JIT_FLAGS
HAS_PGO = 63,
HAS_EDGE_PROFILE = 62,
HAS_CLASS_PROFILE = 61,
HAS_LIKELY_CLASS = 60
HAS_LIKELY_CLASS = 60,
HAS_STATIC_PROFILE = 59,
HAS_DYNAMIC_PROFILE = 58
};

// Asserts to catch changes in corjit flags definitions.
Expand All @@ -59,6 +61,8 @@ static_assert((int)EXTRA_JIT_FLAGS::HAS_PGO == (int)CORJIT_FLAGS::CorJitFlag::CO
static_assert((int)EXTRA_JIT_FLAGS::HAS_EDGE_PROFILE == (int)CORJIT_FLAGS::CorJitFlag::CORJIT_FLAG_UNUSED35, "Jit Flags Mismatch");
static_assert((int)EXTRA_JIT_FLAGS::HAS_CLASS_PROFILE == (int)CORJIT_FLAGS::CorJitFlag::CORJIT_FLAG_UNUSED34, "Jit Flags Mismatch");
static_assert((int)EXTRA_JIT_FLAGS::HAS_LIKELY_CLASS == (int)CORJIT_FLAGS::CorJitFlag::CORJIT_FLAG_UNUSED33, "Jit Flags Mismatch");
static_assert((int)EXTRA_JIT_FLAGS::HAS_STATIC_PROFILE == (int)CORJIT_FLAGS::CorJitFlag::CORJIT_FLAG_UNUSED32, "Jit Flags Mismatch");
static_assert((int)EXTRA_JIT_FLAGS::HAS_DYNAMIC_PROFILE == (int)CORJIT_FLAGS::CorJitFlag::CORJIT_FLAG_UNUSED31, "Jit Flags Mismatch");

class MethodContext
{
Expand Down Expand Up @@ -99,7 +103,7 @@ class MethodContext
int dumpMethodIdentityInfoToBuffer(char* buff, int len, bool ignoreMethodName = false, CORINFO_METHOD_INFO* optInfo = nullptr, unsigned optFlags = 0);
int dumpMethodMD5HashToBuffer(char* buff, int len, bool ignoreMethodName = false, CORINFO_METHOD_INFO* optInfo = nullptr, unsigned optFlags = 0);

bool hasPgoData(bool& hasEdgeProfile, bool& hasClassProfile, bool& hasLikelyClass);
bool hasPgoData(bool& hasEdgeProfile, bool& hasClassProfile, bool& hasLikelyClass, ICorJitInfo::PgoSource& pgoSource);

void recGlobalContext(const MethodContext& other);

Expand Down Expand Up @@ -699,9 +703,9 @@ class MethodContext
void dmpAllocPgoInstrumentationBySchema(DWORDLONG key, const Agnostic_AllocPgoInstrumentationBySchema& value);
HRESULT repAllocPgoInstrumentationBySchema(CORINFO_METHOD_HANDLE ftnHnd, ICorJitInfo::PgoInstrumentationSchema* pSchema, UINT32 countSchemaItems, BYTE** pInstrumentationData);

void recGetPgoInstrumentationResults(CORINFO_METHOD_HANDLE ftnHnd, ICorJitInfo::PgoInstrumentationSchema** pSchema, UINT32* pCountSchemaItems, BYTE** pInstrumentationData, HRESULT result);
void recGetPgoInstrumentationResults(CORINFO_METHOD_HANDLE ftnHnd, ICorJitInfo::PgoInstrumentationSchema** pSchema, UINT32* pCountSchemaItems, BYTE** pInstrumentationData, ICorJitInfo::PgoSource* pPgoSource, HRESULT result);
void dmpGetPgoInstrumentationResults(DWORDLONG key, const Agnostic_GetPgoInstrumentationResults& value);
HRESULT repGetPgoInstrumentationResults(CORINFO_METHOD_HANDLE ftnHnd, ICorJitInfo::PgoInstrumentationSchema** pSchema, UINT32* pCountSchemaItems, BYTE** pInstrumentationData);
HRESULT repGetPgoInstrumentationResults(CORINFO_METHOD_HANDLE ftnHnd, ICorJitInfo::PgoInstrumentationSchema** pSchema, UINT32* pCountSchemaItems, BYTE** pInstrumentationData, ICorJitInfo::PgoSource* pPgoSource);

void recMergeClasses(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2, CORINFO_CLASS_HANDLE result);
void dmpMergeClasses(DLDL key, DWORDLONG value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2067,11 +2067,12 @@ HRESULT interceptor_ICJI::allocPgoInstrumentationBySchema(CORINFO_METHOD_HANDLE
HRESULT interceptor_ICJI::getPgoInstrumentationResults(CORINFO_METHOD_HANDLE ftnHnd,
PgoInstrumentationSchema **pSchema, // pointer to the schema table which describes the instrumentation results (pointer will not remain valid after jit completes)
uint32_t * pCountSchemaItems, // pointer to the count schema items
uint8_t ** pInstrumentationData) // pointer to the actual instrumentation data (pointer will not remain valid after jit completes)
uint8_t ** pInstrumentationData, // pointer to the actual instrumentation data (pointer will not remain valid after jit completes)
PgoSource* pPgoSource)
{
mc->cr->AddCall("getPgoInstrumentationResults");
HRESULT temp = original_ICorJitInfo->getPgoInstrumentationResults(ftnHnd, pSchema, pCountSchemaItems, pInstrumentationData);
mc->recGetPgoInstrumentationResults(ftnHnd, pSchema, pCountSchemaItems, pInstrumentationData, temp);
HRESULT temp = original_ICorJitInfo->getPgoInstrumentationResults(ftnHnd, pSchema, pCountSchemaItems, pInstrumentationData, pPgoSource);
mc->recGetPgoInstrumentationResults(ftnHnd, pSchema, pCountSchemaItems, pInstrumentationData, pPgoSource, temp);
return temp;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1329,10 +1329,11 @@ JITINTERFACE_HRESULT interceptor_ICJI::getPgoInstrumentationResults(
CORINFO_METHOD_HANDLE ftnHnd,
ICorJitInfo::PgoInstrumentationSchema** pSchema,
uint32_t* pCountSchemaItems,
uint8_t** pInstrumentationData)
uint8_t** pInstrumentationData,
ICorJitInfo::PgoSource* pgoSource)
{
mcs->AddCall("getPgoInstrumentationResults");
return original_ICorJitInfo->getPgoInstrumentationResults(ftnHnd, pSchema, pCountSchemaItems, pInstrumentationData);
return original_ICorJitInfo->getPgoInstrumentationResults(ftnHnd, pSchema, pCountSchemaItems, pInstrumentationData, pgoSource);
}

JITINTERFACE_HRESULT interceptor_ICJI::allocPgoInstrumentationBySchema(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1164,9 +1164,10 @@ JITINTERFACE_HRESULT interceptor_ICJI::getPgoInstrumentationResults(
CORINFO_METHOD_HANDLE ftnHnd,
ICorJitInfo::PgoInstrumentationSchema** pSchema,
uint32_t* pCountSchemaItems,
uint8_t** pInstrumentationData)
uint8_t** pInstrumentationData,
ICorJitInfo::PgoSource* pgoSource)
{
return original_ICorJitInfo->getPgoInstrumentationResults(ftnHnd, pSchema, pCountSchemaItems, pInstrumentationData);
return original_ICorJitInfo->getPgoInstrumentationResults(ftnHnd, pSchema, pCountSchemaItems, pInstrumentationData, pgoSource);
}

JITINTERFACE_HRESULT interceptor_ICJI::allocPgoInstrumentationBySchema(
Expand Down
6 changes: 4 additions & 2 deletions src/coreclr/ToolBox/superpmi/superpmi/icorjitinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1815,10 +1815,12 @@ HRESULT MyICJI::allocPgoInstrumentationBySchema(CORINFO_METHOD_HANDLE ftnHnd,
HRESULT MyICJI::getPgoInstrumentationResults(CORINFO_METHOD_HANDLE ftnHnd,
PgoInstrumentationSchema **pSchema, // pointer to the schema table which describes the instrumentation results (pointer will not remain valid after jit completes)
uint32_t * pCountSchemaItems, // pointer to the count schema items
uint8_t ** pInstrumentationData) // pointer to the actual instrumentation data (pointer will not remain valid after jit completes)
uint8_t ** pInstrumentationData, // pointer to the actual instrumentation data (pointer will not remain valid after jit completes)
PgoSource* pPgoSource)

{
jitInstance->mc->cr->AddCall("getPgoInstrumentationResults");
return jitInstance->mc->repGetPgoInstrumentationResults(ftnHnd, pSchema, pCountSchemaItems, pInstrumentationData);
return jitInstance->mc->repGetPgoInstrumentationResults(ftnHnd, pSchema, pCountSchemaItems, pInstrumentationData, pPgoSource);
}

// Associates a native call site, identified by its offset in the native code stream, with
Expand Down
23 changes: 20 additions & 3 deletions src/coreclr/inc/corinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -1601,6 +1601,21 @@ struct CORINFO_CALL_INFO
bool wrapperDelegateInvoke;
};

enum CORINFO_DEVIRTUALIZATION_DETAIL
{
CORINFO_DEVIRTUALIZATION_UNKNOWN, // no details available
CORINFO_DEVIRTUALIZATION_SUCCESS, // devirtualization was successful
CORINFO_DEVIRTUALIZATION_FAILED_CANON, // object class was canonical
CORINFO_DEVIRTUALIZATION_FAILED_COM, // object class was com
CORINFO_DEVIRTUALIZATION_FAILED_CAST, // object class could not be cast to interface class
CORINFO_DEVIRTUALIZATION_FAILED_LOOKUP, // interface method could not be found
CORINFO_DEVIRTUALIZATION_FAILED_DIM, // interface method was default interface method
CORINFO_DEVIRTUALIZATION_FAILED_SUBCLASS, // object not subclass of base class
CORINFO_DEVIRTUALIZATION_FAILED_SLOT, // virtual method installed via explicit override
CORINFO_DEVIRTUALIZATION_FAILED_BUBBLE, // devirtualization crossed version bubble
CORINFO_DEVIRTUALIZATION_COUNT, // sentinel for maximum value
};

struct CORINFO_DEVIRTUALIZATION_INFO
{
//
Expand All @@ -1616,10 +1631,12 @@ struct CORINFO_DEVIRTUALIZATION_INFO
// invariant is `resolveVirtualMethod(...) == (devirtualizedMethod != nullptr)`.
// - requiresInstMethodTableArg is set to TRUE if the devirtualized method requires a type handle arg.
// - exactContext is set to wrapped CORINFO_CLASS_HANDLE of devirt'ed method table.
// - details on the computation done by the jit host
//
CORINFO_METHOD_HANDLE devirtualizedMethod;
bool requiresInstMethodTableArg;
CORINFO_CONTEXT_HANDLE exactContext;
CORINFO_METHOD_HANDLE devirtualizedMethod;
bool requiresInstMethodTableArg;
CORINFO_CONTEXT_HANDLE exactContext;
CORINFO_DEVIRTUALIZATION_DETAIL detail;
};

//----------------------------------------------------------------------------
Expand Down
14 changes: 13 additions & 1 deletion src/coreclr/inc/corjit.h
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,17 @@ class ICorJitInfo : public ICorDynamicInfo
int32_t Other;
};

enum class PgoSource
{
Unknown = 0, // PGO data source unknown
Static = 1, // PGO data comes from embedded R2R profile data
Dynamic = 2, // PGO data comes from current run
Blend = 3, // PGO data comes from blend of prior runs and current run
Text = 4, // PGO data comes from text file
IBC = 5, // PGO data from classic IBC
Sampling= 6, // PGO data derived from sampling
};

#define DEFAULT_UNKNOWN_TYPEHANDLE 1
#define UNKNOWN_TYPEHANDLE_MIN 1
#define UNKNOWN_TYPEHANDLE_MAX 33
Expand All @@ -404,8 +415,9 @@ class ICorJitInfo : public ICorDynamicInfo
PgoInstrumentationSchema **pSchema, // OUT: pointer to the schema table (array) which describes the instrumentation results
// (pointer will not remain valid after jit completes).
uint32_t * pCountSchemaItems, // OUT: pointer to the count of schema items in `pSchema` array.
uint8_t ** pInstrumentationData // OUT: `*pInstrumentationData` is set to the address of the instrumentation data
uint8_t ** pInstrumentationData, // OUT: `*pInstrumentationData` is set to the address of the instrumentation data
// (pointer will not remain valid after jit completes).
PgoSource * pPgoSource // OUT: value describing source of pgo data
) = 0;

// Allocate a profile buffer for use in the current process
Expand Down
Loading