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