Skip to content

Commit 26ad0a8

Browse files
committed
Add support for storing method handle histograms in profiles
Allow method handle histograms in .mibc files and in the PGO text format. Contributes to dotnet#44610.
1 parent a4503d6 commit 26ad0a8

File tree

21 files changed

+477
-156
lines changed

21 files changed

+477
-156
lines changed

src/coreclr/inc/corjit.h

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,7 @@ class ICorJitInfo : public ICorDynamicInfo
368368
FourByte = 1,
369369
EightByte = 2,
370370
TypeHandle = 3,
371+
MethodHandle = 4,
371372

372373
// Mask of all schema data types
373374
MarshalMask = 0xF,
@@ -385,9 +386,10 @@ class ICorJitInfo : public ICorDynamicInfo
385386
Done = None, // All instrumentation schemas must end with a record which is "Done"
386387
BasicBlockIntCount = (DescriptorMin * 1) | FourByte, // basic block counter using unsigned 4 byte int
387388
BasicBlockLongCount = (DescriptorMin * 1) | EightByte, // basic block counter using unsigned 8 byte int
388-
TypeHandleHistogramIntCount = (DescriptorMin * 2) | FourByte | AlignPointer, // 4 byte counter that is part of a type histogram. Aligned to match ClassProfile32's alignment.
389-
TypeHandleHistogramLongCount = (DescriptorMin * 2) | EightByte, // 8 byte counter that is part of a type histogram
390-
TypeHandleHistogramTypeHandle = (DescriptorMin * 3) | TypeHandle, // TypeHandle that is part of a type histogram
389+
HandleHistogramIntCount = (DescriptorMin * 2) | FourByte | AlignPointer, // 4 byte counter that is part of a type histogram. Aligned to match ClassProfile32's alignment.
390+
HandleHistogramLongCount = (DescriptorMin * 2) | EightByte, // 8 byte counter that is part of a type histogram
391+
HandleHistogramTypes = (DescriptorMin * 3) | TypeHandle, // Histogram of type handles
392+
HandleHistogramMethods = (DescriptorMin * 3) | MethodHandle, // Histogram of method handles
391393
Version = (DescriptorMin * 4) | None, // Version is encoded in the Other field of the schema
392394
NumRuns = (DescriptorMin * 5) | None, // Number of runs is encoded in the Other field of the schema
393395
EdgeIntCount = (DescriptorMin * 6) | FourByte, // edge counter using unsigned 4 byte int
@@ -416,12 +418,12 @@ class ICorJitInfo : public ICorDynamicInfo
416418
};
417419

418420
#define DEFAULT_UNKNOWN_TYPEHANDLE 1
419-
#define UNKNOWN_TYPEHANDLE_MIN 1
420-
#define UNKNOWN_TYPEHANDLE_MAX 33
421+
#define UNKNOWN_HANDLE_MIN 1
422+
#define UNKNOWN_HANDLE_MAX 33
421423

422-
static inline bool IsUnknownTypeHandle(intptr_t typeHandle)
424+
static inline bool IsUnknownHandle(intptr_t typeHandle)
423425
{
424-
return ((typeHandle >= UNKNOWN_TYPEHANDLE_MIN) && (typeHandle <= UNKNOWN_TYPEHANDLE_MAX));
426+
return ((typeHandle >= UNKNOWN_HANDLE_MIN) && (typeHandle <= UNKNOWN_HANDLE_MAX));
425427
}
426428

427429
// get profile information to be used for optimizing a current method. The format

src/coreclr/inc/pgo_formatprocessing.h

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,7 @@
88

99
#ifdef FEATURE_PGO
1010

11-
inline bool AddTypeHandleToUnknownTypeHandleMask(INT_PTR typeHandle, uint32_t *unknownTypeHandleMask)
12-
{
13-
uint32_t bitMask = (uint32_t)(1 << (typeHandle - UNKNOWN_TYPEHANDLE_MIN));
14-
bool result = (bitMask & *unknownTypeHandleMask) == 0;
15-
*unknownTypeHandleMask |= bitMask;
16-
return result;
17-
}
18-
19-
inline INT_PTR HashToPgoUnknownTypeHandle(uint32_t hash)
11+
inline INT_PTR HashToPgoUnknownHandle(uint32_t hash)
2012
{
2113
// Map from a 32bit hash to the 32 different unknown type handle values
2214
return (hash & 0x1F) + 1;
@@ -53,6 +45,7 @@ inline uint32_t InstrumentationKindToSize(ICorJitInfo::PgoInstrumentationKind ki
5345
case ICorJitInfo::PgoInstrumentationKind::EightByte:
5446
return 8;
5547
case ICorJitInfo::PgoInstrumentationKind::TypeHandle:
48+
case ICorJitInfo::PgoInstrumentationKind::MethodHandle:
5649
return TARGET_POINTER_SIZE;
5750
default:
5851
_ASSERTE(FALSE);
@@ -242,6 +235,7 @@ bool ReadInstrumentationData(const uint8_t *pByte, size_t cbDataMax, SchemaAndDa
242235
bool done = false;
243236
int64_t lastDataValue = 0;
244237
int64_t lastTypeDataValue = 0;
238+
int64_t lastMethodDataValue = 0;
245239
int32_t dataCountToRead = 0;
246240

247241
ReadCompressedInts(pByte, cbDataMax, [&](int64_t curValue)
@@ -267,8 +261,16 @@ bool ReadInstrumentationData(const uint8_t *pByte, size_t cbDataMax, SchemaAndDa
267261
return false;
268262
}
269263
break;
264+
case ICorJitInfo::PgoInstrumentationKind::MethodHandle:
265+
lastMethodDataValue += curValue;
266+
267+
if (!handler(schemaHandler.GetSchema(), lastMethodDataValue, schemaHandler.GetSchema().Count - dataCountToRead))
268+
{
269+
return false;
270+
}
271+
break;
270272
default:
271-
assert(false);
273+
assert(!"Unexpected PGO instrumentation data type");
272274
break;
273275
}
274276
dataCountToRead--;

src/coreclr/jit/compiler.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6264,6 +6264,7 @@ class Compiler
62646264
UINT32 fgPgoBlockCounts;
62656265
UINT32 fgPgoEdgeCounts;
62666266
UINT32 fgPgoClassProfiles;
6267+
UINT32 fgPgoMethodProfiles;
62676268
unsigned fgPgoInlineePgo;
62686269
unsigned fgPgoInlineeNoPgo;
62696270
unsigned fgPgoInlineeNoPgoSingleBlock;

src/coreclr/jit/fgbasic.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ void Compiler::fgInit()
180180
fgPgoBlockCounts = 0;
181181
fgPgoEdgeCounts = 0;
182182
fgPgoClassProfiles = 0;
183+
fgPgoMethodProfiles = 0;
183184
fgPgoInlineePgo = 0;
184185
fgPgoInlineeNoPgo = 0;
185186
fgPgoInlineeNoPgoSingleBlock = 0;

src/coreclr/jit/fgprofile.cpp

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1496,15 +1496,15 @@ class BuildClassProbeSchemaGen
14961496
}
14971497

14981498
schemaElem.InstrumentationKind = JitConfig.JitCollect64BitCounts()
1499-
? ICorJitInfo::PgoInstrumentationKind::TypeHandleHistogramLongCount
1500-
: ICorJitInfo::PgoInstrumentationKind::TypeHandleHistogramIntCount;
1499+
? ICorJitInfo::PgoInstrumentationKind::HandleHistogramLongCount
1500+
: ICorJitInfo::PgoInstrumentationKind::HandleHistogramIntCount;
15011501
schemaElem.ILOffset = (int32_t)call->gtClassProfileCandidateInfo->ilOffset;
15021502
schemaElem.Offset = 0;
15031503

15041504
m_schema.push_back(schemaElem);
15051505

15061506
// Re-using ILOffset and Other fields from schema item for TypeHandleHistogramCount
1507-
schemaElem.InstrumentationKind = ICorJitInfo::PgoInstrumentationKind::TypeHandleHistogramTypeHandle;
1507+
schemaElem.InstrumentationKind = ICorJitInfo::PgoInstrumentationKind::HandleHistogramTypes;
15081508
schemaElem.Count = ICorJitInfo::ClassProfile32::SIZE;
15091509
m_schema.push_back(schemaElem);
15101510

@@ -1551,9 +1551,9 @@ class ClassProbeInserter
15511551
//
15521552
assert(m_schema[*m_currentSchemaIndex].ILOffset == (int32_t)call->gtClassProfileCandidateInfo->ilOffset);
15531553
bool is32 = m_schema[*m_currentSchemaIndex].InstrumentationKind ==
1554-
ICorJitInfo::PgoInstrumentationKind::TypeHandleHistogramIntCount;
1554+
ICorJitInfo::PgoInstrumentationKind::HandleHistogramIntCount;
15551555
bool is64 = m_schema[*m_currentSchemaIndex].InstrumentationKind ==
1556-
ICorJitInfo::PgoInstrumentationKind::TypeHandleHistogramLongCount;
1556+
ICorJitInfo::PgoInstrumentationKind::HandleHistogramLongCount;
15571557
assert(is32 || is64);
15581558

15591559
// Figure out where the table is located.
@@ -2050,12 +2050,32 @@ PhaseStatus Compiler::fgIncorporateProfileData()
20502050
fgPgoEdgeCounts++;
20512051
break;
20522052

2053-
case ICorJitInfo::PgoInstrumentationKind::TypeHandleHistogramIntCount:
2054-
case ICorJitInfo::PgoInstrumentationKind::TypeHandleHistogramLongCount:
20552053
case ICorJitInfo::PgoInstrumentationKind::GetLikelyClass:
20562054
fgPgoClassProfiles++;
20572055
break;
20582056

2057+
case ICorJitInfo::PgoInstrumentationKind::HandleHistogramIntCount:
2058+
case ICorJitInfo::PgoInstrumentationKind::HandleHistogramLongCount:
2059+
if (iSchema + 1 < fgPgoSchemaCount)
2060+
{
2061+
if (fgPgoSchema[iSchema + 1].InstrumentationKind ==
2062+
ICorJitInfo::PgoInstrumentationKind::HandleHistogramTypes)
2063+
{
2064+
fgPgoClassProfiles++;
2065+
iSchema++;
2066+
break;
2067+
}
2068+
if (fgPgoSchema[iSchema + 1].InstrumentationKind ==
2069+
ICorJitInfo::PgoInstrumentationKind::HandleHistogramMethods)
2070+
{
2071+
fgPgoMethodProfiles++;
2072+
iSchema++;
2073+
break;
2074+
}
2075+
}
2076+
2077+
__fallthrough;
2078+
20592079
default:
20602080
JITDUMP("Unknown PGO record type 0x%x in schema entry %u (offset 0x%x count 0x%x other 0x%x)\n",
20612081
fgPgoSchema[iSchema].InstrumentationKind, iSchema, fgPgoSchema[iSchema].ILOffset,
@@ -2070,8 +2090,9 @@ PhaseStatus Compiler::fgIncorporateProfileData()
20702090
fgNumProfileRuns = 1;
20712091
}
20722092

2073-
JITDUMP("Profile summary: %d runs, %d block probes, %d edge probes, %d class profiles, %d other records\n",
2074-
fgNumProfileRuns, fgPgoBlockCounts, fgPgoEdgeCounts, fgPgoClassProfiles, otherRecords);
2093+
JITDUMP("Profile summary: %d runs, %d block probes, %d edge probes, %d class profiles, %d method profiles, %d "
2094+
"other records\n",
2095+
fgNumProfileRuns, fgPgoBlockCounts, fgPgoEdgeCounts, fgPgoClassProfiles, fgPgoMethodProfiles, otherRecords);
20752096

20762097
const bool haveBlockCounts = fgPgoBlockCounts > 0;
20772098
const bool haveEdgeCounts = fgPgoEdgeCounts > 0;

src/coreclr/jit/likelyclass.cpp

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ extern "C" DLLEXPORT UINT32 WINAPI getLikelyClasses(LikelyClassRecord*
157157
(schema[i].Count == 1))
158158
{
159159
INT_PTR result = *(INT_PTR*)(pInstrumentationData + schema[i].Offset);
160-
if (ICorJitInfo::IsUnknownTypeHandle(result))
160+
if (ICorJitInfo::IsUnknownHandle(result))
161161
{
162162
return 0;
163163
}
@@ -168,11 +168,11 @@ extern "C" DLLEXPORT UINT32 WINAPI getLikelyClasses(LikelyClassRecord*
168168
}
169169

170170
const bool isHistogramCount =
171-
(schema[i].InstrumentationKind == ICorJitInfo::PgoInstrumentationKind::TypeHandleHistogramIntCount) ||
172-
(schema[i].InstrumentationKind == ICorJitInfo::PgoInstrumentationKind::TypeHandleHistogramLongCount);
171+
(schema[i].InstrumentationKind == ICorJitInfo::PgoInstrumentationKind::HandleHistogramIntCount) ||
172+
(schema[i].InstrumentationKind == ICorJitInfo::PgoInstrumentationKind::HandleHistogramLongCount);
173173

174174
if (isHistogramCount && (schema[i].Count == 1) && ((i + 1) < countSchemaItems) &&
175-
(schema[i + 1].InstrumentationKind == ICorJitInfo::PgoInstrumentationKind::TypeHandleHistogramTypeHandle))
175+
(schema[i + 1].InstrumentationKind == ICorJitInfo::PgoInstrumentationKind::HandleHistogramTypes))
176176
{
177177
// Form a histogram
178178
//
@@ -191,7 +191,7 @@ extern "C" DLLEXPORT UINT32 WINAPI getLikelyClasses(LikelyClassRecord*
191191
{
192192
LikelyClassHistogramEntry const hist0 = h.HistogramEntryAt(0);
193193
// Fast path for monomorphic cases
194-
if (ICorJitInfo::IsUnknownTypeHandle(hist0.m_mt))
194+
if (ICorJitInfo::IsUnknownHandle(hist0.m_mt))
195195
{
196196
return 0;
197197
}
@@ -205,12 +205,12 @@ extern "C" DLLEXPORT UINT32 WINAPI getLikelyClasses(LikelyClassRecord*
205205
LikelyClassHistogramEntry const hist0 = h.HistogramEntryAt(0);
206206
LikelyClassHistogramEntry const hist1 = h.HistogramEntryAt(1);
207207
// Fast path for two classes
208-
if ((hist0.m_count >= hist1.m_count) && !ICorJitInfo::IsUnknownTypeHandle(hist0.m_mt))
208+
if ((hist0.m_count >= hist1.m_count) && !ICorJitInfo::IsUnknownHandle(hist0.m_mt))
209209
{
210210
pLikelyClasses[0].likelihood = (100 * hist0.m_count) / h.m_totalCount;
211211
pLikelyClasses[0].clsHandle = (CORINFO_CLASS_HANDLE)hist0.m_mt;
212212

213-
if ((maxLikelyClasses > 1) && !ICorJitInfo::IsUnknownTypeHandle(hist1.m_mt))
213+
if ((maxLikelyClasses > 1) && !ICorJitInfo::IsUnknownHandle(hist1.m_mt))
214214
{
215215
pLikelyClasses[1].likelihood = (100 * hist1.m_count) / h.m_totalCount;
216216
pLikelyClasses[1].clsHandle = (CORINFO_CLASS_HANDLE)hist1.m_mt;
@@ -219,12 +219,12 @@ extern "C" DLLEXPORT UINT32 WINAPI getLikelyClasses(LikelyClassRecord*
219219
return 1;
220220
}
221221

222-
if (!ICorJitInfo::IsUnknownTypeHandle(hist1.m_mt))
222+
if (!ICorJitInfo::IsUnknownHandle(hist1.m_mt))
223223
{
224224
pLikelyClasses[0].likelihood = (100 * hist1.m_count) / h.m_totalCount;
225225
pLikelyClasses[0].clsHandle = (CORINFO_CLASS_HANDLE)hist1.m_mt;
226226

227-
if ((maxLikelyClasses > 1) && !ICorJitInfo::IsUnknownTypeHandle(hist0.m_mt))
227+
if ((maxLikelyClasses > 1) && !ICorJitInfo::IsUnknownHandle(hist0.m_mt))
228228
{
229229
pLikelyClasses[1].likelihood = (100 * hist0.m_count) / h.m_totalCount;
230230
pLikelyClasses[1].clsHandle = (CORINFO_CLASS_HANDLE)hist0.m_mt;
@@ -244,7 +244,7 @@ extern "C" DLLEXPORT UINT32 WINAPI getLikelyClasses(LikelyClassRecord*
244244
for (unsigned m = 0; m < h.countHistogramElements; m++)
245245
{
246246
LikelyClassHistogramEntry const hist = h.HistogramEntryAt(m);
247-
if (!ICorJitInfo::IsUnknownTypeHandle(hist.m_mt))
247+
if (!ICorJitInfo::IsUnknownHandle(hist.m_mt))
248248
{
249249
sortedEntries[knownHandles++] = hist;
250250
}
@@ -311,7 +311,7 @@ CORINFO_CLASS_HANDLE Compiler::getRandomClass(ICorJitInfo::PgoInstrumentationSch
311311
(schema[i].Count == 1))
312312
{
313313
INT_PTR result = *(INT_PTR*)(pInstrumentationData + schema[i].Offset);
314-
if (ICorJitInfo::IsUnknownTypeHandle(result))
314+
if (ICorJitInfo::IsUnknownHandle(result))
315315
{
316316
return NO_CLASS_HANDLE;
317317
}
@@ -322,11 +322,11 @@ CORINFO_CLASS_HANDLE Compiler::getRandomClass(ICorJitInfo::PgoInstrumentationSch
322322
}
323323

324324
bool isHistogramCount =
325-
(schema[i].InstrumentationKind == ICorJitInfo::PgoInstrumentationKind::TypeHandleHistogramIntCount) ||
326-
(schema[i].InstrumentationKind == ICorJitInfo::PgoInstrumentationKind::TypeHandleHistogramLongCount);
325+
(schema[i].InstrumentationKind == ICorJitInfo::PgoInstrumentationKind::HandleHistogramIntCount) ||
326+
(schema[i].InstrumentationKind == ICorJitInfo::PgoInstrumentationKind::HandleHistogramLongCount);
327327

328328
if (isHistogramCount && (schema[i].Count == 1) && ((i + 1) < countSchemaItems) &&
329-
(schema[i + 1].InstrumentationKind == ICorJitInfo::PgoInstrumentationKind::TypeHandleHistogramTypeHandle))
329+
(schema[i + 1].InstrumentationKind == ICorJitInfo::PgoInstrumentationKind::HandleHistogramTypes))
330330
{
331331
// Form a histogram
332332
//
@@ -342,7 +342,7 @@ CORINFO_CLASS_HANDLE Compiler::getRandomClass(ICorJitInfo::PgoInstrumentationSch
342342
unsigned randomEntryIndex = random->Next(0, h.countHistogramElements);
343343
LikelyClassHistogramEntry randomEntry = h.HistogramEntryAt(randomEntryIndex);
344344

345-
if (ICorJitInfo::IsUnknownTypeHandle(randomEntry.m_mt))
345+
if (ICorJitInfo::IsUnknownHandle(randomEntry.m_mt))
346346
{
347347
return NO_CLASS_HANDLE;
348348
}

src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,7 @@ public static IEnumerable<PgoSchemaElem> ConvertTypeHandleHistogramsToCompactTyp
195195
bool hasTypeHistogram = false;
196196
foreach (var elem in pgoData)
197197
{
198-
if (elem.InstrumentationKind == PgoInstrumentationKind.TypeHandleHistogramIntCount ||
199-
elem.InstrumentationKind == PgoInstrumentationKind.TypeHandleHistogramLongCount)
198+
if (elem.InstrumentationKind == PgoInstrumentationKind.HandleHistogramTypes)
200199
{
201200
// found histogram
202201
hasTypeHistogram = true;
@@ -218,10 +217,12 @@ public static IEnumerable<PgoSchemaElem> ConvertTypeHandleHistogramsToCompactTyp
218217

219218
ComputeJitPgoInstrumentationSchema(LocalObjectToHandle, pgoData, out var nativeSchema, out var instrumentationData);
220219

221-
for (int i = 0; i < (pgoData.Length); i++)
220+
for (int i = 0; i < pgoData.Length; i++)
222221
{
223-
if (pgoData[i].InstrumentationKind == PgoInstrumentationKind.TypeHandleHistogramIntCount ||
224-
pgoData[i].InstrumentationKind == PgoInstrumentationKind.TypeHandleHistogramLongCount)
222+
if ((i + 1 < pgoData.Length) &&
223+
(pgoData[i].InstrumentationKind == PgoInstrumentationKind.HandleHistogramIntCount ||
224+
pgoData[i].InstrumentationKind == PgoInstrumentationKind.HandleHistogramLongCount) &&
225+
(pgoData[i + 1].InstrumentationKind == PgoInstrumentationKind.HandleHistogramTypes))
225226
{
226227
PgoSchemaElem? newElem = ComputeLikelyClass(i, handleToObject, nativeSchema, instrumentationData, compilationModuleGroup);
227228
if (newElem.HasValue)
@@ -3863,6 +3864,10 @@ public static void ComputeJitPgoInstrumentationSchema(Func<object, IntPtr> objec
38633864
{
38643865
ptrVal = (IntPtr)objectToHandle(typeVal.AsType);
38653866
}
3867+
else if (typeVal.AsMethod != null)
3868+
{
3869+
ptrVal = (IntPtr)objectToHandle(typeVal.AsMethod);
3870+
}
38663871
else
38673872
{
38683873
// The "Unknown types are the values from 1-33

0 commit comments

Comments
 (0)