/*! \file */ /* ************************************************************************ * Copyright (C) 2019-2026 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 * copies 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 * IMPLIED, 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 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * * ************************************************************************ */ #pragma once #ifndef ROCSPARSE_VECTOR_HPP #define ROCSPARSE_VECTOR_HPP #include "rocsparse_allocator.hpp" #include "rocsparse_clients_float16.hpp" #include "rocsparse_clients_routine_trace.hpp" #include "rocsparse_init.hpp" template struct dense_vector; template struct host_vector; template using host_dense_vector = dense_vector; template using device_dense_vector = dense_vector; template using managed_dense_vector = dense_vector; template struct dense_vector_t { protected: size_t m_size; T* m_val; public: using value_type = T; dense_vector_t(size_t size, T* val); dense_vector_t& operator()(size_t size, T* val) { m_size = size; m_val = val; return *this; } size_t size() const; operator T*(); operator const T*() const; T* data(); const T* data() const; ~dense_vector_t(); // Disallow copying or assigning dense_vector_t(const dense_vector_t&) = delete; template dense_vector_t(const dense_vector_t&) = delete; dense_vector_t& operator=(const dense_vector_t&); template dense_vector_t& operator=(const dense_vector_t&); template void unit_check(const dense_vector_t& that_) const { ROCSPARSE_CLIENTS_ROUTINE_TRACE; switch(MODE) { case memory_mode::device: { host_dense_vector on_host(*this); on_host.unit_check(that_); break; } case memory_mode::managed: case memory_mode::host: { switch(THAT_MODE) { case memory_mode::managed: case memory_mode::host: { unit_check_scalar(this->size(), that_.size()); unit_check_segments(this->size(), this->data(), that_.data()); break; } case memory_mode::device: { host_dense_vector that(that_); this->unit_check(that); break; } } break; } } } template void near_check(const dense_vector_t& that_, floating_data_t tol_ = default_tolerance::value) const { ROCSPARSE_CLIENTS_ROUTINE_TRACE; switch(MODE) { case memory_mode::device: { host_dense_vector on_host(*this, true); on_host.near_check(that_, tol_); break; } case memory_mode::managed: case memory_mode::host: { switch(THAT_MODE) { case memory_mode::managed: case memory_mode::host: { unit_check_scalar(this->size(), that_.size()); near_check_segments(this->size(), this->data(), that_.data(), tol_); break; } case memory_mode::device: { host_dense_vector that(that_); this->near_check(that, tol_); break; } } break; } } } void print() const; template void transfer_from(const dense_vector_t& that) { ROCSPARSE_CLIENTS_ROUTINE_TRACE; CHECK_HIP_THROW_ERROR(this->size() == that.size() ? hipSuccess : hipErrorInvalidValue); auto err = hipMemcpy(this->data(), that.data(), sizeof(T) * that.size(), memory_mode::get_hipMemcpyKind(MODE, THAT_MODE)); CHECK_HIP_THROW_ERROR(err); } void transfer_to(std::vector& that) const; void transfer_from(const host_vector& that); void unit_check(const host_vector& that_) const; void near_check(const host_vector& that_, floating_data_t tol_ = default_tolerance::value) const; }; template struct host_vector : std::vector { // Inherit constructors using std::vector::vector; // Decay into pointer wherever pointer is expected operator T*() { return this->data(); } operator const T*() const { return this->data(); } T& operator[](int64_t index) { return this->data()[index]; } template void transfer_from(const dense_vector_t& that) { ROCSPARSE_CLIENTS_ROUTINE_TRACE; CHECK_HIP_THROW_ERROR(this->size() == that.size() ? hipSuccess : hipErrorInvalidValue); CHECK_HIP_THROW_ERROR( hipMemcpy(this->data(), that.data(), sizeof(T) * that.size(), memory_mode::get_hipMemcpyKind(memory_mode::host, THAT_MODE))); } void transfer_from(const host_vector& that) { ROCSPARSE_CLIENTS_ROUTINE_TRACE; CHECK_HIP_THROW_ERROR(this->size() == that.size() ? hipSuccess : hipErrorInvalidValue); CHECK_HIP_THROW_ERROR( hipMemcpy(this->data(), that.data(), sizeof(T) * that.size(), memory_mode::get_hipMemcpyKind(memory_mode::host, memory_mode::host))); } template void unit_check(const dense_vector_t& that_) const { ROCSPARSE_CLIENTS_ROUTINE_TRACE; that_.unit_check(*this); } template void near_check(const dense_vector_t& that_, floating_data_t tol_ = default_tolerance::value) const { ROCSPARSE_CLIENTS_ROUTINE_TRACE; that_.near_check(*this, tol_); } void unit_check(const host_vector& that_) const { ROCSPARSE_CLIENTS_ROUTINE_TRACE; unit_check_scalar(this->size(), that_.size()); unit_check_segments(this->size(), this->data(), that_); } void near_check(const host_vector& that_, floating_data_t tol_ = default_tolerance::value) const { ROCSPARSE_CLIENTS_ROUTINE_TRACE; unit_check_scalar(this->size(), that_.size()); near_check_segments(this->size(), this->data(), that_.data(), tol_); } template void transfer_from(const T* that) { ROCSPARSE_CLIENTS_ROUTINE_TRACE; CHECK_HIP_THROW_ERROR( hipMemcpy(this->data(), that, sizeof(T) * this->size(), memory_mode::get_hipMemcpyKind(memory_mode::host, THAT_MODE))); }; void print(std::ostream& out) const { ROCSPARSE_CLIENTS_ROUTINE_TRACE; const size_t N = this->size(); for(size_t i = 0; i < N; ++i) { out << "[" << i << "] = " << (*this)[i] << std::endl; } } void print_limited(std::ostream& out, size_t bound) const { ROCSPARSE_CLIENTS_ROUTINE_TRACE; const size_t N = this->size(); for(size_t i = 0; i < N; ++i) { out << "[" << i << "] = " << (*this)[i] << std::endl; if(i >= bound) break; } } }; template struct dense_vector : dense_vector_t { private: using allocator = rocsparse_allocator; public: dense_vector() : dense_vector_t(0, nullptr){}; ~dense_vector() { #ifdef GOOGLE_TEST allocator::check_guards(this->data(), this->size()); #endif allocator::free(this->data()); }; hipError_t memcheck() const { return ((this->m_size == 0) && (this->data() == nullptr)) ? hipSuccess : (((this->m_size > 0) && (this->data() != nullptr)) ? hipSuccess : hipErrorOutOfMemory); } // Tell whether malloc failed void resize(size_t s) { ROCSPARSE_CLIENTS_ROUTINE_TRACE; if(s != this->m_size) { if(this->m_val) { allocator::free(this->m_val); } this->m_val = allocator::malloc(s); this->m_size = s; } } explicit dense_vector(size_t s) : dense_vector_t(s, allocator::malloc(s)) { } explicit dense_vector(const host_vector& that, bool transfer = true) : dense_vector_t(that.size(), allocator::malloc(that.size())) { ROCSPARSE_CLIENTS_ROUTINE_TRACE; if(transfer) { this->transfer_from(that); } } explicit dense_vector(const dense_vector& that, bool transfer = true) : dense_vector_t(that.size(), allocator::malloc(that.size())) { ROCSPARSE_CLIENTS_ROUTINE_TRACE; if(transfer) { this->transfer_from(that); } } explicit dense_vector(const dense_vector_t& that, bool transfer = true) : dense_vector_t(that.size(), allocator::malloc(that.size())) { ROCSPARSE_CLIENTS_ROUTINE_TRACE; if(transfer) { this->transfer_from(that); } } template explicit dense_vector(const dense_vector_t& that, bool transfer = true) : dense_vector_t(that.size(), allocator::malloc(that.size())) { ROCSPARSE_CLIENTS_ROUTINE_TRACE; if(transfer) { this->transfer_from(that); } } }; template dense_vector_t::dense_vector_t(size_t size, T* val) : m_size(size) , m_val(val) { } template size_t dense_vector_t::size() const { return this->m_size; } template dense_vector_t::operator T*() { return this->m_val; } template dense_vector_t::operator const T*() const { return this->m_val; } template T* dense_vector_t::data() { return this->m_val; } template const T* dense_vector_t::data() const { return this->m_val; } template dense_vector_t::~dense_vector_t() { } template void dense_vector_t::unit_check(const host_vector& that_) const { ROCSPARSE_CLIENTS_ROUTINE_TRACE; switch(MODE) { case memory_mode::device: { host_dense_vector on_host(*this); on_host.unit_check(that_); break; } case memory_mode::managed: case memory_mode::host: { unit_check_scalar(this->size(), that_.size()); unit_check_segments(this->size(), this->data(), that_.data()); break; } } } template void dense_vector_t::near_check(const host_vector& that_, floating_data_t tol_) const { ROCSPARSE_CLIENTS_ROUTINE_TRACE; switch(MODE) { case memory_mode::device: { host_dense_vector on_host(*this); on_host.near_check(that_, tol_); break; } case memory_mode::managed: case memory_mode::host: { unit_check_scalar(this->size(), that_.size()); near_check_segments(this->size(), this->data(), that_.data(), tol_); break; } } } template void dense_vector_t::transfer_from(const host_vector& that) { ROCSPARSE_CLIENTS_ROUTINE_TRACE; CHECK_HIP_THROW_ERROR(this->size() == that.size() ? hipSuccess : hipErrorInvalidValue); auto err = hipMemcpy(this->data(), that.data(), sizeof(T) * that.size(), memory_mode::get_hipMemcpyKind(MODE, memory_mode::host)); CHECK_HIP_THROW_ERROR(err); } template void dense_vector_t::transfer_to(std::vector& that) const { ROCSPARSE_CLIENTS_ROUTINE_TRACE; that.resize(this->m_size); CHECK_HIP_THROW_ERROR(hipMemcpy(that.data(), this->data(), sizeof(T) * this->size(), memory_mode::get_hipMemcpyKind(memory_mode::host, MODE))); } template void dense_vector_t::print() const { ROCSPARSE_CLIENTS_ROUTINE_TRACE; switch(MODE) { case memory_mode::host: case memory_mode::managed: { size_t N = this->size(); const T* x = this->data(); for(size_t i = 0; i < N; ++i) { std::cout << " " << x[i] << std::endl; } break; } case memory_mode::device: { dense_vector on_host(*this, true); on_host.print(); break; } } }; /* ============================================================================================ */ /*! \brief pseudo-vector subclass which uses host memory */ template struct memory_traits; template <> struct memory_traits { template using array_t = device_dense_vector; }; template <> struct memory_traits { template using array_t = managed_dense_vector; }; // // For compatibility. // template <> struct memory_traits { template using array_t = host_vector; }; template using device_vector = device_dense_vector; #endif // ROCSPARSE_VECTOR_HPP