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 /// \brief Write samples to a binary file. 126 /// 127 /// \returns true if the samples were written successfully, false otherwise. 128 std::error_code SampleProfileWriterBinary::write(StringRef FName, 129 const FunctionSamples &S) { 130 if (std::error_code EC = writeNameIdx(FName)) 131 return EC; 132 133 encodeULEB128(S.getTotalSamples(), OS); 134 encodeULEB128(S.getHeadSamples(), OS); 135 encodeULEB128(S.getBodySamples().size(), OS); 136 137 // Emit all the body samples. 138 for (const auto &I : S.getBodySamples()) { 139 LineLocation Loc = I.first; 140 const SampleRecord &Sample = I.second; 141 encodeULEB128(Loc.LineOffset, OS); 142 encodeULEB128(Loc.Discriminator, OS); 143 encodeULEB128(Sample.getSamples(), OS); 144 encodeULEB128(Sample.getCallTargets().size(), OS); 145 for (const auto &J : Sample.getCallTargets()) { 146 StringRef Callee = J.first(); 147 uint64_t CalleeSamples = J.second; 148 if (std::error_code EC = writeNameIdx(Callee)) 149 return EC; 150 encodeULEB128(CalleeSamples, OS); 151 } 152 } 153 154 // Recursively emit all the callsite samples. 155 encodeULEB128(S.getCallsiteSamples().size(), OS); 156 for (const auto &J : S.getCallsiteSamples()) { 157 CallsiteLocation Loc = J.first; 158 const FunctionSamples &CalleeSamples = J.second; 159 encodeULEB128(Loc.LineOffset, OS); 160 encodeULEB128(Loc.Discriminator, OS); 161 if (std::error_code EC = write(Loc.CalleeName, CalleeSamples)) 162 return EC; 163 } 164 165 return sampleprof_error::success; 166 } 167 168 /// \brief Create a sample profile writer based on the specified format. 169 /// 170 /// \param Filename The file to create. 171 /// 172 /// \param Writer The writer to instantiate according to the specified format. 173 /// 174 /// \param Format Encoding format for the profile file. 175 /// 176 /// \returns an error code indicating the status of the created writer. 177 ErrorOr<std::unique_ptr<SampleProfileWriter>> 178 SampleProfileWriter::create(StringRef Filename, SampleProfileFormat Format) { 179 std::error_code EC; 180 std::unique_ptr<SampleProfileWriter> Writer; 181 182 if (Format == SPF_Binary) 183 Writer.reset(new SampleProfileWriterBinary(Filename, EC)); 184 else if (Format == SPF_Text) 185 Writer.reset(new SampleProfileWriterText(Filename, EC)); 186 else if (Format == SPF_GCC) 187 EC = sampleprof_error::unsupported_writing_format; 188 else 189 EC = sampleprof_error::unrecognized_format; 190 191 if (EC) 192 return EC; 193 194 return std::move(Writer); 195 } 196