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/LocalUnwinder.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
32 constexpr size_t kMaxFrames = 32;
33
34 struct UnwindData {
35 std::shared_ptr<unwindstack::Memory>& process_memory;
36 unwindstack::Maps* maps;
37 bool resolve_names;
38 };
39
LocalCall5(size_t (* func)(void *),void * data)40 size_t LocalCall5(size_t (*func)(void*), void* data) {
41 return func(data);
42 }
43
LocalCall4(size_t (* func)(void *),void * data)44 size_t LocalCall4(size_t (*func)(void*), void* data) {
45 return LocalCall5(func, data);
46 }
47
LocalCall3(size_t (* func)(void *),void * data)48 size_t LocalCall3(size_t (*func)(void*), void* data) {
49 return LocalCall4(func, data);
50 }
51
LocalCall2(size_t (* func)(void *),void * data)52 size_t LocalCall2(size_t (*func)(void*), void* data) {
53 return LocalCall3(func, data);
54 }
55
LocalCall1(size_t (* func)(void *),void * data)56 size_t LocalCall1(size_t (*func)(void*), void* data) {
57 return LocalCall2(func, data);
58 }
59
Run(benchmark::State & state,size_t (* func)(void *),void * data)60 static void Run(benchmark::State& state, size_t (*func)(void*), void* data) {
61 for (auto _ : state) {
62 if (LocalCall1(func, data) < 5) {
63 state.SkipWithError("Failed to unwind.");
64 }
65 }
66 }
67
Unwind(void * data_ptr)68 static size_t Unwind(void* data_ptr) {
69 UnwindData* data = reinterpret_cast<UnwindData*>(data_ptr);
70 std::unique_ptr<unwindstack::Regs> regs(unwindstack::Regs::CreateFromLocal());
71 unwindstack::RegsGetLocal(regs.get());
72 unwindstack::Unwinder unwinder(kMaxFrames, data->maps, regs.get(), data->process_memory);
73 unwinder.SetResolveNames(data->resolve_names);
74 unwinder.Unwind();
75 return unwinder.NumFrames();
76 }
77
LocalUnwind(void * unwind_ptr)78 static size_t LocalUnwind(void* unwind_ptr) {
79 unwindstack::LocalUnwinder* unwinder = reinterpret_cast<unwindstack::LocalUnwinder*>(unwind_ptr);
80 std::vector<unwindstack::LocalFrameData> frame_info;
81 unwinder->Unwind(&frame_info, kMaxFrames);
82 return frame_info.size();
83 }
84
BM_local_unwind_uncached_process_memory(benchmark::State & state)85 static void BM_local_unwind_uncached_process_memory(benchmark::State& state) {
86 auto process_memory = unwindstack::Memory::CreateProcessMemory(getpid());
87 unwindstack::LocalMaps maps;
88 if (!maps.Parse()) {
89 state.SkipWithError("Failed to parse local maps.");
90 }
91
92 UnwindData data = {.process_memory = process_memory, .maps = &maps, .resolve_names = true};
93 Run(state, Unwind, &data);
94 }
95 BENCHMARK(BM_local_unwind_uncached_process_memory);
96
BM_local_unwind_cached_process_memory(benchmark::State & state)97 static void BM_local_unwind_cached_process_memory(benchmark::State& state) {
98 auto process_memory = unwindstack::Memory::CreateProcessMemoryCached(getpid());
99 unwindstack::LocalMaps maps;
100 if (!maps.Parse()) {
101 state.SkipWithError("Failed to parse local maps.");
102 }
103
104 UnwindData data = {.process_memory = process_memory, .maps = &maps, .resolve_names = true};
105 Run(state, Unwind, &data);
106 }
107 BENCHMARK(BM_local_unwind_cached_process_memory);
108
BM_local_unwind_local_updatable_maps_uncached(benchmark::State & state)109 static void BM_local_unwind_local_updatable_maps_uncached(benchmark::State& state) {
110 auto process_memory = unwindstack::Memory::CreateProcessMemory(getpid());
111 unwindstack::LocalUpdatableMaps maps;
112 if (!maps.Parse()) {
113 state.SkipWithError("Failed to parse local maps.");
114 }
115
116 UnwindData data = {.process_memory = process_memory, .maps = &maps, .resolve_names = true};
117 Run(state, Unwind, &data);
118 }
119 BENCHMARK(BM_local_unwind_local_updatable_maps_uncached);
120
BM_local_unwind_local_updatable_maps_cached(benchmark::State & state)121 static void BM_local_unwind_local_updatable_maps_cached(benchmark::State& state) {
122 auto process_memory = unwindstack::Memory::CreateProcessMemoryCached(getpid());
123 unwindstack::LocalUpdatableMaps maps;
124 if (!maps.Parse()) {
125 state.SkipWithError("Failed to parse local maps.");
126 }
127
128 UnwindData data = {.process_memory = process_memory, .maps = &maps, .resolve_names = true};
129 Run(state, Unwind, &data);
130 }
131 BENCHMARK(BM_local_unwind_local_updatable_maps_cached);
132
BM_local_unwind_local_updatable_maps_thread_cached(benchmark::State & state)133 static void BM_local_unwind_local_updatable_maps_thread_cached(benchmark::State& state) {
134 auto process_memory = unwindstack::Memory::CreateProcessMemoryThreadCached(getpid());
135 unwindstack::LocalUpdatableMaps maps;
136 if (!maps.Parse()) {
137 state.SkipWithError("Failed to parse local maps.");
138 }
139
140 UnwindData data = {.process_memory = process_memory, .maps = &maps, .resolve_names = true};
141 Run(state, Unwind, &data);
142 }
143 BENCHMARK(BM_local_unwind_local_updatable_maps_thread_cached);
144
BM_local_unwind_local_unwinder(benchmark::State & state)145 static void BM_local_unwind_local_unwinder(benchmark::State& state) {
146 unwindstack::LocalUnwinder unwinder;
147 if (!unwinder.Init()) {
148 state.SkipWithError("Failed to init local unwinder.");
149 }
150
151 Run(state, LocalUnwind, &unwinder);
152 }
153 BENCHMARK(BM_local_unwind_local_unwinder);
154
BM_local_unwind_uncached_process_memory_no_func_names(benchmark::State & state)155 static void BM_local_unwind_uncached_process_memory_no_func_names(benchmark::State& state) {
156 auto process_memory = unwindstack::Memory::CreateProcessMemory(getpid());
157 unwindstack::LocalMaps maps;
158 if (!maps.Parse()) {
159 state.SkipWithError("Failed to parse local maps.");
160 }
161
162 UnwindData data = {.process_memory = process_memory, .maps = &maps, .resolve_names = false};
163 Run(state, Unwind, &data);
164 }
165 BENCHMARK(BM_local_unwind_uncached_process_memory_no_func_names);
166
BM_local_unwind_cached_process_memory_no_func_names(benchmark::State & state)167 static void BM_local_unwind_cached_process_memory_no_func_names(benchmark::State& state) {
168 auto process_memory = unwindstack::Memory::CreateProcessMemoryCached(getpid());
169 unwindstack::LocalMaps maps;
170 if (!maps.Parse()) {
171 state.SkipWithError("Failed to parse local maps.");
172 }
173
174 UnwindData data = {.process_memory = process_memory, .maps = &maps, .resolve_names = false};
175 Run(state, Unwind, &data);
176 }
177 BENCHMARK(BM_local_unwind_cached_process_memory_no_func_names);
178
BM_local_unwind_local_updatable_maps_uncached_no_func_names(benchmark::State & state)179 static void BM_local_unwind_local_updatable_maps_uncached_no_func_names(benchmark::State& state) {
180 auto process_memory = unwindstack::Memory::CreateProcessMemory(getpid());
181 unwindstack::LocalUpdatableMaps maps;
182 if (!maps.Parse()) {
183 state.SkipWithError("Failed to parse local maps.");
184 }
185
186 UnwindData data = {.process_memory = process_memory, .maps = &maps, .resolve_names = false};
187 Run(state, Unwind, &data);
188 }
189 BENCHMARK(BM_local_unwind_local_updatable_maps_uncached_no_func_names);
190
BM_local_unwind_local_updatable_maps_cached_no_func_names(benchmark::State & state)191 static void BM_local_unwind_local_updatable_maps_cached_no_func_names(benchmark::State& state) {
192 auto process_memory = unwindstack::Memory::CreateProcessMemoryCached(getpid());
193 unwindstack::LocalUpdatableMaps maps;
194 if (!maps.Parse()) {
195 state.SkipWithError("Failed to parse local maps.");
196 }
197
198 UnwindData data = {.process_memory = process_memory, .maps = &maps, .resolve_names = false};
199 Run(state, Unwind, &data);
200 }
201 BENCHMARK(BM_local_unwind_local_updatable_maps_cached_no_func_names);
202