1*2f083884Ss.makeev_local // The MIT License (MIT)
2*2f083884Ss.makeev_local //
3*2f083884Ss.makeev_local // 	Copyright (c) 2015 Sergey Makeev, Vadim Slyusarev
4*2f083884Ss.makeev_local //
5*2f083884Ss.makeev_local // 	Permission is hereby granted, free of charge, to any person obtaining a copy
6*2f083884Ss.makeev_local // 	of this software and associated documentation files (the "Software"), to deal
7*2f083884Ss.makeev_local // 	in the Software without restriction, including without limitation the rights
8*2f083884Ss.makeev_local // 	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9*2f083884Ss.makeev_local // 	copies of the Software, and to permit persons to whom the Software is
10*2f083884Ss.makeev_local // 	furnished to do so, subject to the following conditions:
11*2f083884Ss.makeev_local //
12*2f083884Ss.makeev_local //  The above copyright notice and this permission notice shall be included in
13*2f083884Ss.makeev_local // 	all copies or substantial portions of the Software.
14*2f083884Ss.makeev_local //
15*2f083884Ss.makeev_local // 	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16*2f083884Ss.makeev_local // 	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17*2f083884Ss.makeev_local // 	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18*2f083884Ss.makeev_local // 	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19*2f083884Ss.makeev_local // 	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20*2f083884Ss.makeev_local // 	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21*2f083884Ss.makeev_local // 	THE SOFTWARE.
22*2f083884Ss.makeev_local 
23*2f083884Ss.makeev_local #include "Tests.h"
24*2f083884Ss.makeev_local #include <UnitTest++.h>
25*2f083884Ss.makeev_local #include <MTScheduler.h>
26*2f083884Ss.makeev_local 
27*2f083884Ss.makeev_local 
28*2f083884Ss.makeev_local #ifdef MT_THREAD_SANITIZER
29*2f083884Ss.makeev_local 	#define MT_DEFAULT_WAIT_TIME (500000)
30*2f083884Ss.makeev_local 	#define MT_SUBTASK_QUEUE_DEEP (3)
31*2f083884Ss.makeev_local 	#define MT_ITERATIONS_COUNT (10)
32*2f083884Ss.makeev_local #else
33*2f083884Ss.makeev_local 	#define MT_DEFAULT_WAIT_TIME (5000)
34*2f083884Ss.makeev_local 	#define MT_SUBTASK_QUEUE_DEEP (12)
35*2f083884Ss.makeev_local 	#define MT_ITERATIONS_COUNT (100000)
36*2f083884Ss.makeev_local #endif
37*2f083884Ss.makeev_local 
38*2f083884Ss.makeev_local SUITE(SubtasksTests)
39*2f083884Ss.makeev_local {
40*2f083884Ss.makeev_local ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
41*2f083884Ss.makeev_local template<size_t N>
42*2f083884Ss.makeev_local struct DeepSubtaskQueue
43*2f083884Ss.makeev_local {
44*2f083884Ss.makeev_local 	MT_DECLARE_TASK(DeepSubtaskQueue<N>, MT::StackRequirements::STANDARD, MT::Color::Blue);
45*2f083884Ss.makeev_local 
46*2f083884Ss.makeev_local 	int result;
47*2f083884Ss.makeev_local 
48*2f083884Ss.makeev_local 	DeepSubtaskQueue() : result(0) {}
49*2f083884Ss.makeev_local 
50*2f083884Ss.makeev_local 	void Do(MT::FiberContext& context)
51*2f083884Ss.makeev_local 	{
52*2f083884Ss.makeev_local 		DeepSubtaskQueue<N - 1> taskNm1;
53*2f083884Ss.makeev_local 		DeepSubtaskQueue<N - 2> taskNm2;
54*2f083884Ss.makeev_local 
55*2f083884Ss.makeev_local 		context.RunSubtasksAndYield(MT::TaskGroup::Default(), &taskNm1, 1);
56*2f083884Ss.makeev_local 		context.RunSubtasksAndYield(MT::TaskGroup::Default(), &taskNm2, 1);
57*2f083884Ss.makeev_local 
58*2f083884Ss.makeev_local 		result = taskNm2.result + taskNm1.result;
59*2f083884Ss.makeev_local 	}
60*2f083884Ss.makeev_local };
61*2f083884Ss.makeev_local 
62*2f083884Ss.makeev_local template<>
63*2f083884Ss.makeev_local struct DeepSubtaskQueue<0>
64*2f083884Ss.makeev_local {
65*2f083884Ss.makeev_local 	MT_DECLARE_TASK(DeepSubtaskQueue<0>, MT::StackRequirements::STANDARD, MT::Color::Blue);
66*2f083884Ss.makeev_local 
67*2f083884Ss.makeev_local 	int result;
68*2f083884Ss.makeev_local 	void Do(MT::FiberContext&)
69*2f083884Ss.makeev_local 	{
70*2f083884Ss.makeev_local 		result = 0;
71*2f083884Ss.makeev_local 	}
72*2f083884Ss.makeev_local };
73*2f083884Ss.makeev_local 
74*2f083884Ss.makeev_local 
75*2f083884Ss.makeev_local template<>
76*2f083884Ss.makeev_local struct DeepSubtaskQueue<1>
77*2f083884Ss.makeev_local {
78*2f083884Ss.makeev_local 	MT_DECLARE_TASK(DeepSubtaskQueue<1>, MT::StackRequirements::STANDARD, MT::Color::Blue);
79*2f083884Ss.makeev_local 
80*2f083884Ss.makeev_local 	int result;
81*2f083884Ss.makeev_local 	void Do(MT::FiberContext&)
82*2f083884Ss.makeev_local 	{
83*2f083884Ss.makeev_local 		result = 1;
84*2f083884Ss.makeev_local 	}
85*2f083884Ss.makeev_local };
86*2f083884Ss.makeev_local 
87*2f083884Ss.makeev_local 
88*2f083884Ss.makeev_local //
89*2f083884Ss.makeev_local TEST(DeepSubtaskQueue)
90*2f083884Ss.makeev_local {
91*2f083884Ss.makeev_local 	MT::TaskScheduler scheduler;
92*2f083884Ss.makeev_local 
93*2f083884Ss.makeev_local 	DeepSubtaskQueue<MT_SUBTASK_QUEUE_DEEP> task;
94*2f083884Ss.makeev_local 	scheduler.RunAsync(MT::TaskGroup::Default(), &task, 1);
95*2f083884Ss.makeev_local 
96*2f083884Ss.makeev_local 	CHECK(scheduler.WaitAll(MT_DEFAULT_WAIT_TIME));
97*2f083884Ss.makeev_local 	CHECK_EQUAL(task.result, 144);
98*2f083884Ss.makeev_local }
99*2f083884Ss.makeev_local ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
100*2f083884Ss.makeev_local 
101*2f083884Ss.makeev_local ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
102*2f083884Ss.makeev_local static MT::TaskGroup sourceGroup;
103*2f083884Ss.makeev_local static MT::TaskGroup resultGroup;
104*2f083884Ss.makeev_local ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
105*2f083884Ss.makeev_local struct GroupSubtask
106*2f083884Ss.makeev_local {
107*2f083884Ss.makeev_local 	MT_DECLARE_TASK(GroupSubtask, MT::StackRequirements::STANDARD, MT::Color::Blue);
108*2f083884Ss.makeev_local 
109*2f083884Ss.makeev_local 	void Do(MT::FiberContext& context)
110*2f083884Ss.makeev_local 	{
111*2f083884Ss.makeev_local 		resultGroup = context.currentGroup;
112*2f083884Ss.makeev_local 	}
113*2f083884Ss.makeev_local };
114*2f083884Ss.makeev_local 
115*2f083884Ss.makeev_local struct GroupTask
116*2f083884Ss.makeev_local {
117*2f083884Ss.makeev_local 	MT_DECLARE_TASK(GroupTask, MT::StackRequirements::STANDARD, MT::Color::Blue);
118*2f083884Ss.makeev_local 
119*2f083884Ss.makeev_local 	void Do(MT::FiberContext& context)
120*2f083884Ss.makeev_local 	{
121*2f083884Ss.makeev_local 		GroupSubtask task;
122*2f083884Ss.makeev_local 		context.RunSubtasksAndYield(sourceGroup, &task, 1);
123*2f083884Ss.makeev_local 	}
124*2f083884Ss.makeev_local };
125*2f083884Ss.makeev_local 
126*2f083884Ss.makeev_local struct TaskWithManySubtasks
127*2f083884Ss.makeev_local {
128*2f083884Ss.makeev_local 	MT_DECLARE_TASK(TaskWithManySubtasks, MT::StackRequirements::STANDARD, MT::Color::Blue);
129*2f083884Ss.makeev_local 
130*2f083884Ss.makeev_local 	void Do(MT::FiberContext& context)
131*2f083884Ss.makeev_local 	{
132*2f083884Ss.makeev_local 		GroupTask task;
133*2f083884Ss.makeev_local 		for (int i = 0; i < 2; ++i)
134*2f083884Ss.makeev_local 		{
135*2f083884Ss.makeev_local 			context.RunSubtasksAndYield(MT::TaskGroup::Default(), &task, 1);
136*2f083884Ss.makeev_local 			MT::Thread::SpinSleepMilliSeconds(1);
137*2f083884Ss.makeev_local 		}
138*2f083884Ss.makeev_local 	}
139*2f083884Ss.makeev_local 
140*2f083884Ss.makeev_local };
141*2f083884Ss.makeev_local 
142*2f083884Ss.makeev_local //
143*2f083884Ss.makeev_local TEST(SubtaskGroup)
144*2f083884Ss.makeev_local {
145*2f083884Ss.makeev_local 	MT::TaskScheduler scheduler;
146*2f083884Ss.makeev_local 
147*2f083884Ss.makeev_local 	sourceGroup = scheduler.CreateGroup();
148*2f083884Ss.makeev_local 
149*2f083884Ss.makeev_local 	GroupTask task;
150*2f083884Ss.makeev_local 	scheduler.RunAsync(sourceGroup, &task, 1);
151*2f083884Ss.makeev_local 
152*2f083884Ss.makeev_local 	CHECK(scheduler.WaitAll(MT_DEFAULT_WAIT_TIME));
153*2f083884Ss.makeev_local 
154*2f083884Ss.makeev_local 	CHECK_EQUAL(sourceGroup.GetValidIndex(), resultGroup.GetValidIndex());
155*2f083884Ss.makeev_local }
156*2f083884Ss.makeev_local 
157*2f083884Ss.makeev_local // Checks task with multiple subtasks
158*2f083884Ss.makeev_local TEST(OneTaskManySubtasks)
159*2f083884Ss.makeev_local {
160*2f083884Ss.makeev_local 	MT::TaskScheduler scheduler;
161*2f083884Ss.makeev_local 
162*2f083884Ss.makeev_local 	sourceGroup = scheduler.CreateGroup();
163*2f083884Ss.makeev_local 
164*2f083884Ss.makeev_local 	TaskWithManySubtasks task;
165*2f083884Ss.makeev_local 	scheduler.RunAsync(MT::TaskGroup::Default(), &task, 1);
166*2f083884Ss.makeev_local 	CHECK(scheduler.WaitAll(MT_DEFAULT_WAIT_TIME));
167*2f083884Ss.makeev_local }
168*2f083884Ss.makeev_local 
169*2f083884Ss.makeev_local // Checks many simple task with subtasks
170*2f083884Ss.makeev_local TEST(ManyTasksOneSubtask)
171*2f083884Ss.makeev_local {
172*2f083884Ss.makeev_local 	MT::TaskScheduler scheduler;
173*2f083884Ss.makeev_local 
174*2f083884Ss.makeev_local 	bool waitAllOK = true;
175*2f083884Ss.makeev_local 
176*2f083884Ss.makeev_local 	sourceGroup = scheduler.CreateGroup();
177*2f083884Ss.makeev_local 
178*2f083884Ss.makeev_local 	for (int i = 0; i < MT_ITERATIONS_COUNT; ++i)
179*2f083884Ss.makeev_local 	{
180*2f083884Ss.makeev_local 		GroupTask group;
181*2f083884Ss.makeev_local 		scheduler.RunAsync(sourceGroup, &group, 1);
182*2f083884Ss.makeev_local 		//if (!scheduler.WaitAll(MT_DEFAULT_WAIT_TIME))
183*2f083884Ss.makeev_local 		if (!scheduler.WaitGroup(sourceGroup, MT_DEFAULT_WAIT_TIME))
184*2f083884Ss.makeev_local 		{
185*2f083884Ss.makeev_local 			printf("Timeout: Failed iteration %d\n", i);
186*2f083884Ss.makeev_local 			waitAllOK = false;
187*2f083884Ss.makeev_local 			break;
188*2f083884Ss.makeev_local 		}
189*2f083884Ss.makeev_local 	}
190*2f083884Ss.makeev_local 
191*2f083884Ss.makeev_local 	CHECK(waitAllOK);
192*2f083884Ss.makeev_local }
193*2f083884Ss.makeev_local ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
194*2f083884Ss.makeev_local 
195*2f083884Ss.makeev_local 
196*2f083884Ss.makeev_local ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
197*2f083884Ss.makeev_local 
198*2f083884Ss.makeev_local struct TaskSubtaskCombo_Sum1
199*2f083884Ss.makeev_local {
200*2f083884Ss.makeev_local 	MT_DECLARE_TASK(TaskSubtaskCombo_Sum1, MT::StackRequirements::STANDARD, MT::Color::Blue);
201*2f083884Ss.makeev_local 
202*2f083884Ss.makeev_local 	MT::Atomic32<int32>* data;
203*2f083884Ss.makeev_local 
204*2f083884Ss.makeev_local 	void Do(MT::FiberContext&)
205*2f083884Ss.makeev_local 	{
206*2f083884Ss.makeev_local 		data->IncFetch();
207*2f083884Ss.makeev_local 	}
208*2f083884Ss.makeev_local };
209*2f083884Ss.makeev_local 
210*2f083884Ss.makeev_local struct TaskSubtaskCombo_Sum4
211*2f083884Ss.makeev_local {
212*2f083884Ss.makeev_local 	MT_DECLARE_TASK(TaskSubtaskCombo_Sum4, MT::StackRequirements::STANDARD, MT::Color::Blue);
213*2f083884Ss.makeev_local 
214*2f083884Ss.makeev_local 	MT::Atomic32<int32>* data;
215*2f083884Ss.makeev_local 
216*2f083884Ss.makeev_local 	TaskSubtaskCombo_Sum1 tasks[2];
217*2f083884Ss.makeev_local 
218*2f083884Ss.makeev_local 	void Do(MT::FiberContext& context)
219*2f083884Ss.makeev_local 	{
220*2f083884Ss.makeev_local 		tasks[0].data = data;
221*2f083884Ss.makeev_local 		tasks[1].data = data;
222*2f083884Ss.makeev_local 
223*2f083884Ss.makeev_local 		context.RunAsync(MT::TaskGroup::Default(), &tasks[0], MT_ARRAY_SIZE(tasks));
224*2f083884Ss.makeev_local 		context.RunSubtasksAndYield(MT::TaskGroup::Default(), &tasks[0], MT_ARRAY_SIZE(tasks));
225*2f083884Ss.makeev_local 	}
226*2f083884Ss.makeev_local };
227*2f083884Ss.makeev_local 
228*2f083884Ss.makeev_local struct TaskSubtaskCombo_Sum16
229*2f083884Ss.makeev_local {
230*2f083884Ss.makeev_local 	MT_DECLARE_TASK(TaskSubtaskCombo_Sum16, MT::StackRequirements::STANDARD, MT::Color::Blue);
231*2f083884Ss.makeev_local 
232*2f083884Ss.makeev_local 	MT::Atomic32<int32>* data;
233*2f083884Ss.makeev_local 
234*2f083884Ss.makeev_local 	TaskSubtaskCombo_Sum4 tasks[2];
235*2f083884Ss.makeev_local 
236*2f083884Ss.makeev_local 	void Do(MT::FiberContext& context)
237*2f083884Ss.makeev_local 	{
238*2f083884Ss.makeev_local 		tasks[0].data = data;
239*2f083884Ss.makeev_local 		tasks[1].data = data;
240*2f083884Ss.makeev_local 
241*2f083884Ss.makeev_local 		context.RunAsync(MT::TaskGroup::Default(), &tasks[0], MT_ARRAY_SIZE(tasks));
242*2f083884Ss.makeev_local 		context.RunSubtasksAndYield(MT::TaskGroup::Default(), &tasks[0], MT_ARRAY_SIZE(tasks));
243*2f083884Ss.makeev_local 	}
244*2f083884Ss.makeev_local };
245*2f083884Ss.makeev_local 
246*2f083884Ss.makeev_local MT::Atomic32<int32> sum;
247*2f083884Ss.makeev_local 
248*2f083884Ss.makeev_local //
249*2f083884Ss.makeev_local TEST(TaskSubtaskCombo)
250*2f083884Ss.makeev_local {
251*2f083884Ss.makeev_local 	sum.Store(0);
252*2f083884Ss.makeev_local 
253*2f083884Ss.makeev_local 	MT::TaskScheduler scheduler;
254*2f083884Ss.makeev_local 
255*2f083884Ss.makeev_local 	TaskSubtaskCombo_Sum16 task[16];
256*2f083884Ss.makeev_local 	for (int i = 0; i < 16; ++i)
257*2f083884Ss.makeev_local 	{
258*2f083884Ss.makeev_local 		task[i].data = &sum;
259*2f083884Ss.makeev_local 		scheduler.RunAsync(MT::TaskGroup::Default(), &task[i], 1);
260*2f083884Ss.makeev_local 	}
261*2f083884Ss.makeev_local 
262*2f083884Ss.makeev_local 	CHECK(scheduler.WaitAll(MT_DEFAULT_WAIT_TIME));
263*2f083884Ss.makeev_local 
264*2f083884Ss.makeev_local 	CHECK_EQUAL(sum.Load(), 256);
265*2f083884Ss.makeev_local }
266*2f083884Ss.makeev_local ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
267*2f083884Ss.makeev_local }
268