parallel_reduce.h 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. // ======================================================================== //
  2. // Copyright 2009-2017 Intel Corporation //
  3. // //
  4. // Licensed under the Apache License, Version 2.0 (the "License"); //
  5. // you may not use this file except in compliance with the License. //
  6. // You may obtain a copy of the License at //
  7. // //
  8. // http://www.apache.org/licenses/LICENSE-2.0 //
  9. // //
  10. // Unless required by applicable law or agreed to in writing, software //
  11. // distributed under the License is distributed on an "AS IS" BASIS, //
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
  13. // See the License for the specific language governing permissions and //
  14. // limitations under the License. //
  15. // ======================================================================== //
  16. #pragma once
  17. #include "parallel_for.h"
  18. namespace embree
  19. {
  20. template<typename Index, typename Value, typename Func, typename Reduction>
  21. __forceinline Value sequential_reduce( const Index first, const Index last, const Value& identity, const Func& func, const Reduction& reduction )
  22. {
  23. return func(range<Index>(first,last));
  24. }
  25. template<typename Index, typename Value, typename Func, typename Reduction>
  26. __forceinline Value sequential_reduce( const Index first, const Index last, const Index minStepSize, const Value& identity, const Func& func, const Reduction& reduction )
  27. {
  28. return func(range<Index>(first,last));
  29. }
  30. template<typename Index, typename Value, typename Func, typename Reduction>
  31. __noinline Value parallel_reduce_internal( Index taskCount, const Index first, const Index last, const Index minStepSize, const Value& identity, const Func& func, const Reduction& reduction )
  32. {
  33. const Index maxTasks = 512;
  34. const Index threadCount = (Index) TaskScheduler::threadCount();
  35. taskCount = min(taskCount,threadCount,maxTasks);
  36. /* parallel invokation of all tasks */
  37. dynamic_large_stack_array(Value,values,taskCount,4096); // consumes at most 4096 bytes on the stack
  38. parallel_for(taskCount, [&](const Index taskIndex) {
  39. const Index k0 = first+(taskIndex+0)*(last-first)/taskCount;
  40. const Index k1 = first+(taskIndex+1)*(last-first)/taskCount;
  41. values[taskIndex] = func(range<Index>(k0,k1));
  42. });
  43. /* perform reduction over all tasks */
  44. Value v = identity;
  45. for (Index i=0; i<taskCount; i++) v = reduction(v,values[i]);
  46. return v;
  47. }
  48. template<typename Index, typename Value, typename Func, typename Reduction>
  49. __forceinline Value parallel_reduce( const Index first, const Index last, const Index minStepSize, const Value& identity, const Func& func, const Reduction& reduction )
  50. {
  51. #if defined(TASKING_INTERNAL)
  52. /* fast path for small number of iterations */
  53. Index taskCount = (last-first+minStepSize-1)/minStepSize;
  54. if (likely(taskCount == 1)) {
  55. return func(range<Index>(first,last));
  56. }
  57. return parallel_reduce_internal(taskCount,first,last,minStepSize,identity,func,reduction);
  58. #elif defined(TASKING_TBB)
  59. const Value v = tbb::parallel_reduce(tbb::blocked_range<Index>(first,last,minStepSize),identity,
  60. [&](const tbb::blocked_range<Index>& r, const Value& start) { return reduction(start,func(range<Index>(r.begin(),r.end()))); },
  61. reduction);
  62. if (tbb::task::self().is_cancelled())
  63. throw std::runtime_error("task cancelled");
  64. return v;
  65. #else // TASKING_PPL
  66. struct AlignedValue
  67. {
  68. char storage[__alignof(Value)+sizeof(Value)];
  69. static uintptr_t alignUp(uintptr_t p, size_t a) { return p + (~(p - 1) % a); };
  70. Value* getValuePtr() { return reinterpret_cast<Value*>(alignUp(uintptr_t(storage), __alignof(Value))); }
  71. const Value* getValuePtr() const { return reinterpret_cast<Value*>(alignUp(uintptr_t(storage), __alignof(Value))); }
  72. AlignedValue(const Value& v) { new(getValuePtr()) Value(v); }
  73. AlignedValue(const AlignedValue& v) { new(getValuePtr()) Value(*v.getValuePtr()); }
  74. AlignedValue(const AlignedValue&& v) { new(getValuePtr()) Value(*v.getValuePtr()); };
  75. AlignedValue& operator = (const AlignedValue& v) { *getValuePtr() = *v.getValuePtr(); return *this; };
  76. AlignedValue& operator = (const AlignedValue&& v) { *getValuePtr() = *v.getValuePtr(); return *this; };
  77. operator Value() const { return *getValuePtr(); }
  78. };
  79. struct Iterator_Index
  80. {
  81. Index v;
  82. typedef std::forward_iterator_tag iterator_category;
  83. typedef AlignedValue value_type;
  84. typedef Index difference_type;
  85. typedef Index distance_type;
  86. typedef AlignedValue* pointer;
  87. typedef AlignedValue& reference;
  88. __forceinline Iterator_Index() {}
  89. __forceinline Iterator_Index(Index v) : v(v) {}
  90. __forceinline bool operator== (Iterator_Index other) { return v == other.v; }
  91. __forceinline bool operator!= (Iterator_Index other) { return v != other.v; }
  92. __forceinline Iterator_Index operator++() { return Iterator_Index(++v); }
  93. __forceinline Iterator_Index operator++(int) { return Iterator_Index(v++); }
  94. };
  95. auto range_reduction = [&](Iterator_Index begin, Iterator_Index end, const AlignedValue& start) {
  96. assert(begin.v < end.v);
  97. return reduction(start, func(range<Index>(begin.v, end.v)));
  98. };
  99. const Value v = concurrency::parallel_reduce(Iterator_Index(first), Iterator_Index(last), AlignedValue(identity), range_reduction, reduction);
  100. return v;
  101. #endif
  102. }
  103. template<typename Index, typename Value, typename Func, typename Reduction>
  104. __forceinline Value parallel_reduce( const Index first, const Index last, const Index minStepSize, const Index parallel_threshold, const Value& identity, const Func& func, const Reduction& reduction )
  105. {
  106. if (likely(last-first < parallel_threshold)) {
  107. return func(range<Index>(first,last));
  108. } else {
  109. return parallel_reduce(first,last,minStepSize,identity,func,reduction);
  110. }
  111. }
  112. template<typename Index, typename Value, typename Func, typename Reduction>
  113. __forceinline Value parallel_reduce( const range<Index> range, const Index minStepSize, const Index parallel_threshold, const Value& identity, const Func& func, const Reduction& reduction )
  114. {
  115. return parallel_reduce(range.begin(),range.end(),minStepSize,parallel_threshold,identity,func,reduction);
  116. }
  117. template<typename Index, typename Value, typename Func, typename Reduction>
  118. __forceinline Value parallel_reduce( const Index first, const Index last, const Value& identity, const Func& func, const Reduction& reduction )
  119. {
  120. return parallel_reduce(first,last,Index(1),identity,func,reduction);
  121. }
  122. template<typename Index, typename Value, typename Func, typename Reduction>
  123. __forceinline Value parallel_reduce( const range<Index> range, const Value& identity, const Func& func, const Reduction& reduction )
  124. {
  125. return parallel_reduce(range.begin(),range.end(),Index(1),identity,func,reduction);
  126. }
  127. }