1800b99b8Sopenharmony_ci/* 2800b99b8Sopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd. 3800b99b8Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4800b99b8Sopenharmony_ci * you may not use this file except in compliance with the License. 5800b99b8Sopenharmony_ci * You may obtain a copy of the License at 6800b99b8Sopenharmony_ci * 7800b99b8Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8800b99b8Sopenharmony_ci * 9800b99b8Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10800b99b8Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11800b99b8Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12800b99b8Sopenharmony_ci * See the License for the specific language governing permissions and 13800b99b8Sopenharmony_ci * limitations under the License. 14800b99b8Sopenharmony_ci */ 15800b99b8Sopenharmony_ci 16800b99b8Sopenharmony_ci#include <benchmark/benchmark.h> 17800b99b8Sopenharmony_ci 18800b99b8Sopenharmony_ci#include <string> 19800b99b8Sopenharmony_ci#include <vector> 20800b99b8Sopenharmony_ci#include "dfx_log.h" 21800b99b8Sopenharmony_ci#include "dfx_ptrace.h" 22800b99b8Sopenharmony_ci#include "dfx_regs_qut.h" 23800b99b8Sopenharmony_ci#include "dfx_test_util.h" 24800b99b8Sopenharmony_ci#include "unwinder.h" 25800b99b8Sopenharmony_ci#include "unwinder_config.h" 26800b99b8Sopenharmony_ci 27800b99b8Sopenharmony_ciusing namespace OHOS::HiviewDFX; 28800b99b8Sopenharmony_ciusing namespace std; 29800b99b8Sopenharmony_ci 30800b99b8Sopenharmony_ci#undef LOG_DOMAIN 31800b99b8Sopenharmony_ci#undef LOG_TAG 32800b99b8Sopenharmony_ci#define LOG_DOMAIN 0xD002D11 33800b99b8Sopenharmony_ci#define LOG_TAG "DfxUnwinderRemote" 34800b99b8Sopenharmony_ci 35800b99b8Sopenharmony_cistatic constexpr size_t TEST_MIN_UNWIND_FRAMES = 5; 36800b99b8Sopenharmony_ci 37800b99b8Sopenharmony_cistruct UnwindData { 38800b99b8Sopenharmony_ci bool isCache = false; 39800b99b8Sopenharmony_ci bool isFillFrames = false; 40800b99b8Sopenharmony_ci bool isFp = false; 41800b99b8Sopenharmony_ci}; 42800b99b8Sopenharmony_ci 43800b99b8Sopenharmony_ciNOINLINE static void TestFunc6(MAYBE_UNUSED void (*func)(void*), MAYBE_UNUSED void* data) 44800b99b8Sopenharmony_ci{ 45800b99b8Sopenharmony_ci while (true) {}; 46800b99b8Sopenharmony_ci DFXLOGE("Not be run here!!!"); 47800b99b8Sopenharmony_ci} 48800b99b8Sopenharmony_ci 49800b99b8Sopenharmony_ciNOINLINE static void TestFunc5(void (*func)(void*), void* data) 50800b99b8Sopenharmony_ci{ 51800b99b8Sopenharmony_ci return TestFunc6(func, data); 52800b99b8Sopenharmony_ci} 53800b99b8Sopenharmony_ci 54800b99b8Sopenharmony_ciNOINLINE static void TestFunc4(void (*func)(void*), void* data) 55800b99b8Sopenharmony_ci{ 56800b99b8Sopenharmony_ci return TestFunc5(func, data); 57800b99b8Sopenharmony_ci} 58800b99b8Sopenharmony_ci 59800b99b8Sopenharmony_ciNOINLINE static void TestFunc3(void (*func)(void*), void* data) 60800b99b8Sopenharmony_ci{ 61800b99b8Sopenharmony_ci return TestFunc4(func, data); 62800b99b8Sopenharmony_ci} 63800b99b8Sopenharmony_ci 64800b99b8Sopenharmony_ciNOINLINE static void TestFunc2(void (*func)(void*), void* data) 65800b99b8Sopenharmony_ci{ 66800b99b8Sopenharmony_ci return TestFunc3(func, data); 67800b99b8Sopenharmony_ci} 68800b99b8Sopenharmony_ci 69800b99b8Sopenharmony_ciNOINLINE static void TestFunc1(void (*func)(void*), void* data) 70800b99b8Sopenharmony_ci{ 71800b99b8Sopenharmony_ci return TestFunc2(func, data); 72800b99b8Sopenharmony_ci} 73800b99b8Sopenharmony_ci 74800b99b8Sopenharmony_cistatic size_t UnwinderRemote(std::shared_ptr<Unwinder> unwinder, const pid_t tid) 75800b99b8Sopenharmony_ci{ 76800b99b8Sopenharmony_ci if (unwinder == nullptr) { 77800b99b8Sopenharmony_ci return 0; 78800b99b8Sopenharmony_ci } 79800b99b8Sopenharmony_ci MAYBE_UNUSED bool unwRet = unwinder->UnwindRemote(tid); 80800b99b8Sopenharmony_ci auto frames = unwinder->GetFrames(); 81800b99b8Sopenharmony_ci DFXLOGU("%{public}s frames.size: %{public}zu", __func__, frames.size()); 82800b99b8Sopenharmony_ci return frames.size(); 83800b99b8Sopenharmony_ci} 84800b99b8Sopenharmony_ci 85800b99b8Sopenharmony_cistatic size_t UnwinderRemoteFp(std::shared_ptr<Unwinder> unwinder, const pid_t tid) 86800b99b8Sopenharmony_ci{ 87800b99b8Sopenharmony_ci if (unwinder == nullptr) { 88800b99b8Sopenharmony_ci return 0; 89800b99b8Sopenharmony_ci } 90800b99b8Sopenharmony_ci auto regs = DfxRegs::CreateRemoteRegs(tid); 91800b99b8Sopenharmony_ci unwinder->SetRegs(regs); 92800b99b8Sopenharmony_ci UnwindContext context; 93800b99b8Sopenharmony_ci context.pid = tid; 94800b99b8Sopenharmony_ci unwinder->EnableFpCheckMapExec(false); 95800b99b8Sopenharmony_ci unwinder->UnwindByFp(&context); 96800b99b8Sopenharmony_ci auto frames = unwinder->GetPcs(); 97800b99b8Sopenharmony_ci DFXLOGU("%{public}s frames.size: %{public}zu", __func__, frames.size()); 98800b99b8Sopenharmony_ci return frames.size(); 99800b99b8Sopenharmony_ci} 100800b99b8Sopenharmony_ci 101800b99b8Sopenharmony_cistatic bool GetUnwinder(pid_t pid, void* data, std::shared_ptr<Unwinder>& unwinder, bool& isFp) 102800b99b8Sopenharmony_ci{ 103800b99b8Sopenharmony_ci static std::unordered_map<pid_t, std::shared_ptr<Unwinder>> unwinders_; 104800b99b8Sopenharmony_ci auto iter = unwinders_.find(pid); 105800b99b8Sopenharmony_ci if (iter != unwinders_.end()) { 106800b99b8Sopenharmony_ci unwinder = iter->second; 107800b99b8Sopenharmony_ci } else { 108800b99b8Sopenharmony_ci unwinder = std::make_shared<Unwinder>(pid); 109800b99b8Sopenharmony_ci unwinders_[pid] = unwinder; 110800b99b8Sopenharmony_ci } 111800b99b8Sopenharmony_ci 112800b99b8Sopenharmony_ci UnwindData* dataPtr = reinterpret_cast<UnwindData*>(data); 113800b99b8Sopenharmony_ci if ((dataPtr != nullptr) && (unwinder != nullptr)) { 114800b99b8Sopenharmony_ci unwinder->EnableFillFrames(dataPtr->isFillFrames); 115800b99b8Sopenharmony_ci unwinder->EnableUnwindCache(dataPtr->isCache); 116800b99b8Sopenharmony_ci isFp = dataPtr->isFp; 117800b99b8Sopenharmony_ci } 118800b99b8Sopenharmony_ci return true; 119800b99b8Sopenharmony_ci} 120800b99b8Sopenharmony_ci 121800b99b8Sopenharmony_cistatic void Run(benchmark::State& state, void* data) 122800b99b8Sopenharmony_ci{ 123800b99b8Sopenharmony_ci pid_t pid = fork(); 124800b99b8Sopenharmony_ci if (pid == 0) { 125800b99b8Sopenharmony_ci TestFunc1(nullptr, nullptr); 126800b99b8Sopenharmony_ci _exit(0); 127800b99b8Sopenharmony_ci } else if (pid < 0) { 128800b99b8Sopenharmony_ci return; 129800b99b8Sopenharmony_ci } 130800b99b8Sopenharmony_ci if (!DfxPtrace::Attach(pid)) { 131800b99b8Sopenharmony_ci DFXLOGE("Failed to attach pid: %{public}d", pid); 132800b99b8Sopenharmony_ci TestScopedPidReaper::Kill(pid); 133800b99b8Sopenharmony_ci return; 134800b99b8Sopenharmony_ci } 135800b99b8Sopenharmony_ci DFXLOGU("pid: %{public}d", pid); 136800b99b8Sopenharmony_ci TestScopedPidReaper reap(pid); 137800b99b8Sopenharmony_ci 138800b99b8Sopenharmony_ci std::shared_ptr<Unwinder> unwinder = nullptr; 139800b99b8Sopenharmony_ci bool isFp = false; 140800b99b8Sopenharmony_ci if (!GetUnwinder(pid, data, unwinder, isFp) || (unwinder == nullptr)) { 141800b99b8Sopenharmony_ci state.SkipWithError("Failed to get unwinder."); 142800b99b8Sopenharmony_ci return; 143800b99b8Sopenharmony_ci } 144800b99b8Sopenharmony_ci 145800b99b8Sopenharmony_ci for (const auto& _ : state) { 146800b99b8Sopenharmony_ci size_t unwSize = 0; 147800b99b8Sopenharmony_ci if (isFp) { 148800b99b8Sopenharmony_ci unwSize = UnwinderRemoteFp(unwinder, pid); 149800b99b8Sopenharmony_ci } else { 150800b99b8Sopenharmony_ci unwSize = UnwinderRemote(unwinder, pid); 151800b99b8Sopenharmony_ci } 152800b99b8Sopenharmony_ci 153800b99b8Sopenharmony_ci if (unwSize < TEST_MIN_UNWIND_FRAMES) { 154800b99b8Sopenharmony_ci state.SkipWithError("Failed to unwind."); 155800b99b8Sopenharmony_ci } 156800b99b8Sopenharmony_ci } 157800b99b8Sopenharmony_ci DFXLOGU("Detach pid: %{public}d", pid); 158800b99b8Sopenharmony_ci DfxPtrace::Detach(pid); 159800b99b8Sopenharmony_ci} 160800b99b8Sopenharmony_ci 161800b99b8Sopenharmony_ci/** 162800b99b8Sopenharmony_ci* @tc.name: BenchmarkUnwinderRemoteFull 163800b99b8Sopenharmony_ci* @tc.desc: Unwind remote full 164800b99b8Sopenharmony_ci* @tc.type: FUNC 165800b99b8Sopenharmony_ci*/ 166800b99b8Sopenharmony_cistatic void BenchmarkUnwinderRemoteFull(benchmark::State& state) 167800b99b8Sopenharmony_ci{ 168800b99b8Sopenharmony_ci std::vector<uint16_t> qutRegs; 169800b99b8Sopenharmony_ci for (uint16_t i = REG_EH; i < REG_LAST; ++i) { 170800b99b8Sopenharmony_ci qutRegs.emplace_back(i); 171800b99b8Sopenharmony_ci } 172800b99b8Sopenharmony_ci DfxRegsQut::SetQutRegs(qutRegs); 173800b99b8Sopenharmony_ci UnwindData data; 174800b99b8Sopenharmony_ci data.isCache = false; 175800b99b8Sopenharmony_ci data.isFillFrames = false; 176800b99b8Sopenharmony_ci Run(state, &data); 177800b99b8Sopenharmony_ci} 178800b99b8Sopenharmony_ciBENCHMARK(BenchmarkUnwinderRemoteFull); 179800b99b8Sopenharmony_ci 180800b99b8Sopenharmony_ci/** 181800b99b8Sopenharmony_ci* @tc.name: BenchmarkUnwinderRemoteQut 182800b99b8Sopenharmony_ci* @tc.desc: Unwind remote qut 183800b99b8Sopenharmony_ci* @tc.type: FUNC 184800b99b8Sopenharmony_ci*/ 185800b99b8Sopenharmony_cistatic void BenchmarkUnwinderRemoteQut(benchmark::State& state) 186800b99b8Sopenharmony_ci{ 187800b99b8Sopenharmony_ci DfxRegsQut::SetQutRegs(QUT_REGS); 188800b99b8Sopenharmony_ci UnwindData data; 189800b99b8Sopenharmony_ci data.isCache = false; 190800b99b8Sopenharmony_ci data.isFillFrames = false; 191800b99b8Sopenharmony_ci Run(state, &data); 192800b99b8Sopenharmony_ci} 193800b99b8Sopenharmony_ciBENCHMARK(BenchmarkUnwinderRemoteQut); 194800b99b8Sopenharmony_ci 195800b99b8Sopenharmony_ci/** 196800b99b8Sopenharmony_ci* @tc.name: BenchmarkUnwinderRemoteQutCache 197800b99b8Sopenharmony_ci* @tc.desc: Unwind remote qut cache 198800b99b8Sopenharmony_ci* @tc.type: FUNC 199800b99b8Sopenharmony_ci*/ 200800b99b8Sopenharmony_cistatic void BenchmarkUnwinderRemoteQutCache(benchmark::State& state) 201800b99b8Sopenharmony_ci{ 202800b99b8Sopenharmony_ci DfxRegsQut::SetQutRegs(QUT_REGS); 203800b99b8Sopenharmony_ci UnwindData data; 204800b99b8Sopenharmony_ci data.isCache = true; 205800b99b8Sopenharmony_ci data.isFillFrames = false; 206800b99b8Sopenharmony_ci Run(state, &data); 207800b99b8Sopenharmony_ci} 208800b99b8Sopenharmony_ciBENCHMARK(BenchmarkUnwinderRemoteQutCache); 209800b99b8Sopenharmony_ci 210800b99b8Sopenharmony_ci/** 211800b99b8Sopenharmony_ci* @tc.name: BenchmarkUnwinderRemoteQutFrames 212800b99b8Sopenharmony_ci* @tc.desc: Unwind remote qut frames 213800b99b8Sopenharmony_ci* @tc.type: FUNC 214800b99b8Sopenharmony_ci*/ 215800b99b8Sopenharmony_cistatic void BenchmarkUnwinderRemoteQutFrames(benchmark::State& state) 216800b99b8Sopenharmony_ci{ 217800b99b8Sopenharmony_ci DfxRegsQut::SetQutRegs(QUT_REGS); 218800b99b8Sopenharmony_ci UnwindData data; 219800b99b8Sopenharmony_ci data.isCache = false; 220800b99b8Sopenharmony_ci data.isFillFrames = true; 221800b99b8Sopenharmony_ci Run(state, &data); 222800b99b8Sopenharmony_ci} 223800b99b8Sopenharmony_ciBENCHMARK(BenchmarkUnwinderRemoteQutFrames); 224800b99b8Sopenharmony_ci 225800b99b8Sopenharmony_ci/** 226800b99b8Sopenharmony_ci* @tc.name: BenchmarkUnwinderRemoteQutFramesCache 227800b99b8Sopenharmony_ci* @tc.desc: Unwind remote qut frames cache 228800b99b8Sopenharmony_ci* @tc.type: FUNC 229800b99b8Sopenharmony_ci*/ 230800b99b8Sopenharmony_cistatic void BenchmarkUnwinderRemoteQutFramesCache(benchmark::State& state) 231800b99b8Sopenharmony_ci{ 232800b99b8Sopenharmony_ci DfxRegsQut::SetQutRegs(QUT_REGS); 233800b99b8Sopenharmony_ci UnwindData data; 234800b99b8Sopenharmony_ci data.isCache = true; 235800b99b8Sopenharmony_ci data.isFillFrames = true; 236800b99b8Sopenharmony_ci Run(state, &data); 237800b99b8Sopenharmony_ci} 238800b99b8Sopenharmony_ciBENCHMARK(BenchmarkUnwinderRemoteQutFramesCache); 239800b99b8Sopenharmony_ci 240800b99b8Sopenharmony_ci/** 241800b99b8Sopenharmony_ci* @tc.name: BenchmarkUnwinderRemoteQutMiniDebugInfos 242800b99b8Sopenharmony_ci* @tc.desc: Unwind remote qut minidebuginfo 243800b99b8Sopenharmony_ci* @tc.type: FUNC 244800b99b8Sopenharmony_ci*/ 245800b99b8Sopenharmony_cistatic void BenchmarkUnwinderRemoteQutMiniDebugInfos(benchmark::State& state) 246800b99b8Sopenharmony_ci{ 247800b99b8Sopenharmony_ci DfxRegsQut::SetQutRegs(QUT_REGS); 248800b99b8Sopenharmony_ci UnwinderConfig::SetEnableMiniDebugInfo(true); 249800b99b8Sopenharmony_ci UnwindData data; 250800b99b8Sopenharmony_ci data.isCache = false; 251800b99b8Sopenharmony_ci data.isFillFrames = true; 252800b99b8Sopenharmony_ci Run(state, &data); 253800b99b8Sopenharmony_ci UnwinderConfig::SetEnableMiniDebugInfo(false); 254800b99b8Sopenharmony_ci} 255800b99b8Sopenharmony_ciBENCHMARK(BenchmarkUnwinderRemoteQutMiniDebugInfos); 256800b99b8Sopenharmony_ci 257800b99b8Sopenharmony_ci/** 258800b99b8Sopenharmony_ci* @tc.name: BenchmarkUnwinderRemoteQutMiniDebugInfosLazily 259800b99b8Sopenharmony_ci* @tc.desc: Unwind remote qut minidebuginfo lazily 260800b99b8Sopenharmony_ci* @tc.type: FUNC 261800b99b8Sopenharmony_ci*/ 262800b99b8Sopenharmony_cistatic void BenchmarkUnwinderRemoteQutMiniDebugInfosLazily(benchmark::State& state) 263800b99b8Sopenharmony_ci{ 264800b99b8Sopenharmony_ci DfxRegsQut::SetQutRegs(QUT_REGS); 265800b99b8Sopenharmony_ci UnwinderConfig::SetEnableMiniDebugInfo(true); 266800b99b8Sopenharmony_ci UnwinderConfig::SetEnableLoadSymbolLazily(true); 267800b99b8Sopenharmony_ci UnwindData data; 268800b99b8Sopenharmony_ci data.isCache = false; 269800b99b8Sopenharmony_ci data.isFillFrames = true; 270800b99b8Sopenharmony_ci Run(state, &data); 271800b99b8Sopenharmony_ci UnwinderConfig::SetEnableMiniDebugInfo(false); 272800b99b8Sopenharmony_ci UnwinderConfig::SetEnableLoadSymbolLazily(false); 273800b99b8Sopenharmony_ci} 274800b99b8Sopenharmony_ciBENCHMARK(BenchmarkUnwinderRemoteQutMiniDebugInfosLazily); 275800b99b8Sopenharmony_ci 276800b99b8Sopenharmony_ci#if defined(__aarch64__) 277800b99b8Sopenharmony_ci/** 278800b99b8Sopenharmony_ci* @tc.name: BenchmarkUnwinderRemoteFp 279800b99b8Sopenharmony_ci* @tc.desc: Unwind remote fp 280800b99b8Sopenharmony_ci* @tc.type: FUNC 281800b99b8Sopenharmony_ci*/ 282800b99b8Sopenharmony_cistatic void BenchmarkUnwinderRemoteFp(benchmark::State& state) 283800b99b8Sopenharmony_ci{ 284800b99b8Sopenharmony_ci UnwindData data; 285800b99b8Sopenharmony_ci data.isFp = true; 286800b99b8Sopenharmony_ci Run(state, &data); 287800b99b8Sopenharmony_ci} 288800b99b8Sopenharmony_ciBENCHMARK(BenchmarkUnwinderRemoteFp); 289800b99b8Sopenharmony_ci#endif