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 <UnitTest++.h>
25 #include <MTScheduler.h>
26 
27 #include "../Profiler/Profiler.h"
28 
29 
30 #ifdef MT_THREAD_SANITIZER
31 	#define MT_DEFAULT_WAIT_TIME (500000)
32 	#define MT_SUBTASK_QUEUE_DEEP (3)
33 	#define MT_ITERATIONS_COUNT (10)
34 #else
35 	#define MT_DEFAULT_WAIT_TIME (5000)
36 	#define MT_SUBTASK_QUEUE_DEEP (12)
37 	#define MT_ITERATIONS_COUNT (100000)
38 #endif
39 
SUITE(SubtasksTests)40 SUITE(SubtasksTests)
41 {
42 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
43 template<size_t N>
44 struct DeepSubtaskQueue
45 {
46 	MT_DECLARE_TASK(DeepSubtaskQueue<N>, MT::StackRequirements::STANDARD, MT::TaskPriority::NORMAL, MT::Color::Blue);
47 
48 	int result;
49 
50 	DeepSubtaskQueue() : result(0) {}
51 
52 	void Do(MT::FiberContext& context)
53 	{
54 		DeepSubtaskQueue<N - 1> taskNm1;
55 		DeepSubtaskQueue<N - 2> taskNm2;
56 
57 		context.RunSubtasksAndYield(MT::TaskGroup::Default(), &taskNm1, 1);
58 		context.RunSubtasksAndYield(MT::TaskGroup::Default(), &taskNm2, 1);
59 
60 		result = taskNm2.result + taskNm1.result;
61 	}
62 };
63 
64 template<>
65 struct DeepSubtaskQueue<0>
66 {
67 	MT_DECLARE_TASK(DeepSubtaskQueue<0>, MT::StackRequirements::STANDARD, MT::TaskPriority::NORMAL, MT::Color::Blue);
68 
69 	int result;
70 	void Do(MT::FiberContext&)
71 	{
72 		result = 0;
73 	}
74 };
75 
76 
77 template<>
78 struct DeepSubtaskQueue<1>
79 {
80 	MT_DECLARE_TASK(DeepSubtaskQueue<1>, MT::StackRequirements::STANDARD, MT::TaskPriority::NORMAL, MT::Color::Blue);
81 
82 	int result;
83 	void Do(MT::FiberContext&)
84 	{
85 		result = 1;
86 	}
87 };
88 
89 
90 //
91 TEST(DeepSubtaskQueue)
92 {
93 	MT::TaskScheduler scheduler;
94 
95 	DeepSubtaskQueue<MT_SUBTASK_QUEUE_DEEP> task;
96 	scheduler.RunAsync(MT::TaskGroup::Default(), &task, 1);
97 
98 	CHECK(scheduler.WaitAll(MT_DEFAULT_WAIT_TIME));
99 	CHECK_EQUAL(task.result, 144);
100 }
101 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
102 
103 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
104 static MT::TaskGroup sourceGroup;
105 static MT::TaskGroup resultGroup;
106 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
107 struct GroupSubtask
108 {
109 	MT_DECLARE_TASK(GroupSubtask, MT::StackRequirements::STANDARD, MT::TaskPriority::NORMAL, MT::Color::Blue);
110 
111 	void Do(MT::FiberContext& context)
112 	{
113 		resultGroup = context.currentGroup;
114 	}
115 };
116 
117 struct GroupTask
118 {
119 	MT_DECLARE_TASK(GroupTask, MT::StackRequirements::STANDARD, MT::TaskPriority::NORMAL, MT::Color::Blue);
120 
121 	void Do(MT::FiberContext& context)
122 	{
123 		GroupSubtask task;
124 		context.RunSubtasksAndYield(sourceGroup, &task, 1);
125 	}
126 };
127 
128 struct TaskWithManySubtasks
129 {
130 	MT_DECLARE_TASK(TaskWithManySubtasks, MT::StackRequirements::STANDARD, MT::TaskPriority::NORMAL, MT::Color::Blue);
131 
132 	void Do(MT::FiberContext& context)
133 	{
134 		GroupTask task;
135 		for (int i = 0; i < 2; ++i)
136 		{
137 			context.RunSubtasksAndYield(MT::TaskGroup::Default(), &task, 1);
138 			MT::SpinSleepMilliSeconds(1);
139 		}
140 	}
141 
142 };
143 
144 //
145 TEST(SubtaskGroup)
146 {
147 	MT::TaskScheduler scheduler;
148 
149 	sourceGroup = scheduler.CreateGroup();
150 
151 	GroupTask task;
152 	scheduler.RunAsync(sourceGroup, &task, 1);
153 
154 	CHECK(scheduler.WaitAll(MT_DEFAULT_WAIT_TIME));
155 
156 	CHECK_EQUAL(sourceGroup.GetValidIndex(), resultGroup.GetValidIndex());
157 }
158 
159 // Checks task with multiple subtasks
160 TEST(OneTaskManySubtasks)
161 {
162 	MT::TaskScheduler scheduler;
163 
164 	sourceGroup = scheduler.CreateGroup();
165 
166 	TaskWithManySubtasks task;
167 	scheduler.RunAsync(MT::TaskGroup::Default(), &task, 1);
168 	CHECK(scheduler.WaitAll(MT_DEFAULT_WAIT_TIME));
169 }
170 
171 // Checks many simple task with subtasks
172 TEST(ManyTasksOneSubtask)
173 {
174 #ifdef MT_INSTRUMENTED_BUILD
175 	MT::TaskScheduler scheduler(0, nullptr, GetProfiler());
176 #else
177 	MT::TaskScheduler scheduler;
178 #endif
179 
180 	bool waitAllOK = true;
181 
182 	sourceGroup = scheduler.CreateGroup();
183 
184 	for (int i = 0; i < MT_ITERATIONS_COUNT; ++i)
185 	{
186 		GroupTask group;
187 		scheduler.RunAsync(sourceGroup, &group, 1);
188 		//if (!scheduler.WaitAll(MT_DEFAULT_WAIT_TIME))
189 		if (!scheduler.WaitGroup(sourceGroup, MT_DEFAULT_WAIT_TIME))
190 		{
191 			printf("Timeout: Failed iteration %d\n", i);
192 			waitAllOK = false;
193 			break;
194 		}
195 	}
196 
197 
198 	CHECK(waitAllOK);
199 }
200 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
201 
202 
203 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
204 
205 struct TaskSubtaskCombo_Sum1
206 {
207 	MT_DECLARE_TASK(TaskSubtaskCombo_Sum1, MT::StackRequirements::STANDARD, MT::TaskPriority::NORMAL, MT::Color::Blue);
208 
209 	MT::Atomic32<int32>* data;
210 
211 	void Do(MT::FiberContext&)
212 	{
213 		data->IncFetch();
214 	}
215 };
216 
217 struct TaskSubtaskCombo_Sum4
218 {
219 	MT_DECLARE_TASK(TaskSubtaskCombo_Sum4, MT::StackRequirements::STANDARD, MT::TaskPriority::NORMAL, MT::Color::Blue);
220 
221 	MT::Atomic32<int32>* data;
222 
223 	TaskSubtaskCombo_Sum1 tasks[2];
224 
225 	void Do(MT::FiberContext& context)
226 	{
227 		tasks[0].data = data;
228 		tasks[1].data = data;
229 
230 		context.RunAsync(MT::TaskGroup::Default(), &tasks[0], MT_ARRAY_SIZE(tasks));
231 		context.RunSubtasksAndYield(MT::TaskGroup::Default(), &tasks[0], MT_ARRAY_SIZE(tasks));
232 	}
233 };
234 
235 struct TaskSubtaskCombo_Sum16
236 {
237 	MT_DECLARE_TASK(TaskSubtaskCombo_Sum16, MT::StackRequirements::STANDARD, MT::TaskPriority::NORMAL, MT::Color::Blue);
238 
239 	MT::Atomic32<int32>* data;
240 
241 	TaskSubtaskCombo_Sum4 tasks[2];
242 
243 	void Do(MT::FiberContext& context)
244 	{
245 		tasks[0].data = data;
246 		tasks[1].data = data;
247 
248 		context.RunAsync(MT::TaskGroup::Default(), &tasks[0], MT_ARRAY_SIZE(tasks));
249 		context.RunSubtasksAndYield(MT::TaskGroup::Default(), &tasks[0], MT_ARRAY_SIZE(tasks));
250 	}
251 };
252 
253 MT::Atomic32<int32> sum;
254 
255 //
256 TEST(TaskSubtaskCombo)
257 {
258 	sum.Store(0);
259 
260 	MT::TaskScheduler scheduler;
261 
262 	TaskSubtaskCombo_Sum16 task[16];
263 	for (int i = 0; i < 16; ++i)
264 	{
265 		task[i].data = &sum;
266 		scheduler.RunAsync(MT::TaskGroup::Default(), &task[i], 1);
267 	}
268 
269 	CHECK(scheduler.WaitAll(MT_DEFAULT_WAIT_TIME));
270 
271 	CHECK_EQUAL(sum.Load(), 256);
272 }
273 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
274 }
275