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