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