1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <benchmark/benchmark.h>
17
18 #include <memory>
19 #include <securec.h>
20 #include <string>
21 #include <vector>
22 #include <unistd.h>
23 #include <unwindstack/Elf.h>
24 #include <unwindstack/Maps.h>
25 #include <unwindstack/Memory.h>
26 #include <unwindstack/Regs.h>
27 #include <unwindstack/RegsGetLocal.h>
28 #include <unwindstack/Unwinder.h>
29 #include "dfx_define.h"
30 #include "dfx_log.h"
31
32 using namespace OHOS::HiviewDFX;
33 using namespace std;
34
35 static constexpr size_t TEST_MIN_UNWIND_FRAMES = 5;
36 static constexpr size_t MAX_FRAMES = 32;
37
38 struct UnwindData {
39 std::shared_ptr<unwindstack::Memory>& processMemory;
40 unwindstack::Maps* maps;
41 bool isFillFrames = false;
42 };
43
TestFunc5(size_t (* func)(void *),void * data)44 NOINLINE static size_t TestFunc5(size_t (*func)(void*), void* data)
45 {
46 return func(data);
47 }
48
TestFunc4(size_t (* func)(void *),void * data)49 NOINLINE static size_t TestFunc4(size_t (*func)(void*), void* data)
50 {
51 return TestFunc5(func, data);
52 }
53
TestFunc3(size_t (* func)(void *),void * data)54 NOINLINE static size_t TestFunc3(size_t (*func)(void*), void* data)
55 {
56 return TestFunc4(func, data);
57 }
58
TestFunc2(size_t (* func)(void *),void * data)59 NOINLINE static size_t TestFunc2(size_t (*func)(void*), void* data)
60 {
61 return TestFunc3(func, data);
62 }
63
TestFunc1(size_t (* func)(void *),void * data)64 NOINLINE static size_t TestFunc1(size_t (*func)(void*), void* data)
65 {
66 return TestFunc2(func, data);
67 }
68
UnwindLocal(MAYBE_UNUSED void * data)69 static size_t UnwindLocal(MAYBE_UNUSED void* data)
70 {
71 UnwindData* dataPtr = reinterpret_cast<UnwindData*>(data);
72 if (dataPtr == nullptr) {
73 return 0;
74 }
75 std::unique_ptr<unwindstack::Regs> regs(unwindstack::Regs::CreateFromLocal());
76 unwindstack::RegsGetLocal(regs.get());
77 unwindstack::Unwinder unwinder(MAX_FRAMES, dataPtr->maps, regs.get(), dataPtr->processMemory);
78 unwinder.SetResolveNames(dataPtr->isFillFrames);
79 unwinder.Unwind();
80 auto unwSize = unwinder.NumFrames();
81 LOGU("%s frames.size: %zu", __func__, unwSize);
82 if (dataPtr->isFillFrames) {
83 for (size_t i = 0; i < unwSize; ++i) {
84 auto str = unwinder.FormatFrame(i);
85 LOGU("%s frames: %s", __func__, str.c_str());
86 }
87 }
88 return unwSize;
89 }
90
Run(benchmark::State & state,size_t (* func)(void *),void * data)91 static void Run(benchmark::State& state, size_t (*func)(void*), void* data)
92 {
93 LOGU("++++++pid: %d", getpid());
94 for (const auto& _ : state) {
95 if (TestFunc1(func, data) < TEST_MIN_UNWIND_FRAMES) {
96 state.SkipWithError("Failed to unwind.");
97 }
98 }
99 LOGU("------pid: %d", getpid());
100 }
101
102 /**
103 * @tc.name: BenchmarkUnwindStackLocal
104 * @tc.desc: UnwindStack local
105 * @tc.type: FUNC
106 */
BenchmarkUnwindStackLocal(benchmark::State & state)107 static void BenchmarkUnwindStackLocal(benchmark::State& state)
108 {
109 auto processMemory = unwindstack::Memory::CreateProcessMemory(getpid());
110 unwindstack::LocalMaps maps;
111 if (!maps.Parse()) {
112 state.SkipWithError("Failed to parse local maps.");
113 }
114
115 UnwindData data = {.processMemory = processMemory, .maps = &maps, .isFillFrames = false};
116 Run(state, UnwindLocal, &data);
117 }
118 BENCHMARK(BenchmarkUnwindStackLocal);
119
120 /**
121 * @tc.name: BenchmarkUnwindStackLocalCache
122 * @tc.desc: UnwindStack local cache
123 * @tc.type: FUNC
124 */
BenchmarkUnwindStackLocalCache(benchmark::State & state)125 static void BenchmarkUnwindStackLocalCache(benchmark::State& state)
126 {
127 auto processMemory = unwindstack::Memory::CreateProcessMemoryCached(getpid());
128 unwindstack::LocalMaps maps;
129 if (!maps.Parse()) {
130 state.SkipWithError("Failed to parse local maps.");
131 }
132
133 UnwindData data = {.processMemory = processMemory, .maps = &maps, .isFillFrames = false};
134 Run(state, UnwindLocal, &data);
135 }
136 BENCHMARK(BenchmarkUnwindStackLocalCache);
137
138 /**
139 * @tc.name: BenchmarkUnwindStackLocalFrames
140 * @tc.desc: UnwindStack local frames
141 * @tc.type: FUNC
142 */
BenchmarkUnwindStackLocalFrames(benchmark::State & state)143 static void BenchmarkUnwindStackLocalFrames(benchmark::State& state)
144 {
145 auto processMemory = unwindstack::Memory::CreateProcessMemory(getpid());
146 unwindstack::LocalMaps maps;
147 if (!maps.Parse()) {
148 state.SkipWithError("Failed to parse local maps.");
149 }
150
151 UnwindData data = {.processMemory = processMemory, .maps = &maps, .isFillFrames = true};
152 Run(state, UnwindLocal, &data);
153 }
154 BENCHMARK(BenchmarkUnwindStackLocalFrames);
155
156 /**
157 * @tc.name: BenchmarkUnwindStackLocalFramesCache
158 * @tc.desc: UnwindStack local frames cache
159 * @tc.type: FUNC
160 */
BenchmarkUnwindStackLocalFramesCache(benchmark::State & state)161 static void BenchmarkUnwindStackLocalFramesCache(benchmark::State& state)
162 {
163 auto processMemory = unwindstack::Memory::CreateProcessMemoryCached(getpid());
164 unwindstack::LocalMaps maps;
165 if (!maps.Parse()) {
166 state.SkipWithError("Failed to parse local maps.");
167 }
168
169 UnwindData data = {.processMemory = processMemory, .maps = &maps, .isFillFrames = true};
170 Run(state, UnwindLocal, &data);
171 }
172 BENCHMARK(BenchmarkUnwindStackLocalFramesCache);