vtk-m2/vtkm/cont/StorageVirtual.cxx
Kenneth Moreland db0f5c31b9 Add a Transfer object for ArrayHandleVirtual
Previously, ArrayHandleVirtual was using the default Transfer object.
This was problematic because it would copy/allocate things in the
execution environment independently from the array that it was wrapped
around. This caused several negative effects, particularly for CUDA
devices. First, if the data were already on the device (or the array is
implicit), a second copy of the data would be made. Second, the copy to
the device is likely less efficient. Third (and worst of all), the data
did not always get pulled back to the original array correctly.

This commit also contains instantiations of ArrayHandleVirtual and its
components for the most common types.
2019-03-01 15:50:16 -07:00

264 lines
9.6 KiB
C++

//============================================================================
// 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 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-NA0003525 with NTESS,
// 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.
//============================================================================
#define vtk_m_cont_StorageVirtual_cxx
#include "StorageVirtual.h"
#include <vtkm/cont/internal/DeviceAdapterError.h>
namespace vtkm
{
namespace cont
{
namespace internal
{
namespace detail
{
//--------------------------------------------------------------------
StorageVirtual::StorageVirtual(const StorageVirtual& src)
: HostUpToDate(src.HostUpToDate)
, DeviceUpToDate(src.DeviceUpToDate)
, DeviceTransferState(src.DeviceTransferState)
{
}
//--------------------------------------------------------------------
StorageVirtual::StorageVirtual(StorageVirtual&& src) noexcept
: HostUpToDate(src.HostUpToDate),
DeviceUpToDate(src.DeviceUpToDate),
DeviceTransferState(std::move(src.DeviceTransferState))
{
}
//--------------------------------------------------------------------
StorageVirtual& StorageVirtual::operator=(const StorageVirtual& src)
{
this->HostUpToDate = src.HostUpToDate;
this->DeviceUpToDate = src.DeviceUpToDate;
this->DeviceTransferState = src.DeviceTransferState;
return *this;
}
//--------------------------------------------------------------------
StorageVirtual& StorageVirtual::operator=(StorageVirtual&& src) noexcept
{
this->HostUpToDate = src.HostUpToDate;
this->DeviceUpToDate = src.DeviceUpToDate;
this->DeviceTransferState = std::move(src.DeviceTransferState);
return *this;
}
//--------------------------------------------------------------------
StorageVirtual::~StorageVirtual()
{
}
//--------------------------------------------------------------------
void StorageVirtual::DropExecutionPortal()
{
this->DeviceTransferState->releaseDevice();
this->DeviceUpToDate = false;
}
//--------------------------------------------------------------------
void StorageVirtual::DropAllPortals()
{
this->DeviceTransferState->releaseAll();
this->HostUpToDate = false;
this->DeviceUpToDate = false;
}
//--------------------------------------------------------------------
std::unique_ptr<StorageVirtual> StorageVirtual::NewInstance() const
{
return this->MakeNewInstance();
}
//--------------------------------------------------------------------
const vtkm::internal::PortalVirtualBase* StorageVirtual::PrepareForInput(
vtkm::cont::DeviceAdapterId devId) const
{
if (devId == vtkm::cont::DeviceAdapterTagUndefined())
{
throw vtkm::cont::ErrorBadValue("device should not be VTKM_DEVICE_ADAPTER_UNDEFINED");
}
if (devId == vtkm::cont::DeviceAdapterTagError())
{
throw vtkm::cont::ErrorBadValue("device should not be VTKM_DEVICE_ADAPTER_ERROR");
}
const bool needsUpload = !(this->DeviceTransferState->valid(devId) && this->DeviceUpToDate);
if (needsUpload)
{ //Either transfer state is pointing to another device, or has
//had the execution resources released. Either way we
//need to re-transfer the execution information
auto* payload = this->DeviceTransferState.get();
this->TransferPortalForInput(*payload, devId);
this->DeviceUpToDate = true;
}
return this->DeviceTransferState->devicePtr();
}
//--------------------------------------------------------------------
const vtkm::internal::PortalVirtualBase* StorageVirtual::PrepareForOutput(
vtkm::Id numberOfValues,
vtkm::cont::DeviceAdapterId devId)
{
if (devId == vtkm::cont::DeviceAdapterTagUndefined())
{
throw vtkm::cont::ErrorBadValue("device should not be VTKM_DEVICE_ADAPTER_UNDEFINED");
}
if (devId == vtkm::cont::DeviceAdapterTagError())
{
throw vtkm::cont::ErrorBadValue("device should not be VTKM_DEVICE_ADAPTER_ERROR");
}
const bool needsUpload = !(this->DeviceTransferState->valid(devId) && this->DeviceUpToDate);
if (needsUpload)
{
this->TransferPortalForOutput(
*(this->DeviceTransferState), OutputMode::WRITE, numberOfValues, devId);
this->HostUpToDate = false;
this->DeviceUpToDate = true;
}
return this->DeviceTransferState->devicePtr();
}
//--------------------------------------------------------------------
const vtkm::internal::PortalVirtualBase* StorageVirtual::PrepareForInPlace(
vtkm::cont::DeviceAdapterId devId)
{
if (devId == vtkm::cont::DeviceAdapterTagUndefined())
{
throw vtkm::cont::ErrorBadValue("device should not be VTKM_DEVICE_ADAPTER_UNDEFINED");
}
if (devId == vtkm::cont::DeviceAdapterTagError())
{
throw vtkm::cont::ErrorBadValue("device should not be VTKM_DEVICE_ADAPTER_ERROR");
}
const bool needsUpload = !(this->DeviceTransferState->valid(devId) && this->DeviceUpToDate);
if (needsUpload)
{
vtkm::Id numberOfValues = this->GetNumberOfValues();
this->TransferPortalForOutput(
*(this->DeviceTransferState), OutputMode::READ_WRITE, numberOfValues, devId);
this->HostUpToDate = false;
this->DeviceUpToDate = true;
}
return this->DeviceTransferState->devicePtr();
}
//--------------------------------------------------------------------
const vtkm::internal::PortalVirtualBase* StorageVirtual::GetPortalControl()
{
if (!this->HostUpToDate)
{
//we need to prepare for input and grab the host ptr
auto* payload = this->DeviceTransferState.get();
this->ControlPortalForOutput(*payload);
}
this->DeviceUpToDate = false;
this->HostUpToDate = true;
return this->DeviceTransferState->hostPtr();
}
//--------------------------------------------------------------------
const vtkm::internal::PortalVirtualBase* StorageVirtual::GetPortalConstControl() const
{
if (!this->HostUpToDate)
{
//we need to prepare for input and grab the host ptr
vtkm::cont::internal::TransferInfoArray* payload = this->DeviceTransferState.get();
this->ControlPortalForInput(*payload);
}
this->HostUpToDate = true;
return this->DeviceTransferState->hostPtr();
}
//--------------------------------------------------------------------
DeviceAdapterId StorageVirtual::GetDeviceAdapterId() const noexcept
{
return this->DeviceTransferState->deviceId();
}
//--------------------------------------------------------------------
void StorageVirtual::ControlPortalForOutput(vtkm::cont::internal::TransferInfoArray&)
{
throw vtkm::cont::ErrorBadValue(
"StorageTagVirtual by default doesn't support control side writes.");
}
//--------------------------------------------------------------------
void StorageVirtual::TransferPortalForOutput(vtkm::cont::internal::TransferInfoArray&,
OutputMode,
vtkm::Id,
vtkm::cont::DeviceAdapterId)
{
throw vtkm::cont::ErrorBadValue("StorageTagVirtual by default doesn't support exec side writes.");
}
#define VTK_M_ARRAY_TRANSFER_VIRTUAL_INSTANTIATE(T) \
template class VTKM_CONT_EXPORT ArrayTransferVirtual<T>; \
template class VTKM_CONT_EXPORT ArrayTransferVirtual<vtkm::Vec<T, 2>>; \
template class VTKM_CONT_EXPORT ArrayTransferVirtual<vtkm::Vec<T, 3>>; \
template class VTKM_CONT_EXPORT ArrayTransferVirtual<vtkm::Vec<T, 4>>
VTK_M_ARRAY_TRANSFER_VIRTUAL_INSTANTIATE(char);
VTK_M_ARRAY_TRANSFER_VIRTUAL_INSTANTIATE(vtkm::Int8);
VTK_M_ARRAY_TRANSFER_VIRTUAL_INSTANTIATE(vtkm::UInt8);
VTK_M_ARRAY_TRANSFER_VIRTUAL_INSTANTIATE(vtkm::Int16);
VTK_M_ARRAY_TRANSFER_VIRTUAL_INSTANTIATE(vtkm::UInt16);
VTK_M_ARRAY_TRANSFER_VIRTUAL_INSTANTIATE(vtkm::Int32);
VTK_M_ARRAY_TRANSFER_VIRTUAL_INSTANTIATE(vtkm::UInt32);
VTK_M_ARRAY_TRANSFER_VIRTUAL_INSTANTIATE(vtkm::Int64);
VTK_M_ARRAY_TRANSFER_VIRTUAL_INSTANTIATE(vtkm::UInt64);
VTK_M_ARRAY_TRANSFER_VIRTUAL_INSTANTIATE(vtkm::Float32);
VTK_M_ARRAY_TRANSFER_VIRTUAL_INSTANTIATE(vtkm::Float64);
#undef VTK_M_ARRAY_TRANSFER_VIRTUAL_INSTANTIATE
#define VTK_M_STORAGE_VIRTUAL_INSTANTIATE(T) \
template class VTKM_CONT_EXPORT StorageVirtualImpl<T, VTKM_DEFAULT_STORAGE_TAG>; \
template class VTKM_CONT_EXPORT StorageVirtualImpl<vtkm::Vec<T, 2>, VTKM_DEFAULT_STORAGE_TAG>; \
template class VTKM_CONT_EXPORT StorageVirtualImpl<vtkm::Vec<T, 3>, VTKM_DEFAULT_STORAGE_TAG>; \
template class VTKM_CONT_EXPORT StorageVirtualImpl<vtkm::Vec<T, 4>, VTKM_DEFAULT_STORAGE_TAG>
VTK_M_STORAGE_VIRTUAL_INSTANTIATE(char);
VTK_M_STORAGE_VIRTUAL_INSTANTIATE(vtkm::Int8);
VTK_M_STORAGE_VIRTUAL_INSTANTIATE(vtkm::UInt8);
VTK_M_STORAGE_VIRTUAL_INSTANTIATE(vtkm::Int16);
VTK_M_STORAGE_VIRTUAL_INSTANTIATE(vtkm::UInt16);
VTK_M_STORAGE_VIRTUAL_INSTANTIATE(vtkm::Int32);
VTK_M_STORAGE_VIRTUAL_INSTANTIATE(vtkm::UInt32);
VTK_M_STORAGE_VIRTUAL_INSTANTIATE(vtkm::Int64);
VTK_M_STORAGE_VIRTUAL_INSTANTIATE(vtkm::UInt64);
VTK_M_STORAGE_VIRTUAL_INSTANTIATE(vtkm::Float32);
VTK_M_STORAGE_VIRTUAL_INSTANTIATE(vtkm::Float64);
#undef VTK_M_STORAGE_VIRTUAL_INSTANTIATE
}
}
}
} // namespace vtkm::cont::internal::detail