llvm-profgen.cpp 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. //===- llvm-profgen.cpp - LLVM SPGO profile generation tool -----*- C++ -*-===//
  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. // llvm-profgen generates SPGO profiles from perf script ouput.
  10. //
  11. //===----------------------------------------------------------------------===//
  12. #include "ErrorHandling.h"
  13. #include "PerfReader.h"
  14. #include "ProfileGenerator.h"
  15. #include "ProfiledBinary.h"
  16. #include "llvm/Support/CommandLine.h"
  17. #include "llvm/Support/FileSystem.h"
  18. #include "llvm/Support/InitLLVM.h"
  19. #include "llvm/Support/TargetSelect.h"
  20. static cl::OptionCategory ProfGenCategory("ProfGen Options");
  21. static cl::opt<std::string> PerfScriptFilename(
  22. "perfscript", cl::value_desc("perfscript"), cl::ZeroOrMore,
  23. llvm::cl::MiscFlags::CommaSeparated,
  24. cl::desc("Path of perf-script trace created by Linux perf tool with "
  25. "`script` command(the raw perf.data should be profiled with -b)"),
  26. cl::cat(ProfGenCategory));
  27. static cl::alias PSA("ps", cl::desc("Alias for --perfscript"),
  28. cl::aliasopt(PerfScriptFilename));
  29. static cl::opt<std::string> PerfDataFilename(
  30. "perfdata", cl::value_desc("perfdata"), cl::ZeroOrMore,
  31. llvm::cl::MiscFlags::CommaSeparated,
  32. cl::desc("Path of raw perf data created by Linux perf tool (it should be "
  33. "profiled with -b)"),
  34. cl::cat(ProfGenCategory));
  35. static cl::alias PDA("pd", cl::desc("Alias for --perfdata"),
  36. cl::aliasopt(PerfDataFilename));
  37. static cl::opt<std::string> UnsymbolizedProfFilename(
  38. "unsymbolized-profile", cl::value_desc("unsymbolized profile"),
  39. cl::ZeroOrMore, llvm::cl::MiscFlags::CommaSeparated,
  40. cl::desc("Path of the unsymbolized profile created by "
  41. "`llvm-profgen` with `--skip-symbolization`"),
  42. cl::cat(ProfGenCategory));
  43. static cl::alias UPA("up", cl::desc("Alias for --unsymbolized-profile"),
  44. cl::aliasopt(UnsymbolizedProfFilename));
  45. static cl::opt<std::string>
  46. BinaryPath("binary", cl::value_desc("binary"), cl::Required,
  47. cl::desc("Path of profiled executable binary."),
  48. cl::cat(ProfGenCategory));
  49. static cl::opt<std::string> DebugBinPath(
  50. "debug-binary", cl::value_desc("debug-binary"), cl::ZeroOrMore,
  51. cl::desc("Path of debug info binary, llvm-profgen will load the DWARF info "
  52. "from it instead of the executable binary."),
  53. cl::cat(ProfGenCategory));
  54. extern cl::opt<bool> ShowDisassemblyOnly;
  55. extern cl::opt<bool> ShowSourceLocations;
  56. extern cl::opt<bool> SkipSymbolization;
  57. using namespace llvm;
  58. using namespace sampleprof;
  59. // Validate the command line input.
  60. static void validateCommandLine() {
  61. // Allow the missing perfscript if we only use to show binary disassembly.
  62. if (!ShowDisassemblyOnly) {
  63. // Validate input profile is provided only once
  64. uint16_t HasPerfData = PerfDataFilename.getNumOccurrences();
  65. uint16_t HasPerfScript = PerfScriptFilename.getNumOccurrences();
  66. uint16_t HasUnsymbolizedProfile =
  67. UnsymbolizedProfFilename.getNumOccurrences();
  68. uint16_t S = HasPerfData + HasPerfScript + HasUnsymbolizedProfile;
  69. if (S != 1) {
  70. std::string Msg =
  71. S > 1
  72. ? "`--perfscript`, `--perfdata` and `--unsymbolized-profile` "
  73. "cannot be used together."
  74. : "Perf input file is missing, please use one of `--perfscript`, "
  75. "`--perfdata` and `--unsymbolized-profile` for the input.";
  76. exitWithError(Msg);
  77. }
  78. auto CheckFileExists = [](bool H, StringRef File) {
  79. if (H && !llvm::sys::fs::exists(File)) {
  80. std::string Msg = "Input perf file(" + File.str() + ") doesn't exist.";
  81. exitWithError(Msg);
  82. }
  83. };
  84. CheckFileExists(HasPerfData, PerfDataFilename);
  85. CheckFileExists(HasPerfScript, PerfScriptFilename);
  86. CheckFileExists(HasUnsymbolizedProfile, UnsymbolizedProfFilename);
  87. }
  88. if (!llvm::sys::fs::exists(BinaryPath)) {
  89. std::string Msg = "Input binary(" + BinaryPath + ") doesn't exist.";
  90. exitWithError(Msg);
  91. }
  92. if (CSProfileGenerator::MaxCompressionSize < -1) {
  93. exitWithError("Value of --compress-recursion should >= -1");
  94. }
  95. if (ShowSourceLocations && !ShowDisassemblyOnly) {
  96. exitWithError("--show-source-locations should work together with "
  97. "--show-disassembly-only!");
  98. }
  99. }
  100. static PerfInputFile getPerfInputFile() {
  101. PerfInputFile File;
  102. if (PerfDataFilename.getNumOccurrences()) {
  103. File.InputFile = PerfDataFilename;
  104. File.Format = PerfFormat::PerfData;
  105. } else if (PerfScriptFilename.getNumOccurrences()) {
  106. File.InputFile = PerfScriptFilename;
  107. File.Format = PerfFormat::PerfScript;
  108. } else if (UnsymbolizedProfFilename.getNumOccurrences()) {
  109. File.InputFile = UnsymbolizedProfFilename;
  110. File.Format = PerfFormat::UnsymbolizedProfile;
  111. }
  112. return File;
  113. }
  114. int main(int argc, const char *argv[]) {
  115. InitLLVM X(argc, argv);
  116. // Initialize targets and assembly printers/parsers.
  117. InitializeAllTargetInfos();
  118. InitializeAllTargetMCs();
  119. InitializeAllDisassemblers();
  120. cl::HideUnrelatedOptions({&ProfGenCategory, &getColorCategory()});
  121. cl::ParseCommandLineOptions(argc, argv, "llvm SPGO profile generator\n");
  122. validateCommandLine();
  123. // Load symbols and disassemble the code of a given binary.
  124. std::unique_ptr<ProfiledBinary> Binary =
  125. std::make_unique<ProfiledBinary>(BinaryPath, DebugBinPath);
  126. if (ShowDisassemblyOnly)
  127. return EXIT_SUCCESS;
  128. PerfInputFile PerfFile = getPerfInputFile();
  129. std::unique_ptr<PerfReaderBase> Reader =
  130. PerfReaderBase::create(Binary.get(), PerfFile);
  131. // Parse perf events and samples
  132. Reader->parsePerfTraces();
  133. if (SkipSymbolization)
  134. return EXIT_SUCCESS;
  135. std::unique_ptr<ProfileGeneratorBase> Generator =
  136. ProfileGeneratorBase::create(Binary.get(), Reader->getSampleCounters(),
  137. Reader->profileIsCSFlat());
  138. Generator->generateProfile();
  139. Generator->write();
  140. return EXIT_SUCCESS;
  141. }