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