• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #ifndef HIPERF_PERF_EVENT_RECORD_H
16 #define HIPERF_PERF_EVENT_RECORD_H
17 
18 #include <atomic>
19 #include <chrono>
20 #include <map>
21 #include <memory>
22 #include <stdint.h>
23 #include <string>
24 #include <sys/types.h>
25 #include <unique_fd.h>
26 #include <variant>
27 #include <vector>
28 #include <linux/perf_event.h>
29 #include <linux/types.h>
30 
31 #include "debug_logger.h"
32 #include "mem_map_item.h"
33 #include "perf_record_format.h"
34 #include "utilities.h"
35 
36 namespace OHOS {
37 namespace Developtools {
38 namespace HiPerf {
39 static constexpr uint32_t RECORD_SIZE_LIMIT = 65535;
40 
41 enum perf_event_hiperf_ext_type {
42     PERF_RECORD_HIPERF_CALLSTACK = UINT32_MAX / 2,
43 };
44 
45 struct CallFrame {
46     uint64_t ip_ = 0;
47     uint64_t sp_ = 0;
48 
49     uint64_t vaddrInFile_ = 0; // in symbol file vaddr
50     int32_t symbolIndex_ = -1; // symbols index , should update after sort
51     std::string_view symbolName_;
52     std::string_view filePath_; // lib path , elf path
53 
ip_CallFrame54     CallFrame(uint64_t ip, uint64_t sp = 0) : ip_(ip), sp_(sp) {}
55 
56     // this is for ut test
CallFrameCallFrame57     CallFrame(uint64_t ip, uint64_t vaddrInFile, const char *name, const char *filePath)
58         : ip_(ip), vaddrInFile_(vaddrInFile), symbolName_(name), filePath_(filePath)
59     {
60     }
61     bool operator==(const CallFrame &b) const
62     {
63         return (ip_ == b.ip_) && (sp_ == b.sp_);
64     }
65     bool operator!=(const CallFrame &b) const
66     {
67         return (ip_ != b.ip_) || (sp_ != b.sp_);
68     }
ToStringCallFrame69     std::string ToString() const
70     {
71         return StringPrintf("ip: 0x%016llx sp: 0x%016llx", ip_, sp_);
72     }
ToSymbolStringCallFrame73     std::string ToSymbolString() const
74     {
75         std::string output;
76         if (vaddrInFile_ != 0) {
77             output = StringPrintf("va: 0x%016llx(%llx) ", vaddrInFile_, ip_);
78         } else {
79             output = StringPrintf("ip: 0x%016llx ", ip_);
80         }
81         output.append(": ");
82         output.append(symbolName_);
83 
84         output.append("@");
85         output.append(filePath_);
86         if (symbolIndex_ != -1) {
87             output.append(":");
88             output.append(std::to_string(symbolIndex_));
89         }
90         return output;
91     }
92 };
93 
94 struct AttrWithId {
95     perf_event_attr attr;
96     std::vector<uint64_t> ids;
97     std::string name; // will be empty in GetAttrSection
98 };
99 
100 class PerfEventRecord {
101 public:
102     PerfEventRecord(const PerfEventRecord &) = delete;
103     PerfEventRecord &operator=(const PerfEventRecord &) = delete;
104 
105     struct perf_event_header header;
106     const std::string name_ {};
107 
108     PerfEventRecord(perf_event_type type, bool in_kernel, const std::string &name);
109     PerfEventRecord(perf_event_hiperf_ext_type type, const std::string &name);
110 
111     PerfEventRecord(uint8_t *p, const std::string &name);
112 
~PerfEventRecord()113     virtual ~PerfEventRecord() {};
114 
GetSize()115     virtual size_t GetSize() const
116     {
117         return header.size;
118     };
GetHeaderSize()119     size_t GetHeaderSize() const
120     {
121         return sizeof(header);
122     };
123     void GetHeaderBinary(std::vector<uint8_t> &buf) const;
124 
GetType()125     uint32_t GetType() const
126     {
127         return header.type;
128     };
GetMisc()129     uint16_t GetMisc() const
130     {
131         return header.misc;
132     };
inKernel()133     bool inKernel()
134     {
135         return header.misc & PERF_RECORD_MISC_KERNEL;
136     }
inUser()137     bool inUser()
138     {
139         return header.misc & PERF_RECORD_MISC_USER;
140     }
GetName()141     const std::string &GetName() const
142     {
143         return name_;
144     };
145 
146     // to support --exclude-hiperf, return sample_id.pid to filter record,
GetPid()147     virtual pid_t GetPid() const
148     {
149         return 0;
150     };
151 
152     virtual bool GetBinary(std::vector<uint8_t> &buf) const = 0;
153     void Dump(int indent = 0) const;
154     virtual void DumpData(int indent) const = 0;
155     virtual void DumpLog(const std::string &prefix) const;
156 };
157 
158 // define convert from linux/perf_event.h
159 // description from https://man7.org/linux/man-pages/man2/perf_event_open.2.html
160 
161 constexpr __u64 SAMPLE_ID = PERF_SAMPLE_TID | PERF_SAMPLE_TIME | PERF_SAMPLE_ID |
162                             PERF_SAMPLE_STREAM_ID | PERF_SAMPLE_CPU | PERF_SAMPLE_IDENTIFIER;
163 
164 constexpr __u64 SAMPLE_TYPE = PERF_SAMPLE_IP | SAMPLE_ID | PERF_SAMPLE_PERIOD;
165 
166 constexpr __u32 MIN_SAMPLE_STACK_SIZE = 8;
167 constexpr __u32 MAX_SAMPLE_STACK_SIZE = 65528;
168 
169 class PerfRecordMmap : public PerfEventRecord {
170 public:
171     PerfRecordMmapData data_;
172 
173     PerfRecordMmap(uint8_t *p);
174 
175     PerfRecordMmap(bool inKernel, u32 pid, u32 tid, u64 addr, u64 len, u64 pgoff,
176                    const std::string &filename);
177 
178     bool GetBinary(std::vector<uint8_t> &buf) const override;
179     virtual void DumpData(int indent) const override;
180     virtual void DumpLog(const std::string &prefix) const override;
181 };
182 
183 class PerfRecordMmap2 : public PerfEventRecord {
184 public:
185     PerfRecordMmap2Data data_;
186 
187     PerfRecordMmap2(uint8_t *p);
188 
189     PerfRecordMmap2(bool inKernel, u32 pid, u32 tid, u64 addr, u64 len, u64 pgoff, u32 maj, u32 min,
190                     u64 ino, u32 prot, u32 flags, const std::string &filename);
191 
192     PerfRecordMmap2(bool inKernel, u32 pid, u32 tid, const MemMapItem &item);
193 
194     bool GetBinary(std::vector<uint8_t> &buf) const override;
195     virtual void DumpData(int indent) const override;
196     virtual void DumpLog(const std::string &prefix) const override;
197 };
198 
199 class PerfRecordLost : public PerfEventRecord {
200 public:
201     PerfRecordLostData data_;
202 
203     PerfRecordLost(uint8_t *p);
204 
205     bool GetBinary(std::vector<uint8_t> &buf) const override;
206     virtual void DumpData(int indent) const override;
207 
208     // only for UT
PerfRecordLost(bool inKernel,u64 id,u64 lost)209     PerfRecordLost(bool inKernel, u64 id, u64 lost)
210         : PerfEventRecord(PERF_RECORD_LOST, inKernel, "lost")
211     {
212         data_.id = id;
213         data_.lost = lost;
214         header.size = sizeof(header) + sizeof(data_);
215     }
216 };
217 
218 class PerfRecordComm : public PerfEventRecord {
219 public:
220     PerfRecordCommData data_;
221 
222     PerfRecordComm(uint8_t *p);
223 
224     PerfRecordComm(bool inKernel, u32 pid, u32 tid, const std::string &comm);
225 
226     bool GetBinary(std::vector<uint8_t> &buf) const override;
227     virtual void DumpData(int indent) const override;
228     void DumpLog(const std::string &prefix) const override;
229 };
230 
231 class PerfRecordSample : public PerfEventRecord {
232 public:
233     PerfRecordSampleData data_ = {};
234     uint64_t sampleType_ = SAMPLE_TYPE;
235 
236     // extend
237     // hold the new ips memory (after unwind)
238     // used for data_.ips replace (ReplaceWithCallStack)
239     std::vector<u64> ips_;
240     std::vector<CallFrame> callFrames_;
241 
242     // referenced input(p) in PerfRecordSample, require caller keep input(p) together
243     PerfRecordSample(uint8_t *p, const perf_event_attr &attr);
244     bool GetBinary(std::vector<uint8_t> &buf) const override;
245     virtual void DumpData(int indent = 0) const override;
246     virtual void DumpLog(const std::string &prefix) const override;
247 
248     // originalSize is use for expand callstack
249     void ReplaceWithCallStack(size_t originalSize = 0);
250     pid_t GetPid() const override;
251 
252     // only for UT
253     PerfRecordSample(bool inKernel, u32 pid, u32 tid, u64 period = 0, u64 time = 0, u64 id = 0)
254         : PerfEventRecord(PERF_RECORD_SAMPLE, inKernel, "sample")
255     {
256         data_.pid = pid;
257         data_.tid = tid;
258         data_.period = period;
259         data_.time = time;
260         data_.id = 0;
261         header.size = sizeof(header) + sizeof(data_);
262     };
263 };
264 
265 class PerfRecordExit : public PerfEventRecord {
266 public:
267     PerfRecordExitData data_;
268 
269     PerfRecordExit(uint8_t *p);
270 
271     bool GetBinary(std::vector<uint8_t> &buf) const override;
272     virtual void DumpData(int indent) const override;
273 };
274 
275 class PerfRecordThrottle : public PerfEventRecord {
276 public:
277     PerfRecordThrottleData data_;
278 
279     PerfRecordThrottle(uint8_t *p);
280 
281     bool GetBinary(std::vector<uint8_t> &buf) const override;
282     virtual void DumpData(int indent) const override;
283 };
284 
285 class PerfRecordUnthrottle : public PerfEventRecord {
286 public:
287     PerfRecordThrottleData data_;
288 
289     PerfRecordUnthrottle(uint8_t *p);
290 
291     bool GetBinary(std::vector<uint8_t> &buf) const override;
292     virtual void DumpData(int indent) const override;
293 };
294 
295 class PerfRecordFork : public PerfEventRecord {
296 public:
297     PerfRecordForkData data_;
298 
299     PerfRecordFork(uint8_t *p);
300 
301     bool GetBinary(std::vector<uint8_t> &buf) const override;
302     virtual void DumpData(int indent) const override;
303 };
304 
305 /*
306     This record indicates a read event.
307 */
308 class PerfRecordRead : public PerfEventRecord {
309 public:
310     PerfRecordReadData data_;
311 
312     PerfRecordRead(uint8_t *p);
313     bool GetBinary(std::vector<uint8_t> &buf) const override;
314     virtual void DumpData(int indent) const override;
315 };
316 
317 /*
318     This record reports that new data is available in the
319     separate AUX buffer region.
320 
321     aux_offset
322             offset in the AUX mmap region where the new
323             data begins.
324     aux_size
325             size of the data made available.
326     flags  describes the AUX update.
327             PERF_AUX_FLAG_TRUNCATED
328                 if set, then the data returned was
329                 truncated to fit the available buffer
330                 size.
331 
332             PERF_AUX_FLAG_OVERWRITE
333                 if set, then the data returned has
334                 overwritten previous data.
335 */
336 class PerfRecordAux : public PerfEventRecord {
337 public:
338     PerfRecordAuxData data_;
339 
340     PerfRecordAux(uint8_t *p);
341     bool GetBinary(std::vector<uint8_t> &buf) const override;
342     virtual void DumpData(int indent) const override;
343 };
344 
345 /*
346     This record indicates which process has initiated an
347     instruction trace event, allowing tools to properly
348     correlate the instruction addresses in the AUX buffer
349     with the proper executable.
350 
351     pid    process ID of the thread starting an
352             instruction trace.
353     tid    thread ID of the thread starting an instruction
354             trace.
355 */
356 class PerfRecordItraceStart : public PerfEventRecord {
357 public:
358     PerfRecordItraceStartData data_;
359 
360     PerfRecordItraceStart(uint8_t *p);
361     bool GetBinary(std::vector<uint8_t> &buf) const override;
362     virtual void DumpData(int indent) const override;
363 };
364 
365 /*
366     When using hardware sampling (such as Intel PEBS) this
367     record indicates some number of samples that may have
368     been lost.
369 */
370 class PerfRecordLostSamples : public PerfEventRecord {
371 public:
372     PerfRecordLostSamplesData data_;
373 
374     PerfRecordLostSamples(uint8_t *p);
375     bool GetBinary(std::vector<uint8_t> &buf) const override;
376     virtual void DumpData(int indent) const override;
377 };
378 
379 /*
380     This record indicates a context switch has happened.
381     The PERF_RECORD_MISC_SWITCH_OUT bit in the misc field
382     indicates whether it was a context switch into or away
383     from the current process.
384 */
385 class PerfRecordSwitch : public PerfEventRecord {
386 public:
387     PerfRecordSwitchData data_;
388     PerfRecordSwitch(uint8_t *p);
389     bool GetBinary(std::vector<uint8_t> &buf) const override;
DumpData(int indent)390     virtual void DumpData([[maybe_unused]] int indent) const override {};
391 };
392 
393 /*
394     As with PERF_RECORD_SWITCH this record indicates a
395     context switch has happened, but it only occurs when
396     sampling in CPU-wide mode and provides additional
397     information on the process being switched to/from.
398     The PERF_RECORD_MISC_SWITCH_OUT bit in the misc field
399     indicates whether it was a context switch into or away
400     from the current process.
401 
402     next_prev_pid
403             The process ID of the previous (if switching
404             in) or next (if switching out) process on the
405             CPU.
406 
407     next_prev_tid
408             The thread ID of the previous (if switching in)
409             or next (if switching out) thread on the CPU.
410 */
411 class PerfRecordSwitchCpuWide : public PerfEventRecord {
412 public:
413     PerfRecordSwitchCpuWideData data_;
414     PerfRecordSwitchCpuWide(uint8_t *p);
415     bool GetBinary(std::vector<uint8_t> &buf) const override;
416     virtual void DumpData(int indent) const override;
417 };
418 
419 std::unique_ptr<PerfEventRecord> GetPerfEventRecord(const int type, uint8_t *data,
420                                                     const perf_event_attr &attr);
421 
422 template<typename T>
423 void PushToBinary(bool condition, uint8_t *&p, const T &v);
424 
425 template<typename T1, typename T2>
426 void PushToBinary2(bool condition, uint8_t *&p, const T1 &v1, const T2 &v2);
427 
428 template<typename T>
429 void PopFromBinary(bool condition, uint8_t *&p, T &v);
430 
431 template<typename T1, typename T2>
432 void PopFromBinary2(bool condition, uint8_t *&p, T1 &v1, T2 &v2);
433 } // namespace HiPerf
434 } // namespace Developtools
435 } // namespace OHOS
436 #endif