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