/* 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::gpuistl { template GpuBuffer::GpuBuffer(const std::vector& data) : GpuBuffer(data.data(), data.size()) { } template GpuBuffer::GpuBuffer(const size_t numberOfElements) : m_numberOfElements(numberOfElements) { if (numberOfElements < 1) { OPM_THROW(std::invalid_argument, "Setting a GpuBuffer size to a non-positive number is not allowed"); } OPM_GPU_SAFE_CALL(cudaMalloc(&m_dataOnDevice, sizeof(T) * m_numberOfElements)); } template GpuBuffer::GpuBuffer(const T* dataOnHost, const size_t numberOfElements) : GpuBuffer(numberOfElements) { OPM_GPU_SAFE_CALL(cudaMemcpy( m_dataOnDevice, dataOnHost, m_numberOfElements * sizeof(T), cudaMemcpyHostToDevice)); } template GpuBuffer::GpuBuffer(const GpuBuffer& other) : GpuBuffer(other.m_numberOfElements) { assertHasElements(); assertSameSize(other); OPM_GPU_SAFE_CALL(cudaMemcpy(m_dataOnDevice, other.m_dataOnDevice, m_numberOfElements * sizeof(T), cudaMemcpyDeviceToDevice)); } template GpuBuffer::~GpuBuffer() { OPM_GPU_WARN_IF_ERROR(cudaFree(m_dataOnDevice)); } template typename GpuBuffer::size_type GpuBuffer::size() const { return m_numberOfElements; } template void GpuBuffer::resize(size_t newSize) { if (newSize < 1) { OPM_THROW(std::invalid_argument, "Setting a GpuBuffer size to a non-positive number is not allowed"); } // Allocate memory for the new buffer T* tmpBuffer = nullptr; OPM_GPU_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_GPU_SAFE_CALL(cudaMemcpy(tmpBuffer, m_dataOnDevice, sizeOfMove * sizeof(T), cudaMemcpyDeviceToDevice)); // free the old buffer OPM_GPU_SAFE_CALL(cudaFree(m_dataOnDevice)); // swap the buffers m_dataOnDevice = tmpBuffer; // update size m_numberOfElements = newSize; } template std::vector GpuBuffer::asStdVector() const { std::vector temporary(m_numberOfElements); copyToHost(temporary); return temporary; } template void GpuBuffer::assertSameSize(const GpuBuffer& x) const { assertSameSize(x.m_numberOfElements); } template void GpuBuffer::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 GpuBuffer::assertHasElements() const { if (m_numberOfElements <= 0) { OPM_THROW(std::invalid_argument, "We have 0 elements"); } } template T* GpuBuffer::data() { return m_dataOnDevice; } template const T* GpuBuffer::data() const { return m_dataOnDevice; } template void GpuBuffer::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_GPU_SAFE_CALL(cudaMemcpy(data(), dataPointer, numberOfElements * sizeof(T), cudaMemcpyHostToDevice)); } template void GpuBuffer::copyToHost(T* dataPointer, size_t numberOfElements) const { assertSameSize(numberOfElements); OPM_GPU_SAFE_CALL(cudaMemcpy(dataPointer, data(), numberOfElements * sizeof(T), cudaMemcpyDeviceToHost)); } template void GpuBuffer::copyFromHost(const std::vector& data) { copyFromHost(data.data(), data.size()); } template void GpuBuffer::copyToHost(std::vector& data) const { copyToHost(data.data(), data.size()); } template class GpuBuffer; template class GpuBuffer; template class GpuBuffer; template GpuView make_view(const GpuBuffer& buf) { return GpuView(buf.data(), buf.size()); } template GpuView make_view(const GpuBuffer&); template GpuView make_view(const GpuBuffer&); template GpuView make_view(const GpuBuffer&); } // namespace Opm::gpuistl