1 /*
2 * Copyright (C) 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <errno.h>
18 #include <stdint.h>
19 #include <stdio.h>
20 #include <sys/ptrace.h>
21 #include <unistd.h>
22
23 #include <memory>
24
25 #include <benchmark/benchmark.h>
26
27 #include <unwindstack/AndroidUnwinder.h>
28 #include <unwindstack/Maps.h>
29 #include <unwindstack/Memory.h>
30 #include <unwindstack/Regs.h>
31 #include <unwindstack/Unwinder.h>
32
33 #include "MemoryRemote.h"
34 #include "PidUtils.h"
35 #include "tests/TestUtils.h"
36
WaitForRemote(pid_t pid,volatile bool * ready_ptr)37 static bool WaitForRemote(pid_t pid, volatile bool* ready_ptr) {
38 return unwindstack::WaitForPidState(pid, [pid, ready_ptr]() {
39 unwindstack::MemoryRemote memory(pid);
40 bool ready;
41 uint64_t ready_addr = reinterpret_cast<uint64_t>(ready_ptr);
42 if (memory.ReadFully(ready_addr, &ready, sizeof(ready)) && ready) {
43 return unwindstack::PID_RUN_PASS;
44 }
45 return unwindstack::PID_RUN_KEEP_GOING;
46 });
47 }
48
RemoteCall6(volatile bool * ready)49 size_t RemoteCall6(volatile bool* ready) {
50 *ready = true;
51 while (true)
52 ;
53 }
54
RemoteCall5(volatile bool * ready)55 size_t RemoteCall5(volatile bool* ready) {
56 return RemoteCall6(ready);
57 }
58
RemoteCall4(volatile bool * ready)59 size_t RemoteCall4(volatile bool* ready) {
60 return RemoteCall5(ready);
61 }
62
RemoteCall3(volatile bool * ready)63 size_t RemoteCall3(volatile bool* ready) {
64 return RemoteCall4(ready);
65 }
66
RemoteCall2(volatile bool * ready)67 size_t RemoteCall2(volatile bool* ready) {
68 return RemoteCall3(ready);
69 }
70
RemoteCall1(volatile bool * ready)71 size_t RemoteCall1(volatile bool* ready) {
72 return RemoteCall2(ready);
73 }
74
StartRemoteRun()75 static pid_t StartRemoteRun() {
76 static volatile bool ready = false;
77
78 pid_t pid;
79 if ((pid = fork()) == 0) {
80 RemoteCall1(&ready);
81 exit(0);
82 }
83 if (pid == -1) {
84 return -1;
85 }
86
87 if (!WaitForRemote(pid, &ready)) {
88 kill(pid, SIGKILL);
89 waitpid(pid, nullptr, 0);
90 return -1;
91 }
92
93 return pid;
94 }
95
RemoteUnwind(benchmark::State & state,bool cached)96 static void RemoteUnwind(benchmark::State& state, bool cached) {
97 pid_t pid = StartRemoteRun();
98 if (pid == -1) {
99 state.SkipWithError("Failed to start remote process.");
100 }
101 unwindstack::TestScopedPidReaper reap(pid);
102
103 std::shared_ptr<unwindstack::Memory> process_memory;
104 if (cached) {
105 process_memory = unwindstack::Memory::CreateProcessMemoryCached(pid);
106 } else {
107 process_memory = unwindstack::Memory::CreateProcessMemory(pid);
108 }
109 unwindstack::RemoteMaps maps(pid);
110 if (!maps.Parse()) {
111 state.SkipWithError("Failed to parse maps.");
112 }
113
114 for (const auto& _ : state) {
115 std::unique_ptr<unwindstack::Regs> regs(unwindstack::Regs::RemoteGet(pid));
116 unwindstack::Unwinder unwinder(32, &maps, regs.get(), process_memory);
117 unwinder.Unwind();
118 if (unwinder.NumFrames() < 5) {
119 state.SkipWithError("Failed to unwind properly.");
120 }
121 }
122
123 ptrace(PTRACE_DETACH, pid, 0, 0);
124 }
125
BM_remote_unwind_uncached(benchmark::State & state)126 static void BM_remote_unwind_uncached(benchmark::State& state) {
127 RemoteUnwind(state, false);
128 }
129 BENCHMARK(BM_remote_unwind_uncached);
130
BM_remote_unwind_cached(benchmark::State & state)131 static void BM_remote_unwind_cached(benchmark::State& state) {
132 RemoteUnwind(state, true);
133 }
134 BENCHMARK(BM_remote_unwind_cached);
135
RemoteAndroidUnwind(benchmark::State & state,bool cached)136 static void RemoteAndroidUnwind(benchmark::State& state, bool cached) {
137 pid_t pid = StartRemoteRun();
138 if (pid == -1) {
139 state.SkipWithError("Failed to start remote process.");
140 }
141 unwindstack::TestScopedPidReaper reap(pid);
142
143 std::shared_ptr<unwindstack::Memory> process_memory;
144 if (cached) {
145 process_memory = unwindstack::Memory::CreateProcessMemoryCached(pid);
146 } else {
147 process_memory = unwindstack::Memory::CreateProcessMemory(pid);
148 }
149 unwindstack::AndroidRemoteUnwinder unwinder(pid, process_memory);
150 unwindstack::ErrorData error;
151 if (!unwinder.Initialize(error)) {
152 state.SkipWithError("Failed to initialize unwinder.");
153 }
154
155 for (const auto& _ : state) {
156 unwindstack::AndroidUnwinderData data;
157 if (!unwinder.Unwind(data) || data.frames.size() < 5) {
158 state.SkipWithError("Failed to unwind properly.");
159 }
160 }
161
162 ptrace(PTRACE_DETACH, pid, 0, 0);
163 }
164
BM_remote_android_unwind_uncached(benchmark::State & state)165 static void BM_remote_android_unwind_uncached(benchmark::State& state) {
166 RemoteAndroidUnwind(state, true);
167 }
168 BENCHMARK(BM_remote_android_unwind_uncached);
169
BM_remote_android_unwind_cached(benchmark::State & state)170 static void BM_remote_android_unwind_cached(benchmark::State& state) {
171 RemoteAndroidUnwind(state, true);
172 }
173 BENCHMARK(BM_remote_android_unwind_cached);
174