• 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(const int indent = 0, std::string outputFilename = "", FILE *outputDump = nullptr) const;
126     virtual void DumpData(const int indent) const = 0;
127     virtual void DumpLog(const std::string& prefix) const;
128 
129 protected:
130     void Init(const perf_event_type type, const bool inKernel);
131     void Init(const 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(const u64 size, const u64 offset, const u64 reference, const u32 idx,
184                        const u32 tid, const u32 cpu, const u32 pid);
185     void Init(uint8_t* data, const perf_event_attr& attr = {}) override;
186 
187     bool GetBinary1(std::vector<uint8_t> &buf) const;
188     bool GetBinary(std::vector<uint8_t> &buf) const override;
189     void DumpData(const int indent) const override;
190     void DumpLog(const std::string &prefix) const override;
191 
192     size_t GetSize() const override;
193 };
194 
195 class PerfRecordAuxTraceInfo : public PerfEventRecordTemplate<PerfRecordAuxtraceInfoData,
196                                PERF_RECORD_TYPE_AUXTRACEINFO> {
197 public:
198     PerfRecordAuxTraceInfo() = default;
199     bool GetBinary(std::vector<uint8_t> &buf) const override;
200     void DumpData(const int indent) const override;
201 };
202 
203 class PerfRecordTimeConv : public PerfEventRecordTemplate<PerfRecordTtimeConvData, PERF_RECORD_TYPE_TIMECONV> {
204 public:
205     PerfRecordTimeConv() = default;
206     bool GetBinary(std::vector<uint8_t> &buf) const override;
207     void DumpData(const int indent) const override;
208 };
209 
210 class PerfRecordCpuMap : public PerfEventRecordTemplate<PerfRecordCpuMapData, PERF_RECORD_TYPE_CPUMAP> {
211 public:
212     PerfRecordCpuMap() = default;
213     bool GetBinary(std::vector<uint8_t> &buf) const override;
214     void DumpData(const int indent) const override;
215 };
216 
217 class PerfRecordMmap : public PerfEventRecordTemplate<PerfRecordMmapData, PERF_RECORD_TYPE_MMAP> {
218 public:
219     PerfRecordMmap() = default;
220     void Init(uint8_t* data, const perf_event_attr& attr = {}) override;
221     PerfRecordMmap(bool inKernel, u32 pid, u32 tid, u64 addr, u64 len, u64 pgoff,
222                    const std::string &filename);
223 
224     bool GetBinary(std::vector<uint8_t> &buf) const override;
225     void DumpData(const int indent) const override;
226     void DumpLog(const std::string &prefix) const override;
227 };
228 
229 class PerfRecordMmap2 : public PerfEventRecordTemplate<PerfRecordMmap2Data, PERF_RECORD_TYPE_MMAP2> {
230 public:
231 
232     PerfRecordMmap2() = default;
233     void Init(uint8_t* data, const perf_event_attr& attr = {}) override;
234     PerfRecordMmap2(const bool inKernel, const u32 pid, const u32 tid, const u64 addr, const u64 len, const u64 pgoff,
235                     const u32 maj, const u32 min, u64 ino, u32 prot, u32 flags, const std::string &filename);
236 
237     PerfRecordMmap2(const bool inKernel, const u32 pid, const u32 tid, std::shared_ptr<DfxMap> item);
238 
239     bool GetBinary(std::vector<uint8_t> &buf) const override;
240     void DumpData(const int indent) const override;
241     void DumpLog(const std::string &prefix) const override;
242     bool discard_ = false;
243 };
244 
245 class PerfRecordLost : public PerfEventRecordTemplate<PerfRecordLostData, PERF_RECORD_TYPE_LOST> {
246 public:
247 
248     PerfRecordLost() = default;
249 
250     bool GetBinary(std::vector<uint8_t> &buf) const override;
251     void DumpData(const int indent) const override;
252 
253     // only for UT
PerfRecordLost(bool inKernel,u64 id,u64 lost)254     PerfRecordLost(bool inKernel, u64 id, u64 lost)
255     {
256         PerfEventRecord::Init(PERF_RECORD_LOST, inKernel);
257         data_.id = id;
258         data_.lost = lost;
259         header_.size = sizeof(header_) + sizeof(data_);
260     }
261 };
262 
263 class PerfRecordComm : public PerfEventRecordTemplate<PerfRecordCommData, PERF_RECORD_TYPE_COMM> {
264 public:
265 
266     PerfRecordComm() = default;
267     void Init(uint8_t* data, const perf_event_attr& attr = {}) override;
268     PerfRecordComm(const bool inKernel, const u32 pid, const u32 tid, const std::string &comm);
269 
270     bool GetBinary(std::vector<uint8_t> &buf) const override;
271     void DumpData(const int indent) const override;
272     void DumpLog(const std::string &prefix) const override;
273 };
274 
275 class PerfRecordSample : public PerfEventRecordTemplate<PerfRecordSampleData, PERF_RECORD_TYPE_SAMPLE> {
276 public:
277     uint64_t sampleType_ = SAMPLE_TYPE;
278     uint64_t skipKernel_ = 0;
279     uint64_t skipPid_ = 0;
280     // extend
281     // hold the new ips memory (after unwind)
282     // used for data_.ips replace (ReplaceWithCallStack)
283     static std::vector<u64> ips_;
284     static std::vector<DfxFrame> callFrames_;
285     static std::vector<pid_t> serverPidMap_;
286 
287     PerfRecordSample() = default;
288     PerfRecordSample(const PerfRecordSample& sample);
289     // referenced input(p) in PerfRecordSample, require caller keep input(p) together
290     void Init(uint8_t* data, const perf_event_attr& attr) override;
291 
292     StackId stackId_ {0};
293     bool removeStack_ {false};
294     static void SetDumpRemoveStack(bool dumpRemoveStack);
295     static bool IsDumpRemoveStack();
296     bool GetBinary(std::vector<uint8_t> &buf) const override;
297     void DumpData(const int indent = 0) const override;
298     void DumpLog(const std::string &prefix) const override;
299 
300     void RecoverCallStack();
301     // originalSize is use for expand callstack
302     void ReplaceWithCallStack(const size_t originalSize = 0);
303     pid_t GetPid() const override;
304     uint64_t GetTime() const;
305     void Clean();
306 
307     // only for UT
308     PerfRecordSample(const bool inKernel, const u32 pid, const u32 tid, const u64 period = 0,
309                      const u64 time = 0, const u64 id = 0)
310     {
311         PerfEventRecord::Init(PERF_RECORD_SAMPLE, inKernel);
312         Clean();
313         data_.pid = pid;
314         data_.tid = tid;
315         data_.period = period;
316         data_.time = time;
317         data_.id = 0;
318         header_.size = sizeof(header_) + sizeof(data_);
319     }
320 
321     pid_t GetUstackServerPid();
322     pid_t GetServerPidof(unsigned int ipNr);
323 private:
324     static bool dumpRemoveStack_;
325 };
326 
327 class PerfRecordExit : public PerfEventRecordTemplate<PerfRecordExitData, PERF_RECORD_TYPE_EXIT> {
328 public:
329     PerfRecordExit() = default;
330 
331     bool GetBinary(std::vector<uint8_t> &buf) const override;
332     void DumpData(const int indent) const override;
333 };
334 
335 class PerfRecordThrottle : public PerfEventRecordTemplate<PerfRecordThrottleData, PERF_RECORD_TYPE_THROTTLE> {
336 public:
337     PerfRecordThrottle() = default;
338 
339     bool GetBinary(std::vector<uint8_t> &buf) const override;
340     void DumpData(const int indent) const override;
341 };
342 
343 class PerfRecordUnthrottle : public PerfEventRecordTemplate<PerfRecordThrottleData, PERF_RECORD_TYPE_UNTHROTTLE> {
344 public:
345     PerfRecordUnthrottle() = default;
346 
347     bool GetBinary(std::vector<uint8_t> &buf) const override;
348     void DumpData(const int indent) const override;
349 };
350 
351 class PerfRecordFork : public PerfEventRecordTemplate<PerfRecordForkData, PERF_RECORD_TYPE_FORK> {
352 public:
353     PerfRecordFork() = default;
354 
355     bool GetBinary(std::vector<uint8_t> &buf) const override;
356     void DumpData(const int indent) const override;
357 };
358 
359 /*
360     This record indicates a read event.
361 */
362 class PerfRecordRead : public PerfEventRecordTemplate<PerfRecordReadData, PERF_RECORD_TYPE_READ> {
363 public:
364     PerfRecordRead() = default;
365 
366     bool GetBinary(std::vector<uint8_t> &buf) const override;
367     void DumpData(const int indent) const override;
368 };
369 
370 /*
371     This record reports that new data is available in the
372     separate AUX buffer region.
373 
374     aux_offset
375             offset in the AUX mmap region where the new
376             data begins.
377     aux_size
378             size of the data made available.
379     flags  describes the AUX update.
380             PERF_AUX_FLAG_TRUNCATED
381                 if set, then the data returned was
382                 truncated to fit the available buffer
383                 size.
384 
385             PERF_AUX_FLAG_OVERWRITE
386                 if set, then the data returned has
387                 overwritten previous data.
388 */
389 class PerfRecordAux : public PerfEventRecordTemplate<PerfRecordAuxData, PERF_RECORD_TYPE_AUX> {
390 public:
391     uint64_t sampleType_ = SAMPLE_ID;
392     PerfRecordAux() = default;
393 
394     bool GetBinary(std::vector<uint8_t> &buf) const override;
395     void DumpData(const int indent) const override;
396 };
397 
398 /*
399     This record indicates which process has initiated an
400     instruction trace event, allowing tools to properly
401     correlate the instruction addresses in the AUX buffer
402     with the proper executable.
403 
404     pid    process ID of the thread starting an
405             instruction trace.
406     tid    thread ID of the thread starting an instruction
407             trace.
408 */
409 class PerfRecordItraceStart : public PerfEventRecordTemplate<PerfRecordItraceStartData, PERF_RECORD_TYPE_ITRACESTART> {
410 public:
411     PerfRecordItraceStart() = default;
412 
413     bool GetBinary(std::vector<uint8_t> &buf) const override;
414     void DumpData(const int indent) const override;
415 };
416 
417 /*
418     When using hardware sampling (such as Intel PEBS) this
419     record indicates some number of samples that may have
420     been lost.
421 */
422 class PerfRecordLostSamples : public PerfEventRecordTemplate<PerfRecordLostSamplesData, PERF_RECORD_TYPE_LOSTSAMPLE> {
423 public:
424     PerfRecordLostSamples() = default;
425 
426     bool GetBinary(std::vector<uint8_t> &buf) const override;
427     void DumpData(const int indent) const override;
428 };
429 
430 /*
431     This record indicates a context switch has happened.
432     The PERF_RECORD_MISC_SWITCH_OUT bit in the misc field
433     indicates whether it was a context switch into or away
434     from the current process.
435 */
436 class PerfRecordSwitch : public PerfEventRecordTemplate<PerfRecordSwitchData, PERF_RECORD_TYPE_SWITCH> {
437 public:
438     PerfRecordSwitch() = default;
439 
440     bool GetBinary(std::vector<uint8_t> &buf) const override;
DumpData(const int)441     void DumpData(const int) const override {};
442 };
443 
444 /*
445     As with PERF_RECORD_SWITCH this record indicates a
446     context switch has happened, but it only occurs when
447     sampling in CPU-wide mode and provides additional
448     information on the process being switched to/from.
449     The PERF_RECORD_MISC_SWITCH_OUT bit in the misc field
450     indicates whether it was a context switch into or away
451     from the current process.
452 
453     next_prev_pid
454             The process ID of the previous (if switching
455             in) or next (if switching out) process on the
456             CPU.
457 
458     next_prev_tid
459             The thread ID of the previous (if switching in)
460             or next (if switching out) thread on the CPU.
461 */
462 class PerfRecordSwitchCpuWide
463     : public PerfEventRecordTemplate<PerfRecordSwitchCpuWideData, PERF_RECORD_TYPE_SWITCHCPUWIDE> {
464 public:
465     PerfRecordSwitchCpuWide() = default;
466 
467     bool GetBinary(std::vector<uint8_t> &buf) const override;
468     void DumpData(const int indent) const override;
469 };
470 
471 class PerfRecordNull : public PerfEventRecordTemplate<PerfRecordSwitchCpuWideData, PERF_RECORD_TYPE_NULL> {
472 public:
473     PerfRecordNull() = default;
474 
GetBinary(std::vector<uint8_t> &)475     bool GetBinary(std::vector<uint8_t>&) const override { return false; };
DumpData(const int indent)476     void DumpData(const int indent) const override {};
477 };
478 
479 class PerfEventRecordFactory {
480 public:
481     static PerfEventRecord& GetPerfEventRecord(PerfRecordType type, uint8_t* data,
482                                                const perf_event_attr& attr);
483 private:
484     static thread_local std::unordered_map<PerfRecordType, PerfEventRecord*> recordMap_;
485 };
486 
487 template<typename T>
488 void PushToBinary(const bool condition, uint8_t *&p, const T &v);
489 
490 template<typename T1, typename T2>
491 void PushToBinary2(const bool condition, uint8_t *&p, const T1 &v1, const T2 &v2);
492 
493 template<typename T>
494 void PopFromBinary(const bool condition, uint8_t *&p, T &v);
495 
496 template<typename T1, typename T2>
497 void PopFromBinary2(const bool condition, uint8_t *&p, T1 &v1, T2 &v2);
498 } // namespace HiPerf
499 } // namespace Developtools
500 } // namespace OHOS
501 #endif // HIPERF_PERF_EVENT_RECORD_H
502