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