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