1 // This file is part of Eigen, a lightweight C++ template library 2 // for linear algebra. 3 // 4 // Copyright (C) 2016 Dmitry Vyukov <dvyukov@google.com> 5 // Copyright (C) 2016 Benoit Steiner <benoit.steiner.goog@gmail.com> 6 // 7 // This Source Code Form is subject to the terms of the Mozilla 8 // Public License v. 2.0. If a copy of the MPL was not distributed 9 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 10 11 #define EIGEN_USE_THREADS 12 #include "main.h" 13 #include "Eigen/CXX11/ThreadPool" 14 15 static void test_create_destroy_empty_pool() 16 { 17 // Just create and destroy the pool. This will wind up and tear down worker 18 // threads. Ensure there are no issues in that logic. 19 for (int i = 0; i < 16; ++i) { 20 NonBlockingThreadPool tp(i); 21 } 22 } 23 24 25 static void test_parallelism() 26 { 27 // Test we never-ever fail to match available tasks with idle threads. 28 const int kThreads = 16; // code below expects that this is a multiple of 4 29 NonBlockingThreadPool tp(kThreads); 30 VERIFY_IS_EQUAL(tp.NumThreads(), kThreads); 31 VERIFY_IS_EQUAL(tp.CurrentThreadId(), -1); 32 for (int iter = 0; iter < 100; ++iter) { 33 std::atomic<int> running(0); 34 std::atomic<int> done(0); 35 std::atomic<int> phase(0); 36 // Schedule kThreads tasks and ensure that they all are running. 37 for (int i = 0; i < kThreads; ++i) { 38 tp.Schedule([&]() { 39 const int thread_id = tp.CurrentThreadId(); 40 VERIFY_GE(thread_id, 0); 41 VERIFY_LE(thread_id, kThreads - 1); 42 running++; 43 while (phase < 1) { 44 } 45 done++; 46 }); 47 } 48 while (running != kThreads) { 49 } 50 running = 0; 51 phase = 1; 52 // Now, while the previous tasks exit, schedule another kThreads tasks and 53 // ensure that they are running. 54 for (int i = 0; i < kThreads; ++i) { 55 tp.Schedule([&, i]() { 56 running++; 57 while (phase < 2) { 58 } 59 // When all tasks are running, half of tasks exit, quarter of tasks 60 // continue running and quarter of tasks schedule another 2 tasks each. 61 // Concurrently main thread schedules another quarter of tasks. 62 // This gives us another kThreads tasks and we ensure that they all 63 // are running. 64 if (i < kThreads / 2) { 65 } else if (i < 3 * kThreads / 4) { 66 running++; 67 while (phase < 3) { 68 } 69 done++; 70 } else { 71 for (int j = 0; j < 2; ++j) { 72 tp.Schedule([&]() { 73 running++; 74 while (phase < 3) { 75 } 76 done++; 77 }); 78 } 79 } 80 done++; 81 }); 82 } 83 while (running != kThreads) { 84 } 85 running = 0; 86 phase = 2; 87 for (int i = 0; i < kThreads / 4; ++i) { 88 tp.Schedule([&]() { 89 running++; 90 while (phase < 3) { 91 } 92 done++; 93 }); 94 } 95 while (running != kThreads) { 96 } 97 phase = 3; 98 while (done != 3 * kThreads) { 99 } 100 } 101 } 102 103 void test_cxx11_non_blocking_thread_pool() 104 { 105 CALL_SUBTEST(test_create_destroy_empty_pool()); 106 CALL_SUBTEST(test_parallelism()); 107 } 108