/* ************************************************************************ * Copyright (C) 2018-2024 Advanced Micro Devices, Inc. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell cop- * ies of the Software, and to permit persons to whom the Software is furnished * to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IM- * PLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNE- * CTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * * ************************************************************************ */ #pragma once // // Local declaration of the device batch vector. // template class device_batch_vector; //! //! @brief Implementation of the batch vector on host. //! template class host_batch_vector { public: using value_type = T; public: //! //! @brief Delete copy constructor. //! host_batch_vector(const host_batch_vector& that) = delete; //! //! @brief Delete copy assignement. //! host_batch_vector& operator=(const host_batch_vector& that) = delete; //! //! @brief Constructor. //! @param n The length of the vector. //! @param inc The increment. //! @param batch_count The batch count. //! explicit host_batch_vector(int64_t n, int64_t inc, int64_t batch_count) : m_n(n) , m_inc(inc) , m_batch_count(batch_count) { if(false == this->try_initialize_memory()) { this->free_memory(); } } //! //! @brief Constructor. //! @param n The length of the vector. //! @param inc The increment. //! @param stride (UNUSED) The stride. //! @param batch_count The batch count. //! explicit host_batch_vector(int64_t n, int64_t inc, rocblas_stride stride, int64_t batch_count) : host_batch_vector(n, inc, batch_count) { } //! //! @brief Destructor. //! ~host_batch_vector() { this->free_memory(); } //! //! @brief Returns the length of the vector. //! int64_t n() const { return this->m_n; } //! //! @brief Returns the increment of the vector. //! int64_t inc() const { return this->m_inc; } //! //! @brief Returns the batch count. //! int64_t batch_count() const { return this->m_batch_count; } //! //! @brief Returns the stride value. //! rocblas_stride stride() const { return 0; } //! //! @brief Random access. //! @param batch_index The batch index. //! @return Pointer to the array on host. //! T* operator[](int64_t batch_index) { return this->m_data[batch_index]; } //! //! @brief Constant random access. //! @param batch_index The batch index. //! @return Constant pointer to the array on host. //! const T* operator[](int64_t batch_index) const { return this->m_data[batch_index]; } // clang-format off //! //! @brief Cast to a double pointer. //! operator T**() { return this->m_data; } //! //! @brief Constant cast to a double pointer. //! operator const T* const*() { return this->m_data; } // clang-format on //! //! @brief Copy from a host batched vector. //! @param that the vector the data is copied from. //! @return true if the copy is done successfully, false otherwise. //! bool copy_from(const host_batch_vector& that) { if((this->batch_count() == that.batch_count()) && (this->n() == that.n()) && (this->inc() == that.inc())) { size_t num_bytes = this->n() * std::abs(this->inc()) * sizeof(T); for(int64_t batch_index = 0; batch_index < this->m_batch_count; ++batch_index) { memcpy((*this)[batch_index], that[batch_index], num_bytes); } return true; } else { return false; } } //! //! @brief Transfer from a device batched vector. //! @param that the vector the data is copied from. //! @return the hip error. //! hipError_t transfer_from(const device_batch_vector& that) { hipError_t hip_err; size_t num_bytes = size_t(this->m_n) * std::abs(this->m_inc) * sizeof(T); for(int64_t batch_index = 0; batch_index < this->m_batch_count; ++batch_index) { if(hipSuccess != (hip_err = hipMemcpy( (*this)[batch_index], that[batch_index], num_bytes, hipMemcpyDeviceToHost))) { return hip_err; } } return hipSuccess; } //! //! @brief Check if memory exists. //! @return hipSuccess if memory exists, hipErrorOutOfMemory otherwise. //! hipError_t memcheck() const { return (nullptr != this->m_data) ? hipSuccess : hipErrorOutOfMemory; } private: int64_t m_n{}; int64_t m_inc{}; int64_t m_batch_count{}; T** m_data{}; bool try_initialize_memory() { bool success = (nullptr != (this->m_data = (T**)calloc(this->m_batch_count, sizeof(T*)))); if(success) { size_t nmemb = size_t(this->m_n) * std::abs(this->m_inc); for(int64_t batch_index = 0; batch_index < this->m_batch_count; ++batch_index) { success = (nullptr != (this->m_data[batch_index] = (T*)calloc(nmemb, sizeof(T)))); if(false == success) { break; } } } return success; } void free_memory() { if(nullptr != this->m_data) { for(int64_t batch_index = 0; batch_index < this->m_batch_count; ++batch_index) { if(nullptr != this->m_data[batch_index]) { free(this->m_data[batch_index]); this->m_data[batch_index] = nullptr; } } free(this->m_data); this->m_data = nullptr; } } };