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