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