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