|  | //===- llvm-profgen.cpp - LLVM SPGO profile generation tool -----*- C++ -*-===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // llvm-profgen generates SPGO profiles from perf script ouput. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "ErrorHandling.h" | 
|  | #include "PerfReader.h" | 
|  | #include "ProfileGenerator.h" | 
|  | #include "ProfiledBinary.h" | 
|  | #include "llvm/DebugInfo/Symbolize/SymbolizableModule.h" | 
|  | #include "llvm/Support/CommandLine.h" | 
|  | #include "llvm/Support/FileSystem.h" | 
|  | #include "llvm/Support/InitLLVM.h" | 
|  | #include "llvm/Support/TargetSelect.h" | 
|  | #include "llvm/Support/VirtualFileSystem.h" | 
|  |  | 
|  | static cl::OptionCategory ProfGenCategory("ProfGen Options"); | 
|  |  | 
|  | static cl::opt<std::string> PerfScriptFilename( | 
|  | "perfscript", cl::value_desc("perfscript"), | 
|  | cl::desc("Path of perf-script trace created by Linux perf tool with " | 
|  | "`script` command(the raw perf.data should be profiled with -b)"), | 
|  | cl::cat(ProfGenCategory)); | 
|  | static cl::alias PSA("ps", cl::desc("Alias for --perfscript"), | 
|  | cl::aliasopt(PerfScriptFilename)); | 
|  |  | 
|  | static cl::opt<std::string> PerfDataFilename( | 
|  | "perfdata", cl::value_desc("perfdata"), | 
|  | cl::desc("Path of raw perf data created by Linux perf tool (it should be " | 
|  | "profiled with -b)"), | 
|  | cl::cat(ProfGenCategory)); | 
|  | static cl::alias PDA("pd", cl::desc("Alias for --perfdata"), | 
|  | cl::aliasopt(PerfDataFilename)); | 
|  |  | 
|  | static cl::opt<std::string> UnsymbolizedProfFilename( | 
|  | "unsymbolized-profile", cl::value_desc("unsymbolized profile"), | 
|  | cl::desc("Path of the unsymbolized profile created by " | 
|  | "`llvm-profgen` with `--skip-symbolization`"), | 
|  | cl::cat(ProfGenCategory)); | 
|  | static cl::alias UPA("up", cl::desc("Alias for --unsymbolized-profile"), | 
|  | cl::aliasopt(UnsymbolizedProfFilename)); | 
|  |  | 
|  | static cl::opt<std::string> SampleProfFilename( | 
|  | "llvm-sample-profile", cl::value_desc("llvm sample profile"), | 
|  | cl::desc("Path of the LLVM sample profile"), cl::cat(ProfGenCategory)); | 
|  |  | 
|  | static cl::opt<std::string> | 
|  | BinaryPath("binary", cl::value_desc("binary"), cl::Required, | 
|  | cl::desc("Path of profiled executable binary."), | 
|  | cl::cat(ProfGenCategory)); | 
|  |  | 
|  | static cl::opt<uint32_t> | 
|  | ProcessId("pid", cl::value_desc("process Id"), cl::init(0), | 
|  | cl::desc("Process Id for the profiled executable binary."), | 
|  | cl::cat(ProfGenCategory)); | 
|  |  | 
|  | static cl::opt<std::string> DebugBinPath( | 
|  | "debug-binary", cl::value_desc("debug-binary"), | 
|  | cl::desc("Path of debug info binary, llvm-profgen will load the DWARF info " | 
|  | "from it instead of the executable binary."), | 
|  | cl::cat(ProfGenCategory)); | 
|  |  | 
|  | extern cl::opt<bool> ShowDisassemblyOnly; | 
|  | extern cl::opt<bool> ShowSourceLocations; | 
|  | extern cl::opt<bool> SkipSymbolization; | 
|  |  | 
|  | using namespace llvm; | 
|  | using namespace sampleprof; | 
|  |  | 
|  | // Validate the command line input. | 
|  | static void validateCommandLine() { | 
|  | // Allow the missing perfscript if we only use to show binary disassembly. | 
|  | if (!ShowDisassemblyOnly) { | 
|  | // Validate input profile is provided only once | 
|  | bool HasPerfData = PerfDataFilename.getNumOccurrences() > 0; | 
|  | bool HasPerfScript = PerfScriptFilename.getNumOccurrences() > 0; | 
|  | bool HasUnsymbolizedProfile = | 
|  | UnsymbolizedProfFilename.getNumOccurrences() > 0; | 
|  | bool HasSampleProfile = SampleProfFilename.getNumOccurrences() > 0; | 
|  | uint16_t S = | 
|  | HasPerfData + HasPerfScript + HasUnsymbolizedProfile + HasSampleProfile; | 
|  | if (S != 1) { | 
|  | std::string Msg = | 
|  | S > 1 | 
|  | ? "`--perfscript`, `--perfdata` and `--unsymbolized-profile` " | 
|  | "cannot be used together." | 
|  | : "Perf input file is missing, please use one of `--perfscript`, " | 
|  | "`--perfdata` and `--unsymbolized-profile` for the input."; | 
|  | exitWithError(Msg); | 
|  | } | 
|  |  | 
|  | auto CheckFileExists = [](bool H, StringRef File) { | 
|  | if (H && !llvm::sys::fs::exists(File)) { | 
|  | std::string Msg = "Input perf file(" + File.str() + ") doesn't exist."; | 
|  | exitWithError(Msg); | 
|  | } | 
|  | }; | 
|  |  | 
|  | CheckFileExists(HasPerfData, PerfDataFilename); | 
|  | CheckFileExists(HasPerfScript, PerfScriptFilename); | 
|  | CheckFileExists(HasUnsymbolizedProfile, UnsymbolizedProfFilename); | 
|  | CheckFileExists(HasSampleProfile, SampleProfFilename); | 
|  | } | 
|  |  | 
|  | if (!llvm::sys::fs::exists(BinaryPath)) { | 
|  | std::string Msg = "Input binary(" + BinaryPath + ") doesn't exist."; | 
|  | exitWithError(Msg); | 
|  | } | 
|  |  | 
|  | if (CSProfileGenerator::MaxCompressionSize < -1) { | 
|  | exitWithError("Value of --compress-recursion should >= -1"); | 
|  | } | 
|  | if (ShowSourceLocations && !ShowDisassemblyOnly) { | 
|  | exitWithError("--show-source-locations should work together with " | 
|  | "--show-disassembly-only!"); | 
|  | } | 
|  | } | 
|  |  | 
|  | static PerfInputFile getPerfInputFile() { | 
|  | PerfInputFile File; | 
|  | if (PerfDataFilename.getNumOccurrences()) { | 
|  | File.InputFile = PerfDataFilename; | 
|  | File.Format = PerfFormat::PerfData; | 
|  | } else if (PerfScriptFilename.getNumOccurrences()) { | 
|  | File.InputFile = PerfScriptFilename; | 
|  | File.Format = PerfFormat::PerfScript; | 
|  | } else if (UnsymbolizedProfFilename.getNumOccurrences()) { | 
|  | File.InputFile = UnsymbolizedProfFilename; | 
|  | File.Format = PerfFormat::UnsymbolizedProfile; | 
|  | } | 
|  | return File; | 
|  | } | 
|  |  | 
|  | int main(int argc, const char *argv[]) { | 
|  | InitLLVM X(argc, argv); | 
|  |  | 
|  | // Initialize targets and assembly printers/parsers. | 
|  | InitializeAllTargetInfos(); | 
|  | InitializeAllTargetMCs(); | 
|  | InitializeAllDisassemblers(); | 
|  |  | 
|  | cl::HideUnrelatedOptions({&ProfGenCategory, &getColorCategory()}); | 
|  | cl::ParseCommandLineOptions(argc, argv, "llvm SPGO profile generator\n"); | 
|  | validateCommandLine(); | 
|  |  | 
|  | // Load symbols and disassemble the code of a given binary. | 
|  | std::unique_ptr<ProfiledBinary> Binary = | 
|  | std::make_unique<ProfiledBinary>(BinaryPath, DebugBinPath); | 
|  | if (ShowDisassemblyOnly) | 
|  | return EXIT_SUCCESS; | 
|  |  | 
|  | if (SampleProfFilename.getNumOccurrences()) { | 
|  | LLVMContext Context; | 
|  | auto FS = vfs::getRealFileSystem(); | 
|  | auto ReaderOrErr = | 
|  | SampleProfileReader::create(SampleProfFilename, Context, *FS); | 
|  | std::unique_ptr<sampleprof::SampleProfileReader> Reader = | 
|  | std::move(ReaderOrErr.get()); | 
|  | Reader->read(); | 
|  | std::unique_ptr<ProfileGeneratorBase> Generator = | 
|  | ProfileGeneratorBase::create(Binary.get(), Reader->getProfiles(), | 
|  | Reader->profileIsCS()); | 
|  | Generator->generateProfile(); | 
|  | Generator->write(); | 
|  | } else { | 
|  | std::optional<uint32_t> PIDFilter; | 
|  | if (ProcessId.getNumOccurrences()) | 
|  | PIDFilter = ProcessId; | 
|  | PerfInputFile PerfFile = getPerfInputFile(); | 
|  | std::unique_ptr<PerfReaderBase> Reader = | 
|  | PerfReaderBase::create(Binary.get(), PerfFile, PIDFilter); | 
|  | // Parse perf events and samples | 
|  | Reader->parsePerfTraces(); | 
|  |  | 
|  | if (SkipSymbolization) | 
|  | return EXIT_SUCCESS; | 
|  |  | 
|  | std::unique_ptr<ProfileGeneratorBase> Generator = | 
|  | ProfileGeneratorBase::create(Binary.get(), &Reader->getSampleCounters(), | 
|  | Reader->profileIsCS()); | 
|  | Generator->generateProfile(); | 
|  | Generator->write(); | 
|  | } | 
|  |  | 
|  | return EXIT_SUCCESS; | 
|  | } |