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