2121#include " llvm/IR/Function.h"
2222#include " llvm/IR/GlobalValue.h"
2323#include " llvm/ProfileData/FunctionId.h"
24+ #include " llvm/ProfileData/HashKeyMap.h"
2425#include " llvm/Support/Allocator.h"
2526#include " llvm/Support/Debug.h"
2627#include " llvm/Support/ErrorOr.h"
2728#include " llvm/Support/MathExtras.h"
28- #include " llvm/ProfileData/HashKeyMap.h"
2929#include < algorithm>
3030#include < cstdint>
3131#include < list>
@@ -59,7 +59,9 @@ enum class sampleprof_error {
5959 ostream_seek_unsupported,
6060 uncompress_failed,
6161 zlib_unavailable,
62- hash_mismatch
62+ hash_mismatch,
63+ illegal_line_offset,
64+ duplicate_vtable_type,
6365};
6466
6567inline std::error_code make_error_code (sampleprof_error E) {
@@ -88,6 +90,9 @@ struct is_error_code_enum<llvm::sampleprof_error> : std::true_type {};
8890namespace llvm {
8991namespace sampleprof {
9092
93+ constexpr char kBodySampleVTableProfPrefix [] = " <vt-call> " ;
94+ constexpr char kInlinedCallsiteVTablerofPrefix [] = " <vt-inline> " ;
95+
9196enum SampleProfileFormat {
9297 SPF_None = 0 ,
9398 SPF_Text = 0x1 ,
@@ -286,6 +291,9 @@ struct LineLocation {
286291 void print (raw_ostream &OS) const ;
287292 void dump () const ;
288293
294+ // / Serialize the line location to \p OS using ULEB128 encoding.
295+ void serialize (raw_ostream &OS) const ;
296+
289297 bool operator <(const LineLocation &O) const {
290298 return LineOffset < O.LineOffset ||
291299 (LineOffset == O.LineOffset && Discriminator < O.Discriminator );
@@ -315,7 +323,9 @@ struct LineLocationHash {
315323
316324raw_ostream &operator <<(raw_ostream &OS, const LineLocation &Loc);
317325
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 >;
319329
320330// / Representation of a single sample record.
321331// /
@@ -342,7 +352,6 @@ class SampleRecord {
342352
343353 using SortedCallTargetSet = std::set<CallTarget, CallTargetComparator>;
344354 using CallTargetMap = std::unordered_map<FunctionId, uint64_t >;
345-
346355 SampleRecord () = default ;
347356
348357 // / Increment the number of samples for this record by \p S.
@@ -372,22 +381,12 @@ class SampleRecord {
372381 // / Sample counts accumulate using saturating arithmetic, to avoid wrapping
373382 // / around unsigned integers.
374383 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 );
383385
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 );
391390
392391 // / Remove called function from the call target map. Return the target sample
393392 // / count of the called function.
@@ -406,8 +405,10 @@ class SampleRecord {
406405
407406 uint64_t getSamples () const { return NumSamples; }
408407 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; }
411412 const SortedCallTargetSet getSortedCallTargets () const {
412413 return sortCallTargets (CallTargets);
413414 }
@@ -456,7 +457,8 @@ class SampleRecord {
456457private:
457458 uint64_t NumSamples = 0 ;
458459 CallTargetMap CallTargets;
459- TypeMap TypeCounts;
460+ // The vtable types and their counts in this sample record.
461+ TypeCountMap VTableAccessCounts;
460462};
461463
462464raw_ostream &operator <<(raw_ostream &OS, const SampleRecord &Sample);
@@ -752,7 +754,7 @@ using BodySampleMap = std::map<LineLocation, SampleRecord>;
752754// memory, which is *very* significant for large profiles.
753755using FunctionSamplesMap = std::map<FunctionId, FunctionSamples>;
754756using CallsiteSampleMap = std::map<LineLocation, FunctionSamplesMap>;
755- using CallsiteTypeMap = std::map<LineLocation, TypeMap >;
757+ using CallsiteTypeMap = std::map<LineLocation, TypeCountMap >;
756758using LocToLocMap =
757759 std::unordered_map<LineLocation, LineLocation, LineLocationHash>;
758760
@@ -810,20 +812,14 @@ class FunctionSamples {
810812 Func, Num, Weight);
811813 }
812814
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);
818819 }
819820
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 ();
827823 }
828824
829825 sampleprof_error addSampleRecord (LineLocation Location,
@@ -951,7 +947,8 @@ class FunctionSamples {
951947 return &Iter->second ;
952948 }
953949
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 {
955952 auto Iter = VirtualCallsiteTypes.find (mapIRLocToProfileLoc (Loc));
956953 if (Iter == VirtualCallsiteTypes.end ())
957954 return nullptr ;
@@ -1019,14 +1016,42 @@ class FunctionSamples {
10191016 return CallsiteSamples;
10201017 }
10211018
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 {
10231022 return VirtualCallsiteTypes;
10241023 }
10251024
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) {
10271027 return VirtualCallsiteTypes[mapIRLocToProfileLoc (Loc)];
10281028 }
10291029
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+
10301055 // / Return the maximum of sample counts in a function body. When SkipCallSite
10311056 // / is false, which is the default, the return count includes samples in the
10321057 // / inlined functions. When SkipCallSite is true, the return count only
@@ -1073,27 +1098,18 @@ class FunctionSamples {
10731098 const LineLocation &Loc = I.first ;
10741099 const SampleRecord &Rec = I.second ;
10751100 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- // }
10811101 }
1082-
10831102 for (const auto &I : Other.getCallsiteSamples ()) {
10841103 const LineLocation &Loc = I.first ;
10851104 FunctionSamplesMap &FSMap = functionSamplesAt (Loc);
10861105 for (const auto &Rec : I.second )
10871106 mergeSampleProfErrors (Result,
10881107 FSMap[Rec.first ].merge (Rec.second , Weight));
10891108 }
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+
10971113 return Result;
10981114 }
10991115
@@ -1337,6 +1353,21 @@ class FunctionSamples {
13371353 // / collected in the call to baz() at line offset 8.
13381354 CallsiteSampleMap CallsiteSamples;
13391355
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.
13401371 CallsiteTypeMap VirtualCallsiteTypes;
13411372
13421373 // / IR to profile location map generated by stale profile matching.
0 commit comments