Files
TheRock/rocm-libraries/projects/hipsolver/clients/include/utility.hpp
T
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

805 lines
25 KiB
C++

/* ************************************************************************
* Copyright (C) 2020-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 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
#include "hipsolver.h"
#ifdef __cplusplus
#include "complex.hpp"
#include "hipsolver_datatype2string.hpp"
#include <cassert>
#include <cmath>
#include <random>
#include <type_traits>
#include <vector>
#endif
#include <stdio.h>
#include <stdlib.h>
/*!\file
* \brief provide data initialization, timing, hipsolver type <-> lapack char conversion utilities.
*/
#ifdef GOOGLE_TEST
#include <gtest/gtest.h>
#define CHECK_HIP_ERROR(error) ASSERT_EQ(error, hipSuccess)
inline void hipsolver_expect_status(hipsolverStatus_t status, hipsolverStatus_t expected)
{
if(status != HIPSOLVER_STATUS_NOT_SUPPORTED)
ASSERT_EQ(status, expected);
}
#define EXPECT_ROCBLAS_STATUS(status, expected) hipsolver_expect_status(status, expected)
#define CHECK_ROCBLAS_ERROR(status) hipsolver_expect_status(status, HIPSOLVER_STATUS_SUCCESS)
#else
#define CHECK_HIP_ERROR(error) \
do \
{ \
if(error != hipSuccess) \
{ \
fprintf(stderr, \
"error: '%s'(%d) at %s:%d\n", \
hipGetErrorString(error), \
error, \
__FILE__, \
__LINE__); \
exit(EXIT_FAILURE); \
} \
} while(0)
inline void hipsolver_expect_status(hipsolverStatus_t status, hipsolverStatus_t expected)
{
if(status != expected && status != HIPSOLVER_STATUS_NOT_SUPPORTED)
{
fprintf(stderr,
"hipSOLVER status error: Expected: %s, Actual: %s\n",
hipsolver2string_status(expected),
hipsolver2string_status(status));
if(expected == HIPSOLVER_STATUS_SUCCESS)
exit(EXIT_FAILURE);
}
}
#define EXPECT_ROCBLAS_STATUS(status, expected) hipsolver_expect_status(status, expected)
#define CHECK_ROCBLAS_ERROR(status) hipsolver_expect_status(status, HIPSOLVER_STATUS_SUCCESS)
// The info provided to EXPECT macros is used in hipsolver-test, but
// in hipsolver-bench, the information is just discarded.
struct hipsolver_info_discarder
{
template <typename T>
hipsolver_info_discarder& operator<<(T&&)
{
return *this;
}
};
#define EXPECT_EQ(v1, v2) hipsolver_info_discarder()
#define EXPECT_NE(v1, v2) hipsolver_info_discarder()
#define EXPECT_LT(v1, v2) hipsolver_info_discarder()
#define EXPECT_LE(v1, v2) hipsolver_info_discarder()
#define EXPECT_GT(v1, v2) hipsolver_info_discarder()
#define EXPECT_GE(v1, v2) hipsolver_info_discarder()
#endif
#ifdef __cplusplus
/* ============================================================================================
*/
/*! \brief local handle which is automatically created and destroyed */
class hipsolver_local_handle
{
hipsolverHandle_t m_handle;
public:
hipsolver_local_handle()
{
if(hipsolverCreate(&m_handle) != HIPSOLVER_STATUS_SUCCESS)
throw std::runtime_error("ERROR: Could not create hipsolverHandle_t");
}
~hipsolver_local_handle()
{
hipsolverDestroy(m_handle);
}
hipsolver_local_handle(const hipsolver_local_handle&) = delete;
hipsolver_local_handle(hipsolver_local_handle&&) = delete;
hipsolver_local_handle& operator=(const hipsolver_local_handle&) = delete;
hipsolver_local_handle& operator=(hipsolver_local_handle&&) = delete;
// Allow hipsolver_local_handle to be used anywhere hipsolverHandle_t is expected
operator hipsolverHandle_t&()
{
return m_handle;
}
operator const hipsolverHandle_t&() const
{
return m_handle;
}
};
class hipsolverRf_local_handle
{
hipsolverRfHandle_t m_handle;
public:
hipsolverRf_local_handle()
{
if(hipsolverRfCreate(&m_handle) != HIPSOLVER_STATUS_SUCCESS)
throw std::runtime_error("ERROR: Could not create hipsolverRfHandle_t");
}
~hipsolverRf_local_handle()
{
hipsolverRfDestroy(m_handle);
}
hipsolverRf_local_handle(const hipsolverRf_local_handle&) = delete;
hipsolverRf_local_handle(hipsolverRf_local_handle&&) = delete;
hipsolverRf_local_handle& operator=(const hipsolverRf_local_handle&) = delete;
hipsolverRf_local_handle& operator=(hipsolverRf_local_handle&&) = delete;
// Allow hipsolverRf_local_handle to be used anywhere hipsolverRfHandle_t is expected
operator hipsolverRfHandle_t&()
{
return m_handle;
}
operator const hipsolverRfHandle_t&() const
{
return m_handle;
}
};
class hipsolverSp_local_handle
{
hipsolverSpHandle_t m_handle;
public:
hipsolverSp_local_handle()
{
if(hipsolverSpCreate(&m_handle) != HIPSOLVER_STATUS_SUCCESS)
throw std::runtime_error("ERROR: Could not create hipsolverSpHandle_t");
}
~hipsolverSp_local_handle()
{
hipsolverSpDestroy(m_handle);
}
hipsolverSp_local_handle(const hipsolverSp_local_handle&) = delete;
hipsolverSp_local_handle(hipsolverSp_local_handle&&) = delete;
hipsolverSp_local_handle& operator=(const hipsolverSp_local_handle&) = delete;
hipsolverSp_local_handle& operator=(hipsolverSp_local_handle&&) = delete;
// Allow hipsolverSp_local_handle to be used anywhere hipsolverSpHandle_t is expected
operator hipsolverSpHandle_t&()
{
return m_handle;
}
operator const hipsolverSpHandle_t&() const
{
return m_handle;
}
};
/* ============================================================================================
*/
/*! \brief local gesvdj params which is automatically created and destroyed */
class hipsolver_local_gesvdj_info
{
hipsolverGesvdjInfo_t m_info;
public:
hipsolver_local_gesvdj_info()
{
if(hipsolverDnCreateGesvdjInfo(&m_info) != HIPSOLVER_STATUS_SUCCESS)
throw std::runtime_error("ERROR: Could not create hipsolverGesvdjInfo_t");
}
~hipsolver_local_gesvdj_info()
{
hipsolverDnDestroyGesvdjInfo(m_info);
}
hipsolver_local_gesvdj_info(const hipsolver_local_gesvdj_info&) = delete;
hipsolver_local_gesvdj_info(hipsolver_local_gesvdj_info&&) = delete;
hipsolver_local_gesvdj_info& operator=(const hipsolver_local_gesvdj_info&) = delete;
hipsolver_local_gesvdj_info& operator=(hipsolver_local_gesvdj_info&&) = delete;
// Allow hipsolver_local_gesvdj_info to be used anywhere hipsolverGesvdjInfo_t is expected
operator hipsolverGesvdjInfo_t&()
{
return m_info;
}
operator const hipsolverGesvdjInfo_t&() const
{
return m_info;
}
};
/* ============================================================================================
*/
/*! \brief local syevj params which is automatically created and destroyed */
class hipsolver_local_syevj_info
{
hipsolverSyevjInfo_t m_info;
public:
hipsolver_local_syevj_info()
{
if(hipsolverDnCreateSyevjInfo(&m_info) != HIPSOLVER_STATUS_SUCCESS)
throw std::runtime_error("ERROR: Could not create hipsolverSyevjInfo_t");
}
~hipsolver_local_syevj_info()
{
hipsolverDnDestroySyevjInfo(m_info);
}
hipsolver_local_syevj_info(const hipsolver_local_syevj_info&) = delete;
hipsolver_local_syevj_info(hipsolver_local_syevj_info&&) = delete;
hipsolver_local_syevj_info& operator=(const hipsolver_local_syevj_info&) = delete;
hipsolver_local_syevj_info& operator=(hipsolver_local_syevj_info&&) = delete;
// Allow hipsolver_local_syevj_info to be used anywhere hipsolverSyevjInfo_t is expected
operator hipsolverSyevjInfo_t&()
{
return m_info;
}
operator const hipsolverSyevjInfo_t&() const
{
return m_info;
}
};
/* ============================================================================================
*/
/*! \brief local params which is automatically created and destroyed */
class hipsolver_local_params
{
hipsolverDnParams_t m_info;
public:
hipsolver_local_params()
{
if(hipsolverDnCreateParams(&m_info) != HIPSOLVER_STATUS_SUCCESS)
throw std::runtime_error("ERROR: Could not create hipsolverDnParams_t");
}
~hipsolver_local_params()
{
hipsolverDnDestroyParams(m_info);
}
hipsolver_local_params(const hipsolver_local_params&) = delete;
hipsolver_local_params(hipsolver_local_params&&) = delete;
hipsolver_local_params& operator=(const hipsolver_local_params&) = delete;
hipsolver_local_params& operator=(hipsolver_local_params&&) = delete;
// Allow hipsolver_local_params to be used anywhere hipsolverDnParams_t is expected
operator hipsolverDnParams_t&()
{
return m_info;
}
operator const hipsolverDnParams_t&() const
{
return m_info;
}
};
/* ============================================================================================
*/
// Return true if value is NaN
template <typename T>
inline bool hipsolver_isnan(T)
{
return false;
}
inline bool hipsolver_isnan(double arg)
{
return std::isnan(arg);
}
inline bool hipsolver_isnan(float arg)
{
return std::isnan(arg);
}
inline bool hipsolver_isnan(hipsolverComplex arg)
{
return std::isnan(arg.real()) || std::isnan(arg.imag());
}
inline bool hipsolver_isnan(hipsolverDoubleComplex arg)
{
return std::isnan(arg.real()) || std::isnan(arg.imag());
}
/* =============================================================================================== */
/* Complex / real helpers. */
/* Workaround for clang bug:
https://bugs.llvm.org/show_bug.cgi?id=35863
*/
template <typename T>
inline constexpr bool is_complex = false;
// cppcheck-suppress syntaxError
template <>
inline constexpr bool is_complex<hipsolverComplex> = true;
template <>
inline constexpr bool is_complex<hipsolverDoubleComplex> = true;
// Get base types from complex types.
template <typename T, typename = void>
struct real_t_impl
{
using type = T;
};
template <typename T>
struct real_t_impl<T, std::enable_if_t<is_complex<T>>>
{
using type = decltype(T{}.real());
};
template <typename T>
using real_t = typename real_t_impl<T>::type;
/* ============================================================================================ */
/*! \brief Random number generator which generates NaN values */
using hipsolver_rng_t = std::mt19937;
extern hipsolver_rng_t hipsolver_rng, hipsolver_seed;
// Reset the seed (mainly to ensure repeatability of failures in a given suite)
inline void hipsolver_seedrand()
{
hipsolver_rng = hipsolver_seed;
}
class hipsolver_nan_rng
{
// Generate random NaN values
template <typename T, typename UINT_T, int SIG, int EXP>
static T random_nan_data()
{
static_assert(sizeof(UINT_T) == sizeof(T), "Type sizes do not match");
union u_t
{
u_t() {}
UINT_T u;
T fp;
} x;
do
x.u = std::uniform_int_distribution<UINT_T>{}(hipsolver_rng);
while(!(x.u & (((UINT_T)1 << SIG) - 1))); // Reject Inf (mantissa == 0)
x.u |= (((UINT_T)1 << EXP) - 1) << SIG; // Exponent = all 1's
return x.fp; // NaN with random bits
}
public:
// Random integer
template <typename T, typename std::enable_if<std::is_integral<T>{}, int>::type = 0>
explicit operator T() const
{
return std::uniform_int_distribution<T>{}(hipsolver_rng);
}
// Random NaN float
explicit operator float() const
{
return random_nan_data<float, uint32_t, 23, 8>();
}
// Random NaN double
explicit operator double() const
{
return random_nan_data<double, uint64_t, 52, 11>();
}
// Random NaN Complex
explicit operator hipsolverComplex() const
{
return {float(*this), float(*this)};
}
// Random NaN Double Complex
explicit operator hipsolverDoubleComplex() const
{
return {double(*this), double(*this)};
}
};
/* ============================================================================================ */
/* generate random number :*/
/*! \brief generate a random number in range [1,2,3,4,5,6,7,8,9,10] */
template <typename T>
T random_generator()
{
return std::uniform_int_distribution<int>(1, 10)(hipsolver_rng);
};
// for hipsolverComplex, generate 2 floats
/*! \brief generate two random numbers in range [1,2,3,4,5,6,7,8,9,10] */
template <>
inline hipsolverComplex random_generator<hipsolverComplex>()
{
return hipsolverComplex(float(std::uniform_int_distribution<int>(1, 10)(hipsolver_rng)),
float(std::uniform_int_distribution<int>(1, 10)(hipsolver_rng)));
}
// for hipsolverDoubleComplex, generate 2 doubles
/*! \brief generate two random numbers in range [1,2,3,4,5,6,7,8,9,10] */
template <>
inline hipsolverDoubleComplex random_generator<hipsolverDoubleComplex>()
{
return hipsolverDoubleComplex(double(std::uniform_int_distribution<int>(1, 10)(hipsolver_rng)),
double(std::uniform_int_distribution<int>(1, 10)(hipsolver_rng)));
}
/*! \brief generate a random number in range [-1,-2,-3,-4,-5,-6,-7,-8,-9,-10] */
template <typename T>
inline T random_generator_negative()
{
return std::uniform_int_distribution<int>(-10, -1)(hipsolver_rng);
};
// for complex, generate two values, convert both to negative
/*! \brief generate a random real value in range [-1, -10] and random
* imaginary value in range [-1, -10]
*/
template <>
inline hipsolverComplex random_generator_negative<hipsolverComplex>()
{
return hipsolverComplex(float(std::uniform_int_distribution<int>(-10, -1)(hipsolver_rng)),
float(std::uniform_int_distribution<int>(-10, -1)(hipsolver_rng)));
}
template <>
inline hipsolverDoubleComplex random_generator_negative<hipsolverDoubleComplex>()
{
return hipsolverDoubleComplex(
double(std::uniform_int_distribution<int>(-10, -1)(hipsolver_rng)),
double(std::uniform_int_distribution<int>(-10, -1)(hipsolver_rng)));
}
/* ============================================================================================ */
/* ============================================================================================ */
/*! \brief Packs strided_batched matricies into groups of 4 in N */
template <typename T>
void hipsolver_packInt8(
std::vector<T>& A, size_t M, size_t N, size_t lda, size_t batch_count = 1, size_t stride_a = 0)
{
std::vector<T> temp(A);
for(size_t b = 0; b < batch_count; b++)
for(size_t colBase = 0; colBase < N; colBase += 4)
for(size_t row = 0; row < lda; row++)
for(size_t colOffset = 0; colOffset < 4; colOffset++)
A[(colBase * lda + 4 * row) + colOffset + (stride_a * b)]
= temp[(colBase + colOffset) * lda + row + (stride_a * b)];
}
/* ============================================================================================ */
/* ============================================================================================ */
/*! \brief turn float -> 's', double -> 'd', hipsolverComplex -> 'c', hipsolverDoubleComplex
* -> 'z' */
template <typename T>
char type2char();
/* ============================================================================================ */
/*! \brief turn float -> int, double -> int, hipsolverComplex.real() -> int,
* hipsolverDoubleComplex.real() -> int */
template <typename T>
int type2int(T val);
/* ============================================================================================ */
/*! \brief Debugging purpose, print out CPU and GPU result matrix, not valid in complex number */
template <typename T, std::enable_if_t<!is_complex<T>, int> = 0>
void print_matrix(T* result, int m, int n, int lda)
{
for(int i = 0; i < m; i++)
for(int j = 0; j < n; j++)
printf("matrix col %d, row %d, result=%.8g\n", j, i, double(result[i + j * lda]));
}
/*! \brief Debugging purpose, print out CPU and GPU result matrix, valid for complex number */
template <typename T, std::enable_if_t<+is_complex<T>, int> = 0>
void print_matrix(T* result, int m, int n, int lda)
{
for(int i = 0; i < m; i++)
for(int j = 0; j < n; j++)
printf("matrix col %d, row %d, result=(%.8g,%.8g)\n",
j,
i,
double(result[i + j * lda].real()),
double(result[i + j * lda].imag()));
}
template <typename T, std::enable_if_t<!is_complex<T>, int> = 0>
void print_matrix(T* CPU_result, T* GPU_result, int m, int n, int lda)
{
for(int i = 0; i < m; i++)
for(int j = 0; j < n; j++)
printf("matrix col %d, row %d, CPU result=%.8g, GPU result=%.8g\n",
j,
i,
double(CPU_result[i + j * lda]),
double(GPU_result[i + j * lda]));
}
/*! \brief Debugging purpose, print out CPU and GPU result matrix, valid for complex number */
template <typename T, std::enable_if_t<+is_complex<T>, int> = 0>
void print_matrix(T* CPU_result, T* GPU_result, int m, int n, int lda)
{
for(int i = 0; i < m; i++)
for(int j = 0; j < n; j++)
printf("matrix col %d, row %d, CPU result=(%.8g,%.8g), GPU result=(%.8g,%.8g)\n",
j,
i,
double(CPU_result[i + j * lda].real()),
double(CPU_result[i + j * lda].imag()),
double(GPU_result[i + j * lda].real()),
double(GPU_result[i + j * lda].imag()));
}
/*! \brief Debugging purpose, print out sparse matrix, not valid in complex number */
template <typename T, std::enable_if_t<!is_complex<T>, int> = 0>
void print_sparse_matrix(int m, int n, int* csrRowPtr, int* csrColInd, T* csrVal)
{
printf("%d by %d matrix\n", m, n);
int idx = 0;
for(int i = 0; i < m; i++)
{
printf(" ");
for(int j = 0; j < n; j++)
{
if(idx < csrRowPtr[i + 1] && j == csrColInd[idx])
{
printf("%.8g, ", csrVal[idx]);
idx++;
}
else
printf("0, ");
}
printf("\n");
}
printf("\n");
}
/* ============================================================================================ */
/* read matrix or values from file */
// integers:
inline void
read_matrix(const std::string filenameS, const int m, const int n, int* A, const int lda)
{
const char* filename = filenameS.c_str();
FILE* mat;
mat = fopen(filename, "r");
int v;
if(mat == NULL)
throw std::invalid_argument(std::string("Error: Could not open file ") + filename
+ " with test data...");
for(int j = 0; j < n; ++j)
{
for(int i = 0; i < m; ++i)
{
int read = fscanf(mat, "%d", &v);
if(read != 1)
throw std::out_of_range(std::string("Error: Could not read element from file ")
+ filename);
A[i + j * lda] = v;
}
}
fclose(mat);
}
inline void read_last(const std::string filenameS, int* A)
{
const char* filename = filenameS.c_str();
FILE* mat;
mat = fopen(filename, "r");
int v;
if(mat == NULL)
throw std::invalid_argument(std::string("Error: Could not open file ") + filename
+ " with test data...");
while(fscanf(mat, "%d", &v) == 1)
{
// do nothing
}
*A = v;
}
// singles:
inline void
read_matrix(const std::string filenameS, const int m, const int n, float* A, const int lda)
{
const char* filename = filenameS.c_str();
FILE* mat;
mat = fopen(filename, "r");
float v;
if(mat == NULL)
throw std::invalid_argument(std::string("Error: Could not open file ") + filename
+ " with test data...");
for(int j = 0; j < n; ++j)
{
for(int i = 0; i < m; ++i)
{
int read = fscanf(mat, "%g", &v);
if(read != 1)
throw std::out_of_range(std::string("Error: Could not read element from file ")
+ filename);
A[i + j * lda] = v;
}
}
fclose(mat);
}
// doubles:
inline void
read_matrix(const std::string filenameS, const int m, const int n, double* A, const int lda)
{
const char* filename = filenameS.c_str();
FILE* mat;
mat = fopen(filename, "r");
double v;
if(mat == NULL)
throw std::invalid_argument(std::string("Error: Could not open file ") + filename
+ " with test data...");
for(int j = 0; j < n; ++j)
{
for(int i = 0; i < m; ++i)
{
int read = fscanf(mat, "%lg", &v);
if(read != 1)
throw std::out_of_range(std::string("Error: Could not read element from file ")
+ filename);
A[i + j * lda] = v;
}
}
fclose(mat);
}
// complex float:
inline void read_matrix(
const std::string filenameS, const int m, const int n, hipsolverComplex* A, const int lda)
{
const char* filename = filenameS.c_str();
FILE* mat;
mat = fopen(filename, "r");
float v;
if(mat == NULL)
throw std::invalid_argument(std::string("Error: Could not open file ") + filename
+ " with test data...");
for(int j = 0; j < n; ++j)
{
for(int i = 0; i < m; ++i)
{
int read = fscanf(mat, "%g", &v);
if(read != 1)
throw std::out_of_range(std::string("Error: Could not read element from file ")
+ filename);
A[i + j * lda] = {v, 0};
}
}
fclose(mat);
}
// complex double:
inline void read_matrix(
const std::string filenameS, const int m, const int n, hipsolverDoubleComplex* A, const int lda)
{
const char* filename = filenameS.c_str();
FILE* mat;
mat = fopen(filename, "r");
double v;
if(mat == NULL)
throw std::invalid_argument(std::string("Error: Could not open file ") + filename
+ " with test data...");
for(int j = 0; j < n; ++j)
{
for(int i = 0; i < m; ++i)
{
int read = fscanf(mat, "%lg", &v);
if(read != 1)
throw std::out_of_range(std::string("Error: Could not read element from file ")
+ filename);
A[i + j * lda] = {v, 0};
}
}
fclose(mat);
}
/* =============================================================================================== */
/* ============================================================================================ */
#endif // __cplusplus
#ifdef __cplusplus
extern "C" {
#endif
/* ============================================================================================ */
/* timing: HIP only provides very limited timers function clock() and not general;
hipsolver sync CPU and device and use more accurate CPU timer*/
/*! \brief CPU Timer(in microsecond): synchronize with the default device and return wall time */
double get_time_us();
/*! \brief CPU Timer(in microsecond): synchronize with given queue/stream and return wall time */
double get_time_us_sync(hipStream_t stream);
/*! \brief CPU Timer(in microsecond): no GPU synchronization and return wall time */
double get_time_us_no_sync();
#ifdef __cplusplus
}
#endif
/* ============================================================================================ */