• 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 <cinttypes>
19 #include "utilities.h"
20 
21 
22 using namespace std;
23 namespace OHOS {
24 namespace Developtools {
25 namespace HiPerf {
GetPerfEventRecord(const int type,uint8_t * p,const perf_event_attr & attr)26 std::unique_ptr<PerfEventRecord> GetPerfEventRecord(const int type, uint8_t *p,
27                                                     const perf_event_attr &attr)
28 {
29     HLOG_ASSERT(p);
30     uint8_t *data = p;
31 
32     // check kernel
33     switch (type) {
34         case PERF_RECORD_SAMPLE:
35             return std::make_unique<PerfRecordSample>(data, attr);
36         case PERF_RECORD_MMAP:
37             return std::make_unique<PerfRecordMmap>(data);
38         case PERF_RECORD_MMAP2:
39             return std::make_unique<PerfRecordMmap2>(data);
40         case PERF_RECORD_LOST:
41             return std::make_unique<PerfRecordLost>(data);
42         case PERF_RECORD_COMM:
43             return std::make_unique<PerfRecordComm>(data);
44         case PERF_RECORD_EXIT:
45             return std::make_unique<PerfRecordExit>(data);
46         case PERF_RECORD_THROTTLE:
47             return std::make_unique<PerfRecordThrottle>(data);
48         case PERF_RECORD_UNTHROTTLE:
49             return std::make_unique<PerfRecordUnthrottle>(data);
50         case PERF_RECORD_FORK:
51             return std::make_unique<PerfRecordFork>(data);
52         case PERF_RECORD_READ:
53             return std::make_unique<PerfRecordRead>(data);
54         case PERF_RECORD_AUX:
55             return std::make_unique<PerfRecordAux>(data);
56         case PERF_RECORD_ITRACE_START:
57             return std::make_unique<PerfRecordItraceStart>(data);
58         case PERF_RECORD_LOST_SAMPLES:
59             return std::make_unique<PerfRecordLostSamples>(data);
60         case PERF_RECORD_SWITCH:
61             return std::make_unique<PerfRecordSwitch>(data);
62         case PERF_RECORD_SWITCH_CPU_WIDE:
63             return std::make_unique<PerfRecordSwitchCpuWide>(data);
64         default:
65             HLOGE("unknown record type %d\n", type);
66             return nullptr;
67     }
68 }
69 
70 template<typename T>
PushToBinary(bool condition,uint8_t * & p,const T & v)71 inline void PushToBinary(bool condition, uint8_t *&p, const T &v)
72 {
73     if (condition) {
74         *(reinterpret_cast<T *>(p)) = v;
75         p += sizeof(T);
76     }
77 }
78 
79 template<typename T1, typename T2>
PushToBinary2(bool condition,uint8_t * & p,const T1 & v1,const T2 & v2)80 inline void PushToBinary2(bool condition, uint8_t *&p, const T1 &v1, const T2 &v2)
81 {
82     if (condition) {
83         *(reinterpret_cast<T1 *>(p)) = v1;
84         p += sizeof(T1);
85         *(reinterpret_cast<T2 *>(p)) = v2;
86         p += sizeof(T2);
87     }
88 }
89 
90 template<typename T>
PopFromBinary(bool condition,uint8_t * & p,T & v)91 inline void PopFromBinary(bool condition, uint8_t *&p, T &v)
92 {
93     if (condition) {
94         v = *(reinterpret_cast<const T *>(p));
95         p += sizeof(T);
96     }
97 }
98 
99 template<typename T1, typename T2>
PopFromBinary2(bool condition,uint8_t * & p,T1 & v1,T2 & v2)100 inline void PopFromBinary2(bool condition, uint8_t *&p, T1 &v1, T2 &v2)
101 {
102     if (condition) {
103         v1 = *(reinterpret_cast<const T1 *>(p));
104         p += sizeof(T1);
105         v2 = *(reinterpret_cast<const T2 *>(p));
106         p += sizeof(T2);
107     }
108 }
109 
110 // PerfEventRecord
PerfEventRecord(perf_event_type type,bool in_kernel,const std::string & name)111 PerfEventRecord::PerfEventRecord(perf_event_type type, bool in_kernel, const std::string &name)
112     : name_(name)
113 {
114     header.type = type;
115     header.misc = in_kernel ? PERF_RECORD_MISC_KERNEL : PERF_RECORD_MISC_USER;
116     header.size = sizeof(header);
117 }
118 
PerfEventRecord(perf_event_hiperf_ext_type type,const std::string & name)119 PerfEventRecord::PerfEventRecord(perf_event_hiperf_ext_type type, const std::string &name)
120     : name_(name)
121 {
122     header.type = type;
123     header.misc = PERF_RECORD_MISC_USER;
124     header.size = sizeof(header);
125 }
126 
PerfEventRecord(uint8_t * p,const std::string & name)127 PerfEventRecord::PerfEventRecord(uint8_t *p, const std::string &name) : name_(name)
128 {
129     header = *(reinterpret_cast<perf_event_header *>(p));
130 }
131 
GetHeaderBinary(std::vector<uint8_t> & buf) const132 void PerfEventRecord::GetHeaderBinary(std::vector<uint8_t> &buf) const
133 {
134     if (buf.size() < GetHeaderSize()) {
135         buf.resize(GetHeaderSize());
136     }
137     uint8_t *p = buf.data();
138     *(reinterpret_cast<perf_event_header *>(p)) = header;
139 }
140 
Dump(int indent) const141 void PerfEventRecord::Dump(int indent) const
142 {
143     PrintIndent(indent, "\n");
144     PrintIndent(indent, "record %s: type %u, misc %u, size %zu\n", GetName().c_str(), GetType(),
145                 GetMisc(), GetSize());
146     DumpData(indent + 1);
147 }
148 
DumpLog(const std::string & prefix) const149 void PerfEventRecord::DumpLog(const std::string &prefix) const
150 {
151     HLOGV("%s: record %s: type %u, misc %u, size %zu\n", prefix.c_str(), GetName().c_str(),
152           GetType(), GetMisc(), GetSize());
153 }
154 
DumpLog(const std::string & prefix) const155 void PerfRecordSample::DumpLog(const std::string &prefix) const
156 {
157     HLOGV("%s: SAMPLE: id= %llu size %d pid %u tid %u ips %llu regs %llu, stacks %llu time %llu",
158           prefix.c_str(), data_.sample_id, header.size, data_.pid, data_.tid, data_.nr,
159           data_.reg_nr, data_.dyn_size, data_.time);
160 }
161 
ReplaceWithCallStack(size_t originalSize)162 void PerfRecordSample::ReplaceWithCallStack(size_t originalSize)
163 {
164     // first we check if we have some user unwind stack need to merge ?
165     if (callFrames_.size() != 0) {
166         // when we have some kernel ips , we cp it first
167         // new size is user call frames + kernel call frames
168         // + PERF_CONTEXT_USER(last + 1) + expand mark(also PERF_CONTEXT_USER)
169         const unsigned int perfContextSize = 2;
170         ips_.reserve(data_.nr + callFrames_.size() + perfContextSize);
171         if (data_.nr > 0) {
172             ips_.assign(data_.ips, data_.ips + data_.nr);
173         }
174         // add user context mark
175         ips_.emplace_back(PERF_CONTEXT_USER);
176         // we also need make a expand mark just for debug only
177         const size_t beginIpsSize = ips_.size();
178         bool ret = std::all_of(callFrames_.begin(), callFrames_.end(), [&](const CallFrame &frame) {
179             ips_.emplace_back(frame.ip_);
180             if (originalSize != 0 and (originalSize != callFrames_.size()) and
181                 ips_.size() == (originalSize + beginIpsSize)) {
182                 // just for debug
183                 // so we can see which frame begin is expand call frames
184                 ips_.emplace_back(PERF_CONTEXT_USER);
185             }
186             return true;
187         });
188         if (ret) {
189             HLOGV("combed %zu", callFrames_.size());
190         } else {
191             HLOGV("failed to combed %zu", callFrames_.size());
192         }
193 
194         if (sampleType_ & PERF_SAMPLE_REGS_USER) {
195             data_.reg_nr = 0;
196             header.size -= data_.reg_nr * sizeof(u64);
197         }
198 
199         if (sampleType_ & PERF_SAMPLE_STACK_USER) {
200             // 1. remove the user stack
201             header.size -= data_.stack_size;
202 
203             // 2. clean the size
204             data_.user_abi = 0;
205             data_.stack_size = 0;
206             data_.dyn_size = 0;
207         }
208 
209         if (sampleType_ & PERF_SAMPLE_CALLCHAIN) {
210             HLOGV("ips change from %llu -> %zu", data_.nr, ips_.size());
211 
212             // 3. remove the nr size
213             header.size -= data_.nr * sizeof(u64);
214 
215             // 4. add new nr size
216             data_.nr = ips_.size();
217             header.size += data_.nr * sizeof(u64);
218 
219             // 5. change ips potin to our ips array and hold it.
220             data_.ips = ips_.data();
221         }
222     } else {
223         // nothing need change
224         return;
225     }
226 }
227 
PerfRecordSample(uint8_t * p,const perf_event_attr & attr)228 PerfRecordSample::PerfRecordSample(uint8_t *p, const perf_event_attr &attr)
229     : PerfEventRecord(p, "sample")
230 {
231     if (p == nullptr) {
232         HLOG_ASSERT(p);
233         return;
234     }
235     sampleType_ = attr.sample_type;
236 
237     p += sizeof(header);
238 
239     // parse record according SAMPLE_TYPE
240     PopFromBinary(sampleType_ & PERF_SAMPLE_IDENTIFIER, p, data_.sample_id);
241     PopFromBinary(sampleType_ & PERF_SAMPLE_IP, p, data_.ip);
242     PopFromBinary2(sampleType_ & PERF_SAMPLE_TID, p, data_.pid, data_.tid);
243     PopFromBinary(sampleType_ & PERF_SAMPLE_TIME, p, data_.time);
244     PopFromBinary(sampleType_ & PERF_SAMPLE_ADDR, p, data_.addr);
245     PopFromBinary(sampleType_ & PERF_SAMPLE_ID, p, data_.id);
246     PopFromBinary(sampleType_ & PERF_SAMPLE_STREAM_ID, p, data_.stream_id);
247     PopFromBinary2(sampleType_ & PERF_SAMPLE_CPU, p, data_.cpu, data_.res);
248     PopFromBinary(sampleType_ & PERF_SAMPLE_PERIOD, p, data_.period);
249     PopFromBinary(sampleType_ & PERF_SAMPLE_CALLCHAIN, p, data_.nr);
250     if (data_.nr > 0) {
251         // the pointer is from input(p), require caller keep input(p) with *this together
252         // think it in next time
253         data_.ips = reinterpret_cast<u64 *>(p);
254         p += data_.nr * sizeof(u64);
255     }
256     PopFromBinary(sampleType_ & PERF_SAMPLE_RAW, p, data_.raw_size);
257     if (data_.raw_size > 0) {
258         data_.raw_data = p;
259         p += data_.raw_size * sizeof(u8);
260     }
261     PopFromBinary(sampleType_ & PERF_SAMPLE_BRANCH_STACK, p, data_.bnr);
262     if (data_.bnr > 0) {
263         data_.lbr = reinterpret_cast<perf_branch_entry *>(p);
264         p += data_.bnr * sizeof(perf_branch_entry);
265     }
266     PopFromBinary(sampleType_ & PERF_SAMPLE_REGS_USER, p, data_.user_abi);
267     if (data_.user_abi > 0) {
268         data_.reg_mask = attr.sample_regs_user;
269         data_.reg_nr = __builtin_popcountll(data_.reg_mask);
270         data_.user_regs = reinterpret_cast<u64 *>(p);
271         p += data_.reg_nr * sizeof(u64);
272     }
273     PopFromBinary(sampleType_ & PERF_SAMPLE_STACK_USER, p, data_.stack_size);
274     if (data_.stack_size > 0) {
275         data_.stack_data = p;
276         p += data_.stack_size;
277         PopFromBinary(true, p, data_.dyn_size);
278     }
279 }
280 
GetBinary(std::vector<uint8_t> & buf) const281 bool PerfRecordSample::GetBinary(std::vector<uint8_t> &buf) const
282 {
283     if (buf.size() < GetSize()) {
284         buf.resize(GetSize());
285     }
286 
287     GetHeaderBinary(buf);
288     uint8_t *p = buf.data() + GetHeaderSize();
289 
290     PushToBinary(sampleType_ & PERF_SAMPLE_IDENTIFIER, p, data_.sample_id);
291     PushToBinary(sampleType_ & PERF_SAMPLE_IP, p, data_.ip);
292     PushToBinary2(sampleType_ & PERF_SAMPLE_TID, p, data_.pid, data_.tid);
293     PushToBinary(sampleType_ & PERF_SAMPLE_TIME, p, data_.time);
294     PushToBinary(sampleType_ & PERF_SAMPLE_ADDR, p, data_.addr);
295     PushToBinary(sampleType_ & PERF_SAMPLE_ID, p, data_.id);
296     PushToBinary(sampleType_ & PERF_SAMPLE_STREAM_ID, p, data_.stream_id);
297     PushToBinary2(sampleType_ & PERF_SAMPLE_CPU, p, data_.cpu, data_.res);
298     PushToBinary(sampleType_ & PERF_SAMPLE_PERIOD, p, data_.period);
299     PushToBinary(sampleType_ & PERF_SAMPLE_CALLCHAIN, p, data_.nr);
300     if (data_.nr > 0) {
301         std::copy(data_.ips, data_.ips + data_.nr, reinterpret_cast<u64 *>(p));
302         p += data_.nr * sizeof(u64);
303     }
304     PushToBinary(sampleType_ & PERF_SAMPLE_RAW, p, data_.raw_size);
305     if (data_.raw_size > 0) {
306         std::copy(data_.raw_data, data_.raw_data + data_.raw_size, p);
307         p += data_.raw_size * sizeof(u8);
308     }
309     PushToBinary(sampleType_ & PERF_SAMPLE_BRANCH_STACK, p, data_.bnr);
310     if (data_.bnr > 0) {
311         std::copy(data_.lbr, data_.lbr + data_.bnr, reinterpret_cast<perf_branch_entry *>(p));
312         p += data_.bnr * sizeof(perf_branch_entry);
313     }
314     PushToBinary(sampleType_ & PERF_SAMPLE_REGS_USER, p, data_.user_abi);
315     if (data_.user_abi > 0 && data_.reg_nr > 0) {
316         std::copy(data_.user_regs, data_.user_regs + data_.reg_nr, reinterpret_cast<u64 *>(p));
317         p += data_.reg_nr * sizeof(u64);
318     }
319     PushToBinary(sampleType_ & PERF_SAMPLE_STACK_USER, p, data_.stack_size);
320     if (data_.stack_size > 0) {
321         std::copy(data_.stack_data, data_.stack_data + data_.stack_size, p);
322         p += data_.stack_size * sizeof(u8);
323         PushToBinary(true, p, data_.dyn_size);
324     }
325 
326     return true;
327 }
328 
DumpData(int indent) const329 void PerfRecordSample::DumpData(int indent) const
330 {
331     PrintIndent(indent, "sample_type: 0x%" PRIx64 "\n", sampleType_);
332 
333     // dump record according sampleType
334     if (sampleType_ & (PERF_SAMPLE_ID | PERF_SAMPLE_IDENTIFIER)) {
335         PrintIndent(indent, "ID %lld\n", data_.sample_id);
336     }
337     if (sampleType_ & PERF_SAMPLE_IP) {
338         PrintIndent(indent, "ip %llx\n", data_.ip);
339     }
340     if (sampleType_ & PERF_SAMPLE_TID) {
341         PrintIndent(indent, "pid %u, tid %u\n", data_.pid, data_.tid);
342     }
343     if (sampleType_ & PERF_SAMPLE_TIME) {
344         PrintIndent(indent, "time %llu\n", data_.time);
345     }
346     if (sampleType_ & PERF_SAMPLE_ADDR) {
347         PrintIndent(indent, "addr %p\n", reinterpret_cast<void *>(data_.addr));
348     }
349     if (sampleType_ & PERF_SAMPLE_STREAM_ID) {
350         PrintIndent(indent, "stream_id %lld\n", data_.stream_id);
351     }
352     if (sampleType_ & PERF_SAMPLE_CPU) {
353         PrintIndent(indent, "cpu %u, res %u\n", data_.cpu, data_.res);
354     }
355     if (sampleType_ & PERF_SAMPLE_PERIOD) {
356         PrintIndent(indent, "period %lld\n", data_.period);
357     }
358     if (sampleType_ & PERF_SAMPLE_CALLCHAIN) {
359         bool userContext = false;
360         PrintIndent(indent, "callchain nr=%lld\n", data_.nr);
361         for (uint64_t i = 0; i < data_.nr; ++i) {
362             std::string_view supplement = "";
363             if ((sampleType_ & PERF_SAMPLE_STACK_USER) == 0 || data_.ips[i] != PERF_CONTEXT_USER) {
364                 PrintIndent(indent + 1, "0x%llx%s\n", data_.ips[i], supplement.data());
365                 continue;
366             }
367             // is PERF_SAMPLE_STACK_USER type and is PERF_CONTEXT_USER
368             if (!userContext) {
369                 userContext = true;
370                 supplement = " <unwind callstack>";
371             } else {
372                 supplement = " <expand callstack>";
373             }
374             PrintIndent(indent + 1, "0x%llx%s\n", data_.ips[i], supplement.data());
375         }
376     }
377     if (sampleType_ & PERF_SAMPLE_RAW) {
378         PrintIndent(indent, "raw size=%u\n", data_.raw_size);
379         const uint32_t *data = reinterpret_cast<const uint32_t *>(data_.raw_data);
380         size_t size = data_.raw_size / sizeof(uint32_t);
381         for (size_t i = 0; i < size; ++i) {
382             PrintIndent(indent + 1, "0x%08x (%x)\n", data[i], data[i]);
383         }
384     }
385     if (sampleType_ & PERF_SAMPLE_BRANCH_STACK) {
386         PrintIndent(indent, "branch_stack nr=%lld\n", data_.bnr);
387         for (uint64_t i = 0; i < data_.bnr; ++i) {
388             auto &item = data_.lbr[i];
389             PrintIndent(indent + 1, "from 0x%llx, to 0x%llx %s%s\n", item.from, item.to,
390                         item.mispred ? "mispred" : "", item.predicted ? "predicted" : "");
391         }
392     }
393     if (sampleType_ & PERF_SAMPLE_REGS_USER) {
394         PrintIndent(indent, "user regs: abi=%lld, reg_nr=%lld\n", data_.user_abi, data_.reg_nr);
395         for (uint64_t i = 0; i < data_.reg_nr; ++i) {
396             PrintIndent(indent + 1, "0x%llx\n", data_.user_regs[i]);
397         }
398     }
399     if (sampleType_ & PERF_SAMPLE_STACK_USER) {
400         PrintIndent(indent, "user stack: size %llu dyn_size %lld\n", data_.stack_size,
401                     data_.dyn_size);
402     }
403 }
404 
GetPid() const405 inline pid_t PerfRecordSample::GetPid() const
406 {
407     return data_.pid;
408 }
409 
PerfRecordMmap(uint8_t * p)410 PerfRecordMmap::PerfRecordMmap(uint8_t *p) : PerfEventRecord(p, "mmap")
411 {
412     size_t copySize = GetSize() - sizeof(header);
413     if (memcpy_s((uint8_t *)&data_, sizeof(data_), p + sizeof(header), copySize) != 0) {
414         HLOGE("memcpy_s retren failed !!!");
415     }
416 }
417 
PerfRecordMmap(bool inKernel,u32 pid,u32 tid,u64 addr,u64 len,u64 pgoff,const std::string & filename)418 PerfRecordMmap::PerfRecordMmap(bool inKernel, u32 pid, u32 tid, u64 addr, u64 len, u64 pgoff,
419                                const std::string &filename)
420     : PerfEventRecord(PERF_RECORD_MMAP, inKernel, "mmap")
421 {
422     data_.pid = pid;
423     data_.tid = tid;
424     data_.addr = addr;
425     data_.len = len;
426     data_.pgoff = pgoff;
427     if (strncpy_s(data_.filename, KILO, filename.c_str(), filename.size()) != 0) {
428         HLOGE("strncpy_s failed");
429     }
430 
431     header.size = sizeof(header) + sizeof(data_) - KILO + filename.size() + 1;
432 }
433 
GetBinary(std::vector<uint8_t> & buf) const434 bool PerfRecordMmap::GetBinary(std::vector<uint8_t> &buf) const
435 {
436     if (buf.size() < GetSize()) {
437         buf.resize(GetSize());
438     }
439 
440     GetHeaderBinary(buf);
441     uint8_t *p = buf.data() + GetHeaderSize();
442 
443     // data_.filename[] is variable-length
444     std::copy((uint8_t *)&data_, (uint8_t *)&data_ + GetSize() - GetHeaderSize(), p);
445     return true;
446 }
447 
DumpData(int indent) const448 void PerfRecordMmap::DumpData(int indent) const
449 {
450     PrintIndent(indent, "pid %u, tid %u, addr 0x%llx, len 0x%llx\n", data_.pid, data_.tid,
451                 data_.addr, data_.len);
452     PrintIndent(indent, "pgoff 0x%llx, filename %s\n", data_.pgoff, data_.filename);
453 }
454 
DumpLog(const std::string & prefix) const455 void PerfRecordMmap::DumpLog(const std::string &prefix) const
456 {
457     HLOGV("%s:  MMAP: size %d pid %u tid %u dso '%s' (0x%llx-0x%llx)@0x%llx", prefix.c_str(),
458           header.size, data_.pid, data_.tid, data_.filename, data_.addr, data_.addr + data_.len,
459           data_.pgoff);
460 }
461 
PerfRecordMmap2(uint8_t * p)462 PerfRecordMmap2::PerfRecordMmap2(uint8_t *p) : PerfEventRecord(p, "mmap2")
463 {
464     size_t copySize = GetSize() - sizeof(header);
465     if (memcpy_s((uint8_t *)&data_, sizeof(data_), p + sizeof(header), copySize) != 0) {
466         HLOGE("memcpy_s retren failed !!!");
467     }
468 }
469 
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)470 PerfRecordMmap2::PerfRecordMmap2(bool inKernel, u32 pid, u32 tid, u64 addr, u64 len, u64 pgoff,
471                                  u32 maj, u32 min, u64 ino, u32 prot, u32 flags,
472                                  const std::string &filename)
473     : PerfEventRecord(PERF_RECORD_MMAP2, inKernel, "mmap2")
474 {
475     data_.pid = pid;
476     data_.tid = tid;
477     data_.addr = addr;
478     data_.len = len;
479     data_.pgoff = pgoff;
480     data_.maj = maj;
481     data_.min = min;
482     data_.ino = ino;
483     data_.ino_generation = 0;
484     data_.prot = prot;
485     data_.flags = flags;
486     if (strncpy_s(data_.filename, KILO, filename.c_str(), filename.size()) != 0) {
487         HLOGE("strncpy_s failed");
488     }
489 
490     header.size = sizeof(header) + sizeof(data_) - KILO + filename.size() + 1;
491 }
492 
PerfRecordMmap2(bool inKernel,u32 pid,u32 tid,const MemMapItem & item)493 PerfRecordMmap2::PerfRecordMmap2(bool inKernel, u32 pid, u32 tid, const MemMapItem &item)
494     : PerfEventRecord(PERF_RECORD_MMAP2, inKernel, "mmap2")
495 {
496     data_.pid = pid;
497     data_.tid = tid;
498     data_.addr = item.begin_;
499     data_.len = item.end_ - item.begin_;
500     data_.pgoff = item.pageoffset_;
501     data_.maj = item.major_;
502     data_.min = item.minor_;
503     data_.ino = item.inode;
504     data_.ino_generation = 0;
505     data_.prot = item.type_;
506     data_.flags = item.flags;
507     if (strncpy_s(data_.filename, KILO, item.name_.c_str(), item.name_.size()) != 0) {
508         HLOGE("strncpy_s failed");
509     }
510 
511     header.size = sizeof(header) + sizeof(data_) - KILO + item.name_.size() + 1;
512 }
513 
GetBinary(std::vector<uint8_t> & buf) const514 bool PerfRecordMmap2::GetBinary(std::vector<uint8_t> &buf) const
515 {
516     if (buf.size() < GetSize()) {
517         buf.resize(GetSize());
518     }
519 
520     GetHeaderBinary(buf);
521     uint8_t *p = buf.data() + GetHeaderSize();
522 
523     // data_.filename[] is variable-length
524     std::copy((uint8_t *)&data_, (uint8_t *)&data_ + GetSize() - GetHeaderSize(), p);
525     return true;
526 }
527 
DumpData(int indent) const528 void PerfRecordMmap2::DumpData(int indent) const
529 {
530     PrintIndent(indent, "pid %u, tid %u, addr 0x%llx, len 0x%llx\n", data_.pid, data_.tid,
531                 data_.addr, data_.len);
532     PrintIndent(indent, "pgoff 0x%llx, maj %u, min %u, ino %llu, ino_generation %llu\n",
533                 data_.pgoff, data_.maj, data_.min, data_.ino, data_.ino_generation);
534     PrintIndent(indent, "prot %u, flags %u, filename %s\n", data_.prot, data_.flags,
535                 data_.filename);
536 }
DumpLog(const std::string & prefix) const537 void PerfRecordMmap2::DumpLog(const std::string &prefix) const
538 {
539     HLOGV("%s:  MMAP2: size %d pid %u tid %u dso '%s' (0x%llx-0x%llx)@0x%llx", prefix.c_str(),
540           header.size, data_.pid, data_.tid, data_.filename, data_.addr, data_.addr + data_.len,
541           data_.pgoff);
542 }
543 
PerfRecordLost(uint8_t * p)544 PerfRecordLost::PerfRecordLost(uint8_t *p) : PerfEventRecord(p, "lost")
545 {
546     size_t copySize = GetSize() - sizeof(header);
547     if (memcpy_s((uint8_t *)&data_, sizeof(data_), p + sizeof(header), copySize) != 0) {
548         HLOGE("memcpy_s retren failed !!!");
549     }
550 }
551 
GetBinary(std::vector<uint8_t> & buf) const552 bool PerfRecordLost::GetBinary(std::vector<uint8_t> &buf) const
553 {
554     if (buf.size() < GetSize()) {
555         buf.resize(GetSize());
556     }
557 
558     GetHeaderBinary(buf);
559     uint8_t *p = buf.data() + GetHeaderSize();
560 
561     auto pDest = reinterpret_cast<PerfRecordLostData *>(p);
562     *pDest = data_;
563 
564     return true;
565 }
566 
DumpData(int indent) const567 void PerfRecordLost::DumpData(int indent) const
568 {
569     PrintIndent(indent, "id %llu, lost %llu\n", data_.id, data_.lost);
570 }
571 
PerfRecordComm(uint8_t * p)572 PerfRecordComm::PerfRecordComm(uint8_t *p) : PerfEventRecord(p, "comm")
573 {
574     size_t copySize = GetSize() - sizeof(header);
575     if (memcpy_s((uint8_t *)&data_, sizeof(data_), p + sizeof(header), copySize) != 0) {
576         HLOGE("memcpy_s retren failed !!!");
577     }
578 }
579 
PerfRecordComm(bool inKernel,u32 pid,u32 tid,const std::string & comm)580 PerfRecordComm::PerfRecordComm(bool inKernel, u32 pid, u32 tid, const std::string &comm)
581     : PerfEventRecord(PERF_RECORD_COMM, inKernel, "comm")
582 {
583     data_.pid = pid;
584     data_.tid = tid;
585     if (strncpy_s(data_.comm, KILO, comm.c_str(), comm.size()) != 0) {
586         HLOGE("strncpy_s failed !!!");
587     }
588 
589     header.size = sizeof(header) + sizeof(data_) - KILO + comm.size() + 1;
590 }
591 
GetBinary(std::vector<uint8_t> & buf) const592 bool PerfRecordComm::GetBinary(std::vector<uint8_t> &buf) const
593 {
594     if (buf.size() < GetSize()) {
595         buf.resize(GetSize());
596     }
597 
598     GetHeaderBinary(buf);
599     uint8_t *p = buf.data() + GetHeaderSize();
600 
601     // data_.comm[] is variable-length
602     std::copy((uint8_t *)&data_, (uint8_t *)&data_ + GetSize() - GetHeaderSize(), p);
603 
604     return true;
605 }
606 
DumpData(int indent) const607 void PerfRecordComm::DumpData(int indent) const
608 {
609     PrintIndent(indent, "pid %u, tid %u, comm %s\n", data_.pid, data_.tid, data_.comm);
610 }
611 
DumpLog(const std::string & prefix) const612 void PerfRecordComm::DumpLog(const std::string &prefix) const
613 {
614     HLOGV("pid %u, tid %u, comm %s\n", data_.pid, data_.tid, data_.comm);
615 }
616 
PerfRecordExit(uint8_t * p)617 PerfRecordExit::PerfRecordExit(uint8_t *p) : PerfEventRecord(p, "exit")
618 {
619     size_t copySize = GetSize() - sizeof(header);
620     if (memcpy_s((uint8_t *)&data_, sizeof(data_), p + sizeof(header), copySize) != 0) {
621         HLOGE("memcpy_s retren failed !!!");
622     }
623 }
624 
GetBinary(std::vector<uint8_t> & buf) const625 bool PerfRecordExit::GetBinary(std::vector<uint8_t> &buf) const
626 {
627     if (buf.size() < GetSize()) {
628         buf.resize(GetSize());
629     }
630 
631     GetHeaderBinary(buf);
632     uint8_t *p = buf.data() + GetHeaderSize();
633 
634     auto pDest = reinterpret_cast<PerfRecordExitData *>(p);
635     *pDest = data_;
636     return true;
637 }
638 
DumpData(int indent) const639 void PerfRecordExit::DumpData(int indent) const
640 {
641     PrintIndent(indent, "pid %u, ppid %u, tid %u, ptid %u time 0x%llx\n", data_.pid, data_.ppid,
642                 data_.tid, data_.ptid, data_.time);
643 }
644 
PerfRecordThrottle(uint8_t * p)645 PerfRecordThrottle::PerfRecordThrottle(uint8_t *p) : PerfEventRecord(p, "throttle")
646 {
647     size_t copySize = GetSize() - sizeof(header);
648     if (memcpy_s((uint8_t *)&data_, sizeof(data_), p + sizeof(header), copySize) != 0) {
649         HLOGE("memcpy_s retren failed !!!");
650     }
651 }
652 
GetBinary(std::vector<uint8_t> & buf) const653 bool PerfRecordThrottle::GetBinary(std::vector<uint8_t> &buf) const
654 {
655     if (buf.size() < GetSize()) {
656         buf.resize(GetSize());
657     }
658 
659     GetHeaderBinary(buf);
660     uint8_t *p = buf.data() + GetHeaderSize();
661 
662     auto pDest = reinterpret_cast<PerfRecordThrottleData *>(p);
663     *pDest = data_;
664     return true;
665 }
666 
DumpData(int indent) const667 void PerfRecordThrottle::DumpData(int indent) const
668 {
669     PrintIndent(indent, "time 0x%llx, id %llx, stream_id %llx\n", data_.time, data_.id,
670                 data_.stream_id);
671 }
672 
PerfRecordUnthrottle(uint8_t * p)673 PerfRecordUnthrottle::PerfRecordUnthrottle(uint8_t *p) : PerfEventRecord(p, "unthrottle")
674 {
675     size_t copySize = GetSize() - sizeof(header);
676     if (memcpy_s((uint8_t *)&data_, sizeof(data_), p + sizeof(header), copySize) != 0) {
677         HLOGE("memcpy_s retren failed !!!");
678     }
679 }
680 
GetBinary(std::vector<uint8_t> & buf) const681 bool PerfRecordUnthrottle::GetBinary(std::vector<uint8_t> &buf) const
682 {
683     if (buf.size() < GetSize()) {
684         buf.resize(GetSize());
685     }
686 
687     GetHeaderBinary(buf);
688     uint8_t *p = buf.data() + GetHeaderSize();
689 
690     auto pDest = reinterpret_cast<PerfRecordThrottleData *>(p);
691     *pDest = data_;
692     return true;
693 }
DumpData(int indent) const694 void PerfRecordUnthrottle::DumpData(int indent) const
695 {
696     PrintIndent(indent, "time 0x%llx, id %llx, stream_id %llx\n", data_.time, data_.id,
697                 data_.stream_id);
698 }
699 
PerfRecordFork(uint8_t * p)700 PerfRecordFork::PerfRecordFork(uint8_t *p) : PerfEventRecord(p, "fork")
701 {
702     size_t copySize = GetSize() - sizeof(header);
703     if (memcpy_s((uint8_t *)&data_, sizeof(data_), p + sizeof(header), copySize) != 0) {
704         HLOGE("memcpy_s retren failed !!!");
705     }
706 }
707 
GetBinary(std::vector<uint8_t> & buf) const708 bool PerfRecordFork::GetBinary(std::vector<uint8_t> &buf) const
709 {
710     if (buf.size() < GetSize()) {
711         buf.resize(GetSize());
712     }
713 
714     GetHeaderBinary(buf);
715     uint8_t *p = buf.data() + GetHeaderSize();
716 
717     auto pDest = reinterpret_cast<PerfRecordForkData *>(p);
718     *pDest = data_;
719     return true;
720 }
721 
DumpData(int indent) const722 void PerfRecordFork::DumpData(int indent) const
723 {
724     PrintIndent(indent, "pid %u, ppid %u, tid %u, ptid %u\n", data_.pid, data_.ppid, data_.tid,
725                 data_.ptid);
726 }
727 
PerfRecordRead(uint8_t * p)728 PerfRecordRead::PerfRecordRead(uint8_t *p) : PerfEventRecord(p, "read")
729 {
730     size_t copySize = GetSize() - sizeof(header);
731     if (memcpy_s((uint8_t *)&data_, sizeof(data_), p + sizeof(header), copySize) != 0) {
732         HLOGE("memcpy_s retren failed !!!");
733     }
734 }
735 
GetBinary(std::vector<uint8_t> & buf) const736 bool PerfRecordRead::GetBinary(std::vector<uint8_t> &buf) const
737 {
738     if (buf.size() < GetSize()) {
739         buf.resize(GetSize());
740     }
741 
742     GetHeaderBinary(buf);
743     uint8_t *p = buf.data() + GetHeaderSize();
744 
745     auto pDest = reinterpret_cast<PerfRecordReadData *>(p);
746     *pDest = data_;
747     return true;
748 }
749 
DumpData(int indent) const750 void PerfRecordRead::DumpData(int indent) const
751 {
752     PrintIndent(indent, "pid %u, tid %u\n", data_.pid, data_.tid);
753     PrintIndent(indent, "values: value %llx, time_enabled %llx, time_running %llx, id %llx\n",
754                 data_.values.value, data_.values.time_enabled, data_.values.time_running,
755                 data_.values.id);
756 }
757 
PerfRecordAux(uint8_t * p)758 PerfRecordAux::PerfRecordAux(uint8_t *p) : PerfEventRecord(p, "aux")
759 {
760     size_t copySize = GetSize() - sizeof(header);
761     if (memcpy_s((uint8_t *)&data_, sizeof(data_), p + sizeof(header), copySize) != 0) {
762         HLOGE("memcpy_s retren failed !!!");
763     }
764 }
765 
GetBinary(std::vector<uint8_t> & buf) const766 bool PerfRecordAux::GetBinary(std::vector<uint8_t> &buf) const
767 {
768     if (buf.size() < GetSize()) {
769         buf.resize(GetSize());
770     }
771 
772     GetHeaderBinary(buf);
773     uint8_t *p = buf.data() + GetHeaderSize();
774 
775     auto pDest = reinterpret_cast<PerfRecordAuxData *>(p);
776     *pDest = data_;
777     return true;
778 }
779 
DumpData(int indent) const780 void PerfRecordAux::DumpData(int indent) const
781 {
782     PrintIndent(indent, "aux_offset %llx, aux_size %llx, flags %llx\n", data_.aux_offset,
783                 data_.aux_size, data_.flags);
784 }
785 
PerfRecordItraceStart(uint8_t * p)786 PerfRecordItraceStart::PerfRecordItraceStart(uint8_t *p) : PerfEventRecord(p, "itraceStart")
787 {
788     size_t copySize = GetSize() - sizeof(header);
789     if (memcpy_s((uint8_t *)&data_, sizeof(data_), p + sizeof(header), copySize) != 0) {
790         HLOGE("memcpy_s retren failed !!!");
791     }
792 }
793 
GetBinary(std::vector<uint8_t> & buf) const794 bool PerfRecordItraceStart::GetBinary(std::vector<uint8_t> &buf) const
795 {
796     if (buf.size() < GetSize()) {
797         buf.resize(GetSize());
798     }
799 
800     GetHeaderBinary(buf);
801     uint8_t *p = buf.data() + GetHeaderSize();
802 
803     auto pDest = reinterpret_cast<PerfRecordItraceStartData *>(p);
804     *pDest = data_;
805     return true;
806 }
807 
DumpData(int indent) const808 void PerfRecordItraceStart::DumpData(int indent) const
809 {
810     PrintIndent(indent, "pid %u, tid %u\n", data_.pid, data_.tid);
811 }
812 
PerfRecordLostSamples(uint8_t * p)813 PerfRecordLostSamples::PerfRecordLostSamples(uint8_t *p) : PerfEventRecord(p, "lostSamples")
814 {
815     size_t copySize = GetSize() - sizeof(header);
816     if (memcpy_s((uint8_t *)&data_, sizeof(data_), p + sizeof(header), copySize) != 0) {
817         HLOGE("memcpy_s retren failed !!!");
818     }
819 }
820 
GetBinary(std::vector<uint8_t> & buf) const821 bool PerfRecordLostSamples::GetBinary(std::vector<uint8_t> &buf) const
822 {
823     if (buf.size() < GetSize()) {
824         buf.resize(GetSize());
825     }
826 
827     GetHeaderBinary(buf);
828     uint8_t *p = buf.data() + GetHeaderSize();
829 
830     auto pDest = reinterpret_cast<PerfRecordLostSamplesData *>(p);
831     *pDest = data_;
832     return true;
833 }
834 
DumpData(int indent) const835 void PerfRecordLostSamples::DumpData(int indent) const
836 {
837     PrintIndent(indent, "lost %llu\n", data_.lost);
838 }
839 
PerfRecordSwitch(uint8_t * p)840 PerfRecordSwitch::PerfRecordSwitch(uint8_t *p) : PerfEventRecord(p, "switch")
841 {
842     size_t copySize = GetSize() - sizeof(header);
843     if (memcpy_s((uint8_t *)&data_, sizeof(data_), p + sizeof(header), copySize) != 0) {
844         HLOGE("memcpy_s retren failed !!!");
845     }
846 }
847 
GetBinary(std::vector<uint8_t> & buf) const848 bool PerfRecordSwitch::GetBinary(std::vector<uint8_t> &buf) const
849 {
850     if (buf.size() < GetSize()) {
851         buf.resize(GetSize());
852     }
853 
854     GetHeaderBinary(buf);
855     uint8_t *p = buf.data() + GetHeaderSize();
856 
857     auto pDest = reinterpret_cast<PerfRecordSwitchData *>(p);
858     *pDest = data_;
859     return true;
860 }
861 
PerfRecordSwitchCpuWide(uint8_t * p)862 PerfRecordSwitchCpuWide::PerfRecordSwitchCpuWide(uint8_t *p) : PerfEventRecord(p, "switchCpuWide")
863 {
864     size_t copySize = GetSize() - sizeof(header);
865     if (memcpy_s((uint8_t *)&data_, sizeof(data_), p + sizeof(header), copySize) != 0) {
866         HLOGE("memcpy_s retren failed !!!");
867     }
868 }
869 
GetBinary(std::vector<uint8_t> & buf) const870 bool PerfRecordSwitchCpuWide::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<PerfRecordSwitchCpuWideData *>(p);
880     *pDest = data_;
881     return true;
882 }
883 
DumpData(int indent) const884 void PerfRecordSwitchCpuWide::DumpData(int indent) const
885 {
886     PrintIndent(indent, "next_prev_pid %u, next_prev_tid %u\n", data_.next_prev_pid,
887                 data_.next_prev_tid);
888 }
889 } // namespace HiPerf
890 } // namespace Developtools
891 } // namespace OHOS
892