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 = ∑
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