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