1 //===-- PerfReader.cpp - perfscript reader  ---------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 #include "PerfReader.h"
9 #include "ProfileGenerator.h"
10 #include "llvm/Support/FileSystem.h"
11 #include "llvm/Support/Process.h"
12 
13 #define DEBUG_TYPE "perf-reader"
14 
15 cl::opt<bool> SkipSymbolization("skip-symbolization", cl::init(false),
16                                 cl::ZeroOrMore,
17                                 cl::desc("Dump the unsymbolized profile to the "
18                                          "output file. It will show unwinder "
19                                          "output for CS profile generation."));
20 
21 static cl::opt<bool> ShowMmapEvents("show-mmap-events", cl::init(false),
22                                     cl::ZeroOrMore,
23                                     cl::desc("Print binary load events."));
24 
25 static cl::opt<bool>
26     UseOffset("use-offset", cl::init(true), cl::ZeroOrMore,
27               cl::desc("Work with `--skip-symbolization` or "
28                        "`--unsymbolized-profile` to write/read the "
29                        "offset instead of virtual address."));
30 static cl::opt<bool>
31     IgnoreStackSamples("ignore-stack-samples", cl::init(false), cl::ZeroOrMore,
32                        cl::desc("Ignore call stack samples for hybrid samples "
33                                 "and produce context-insensitive profile."));
34 static cl::opt<bool>
35     ShowDetailedWarning("show-detailed-warning", cl::init(false),
36                         cl::ZeroOrMore,
37                         cl::desc("Show detailed warning message."));
38 
39 extern cl::opt<std::string> PerfTraceFilename;
40 extern cl::opt<bool> ShowDisassemblyOnly;
41 extern cl::opt<bool> ShowSourceLocations;
42 extern cl::opt<std::string> OutputFilename;
43 
44 namespace llvm {
45 namespace sampleprof {
46 
47 void VirtualUnwinder::unwindCall(UnwindState &State) {
48   // The 2nd frame after leaf could be missing if stack sample is
49   // taken when IP is within prolog/epilog, as frame chain isn't
50   // setup yet. Fill in the missing frame in that case.
51   // TODO: Currently we just assume all the addr that can't match the
52   // 2nd frame is in prolog/epilog. In the future, we will switch to
53   // pro/epi tracker(Dwarf CFI) for the precise check.
54   uint64_t Source = State.getCurrentLBRSource();
55   auto *ParentFrame = State.getParentFrame();
56   if (ParentFrame == State.getDummyRootPtr() ||
57       ParentFrame->Address != Source) {
58     State.switchToFrame(Source);
59   } else {
60     State.popFrame();
61   }
62   State.InstPtr.update(Source);
63 }
64 
65 void VirtualUnwinder::unwindLinear(UnwindState &State, uint64_t Repeat) {
66   InstructionPointer &IP = State.InstPtr;
67   uint64_t Target = State.getCurrentLBRTarget();
68   uint64_t End = IP.Address;
69   if (Binary->usePseudoProbes()) {
70     // We don't need to top frame probe since it should be extracted
71     // from the range.
72     // The outcome of the virtual unwinding with pseudo probes is a
73     // map from a context key to the address range being unwound.
74     // This means basically linear unwinding is not needed for pseudo
75     // probes. The range will be simply recorded here and will be
76     // converted to a list of pseudo probes to report in ProfileGenerator.
77     State.getParentFrame()->recordRangeCount(Target, End, Repeat);
78   } else {
79     // Unwind linear execution part.
80     // Split and record the range by different inline context. For example:
81     // [0x01] ... main:1          # Target
82     // [0x02] ... main:2
83     // [0x03] ... main:3 @ foo:1
84     // [0x04] ... main:3 @ foo:2
85     // [0x05] ... main:3 @ foo:3
86     // [0x06] ... main:4
87     // [0x07] ... main:5          # End
88     // It will be recorded:
89     // [main:*]         : [0x06, 0x07], [0x01, 0x02]
90     // [main:3 @ foo:*] : [0x03, 0x05]
91     while (IP.Address > Target) {
92       uint64_t PrevIP = IP.Address;
93       IP.backward();
94       // Break into segments for implicit call/return due to inlining
95       bool SameInlinee = Binary->inlineContextEqual(PrevIP, IP.Address);
96       if (!SameInlinee) {
97         State.switchToFrame(PrevIP);
98         State.CurrentLeafFrame->recordRangeCount(PrevIP, End, Repeat);
99         End = IP.Address;
100       }
101     }
102     assert(IP.Address == Target && "The last one must be the target address.");
103     // Record the remaining range, [0x01, 0x02] in the example
104     State.switchToFrame(IP.Address);
105     State.CurrentLeafFrame->recordRangeCount(IP.Address, End, Repeat);
106   }
107 }
108 
109 void VirtualUnwinder::unwindReturn(UnwindState &State) {
110   // Add extra frame as we unwind through the return
111   const LBREntry &LBR = State.getCurrentLBR();
112   uint64_t CallAddr = Binary->getCallAddrFromFrameAddr(LBR.Target);
113   State.switchToFrame(CallAddr);
114   State.pushFrame(LBR.Source);
115   State.InstPtr.update(LBR.Source);
116 }
117 
118 void VirtualUnwinder::unwindBranchWithinFrame(UnwindState &State) {
119   // TODO: Tolerate tail call for now, as we may see tail call from libraries.
120   // This is only for intra function branches, excluding tail calls.
121   uint64_t Source = State.getCurrentLBRSource();
122   State.switchToFrame(Source);
123   State.InstPtr.update(Source);
124 }
125 
126 std::shared_ptr<StringBasedCtxKey> FrameStack::getContextKey() {
127   std::shared_ptr<StringBasedCtxKey> KeyStr =
128       std::make_shared<StringBasedCtxKey>();
129   KeyStr->Context = Binary->getExpandedContext(Stack, KeyStr->WasLeafInlined);
130   if (KeyStr->Context.empty())
131     return nullptr;
132   return KeyStr;
133 }
134 
135 std::shared_ptr<ProbeBasedCtxKey> ProbeStack::getContextKey() {
136   std::shared_ptr<ProbeBasedCtxKey> ProbeBasedKey =
137       std::make_shared<ProbeBasedCtxKey>();
138   for (auto CallProbe : Stack) {
139     ProbeBasedKey->Probes.emplace_back(CallProbe);
140   }
141   CSProfileGenerator::compressRecursionContext<const MCDecodedPseudoProbe *>(
142       ProbeBasedKey->Probes);
143   CSProfileGenerator::trimContext<const MCDecodedPseudoProbe *>(
144       ProbeBasedKey->Probes);
145   return ProbeBasedKey;
146 }
147 
148 template <typename T>
149 void VirtualUnwinder::collectSamplesFromFrame(UnwindState::ProfiledFrame *Cur,
150                                               T &Stack) {
151   if (Cur->RangeSamples.empty() && Cur->BranchSamples.empty())
152     return;
153 
154   std::shared_ptr<ContextKey> Key = Stack.getContextKey();
155   if (Key == nullptr)
156     return;
157   auto Ret = CtxCounterMap->emplace(Hashable<ContextKey>(Key), SampleCounter());
158   SampleCounter &SCounter = Ret.first->second;
159   for (auto &Item : Cur->RangeSamples) {
160     uint64_t StartOffset = Binary->virtualAddrToOffset(std::get<0>(Item));
161     uint64_t EndOffset = Binary->virtualAddrToOffset(std::get<1>(Item));
162     SCounter.recordRangeCount(StartOffset, EndOffset, std::get<2>(Item));
163   }
164 
165   for (auto &Item : Cur->BranchSamples) {
166     uint64_t SourceOffset = Binary->virtualAddrToOffset(std::get<0>(Item));
167     uint64_t TargetOffset = Binary->virtualAddrToOffset(std::get<1>(Item));
168     SCounter.recordBranchCount(SourceOffset, TargetOffset, std::get<2>(Item));
169   }
170 }
171 
172 template <typename T>
173 void VirtualUnwinder::collectSamplesFromFrameTrie(
174     UnwindState::ProfiledFrame *Cur, T &Stack) {
175   if (!Cur->isDummyRoot()) {
176     if (!Stack.pushFrame(Cur)) {
177       // Process truncated context
178       // Start a new traversal ignoring its bottom context
179       T EmptyStack(Binary);
180       collectSamplesFromFrame(Cur, EmptyStack);
181       for (const auto &Item : Cur->Children) {
182         collectSamplesFromFrameTrie(Item.second.get(), EmptyStack);
183       }
184 
185       // Keep note of untracked call site and deduplicate them
186       // for warning later.
187       if (!Cur->isLeafFrame())
188         UntrackedCallsites.insert(Cur->Address);
189 
190       return;
191     }
192   }
193 
194   collectSamplesFromFrame(Cur, Stack);
195   // Process children frame
196   for (const auto &Item : Cur->Children) {
197     collectSamplesFromFrameTrie(Item.second.get(), Stack);
198   }
199   // Recover the call stack
200   Stack.popFrame();
201 }
202 
203 void VirtualUnwinder::collectSamplesFromFrameTrie(
204     UnwindState::ProfiledFrame *Cur) {
205   if (Binary->usePseudoProbes()) {
206     ProbeStack Stack(Binary);
207     collectSamplesFromFrameTrie<ProbeStack>(Cur, Stack);
208   } else {
209     FrameStack Stack(Binary);
210     collectSamplesFromFrameTrie<FrameStack>(Cur, Stack);
211   }
212 }
213 
214 void VirtualUnwinder::recordBranchCount(const LBREntry &Branch,
215                                         UnwindState &State, uint64_t Repeat) {
216   if (Branch.IsArtificial)
217     return;
218 
219   if (Binary->usePseudoProbes()) {
220     // Same as recordRangeCount, We don't need to top frame probe since we will
221     // extract it from branch's source address
222     State.getParentFrame()->recordBranchCount(Branch.Source, Branch.Target,
223                                               Repeat);
224   } else {
225     State.CurrentLeafFrame->recordBranchCount(Branch.Source, Branch.Target,
226                                               Repeat);
227   }
228 }
229 
230 bool VirtualUnwinder::unwind(const PerfSample *Sample, uint64_t Repeat) {
231   // Capture initial state as starting point for unwinding.
232   UnwindState State(Sample, Binary);
233 
234   // Sanity check - making sure leaf of LBR aligns with leaf of stack sample
235   // Stack sample sometimes can be unreliable, so filter out bogus ones.
236   if (!State.validateInitialState())
237     return false;
238 
239   // Also do not attempt linear unwind for the leaf range as it's incomplete.
240   bool IsLeaf = true;
241 
242   // Now process the LBR samples in parrallel with stack sample
243   // Note that we do not reverse the LBR entry order so we can
244   // unwind the sample stack as we walk through LBR entries.
245   while (State.hasNextLBR()) {
246     State.checkStateConsistency();
247 
248     // Unwind implicit calls/returns from inlining, along the linear path,
249     // break into smaller sub section each with its own calling context.
250     if (!IsLeaf) {
251       unwindLinear(State, Repeat);
252     }
253     IsLeaf = false;
254 
255     // Save the LBR branch before it gets unwound.
256     const LBREntry &Branch = State.getCurrentLBR();
257 
258     if (isCallState(State)) {
259       // Unwind calls - we know we encountered call if LBR overlaps with
260       // transition between leaf the 2nd frame. Note that for calls that
261       // were not in the original stack sample, we should have added the
262       // extra frame when processing the return paired with this call.
263       unwindCall(State);
264     } else if (isReturnState(State)) {
265       // Unwind returns - check whether the IP is indeed at a return instruction
266       unwindReturn(State);
267     } else {
268       // Unwind branches - for regular intra function branches, we only
269       // need to record branch with context.
270       unwindBranchWithinFrame(State);
271     }
272     State.advanceLBR();
273     // Record `branch` with calling context after unwinding.
274     recordBranchCount(Branch, State, Repeat);
275   }
276   // As samples are aggregated on trie, record them into counter map
277   collectSamplesFromFrameTrie(State.getDummyRootPtr());
278 
279   return true;
280 }
281 
282 std::unique_ptr<PerfReaderBase>
283 PerfReaderBase::create(ProfiledBinary *Binary, PerfInputFile &PerfInput) {
284   std::unique_ptr<PerfReaderBase> PerfReader;
285 
286   if (PerfInput.Format == PerfFormat::UnsymbolizedProfile) {
287     PerfReader.reset(
288         new UnsymbolizedProfileReader(Binary, PerfInput.InputFile));
289     return PerfReader;
290   }
291 
292   // For perf data input, we need to convert them into perf script first.
293   if (PerfInput.Format == PerfFormat::PerfData)
294     PerfInput = PerfScriptReader::convertPerfDataToTrace(Binary, PerfInput);
295 
296   assert((PerfInput.Format == PerfFormat::PerfScript) &&
297          "Should be a perfscript!");
298 
299   PerfInput.Content =
300       PerfScriptReader::checkPerfScriptType(PerfInput.InputFile);
301   if (PerfInput.Content == PerfContent::LBRStack) {
302     PerfReader.reset(new HybridPerfReader(Binary, PerfInput.InputFile));
303   } else if (PerfInput.Content == PerfContent::LBR) {
304     PerfReader.reset(new LBRPerfReader(Binary, PerfInput.InputFile));
305   } else {
306     exitWithError("Unsupported perfscript!");
307   }
308 
309   return PerfReader;
310 }
311 
312 PerfInputFile PerfScriptReader::convertPerfDataToTrace(ProfiledBinary *Binary,
313                                                        PerfInputFile &File) {
314   StringRef PerfData = File.InputFile;
315   // Run perf script to retrieve PIDs matching binary we're interested in.
316   auto PerfExecutable = sys::Process::FindInEnvPath("PATH", "perf");
317   if (!PerfExecutable) {
318     exitWithError("Perf not found.");
319   }
320   std::string PerfPath = *PerfExecutable;
321   std::string PerfTraceFile = PerfData.str() + ".script.tmp";
322   StringRef ScriptMMapArgs[] = {PerfPath, "script",   "--show-mmap-events",
323                                 "-F",     "comm,pid", "-i",
324                                 PerfData};
325   Optional<StringRef> Redirects[] = {llvm::None,                // Stdin
326                                      StringRef(PerfTraceFile),  // Stdout
327                                      StringRef(PerfTraceFile)}; // Stderr
328   sys::ExecuteAndWait(PerfPath, ScriptMMapArgs, llvm::None, Redirects);
329 
330   // Collect the PIDs
331   TraceStream TraceIt(PerfTraceFile);
332   std::string PIDs;
333   std::unordered_set<uint32_t> PIDSet;
334   while (!TraceIt.isAtEoF()) {
335     MMapEvent MMap;
336     if (isMMap2Event(TraceIt.getCurrentLine()) &&
337         extractMMap2EventForBinary(Binary, TraceIt.getCurrentLine(), MMap)) {
338       auto It = PIDSet.emplace(MMap.PID);
339       if (It.second) {
340         if (!PIDs.empty()) {
341           PIDs.append(",");
342         }
343         PIDs.append(utostr(MMap.PID));
344       }
345     }
346     TraceIt.advance();
347   }
348 
349   if (PIDs.empty()) {
350     exitWithError("No relevant mmap event is found in perf data.");
351   }
352 
353   // Run perf script again to retrieve events for PIDs collected above
354   StringRef ScriptSampleArgs[] = {PerfPath, "script",     "--show-mmap-events",
355                                   "-F",     "ip,brstack", "--pid",
356                                   PIDs,     "-i",         PerfData};
357   sys::ExecuteAndWait(PerfPath, ScriptSampleArgs, llvm::None, Redirects);
358 
359   return {PerfTraceFile, PerfFormat::PerfScript, PerfContent::UnknownContent};
360 }
361 
362 void PerfScriptReader::updateBinaryAddress(const MMapEvent &Event) {
363   // Drop the event which doesn't belong to user-provided binary
364   StringRef BinaryName = llvm::sys::path::filename(Event.BinaryPath);
365   if (Binary->getName() != BinaryName)
366     return;
367 
368   // Drop the event if its image is loaded at the same address
369   if (Event.Address == Binary->getBaseAddress()) {
370     Binary->setIsLoadedByMMap(true);
371     return;
372   }
373 
374   if (Event.Offset == Binary->getTextSegmentOffset()) {
375     // A binary image could be unloaded and then reloaded at different
376     // place, so update binary load address.
377     // Only update for the first executable segment and assume all other
378     // segments are loaded at consecutive memory addresses, which is the case on
379     // X64.
380     Binary->setBaseAddress(Event.Address);
381     Binary->setIsLoadedByMMap(true);
382   } else {
383     // Verify segments are loaded consecutively.
384     const auto &Offsets = Binary->getTextSegmentOffsets();
385     auto It = std::lower_bound(Offsets.begin(), Offsets.end(), Event.Offset);
386     if (It != Offsets.end() && *It == Event.Offset) {
387       // The event is for loading a separate executable segment.
388       auto I = std::distance(Offsets.begin(), It);
389       const auto &PreferredAddrs = Binary->getPreferredTextSegmentAddresses();
390       if (PreferredAddrs[I] - Binary->getPreferredBaseAddress() !=
391           Event.Address - Binary->getBaseAddress())
392         exitWithError("Executable segments not loaded consecutively");
393     } else {
394       if (It == Offsets.begin())
395         exitWithError("File offset not found");
396       else {
397         // Find the segment the event falls in. A large segment could be loaded
398         // via multiple mmap calls with consecutive memory addresses.
399         --It;
400         assert(*It < Event.Offset);
401         if (Event.Offset - *It != Event.Address - Binary->getBaseAddress())
402           exitWithError("Segment not loaded by consecutive mmaps");
403       }
404     }
405   }
406 }
407 
408 static std::string getContextKeyStr(ContextKey *K,
409                                     const ProfiledBinary *Binary) {
410   if (const auto *CtxKey = dyn_cast<StringBasedCtxKey>(K)) {
411     return SampleContext::getContextString(CtxKey->Context);
412   } else if (const auto *CtxKey = dyn_cast<ProbeBasedCtxKey>(K)) {
413     SampleContextFrameVector ContextStack;
414     for (const auto *Probe : CtxKey->Probes) {
415       Binary->getInlineContextForProbe(Probe, ContextStack, true);
416     }
417     // Probe context key at this point does not have leaf probe, so do not
418     // include the leaf inline location.
419     return SampleContext::getContextString(ContextStack, true);
420   } else {
421     llvm_unreachable("unexpected key type");
422   }
423 }
424 
425 void HybridPerfReader::unwindSamples() {
426   std::set<uint64_t> AllUntrackedCallsites;
427   for (const auto &Item : AggregatedSamples) {
428     const PerfSample *Sample = Item.first.getPtr();
429     VirtualUnwinder Unwinder(&SampleCounters, Binary);
430     Unwinder.unwind(Sample, Item.second);
431     auto &CurrUntrackedCallsites = Unwinder.getUntrackedCallsites();
432     AllUntrackedCallsites.insert(CurrUntrackedCallsites.begin(),
433                                  CurrUntrackedCallsites.end());
434   }
435 
436   // Warn about untracked frames due to missing probes.
437   if (ShowDetailedWarning) {
438     for (auto Address : AllUntrackedCallsites)
439       WithColor::warning() << "Profile context truncated due to missing probe "
440                            << "for call instruction at "
441                            << format("0x%" PRIx64, Address) << "\n";
442   }
443 
444   emitWarningSummary(AllUntrackedCallsites.size(), SampleCounters.size(),
445                      "of profiled contexts are truncated due to missing probe "
446                      "for call instruction.");
447 }
448 
449 bool PerfScriptReader::extractLBRStack(TraceStream &TraceIt,
450                                        SmallVectorImpl<LBREntry> &LBRStack) {
451   // The raw format of LBR stack is like:
452   // 0x4005c8/0x4005dc/P/-/-/0 0x40062f/0x4005b0/P/-/-/0 ...
453   //                           ... 0x4005c8/0x4005dc/P/-/-/0
454   // It's in FIFO order and seperated by whitespace.
455   SmallVector<StringRef, 32> Records;
456   TraceIt.getCurrentLine().split(Records, " ", -1, false);
457   auto WarnInvalidLBR = [](TraceStream &TraceIt) {
458     WithColor::warning() << "Invalid address in LBR record at line "
459                          << TraceIt.getLineNumber() << ": "
460                          << TraceIt.getCurrentLine() << "\n";
461   };
462 
463   // Skip the leading instruction pointer.
464   size_t Index = 0;
465   uint64_t LeadingAddr;
466   if (!Records.empty() && !Records[0].contains('/')) {
467     if (Records[0].getAsInteger(16, LeadingAddr)) {
468       WarnInvalidLBR(TraceIt);
469       TraceIt.advance();
470       return false;
471     }
472     Index = 1;
473   }
474   // Now extract LBR samples - note that we do not reverse the
475   // LBR entry order so we can unwind the sample stack as we walk
476   // through LBR entries.
477   uint64_t PrevTrDst = 0;
478 
479   while (Index < Records.size()) {
480     auto &Token = Records[Index++];
481     if (Token.size() == 0)
482       continue;
483 
484     SmallVector<StringRef, 8> Addresses;
485     Token.split(Addresses, "/");
486     uint64_t Src;
487     uint64_t Dst;
488 
489     // Stop at broken LBR records.
490     if (Addresses.size() < 2 || Addresses[0].substr(2).getAsInteger(16, Src) ||
491         Addresses[1].substr(2).getAsInteger(16, Dst)) {
492       WarnInvalidLBR(TraceIt);
493       break;
494     }
495 
496     bool SrcIsInternal = Binary->addressIsCode(Src);
497     bool DstIsInternal = Binary->addressIsCode(Dst);
498     bool IsExternal = !SrcIsInternal && !DstIsInternal;
499     bool IsIncoming = !SrcIsInternal && DstIsInternal;
500     bool IsOutgoing = SrcIsInternal && !DstIsInternal;
501     bool IsArtificial = false;
502 
503     // Ignore branches outside the current binary. Ignore all remaining branches
504     // if there's no incoming branch before the external branch in reverse
505     // order.
506     if (IsExternal) {
507       if (PrevTrDst)
508         continue;
509       if (!LBRStack.empty()) {
510         WithColor::warning()
511             << "Invalid transfer to external code in LBR record at line "
512             << TraceIt.getLineNumber() << ": " << TraceIt.getCurrentLine()
513             << "\n";
514       }
515       break;
516     }
517 
518     if (IsOutgoing) {
519       if (!PrevTrDst) {
520         // This is unpaired outgoing jump which is likely due to interrupt or
521         // incomplete LBR trace. Ignore current and subsequent entries since
522         // they are likely in different contexts.
523         break;
524       }
525 
526       if (Binary->addressIsReturn(Src)) {
527         // In a callback case, a return from internal code, say A, to external
528         // runtime can happen. The external runtime can then call back to
529         // another internal routine, say B. Making an artificial branch that
530         // looks like a return from A to B can confuse the unwinder to treat
531         // the instruction before B as the call instruction.
532         break;
533       }
534 
535       // For transition to external code, group the Source with the next
536       // availabe transition target.
537       Dst = PrevTrDst;
538       PrevTrDst = 0;
539       IsArtificial = true;
540     } else {
541       if (PrevTrDst) {
542         // If we have seen an incoming transition from external code to internal
543         // code, but not a following outgoing transition, the incoming
544         // transition is likely due to interrupt which is usually unpaired.
545         // Ignore current and subsequent entries since they are likely in
546         // different contexts.
547         break;
548       }
549 
550       if (IsIncoming) {
551         // For transition from external code (such as dynamic libraries) to
552         // the current binary, keep track of the branch target which will be
553         // grouped with the Source of the last transition from the current
554         // binary.
555         PrevTrDst = Dst;
556         continue;
557       }
558     }
559 
560     // TODO: filter out buggy duplicate branches on Skylake
561 
562     LBRStack.emplace_back(LBREntry(Src, Dst, IsArtificial));
563   }
564   TraceIt.advance();
565   return !LBRStack.empty();
566 }
567 
568 bool PerfScriptReader::extractCallstack(TraceStream &TraceIt,
569                                         SmallVectorImpl<uint64_t> &CallStack) {
570   // The raw format of call stack is like:
571   //            4005dc      # leaf frame
572   //	          400634
573   //	          400684      # root frame
574   // It's in bottom-up order with each frame in one line.
575 
576   // Extract stack frames from sample
577   while (!TraceIt.isAtEoF() && !TraceIt.getCurrentLine().startswith(" 0x")) {
578     StringRef FrameStr = TraceIt.getCurrentLine().ltrim();
579     uint64_t FrameAddr = 0;
580     if (FrameStr.getAsInteger(16, FrameAddr)) {
581       // We might parse a non-perf sample line like empty line and comments,
582       // skip it
583       TraceIt.advance();
584       return false;
585     }
586     TraceIt.advance();
587     // Currently intermixed frame from different binaries is not supported.
588     // Ignore caller frames not from binary of interest.
589     if (!Binary->addressIsCode(FrameAddr))
590       break;
591 
592     // We need to translate return address to call address for non-leaf frames.
593     if (!CallStack.empty()) {
594       auto CallAddr = Binary->getCallAddrFromFrameAddr(FrameAddr);
595       if (!CallAddr) {
596         // Stop at an invalid return address caused by bad unwinding. This could
597         // happen to frame-pointer-based unwinding and the callee functions that
598         // do not have the frame pointer chain set up.
599         InvalidReturnAddresses.insert(FrameAddr);
600         break;
601       }
602       FrameAddr = CallAddr;
603     }
604 
605     CallStack.emplace_back(FrameAddr);
606   }
607 
608   // Skip other unrelated line, find the next valid LBR line
609   // Note that even for empty call stack, we should skip the address at the
610   // bottom, otherwise the following pass may generate a truncated callstack
611   while (!TraceIt.isAtEoF() && !TraceIt.getCurrentLine().startswith(" 0x")) {
612     TraceIt.advance();
613   }
614   // Filter out broken stack sample. We may not have complete frame info
615   // if sample end up in prolog/epilog, the result is dangling context not
616   // connected to entry point. This should be relatively rare thus not much
617   // impact on overall profile quality. However we do want to filter them
618   // out to reduce the number of different calling contexts. One instance
619   // of such case - when sample landed in prolog/epilog, somehow stack
620   // walking will be broken in an unexpected way that higher frames will be
621   // missing.
622   return !CallStack.empty() &&
623          !Binary->addressInPrologEpilog(CallStack.front());
624 }
625 
626 void PerfScriptReader::warnIfMissingMMap() {
627   if (!Binary->getMissingMMapWarned() && !Binary->getIsLoadedByMMap()) {
628     WithColor::warning() << "No relevant mmap event is matched for "
629                          << Binary->getName()
630                          << ", will use preferred address ("
631                          << format("0x%" PRIx64,
632                                    Binary->getPreferredBaseAddress())
633                          << ") as the base loading address!\n";
634     // Avoid redundant warning, only warn at the first unmatched sample.
635     Binary->setMissingMMapWarned(true);
636   }
637 }
638 
639 void HybridPerfReader::parseSample(TraceStream &TraceIt, uint64_t Count) {
640   // The raw hybird sample started with call stack in FILO order and followed
641   // intermediately by LBR sample
642   // e.g.
643   // 	          4005dc    # call stack leaf
644   //	          400634
645   //	          400684    # call stack root
646   // 0x4005c8/0x4005dc/P/-/-/0   0x40062f/0x4005b0/P/-/-/0 ...
647   //          ... 0x4005c8/0x4005dc/P/-/-/0    # LBR Entries
648   //
649   std::shared_ptr<PerfSample> Sample = std::make_shared<PerfSample>();
650 
651   // Parsing call stack and populate into PerfSample.CallStack
652   if (!extractCallstack(TraceIt, Sample->CallStack)) {
653     // Skip the next LBR line matched current call stack
654     if (!TraceIt.isAtEoF() && TraceIt.getCurrentLine().startswith(" 0x"))
655       TraceIt.advance();
656     return;
657   }
658 
659   warnIfMissingMMap();
660 
661   if (!TraceIt.isAtEoF() && TraceIt.getCurrentLine().startswith(" 0x")) {
662     // Parsing LBR stack and populate into PerfSample.LBRStack
663     if (extractLBRStack(TraceIt, Sample->LBRStack)) {
664       if (IgnoreStackSamples) {
665         Sample->CallStack.clear();
666       } else {
667         // Canonicalize stack leaf to avoid 'random' IP from leaf frame skew LBR
668         // ranges
669         Sample->CallStack.front() = Sample->LBRStack[0].Target;
670       }
671       // Record samples by aggregation
672       AggregatedSamples[Hashable<PerfSample>(Sample)] += Count;
673     }
674   } else {
675     // LBR sample is encoded in single line after stack sample
676     exitWithError("'Hybrid perf sample is corrupted, No LBR sample line");
677   }
678 }
679 
680 void PerfScriptReader::writeUnsymbolizedProfile(StringRef Filename) {
681   std::error_code EC;
682   raw_fd_ostream OS(Filename, EC, llvm::sys::fs::OF_TextWithCRLF);
683   if (EC)
684     exitWithError(EC, Filename);
685   writeUnsymbolizedProfile(OS);
686 }
687 
688 // Use ordered map to make the output deterministic
689 using OrderedCounterForPrint = std::map<std::string, SampleCounter *>;
690 
691 void PerfScriptReader::writeUnsymbolizedProfile(raw_fd_ostream &OS) {
692   OrderedCounterForPrint OrderedCounters;
693   for (auto &CI : SampleCounters) {
694     OrderedCounters[getContextKeyStr(CI.first.getPtr(), Binary)] = &CI.second;
695   }
696 
697   auto SCounterPrinter = [&](RangeSample &Counter, StringRef Separator,
698                              uint32_t Indent) {
699     OS.indent(Indent);
700     OS << Counter.size() << "\n";
701     for (auto &I : Counter) {
702       uint64_t Start = UseOffset ? I.first.first
703                                  : Binary->offsetToVirtualAddr(I.first.first);
704       uint64_t End = UseOffset ? I.first.second
705                                : Binary->offsetToVirtualAddr(I.first.second);
706       OS.indent(Indent);
707       OS << Twine::utohexstr(Start) << Separator << Twine::utohexstr(End) << ":"
708          << I.second << "\n";
709     }
710   };
711 
712   for (auto &CI : OrderedCounters) {
713     uint32_t Indent = 0;
714     if (ProfileIsCS) {
715       // Context string key
716       OS << "[" << CI.first << "]\n";
717       Indent = 2;
718     }
719 
720     SampleCounter &Counter = *CI.second;
721     SCounterPrinter(Counter.RangeCounter, "-", Indent);
722     SCounterPrinter(Counter.BranchCounter, "->", Indent);
723   }
724 }
725 
726 // Format of input:
727 // number of entries in RangeCounter
728 // from_1-to_1:count_1
729 // from_2-to_2:count_2
730 // ......
731 // from_n-to_n:count_n
732 // number of entries in BranchCounter
733 // src_1->dst_1:count_1
734 // src_2->dst_2:count_2
735 // ......
736 // src_n->dst_n:count_n
737 void UnsymbolizedProfileReader::readSampleCounters(TraceStream &TraceIt,
738                                                    SampleCounter &SCounters) {
739   auto exitWithErrorForTraceLine = [](TraceStream &TraceIt) {
740     std::string Msg = TraceIt.isAtEoF()
741                           ? "Invalid raw profile!"
742                           : "Invalid raw profile at line " +
743                                 Twine(TraceIt.getLineNumber()).str() + ": " +
744                                 TraceIt.getCurrentLine().str();
745     exitWithError(Msg);
746   };
747   auto ReadNumber = [&](uint64_t &Num) {
748     if (TraceIt.isAtEoF())
749       exitWithErrorForTraceLine(TraceIt);
750     if (TraceIt.getCurrentLine().ltrim().getAsInteger(10, Num))
751       exitWithErrorForTraceLine(TraceIt);
752     TraceIt.advance();
753   };
754 
755   auto ReadCounter = [&](RangeSample &Counter, StringRef Separator) {
756     uint64_t Num = 0;
757     ReadNumber(Num);
758     while (Num--) {
759       if (TraceIt.isAtEoF())
760         exitWithErrorForTraceLine(TraceIt);
761       StringRef Line = TraceIt.getCurrentLine().ltrim();
762 
763       uint64_t Count = 0;
764       auto LineSplit = Line.split(":");
765       if (LineSplit.second.empty() || LineSplit.second.getAsInteger(10, Count))
766         exitWithErrorForTraceLine(TraceIt);
767 
768       uint64_t Source = 0;
769       uint64_t Target = 0;
770       auto Range = LineSplit.first.split(Separator);
771       if (Range.second.empty() || Range.first.getAsInteger(16, Source) ||
772           Range.second.getAsInteger(16, Target))
773         exitWithErrorForTraceLine(TraceIt);
774 
775       if (!UseOffset) {
776         Source = Binary->virtualAddrToOffset(Source);
777         Target = Binary->virtualAddrToOffset(Target);
778       }
779 
780       Counter[{Source, Target}] += Count;
781       TraceIt.advance();
782     }
783   };
784 
785   ReadCounter(SCounters.RangeCounter, "-");
786   ReadCounter(SCounters.BranchCounter, "->");
787 }
788 
789 void UnsymbolizedProfileReader::readUnsymbolizedProfile(StringRef FileName) {
790   TraceStream TraceIt(FileName);
791   while (!TraceIt.isAtEoF()) {
792     std::shared_ptr<StringBasedCtxKey> Key =
793         std::make_shared<StringBasedCtxKey>();
794     StringRef Line = TraceIt.getCurrentLine();
795     // Read context stack for CS profile.
796     if (Line.startswith("[")) {
797       ProfileIsCS = true;
798       auto I = ContextStrSet.insert(Line.str());
799       SampleContext::createCtxVectorFromStr(*I.first, Key->Context);
800       TraceIt.advance();
801     }
802     auto Ret =
803         SampleCounters.emplace(Hashable<ContextKey>(Key), SampleCounter());
804     readSampleCounters(TraceIt, Ret.first->second);
805   }
806 }
807 
808 void UnsymbolizedProfileReader::parsePerfTraces() {
809   readUnsymbolizedProfile(PerfTraceFile);
810 }
811 
812 void PerfScriptReader::computeCounterFromLBR(const PerfSample *Sample,
813                                              uint64_t Repeat) {
814   SampleCounter &Counter = SampleCounters.begin()->second;
815   uint64_t EndOffeset = 0;
816   for (const LBREntry &LBR : Sample->LBRStack) {
817     uint64_t SourceOffset = Binary->virtualAddrToOffset(LBR.Source);
818     uint64_t TargetOffset = Binary->virtualAddrToOffset(LBR.Target);
819 
820     if (!LBR.IsArtificial) {
821       Counter.recordBranchCount(SourceOffset, TargetOffset, Repeat);
822     }
823 
824     // If this not the first LBR, update the range count between TO of current
825     // LBR and FROM of next LBR.
826     uint64_t StartOffset = TargetOffset;
827     if (EndOffeset != 0)
828       Counter.recordRangeCount(StartOffset, EndOffeset, Repeat);
829     EndOffeset = SourceOffset;
830   }
831 }
832 
833 void LBRPerfReader::parseSample(TraceStream &TraceIt, uint64_t Count) {
834   std::shared_ptr<PerfSample> Sample = std::make_shared<PerfSample>();
835   // Parsing LBR stack and populate into PerfSample.LBRStack
836   if (extractLBRStack(TraceIt, Sample->LBRStack)) {
837     warnIfMissingMMap();
838     // Record LBR only samples by aggregation
839     AggregatedSamples[Hashable<PerfSample>(Sample)] += Count;
840   }
841 }
842 
843 void PerfScriptReader::generateUnsymbolizedProfile() {
844   // There is no context for LBR only sample, so initialize one entry with
845   // fake "empty" context key.
846   assert(SampleCounters.empty() &&
847          "Sample counter map should be empty before raw profile generation");
848   std::shared_ptr<StringBasedCtxKey> Key =
849       std::make_shared<StringBasedCtxKey>();
850   SampleCounters.emplace(Hashable<ContextKey>(Key), SampleCounter());
851   for (const auto &Item : AggregatedSamples) {
852     const PerfSample *Sample = Item.first.getPtr();
853     computeCounterFromLBR(Sample, Item.second);
854   }
855 }
856 
857 uint64_t PerfScriptReader::parseAggregatedCount(TraceStream &TraceIt) {
858   // The aggregated count is optional, so do not skip the line and return 1 if
859   // it's unmatched
860   uint64_t Count = 1;
861   if (!TraceIt.getCurrentLine().getAsInteger(10, Count))
862     TraceIt.advance();
863   return Count;
864 }
865 
866 void PerfScriptReader::parseSample(TraceStream &TraceIt) {
867   uint64_t Count = parseAggregatedCount(TraceIt);
868   assert(Count >= 1 && "Aggregated count should be >= 1!");
869   parseSample(TraceIt, Count);
870 }
871 
872 bool PerfScriptReader::extractMMap2EventForBinary(ProfiledBinary *Binary,
873                                                   StringRef Line,
874                                                   MMapEvent &MMap) {
875   // Parse a line like:
876   //  PERF_RECORD_MMAP2 2113428/2113428: [0x7fd4efb57000(0x204000) @ 0
877   //  08:04 19532229 3585508847]: r-xp /usr/lib64/libdl-2.17.so
878   constexpr static const char *const Pattern =
879       "PERF_RECORD_MMAP2 ([0-9]+)/[0-9]+: "
880       "\\[(0x[a-f0-9]+)\\((0x[a-f0-9]+)\\) @ "
881       "(0x[a-f0-9]+|0) .*\\]: [-a-z]+ (.*)";
882   // Field 0 - whole line
883   // Field 1 - PID
884   // Field 2 - base address
885   // Field 3 - mmapped size
886   // Field 4 - page offset
887   // Field 5 - binary path
888   enum EventIndex {
889     WHOLE_LINE = 0,
890     PID = 1,
891     MMAPPED_ADDRESS = 2,
892     MMAPPED_SIZE = 3,
893     PAGE_OFFSET = 4,
894     BINARY_PATH = 5
895   };
896 
897   Regex RegMmap2(Pattern);
898   SmallVector<StringRef, 6> Fields;
899   bool R = RegMmap2.match(Line, &Fields);
900   if (!R) {
901     std::string ErrorMsg = "Cannot parse mmap event: " + Line.str() + " \n";
902     exitWithError(ErrorMsg);
903   }
904   Fields[PID].getAsInteger(10, MMap.PID);
905   Fields[MMAPPED_ADDRESS].getAsInteger(0, MMap.Address);
906   Fields[MMAPPED_SIZE].getAsInteger(0, MMap.Size);
907   Fields[PAGE_OFFSET].getAsInteger(0, MMap.Offset);
908   MMap.BinaryPath = Fields[BINARY_PATH];
909   if (ShowMmapEvents) {
910     outs() << "Mmap: Binary " << MMap.BinaryPath << " loaded at "
911            << format("0x%" PRIx64 ":", MMap.Address) << " \n";
912   }
913 
914   StringRef BinaryName = llvm::sys::path::filename(MMap.BinaryPath);
915   return Binary->getName() == BinaryName;
916 }
917 
918 void PerfScriptReader::parseMMap2Event(TraceStream &TraceIt) {
919   MMapEvent MMap;
920   if (extractMMap2EventForBinary(Binary, TraceIt.getCurrentLine(), MMap))
921     updateBinaryAddress(MMap);
922   TraceIt.advance();
923 }
924 
925 void PerfScriptReader::parseEventOrSample(TraceStream &TraceIt) {
926   if (isMMap2Event(TraceIt.getCurrentLine()))
927     parseMMap2Event(TraceIt);
928   else
929     parseSample(TraceIt);
930 }
931 
932 void PerfScriptReader::parseAndAggregateTrace() {
933   // Trace line iterator
934   TraceStream TraceIt(PerfTraceFile);
935   while (!TraceIt.isAtEoF())
936     parseEventOrSample(TraceIt);
937 }
938 
939 // A LBR sample is like:
940 // 40062f 0x5c6313f/0x5c63170/P/-/-/0  0x5c630e7/0x5c63130/P/-/-/0 ...
941 // A heuristic for fast detection by checking whether a
942 // leading "  0x" and the '/' exist.
943 bool PerfScriptReader::isLBRSample(StringRef Line) {
944   // Skip the leading instruction pointer
945   SmallVector<StringRef, 32> Records;
946   Line.trim().split(Records, " ", 2, false);
947   if (Records.size() < 2)
948     return false;
949   if (Records[1].startswith("0x") && Records[1].contains('/'))
950     return true;
951   return false;
952 }
953 
954 bool PerfScriptReader::isMMap2Event(StringRef Line) {
955   // Short cut to avoid string find is possible.
956   if (Line.empty() || Line.size() < 50)
957     return false;
958 
959   if (std::isdigit(Line[0]))
960     return false;
961 
962   // PERF_RECORD_MMAP2 does not appear at the beginning of the line
963   // for ` perf script  --show-mmap-events  -i ...`
964   return Line.contains("PERF_RECORD_MMAP2");
965 }
966 
967 // The raw hybird sample is like
968 // e.g.
969 // 	          4005dc    # call stack leaf
970 //	          400634
971 //	          400684    # call stack root
972 // 0x4005c8/0x4005dc/P/-/-/0   0x40062f/0x4005b0/P/-/-/0 ...
973 //          ... 0x4005c8/0x4005dc/P/-/-/0    # LBR Entries
974 // Determine the perfscript contains hybrid samples(call stack + LBRs) by
975 // checking whether there is a non-empty call stack immediately followed by
976 // a LBR sample
977 PerfContent PerfScriptReader::checkPerfScriptType(StringRef FileName) {
978   TraceStream TraceIt(FileName);
979   uint64_t FrameAddr = 0;
980   while (!TraceIt.isAtEoF()) {
981     // Skip the aggregated count
982     if (!TraceIt.getCurrentLine().getAsInteger(10, FrameAddr))
983       TraceIt.advance();
984 
985     // Detect sample with call stack
986     int32_t Count = 0;
987     while (!TraceIt.isAtEoF() &&
988            !TraceIt.getCurrentLine().ltrim().getAsInteger(16, FrameAddr)) {
989       Count++;
990       TraceIt.advance();
991     }
992     if (!TraceIt.isAtEoF()) {
993       if (isLBRSample(TraceIt.getCurrentLine())) {
994         if (Count > 0)
995           return PerfContent::LBRStack;
996         else
997           return PerfContent::LBR;
998       }
999       TraceIt.advance();
1000     }
1001   }
1002 
1003   exitWithError("Invalid perf script input!");
1004   return PerfContent::UnknownContent;
1005 }
1006 
1007 void HybridPerfReader::generateUnsymbolizedProfile() {
1008   ProfileIsCS = !IgnoreStackSamples;
1009   if (ProfileIsCS)
1010     unwindSamples();
1011   else
1012     PerfScriptReader::generateUnsymbolizedProfile();
1013 }
1014 
1015 void PerfScriptReader::warnTruncatedStack() {
1016   if (ShowDetailedWarning) {
1017     for (auto Address : InvalidReturnAddresses) {
1018       WithColor::warning()
1019           << "Truncated stack sample due to invalid return address at "
1020           << format("0x%" PRIx64, Address)
1021           << ", likely caused by frame pointer omission\n";
1022     }
1023   }
1024   emitWarningSummary(
1025       InvalidReturnAddresses.size(), AggregatedSamples.size(),
1026       "of truncated stack samples due to invalid return address, "
1027       "likely caused by frame pointer omission.");
1028 }
1029 
1030 void PerfScriptReader::emitWarningSummary(uint64_t Num, uint64_t Total,
1031                                           StringRef Msg) {
1032   if (!Total || !Num)
1033     return;
1034   WithColor::warning() << format("%.2f", static_cast<double>(Num) * 100 / Total)
1035                        << "%(" << Num << "/" << Total << ") " << Msg << "\n";
1036 }
1037 
1038 void PerfScriptReader::warnInvalidRange() {
1039   std::unordered_map<std::pair<uint64_t, uint64_t>, uint64_t,
1040                      pair_hash<uint64_t, uint64_t>>
1041       Ranges;
1042 
1043   for (const auto &Item : AggregatedSamples) {
1044     const PerfSample *Sample = Item.first.getPtr();
1045     uint64_t Count = Item.second;
1046     uint64_t EndOffeset = 0;
1047     for (const LBREntry &LBR : Sample->LBRStack) {
1048       uint64_t SourceOffset = Binary->virtualAddrToOffset(LBR.Source);
1049       uint64_t StartOffset = Binary->virtualAddrToOffset(LBR.Target);
1050       if (EndOffeset != 0)
1051         Ranges[{StartOffset, EndOffeset}] += Count;
1052       EndOffeset = SourceOffset;
1053     }
1054   }
1055 
1056   if (Ranges.empty()) {
1057     WithColor::warning() << "No samples in perf script!\n";
1058     return;
1059   }
1060 
1061   auto WarnInvalidRange =
1062       [&](uint64_t StartOffset, uint64_t EndOffset, StringRef Msg) {
1063         if (!ShowDetailedWarning)
1064           return;
1065         WithColor::warning()
1066             << "["
1067             << format("%8" PRIx64, Binary->offsetToVirtualAddr(StartOffset))
1068             << ","
1069             << format("%8" PRIx64, Binary->offsetToVirtualAddr(EndOffset))
1070             << "]: " << Msg << "\n";
1071       };
1072 
1073   const char *EndNotBoundaryMsg = "Range is not on instruction boundary, "
1074                                   "likely due to profile and binary mismatch.";
1075   const char *DanglingRangeMsg = "Range does not belong to any functions, "
1076                                  "likely from PLT, .init or .fini section.";
1077   const char *RangeCrossFuncMsg =
1078       "Fall through range should not cross function boundaries, likely due to "
1079       "profile and binary mismatch.";
1080 
1081   uint64_t InstNotBoundary = 0;
1082   uint64_t UnmatchedRange = 0;
1083   uint64_t RangeCrossFunc = 0;
1084 
1085   for (auto &I : Ranges) {
1086     uint64_t StartOffset = I.first.first;
1087     uint64_t EndOffset = I.first.second;
1088 
1089     if (!Binary->offsetIsCode(StartOffset) ||
1090         !Binary->offsetIsTransfer(EndOffset)) {
1091       InstNotBoundary++;
1092       WarnInvalidRange(StartOffset, EndOffset, EndNotBoundaryMsg);
1093     }
1094 
1095     auto *FRange = Binary->findFuncRangeForOffset(StartOffset);
1096     if (!FRange) {
1097       UnmatchedRange++;
1098       WarnInvalidRange(StartOffset, EndOffset, DanglingRangeMsg);
1099       continue;
1100     }
1101 
1102     if (EndOffset >= FRange->EndOffset) {
1103       RangeCrossFunc++;
1104       WarnInvalidRange(StartOffset, EndOffset, RangeCrossFuncMsg);
1105     }
1106   }
1107 
1108   uint64_t TotalRangeNum = Ranges.size();
1109   emitWarningSummary(InstNotBoundary, TotalRangeNum,
1110                      "of profiled ranges are not on instruction boundary.");
1111   emitWarningSummary(UnmatchedRange, TotalRangeNum,
1112                      "of profiled ranges do not belong to any functions.");
1113   emitWarningSummary(RangeCrossFunc, TotalRangeNum,
1114                      "of profiled ranges do cross function boundaries.");
1115 }
1116 
1117 void PerfScriptReader::parsePerfTraces() {
1118   // Parse perf traces and do aggregation.
1119   parseAndAggregateTrace();
1120 
1121   // Generate unsymbolized profile.
1122   warnTruncatedStack();
1123   warnInvalidRange();
1124   generateUnsymbolizedProfile();
1125 
1126   if (SkipSymbolization)
1127     writeUnsymbolizedProfile(OutputFilename);
1128 }
1129 
1130 } // end namespace sampleprof
1131 } // end namespace llvm
1132