• 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 <unordered_map>
27 #include <variant>
28 #include <vector>
29 #include <linux/perf_event.h>
30 #include <linux/types.h>
31 
32 #include "debug_logger.h"
33 #include "dfx_frame.h"
34 #include "dfx_map.h"
35 #include "perf_record_format.h"
36 #include "unique_stack_table.h"
37 #include "utilities.h"
38 
39 namespace OHOS {
40 namespace Developtools {
41 namespace HiPerf {
42 using namespace OHOS::HiviewDFX;
43 using PerfRecordType = int32_t;
44 
45 static constexpr uint32_t RECORD_SIZE_LIMIT = 65535;
46 static constexpr uint32_t RECORD_SIZE_LIMIT_SPE = 524288; // auxMmapPages_ * pageSize_
47 
48 static constexpr char PERF_RECORD_TYPE_AUXTRACE[] = "auxtrace";
49 static constexpr char PERF_RECORD_TYPE_SAMPLE[] = "sample";
50 static constexpr char PERF_RECORD_TYPE_MMAP[] = "mmap";
51 static constexpr char PERF_RECORD_TYPE_MMAP2[] = "mmap2";
52 static constexpr char PERF_RECORD_TYPE_LOST[] = "lost";
53 static constexpr char PERF_RECORD_TYPE_COMM[] = "comm";
54 static constexpr char PERF_RECORD_TYPE_EXIT[] = "exit";
55 static constexpr char PERF_RECORD_TYPE_THROTTLE[] = "throttle";
56 static constexpr char PERF_RECORD_TYPE_UNTHROTTLE[] = "unthrottle";
57 static constexpr char PERF_RECORD_TYPE_FORK[] = "fork";
58 static constexpr char PERF_RECORD_TYPE_READ[] = "read";
59 static constexpr char PERF_RECORD_TYPE_AUX[] = "aux";
60 static constexpr char PERF_RECORD_TYPE_ITRACESTART[] = "itraceStart";
61 static constexpr char PERF_RECORD_TYPE_LOSTSAMPLE[] = "lostSamples";
62 static constexpr char PERF_RECORD_TYPE_SWITCH[] = "switch";
63 static constexpr char PERF_RECORD_TYPE_SWITCHCPUWIDE[] = "switchCpuWide";
64 static constexpr char PERF_RECORD_TYPE_AUXTRACEINFO[] = "auxtraceinfo";
65 static constexpr char PERF_RECORD_TYPE_TIMECONV[] = "timeconv";
66 static constexpr char PERF_RECORD_TYPE_CPUMAP[] = "cpumap";
67 static constexpr char* PERF_RECORD_TYPE_NULL = nullptr;
68 
69 enum perf_event_hiperf_ext_type {
70     PERF_RECORD_AUXTRACE_INFO = 70,
71     PERF_RECORD_AUXTRACE = 71,
72     PERF_RECORD_CPU_MAP = 74,
73     PERF_RECORD_TIME_CONV = 79,
74     PERF_RECORD_HIPERF_CALLSTACK = UINT32_MAX / 2,
75 };
76 
77 struct AttrWithId {
78     perf_event_attr attr;
79     std::vector<uint64_t> ids;
80     std::string name; // will be empty in GetAttrSection
81 };
82 
83 class PerfEventRecord {
84 public:
85     struct perf_event_header header_ = {};
86 
87     virtual const char* GetName() const = 0;
88     virtual void Init(uint8_t* data, const perf_event_attr& attr) = 0;
89 
90     virtual ~PerfEventRecord() = default;
91 
GetSize()92     virtual size_t GetSize() const
93     {
94         return header_.size;
95     };
GetHeaderSize()96     size_t GetHeaderSize() const
97     {
98         return sizeof(header_);
99     };
100     void GetHeaderBinary(std::vector<uint8_t> &buf) const;
101 
GetType()102     uint32_t GetType() const
103     {
104         return header_.type;
105     };
GetMisc()106     uint16_t GetMisc() const
107     {
108         return header_.misc;
109     };
InKernel()110     bool InKernel()
111     {
112         return header_.misc & PERF_RECORD_MISC_KERNEL;
113     }
InUser()114     bool InUser()
115     {
116         return header_.misc & PERF_RECORD_MISC_USER;
117     }
118     // to support --exclude-hiperf, return sample_id.pid to filter record,
GetPid()119     virtual pid_t GetPid() const
120     {
121         return 0;
122     };
123 
124     virtual bool GetBinary(std::vector<uint8_t> &buf) const = 0;
125     void Dump(int indent = 0, std::string outputFilename = "", FILE *outputDump = nullptr) const;
126     virtual void DumpData(int indent) const = 0;
127     virtual void DumpLog(const std::string& prefix) const;
128 
129 protected:
130     void Init(perf_event_type type, bool inKernel);
131     void Init(perf_event_hiperf_ext_type type);
132     void InitHeader(uint8_t* p);
133 };
134 
135 template <typename DataType, const char* RECORD_TYPE_NAME>
136 class PerfEventRecordTemplate : public PerfEventRecord {
137 public:
138     PerfEventRecordTemplate(const PerfEventRecordTemplate&) = delete;
139     PerfEventRecordTemplate& operator=(const PerfEventRecordTemplate&) = delete;
140 
141     DataType data_ = {};
GetName()142     const char* GetName() const override final
143     {
144         return RECORD_TYPE_NAME;
145     }
146 
147     PerfEventRecordTemplate() = default;
148     virtual ~PerfEventRecordTemplate() = default;
149     void Init(uint8_t* p, const perf_event_attr& = {}) override
150     {
151         InitHeader(p);
152         if (p == nullptr) {
153             return;
154         }
155 
156         size_t dataSize = GetSize();
157         if (dataSize >= sizeof(header_)) {
158             size_t copySize = dataSize - sizeof(header_);
159             if (memcpy_s(reinterpret_cast<uint8_t*>(&data_), sizeof(data_), p + sizeof(header_), copySize) != 0) {
160                 HLOGE("init perf record memcpy_s failed!");
161             }
162         } else {
163             HLOGE("init perf record failed!");
164         }
165     };
166 };
167 
168 // define convert from linux/perf_event.h
169 // description from https://man7.org/linux/man-pages/man2/perf_event_open.2.html
170 
171 constexpr __u64 SAMPLE_ID = PERF_SAMPLE_TID | PERF_SAMPLE_TIME | PERF_SAMPLE_ID |
172                             PERF_SAMPLE_STREAM_ID | PERF_SAMPLE_CPU | PERF_SAMPLE_IDENTIFIER;
173 
174 constexpr __u64 SAMPLE_TYPE = PERF_SAMPLE_IP | SAMPLE_ID | PERF_SAMPLE_PERIOD;
175 
176 constexpr __u32 MIN_SAMPLE_STACK_SIZE = 8;
177 constexpr __u32 MAX_SAMPLE_STACK_SIZE = 65528;
178 
179 class PerfRecordAuxtrace : public PerfEventRecordTemplate<PerfRecordAuxtraceData, PERF_RECORD_TYPE_AUXTRACE> {
180 public:
181     u8* rawData_ = nullptr;
182     PerfRecordAuxtrace() = default;
183     PerfRecordAuxtrace(u64 size, u64 offset, u64 reference, u32 idx, u32 tid, u32 cpu, u32 pid);
184     void Init(uint8_t* data, const perf_event_attr& attr = {}) override;
185 
186     bool GetBinary1(std::vector<uint8_t> &buf) const;
187     bool GetBinary(std::vector<uint8_t> &buf) const override;
188     void DumpData(int indent) const override;
189     void DumpLog(const std::string &prefix) const override;
190 
191     size_t GetSize() const override;
192 };
193 
194 class PerfRecordAuxTraceInfo : public PerfEventRecordTemplate<PerfRecordAuxtraceInfoData,
195                                PERF_RECORD_TYPE_AUXTRACEINFO> {
196 public:
197     PerfRecordAuxTraceInfo() = default;
198     bool GetBinary(std::vector<uint8_t> &buf) const override;
199     void DumpData(int indent) const override;
200 };
201 
202 class PerfRecordTimeConv : public PerfEventRecordTemplate<PerfRecordTtimeConvData, PERF_RECORD_TYPE_TIMECONV> {
203 public:
204     PerfRecordTimeConv() = default;
205     bool GetBinary(std::vector<uint8_t> &buf) const override;
206     void DumpData(int indent) const override;
207 };
208 
209 class PerfRecordCpuMap : public PerfEventRecordTemplate<PerfRecordCpuMapData, PERF_RECORD_TYPE_CPUMAP> {
210 public:
211     PerfRecordCpuMap() = default;
212     bool GetBinary(std::vector<uint8_t> &buf) const override;
213     void DumpData(int indent) const override;
214 };
215 
216 class PerfRecordMmap : public PerfEventRecordTemplate<PerfRecordMmapData, PERF_RECORD_TYPE_MMAP> {
217 public:
218     PerfRecordMmap() = default;
219     void Init(uint8_t* data, const perf_event_attr& attr = {}) override;
220     PerfRecordMmap(bool inKernel, u32 pid, u32 tid, u64 addr, u64 len, u64 pgoff,
221                    const std::string &filename);
222 
223     bool GetBinary(std::vector<uint8_t> &buf) const override;
224     void DumpData(int indent) const override;
225     void DumpLog(const std::string &prefix) const override;
226 };
227 
228 class PerfRecordMmap2 : public PerfEventRecordTemplate<PerfRecordMmap2Data, PERF_RECORD_TYPE_MMAP2> {
229 public:
230 
231     PerfRecordMmap2() = default;
232     void Init(uint8_t* data, const perf_event_attr& attr = {}) override;
233     PerfRecordMmap2(bool inKernel, u32 pid, u32 tid, u64 addr, u64 len, u64 pgoff, u32 maj, u32 min,
234                     u64 ino, u32 prot, u32 flags, const std::string &filename);
235 
236     PerfRecordMmap2(bool inKernel, u32 pid, u32 tid, std::shared_ptr<DfxMap> item);
237 
238     bool GetBinary(std::vector<uint8_t> &buf) const override;
239     void DumpData(int indent) const override;
240     void DumpLog(const std::string &prefix) const override;
241     bool discard_ = false;
242 };
243 
244 class PerfRecordLost : public PerfEventRecordTemplate<PerfRecordLostData, PERF_RECORD_TYPE_LOST> {
245 public:
246 
247     PerfRecordLost() = default;
248 
249     bool GetBinary(std::vector<uint8_t> &buf) const override;
250     void DumpData(int indent) const override;
251 
252     // only for UT
PerfRecordLost(bool inKernel,u64 id,u64 lost)253     PerfRecordLost(bool inKernel, u64 id, u64 lost)
254     {
255         PerfEventRecord::Init(PERF_RECORD_LOST, inKernel);
256         data_.id = id;
257         data_.lost = lost;
258         header_.size = sizeof(header_) + sizeof(data_);
259     }
260 };
261 
262 class PerfRecordComm : public PerfEventRecordTemplate<PerfRecordCommData, PERF_RECORD_TYPE_COMM> {
263 public:
264 
265     PerfRecordComm() = default;
266     void Init(uint8_t* data, const perf_event_attr& attr = {}) override;
267     PerfRecordComm(bool inKernel, u32 pid, u32 tid, const std::string &comm);
268 
269     bool GetBinary(std::vector<uint8_t> &buf) const override;
270     void DumpData(int indent) const override;
271     void DumpLog(const std::string &prefix) const override;
272 };
273 
274 class PerfRecordSample : public PerfEventRecordTemplate<PerfRecordSampleData, PERF_RECORD_TYPE_SAMPLE> {
275 public:
276     uint64_t sampleType_ = SAMPLE_TYPE;
277     uint64_t skipKernel_ = 0;
278     uint64_t skipPid_ = 0;
279     // extend
280     // hold the new ips memory (after unwind)
281     // used for data_.ips replace (ReplaceWithCallStack)
282     static std::vector<u64> ips_;
283     static std::vector<DfxFrame> callFrames_;
284     static std::vector<pid_t> serverPidMap_;
285 
286     PerfRecordSample() = default;
287     PerfRecordSample(const PerfRecordSample& sample);
288     // referenced input(p) in PerfRecordSample, require caller keep input(p) together
289     void Init(uint8_t* data, const perf_event_attr& attr) override;
290 
291     StackId stackId_ {0};
292     bool removeStack_ {false};
293     static void SetDumpRemoveStack(bool dumpRemoveStack);
294     static bool IsDumpRemoveStack();
295     bool GetBinary(std::vector<uint8_t> &buf) const override;
296     void DumpData(int indent = 0) const override;
297     void DumpLog(const std::string &prefix) const override;
298 
299     void RecoverCallStack();
300     // originalSize is use for expand callstack
301     void ReplaceWithCallStack(size_t originalSize = 0);
302     pid_t GetPid() const override;
303     uint64_t GetTime() const;
304     void Clean();
305 
306     // only for UT
307     PerfRecordSample(bool inKernel, u32 pid, u32 tid, u64 period = 0, u64 time = 0, u64 id = 0)
308     {
309         PerfEventRecord::Init(PERF_RECORD_SAMPLE, inKernel);
310         Clean();
311         data_.pid = pid;
312         data_.tid = tid;
313         data_.period = period;
314         data_.time = time;
315         data_.id = 0;
316         header_.size = sizeof(header_) + sizeof(data_);
317     }
318 
319     pid_t GetUstackServerPid();
320     pid_t GetServerPidof(unsigned int ipNr);
321 private:
322     static bool dumpRemoveStack_;
323 };
324 
325 class PerfRecordExit : public PerfEventRecordTemplate<PerfRecordExitData, PERF_RECORD_TYPE_EXIT> {
326 public:
327     PerfRecordExit() = default;
328 
329     bool GetBinary(std::vector<uint8_t> &buf) const override;
330     void DumpData(int indent) const override;
331 };
332 
333 class PerfRecordThrottle : public PerfEventRecordTemplate<PerfRecordThrottleData, PERF_RECORD_TYPE_THROTTLE> {
334 public:
335     PerfRecordThrottle() = default;
336 
337     bool GetBinary(std::vector<uint8_t> &buf) const override;
338     void DumpData(int indent) const override;
339 };
340 
341 class PerfRecordUnthrottle : public PerfEventRecordTemplate<PerfRecordThrottleData, PERF_RECORD_TYPE_UNTHROTTLE> {
342 public:
343     PerfRecordUnthrottle() = default;
344 
345     bool GetBinary(std::vector<uint8_t> &buf) const override;
346     void DumpData(int indent) const override;
347 };
348 
349 class PerfRecordFork : public PerfEventRecordTemplate<PerfRecordForkData, PERF_RECORD_TYPE_FORK> {
350 public:
351     PerfRecordFork() = default;
352 
353     bool GetBinary(std::vector<uint8_t> &buf) const override;
354     void DumpData(int indent) const override;
355 };
356 
357 /*
358     This record indicates a read event.
359 */
360 class PerfRecordRead : public PerfEventRecordTemplate<PerfRecordReadData, PERF_RECORD_TYPE_READ> {
361 public:
362     PerfRecordRead() = default;
363 
364     bool GetBinary(std::vector<uint8_t> &buf) const override;
365     void DumpData(int indent) const override;
366 };
367 
368 /*
369     This record reports that new data is available in the
370     separate AUX buffer region.
371 
372     aux_offset
373             offset in the AUX mmap region where the new
374             data begins.
375     aux_size
376             size of the data made available.
377     flags  describes the AUX update.
378             PERF_AUX_FLAG_TRUNCATED
379                 if set, then the data returned was
380                 truncated to fit the available buffer
381                 size.
382 
383             PERF_AUX_FLAG_OVERWRITE
384                 if set, then the data returned has
385                 overwritten previous data.
386 */
387 class PerfRecordAux : public PerfEventRecordTemplate<PerfRecordAuxData, PERF_RECORD_TYPE_AUX> {
388 public:
389     uint64_t sampleType_ = SAMPLE_ID;
390     PerfRecordAux() = default;
391 
392     bool GetBinary(std::vector<uint8_t> &buf) const override;
393     void DumpData(int indent) const override;
394 };
395 
396 /*
397     This record indicates which process has initiated an
398     instruction trace event, allowing tools to properly
399     correlate the instruction addresses in the AUX buffer
400     with the proper executable.
401 
402     pid    process ID of the thread starting an
403             instruction trace.
404     tid    thread ID of the thread starting an instruction
405             trace.
406 */
407 class PerfRecordItraceStart : public PerfEventRecordTemplate<PerfRecordItraceStartData, PERF_RECORD_TYPE_ITRACESTART> {
408 public:
409     PerfRecordItraceStart() = default;
410 
411     bool GetBinary(std::vector<uint8_t> &buf) const override;
412     void DumpData(int indent) const override;
413 };
414 
415 /*
416     When using hardware sampling (such as Intel PEBS) this
417     record indicates some number of samples that may have
418     been lost.
419 */
420 class PerfRecordLostSamples : public PerfEventRecordTemplate<PerfRecordLostSamplesData, PERF_RECORD_TYPE_LOSTSAMPLE> {
421 public:
422     PerfRecordLostSamples() = default;
423 
424     bool GetBinary(std::vector<uint8_t> &buf) const override;
425     void DumpData(int indent) const override;
426 };
427 
428 /*
429     This record indicates a context switch has happened.
430     The PERF_RECORD_MISC_SWITCH_OUT bit in the misc field
431     indicates whether it was a context switch into or away
432     from the current process.
433 */
434 class PerfRecordSwitch : public PerfEventRecordTemplate<PerfRecordSwitchData, PERF_RECORD_TYPE_SWITCH> {
435 public:
436     PerfRecordSwitch() = default;
437 
438     bool GetBinary(std::vector<uint8_t> &buf) const override;
DumpData(int)439     void DumpData(int) const override {};
440 };
441 
442 /*
443     As with PERF_RECORD_SWITCH this record indicates a
444     context switch has happened, but it only occurs when
445     sampling in CPU-wide mode and provides additional
446     information on the process being switched to/from.
447     The PERF_RECORD_MISC_SWITCH_OUT bit in the misc field
448     indicates whether it was a context switch into or away
449     from the current process.
450 
451     next_prev_pid
452             The process ID of the previous (if switching
453             in) or next (if switching out) process on the
454             CPU.
455 
456     next_prev_tid
457             The thread ID of the previous (if switching in)
458             or next (if switching out) thread on the CPU.
459 */
460 class PerfRecordSwitchCpuWide
461     : public PerfEventRecordTemplate<PerfRecordSwitchCpuWideData, PERF_RECORD_TYPE_SWITCHCPUWIDE> {
462 public:
463     PerfRecordSwitchCpuWide() = default;
464 
465     bool GetBinary(std::vector<uint8_t> &buf) const override;
466     void DumpData(int indent) const override;
467 };
468 
469 class PerfRecordNull : public PerfEventRecordTemplate<PerfRecordSwitchCpuWideData, PERF_RECORD_TYPE_NULL> {
470 public:
471     PerfRecordNull() = default;
472 
GetBinary(std::vector<uint8_t> &)473     bool GetBinary(std::vector<uint8_t>&) const override { return false; };
DumpData(int indent)474     void DumpData(int indent) const override {};
475 };
476 
477 class PerfEventRecordFactory {
478 public:
479     static PerfEventRecord& GetPerfEventRecord(PerfRecordType type, uint8_t* data,
480                                                const perf_event_attr& attr);
481 private:
482     static thread_local std::unordered_map<PerfRecordType, PerfEventRecord*> recordMap_;
483 };
484 
485 template<typename T>
486 void PushToBinary(bool condition, uint8_t *&p, const T &v);
487 
488 template<typename T1, typename T2>
489 void PushToBinary2(bool condition, uint8_t *&p, const T1 &v1, const T2 &v2);
490 
491 template<typename T>
492 void PopFromBinary(bool condition, uint8_t *&p, T &v);
493 
494 template<typename T1, typename T2>
495 void PopFromBinary2(bool condition, uint8_t *&p, T1 &v1, T2 &v2);
496 } // namespace HiPerf
497 } // namespace Developtools
498 } // namespace OHOS
499 #endif // HIPERF_PERF_EVENT_RECORD_H
500