• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2025 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 <gmock/gmock.h>
17 #include <gtest/gtest.h>
18 #include <atomic>
19 
20 #include "assembler/assembly-parser.h"
21 #include "libpandafile/file.h"
22 #include "libpandabase/trace/trace.h"
23 #include "libpandabase/panda_gen_options/generated/base_options.h"
24 #include "runtime/include/thread_scopes.h"
25 #include "runtime/include/runtime.h"
26 #include "runtime/tooling/sampler/sampling_profiler.h"
27 #include "runtime/interpreter/runtime_interface.h"
28 #include "tools/sampler/aspt_converter.h"
29 
30 namespace ark::tooling::sampler::test {
31 
Separator()32 inline std::string Separator()
33 {
34 #ifdef _WIN32
35     return "\\";
36 #else
37     return "/";
38 #endif
39 }
40 
41 static const char *g_profilerFilename = "profiler_result.aspt";
42 static const char *g_pandaFileName = "sampling_profiler_test_ark_asm.abc";
43 static constexpr size_t TEST_CYCLE_THRESHOLD = 100;
44 static const std::shared_ptr<SamplesRecord> G_SAMPLES_RECORD = std::make_shared<SamplesRecord>();
45 
46 // NOLINTBEGIN(misc-non-private-member-variables-in-classes)
47 class SamplerTest : public testing::Test {
48 public:
49     // NOLINTNEXTLINE(readability-function-size)
SetUp()50     void SetUp() override
51     {
52         Logger::Initialize(base_options::Options(""));
53 
54         RuntimeOptions options;
55         options.SetLoadRuntimes({"core"});
56         options.SetRunGcInPlace(true);
57         options.SetVerifyCallStack(false);
58         options.SetInterpreterType("cpp");
59         auto execPath = ark::os::file::File::GetExecutablePath();
60         std::string pandaStdLib =
61             execPath.Value() + Separator() + ".." + Separator() + "pandastdlib" + Separator() + "arkstdlib.abc";
62         options.SetBootPandaFiles({pandaStdLib});
63         Runtime::Create(options);
64 
65         auto pf = panda_file::OpenPandaFileOrZip(g_pandaFileName);
66         Runtime::GetCurrent()->GetClassLinker()->AddPandaFile(std::move(pf));
67 
68         thread_ = ark::MTManagedThread::GetCurrent();
69     }
70 
TearDown()71     void TearDown() override
72     {
73         Runtime::Destroy();
74     }
75 
FullfillFakeSample(SampleInfo * ps)76     void FullfillFakeSample(SampleInfo *ps)
77     {
78         for (uint32_t i = 0; i < SampleInfo::StackInfo::MAX_STACK_DEPTH; ++i) {
79             ps->stackInfo.managedStack[i] = {i, pfId_};
80         }
81         ps->threadInfo.threadId = GetThreadId();
82         ps->stackInfo.managedStackSize = SampleInfo::StackInfo::MAX_STACK_DEPTH;
83     }
84 
85     // Friend wrappers for accesing samplers private fields
ExtractListenerTid(const Sampler * sPtr)86     static os::thread::NativeHandleType ExtractListenerTid(const Sampler *sPtr)
87     {
88         return sPtr->listenerTid_;
89     }
90 
ExtractSamplerTid(const Sampler * sPtr)91     static os::thread::NativeHandleType ExtractSamplerTid(const Sampler *sPtr)
92     {
93         return sPtr->samplerTid_;
94     }
95 
ExtractManagedThreads(Sampler * sPtr)96     static PandaSet<os::thread::ThreadId> ExtractManagedThreads(Sampler *sPtr)
97     {
98         // Sending a copy to avoid of datarace
99         os::memory::LockHolder holder(sPtr->managedThreadsLock_);
100         PandaSet<os::thread::ThreadId> managedThreadsCopy = sPtr->managedThreads_;
101         return managedThreadsCopy;
102     }
103 
ExtractLoadedPFSize(Sampler * sPtr)104     static size_t ExtractLoadedPFSize(Sampler *sPtr)
105     {
106         os::memory::LockHolder holder(sPtr->loadedPfsLock_);
107         return sPtr->loadedPfs_.size();
108     }
109 
ExtractPipes(const Sampler * sPtr)110     static std::array<int, 2> ExtractPipes(const Sampler *sPtr)
111     {
112         // Sending a copy to avoid of datarace
113         return sPtr->communicator_.listenerPipe_;
114     }
115 
ExtractIsActive(const Sampler * sPtr)116     static bool ExtractIsActive(const Sampler *sPtr)
117     {
118         // Atomic with acquire order reason: To ensure start/stop load correctly
119         return sPtr->isActive_.load(std::memory_order_acquire);
120     }
121 
GetThreadId()122     uint32_t GetThreadId()
123     {
124         return os::thread::GetCurrentThreadId();
125     }
126 
127 protected:
128     ark::MTManagedThread *thread_ {nullptr};
129     uintptr_t pfId_ {0};
130     uint32_t checksum_ {0};
131 };
132 // NOLINTEND(misc-non-private-member-variables-in-classes)
133 
TEST_F(SamplerTest,SamplerInitTest)134 TEST_F(SamplerTest, SamplerInitTest)
135 {
136     auto *sp = Sampler::Create();
137     ASSERT_NE(sp, nullptr);
138 
139     ASSERT_EQ(ExtractListenerTid(sp), 0);
140     ASSERT_EQ(ExtractSamplerTid(sp), 0);
141     ASSERT_EQ(ExtractIsActive(sp), false);
142 
143     ASSERT_EQ(sp->Start(std::make_unique<FileStreamWriter>(g_profilerFilename)), true);
144     ASSERT_NE(ExtractListenerTid(sp), 0);
145     ASSERT_NE(ExtractSamplerTid(sp), 0);
146     ASSERT_EQ(ExtractIsActive(sp), true);
147 
148     ASSERT_EQ(sp->Start(std::make_unique<FileStreamWriter>(g_profilerFilename)), false);
149 
150     sp->Stop();
151     ASSERT_EQ(ExtractListenerTid(sp), 0);
152     ASSERT_EQ(ExtractSamplerTid(sp), 0);
153     ASSERT_EQ(ExtractIsActive(sp), false);
154 
155     // Second run
156     ASSERT_EQ(sp->Start(std::make_unique<FileStreamWriter>(g_profilerFilename)), true);
157     ASSERT_NE(ExtractListenerTid(sp), 0);
158     ASSERT_NE(ExtractSamplerTid(sp), 0);
159     ASSERT_EQ(ExtractIsActive(sp), true);
160 
161     sp->Stop();
162     ASSERT_EQ(ExtractListenerTid(sp), 0);
163     ASSERT_EQ(ExtractSamplerTid(sp), 0);
164     ASSERT_EQ(ExtractIsActive(sp), false);
165     Sampler::Destroy(sp);
166 }
167 
TEST_F(SamplerTest,InspectorSamplerInitTest)168 TEST_F(SamplerTest, InspectorSamplerInitTest)
169 {
170     auto *sp = Sampler::Create();
171     ASSERT_NE(sp, nullptr);
172 
173     ASSERT_EQ(ExtractListenerTid(sp), 0);
174     ASSERT_EQ(ExtractSamplerTid(sp), 0);
175     ASSERT_EQ(ExtractIsActive(sp), false);
176 
177     ASSERT_EQ(sp->Start(std::make_unique<InspectorStreamWriter>(G_SAMPLES_RECORD)), true);
178     ASSERT_NE(ExtractListenerTid(sp), 0);
179     ASSERT_NE(ExtractSamplerTid(sp), 0);
180     ASSERT_EQ(ExtractIsActive(sp), true);
181 
182     ASSERT_EQ(sp->Start(std::make_unique<InspectorStreamWriter>(G_SAMPLES_RECORD)), false);
183 
184     sp->Stop();
185     ASSERT_EQ(ExtractListenerTid(sp), 0);
186     ASSERT_EQ(ExtractSamplerTid(sp), 0);
187     ASSERT_EQ(ExtractIsActive(sp), false);
188 
189     // Second run
190     ASSERT_EQ(sp->Start(std::make_unique<InspectorStreamWriter>(G_SAMPLES_RECORD)), true);
191     ASSERT_NE(ExtractListenerTid(sp), 0);
192     ASSERT_NE(ExtractSamplerTid(sp), 0);
193     ASSERT_EQ(ExtractIsActive(sp), true);
194 
195     sp->Stop();
196     ASSERT_EQ(ExtractListenerTid(sp), 0);
197     ASSERT_EQ(ExtractSamplerTid(sp), 0);
198     ASSERT_EQ(ExtractIsActive(sp), false);
199     Sampler::Destroy(sp);
200 }
201 
RunManagedThread(std::atomic<bool> * syncFlag)202 void RunManagedThread(std::atomic<bool> *syncFlag)
203 {
204     auto *mThr = ark::MTManagedThread::Create(ark::Runtime::GetCurrent(), ark::Runtime::GetCurrent()->GetPandaVM());
205     mThr->ManagedCodeBegin();
206 
207     *syncFlag = true;
208     while (*syncFlag) {
209         // Calling safepoint 'cause starting profiler required to stop all managed threads
210         interpreter::RuntimeInterface::Safepoint();
211     }
212 
213     mThr->ManagedCodeEnd();
214     mThr->Destroy();
215 }
216 
RunManagedThreadAndSaveThreadId(std::atomic<bool> * syncFlag,os::thread::ThreadId * id)217 void RunManagedThreadAndSaveThreadId(std::atomic<bool> *syncFlag, os::thread::ThreadId *id)
218 {
219     auto *mThr = ark::MTManagedThread::Create(ark::Runtime::GetCurrent(), ark::Runtime::GetCurrent()->GetPandaVM());
220     mThr->ManagedCodeBegin();
221 
222     *id = os::thread::GetCurrentThreadId();
223     *syncFlag = true;
224     while (*syncFlag) {
225         // Calling safepoint 'cause starting profiler required to stop all managed threads
226         interpreter::RuntimeInterface::Safepoint();
227     }
228 
229     mThr->ManagedCodeEnd();
230     mThr->Destroy();
231 }
232 
RunNativeThread(std::atomic<bool> * syncFlag)233 void RunNativeThread(std::atomic<bool> *syncFlag)
234 {
235     auto *mThr = ark::MTManagedThread::Create(ark::Runtime::GetCurrent(), ark::Runtime::GetCurrent()->GetPandaVM());
236 
237     *syncFlag = true;
238     while (*syncFlag) {
239     }
240 
241     mThr->Destroy();
242 }
243 
244 // Testing notification thread started/finished
TEST_F(SamplerTest,SamplerEventThreadNotificationTest)245 TEST_F(SamplerTest, SamplerEventThreadNotificationTest)
246 {
247     auto *sp = Sampler::Create();
248     ASSERT_NE(sp, nullptr);
249 
250     ASSERT_EQ(sp->Start(std::make_unique<FileStreamWriter>(g_profilerFilename)), true);
251     ASSERT_NE(ExtractListenerTid(sp), 0);
252     ASSERT_NE(ExtractSamplerTid(sp), 0);
253     ASSERT_EQ(ExtractIsActive(sp), true);
254 
255     ASSERT_FALSE(ExtractManagedThreads(sp).empty());
256     ASSERT_EQ(ExtractManagedThreads(sp).size(), 1);
257 
258     std::atomic<bool> syncFlag1 = false;
259     std::atomic<bool> syncFlag2 = false;
260     std::atomic<bool> syncFlag3 = false;
261     std::thread managedThread1(RunManagedThread, &syncFlag1);
262     std::thread managedThread2(RunManagedThread, &syncFlag2);
263     std::thread managedThread3(RunManagedThread, &syncFlag3);
264 
265     while (!syncFlag1 || !syncFlag2 || !syncFlag3) {
266         ;
267     }
268     ASSERT_EQ(ExtractManagedThreads(sp).size(), 4UL);
269 
270     syncFlag1 = false;
271     syncFlag2 = false;
272     syncFlag3 = false;
273     managedThread1.join();
274     managedThread2.join();
275     managedThread3.join();
276 
277     ASSERT_EQ(ExtractManagedThreads(sp).size(), 1);
278 
279     sp->Stop();
280     ASSERT_EQ(ExtractListenerTid(sp), 0);
281     ASSERT_EQ(ExtractSamplerTid(sp), 0);
282     ASSERT_EQ(ExtractIsActive(sp), false);
283     Sampler::Destroy(sp);
284 }
285 
TEST_F(SamplerTest,InspectorSamplerEventThreadNotificationTest)286 TEST_F(SamplerTest, InspectorSamplerEventThreadNotificationTest)
287 {
288     auto *sp = Sampler::Create();
289     ASSERT_NE(sp, nullptr);
290 
291     ASSERT_EQ(sp->Start(std::make_unique<InspectorStreamWriter>(G_SAMPLES_RECORD)), true);
292     ASSERT_NE(ExtractListenerTid(sp), 0);
293     ASSERT_NE(ExtractSamplerTid(sp), 0);
294     ASSERT_EQ(ExtractIsActive(sp), true);
295 
296     ASSERT_FALSE(ExtractManagedThreads(sp).empty());
297     ASSERT_EQ(ExtractManagedThreads(sp).size(), 1);
298 
299     std::atomic<bool> syncFlag1 = false;
300     std::atomic<bool> syncFlag2 = false;
301     std::atomic<bool> syncFlag3 = false;
302     std::thread managedThread1(RunManagedThread, &syncFlag1);
303     std::thread managedThread2(RunManagedThread, &syncFlag2);
304     std::thread managedThread3(RunManagedThread, &syncFlag3);
305 
306     while (!syncFlag1 || !syncFlag2 || !syncFlag3) {
307         ;
308     }
309     ASSERT_EQ(ExtractManagedThreads(sp).size(), 4UL);
310 
311     syncFlag1 = false;
312     syncFlag2 = false;
313     syncFlag3 = false;
314     managedThread1.join();
315     managedThread2.join();
316     managedThread3.join();
317 
318     ASSERT_EQ(ExtractManagedThreads(sp).size(), 1);
319 
320     sp->Stop();
321     ASSERT_EQ(ExtractListenerTid(sp), 0);
322     ASSERT_EQ(ExtractSamplerTid(sp), 0);
323     ASSERT_EQ(ExtractIsActive(sp), false);
324     Sampler::Destroy(sp);
325 }
326 
327 // Testing notification thread started/finished
TEST_F(SamplerTest,SamplerCheckThreadIdTest)328 TEST_F(SamplerTest, SamplerCheckThreadIdTest)
329 {
330     auto *sp = Sampler::Create();
331     ASSERT_NE(sp, nullptr);
332 
333     ASSERT_EQ(sp->Start(std::make_unique<FileStreamWriter>(g_profilerFilename)), true);
334     ASSERT_NE(ExtractListenerTid(sp), 0);
335     ASSERT_NE(ExtractSamplerTid(sp), 0);
336     ASSERT_EQ(ExtractIsActive(sp), true);
337 
338     ASSERT_EQ(ExtractManagedThreads(sp).size(), 1);
339 
340     std::atomic<bool> syncFlag1 = false;
341     os::thread::ThreadId mtId = 0;
342     std::thread managedThread1(RunManagedThreadAndSaveThreadId, &syncFlag1, &mtId);
343 
344     while (!syncFlag1) {
345         ;
346     }
347     // only one additional managed thread must be running
348     ASSERT_EQ(ExtractManagedThreads(sp).size(), 2UL);
349     bool isPassed = false;
350 
351     for (const auto &elem : ExtractManagedThreads(sp)) {
352         if (elem == mtId) {
353             isPassed = true;
354             break;
355         }
356     }
357     ASSERT_TRUE(isPassed);
358 
359     syncFlag1 = false;
360     managedThread1.join();
361 
362     ASSERT_EQ(ExtractManagedThreads(sp).size(), 1);
363 
364     sp->Stop();
365     ASSERT_EQ(ExtractListenerTid(sp), 0);
366     ASSERT_EQ(ExtractSamplerTid(sp), 0);
367     ASSERT_EQ(ExtractIsActive(sp), false);
368     Sampler::Destroy(sp);
369 }
370 
TEST_F(SamplerTest,InspectorSamplerCheckThreadIdTest)371 TEST_F(SamplerTest, InspectorSamplerCheckThreadIdTest)
372 {
373     auto *sp = Sampler::Create();
374     ASSERT_NE(sp, nullptr);
375 
376     ASSERT_EQ(sp->Start(std::make_unique<InspectorStreamWriter>(G_SAMPLES_RECORD)), true);
377     ASSERT_NE(ExtractListenerTid(sp), 0);
378     ASSERT_NE(ExtractSamplerTid(sp), 0);
379     ASSERT_EQ(ExtractIsActive(sp), true);
380 
381     ASSERT_EQ(ExtractManagedThreads(sp).size(), 1);
382 
383     std::atomic<bool> syncFlag1 = false;
384     os::thread::ThreadId mtId = 0;
385     std::thread managedThread1(RunManagedThreadAndSaveThreadId, &syncFlag1, &mtId);
386 
387     while (!syncFlag1) {
388         ;
389     }
390     // only one additional managed thread must be running
391     ASSERT_EQ(ExtractManagedThreads(sp).size(), 2UL);
392     bool isPassed = false;
393 
394     for (const auto &elem : ExtractManagedThreads(sp)) {
395         if (elem == mtId) {
396             isPassed = true;
397             break;
398         }
399     }
400     ASSERT_TRUE(isPassed);
401 
402     syncFlag1 = false;
403     managedThread1.join();
404 
405     ASSERT_EQ(ExtractManagedThreads(sp).size(), 1);
406 
407     sp->Stop();
408     ASSERT_EQ(ExtractListenerTid(sp), 0);
409     ASSERT_EQ(ExtractSamplerTid(sp), 0);
410     ASSERT_EQ(ExtractIsActive(sp), false);
411     Sampler::Destroy(sp);
412 }
413 
414 // Testing thread collection
TEST_F(SamplerTest,SamplerCollectThreadTest)415 TEST_F(SamplerTest, SamplerCollectThreadTest)
416 {
417     auto *sp = Sampler::Create();
418     ASSERT_NE(sp, nullptr);
419 
420     std::atomic<bool> syncFlag1 = false;
421     std::atomic<bool> syncFlag2 = false;
422     std::atomic<bool> syncFlag3 = false;
423     std::thread managedThread1(RunManagedThread, &syncFlag1);
424     std::thread managedThread2(RunManagedThread, &syncFlag2);
425     std::thread managedThread3(RunManagedThread, &syncFlag3);
426 
427     while (!syncFlag1 || !syncFlag2 || !syncFlag3) {
428         ;
429     }
430 
431     ASSERT_EQ(sp->Start(std::make_unique<FileStreamWriter>(g_profilerFilename)), true);
432     ASSERT_NE(ExtractListenerTid(sp), 0);
433     ASSERT_NE(ExtractSamplerTid(sp), 0);
434     ASSERT_EQ(ExtractIsActive(sp), true);
435 
436     ASSERT_EQ(ExtractManagedThreads(sp).size(), 4UL);
437 
438     syncFlag1 = false;
439     syncFlag2 = false;
440     syncFlag3 = false;
441     managedThread1.join();
442     managedThread2.join();
443     managedThread3.join();
444 
445     ASSERT_EQ(ExtractManagedThreads(sp).size(), 1);
446 
447     sp->Stop();
448     ASSERT_EQ(ExtractListenerTid(sp), 0);
449     ASSERT_EQ(ExtractSamplerTid(sp), 0);
450     ASSERT_EQ(ExtractIsActive(sp), false);
451     Sampler::Destroy(sp);
452 }
453 
TEST_F(SamplerTest,InspectorSamplerCollectThreadTest)454 TEST_F(SamplerTest, InspectorSamplerCollectThreadTest)
455 {
456     auto *sp = Sampler::Create();
457     ASSERT_NE(sp, nullptr);
458 
459     std::atomic<bool> syncFlag1 = false;
460     std::atomic<bool> syncFlag2 = false;
461     std::atomic<bool> syncFlag3 = false;
462     std::thread managedThread1(RunManagedThread, &syncFlag1);
463     std::thread managedThread2(RunManagedThread, &syncFlag2);
464     std::thread managedThread3(RunManagedThread, &syncFlag3);
465 
466     while (!syncFlag1 || !syncFlag2 || !syncFlag3) {
467         ;
468     }
469 
470     ASSERT_EQ(sp->Start(std::make_unique<InspectorStreamWriter>(G_SAMPLES_RECORD)), true);
471     ASSERT_NE(ExtractListenerTid(sp), 0);
472     ASSERT_NE(ExtractSamplerTid(sp), 0);
473     ASSERT_EQ(ExtractIsActive(sp), true);
474 
475     ASSERT_EQ(ExtractManagedThreads(sp).size(), 4UL);
476 
477     syncFlag1 = false;
478     syncFlag2 = false;
479     syncFlag3 = false;
480     managedThread1.join();
481     managedThread2.join();
482     managedThread3.join();
483 
484     ASSERT_EQ(ExtractManagedThreads(sp).size(), 1);
485 
486     sp->Stop();
487     ASSERT_EQ(ExtractListenerTid(sp), 0);
488     ASSERT_EQ(ExtractSamplerTid(sp), 0);
489     ASSERT_EQ(ExtractIsActive(sp), false);
490     Sampler::Destroy(sp);
491 }
492 
493 // Testing native thread collection
TEST_F(SamplerTest,SamplerCollectNativeThreadTest)494 TEST_F(SamplerTest, SamplerCollectNativeThreadTest)
495 {
496     auto *sp = Sampler::Create();
497     ASSERT_NE(sp, nullptr);
498 
499     std::atomic<bool> syncFlag1 = false;
500     std::atomic<bool> syncFlag2 = false;
501     std::atomic<bool> syncFlag3 = false;
502     std::thread managedThread1(RunManagedThread, &syncFlag1);
503     std::thread nativeThread2(RunNativeThread, &syncFlag2);
504 
505     while (!syncFlag1 || !syncFlag2) {
506         ;
507     }
508 
509     ASSERT_EQ(sp->Start(std::make_unique<FileStreamWriter>(g_profilerFilename)), true);
510     ASSERT_NE(ExtractListenerTid(sp), 0);
511     ASSERT_NE(ExtractSamplerTid(sp), 0);
512     ASSERT_EQ(ExtractIsActive(sp), true);
513 
514     // two additional threads must be running - a managed and a native one
515     ASSERT_EQ(ExtractManagedThreads(sp).size(), 3UL);
516     std::thread nativeThread3(RunNativeThread, &syncFlag3);
517     while (!syncFlag3) {
518         ;
519     }
520 
521     ASSERT_EQ(ExtractManagedThreads(sp).size(), 4UL);
522 
523     syncFlag1 = false;
524     syncFlag2 = false;
525     syncFlag3 = false;
526     managedThread1.join();
527     nativeThread2.join();
528     nativeThread3.join();
529 
530     ASSERT_EQ(ExtractManagedThreads(sp).size(), 1);
531 
532     sp->Stop();
533     ASSERT_EQ(ExtractListenerTid(sp), 0);
534     ASSERT_EQ(ExtractSamplerTid(sp), 0);
535     ASSERT_EQ(ExtractIsActive(sp), false);
536     Sampler::Destroy(sp);
537 }
538 
TEST_F(SamplerTest,InspectorSamplerCollectNativeThreadTest)539 TEST_F(SamplerTest, InspectorSamplerCollectNativeThreadTest)
540 {
541     auto *sp = Sampler::Create();
542     ASSERT_NE(sp, nullptr);
543 
544     std::atomic<bool> syncFlag1 = false;
545     std::atomic<bool> syncFlag2 = false;
546     std::atomic<bool> syncFlag3 = false;
547     std::thread managedThread1(RunManagedThread, &syncFlag1);
548     std::thread nativeThread2(RunNativeThread, &syncFlag2);
549 
550     while (!syncFlag1 || !syncFlag2) {
551         ;
552     }
553 
554     ASSERT_EQ(sp->Start(std::make_unique<InspectorStreamWriter>(G_SAMPLES_RECORD)), true);
555     ASSERT_NE(ExtractListenerTid(sp), 0);
556     ASSERT_NE(ExtractSamplerTid(sp), 0);
557     ASSERT_EQ(ExtractIsActive(sp), true);
558 
559     // two additional threads must be running - a managed and a native one
560     ASSERT_EQ(ExtractManagedThreads(sp).size(), 3UL);
561     std::thread nativeThread3(RunNativeThread, &syncFlag3);
562     while (!syncFlag3) {
563         ;
564     }
565 
566     ASSERT_EQ(ExtractManagedThreads(sp).size(), 4UL);
567 
568     syncFlag1 = false;
569     syncFlag2 = false;
570     syncFlag3 = false;
571     managedThread1.join();
572     nativeThread2.join();
573     nativeThread3.join();
574 
575     ASSERT_EQ(ExtractManagedThreads(sp).size(), 1);
576 
577     sp->Stop();
578     ASSERT_EQ(ExtractListenerTid(sp), 0);
579     ASSERT_EQ(ExtractSamplerTid(sp), 0);
580     ASSERT_EQ(ExtractIsActive(sp), false);
581     Sampler::Destroy(sp);
582 }
583 
584 // Testing pipes
TEST_F(SamplerTest,SamplerPipesTest)585 TEST_F(SamplerTest, SamplerPipesTest)
586 {
587     auto *sp = Sampler::Create();
588     ASSERT_NE(sp, nullptr);
589     sp->Start(std::make_unique<FileStreamWriter>(g_profilerFilename));
590 
591     ASSERT_NE(ExtractPipes(sp)[ThreadCommunicator::PIPE_READ_ID], 0);
592     ASSERT_NE(ExtractPipes(sp)[ThreadCommunicator::PIPE_WRITE_ID], 0);
593 
594     sp->Stop();
595     Sampler::Destroy(sp);
596 }
597 
TEST_F(SamplerTest,InspectorSamplerPipesTest)598 TEST_F(SamplerTest, InspectorSamplerPipesTest)
599 {
600     auto *sp = Sampler::Create();
601     ASSERT_NE(sp, nullptr);
602     sp->Start(std::make_unique<InspectorStreamWriter>(G_SAMPLES_RECORD));
603 
604     ASSERT_NE(ExtractPipes(sp)[ThreadCommunicator::PIPE_READ_ID], 0);
605     ASSERT_NE(ExtractPipes(sp)[ThreadCommunicator::PIPE_WRITE_ID], 0);
606 
607     sp->Stop();
608     Sampler::Destroy(sp);
609 }
610 
611 // Stress testing restart
TEST_F(SamplerTest,ProfilerRestartStressTest)612 TEST_F(SamplerTest, ProfilerRestartStressTest)
613 {
614     constexpr size_t CURRENT_TEST_THRESHOLD = TEST_CYCLE_THRESHOLD / 10;
615     auto *sp = Sampler::Create();
616     ASSERT_NE(sp, nullptr);
617 
618     for (uint32_t i = 0; i < CURRENT_TEST_THRESHOLD; i++) {
619         ASSERT_EQ(sp->Start(std::make_unique<FileStreamWriter>(g_profilerFilename)), true);
620         sp->Stop();
621     }
622 
623     Sampler::Destroy(sp);
624 }
625 
TEST_F(SamplerTest,InspectorProfilerRestartStressTest)626 TEST_F(SamplerTest, InspectorProfilerRestartStressTest)
627 {
628     constexpr size_t CURRENT_TEST_THRESHOLD = TEST_CYCLE_THRESHOLD / 10;
629     auto *sp = Sampler::Create();
630     ASSERT_NE(sp, nullptr);
631 
632     for (uint32_t i = 0; i < CURRENT_TEST_THRESHOLD; i++) {
633         ASSERT_EQ(sp->Start(std::make_unique<InspectorStreamWriter>(G_SAMPLES_RECORD)), true);
634         sp->Stop();
635     }
636 
637     Sampler::Destroy(sp);
638 }
639 
TEST_F(SamplerTest,ThreadCommunicatorTest)640 TEST_F(SamplerTest, ThreadCommunicatorTest)
641 {
642     ThreadCommunicator communicator;
643 
644     SampleInfo sampleInput;
645     SampleInfo sampleOutput;
646     FullfillFakeSample(&sampleInput);
647     ASSERT_TRUE(communicator.Init());
648     ASSERT_TRUE(communicator.SendSample(sampleInput));
649     ASSERT_TRUE(communicator.ReadSample(&sampleOutput));
650     ASSERT_EQ(sampleOutput, sampleInput);
651 }
652 
CommunicatorStressWritterThread(const ThreadCommunicator * com,const SampleInfo & sample,uint32_t messagesAmount)653 static void CommunicatorStressWritterThread(const ThreadCommunicator *com, const SampleInfo &sample,
654                                             uint32_t messagesAmount)
655 {
656     for (uint32_t i = 0; i < messagesAmount; ++i) {
657         // If the sample write failed we retrying to send it
658         if (!com->SendSample(sample)) {
659             std::cerr << "Failed to send a sample" << std::endl;
660             Runtime::Abort();
661         }
662     }
663 }
664 
665 static constexpr uint32_t MESSAGES_AMOUNT = TEST_CYCLE_THRESHOLD * 100;
666 
TEST_F(SamplerTest,ThreadCommunicatorMultithreadTest)667 TEST_F(SamplerTest, ThreadCommunicatorMultithreadTest)
668 {
669     ThreadCommunicator communicator;
670     SampleInfo sampleOutput;
671     SampleInfo sampleInput;
672     FullfillFakeSample(&sampleInput);
673     ASSERT_TRUE(communicator.Init());
674 
675     std::thread sender(CommunicatorStressWritterThread, &communicator, sampleInput, MESSAGES_AMOUNT);
676     for (uint32_t i = 0; i < MESSAGES_AMOUNT; ++i) {
677         // If the sample write failed we retrying to send it
678         if (!communicator.ReadSample(&sampleOutput)) {
679             std::cerr << "Failed to read a sample" << std::endl;
680             Runtime::Abort();
681         }
682         ASSERT_EQ(sampleOutput, sampleInput);
683     }
684     sender.join();
685 }
686 
687 // Testing reader and writer by writing and reading from .aspt one sample
TEST_F(SamplerTest,StreamWriterReaderTest)688 TEST_F(SamplerTest, StreamWriterReaderTest)
689 {
690     const char *streamTestFilename = "stream_writer_reader_test.aspt";
691     SampleInfo sampleOutput;
692     SampleInfo sampleInput;
693 
694     {
695         FileStreamWriter writer(streamTestFilename);
696         FullfillFakeSample(&sampleInput);
697 
698         writer.WriteSample(sampleInput);
699     }
700 
701     SampleReader reader(streamTestFilename);
702     ASSERT_TRUE(reader.GetNextSample(&sampleOutput));
703     ASSERT_EQ(sampleOutput, sampleInput);
704     ASSERT_FALSE(reader.GetNextSample(&sampleOutput));
705     ASSERT_FALSE(reader.GetNextModule(nullptr));
706 }
707 
TEST_F(SamplerTest,InspectorStreamWriterReaderTest)708 TEST_F(SamplerTest, InspectorStreamWriterReaderTest)
709 {
710     const std::shared_ptr<SamplesRecord> samplesRecord = std::make_shared<SamplesRecord>();
711     SampleInfo sampleInput;
712 
713     {
714         InspectorStreamWriter writer(samplesRecord);
715         FullfillFakeSample(&sampleInput);
716 
717         writer.WriteSample(sampleInput);
718     }
719 
720     auto allThreadsProfileInfos = samplesRecord->GetAllThreadsProfileInfos();
721     ASSERT_NE(allThreadsProfileInfos, nullptr);
722     ASSERT_EQ(allThreadsProfileInfos->size(), 1);
723     ASSERT_NE((*allThreadsProfileInfos)[0]->nodeCount, 0);
724     ASSERT_EQ((*allThreadsProfileInfos)[0]->startTime, 0);
725     ASSERT_EQ((*allThreadsProfileInfos)[0]->stopTime, 0);
726     ASSERT_EQ((*allThreadsProfileInfos)[0]->tid, GetThreadId());
727 }
728 
729 // Testing reader and writer by writing and reading from .aspt lots of samples
TEST_F(SamplerTest,StreamWriterReaderLotsSamplesTest)730 TEST_F(SamplerTest, StreamWriterReaderLotsSamplesTest)
731 {
732     constexpr size_t CURRENT_TEST_THRESHOLD = TEST_CYCLE_THRESHOLD * 100;
733     const char *streamTestFilename = "stream_writer_reader_test_lots_samples.aspt";
734     SampleInfo sampleOutput;
735     SampleInfo sampleInput;
736 
737     {
738         FileStreamWriter writer(streamTestFilename);
739         FullfillFakeSample(&sampleInput);
740 
741         for (size_t i = 0; i < CURRENT_TEST_THRESHOLD; ++i) {
742             writer.WriteSample(sampleInput);
743         }
744     }
745 
746     SampleReader reader(streamTestFilename);
747     for (size_t i = 0; i < CURRENT_TEST_THRESHOLD; ++i) {
748         ASSERT_TRUE(reader.GetNextSample(&sampleOutput));
749         ASSERT_EQ(sampleOutput, sampleInput);
750     }
751     ASSERT_FALSE(reader.GetNextSample(&sampleOutput));
752     ASSERT_FALSE(reader.GetNextModule(nullptr));
753 }
754 
TEST_F(SamplerTest,InspectorStreamWriterReaderLotsSamplesTest)755 TEST_F(SamplerTest, InspectorStreamWriterReaderLotsSamplesTest)
756 {
757     constexpr size_t CURRENT_TEST_THRESHOLD = TEST_CYCLE_THRESHOLD * 100;
758     const std::shared_ptr<SamplesRecord> samplesRecord = std::make_shared<SamplesRecord>();
759     SampleInfo sampleInput;
760 
761     {
762         InspectorStreamWriter writer(samplesRecord);
763         FullfillFakeSample(&sampleInput);
764 
765         for (size_t i = 0; i < CURRENT_TEST_THRESHOLD; ++i) {
766             writer.WriteSample(sampleInput);
767         }
768     }
769 
770     auto allThreadsProfileInfos = samplesRecord->GetAllThreadsProfileInfos();
771     ASSERT_NE(allThreadsProfileInfos, nullptr);
772     ASSERT_EQ(allThreadsProfileInfos->size(), 1);
773     ASSERT_NE((*allThreadsProfileInfos)[0]->nodeCount, 0);
774     ASSERT_EQ((*allThreadsProfileInfos)[0]->startTime, 0);
775     ASSERT_EQ((*allThreadsProfileInfos)[0]->stopTime, 0);
776     ASSERT_EQ((*allThreadsProfileInfos)[0]->tid, GetThreadId());
777     ASSERT_EQ((*allThreadsProfileInfos)[0]->timeDeltas.size(), CURRENT_TEST_THRESHOLD);
778 }
779 
780 // Testing reader and writer by writing and reading from .aspt one module
TEST_F(SamplerTest,ModuleWriterReaderTest)781 TEST_F(SamplerTest, ModuleWriterReaderTest)
782 {
783     const char *streamTestFilename = "stream_module_test_filename.aspt";
784     FileInfo moduleInput = {pfId_, checksum_, "~/folder/folder/lib/panda_file.pa"};
785     FileInfo moduleOutput = {};
786 
787     {
788         FileStreamWriter writer(streamTestFilename);
789         writer.WriteModule(moduleInput);
790     }
791 
792     SampleReader reader(streamTestFilename);
793     ASSERT_TRUE(reader.GetNextModule(&moduleOutput));
794     ASSERT_EQ(moduleOutput, moduleInput);
795     ASSERT_FALSE(reader.GetNextModule(&moduleOutput));
796     ASSERT_FALSE(reader.GetNextSample(nullptr));
797 }
798 
799 // Testing reader and writer by writing and reading from .aspt lots of modules
TEST_F(SamplerTest,ModuleWriterReaderLotsModulesTest)800 TEST_F(SamplerTest, ModuleWriterReaderLotsModulesTest)
801 {
802     constexpr size_t CURRENT_TEST_THRESHOLD = TEST_CYCLE_THRESHOLD * 100;
803     const char *streamTestFilename = "stream_lots_modules_test_filename.aspt";
804     FileInfo moduleInput = {pfId_, checksum_, "~/folder/folder/lib/panda_file.pa"};
805     FileInfo moduleOutput = {};
806 
807     {
808         FileStreamWriter writer(streamTestFilename);
809         for (size_t i = 0; i < CURRENT_TEST_THRESHOLD; ++i) {
810             writer.WriteModule(moduleInput);
811         }
812     }
813 
814     SampleReader reader(streamTestFilename);
815     for (size_t i = 0; i < CURRENT_TEST_THRESHOLD; ++i) {
816         ASSERT_TRUE(reader.GetNextModule(&moduleOutput));
817         ASSERT_EQ(moduleOutput, moduleInput);
818     }
819     ASSERT_FALSE(reader.GetNextModule(&moduleOutput));
820     ASSERT_FALSE(reader.GetNextSample(nullptr));
821 }
822 
823 // Testing reader and writer by writing and reading from .aspt lots of modules
TEST_F(SamplerTest,WriterReaderLotsRowsModulesAndSamplesTest)824 TEST_F(SamplerTest, WriterReaderLotsRowsModulesAndSamplesTest)
825 {
826     constexpr size_t CURRENT_TEST_THRESHOLD = TEST_CYCLE_THRESHOLD * 100;
827     const char *streamTestFilename = "stream_lots_modules_and_samples_test_filename.aspt";
828     FileInfo moduleInput = {pfId_, checksum_, "~/folder/folder/lib/panda_file.pa"};
829     FileInfo moduleOutput = {};
830     SampleInfo sampleOutput;
831     SampleInfo sampleInput;
832 
833     {
834         FileStreamWriter writer(streamTestFilename);
835         FullfillFakeSample(&sampleInput);
836         for (size_t i = 0; i < CURRENT_TEST_THRESHOLD; ++i) {
837             writer.WriteModule(moduleInput);
838             writer.WriteSample(sampleInput);
839         }
840     }
841 
842     SampleReader reader(streamTestFilename);
843     for (size_t i = 0; i < CURRENT_TEST_THRESHOLD; ++i) {
844         ASSERT_TRUE(reader.GetNextModule(&moduleOutput));
845         ASSERT_EQ(moduleOutput, moduleInput);
846     }
847 
848     for (size_t i = 0; i < CURRENT_TEST_THRESHOLD; ++i) {
849         ASSERT_TRUE(reader.GetNextSample(&sampleOutput));
850         ASSERT_EQ(sampleOutput, sampleInput);
851     }
852 
853     ASSERT_FALSE(reader.GetNextModule(&moduleOutput));
854     ASSERT_FALSE(reader.GetNextSample(&sampleOutput));
855 }
856 
857 // Send sample to listener and check it inside the file
TEST_F(SamplerTest,ListenerWriteFakeSampleTest)858 TEST_F(SamplerTest, ListenerWriteFakeSampleTest)
859 {
860     const char *streamTestFilename = "listener_write_fake_sample_test.aspt";
861     auto *sp = Sampler::Create();
862     ASSERT_NE(sp, nullptr);
863     ASSERT_EQ(sp->Start(std::make_unique<FileStreamWriter>(streamTestFilename)), true);
864 
865     SampleInfo sampleOutput;
866     SampleInfo sampleInput;
867     FullfillFakeSample(&sampleInput);
868     sp->GetCommunicator().SendSample(sampleInput);
869     sp->Stop();
870 
871     bool status = true;
872     bool isPassed = false;
873     SampleReader reader(streamTestFilename);
874     while (status) {
875         status = reader.GetNextSample(&sampleOutput);
876         if (sampleOutput == sampleInput) {
877             isPassed = true;
878             break;
879         }
880     }
881 
882     ASSERT_TRUE(isPassed);
883 
884     Sampler::Destroy(sp);
885 }
886 
887 // Send lots of sample to listener and check it inside the file
TEST_F(SamplerTest,ListenerWriteLotsFakeSampleTest)888 TEST_F(SamplerTest, ListenerWriteLotsFakeSampleTest)
889 {
890     constexpr size_t CURRENT_TEST_THRESHOLD = TEST_CYCLE_THRESHOLD * 100;
891     const char *streamTestFilename = "listener_write_lots_fake_sample_test.aspt";
892     auto *sp = Sampler::Create();
893     ASSERT_NE(sp, nullptr);
894     ASSERT_EQ(sp->Start(std::make_unique<FileStreamWriter>(streamTestFilename)), true);
895 
896     SampleInfo sampleOutput;
897     SampleInfo sampleInput;
898     size_t sentSamplesCounter = 0;
899     FullfillFakeSample(&sampleInput);
900     for (size_t i = 0; i < CURRENT_TEST_THRESHOLD; ++i) {
901         if (sp->GetCommunicator().SendSample(sampleInput)) {
902             ++sentSamplesCounter;
903         }
904     }
905     sp->Stop();
906 
907     bool status = true;
908     size_t amountOfSamples = 0;
909     SampleReader reader(streamTestFilename);
910     while (status) {
911         if (sampleOutput == sampleInput) {
912             ++amountOfSamples;
913         }
914         status = reader.GetNextSample(&sampleOutput);
915     }
916 
917     ASSERT_EQ(amountOfSamples, sentSamplesCounter);
918 
919     Sampler::Destroy(sp);
920 }
921 
922 // Checking that sampler collect panda files correctly
TEST_F(SamplerTest,CollectPandaFilesTest)923 TEST_F(SamplerTest, CollectPandaFilesTest)
924 {
925     const char *streamTestFilename = "collect_panda_file_test.aspt";
926     auto *sp = Sampler::Create();
927     ASSERT_NE(sp, nullptr);
928     ASSERT_EQ(sp->Start(std::make_unique<FileStreamWriter>(streamTestFilename)), true);
929     sp->Stop();
930 
931     FileInfo moduleInfo;
932     SampleReader reader(streamTestFilename);
933     bool status = false;
934     while (reader.GetNextModule(&moduleInfo)) {
935         auto pfPtr = reinterpret_cast<panda_file::File *>(moduleInfo.ptr);
936         ASSERT_EQ(pfPtr->GetFullFileName(), moduleInfo.pathname);
937         status = true;
938     }
939     ASSERT_TRUE(status);
940     Sampler::Destroy(sp);
941 }
942 
943 // Checking that sampler collect panda files correctly
TEST_F(SamplerTest,WriteModuleEventTest)944 TEST_F(SamplerTest, WriteModuleEventTest)
945 {
946     const char *streamTestFilename = "collect_panda_file_test.aspt";
947     auto *sp = Sampler::Create();
948     ASSERT_NE(sp, nullptr);
949     ASSERT_EQ(sp->Start(std::make_unique<FileStreamWriter>(streamTestFilename)), true);
950 
951     auto execPath = ark::os::file::File::GetExecutablePath();
952     std::string pandafile =
953         execPath.Value() + Separator() + ".." + Separator() + "pandastdlib" + Separator() + "arkstdlib.abc";
954 
955     auto pf = panda_file::OpenPandaFileOrZip(pandafile);
956     Runtime::GetCurrent()->GetClassLinker()->AddPandaFile(std::move(pf));
957     // NOTE:
958     // It's necessary to add assert that only one module is loaded
959     // But simply add assert on loaded size is UB, because such assert may fail if the WriteLoadedPandaFiles
960     // managed to dump the loaded module into the trace before the assert call occurs in this test
961 
962     sp->Stop();
963 
964     FileInfo moduleInfo;
965     SampleReader reader(streamTestFilename);
966     bool status = false;
967     while (reader.GetNextModule(&moduleInfo)) {
968         auto pfPtr = reinterpret_cast<panda_file::File *>(moduleInfo.ptr);
969         ASSERT_EQ(pfPtr->GetFullFileName(), moduleInfo.pathname);
970         status = true;
971     }
972     ASSERT_TRUE(status);
973 
974     Sampler::Destroy(sp);
975 }
976 
977 // Sampling big pandasm program and convert it
TEST_F(SamplerTest,ProfilerSamplerSignalHandlerTest)978 TEST_F(SamplerTest, ProfilerSamplerSignalHandlerTest)
979 {
980     const char *streamTestFilename = "sampler_signal_handler_test.aspt";
981     const char *resultTestFilename = "sampler_signal_handler_test.csv";
982     size_t sampleCounter = 0;
983 
984     {
985         auto *sp = Sampler::Create();
986         ASSERT_NE(sp, nullptr);
987         ASSERT_EQ(sp->Start(std::make_unique<FileStreamWriter>(streamTestFilename)), true);
988 
989         {
990             ASSERT_TRUE(Runtime::GetCurrent()->Execute("_GLOBAL::main", {}));
991         }
992         sp->Stop();
993 
994         SampleInfo sample;
995         SampleReader reader(streamTestFilename);
996         bool isFind = false;
997 
998         while (reader.GetNextSample(&sample)) {
999             ++sampleCounter;
1000             if (sample.stackInfo.managedStackSize == 2U) {
1001                 isFind = true;
1002                 continue;
1003             }
1004             ASSERT_NE(sample.stackInfo.managedStackSize, 0);
1005             ASSERT_EQ(GetThreadId(), sample.threadInfo.threadId);
1006         }
1007 
1008         ASSERT_EQ(isFind, true);
1009 
1010         Sampler::Destroy(sp);
1011     }
1012 
1013     // Checking converter
1014     {
1015         AsptConverter conv(streamTestFilename);
1016         ASSERT_EQ(conv.CollectTracesStats(), sampleCounter);
1017         ASSERT_TRUE(conv.CollectModules());
1018         ASSERT_TRUE(conv.DumpResolvedTracesAsCSV(resultTestFilename));
1019     }
1020 }
1021 
1022 }  // namespace ark::tooling::sampler::test
1023