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 <sys/ptrace.h> 21800b99b8Sopenharmony_ci#include <unwindstack/Maps.h> 22800b99b8Sopenharmony_ci#include <unwindstack/Memory.h> 23800b99b8Sopenharmony_ci#include <unwindstack/Regs.h> 24800b99b8Sopenharmony_ci#include <unwindstack/Unwinder.h> 25800b99b8Sopenharmony_ci#include "dfx_define.h" 26800b99b8Sopenharmony_ci#include "dfx_log.h" 27800b99b8Sopenharmony_ci#include "dfx_test_util.h" 28800b99b8Sopenharmony_ci#include "MemoryRemote.h" 29800b99b8Sopenharmony_ci#include "pid_utils.h" 30800b99b8Sopenharmony_ci 31800b99b8Sopenharmony_ciusing namespace OHOS::HiviewDFX; 32800b99b8Sopenharmony_ciusing namespace std; 33800b99b8Sopenharmony_ci 34800b99b8Sopenharmony_cistatic constexpr size_t TEST_MIN_UNWIND_FRAMES = 5; 35800b99b8Sopenharmony_cistatic constexpr size_t MAX_FRAMES = 32; 36800b99b8Sopenharmony_ci 37800b99b8Sopenharmony_cistruct UnwindData { 38800b99b8Sopenharmony_ci bool isCache = false; 39800b99b8Sopenharmony_ci bool isFillFrames = false; 40800b99b8Sopenharmony_ci}; 41800b99b8Sopenharmony_ci 42800b99b8Sopenharmony_ciNOINLINE static void TestFunc6(MAYBE_UNUSED void (*func)(void*), MAYBE_UNUSED volatile bool* ready) 43800b99b8Sopenharmony_ci{ 44800b99b8Sopenharmony_ci *ready = true; 45800b99b8Sopenharmony_ci while (true) {}; 46800b99b8Sopenharmony_ci DFXLOGE("Not be run here!!!"); 47800b99b8Sopenharmony_ci} 48800b99b8Sopenharmony_ci 49800b99b8Sopenharmony_ciNOINLINE static void TestFunc5(void (*func)(void*), volatile bool* ready) 50800b99b8Sopenharmony_ci{ 51800b99b8Sopenharmony_ci return TestFunc6(func, ready); 52800b99b8Sopenharmony_ci} 53800b99b8Sopenharmony_ci 54800b99b8Sopenharmony_ciNOINLINE static void TestFunc4(void (*func)(void*), volatile bool* ready) 55800b99b8Sopenharmony_ci{ 56800b99b8Sopenharmony_ci return TestFunc5(func, ready); 57800b99b8Sopenharmony_ci} 58800b99b8Sopenharmony_ci 59800b99b8Sopenharmony_ciNOINLINE static void TestFunc3(void (*func)(void*), volatile bool* ready) 60800b99b8Sopenharmony_ci{ 61800b99b8Sopenharmony_ci return TestFunc4(func, ready); 62800b99b8Sopenharmony_ci} 63800b99b8Sopenharmony_ci 64800b99b8Sopenharmony_ciNOINLINE static void TestFunc2(void (*func)(void*), volatile bool* ready) 65800b99b8Sopenharmony_ci{ 66800b99b8Sopenharmony_ci return TestFunc3(func, ready); 67800b99b8Sopenharmony_ci} 68800b99b8Sopenharmony_ci 69800b99b8Sopenharmony_ciNOINLINE static void TestFunc1(void (*func)(void*), volatile bool* ready) 70800b99b8Sopenharmony_ci{ 71800b99b8Sopenharmony_ci return TestFunc2(func, ready); 72800b99b8Sopenharmony_ci} 73800b99b8Sopenharmony_ci 74800b99b8Sopenharmony_cistatic bool WaitForRemote(pid_t pid, volatile bool* readyPtr) 75800b99b8Sopenharmony_ci{ 76800b99b8Sopenharmony_ci return PidUtils::WaitForPidState(pid, [pid, readyPtr]() { 77800b99b8Sopenharmony_ci unwindstack::MemoryRemote memory(pid); 78800b99b8Sopenharmony_ci bool ready; 79800b99b8Sopenharmony_ci uint64_t readyAddr = reinterpret_cast<uint64_t>(readyPtr); 80800b99b8Sopenharmony_ci if (memory.ReadFully(readyAddr, &ready, sizeof(ready)) && ready) { 81800b99b8Sopenharmony_ci return PidRunEnum::PID_RUN_PASS; 82800b99b8Sopenharmony_ci } 83800b99b8Sopenharmony_ci return PidRunEnum::PID_RUN_KEEP_GOING; 84800b99b8Sopenharmony_ci }); 85800b99b8Sopenharmony_ci} 86800b99b8Sopenharmony_ci 87800b99b8Sopenharmony_cistatic pid_t RemoteFork() 88800b99b8Sopenharmony_ci{ 89800b99b8Sopenharmony_ci static volatile bool ready = false; 90800b99b8Sopenharmony_ci 91800b99b8Sopenharmony_ci pid_t pid; 92800b99b8Sopenharmony_ci if ((pid = fork()) == 0) { 93800b99b8Sopenharmony_ci TestFunc1(nullptr, &ready); 94800b99b8Sopenharmony_ci _exit(0); 95800b99b8Sopenharmony_ci } else if (pid < 0) { 96800b99b8Sopenharmony_ci return -1; 97800b99b8Sopenharmony_ci } 98800b99b8Sopenharmony_ci 99800b99b8Sopenharmony_ci if (!WaitForRemote(pid, &ready)) { 100800b99b8Sopenharmony_ci DFXLOGE("Failed to wait pid: %{public}d", pid); 101800b99b8Sopenharmony_ci TestScopedPidReaper::Kill(pid); 102800b99b8Sopenharmony_ci return -1; 103800b99b8Sopenharmony_ci } 104800b99b8Sopenharmony_ci return pid; 105800b99b8Sopenharmony_ci} 106800b99b8Sopenharmony_ci 107800b99b8Sopenharmony_cistatic size_t UnwindRemote(unwindstack::Unwinder unwinder, MAYBE_UNUSED UnwindData* dataPtr) 108800b99b8Sopenharmony_ci{ 109800b99b8Sopenharmony_ci if (dataPtr != nullptr) { 110800b99b8Sopenharmony_ci unwinder.SetResolveNames(dataPtr->isFillFrames); 111800b99b8Sopenharmony_ci } 112800b99b8Sopenharmony_ci unwinder.Unwind(); 113800b99b8Sopenharmony_ci auto unwSize = unwinder.NumFrames(); 114800b99b8Sopenharmony_ci DFXLOGU("%{public}s frames.size: %{public}zu", __func__, unwSize); 115800b99b8Sopenharmony_ci if (dataPtr != nullptr && dataPtr->isFillFrames) { 116800b99b8Sopenharmony_ci for (size_t i = 0; i < unwSize; ++i) { 117800b99b8Sopenharmony_ci auto str = unwinder.FormatFrame(i); 118800b99b8Sopenharmony_ci DFXLOGU("%{public}s frames: %{public}s", __func__, str.c_str()); 119800b99b8Sopenharmony_ci } 120800b99b8Sopenharmony_ci } 121800b99b8Sopenharmony_ci return unwSize; 122800b99b8Sopenharmony_ci} 123800b99b8Sopenharmony_ci 124800b99b8Sopenharmony_cistatic void Run(benchmark::State& state, void* data) 125800b99b8Sopenharmony_ci{ 126800b99b8Sopenharmony_ci UnwindData* dataPtr = reinterpret_cast<UnwindData*>(data); 127800b99b8Sopenharmony_ci UnwindData unwindData; 128800b99b8Sopenharmony_ci if (dataPtr != nullptr) { 129800b99b8Sopenharmony_ci unwindData.isCache = dataPtr->isCache; 130800b99b8Sopenharmony_ci } 131800b99b8Sopenharmony_ci 132800b99b8Sopenharmony_ci pid_t pid = RemoteFork(); 133800b99b8Sopenharmony_ci if (pid == -1) { 134800b99b8Sopenharmony_ci state.SkipWithError("Failed to fork remote process."); 135800b99b8Sopenharmony_ci return; 136800b99b8Sopenharmony_ci } 137800b99b8Sopenharmony_ci DFXLOGU("pid: %{public}d", pid); 138800b99b8Sopenharmony_ci TestScopedPidReaper reap(pid); 139800b99b8Sopenharmony_ci 140800b99b8Sopenharmony_ci std::shared_ptr<unwindstack::Memory> processMemory; 141800b99b8Sopenharmony_ci if (unwindData.isCache) { 142800b99b8Sopenharmony_ci processMemory = unwindstack::Memory::CreateProcessMemoryCached(pid); 143800b99b8Sopenharmony_ci } else { 144800b99b8Sopenharmony_ci processMemory = unwindstack::Memory::CreateProcessMemory(pid); 145800b99b8Sopenharmony_ci } 146800b99b8Sopenharmony_ci unwindstack::RemoteMaps maps(pid); 147800b99b8Sopenharmony_ci if (!maps.Parse()) { 148800b99b8Sopenharmony_ci state.SkipWithError("Failed to parse maps."); 149800b99b8Sopenharmony_ci } 150800b99b8Sopenharmony_ci 151800b99b8Sopenharmony_ci for (const auto& _ : state) { 152800b99b8Sopenharmony_ci std::unique_ptr<unwindstack::Regs> regs(unwindstack::Regs::RemoteGet(pid)); 153800b99b8Sopenharmony_ci unwindstack::Unwinder unwinder(MAX_FRAMES, &maps, regs.get(), processMemory); 154800b99b8Sopenharmony_ci auto unwSize = UnwindRemote(unwinder, dataPtr); 155800b99b8Sopenharmony_ci if (unwSize < TEST_MIN_UNWIND_FRAMES) { 156800b99b8Sopenharmony_ci state.SkipWithError("Failed to unwind."); 157800b99b8Sopenharmony_ci } 158800b99b8Sopenharmony_ci } 159800b99b8Sopenharmony_ci DFXLOGU("Detach pid: %{public}d", pid); 160800b99b8Sopenharmony_ci ptrace(PTRACE_DETACH, pid, 0, 0); 161800b99b8Sopenharmony_ci} 162800b99b8Sopenharmony_ci 163800b99b8Sopenharmony_ci/** 164800b99b8Sopenharmony_ci* @tc.name: BenchmarkUnwindStackRemote 165800b99b8Sopenharmony_ci* @tc.desc: UnwindStack remote 166800b99b8Sopenharmony_ci* @tc.type: FUNC 167800b99b8Sopenharmony_ci*/ 168800b99b8Sopenharmony_cistatic void BenchmarkUnwindStackRemote(benchmark::State& state) 169800b99b8Sopenharmony_ci{ 170800b99b8Sopenharmony_ci UnwindData data; 171800b99b8Sopenharmony_ci data.isCache = false; 172800b99b8Sopenharmony_ci Run(state, &data); 173800b99b8Sopenharmony_ci} 174800b99b8Sopenharmony_ciBENCHMARK(BenchmarkUnwindStackRemote); 175800b99b8Sopenharmony_ci 176800b99b8Sopenharmony_ci/** 177800b99b8Sopenharmony_ci* @tc.name: BenchmarkUnwindStackRemoteCache 178800b99b8Sopenharmony_ci* @tc.desc: UnwindStack remote cache 179800b99b8Sopenharmony_ci* @tc.type: FUNC 180800b99b8Sopenharmony_ci*/ 181800b99b8Sopenharmony_cistatic void BenchmarkUnwindStackRemoteCache(benchmark::State& state) 182800b99b8Sopenharmony_ci{ 183800b99b8Sopenharmony_ci UnwindData data; 184800b99b8Sopenharmony_ci data.isCache = true; 185800b99b8Sopenharmony_ci Run(state, &data); 186800b99b8Sopenharmony_ci} 187800b99b8Sopenharmony_ciBENCHMARK(BenchmarkUnwindStackRemoteCache); 188800b99b8Sopenharmony_ci 189800b99b8Sopenharmony_ci/** 190800b99b8Sopenharmony_ci* @tc.name: BenchmarkUnwindStackRemoteFrames 191800b99b8Sopenharmony_ci* @tc.desc: UnwindStack remote frames 192800b99b8Sopenharmony_ci* @tc.type: FUNC 193800b99b8Sopenharmony_ci*/ 194800b99b8Sopenharmony_cistatic void BenchmarkUnwindStackRemoteFrames(benchmark::State& state) 195800b99b8Sopenharmony_ci{ 196800b99b8Sopenharmony_ci UnwindData data; 197800b99b8Sopenharmony_ci data.isCache = false; 198800b99b8Sopenharmony_ci data.isFillFrames = true; 199800b99b8Sopenharmony_ci Run(state, &data); 200800b99b8Sopenharmony_ci} 201800b99b8Sopenharmony_ciBENCHMARK(BenchmarkUnwindStackRemoteFrames); 202800b99b8Sopenharmony_ci 203800b99b8Sopenharmony_ci/** 204800b99b8Sopenharmony_ci* @tc.name: BenchmarkUnwindStackRemoteFramesCache 205800b99b8Sopenharmony_ci* @tc.desc: UnwindStack remote frames cache 206800b99b8Sopenharmony_ci* @tc.type: FUNC 207800b99b8Sopenharmony_ci*/ 208800b99b8Sopenharmony_cistatic void BenchmarkUnwindStackRemoteFramesCache(benchmark::State& state) 209800b99b8Sopenharmony_ci{ 210800b99b8Sopenharmony_ci UnwindData data; 211800b99b8Sopenharmony_ci data.isCache = true; 212800b99b8Sopenharmony_ci data.isFillFrames = true; 213800b99b8Sopenharmony_ci Run(state, &data); 214800b99b8Sopenharmony_ci} 215800b99b8Sopenharmony_ciBENCHMARK(BenchmarkUnwindStackRemoteFramesCache);