xref: /llvm-project/bolt/lib/Profile/DataAggregator.cpp (revision 835a9c2801a62c2b7b35d7c2985eec32f518dbf5)
12f09f445SMaksim Panchenko //===- bolt/Profile/DataAggregator.cpp - Perf data aggregator -------------===//
2a34c753fSRafael Auler //
3a34c753fSRafael Auler // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4a34c753fSRafael Auler // See https://llvm.org/LICENSE.txt for license information.
5a34c753fSRafael Auler // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a34c753fSRafael Auler //
7a34c753fSRafael Auler //===----------------------------------------------------------------------===//
8a34c753fSRafael Auler //
9a34c753fSRafael Auler // This family of functions reads profile data written by perf record,
10a34c753fSRafael Auler // aggregate it and then write it back to an output file.
11a34c753fSRafael Auler //
12a34c753fSRafael Auler //===----------------------------------------------------------------------===//
13a34c753fSRafael Auler 
14a34c753fSRafael Auler #include "bolt/Profile/DataAggregator.h"
15a34c753fSRafael Auler #include "bolt/Core/BinaryContext.h"
16a34c753fSRafael Auler #include "bolt/Core/BinaryFunction.h"
17a34c753fSRafael Auler #include "bolt/Profile/BoltAddressTranslation.h"
18a34c753fSRafael Auler #include "bolt/Profile/Heatmap.h"
19a34c753fSRafael Auler #include "bolt/Utils/CommandLineOpts.h"
20a34c753fSRafael Auler #include "bolt/Utils/Utils.h"
21f119a248SAmir Ayupov #include "llvm/ADT/STLExtras.h"
22ae585be1SRafael Auler #include "llvm/ADT/ScopeExit.h"
23a34c753fSRafael Auler #include "llvm/Support/CommandLine.h"
24a34c753fSRafael Auler #include "llvm/Support/Debug.h"
25290e4823Sserge-sans-paille #include "llvm/Support/Errc.h"
26a34c753fSRafael Auler #include "llvm/Support/FileSystem.h"
27a34c753fSRafael Auler #include "llvm/Support/Process.h"
28a34c753fSRafael Auler #include "llvm/Support/Program.h"
29a34c753fSRafael Auler #include "llvm/Support/Regex.h"
30a34c753fSRafael Auler #include "llvm/Support/Timer.h"
31a34c753fSRafael Auler #include "llvm/Support/raw_ostream.h"
32a34c753fSRafael Auler #include <map>
333c255f67SKrzysztof Parzyszek #include <optional>
34a34c753fSRafael Auler #include <unordered_map>
35d914486aSAmir Ayupov #include <utility>
36a34c753fSRafael Auler 
37a34c753fSRafael Auler #define DEBUG_TYPE "aggregator"
38a34c753fSRafael Auler 
39a34c753fSRafael Auler using namespace llvm;
40a34c753fSRafael Auler using namespace bolt;
41a34c753fSRafael Auler 
42a34c753fSRafael Auler namespace opts {
43a34c753fSRafael Auler 
44a34c753fSRafael Auler static cl::opt<bool>
45a34c753fSRafael Auler     BasicAggregation("nl",
46a34c753fSRafael Auler                      cl::desc("aggregate basic samples (without LBR info)"),
47a34c753fSRafael Auler                      cl::cat(AggregatorCategory));
48a34c753fSRafael Auler 
49a34c753fSRafael Auler static cl::opt<bool>
50a34c753fSRafael Auler FilterMemProfile("filter-mem-profile",
51a34c753fSRafael Auler   cl::desc("if processing a memory profile, filter out stack or heap accesses "
52a34c753fSRafael Auler            "that won't be useful for BOLT to reduce profile file size"),
53a34c753fSRafael Auler   cl::init(true),
54a34c753fSRafael Auler   cl::cat(AggregatorCategory));
55a34c753fSRafael Auler 
56a34c753fSRafael Auler static cl::opt<unsigned long long>
57a34c753fSRafael Auler FilterPID("pid",
58a34c753fSRafael Auler   cl::desc("only use samples from process with specified PID"),
59a34c753fSRafael Auler   cl::init(0),
60a34c753fSRafael Auler   cl::Optional,
61a34c753fSRafael Auler   cl::cat(AggregatorCategory));
62a34c753fSRafael Auler 
63a34c753fSRafael Auler static cl::opt<bool>
64a34c753fSRafael Auler IgnoreBuildID("ignore-build-id",
65a34c753fSRafael Auler   cl::desc("continue even if build-ids in input binary and perf.data mismatch"),
66a34c753fSRafael Auler   cl::init(false),
67a34c753fSRafael Auler   cl::cat(AggregatorCategory));
68a34c753fSRafael Auler 
69b92436efSFangrui Song static cl::opt<bool> IgnoreInterruptLBR(
70b92436efSFangrui Song     "ignore-interrupt-lbr",
71a34c753fSRafael Auler     cl::desc("ignore kernel interrupt LBR that happens asynchronously"),
72b92436efSFangrui Song     cl::init(true), cl::cat(AggregatorCategory));
73a34c753fSRafael Auler 
74a34c753fSRafael Auler static cl::opt<unsigned long long>
75a34c753fSRafael Auler MaxSamples("max-samples",
76a34c753fSRafael Auler   cl::init(-1ULL),
77a34c753fSRafael Auler   cl::desc("maximum number of samples to read from LBR profile"),
78a34c753fSRafael Auler   cl::Optional,
79a34c753fSRafael Auler   cl::Hidden,
80a34c753fSRafael Auler   cl::cat(AggregatorCategory));
81a34c753fSRafael Auler 
8239336fc0SAmir Ayupov extern cl::opt<opts::ProfileFormatKind> ProfileFormat;
8339336fc0SAmir Ayupov 
84661577b5SMaksim Panchenko cl::opt<bool> ReadPreAggregated(
85b92436efSFangrui Song     "pa", cl::desc("skip perf and read data from a pre-aggregated file format"),
86a34c753fSRafael Auler     cl::cat(AggregatorCategory));
87a34c753fSRafael Auler 
88a34c753fSRafael Auler static cl::opt<bool>
89a34c753fSRafael Auler TimeAggregator("time-aggr",
90a34c753fSRafael Auler   cl::desc("time BOLT aggregator"),
91a34c753fSRafael Auler   cl::init(false),
92a34c753fSRafael Auler   cl::ZeroOrMore,
93a34c753fSRafael Auler   cl::cat(AggregatorCategory));
94a34c753fSRafael Auler 
95a34c753fSRafael Auler static cl::opt<bool>
96a34c753fSRafael Auler     UseEventPC("use-event-pc",
97a34c753fSRafael Auler                cl::desc("use event PC in combination with LBR sampling"),
98a34c753fSRafael Auler                cl::cat(AggregatorCategory));
99a34c753fSRafael Auler 
100b92436efSFangrui Song static cl::opt<bool> WriteAutoFDOData(
101b92436efSFangrui Song     "autofdo", cl::desc("generate autofdo textual data instead of bolt data"),
102a34c753fSRafael Auler     cl::cat(AggregatorCategory));
103a34c753fSRafael Auler 
10440c2e0faSMaksim Panchenko } // namespace opts
105a34c753fSRafael Auler 
106a34c753fSRafael Auler namespace {
107a34c753fSRafael Auler 
108a34c753fSRafael Auler const char TimerGroupName[] = "aggregator";
109a34c753fSRafael Auler const char TimerGroupDesc[] = "Aggregator";
110a34c753fSRafael Auler 
111733dc3e5SRahman Lavaee std::vector<SectionNameAndRange> getTextSections(const BinaryContext *BC) {
112733dc3e5SRahman Lavaee   std::vector<SectionNameAndRange> sections;
113733dc3e5SRahman Lavaee   for (BinarySection &Section : BC->sections()) {
114733dc3e5SRahman Lavaee     if (!Section.isText())
115733dc3e5SRahman Lavaee       continue;
116733dc3e5SRahman Lavaee     if (Section.getSize() == 0)
117733dc3e5SRahman Lavaee       continue;
118733dc3e5SRahman Lavaee     sections.push_back(
119733dc3e5SRahman Lavaee         {Section.getName(), Section.getAddress(), Section.getEndAddress()});
120733dc3e5SRahman Lavaee   }
121d2c87699SAmir Ayupov   llvm::sort(sections,
122733dc3e5SRahman Lavaee              [](const SectionNameAndRange &A, const SectionNameAndRange &B) {
123733dc3e5SRahman Lavaee                return A.BeginAddress < B.BeginAddress;
124733dc3e5SRahman Lavaee              });
125733dc3e5SRahman Lavaee   return sections;
126733dc3e5SRahman Lavaee }
127a34c753fSRafael Auler }
128a34c753fSRafael Auler 
129a34c753fSRafael Auler constexpr uint64_t DataAggregator::KernelBaseAddr;
130a34c753fSRafael Auler 
13140c2e0faSMaksim Panchenko DataAggregator::~DataAggregator() { deleteTempFiles(); }
132a34c753fSRafael Auler 
133a34c753fSRafael Auler namespace {
134a34c753fSRafael Auler void deleteTempFile(const std::string &FileName) {
135def464aaSAmir Ayupov   if (std::error_code Errc = sys::fs::remove(FileName.c_str()))
13640c2e0faSMaksim Panchenko     errs() << "PERF2BOLT: failed to delete temporary file " << FileName
13740c2e0faSMaksim Panchenko            << " with error " << Errc.message() << "\n";
138a34c753fSRafael Auler }
139a34c753fSRafael Auler }
140a34c753fSRafael Auler 
141a34c753fSRafael Auler void DataAggregator::deleteTempFiles() {
142def464aaSAmir Ayupov   for (std::string &FileName : TempFiles)
143a34c753fSRafael Auler     deleteTempFile(FileName);
144a34c753fSRafael Auler   TempFiles.clear();
145a34c753fSRafael Auler }
146a34c753fSRafael Auler 
147a34c753fSRafael Auler void DataAggregator::findPerfExecutable() {
1483c255f67SKrzysztof Parzyszek   std::optional<std::string> PerfExecutable =
149a34c753fSRafael Auler       sys::Process::FindInEnvPath("PATH", "perf");
150a34c753fSRafael Auler   if (!PerfExecutable) {
151a34c753fSRafael Auler     outs() << "PERF2BOLT: No perf executable found!\n";
152a34c753fSRafael Auler     exit(1);
153a34c753fSRafael Auler   }
154a34c753fSRafael Auler   PerfPath = *PerfExecutable;
155a34c753fSRafael Auler }
156a34c753fSRafael Auler 
157a34c753fSRafael Auler void DataAggregator::start() {
15840c2e0faSMaksim Panchenko   outs() << "PERF2BOLT: Starting data aggregation job for " << Filename << "\n";
159a34c753fSRafael Auler 
160a34c753fSRafael Auler   // Don't launch perf for pre-aggregated files
161a34c753fSRafael Auler   if (opts::ReadPreAggregated)
162a34c753fSRafael Auler     return;
163a34c753fSRafael Auler 
164a34c753fSRafael Auler   findPerfExecutable();
165a34c753fSRafael Auler 
166def464aaSAmir Ayupov   if (opts::BasicAggregation)
167a34c753fSRafael Auler     launchPerfProcess("events without LBR",
168a34c753fSRafael Auler                       MainEventsPPI,
169a34c753fSRafael Auler                       "script -F pid,event,ip",
170a34c753fSRafael Auler                       /*Wait = */false);
171def464aaSAmir Ayupov   else
172a34c753fSRafael Auler     launchPerfProcess("branch events",
173a34c753fSRafael Auler                       MainEventsPPI,
174a34c753fSRafael Auler                       "script -F pid,ip,brstack",
175a34c753fSRafael Auler                       /*Wait = */false);
176a34c753fSRafael Auler 
177a34c753fSRafael Auler   // Note: we launch script for mem events regardless of the option, as the
178a34c753fSRafael Auler   //       command fails fairly fast if mem events were not collected.
179a34c753fSRafael Auler   launchPerfProcess("mem events",
180a34c753fSRafael Auler                     MemEventsPPI,
181a34c753fSRafael Auler                     "script -F pid,event,addr,ip",
182a34c753fSRafael Auler                     /*Wait = */false);
183a34c753fSRafael Auler 
184a34c753fSRafael Auler   launchPerfProcess("process events",
185a34c753fSRafael Auler                     MMapEventsPPI,
186a34c753fSRafael Auler                     "script --show-mmap-events",
187a34c753fSRafael Auler                     /*Wait = */false);
188a34c753fSRafael Auler 
189a34c753fSRafael Auler   launchPerfProcess("task events",
190a34c753fSRafael Auler                     TaskEventsPPI,
191a34c753fSRafael Auler                     "script --show-task-events",
192a34c753fSRafael Auler                     /*Wait = */false);
193a34c753fSRafael Auler }
194a34c753fSRafael Auler 
195a34c753fSRafael Auler void DataAggregator::abort() {
196a34c753fSRafael Auler   if (opts::ReadPreAggregated)
197a34c753fSRafael Auler     return;
198a34c753fSRafael Auler 
199a34c753fSRafael Auler   std::string Error;
200a34c753fSRafael Auler 
201a34c753fSRafael Auler   // Kill subprocesses in case they are not finished
202a34c753fSRafael Auler   sys::Wait(TaskEventsPPI.PI, 1, false, &Error);
203a34c753fSRafael Auler   sys::Wait(MMapEventsPPI.PI, 1, false, &Error);
204a34c753fSRafael Auler   sys::Wait(MainEventsPPI.PI, 1, false, &Error);
205a34c753fSRafael Auler   sys::Wait(MemEventsPPI.PI, 1, false, &Error);
206a34c753fSRafael Auler 
207a34c753fSRafael Auler   deleteTempFiles();
208a34c753fSRafael Auler 
209a34c753fSRafael Auler   exit(1);
210a34c753fSRafael Auler }
211a34c753fSRafael Auler 
212a34c753fSRafael Auler void DataAggregator::launchPerfProcess(StringRef Name, PerfProcessInfo &PPI,
213a34c753fSRafael Auler                                        const char *ArgsString, bool Wait) {
214a34c753fSRafael Auler   SmallVector<StringRef, 4> Argv;
215a34c753fSRafael Auler 
216a34c753fSRafael Auler   outs() << "PERF2BOLT: spawning perf job to read " << Name << '\n';
217a34c753fSRafael Auler   Argv.push_back(PerfPath.data());
218a34c753fSRafael Auler 
219a34c753fSRafael Auler   char *WritableArgsString = strdup(ArgsString);
220a34c753fSRafael Auler   char *Str = WritableArgsString;
221a34c753fSRafael Auler   do {
222a34c753fSRafael Auler     Argv.push_back(Str);
223a34c753fSRafael Auler     while (*Str && *Str != ' ')
224a34c753fSRafael Auler       ++Str;
225a34c753fSRafael Auler     if (!*Str)
226a34c753fSRafael Auler       break;
227a34c753fSRafael Auler     *Str++ = 0;
228a34c753fSRafael Auler   } while (true);
229a34c753fSRafael Auler 
230a34c753fSRafael Auler   Argv.push_back("-f");
231a34c753fSRafael Auler   Argv.push_back("-i");
232a34c753fSRafael Auler   Argv.push_back(Filename.c_str());
233a34c753fSRafael Auler 
234a34c753fSRafael Auler   if (std::error_code Errc =
235a34c753fSRafael Auler           sys::fs::createTemporaryFile("perf.script", "out", PPI.StdoutPath)) {
23640c2e0faSMaksim Panchenko     errs() << "PERF2BOLT: failed to create temporary file " << PPI.StdoutPath
23740c2e0faSMaksim Panchenko            << " with error " << Errc.message() << "\n";
238a34c753fSRafael Auler     exit(1);
239a34c753fSRafael Auler   }
240a34c753fSRafael Auler   TempFiles.push_back(PPI.StdoutPath.data());
241a34c753fSRafael Auler 
242a34c753fSRafael Auler   if (std::error_code Errc =
243a34c753fSRafael Auler           sys::fs::createTemporaryFile("perf.script", "err", PPI.StderrPath)) {
24440c2e0faSMaksim Panchenko     errs() << "PERF2BOLT: failed to create temporary file " << PPI.StderrPath
24540c2e0faSMaksim Panchenko            << " with error " << Errc.message() << "\n";
246a34c753fSRafael Auler     exit(1);
247a34c753fSRafael Auler   }
248a34c753fSRafael Auler   TempFiles.push_back(PPI.StderrPath.data());
249a34c753fSRafael Auler 
2501028b165SKazu Hirata   std::optional<StringRef> Redirects[] = {
251e324a80fSKazu Hirata       std::nullopt,                      // Stdin
252a34c753fSRafael Auler       StringRef(PPI.StdoutPath.data()),  // Stdout
253a34c753fSRafael Auler       StringRef(PPI.StderrPath.data())}; // Stderr
254a34c753fSRafael Auler 
255a34c753fSRafael Auler   LLVM_DEBUG({
256a34c753fSRafael Auler     dbgs() << "Launching perf: ";
257a34c753fSRafael Auler     for (StringRef Arg : Argv)
258a34c753fSRafael Auler       dbgs() << Arg << " ";
259a34c753fSRafael Auler     dbgs() << " 1> " << PPI.StdoutPath.data() << " 2> " << PPI.StderrPath.data()
260a34c753fSRafael Auler            << "\n";
261a34c753fSRafael Auler   });
262a34c753fSRafael Auler 
263def464aaSAmir Ayupov   if (Wait)
264a34c753fSRafael Auler     PPI.PI.ReturnCode = sys::ExecuteAndWait(PerfPath.data(), Argv,
265e324a80fSKazu Hirata                                             /*envp*/ std::nullopt, Redirects);
266def464aaSAmir Ayupov   else
267e324a80fSKazu Hirata     PPI.PI = sys::ExecuteNoWait(PerfPath.data(), Argv, /*envp*/ std::nullopt,
268a34c753fSRafael Auler                                 Redirects);
269a34c753fSRafael Auler 
270a34c753fSRafael Auler   free(WritableArgsString);
271a34c753fSRafael Auler }
272a34c753fSRafael Auler 
273a34c753fSRafael Auler void DataAggregator::processFileBuildID(StringRef FileBuildID) {
274a34c753fSRafael Auler   PerfProcessInfo BuildIDProcessInfo;
275a34c753fSRafael Auler   launchPerfProcess("buildid list",
276a34c753fSRafael Auler                     BuildIDProcessInfo,
277a34c753fSRafael Auler                     "buildid-list",
278a34c753fSRafael Auler                     /*Wait = */true);
279a34c753fSRafael Auler 
280a34c753fSRafael Auler   if (BuildIDProcessInfo.PI.ReturnCode != 0) {
281a34c753fSRafael Auler     ErrorOr<std::unique_ptr<MemoryBuffer>> MB =
282a34c753fSRafael Auler         MemoryBuffer::getFileOrSTDIN(BuildIDProcessInfo.StderrPath.data());
283a34c753fSRafael Auler     StringRef ErrBuf = (*MB)->getBuffer();
284a34c753fSRafael Auler 
285a34c753fSRafael Auler     errs() << "PERF-ERROR: return code " << BuildIDProcessInfo.PI.ReturnCode
286a34c753fSRafael Auler            << '\n';
287a34c753fSRafael Auler     errs() << ErrBuf;
288a34c753fSRafael Auler     return;
289a34c753fSRafael Auler   }
290a34c753fSRafael Auler 
291a34c753fSRafael Auler   ErrorOr<std::unique_ptr<MemoryBuffer>> MB =
292a34c753fSRafael Auler       MemoryBuffer::getFileOrSTDIN(BuildIDProcessInfo.StdoutPath.data());
293a34c753fSRafael Auler   if (std::error_code EC = MB.getError()) {
294a34c753fSRafael Auler     errs() << "Cannot open " << BuildIDProcessInfo.StdoutPath.data() << ": "
295a34c753fSRafael Auler            << EC.message() << "\n";
296a34c753fSRafael Auler     return;
297a34c753fSRafael Auler   }
298a34c753fSRafael Auler 
299d914486aSAmir Ayupov   FileBuf = std::move(*MB);
300a34c753fSRafael Auler   ParsingBuf = FileBuf->getBuffer();
301a34c753fSRafael Auler 
302*835a9c28SAmir Ayupov   std::optional<StringRef> FileName = getFileNameForBuildID(FileBuildID);
303a34c753fSRafael Auler   if (!FileName) {
304661577b5SMaksim Panchenko     if (hasAllBuildIDs()) {
305a34c753fSRafael Auler       errs() << "PERF2BOLT-ERROR: failed to match build-id from perf output. "
306a34c753fSRafael Auler                 "This indicates the input binary supplied for data aggregation "
307a34c753fSRafael Auler                 "is not the same recorded by perf when collecting profiling "
308a34c753fSRafael Auler                 "data, or there were no samples recorded for the binary. "
309a34c753fSRafael Auler                 "Use -ignore-build-id option to override.\n";
310def464aaSAmir Ayupov       if (!opts::IgnoreBuildID)
311a34c753fSRafael Auler         abort();
312661577b5SMaksim Panchenko     } else {
313661577b5SMaksim Panchenko       errs() << "PERF2BOLT-WARNING: build-id will not be checked because perf "
314661577b5SMaksim Panchenko                 "data was recorded without it\n";
315661577b5SMaksim Panchenko       return;
316661577b5SMaksim Panchenko     }
317a34c753fSRafael Auler   } else if (*FileName != llvm::sys::path::filename(BC->getFilename())) {
318a34c753fSRafael Auler     errs() << "PERF2BOLT-WARNING: build-id matched a different file name\n";
319a34c753fSRafael Auler     BuildIDBinaryName = std::string(*FileName);
320a34c753fSRafael Auler   } else {
321a34c753fSRafael Auler     outs() << "PERF2BOLT: matched build-id and file name\n";
322a34c753fSRafael Auler   }
323a34c753fSRafael Auler }
324a34c753fSRafael Auler 
325a34c753fSRafael Auler bool DataAggregator::checkPerfDataMagic(StringRef FileName) {
326a34c753fSRafael Auler   if (opts::ReadPreAggregated)
327a34c753fSRafael Auler     return true;
328a34c753fSRafael Auler 
329ae585be1SRafael Auler   Expected<sys::fs::file_t> FD = sys::fs::openNativeFileForRead(FileName);
3300f915826SMaksim Panchenko   if (!FD) {
3310f915826SMaksim Panchenko     consumeError(FD.takeError());
332a34c753fSRafael Auler     return false;
3330f915826SMaksim Panchenko   }
334a34c753fSRafael Auler 
335a34c753fSRafael Auler   char Buf[7] = {0, 0, 0, 0, 0, 0, 0};
336a34c753fSRafael Auler 
337ae585be1SRafael Auler   auto Close = make_scope_exit([&] { sys::fs::closeFile(*FD); });
338ae585be1SRafael Auler   Expected<size_t> BytesRead = sys::fs::readNativeFileSlice(
339ae585be1SRafael Auler       *FD, makeMutableArrayRef(Buf, sizeof(Buf)), 0);
3400f915826SMaksim Panchenko   if (!BytesRead) {
3410f915826SMaksim Panchenko     consumeError(BytesRead.takeError());
3420f915826SMaksim Panchenko     return false;
3430f915826SMaksim Panchenko   }
3440f915826SMaksim Panchenko 
3450f915826SMaksim Panchenko   if (*BytesRead != 7)
346a34c753fSRafael Auler     return false;
347a34c753fSRafael Auler 
348a34c753fSRafael Auler   if (strncmp(Buf, "PERFILE", 7) == 0)
349a34c753fSRafael Auler     return true;
350a34c753fSRafael Auler   return false;
351a34c753fSRafael Auler }
352a34c753fSRafael Auler 
353a34c753fSRafael Auler void DataAggregator::parsePreAggregated() {
354a34c753fSRafael Auler   std::string Error;
355a34c753fSRafael Auler 
356a34c753fSRafael Auler   ErrorOr<std::unique_ptr<MemoryBuffer>> MB =
357a34c753fSRafael Auler       MemoryBuffer::getFileOrSTDIN(Filename);
358a34c753fSRafael Auler   if (std::error_code EC = MB.getError()) {
359a34c753fSRafael Auler     errs() << "PERF2BOLT-ERROR: cannot open " << Filename << ": "
360a34c753fSRafael Auler            << EC.message() << "\n";
361a34c753fSRafael Auler     exit(1);
362a34c753fSRafael Auler   }
363a34c753fSRafael Auler 
364d914486aSAmir Ayupov   FileBuf = std::move(*MB);
365a34c753fSRafael Auler   ParsingBuf = FileBuf->getBuffer();
366a34c753fSRafael Auler   Col = 0;
367a34c753fSRafael Auler   Line = 1;
368a34c753fSRafael Auler   if (parsePreAggregatedLBRSamples()) {
369a34c753fSRafael Auler     errs() << "PERF2BOLT: failed to parse samples\n";
370a34c753fSRafael Auler     exit(1);
371a34c753fSRafael Auler   }
372a34c753fSRafael Auler }
373a34c753fSRafael Auler 
374a34c753fSRafael Auler std::error_code DataAggregator::writeAutoFDOData(StringRef OutputFilename) {
375a34c753fSRafael Auler   outs() << "PERF2BOLT: writing data for autofdo tools...\n";
37640c2e0faSMaksim Panchenko   NamedRegionTimer T("writeAutoFDO", "Processing branch events", TimerGroupName,
37740c2e0faSMaksim Panchenko                      TimerGroupDesc, opts::TimeAggregator);
378a34c753fSRafael Auler 
379a34c753fSRafael Auler   std::error_code EC;
380a34c753fSRafael Auler   raw_fd_ostream OutFile(OutputFilename, EC, sys::fs::OpenFlags::OF_None);
381a34c753fSRafael Auler   if (EC)
382a34c753fSRafael Auler     return EC;
383a34c753fSRafael Auler 
384a34c753fSRafael Auler   // Format:
385a34c753fSRafael Auler   // number of unique traces
386a34c753fSRafael Auler   // from_1-to_1:count_1
387a34c753fSRafael Auler   // from_2-to_2:count_2
388a34c753fSRafael Auler   // ......
389a34c753fSRafael Auler   // from_n-to_n:count_n
390a34c753fSRafael Auler   // number of unique sample addresses
391a34c753fSRafael Auler   // addr_1:count_1
392a34c753fSRafael Auler   // addr_2:count_2
393a34c753fSRafael Auler   // ......
394a34c753fSRafael Auler   // addr_n:count_n
395a34c753fSRafael Auler   // number of unique LBR entries
396a34c753fSRafael Auler   // src_1->dst_1:count_1
397a34c753fSRafael Auler   // src_2->dst_2:count_2
398a34c753fSRafael Auler   // ......
399a34c753fSRafael Auler   // src_n->dst_n:count_n
400a34c753fSRafael Auler 
401a34c753fSRafael Auler   const uint64_t FirstAllocAddress = this->BC->FirstAllocAddress;
402a34c753fSRafael Auler 
403a34c753fSRafael Auler   // AutoFDO addresses are relative to the first allocated loadable program
404a34c753fSRafael Auler   // segment
405a34c753fSRafael Auler   auto filterAddress = [&FirstAllocAddress](uint64_t Address) -> uint64_t {
406a34c753fSRafael Auler     if (Address < FirstAllocAddress)
407a34c753fSRafael Auler       return 0;
408a34c753fSRafael Auler     return Address - FirstAllocAddress;
409a34c753fSRafael Auler   };
410a34c753fSRafael Auler 
411a34c753fSRafael Auler   OutFile << FallthroughLBRs.size() << "\n";
412a34c753fSRafael Auler   for (const auto &AggrLBR : FallthroughLBRs) {
413a34c753fSRafael Auler     const Trace &Trace = AggrLBR.first;
414a34c753fSRafael Auler     const FTInfo &Info = AggrLBR.second;
415a34c753fSRafael Auler     OutFile << Twine::utohexstr(filterAddress(Trace.From)) << "-"
416a34c753fSRafael Auler             << Twine::utohexstr(filterAddress(Trace.To)) << ":"
417a34c753fSRafael Auler             << (Info.InternCount + Info.ExternCount) << "\n";
418a34c753fSRafael Auler   }
419a34c753fSRafael Auler 
420a34c753fSRafael Auler   OutFile << BasicSamples.size() << "\n";
421a34c753fSRafael Auler   for (const auto &Sample : BasicSamples) {
422a34c753fSRafael Auler     uint64_t PC = Sample.first;
423a34c753fSRafael Auler     uint64_t HitCount = Sample.second;
424a34c753fSRafael Auler     OutFile << Twine::utohexstr(filterAddress(PC)) << ":" << HitCount << "\n";
425a34c753fSRafael Auler   }
426a34c753fSRafael Auler 
427a34c753fSRafael Auler   OutFile << BranchLBRs.size() << "\n";
428a34c753fSRafael Auler   for (const auto &AggrLBR : BranchLBRs) {
429a34c753fSRafael Auler     const Trace &Trace = AggrLBR.first;
430a34c753fSRafael Auler     const BranchInfo &Info = AggrLBR.second;
431a34c753fSRafael Auler     OutFile << Twine::utohexstr(filterAddress(Trace.From)) << "->"
432a34c753fSRafael Auler             << Twine::utohexstr(filterAddress(Trace.To)) << ":"
433a34c753fSRafael Auler             << Info.TakenCount << "\n";
434a34c753fSRafael Auler   }
435a34c753fSRafael Auler 
436a34c753fSRafael Auler   outs() << "PERF2BOLT: wrote " << FallthroughLBRs.size() << " unique traces, "
437a34c753fSRafael Auler          << BasicSamples.size() << " sample addresses and " << BranchLBRs.size()
438a34c753fSRafael Auler          << " unique branches to " << OutputFilename << "\n";
439a34c753fSRafael Auler 
440a34c753fSRafael Auler   return std::error_code();
441a34c753fSRafael Auler }
442a34c753fSRafael Auler 
443a34c753fSRafael Auler void DataAggregator::filterBinaryMMapInfo() {
444a34c753fSRafael Auler   if (opts::FilterPID) {
445a34c753fSRafael Auler     auto MMapInfoIter = BinaryMMapInfo.find(opts::FilterPID);
446a34c753fSRafael Auler     if (MMapInfoIter != BinaryMMapInfo.end()) {
447a34c753fSRafael Auler       MMapInfo MMap = MMapInfoIter->second;
448a34c753fSRafael Auler       BinaryMMapInfo.clear();
449a34c753fSRafael Auler       BinaryMMapInfo.insert(std::make_pair(MMap.PID, MMap));
450a34c753fSRafael Auler     } else {
451a34c753fSRafael Auler       if (errs().has_colors())
452a34c753fSRafael Auler         errs().changeColor(raw_ostream::RED);
453a34c753fSRafael Auler       errs() << "PERF2BOLT-ERROR: could not find a profile matching PID \""
45440c2e0faSMaksim Panchenko              << opts::FilterPID << "\""
45540c2e0faSMaksim Panchenko              << " for binary \"" << BC->getFilename() << "\".";
456a34c753fSRafael Auler       assert(!BinaryMMapInfo.empty() && "No memory map for matching binary");
457a34c753fSRafael Auler       errs() << " Profile for the following process is available:\n";
458def464aaSAmir Ayupov       for (std::pair<const uint64_t, MMapInfo> &MMI : BinaryMMapInfo)
459a34c753fSRafael Auler         outs() << "  " << MMI.second.PID
460a34c753fSRafael Auler                << (MMI.second.Forked ? " (forked)\n" : "\n");
461def464aaSAmir Ayupov 
462a34c753fSRafael Auler       if (errs().has_colors())
463a34c753fSRafael Auler         errs().resetColor();
464a34c753fSRafael Auler 
465a34c753fSRafael Auler       exit(1);
466a34c753fSRafael Auler     }
467a34c753fSRafael Auler   }
468a34c753fSRafael Auler }
469a34c753fSRafael Auler 
470a34c753fSRafael Auler Error DataAggregator::preprocessProfile(BinaryContext &BC) {
471a34c753fSRafael Auler   this->BC = &BC;
472a34c753fSRafael Auler 
473a34c753fSRafael Auler   if (opts::ReadPreAggregated) {
474a34c753fSRafael Auler     parsePreAggregated();
475a34c753fSRafael Auler     return Error::success();
476a34c753fSRafael Auler   }
477a34c753fSRafael Auler 
478a34c753fSRafael Auler   if (Optional<StringRef> FileBuildID = BC.getFileBuildID()) {
479a34c753fSRafael Auler     outs() << "BOLT-INFO: binary build-id is:     " << *FileBuildID << "\n";
480a34c753fSRafael Auler     processFileBuildID(*FileBuildID);
481a34c753fSRafael Auler   } else {
482a34c753fSRafael Auler     errs() << "BOLT-WARNING: build-id will not be checked because we could "
483a34c753fSRafael Auler               "not read one from input binary\n";
484a34c753fSRafael Auler   }
485a34c753fSRafael Auler 
486a34c753fSRafael Auler   auto prepareToParse = [&](StringRef Name, PerfProcessInfo &Process) {
487a34c753fSRafael Auler     std::string Error;
488a34c753fSRafael Auler     outs() << "PERF2BOLT: waiting for perf " << Name
489a34c753fSRafael Auler            << " collection to finish...\n";
490a34c753fSRafael Auler     sys::ProcessInfo PI = sys::Wait(Process.PI, 0, true, &Error);
491a34c753fSRafael Auler 
492a34c753fSRafael Auler     if (!Error.empty()) {
493a34c753fSRafael Auler       errs() << "PERF-ERROR: " << PerfPath << ": " << Error << "\n";
494a34c753fSRafael Auler       deleteTempFiles();
495a34c753fSRafael Auler       exit(1);
496a34c753fSRafael Auler     }
497a34c753fSRafael Auler 
498a34c753fSRafael Auler     if (PI.ReturnCode != 0) {
499a34c753fSRafael Auler       ErrorOr<std::unique_ptr<MemoryBuffer>> ErrorMB =
500a34c753fSRafael Auler           MemoryBuffer::getFileOrSTDIN(Process.StderrPath.data());
501a34c753fSRafael Auler       StringRef ErrBuf = (*ErrorMB)->getBuffer();
502a34c753fSRafael Auler 
503a34c753fSRafael Auler       errs() << "PERF-ERROR: return code " << PI.ReturnCode << "\n";
504a34c753fSRafael Auler       errs() << ErrBuf;
505a34c753fSRafael Auler       deleteTempFiles();
506a34c753fSRafael Auler       exit(1);
507a34c753fSRafael Auler     }
508a34c753fSRafael Auler 
509a34c753fSRafael Auler     ErrorOr<std::unique_ptr<MemoryBuffer>> MB =
510a34c753fSRafael Auler         MemoryBuffer::getFileOrSTDIN(Process.StdoutPath.data());
511a34c753fSRafael Auler     if (std::error_code EC = MB.getError()) {
512a34c753fSRafael Auler       errs() << "Cannot open " << Process.StdoutPath.data() << ": "
513a34c753fSRafael Auler              << EC.message() << "\n";
514a34c753fSRafael Auler       deleteTempFiles();
515a34c753fSRafael Auler       exit(1);
516a34c753fSRafael Auler     }
517a34c753fSRafael Auler 
518d914486aSAmir Ayupov     FileBuf = std::move(*MB);
519a34c753fSRafael Auler     ParsingBuf = FileBuf->getBuffer();
520a34c753fSRafael Auler     Col = 0;
521a34c753fSRafael Auler     Line = 1;
522a34c753fSRafael Auler   };
523a34c753fSRafael Auler 
524a34c753fSRafael Auler   if (opts::LinuxKernelMode) {
525a34c753fSRafael Auler     // Current MMap parsing logic does not work with linux kernel.
526a34c753fSRafael Auler     // MMap entries for linux kernel uses PERF_RECORD_MMAP
527a34c753fSRafael Auler     // format instead of typical PERF_RECORD_MMAP2 format.
528a34c753fSRafael Auler     // Since linux kernel address mapping is absolute (same as
529a34c753fSRafael Auler     // in the ELF file), we avoid parsing MMap in linux kernel mode.
530a34c753fSRafael Auler     // While generating optimized linux kernel binary, we may need
531a34c753fSRafael Auler     // to parse MMap entries.
532a34c753fSRafael Auler 
533a34c753fSRafael Auler     // In linux kernel mode, we analyze and optimize
534a34c753fSRafael Auler     // all linux kernel binary instructions, irrespective
535a34c753fSRafael Auler     // of whether they are due to system calls or due to
536a34c753fSRafael Auler     // interrupts. Therefore, we cannot ignore interrupt
537a34c753fSRafael Auler     // in Linux kernel mode.
538a34c753fSRafael Auler     opts::IgnoreInterruptLBR = false;
539a34c753fSRafael Auler   } else {
540a34c753fSRafael Auler     prepareToParse("mmap events", MMapEventsPPI);
541def464aaSAmir Ayupov     if (parseMMapEvents())
542a34c753fSRafael Auler       errs() << "PERF2BOLT: failed to parse mmap events\n";
543a34c753fSRafael Auler   }
544a34c753fSRafael Auler 
545a34c753fSRafael Auler   prepareToParse("task events", TaskEventsPPI);
546def464aaSAmir Ayupov   if (parseTaskEvents())
547a34c753fSRafael Auler     errs() << "PERF2BOLT: failed to parse task events\n";
548a34c753fSRafael Auler 
549a34c753fSRafael Auler   filterBinaryMMapInfo();
550a34c753fSRafael Auler   prepareToParse("events", MainEventsPPI);
551a34c753fSRafael Auler 
552a34c753fSRafael Auler   if (opts::HeatmapMode) {
553a34c753fSRafael Auler     if (std::error_code EC = printLBRHeatMap()) {
554a34c753fSRafael Auler       errs() << "ERROR: failed to print heat map: " << EC.message() << '\n';
555a34c753fSRafael Auler       exit(1);
556a34c753fSRafael Auler     }
557a34c753fSRafael Auler     exit(0);
558a34c753fSRafael Auler   }
559a34c753fSRafael Auler 
560a34c753fSRafael Auler   if ((!opts::BasicAggregation && parseBranchEvents()) ||
561def464aaSAmir Ayupov       (opts::BasicAggregation && parseBasicEvents()))
562a34c753fSRafael Auler     errs() << "PERF2BOLT: failed to parse samples\n";
563a34c753fSRafael Auler 
564a34c753fSRafael Auler   // We can finish early if the goal is just to generate data for autofdo
565a34c753fSRafael Auler   if (opts::WriteAutoFDOData) {
566def464aaSAmir Ayupov     if (std::error_code EC = writeAutoFDOData(opts::OutputFilename))
567a34c753fSRafael Auler       errs() << "Error writing autofdo data to file: " << EC.message() << "\n";
568def464aaSAmir Ayupov 
569a34c753fSRafael Auler     deleteTempFiles();
570a34c753fSRafael Auler     exit(0);
571a34c753fSRafael Auler   }
572a34c753fSRafael Auler 
573a34c753fSRafael Auler   // Special handling for memory events
574a34c753fSRafael Auler   std::string Error;
575a34c753fSRafael Auler   sys::ProcessInfo PI = sys::Wait(MemEventsPPI.PI, 0, true, &Error);
576a34c753fSRafael Auler   if (PI.ReturnCode != 0) {
577a34c753fSRafael Auler     ErrorOr<std::unique_ptr<MemoryBuffer>> MB =
578a34c753fSRafael Auler         MemoryBuffer::getFileOrSTDIN(MemEventsPPI.StderrPath.data());
579a34c753fSRafael Auler     StringRef ErrBuf = (*MB)->getBuffer();
580a34c753fSRafael Auler 
581a34c753fSRafael Auler     deleteTempFiles();
582a34c753fSRafael Auler 
583a34c753fSRafael Auler     Regex NoData("Samples for '.*' event do not have ADDR attribute set. "
584a34c753fSRafael Auler                  "Cannot print 'addr' field.");
585a34c753fSRafael Auler     if (!NoData.match(ErrBuf)) {
586a34c753fSRafael Auler       errs() << "PERF-ERROR: return code " << PI.ReturnCode << "\n";
587a34c753fSRafael Auler       errs() << ErrBuf;
588a34c753fSRafael Auler       exit(1);
589a34c753fSRafael Auler     }
590a34c753fSRafael Auler     return Error::success();
591a34c753fSRafael Auler   }
592a34c753fSRafael Auler 
593a34c753fSRafael Auler   ErrorOr<std::unique_ptr<MemoryBuffer>> MB =
594a34c753fSRafael Auler       MemoryBuffer::getFileOrSTDIN(MemEventsPPI.StdoutPath.data());
595a34c753fSRafael Auler   if (std::error_code EC = MB.getError()) {
596a34c753fSRafael Auler     errs() << "Cannot open " << MemEventsPPI.StdoutPath.data() << ": "
597a34c753fSRafael Auler            << EC.message() << "\n";
598a34c753fSRafael Auler     deleteTempFiles();
599a34c753fSRafael Auler     exit(1);
600a34c753fSRafael Auler   }
601a34c753fSRafael Auler 
602d914486aSAmir Ayupov   FileBuf = std::move(*MB);
603a34c753fSRafael Auler   ParsingBuf = FileBuf->getBuffer();
604a34c753fSRafael Auler   Col = 0;
605a34c753fSRafael Auler   Line = 1;
606def464aaSAmir Ayupov   if (const std::error_code EC = parseMemEvents())
60740c2e0faSMaksim Panchenko     errs() << "PERF2BOLT: failed to parse memory events: " << EC.message()
60840c2e0faSMaksim Panchenko            << '\n';
609a34c753fSRafael Auler 
610a34c753fSRafael Auler   deleteTempFiles();
611a34c753fSRafael Auler 
612a34c753fSRafael Auler   return Error::success();
613a34c753fSRafael Auler }
614a34c753fSRafael Auler 
615a34c753fSRafael Auler Error DataAggregator::readProfile(BinaryContext &BC) {
616a34c753fSRafael Auler   processProfile(BC);
617a34c753fSRafael Auler 
618a34c753fSRafael Auler   for (auto &BFI : BC.getBinaryFunctions()) {
619a34c753fSRafael Auler     BinaryFunction &Function = BFI.second;
620a34c753fSRafael Auler     convertBranchData(Function);
621a34c753fSRafael Auler   }
622a34c753fSRafael Auler 
62339336fc0SAmir Ayupov   if (opts::AggregateOnly &&
62439336fc0SAmir Ayupov       opts::ProfileFormat == opts::ProfileFormatKind::PF_Fdata) {
625def464aaSAmir Ayupov     if (std::error_code EC = writeAggregatedFile(opts::OutputFilename))
626a34c753fSRafael Auler       report_error("cannot create output data file", EC);
627a34c753fSRafael Auler   }
628a34c753fSRafael Auler 
629a34c753fSRafael Auler   return Error::success();
630a34c753fSRafael Auler }
631a34c753fSRafael Auler 
632a34c753fSRafael Auler bool DataAggregator::mayHaveProfileData(const BinaryFunction &Function) {
633a34c753fSRafael Auler   return Function.hasProfileAvailable();
634a34c753fSRafael Auler }
635a34c753fSRafael Auler 
636a34c753fSRafael Auler void DataAggregator::processProfile(BinaryContext &BC) {
637a34c753fSRafael Auler   if (opts::ReadPreAggregated)
638a34c753fSRafael Auler     processPreAggregated();
639a34c753fSRafael Auler   else if (opts::BasicAggregation)
640a34c753fSRafael Auler     processBasicEvents();
641a34c753fSRafael Auler   else
642a34c753fSRafael Auler     processBranchEvents();
643a34c753fSRafael Auler 
644a34c753fSRafael Auler   processMemEvents();
645a34c753fSRafael Auler 
646a34c753fSRafael Auler   // Mark all functions with registered events as having a valid profile.
647a34c753fSRafael Auler   for (auto &BFI : BC.getBinaryFunctions()) {
648a34c753fSRafael Auler     BinaryFunction &BF = BFI.second;
649a34c753fSRafael Auler     if (getBranchData(BF)) {
650a34c753fSRafael Auler       const auto Flags = opts::BasicAggregation ? BinaryFunction::PF_SAMPLE
651a34c753fSRafael Auler                                                 : BinaryFunction::PF_LBR;
652a34c753fSRafael Auler       BF.markProfiled(Flags);
653a34c753fSRafael Auler     }
654a34c753fSRafael Auler   }
655a34c753fSRafael Auler 
656a34c753fSRafael Auler   // Release intermediate storage.
657a34c753fSRafael Auler   clear(BranchLBRs);
658a34c753fSRafael Auler   clear(FallthroughLBRs);
659a34c753fSRafael Auler   clear(AggregatedLBRs);
660a34c753fSRafael Auler   clear(BasicSamples);
661a34c753fSRafael Auler   clear(MemSamples);
662a34c753fSRafael Auler }
663a34c753fSRafael Auler 
664a34c753fSRafael Auler BinaryFunction *
665a34c753fSRafael Auler DataAggregator::getBinaryFunctionContainingAddress(uint64_t Address) const {
666a34c753fSRafael Auler   if (!BC->containsAddress(Address))
667a34c753fSRafael Auler     return nullptr;
668a34c753fSRafael Auler 
669a34c753fSRafael Auler   return BC->getBinaryFunctionContainingAddress(Address, /*CheckPastEnd=*/false,
670a34c753fSRafael Auler                                                 /*UseMaxSize=*/true);
671a34c753fSRafael Auler }
672a34c753fSRafael Auler 
673a34c753fSRafael Auler StringRef DataAggregator::getLocationName(BinaryFunction &Func,
674a34c753fSRafael Auler                                           uint64_t Count) {
675a34c753fSRafael Auler   if (!BAT)
676a34c753fSRafael Auler     return Func.getOneName();
677a34c753fSRafael Auler 
678a34c753fSRafael Auler   const BinaryFunction *OrigFunc = &Func;
679a34c753fSRafael Auler   if (const uint64_t HotAddr = BAT->fetchParentAddress(Func.getAddress())) {
680a34c753fSRafael Auler     NumColdSamples += Count;
681a34c753fSRafael Auler     BinaryFunction *HotFunc = getBinaryFunctionContainingAddress(HotAddr);
682a34c753fSRafael Auler     if (HotFunc)
683a34c753fSRafael Auler       OrigFunc = HotFunc;
684a34c753fSRafael Auler   }
685a34c753fSRafael Auler   // If it is a local function, prefer the name containing the file name where
686a34c753fSRafael Auler   // the local function was declared
687a34c753fSRafael Auler   for (StringRef AlternativeName : OrigFunc->getNames()) {
688a34c753fSRafael Auler     size_t FileNameIdx = AlternativeName.find('/');
689a34c753fSRafael Auler     // Confirm the alternative name has the pattern Symbol/FileName/1 before
690a34c753fSRafael Auler     // using it
691a34c753fSRafael Auler     if (FileNameIdx == StringRef::npos ||
692a34c753fSRafael Auler         AlternativeName.find('/', FileNameIdx + 1) == StringRef::npos)
693a34c753fSRafael Auler       continue;
694a34c753fSRafael Auler     return AlternativeName;
695a34c753fSRafael Auler   }
696a34c753fSRafael Auler   return OrigFunc->getOneName();
697a34c753fSRafael Auler }
698a34c753fSRafael Auler 
699a34c753fSRafael Auler bool DataAggregator::doSample(BinaryFunction &Func, uint64_t Address,
700a34c753fSRafael Auler                               uint64_t Count) {
701a34c753fSRafael Auler   auto I = NamesToSamples.find(Func.getOneName());
702a34c753fSRafael Auler   if (I == NamesToSamples.end()) {
703a34c753fSRafael Auler     bool Success;
704a34c753fSRafael Auler     StringRef LocName = getLocationName(Func, Count);
70540c2e0faSMaksim Panchenko     std::tie(I, Success) = NamesToSamples.insert(
70640c2e0faSMaksim Panchenko         std::make_pair(Func.getOneName(),
707a34c753fSRafael Auler                        FuncSampleData(LocName, FuncSampleData::ContainerTy())));
708a34c753fSRafael Auler   }
709a34c753fSRafael Auler 
710a34c753fSRafael Auler   Address -= Func.getAddress();
711a34c753fSRafael Auler   if (BAT)
712fc0ced73SRafael Auler     Address = BAT->translate(Func.getAddress(), Address, /*IsBranchSrc=*/false);
713a34c753fSRafael Auler 
714a34c753fSRafael Auler   I->second.bumpCount(Address, Count);
715a34c753fSRafael Auler   return true;
716a34c753fSRafael Auler }
717a34c753fSRafael Auler 
718a34c753fSRafael Auler bool DataAggregator::doIntraBranch(BinaryFunction &Func, uint64_t From,
719a34c753fSRafael Auler                                    uint64_t To, uint64_t Count,
720a34c753fSRafael Auler                                    uint64_t Mispreds) {
721a34c753fSRafael Auler   FuncBranchData *AggrData = getBranchData(Func);
722a34c753fSRafael Auler   if (!AggrData) {
723a34c753fSRafael Auler     AggrData = &NamesToBranches[Func.getOneName()];
724a34c753fSRafael Auler     AggrData->Name = getLocationName(Func, Count);
725a34c753fSRafael Auler     setBranchData(Func, AggrData);
726a34c753fSRafael Auler   }
727a34c753fSRafael Auler 
728a34c753fSRafael Auler   From -= Func.getAddress();
729a34c753fSRafael Auler   To -= Func.getAddress();
730a34c753fSRafael Auler   LLVM_DEBUG(dbgs() << "BOLT-DEBUG: bumpBranchCount: " << Func.getPrintName()
731a34c753fSRafael Auler                     << " @ " << Twine::utohexstr(From) << " -> "
732a34c753fSRafael Auler                     << Func.getPrintName() << " @ " << Twine::utohexstr(To)
733a34c753fSRafael Auler                     << '\n');
734a34c753fSRafael Auler   if (BAT) {
735fc0ced73SRafael Auler     From = BAT->translate(Func.getAddress(), From, /*IsBranchSrc=*/true);
736fc0ced73SRafael Auler     To = BAT->translate(Func.getAddress(), To, /*IsBranchSrc=*/false);
737a34c753fSRafael Auler     LLVM_DEBUG(dbgs() << "BOLT-DEBUG: BAT translation on bumpBranchCount: "
738a34c753fSRafael Auler                       << Func.getPrintName() << " @ " << Twine::utohexstr(From)
739a34c753fSRafael Auler                       << " -> " << Func.getPrintName() << " @ "
740a34c753fSRafael Auler                       << Twine::utohexstr(To) << '\n');
741a34c753fSRafael Auler   }
742a34c753fSRafael Auler 
743a34c753fSRafael Auler   AggrData->bumpBranchCount(From, To, Count, Mispreds);
744a34c753fSRafael Auler   return true;
745a34c753fSRafael Auler }
746a34c753fSRafael Auler 
747a34c753fSRafael Auler bool DataAggregator::doInterBranch(BinaryFunction *FromFunc,
748a34c753fSRafael Auler                                    BinaryFunction *ToFunc, uint64_t From,
749a34c753fSRafael Auler                                    uint64_t To, uint64_t Count,
750a34c753fSRafael Auler                                    uint64_t Mispreds) {
751a34c753fSRafael Auler   FuncBranchData *FromAggrData = nullptr;
752a34c753fSRafael Auler   FuncBranchData *ToAggrData = nullptr;
753a34c753fSRafael Auler   StringRef SrcFunc;
754a34c753fSRafael Auler   StringRef DstFunc;
755a34c753fSRafael Auler   if (FromFunc) {
756a34c753fSRafael Auler     SrcFunc = getLocationName(*FromFunc, Count);
757a34c753fSRafael Auler     FromAggrData = getBranchData(*FromFunc);
758a34c753fSRafael Auler     if (!FromAggrData) {
759a34c753fSRafael Auler       FromAggrData = &NamesToBranches[FromFunc->getOneName()];
760a34c753fSRafael Auler       FromAggrData->Name = SrcFunc;
761a34c753fSRafael Auler       setBranchData(*FromFunc, FromAggrData);
762a34c753fSRafael Auler     }
763a34c753fSRafael Auler     From -= FromFunc->getAddress();
764a34c753fSRafael Auler     if (BAT)
765fc0ced73SRafael Auler       From = BAT->translate(FromFunc->getAddress(), From, /*IsBranchSrc=*/true);
766a34c753fSRafael Auler 
767a34c753fSRafael Auler     recordExit(*FromFunc, From, Mispreds, Count);
768a34c753fSRafael Auler   }
769a34c753fSRafael Auler   if (ToFunc) {
770a34c753fSRafael Auler     DstFunc = getLocationName(*ToFunc, 0);
771a34c753fSRafael Auler     ToAggrData = getBranchData(*ToFunc);
772a34c753fSRafael Auler     if (!ToAggrData) {
773a34c753fSRafael Auler       ToAggrData = &NamesToBranches[ToFunc->getOneName()];
774a34c753fSRafael Auler       ToAggrData->Name = DstFunc;
775a34c753fSRafael Auler       setBranchData(*ToFunc, ToAggrData);
776a34c753fSRafael Auler     }
777a34c753fSRafael Auler     To -= ToFunc->getAddress();
778a34c753fSRafael Auler     if (BAT)
779fc0ced73SRafael Auler       To = BAT->translate(ToFunc->getAddress(), To, /*IsBranchSrc=*/false);
780a34c753fSRafael Auler 
781a34c753fSRafael Auler     recordEntry(*ToFunc, To, Mispreds, Count);
782a34c753fSRafael Auler   }
783a34c753fSRafael Auler 
784a34c753fSRafael Auler   if (FromAggrData)
785a34c753fSRafael Auler     FromAggrData->bumpCallCount(From, Location(!DstFunc.empty(), DstFunc, To),
786a34c753fSRafael Auler                                 Count, Mispreds);
787a34c753fSRafael Auler   if (ToAggrData)
788a34c753fSRafael Auler     ToAggrData->bumpEntryCount(Location(!SrcFunc.empty(), SrcFunc, From), To,
789a34c753fSRafael Auler                                Count, Mispreds);
790a34c753fSRafael Auler   return true;
791a34c753fSRafael Auler }
792a34c753fSRafael Auler 
793a34c753fSRafael Auler bool DataAggregator::doBranch(uint64_t From, uint64_t To, uint64_t Count,
794a34c753fSRafael Auler                               uint64_t Mispreds) {
795a34c753fSRafael Auler   BinaryFunction *FromFunc = getBinaryFunctionContainingAddress(From);
796a34c753fSRafael Auler   BinaryFunction *ToFunc = getBinaryFunctionContainingAddress(To);
797a34c753fSRafael Auler   if (!FromFunc && !ToFunc)
798a34c753fSRafael Auler     return false;
799a34c753fSRafael Auler 
800a34c753fSRafael Auler   if (FromFunc == ToFunc) {
801a34c753fSRafael Auler     recordBranch(*FromFunc, From - FromFunc->getAddress(),
802a34c753fSRafael Auler                  To - FromFunc->getAddress(), Count, Mispreds);
803a34c753fSRafael Auler     return doIntraBranch(*FromFunc, From, To, Count, Mispreds);
804a34c753fSRafael Auler   }
805a34c753fSRafael Auler 
806a34c753fSRafael Auler   return doInterBranch(FromFunc, ToFunc, From, To, Count, Mispreds);
807a34c753fSRafael Auler }
808a34c753fSRafael Auler 
809a34c753fSRafael Auler bool DataAggregator::doTrace(const LBREntry &First, const LBREntry &Second,
810a34c753fSRafael Auler                              uint64_t Count) {
811a34c753fSRafael Auler   BinaryFunction *FromFunc = getBinaryFunctionContainingAddress(First.To);
812a34c753fSRafael Auler   BinaryFunction *ToFunc = getBinaryFunctionContainingAddress(Second.From);
813a34c753fSRafael Auler   if (!FromFunc || !ToFunc) {
814a34c753fSRafael Auler     LLVM_DEBUG(
815a34c753fSRafael Auler         dbgs() << "Out of range trace starting in " << FromFunc->getPrintName()
816a34c753fSRafael Auler                << " @ " << Twine::utohexstr(First.To - FromFunc->getAddress())
817a34c753fSRafael Auler                << " and ending in " << ToFunc->getPrintName() << " @ "
818a34c753fSRafael Auler                << ToFunc->getPrintName() << " @ "
819a34c753fSRafael Auler                << Twine::utohexstr(Second.From - ToFunc->getAddress()) << '\n');
820a34c753fSRafael Auler     NumLongRangeTraces += Count;
821a34c753fSRafael Auler     return false;
822a34c753fSRafael Auler   }
823a34c753fSRafael Auler   if (FromFunc != ToFunc) {
824a34c753fSRafael Auler     NumInvalidTraces += Count;
825a34c753fSRafael Auler     LLVM_DEBUG(
826a34c753fSRafael Auler         dbgs() << "Invalid trace starting in " << FromFunc->getPrintName()
827a34c753fSRafael Auler                << " @ " << Twine::utohexstr(First.To - FromFunc->getAddress())
828a34c753fSRafael Auler                << " and ending in " << ToFunc->getPrintName() << " @ "
829a34c753fSRafael Auler                << ToFunc->getPrintName() << " @ "
830a34c753fSRafael Auler                << Twine::utohexstr(Second.From - ToFunc->getAddress()) << '\n');
831a34c753fSRafael Auler     return false;
832a34c753fSRafael Auler   }
833a34c753fSRafael Auler 
8343d573fdbSAmir Ayupov   std::optional<BoltAddressTranslation::FallthroughListTy> FTs =
835fc0ced73SRafael Auler       BAT ? BAT->getFallthroughsInTrace(FromFunc->getAddress(), First.To,
836fc0ced73SRafael Auler                                         Second.From)
837a34c753fSRafael Auler           : getFallthroughsInTrace(*FromFunc, First, Second, Count);
838a34c753fSRafael Auler   if (!FTs) {
839a34c753fSRafael Auler     LLVM_DEBUG(
840a34c753fSRafael Auler         dbgs() << "Invalid trace starting in " << FromFunc->getPrintName()
841a34c753fSRafael Auler                << " @ " << Twine::utohexstr(First.To - FromFunc->getAddress())
842a34c753fSRafael Auler                << " and ending in " << ToFunc->getPrintName() << " @ "
843a34c753fSRafael Auler                << ToFunc->getPrintName() << " @ "
844a34c753fSRafael Auler                << Twine::utohexstr(Second.From - ToFunc->getAddress()) << '\n');
845a34c753fSRafael Auler     NumInvalidTraces += Count;
846a34c753fSRafael Auler     return false;
847a34c753fSRafael Auler   }
848a34c753fSRafael Auler 
849a34c753fSRafael Auler   LLVM_DEBUG(dbgs() << "Processing " << FTs->size() << " fallthroughs for "
850a34c753fSRafael Auler                     << FromFunc->getPrintName() << ":"
851a34c753fSRafael Auler                     << Twine::utohexstr(First.To) << " to "
852a34c753fSRafael Auler                     << Twine::utohexstr(Second.From) << ".\n");
853def464aaSAmir Ayupov   for (const std::pair<uint64_t, uint64_t> &Pair : *FTs)
854a34c753fSRafael Auler     doIntraBranch(*FromFunc, Pair.first + FromFunc->getAddress(),
855a34c753fSRafael Auler                   Pair.second + FromFunc->getAddress(), Count, false);
856a34c753fSRafael Auler 
857a34c753fSRafael Auler   return true;
858a34c753fSRafael Auler }
859a34c753fSRafael Auler 
860a34c753fSRafael Auler bool DataAggregator::recordTrace(
861a34c753fSRafael Auler     BinaryFunction &BF,
862a34c753fSRafael Auler     const LBREntry &FirstLBR,
863a34c753fSRafael Auler     const LBREntry &SecondLBR,
864a34c753fSRafael Auler     uint64_t Count,
865a34c753fSRafael Auler     SmallVector<std::pair<uint64_t, uint64_t>, 16> *Branches) const {
866a34c753fSRafael Auler   BinaryContext &BC = BF.getBinaryContext();
867a34c753fSRafael Auler 
868a34c753fSRafael Auler   if (!BF.isSimple())
869a34c753fSRafael Auler     return false;
870a34c753fSRafael Auler 
871a34c753fSRafael Auler   assert(BF.hasCFG() && "can only record traces in CFG state");
872a34c753fSRafael Auler 
873a34c753fSRafael Auler   // Offsets of the trace within this function.
874a34c753fSRafael Auler   const uint64_t From = FirstLBR.To - BF.getAddress();
875a34c753fSRafael Auler   const uint64_t To = SecondLBR.From - BF.getAddress();
876a34c753fSRafael Auler 
877a34c753fSRafael Auler   if (From > To)
878a34c753fSRafael Auler     return false;
879a34c753fSRafael Auler 
880d5c03defSFabian Parzefall   const BinaryBasicBlock *FromBB = BF.getBasicBlockContainingOffset(From);
881d5c03defSFabian Parzefall   const BinaryBasicBlock *ToBB = BF.getBasicBlockContainingOffset(To);
882a34c753fSRafael Auler 
883a34c753fSRafael Auler   if (!FromBB || !ToBB)
884a34c753fSRafael Auler     return false;
885a34c753fSRafael Auler 
886a34c753fSRafael Auler   // Adjust FromBB if the first LBR is a return from the last instruction in
887a34c753fSRafael Auler   // the previous block (that instruction should be a call).
888a34c753fSRafael Auler   if (From == FromBB->getOffset() && !BF.containsAddress(FirstLBR.From) &&
889a34c753fSRafael Auler       !FromBB->isEntryPoint() && !FromBB->isLandingPad()) {
890d5c03defSFabian Parzefall     const BinaryBasicBlock *PrevBB =
891d5c03defSFabian Parzefall         BF.getLayout().getBlock(FromBB->getIndex() - 1);
892a34c753fSRafael Auler     if (PrevBB->getSuccessor(FromBB->getLabel())) {
893a34c753fSRafael Auler       const MCInst *Instr = PrevBB->getLastNonPseudoInstr();
894def464aaSAmir Ayupov       if (Instr && BC.MIB->isCall(*Instr))
895a34c753fSRafael Auler         FromBB = PrevBB;
896def464aaSAmir Ayupov       else
897a34c753fSRafael Auler         LLVM_DEBUG(dbgs() << "invalid incoming LBR (no call): " << FirstLBR
898a34c753fSRafael Auler                           << '\n');
899a34c753fSRafael Auler     } else {
900a34c753fSRafael Auler       LLVM_DEBUG(dbgs() << "invalid incoming LBR: " << FirstLBR << '\n');
901a34c753fSRafael Auler     }
902a34c753fSRafael Auler   }
903a34c753fSRafael Auler 
904a34c753fSRafael Auler   // Fill out information for fall-through edges. The From and To could be
905a34c753fSRafael Auler   // within the same basic block, e.g. when two call instructions are in the
906a34c753fSRafael Auler   // same block. In this case we skip the processing.
907def464aaSAmir Ayupov   if (FromBB == ToBB)
908a34c753fSRafael Auler     return true;
909a34c753fSRafael Auler 
910a34c753fSRafael Auler   // Process blocks in the original layout order.
9118477bc67SFabian Parzefall   BinaryBasicBlock *BB = BF.getLayout().getBlock(FromBB->getIndex());
912a34c753fSRafael Auler   assert(BB == FromBB && "index mismatch");
913a34c753fSRafael Auler   while (BB != ToBB) {
9148477bc67SFabian Parzefall     BinaryBasicBlock *NextBB = BF.getLayout().getBlock(BB->getIndex() + 1);
915a34c753fSRafael Auler     assert((NextBB && NextBB->getOffset() > BB->getOffset()) && "bad layout");
916a34c753fSRafael Auler 
917a34c753fSRafael Auler     // Check for bad LBRs.
918a34c753fSRafael Auler     if (!BB->getSuccessor(NextBB->getLabel())) {
919a34c753fSRafael Auler       LLVM_DEBUG(dbgs() << "no fall-through for the trace:\n"
920a34c753fSRafael Auler                         << "  " << FirstLBR << '\n'
921a34c753fSRafael Auler                         << "  " << SecondLBR << '\n');
922a34c753fSRafael Auler       return false;
923a34c753fSRafael Auler     }
924a34c753fSRafael Auler 
925a34c753fSRafael Auler     // Record fall-through jumps
926a34c753fSRafael Auler     BinaryBasicBlock::BinaryBranchInfo &BI = BB->getBranchInfo(*NextBB);
927a34c753fSRafael Auler     BI.Count += Count;
928a34c753fSRafael Auler 
929a34c753fSRafael Auler     if (Branches) {
930a34c753fSRafael Auler       const MCInst *Instr = BB->getLastNonPseudoInstr();
931a34c753fSRafael Auler       uint64_t Offset = 0;
932def464aaSAmir Ayupov       if (Instr)
933a9cd49d5SAmir Ayupov         Offset = BC.MIB->getOffsetWithDefault(*Instr, 0);
934def464aaSAmir Ayupov       else
935a34c753fSRafael Auler         Offset = BB->getOffset();
936def464aaSAmir Ayupov 
937a34c753fSRafael Auler       Branches->emplace_back(Offset, NextBB->getOffset());
938a34c753fSRafael Auler     }
939a34c753fSRafael Auler 
940a34c753fSRafael Auler     BB = NextBB;
941a34c753fSRafael Auler   }
942a34c753fSRafael Auler 
943a34c753fSRafael Auler   return true;
944a34c753fSRafael Auler }
945a34c753fSRafael Auler 
9463d573fdbSAmir Ayupov std::optional<SmallVector<std::pair<uint64_t, uint64_t>, 16>>
947a34c753fSRafael Auler DataAggregator::getFallthroughsInTrace(BinaryFunction &BF,
948a34c753fSRafael Auler                                        const LBREntry &FirstLBR,
949a34c753fSRafael Auler                                        const LBREntry &SecondLBR,
950a34c753fSRafael Auler                                        uint64_t Count) const {
951a34c753fSRafael Auler   SmallVector<std::pair<uint64_t, uint64_t>, 16> Res;
952a34c753fSRafael Auler 
953a34c753fSRafael Auler   if (!recordTrace(BF, FirstLBR, SecondLBR, Count, &Res))
954e324a80fSKazu Hirata     return std::nullopt;
955a34c753fSRafael Auler 
956a34c753fSRafael Auler   return Res;
957a34c753fSRafael Auler }
958a34c753fSRafael Auler 
959a34c753fSRafael Auler bool DataAggregator::recordEntry(BinaryFunction &BF, uint64_t To, bool Mispred,
960a34c753fSRafael Auler                                  uint64_t Count) const {
961a34c753fSRafael Auler   if (To > BF.getSize())
962a34c753fSRafael Auler     return false;
963a34c753fSRafael Auler 
964a34c753fSRafael Auler   if (!BF.hasProfile())
965a34c753fSRafael Auler     BF.ExecutionCount = 0;
966a34c753fSRafael Auler 
967a34c753fSRafael Auler   BinaryBasicBlock *EntryBB = nullptr;
968a34c753fSRafael Auler   if (To == 0) {
969a34c753fSRafael Auler     BF.ExecutionCount += Count;
970a34c753fSRafael Auler     if (!BF.empty())
971a34c753fSRafael Auler       EntryBB = &BF.front();
972a34c753fSRafael Auler   } else if (BinaryBasicBlock *BB = BF.getBasicBlockAtOffset(To)) {
973a34c753fSRafael Auler     if (BB->isEntryPoint())
974a34c753fSRafael Auler       EntryBB = BB;
975a34c753fSRafael Auler   }
976a34c753fSRafael Auler 
977a34c753fSRafael Auler   if (EntryBB)
978a34c753fSRafael Auler     EntryBB->setExecutionCount(EntryBB->getKnownExecutionCount() + Count);
979a34c753fSRafael Auler 
980a34c753fSRafael Auler   return true;
981a34c753fSRafael Auler }
982a34c753fSRafael Auler 
98340c2e0faSMaksim Panchenko bool DataAggregator::recordExit(BinaryFunction &BF, uint64_t From, bool Mispred,
98440c2e0faSMaksim Panchenko                                 uint64_t Count) const {
985a34c753fSRafael Auler   if (!BF.isSimple() || From > BF.getSize())
986a34c753fSRafael Auler     return false;
987a34c753fSRafael Auler 
988a34c753fSRafael Auler   if (!BF.hasProfile())
989a34c753fSRafael Auler     BF.ExecutionCount = 0;
990a34c753fSRafael Auler 
991a34c753fSRafael Auler   return true;
992a34c753fSRafael Auler }
993a34c753fSRafael Auler 
994a34c753fSRafael Auler ErrorOr<LBREntry> DataAggregator::parseLBREntry() {
995a34c753fSRafael Auler   LBREntry Res;
996a34c753fSRafael Auler   ErrorOr<StringRef> FromStrRes = parseString('/');
997a34c753fSRafael Auler   if (std::error_code EC = FromStrRes.getError())
998a34c753fSRafael Auler     return EC;
999a34c753fSRafael Auler   StringRef OffsetStr = FromStrRes.get();
1000a34c753fSRafael Auler   if (OffsetStr.getAsInteger(0, Res.From)) {
1001a34c753fSRafael Auler     reportError("expected hexadecimal number with From address");
1002a34c753fSRafael Auler     Diag << "Found: " << OffsetStr << "\n";
1003a34c753fSRafael Auler     return make_error_code(llvm::errc::io_error);
1004a34c753fSRafael Auler   }
1005a34c753fSRafael Auler 
1006a34c753fSRafael Auler   ErrorOr<StringRef> ToStrRes = parseString('/');
1007a34c753fSRafael Auler   if (std::error_code EC = ToStrRes.getError())
1008a34c753fSRafael Auler     return EC;
1009a34c753fSRafael Auler   OffsetStr = ToStrRes.get();
1010a34c753fSRafael Auler   if (OffsetStr.getAsInteger(0, Res.To)) {
1011a34c753fSRafael Auler     reportError("expected hexadecimal number with To address");
1012a34c753fSRafael Auler     Diag << "Found: " << OffsetStr << "\n";
1013a34c753fSRafael Auler     return make_error_code(llvm::errc::io_error);
1014a34c753fSRafael Auler   }
1015a34c753fSRafael Auler 
1016a34c753fSRafael Auler   ErrorOr<StringRef> MispredStrRes = parseString('/');
1017a34c753fSRafael Auler   if (std::error_code EC = MispredStrRes.getError())
1018a34c753fSRafael Auler     return EC;
1019a34c753fSRafael Auler   StringRef MispredStr = MispredStrRes.get();
1020a34c753fSRafael Auler   if (MispredStr.size() != 1 ||
1021a34c753fSRafael Auler       (MispredStr[0] != 'P' && MispredStr[0] != 'M' && MispredStr[0] != '-')) {
1022a34c753fSRafael Auler     reportError("expected single char for mispred bit");
1023a34c753fSRafael Auler     Diag << "Found: " << MispredStr << "\n";
1024a34c753fSRafael Auler     return make_error_code(llvm::errc::io_error);
1025a34c753fSRafael Auler   }
1026a34c753fSRafael Auler   Res.Mispred = MispredStr[0] == 'M';
1027a34c753fSRafael Auler 
102840c2e0faSMaksim Panchenko   static bool MispredWarning = true;
1029a34c753fSRafael Auler   if (MispredStr[0] == '-' && MispredWarning) {
1030a34c753fSRafael Auler     errs() << "PERF2BOLT-WARNING: misprediction bit is missing in profile\n";
1031a34c753fSRafael Auler     MispredWarning = false;
1032a34c753fSRafael Auler   }
1033a34c753fSRafael Auler 
1034a34c753fSRafael Auler   ErrorOr<StringRef> Rest = parseString(FieldSeparator, true);
1035a34c753fSRafael Auler   if (std::error_code EC = Rest.getError())
1036a34c753fSRafael Auler     return EC;
1037a34c753fSRafael Auler   if (Rest.get().size() < 5) {
1038a34c753fSRafael Auler     reportError("expected rest of LBR entry");
1039a34c753fSRafael Auler     Diag << "Found: " << Rest.get() << "\n";
1040a34c753fSRafael Auler     return make_error_code(llvm::errc::io_error);
1041a34c753fSRafael Auler   }
1042a34c753fSRafael Auler   return Res;
1043a34c753fSRafael Auler }
1044a34c753fSRafael Auler 
1045a34c753fSRafael Auler bool DataAggregator::checkAndConsumeFS() {
1046def464aaSAmir Ayupov   if (ParsingBuf[0] != FieldSeparator)
1047a34c753fSRafael Auler     return false;
1048def464aaSAmir Ayupov 
1049a34c753fSRafael Auler   ParsingBuf = ParsingBuf.drop_front(1);
1050a34c753fSRafael Auler   Col += 1;
1051a34c753fSRafael Auler   return true;
1052a34c753fSRafael Auler }
1053a34c753fSRafael Auler 
1054a34c753fSRafael Auler void DataAggregator::consumeRestOfLine() {
1055a34c753fSRafael Auler   size_t LineEnd = ParsingBuf.find_first_of('\n');
1056a34c753fSRafael Auler   if (LineEnd == StringRef::npos) {
1057a34c753fSRafael Auler     ParsingBuf = StringRef();
1058a34c753fSRafael Auler     Col = 0;
1059a34c753fSRafael Auler     Line += 1;
1060a34c753fSRafael Auler     return;
1061a34c753fSRafael Auler   }
1062a34c753fSRafael Auler   ParsingBuf = ParsingBuf.drop_front(LineEnd + 1);
1063a34c753fSRafael Auler   Col = 0;
1064a34c753fSRafael Auler   Line += 1;
1065a34c753fSRafael Auler }
1066a34c753fSRafael Auler 
1067ba9cc653SRafael Auler bool DataAggregator::checkNewLine() {
1068ba9cc653SRafael Auler   return ParsingBuf[0] == '\n';
1069ba9cc653SRafael Auler }
1070ba9cc653SRafael Auler 
1071a34c753fSRafael Auler ErrorOr<DataAggregator::PerfBranchSample> DataAggregator::parseBranchSample() {
1072a34c753fSRafael Auler   PerfBranchSample Res;
1073a34c753fSRafael Auler 
107440c2e0faSMaksim Panchenko   while (checkAndConsumeFS()) {
107540c2e0faSMaksim Panchenko   }
1076a34c753fSRafael Auler 
1077a34c753fSRafael Auler   ErrorOr<int64_t> PIDRes = parseNumberField(FieldSeparator, true);
1078a34c753fSRafael Auler   if (std::error_code EC = PIDRes.getError())
1079a34c753fSRafael Auler     return EC;
1080a34c753fSRafael Auler   auto MMapInfoIter = BinaryMMapInfo.find(*PIDRes);
1081a34c753fSRafael Auler   if (!opts::LinuxKernelMode && MMapInfoIter == BinaryMMapInfo.end()) {
1082a34c753fSRafael Auler     consumeRestOfLine();
1083a34c753fSRafael Auler     return make_error_code(errc::no_such_process);
1084a34c753fSRafael Auler   }
1085a34c753fSRafael Auler 
108640c2e0faSMaksim Panchenko   while (checkAndConsumeFS()) {
108740c2e0faSMaksim Panchenko   }
1088a34c753fSRafael Auler 
1089a34c753fSRafael Auler   ErrorOr<uint64_t> PCRes = parseHexField(FieldSeparator, true);
1090a34c753fSRafael Auler   if (std::error_code EC = PCRes.getError())
1091a34c753fSRafael Auler     return EC;
1092a34c753fSRafael Auler   Res.PC = PCRes.get();
1093a34c753fSRafael Auler 
1094a34c753fSRafael Auler   if (checkAndConsumeNewLine())
1095a34c753fSRafael Auler     return Res;
1096a34c753fSRafael Auler 
1097a34c753fSRafael Auler   while (!checkAndConsumeNewLine()) {
1098a34c753fSRafael Auler     checkAndConsumeFS();
1099a34c753fSRafael Auler 
1100a34c753fSRafael Auler     ErrorOr<LBREntry> LBRRes = parseLBREntry();
1101a34c753fSRafael Auler     if (std::error_code EC = LBRRes.getError())
1102a34c753fSRafael Auler       return EC;
1103a34c753fSRafael Auler     LBREntry LBR = LBRRes.get();
1104a34c753fSRafael Auler     if (ignoreKernelInterrupt(LBR))
1105a34c753fSRafael Auler       continue;
1106a34c753fSRafael Auler     if (!BC->HasFixedLoadAddress)
1107a34c753fSRafael Auler       adjustLBR(LBR, MMapInfoIter->second);
1108a34c753fSRafael Auler     Res.LBR.push_back(LBR);
1109a34c753fSRafael Auler   }
1110a34c753fSRafael Auler 
1111a34c753fSRafael Auler   return Res;
1112a34c753fSRafael Auler }
1113a34c753fSRafael Auler 
1114a34c753fSRafael Auler ErrorOr<DataAggregator::PerfBasicSample> DataAggregator::parseBasicSample() {
111540c2e0faSMaksim Panchenko   while (checkAndConsumeFS()) {
111640c2e0faSMaksim Panchenko   }
1117a34c753fSRafael Auler 
1118a34c753fSRafael Auler   ErrorOr<int64_t> PIDRes = parseNumberField(FieldSeparator, true);
1119a34c753fSRafael Auler   if (std::error_code EC = PIDRes.getError())
1120a34c753fSRafael Auler     return EC;
1121a34c753fSRafael Auler 
1122a34c753fSRafael Auler   auto MMapInfoIter = BinaryMMapInfo.find(*PIDRes);
1123a34c753fSRafael Auler   if (MMapInfoIter == BinaryMMapInfo.end()) {
1124a34c753fSRafael Auler     consumeRestOfLine();
1125a34c753fSRafael Auler     return PerfBasicSample{StringRef(), 0};
1126a34c753fSRafael Auler   }
1127a34c753fSRafael Auler 
112840c2e0faSMaksim Panchenko   while (checkAndConsumeFS()) {
112940c2e0faSMaksim Panchenko   }
1130a34c753fSRafael Auler 
1131a34c753fSRafael Auler   ErrorOr<StringRef> Event = parseString(FieldSeparator);
1132a34c753fSRafael Auler   if (std::error_code EC = Event.getError())
1133a34c753fSRafael Auler     return EC;
1134a34c753fSRafael Auler 
113540c2e0faSMaksim Panchenko   while (checkAndConsumeFS()) {
113640c2e0faSMaksim Panchenko   }
1137a34c753fSRafael Auler 
1138a34c753fSRafael Auler   ErrorOr<uint64_t> AddrRes = parseHexField(FieldSeparator, true);
1139def464aaSAmir Ayupov   if (std::error_code EC = AddrRes.getError())
1140a34c753fSRafael Auler     return EC;
1141a34c753fSRafael Auler 
1142a34c753fSRafael Auler   if (!checkAndConsumeNewLine()) {
1143a34c753fSRafael Auler     reportError("expected end of line");
1144a34c753fSRafael Auler     return make_error_code(llvm::errc::io_error);
1145a34c753fSRafael Auler   }
1146a34c753fSRafael Auler 
1147a34c753fSRafael Auler   uint64_t Address = *AddrRes;
1148a34c753fSRafael Auler   if (!BC->HasFixedLoadAddress)
1149a34c753fSRafael Auler     adjustAddress(Address, MMapInfoIter->second);
1150a34c753fSRafael Auler 
1151a34c753fSRafael Auler   return PerfBasicSample{Event.get(), Address};
1152a34c753fSRafael Auler }
1153a34c753fSRafael Auler 
1154a34c753fSRafael Auler ErrorOr<DataAggregator::PerfMemSample> DataAggregator::parseMemSample() {
1155a34c753fSRafael Auler   PerfMemSample Res{0, 0};
1156a34c753fSRafael Auler 
115740c2e0faSMaksim Panchenko   while (checkAndConsumeFS()) {
115840c2e0faSMaksim Panchenko   }
1159a34c753fSRafael Auler 
1160a34c753fSRafael Auler   ErrorOr<int64_t> PIDRes = parseNumberField(FieldSeparator, true);
1161a34c753fSRafael Auler   if (std::error_code EC = PIDRes.getError())
1162a34c753fSRafael Auler     return EC;
1163a34c753fSRafael Auler 
1164a34c753fSRafael Auler   auto MMapInfoIter = BinaryMMapInfo.find(*PIDRes);
1165a34c753fSRafael Auler   if (MMapInfoIter == BinaryMMapInfo.end()) {
1166a34c753fSRafael Auler     consumeRestOfLine();
1167a34c753fSRafael Auler     return Res;
1168a34c753fSRafael Auler   }
1169a34c753fSRafael Auler 
117040c2e0faSMaksim Panchenko   while (checkAndConsumeFS()) {
117140c2e0faSMaksim Panchenko   }
1172a34c753fSRafael Auler 
1173a34c753fSRafael Auler   ErrorOr<StringRef> Event = parseString(FieldSeparator);
1174a34c753fSRafael Auler   if (std::error_code EC = Event.getError())
1175a34c753fSRafael Auler     return EC;
117620f0f15aSKazu Hirata   if (!Event.get().contains("mem-loads")) {
1177a34c753fSRafael Auler     consumeRestOfLine();
1178a34c753fSRafael Auler     return Res;
1179a34c753fSRafael Auler   }
1180a34c753fSRafael Auler 
118140c2e0faSMaksim Panchenko   while (checkAndConsumeFS()) {
118240c2e0faSMaksim Panchenko   }
1183a34c753fSRafael Auler 
1184a34c753fSRafael Auler   ErrorOr<uint64_t> AddrRes = parseHexField(FieldSeparator);
1185def464aaSAmir Ayupov   if (std::error_code EC = AddrRes.getError())
1186a34c753fSRafael Auler     return EC;
1187a34c753fSRafael Auler 
118840c2e0faSMaksim Panchenko   while (checkAndConsumeFS()) {
118940c2e0faSMaksim Panchenko   }
1190a34c753fSRafael Auler 
1191a34c753fSRafael Auler   ErrorOr<uint64_t> PCRes = parseHexField(FieldSeparator, true);
1192a34c753fSRafael Auler   if (std::error_code EC = PCRes.getError()) {
1193a34c753fSRafael Auler     consumeRestOfLine();
1194a34c753fSRafael Auler     return EC;
1195a34c753fSRafael Auler   }
1196a34c753fSRafael Auler 
1197a34c753fSRafael Auler   if (!checkAndConsumeNewLine()) {
1198a34c753fSRafael Auler     reportError("expected end of line");
1199a34c753fSRafael Auler     return make_error_code(llvm::errc::io_error);
1200a34c753fSRafael Auler   }
1201a34c753fSRafael Auler 
1202a34c753fSRafael Auler   uint64_t Address = *AddrRes;
1203a34c753fSRafael Auler   if (!BC->HasFixedLoadAddress)
1204a34c753fSRafael Auler     adjustAddress(Address, MMapInfoIter->second);
1205a34c753fSRafael Auler 
1206a34c753fSRafael Auler   return PerfMemSample{PCRes.get(), Address};
1207a34c753fSRafael Auler }
1208a34c753fSRafael Auler 
1209a34c753fSRafael Auler ErrorOr<Location> DataAggregator::parseLocationOrOffset() {
1210a34c753fSRafael Auler   auto parseOffset = [this]() -> ErrorOr<Location> {
1211a34c753fSRafael Auler     ErrorOr<uint64_t> Res = parseHexField(FieldSeparator);
1212a34c753fSRafael Auler     if (std::error_code EC = Res.getError())
1213a34c753fSRafael Auler       return EC;
1214a34c753fSRafael Auler     return Location(Res.get());
1215a34c753fSRafael Auler   };
1216a34c753fSRafael Auler 
1217a34c753fSRafael Auler   size_t Sep = ParsingBuf.find_first_of(" \n");
1218a34c753fSRafael Auler   if (Sep == StringRef::npos)
1219a34c753fSRafael Auler     return parseOffset();
1220a34c753fSRafael Auler   StringRef LookAhead = ParsingBuf.substr(0, Sep);
1221a34c753fSRafael Auler   if (LookAhead.find_first_of(":") == StringRef::npos)
1222a34c753fSRafael Auler     return parseOffset();
1223a34c753fSRafael Auler 
1224a34c753fSRafael Auler   ErrorOr<StringRef> BuildID = parseString(':');
1225a34c753fSRafael Auler   if (std::error_code EC = BuildID.getError())
1226a34c753fSRafael Auler     return EC;
1227a34c753fSRafael Auler   ErrorOr<uint64_t> Offset = parseHexField(FieldSeparator);
1228a34c753fSRafael Auler   if (std::error_code EC = Offset.getError())
1229a34c753fSRafael Auler     return EC;
1230a34c753fSRafael Auler   return Location(true, BuildID.get(), Offset.get());
1231a34c753fSRafael Auler }
1232a34c753fSRafael Auler 
1233a34c753fSRafael Auler ErrorOr<DataAggregator::AggregatedLBREntry>
1234a34c753fSRafael Auler DataAggregator::parseAggregatedLBREntry() {
123540c2e0faSMaksim Panchenko   while (checkAndConsumeFS()) {
123640c2e0faSMaksim Panchenko   }
1237a34c753fSRafael Auler 
1238a34c753fSRafael Auler   ErrorOr<StringRef> TypeOrErr = parseString(FieldSeparator);
1239a34c753fSRafael Auler   if (std::error_code EC = TypeOrErr.getError())
1240a34c753fSRafael Auler     return EC;
1241a34c753fSRafael Auler   auto Type = AggregatedLBREntry::BRANCH;
1242a34c753fSRafael Auler   if (TypeOrErr.get() == "B") {
1243a34c753fSRafael Auler     Type = AggregatedLBREntry::BRANCH;
1244a34c753fSRafael Auler   } else if (TypeOrErr.get() == "F") {
1245a34c753fSRafael Auler     Type = AggregatedLBREntry::FT;
1246a34c753fSRafael Auler   } else if (TypeOrErr.get() == "f") {
1247a34c753fSRafael Auler     Type = AggregatedLBREntry::FT_EXTERNAL_ORIGIN;
1248a34c753fSRafael Auler   } else {
1249a34c753fSRafael Auler     reportError("expected B, F or f");
1250a34c753fSRafael Auler     return make_error_code(llvm::errc::io_error);
1251a34c753fSRafael Auler   }
1252a34c753fSRafael Auler 
125340c2e0faSMaksim Panchenko   while (checkAndConsumeFS()) {
125440c2e0faSMaksim Panchenko   }
1255a34c753fSRafael Auler   ErrorOr<Location> From = parseLocationOrOffset();
1256a34c753fSRafael Auler   if (std::error_code EC = From.getError())
1257a34c753fSRafael Auler     return EC;
1258a34c753fSRafael Auler 
125940c2e0faSMaksim Panchenko   while (checkAndConsumeFS()) {
126040c2e0faSMaksim Panchenko   }
1261a34c753fSRafael Auler   ErrorOr<Location> To = parseLocationOrOffset();
1262a34c753fSRafael Auler   if (std::error_code EC = To.getError())
1263a34c753fSRafael Auler     return EC;
1264a34c753fSRafael Auler 
126540c2e0faSMaksim Panchenko   while (checkAndConsumeFS()) {
126640c2e0faSMaksim Panchenko   }
1267a34c753fSRafael Auler   ErrorOr<int64_t> Frequency =
1268a34c753fSRafael Auler       parseNumberField(FieldSeparator, Type != AggregatedLBREntry::BRANCH);
1269a34c753fSRafael Auler   if (std::error_code EC = Frequency.getError())
1270a34c753fSRafael Auler     return EC;
1271a34c753fSRafael Auler 
1272a34c753fSRafael Auler   uint64_t Mispreds = 0;
1273a34c753fSRafael Auler   if (Type == AggregatedLBREntry::BRANCH) {
127440c2e0faSMaksim Panchenko     while (checkAndConsumeFS()) {
127540c2e0faSMaksim Panchenko     }
1276a34c753fSRafael Auler     ErrorOr<int64_t> MispredsOrErr = parseNumberField(FieldSeparator, true);
1277a34c753fSRafael Auler     if (std::error_code EC = MispredsOrErr.getError())
1278a34c753fSRafael Auler       return EC;
1279a34c753fSRafael Auler     Mispreds = static_cast<uint64_t>(MispredsOrErr.get());
1280a34c753fSRafael Auler   }
1281a34c753fSRafael Auler 
1282a34c753fSRafael Auler   if (!checkAndConsumeNewLine()) {
1283a34c753fSRafael Auler     reportError("expected end of line");
1284a34c753fSRafael Auler     return make_error_code(llvm::errc::io_error);
1285a34c753fSRafael Auler   }
1286a34c753fSRafael Auler 
1287a34c753fSRafael Auler   return AggregatedLBREntry{From.get(), To.get(),
1288a34c753fSRafael Auler                             static_cast<uint64_t>(Frequency.get()), Mispreds,
1289a34c753fSRafael Auler                             Type};
1290a34c753fSRafael Auler }
1291a34c753fSRafael Auler 
1292a34c753fSRafael Auler bool DataAggregator::ignoreKernelInterrupt(LBREntry &LBR) const {
1293a34c753fSRafael Auler   return opts::IgnoreInterruptLBR &&
1294a34c753fSRafael Auler          (LBR.From >= KernelBaseAddr || LBR.To >= KernelBaseAddr);
1295a34c753fSRafael Auler }
1296a34c753fSRafael Auler 
1297a34c753fSRafael Auler std::error_code DataAggregator::printLBRHeatMap() {
1298a34c753fSRafael Auler   outs() << "PERF2BOLT: parse branch events...\n";
1299a34c753fSRafael Auler   NamedRegionTimer T("parseBranch", "Parsing branch events", TimerGroupName,
1300a34c753fSRafael Auler                      TimerGroupDesc, opts::TimeAggregator);
1301a34c753fSRafael Auler 
1302a34c753fSRafael Auler   if (opts::LinuxKernelMode) {
1303a34c753fSRafael Auler     opts::HeatmapMaxAddress = 0xffffffffffffffff;
1304a34c753fSRafael Auler     opts::HeatmapMinAddress = KernelBaseAddr;
1305a34c753fSRafael Auler   }
1306a34c753fSRafael Auler   Heatmap HM(opts::HeatmapBlock, opts::HeatmapMinAddress,
1307733dc3e5SRahman Lavaee              opts::HeatmapMaxAddress, getTextSections(BC));
1308a34c753fSRafael Auler   uint64_t NumTotalSamples = 0;
1309a34c753fSRafael Auler 
13100c13d97eSRahman Lavaee   if (opts::BasicAggregation) {
1311e59e5801SRahman Lavaee     while (hasData()) {
13120c13d97eSRahman Lavaee       ErrorOr<PerfBasicSample> SampleRes = parseBasicSample();
13130c13d97eSRahman Lavaee       if (std::error_code EC = SampleRes.getError()) {
13140c13d97eSRahman Lavaee         if (EC == errc::no_such_process)
13150c13d97eSRahman Lavaee           continue;
13160c13d97eSRahman Lavaee         return EC;
13170c13d97eSRahman Lavaee       }
13180c13d97eSRahman Lavaee       PerfBasicSample &Sample = SampleRes.get();
13190c13d97eSRahman Lavaee       HM.registerAddress(Sample.PC);
13200c13d97eSRahman Lavaee       NumTotalSamples++;
1321e59e5801SRahman Lavaee     }
1322e59e5801SRahman Lavaee     outs() << "HEATMAP: read " << NumTotalSamples << " basic samples\n";
13230c13d97eSRahman Lavaee   } else {
1324e59e5801SRahman Lavaee     while (hasData()) {
1325a34c753fSRafael Auler       ErrorOr<PerfBranchSample> SampleRes = parseBranchSample();
1326a34c753fSRafael Auler       if (std::error_code EC = SampleRes.getError()) {
1327a34c753fSRafael Auler         if (EC == errc::no_such_process)
1328a34c753fSRafael Auler           continue;
1329a34c753fSRafael Auler         return EC;
1330a34c753fSRafael Auler       }
1331a34c753fSRafael Auler 
1332a34c753fSRafael Auler       PerfBranchSample &Sample = SampleRes.get();
1333a34c753fSRafael Auler 
1334a34c753fSRafael Auler       // LBRs are stored in reverse execution order. NextLBR refers to the next
1335a34c753fSRafael Auler       // executed branch record.
1336a34c753fSRafael Auler       const LBREntry *NextLBR = nullptr;
1337a34c753fSRafael Auler       for (const LBREntry &LBR : Sample.LBR) {
1338a34c753fSRafael Auler         if (NextLBR) {
1339a34c753fSRafael Auler           // Record fall-through trace.
1340a34c753fSRafael Auler           const uint64_t TraceFrom = LBR.To;
1341a34c753fSRafael Auler           const uint64_t TraceTo = NextLBR->From;
1342a34c753fSRafael Auler           ++FallthroughLBRs[Trace(TraceFrom, TraceTo)].InternCount;
1343a34c753fSRafael Auler         }
1344a34c753fSRafael Auler         NextLBR = &LBR;
1345a34c753fSRafael Auler       }
1346a34c753fSRafael Auler       if (!Sample.LBR.empty()) {
1347a34c753fSRafael Auler         HM.registerAddress(Sample.LBR.front().To);
1348a34c753fSRafael Auler         HM.registerAddress(Sample.LBR.back().From);
1349a34c753fSRafael Auler       }
1350a34c753fSRafael Auler       NumTotalSamples += Sample.LBR.size();
1351a34c753fSRafael Auler     }
1352e59e5801SRahman Lavaee     outs() << "HEATMAP: read " << NumTotalSamples << " LBR samples\n";
1353e59e5801SRahman Lavaee     outs() << "HEATMAP: " << FallthroughLBRs.size() << " unique traces\n";
13540c13d97eSRahman Lavaee   }
1355a34c753fSRafael Auler 
1356a34c753fSRafael Auler   if (!NumTotalSamples) {
1357e59e5801SRahman Lavaee     if (opts::BasicAggregation) {
1358e59e5801SRahman Lavaee       errs() << "HEATMAP-ERROR: no basic event samples detected in profile. "
1359e59e5801SRahman Lavaee                 "Cannot build heatmap.";
1360e59e5801SRahman Lavaee     } else {
1361a34c753fSRafael Auler       errs() << "HEATMAP-ERROR: no LBR traces detected in profile. "
13620c13d97eSRahman Lavaee                 "Cannot build heatmap. Use -nl for building heatmap from "
13630c13d97eSRahman Lavaee                 "basic events.\n";
13640c13d97eSRahman Lavaee     }
1365a34c753fSRafael Auler     exit(1);
1366a34c753fSRafael Auler   }
1367a34c753fSRafael Auler 
1368a34c753fSRafael Auler   outs() << "HEATMAP: building heat map...\n";
1369a34c753fSRafael Auler 
1370a34c753fSRafael Auler   for (const auto &LBR : FallthroughLBRs) {
1371a34c753fSRafael Auler     const Trace &Trace = LBR.first;
1372a34c753fSRafael Auler     const FTInfo &Info = LBR.second;
1373a34c753fSRafael Auler     HM.registerAddressRange(Trace.From, Trace.To, Info.InternCount);
1374a34c753fSRafael Auler   }
1375a34c753fSRafael Auler 
1376a34c753fSRafael Auler   if (HM.getNumInvalidRanges())
1377a34c753fSRafael Auler     outs() << "HEATMAP: invalid traces: " << HM.getNumInvalidRanges() << '\n';
1378a34c753fSRafael Auler 
1379a34c753fSRafael Auler   if (!HM.size()) {
1380a34c753fSRafael Auler     errs() << "HEATMAP-ERROR: no valid traces registered\n";
1381a34c753fSRafael Auler     exit(1);
1382a34c753fSRafael Auler   }
1383a34c753fSRafael Auler 
13845c2ae5f4SVladislav Khmelevsky   HM.print(opts::OutputFilename);
13855c2ae5f4SVladislav Khmelevsky   if (opts::OutputFilename == "-")
13865c2ae5f4SVladislav Khmelevsky     HM.printCDF(opts::OutputFilename);
1387def464aaSAmir Ayupov   else
13885c2ae5f4SVladislav Khmelevsky     HM.printCDF(opts::OutputFilename + ".csv");
1389733dc3e5SRahman Lavaee   if (opts::OutputFilename == "-")
1390733dc3e5SRahman Lavaee     HM.printSectionHotness(opts::OutputFilename);
1391733dc3e5SRahman Lavaee   else
1392733dc3e5SRahman Lavaee     HM.printSectionHotness(opts::OutputFilename + "-section-hotness.csv");
1393a34c753fSRafael Auler 
1394a34c753fSRafael Auler   return std::error_code();
1395a34c753fSRafael Auler }
1396a34c753fSRafael Auler 
1397a34c753fSRafael Auler std::error_code DataAggregator::parseBranchEvents() {
1398a34c753fSRafael Auler   outs() << "PERF2BOLT: parse branch events...\n";
1399a34c753fSRafael Auler   NamedRegionTimer T("parseBranch", "Parsing branch events", TimerGroupName,
1400a34c753fSRafael Auler                      TimerGroupDesc, opts::TimeAggregator);
1401a34c753fSRafael Auler 
1402a34c753fSRafael Auler   uint64_t NumTotalSamples = 0;
1403a34c753fSRafael Auler   uint64_t NumEntries = 0;
1404a34c753fSRafael Auler   uint64_t NumSamples = 0;
1405a34c753fSRafael Auler   uint64_t NumSamplesNoLBR = 0;
1406a34c753fSRafael Auler   uint64_t NumTraces = 0;
1407a34c753fSRafael Auler   bool NeedsSkylakeFix = false;
1408a34c753fSRafael Auler 
1409a34c753fSRafael Auler   while (hasData() && NumTotalSamples < opts::MaxSamples) {
1410a34c753fSRafael Auler     ++NumTotalSamples;
1411a34c753fSRafael Auler 
1412a34c753fSRafael Auler     ErrorOr<PerfBranchSample> SampleRes = parseBranchSample();
1413a34c753fSRafael Auler     if (std::error_code EC = SampleRes.getError()) {
1414a34c753fSRafael Auler       if (EC == errc::no_such_process)
1415a34c753fSRafael Auler         continue;
1416a34c753fSRafael Auler       return EC;
1417a34c753fSRafael Auler     }
1418a34c753fSRafael Auler     ++NumSamples;
1419a34c753fSRafael Auler 
1420a34c753fSRafael Auler     PerfBranchSample &Sample = SampleRes.get();
1421a34c753fSRafael Auler     if (opts::WriteAutoFDOData)
1422a34c753fSRafael Auler       ++BasicSamples[Sample.PC];
1423a34c753fSRafael Auler 
1424a34c753fSRafael Auler     if (Sample.LBR.empty()) {
1425a34c753fSRafael Auler       ++NumSamplesNoLBR;
1426a34c753fSRafael Auler       continue;
1427a34c753fSRafael Auler     }
1428a34c753fSRafael Auler 
1429a34c753fSRafael Auler     NumEntries += Sample.LBR.size();
1430a34c753fSRafael Auler     if (BAT && Sample.LBR.size() == 32 && !NeedsSkylakeFix) {
1431a34c753fSRafael Auler       errs() << "PERF2BOLT-WARNING: using Intel Skylake bug workaround\n";
1432a34c753fSRafael Auler       NeedsSkylakeFix = true;
1433a34c753fSRafael Auler     }
1434a34c753fSRafael Auler 
1435a34c753fSRafael Auler     // LBRs are stored in reverse execution order. NextPC refers to the next
1436a34c753fSRafael Auler     // recorded executed PC.
1437a34c753fSRafael Auler     uint64_t NextPC = opts::UseEventPC ? Sample.PC : 0;
1438a34c753fSRafael Auler     uint32_t NumEntry = 0;
1439a34c753fSRafael Auler     for (const LBREntry &LBR : Sample.LBR) {
1440a34c753fSRafael Auler       ++NumEntry;
1441a34c753fSRafael Auler       // Hardware bug workaround: Intel Skylake (which has 32 LBR entries)
1442a34c753fSRafael Auler       // sometimes record entry 32 as an exact copy of entry 31. This will cause
1443a34c753fSRafael Auler       // us to likely record an invalid trace and generate a stale function for
1444a34c753fSRafael Auler       // BAT mode (non BAT disassembles the function and is able to ignore this
1445a34c753fSRafael Auler       // trace at aggregation time). Drop first 2 entries (last two, in
1446a34c753fSRafael Auler       // chronological order)
1447a34c753fSRafael Auler       if (NeedsSkylakeFix && NumEntry <= 2)
1448a34c753fSRafael Auler         continue;
1449a34c753fSRafael Auler       if (NextPC) {
1450a34c753fSRafael Auler         // Record fall-through trace.
1451a34c753fSRafael Auler         const uint64_t TraceFrom = LBR.To;
1452a34c753fSRafael Auler         const uint64_t TraceTo = NextPC;
1453a34c753fSRafael Auler         const BinaryFunction *TraceBF =
1454a34c753fSRafael Auler             getBinaryFunctionContainingAddress(TraceFrom);
1455a34c753fSRafael Auler         if (TraceBF && TraceBF->containsAddress(TraceTo)) {
1456a34c753fSRafael Auler           FTInfo &Info = FallthroughLBRs[Trace(TraceFrom, TraceTo)];
1457def464aaSAmir Ayupov           if (TraceBF->containsAddress(LBR.From))
1458a34c753fSRafael Auler             ++Info.InternCount;
1459def464aaSAmir Ayupov           else
1460a34c753fSRafael Auler             ++Info.ExternCount;
1461a34c753fSRafael Auler         } else {
1462a34c753fSRafael Auler           if (TraceBF && getBinaryFunctionContainingAddress(TraceTo)) {
1463a34c753fSRafael Auler             LLVM_DEBUG(dbgs()
1464a34c753fSRafael Auler                        << "Invalid trace starting in "
1465a34c753fSRafael Auler                        << TraceBF->getPrintName() << " @ "
1466a34c753fSRafael Auler                        << Twine::utohexstr(TraceFrom - TraceBF->getAddress())
1467a34c753fSRafael Auler                        << " and ending @ " << Twine::utohexstr(TraceTo)
1468a34c753fSRafael Auler                        << '\n');
1469a34c753fSRafael Auler             ++NumInvalidTraces;
1470a34c753fSRafael Auler           } else {
1471a34c753fSRafael Auler             LLVM_DEBUG(dbgs()
1472a34c753fSRafael Auler                        << "Out of range trace starting in "
1473a34c753fSRafael Auler                        << (TraceBF ? TraceBF->getPrintName() : "None") << " @ "
1474a34c753fSRafael Auler                        << Twine::utohexstr(
1475a34c753fSRafael Auler                               TraceFrom - (TraceBF ? TraceBF->getAddress() : 0))
1476a34c753fSRafael Auler                        << " and ending in "
1477a34c753fSRafael Auler                        << (getBinaryFunctionContainingAddress(TraceTo)
1478a34c753fSRafael Auler                                ? getBinaryFunctionContainingAddress(TraceTo)
1479a34c753fSRafael Auler                                      ->getPrintName()
1480a34c753fSRafael Auler                                : "None")
1481a34c753fSRafael Auler                        << " @ "
1482a34c753fSRafael Auler                        << Twine::utohexstr(
1483a34c753fSRafael Auler                               TraceTo -
1484a34c753fSRafael Auler                               (getBinaryFunctionContainingAddress(TraceTo)
1485a34c753fSRafael Auler                                    ? getBinaryFunctionContainingAddress(TraceTo)
1486a34c753fSRafael Auler                                          ->getAddress()
1487a34c753fSRafael Auler                                    : 0))
1488a34c753fSRafael Auler                        << '\n');
1489a34c753fSRafael Auler             ++NumLongRangeTraces;
1490a34c753fSRafael Auler           }
1491a34c753fSRafael Auler         }
1492a34c753fSRafael Auler         ++NumTraces;
1493a34c753fSRafael Auler       }
1494a34c753fSRafael Auler       NextPC = LBR.From;
1495a34c753fSRafael Auler 
1496a34c753fSRafael Auler       uint64_t From = LBR.From;
1497a34c753fSRafael Auler       if (!getBinaryFunctionContainingAddress(From))
1498a34c753fSRafael Auler         From = 0;
1499a34c753fSRafael Auler       uint64_t To = LBR.To;
1500a34c753fSRafael Auler       if (!getBinaryFunctionContainingAddress(To))
1501a34c753fSRafael Auler         To = 0;
1502a34c753fSRafael Auler       if (!From && !To)
1503a34c753fSRafael Auler         continue;
1504a34c753fSRafael Auler       BranchInfo &Info = BranchLBRs[Trace(From, To)];
1505a34c753fSRafael Auler       ++Info.TakenCount;
1506a34c753fSRafael Auler       Info.MispredCount += LBR.Mispred;
1507a34c753fSRafael Auler     }
1508a34c753fSRafael Auler   }
1509a34c753fSRafael Auler 
1510a34c753fSRafael Auler   for (const auto &LBR : BranchLBRs) {
1511a34c753fSRafael Auler     const Trace &Trace = LBR.first;
1512a34c753fSRafael Auler     if (BinaryFunction *BF = getBinaryFunctionContainingAddress(Trace.From))
1513a34c753fSRafael Auler       BF->setHasProfileAvailable();
1514a34c753fSRafael Auler     if (BinaryFunction *BF = getBinaryFunctionContainingAddress(Trace.To))
1515a34c753fSRafael Auler       BF->setHasProfileAvailable();
1516a34c753fSRafael Auler   }
1517a34c753fSRafael Auler 
1518a34c753fSRafael Auler   auto printColored = [](raw_ostream &OS, float Percent, float T1, float T2) {
1519a34c753fSRafael Auler     OS << " (";
1520a34c753fSRafael Auler     if (OS.has_colors()) {
1521def464aaSAmir Ayupov       if (Percent > T2)
1522a34c753fSRafael Auler         OS.changeColor(raw_ostream::RED);
1523def464aaSAmir Ayupov       else if (Percent > T1)
1524a34c753fSRafael Auler         OS.changeColor(raw_ostream::YELLOW);
1525def464aaSAmir Ayupov       else
1526a34c753fSRafael Auler         OS.changeColor(raw_ostream::GREEN);
1527a34c753fSRafael Auler     }
1528a34c753fSRafael Auler     OS << format("%.1f%%", Percent);
1529a34c753fSRafael Auler     if (OS.has_colors())
1530a34c753fSRafael Auler       OS.resetColor();
1531a34c753fSRafael Auler     OS << ")";
1532a34c753fSRafael Auler   };
1533a34c753fSRafael Auler 
153440c2e0faSMaksim Panchenko   outs() << "PERF2BOLT: read " << NumSamples << " samples and " << NumEntries
153540c2e0faSMaksim Panchenko          << " LBR entries\n";
1536a34c753fSRafael Auler   if (NumTotalSamples) {
1537a34c753fSRafael Auler     if (NumSamples && NumSamplesNoLBR == NumSamples) {
1538a34c753fSRafael Auler       // Note: we don't know if perf2bolt is being used to parse memory samples
1539a34c753fSRafael Auler       // at this point. In this case, it is OK to parse zero LBRs.
1540a34c753fSRafael Auler       errs() << "PERF2BOLT-WARNING: all recorded samples for this binary lack "
1541a34c753fSRafael Auler                 "LBR. Record profile with perf record -j any or run perf2bolt "
1542a34c753fSRafael Auler                 "in no-LBR mode with -nl (the performance improvement in -nl "
1543a34c753fSRafael Auler                 "mode may be limited)\n";
1544a34c753fSRafael Auler     } else {
1545a34c753fSRafael Auler       const uint64_t IgnoredSamples = NumTotalSamples - NumSamples;
1546a34c753fSRafael Auler       const float PercentIgnored = 100.0f * IgnoredSamples / NumTotalSamples;
1547a34c753fSRafael Auler       outs() << "PERF2BOLT: " << IgnoredSamples << " samples";
1548a34c753fSRafael Auler       printColored(outs(), PercentIgnored, 20, 50);
1549a34c753fSRafael Auler       outs() << " were ignored\n";
1550def464aaSAmir Ayupov       if (PercentIgnored > 50.0f)
1551a34c753fSRafael Auler         errs() << "PERF2BOLT-WARNING: less than 50% of all recorded samples "
1552a34c753fSRafael Auler                   "were attributed to the input binary\n";
1553a34c753fSRafael Auler     }
1554a34c753fSRafael Auler   }
1555a34c753fSRafael Auler   outs() << "PERF2BOLT: traces mismatching disassembled function contents: "
1556a34c753fSRafael Auler          << NumInvalidTraces;
1557a34c753fSRafael Auler   float Perc = 0.0f;
1558a34c753fSRafael Auler   if (NumTraces > 0) {
1559a34c753fSRafael Auler     Perc = NumInvalidTraces * 100.0f / NumTraces;
1560a34c753fSRafael Auler     printColored(outs(), Perc, 5, 10);
1561a34c753fSRafael Auler   }
1562a34c753fSRafael Auler   outs() << "\n";
1563def464aaSAmir Ayupov   if (Perc > 10.0f)
1564a34c753fSRafael Auler     outs() << "\n !! WARNING !! This high mismatch ratio indicates the input "
1565a34c753fSRafael Auler               "binary is probably not the same binary used during profiling "
1566a34c753fSRafael Auler               "collection. The generated data may be ineffective for improving "
1567a34c753fSRafael Auler               "performance.\n\n";
1568a34c753fSRafael Auler 
1569a34c753fSRafael Auler   outs() << "PERF2BOLT: out of range traces involving unknown regions: "
1570a34c753fSRafael Auler          << NumLongRangeTraces;
1571def464aaSAmir Ayupov   if (NumTraces > 0)
1572a34c753fSRafael Auler     outs() << format(" (%.1f%%)", NumLongRangeTraces * 100.0f / NumTraces);
1573a34c753fSRafael Auler   outs() << "\n";
1574a34c753fSRafael Auler 
1575a34c753fSRafael Auler   if (NumColdSamples > 0) {
1576a34c753fSRafael Auler     const float ColdSamples = NumColdSamples * 100.0f / NumTotalSamples;
1577a34c753fSRafael Auler     outs() << "PERF2BOLT: " << NumColdSamples
1578a34c753fSRafael Auler            << format(" (%.1f%%)", ColdSamples)
1579a34c753fSRafael Auler            << " samples recorded in cold regions of split functions.\n";
1580def464aaSAmir Ayupov     if (ColdSamples > 5.0f)
1581a34c753fSRafael Auler       outs()
1582a34c753fSRafael Auler           << "WARNING: The BOLT-processed binary where samples were collected "
1583a34c753fSRafael Auler              "likely used bad data or your service observed a large shift in "
1584a34c753fSRafael Auler              "profile. You may want to audit this.\n";
1585a34c753fSRafael Auler   }
1586a34c753fSRafael Auler 
1587a34c753fSRafael Auler   return std::error_code();
1588a34c753fSRafael Auler }
1589a34c753fSRafael Auler 
1590a34c753fSRafael Auler void DataAggregator::processBranchEvents() {
1591a34c753fSRafael Auler   outs() << "PERF2BOLT: processing branch events...\n";
1592a34c753fSRafael Auler   NamedRegionTimer T("processBranch", "Processing branch events",
1593a34c753fSRafael Auler                      TimerGroupName, TimerGroupDesc, opts::TimeAggregator);
1594a34c753fSRafael Auler 
1595a34c753fSRafael Auler   for (const auto &AggrLBR : FallthroughLBRs) {
1596a34c753fSRafael Auler     const Trace &Loc = AggrLBR.first;
1597a34c753fSRafael Auler     const FTInfo &Info = AggrLBR.second;
1598a34c753fSRafael Auler     LBREntry First{Loc.From, Loc.From, false};
1599a34c753fSRafael Auler     LBREntry Second{Loc.To, Loc.To, false};
1600def464aaSAmir Ayupov     if (Info.InternCount)
1601a34c753fSRafael Auler       doTrace(First, Second, Info.InternCount);
1602a34c753fSRafael Auler     if (Info.ExternCount) {
1603a34c753fSRafael Auler       First.From = 0;
1604a34c753fSRafael Auler       doTrace(First, Second, Info.ExternCount);
1605a34c753fSRafael Auler     }
1606a34c753fSRafael Auler   }
1607a34c753fSRafael Auler 
1608a34c753fSRafael Auler   for (const auto &AggrLBR : BranchLBRs) {
1609a34c753fSRafael Auler     const Trace &Loc = AggrLBR.first;
1610a34c753fSRafael Auler     const BranchInfo &Info = AggrLBR.second;
1611a34c753fSRafael Auler     doBranch(Loc.From, Loc.To, Info.TakenCount, Info.MispredCount);
1612a34c753fSRafael Auler   }
1613a34c753fSRafael Auler }
1614a34c753fSRafael Auler 
1615a34c753fSRafael Auler std::error_code DataAggregator::parseBasicEvents() {
1616a34c753fSRafael Auler   outs() << "PERF2BOLT: parsing basic events (without LBR)...\n";
1617a34c753fSRafael Auler   NamedRegionTimer T("parseBasic", "Parsing basic events", TimerGroupName,
1618a34c753fSRafael Auler                      TimerGroupDesc, opts::TimeAggregator);
1619a34c753fSRafael Auler   while (hasData()) {
1620a34c753fSRafael Auler     ErrorOr<PerfBasicSample> Sample = parseBasicSample();
1621a34c753fSRafael Auler     if (std::error_code EC = Sample.getError())
1622a34c753fSRafael Auler       return EC;
1623a34c753fSRafael Auler 
1624a34c753fSRafael Auler     if (!Sample->PC)
1625a34c753fSRafael Auler       continue;
1626a34c753fSRafael Auler 
1627a34c753fSRafael Auler     if (BinaryFunction *BF = getBinaryFunctionContainingAddress(Sample->PC))
1628a34c753fSRafael Auler       BF->setHasProfileAvailable();
1629a34c753fSRafael Auler 
1630a34c753fSRafael Auler     ++BasicSamples[Sample->PC];
1631a34c753fSRafael Auler     EventNames.insert(Sample->EventName);
1632a34c753fSRafael Auler   }
1633a34c753fSRafael Auler 
1634a34c753fSRafael Auler   return std::error_code();
1635a34c753fSRafael Auler }
1636a34c753fSRafael Auler 
1637a34c753fSRafael Auler void DataAggregator::processBasicEvents() {
1638a34c753fSRafael Auler   outs() << "PERF2BOLT: processing basic events (without LBR)...\n";
163940c2e0faSMaksim Panchenko   NamedRegionTimer T("processBasic", "Processing basic events", TimerGroupName,
164040c2e0faSMaksim Panchenko                      TimerGroupDesc, opts::TimeAggregator);
1641a34c753fSRafael Auler   uint64_t OutOfRangeSamples = 0;
1642a34c753fSRafael Auler   uint64_t NumSamples = 0;
1643a34c753fSRafael Auler   for (auto &Sample : BasicSamples) {
1644a34c753fSRafael Auler     const uint64_t PC = Sample.first;
1645a34c753fSRafael Auler     const uint64_t HitCount = Sample.second;
1646a34c753fSRafael Auler     NumSamples += HitCount;
1647a34c753fSRafael Auler     BinaryFunction *Func = getBinaryFunctionContainingAddress(PC);
1648a34c753fSRafael Auler     if (!Func) {
1649a34c753fSRafael Auler       OutOfRangeSamples += HitCount;
1650a34c753fSRafael Auler       continue;
1651a34c753fSRafael Auler     }
1652a34c753fSRafael Auler 
1653a34c753fSRafael Auler     doSample(*Func, PC, HitCount);
1654a34c753fSRafael Auler   }
1655a34c753fSRafael Auler   outs() << "PERF2BOLT: read " << NumSamples << " samples\n";
1656a34c753fSRafael Auler 
1657a34c753fSRafael Auler   outs() << "PERF2BOLT: out of range samples recorded in unknown regions: "
1658a34c753fSRafael Auler          << OutOfRangeSamples;
1659a34c753fSRafael Auler   float Perc = 0.0f;
1660a34c753fSRafael Auler   if (NumSamples > 0) {
1661a34c753fSRafael Auler     outs() << " (";
1662a34c753fSRafael Auler     Perc = OutOfRangeSamples * 100.0f / NumSamples;
1663a34c753fSRafael Auler     if (outs().has_colors()) {
1664def464aaSAmir Ayupov       if (Perc > 60.0f)
1665a34c753fSRafael Auler         outs().changeColor(raw_ostream::RED);
1666def464aaSAmir Ayupov       else if (Perc > 40.0f)
1667a34c753fSRafael Auler         outs().changeColor(raw_ostream::YELLOW);
1668def464aaSAmir Ayupov       else
1669a34c753fSRafael Auler         outs().changeColor(raw_ostream::GREEN);
1670a34c753fSRafael Auler     }
1671a34c753fSRafael Auler     outs() << format("%.1f%%", Perc);
1672a34c753fSRafael Auler     if (outs().has_colors())
1673a34c753fSRafael Auler       outs().resetColor();
1674a34c753fSRafael Auler     outs() << ")";
1675a34c753fSRafael Auler   }
1676a34c753fSRafael Auler   outs() << "\n";
1677def464aaSAmir Ayupov   if (Perc > 80.0f)
1678a34c753fSRafael Auler     outs() << "\n !! WARNING !! This high mismatch ratio indicates the input "
1679a34c753fSRafael Auler               "binary is probably not the same binary used during profiling "
1680a34c753fSRafael Auler               "collection. The generated data may be ineffective for improving "
1681a34c753fSRafael Auler               "performance.\n\n";
1682a34c753fSRafael Auler }
1683a34c753fSRafael Auler 
1684a34c753fSRafael Auler std::error_code DataAggregator::parseMemEvents() {
1685a34c753fSRafael Auler   outs() << "PERF2BOLT: parsing memory events...\n";
1686a34c753fSRafael Auler   NamedRegionTimer T("parseMemEvents", "Parsing mem events", TimerGroupName,
1687a34c753fSRafael Auler                      TimerGroupDesc, opts::TimeAggregator);
1688a34c753fSRafael Auler   while (hasData()) {
1689a34c753fSRafael Auler     ErrorOr<PerfMemSample> Sample = parseMemSample();
1690a34c753fSRafael Auler     if (std::error_code EC = Sample.getError())
1691a34c753fSRafael Auler       return EC;
1692a34c753fSRafael Auler 
1693a34c753fSRafael Auler     if (BinaryFunction *BF = getBinaryFunctionContainingAddress(Sample->PC))
1694a34c753fSRafael Auler       BF->setHasProfileAvailable();
1695a34c753fSRafael Auler 
1696a34c753fSRafael Auler     MemSamples.emplace_back(std::move(Sample.get()));
1697a34c753fSRafael Auler   }
1698a34c753fSRafael Auler 
1699a34c753fSRafael Auler   return std::error_code();
1700a34c753fSRafael Auler }
1701a34c753fSRafael Auler 
1702a34c753fSRafael Auler void DataAggregator::processMemEvents() {
1703a34c753fSRafael Auler   NamedRegionTimer T("ProcessMemEvents", "Processing mem events",
1704a34c753fSRafael Auler                      TimerGroupName, TimerGroupDesc, opts::TimeAggregator);
1705a34c753fSRafael Auler   for (const PerfMemSample &Sample : MemSamples) {
1706a34c753fSRafael Auler     uint64_t PC = Sample.PC;
1707a34c753fSRafael Auler     uint64_t Addr = Sample.Addr;
1708a34c753fSRafael Auler     StringRef FuncName;
1709a34c753fSRafael Auler     StringRef MemName;
1710a34c753fSRafael Auler 
1711a34c753fSRafael Auler     // Try to resolve symbol for PC
1712a34c753fSRafael Auler     BinaryFunction *Func = getBinaryFunctionContainingAddress(PC);
1713a34c753fSRafael Auler     if (!Func) {
1714a34c753fSRafael Auler       LLVM_DEBUG(if (PC != 0) {
1715a34c753fSRafael Auler         dbgs() << "Skipped mem event: 0x" << Twine::utohexstr(PC) << " => 0x"
1716a34c753fSRafael Auler                << Twine::utohexstr(Addr) << "\n";
1717a34c753fSRafael Auler       });
1718a34c753fSRafael Auler       continue;
1719a34c753fSRafael Auler     }
1720a34c753fSRafael Auler 
1721a34c753fSRafael Auler     FuncName = Func->getOneName();
1722a34c753fSRafael Auler     PC -= Func->getAddress();
1723a34c753fSRafael Auler 
1724a34c753fSRafael Auler     // Try to resolve symbol for memory load
1725a34c753fSRafael Auler     if (BinaryData *BD = BC->getBinaryDataContainingAddress(Addr)) {
1726a34c753fSRafael Auler       MemName = BD->getName();
1727a34c753fSRafael Auler       Addr -= BD->getAddress();
1728a34c753fSRafael Auler     } else if (opts::FilterMemProfile) {
1729a34c753fSRafael Auler       // Filter out heap/stack accesses
1730a34c753fSRafael Auler       continue;
1731a34c753fSRafael Auler     }
1732a34c753fSRafael Auler 
1733a34c753fSRafael Auler     const Location FuncLoc(!FuncName.empty(), FuncName, PC);
1734a34c753fSRafael Auler     const Location AddrLoc(!MemName.empty(), MemName, Addr);
1735a34c753fSRafael Auler 
1736a34c753fSRafael Auler     FuncMemData *MemData = &NamesToMemEvents[FuncName];
1737a34c753fSRafael Auler     setMemData(*Func, MemData);
1738a34c753fSRafael Auler     MemData->update(FuncLoc, AddrLoc);
1739a34c753fSRafael Auler     LLVM_DEBUG(dbgs() << "Mem event: " << FuncLoc << " = " << AddrLoc << "\n");
1740a34c753fSRafael Auler   }
1741a34c753fSRafael Auler }
1742a34c753fSRafael Auler 
1743a34c753fSRafael Auler std::error_code DataAggregator::parsePreAggregatedLBRSamples() {
1744a34c753fSRafael Auler   outs() << "PERF2BOLT: parsing pre-aggregated profile...\n";
1745a34c753fSRafael Auler   NamedRegionTimer T("parseAggregated", "Parsing aggregated branch events",
1746a34c753fSRafael Auler                      TimerGroupName, TimerGroupDesc, opts::TimeAggregator);
1747a34c753fSRafael Auler   while (hasData()) {
1748a34c753fSRafael Auler     ErrorOr<AggregatedLBREntry> AggrEntry = parseAggregatedLBREntry();
1749a34c753fSRafael Auler     if (std::error_code EC = AggrEntry.getError())
1750a34c753fSRafael Auler       return EC;
1751a34c753fSRafael Auler 
1752a34c753fSRafael Auler     if (BinaryFunction *BF =
1753a34c753fSRafael Auler             getBinaryFunctionContainingAddress(AggrEntry->From.Offset))
1754a34c753fSRafael Auler       BF->setHasProfileAvailable();
1755a34c753fSRafael Auler     if (BinaryFunction *BF =
1756a34c753fSRafael Auler             getBinaryFunctionContainingAddress(AggrEntry->To.Offset))
1757a34c753fSRafael Auler       BF->setHasProfileAvailable();
1758a34c753fSRafael Auler 
1759a34c753fSRafael Auler     AggregatedLBRs.emplace_back(std::move(AggrEntry.get()));
1760a34c753fSRafael Auler   }
1761a34c753fSRafael Auler 
1762a34c753fSRafael Auler   return std::error_code();
1763a34c753fSRafael Auler }
1764a34c753fSRafael Auler 
1765a34c753fSRafael Auler void DataAggregator::processPreAggregated() {
1766a34c753fSRafael Auler   outs() << "PERF2BOLT: processing pre-aggregated profile...\n";
1767a34c753fSRafael Auler   NamedRegionTimer T("processAggregated", "Processing aggregated branch events",
1768a34c753fSRafael Auler                      TimerGroupName, TimerGroupDesc, opts::TimeAggregator);
1769a34c753fSRafael Auler 
1770a34c753fSRafael Auler   uint64_t NumTraces = 0;
1771a34c753fSRafael Auler   for (const AggregatedLBREntry &AggrEntry : AggregatedLBRs) {
1772a34c753fSRafael Auler     switch (AggrEntry.EntryType) {
1773a34c753fSRafael Auler     case AggregatedLBREntry::BRANCH:
1774a34c753fSRafael Auler       doBranch(AggrEntry.From.Offset, AggrEntry.To.Offset, AggrEntry.Count,
1775a34c753fSRafael Auler                AggrEntry.Mispreds);
1776a34c753fSRafael Auler       break;
1777a34c753fSRafael Auler     case AggregatedLBREntry::FT:
1778a34c753fSRafael Auler     case AggregatedLBREntry::FT_EXTERNAL_ORIGIN: {
1779a34c753fSRafael Auler       LBREntry First{AggrEntry.EntryType == AggregatedLBREntry::FT
1780a34c753fSRafael Auler                          ? AggrEntry.From.Offset
1781a34c753fSRafael Auler                          : 0,
1782a34c753fSRafael Auler                      AggrEntry.From.Offset, false};
1783a34c753fSRafael Auler       LBREntry Second{AggrEntry.To.Offset, AggrEntry.To.Offset, false};
1784a34c753fSRafael Auler       doTrace(First, Second, AggrEntry.Count);
1785a34c753fSRafael Auler       NumTraces += AggrEntry.Count;
1786a34c753fSRafael Auler       break;
1787a34c753fSRafael Auler     }
1788a34c753fSRafael Auler     }
1789a34c753fSRafael Auler   }
1790a34c753fSRafael Auler 
1791a34c753fSRafael Auler   outs() << "PERF2BOLT: read " << AggregatedLBRs.size()
1792a34c753fSRafael Auler          << " aggregated LBR entries\n";
1793a34c753fSRafael Auler   outs() << "PERF2BOLT: traces mismatching disassembled function contents: "
1794a34c753fSRafael Auler          << NumInvalidTraces;
1795a34c753fSRafael Auler   float Perc = 0.0f;
1796a34c753fSRafael Auler   if (NumTraces > 0) {
1797a34c753fSRafael Auler     outs() << " (";
1798a34c753fSRafael Auler     Perc = NumInvalidTraces * 100.0f / NumTraces;
1799a34c753fSRafael Auler     if (outs().has_colors()) {
1800def464aaSAmir Ayupov       if (Perc > 10.0f)
1801a34c753fSRafael Auler         outs().changeColor(raw_ostream::RED);
1802def464aaSAmir Ayupov       else if (Perc > 5.0f)
1803a34c753fSRafael Auler         outs().changeColor(raw_ostream::YELLOW);
1804def464aaSAmir Ayupov       else
1805a34c753fSRafael Auler         outs().changeColor(raw_ostream::GREEN);
1806a34c753fSRafael Auler     }
1807a34c753fSRafael Auler     outs() << format("%.1f%%", Perc);
1808a34c753fSRafael Auler     if (outs().has_colors())
1809a34c753fSRafael Auler       outs().resetColor();
1810a34c753fSRafael Auler     outs() << ")";
1811a34c753fSRafael Auler   }
1812a34c753fSRafael Auler   outs() << "\n";
1813def464aaSAmir Ayupov   if (Perc > 10.0f)
1814a34c753fSRafael Auler     outs() << "\n !! WARNING !! This high mismatch ratio indicates the input "
1815a34c753fSRafael Auler               "binary is probably not the same binary used during profiling "
1816a34c753fSRafael Auler               "collection. The generated data may be ineffective for improving "
1817a34c753fSRafael Auler               "performance.\n\n";
1818a34c753fSRafael Auler 
1819a34c753fSRafael Auler   outs() << "PERF2BOLT: Out of range traces involving unknown regions: "
1820a34c753fSRafael Auler          << NumLongRangeTraces;
1821def464aaSAmir Ayupov   if (NumTraces > 0)
1822a34c753fSRafael Auler     outs() << format(" (%.1f%%)", NumLongRangeTraces * 100.0f / NumTraces);
1823a34c753fSRafael Auler   outs() << "\n";
1824a34c753fSRafael Auler }
1825a34c753fSRafael Auler 
1826*835a9c28SAmir Ayupov std::optional<int32_t> DataAggregator::parseCommExecEvent() {
1827a34c753fSRafael Auler   size_t LineEnd = ParsingBuf.find_first_of("\n");
1828a34c753fSRafael Auler   if (LineEnd == StringRef::npos) {
1829a34c753fSRafael Auler     reportError("expected rest of line");
1830a34c753fSRafael Auler     Diag << "Found: " << ParsingBuf << "\n";
1831e324a80fSKazu Hirata     return std::nullopt;
1832a34c753fSRafael Auler   }
1833a34c753fSRafael Auler   StringRef Line = ParsingBuf.substr(0, LineEnd);
1834a34c753fSRafael Auler 
1835a34c753fSRafael Auler   size_t Pos = Line.find("PERF_RECORD_COMM exec");
1836def464aaSAmir Ayupov   if (Pos == StringRef::npos)
1837e324a80fSKazu Hirata     return std::nullopt;
1838a34c753fSRafael Auler   Line = Line.drop_front(Pos);
1839a34c753fSRafael Auler 
1840a34c753fSRafael Auler   // Line:
1841a34c753fSRafael Auler   //  PERF_RECORD_COMM exec: <name>:<pid>/<tid>"
1842a34c753fSRafael Auler   StringRef PIDStr = Line.rsplit(':').second.split('/').first;
1843ae585be1SRafael Auler   int32_t PID;
1844a34c753fSRafael Auler   if (PIDStr.getAsInteger(10, PID)) {
1845a34c753fSRafael Auler     reportError("expected PID");
1846a34c753fSRafael Auler     Diag << "Found: " << PIDStr << "in '" << Line << "'\n";
1847e324a80fSKazu Hirata     return std::nullopt;
1848a34c753fSRafael Auler   }
1849a34c753fSRafael Auler 
1850a34c753fSRafael Auler   return PID;
1851a34c753fSRafael Auler }
1852a34c753fSRafael Auler 
1853a34c753fSRafael Auler namespace {
1854*835a9c28SAmir Ayupov std::optional<uint64_t> parsePerfTime(const StringRef TimeStr) {
1855a34c753fSRafael Auler   const StringRef SecTimeStr = TimeStr.split('.').first;
1856a34c753fSRafael Auler   const StringRef USecTimeStr = TimeStr.split('.').second;
1857a34c753fSRafael Auler   uint64_t SecTime;
1858a34c753fSRafael Auler   uint64_t USecTime;
1859a34c753fSRafael Auler   if (SecTimeStr.getAsInteger(10, SecTime) ||
1860def464aaSAmir Ayupov       USecTimeStr.getAsInteger(10, USecTime))
1861e324a80fSKazu Hirata     return std::nullopt;
1862a34c753fSRafael Auler   return SecTime * 1000000ULL + USecTime;
1863a34c753fSRafael Auler }
1864a34c753fSRafael Auler }
1865a34c753fSRafael Auler 
1866*835a9c28SAmir Ayupov std::optional<DataAggregator::ForkInfo> DataAggregator::parseForkEvent() {
186740c2e0faSMaksim Panchenko   while (checkAndConsumeFS()) {
186840c2e0faSMaksim Panchenko   }
1869a34c753fSRafael Auler 
1870a34c753fSRafael Auler   size_t LineEnd = ParsingBuf.find_first_of("\n");
1871a34c753fSRafael Auler   if (LineEnd == StringRef::npos) {
1872a34c753fSRafael Auler     reportError("expected rest of line");
1873a34c753fSRafael Auler     Diag << "Found: " << ParsingBuf << "\n";
1874e324a80fSKazu Hirata     return std::nullopt;
1875a34c753fSRafael Auler   }
1876a34c753fSRafael Auler   StringRef Line = ParsingBuf.substr(0, LineEnd);
1877a34c753fSRafael Auler 
1878a34c753fSRafael Auler   size_t Pos = Line.find("PERF_RECORD_FORK");
1879a34c753fSRafael Auler   if (Pos == StringRef::npos) {
1880a34c753fSRafael Auler     consumeRestOfLine();
1881e324a80fSKazu Hirata     return std::nullopt;
1882a34c753fSRafael Auler   }
1883a34c753fSRafael Auler 
1884a34c753fSRafael Auler   ForkInfo FI;
1885a34c753fSRafael Auler 
1886a34c753fSRafael Auler   const StringRef TimeStr =
1887a34c753fSRafael Auler       Line.substr(0, Pos).rsplit(':').first.rsplit(FieldSeparator).second;
1888*835a9c28SAmir Ayupov   if (std::optional<uint64_t> TimeRes = parsePerfTime(TimeStr)) {
1889a34c753fSRafael Auler     FI.Time = *TimeRes;
1890a34c753fSRafael Auler   }
1891a34c753fSRafael Auler 
1892a34c753fSRafael Auler   Line = Line.drop_front(Pos);
1893a34c753fSRafael Auler 
1894a34c753fSRafael Auler   // Line:
1895a34c753fSRafael Auler   //  PERF_RECORD_FORK(<child_pid>:<child_tid>):(<parent_pid>:<parent_tid>)
1896a34c753fSRafael Auler   const StringRef ChildPIDStr = Line.split('(').second.split(':').first;
1897a34c753fSRafael Auler   if (ChildPIDStr.getAsInteger(10, FI.ChildPID)) {
1898a34c753fSRafael Auler     reportError("expected PID");
1899a34c753fSRafael Auler     Diag << "Found: " << ChildPIDStr << "in '" << Line << "'\n";
1900e324a80fSKazu Hirata     return std::nullopt;
1901a34c753fSRafael Auler   }
1902a34c753fSRafael Auler 
1903a34c753fSRafael Auler   const StringRef ParentPIDStr = Line.rsplit('(').second.split(':').first;
1904a34c753fSRafael Auler   if (ParentPIDStr.getAsInteger(10, FI.ParentPID)) {
1905a34c753fSRafael Auler     reportError("expected PID");
1906a34c753fSRafael Auler     Diag << "Found: " << ParentPIDStr << "in '" << Line << "'\n";
1907e324a80fSKazu Hirata     return std::nullopt;
1908a34c753fSRafael Auler   }
1909a34c753fSRafael Auler 
1910a34c753fSRafael Auler   consumeRestOfLine();
1911a34c753fSRafael Auler 
1912a34c753fSRafael Auler   return FI;
1913a34c753fSRafael Auler }
1914a34c753fSRafael Auler 
1915a34c753fSRafael Auler ErrorOr<std::pair<StringRef, DataAggregator::MMapInfo>>
1916a34c753fSRafael Auler DataAggregator::parseMMapEvent() {
191740c2e0faSMaksim Panchenko   while (checkAndConsumeFS()) {
191840c2e0faSMaksim Panchenko   }
1919a34c753fSRafael Auler 
1920a34c753fSRafael Auler   MMapInfo ParsedInfo;
1921a34c753fSRafael Auler 
1922a34c753fSRafael Auler   size_t LineEnd = ParsingBuf.find_first_of("\n");
1923a34c753fSRafael Auler   if (LineEnd == StringRef::npos) {
1924a34c753fSRafael Auler     reportError("expected rest of line");
1925a34c753fSRafael Auler     Diag << "Found: " << ParsingBuf << "\n";
1926a34c753fSRafael Auler     return make_error_code(llvm::errc::io_error);
1927a34c753fSRafael Auler   }
1928a34c753fSRafael Auler   StringRef Line = ParsingBuf.substr(0, LineEnd);
1929a34c753fSRafael Auler 
1930a34c753fSRafael Auler   size_t Pos = Line.find("PERF_RECORD_MMAP2");
1931a34c753fSRafael Auler   if (Pos == StringRef::npos) {
1932a34c753fSRafael Auler     consumeRestOfLine();
1933a34c753fSRafael Auler     return std::make_pair(StringRef(), ParsedInfo);
1934a34c753fSRafael Auler   }
1935a34c753fSRafael Auler 
1936a34c753fSRafael Auler   // Line:
1937a34c753fSRafael Auler   //   {<name> .* <sec>.<usec>: }PERF_RECORD_MMAP2 <pid>/<tid>: .* <file_name>
1938a34c753fSRafael Auler 
1939a34c753fSRafael Auler   const StringRef TimeStr =
1940a34c753fSRafael Auler       Line.substr(0, Pos).rsplit(':').first.rsplit(FieldSeparator).second;
1941*835a9c28SAmir Ayupov   if (std::optional<uint64_t> TimeRes = parsePerfTime(TimeStr))
1942a34c753fSRafael Auler     ParsedInfo.Time = *TimeRes;
1943a34c753fSRafael Auler 
1944a34c753fSRafael Auler   Line = Line.drop_front(Pos);
1945a34c753fSRafael Auler 
1946a34c753fSRafael Auler   // Line:
1947a34c753fSRafael Auler   //   PERF_RECORD_MMAP2 <pid>/<tid>: [<hexbase>(<hexsize>) .*]: .* <file_name>
1948a34c753fSRafael Auler 
1949a34c753fSRafael Auler   StringRef FileName = Line.rsplit(FieldSeparator).second;
1950a34c753fSRafael Auler   if (FileName.startswith("//") || FileName.startswith("[")) {
1951a34c753fSRafael Auler     consumeRestOfLine();
1952a34c753fSRafael Auler     return std::make_pair(StringRef(), ParsedInfo);
1953a34c753fSRafael Auler   }
1954a34c753fSRafael Auler   FileName = sys::path::filename(FileName);
1955a34c753fSRafael Auler 
1956a34c753fSRafael Auler   const StringRef PIDStr = Line.split(FieldSeparator).second.split('/').first;
1957a34c753fSRafael Auler   if (PIDStr.getAsInteger(10, ParsedInfo.PID)) {
1958a34c753fSRafael Auler     reportError("expected PID");
1959a34c753fSRafael Auler     Diag << "Found: " << PIDStr << "in '" << Line << "'\n";
1960a34c753fSRafael Auler     return make_error_code(llvm::errc::io_error);
1961a34c753fSRafael Auler   }
1962a34c753fSRafael Auler 
1963a34c753fSRafael Auler   const StringRef BaseAddressStr = Line.split('[').second.split('(').first;
196477b75ca5SMaksim Panchenko   if (BaseAddressStr.getAsInteger(0, ParsedInfo.MMapAddress)) {
1965a34c753fSRafael Auler     reportError("expected base address");
1966a34c753fSRafael Auler     Diag << "Found: " << BaseAddressStr << "in '" << Line << "'\n";
1967a34c753fSRafael Auler     return make_error_code(llvm::errc::io_error);
1968a34c753fSRafael Auler   }
1969a34c753fSRafael Auler 
1970a34c753fSRafael Auler   const StringRef SizeStr = Line.split('(').second.split(')').first;
1971a34c753fSRafael Auler   if (SizeStr.getAsInteger(0, ParsedInfo.Size)) {
1972a34c753fSRafael Auler     reportError("expected mmaped size");
1973a34c753fSRafael Auler     Diag << "Found: " << SizeStr << "in '" << Line << "'\n";
1974a34c753fSRafael Auler     return make_error_code(llvm::errc::io_error);
1975a34c753fSRafael Auler   }
1976a34c753fSRafael Auler 
1977a34c753fSRafael Auler   const StringRef OffsetStr =
1978a34c753fSRafael Auler       Line.split('@').second.ltrim().split(FieldSeparator).first;
1979a34c753fSRafael Auler   if (OffsetStr.getAsInteger(0, ParsedInfo.Offset)) {
1980a34c753fSRafael Auler     reportError("expected mmaped page-aligned offset");
1981a34c753fSRafael Auler     Diag << "Found: " << OffsetStr << "in '" << Line << "'\n";
1982a34c753fSRafael Auler     return make_error_code(llvm::errc::io_error);
1983a34c753fSRafael Auler   }
1984a34c753fSRafael Auler 
1985a34c753fSRafael Auler   consumeRestOfLine();
1986a34c753fSRafael Auler 
1987a34c753fSRafael Auler   return std::make_pair(FileName, ParsedInfo);
1988a34c753fSRafael Auler }
1989a34c753fSRafael Auler 
1990a34c753fSRafael Auler std::error_code DataAggregator::parseMMapEvents() {
1991a34c753fSRafael Auler   outs() << "PERF2BOLT: parsing perf-script mmap events output\n";
1992a34c753fSRafael Auler   NamedRegionTimer T("parseMMapEvents", "Parsing mmap events", TimerGroupName,
1993a34c753fSRafael Auler                      TimerGroupDesc, opts::TimeAggregator);
1994a34c753fSRafael Auler 
1995a34c753fSRafael Auler   std::multimap<StringRef, MMapInfo> GlobalMMapInfo;
1996a34c753fSRafael Auler   while (hasData()) {
1997a34c753fSRafael Auler     ErrorOr<std::pair<StringRef, MMapInfo>> FileMMapInfoRes = parseMMapEvent();
1998a34c753fSRafael Auler     if (std::error_code EC = FileMMapInfoRes.getError())
1999a34c753fSRafael Auler       return EC;
2000a34c753fSRafael Auler 
2001a34c753fSRafael Auler     std::pair<StringRef, MMapInfo> FileMMapInfo = FileMMapInfoRes.get();
2002a34c753fSRafael Auler     if (FileMMapInfo.second.PID == -1)
2003a34c753fSRafael Auler       continue;
2004a34c753fSRafael Auler 
2005a34c753fSRafael Auler     // Consider only the first mapping of the file for any given PID
2006a34c753fSRafael Auler     bool PIDExists = false;
2007a34c753fSRafael Auler     auto Range = GlobalMMapInfo.equal_range(FileMMapInfo.first);
2008a34c753fSRafael Auler     for (auto MI = Range.first; MI != Range.second; ++MI) {
2009a34c753fSRafael Auler       if (MI->second.PID == FileMMapInfo.second.PID) {
2010a34c753fSRafael Auler         PIDExists = true;
2011a34c753fSRafael Auler         break;
2012a34c753fSRafael Auler       }
2013a34c753fSRafael Auler     }
2014a34c753fSRafael Auler     if (PIDExists)
2015a34c753fSRafael Auler       continue;
2016a34c753fSRafael Auler 
2017a34c753fSRafael Auler     GlobalMMapInfo.insert(FileMMapInfo);
2018a34c753fSRafael Auler   }
2019a34c753fSRafael Auler 
2020a34c753fSRafael Auler   LLVM_DEBUG({
2021a34c753fSRafael Auler     dbgs() << "FileName -> mmap info:\n";
2022def464aaSAmir Ayupov     for (const std::pair<const StringRef, MMapInfo> &Pair : GlobalMMapInfo)
2023a34c753fSRafael Auler       dbgs() << "  " << Pair.first << " : " << Pair.second.PID << " [0x"
202477b75ca5SMaksim Panchenko              << Twine::utohexstr(Pair.second.MMapAddress) << ", "
2025a34c753fSRafael Auler              << Twine::utohexstr(Pair.second.Size) << " @ "
2026a34c753fSRafael Auler              << Twine::utohexstr(Pair.second.Offset) << "]\n";
2027a34c753fSRafael Auler   });
2028a34c753fSRafael Auler 
2029a34c753fSRafael Auler   StringRef NameToUse = llvm::sys::path::filename(BC->getFilename());
2030a34c753fSRafael Auler   if (GlobalMMapInfo.count(NameToUse) == 0 && !BuildIDBinaryName.empty()) {
2031a34c753fSRafael Auler     errs() << "PERF2BOLT-WARNING: using \"" << BuildIDBinaryName
2032a34c753fSRafael Auler            << "\" for profile matching\n";
2033a34c753fSRafael Auler     NameToUse = BuildIDBinaryName;
2034a34c753fSRafael Auler   }
2035a34c753fSRafael Auler 
2036a34c753fSRafael Auler   auto Range = GlobalMMapInfo.equal_range(NameToUse);
2037a34c753fSRafael Auler   for (auto I = Range.first; I != Range.second; ++I) {
203877b75ca5SMaksim Panchenko     MMapInfo &MMapInfo = I->second;
203977b75ca5SMaksim Panchenko     if (BC->HasFixedLoadAddress && MMapInfo.MMapAddress) {
2040a34c753fSRafael Auler       // Check that the binary mapping matches one of the segments.
2041f119a248SAmir Ayupov       bool MatchFound = llvm::any_of(
2042f119a248SAmir Ayupov           llvm::make_second_range(BC->SegmentMapInfo),
2043f119a248SAmir Ayupov           [&](SegmentInfo &SegInfo) {
204477b75ca5SMaksim Panchenko             // The mapping is page-aligned and hence the MMapAddress could be
2045a34c753fSRafael Auler             // different from the segment start address. We cannot know the page
2046a34c753fSRafael Auler             // size of the mapping, but we know it should not exceed the segment
2047a34c753fSRafael Auler             // alignment value. Hence we are performing an approximate check.
2048f119a248SAmir Ayupov             return SegInfo.Address >= MMapInfo.MMapAddress &&
2049f119a248SAmir Ayupov                    SegInfo.Address - MMapInfo.MMapAddress < SegInfo.Alignment;
2050f119a248SAmir Ayupov           });
2051a34c753fSRafael Auler       if (!MatchFound) {
2052a34c753fSRafael Auler         errs() << "PERF2BOLT-WARNING: ignoring mapping of " << NameToUse
205377b75ca5SMaksim Panchenko                << " at 0x" << Twine::utohexstr(MMapInfo.MMapAddress) << '\n';
2054a34c753fSRafael Auler         continue;
2055a34c753fSRafael Auler       }
2056a34c753fSRafael Auler     }
2057a34c753fSRafael Auler 
205877b75ca5SMaksim Panchenko     // Set base address for shared objects.
205977b75ca5SMaksim Panchenko     if (!BC->HasFixedLoadAddress) {
206077b75ca5SMaksim Panchenko       Optional<uint64_t> BaseAddress =
206177b75ca5SMaksim Panchenko           BC->getBaseAddressForMapping(MMapInfo.MMapAddress, MMapInfo.Offset);
206277b75ca5SMaksim Panchenko       if (!BaseAddress) {
206377b75ca5SMaksim Panchenko         errs() << "PERF2BOLT-WARNING: unable to find base address of the "
206477b75ca5SMaksim Panchenko                   "binary when memory mapped at 0x"
206577b75ca5SMaksim Panchenko                << Twine::utohexstr(MMapInfo.MMapAddress)
206677b75ca5SMaksim Panchenko                << " using file offset 0x" << Twine::utohexstr(MMapInfo.Offset)
206777b75ca5SMaksim Panchenko                << ". Ignoring profile data for this mapping\n";
206877b75ca5SMaksim Panchenko         continue;
206977b75ca5SMaksim Panchenko       } else {
207077b75ca5SMaksim Panchenko         MMapInfo.BaseAddress = *BaseAddress;
207177b75ca5SMaksim Panchenko       }
207277b75ca5SMaksim Panchenko     }
207377b75ca5SMaksim Panchenko 
2074a34c753fSRafael Auler     BinaryMMapInfo.insert(std::make_pair(MMapInfo.PID, MMapInfo));
2075a34c753fSRafael Auler   }
2076a34c753fSRafael Auler 
2077a34c753fSRafael Auler   if (BinaryMMapInfo.empty()) {
2078a34c753fSRafael Auler     if (errs().has_colors())
2079a34c753fSRafael Auler       errs().changeColor(raw_ostream::RED);
2080a34c753fSRafael Auler     errs() << "PERF2BOLT-ERROR: could not find a profile matching binary \""
2081a34c753fSRafael Auler            << BC->getFilename() << "\".";
2082a34c753fSRafael Auler     if (!GlobalMMapInfo.empty()) {
2083a34c753fSRafael Auler       errs() << " Profile for the following binary name(s) is available:\n";
2084a34c753fSRafael Auler       for (auto I = GlobalMMapInfo.begin(), IE = GlobalMMapInfo.end(); I != IE;
2085def464aaSAmir Ayupov            I = GlobalMMapInfo.upper_bound(I->first))
2086a34c753fSRafael Auler         errs() << "  " << I->first << '\n';
2087a34c753fSRafael Auler       errs() << "Please rename the input binary.\n";
2088a34c753fSRafael Auler     } else {
2089a34c753fSRafael Auler       errs() << " Failed to extract any binary name from a profile.\n";
2090a34c753fSRafael Auler     }
2091a34c753fSRafael Auler     if (errs().has_colors())
2092a34c753fSRafael Auler       errs().resetColor();
2093a34c753fSRafael Auler 
2094a34c753fSRafael Auler     exit(1);
2095a34c753fSRafael Auler   }
2096a34c753fSRafael Auler 
2097a34c753fSRafael Auler   return std::error_code();
2098a34c753fSRafael Auler }
2099a34c753fSRafael Auler 
2100a34c753fSRafael Auler std::error_code DataAggregator::parseTaskEvents() {
2101a34c753fSRafael Auler   outs() << "PERF2BOLT: parsing perf-script task events output\n";
2102a34c753fSRafael Auler   NamedRegionTimer T("parseTaskEvents", "Parsing task events", TimerGroupName,
2103a34c753fSRafael Auler                      TimerGroupDesc, opts::TimeAggregator);
2104a34c753fSRafael Auler 
2105a34c753fSRafael Auler   while (hasData()) {
2106*835a9c28SAmir Ayupov     if (std::optional<int32_t> CommInfo = parseCommExecEvent()) {
2107a34c753fSRafael Auler       // Remove forked child that ran execve
2108a34c753fSRafael Auler       auto MMapInfoIter = BinaryMMapInfo.find(*CommInfo);
2109def464aaSAmir Ayupov       if (MMapInfoIter != BinaryMMapInfo.end() && MMapInfoIter->second.Forked)
2110a34c753fSRafael Auler         BinaryMMapInfo.erase(MMapInfoIter);
2111a34c753fSRafael Auler       consumeRestOfLine();
2112a34c753fSRafael Auler       continue;
2113a34c753fSRafael Auler     }
2114a34c753fSRafael Auler 
2115*835a9c28SAmir Ayupov     std::optional<ForkInfo> ForkInfo = parseForkEvent();
2116a34c753fSRafael Auler     if (!ForkInfo)
2117a34c753fSRafael Auler       continue;
2118a34c753fSRafael Auler 
2119a34c753fSRafael Auler     if (ForkInfo->ParentPID == ForkInfo->ChildPID)
2120a34c753fSRafael Auler       continue;
2121a34c753fSRafael Auler 
2122a34c753fSRafael Auler     if (ForkInfo->Time == 0) {
2123a34c753fSRafael Auler       // Process was forked and mmaped before perf ran. In this case the child
2124a34c753fSRafael Auler       // should have its own mmap entry unless it was execve'd.
2125a34c753fSRafael Auler       continue;
2126a34c753fSRafael Auler     }
2127a34c753fSRafael Auler 
2128a34c753fSRafael Auler     auto MMapInfoIter = BinaryMMapInfo.find(ForkInfo->ParentPID);
2129a34c753fSRafael Auler     if (MMapInfoIter == BinaryMMapInfo.end())
2130a34c753fSRafael Auler       continue;
2131a34c753fSRafael Auler 
2132a34c753fSRafael Auler     MMapInfo MMapInfo = MMapInfoIter->second;
2133a34c753fSRafael Auler     MMapInfo.PID = ForkInfo->ChildPID;
2134a34c753fSRafael Auler     MMapInfo.Forked = true;
2135a34c753fSRafael Auler     BinaryMMapInfo.insert(std::make_pair(MMapInfo.PID, MMapInfo));
2136a34c753fSRafael Auler   }
2137a34c753fSRafael Auler 
2138a34c753fSRafael Auler   outs() << "PERF2BOLT: input binary is associated with "
2139a34c753fSRafael Auler          << BinaryMMapInfo.size() << " PID(s)\n";
2140a34c753fSRafael Auler 
2141a34c753fSRafael Auler   LLVM_DEBUG({
2142def464aaSAmir Ayupov     for (std::pair<const uint64_t, MMapInfo> &MMI : BinaryMMapInfo)
2143a34c753fSRafael Auler       outs() << "  " << MMI.second.PID << (MMI.second.Forked ? " (forked)" : "")
214477b75ca5SMaksim Panchenko              << ": (0x" << Twine::utohexstr(MMI.second.MMapAddress) << ": 0x"
214540c2e0faSMaksim Panchenko              << Twine::utohexstr(MMI.second.Size) << ")\n";
2146a34c753fSRafael Auler   });
2147a34c753fSRafael Auler 
2148a34c753fSRafael Auler   return std::error_code();
2149a34c753fSRafael Auler }
2150a34c753fSRafael Auler 
2151*835a9c28SAmir Ayupov std::optional<std::pair<StringRef, StringRef>>
2152a34c753fSRafael Auler DataAggregator::parseNameBuildIDPair() {
215340c2e0faSMaksim Panchenko   while (checkAndConsumeFS()) {
215440c2e0faSMaksim Panchenko   }
2155a34c753fSRafael Auler 
2156a34c753fSRafael Auler   ErrorOr<StringRef> BuildIDStr = parseString(FieldSeparator, true);
2157a34c753fSRafael Auler   if (std::error_code EC = BuildIDStr.getError())
2158e324a80fSKazu Hirata     return std::nullopt;
2159a34c753fSRafael Auler 
2160661577b5SMaksim Panchenko   // If one of the strings is missing, don't issue a parsing error, but still
2161661577b5SMaksim Panchenko   // do not return a value.
2162e549ac07SRafael Auler   consumeAllRemainingFS();
2163ba9cc653SRafael Auler   if (checkNewLine())
2164e324a80fSKazu Hirata     return std::nullopt;
2165661577b5SMaksim Panchenko 
2166a34c753fSRafael Auler   ErrorOr<StringRef> NameStr = parseString(FieldSeparator, true);
2167a34c753fSRafael Auler   if (std::error_code EC = NameStr.getError())
2168e324a80fSKazu Hirata     return std::nullopt;
2169a34c753fSRafael Auler 
2170a34c753fSRafael Auler   consumeRestOfLine();
2171a34c753fSRafael Auler   return std::make_pair(NameStr.get(), BuildIDStr.get());
2172a34c753fSRafael Auler }
2173a34c753fSRafael Auler 
2174661577b5SMaksim Panchenko bool DataAggregator::hasAllBuildIDs() {
2175661577b5SMaksim Panchenko   const StringRef SavedParsingBuf = ParsingBuf;
2176661577b5SMaksim Panchenko 
2177661577b5SMaksim Panchenko   if (!hasData())
2178661577b5SMaksim Panchenko     return false;
2179661577b5SMaksim Panchenko 
2180661577b5SMaksim Panchenko   bool HasInvalidEntries = false;
2181661577b5SMaksim Panchenko   while (hasData()) {
2182661577b5SMaksim Panchenko     if (!parseNameBuildIDPair()) {
2183661577b5SMaksim Panchenko       HasInvalidEntries = true;
2184661577b5SMaksim Panchenko       break;
2185661577b5SMaksim Panchenko     }
2186661577b5SMaksim Panchenko   }
2187661577b5SMaksim Panchenko 
2188661577b5SMaksim Panchenko   ParsingBuf = SavedParsingBuf;
2189661577b5SMaksim Panchenko 
2190661577b5SMaksim Panchenko   return !HasInvalidEntries;
2191661577b5SMaksim Panchenko }
2192661577b5SMaksim Panchenko 
2193*835a9c28SAmir Ayupov std::optional<StringRef>
2194a34c753fSRafael Auler DataAggregator::getFileNameForBuildID(StringRef FileBuildID) {
2195661577b5SMaksim Panchenko   const StringRef SavedParsingBuf = ParsingBuf;
2196661577b5SMaksim Panchenko 
2197661577b5SMaksim Panchenko   StringRef FileName;
2198a34c753fSRafael Auler   while (hasData()) {
2199*835a9c28SAmir Ayupov     std::optional<std::pair<StringRef, StringRef>> IDPair =
2200*835a9c28SAmir Ayupov         parseNameBuildIDPair();
2201661577b5SMaksim Panchenko     if (!IDPair) {
2202661577b5SMaksim Panchenko       consumeRestOfLine();
2203661577b5SMaksim Panchenko       continue;
2204a34c753fSRafael Auler     }
2205661577b5SMaksim Panchenko 
2206661577b5SMaksim Panchenko     if (IDPair->second.startswith(FileBuildID)) {
2207661577b5SMaksim Panchenko       FileName = sys::path::filename(IDPair->first);
2208661577b5SMaksim Panchenko       break;
2209661577b5SMaksim Panchenko     }
2210661577b5SMaksim Panchenko   }
2211661577b5SMaksim Panchenko 
2212661577b5SMaksim Panchenko   ParsingBuf = SavedParsingBuf;
2213661577b5SMaksim Panchenko 
2214661577b5SMaksim Panchenko   if (!FileName.empty())
2215661577b5SMaksim Panchenko     return FileName;
2216661577b5SMaksim Panchenko 
2217e324a80fSKazu Hirata   return std::nullopt;
2218a34c753fSRafael Auler }
2219a34c753fSRafael Auler 
2220a34c753fSRafael Auler std::error_code
2221a34c753fSRafael Auler DataAggregator::writeAggregatedFile(StringRef OutputFilename) const {
2222a34c753fSRafael Auler   std::error_code EC;
2223a34c753fSRafael Auler   raw_fd_ostream OutFile(OutputFilename, EC, sys::fs::OpenFlags::OF_None);
2224a34c753fSRafael Auler   if (EC)
2225a34c753fSRafael Auler     return EC;
2226a34c753fSRafael Auler 
2227a34c753fSRafael Auler   bool WriteMemLocs = false;
2228a34c753fSRafael Auler 
2229a34c753fSRafael Auler   auto writeLocation = [&OutFile, &WriteMemLocs](const Location &Loc) {
2230a34c753fSRafael Auler     if (WriteMemLocs)
2231a34c753fSRafael Auler       OutFile << (Loc.IsSymbol ? "4 " : "3 ");
2232a34c753fSRafael Auler     else
2233a34c753fSRafael Auler       OutFile << (Loc.IsSymbol ? "1 " : "0 ");
2234a34c753fSRafael Auler     OutFile << (Loc.Name.empty() ? "[unknown]" : getEscapedName(Loc.Name))
2235a34c753fSRafael Auler             << " " << Twine::utohexstr(Loc.Offset) << FieldSeparator;
2236a34c753fSRafael Auler   };
2237a34c753fSRafael Auler 
2238a34c753fSRafael Auler   uint64_t BranchValues = 0;
2239a34c753fSRafael Auler   uint64_t MemValues = 0;
2240a34c753fSRafael Auler 
2241a34c753fSRafael Auler   if (BAT)
2242a34c753fSRafael Auler     OutFile << "boltedcollection\n";
2243a34c753fSRafael Auler   if (opts::BasicAggregation) {
2244a34c753fSRafael Auler     OutFile << "no_lbr";
224534bcadc3SKazu Hirata     for (const StringMapEntry<std::nullopt_t> &Entry : EventNames)
2246a34c753fSRafael Auler       OutFile << " " << Entry.getKey();
2247a34c753fSRafael Auler     OutFile << "\n";
2248a34c753fSRafael Auler 
2249a34c753fSRafael Auler     for (const StringMapEntry<FuncSampleData> &Func : NamesToSamples) {
2250a34c753fSRafael Auler       for (const SampleInfo &SI : Func.getValue().Data) {
2251a34c753fSRafael Auler         writeLocation(SI.Loc);
2252a34c753fSRafael Auler         OutFile << SI.Hits << "\n";
2253a34c753fSRafael Auler         ++BranchValues;
2254a34c753fSRafael Auler       }
2255a34c753fSRafael Auler     }
2256a34c753fSRafael Auler   } else {
2257a34c753fSRafael Auler     for (const StringMapEntry<FuncBranchData> &Func : NamesToBranches) {
2258a34c753fSRafael Auler       for (const llvm::bolt::BranchInfo &BI : Func.getValue().Data) {
2259a34c753fSRafael Auler         writeLocation(BI.From);
2260a34c753fSRafael Auler         writeLocation(BI.To);
2261a34c753fSRafael Auler         OutFile << BI.Mispreds << " " << BI.Branches << "\n";
2262a34c753fSRafael Auler         ++BranchValues;
2263a34c753fSRafael Auler       }
2264a34c753fSRafael Auler       for (const llvm::bolt::BranchInfo &BI : Func.getValue().EntryData) {
2265a34c753fSRafael Auler         // Do not output if source is a known symbol, since this was already
2266a34c753fSRafael Auler         // accounted for in the source function
2267a34c753fSRafael Auler         if (BI.From.IsSymbol)
2268a34c753fSRafael Auler           continue;
2269a34c753fSRafael Auler         writeLocation(BI.From);
2270a34c753fSRafael Auler         writeLocation(BI.To);
2271a34c753fSRafael Auler         OutFile << BI.Mispreds << " " << BI.Branches << "\n";
2272a34c753fSRafael Auler         ++BranchValues;
2273a34c753fSRafael Auler       }
2274a34c753fSRafael Auler     }
2275a34c753fSRafael Auler 
2276a34c753fSRafael Auler     WriteMemLocs = true;
2277a34c753fSRafael Auler     for (const StringMapEntry<FuncMemData> &Func : NamesToMemEvents) {
2278a34c753fSRafael Auler       for (const MemInfo &MemEvent : Func.getValue().Data) {
2279a34c753fSRafael Auler         writeLocation(MemEvent.Offset);
2280a34c753fSRafael Auler         writeLocation(MemEvent.Addr);
2281a34c753fSRafael Auler         OutFile << MemEvent.Count << "\n";
2282a34c753fSRafael Auler         ++MemValues;
2283a34c753fSRafael Auler       }
2284a34c753fSRafael Auler     }
2285a34c753fSRafael Auler   }
2286a34c753fSRafael Auler 
228740c2e0faSMaksim Panchenko   outs() << "PERF2BOLT: wrote " << BranchValues << " objects and " << MemValues
228840c2e0faSMaksim Panchenko          << " memory objects to " << OutputFilename << "\n";
2289a34c753fSRafael Auler 
2290a34c753fSRafael Auler   return std::error_code();
2291a34c753fSRafael Auler }
2292a34c753fSRafael Auler 
229340c2e0faSMaksim Panchenko void DataAggregator::dump() const { DataReader::dump(); }
2294a34c753fSRafael Auler 
2295a34c753fSRafael Auler void DataAggregator::dump(const LBREntry &LBR) const {
2296a34c753fSRafael Auler   Diag << "From: " << Twine::utohexstr(LBR.From)
2297a34c753fSRafael Auler        << " To: " << Twine::utohexstr(LBR.To) << " Mispred? " << LBR.Mispred
2298a34c753fSRafael Auler        << "\n";
2299a34c753fSRafael Auler }
2300a34c753fSRafael Auler 
2301a34c753fSRafael Auler void DataAggregator::dump(const PerfBranchSample &Sample) const {
2302a34c753fSRafael Auler   Diag << "Sample LBR entries: " << Sample.LBR.size() << "\n";
2303def464aaSAmir Ayupov   for (const LBREntry &LBR : Sample.LBR)
2304a34c753fSRafael Auler     dump(LBR);
2305a34c753fSRafael Auler }
2306a34c753fSRafael Auler 
2307a34c753fSRafael Auler void DataAggregator::dump(const PerfMemSample &Sample) const {
2308a34c753fSRafael Auler   Diag << "Sample mem entries: " << Sample.PC << ": " << Sample.Addr << "\n";
2309a34c753fSRafael Auler }
2310