12f083884Ss.makeev_local // The MIT License (MIT)
22f083884Ss.makeev_local //
32f083884Ss.makeev_local // Copyright (c) 2015 Sergey Makeev, Vadim Slyusarev
42f083884Ss.makeev_local //
52f083884Ss.makeev_local // Permission is hereby granted, free of charge, to any person obtaining a copy
62f083884Ss.makeev_local // of this software and associated documentation files (the "Software"), to deal
72f083884Ss.makeev_local // in the Software without restriction, including without limitation the rights
82f083884Ss.makeev_local // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
92f083884Ss.makeev_local // copies of the Software, and to permit persons to whom the Software is
102f083884Ss.makeev_local // furnished to do so, subject to the following conditions:
112f083884Ss.makeev_local //
122f083884Ss.makeev_local // The above copyright notice and this permission notice shall be included in
132f083884Ss.makeev_local // all copies or substantial portions of the Software.
142f083884Ss.makeev_local //
152f083884Ss.makeev_local // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
162f083884Ss.makeev_local // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
172f083884Ss.makeev_local // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
182f083884Ss.makeev_local // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
192f083884Ss.makeev_local // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
202f083884Ss.makeev_local // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
212f083884Ss.makeev_local // THE SOFTWARE.
222f083884Ss.makeev_local
232f083884Ss.makeev_local #include "Tests.h"
24*01616bcfSs.makeev_local #include "../Profiler/Profiler.h"
252f083884Ss.makeev_local #include <UnitTest++.h>
262f083884Ss.makeev_local #include <MTScheduler.h>
272f083884Ss.makeev_local
SUITE(PlatformTests)282f083884Ss.makeev_local SUITE(PlatformTests)
292f083884Ss.makeev_local {
302f083884Ss.makeev_local static const intptr_t DATA_VALUE = 13;
312f083884Ss.makeev_local
322f083884Ss.makeev_local intptr_t g_Variable = 0;
332f083884Ss.makeev_local
342f083884Ss.makeev_local void MyThreadFunc(void* userData)
352f083884Ss.makeev_local {
362f083884Ss.makeev_local intptr_t data = (intptr_t)userData;
372f083884Ss.makeev_local
382f083884Ss.makeev_local CHECK(data == DATA_VALUE);
392f083884Ss.makeev_local
402f083884Ss.makeev_local g_Variable = data;
412f083884Ss.makeev_local }
422f083884Ss.makeev_local
432f083884Ss.makeev_local TEST(ThreadTest)
442f083884Ss.makeev_local {
452f083884Ss.makeev_local intptr_t data = DATA_VALUE;
462f083884Ss.makeev_local
472f083884Ss.makeev_local MT::Thread thread;
482f083884Ss.makeev_local thread.Start(32768, MyThreadFunc, (void*)data);
492f083884Ss.makeev_local thread.Join();
502f083884Ss.makeev_local
512f083884Ss.makeev_local CHECK(g_Variable == DATA_VALUE);
522f083884Ss.makeev_local }
532f083884Ss.makeev_local ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
542f083884Ss.makeev_local
552f083884Ss.makeev_local MT::Event *pEvent1 = nullptr;
562f083884Ss.makeev_local MT::Event *pEvent2 = nullptr;
572f083884Ss.makeev_local
582f083884Ss.makeev_local void MyThreadFunc2(void*)
592f083884Ss.makeev_local {
603cb1fd8eSs.makeev_local MT::SpinSleepMilliSeconds(300);
612f083884Ss.makeev_local pEvent1->Signal();
622f083884Ss.makeev_local }
632f083884Ss.makeev_local
642f083884Ss.makeev_local TEST(EventTest)
652f083884Ss.makeev_local {
662f083884Ss.makeev_local MT::Event event1;
672f083884Ss.makeev_local event1.Create(MT::EventReset::MANUAL, false);
682f083884Ss.makeev_local pEvent1 = &event1;
692f083884Ss.makeev_local
702f083884Ss.makeev_local MT::Event event2;
712f083884Ss.makeev_local event2.Create(MT::EventReset::AUTOMATIC, false);
722f083884Ss.makeev_local pEvent2 = &event2;
732f083884Ss.makeev_local
742f083884Ss.makeev_local MT::Thread thread;
752f083884Ss.makeev_local thread.Start(32768, MyThreadFunc2, nullptr);
762f083884Ss.makeev_local
772f083884Ss.makeev_local bool res0 = event1.Wait(100);
782f083884Ss.makeev_local bool res1 = event1.Wait(1000);
792f083884Ss.makeev_local bool res2 = event1.Wait(1000);
802f083884Ss.makeev_local event1.Reset();
812f083884Ss.makeev_local bool res3 = event1.Wait(100);
822f083884Ss.makeev_local
832f083884Ss.makeev_local CHECK(!res0);
842f083884Ss.makeev_local CHECK(res1);
852f083884Ss.makeev_local CHECK(res2);
862f083884Ss.makeev_local CHECK(!res3);
872f083884Ss.makeev_local
882f083884Ss.makeev_local bool res4 = event2.Wait(100);
892f083884Ss.makeev_local CHECK(!res4);
902f083884Ss.makeev_local bool res5 = event2.Wait(100);
912f083884Ss.makeev_local CHECK(!res5);
922f083884Ss.makeev_local bool res6 = event2.Wait(100);
932f083884Ss.makeev_local CHECK(!res6);
942f083884Ss.makeev_local
952f083884Ss.makeev_local thread.Join();
962f083884Ss.makeev_local }
972f083884Ss.makeev_local
982f083884Ss.makeev_local
992f083884Ss.makeev_local
1002f083884Ss.makeev_local MT::AtomicPtrBase<MT::Event> pStressEvent = { nullptr };
1012f083884Ss.makeev_local MT::Atomic32Base<uint32> needExitSignal = { 0 };
1022f083884Ss.makeev_local MT::Atomic32Base<uint32> needExitWait = { 0 };
103*01616bcfSs.makeev_local MT::Atomic32Base<uint32> needStartWork = { 0 };
1042f083884Ss.makeev_local
1052f083884Ss.makeev_local void EventStressTestSignalThreadFunc(void*)
106*01616bcfSs.makeev_local { BROFILER_THREAD("SignalThread");
107*01616bcfSs.makeev_local
108*01616bcfSs.makeev_local while (needStartWork.Load() == 0)
109*01616bcfSs.makeev_local { BROFILER_CATEGORY("Signal prepare", 0xFFFF00FF);
110*01616bcfSs.makeev_local MT::SpinSleepMicroSeconds(300);
111*01616bcfSs.makeev_local }
112*01616bcfSs.makeev_local
1132f083884Ss.makeev_local while (needExitSignal.Load() == 0)
114*01616bcfSs.makeev_local { BROFILER_CATEGORY("Signal Loop", 0xFF556B2F);
115*01616bcfSs.makeev_local MT::SpinSleepMicroSeconds(300);
1162f083884Ss.makeev_local MT::Event * pEvent = pStressEvent.Load();
1172f083884Ss.makeev_local pEvent->Signal();
1182f083884Ss.makeev_local }
1192f083884Ss.makeev_local }
1202f083884Ss.makeev_local
1212f083884Ss.makeev_local void EventStressTestWaitThreadFunc(void*)
122*01616bcfSs.makeev_local { BROFILER_THREAD("WaitThread");
123*01616bcfSs.makeev_local
124*01616bcfSs.makeev_local while (needStartWork.Load() == 0)
125*01616bcfSs.makeev_local { BROFILER_CATEGORY("Wait prepare", 0xFFFF00FF);
126*01616bcfSs.makeev_local MT::SpinSleepMicroSeconds(300);
127*01616bcfSs.makeev_local }
128*01616bcfSs.makeev_local
1292f083884Ss.makeev_local while (needExitWait.Load() == 0)
130*01616bcfSs.makeev_local { BROFILER_CATEGORY("Wait Loop", 0xFFF0F8FF);
1312f083884Ss.makeev_local MT::Event* pEvent = pStressEvent.Load();
132ea599e92Ss.makeev_local bool res = pEvent->Wait(1000);
133*01616bcfSs.makeev_local MT::SpinSleepMicroSeconds(300);
1342f083884Ss.makeev_local CHECK(res == true);
1352f083884Ss.makeev_local }
1362f083884Ss.makeev_local }
1372f083884Ss.makeev_local
1382f083884Ss.makeev_local
1392f083884Ss.makeev_local
1402f083884Ss.makeev_local
141*01616bcfSs.makeev_local
1422f083884Ss.makeev_local TEST(EventStressTest)
1432f083884Ss.makeev_local {
144*01616bcfSs.makeev_local #if defined(MT_ENABLE_LEGACY_WINDOWSXP_SUPPORT) && defined(MT_PLATFORM_WINDOWS)
145*01616bcfSs.makeev_local printf("Kernel mode events\n");
146*01616bcfSs.makeev_local #else
147*01616bcfSs.makeev_local printf("User mode events\n");
148*01616bcfSs.makeev_local #endif
149*01616bcfSs.makeev_local
150*01616bcfSs.makeev_local
1512f083884Ss.makeev_local MT::Event stressEvent;
152*01616bcfSs.makeev_local MT::Thread signalThreads[3];
153*01616bcfSs.makeev_local MT::Thread waitThreads[3];
154*01616bcfSs.makeev_local needStartWork.Store(0);
155*01616bcfSs.makeev_local
156*01616bcfSs.makeev_local {
157*01616bcfSs.makeev_local BROFILER_NEXT_FRAME();
1582f083884Ss.makeev_local stressEvent.Create(MT::EventReset::AUTOMATIC, false);
1592f083884Ss.makeev_local pStressEvent.Store( &stressEvent );
1602f083884Ss.makeev_local
1612f083884Ss.makeev_local needExitSignal.Store(0);
1622f083884Ss.makeev_local needExitWait.Store(0);
1632f083884Ss.makeev_local
1642f083884Ss.makeev_local for(uint32 i = 0; i < MT_ARRAY_SIZE(signalThreads); i++)
1652f083884Ss.makeev_local {
1662f083884Ss.makeev_local signalThreads[i].Start(32768, EventStressTestSignalThreadFunc, nullptr);
1672f083884Ss.makeev_local }
1682f083884Ss.makeev_local
1692f083884Ss.makeev_local for(uint32 i = 0; i < MT_ARRAY_SIZE(waitThreads); i++)
1702f083884Ss.makeev_local {
1712f083884Ss.makeev_local waitThreads[i].Start(32768, EventStressTestWaitThreadFunc, nullptr);
1722f083884Ss.makeev_local }
1732f083884Ss.makeev_local
174*01616bcfSs.makeev_local printf("Signal threads num = %d\n", (uint32)MT_ARRAY_SIZE(signalThreads));
175*01616bcfSs.makeev_local printf("Wait threads num = %d\n", (uint32)MT_ARRAY_SIZE(waitThreads));
176*01616bcfSs.makeev_local }
1772f083884Ss.makeev_local
1782f083884Ss.makeev_local
179*01616bcfSs.makeev_local #if defined(MT_INSTRUMENTED_BUILD) && defined(MT_ENABLE_BROFILER_SUPPORT)
180*01616bcfSs.makeev_local BROFILER_FRAME("EventStressTest");
181*01616bcfSs.makeev_local {
182*01616bcfSs.makeev_local printf("Waiting for 'Brofiler' connection.\n");
183*01616bcfSs.makeev_local for(;;)
184*01616bcfSs.makeev_local {
185*01616bcfSs.makeev_local BROFILER_NEXT_FRAME();
186*01616bcfSs.makeev_local MT::Thread::Sleep(150);
187*01616bcfSs.makeev_local if (Brofiler::IsActive())
188*01616bcfSs.makeev_local {
189*01616bcfSs.makeev_local break;
190*01616bcfSs.makeev_local }
191*01616bcfSs.makeev_local }
192*01616bcfSs.makeev_local }
193*01616bcfSs.makeev_local #endif
194*01616bcfSs.makeev_local needStartWork.Store(1);
1952f083884Ss.makeev_local
1962f083884Ss.makeev_local const int iterationsCount = 5000;
197*01616bcfSs.makeev_local
198*01616bcfSs.makeev_local int64 startTimeSignal = MT::GetTimeMicroSeconds();
199*01616bcfSs.makeev_local { BROFILER_NEXT_FRAME();
200*01616bcfSs.makeev_local BROFILER_CATEGORY("Signal Loop", 0xFF556B2F);
201*01616bcfSs.makeev_local for(int i = 0; i < iterationsCount; i++)
202*01616bcfSs.makeev_local {
203*01616bcfSs.makeev_local stressEvent.Signal();
204*01616bcfSs.makeev_local }
205*01616bcfSs.makeev_local }
206*01616bcfSs.makeev_local int64 endTimeSignal = MT::GetTimeMicroSeconds();
207*01616bcfSs.makeev_local
208*01616bcfSs.makeev_local
209*01616bcfSs.makeev_local int64 startTimeWait = MT::GetTimeMicroSeconds();
210*01616bcfSs.makeev_local { BROFILER_NEXT_FRAME();
211*01616bcfSs.makeev_local BROFILER_CATEGORY("Wait Loop", 0xFFF0F8FF);
2122f083884Ss.makeev_local for(int i = 0; i < iterationsCount; i++)
2132f083884Ss.makeev_local {
214ea599e92Ss.makeev_local bool res = stressEvent.Wait(1000);
2152f083884Ss.makeev_local CHECK(res == true);
2162f083884Ss.makeev_local }
217*01616bcfSs.makeev_local }
218*01616bcfSs.makeev_local int64 endTimeWait = MT::GetTimeMicroSeconds();
2192f083884Ss.makeev_local
220*01616bcfSs.makeev_local double microSecondsPerWait = (double)((endTimeWait - startTimeWait) / (double)iterationsCount);
221*01616bcfSs.makeev_local double microSecondsPerSignal = (double)((endTimeSignal - startTimeSignal) / (double)iterationsCount);
2222f083884Ss.makeev_local
223*01616bcfSs.makeev_local printf("microseconds per signal = %3.2f, iterations = %d\n", microSecondsPerSignal, iterationsCount);
224*01616bcfSs.makeev_local printf("microseconds per wait = %3.2f, iterations = %d\n", microSecondsPerWait, iterationsCount);
2252f083884Ss.makeev_local
226*01616bcfSs.makeev_local #if defined(MT_INSTRUMENTED_BUILD) && defined(MT_ENABLE_BROFILER_SUPPORT)
227*01616bcfSs.makeev_local {
228*01616bcfSs.makeev_local printf("Waiting for the 'Brofiler' to be disconnected\n");
229*01616bcfSs.makeev_local for(;;)
230*01616bcfSs.makeev_local {
231*01616bcfSs.makeev_local BROFILER_NEXT_FRAME();
232*01616bcfSs.makeev_local MT::Thread::Sleep(150);
233*01616bcfSs.makeev_local if (!Brofiler::IsActive())
234*01616bcfSs.makeev_local {
235*01616bcfSs.makeev_local break;
236*01616bcfSs.makeev_local }
237*01616bcfSs.makeev_local }
238*01616bcfSs.makeev_local }
239*01616bcfSs.makeev_local
240*01616bcfSs.makeev_local printf("Done\n");
241*01616bcfSs.makeev_local #endif
2422f083884Ss.makeev_local
2432f083884Ss.makeev_local needExitWait.Store(1);
2442f083884Ss.makeev_local for(uint32 i = 0; i < MT_ARRAY_SIZE(waitThreads); i++)
2452f083884Ss.makeev_local {
2462f083884Ss.makeev_local waitThreads[i].Join();
2472f083884Ss.makeev_local }
2482f083884Ss.makeev_local
2492f083884Ss.makeev_local MT::Thread::Sleep(100);
2502f083884Ss.makeev_local
2512f083884Ss.makeev_local needExitSignal.Store(1);
2522f083884Ss.makeev_local for(uint32 i = 0; i < MT_ARRAY_SIZE(signalThreads); i++)
2532f083884Ss.makeev_local {
2542f083884Ss.makeev_local signalThreads[i].Join();
2552f083884Ss.makeev_local }
2562f083884Ss.makeev_local
2572f083884Ss.makeev_local bool res = stressEvent.Wait(300);
2582f083884Ss.makeev_local CHECK(res == true);
2592f083884Ss.makeev_local
2602f083884Ss.makeev_local res = stressEvent.Wait(300);
2612f083884Ss.makeev_local CHECK(res == false);
2622f083884Ss.makeev_local
2632f083884Ss.makeev_local }
2642f083884Ss.makeev_local
2652f083884Ss.makeev_local
2662f083884Ss.makeev_local TEST(SleepTest)
2672f083884Ss.makeev_local {
2682f083884Ss.makeev_local
2692f083884Ss.makeev_local MT::Timer timer;
2702f083884Ss.makeev_local
2713cb1fd8eSs.makeev_local MT::SpinSleepMilliSeconds(100);
2722f083884Ss.makeev_local
2732f083884Ss.makeev_local CHECK( timer.GetPastMilliSeconds() >= 100 );
2742f083884Ss.makeev_local }
2752f083884Ss.makeev_local ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2762f083884Ss.makeev_local }
277