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::list<std::string> PerfTraceFilenames(
25     "perfscript", cl::value_desc("perfscript"), cl::OneOrMore,
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 
31 static cl::opt<std::string> BinaryPath(
32     "binary", cl::value_desc("binary"), cl::Required,
33     cl::desc("Path of profiled binary, only one binary is supported."),
34     cl::cat(ProfGenCategory));
35 
36 extern cl::opt<bool> ShowDisassemblyOnly;
37 extern cl::opt<bool> ShowSourceLocations;
38 extern cl::opt<bool> SkipSymbolization;
39 
40 using namespace llvm;
41 using namespace sampleprof;
42 
43 // Validate the command line input.
44 static void validateCommandLine(StringRef BinaryPath,
45                                 cl::list<std::string> &PerfTraceFilenames) {
46   // Allow the invalid perfscript if we only use to show binary disassembly.
47   if (!ShowDisassemblyOnly) {
48     for (auto &File : PerfTraceFilenames) {
49       if (!llvm::sys::fs::exists(File)) {
50         std::string Msg = "Input perf script(" + File + ") doesn't exist!";
51         exitWithError(Msg);
52       }
53     }
54   }
55 
56   if (!llvm::sys::fs::exists(BinaryPath)) {
57     std::string Msg = "Input binary(" + BinaryPath.str() + ") doesn't exist!";
58     exitWithError(Msg);
59   }
60 
61   if (CSProfileGenerator::MaxCompressionSize < -1) {
62     exitWithError("Value of --compress-recursion should >= -1");
63   }
64   if (ShowSourceLocations && !ShowDisassemblyOnly) {
65     exitWithError("--show-source-locations should work together with "
66                   "--show-disassembly-only!");
67   }
68 }
69 
70 int main(int argc, const char *argv[]) {
71   InitLLVM X(argc, argv);
72 
73   // Initialize targets and assembly printers/parsers.
74   InitializeAllTargetInfos();
75   InitializeAllTargetMCs();
76   InitializeAllDisassemblers();
77 
78   cl::HideUnrelatedOptions({&ProfGenCategory, &getColorCategory()});
79   cl::ParseCommandLineOptions(argc, argv, "llvm SPGO profile generator\n");
80   validateCommandLine(BinaryPath, PerfTraceFilenames);
81 
82   // Load symbols and disassemble the code of a given binary.
83   std::unique_ptr<ProfiledBinary> Binary =
84       std::make_unique<ProfiledBinary>(BinaryPath);
85   if (ShowDisassemblyOnly)
86     return EXIT_SUCCESS;
87 
88   // Parse perf events and samples
89   std::unique_ptr<PerfReaderBase> Reader =
90       PerfReaderBase::create(Binary.get(), PerfTraceFilenames);
91   Reader->parsePerfTraces(PerfTraceFilenames);
92 
93   if (SkipSymbolization)
94     return EXIT_SUCCESS;
95 
96   // TBD
97   if (Reader->getPerfScriptType() == PERF_LBR) {
98     WithColor::warning() << "Currently LBR only perf script is not supported!";
99     return EXIT_SUCCESS;
100   }
101 
102   std::unique_ptr<ProfileGenerator> Generator = ProfileGenerator::create(
103       Binary.get(), Reader->getSampleCounters(), Reader->getPerfScriptType());
104   Generator->generateProfile();
105   Generator->write();
106 
107   return EXIT_SUCCESS;
108 }
109