• 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(bool condition,uint8_t * & p,const T & v)81 inline void PushToBinary(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(bool condition,uint8_t * & p,const T1 & v1,const T2 & v2)90 inline void PushToBinary2(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(bool condition,uint8_t * & p,T & v,u64 & size)101 inline void PopFromBinary(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(bool condition,uint8_t * & p,T1 & v1,T2 & v2,u64 & size)112 inline void PopFromBinary2(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(int indent,std::string outputFilename,FILE * outputDump) const140 void PerfEventRecord::Dump(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(perf_event_type type,bool inKernel)164 void PerfEventRecord::Init(perf_event_type type, 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(perf_event_hiperf_ext_type type)171 void PerfEventRecord::Init(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(u64 size,u64 offset,u64 reference,u32 idx,u32 tid,u32 cpu,u32 pid)206 PerfRecordAuxtrace::PerfRecordAuxtrace(u64 size, u64 offset, u64 reference, u32 idx, u32 tid, u32 cpu, u32 pid)
207 {
208     PerfEventRecord::Init(PERF_RECORD_AUXTRACE);
209     data_.size = size;
210     data_.offset = offset;
211     data_.reference = reference;
212     data_.idx = idx;
213     data_.tid = tid;
214     data_.cpu = cpu;
215     data_.reserved__ = pid;
216 
217     header_.size = sizeof(header_) + sizeof(data_);
218 }
219 
GetBinary1(std::vector<uint8_t> & buf) const220 bool PerfRecordAuxtrace::GetBinary1(std::vector<uint8_t> &buf) const
221 {
222     if (buf.size() < header_.size) {
223         buf.resize(header_.size);
224     }
225 
226     GetHeaderBinary(buf);
227     uint8_t *p = buf.data() + GetHeaderSize();
228 
229     size_t copySize = header_.size - GetHeaderSize();
230     if (memcpy_s(p, buf.size() - GetHeaderSize(), reinterpret_cast<const uint8_t *>(&data_), copySize) != 0) {
231         HLOGE("memcpy_s return failed in GetBinary1");
232         return false;
233     }
234     return true;
235 }
236 
GetBinary(std::vector<uint8_t> & buf) const237 bool PerfRecordAuxtrace::GetBinary(std::vector<uint8_t> &buf) const
238 {
239     if (buf.size() < GetSize()) {
240         buf.resize(GetSize());
241     }
242 
243     GetHeaderBinary(buf);
244     uint8_t *p = buf.data() + GetHeaderSize();
245 
246     size_t copySize = header_.size - GetHeaderSize();
247     if (memcpy_s(p, buf.size() - GetHeaderSize(), reinterpret_cast<const uint8_t *>(&data_), copySize) != 0) {
248         HLOGE("memcpy_s return failed in GetBinary with data_");
249         return false;
250     }
251     p += header_.size - GetHeaderSize();
252     if (memcpy_s(p, buf.size() - header_.size, static_cast<uint8_t *>(rawData_), data_.size) != 0) {
253         HLOGE("memcpy_s return failed in GetBinary with rawData_");
254         return false;
255     }
256     return true;
257 }
258 
DumpData(int indent) const259 void PerfRecordAuxtrace::DumpData(int indent) const
260 {
261     PRINT_INDENT(indent, "size 0x%llx, offset 0x%llx, reference 0x%llx, idx %u, tid %u, cpu %u, pid %u\n",
262                  data_.size, data_.offset, data_.reference, data_.idx, data_.tid, data_.cpu, data_.reserved__);
263 #if defined(is_ohos) && is_ohos
264     if (!SpeDumpRawData(rawData_, data_.size, indent, g_outputDump)) {
265         HLOGE("SpeDumpRawData failed");
266     }
267 #endif
268 }
269 
DumpLog(const std::string & prefix) const270 void PerfRecordAuxtrace::DumpLog(const std::string &prefix) const
271 {
272     HLOGV("size %llu, offset 0x%llx, reference 0x%llx, idx %u, tid %u, cpu %u\n",
273           data_.size, data_.offset, data_.reference, data_.idx, data_.tid, data_.cpu);
274 }
275 
GetSize() const276 size_t PerfRecordAuxtrace::GetSize() const
277 {
278     return header_.size + data_.size;
279 }
280 
Init(uint8_t * data,const perf_event_attr &)281 void PerfRecordMmap::Init(uint8_t* data, const perf_event_attr&)
282 {
283     PerfEventRecordTemplate::Init(data);
284     data_.filename[KILO - 1] = '\0';
285 }
286 
PerfRecordMmap(bool inKernel,u32 pid,u32 tid,u64 addr,u64 len,u64 pgoff,const std::string & filename)287 PerfRecordMmap::PerfRecordMmap(bool inKernel, u32 pid, u32 tid, u64 addr, u64 len, u64 pgoff,
288                                const std::string &filename)
289 {
290     PerfEventRecord::Init(PERF_RECORD_MMAP, inKernel);
291 
292     data_.pid = pid;
293     data_.tid = tid;
294     data_.addr = addr;
295     data_.len = len;
296     data_.pgoff = pgoff;
297     if (strncpy_s(data_.filename, KILO, filename.c_str(), filename.size()) != 0) {
298         HLOGE("strncpy_s failed");
299     }
300 
301     header_.size = sizeof(header_) + sizeof(data_) - KILO + filename.size() + 1;
302 }
303 
GetBinary(std::vector<uint8_t> & buf) const304 bool PerfRecordMmap::GetBinary(std::vector<uint8_t> &buf) const
305 {
306     if (buf.size() < GetSize()) {
307         buf.resize(GetSize());
308     }
309 
310     GetHeaderBinary(buf);
311     uint8_t *p = buf.data() + GetHeaderSize();
312 
313     // data_.filename[] is variable-length
314     std::copy(reinterpret_cast<const uint8_t *>(&data_),
315               reinterpret_cast<const uint8_t *>(&data_) + GetSize() - GetHeaderSize(), p);
316     return true;
317 }
318 
DumpData(int indent) const319 void PerfRecordMmap::DumpData(int indent) const
320 {
321 #if defined(is_ohos) && is_ohos
322     if (IsRoot()) {
323         PRINT_INDENT(indent, "pid %u, tid %u, addr 0x%llx, len 0x%llx\n", data_.pid, data_.tid,
324                      data_.addr, data_.len);
325         PRINT_INDENT(indent, "pgoff 0x%llx, filename %s\n", data_.pgoff, data_.filename);
326     }
327 #endif
328 }
329 
DumpLog(const std::string & prefix) const330 void PerfRecordMmap::DumpLog(const std::string &prefix) const
331 {
332     HLOGV("%s:  MMAP: size %d pid %u tid %u dso '%s' (0x%llx-0x%llx)@0x%llx", prefix.c_str(),
333           header_.size, data_.pid, data_.tid, data_.filename, data_.addr, data_.addr + data_.len, data_.pgoff);
334 }
335 
Init(uint8_t * data,const perf_event_attr &)336 void PerfRecordMmap2::Init(uint8_t* data, const perf_event_attr&)
337 {
338     PerfEventRecordTemplate::Init(data);
339     discard_ = false;
340 }
341 
PerfRecordMmap2(bool inKernel,u32 pid,u32 tid,u64 addr,u64 len,u64 pgoff,u32 maj,u32 min,u64 ino,u32 prot,u32 flags,const std::string & filename)342 PerfRecordMmap2::PerfRecordMmap2(bool inKernel, u32 pid, u32 tid, u64 addr, u64 len, u64 pgoff,
343                                  u32 maj, u32 min, u64 ino, u32 prot, u32 flags,
344                                  const std::string &filename)
345 {
346     PerfEventRecord::Init(PERF_RECORD_MMAP2, inKernel);
347     data_.pid = pid;
348     data_.tid = tid;
349     data_.addr = addr;
350     data_.len = len;
351     data_.pgoff = pgoff;
352     data_.maj = maj;
353     data_.min = min;
354     data_.ino = ino;
355     data_.ino_generation = 0;
356     data_.prot = prot;
357     data_.flags = flags;
358     if (strncpy_s(data_.filename, KILO, filename.c_str(), filename.size()) != 0) {
359         HLOGE("strncpy_s failed");
360     }
361 
362     header_.size = sizeof(header_) + sizeof(data_) - KILO + filename.size() + 1;
363 }
364 
PerfRecordMmap2(bool inKernel,u32 pid,u32 tid,std::shared_ptr<DfxMap> item)365 PerfRecordMmap2::PerfRecordMmap2(bool inKernel, u32 pid, u32 tid, std::shared_ptr<DfxMap> item)
366 {
367     PerfEventRecord::Init(PERF_RECORD_MMAP2, inKernel);
368     data_.pid = pid;
369     data_.tid = tid;
370     if (item != nullptr) {
371         data_.addr = item->begin;
372         data_.len = item->end - item->begin;
373         data_.pgoff = item->offset;
374         data_.maj = item->major;
375         data_.min = item->minor;
376         data_.ino = item->inode;
377         data_.ino_generation = 0;
378         // r--p 00000000 103:3e 12307                         /data/storage/el1/bundle/entry.hap
379         // why prot get from this is 7. rwxp
380         DfxMap::PermsToProts(item->perms, data_.prot, data_.flags);
381         if (strncpy_s(data_.filename, KILO, item->name.c_str(), item->name.size()) != 0) {
382             HLOGE("strncpy_s failed");
383         }
384 
385         header_.size = sizeof(header_) + sizeof(data_) - KILO + item->name.size() + 1;
386     } else {
387         data_.addr = 0;
388         data_.len = 0;
389         data_.pgoff = 0;
390         data_.maj = 0;
391         data_.min = 0;
392         data_.ino = 0;
393         data_.ino_generation = 0;
394         if (memset_s(data_.filename, KILO, 0, KILO) != EOK) {
395             HLOGE("memset_s failed");
396         }
397     }
398 }
399 
GetBinary(std::vector<uint8_t> & buf) const400 bool PerfRecordMmap2::GetBinary(std::vector<uint8_t> &buf) const
401 {
402     if (buf.size() < GetSize()) {
403         buf.resize(GetSize());
404     }
405 
406     GetHeaderBinary(buf);
407     uint8_t *p = buf.data() + GetHeaderSize();
408 
409     // data_.filename[] is variable-length
410     std::copy(reinterpret_cast<const uint8_t *>(&data_),
411               reinterpret_cast<const uint8_t *>(&data_) + GetSize() - GetHeaderSize(), p);
412     return true;
413 }
414 
DumpData(int indent) const415 void PerfRecordMmap2::DumpData(int indent) const
416 {
417 #if defined(is_ohos) && is_ohos
418     if (IsRoot()) {
419         PRINT_INDENT(indent, "pid %u, tid %u, addr 0x%llx, len 0x%llx\n", data_.pid, data_.tid,
420                      data_.addr, data_.len);
421         PRINT_INDENT(indent, "pgoff 0x%llx, maj %u, min %u, ino %llu, ino_generation %llu\n",
422                      data_.pgoff, data_.maj, data_.min, data_.ino, data_.ino_generation);
423         PRINT_INDENT(indent, "prot %u, flags %u, filename %s\n", data_.prot, data_.flags,
424                      data_.filename);
425     }
426 #endif
427 }
428 
DumpLog(const std::string & prefix) const429 void PerfRecordMmap2::DumpLog(const std::string &prefix) const
430 {
431     HLOGV("%s:  MMAP2: size %d pid %u tid %u dso '%s' (0x%llx-0x%llx)@0x%llx", prefix.c_str(),
432           header_.size, data_.pid, data_.tid, data_.filename, data_.addr, data_.addr + data_.len,
433           data_.pgoff);
434 }
435 
GetBinary(std::vector<uint8_t> & buf) const436 bool PerfRecordLost::GetBinary(std::vector<uint8_t> &buf) const
437 {
438     if (buf.size() < GetSize()) {
439         buf.resize(GetSize());
440     }
441 
442     GetHeaderBinary(buf);
443     uint8_t *p = buf.data() + GetHeaderSize();
444 
445     auto pDest = reinterpret_cast<PerfRecordLostData *>(p);
446     *pDest = data_;
447 
448     return true;
449 }
450 
DumpData(int indent) const451 void PerfRecordLost::DumpData(int indent) const
452 {
453     PRINT_INDENT(indent, "id %llu, lost %llu\n", data_.id, data_.lost);
454 }
455 
Init(uint8_t * data,const perf_event_attr &)456 void PerfRecordComm::Init(uint8_t* data, const perf_event_attr&)
457 {
458     PerfEventRecordTemplate::Init(data);
459     data_.comm[KILO - 1] = '\0';
460 }
461 
PerfRecordComm(bool inKernel,u32 pid,u32 tid,const std::string & comm)462 PerfRecordComm::PerfRecordComm(bool inKernel, u32 pid, u32 tid, const std::string &comm)
463 {
464     PerfEventRecord::Init(PERF_RECORD_COMM, inKernel);
465     data_.pid = pid;
466     data_.tid = tid;
467     if (strncpy_s(data_.comm, KILO, comm.c_str(), comm.size()) != 0) {
468         HLOGE("strncpy_s failed !!!");
469     }
470 
471     header_.size = sizeof(header_) + sizeof(data_) - KILO + comm.size() + 1;
472 }
473 
GetBinary(std::vector<uint8_t> & buf) const474 bool PerfRecordComm::GetBinary(std::vector<uint8_t> &buf) const
475 {
476     if (buf.size() < GetSize()) {
477         buf.resize(GetSize());
478     }
479 
480     GetHeaderBinary(buf);
481     uint8_t *p = buf.data() + GetHeaderSize();
482 
483     // data_.comm[] is variable-length
484     std::copy(reinterpret_cast<const uint8_t *>(&data_),
485               reinterpret_cast<const uint8_t *>(&data_) + GetSize() - GetHeaderSize(), p);
486 
487     return true;
488 }
489 
DumpData(int indent) const490 void PerfRecordComm::DumpData(int indent) const
491 {
492     PRINT_INDENT(indent, "pid %u, tid %u, comm %s\n", data_.pid, data_.tid, data_.comm);
493 }
494 
DumpLog(const std::string & prefix) const495 void PerfRecordComm::DumpLog(const std::string &prefix) const
496 {
497     HLOGV("pid %u, tid %u, comm %s\n", data_.pid, data_.tid, data_.comm);
498 }
499 
PerfRecordSample(const PerfRecordSample & sample)500 PerfRecordSample::PerfRecordSample(const PerfRecordSample& sample)
501 {
502     header_ = sample.header_;
503     data_ = sample.data_;
504 
505     sampleType_ = sample.sampleType_;
506     skipKernel_ = sample.skipKernel_;
507     skipPid_ = sample.skipPid_;
508 
509     ips_ = sample.ips_;
510     callFrames_ = sample.callFrames_;
511     serverPidMap_ = sample.serverPidMap_;
512 
513     stackId_ = sample.stackId_;
514     removeStack_ = sample.removeStack_;
515 }
516 
Init(uint8_t * p,const perf_event_attr & attr)517 void PerfRecordSample::Init(uint8_t *p, const perf_event_attr &attr)
518 {
519     PerfEventRecord::InitHeader(p);
520 
521     HLOG_ASSERT(p != nullptr);
522     // clear the vector data
523     Clean();
524     sampleType_ = attr.sample_type;
525     skipKernel_ = 0;
526     skipPid_ = 0;
527     stackId_ = {0};
528     removeStack_ = false;
529     data_ = {};
530     uint8_t *start = p;
531     u64 dataSize = static_cast<u64>(RECORD_SIZE_LIMIT);
532     SetPointerOffset(p, sizeof(header_), dataSize);
533 
534     // parse record according SAMPLE_TYPE
535     PopFromBinary(sampleType_ & PERF_SAMPLE_IDENTIFIER, p, data_.sample_id, dataSize);
536     PopFromBinary(sampleType_ & PERF_SAMPLE_IP, p, data_.ip, dataSize);
537     PopFromBinary2(sampleType_ & PERF_SAMPLE_TID, p, data_.pid, data_.tid, dataSize);
538     PopFromBinary(sampleType_ & PERF_SAMPLE_TIME, p, data_.time, dataSize);
539     PopFromBinary(sampleType_ & PERF_SAMPLE_ADDR, p, data_.addr, dataSize);
540     PopFromBinary(sampleType_ & PERF_SAMPLE_ID, p, data_.id, dataSize);
541     PopFromBinary(sampleType_ & PERF_SAMPLE_STREAM_ID, p, data_.stream_id, dataSize);
542     PopFromBinary2(sampleType_ & PERF_SAMPLE_CPU, p, data_.cpu, data_.res, dataSize);
543     PopFromBinary(sampleType_ & PERF_SAMPLE_PERIOD, p, data_.period, dataSize);
544     PopFromBinary(sampleType_ & PERF_SAMPLE_CALLCHAIN, p, data_.nr, dataSize);
545     if (data_.nr > 0) {
546         // the pointer is from input(p), require caller keep input(p) with *this together
547         // think it in next time
548         data_.ips = reinterpret_cast<u64 *>(p);
549         SetPointerOffset(p, data_.nr * sizeof(u64), dataSize);
550     }
551     PopFromBinary(sampleType_ & PERF_SAMPLE_RAW, p, data_.raw_size, dataSize);
552     if (data_.raw_size > 0) {
553         data_.raw_data = p;
554         SetPointerOffset(p, data_.raw_size * sizeof(u8), dataSize);
555     }
556     PopFromBinary(sampleType_ & PERF_SAMPLE_BRANCH_STACK, p, data_.bnr, dataSize);
557     if (data_.bnr > 0) {
558         data_.lbr = reinterpret_cast<PerfBranchEntry *>(p);
559         SetPointerOffset(p, data_.bnr * sizeof(PerfBranchEntry), dataSize);
560     }
561     PopFromBinary(sampleType_ & PERF_SAMPLE_REGS_USER, p, data_.user_abi, dataSize);
562     if (data_.user_abi > 0) {
563         data_.reg_mask = attr.sample_regs_user;
564         data_.reg_nr = __builtin_popcountll(data_.reg_mask);
565         data_.user_regs = reinterpret_cast<u64 *>(p);
566         SetPointerOffset(p, data_.reg_nr * sizeof(u64), dataSize);
567     }
568     PopFromBinary(sampleType_ & PERF_SAMPLE_SERVER_PID, p, data_.server_nr, dataSize);
569     if (data_.server_nr > 0) {
570         data_.server_pids = reinterpret_cast<u64 *>(p);
571         SetPointerOffset(p, data_.server_nr * sizeof(u64), dataSize);
572     }
573     PopFromBinary(sampleType_ & PERF_SAMPLE_STACK_USER, p, data_.stack_size, dataSize);
574     if (data_.stack_size > 0) {
575         data_.stack_data = p;
576         SetPointerOffset(p, data_.stack_size, dataSize);
577         PopFromBinary(true, p, data_.dyn_size, dataSize);
578     }
579     uint32_t remain = header_.size - (p - start);
580     if (data_.nr == 0 && dumpRemoveStack_ && remain == sizeof(stackId_)) {
581         PopFromBinary(true, p, stackId_.value, dataSize);
582     }
583 }
584 
SetDumpRemoveStack(bool dumpRemoveStack)585 void PerfRecordSample::SetDumpRemoveStack(bool dumpRemoveStack)
586 {
587     dumpRemoveStack_ = dumpRemoveStack;
588 }
589 
IsDumpRemoveStack()590 bool PerfRecordSample::IsDumpRemoveStack()
591 {
592     return dumpRemoveStack_;
593 }
594 
GetBinary(std::vector<uint8_t> & buf) const595 bool PerfRecordSample::GetBinary(std::vector<uint8_t> &buf) const
596 {
597     if (buf.size() < GetSize()) {
598         buf.resize(GetSize());
599     }
600 
601     GetHeaderBinary(buf);
602     uint8_t *p = buf.data() + GetHeaderSize();
603 
604     PushToBinary(sampleType_ & PERF_SAMPLE_IDENTIFIER, p, data_.sample_id);
605     PushToBinary(sampleType_ & PERF_SAMPLE_IP, p, data_.ip);
606     PushToBinary2(sampleType_ & PERF_SAMPLE_TID, p, data_.pid, data_.tid);
607     PushToBinary(sampleType_ & PERF_SAMPLE_TIME, p, data_.time);
608     PushToBinary(sampleType_ & PERF_SAMPLE_ADDR, p, data_.addr);
609     PushToBinary(sampleType_ & PERF_SAMPLE_ID, p, data_.id);
610     PushToBinary(sampleType_ & PERF_SAMPLE_STREAM_ID, p, data_.stream_id);
611     PushToBinary2(sampleType_ & PERF_SAMPLE_CPU, p, data_.cpu, data_.res);
612     PushToBinary(sampleType_ & PERF_SAMPLE_PERIOD, p, data_.period);
613     PushToBinary(sampleType_ & PERF_SAMPLE_CALLCHAIN, p, data_.nr);
614     if (data_.nr > 0 && !removeStack_) {
615         std::copy(data_.ips + skipKernel_, data_.ips + data_.nr + skipKernel_,
616                   reinterpret_cast<u64 *>(p));
617         p += data_.nr * sizeof(u64);
618     }
619     PushToBinary(sampleType_ & PERF_SAMPLE_RAW, p, data_.raw_size);
620     if (data_.raw_size > 0) {
621         std::copy(data_.raw_data, data_.raw_data + data_.raw_size, p);
622         p += data_.raw_size * sizeof(u8);
623     }
624     PushToBinary(sampleType_ & PERF_SAMPLE_BRANCH_STACK, p, data_.bnr);
625     if (data_.bnr > 0) {
626         std::copy(data_.lbr, data_.lbr + data_.bnr, reinterpret_cast<PerfBranchEntry *>(p));
627         p += data_.bnr * sizeof(PerfBranchEntry);
628     }
629     PushToBinary(sampleType_ & PERF_SAMPLE_REGS_USER, p, data_.user_abi);
630     if (data_.user_abi > 0 && data_.reg_nr > 0) {
631         std::copy(data_.user_regs, data_.user_regs + data_.reg_nr, reinterpret_cast<u64 *>(p));
632         p += data_.reg_nr * sizeof(u64);
633     }
634     PushToBinary(sampleType_ & PERF_SAMPLE_SERVER_PID, p, data_.server_nr);
635     if (data_.server_nr > 0) {
636         std::copy(data_.server_pids + skipPid_, data_.server_pids + data_.server_nr + skipPid_,
637                   reinterpret_cast<u64 *>(p));
638         p += data_.server_nr * sizeof(u64);
639     }
640     PushToBinary(sampleType_ & PERF_SAMPLE_STACK_USER, p, data_.stack_size);
641     if (data_.stack_size > 0) {
642         std::copy(data_.stack_data, data_.stack_data + data_.stack_size, p);
643         p += data_.stack_size * sizeof(u8);
644         PushToBinary(true, p, data_.dyn_size);
645     }
646     PushToBinary(removeStack_, p, stackId_.value);
647     return true;
648 }
649 
DumpData(int indent) const650 void PerfRecordSample::DumpData(int indent) const
651 {
652     PRINT_INDENT(indent, "sample_type: 0x%" PRIx64 "\n", sampleType_);
653 
654     // dump record according sampleType
655     if (sampleType_ & (PERF_SAMPLE_ID | PERF_SAMPLE_IDENTIFIER)) {
656         PRINT_INDENT(indent, "ID %" PRIu64 "\n", static_cast<uint64_t>(data_.sample_id));
657     }
658     if (sampleType_ & PERF_SAMPLE_IP) {
659         PRINT_INDENT(indent, "ip %llx\n", data_.ip);
660     }
661     if (sampleType_ & PERF_SAMPLE_TID) {
662         PRINT_INDENT(indent, "pid %u, tid %u\n", data_.pid, data_.tid);
663     }
664     if (sampleType_ & PERF_SAMPLE_TIME) {
665         PRINT_INDENT(indent, "time %llu\n", data_.time);
666     }
667     if (sampleType_ & PERF_SAMPLE_ADDR) {
668         PRINT_INDENT(indent, "addr %p\n", reinterpret_cast<void *>(data_.addr));
669     }
670     if (sampleType_ & PERF_SAMPLE_STREAM_ID) {
671         PRINT_INDENT(indent, "stream_id %" PRIu64 "\n", static_cast<uint64_t>(data_.stream_id));
672     }
673     if (sampleType_ & PERF_SAMPLE_CPU) {
674         PRINT_INDENT(indent, "cpu %u, res %u\n", data_.cpu, data_.res);
675     }
676     if (sampleType_ & PERF_SAMPLE_PERIOD) {
677         PRINT_INDENT(indent, "period %" PRIu64 "\n", static_cast<uint64_t>(data_.period));
678     }
679     if (stackId_.section.id > 0) {
680         PRINT_INDENT(indent, "stackid %" PRIu64 "\n", static_cast<uint64_t>(stackId_.section.id));
681     }
682     if (sampleType_ & PERF_SAMPLE_CALLCHAIN) {
683         bool userContext = false;
684         PRINT_INDENT(indent, "callchain nr=%lld\n", data_.nr);
685         for (uint64_t i = 0; i < data_.nr; ++i) {
686             std::string_view supplement = "";
687             if ((sampleType_ & PERF_SAMPLE_STACK_USER) == 0 || data_.ips[i] != PERF_CONTEXT_USER) {
688                 PRINT_INDENT(indent + 1, "0x%llx%s\n", data_.ips[i], supplement.data());
689                 continue;
690             }
691             // is PERF_SAMPLE_STACK_USER type and is PERF_CONTEXT_USER
692             if (!userContext) {
693                 userContext = true;
694                 supplement = " <unwind callstack>";
695             } else {
696                 supplement = " <expand callstack>";
697             }
698             PRINT_INDENT(indent + 1, "0x%llx%s\n", data_.ips[i], supplement.data());
699         }
700     }
701     if (sampleType_ & PERF_SAMPLE_RAW) {
702         PRINT_INDENT(indent, "raw size=%u\n", data_.raw_size);
703         const uint32_t *data = reinterpret_cast<const uint32_t *>(data_.raw_data);
704         size_t size = data_.raw_size / sizeof(uint32_t);
705         for (size_t i = 0; i < size; ++i) {
706             PRINT_INDENT(indent + 1, "0x%08x (%x)\n", data[i], data[i]);
707         }
708     }
709     if (sampleType_ & PERF_SAMPLE_BRANCH_STACK) {
710         PRINT_INDENT(indent, "branch_stack nr=%lld\n", data_.bnr);
711         for (uint64_t i = 0; i < data_.bnr; ++i) {
712             auto &item = data_.lbr[i];
713             PRINT_INDENT(indent + 1, "from 0x%llx, to 0x%llx, flags 0x%llx\n", item.from, item.to, item.flags);
714         }
715     }
716     if (sampleType_ & PERF_SAMPLE_REGS_USER) {
717         PRINT_INDENT(indent, "user regs: abi=%lld, reg_nr=%lld\n", data_.user_abi, data_.reg_nr);
718 #if defined(is_ohos) && is_ohos
719         if (IsRoot()) {
720             for (uint64_t i = 0; i < data_.reg_nr; ++i) {
721                 PRINT_INDENT(indent + 1, "0x%llx\n", data_.user_regs[i]);
722             }
723         }
724 #endif
725     }
726     if (sampleType_ & PERF_SAMPLE_SERVER_PID) {
727         PRINT_INDENT(indent, "server nr=%lld\n", data_.server_nr);
728         for (uint64_t i = 0; i < data_.server_nr; ++i) {
729             PRINT_INDENT(indent + 1, "pid: %llu\n", data_.server_pids[i]);
730         }
731     }
732     if (sampleType_ & PERF_SAMPLE_STACK_USER) {
733         PRINT_INDENT(indent, "user stack: size %llu dyn_size %lld\n", data_.stack_size,
734                      data_.dyn_size);
735     }
736 }
737 
DumpLog(const std::string & prefix) const738 void PerfRecordSample::DumpLog(const std::string &prefix) const
739 {
740     HLOGV("%s: SAMPLE: id= %llu size %d pid %u tid %u ips %llu regs %llu, stacks %llu time %llu",
741           prefix.c_str(), data_.sample_id, header_.size, data_.pid, data_.tid, data_.nr,
742           data_.reg_nr, data_.dyn_size, data_.time);
743 }
744 
RecoverCallStack()745 void PerfRecordSample::RecoverCallStack()
746 {
747     data_.ips = ips_.data();
748     data_.nr = ips_.size();
749     removeStack_ = true;
750 }
751 
ReplaceWithCallStack(size_t originalSize)752 void PerfRecordSample::ReplaceWithCallStack(size_t originalSize)
753 {
754     // first we check if we have some user unwind stack need to merge ?
755     if (callFrames_.size() != 0) {
756         // when we have some kernel ips , we cp it first
757         // new size is user call frames + kernel call frames
758         // + PERF_CONTEXT_USER(last + 1) + expand mark(also PERF_CONTEXT_USER)
759         const unsigned int perfContextSize = 2;
760         ips_.reserve(data_.nr + callFrames_.size() + perfContextSize);
761         if (data_.nr > 0) {
762             ips_.assign(data_.ips, data_.ips + data_.nr);
763         }
764         // add user context mark
765         ips_.emplace_back(PERF_CONTEXT_USER);
766         // we also need make a expand mark just for debug only
767         const size_t beginIpsSize = ips_.size();
768         bool ret = std::all_of(callFrames_.begin(), callFrames_.end(), [&](const DfxFrame &frame) {
769             ips_.emplace_back(frame.pc);
770             if (originalSize != 0 && (originalSize != callFrames_.size()) &&
771                 ips_.size() == (originalSize + beginIpsSize)) {
772                 // just for debug
773                 // so we can see which frame begin is expand call frames
774                 ips_.emplace_back(PERF_CONTEXT_USER);
775             }
776             return true;
777         });
778         if (ret) {
779             HLOGV("combed %zu", callFrames_.size());
780         } else {
781             HLOGV("failed to combed %zu", callFrames_.size());
782         }
783 
784         if (sampleType_ & PERF_SAMPLE_REGS_USER) {
785             header_.size -= data_.reg_nr * sizeof(u64);
786             data_.reg_nr = 0;
787             data_.user_abi = 0;
788         }
789 
790         if (sampleType_ & PERF_SAMPLE_STACK_USER) {
791             // 1. remove the user stack
792             header_.size -= data_.stack_size;
793             header_.size -= sizeof(data_.dyn_size);
794 
795             // 2. clean the size
796             data_.stack_size = 0;
797             data_.dyn_size = 0;
798         }
799 
800         if (sampleType_ & PERF_SAMPLE_CALLCHAIN) {
801             HLOGV("ips change from %llu -> %zu", data_.nr, ips_.size());
802 
803             // 3. remove the nr size
804             header_.size -= data_.nr * sizeof(u64);
805 
806             // 4. add new nr size
807             data_.nr = ips_.size();
808             header_.size += data_.nr * sizeof(u64);
809 
810             // 5. change ips potin to our ips array and hold it.
811             data_.ips = ips_.data();
812         }
813     }
814 }
815 
GetPid() const816 inline pid_t PerfRecordSample::GetPid() const
817 {
818     return data_.pid;
819 }
820 
GetTime() const821 uint64_t PerfRecordSample::GetTime() const
822 {
823     return data_.time;
824 }
825 
Clean()826 void PerfRecordSample::Clean()
827 {
828     ips_.clear();
829     callFrames_.clear();
830     serverPidMap_.clear();
831 }
832 
GetUstackServerPid()833 pid_t PerfRecordSample::GetUstackServerPid()
834 {
835     if (!data_.server_nr) {
836         return data_.pid;
837     }
838 
839     size_t currServer = 0;
840     // ipNr == 1...nr: server_pid of data_.ips[nr]
841     for (size_t i = 0; i < data_.nr; i++) {
842         // context change, use next server pid
843         if (data_.ips[i] >= PERF_CONTEXT_MAX) {
844             currServer++;
845         }
846     }
847     // ipNr == nr + 1: server_pid of ustack
848     if (currServer > 0) {
849         currServer++;
850     }
851     if (currServer >= data_.server_nr) {
852         HLOGE("ustack server pid nr %zu out of range", currServer);
853         return data_.pid;
854     }
855 
856     // return server pid
857     return data_.server_pids[currServer];
858 }
859 
GetServerPidof(unsigned int ipNr)860 pid_t PerfRecordSample::GetServerPidof(unsigned int ipNr)
861 {
862     if (!data_.server_nr) {
863         return data_.pid;
864     }
865 
866     // init serverPidMap_
867     if (!serverPidMap_.size()) {
868         size_t currServer = 0;
869         // ipNr == 0: server_pid of data_.ip
870         serverPidMap_.emplace_back(data_.server_pids[currServer]);
871         // ipNr == 1...nr: server_pid of data_.ips[nr]
872         for (size_t i = 1; i < data_.nr; i++) {
873             // context change, use next server pid
874             if (data_.ips[i] >= PERF_CONTEXT_MAX) {
875                 currServer++;
876             }
877             if (currServer >= data_.server_nr) {
878                 HLOGE("callchain server pid nr %zu out of range", currServer);
879                 break;
880             }
881             serverPidMap_.emplace_back(data_.server_pids[currServer]);
882         }
883     }
884 
885     // return server pid
886     if (ipNr >= serverPidMap_.size()) {
887         return data_.pid;
888     } else {
889         return serverPidMap_[ipNr];
890     }
891 }
892 
GetBinary(std::vector<uint8_t> & buf) const893 bool PerfRecordExit::GetBinary(std::vector<uint8_t> &buf) const
894 {
895     if (buf.size() < GetSize()) {
896         buf.resize(GetSize());
897     }
898 
899     GetHeaderBinary(buf);
900     uint8_t *p = buf.data() + GetHeaderSize();
901 
902     auto pDest = reinterpret_cast<PerfRecordExitData *>(p);
903     *pDest = data_;
904     return true;
905 }
906 
DumpData(int indent) const907 void PerfRecordExit::DumpData(int indent) const
908 {
909     PRINT_INDENT(indent, "pid %u, ppid %u, tid %u, ptid %u time 0x%llx\n", data_.pid, data_.ppid,
910                  data_.tid, data_.ptid, data_.time);
911 }
912 
GetBinary(std::vector<uint8_t> & buf) const913 bool PerfRecordThrottle::GetBinary(std::vector<uint8_t> &buf) const
914 {
915     if (buf.size() < GetSize()) {
916         buf.resize(GetSize());
917     }
918 
919     GetHeaderBinary(buf);
920     uint8_t *p = buf.data() + GetHeaderSize();
921 
922     auto pDest = reinterpret_cast<PerfRecordThrottleData *>(p);
923     *pDest = data_;
924     return true;
925 }
926 
DumpData(int indent) const927 void PerfRecordThrottle::DumpData(int indent) const
928 {
929     PRINT_INDENT(indent, "time 0x%llx, id %llx, stream_id %llx\n", data_.time, data_.id,
930                  data_.stream_id);
931 }
932 
GetBinary(std::vector<uint8_t> & buf) const933 bool PerfRecordUnthrottle::GetBinary(std::vector<uint8_t> &buf) const
934 {
935     if (buf.size() < GetSize()) {
936         buf.resize(GetSize());
937     }
938 
939     GetHeaderBinary(buf);
940     uint8_t *p = buf.data() + GetHeaderSize();
941 
942     auto pDest = reinterpret_cast<PerfRecordThrottleData *>(p);
943     *pDest = data_;
944     return true;
945 }
946 
DumpData(int indent) const947 void PerfRecordUnthrottle::DumpData(int indent) const
948 {
949     PRINT_INDENT(indent, "time 0x%llx, id %llx, stream_id %llx\n", data_.time, data_.id,
950                  data_.stream_id);
951 }
952 
GetBinary(std::vector<uint8_t> & buf) const953 bool PerfRecordFork::GetBinary(std::vector<uint8_t> &buf) const
954 {
955     if (buf.size() < GetSize()) {
956         buf.resize(GetSize());
957     }
958 
959     GetHeaderBinary(buf);
960     uint8_t *p = buf.data() + GetHeaderSize();
961 
962     auto pDest = reinterpret_cast<PerfRecordForkData *>(p);
963     *pDest = data_;
964     return true;
965 }
966 
DumpData(int indent) const967 void PerfRecordFork::DumpData(int indent) const
968 {
969     PRINT_INDENT(indent, "pid %u, ppid %u, tid %u, ptid %u\n", data_.pid, data_.ppid, data_.tid,
970                  data_.ptid);
971 }
972 
GetBinary(std::vector<uint8_t> & buf) const973 bool PerfRecordRead::GetBinary(std::vector<uint8_t> &buf) const
974 {
975     if (buf.size() < GetSize()) {
976         buf.resize(GetSize());
977     }
978 
979     GetHeaderBinary(buf);
980     uint8_t *p = buf.data() + GetHeaderSize();
981 
982     auto pDest = reinterpret_cast<PerfRecordReadData *>(p);
983     *pDest = data_;
984     return true;
985 }
986 
DumpData(int indent) const987 void PerfRecordRead::DumpData(int indent) const
988 {
989     PRINT_INDENT(indent, "pid %u, tid %u\n", data_.pid, data_.tid);
990     PRINT_INDENT(indent, "values: value %llx, timeEnabled %llx, timeRunning %llx, id %llx\n",
991                  data_.values.value, data_.values.timeEnabled, data_.values.timeRunning, data_.values.id);
992 }
993 
GetBinary(std::vector<uint8_t> & buf) const994 bool PerfRecordAux::GetBinary(std::vector<uint8_t> &buf) const
995 {
996     if (buf.size() < GetSize()) {
997         buf.resize(GetSize());
998     }
999 
1000     GetHeaderBinary(buf);
1001     uint8_t *p = buf.data() + GetHeaderSize();
1002 
1003     PushToBinary(true, p, data_.aux_offset);
1004     PushToBinary(true, p, data_.aux_size);
1005     PushToBinary(true, p, data_.flags);
1006     PushToBinary2(sampleType_ & PERF_SAMPLE_TID, p, data_.sample_id.pid, data_.sample_id.tid);
1007     PushToBinary(sampleType_ & PERF_SAMPLE_TIME, p, data_.sample_id.time);
1008     PushToBinary(sampleType_ & PERF_SAMPLE_ID, p, data_.sample_id.id);
1009     PushToBinary(sampleType_ & PERF_SAMPLE_STREAM_ID, p, data_.sample_id.stream_id);
1010 
1011     PushToBinary2(sampleType_ & PERF_SAMPLE_CPU, p, data_.sample_id.cpu, data_.sample_id.res);
1012     PushToBinary(sampleType_ & PERF_SAMPLE_IDENTIFIER, p, data_.sample_id.id2);
1013     return true;
1014 }
1015 
DumpData(int indent) const1016 void PerfRecordAux::DumpData(int indent) const
1017 {
1018     PRINT_INDENT(indent, "aux_offset 0x%llx aux_size 0x%llx flags 0x%llx pid %u tid %u time %llu",
1019                  data_.aux_offset, data_.aux_size, data_.flags, data_.sample_id.pid, data_.sample_id.tid,
1020                  data_.sample_id.time);
1021 }
1022 
GetBinary(std::vector<uint8_t> & buf) const1023 bool PerfRecordAuxTraceInfo::GetBinary(std::vector<uint8_t> &buf) const
1024 {
1025     if (buf.size() < GetSize()) {
1026         buf.resize(GetSize());
1027     }
1028 
1029     GetHeaderBinary(buf);
1030     uint8_t *p = buf.data() + GetHeaderSize();
1031     std::copy(reinterpret_cast<const uint8_t *>(&data_),
1032               reinterpret_cast<const uint8_t *>(&data_) + GetSize() - GetHeaderSize(), p);
1033     return true;
1034 }
1035 
DumpData(int indent) const1036 void PerfRecordAuxTraceInfo::DumpData(int indent) const
1037 {
1038     PRINT_INDENT(indent, "aux_trace_event");
1039 }
1040 
GetBinary(std::vector<uint8_t> & buf) const1041 bool PerfRecordTimeConv::GetBinary(std::vector<uint8_t> &buf) const
1042 {
1043     if (buf.size() < GetSize()) {
1044         buf.resize(GetSize());
1045     }
1046 
1047     GetHeaderBinary(buf);
1048     uint8_t *p = buf.data() + GetHeaderSize();
1049     std::copy(reinterpret_cast<const uint8_t *>(&data_),
1050               reinterpret_cast<const uint8_t *>(&data_) + GetSize() - GetHeaderSize(), p);
1051     return true;
1052 }
1053 
DumpData(int indent) const1054 void PerfRecordTimeConv::DumpData(int indent) const
1055 {
1056     PRINT_INDENT(indent, "aux_time_event");
1057 }
1058 
GetBinary(std::vector<uint8_t> & buf) const1059 bool PerfRecordCpuMap::GetBinary(std::vector<uint8_t> &buf) const
1060 {
1061     if (buf.size() < GetSize()) {
1062         buf.resize(GetSize());
1063     }
1064 
1065     GetHeaderBinary(buf);
1066     uint8_t *p = buf.data() + GetHeaderSize();
1067     std::copy(reinterpret_cast<const uint8_t *>(&data_),
1068               reinterpret_cast<const uint8_t *>(&data_) + GetSize() - GetHeaderSize(), p);
1069     return true;
1070 }
1071 
DumpData(int indent) const1072 void PerfRecordCpuMap::DumpData(int indent) const
1073 {
1074     PRINT_INDENT(indent, "cpu_map_event");
1075 }
1076 
GetBinary(std::vector<uint8_t> & buf) const1077 bool PerfRecordItraceStart::GetBinary(std::vector<uint8_t> &buf) const
1078 {
1079     if (buf.size() < GetSize()) {
1080         buf.resize(GetSize());
1081     }
1082 
1083     GetHeaderBinary(buf);
1084     uint8_t *p = buf.data() + GetHeaderSize();
1085 
1086     auto pDest = reinterpret_cast<PerfRecordItraceStartData *>(p);
1087     *pDest = data_;
1088     return true;
1089 }
1090 
DumpData(int indent) const1091 void PerfRecordItraceStart::DumpData(int indent) const
1092 {
1093     PRINT_INDENT(indent, "pid %u, tid %u\n", data_.pid, data_.tid);
1094 }
1095 
GetBinary(std::vector<uint8_t> & buf) const1096 bool PerfRecordLostSamples::GetBinary(std::vector<uint8_t> &buf) const
1097 {
1098     if (buf.size() < GetSize()) {
1099         buf.resize(GetSize());
1100     }
1101 
1102     GetHeaderBinary(buf);
1103     uint8_t *p = buf.data() + GetHeaderSize();
1104 
1105     auto pDest = reinterpret_cast<PerfRecordLostSamplesData *>(p);
1106     *pDest = data_;
1107     return true;
1108 }
1109 
DumpData(int indent) const1110 void PerfRecordLostSamples::DumpData(int indent) const
1111 {
1112     PRINT_INDENT(indent, "lost %llu\n", data_.lost);
1113 }
1114 
GetBinary(std::vector<uint8_t> & buf) const1115 bool PerfRecordSwitch::GetBinary(std::vector<uint8_t> &buf) const
1116 {
1117     if (buf.size() < GetSize()) {
1118         buf.resize(GetSize());
1119     }
1120 
1121     GetHeaderBinary(buf);
1122     uint8_t *p = buf.data() + GetHeaderSize();
1123 
1124     auto pDest = reinterpret_cast<PerfRecordSwitchData *>(p);
1125     *pDest = data_;
1126     return true;
1127 }
1128 
GetBinary(std::vector<uint8_t> & buf) const1129 bool PerfRecordSwitchCpuWide::GetBinary(std::vector<uint8_t> &buf) const
1130 {
1131     if (buf.size() < GetSize()) {
1132         buf.resize(GetSize());
1133     }
1134 
1135     GetHeaderBinary(buf);
1136     uint8_t *p = buf.data() + GetHeaderSize();
1137 
1138     auto pDest = reinterpret_cast<PerfRecordSwitchCpuWideData *>(p);
1139     *pDest = data_;
1140     return true;
1141 }
1142 
DumpData(int indent) const1143 void PerfRecordSwitchCpuWide::DumpData(int indent) const
1144 {
1145     PRINT_INDENT(indent, "next_prev_pid %u, next_prev_tid %u\n", data_.next_prev_pid,
1146                  data_.next_prev_tid);
1147 }
1148 
GetPerfEventRecord(PerfRecordType type,uint8_t * data,const perf_event_attr & attr)1149 PerfEventRecord& PerfEventRecordFactory::GetPerfEventRecord(PerfRecordType type, uint8_t* data,
1150                                                             const perf_event_attr &attr)
1151 {
1152     HLOG_ASSERT(data != nullptr);
1153     PerfEventRecord* record = nullptr;
1154     auto it = recordMap_.find(type);
1155     if (it == recordMap_.end()) {
1156         record = CreatePerfEventRecord(type);
1157         if (record == nullptr) {
1158             record = new PerfRecordNull();
1159         }
1160         recordMap_.emplace(type, record);
1161     } else {
1162         record = it->second;
1163     }
1164     record->Init(data, attr);
1165     return *record;
1166 }
1167 } // namespace HiPerf
1168 } // namespace Developtools
1169 } // namespace OHOS
1170