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 
10 static cl::opt<bool> ShowMmapEvents("show-mmap-events", cl::ReallyHidden,
11                                     cl::init(false), cl::ZeroOrMore,
12                                     cl::desc("Print binary load events."));
13 
14 namespace llvm {
15 namespace sampleprof {
16 
17 PerfReader::PerfReader(cl::list<std::string> &BinaryFilenames) {
18   // Load the binaries.
19   for (auto Filename : BinaryFilenames)
20     loadBinary(Filename, /*AllowNameConflict*/ false);
21 }
22 
23 ProfiledBinary &PerfReader::loadBinary(const StringRef BinaryPath,
24                                        bool AllowNameConflict) {
25   // The binary table is currently indexed by the binary name not the full
26   // binary path. This is because the user-given path may not match the one
27   // that was actually executed.
28   StringRef BinaryName = llvm::sys::path::filename(BinaryPath);
29 
30   // Call to load the binary in the ctor of ProfiledBinary.
31   auto Ret = BinaryTable.insert({BinaryName, ProfiledBinary(BinaryPath)});
32 
33   if (!Ret.second && !AllowNameConflict) {
34     std::string ErrorMsg = "Binary name conflict: " + BinaryPath.str() +
35                            " and " + Ret.first->second.getPath().str() + " \n";
36     exitWithError(ErrorMsg);
37   }
38 
39   return Ret.first->second;
40 }
41 
42 void PerfReader::updateBinaryAddress(const MMapEvent &Event) {
43   // Load the binary.
44   StringRef BinaryPath = Event.BinaryPath;
45   StringRef BinaryName = llvm::sys::path::filename(BinaryPath);
46 
47   auto I = BinaryTable.find(BinaryName);
48   // Drop the event which doesn't belong to user-provided binaries
49   // or if its image is loaded at the same address
50   if (I == BinaryTable.end() || Event.BaseAddress == I->second.getBaseAddress())
51     return;
52 
53   ProfiledBinary &Binary = I->second;
54 
55   // A binary image could be uploaded and then reloaded at different
56   // place, so update the address map here
57   AddrToBinaryMap.erase(Binary.getBaseAddress());
58   AddrToBinaryMap[Event.BaseAddress] = &Binary;
59 
60   // Update binary load address.
61   Binary.setBaseAddress(Event.BaseAddress);
62 }
63 
64 void PerfReader::parseMMap2Event(TraceStream &TraceIt) {
65   // Parse a line like:
66   //  PERF_RECORD_MMAP2 2113428/2113428: [0x7fd4efb57000(0x204000) @ 0
67   //  08:04 19532229 3585508847]: r-xp /usr/lib64/libdl-2.17.so
68   constexpr static const char *const Pattern =
69       "PERF_RECORD_MMAP2 ([0-9]+)/[0-9]+: "
70       "\\[(0x[a-f0-9]+)\\((0x[a-f0-9]+)\\) @ "
71       "(0x[a-f0-9]+|0) .*\\]: [-a-z]+ (.*)";
72   // Field 0 - whole line
73   // Field 1 - PID
74   // Field 2 - base address
75   // Field 3 - mmapped size
76   // Field 4 - page offset
77   // Field 5 - binary path
78   enum EventIndex {
79     WHOLE_LINE = 0,
80     PID = 1,
81     BASE_ADDRESS = 2,
82     MMAPPED_SIZE = 3,
83     PAGE_OFFSET = 4,
84     BINARY_PATH = 5
85   };
86 
87   Regex RegMmap2(Pattern);
88   SmallVector<StringRef, 6> Fields;
89   bool R = RegMmap2.match(TraceIt.getCurrentLine(), &Fields);
90   if (!R) {
91     std::string ErrorMsg = "Cannot parse mmap event: Line" +
92                            Twine(TraceIt.getLineNumber()).str() + ": " +
93                            TraceIt.getCurrentLine().str() + " \n";
94     exitWithError(ErrorMsg);
95   }
96   MMapEvent Event;
97   Fields[PID].getAsInteger(10, Event.PID);
98   Fields[BASE_ADDRESS].getAsInteger(0, Event.BaseAddress);
99   Fields[MMAPPED_SIZE].getAsInteger(0, Event.Size);
100   Fields[PAGE_OFFSET].getAsInteger(0, Event.Offset);
101   Event.BinaryPath = Fields[BINARY_PATH];
102   updateBinaryAddress(Event);
103   if (ShowMmapEvents) {
104     outs() << "Mmap: Binary " << Event.BinaryPath << " loaded at "
105            << format("0x%" PRIx64 ":", Event.BaseAddress) << " \n";
106   }
107 }
108 
109 void PerfReader::parseEvent(TraceStream &TraceIt) {
110   if (TraceIt.getCurrentLine().startswith("PERF_RECORD_MMAP2"))
111     parseMMap2Event(TraceIt);
112 
113   TraceIt.advance();
114 }
115 
116 void PerfReader::parseTrace(StringRef Filename) {
117   // Trace line iterator
118   TraceStream TraceIt(Filename);
119   while (!TraceIt.isAtEoF()) {
120     parseEvent(TraceIt);
121   }
122 }
123 
124 void PerfReader::parsePerfTraces(cl::list<std::string> &PerfTraceFilenames) {
125   // Parse perf traces.
126   for (auto Filename : PerfTraceFilenames)
127     parseTrace(Filename);
128 }
129 
130 } // end namespace sampleprof
131 } // end namespace llvm
132