xref: /aosp_15_r20/system/unwinding/libunwindstack/benchmarks/local_unwind_benchmarks.cpp (revision eb293b8f56ee8303637c5595cfcdeef8039e85c6)
1 /*
2  * Copyright (C) 2018 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 <stdint.h>
18 
19 #include <memory>
20 
21 #include <benchmark/benchmark.h>
22 
23 #include <android-base/strings.h>
24 
25 #include <unwindstack/AndroidUnwinder.h>
26 #include <unwindstack/Maps.h>
27 #include <unwindstack/Memory.h>
28 #include <unwindstack/Regs.h>
29 #include <unwindstack/RegsGetLocal.h>
30 #include <unwindstack/Unwinder.h>
31 #include "MemoryLocalUnsafe.h"
32 
33 constexpr size_t kMaxFrames = 32;
34 
35 struct UnwindData {
36   std::shared_ptr<unwindstack::Memory>& process_memory;
37   unwindstack::Maps* maps;
38   bool resolve_names;
39 };
40 
LocalCall5(size_t (* func)(void *),void * data)41 size_t LocalCall5(size_t (*func)(void*), void* data) {
42   return func(data);
43 }
44 
LocalCall4(size_t (* func)(void *),void * data)45 size_t LocalCall4(size_t (*func)(void*), void* data) {
46   return LocalCall5(func, data);
47 }
48 
LocalCall3(size_t (* func)(void *),void * data)49 size_t LocalCall3(size_t (*func)(void*), void* data) {
50   return LocalCall4(func, data);
51 }
52 
LocalCall2(size_t (* func)(void *),void * data)53 size_t LocalCall2(size_t (*func)(void*), void* data) {
54   return LocalCall3(func, data);
55 }
56 
LocalCall1(size_t (* func)(void *),void * data)57 size_t LocalCall1(size_t (*func)(void*), void* data) {
58   return LocalCall2(func, data);
59 }
60 
Run(benchmark::State & state,size_t (* func)(void *),void * data)61 static void Run(benchmark::State& state, size_t (*func)(void*), void* data) {
62   for (const auto& _ : state) {
63     if (LocalCall1(func, data) < 5) {
64       state.SkipWithError("Failed to unwind.");
65     }
66   }
67 }
68 
Unwind(void * data_ptr)69 static size_t Unwind(void* data_ptr) {
70   UnwindData* data = reinterpret_cast<UnwindData*>(data_ptr);
71   std::unique_ptr<unwindstack::Regs> regs(unwindstack::Regs::CreateFromLocal());
72   unwindstack::RegsGetLocal(regs.get());
73   unwindstack::Unwinder unwinder(kMaxFrames, data->maps, regs.get(), data->process_memory);
74   unwinder.SetResolveNames(data->resolve_names);
75   unwinder.Unwind();
76   return unwinder.NumFrames();
77 }
78 
BM_local_unwind_uncached_process_memory(benchmark::State & state)79 static void BM_local_unwind_uncached_process_memory(benchmark::State& state) {
80   auto process_memory = unwindstack::Memory::CreateProcessMemory(getpid());
81   unwindstack::LocalMaps maps;
82   if (!maps.Parse()) {
83     state.SkipWithError("Failed to parse local maps.");
84   }
85 
86   UnwindData data = {.process_memory = process_memory, .maps = &maps, .resolve_names = true};
87   Run(state, Unwind, &data);
88 }
89 BENCHMARK(BM_local_unwind_uncached_process_memory);
90 
BM_local_unwind_cached_process_memory(benchmark::State & state)91 static void BM_local_unwind_cached_process_memory(benchmark::State& state) {
92   auto process_memory = unwindstack::Memory::CreateProcessMemoryCached(getpid());
93   unwindstack::LocalMaps maps;
94   if (!maps.Parse()) {
95     state.SkipWithError("Failed to parse local maps.");
96   }
97 
98   UnwindData data = {.process_memory = process_memory, .maps = &maps, .resolve_names = true};
99   Run(state, Unwind, &data);
100 }
101 BENCHMARK(BM_local_unwind_cached_process_memory);
102 
BM_local_android_unwind_uncached_process_memory(benchmark::State & state)103 static void BM_local_android_unwind_uncached_process_memory(benchmark::State& state) {
104   auto process_memory = unwindstack::Memory::CreateProcessMemory(getpid());
105   unwindstack::AndroidLocalUnwinder unwinder(process_memory);
106   unwindstack::ErrorData error;
107   if (!unwinder.Initialize(error)) {
108     state.SkipWithError("Failed to initialize.");
109   }
110 
111   for (const auto& _ : state) {
112     if (LocalCall1(
113             [](void* u) -> size_t {
114               unwindstack::AndroidLocalUnwinder* unwinder =
115                   reinterpret_cast<unwindstack::AndroidLocalUnwinder*>(u);
116               unwindstack::AndroidUnwinderData data;
117               unwinder->Unwind(data);
118               return data.frames.size();
119             },
120             &unwinder) < 5) {
121       state.SkipWithError("Failed to unwind.");
122     }
123   }
124 }
125 BENCHMARK(BM_local_android_unwind_uncached_process_memory);
126 
BM_local_android_unwind_cached_process_memory(benchmark::State & state)127 static void BM_local_android_unwind_cached_process_memory(benchmark::State& state) {
128   auto process_memory = unwindstack::Memory::CreateProcessMemoryCached(getpid());
129   unwindstack::AndroidLocalUnwinder unwinder(process_memory);
130   unwindstack::ErrorData error;
131   if (!unwinder.Initialize(error)) {
132     state.SkipWithError("Failed to initialize.");
133   }
134 
135   for (const auto& _ : state) {
136     if (LocalCall1(
137             [](void* u) -> size_t {
138               unwindstack::AndroidLocalUnwinder* unwinder =
139                   reinterpret_cast<unwindstack::AndroidLocalUnwinder*>(u);
140               unwindstack::AndroidUnwinderData data;
141               unwinder->Unwind(data);
142               return data.frames.size();
143             },
144             &unwinder) < 5) {
145       state.SkipWithError("Failed to unwind.");
146     }
147   }
148 }
149 BENCHMARK(BM_local_android_unwind_cached_process_memory);
150 
BM_local_unwind_local_updatable_maps_uncached(benchmark::State & state)151 static void BM_local_unwind_local_updatable_maps_uncached(benchmark::State& state) {
152   auto process_memory = unwindstack::Memory::CreateProcessMemory(getpid());
153   unwindstack::LocalUpdatableMaps maps;
154   if (!maps.Parse()) {
155     state.SkipWithError("Failed to parse local maps.");
156   }
157 
158   UnwindData data = {.process_memory = process_memory, .maps = &maps, .resolve_names = true};
159   Run(state, Unwind, &data);
160 }
161 BENCHMARK(BM_local_unwind_local_updatable_maps_uncached);
162 
BM_local_unwind_local_updatable_maps_cached(benchmark::State & state)163 static void BM_local_unwind_local_updatable_maps_cached(benchmark::State& state) {
164   auto process_memory = unwindstack::Memory::CreateProcessMemoryCached(getpid());
165   unwindstack::LocalUpdatableMaps maps;
166   if (!maps.Parse()) {
167     state.SkipWithError("Failed to parse local maps.");
168   }
169 
170   UnwindData data = {.process_memory = process_memory, .maps = &maps, .resolve_names = true};
171   Run(state, Unwind, &data);
172 }
173 BENCHMARK(BM_local_unwind_local_updatable_maps_cached);
174 
BM_local_unwind_local_updatable_maps_thread_cached(benchmark::State & state)175 static void BM_local_unwind_local_updatable_maps_thread_cached(benchmark::State& state) {
176   auto process_memory = unwindstack::Memory::CreateProcessMemoryThreadCached(getpid());
177   unwindstack::LocalUpdatableMaps maps;
178   if (!maps.Parse()) {
179     state.SkipWithError("Failed to parse local maps.");
180   }
181 
182   UnwindData data = {.process_memory = process_memory, .maps = &maps, .resolve_names = true};
183   Run(state, Unwind, &data);
184 }
185 BENCHMARK(BM_local_unwind_local_updatable_maps_thread_cached);
186 
BM_local_unwind_uncached_process_memory_no_func_names(benchmark::State & state)187 static void BM_local_unwind_uncached_process_memory_no_func_names(benchmark::State& state) {
188   auto process_memory = unwindstack::Memory::CreateProcessMemory(getpid());
189   unwindstack::LocalMaps maps;
190   if (!maps.Parse()) {
191     state.SkipWithError("Failed to parse local maps.");
192   }
193 
194   UnwindData data = {.process_memory = process_memory, .maps = &maps, .resolve_names = false};
195   Run(state, Unwind, &data);
196 }
197 BENCHMARK(BM_local_unwind_uncached_process_memory_no_func_names);
198 
BM_local_unwind_cached_process_memory_no_func_names(benchmark::State & state)199 static void BM_local_unwind_cached_process_memory_no_func_names(benchmark::State& state) {
200   auto process_memory = unwindstack::Memory::CreateProcessMemoryCached(getpid());
201   unwindstack::LocalMaps maps;
202   if (!maps.Parse()) {
203     state.SkipWithError("Failed to parse local maps.");
204   }
205 
206   UnwindData data = {.process_memory = process_memory, .maps = &maps, .resolve_names = false};
207   Run(state, Unwind, &data);
208 }
209 BENCHMARK(BM_local_unwind_cached_process_memory_no_func_names);
210 
BM_local_unwind_local_updatable_maps_uncached_no_func_names(benchmark::State & state)211 static void BM_local_unwind_local_updatable_maps_uncached_no_func_names(benchmark::State& state) {
212   auto process_memory = unwindstack::Memory::CreateProcessMemory(getpid());
213   unwindstack::LocalUpdatableMaps maps;
214   if (!maps.Parse()) {
215     state.SkipWithError("Failed to parse local maps.");
216   }
217 
218   UnwindData data = {.process_memory = process_memory, .maps = &maps, .resolve_names = false};
219   Run(state, Unwind, &data);
220 }
221 BENCHMARK(BM_local_unwind_local_updatable_maps_uncached_no_func_names);
222 
BM_local_unwind_local_updatable_maps_cached_no_func_names(benchmark::State & state)223 static void BM_local_unwind_local_updatable_maps_cached_no_func_names(benchmark::State& state) {
224   auto process_memory = unwindstack::Memory::CreateProcessMemoryCached(getpid());
225   unwindstack::LocalUpdatableMaps maps;
226   if (!maps.Parse()) {
227     state.SkipWithError("Failed to parse local maps.");
228   }
229 
230   UnwindData data = {.process_memory = process_memory, .maps = &maps, .resolve_names = false};
231   Run(state, Unwind, &data);
232 }
233 BENCHMARK(BM_local_unwind_local_updatable_maps_cached_no_func_names);
234 
BM_local_unwind_uncached_process_memory_unsafe_reads(benchmark::State & state)235 static void BM_local_unwind_uncached_process_memory_unsafe_reads(benchmark::State& state) {
236   std::shared_ptr<unwindstack::Memory> process_memory(new unwindstack::MemoryLocalUnsafe());
237   unwindstack::LocalMaps maps;
238   if (!maps.Parse()) {
239     state.SkipWithError("Failed to parse local maps.");
240   }
241 
242   UnwindData data = {.process_memory = process_memory, .maps = &maps, .resolve_names = true};
243   Run(state, Unwind, &data);
244 }
245 BENCHMARK(BM_local_unwind_uncached_process_memory_unsafe_reads);
246