1 //===- llvm-profgen.cpp - LLVM SPGO profile generation tool -----*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // llvm-profgen generates SPGO profiles from perf script ouput.
11 //===----------------------------------------------------------------------===//
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"
22 static cl::OptionCategory
ProfGenCategory("ProfGen Options");
24 static cl::opt
<std::string
> PerfScriptFilename(
25 "perfscript", cl::value_desc("perfscript"), cl::ZeroOrMore
,
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 static cl::alias
PSA("ps", cl::desc("Alias for --perfscript"),
31 cl::aliasopt(PerfScriptFilename
));
33 static cl::opt
<std::string
> PerfDataFilename(
34 "perfdata", cl::value_desc("perfdata"), cl::ZeroOrMore
,
35 llvm::cl::MiscFlags::CommaSeparated
,
36 cl::desc("Path of raw perf data created by Linux perf tool (it should be "
38 cl::cat(ProfGenCategory
));
39 static cl::alias
PDA("pd", cl::desc("Alias for --perfdata"),
40 cl::aliasopt(PerfDataFilename
));
42 static cl::opt
<std::string
> UnsymbolizedProfFilename(
43 "unsymbolized-profile", cl::value_desc("unsymbolized profile"),
44 cl::ZeroOrMore
, 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
));
51 static cl::opt
<std::string
> BinaryPath(
52 "binary", cl::value_desc("binary"), cl::Required
,
53 cl::desc("Path of profiled binary, only one binary is supported."),
54 cl::cat(ProfGenCategory
));
56 extern cl::opt
<bool> ShowDisassemblyOnly
;
57 extern cl::opt
<bool> ShowSourceLocations
;
58 extern cl::opt
<bool> SkipSymbolization
;
61 using namespace sampleprof
;
63 // Validate the command line input.
64 static void validateCommandLine() {
65 // Allow the missing perfscript if we only use to show binary disassembly.
66 if (!ShowDisassemblyOnly
) {
67 // Validate input profile is provided only once
68 uint16_t HasPerfData
= PerfDataFilename
.getNumOccurrences();
69 uint16_t HasPerfScript
= PerfScriptFilename
.getNumOccurrences();
70 uint16_t HasUnsymbolizedProfile
=
71 UnsymbolizedProfFilename
.getNumOccurrences();
72 uint16_t S
= HasPerfData
+ HasPerfScript
+ HasUnsymbolizedProfile
;
76 ? "`--perfscript`, `--perfdata` and `--unsymbolized-profile` "
77 "cannot be used together."
78 : "Perf input file is missing, please use one of `--perfscript`, "
79 "`--perfdata` and `--unsymbolized-profile` for the input.";
83 auto CheckFileExists
= [](bool H
, StringRef File
) {
84 if (H
&& !llvm::sys::fs::exists(File
)) {
85 std::string Msg
= "Input perf file(" + File
.str() + ") doesn't exist.";
90 CheckFileExists(HasPerfData
, PerfDataFilename
);
91 CheckFileExists(HasPerfScript
, PerfScriptFilename
);
92 CheckFileExists(HasUnsymbolizedProfile
, UnsymbolizedProfFilename
);
95 if (!llvm::sys::fs::exists(BinaryPath
)) {
96 std::string Msg
= "Input binary(" + BinaryPath
+ ") doesn't exist.";
100 if (CSProfileGenerator::MaxCompressionSize
< -1) {
101 exitWithError("Value of --compress-recursion should >= -1");
103 if (ShowSourceLocations
&& !ShowDisassemblyOnly
) {
104 exitWithError("--show-source-locations should work together with "
105 "--show-disassembly-only!");
109 static PerfInputFile
getPerfInputFile() {
111 if (PerfDataFilename
.getNumOccurrences()) {
112 File
.InputFile
= PerfDataFilename
;
113 File
.Format
= PerfFormat::PerfData
;
114 } else if (PerfScriptFilename
.getNumOccurrences()) {
115 File
.InputFile
= PerfScriptFilename
;
116 File
.Format
= PerfFormat::PerfScript
;
117 } else if (UnsymbolizedProfFilename
.getNumOccurrences()) {
118 File
.InputFile
= UnsymbolizedProfFilename
;
119 File
.Format
= PerfFormat::UnsymbolizedProfile
;
124 int main(int argc
, const char *argv
[]) {
125 InitLLVM
X(argc
, argv
);
127 // Initialize targets and assembly printers/parsers.
128 InitializeAllTargetInfos();
129 InitializeAllTargetMCs();
130 InitializeAllDisassemblers();
132 cl::HideUnrelatedOptions({&ProfGenCategory
, &getColorCategory()});
133 cl::ParseCommandLineOptions(argc
, argv
, "llvm SPGO profile generator\n");
134 validateCommandLine();
136 // Load symbols and disassemble the code of a given binary.
137 std::unique_ptr
<ProfiledBinary
> Binary
=
138 std::make_unique
<ProfiledBinary
>(BinaryPath
);
139 if (ShowDisassemblyOnly
)
142 PerfInputFile PerfFile
= getPerfInputFile();
143 std::unique_ptr
<PerfReaderBase
> Reader
=
144 PerfReaderBase::create(Binary
.get(), PerfFile
);
145 // Parse perf events and samples
146 Reader
->parsePerfTraces();
148 if (SkipSymbolization
)
151 std::unique_ptr
<ProfileGeneratorBase
> Generator
=
152 ProfileGeneratorBase::create(Binary
.get(), Reader
->getSampleCounters(),
153 Reader
->profileIsCSFlat());
154 Generator
->generateProfile();