• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-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 <gmock/gmock.h>
17 #include <gtest/gtest.h>
18 
19 #include "assembler/assembly-parser.h"
20 #include "libpandafile/file.h"
21 #include "libpandabase/trace/trace.h"
22 #include "libpandabase/panda_gen_options/generated/base_options.h"
23 #include "runtime/include/thread_scopes.h"
24 #include "runtime/include/runtime.h"
25 #include "runtime/tooling/sampler/sampling_profiler.h"
26 #include "runtime/interpreter/runtime_interface.h"
27 #include "tools/sampler/aspt_converter.h"
28 
29 namespace ark::tooling::sampler::test {
30 
Separator()31 inline std::string Separator()
32 {
33 #ifdef _WIN32
34     return "\\";
35 #else
36     return "/";
37 #endif
38 }
39 
40 static const char *g_profilerFilename = "profiler_result.aspt";
41 static const char *g_pandaFileName = "sampling_profiler_test_ark_asm.abc";
42 static constexpr size_t TEST_CYCLE_THRESHOLD = 100;
43 
44 // NOLINTBEGIN(misc-non-private-member-variables-in-classes)
45 class SamplerTest : public testing::Test {
46 public:
47     // NOLINTNEXTLINE(readability-function-size)
SetUp()48     void SetUp() override
49     {
50         Logger::Initialize(base_options::Options(""));
51 
52         RuntimeOptions options;
53         options.SetLoadRuntimes({"core"});
54         options.SetRunGcInPlace(true);
55         options.SetVerifyCallStack(false);
56         options.SetInterpreterType("cpp");
57         auto execPath = ark::os::file::File::GetExecutablePath();
58         std::string pandaStdLib =
59             execPath.Value() + Separator() + ".." + Separator() + "pandastdlib" + Separator() + "arkstdlib.abc";
60         options.SetBootPandaFiles({pandaStdLib});
61         Runtime::Create(options);
62 
63         auto pf = panda_file::OpenPandaFileOrZip(g_pandaFileName);
64         Runtime::GetCurrent()->GetClassLinker()->AddPandaFile(std::move(pf));
65 
66         thread_ = ark::MTManagedThread::GetCurrent();
67     }
68 
TearDown()69     void TearDown() override
70     {
71         Runtime::Destroy();
72     }
73 
FullfillFakeSample(SampleInfo * ps)74     void FullfillFakeSample(SampleInfo *ps)
75     {
76         for (uint32_t i = 0; i < SampleInfo::StackInfo::MAX_STACK_DEPTH; ++i) {
77             ps->stackInfo.managedStack[i] = {i, pfId_};
78         }
79         ps->threadInfo.threadId = GetThreadId();
80         ps->stackInfo.managedStackSize = SampleInfo::StackInfo::MAX_STACK_DEPTH;
81     }
82 
83     // Friend wrappers for accesing samplers private fields
ExtractListenerTid(const Sampler * sPtr)84     static os::thread::NativeHandleType ExtractListenerTid(const Sampler *sPtr)
85     {
86         return sPtr->listenerTid_;
87     }
88 
ExtractSamplerTid(const Sampler * sPtr)89     static os::thread::NativeHandleType ExtractSamplerTid(const Sampler *sPtr)
90     {
91         return sPtr->samplerTid_;
92     }
93 
ExtractManagedThreads(Sampler * sPtr)94     static PandaSet<os::thread::ThreadId> ExtractManagedThreads(Sampler *sPtr)
95     {
96         // Sending a copy to avoid of datarace
97         os::memory::LockHolder holder(sPtr->managedThreadsLock_);
98         PandaSet<os::thread::ThreadId> managedThreadsCopy = sPtr->managedThreads_;
99         return managedThreadsCopy;
100     }
101 
ExtractLoadedPFSize(Sampler * sPtr)102     static size_t ExtractLoadedPFSize(Sampler *sPtr)
103     {
104         os::memory::LockHolder holder(sPtr->loadedPfsLock_);
105         return sPtr->loadedPfs_.size();
106     }
107 
ExtractPipes(const Sampler * sPtr)108     static std::array<int, 2> ExtractPipes(const Sampler *sPtr)
109     {
110         // Sending a copy to avoid of datarace
111         return sPtr->communicator_.listenerPipe_;
112     }
113 
ExtractIsActive(const Sampler * sPtr)114     static bool ExtractIsActive(const Sampler *sPtr)
115     {
116         return sPtr->isActive_;
117     }
118 
GetThreadId()119     uint32_t GetThreadId()
120     {
121         return os::thread::GetCurrentThreadId();
122     }
123 
124 protected:
125     ark::MTManagedThread *thread_ {nullptr};
126     uintptr_t pfId_ {0};
127     uint32_t checksum_ {0};
128 };
129 // NOLINTEND(misc-non-private-member-variables-in-classes)
130 
TEST_F(SamplerTest,SamplerInitTest)131 TEST_F(SamplerTest, SamplerInitTest)
132 {
133     auto *sp = Sampler::Create();
134     ASSERT_NE(sp, nullptr);
135 
136     ASSERT_EQ(ExtractListenerTid(sp), 0);
137     ASSERT_EQ(ExtractSamplerTid(sp), 0);
138     ASSERT_EQ(ExtractIsActive(sp), false);
139 
140     ASSERT_EQ(sp->Start(g_profilerFilename), true);
141     ASSERT_NE(ExtractListenerTid(sp), 0);
142     ASSERT_NE(ExtractSamplerTid(sp), 0);
143     ASSERT_EQ(ExtractIsActive(sp), true);
144 
145     ASSERT_EQ(sp->Start(g_profilerFilename), false);
146 
147     sp->Stop();
148     ASSERT_EQ(ExtractListenerTid(sp), 0);
149     ASSERT_EQ(ExtractSamplerTid(sp), 0);
150     ASSERT_EQ(ExtractIsActive(sp), false);
151 
152     // Second run
153     ASSERT_EQ(sp->Start(g_profilerFilename), true);
154     ASSERT_NE(ExtractListenerTid(sp), 0);
155     ASSERT_NE(ExtractSamplerTid(sp), 0);
156     ASSERT_EQ(ExtractIsActive(sp), true);
157 
158     sp->Stop();
159     ASSERT_EQ(ExtractListenerTid(sp), 0);
160     ASSERT_EQ(ExtractSamplerTid(sp), 0);
161     ASSERT_EQ(ExtractIsActive(sp), false);
162     Sampler::Destroy(sp);
163 }
164 
RunManagedThread(std::atomic<bool> * syncFlag)165 void RunManagedThread(std::atomic<bool> *syncFlag)
166 {
167     auto *mThr = ark::MTManagedThread::Create(ark::Runtime::GetCurrent(), ark::Runtime::GetCurrent()->GetPandaVM());
168     mThr->ManagedCodeBegin();
169 
170     *syncFlag = true;
171     while (*syncFlag) {
172         // Calling safepoint 'cause starting profiler required to stop all managed threads
173         interpreter::RuntimeInterface::Safepoint();
174     }
175 
176     mThr->ManagedCodeEnd();
177     mThr->Destroy();
178 }
179 
RunManagedThreadAndSaveThreadId(std::atomic<bool> * syncFlag,os::thread::ThreadId * id)180 void RunManagedThreadAndSaveThreadId(std::atomic<bool> *syncFlag, os::thread::ThreadId *id)
181 {
182     auto *mThr = ark::MTManagedThread::Create(ark::Runtime::GetCurrent(), ark::Runtime::GetCurrent()->GetPandaVM());
183     mThr->ManagedCodeBegin();
184 
185     *id = os::thread::GetCurrentThreadId();
186     *syncFlag = true;
187     while (*syncFlag) {
188         // Calling safepoint 'cause starting profiler required to stop all managed threads
189         interpreter::RuntimeInterface::Safepoint();
190     }
191 
192     mThr->ManagedCodeEnd();
193     mThr->Destroy();
194 }
195 
RunNativeThread(std::atomic<bool> * syncFlag)196 void RunNativeThread(std::atomic<bool> *syncFlag)
197 {
198     auto *mThr = ark::MTManagedThread::Create(ark::Runtime::GetCurrent(), ark::Runtime::GetCurrent()->GetPandaVM());
199 
200     *syncFlag = true;
201     while (*syncFlag) {
202     }
203 
204     mThr->Destroy();
205 }
206 
207 // Testing notification thread started/finished
TEST_F(SamplerTest,SamplerEventThreadNotificationTest)208 TEST_F(SamplerTest, SamplerEventThreadNotificationTest)
209 {
210     auto *sp = Sampler::Create();
211     ASSERT_NE(sp, nullptr);
212 
213     ASSERT_EQ(sp->Start(g_profilerFilename), true);
214     ASSERT_NE(ExtractListenerTid(sp), 0);
215     ASSERT_NE(ExtractSamplerTid(sp), 0);
216     ASSERT_EQ(ExtractIsActive(sp), true);
217 
218     ASSERT_FALSE(ExtractManagedThreads(sp).empty());
219     ASSERT_EQ(ExtractManagedThreads(sp).size(), 1);
220 
221     std::atomic<bool> syncFlag1 = false;
222     std::atomic<bool> syncFlag2 = false;
223     std::atomic<bool> syncFlag3 = false;
224     std::thread managedThread1(RunManagedThread, &syncFlag1);
225     std::thread managedThread2(RunManagedThread, &syncFlag2);
226     std::thread managedThread3(RunManagedThread, &syncFlag3);
227 
228     while (!syncFlag1 || !syncFlag2 || !syncFlag3) {
229         ;
230     }
231     ASSERT_EQ(ExtractManagedThreads(sp).size(), 4UL);
232 
233     syncFlag1 = false;
234     syncFlag2 = false;
235     syncFlag3 = false;
236     managedThread1.join();
237     managedThread2.join();
238     managedThread3.join();
239 
240     ASSERT_EQ(ExtractManagedThreads(sp).size(), 1);
241 
242     sp->Stop();
243     ASSERT_EQ(ExtractListenerTid(sp), 0);
244     ASSERT_EQ(ExtractSamplerTid(sp), 0);
245     ASSERT_EQ(ExtractIsActive(sp), false);
246     Sampler::Destroy(sp);
247 }
248 
249 // Testing notification thread started/finished
TEST_F(SamplerTest,SamplerCheckThreadIdTest)250 TEST_F(SamplerTest, SamplerCheckThreadIdTest)
251 {
252     auto *sp = Sampler::Create();
253     ASSERT_NE(sp, nullptr);
254 
255     ASSERT_EQ(sp->Start(g_profilerFilename), true);
256     ASSERT_NE(ExtractListenerTid(sp), 0);
257     ASSERT_NE(ExtractSamplerTid(sp), 0);
258     ASSERT_EQ(ExtractIsActive(sp), true);
259 
260     ASSERT_EQ(ExtractManagedThreads(sp).size(), 1);
261 
262     std::atomic<bool> syncFlag1 = false;
263     os::thread::ThreadId mtId = 0;
264     std::thread managedThread1(RunManagedThreadAndSaveThreadId, &syncFlag1, &mtId);
265 
266     while (!syncFlag1) {
267         ;
268     }
269     // only one additional managed thread must be running
270     ASSERT_EQ(ExtractManagedThreads(sp).size(), 2UL);
271     bool isPassed = false;
272 
273     for (const auto &elem : ExtractManagedThreads(sp)) {
274         if (elem == mtId) {
275             isPassed = true;
276             break;
277         }
278     }
279     ASSERT_TRUE(isPassed);
280 
281     syncFlag1 = false;
282     managedThread1.join();
283 
284     ASSERT_EQ(ExtractManagedThreads(sp).size(), 1);
285 
286     sp->Stop();
287     ASSERT_EQ(ExtractListenerTid(sp), 0);
288     ASSERT_EQ(ExtractSamplerTid(sp), 0);
289     ASSERT_EQ(ExtractIsActive(sp), false);
290     Sampler::Destroy(sp);
291 }
292 
293 // Testing thread collection
TEST_F(SamplerTest,SamplerCollectThreadTest)294 TEST_F(SamplerTest, SamplerCollectThreadTest)
295 {
296     auto *sp = Sampler::Create();
297     ASSERT_NE(sp, nullptr);
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 
310     ASSERT_EQ(sp->Start(g_profilerFilename), true);
311     ASSERT_NE(ExtractListenerTid(sp), 0);
312     ASSERT_NE(ExtractSamplerTid(sp), 0);
313     ASSERT_EQ(ExtractIsActive(sp), true);
314 
315     ASSERT_EQ(ExtractManagedThreads(sp).size(), 4UL);
316 
317     syncFlag1 = false;
318     syncFlag2 = false;
319     syncFlag3 = false;
320     managedThread1.join();
321     managedThread2.join();
322     managedThread3.join();
323 
324     ASSERT_EQ(ExtractManagedThreads(sp).size(), 1);
325 
326     sp->Stop();
327     ASSERT_EQ(ExtractListenerTid(sp), 0);
328     ASSERT_EQ(ExtractSamplerTid(sp), 0);
329     ASSERT_EQ(ExtractIsActive(sp), false);
330     Sampler::Destroy(sp);
331 }
332 
333 // Testing native thread collection
TEST_F(SamplerTest,SamplerCollectNativeThreadTest)334 TEST_F(SamplerTest, SamplerCollectNativeThreadTest)
335 {
336     auto *sp = Sampler::Create();
337     ASSERT_NE(sp, nullptr);
338 
339     std::atomic<bool> syncFlag1 = false;
340     std::atomic<bool> syncFlag2 = false;
341     std::atomic<bool> syncFlag3 = false;
342     std::thread managedThread1(RunManagedThread, &syncFlag1);
343     std::thread nativeThread2(RunNativeThread, &syncFlag2);
344 
345     while (!syncFlag1 || !syncFlag2) {
346         ;
347     }
348 
349     ASSERT_EQ(sp->Start(g_profilerFilename), true);
350     ASSERT_NE(ExtractListenerTid(sp), 0);
351     ASSERT_NE(ExtractSamplerTid(sp), 0);
352     ASSERT_EQ(ExtractIsActive(sp), true);
353 
354     // two additional threads must be running - a managed and a native one
355     ASSERT_EQ(ExtractManagedThreads(sp).size(), 3UL);
356     std::thread nativeThread3(RunNativeThread, &syncFlag3);
357     while (!syncFlag3) {
358         ;
359     }
360 
361     ASSERT_EQ(ExtractManagedThreads(sp).size(), 4UL);
362 
363     syncFlag1 = false;
364     syncFlag2 = false;
365     syncFlag3 = false;
366     managedThread1.join();
367     nativeThread2.join();
368     nativeThread3.join();
369 
370     ASSERT_EQ(ExtractManagedThreads(sp).size(), 1);
371 
372     sp->Stop();
373     ASSERT_EQ(ExtractListenerTid(sp), 0);
374     ASSERT_EQ(ExtractSamplerTid(sp), 0);
375     ASSERT_EQ(ExtractIsActive(sp), false);
376     Sampler::Destroy(sp);
377 }
378 
379 // Testing pipes
TEST_F(SamplerTest,SamplerPipesTest)380 TEST_F(SamplerTest, SamplerPipesTest)
381 {
382     auto *sp = Sampler::Create();
383     ASSERT_NE(sp, nullptr);
384     sp->Start(g_profilerFilename);
385 
386     ASSERT_NE(ExtractPipes(sp)[ThreadCommunicator::PIPE_READ_ID], 0);
387     ASSERT_NE(ExtractPipes(sp)[ThreadCommunicator::PIPE_WRITE_ID], 0);
388 
389     sp->Stop();
390     Sampler::Destroy(sp);
391 }
392 
393 // Stress testing restart
TEST_F(SamplerTest,ProfilerRestartStressTest)394 TEST_F(SamplerTest, ProfilerRestartStressTest)
395 {
396     constexpr size_t CURRENT_TEST_THRESHOLD = TEST_CYCLE_THRESHOLD / 10;
397     auto *sp = Sampler::Create();
398     ASSERT_NE(sp, nullptr);
399 
400     for (uint32_t i = 0; i < CURRENT_TEST_THRESHOLD; i++) {
401         ASSERT_EQ(sp->Start(g_profilerFilename), true);
402         sp->Stop();
403     }
404 
405     Sampler::Destroy(sp);
406 }
407 
TEST_F(SamplerTest,ThreadCommunicatorTest)408 TEST_F(SamplerTest, ThreadCommunicatorTest)
409 {
410     ThreadCommunicator communicator;
411 
412     SampleInfo sampleInput;
413     SampleInfo sampleOutput;
414     FullfillFakeSample(&sampleInput);
415     ASSERT_TRUE(communicator.Init());
416     ASSERT_TRUE(communicator.SendSample(sampleInput));
417     ASSERT_TRUE(communicator.ReadSample(&sampleOutput));
418     ASSERT_EQ(sampleOutput, sampleInput);
419 }
420 
CommunicatorStressWritterThread(const ThreadCommunicator * com,const SampleInfo & sample,uint32_t messagesAmount)421 static void CommunicatorStressWritterThread(const ThreadCommunicator *com, const SampleInfo &sample,
422                                             uint32_t messagesAmount)
423 {
424     for (uint32_t i = 0; i < messagesAmount; ++i) {
425         // If the sample write failed we retrying to send it
426         if (!com->SendSample(sample)) {
427             std::cerr << "Failed to send a sample" << std::endl;
428             Runtime::Abort();
429         }
430     }
431 }
432 
TEST_F(SamplerTest,ThreadCommunicatorMultithreadTest)433 TEST_F(SamplerTest, ThreadCommunicatorMultithreadTest)
434 {
435     constexpr uint32_t MESSAGES_AMOUNT = TEST_CYCLE_THRESHOLD * 100;
436 
437     ThreadCommunicator communicator;
438     SampleInfo sampleOutput;
439     SampleInfo sampleInput;
440     FullfillFakeSample(&sampleInput);
441     ASSERT_TRUE(communicator.Init());
442 
443     std::thread sender(CommunicatorStressWritterThread, &communicator, sampleInput, MESSAGES_AMOUNT);
444     for (uint32_t i = 0; i < MESSAGES_AMOUNT; ++i) {
445         // If the sample write failed we retrying to send it
446         if (!communicator.ReadSample(&sampleOutput)) {
447             std::cerr << "Failed to read a sample" << std::endl;
448             Runtime::Abort();
449         }
450         ASSERT_EQ(sampleOutput, sampleInput);
451     }
452     sender.join();
453 }
454 
455 // Testing reader and writer by writing and reading from .aspt one sample
TEST_F(SamplerTest,StreamWriterReaderTest)456 TEST_F(SamplerTest, StreamWriterReaderTest)
457 {
458     const char *streamTestFilename = "stream_writer_reader_test.aspt";
459     SampleInfo sampleOutput;
460     SampleInfo sampleInput;
461 
462     {
463         StreamWriter writer(streamTestFilename);
464         FullfillFakeSample(&sampleInput);
465 
466         writer.WriteSample(sampleInput);
467     }
468 
469     SampleReader reader(streamTestFilename);
470     ASSERT_TRUE(reader.GetNextSample(&sampleOutput));
471     ASSERT_EQ(sampleOutput, sampleInput);
472     ASSERT_FALSE(reader.GetNextSample(&sampleOutput));
473     ASSERT_FALSE(reader.GetNextModule(nullptr));
474 }
475 
476 // Testing reader and writer by writing and reading from .aspt lots of samples
TEST_F(SamplerTest,StreamWriterReaderLotsSamplesTest)477 TEST_F(SamplerTest, StreamWriterReaderLotsSamplesTest)
478 {
479     constexpr size_t CURRENT_TEST_THRESHOLD = TEST_CYCLE_THRESHOLD * 100;
480     const char *streamTestFilename = "stream_writer_reader_test_lots_samples.aspt";
481     SampleInfo sampleOutput;
482     SampleInfo sampleInput;
483 
484     {
485         StreamWriter writer(streamTestFilename);
486         FullfillFakeSample(&sampleInput);
487 
488         for (size_t i = 0; i < CURRENT_TEST_THRESHOLD; ++i) {
489             writer.WriteSample(sampleInput);
490         }
491     }
492 
493     SampleReader reader(streamTestFilename);
494     for (size_t i = 0; i < CURRENT_TEST_THRESHOLD; ++i) {
495         ASSERT_TRUE(reader.GetNextSample(&sampleOutput));
496         ASSERT_EQ(sampleOutput, sampleInput);
497     }
498     ASSERT_FALSE(reader.GetNextSample(&sampleOutput));
499     ASSERT_FALSE(reader.GetNextModule(nullptr));
500 }
501 
502 // Testing reader and writer by writing and reading from .aspt one module
TEST_F(SamplerTest,ModuleWriterReaderTest)503 TEST_F(SamplerTest, ModuleWriterReaderTest)
504 {
505     const char *streamTestFilename = "stream_module_test_filename.aspt";
506     FileInfo moduleInput = {pfId_, checksum_, "~/folder/folder/lib/panda_file.pa"};
507     FileInfo moduleOutput = {};
508 
509     {
510         StreamWriter writer(streamTestFilename);
511         writer.WriteModule(moduleInput);
512     }
513 
514     SampleReader reader(streamTestFilename);
515     ASSERT_TRUE(reader.GetNextModule(&moduleOutput));
516     ASSERT_EQ(moduleOutput, moduleInput);
517     ASSERT_FALSE(reader.GetNextModule(&moduleOutput));
518     ASSERT_FALSE(reader.GetNextSample(nullptr));
519 }
520 
521 // Testing reader and writer by writing and reading from .aspt lots of modules
TEST_F(SamplerTest,ModuleWriterReaderLotsModulesTest)522 TEST_F(SamplerTest, ModuleWriterReaderLotsModulesTest)
523 {
524     constexpr size_t CURRENT_TEST_THRESHOLD = TEST_CYCLE_THRESHOLD * 100;
525     const char *streamTestFilename = "stream_lots_modules_test_filename.aspt";
526     FileInfo moduleInput = {pfId_, checksum_, "~/folder/folder/lib/panda_file.pa"};
527     FileInfo moduleOutput = {};
528 
529     {
530         StreamWriter writer(streamTestFilename);
531         for (size_t i = 0; i < CURRENT_TEST_THRESHOLD; ++i) {
532             writer.WriteModule(moduleInput);
533         }
534     }
535 
536     SampleReader reader(streamTestFilename);
537     for (size_t i = 0; i < CURRENT_TEST_THRESHOLD; ++i) {
538         ASSERT_TRUE(reader.GetNextModule(&moduleOutput));
539         ASSERT_EQ(moduleOutput, moduleInput);
540     }
541     ASSERT_FALSE(reader.GetNextModule(&moduleOutput));
542     ASSERT_FALSE(reader.GetNextSample(nullptr));
543 }
544 
545 // Testing reader and writer by writing and reading from .aspt lots of modules
TEST_F(SamplerTest,WriterReaderLotsRowsModulesAndSamplesTest)546 TEST_F(SamplerTest, WriterReaderLotsRowsModulesAndSamplesTest)
547 {
548     constexpr size_t CURRENT_TEST_THRESHOLD = TEST_CYCLE_THRESHOLD * 100;
549     const char *streamTestFilename = "stream_lots_modules_and_samples_test_filename.aspt";
550     FileInfo moduleInput = {pfId_, checksum_, "~/folder/folder/lib/panda_file.pa"};
551     FileInfo moduleOutput = {};
552     SampleInfo sampleOutput;
553     SampleInfo sampleInput;
554 
555     {
556         StreamWriter writer(streamTestFilename);
557         FullfillFakeSample(&sampleInput);
558         for (size_t i = 0; i < CURRENT_TEST_THRESHOLD; ++i) {
559             writer.WriteModule(moduleInput);
560             writer.WriteSample(sampleInput);
561         }
562     }
563 
564     SampleReader reader(streamTestFilename);
565     for (size_t i = 0; i < CURRENT_TEST_THRESHOLD; ++i) {
566         ASSERT_TRUE(reader.GetNextModule(&moduleOutput));
567         ASSERT_EQ(moduleOutput, moduleInput);
568     }
569 
570     for (size_t i = 0; i < CURRENT_TEST_THRESHOLD; ++i) {
571         ASSERT_TRUE(reader.GetNextSample(&sampleOutput));
572         ASSERT_EQ(sampleOutput, sampleInput);
573     }
574 
575     ASSERT_FALSE(reader.GetNextModule(&moduleOutput));
576     ASSERT_FALSE(reader.GetNextSample(&sampleOutput));
577 }
578 
579 // Send sample to listener and check it inside the file
TEST_F(SamplerTest,ListenerWriteFakeSampleTest)580 TEST_F(SamplerTest, ListenerWriteFakeSampleTest)
581 {
582     const char *streamTestFilename = "listener_write_fake_sample_test.aspt";
583     auto *sp = Sampler::Create();
584     ASSERT_NE(sp, nullptr);
585     ASSERT_EQ(sp->Start(streamTestFilename), true);
586 
587     SampleInfo sampleOutput;
588     SampleInfo sampleInput;
589     FullfillFakeSample(&sampleInput);
590     sp->GetCommunicator().SendSample(sampleInput);
591     sp->Stop();
592 
593     bool status = true;
594     bool isPassed = false;
595     SampleReader reader(streamTestFilename);
596     while (status) {
597         status = reader.GetNextSample(&sampleOutput);
598         if (sampleOutput == sampleInput) {
599             isPassed = true;
600             break;
601         }
602     }
603 
604     ASSERT_TRUE(isPassed);
605 
606     Sampler::Destroy(sp);
607 }
608 
609 // Send lots of sample to listener and check it inside the file
TEST_F(SamplerTest,ListenerWriteLotsFakeSampleTest)610 TEST_F(SamplerTest, ListenerWriteLotsFakeSampleTest)
611 {
612     constexpr size_t CURRENT_TEST_THRESHOLD = TEST_CYCLE_THRESHOLD * 100;
613     const char *streamTestFilename = "listener_write_lots_fake_sample_test.aspt";
614     auto *sp = Sampler::Create();
615     ASSERT_NE(sp, nullptr);
616     ASSERT_EQ(sp->Start(streamTestFilename), true);
617 
618     SampleInfo sampleOutput;
619     SampleInfo sampleInput;
620     size_t sentSamplesCounter = 0;
621     FullfillFakeSample(&sampleInput);
622     for (size_t i = 0; i < CURRENT_TEST_THRESHOLD; ++i) {
623         if (sp->GetCommunicator().SendSample(sampleInput)) {
624             ++sentSamplesCounter;
625         }
626     }
627     sp->Stop();
628 
629     bool status = true;
630     size_t amountOfSamples = 0;
631     SampleReader reader(streamTestFilename);
632     while (status) {
633         if (sampleOutput == sampleInput) {
634             ++amountOfSamples;
635         }
636         status = reader.GetNextSample(&sampleOutput);
637     }
638 
639     ASSERT_EQ(amountOfSamples, sentSamplesCounter);
640 
641     Sampler::Destroy(sp);
642 }
643 
644 // Checking that sampler collect panda files correctly
TEST_F(SamplerTest,CollectPandaFilesTest)645 TEST_F(SamplerTest, CollectPandaFilesTest)
646 {
647     const char *streamTestFilename = "collect_panda_file_test.aspt";
648     auto *sp = Sampler::Create();
649     ASSERT_NE(sp, nullptr);
650     ASSERT_EQ(sp->Start(streamTestFilename), true);
651     sp->Stop();
652 
653     FileInfo moduleInfo;
654     SampleReader reader(streamTestFilename);
655     bool status = false;
656     while (reader.GetNextModule(&moduleInfo)) {
657         auto pfPtr = reinterpret_cast<panda_file::File *>(moduleInfo.ptr);
658         ASSERT_EQ(pfPtr->GetFullFileName(), moduleInfo.pathname);
659         status = true;
660     }
661     ASSERT_TRUE(status);
662     Sampler::Destroy(sp);
663 }
664 
665 // Checking that sampler collect panda files correctly
TEST_F(SamplerTest,WriteModuleEventTest)666 TEST_F(SamplerTest, WriteModuleEventTest)
667 {
668     const char *streamTestFilename = "collect_panda_file_test.aspt";
669     auto *sp = Sampler::Create();
670     ASSERT_NE(sp, nullptr);
671     ASSERT_EQ(sp->Start(streamTestFilename), true);
672 
673     auto execPath = ark::os::file::File::GetExecutablePath();
674     std::string pandafile =
675         execPath.Value() + Separator() + ".." + Separator() + "pandastdlib" + Separator() + "arkstdlib.abc";
676 
677     auto pf = panda_file::OpenPandaFileOrZip(pandafile);
678     Runtime::GetCurrent()->GetClassLinker()->AddPandaFile(std::move(pf));
679     // NOTE:
680     // It's necessary to add assert that only one module is loaded
681     // But simply add assert on loaded size is UB, because such assert may fail if the WriteLoadedPandaFiles
682     // managed to dump the loaded module into the trace before the assert call occurs in this test
683 
684     sp->Stop();
685 
686     FileInfo moduleInfo;
687     SampleReader reader(streamTestFilename);
688     bool status = false;
689     while (reader.GetNextModule(&moduleInfo)) {
690         auto pfPtr = reinterpret_cast<panda_file::File *>(moduleInfo.ptr);
691         ASSERT_EQ(pfPtr->GetFullFileName(), moduleInfo.pathname);
692         status = true;
693     }
694     ASSERT_TRUE(status);
695 
696     Sampler::Destroy(sp);
697 }
698 
699 // Sampling big pandasm program and convert it
TEST_F(SamplerTest,ProfilerSamplerSignalHandlerTest)700 TEST_F(SamplerTest, ProfilerSamplerSignalHandlerTest)
701 {
702     const char *streamTestFilename = "sampler_signal_handler_test.aspt";
703     const char *resultTestFilename = "sampler_signal_handler_test.csv";
704     size_t sampleCounter = 0;
705 
706     {
707         auto *sp = Sampler::Create();
708         ASSERT_NE(sp, nullptr);
709         ASSERT_EQ(sp->Start(streamTestFilename), true);
710 
711         {
712             ASSERT_TRUE(Runtime::GetCurrent()->Execute("_GLOBAL::main", {}));
713         }
714         sp->Stop();
715 
716         SampleInfo sample;
717         SampleReader reader(streamTestFilename);
718         bool isFind = false;
719 
720         while (reader.GetNextSample(&sample)) {
721             ++sampleCounter;
722             if (sample.stackInfo.managedStackSize == 2U) {
723                 isFind = true;
724                 continue;
725             }
726             ASSERT_NE(sample.stackInfo.managedStackSize, 0);
727             ASSERT_EQ(GetThreadId(), sample.threadInfo.threadId);
728         }
729 
730         ASSERT_EQ(isFind, true);
731 
732         Sampler::Destroy(sp);
733     }
734 
735     // Checking converter
736     {
737         AsptConverter conv(streamTestFilename);
738         ASSERT_EQ(conv.CollectTracesStats(), sampleCounter);
739         ASSERT_TRUE(conv.CollectModules());
740         ASSERT_TRUE(conv.DumpResolvedTracesAsCSV(resultTestFilename));
741     }
742 }
743 
744 }  // namespace ark::tooling::sampler::test
745