1*2f09f445SMaksim Panchenko //===- bolt/Profile/DataReader.cpp - Perf data reader ---------------------===// 2a34c753fSRafael Auler // 3a34c753fSRafael Auler // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4a34c753fSRafael Auler // See https://llvm.org/LICENSE.txt for license information. 5a34c753fSRafael Auler // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6a34c753fSRafael Auler // 7a34c753fSRafael Auler //===----------------------------------------------------------------------===// 8a34c753fSRafael Auler // 9a34c753fSRafael Auler // This family of functions reads profile data written by the perf2bolt 10a34c753fSRafael Auler // utility and stores it in memory for llvm-bolt consumption. 11a34c753fSRafael Auler // 12a34c753fSRafael Auler //===----------------------------------------------------------------------===// 13a34c753fSRafael Auler 14a34c753fSRafael Auler #include "bolt/Profile/DataReader.h" 15a34c753fSRafael Auler #include "bolt/Core/BinaryFunction.h" 16a34c753fSRafael Auler #include "bolt/Passes/MCF.h" 17a34c753fSRafael Auler #include "bolt/Utils/Utils.h" 18a34c753fSRafael Auler #include "llvm/Support/CommandLine.h" 19a34c753fSRafael Auler #include "llvm/Support/Debug.h" 20a34c753fSRafael Auler #include <map> 21a34c753fSRafael Auler 22a34c753fSRafael Auler #undef DEBUG_TYPE 23a34c753fSRafael Auler #define DEBUG_TYPE "bolt-prof" 24a34c753fSRafael Auler 25a34c753fSRafael Auler using namespace llvm; 26a34c753fSRafael Auler 27a34c753fSRafael Auler namespace opts { 28a34c753fSRafael Auler 29a34c753fSRafael Auler extern cl::OptionCategory BoltCategory; 30a34c753fSRafael Auler extern llvm::cl::opt<unsigned> Verbosity; 31a34c753fSRafael Auler 32a34c753fSRafael Auler static cl::opt<bool> 33a34c753fSRafael Auler DumpData("dump-data", 34a34c753fSRafael Auler cl::desc("dump parsed bolt data for debugging"), 35a34c753fSRafael Auler cl::Hidden, 36a34c753fSRafael Auler cl::cat(BoltCategory)); 37a34c753fSRafael Auler 38a34c753fSRafael Auler } // namespace opts 39a34c753fSRafael Auler 40a34c753fSRafael Auler namespace llvm { 41a34c753fSRafael Auler namespace bolt { 42a34c753fSRafael Auler 43a34c753fSRafael Auler Optional<StringRef> getLTOCommonName(const StringRef Name) { 44a34c753fSRafael Auler size_t LTOSuffixPos = Name.find(".lto_priv."); 45a34c753fSRafael Auler if (LTOSuffixPos != StringRef::npos) { 46a34c753fSRafael Auler return Name.substr(0, LTOSuffixPos + 10); 47a34c753fSRafael Auler } else if ((LTOSuffixPos = Name.find(".constprop.")) != StringRef::npos) { 48a34c753fSRafael Auler return Name.substr(0, LTOSuffixPos + 11); 49a34c753fSRafael Auler } else { 50a34c753fSRafael Auler return NoneType(); 51a34c753fSRafael Auler } 52a34c753fSRafael Auler } 53a34c753fSRafael Auler 54a34c753fSRafael Auler namespace { 55a34c753fSRafael Auler 56a34c753fSRafael Auler /// Return true if the function name can change across compilations. 57a34c753fSRafael Auler bool hasVolatileName(const BinaryFunction &BF) { 58a34c753fSRafael Auler for (const StringRef Name : BF.getNames()) { 59a34c753fSRafael Auler if (getLTOCommonName(Name)) 60a34c753fSRafael Auler return true; 61a34c753fSRafael Auler } 62a34c753fSRafael Auler return false; 63a34c753fSRafael Auler } 64a34c753fSRafael Auler 65a34c753fSRafael Auler /// Return standard escaped name of the function possibly renamed by BOLT. 66a34c753fSRafael Auler std::string normalizeName(StringRef NameRef) { 67a34c753fSRafael Auler // Strip "PG." prefix used for globalized locals. 68a34c753fSRafael Auler NameRef = NameRef.startswith("PG.") ? NameRef.substr(2) : NameRef; 69a34c753fSRafael Auler return getEscapedName(NameRef); 70a34c753fSRafael Auler } 71a34c753fSRafael Auler 72a34c753fSRafael Auler } // anonymous namespace 73a34c753fSRafael Auler 74a34c753fSRafael Auler raw_ostream &operator<<(raw_ostream &OS, const Location &Loc) { 75a34c753fSRafael Auler if (Loc.IsSymbol) { 76a34c753fSRafael Auler OS << Loc.Name; 77a34c753fSRafael Auler if (Loc.Offset) 78a34c753fSRafael Auler OS << "+" << Twine::utohexstr(Loc.Offset); 79a34c753fSRafael Auler } else { 80a34c753fSRafael Auler OS << Twine::utohexstr(Loc.Offset); 81a34c753fSRafael Auler } 82a34c753fSRafael Auler return OS; 83a34c753fSRafael Auler } 84a34c753fSRafael Auler 85a34c753fSRafael Auler void FuncBranchData::appendFrom(const FuncBranchData &FBD, uint64_t Offset) { 86a34c753fSRafael Auler Data.insert(Data.end(), FBD.Data.begin(), FBD.Data.end()); 87a34c753fSRafael Auler for (auto I = Data.begin(), E = Data.end(); I != E; ++I) { 88a34c753fSRafael Auler if (I->From.Name == FBD.Name) { 89a34c753fSRafael Auler I->From.Name = this->Name; 90a34c753fSRafael Auler I->From.Offset += Offset; 91a34c753fSRafael Auler } 92a34c753fSRafael Auler if (I->To.Name == FBD.Name) { 93a34c753fSRafael Auler I->To.Name = this->Name; 94a34c753fSRafael Auler I->To.Offset += Offset; 95a34c753fSRafael Auler } 96a34c753fSRafael Auler } 97a34c753fSRafael Auler std::stable_sort(Data.begin(), Data.end()); 98a34c753fSRafael Auler ExecutionCount += FBD.ExecutionCount; 99a34c753fSRafael Auler for (auto I = FBD.EntryData.begin(), E = FBD.EntryData.end(); I != E; ++I) { 100a34c753fSRafael Auler assert(I->To.Name == FBD.Name); 101a34c753fSRafael Auler auto NewElmt = EntryData.insert(EntryData.end(), *I); 102a34c753fSRafael Auler NewElmt->To.Name = this->Name; 103a34c753fSRafael Auler NewElmt->To.Offset += Offset; 104a34c753fSRafael Auler } 105a34c753fSRafael Auler } 106a34c753fSRafael Auler 107a34c753fSRafael Auler uint64_t FuncBranchData::getNumExecutedBranches() const { 108a34c753fSRafael Auler uint64_t ExecutedBranches = 0; 109a34c753fSRafael Auler for (const BranchInfo &BI : Data) { 110a34c753fSRafael Auler int64_t BranchCount = BI.Branches; 111a34c753fSRafael Auler assert(BranchCount >= 0 && "branch execution count should not be negative"); 112a34c753fSRafael Auler ExecutedBranches += BranchCount; 113a34c753fSRafael Auler } 114a34c753fSRafael Auler return ExecutedBranches; 115a34c753fSRafael Auler } 116a34c753fSRafael Auler 11740c2e0faSMaksim Panchenko void SampleInfo::mergeWith(const SampleInfo &SI) { Hits += SI.Hits; } 118a34c753fSRafael Auler 119a34c753fSRafael Auler void SampleInfo::print(raw_ostream &OS) const { 120a34c753fSRafael Auler OS << Loc.IsSymbol << " " << Loc.Name << " " << Twine::utohexstr(Loc.Offset) 121a34c753fSRafael Auler << " " << Hits << "\n"; 122a34c753fSRafael Auler } 123a34c753fSRafael Auler 12440c2e0faSMaksim Panchenko uint64_t FuncSampleData::getSamples(uint64_t Start, uint64_t End) const { 125a34c753fSRafael Auler assert(std::is_sorted(Data.begin(), Data.end())); 126a34c753fSRafael Auler struct Compare { 127a34c753fSRafael Auler bool operator()(const SampleInfo &SI, const uint64_t Val) const { 128a34c753fSRafael Auler return SI.Loc.Offset < Val; 129a34c753fSRafael Auler } 130a34c753fSRafael Auler bool operator()(const uint64_t Val, const SampleInfo &SI) const { 131a34c753fSRafael Auler return Val < SI.Loc.Offset; 132a34c753fSRafael Auler } 133a34c753fSRafael Auler }; 134a34c753fSRafael Auler uint64_t Result = 0; 135a34c753fSRafael Auler for (auto I = std::lower_bound(Data.begin(), Data.end(), Start, Compare()), 136a34c753fSRafael Auler E = std::lower_bound(Data.begin(), Data.end(), End, Compare()); 137a34c753fSRafael Auler I != E; ++I) { 138a34c753fSRafael Auler Result += I->Hits; 139a34c753fSRafael Auler } 140a34c753fSRafael Auler return Result; 141a34c753fSRafael Auler } 142a34c753fSRafael Auler 143a34c753fSRafael Auler void FuncSampleData::bumpCount(uint64_t Offset, uint64_t Count) { 144a34c753fSRafael Auler auto Iter = Index.find(Offset); 145a34c753fSRafael Auler if (Iter == Index.end()) { 146a34c753fSRafael Auler Data.emplace_back(Location(true, Name, Offset), Count); 147a34c753fSRafael Auler Index[Offset] = Data.size() - 1; 148a34c753fSRafael Auler return; 149a34c753fSRafael Auler } 150a34c753fSRafael Auler SampleInfo &SI = Data[Iter->second]; 151a34c753fSRafael Auler SI.Hits += Count; 152a34c753fSRafael Auler } 153a34c753fSRafael Auler 154a34c753fSRafael Auler void FuncBranchData::bumpBranchCount(uint64_t OffsetFrom, uint64_t OffsetTo, 155a34c753fSRafael Auler uint64_t Count, uint64_t Mispreds) { 156a34c753fSRafael Auler auto Iter = IntraIndex[OffsetFrom].find(OffsetTo); 157a34c753fSRafael Auler if (Iter == IntraIndex[OffsetFrom].end()) { 158a34c753fSRafael Auler Data.emplace_back(Location(true, Name, OffsetFrom), 159a34c753fSRafael Auler Location(true, Name, OffsetTo), Mispreds, Count); 160a34c753fSRafael Auler IntraIndex[OffsetFrom][OffsetTo] = Data.size() - 1; 161a34c753fSRafael Auler return; 162a34c753fSRafael Auler } 163a34c753fSRafael Auler BranchInfo &BI = Data[Iter->second]; 164a34c753fSRafael Auler BI.Branches += Count; 165a34c753fSRafael Auler BI.Mispreds += Mispreds; 166a34c753fSRafael Auler } 167a34c753fSRafael Auler 168a34c753fSRafael Auler void FuncBranchData::bumpCallCount(uint64_t OffsetFrom, const Location &To, 169a34c753fSRafael Auler uint64_t Count, uint64_t Mispreds) { 170a34c753fSRafael Auler auto Iter = InterIndex[OffsetFrom].find(To); 171a34c753fSRafael Auler if (Iter == InterIndex[OffsetFrom].end()) { 172a34c753fSRafael Auler Data.emplace_back(Location(true, Name, OffsetFrom), To, Mispreds, Count); 173a34c753fSRafael Auler InterIndex[OffsetFrom][To] = Data.size() - 1; 174a34c753fSRafael Auler return; 175a34c753fSRafael Auler } 176a34c753fSRafael Auler BranchInfo &BI = Data[Iter->second]; 177a34c753fSRafael Auler BI.Branches += Count; 178a34c753fSRafael Auler BI.Mispreds += Mispreds; 179a34c753fSRafael Auler } 180a34c753fSRafael Auler 181a34c753fSRafael Auler void FuncBranchData::bumpEntryCount(const Location &From, uint64_t OffsetTo, 182a34c753fSRafael Auler uint64_t Count, uint64_t Mispreds) { 183a34c753fSRafael Auler auto Iter = EntryIndex[OffsetTo].find(From); 184a34c753fSRafael Auler if (Iter == EntryIndex[OffsetTo].end()) { 185a34c753fSRafael Auler EntryData.emplace_back(From, Location(true, Name, OffsetTo), Mispreds, 186a34c753fSRafael Auler Count); 187a34c753fSRafael Auler EntryIndex[OffsetTo][From] = EntryData.size() - 1; 188a34c753fSRafael Auler return; 189a34c753fSRafael Auler } 190a34c753fSRafael Auler BranchInfo &BI = EntryData[Iter->second]; 191a34c753fSRafael Auler BI.Branches += Count; 192a34c753fSRafael Auler BI.Mispreds += Mispreds; 193a34c753fSRafael Auler } 194a34c753fSRafael Auler 195a34c753fSRafael Auler void BranchInfo::mergeWith(const BranchInfo &BI) { 196a34c753fSRafael Auler Branches += BI.Branches; 197a34c753fSRafael Auler Mispreds += BI.Mispreds; 198a34c753fSRafael Auler } 199a34c753fSRafael Auler 200a34c753fSRafael Auler void BranchInfo::print(raw_ostream &OS) const { 201a34c753fSRafael Auler OS << From.IsSymbol << " " << From.Name << " " 20240c2e0faSMaksim Panchenko << Twine::utohexstr(From.Offset) << " " << To.IsSymbol << " " << To.Name 20340c2e0faSMaksim Panchenko << " " << Twine::utohexstr(To.Offset) << " " << Mispreds << " " << Branches 20440c2e0faSMaksim Panchenko << '\n'; 205a34c753fSRafael Auler } 206a34c753fSRafael Auler 207a34c753fSRafael Auler ErrorOr<const BranchInfo &> FuncBranchData::getBranch(uint64_t From, 208a34c753fSRafael Auler uint64_t To) const { 209a34c753fSRafael Auler for (const BranchInfo &I : Data) { 21040c2e0faSMaksim Panchenko if (I.From.Offset == From && I.To.Offset == To && I.From.Name == I.To.Name) 211a34c753fSRafael Auler return I; 212a34c753fSRafael Auler } 213a34c753fSRafael Auler return make_error_code(llvm::errc::invalid_argument); 214a34c753fSRafael Auler } 215a34c753fSRafael Auler 216a34c753fSRafael Auler ErrorOr<const BranchInfo &> 217a34c753fSRafael Auler FuncBranchData::getDirectCallBranch(uint64_t From) const { 218a34c753fSRafael Auler // Commented out because it can be expensive. 219a34c753fSRafael Auler // assert(std::is_sorted(Data.begin(), Data.end())); 220a34c753fSRafael Auler struct Compare { 221a34c753fSRafael Auler bool operator()(const BranchInfo &BI, const uint64_t Val) const { 222a34c753fSRafael Auler return BI.From.Offset < Val; 223a34c753fSRafael Auler } 224a34c753fSRafael Auler bool operator()(const uint64_t Val, const BranchInfo &BI) const { 225a34c753fSRafael Auler return Val < BI.From.Offset; 226a34c753fSRafael Auler } 227a34c753fSRafael Auler }; 228a34c753fSRafael Auler auto Range = std::equal_range(Data.begin(), Data.end(), From, Compare()); 229a34c753fSRafael Auler for (auto I = Range.first; I != Range.second; ++I) { 230a34c753fSRafael Auler if (I->From.Name != I->To.Name) 231a34c753fSRafael Auler return *I; 232a34c753fSRafael Auler } 233a34c753fSRafael Auler return make_error_code(llvm::errc::invalid_argument); 234a34c753fSRafael Auler } 235a34c753fSRafael Auler 236a34c753fSRafael Auler void MemInfo::print(raw_ostream &OS) const { 237a34c753fSRafael Auler OS << (Offset.IsSymbol + 3) << " " << Offset.Name << " " 23840c2e0faSMaksim Panchenko << Twine::utohexstr(Offset.Offset) << " " << (Addr.IsSymbol + 3) << " " 23940c2e0faSMaksim Panchenko << Addr.Name << " " << Twine::utohexstr(Addr.Offset) << " " << Count 24040c2e0faSMaksim Panchenko << "\n"; 241a34c753fSRafael Auler } 242a34c753fSRafael Auler 243a34c753fSRafael Auler void MemInfo::prettyPrint(raw_ostream &OS) const { 244a34c753fSRafael Auler OS << "(PC: " << Offset << ", M: " << Addr << ", C: " << Count << ")"; 245a34c753fSRafael Auler } 246a34c753fSRafael Auler 247a34c753fSRafael Auler void FuncMemData::update(const Location &Offset, const Location &Addr) { 248a34c753fSRafael Auler auto Iter = EventIndex[Offset.Offset].find(Addr); 249a34c753fSRafael Auler if (Iter == EventIndex[Offset.Offset].end()) { 250a34c753fSRafael Auler Data.emplace_back(MemInfo(Offset, Addr, 1)); 251a34c753fSRafael Auler EventIndex[Offset.Offset][Addr] = Data.size() - 1; 252a34c753fSRafael Auler return; 253a34c753fSRafael Auler } 254a34c753fSRafael Auler ++Data[Iter->second].Count; 255a34c753fSRafael Auler } 256a34c753fSRafael Auler 257a34c753fSRafael Auler Error DataReader::preprocessProfile(BinaryContext &BC) { 258a34c753fSRafael Auler if (std::error_code EC = parseInput()) { 259a34c753fSRafael Auler return errorCodeToError(EC); 260a34c753fSRafael Auler } 261a34c753fSRafael Auler 262a34c753fSRafael Auler if (opts::DumpData) { 263a34c753fSRafael Auler dump(); 264a34c753fSRafael Auler } 265a34c753fSRafael Auler 266a34c753fSRafael Auler if (collectedInBoltedBinary()) { 267a34c753fSRafael Auler outs() << "BOLT-INFO: profile collection done on a binary already " 268a34c753fSRafael Auler "processed by BOLT\n"; 269a34c753fSRafael Auler } 270a34c753fSRafael Auler 271a34c753fSRafael Auler for (auto &BFI : BC.getBinaryFunctions()) { 272a34c753fSRafael Auler BinaryFunction &Function = BFI.second; 273a34c753fSRafael Auler if (FuncMemData *MemData = getMemDataForNames(Function.getNames())) { 274a34c753fSRafael Auler setMemData(Function, MemData); 275a34c753fSRafael Auler MemData->Used = true; 276a34c753fSRafael Auler } 277a34c753fSRafael Auler if (FuncBranchData *FuncData = getBranchDataForNames(Function.getNames())) { 278a34c753fSRafael Auler setBranchData(Function, FuncData); 279a34c753fSRafael Auler Function.ExecutionCount = FuncData->ExecutionCount; 280a34c753fSRafael Auler FuncData->Used = true; 281a34c753fSRafael Auler } 282a34c753fSRafael Auler } 283a34c753fSRafael Auler 284a34c753fSRafael Auler for (auto &BFI : BC.getBinaryFunctions()) { 285a34c753fSRafael Auler BinaryFunction &Function = BFI.second; 286a34c753fSRafael Auler matchProfileMemData(Function); 287a34c753fSRafael Auler } 288a34c753fSRafael Auler 289a34c753fSRafael Auler return Error::success(); 290a34c753fSRafael Auler } 291a34c753fSRafael Auler 292a34c753fSRafael Auler Error DataReader::readProfilePreCFG(BinaryContext &BC) { 293a34c753fSRafael Auler for (auto &BFI : BC.getBinaryFunctions()) { 294a34c753fSRafael Auler BinaryFunction &Function = BFI.second; 295a34c753fSRafael Auler FuncMemData *MemoryData = getMemData(Function); 296a34c753fSRafael Auler if (!MemoryData) 297a34c753fSRafael Auler continue; 298a34c753fSRafael Auler 299a34c753fSRafael Auler for (MemInfo &MI : MemoryData->Data) { 300a34c753fSRafael Auler const uint64_t Offset = MI.Offset.Offset; 301a34c753fSRafael Auler auto II = Function.Instructions.find(Offset); 302a34c753fSRafael Auler if (II == Function.Instructions.end()) { 303a34c753fSRafael Auler // Ignore bad instruction address. 304a34c753fSRafael Auler continue; 305a34c753fSRafael Auler } 306a34c753fSRafael Auler 307a34c753fSRafael Auler auto &MemAccessProfile = 308a34c753fSRafael Auler BC.MIB->getOrCreateAnnotationAs<MemoryAccessProfile>( 309a34c753fSRafael Auler II->second, "MemoryAccessProfile"); 310a34c753fSRafael Auler BinaryData *BD = nullptr; 311a34c753fSRafael Auler if (MI.Addr.IsSymbol) { 312a34c753fSRafael Auler BD = BC.getBinaryDataByName(MI.Addr.Name); 313a34c753fSRafael Auler } 31440c2e0faSMaksim Panchenko MemAccessProfile.AddressAccessInfo.push_back( 31540c2e0faSMaksim Panchenko {BD, MI.Addr.Offset, MI.Count}); 316a34c753fSRafael Auler auto NextII = std::next(II); 317a34c753fSRafael Auler if (NextII == Function.Instructions.end()) { 318a34c753fSRafael Auler MemAccessProfile.NextInstrOffset = Function.getSize(); 319a34c753fSRafael Auler } else { 320a34c753fSRafael Auler MemAccessProfile.NextInstrOffset = II->first; 321a34c753fSRafael Auler } 322a34c753fSRafael Auler } 323a34c753fSRafael Auler Function.HasMemoryProfile = true; 324a34c753fSRafael Auler } 325a34c753fSRafael Auler 326a34c753fSRafael Auler return Error::success(); 327a34c753fSRafael Auler } 328a34c753fSRafael Auler 329a34c753fSRafael Auler Error DataReader::readProfile(BinaryContext &BC) { 330a34c753fSRafael Auler for (auto &BFI : BC.getBinaryFunctions()) { 331a34c753fSRafael Auler BinaryFunction &Function = BFI.second; 332a34c753fSRafael Auler readProfile(Function); 333a34c753fSRafael Auler } 334a34c753fSRafael Auler 335a34c753fSRafael Auler uint64_t NumUnused = 0; 336a34c753fSRafael Auler for (const StringMapEntry<FuncBranchData> &FuncData : NamesToBranches) 337a34c753fSRafael Auler if (!FuncData.getValue().Used) 338a34c753fSRafael Auler ++NumUnused; 339a34c753fSRafael Auler BC.setNumUnusedProfiledObjects(NumUnused); 340a34c753fSRafael Auler 341a34c753fSRafael Auler return Error::success(); 342a34c753fSRafael Auler } 343a34c753fSRafael Auler 344a34c753fSRafael Auler std::error_code DataReader::parseInput() { 345a34c753fSRafael Auler ErrorOr<std::unique_ptr<MemoryBuffer>> MB = 346a34c753fSRafael Auler MemoryBuffer::getFileOrSTDIN(Filename); 347a34c753fSRafael Auler if (std::error_code EC = MB.getError()) { 348a34c753fSRafael Auler Diag << "cannot open " << Filename << ": " << EC.message() << "\n"; 349a34c753fSRafael Auler return EC; 350a34c753fSRafael Auler } 351a34c753fSRafael Auler FileBuf = std::move(MB.get()); 352a34c753fSRafael Auler ParsingBuf = FileBuf->getBuffer(); 353a34c753fSRafael Auler if (std::error_code EC = parse()) { 354a34c753fSRafael Auler return EC; 355a34c753fSRafael Auler } 356a34c753fSRafael Auler if (!ParsingBuf.empty()) { 357a34c753fSRafael Auler Diag << "WARNING: invalid profile data detected at line " << Line 358a34c753fSRafael Auler << ". Possibly corrupted profile.\n"; 359a34c753fSRafael Auler } 360a34c753fSRafael Auler 361a34c753fSRafael Auler buildLTONameMaps(); 362a34c753fSRafael Auler 363a34c753fSRafael Auler return std::error_code(); 364a34c753fSRafael Auler } 365a34c753fSRafael Auler 366a34c753fSRafael Auler void DataReader::readProfile(BinaryFunction &BF) { 367a34c753fSRafael Auler if (BF.empty()) 368a34c753fSRafael Auler return; 369a34c753fSRafael Auler 370a34c753fSRafael Auler if (!hasLBR()) { 371a34c753fSRafael Auler BF.ProfileFlags = BinaryFunction::PF_SAMPLE; 372a34c753fSRafael Auler readSampleData(BF); 373a34c753fSRafael Auler return; 374a34c753fSRafael Auler } 375a34c753fSRafael Auler 376a34c753fSRafael Auler BF.ProfileFlags = BinaryFunction::PF_LBR; 377a34c753fSRafael Auler 378a34c753fSRafael Auler // Possibly assign/re-assign branch profile data. 379a34c753fSRafael Auler matchProfileData(BF); 380a34c753fSRafael Auler 381a34c753fSRafael Auler FuncBranchData *FBD = getBranchData(BF); 382a34c753fSRafael Auler if (!FBD) 383a34c753fSRafael Auler return; 384a34c753fSRafael Auler 385a34c753fSRafael Auler // Assign basic block counts to function entry points. These only include 386a34c753fSRafael Auler // counts for outside entries. 387a34c753fSRafael Auler // 388a34c753fSRafael Auler // There is a slight skew introduced here as branches originated from RETs 389a34c753fSRafael Auler // may be accounted for in the execution count of an entry block if the last 390a34c753fSRafael Auler // instruction in a predecessor fall-through block is a call. This situation 391a34c753fSRafael Auler // should rarely happen because there are few multiple-entry functions. 392a34c753fSRafael Auler for (const BranchInfo &BI : FBD->EntryData) { 393a34c753fSRafael Auler BinaryBasicBlock *BB = BF.getBasicBlockAtOffset(BI.To.Offset); 394a34c753fSRafael Auler if (BB && (BB->isEntryPoint() || BB->isLandingPad())) { 395a34c753fSRafael Auler uint64_t Count = BB->getExecutionCount(); 396a34c753fSRafael Auler if (Count == BinaryBasicBlock::COUNT_NO_PROFILE) 397a34c753fSRafael Auler Count = 0; 398a34c753fSRafael Auler BB->setExecutionCount(Count + BI.Branches); 399a34c753fSRafael Auler } 400a34c753fSRafael Auler } 401a34c753fSRafael Auler 402a34c753fSRafael Auler uint64_t MismatchedBranches = 0; 403a34c753fSRafael Auler for (const BranchInfo &BI : FBD->Data) { 404a34c753fSRafael Auler if (BI.From.Name != BI.To.Name) { 405a34c753fSRafael Auler continue; 406a34c753fSRafael Auler } 407a34c753fSRafael Auler 40840c2e0faSMaksim Panchenko if (!recordBranch(BF, BI.From.Offset, BI.To.Offset, BI.Branches, 40940c2e0faSMaksim Panchenko BI.Mispreds)) { 410a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "bad branch : " << BI.From.Offset << " -> " 411a34c753fSRafael Auler << BI.To.Offset << '\n'); 412a34c753fSRafael Auler ++MismatchedBranches; 413a34c753fSRafael Auler } 414a34c753fSRafael Auler } 415a34c753fSRafael Auler 416a34c753fSRafael Auler // Convert branch data into annotations. 417a34c753fSRafael Auler convertBranchData(BF); 418a34c753fSRafael Auler } 419a34c753fSRafael Auler 420a34c753fSRafael Auler void DataReader::matchProfileData(BinaryFunction &BF) { 421a34c753fSRafael Auler // This functionality is available for LBR-mode only 422a34c753fSRafael Auler // TODO: Implement evaluateProfileData() for samples, checking whether 423a34c753fSRafael Auler // sample addresses match instruction addresses in the function 424a34c753fSRafael Auler if (!hasLBR()) 425a34c753fSRafael Auler return; 426a34c753fSRafael Auler 427a34c753fSRafael Auler FuncBranchData *FBD = getBranchData(BF); 428a34c753fSRafael Auler if (FBD) { 429a34c753fSRafael Auler BF.ProfileMatchRatio = evaluateProfileData(BF, *FBD); 430a34c753fSRafael Auler BF.RawBranchCount = FBD->getNumExecutedBranches(); 431a34c753fSRafael Auler if (BF.ProfileMatchRatio == 1.0f) { 432a34c753fSRafael Auler if (fetchProfileForOtherEntryPoints(BF)) { 433a34c753fSRafael Auler BF.ProfileMatchRatio = evaluateProfileData(BF, *FBD); 434a34c753fSRafael Auler BF.ExecutionCount = FBD->ExecutionCount; 435a34c753fSRafael Auler BF.RawBranchCount = FBD->getNumExecutedBranches(); 436a34c753fSRafael Auler } 437a34c753fSRafael Auler return; 438a34c753fSRafael Auler } 439a34c753fSRafael Auler } 440a34c753fSRafael Auler 441a34c753fSRafael Auler // Check if the function name can fluctuate between several compilations 442a34c753fSRafael Auler // possibly triggered by minor unrelated code changes in the source code 443a34c753fSRafael Auler // of the input binary. 444a34c753fSRafael Auler if (!hasVolatileName(BF)) 445a34c753fSRafael Auler return; 446a34c753fSRafael Auler 447a34c753fSRafael Auler // Check for a profile that matches with 100% confidence. 448a34c753fSRafael Auler const std::vector<FuncBranchData *> AllBranchData = 449a34c753fSRafael Auler getBranchDataForNamesRegex(BF.getNames()); 450a34c753fSRafael Auler for (FuncBranchData *NewBranchData : AllBranchData) { 451a34c753fSRafael Auler // Prevent functions from sharing the same profile. 452a34c753fSRafael Auler if (NewBranchData->Used) 453a34c753fSRafael Auler continue; 454a34c753fSRafael Auler 455a34c753fSRafael Auler if (evaluateProfileData(BF, *NewBranchData) != 1.0f) 456a34c753fSRafael Auler continue; 457a34c753fSRafael Auler 458a34c753fSRafael Auler if (FBD) 459a34c753fSRafael Auler FBD->Used = false; 460a34c753fSRafael Auler 461a34c753fSRafael Auler // Update function profile data with the new set. 462a34c753fSRafael Auler setBranchData(BF, NewBranchData); 463a34c753fSRafael Auler NewBranchData->Used = true; 464a34c753fSRafael Auler BF.ExecutionCount = NewBranchData->ExecutionCount; 465a34c753fSRafael Auler BF.ProfileMatchRatio = 1.0f; 466a34c753fSRafael Auler break; 467a34c753fSRafael Auler } 468a34c753fSRafael Auler } 469a34c753fSRafael Auler 470a34c753fSRafael Auler void DataReader::matchProfileMemData(BinaryFunction &BF) { 471a34c753fSRafael Auler const std::vector<FuncMemData *> AllMemData = 472a34c753fSRafael Auler getMemDataForNamesRegex(BF.getNames()); 473a34c753fSRafael Auler for (FuncMemData *NewMemData : AllMemData) { 474a34c753fSRafael Auler // Prevent functions from sharing the same profile. 475a34c753fSRafael Auler if (NewMemData->Used) 476a34c753fSRafael Auler continue; 477a34c753fSRafael Auler 478a34c753fSRafael Auler if (FuncMemData *MD = getMemData(BF)) 479a34c753fSRafael Auler MD->Used = false; 480a34c753fSRafael Auler 481a34c753fSRafael Auler // Update function profile data with the new set. 482a34c753fSRafael Auler setMemData(BF, NewMemData); 483a34c753fSRafael Auler NewMemData->Used = true; 484a34c753fSRafael Auler break; 485a34c753fSRafael Auler } 486a34c753fSRafael Auler } 487a34c753fSRafael Auler 488a34c753fSRafael Auler bool DataReader::fetchProfileForOtherEntryPoints(BinaryFunction &BF) { 489a34c753fSRafael Auler BinaryContext &BC = BF.getBinaryContext(); 490a34c753fSRafael Auler 491a34c753fSRafael Auler FuncBranchData *FBD = getBranchData(BF); 492a34c753fSRafael Auler if (!FBD) 493a34c753fSRafael Auler return false; 494a34c753fSRafael Auler 495a34c753fSRafael Auler // Check if we are missing profiling data for secondary entry points 496a34c753fSRafael Auler bool First = true; 497a34c753fSRafael Auler bool Updated = false; 498a34c753fSRafael Auler for (BinaryBasicBlock *BB : BF.BasicBlocks) { 499a34c753fSRafael Auler if (First) { 500a34c753fSRafael Auler First = false; 501a34c753fSRafael Auler continue; 502a34c753fSRafael Auler } 503a34c753fSRafael Auler if (BB->isEntryPoint()) { 504a34c753fSRafael Auler uint64_t EntryAddress = BB->getOffset() + BF.getAddress(); 505a34c753fSRafael Auler // Look for branch data associated with this entry point 506a34c753fSRafael Auler if (BinaryData *BD = BC.getBinaryDataAtAddress(EntryAddress)) { 507a34c753fSRafael Auler if (FuncBranchData *Data = getBranchDataForSymbols(BD->getSymbols())) { 508a34c753fSRafael Auler FBD->appendFrom(*Data, BB->getOffset()); 509a34c753fSRafael Auler Data->Used = true; 510a34c753fSRafael Auler Updated = true; 511a34c753fSRafael Auler } 512a34c753fSRafael Auler } 513a34c753fSRafael Auler } 514a34c753fSRafael Auler } 515a34c753fSRafael Auler 516a34c753fSRafael Auler return Updated; 517a34c753fSRafael Auler } 518a34c753fSRafael Auler 519a34c753fSRafael Auler float DataReader::evaluateProfileData(BinaryFunction &BF, 520a34c753fSRafael Auler const FuncBranchData &BranchData) const { 521a34c753fSRafael Auler BinaryContext &BC = BF.getBinaryContext(); 522a34c753fSRafael Auler 523a34c753fSRafael Auler // Until we define a minimal profile, we consider an empty branch data to be 524a34c753fSRafael Auler // a valid profile. It could happen to a function without branches when we 525a34c753fSRafael Auler // still have an EntryData for the execution count. 526a34c753fSRafael Auler if (BranchData.Data.empty()) { 527a34c753fSRafael Auler return 1.0f; 528a34c753fSRafael Auler } 529a34c753fSRafael Auler 530a34c753fSRafael Auler uint64_t NumMatchedBranches = 0; 531a34c753fSRafael Auler for (const BranchInfo &BI : BranchData.Data) { 532a34c753fSRafael Auler bool IsValid = false; 533a34c753fSRafael Auler if (BI.From.Name == BI.To.Name) { 534a34c753fSRafael Auler // Try to record information with 0 count. 535a34c753fSRafael Auler IsValid = recordBranch(BF, BI.From.Offset, BI.To.Offset, 0); 536a34c753fSRafael Auler } else if (collectedInBoltedBinary()) { 537a34c753fSRafael Auler // We can't check branch source for collections in bolted binaries because 538a34c753fSRafael Auler // the source of the branch may be mapped to the first instruction in a BB 539a34c753fSRafael Auler // instead of the original branch (which may not exist in the source bin). 540a34c753fSRafael Auler IsValid = true; 541a34c753fSRafael Auler } else { 542a34c753fSRafael Auler // The branch has to originate from this function. 543a34c753fSRafael Auler // Check for calls, tail calls, rets and indirect branches. 544a34c753fSRafael Auler // When matching profiling info, we did not reach the stage 545a34c753fSRafael Auler // when we identify tail calls, so they are still represented 546a34c753fSRafael Auler // by regular branch instructions and we need isBranch() here. 547a34c753fSRafael Auler MCInst *Instr = BF.getInstructionAtOffset(BI.From.Offset); 548a34c753fSRafael Auler // If it's a prefix - skip it. 549a34c753fSRafael Auler if (Instr && BC.MIB->isPrefix(*Instr)) 550a34c753fSRafael Auler Instr = BF.getInstructionAtOffset(BI.From.Offset + 1); 55140c2e0faSMaksim Panchenko if (Instr && (BC.MIB->isCall(*Instr) || BC.MIB->isBranch(*Instr) || 552a34c753fSRafael Auler BC.MIB->isReturn(*Instr))) { 553a34c753fSRafael Auler IsValid = true; 554a34c753fSRafael Auler } 555a34c753fSRafael Auler } 556a34c753fSRafael Auler 557a34c753fSRafael Auler if (IsValid) { 558a34c753fSRafael Auler ++NumMatchedBranches; 559a34c753fSRafael Auler continue; 560a34c753fSRafael Auler } 561a34c753fSRafael Auler 562a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "\tinvalid branch in " << BF << " : 0x" 563a34c753fSRafael Auler << Twine::utohexstr(BI.From.Offset) << " -> "; 564a34c753fSRafael Auler if (BI.From.Name == BI.To.Name) dbgs() 565a34c753fSRafael Auler << "0x" << Twine::utohexstr(BI.To.Offset) << '\n'; 566a34c753fSRafael Auler else dbgs() << "<outbounds>\n";); 567a34c753fSRafael Auler } 568a34c753fSRafael Auler 569a34c753fSRafael Auler const float MatchRatio = (float)NumMatchedBranches / BranchData.Data.size(); 570a34c753fSRafael Auler if (opts::Verbosity >= 2 && NumMatchedBranches < BranchData.Data.size()) { 571a34c753fSRafael Auler errs() << "BOLT-WARNING: profile branches match only " 572a34c753fSRafael Auler << format("%.1f%%", MatchRatio * 100.0f) << " (" 573a34c753fSRafael Auler << NumMatchedBranches << '/' << BranchData.Data.size() 574a34c753fSRafael Auler << ") for function " << BF << '\n'; 575a34c753fSRafael Auler } 576a34c753fSRafael Auler 577a34c753fSRafael Auler return MatchRatio; 578a34c753fSRafael Auler } 579a34c753fSRafael Auler 580a34c753fSRafael Auler void DataReader::readSampleData(BinaryFunction &BF) { 581a34c753fSRafael Auler FuncSampleData *SampleDataOrErr = getFuncSampleData(BF.getNames()); 582a34c753fSRafael Auler if (!SampleDataOrErr) 583a34c753fSRafael Auler return; 584a34c753fSRafael Auler 585a34c753fSRafael Auler // Basic samples mode territory (without LBR info) 586a34c753fSRafael Auler // First step is to assign BB execution count based on samples from perf 587a34c753fSRafael Auler BF.ProfileMatchRatio = 1.0f; 588a34c753fSRafael Auler BF.removeTagsFromProfile(); 589a34c753fSRafael Auler bool NormalizeByInsnCount = usesEvent("cycles") || usesEvent("instructions"); 590a34c753fSRafael Auler bool NormalizeByCalls = usesEvent("branches"); 591a34c753fSRafael Auler static bool NagUser = true; 592a34c753fSRafael Auler if (NagUser) { 593a34c753fSRafael Auler outs() 594a34c753fSRafael Auler << "BOLT-INFO: operating with basic samples profiling data (no LBR).\n"; 595a34c753fSRafael Auler if (NormalizeByInsnCount) { 596a34c753fSRafael Auler outs() << "BOLT-INFO: normalizing samples by instruction count.\n"; 597a34c753fSRafael Auler } else if (NormalizeByCalls) { 598a34c753fSRafael Auler outs() << "BOLT-INFO: normalizing samples by branches.\n"; 599a34c753fSRafael Auler } 600a34c753fSRafael Auler NagUser = false; 601a34c753fSRafael Auler } 602a34c753fSRafael Auler uint64_t LastOffset = BF.getSize(); 603a34c753fSRafael Auler uint64_t TotalEntryCount = 0; 604a34c753fSRafael Auler for (auto I = BF.BasicBlockOffsets.rbegin(), E = BF.BasicBlockOffsets.rend(); 605a34c753fSRafael Auler I != E; ++I) { 606a34c753fSRafael Auler uint64_t CurOffset = I->first; 607a34c753fSRafael Auler // Always work with samples multiplied by 1000 to avoid losing them if we 608a34c753fSRafael Auler // later need to normalize numbers 609a34c753fSRafael Auler uint64_t NumSamples = 610a34c753fSRafael Auler SampleDataOrErr->getSamples(CurOffset, LastOffset) * 1000; 611a34c753fSRafael Auler if (NormalizeByInsnCount && I->second->getNumNonPseudos()) 612a34c753fSRafael Auler NumSamples /= I->second->getNumNonPseudos(); 613a34c753fSRafael Auler else if (NormalizeByCalls) { 614a34c753fSRafael Auler uint32_t NumCalls = I->second->getNumCalls(); 615a34c753fSRafael Auler NumSamples /= NumCalls + 1; 616a34c753fSRafael Auler } 617a34c753fSRafael Auler I->second->setExecutionCount(NumSamples); 618a34c753fSRafael Auler if (I->second->isEntryPoint()) 619a34c753fSRafael Auler TotalEntryCount += NumSamples; 620a34c753fSRafael Auler LastOffset = CurOffset; 621a34c753fSRafael Auler } 622a34c753fSRafael Auler 623a34c753fSRafael Auler BF.ExecutionCount = TotalEntryCount; 624a34c753fSRafael Auler 625a34c753fSRafael Auler estimateEdgeCounts(BF); 626a34c753fSRafael Auler } 627a34c753fSRafael Auler 628a34c753fSRafael Auler void DataReader::convertBranchData(BinaryFunction &BF) const { 629a34c753fSRafael Auler BinaryContext &BC = BF.getBinaryContext(); 630a34c753fSRafael Auler 631a34c753fSRafael Auler if (BF.empty()) 632a34c753fSRafael Auler return; 633a34c753fSRafael Auler 634a34c753fSRafael Auler FuncBranchData *FBD = getBranchData(BF); 635a34c753fSRafael Auler if (!FBD) 636a34c753fSRafael Auler return; 637a34c753fSRafael Auler 638a34c753fSRafael Auler // Profile information for calls. 639a34c753fSRafael Auler // 640a34c753fSRafael Auler // There are 3 cases that we annotate differently: 641a34c753fSRafael Auler // 1) Conditional tail calls that could be mispredicted. 642a34c753fSRafael Auler // 2) Indirect calls to multiple destinations with mispredictions. 643a34c753fSRafael Auler // Before we validate CFG we have to handle indirect branches here too. 644a34c753fSRafael Auler // 3) Regular direct calls. The count could be different from containing 645a34c753fSRafael Auler // basic block count. Keep this data in case we find it useful. 646a34c753fSRafael Auler // 647a34c753fSRafael Auler for (BranchInfo &BI : FBD->Data) { 648a34c753fSRafael Auler // Ignore internal branches. 649a34c753fSRafael Auler if (BI.To.IsSymbol && BI.To.Name == BI.From.Name && BI.To.Offset != 0) 650a34c753fSRafael Auler continue; 651a34c753fSRafael Auler 652a34c753fSRafael Auler MCInst *Instr = BF.getInstructionAtOffset(BI.From.Offset); 653a34c753fSRafael Auler if (!Instr || 654a34c753fSRafael Auler (!BC.MIB->isCall(*Instr) && !BC.MIB->isIndirectBranch(*Instr))) 655a34c753fSRafael Auler continue; 656a34c753fSRafael Auler 657a34c753fSRafael Auler auto setOrUpdateAnnotation = [&](StringRef Name, uint64_t Count) { 658a34c753fSRafael Auler if (opts::Verbosity >= 1 && BC.MIB->hasAnnotation(*Instr, Name)) { 659a34c753fSRafael Auler errs() << "BOLT-WARNING: duplicate " << Name << " info for offset 0x" 66040c2e0faSMaksim Panchenko << Twine::utohexstr(BI.From.Offset) << " in function " << BF 66140c2e0faSMaksim Panchenko << '\n'; 662a34c753fSRafael Auler } 663a34c753fSRafael Auler auto &Value = BC.MIB->getOrCreateAnnotationAs<uint64_t>(*Instr, Name); 664a34c753fSRafael Auler Value += Count; 665a34c753fSRafael Auler }; 666a34c753fSRafael Auler 667a34c753fSRafael Auler if (BC.MIB->isIndirectCall(*Instr) || BC.MIB->isIndirectBranch(*Instr)) { 668a34c753fSRafael Auler IndirectCallSiteProfile &CSP = 669a34c753fSRafael Auler BC.MIB->getOrCreateAnnotationAs<IndirectCallSiteProfile>( 670a34c753fSRafael Auler *Instr, "CallProfile"); 671a34c753fSRafael Auler MCSymbol *CalleeSymbol = nullptr; 672a34c753fSRafael Auler if (BI.To.IsSymbol) { 673a34c753fSRafael Auler if (BinaryData *BD = BC.getBinaryDataByName(BI.To.Name)) { 674a34c753fSRafael Auler CalleeSymbol = BD->getSymbol(); 675a34c753fSRafael Auler } 676a34c753fSRafael Auler } 677a34c753fSRafael Auler CSP.emplace_back(CalleeSymbol, BI.Branches, BI.Mispreds); 678a34c753fSRafael Auler } else if (BC.MIB->getConditionalTailCall(*Instr)) { 679a34c753fSRafael Auler setOrUpdateAnnotation("CTCTakenCount", BI.Branches); 680a34c753fSRafael Auler setOrUpdateAnnotation("CTCMispredCount", BI.Mispreds); 681a34c753fSRafael Auler } else { 682a34c753fSRafael Auler setOrUpdateAnnotation("Count", BI.Branches); 683a34c753fSRafael Auler } 684a34c753fSRafael Auler } 685a34c753fSRafael Auler } 686a34c753fSRafael Auler 68740c2e0faSMaksim Panchenko bool DataReader::recordBranch(BinaryFunction &BF, uint64_t From, uint64_t To, 688a34c753fSRafael Auler uint64_t Count, uint64_t Mispreds) const { 689a34c753fSRafael Auler BinaryContext &BC = BF.getBinaryContext(); 690a34c753fSRafael Auler 691a34c753fSRafael Auler BinaryBasicBlock *FromBB = BF.getBasicBlockContainingOffset(From); 692a34c753fSRafael Auler BinaryBasicBlock *ToBB = BF.getBasicBlockContainingOffset(To); 693a34c753fSRafael Auler 694a34c753fSRafael Auler if (!FromBB || !ToBB) { 695a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "failed to get block for recorded branch\n"); 696a34c753fSRafael Auler return false; 697a34c753fSRafael Auler } 698a34c753fSRafael Auler 699a34c753fSRafael Auler // Could be bad LBR data; ignore the branch. In the case of data collected 700a34c753fSRafael Auler // in binaries optimized by BOLT, a source BB may be mapped to two output 701a34c753fSRafael Auler // BBs as a result of optimizations. In that case, a branch between these 702a34c753fSRafael Auler // two will be recorded as a branch from A going to A in the source address 703a34c753fSRafael Auler // space. Keep processing. 704a34c753fSRafael Auler if (From == To) { 705a34c753fSRafael Auler return true; 706a34c753fSRafael Auler } 707a34c753fSRafael Auler 708a34c753fSRafael Auler // Return from a tail call. 709ccb99dd1SMaksim Panchenko if (FromBB->succ_size() == 0) 710a34c753fSRafael Auler return true; 711a34c753fSRafael Auler 712a34c753fSRafael Auler // Very rarely we will see ignored branches. Do a linear check. 713a34c753fSRafael Auler for (std::pair<uint32_t, uint32_t> &Branch : BF.IgnoredBranches) { 71440c2e0faSMaksim Panchenko if (Branch == 71540c2e0faSMaksim Panchenko std::make_pair(static_cast<uint32_t>(From), static_cast<uint32_t>(To))) 716a34c753fSRafael Auler return true; 717a34c753fSRafael Auler } 718a34c753fSRafael Auler 71908f56926SVladislav Khmelevsky bool OffsetMatches = !!(To == ToBB->getOffset()); 72008f56926SVladislav Khmelevsky if (!OffsetMatches) { 72108f56926SVladislav Khmelevsky // Skip the nops to support old .fdata 72208f56926SVladislav Khmelevsky uint64_t Offset = ToBB->getOffset(); 72308f56926SVladislav Khmelevsky for (MCInst &Instr : *ToBB) { 72408f56926SVladislav Khmelevsky if (!BC.MIB->isNoop(Instr)) 72508f56926SVladislav Khmelevsky break; 72608f56926SVladislav Khmelevsky 72708f56926SVladislav Khmelevsky Offset += BC.MIB->getAnnotationWithDefault<uint32_t>(Instr, "Size"); 72808f56926SVladislav Khmelevsky } 72908f56926SVladislav Khmelevsky 73008f56926SVladislav Khmelevsky if (To == Offset) 73108f56926SVladislav Khmelevsky OffsetMatches = true; 73208f56926SVladislav Khmelevsky } 73308f56926SVladislav Khmelevsky 73408f56926SVladislav Khmelevsky if (!OffsetMatches) { 735a34c753fSRafael Auler // "To" could be referring to nop instructions in between 2 basic blocks. 736a34c753fSRafael Auler // While building the CFG we make sure these nops are attributed to the 737a34c753fSRafael Auler // previous basic block, thus we check if the destination belongs to the 738a34c753fSRafael Auler // gap past the last instruction. 739a34c753fSRafael Auler const MCInst *LastInstr = ToBB->getLastNonPseudoInstr(); 740a34c753fSRafael Auler if (LastInstr) { 741a34c753fSRafael Auler const uint32_t LastInstrOffset = 742a34c753fSRafael Auler BC.MIB->getAnnotationWithDefault<uint32_t>(*LastInstr, "Offset"); 743a34c753fSRafael Auler 744a34c753fSRafael Auler // With old .fdata we are getting FT branches for "jcc,jmp" sequences. 745a34c753fSRafael Auler if (To == LastInstrOffset && BC.MIB->isUnconditionalBranch(*LastInstr)) { 746a34c753fSRafael Auler return true; 747a34c753fSRafael Auler } 748a34c753fSRafael Auler 749a34c753fSRafael Auler if (To <= LastInstrOffset) { 750a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "branch recorded into the middle of the block" 751a34c753fSRafael Auler << " in " << BF << " : " << From << " -> " << To 752a34c753fSRafael Auler << '\n'); 753a34c753fSRafael Auler return false; 754a34c753fSRafael Auler } 755a34c753fSRafael Auler } 756a34c753fSRafael Auler 757a34c753fSRafael Auler // The real destination is the layout successor of the detected ToBB. 758a34c753fSRafael Auler if (ToBB == BF.BasicBlocksLayout.back()) 759a34c753fSRafael Auler return false; 760a34c753fSRafael Auler BinaryBasicBlock *NextBB = BF.BasicBlocksLayout[ToBB->getIndex() + 1]; 761a34c753fSRafael Auler assert((NextBB && NextBB->getOffset() > ToBB->getOffset()) && "bad layout"); 762a34c753fSRafael Auler ToBB = NextBB; 763a34c753fSRafael Auler } 764a34c753fSRafael Auler 765a34c753fSRafael Auler // If there's no corresponding instruction for 'From', we have probably 766a34c753fSRafael Auler // discarded it as a FT from __builtin_unreachable. 767a34c753fSRafael Auler MCInst *FromInstruction = BF.getInstructionAtOffset(From); 768a34c753fSRafael Auler if (!FromInstruction) { 769a34c753fSRafael Auler // If the data was collected in a bolted binary, the From addresses may be 770a34c753fSRafael Auler // translated to the first instruction of the source BB if BOLT inserted 771a34c753fSRafael Auler // a new branch that did not exist in the source (we can't map it to the 772a34c753fSRafael Auler // source instruction, so we map it to the first instr of source BB). 773a34c753fSRafael Auler // We do not keep offsets for random instructions. So the check above will 774a34c753fSRafael Auler // evaluate to true if the first instr is not a branch (call/jmp/ret/etc) 775a34c753fSRafael Auler if (collectedInBoltedBinary()) { 776a34c753fSRafael Auler if (FromBB->getInputOffset() != From) { 777a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "offset " << From << " does not match a BB in " 778a34c753fSRafael Auler << BF << '\n'); 779a34c753fSRafael Auler return false; 780a34c753fSRafael Auler } 781a34c753fSRafael Auler FromInstruction = nullptr; 782a34c753fSRafael Auler } else { 783a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "no instruction for offset " << From << " in " << BF 784a34c753fSRafael Auler << '\n'); 785a34c753fSRafael Auler return false; 786a34c753fSRafael Auler } 787a34c753fSRafael Auler } 788a34c753fSRafael Auler 789a34c753fSRafael Auler if (!FromBB->getSuccessor(ToBB->getLabel())) { 790a34c753fSRafael Auler // Check if this is a recursive call or a return from a recursive call. 791a34c753fSRafael Auler if (FromInstruction && ToBB->isEntryPoint() && 792a34c753fSRafael Auler (BC.MIB->isCall(*FromInstruction) || 793a34c753fSRafael Auler BC.MIB->isIndirectBranch(*FromInstruction))) { 794a34c753fSRafael Auler // Execution count is already accounted for. 795a34c753fSRafael Auler return true; 796a34c753fSRafael Auler } 797a34c753fSRafael Auler // For data collected in a bolted binary, we may have created two output BBs 798a34c753fSRafael Auler // that map to one original block. Branches between these two blocks will 79940c2e0faSMaksim Panchenko // appear here as one BB jumping to itself, even though it has no loop 80040c2e0faSMaksim Panchenko // edges. Ignore these. 801a34c753fSRafael Auler if (collectedInBoltedBinary() && FromBB == ToBB) 802a34c753fSRafael Auler return true; 803a34c753fSRafael Auler 804ccb99dd1SMaksim Panchenko BinaryBasicBlock *FTSuccessor = FromBB->getConditionalSuccessor(false); 805ccb99dd1SMaksim Panchenko if (FTSuccessor && FTSuccessor->succ_size() == 1 && 806ccb99dd1SMaksim Panchenko FTSuccessor->getSuccessor(ToBB->getLabel())) { 807ccb99dd1SMaksim Panchenko BinaryBasicBlock::BinaryBranchInfo &FTBI = 808ccb99dd1SMaksim Panchenko FTSuccessor->getBranchInfo(*ToBB); 809ccb99dd1SMaksim Panchenko FTBI.Count += Count; 810ccb99dd1SMaksim Panchenko if (Count) 811ccb99dd1SMaksim Panchenko FTBI.MispredictedCount += Mispreds; 812ccb99dd1SMaksim Panchenko ToBB = FTSuccessor; 813ccb99dd1SMaksim Panchenko } else { 814a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "invalid branch in " << BF << '\n' 815a34c753fSRafael Auler << Twine::utohexstr(From) << " -> " 816a34c753fSRafael Auler << Twine::utohexstr(To) << '\n'); 817a34c753fSRafael Auler return false; 818a34c753fSRafael Auler } 819ccb99dd1SMaksim Panchenko } 820a34c753fSRafael Auler 821a34c753fSRafael Auler BinaryBasicBlock::BinaryBranchInfo &BI = FromBB->getBranchInfo(*ToBB); 822a34c753fSRafael Auler BI.Count += Count; 823a34c753fSRafael Auler // Only update mispredicted count if it the count was real. 824a34c753fSRafael Auler if (Count) { 825a34c753fSRafael Auler BI.MispredictedCount += Mispreds; 826a34c753fSRafael Auler } 827a34c753fSRafael Auler 828a34c753fSRafael Auler return true; 829a34c753fSRafael Auler } 830a34c753fSRafael Auler 831a34c753fSRafael Auler void DataReader::reportError(StringRef ErrorMsg) { 832a34c753fSRafael Auler Diag << "Error reading BOLT data input file: line " << Line << ", column " 833a34c753fSRafael Auler << Col << ": " << ErrorMsg << '\n'; 834a34c753fSRafael Auler } 835a34c753fSRafael Auler 836a34c753fSRafael Auler bool DataReader::expectAndConsumeFS() { 837a34c753fSRafael Auler if (ParsingBuf[0] != FieldSeparator) { 838a34c753fSRafael Auler reportError("expected field separator"); 839a34c753fSRafael Auler return false; 840a34c753fSRafael Auler } 841a34c753fSRafael Auler ParsingBuf = ParsingBuf.drop_front(1); 842a34c753fSRafael Auler Col += 1; 843a34c753fSRafael Auler return true; 844a34c753fSRafael Auler } 845a34c753fSRafael Auler 846a34c753fSRafael Auler void DataReader::consumeAllRemainingFS() { 847a34c753fSRafael Auler while (ParsingBuf[0] == FieldSeparator) { 848a34c753fSRafael Auler ParsingBuf = ParsingBuf.drop_front(1); 849a34c753fSRafael Auler Col += 1; 850a34c753fSRafael Auler } 851a34c753fSRafael Auler } 852a34c753fSRafael Auler 853a34c753fSRafael Auler bool DataReader::checkAndConsumeNewLine() { 854a34c753fSRafael Auler if (ParsingBuf[0] != '\n') 855a34c753fSRafael Auler return false; 856a34c753fSRafael Auler 857a34c753fSRafael Auler ParsingBuf = ParsingBuf.drop_front(1); 858a34c753fSRafael Auler Col = 0; 859a34c753fSRafael Auler Line += 1; 860a34c753fSRafael Auler return true; 861a34c753fSRafael Auler } 862a34c753fSRafael Auler 863a34c753fSRafael Auler ErrorOr<StringRef> DataReader::parseString(char EndChar, bool EndNl) { 864a34c753fSRafael Auler if (EndChar == '\\') { 865a34c753fSRafael Auler reportError("EndChar could not be backslash"); 866a34c753fSRafael Auler return make_error_code(llvm::errc::io_error); 867a34c753fSRafael Auler } 868a34c753fSRafael Auler 869a34c753fSRafael Auler std::string EndChars(1, EndChar); 870a34c753fSRafael Auler EndChars.push_back('\\'); 871a34c753fSRafael Auler if (EndNl) 872a34c753fSRafael Auler EndChars.push_back('\n'); 873a34c753fSRafael Auler 874a34c753fSRafael Auler size_t StringEnd = 0; 875a34c753fSRafael Auler do { 876a34c753fSRafael Auler StringEnd = ParsingBuf.find_first_of(EndChars, StringEnd); 877a34c753fSRafael Auler if (StringEnd == StringRef::npos || 878a34c753fSRafael Auler (StringEnd == 0 && ParsingBuf[StringEnd] != '\\')) { 879a34c753fSRafael Auler reportError("malformed field"); 880a34c753fSRafael Auler return make_error_code(llvm::errc::io_error); 881a34c753fSRafael Auler } 882a34c753fSRafael Auler 883a34c753fSRafael Auler if (ParsingBuf[StringEnd] != '\\') 884a34c753fSRafael Auler break; 885a34c753fSRafael Auler 886a34c753fSRafael Auler StringEnd += 2; 887a34c753fSRafael Auler } while (1); 888a34c753fSRafael Auler 889a34c753fSRafael Auler StringRef Str = ParsingBuf.substr(0, StringEnd); 890a34c753fSRafael Auler 891a34c753fSRafael Auler // If EndNl was set and nl was found instead of EndChar, do not consume the 892a34c753fSRafael Auler // new line. 89340c2e0faSMaksim Panchenko bool EndNlInsteadOfEndChar = ParsingBuf[StringEnd] == '\n' && EndChar != '\n'; 894a34c753fSRafael Auler unsigned End = EndNlInsteadOfEndChar ? StringEnd : StringEnd + 1; 895a34c753fSRafael Auler 896a34c753fSRafael Auler ParsingBuf = ParsingBuf.drop_front(End); 897a34c753fSRafael Auler if (EndChar == '\n') { 898a34c753fSRafael Auler Col = 0; 899a34c753fSRafael Auler Line += 1; 900a34c753fSRafael Auler } else { 901a34c753fSRafael Auler Col += End; 902a34c753fSRafael Auler } 903a34c753fSRafael Auler return Str; 904a34c753fSRafael Auler } 905a34c753fSRafael Auler 906a34c753fSRafael Auler ErrorOr<int64_t> DataReader::parseNumberField(char EndChar, bool EndNl) { 907a34c753fSRafael Auler ErrorOr<StringRef> NumStrRes = parseString(EndChar, EndNl); 908a34c753fSRafael Auler if (std::error_code EC = NumStrRes.getError()) 909a34c753fSRafael Auler return EC; 910a34c753fSRafael Auler StringRef NumStr = NumStrRes.get(); 911a34c753fSRafael Auler int64_t Num; 912a34c753fSRafael Auler if (NumStr.getAsInteger(10, Num)) { 913a34c753fSRafael Auler reportError("expected decimal number"); 914a34c753fSRafael Auler Diag << "Found: " << NumStr << "\n"; 915a34c753fSRafael Auler return make_error_code(llvm::errc::io_error); 916a34c753fSRafael Auler } 917a34c753fSRafael Auler return Num; 918a34c753fSRafael Auler } 919a34c753fSRafael Auler 920a34c753fSRafael Auler ErrorOr<uint64_t> DataReader::parseHexField(char EndChar, bool EndNl) { 921a34c753fSRafael Auler ErrorOr<StringRef> NumStrRes = parseString(EndChar, EndNl); 922a34c753fSRafael Auler if (std::error_code EC = NumStrRes.getError()) 923a34c753fSRafael Auler return EC; 924a34c753fSRafael Auler StringRef NumStr = NumStrRes.get(); 925a34c753fSRafael Auler uint64_t Num; 926a34c753fSRafael Auler if (NumStr.getAsInteger(16, Num)) { 927a34c753fSRafael Auler reportError("expected hexidecimal number"); 928a34c753fSRafael Auler Diag << "Found: " << NumStr << "\n"; 929a34c753fSRafael Auler return make_error_code(llvm::errc::io_error); 930a34c753fSRafael Auler } 931a34c753fSRafael Auler return Num; 932a34c753fSRafael Auler } 933a34c753fSRafael Auler 93440c2e0faSMaksim Panchenko ErrorOr<Location> DataReader::parseLocation(char EndChar, bool EndNl, 935a34c753fSRafael Auler bool ExpectMemLoc) { 936a34c753fSRafael Auler // Read whether the location of the branch should be DSO or a symbol 937a34c753fSRafael Auler // 0 means it is a DSO. 1 means it is a global symbol. 2 means it is a local 938a34c753fSRafael Auler // symbol. 939a34c753fSRafael Auler // The symbol flag is also used to tag memory load events by adding 3 to the 940a34c753fSRafael Auler // base values, i.e. 3 not a symbol, 4 global symbol and 5 local symbol. 94140c2e0faSMaksim Panchenko if (!ExpectMemLoc && ParsingBuf[0] != '0' && ParsingBuf[0] != '1' && 94240c2e0faSMaksim Panchenko ParsingBuf[0] != '2') { 943a34c753fSRafael Auler reportError("expected 0, 1 or 2"); 944a34c753fSRafael Auler return make_error_code(llvm::errc::io_error); 945a34c753fSRafael Auler } 946a34c753fSRafael Auler 94740c2e0faSMaksim Panchenko if (ExpectMemLoc && ParsingBuf[0] != '3' && ParsingBuf[0] != '4' && 94840c2e0faSMaksim Panchenko ParsingBuf[0] != '5') { 949a34c753fSRafael Auler reportError("expected 3, 4 or 5"); 950a34c753fSRafael Auler return make_error_code(llvm::errc::io_error); 951a34c753fSRafael Auler } 952a34c753fSRafael Auler 953a34c753fSRafael Auler bool IsSymbol = 954a34c753fSRafael Auler (!ExpectMemLoc && (ParsingBuf[0] == '1' || ParsingBuf[0] == '2')) || 955a34c753fSRafael Auler (ExpectMemLoc && (ParsingBuf[0] == '4' || ParsingBuf[0] == '5')); 956a34c753fSRafael Auler ParsingBuf = ParsingBuf.drop_front(1); 957a34c753fSRafael Auler Col += 1; 958a34c753fSRafael Auler 959a34c753fSRafael Auler if (!expectAndConsumeFS()) 960a34c753fSRafael Auler return make_error_code(llvm::errc::io_error); 961a34c753fSRafael Auler consumeAllRemainingFS(); 962a34c753fSRafael Auler 963a34c753fSRafael Auler // Read the string containing the symbol or the DSO name 964a34c753fSRafael Auler ErrorOr<StringRef> NameRes = parseString(FieldSeparator); 965a34c753fSRafael Auler if (std::error_code EC = NameRes.getError()) 966a34c753fSRafael Auler return EC; 967a34c753fSRafael Auler StringRef Name = NameRes.get(); 968a34c753fSRafael Auler consumeAllRemainingFS(); 969a34c753fSRafael Auler 970a34c753fSRafael Auler // Read the offset 971a34c753fSRafael Auler ErrorOr<uint64_t> Offset = parseHexField(EndChar, EndNl); 972a34c753fSRafael Auler if (std::error_code EC = Offset.getError()) 973a34c753fSRafael Auler return EC; 974a34c753fSRafael Auler 975a34c753fSRafael Auler return Location(IsSymbol, Name, Offset.get()); 976a34c753fSRafael Auler } 977a34c753fSRafael Auler 978a34c753fSRafael Auler ErrorOr<BranchInfo> DataReader::parseBranchInfo() { 979a34c753fSRafael Auler ErrorOr<Location> Res = parseLocation(FieldSeparator); 980a34c753fSRafael Auler if (std::error_code EC = Res.getError()) 981a34c753fSRafael Auler return EC; 982a34c753fSRafael Auler Location From = Res.get(); 983a34c753fSRafael Auler 984a34c753fSRafael Auler consumeAllRemainingFS(); 985a34c753fSRafael Auler Res = parseLocation(FieldSeparator); 986a34c753fSRafael Auler if (std::error_code EC = Res.getError()) 987a34c753fSRafael Auler return EC; 988a34c753fSRafael Auler Location To = Res.get(); 989a34c753fSRafael Auler 990a34c753fSRafael Auler consumeAllRemainingFS(); 991a34c753fSRafael Auler ErrorOr<int64_t> MRes = parseNumberField(FieldSeparator); 992a34c753fSRafael Auler if (std::error_code EC = MRes.getError()) 993a34c753fSRafael Auler return EC; 994a34c753fSRafael Auler int64_t NumMispreds = MRes.get(); 995a34c753fSRafael Auler 996a34c753fSRafael Auler consumeAllRemainingFS(); 997a34c753fSRafael Auler ErrorOr<int64_t> BRes = parseNumberField(FieldSeparator, /* EndNl = */ true); 998a34c753fSRafael Auler if (std::error_code EC = BRes.getError()) 999a34c753fSRafael Auler return EC; 1000a34c753fSRafael Auler int64_t NumBranches = BRes.get(); 1001a34c753fSRafael Auler 1002a34c753fSRafael Auler consumeAllRemainingFS(); 1003a34c753fSRafael Auler if (!checkAndConsumeNewLine()) { 1004a34c753fSRafael Auler reportError("expected end of line"); 1005a34c753fSRafael Auler return make_error_code(llvm::errc::io_error); 1006a34c753fSRafael Auler } 1007a34c753fSRafael Auler 1008a34c753fSRafael Auler return BranchInfo(std::move(From), std::move(To), NumMispreds, NumBranches); 1009a34c753fSRafael Auler } 1010a34c753fSRafael Auler 1011a34c753fSRafael Auler ErrorOr<MemInfo> DataReader::parseMemInfo() { 1012a34c753fSRafael Auler ErrorOr<Location> Res = parseMemLocation(FieldSeparator); 1013a34c753fSRafael Auler if (std::error_code EC = Res.getError()) 1014a34c753fSRafael Auler return EC; 1015a34c753fSRafael Auler Location Offset = Res.get(); 1016a34c753fSRafael Auler 1017a34c753fSRafael Auler consumeAllRemainingFS(); 1018a34c753fSRafael Auler Res = parseMemLocation(FieldSeparator); 1019a34c753fSRafael Auler if (std::error_code EC = Res.getError()) 1020a34c753fSRafael Auler return EC; 1021a34c753fSRafael Auler Location Addr = Res.get(); 1022a34c753fSRafael Auler 1023a34c753fSRafael Auler consumeAllRemainingFS(); 1024a34c753fSRafael Auler ErrorOr<int64_t> CountRes = parseNumberField(FieldSeparator, true); 1025a34c753fSRafael Auler if (std::error_code EC = CountRes.getError()) 1026a34c753fSRafael Auler return EC; 1027a34c753fSRafael Auler 1028a34c753fSRafael Auler consumeAllRemainingFS(); 1029a34c753fSRafael Auler if (!checkAndConsumeNewLine()) { 1030a34c753fSRafael Auler reportError("expected end of line"); 1031a34c753fSRafael Auler return make_error_code(llvm::errc::io_error); 1032a34c753fSRafael Auler } 1033a34c753fSRafael Auler 1034a34c753fSRafael Auler return MemInfo(Offset, Addr, CountRes.get()); 1035a34c753fSRafael Auler } 1036a34c753fSRafael Auler 1037a34c753fSRafael Auler ErrorOr<SampleInfo> DataReader::parseSampleInfo() { 1038a34c753fSRafael Auler ErrorOr<Location> Res = parseLocation(FieldSeparator); 1039a34c753fSRafael Auler if (std::error_code EC = Res.getError()) 1040a34c753fSRafael Auler return EC; 1041a34c753fSRafael Auler Location Address = Res.get(); 1042a34c753fSRafael Auler 1043a34c753fSRafael Auler consumeAllRemainingFS(); 1044a34c753fSRafael Auler ErrorOr<int64_t> BRes = parseNumberField(FieldSeparator, /* EndNl = */ true); 1045a34c753fSRafael Auler if (std::error_code EC = BRes.getError()) 1046a34c753fSRafael Auler return EC; 1047a34c753fSRafael Auler int64_t Occurrences = BRes.get(); 1048a34c753fSRafael Auler 1049a34c753fSRafael Auler consumeAllRemainingFS(); 1050a34c753fSRafael Auler if (!checkAndConsumeNewLine()) { 1051a34c753fSRafael Auler reportError("expected end of line"); 1052a34c753fSRafael Auler return make_error_code(llvm::errc::io_error); 1053a34c753fSRafael Auler } 1054a34c753fSRafael Auler 1055a34c753fSRafael Auler return SampleInfo(std::move(Address), Occurrences); 1056a34c753fSRafael Auler } 1057a34c753fSRafael Auler 1058a34c753fSRafael Auler ErrorOr<bool> DataReader::maybeParseNoLBRFlag() { 1059a34c753fSRafael Auler if (ParsingBuf.size() < 6 || ParsingBuf.substr(0, 6) != "no_lbr") 1060a34c753fSRafael Auler return false; 1061a34c753fSRafael Auler ParsingBuf = ParsingBuf.drop_front(6); 1062a34c753fSRafael Auler Col += 6; 1063a34c753fSRafael Auler 1064a34c753fSRafael Auler if (ParsingBuf.size() > 0 && ParsingBuf[0] == ' ') 1065a34c753fSRafael Auler ParsingBuf = ParsingBuf.drop_front(1); 1066a34c753fSRafael Auler 1067a34c753fSRafael Auler while (ParsingBuf.size() > 0 && ParsingBuf[0] != '\n') { 1068a34c753fSRafael Auler ErrorOr<StringRef> EventName = parseString(' ', true); 1069a34c753fSRafael Auler if (!EventName) 1070a34c753fSRafael Auler return make_error_code(llvm::errc::io_error); 1071a34c753fSRafael Auler EventNames.insert(EventName.get()); 1072a34c753fSRafael Auler } 1073a34c753fSRafael Auler 1074a34c753fSRafael Auler if (!checkAndConsumeNewLine()) { 1075a34c753fSRafael Auler reportError("malformed no_lbr line"); 1076a34c753fSRafael Auler return make_error_code(llvm::errc::io_error); 1077a34c753fSRafael Auler } 1078a34c753fSRafael Auler return true; 1079a34c753fSRafael Auler } 1080a34c753fSRafael Auler 1081a34c753fSRafael Auler ErrorOr<bool> DataReader::maybeParseBATFlag() { 1082a34c753fSRafael Auler if (ParsingBuf.size() < 16 || ParsingBuf.substr(0, 16) != "boltedcollection") 1083a34c753fSRafael Auler return false; 1084a34c753fSRafael Auler ParsingBuf = ParsingBuf.drop_front(16); 1085a34c753fSRafael Auler Col += 16; 1086a34c753fSRafael Auler 1087a34c753fSRafael Auler if (!checkAndConsumeNewLine()) { 1088a34c753fSRafael Auler reportError("malformed boltedcollection line"); 1089a34c753fSRafael Auler return make_error_code(llvm::errc::io_error); 1090a34c753fSRafael Auler } 1091a34c753fSRafael Auler return true; 1092a34c753fSRafael Auler } 1093a34c753fSRafael Auler 1094a34c753fSRafael Auler bool DataReader::hasBranchData() { 1095a34c753fSRafael Auler if (ParsingBuf.size() == 0) 1096a34c753fSRafael Auler return false; 1097a34c753fSRafael Auler 1098a34c753fSRafael Auler if (ParsingBuf[0] == '0' || ParsingBuf[0] == '1' || ParsingBuf[0] == '2') 1099a34c753fSRafael Auler return true; 1100a34c753fSRafael Auler return false; 1101a34c753fSRafael Auler } 1102a34c753fSRafael Auler 1103a34c753fSRafael Auler bool DataReader::hasMemData() { 1104a34c753fSRafael Auler if (ParsingBuf.size() == 0) 1105a34c753fSRafael Auler return false; 1106a34c753fSRafael Auler 1107a34c753fSRafael Auler if (ParsingBuf[0] == '3' || ParsingBuf[0] == '4' || ParsingBuf[0] == '5') 1108a34c753fSRafael Auler return true; 1109a34c753fSRafael Auler return false; 1110a34c753fSRafael Auler } 1111a34c753fSRafael Auler 1112a34c753fSRafael Auler std::error_code DataReader::parseInNoLBRMode() { 1113a34c753fSRafael Auler auto GetOrCreateFuncEntry = [&](StringRef Name) { 1114a34c753fSRafael Auler auto I = NamesToSamples.find(Name); 1115a34c753fSRafael Auler if (I == NamesToSamples.end()) { 1116a34c753fSRafael Auler bool Success; 1117a34c753fSRafael Auler std::tie(I, Success) = NamesToSamples.insert(std::make_pair( 1118a34c753fSRafael Auler Name, FuncSampleData(Name, FuncSampleData::ContainerTy()))); 1119a34c753fSRafael Auler 1120a34c753fSRafael Auler assert(Success && "unexpected result of insert"); 1121a34c753fSRafael Auler } 1122a34c753fSRafael Auler return I; 1123a34c753fSRafael Auler }; 1124a34c753fSRafael Auler 1125a34c753fSRafael Auler auto GetOrCreateFuncMemEntry = [&](StringRef Name) { 1126a34c753fSRafael Auler auto I = NamesToMemEvents.find(Name); 1127a34c753fSRafael Auler if (I == NamesToMemEvents.end()) { 1128a34c753fSRafael Auler bool Success; 1129a34c753fSRafael Auler std::tie(I, Success) = NamesToMemEvents.insert( 1130a34c753fSRafael Auler std::make_pair(Name, FuncMemData(Name, FuncMemData::ContainerTy()))); 1131a34c753fSRafael Auler assert(Success && "unexpected result of insert"); 1132a34c753fSRafael Auler } 1133a34c753fSRafael Auler return I; 1134a34c753fSRafael Auler }; 1135a34c753fSRafael Auler 1136a34c753fSRafael Auler while (hasBranchData()) { 1137a34c753fSRafael Auler ErrorOr<SampleInfo> Res = parseSampleInfo(); 1138a34c753fSRafael Auler if (std::error_code EC = Res.getError()) 1139a34c753fSRafael Auler return EC; 1140a34c753fSRafael Auler 1141a34c753fSRafael Auler SampleInfo SI = Res.get(); 1142a34c753fSRafael Auler 1143a34c753fSRafael Auler // Ignore samples not involving known locations 1144a34c753fSRafael Auler if (!SI.Loc.IsSymbol) 1145a34c753fSRafael Auler continue; 1146a34c753fSRafael Auler 1147a34c753fSRafael Auler StringMapIterator<FuncSampleData> I = GetOrCreateFuncEntry(SI.Loc.Name); 1148a34c753fSRafael Auler I->getValue().Data.emplace_back(std::move(SI)); 1149a34c753fSRafael Auler } 1150a34c753fSRafael Auler 1151a34c753fSRafael Auler while (hasMemData()) { 1152a34c753fSRafael Auler ErrorOr<MemInfo> Res = parseMemInfo(); 1153a34c753fSRafael Auler if (std::error_code EC = Res.getError()) 1154a34c753fSRafael Auler return EC; 1155a34c753fSRafael Auler 1156a34c753fSRafael Auler MemInfo MI = Res.get(); 1157a34c753fSRafael Auler 1158a34c753fSRafael Auler // Ignore memory events not involving known pc. 1159a34c753fSRafael Auler if (!MI.Offset.IsSymbol) 1160a34c753fSRafael Auler continue; 1161a34c753fSRafael Auler 1162a34c753fSRafael Auler StringMapIterator<FuncMemData> I = GetOrCreateFuncMemEntry(MI.Offset.Name); 1163a34c753fSRafael Auler I->getValue().Data.emplace_back(std::move(MI)); 1164a34c753fSRafael Auler } 1165a34c753fSRafael Auler 1166a34c753fSRafael Auler for (StringMapEntry<FuncSampleData> &FuncSamples : NamesToSamples) { 1167a34c753fSRafael Auler std::stable_sort(FuncSamples.second.Data.begin(), 1168a34c753fSRafael Auler FuncSamples.second.Data.end()); 1169a34c753fSRafael Auler } 1170a34c753fSRafael Auler 1171a34c753fSRafael Auler for (StringMapEntry<FuncMemData> &MemEvents : NamesToMemEvents) { 1172a34c753fSRafael Auler std::stable_sort(MemEvents.second.Data.begin(), 1173a34c753fSRafael Auler MemEvents.second.Data.end()); 1174a34c753fSRafael Auler } 1175a34c753fSRafael Auler 1176a34c753fSRafael Auler return std::error_code(); 1177a34c753fSRafael Auler } 1178a34c753fSRafael Auler 1179a34c753fSRafael Auler std::error_code DataReader::parse() { 1180a34c753fSRafael Auler auto GetOrCreateFuncEntry = [&](StringRef Name) { 1181a34c753fSRafael Auler auto I = NamesToBranches.find(Name); 1182a34c753fSRafael Auler if (I == NamesToBranches.end()) { 1183a34c753fSRafael Auler bool Success; 1184a34c753fSRafael Auler std::tie(I, Success) = NamesToBranches.insert(std::make_pair( 1185a34c753fSRafael Auler Name, FuncBranchData(Name, FuncBranchData::ContainerTy(), 1186a34c753fSRafael Auler FuncBranchData::ContainerTy()))); 1187a34c753fSRafael Auler assert(Success && "unexpected result of insert"); 1188a34c753fSRafael Auler } 1189a34c753fSRafael Auler return I; 1190a34c753fSRafael Auler }; 1191a34c753fSRafael Auler 1192a34c753fSRafael Auler auto GetOrCreateFuncMemEntry = [&](StringRef Name) { 1193a34c753fSRafael Auler auto I = NamesToMemEvents.find(Name); 1194a34c753fSRafael Auler if (I == NamesToMemEvents.end()) { 1195a34c753fSRafael Auler bool Success; 1196a34c753fSRafael Auler std::tie(I, Success) = NamesToMemEvents.insert( 1197a34c753fSRafael Auler std::make_pair(Name, FuncMemData(Name, FuncMemData::ContainerTy()))); 1198a34c753fSRafael Auler assert(Success && "unexpected result of insert"); 1199a34c753fSRafael Auler } 1200a34c753fSRafael Auler return I; 1201a34c753fSRafael Auler }; 1202a34c753fSRafael Auler 1203a34c753fSRafael Auler Col = 0; 1204a34c753fSRafael Auler Line = 1; 1205a34c753fSRafael Auler ErrorOr<bool> FlagOrErr = maybeParseNoLBRFlag(); 1206a34c753fSRafael Auler if (!FlagOrErr) 1207a34c753fSRafael Auler return FlagOrErr.getError(); 1208a34c753fSRafael Auler NoLBRMode = *FlagOrErr; 1209a34c753fSRafael Auler 1210a34c753fSRafael Auler ErrorOr<bool> BATFlagOrErr = maybeParseBATFlag(); 1211a34c753fSRafael Auler if (!BATFlagOrErr) 1212a34c753fSRafael Auler return BATFlagOrErr.getError(); 1213a34c753fSRafael Auler BATMode = *BATFlagOrErr; 1214a34c753fSRafael Auler 1215a34c753fSRafael Auler if (!hasBranchData() && !hasMemData()) { 1216a34c753fSRafael Auler Diag << "ERROR: no valid profile data found\n"; 1217a34c753fSRafael Auler return make_error_code(llvm::errc::io_error); 1218a34c753fSRafael Auler } 1219a34c753fSRafael Auler 1220a34c753fSRafael Auler if (NoLBRMode) 1221a34c753fSRafael Auler return parseInNoLBRMode(); 1222a34c753fSRafael Auler 1223a34c753fSRafael Auler while (hasBranchData()) { 1224a34c753fSRafael Auler ErrorOr<BranchInfo> Res = parseBranchInfo(); 1225a34c753fSRafael Auler if (std::error_code EC = Res.getError()) 1226a34c753fSRafael Auler return EC; 1227a34c753fSRafael Auler 1228a34c753fSRafael Auler BranchInfo BI = Res.get(); 1229a34c753fSRafael Auler 1230a34c753fSRafael Auler // Ignore branches not involving known location. 1231a34c753fSRafael Auler if (!BI.From.IsSymbol && !BI.To.IsSymbol) 1232a34c753fSRafael Auler continue; 1233a34c753fSRafael Auler 1234a34c753fSRafael Auler StringMapIterator<FuncBranchData> I = GetOrCreateFuncEntry(BI.From.Name); 1235a34c753fSRafael Auler I->getValue().Data.emplace_back(std::move(BI)); 1236a34c753fSRafael Auler 1237a34c753fSRafael Auler // Add entry data for branches to another function or branches 1238a34c753fSRafael Auler // to entry points (including recursive calls) 1239a34c753fSRafael Auler if (BI.To.IsSymbol && 1240a34c753fSRafael Auler (!BI.From.Name.equals(BI.To.Name) || BI.To.Offset == 0)) { 1241a34c753fSRafael Auler I = GetOrCreateFuncEntry(BI.To.Name); 1242a34c753fSRafael Auler I->getValue().EntryData.emplace_back(std::move(BI)); 1243a34c753fSRafael Auler } 1244a34c753fSRafael Auler 1245a34c753fSRafael Auler // If destination is the function start - update execution count. 1246a34c753fSRafael Auler // NB: the data is skewed since we cannot tell tail recursion from 1247a34c753fSRafael Auler // branches to the function start. 1248a34c753fSRafael Auler if (BI.To.IsSymbol && BI.To.Offset == 0) { 1249a34c753fSRafael Auler I = GetOrCreateFuncEntry(BI.To.Name); 1250a34c753fSRafael Auler I->getValue().ExecutionCount += BI.Branches; 1251a34c753fSRafael Auler } 1252a34c753fSRafael Auler } 1253a34c753fSRafael Auler 1254a34c753fSRafael Auler while (hasMemData()) { 1255a34c753fSRafael Auler ErrorOr<MemInfo> Res = parseMemInfo(); 1256a34c753fSRafael Auler if (std::error_code EC = Res.getError()) 1257a34c753fSRafael Auler return EC; 1258a34c753fSRafael Auler 1259a34c753fSRafael Auler MemInfo MI = Res.get(); 1260a34c753fSRafael Auler 1261a34c753fSRafael Auler // Ignore memory events not involving known pc. 1262a34c753fSRafael Auler if (!MI.Offset.IsSymbol) 1263a34c753fSRafael Auler continue; 1264a34c753fSRafael Auler 1265a34c753fSRafael Auler StringMapIterator<FuncMemData> I = GetOrCreateFuncMemEntry(MI.Offset.Name); 1266a34c753fSRafael Auler I->getValue().Data.emplace_back(std::move(MI)); 1267a34c753fSRafael Auler } 1268a34c753fSRafael Auler 1269a34c753fSRafael Auler for (StringMapEntry<FuncBranchData> &FuncBranches : NamesToBranches) { 1270a34c753fSRafael Auler std::stable_sort(FuncBranches.second.Data.begin(), 1271a34c753fSRafael Auler FuncBranches.second.Data.end()); 1272a34c753fSRafael Auler } 1273a34c753fSRafael Auler 1274a34c753fSRafael Auler for (StringMapEntry<FuncMemData> &MemEvents : NamesToMemEvents) { 1275a34c753fSRafael Auler std::stable_sort(MemEvents.second.Data.begin(), 1276a34c753fSRafael Auler MemEvents.second.Data.end()); 1277a34c753fSRafael Auler } 1278a34c753fSRafael Auler 1279a34c753fSRafael Auler return std::error_code(); 1280a34c753fSRafael Auler } 1281a34c753fSRafael Auler 1282a34c753fSRafael Auler void DataReader::buildLTONameMaps() { 1283a34c753fSRafael Auler for (StringMapEntry<FuncBranchData> &FuncData : NamesToBranches) { 1284a34c753fSRafael Auler const StringRef FuncName = FuncData.getKey(); 1285a34c753fSRafael Auler const Optional<StringRef> CommonName = getLTOCommonName(FuncName); 1286a34c753fSRafael Auler if (CommonName) 1287a34c753fSRafael Auler LTOCommonNameMap[*CommonName].push_back(&FuncData.getValue()); 1288a34c753fSRafael Auler } 1289a34c753fSRafael Auler 1290a34c753fSRafael Auler for (StringMapEntry<FuncMemData> &FuncData : NamesToMemEvents) { 1291a34c753fSRafael Auler const StringRef FuncName = FuncData.getKey(); 1292a34c753fSRafael Auler const Optional<StringRef> CommonName = getLTOCommonName(FuncName); 1293a34c753fSRafael Auler if (CommonName) 1294a34c753fSRafael Auler LTOCommonNameMemMap[*CommonName].push_back(&FuncData.getValue()); 1295a34c753fSRafael Auler } 1296a34c753fSRafael Auler } 1297a34c753fSRafael Auler 1298a34c753fSRafael Auler namespace { 1299a34c753fSRafael Auler template <typename MapTy> 1300a34c753fSRafael Auler decltype(MapTy::MapEntryTy::second) * 1301a34c753fSRafael Auler fetchMapEntry(MapTy &Map, const std::vector<MCSymbol *> &Symbols) { 1302a34c753fSRafael Auler // Do a reverse order iteration since the name in profile has a higher chance 1303a34c753fSRafael Auler // of matching a name at the end of the list. 1304a34c753fSRafael Auler for (auto SI = Symbols.rbegin(), SE = Symbols.rend(); SI != SE; ++SI) { 1305a34c753fSRafael Auler auto I = Map.find(normalizeName((*SI)->getName())); 1306a34c753fSRafael Auler if (I != Map.end()) 1307a34c753fSRafael Auler return &I->getValue(); 1308a34c753fSRafael Auler } 1309a34c753fSRafael Auler return nullptr; 1310a34c753fSRafael Auler } 1311a34c753fSRafael Auler 1312a34c753fSRafael Auler template <typename MapTy> 1313a34c753fSRafael Auler decltype(MapTy::MapEntryTy::second) * 1314a34c753fSRafael Auler fetchMapEntry(MapTy &Map, const std::vector<StringRef> &FuncNames) { 1315a34c753fSRafael Auler // Do a reverse order iteration since the name in profile has a higher chance 1316a34c753fSRafael Auler // of matching a name at the end of the list. 1317a34c753fSRafael Auler for (auto FI = FuncNames.rbegin(), FE = FuncNames.rend(); FI != FE; ++FI) { 1318a34c753fSRafael Auler auto I = Map.find(normalizeName(*FI)); 1319a34c753fSRafael Auler if (I != Map.end()) 1320a34c753fSRafael Auler return &I->getValue(); 1321a34c753fSRafael Auler } 1322a34c753fSRafael Auler return nullptr; 1323a34c753fSRafael Auler } 1324a34c753fSRafael Auler 1325a34c753fSRafael Auler template <typename MapTy> 132640c2e0faSMaksim Panchenko std::vector<decltype(MapTy::MapEntryTy::second) *> fetchMapEntriesRegex( 1327a34c753fSRafael Auler MapTy &Map, 132840c2e0faSMaksim Panchenko const StringMap<std::vector<decltype(MapTy::MapEntryTy::second) *>> 132940c2e0faSMaksim Panchenko <OCommonNameMap, 1330a34c753fSRafael Auler const std::vector<StringRef> &FuncNames) { 1331a34c753fSRafael Auler std::vector<decltype(MapTy::MapEntryTy::second) *> AllData; 1332a34c753fSRafael Auler // Do a reverse order iteration since the name in profile has a higher chance 1333a34c753fSRafael Auler // of matching a name at the end of the list. 1334a34c753fSRafael Auler for (auto FI = FuncNames.rbegin(), FE = FuncNames.rend(); FI != FE; ++FI) { 1335a34c753fSRafael Auler std::string Name = normalizeName(*FI); 1336a34c753fSRafael Auler const Optional<StringRef> LTOCommonName = getLTOCommonName(Name); 1337a34c753fSRafael Auler if (LTOCommonName) { 1338a34c753fSRafael Auler auto I = LTOCommonNameMap.find(*LTOCommonName); 1339a34c753fSRafael Auler if (I != LTOCommonNameMap.end()) { 1340a34c753fSRafael Auler const std::vector<decltype(MapTy::MapEntryTy::second) *> &CommonData = 1341a34c753fSRafael Auler I->getValue(); 1342a34c753fSRafael Auler AllData.insert(AllData.end(), CommonData.begin(), CommonData.end()); 1343a34c753fSRafael Auler } 1344a34c753fSRafael Auler } else { 1345a34c753fSRafael Auler auto I = Map.find(Name); 1346a34c753fSRafael Auler if (I != Map.end()) { 1347a34c753fSRafael Auler return {&I->getValue()}; 1348a34c753fSRafael Auler } 1349a34c753fSRafael Auler } 1350a34c753fSRafael Auler } 1351a34c753fSRafael Auler return AllData; 1352a34c753fSRafael Auler } 1353a34c753fSRafael Auler 1354a34c753fSRafael Auler } 1355a34c753fSRafael Auler 1356a34c753fSRafael Auler bool DataReader::mayHaveProfileData(const BinaryFunction &Function) { 1357a34c753fSRafael Auler if (getBranchData(Function) || getMemData(Function)) 1358a34c753fSRafael Auler return true; 1359a34c753fSRafael Auler 1360a34c753fSRafael Auler if (getBranchDataForNames(Function.getNames()) || 1361a34c753fSRafael Auler getMemDataForNames(Function.getNames())) 1362a34c753fSRafael Auler return true; 1363a34c753fSRafael Auler 1364a34c753fSRafael Auler if (!hasVolatileName(Function)) 1365a34c753fSRafael Auler return false; 1366a34c753fSRafael Auler 1367a34c753fSRafael Auler const std::vector<FuncBranchData *> AllBranchData = 1368a34c753fSRafael Auler getBranchDataForNamesRegex(Function.getNames()); 1369a34c753fSRafael Auler if (!AllBranchData.empty()) 1370a34c753fSRafael Auler return true; 1371a34c753fSRafael Auler 1372a34c753fSRafael Auler const std::vector<FuncMemData *> AllMemData = 1373a34c753fSRafael Auler getMemDataForNamesRegex(Function.getNames()); 1374a34c753fSRafael Auler if (!AllMemData.empty()) 1375a34c753fSRafael Auler return true; 1376a34c753fSRafael Auler 1377a34c753fSRafael Auler return false; 1378a34c753fSRafael Auler } 1379a34c753fSRafael Auler 1380a34c753fSRafael Auler FuncBranchData * 1381a34c753fSRafael Auler DataReader::getBranchDataForNames(const std::vector<StringRef> &FuncNames) { 1382a34c753fSRafael Auler return fetchMapEntry<NamesToBranchesMapTy>(NamesToBranches, FuncNames); 1383a34c753fSRafael Auler } 1384a34c753fSRafael Auler 1385a34c753fSRafael Auler FuncBranchData * 1386a34c753fSRafael Auler DataReader::getBranchDataForSymbols(const std::vector<MCSymbol *> &Symbols) { 1387a34c753fSRafael Auler return fetchMapEntry<NamesToBranchesMapTy>(NamesToBranches, Symbols); 1388a34c753fSRafael Auler } 1389a34c753fSRafael Auler 1390a34c753fSRafael Auler FuncMemData * 1391a34c753fSRafael Auler DataReader::getMemDataForNames(const std::vector<StringRef> &FuncNames) { 1392a34c753fSRafael Auler return fetchMapEntry<NamesToMemEventsMapTy>(NamesToMemEvents, FuncNames); 1393a34c753fSRafael Auler } 1394a34c753fSRafael Auler 1395a34c753fSRafael Auler FuncSampleData * 1396a34c753fSRafael Auler DataReader::getFuncSampleData(const std::vector<StringRef> &FuncNames) { 1397a34c753fSRafael Auler return fetchMapEntry<NamesToSamplesMapTy>(NamesToSamples, FuncNames); 1398a34c753fSRafael Auler } 1399a34c753fSRafael Auler 140040c2e0faSMaksim Panchenko std::vector<FuncBranchData *> DataReader::getBranchDataForNamesRegex( 1401a34c753fSRafael Auler const std::vector<StringRef> &FuncNames) { 1402a34c753fSRafael Auler return fetchMapEntriesRegex(NamesToBranches, LTOCommonNameMap, FuncNames); 1403a34c753fSRafael Auler } 1404a34c753fSRafael Auler 1405a34c753fSRafael Auler std::vector<FuncMemData *> 1406a34c753fSRafael Auler DataReader::getMemDataForNamesRegex(const std::vector<StringRef> &FuncNames) { 1407a34c753fSRafael Auler return fetchMapEntriesRegex(NamesToMemEvents, LTOCommonNameMemMap, FuncNames); 1408a34c753fSRafael Auler } 1409a34c753fSRafael Auler 1410a34c753fSRafael Auler bool DataReader::hasLocalsWithFileName() const { 1411a34c753fSRafael Auler for (const StringMapEntry<FuncBranchData> &Func : NamesToBranches) { 1412a34c753fSRafael Auler const StringRef &FuncName = Func.getKey(); 1413a34c753fSRafael Auler if (FuncName.count('/') == 2 && FuncName[0] != '/') 1414a34c753fSRafael Auler return true; 1415a34c753fSRafael Auler } 1416a34c753fSRafael Auler return false; 1417a34c753fSRafael Auler } 1418a34c753fSRafael Auler 1419a34c753fSRafael Auler void DataReader::dump() const { 1420a34c753fSRafael Auler for (const StringMapEntry<FuncBranchData> &Func : NamesToBranches) { 1421a34c753fSRafael Auler Diag << Func.getKey() << " branches:\n"; 1422a34c753fSRafael Auler for (const BranchInfo &BI : Func.getValue().Data) { 1423a34c753fSRafael Auler Diag << BI.From.Name << " " << BI.From.Offset << " " << BI.To.Name << " " 1424a34c753fSRafael Auler << BI.To.Offset << " " << BI.Mispreds << " " << BI.Branches << "\n"; 1425a34c753fSRafael Auler } 1426a34c753fSRafael Auler Diag << Func.getKey() << " entry points:\n"; 1427a34c753fSRafael Auler for (const BranchInfo &BI : Func.getValue().EntryData) { 1428a34c753fSRafael Auler Diag << BI.From.Name << " " << BI.From.Offset << " " << BI.To.Name << " " 1429a34c753fSRafael Auler << BI.To.Offset << " " << BI.Mispreds << " " << BI.Branches << "\n"; 1430a34c753fSRafael Auler } 1431a34c753fSRafael Auler } 1432a34c753fSRafael Auler 1433a34c753fSRafael Auler for (auto I = EventNames.begin(), E = EventNames.end(); I != E; ++I) { 1434a34c753fSRafael Auler StringRef Event = I->getKey(); 1435a34c753fSRafael Auler Diag << "Data was collected with event: " << Event << "\n"; 1436a34c753fSRafael Auler } 1437a34c753fSRafael Auler for (const StringMapEntry<FuncSampleData> &Func : NamesToSamples) { 1438a34c753fSRafael Auler Diag << Func.getKey() << " samples:\n"; 1439a34c753fSRafael Auler for (const SampleInfo &SI : Func.getValue().Data) { 144040c2e0faSMaksim Panchenko Diag << SI.Loc.Name << " " << SI.Loc.Offset << " " << SI.Hits << "\n"; 1441a34c753fSRafael Auler } 1442a34c753fSRafael Auler } 1443a34c753fSRafael Auler 1444a34c753fSRafael Auler for (const StringMapEntry<FuncMemData> &Func : NamesToMemEvents) { 1445a34c753fSRafael Auler Diag << "Memory events for " << Func.getValue().Name; 1446a34c753fSRafael Auler Location LastOffset(0); 1447a34c753fSRafael Auler for (const MemInfo &MI : Func.getValue().Data) { 1448a34c753fSRafael Auler if (MI.Offset == LastOffset) { 1449a34c753fSRafael Auler Diag << ", " << MI.Addr << "/" << MI.Count; 1450a34c753fSRafael Auler } else { 1451a34c753fSRafael Auler Diag << "\n" << MI.Offset << ": " << MI.Addr << "/" << MI.Count; 1452a34c753fSRafael Auler } 1453a34c753fSRafael Auler LastOffset = MI.Offset; 1454a34c753fSRafael Auler } 1455a34c753fSRafael Auler Diag << "\n"; 1456a34c753fSRafael Auler } 1457a34c753fSRafael Auler } 1458a34c753fSRafael Auler 1459a34c753fSRafael Auler } // namespace bolt 1460a34c753fSRafael Auler } // namespace llvm 1461