mirror of
https://gitlab.kitware.com/vtk/vtk-m
synced 2024-10-05 01:49:02 +00:00
Better fallback for ArrayGetValue
To avoid having to use a device compiler every time you wish to use `ArrayGetValue`, the actual implementation is compiled into the `vtkm_cont` library. To allow this to work for all the templated versions of `ArrayHandle`, the implementation uses the extract component features of `UnknownArrayHandle`. This works for most common arrays, but not all arrays. For arrays that cannot be directly represented by an `ArrayHandleStride`, the fallback is bad. The entire array has to be pulled to the host and then copied serially to a basic array. For `ArrayGetValue`, this is just silly. So, for arrays that cannot be simply represented by `ArrayHandleStride`, make a fallback that just uses `ReadPortal` to get the data. Often this is not the most efficient method, but it is better than the current alternative.
This commit is contained in:
parent
385ea820be
commit
5b34e6f70b
17
docs/changelog/get-value-fallback.md
Normal file
17
docs/changelog/get-value-fallback.md
Normal file
@ -0,0 +1,17 @@
|
||||
# Better fallback for ArrayGetValue
|
||||
|
||||
To avoid having to use a device compiler every time you wish to use
|
||||
`ArrayGetValue`, the actual implementation is compiled into the `vtkm_cont`
|
||||
library. To allow this to work for all the templated versions of
|
||||
`ArrayHandle`, the implementation uses the extract component features of
|
||||
`UnknownArrayHandle`. This works for most common arrays, but not all
|
||||
arrays.
|
||||
|
||||
For arrays that cannot be directly represented by an `ArrayHandleStride`,
|
||||
the fallback is bad. The entire array has to be pulled to the host and then
|
||||
copied serially to a basic array.
|
||||
|
||||
For `ArrayGetValue`, this is just silly. So, for arrays that cannot be
|
||||
simply represented by `ArrayHandleStride`, make a fallback that just uses
|
||||
`ReadPortal` to get the data. Often this is not the most efficient method,
|
||||
but it is better than the current alternative.
|
@ -66,8 +66,14 @@ ArrayExtractComponentFallback(const vtkm::cont::ArrayHandle<T, S>& src,
|
||||
return vtkm::cont::ArrayHandleStride<BaseComponentType>(dest, numValues, 1, 0);
|
||||
}
|
||||
|
||||
// Used as a superclass for ArrayHandleComponentImpls that are inefficient (and should be
|
||||
// avoided).
|
||||
struct ArrayExtractComponentImplInefficient
|
||||
{
|
||||
};
|
||||
|
||||
template <typename S>
|
||||
struct ArrayExtractComponentImpl
|
||||
struct ArrayExtractComponentImpl : ArrayExtractComponentImplInefficient
|
||||
{
|
||||
template <typename T>
|
||||
vtkm::cont::ArrayHandleStride<typename vtkm::VecTraits<T>::BaseComponentType> operator()(
|
||||
@ -131,6 +137,13 @@ struct ArrayExtractComponentImpl<vtkm::cont::StorageTagBasic>
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Resolves to true if ArrayHandleComponent of the array handle would be inefficient.
|
||||
///
|
||||
template <typename ArrayHandleType>
|
||||
using ArrayExtractComponentIsInefficient = typename std::is_base_of<
|
||||
vtkm::cont::internal::ArrayExtractComponentImplInefficient,
|
||||
vtkm::cont::internal::ArrayExtractComponentImpl<typename ArrayHandleType::StorageTag>>::type;
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/// \brief Pulls a component out of an `ArrayHandle`.
|
||||
|
@ -19,7 +19,8 @@
|
||||
|
||||
void vtkm::cont::internal::ArrayGetValuesImpl(const vtkm::cont::UnknownArrayHandle& ids,
|
||||
const vtkm::cont::UnknownArrayHandle& data,
|
||||
const vtkm::cont::UnknownArrayHandle& output)
|
||||
const vtkm::cont::UnknownArrayHandle& output,
|
||||
std::false_type)
|
||||
{
|
||||
auto idArray = ids.ExtractComponent<vtkm::Id>(0, vtkm::CopyFlag::On);
|
||||
output.Allocate(ids.GetNumberOfValues());
|
||||
|
@ -31,7 +31,30 @@ namespace internal
|
||||
|
||||
VTKM_CONT_EXPORT void ArrayGetValuesImpl(const vtkm::cont::UnknownArrayHandle& ids,
|
||||
const vtkm::cont::UnknownArrayHandle& data,
|
||||
const vtkm::cont::UnknownArrayHandle& output);
|
||||
const vtkm::cont::UnknownArrayHandle& output,
|
||||
std::false_type extractComponentInefficient);
|
||||
|
||||
template <typename IdsArrayHandle, typename DataArrayHandle, typename OutputArrayHandle>
|
||||
void ArrayGetValuesImpl(const IdsArrayHandle& ids,
|
||||
const DataArrayHandle& data,
|
||||
const OutputArrayHandle& output,
|
||||
std::true_type vtkmNotUsed(extractComponentInefficient))
|
||||
{
|
||||
// Fallback implementation. Using UnknownArrayHandle to extract the data would be more
|
||||
// inefficient than simply getting the ReadPortal (which could potentially copy everything
|
||||
// form device to host), so we do that here. The only other alternative would be to write
|
||||
// a custom worklet, but that would require a device compiler, and we are avoiding that for
|
||||
// this header.
|
||||
vtkm::Id outputSize = ids.GetNumberOfValues();
|
||||
output.Allocate(outputSize);
|
||||
auto idsPortal = ids.ReadPortal();
|
||||
auto dataPortal = data.ReadPortal();
|
||||
auto outputPortal = output.WritePortal();
|
||||
for (vtkm::Id index = 0; index < outputSize; ++index)
|
||||
{
|
||||
outputPortal.Set(index, dataPortal.Get(idsPortal.Get(index)));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
@ -100,7 +123,10 @@ VTKM_CONT void ArrayGetValues(const vtkm::cont::ArrayHandle<vtkm::Id, SIds>& ids
|
||||
VTKM_STATIC_ASSERT_MSG(
|
||||
vtkm::HasVecTraits<T>::value,
|
||||
"ArrayGetValues can only be used with arrays containing value types with VecTraits defined.");
|
||||
internal::ArrayGetValuesImpl(ids, data, output);
|
||||
using DataArrayHandle = vtkm::cont::ArrayHandle<T, SData>;
|
||||
using InefficientExtract =
|
||||
vtkm::cont::internal::ArrayExtractComponentIsInefficient<DataArrayHandle>;
|
||||
internal::ArrayGetValuesImpl(ids, data, output, InefficientExtract{});
|
||||
}
|
||||
|
||||
/// We need a specialization for `ArrayHandleCasts` to avoid runtime type missmatch errors inside
|
||||
|
Loading…
Reference in New Issue
Block a user