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/DebugInfo/Symbolize/SymbolizableModule.h" 18 #include "llvm/Support/CommandLine.h" 19 #include "llvm/Support/FileSystem.h" 20 #include "llvm/Support/InitLLVM.h" 21 #include "llvm/Support/TargetSelect.h" 22 23 static cl::OptionCategory ProfGenCategory("ProfGen Options"); 24 25 static cl::opt<std::string> PerfScriptFilename( 26 "perfscript", cl::value_desc("perfscript"), 27 llvm::cl::MiscFlags::CommaSeparated, 28 cl::desc("Path of perf-script trace created by Linux perf tool with " 29 "`script` command(the raw perf.data should be profiled with -b)"), 30 cl::cat(ProfGenCategory)); 31 static cl::alias PSA("ps", cl::desc("Alias for --perfscript"), 32 cl::aliasopt(PerfScriptFilename)); 33 34 static cl::opt<std::string> PerfDataFilename( 35 "perfdata", cl::value_desc("perfdata"), 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 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> SampleProfFilename( 52 "llvm-sample-profile", cl::value_desc("llvm sample profile"), 53 cl::desc("Path of the LLVM sample profile"), cl::cat(ProfGenCategory)); 54 55 static cl::opt<std::string> 56 BinaryPath("binary", cl::value_desc("binary"), cl::Required, 57 cl::desc("Path of profiled executable binary."), 58 cl::cat(ProfGenCategory)); 59 60 static cl::opt<uint32_t> 61 ProcessId("pid", cl::value_desc("process Id"), cl::init(0), 62 cl::desc("Process Id for the profiled executable binary."), 63 cl::cat(ProfGenCategory)); 64 65 static cl::opt<std::string> DebugBinPath( 66 "debug-binary", cl::value_desc("debug-binary"), 67 cl::desc("Path of debug info binary, llvm-profgen will load the DWARF info " 68 "from it instead of the executable binary."), 69 cl::cat(ProfGenCategory)); 70 71 extern cl::opt<bool> ShowDisassemblyOnly; 72 extern cl::opt<bool> ShowSourceLocations; 73 extern cl::opt<bool> SkipSymbolization; 74 75 using namespace llvm; 76 using namespace sampleprof; 77 78 // Validate the command line input. 79 static void validateCommandLine() { 80 // Allow the missing perfscript if we only use to show binary disassembly. 81 if (!ShowDisassemblyOnly) { 82 // Validate input profile is provided only once 83 uint16_t HasPerfData = PerfDataFilename.getNumOccurrences(); 84 uint16_t HasPerfScript = PerfScriptFilename.getNumOccurrences(); 85 uint16_t HasUnsymbolizedProfile = 86 UnsymbolizedProfFilename.getNumOccurrences(); 87 uint16_t HasSampleProfile = SampleProfFilename.getNumOccurrences(); 88 uint16_t S = 89 HasPerfData + HasPerfScript + HasUnsymbolizedProfile + HasSampleProfile; 90 if (S != 1) { 91 std::string Msg = 92 S > 1 93 ? "`--perfscript`, `--perfdata` and `--unsymbolized-profile` " 94 "cannot be used together." 95 : "Perf input file is missing, please use one of `--perfscript`, " 96 "`--perfdata` and `--unsymbolized-profile` for the input."; 97 exitWithError(Msg); 98 } 99 100 auto CheckFileExists = [](bool H, StringRef File) { 101 if (H && !llvm::sys::fs::exists(File)) { 102 std::string Msg = "Input perf file(" + File.str() + ") doesn't exist."; 103 exitWithError(Msg); 104 } 105 }; 106 107 CheckFileExists(HasPerfData, PerfDataFilename); 108 CheckFileExists(HasPerfScript, PerfScriptFilename); 109 CheckFileExists(HasUnsymbolizedProfile, UnsymbolizedProfFilename); 110 CheckFileExists(HasSampleProfile, SampleProfFilename); 111 } 112 113 if (!llvm::sys::fs::exists(BinaryPath)) { 114 std::string Msg = "Input binary(" + BinaryPath + ") doesn't exist."; 115 exitWithError(Msg); 116 } 117 118 if (CSProfileGenerator::MaxCompressionSize < -1) { 119 exitWithError("Value of --compress-recursion should >= -1"); 120 } 121 if (ShowSourceLocations && !ShowDisassemblyOnly) { 122 exitWithError("--show-source-locations should work together with " 123 "--show-disassembly-only!"); 124 } 125 } 126 127 static PerfInputFile getPerfInputFile() { 128 PerfInputFile File; 129 if (PerfDataFilename.getNumOccurrences()) { 130 File.InputFile = PerfDataFilename; 131 File.Format = PerfFormat::PerfData; 132 } else if (PerfScriptFilename.getNumOccurrences()) { 133 File.InputFile = PerfScriptFilename; 134 File.Format = PerfFormat::PerfScript; 135 } else if (UnsymbolizedProfFilename.getNumOccurrences()) { 136 File.InputFile = UnsymbolizedProfFilename; 137 File.Format = PerfFormat::UnsymbolizedProfile; 138 } 139 return File; 140 } 141 142 int main(int argc, const char *argv[]) { 143 InitLLVM X(argc, argv); 144 145 // Initialize targets and assembly printers/parsers. 146 InitializeAllTargetInfos(); 147 InitializeAllTargetMCs(); 148 InitializeAllDisassemblers(); 149 150 cl::HideUnrelatedOptions({&ProfGenCategory, &getColorCategory()}); 151 cl::ParseCommandLineOptions(argc, argv, "llvm SPGO profile generator\n"); 152 validateCommandLine(); 153 154 // Load symbols and disassemble the code of a given binary. 155 std::unique_ptr<ProfiledBinary> Binary = 156 std::make_unique<ProfiledBinary>(BinaryPath, DebugBinPath); 157 if (ShowDisassemblyOnly) 158 return EXIT_SUCCESS; 159 160 if (SampleProfFilename.getNumOccurrences()) { 161 LLVMContext Context; 162 auto ReaderOrErr = SampleProfileReader::create(SampleProfFilename, Context); 163 std::unique_ptr<sampleprof::SampleProfileReader> Reader = 164 std::move(ReaderOrErr.get()); 165 Reader->read(); 166 std::unique_ptr<ProfileGeneratorBase> Generator = 167 ProfileGeneratorBase::create(Binary.get(), Reader->getProfiles(), 168 Reader->profileIsCS()); 169 Generator->generateProfile(); 170 Generator->write(); 171 } else { 172 Optional<uint32_t> PIDFilter; 173 if (ProcessId.getNumOccurrences()) 174 PIDFilter = ProcessId; 175 PerfInputFile PerfFile = getPerfInputFile(); 176 std::unique_ptr<PerfReaderBase> Reader = 177 PerfReaderBase::create(Binary.get(), PerfFile, PIDFilter); 178 // Parse perf events and samples 179 Reader->parsePerfTraces(); 180 181 if (SkipSymbolization) 182 return EXIT_SUCCESS; 183 184 std::unique_ptr<ProfileGeneratorBase> Generator = 185 ProfileGeneratorBase::create(Binary.get(), &Reader->getSampleCounters(), 186 Reader->profileIsCS()); 187 Generator->generateProfile(); 188 Generator->write(); 189 } 190 191 return EXIT_SUCCESS; 192 } 193