1 //===- llvm-profdata.cpp - LLVM profile data tool -------------------------===// 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 // llvm-profdata merges .profdata files. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "llvm/ADT/StringRef.h" 15 #include "llvm/IR/LLVMContext.h" 16 #include "llvm/ProfileData/InstrProfReader.h" 17 #include "llvm/ProfileData/InstrProfWriter.h" 18 #include "llvm/ProfileData/SampleProfReader.h" 19 #include "llvm/ProfileData/SampleProfWriter.h" 20 #include "llvm/Support/CommandLine.h" 21 #include "llvm/Support/FileSystem.h" 22 #include "llvm/Support/Format.h" 23 #include "llvm/Support/ManagedStatic.h" 24 #include "llvm/Support/MemoryBuffer.h" 25 #include "llvm/Support/Path.h" 26 #include "llvm/Support/PrettyStackTrace.h" 27 #include "llvm/Support/Signals.h" 28 #include "llvm/Support/raw_ostream.h" 29 30 using namespace llvm; 31 32 static void exitWithError(const Twine &Message, 33 StringRef Whence = "", 34 StringRef Hint = "") { 35 errs() << "error: "; 36 if (!Whence.empty()) 37 errs() << Whence << ": "; 38 errs() << Message << "\n"; 39 if (!Hint.empty()) 40 errs() << Hint << "\n"; 41 ::exit(1); 42 } 43 44 static void exitWithErrorCode(const std::error_code &Error, StringRef Whence = "") { 45 if (Error.category() == instrprof_category()) { 46 instrprof_error instrError = static_cast<instrprof_error>(Error.value()); 47 if (instrError == instrprof_error::unrecognized_format) { 48 // Hint for common error of forgetting -sample for sample profiles. 49 exitWithError(Error.message(), Whence, 50 "Perhaps you forgot to use the -sample option?"); 51 } 52 } 53 exitWithError(Error.message(), Whence); 54 } 55 56 namespace { 57 enum ProfileKinds { instr, sample }; 58 } 59 60 static void mergeInstrProfile(const cl::list<std::string> &Inputs, 61 StringRef OutputFilename) { 62 if (OutputFilename.compare("-") == 0) 63 exitWithError("Cannot write indexed profdata format to stdout."); 64 65 std::error_code EC; 66 raw_fd_ostream Output(OutputFilename.data(), EC, sys::fs::F_None); 67 if (EC) 68 exitWithErrorCode(EC, OutputFilename); 69 70 InstrProfWriter Writer; 71 for (const auto &Filename : Inputs) { 72 auto ReaderOrErr = InstrProfReader::create(Filename); 73 if (std::error_code ec = ReaderOrErr.getError()) 74 exitWithErrorCode(ec, Filename); 75 76 auto Reader = std::move(ReaderOrErr.get()); 77 for (auto &I : *Reader) 78 if (std::error_code EC = Writer.addRecord(std::move(I))) 79 errs() << Filename << ": " << I.Name << ": " << EC.message() << "\n"; 80 if (Reader->hasError()) 81 exitWithErrorCode(Reader->getError(), Filename); 82 } 83 Writer.write(Output); 84 } 85 86 static void mergeSampleProfile(const cl::list<std::string> &Inputs, 87 StringRef OutputFilename, 88 sampleprof::SampleProfileFormat OutputFormat) { 89 using namespace sampleprof; 90 auto WriterOrErr = SampleProfileWriter::create(OutputFilename, OutputFormat); 91 if (std::error_code EC = WriterOrErr.getError()) 92 exitWithErrorCode(EC, OutputFilename); 93 94 auto Writer = std::move(WriterOrErr.get()); 95 StringMap<FunctionSamples> ProfileMap; 96 SmallVector<std::unique_ptr<sampleprof::SampleProfileReader>, 5> Readers; 97 for (const auto &Filename : Inputs) { 98 auto ReaderOrErr = 99 SampleProfileReader::create(Filename, getGlobalContext()); 100 if (std::error_code EC = ReaderOrErr.getError()) 101 exitWithErrorCode(EC, Filename); 102 103 // We need to keep the readers around until after all the files are 104 // read so that we do not lose the function names stored in each 105 // reader's memory. The function names are needed to write out the 106 // merged profile map. 107 Readers.push_back(std::move(ReaderOrErr.get())); 108 const auto Reader = Readers.back().get(); 109 if (std::error_code EC = Reader->read()) 110 exitWithErrorCode(EC, Filename); 111 112 StringMap<FunctionSamples> &Profiles = Reader->getProfiles(); 113 for (StringMap<FunctionSamples>::iterator I = Profiles.begin(), 114 E = Profiles.end(); 115 I != E; ++I) { 116 StringRef FName = I->first(); 117 FunctionSamples &Samples = I->second; 118 ProfileMap[FName].merge(Samples); 119 } 120 } 121 Writer->write(ProfileMap); 122 } 123 124 static int merge_main(int argc, const char *argv[]) { 125 cl::list<std::string> Inputs(cl::Positional, cl::Required, cl::OneOrMore, 126 cl::desc("<filenames...>")); 127 128 cl::opt<std::string> OutputFilename("output", cl::value_desc("output"), 129 cl::init("-"), cl::Required, 130 cl::desc("Output file")); 131 cl::alias OutputFilenameA("o", cl::desc("Alias for --output"), 132 cl::aliasopt(OutputFilename)); 133 cl::opt<ProfileKinds> ProfileKind( 134 cl::desc("Profile kind:"), cl::init(instr), 135 cl::values(clEnumVal(instr, "Instrumentation profile (default)"), 136 clEnumVal(sample, "Sample profile"), clEnumValEnd)); 137 138 cl::opt<sampleprof::SampleProfileFormat> OutputFormat( 139 cl::desc("Format of output profile (only meaningful with --sample)"), 140 cl::init(sampleprof::SPF_Binary), 141 cl::values(clEnumValN(sampleprof::SPF_Binary, "binary", 142 "Binary encoding (default)"), 143 clEnumValN(sampleprof::SPF_Text, "text", "Text encoding"), 144 clEnumValN(sampleprof::SPF_GCC, "gcc", "GCC encoding"), 145 clEnumValEnd)); 146 147 cl::ParseCommandLineOptions(argc, argv, "LLVM profile data merger\n"); 148 149 if (ProfileKind == instr) 150 mergeInstrProfile(Inputs, OutputFilename); 151 else 152 mergeSampleProfile(Inputs, OutputFilename, OutputFormat); 153 154 return 0; 155 } 156 157 static int showInstrProfile(std::string Filename, bool ShowCounts, 158 bool ShowIndirectCallTargets, bool ShowAllFunctions, 159 std::string ShowFunction, raw_fd_ostream &OS) { 160 auto ReaderOrErr = InstrProfReader::create(Filename); 161 if (std::error_code EC = ReaderOrErr.getError()) 162 exitWithErrorCode(EC, Filename); 163 164 auto Reader = std::move(ReaderOrErr.get()); 165 uint64_t MaxFunctionCount = 0, MaxBlockCount = 0; 166 size_t ShownFunctions = 0, TotalFunctions = 0; 167 for (const auto &Func : *Reader) { 168 bool Show = 169 ShowAllFunctions || (!ShowFunction.empty() && 170 Func.Name.find(ShowFunction) != Func.Name.npos); 171 172 ++TotalFunctions; 173 assert(Func.Counts.size() > 0 && "function missing entry counter"); 174 if (Func.Counts[0] > MaxFunctionCount) 175 MaxFunctionCount = Func.Counts[0]; 176 177 if (Show) { 178 if (!ShownFunctions) 179 OS << "Counters:\n"; 180 ++ShownFunctions; 181 182 OS << " " << Func.Name << ":\n" 183 << " Hash: " << format("0x%016" PRIx64, Func.Hash) << "\n" 184 << " Counters: " << Func.Counts.size() << "\n" 185 << " Function count: " << Func.Counts[0] << "\n"; 186 if (ShowIndirectCallTargets) 187 OS << " Indirect Call Site Count: " 188 << Func.getNumValueSites(IPVK_IndirectCallTarget) << "\n"; 189 } 190 191 if (Show && ShowCounts) 192 OS << " Block counts: ["; 193 for (size_t I = 1, E = Func.Counts.size(); I < E; ++I) { 194 if (Func.Counts[I] > MaxBlockCount) 195 MaxBlockCount = Func.Counts[I]; 196 if (Show && ShowCounts) 197 OS << (I == 1 ? "" : ", ") << Func.Counts[I]; 198 } 199 if (Show && ShowCounts) 200 OS << "]\n"; 201 202 if (Show && ShowIndirectCallTargets) { 203 uint32_t NS = Func.getNumValueSites(IPVK_IndirectCallTarget); 204 OS << " Indirect Target Results: \n"; 205 for (size_t I = 0; I < NS; ++I) { 206 uint32_t NV = Func.getNumValueDataForSite(IPVK_IndirectCallTarget, I); 207 std::unique_ptr<InstrProfValueData[]> VD = 208 Func.getValueForSite(IPVK_IndirectCallTarget, I); 209 for (uint32_t V = 0; V < NV; V++) { 210 OS << "\t[ " << I << ", "; 211 OS << (const char *)VD[V].Value << ", " << VD[V].Count << " ]\n"; 212 } 213 } 214 } 215 } 216 if (Reader->hasError()) 217 exitWithErrorCode(Reader->getError(), Filename); 218 219 if (ShowAllFunctions || !ShowFunction.empty()) 220 OS << "Functions shown: " << ShownFunctions << "\n"; 221 OS << "Total functions: " << TotalFunctions << "\n"; 222 OS << "Maximum function count: " << MaxFunctionCount << "\n"; 223 OS << "Maximum internal block count: " << MaxBlockCount << "\n"; 224 return 0; 225 } 226 227 static int showSampleProfile(std::string Filename, bool ShowCounts, 228 bool ShowAllFunctions, std::string ShowFunction, 229 raw_fd_ostream &OS) { 230 using namespace sampleprof; 231 auto ReaderOrErr = SampleProfileReader::create(Filename, getGlobalContext()); 232 if (std::error_code EC = ReaderOrErr.getError()) 233 exitWithErrorCode(EC, Filename); 234 235 auto Reader = std::move(ReaderOrErr.get()); 236 if (std::error_code EC = Reader->read()) 237 exitWithErrorCode(EC, Filename); 238 239 if (ShowAllFunctions || ShowFunction.empty()) 240 Reader->dump(OS); 241 else 242 Reader->dumpFunctionProfile(ShowFunction, OS); 243 244 return 0; 245 } 246 247 static int show_main(int argc, const char *argv[]) { 248 cl::opt<std::string> Filename(cl::Positional, cl::Required, 249 cl::desc("<profdata-file>")); 250 251 cl::opt<bool> ShowCounts("counts", cl::init(false), 252 cl::desc("Show counter values for shown functions")); 253 cl::opt<bool> ShowIndirectCallTargets( 254 "ic-targets", cl::init(false), 255 cl::desc("Show indirect call site target values for shown functions")); 256 cl::opt<bool> ShowAllFunctions("all-functions", cl::init(false), 257 cl::desc("Details for every function")); 258 cl::opt<std::string> ShowFunction("function", 259 cl::desc("Details for matching functions")); 260 261 cl::opt<std::string> OutputFilename("output", cl::value_desc("output"), 262 cl::init("-"), cl::desc("Output file")); 263 cl::alias OutputFilenameA("o", cl::desc("Alias for --output"), 264 cl::aliasopt(OutputFilename)); 265 cl::opt<ProfileKinds> ProfileKind( 266 cl::desc("Profile kind:"), cl::init(instr), 267 cl::values(clEnumVal(instr, "Instrumentation profile (default)"), 268 clEnumVal(sample, "Sample profile"), clEnumValEnd)); 269 270 cl::ParseCommandLineOptions(argc, argv, "LLVM profile data summary\n"); 271 272 if (OutputFilename.empty()) 273 OutputFilename = "-"; 274 275 std::error_code EC; 276 raw_fd_ostream OS(OutputFilename.data(), EC, sys::fs::F_Text); 277 if (EC) 278 exitWithErrorCode(EC, OutputFilename); 279 280 if (ShowAllFunctions && !ShowFunction.empty()) 281 errs() << "warning: -function argument ignored: showing all functions\n"; 282 283 if (ProfileKind == instr) 284 return showInstrProfile(Filename, ShowCounts, ShowIndirectCallTargets, 285 ShowAllFunctions, ShowFunction, OS); 286 else 287 return showSampleProfile(Filename, ShowCounts, ShowAllFunctions, 288 ShowFunction, OS); 289 } 290 291 int main(int argc, const char *argv[]) { 292 // Print a stack trace if we signal out. 293 sys::PrintStackTraceOnErrorSignal(); 294 PrettyStackTraceProgram X(argc, argv); 295 llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. 296 297 StringRef ProgName(sys::path::filename(argv[0])); 298 if (argc > 1) { 299 int (*func)(int, const char *[]) = nullptr; 300 301 if (strcmp(argv[1], "merge") == 0) 302 func = merge_main; 303 else if (strcmp(argv[1], "show") == 0) 304 func = show_main; 305 306 if (func) { 307 std::string Invocation(ProgName.str() + " " + argv[1]); 308 argv[1] = Invocation.c_str(); 309 return func(argc - 1, argv + 1); 310 } 311 312 if (strcmp(argv[1], "-h") == 0 || 313 strcmp(argv[1], "-help") == 0 || 314 strcmp(argv[1], "--help") == 0) { 315 316 errs() << "OVERVIEW: LLVM profile data tools\n\n" 317 << "USAGE: " << ProgName << " <command> [args...]\n" 318 << "USAGE: " << ProgName << " <command> -help\n\n" 319 << "Available commands: merge, show\n"; 320 return 0; 321 } 322 } 323 324 if (argc < 2) 325 errs() << ProgName << ": No command specified!\n"; 326 else 327 errs() << ProgName << ": Unknown command!\n"; 328 329 errs() << "USAGE: " << ProgName << " <merge|show> [args...]\n"; 330 return 1; 331 } 332