1 #include "thread/OpenMp.h"
2 #include "math/MathBasic.h"
3 #include "objects/wrappers/Optional.h"
4 #include "thread/CheckFunction.h"
5 
6 #ifdef SPH_USE_OPENMP
7 #include <omp.h>
8 #endif
9 
10 NAMESPACE_SPH_BEGIN
11 
12 #ifdef SPH_USE_OPENMP
13 
14 SharedPtr<OmpScheduler> OmpScheduler::globalInstance;
15 
OmpScheduler(const Size numThreads)16 OmpScheduler::OmpScheduler(const Size numThreads) {
17     if (numThreads > 0) {
18         omp_set_num_threads(numThreads);
19     }
20 }
21 
22 class OmpTaskHandle : public ITask {
23 public:
wait()24     virtual void wait() override {}
25 
completed() const26     virtual bool completed() const override {
27         return true;
28     }
29 };
30 
31 
submit(const Function<void ()> & task)32 SharedPtr<ITask> OmpScheduler::submit(const Function<void()>& task) {
33     if (isMainThread()) {
34 #pragma omp parallel
35         {
36 #pragma omp single
37             {
38 #pragma omp taskgroup
39                 {
40 #pragma omp task
41                     { task(); }
42                 }
43             }
44         }
45     } else {
46 #pragma omp task
47         { task(); }
48     }
49     return makeShared<OmpTaskHandle>();
50 }
51 
getThreadIdx() const52 Optional<Size> OmpScheduler::getThreadIdx() const {
53     return omp_get_thread_num();
54 }
55 
getThreadCnt() const56 Size OmpScheduler::getThreadCnt() const {
57     return omp_get_max_threads();
58 }
59 
getRecommendedGranularity() const60 Size OmpScheduler::getRecommendedGranularity() const {
61     return granularity;
62 }
63 
parallelFor(const Size from,const Size to,const Size granularity,const RangeFunctor & functor)64 void OmpScheduler::parallelFor(const Size from,
65     const Size to,
66     const Size granularity,
67     const RangeFunctor& functor) {
68 #pragma omp parallel for schedule(dynamic, 1)
69     for (Size n = from; n < to; n += granularity) {
70         const Size n1 = n;
71         const Size n2 = min(n1 + granularity, to);
72         functor(n1, n2);
73     }
74 }
75 
invoke(const OmpScheduler::Functor & task1,const OmpScheduler::Functor & task2)76 static void invoke(const OmpScheduler::Functor& task1, const OmpScheduler::Functor& task2) {
77 #pragma omp taskgroup
78     {
79 #pragma omp task shared(task1)
80         task1();
81 
82 #pragma omp task shared(task2)
83         task2();
84     }
85 }
86 
parallelInvoke(const Functor & task1,const Functor & task2)87 void OmpScheduler::parallelInvoke(const Functor& task1, const Functor& task2) {
88     if (omp_get_level() == 0) {
89 // top-level call
90 #pragma omp parallel shared(task1, task2)
91         {
92 #pragma omp single
93             { invoke(task1, task2); }
94         }
95     } else {
96         // nested call
97         invoke(task1, task2);
98     }
99 }
100 
getGlobalInstance()101 SharedPtr<OmpScheduler> OmpScheduler::getGlobalInstance() {
102     if (!globalInstance) {
103         globalInstance = makeShared<OmpScheduler>();
104     }
105     return globalInstance;
106 }
107 
108 #endif
109 
110 NAMESPACE_SPH_END
111