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