Path: blob/main/contrib/llvm-project/llvm/lib/ProfileData/DataAccessProf.cpp
213765 views
#include "llvm/ProfileData/DataAccessProf.h"1#include "llvm/ADT/STLExtras.h"2#include "llvm/ProfileData/InstrProf.h"3#include "llvm/Support/Compression.h"4#include "llvm/Support/Endian.h"5#include "llvm/Support/Errc.h"6#include "llvm/Support/Error.h"7#include "llvm/Support/StringSaver.h"8#include "llvm/Support/raw_ostream.h"910namespace llvm {11namespace memprof {1213// If `Map` has an entry keyed by `Str`, returns the entry iterator. Otherwise,14// creates an owned copy of `Str`, adds a map entry for it and returns the15// iterator.16static std::pair<StringRef, uint64_t>17saveStringToMap(DataAccessProfData::StringToIndexMap &Map,18llvm::UniqueStringSaver &Saver, StringRef Str) {19auto [Iter, Inserted] = Map.try_emplace(Saver.save(Str), Map.size());20return *Iter;21}2223// Returns the canonical name or error.24static Expected<StringRef> getCanonicalName(StringRef Name) {25if (Name.empty())26return make_error<StringError>("Empty symbol name",27llvm::errc::invalid_argument);28return InstrProfSymtab::getCanonicalName(Name);29}3031std::optional<DataAccessProfRecord>32DataAccessProfData::getProfileRecord(const SymbolHandleRef SymbolID) const {33auto Key = SymbolID;34if (std::holds_alternative<StringRef>(SymbolID)) {35auto NameOrErr = getCanonicalName(std::get<StringRef>(SymbolID));36// If name canonicalization fails, suppress the error inside.37if (!NameOrErr) {38assert(39std::get<StringRef>(SymbolID).empty() &&40"Name canonicalization only fails when stringified string is empty.");41return std::nullopt;42}43Key = *NameOrErr;44}4546auto It = Records.find(Key);47if (It != Records.end()) {48return DataAccessProfRecord(Key, It->second.AccessCount,49It->second.Locations);50}5152return std::nullopt;53}5455bool DataAccessProfData::isKnownColdSymbol(const SymbolHandleRef SymID) const {56if (std::holds_alternative<uint64_t>(SymID))57return KnownColdHashes.contains(std::get<uint64_t>(SymID));58return KnownColdSymbols.contains(std::get<StringRef>(SymID));59}6061Error DataAccessProfData::setDataAccessProfile(SymbolHandleRef Symbol,62uint64_t AccessCount) {63uint64_t RecordID = -1;64const bool IsStringLiteral = std::holds_alternative<uint64_t>(Symbol);65SymbolHandleRef Key;66if (IsStringLiteral) {67RecordID = std::get<uint64_t>(Symbol);68Key = RecordID;69} else {70auto CanonicalName = getCanonicalName(std::get<StringRef>(Symbol));71if (!CanonicalName)72return CanonicalName.takeError();73std::tie(Key, RecordID) =74saveStringToMap(StrToIndexMap, Saver, *CanonicalName);75}7677auto [Iter, Inserted] =78Records.try_emplace(Key, RecordID, AccessCount, IsStringLiteral);79if (!Inserted)80return make_error<StringError>("Duplicate symbol or string literal added. "81"User of DataAccessProfData should "82"aggregate count for the same symbol. ",83llvm::errc::invalid_argument);8485return Error::success();86}8788Error DataAccessProfData::setDataAccessProfile(89SymbolHandleRef SymbolID, uint64_t AccessCount,90ArrayRef<SourceLocation> Locations) {91if (Error E = setDataAccessProfile(SymbolID, AccessCount))92return E;9394auto &Record = Records.back().second;95for (const auto &Location : Locations)96Record.Locations.push_back(97{saveStringToMap(StrToIndexMap, Saver, Location.FileName).first,98Location.Line});99100return Error::success();101}102103Error DataAccessProfData::addKnownSymbolWithoutSamples(104SymbolHandleRef SymbolID) {105if (std::holds_alternative<uint64_t>(SymbolID)) {106KnownColdHashes.insert(std::get<uint64_t>(SymbolID));107return Error::success();108}109auto CanonicalName = getCanonicalName(std::get<StringRef>(SymbolID));110if (!CanonicalName)111return CanonicalName.takeError();112KnownColdSymbols.insert(113saveStringToMap(StrToIndexMap, Saver, *CanonicalName).first);114return Error::success();115}116117Error DataAccessProfData::deserialize(const unsigned char *&Ptr) {118uint64_t NumSampledSymbols =119support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);120uint64_t NumColdKnownSymbols =121support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);122if (Error E = deserializeSymbolsAndFilenames(Ptr, NumSampledSymbols,123NumColdKnownSymbols))124return E;125126uint64_t Num =127support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);128for (uint64_t I = 0; I < Num; ++I)129KnownColdHashes.insert(130support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr));131132return deserializeRecords(Ptr);133}134135Error DataAccessProfData::serializeSymbolsAndFilenames(ProfOStream &OS) const {136OS.write(StrToIndexMap.size());137OS.write(KnownColdSymbols.size());138139std::vector<std::string> Strs;140Strs.reserve(StrToIndexMap.size() + KnownColdSymbols.size());141for (const auto &Str : StrToIndexMap)142Strs.push_back(Str.first.str());143for (const auto &Str : KnownColdSymbols)144Strs.push_back(Str.str());145146std::string CompressedStrings;147if (!Strs.empty())148if (Error E = collectGlobalObjectNameStrings(149Strs, compression::zlib::isAvailable(), CompressedStrings))150return E;151const uint64_t CompressedStringLen = CompressedStrings.length();152// Record the length of compressed string.153OS.write(CompressedStringLen);154// Write the chars in compressed strings.155for (char C : CompressedStrings)156OS.writeByte(static_cast<uint8_t>(C));157// Pad up to a multiple of 8.158// InstrProfReader could read bytes according to 'CompressedStringLen'.159const uint64_t PaddedLength = alignTo(CompressedStringLen, 8);160for (uint64_t K = CompressedStringLen; K < PaddedLength; K++)161OS.writeByte(0);162return Error::success();163}164165uint64_t166DataAccessProfData::getEncodedIndex(const SymbolHandleRef SymbolID) const {167if (std::holds_alternative<uint64_t>(SymbolID))168return std::get<uint64_t>(SymbolID);169170auto Iter = StrToIndexMap.find(std::get<StringRef>(SymbolID));171assert(Iter != StrToIndexMap.end() &&172"String literals not found in StrToIndexMap");173return Iter->second;174}175176Error DataAccessProfData::serialize(ProfOStream &OS) const {177if (Error E = serializeSymbolsAndFilenames(OS))178return E;179OS.write(KnownColdHashes.size());180for (const auto &Hash : KnownColdHashes)181OS.write(Hash);182OS.write((uint64_t)(Records.size()));183for (const auto &[Key, Rec] : Records) {184OS.write(getEncodedIndex(Rec.SymbolID));185OS.writeByte(Rec.IsStringLiteral);186OS.write(Rec.AccessCount);187OS.write(Rec.Locations.size());188for (const auto &Loc : Rec.Locations) {189OS.write(getEncodedIndex(Loc.FileName));190OS.write32(Loc.Line);191}192}193return Error::success();194}195196Error DataAccessProfData::deserializeSymbolsAndFilenames(197const unsigned char *&Ptr, const uint64_t NumSampledSymbols,198const uint64_t NumColdKnownSymbols) {199uint64_t Len =200support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);201202// The first NumSampledSymbols strings are symbols with samples, and next203// NumColdKnownSymbols strings are known cold symbols.204uint64_t StringCnt = 0;205std::function<Error(StringRef)> addName = [&](StringRef Name) {206if (StringCnt < NumSampledSymbols)207saveStringToMap(StrToIndexMap, Saver, Name);208else209KnownColdSymbols.insert(Saver.save(Name));210++StringCnt;211return Error::success();212};213if (Error E =214readAndDecodeStrings(StringRef((const char *)Ptr, Len), addName))215return E;216217Ptr += alignTo(Len, 8);218return Error::success();219}220221Error DataAccessProfData::deserializeRecords(const unsigned char *&Ptr) {222SmallVector<StringRef> Strings =223llvm::to_vector(llvm::make_first_range(getStrToIndexMapRef()));224225uint64_t NumRecords =226support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);227228for (uint64_t I = 0; I < NumRecords; ++I) {229uint64_t ID =230support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);231232bool IsStringLiteral =233support::endian::readNext<uint8_t, llvm::endianness::little>(Ptr);234235uint64_t AccessCount =236support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);237238SymbolHandleRef SymbolID;239if (IsStringLiteral)240SymbolID = ID;241else242SymbolID = Strings[ID];243if (Error E = setDataAccessProfile(SymbolID, AccessCount))244return E;245246auto &Record = Records.back().second;247248uint64_t NumLocations =249support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);250251Record.Locations.reserve(NumLocations);252for (uint64_t J = 0; J < NumLocations; ++J) {253uint64_t FileNameIndex =254support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);255uint32_t Line =256support::endian::readNext<uint32_t, llvm::endianness::little>(Ptr);257Record.Locations.push_back({Strings[FileNameIndex], Line});258}259}260return Error::success();261}262} // namespace memprof263} // namespace llvm264265266