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 29*2f083884Ss.makeev_local SUITE(FireAndForget) 30*2f083884Ss.makeev_local { 31*2f083884Ss.makeev_local 32*2f083884Ss.makeev_local struct SimpleTask; 33*2f083884Ss.makeev_local 34*2f083884Ss.makeev_local typedef MT::TaskPool<SimpleTask, 512> TestPoolType; 35*2f083884Ss.makeev_local 36*2f083884Ss.makeev_local struct SimpleTask 37*2f083884Ss.makeev_local { 38*2f083884Ss.makeev_local MT_DECLARE_TASK(SimpleTask, MT::StackRequirements::STANDARD, MT::Color::Blue); 39*2f083884Ss.makeev_local 40*2f083884Ss.makeev_local MT::Atomic32<int32>* doCounter; 41*2f083884Ss.makeev_local MT::Atomic32<int32>* dtorCounter; 42*2f083884Ss.makeev_local TestPoolType* taskPool; 43*2f083884Ss.makeev_local 44*2f083884Ss.makeev_local SimpleTask() 45*2f083884Ss.makeev_local : doCounter(nullptr) 46*2f083884Ss.makeev_local , dtorCounter(nullptr) 47*2f083884Ss.makeev_local , taskPool(nullptr) 48*2f083884Ss.makeev_local { 49*2f083884Ss.makeev_local } 50*2f083884Ss.makeev_local 51*2f083884Ss.makeev_local SimpleTask(MT::Atomic32<int32>* _doCounter, MT::Atomic32<int32>* _dtorCounter, TestPoolType * _taskPool) 52*2f083884Ss.makeev_local : doCounter(_doCounter) 53*2f083884Ss.makeev_local , dtorCounter(_dtorCounter) 54*2f083884Ss.makeev_local , taskPool(_taskPool) 55*2f083884Ss.makeev_local { 56*2f083884Ss.makeev_local } 57*2f083884Ss.makeev_local 58*2f083884Ss.makeev_local SimpleTask(SimpleTask&& other) 59*2f083884Ss.makeev_local : doCounter(other.doCounter) 60*2f083884Ss.makeev_local , dtorCounter(other.dtorCounter) 61*2f083884Ss.makeev_local , taskPool(other.taskPool) 62*2f083884Ss.makeev_local { 63*2f083884Ss.makeev_local other.doCounter = nullptr; 64*2f083884Ss.makeev_local other.dtorCounter = nullptr; 65*2f083884Ss.makeev_local other.taskPool = nullptr; 66*2f083884Ss.makeev_local } 67*2f083884Ss.makeev_local 68*2f083884Ss.makeev_local ~SimpleTask() 69*2f083884Ss.makeev_local { 70*2f083884Ss.makeev_local if (dtorCounter) 71*2f083884Ss.makeev_local { 72*2f083884Ss.makeev_local dtorCounter->IncFetch(); 73*2f083884Ss.makeev_local } 74*2f083884Ss.makeev_local } 75*2f083884Ss.makeev_local 76*2f083884Ss.makeev_local void Do(MT::FiberContext& context) 77*2f083884Ss.makeev_local { 78*2f083884Ss.makeev_local if (doCounter) 79*2f083884Ss.makeev_local { 80*2f083884Ss.makeev_local doCounter->IncFetch(); 81*2f083884Ss.makeev_local } 82*2f083884Ss.makeev_local 83*2f083884Ss.makeev_local if (taskPool) 84*2f083884Ss.makeev_local { 85*2f083884Ss.makeev_local MT::TaskHandle handle = taskPool->Alloc(SimpleTask(doCounter, dtorCounter, nullptr)); 86*2f083884Ss.makeev_local 87*2f083884Ss.makeev_local context.RunSubtasksAndYield(MT::TaskGroup::Default(), &handle, 1); 88*2f083884Ss.makeev_local } 89*2f083884Ss.makeev_local } 90*2f083884Ss.makeev_local }; 91*2f083884Ss.makeev_local 92*2f083884Ss.makeev_local 93*2f083884Ss.makeev_local 94*2f083884Ss.makeev_local TEST(SingleThreadPoolTest) 95*2f083884Ss.makeev_local { 96*2f083884Ss.makeev_local MT::TaskPool<SimpleTask, 4> taskPool; 97*2f083884Ss.makeev_local 98*2f083884Ss.makeev_local MT::TaskHandle taskHandle0 = taskPool.Alloc(SimpleTask()); 99*2f083884Ss.makeev_local CHECK_EQUAL(true, taskHandle0.IsValid()); 100*2f083884Ss.makeev_local 101*2f083884Ss.makeev_local MT::TaskHandle taskHandle1 = taskPool.Alloc(SimpleTask()); 102*2f083884Ss.makeev_local CHECK_EQUAL(true, taskHandle1.IsValid()); 103*2f083884Ss.makeev_local 104*2f083884Ss.makeev_local MT::TaskHandle taskHandle2 = taskPool.Alloc(SimpleTask()); 105*2f083884Ss.makeev_local CHECK_EQUAL(true, taskHandle2.IsValid()); 106*2f083884Ss.makeev_local 107*2f083884Ss.makeev_local MT::TaskHandle taskHandle3 = taskPool.Alloc(SimpleTask()); 108*2f083884Ss.makeev_local CHECK_EQUAL(true, taskHandle3.IsValid()); 109*2f083884Ss.makeev_local 110*2f083884Ss.makeev_local CHECK_EQUAL(true, taskHandle0.IsValid()); 111*2f083884Ss.makeev_local CHECK_EQUAL(true, taskHandle1.IsValid()); 112*2f083884Ss.makeev_local CHECK_EQUAL(true, taskHandle2.IsValid()); 113*2f083884Ss.makeev_local CHECK_EQUAL(true, taskHandle3.IsValid()); 114*2f083884Ss.makeev_local 115*2f083884Ss.makeev_local 116*2f083884Ss.makeev_local // check for allocation fail 117*2f083884Ss.makeev_local MT::TaskHandle taskHandle4 = taskPool.TryAlloc(SimpleTask()); 118*2f083884Ss.makeev_local CHECK_EQUAL(false, taskHandle4.IsValid()); 119*2f083884Ss.makeev_local 120*2f083884Ss.makeev_local 121*2f083884Ss.makeev_local // check state 122*2f083884Ss.makeev_local CHECK_EQUAL(true, taskHandle0.IsValid()); 123*2f083884Ss.makeev_local CHECK_EQUAL(true, taskHandle1.IsValid()); 124*2f083884Ss.makeev_local CHECK_EQUAL(true, taskHandle2.IsValid()); 125*2f083884Ss.makeev_local CHECK_EQUAL(true, taskHandle3.IsValid()); 126*2f083884Ss.makeev_local CHECK_EQUAL(false, taskHandle4.IsValid()); 127*2f083884Ss.makeev_local 128*2f083884Ss.makeev_local // destroy pool task by handle 129*2f083884Ss.makeev_local CHECK_EQUAL(true, MT::PoolElementHeader::DestoryByHandle(taskHandle0)); 130*2f083884Ss.makeev_local CHECK_EQUAL(true, MT::PoolElementHeader::DestoryByHandle(taskHandle1)); 131*2f083884Ss.makeev_local CHECK_EQUAL(true, MT::PoolElementHeader::DestoryByHandle(taskHandle2)); 132*2f083884Ss.makeev_local CHECK_EQUAL(true, MT::PoolElementHeader::DestoryByHandle(taskHandle3)); 133*2f083884Ss.makeev_local CHECK_EQUAL(false, MT::PoolElementHeader::DestoryByHandle(taskHandle4)); 134*2f083884Ss.makeev_local 135*2f083884Ss.makeev_local // check for double destroy 136*2f083884Ss.makeev_local CHECK_EQUAL(false, MT::PoolElementHeader::DestoryByHandle(taskHandle0)); 137*2f083884Ss.makeev_local CHECK_EQUAL(false, MT::PoolElementHeader::DestoryByHandle(taskHandle3)); 138*2f083884Ss.makeev_local 139*2f083884Ss.makeev_local MT::TaskHandle taskHandle5 = taskPool.Alloc(SimpleTask()); 140*2f083884Ss.makeev_local 141*2f083884Ss.makeev_local CHECK_EQUAL(false, taskHandle0.IsValid()); 142*2f083884Ss.makeev_local CHECK_EQUAL(false, taskHandle1.IsValid()); 143*2f083884Ss.makeev_local CHECK_EQUAL(false, taskHandle2.IsValid()); 144*2f083884Ss.makeev_local CHECK_EQUAL(false, taskHandle3.IsValid()); 145*2f083884Ss.makeev_local CHECK_EQUAL(false, taskHandle4.IsValid()); 146*2f083884Ss.makeev_local CHECK_EQUAL(true, taskHandle5.IsValid()); 147*2f083884Ss.makeev_local } 148*2f083884Ss.makeev_local 149*2f083884Ss.makeev_local 150*2f083884Ss.makeev_local struct ThreadTest 151*2f083884Ss.makeev_local { 152*2f083884Ss.makeev_local MT_DECLARE_TASK(ThreadTest, MT::StackRequirements::STANDARD, MT::Color::Blue); 153*2f083884Ss.makeev_local 154*2f083884Ss.makeev_local TestPoolType * taskPool; 155*2f083884Ss.makeev_local 156*2f083884Ss.makeev_local void Do(MT::FiberContext&) 157*2f083884Ss.makeev_local { 158*2f083884Ss.makeev_local for (int i = 0; i < 20000; i++) 159*2f083884Ss.makeev_local { 160*2f083884Ss.makeev_local MT::TaskHandle handle = taskPool->TryAlloc(SimpleTask()); 161*2f083884Ss.makeev_local if (handle.IsValid()) 162*2f083884Ss.makeev_local { 163*2f083884Ss.makeev_local CHECK_EQUAL(true, MT::PoolElementHeader::DestoryByHandle(handle)); 164*2f083884Ss.makeev_local } else 165*2f083884Ss.makeev_local { 166*2f083884Ss.makeev_local CHECK_EQUAL(false, MT::PoolElementHeader::DestoryByHandle(handle)); 167*2f083884Ss.makeev_local } 168*2f083884Ss.makeev_local } 169*2f083884Ss.makeev_local } 170*2f083884Ss.makeev_local }; 171*2f083884Ss.makeev_local 172*2f083884Ss.makeev_local 173*2f083884Ss.makeev_local TEST(MultiThreadPoolTest) 174*2f083884Ss.makeev_local { 175*2f083884Ss.makeev_local TestPoolType taskPool; 176*2f083884Ss.makeev_local 177*2f083884Ss.makeev_local MT::TaskScheduler scheduler; 178*2f083884Ss.makeev_local 179*2f083884Ss.makeev_local ThreadTest tasks[8]; 180*2f083884Ss.makeev_local for (size_t i = 0; i < MT_ARRAY_SIZE(tasks); ++i) 181*2f083884Ss.makeev_local { 182*2f083884Ss.makeev_local tasks[i].taskPool = &taskPool; 183*2f083884Ss.makeev_local } 184*2f083884Ss.makeev_local 185*2f083884Ss.makeev_local scheduler.RunAsync(MT::TaskGroup::Default(), &tasks[0], MT_ARRAY_SIZE(tasks)); 186*2f083884Ss.makeev_local 187*2f083884Ss.makeev_local int timeout = 20000; 188*2f083884Ss.makeev_local CHECK(scheduler.WaitGroup(MT::TaskGroup::Default(), timeout)); 189*2f083884Ss.makeev_local } 190*2f083884Ss.makeev_local 191*2f083884Ss.makeev_local 192*2f083884Ss.makeev_local // 193*2f083884Ss.makeev_local TEST(FireAndForgetSimple) 194*2f083884Ss.makeev_local { 195*2f083884Ss.makeev_local MT::Atomic32<int32> doCounter(0); 196*2f083884Ss.makeev_local MT::Atomic32<int32> dtorCounter(0); 197*2f083884Ss.makeev_local 198*2f083884Ss.makeev_local MT::TaskScheduler scheduler; 199*2f083884Ss.makeev_local TestPoolType taskPool; 200*2f083884Ss.makeev_local 201*2f083884Ss.makeev_local for(int pass = 0; pass < 4; pass++) 202*2f083884Ss.makeev_local { 203*2f083884Ss.makeev_local printf("--- step %d ---\n", pass); 204*2f083884Ss.makeev_local 205*2f083884Ss.makeev_local doCounter.Store(0); 206*2f083884Ss.makeev_local dtorCounter.Store(0); 207*2f083884Ss.makeev_local 208*2f083884Ss.makeev_local MT::TaskHandle taskHandles[250]; 209*2f083884Ss.makeev_local for (size_t i = 0; i < MT_ARRAY_SIZE(taskHandles); ++i) 210*2f083884Ss.makeev_local { 211*2f083884Ss.makeev_local taskHandles[i] = taskPool.Alloc(SimpleTask(&doCounter, &dtorCounter, &taskPool)); 212*2f083884Ss.makeev_local CHECK_EQUAL(true, taskHandles[i].IsValid()); 213*2f083884Ss.makeev_local } 214*2f083884Ss.makeev_local 215*2f083884Ss.makeev_local scheduler.RunAsync(MT::TaskGroup::Default(), &taskHandles[0], MT_ARRAY_SIZE(taskHandles)); 216*2f083884Ss.makeev_local 217*2f083884Ss.makeev_local int timeout = 20000; 218*2f083884Ss.makeev_local CHECK(scheduler.WaitAll(timeout)); 219*2f083884Ss.makeev_local 220*2f083884Ss.makeev_local CHECK_EQUAL(MT_ARRAY_SIZE(taskHandles) * 2, (size_t)doCounter.Load()); 221*2f083884Ss.makeev_local CHECK_EQUAL(MT_ARRAY_SIZE(taskHandles) * 2, (size_t)dtorCounter.Load()); 222*2f083884Ss.makeev_local } 223*2f083884Ss.makeev_local 224*2f083884Ss.makeev_local } 225*2f083884Ss.makeev_local 226*2f083884Ss.makeev_local //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 227*2f083884Ss.makeev_local } 228