1209bc2fbSopenharmony_ci/* 2209bc2fbSopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd. 3209bc2fbSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4209bc2fbSopenharmony_ci * you may not use this file except in compliance with the License. 5209bc2fbSopenharmony_ci * You may obtain a copy of the License at 6209bc2fbSopenharmony_ci * 7209bc2fbSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8209bc2fbSopenharmony_ci * 9209bc2fbSopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10209bc2fbSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11209bc2fbSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12209bc2fbSopenharmony_ci * See the License for the specific language governing permissions and 13209bc2fbSopenharmony_ci * limitations under the License. 14209bc2fbSopenharmony_ci */ 15209bc2fbSopenharmony_ci 16209bc2fbSopenharmony_ci#include "thread_sampler.h" 17209bc2fbSopenharmony_ci 18209bc2fbSopenharmony_ci#include <atomic> 19209bc2fbSopenharmony_ci#include <condition_variable> 20209bc2fbSopenharmony_ci#include <memory> 21209bc2fbSopenharmony_ci#include <queue> 22209bc2fbSopenharmony_ci#include <set> 23209bc2fbSopenharmony_ci#include <string> 24209bc2fbSopenharmony_ci 25209bc2fbSopenharmony_ci#include <sys/mman.h> 26209bc2fbSopenharmony_ci#include <sys/prctl.h> 27209bc2fbSopenharmony_ci#include <syscall.h> 28209bc2fbSopenharmony_ci#include <csignal> 29209bc2fbSopenharmony_ci 30209bc2fbSopenharmony_ci#include "unwinder.h" 31209bc2fbSopenharmony_ci#include "dfx_regs.h" 32209bc2fbSopenharmony_ci#include "dfx_elf.h" 33209bc2fbSopenharmony_ci#include "dfx_ark.h" 34209bc2fbSopenharmony_ci#include "dfx_frame_formatter.h" 35209bc2fbSopenharmony_ci#include "sample_stack_printer.h" 36209bc2fbSopenharmony_ci#include "thread_sampler_utils.h" 37209bc2fbSopenharmony_ci#include "file_ex.h" 38209bc2fbSopenharmony_ci 39209bc2fbSopenharmony_ci#define NO_SANITIZER __attribute__((no_sanitize("address"), no_sanitize("hwaddress"))) 40209bc2fbSopenharmony_ci 41209bc2fbSopenharmony_cinamespace OHOS { 42209bc2fbSopenharmony_cinamespace HiviewDFX { 43209bc2fbSopenharmony_cistatic const int CRASH_SIGNAL_LIST[] = { 44209bc2fbSopenharmony_ci SIGILL, SIGABRT, SIGBUS, SIGFPE, 45209bc2fbSopenharmony_ci SIGSEGV, SIGSTKFLT, SIGSYS, SIGTRAP 46209bc2fbSopenharmony_ci}; 47209bc2fbSopenharmony_cistatic pthread_mutex_t mutex_ = PTHREAD_MUTEX_INITIALIZER; 48209bc2fbSopenharmony_ciconstexpr int LOCK_TIMEOUT = 10; 49209bc2fbSopenharmony_ci 50209bc2fbSopenharmony_civoid ThreadSampler::ThreadSamplerSignalHandler(int sig, siginfo_t* si, void* context) 51209bc2fbSopenharmony_ci{ 52209bc2fbSopenharmony_ci#if defined(__aarch64__) 53209bc2fbSopenharmony_ci int preErrno = errno; 54209bc2fbSopenharmony_ci int err = pthread_mutex_trylock(&mutex_); 55209bc2fbSopenharmony_ci if (err != 0) { 56209bc2fbSopenharmony_ci errno = preErrno; 57209bc2fbSopenharmony_ci return; 58209bc2fbSopenharmony_ci } 59209bc2fbSopenharmony_ci ThreadSampler::GetInstance().WriteContext(context); 60209bc2fbSopenharmony_ci pthread_mutex_unlock(&mutex_); 61209bc2fbSopenharmony_ci errno = preErrno; 62209bc2fbSopenharmony_ci#endif 63209bc2fbSopenharmony_ci} 64209bc2fbSopenharmony_ci 65209bc2fbSopenharmony_ciThreadSampler::ThreadSampler() 66209bc2fbSopenharmony_ci{ 67209bc2fbSopenharmony_ci XCOLLIE_LOGI("Create ThreadSampler.\n"); 68209bc2fbSopenharmony_ci} 69209bc2fbSopenharmony_ci 70209bc2fbSopenharmony_ciThreadSampler::~ThreadSampler() 71209bc2fbSopenharmony_ci{ 72209bc2fbSopenharmony_ci XCOLLIE_LOGI("Destroy ThreadSampler.\n"); 73209bc2fbSopenharmony_ci} 74209bc2fbSopenharmony_ci 75209bc2fbSopenharmony_ciint ThreadSampler::FindUnwindTable(uintptr_t pc, UnwindTableInfo& outTableInfo, void *arg) 76209bc2fbSopenharmony_ci{ 77209bc2fbSopenharmony_ci UnwindInfo* unwindInfo = static_cast<UnwindInfo *>(arg); 78209bc2fbSopenharmony_ci if (unwindInfo == nullptr) { 79209bc2fbSopenharmony_ci XCOLLIE_LOGE("invalid FindUnwindTable param\n"); 80209bc2fbSopenharmony_ci return -1; 81209bc2fbSopenharmony_ci } 82209bc2fbSopenharmony_ci 83209bc2fbSopenharmony_ci std::shared_ptr<DfxMap> map; 84209bc2fbSopenharmony_ci if (unwindInfo->maps->FindMapByAddr(pc, map)) { 85209bc2fbSopenharmony_ci if (map == nullptr) { 86209bc2fbSopenharmony_ci XCOLLIE_LOGE("FindUnwindTable: map is nullptr\n"); 87209bc2fbSopenharmony_ci return -1; 88209bc2fbSopenharmony_ci } 89209bc2fbSopenharmony_ci auto elf = map->GetElf(getpid()); 90209bc2fbSopenharmony_ci if (elf != nullptr) { 91209bc2fbSopenharmony_ci return elf->FindUnwindTableInfo(pc, map, outTableInfo); 92209bc2fbSopenharmony_ci } 93209bc2fbSopenharmony_ci } 94209bc2fbSopenharmony_ci return -1; 95209bc2fbSopenharmony_ci} 96209bc2fbSopenharmony_ci 97209bc2fbSopenharmony_ciint ThreadSampler::AccessMem(uintptr_t addr, uintptr_t *val, void *arg) 98209bc2fbSopenharmony_ci{ 99209bc2fbSopenharmony_ci UnwindInfo* unwindInfo = static_cast<UnwindInfo *>(arg); 100209bc2fbSopenharmony_ci if (unwindInfo == nullptr || addr + sizeof(uintptr_t) < addr) { 101209bc2fbSopenharmony_ci XCOLLIE_LOGE("invalid AccessMem param\n"); 102209bc2fbSopenharmony_ci return -1; 103209bc2fbSopenharmony_ci } 104209bc2fbSopenharmony_ci 105209bc2fbSopenharmony_ci *val = 0; 106209bc2fbSopenharmony_ci if (addr < unwindInfo->context->sp || 107209bc2fbSopenharmony_ci addr + sizeof(uintptr_t) >= unwindInfo->context->sp + STACK_BUFFER_SIZE) { 108209bc2fbSopenharmony_ci return ThreadSampler::GetInstance().AccessElfMem(addr, val); 109209bc2fbSopenharmony_ci } else { 110209bc2fbSopenharmony_ci size_t stackOffset = addr - unwindInfo->context->sp; 111209bc2fbSopenharmony_ci if (stackOffset >= STACK_BUFFER_SIZE) { 112209bc2fbSopenharmony_ci XCOLLIE_LOGE("limit stack\n"); 113209bc2fbSopenharmony_ci return -1; 114209bc2fbSopenharmony_ci } 115209bc2fbSopenharmony_ci *val = *(reinterpret_cast<uintptr_t *>(&unwindInfo->context->buffer[stackOffset])); 116209bc2fbSopenharmony_ci } 117209bc2fbSopenharmony_ci return 0; 118209bc2fbSopenharmony_ci} 119209bc2fbSopenharmony_ci 120209bc2fbSopenharmony_ciint ThreadSampler::GetMapByPc(uintptr_t pc, std::shared_ptr<DfxMap>& map, void *arg) 121209bc2fbSopenharmony_ci{ 122209bc2fbSopenharmony_ci UnwindInfo* unwindInfo = static_cast<UnwindInfo *>(arg); 123209bc2fbSopenharmony_ci if (unwindInfo == nullptr) { 124209bc2fbSopenharmony_ci XCOLLIE_LOGE("invalid GetMapByPc param\n"); 125209bc2fbSopenharmony_ci return -1; 126209bc2fbSopenharmony_ci } 127209bc2fbSopenharmony_ci 128209bc2fbSopenharmony_ci return unwindInfo->maps->FindMapByAddr(pc, map) ? 0 : -1; 129209bc2fbSopenharmony_ci} 130209bc2fbSopenharmony_ci 131209bc2fbSopenharmony_cibool ThreadSampler::Init(int collectStackCount) 132209bc2fbSopenharmony_ci{ 133209bc2fbSopenharmony_ci if (init_) { 134209bc2fbSopenharmony_ci return true; 135209bc2fbSopenharmony_ci } 136209bc2fbSopenharmony_ci 137209bc2fbSopenharmony_ci if (!InitRecordBuffer()) { 138209bc2fbSopenharmony_ci XCOLLIE_LOGE("Failed to InitRecordBuffer\n"); 139209bc2fbSopenharmony_ci Deinit(); 140209bc2fbSopenharmony_ci return false; 141209bc2fbSopenharmony_ci } 142209bc2fbSopenharmony_ci 143209bc2fbSopenharmony_ci if (!InitUnwinder()) { 144209bc2fbSopenharmony_ci XCOLLIE_LOGE("Failed to InitUnwinder\n"); 145209bc2fbSopenharmony_ci Deinit(); 146209bc2fbSopenharmony_ci return false; 147209bc2fbSopenharmony_ci } 148209bc2fbSopenharmony_ci 149209bc2fbSopenharmony_ci pid_ = getprocpid(); 150209bc2fbSopenharmony_ci if (!InitUniqueStackTable()) { 151209bc2fbSopenharmony_ci XCOLLIE_LOGE("Failed to InitUniqueStackTable\n"); 152209bc2fbSopenharmony_ci Deinit(); 153209bc2fbSopenharmony_ci return false; 154209bc2fbSopenharmony_ci } 155209bc2fbSopenharmony_ci 156209bc2fbSopenharmony_ci if (!InstallSignalHandler()) { 157209bc2fbSopenharmony_ci XCOLLIE_LOGE("Failed to InstallSignalHandler\n"); 158209bc2fbSopenharmony_ci Deinit(); 159209bc2fbSopenharmony_ci return false; 160209bc2fbSopenharmony_ci } 161209bc2fbSopenharmony_ci 162209bc2fbSopenharmony_ci if (collectStackCount <= 0) { 163209bc2fbSopenharmony_ci XCOLLIE_LOGE("Invalid collectStackCount\n"); 164209bc2fbSopenharmony_ci Deinit(); 165209bc2fbSopenharmony_ci return false; 166209bc2fbSopenharmony_ci } 167209bc2fbSopenharmony_ci stackIdCount_.reserve(collectStackCount); 168209bc2fbSopenharmony_ci 169209bc2fbSopenharmony_ci init_ = true; 170209bc2fbSopenharmony_ci return true; 171209bc2fbSopenharmony_ci} 172209bc2fbSopenharmony_ci 173209bc2fbSopenharmony_cibool ThreadSampler::InitRecordBuffer() 174209bc2fbSopenharmony_ci{ 175209bc2fbSopenharmony_ci if (mmapStart_ != MAP_FAILED) { 176209bc2fbSopenharmony_ci return true; 177209bc2fbSopenharmony_ci } 178209bc2fbSopenharmony_ci // create buffer 179209bc2fbSopenharmony_ci bufferSize_ = SAMPLER_MAX_BUFFER_SZ * sizeof(struct ThreadUnwindContext); 180209bc2fbSopenharmony_ci mmapStart_ = mmap(nullptr, bufferSize_, 181209bc2fbSopenharmony_ci PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 182209bc2fbSopenharmony_ci if (mmapStart_ == MAP_FAILED) { 183209bc2fbSopenharmony_ci XCOLLIE_LOGE("Failed to create buffer for thread sampler!(%{public}d)\n", errno); 184209bc2fbSopenharmony_ci return false; 185209bc2fbSopenharmony_ci } 186209bc2fbSopenharmony_ci 187209bc2fbSopenharmony_ci prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, mmapStart_, bufferSize_, "sampler_buf"); 188209bc2fbSopenharmony_ci return true; 189209bc2fbSopenharmony_ci} 190209bc2fbSopenharmony_ci 191209bc2fbSopenharmony_civoid ThreadSampler::ReleaseRecordBuffer() 192209bc2fbSopenharmony_ci{ 193209bc2fbSopenharmony_ci if (mmapStart_ == MAP_FAILED) { 194209bc2fbSopenharmony_ci return; 195209bc2fbSopenharmony_ci } 196209bc2fbSopenharmony_ci // release buffer 197209bc2fbSopenharmony_ci if (munmap(mmapStart_, bufferSize_) != 0) { 198209bc2fbSopenharmony_ci XCOLLIE_LOGE("Failed to release buffer!(%{public}d)\n", errno); 199209bc2fbSopenharmony_ci return; 200209bc2fbSopenharmony_ci } 201209bc2fbSopenharmony_ci mmapStart_ = MAP_FAILED; 202209bc2fbSopenharmony_ci} 203209bc2fbSopenharmony_ci 204209bc2fbSopenharmony_cibool ThreadSampler::InitUnwinder() 205209bc2fbSopenharmony_ci{ 206209bc2fbSopenharmony_ci accessors_ = std::make_shared<OHOS::HiviewDFX::UnwindAccessors>(); 207209bc2fbSopenharmony_ci accessors_->AccessReg = nullptr; 208209bc2fbSopenharmony_ci accessors_->AccessMem = &ThreadSampler::AccessMem; 209209bc2fbSopenharmony_ci accessors_->GetMapByPc = &ThreadSampler::GetMapByPc; 210209bc2fbSopenharmony_ci accessors_->FindUnwindTable = &ThreadSampler::FindUnwindTable; 211209bc2fbSopenharmony_ci unwinder_ = std::make_shared<Unwinder>(accessors_, true); 212209bc2fbSopenharmony_ci 213209bc2fbSopenharmony_ci maps_ = DfxMaps::Create(); 214209bc2fbSopenharmony_ci if (maps_ == nullptr) { 215209bc2fbSopenharmony_ci XCOLLIE_LOGE("maps is nullptr\n"); 216209bc2fbSopenharmony_ci return false; 217209bc2fbSopenharmony_ci } 218209bc2fbSopenharmony_ci if (!maps_->GetStackRange(stackBegin_, stackEnd_)) { 219209bc2fbSopenharmony_ci XCOLLIE_LOGE("Failed to get stack range\n"); 220209bc2fbSopenharmony_ci return false; 221209bc2fbSopenharmony_ci } 222209bc2fbSopenharmony_ci return true; 223209bc2fbSopenharmony_ci} 224209bc2fbSopenharmony_ci 225209bc2fbSopenharmony_cibool ThreadSampler::InitUniqueStackTable() 226209bc2fbSopenharmony_ci{ 227209bc2fbSopenharmony_ci uniqueStackTable_ = std::make_unique<UniqueStackTable>(pid_, uniqueStackTableSize_); 228209bc2fbSopenharmony_ci if (!uniqueStackTable_->Init()) { 229209bc2fbSopenharmony_ci XCOLLIE_LOGE("Failed to init unique_table\n"); 230209bc2fbSopenharmony_ci return false; 231209bc2fbSopenharmony_ci } 232209bc2fbSopenharmony_ci void* uniqueTableBufMMap = reinterpret_cast<void*>(uniqueStackTable_->GetHeadNode()); 233209bc2fbSopenharmony_ci prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, uniqueTableBufMMap, uniqueStackTableSize_, uniTableMMapName_.c_str()); 234209bc2fbSopenharmony_ci return true; 235209bc2fbSopenharmony_ci} 236209bc2fbSopenharmony_ci 237209bc2fbSopenharmony_civoid ThreadSampler::DeinitUniqueStackTable() 238209bc2fbSopenharmony_ci{ 239209bc2fbSopenharmony_ci uniqueStackTable_.reset(); 240209bc2fbSopenharmony_ci} 241209bc2fbSopenharmony_ci 242209bc2fbSopenharmony_civoid ThreadSampler::DestroyUnwinder() 243209bc2fbSopenharmony_ci{ 244209bc2fbSopenharmony_ci maps_.reset(); 245209bc2fbSopenharmony_ci DfxArk::ArkDestoryLocal(); 246209bc2fbSopenharmony_ci unwinder_.reset(); 247209bc2fbSopenharmony_ci accessors_.reset(); 248209bc2fbSopenharmony_ci} 249209bc2fbSopenharmony_ci 250209bc2fbSopenharmony_cibool ThreadSampler::InstallSignalHandler() 251209bc2fbSopenharmony_ci{ 252209bc2fbSopenharmony_ci struct sigaction action {}; 253209bc2fbSopenharmony_ci sigfillset(&action.sa_mask); 254209bc2fbSopenharmony_ci for (size_t i = 0; i < sizeof(CRASH_SIGNAL_LIST) / sizeof(CRASH_SIGNAL_LIST[0]); i++) { 255209bc2fbSopenharmony_ci sigdelset(&action.sa_mask, CRASH_SIGNAL_LIST[i]); 256209bc2fbSopenharmony_ci } 257209bc2fbSopenharmony_ci action.sa_sigaction = ThreadSampler::ThreadSamplerSignalHandler; 258209bc2fbSopenharmony_ci action.sa_flags = SA_RESTART | SA_SIGINFO; 259209bc2fbSopenharmony_ci if (sigaction(MUSL_SIGNAL_SAMPLE_STACK, &action, nullptr) != 0) { 260209bc2fbSopenharmony_ci XCOLLIE_LOGE("Failed to register signal(%{public}d:%{public}d)", MUSL_SIGNAL_SAMPLE_STACK, errno); 261209bc2fbSopenharmony_ci return false; 262209bc2fbSopenharmony_ci } 263209bc2fbSopenharmony_ci return true; 264209bc2fbSopenharmony_ci} 265209bc2fbSopenharmony_ci 266209bc2fbSopenharmony_civoid ThreadSampler::UninstallSignalHandler() 267209bc2fbSopenharmony_ci{ 268209bc2fbSopenharmony_ci if (signal(MUSL_SIGNAL_SAMPLE_STACK, SIG_IGN) == SIG_ERR) { 269209bc2fbSopenharmony_ci XCOLLIE_LOGE("Failed to unregister signal(%{public}d)", MUSL_SIGNAL_SAMPLE_STACK); 270209bc2fbSopenharmony_ci } 271209bc2fbSopenharmony_ci} 272209bc2fbSopenharmony_ci 273209bc2fbSopenharmony_ciint ThreadSampler::AccessElfMem(uintptr_t addr, uintptr_t *val) 274209bc2fbSopenharmony_ci{ 275209bc2fbSopenharmony_ci std::shared_ptr<DfxMap> map; 276209bc2fbSopenharmony_ci if (maps_->FindMapByAddr(addr, map)) { 277209bc2fbSopenharmony_ci if (map == nullptr) { 278209bc2fbSopenharmony_ci XCOLLIE_LOGE("AccessElfMem: map is nullptr\n"); 279209bc2fbSopenharmony_ci return -1; 280209bc2fbSopenharmony_ci } 281209bc2fbSopenharmony_ci auto elf = map->GetElf(getpid()); 282209bc2fbSopenharmony_ci if (elf != nullptr) { 283209bc2fbSopenharmony_ci uint64_t foff = addr - map->begin + map->offset - elf->GetBaseOffset(); 284209bc2fbSopenharmony_ci if (elf->Read(foff, val, sizeof(uintptr_t))) { 285209bc2fbSopenharmony_ci return 0; 286209bc2fbSopenharmony_ci } 287209bc2fbSopenharmony_ci } 288209bc2fbSopenharmony_ci } 289209bc2fbSopenharmony_ci return -1; 290209bc2fbSopenharmony_ci} 291209bc2fbSopenharmony_ci 292209bc2fbSopenharmony_ciThreadUnwindContext* ThreadSampler::GetReadContext() 293209bc2fbSopenharmony_ci{ 294209bc2fbSopenharmony_ci if (mmapStart_ == MAP_FAILED) { 295209bc2fbSopenharmony_ci return nullptr; 296209bc2fbSopenharmony_ci } 297209bc2fbSopenharmony_ci ThreadUnwindContext* contextArray = static_cast<ThreadUnwindContext*>(mmapStart_); 298209bc2fbSopenharmony_ci int32_t index = readIndex_; 299209bc2fbSopenharmony_ci if (contextArray[index].requestTime == 0 || contextArray[index].snapshotTime == 0) { 300209bc2fbSopenharmony_ci return nullptr; 301209bc2fbSopenharmony_ci } 302209bc2fbSopenharmony_ci 303209bc2fbSopenharmony_ci ThreadUnwindContext* ret = &contextArray[index]; 304209bc2fbSopenharmony_ci readIndex_ = (index + 1) % SAMPLER_MAX_BUFFER_SZ; 305209bc2fbSopenharmony_ci return ret; 306209bc2fbSopenharmony_ci} 307209bc2fbSopenharmony_ci 308209bc2fbSopenharmony_ciThreadUnwindContext* ThreadSampler::GetWriteContext() 309209bc2fbSopenharmony_ci{ 310209bc2fbSopenharmony_ci if (mmapStart_ == MAP_FAILED) { 311209bc2fbSopenharmony_ci return nullptr; 312209bc2fbSopenharmony_ci } 313209bc2fbSopenharmony_ci ThreadUnwindContext* contextArray = static_cast<ThreadUnwindContext*>(mmapStart_); 314209bc2fbSopenharmony_ci int32_t index = writeIndex_; 315209bc2fbSopenharmony_ci if (contextArray[index].requestTime > 0 && 316209bc2fbSopenharmony_ci (contextArray[index].snapshotTime == 0 || contextArray[index].processTime == 0)) { 317209bc2fbSopenharmony_ci return nullptr; 318209bc2fbSopenharmony_ci } 319209bc2fbSopenharmony_ci return &contextArray[index]; 320209bc2fbSopenharmony_ci} 321209bc2fbSopenharmony_ci 322209bc2fbSopenharmony_ciNO_SANITIZER void ThreadSampler::WriteContext(void* context) 323209bc2fbSopenharmony_ci{ 324209bc2fbSopenharmony_ci#if defined(__aarch64__) 325209bc2fbSopenharmony_ci if (!init_) { 326209bc2fbSopenharmony_ci return; 327209bc2fbSopenharmony_ci } 328209bc2fbSopenharmony_ci#if defined(CONSUME_STATISTICS) 329209bc2fbSopenharmony_ci uint64_t begin = GetCurrentTimeNanoseconds(); 330209bc2fbSopenharmony_ci#endif 331209bc2fbSopenharmony_ci if (mmapStart_ == MAP_FAILED) { 332209bc2fbSopenharmony_ci return; 333209bc2fbSopenharmony_ci } 334209bc2fbSopenharmony_ci ThreadUnwindContext* contextArray = static_cast<ThreadUnwindContext*>(mmapStart_); 335209bc2fbSopenharmony_ci int32_t index = writeIndex_; 336209bc2fbSopenharmony_ci#if defined(CONSUME_STATISTICS) 337209bc2fbSopenharmony_ci signalTimeCost_ += begin - contextArray[index].requestTime; 338209bc2fbSopenharmony_ci#endif 339209bc2fbSopenharmony_ci 340209bc2fbSopenharmony_ci // current buffer has not been processed, stop copy 341209bc2fbSopenharmony_ci if (contextArray[index].snapshotTime > 0 && contextArray[index].processTime == 0) { 342209bc2fbSopenharmony_ci return; 343209bc2fbSopenharmony_ci } 344209bc2fbSopenharmony_ci 345209bc2fbSopenharmony_ci contextArray[index].fp = static_cast<ucontext_t*>(context)->uc_mcontext.regs[RegsEnumArm64::REG_FP]; 346209bc2fbSopenharmony_ci contextArray[index].lr = static_cast<ucontext_t*>(context)->uc_mcontext.regs[RegsEnumArm64::REG_LR]; 347209bc2fbSopenharmony_ci contextArray[index].sp = static_cast<ucontext_t*>(context)->uc_mcontext.sp; 348209bc2fbSopenharmony_ci contextArray[index].pc = static_cast<ucontext_t*>(context)->uc_mcontext.pc; 349209bc2fbSopenharmony_ci if (contextArray[index].sp < stackBegin_ || 350209bc2fbSopenharmony_ci contextArray[index].sp >= stackEnd_) { 351209bc2fbSopenharmony_ci return; 352209bc2fbSopenharmony_ci } 353209bc2fbSopenharmony_ci 354209bc2fbSopenharmony_ci uintptr_t curStackSz = stackEnd_ - contextArray[index].sp; 355209bc2fbSopenharmony_ci uintptr_t cpySz = curStackSz > STACK_BUFFER_SIZE ? STACK_BUFFER_SIZE : curStackSz; 356209bc2fbSopenharmony_ci 357209bc2fbSopenharmony_ci for (uintptr_t pos = 0; pos < cpySz; pos++) { 358209bc2fbSopenharmony_ci reinterpret_cast<char*>(contextArray[index].buffer)[pos] = 359209bc2fbSopenharmony_ci reinterpret_cast<const char*>(contextArray[index].sp)[pos]; 360209bc2fbSopenharmony_ci } 361209bc2fbSopenharmony_ci 362209bc2fbSopenharmony_ci writeIndex_ = (index + 1) % SAMPLER_MAX_BUFFER_SZ; 363209bc2fbSopenharmony_ci uint64_t end = GetCurrentTimeNanoseconds(); 364209bc2fbSopenharmony_ci contextArray[index].processTime.store(0, std::memory_order_relaxed); 365209bc2fbSopenharmony_ci contextArray[index].snapshotTime.store(end, std::memory_order_release); 366209bc2fbSopenharmony_ci 367209bc2fbSopenharmony_ci#if defined(CONSUME_STATISTICS) 368209bc2fbSopenharmony_ci copyStackCount_++; 369209bc2fbSopenharmony_ci copyStackTimeCost_ += end - begin; 370209bc2fbSopenharmony_ci#endif 371209bc2fbSopenharmony_ci#endif // #if defined(__aarch64__) 372209bc2fbSopenharmony_ci} 373209bc2fbSopenharmony_ci 374209bc2fbSopenharmony_civoid ThreadSampler::SendSampleRequest() 375209bc2fbSopenharmony_ci{ 376209bc2fbSopenharmony_ci ThreadUnwindContext* ptr = GetWriteContext(); 377209bc2fbSopenharmony_ci if (ptr == nullptr) { 378209bc2fbSopenharmony_ci return; 379209bc2fbSopenharmony_ci } 380209bc2fbSopenharmony_ci 381209bc2fbSopenharmony_ci uint64_t ts = GetCurrentTimeNanoseconds(); 382209bc2fbSopenharmony_ci 383209bc2fbSopenharmony_ci ptr->requestTime = ts; 384209bc2fbSopenharmony_ci siginfo_t si {0}; 385209bc2fbSopenharmony_ci si.si_signo = MUSL_SIGNAL_SAMPLE_STACK; 386209bc2fbSopenharmony_ci si.si_errno = 0; 387209bc2fbSopenharmony_ci si.si_code = -1; 388209bc2fbSopenharmony_ci if (syscall(SYS_rt_tgsigqueueinfo, pid_, pid_, si.si_signo, &si) != 0) { 389209bc2fbSopenharmony_ci XCOLLIE_LOGE("Failed to queue signal(%{public}d) to %{public}d, errno(%{public}d).\n", 390209bc2fbSopenharmony_ci si.si_signo, pid_, errno); 391209bc2fbSopenharmony_ci return; 392209bc2fbSopenharmony_ci } 393209bc2fbSopenharmony_ci#if defined (CONSUME_STATISTICS) 394209bc2fbSopenharmony_ci requestCount_++; 395209bc2fbSopenharmony_ci#endif 396209bc2fbSopenharmony_ci} 397209bc2fbSopenharmony_ci 398209bc2fbSopenharmony_civoid ThreadSampler::ProcessStackBuffer() 399209bc2fbSopenharmony_ci{ 400209bc2fbSopenharmony_ci#if defined(__aarch64__) 401209bc2fbSopenharmony_ci if (!init_) { 402209bc2fbSopenharmony_ci XCOLLIE_LOGE("sampler has not initialized.\n"); 403209bc2fbSopenharmony_ci return; 404209bc2fbSopenharmony_ci } 405209bc2fbSopenharmony_ci while (true) { 406209bc2fbSopenharmony_ci ThreadUnwindContext* context = GetReadContext(); 407209bc2fbSopenharmony_ci if (context == nullptr) { 408209bc2fbSopenharmony_ci break; 409209bc2fbSopenharmony_ci } 410209bc2fbSopenharmony_ci 411209bc2fbSopenharmony_ci UnwindInfo unwindInfo = { 412209bc2fbSopenharmony_ci .context = context, 413209bc2fbSopenharmony_ci .maps = maps_.get(), 414209bc2fbSopenharmony_ci }; 415209bc2fbSopenharmony_ci 416209bc2fbSopenharmony_ci struct TimeAndFrames taf; 417209bc2fbSopenharmony_ci taf.requestTime = unwindInfo.context->requestTime; 418209bc2fbSopenharmony_ci taf.snapshotTime = unwindInfo.context->snapshotTime; 419209bc2fbSopenharmony_ci 420209bc2fbSopenharmony_ci#if defined(CONSUME_STATISTICS) 421209bc2fbSopenharmony_ci uint64_t unwindStart = GetCurrentTimeNanoseconds(); 422209bc2fbSopenharmony_ci#endif 423209bc2fbSopenharmony_ci DoUnwind(unwinder_, unwindInfo); 424209bc2fbSopenharmony_ci#if defined(CONSUME_STATISTICS) 425209bc2fbSopenharmony_ci uint64_t unwindEnd = GetCurrentTimeNanoseconds(); 426209bc2fbSopenharmony_ci#endif 427209bc2fbSopenharmony_ci /* for print full stack */ 428209bc2fbSopenharmony_ci auto frames = unwinder_->GetFrames(); 429209bc2fbSopenharmony_ci taf.frameList = frames; 430209bc2fbSopenharmony_ci timeAndFrameList_.emplace_back(taf); 431209bc2fbSopenharmony_ci /* for print tree format stack */ 432209bc2fbSopenharmony_ci auto pcs = unwinder_->GetPcs(); 433209bc2fbSopenharmony_ci uint64_t stackId = 0; 434209bc2fbSopenharmony_ci auto stackIdPtr = reinterpret_cast<OHOS::HiviewDFX::StackId*>(&stackId); 435209bc2fbSopenharmony_ci uniqueStackTable_->PutPcsInTable(stackIdPtr, pcs.data(), pcs.size()); 436209bc2fbSopenharmony_ci PutStackId(stackIdCount_, stackId); 437209bc2fbSopenharmony_ci 438209bc2fbSopenharmony_ci uint64_t ts = GetCurrentTimeNanoseconds(); 439209bc2fbSopenharmony_ci 440209bc2fbSopenharmony_ci#if defined(CONSUME_STATISTICS) 441209bc2fbSopenharmony_ci processTimeCost_ += ts - unwindStart; 442209bc2fbSopenharmony_ci processCount_++; 443209bc2fbSopenharmony_ci unwindCount_++; 444209bc2fbSopenharmony_ci unwindTimeCost_ += unwindEnd - unwindStart; 445209bc2fbSopenharmony_ci#endif //#if defined(CONSUME_STATISTICS) 446209bc2fbSopenharmony_ci context->requestTime.store(0, std::memory_order_release); 447209bc2fbSopenharmony_ci context->snapshotTime.store(0, std::memory_order_release); 448209bc2fbSopenharmony_ci context->processTime.store(ts, std::memory_order_release); 449209bc2fbSopenharmony_ci } 450209bc2fbSopenharmony_ci#endif // #if defined(__aarch64__) 451209bc2fbSopenharmony_ci} 452209bc2fbSopenharmony_ci 453209bc2fbSopenharmony_ciint32_t ThreadSampler::Sample() 454209bc2fbSopenharmony_ci{ 455209bc2fbSopenharmony_ci if (!init_) { 456209bc2fbSopenharmony_ci XCOLLIE_LOGE("sampler has not initialized.\n"); 457209bc2fbSopenharmony_ci return -1; 458209bc2fbSopenharmony_ci } 459209bc2fbSopenharmony_ci#if defined(CONSUME_STATISTICS) 460209bc2fbSopenharmony_ci sampleCount_++; 461209bc2fbSopenharmony_ci#endif 462209bc2fbSopenharmony_ci SendSampleRequest(); 463209bc2fbSopenharmony_ci ProcessStackBuffer(); 464209bc2fbSopenharmony_ci return 0; 465209bc2fbSopenharmony_ci} 466209bc2fbSopenharmony_ci 467209bc2fbSopenharmony_civoid ThreadSampler::ResetConsumeInfo() 468209bc2fbSopenharmony_ci{ 469209bc2fbSopenharmony_ci#if defined(CONSUME_STATISTICS) 470209bc2fbSopenharmony_ci sampleCount_ = 0; 471209bc2fbSopenharmony_ci requestCount_ = 0; 472209bc2fbSopenharmony_ci copyStackCount_ = 0; 473209bc2fbSopenharmony_ci copyStackTimeCost_ = 0; 474209bc2fbSopenharmony_ci processTimeCost_ = 0; 475209bc2fbSopenharmony_ci processCount_ = 0; 476209bc2fbSopenharmony_ci unwindCount_ = 0; 477209bc2fbSopenharmony_ci unwindTimeCost_ = 0; 478209bc2fbSopenharmony_ci signalTimeCost_ = 0; 479209bc2fbSopenharmony_ci#endif // #if defined(CONSUME_STATISTICS) 480209bc2fbSopenharmony_ci} 481209bc2fbSopenharmony_ci 482209bc2fbSopenharmony_cibool ThreadSampler::CollectStack(std::string& stack, bool treeFormat) 483209bc2fbSopenharmony_ci{ 484209bc2fbSopenharmony_ci ProcessStackBuffer(); 485209bc2fbSopenharmony_ci 486209bc2fbSopenharmony_ci if (!init_) { 487209bc2fbSopenharmony_ci XCOLLIE_LOGE("sampler has not initialized.\n"); 488209bc2fbSopenharmony_ci } 489209bc2fbSopenharmony_ci 490209bc2fbSopenharmony_ci stack.clear(); 491209bc2fbSopenharmony_ci if (timeAndFrameList_.empty() && stackIdCount_.empty()) { 492209bc2fbSopenharmony_ci if (!LoadStringFromFile("/proc/self/wchan", stack)) { 493209bc2fbSopenharmony_ci XCOLLIE_LOGE("read file failed.\n"); 494209bc2fbSopenharmony_ci } 495209bc2fbSopenharmony_ci if (stack.empty()) { 496209bc2fbSopenharmony_ci stack += "empty"; 497209bc2fbSopenharmony_ci } 498209bc2fbSopenharmony_ci stack += "\n"; 499209bc2fbSopenharmony_ci#if defined(CONSUME_STATISTICS) 500209bc2fbSopenharmony_ci ResetConsumeInfo(); 501209bc2fbSopenharmony_ci#endif 502209bc2fbSopenharmony_ci return false; 503209bc2fbSopenharmony_ci } 504209bc2fbSopenharmony_ci 505209bc2fbSopenharmony_ci#if defined(CONSUME_STATISTICS) 506209bc2fbSopenharmony_ci uint64_t collectStart = GetCurrentTimeNanoseconds(); 507209bc2fbSopenharmony_ci#endif 508209bc2fbSopenharmony_ci auto printer = std::make_unique<SampleStackPrinter>(unwinder_, maps_); 509209bc2fbSopenharmony_ci if (!treeFormat) { 510209bc2fbSopenharmony_ci stack = printer->GetFullStack(timeAndFrameList_); 511209bc2fbSopenharmony_ci } else { 512209bc2fbSopenharmony_ci stack = printer->GetTreeStack(stackIdCount_, uniqueStackTable_); 513209bc2fbSopenharmony_ci } 514209bc2fbSopenharmony_ci timeAndFrameList_.clear(); 515209bc2fbSopenharmony_ci stackIdCount_.clear(); 516209bc2fbSopenharmony_ci 517209bc2fbSopenharmony_ci#if defined(CONSUME_STATISTICS) 518209bc2fbSopenharmony_ci uint64_t collectEnd = GetCurrentTimeNanoseconds(); 519209bc2fbSopenharmony_ci uint64_t elapse = collectEnd - collectStart; 520209bc2fbSopenharmony_ci XCOLLIE_LOGI("Sample count:%{public}llu\nRequest count:%{public}llu\n\ 521209bc2fbSopenharmony_ci Snapshot count:%{public}llu\nAverage copy stack time:%{public}llu ns\n", 522209bc2fbSopenharmony_ci (unsigned long long)sampleCount_, (unsigned long long)requestCount_, 523209bc2fbSopenharmony_ci (unsigned long long)copyStackCount_, (unsigned long long)copyStackTimeCost_ / copyStackCount_); 524209bc2fbSopenharmony_ci XCOLLIE_LOGI("Average process time:%{public}llu ns\n", (unsigned long long)processTimeCost_/processCount_); 525209bc2fbSopenharmony_ci XCOLLIE_LOGI("Average unwind time:%{public}llu ns\n", (unsigned long long)unwindTimeCost_/unwindCount_); 526209bc2fbSopenharmony_ci XCOLLIE_LOGI("FormatStack time:%{public}llu ns\n", (unsigned long long)elapse); 527209bc2fbSopenharmony_ci ResetConsumeInfo(); 528209bc2fbSopenharmony_ci#endif 529209bc2fbSopenharmony_ci return true; 530209bc2fbSopenharmony_ci} 531209bc2fbSopenharmony_ci 532209bc2fbSopenharmony_cibool ThreadSampler::Deinit() 533209bc2fbSopenharmony_ci{ 534209bc2fbSopenharmony_ci if (!init_) { 535209bc2fbSopenharmony_ci return true; 536209bc2fbSopenharmony_ci } 537209bc2fbSopenharmony_ci UninstallSignalHandler(); 538209bc2fbSopenharmony_ci struct timespec timeout; 539209bc2fbSopenharmony_ci timeout.tv_sec = time(nullptr) + LOCK_TIMEOUT; 540209bc2fbSopenharmony_ci timeout.tv_nsec = 0; 541209bc2fbSopenharmony_ci int err = pthread_mutex_timedlock(&mutex_, &timeout); 542209bc2fbSopenharmony_ci if (err != 0) { 543209bc2fbSopenharmony_ci XCOLLIE_LOGE("Failed to get lock when deinit thread_sampler.\n"); 544209bc2fbSopenharmony_ci return false; 545209bc2fbSopenharmony_ci } 546209bc2fbSopenharmony_ci DeinitUniqueStackTable(); 547209bc2fbSopenharmony_ci DestroyUnwinder(); 548209bc2fbSopenharmony_ci ReleaseRecordBuffer(); 549209bc2fbSopenharmony_ci init_ = false; 550209bc2fbSopenharmony_ci pthread_mutex_unlock(&mutex_); 551209bc2fbSopenharmony_ci return !init_; 552209bc2fbSopenharmony_ci} 553209bc2fbSopenharmony_ci} // end of namespace HiviewDFX 554209bc2fbSopenharmony_ci} // end of namespace OHOS 555