Skip to content

Commit cae8546

Browse files
authored
Add support for delegate GDV and method-based vtable GDV (#68703)
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.
1 parent 9dfdfbf commit cae8546

37 files changed

+1649
-602
lines changed

eng/pipelines/common/templates/runtimes/run-test-job.yml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -227,13 +227,13 @@ jobs:
227227
timeoutInMinutes: 300
228228
${{ else }}:
229229
timeoutInMinutes: 200
230-
${{ if in(parameters.testGroup, 'outerloop', 'jit-experimental', 'pgo', 'jit-cfg') }}:
230+
${{ if in(parameters.testGroup, 'outerloop', 'jit-experimental', 'jit-cfg') }}:
231231
timeoutInMinutes: 270
232232
${{ if in(parameters.testGroup, 'gc-longrunning', 'gc-simulator') }}:
233233
timeoutInMinutes: 480
234234
${{ if in(parameters.testGroup, 'jitstress', 'jitstress-isas-arm', 'jitstressregs-x86', 'jitstressregs', 'jitstress2-jitstressregs', 'gcstress0x3-gcstress0xc', 'ilasm') }}:
235235
timeoutInMinutes: 390
236-
${{ if in(parameters.testGroup, 'gcstress-extra', 'r2r-extra', 'clrinterpreter') }}:
236+
${{ if in(parameters.testGroup, 'gcstress-extra', 'r2r-extra', 'clrinterpreter', 'pgo') }}:
237237
timeoutInMinutes: 510
238238
${{ if eq(parameters.testGroup, 'jitstress-isas-x86') }}:
239239
timeoutInMinutes: 960
@@ -397,7 +397,7 @@ jobs:
397397
${{ if eq(parameters.runtimeFlavor, 'mono') }}:
398398
# tiered compilation isn't done on mono yet
399399
scenarios:
400-
- normal
400+
- normal
401401
${{ elseif eq(variables['Build.Reason'], 'PullRequest') }}:
402402
scenarios:
403403
- no_tiered_compilation
@@ -545,7 +545,9 @@ jobs:
545545
- defaultpgo
546546
- dynamicpgo
547547
- fullpgo
548+
- fullpgo_methodprofiling
548549
- fullpgo_random_gdv
550+
- fullpgo_random_gdv_methodprofiling_only
549551
- fullpgo_random_edge
550552
- fullpgo_random_gdv_edge
551553
${{ if in(parameters.testGroup, 'gc-longrunning') }}:
@@ -568,7 +570,6 @@ jobs:
568570
- jitelthookenabled_tiered
569571
${{ if in(parameters.testGroup, 'jit-experimental') }}:
570572
scenarios:
571-
- jitosr
572573
- jitosr_stress
573574
- jitosr_pgo
574575
- jitosr_stress_random

eng/pipelines/coreclr/libraries-pgo.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ jobs:
4747
helixQueueGroup: libraries
4848
helixQueuesTemplate: /eng/pipelines/coreclr/templates/helix-queues-setup.yml
4949
jobParameters:
50-
timeoutInMinutes: 150
50+
timeoutInMinutes: 600
5151
testScope: innerloop
5252
liveRuntimeBuildConfig: checked
5353
dependsOnTestBuildConfiguration: Release

eng/pipelines/libraries/run-test-job.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,10 +173,11 @@ jobs:
173173
- defaultpgo
174174
- dynamicpgo
175175
- fullpgo
176+
- fullpgo_methodprofiling
176177
- fullpgo_random_gdv
178+
- fullpgo_random_gdv_methodprofiling_only
177179
- fullpgo_random_edge
178180
- fullpgo_random_gdv_edge
179-
- jitosr
180181
- jitosr_stress
181182
- jitosr_stress_random
182183
- jitosr_pgo

src/coreclr/inc/corinfo.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -640,9 +640,14 @@ enum CorInfoHelpFunc
640640
CORINFO_HELP_STACK_PROBE, // Probes each page of the allocated stack frame
641641

642642
CORINFO_HELP_PATCHPOINT, // Notify runtime that code has reached a patchpoint
643+
CORINFO_HELP_PARTIAL_COMPILATION_PATCHPOINT, // Notify runtime that code has reached a part of the method that wasn't originally jitted.
644+
643645
CORINFO_HELP_CLASSPROFILE32, // Update 32-bit class profile for a call site
644646
CORINFO_HELP_CLASSPROFILE64, // Update 64-bit class profile for a call site
645-
CORINFO_HELP_PARTIAL_COMPILATION_PATCHPOINT, // Notify runtime that code has reached a part of the method that wasn't originally jitted.
647+
CORINFO_HELP_DELEGATEPROFILE32, // Update 32-bit method profile for a delegate call site
648+
CORINFO_HELP_DELEGATEPROFILE64, // Update 64-bit method profile for a delegate call site
649+
CORINFO_HELP_VTABLEPROFILE32, // Update 32-bit method profile for a vtable call site
650+
CORINFO_HELP_VTABLEPROFILE64, // Update 64-bit method profile for a vtable call site
646651

647652
CORINFO_HELP_VALIDATE_INDIRECT_CALL, // CFG: Validate function pointer
648653
CORINFO_HELP_DISPATCH_INDIRECT_CALL, // CFG: Validate and dispatch to pointer

src/coreclr/inc/corjit.h

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -330,34 +330,36 @@ class ICorJitInfo : public ICorDynamicInfo
330330

331331
// Data structure for a single class probe using 32-bit count.
332332
//
333-
// CLASS_FLAG and INTERFACE_FLAG are placed into the Other field in the schema
333+
// CLASS_FLAG, INTERFACE_FLAG and DELEGATE_FLAG are placed into the Other field in the schema.
334+
// If CLASS_FLAG is set the handle table consists of type handles, and otherwise method handles.
334335
//
335336
// Count is the number of times a call was made at that call site.
336337
//
337338
// SIZE is the number of entries in the table.
338339
//
339340
// SAMPLE_INTERVAL must be >= SIZE. SAMPLE_INTERVAL / SIZE
340341
// gives the average number of calls between table updates.
341-
//
342-
struct ClassProfile32
342+
//
343+
struct HandleHistogram32
343344
{
344345
enum
345346
{
346347
SIZE = 8,
347348
SAMPLE_INTERVAL = 32,
348349
CLASS_FLAG = 0x80000000,
349350
INTERFACE_FLAG = 0x40000000,
350-
OFFSET_MASK = 0x3FFFFFFF
351+
DELEGATE_FLAG = 0x20000000,
352+
OFFSET_MASK = 0x0FFFFFFF
351353
};
352354

353355
uint32_t Count;
354-
CORINFO_CLASS_HANDLE ClassTable[SIZE];
356+
void* HandleTable[SIZE];
355357
};
356358

357-
struct ClassProfile64
359+
struct HandleHistogram64
358360
{
359361
uint64_t Count;
360-
CORINFO_CLASS_HANDLE ClassTable[ClassProfile32::SIZE];
362+
void* HandleTable[HandleHistogram32::SIZE];
361363
};
362364

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

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

421-
#define DEFAULT_UNKNOWN_TYPEHANDLE 1
424+
#define DEFAULT_UNKNOWN_HANDLE 1
422425
#define UNKNOWN_HANDLE_MIN 1
423426
#define UNKNOWN_HANDLE_MAX 33
424427

src/coreclr/inc/jiteeversionguid.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,11 @@ typedef const GUID *LPCGUID;
4343
#define GUID_DEFINED
4444
#endif // !GUID_DEFINED
4545

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

5353
//////////////////////////////////////////////////////////////////////////////////////////////////////////

src/coreclr/inc/jithelpers.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -328,9 +328,14 @@
328328
#endif
329329

330330
JITHELPER(CORINFO_HELP_PATCHPOINT, JIT_Patchpoint, CORINFO_HELP_SIG_REG_ONLY)
331+
JITHELPER(CORINFO_HELP_PARTIAL_COMPILATION_PATCHPOINT, JIT_PartialCompilationPatchpoint, CORINFO_HELP_SIG_REG_ONLY)
332+
331333
JITHELPER(CORINFO_HELP_CLASSPROFILE32, JIT_ClassProfile32, CORINFO_HELP_SIG_REG_ONLY)
332334
JITHELPER(CORINFO_HELP_CLASSPROFILE64, JIT_ClassProfile64, CORINFO_HELP_SIG_REG_ONLY)
333-
JITHELPER(CORINFO_HELP_PARTIAL_COMPILATION_PATCHPOINT, JIT_PartialCompilationPatchpoint, CORINFO_HELP_SIG_REG_ONLY)
335+
JITHELPER(CORINFO_HELP_DELEGATEPROFILE32, JIT_DelegateProfile32, CORINFO_HELP_SIG_REG_ONLY)
336+
JITHELPER(CORINFO_HELP_DELEGATEPROFILE64, JIT_DelegateProfile64, CORINFO_HELP_SIG_REG_ONLY)
337+
JITHELPER(CORINFO_HELP_VTABLEPROFILE32, JIT_VTableProfile32, CORINFO_HELP_SIG_4_STACK)
338+
JITHELPER(CORINFO_HELP_VTABLEPROFILE64, JIT_VTableProfile64, CORINFO_HELP_SIG_4_STACK)
334339

335340
#if defined(TARGET_AMD64) || defined(TARGET_ARM64)
336341
JITHELPER(CORINFO_HELP_VALIDATE_INDIRECT_CALL, JIT_ValidateIndirectCall, CORINFO_HELP_SIG_REG_ONLY)

src/coreclr/inc/readytorun.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
// Keep these in sync with src/coreclr/tools/Common/Internal/Runtime/ModuleHeaders.cs
1818
#define READYTORUN_MAJOR_VERSION 0x0006
19-
#define READYTORUN_MINOR_VERSION 0x0001
19+
#define READYTORUN_MINOR_VERSION 0x0002
2020

2121
#define MINIMUM_READYTORUN_MAJOR_VERSION 0x006
2222

src/coreclr/jit/ClrJit.PAL.exports

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
getJit
22
jitStartup
33
getLikelyClasses
4+
getLikelyMethods
45
jitBuildString

src/coreclr/jit/ClrJit.exports

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ EXPORTS
55
getJit
66
jitStartup
77
getLikelyClasses
8+
getLikelyMethods
89
jitBuildString

0 commit comments

Comments
 (0)