1 // The MIT License (MIT)
2 //
3 // Copyright (c) 2015 Sergey Makeev, Vadim Slyusarev
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining a copy
6 // of this software and associated documentation files (the "Software"), to deal
7 // in the Software without restriction, including without limitation the rights
8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 // copies of the Software, and to permit persons to whom the Software is
10 // furnished to do so, subject to the following conditions:
11 //
12 // The above copyright notice and this permission notice shall be included in
13 // all copies or substantial portions of the Software.
14 //
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 // THE SOFTWARE.
22
23 #include "Tests.h"
24 #include "../Profiler/Profiler.h"
25 #include <UnitTest++.h>
26 #include <MTScheduler.h>
27
SUITE(PlatformTests)28 SUITE(PlatformTests)
29 {
30 static const intptr_t DATA_VALUE = 13;
31
32 intptr_t g_Variable = 0;
33
34 void MyThreadFunc(void* userData)
35 {
36 intptr_t data = (intptr_t)userData;
37
38 CHECK(data == DATA_VALUE);
39
40 g_Variable = data;
41 }
42
43 TEST(ThreadTest)
44 {
45 intptr_t data = DATA_VALUE;
46
47 MT::Thread thread;
48 thread.Start(32768, MyThreadFunc, (void*)data);
49 thread.Join();
50
51 CHECK(g_Variable == DATA_VALUE);
52 }
53 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
54
55 MT::Event *pEvent1 = nullptr;
56 MT::Event *pEvent2 = nullptr;
57
58 void MyThreadFunc2(void*)
59 {
60 MT::SpinSleepMilliSeconds(300);
61 pEvent1->Signal();
62 }
63
64 TEST(EventTest)
65 {
66 MT::Event event1;
67 event1.Create(MT::EventReset::MANUAL, false);
68 pEvent1 = &event1;
69
70 MT::Event event2;
71 event2.Create(MT::EventReset::AUTOMATIC, false);
72 pEvent2 = &event2;
73
74 MT::Thread thread;
75 thread.Start(32768, MyThreadFunc2, nullptr);
76
77 bool res0 = event1.Wait(100);
78 bool res1 = event1.Wait(1000);
79 bool res2 = event1.Wait(1000);
80 event1.Reset();
81 bool res3 = event1.Wait(100);
82
83 CHECK(!res0);
84 CHECK(res1);
85 CHECK(res2);
86 CHECK(!res3);
87
88 bool res4 = event2.Wait(100);
89 CHECK(!res4);
90 bool res5 = event2.Wait(100);
91 CHECK(!res5);
92 bool res6 = event2.Wait(100);
93 CHECK(!res6);
94
95 thread.Join();
96 }
97
98
99
100 MT::AtomicPtrBase<MT::Event> pStressEvent = { nullptr };
101 MT::Atomic32Base<uint32> needExitSignal = { 0 };
102 MT::Atomic32Base<uint32> needExitWait = { 0 };
103 MT::Atomic32Base<uint32> needStartWork = { 0 };
104
105 void EventStressTestSignalThreadFunc(void*)
106 { BROFILER_THREAD("SignalThread");
107
108 while (needStartWork.Load() == 0)
109 { BROFILER_CATEGORY("Signal prepare", 0xFFFF00FF);
110 MT::SpinSleepMicroSeconds(300);
111 }
112
113 while (needExitSignal.Load() == 0)
114 { BROFILER_CATEGORY("Signal Loop", 0xFF556B2F);
115 MT::SpinSleepMicroSeconds(300);
116 MT::Event * pEvent = pStressEvent.Load();
117 pEvent->Signal();
118 }
119 }
120
121 void EventStressTestWaitThreadFunc(void*)
122 { BROFILER_THREAD("WaitThread");
123
124 while (needStartWork.Load() == 0)
125 { BROFILER_CATEGORY("Wait prepare", 0xFFFF00FF);
126 MT::SpinSleepMicroSeconds(300);
127 }
128
129 while (needExitWait.Load() == 0)
130 { BROFILER_CATEGORY("Wait Loop", 0xFFF0F8FF);
131 MT::Event* pEvent = pStressEvent.Load();
132 bool res = pEvent->Wait(1000);
133 MT::SpinSleepMicroSeconds(300);
134 CHECK(res == true);
135 }
136 }
137
138
139
140
141
142 TEST(EventStressTest)
143 {
144 #if defined(MT_ENABLE_LEGACY_WINDOWSXP_SUPPORT) && defined(MT_PLATFORM_WINDOWS)
145 printf("Kernel mode events\n");
146 #else
147 printf("User mode events\n");
148 #endif
149
150
151 MT::Event stressEvent;
152 MT::Thread signalThreads[3];
153 MT::Thread waitThreads[3];
154 needStartWork.Store(0);
155
156 {
157 BROFILER_NEXT_FRAME();
158 stressEvent.Create(MT::EventReset::AUTOMATIC, false);
159 pStressEvent.Store( &stressEvent );
160
161 needExitSignal.Store(0);
162 needExitWait.Store(0);
163
164 for(uint32 i = 0; i < MT_ARRAY_SIZE(signalThreads); i++)
165 {
166 signalThreads[i].Start(32768, EventStressTestSignalThreadFunc, nullptr);
167 }
168
169 for(uint32 i = 0; i < MT_ARRAY_SIZE(waitThreads); i++)
170 {
171 waitThreads[i].Start(32768, EventStressTestWaitThreadFunc, nullptr);
172 }
173
174 printf("Signal threads num = %d\n", (uint32)MT_ARRAY_SIZE(signalThreads));
175 printf("Wait threads num = %d\n", (uint32)MT_ARRAY_SIZE(waitThreads));
176 }
177
178
179 #if defined(MT_INSTRUMENTED_BUILD) && defined(MT_ENABLE_BROFILER_SUPPORT)
180 BROFILER_FRAME("EventStressTest");
181 {
182 printf("Waiting for 'Brofiler' connection.\n");
183 for(;;)
184 {
185 BROFILER_NEXT_FRAME();
186 MT::Thread::Sleep(150);
187 if (Brofiler::IsActive())
188 {
189 break;
190 }
191 }
192 }
193 #endif
194 needStartWork.Store(1);
195
196 const int iterationsCount = 5000;
197
198 int64 startTimeSignal = MT::GetTimeMicroSeconds();
199 { BROFILER_NEXT_FRAME();
200 BROFILER_CATEGORY("Signal Loop", 0xFF556B2F);
201 for(int i = 0; i < iterationsCount; i++)
202 {
203 stressEvent.Signal();
204 }
205 }
206 int64 endTimeSignal = MT::GetTimeMicroSeconds();
207
208
209 int64 startTimeWait = MT::GetTimeMicroSeconds();
210 { BROFILER_NEXT_FRAME();
211 BROFILER_CATEGORY("Wait Loop", 0xFFF0F8FF);
212 for(int i = 0; i < iterationsCount; i++)
213 {
214 bool res = stressEvent.Wait(1000);
215 CHECK(res == true);
216 }
217 }
218 int64 endTimeWait = MT::GetTimeMicroSeconds();
219
220 double microSecondsPerWait = (double)((endTimeWait - startTimeWait) / (double)iterationsCount);
221 double microSecondsPerSignal = (double)((endTimeSignal - startTimeSignal) / (double)iterationsCount);
222
223 printf("microseconds per signal = %3.2f, iterations = %d\n", microSecondsPerSignal, iterationsCount);
224 printf("microseconds per wait = %3.2f, iterations = %d\n", microSecondsPerWait, iterationsCount);
225
226 #if defined(MT_INSTRUMENTED_BUILD) && defined(MT_ENABLE_BROFILER_SUPPORT)
227 {
228 printf("Waiting for the 'Brofiler' to be disconnected\n");
229 for(;;)
230 {
231 BROFILER_NEXT_FRAME();
232 MT::Thread::Sleep(150);
233 if (!Brofiler::IsActive())
234 {
235 break;
236 }
237 }
238 }
239
240 printf("Done\n");
241 #endif
242
243 needExitWait.Store(1);
244 for(uint32 i = 0; i < MT_ARRAY_SIZE(waitThreads); i++)
245 {
246 waitThreads[i].Join();
247 }
248
249 MT::Thread::Sleep(100);
250
251 needExitSignal.Store(1);
252 for(uint32 i = 0; i < MT_ARRAY_SIZE(signalThreads); i++)
253 {
254 signalThreads[i].Join();
255 }
256
257 bool res = stressEvent.Wait(300);
258 CHECK(res == true);
259
260 res = stressEvent.Wait(300);
261 CHECK(res == false);
262
263 }
264
265
266 TEST(SleepTest)
267 {
268
269 MT::Timer timer;
270
271 MT::SpinSleepMilliSeconds(100);
272
273 CHECK( timer.GetPastMilliSeconds() >= 100 );
274 }
275 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
276 }
277