/* ************************************************************************ * Copyright (C) 2023 Advanced Micro Devices, Inc. * ************************************************************************ */ #pragma once #include "clientcommon.hpp" #include "hipsolverSp.hpp" template void csrlsvchol_checkBadArgs(hipsolverSpHandle_t handle, const int n, const int nnzA, const hipsparseMatDescr_t descrA, int* ptrA, int* indA, T valA, T B, T X, int* singularity) { // handle EXPECT_ROCBLAS_STATUS( hipsolver_csrlsvchol( HOST, nullptr, n, nnzA, descrA, valA, ptrA, indA, B, 0, 0, X, singularity), HIPSOLVER_STATUS_NOT_INITIALIZED); // values // N/A #if defined(__HIP_PLATFORM_HCC__) || defined(__HIP_PLATFORM_AMD__) // pointers EXPECT_ROCBLAS_STATUS( hipsolver_csrlsvchol( HOST, handle, n, nnzA, nullptr, valA, ptrA, indA, B, 0, 0, X, singularity), HIPSOLVER_STATUS_INVALID_VALUE); EXPECT_ROCBLAS_STATUS( hipsolver_csrlsvchol( HOST, handle, n, nnzA, descrA, (T) nullptr, ptrA, indA, B, 0, 0, X, singularity), HIPSOLVER_STATUS_INVALID_VALUE); EXPECT_ROCBLAS_STATUS( hipsolver_csrlsvchol( HOST, handle, n, nnzA, descrA, valA, (int*)nullptr, indA, B, 0, 0, X, singularity), HIPSOLVER_STATUS_INVALID_VALUE); EXPECT_ROCBLAS_STATUS( hipsolver_csrlsvchol( HOST, handle, n, nnzA, descrA, valA, ptrA, (int*)nullptr, B, 0, 0, X, singularity), HIPSOLVER_STATUS_INVALID_VALUE); EXPECT_ROCBLAS_STATUS( hipsolver_csrlsvchol( HOST, handle, n, nnzA, descrA, valA, ptrA, indA, (T) nullptr, 0, 0, X, singularity), HIPSOLVER_STATUS_INVALID_VALUE); EXPECT_ROCBLAS_STATUS( hipsolver_csrlsvchol( HOST, handle, n, nnzA, descrA, valA, ptrA, indA, B, 0, 0, (T) nullptr, singularity), HIPSOLVER_STATUS_INVALID_VALUE); #endif } template void testing_csrlsvchol_bad_arg() { // safe arguments hipsolverSp_local_handle handle; int n = 1; int nnzA = 1; hipsparse_local_mat_descr descrA; hipsparseSetMatType(descrA, HIPSPARSE_MATRIX_TYPE_GENERAL); hipsparseSetMatIndexBase(descrA, HIPSPARSE_INDEX_BASE_ZERO); if(HOST) { // memory allocations host_strided_batch_vector singularity(1, 1, 1, 1); host_strided_batch_vector ptrA(1, 1, 1, 1); host_strided_batch_vector indA(1, 1, 1, 1); host_strided_batch_vector valA(1, 1, 1, 1); host_strided_batch_vector B(1, 1, 1, 1); host_strided_batch_vector X(1, 1, 1, 1); // check bad arguments csrlsvchol_checkBadArgs(handle, n, nnzA, descrA, ptrA.data(), indA.data(), valA.data(), B.data(), X.data(), singularity.data()); } else { // memory allocations host_strided_batch_vector singularity(1, 1, 1, 1); device_strided_batch_vector ptrA(1, 1, 1, 1); device_strided_batch_vector indA(1, 1, 1, 1); device_strided_batch_vector valA(1, 1, 1, 1); device_strided_batch_vector B(1, 1, 1, 1); device_strided_batch_vector X(1, 1, 1, 1); CHECK_HIP_ERROR(ptrA.memcheck()); CHECK_HIP_ERROR(indA.memcheck()); CHECK_HIP_ERROR(valA.memcheck()); CHECK_HIP_ERROR(B.memcheck()); CHECK_HIP_ERROR(X.memcheck()); // check bad arguments csrlsvchol_checkBadArgs(handle, n, nnzA, descrA, ptrA.data(), indA.data(), valA.data(), B.data(), X.data(), singularity.data()); } } template void csrlsvchol_initData(hipsolverSpHandle_t handle, const int n, const int nnzA, hipsparseMatDescr_t descrA, Ud& dptrA, Ud& dindA, Td& dvalA, Td& dB, Uh& hptrA, Uh& hindA, Th& hvalA, Th& hB, Th& hX, const fs::path testcase, bool test = true) { if(CPU) { fs::path file; // read-in A file = testcase / "ptrA"; read_matrix(file.string(), 1, n + 1, hptrA.data(), 1); file = testcase / "indA"; read_matrix(file.string(), 1, nnzA, hindA.data(), 1); file = testcase / "valA"; read_matrix(file.string(), 1, nnzA, hvalA.data(), 1); // read-in B file = testcase / "B_1"; read_matrix(file.string(), n, 1, hB.data(), n); // get results (matrix X) if validation is required if(test) { // read-in X file = testcase / "X_1"; read_matrix(file.string(), n, 1, hX.data(), n); } // change to base 1, if applicable hipsparseIndexBase_t indbase = hipsparseGetMatIndexBase(descrA); if(indbase == HIPSPARSE_INDEX_BASE_ONE) { for(rocblas_int i = 0; i <= n; i++) hptrA[0][i]++; for(rocblas_int i = 0; i < nnzA; i++) hindA[0][i]++; } } if(GPU) { CHECK_HIP_ERROR(dptrA.transfer_from(hptrA)); CHECK_HIP_ERROR(dindA.transfer_from(hindA)); CHECK_HIP_ERROR(dvalA.transfer_from(hvalA)); CHECK_HIP_ERROR(dB.transfer_from(hB)); } } template void csrlsvchol_getError(hipsolverSpHandle_t handle, const int n, const int nnzA, const hipsparseMatDescr_t descrA, Ud& dptrA, Ud& dindA, Td& dvalA, Td& dB, const S tolerance, const int reorder, Td& dX, Uh& hptrA, Uh& hindA, Th& hvalA, Th& hB, Th& hX, Th& hXRes, Uh& hSingularity, double* max_err, const fs::path testcase) { // input data initialization csrlsvchol_initData( handle, n, nnzA, descrA, dptrA, dindA, dvalA, dB, hptrA, hindA, hvalA, hB, hX, testcase); // execute computations // GPU lapack CHECK_ROCBLAS_ERROR(hipsolver_csrlsvchol(HOST, handle, n, nnzA, descrA, dvalA.data(), dptrA.data(), dindA.data(), dB.data(), tolerance, reorder, dX.data(), hSingularity.data())); CHECK_HIP_ERROR(hXRes.transfer_from(dX)); // compare computed results with original result double err; *max_err = 0; err = norm_error('I', n, 1, n, hX[0], hXRes[0]); *max_err = err > *max_err ? err : *max_err; // TODO: Add non-positive definite test matrices // also check info for singularities err = 0; EXPECT_EQ(hSingularity[0][0], -1); if(hSingularity[0][0] != -1) err++; *max_err += err; } template void csrlsvchol_getPerfData(hipsolverSpHandle_t handle, const int n, const int nnzA, const hipsparseMatDescr_t descrA, Ud& dptrA, Ud& dindA, Td& dvalA, Td& dB, const S tolerance, const int reorder, Td& dX, Uh& hptrA, Uh& hindA, Th& hvalA, Th& hB, Th& hX, Uh& hSingularity, double* gpu_time_used, double* cpu_time_used, const int hot_calls, const bool perf, const fs::path testcase) { *cpu_time_used = nan(""); // no timing on cpu-lapack execution csrlsvchol_initData( handle, n, nnzA, descrA, dptrA, dindA, dvalA, dB, hptrA, hindA, hvalA, hB, hX, testcase); // cold calls for(int iter = 0; iter < 2; iter++) { csrlsvchol_initData(handle, n, nnzA, descrA, dptrA, dindA, dvalA, dB, hptrA, hindA, hvalA, hB, hX, testcase); CHECK_ROCBLAS_ERROR(hipsolver_csrlsvchol(HOST, handle, n, nnzA, descrA, dvalA.data(), dptrA.data(), dindA.data(), dB.data(), tolerance, reorder, dX.data(), hSingularity.data())); } // gpu-lapack performance hipStream_t stream; CHECK_ROCBLAS_ERROR(hipsolverGetStream(handle, &stream)); double start; for(int iter = 0; iter < hot_calls; iter++) { csrlsvchol_initData(handle, n, nnzA, descrA, dptrA, dindA, dvalA, dB, hptrA, hindA, hvalA, hB, hX, testcase); start = get_time_us_sync(stream); hipsolver_csrlsvchol(HOST, handle, n, nnzA, descrA, dvalA.data(), dptrA.data(), dindA.data(), dB.data(), tolerance, reorder, dX.data(), hSingularity.data()); *gpu_time_used += get_time_us_sync(stream) - start; } *gpu_time_used /= hot_calls; } template void testing_csrlsvchol(Arguments& argus) { using S = decltype(std::real(T{})); // get arguments hipsolverSp_local_handle handle; int n = argus.get("n"); int nnzA = argus.get("nnzA"); double tolerance = argus.get("tolerance", 0); int reorder = argus.get("reorder", 0); int base1 = argus.get("base1", 0); int hot_calls = argus.iters; // check non-supported values // N/A // check invalid sizes bool invalid_size = (n < 0 || nnzA < 0); if(invalid_size) { EXPECT_ROCBLAS_STATUS(hipsolver_csrlsvchol(HOST, handle, n, nnzA, (hipsparseMatDescr_t) nullptr, (T*)nullptr, (int*)nullptr, (int*)nullptr, (T*)nullptr, tolerance, reorder, (T*)nullptr, (int*)nullptr), HIPSOLVER_STATUS_INVALID_VALUE); if(argus.timing) rocsolver_bench_inform(inform_invalid_size); return; } // determine existing test case if(n > 0) { if(n <= 35) n = 20; else if(n <= 75) n = 50; else if(n <= 175) n = 100; else n = 250; } if(n <= 50) // small case { if(nnzA <= 80) nnzA = 60; else if(nnzA <= 120) nnzA = 100; else nnzA = 140; } else // large case { if(nnzA <= 400) nnzA = 300; else if(nnzA <= 600) nnzA = 500; else nnzA = 700; } // read/set corresponding nnzA fs::path testcase; if(n > 0) { fs::path file; std::string folder = std::string("posmat_") + std::to_string(n) + "_" + std::to_string(nnzA); testcase = get_sparse_data_dir() / folder; file = testcase / "ptrA"; read_last(file.string(), &nnzA); } // determine sizes size_t size_ptrA = size_t(n) + 1; size_t size_indA = size_t(nnzA); size_t size_valA = size_t(nnzA); size_t size_BX = size_t(n); size_t size_BXres = 0; if(argus.unit_check || argus.norm_check) size_BXres = size_BX; double max_error = 0, gpu_time_used = 0, cpu_time_used = 0; // memory allocations (all cases) hipsparse_local_mat_descr descrA; hipsparseSetMatType(descrA, HIPSPARSE_MATRIX_TYPE_GENERAL); if(base1 == 0) hipsparseSetMatIndexBase(descrA, HIPSPARSE_INDEX_BASE_ZERO); else hipsparseSetMatIndexBase(descrA, HIPSPARSE_INDEX_BASE_ONE); host_strided_batch_vector hptrA(size_ptrA, 1, size_ptrA, 1); host_strided_batch_vector hindA(size_indA, 1, size_indA, 1); host_strided_batch_vector hvalA(size_valA, 1, size_valA, 1); host_strided_batch_vector hB(size_BX, 1, size_BX, 1); host_strided_batch_vector hX(size_BX, 1, size_BX, 1); host_strided_batch_vector hXRes(size_BXres, 1, size_BXres, 1); host_strided_batch_vector hSingularity(1, 1, 1, 1); if(HOST) { // memory allocations host_strided_batch_vector dptrA(size_ptrA, 1, size_ptrA, 1); host_strided_batch_vector dindA(size_indA, 1, size_indA, 1); host_strided_batch_vector dvalA(size_valA, 1, size_valA, 1); host_strided_batch_vector dB(size_BX, 1, size_BX, 1); host_strided_batch_vector dX(size_BX, 1, size_BX, 1); CHECK_HIP_ERROR(dptrA.memcheck()); if(size_indA) CHECK_HIP_ERROR(dindA.memcheck()); if(size_valA) CHECK_HIP_ERROR(dvalA.memcheck()); if(size_BX) CHECK_HIP_ERROR(dB.memcheck()); if(size_BX) CHECK_HIP_ERROR(dX.memcheck()); // check computations if(argus.unit_check || argus.norm_check) csrlsvchol_getError(handle, n, nnzA, descrA, dptrA, dindA, dvalA, dB, tolerance, reorder, dX, hptrA, hindA, hvalA, hB, hX, hXRes, hSingularity, &max_error, testcase); // collect performance data if(argus.timing) csrlsvchol_getPerfData(handle, n, nnzA, descrA, dptrA, dindA, dvalA, dB, tolerance, reorder, dX, hptrA, hindA, hvalA, hB, hX, hSingularity, &gpu_time_used, &cpu_time_used, hot_calls, argus.perf, testcase); } else { // memory allocations device_strided_batch_vector dptrA(size_ptrA, 1, size_ptrA, 1); device_strided_batch_vector dindA(size_indA, 1, size_indA, 1); device_strided_batch_vector dvalA(size_valA, 1, size_valA, 1); device_strided_batch_vector dB(size_BX, 1, size_BX, 1); device_strided_batch_vector dX(size_BX, 1, size_BX, 1); CHECK_HIP_ERROR(dptrA.memcheck()); if(size_indA) CHECK_HIP_ERROR(dindA.memcheck()); if(size_valA) CHECK_HIP_ERROR(dvalA.memcheck()); if(size_BX) CHECK_HIP_ERROR(dB.memcheck()); if(size_BX) CHECK_HIP_ERROR(dX.memcheck()); // check computations if(argus.unit_check || argus.norm_check) csrlsvchol_getError(handle, n, nnzA, descrA, dptrA, dindA, dvalA, dB, tolerance, reorder, dX, hptrA, hindA, hvalA, hB, hX, hXRes, hSingularity, &max_error, testcase); // collect performance data if(argus.timing) csrlsvchol_getPerfData(handle, n, nnzA, descrA, dptrA, dindA, dvalA, dB, tolerance, reorder, dX, hptrA, hindA, hvalA, hB, hX, hSingularity, &gpu_time_used, &cpu_time_used, hot_calls, argus.perf, testcase); } // validate results for rocsolver-test // using n * machine_precision as tolerance if(argus.unit_check) ROCSOLVER_TEST_CHECK(T, max_error, n); // output results for rocsolver-bench if(argus.timing) { if(!argus.perf) { std::cerr << "\n============================================\n"; std::cerr << "Arguments:\n"; std::cerr << "============================================\n"; rocsolver_bench_output("n", "nnzA"); rocsolver_bench_output(n, nnzA); std::cerr << "\n============================================\n"; std::cerr << "Results:\n"; std::cerr << "============================================\n"; if(argus.norm_check) { rocsolver_bench_output("cpu_time_us", "gpu_time_us", "error"); rocsolver_bench_output(cpu_time_used, gpu_time_used, max_error); } else { rocsolver_bench_output("cpu_time_us", "gpu_time_us"); rocsolver_bench_output(cpu_time_used, gpu_time_used); } std::cerr << std::endl; } else { if(argus.norm_check) rocsolver_bench_output(gpu_time_used, max_error); else rocsolver_bench_output(gpu_time_used); } } // ensure all arguments were consumed argus.validate_consumed(); }