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,std::string outputFilename) const141 void PerfEventRecord::Dump(int indent, std::string outputFilename) const
142 {
143 if (!outputFilename.empty() && outputDump_ == nullptr) {
144 std::string resolvedPath = CanonicalizeSpecPath(outputFilename.c_str());
145 outputDump_ = fopen(resolvedPath.c_str(), "w");
146 if (outputDump_ == nullptr) {
147 printf("unable open file to '%s' because '%d'\n", outputFilename.c_str(), errno);
148 return;
149 }
150 }
151 PrintIndent(indent, "\n");
152 PrintIndent(indent, "record %s: type %u, misc %u, size %zu\n", GetName().c_str(), GetType(),
153 GetMisc(), GetSize());
154 DumpData(indent + 1);
155 }
156
DumpLog(const std::string & prefix) const157 void PerfEventRecord::DumpLog(const std::string &prefix) const
158 {
159 HLOGV("%s: record %s: type %u, misc %u, size %zu\n", prefix.c_str(), GetName().c_str(),
160 GetType(), GetMisc(), GetSize());
161 }
162
DumpLog(const std::string & prefix) const163 void PerfRecordSample::DumpLog(const std::string &prefix) const
164 {
165 HLOGV("%s: SAMPLE: id= %llu size %d pid %u tid %u ips %llu regs %llu, stacks %llu time %llu",
166 prefix.c_str(), data_.sample_id, header.size, data_.pid, data_.tid, data_.nr,
167 data_.reg_nr, data_.dyn_size, data_.time);
168 }
169
ReplaceWithCallStack(size_t originalSize)170 void PerfRecordSample::ReplaceWithCallStack(size_t originalSize)
171 {
172 // first we check if we have some user unwind stack need to merge ?
173 if (callFrames_.size() != 0) {
174 // when we have some kernel ips , we cp it first
175 // new size is user call frames + kernel call frames
176 // + PERF_CONTEXT_USER(last + 1) + expand mark(also PERF_CONTEXT_USER)
177 const unsigned int perfContextSize = 2;
178 ips_.reserve(data_.nr + callFrames_.size() + perfContextSize);
179 if (data_.nr > 0) {
180 ips_.assign(data_.ips, data_.ips + data_.nr);
181 }
182 // add user context mark
183 ips_.emplace_back(PERF_CONTEXT_USER);
184 // we also need make a expand mark just for debug only
185 const size_t beginIpsSize = ips_.size();
186 bool ret = std::all_of(callFrames_.begin(), callFrames_.end(), [&](const CallFrame &frame) {
187 ips_.emplace_back(frame.ip_);
188 if (originalSize != 0 and (originalSize != callFrames_.size()) and
189 ips_.size() == (originalSize + beginIpsSize)) {
190 // just for debug
191 // so we can see which frame begin is expand call frames
192 ips_.emplace_back(PERF_CONTEXT_USER);
193 }
194 return true;
195 });
196 if (ret) {
197 HLOGV("combed %zu", callFrames_.size());
198 } else {
199 HLOGV("failed to combed %zu", callFrames_.size());
200 }
201
202 if (sampleType_ & PERF_SAMPLE_REGS_USER) {
203 data_.reg_nr = 0;
204 header.size -= data_.reg_nr * sizeof(u64);
205 }
206
207 if (sampleType_ & PERF_SAMPLE_STACK_USER) {
208 // 1. remove the user stack
209 header.size -= data_.stack_size;
210
211 // 2. clean the size
212 data_.user_abi = 0;
213 data_.stack_size = 0;
214 data_.dyn_size = 0;
215 }
216
217 if (sampleType_ & PERF_SAMPLE_CALLCHAIN) {
218 HLOGV("ips change from %llu -> %zu", data_.nr, ips_.size());
219
220 // 3. remove the nr size
221 header.size -= data_.nr * sizeof(u64);
222
223 // 4. add new nr size
224 data_.nr = ips_.size();
225 header.size += data_.nr * sizeof(u64);
226
227 // 5. change ips potin to our ips array and hold it.
228 data_.ips = ips_.data();
229 }
230 } else {
231 // nothing need change
232 return;
233 }
234 }
235
PerfRecordSample(uint8_t * p,const perf_event_attr & attr)236 PerfRecordSample::PerfRecordSample(uint8_t *p, const perf_event_attr &attr)
237 : PerfEventRecord(p, "sample")
238 {
239 if (p == nullptr) {
240 HLOG_ASSERT(p);
241 return;
242 }
243 sampleType_ = attr.sample_type;
244
245 p += sizeof(header);
246
247 // parse record according SAMPLE_TYPE
248 PopFromBinary(sampleType_ & PERF_SAMPLE_IDENTIFIER, p, data_.sample_id);
249 PopFromBinary(sampleType_ & PERF_SAMPLE_IP, p, data_.ip);
250 PopFromBinary2(sampleType_ & PERF_SAMPLE_TID, p, data_.pid, data_.tid);
251 PopFromBinary(sampleType_ & PERF_SAMPLE_TIME, p, data_.time);
252 PopFromBinary(sampleType_ & PERF_SAMPLE_ADDR, p, data_.addr);
253 PopFromBinary(sampleType_ & PERF_SAMPLE_ID, p, data_.id);
254 PopFromBinary(sampleType_ & PERF_SAMPLE_STREAM_ID, p, data_.stream_id);
255 PopFromBinary2(sampleType_ & PERF_SAMPLE_CPU, p, data_.cpu, data_.res);
256 PopFromBinary(sampleType_ & PERF_SAMPLE_PERIOD, p, data_.period);
257 PopFromBinary(sampleType_ & PERF_SAMPLE_CALLCHAIN, p, data_.nr);
258 if (data_.nr > 0) {
259 // the pointer is from input(p), require caller keep input(p) with *this together
260 // think it in next time
261 data_.ips = reinterpret_cast<u64 *>(p);
262 p += data_.nr * sizeof(u64);
263 }
264 PopFromBinary(sampleType_ & PERF_SAMPLE_RAW, p, data_.raw_size);
265 if (data_.raw_size > 0) {
266 data_.raw_data = p;
267 p += data_.raw_size * sizeof(u8);
268 }
269 PopFromBinary(sampleType_ & PERF_SAMPLE_BRANCH_STACK, p, data_.bnr);
270 if (data_.bnr > 0) {
271 data_.lbr = reinterpret_cast<perf_branch_entry *>(p);
272 p += data_.bnr * sizeof(perf_branch_entry);
273 }
274 PopFromBinary(sampleType_ & PERF_SAMPLE_REGS_USER, p, data_.user_abi);
275 if (data_.user_abi > 0) {
276 data_.reg_mask = attr.sample_regs_user;
277 data_.reg_nr = __builtin_popcountll(data_.reg_mask);
278 data_.user_regs = reinterpret_cast<u64 *>(p);
279 p += data_.reg_nr * sizeof(u64);
280 }
281 PopFromBinary(sampleType_ & PERF_SAMPLE_STACK_USER, p, data_.stack_size);
282 if (data_.stack_size > 0) {
283 data_.stack_data = p;
284 p += data_.stack_size;
285 PopFromBinary(true, p, data_.dyn_size);
286 }
287 }
288
GetBinary(std::vector<uint8_t> & buf) const289 bool PerfRecordSample::GetBinary(std::vector<uint8_t> &buf) const
290 {
291 if (buf.size() < GetSize()) {
292 buf.resize(GetSize());
293 }
294
295 GetHeaderBinary(buf);
296 uint8_t *p = buf.data() + GetHeaderSize();
297
298 PushToBinary(sampleType_ & PERF_SAMPLE_IDENTIFIER, p, data_.sample_id);
299 PushToBinary(sampleType_ & PERF_SAMPLE_IP, p, data_.ip);
300 PushToBinary2(sampleType_ & PERF_SAMPLE_TID, p, data_.pid, data_.tid);
301 PushToBinary(sampleType_ & PERF_SAMPLE_TIME, p, data_.time);
302 PushToBinary(sampleType_ & PERF_SAMPLE_ADDR, p, data_.addr);
303 PushToBinary(sampleType_ & PERF_SAMPLE_ID, p, data_.id);
304 PushToBinary(sampleType_ & PERF_SAMPLE_STREAM_ID, p, data_.stream_id);
305 PushToBinary2(sampleType_ & PERF_SAMPLE_CPU, p, data_.cpu, data_.res);
306 PushToBinary(sampleType_ & PERF_SAMPLE_PERIOD, p, data_.period);
307 PushToBinary(sampleType_ & PERF_SAMPLE_CALLCHAIN, p, data_.nr);
308 if (data_.nr > 0) {
309 std::copy(data_.ips, data_.ips + data_.nr, reinterpret_cast<u64 *>(p));
310 p += data_.nr * sizeof(u64);
311 }
312 PushToBinary(sampleType_ & PERF_SAMPLE_RAW, p, data_.raw_size);
313 if (data_.raw_size > 0) {
314 std::copy(data_.raw_data, data_.raw_data + data_.raw_size, p);
315 p += data_.raw_size * sizeof(u8);
316 }
317 PushToBinary(sampleType_ & PERF_SAMPLE_BRANCH_STACK, p, data_.bnr);
318 if (data_.bnr > 0) {
319 std::copy(data_.lbr, data_.lbr + data_.bnr, reinterpret_cast<perf_branch_entry *>(p));
320 p += data_.bnr * sizeof(perf_branch_entry);
321 }
322 PushToBinary(sampleType_ & PERF_SAMPLE_REGS_USER, p, data_.user_abi);
323 if (data_.user_abi > 0 && data_.reg_nr > 0) {
324 std::copy(data_.user_regs, data_.user_regs + data_.reg_nr, reinterpret_cast<u64 *>(p));
325 p += data_.reg_nr * sizeof(u64);
326 }
327 PushToBinary(sampleType_ & PERF_SAMPLE_STACK_USER, p, data_.stack_size);
328 if (data_.stack_size > 0) {
329 std::copy(data_.stack_data, data_.stack_data + data_.stack_size, p);
330 p += data_.stack_size * sizeof(u8);
331 PushToBinary(true, p, data_.dyn_size);
332 }
333
334 return true;
335 }
336
DumpData(int indent) const337 void PerfRecordSample::DumpData(int indent) const
338 {
339 PrintIndent(indent, "sample_type: 0x%" PRIx64 "\n", sampleType_);
340
341 // dump record according sampleType
342 if (sampleType_ & (PERF_SAMPLE_ID | PERF_SAMPLE_IDENTIFIER)) {
343 PrintIndent(indent, "ID %" PRIu64 "\n", static_cast<uint64_t>(data_.sample_id));
344 }
345 if (sampleType_ & PERF_SAMPLE_IP) {
346 PrintIndent(indent, "ip %llx\n", data_.ip);
347 }
348 if (sampleType_ & PERF_SAMPLE_TID) {
349 PrintIndent(indent, "pid %u, tid %u\n", data_.pid, data_.tid);
350 }
351 if (sampleType_ & PERF_SAMPLE_TIME) {
352 PrintIndent(indent, "time %llu\n", data_.time);
353 }
354 if (sampleType_ & PERF_SAMPLE_ADDR) {
355 PrintIndent(indent, "addr %p\n", reinterpret_cast<void *>(data_.addr));
356 }
357 if (sampleType_ & PERF_SAMPLE_STREAM_ID) {
358 PrintIndent(indent, "stream_id %" PRIu64 "\n", static_cast<uint64_t>(data_.stream_id));
359 }
360 if (sampleType_ & PERF_SAMPLE_CPU) {
361 PrintIndent(indent, "cpu %u, res %u\n", data_.cpu, data_.res);
362 }
363 if (sampleType_ & PERF_SAMPLE_PERIOD) {
364 PrintIndent(indent, "period %" PRIu64 "\n", static_cast<uint64_t>(data_.period));
365 }
366 if (sampleType_ & PERF_SAMPLE_CALLCHAIN) {
367 bool userContext = false;
368 PrintIndent(indent, "callchain nr=%lld\n", data_.nr);
369 for (uint64_t i = 0; i < data_.nr; ++i) {
370 std::string_view supplement = "";
371 if ((sampleType_ & PERF_SAMPLE_STACK_USER) == 0 || data_.ips[i] != PERF_CONTEXT_USER) {
372 PrintIndent(indent + 1, "0x%llx%s\n", data_.ips[i], supplement.data());
373 continue;
374 }
375 // is PERF_SAMPLE_STACK_USER type and is PERF_CONTEXT_USER
376 if (!userContext) {
377 userContext = true;
378 supplement = " <unwind callstack>";
379 } else {
380 supplement = " <expand callstack>";
381 }
382 PrintIndent(indent + 1, "0x%llx%s\n", data_.ips[i], supplement.data());
383 }
384 }
385 if (sampleType_ & PERF_SAMPLE_RAW) {
386 PrintIndent(indent, "raw size=%u\n", data_.raw_size);
387 const uint32_t *data = reinterpret_cast<const uint32_t *>(data_.raw_data);
388 size_t size = data_.raw_size / sizeof(uint32_t);
389 for (size_t i = 0; i < size; ++i) {
390 PrintIndent(indent + 1, "0x%08x (%x)\n", data[i], data[i]);
391 }
392 }
393 if (sampleType_ & PERF_SAMPLE_BRANCH_STACK) {
394 PrintIndent(indent, "branch_stack nr=%lld\n", data_.bnr);
395 for (uint64_t i = 0; i < data_.bnr; ++i) {
396 auto &item = data_.lbr[i];
397 PrintIndent(indent + 1, "from 0x%llx, to 0x%llx %s%s\n", item.from, item.to,
398 item.mispred ? "mispred" : "", item.predicted ? "predicted" : "");
399 }
400 }
401 if (sampleType_ & PERF_SAMPLE_REGS_USER) {
402 PrintIndent(indent, "user regs: abi=%lld, reg_nr=%lld\n", data_.user_abi, data_.reg_nr);
403 for (uint64_t i = 0; i < data_.reg_nr; ++i) {
404 PrintIndent(indent + 1, "0x%llx\n", data_.user_regs[i]);
405 }
406 }
407 if (sampleType_ & PERF_SAMPLE_STACK_USER) {
408 PrintIndent(indent, "user stack: size %llu dyn_size %lld\n", data_.stack_size,
409 data_.dyn_size);
410 }
411 }
412
GetPid() const413 inline pid_t PerfRecordSample::GetPid() const
414 {
415 return data_.pid;
416 }
417
PerfRecordMmap(uint8_t * p)418 PerfRecordMmap::PerfRecordMmap(uint8_t *p) : PerfEventRecord(p, "mmap")
419 {
420 size_t copySize = GetSize() - sizeof(header);
421 if (memcpy_s((uint8_t *)&data_, sizeof(data_), p + sizeof(header), copySize) != 0) {
422 HLOGE("memcpy_s retren failed !!!");
423 }
424 }
425
PerfRecordMmap(bool inKernel,u32 pid,u32 tid,u64 addr,u64 len,u64 pgoff,const std::string & filename)426 PerfRecordMmap::PerfRecordMmap(bool inKernel, u32 pid, u32 tid, u64 addr, u64 len, u64 pgoff,
427 const std::string &filename)
428 : PerfEventRecord(PERF_RECORD_MMAP, inKernel, "mmap")
429 {
430 data_.pid = pid;
431 data_.tid = tid;
432 data_.addr = addr;
433 data_.len = len;
434 data_.pgoff = pgoff;
435 if (strncpy_s(data_.filename, KILO, filename.c_str(), filename.size()) != 0) {
436 HLOGE("strncpy_s failed");
437 }
438
439 header.size = sizeof(header) + sizeof(data_) - KILO + filename.size() + 1;
440 }
441
GetBinary(std::vector<uint8_t> & buf) const442 bool PerfRecordMmap::GetBinary(std::vector<uint8_t> &buf) const
443 {
444 if (buf.size() < GetSize()) {
445 buf.resize(GetSize());
446 }
447
448 GetHeaderBinary(buf);
449 uint8_t *p = buf.data() + GetHeaderSize();
450
451 // data_.filename[] is variable-length
452 std::copy((uint8_t *)&data_, (uint8_t *)&data_ + GetSize() - GetHeaderSize(), p);
453 return true;
454 }
455
DumpData(int indent) const456 void PerfRecordMmap::DumpData(int indent) const
457 {
458 PrintIndent(indent, "pid %u, tid %u, addr 0x%llx, len 0x%llx\n", data_.pid, data_.tid,
459 data_.addr, data_.len);
460 PrintIndent(indent, "pgoff 0x%llx, filename %s\n", data_.pgoff, data_.filename);
461 }
462
DumpLog(const std::string & prefix) const463 void PerfRecordMmap::DumpLog(const std::string &prefix) const
464 {
465 HLOGV("%s: MMAP: size %d pid %u tid %u dso '%s' (0x%llx-0x%llx)@0x%llx", prefix.c_str(),
466 header.size, data_.pid, data_.tid, data_.filename, data_.addr, data_.addr + data_.len,
467 data_.pgoff);
468 }
469
PerfRecordMmap2(uint8_t * p)470 PerfRecordMmap2::PerfRecordMmap2(uint8_t *p) : PerfEventRecord(p, "mmap2")
471 {
472 size_t copySize = GetSize() - sizeof(header);
473 if (memcpy_s((uint8_t *)&data_, sizeof(data_), p + sizeof(header), copySize) != 0) {
474 HLOGE("memcpy_s retren failed !!!");
475 }
476 }
477
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)478 PerfRecordMmap2::PerfRecordMmap2(bool inKernel, u32 pid, u32 tid, u64 addr, u64 len, u64 pgoff,
479 u32 maj, u32 min, u64 ino, u32 prot, u32 flags,
480 const std::string &filename)
481 : PerfEventRecord(PERF_RECORD_MMAP2, inKernel, "mmap2")
482 {
483 data_.pid = pid;
484 data_.tid = tid;
485 data_.addr = addr;
486 data_.len = len;
487 data_.pgoff = pgoff;
488 data_.maj = maj;
489 data_.min = min;
490 data_.ino = ino;
491 data_.ino_generation = 0;
492 data_.prot = prot;
493 data_.flags = flags;
494 if (strncpy_s(data_.filename, KILO, filename.c_str(), filename.size()) != 0) {
495 HLOGE("strncpy_s failed");
496 }
497
498 header.size = sizeof(header) + sizeof(data_) - KILO + filename.size() + 1;
499 }
500
PerfRecordMmap2(bool inKernel,u32 pid,u32 tid,const MemMapItem & item)501 PerfRecordMmap2::PerfRecordMmap2(bool inKernel, u32 pid, u32 tid, const MemMapItem &item)
502 : PerfEventRecord(PERF_RECORD_MMAP2, inKernel, "mmap2")
503 {
504 data_.pid = pid;
505 data_.tid = tid;
506 data_.addr = item.begin_;
507 data_.len = item.end_ - item.begin_;
508 data_.pgoff = item.pageoffset_;
509 data_.maj = item.major_;
510 data_.min = item.minor_;
511 data_.ino = item.inode;
512 data_.ino_generation = 0;
513 data_.prot = item.type_;
514 data_.flags = item.flags;
515 if (strncpy_s(data_.filename, KILO, item.name_.c_str(), item.name_.size()) != 0) {
516 HLOGE("strncpy_s failed");
517 }
518
519 header.size = sizeof(header) + sizeof(data_) - KILO + item.name_.size() + 1;
520 }
521
GetBinary(std::vector<uint8_t> & buf) const522 bool PerfRecordMmap2::GetBinary(std::vector<uint8_t> &buf) const
523 {
524 if (buf.size() < GetSize()) {
525 buf.resize(GetSize());
526 }
527
528 GetHeaderBinary(buf);
529 uint8_t *p = buf.data() + GetHeaderSize();
530
531 // data_.filename[] is variable-length
532 std::copy((uint8_t *)&data_, (uint8_t *)&data_ + GetSize() - GetHeaderSize(), p);
533 return true;
534 }
535
DumpData(int indent) const536 void PerfRecordMmap2::DumpData(int indent) const
537 {
538 PrintIndent(indent, "pid %u, tid %u, addr 0x%llx, len 0x%llx\n", data_.pid, data_.tid,
539 data_.addr, data_.len);
540 PrintIndent(indent, "pgoff 0x%llx, maj %u, min %u, ino %llu, ino_generation %llu\n",
541 data_.pgoff, data_.maj, data_.min, data_.ino, data_.ino_generation);
542 PrintIndent(indent, "prot %u, flags %u, filename %s\n", data_.prot, data_.flags,
543 data_.filename);
544 }
DumpLog(const std::string & prefix) const545 void PerfRecordMmap2::DumpLog(const std::string &prefix) const
546 {
547 HLOGV("%s: MMAP2: size %d pid %u tid %u dso '%s' (0x%llx-0x%llx)@0x%llx", prefix.c_str(),
548 header.size, data_.pid, data_.tid, data_.filename, data_.addr, data_.addr + data_.len,
549 data_.pgoff);
550 }
551
PerfRecordLost(uint8_t * p)552 PerfRecordLost::PerfRecordLost(uint8_t *p) : PerfEventRecord(p, "lost")
553 {
554 size_t copySize = GetSize() - sizeof(header);
555 if (memcpy_s((uint8_t *)&data_, sizeof(data_), p + sizeof(header), copySize) != 0) {
556 HLOGE("memcpy_s retren failed !!!");
557 }
558 }
559
GetBinary(std::vector<uint8_t> & buf) const560 bool PerfRecordLost::GetBinary(std::vector<uint8_t> &buf) const
561 {
562 if (buf.size() < GetSize()) {
563 buf.resize(GetSize());
564 }
565
566 GetHeaderBinary(buf);
567 uint8_t *p = buf.data() + GetHeaderSize();
568
569 auto pDest = reinterpret_cast<PerfRecordLostData *>(p);
570 *pDest = data_;
571
572 return true;
573 }
574
DumpData(int indent) const575 void PerfRecordLost::DumpData(int indent) const
576 {
577 PrintIndent(indent, "id %llu, lost %llu\n", data_.id, data_.lost);
578 }
579
PerfRecordComm(uint8_t * p)580 PerfRecordComm::PerfRecordComm(uint8_t *p) : PerfEventRecord(p, "comm")
581 {
582 size_t copySize = GetSize() - sizeof(header);
583 if (memcpy_s((uint8_t *)&data_, sizeof(data_), p + sizeof(header), copySize) != 0) {
584 HLOGE("memcpy_s retren failed !!!");
585 }
586 }
587
PerfRecordComm(bool inKernel,u32 pid,u32 tid,const std::string & comm)588 PerfRecordComm::PerfRecordComm(bool inKernel, u32 pid, u32 tid, const std::string &comm)
589 : PerfEventRecord(PERF_RECORD_COMM, inKernel, "comm")
590 {
591 data_.pid = pid;
592 data_.tid = tid;
593 if (strncpy_s(data_.comm, KILO, comm.c_str(), comm.size()) != 0) {
594 HLOGE("strncpy_s failed !!!");
595 }
596
597 header.size = sizeof(header) + sizeof(data_) - KILO + comm.size() + 1;
598 }
599
GetBinary(std::vector<uint8_t> & buf) const600 bool PerfRecordComm::GetBinary(std::vector<uint8_t> &buf) const
601 {
602 if (buf.size() < GetSize()) {
603 buf.resize(GetSize());
604 }
605
606 GetHeaderBinary(buf);
607 uint8_t *p = buf.data() + GetHeaderSize();
608
609 // data_.comm[] is variable-length
610 std::copy((uint8_t *)&data_, (uint8_t *)&data_ + GetSize() - GetHeaderSize(), p);
611
612 return true;
613 }
614
DumpData(int indent) const615 void PerfRecordComm::DumpData(int indent) const
616 {
617 PrintIndent(indent, "pid %u, tid %u, comm %s\n", data_.pid, data_.tid, data_.comm);
618 }
619
DumpLog(const std::string & prefix) const620 void PerfRecordComm::DumpLog(const std::string &prefix) const
621 {
622 HLOGV("pid %u, tid %u, comm %s\n", data_.pid, data_.tid, data_.comm);
623 }
624
PerfRecordExit(uint8_t * p)625 PerfRecordExit::PerfRecordExit(uint8_t *p) : PerfEventRecord(p, "exit")
626 {
627 size_t copySize = GetSize() - sizeof(header);
628 if (memcpy_s((uint8_t *)&data_, sizeof(data_), p + sizeof(header), copySize) != 0) {
629 HLOGE("memcpy_s retren failed !!!");
630 }
631 }
632
GetBinary(std::vector<uint8_t> & buf) const633 bool PerfRecordExit::GetBinary(std::vector<uint8_t> &buf) const
634 {
635 if (buf.size() < GetSize()) {
636 buf.resize(GetSize());
637 }
638
639 GetHeaderBinary(buf);
640 uint8_t *p = buf.data() + GetHeaderSize();
641
642 auto pDest = reinterpret_cast<PerfRecordExitData *>(p);
643 *pDest = data_;
644 return true;
645 }
646
DumpData(int indent) const647 void PerfRecordExit::DumpData(int indent) const
648 {
649 PrintIndent(indent, "pid %u, ppid %u, tid %u, ptid %u time 0x%llx\n", data_.pid, data_.ppid,
650 data_.tid, data_.ptid, data_.time);
651 }
652
PerfRecordThrottle(uint8_t * p)653 PerfRecordThrottle::PerfRecordThrottle(uint8_t *p) : PerfEventRecord(p, "throttle")
654 {
655 size_t copySize = GetSize() - sizeof(header);
656 if (memcpy_s((uint8_t *)&data_, sizeof(data_), p + sizeof(header), copySize) != 0) {
657 HLOGE("memcpy_s retren failed !!!");
658 }
659 }
660
GetBinary(std::vector<uint8_t> & buf) const661 bool PerfRecordThrottle::GetBinary(std::vector<uint8_t> &buf) const
662 {
663 if (buf.size() < GetSize()) {
664 buf.resize(GetSize());
665 }
666
667 GetHeaderBinary(buf);
668 uint8_t *p = buf.data() + GetHeaderSize();
669
670 auto pDest = reinterpret_cast<PerfRecordThrottleData *>(p);
671 *pDest = data_;
672 return true;
673 }
674
DumpData(int indent) const675 void PerfRecordThrottle::DumpData(int indent) const
676 {
677 PrintIndent(indent, "time 0x%llx, id %llx, stream_id %llx\n", data_.time, data_.id,
678 data_.stream_id);
679 }
680
PerfRecordUnthrottle(uint8_t * p)681 PerfRecordUnthrottle::PerfRecordUnthrottle(uint8_t *p) : PerfEventRecord(p, "unthrottle")
682 {
683 size_t copySize = GetSize() - sizeof(header);
684 if (memcpy_s((uint8_t *)&data_, sizeof(data_), p + sizeof(header), copySize) != 0) {
685 HLOGE("memcpy_s retren failed !!!");
686 }
687 }
688
GetBinary(std::vector<uint8_t> & buf) const689 bool PerfRecordUnthrottle::GetBinary(std::vector<uint8_t> &buf) const
690 {
691 if (buf.size() < GetSize()) {
692 buf.resize(GetSize());
693 }
694
695 GetHeaderBinary(buf);
696 uint8_t *p = buf.data() + GetHeaderSize();
697
698 auto pDest = reinterpret_cast<PerfRecordThrottleData *>(p);
699 *pDest = data_;
700 return true;
701 }
DumpData(int indent) const702 void PerfRecordUnthrottle::DumpData(int indent) const
703 {
704 PrintIndent(indent, "time 0x%llx, id %llx, stream_id %llx\n", data_.time, data_.id,
705 data_.stream_id);
706 }
707
PerfRecordFork(uint8_t * p)708 PerfRecordFork::PerfRecordFork(uint8_t *p) : PerfEventRecord(p, "fork")
709 {
710 size_t copySize = GetSize() - sizeof(header);
711 if (memcpy_s((uint8_t *)&data_, sizeof(data_), p + sizeof(header), copySize) != 0) {
712 HLOGE("memcpy_s retren failed !!!");
713 }
714 }
715
GetBinary(std::vector<uint8_t> & buf) const716 bool PerfRecordFork::GetBinary(std::vector<uint8_t> &buf) const
717 {
718 if (buf.size() < GetSize()) {
719 buf.resize(GetSize());
720 }
721
722 GetHeaderBinary(buf);
723 uint8_t *p = buf.data() + GetHeaderSize();
724
725 auto pDest = reinterpret_cast<PerfRecordForkData *>(p);
726 *pDest = data_;
727 return true;
728 }
729
DumpData(int indent) const730 void PerfRecordFork::DumpData(int indent) const
731 {
732 PrintIndent(indent, "pid %u, ppid %u, tid %u, ptid %u\n", data_.pid, data_.ppid, data_.tid,
733 data_.ptid);
734 }
735
PerfRecordRead(uint8_t * p)736 PerfRecordRead::PerfRecordRead(uint8_t *p) : PerfEventRecord(p, "read")
737 {
738 size_t copySize = GetSize() - sizeof(header);
739 if (memcpy_s((uint8_t *)&data_, sizeof(data_), p + sizeof(header), copySize) != 0) {
740 HLOGE("memcpy_s retren failed !!!");
741 }
742 }
743
GetBinary(std::vector<uint8_t> & buf) const744 bool PerfRecordRead::GetBinary(std::vector<uint8_t> &buf) const
745 {
746 if (buf.size() < GetSize()) {
747 buf.resize(GetSize());
748 }
749
750 GetHeaderBinary(buf);
751 uint8_t *p = buf.data() + GetHeaderSize();
752
753 auto pDest = reinterpret_cast<PerfRecordReadData *>(p);
754 *pDest = data_;
755 return true;
756 }
757
DumpData(int indent) const758 void PerfRecordRead::DumpData(int indent) const
759 {
760 PrintIndent(indent, "pid %u, tid %u\n", data_.pid, data_.tid);
761 PrintIndent(indent, "values: value %llx, time_enabled %llx, time_running %llx, id %llx\n",
762 data_.values.value, data_.values.time_enabled, data_.values.time_running,
763 data_.values.id);
764 }
765
PerfRecordAux(uint8_t * p)766 PerfRecordAux::PerfRecordAux(uint8_t *p) : PerfEventRecord(p, "aux")
767 {
768 size_t copySize = GetSize() - sizeof(header);
769 if (memcpy_s((uint8_t *)&data_, sizeof(data_), p + sizeof(header), copySize) != 0) {
770 HLOGE("memcpy_s retren failed !!!");
771 }
772 }
773
GetBinary(std::vector<uint8_t> & buf) const774 bool PerfRecordAux::GetBinary(std::vector<uint8_t> &buf) const
775 {
776 if (buf.size() < GetSize()) {
777 buf.resize(GetSize());
778 }
779
780 GetHeaderBinary(buf);
781 uint8_t *p = buf.data() + GetHeaderSize();
782
783 auto pDest = reinterpret_cast<PerfRecordAuxData *>(p);
784 *pDest = data_;
785 return true;
786 }
787
DumpData(int indent) const788 void PerfRecordAux::DumpData(int indent) const
789 {
790 PrintIndent(indent, "aux_offset %llx, aux_size %llx, flags %llx\n", data_.aux_offset,
791 data_.aux_size, data_.flags);
792 }
793
PerfRecordItraceStart(uint8_t * p)794 PerfRecordItraceStart::PerfRecordItraceStart(uint8_t *p) : PerfEventRecord(p, "itraceStart")
795 {
796 size_t copySize = GetSize() - sizeof(header);
797 if (memcpy_s((uint8_t *)&data_, sizeof(data_), p + sizeof(header), copySize) != 0) {
798 HLOGE("memcpy_s retren failed !!!");
799 }
800 }
801
GetBinary(std::vector<uint8_t> & buf) const802 bool PerfRecordItraceStart::GetBinary(std::vector<uint8_t> &buf) const
803 {
804 if (buf.size() < GetSize()) {
805 buf.resize(GetSize());
806 }
807
808 GetHeaderBinary(buf);
809 uint8_t *p = buf.data() + GetHeaderSize();
810
811 auto pDest = reinterpret_cast<PerfRecordItraceStartData *>(p);
812 *pDest = data_;
813 return true;
814 }
815
DumpData(int indent) const816 void PerfRecordItraceStart::DumpData(int indent) const
817 {
818 PrintIndent(indent, "pid %u, tid %u\n", data_.pid, data_.tid);
819 }
820
PerfRecordLostSamples(uint8_t * p)821 PerfRecordLostSamples::PerfRecordLostSamples(uint8_t *p) : PerfEventRecord(p, "lostSamples")
822 {
823 size_t copySize = GetSize() - sizeof(header);
824 if (memcpy_s((uint8_t *)&data_, sizeof(data_), p + sizeof(header), copySize) != 0) {
825 HLOGE("memcpy_s retren failed !!!");
826 }
827 }
828
GetBinary(std::vector<uint8_t> & buf) const829 bool PerfRecordLostSamples::GetBinary(std::vector<uint8_t> &buf) const
830 {
831 if (buf.size() < GetSize()) {
832 buf.resize(GetSize());
833 }
834
835 GetHeaderBinary(buf);
836 uint8_t *p = buf.data() + GetHeaderSize();
837
838 auto pDest = reinterpret_cast<PerfRecordLostSamplesData *>(p);
839 *pDest = data_;
840 return true;
841 }
842
DumpData(int indent) const843 void PerfRecordLostSamples::DumpData(int indent) const
844 {
845 PrintIndent(indent, "lost %llu\n", data_.lost);
846 }
847
PerfRecordSwitch(uint8_t * p)848 PerfRecordSwitch::PerfRecordSwitch(uint8_t *p) : PerfEventRecord(p, "switch")
849 {
850 size_t copySize = GetSize() - sizeof(header);
851 if (memcpy_s((uint8_t *)&data_, sizeof(data_), p + sizeof(header), copySize) != 0) {
852 HLOGE("memcpy_s retren failed !!!");
853 }
854 }
855
GetBinary(std::vector<uint8_t> & buf) const856 bool PerfRecordSwitch::GetBinary(std::vector<uint8_t> &buf) const
857 {
858 if (buf.size() < GetSize()) {
859 buf.resize(GetSize());
860 }
861
862 GetHeaderBinary(buf);
863 uint8_t *p = buf.data() + GetHeaderSize();
864
865 auto pDest = reinterpret_cast<PerfRecordSwitchData *>(p);
866 *pDest = data_;
867 return true;
868 }
869
PerfRecordSwitchCpuWide(uint8_t * p)870 PerfRecordSwitchCpuWide::PerfRecordSwitchCpuWide(uint8_t *p) : PerfEventRecord(p, "switchCpuWide")
871 {
872 size_t copySize = GetSize() - sizeof(header);
873 if (memcpy_s((uint8_t *)&data_, sizeof(data_), p + sizeof(header), copySize) != 0) {
874 HLOGE("memcpy_s retren failed !!!");
875 }
876 }
877
GetBinary(std::vector<uint8_t> & buf) const878 bool PerfRecordSwitchCpuWide::GetBinary(std::vector<uint8_t> &buf) const
879 {
880 if (buf.size() < GetSize()) {
881 buf.resize(GetSize());
882 }
883
884 GetHeaderBinary(buf);
885 uint8_t *p = buf.data() + GetHeaderSize();
886
887 auto pDest = reinterpret_cast<PerfRecordSwitchCpuWideData *>(p);
888 *pDest = data_;
889 return true;
890 }
891
DumpData(int indent) const892 void PerfRecordSwitchCpuWide::DumpData(int indent) const
893 {
894 PrintIndent(indent, "next_prev_pid %u, next_prev_tid %u\n", data_.next_prev_pid,
895 data_.next_prev_tid);
896 }
897 } // namespace HiPerf
898 } // namespace Developtools
899 } // namespace OHOS
900