Geant4 Cross Reference |
1 // 1 // 2 // MIT License 2 // MIT License 3 // Copyright (c) 2020 Jonathan R. Madsen 3 // Copyright (c) 2020 Jonathan R. Madsen 4 // Permission is hereby granted, free of charg 4 // Permission is hereby granted, free of charge, to any person obtaining a copy 5 // of this software and associated documentati 5 // of this software and associated documentation files (the "Software"), to deal 6 // in the Software without restriction, includ 6 // in the Software without restriction, including without limitation the rights 7 // to use, copy, modify, merge, publish, distr 7 // to use, copy, modify, merge, publish, distribute, sublicense, and 8 // copies of the Software, and to permit perso 8 // copies of the Software, and to permit persons to whom the Software is 9 // furnished to do so, subject to the followin 9 // furnished to do so, subject to the following conditions: 10 // The above copyright notice and this permiss 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the S 11 // all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED 12 // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPR 12 // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 13 // LIMITED TO THE WARRANTIES OF MERCHANTABILIT 13 // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 14 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SH 14 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 15 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 15 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 16 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARIS 16 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 17 // WITH THE SOFTWARE OR THE USE OR OTHER DEALI 17 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 // 18 // 19 // ------------------------------------------ 19 // --------------------------------------------------------------- 20 // Tasking class header 20 // Tasking class header 21 // Class Description: 21 // Class Description: 22 // Abstract base class for creating a tas 22 // Abstract base class for creating a task queue used by 23 // ThreadPool 23 // ThreadPool 24 // ------------------------------------------ 24 // --------------------------------------------------------------- 25 // Author: Jonathan Madsen 25 // Author: Jonathan Madsen 26 // ------------------------------------------ 26 // --------------------------------------------------------------- 27 27 28 #pragma once 28 #pragma once 29 29 30 #include "PTL/Macros.hh" << 30 #include "PTL/Globals.hh" >> 31 #include "PTL/Threading.hh" 31 #include "PTL/Types.hh" 32 #include "PTL/Types.hh" 32 33 33 #include <atomic> << 34 #include <cstddef> 34 #include <cstdint> << 35 #include <functional> << 36 #include <memory> << 37 #include <set> 35 #include <set> >> 36 #include <tuple> >> 37 #include <type_traits> >> 38 #include <utility> 38 39 39 namespace PTL 40 namespace PTL 40 { 41 { 41 class VTask; 42 class VTask; >> 43 class VTaskGroup; 42 class ThreadPool; 44 class ThreadPool; 43 class ThreadData; 45 class ThreadData; 44 46 45 class VUserTaskQueue 47 class VUserTaskQueue 46 { 48 { 47 public: 49 public: 48 using task_pointer = std::shared_ptr<VTas << 50 typedef VTask* task_pointer; 49 using AtomicInt = std::atomic<intmax_t << 51 typedef std::atomic<intmax_t> AtomicInt; 50 using size_type = uintmax_t; << 52 typedef uintmax_t size_type; 51 using function_type = std::function<void() << 53 typedef std::function<void()> function_type; 52 using ThreadIdSet = std::set<ThreadId>; << 54 typedef std::set<ThreadId> ThreadIdSet; 53 55 54 public: 56 public: 55 // Constructor - accepting the number of w 57 // Constructor - accepting the number of workers 56 explicit VUserTaskQueue(intmax_t nworkers 58 explicit VUserTaskQueue(intmax_t nworkers = -1); 57 // Virtual destructors are required by abs 59 // Virtual destructors are required by abstract classes 58 // so add it by default, just in case 60 // so add it by default, just in case 59 virtual ~VUserTaskQueue() = default; << 61 virtual ~VUserTaskQueue(); 60 62 61 public: 63 public: 62 // Virtual function for getting a task fro 64 // Virtual function for getting a task from the queue 63 // parameters: 65 // parameters: 64 // 1. int - get from specific sub-que 66 // 1. int - get from specific sub-queue 65 // 2. int - number of iterations 67 // 2. int - number of iterations 66 // returns: 68 // returns: 67 // VTask* - a task or nullptr 69 // VTask* - a task or nullptr 68 virtual task_pointer GetTask(intmax_t subq 70 virtual task_pointer GetTask(intmax_t subq = -1, intmax_t nitr = -1) = 0; 69 71 70 // Virtual function for inserting a task i 72 // Virtual function for inserting a task into the queue 71 // parameters: 73 // parameters: 72 // 1. VTask* - task to insert 74 // 1. VTask* - task to insert 73 // 2. int - sub-queue to inserting in 75 // 2. int - sub-queue to inserting into 74 // return: 76 // return: 75 // int - subqueue inserted into 77 // int - subqueue inserted into 76 virtual intmax_t InsertTask(task_pointer&& << 78 virtual intmax_t InsertTask(task_pointer, ThreadData* = nullptr, 77 intmax_t subq << 79 intmax_t subq = -1) = 0; 78 80 79 // Overload this function to hold threads 81 // Overload this function to hold threads 80 virtual void Wait() = 0; 82 virtual void Wait() = 0; 81 virtual intmax_t GetThreadBin() const = 0; 83 virtual intmax_t GetThreadBin() const = 0; 82 84 83 virtual void resize(intmax_t) = 0; 85 virtual void resize(intmax_t) = 0; 84 86 85 // these are used for stanard checking 87 // these are used for stanard checking 86 virtual size_type size() const = 0; 88 virtual size_type size() const = 0; 87 virtual bool empty() const = 0; 89 virtual bool empty() const = 0; 88 90 89 virtual size_type bin_size(size_type bin) 91 virtual size_type bin_size(size_type bin) const = 0; 90 virtual bool bin_empty(size_type bin) 92 virtual bool bin_empty(size_type bin) const = 0; 91 93 92 // these are for slower checking, default 94 // these are for slower checking, default to returning normal size()/empty 93 virtual size_type true_size() const { retu 95 virtual size_type true_size() const { return size(); } 94 virtual bool true_empty() const { ret 96 virtual bool true_empty() const { return empty(); } 95 97 96 // a method of executing a specific functi 98 // a method of executing a specific function on all threads 97 virtual void ExecuteOnAllThreads(ThreadPoo 99 virtual void ExecuteOnAllThreads(ThreadPool* tp, function_type f) = 0; 98 100 99 virtual void ExecuteOnSpecificThreads(Thre 101 virtual void ExecuteOnSpecificThreads(ThreadIdSet tid_set, ThreadPool* tp, 100 func 102 function_type f) = 0; 101 103 102 intmax_t workers() const { return m_worker 104 intmax_t workers() const { return m_workers; } 103 105 104 virtual VUserTaskQueue* clone() = 0; 106 virtual VUserTaskQueue* clone() = 0; >> 107 >> 108 // operator for number of tasks >> 109 // prefix versions >> 110 // virtual uintmax_t operator++() = 0; >> 111 // virtual uintmax_t operator--() = 0; >> 112 // postfix versions >> 113 // virtual uintmax_t operator++(int) = 0; >> 114 // virtual uintmax_t operator--(int) = 0; >> 115 >> 116 public: >> 117 template <typename ContainerT, size_t... Idx> >> 118 static auto ContainerToTupleImpl(ContainerT&& container, mpl::index_sequence<Idx...>) >> 119 -> decltype(std::make_tuple(std::forward<ContainerT>(container)[Idx]...)) >> 120 { >> 121 return std::make_tuple(std::forward<ContainerT>(container)[Idx]...); >> 122 } >> 123 >> 124 template <std::size_t N, typename ContainerT> >> 125 static auto ContainerToTuple(ContainerT&& container) >> 126 -> decltype(ContainerToTupleImpl(std::forward<ContainerT>(container), >> 127 mpl::make_index_sequence<N>{})) >> 128 { >> 129 return ContainerToTupleImpl(std::forward<ContainerT>(container), >> 130 mpl::make_index_sequence<N>{}); >> 131 } >> 132 >> 133 template <std::size_t N, std::size_t Nt, typename TupleT, >> 134 enable_if_t<(N == Nt), int> = 0> >> 135 static void TExecutor(TupleT&& _t) >> 136 { >> 137 if(std::get<N>(_t).get()) >> 138 (*(std::get<N>(_t)))(); >> 139 } >> 140 >> 141 template <std::size_t N, std::size_t Nt, typename TupleT, >> 142 enable_if_t<(N < Nt), int> = 0> >> 143 static void TExecutor(TupleT&& _t) >> 144 { >> 145 if(std::get<N>(_t).get()) >> 146 (*(std::get<N>(_t)))(); >> 147 TExecutor<N + 1, Nt, TupleT>(std::forward<TupleT>(_t)); >> 148 } >> 149 >> 150 template <typename TupleT, std::size_t N = std::tuple_size<decay_t<TupleT>>::value> >> 151 static void Executor(TupleT&& __t) >> 152 { >> 153 TExecutor<0, N - 1, TupleT>(std::forward<TupleT>(__t)); >> 154 } >> 155 >> 156 template <typename Container, >> 157 typename std::enable_if<std::is_same<Container, task_pointer>::value, >> 158 int>::type = 0> >> 159 static void Execute(Container& obj) >> 160 { >> 161 if(obj.get()) >> 162 (*obj)(); >> 163 } >> 164 >> 165 template <typename Container, >> 166 typename std::enable_if<!std::is_same<Container, task_pointer>::value, >> 167 int>::type = 0> >> 168 static void Execute(Container& tasks) >> 169 { >> 170 /* >> 171 for(auto& itr : tasks) >> 172 { >> 173 if(itr.get()) >> 174 (*itr)(); >> 175 }*/ >> 176 >> 177 size_type n = tasks.size(); >> 178 size_type max_n = 4; >> 179 while(n > 0) >> 180 { >> 181 auto compute = (n > max_n) ? max_n : n; >> 182 switch(compute) >> 183 { >> 184 case 4: { >> 185 auto t = ContainerToTuple<4>(tasks); >> 186 Executor(t); >> 187 break; >> 188 } >> 189 case 3: { >> 190 auto t = ContainerToTuple<3>(tasks); >> 191 Executor(t); >> 192 break; >> 193 } >> 194 case 2: { >> 195 auto t = ContainerToTuple<2>(tasks); >> 196 Executor(t); >> 197 break; >> 198 } >> 199 case 1: { >> 200 auto t = ContainerToTuple<1>(tasks); >> 201 Executor(t); >> 202 break; >> 203 } >> 204 case 0: break; >> 205 } >> 206 // tasks.erase(tasks.begin(), tasks.begin() + compute); >> 207 n -= compute; >> 208 } >> 209 } 105 210 106 protected: 211 protected: 107 intmax_t m_workers = 0; 212 intmax_t m_workers = 0; 108 }; 213 }; 109 214 110 } // namespace PTL 215 } // namespace PTL 111 216