xref: /aosp_15_r20/system/unwinding/libunwindstack/benchmarks/remote_unwind_benchmarks.cpp (revision eb293b8f56ee8303637c5595cfcdeef8039e85c6)
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