• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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 
16 #include <benchmark/benchmark.h>
17 
18 #include <string>
19 #include <vector>
20 #include <sys/ptrace.h>
21 #include <unwindstack/Maps.h>
22 #include <unwindstack/Memory.h>
23 #include <unwindstack/Regs.h>
24 #include <unwindstack/Unwinder.h>
25 #include "MemoryRemote.h"
26 #include "pid_utils.h"
27 #include "dfx_define.h"
28 #include "dfx_log.h"
29 #include "dfx_test_util.h"
30 
31 using namespace OHOS::HiviewDFX;
32 using namespace std;
33 
34 static constexpr size_t TEST_MIN_UNWIND_FRAMES = 5;
35 static constexpr size_t MAX_FRAMES = 32;
36 
37 struct UnwindData {
38     bool isCache = false;
39     bool isFillFrames = false;
40 };
41 
TestFunc6(MAYBE_UNUSED void (* func)(void *),MAYBE_UNUSED volatile bool * ready)42 static void TestFunc6(MAYBE_UNUSED void (*func)(void*), MAYBE_UNUSED volatile bool* ready)
43 {
44     *ready = true;
45     while (true);
46     LOGE("Not be run here!!!");
47 }
48 
TestFunc5(void (* func)(void *),volatile bool * ready)49 static void TestFunc5(void (*func)(void*), volatile bool* ready)
50 {
51     return TestFunc6(func, ready);
52 }
53 
TestFunc4(void (* func)(void *),volatile bool * ready)54 static void TestFunc4(void (*func)(void*), volatile bool* ready)
55 {
56     return TestFunc5(func, ready);
57 }
58 
TestFunc3(void (* func)(void *),volatile bool * ready)59 static void TestFunc3(void (*func)(void*), volatile bool* ready)
60 {
61     return TestFunc4(func, ready);
62 }
63 
TestFunc2(void (* func)(void *),volatile bool * ready)64 static void TestFunc2(void (*func)(void*), volatile bool* ready)
65 {
66     return TestFunc3(func, ready);
67 }
68 
TestFunc1(void (* func)(void *),volatile bool * ready)69 static void TestFunc1(void (*func)(void*), volatile bool* ready)
70 {
71     return TestFunc2(func, ready);
72 }
73 
WaitForRemote(pid_t pid,volatile bool * readyPtr)74 static bool WaitForRemote(pid_t pid, volatile bool* readyPtr)
75 {
76     return PidUtils::WaitForPidState(pid, [pid, readyPtr]() {
77         unwindstack::MemoryRemote memory(pid);
78         bool ready;
79         uint64_t readyAddr = reinterpret_cast<uint64_t>(readyPtr);
80         if (memory.ReadFully(readyAddr, &ready, sizeof(ready)) && ready) {
81             return PidRunEnum::PID_RUN_PASS;
82         }
83         return PidRunEnum::PID_RUN_KEEP_GOING;
84     });
85 }
86 
RemoteFork()87 static pid_t RemoteFork()
88 {
89     static volatile bool ready = false;
90 
91     pid_t pid;
92     if ((pid = fork()) == 0) {
93         TestFunc1(nullptr, &ready);
94         _exit(0);
95     }
96     if (pid == -1) {
97         return -1;
98     }
99 
100     if (!WaitForRemote(pid, &ready)) {
101         LOGE("Failed to wait pid: %d", pid);
102         TestScopedPidReaper::Kill(pid);
103         return -1;
104     }
105     return pid;
106 }
107 
UnwindRemote(unwindstack::Unwinder unwinder,MAYBE_UNUSED UnwindData * dataPtr)108 static size_t UnwindRemote(unwindstack::Unwinder unwinder, MAYBE_UNUSED UnwindData* dataPtr)
109 {
110     if (dataPtr != nullptr) {
111         unwinder.SetResolveNames(dataPtr->isFillFrames);
112     }
113     unwinder.Unwind();
114     auto unwSize = unwinder.NumFrames();
115     LOGU("%s frames.size: %zu", __func__, unwSize);
116     if (dataPtr != nullptr && dataPtr->isFillFrames) {
117         for (size_t i = 0; i < unwSize; ++i) {
118             auto str = unwinder.FormatFrame(i);
119             LOGU("%s frames: %s", __func__, str.c_str());
120         }
121     }
122     return unwSize;
123 }
124 
Run(benchmark::State & state,void * data)125 static void Run(benchmark::State& state, void* data)
126 {
127     UnwindData* dataPtr = reinterpret_cast<UnwindData*>(data);
128     UnwindData unwindData;
129     if (dataPtr != nullptr) {
130         unwindData.isCache = dataPtr->isCache;
131     }
132 
133     pid_t pid = RemoteFork();
134     if (pid == -1) {
135         state.SkipWithError("Failed to fork remote process.");
136         return;
137     }
138     LOGU("pid: %d", pid);
139     TestScopedPidReaper reap(pid);
140 
141     std::shared_ptr<unwindstack::Memory> processMemory;
142     if (unwindData.isCache) {
143         processMemory = unwindstack::Memory::CreateProcessMemoryCached(pid);
144     } else {
145         processMemory = unwindstack::Memory::CreateProcessMemory(pid);
146     }
147     unwindstack::RemoteMaps maps(pid);
148     if (!maps.Parse()) {
149         state.SkipWithError("Failed to parse maps.");
150     }
151 
152     for (const auto& _ : state) {
153         std::unique_ptr<unwindstack::Regs> regs(unwindstack::Regs::RemoteGet(pid));
154         unwindstack::Unwinder unwinder(MAX_FRAMES, &maps, regs.get(), processMemory);
155         auto unwSize = UnwindRemote(unwinder, dataPtr);
156         if (unwSize < TEST_MIN_UNWIND_FRAMES) {
157             state.SkipWithError("Failed to unwind.");
158         }
159     }
160     LOGU("Detach pid: %d", pid);
161     ptrace(PTRACE_DETACH, pid, 0, 0);
162 }
163 
164 /**
165 * @tc.name: BenchmarkUnwindStackRemote
166 * @tc.desc: UnwindStack remote
167 * @tc.type: FUNC
168 */
BenchmarkUnwindStackRemote(benchmark::State & state)169 static void BenchmarkUnwindStackRemote(benchmark::State& state)
170 {
171     UnwindData data;
172     data.isCache = false;
173     Run(state, &data);
174 }
175 BENCHMARK(BenchmarkUnwindStackRemote);
176 
177 /**
178 * @tc.name: BenchmarkUnwindStackRemoteCache
179 * @tc.desc: UnwindStack remote cache
180 * @tc.type: FUNC
181 */
BenchmarkUnwindStackRemoteCache(benchmark::State & state)182 static void BenchmarkUnwindStackRemoteCache(benchmark::State& state)
183 {
184     UnwindData data;
185     data.isCache = true;
186     Run(state, &data);
187 }
188 BENCHMARK(BenchmarkUnwindStackRemoteCache);
189 
190 /**
191 * @tc.name: BenchmarkUnwindStackRemoteFrames
192 * @tc.desc: UnwindStack remote frames
193 * @tc.type: FUNC
194 */
BenchmarkUnwindStackRemoteFrames(benchmark::State & state)195 static void BenchmarkUnwindStackRemoteFrames(benchmark::State& state)
196 {
197     UnwindData data;
198     data.isCache = false;
199     data.isFillFrames = true;
200     Run(state, &data);
201 }
202 BENCHMARK(BenchmarkUnwindStackRemoteFrames);
203 
204 /**
205 * @tc.name: BenchmarkUnwindStackRemoteFramesCache
206 * @tc.desc: UnwindStack remote frames cache
207 * @tc.type: FUNC
208 */
BenchmarkUnwindStackRemoteFramesCache(benchmark::State & state)209 static void BenchmarkUnwindStackRemoteFramesCache(benchmark::State& state)
210 {
211     UnwindData data;
212     data.isCache = true;
213     data.isFillFrames = true;
214     Run(state, &data);
215 }
216 BENCHMARK(BenchmarkUnwindStackRemoteFramesCache);