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 <securec.h>
19#include <string>
20#include <vector>
21#include <unistd.h>
22#include "dfx_define.h"
23#include "dfx_log.h"
24#include <libunwind.h>
25#include "dfx_test_util.h"
26
27using namespace OHOS::HiviewDFX;
28using namespace std;
29
30static constexpr size_t TEST_MIN_UNWIND_FRAMES = 5;
31
32NOINLINE static size_t TestFunc5(size_t (*func)(void))
33{
34    return func();
35}
36
37NOINLINE static size_t TestFunc4(size_t (*func)(void))
38{
39    return TestFunc5(func);
40}
41
42NOINLINE static size_t TestFunc3(size_t (*func)(void))
43{
44    return TestFunc4(func);
45}
46
47NOINLINE static size_t TestFunc2(size_t (*func)(void))
48{
49    return TestFunc3(func);
50}
51
52NOINLINE static size_t TestFunc1(size_t (*func)(void))
53{
54    return TestFunc2(func);
55}
56
57static size_t UnwindLocal()
58{
59    unw_context_t context;
60    (void)memset_s(&context, sizeof(unw_context_t), 0, sizeof(unw_context_t));
61    unw_getcontext(&context);
62
63    unw_cursor_t cursor;
64    unw_init_local(&cursor, &context);
65
66    std::vector<unw_word_t> pcs;
67    size_t index = 0;
68    unw_word_t pc = 0;
69    unw_word_t prevPc = 0;
70    do {
71        if ((unw_get_reg(&cursor, UNW_REG_IP, (unw_word_t*)(&(pc)))) || (prevPc == pc)) {
72            break;
73        }
74        pcs.emplace_back(pc);
75        prevPc = pc;
76        index++;
77    } while (unw_step(&cursor) > 0);
78    DFXLOGU("%{public}s pcs.size: %{public}zu", __func__, pcs.size());
79    return pcs.size();
80}
81
82static void Run(benchmark::State& state, size_t (*func)(void))
83{
84    DFXLOGU("++++++pid: %{public}d", getpid());
85    for (const auto& _ : state) {
86        if (TestFunc1(func) < TEST_MIN_UNWIND_FRAMES) {
87            state.SkipWithError("Failed to unwind.");
88        }
89    }
90    DFXLOGU("------pid: %{public}d", getpid());
91}
92
93/**
94* @tc.name: BenchmarkUnwindLocal
95* @tc.desc: Unwind local
96* @tc.type: FUNC
97*/
98static void BenchmarkUnwindLocal(benchmark::State& state)
99{
100    Run(state, UnwindLocal);
101}
102BENCHMARK(BenchmarkUnwindLocal);
103
104/**
105* @tc.name: BenchmarkUnwindLocalCache
106* @tc.desc: Unwind local cache
107* @tc.type: FUNC
108*/
109static void BenchmarkUnwindLocalCache(benchmark::State& state)
110{
111    Run(state, UnwindLocal);
112}
113BENCHMARK(BenchmarkUnwindLocalCache);
114