1 //===- SampleProfWriter.cpp - Write LLVM sample profile data --------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file implements the class that writes LLVM sample profiles. It 11 // supports two file formats: text and binary. The textual representation 12 // is useful for debugging and testing purposes. The binary representation 13 // is more compact, resulting in smaller file sizes. However, they can 14 // both be used interchangeably. 15 // 16 // See lib/ProfileData/SampleProfReader.cpp for documentation on each of the 17 // supported formats. 18 // 19 //===----------------------------------------------------------------------===// 20 21 #include "llvm/ProfileData/SampleProfWriter.h" 22 #include "llvm/Support/Debug.h" 23 #include "llvm/Support/ErrorOr.h" 24 #include "llvm/Support/LEB128.h" 25 #include "llvm/Support/LineIterator.h" 26 #include "llvm/Support/MemoryBuffer.h" 27 #include "llvm/Support/Regex.h" 28 29 using namespace llvm::sampleprof; 30 using namespace llvm; 31 32 /// \brief Write samples to a text file. 33 std::error_code SampleProfileWriterText::write(StringRef FName, 34 const FunctionSamples &S) { 35 OS << FName << ":" << S.getTotalSamples(); 36 if (Indent == 0) 37 OS << ":" << S.getHeadSamples(); 38 OS << "\n"; 39 40 for (const auto &I : S.getBodySamples()) { 41 LineLocation Loc = I.first; 42 const SampleRecord &Sample = I.second; 43 OS.indent(Indent + 1); 44 if (Loc.Discriminator == 0) 45 OS << Loc.LineOffset << ": "; 46 else 47 OS << Loc.LineOffset << "." << Loc.Discriminator << ": "; 48 49 OS << Sample.getSamples(); 50 51 for (const auto &J : Sample.getCallTargets()) 52 OS << " " << J.first() << ":" << J.second; 53 OS << "\n"; 54 } 55 56 Indent += 1; 57 for (const auto &I : S.getCallsiteSamples()) { 58 CallsiteLocation Loc = I.first; 59 const FunctionSamples &CalleeSamples = I.second; 60 OS.indent(Indent); 61 if (Loc.Discriminator == 0) 62 OS << Loc.LineOffset << ": "; 63 else 64 OS << Loc.LineOffset << "." << Loc.Discriminator << ": "; 65 if (std::error_code EC = write(Loc.CalleeName, CalleeSamples)) 66 return EC; 67 } 68 Indent -= 1; 69 70 return sampleprof_error::success; 71 } 72 73 std::error_code SampleProfileWriterBinary::writeNameIdx(StringRef FName) { 74 const auto &ret = NameTable.find(FName); 75 if (ret == NameTable.end()) 76 return sampleprof_error::truncated_name_table; 77 encodeULEB128(ret->second, OS); 78 return sampleprof_error::success; 79 } 80 81 void SampleProfileWriterBinary::addName(StringRef FName) { 82 auto NextIdx = NameTable.size(); 83 NameTable.insert(std::make_pair(FName, NextIdx)); 84 } 85 86 void SampleProfileWriterBinary::addNames(const FunctionSamples &S) { 87 // Add all the names in indirect call targets. 88 for (const auto &I : S.getBodySamples()) { 89 const SampleRecord &Sample = I.second; 90 for (const auto &J : Sample.getCallTargets()) 91 addName(J.first()); 92 } 93 94 // Recursively add all the names for inlined callsites. 95 for (const auto &J : S.getCallsiteSamples()) { 96 CallsiteLocation Loc = J.first; 97 const FunctionSamples &CalleeSamples = J.second; 98 addName(Loc.CalleeName); 99 addNames(CalleeSamples); 100 } 101 } 102 103 std::error_code SampleProfileWriterBinary::writeHeader( 104 const StringMap<FunctionSamples> &ProfileMap) { 105 // Write file magic identifier. 106 encodeULEB128(SPMagic(), OS); 107 encodeULEB128(SPVersion(), OS); 108 109 // Generate the name table for all the functions referenced in the profile. 110 for (const auto &I : ProfileMap) { 111 addName(I.first()); 112 addNames(I.second); 113 } 114 115 // Write out the name table. 116 encodeULEB128(NameTable.size(), OS); 117 for (auto N : NameTable) { 118 OS << N.first; 119 encodeULEB128(0, OS); 120 } 121 122 return sampleprof_error::success; 123 } 124 125 std::error_code SampleProfileWriterBinary::writeBody(StringRef FName, 126 const FunctionSamples &S) { 127 if (std::error_code EC = writeNameIdx(FName)) 128 return EC; 129 130 encodeULEB128(S.getTotalSamples(), OS); 131 132 // Emit all the body samples. 133 encodeULEB128(S.getBodySamples().size(), OS); 134 for (const auto &I : S.getBodySamples()) { 135 LineLocation Loc = I.first; 136 const SampleRecord &Sample = I.second; 137 encodeULEB128(Loc.LineOffset, OS); 138 encodeULEB128(Loc.Discriminator, OS); 139 encodeULEB128(Sample.getSamples(), OS); 140 encodeULEB128(Sample.getCallTargets().size(), OS); 141 for (const auto &J : Sample.getCallTargets()) { 142 StringRef Callee = J.first(); 143 uint64_t CalleeSamples = J.second; 144 if (std::error_code EC = writeNameIdx(Callee)) 145 return EC; 146 encodeULEB128(CalleeSamples, OS); 147 } 148 } 149 150 // Recursively emit all the callsite samples. 151 encodeULEB128(S.getCallsiteSamples().size(), OS); 152 for (const auto &J : S.getCallsiteSamples()) { 153 CallsiteLocation Loc = J.first; 154 const FunctionSamples &CalleeSamples = J.second; 155 encodeULEB128(Loc.LineOffset, OS); 156 encodeULEB128(Loc.Discriminator, OS); 157 if (std::error_code EC = writeBody(Loc.CalleeName, CalleeSamples)) 158 return EC; 159 } 160 161 return sampleprof_error::success; 162 } 163 164 /// \brief Write samples of a top-level function to a binary file. 165 /// 166 /// \returns true if the samples were written successfully, false otherwise. 167 std::error_code SampleProfileWriterBinary::write(StringRef FName, 168 const FunctionSamples &S) { 169 encodeULEB128(S.getHeadSamples(), OS); 170 return writeBody(FName, S); 171 } 172 173 /// \brief Create a sample profile writer based on the specified format. 174 /// 175 /// \param Filename The file to create. 176 /// 177 /// \param Writer The writer to instantiate according to the specified format. 178 /// 179 /// \param Format Encoding format for the profile file. 180 /// 181 /// \returns an error code indicating the status of the created writer. 182 ErrorOr<std::unique_ptr<SampleProfileWriter>> 183 SampleProfileWriter::create(StringRef Filename, SampleProfileFormat Format) { 184 std::error_code EC; 185 std::unique_ptr<SampleProfileWriter> Writer; 186 187 if (Format == SPF_Binary) 188 Writer.reset(new SampleProfileWriterBinary(Filename, EC)); 189 else if (Format == SPF_Text) 190 Writer.reset(new SampleProfileWriterText(Filename, EC)); 191 else if (Format == SPF_GCC) 192 EC = sampleprof_error::unsupported_writing_format; 193 else 194 EC = sampleprof_error::unrecognized_format; 195 196 if (EC) 197 return EC; 198 199 return std::move(Writer); 200 } 201