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