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