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 32using namespace OHOS::HiviewDFX; 33using namespace std; 34 35static constexpr size_t TEST_MIN_UNWIND_FRAMES = 5; 36static constexpr size_t MAX_FRAMES = 32; 37 38struct UnwindData { 39 std::shared_ptr<unwindstack::Memory>& processMemory; 40 unwindstack::Maps* maps; 41 bool isFillFrames = false; 42}; 43 44NOINLINE static size_t TestFunc5(size_t (*func)(void*), void* data) 45{ 46 return func(data); 47} 48 49NOINLINE static size_t TestFunc4(size_t (*func)(void*), void* data) 50{ 51 return TestFunc5(func, data); 52} 53 54NOINLINE static size_t TestFunc3(size_t (*func)(void*), void* data) 55{ 56 return TestFunc4(func, data); 57} 58 59NOINLINE static size_t TestFunc2(size_t (*func)(void*), void* data) 60{ 61 return TestFunc3(func, data); 62} 63 64NOINLINE static size_t TestFunc1(size_t (*func)(void*), void* data) 65{ 66 return TestFunc2(func, data); 67} 68 69static 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 DFXLOGU("%{public}s frames.size: %{public}zu", __func__, unwSize); 82 if (dataPtr->isFillFrames) { 83 for (size_t i = 0; i < unwSize; ++i) { 84 auto str = unwinder.FormatFrame(i); 85 DFXLOGU("%{public}s frames: %{public}s", __func__, str.c_str()); 86 } 87 } 88 return unwSize; 89} 90 91static void Run(benchmark::State& state, size_t (*func)(void*), void* data) 92{ 93 DFXLOGU("++++++pid: %{public}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 DFXLOGU("------pid: %{public}d", getpid()); 100} 101 102/** 103* @tc.name: BenchmarkUnwindStackLocal 104* @tc.desc: UnwindStack local 105* @tc.type: FUNC 106*/ 107static 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} 118BENCHMARK(BenchmarkUnwindStackLocal); 119 120/** 121* @tc.name: BenchmarkUnwindStackLocalCache 122* @tc.desc: UnwindStack local cache 123* @tc.type: FUNC 124*/ 125static 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} 136BENCHMARK(BenchmarkUnwindStackLocalCache); 137 138/** 139* @tc.name: BenchmarkUnwindStackLocalFrames 140* @tc.desc: UnwindStack local frames 141* @tc.type: FUNC 142*/ 143static 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} 154BENCHMARK(BenchmarkUnwindStackLocalFrames); 155 156/** 157* @tc.name: BenchmarkUnwindStackLocalFramesCache 158* @tc.desc: UnwindStack local frames cache 159* @tc.type: FUNC 160*/ 161static 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} 172BENCHMARK(BenchmarkUnwindStackLocalFramesCache);