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"
242f083884Ss.makeev_local #include <UnitTest++.h>
252f083884Ss.makeev_local #include <MTScheduler.h>
262f083884Ss.makeev_local 
27f7a9bfc3Ss.makeev_local #include "../Profiler/Profiler.h"
28f7a9bfc3Ss.makeev_local 
292f083884Ss.makeev_local 
302f083884Ss.makeev_local #ifdef MT_THREAD_SANITIZER
312f083884Ss.makeev_local 	#define MT_DEFAULT_WAIT_TIME (500000)
322f083884Ss.makeev_local 	#define MT_SUBTASK_QUEUE_DEEP (3)
332f083884Ss.makeev_local 	#define MT_ITERATIONS_COUNT (10)
342f083884Ss.makeev_local #else
352f083884Ss.makeev_local 	#define MT_DEFAULT_WAIT_TIME (5000)
362f083884Ss.makeev_local 	#define MT_SUBTASK_QUEUE_DEEP (12)
372f083884Ss.makeev_local 	#define MT_ITERATIONS_COUNT (100000)
382f083884Ss.makeev_local #endif
392f083884Ss.makeev_local 
SUITE(SubtasksTests)402f083884Ss.makeev_local SUITE(SubtasksTests)
412f083884Ss.makeev_local {
422f083884Ss.makeev_local ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
432f083884Ss.makeev_local template<size_t N>
442f083884Ss.makeev_local struct DeepSubtaskQueue
452f083884Ss.makeev_local {
46b23bdf5aSs.makeev_local 	MT_DECLARE_TASK(DeepSubtaskQueue<N>, MT::StackRequirements::STANDARD, MT::TaskPriority::NORMAL, MT::Color::Blue);
472f083884Ss.makeev_local 
482f083884Ss.makeev_local 	int result;
492f083884Ss.makeev_local 
502f083884Ss.makeev_local 	DeepSubtaskQueue() : result(0) {}
512f083884Ss.makeev_local 
522f083884Ss.makeev_local 	void Do(MT::FiberContext& context)
532f083884Ss.makeev_local 	{
542f083884Ss.makeev_local 		DeepSubtaskQueue<N - 1> taskNm1;
552f083884Ss.makeev_local 		DeepSubtaskQueue<N - 2> taskNm2;
562f083884Ss.makeev_local 
572f083884Ss.makeev_local 		context.RunSubtasksAndYield(MT::TaskGroup::Default(), &taskNm1, 1);
582f083884Ss.makeev_local 		context.RunSubtasksAndYield(MT::TaskGroup::Default(), &taskNm2, 1);
592f083884Ss.makeev_local 
602f083884Ss.makeev_local 		result = taskNm2.result + taskNm1.result;
612f083884Ss.makeev_local 	}
622f083884Ss.makeev_local };
632f083884Ss.makeev_local 
642f083884Ss.makeev_local template<>
652f083884Ss.makeev_local struct DeepSubtaskQueue<0>
662f083884Ss.makeev_local {
67b23bdf5aSs.makeev_local 	MT_DECLARE_TASK(DeepSubtaskQueue<0>, MT::StackRequirements::STANDARD, MT::TaskPriority::NORMAL, MT::Color::Blue);
682f083884Ss.makeev_local 
692f083884Ss.makeev_local 	int result;
702f083884Ss.makeev_local 	void Do(MT::FiberContext&)
712f083884Ss.makeev_local 	{
722f083884Ss.makeev_local 		result = 0;
732f083884Ss.makeev_local 	}
742f083884Ss.makeev_local };
752f083884Ss.makeev_local 
762f083884Ss.makeev_local 
772f083884Ss.makeev_local template<>
782f083884Ss.makeev_local struct DeepSubtaskQueue<1>
792f083884Ss.makeev_local {
80b23bdf5aSs.makeev_local 	MT_DECLARE_TASK(DeepSubtaskQueue<1>, MT::StackRequirements::STANDARD, MT::TaskPriority::NORMAL, MT::Color::Blue);
812f083884Ss.makeev_local 
822f083884Ss.makeev_local 	int result;
832f083884Ss.makeev_local 	void Do(MT::FiberContext&)
842f083884Ss.makeev_local 	{
852f083884Ss.makeev_local 		result = 1;
862f083884Ss.makeev_local 	}
872f083884Ss.makeev_local };
882f083884Ss.makeev_local 
892f083884Ss.makeev_local 
902f083884Ss.makeev_local //
912f083884Ss.makeev_local TEST(DeepSubtaskQueue)
922f083884Ss.makeev_local {
932f083884Ss.makeev_local 	MT::TaskScheduler scheduler;
942f083884Ss.makeev_local 
952f083884Ss.makeev_local 	DeepSubtaskQueue<MT_SUBTASK_QUEUE_DEEP> task;
962f083884Ss.makeev_local 	scheduler.RunAsync(MT::TaskGroup::Default(), &task, 1);
972f083884Ss.makeev_local 
982f083884Ss.makeev_local 	CHECK(scheduler.WaitAll(MT_DEFAULT_WAIT_TIME));
992f083884Ss.makeev_local 	CHECK_EQUAL(task.result, 144);
1002f083884Ss.makeev_local }
1012f083884Ss.makeev_local ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1022f083884Ss.makeev_local 
1032f083884Ss.makeev_local ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1042f083884Ss.makeev_local static MT::TaskGroup sourceGroup;
1052f083884Ss.makeev_local static MT::TaskGroup resultGroup;
1062f083884Ss.makeev_local ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1072f083884Ss.makeev_local struct GroupSubtask
1082f083884Ss.makeev_local {
109b23bdf5aSs.makeev_local 	MT_DECLARE_TASK(GroupSubtask, MT::StackRequirements::STANDARD, MT::TaskPriority::NORMAL, MT::Color::Blue);
1102f083884Ss.makeev_local 
1112f083884Ss.makeev_local 	void Do(MT::FiberContext& context)
1122f083884Ss.makeev_local 	{
1132f083884Ss.makeev_local 		resultGroup = context.currentGroup;
1142f083884Ss.makeev_local 	}
1152f083884Ss.makeev_local };
1162f083884Ss.makeev_local 
1172f083884Ss.makeev_local struct GroupTask
1182f083884Ss.makeev_local {
119b23bdf5aSs.makeev_local 	MT_DECLARE_TASK(GroupTask, MT::StackRequirements::STANDARD, MT::TaskPriority::NORMAL, MT::Color::Blue);
1202f083884Ss.makeev_local 
1212f083884Ss.makeev_local 	void Do(MT::FiberContext& context)
1222f083884Ss.makeev_local 	{
1232f083884Ss.makeev_local 		GroupSubtask task;
1242f083884Ss.makeev_local 		context.RunSubtasksAndYield(sourceGroup, &task, 1);
1252f083884Ss.makeev_local 	}
1262f083884Ss.makeev_local };
1272f083884Ss.makeev_local 
1282f083884Ss.makeev_local struct TaskWithManySubtasks
1292f083884Ss.makeev_local {
130b23bdf5aSs.makeev_local 	MT_DECLARE_TASK(TaskWithManySubtasks, MT::StackRequirements::STANDARD, MT::TaskPriority::NORMAL, MT::Color::Blue);
1312f083884Ss.makeev_local 
1322f083884Ss.makeev_local 	void Do(MT::FiberContext& context)
1332f083884Ss.makeev_local 	{
1342f083884Ss.makeev_local 		GroupTask task;
1352f083884Ss.makeev_local 		for (int i = 0; i < 2; ++i)
1362f083884Ss.makeev_local 		{
1372f083884Ss.makeev_local 			context.RunSubtasksAndYield(MT::TaskGroup::Default(), &task, 1);
138*3cb1fd8eSs.makeev_local 			MT::SpinSleepMilliSeconds(1);
1392f083884Ss.makeev_local 		}
1402f083884Ss.makeev_local 	}
1412f083884Ss.makeev_local 
1422f083884Ss.makeev_local };
1432f083884Ss.makeev_local 
1442f083884Ss.makeev_local //
1452f083884Ss.makeev_local TEST(SubtaskGroup)
1462f083884Ss.makeev_local {
1472f083884Ss.makeev_local 	MT::TaskScheduler scheduler;
1482f083884Ss.makeev_local 
1492f083884Ss.makeev_local 	sourceGroup = scheduler.CreateGroup();
1502f083884Ss.makeev_local 
1512f083884Ss.makeev_local 	GroupTask task;
1522f083884Ss.makeev_local 	scheduler.RunAsync(sourceGroup, &task, 1);
1532f083884Ss.makeev_local 
1542f083884Ss.makeev_local 	CHECK(scheduler.WaitAll(MT_DEFAULT_WAIT_TIME));
1552f083884Ss.makeev_local 
1562f083884Ss.makeev_local 	CHECK_EQUAL(sourceGroup.GetValidIndex(), resultGroup.GetValidIndex());
1572f083884Ss.makeev_local }
1582f083884Ss.makeev_local 
1592f083884Ss.makeev_local // Checks task with multiple subtasks
1602f083884Ss.makeev_local TEST(OneTaskManySubtasks)
1612f083884Ss.makeev_local {
1622f083884Ss.makeev_local 	MT::TaskScheduler scheduler;
1632f083884Ss.makeev_local 
1642f083884Ss.makeev_local 	sourceGroup = scheduler.CreateGroup();
1652f083884Ss.makeev_local 
1662f083884Ss.makeev_local 	TaskWithManySubtasks task;
1672f083884Ss.makeev_local 	scheduler.RunAsync(MT::TaskGroup::Default(), &task, 1);
1682f083884Ss.makeev_local 	CHECK(scheduler.WaitAll(MT_DEFAULT_WAIT_TIME));
1692f083884Ss.makeev_local }
1702f083884Ss.makeev_local 
1712f083884Ss.makeev_local // Checks many simple task with subtasks
1722f083884Ss.makeev_local TEST(ManyTasksOneSubtask)
1732f083884Ss.makeev_local {
174f7a9bfc3Ss.makeev_local #ifdef MT_INSTRUMENTED_BUILD
175*3cb1fd8eSs.makeev_local 	MT::TaskScheduler scheduler(0, nullptr, GetProfiler());
176f7a9bfc3Ss.makeev_local #else
177f7a9bfc3Ss.makeev_local 	MT::TaskScheduler scheduler;
178*3cb1fd8eSs.makeev_local #endif
1792f083884Ss.makeev_local 
1802f083884Ss.makeev_local 	bool waitAllOK = true;
1812f083884Ss.makeev_local 
1822f083884Ss.makeev_local 	sourceGroup = scheduler.CreateGroup();
1832f083884Ss.makeev_local 
1842f083884Ss.makeev_local 	for (int i = 0; i < MT_ITERATIONS_COUNT; ++i)
1852f083884Ss.makeev_local 	{
1862f083884Ss.makeev_local 		GroupTask group;
1872f083884Ss.makeev_local 		scheduler.RunAsync(sourceGroup, &group, 1);
1882f083884Ss.makeev_local 		//if (!scheduler.WaitAll(MT_DEFAULT_WAIT_TIME))
1892f083884Ss.makeev_local 		if (!scheduler.WaitGroup(sourceGroup, MT_DEFAULT_WAIT_TIME))
1902f083884Ss.makeev_local 		{
1912f083884Ss.makeev_local 			printf("Timeout: Failed iteration %d\n", i);
1922f083884Ss.makeev_local 			waitAllOK = false;
1932f083884Ss.makeev_local 			break;
1942f083884Ss.makeev_local 		}
1952f083884Ss.makeev_local 	}
1962f083884Ss.makeev_local 
197f7a9bfc3Ss.makeev_local 
1982f083884Ss.makeev_local 	CHECK(waitAllOK);
1992f083884Ss.makeev_local }
2002f083884Ss.makeev_local ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2012f083884Ss.makeev_local 
2022f083884Ss.makeev_local 
2032f083884Ss.makeev_local ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2042f083884Ss.makeev_local 
2052f083884Ss.makeev_local struct TaskSubtaskCombo_Sum1
2062f083884Ss.makeev_local {
207b23bdf5aSs.makeev_local 	MT_DECLARE_TASK(TaskSubtaskCombo_Sum1, MT::StackRequirements::STANDARD, MT::TaskPriority::NORMAL, MT::Color::Blue);
2082f083884Ss.makeev_local 
2092f083884Ss.makeev_local 	MT::Atomic32<int32>* data;
2102f083884Ss.makeev_local 
2112f083884Ss.makeev_local 	void Do(MT::FiberContext&)
2122f083884Ss.makeev_local 	{
2132f083884Ss.makeev_local 		data->IncFetch();
2142f083884Ss.makeev_local 	}
2152f083884Ss.makeev_local };
2162f083884Ss.makeev_local 
2172f083884Ss.makeev_local struct TaskSubtaskCombo_Sum4
2182f083884Ss.makeev_local {
219b23bdf5aSs.makeev_local 	MT_DECLARE_TASK(TaskSubtaskCombo_Sum4, MT::StackRequirements::STANDARD, MT::TaskPriority::NORMAL, MT::Color::Blue);
2202f083884Ss.makeev_local 
2212f083884Ss.makeev_local 	MT::Atomic32<int32>* data;
2222f083884Ss.makeev_local 
2232f083884Ss.makeev_local 	TaskSubtaskCombo_Sum1 tasks[2];
2242f083884Ss.makeev_local 
2252f083884Ss.makeev_local 	void Do(MT::FiberContext& context)
2262f083884Ss.makeev_local 	{
2272f083884Ss.makeev_local 		tasks[0].data = data;
2282f083884Ss.makeev_local 		tasks[1].data = data;
2292f083884Ss.makeev_local 
2302f083884Ss.makeev_local 		context.RunAsync(MT::TaskGroup::Default(), &tasks[0], MT_ARRAY_SIZE(tasks));
2312f083884Ss.makeev_local 		context.RunSubtasksAndYield(MT::TaskGroup::Default(), &tasks[0], MT_ARRAY_SIZE(tasks));
2322f083884Ss.makeev_local 	}
2332f083884Ss.makeev_local };
2342f083884Ss.makeev_local 
2352f083884Ss.makeev_local struct TaskSubtaskCombo_Sum16
2362f083884Ss.makeev_local {
237b23bdf5aSs.makeev_local 	MT_DECLARE_TASK(TaskSubtaskCombo_Sum16, MT::StackRequirements::STANDARD, MT::TaskPriority::NORMAL, MT::Color::Blue);
2382f083884Ss.makeev_local 
2392f083884Ss.makeev_local 	MT::Atomic32<int32>* data;
2402f083884Ss.makeev_local 
2412f083884Ss.makeev_local 	TaskSubtaskCombo_Sum4 tasks[2];
2422f083884Ss.makeev_local 
2432f083884Ss.makeev_local 	void Do(MT::FiberContext& context)
2442f083884Ss.makeev_local 	{
2452f083884Ss.makeev_local 		tasks[0].data = data;
2462f083884Ss.makeev_local 		tasks[1].data = data;
2472f083884Ss.makeev_local 
2482f083884Ss.makeev_local 		context.RunAsync(MT::TaskGroup::Default(), &tasks[0], MT_ARRAY_SIZE(tasks));
2492f083884Ss.makeev_local 		context.RunSubtasksAndYield(MT::TaskGroup::Default(), &tasks[0], MT_ARRAY_SIZE(tasks));
2502f083884Ss.makeev_local 	}
2512f083884Ss.makeev_local };
2522f083884Ss.makeev_local 
2532f083884Ss.makeev_local MT::Atomic32<int32> sum;
2542f083884Ss.makeev_local 
2552f083884Ss.makeev_local //
2562f083884Ss.makeev_local TEST(TaskSubtaskCombo)
2572f083884Ss.makeev_local {
2582f083884Ss.makeev_local 	sum.Store(0);
2592f083884Ss.makeev_local 
2602f083884Ss.makeev_local 	MT::TaskScheduler scheduler;
2612f083884Ss.makeev_local 
2622f083884Ss.makeev_local 	TaskSubtaskCombo_Sum16 task[16];
2632f083884Ss.makeev_local 	for (int i = 0; i < 16; ++i)
2642f083884Ss.makeev_local 	{
2652f083884Ss.makeev_local 		task[i].data = &sum;
2662f083884Ss.makeev_local 		scheduler.RunAsync(MT::TaskGroup::Default(), &task[i], 1);
2672f083884Ss.makeev_local 	}
2682f083884Ss.makeev_local 
2692f083884Ss.makeev_local 	CHECK(scheduler.WaitAll(MT_DEFAULT_WAIT_TIME));
2702f083884Ss.makeev_local 
2712f083884Ss.makeev_local 	CHECK_EQUAL(sum.Load(), 256);
2722f083884Ss.makeev_local }
2732f083884Ss.makeev_local ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2742f083884Ss.makeev_local }
275