parallel_for.h 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. // Copyright 2009-2020 Intel Corporation
  2. // SPDX-License-Identifier: Apache-2.0
  3. #pragma once
  4. #include "../tasking/taskscheduler.h"
  5. #include "../sys/array.h"
  6. #include "../math/math.h"
  7. #include "../math/range.h"
  8. #if defined(TASKING_GCD) && defined(BUILD_IOS)
  9. #include <dispatch/dispatch.h>
  10. #include <algorithm>
  11. #include <type_traits>
  12. #endif
  13. namespace embree
  14. {
  15. /* parallel_for without range */
  16. template<typename Index, typename Func>
  17. __forceinline void parallel_for( const Index N, const Func& func)
  18. {
  19. #if defined(TASKING_INTERNAL)
  20. if (N) {
  21. TaskScheduler::spawn(Index(0),N,Index(1),[&] (const range<Index>& r) {
  22. assert(r.size() == 1);
  23. func(r.begin());
  24. });
  25. if (!TaskScheduler::wait())
  26. // -- GODOT start --
  27. // throw std::runtime_error("task cancelled");
  28. abort();
  29. // -- GODOT end --
  30. }
  31. #elif defined(TASKING_GCD) && defined(BUILD_IOS)
  32. const size_t baselineNumBlocks = (TaskScheduler::threadCount() > 1)? TaskScheduler::threadCount() : 1;
  33. const size_t length = N;
  34. const size_t blockSize = (length + baselineNumBlocks-1) / baselineNumBlocks;
  35. const size_t numBlocks = (length + blockSize-1) / blockSize;
  36. dispatch_apply(numBlocks, DISPATCH_APPLY_AUTO, ^(size_t currentBlock) {
  37. const size_t start = (currentBlock * blockSize);
  38. const size_t blockLength = std::min(length - start, blockSize);
  39. const size_t end = start + blockLength;
  40. for(size_t i=start; i < end; i++)
  41. {
  42. func(i);
  43. }
  44. });
  45. #elif defined(TASKING_TBB)
  46. #if TBB_INTERFACE_VERSION >= 12002
  47. tbb::task_group_context context;
  48. tbb::parallel_for(Index(0),N,Index(1),[&](Index i) {
  49. func(i);
  50. },context);
  51. if (context.is_group_execution_cancelled())
  52. // -- GODOT start --
  53. // throw std::runtime_error("task cancelled");
  54. abort();
  55. // -- GODOT end --
  56. #else
  57. tbb::parallel_for(Index(0),N,Index(1),[&](Index i) {
  58. func(i);
  59. });
  60. if (tbb::task::self().is_cancelled())
  61. // -- GODOT start --
  62. // throw std::runtime_error("task cancelled");
  63. abort();
  64. // -- GODOT end --
  65. #endif
  66. #elif defined(TASKING_PPL)
  67. concurrency::parallel_for(Index(0),N,Index(1),[&](Index i) {
  68. func(i);
  69. });
  70. #else
  71. # error "no tasking system enabled"
  72. #endif
  73. }
  74. /* parallel for with range and granulatity */
  75. template<typename Index, typename Func>
  76. __forceinline void parallel_for( const Index first, const Index last, const Index minStepSize, const Func& func)
  77. {
  78. assert(first <= last);
  79. #if defined(TASKING_INTERNAL)
  80. TaskScheduler::spawn(first,last,minStepSize,func);
  81. if (!TaskScheduler::wait())
  82. // -- GODOT start --
  83. // throw std::runtime_error("task cancelled");
  84. abort();
  85. // -- GODOT end --
  86. #elif defined(TASKING_GCD) && defined(BUILD_IOS)
  87. const size_t baselineNumBlocks = (TaskScheduler::threadCount() > 1)? 4*TaskScheduler::threadCount() : 1;
  88. const size_t length = last - first;
  89. const size_t blockSizeByThreads = (length + baselineNumBlocks-1) / baselineNumBlocks;
  90. size_t blockSize = std::max<size_t>(minStepSize,blockSizeByThreads);
  91. blockSize += blockSize % 4;
  92. const size_t numBlocks = (length + blockSize-1) / blockSize;
  93. dispatch_apply(numBlocks, DISPATCH_APPLY_AUTO, ^(size_t currentBlock) {
  94. const size_t start = first + (currentBlock * blockSize);
  95. const size_t end = std::min<size_t>(last, start + blockSize);
  96. func( embree::range<Index>(start,end) );
  97. });
  98. #elif defined(TASKING_TBB)
  99. #if TBB_INTERFACE_VERSION >= 12002
  100. tbb::task_group_context context;
  101. tbb::parallel_for(tbb::blocked_range<Index>(first,last,minStepSize),[&](const tbb::blocked_range<Index>& r) {
  102. func(range<Index>(r.begin(),r.end()));
  103. },context);
  104. if (context.is_group_execution_cancelled())
  105. // -- GODOT start --
  106. // throw std::runtime_error("task cancelled");
  107. abort();
  108. // -- GODOT end --
  109. #else
  110. tbb::parallel_for(tbb::blocked_range<Index>(first,last,minStepSize),[&](const tbb::blocked_range<Index>& r) {
  111. func(range<Index>(r.begin(),r.end()));
  112. });
  113. if (tbb::task::self().is_cancelled())
  114. // -- GODOT start --
  115. // throw std::runtime_error("task cancelled");
  116. abort();
  117. // -- GODOT end --
  118. #endif
  119. #elif defined(TASKING_PPL)
  120. concurrency::parallel_for(first, last, Index(1) /*minStepSize*/, [&](Index i) {
  121. func(range<Index>(i,i+1));
  122. });
  123. #else
  124. # error "no tasking system enabled"
  125. #endif
  126. }
  127. /* parallel for with range */
  128. template<typename Index, typename Func>
  129. __forceinline void parallel_for( const Index first, const Index last, const Func& func)
  130. {
  131. assert(first <= last);
  132. parallel_for(first,last,(Index)1,func);
  133. }
  134. #if defined(TASKING_TBB) && (TBB_INTERFACE_VERSION > 4001)
  135. template<typename Index, typename Func>
  136. __forceinline void parallel_for_static( const Index N, const Func& func)
  137. {
  138. #if TBB_INTERFACE_VERSION >= 12002
  139. tbb::task_group_context context;
  140. tbb::parallel_for(Index(0),N,Index(1),[&](Index i) {
  141. func(i);
  142. },tbb::simple_partitioner(),context);
  143. if (context.is_group_execution_cancelled())
  144. // -- GODOT start --
  145. // throw std::runtime_error("task cancelled");
  146. abort();
  147. // -- GODOT end --
  148. #else
  149. tbb::parallel_for(Index(0),N,Index(1),[&](Index i) {
  150. func(i);
  151. },tbb::simple_partitioner());
  152. if (tbb::task::self().is_cancelled())
  153. // -- GODOT start --
  154. // throw std::runtime_error("task cancelled");
  155. abort();
  156. // -- GODOT end --
  157. #endif
  158. }
  159. typedef tbb::affinity_partitioner affinity_partitioner;
  160. template<typename Index, typename Func>
  161. __forceinline void parallel_for_affinity( const Index N, const Func& func, tbb::affinity_partitioner& ap)
  162. {
  163. #if TBB_INTERFACE_VERSION >= 12002
  164. tbb::task_group_context context;
  165. tbb::parallel_for(Index(0),N,Index(1),[&](Index i) {
  166. func(i);
  167. },ap,context);
  168. if (context.is_group_execution_cancelled())
  169. // -- GODOT start --
  170. // throw std::runtime_error("task cancelled");
  171. abort();
  172. // -- GODOT end --
  173. #else
  174. tbb::parallel_for(Index(0),N,Index(1),[&](Index i) {
  175. func(i);
  176. },ap);
  177. if (tbb::task::self().is_cancelled())
  178. // -- GODOT start --
  179. // throw std::runtime_error("task cancelled");
  180. abort();
  181. // -- GODOT end --
  182. #endif
  183. }
  184. #else
  185. template<typename Index, typename Func>
  186. __forceinline void parallel_for_static( const Index N, const Func& func)
  187. {
  188. parallel_for(N,func);
  189. }
  190. struct affinity_partitioner {
  191. };
  192. template<typename Index, typename Func>
  193. __forceinline void parallel_for_affinity( const Index N, const Func& func, affinity_partitioner& ap)
  194. {
  195. parallel_for(N,func);
  196. }
  197. #endif
  198. }