/* Copyright 2024 SINTEF AS This file is part of the Open Porous Media project (OPM). OPM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. OPM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OPM. If not, see . */ #include #include #include #include #include #include #include namespace Opm::cuistl { template CuBuffer::CuBuffer(const std::vector& data) : CuBuffer(data.data(), data.size()) { } template CuBuffer::CuBuffer(const size_t numberOfElements) : m_numberOfElements(numberOfElements) { if (numberOfElements < 1) { OPM_THROW(std::invalid_argument, "Setting a CuBuffer size to a non-positive number is not allowed"); } OPM_CUDA_SAFE_CALL(cudaMalloc(&m_dataOnDevice, sizeof(T) * m_numberOfElements)); } template CuBuffer::CuBuffer(const T* dataOnHost, const size_t numberOfElements) : CuBuffer(numberOfElements) { OPM_CUDA_SAFE_CALL(cudaMemcpy( m_dataOnDevice, dataOnHost, m_numberOfElements * sizeof(T), cudaMemcpyHostToDevice)); } template CuBuffer::CuBuffer(const CuBuffer& other) : CuBuffer(other.m_numberOfElements) { assertHasElements(); assertSameSize(other); OPM_CUDA_SAFE_CALL(cudaMemcpy(m_dataOnDevice, other.m_dataOnDevice, m_numberOfElements * sizeof(T), cudaMemcpyDeviceToDevice)); } template CuBuffer::~CuBuffer() { OPM_CUDA_WARN_IF_ERROR(cudaFree(m_dataOnDevice)); } template typename CuBuffer::size_type CuBuffer::size() const { return m_numberOfElements; } template void CuBuffer::resize(size_t newSize) { if (newSize < 1) { OPM_THROW(std::invalid_argument, "Setting a CuBuffer size to a non-positive number is not allowed"); } // Allocate memory for the new buffer T* tmpBuffer = nullptr; OPM_CUDA_SAFE_CALL(cudaMalloc(&tmpBuffer, sizeof(T) * newSize)); // Move the data from the old to the new buffer with truncation size_t sizeOfMove = std::min({m_numberOfElements, newSize}); OPM_CUDA_SAFE_CALL(cudaMemcpy(tmpBuffer, m_dataOnDevice, sizeOfMove * sizeof(T), cudaMemcpyDeviceToDevice)); // free the old buffer OPM_CUDA_SAFE_CALL(cudaFree(m_dataOnDevice)); // swap the buffers m_dataOnDevice = tmpBuffer; // update size m_numberOfElements = newSize; } template std::vector CuBuffer::asStdVector() const { std::vector temporary(m_numberOfElements); copyToHost(temporary); return temporary; } template void CuBuffer::assertSameSize(const CuBuffer& x) const { assertSameSize(x.m_numberOfElements); } template void CuBuffer::assertSameSize(size_t size) const { if (size != m_numberOfElements) { OPM_THROW(std::invalid_argument, fmt::format("Given buffer has {}, while we have {}.", size, m_numberOfElements)); } } template void CuBuffer::assertHasElements() const { if (m_numberOfElements <= 0) { OPM_THROW(std::invalid_argument, "We have 0 elements"); } } template T* CuBuffer::data() { return m_dataOnDevice; } template const T* CuBuffer::data() const { return m_dataOnDevice; } template void CuBuffer::copyFromHost(const T* dataPointer, size_t numberOfElements) { if (numberOfElements > size()) { OPM_THROW(std::runtime_error, fmt::format("Requesting to copy too many elements. buffer has {} elements, while {} was requested.", size(), numberOfElements)); } OPM_CUDA_SAFE_CALL(cudaMemcpy(data(), dataPointer, numberOfElements * sizeof(T), cudaMemcpyHostToDevice)); } template void CuBuffer::copyToHost(T* dataPointer, size_t numberOfElements) const { assertSameSize(numberOfElements); OPM_CUDA_SAFE_CALL(cudaMemcpy(dataPointer, data(), numberOfElements * sizeof(T), cudaMemcpyDeviceToHost)); } template void CuBuffer::copyFromHost(const std::vector& data) { copyFromHost(data.data(), data.size()); } template void CuBuffer::copyToHost(std::vector& data) const { copyToHost(data.data(), data.size()); } template class CuBuffer; template class CuBuffer; template class CuBuffer; template CuView make_view(const CuBuffer& buf) { return CuView(buf.data(), buf.size()); } template CuView make_view(const CuBuffer&); template CuView make_view(const CuBuffer&); template CuView make_view(const CuBuffer&); } // namespace Opm::cuistl