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