1 // Copyright 2009-2021 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
3 
4 #pragma once
5 
6 #include "../tasking/taskscheduler.h"
7 #include "../sys/array.h"
8 #include "../math/math.h"
9 #include "../math/range.h"
10 
11 namespace embree
12 {
13   /* parallel_for without range */
14   template<typename Index, typename Func>
parallel_for(const Index N,const Func & func)15     __forceinline void parallel_for( const Index N, const Func& func)
16   {
17 #if defined(TASKING_INTERNAL)
18     if (N) {
19       TaskScheduler::spawn(Index(0),N,Index(1),[&] (const range<Index>& r) {
20           assert(r.size() == 1);
21           func(r.begin());
22         });
23       if (!TaskScheduler::wait())
24         throw std::runtime_error("task cancelled");
25     }
26 
27 #elif defined(TASKING_TBB)
28   #if TBB_INTERFACE_VERSION >= 12002
29     tbb::task_group_context context;
30     tbb::parallel_for(Index(0),N,Index(1),[&](Index i) {
31         func(i);
32       },context);
33     if (context.is_group_execution_cancelled())
34       throw std::runtime_error("task cancelled");
35   #else
36     tbb::parallel_for(Index(0),N,Index(1),[&](Index i) {
37         func(i);
38       });
39     if (tbb::task::self().is_cancelled())
40       throw std::runtime_error("task cancelled");
41   #endif
42 
43 #elif defined(TASKING_PPL)
44     concurrency::parallel_for(Index(0),N,Index(1),[&](Index i) {
45         func(i);
46       });
47 #else
48 #  error "no tasking system enabled"
49 #endif
50   }
51 
52   /* parallel for with range and granulatity */
53   template<typename Index, typename Func>
parallel_for(const Index first,const Index last,const Index minStepSize,const Func & func)54     __forceinline void parallel_for( const Index first, const Index last, const Index minStepSize, const Func& func)
55   {
56     assert(first <= last);
57 #if defined(TASKING_INTERNAL)
58     TaskScheduler::spawn(first,last,minStepSize,func);
59     if (!TaskScheduler::wait())
60       throw std::runtime_error("task cancelled");
61 
62 #elif defined(TASKING_TBB)
63   #if TBB_INTERFACE_VERSION >= 12002
64     tbb::task_group_context context;
65     tbb::parallel_for(tbb::blocked_range<Index>(first,last,minStepSize),[&](const tbb::blocked_range<Index>& r) {
66         func(range<Index>(r.begin(),r.end()));
67       },context);
68     if (context.is_group_execution_cancelled())
69       throw std::runtime_error("task cancelled");
70   #else
71     tbb::parallel_for(tbb::blocked_range<Index>(first,last,minStepSize),[&](const tbb::blocked_range<Index>& r) {
72         func(range<Index>(r.begin(),r.end()));
73       });
74     if (tbb::task::self().is_cancelled())
75       throw std::runtime_error("task cancelled");
76   #endif
77 
78 #elif defined(TASKING_PPL)
79     concurrency::parallel_for(first, last, Index(1) /*minStepSize*/, [&](Index i) {
80         func(range<Index>(i,i+1));
81       });
82 
83 #else
84 #  error "no tasking system enabled"
85 #endif
86   }
87 
88   /* parallel for with range */
89   template<typename Index, typename Func>
parallel_for(const Index first,const Index last,const Func & func)90     __forceinline void parallel_for( const Index first, const Index last, const Func& func)
91   {
92     assert(first <= last);
93     parallel_for(first,last,(Index)1,func);
94   }
95 
96 #if defined(TASKING_TBB) && (TBB_INTERFACE_VERSION > 4001)
97 
98   template<typename Index, typename Func>
parallel_for_static(const Index N,const Func & func)99     __forceinline void parallel_for_static( const Index N, const Func& func)
100   {
101     #if TBB_INTERFACE_VERSION >= 12002
102       tbb::task_group_context context;
103       tbb::parallel_for(Index(0),N,Index(1),[&](Index i) {
104           func(i);
105         },tbb::simple_partitioner(),context);
106       if (context.is_group_execution_cancelled())
107         throw std::runtime_error("task cancelled");
108     #else
109       tbb::parallel_for(Index(0),N,Index(1),[&](Index i) {
110           func(i);
111         },tbb::simple_partitioner());
112       if (tbb::task::self().is_cancelled())
113         throw std::runtime_error("task cancelled");
114     #endif
115   }
116 
117   typedef tbb::affinity_partitioner affinity_partitioner;
118 
119   template<typename Index, typename Func>
parallel_for_affinity(const Index N,const Func & func,tbb::affinity_partitioner & ap)120     __forceinline void parallel_for_affinity( const Index N, const Func& func, tbb::affinity_partitioner& ap)
121   {
122     #if TBB_INTERFACE_VERSION >= 12002
123       tbb::task_group_context context;
124       tbb::parallel_for(Index(0),N,Index(1),[&](Index i) {
125           func(i);
126         },ap,context);
127       if (context.is_group_execution_cancelled())
128         throw std::runtime_error("task cancelled");
129     #else
130       tbb::parallel_for(Index(0),N,Index(1),[&](Index i) {
131           func(i);
132         },ap);
133       if (tbb::task::self().is_cancelled())
134         throw std::runtime_error("task cancelled");
135     #endif
136   }
137 
138 #else
139 
140   template<typename Index, typename Func>
parallel_for_static(const Index N,const Func & func)141     __forceinline void parallel_for_static( const Index N, const Func& func)
142   {
143     parallel_for(N,func);
144   }
145 
146   struct affinity_partitioner {
147   };
148 
149   template<typename Index, typename Func>
parallel_for_affinity(const Index N,const Func & func,affinity_partitioner & ap)150     __forceinline void parallel_for_affinity( const Index N, const Func& func, affinity_partitioner& ap)
151   {
152     parallel_for(N,func);
153   }
154 
155 #endif
156 }
157