Skip to content

Commit

Permalink
Add support for delegate GDV and method-based vtable GDV (dotnet#68703)
Browse files Browse the repository at this point in the history
Add support for instrumenting delegate calls and vtable calls into method handle histograms. Use these histograms to do GDV for delegate calls and also support method-based GDV for vtable calls.

For instrumentation we now support class probes at interface call sites, method probes at delegate call sites and both class probes and method probes at vtable call sites. For vtable calls, when turned on, instrumentation produces both histograms as PGO data so that the JIT can later make the choice about what is the best form of guard to use at that site.

For guarding, there are some things to take into account. Delegate calls currently (practically) always point to precode, so this PR is just guarding on getFunctionFixedEntryPoint which returns the precode address, and this is generally quite cheap (same cost as class-based GDV). That's the case for delegates pointing to instance methods anyway, this PR does not support static methods yet -- those will be more expensive.

For vtable calls the runtime will backpatch the slots when tiering, so the JIT guards the address retrieved from the vtable against an indirection of the slot, which is slightly more expensive than a class-based guard.

Currently the instrumentation is enabled conditionally with COMPlus_JitDelegateProfiling=1 (for delegates) and COMPlus_JitVTableProfiling=1 (for vtable calls). Currently delegate profiling is turned on by default while vtable profiling is off by default.
  • Loading branch information
jakobbotsch authored Jun 17, 2022
1 parent 9dfdfbf commit cae8546
Show file tree
Hide file tree
Showing 37 changed files with 1,649 additions and 602 deletions.
9 changes: 5 additions & 4 deletions eng/pipelines/common/templates/runtimes/run-test-job.yml
Original file line number Diff line number Diff line change
Expand Up @@ -227,13 +227,13 @@ jobs:
timeoutInMinutes: 300
${{ else }}:
timeoutInMinutes: 200
${{ if in(parameters.testGroup, 'outerloop', 'jit-experimental', 'pgo', 'jit-cfg') }}:
${{ if in(parameters.testGroup, 'outerloop', 'jit-experimental', 'jit-cfg') }}:
timeoutInMinutes: 270
${{ if in(parameters.testGroup, 'gc-longrunning', 'gc-simulator') }}:
timeoutInMinutes: 480
${{ if in(parameters.testGroup, 'jitstress', 'jitstress-isas-arm', 'jitstressregs-x86', 'jitstressregs', 'jitstress2-jitstressregs', 'gcstress0x3-gcstress0xc', 'ilasm') }}:
timeoutInMinutes: 390
${{ if in(parameters.testGroup, 'gcstress-extra', 'r2r-extra', 'clrinterpreter') }}:
${{ if in(parameters.testGroup, 'gcstress-extra', 'r2r-extra', 'clrinterpreter', 'pgo') }}:
timeoutInMinutes: 510
${{ if eq(parameters.testGroup, 'jitstress-isas-x86') }}:
timeoutInMinutes: 960
Expand Down Expand Up @@ -397,7 +397,7 @@ jobs:
${{ if eq(parameters.runtimeFlavor, 'mono') }}:
# tiered compilation isn't done on mono yet
scenarios:
- normal
- normal
${{ elseif eq(variables['Build.Reason'], 'PullRequest') }}:
scenarios:
- no_tiered_compilation
Expand Down Expand Up @@ -545,7 +545,9 @@ jobs:
- defaultpgo
- dynamicpgo
- fullpgo
- fullpgo_methodprofiling
- fullpgo_random_gdv
- fullpgo_random_gdv_methodprofiling_only
- fullpgo_random_edge
- fullpgo_random_gdv_edge
${{ if in(parameters.testGroup, 'gc-longrunning') }}:
Expand All @@ -568,7 +570,6 @@ jobs:
- jitelthookenabled_tiered
${{ if in(parameters.testGroup, 'jit-experimental') }}:
scenarios:
- jitosr
- jitosr_stress
- jitosr_pgo
- jitosr_stress_random
Expand Down
2 changes: 1 addition & 1 deletion eng/pipelines/coreclr/libraries-pgo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ jobs:
helixQueueGroup: libraries
helixQueuesTemplate: /eng/pipelines/coreclr/templates/helix-queues-setup.yml
jobParameters:
timeoutInMinutes: 150
timeoutInMinutes: 600
testScope: innerloop
liveRuntimeBuildConfig: checked
dependsOnTestBuildConfiguration: Release
Expand Down
3 changes: 2 additions & 1 deletion eng/pipelines/libraries/run-test-job.yml
Original file line number Diff line number Diff line change
Expand Up @@ -173,10 +173,11 @@ jobs:
- defaultpgo
- dynamicpgo
- fullpgo
- fullpgo_methodprofiling
- fullpgo_random_gdv
- fullpgo_random_gdv_methodprofiling_only
- fullpgo_random_edge
- fullpgo_random_gdv_edge
- jitosr
- jitosr_stress
- jitosr_stress_random
- jitosr_pgo
Expand Down
7 changes: 6 additions & 1 deletion src/coreclr/inc/corinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -640,9 +640,14 @@ enum CorInfoHelpFunc
CORINFO_HELP_STACK_PROBE, // Probes each page of the allocated stack frame

CORINFO_HELP_PATCHPOINT, // Notify runtime that code has reached a patchpoint
CORINFO_HELP_PARTIAL_COMPILATION_PATCHPOINT, // Notify runtime that code has reached a part of the method that wasn't originally jitted.

CORINFO_HELP_CLASSPROFILE32, // Update 32-bit class profile for a call site
CORINFO_HELP_CLASSPROFILE64, // Update 64-bit class profile for a call site
CORINFO_HELP_PARTIAL_COMPILATION_PATCHPOINT, // Notify runtime that code has reached a part of the method that wasn't originally jitted.
CORINFO_HELP_DELEGATEPROFILE32, // Update 32-bit method profile for a delegate call site
CORINFO_HELP_DELEGATEPROFILE64, // Update 64-bit method profile for a delegate call site
CORINFO_HELP_VTABLEPROFILE32, // Update 32-bit method profile for a vtable call site
CORINFO_HELP_VTABLEPROFILE64, // Update 64-bit method profile for a vtable call site

CORINFO_HELP_VALIDATE_INDIRECT_CALL, // CFG: Validate function pointer
CORINFO_HELP_DISPATCH_INDIRECT_CALL, // CFG: Validate and dispatch to pointer
Expand Down
21 changes: 12 additions & 9 deletions src/coreclr/inc/corjit.h
Original file line number Diff line number Diff line change
Expand Up @@ -330,34 +330,36 @@ class ICorJitInfo : public ICorDynamicInfo

// Data structure for a single class probe using 32-bit count.
//
// CLASS_FLAG and INTERFACE_FLAG are placed into the Other field in the schema
// CLASS_FLAG, INTERFACE_FLAG and DELEGATE_FLAG are placed into the Other field in the schema.
// If CLASS_FLAG is set the handle table consists of type handles, and otherwise method handles.
//
// Count is the number of times a call was made at that call site.
//
// SIZE is the number of entries in the table.
//
// SAMPLE_INTERVAL must be >= SIZE. SAMPLE_INTERVAL / SIZE
// gives the average number of calls between table updates.
//
struct ClassProfile32
//
struct HandleHistogram32
{
enum
{
SIZE = 8,
SAMPLE_INTERVAL = 32,
CLASS_FLAG = 0x80000000,
INTERFACE_FLAG = 0x40000000,
OFFSET_MASK = 0x3FFFFFFF
DELEGATE_FLAG = 0x20000000,
OFFSET_MASK = 0x0FFFFFFF
};

uint32_t Count;
CORINFO_CLASS_HANDLE ClassTable[SIZE];
void* HandleTable[SIZE];
};

struct ClassProfile64
struct HandleHistogram64
{
uint64_t Count;
CORINFO_CLASS_HANDLE ClassTable[ClassProfile32::SIZE];
void* HandleTable[HandleHistogram32::SIZE];
};

enum class PgoInstrumentationKind
Expand Down Expand Up @@ -387,7 +389,7 @@ class ICorJitInfo : public ICorDynamicInfo
Done = None, // All instrumentation schemas must end with a record which is "Done"
BasicBlockIntCount = (DescriptorMin * 1) | FourByte, // basic block counter using unsigned 4 byte int
BasicBlockLongCount = (DescriptorMin * 1) | EightByte, // basic block counter using unsigned 8 byte int
HandleHistogramIntCount = (DescriptorMin * 2) | FourByte | AlignPointer, // 4 byte counter that is part of a type histogram. Aligned to match ClassProfile32's alignment.
HandleHistogramIntCount = (DescriptorMin * 2) | FourByte | AlignPointer, // 4 byte counter that is part of a type histogram. Aligned to match HandleHistogram32's alignment.
HandleHistogramLongCount = (DescriptorMin * 2) | EightByte, // 8 byte counter that is part of a type histogram
HandleHistogramTypes = (DescriptorMin * 3) | TypeHandle, // Histogram of type handles
HandleHistogramMethods = (DescriptorMin * 3) | MethodHandle, // Histogram of method handles
Expand All @@ -396,6 +398,7 @@ class ICorJitInfo : public ICorDynamicInfo
EdgeIntCount = (DescriptorMin * 6) | FourByte, // edge counter using unsigned 4 byte int
EdgeLongCount = (DescriptorMin * 6) | EightByte, // edge counter using unsigned 8 byte int
GetLikelyClass = (DescriptorMin * 7) | TypeHandle, // Compressed get likely class data
GetLikelyMethod = (DescriptorMin * 7) | MethodHandle, // Compressed get likely method data
};

struct PgoInstrumentationSchema
Expand All @@ -418,7 +421,7 @@ class ICorJitInfo : public ICorDynamicInfo
Sampling= 6, // PGO data derived from sampling
};

#define DEFAULT_UNKNOWN_TYPEHANDLE 1
#define DEFAULT_UNKNOWN_HANDLE 1
#define UNKNOWN_HANDLE_MIN 1
#define UNKNOWN_HANDLE_MAX 33

Expand Down
10 changes: 5 additions & 5 deletions src/coreclr/inc/jiteeversionguid.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ typedef const GUID *LPCGUID;
#define GUID_DEFINED
#endif // !GUID_DEFINED

constexpr GUID JITEEVersionIdentifier = { /* af5b6632-6fbe-4a2e-82d6-24487a138e4a */
0xaf5b6632,
0x6fbe,
0x4a2e,
{0x82, 0xd6, 0x24, 0x48, 0x7a, 0x13, 0x8e, 0x4a}
constexpr GUID JITEEVersionIdentifier = { /* f2faa5fc-a1ec-4244-aebb-5597bfd7153a */
0xf2faa5fc,
0xa1ec,
0x4244,
{0xae, 0xbb, 0x55, 0x97, 0xbf, 0xd7, 0x15, 0x3a}
};

//////////////////////////////////////////////////////////////////////////////////////////////////////////
Expand Down
7 changes: 6 additions & 1 deletion src/coreclr/inc/jithelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -328,9 +328,14 @@
#endif

JITHELPER(CORINFO_HELP_PATCHPOINT, JIT_Patchpoint, CORINFO_HELP_SIG_REG_ONLY)
JITHELPER(CORINFO_HELP_PARTIAL_COMPILATION_PATCHPOINT, JIT_PartialCompilationPatchpoint, CORINFO_HELP_SIG_REG_ONLY)

JITHELPER(CORINFO_HELP_CLASSPROFILE32, JIT_ClassProfile32, CORINFO_HELP_SIG_REG_ONLY)
JITHELPER(CORINFO_HELP_CLASSPROFILE64, JIT_ClassProfile64, CORINFO_HELP_SIG_REG_ONLY)
JITHELPER(CORINFO_HELP_PARTIAL_COMPILATION_PATCHPOINT, JIT_PartialCompilationPatchpoint, CORINFO_HELP_SIG_REG_ONLY)
JITHELPER(CORINFO_HELP_DELEGATEPROFILE32, JIT_DelegateProfile32, CORINFO_HELP_SIG_REG_ONLY)
JITHELPER(CORINFO_HELP_DELEGATEPROFILE64, JIT_DelegateProfile64, CORINFO_HELP_SIG_REG_ONLY)
JITHELPER(CORINFO_HELP_VTABLEPROFILE32, JIT_VTableProfile32, CORINFO_HELP_SIG_4_STACK)
JITHELPER(CORINFO_HELP_VTABLEPROFILE64, JIT_VTableProfile64, CORINFO_HELP_SIG_4_STACK)

#if defined(TARGET_AMD64) || defined(TARGET_ARM64)
JITHELPER(CORINFO_HELP_VALIDATE_INDIRECT_CALL, JIT_ValidateIndirectCall, CORINFO_HELP_SIG_REG_ONLY)
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/inc/readytorun.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

// Keep these in sync with src/coreclr/tools/Common/Internal/Runtime/ModuleHeaders.cs
#define READYTORUN_MAJOR_VERSION 0x0006
#define READYTORUN_MINOR_VERSION 0x0001
#define READYTORUN_MINOR_VERSION 0x0002

#define MINIMUM_READYTORUN_MAJOR_VERSION 0x006

Expand Down
1 change: 1 addition & 0 deletions src/coreclr/jit/ClrJit.PAL.exports
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
getJit
jitStartup
getLikelyClasses
getLikelyMethods
jitBuildString
1 change: 1 addition & 0 deletions src/coreclr/jit/ClrJit.exports
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ EXPORTS
getJit
jitStartup
getLikelyClasses
getLikelyMethods
jitBuildString
52 changes: 26 additions & 26 deletions src/coreclr/jit/block.h
Original file line number Diff line number Diff line change
Expand Up @@ -526,32 +526,32 @@ enum BasicBlockFlags : unsigned __int64

#endif // defined(FEATURE_EH_FUNCLETS) && defined(TARGET_ARM)

BBF_BACKWARD_JUMP = MAKE_BBFLAG(24), // BB is surrounded by a backward jump/switch arc
BBF_RETLESS_CALL = MAKE_BBFLAG(25), // BBJ_CALLFINALLY that will never return (and therefore, won't need a paired
// BBJ_ALWAYS); see isBBCallAlwaysPair().
BBF_LOOP_PREHEADER = MAKE_BBFLAG(26), // BB is a loop preheader block
BBF_COLD = MAKE_BBFLAG(27), // BB is cold

BBF_PROF_WEIGHT = MAKE_BBFLAG(28), // BB weight is computed from profile data
BBF_IS_LIR = MAKE_BBFLAG(29), // Set if the basic block contains LIR (as opposed to HIR)
BBF_KEEP_BBJ_ALWAYS = MAKE_BBFLAG(30), // A special BBJ_ALWAYS block, used by EH code generation. Keep the jump kind
// as BBJ_ALWAYS. Used for the paired BBJ_ALWAYS block following the
// BBJ_CALLFINALLY block, as well as, on x86, the final step block out of a
// finally.
BBF_CLONED_FINALLY_BEGIN = MAKE_BBFLAG(31), // First block of a cloned finally region

BBF_CLONED_FINALLY_END = MAKE_BBFLAG(32), // Last block of a cloned finally region
BBF_HAS_CALL = MAKE_BBFLAG(33), // BB contains a call
BBF_BACKWARD_JUMP = MAKE_BBFLAG(24), // BB is surrounded by a backward jump/switch arc
BBF_RETLESS_CALL = MAKE_BBFLAG(25), // BBJ_CALLFINALLY that will never return (and therefore, won't need a paired
// BBJ_ALWAYS); see isBBCallAlwaysPair().
BBF_LOOP_PREHEADER = MAKE_BBFLAG(26), // BB is a loop preheader block
BBF_COLD = MAKE_BBFLAG(27), // BB is cold

BBF_PROF_WEIGHT = MAKE_BBFLAG(28), // BB weight is computed from profile data
BBF_IS_LIR = MAKE_BBFLAG(29), // Set if the basic block contains LIR (as opposed to HIR)
BBF_KEEP_BBJ_ALWAYS = MAKE_BBFLAG(30), // A special BBJ_ALWAYS block, used by EH code generation. Keep the jump kind
// as BBJ_ALWAYS. Used for the paired BBJ_ALWAYS block following the
// BBJ_CALLFINALLY block, as well as, on x86, the final step block out of a
// finally.
BBF_CLONED_FINALLY_BEGIN = MAKE_BBFLAG(31), // First block of a cloned finally region

BBF_CLONED_FINALLY_END = MAKE_BBFLAG(32), // Last block of a cloned finally region
BBF_HAS_CALL = MAKE_BBFLAG(33), // BB contains a call
BBF_DOMINATED_BY_EXCEPTIONAL_ENTRY = MAKE_BBFLAG(34), // Block is dominated by exceptional entry.
BBF_BACKWARD_JUMP_TARGET = MAKE_BBFLAG(35), // Block is a target of a backward jump
BBF_BACKWARD_JUMP_TARGET = MAKE_BBFLAG(35), // Block is a target of a backward jump

BBF_PATCHPOINT = MAKE_BBFLAG(36), // Block is a patchpoint
BBF_HAS_CLASS_PROFILE = MAKE_BBFLAG(37), // BB contains a call needing a class profile
BBF_PARTIAL_COMPILATION_PATCHPOINT = MAKE_BBFLAG(38), // Block is a partial compilation patchpoint
BBF_HAS_ALIGN = MAKE_BBFLAG(39), // BB ends with 'align' instruction
BBF_TAILCALL_SUCCESSOR = MAKE_BBFLAG(40), // BB has pred that has potential tail call
BBF_PATCHPOINT = MAKE_BBFLAG(36), // Block is a patchpoint
BBF_HAS_HISTOGRAM_PROFILE = MAKE_BBFLAG(37), // BB contains a call needing a histogram profile
BBF_PARTIAL_COMPILATION_PATCHPOINT = MAKE_BBFLAG(38), // Block is a partial compilation patchpoint
BBF_HAS_ALIGN = MAKE_BBFLAG(39), // BB ends with 'align' instruction
BBF_TAILCALL_SUCCESSOR = MAKE_BBFLAG(40), // BB has pred that has potential tail call

BBF_BACKWARD_JUMP_SOURCE = MAKE_BBFLAG(41), // Block is a source of a backward jump
BBF_BACKWARD_JUMP_SOURCE = MAKE_BBFLAG(41), // Block is a source of a backward jump

// The following are sets of flags.

Expand Down Expand Up @@ -582,7 +582,7 @@ enum BasicBlockFlags : unsigned __int64
// TODO: Should BBF_RUN_RARELY be added to BBF_SPLIT_GAINED ?

BBF_SPLIT_GAINED = BBF_DONT_REMOVE | BBF_HAS_JMP | BBF_BACKWARD_JUMP | BBF_HAS_IDX_LEN | BBF_HAS_NEWARRAY | BBF_PROF_WEIGHT | \
BBF_HAS_NEWOBJ | BBF_KEEP_BBJ_ALWAYS | BBF_CLONED_FINALLY_END | BBF_HAS_NULLCHECK | BBF_HAS_CLASS_PROFILE,
BBF_HAS_NEWOBJ | BBF_KEEP_BBJ_ALWAYS | BBF_CLONED_FINALLY_END | BBF_HAS_NULLCHECK | BBF_HAS_HISTOGRAM_PROFILE,
};

inline constexpr BasicBlockFlags operator ~(BasicBlockFlags a)
Expand Down Expand Up @@ -918,8 +918,8 @@ struct BasicBlock : private LIR::Range
};

union {
unsigned bbStkTempsOut; // base# for output stack temps
int bbClassSchemaIndex; // schema index for class instrumentation
unsigned bbStkTempsOut; // base# for output stack temps
int bbHistogramSchemaIndex; // schema index for histogram instrumentation
};

#define MAX_XCPTN_INDEX (USHRT_MAX - 1)
Expand Down
8 changes: 4 additions & 4 deletions src/coreclr/jit/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6384,10 +6384,10 @@ int Compiler::compCompileHelper(CORINFO_MODULE_HANDLE classPtr,
compHndBBtabCount = 0;
compHndBBtabAllocCount = 0;

info.compNativeCodeSize = 0;
info.compTotalHotCodeSize = 0;
info.compTotalColdCodeSize = 0;
info.compClassProbeCount = 0;
info.compNativeCodeSize = 0;
info.compTotalHotCodeSize = 0;
info.compTotalColdCodeSize = 0;
info.compHandleHistogramProbeCount = 0;

compHasBackwardJump = false;
compHasBackwardJumpInHandler = false;
Expand Down
42 changes: 33 additions & 9 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -1821,6 +1821,7 @@ class Compiler
friend class MorphInitBlockHelper;
friend class MorphCopyBlockHelper;
friend class CallArgs;
friend class IndirectCallTransformer;

#ifdef FEATURE_HW_INTRINSICS
friend struct HWIntrinsicInfo;
Expand Down Expand Up @@ -3539,6 +3540,18 @@ class Compiler
bool isExplicitTailCall,
IL_OFFSET ilOffset = BAD_IL_OFFSET);

bool impConsiderCallProbe(GenTreeCall* call, IL_OFFSET ilOffset);

enum class GDVProbeType
{
None,
ClassProfile,
MethodProfile,
MethodAndClassProfile,
};

GDVProbeType compClassifyGDVProbeType(GenTreeCall* call);

//=========================================================================
// PROTECTED
//=========================================================================
Expand Down Expand Up @@ -5427,19 +5440,21 @@ class Compiler
bool fgGetProfileWeightForBasicBlock(IL_OFFSET offset, weight_t* weight);

Instrumentor* fgCountInstrumentor;
Instrumentor* fgClassInstrumentor;
Instrumentor* fgHistogramInstrumentor;

PhaseStatus fgPrepareToInstrumentMethod();
PhaseStatus fgInstrumentMethod();
PhaseStatus fgIncorporateProfileData();
void fgIncorporateBlockCounts();
void fgIncorporateEdgeCounts();

CORINFO_CLASS_HANDLE getRandomClass(ICorJitInfo::PgoInstrumentationSchema* schema,
UINT32 countSchemaItems,
BYTE* pInstrumentationData,
int32_t ilOffset,
CLRRandom* random);
void getRandomGDV(ICorJitInfo::PgoInstrumentationSchema* schema,
UINT32 countSchemaItems,
BYTE* pInstrumentationData,
int32_t ilOffset,
CLRRandom* random,
CORINFO_CLASS_HANDLE* classGuess,
CORINFO_METHOD_HANDLE* methodGuess);

public:
const char* fgPgoFailReason;
Expand Down Expand Up @@ -5679,6 +5694,7 @@ class Compiler
Statement* paramAssignmentInsertionPoint);
GenTree* fgMorphCall(GenTreeCall* call);
GenTree* fgExpandVirtualVtableCallTarget(GenTreeCall* call);

void fgMorphCallInline(GenTreeCall* call, InlineResult* result);
void fgMorphCallInlineHelper(GenTreeCall* call, InlineResult* result, InlineContext** createdContext);
#if DEBUG
Expand Down Expand Up @@ -6806,13 +6822,21 @@ class Compiler
optMethodFlags |= OMF_HAS_GUARDEDDEVIRT;
}

void pickGDV(GenTreeCall* call,
IL_OFFSET ilOffset,
bool isInterface,
CORINFO_CLASS_HANDLE* classGuess,
CORINFO_METHOD_HANDLE* methodGuess,
unsigned* likelihood);

void considerGuardedDevirtualization(GenTreeCall* call,
IL_OFFSET ilOffset,
bool isInterface,
CORINFO_METHOD_HANDLE baseMethod,
CORINFO_CLASS_HANDLE baseClass,
CORINFO_CONTEXT_HANDLE* pContextHandle DEBUGARG(CORINFO_CLASS_HANDLE objClass)
DEBUGARG(const char* objClassName));
CORINFO_CONTEXT_HANDLE* pContextHandle);

bool isCompatibleMethodGDV(GenTreeCall* call, CORINFO_METHOD_HANDLE gdvTarget);

void addGuardedDevirtualizationCandidate(GenTreeCall* call,
CORINFO_METHOD_HANDLE methodHandle,
Expand Down Expand Up @@ -9548,7 +9572,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
unsigned genCPU; // What CPU are we running on

// Number of class profile probes in this method
unsigned compClassProbeCount;
unsigned compHandleHistogramProbeCount;

} info;

Expand Down
Loading

0 comments on commit cae8546

Please sign in to comment.