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