@@ -61,7 +61,9 @@ enum class sampleprof_error {
6161 ostream_seek_unsupported,
6262 uncompress_failed,
6363 zlib_unavailable,
64- hash_mismatch
64+ hash_mismatch,
65+ illegal_line_offset,
66+ duplicate_vtable_type,
6567};
6668
6769inline std::error_code make_error_code (sampleprof_error E) {
@@ -90,6 +92,8 @@ struct is_error_code_enum<llvm::sampleprof_error> : std::true_type {};
9092namespace llvm {
9193namespace sampleprof {
9294
95+ constexpr char kVTableProfPrefix [] = " vtables " ;
96+
9397enum SampleProfileFormat {
9498 SPF_None = 0 ,
9599 SPF_Text = 0x1 ,
@@ -203,6 +207,9 @@ enum class SecProfSummaryFlags : uint32_t {
203207 // / SecFlagIsPreInlined means this profile contains ShouldBeInlined
204208 // / contexts thus this is CS preinliner computed.
205209 SecFlagIsPreInlined = (1 << 4 ),
210+
211+ // / SecFlagHasVTableTypeProf means this profile contains vtable type profiles.
212+ SecFlagHasVTableTypeProf = (1 << 5 ),
206213};
207214
208215enum class SecFuncMetadataFlags : uint32_t {
@@ -286,7 +293,7 @@ struct LineLocation {
286293 LLVM_ABI void dump () const ;
287294
288295 // Serialize the line location to the output stream using ULEB128 encoding.
289- LLVM_ABI void serialize (raw_ostream &OS);
296+ LLVM_ABI void serialize (raw_ostream &OS) const ;
290297
291298 bool operator <(const LineLocation &O) const {
292299 return std::tie (LineOffset, Discriminator) <
@@ -302,7 +309,7 @@ struct LineLocation {
302309 }
303310
304311 uint64_t getHashCode () const {
305- return ((uint64_t ) Discriminator << 32 ) | LineOffset;
312+ return ((uint64_t )Discriminator << 32 ) | LineOffset;
306313 }
307314
308315 uint32_t LineOffset;
@@ -317,16 +324,28 @@ struct LineLocationHash {
317324
318325LLVM_ABI raw_ostream &operator <<(raw_ostream &OS, const LineLocation &Loc);
319326
327+ // / Key represents the id of a vtable and value represents its count.
328+ // / TODO: Rename class FunctionId to SymbolId in a separate PR.
329+ using TypeCountMap = std::map<FunctionId, uint64_t >;
330+
331+ // / Write \p Map to the output stream. Keys are linearized using \p NameTable
332+ // / and written as ULEB128. Values are written as ULEB128 as well.
333+ std::error_code
334+ serializeTypeMap (const TypeCountMap &Map,
335+ const MapVector<FunctionId, uint32_t > &NameTable,
336+ raw_ostream &OS);
337+
320338// / Representation of a single sample record.
321339// /
322340// / A sample record is represented by a positive integer value, which
323341// / indicates how frequently was the associated line location executed.
324342// /
325343// / Additionally, if the associated location contains a function call,
326- // / the record will hold a list of all the possible called targets. For
327- // / direct calls, this will be the exact function being invoked. For
328- // / indirect calls (function pointers, virtual table dispatch), this
329- // / will be a list of one or more functions.
344+ // / the record will hold a list of all the possible called targets and the types
345+ // / for virtual table dispatches. For direct calls, this will be the exact
346+ // / function being invoked. For indirect calls (function pointers, virtual table
347+ // / dispatch), this will be a list of one or more functions. For virtual table
348+ // / dispatches, this record will also hold the type of the object.
330349class SampleRecord {
331350public:
332351 using CallTarget = std::pair<FunctionId, uint64_t >;
@@ -745,6 +764,7 @@ using BodySampleMap = std::map<LineLocation, SampleRecord>;
745764// memory, which is *very* significant for large profiles.
746765using FunctionSamplesMap = std::map<FunctionId, FunctionSamples>;
747766using CallsiteSampleMap = std::map<LineLocation, FunctionSamplesMap>;
767+ using CallsiteTypeMap = std::map<LineLocation, TypeCountMap>;
748768using LocToLocMap =
749769 std::unordered_map<LineLocation, LineLocation, LineLocationHash>;
750770
@@ -927,6 +947,14 @@ class FunctionSamples {
927947 return &Iter->second ;
928948 }
929949
950+ // / Returns the TypeCountMap for inlined callsites at the given \p Loc.
951+ const TypeCountMap *findCallsiteTypeSamplesAt (const LineLocation &Loc) const {
952+ auto Iter = VirtualCallsiteTypeCounts.find (mapIRLocToProfileLoc (Loc));
953+ if (Iter == VirtualCallsiteTypeCounts.end ())
954+ return nullptr ;
955+ return &Iter->second ;
956+ }
957+
930958 // / Returns a pointer to FunctionSamples at the given callsite location
931959 // / \p Loc with callee \p CalleeName. If no callsite can be found, relax
932960 // / the restriction to return the FunctionSamples at callsite location
@@ -988,6 +1016,42 @@ class FunctionSamples {
9881016 return CallsiteSamples;
9891017 }
9901018
1019+ // / Return all the callsite type samples collected in the body of the
1020+ // / function.
1021+ const CallsiteTypeMap &getCallsiteTypeCounts () const {
1022+ return VirtualCallsiteTypeCounts;
1023+ }
1024+
1025+ // / Returns the type samples for the un-drifted location of \p Loc.
1026+ TypeCountMap &getTypeSamplesAt (const LineLocation &Loc) {
1027+ return VirtualCallsiteTypeCounts[mapIRLocToProfileLoc (Loc)];
1028+ }
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+
9911055 // / Return the maximum of sample counts in a function body. When SkipCallSite
9921056 // / is false, which is the default, the return count includes samples in the
9931057 // / inlined functions. When SkipCallSite is true, the return count only
@@ -1042,6 +1106,10 @@ class FunctionSamples {
10421106 mergeSampleProfErrors (Result,
10431107 FSMap[Rec.first ].merge (Rec.second , Weight));
10441108 }
1109+ for (const auto &[Loc, OtherTypeMap] : Other.getCallsiteTypeCounts ())
1110+ mergeSampleProfErrors (
1111+ Result, addCallsiteVTableTypeProfAt (Loc, OtherTypeMap, Weight));
1112+
10451113 return Result;
10461114 }
10471115
@@ -1285,6 +1353,23 @@ class FunctionSamples {
12851353 // / collected in the call to baz() at line offset 8.
12861354 CallsiteSampleMap CallsiteSamples;
12871355
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.
1371+ CallsiteTypeMap VirtualCallsiteTypeCounts;
1372+
12881373 // / IR to profile location map generated by stale profile matching.
12891374 // /
12901375 // / Each entry is a mapping from the location on current build to the matched
0 commit comments