1 //=-- SampleProf.cpp - Sample profiling format support --------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file contains common definitions used in the reading and writing of 10 // sample profile data. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "llvm/ProfileData/SampleProf.h" 15 #include "llvm/Config/llvm-config.h" 16 #include "llvm/IR/DebugInfoMetadata.h" 17 #include "llvm/Support/Compiler.h" 18 #include "llvm/Support/Debug.h" 19 #include "llvm/Support/ErrorHandling.h" 20 #include "llvm/Support/ManagedStatic.h" 21 #include "llvm/Support/raw_ostream.h" 22 #include <string> 23 #include <system_error> 24 25 using namespace llvm; 26 using namespace sampleprof; 27 28 namespace llvm { 29 namespace sampleprof { 30 SampleProfileFormat FunctionSamples::Format; 31 DenseMap<uint64_t, StringRef> FunctionSamples::GUIDToFuncNameMap; 32 Module *FunctionSamples::CurrentModule; 33 } // namespace sampleprof 34 } // namespace llvm 35 36 namespace { 37 38 // FIXME: This class is only here to support the transition to llvm::Error. It 39 // will be removed once this transition is complete. Clients should prefer to 40 // deal with the Error value directly, rather than converting to error_code. 41 class SampleProfErrorCategoryType : public std::error_category { 42 const char *name() const noexcept override { return "llvm.sampleprof"; } 43 44 std::string message(int IE) const override { 45 sampleprof_error E = static_cast<sampleprof_error>(IE); 46 switch (E) { 47 case sampleprof_error::success: 48 return "Success"; 49 case sampleprof_error::bad_magic: 50 return "Invalid sample profile data (bad magic)"; 51 case sampleprof_error::unsupported_version: 52 return "Unsupported sample profile format version"; 53 case sampleprof_error::too_large: 54 return "Too much profile data"; 55 case sampleprof_error::truncated: 56 return "Truncated profile data"; 57 case sampleprof_error::malformed: 58 return "Malformed sample profile data"; 59 case sampleprof_error::unrecognized_format: 60 return "Unrecognized sample profile encoding format"; 61 case sampleprof_error::unsupported_writing_format: 62 return "Profile encoding format unsupported for writing operations"; 63 case sampleprof_error::truncated_name_table: 64 return "Truncated function name table"; 65 case sampleprof_error::not_implemented: 66 return "Unimplemented feature"; 67 case sampleprof_error::counter_overflow: 68 return "Counter overflow"; 69 case sampleprof_error::ostream_seek_unsupported: 70 return "Ostream does not support seek"; 71 } 72 llvm_unreachable("A value of sampleprof_error has no message."); 73 } 74 }; 75 76 } // end anonymous namespace 77 78 static ManagedStatic<SampleProfErrorCategoryType> ErrorCategory; 79 80 const std::error_category &llvm::sampleprof_category() { 81 return *ErrorCategory; 82 } 83 84 void LineLocation::print(raw_ostream &OS) const { 85 OS << LineOffset; 86 if (Discriminator > 0) 87 OS << "." << Discriminator; 88 } 89 90 raw_ostream &llvm::sampleprof::operator<<(raw_ostream &OS, 91 const LineLocation &Loc) { 92 Loc.print(OS); 93 return OS; 94 } 95 96 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 97 LLVM_DUMP_METHOD void LineLocation::dump() const { print(dbgs()); } 98 #endif 99 100 /// Print the sample record to the stream \p OS indented by \p Indent. 101 void SampleRecord::print(raw_ostream &OS, unsigned Indent) const { 102 OS << NumSamples; 103 if (hasCalls()) { 104 OS << ", calls:"; 105 for (const auto &I : getCallTargets()) 106 OS << " " << I.first() << ":" << I.second; 107 } 108 OS << "\n"; 109 } 110 111 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 112 LLVM_DUMP_METHOD void SampleRecord::dump() const { print(dbgs(), 0); } 113 #endif 114 115 raw_ostream &llvm::sampleprof::operator<<(raw_ostream &OS, 116 const SampleRecord &Sample) { 117 Sample.print(OS, 0); 118 return OS; 119 } 120 121 /// Print the samples collected for a function on stream \p OS. 122 void FunctionSamples::print(raw_ostream &OS, unsigned Indent) const { 123 OS << TotalSamples << ", " << TotalHeadSamples << ", " << BodySamples.size() 124 << " sampled lines\n"; 125 126 OS.indent(Indent); 127 if (!BodySamples.empty()) { 128 OS << "Samples collected in the function's body {\n"; 129 SampleSorter<LineLocation, SampleRecord> SortedBodySamples(BodySamples); 130 for (const auto &SI : SortedBodySamples.get()) { 131 OS.indent(Indent + 2); 132 OS << SI->first << ": " << SI->second; 133 } 134 OS.indent(Indent); 135 OS << "}\n"; 136 } else { 137 OS << "No samples collected in the function's body\n"; 138 } 139 140 OS.indent(Indent); 141 if (!CallsiteSamples.empty()) { 142 OS << "Samples collected in inlined callsites {\n"; 143 SampleSorter<LineLocation, FunctionSamplesMap> SortedCallsiteSamples( 144 CallsiteSamples); 145 for (const auto &CS : SortedCallsiteSamples.get()) { 146 for (const auto &FS : CS->second) { 147 OS.indent(Indent + 2); 148 OS << CS->first << ": inlined callee: " << FS.second.getName() << ": "; 149 FS.second.print(OS, Indent + 4); 150 } 151 } 152 OS << "}\n"; 153 } else { 154 OS << "No inlined callsites in this function\n"; 155 } 156 } 157 158 raw_ostream &llvm::sampleprof::operator<<(raw_ostream &OS, 159 const FunctionSamples &FS) { 160 FS.print(OS); 161 return OS; 162 } 163 164 unsigned FunctionSamples::getOffset(const DILocation *DIL) { 165 return (DIL->getLine() - DIL->getScope()->getSubprogram()->getLine()) & 166 0xffff; 167 } 168 169 const FunctionSamples * 170 FunctionSamples::findFunctionSamples(const DILocation *DIL) const { 171 assert(DIL); 172 SmallVector<std::pair<LineLocation, StringRef>, 10> S; 173 174 const DILocation *PrevDIL = DIL; 175 for (DIL = DIL->getInlinedAt(); DIL; DIL = DIL->getInlinedAt()) { 176 S.push_back(std::make_pair( 177 LineLocation(getOffset(DIL), DIL->getBaseDiscriminator()), 178 PrevDIL->getScope()->getSubprogram()->getLinkageName())); 179 PrevDIL = DIL; 180 } 181 if (S.size() == 0) 182 return this; 183 const FunctionSamples *FS = this; 184 for (int i = S.size() - 1; i >= 0 && FS != nullptr; i--) { 185 FS = FS->findFunctionSamplesAt(S[i].first, S[i].second); 186 } 187 return FS; 188 } 189 190 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 191 LLVM_DUMP_METHOD void FunctionSamples::dump() const { print(dbgs(), 0); } 192 #endif 193