• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "thread_sampler_test.h"
17 
18 #include <csignal>
19 #include <fstream>
20 #include <sstream>
21 #include <dlfcn.h>
22 
23 #include "watchdog.h"
24 
25 using namespace testing::ext;
26 namespace OHOS {
27 namespace HiviewDFX {
28 const char* LIB_THREAD_SAMPLER_PATH = "libthread_sampler.z.so";
29 
30 constexpr int SAMPLE_CNT = 10;
31 constexpr int INTERVAL = 100;
32 constexpr size_t STACK_LENGTH = 32 * 1024;
33 constexpr int MILLSEC_TO_MICROSEC = 1000;
34 
35 static std::mutex threadSamplerSignalMutex_;
36 SigActionType ThreadSamplerTest::threadSamplerSigHandler_ = nullptr;
37 
SetUpTestCase(void)38 void ThreadSamplerTest::SetUpTestCase(void)
39 {
40     printf("SetUpTestCase.\n");
41 }
42 
TearDownTestCase(void)43 void ThreadSamplerTest::TearDownTestCase(void)
44 {
45     printf("TearDownTestCase.\n");
46     Watchdog::GetInstance().StopWatchdog();
47 }
48 
SetUp(void)49 void ThreadSamplerTest::SetUp(void)
50 {
51     printf("SetUp.\n");
52 }
53 
TearDown(void)54 void ThreadSamplerTest::TearDown(void)
55 {
56     printf("TearDown.\n");
57 }
58 
WaitSomeTime()59 void WaitSomeTime()
60 {
61     int waitDelay = 3;
62     int32_t left = (INTERVAL * SAMPLE_CNT + INTERVAL) / MILLSEC_TO_MICROSEC + waitDelay;
63     int32_t end = time(nullptr) + left;
64     while (left > 0) {
65         left = end - time(nullptr);
66     }
67     sleep((INTERVAL * SAMPLE_CNT + INTERVAL) / MILLSEC_TO_MICROSEC + waitDelay);
68 }
69 
GetMMapSizeAndName(const std::string & checkName,std::string & mmapName)70 uint32_t GetMMapSizeAndName(const std::string& checkName, std::string& mmapName)
71 {
72     uint64_t size = 0;
73     mmapName = "";
74     std::ifstream mapsFile("/proc/self/maps");
75     std::string line;
76     int base = 16;
77     while (getline(mapsFile, line)) {
78         std::istringstream iss(line);
79         std::string addrs;
80         std::string permissions;
81         std::string offset;
82         std::string devices;
83         std::string inode;
84         std::string pathname;
85         iss >> addrs >> permissions >> offset >> devices >> inode >> pathname;
86         if (pathname.find(checkName) != std::string::npos) {
87             std::string start = addrs.substr(0, addrs.find('-'));
88             std::string end = addrs.substr(addrs.find('-') + 1);
89             size = std::stoul(end, nullptr, base) - std::stoul(start, nullptr, base);
90             mmapName = pathname;
91         }
92     }
93     return static_cast<uint32_t>(size);
94 }
95 
FunctionOpen(void * funcHandler,const char * funcName)96 void* FunctionOpen(void* funcHandler, const char* funcName)
97 {
98     dlerror();
99     char* err = nullptr;
100     void* func = dlsym(funcHandler, funcName);
101     err = dlerror();
102     if (err != nullptr) {
103         return nullptr;
104     }
105     return func;
106 }
107 
ThreadSamplerSigHandler(int sig,siginfo_t * si,void * context)108 void ThreadSamplerTest::ThreadSamplerSigHandler(int sig, siginfo_t* si, void* context)
109 {
110     std::lock_guard<std::mutex> lock(threadSamplerSignalMutex_);
111     if (ThreadSamplerTest::threadSamplerSigHandler_ == nullptr) {
112         return;
113     }
114     ThreadSamplerTest::threadSamplerSigHandler_(sig, si, context);
115 }
116 
InstallThreadSamplerSignal()117 bool ThreadSamplerTest::InstallThreadSamplerSignal()
118 {
119     struct sigaction action {};
120     sigfillset(&action.sa_mask);
121     action.sa_sigaction = ThreadSamplerTest::ThreadSamplerSigHandler;
122     action.sa_flags = SA_RESTART | SA_SIGINFO;
123     if (sigaction(MUSL_SIGNAL_SAMPLE_STACK, &action, nullptr) != 0) {
124         return false;
125     }
126     return true;
127 }
128 
UninstallThreadSamplerSignal()129 void ThreadSamplerTest::UninstallThreadSamplerSignal()
130 {
131     std::lock_guard<std::mutex> lock(threadSamplerSignalMutex_);
132     threadSamplerSigHandler_ = nullptr;
133 }
134 
InitThreadSamplerFuncs()135 bool ThreadSamplerTest::InitThreadSamplerFuncs()
136 {
137     threadSamplerFuncHandler_ = dlopen(LIB_THREAD_SAMPLER_PATH, RTLD_LAZY);
138     if (threadSamplerFuncHandler_ == nullptr) {
139         return false;
140     }
141 
142     threadSamplerInitFunc_ =
143         reinterpret_cast<ThreadSamplerInitFunc>(FunctionOpen(threadSamplerFuncHandler_, "ThreadSamplerInit"));
144     threadSamplerSampleFunc_ =
145         reinterpret_cast<ThreadSamplerSampleFunc>(FunctionOpen(threadSamplerFuncHandler_, "ThreadSamplerSample"));
146     threadSamplerCollectFunc_ =
147         reinterpret_cast<ThreadSamplerCollectFunc>(FunctionOpen(threadSamplerFuncHandler_, "ThreadSamplerCollect"));
148     threadSamplerDeinitFunc_ =
149         reinterpret_cast<ThreadSamplerDeinitFunc>(FunctionOpen(threadSamplerFuncHandler_, "ThreadSamplerDeinit"));
150     threadSamplerSigHandler_ =
151         reinterpret_cast<SigActionType>(FunctionOpen(threadSamplerFuncHandler_, "ThreadSamplerSigHandler"));
152     if (threadSamplerInitFunc_ == nullptr || threadSamplerSampleFunc_ == nullptr ||
153         threadSamplerCollectFunc_ == nullptr || threadSamplerDeinitFunc_ == nullptr ||
154         threadSamplerSigHandler_ == nullptr) {
155         threadSamplerInitFunc_ = nullptr;
156         threadSamplerSampleFunc_ = nullptr;
157         threadSamplerCollectFunc_ = nullptr;
158         threadSamplerDeinitFunc_ = nullptr;
159         threadSamplerSigHandler_ = nullptr;
160         dlclose(threadSamplerFuncHandler_);
161         threadSamplerFuncHandler_ = nullptr;
162         return false;
163     }
164     return true;
165 }
166 
InitThreadSampler()167 bool ThreadSamplerTest::InitThreadSampler()
168 {
169     if (!InitThreadSamplerFuncs()) {
170         return false;
171     }
172 
173     if (!InstallThreadSamplerSignal()) {
174         return false;
175     }
176     return true;
177 }
178 
179 /**
180  * @tc.name: ThreadSamplerTest_001
181  * @tc.desc: sample thread SAMPLE_CNT times and check the stacktrace
182  * @tc.type: FUNC
183  * @tc.require
184  */
185 HWTEST_F(ThreadSamplerTest, ThreadSamplerTest_001, TestSize.Level0)
186 {
187     printf("ThreadSamplerTest_001\n");
188     printf("Total:%dMS Sample:%dMS \n", INTERVAL * SAMPLE_CNT + INTERVAL, INTERVAL);
189 
190     bool flag = InitThreadSampler();
191     ASSERT_TRUE(flag);
192 
193     threadSamplerInitFunc_(SAMPLE_CNT);
__anon8a91e8a10102() 194     auto sampleHandler = [this]() {
195         threadSamplerSampleFunc_();
196     };
197 
198     char* stk = new char[STACK_LENGTH];
199     char* heaviestStk = new char[STACK_LENGTH];
__anon8a91e8a10202() 200     auto collectHandler = [this, &stk, &heaviestStk]() {
201         int treeFormat = 0;
202         threadSamplerCollectFunc_(stk, heaviestStk, STACK_LENGTH, STACK_LENGTH, treeFormat);
203     };
204 
205     for (int i = 0; i < SAMPLE_CNT; i++) {
206         uint64_t delay = INTERVAL * i + INTERVAL;
207         Watchdog::GetInstance().RunOneShotTask("ThreadSamplerTest", sampleHandler, delay);
208     }
209     Watchdog::GetInstance().RunOneShotTask("CollectStackTest", collectHandler, INTERVAL * SAMPLE_CNT + INTERVAL);
210 
211     WaitSomeTime();
212 
213     std::string stack = stk;
214     std::string heaviestStack = heaviestStk;
215     ASSERT_NE(stack, "");
216     printf("stack:\n%s\nheaviestStack:\n%s", stack.c_str(), heaviestStack.c_str());
217     delete[] stk;
218     delete[] heaviestStk;
219     UninstallThreadSamplerSignal();
220     threadSamplerDeinitFunc_();
221     dlclose(threadSamplerFuncHandler_);
222 }
223 
224 /**
225  * @tc.name: ThreadSamplerTest_002
226  * @tc.desc: sample thread SAMPLE_CNT times and check the stacktrace in tree format
227  * @tc.type: FUNC
228  * @tc.require
229  */
230 HWTEST_F(ThreadSamplerTest, ThreadSamplerTest_002, TestSize.Level3)
231 {
232     printf("ThreadSamplerTest_002\n");
233     printf("Total:%dMS Sample:%dMS \n", INTERVAL * SAMPLE_CNT + INTERVAL, INTERVAL);
234 
235     bool flag = InitThreadSampler();
236     ASSERT_TRUE(flag);
237 
238     threadSamplerInitFunc_(SAMPLE_CNT);
__anon8a91e8a10302() 239     auto sampleHandler = [this]() {
240         threadSamplerSampleFunc_();
241     };
242 
243     char* stk = new char[STACK_LENGTH];
244     char* heaviestStk = new char[STACK_LENGTH];
__anon8a91e8a10402() 245     auto collectHandler = [this, &stk, &heaviestStk]() {
246         int treeFormat = 1;
247         threadSamplerCollectFunc_(stk, heaviestStk, STACK_LENGTH, STACK_LENGTH, treeFormat);
248     };
249 
250     for (int i = 0; i < SAMPLE_CNT; i++) {
251         uint64_t delay = INTERVAL * i + INTERVAL;
252         Watchdog::GetInstance().RunOneShotTask("ThreadSamplerTest", sampleHandler, delay);
253     }
254     Watchdog::GetInstance().RunOneShotTask("CollectStackTest", collectHandler, INTERVAL * SAMPLE_CNT + INTERVAL);
255 
256     WaitSomeTime();
257 
258     std::string stack = stk;
259     std::string heaviestStack = heaviestStk;
260     ASSERT_NE(stack, "");
261     printf("stack:\n%s\nheaviestStack:\n%s", stack.c_str(), heaviestStack.c_str());
262     delete[] stk;
263     delete[] heaviestStk;
264     UninstallThreadSamplerSignal();
265     threadSamplerDeinitFunc_();
266     dlclose(threadSamplerFuncHandler_);
267 }
268 
269 /**
270  * @tc.name: ThreadSamplerTest_003
271  * @tc.desc: sample thread SAMPLE_CNT times and deinit sampler send SAMPLE_CNT sample requestion and restart sampler.
272  * @tc.type: FUNC
273  * @tc.require
274  */
275 HWTEST_F(ThreadSamplerTest, ThreadSamplerTest_003, TestSize.Level3)
276 {
277     printf("ThreadSamplerTest_003\n");
278     printf("Total:%dMS Sample:%dMS \n", INTERVAL * SAMPLE_CNT + INTERVAL, INTERVAL);
279 
280     InitThreadSampler();
281 
282     threadSamplerInitFunc_(SAMPLE_CNT);
__anon8a91e8a10502() 283     auto sampleHandler = [this]() {
284         threadSamplerSampleFunc_();
285     };
286 
287     char* stk = new char[STACK_LENGTH];
288     char* heaviestStk = new char[STACK_LENGTH];
__anon8a91e8a10602() 289     auto collectHandler = [this, &stk, &heaviestStk]() {
290         int treeFormat = 1;
291         threadSamplerCollectFunc_(stk, heaviestStk, STACK_LENGTH, STACK_LENGTH, treeFormat);
292     };
293 
294     for (int i = 0; i < SAMPLE_CNT; i++) {
295         Watchdog::GetInstance().RunOneShotTask("ThreadSamplerTest", sampleHandler, INTERVAL * i + INTERVAL);
296     }
297     Watchdog::GetInstance().RunOneShotTask("CollectStackTest", collectHandler, INTERVAL * SAMPLE_CNT + INTERVAL);
298 
299     WaitSomeTime();
300 
301     std::string stack = stk;
302     std::string heaviestStack = heaviestStk;
303     ASSERT_NE(stack, "");
304     printf("stack:\n%s\nheaviestStack:\n%s", stack.c_str(), heaviestStack.c_str());
305     threadSamplerDeinitFunc_();
306 
307     for (int i = 0; i < SAMPLE_CNT; i++) {
308         Watchdog::GetInstance().RunOneShotTask("ThreadSamplerTest", sampleHandler, INTERVAL * i + INTERVAL);
309     }
310     Watchdog::GetInstance().RunOneShotTask("CollectStackTest", collectHandler, INTERVAL * SAMPLE_CNT + INTERVAL);
311 
312     WaitSomeTime();
313     stack = stk;
314     heaviestStack = heaviestStk;
315     ASSERT_NE(stack, "");
316     printf("stack:\n%s\nheaviestStack:\n%s", stack.c_str(), heaviestStack.c_str());
317 
318     threadSamplerInitFunc_(SAMPLE_CNT);
319 
320     for (int i = 0; i < SAMPLE_CNT; i++) {
321         Watchdog::GetInstance().RunOneShotTask("ThreadSamplerTest", sampleHandler, INTERVAL * i + INTERVAL);
322     }
323     Watchdog::GetInstance().RunOneShotTask("CollectStackTest", collectHandler, INTERVAL * SAMPLE_CNT + INTERVAL);
324 
325     WaitSomeTime();
326     stack = stk;
327     heaviestStack = heaviestStk;
328     ASSERT_NE(stack, "");
329     printf("stack:\n%s\nheaviestStack:\n%s", stack.c_str(), heaviestStack.c_str());
330     delete[] stk;
331     delete[] heaviestStk;
332     UninstallThreadSamplerSignal();
333     threadSamplerDeinitFunc_();
334     dlclose(threadSamplerFuncHandler_);
335 }
336 
337 /**
338  * @tc.name: ThreadSamplerTest_004
339  * @tc.desc: sample thread several times but signal is blocked.
340  * @tc.type: FUNC
341  * @tc.require
342  */
343 HWTEST_F(ThreadSamplerTest, ThreadSamplerTest_004, TestSize.Level3)
344 {
345     printf("ThreadSamplerTest_004\n");
346     printf("Total:%dMS Sample:%dMS \n", INTERVAL * SAMPLE_CNT + INTERVAL, INTERVAL);
347 
348     bool flag = InitThreadSampler();
349     ASSERT_TRUE(flag);
350 
351     threadSamplerInitFunc_(SAMPLE_CNT);
__anon8a91e8a10702() 352     auto sampleHandler = [this]() {
353         threadSamplerSampleFunc_();
354     };
355 
356     char* stk = new char[STACK_LENGTH];
357     char* heaviestStk = new char[STACK_LENGTH];
__anon8a91e8a10802() 358     auto collectHandler = [this, &stk, &heaviestStk]() {
359         int treeFormat = 1;
360         threadSamplerCollectFunc_(stk, heaviestStk, STACK_LENGTH, STACK_LENGTH, treeFormat);
361     };
362 
363     sigset_t sigset;
364     sigemptyset(&sigset);
365     sigaddset(&sigset, MUSL_SIGNAL_SAMPLE_STACK);
366     sigprocmask(SIG_BLOCK, &sigset, nullptr);
367 
368     for (int i = 0; i < SAMPLE_CNT; i++) {
369         uint64_t delay = INTERVAL * i + INTERVAL;
370         Watchdog::GetInstance().RunOneShotTask("ThreadSamplerTest", sampleHandler, delay);
371     }
372     Watchdog::GetInstance().RunOneShotTask("CollectStackTest", collectHandler, INTERVAL * SAMPLE_CNT + INTERVAL);
373 
374     WaitSomeTime();
375 
376     std::string stack = stk;
377     std::string heaviestStack = heaviestStk;
378     ASSERT_NE(stack, "");
379     printf("stack:\n%s\nheaviestStack:\n%s", stack.c_str(), heaviestStack.c_str());
380     sigprocmask(SIG_UNBLOCK, &sigset, nullptr);
381     sigdelset(&sigset, MUSL_SIGNAL_SAMPLE_STACK);
382     delete[] stk;
383     delete[] heaviestStk;
384     UninstallThreadSamplerSignal();
385     threadSamplerDeinitFunc_();
386     dlclose(threadSamplerFuncHandler_);
387 }
388 
389 /**
390  * @tc.name: ThreadSamplerTest_005
391  * @tc.desc: Check the size and name of uniqueStackTable mmap.
392  * @tc.type: FUNC
393  * @tc.require
394  */
395 HWTEST_F(ThreadSamplerTest, ThreadSamplerTest_005, TestSize.Level3)
396 {
397     printf("ThreadSamplerTest_005\n");
398 
__anon8a91e8a10902(const std::string& str, const std::string& sub) 399     auto isSubStr = [](const std::string& str, const std::string& sub) {
400         return str.find(sub) != std::string::npos;
401     };
402 
403     uint32_t uniTableSize = 0;
404     std::string uniStackTableMMapName = "";
405 
406     bool flag = InitThreadSamplerFuncs();
407     ASSERT_TRUE(flag);
408 
409     threadSamplerInitFunc_(SAMPLE_CNT);
410     uniTableSize = GetMMapSizeAndName("hicollie_buf", uniStackTableMMapName);
411 
412     uint32_t bufSize = 128 * 1024;
413     ASSERT_EQ(uniTableSize, bufSize);
414     ASSERT_EQ(isSubStr(uniStackTableMMapName, "hicollie_buf"), true);
415     printf("mmap name: %s, size: %u KB\n", uniStackTableMMapName.c_str(), uniTableSize);
416 
417     threadSamplerDeinitFunc_();
418     dlclose(threadSamplerFuncHandler_);
419 }
420 } // end of namespace HiviewDFX
421 } // end of namespace OHOS
422