1 /*
2 * Copyright (c) 2024 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 <atomic>
17 #include <benchmark/benchmark.h>
18 #include <mutex>
19 #include <thread>
20 #include <unistd.h>
21 #include <vector>
22 #include "dfx_log.h"
23 #include "unwinder.h"
24
25 using namespace OHOS::HiviewDFX;
26 using namespace std;
27
28 #undef LOG_DOMAIN
29 #undef LOG_TAG
30 #define LOG_DOMAIN 0xD002D11
31 #define LOG_TAG "DfxUnwinderLocalTid"
32
33 #define NOINLINE __attribute__((noinline))
34 static constexpr size_t TEST_MIN_UNWIND_FRAMES = 5;
35 static constexpr int NUM_ONE = 1;
36 static constexpr int NUM_TWO = 2;
37 static constexpr int NUM_THREE = 3;
38 static constexpr int NUM_FOUR = 4;
39 static constexpr int NUM_FIVE = 5;
40
TestFunc6(std::atomic_int * tid,std::atomic_bool * done)41 NOINLINE int TestFunc6(std::atomic_int* tid, std::atomic_bool* done)
42 {
43 tid->store(gettid());
44 while (!done->load()) {
45 }
46 return NUM_ONE;
47 }
48
TestFunc5(std::atomic_int * tid,std::atomic_bool * done)49 NOINLINE int TestFunc5(std::atomic_int* tid, std::atomic_bool* done)
50 {
51 int val = TestFunc6(tid, done);
52 return val * val + NUM_FIVE;
53 }
54
TestFunc4(std::atomic_int * tid,std::atomic_bool * done)55 NOINLINE int TestFunc4(std::atomic_int* tid, std::atomic_bool* done)
56 {
57 int val = TestFunc5(tid, done);
58 return val * val + NUM_FOUR;
59 }
60
TestFunc3(std::atomic_int * tid,std::atomic_bool * done)61 NOINLINE int TestFunc3(std::atomic_int* tid, std::atomic_bool* done)
62 {
63 int val = TestFunc4(tid, done);
64 return val * val + NUM_THREE;
65 }
66
TestFunc2(std::atomic_int * tid,std::atomic_bool * done)67 NOINLINE int TestFunc2(std::atomic_int* tid, std::atomic_bool* done)
68 {
69 int val = TestFunc3(tid, done);
70 return val * val + NUM_TWO;
71 }
72
TestFunc1(std::atomic_int * tid,std::atomic_bool * done)73 NOINLINE int TestFunc1(std::atomic_int* tid, std::atomic_bool* done)
74 {
75 int val = TestFunc2(tid, done);
76 return val * val + NUM_ONE;
77 }
78
79 /**
80 * @tc.name: BenchmarkUnwinderLocalWithTid
81 * @tc.desc: Unwind local with tid
82 * @tc.type: FUNC
83 */
BenchmarkUnwinderLocalWithTid(benchmark::State & state)84 static void BenchmarkUnwinderLocalWithTid(benchmark::State& state)
85 {
86 static std::mutex mutex;
87 constexpr int waitThreadTime = 1000;
88 std::atomic_int tid(0);
89 std::atomic_bool done(false);
90 std::thread th([&tid, &done] { TestFunc1(&tid, &done); });
91 while (tid.load() == 0) {
92 usleep(waitThreadTime);
93 LOGU("wait thread");
94 }
95 LOGU("+++tid: %d", tid.load());
96 #if defined(__aarch64__)
97 auto unwinder = std::make_shared<Unwinder>(false);
98 #else
99 auto unwinder = std::make_shared<Unwinder>();
100 #endif
101 unwinder->EnableFillFrames(false);
102 for (const auto& _ : state) {
103 std::unique_lock<std::mutex> lock(mutex);
104 if (!unwinder->UnwindLocalWithTid(tid.load())) {
105 continue;
106 }
107 auto unwSize = unwinder->GetPcs().size();
108 //rk 64 frames size is 14, rk 32 frames size is 4
109 LOGU("%s, frames.size: %zu", __func__, unwSize);
110 if (unwSize < TEST_MIN_UNWIND_FRAMES) {
111 state.SkipWithError("Failed to unwind.");
112 }
113 }
114
115 done.store(true);
116 LOGU("---tid: %d", tid.load());
117 th.join();
118 }
119 BENCHMARK(BenchmarkUnwinderLocalWithTid);