brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.3 KiB · 8d2ed28 Raw
218 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// llvm-profgen generates SPGO profiles from perf script ouput.10//11//===----------------------------------------------------------------------===//12 13#include "ErrorHandling.h"14#include "Options.h"15#include "PerfReader.h"16#include "ProfileGenerator.h"17#include "ProfiledBinary.h"18#include "llvm/DebugInfo/Symbolize/SymbolizableModule.h"19#include "llvm/Support/CommandLine.h"20#include "llvm/Support/FileSystem.h"21#include "llvm/Support/InitLLVM.h"22#include "llvm/Support/TargetSelect.h"23#include "llvm/Support/VirtualFileSystem.h"24 25using namespace llvm;26using namespace sampleprof;27 28namespace llvm {29 30cl::OptionCategory ProfGenCategory("ProfGen Options");31 32static cl::opt<std::string> PerfScriptFilename(33    "perfscript", cl::value_desc("perfscript"),34    cl::desc("Path of perf-script trace created by Linux perf tool with "35             "`script` command(the raw perf.data should be profiled with -b)"),36    cl::cat(ProfGenCategory));37static cl::alias PSA("ps", cl::desc("Alias for --perfscript"),38                     cl::aliasopt(PerfScriptFilename));39 40static cl::opt<std::string> PerfDataFilename(41    "perfdata", cl::value_desc("perfdata"),42    cl::desc("Path of raw perf data created by Linux perf tool (it should be "43             "profiled with -b)"),44    cl::cat(ProfGenCategory));45static cl::alias PDA("pd", cl::desc("Alias for --perfdata"),46                     cl::aliasopt(PerfDataFilename));47 48static cl::opt<std::string> UnsymbolizedProfFilename(49    "unsymbolized-profile", cl::value_desc("unsymbolized profile"),50    cl::desc("Path of the unsymbolized profile created by "51             "`llvm-profgen` with `--skip-symbolization`"),52    cl::cat(ProfGenCategory));53static cl::alias UPA("up", cl::desc("Alias for --unsymbolized-profile"),54                     cl::aliasopt(UnsymbolizedProfFilename));55 56static cl::opt<std::string> SampleProfFilename(57    "llvm-sample-profile", cl::value_desc("llvm sample profile"),58    cl::desc("Path of the LLVM sample profile"), cl::cat(ProfGenCategory));59 60static cl::opt<std::string>61    BinaryPath("binary", cl::value_desc("binary"), cl::Required,62               cl::desc("Path of profiled executable binary."),63               cl::cat(ProfGenCategory));64 65static cl::opt<uint32_t>66    ProcessId("pid", cl::value_desc("process Id"), cl::init(0),67              cl::desc("Process Id for the profiled executable binary."),68              cl::cat(ProfGenCategory));69 70static cl::opt<std::string> DebugBinPath(71    "debug-binary", cl::value_desc("debug-binary"),72    cl::desc("Path of debug info binary, llvm-profgen will load the DWARF info "73             "from it instead of the executable binary."),74    cl::cat(ProfGenCategory));75 76static cl::opt<std::string> DataAccessProfileFilename(77    "data-access-perftrace", cl::value_desc("data-access-perftrace"),78    cl::desc("File path of a Linux perf raw trace (generated by `perf report "79             "-D`) consisting of memory access events."),80    cl::cat(ProfGenCategory));81 82// Validate the command line input.83static void validateCommandLine() {84  // Allow the missing perfscript if we only use to show binary disassembly.85  if (!ShowDisassemblyOnly) {86    // Validate input profile is provided only once87    bool HasPerfData = PerfDataFilename.getNumOccurrences() > 0;88    bool HasPerfScript = PerfScriptFilename.getNumOccurrences() > 0;89    bool HasUnsymbolizedProfile =90        UnsymbolizedProfFilename.getNumOccurrences() > 0;91    bool HasSampleProfile = SampleProfFilename.getNumOccurrences() > 0;92    uint16_t S =93        HasPerfData + HasPerfScript + HasUnsymbolizedProfile + HasSampleProfile;94    if (S != 1) {95      std::string Msg =96          S > 197              ? "`--perfscript`, `--perfdata` and `--unsymbolized-profile` "98                "cannot be used together."99              : "Perf input file is missing, please use one of `--perfscript`, "100                "`--perfdata` and `--unsymbolized-profile` for the input.";101      exitWithError(Msg);102    }103 104    auto CheckFileExists = [](bool H, StringRef File) {105      if (H && !llvm::sys::fs::exists(File)) {106        std::string Msg = "Input perf file(" + File.str() + ") doesn't exist.";107        exitWithError(Msg);108      }109    };110 111    CheckFileExists(HasPerfData, PerfDataFilename);112    CheckFileExists(HasPerfScript, PerfScriptFilename);113    CheckFileExists(HasUnsymbolizedProfile, UnsymbolizedProfFilename);114    CheckFileExists(HasSampleProfile, SampleProfFilename);115  }116 117  if (!llvm::sys::fs::exists(BinaryPath)) {118    std::string Msg = "Input binary(" + BinaryPath + ") doesn't exist.";119    exitWithError(Msg);120  }121 122  if (CSProfileGenerator::MaxCompressionSize < -1) {123    exitWithError("Value of --compress-recursion should >= -1");124  }125  if (ShowSourceLocations && !ShowDisassemblyOnly) {126    exitWithError("--show-source-locations should work together with "127                  "--show-disassembly-only!");128  }129}130 131static PerfInputFile getPerfInputFile() {132  PerfInputFile File;133  if (PerfDataFilename.getNumOccurrences()) {134    File.InputFile = PerfDataFilename;135    File.Format = PerfFormat::PerfData;136  } else if (PerfScriptFilename.getNumOccurrences()) {137    File.InputFile = PerfScriptFilename;138    File.Format = PerfFormat::PerfScript;139  } else if (UnsymbolizedProfFilename.getNumOccurrences()) {140    File.InputFile = UnsymbolizedProfFilename;141    File.Format = PerfFormat::UnsymbolizedProfile;142  }143  return File;144}145 146} // end namespace llvm147 148int main(int argc, const char *argv[]) {149  InitLLVM X(argc, argv);150 151  // Initialize targets and assembly printers/parsers.152  InitializeAllTargetInfos();153  InitializeAllTargetMCs();154  InitializeAllDisassemblers();155 156  cl::HideUnrelatedOptions({&ProfGenCategory, &getColorCategory()});157  cl::ParseCommandLineOptions(argc, argv, "llvm SPGO profile generator\n");158  validateCommandLine();159 160  // Load symbols and disassemble the code of a given binary.161  std::unique_ptr<ProfiledBinary> Binary =162      std::make_unique<ProfiledBinary>(BinaryPath, DebugBinPath);163  if (ShowDisassemblyOnly)164    return EXIT_SUCCESS;165 166  if (SampleProfFilename.getNumOccurrences()) {167    LLVMContext Context;168    auto FS = vfs::getRealFileSystem();169    auto ReaderOrErr =170        SampleProfileReader::create(SampleProfFilename, Context, *FS);171    std::unique_ptr<sampleprof::SampleProfileReader> Reader =172        std::move(ReaderOrErr.get());173    Reader->read();174    std::unique_ptr<ProfileGeneratorBase> Generator =175        ProfileGeneratorBase::create(Binary.get(), Reader->getProfiles(),176                                     Reader->profileIsCS());177    Generator->generateProfile();178    Generator->write();179  } else {180    std::optional<uint32_t> PIDFilter;181    if (ProcessId.getNumOccurrences())182      PIDFilter = ProcessId;183    PerfInputFile PerfFile = getPerfInputFile();184    std::unique_ptr<PerfReaderBase> Reader =185        PerfReaderBase::create(Binary.get(), PerfFile, PIDFilter);186    // Parse perf events and samples187    Reader->parsePerfTraces();188 189    if (!DataAccessProfileFilename.empty()) {190      if (Reader->profileIsCS() || Binary->usePseudoProbes()) {191        exitWithError("Symbolizing vtables from data access profiles is not "192                      "yet supported for context-sensitive perf traces or "193                      "when pseudo-probe based mapping is enabled. ");194      }195      // Parse the data access perf traces into <ip, data-addr> pairs, symbolize196      // the data-addr to data-symbol. If the data-addr is a vtable, increment197      // counters for the <ip, data-symbol> pair.198      if (Error E = Reader->parseDataAccessPerfTraces(DataAccessProfileFilename,199                                                      PIDFilter)) {200        handleAllErrors(std::move(E), [&](const StringError &SE) {201          exitWithError(SE.getMessage());202        });203      }204    }205 206    if (SkipSymbolization)207      return EXIT_SUCCESS;208 209    std::unique_ptr<ProfileGeneratorBase> Generator =210        ProfileGeneratorBase::create(Binary.get(), &Reader->getSampleCounters(),211                                     Reader->profileIsCS());212    Generator->generateProfile();213    Generator->write();214  }215 216  return EXIT_SUCCESS;217}218