1*0b57cec5SDimitry Andric //=-- SampleProf.cpp - Sample profiling format support --------------------===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric // 9*0b57cec5SDimitry Andric // This file contains common definitions used in the reading and writing of 10*0b57cec5SDimitry Andric // sample profile data. 11*0b57cec5SDimitry Andric // 12*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 13*0b57cec5SDimitry Andric 14*0b57cec5SDimitry Andric #include "llvm/ProfileData/SampleProf.h" 15*0b57cec5SDimitry Andric #include "llvm/Config/llvm-config.h" 16*0b57cec5SDimitry Andric #include "llvm/IR/DebugInfoMetadata.h" 17e8d8bef9SDimitry Andric #include "llvm/IR/PseudoProbe.h" 18e8d8bef9SDimitry Andric #include "llvm/ProfileData/SampleProfReader.h" 19*0b57cec5SDimitry Andric #include "llvm/Support/Compiler.h" 20*0b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 218bcb0991SDimitry Andric #include "llvm/Support/Error.h" 22*0b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h" 238bcb0991SDimitry Andric #include "llvm/Support/LEB128.h" 24*0b57cec5SDimitry Andric #include "llvm/Support/ManagedStatic.h" 25*0b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 26*0b57cec5SDimitry Andric #include <string> 27*0b57cec5SDimitry Andric #include <system_error> 28*0b57cec5SDimitry Andric 29*0b57cec5SDimitry Andric using namespace llvm; 30*0b57cec5SDimitry Andric using namespace sampleprof; 31*0b57cec5SDimitry Andric 32*0b57cec5SDimitry Andric namespace llvm { 33*0b57cec5SDimitry Andric namespace sampleprof { 34*0b57cec5SDimitry Andric SampleProfileFormat FunctionSamples::Format; 35e8d8bef9SDimitry Andric bool FunctionSamples::ProfileIsProbeBased = false; 36e8d8bef9SDimitry Andric bool FunctionSamples::ProfileIsCS = false; 375ffd83dbSDimitry Andric bool FunctionSamples::UseMD5; 38*0b57cec5SDimitry Andric } // namespace sampleprof 39*0b57cec5SDimitry Andric } // namespace llvm 40*0b57cec5SDimitry Andric 41*0b57cec5SDimitry Andric namespace { 42*0b57cec5SDimitry Andric 43*0b57cec5SDimitry Andric // FIXME: This class is only here to support the transition to llvm::Error. It 44*0b57cec5SDimitry Andric // will be removed once this transition is complete. Clients should prefer to 45*0b57cec5SDimitry Andric // deal with the Error value directly, rather than converting to error_code. 46*0b57cec5SDimitry Andric class SampleProfErrorCategoryType : public std::error_category { 47*0b57cec5SDimitry Andric const char *name() const noexcept override { return "llvm.sampleprof"; } 48*0b57cec5SDimitry Andric 49*0b57cec5SDimitry Andric std::string message(int IE) const override { 50*0b57cec5SDimitry Andric sampleprof_error E = static_cast<sampleprof_error>(IE); 51*0b57cec5SDimitry Andric switch (E) { 52*0b57cec5SDimitry Andric case sampleprof_error::success: 53*0b57cec5SDimitry Andric return "Success"; 54*0b57cec5SDimitry Andric case sampleprof_error::bad_magic: 55*0b57cec5SDimitry Andric return "Invalid sample profile data (bad magic)"; 56*0b57cec5SDimitry Andric case sampleprof_error::unsupported_version: 57*0b57cec5SDimitry Andric return "Unsupported sample profile format version"; 58*0b57cec5SDimitry Andric case sampleprof_error::too_large: 59*0b57cec5SDimitry Andric return "Too much profile data"; 60*0b57cec5SDimitry Andric case sampleprof_error::truncated: 61*0b57cec5SDimitry Andric return "Truncated profile data"; 62*0b57cec5SDimitry Andric case sampleprof_error::malformed: 63*0b57cec5SDimitry Andric return "Malformed sample profile data"; 64*0b57cec5SDimitry Andric case sampleprof_error::unrecognized_format: 65*0b57cec5SDimitry Andric return "Unrecognized sample profile encoding format"; 66*0b57cec5SDimitry Andric case sampleprof_error::unsupported_writing_format: 67*0b57cec5SDimitry Andric return "Profile encoding format unsupported for writing operations"; 68*0b57cec5SDimitry Andric case sampleprof_error::truncated_name_table: 69*0b57cec5SDimitry Andric return "Truncated function name table"; 70*0b57cec5SDimitry Andric case sampleprof_error::not_implemented: 71*0b57cec5SDimitry Andric return "Unimplemented feature"; 72*0b57cec5SDimitry Andric case sampleprof_error::counter_overflow: 73*0b57cec5SDimitry Andric return "Counter overflow"; 74*0b57cec5SDimitry Andric case sampleprof_error::ostream_seek_unsupported: 75*0b57cec5SDimitry Andric return "Ostream does not support seek"; 768bcb0991SDimitry Andric case sampleprof_error::compress_failed: 778bcb0991SDimitry Andric return "Compress failure"; 788bcb0991SDimitry Andric case sampleprof_error::uncompress_failed: 798bcb0991SDimitry Andric return "Uncompress failure"; 808bcb0991SDimitry Andric case sampleprof_error::zlib_unavailable: 818bcb0991SDimitry Andric return "Zlib is unavailable"; 82e8d8bef9SDimitry Andric case sampleprof_error::hash_mismatch: 83e8d8bef9SDimitry Andric return "Function hash mismatch"; 84*0b57cec5SDimitry Andric } 85*0b57cec5SDimitry Andric llvm_unreachable("A value of sampleprof_error has no message."); 86*0b57cec5SDimitry Andric } 87*0b57cec5SDimitry Andric }; 88*0b57cec5SDimitry Andric 89*0b57cec5SDimitry Andric } // end anonymous namespace 90*0b57cec5SDimitry Andric 91*0b57cec5SDimitry Andric static ManagedStatic<SampleProfErrorCategoryType> ErrorCategory; 92*0b57cec5SDimitry Andric 93*0b57cec5SDimitry Andric const std::error_category &llvm::sampleprof_category() { 94*0b57cec5SDimitry Andric return *ErrorCategory; 95*0b57cec5SDimitry Andric } 96*0b57cec5SDimitry Andric 97*0b57cec5SDimitry Andric void LineLocation::print(raw_ostream &OS) const { 98*0b57cec5SDimitry Andric OS << LineOffset; 99*0b57cec5SDimitry Andric if (Discriminator > 0) 100*0b57cec5SDimitry Andric OS << "." << Discriminator; 101*0b57cec5SDimitry Andric } 102*0b57cec5SDimitry Andric 103*0b57cec5SDimitry Andric raw_ostream &llvm::sampleprof::operator<<(raw_ostream &OS, 104*0b57cec5SDimitry Andric const LineLocation &Loc) { 105*0b57cec5SDimitry Andric Loc.print(OS); 106*0b57cec5SDimitry Andric return OS; 107*0b57cec5SDimitry Andric } 108*0b57cec5SDimitry Andric 109*0b57cec5SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 110*0b57cec5SDimitry Andric LLVM_DUMP_METHOD void LineLocation::dump() const { print(dbgs()); } 111*0b57cec5SDimitry Andric #endif 112*0b57cec5SDimitry Andric 113*0b57cec5SDimitry Andric /// Print the sample record to the stream \p OS indented by \p Indent. 114*0b57cec5SDimitry Andric void SampleRecord::print(raw_ostream &OS, unsigned Indent) const { 115*0b57cec5SDimitry Andric OS << NumSamples; 116*0b57cec5SDimitry Andric if (hasCalls()) { 117*0b57cec5SDimitry Andric OS << ", calls:"; 1188bcb0991SDimitry Andric for (const auto &I : getSortedCallTargets()) 1198bcb0991SDimitry Andric OS << " " << I.first << ":" << I.second; 120*0b57cec5SDimitry Andric } 121*0b57cec5SDimitry Andric OS << "\n"; 122*0b57cec5SDimitry Andric } 123*0b57cec5SDimitry Andric 124*0b57cec5SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 125*0b57cec5SDimitry Andric LLVM_DUMP_METHOD void SampleRecord::dump() const { print(dbgs(), 0); } 126*0b57cec5SDimitry Andric #endif 127*0b57cec5SDimitry Andric 128*0b57cec5SDimitry Andric raw_ostream &llvm::sampleprof::operator<<(raw_ostream &OS, 129*0b57cec5SDimitry Andric const SampleRecord &Sample) { 130*0b57cec5SDimitry Andric Sample.print(OS, 0); 131*0b57cec5SDimitry Andric return OS; 132*0b57cec5SDimitry Andric } 133*0b57cec5SDimitry Andric 134*0b57cec5SDimitry Andric /// Print the samples collected for a function on stream \p OS. 135*0b57cec5SDimitry Andric void FunctionSamples::print(raw_ostream &OS, unsigned Indent) const { 136e8d8bef9SDimitry Andric if (getFunctionHash()) 137e8d8bef9SDimitry Andric OS << "CFG checksum " << getFunctionHash() << "\n"; 138e8d8bef9SDimitry Andric 139*0b57cec5SDimitry Andric OS << TotalSamples << ", " << TotalHeadSamples << ", " << BodySamples.size() 140*0b57cec5SDimitry Andric << " sampled lines\n"; 141*0b57cec5SDimitry Andric 142*0b57cec5SDimitry Andric OS.indent(Indent); 143*0b57cec5SDimitry Andric if (!BodySamples.empty()) { 144*0b57cec5SDimitry Andric OS << "Samples collected in the function's body {\n"; 145*0b57cec5SDimitry Andric SampleSorter<LineLocation, SampleRecord> SortedBodySamples(BodySamples); 146*0b57cec5SDimitry Andric for (const auto &SI : SortedBodySamples.get()) { 147*0b57cec5SDimitry Andric OS.indent(Indent + 2); 148*0b57cec5SDimitry Andric OS << SI->first << ": " << SI->second; 149*0b57cec5SDimitry Andric } 150*0b57cec5SDimitry Andric OS.indent(Indent); 151*0b57cec5SDimitry Andric OS << "}\n"; 152*0b57cec5SDimitry Andric } else { 153*0b57cec5SDimitry Andric OS << "No samples collected in the function's body\n"; 154*0b57cec5SDimitry Andric } 155*0b57cec5SDimitry Andric 156*0b57cec5SDimitry Andric OS.indent(Indent); 157*0b57cec5SDimitry Andric if (!CallsiteSamples.empty()) { 158*0b57cec5SDimitry Andric OS << "Samples collected in inlined callsites {\n"; 159*0b57cec5SDimitry Andric SampleSorter<LineLocation, FunctionSamplesMap> SortedCallsiteSamples( 160*0b57cec5SDimitry Andric CallsiteSamples); 161*0b57cec5SDimitry Andric for (const auto &CS : SortedCallsiteSamples.get()) { 162*0b57cec5SDimitry Andric for (const auto &FS : CS->second) { 163*0b57cec5SDimitry Andric OS.indent(Indent + 2); 164*0b57cec5SDimitry Andric OS << CS->first << ": inlined callee: " << FS.second.getName() << ": "; 165*0b57cec5SDimitry Andric FS.second.print(OS, Indent + 4); 166*0b57cec5SDimitry Andric } 167*0b57cec5SDimitry Andric } 1688bcb0991SDimitry Andric OS.indent(Indent); 169*0b57cec5SDimitry Andric OS << "}\n"; 170*0b57cec5SDimitry Andric } else { 171*0b57cec5SDimitry Andric OS << "No inlined callsites in this function\n"; 172*0b57cec5SDimitry Andric } 173*0b57cec5SDimitry Andric } 174*0b57cec5SDimitry Andric 175*0b57cec5SDimitry Andric raw_ostream &llvm::sampleprof::operator<<(raw_ostream &OS, 176*0b57cec5SDimitry Andric const FunctionSamples &FS) { 177*0b57cec5SDimitry Andric FS.print(OS); 178*0b57cec5SDimitry Andric return OS; 179*0b57cec5SDimitry Andric } 180*0b57cec5SDimitry Andric 181*0b57cec5SDimitry Andric unsigned FunctionSamples::getOffset(const DILocation *DIL) { 182*0b57cec5SDimitry Andric return (DIL->getLine() - DIL->getScope()->getSubprogram()->getLine()) & 183*0b57cec5SDimitry Andric 0xffff; 184*0b57cec5SDimitry Andric } 185*0b57cec5SDimitry Andric 186e8d8bef9SDimitry Andric LineLocation FunctionSamples::getCallSiteIdentifier(const DILocation *DIL) { 187e8d8bef9SDimitry Andric if (FunctionSamples::ProfileIsProbeBased) 188e8d8bef9SDimitry Andric // In a pseudo-probe based profile, a callsite is simply represented by the 189e8d8bef9SDimitry Andric // ID of the probe associated with the call instruction. The probe ID is 190e8d8bef9SDimitry Andric // encoded in the Discriminator field of the call instruction's debug 191e8d8bef9SDimitry Andric // metadata. 192e8d8bef9SDimitry Andric return LineLocation(PseudoProbeDwarfDiscriminator::extractProbeIndex( 193e8d8bef9SDimitry Andric DIL->getDiscriminator()), 194e8d8bef9SDimitry Andric 0); 195e8d8bef9SDimitry Andric else 196e8d8bef9SDimitry Andric return LineLocation(FunctionSamples::getOffset(DIL), 197e8d8bef9SDimitry Andric DIL->getBaseDiscriminator()); 198e8d8bef9SDimitry Andric } 199e8d8bef9SDimitry Andric 200e8d8bef9SDimitry Andric const FunctionSamples *FunctionSamples::findFunctionSamples( 201e8d8bef9SDimitry Andric const DILocation *DIL, SampleProfileReaderItaniumRemapper *Remapper) const { 202*0b57cec5SDimitry Andric assert(DIL); 203*0b57cec5SDimitry Andric SmallVector<std::pair<LineLocation, StringRef>, 10> S; 204*0b57cec5SDimitry Andric 205*0b57cec5SDimitry Andric const DILocation *PrevDIL = DIL; 206*0b57cec5SDimitry Andric for (DIL = DIL->getInlinedAt(); DIL; DIL = DIL->getInlinedAt()) { 207*0b57cec5SDimitry Andric S.push_back(std::make_pair( 208*0b57cec5SDimitry Andric LineLocation(getOffset(DIL), DIL->getBaseDiscriminator()), 209*0b57cec5SDimitry Andric PrevDIL->getScope()->getSubprogram()->getLinkageName())); 210*0b57cec5SDimitry Andric PrevDIL = DIL; 211*0b57cec5SDimitry Andric } 212*0b57cec5SDimitry Andric if (S.size() == 0) 213*0b57cec5SDimitry Andric return this; 214*0b57cec5SDimitry Andric const FunctionSamples *FS = this; 215*0b57cec5SDimitry Andric for (int i = S.size() - 1; i >= 0 && FS != nullptr; i--) { 216e8d8bef9SDimitry Andric FS = FS->findFunctionSamplesAt(S[i].first, S[i].second, Remapper); 217*0b57cec5SDimitry Andric } 218*0b57cec5SDimitry Andric return FS; 219*0b57cec5SDimitry Andric } 220*0b57cec5SDimitry Andric 221e8d8bef9SDimitry Andric void FunctionSamples::findAllNames(DenseSet<StringRef> &NameSet) const { 222e8d8bef9SDimitry Andric NameSet.insert(Name); 223e8d8bef9SDimitry Andric for (const auto &BS : BodySamples) 224e8d8bef9SDimitry Andric for (const auto &TS : BS.second.getCallTargets()) 225e8d8bef9SDimitry Andric NameSet.insert(TS.getKey()); 226e8d8bef9SDimitry Andric 227e8d8bef9SDimitry Andric for (const auto &CS : CallsiteSamples) { 228e8d8bef9SDimitry Andric for (const auto &NameFS : CS.second) { 229e8d8bef9SDimitry Andric NameSet.insert(NameFS.first); 230e8d8bef9SDimitry Andric NameFS.second.findAllNames(NameSet); 231e8d8bef9SDimitry Andric } 232e8d8bef9SDimitry Andric } 233e8d8bef9SDimitry Andric } 234e8d8bef9SDimitry Andric 235e8d8bef9SDimitry Andric const FunctionSamples *FunctionSamples::findFunctionSamplesAt( 236e8d8bef9SDimitry Andric const LineLocation &Loc, StringRef CalleeName, 237e8d8bef9SDimitry Andric SampleProfileReaderItaniumRemapper *Remapper) const { 238e8d8bef9SDimitry Andric std::string CalleeGUID; 239e8d8bef9SDimitry Andric CalleeName = getRepInFormat(CalleeName, UseMD5, CalleeGUID); 240e8d8bef9SDimitry Andric 241e8d8bef9SDimitry Andric auto iter = CallsiteSamples.find(Loc); 242e8d8bef9SDimitry Andric if (iter == CallsiteSamples.end()) 243e8d8bef9SDimitry Andric return nullptr; 244e8d8bef9SDimitry Andric auto FS = iter->second.find(CalleeName); 245e8d8bef9SDimitry Andric if (FS != iter->second.end()) 246e8d8bef9SDimitry Andric return &FS->second; 247e8d8bef9SDimitry Andric if (Remapper) { 248e8d8bef9SDimitry Andric if (auto NameInProfile = Remapper->lookUpNameInProfile(CalleeName)) { 249e8d8bef9SDimitry Andric auto FS = iter->second.find(*NameInProfile); 250e8d8bef9SDimitry Andric if (FS != iter->second.end()) 251e8d8bef9SDimitry Andric return &FS->second; 252e8d8bef9SDimitry Andric } 253e8d8bef9SDimitry Andric } 254e8d8bef9SDimitry Andric // If we cannot find exact match of the callee name, return the FS with 255e8d8bef9SDimitry Andric // the max total count. Only do this when CalleeName is not provided, 256e8d8bef9SDimitry Andric // i.e., only for indirect calls. 257e8d8bef9SDimitry Andric if (!CalleeName.empty()) 258e8d8bef9SDimitry Andric return nullptr; 259e8d8bef9SDimitry Andric uint64_t MaxTotalSamples = 0; 260e8d8bef9SDimitry Andric const FunctionSamples *R = nullptr; 261e8d8bef9SDimitry Andric for (const auto &NameFS : iter->second) 262e8d8bef9SDimitry Andric if (NameFS.second.getTotalSamples() >= MaxTotalSamples) { 263e8d8bef9SDimitry Andric MaxTotalSamples = NameFS.second.getTotalSamples(); 264e8d8bef9SDimitry Andric R = &NameFS.second; 265e8d8bef9SDimitry Andric } 266e8d8bef9SDimitry Andric return R; 267e8d8bef9SDimitry Andric } 268e8d8bef9SDimitry Andric 269*0b57cec5SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 270*0b57cec5SDimitry Andric LLVM_DUMP_METHOD void FunctionSamples::dump() const { print(dbgs(), 0); } 271*0b57cec5SDimitry Andric #endif 2728bcb0991SDimitry Andric 2738bcb0991SDimitry Andric std::error_code ProfileSymbolList::read(const uint8_t *Data, 2748bcb0991SDimitry Andric uint64_t ListSize) { 2758bcb0991SDimitry Andric const char *ListStart = reinterpret_cast<const char *>(Data); 2768bcb0991SDimitry Andric uint64_t Size = 0; 2778bcb0991SDimitry Andric while (Size < ListSize) { 2788bcb0991SDimitry Andric StringRef Str(ListStart + Size); 2798bcb0991SDimitry Andric add(Str); 2808bcb0991SDimitry Andric Size += Str.size() + 1; 2818bcb0991SDimitry Andric } 2828bcb0991SDimitry Andric if (Size != ListSize) 2838bcb0991SDimitry Andric return sampleprof_error::malformed; 2848bcb0991SDimitry Andric return sampleprof_error::success; 2858bcb0991SDimitry Andric } 2868bcb0991SDimitry Andric 2878bcb0991SDimitry Andric std::error_code ProfileSymbolList::write(raw_ostream &OS) { 2888bcb0991SDimitry Andric // Sort the symbols before output. If doing compression. 2898bcb0991SDimitry Andric // It will make the compression much more effective. 290e8d8bef9SDimitry Andric std::vector<StringRef> SortedList(Syms.begin(), Syms.end()); 2918bcb0991SDimitry Andric llvm::sort(SortedList); 2928bcb0991SDimitry Andric 2938bcb0991SDimitry Andric std::string OutputString; 2948bcb0991SDimitry Andric for (auto &Sym : SortedList) { 2958bcb0991SDimitry Andric OutputString.append(Sym.str()); 2968bcb0991SDimitry Andric OutputString.append(1, '\0'); 2978bcb0991SDimitry Andric } 2988bcb0991SDimitry Andric 2998bcb0991SDimitry Andric OS << OutputString; 3008bcb0991SDimitry Andric return sampleprof_error::success; 3018bcb0991SDimitry Andric } 3028bcb0991SDimitry Andric 3038bcb0991SDimitry Andric void ProfileSymbolList::dump(raw_ostream &OS) const { 3048bcb0991SDimitry Andric OS << "======== Dump profile symbol list ========\n"; 305e8d8bef9SDimitry Andric std::vector<StringRef> SortedList(Syms.begin(), Syms.end()); 3068bcb0991SDimitry Andric llvm::sort(SortedList); 3078bcb0991SDimitry Andric 3088bcb0991SDimitry Andric for (auto &Sym : SortedList) 3098bcb0991SDimitry Andric OS << Sym << "\n"; 3108bcb0991SDimitry Andric } 311