Viskores  1.0
FunctorsTBB.h
Go to the documentation of this file.
1 //============================================================================
2 // The contents of this file are covered by the Viskores license. See
3 // LICENSE.txt for details.
4 //
5 // By contributing to this file, all contributors agree to the Developer
6 // Certificate of Origin Version 1.1 (DCO 1.1) as stated in DCO.txt.
7 //============================================================================
8 
9 //============================================================================
10 // Copyright (c) Kitware, Inc.
11 // All rights reserved.
12 // See LICENSE.txt for details.
13 //
14 // This software is distributed WITHOUT ANY WARRANTY; without even
15 // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
16 // PURPOSE. See the above copyright notice for more information.
17 //============================================================================
18 #ifndef viskores_cont_tbb_internal_FunctorsTBB_h
19 #define viskores_cont_tbb_internal_FunctorsTBB_h
20 
21 #include <viskores/TypeTraits.h>
22 #include <viskores/Types.h>
24 #include <viskores/cont/Error.h>
27 
28 #include <algorithm>
29 #include <iterator>
30 #include <sstream>
31 #include <type_traits>
32 
34 
35 #if defined(VISKORES_MSVC)
36 
37 // TBB's header include a #pragma comment(lib,"tbb.lib") line to make all
38 // consuming libraries link to tbb, this is bad behavior in a header
39 // based project
40 #pragma push_macro("__TBB_NO_IMPLICITLINKAGE")
41 #define __TBB_NO_IMPLICIT_LINKAGE 1
42 
43 #endif // defined(VISKORES_MSVC)
44 
45 // TBB includes windows.h, so instead we want to include windows.h with the
46 // correct settings so that we don't clobber any existing function
48 
49 
50 #include <numeric>
51 #include <tbb/blocked_range.h>
52 #include <tbb/blocked_range3d.h>
53 #include <tbb/parallel_for.h>
54 #include <tbb/parallel_reduce.h>
55 #include <tbb/parallel_scan.h>
56 #include <tbb/parallel_sort.h>
57 #include <tbb/partitioner.h>
58 #include <tbb/tick_count.h>
59 
60 #if defined(VISKORES_MSVC)
61 #pragma pop_macro("__TBB_NO_IMPLICITLINKAGE")
62 #endif
63 
65 
66 namespace viskores
67 {
68 namespace cont
69 {
70 namespace tbb
71 {
72 
73 namespace internal
74 {
75 template <typename ResultType, typename Function>
76 using WrappedBinaryOperator = viskores::cont::internal::WrappedBinaryOperator<ResultType, Function>;
77 }
78 
79 // The "grain size" of scheduling with TBB. Not a lot of thought has gone
80 // into picking this size.
81 static constexpr viskores::Id TBB_GRAIN_SIZE = 1024;
82 
83 template <typename InputPortalType, typename OutputPortalType>
84 struct CopyBody
85 {
86  InputPortalType InputPortal;
87  OutputPortalType OutputPortal;
90 
91  CopyBody(const InputPortalType& inPortal,
92  const OutputPortalType& outPortal,
93  viskores::Id inOffset,
94  viskores::Id outOffset)
95  : InputPortal(inPortal)
96  , OutputPortal(outPortal)
97  , InputOffset(inOffset)
98  , OutputOffset(outOffset)
99  {
100  }
101 
102  // MSVC likes complain about narrowing type conversions in std::copy and
103  // provides no reasonable way to disable the warning. As a work-around, this
104  // template calls std::copy if and only if the types match, otherwise falls
105  // back to a iterative casting approach. Since std::copy can only really
106  // optimize same-type copies, this shouldn't affect performance.
107  template <typename InIter, typename OutIter>
108  void DoCopy(InIter src, InIter srcEnd, OutIter dst, std::false_type) const
109  {
110  using InputType = typename InputPortalType::ValueType;
111  using OutputType = typename OutputPortalType::ValueType;
112  while (src != srcEnd)
113  {
114  // The conversion to InputType and then OutputType looks weird, but it is necessary.
115  // *src actually returns an ArrayPortalValueReference, which can automatically convert
116  // itself to InputType but not necessarily OutputType. Thus, we first convert to
117  // InputType, and then allow the conversion to OutputType.
118  *dst = static_cast<OutputType>(static_cast<InputType>(*src));
119  ++src;
120  ++dst;
121  }
122  }
123 
124 
125  template <typename InIter, typename OutIter>
126  void DoCopy(InIter src, InIter srcEnd, OutIter dst, std::true_type) const
127  {
128  std::copy(src, srcEnd, dst);
129  }
130 
131 
132 
133  void operator()(const ::tbb::blocked_range<viskores::Id>& range) const
134  {
135  if (range.empty())
136  {
137  return;
138  }
139 
140  auto inIter = viskores::cont::ArrayPortalToIteratorBegin(this->InputPortal);
141  auto outIter = viskores::cont::ArrayPortalToIteratorBegin(this->OutputPortal);
142 
143  using InputType = typename InputPortalType::ValueType;
144  using OutputType = typename OutputPortalType::ValueType;
145 
146  this->DoCopy(inIter + this->InputOffset + range.begin(),
147  inIter + this->InputOffset + range.end(),
148  outIter + this->OutputOffset + range.begin(),
149  std::is_same<InputType, OutputType>());
150  }
151 };
152 
153 template <typename InputPortalType, typename OutputPortalType>
154 void CopyPortals(const InputPortalType& inPortal,
155  const OutputPortalType& outPortal,
156  viskores::Id inOffset,
157  viskores::Id outOffset,
158  viskores::Id numValues)
159 {
161  Kernel kernel(inPortal, outPortal, inOffset, outOffset);
162  ::tbb::blocked_range<viskores::Id> range(0, numValues, TBB_GRAIN_SIZE);
163  ::tbb::parallel_for(range, kernel);
164 }
165 
166 template <typename InputPortalType,
167  typename StencilPortalType,
168  typename OutputPortalType,
169  typename UnaryPredicateType>
171 {
172  using ValueType = typename InputPortalType::ValueType;
173  using StencilType = typename StencilPortalType::ValueType;
174 
175  struct Range
176  {
181 
182 
184  : InputBegin(-1)
185  , InputEnd(-1)
186  , OutputBegin(-1)
187  , OutputEnd(-1)
188  {
189  }
190 
191 
192  Range(viskores::Id inputBegin,
193  viskores::Id inputEnd,
194  viskores::Id outputBegin,
195  viskores::Id outputEnd)
196  : InputBegin(inputBegin)
197  , InputEnd(inputEnd)
198  , OutputBegin(outputBegin)
199  , OutputEnd(outputEnd)
200  {
201  this->AssertSane();
202  }
203 
204 
205  void AssertSane() const
206  {
207  VISKORES_ASSERT("Input begin precedes end" && this->InputBegin <= this->InputEnd);
208  VISKORES_ASSERT("Output begin precedes end" && this->OutputBegin <= this->OutputEnd);
209  VISKORES_ASSERT("Output not past input" && this->OutputBegin <= this->InputBegin &&
210  this->OutputEnd <= this->InputEnd);
211  VISKORES_ASSERT("Output smaller than input" &&
212  (this->OutputEnd - this->OutputBegin) <= (this->InputEnd - this->InputBegin));
213  }
214 
215 
216  bool IsNext(const Range& next) const { return this->InputEnd == next.InputBegin; }
217  };
218 
219  InputPortalType InputPortal;
220  StencilPortalType StencilPortal;
221  OutputPortalType OutputPortal;
222  UnaryPredicateType UnaryPredicate;
224 
226  CopyIfBody(const InputPortalType& inputPortal,
227  const StencilPortalType& stencilPortal,
228  const OutputPortalType& outputPortal,
229  UnaryPredicateType unaryPredicate)
230  : InputPortal(inputPortal)
231  , StencilPortal(stencilPortal)
232  , OutputPortal(outputPortal)
233  , UnaryPredicate(unaryPredicate)
234  {
235  }
236 
237 
238  CopyIfBody(const CopyIfBody& body, ::tbb::split)
239  : InputPortal(body.InputPortal)
241  , OutputPortal(body.OutputPortal)
243  {
244  }
245 
246 
247 
248  void operator()(const ::tbb::blocked_range<viskores::Id>& range)
249  {
250  if (range.empty())
251  {
252  return;
253  }
254 
255  bool firstRun = this->Ranges.OutputBegin < 0; // First use of this body object
256  if (firstRun)
257  {
258  this->Ranges.InputBegin = range.begin();
259  }
260  else
261  {
262  // Must be a continuation of the previous input range:
263  VISKORES_ASSERT(this->Ranges.InputEnd == range.begin());
264  }
265  this->Ranges.InputEnd = range.end();
266  this->Ranges.AssertSane();
267 
271 
272  InputIteratorsType inputIters(this->InputPortal);
273  StencilIteratorsType stencilIters(this->StencilPortal);
274  OutputIteratorsType outputIters(this->OutputPortal);
275 
276  using InputIteratorType = typename InputIteratorsType::IteratorType;
277  using StencilIteratorType = typename StencilIteratorsType::IteratorType;
278  using OutputIteratorType = typename OutputIteratorsType::IteratorType;
279 
280  InputIteratorType inIter = inputIters.GetBegin();
281  StencilIteratorType stencilIter = stencilIters.GetBegin();
282  OutputIteratorType outIter = outputIters.GetBegin();
283 
284  viskores::Id readPos = range.begin();
285  const viskores::Id readEnd = range.end();
286 
287  // Determine output index. If we're reusing the body, pick up where the
288  // last block left off. If not, use the input range.
289  viskores::Id writePos;
290  if (firstRun)
291  {
292  this->Ranges.OutputBegin = range.begin();
293  this->Ranges.OutputEnd = range.begin();
294  writePos = range.begin();
295  }
296  else
297  {
298  writePos = this->Ranges.OutputEnd;
299  }
300  this->Ranges.AssertSane();
301 
302  // We're either writing at the end of a previous block, or at the input
303  // location. Either way, the write position will never be greater than
304  // the read position.
305  VISKORES_ASSERT(writePos <= readPos);
306 
307  UnaryPredicateType predicate(this->UnaryPredicate);
308  for (; readPos < readEnd; ++readPos)
309  {
310  if (predicate(stencilIter[readPos]))
311  {
312  outIter[writePos] = inIter[readPos];
313  ++writePos;
314  }
315  }
316 
317  this->Ranges.OutputEnd = writePos;
318  }
319 
320 
321 
322  void join(const CopyIfBody& rhs)
323  {
325  using OutputIteratorType = typename OutputIteratorsType::IteratorType;
326 
327  OutputIteratorsType outputIters(this->OutputPortal);
328  OutputIteratorType outIter = outputIters.GetBegin();
329 
330  this->Ranges.AssertSane();
331  rhs.Ranges.AssertSane();
332  // Ensure that we're joining two consecutive subsets of the input:
333  VISKORES_ASSERT(this->Ranges.IsNext(rhs.Ranges));
334 
335  viskores::Id srcBegin = rhs.Ranges.OutputBegin;
336  const viskores::Id srcEnd = rhs.Ranges.OutputEnd;
337  const viskores::Id dstBegin = this->Ranges.OutputEnd;
338 
339  // move data:
340  if (srcBegin != dstBegin && srcBegin != srcEnd)
341  {
342  // Sanity check:
343  VISKORES_ASSERT(srcBegin < srcEnd);
344  std::copy(outIter + srcBegin, outIter + srcEnd, outIter + dstBegin);
345  }
346 
347  this->Ranges.InputEnd = rhs.Ranges.InputEnd;
348  this->Ranges.OutputEnd += srcEnd - srcBegin;
349  this->Ranges.AssertSane();
350  }
351 };
352 
353 
354 template <typename InputPortalType,
355  typename StencilPortalType,
356  typename OutputPortalType,
357  typename UnaryPredicateType>
358 VISKORES_CONT viskores::Id CopyIfPortals(InputPortalType inputPortal,
359  StencilPortalType stencilPortal,
360  OutputPortalType outputPortal,
361  UnaryPredicateType unaryPredicate)
362 {
363  const viskores::Id inputLength = inputPortal.GetNumberOfValues();
364  VISKORES_ASSERT(inputLength == stencilPortal.GetNumberOfValues());
365 
366  if (inputLength == 0)
367  {
368  return 0;
369  }
370 
372  inputPortal, stencilPortal, outputPortal, unaryPredicate);
373  ::tbb::blocked_range<viskores::Id> range(0, inputLength, TBB_GRAIN_SIZE);
374 
375  ::tbb::parallel_reduce(range, body);
376 
377  body.Ranges.AssertSane();
378  VISKORES_ASSERT(body.Ranges.InputBegin == 0 && body.Ranges.InputEnd == inputLength &&
379  body.Ranges.OutputBegin == 0 && body.Ranges.OutputEnd <= inputLength);
380 
381  return body.Ranges.OutputEnd;
382 }
383 
384 template <class InputPortalType, class T, class BinaryOperationType>
386 {
387  T Sum;
389  bool FirstCall;
390  InputPortalType InputPortal;
391  BinaryOperationType BinaryOperation;
392 
394  ReduceBody(const InputPortalType& inputPortal,
395  T initialValue,
396  BinaryOperationType binaryOperation)
397  : Sum(viskores::TypeTraits<T>::ZeroInitialization())
398  , InitialValue(initialValue)
399  , FirstCall(true)
400  , InputPortal(inputPortal)
401  , BinaryOperation(binaryOperation)
402  {
403  }
404 
405 
406  ReduceBody(const ReduceBody& body, ::tbb::split)
407  : Sum(viskores::TypeTraits<T>::ZeroInitialization())
408  , InitialValue(body.InitialValue)
409  , FirstCall(true)
410  , InputPortal(body.InputPortal)
412  {
413  }
414 
415 
416 
417  void operator()(const ::tbb::blocked_range<viskores::Id>& range)
418  {
420  InputIteratorsType inputIterators(this->InputPortal);
421 
422  //use temp, and iterators instead of member variable to reduce false sharing
423  typename InputIteratorsType::IteratorType inIter =
424  inputIterators.GetBegin() + static_cast<std::ptrdiff_t>(range.begin());
425 
426  T temp = this->BinaryOperation(*inIter, *(inIter + 1));
427  ++inIter;
428  ++inIter;
429  for (viskores::Id index = range.begin() + 2; index != range.end(); ++index, ++inIter)
430  {
431  temp = this->BinaryOperation(temp, *inIter);
432  }
433 
434  //determine if we also have to add the initial value to temp
435  if (range.begin() == 0)
436  {
437  temp = this->BinaryOperation(temp, this->InitialValue);
438  }
439 
440  //Now we can save temp back to sum, taking into account if
441  //this task has been called before, and the sum value needs
442  //to also be reduced.
443  if (this->FirstCall)
444  {
445  this->Sum = temp;
446  }
447  else
448  {
449  this->Sum = this->BinaryOperation(this->Sum, temp);
450  }
451 
452  this->FirstCall = false;
453  }
454 
455 
456 
457  void join(const ReduceBody& left)
458  {
459  // std::cout << "join" << std::endl;
460  this->Sum = this->BinaryOperation(left.Sum, this->Sum);
461  }
462 };
463 
464 
465 template <class InputPortalType, typename T, class BinaryOperationType>
466 VISKORES_CONT static auto ReducePortals(InputPortalType inputPortal,
467  T initialValue,
468  BinaryOperationType binaryOperation)
469  -> decltype(binaryOperation(initialValue, inputPortal.Get(0)))
470 {
471  using ResultType = decltype(binaryOperation(initialValue, inputPortal.Get(0)));
472  using WrappedBinaryOp = internal::WrappedBinaryOperator<ResultType, BinaryOperationType>;
473 
474  WrappedBinaryOp wrappedBinaryOp(binaryOperation);
475  ReduceBody<InputPortalType, ResultType, WrappedBinaryOp> body(
476  inputPortal, initialValue, wrappedBinaryOp);
477  viskores::Id arrayLength = inputPortal.GetNumberOfValues();
478 
479  if (arrayLength > 1)
480  {
481  ::tbb::blocked_range<viskores::Id> range(0, arrayLength, TBB_GRAIN_SIZE);
482  ::tbb::parallel_reduce(range, body);
483  return body.Sum;
484  }
485  else if (arrayLength == 1)
486  {
487  //ReduceBody does not work with an array of size 1.
488  return binaryOperation(initialValue, inputPortal.Get(0));
489  }
490  else // arrayLength == 0
491  {
492  // ReduceBody does not work with an array of size 0.
493  return static_cast<ResultType>(initialValue);
494  }
495 }
496 
497 // Define this to print out timing information from the reduction and join
498 // operations in the tbb ReduceByKey algorithm:
499 //#define VISKORES_DEBUG_TBB_RBK
500 
501 template <typename KeysInPortalType,
502  typename ValuesInPortalType,
503  typename KeysOutPortalType,
504  typename ValuesOutPortalType,
505  class BinaryOperationType>
507 {
508  using KeyType = typename KeysInPortalType::ValueType;
509  using ValueType = typename ValuesInPortalType::ValueType;
510 
511  struct Range
512  {
517 
518 
520  : InputBegin(-1)
521  , InputEnd(-1)
522  , OutputBegin(-1)
523  , OutputEnd(-1)
524  {
525  }
526 
527 
528  Range(viskores::Id inputBegin,
529  viskores::Id inputEnd,
530  viskores::Id outputBegin,
531  viskores::Id outputEnd)
532  : InputBegin(inputBegin)
533  , InputEnd(inputEnd)
534  , OutputBegin(outputBegin)
535  , OutputEnd(outputEnd)
536  {
537  this->AssertSane();
538  }
539 
540 
541  void AssertSane() const
542  {
543  VISKORES_ASSERT("Input begin precedes end" && this->InputBegin <= this->InputEnd);
544  VISKORES_ASSERT("Output begin precedes end" && this->OutputBegin <= this->OutputEnd);
545  VISKORES_ASSERT("Output not past input" && this->OutputBegin <= this->InputBegin &&
546  this->OutputEnd <= this->InputEnd);
547  VISKORES_ASSERT("Output smaller than input" &&
548  (this->OutputEnd - this->OutputBegin) <= (this->InputEnd - this->InputBegin));
549  }
550 
551 
552  bool IsNext(const Range& next) const { return this->InputEnd == next.InputBegin; }
553  };
554 
555  KeysInPortalType KeysInPortal;
556  ValuesInPortalType ValuesInPortal;
557  KeysOutPortalType KeysOutPortal;
558  ValuesOutPortalType ValuesOutPortal;
559  BinaryOperationType BinaryOperation;
561 #ifdef VISKORES_DEBUG_TBB_RBK
562  double ReduceTime;
563  double JoinTime;
564 #endif
565 
567  ReduceByKeyBody(const KeysInPortalType& keysInPortal,
568  const ValuesInPortalType& valuesInPortal,
569  const KeysOutPortalType& keysOutPortal,
570  const ValuesOutPortalType& valuesOutPortal,
571  BinaryOperationType binaryOperation)
572  : KeysInPortal(keysInPortal)
573  , ValuesInPortal(valuesInPortal)
574  , KeysOutPortal(keysOutPortal)
575  , ValuesOutPortal(valuesOutPortal)
576  , BinaryOperation(binaryOperation)
577 #ifdef VISKORES_DEBUG_TBB_RBK
578  , ReduceTime(0)
579  , JoinTime(0)
580 #endif
581  {
582  }
583 
584 
585  ReduceByKeyBody(const ReduceByKeyBody& body, ::tbb::split)
586  : KeysInPortal(body.KeysInPortal)
591 #ifdef VISKORES_DEBUG_TBB_RBK
592  , ReduceTime(0)
593  , JoinTime(0)
594 #endif
595  {
596  }
597 
598 
599 
600  void operator()(const ::tbb::blocked_range<viskores::Id>& range)
601  {
602 #ifdef VISKORES_DEBUG_TBB_RBK
603  ::tbb::tick_count startTime = ::tbb::tick_count::now();
604 #endif // VISKORES_DEBUG_TBB_RBK
605  if (range.empty())
606  {
607  return;
608  }
609 
610  bool firstRun = this->Ranges.OutputBegin < 0; // First use of this body object
611  if (firstRun)
612  {
613  this->Ranges.InputBegin = range.begin();
614  }
615  else
616  {
617  // Must be a continuation of the previous input range:
618  VISKORES_ASSERT(this->Ranges.InputEnd == range.begin());
619  }
620  this->Ranges.InputEnd = range.end();
621  this->Ranges.AssertSane();
622 
627 
628  KeysInIteratorsType keysInIters(this->KeysInPortal);
629  ValuesInIteratorsType valuesInIters(this->ValuesInPortal);
630  KeysOutIteratorsType keysOutIters(this->KeysOutPortal);
631  ValuesOutIteratorsType valuesOutIters(this->ValuesOutPortal);
632 
633  using KeysInIteratorType = typename KeysInIteratorsType::IteratorType;
634  using ValuesInIteratorType = typename ValuesInIteratorsType::IteratorType;
635  using KeysOutIteratorType = typename KeysOutIteratorsType::IteratorType;
636  using ValuesOutIteratorType = typename ValuesOutIteratorsType::IteratorType;
637 
638  KeysInIteratorType keysIn = keysInIters.GetBegin();
639  ValuesInIteratorType valuesIn = valuesInIters.GetBegin();
640  KeysOutIteratorType keysOut = keysOutIters.GetBegin();
641  ValuesOutIteratorType valuesOut = valuesOutIters.GetBegin();
642 
643  viskores::Id readPos = range.begin();
644  const viskores::Id readEnd = range.end();
645 
646  // Determine output index. If we're reusing the body, pick up where the
647  // last block left off. If not, use the input range.
648  viskores::Id writePos;
649  if (firstRun)
650  {
651  this->Ranges.OutputBegin = range.begin();
652  this->Ranges.OutputEnd = range.begin();
653  writePos = range.begin();
654  }
655  else
656  {
657  writePos = this->Ranges.OutputEnd;
658  }
659  this->Ranges.AssertSane();
660 
661  // We're either writing at the end of a previous block, or at the input
662  // location. Either way, the write position will never be greater than
663  // the read position.
664  VISKORES_ASSERT(writePos <= readPos);
665 
666  // Initialize reduction variables:
667  BinaryOperationType functor(this->BinaryOperation);
668  KeyType currentKey = keysIn[readPos];
669  ValueType currentValue = valuesIn[readPos];
670  ++readPos;
671 
672  // If the start of the current range continues a previous key block,
673  // initialize with the previous result and decrement the write index.
674  VISKORES_ASSERT(firstRun || writePos > 0);
675  if (!firstRun && keysOut[writePos - 1] == currentKey)
676  {
677  // Ensure that we'll overwrite the continued key values:
678  --writePos;
679 
680  // Update our accumulator with the partial value:
681  currentValue = functor(valuesOut[writePos], currentValue);
682  }
683 
684  // Special case: single value in range
685  if (readPos >= readEnd)
686  {
687  keysOut[writePos] = currentKey;
688  valuesOut[writePos] = currentValue;
689  ++writePos;
690 
691  this->Ranges.OutputEnd = writePos;
692  return;
693  }
694 
695  for (;;)
696  {
697  while (readPos < readEnd && currentKey == keysIn[readPos])
698  {
699  currentValue = functor(currentValue, valuesIn[readPos]);
700  ++readPos;
701  }
702 
703  VISKORES_ASSERT(writePos <= readPos);
704  keysOut[writePos] = currentKey;
705  valuesOut[writePos] = currentValue;
706  ++writePos;
707 
708  if (readPos < readEnd)
709  {
710  currentKey = keysIn[readPos];
711  currentValue = valuesIn[readPos];
712  ++readPos;
713  continue;
714  }
715 
716  break;
717  }
718 
719  this->Ranges.OutputEnd = writePos;
720 
721 #ifdef VISKORES_DEBUG_TBB_RBK
722  ::tbb::tick_count endTime = ::tbb::tick_count::now();
723  double time = (endTime - startTime).seconds();
724  this->ReduceTime += time;
725  std::ostringstream out;
726  out << "Reduced " << range.size() << " key/value pairs in " << time << "s. "
727  << "InRange: " << this->Ranges.InputBegin << " " << this->Ranges.InputEnd << " "
728  << "OutRange: " << this->Ranges.OutputBegin << " " << this->Ranges.OutputEnd << "\n";
729  std::cerr << out.str();
730 #endif
731  }
732 
733 
734 
735  void join(const ReduceByKeyBody& rhs)
736  {
739  using KeysIteratorType = typename KeysIteratorsType::IteratorType;
740  using ValuesIteratorType = typename ValuesIteratorsType::IteratorType;
741 
742 #ifdef VISKORES_DEBUG_TBB_RBK
743  ::tbb::tick_count startTime = ::tbb::tick_count::now();
744 #endif
745 
746  this->Ranges.AssertSane();
747  rhs.Ranges.AssertSane();
748  // Ensure that we're joining two consecutive subsets of the input:
749  VISKORES_ASSERT(this->Ranges.IsNext(rhs.Ranges));
750 
751  KeysIteratorsType keysIters(this->KeysOutPortal);
752  ValuesIteratorsType valuesIters(this->ValuesOutPortal);
753  KeysIteratorType keys = keysIters.GetBegin();
754  ValuesIteratorType values = valuesIters.GetBegin();
755 
756  const viskores::Id dstBegin = this->Ranges.OutputEnd;
757  const viskores::Id lastDstIdx = this->Ranges.OutputEnd - 1;
758 
759  viskores::Id srcBegin = rhs.Ranges.OutputBegin;
760  const viskores::Id srcEnd = rhs.Ranges.OutputEnd;
761 
762  // Merge boundaries if needed:
763  if (keys[srcBegin] == keys[lastDstIdx])
764  {
765  values[lastDstIdx] = this->BinaryOperation(values[lastDstIdx], values[srcBegin]);
766  ++srcBegin; // Don't copy the key/value we just reduced
767  }
768 
769  // move data:
770  if (srcBegin != dstBegin && srcBegin != srcEnd)
771  {
772  // Sanity check:
773  VISKORES_ASSERT(srcBegin < srcEnd);
774  std::copy(keys + srcBegin, keys + srcEnd, keys + dstBegin);
775  std::copy(values + srcBegin, values + srcEnd, values + dstBegin);
776  }
777 
778  this->Ranges.InputEnd = rhs.Ranges.InputEnd;
779  this->Ranges.OutputEnd += srcEnd - srcBegin;
780  this->Ranges.AssertSane();
781 
782 #ifdef VISKORES_DEBUG_TBB_RBK
783  ::tbb::tick_count endTime = ::tbb::tick_count::now();
784  double time = (endTime - startTime).seconds();
785  this->JoinTime += rhs.JoinTime + time;
786  std::ostringstream out;
787  out << "Joined " << (srcEnd - srcBegin) << " rhs values into body in " << time << "s. "
788  << "InRange: " << this->Ranges.InputBegin << " " << this->Ranges.InputEnd << " "
789  << "OutRange: " << this->Ranges.OutputBegin << " " << this->Ranges.OutputEnd << "\n";
790  std::cerr << out.str();
791 #endif
792  }
793 };
794 
795 
796 template <typename KeysInPortalType,
797  typename ValuesInPortalType,
798  typename KeysOutPortalType,
799  typename ValuesOutPortalType,
800  typename BinaryOperationType>
801 VISKORES_CONT viskores::Id ReduceByKeyPortals(KeysInPortalType keysInPortal,
802  ValuesInPortalType valuesInPortal,
803  KeysOutPortalType keysOutPortal,
804  ValuesOutPortalType valuesOutPortal,
805  BinaryOperationType binaryOperation)
806 {
807  const viskores::Id inputLength = keysInPortal.GetNumberOfValues();
808  VISKORES_ASSERT(inputLength == valuesInPortal.GetNumberOfValues());
809 
810  if (inputLength == 0)
811  {
812  return 0;
813  }
814 
815  using ValueType = typename ValuesInPortalType::ValueType;
816  using WrappedBinaryOp = internal::WrappedBinaryOperator<ValueType, BinaryOperationType>;
817  WrappedBinaryOp wrappedBinaryOp(binaryOperation);
818 
819  ReduceByKeyBody<KeysInPortalType,
820  ValuesInPortalType,
821  KeysOutPortalType,
822  ValuesOutPortalType,
823  WrappedBinaryOp>
824  body(keysInPortal, valuesInPortal, keysOutPortal, valuesOutPortal, wrappedBinaryOp);
825  ::tbb::blocked_range<viskores::Id> range(0, inputLength, TBB_GRAIN_SIZE);
826 
827 #ifdef VISKORES_DEBUG_TBB_RBK
828  std::cerr << "\n\nTBB ReduceByKey:\n";
829 #endif
830 
831  ::tbb::parallel_reduce(range, body);
832 
833 #ifdef VISKORES_DEBUG_TBB_RBK
834  std::cerr << "Total reduce time: " << body.ReduceTime << "s\n";
835  std::cerr << "Total join time: " << body.JoinTime << "s\n";
836  std::cerr << "\nend\n";
837 #endif
838 
839  body.Ranges.AssertSane();
840  VISKORES_ASSERT(body.Ranges.InputBegin == 0 && body.Ranges.InputEnd == inputLength &&
841  body.Ranges.OutputBegin == 0 && body.Ranges.OutputEnd <= inputLength);
842 
843  return body.Ranges.OutputEnd;
844 }
845 
846 #ifdef VISKORES_DEBUG_TBB_RBK
847 #undef VISKORES_DEBUG_TBB_RBK
848 #endif
849 
850 template <class InputPortalType, class OutputPortalType, class BinaryOperationType>
852 {
853  using ValueType = typename std::remove_reference<typename OutputPortalType::ValueType>::type;
855  bool FirstCall;
856  InputPortalType InputPortal;
857  OutputPortalType OutputPortal;
858  BinaryOperationType BinaryOperation;
859 
861  ScanInclusiveBody(const InputPortalType& inputPortal,
862  const OutputPortalType& outputPortal,
863  BinaryOperationType binaryOperation)
864  : Sum(viskores::TypeTraits<ValueType>::ZeroInitialization())
865  , FirstCall(true)
866  , InputPortal(inputPortal)
867  , OutputPortal(outputPortal)
868  , BinaryOperation(binaryOperation)
869  {
870  }
871 
872 
873  ScanInclusiveBody(const ScanInclusiveBody& body, ::tbb::split)
874  : Sum(viskores::TypeTraits<ValueType>::ZeroInitialization())
875  , FirstCall(true)
876  , InputPortal(body.InputPortal)
877  , OutputPortal(body.OutputPortal)
879  {
880  }
881 
882 
883 
884  void operator()(const ::tbb::blocked_range<viskores::Id>& range, ::tbb::pre_scan_tag)
885  {
887  InputIteratorsType inputIterators(this->InputPortal);
888 
889  //use temp, and iterators instead of member variable to reduce false sharing
890  typename InputIteratorsType::IteratorType inIter =
891  inputIterators.GetBegin() + static_cast<std::ptrdiff_t>(range.begin());
892  ValueType temp = this->FirstCall ? *inIter++ : this->BinaryOperation(this->Sum, *inIter++);
893  this->FirstCall = false;
894  for (viskores::Id index = range.begin() + 1; index != range.end(); ++index, ++inIter)
895  {
896  temp = this->BinaryOperation(temp, *inIter);
897  }
898  this->Sum = temp;
899  }
900 
901 
902 
903  void operator()(const ::tbb::blocked_range<viskores::Id>& range, ::tbb::final_scan_tag)
904  {
907 
908  InputIteratorsType inputIterators(this->InputPortal);
909  OutputIteratorsType outputIterators(this->OutputPortal);
910 
911  //use temp, and iterators instead of member variable to reduce false sharing
912  typename InputIteratorsType::IteratorType inIter =
913  inputIterators.GetBegin() + static_cast<std::ptrdiff_t>(range.begin());
914  typename OutputIteratorsType::IteratorType outIter =
915  outputIterators.GetBegin() + static_cast<std::ptrdiff_t>(range.begin());
916  ValueType temp = this->FirstCall ? *inIter++ : this->BinaryOperation(this->Sum, *inIter++);
917  this->FirstCall = false;
918  *outIter++ = temp;
919  for (viskores::Id index = range.begin() + 1; index != range.end(); ++index, ++inIter, ++outIter)
920  {
921  *outIter = temp = this->BinaryOperation(temp, *inIter);
922  }
923  this->Sum = temp;
924  }
925 
926 
927 
928  void reverse_join(const ScanInclusiveBody& left)
929  {
930  this->Sum = this->BinaryOperation(left.Sum, this->Sum);
931  }
932 
933 
934 
935  void assign(const ScanInclusiveBody& src) { this->Sum = src.Sum; }
936 };
937 
938 template <class InputPortalType, class OutputPortalType, class BinaryOperationType>
940 {
941  using ValueType = typename std::remove_reference<typename OutputPortalType::ValueType>::type;
942 
944  bool FirstCall;
945  InputPortalType InputPortal;
946  OutputPortalType OutputPortal;
947  BinaryOperationType BinaryOperation;
948 
950  ScanExclusiveBody(const InputPortalType& inputPortal,
951  const OutputPortalType& outputPortal,
952  BinaryOperationType binaryOperation,
953  const ValueType& initialValue)
954  : Sum(initialValue)
955  , FirstCall(true)
956  , InputPortal(inputPortal)
957  , OutputPortal(outputPortal)
958  , BinaryOperation(binaryOperation)
959  {
960  }
961 
962 
963  ScanExclusiveBody(const ScanExclusiveBody& body, ::tbb::split)
964  : Sum(body.Sum)
965  , FirstCall(true)
966  , InputPortal(body.InputPortal)
967  , OutputPortal(body.OutputPortal)
969  {
970  }
971 
972 
973 
974  void operator()(const ::tbb::blocked_range<viskores::Id>& range, ::tbb::pre_scan_tag)
975  {
977  InputIteratorsType inputIterators(this->InputPortal);
978 
979  //move the iterator to the first item
980  typename InputIteratorsType::IteratorType iter =
981  inputIterators.GetBegin() + static_cast<std::ptrdiff_t>(range.begin());
982 
983  ValueType temp = *iter;
984  ++iter;
985  if (!(this->FirstCall && range.begin() > 0))
986  {
987  temp = this->BinaryOperation(this->Sum, temp);
988  }
989  for (viskores::Id index = range.begin() + 1; index != range.end(); ++index, ++iter)
990  {
991  temp = this->BinaryOperation(temp, *iter);
992  }
993  this->Sum = temp;
994  this->FirstCall = false;
995  }
996 
997 
998 
999  void operator()(const ::tbb::blocked_range<viskores::Id>& range, ::tbb::final_scan_tag)
1000  {
1003 
1004  InputIteratorsType inputIterators(this->InputPortal);
1005  OutputIteratorsType outputIterators(this->OutputPortal);
1006 
1007  //move the iterators to the first item
1008  typename InputIteratorsType::IteratorType inIter =
1009  inputIterators.GetBegin() + static_cast<std::ptrdiff_t>(range.begin());
1010  typename OutputIteratorsType::IteratorType outIter =
1011  outputIterators.GetBegin() + static_cast<std::ptrdiff_t>(range.begin());
1012 
1013  ValueType temp = this->Sum;
1014  for (viskores::Id index = range.begin(); index != range.end(); ++index, ++inIter, ++outIter)
1015  {
1016  //copy into a local reference since Input and Output portal
1017  //could point to the same memory location
1018  ValueType v = *inIter;
1019  *outIter = temp;
1020  temp = this->BinaryOperation(temp, v);
1021  }
1022  this->Sum = temp;
1023  this->FirstCall = false;
1024  }
1025 
1026 
1027 
1029  {
1030  //The contract we have with TBB is that they will only join
1031  //two objects that have been scanned, or two objects which
1032  //haven't been scanned
1033  VISKORES_ASSERT(left.FirstCall == this->FirstCall);
1034  if (!left.FirstCall && !this->FirstCall)
1035  {
1036  this->Sum = this->BinaryOperation(left.Sum, this->Sum);
1037  }
1038  }
1039 
1040 
1041 
1042  void assign(const ScanExclusiveBody& src) { this->Sum = src.Sum; }
1043 };
1044 
1045 
1046 template <class InputPortalType, class OutputPortalType, class BinaryOperationType>
1047 VISKORES_CONT static typename std::remove_reference<typename OutputPortalType::ValueType>::type
1048 ScanInclusivePortals(InputPortalType inputPortal,
1049  OutputPortalType outputPortal,
1050  BinaryOperationType binaryOperation)
1051 {
1052  using ValueType = typename std::remove_reference<typename OutputPortalType::ValueType>::type;
1053 
1054  using WrappedBinaryOp = internal::WrappedBinaryOperator<ValueType, BinaryOperationType>;
1055 
1056  WrappedBinaryOp wrappedBinaryOp(binaryOperation);
1057  ScanInclusiveBody<InputPortalType, OutputPortalType, WrappedBinaryOp> body(
1058  inputPortal, outputPortal, wrappedBinaryOp);
1059  viskores::Id arrayLength = inputPortal.GetNumberOfValues();
1060 
1061  ::tbb::blocked_range<viskores::Id> range(0, arrayLength, TBB_GRAIN_SIZE);
1062  ::tbb::parallel_scan(range, body);
1063  return body.Sum;
1064 }
1065 
1066 
1067 template <class InputPortalType, class OutputPortalType, class BinaryOperationType>
1068 VISKORES_CONT static typename std::remove_reference<typename OutputPortalType::ValueType>::type
1069 ScanExclusivePortals(
1070  InputPortalType inputPortal,
1071  OutputPortalType outputPortal,
1072  BinaryOperationType binaryOperation,
1073  typename std::remove_reference<typename OutputPortalType::ValueType>::type initialValue)
1074 {
1075  using ValueType = typename std::remove_reference<typename OutputPortalType::ValueType>::type;
1076 
1077  using WrappedBinaryOp = internal::WrappedBinaryOperator<ValueType, BinaryOperationType>;
1078 
1079  WrappedBinaryOp wrappedBinaryOp(binaryOperation);
1080  ScanExclusiveBody<InputPortalType, OutputPortalType, WrappedBinaryOp> body(
1081  inputPortal, outputPortal, wrappedBinaryOp, initialValue);
1082  viskores::Id arrayLength = inputPortal.GetNumberOfValues();
1083 
1084  ::tbb::blocked_range<viskores::Id> range(0, arrayLength, TBB_GRAIN_SIZE);
1085  ::tbb::parallel_scan(range, body);
1086 
1087  // Seems a little weird to me that we would return the last value in the
1088  // array rather than the sum, but that is how the function is specified.
1089  return body.Sum;
1090 }
1091 
1092 template <typename InputPortalType, typename IndexPortalType, typename OutputPortalType>
1094 {
1095 public:
1096  VISKORES_CONT ScatterKernel(InputPortalType inputPortal,
1097  IndexPortalType indexPortal,
1098  OutputPortalType outputPortal)
1099  : ValuesPortal(inputPortal)
1100  , IndexPortal(indexPortal)
1101  , OutputPortal(outputPortal)
1102  {
1103  }
1104 
1106  void operator()(const ::tbb::blocked_range<viskores::Id>& range) const
1107  {
1108  // The TBB device adapter causes array classes to be shared between
1109  // control and execution environment. This means that it is possible for
1110  // an exception to be thrown even though this is typically not allowed.
1111  // Throwing an exception from here is bad because there are several
1112  // simultaneous threads running. Get around the problem by catching the
1113  // error and setting the message buffer as expected.
1114  try
1115  {
1117  for (viskores::Id i = range.begin(); i < range.end(); i++)
1118  {
1120  OutputPortal.Set(i, ValuesPortal.Get(IndexPortal.Get(i)));
1121  }
1122  }
1123  catch (viskores::cont::Error& error)
1124  {
1125  this->ErrorMessage.RaiseError(error.GetMessage().c_str());
1126  }
1127  catch (...)
1128  {
1129  this->ErrorMessage.RaiseError("Unexpected error in execution environment.");
1130  }
1131  }
1132 
1133 private:
1134  InputPortalType ValuesPortal;
1135  IndexPortalType IndexPortal;
1136  OutputPortalType OutputPortal;
1137  viskores::exec::internal::ErrorMessageBuffer ErrorMessage;
1138 };
1139 
1140 
1141 template <typename InputPortalType, typename IndexPortalType, typename OutputPortalType>
1142 VISKORES_CONT static void ScatterPortal(InputPortalType inputPortal,
1143  IndexPortalType indexPortal,
1144  OutputPortalType outputPortal)
1145 {
1146  const viskores::Id size = inputPortal.GetNumberOfValues();
1147  VISKORES_ASSERT(size == indexPortal.GetNumberOfValues());
1148 
1150  inputPortal, indexPortal, outputPortal);
1151 
1152  ::tbb::blocked_range<viskores::Id> range(0, size, TBB_GRAIN_SIZE);
1153  ::tbb::parallel_for(range, scatter);
1154 }
1155 
1156 template <typename PortalType, typename BinaryOperationType>
1158 {
1159  using ValueType = typename PortalType::ValueType;
1160 
1161  struct Range
1162  {
1167 
1168 
1169 
1171  : InputBegin(-1)
1172  , InputEnd(-1)
1173  , OutputBegin(-1)
1174  , OutputEnd(-1)
1175  {
1176  }
1177 
1178 
1179 
1180  Range(viskores::Id inputBegin,
1181  viskores::Id inputEnd,
1182  viskores::Id outputBegin,
1183  viskores::Id outputEnd)
1184  : InputBegin(inputBegin)
1185  , InputEnd(inputEnd)
1186  , OutputBegin(outputBegin)
1187  , OutputEnd(outputEnd)
1188  {
1189  this->AssertSane();
1190  }
1191 
1192 
1193 
1194  void AssertSane() const
1195  {
1196  VISKORES_ASSERT("Input begin precedes end" && this->InputBegin <= this->InputEnd);
1197  VISKORES_ASSERT("Output begin precedes end" && this->OutputBegin <= this->OutputEnd);
1198  VISKORES_ASSERT("Output not past input" && this->OutputBegin <= this->InputBegin &&
1199  this->OutputEnd <= this->InputEnd);
1200  VISKORES_ASSERT("Output smaller than input" &&
1201  (this->OutputEnd - this->OutputBegin) <= (this->InputEnd - this->InputBegin));
1202  }
1203 
1204 
1205 
1206  bool IsNext(const Range& next) const { return this->InputEnd == next.InputBegin; }
1207  };
1208 
1209  PortalType Portal;
1210  BinaryOperationType BinaryOperation;
1212 
1214  UniqueBody(const PortalType& portal, BinaryOperationType binaryOperation)
1215  : Portal(portal)
1216  , BinaryOperation(binaryOperation)
1217  {
1218  }
1219 
1221  UniqueBody(const UniqueBody& body, ::tbb::split)
1222  : Portal(body.Portal)
1224  {
1225  }
1226 
1227 
1228 
1229  void operator()(const ::tbb::blocked_range<viskores::Id>& range)
1230  {
1231  if (range.empty())
1232  {
1233  return;
1234  }
1235 
1236  bool firstRun = this->Ranges.OutputBegin < 0; // First use of this body object
1237  if (firstRun)
1238  {
1239  this->Ranges.InputBegin = range.begin();
1240  }
1241  else
1242  {
1243  // Must be a continuation of the previous input range:
1244  VISKORES_ASSERT(this->Ranges.InputEnd == range.begin());
1245  }
1246  this->Ranges.InputEnd = range.end();
1247  this->Ranges.AssertSane();
1248 
1250  using IteratorType = typename IteratorsType::IteratorType;
1251 
1252  IteratorsType iters(this->Portal);
1253  IteratorType data = iters.GetBegin();
1254 
1255  viskores::Id readPos = range.begin();
1256  const viskores::Id readEnd = range.end();
1257 
1258  // Determine output index. If we're reusing the body, pick up where the
1259  // last block left off. If not, use the input range.
1260  viskores::Id writePos;
1261  if (firstRun)
1262  {
1263  this->Ranges.OutputBegin = range.begin();
1264  this->Ranges.OutputEnd = range.begin();
1265  writePos = range.begin();
1266  }
1267  else
1268  {
1269  writePos = this->Ranges.OutputEnd;
1270  }
1271  this->Ranges.AssertSane();
1272 
1273  // We're either writing at the end of a previous block, or at the input
1274  // location. Either way, the write position will never be greater than
1275  // the read position.
1276  VISKORES_ASSERT(writePos <= readPos);
1277 
1278  // Initialize loop variables:
1279  BinaryOperationType functor(this->BinaryOperation);
1280  ValueType current = data[readPos];
1281  ++readPos;
1282 
1283  // If the start of the current range continues a previous block of
1284  // identical elements, initialize with the previous result and decrement
1285  // the write index.
1286  VISKORES_ASSERT(firstRun || writePos > 0);
1287  if (!firstRun && functor(data[writePos - 1], current))
1288  {
1289  // Ensure that we'll overwrite the duplicate value:
1290  --writePos;
1291 
1292  // Copy the last data value into current. TestingDeviceAdapter's test
1293  // using the FuseAll functor requires that the first value in a set of
1294  // duplicates must be used, and this ensures that condition is met.
1295  current = data[writePos];
1296  }
1297 
1298  // Special case: single value in range
1299  if (readPos >= readEnd)
1300  {
1301  data[writePos] = current;
1302  ++writePos;
1303 
1304  this->Ranges.OutputEnd = writePos;
1305  return;
1306  }
1307 
1308  for (;;)
1309  {
1310  // Advance readPos until the value changes
1311  while (readPos < readEnd && functor(current, data[readPos]))
1312  {
1313  ++readPos;
1314  }
1315 
1316  // Write out the unique value
1317  VISKORES_ASSERT(writePos <= readPos);
1318  data[writePos] = current;
1319  ++writePos;
1320 
1321  // Update the current value if there are more entries
1322  if (readPos < readEnd)
1323  {
1324  current = data[readPos];
1325  ++readPos;
1326  continue;
1327  }
1328 
1329  // Input range is exhausted if we reach this point.
1330  break;
1331  }
1332 
1333  this->Ranges.OutputEnd = writePos;
1334  }
1335 
1336 
1337 
1338  void join(const UniqueBody& rhs)
1339  {
1341  using IteratorType = typename IteratorsType::IteratorType;
1342 
1343  this->Ranges.AssertSane();
1344  rhs.Ranges.AssertSane();
1345 
1346  // Ensure that we're joining two consecutive subsets of the input:
1347  VISKORES_ASSERT(this->Ranges.IsNext(rhs.Ranges));
1348 
1349  IteratorsType iters(this->Portal);
1350  IteratorType data = iters.GetBegin();
1351  BinaryOperationType functor(this->BinaryOperation);
1352 
1353  const viskores::Id dstBegin = this->Ranges.OutputEnd;
1354  const viskores::Id lastDstIdx = this->Ranges.OutputEnd - 1;
1355 
1356  viskores::Id srcBegin = rhs.Ranges.OutputBegin;
1357  const viskores::Id srcEnd = rhs.Ranges.OutputEnd;
1358 
1359  // Merge boundaries if needed:
1360  if (functor(data[srcBegin], data[lastDstIdx]))
1361  {
1362  ++srcBegin; // Don't copy the duplicate value
1363  }
1364 
1365  // move data:
1366  if (srcBegin != dstBegin && srcBegin != srcEnd)
1367  {
1368  // Sanity check:
1369  VISKORES_ASSERT(srcBegin < srcEnd);
1370  std::copy(data + srcBegin, data + srcEnd, data + dstBegin);
1371  }
1372 
1373  this->Ranges.InputEnd = rhs.Ranges.InputEnd;
1374  this->Ranges.OutputEnd += srcEnd - srcBegin;
1375  this->Ranges.AssertSane();
1376  }
1377 };
1378 
1379 
1380 template <typename PortalType, typename BinaryOperationType>
1381 VISKORES_CONT viskores::Id UniquePortals(PortalType portal, BinaryOperationType binaryOperation)
1382 {
1383  const viskores::Id inputLength = portal.GetNumberOfValues();
1384  if (inputLength == 0)
1385  {
1386  return 0;
1387  }
1388 
1389  using WrappedBinaryOp = internal::WrappedBinaryOperator<bool, BinaryOperationType>;
1390  WrappedBinaryOp wrappedBinaryOp(binaryOperation);
1391 
1392  UniqueBody<PortalType, WrappedBinaryOp> body(portal, wrappedBinaryOp);
1393  ::tbb::blocked_range<viskores::Id> range(0, inputLength, TBB_GRAIN_SIZE);
1394 
1395  ::tbb::parallel_reduce(range, body);
1396 
1397  body.Ranges.AssertSane();
1398  VISKORES_ASSERT(body.Ranges.InputBegin == 0 && body.Ranges.InputEnd == inputLength &&
1399  body.Ranges.OutputBegin == 0 && body.Ranges.OutputEnd <= inputLength);
1400 
1401  return body.Ranges.OutputEnd;
1402 }
1403 }
1404 }
1405 }
1406 #endif //viskores_cont_tbb_internal_FunctorsTBB_h
viskores::cont::tbb::ScanExclusiveBody::InputPortal
InputPortalType InputPortal
Definition: FunctorsTBB.h:945
viskores::cont::tbb::ScatterKernel::IndexPortal
IndexPortalType IndexPortal
Definition: FunctorsTBB.h:1135
viskores::cont::tbb::CopyIfPortals
viskores::Id CopyIfPortals(InputPortalType inputPortal, StencilPortalType stencilPortal, OutputPortalType outputPortal, UnaryPredicateType unaryPredicate)
Definition: FunctorsTBB.h:358
viskores::cont::tbb::ScanInclusiveBody::assign
void assign(const ScanInclusiveBody &src)
Definition: FunctorsTBB.h:935
FunctorsGeneral.h
viskores::cont::tbb::ScanExclusiveBody
Definition: FunctorsTBB.h:939
viskores::cont::tbb::ReduceBody::operator()
void operator()(const ::tbb::blocked_range< viskores::Id > &range)
Definition: FunctorsTBB.h:417
viskores::cont::tbb::ScanExclusiveBody::Sum
ValueType Sum
Definition: FunctorsTBB.h:943
viskores::cont::tbb::ReduceBody::InitialValue
T InitialValue
Definition: FunctorsTBB.h:388
viskores::cont::tbb::CopyBody::DoCopy
void DoCopy(InIter src, InIter srcEnd, OutIter dst, std::true_type) const
Definition: FunctorsTBB.h:126
viskores::cont::tbb::ReduceByKeyBody::Range::InputEnd
viskores::Id InputEnd
Definition: FunctorsTBB.h:514
viskores::cont::tbb::ScanInclusiveBody::ScanInclusiveBody
ScanInclusiveBody(const ScanInclusiveBody &body, ::tbb::split)
Definition: FunctorsTBB.h:873
viskores::cont::tbb::CopyIfBody::Range::Range
Range(viskores::Id inputBegin, viskores::Id inputEnd, viskores::Id outputBegin, viskores::Id outputEnd)
Definition: FunctorsTBB.h:192
viskores::cont::tbb::CopyBody::operator()
void operator()(const ::tbb::blocked_range< viskores::Id > &range) const
Definition: FunctorsTBB.h:133
Types.h
viskores::cont::tbb::ReduceByKeyBody::ValuesOutPortal
ValuesOutPortalType ValuesOutPortal
Definition: FunctorsTBB.h:558
viskores::cont::tbb::UniqueBody::UniqueBody
UniqueBody(const UniqueBody &body, ::tbb::split)
Definition: FunctorsTBB.h:1221
viskores::cont::tbb::CopyIfBody::Range
Definition: FunctorsTBB.h:175
viskores::cont::tbb::ReduceByKeyBody::Range
Definition: FunctorsTBB.h:511
viskores::cont::tbb::UniqueBody::Range::Range
Range()
Definition: FunctorsTBB.h:1170
viskores::cont::tbb::CopyBody::OutputOffset
viskores::Id OutputOffset
Definition: FunctorsTBB.h:89
viskores::cont::tbb::ReduceByKeyBody::ValuesInPortal
ValuesInPortalType ValuesInPortal
Definition: FunctorsTBB.h:556
VISKORES_THIRDPARTY_POST_INCLUDE
#define VISKORES_THIRDPARTY_POST_INCLUDE
Definition: Configure.h:200
viskores::cont::tbb::CopyIfBody::Range::OutputBegin
viskores::Id OutputBegin
Definition: FunctorsTBB.h:179
ArrayPortalToIterators.h
viskores::cont::tbb::ScanInclusiveBody::OutputPortal
OutputPortalType OutputPortal
Definition: FunctorsTBB.h:857
viskores::cont::tbb::UniqueBody::ValueType
typename PortalType::ValueType ValueType
Definition: FunctorsTBB.h:1159
viskores::cont::tbb::ScanInclusiveBody::operator()
void operator()(const ::tbb::blocked_range< viskores::Id > &range, ::tbb::final_scan_tag)
Definition: FunctorsTBB.h:903
viskores::cont::tbb::ScanExclusiveBody::BinaryOperation
BinaryOperationType BinaryOperation
Definition: FunctorsTBB.h:947
viskores::cont::tbb::ScanExclusiveBody::FirstCall
bool FirstCall
Definition: FunctorsTBB.h:944
viskores::cont::tbb::CopyIfBody::Range::OutputEnd
viskores::Id OutputEnd
Definition: FunctorsTBB.h:180
viskores::cont::tbb::ReduceByKeyBody::Range::IsNext
bool IsNext(const Range &next) const
Definition: FunctorsTBB.h:552
viskores::cont::tbb::UniqueBody::join
void join(const UniqueBody &rhs)
Definition: FunctorsTBB.h:1338
viskores::cont::tbb::ScanInclusiveBody::Sum
ValueType Sum
Definition: FunctorsTBB.h:854
viskores::cont::tbb::ScanExclusiveBody::operator()
void operator()(const ::tbb::blocked_range< viskores::Id > &range, ::tbb::pre_scan_tag)
Definition: FunctorsTBB.h:974
viskores::cont::tbb::CopyIfBody::operator()
void operator()(const ::tbb::blocked_range< viskores::Id > &range)
Definition: FunctorsTBB.h:248
VISKORES_VECTORIZATION_IN_LOOP
#define VISKORES_VECTORIZATION_IN_LOOP
Definition: Configure.h:284
viskores::cont::tbb::ScanExclusiveBody::ValueType
typename std::remove_reference< typename OutputPortalType::ValueType >::type ValueType
Definition: FunctorsTBB.h:941
viskores::cont::tbb::CopyIfBody::StencilPortal
StencilPortalType StencilPortal
Definition: FunctorsTBB.h:220
viskores::cont::tbb::CopyIfBody::StencilType
typename StencilPortalType::ValueType StencilType
Definition: FunctorsTBB.h:173
viskores::cont::tbb::UniqueBody::Range
Definition: FunctorsTBB.h:1161
viskores::cont::tbb::ReduceBody::join
void join(const ReduceBody &left)
Definition: FunctorsTBB.h:457
viskores::cont::tbb::CopyBody::CopyBody
CopyBody(const InputPortalType &inPortal, const OutputPortalType &outPortal, viskores::Id inOffset, viskores::Id outOffset)
Definition: FunctorsTBB.h:91
viskores::cont::tbb::ReduceBody
Definition: FunctorsTBB.h:385
viskores::cont::tbb::UniqueBody::Range::IsNext
bool IsNext(const Range &next) const
Definition: FunctorsTBB.h:1206
viskores::cont::tbb::ReduceByKeyBody::Range::OutputEnd
viskores::Id OutputEnd
Definition: FunctorsTBB.h:516
viskores::cont::tbb::ScatterKernel::operator()
void operator()(const ::tbb::blocked_range< viskores::Id > &range) const
Definition: FunctorsTBB.h:1106
viskores::cont::tbb::CopyIfBody::InputPortal
InputPortalType InputPortal
Definition: FunctorsTBB.h:219
viskores::cont::tbb::ScanInclusiveBody::ScanInclusiveBody
ScanInclusiveBody(const InputPortalType &inputPortal, const OutputPortalType &outputPortal, BinaryOperationType binaryOperation)
Definition: FunctorsTBB.h:861
viskores::cont::tbb::UniqueBody::BinaryOperation
BinaryOperationType BinaryOperation
Definition: FunctorsTBB.h:1210
viskores::cont::tbb::ReduceByKeyBody::KeyType
typename KeysInPortalType::ValueType KeyType
Definition: FunctorsTBB.h:508
viskores::cont::tbb::ReduceByKeyBody::BinaryOperation
BinaryOperationType BinaryOperation
Definition: FunctorsTBB.h:559
viskores::cont::tbb::ReduceByKeyBody::ReduceByKeyBody
ReduceByKeyBody(const ReduceByKeyBody &body, ::tbb::split)
Definition: FunctorsTBB.h:585
viskores::cont::tbb::ReduceByKeyBody::Range::AssertSane
void AssertSane() const
Definition: FunctorsTBB.h:541
viskores::cont::tbb::UniqueBody::UniqueBody
UniqueBody(const PortalType &portal, BinaryOperationType binaryOperation)
Definition: FunctorsTBB.h:1214
TypeTraits.h
viskores::cont::tbb::UniqueBody::Range::AssertSane
void AssertSane() const
Definition: FunctorsTBB.h:1194
viskores::cont::tbb::UniqueBody::Range::OutputEnd
viskores::Id OutputEnd
Definition: FunctorsTBB.h:1166
viskores::cont::tbb::UniqueBody::Range::Range
Range(viskores::Id inputBegin, viskores::Id inputEnd, viskores::Id outputBegin, viskores::Id outputEnd)
Definition: FunctorsTBB.h:1180
viskores::TypeTraits
The TypeTraits class provides helpful compile-time information about the basic types used in Viskores...
Definition: TypeTraits.h:69
viskores::cont::Error::GetMessage
const std::string & GetMessage() const
Returns a message describing what caused the error.
Definition: Error.h:47
viskores::Id
viskores::Int64 Id
Base type to use to index arrays.
Definition: Types.h:235
viskores::cont::tbb::CopyIfBody::Range::Range
Range()
Definition: FunctorsTBB.h:183
viskores::cont::tbb::CopyIfBody
Definition: FunctorsTBB.h:170
VISKORES_CONT
#define VISKORES_CONT
Definition: ExportMacros.h:65
viskores::cont::tbb::UniqueBody::operator()
void operator()(const ::tbb::blocked_range< viskores::Id > &range)
Definition: FunctorsTBB.h:1229
viskores::cont::tbb::ReduceBody::Sum
T Sum
Definition: FunctorsTBB.h:387
viskores::cont::tbb::CopyIfBody::ValueType
typename InputPortalType::ValueType ValueType
Definition: FunctorsTBB.h:172
viskores
Groups connected points that have the same field value.
Definition: Atomic.h:27
viskores::cont::tbb::CopyIfBody::Ranges
Range Ranges
Definition: FunctorsTBB.h:223
viskores::cont::tbb::CopyPortals
void CopyPortals(const InputPortalType &inPortal, const OutputPortalType &outPortal, viskores::Id inOffset, viskores::Id outOffset, viskores::Id numValues)
Definition: FunctorsTBB.h:154
viskores::cont::tbb::UniqueBody
Definition: FunctorsTBB.h:1157
viskores::cont::tbb::CopyIfBody::Range::InputEnd
viskores::Id InputEnd
Definition: FunctorsTBB.h:178
viskores::cont::tbb::CopyBody
Definition: FunctorsTBB.h:84
ErrorMessageBuffer.h
viskores::cont::tbb::ReduceByKeyBody::join
void join(const ReduceByKeyBody &rhs)
Definition: FunctorsTBB.h:735
viskores::cont::ArrayPortalToIteratorBegin
viskores::cont::ArrayPortalToIterators< PortalType >::IteratorType ArrayPortalToIteratorBegin(const PortalType &portal)
Convenience function for converting an ArrayPortal to a begin iterator.
Definition: ArrayPortalToIterators.h:189
Error.h
viskores::cont::tbb::ScanInclusiveBody::InputPortal
InputPortalType InputPortal
Definition: FunctorsTBB.h:856
viskores::cont::tbb::ReduceBody::BinaryOperation
BinaryOperationType BinaryOperation
Definition: FunctorsTBB.h:391
viskores::cont::tbb::UniqueBody::Range::InputEnd
viskores::Id InputEnd
Definition: FunctorsTBB.h:1164
viskores::cont::tbb::ScanExclusiveBody::OutputPortal
OutputPortalType OutputPortal
Definition: FunctorsTBB.h:946
viskores::cont::tbb::ScanExclusiveBody::reverse_join
void reverse_join(const ScanExclusiveBody &left)
Definition: FunctorsTBB.h:1028
viskores::cont::tbb::CopyBody::InputPortal
InputPortalType InputPortal
Definition: FunctorsTBB.h:86
viskores::cont::tbb::ScanExclusiveBody::ScanExclusiveBody
ScanExclusiveBody(const ScanExclusiveBody &body, ::tbb::split)
Definition: FunctorsTBB.h:963
viskores::cont::tbb::ScatterKernel::ValuesPortal
InputPortalType ValuesPortal
Definition: FunctorsTBB.h:1134
viskores::cont::tbb::ReduceByKeyBody::Range::Range
Range(viskores::Id inputBegin, viskores::Id inputEnd, viskores::Id outputBegin, viskores::Id outputEnd)
Definition: FunctorsTBB.h:528
viskores::cont::tbb::ScatterKernel::OutputPortal
OutputPortalType OutputPortal
Definition: FunctorsTBB.h:1136
viskores::cont::tbb::UniqueBody::Range::OutputBegin
viskores::Id OutputBegin
Definition: FunctorsTBB.h:1165
viskores::cont::tbb::ReduceByKeyBody::KeysInPortal
KeysInPortalType KeysInPortal
Definition: FunctorsTBB.h:555
viskores::cont::tbb::CopyIfBody::join
void join(const CopyIfBody &rhs)
Definition: FunctorsTBB.h:322
viskores::cont::tbb::ScanExclusiveBody::ScanExclusiveBody
ScanExclusiveBody(const InputPortalType &inputPortal, const OutputPortalType &outputPortal, BinaryOperationType binaryOperation, const ValueType &initialValue)
Definition: FunctorsTBB.h:950
VISKORES_ASSERT
#define VISKORES_ASSERT(condition)
Definition: Assert.h:51
viskores::cont::tbb::UniqueBody::Ranges
Range Ranges
Definition: FunctorsTBB.h:1211
viskores::cont::ArrayPortalToIterators
Definition: ArrayPortalToIterators.h:35
viskores::cont::tbb::ScanInclusiveBody
Definition: FunctorsTBB.h:851
viskores::cont::tbb::CopyIfBody::Range::InputBegin
viskores::Id InputBegin
Definition: FunctorsTBB.h:177
viskores::cont::tbb::ReduceByKeyBody::Range::Range
Range()
Definition: FunctorsTBB.h:519
viskores::cont::tbb::ReduceByKeyPortals
viskores::Id ReduceByKeyPortals(KeysInPortalType keysInPortal, ValuesInPortalType valuesInPortal, KeysOutPortalType keysOutPortal, ValuesOutPortalType valuesOutPortal, BinaryOperationType binaryOperation)
Definition: FunctorsTBB.h:801
viskores::cont::tbb::ReduceBody::ReduceBody
ReduceBody(const InputPortalType &inputPortal, T initialValue, BinaryOperationType binaryOperation)
Definition: FunctorsTBB.h:394
viskores::cont::tbb::CopyIfBody::OutputPortal
OutputPortalType OutputPortal
Definition: FunctorsTBB.h:221
viskores::cont::tbb::ReduceByKeyBody::Range::OutputBegin
viskores::Id OutputBegin
Definition: FunctorsTBB.h:515
viskores::Sum
Binary Predicate that takes two arguments argument x, and y and returns sum (addition) of the two val...
Definition: BinaryOperators.h:41
viskores::cont::tbb::CopyBody::DoCopy
void DoCopy(InIter src, InIter srcEnd, OutIter dst, std::false_type) const
Definition: FunctorsTBB.h:108
viskores::cont::tbb::ReduceByKeyBody::KeysOutPortal
KeysOutPortalType KeysOutPortal
Definition: FunctorsTBB.h:557
viskores::cont::tbb::CopyIfBody::Range::AssertSane
void AssertSane() const
Definition: FunctorsTBB.h:205
viskores::cont::tbb::ReduceBody::FirstCall
bool FirstCall
Definition: FunctorsTBB.h:389
viskores::cont::tbb::UniqueBody::Portal
PortalType Portal
Definition: FunctorsTBB.h:1209
viskores::cont::tbb::ReduceBody::ReduceBody
ReduceBody(const ReduceBody &body, ::tbb::split)
Definition: FunctorsTBB.h:406
viskores::cont::tbb::ReduceBody::InputPortal
InputPortalType InputPortal
Definition: FunctorsTBB.h:390
viskores::cont::tbb::CopyIfBody::CopyIfBody
CopyIfBody(const InputPortalType &inputPortal, const StencilPortalType &stencilPortal, const OutputPortalType &outputPortal, UnaryPredicateType unaryPredicate)
Definition: FunctorsTBB.h:226
viskores::cont::tbb::CopyIfBody::Range::IsNext
bool IsNext(const Range &next) const
Definition: FunctorsTBB.h:216
viskores::cont::tbb::ScatterKernel
Definition: FunctorsTBB.h:1093
viskores::cont::tbb::ReduceByKeyBody::Range::InputBegin
viskores::Id InputBegin
Definition: FunctorsTBB.h:513
VISKORES_VECTORIZATION_PRE_LOOP
#define VISKORES_VECTORIZATION_PRE_LOOP
Definition: Configure.h:283
viskores::cont::tbb::CopyBody::InputOffset
viskores::Id InputOffset
Definition: FunctorsTBB.h:88
viskores::cont::tbb::CopyIfBody::UnaryPredicate
UnaryPredicateType UnaryPredicate
Definition: FunctorsTBB.h:222
viskores::cont::Error
The superclass of all exceptions thrown by any Viskores function or method.
Definition: Error.h:41
viskores::cont::tbb::ScanExclusiveBody::assign
void assign(const ScanExclusiveBody &src)
Definition: FunctorsTBB.h:1042
viskores::cont::tbb::ScatterKernel::ErrorMessage
viskores::exec::internal::ErrorMessageBuffer ErrorMessage
Definition: FunctorsTBB.h:1137
viskores::cont::tbb::ScanInclusiveBody::reverse_join
void reverse_join(const ScanInclusiveBody &left)
Definition: FunctorsTBB.h:928
viskores::cont::tbb::ReduceByKeyBody::ReduceByKeyBody
ReduceByKeyBody(const KeysInPortalType &keysInPortal, const ValuesInPortalType &valuesInPortal, const KeysOutPortalType &keysOutPortal, const ValuesOutPortalType &valuesOutPortal, BinaryOperationType binaryOperation)
Definition: FunctorsTBB.h:567
viskores::cont::tbb::ScanInclusiveBody::ValueType
typename std::remove_reference< typename OutputPortalType::ValueType >::type ValueType
Definition: FunctorsTBB.h:853
viskores::cont::tbb::ReduceByKeyBody::Ranges
Range Ranges
Definition: FunctorsTBB.h:560
viskores::cont::tbb::ScanInclusiveBody::BinaryOperation
BinaryOperationType BinaryOperation
Definition: FunctorsTBB.h:858
viskores::cont::tbb::ReduceByKeyBody::ValueType
typename ValuesInPortalType::ValueType ValueType
Definition: FunctorsTBB.h:509
VISKORES_THIRDPARTY_PRE_INCLUDE
#define VISKORES_THIRDPARTY_PRE_INCLUDE
Definition: Configure.h:199
Windows.h
viskores::cont::tbb::ScatterKernel::ScatterKernel
ScatterKernel(InputPortalType inputPortal, IndexPortalType indexPortal, OutputPortalType outputPortal)
Definition: FunctorsTBB.h:1096
viskores::cont::tbb::UniquePortals
viskores::Id UniquePortals(PortalType portal, BinaryOperationType binaryOperation)
Definition: FunctorsTBB.h:1381
viskores::cont::tbb::ScanInclusiveBody::operator()
void operator()(const ::tbb::blocked_range< viskores::Id > &range, ::tbb::pre_scan_tag)
Definition: FunctorsTBB.h:884
viskores::cont::tbb::UniqueBody::Range::InputBegin
viskores::Id InputBegin
Definition: FunctorsTBB.h:1163
viskores::cont::tbb::CopyIfBody::CopyIfBody
CopyIfBody(const CopyIfBody &body, ::tbb::split)
Definition: FunctorsTBB.h:238
viskores::cont::tbb::ScanExclusiveBody::operator()
void operator()(const ::tbb::blocked_range< viskores::Id > &range, ::tbb::final_scan_tag)
Definition: FunctorsTBB.h:999
viskores::cont::tbb::ScanInclusiveBody::FirstCall
bool FirstCall
Definition: FunctorsTBB.h:855
viskores::cont::tbb::ReduceByKeyBody
Definition: FunctorsTBB.h:506
viskores::cont::tbb::ReduceByKeyBody::operator()
void operator()(const ::tbb::blocked_range< viskores::Id > &range)
Definition: FunctorsTBB.h:600
viskores::cont::tbb::CopyBody::OutputPortal
OutputPortalType OutputPortal
Definition: FunctorsTBB.h:87