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