• 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 #define HILOG_TAG "PerfRecord"
16 
17 #include "perf_event_record.h"
18 #include "spe_decoder.h"
19 #include <cinttypes>
20 
21 #include "utilities.h"
22 
23 namespace OHOS {
24 namespace Developtools {
25 namespace HiPerf {
26 
27 bool PerfRecordSample::dumpRemoveStack_ = false;
28 std::vector<u64> PerfRecordSample::ips_ = {};
29 std::vector<DfxFrame> PerfRecordSample::callFrames_ = {};
30 std::vector<pid_t> PerfRecordSample::serverPidMap_ = {};
31 thread_local std::unordered_map<PerfRecordType, PerfEventRecord*> PerfEventRecordFactory::recordMap_ = {};
32 
CreatePerfEventRecord(PerfRecordType type)33 static PerfEventRecord* CreatePerfEventRecord(PerfRecordType type)
34 {
35     switch (type) {
36         case PERF_RECORD_SAMPLE:
37             return new PerfRecordSample();
38         case PERF_RECORD_MMAP:
39             return new PerfRecordMmap();
40         case PERF_RECORD_MMAP2:
41             return new PerfRecordMmap2();
42         case PERF_RECORD_LOST:
43             return new PerfRecordLost();
44         case PERF_RECORD_COMM:
45             return new PerfRecordComm();
46         case PERF_RECORD_EXIT:
47             return new PerfRecordExit();
48         case PERF_RECORD_THROTTLE:
49             return new PerfRecordThrottle();
50         case PERF_RECORD_UNTHROTTLE:
51             return new PerfRecordUnthrottle();
52         case PERF_RECORD_FORK:
53             return new PerfRecordFork();
54         case PERF_RECORD_READ:
55             return new PerfRecordRead();
56         case PERF_RECORD_AUX:
57             return new PerfRecordAux();
58         case PERF_RECORD_AUXTRACE:
59             return new PerfRecordAuxtrace();
60         case PERF_RECORD_AUXTRACE_INFO:
61             return new PerfRecordAuxTraceInfo();
62         case PERF_RECORD_TIME_CONV:
63             return new PerfRecordTimeConv();
64         case PERF_RECORD_CPU_MAP:
65             return new PerfRecordCpuMap();
66         case PERF_RECORD_ITRACE_START:
67             return new PerfRecordItraceStart();
68         case PERF_RECORD_LOST_SAMPLES:
69             return new PerfRecordLostSamples();
70         case PERF_RECORD_SWITCH:
71             return new PerfRecordSwitch();
72         case PERF_RECORD_SWITCH_CPU_WIDE:
73             return new PerfRecordSwitchCpuWide();
74         default:
75             HLOGE("unknown record type %d\n", type);
76             return new PerfRecordNull();
77     }
78 }
79 
80 template<typename T>
PushToBinary(const bool condition,uint8_t * & p,const T & v)81 inline void PushToBinary(const bool condition, uint8_t *&p, const T &v)
82 {
83     if (condition) {
84         *(reinterpret_cast<T *>(p)) = v;
85         p += sizeof(T);
86     }
87 }
88 
89 template<typename T1, typename T2>
PushToBinary2(const bool condition,uint8_t * & p,const T1 & v1,const T2 & v2)90 inline void PushToBinary2(const bool condition, uint8_t *&p, const T1 &v1, const T2 &v2)
91 {
92     if (condition) {
93         *(reinterpret_cast<T1 *>(p)) = v1;
94         p += sizeof(T1);
95         *(reinterpret_cast<T2 *>(p)) = v2;
96         p += sizeof(T2);
97     }
98 }
99 
100 template<typename T>
PopFromBinary(const bool condition,uint8_t * & p,T & v,u64 & size)101 inline void PopFromBinary(const bool condition, uint8_t*& p, T& v, u64& size)
102 {
103     HIPERF_ASSERT(sizeof(T) <= size, "PopFromBinary error\n");
104     if (condition) {
105         v = *(reinterpret_cast<const T *>(p));
106         p += sizeof(T);
107         size -= sizeof(T);
108     }
109 }
110 
111 template<typename T1, typename T2>
PopFromBinary2(const bool condition,uint8_t * & p,T1 & v1,T2 & v2,u64 & size)112 inline void PopFromBinary2(const bool condition, uint8_t*& p, T1& v1, T2& v2, u64& size)
113 {
114     HIPERF_ASSERT(sizeof(T1) + sizeof(T2) <= size, "PopFromBinary2 error\n");
115     if (condition) {
116         v1 = *(reinterpret_cast<const T1 *>(p));
117         p += sizeof(T1);
118         v2 = *(reinterpret_cast<const T2 *>(p));
119         p += sizeof(T2);
120         size -= (sizeof(T1) + sizeof(T2));
121     }
122 }
123 
SetPointerOffset(uint8_t * & p,u64 offset,u64 & size)124 inline void SetPointerOffset(uint8_t*& p, u64 offset, u64& size)
125 {
126     HIPERF_ASSERT(offset <= size && offset <= RECORD_SIZE_LIMIT, "SetPointerOffset error\n");
127     size -= offset;
128     p += offset;
129 }
130 
GetHeaderBinary(std::vector<uint8_t> & buf) const131 void PerfEventRecord::GetHeaderBinary(std::vector<uint8_t> &buf) const
132 {
133     if (buf.size() < GetHeaderSize()) {
134         buf.resize(GetHeaderSize());
135     }
136     uint8_t *p = buf.data();
137     *(reinterpret_cast<perf_event_header*>(p)) = header_;
138 }
139 
Dump(const int indent,std::string outputFilename,FILE * outputDump) const140 void PerfEventRecord::Dump(const int indent, std::string outputFilename, FILE *outputDump) const
141 {
142     if (outputDump != nullptr) {
143         g_outputDump = outputDump;
144     } else if (!outputFilename.empty() && g_outputDump == nullptr) {
145         std::string resolvedPath = CanonicalizeSpecPath(outputFilename.c_str());
146         g_outputDump = fopen(resolvedPath.c_str(), "w");
147         if (g_outputDump == nullptr) {
148             printf("unable open file to '%s' because '%d'\n", outputFilename.c_str(), errno);
149             return;
150         }
151     }
152     PRINT_INDENT(indent, "\n");
153     PRINT_INDENT(indent, "record %s: type %u, misc %u, size %zu\n", GetName(), GetType(),
154                  GetMisc(), GetSize());
155     DumpData(indent + 1);
156 }
157 
DumpLog(const std::string & prefix) const158 void PerfEventRecord::DumpLog(const std::string &prefix) const
159 {
160     HLOGV("%s: record %s: type %u, misc %u, size %zu\n", prefix.c_str(), GetName(),
161           GetType(), GetMisc(), GetSize());
162 }
163 
Init(const perf_event_type type,const bool inKernel)164 void PerfEventRecord::Init(const perf_event_type type, const bool inKernel)
165 {
166     header_.type = type;
167     header_.misc = inKernel ? PERF_RECORD_MISC_KERNEL : PERF_RECORD_MISC_USER;
168     header_.size = sizeof(header_);
169 };
170 
Init(const perf_event_hiperf_ext_type type)171 void PerfEventRecord::Init(const perf_event_hiperf_ext_type type)
172 {
173     header_.type = type;
174     header_.misc = PERF_RECORD_MISC_USER;
175     header_.size = sizeof(header_);
176 }
177 
InitHeader(uint8_t * p)178 void PerfEventRecord::InitHeader(uint8_t* p)
179 {
180     if (p == nullptr) {
181         header_.type = PERF_RECORD_MMAP;
182         header_.misc = PERF_RECORD_MISC_USER;
183         header_.size = 0;
184         return;
185     }
186     header_ = *(reinterpret_cast<perf_event_header*>(p));
187 }
188 
Init(uint8_t * data,const perf_event_attr & attr)189 void PerfRecordAuxtrace::Init(uint8_t* data, const perf_event_attr& attr)
190 {
191     data_ = {};
192     rawData_ = nullptr;
193     if (data == nullptr) {
194         PerfEventRecord::InitHeader(data);
195         HLOGE("Init failed");
196         return;
197     }
198     PerfEventRecordTemplate::Init(data);
199     if (header_.size != sizeof(header_) + sizeof(data_)) {
200         HLOGE("header_.size invalid");
201         return;
202     }
203     rawData_ = data + header_.size;
204 }
205 
PerfRecordAuxtrace(const u64 size,const u64 offset,const u64 reference,const u32 idx,const u32 tid,const u32 cpu,const u32 pid)206 PerfRecordAuxtrace::PerfRecordAuxtrace(const u64 size, const u64 offset, const u64 reference, const u32 idx,
207                                        const u32 tid, const u32 cpu, const u32 pid)
208 {
209     PerfEventRecord::Init(PERF_RECORD_AUXTRACE);
210     data_.size = size;
211     data_.offset = offset;
212     data_.reference = reference;
213     data_.idx = idx;
214     data_.tid = tid;
215     data_.cpu = cpu;
216     data_.reserved__ = pid;
217 
218     header_.size = sizeof(header_) + sizeof(data_);
219 }
220 
GetBinary1(std::vector<uint8_t> & buf) const221 bool PerfRecordAuxtrace::GetBinary1(std::vector<uint8_t> &buf) const
222 {
223     if (buf.size() < header_.size) {
224         buf.resize(header_.size);
225     }
226 
227     GetHeaderBinary(buf);
228     uint8_t *p = buf.data() + GetHeaderSize();
229 
230     size_t copySize = header_.size - GetHeaderSize();
231     if (memcpy_s(p, buf.size() - GetHeaderSize(), reinterpret_cast<const uint8_t *>(&data_), copySize) != 0) {
232         HLOGE("memcpy_s return failed in GetBinary1");
233         return false;
234     }
235     return true;
236 }
237 
GetBinary(std::vector<uint8_t> & buf) const238 bool PerfRecordAuxtrace::GetBinary(std::vector<uint8_t> &buf) const
239 {
240     if (buf.size() < GetSize()) {
241         buf.resize(GetSize());
242     }
243 
244     GetHeaderBinary(buf);
245     uint8_t *p = buf.data() + GetHeaderSize();
246 
247     size_t copySize = header_.size - GetHeaderSize();
248     if (memcpy_s(p, buf.size() - GetHeaderSize(), reinterpret_cast<const uint8_t *>(&data_), copySize) != 0) {
249         HLOGE("memcpy_s return failed in GetBinary with data_");
250         return false;
251     }
252     p += header_.size - GetHeaderSize();
253     if (memcpy_s(p, buf.size() - header_.size, static_cast<uint8_t *>(rawData_), data_.size) != 0) {
254         HLOGE("memcpy_s return failed in GetBinary with rawData_");
255         return false;
256     }
257     return true;
258 }
259 
DumpData(const int indent) const260 void PerfRecordAuxtrace::DumpData(const int indent) const
261 {
262     PRINT_INDENT(indent, "size 0x%llx, offset 0x%llx, reference 0x%llx, idx %u, tid %u, cpu %u, pid %u\n",
263                  data_.size, data_.offset, data_.reference, data_.idx, data_.tid, data_.cpu, data_.reserved__);
264 #if defined(is_ohos) && is_ohos
265     if (!SpeDumpRawData(rawData_, data_.size, indent, g_outputDump)) {
266         HLOGE("SpeDumpRawData failed");
267     }
268 #endif
269 }
270 
DumpLog(const std::string & prefix) const271 void PerfRecordAuxtrace::DumpLog(const std::string &prefix) const
272 {
273     HLOGV("size %llu, offset 0x%llx, reference 0x%llx, idx %u, tid %u, cpu %u\n",
274           data_.size, data_.offset, data_.reference, data_.idx, data_.tid, data_.cpu);
275 }
276 
GetSize() const277 size_t PerfRecordAuxtrace::GetSize() const
278 {
279     return header_.size + data_.size;
280 }
281 
Init(uint8_t * data,const perf_event_attr &)282 void PerfRecordMmap::Init(uint8_t* data, const perf_event_attr&)
283 {
284     PerfEventRecordTemplate::Init(data);
285     data_.filename[KILO - 1] = '\0';
286 }
287 
PerfRecordMmap(bool inKernel,u32 pid,u32 tid,u64 addr,u64 len,u64 pgoff,const std::string & filename)288 PerfRecordMmap::PerfRecordMmap(bool inKernel, u32 pid, u32 tid, u64 addr, u64 len, u64 pgoff,
289                                const std::string &filename)
290 {
291     PerfEventRecord::Init(PERF_RECORD_MMAP, inKernel);
292 
293     data_.pid = pid;
294     data_.tid = tid;
295     data_.addr = addr;
296     data_.len = len;
297     data_.pgoff = pgoff;
298     if (strncpy_s(data_.filename, KILO, filename.c_str(), filename.size()) != 0) {
299         HLOGE("strncpy_s failed");
300     }
301 
302     header_.size = sizeof(header_) + sizeof(data_) - KILO + filename.size() + 1;
303 }
304 
GetBinary(std::vector<uint8_t> & buf) const305 bool PerfRecordMmap::GetBinary(std::vector<uint8_t> &buf) const
306 {
307     if (buf.size() < GetSize()) {
308         buf.resize(GetSize());
309     }
310 
311     GetHeaderBinary(buf);
312     uint8_t *p = buf.data() + GetHeaderSize();
313 
314     // data_.filename[] is variable-length
315     std::copy(reinterpret_cast<const uint8_t *>(&data_),
316               reinterpret_cast<const uint8_t *>(&data_) + GetSize() - GetHeaderSize(), p);
317     return true;
318 }
319 
DumpData(const int indent) const320 void PerfRecordMmap::DumpData(const int indent) const
321 {
322 #if defined(is_ohos) && is_ohos
323     if (IsRoot()) {
324         PRINT_INDENT(indent, "pid %u, tid %u, addr 0x%llx, len 0x%llx\n", data_.pid, data_.tid,
325                      data_.addr, data_.len);
326         PRINT_INDENT(indent, "pgoff 0x%llx, filename %s\n", data_.pgoff, data_.filename);
327     }
328 #endif
329 }
330 
DumpLog(const std::string & prefix) const331 void PerfRecordMmap::DumpLog(const std::string &prefix) const
332 {
333     HLOGV("%s:  MMAP: size %d pid %u tid %u dso '%s' (0x%llx-0x%llx)@0x%llx", prefix.c_str(),
334           header_.size, data_.pid, data_.tid, data_.filename, data_.addr, data_.addr + data_.len, data_.pgoff);
335 }
336 
Init(uint8_t * data,const perf_event_attr &)337 void PerfRecordMmap2::Init(uint8_t* data, const perf_event_attr&)
338 {
339     PerfEventRecordTemplate::Init(data);
340     discard_ = false;
341 }
342 
PerfRecordMmap2(const bool inKernel,const u32 pid,const u32 tid,const u64 addr,const u64 len,const u64 pgoff,const u32 maj,const u32 min,const u64 ino,const u32 prot,const u32 flags,const std::string & filename)343 PerfRecordMmap2::PerfRecordMmap2(const bool inKernel, const u32 pid, const u32 tid, const u64 addr, const u64 len,
344                                  const u64 pgoff, const u32 maj, const u32 min, const u64 ino, const u32 prot,
345                                  const u32 flags, const std::string &filename)
346 {
347     PerfEventRecord::Init(PERF_RECORD_MMAP2, inKernel);
348     data_.pid = pid;
349     data_.tid = tid;
350     data_.addr = addr;
351     data_.len = len;
352     data_.pgoff = pgoff;
353     data_.maj = maj;
354     data_.min = min;
355     data_.ino = ino;
356     data_.ino_generation = 0;
357     data_.prot = prot;
358     data_.flags = flags;
359     if (strncpy_s(data_.filename, KILO, filename.c_str(), filename.size()) != 0) {
360         HLOGE("strncpy_s failed");
361     }
362 
363     header_.size = sizeof(header_) + sizeof(data_) - KILO + filename.size() + 1;
364 }
365 
PerfRecordMmap2(const bool inKernel,const u32 pid,const u32 tid,std::shared_ptr<DfxMap> item)366 PerfRecordMmap2::PerfRecordMmap2(const bool inKernel, const u32 pid, const u32 tid, std::shared_ptr<DfxMap> item)
367 {
368     PerfEventRecord::Init(PERF_RECORD_MMAP2, inKernel);
369     data_.pid = pid;
370     data_.tid = tid;
371     if (item != nullptr) {
372         data_.addr = item->begin;
373         data_.len = item->end - item->begin;
374         data_.pgoff = item->offset;
375         data_.maj = item->major;
376         data_.min = item->minor;
377         data_.ino = item->inode;
378         data_.ino_generation = 0;
379         // r--p 00000000 103:3e 12307                         /data/storage/el1/bundle/entry.hap
380         // why prot get from this is 7. rwxp
381         DfxMap::PermsToProts(item->perms, data_.prot, data_.flags);
382         if (strncpy_s(data_.filename, KILO, item->name.c_str(), item->name.size()) != 0) {
383             HLOGE("strncpy_s failed");
384         }
385 
386         header_.size = sizeof(header_) + sizeof(data_) - KILO + item->name.size() + 1;
387     } else {
388         data_.addr = 0;
389         data_.len = 0;
390         data_.pgoff = 0;
391         data_.maj = 0;
392         data_.min = 0;
393         data_.ino = 0;
394         data_.ino_generation = 0;
395         if (memset_s(data_.filename, KILO, 0, KILO) != EOK) {
396             HLOGE("memset_s failed");
397         }
398     }
399 }
400 
GetBinary(std::vector<uint8_t> & buf) const401 bool PerfRecordMmap2::GetBinary(std::vector<uint8_t> &buf) const
402 {
403     if (buf.size() < GetSize()) {
404         buf.resize(GetSize());
405     }
406 
407     GetHeaderBinary(buf);
408     uint8_t *p = buf.data() + GetHeaderSize();
409 
410     // data_.filename[] is variable-length
411     std::copy(reinterpret_cast<const uint8_t *>(&data_),
412               reinterpret_cast<const uint8_t *>(&data_) + GetSize() - GetHeaderSize(), p);
413     return true;
414 }
415 
DumpData(const int indent) const416 void PerfRecordMmap2::DumpData(const int indent) const
417 {
418 #if defined(is_ohos) && is_ohos
419     if (IsRoot()) {
420         PRINT_INDENT(indent, "pid %u, tid %u, addr 0x%llx, len 0x%llx\n", data_.pid, data_.tid,
421                      data_.addr, data_.len);
422         PRINT_INDENT(indent, "pgoff 0x%llx, maj %u, min %u, ino %llu, ino_generation %llu\n",
423                      data_.pgoff, data_.maj, data_.min, data_.ino, data_.ino_generation);
424         PRINT_INDENT(indent, "prot %u, flags %u, filename %s\n", data_.prot, data_.flags,
425                      data_.filename);
426     }
427 #endif
428 }
429 
DumpLog(const std::string & prefix) const430 void PerfRecordMmap2::DumpLog(const std::string &prefix) const
431 {
432     HLOGV("%s:  MMAP2: size %d pid %u tid %u dso '%s' (0x%llx-0x%llx)@0x%llx", prefix.c_str(),
433           header_.size, data_.pid, data_.tid, data_.filename, data_.addr, data_.addr + data_.len,
434           data_.pgoff);
435 }
436 
GetBinary(std::vector<uint8_t> & buf) const437 bool PerfRecordLost::GetBinary(std::vector<uint8_t> &buf) const
438 {
439     if (buf.size() < GetSize()) {
440         buf.resize(GetSize());
441     }
442 
443     GetHeaderBinary(buf);
444     uint8_t *p = buf.data() + GetHeaderSize();
445 
446     auto pDest = reinterpret_cast<PerfRecordLostData *>(p);
447     *pDest = data_;
448 
449     return true;
450 }
451 
DumpData(const int indent) const452 void PerfRecordLost::DumpData(const int indent) const
453 {
454     PRINT_INDENT(indent, "id %llu, lost %llu\n", data_.id, data_.lost);
455 }
456 
Init(uint8_t * data,const perf_event_attr &)457 void PerfRecordComm::Init(uint8_t* data, const perf_event_attr&)
458 {
459     PerfEventRecordTemplate::Init(data);
460     data_.comm[KILO - 1] = '\0';
461 }
462 
PerfRecordComm(const bool inKernel,const u32 pid,const u32 tid,const std::string & comm)463 PerfRecordComm::PerfRecordComm(const bool inKernel, const u32 pid, const u32 tid, const std::string &comm)
464 {
465     PerfEventRecord::Init(PERF_RECORD_COMM, inKernel);
466     data_.pid = pid;
467     data_.tid = tid;
468     if (strncpy_s(data_.comm, KILO, comm.c_str(), comm.size()) != 0) {
469         HLOGE("strncpy_s failed !!!");
470     }
471 
472     header_.size = sizeof(header_) + sizeof(data_) - KILO + comm.size() + 1;
473 }
474 
GetBinary(std::vector<uint8_t> & buf) const475 bool PerfRecordComm::GetBinary(std::vector<uint8_t> &buf) const
476 {
477     if (buf.size() < GetSize()) {
478         buf.resize(GetSize());
479     }
480 
481     GetHeaderBinary(buf);
482     uint8_t *p = buf.data() + GetHeaderSize();
483 
484     // data_.comm[] is variable-length
485     std::copy(reinterpret_cast<const uint8_t *>(&data_),
486               reinterpret_cast<const uint8_t *>(&data_) + GetSize() - GetHeaderSize(), p);
487 
488     return true;
489 }
490 
DumpData(const int indent) const491 void PerfRecordComm::DumpData(const int indent) const
492 {
493     PRINT_INDENT(indent, "pid %u, tid %u, comm %s\n", data_.pid, data_.tid, data_.comm);
494 }
495 
DumpLog(const std::string & prefix) const496 void PerfRecordComm::DumpLog(const std::string &prefix) const
497 {
498     HLOGV("pid %u, tid %u, comm %s\n", data_.pid, data_.tid, data_.comm);
499 }
500 
PerfRecordSample(const PerfRecordSample & sample)501 PerfRecordSample::PerfRecordSample(const PerfRecordSample& sample)
502 {
503     header_ = sample.header_;
504     data_ = sample.data_;
505 
506     sampleType_ = sample.sampleType_;
507     skipKernel_ = sample.skipKernel_;
508     skipPid_ = sample.skipPid_;
509 
510     ips_ = sample.ips_;
511     callFrames_ = sample.callFrames_;
512     serverPidMap_ = sample.serverPidMap_;
513 
514     stackId_ = sample.stackId_;
515     removeStack_ = sample.removeStack_;
516 }
517 
Init(uint8_t * p,const perf_event_attr & attr)518 void PerfRecordSample::Init(uint8_t *p, const perf_event_attr &attr)
519 {
520     PerfEventRecord::InitHeader(p);
521 
522     HLOG_ASSERT(p != nullptr);
523     // clear the vector data
524     Clean();
525     sampleType_ = attr.sample_type;
526     skipKernel_ = 0;
527     skipPid_ = 0;
528     stackId_ = {0};
529     removeStack_ = false;
530     data_ = {};
531     uint8_t *start = p;
532     u64 dataSize = static_cast<u64>(RECORD_SIZE_LIMIT);
533     SetPointerOffset(p, sizeof(header_), dataSize);
534 
535     // parse record according SAMPLE_TYPE
536     PopFromBinary(sampleType_ & PERF_SAMPLE_IDENTIFIER, p, data_.sample_id, dataSize);
537     PopFromBinary(sampleType_ & PERF_SAMPLE_IP, p, data_.ip, dataSize);
538     PopFromBinary2(sampleType_ & PERF_SAMPLE_TID, p, data_.pid, data_.tid, dataSize);
539     PopFromBinary(sampleType_ & PERF_SAMPLE_TIME, p, data_.time, dataSize);
540     PopFromBinary(sampleType_ & PERF_SAMPLE_ADDR, p, data_.addr, dataSize);
541     PopFromBinary(sampleType_ & PERF_SAMPLE_ID, p, data_.id, dataSize);
542     PopFromBinary(sampleType_ & PERF_SAMPLE_STREAM_ID, p, data_.stream_id, dataSize);
543     PopFromBinary2(sampleType_ & PERF_SAMPLE_CPU, p, data_.cpu, data_.res, dataSize);
544     PopFromBinary(sampleType_ & PERF_SAMPLE_PERIOD, p, data_.period, dataSize);
545     PopFromBinary(sampleType_ & PERF_SAMPLE_CALLCHAIN, p, data_.nr, dataSize);
546     if (data_.nr > 0) {
547         // the pointer is from input(p), require caller keep input(p) with *this together
548         // think it in next time
549         data_.ips = reinterpret_cast<u64 *>(p);
550         SetPointerOffset(p, data_.nr * sizeof(u64), dataSize);
551     }
552     PopFromBinary(sampleType_ & PERF_SAMPLE_RAW, p, data_.raw_size, dataSize);
553     if (data_.raw_size > 0) {
554         data_.raw_data = p;
555         SetPointerOffset(p, data_.raw_size * sizeof(u8), dataSize);
556     }
557     PopFromBinary(sampleType_ & PERF_SAMPLE_BRANCH_STACK, p, data_.bnr, dataSize);
558     if (data_.bnr > 0) {
559         data_.lbr = reinterpret_cast<PerfBranchEntry *>(p);
560         SetPointerOffset(p, data_.bnr * sizeof(PerfBranchEntry), dataSize);
561     }
562     PopFromBinary(sampleType_ & PERF_SAMPLE_REGS_USER, p, data_.user_abi, dataSize);
563     if (data_.user_abi > 0) {
564         data_.reg_mask = attr.sample_regs_user;
565         data_.reg_nr = __builtin_popcountll(data_.reg_mask);
566         data_.user_regs = reinterpret_cast<u64 *>(p);
567         SetPointerOffset(p, data_.reg_nr * sizeof(u64), dataSize);
568     }
569     PopFromBinary(sampleType_ & PERF_SAMPLE_SERVER_PID, p, data_.server_nr, dataSize);
570     if (data_.server_nr > 0) {
571         data_.server_pids = reinterpret_cast<u64 *>(p);
572         SetPointerOffset(p, data_.server_nr * sizeof(u64), dataSize);
573     }
574     PopFromBinary(sampleType_ & PERF_SAMPLE_STACK_USER, p, data_.stack_size, dataSize);
575     if (data_.stack_size > 0) {
576         data_.stack_data = p;
577         SetPointerOffset(p, data_.stack_size, dataSize);
578         PopFromBinary(true, p, data_.dyn_size, dataSize);
579     }
580     uint32_t remain = header_.size - (p - start);
581     if (data_.nr == 0 && dumpRemoveStack_ && remain == sizeof(stackId_)) {
582         PopFromBinary(true, p, stackId_.value, dataSize);
583     }
584 }
585 
SetDumpRemoveStack(bool dumpRemoveStack)586 void PerfRecordSample::SetDumpRemoveStack(bool dumpRemoveStack)
587 {
588     dumpRemoveStack_ = dumpRemoveStack;
589 }
590 
IsDumpRemoveStack()591 bool PerfRecordSample::IsDumpRemoveStack()
592 {
593     return dumpRemoveStack_;
594 }
595 
GetBinary(std::vector<uint8_t> & buf) const596 bool PerfRecordSample::GetBinary(std::vector<uint8_t> &buf) const
597 {
598     if (buf.size() < GetSize()) {
599         buf.resize(GetSize());
600     }
601 
602     GetHeaderBinary(buf);
603     uint8_t *p = buf.data() + GetHeaderSize();
604 
605     PushToBinary(sampleType_ & PERF_SAMPLE_IDENTIFIER, p, data_.sample_id);
606     PushToBinary(sampleType_ & PERF_SAMPLE_IP, p, data_.ip);
607     PushToBinary2(sampleType_ & PERF_SAMPLE_TID, p, data_.pid, data_.tid);
608     PushToBinary(sampleType_ & PERF_SAMPLE_TIME, p, data_.time);
609     PushToBinary(sampleType_ & PERF_SAMPLE_ADDR, p, data_.addr);
610     PushToBinary(sampleType_ & PERF_SAMPLE_ID, p, data_.id);
611     PushToBinary(sampleType_ & PERF_SAMPLE_STREAM_ID, p, data_.stream_id);
612     PushToBinary2(sampleType_ & PERF_SAMPLE_CPU, p, data_.cpu, data_.res);
613     PushToBinary(sampleType_ & PERF_SAMPLE_PERIOD, p, data_.period);
614     PushToBinary(sampleType_ & PERF_SAMPLE_CALLCHAIN, p, data_.nr);
615     if (data_.nr > 0 && !removeStack_) {
616         std::copy(data_.ips + skipKernel_, data_.ips + data_.nr + skipKernel_,
617                   reinterpret_cast<u64 *>(p));
618         p += data_.nr * sizeof(u64);
619     }
620     PushToBinary(sampleType_ & PERF_SAMPLE_RAW, p, data_.raw_size);
621     if (data_.raw_size > 0) {
622         std::copy(data_.raw_data, data_.raw_data + data_.raw_size, p);
623         p += data_.raw_size * sizeof(u8);
624     }
625     PushToBinary(sampleType_ & PERF_SAMPLE_BRANCH_STACK, p, data_.bnr);
626     if (data_.bnr > 0) {
627         std::copy(data_.lbr, data_.lbr + data_.bnr, reinterpret_cast<PerfBranchEntry *>(p));
628         p += data_.bnr * sizeof(PerfBranchEntry);
629     }
630     PushToBinary(sampleType_ & PERF_SAMPLE_REGS_USER, p, data_.user_abi);
631     if (data_.user_abi > 0 && data_.reg_nr > 0) {
632         std::copy(data_.user_regs, data_.user_regs + data_.reg_nr, reinterpret_cast<u64 *>(p));
633         p += data_.reg_nr * sizeof(u64);
634     }
635     PushToBinary(sampleType_ & PERF_SAMPLE_SERVER_PID, p, data_.server_nr);
636     if (data_.server_nr > 0) {
637         std::copy(data_.server_pids + skipPid_, data_.server_pids + data_.server_nr + skipPid_,
638                   reinterpret_cast<u64 *>(p));
639         p += data_.server_nr * sizeof(u64);
640     }
641     PushToBinary(sampleType_ & PERF_SAMPLE_STACK_USER, p, data_.stack_size);
642     if (data_.stack_size > 0) {
643         std::copy(data_.stack_data, data_.stack_data + data_.stack_size, p);
644         p += data_.stack_size * sizeof(u8);
645         PushToBinary(true, p, data_.dyn_size);
646     }
647     PushToBinary(removeStack_, p, stackId_.value);
648     return true;
649 }
650 
DumpData(const int indent) const651 void PerfRecordSample::DumpData(const int indent) const
652 {
653     PRINT_INDENT(indent, "sample_type: 0x%" PRIx64 "\n", sampleType_);
654 
655     // dump record according sampleType
656     if (sampleType_ & (PERF_SAMPLE_ID | PERF_SAMPLE_IDENTIFIER)) {
657         PRINT_INDENT(indent, "ID %" PRIu64 "\n", static_cast<uint64_t>(data_.sample_id));
658     }
659     if (sampleType_ & PERF_SAMPLE_IP) {
660         PRINT_INDENT(indent, "ip %llx\n", data_.ip);
661     }
662     if (sampleType_ & PERF_SAMPLE_TID) {
663         PRINT_INDENT(indent, "pid %u, tid %u\n", data_.pid, data_.tid);
664     }
665     if (sampleType_ & PERF_SAMPLE_TIME) {
666         PRINT_INDENT(indent, "time %llu\n", data_.time);
667     }
668     // PERF_SAMPLE_ADDR is not enabled, delete output
669     if (sampleType_ & PERF_SAMPLE_ADDR) {
670         PRINT_INDENT(indent, "addr\n");
671     }
672     if (sampleType_ & PERF_SAMPLE_STREAM_ID) {
673         PRINT_INDENT(indent, "stream_id %" PRIu64 "\n", static_cast<uint64_t>(data_.stream_id));
674     }
675     if (sampleType_ & PERF_SAMPLE_CPU) {
676         PRINT_INDENT(indent, "cpu %u, res %u\n", data_.cpu, data_.res);
677     }
678     if (sampleType_ & PERF_SAMPLE_PERIOD) {
679         PRINT_INDENT(indent, "period %" PRIu64 "\n", static_cast<uint64_t>(data_.period));
680     }
681     if (stackId_.section.id > 0) {
682         PRINT_INDENT(indent, "stackid %" PRIu64 "\n", static_cast<uint64_t>(stackId_.section.id));
683     }
684     if (sampleType_ & PERF_SAMPLE_CALLCHAIN) {
685         bool userContext = false;
686         PRINT_INDENT(indent, "callchain nr=%lld\n", data_.nr);
687         for (uint64_t i = 0; i < data_.nr; ++i) {
688             std::string_view supplement = "";
689             if ((sampleType_ & PERF_SAMPLE_STACK_USER) == 0 || data_.ips[i] != PERF_CONTEXT_USER) {
690                 PRINT_INDENT(indent + 1, "0x%llx%s\n", data_.ips[i], supplement.data());
691                 continue;
692             }
693             // is PERF_SAMPLE_STACK_USER type and is PERF_CONTEXT_USER
694             if (!userContext) {
695                 userContext = true;
696                 supplement = " <unwind callstack>";
697             } else {
698                 supplement = " <expand callstack>";
699             }
700             PRINT_INDENT(indent + 1, "0x%llx%s\n", data_.ips[i], supplement.data());
701         }
702     }
703     if (sampleType_ & PERF_SAMPLE_RAW) {
704         PRINT_INDENT(indent, "raw size=%u\n", data_.raw_size);
705         const uint32_t *data = reinterpret_cast<const uint32_t *>(data_.raw_data);
706         size_t size = data_.raw_size / sizeof(uint32_t);
707         for (size_t i = 0; i < size; ++i) {
708             PRINT_INDENT(indent + 1, "0x%08x (%x)\n", data[i], data[i]);
709         }
710     }
711     if (sampleType_ & PERF_SAMPLE_BRANCH_STACK) {
712         PRINT_INDENT(indent, "branch_stack nr=%lld\n", data_.bnr);
713         for (uint64_t i = 0; i < data_.bnr; ++i) {
714             auto &item = data_.lbr[i];
715             PRINT_INDENT(indent + 1, "from 0x%llx, to 0x%llx, flags 0x%llx\n", item.from, item.to, item.flags);
716         }
717     }
718     if (sampleType_ & PERF_SAMPLE_REGS_USER) {
719         PRINT_INDENT(indent, "user regs: abi=%lld, reg_nr=%lld\n", data_.user_abi, data_.reg_nr);
720 #if defined(is_ohos) && is_ohos
721         if (IsRoot()) {
722             for (uint64_t i = 0; i < data_.reg_nr; ++i) {
723                 PRINT_INDENT(indent + 1, "0x%llx\n", data_.user_regs[i]);
724             }
725         }
726 #endif
727     }
728     if (sampleType_ & PERF_SAMPLE_SERVER_PID) {
729         PRINT_INDENT(indent, "server nr=%lld\n", data_.server_nr);
730         for (uint64_t i = 0; i < data_.server_nr; ++i) {
731             PRINT_INDENT(indent + 1, "pid: %llu\n", data_.server_pids[i]);
732         }
733     }
734     if (sampleType_ & PERF_SAMPLE_STACK_USER) {
735         PRINT_INDENT(indent, "user stack: size %llu dyn_size %lld\n", data_.stack_size,
736                      data_.dyn_size);
737     }
738 }
739 
DumpLog(const std::string & prefix) const740 void PerfRecordSample::DumpLog(const std::string &prefix) const
741 {
742     HLOGV("%s: SAMPLE: id= %llu size %d pid %u tid %u ips %llu regs %llu, stacks %llu time %llu",
743           prefix.c_str(), data_.sample_id, header_.size, data_.pid, data_.tid, data_.nr,
744           data_.reg_nr, data_.dyn_size, data_.time);
745 }
746 
RecoverCallStack()747 void PerfRecordSample::RecoverCallStack()
748 {
749     data_.ips = ips_.data();
750     data_.nr = ips_.size();
751     removeStack_ = true;
752 }
753 
ReplaceWithCallStack(const size_t originalSize)754 void PerfRecordSample::ReplaceWithCallStack(const size_t originalSize)
755 {
756     // first we check if we have some user unwind stack need to merge ?
757     if (callFrames_.size() != 0) {
758         // when we have some kernel ips , we cp it first
759         // new size is user call frames + kernel call frames
760         // + PERF_CONTEXT_USER(last + 1) + expand mark(also PERF_CONTEXT_USER)
761         const unsigned int perfContextSize = 2;
762         ips_.reserve(data_.nr + callFrames_.size() + perfContextSize);
763         if (data_.nr > 0) {
764             ips_.assign(data_.ips, data_.ips + data_.nr);
765         }
766         // add user context mark
767         ips_.emplace_back(PERF_CONTEXT_USER);
768         // we also need make a expand mark just for debug only
769         const size_t beginIpsSize = ips_.size();
770         bool ret = std::all_of(callFrames_.begin(), callFrames_.end(), [&](const DfxFrame &frame) {
771             ips_.emplace_back(frame.pc);
772             if (originalSize != 0 && (originalSize != callFrames_.size()) &&
773                 ips_.size() == (originalSize + beginIpsSize)) {
774                 // just for debug
775                 // so we can see which frame begin is expand call frames
776                 ips_.emplace_back(PERF_CONTEXT_USER);
777             }
778             return true;
779         });
780         if (ret) {
781             HLOGV("combed %zu", callFrames_.size());
782         } else {
783             HLOGV("failed to combed %zu", callFrames_.size());
784         }
785 
786         if (sampleType_ & PERF_SAMPLE_REGS_USER) {
787             header_.size -= data_.reg_nr * sizeof(u64);
788             data_.reg_nr = 0;
789             data_.user_abi = 0;
790         }
791 
792         if (sampleType_ & PERF_SAMPLE_STACK_USER) {
793             // 1. remove the user stack
794             header_.size -= data_.stack_size;
795             header_.size -= sizeof(data_.dyn_size);
796 
797             // 2. clean the size
798             data_.stack_size = 0;
799             data_.dyn_size = 0;
800         }
801 
802         if (sampleType_ & PERF_SAMPLE_CALLCHAIN) {
803             HLOGV("ips change from %llu -> %zu", data_.nr, ips_.size());
804 
805             // 3. remove the nr size
806             header_.size -= data_.nr * sizeof(u64);
807 
808             // 4. add new nr size
809             data_.nr = ips_.size();
810             header_.size += data_.nr * sizeof(u64);
811 
812             // 5. change ips potin to our ips array and hold it.
813             data_.ips = ips_.data();
814         }
815     }
816 }
817 
GetPid() const818 inline pid_t PerfRecordSample::GetPid() const
819 {
820     return data_.pid;
821 }
822 
GetTime() const823 uint64_t PerfRecordSample::GetTime() const
824 {
825     return data_.time;
826 }
827 
Clean()828 void PerfRecordSample::Clean()
829 {
830     ips_.clear();
831     callFrames_.clear();
832     serverPidMap_.clear();
833 }
834 
GetUstackServerPid()835 pid_t PerfRecordSample::GetUstackServerPid()
836 {
837     if (!data_.server_nr) {
838         return data_.pid;
839     }
840 
841     size_t currServer = 0;
842     // ipNr == 1...nr: server_pid of data_.ips[nr]
843     for (size_t i = 0; i < data_.nr; i++) {
844         // context change, use next server pid
845         if (data_.ips[i] >= PERF_CONTEXT_MAX) {
846             currServer++;
847         }
848     }
849     // ipNr == nr + 1: server_pid of ustack
850     if (currServer > 0) {
851         currServer++;
852     }
853     if (currServer >= data_.server_nr) {
854         HLOGE("ustack server pid nr %zu out of range", currServer);
855         return data_.pid;
856     }
857 
858     // return server pid
859     return data_.server_pids[currServer];
860 }
861 
GetServerPidof(unsigned int ipNr)862 pid_t PerfRecordSample::GetServerPidof(unsigned int ipNr)
863 {
864     if (!data_.server_nr) {
865         return data_.pid;
866     }
867 
868     // init serverPidMap_
869     if (!serverPidMap_.size()) {
870         size_t currServer = 0;
871         // ipNr == 0: server_pid of data_.ip
872         serverPidMap_.emplace_back(data_.server_pids[currServer]);
873         // ipNr == 1...nr: server_pid of data_.ips[nr]
874         for (size_t i = 1; i < data_.nr; i++) {
875             // context change, use next server pid
876             if (data_.ips[i] >= PERF_CONTEXT_MAX) {
877                 currServer++;
878             }
879             if (currServer >= data_.server_nr) {
880                 HLOGE("callchain server pid nr %zu out of range", currServer);
881                 break;
882             }
883             serverPidMap_.emplace_back(data_.server_pids[currServer]);
884         }
885     }
886 
887     // return server pid
888     if (ipNr >= serverPidMap_.size()) {
889         return data_.pid;
890     } else {
891         return serverPidMap_[ipNr];
892     }
893 }
894 
GetBinary(std::vector<uint8_t> & buf) const895 bool PerfRecordExit::GetBinary(std::vector<uint8_t> &buf) const
896 {
897     if (buf.size() < GetSize()) {
898         buf.resize(GetSize());
899     }
900 
901     GetHeaderBinary(buf);
902     uint8_t *p = buf.data() + GetHeaderSize();
903 
904     auto pDest = reinterpret_cast<PerfRecordExitData *>(p);
905     *pDest = data_;
906     return true;
907 }
908 
DumpData(const int indent) const909 void PerfRecordExit::DumpData(const int indent) const
910 {
911     PRINT_INDENT(indent, "pid %u, ppid %u, tid %u, ptid %u time 0x%llx\n", data_.pid, data_.ppid,
912                  data_.tid, data_.ptid, data_.time);
913 }
914 
GetBinary(std::vector<uint8_t> & buf) const915 bool PerfRecordThrottle::GetBinary(std::vector<uint8_t> &buf) const
916 {
917     if (buf.size() < GetSize()) {
918         buf.resize(GetSize());
919     }
920 
921     GetHeaderBinary(buf);
922     uint8_t *p = buf.data() + GetHeaderSize();
923 
924     auto pDest = reinterpret_cast<PerfRecordThrottleData *>(p);
925     *pDest = data_;
926     return true;
927 }
928 
DumpData(const int indent) const929 void PerfRecordThrottle::DumpData(const int indent) const
930 {
931     PRINT_INDENT(indent, "time 0x%llx, id %llx, stream_id %llx\n", data_.time, data_.id,
932                  data_.stream_id);
933 }
934 
GetBinary(std::vector<uint8_t> & buf) const935 bool PerfRecordUnthrottle::GetBinary(std::vector<uint8_t> &buf) const
936 {
937     if (buf.size() < GetSize()) {
938         buf.resize(GetSize());
939     }
940 
941     GetHeaderBinary(buf);
942     uint8_t *p = buf.data() + GetHeaderSize();
943 
944     auto pDest = reinterpret_cast<PerfRecordThrottleData *>(p);
945     *pDest = data_;
946     return true;
947 }
948 
DumpData(const int indent) const949 void PerfRecordUnthrottle::DumpData(const int indent) const
950 {
951     PRINT_INDENT(indent, "time 0x%llx, id %llx, stream_id %llx\n", data_.time, data_.id,
952                  data_.stream_id);
953 }
954 
GetBinary(std::vector<uint8_t> & buf) const955 bool PerfRecordFork::GetBinary(std::vector<uint8_t> &buf) const
956 {
957     if (buf.size() < GetSize()) {
958         buf.resize(GetSize());
959     }
960 
961     GetHeaderBinary(buf);
962     uint8_t *p = buf.data() + GetHeaderSize();
963 
964     auto pDest = reinterpret_cast<PerfRecordForkData *>(p);
965     *pDest = data_;
966     return true;
967 }
968 
DumpData(const int indent) const969 void PerfRecordFork::DumpData(const int indent) const
970 {
971     PRINT_INDENT(indent, "pid %u, ppid %u, tid %u, ptid %u\n", data_.pid, data_.ppid, data_.tid,
972                  data_.ptid);
973 }
974 
GetBinary(std::vector<uint8_t> & buf) const975 bool PerfRecordRead::GetBinary(std::vector<uint8_t> &buf) const
976 {
977     if (buf.size() < GetSize()) {
978         buf.resize(GetSize());
979     }
980 
981     GetHeaderBinary(buf);
982     uint8_t *p = buf.data() + GetHeaderSize();
983 
984     auto pDest = reinterpret_cast<PerfRecordReadData *>(p);
985     *pDest = data_;
986     return true;
987 }
988 
DumpData(const int indent) const989 void PerfRecordRead::DumpData(const int indent) const
990 {
991     PRINT_INDENT(indent, "pid %u, tid %u\n", data_.pid, data_.tid);
992     PRINT_INDENT(indent, "values: value %llx, timeEnabled %llx, timeRunning %llx, id %llx\n",
993                  data_.values.value, data_.values.timeEnabled, data_.values.timeRunning, data_.values.id);
994 }
995 
GetBinary(std::vector<uint8_t> & buf) const996 bool PerfRecordAux::GetBinary(std::vector<uint8_t> &buf) const
997 {
998     if (buf.size() < GetSize()) {
999         buf.resize(GetSize());
1000     }
1001 
1002     GetHeaderBinary(buf);
1003     uint8_t *p = buf.data() + GetHeaderSize();
1004 
1005     PushToBinary(true, p, data_.aux_offset);
1006     PushToBinary(true, p, data_.aux_size);
1007     PushToBinary(true, p, data_.flags);
1008     PushToBinary2(sampleType_ & PERF_SAMPLE_TID, p, data_.sample_id.pid, data_.sample_id.tid);
1009     PushToBinary(sampleType_ & PERF_SAMPLE_TIME, p, data_.sample_id.time);
1010     PushToBinary(sampleType_ & PERF_SAMPLE_ID, p, data_.sample_id.id);
1011     PushToBinary(sampleType_ & PERF_SAMPLE_STREAM_ID, p, data_.sample_id.stream_id);
1012 
1013     PushToBinary2(sampleType_ & PERF_SAMPLE_CPU, p, data_.sample_id.cpu, data_.sample_id.res);
1014     PushToBinary(sampleType_ & PERF_SAMPLE_IDENTIFIER, p, data_.sample_id.id2);
1015     return true;
1016 }
1017 
DumpData(const int indent) const1018 void PerfRecordAux::DumpData(const int indent) const
1019 {
1020     PRINT_INDENT(indent, "aux_offset 0x%llx aux_size 0x%llx flags 0x%llx pid %u tid %u time %llu",
1021                  data_.aux_offset, data_.aux_size, data_.flags, data_.sample_id.pid, data_.sample_id.tid,
1022                  data_.sample_id.time);
1023 }
1024 
GetBinary(std::vector<uint8_t> & buf) const1025 bool PerfRecordAuxTraceInfo::GetBinary(std::vector<uint8_t> &buf) const
1026 {
1027     if (buf.size() < GetSize()) {
1028         buf.resize(GetSize());
1029     }
1030 
1031     GetHeaderBinary(buf);
1032     uint8_t *p = buf.data() + GetHeaderSize();
1033     std::copy(reinterpret_cast<const uint8_t *>(&data_),
1034               reinterpret_cast<const uint8_t *>(&data_) + GetSize() - GetHeaderSize(), p);
1035     return true;
1036 }
1037 
DumpData(const int indent) const1038 void PerfRecordAuxTraceInfo::DumpData(const int indent) const
1039 {
1040     PRINT_INDENT(indent, "aux_trace_event");
1041 }
1042 
GetBinary(std::vector<uint8_t> & buf) const1043 bool PerfRecordTimeConv::GetBinary(std::vector<uint8_t> &buf) const
1044 {
1045     if (buf.size() < GetSize()) {
1046         buf.resize(GetSize());
1047     }
1048 
1049     GetHeaderBinary(buf);
1050     uint8_t *p = buf.data() + GetHeaderSize();
1051     std::copy(reinterpret_cast<const uint8_t *>(&data_),
1052               reinterpret_cast<const uint8_t *>(&data_) + GetSize() - GetHeaderSize(), p);
1053     return true;
1054 }
1055 
DumpData(const int indent) const1056 void PerfRecordTimeConv::DumpData(const int indent) const
1057 {
1058     PRINT_INDENT(indent, "aux_time_event");
1059 }
1060 
GetBinary(std::vector<uint8_t> & buf) const1061 bool PerfRecordCpuMap::GetBinary(std::vector<uint8_t> &buf) const
1062 {
1063     if (buf.size() < GetSize()) {
1064         buf.resize(GetSize());
1065     }
1066 
1067     GetHeaderBinary(buf);
1068     uint8_t *p = buf.data() + GetHeaderSize();
1069     std::copy(reinterpret_cast<const uint8_t *>(&data_),
1070               reinterpret_cast<const uint8_t *>(&data_) + GetSize() - GetHeaderSize(), p);
1071     return true;
1072 }
1073 
DumpData(const int indent) const1074 void PerfRecordCpuMap::DumpData(const int indent) const
1075 {
1076     PRINT_INDENT(indent, "cpu_map_event");
1077 }
1078 
GetBinary(std::vector<uint8_t> & buf) const1079 bool PerfRecordItraceStart::GetBinary(std::vector<uint8_t> &buf) const
1080 {
1081     if (buf.size() < GetSize()) {
1082         buf.resize(GetSize());
1083     }
1084 
1085     GetHeaderBinary(buf);
1086     uint8_t *p = buf.data() + GetHeaderSize();
1087 
1088     auto pDest = reinterpret_cast<PerfRecordItraceStartData *>(p);
1089     *pDest = data_;
1090     return true;
1091 }
1092 
DumpData(const int indent) const1093 void PerfRecordItraceStart::DumpData(const int indent) const
1094 {
1095     PRINT_INDENT(indent, "pid %u, tid %u\n", data_.pid, data_.tid);
1096 }
1097 
GetBinary(std::vector<uint8_t> & buf) const1098 bool PerfRecordLostSamples::GetBinary(std::vector<uint8_t> &buf) const
1099 {
1100     if (buf.size() < GetSize()) {
1101         buf.resize(GetSize());
1102     }
1103 
1104     GetHeaderBinary(buf);
1105     uint8_t *p = buf.data() + GetHeaderSize();
1106 
1107     auto pDest = reinterpret_cast<PerfRecordLostSamplesData *>(p);
1108     *pDest = data_;
1109     return true;
1110 }
1111 
DumpData(const int indent) const1112 void PerfRecordLostSamples::DumpData(const int indent) const
1113 {
1114     PRINT_INDENT(indent, "lost %llu\n", data_.lost);
1115 }
1116 
GetBinary(std::vector<uint8_t> & buf) const1117 bool PerfRecordSwitch::GetBinary(std::vector<uint8_t> &buf) const
1118 {
1119     if (buf.size() < GetSize()) {
1120         buf.resize(GetSize());
1121     }
1122 
1123     GetHeaderBinary(buf);
1124     uint8_t *p = buf.data() + GetHeaderSize();
1125 
1126     auto pDest = reinterpret_cast<PerfRecordSwitchData *>(p);
1127     *pDest = data_;
1128     return true;
1129 }
1130 
GetBinary(std::vector<uint8_t> & buf) const1131 bool PerfRecordSwitchCpuWide::GetBinary(std::vector<uint8_t> &buf) const
1132 {
1133     if (buf.size() < GetSize()) {
1134         buf.resize(GetSize());
1135     }
1136 
1137     GetHeaderBinary(buf);
1138     uint8_t *p = buf.data() + GetHeaderSize();
1139 
1140     auto pDest = reinterpret_cast<PerfRecordSwitchCpuWideData *>(p);
1141     *pDest = data_;
1142     return true;
1143 }
1144 
DumpData(const int indent) const1145 void PerfRecordSwitchCpuWide::DumpData(const int indent) const
1146 {
1147     PRINT_INDENT(indent, "next_prev_pid %u, next_prev_tid %u\n", data_.next_prev_pid,
1148                  data_.next_prev_tid);
1149 }
1150 
GetPerfEventRecord(PerfRecordType type,uint8_t * data,const perf_event_attr & attr)1151 PerfEventRecord& PerfEventRecordFactory::GetPerfEventRecord(PerfRecordType type, uint8_t* data,
1152                                                             const perf_event_attr &attr)
1153 {
1154     HLOG_ASSERT(data != nullptr);
1155     PerfEventRecord* record = nullptr;
1156     auto it = recordMap_.find(type);
1157     if (it == recordMap_.end()) {
1158         record = CreatePerfEventRecord(type);
1159         if (record == nullptr) {
1160             record = new PerfRecordNull();
1161         }
1162         recordMap_.emplace(type, record);
1163     } else {
1164         record = it->second;
1165     }
1166     record->Init(data, attr);
1167     return *record;
1168 }
1169 } // namespace HiPerf
1170 } // namespace Developtools
1171 } // namespace OHOS
1172