21
21
#include " llvm/IR/Function.h"
22
22
#include " llvm/IR/GlobalValue.h"
23
23
#include " llvm/ProfileData/FunctionId.h"
24
+ #include " llvm/ProfileData/HashKeyMap.h"
24
25
#include " llvm/Support/Allocator.h"
25
26
#include " llvm/Support/Debug.h"
26
27
#include " llvm/Support/ErrorOr.h"
27
28
#include " llvm/Support/MathExtras.h"
28
- #include " llvm/ProfileData/HashKeyMap.h"
29
29
#include < algorithm>
30
30
#include < cstdint>
31
31
#include < list>
@@ -59,7 +59,9 @@ enum class sampleprof_error {
59
59
ostream_seek_unsupported,
60
60
uncompress_failed,
61
61
zlib_unavailable,
62
- hash_mismatch
62
+ hash_mismatch,
63
+ illegal_line_offset,
64
+ duplicate_vtable_type,
63
65
};
64
66
65
67
inline std::error_code make_error_code (sampleprof_error E) {
@@ -88,6 +90,9 @@ struct is_error_code_enum<llvm::sampleprof_error> : std::true_type {};
88
90
namespace llvm {
89
91
namespace sampleprof {
90
92
93
+ constexpr char kBodySampleVTableProfPrefix [] = " <vt-call> " ;
94
+ constexpr char kInlinedCallsiteVTablerofPrefix [] = " <vt-inline> " ;
95
+
91
96
enum SampleProfileFormat {
92
97
SPF_None = 0 ,
93
98
SPF_Text = 0x1 ,
@@ -286,6 +291,9 @@ struct LineLocation {
286
291
void print (raw_ostream &OS) const ;
287
292
void dump () const ;
288
293
294
+ // / Serialize the line location to \p OS using ULEB128 encoding.
295
+ void serialize (raw_ostream &OS) const ;
296
+
289
297
bool operator <(const LineLocation &O) const {
290
298
return LineOffset < O.LineOffset ||
291
299
(LineOffset == O.LineOffset && Discriminator < O.Discriminator );
@@ -315,7 +323,9 @@ struct LineLocationHash {
315
323
316
324
raw_ostream &operator <<(raw_ostream &OS, const LineLocation &Loc);
317
325
318
- using TypeMap = std::map<FunctionId, uint64_t >;
326
+ // / Key represents the id of a vtable and value represents its count.
327
+ // / TODO: Rename class FunctionId to SymbolId in a separate PR.
328
+ using TypeCountMap = std::map<FunctionId, uint64_t >;
319
329
320
330
// / Representation of a single sample record.
321
331
// /
@@ -342,7 +352,6 @@ class SampleRecord {
342
352
343
353
using SortedCallTargetSet = std::set<CallTarget, CallTargetComparator>;
344
354
using CallTargetMap = std::unordered_map<FunctionId, uint64_t >;
345
-
346
355
SampleRecord () = default ;
347
356
348
357
// / Increment the number of samples for this record by \p S.
@@ -372,22 +381,12 @@ class SampleRecord {
372
381
// / Sample counts accumulate using saturating arithmetic, to avoid wrapping
373
382
// / around unsigned integers.
374
383
sampleprof_error addCalledTarget (FunctionId F, uint64_t S,
375
- uint64_t Weight = 1 ) {
376
- uint64_t &TargetSamples = CallTargets[F];
377
- bool Overflowed;
378
- TargetSamples =
379
- SaturatingMultiplyAdd (S, Weight, TargetSamples, &Overflowed);
380
- return Overflowed ? sampleprof_error::counter_overflow
381
- : sampleprof_error::success;
382
- }
384
+ uint64_t Weight = 1 );
383
385
384
- sampleprof_error addTypeCount (FunctionId F, uint64_t S, uint64_t Weight = 1 ) {
385
- uint64_t &Samples = TypeCounts[F];
386
- bool Overflowed;
387
- Samples = SaturatingMultiplyAdd (S, Weight, Samples, &Overflowed);
388
- return Overflowed ? sampleprof_error::counter_overflow
389
- : sampleprof_error::success;
390
- }
386
+ // / Add vtable type \p F with samples \p S.
387
+ // / Optionally scale sample count \p S by \p Weight.
388
+ sampleprof_error addVTableAccessCount (FunctionId F, uint64_t S,
389
+ uint64_t Weight = 1 );
391
390
392
391
// / Remove called function from the call target map. Return the target sample
393
392
// / count of the called function.
@@ -406,8 +405,10 @@ class SampleRecord {
406
405
407
406
uint64_t getSamples () const { return NumSamples; }
408
407
const CallTargetMap &getCallTargets () const { return CallTargets; }
409
- const TypeMap &getTypes () const { return TypeCounts; }
410
- TypeMap &getTypes () { return TypeCounts; }
408
+ const TypeCountMap &getVTableAccessCounts () const {
409
+ return VTableAccessCounts;
410
+ }
411
+ TypeCountMap &getVTableAccessCounts () { return VTableAccessCounts; }
411
412
const SortedCallTargetSet getSortedCallTargets () const {
412
413
return sortCallTargets (CallTargets);
413
414
}
@@ -456,7 +457,8 @@ class SampleRecord {
456
457
private:
457
458
uint64_t NumSamples = 0 ;
458
459
CallTargetMap CallTargets;
459
- TypeMap TypeCounts;
460
+ // The vtable types and their counts in this sample record.
461
+ TypeCountMap VTableAccessCounts;
460
462
};
461
463
462
464
raw_ostream &operator <<(raw_ostream &OS, const SampleRecord &Sample);
@@ -752,7 +754,7 @@ using BodySampleMap = std::map<LineLocation, SampleRecord>;
752
754
// memory, which is *very* significant for large profiles.
753
755
using FunctionSamplesMap = std::map<FunctionId, FunctionSamples>;
754
756
using CallsiteSampleMap = std::map<LineLocation, FunctionSamplesMap>;
755
- using CallsiteTypeMap = std::map<LineLocation, TypeMap >;
757
+ using CallsiteTypeMap = std::map<LineLocation, TypeCountMap >;
756
758
using LocToLocMap =
757
759
std::unordered_map<LineLocation, LineLocation, LineLocationHash>;
758
760
@@ -810,20 +812,14 @@ class FunctionSamples {
810
812
Func, Num, Weight);
811
813
}
812
814
813
- sampleprof_error addTypeSamples (uint32_t LineOffset, uint32_t Discriminator,
814
- FunctionId Func, uint64_t Num,
815
- uint64_t Weight = 1 ) {
816
- return BodySamples[LineLocation (LineOffset, Discriminator)].addTypeCount (
817
- Func, Num, Weight);
815
+ sampleprof_error addFunctionBodyTypeSamples (const LineLocation &Loc,
816
+ FunctionId Func, uint64_t Num,
817
+ uint64_t Weight = 1 ) {
818
+ return BodySamples[Loc].addVTableAccessCount (Func, Num, Weight);
818
819
}
819
820
820
- sampleprof_error addTypeSamples (const LineLocation &Loc, FunctionId Func,
821
- uint64_t Num, uint64_t Weight = 1 ) {
822
- return BodySamples[Loc].addTypeCount (Func, Num, Weight);
823
- }
824
-
825
- TypeMap &getTypeSamples (const LineLocation &Loc) {
826
- return BodySamples[Loc].getTypes ();
821
+ TypeCountMap &getFunctionBodyTypeSamples (const LineLocation &Loc) {
822
+ return BodySamples[Loc].getVTableAccessCounts ();
827
823
}
828
824
829
825
sampleprof_error addSampleRecord (LineLocation Location,
@@ -951,7 +947,8 @@ class FunctionSamples {
951
947
return &Iter->second ;
952
948
}
953
949
954
- const TypeMap *findTypeSamplesAt (const LineLocation &Loc) const {
950
+ // / Returns the TypeCountMap for inlined callsites at the given \p Loc.
951
+ const TypeCountMap *findCallsiteTypeSamplesAt (const LineLocation &Loc) const {
955
952
auto Iter = VirtualCallsiteTypes.find (mapIRLocToProfileLoc (Loc));
956
953
if (Iter == VirtualCallsiteTypes.end ())
957
954
return nullptr ;
@@ -1019,14 +1016,42 @@ class FunctionSamples {
1019
1016
return CallsiteSamples;
1020
1017
}
1021
1018
1022
- const CallsiteTypeMap &getCallsiteTypes () const {
1019
+ // / Return all the callsite type samples collected in the body of the
1020
+ // / function.
1021
+ const CallsiteTypeMap &getCallsiteTypeCounts () const {
1023
1022
return VirtualCallsiteTypes;
1024
1023
}
1025
1024
1026
- TypeMap& getTypeSamplesAt (const LineLocation &Loc) {
1025
+ // / Returns the type samples for the un-drifted location of \p Loc.
1026
+ TypeCountMap &getTypeSamplesAt (const LineLocation &Loc) {
1027
1027
return VirtualCallsiteTypes[mapIRLocToProfileLoc (Loc)];
1028
1028
}
1029
1029
1030
+ // / Scale \p Other sample counts by \p Weight and add the scaled result to the
1031
+ // / type samples for the undrifted location of \p Loc.
1032
+ template <typename T>
1033
+ sampleprof_error addCallsiteVTableTypeProfAt (const LineLocation &Loc,
1034
+ const T &Other,
1035
+ uint64_t Weight = 1 ) {
1036
+ static_assert ((std::is_same_v<typename T::key_type, StringRef> ||
1037
+ std::is_same_v<typename T::key_type, FunctionId>) &&
1038
+ std::is_same_v<typename T::mapped_type, uint64_t >,
1039
+ " T must be a map with StringRef or FunctionId as key and "
1040
+ " uint64_t as value" );
1041
+ TypeCountMap &TypeCounts = getTypeSamplesAt (Loc);
1042
+ bool Overflowed = false ;
1043
+
1044
+ for (const auto [Type, Count] : Other) {
1045
+ FunctionId TypeId (Type);
1046
+ bool RowOverflow = false ;
1047
+ TypeCounts[TypeId] = SaturatingMultiplyAdd (
1048
+ Count, Weight, TypeCounts[TypeId], &RowOverflow);
1049
+ Overflowed |= RowOverflow;
1050
+ }
1051
+ return Overflowed ? sampleprof_error::counter_overflow
1052
+ : sampleprof_error::success;
1053
+ }
1054
+
1030
1055
// / Return the maximum of sample counts in a function body. When SkipCallSite
1031
1056
// / is false, which is the default, the return count includes samples in the
1032
1057
// / inlined functions. When SkipCallSite is true, the return count only
@@ -1073,27 +1098,18 @@ class FunctionSamples {
1073
1098
const LineLocation &Loc = I.first ;
1074
1099
const SampleRecord &Rec = I.second ;
1075
1100
mergeSampleProfErrors (Result, BodySamples[Loc].merge (Rec, Weight));
1076
- // const auto &OtherTypeCountMap = Rec.getTypes();
1077
- // for (const auto &[Type, Count] : OtherTypeCountMap) {
1078
- // mergeSampleProfErrors(Result, addTypeSamples(Loc, Type, Count,
1079
- // Weight));
1080
- // }
1081
1101
}
1082
-
1083
1102
for (const auto &I : Other.getCallsiteSamples ()) {
1084
1103
const LineLocation &Loc = I.first ;
1085
1104
FunctionSamplesMap &FSMap = functionSamplesAt (Loc);
1086
1105
for (const auto &Rec : I.second )
1087
1106
mergeSampleProfErrors (Result,
1088
1107
FSMap[Rec.first ].merge (Rec.second , Weight));
1089
1108
}
1090
- for (const auto &[Loc, TypeCountMap] : Other.getCallsiteTypes ()) {
1091
- TypeMap &TypeCounts = getTypeSamplesAt (Loc);
1092
- for (const auto &[Type, Count] : TypeCountMap) {
1093
- TypeCounts[Type] =
1094
- SaturatingMultiplyAdd (Count, Weight, TypeCounts[Type]);
1095
- }
1096
- }
1109
+ for (const auto &[Loc, OtherTypeMap] : Other.getCallsiteTypeCounts ())
1110
+ mergeSampleProfErrors (
1111
+ Result, addCallsiteVTableTypeProfAt (Loc, OtherTypeMap, Weight));
1112
+
1097
1113
return Result;
1098
1114
}
1099
1115
@@ -1337,6 +1353,21 @@ class FunctionSamples {
1337
1353
// / collected in the call to baz() at line offset 8.
1338
1354
CallsiteSampleMap CallsiteSamples;
1339
1355
1356
+ // / Map inlined virtual callsites to the vtable from which they are loaded.
1357
+ // /
1358
+ // / Each entry is a mapping from the location to the list of vtables and their
1359
+ // / sampled counts. For example, given:
1360
+ // /
1361
+ // / void foo() {
1362
+ // / ...
1363
+ // / 5 inlined_vcall_bar();
1364
+ // / ...
1365
+ // / 5 inlined_vcall_baz();
1366
+ // / ...
1367
+ // / 200 inlined_vcall_qux();
1368
+ // / }
1369
+ // / This map will contain two entries. One with two types for line offset 5
1370
+ // / and one with one type for line offset 200.
1340
1371
CallsiteTypeMap VirtualCallsiteTypes;
1341
1372
1342
1373
// / IR to profile location map generated by stale profile matching.
0 commit comments