Commit 60a405ef authored by Robert Maynard's avatar Robert Maynard

Add TaskTiling1D/3D which use faux virtuals to reduce binary size.

Redesigns the TBB and Serial backends and the vtkm::exec::Task concept so that
we can re-use the same launching logic for all Worklets, instead of generating
per worlet code. To keep the performance the same the TilingTask now is past
a range of indices to work on, rather than a single index.

Binary size reduction:
WorkletTests_SERIAL old - 19MB
WorkletTests_SERIAL new - 18MB

WorkletTests_TBB old - 39MB
WorkletTests_TBB new - 18MB

libvtkAcceleratorsVTKm old - 48MB
libvtkAcceleratorsVTKm new - 19MB
parent 4655f5af
......@@ -103,15 +103,20 @@ set(device_sources
RuntimeDeviceTracker.cxx
)
vtkm_declare_headers(${headers})
#-----------------------------------------------------------------------------
add_subdirectory(internal)
add_subdirectory(arg)
vtkm_declare_headers(${headers})
add_subdirectory(serial)
set(sources ${sources} $<TARGET_OBJECTS:vtkm_cont_serial>)
add_subdirectory(tbb)
if (VTKm_ENABLE_TBB)
set(sources ${sources} $<TARGET_OBJECTS:vtkm_cont_tbb>)
endif()
add_subdirectory(cuda)
if (VTKm_ENABLE_CUDA)
get_property(vtkm_cont_cuda_object_files GLOBAL
......@@ -122,15 +127,8 @@ if (VTKm_ENABLE_CUDA)
PROPERTIES GENERATED TRUE)
set(sources ${sources} ${vtkm_cont_cuda_object_files})
endif()
add_subdirectory(tbb)
if (VTKm_ENABLE_TBB)
set(sources ${sources} $<TARGET_OBJECTS:vtkm_cont_tbb>)
endif()
vtkm_library(
SOURCES ${sources}
WRAP_FOR_CUDA ${device_sources}
......
......@@ -583,6 +583,22 @@ public:
///
template <typename T, typename DeviceTag>
class DeviceAdapterAtomicArrayImplementation;
/// \brief Class providing a device-specific support for selecting the optimal
/// Task type for a given worklet.
///
/// When worklets are launched inside the execution enviornment we need to
/// ask the device adapter what is the preferred execution style, be it
/// a tiled iteration pattern, or strided. This class
///
/// By default if not specialized for a device adapter the default
/// is to use vtkm::exec::internal::TaskSingular
///
/// The class provide the actual implementation used by
/// vtkm::cont::DeviceTaskTypes.
///
template <typename DeviceTag>
class DeviceTaskTypes;
}
} // namespace vtkm::cont
......
......@@ -33,7 +33,7 @@ namespace
static const vtkm::Id ARRAY_SIZE = 10;
template <typename PortalType>
struct TestKernel : public vtkm::exec::FunctorBase
struct TestKernelIn : public vtkm::exec::FunctorBase
{
PortalType Portal;
......@@ -68,7 +68,7 @@ struct TryArrayInType
vtkm::cont::arg::Transport<vtkm::cont::arg::TransportTagArrayIn, ArrayHandleType, Device>
transport;
TestKernel<PortalType> kernel;
TestKernelIn<PortalType> kernel;
kernel.Portal = transport(handle, handle, ARRAY_SIZE, ARRAY_SIZE);
vtkm::cont::DeviceAdapterAlgorithm<Device>::Schedule(kernel, ARRAY_SIZE);
......
......@@ -33,7 +33,7 @@ namespace
static const vtkm::Id ARRAY_SIZE = 10;
template <typename PortalType>
struct TestKernel : public vtkm::exec::FunctorBase
struct TestKernelInOut : public vtkm::exec::FunctorBase
{
PortalType Portal;
......@@ -66,7 +66,7 @@ struct TryArrayInOutType
vtkm::cont::arg::Transport<vtkm::cont::arg::TransportTagArrayInOut, ArrayHandleType, Device>
transport;
TestKernel<PortalType> kernel;
TestKernelInOut<PortalType> kernel;
kernel.Portal = transport(handle, handle, ARRAY_SIZE, ARRAY_SIZE);
vtkm::cont::DeviceAdapterAlgorithm<Device>::Schedule(kernel, ARRAY_SIZE);
......
......@@ -34,7 +34,7 @@ namespace
static const vtkm::Id ARRAY_SIZE = 10;
template <typename PortalType>
struct TestKernel : public vtkm::exec::FunctorBase
struct TestKernelOut : public vtkm::exec::FunctorBase
{
PortalType Portal;
......@@ -60,7 +60,7 @@ struct TryArrayOutType
vtkm::cont::arg::Transport<vtkm::cont::arg::TransportTagArrayOut, ArrayHandleType, Device>
transport;
TestKernel<PortalType> kernel;
TestKernelOut<PortalType> kernel;
kernel.Portal =
transport(handle, vtkm::cont::ArrayHandleIndex(ARRAY_SIZE), ARRAY_SIZE, ARRAY_SIZE);
......
......@@ -241,6 +241,29 @@ private:
(unsigned long long int)newValue);
}
};
template <>
class DeviceTaskTypes<vtkm::cont::DeviceAdapterTagCuda>
{
public:
template <typename WorkletType, typename InvocationType>
static vtkm::exec::internal::TaskSingular<WorkletType, InvocationType> MakeTask(
const WorkletType& worklet, const InvocationType& invocation, vtkm::Id,
vtkm::Id globalIndexOffset = 0)
{
using Task = vtkm::exec::internal::TaskSingular<WorkletType, InvocationType>;
return Task(worklet, invocation, globalIndexOffset);
}
template <typename WorkletType, typename InvocationType>
static vtkm::exec::internal::TaskSingular<WorkletType, InvocationType> MakeTask(
const WorkletType& worklet, const InvocationType& invocation, vtkm::Id3,
vtkm::Id globalIndexOffset = 0)
{
using Task = vtkm::exec::internal::TaskSingular<WorkletType, InvocationType>;
return Task(worklet, invocation, globalIndexOffset);
}
};
}
} // namespace vtkm::cont
......
......@@ -1187,6 +1187,14 @@ private:
}
public:
template <class TaskType, typename RangeType>
VTKM_CONT static void ScheduleTask(TaskType task, RangeType size)
{ //for now defer to the schedule api, we need to do a significant
//amount of build infrastructure work to implement type erasure tasks
//for cuda
Schedule(task, size);
}
template <class Functor>
VTKM_CONT static void Schedule(Functor functor, vtkm::Id numInstances)
{
......
......@@ -29,6 +29,7 @@
#include <vtkm/cont/internal/FunctorsGeneral.h>
#include <vtkm/exec/internal/ErrorMessageBuffer.h>
#include <vtkm/exec/internal/TaskSingular.h>
#include <vtkm/TypeTraits.h>
......@@ -1029,6 +1030,39 @@ private:
#endif
};
/// \brief Class providing a device-specific support for selecting the optimal
/// Task type for a given worklet.
///
/// When worklets are launched inside the execution enviornment we need to
/// ask the device adapter what is the preferred execution style, be it
/// a tiled iteration pattern, or strided. This class
///
/// By default if not specialized for a device adapter the default
/// is to use vtkm::exec::internal::TaskSingular
///
template <typename DeviceTag>
class DeviceTaskTypes
{
public:
template <typename WorkletType, typename InvocationType>
static vtkm::exec::internal::TaskSingular<WorkletType, InvocationType> MakeTask(
const WorkletType& worklet, const InvocationType& invocation, vtkm::Id,
vtkm::Id globalIndexOffset = 0)
{
using Task = vtkm::exec::internal::TaskSingular<WorkletType, InvocationType>;
return Task(worklet, invocation, globalIndexOffset);
}
template <typename WorkletType, typename InvocationType>
static vtkm::exec::internal::TaskSingular<WorkletType, InvocationType> MakeTask(
const WorkletType& worklet, const InvocationType& invocation, vtkm::Id3,
vtkm::Id globalIndexOffset = 0)
{
using Task = vtkm::exec::internal::TaskSingular<WorkletType, InvocationType>;
return Task(worklet, invocation, globalIndexOffset);
}
};
}
} // namespace vtkm::cont
......
......@@ -25,22 +25,19 @@ set(headers
VirtualObjectTransferSerial.h
)
vtkm_declare_headers(${headers})
add_library(vtkm_cont_serial OBJECT ArrayManagerExecutionSerial.cxx)
add_library(vtkm_cont_serial OBJECT
ArrayManagerExecutionSerial.cxx
DeviceAdapterAlgorithmSerial.cxx
)
target_compile_features(vtkm_cont_serial PRIVATE cxx_auto_type)
target_compile_definitions(vtkm_cont_serial PRIVATE vtkm_cont_EXPORTS)
if(BUILD_SHARED_LIBS)
set_property(TARGET vtkm_cont_serial PROPERTY POSITION_INDEPENDENT_CODE ON)
endif()
target_include_directories(vtkm_cont_serial PRIVATE
${VTKm_BACKEND_INCLUDE_DIRS}
${VTKm_SOURCE_DIR}
${VTKm_BINARY_DIR}/include
)
if (BUILD_SHARED_LIBS)
set_property(TARGET vtkm_cont_serial
PROPERTY POSITION_INDEPENDENT_CODE ON
)
endif()
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2014 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#include <vtkm/cont/serial/internal/DeviceAdapterAlgorithmSerial.h>
namespace vtkm
{
namespace cont
{
void DeviceAdapterAlgorithm<vtkm::cont::DeviceAdapterTagSerial>::ScheduleTask(
vtkm::exec::serial::internal::TaskTiling1D& functor, vtkm::Id size)
{
const vtkm::Id MESSAGE_SIZE = 1024;
char errorString[MESSAGE_SIZE];
errorString[0] = '\0';
vtkm::exec::internal::ErrorMessageBuffer errorMessage(errorString, MESSAGE_SIZE);
functor.SetErrorMessageBuffer(errorMessage);
const vtkm::Id iterations = size / 1024;
vtkm::Id index = 0;
for (vtkm::Id i = 0; i < iterations; ++i)
{
functor(index, index + 1024);
index += 1024;
}
functor(index, size);
if (errorMessage.IsErrorRaised())
{
throw vtkm::cont::ErrorExecution(errorString);
}
}
void DeviceAdapterAlgorithm<vtkm::cont::DeviceAdapterTagSerial>::ScheduleTask(
vtkm::exec::serial::internal::TaskTiling3D& functor, vtkm::Id3 size)
{
const vtkm::Id MESSAGE_SIZE = 1024;
char errorString[MESSAGE_SIZE];
errorString[0] = '\0';
vtkm::exec::internal::ErrorMessageBuffer errorMessage(errorString, MESSAGE_SIZE);
functor.SetErrorMessageBuffer(errorMessage);
for (vtkm::Id k = 0; k < size[2]; ++k)
{
for (vtkm::Id j = 0; j < size[1]; ++j)
{
functor(0, size[0], j, k);
}
}
if (errorMessage.IsErrorRaised())
{
throw vtkm::cont::ErrorExecution(errorString);
}
}
}
}
......@@ -30,7 +30,7 @@
#include <vtkm/BinaryOperators.h>
#include <vtkm/exec/internal/ErrorMessageBuffer.h>
#include <vtkm/exec/serial/internal/TaskTiling.h>
#include <algorithm>
#include <numeric>
......@@ -237,86 +237,23 @@ public:
return ScanExclusive(input, output, vtkm::Sum(), vtkm::TypeTraits<T>::ZeroInitialization());
}
private:
// This runs in the execution environment.
template <class FunctorType>
class ScheduleKernel
{
public:
ScheduleKernel(const FunctorType& functor)
: Functor(functor)
{
}
VTKM_CONT_EXPORT static void ScheduleTask(vtkm::exec::serial::internal::TaskTiling1D& functor,
vtkm::Id size);
VTKM_CONT_EXPORT static void ScheduleTask(vtkm::exec::serial::internal::TaskTiling3D& functor,
vtkm::Id3 size);
//needed for when calling from schedule on a range
template <typename T>
VTKM_EXEC void operator()(const T& index) const
{
this->Functor(index);
}
private:
const FunctorType Functor;
void operator=(const ScheduleKernel<FunctorType>&) = delete;
};
public:
template <class Functor>
VTKM_CONT static void Schedule(Functor functor, vtkm::Id numInstances)
template <class FunctorType>
VTKM_CONT static inline void Schedule(FunctorType functor, vtkm::Id size)
{
const vtkm::Id MESSAGE_SIZE = 1024;
char errorString[MESSAGE_SIZE];
errorString[0] = '\0';
vtkm::exec::internal::ErrorMessageBuffer errorMessage(errorString, MESSAGE_SIZE);
functor.SetErrorMessageBuffer(errorMessage);
DeviceAdapterAlgorithm<Device>::ScheduleKernel<Functor> kernel(functor);
const vtkm::Id size = numInstances;
VTKM_VECTORIZATION_PRE_LOOP
for (vtkm::Id i = 0; i < size; ++i)
{
VTKM_VECTORIZATION_IN_LOOP
kernel(i);
}
if (errorMessage.IsErrorRaised())
{
throw vtkm::cont::ErrorExecution(errorString);
}
vtkm::exec::serial::internal::TaskTiling1D kernel(functor);
ScheduleTask(kernel, size);
}
template <class Functor>
VTKM_CONT static void Schedule(Functor functor, vtkm::Id3 rangeMax)
template <class FunctorType>
VTKM_CONT static inline void Schedule(FunctorType functor, vtkm::Id3 size)
{
const vtkm::Id MESSAGE_SIZE = 1024;
char errorString[MESSAGE_SIZE];
errorString[0] = '\0';
vtkm::exec::internal::ErrorMessageBuffer errorMessage(errorString, MESSAGE_SIZE);
functor.SetErrorMessageBuffer(errorMessage);
DeviceAdapterAlgorithm<Device>::ScheduleKernel<Functor> kernel(functor);
for (vtkm::Id k = 0; k < rangeMax[2]; ++k)
{
for (vtkm::Id j = 0; j < rangeMax[1]; ++j)
{
VTKM_VECTORIZATION_PRE_LOOP
for (vtkm::Id i = 0; i < rangeMax[0]; ++i)
{
VTKM_VECTORIZATION_IN_LOOP
kernel(vtkm::Id3(i, j, k));
}
}
}
if (errorMessage.IsErrorRaised())
{
throw vtkm::cont::ErrorExecution(errorString);
}
vtkm::exec::serial::internal::TaskTiling3D kernel(functor);
ScheduleTask(kernel, size);
}
private:
......@@ -427,6 +364,29 @@ public:
// Nothing to do. This device is serial and has no asynchronous operations.
}
};
template <>
class DeviceTaskTypes<vtkm::cont::DeviceAdapterTagSerial>
{
public:
template <typename WorkletType, typename InvocationType>
static vtkm::exec::serial::internal::TaskTiling1D MakeTask(const WorkletType& worklet,
const InvocationType& invocation,
vtkm::Id,
vtkm::Id globalIndexOffset = 0)
{
return vtkm::exec::serial::internal::TaskTiling1D(worklet, invocation, globalIndexOffset);
}
template <typename WorkletType, typename InvocationType>
static vtkm::exec::serial::internal::TaskTiling3D MakeTask(const WorkletType& worklet,
const InvocationType& invocation,
vtkm::Id3,
vtkm::Id globalIndexOffset = 0)
{
return vtkm::exec::serial::internal::TaskTiling3D(worklet, invocation, globalIndexOffset);
}
};
}
} // namespace vtkm::cont
......
......@@ -38,16 +38,23 @@ vtkm_declare_headers(parallel_sort.h TESTABLE OFF)
vtkm_declare_headers(${headers} TESTABLE ${VTKm_ENABLE_TBB})
#-----------------------------------------------------------------------------
if (VTKm_ENABLE_TBB)
add_library(vtkm_cont_tbb OBJECT ArrayManagerExecutionTBB.cxx)
target_compile_features(vtkm_cont_tbb PRIVATE cxx_auto_type)
target_compile_definitions(vtkm_cont_tbb PRIVATE vtkm_cont_EXPORTS)
target_include_directories(vtkm_cont_tbb PRIVATE
"${VTKm_SOURCE_DIR}"
"${VTKm_BINARY_DIR}/include"
${VTKm_BACKEND_INCLUDE_DIRS}
)
if (BUILD_SHARED_LIBS)
set_property(TARGET vtkm_cont_tbb PROPERTY POSITION_INDEPENDENT_CODE ON)
endif()
if (NOT VTKm_ENABLE_TBB)
return()
endif()
add_library(vtkm_cont_tbb OBJECT
ArrayManagerExecutionTBB.cxx
DeviceAdapterAlgorithmTBB.cxx
)
target_compile_features(vtkm_cont_tbb PRIVATE cxx_auto_type)
target_compile_definitions(vtkm_cont_tbb PRIVATE vtkm_cont_EXPORTS)
if(BUILD_SHARED_LIBS)
set_property(TARGET vtkm_cont_tbb PROPERTY POSITION_INDEPENDENT_CODE ON)
endif()
target_include_directories(vtkm_cont_tbb PRIVATE
"${VTKm_SOURCE_DIR}"
"${VTKm_BINARY_DIR}/include"
${VTKm_BACKEND_INCLUDE_DIRS}
)
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2014 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#include <vtkm/cont/tbb/internal/DeviceAdapterAlgorithmTBB.h>
namespace vtkm
{
namespace cont
{
void DeviceAdapterAlgorithm<vtkm::cont::DeviceAdapterTagTBB>::ScheduleTask(
vtkm::exec::tbb::internal::TaskTiling1D& functor, vtkm::Id size)
{
const vtkm::Id MESSAGE_SIZE = 1024;
char errorString[MESSAGE_SIZE];
errorString[0] = '\0';
vtkm::exec::internal::ErrorMessageBuffer errorMessage(errorString, MESSAGE_SIZE);
functor.SetErrorMessageBuffer(errorMessage);
::tbb::blocked_range<vtkm::Id> range(0, size);
::tbb::parallel_for(
range, [&](const ::tbb::blocked_range<vtkm::Id>& r) { functor(r.begin(), r.end()); });
if (errorMessage.IsErrorRaised())
{
throw vtkm::cont::ErrorExecution(errorString);
}
}
void DeviceAdapterAlgorithm<vtkm::cont::DeviceAdapterTagTBB>::ScheduleTask(
vtkm::exec::tbb::internal::TaskTiling3D& functor, vtkm::Id3 size)
{
static const vtkm::UInt32 TBB_GRAIN_SIZE_3D[3] = { 1, 4, 256 };
const vtkm::Id MESSAGE_SIZE = 1024;
char errorString[MESSAGE_SIZE];
errorString[0] = '\0';
vtkm::exec::internal::ErrorMessageBuffer errorMessage(errorString, MESSAGE_SIZE);
functor.SetErrorMessageBuffer(errorMessage);
//memory is generally setup in a way that iterating the first range
//in the tightest loop has the best cache coherence.
::tbb::blocked_range3d<vtkm::Id> range(0, size[2], TBB_GRAIN_SIZE_3D[0], 0, size[1],
TBB_GRAIN_SIZE_3D[1], 0, size[0], TBB_GRAIN_SIZE_3D[2]);
::tbb::parallel_for(range, [&](const ::tbb::blocked_range3d<vtkm::Id>& r) {
for (vtkm::Id k = r.pages().begin(); k != r.pages().end(); ++k)
{
for (vtkm::Id j = r.rows().begin(); j != r.rows().end(); ++j)
{
const vtkm::Id start = r.cols().begin();
const vtkm::Id end = r.cols().end();
functor(start, end, j, k);
}
}
});
if (errorMessage.IsErrorRaised())
{
throw vtkm::cont::ErrorExecution(errorString);
}
}
}
}
......@@ -30,7 +30,8 @@
#include <vtkm/cont/tbb/internal/ArrayManagerExecutionTBB.h>
#include <vtkm/cont/tbb/internal/DeviceAdapterTagTBB.h>
#include <vtkm/cont/tbb/internal/FunctorsTBB.h>
#include <vtkm/exec/internal/ErrorMessageBuffer.h>
#include <vtkm/exec/tbb/internal/TaskTiling.h>
namespace vtkm
{
......@@ -99,53 +100,23 @@ public:
binary_functor, initialValue);
}
VTKM_CONT_EXPORT static void ScheduleTask(vtkm::exec::tbb::internal::TaskTiling1D& functor,
vtkm::Id size);
VTKM_CONT_EXPORT static void ScheduleTask(vtkm::exec::tbb::internal::TaskTiling3D& functor,
vtkm::Id3 size);
template <class FunctorType>
VTKM_CONT static void Schedule(FunctorType functor, vtkm::Id numInstances)
VTKM_CONT static inline void Schedule(FunctorType functor, vtkm::Id numInstances)
{
const vtkm::Id MESSAGE_SIZE = 1024;
char errorString[MESSAGE_SIZE];
errorString[0] = '\0';
vtkm::exec::internal::ErrorMessageBuffer errorMessage(errorString, MESSAGE_SIZE);
tbb::ScheduleKernel<FunctorType> kernel(functor);
kernel.SetErrorMessageBuffer(errorMessage);
::tbb::blocked_range<vtkm::Id> range(0, numInstances, tbb::TBB_GRAIN_SIZE);
::tbb::parallel_for(range, kernel);
if (errorMessage.IsErrorRaised())
{
throw vtkm::cont::ErrorExecution(errorString);
}
vtkm::exec::tbb::internal::TaskTiling1D kernel(functor);
ScheduleTask(kernel, numInstances);
}
template <class FunctorType>
VTKM_CONT static void Schedule(FunctorType functor, vtkm::Id3 rangeMax)
VTKM_CONT static inline void Schedule(FunctorType functor, vtkm::Id3 rangeMax)
{
static const vtkm::UInt32 TBB_GRAIN_SIZE_3D[3] = { 1, 4, 256 };
//we need to extract from the functor that uniform grid information
const vtkm::Id MESSAGE_SIZE = 1024;
char errorString[MESSAGE_SIZE];
errorString[0] = '\0';
vtkm::exec::internal::ErrorMessageBuffer errorMessage(errorString, MESSAGE_SIZE);
//memory is generally setup in a way that iterating the first range
//in the tightest loop has the best cache coherence.
::tbb::blocked_range3d<vtkm::Id> range(0, rangeMax[2], TBB_GRAIN_SIZE_3D[0], 0, rangeMax[1],
TBB_GRAIN_SIZE_3D[1], 0, rangeMax[0],
TBB_GRAIN_SIZE_3D[2]);
tbb::ScheduleKernelId3<FunctorType> kernel(functor);
kernel.SetErrorMessageBuffer(errorMessage);
::tbb::parallel_for(range, kernel);
if (errorMessage.IsErrorRaised())
{
throw vtkm::cont::ErrorExecution(errorString);
}
vtkm::exec::tbb::internal::TaskTiling3D kernel(functor);
ScheduleTask(kernel, rangeMax);
}
template <typename T, class Container>
......@@ -249,6 +220,29 @@ public:
private:
::tbb::tick_count StartTime;
};
template <>
class DeviceTaskTypes<vtkm::cont::DeviceAdapterTagTBB>
{
public:
template <typename WorkletType, typename InvocationType>
static vtkm::exec::serial::internal::TaskTiling1D MakeTask(const WorkletType& worklet,
const InvocationType& invocation,
vtkm::Id,
vtkm::Id globalIndexOffset = 0)
{
return vtkm::exec::tbb::internal::TaskTiling1D(worklet, invocation, globalIndexOffset);
}
template <typename WorkletType, typename InvocationType>
static vtkm::exec::serial::internal::TaskTiling3D MakeTask(const WorkletType& worklet,
const InvocationType& invocation,
vtkm::Id3,
vtkm::Id globalIndexOffset = 0)
{
return vtkm::exec::tbb::internal::TaskTiling3D(worklet, invocation, globalIndexOffset);
}
};
}
} // namespace vtkm::cont