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);