10b57cec5SDimitry Andric //===- SampleProfReader.cpp - Read LLVM sample profile data ---------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file implements the class that reads LLVM sample profiles. It 100b57cec5SDimitry Andric // supports three file formats: text, binary and gcov. 110b57cec5SDimitry Andric // 120b57cec5SDimitry Andric // The textual representation is useful for debugging and testing purposes. The 130b57cec5SDimitry Andric // binary representation is more compact, resulting in smaller file sizes. 140b57cec5SDimitry Andric // 150b57cec5SDimitry Andric // The gcov encoding is the one generated by GCC's AutoFDO profile creation 160b57cec5SDimitry Andric // tool (https://github.com/google/autofdo) 170b57cec5SDimitry Andric // 180b57cec5SDimitry Andric // All three encodings can be used interchangeably as an input sample profile. 190b57cec5SDimitry Andric // 200b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 210b57cec5SDimitry Andric 220b57cec5SDimitry Andric #include "llvm/ProfileData/SampleProfReader.h" 230b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h" 240b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h" 250b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h" 2681ad6265SDimitry Andric #include "llvm/IR/Module.h" 270b57cec5SDimitry Andric #include "llvm/IR/ProfileSummary.h" 280b57cec5SDimitry Andric #include "llvm/ProfileData/ProfileCommon.h" 290b57cec5SDimitry Andric #include "llvm/ProfileData/SampleProf.h" 30fe6060f1SDimitry Andric #include "llvm/Support/CommandLine.h" 318bcb0991SDimitry Andric #include "llvm/Support/Compression.h" 320b57cec5SDimitry Andric #include "llvm/Support/ErrorOr.h" 33bdd1243dSDimitry Andric #include "llvm/Support/JSON.h" 340b57cec5SDimitry Andric #include "llvm/Support/LEB128.h" 350b57cec5SDimitry Andric #include "llvm/Support/LineIterator.h" 360b57cec5SDimitry Andric #include "llvm/Support/MD5.h" 370b57cec5SDimitry Andric #include "llvm/Support/MemoryBuffer.h" 3806c3fb27SDimitry Andric #include "llvm/Support/VirtualFileSystem.h" 390b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 400b57cec5SDimitry Andric #include <algorithm> 410b57cec5SDimitry Andric #include <cstddef> 420b57cec5SDimitry Andric #include <cstdint> 430b57cec5SDimitry Andric #include <limits> 440b57cec5SDimitry Andric #include <memory> 450b57cec5SDimitry Andric #include <system_error> 460b57cec5SDimitry Andric #include <vector> 470b57cec5SDimitry Andric 480b57cec5SDimitry Andric using namespace llvm; 490b57cec5SDimitry Andric using namespace sampleprof; 500b57cec5SDimitry Andric 51fe6060f1SDimitry Andric #define DEBUG_TYPE "samplepgo-reader" 52fe6060f1SDimitry Andric 53fe6060f1SDimitry Andric // This internal option specifies if the profile uses FS discriminators. 5406c3fb27SDimitry Andric // It only applies to text, and binary format profiles. 55fe6060f1SDimitry Andric // For ext-binary format profiles, the flag is set in the summary. 56fe6060f1SDimitry Andric static cl::opt<bool> ProfileIsFSDisciminator( 57fe6060f1SDimitry Andric "profile-isfs", cl::Hidden, cl::init(false), 58349cc55cSDimitry Andric cl::desc("Profile uses flow sensitive discriminators")); 59fe6060f1SDimitry Andric 600b57cec5SDimitry Andric /// Dump the function profile for \p FName. 610b57cec5SDimitry Andric /// 62349cc55cSDimitry Andric /// \param FContext Name + context of the function to print. 630b57cec5SDimitry Andric /// \param OS Stream to emit the output to. 645f757f3fSDimitry Andric void SampleProfileReader::dumpFunctionProfile(const FunctionSamples &FS, 650b57cec5SDimitry Andric raw_ostream &OS) { 665f757f3fSDimitry Andric OS << "Function: " << FS.getContext().toString() << ": " << FS; 670b57cec5SDimitry Andric } 680b57cec5SDimitry Andric 690b57cec5SDimitry Andric /// Dump all the function profiles found on stream \p OS. 700b57cec5SDimitry Andric void SampleProfileReader::dump(raw_ostream &OS) { 71349cc55cSDimitry Andric std::vector<NameFunctionSamples> V; 72349cc55cSDimitry Andric sortFuncProfiles(Profiles, V); 73349cc55cSDimitry Andric for (const auto &I : V) 745f757f3fSDimitry Andric dumpFunctionProfile(*I.second, OS); 750b57cec5SDimitry Andric } 760b57cec5SDimitry Andric 77bdd1243dSDimitry Andric static void dumpFunctionProfileJson(const FunctionSamples &S, 78bdd1243dSDimitry Andric json::OStream &JOS, bool TopLevel = false) { 79bdd1243dSDimitry Andric auto DumpBody = [&](const BodySampleMap &BodySamples) { 80bdd1243dSDimitry Andric for (const auto &I : BodySamples) { 81bdd1243dSDimitry Andric const LineLocation &Loc = I.first; 82bdd1243dSDimitry Andric const SampleRecord &Sample = I.second; 83bdd1243dSDimitry Andric JOS.object([&] { 84bdd1243dSDimitry Andric JOS.attribute("line", Loc.LineOffset); 85bdd1243dSDimitry Andric if (Loc.Discriminator) 86bdd1243dSDimitry Andric JOS.attribute("discriminator", Loc.Discriminator); 87bdd1243dSDimitry Andric JOS.attribute("samples", Sample.getSamples()); 88bdd1243dSDimitry Andric 89bdd1243dSDimitry Andric auto CallTargets = Sample.getSortedCallTargets(); 90bdd1243dSDimitry Andric if (!CallTargets.empty()) { 91bdd1243dSDimitry Andric JOS.attributeArray("calls", [&] { 92bdd1243dSDimitry Andric for (const auto &J : CallTargets) { 93bdd1243dSDimitry Andric JOS.object([&] { 945f757f3fSDimitry Andric JOS.attribute("function", J.first.str()); 95bdd1243dSDimitry Andric JOS.attribute("samples", J.second); 96bdd1243dSDimitry Andric }); 97bdd1243dSDimitry Andric } 98bdd1243dSDimitry Andric }); 99bdd1243dSDimitry Andric } 100bdd1243dSDimitry Andric }); 101bdd1243dSDimitry Andric } 102bdd1243dSDimitry Andric }; 103bdd1243dSDimitry Andric 104bdd1243dSDimitry Andric auto DumpCallsiteSamples = [&](const CallsiteSampleMap &CallsiteSamples) { 105bdd1243dSDimitry Andric for (const auto &I : CallsiteSamples) 106bdd1243dSDimitry Andric for (const auto &FS : I.second) { 107bdd1243dSDimitry Andric const LineLocation &Loc = I.first; 108bdd1243dSDimitry Andric const FunctionSamples &CalleeSamples = FS.second; 109bdd1243dSDimitry Andric JOS.object([&] { 110bdd1243dSDimitry Andric JOS.attribute("line", Loc.LineOffset); 111bdd1243dSDimitry Andric if (Loc.Discriminator) 112bdd1243dSDimitry Andric JOS.attribute("discriminator", Loc.Discriminator); 113bdd1243dSDimitry Andric JOS.attributeArray( 114bdd1243dSDimitry Andric "samples", [&] { dumpFunctionProfileJson(CalleeSamples, JOS); }); 115bdd1243dSDimitry Andric }); 116bdd1243dSDimitry Andric } 117bdd1243dSDimitry Andric }; 118bdd1243dSDimitry Andric 119bdd1243dSDimitry Andric JOS.object([&] { 1205f757f3fSDimitry Andric JOS.attribute("name", S.getFunction().str()); 121bdd1243dSDimitry Andric JOS.attribute("total", S.getTotalSamples()); 122bdd1243dSDimitry Andric if (TopLevel) 123bdd1243dSDimitry Andric JOS.attribute("head", S.getHeadSamples()); 124bdd1243dSDimitry Andric 125bdd1243dSDimitry Andric const auto &BodySamples = S.getBodySamples(); 126bdd1243dSDimitry Andric if (!BodySamples.empty()) 127bdd1243dSDimitry Andric JOS.attributeArray("body", [&] { DumpBody(BodySamples); }); 128bdd1243dSDimitry Andric 129bdd1243dSDimitry Andric const auto &CallsiteSamples = S.getCallsiteSamples(); 130bdd1243dSDimitry Andric if (!CallsiteSamples.empty()) 131bdd1243dSDimitry Andric JOS.attributeArray("callsites", 132bdd1243dSDimitry Andric [&] { DumpCallsiteSamples(CallsiteSamples); }); 133bdd1243dSDimitry Andric }); 134bdd1243dSDimitry Andric } 135bdd1243dSDimitry Andric 136bdd1243dSDimitry Andric /// Dump all the function profiles found on stream \p OS in the JSON format. 137bdd1243dSDimitry Andric void SampleProfileReader::dumpJson(raw_ostream &OS) { 138bdd1243dSDimitry Andric std::vector<NameFunctionSamples> V; 139bdd1243dSDimitry Andric sortFuncProfiles(Profiles, V); 140bdd1243dSDimitry Andric json::OStream JOS(OS, 2); 141bdd1243dSDimitry Andric JOS.arrayBegin(); 142bdd1243dSDimitry Andric for (const auto &F : V) 143bdd1243dSDimitry Andric dumpFunctionProfileJson(*F.second, JOS, true); 144bdd1243dSDimitry Andric JOS.arrayEnd(); 145bdd1243dSDimitry Andric 146bdd1243dSDimitry Andric // Emit a newline character at the end as json::OStream doesn't emit one. 147bdd1243dSDimitry Andric OS << "\n"; 148bdd1243dSDimitry Andric } 149bdd1243dSDimitry Andric 1500b57cec5SDimitry Andric /// Parse \p Input as function head. 1510b57cec5SDimitry Andric /// 1520b57cec5SDimitry Andric /// Parse one line of \p Input, and update function name in \p FName, 1530b57cec5SDimitry Andric /// function's total sample count in \p NumSamples, function's entry 1540b57cec5SDimitry Andric /// count in \p NumHeadSamples. 1550b57cec5SDimitry Andric /// 1560b57cec5SDimitry Andric /// \returns true if parsing is successful. 1570b57cec5SDimitry Andric static bool ParseHead(const StringRef &Input, StringRef &FName, 1580b57cec5SDimitry Andric uint64_t &NumSamples, uint64_t &NumHeadSamples) { 1590b57cec5SDimitry Andric if (Input[0] == ' ') 1600b57cec5SDimitry Andric return false; 1610b57cec5SDimitry Andric size_t n2 = Input.rfind(':'); 1620b57cec5SDimitry Andric size_t n1 = Input.rfind(':', n2 - 1); 1630b57cec5SDimitry Andric FName = Input.substr(0, n1); 1640b57cec5SDimitry Andric if (Input.substr(n1 + 1, n2 - n1 - 1).getAsInteger(10, NumSamples)) 1650b57cec5SDimitry Andric return false; 1660b57cec5SDimitry Andric if (Input.substr(n2 + 1).getAsInteger(10, NumHeadSamples)) 1670b57cec5SDimitry Andric return false; 1680b57cec5SDimitry Andric return true; 1690b57cec5SDimitry Andric } 1700b57cec5SDimitry Andric 1710b57cec5SDimitry Andric /// Returns true if line offset \p L is legal (only has 16 bits). 1720b57cec5SDimitry Andric static bool isOffsetLegal(unsigned L) { return (L & 0xffff) == L; } 1730b57cec5SDimitry Andric 174e8d8bef9SDimitry Andric /// Parse \p Input that contains metadata. 175e8d8bef9SDimitry Andric /// Possible metadata: 176e8d8bef9SDimitry Andric /// - CFG Checksum information: 177e8d8bef9SDimitry Andric /// !CFGChecksum: 12345 178fe6060f1SDimitry Andric /// - CFG Checksum information: 179fe6060f1SDimitry Andric /// !Attributes: 1 180e8d8bef9SDimitry Andric /// Stores the FunctionHash (a.k.a. CFG Checksum) into \p FunctionHash. 181fe6060f1SDimitry Andric static bool parseMetadata(const StringRef &Input, uint64_t &FunctionHash, 182fe6060f1SDimitry Andric uint32_t &Attributes) { 1835f757f3fSDimitry Andric if (Input.starts_with("!CFGChecksum:")) { 184e8d8bef9SDimitry Andric StringRef CFGInfo = Input.substr(strlen("!CFGChecksum:")).trim(); 185e8d8bef9SDimitry Andric return !CFGInfo.getAsInteger(10, FunctionHash); 186e8d8bef9SDimitry Andric } 187e8d8bef9SDimitry Andric 1885f757f3fSDimitry Andric if (Input.starts_with("!Attributes:")) { 189fe6060f1SDimitry Andric StringRef Attrib = Input.substr(strlen("!Attributes:")).trim(); 190fe6060f1SDimitry Andric return !Attrib.getAsInteger(10, Attributes); 191fe6060f1SDimitry Andric } 192fe6060f1SDimitry Andric 193fe6060f1SDimitry Andric return false; 194fe6060f1SDimitry Andric } 195fe6060f1SDimitry Andric 196e8d8bef9SDimitry Andric enum class LineType { 197e8d8bef9SDimitry Andric CallSiteProfile, 198e8d8bef9SDimitry Andric BodyProfile, 199e8d8bef9SDimitry Andric Metadata, 200e8d8bef9SDimitry Andric }; 201e8d8bef9SDimitry Andric 2020b57cec5SDimitry Andric /// Parse \p Input as line sample. 2030b57cec5SDimitry Andric /// 2040b57cec5SDimitry Andric /// \param Input input line. 205e8d8bef9SDimitry Andric /// \param LineTy Type of this line. 2060b57cec5SDimitry Andric /// \param Depth the depth of the inline stack. 2070b57cec5SDimitry Andric /// \param NumSamples total samples of the line/inlined callsite. 2080b57cec5SDimitry Andric /// \param LineOffset line offset to the start of the function. 2090b57cec5SDimitry Andric /// \param Discriminator discriminator of the line. 2100b57cec5SDimitry Andric /// \param TargetCountMap map from indirect call target to count. 211e8d8bef9SDimitry Andric /// \param FunctionHash the function's CFG hash, used by pseudo probe. 2120b57cec5SDimitry Andric /// 2130b57cec5SDimitry Andric /// returns true if parsing is successful. 214e8d8bef9SDimitry Andric static bool ParseLine(const StringRef &Input, LineType &LineTy, uint32_t &Depth, 2150b57cec5SDimitry Andric uint64_t &NumSamples, uint32_t &LineOffset, 2160b57cec5SDimitry Andric uint32_t &Discriminator, StringRef &CalleeName, 217e8d8bef9SDimitry Andric DenseMap<StringRef, uint64_t> &TargetCountMap, 218fe6060f1SDimitry Andric uint64_t &FunctionHash, uint32_t &Attributes) { 2190b57cec5SDimitry Andric for (Depth = 0; Input[Depth] == ' '; Depth++) 2200b57cec5SDimitry Andric ; 2210b57cec5SDimitry Andric if (Depth == 0) 2220b57cec5SDimitry Andric return false; 2230b57cec5SDimitry Andric 2240eae32dcSDimitry Andric if (Input[Depth] == '!') { 225e8d8bef9SDimitry Andric LineTy = LineType::Metadata; 226fe6060f1SDimitry Andric return parseMetadata(Input.substr(Depth), FunctionHash, Attributes); 227e8d8bef9SDimitry Andric } 228e8d8bef9SDimitry Andric 2290b57cec5SDimitry Andric size_t n1 = Input.find(':'); 2300b57cec5SDimitry Andric StringRef Loc = Input.substr(Depth, n1 - Depth); 2310b57cec5SDimitry Andric size_t n2 = Loc.find('.'); 2320b57cec5SDimitry Andric if (n2 == StringRef::npos) { 2330b57cec5SDimitry Andric if (Loc.getAsInteger(10, LineOffset) || !isOffsetLegal(LineOffset)) 2340b57cec5SDimitry Andric return false; 2350b57cec5SDimitry Andric Discriminator = 0; 2360b57cec5SDimitry Andric } else { 2370b57cec5SDimitry Andric if (Loc.substr(0, n2).getAsInteger(10, LineOffset)) 2380b57cec5SDimitry Andric return false; 2390b57cec5SDimitry Andric if (Loc.substr(n2 + 1).getAsInteger(10, Discriminator)) 2400b57cec5SDimitry Andric return false; 2410b57cec5SDimitry Andric } 2420b57cec5SDimitry Andric 2430b57cec5SDimitry Andric StringRef Rest = Input.substr(n1 + 2); 244e8d8bef9SDimitry Andric if (isDigit(Rest[0])) { 245e8d8bef9SDimitry Andric LineTy = LineType::BodyProfile; 2460b57cec5SDimitry Andric size_t n3 = Rest.find(' '); 2470b57cec5SDimitry Andric if (n3 == StringRef::npos) { 2480b57cec5SDimitry Andric if (Rest.getAsInteger(10, NumSamples)) 2490b57cec5SDimitry Andric return false; 2500b57cec5SDimitry Andric } else { 2510b57cec5SDimitry Andric if (Rest.substr(0, n3).getAsInteger(10, NumSamples)) 2520b57cec5SDimitry Andric return false; 2530b57cec5SDimitry Andric } 2540b57cec5SDimitry Andric // Find call targets and their sample counts. 2550b57cec5SDimitry Andric // Note: In some cases, there are symbols in the profile which are not 2560b57cec5SDimitry Andric // mangled. To accommodate such cases, use colon + integer pairs as the 2570b57cec5SDimitry Andric // anchor points. 2580b57cec5SDimitry Andric // An example: 2590b57cec5SDimitry Andric // _M_construct<char *>:1000 string_view<std::allocator<char> >:437 2600b57cec5SDimitry Andric // ":1000" and ":437" are used as anchor points so the string above will 2610b57cec5SDimitry Andric // be interpreted as 2620b57cec5SDimitry Andric // target: _M_construct<char *> 2630b57cec5SDimitry Andric // count: 1000 2640b57cec5SDimitry Andric // target: string_view<std::allocator<char> > 2650b57cec5SDimitry Andric // count: 437 2660b57cec5SDimitry Andric while (n3 != StringRef::npos) { 2670b57cec5SDimitry Andric n3 += Rest.substr(n3).find_first_not_of(' '); 2680b57cec5SDimitry Andric Rest = Rest.substr(n3); 2690b57cec5SDimitry Andric n3 = Rest.find_first_of(':'); 2700b57cec5SDimitry Andric if (n3 == StringRef::npos || n3 == 0) 2710b57cec5SDimitry Andric return false; 2720b57cec5SDimitry Andric 2730b57cec5SDimitry Andric StringRef Target; 2740b57cec5SDimitry Andric uint64_t count, n4; 2750b57cec5SDimitry Andric while (true) { 2760b57cec5SDimitry Andric // Get the segment after the current colon. 2770b57cec5SDimitry Andric StringRef AfterColon = Rest.substr(n3 + 1); 2780b57cec5SDimitry Andric // Get the target symbol before the current colon. 2790b57cec5SDimitry Andric Target = Rest.substr(0, n3); 2800b57cec5SDimitry Andric // Check if the word after the current colon is an integer. 2810b57cec5SDimitry Andric n4 = AfterColon.find_first_of(' '); 2820b57cec5SDimitry Andric n4 = (n4 != StringRef::npos) ? n3 + n4 + 1 : Rest.size(); 2830b57cec5SDimitry Andric StringRef WordAfterColon = Rest.substr(n3 + 1, n4 - n3 - 1); 2840b57cec5SDimitry Andric if (!WordAfterColon.getAsInteger(10, count)) 2850b57cec5SDimitry Andric break; 2860b57cec5SDimitry Andric 2870b57cec5SDimitry Andric // Try to find the next colon. 2880b57cec5SDimitry Andric uint64_t n5 = AfterColon.find_first_of(':'); 2890b57cec5SDimitry Andric if (n5 == StringRef::npos) 2900b57cec5SDimitry Andric return false; 2910b57cec5SDimitry Andric n3 += n5 + 1; 2920b57cec5SDimitry Andric } 2930b57cec5SDimitry Andric 2940b57cec5SDimitry Andric // An anchor point is found. Save the {target, count} pair 2950b57cec5SDimitry Andric TargetCountMap[Target] = count; 2960b57cec5SDimitry Andric if (n4 == Rest.size()) 2970b57cec5SDimitry Andric break; 2980b57cec5SDimitry Andric // Change n3 to the next blank space after colon + integer pair. 2990b57cec5SDimitry Andric n3 = n4; 3000b57cec5SDimitry Andric } 3010b57cec5SDimitry Andric } else { 302e8d8bef9SDimitry Andric LineTy = LineType::CallSiteProfile; 3030b57cec5SDimitry Andric size_t n3 = Rest.find_last_of(':'); 3040b57cec5SDimitry Andric CalleeName = Rest.substr(0, n3); 3050b57cec5SDimitry Andric if (Rest.substr(n3 + 1).getAsInteger(10, NumSamples)) 3060b57cec5SDimitry Andric return false; 3070b57cec5SDimitry Andric } 3080b57cec5SDimitry Andric return true; 3090b57cec5SDimitry Andric } 3100b57cec5SDimitry Andric 3110b57cec5SDimitry Andric /// Load samples from a text file. 3120b57cec5SDimitry Andric /// 3130b57cec5SDimitry Andric /// See the documentation at the top of the file for an explanation of 3140b57cec5SDimitry Andric /// the expected format. 3150b57cec5SDimitry Andric /// 3160b57cec5SDimitry Andric /// \returns true if the file was loaded successfully, false otherwise. 3178bcb0991SDimitry Andric std::error_code SampleProfileReaderText::readImpl() { 3180b57cec5SDimitry Andric line_iterator LineIt(*Buffer, /*SkipBlanks=*/true, '#'); 3190b57cec5SDimitry Andric sampleprof_error Result = sampleprof_error::success; 3200b57cec5SDimitry Andric 3210b57cec5SDimitry Andric InlineCallStack InlineStack; 3220eae32dcSDimitry Andric uint32_t TopLevelProbeProfileCount = 0; 323e8d8bef9SDimitry Andric 3240eae32dcSDimitry Andric // DepthMetadata tracks whether we have processed metadata for the current 3250eae32dcSDimitry Andric // top-level or nested function profile. 3260eae32dcSDimitry Andric uint32_t DepthMetadata = 0; 3270b57cec5SDimitry Andric 328fe6060f1SDimitry Andric ProfileIsFS = ProfileIsFSDisciminator; 329349cc55cSDimitry Andric FunctionSamples::ProfileIsFS = ProfileIsFS; 3300b57cec5SDimitry Andric for (; !LineIt.is_at_eof(); ++LineIt) { 33106c3fb27SDimitry Andric size_t pos = LineIt->find_first_not_of(' '); 33206c3fb27SDimitry Andric if (pos == LineIt->npos || (*LineIt)[pos] == '#') 3330b57cec5SDimitry Andric continue; 3340b57cec5SDimitry Andric // Read the header of each function. 3350b57cec5SDimitry Andric // 3360b57cec5SDimitry Andric // Note that for function identifiers we are actually expecting 3370b57cec5SDimitry Andric // mangled names, but we may not always get them. This happens when 3380b57cec5SDimitry Andric // the compiler decides not to emit the function (e.g., it was inlined 3390b57cec5SDimitry Andric // and removed). In this case, the binary will not have the linkage 3400b57cec5SDimitry Andric // name for the function, so the profiler will emit the function's 3410b57cec5SDimitry Andric // unmangled name, which may contain characters like ':' and '>' in its 3420b57cec5SDimitry Andric // name (member functions, templates, etc). 3430b57cec5SDimitry Andric // 3440b57cec5SDimitry Andric // The only requirement we place on the identifier, then, is that it 3450b57cec5SDimitry Andric // should not begin with a number. 3460b57cec5SDimitry Andric if ((*LineIt)[0] != ' ') { 3470b57cec5SDimitry Andric uint64_t NumSamples, NumHeadSamples; 3480b57cec5SDimitry Andric StringRef FName; 3490b57cec5SDimitry Andric if (!ParseHead(*LineIt, FName, NumSamples, NumHeadSamples)) { 3500b57cec5SDimitry Andric reportError(LineIt.line_number(), 3510b57cec5SDimitry Andric "Expected 'mangled_name:NUM:NUM', found " + *LineIt); 3520b57cec5SDimitry Andric return sampleprof_error::malformed; 3530b57cec5SDimitry Andric } 3540eae32dcSDimitry Andric DepthMetadata = 0; 355349cc55cSDimitry Andric SampleContext FContext(FName, CSNameTable); 356e8d8bef9SDimitry Andric if (FContext.hasContext()) 357e8d8bef9SDimitry Andric ++CSProfileCount; 358*0fca6ea1SDimitry Andric FunctionSamples &FProfile = Profiles.create(FContext); 359*0fca6ea1SDimitry Andric mergeSampleProfErrors(Result, FProfile.addTotalSamples(NumSamples)); 360*0fca6ea1SDimitry Andric mergeSampleProfErrors(Result, FProfile.addHeadSamples(NumHeadSamples)); 3610b57cec5SDimitry Andric InlineStack.clear(); 3620b57cec5SDimitry Andric InlineStack.push_back(&FProfile); 3630b57cec5SDimitry Andric } else { 3640b57cec5SDimitry Andric uint64_t NumSamples; 3650b57cec5SDimitry Andric StringRef FName; 3660b57cec5SDimitry Andric DenseMap<StringRef, uint64_t> TargetCountMap; 3670b57cec5SDimitry Andric uint32_t Depth, LineOffset, Discriminator; 368e8d8bef9SDimitry Andric LineType LineTy; 369fe6060f1SDimitry Andric uint64_t FunctionHash = 0; 370fe6060f1SDimitry Andric uint32_t Attributes = 0; 371e8d8bef9SDimitry Andric if (!ParseLine(*LineIt, LineTy, Depth, NumSamples, LineOffset, 372fe6060f1SDimitry Andric Discriminator, FName, TargetCountMap, FunctionHash, 373fe6060f1SDimitry Andric Attributes)) { 3740b57cec5SDimitry Andric reportError(LineIt.line_number(), 3750b57cec5SDimitry Andric "Expected 'NUM[.NUM]: NUM[ mangled_name:NUM]*', found " + 3760b57cec5SDimitry Andric *LineIt); 3770b57cec5SDimitry Andric return sampleprof_error::malformed; 3780b57cec5SDimitry Andric } 3790eae32dcSDimitry Andric if (LineTy != LineType::Metadata && Depth == DepthMetadata) { 380e8d8bef9SDimitry Andric // Metadata must be put at the end of a function profile. 381e8d8bef9SDimitry Andric reportError(LineIt.line_number(), 382e8d8bef9SDimitry Andric "Found non-metadata after metadata: " + *LineIt); 383e8d8bef9SDimitry Andric return sampleprof_error::malformed; 384e8d8bef9SDimitry Andric } 385fe6060f1SDimitry Andric 386fe6060f1SDimitry Andric // Here we handle FS discriminators. 387fe6060f1SDimitry Andric Discriminator &= getDiscriminatorMask(); 388fe6060f1SDimitry Andric 3890b57cec5SDimitry Andric while (InlineStack.size() > Depth) { 3900b57cec5SDimitry Andric InlineStack.pop_back(); 3910b57cec5SDimitry Andric } 392e8d8bef9SDimitry Andric switch (LineTy) { 393e8d8bef9SDimitry Andric case LineType::CallSiteProfile: { 3940b57cec5SDimitry Andric FunctionSamples &FSamples = InlineStack.back()->functionSamplesAt( 3955f757f3fSDimitry Andric LineLocation(LineOffset, Discriminator))[FunctionId(FName)]; 3965f757f3fSDimitry Andric FSamples.setFunction(FunctionId(FName)); 397*0fca6ea1SDimitry Andric mergeSampleProfErrors(Result, FSamples.addTotalSamples(NumSamples)); 3980b57cec5SDimitry Andric InlineStack.push_back(&FSamples); 3990eae32dcSDimitry Andric DepthMetadata = 0; 400e8d8bef9SDimitry Andric break; 401e8d8bef9SDimitry Andric } 402e8d8bef9SDimitry Andric case LineType::BodyProfile: { 4030b57cec5SDimitry Andric while (InlineStack.size() > Depth) { 4040b57cec5SDimitry Andric InlineStack.pop_back(); 4050b57cec5SDimitry Andric } 4060b57cec5SDimitry Andric FunctionSamples &FProfile = *InlineStack.back(); 4070b57cec5SDimitry Andric for (const auto &name_count : TargetCountMap) { 408*0fca6ea1SDimitry Andric mergeSampleProfErrors(Result, FProfile.addCalledTargetSamples( 4095f757f3fSDimitry Andric LineOffset, Discriminator, 4105f757f3fSDimitry Andric FunctionId(name_count.first), 4110b57cec5SDimitry Andric name_count.second)); 4120b57cec5SDimitry Andric } 413*0fca6ea1SDimitry Andric mergeSampleProfErrors( 414*0fca6ea1SDimitry Andric Result, 415*0fca6ea1SDimitry Andric FProfile.addBodySamples(LineOffset, Discriminator, NumSamples)); 416e8d8bef9SDimitry Andric break; 417e8d8bef9SDimitry Andric } 418e8d8bef9SDimitry Andric case LineType::Metadata: { 419e8d8bef9SDimitry Andric FunctionSamples &FProfile = *InlineStack.back(); 420fe6060f1SDimitry Andric if (FunctionHash) { 421e8d8bef9SDimitry Andric FProfile.setFunctionHash(FunctionHash); 4220eae32dcSDimitry Andric if (Depth == 1) 4230eae32dcSDimitry Andric ++TopLevelProbeProfileCount; 424fe6060f1SDimitry Andric } 425fe6060f1SDimitry Andric FProfile.getContext().setAllAttributes(Attributes); 4260eae32dcSDimitry Andric if (Attributes & (uint32_t)ContextShouldBeInlined) 42781ad6265SDimitry Andric ProfileIsPreInlined = true; 4280eae32dcSDimitry Andric DepthMetadata = Depth; 429e8d8bef9SDimitry Andric break; 4300b57cec5SDimitry Andric } 4310b57cec5SDimitry Andric } 4320b57cec5SDimitry Andric } 433e8d8bef9SDimitry Andric } 434e8d8bef9SDimitry Andric 435d409305fSDimitry Andric assert((CSProfileCount == 0 || CSProfileCount == Profiles.size()) && 436e8d8bef9SDimitry Andric "Cannot have both context-sensitive and regular profile"); 43781ad6265SDimitry Andric ProfileIsCS = (CSProfileCount > 0); 4380eae32dcSDimitry Andric assert((TopLevelProbeProfileCount == 0 || 4390eae32dcSDimitry Andric TopLevelProbeProfileCount == Profiles.size()) && 440e8d8bef9SDimitry Andric "Cannot have both probe-based profiles and regular profiles"); 4410eae32dcSDimitry Andric ProfileIsProbeBased = (TopLevelProbeProfileCount > 0); 442e8d8bef9SDimitry Andric FunctionSamples::ProfileIsProbeBased = ProfileIsProbeBased; 44381ad6265SDimitry Andric FunctionSamples::ProfileIsCS = ProfileIsCS; 44481ad6265SDimitry Andric FunctionSamples::ProfileIsPreInlined = ProfileIsPreInlined; 445e8d8bef9SDimitry Andric 4460b57cec5SDimitry Andric if (Result == sampleprof_error::success) 4470b57cec5SDimitry Andric computeSummary(); 4480b57cec5SDimitry Andric 4490b57cec5SDimitry Andric return Result; 4500b57cec5SDimitry Andric } 4510b57cec5SDimitry Andric 4520b57cec5SDimitry Andric bool SampleProfileReaderText::hasFormat(const MemoryBuffer &Buffer) { 4530b57cec5SDimitry Andric bool result = false; 4540b57cec5SDimitry Andric 4550b57cec5SDimitry Andric // Check that the first non-comment line is a valid function header. 4560b57cec5SDimitry Andric line_iterator LineIt(Buffer, /*SkipBlanks=*/true, '#'); 4570b57cec5SDimitry Andric if (!LineIt.is_at_eof()) { 4580b57cec5SDimitry Andric if ((*LineIt)[0] != ' ') { 4590b57cec5SDimitry Andric uint64_t NumSamples, NumHeadSamples; 4600b57cec5SDimitry Andric StringRef FName; 4610b57cec5SDimitry Andric result = ParseHead(*LineIt, FName, NumSamples, NumHeadSamples); 4620b57cec5SDimitry Andric } 4630b57cec5SDimitry Andric } 4640b57cec5SDimitry Andric 4650b57cec5SDimitry Andric return result; 4660b57cec5SDimitry Andric } 4670b57cec5SDimitry Andric 4680b57cec5SDimitry Andric template <typename T> ErrorOr<T> SampleProfileReaderBinary::readNumber() { 4690b57cec5SDimitry Andric unsigned NumBytesRead = 0; 4700b57cec5SDimitry Andric uint64_t Val = decodeULEB128(Data, &NumBytesRead); 4710b57cec5SDimitry Andric 4725f757f3fSDimitry Andric if (Val > std::numeric_limits<T>::max()) { 4735f757f3fSDimitry Andric std::error_code EC = sampleprof_error::malformed; 4745f757f3fSDimitry Andric reportError(0, EC.message()); 4755f757f3fSDimitry Andric return EC; 4765f757f3fSDimitry Andric } else if (Data + NumBytesRead > End) { 4775f757f3fSDimitry Andric std::error_code EC = sampleprof_error::truncated; 4780b57cec5SDimitry Andric reportError(0, EC.message()); 4790b57cec5SDimitry Andric return EC; 4800b57cec5SDimitry Andric } 4810b57cec5SDimitry Andric 4820b57cec5SDimitry Andric Data += NumBytesRead; 4830b57cec5SDimitry Andric return static_cast<T>(Val); 4840b57cec5SDimitry Andric } 4850b57cec5SDimitry Andric 4860b57cec5SDimitry Andric ErrorOr<StringRef> SampleProfileReaderBinary::readString() { 4870b57cec5SDimitry Andric StringRef Str(reinterpret_cast<const char *>(Data)); 4880b57cec5SDimitry Andric if (Data + Str.size() + 1 > End) { 4895f757f3fSDimitry Andric std::error_code EC = sampleprof_error::truncated; 4900b57cec5SDimitry Andric reportError(0, EC.message()); 4910b57cec5SDimitry Andric return EC; 4920b57cec5SDimitry Andric } 4930b57cec5SDimitry Andric 4940b57cec5SDimitry Andric Data += Str.size() + 1; 4950b57cec5SDimitry Andric return Str; 4960b57cec5SDimitry Andric } 4970b57cec5SDimitry Andric 4980b57cec5SDimitry Andric template <typename T> 4990b57cec5SDimitry Andric ErrorOr<T> SampleProfileReaderBinary::readUnencodedNumber() { 5000b57cec5SDimitry Andric if (Data + sizeof(T) > End) { 5015f757f3fSDimitry Andric std::error_code EC = sampleprof_error::truncated; 5020b57cec5SDimitry Andric reportError(0, EC.message()); 5030b57cec5SDimitry Andric return EC; 5040b57cec5SDimitry Andric } 5050b57cec5SDimitry Andric 5060b57cec5SDimitry Andric using namespace support; 507*0fca6ea1SDimitry Andric T Val = endian::readNext<T, llvm::endianness::little>(Data); 5080b57cec5SDimitry Andric return Val; 5090b57cec5SDimitry Andric } 5100b57cec5SDimitry Andric 5110b57cec5SDimitry Andric template <typename T> 51206c3fb27SDimitry Andric inline ErrorOr<size_t> SampleProfileReaderBinary::readStringIndex(T &Table) { 51306c3fb27SDimitry Andric auto Idx = readNumber<size_t>(); 5140b57cec5SDimitry Andric if (std::error_code EC = Idx.getError()) 5150b57cec5SDimitry Andric return EC; 5160b57cec5SDimitry Andric if (*Idx >= Table.size()) 5170b57cec5SDimitry Andric return sampleprof_error::truncated_name_table; 5180b57cec5SDimitry Andric return *Idx; 5190b57cec5SDimitry Andric } 5200b57cec5SDimitry Andric 5215f757f3fSDimitry Andric ErrorOr<FunctionId> 5225f757f3fSDimitry Andric SampleProfileReaderBinary::readStringFromTable(size_t *RetIdx) { 5230b57cec5SDimitry Andric auto Idx = readStringIndex(NameTable); 5240b57cec5SDimitry Andric if (std::error_code EC = Idx.getError()) 5250b57cec5SDimitry Andric return EC; 5265f757f3fSDimitry Andric if (RetIdx) 5275f757f3fSDimitry Andric *RetIdx = *Idx; 5285f757f3fSDimitry Andric return NameTable[*Idx]; 52906c3fb27SDimitry Andric } 53006c3fb27SDimitry Andric 5315f757f3fSDimitry Andric ErrorOr<SampleContextFrames> 5325f757f3fSDimitry Andric SampleProfileReaderBinary::readContextFromTable(size_t *RetIdx) { 53306c3fb27SDimitry Andric auto ContextIdx = readNumber<size_t>(); 53406c3fb27SDimitry Andric if (std::error_code EC = ContextIdx.getError()) 53506c3fb27SDimitry Andric return EC; 53606c3fb27SDimitry Andric if (*ContextIdx >= CSNameTable.size()) 53706c3fb27SDimitry Andric return sampleprof_error::truncated_name_table; 5385f757f3fSDimitry Andric if (RetIdx) 5395f757f3fSDimitry Andric *RetIdx = *ContextIdx; 54006c3fb27SDimitry Andric return CSNameTable[*ContextIdx]; 5410b57cec5SDimitry Andric } 5420b57cec5SDimitry Andric 5435f757f3fSDimitry Andric ErrorOr<std::pair<SampleContext, uint64_t>> 5445f757f3fSDimitry Andric SampleProfileReaderBinary::readSampleContextFromTable() { 5455f757f3fSDimitry Andric SampleContext Context; 5465f757f3fSDimitry Andric size_t Idx; 54706c3fb27SDimitry Andric if (ProfileIsCS) { 5485f757f3fSDimitry Andric auto FContext(readContextFromTable(&Idx)); 54906c3fb27SDimitry Andric if (std::error_code EC = FContext.getError()) 55006c3fb27SDimitry Andric return EC; 5515f757f3fSDimitry Andric Context = SampleContext(*FContext); 55206c3fb27SDimitry Andric } else { 5535f757f3fSDimitry Andric auto FName(readStringFromTable(&Idx)); 554349cc55cSDimitry Andric if (std::error_code EC = FName.getError()) 555349cc55cSDimitry Andric return EC; 5565f757f3fSDimitry Andric Context = SampleContext(*FName); 557349cc55cSDimitry Andric } 5585f757f3fSDimitry Andric // Since MD5SampleContextStart may point to the profile's file data, need to 5595f757f3fSDimitry Andric // make sure it is reading the same value on big endian CPU. 5605f757f3fSDimitry Andric uint64_t Hash = support::endian::read64le(MD5SampleContextStart + Idx); 5615f757f3fSDimitry Andric // Lazy computing of hash value, write back to the table to cache it. Only 5625f757f3fSDimitry Andric // compute the context's hash value if it is being referenced for the first 5635f757f3fSDimitry Andric // time. 5645f757f3fSDimitry Andric if (Hash == 0) { 5655f757f3fSDimitry Andric assert(MD5SampleContextStart == MD5SampleContextTable.data()); 5665f757f3fSDimitry Andric Hash = Context.getHashCode(); 5675f757f3fSDimitry Andric support::endian::write64le(&MD5SampleContextTable[Idx], Hash); 5685f757f3fSDimitry Andric } 5695f757f3fSDimitry Andric return std::make_pair(Context, Hash); 5700b57cec5SDimitry Andric } 5710b57cec5SDimitry Andric 5720b57cec5SDimitry Andric std::error_code 5730b57cec5SDimitry Andric SampleProfileReaderBinary::readProfile(FunctionSamples &FProfile) { 5740b57cec5SDimitry Andric auto NumSamples = readNumber<uint64_t>(); 5750b57cec5SDimitry Andric if (std::error_code EC = NumSamples.getError()) 5760b57cec5SDimitry Andric return EC; 5770b57cec5SDimitry Andric FProfile.addTotalSamples(*NumSamples); 5780b57cec5SDimitry Andric 5790b57cec5SDimitry Andric // Read the samples in the body. 5800b57cec5SDimitry Andric auto NumRecords = readNumber<uint32_t>(); 5810b57cec5SDimitry Andric if (std::error_code EC = NumRecords.getError()) 5820b57cec5SDimitry Andric return EC; 5830b57cec5SDimitry Andric 5840b57cec5SDimitry Andric for (uint32_t I = 0; I < *NumRecords; ++I) { 5850b57cec5SDimitry Andric auto LineOffset = readNumber<uint64_t>(); 5860b57cec5SDimitry Andric if (std::error_code EC = LineOffset.getError()) 5870b57cec5SDimitry Andric return EC; 5880b57cec5SDimitry Andric 5890b57cec5SDimitry Andric if (!isOffsetLegal(*LineOffset)) { 5900b57cec5SDimitry Andric return std::error_code(); 5910b57cec5SDimitry Andric } 5920b57cec5SDimitry Andric 5930b57cec5SDimitry Andric auto Discriminator = readNumber<uint64_t>(); 5940b57cec5SDimitry Andric if (std::error_code EC = Discriminator.getError()) 5950b57cec5SDimitry Andric return EC; 5960b57cec5SDimitry Andric 5970b57cec5SDimitry Andric auto NumSamples = readNumber<uint64_t>(); 5980b57cec5SDimitry Andric if (std::error_code EC = NumSamples.getError()) 5990b57cec5SDimitry Andric return EC; 6000b57cec5SDimitry Andric 6010b57cec5SDimitry Andric auto NumCalls = readNumber<uint32_t>(); 6020b57cec5SDimitry Andric if (std::error_code EC = NumCalls.getError()) 6030b57cec5SDimitry Andric return EC; 6040b57cec5SDimitry Andric 605fe6060f1SDimitry Andric // Here we handle FS discriminators: 606fe6060f1SDimitry Andric uint32_t DiscriminatorVal = (*Discriminator) & getDiscriminatorMask(); 607fe6060f1SDimitry Andric 6080b57cec5SDimitry Andric for (uint32_t J = 0; J < *NumCalls; ++J) { 6090b57cec5SDimitry Andric auto CalledFunction(readStringFromTable()); 6100b57cec5SDimitry Andric if (std::error_code EC = CalledFunction.getError()) 6110b57cec5SDimitry Andric return EC; 6120b57cec5SDimitry Andric 6130b57cec5SDimitry Andric auto CalledFunctionSamples = readNumber<uint64_t>(); 6140b57cec5SDimitry Andric if (std::error_code EC = CalledFunctionSamples.getError()) 6150b57cec5SDimitry Andric return EC; 6160b57cec5SDimitry Andric 617fe6060f1SDimitry Andric FProfile.addCalledTargetSamples(*LineOffset, DiscriminatorVal, 6180b57cec5SDimitry Andric *CalledFunction, *CalledFunctionSamples); 6190b57cec5SDimitry Andric } 6200b57cec5SDimitry Andric 621fe6060f1SDimitry Andric FProfile.addBodySamples(*LineOffset, DiscriminatorVal, *NumSamples); 6220b57cec5SDimitry Andric } 6230b57cec5SDimitry Andric 6240b57cec5SDimitry Andric // Read all the samples for inlined function calls. 6250b57cec5SDimitry Andric auto NumCallsites = readNumber<uint32_t>(); 6260b57cec5SDimitry Andric if (std::error_code EC = NumCallsites.getError()) 6270b57cec5SDimitry Andric return EC; 6280b57cec5SDimitry Andric 6290b57cec5SDimitry Andric for (uint32_t J = 0; J < *NumCallsites; ++J) { 6300b57cec5SDimitry Andric auto LineOffset = readNumber<uint64_t>(); 6310b57cec5SDimitry Andric if (std::error_code EC = LineOffset.getError()) 6320b57cec5SDimitry Andric return EC; 6330b57cec5SDimitry Andric 6340b57cec5SDimitry Andric auto Discriminator = readNumber<uint64_t>(); 6350b57cec5SDimitry Andric if (std::error_code EC = Discriminator.getError()) 6360b57cec5SDimitry Andric return EC; 6370b57cec5SDimitry Andric 6380b57cec5SDimitry Andric auto FName(readStringFromTable()); 6390b57cec5SDimitry Andric if (std::error_code EC = FName.getError()) 6400b57cec5SDimitry Andric return EC; 6410b57cec5SDimitry Andric 642fe6060f1SDimitry Andric // Here we handle FS discriminators: 643fe6060f1SDimitry Andric uint32_t DiscriminatorVal = (*Discriminator) & getDiscriminatorMask(); 644fe6060f1SDimitry Andric 6450b57cec5SDimitry Andric FunctionSamples &CalleeProfile = FProfile.functionSamplesAt( 6465f757f3fSDimitry Andric LineLocation(*LineOffset, DiscriminatorVal))[*FName]; 6475f757f3fSDimitry Andric CalleeProfile.setFunction(*FName); 6480b57cec5SDimitry Andric if (std::error_code EC = readProfile(CalleeProfile)) 6490b57cec5SDimitry Andric return EC; 6500b57cec5SDimitry Andric } 6510b57cec5SDimitry Andric 6520b57cec5SDimitry Andric return sampleprof_error::success; 6530b57cec5SDimitry Andric } 6540b57cec5SDimitry Andric 6558bcb0991SDimitry Andric std::error_code 6568bcb0991SDimitry Andric SampleProfileReaderBinary::readFuncProfile(const uint8_t *Start) { 6578bcb0991SDimitry Andric Data = Start; 6580b57cec5SDimitry Andric auto NumHeadSamples = readNumber<uint64_t>(); 6590b57cec5SDimitry Andric if (std::error_code EC = NumHeadSamples.getError()) 6600b57cec5SDimitry Andric return EC; 6610b57cec5SDimitry Andric 6625f757f3fSDimitry Andric auto FContextHash(readSampleContextFromTable()); 6635f757f3fSDimitry Andric if (std::error_code EC = FContextHash.getError()) 6640b57cec5SDimitry Andric return EC; 6650b57cec5SDimitry Andric 6665f757f3fSDimitry Andric auto &[FContext, Hash] = *FContextHash; 6675f757f3fSDimitry Andric // Use the cached hash value for insertion instead of recalculating it. 6685f757f3fSDimitry Andric auto Res = Profiles.try_emplace(Hash, FContext, FunctionSamples()); 6695f757f3fSDimitry Andric FunctionSamples &FProfile = Res.first->second; 6705f757f3fSDimitry Andric FProfile.setContext(FContext); 6710b57cec5SDimitry Andric FProfile.addHeadSamples(*NumHeadSamples); 6720b57cec5SDimitry Andric 6735f757f3fSDimitry Andric if (FContext.hasContext()) 674d409305fSDimitry Andric CSProfileCount++; 675d409305fSDimitry Andric 6760b57cec5SDimitry Andric if (std::error_code EC = readProfile(FProfile)) 6770b57cec5SDimitry Andric return EC; 6780b57cec5SDimitry Andric return sampleprof_error::success; 6790b57cec5SDimitry Andric } 6800b57cec5SDimitry Andric 6818bcb0991SDimitry Andric std::error_code SampleProfileReaderBinary::readImpl() { 682fe6060f1SDimitry Andric ProfileIsFS = ProfileIsFSDisciminator; 683349cc55cSDimitry Andric FunctionSamples::ProfileIsFS = ProfileIsFS; 68406c3fb27SDimitry Andric while (Data < End) { 6858bcb0991SDimitry Andric if (std::error_code EC = readFuncProfile(Data)) 6860b57cec5SDimitry Andric return EC; 6870b57cec5SDimitry Andric } 6880b57cec5SDimitry Andric 6890b57cec5SDimitry Andric return sampleprof_error::success; 6900b57cec5SDimitry Andric } 6910b57cec5SDimitry Andric 692e8d8bef9SDimitry Andric std::error_code SampleProfileReaderExtBinaryBase::readOneSection( 6935ffd83dbSDimitry Andric const uint8_t *Start, uint64_t Size, const SecHdrTableEntry &Entry) { 6948bcb0991SDimitry Andric Data = Start; 6958bcb0991SDimitry Andric End = Start + Size; 6965ffd83dbSDimitry Andric switch (Entry.Type) { 6978bcb0991SDimitry Andric case SecProfSummary: 6988bcb0991SDimitry Andric if (std::error_code EC = readSummary()) 6998bcb0991SDimitry Andric return EC; 7005ffd83dbSDimitry Andric if (hasSecFlag(Entry, SecProfSummaryFlags::SecFlagPartial)) 7015ffd83dbSDimitry Andric Summary->setPartialProfile(true); 702fe6060f1SDimitry Andric if (hasSecFlag(Entry, SecProfSummaryFlags::SecFlagFullContext)) 70381ad6265SDimitry Andric FunctionSamples::ProfileIsCS = ProfileIsCS = true; 70481ad6265SDimitry Andric if (hasSecFlag(Entry, SecProfSummaryFlags::SecFlagIsPreInlined)) 70581ad6265SDimitry Andric FunctionSamples::ProfileIsPreInlined = ProfileIsPreInlined = true; 706fe6060f1SDimitry Andric if (hasSecFlag(Entry, SecProfSummaryFlags::SecFlagFSDiscriminator)) 707fe6060f1SDimitry Andric FunctionSamples::ProfileIsFS = ProfileIsFS = true; 7088bcb0991SDimitry Andric break; 709e8d8bef9SDimitry Andric case SecNameTable: { 71006c3fb27SDimitry Andric bool FixedLengthMD5 = 711e8d8bef9SDimitry Andric hasSecFlag(Entry, SecNameTableFlags::SecFlagFixedLengthMD5); 712e8d8bef9SDimitry Andric bool UseMD5 = hasSecFlag(Entry, SecNameTableFlags::SecFlagMD5Name); 71306c3fb27SDimitry Andric // UseMD5 means if THIS section uses MD5, ProfileIsMD5 means if the entire 71406c3fb27SDimitry Andric // profile uses MD5 for function name matching in IPO passes. 71506c3fb27SDimitry Andric ProfileIsMD5 = ProfileIsMD5 || UseMD5; 716fe6060f1SDimitry Andric FunctionSamples::HasUniqSuffix = 717fe6060f1SDimitry Andric hasSecFlag(Entry, SecNameTableFlags::SecFlagUniqSuffix); 71806c3fb27SDimitry Andric if (std::error_code EC = readNameTableSec(UseMD5, FixedLengthMD5)) 7198bcb0991SDimitry Andric return EC; 7208bcb0991SDimitry Andric break; 721e8d8bef9SDimitry Andric } 722349cc55cSDimitry Andric case SecCSNameTable: { 723349cc55cSDimitry Andric if (std::error_code EC = readCSNameTableSec()) 724349cc55cSDimitry Andric return EC; 725349cc55cSDimitry Andric break; 726349cc55cSDimitry Andric } 7278bcb0991SDimitry Andric case SecLBRProfile: 7288bcb0991SDimitry Andric if (std::error_code EC = readFuncProfiles()) 7298bcb0991SDimitry Andric return EC; 7308bcb0991SDimitry Andric break; 7318bcb0991SDimitry Andric case SecFuncOffsetTable: 73206c3fb27SDimitry Andric // If module is absent, we are using LLVM tools, and need to read all 73306c3fb27SDimitry Andric // profiles, so skip reading the function offset table. 73406c3fb27SDimitry Andric if (!M) { 73506c3fb27SDimitry Andric Data = End; 73606c3fb27SDimitry Andric } else { 73706c3fb27SDimitry Andric assert((!ProfileIsCS || 73806c3fb27SDimitry Andric hasSecFlag(Entry, SecFuncOffsetFlags::SecFlagOrdered)) && 73906c3fb27SDimitry Andric "func offset table should always be sorted in CS profile"); 7408bcb0991SDimitry Andric if (std::error_code EC = readFuncOffsetTable()) 7418bcb0991SDimitry Andric return EC; 74206c3fb27SDimitry Andric } 7438bcb0991SDimitry Andric break; 744fe6060f1SDimitry Andric case SecFuncMetadata: { 745e8d8bef9SDimitry Andric ProfileIsProbeBased = 746e8d8bef9SDimitry Andric hasSecFlag(Entry, SecFuncMetadataFlags::SecFlagIsProbeBased); 747e8d8bef9SDimitry Andric FunctionSamples::ProfileIsProbeBased = ProfileIsProbeBased; 748fe6060f1SDimitry Andric bool HasAttribute = 749fe6060f1SDimitry Andric hasSecFlag(Entry, SecFuncMetadataFlags::SecFlagHasAttribute); 750fe6060f1SDimitry Andric if (std::error_code EC = readFuncMetadata(HasAttribute)) 751e8d8bef9SDimitry Andric return EC; 752e8d8bef9SDimitry Andric break; 753fe6060f1SDimitry Andric } 754e8d8bef9SDimitry Andric case SecProfileSymbolList: 755e8d8bef9SDimitry Andric if (std::error_code EC = readProfileSymbolList()) 756e8d8bef9SDimitry Andric return EC; 757e8d8bef9SDimitry Andric break; 7588bcb0991SDimitry Andric default: 759e8d8bef9SDimitry Andric if (std::error_code EC = readCustomSection(Entry)) 760e8d8bef9SDimitry Andric return EC; 7618bcb0991SDimitry Andric break; 7628bcb0991SDimitry Andric } 7638bcb0991SDimitry Andric return sampleprof_error::success; 7648bcb0991SDimitry Andric } 7658bcb0991SDimitry Andric 76606c3fb27SDimitry Andric bool SampleProfileReaderExtBinaryBase::useFuncOffsetList() const { 76706c3fb27SDimitry Andric // If profile is CS, the function offset section is expected to consist of 76806c3fb27SDimitry Andric // sequences of contexts in pre-order layout 76906c3fb27SDimitry Andric // (e.g. [A, A:1 @ B, A:1 @ B:2.3 @ C] [D, D:1 @ E]), so that when a matched 77006c3fb27SDimitry Andric // context in the module is found, the profiles of all its callees are 77106c3fb27SDimitry Andric // recursively loaded. A list is needed since the order of profiles matters. 77206c3fb27SDimitry Andric if (ProfileIsCS) 77306c3fb27SDimitry Andric return true; 77406c3fb27SDimitry Andric 77506c3fb27SDimitry Andric // If the profile is MD5, use the map container to lookup functions in 77606c3fb27SDimitry Andric // the module. A remapper has no use on MD5 names. 77706c3fb27SDimitry Andric if (useMD5()) 77806c3fb27SDimitry Andric return false; 77906c3fb27SDimitry Andric 78006c3fb27SDimitry Andric // Profile is not MD5 and if a remapper is present, the remapped name of 78106c3fb27SDimitry Andric // every function needed to be matched against the module, so use the list 78206c3fb27SDimitry Andric // container since each entry is accessed. 78306c3fb27SDimitry Andric if (Remapper) 78406c3fb27SDimitry Andric return true; 78506c3fb27SDimitry Andric 78606c3fb27SDimitry Andric // Otherwise use the map container for faster lookup. 78706c3fb27SDimitry Andric // TODO: If the cardinality of the function offset section is much smaller 78806c3fb27SDimitry Andric // than the number of functions in the module, using the list container can 78906c3fb27SDimitry Andric // be always faster, but we need to figure out the constant factor to 79006c3fb27SDimitry Andric // determine the cutoff. 79106c3fb27SDimitry Andric return false; 79206c3fb27SDimitry Andric } 79306c3fb27SDimitry Andric 79406c3fb27SDimitry Andric 795fe6060f1SDimitry Andric bool SampleProfileReaderExtBinaryBase::collectFuncsFromModule() { 796fe6060f1SDimitry Andric if (!M) 797fe6060f1SDimitry Andric return false; 7988bcb0991SDimitry Andric FuncsToUse.clear(); 799fe6060f1SDimitry Andric for (auto &F : *M) 8008bcb0991SDimitry Andric FuncsToUse.insert(FunctionSamples::getCanonicalFnName(F)); 801fe6060f1SDimitry Andric return true; 8028bcb0991SDimitry Andric } 8038bcb0991SDimitry Andric 804e8d8bef9SDimitry Andric std::error_code SampleProfileReaderExtBinaryBase::readFuncOffsetTable() { 80506c3fb27SDimitry Andric // If there are more than one function offset section, the profile associated 80606c3fb27SDimitry Andric // with the previous section has to be done reading before next one is read. 807e8d8bef9SDimitry Andric FuncOffsetTable.clear(); 80806c3fb27SDimitry Andric FuncOffsetList.clear(); 809e8d8bef9SDimitry Andric 8108bcb0991SDimitry Andric auto Size = readNumber<uint64_t>(); 8118bcb0991SDimitry Andric if (std::error_code EC = Size.getError()) 8128bcb0991SDimitry Andric return EC; 8138bcb0991SDimitry Andric 81406c3fb27SDimitry Andric bool UseFuncOffsetList = useFuncOffsetList(); 81506c3fb27SDimitry Andric if (UseFuncOffsetList) 81606c3fb27SDimitry Andric FuncOffsetList.reserve(*Size); 81706c3fb27SDimitry Andric else 8188bcb0991SDimitry Andric FuncOffsetTable.reserve(*Size); 819349cc55cSDimitry Andric 820bdd1243dSDimitry Andric for (uint64_t I = 0; I < *Size; ++I) { 8215f757f3fSDimitry Andric auto FContextHash(readSampleContextFromTable()); 8225f757f3fSDimitry Andric if (std::error_code EC = FContextHash.getError()) 8238bcb0991SDimitry Andric return EC; 8248bcb0991SDimitry Andric 8255f757f3fSDimitry Andric auto &[FContext, Hash] = *FContextHash; 8268bcb0991SDimitry Andric auto Offset = readNumber<uint64_t>(); 8278bcb0991SDimitry Andric if (std::error_code EC = Offset.getError()) 8288bcb0991SDimitry Andric return EC; 8298bcb0991SDimitry Andric 83006c3fb27SDimitry Andric if (UseFuncOffsetList) 8315f757f3fSDimitry Andric FuncOffsetList.emplace_back(FContext, *Offset); 83206c3fb27SDimitry Andric else 8335f757f3fSDimitry Andric // Because Porfiles replace existing value with new value if collision 8345f757f3fSDimitry Andric // happens, we also use the latest offset so that they are consistent. 8355f757f3fSDimitry Andric FuncOffsetTable[Hash] = *Offset; 8368bcb0991SDimitry Andric } 837349cc55cSDimitry Andric 8388bcb0991SDimitry Andric return sampleprof_error::success; 8398bcb0991SDimitry Andric } 8408bcb0991SDimitry Andric 841e8d8bef9SDimitry Andric std::error_code SampleProfileReaderExtBinaryBase::readFuncProfiles() { 842fe6060f1SDimitry Andric // Collect functions used by current module if the Reader has been 843fe6060f1SDimitry Andric // given a module. 844fe6060f1SDimitry Andric // collectFuncsFromModule uses FunctionSamples::getCanonicalFnName 845fe6060f1SDimitry Andric // which will query FunctionSamples::HasUniqSuffix, so it has to be 846fe6060f1SDimitry Andric // called after FunctionSamples::HasUniqSuffix is set, i.e. after 847fe6060f1SDimitry Andric // NameTable section is read. 848fe6060f1SDimitry Andric bool LoadFuncsToBeUsed = collectFuncsFromModule(); 849fe6060f1SDimitry Andric 85006c3fb27SDimitry Andric // When LoadFuncsToBeUsed is false, we are using LLVM tool, need to read all 85106c3fb27SDimitry Andric // profiles. 8528bcb0991SDimitry Andric const uint8_t *Start = Data; 853fe6060f1SDimitry Andric if (!LoadFuncsToBeUsed) { 8548bcb0991SDimitry Andric while (Data < End) { 8558bcb0991SDimitry Andric if (std::error_code EC = readFuncProfile(Data)) 8568bcb0991SDimitry Andric return EC; 8578bcb0991SDimitry Andric } 8588bcb0991SDimitry Andric assert(Data == End && "More data is read than expected"); 859d409305fSDimitry Andric } else { 860fe6060f1SDimitry Andric // Load function profiles on demand. 8618bcb0991SDimitry Andric if (Remapper) { 8628bcb0991SDimitry Andric for (auto Name : FuncsToUse) { 8638bcb0991SDimitry Andric Remapper->insert(Name); 8648bcb0991SDimitry Andric } 8658bcb0991SDimitry Andric } 8668bcb0991SDimitry Andric 86781ad6265SDimitry Andric if (ProfileIsCS) { 86806c3fb27SDimitry Andric assert(useFuncOffsetList()); 869349cc55cSDimitry Andric DenseSet<uint64_t> FuncGuidsToUse; 870349cc55cSDimitry Andric if (useMD5()) { 871349cc55cSDimitry Andric for (auto Name : FuncsToUse) 872349cc55cSDimitry Andric FuncGuidsToUse.insert(Function::getGUID(Name)); 873349cc55cSDimitry Andric } 874349cc55cSDimitry Andric 875349cc55cSDimitry Andric // For each function in current module, load all context profiles for 876349cc55cSDimitry Andric // the function as well as their callee contexts which can help profile 877349cc55cSDimitry Andric // guided importing for ThinLTO. This can be achieved by walking 878349cc55cSDimitry Andric // through an ordered context container, where contexts are laid out 879349cc55cSDimitry Andric // as if they were walked in preorder of a context trie. While 880349cc55cSDimitry Andric // traversing the trie, a link to the highest common ancestor node is 881349cc55cSDimitry Andric // kept so that all of its decendants will be loaded. 882349cc55cSDimitry Andric const SampleContext *CommonContext = nullptr; 88306c3fb27SDimitry Andric for (const auto &NameOffset : FuncOffsetList) { 884349cc55cSDimitry Andric const auto &FContext = NameOffset.first; 8855f757f3fSDimitry Andric FunctionId FName = FContext.getFunction(); 8865f757f3fSDimitry Andric StringRef FNameString; 8875f757f3fSDimitry Andric if (!useMD5()) 8885f757f3fSDimitry Andric FNameString = FName.stringRef(); 8895f757f3fSDimitry Andric 890349cc55cSDimitry Andric // For function in the current module, keep its farthest ancestor 891349cc55cSDimitry Andric // context. This can be used to load itself and its child and 892349cc55cSDimitry Andric // sibling contexts. 8935f757f3fSDimitry Andric if ((useMD5() && FuncGuidsToUse.count(FName.getHashCode())) || 8945f757f3fSDimitry Andric (!useMD5() && (FuncsToUse.count(FNameString) || 8955f757f3fSDimitry Andric (Remapper && Remapper->exist(FNameString))))) { 896*0fca6ea1SDimitry Andric if (!CommonContext || !CommonContext->isPrefixOf(FContext)) 897349cc55cSDimitry Andric CommonContext = &FContext; 898349cc55cSDimitry Andric } 899349cc55cSDimitry Andric 900349cc55cSDimitry Andric if (CommonContext == &FContext || 901*0fca6ea1SDimitry Andric (CommonContext && CommonContext->isPrefixOf(FContext))) { 902349cc55cSDimitry Andric // Load profile for the current context which originated from 903349cc55cSDimitry Andric // the common ancestor. 904349cc55cSDimitry Andric const uint8_t *FuncProfileAddr = Start + NameOffset.second; 905349cc55cSDimitry Andric if (std::error_code EC = readFuncProfile(FuncProfileAddr)) 906349cc55cSDimitry Andric return EC; 907349cc55cSDimitry Andric } 908349cc55cSDimitry Andric } 90906c3fb27SDimitry Andric } else if (useMD5()) { 91006c3fb27SDimitry Andric assert(!useFuncOffsetList()); 9115ffd83dbSDimitry Andric for (auto Name : FuncsToUse) { 9125f757f3fSDimitry Andric auto GUID = MD5Hash(Name); 9135f757f3fSDimitry Andric auto iter = FuncOffsetTable.find(GUID); 9145ffd83dbSDimitry Andric if (iter == FuncOffsetTable.end()) 9155ffd83dbSDimitry Andric continue; 9165ffd83dbSDimitry Andric const uint8_t *FuncProfileAddr = Start + iter->second; 91706c3fb27SDimitry Andric if (std::error_code EC = readFuncProfile(FuncProfileAddr)) 91806c3fb27SDimitry Andric return EC; 91906c3fb27SDimitry Andric } 92006c3fb27SDimitry Andric } else if (Remapper) { 92106c3fb27SDimitry Andric assert(useFuncOffsetList()); 92206c3fb27SDimitry Andric for (auto NameOffset : FuncOffsetList) { 92306c3fb27SDimitry Andric SampleContext FContext(NameOffset.first); 9245f757f3fSDimitry Andric auto FuncName = FContext.getFunction(); 9255f757f3fSDimitry Andric StringRef FuncNameStr = FuncName.stringRef(); 9265f757f3fSDimitry Andric if (!FuncsToUse.count(FuncNameStr) && !Remapper->exist(FuncNameStr)) 92706c3fb27SDimitry Andric continue; 92806c3fb27SDimitry Andric const uint8_t *FuncProfileAddr = Start + NameOffset.second; 9295ffd83dbSDimitry Andric if (std::error_code EC = readFuncProfile(FuncProfileAddr)) 9305ffd83dbSDimitry Andric return EC; 9315ffd83dbSDimitry Andric } 9325ffd83dbSDimitry Andric } else { 93306c3fb27SDimitry Andric assert(!useFuncOffsetList()); 93406c3fb27SDimitry Andric for (auto Name : FuncsToUse) { 9355f757f3fSDimitry Andric auto iter = FuncOffsetTable.find(MD5Hash(Name)); 93606c3fb27SDimitry Andric if (iter == FuncOffsetTable.end()) 9378bcb0991SDimitry Andric continue; 93806c3fb27SDimitry Andric const uint8_t *FuncProfileAddr = Start + iter->second; 9398bcb0991SDimitry Andric if (std::error_code EC = readFuncProfile(FuncProfileAddr)) 9408bcb0991SDimitry Andric return EC; 9418bcb0991SDimitry Andric } 9425ffd83dbSDimitry Andric } 9438bcb0991SDimitry Andric Data = End; 944d409305fSDimitry Andric } 945d409305fSDimitry Andric assert((CSProfileCount == 0 || CSProfileCount == Profiles.size()) && 946d409305fSDimitry Andric "Cannot have both context-sensitive and regular profile"); 94781ad6265SDimitry Andric assert((!CSProfileCount || ProfileIsCS) && 948fe6060f1SDimitry Andric "Section flag should be consistent with actual profile"); 9498bcb0991SDimitry Andric return sampleprof_error::success; 9508bcb0991SDimitry Andric } 9518bcb0991SDimitry Andric 952e8d8bef9SDimitry Andric std::error_code SampleProfileReaderExtBinaryBase::readProfileSymbolList() { 9538bcb0991SDimitry Andric if (!ProfSymList) 9548bcb0991SDimitry Andric ProfSymList = std::make_unique<ProfileSymbolList>(); 9558bcb0991SDimitry Andric 9568bcb0991SDimitry Andric if (std::error_code EC = ProfSymList->read(Data, End - Data)) 9578bcb0991SDimitry Andric return EC; 9588bcb0991SDimitry Andric 9598bcb0991SDimitry Andric Data = End; 9608bcb0991SDimitry Andric return sampleprof_error::success; 9618bcb0991SDimitry Andric } 9628bcb0991SDimitry Andric 9638bcb0991SDimitry Andric std::error_code SampleProfileReaderExtBinaryBase::decompressSection( 9648bcb0991SDimitry Andric const uint8_t *SecStart, const uint64_t SecSize, 9658bcb0991SDimitry Andric const uint8_t *&DecompressBuf, uint64_t &DecompressBufSize) { 9668bcb0991SDimitry Andric Data = SecStart; 9678bcb0991SDimitry Andric End = SecStart + SecSize; 9688bcb0991SDimitry Andric auto DecompressSize = readNumber<uint64_t>(); 9698bcb0991SDimitry Andric if (std::error_code EC = DecompressSize.getError()) 9708bcb0991SDimitry Andric return EC; 9718bcb0991SDimitry Andric DecompressBufSize = *DecompressSize; 9728bcb0991SDimitry Andric 9738bcb0991SDimitry Andric auto CompressSize = readNumber<uint64_t>(); 9748bcb0991SDimitry Andric if (std::error_code EC = CompressSize.getError()) 9758bcb0991SDimitry Andric return EC; 9768bcb0991SDimitry Andric 977753f127fSDimitry Andric if (!llvm::compression::zlib::isAvailable()) 9788bcb0991SDimitry Andric return sampleprof_error::zlib_unavailable; 9798bcb0991SDimitry Andric 980753f127fSDimitry Andric uint8_t *Buffer = Allocator.Allocate<uint8_t>(DecompressBufSize); 9818bcb0991SDimitry Andric size_t UCSize = DecompressBufSize; 982bdd1243dSDimitry Andric llvm::Error E = compression::zlib::decompress(ArrayRef(Data, *CompressSize), 983bdd1243dSDimitry Andric Buffer, UCSize); 9848bcb0991SDimitry Andric if (E) 9858bcb0991SDimitry Andric return sampleprof_error::uncompress_failed; 9868bcb0991SDimitry Andric DecompressBuf = reinterpret_cast<const uint8_t *>(Buffer); 9878bcb0991SDimitry Andric return sampleprof_error::success; 9888bcb0991SDimitry Andric } 9898bcb0991SDimitry Andric 9908bcb0991SDimitry Andric std::error_code SampleProfileReaderExtBinaryBase::readImpl() { 9918bcb0991SDimitry Andric const uint8_t *BufStart = 9928bcb0991SDimitry Andric reinterpret_cast<const uint8_t *>(Buffer->getBufferStart()); 9938bcb0991SDimitry Andric 9948bcb0991SDimitry Andric for (auto &Entry : SecHdrTable) { 9958bcb0991SDimitry Andric // Skip empty section. 9968bcb0991SDimitry Andric if (!Entry.Size) 9978bcb0991SDimitry Andric continue; 9988bcb0991SDimitry Andric 999e8d8bef9SDimitry Andric // Skip sections without context when SkipFlatProf is true. 1000e8d8bef9SDimitry Andric if (SkipFlatProf && hasSecFlag(Entry, SecCommonFlags::SecFlagFlat)) 1001e8d8bef9SDimitry Andric continue; 1002e8d8bef9SDimitry Andric 10038bcb0991SDimitry Andric const uint8_t *SecStart = BufStart + Entry.Offset; 10048bcb0991SDimitry Andric uint64_t SecSize = Entry.Size; 10058bcb0991SDimitry Andric 10068bcb0991SDimitry Andric // If the section is compressed, decompress it into a buffer 10078bcb0991SDimitry Andric // DecompressBuf before reading the actual data. The pointee of 10088bcb0991SDimitry Andric // 'Data' will be changed to buffer hold by DecompressBuf 10098bcb0991SDimitry Andric // temporarily when reading the actual data. 10105ffd83dbSDimitry Andric bool isCompressed = hasSecFlag(Entry, SecCommonFlags::SecFlagCompress); 10118bcb0991SDimitry Andric if (isCompressed) { 10128bcb0991SDimitry Andric const uint8_t *DecompressBuf; 10138bcb0991SDimitry Andric uint64_t DecompressBufSize; 10148bcb0991SDimitry Andric if (std::error_code EC = decompressSection( 10158bcb0991SDimitry Andric SecStart, SecSize, DecompressBuf, DecompressBufSize)) 10168bcb0991SDimitry Andric return EC; 10178bcb0991SDimitry Andric SecStart = DecompressBuf; 10188bcb0991SDimitry Andric SecSize = DecompressBufSize; 10198bcb0991SDimitry Andric } 10208bcb0991SDimitry Andric 10215ffd83dbSDimitry Andric if (std::error_code EC = readOneSection(SecStart, SecSize, Entry)) 10228bcb0991SDimitry Andric return EC; 10238bcb0991SDimitry Andric if (Data != SecStart + SecSize) 10248bcb0991SDimitry Andric return sampleprof_error::malformed; 10258bcb0991SDimitry Andric 10268bcb0991SDimitry Andric // Change the pointee of 'Data' from DecompressBuf to original Buffer. 10278bcb0991SDimitry Andric if (isCompressed) { 10288bcb0991SDimitry Andric Data = BufStart + Entry.Offset; 10298bcb0991SDimitry Andric End = BufStart + Buffer->getBufferSize(); 10308bcb0991SDimitry Andric } 10318bcb0991SDimitry Andric } 10328bcb0991SDimitry Andric 10338bcb0991SDimitry Andric return sampleprof_error::success; 10348bcb0991SDimitry Andric } 10358bcb0991SDimitry Andric 10360b57cec5SDimitry Andric std::error_code SampleProfileReaderRawBinary::verifySPMagic(uint64_t Magic) { 10370b57cec5SDimitry Andric if (Magic == SPMagic()) 10380b57cec5SDimitry Andric return sampleprof_error::success; 10390b57cec5SDimitry Andric return sampleprof_error::bad_magic; 10400b57cec5SDimitry Andric } 10410b57cec5SDimitry Andric 10428bcb0991SDimitry Andric std::error_code SampleProfileReaderExtBinary::verifySPMagic(uint64_t Magic) { 10438bcb0991SDimitry Andric if (Magic == SPMagic(SPF_Ext_Binary)) 10448bcb0991SDimitry Andric return sampleprof_error::success; 10458bcb0991SDimitry Andric return sampleprof_error::bad_magic; 10468bcb0991SDimitry Andric } 10478bcb0991SDimitry Andric 10488bcb0991SDimitry Andric std::error_code SampleProfileReaderBinary::readNameTable() { 104906c3fb27SDimitry Andric auto Size = readNumber<size_t>(); 10500b57cec5SDimitry Andric if (std::error_code EC = Size.getError()) 10510b57cec5SDimitry Andric return EC; 105206c3fb27SDimitry Andric 105306c3fb27SDimitry Andric // Normally if useMD5 is true, the name table should have MD5 values, not 105406c3fb27SDimitry Andric // strings, however in the case that ExtBinary profile has multiple name 105506c3fb27SDimitry Andric // tables mixing string and MD5, all of them have to be normalized to use MD5, 105606c3fb27SDimitry Andric // because optimization passes can only handle either type. 105706c3fb27SDimitry Andric bool UseMD5 = useMD5(); 105806c3fb27SDimitry Andric 105906c3fb27SDimitry Andric NameTable.clear(); 106006c3fb27SDimitry Andric NameTable.reserve(*Size); 10615f757f3fSDimitry Andric if (!ProfileIsCS) { 10625f757f3fSDimitry Andric MD5SampleContextTable.clear(); 10635f757f3fSDimitry Andric if (UseMD5) 10645f757f3fSDimitry Andric MD5SampleContextTable.reserve(*Size); 10655f757f3fSDimitry Andric else 10665f757f3fSDimitry Andric // If we are using strings, delay MD5 computation since only a portion of 10675f757f3fSDimitry Andric // names are used by top level functions. Use 0 to indicate MD5 value is 10685f757f3fSDimitry Andric // to be calculated as no known string has a MD5 value of 0. 10695f757f3fSDimitry Andric MD5SampleContextTable.resize(*Size); 10705f757f3fSDimitry Andric } 107106c3fb27SDimitry Andric for (size_t I = 0; I < *Size; ++I) { 10720b57cec5SDimitry Andric auto Name(readString()); 10730b57cec5SDimitry Andric if (std::error_code EC = Name.getError()) 10740b57cec5SDimitry Andric return EC; 107506c3fb27SDimitry Andric if (UseMD5) { 10765f757f3fSDimitry Andric FunctionId FID(*Name); 10775f757f3fSDimitry Andric if (!ProfileIsCS) 10785f757f3fSDimitry Andric MD5SampleContextTable.emplace_back(FID.getHashCode()); 10795f757f3fSDimitry Andric NameTable.emplace_back(FID); 108006c3fb27SDimitry Andric } else 10815f757f3fSDimitry Andric NameTable.push_back(FunctionId(*Name)); 10820b57cec5SDimitry Andric } 10835f757f3fSDimitry Andric if (!ProfileIsCS) 10845f757f3fSDimitry Andric MD5SampleContextStart = MD5SampleContextTable.data(); 10850b57cec5SDimitry Andric return sampleprof_error::success; 10860b57cec5SDimitry Andric } 10870b57cec5SDimitry Andric 108806c3fb27SDimitry Andric std::error_code 108906c3fb27SDimitry Andric SampleProfileReaderExtBinaryBase::readNameTableSec(bool IsMD5, 109006c3fb27SDimitry Andric bool FixedLengthMD5) { 109106c3fb27SDimitry Andric if (FixedLengthMD5) { 109206c3fb27SDimitry Andric if (!IsMD5) 109306c3fb27SDimitry Andric errs() << "If FixedLengthMD5 is true, UseMD5 has to be true"; 109406c3fb27SDimitry Andric auto Size = readNumber<size_t>(); 10955ffd83dbSDimitry Andric if (std::error_code EC = Size.getError()) 10965ffd83dbSDimitry Andric return EC; 109706c3fb27SDimitry Andric 109806c3fb27SDimitry Andric assert(Data + (*Size) * sizeof(uint64_t) == End && 109906c3fb27SDimitry Andric "Fixed length MD5 name table does not contain specified number of " 110006c3fb27SDimitry Andric "entries"); 110106c3fb27SDimitry Andric if (Data + (*Size) * sizeof(uint64_t) > End) 110206c3fb27SDimitry Andric return sampleprof_error::truncated; 110306c3fb27SDimitry Andric 110406c3fb27SDimitry Andric NameTable.clear(); 11055f757f3fSDimitry Andric NameTable.reserve(*Size); 11065f757f3fSDimitry Andric for (size_t I = 0; I < *Size; ++I) { 11075f757f3fSDimitry Andric using namespace support; 11085f757f3fSDimitry Andric uint64_t FID = endian::read<uint64_t, endianness::little, unaligned>( 11095f757f3fSDimitry Andric Data + I * sizeof(uint64_t)); 11105f757f3fSDimitry Andric NameTable.emplace_back(FunctionId(FID)); 11115f757f3fSDimitry Andric } 11125f757f3fSDimitry Andric if (!ProfileIsCS) 11135f757f3fSDimitry Andric MD5SampleContextStart = reinterpret_cast<const uint64_t *>(Data); 1114e8d8bef9SDimitry Andric Data = Data + (*Size) * sizeof(uint64_t); 1115e8d8bef9SDimitry Andric return sampleprof_error::success; 1116e8d8bef9SDimitry Andric } 111706c3fb27SDimitry Andric 111806c3fb27SDimitry Andric if (IsMD5) { 111906c3fb27SDimitry Andric assert(!FixedLengthMD5 && "FixedLengthMD5 should be unreachable here"); 112006c3fb27SDimitry Andric auto Size = readNumber<size_t>(); 112106c3fb27SDimitry Andric if (std::error_code EC = Size.getError()) 112206c3fb27SDimitry Andric return EC; 112306c3fb27SDimitry Andric 112406c3fb27SDimitry Andric NameTable.clear(); 1125e8d8bef9SDimitry Andric NameTable.reserve(*Size); 11265f757f3fSDimitry Andric if (!ProfileIsCS) 11275f757f3fSDimitry Andric MD5SampleContextTable.resize(*Size); 112806c3fb27SDimitry Andric for (size_t I = 0; I < *Size; ++I) { 11295ffd83dbSDimitry Andric auto FID = readNumber<uint64_t>(); 11305ffd83dbSDimitry Andric if (std::error_code EC = FID.getError()) 11315ffd83dbSDimitry Andric return EC; 11325f757f3fSDimitry Andric if (!ProfileIsCS) 11335f757f3fSDimitry Andric support::endian::write64le(&MD5SampleContextTable[I], *FID); 11345f757f3fSDimitry Andric NameTable.emplace_back(FunctionId(*FID)); 11355ffd83dbSDimitry Andric } 11365f757f3fSDimitry Andric if (!ProfileIsCS) 11375f757f3fSDimitry Andric MD5SampleContextStart = MD5SampleContextTable.data(); 11385ffd83dbSDimitry Andric return sampleprof_error::success; 11395ffd83dbSDimitry Andric } 11405ffd83dbSDimitry Andric 11415ffd83dbSDimitry Andric return SampleProfileReaderBinary::readNameTable(); 11425ffd83dbSDimitry Andric } 11435ffd83dbSDimitry Andric 1144349cc55cSDimitry Andric // Read in the CS name table section, which basically contains a list of context 1145349cc55cSDimitry Andric // vectors. Each element of a context vector, aka a frame, refers to the 1146349cc55cSDimitry Andric // underlying raw function names that are stored in the name table, as well as 1147349cc55cSDimitry Andric // a callsite identifier that only makes sense for non-leaf frames. 1148349cc55cSDimitry Andric std::error_code SampleProfileReaderExtBinaryBase::readCSNameTableSec() { 114906c3fb27SDimitry Andric auto Size = readNumber<size_t>(); 1150349cc55cSDimitry Andric if (std::error_code EC = Size.getError()) 1151349cc55cSDimitry Andric return EC; 1152349cc55cSDimitry Andric 115306c3fb27SDimitry Andric CSNameTable.clear(); 115406c3fb27SDimitry Andric CSNameTable.reserve(*Size); 11555f757f3fSDimitry Andric if (ProfileIsCS) { 11565f757f3fSDimitry Andric // Delay MD5 computation of CS context until they are needed. Use 0 to 11575f757f3fSDimitry Andric // indicate MD5 value is to be calculated as no known string has a MD5 11585f757f3fSDimitry Andric // value of 0. 11595f757f3fSDimitry Andric MD5SampleContextTable.clear(); 11605f757f3fSDimitry Andric MD5SampleContextTable.resize(*Size); 11615f757f3fSDimitry Andric MD5SampleContextStart = MD5SampleContextTable.data(); 11625f757f3fSDimitry Andric } 116306c3fb27SDimitry Andric for (size_t I = 0; I < *Size; ++I) { 116406c3fb27SDimitry Andric CSNameTable.emplace_back(SampleContextFrameVector()); 1165349cc55cSDimitry Andric auto ContextSize = readNumber<uint32_t>(); 1166349cc55cSDimitry Andric if (std::error_code EC = ContextSize.getError()) 1167349cc55cSDimitry Andric return EC; 1168349cc55cSDimitry Andric for (uint32_t J = 0; J < *ContextSize; ++J) { 1169e8d8bef9SDimitry Andric auto FName(readStringFromTable()); 1170e8d8bef9SDimitry Andric if (std::error_code EC = FName.getError()) 1171e8d8bef9SDimitry Andric return EC; 1172349cc55cSDimitry Andric auto LineOffset = readNumber<uint64_t>(); 1173349cc55cSDimitry Andric if (std::error_code EC = LineOffset.getError()) 1174349cc55cSDimitry Andric return EC; 1175e8d8bef9SDimitry Andric 1176349cc55cSDimitry Andric if (!isOffsetLegal(*LineOffset)) 1177349cc55cSDimitry Andric return std::error_code(); 1178fe6060f1SDimitry Andric 1179349cc55cSDimitry Andric auto Discriminator = readNumber<uint64_t>(); 1180349cc55cSDimitry Andric if (std::error_code EC = Discriminator.getError()) 1181349cc55cSDimitry Andric return EC; 1182349cc55cSDimitry Andric 118306c3fb27SDimitry Andric CSNameTable.back().emplace_back( 1184349cc55cSDimitry Andric FName.get(), LineLocation(LineOffset.get(), Discriminator.get())); 1185349cc55cSDimitry Andric } 1186349cc55cSDimitry Andric } 1187349cc55cSDimitry Andric 1188349cc55cSDimitry Andric return sampleprof_error::success; 1189349cc55cSDimitry Andric } 1190349cc55cSDimitry Andric 1191349cc55cSDimitry Andric std::error_code 11920eae32dcSDimitry Andric SampleProfileReaderExtBinaryBase::readFuncMetadata(bool ProfileHasAttribute, 11930eae32dcSDimitry Andric FunctionSamples *FProfile) { 11940eae32dcSDimitry Andric if (Data < End) { 1195fe6060f1SDimitry Andric if (ProfileIsProbeBased) { 1196e8d8bef9SDimitry Andric auto Checksum = readNumber<uint64_t>(); 1197e8d8bef9SDimitry Andric if (std::error_code EC = Checksum.getError()) 1198e8d8bef9SDimitry Andric return EC; 11990eae32dcSDimitry Andric if (FProfile) 12000eae32dcSDimitry Andric FProfile->setFunctionHash(*Checksum); 1201e8d8bef9SDimitry Andric } 1202d409305fSDimitry Andric 1203fe6060f1SDimitry Andric if (ProfileHasAttribute) { 1204fe6060f1SDimitry Andric auto Attributes = readNumber<uint32_t>(); 1205fe6060f1SDimitry Andric if (std::error_code EC = Attributes.getError()) 1206fe6060f1SDimitry Andric return EC; 12070eae32dcSDimitry Andric if (FProfile) 12080eae32dcSDimitry Andric FProfile->getContext().setAllAttributes(*Attributes); 1209fe6060f1SDimitry Andric } 12100eae32dcSDimitry Andric 121181ad6265SDimitry Andric if (!ProfileIsCS) { 12120eae32dcSDimitry Andric // Read all the attributes for inlined function calls. 12130eae32dcSDimitry Andric auto NumCallsites = readNumber<uint32_t>(); 12140eae32dcSDimitry Andric if (std::error_code EC = NumCallsites.getError()) 12150eae32dcSDimitry Andric return EC; 12160eae32dcSDimitry Andric 12170eae32dcSDimitry Andric for (uint32_t J = 0; J < *NumCallsites; ++J) { 12180eae32dcSDimitry Andric auto LineOffset = readNumber<uint64_t>(); 12190eae32dcSDimitry Andric if (std::error_code EC = LineOffset.getError()) 12200eae32dcSDimitry Andric return EC; 12210eae32dcSDimitry Andric 12220eae32dcSDimitry Andric auto Discriminator = readNumber<uint64_t>(); 12230eae32dcSDimitry Andric if (std::error_code EC = Discriminator.getError()) 12240eae32dcSDimitry Andric return EC; 12250eae32dcSDimitry Andric 12265f757f3fSDimitry Andric auto FContextHash(readSampleContextFromTable()); 12275f757f3fSDimitry Andric if (std::error_code EC = FContextHash.getError()) 12280eae32dcSDimitry Andric return EC; 12290eae32dcSDimitry Andric 12305f757f3fSDimitry Andric auto &[FContext, Hash] = *FContextHash; 12310eae32dcSDimitry Andric FunctionSamples *CalleeProfile = nullptr; 12320eae32dcSDimitry Andric if (FProfile) { 12330eae32dcSDimitry Andric CalleeProfile = const_cast<FunctionSamples *>( 12340eae32dcSDimitry Andric &FProfile->functionSamplesAt(LineLocation( 12350eae32dcSDimitry Andric *LineOffset, 12365f757f3fSDimitry Andric *Discriminator))[FContext.getFunction()]); 12370eae32dcSDimitry Andric } 12380eae32dcSDimitry Andric if (std::error_code EC = 12390eae32dcSDimitry Andric readFuncMetadata(ProfileHasAttribute, CalleeProfile)) 12400eae32dcSDimitry Andric return EC; 12410eae32dcSDimitry Andric } 12420eae32dcSDimitry Andric } 12430eae32dcSDimitry Andric } 12440eae32dcSDimitry Andric 12450eae32dcSDimitry Andric return sampleprof_error::success; 12460eae32dcSDimitry Andric } 12470eae32dcSDimitry Andric 12480eae32dcSDimitry Andric std::error_code 12490eae32dcSDimitry Andric SampleProfileReaderExtBinaryBase::readFuncMetadata(bool ProfileHasAttribute) { 12500eae32dcSDimitry Andric while (Data < End) { 12515f757f3fSDimitry Andric auto FContextHash(readSampleContextFromTable()); 12525f757f3fSDimitry Andric if (std::error_code EC = FContextHash.getError()) 12530eae32dcSDimitry Andric return EC; 12545f757f3fSDimitry Andric auto &[FContext, Hash] = *FContextHash; 12550eae32dcSDimitry Andric FunctionSamples *FProfile = nullptr; 12565f757f3fSDimitry Andric auto It = Profiles.find(FContext); 12570eae32dcSDimitry Andric if (It != Profiles.end()) 12580eae32dcSDimitry Andric FProfile = &It->second; 12590eae32dcSDimitry Andric 12600eae32dcSDimitry Andric if (std::error_code EC = readFuncMetadata(ProfileHasAttribute, FProfile)) 12610eae32dcSDimitry Andric return EC; 1262fe6060f1SDimitry Andric } 1263fe6060f1SDimitry Andric 1264d409305fSDimitry Andric assert(Data == End && "More data is read than expected"); 1265e8d8bef9SDimitry Andric return sampleprof_error::success; 1266e8d8bef9SDimitry Andric } 1267e8d8bef9SDimitry Andric 1268e8d8bef9SDimitry Andric std::error_code 126906c3fb27SDimitry Andric SampleProfileReaderExtBinaryBase::readSecHdrTableEntry(uint64_t Idx) { 12708bcb0991SDimitry Andric SecHdrTableEntry Entry; 12718bcb0991SDimitry Andric auto Type = readUnencodedNumber<uint64_t>(); 12728bcb0991SDimitry Andric if (std::error_code EC = Type.getError()) 12738bcb0991SDimitry Andric return EC; 12748bcb0991SDimitry Andric Entry.Type = static_cast<SecType>(*Type); 12750b57cec5SDimitry Andric 12768bcb0991SDimitry Andric auto Flags = readUnencodedNumber<uint64_t>(); 12778bcb0991SDimitry Andric if (std::error_code EC = Flags.getError()) 12788bcb0991SDimitry Andric return EC; 12798bcb0991SDimitry Andric Entry.Flags = *Flags; 12808bcb0991SDimitry Andric 12818bcb0991SDimitry Andric auto Offset = readUnencodedNumber<uint64_t>(); 12828bcb0991SDimitry Andric if (std::error_code EC = Offset.getError()) 12838bcb0991SDimitry Andric return EC; 12848bcb0991SDimitry Andric Entry.Offset = *Offset; 12858bcb0991SDimitry Andric 12868bcb0991SDimitry Andric auto Size = readUnencodedNumber<uint64_t>(); 12878bcb0991SDimitry Andric if (std::error_code EC = Size.getError()) 12888bcb0991SDimitry Andric return EC; 12898bcb0991SDimitry Andric Entry.Size = *Size; 12908bcb0991SDimitry Andric 1291e8d8bef9SDimitry Andric Entry.LayoutIndex = Idx; 12928bcb0991SDimitry Andric SecHdrTable.push_back(std::move(Entry)); 12938bcb0991SDimitry Andric return sampleprof_error::success; 12948bcb0991SDimitry Andric } 12958bcb0991SDimitry Andric 12968bcb0991SDimitry Andric std::error_code SampleProfileReaderExtBinaryBase::readSecHdrTable() { 12978bcb0991SDimitry Andric auto EntryNum = readUnencodedNumber<uint64_t>(); 12988bcb0991SDimitry Andric if (std::error_code EC = EntryNum.getError()) 12998bcb0991SDimitry Andric return EC; 13008bcb0991SDimitry Andric 1301bdd1243dSDimitry Andric for (uint64_t i = 0; i < (*EntryNum); i++) 1302e8d8bef9SDimitry Andric if (std::error_code EC = readSecHdrTableEntry(i)) 13038bcb0991SDimitry Andric return EC; 13048bcb0991SDimitry Andric 13058bcb0991SDimitry Andric return sampleprof_error::success; 13068bcb0991SDimitry Andric } 13078bcb0991SDimitry Andric 13088bcb0991SDimitry Andric std::error_code SampleProfileReaderExtBinaryBase::readHeader() { 13098bcb0991SDimitry Andric const uint8_t *BufStart = 13108bcb0991SDimitry Andric reinterpret_cast<const uint8_t *>(Buffer->getBufferStart()); 13118bcb0991SDimitry Andric Data = BufStart; 13128bcb0991SDimitry Andric End = BufStart + Buffer->getBufferSize(); 13138bcb0991SDimitry Andric 13148bcb0991SDimitry Andric if (std::error_code EC = readMagicIdent()) 13158bcb0991SDimitry Andric return EC; 13168bcb0991SDimitry Andric 13178bcb0991SDimitry Andric if (std::error_code EC = readSecHdrTable()) 13188bcb0991SDimitry Andric return EC; 13198bcb0991SDimitry Andric 13208bcb0991SDimitry Andric return sampleprof_error::success; 13218bcb0991SDimitry Andric } 13228bcb0991SDimitry Andric 13238bcb0991SDimitry Andric uint64_t SampleProfileReaderExtBinaryBase::getSectionSize(SecType Type) { 1324e8d8bef9SDimitry Andric uint64_t Size = 0; 13258bcb0991SDimitry Andric for (auto &Entry : SecHdrTable) { 13268bcb0991SDimitry Andric if (Entry.Type == Type) 1327e8d8bef9SDimitry Andric Size += Entry.Size; 13288bcb0991SDimitry Andric } 1329e8d8bef9SDimitry Andric return Size; 13308bcb0991SDimitry Andric } 13318bcb0991SDimitry Andric 13328bcb0991SDimitry Andric uint64_t SampleProfileReaderExtBinaryBase::getFileSize() { 13338bcb0991SDimitry Andric // Sections in SecHdrTable is not necessarily in the same order as 13348bcb0991SDimitry Andric // sections in the profile because section like FuncOffsetTable needs 13358bcb0991SDimitry Andric // to be written after section LBRProfile but needs to be read before 13368bcb0991SDimitry Andric // section LBRProfile, so we cannot simply use the last entry in 13378bcb0991SDimitry Andric // SecHdrTable to calculate the file size. 13388bcb0991SDimitry Andric uint64_t FileSize = 0; 13398bcb0991SDimitry Andric for (auto &Entry : SecHdrTable) { 13408bcb0991SDimitry Andric FileSize = std::max(Entry.Offset + Entry.Size, FileSize); 13418bcb0991SDimitry Andric } 13428bcb0991SDimitry Andric return FileSize; 13438bcb0991SDimitry Andric } 13448bcb0991SDimitry Andric 13455ffd83dbSDimitry Andric static std::string getSecFlagsStr(const SecHdrTableEntry &Entry) { 13465ffd83dbSDimitry Andric std::string Flags; 13475ffd83dbSDimitry Andric if (hasSecFlag(Entry, SecCommonFlags::SecFlagCompress)) 13485ffd83dbSDimitry Andric Flags.append("{compressed,"); 13495ffd83dbSDimitry Andric else 13505ffd83dbSDimitry Andric Flags.append("{"); 13515ffd83dbSDimitry Andric 1352e8d8bef9SDimitry Andric if (hasSecFlag(Entry, SecCommonFlags::SecFlagFlat)) 1353e8d8bef9SDimitry Andric Flags.append("flat,"); 1354e8d8bef9SDimitry Andric 13555ffd83dbSDimitry Andric switch (Entry.Type) { 13565ffd83dbSDimitry Andric case SecNameTable: 1357e8d8bef9SDimitry Andric if (hasSecFlag(Entry, SecNameTableFlags::SecFlagFixedLengthMD5)) 1358e8d8bef9SDimitry Andric Flags.append("fixlenmd5,"); 1359e8d8bef9SDimitry Andric else if (hasSecFlag(Entry, SecNameTableFlags::SecFlagMD5Name)) 13605ffd83dbSDimitry Andric Flags.append("md5,"); 1361fe6060f1SDimitry Andric if (hasSecFlag(Entry, SecNameTableFlags::SecFlagUniqSuffix)) 1362fe6060f1SDimitry Andric Flags.append("uniq,"); 13635ffd83dbSDimitry Andric break; 13645ffd83dbSDimitry Andric case SecProfSummary: 13655ffd83dbSDimitry Andric if (hasSecFlag(Entry, SecProfSummaryFlags::SecFlagPartial)) 13665ffd83dbSDimitry Andric Flags.append("partial,"); 1367fe6060f1SDimitry Andric if (hasSecFlag(Entry, SecProfSummaryFlags::SecFlagFullContext)) 1368fe6060f1SDimitry Andric Flags.append("context,"); 136981ad6265SDimitry Andric if (hasSecFlag(Entry, SecProfSummaryFlags::SecFlagIsPreInlined)) 137081ad6265SDimitry Andric Flags.append("preInlined,"); 1371fe6060f1SDimitry Andric if (hasSecFlag(Entry, SecProfSummaryFlags::SecFlagFSDiscriminator)) 1372fe6060f1SDimitry Andric Flags.append("fs-discriminator,"); 13735ffd83dbSDimitry Andric break; 1374349cc55cSDimitry Andric case SecFuncOffsetTable: 1375349cc55cSDimitry Andric if (hasSecFlag(Entry, SecFuncOffsetFlags::SecFlagOrdered)) 1376349cc55cSDimitry Andric Flags.append("ordered,"); 1377349cc55cSDimitry Andric break; 1378349cc55cSDimitry Andric case SecFuncMetadata: 1379349cc55cSDimitry Andric if (hasSecFlag(Entry, SecFuncMetadataFlags::SecFlagIsProbeBased)) 1380349cc55cSDimitry Andric Flags.append("probe,"); 1381349cc55cSDimitry Andric if (hasSecFlag(Entry, SecFuncMetadataFlags::SecFlagHasAttribute)) 1382349cc55cSDimitry Andric Flags.append("attr,"); 1383349cc55cSDimitry Andric break; 13845ffd83dbSDimitry Andric default: 13855ffd83dbSDimitry Andric break; 13865ffd83dbSDimitry Andric } 13875ffd83dbSDimitry Andric char &last = Flags.back(); 13885ffd83dbSDimitry Andric if (last == ',') 13895ffd83dbSDimitry Andric last = '}'; 13905ffd83dbSDimitry Andric else 13915ffd83dbSDimitry Andric Flags.append("}"); 13925ffd83dbSDimitry Andric return Flags; 13935ffd83dbSDimitry Andric } 13945ffd83dbSDimitry Andric 13958bcb0991SDimitry Andric bool SampleProfileReaderExtBinaryBase::dumpSectionInfo(raw_ostream &OS) { 13968bcb0991SDimitry Andric uint64_t TotalSecsSize = 0; 13978bcb0991SDimitry Andric for (auto &Entry : SecHdrTable) { 13988bcb0991SDimitry Andric OS << getSecName(Entry.Type) << " - Offset: " << Entry.Offset 13995ffd83dbSDimitry Andric << ", Size: " << Entry.Size << ", Flags: " << getSecFlagsStr(Entry) 14005ffd83dbSDimitry Andric << "\n"; 14015ffd83dbSDimitry Andric ; 1402e8d8bef9SDimitry Andric TotalSecsSize += Entry.Size; 14038bcb0991SDimitry Andric } 14048bcb0991SDimitry Andric uint64_t HeaderSize = SecHdrTable.front().Offset; 14058bcb0991SDimitry Andric assert(HeaderSize + TotalSecsSize == getFileSize() && 14068bcb0991SDimitry Andric "Size of 'header + sections' doesn't match the total size of profile"); 14078bcb0991SDimitry Andric 14088bcb0991SDimitry Andric OS << "Header Size: " << HeaderSize << "\n"; 14098bcb0991SDimitry Andric OS << "Total Sections Size: " << TotalSecsSize << "\n"; 14108bcb0991SDimitry Andric OS << "File Size: " << getFileSize() << "\n"; 14118bcb0991SDimitry Andric return true; 14128bcb0991SDimitry Andric } 14138bcb0991SDimitry Andric 14148bcb0991SDimitry Andric std::error_code SampleProfileReaderBinary::readMagicIdent() { 14150b57cec5SDimitry Andric // Read and check the magic identifier. 14160b57cec5SDimitry Andric auto Magic = readNumber<uint64_t>(); 14170b57cec5SDimitry Andric if (std::error_code EC = Magic.getError()) 14180b57cec5SDimitry Andric return EC; 14190b57cec5SDimitry Andric else if (std::error_code EC = verifySPMagic(*Magic)) 14200b57cec5SDimitry Andric return EC; 14210b57cec5SDimitry Andric 14220b57cec5SDimitry Andric // Read the version number. 14230b57cec5SDimitry Andric auto Version = readNumber<uint64_t>(); 14240b57cec5SDimitry Andric if (std::error_code EC = Version.getError()) 14250b57cec5SDimitry Andric return EC; 14260b57cec5SDimitry Andric else if (*Version != SPVersion()) 14270b57cec5SDimitry Andric return sampleprof_error::unsupported_version; 14280b57cec5SDimitry Andric 14298bcb0991SDimitry Andric return sampleprof_error::success; 14308bcb0991SDimitry Andric } 14318bcb0991SDimitry Andric 14328bcb0991SDimitry Andric std::error_code SampleProfileReaderBinary::readHeader() { 14338bcb0991SDimitry Andric Data = reinterpret_cast<const uint8_t *>(Buffer->getBufferStart()); 14348bcb0991SDimitry Andric End = Data + Buffer->getBufferSize(); 14358bcb0991SDimitry Andric 14368bcb0991SDimitry Andric if (std::error_code EC = readMagicIdent()) 14378bcb0991SDimitry Andric return EC; 14388bcb0991SDimitry Andric 14390b57cec5SDimitry Andric if (std::error_code EC = readSummary()) 14400b57cec5SDimitry Andric return EC; 14410b57cec5SDimitry Andric 14420b57cec5SDimitry Andric if (std::error_code EC = readNameTable()) 14430b57cec5SDimitry Andric return EC; 14440b57cec5SDimitry Andric return sampleprof_error::success; 14450b57cec5SDimitry Andric } 14460b57cec5SDimitry Andric 14470b57cec5SDimitry Andric std::error_code SampleProfileReaderBinary::readSummaryEntry( 14480b57cec5SDimitry Andric std::vector<ProfileSummaryEntry> &Entries) { 14490b57cec5SDimitry Andric auto Cutoff = readNumber<uint64_t>(); 14500b57cec5SDimitry Andric if (std::error_code EC = Cutoff.getError()) 14510b57cec5SDimitry Andric return EC; 14520b57cec5SDimitry Andric 14530b57cec5SDimitry Andric auto MinBlockCount = readNumber<uint64_t>(); 14540b57cec5SDimitry Andric if (std::error_code EC = MinBlockCount.getError()) 14550b57cec5SDimitry Andric return EC; 14560b57cec5SDimitry Andric 14570b57cec5SDimitry Andric auto NumBlocks = readNumber<uint64_t>(); 14580b57cec5SDimitry Andric if (std::error_code EC = NumBlocks.getError()) 14590b57cec5SDimitry Andric return EC; 14600b57cec5SDimitry Andric 14610b57cec5SDimitry Andric Entries.emplace_back(*Cutoff, *MinBlockCount, *NumBlocks); 14620b57cec5SDimitry Andric return sampleprof_error::success; 14630b57cec5SDimitry Andric } 14640b57cec5SDimitry Andric 14650b57cec5SDimitry Andric std::error_code SampleProfileReaderBinary::readSummary() { 14660b57cec5SDimitry Andric auto TotalCount = readNumber<uint64_t>(); 14670b57cec5SDimitry Andric if (std::error_code EC = TotalCount.getError()) 14680b57cec5SDimitry Andric return EC; 14690b57cec5SDimitry Andric 14700b57cec5SDimitry Andric auto MaxBlockCount = readNumber<uint64_t>(); 14710b57cec5SDimitry Andric if (std::error_code EC = MaxBlockCount.getError()) 14720b57cec5SDimitry Andric return EC; 14730b57cec5SDimitry Andric 14740b57cec5SDimitry Andric auto MaxFunctionCount = readNumber<uint64_t>(); 14750b57cec5SDimitry Andric if (std::error_code EC = MaxFunctionCount.getError()) 14760b57cec5SDimitry Andric return EC; 14770b57cec5SDimitry Andric 14780b57cec5SDimitry Andric auto NumBlocks = readNumber<uint64_t>(); 14790b57cec5SDimitry Andric if (std::error_code EC = NumBlocks.getError()) 14800b57cec5SDimitry Andric return EC; 14810b57cec5SDimitry Andric 14820b57cec5SDimitry Andric auto NumFunctions = readNumber<uint64_t>(); 14830b57cec5SDimitry Andric if (std::error_code EC = NumFunctions.getError()) 14840b57cec5SDimitry Andric return EC; 14850b57cec5SDimitry Andric 14860b57cec5SDimitry Andric auto NumSummaryEntries = readNumber<uint64_t>(); 14870b57cec5SDimitry Andric if (std::error_code EC = NumSummaryEntries.getError()) 14880b57cec5SDimitry Andric return EC; 14890b57cec5SDimitry Andric 14900b57cec5SDimitry Andric std::vector<ProfileSummaryEntry> Entries; 14910b57cec5SDimitry Andric for (unsigned i = 0; i < *NumSummaryEntries; i++) { 14920b57cec5SDimitry Andric std::error_code EC = readSummaryEntry(Entries); 14930b57cec5SDimitry Andric if (EC != sampleprof_error::success) 14940b57cec5SDimitry Andric return EC; 14950b57cec5SDimitry Andric } 14968bcb0991SDimitry Andric Summary = std::make_unique<ProfileSummary>( 14970b57cec5SDimitry Andric ProfileSummary::PSK_Sample, Entries, *TotalCount, *MaxBlockCount, 0, 14980b57cec5SDimitry Andric *MaxFunctionCount, *NumBlocks, *NumFunctions); 14990b57cec5SDimitry Andric 15000b57cec5SDimitry Andric return sampleprof_error::success; 15010b57cec5SDimitry Andric } 15020b57cec5SDimitry Andric 15030b57cec5SDimitry Andric bool SampleProfileReaderRawBinary::hasFormat(const MemoryBuffer &Buffer) { 15040b57cec5SDimitry Andric const uint8_t *Data = 15050b57cec5SDimitry Andric reinterpret_cast<const uint8_t *>(Buffer.getBufferStart()); 15060b57cec5SDimitry Andric uint64_t Magic = decodeULEB128(Data); 15070b57cec5SDimitry Andric return Magic == SPMagic(); 15080b57cec5SDimitry Andric } 15090b57cec5SDimitry Andric 15108bcb0991SDimitry Andric bool SampleProfileReaderExtBinary::hasFormat(const MemoryBuffer &Buffer) { 15118bcb0991SDimitry Andric const uint8_t *Data = 15128bcb0991SDimitry Andric reinterpret_cast<const uint8_t *>(Buffer.getBufferStart()); 15138bcb0991SDimitry Andric uint64_t Magic = decodeULEB128(Data); 15148bcb0991SDimitry Andric return Magic == SPMagic(SPF_Ext_Binary); 15158bcb0991SDimitry Andric } 15168bcb0991SDimitry Andric 15170b57cec5SDimitry Andric std::error_code SampleProfileReaderGCC::skipNextWord() { 15180b57cec5SDimitry Andric uint32_t dummy; 15190b57cec5SDimitry Andric if (!GcovBuffer.readInt(dummy)) 15200b57cec5SDimitry Andric return sampleprof_error::truncated; 15210b57cec5SDimitry Andric return sampleprof_error::success; 15220b57cec5SDimitry Andric } 15230b57cec5SDimitry Andric 15240b57cec5SDimitry Andric template <typename T> ErrorOr<T> SampleProfileReaderGCC::readNumber() { 15250b57cec5SDimitry Andric if (sizeof(T) <= sizeof(uint32_t)) { 15260b57cec5SDimitry Andric uint32_t Val; 15270b57cec5SDimitry Andric if (GcovBuffer.readInt(Val) && Val <= std::numeric_limits<T>::max()) 15280b57cec5SDimitry Andric return static_cast<T>(Val); 15290b57cec5SDimitry Andric } else if (sizeof(T) <= sizeof(uint64_t)) { 15300b57cec5SDimitry Andric uint64_t Val; 15310b57cec5SDimitry Andric if (GcovBuffer.readInt64(Val) && Val <= std::numeric_limits<T>::max()) 15320b57cec5SDimitry Andric return static_cast<T>(Val); 15330b57cec5SDimitry Andric } 15340b57cec5SDimitry Andric 15350b57cec5SDimitry Andric std::error_code EC = sampleprof_error::malformed; 15360b57cec5SDimitry Andric reportError(0, EC.message()); 15370b57cec5SDimitry Andric return EC; 15380b57cec5SDimitry Andric } 15390b57cec5SDimitry Andric 15400b57cec5SDimitry Andric ErrorOr<StringRef> SampleProfileReaderGCC::readString() { 15410b57cec5SDimitry Andric StringRef Str; 15420b57cec5SDimitry Andric if (!GcovBuffer.readString(Str)) 15430b57cec5SDimitry Andric return sampleprof_error::truncated; 15440b57cec5SDimitry Andric return Str; 15450b57cec5SDimitry Andric } 15460b57cec5SDimitry Andric 15470b57cec5SDimitry Andric std::error_code SampleProfileReaderGCC::readHeader() { 15480b57cec5SDimitry Andric // Read the magic identifier. 15490b57cec5SDimitry Andric if (!GcovBuffer.readGCDAFormat()) 15500b57cec5SDimitry Andric return sampleprof_error::unrecognized_format; 15510b57cec5SDimitry Andric 15520b57cec5SDimitry Andric // Read the version number. Note - the GCC reader does not validate this 15530b57cec5SDimitry Andric // version, but the profile creator generates v704. 15540b57cec5SDimitry Andric GCOV::GCOVVersion version; 15550b57cec5SDimitry Andric if (!GcovBuffer.readGCOVVersion(version)) 15560b57cec5SDimitry Andric return sampleprof_error::unrecognized_format; 15570b57cec5SDimitry Andric 15585ffd83dbSDimitry Andric if (version != GCOV::V407) 15590b57cec5SDimitry Andric return sampleprof_error::unsupported_version; 15600b57cec5SDimitry Andric 15610b57cec5SDimitry Andric // Skip the empty integer. 15620b57cec5SDimitry Andric if (std::error_code EC = skipNextWord()) 15630b57cec5SDimitry Andric return EC; 15640b57cec5SDimitry Andric 15650b57cec5SDimitry Andric return sampleprof_error::success; 15660b57cec5SDimitry Andric } 15670b57cec5SDimitry Andric 15680b57cec5SDimitry Andric std::error_code SampleProfileReaderGCC::readSectionTag(uint32_t Expected) { 15690b57cec5SDimitry Andric uint32_t Tag; 15700b57cec5SDimitry Andric if (!GcovBuffer.readInt(Tag)) 15710b57cec5SDimitry Andric return sampleprof_error::truncated; 15720b57cec5SDimitry Andric 15730b57cec5SDimitry Andric if (Tag != Expected) 15740b57cec5SDimitry Andric return sampleprof_error::malformed; 15750b57cec5SDimitry Andric 15760b57cec5SDimitry Andric if (std::error_code EC = skipNextWord()) 15770b57cec5SDimitry Andric return EC; 15780b57cec5SDimitry Andric 15790b57cec5SDimitry Andric return sampleprof_error::success; 15800b57cec5SDimitry Andric } 15810b57cec5SDimitry Andric 15820b57cec5SDimitry Andric std::error_code SampleProfileReaderGCC::readNameTable() { 15830b57cec5SDimitry Andric if (std::error_code EC = readSectionTag(GCOVTagAFDOFileNames)) 15840b57cec5SDimitry Andric return EC; 15850b57cec5SDimitry Andric 15860b57cec5SDimitry Andric uint32_t Size; 15870b57cec5SDimitry Andric if (!GcovBuffer.readInt(Size)) 15880b57cec5SDimitry Andric return sampleprof_error::truncated; 15890b57cec5SDimitry Andric 15900b57cec5SDimitry Andric for (uint32_t I = 0; I < Size; ++I) { 15910b57cec5SDimitry Andric StringRef Str; 15920b57cec5SDimitry Andric if (!GcovBuffer.readString(Str)) 15930b57cec5SDimitry Andric return sampleprof_error::truncated; 15945ffd83dbSDimitry Andric Names.push_back(std::string(Str)); 15950b57cec5SDimitry Andric } 15960b57cec5SDimitry Andric 15970b57cec5SDimitry Andric return sampleprof_error::success; 15980b57cec5SDimitry Andric } 15990b57cec5SDimitry Andric 16000b57cec5SDimitry Andric std::error_code SampleProfileReaderGCC::readFunctionProfiles() { 16010b57cec5SDimitry Andric if (std::error_code EC = readSectionTag(GCOVTagAFDOFunction)) 16020b57cec5SDimitry Andric return EC; 16030b57cec5SDimitry Andric 16040b57cec5SDimitry Andric uint32_t NumFunctions; 16050b57cec5SDimitry Andric if (!GcovBuffer.readInt(NumFunctions)) 16060b57cec5SDimitry Andric return sampleprof_error::truncated; 16070b57cec5SDimitry Andric 16080b57cec5SDimitry Andric InlineCallStack Stack; 16090b57cec5SDimitry Andric for (uint32_t I = 0; I < NumFunctions; ++I) 16100b57cec5SDimitry Andric if (std::error_code EC = readOneFunctionProfile(Stack, true, 0)) 16110b57cec5SDimitry Andric return EC; 16120b57cec5SDimitry Andric 16130b57cec5SDimitry Andric computeSummary(); 16140b57cec5SDimitry Andric return sampleprof_error::success; 16150b57cec5SDimitry Andric } 16160b57cec5SDimitry Andric 16170b57cec5SDimitry Andric std::error_code SampleProfileReaderGCC::readOneFunctionProfile( 16180b57cec5SDimitry Andric const InlineCallStack &InlineStack, bool Update, uint32_t Offset) { 16190b57cec5SDimitry Andric uint64_t HeadCount = 0; 16200b57cec5SDimitry Andric if (InlineStack.size() == 0) 16210b57cec5SDimitry Andric if (!GcovBuffer.readInt64(HeadCount)) 16220b57cec5SDimitry Andric return sampleprof_error::truncated; 16230b57cec5SDimitry Andric 16240b57cec5SDimitry Andric uint32_t NameIdx; 16250b57cec5SDimitry Andric if (!GcovBuffer.readInt(NameIdx)) 16260b57cec5SDimitry Andric return sampleprof_error::truncated; 16270b57cec5SDimitry Andric 16280b57cec5SDimitry Andric StringRef Name(Names[NameIdx]); 16290b57cec5SDimitry Andric 16300b57cec5SDimitry Andric uint32_t NumPosCounts; 16310b57cec5SDimitry Andric if (!GcovBuffer.readInt(NumPosCounts)) 16320b57cec5SDimitry Andric return sampleprof_error::truncated; 16330b57cec5SDimitry Andric 16340b57cec5SDimitry Andric uint32_t NumCallsites; 16350b57cec5SDimitry Andric if (!GcovBuffer.readInt(NumCallsites)) 16360b57cec5SDimitry Andric return sampleprof_error::truncated; 16370b57cec5SDimitry Andric 16380b57cec5SDimitry Andric FunctionSamples *FProfile = nullptr; 16390b57cec5SDimitry Andric if (InlineStack.size() == 0) { 16400b57cec5SDimitry Andric // If this is a top function that we have already processed, do not 16410b57cec5SDimitry Andric // update its profile again. This happens in the presence of 16420b57cec5SDimitry Andric // function aliases. Since these aliases share the same function 16430b57cec5SDimitry Andric // body, there will be identical replicated profiles for the 16440b57cec5SDimitry Andric // original function. In this case, we simply not bother updating 16450b57cec5SDimitry Andric // the profile of the original function. 16465f757f3fSDimitry Andric FProfile = &Profiles[FunctionId(Name)]; 16470b57cec5SDimitry Andric FProfile->addHeadSamples(HeadCount); 16480b57cec5SDimitry Andric if (FProfile->getTotalSamples() > 0) 16490b57cec5SDimitry Andric Update = false; 16500b57cec5SDimitry Andric } else { 16510b57cec5SDimitry Andric // Otherwise, we are reading an inlined instance. The top of the 16520b57cec5SDimitry Andric // inline stack contains the profile of the caller. Insert this 16530b57cec5SDimitry Andric // callee in the caller's CallsiteMap. 16540b57cec5SDimitry Andric FunctionSamples *CallerProfile = InlineStack.front(); 16550b57cec5SDimitry Andric uint32_t LineOffset = Offset >> 16; 16560b57cec5SDimitry Andric uint32_t Discriminator = Offset & 0xffff; 16570b57cec5SDimitry Andric FProfile = &CallerProfile->functionSamplesAt( 16585f757f3fSDimitry Andric LineLocation(LineOffset, Discriminator))[FunctionId(Name)]; 16590b57cec5SDimitry Andric } 16605f757f3fSDimitry Andric FProfile->setFunction(FunctionId(Name)); 16610b57cec5SDimitry Andric 16620b57cec5SDimitry Andric for (uint32_t I = 0; I < NumPosCounts; ++I) { 16630b57cec5SDimitry Andric uint32_t Offset; 16640b57cec5SDimitry Andric if (!GcovBuffer.readInt(Offset)) 16650b57cec5SDimitry Andric return sampleprof_error::truncated; 16660b57cec5SDimitry Andric 16670b57cec5SDimitry Andric uint32_t NumTargets; 16680b57cec5SDimitry Andric if (!GcovBuffer.readInt(NumTargets)) 16690b57cec5SDimitry Andric return sampleprof_error::truncated; 16700b57cec5SDimitry Andric 16710b57cec5SDimitry Andric uint64_t Count; 16720b57cec5SDimitry Andric if (!GcovBuffer.readInt64(Count)) 16730b57cec5SDimitry Andric return sampleprof_error::truncated; 16740b57cec5SDimitry Andric 16750b57cec5SDimitry Andric // The line location is encoded in the offset as: 16760b57cec5SDimitry Andric // high 16 bits: line offset to the start of the function. 16770b57cec5SDimitry Andric // low 16 bits: discriminator. 16780b57cec5SDimitry Andric uint32_t LineOffset = Offset >> 16; 16790b57cec5SDimitry Andric uint32_t Discriminator = Offset & 0xffff; 16800b57cec5SDimitry Andric 16810b57cec5SDimitry Andric InlineCallStack NewStack; 16820b57cec5SDimitry Andric NewStack.push_back(FProfile); 1683e8d8bef9SDimitry Andric llvm::append_range(NewStack, InlineStack); 16840b57cec5SDimitry Andric if (Update) { 16850b57cec5SDimitry Andric // Walk up the inline stack, adding the samples on this line to 16860b57cec5SDimitry Andric // the total sample count of the callers in the chain. 1687bdd1243dSDimitry Andric for (auto *CallerProfile : NewStack) 16880b57cec5SDimitry Andric CallerProfile->addTotalSamples(Count); 16890b57cec5SDimitry Andric 16900b57cec5SDimitry Andric // Update the body samples for the current profile. 16910b57cec5SDimitry Andric FProfile->addBodySamples(LineOffset, Discriminator, Count); 16920b57cec5SDimitry Andric } 16930b57cec5SDimitry Andric 16940b57cec5SDimitry Andric // Process the list of functions called at an indirect call site. 16950b57cec5SDimitry Andric // These are all the targets that a function pointer (or virtual 16960b57cec5SDimitry Andric // function) resolved at runtime. 16970b57cec5SDimitry Andric for (uint32_t J = 0; J < NumTargets; J++) { 16980b57cec5SDimitry Andric uint32_t HistVal; 16990b57cec5SDimitry Andric if (!GcovBuffer.readInt(HistVal)) 17000b57cec5SDimitry Andric return sampleprof_error::truncated; 17010b57cec5SDimitry Andric 17020b57cec5SDimitry Andric if (HistVal != HIST_TYPE_INDIR_CALL_TOPN) 17030b57cec5SDimitry Andric return sampleprof_error::malformed; 17040b57cec5SDimitry Andric 17050b57cec5SDimitry Andric uint64_t TargetIdx; 17060b57cec5SDimitry Andric if (!GcovBuffer.readInt64(TargetIdx)) 17070b57cec5SDimitry Andric return sampleprof_error::truncated; 17080b57cec5SDimitry Andric StringRef TargetName(Names[TargetIdx]); 17090b57cec5SDimitry Andric 17100b57cec5SDimitry Andric uint64_t TargetCount; 17110b57cec5SDimitry Andric if (!GcovBuffer.readInt64(TargetCount)) 17120b57cec5SDimitry Andric return sampleprof_error::truncated; 17130b57cec5SDimitry Andric 17140b57cec5SDimitry Andric if (Update) 17150b57cec5SDimitry Andric FProfile->addCalledTargetSamples(LineOffset, Discriminator, 17165f757f3fSDimitry Andric FunctionId(TargetName), 17175f757f3fSDimitry Andric TargetCount); 17180b57cec5SDimitry Andric } 17190b57cec5SDimitry Andric } 17200b57cec5SDimitry Andric 17210b57cec5SDimitry Andric // Process all the inlined callers into the current function. These 17220b57cec5SDimitry Andric // are all the callsites that were inlined into this function. 17230b57cec5SDimitry Andric for (uint32_t I = 0; I < NumCallsites; I++) { 17240b57cec5SDimitry Andric // The offset is encoded as: 17250b57cec5SDimitry Andric // high 16 bits: line offset to the start of the function. 17260b57cec5SDimitry Andric // low 16 bits: discriminator. 17270b57cec5SDimitry Andric uint32_t Offset; 17280b57cec5SDimitry Andric if (!GcovBuffer.readInt(Offset)) 17290b57cec5SDimitry Andric return sampleprof_error::truncated; 17300b57cec5SDimitry Andric InlineCallStack NewStack; 17310b57cec5SDimitry Andric NewStack.push_back(FProfile); 1732e8d8bef9SDimitry Andric llvm::append_range(NewStack, InlineStack); 17330b57cec5SDimitry Andric if (std::error_code EC = readOneFunctionProfile(NewStack, Update, Offset)) 17340b57cec5SDimitry Andric return EC; 17350b57cec5SDimitry Andric } 17360b57cec5SDimitry Andric 17370b57cec5SDimitry Andric return sampleprof_error::success; 17380b57cec5SDimitry Andric } 17390b57cec5SDimitry Andric 17400b57cec5SDimitry Andric /// Read a GCC AutoFDO profile. 17410b57cec5SDimitry Andric /// 17420b57cec5SDimitry Andric /// This format is generated by the Linux Perf conversion tool at 17430b57cec5SDimitry Andric /// https://github.com/google/autofdo. 17448bcb0991SDimitry Andric std::error_code SampleProfileReaderGCC::readImpl() { 1745fe6060f1SDimitry Andric assert(!ProfileIsFSDisciminator && "Gcc profiles not support FSDisciminator"); 17460b57cec5SDimitry Andric // Read the string table. 17470b57cec5SDimitry Andric if (std::error_code EC = readNameTable()) 17480b57cec5SDimitry Andric return EC; 17490b57cec5SDimitry Andric 17500b57cec5SDimitry Andric // Read the source profile. 17510b57cec5SDimitry Andric if (std::error_code EC = readFunctionProfiles()) 17520b57cec5SDimitry Andric return EC; 17530b57cec5SDimitry Andric 17540b57cec5SDimitry Andric return sampleprof_error::success; 17550b57cec5SDimitry Andric } 17560b57cec5SDimitry Andric 17570b57cec5SDimitry Andric bool SampleProfileReaderGCC::hasFormat(const MemoryBuffer &Buffer) { 17580b57cec5SDimitry Andric StringRef Magic(reinterpret_cast<const char *>(Buffer.getBufferStart())); 17590b57cec5SDimitry Andric return Magic == "adcg*704"; 17600b57cec5SDimitry Andric } 17610b57cec5SDimitry Andric 17628bcb0991SDimitry Andric void SampleProfileReaderItaniumRemapper::applyRemapping(LLVMContext &Ctx) { 17635ffd83dbSDimitry Andric // If the reader uses MD5 to represent string, we can't remap it because 17640b57cec5SDimitry Andric // we don't know what the original function names were. 17655ffd83dbSDimitry Andric if (Reader.useMD5()) { 17660b57cec5SDimitry Andric Ctx.diagnose(DiagnosticInfoSampleProfile( 17678bcb0991SDimitry Andric Reader.getBuffer()->getBufferIdentifier(), 17680b57cec5SDimitry Andric "Profile data remapping cannot be applied to profile data " 176906c3fb27SDimitry Andric "using MD5 names (original mangled names are not available).", 17700b57cec5SDimitry Andric DS_Warning)); 17718bcb0991SDimitry Andric return; 17720b57cec5SDimitry Andric } 17730b57cec5SDimitry Andric 1774e8d8bef9SDimitry Andric // CSSPGO-TODO: Remapper is not yet supported. 1775e8d8bef9SDimitry Andric // We will need to remap the entire context string. 17768bcb0991SDimitry Andric assert(Remappings && "should be initialized while creating remapper"); 1777e8d8bef9SDimitry Andric for (auto &Sample : Reader.getProfiles()) { 17785f757f3fSDimitry Andric DenseSet<FunctionId> NamesInSample; 1779e8d8bef9SDimitry Andric Sample.second.findAllNames(NamesInSample); 17805f757f3fSDimitry Andric for (auto &Name : NamesInSample) { 17815f757f3fSDimitry Andric StringRef NameStr = Name.stringRef(); 17825f757f3fSDimitry Andric if (auto Key = Remappings->insert(NameStr)) 17835f757f3fSDimitry Andric NameMap.insert({Key, NameStr}); 17845f757f3fSDimitry Andric } 1785e8d8bef9SDimitry Andric } 17860b57cec5SDimitry Andric 17878bcb0991SDimitry Andric RemappingApplied = true; 17880b57cec5SDimitry Andric } 17890b57cec5SDimitry Andric 1790bdd1243dSDimitry Andric std::optional<StringRef> 1791e8d8bef9SDimitry Andric SampleProfileReaderItaniumRemapper::lookUpNameInProfile(StringRef Fname) { 17925f757f3fSDimitry Andric if (auto Key = Remappings->lookup(Fname)) { 17935f757f3fSDimitry Andric StringRef Result = NameMap.lookup(Key); 17945f757f3fSDimitry Andric if (!Result.empty()) 17955f757f3fSDimitry Andric return Result; 17965f757f3fSDimitry Andric } 1797bdd1243dSDimitry Andric return std::nullopt; 17980b57cec5SDimitry Andric } 17990b57cec5SDimitry Andric 18000b57cec5SDimitry Andric /// Prepare a memory buffer for the contents of \p Filename. 18010b57cec5SDimitry Andric /// 18020b57cec5SDimitry Andric /// \returns an error code indicating the status of the buffer. 18030b57cec5SDimitry Andric static ErrorOr<std::unique_ptr<MemoryBuffer>> 180406c3fb27SDimitry Andric setupMemoryBuffer(const Twine &Filename, vfs::FileSystem &FS) { 180506c3fb27SDimitry Andric auto BufferOrErr = Filename.str() == "-" ? MemoryBuffer::getSTDIN() 180606c3fb27SDimitry Andric : FS.getBufferForFile(Filename); 18070b57cec5SDimitry Andric if (std::error_code EC = BufferOrErr.getError()) 18080b57cec5SDimitry Andric return EC; 18090b57cec5SDimitry Andric auto Buffer = std::move(BufferOrErr.get()); 18100b57cec5SDimitry Andric 18110b57cec5SDimitry Andric return std::move(Buffer); 18120b57cec5SDimitry Andric } 18130b57cec5SDimitry Andric 18140b57cec5SDimitry Andric /// Create a sample profile reader based on the format of the input file. 18150b57cec5SDimitry Andric /// 18160b57cec5SDimitry Andric /// \param Filename The file to open. 18170b57cec5SDimitry Andric /// 18180b57cec5SDimitry Andric /// \param C The LLVM context to use to emit diagnostics. 18190b57cec5SDimitry Andric /// 1820fe6060f1SDimitry Andric /// \param P The FSDiscriminatorPass. 1821fe6060f1SDimitry Andric /// 18228bcb0991SDimitry Andric /// \param RemapFilename The file used for profile remapping. 18238bcb0991SDimitry Andric /// 18240b57cec5SDimitry Andric /// \returns an error code indicating the status of the created reader. 18250b57cec5SDimitry Andric ErrorOr<std::unique_ptr<SampleProfileReader>> 1826*0fca6ea1SDimitry Andric SampleProfileReader::create(StringRef Filename, LLVMContext &C, 182706c3fb27SDimitry Andric vfs::FileSystem &FS, FSDiscriminatorPass P, 1828*0fca6ea1SDimitry Andric StringRef RemapFilename) { 182906c3fb27SDimitry Andric auto BufferOrError = setupMemoryBuffer(Filename, FS); 18300b57cec5SDimitry Andric if (std::error_code EC = BufferOrError.getError()) 18310b57cec5SDimitry Andric return EC; 183206c3fb27SDimitry Andric return create(BufferOrError.get(), C, FS, P, RemapFilename); 18330b57cec5SDimitry Andric } 18340b57cec5SDimitry Andric 18350b57cec5SDimitry Andric /// Create a sample profile remapper from the given input, to remap the 18360b57cec5SDimitry Andric /// function names in the given profile data. 18370b57cec5SDimitry Andric /// 18380b57cec5SDimitry Andric /// \param Filename The file to open. 18390b57cec5SDimitry Andric /// 18408bcb0991SDimitry Andric /// \param Reader The profile reader the remapper is going to be applied to. 18418bcb0991SDimitry Andric /// 18420b57cec5SDimitry Andric /// \param C The LLVM context to use to emit diagnostics. 18430b57cec5SDimitry Andric /// 18440b57cec5SDimitry Andric /// \returns an error code indicating the status of the created reader. 18458bcb0991SDimitry Andric ErrorOr<std::unique_ptr<SampleProfileReaderItaniumRemapper>> 1846*0fca6ea1SDimitry Andric SampleProfileReaderItaniumRemapper::create(StringRef Filename, 184706c3fb27SDimitry Andric vfs::FileSystem &FS, 18488bcb0991SDimitry Andric SampleProfileReader &Reader, 18498bcb0991SDimitry Andric LLVMContext &C) { 185006c3fb27SDimitry Andric auto BufferOrError = setupMemoryBuffer(Filename, FS); 18510b57cec5SDimitry Andric if (std::error_code EC = BufferOrError.getError()) 18520b57cec5SDimitry Andric return EC; 18538bcb0991SDimitry Andric return create(BufferOrError.get(), Reader, C); 18548bcb0991SDimitry Andric } 18558bcb0991SDimitry Andric 18568bcb0991SDimitry Andric /// Create a sample profile remapper from the given input, to remap the 18578bcb0991SDimitry Andric /// function names in the given profile data. 18588bcb0991SDimitry Andric /// 18598bcb0991SDimitry Andric /// \param B The memory buffer to create the reader from (assumes ownership). 18608bcb0991SDimitry Andric /// 18618bcb0991SDimitry Andric /// \param C The LLVM context to use to emit diagnostics. 18628bcb0991SDimitry Andric /// 18638bcb0991SDimitry Andric /// \param Reader The profile reader the remapper is going to be applied to. 18648bcb0991SDimitry Andric /// 18658bcb0991SDimitry Andric /// \returns an error code indicating the status of the created reader. 18668bcb0991SDimitry Andric ErrorOr<std::unique_ptr<SampleProfileReaderItaniumRemapper>> 18678bcb0991SDimitry Andric SampleProfileReaderItaniumRemapper::create(std::unique_ptr<MemoryBuffer> &B, 18688bcb0991SDimitry Andric SampleProfileReader &Reader, 18698bcb0991SDimitry Andric LLVMContext &C) { 18708bcb0991SDimitry Andric auto Remappings = std::make_unique<SymbolRemappingReader>(); 187181ad6265SDimitry Andric if (Error E = Remappings->read(*B)) { 18728bcb0991SDimitry Andric handleAllErrors( 18738bcb0991SDimitry Andric std::move(E), [&](const SymbolRemappingParseError &ParseError) { 18748bcb0991SDimitry Andric C.diagnose(DiagnosticInfoSampleProfile(B->getBufferIdentifier(), 18758bcb0991SDimitry Andric ParseError.getLineNum(), 18768bcb0991SDimitry Andric ParseError.getMessage())); 18778bcb0991SDimitry Andric }); 18788bcb0991SDimitry Andric return sampleprof_error::malformed; 18798bcb0991SDimitry Andric } 18808bcb0991SDimitry Andric 18818bcb0991SDimitry Andric return std::make_unique<SampleProfileReaderItaniumRemapper>( 18828bcb0991SDimitry Andric std::move(B), std::move(Remappings), Reader); 18830b57cec5SDimitry Andric } 18840b57cec5SDimitry Andric 18850b57cec5SDimitry Andric /// Create a sample profile reader based on the format of the input data. 18860b57cec5SDimitry Andric /// 18870b57cec5SDimitry Andric /// \param B The memory buffer to create the reader from (assumes ownership). 18880b57cec5SDimitry Andric /// 18890b57cec5SDimitry Andric /// \param C The LLVM context to use to emit diagnostics. 18900b57cec5SDimitry Andric /// 1891fe6060f1SDimitry Andric /// \param P The FSDiscriminatorPass. 1892fe6060f1SDimitry Andric /// 18938bcb0991SDimitry Andric /// \param RemapFilename The file used for profile remapping. 18948bcb0991SDimitry Andric /// 18950b57cec5SDimitry Andric /// \returns an error code indicating the status of the created reader. 18960b57cec5SDimitry Andric ErrorOr<std::unique_ptr<SampleProfileReader>> 18978bcb0991SDimitry Andric SampleProfileReader::create(std::unique_ptr<MemoryBuffer> &B, LLVMContext &C, 189806c3fb27SDimitry Andric vfs::FileSystem &FS, FSDiscriminatorPass P, 1899*0fca6ea1SDimitry Andric StringRef RemapFilename) { 19000b57cec5SDimitry Andric std::unique_ptr<SampleProfileReader> Reader; 19010b57cec5SDimitry Andric if (SampleProfileReaderRawBinary::hasFormat(*B)) 19020b57cec5SDimitry Andric Reader.reset(new SampleProfileReaderRawBinary(std::move(B), C)); 19038bcb0991SDimitry Andric else if (SampleProfileReaderExtBinary::hasFormat(*B)) 19048bcb0991SDimitry Andric Reader.reset(new SampleProfileReaderExtBinary(std::move(B), C)); 19050b57cec5SDimitry Andric else if (SampleProfileReaderGCC::hasFormat(*B)) 19060b57cec5SDimitry Andric Reader.reset(new SampleProfileReaderGCC(std::move(B), C)); 19070b57cec5SDimitry Andric else if (SampleProfileReaderText::hasFormat(*B)) 19080b57cec5SDimitry Andric Reader.reset(new SampleProfileReaderText(std::move(B), C)); 19090b57cec5SDimitry Andric else 19100b57cec5SDimitry Andric return sampleprof_error::unrecognized_format; 19110b57cec5SDimitry Andric 19128bcb0991SDimitry Andric if (!RemapFilename.empty()) { 191306c3fb27SDimitry Andric auto ReaderOrErr = SampleProfileReaderItaniumRemapper::create( 191406c3fb27SDimitry Andric RemapFilename, FS, *Reader, C); 19158bcb0991SDimitry Andric if (std::error_code EC = ReaderOrErr.getError()) { 19168bcb0991SDimitry Andric std::string Msg = "Could not create remapper: " + EC.message(); 19178bcb0991SDimitry Andric C.diagnose(DiagnosticInfoSampleProfile(RemapFilename, Msg)); 19180b57cec5SDimitry Andric return EC; 19198bcb0991SDimitry Andric } 19208bcb0991SDimitry Andric Reader->Remapper = std::move(ReaderOrErr.get()); 19218bcb0991SDimitry Andric } 19228bcb0991SDimitry Andric 19238bcb0991SDimitry Andric if (std::error_code EC = Reader->readHeader()) { 19248bcb0991SDimitry Andric return EC; 19258bcb0991SDimitry Andric } 19260b57cec5SDimitry Andric 1927fe6060f1SDimitry Andric Reader->setDiscriminatorMaskedBitFrom(P); 1928fe6060f1SDimitry Andric 19290b57cec5SDimitry Andric return std::move(Reader); 19300b57cec5SDimitry Andric } 19310b57cec5SDimitry Andric 19320b57cec5SDimitry Andric // For text and GCC file formats, we compute the summary after reading the 19330b57cec5SDimitry Andric // profile. Binary format has the profile summary in its header. 19340b57cec5SDimitry Andric void SampleProfileReader::computeSummary() { 19350b57cec5SDimitry Andric SampleProfileSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs); 1936d409305fSDimitry Andric Summary = Builder.computeSummaryForProfiles(Profiles); 19370b57cec5SDimitry Andric } 1938