xref: /llvm-project/llvm/tools/llvm-profgen/llvm-profgen.cpp (revision 516e301752560311d2cd8c2b549493eb0f98d01b)
11f05b1a9Swlei //===- llvm-profgen.cpp - LLVM SPGO profile generation tool -----*- C++ -*-===//
2a94fa862Swlei //
3a94fa862Swlei // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4a94fa862Swlei // See https://llvm.org/LICENSE.txt for license information.
5a94fa862Swlei // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a94fa862Swlei //
7a94fa862Swlei //===----------------------------------------------------------------------===//
8a94fa862Swlei //
9a94fa862Swlei // llvm-profgen generates SPGO profiles from perf script ouput.
10a94fa862Swlei //
11a94fa862Swlei //===----------------------------------------------------------------------===//
12a94fa862Swlei 
13a94fa862Swlei #include "ErrorHandling.h"
14a94fa862Swlei #include "PerfReader.h"
151f05b1a9Swlei #include "ProfileGenerator.h"
16a94fa862Swlei #include "ProfiledBinary.h"
17db29f437Sserge-sans-paille #include "llvm/DebugInfo/Symbolize/SymbolizableModule.h"
18a94fa862Swlei #include "llvm/Support/CommandLine.h"
199af46710Swlei #include "llvm/Support/FileSystem.h"
20a94fa862Swlei #include "llvm/Support/InitLLVM.h"
2132221694Swlei #include "llvm/Support/TargetSelect.h"
22*516e3017SSteven Wu #include "llvm/Support/VirtualFileSystem.h"
23a94fa862Swlei 
24d16f1542STimm Bäder static cl::OptionCategory ProfGenCategory("ProfGen Options");
25d16f1542STimm Bäder 
26a5f411b7Swlei static cl::opt<std::string> PerfScriptFilename(
27557efc9aSFangrui Song     "perfscript", cl::value_desc("perfscript"),
28a94fa862Swlei     cl::desc("Path of perf-script trace created by Linux perf tool with "
29d16f1542STimm Bäder              "`script` command(the raw perf.data should be profiled with -b)"),
30d16f1542STimm Bäder     cl::cat(ProfGenCategory));
31a5f411b7Swlei static cl::alias PSA("ps", cl::desc("Alias for --perfscript"),
32a5f411b7Swlei                      cl::aliasopt(PerfScriptFilename));
33a94fa862Swlei 
34941191aaSWenlei He static cl::opt<std::string> PerfDataFilename(
35c136d858Swlei     "perfdata", cl::value_desc("perfdata"),
36941191aaSWenlei He     cl::desc("Path of raw perf data created by Linux perf tool (it should be "
37941191aaSWenlei He              "profiled with -b)"),
38941191aaSWenlei He     cl::cat(ProfGenCategory));
39a5f411b7Swlei static cl::alias PDA("pd", cl::desc("Alias for --perfdata"),
40a5f411b7Swlei                      cl::aliasopt(PerfDataFilename));
41a5f411b7Swlei 
42a5f411b7Swlei static cl::opt<std::string> UnsymbolizedProfFilename(
43a5f411b7Swlei     "unsymbolized-profile", cl::value_desc("unsymbolized profile"),
44a5f411b7Swlei     cl::desc("Path of the unsymbolized profile created by "
45a5f411b7Swlei              "`llvm-profgen` with `--skip-symbolization`"),
46a5f411b7Swlei     cl::cat(ProfGenCategory));
47a5f411b7Swlei static cl::alias UPA("up", cl::desc("Alias for --unsymbolized-profile"),
48a5f411b7Swlei                      cl::aliasopt(UnsymbolizedProfFilename));
49941191aaSWenlei He 
5036c7d79dSFangrui Song static cl::opt<std::string> SampleProfFilename(
5136c7d79dSFangrui Song     "llvm-sample-profile", cl::value_desc("llvm sample profile"),
5236c7d79dSFangrui Song     cl::desc("Path of the LLVM sample profile"), cl::cat(ProfGenCategory));
53937924ebSHongtao Yu 
54937924ebSHongtao Yu static cl::opt<std::string>
556693c562Swlei     BinaryPath("binary", cl::value_desc("binary"), cl::Required,
566693c562Swlei                cl::desc("Path of profiled executable binary."),
576693c562Swlei                cl::cat(ProfGenCategory));
586693c562Swlei 
5917f6cba3SWenlei He static cl::opt<uint32_t>
60557efc9aSFangrui Song     ProcessId("pid", cl::value_desc("process Id"), cl::init(0),
6117f6cba3SWenlei He               cl::desc("Process Id for the profiled executable binary."),
6217f6cba3SWenlei He               cl::cat(ProfGenCategory));
6317f6cba3SWenlei He 
646693c562Swlei static cl::opt<std::string> DebugBinPath(
65557efc9aSFangrui Song     "debug-binary", cl::value_desc("debug-binary"),
666693c562Swlei     cl::desc("Path of debug info binary, llvm-profgen will load the DWARF info "
676693c562Swlei              "from it instead of the executable binary."),
68d16f1542STimm Bäder     cl::cat(ProfGenCategory));
69a94fa862Swlei 
70426e326aSwlei extern cl::opt<bool> ShowDisassemblyOnly;
719af46710Swlei extern cl::opt<bool> ShowSourceLocations;
72964053d5Swlei extern cl::opt<bool> SkipSymbolization;
73426e326aSwlei 
74a94fa862Swlei using namespace llvm;
75a94fa862Swlei using namespace sampleprof;
76a94fa862Swlei 
779af46710Swlei // Validate the command line input.
validateCommandLine()78941191aaSWenlei He static void validateCommandLine() {
79a5f411b7Swlei   // Allow the missing perfscript if we only use to show binary disassembly.
80941191aaSWenlei He   if (!ShowDisassemblyOnly) {
81a5f411b7Swlei     // Validate input profile is provided only once
82c136d858Swlei     bool HasPerfData = PerfDataFilename.getNumOccurrences() > 0;
83c136d858Swlei     bool HasPerfScript = PerfScriptFilename.getNumOccurrences() > 0;
84c136d858Swlei     bool HasUnsymbolizedProfile =
85c136d858Swlei         UnsymbolizedProfFilename.getNumOccurrences() > 0;
86c136d858Swlei     bool HasSampleProfile = SampleProfFilename.getNumOccurrences() > 0;
87937924ebSHongtao Yu     uint16_t S =
88937924ebSHongtao Yu         HasPerfData + HasPerfScript + HasUnsymbolizedProfile + HasSampleProfile;
89a5f411b7Swlei     if (S != 1) {
90941191aaSWenlei He       std::string Msg =
91a5f411b7Swlei           S > 1
92a5f411b7Swlei               ? "`--perfscript`, `--perfdata` and `--unsymbolized-profile` "
93a5f411b7Swlei                 "cannot be used together."
94a5f411b7Swlei               : "Perf input file is missing, please use one of `--perfscript`, "
95a5f411b7Swlei                 "`--perfdata` and `--unsymbolized-profile` for the input.";
96941191aaSWenlei He       exitWithError(Msg);
97941191aaSWenlei He     }
98941191aaSWenlei He 
99a5f411b7Swlei     auto CheckFileExists = [](bool H, StringRef File) {
100a5f411b7Swlei       if (H && !llvm::sys::fs::exists(File)) {
101a5f411b7Swlei         std::string Msg = "Input perf file(" + File.str() + ") doesn't exist.";
102941191aaSWenlei He         exitWithError(Msg);
1039af46710Swlei       }
104a5f411b7Swlei     };
105a5f411b7Swlei 
106a5f411b7Swlei     CheckFileExists(HasPerfData, PerfDataFilename);
107a5f411b7Swlei     CheckFileExists(HasPerfScript, PerfScriptFilename);
108a5f411b7Swlei     CheckFileExists(HasUnsymbolizedProfile, UnsymbolizedProfFilename);
109937924ebSHongtao Yu     CheckFileExists(HasSampleProfile, SampleProfFilename);
1109af46710Swlei   }
1119af46710Swlei 
1129af46710Swlei   if (!llvm::sys::fs::exists(BinaryPath)) {
113941191aaSWenlei He     std::string Msg = "Input binary(" + BinaryPath + ") doesn't exist.";
1149af46710Swlei     exitWithError(Msg);
1159af46710Swlei   }
1169af46710Swlei 
1179af46710Swlei   if (CSProfileGenerator::MaxCompressionSize < -1) {
1189af46710Swlei     exitWithError("Value of --compress-recursion should >= -1");
1199af46710Swlei   }
1209af46710Swlei   if (ShowSourceLocations && !ShowDisassemblyOnly) {
1219af46710Swlei     exitWithError("--show-source-locations should work together with "
1229af46710Swlei                   "--show-disassembly-only!");
1239af46710Swlei   }
1249af46710Swlei }
1259af46710Swlei 
getPerfInputFile()126a5f411b7Swlei static PerfInputFile getPerfInputFile() {
127a5f411b7Swlei   PerfInputFile File;
128a5f411b7Swlei   if (PerfDataFilename.getNumOccurrences()) {
129a5f411b7Swlei     File.InputFile = PerfDataFilename;
130a5f411b7Swlei     File.Format = PerfFormat::PerfData;
131a5f411b7Swlei   } else if (PerfScriptFilename.getNumOccurrences()) {
132a5f411b7Swlei     File.InputFile = PerfScriptFilename;
133a5f411b7Swlei     File.Format = PerfFormat::PerfScript;
134a5f411b7Swlei   } else if (UnsymbolizedProfFilename.getNumOccurrences()) {
135a5f411b7Swlei     File.InputFile = UnsymbolizedProfFilename;
136a5f411b7Swlei     File.Format = PerfFormat::UnsymbolizedProfile;
137a5f411b7Swlei   }
138a5f411b7Swlei   return File;
139a5f411b7Swlei }
140a5f411b7Swlei 
main(int argc,const char * argv[])141a94fa862Swlei int main(int argc, const char *argv[]) {
142a94fa862Swlei   InitLLVM X(argc, argv);
143a94fa862Swlei 
14432221694Swlei   // Initialize targets and assembly printers/parsers.
14532221694Swlei   InitializeAllTargetInfos();
14632221694Swlei   InitializeAllTargetMCs();
14732221694Swlei   InitializeAllDisassemblers();
14832221694Swlei 
149d16f1542STimm Bäder   cl::HideUnrelatedOptions({&ProfGenCategory, &getColorCategory()});
1504ad0cfd4STom Stellard   cl::ParseCommandLineOptions(argc, argv, "llvm SPGO profile generator\n");
151941191aaSWenlei He   validateCommandLine();
1524ad0cfd4STom Stellard 
1539af46710Swlei   // Load symbols and disassemble the code of a given binary.
1549af46710Swlei   std::unique_ptr<ProfiledBinary> Binary =
1556693c562Swlei       std::make_unique<ProfiledBinary>(BinaryPath, DebugBinPath);
1569af46710Swlei   if (ShowDisassemblyOnly)
157426e326aSwlei     return EXIT_SUCCESS;
1586da9241aSwlei 
159937924ebSHongtao Yu   if (SampleProfFilename.getNumOccurrences()) {
160937924ebSHongtao Yu     LLVMContext Context;
161*516e3017SSteven Wu     auto FS = vfs::getRealFileSystem();
162*516e3017SSteven Wu     auto ReaderOrErr =
163*516e3017SSteven Wu         SampleProfileReader::create(SampleProfFilename, Context, *FS);
164937924ebSHongtao Yu     std::unique_ptr<sampleprof::SampleProfileReader> Reader =
165937924ebSHongtao Yu         std::move(ReaderOrErr.get());
166937924ebSHongtao Yu     Reader->read();
167937924ebSHongtao Yu     std::unique_ptr<ProfileGeneratorBase> Generator =
168aa58b7b1Swlei         ProfileGeneratorBase::create(Binary.get(), Reader->getProfiles(),
169e36786d1SHongtao Yu                                      Reader->profileIsCS());
170937924ebSHongtao Yu     Generator->generateProfile();
171937924ebSHongtao Yu     Generator->write();
172937924ebSHongtao Yu   } else {
173da2f5d0aSFangrui Song     std::optional<uint32_t> PIDFilter;
17417f6cba3SWenlei He     if (ProcessId.getNumOccurrences())
17517f6cba3SWenlei He       PIDFilter = ProcessId;
176a5f411b7Swlei     PerfInputFile PerfFile = getPerfInputFile();
1776da9241aSwlei     std::unique_ptr<PerfReaderBase> Reader =
17817f6cba3SWenlei He         PerfReaderBase::create(Binary.get(), PerfFile, PIDFilter);
179a5f411b7Swlei     // Parse perf events and samples
180941191aaSWenlei He     Reader->parsePerfTraces();
181a94fa862Swlei 
182964053d5Swlei     if (SkipSymbolization)
183964053d5Swlei       return EXIT_SUCCESS;
184964053d5Swlei 
185d5f20130Swlei     std::unique_ptr<ProfileGeneratorBase> Generator =
186937924ebSHongtao Yu         ProfileGeneratorBase::create(Binary.get(), &Reader->getSampleCounters(),
187e36786d1SHongtao Yu                                      Reader->profileIsCS());
1881f05b1a9Swlei     Generator->generateProfile();
1891f05b1a9Swlei     Generator->write();
190937924ebSHongtao Yu   }
1911f05b1a9Swlei 
192a94fa862Swlei   return EXIT_SUCCESS;
193a94fa862Swlei }
194