/* ************************************************************************ * Copyright (C) 2016-2025 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. * * ************************************************************************ */ #define ROCBLAS_BETA_FEATURES_API #include "program_options.hpp" #include "client_omp.hpp" #include "client_utility.hpp" #include "rocblas.hpp" #include "rocblas_data.hpp" #include "rocblas_datatype2string.hpp" #include "rocblas_parse_data.hpp" #include "tensile_host.hpp" #include "type_dispatch.hpp" #include #include #include #include #include #include #include #include #include #include "frequency_monitor.hpp" // aux #include "testing_set_get_matrix.hpp" #include "testing_set_get_matrix_async.hpp" #include "testing_set_get_vector.hpp" #include "testing_set_get_vector_async.hpp" // blas1 // new way with prototypes #include "blas1/common_asum.hpp" #include "blas1/common_axpy.hpp" #include "blas1/common_copy.hpp" #include "blas1/common_dot.hpp" #include "blas1/common_iamax_iamin.hpp" #include "blas1/common_nrm2.hpp" #include "blas1/common_rot.hpp" #include "blas1/common_scal.hpp" #include "blas1/common_swap.hpp" #include "blas_ex/common_axpy_ex.hpp" #include "blas_ex/common_dot_ex.hpp" #include "blas_ex/common_nrm2_ex.hpp" #include "blas_ex/common_rot_ex.hpp" #include "blas_ex/common_scal_ex.hpp" // blas2 #include "blas2/common_gbmv.hpp" #include "blas2/common_gemv.hpp" #include "blas2/common_ger.hpp" #include "blas2/common_hbmv.hpp" #include "blas2/common_hemv.hpp" #include "blas2/common_her.hpp" #include "blas2/common_her2.hpp" #include "blas2/common_hpmv.hpp" #include "blas2/common_hpr.hpp" #include "blas2/common_hpr2.hpp" #include "blas2/common_sbmv.hpp" #include "blas2/common_spmv.hpp" #include "blas2/common_spr.hpp" #include "blas2/common_spr2.hpp" #include "blas2/common_symv.hpp" #include "blas2/common_syr.hpp" #include "blas2/common_syr2.hpp" #include "blas2/common_tbmv.hpp" #include "blas2/common_tbsv.hpp" #include "blas2/common_tpmv.hpp" #include "blas2/common_tpsv.hpp" #include "blas2/common_trmv.hpp" #include "blas2/common_trsv.hpp" // for blas3 with no tensile, some will use source gemms #include "blas3/common_dgmm.hpp" #include "blas3/common_geam.hpp" #include "blas3/common_gemm.hpp" #include "blas3/common_her2k.hpp" #include "blas3/common_herk.hpp" #include "blas3/common_symm_hemm.hpp" #include "blas3/common_syr2k.hpp" #include "blas3/common_syrk.hpp" #include "blas3/common_trmm.hpp" #include "blas3/common_trsm.hpp" #include "blas3/common_trtri.hpp" #include "blas_ex/common_geam_ex.hpp" #include "blas_ex/common_gemm_ex.hpp" #include "blas_ex/common_gemmt.hpp" #include "blas_ex/common_syrk_ex.hpp" #include "blas_ex/common_trsm_ex.hpp" #include "type_dispatch.hpp" #undef I using namespace roc; // For emulated program_options using namespace std::literals; // For std::string literals of form "str"s struct str_less { bool operator()(const char* a, const char* b) const { return strcmp(a, b) < 0; } }; // Map from const char* to function taking const Arguments& using comparison above using func_map = std::map; // Run a function by using map to map arg.function to function void run_function(const func_map& map, const Arguments& arg, const std::string& msg = "") { auto match = map.find(arg.function); if(match == map.end()) throw std::invalid_argument("Invalid combination --function "s + arg.function + " --a_type "s + rocblas_datatype2string(arg.a_type) + msg); match->second(arg); } // Template to dispatch testing_gemm_ex for performance tests // When Ti == void or Ti == To == Tc == bfloat16, the test is marked invalid template struct perf_gemm_ex : rocblas_test_invalid { }; template struct perf_gemm_ex< Ti, To, Tc, std::enable_if_t< !std::is_same_v< Ti, void> && !(std::is_same_v && std::is_same_v && std::is_same_v)>> : rocblas_test_valid { void operator()(const Arguments& arg) { static const func_map map = { {"gemm_ex", testing_gemm_ex}, {"gemm_batched_ex", testing_gemm_batched_ex}, }; run_function(map, arg); } }; // Template to dispatch testing_gemm_strided_batched_ex for performance tests // When Ti == void or Ti == To == Tc == bfloat16, the test is marked invalid template struct perf_gemm_strided_batched_ex : rocblas_test_invalid { }; template struct perf_gemm_strided_batched_ex< Ti, To, Tc, std::enable_if_t< !std::is_same_v< Ti, void> && !(std::is_same_v && std::is_same_v && std::is_same_v)>> : rocblas_test_valid { void operator()(const Arguments& arg) { static const func_map map = { {"gemm_strided_batched_ex", testing_gemm_strided_batched_ex}, }; run_function(map, arg); } }; template struct perf_blas : rocblas_test_invalid { }; template struct perf_blas || std::is_same_v>> : rocblas_test_valid { void operator()(const Arguments& arg) { static const func_map map = { {"set_get_vector", testing_set_get_vector}, {"set_get_vector_async", testing_set_get_vector_async}, {"set_get_matrix", testing_set_get_matrix}, {"set_get_matrix_async", testing_set_get_matrix_async}, // L1 {"asum", testing_asum}, {"asum_batched", testing_asum_batched}, {"asum_strided_batched", testing_asum_strided_batched}, {"axpy", testing_axpy}, {"axpy_batched", testing_axpy_batched}, {"axpy_strided_batched", testing_axpy_strided_batched}, {"copy", testing_copy}, {"copy_batched", testing_copy_batched}, {"copy_strided_batched", testing_copy_strided_batched}, {"dot", testing_dot}, {"dot_batched", testing_dot_batched}, {"dot_strided_batched", testing_dot_strided_batched}, {"iamax", testing_iamax}, {"iamax_batched", testing_iamax_batched}, {"iamax_strided_batched", testing_iamax_strided_batched}, {"iamin", testing_iamin}, {"iamin_batched", testing_iamin_batched}, {"iamin_strided_batched", testing_iamin_strided_batched}, {"nrm2", testing_nrm2}, {"nrm2_batched", testing_nrm2_batched}, {"nrm2_strided_batched", testing_nrm2_strided_batched}, {"rotm", testing_rotm}, {"rotm_batched", testing_rotm_batched}, {"rotm_strided_batched", testing_rotm_strided_batched}, {"rotmg", testing_rotmg}, {"rotmg_batched", testing_rotmg_batched}, {"rotmg_strided_batched", testing_rotmg_strided_batched}, {"swap", testing_swap}, {"swap_batched", testing_swap_batched}, {"swap_strided_batched", testing_swap_strided_batched}, // L2 {"gbmv", testing_gbmv}, {"gbmv_batched", testing_gbmv_batched}, {"gbmv_strided_batched", testing_gbmv_strided_batched}, {"geam", testing_geam}, {"geam_batched", testing_geam_batched}, {"geam_strided_batched", testing_geam_strided_batched}, {"geam_ex", testing_geam_ex}, {"gemv", testing_gemv}, {"ger", testing_ger}, {"ger_batched", testing_ger_batched}, {"ger_strided_batched", testing_ger_strided_batched}, {"spr", testing_spr}, {"spr_batched", testing_spr_batched}, {"spr_strided_batched", testing_spr_strided_batched}, {"spr2", testing_spr2}, {"spr2_batched", testing_spr2_batched}, {"spr2_strided_batched", testing_spr2_strided_batched}, {"syr", testing_syr}, {"syr_batched", testing_syr_batched}, {"syr_strided_batched", testing_syr_strided_batched}, {"syr2", testing_syr2}, {"syr2_batched", testing_syr2_batched}, {"syr2_strided_batched", testing_syr2_strided_batched}, {"sbmv", testing_sbmv}, {"sbmv_batched", testing_sbmv_batched}, {"sbmv_strided_batched", testing_sbmv_strided_batched}, {"spmv", testing_spmv}, {"spmv_batched", testing_spmv_batched}, {"spmv_strided_batched", testing_spmv_strided_batched}, {"symv", testing_symv}, {"symv_batched", testing_symv_batched}, {"symv_strided_batched", testing_symv_strided_batched}, {"tbmv", testing_tbmv}, {"tbmv_batched", testing_tbmv_batched}, {"tbmv_strided_batched", testing_tbmv_strided_batched}, {"tbsv", testing_tbsv}, {"tbsv_batched", testing_tbsv_batched}, {"tbsv_strided_batched", testing_tbsv_strided_batched}, {"tpmv", testing_tpmv}, {"tpmv_batched", testing_tpmv_batched}, {"tpmv_strided_batched", testing_tpmv_strided_batched}, {"tpsv", testing_tpsv}, {"tpsv_batched", testing_tpsv_batched}, {"tpsv_strided_batched", testing_tpsv_strided_batched}, {"trmv", testing_trmv}, {"trmv_batched", testing_trmv_batched}, {"trmv_strided_batched", testing_trmv_strided_batched}, // L3 {"dgmm", testing_dgmm}, {"dgmm_batched", testing_dgmm_batched}, {"dgmm_strided_batched", testing_dgmm_strided_batched}, {"gemmt", testing_gemmt}, {"gemmt_batched", testing_gemmt_batched}, {"gemmt_strided_batched", testing_gemmt_strided_batched}, {"symm", testing_symm_hemm}, {"symm_batched", testing_symm_hemm_batched}, {"symm_strided_batched", testing_symm_hemm_strided_batched}, {"trmm", testing_trmm}, {"trmm_batched", testing_trmm_batched}, {"trmm_strided_batched", testing_trmm_strided_batched}, {"syrk", testing_syrk}, {"syrk_batched", testing_syrk_batched}, {"syrk_strided_batched", testing_syrk_strided_batched}, {"syr2k", testing_syr2k}, {"syr2k_batched", testing_syr2k_batched}, {"syr2k_strided_batched", testing_syr2k_strided_batched}, {"trsv", testing_trsv}, {"trsv_batched", testing_trsv_batched}, {"trsv_strided_batched", testing_trsv_strided_batched}, // allow profiling with source gemms even without BUILD_WITH_TENSILE {"gemm", testing_gemm}, {"gemm_batched", testing_gemm_batched}, {"gemm_strided_batched", testing_gemm_strided_batched}, {"syrkx", testing_syr2k}, {"syrkx_batched", testing_syr2k_batched}, {"syrkx_strided_batched", testing_syr2k_strided_batched}, {"trtri", testing_trtri}, {"trtri_batched", testing_trtri_batched}, {"trtri_strided_batched", testing_trtri_strided_batched}, {"trsm", testing_trsm}, {"trsm_ex", testing_trsm_ex}, {"trsm_batched", testing_trsm_batched}, {"trsm_batched_ex", testing_trsm_batched_ex}, {"trsm_strided_batched", testing_trsm_strided_batched}, {"trsm_strided_batched_ex", testing_trsm_strided_batched_ex}, }; run_function(map, arg); } }; template struct perf_blas>> : rocblas_test_valid { void operator()(const Arguments& arg) { static const func_map map = { {"dot", testing_dot}, {"dot_batched", testing_dot_batched}, {"dot_strided_batched", testing_dot_strided_batched}, }; run_function(map, arg); } }; template struct perf_blas>> : rocblas_test_valid { void operator()(const Arguments& arg) { static const func_map map = { {"axpy", testing_axpy}, {"axpy_batched", testing_axpy_batched}, {"axpy_strided_batched", testing_axpy_strided_batched}, {"dot", testing_dot}, {"dot_batched", testing_dot_batched}, {"dot_strided_batched", testing_dot_strided_batched}, {"geam_ex", testing_geam_ex}, #if BUILD_WITH_TENSILE {"gemm", testing_gemm}, {"gemm_batched", testing_gemm_batched}, {"gemm_strided_batched", testing_gemm_strided_batched}, #endif }; run_function(map, arg); } }; // rocblas-bench dispatch for gemv_batched and gemv_strided_batched tests template struct perf_gemv_batched_and_strided_batched : rocblas_test_invalid { }; template struct perf_gemv_batched_and_strided_batched< Ti, Tex, To, std::enable_if_t< (std::is_same{} && std::is_same{} && std::is_same{}) || (std::is_same{} && std::is_same{} && std::is_same{}) || (std::is_same{} && std::is_same{} && std::is_same{}) || (std::is_same{} && std::is_same{} && std::is_same{}) || (std::is_same{} && std::is_same{} && (std::is_same{} || std::is_same{})) || (std::is_same{} && std::is_same{} && (std::is_same{} || std::is_same{}))>> : rocblas_test_valid { void operator()(const Arguments& arg) { static const func_map map = { {"gemv_batched", testing_gemv_batched}, {"gemv_strided_batched", testing_gemv_strided_batched}, }; run_function(map, arg); } }; template struct perf_blas< T, U, std::enable_if_t< std::is_same_v || std::is_same_v>> : rocblas_test_valid { void operator()(const Arguments& arg) { static const func_map map = { {"set_get_vector", testing_set_get_vector}, {"set_get_vector_async", testing_set_get_vector_async}, {"set_get_matrix", testing_set_get_matrix}, {"set_get_matrix_async", testing_set_get_matrix_async}, // L1 {"asum", testing_asum}, {"asum_batched", testing_asum_batched}, {"asum_strided_batched", testing_asum_strided_batched}, {"axpy", testing_axpy}, {"axpy_batched", testing_axpy_batched}, {"axpy_strided_batched", testing_axpy_strided_batched}, {"copy", testing_copy}, {"copy_batched", testing_copy_batched}, {"copy_strided_batched", testing_copy_strided_batched}, {"dot", testing_dot}, {"dot_batched", testing_dot_batched}, {"dot_strided_batched", testing_dot_strided_batched}, {"dotc", testing_dotc}, {"dotc_batched", testing_dotc_batched}, {"dotc_strided_batched", testing_dotc_strided_batched}, {"iamax", testing_iamax}, {"iamax_batched", testing_iamax_batched}, {"iamax_strided_batched", testing_iamax_strided_batched}, {"iamin", testing_iamin}, {"iamin_batched", testing_iamin_batched}, {"iamin_strided_batched", testing_iamin_strided_batched}, {"nrm2", testing_nrm2}, {"nrm2_batched", testing_nrm2_batched}, {"nrm2_strided_batched", testing_nrm2_strided_batched}, {"swap", testing_swap}, {"swap_batched", testing_swap_batched}, {"swap_strided_batched", testing_swap_strided_batched}, // L2 {"gbmv", testing_gbmv}, {"gbmv_batched", testing_gbmv_batched}, {"gbmv_strided_batched", testing_gbmv_strided_batched}, {"gemv", testing_gemv}, {"geru", testing_ger}, {"geru_batched", testing_ger_batched}, {"geru_strided_batched", testing_ger_strided_batched}, {"gerc", testing_ger}, {"gerc_batched", testing_ger_batched}, {"gerc_strided_batched", testing_ger_strided_batched}, {"hbmv", testing_hbmv}, {"hbmv_batched", testing_hbmv_batched}, {"hbmv_strided_batched", testing_hbmv_strided_batched}, {"hemv", testing_hemv}, {"hemv_batched", testing_hemv_batched}, {"hemv_strided_batched", testing_hemv_strided_batched}, {"her", testing_her}, {"her_batched", testing_her_batched}, {"her_strided_batched", testing_her_strided_batched}, {"her2", testing_her2}, {"her2_batched", testing_her2_batched}, {"her2_strided_batched", testing_her2_strided_batched}, {"hpmv", testing_hpmv}, {"hpmv_batched", testing_hpmv_batched}, {"hpmv_strided_batched", testing_hpmv_strided_batched}, {"hpr", testing_hpr}, {"hpr_batched", testing_hpr_batched}, {"hpr_strided_batched", testing_hpr_strided_batched}, {"hpr2", testing_hpr2}, {"hpr2_batched", testing_hpr2_batched}, {"hpr2_strided_batched", testing_hpr2_strided_batched}, {"spr", testing_spr}, {"spr_batched", testing_spr_batched}, {"spr_strided_batched", testing_spr_strided_batched}, {"syr", testing_syr}, {"syr_batched", testing_syr_batched}, {"syr_strided_batched", testing_syr_strided_batched}, {"syr2", testing_syr2}, {"syr2_batched", testing_syr2_batched}, {"syr2_strided_batched", testing_syr2_strided_batched}, {"tbmv", testing_tbmv}, {"tbmv_batched", testing_tbmv_batched}, {"tbmv_strided_batched", testing_tbmv_strided_batched}, {"tbsv", testing_tbsv}, {"tbsv_batched", testing_tbsv_batched}, {"tbsv_strided_batched", testing_tbsv_strided_batched}, {"tpmv", testing_tpmv}, {"tpmv_batched", testing_tpmv_batched}, {"tpmv_strided_batched", testing_tpmv_strided_batched}, {"tpsv", testing_tpsv}, {"tpsv_batched", testing_tpsv_batched}, {"tpsv_strided_batched", testing_tpsv_strided_batched}, {"symv", testing_symv}, {"symv_batched", testing_symv_batched}, {"symv_strided_batched", testing_symv_strided_batched}, {"trmv", testing_trmv}, {"trmv_batched", testing_trmv_batched}, {"trmv_strided_batched", testing_trmv_strided_batched}, {"trsv", testing_trsv}, {"trsv_batched", testing_trsv_batched}, {"trsv_strided_batched", testing_trsv_strided_batched}, // L3 {"dgmm", testing_dgmm}, {"dgmm_batched", testing_dgmm_batched}, {"dgmm_strided_batched", testing_dgmm_strided_batched}, {"gemmt", testing_gemmt}, {"gemmt_batched", testing_gemmt_batched}, {"gemmt_strided_batched", testing_gemmt_strided_batched}, {"geam", testing_geam}, {"geam_batched", testing_geam_batched}, {"geam_strided_batched", testing_geam_strided_batched}, {"syrk", testing_syrk}, {"syrk_batched", testing_syrk_batched}, {"syrk_strided_batched", testing_syrk_strided_batched}, {"syr2k", testing_syr2k}, {"syr2k_batched", testing_syr2k_batched}, {"syr2k_strided_batched", testing_syr2k_strided_batched}, {"syrkx", testing_syr2k}, {"syrkx_batched", testing_syr2k_batched}, {"syrkx_strided_batched", testing_syr2k_strided_batched}, {"symm", testing_symm_hemm}, {"symm_batched", testing_symm_hemm_batched}, {"symm_strided_batched", testing_symm_hemm_strided_batched}, {"trmm", testing_trmm}, {"trmm_batched", testing_trmm_batched}, {"trmm_strided_batched", testing_trmm_strided_batched}, {"hemm", testing_symm_hemm}, {"hemm_batched", testing_symm_hemm_batched}, {"hemm_strided_batched", testing_symm_hemm_strided_batched}, {"herk", testing_herk}, {"herk_batched", testing_herk_batched}, {"herk_strided_batched", testing_herk_strided_batched}, {"her2k", testing_her2k}, {"her2k_batched", testing_her2k_batched}, {"her2k_strided_batched", testing_her2k_strided_batched}, {"herkx", testing_her2k}, {"herkx_batched", testing_her2k_batched}, {"herkx_strided_batched", testing_her2k_strided_batched}, {"gemm", testing_gemm}, {"gemm_batched", testing_gemm_batched}, {"gemm_strided_batched", testing_gemm_strided_batched}, {"trsm", testing_trsm}, {"trsm_ex", testing_trsm_ex}, {"trsm_batched", testing_trsm_batched}, {"trsm_batched_ex", testing_trsm_batched_ex}, {"trsm_strided_batched", testing_trsm_strided_batched}, {"trsm_strided_batched_ex", testing_trsm_strided_batched_ex}, {"trtri", testing_trtri}, {"trtri_batched", testing_trtri_batched}, {"trtri_strided_batched", testing_trtri_strided_batched}, }; run_function(map, arg); } }; template struct perf_blas_axpy_ex : rocblas_test_invalid { }; template struct perf_blas_axpy_ex< Ta, Tx, Ty, Tex, std::enable_if_t< (std::is_same_v< Ta, float> && std::is_same_v && std::is_same_v && std::is_same_v) || (std::is_same_v< Ta, double> && std::is_same_v && std::is_same_v && std::is_same_v) || (std::is_same_v< Ta, rocblas_half> && std::is_same_v && std::is_same_v && std::is_same_v) || (std::is_same_v< Ta, rocblas_float_complex> && std::is_same_v && std::is_same_v && std::is_same_v) || (std::is_same_v< Ta, rocblas_double_complex> && std::is_same_v && std::is_same_v && std::is_same_v) || (std::is_same_v< Ta, rocblas_half> && std::is_same_v && std::is_same_v && std::is_same_v) || (std::is_same_v< Ta, rocblas_half> && std::is_same_v && std::is_same_v && std::is_same_v) || (std::is_same_v< Ta, float> && std::is_same_v && std::is_same_v && std::is_same_v) || (std::is_same_v< Ta, rocblas_bfloat16> && std::is_same_v && std::is_same_v && std::is_same_v) || (std::is_same_v< Ta, float> && std::is_same_v && std::is_same_v && std::is_same_v)>> : rocblas_test_valid { void operator()(const Arguments& arg) { static const func_map map = { {"axpy_ex", testing_axpy_ex}, {"axpy_batched_ex", testing_axpy_batched_ex}, {"axpy_strided_batched_ex", testing_axpy_strided_batched_ex}, }; run_function(map, arg); } }; template struct perf_blas_dot_ex : rocblas_test_invalid { }; template struct perf_blas_dot_ex< Tx, Ty, Tr, Tex, std::enable_if_t< (std::is_same_v< Tx, float> && std::is_same_v && std::is_same_v && std::is_same_v) || (std::is_same_v< Tx, double> && std::is_same_v && std::is_same_v && std::is_same_v) || (std::is_same_v< Tx, rocblas_half> && std::is_same_v && std::is_same_v && std::is_same_v) || (std::is_same_v< Tx, rocblas_float_complex> && std::is_same_v && std::is_same_v && std::is_same_v) || (std::is_same_v< Tx, rocblas_double_complex> && std::is_same_v && std::is_same_v && std::is_same_v) || (std::is_same_v< Tx, rocblas_half> && std::is_same_v && std::is_same_v && std::is_same_v) || (std::is_same_v< Tx, rocblas_bfloat16> && std::is_same_v && std::is_same_v && std::is_same_v) || (std::is_same_v< Tx, float> && std::is_same_v && std::is_same_v && std::is_same_v)>> : rocblas_test_valid { void operator()(const Arguments& arg) { static const func_map map = { {"dot_ex", testing_dot_ex}, {"dot_batched_ex", testing_dot_batched_ex}, {"dot_strided_batched_ex", testing_dot_strided_batched_ex}, {"dotc_ex", testing_dotc_ex}, {"dotc_batched_ex", testing_dotc_batched_ex}, {"dotc_strided_batched_ex", testing_dotc_strided_batched_ex}, }; run_function(map, arg); } }; template struct perf_blas_nrm2_ex : rocblas_test_invalid { }; template struct perf_blas_nrm2_ex< Tx, Tr, Tex, std::enable_if_t< (std::is_same_v && std::is_same_v && std::is_same_v) || (std::is_same_v && std::is_same_v && std::is_same_v) || (std::is_same_v< Tx, rocblas_float_complex> && std::is_same_v && std::is_same_v) || (std::is_same_v< Tx, rocblas_double_complex> && std::is_same_v && std::is_same_v) || (std::is_same_v< Tx, rocblas_bfloat16> && std::is_same_v && std::is_same_v) || (std::is_same_v && std::is_same_v && std::is_same_v)>> : rocblas_test_valid { void operator()(const Arguments& arg) { static const func_map map = { {"nrm2_ex", testing_nrm2_ex}, {"nrm2_batched_ex", testing_nrm2_batched_ex}, {"nrm2_strided_batched_ex", testing_nrm2_strided_batched_ex}, }; run_function(map, arg); } }; template struct perf_blas_rot : rocblas_test_invalid { }; template struct perf_blas_rot< Ti, To, Tc, std::enable_if_t< (std::is_same_v && std::is_same_v && std::is_same_v) || (std::is_same_v && std::is_same_v && std::is_same_v) || (std::is_same_v< Ti, rocblas_float_complex> && std::is_same_v && std::is_same_v) || (std::is_same_v< Ti, rocblas_float_complex> && std::is_same_v && std::is_same_v) || (std::is_same_v< Ti, rocblas_double_complex> && std::is_same_v && std::is_same_v) || (std::is_same_v< Ti, rocblas_double_complex> && std::is_same_v && std::is_same_v)>> : rocblas_test_valid { void operator()(const Arguments& arg) { static const func_map map = { {"rot", testing_rot}, {"rot_batched", testing_rot_batched}, {"rot_strided_batched", testing_rot_strided_batched}, }; run_function(map, arg); } }; template struct perf_blas_rot_ex : rocblas_test_invalid { }; template struct perf_blas_rot_ex< Tx, Ty, Tcs, Tex, std::enable_if_t< (std::is_same_v< Tx, float> && std::is_same_v && std::is_same_v && std::is_same_v) || (std::is_same_v< Tx, double> && std::is_same_v && std::is_same_v && std::is_same_v) || (std::is_same_v< Tx, rocblas_float_complex> && std::is_same_v && std::is_same_v && std::is_same_v) || (std::is_same_v< Tx, rocblas_double_complex> && std::is_same_v && std::is_same_v && std::is_same_v) || (std::is_same_v< Tx, rocblas_float_complex> && std::is_same_v && std::is_same_v && std::is_same_v) || (std::is_same_v< Tx, rocblas_double_complex> && std::is_same_v && std::is_same_v && std::is_same_v) || (std::is_same_v< Tx, rocblas_half> && std::is_same_v && std::is_same_v && std::is_same_v) || (std::is_same_v< Tx, rocblas_bfloat16> && std::is_same_v && std::is_same_v && std::is_same_v)>> : rocblas_test_valid { void operator()(const Arguments& arg) { static const func_map map = { {"rot_ex", testing_rot_ex}, {"rot_batched_ex", testing_rot_batched_ex}, {"rot_strided_batched_ex", testing_rot_strided_batched_ex}, }; run_function(map, arg); } }; template struct perf_blas_scal : rocblas_test_invalid { }; template struct perf_blas_scal< Tx, Ta, std::enable_if_t<(std::is_same_v && std::is_same_v) || (std::is_same_v && std::is_same_v) || (std::is_same_v && std::is_same_v) || (std::is_same_v && std::is_same_v) || (std::is_same_v && std::is_same_v) || (std::is_same_v && std::is_same_v)>> : rocblas_test_valid { void operator()(const Arguments& arg) { static const func_map map = { // Tx, Ta is reversed compared to scal_ex order as alpha is second argument {"scal", testing_scal}, {"scal_batched", testing_scal_batched}, {"scal_strided_batched", testing_scal_strided_batched}, }; run_function(map, arg); } }; template struct perf_blas_scal_ex : rocblas_test_invalid { }; template struct perf_blas_scal_ex< Ta, Tx, Tex, std::enable_if_t< (std::is_same_v && std::is_same_v && std::is_same_v) || (std::is_same_v && std::is_same_v && std::is_same_v) || (std::is_same_v && std::is_same_v && std::is_same_v) || (std::is_same_v< Ta, rocblas_float_complex> && std::is_same_v && std::is_same_v) || (std::is_same_v< Ta, rocblas_double_complex> && std::is_same_v && std::is_same_v) || (std::is_same_v && std::is_same_v && std::is_same_v) || (std::is_same_v && std::is_same_v && std::is_same_v) || (std::is_same_v< Ta, rocblas_bfloat16> && std::is_same_v && std::is_same_v) || (std::is_same_v< Ta, float> && std::is_same_v && std::is_same_v) || (std::is_same_v< Ta, float> && std::is_same_v && std::is_same_v) || (std::is_same_v< Ta, double> && std::is_same_v && std::is_same_v)>> : rocblas_test_valid { void operator()(const Arguments& arg) { static const func_map map = { {"scal_ex", testing_scal_ex}, {"scal_batched_ex", testing_scal_batched_ex}, {"scal_strided_batched_ex", testing_scal_strided_batched_ex}, }; run_function(map, arg); } }; template struct perf_blas_rotg : rocblas_test_invalid { }; template struct perf_blas_rotg< Ta, Tb, Tc, std::enable_if_t< (std::is_same_v< Ta, rocblas_double_complex> && std::is_same_v && std::is_same_v) || (std::is_same_v< Ta, rocblas_float_complex> && std::is_same_v && std::is_same_v) || (std::is_same_v && std::is_same_v && std::is_same_v) || (std::is_same_v && std::is_same_v && std::is_same_v)>> : rocblas_test_valid { void operator()(const Arguments& arg) { static const func_map map = { {"rotg", testing_rotg}, {"rotg_batched", testing_rotg_batched}, {"rotg_strided_batched", testing_rotg_strided_batched}, }; run_function(map, arg, " --b_type "s + rocblas_datatype2string(arg.b_type)); } }; // Template to dispatch testing_syrk_ex for performance tests // When Ti == void or Ti == To == Tc == bfloat16, the test is marked invalid template struct perf_syrk_ex : rocblas_test_invalid { }; template struct perf_syrk_ex< Ti, To, Tc, std::enable_if_t< !std::is_same_v< Ti, void> && !(std::is_same_v && std::is_same_v && (std::is_same_v || std::is_same_v))>> : rocblas_test_valid { void operator()(const Arguments& arg) { static const func_map map = { {"syrk_ex", testing_syrk_ex}, }; run_function(map, arg); } }; // // globals, functions, and main() // unit check override int8_t g_unit_check = 0; inline bool int32_api_invalid(const int64_t& val) { return ((int32_t)val != val); } bool api_arg_check(Arguments& arg, bool any_stride) { // check if 64 bit arguments were passed to 32bit APIs if(arg.api & c_API_64) // bitmask return true; auto invalid = [](const char* var) { rocblas_cout << "rocblas-bench INFO: argument int32 overflow: " << var << ", did you indend to use --api 1 ?" << std::endl; return false; }; if(int32_api_invalid(arg.batch_count)) { return invalid("batch_count"); } if(int32_api_invalid(arg.M)) { return invalid("m"); } if(int32_api_invalid(arg.N)) { return invalid("n"); } if(int32_api_invalid(arg.K)) { return invalid("k"); } return true; } void gemm_arg_adjust(Arguments& arg, bool any_stride) { // adjust dimension for GEMM routines int64_t min_lda = arg.transA == 'N' ? arg.M : arg.K; int64_t min_ldb = arg.transB == 'N' ? arg.K : arg.N; int64_t min_ldc = arg.M; int64_t min_ldd = arg.M; bool is_ex = strstr(arg.function, "_ex"); if(arg.lda < min_lda) { rocblas_cout << "rocblas-bench INFO: lda < min_lda, setting lda = " << min_lda << std::endl; arg.lda = min_lda; } if(arg.ldb < min_ldb) { rocblas_cout << "rocblas-bench INFO: ldb < min_ldb, setting ldb = " << min_ldb << std::endl; arg.ldb = min_ldb; } if(arg.ldc < min_ldc) { rocblas_cout << "rocblas-bench INFO: ldc < min_ldc, setting ldc = " << min_ldc << std::endl; arg.ldc = min_ldc; } if(is_ex && arg.ldd < min_ldd) { rocblas_cout << "rocblas-bench INFO: ldd < min_ldd, setting ldd = " << min_ldd << std::endl; arg.ldd = min_ldd; } if(strstr(arg.function, "strided")) { rocblas_stride min_stride_c = arg.ldc * arg.N; rocblas_stride min_stride_d = arg.ldd * arg.N; if(!any_stride && arg.stride_c < min_stride_c) { rocblas_cout << "rocblas-bench INFO: stride_c < min_stride_c, setting stride_c = " << min_stride_c << std::endl; arg.stride_c = min_stride_c; } if(is_ex && !any_stride && arg.stride_d < min_stride_d) { rocblas_cout << "rocblas-bench INFO: stride_d < min_stride_d, setting stride_d = " << min_stride_d << std::endl; arg.stride_d = min_stride_d; } } if(!strstr(arg.function, "batched") && arg.batch_count > 1) { rocblas_cout << "rocblas-bench INFO: batch_count can only be 1 for non batched functions" << ", setting batch_count = 1" << std::endl; arg.batch_count = 1; } if(!is_ex && arg.solution_index) { rocblas_cout << "rocblas-bench INFO: solution_index only supported by gemm_ex, " << "gemm_batched_ex, gemm_strided_batched_ex" << ", setting solution_index = 0" << std::endl; arg.solution_index = 0; } } void alpha_beta_stride_adjust(Arguments& arg) { if(!arg.alpha_beta_stride) return; // only applicable to device pointer mode arg.pointer_mode_host = false; arg.pointer_mode_device = true; } int run_bench_test(bool init, Arguments& arg, const std::string& filter, const std::string& name_filter, bool any_stride, bool yaml = false) { if(init) { static int runOnce = (rocblas_parallel_initialize(1), 0); // Initialize rocBLAS } rocblas_cout << std::setiosflags(std::ios::fixed) << std::setprecision(7); // Set precision to 7 digits // unit_check was forced off by default, so check global flag for enablement if(g_unit_check) arg.unit_check = g_unit_check; else arg.unit_check = 0; // enable timing check,otherwise no performance data collected arg.timing = 1; // defeat memory padding for benchmarks arg.pad = 0; // One stream and one thread (0 indicates to use default behavior) arg.streams = 0; arg.threads = 0; // Skip past any testing_ prefix in function static constexpr char prefix[] = "testing_"; const char* function = arg.function; const char* name = arg.name; if(!strncmp(function, prefix, sizeof(prefix) - 1)) function += sizeof(prefix) - 1; if(yaml && strstr(function, "_bad_arg")) return 0; if(!filter.empty()) { if(!strstr(function, filter.c_str())) return 0; } if(!name_filter.empty()) { if(!strstr(name, name_filter.c_str())) return 0; } if(!api_arg_check(arg, any_stride)) return 0; // argument modifications and dispatch if(!strcmp(function, "gemm_ex") || !strcmp(function, "gemm_batched_ex")) { gemm_arg_adjust(arg, any_stride); rocblas_gemm_dispatch(arg); } else if(!strcmp(function, "gemm_strided_batched_ex")) { gemm_arg_adjust(arg, any_stride); rocblas_gemm_dispatch(arg); } else { if(!strcmp(function, "gemm") || !strcmp(function, "gemm_batched") || !strcmp(function, "gemm_strided_batched")) { gemm_arg_adjust(arg, any_stride); } alpha_beta_stride_adjust(arg); if(!strcmp(function, "scal") || !strcmp(function, "scal_batched") || !strcmp(function, "scal_strided_batched")) rocblas_blas1_dispatch(arg); else if(!strcmp(function, "rotg") || !strcmp(function, "rotg_batched") || !strcmp(function, "rotg_strided_batched")) rocblas_blas1_dispatch(arg); else if(!strcmp(function, "rot") || !strcmp(function, "rot_batched") || !strcmp(function, "rot_strided_batched")) rocblas_blas1_dispatch(arg); else if(!strcmp(function, "rot_ex") || !strcmp(function, "rot_batched_ex") || !strcmp(function, "rot_strided_batched_ex")) rocblas_blas1_ex_dispatch(arg); else if(!strcmp(function, "axpy_ex") || !strcmp(function, "axpy_batched_ex") || !strcmp(function, "axpy_strided_batched_ex")) rocblas_blas1_ex_dispatch(arg); else if(!strcmp(function, "dot_ex") || !strcmp(function, "dot_batched_ex") || !strcmp(function, "dot_strided_batched_ex") || !strcmp(function, "dotc_ex") || !strcmp(function, "dotc_batched_ex") || !strcmp(function, "dotc_strided_batched_ex")) rocblas_blas1_ex_dispatch(arg); else if(!strcmp(function, "nrm2_ex") || !strcmp(function, "nrm2_batched_ex") || !strcmp(function, "nrm2_strided_batched_ex")) rocblas_blas1_ex_dispatch(arg); else if(!strcmp(function, "scal_ex") || !strcmp(function, "scal_batched_ex") || !strcmp(function, "scal_strided_batched_ex")) rocblas_blas1_ex_dispatch(arg); else if(!strcmp(function, "gemv_batched") || !strcmp(function, "gemv_strided_batched")) rocblas_gemv_batched_and_strided_batched_dispatch< perf_gemv_batched_and_strided_batched>(arg); else if(!strcmp(function, "syrk_ex")) rocblas_syrk_ex_dispatch(arg); else rocblas_simple_dispatch(arg); } return 0; } void check_device_matrix_reuse(std::vector& args) { if(args.empty()) { return; } auto* arg_prev = &args.front(); for(auto& arg : args) { if(arg.a_type == arg_prev->a_type && arg.b_type == arg_prev->b_type && arg.c_type == arg_prev->c_type && arg.d_type == arg_prev->d_type && arg.initialization == arg_prev->initialization) { arg_prev->cleanup = false; } arg_prev = &arg; } } int rocblas_bench_datafile(const std::string& filter, const std::string& name_filter, bool any_stride) { int ret = 0; auto arg_iter = RocBLAS_TestData(); std::vector args{arg_iter.begin(), arg_iter.end()}; check_device_matrix_reuse(args); for(Arguments arg : args) { ret |= run_bench_test(true, arg, filter, name_filter, any_stride, true); } test_cleanup::cleanup(); return ret; } void gpu_thread_init_device(int id, const Arguments& arg, const std::string& filter, bool any_stride) { CHECK_HIP_ERROR(hipSetDevice(id)); Arguments a(arg); std::string name_filter = ""; a.cold_iters = 1; a.iters = 0; run_bench_test(false, a, filter, name_filter, any_stride, false); } void gpu_thread_run_bench(int id, const Arguments& arg, const std::string& filter, bool any_stride) { CHECK_HIP_ERROR(hipSetDevice(id)); Arguments a(arg); std::string name_filter = ""; run_bench_test(false, a, filter, name_filter, any_stride, false); } void run_bench_gpu_test(int parallel_devices, Arguments& arg, const std::string& filter, bool any_stride) { int count; CHECK_HIP_ERROR(hipGetDeviceCount(&count)); if(parallel_devices > count || parallel_devices < 1) GTEST_ASSERT_TRUE(false); // initialization rocblas_parallel_initialize(parallel_devices); // run cold call on each device auto thread_init = std::make_unique(parallel_devices); for(int id = 0; id < parallel_devices; ++id) thread_init[id] = std::thread(::gpu_thread_init_device, id, arg, filter, any_stride); for(int id = 0; id < parallel_devices; ++id) thread_init[id].join(); // synchronized launch of cold & hot calls auto thread = std::make_unique(parallel_devices); for(int id = 0; id < parallel_devices; ++id) thread[id] = std::thread(::gpu_thread_run_bench, id, arg, filter, any_stride); for(int id = 0; id < parallel_devices; ++id) thread[id].join(); } // Replace --batch with --batch_count for backward compatibility void fix_batch(int argc, char* argv[]) { static char b_c[] = "--batch_count"; for(int i = 1; i < argc; ++i) if(!strcmp(argv[i], "--batch")) { static int once = (rocblas_cerr << argv[0] << " warning: --batch is deprecated, and --batch_count " "should be used instead." << std::endl, 0); argv[i] = b_c; } } int main(int argc, char* argv[]) try { client_omp_manager::limit_by_processor_count(); rocblas_client_init(); print_asan_kernel_warning("rocblas-bench"); fix_batch(argc, argv); Arguments arg; std::string function; std::string precision; std::string a_type; std::string b_type; std::string c_type; std::string d_type; std::string compute_type; std::string initialization; std::string filter; std::string name_filter; int32_t device_id = 0; int32_t parallel_devices = 0; int32_t flags = 0; int32_t geam_ex_op = 0; int32_t api = 0; bool datafile = rocblas_parse_data(argc, argv); bool atomics_allowed = false; bool atomics_not_allowed = true; bool log_function_name = false; bool log_datatype = false; bool any_stride = false; uint32_t math_mode = 0; uint64_t flush_batch_count = 1; uint64_t flush_memory_size = 0; bool fortran = false; bool eazy = false; arg.init(); // set all defaults options_description desc("rocblas-bench command line options"); desc.add_options() // clang-format off ("sizem,m", value(&arg.M)->default_value(128), "Specific matrix size: sizem is only applicable to BLAS-2 & BLAS-3: the number of " "rows or columns in matrix.") ("sizen,n", value(&arg.N)->default_value(128), "Specific matrix/vector size: BLAS-1: the length of the vector. BLAS-2 & " "BLAS-3: the number of rows or columns in matrix") ("sizek,k", value(&arg.K)->default_value(128), "Specific matrix size: BLAS-2: the number of sub or super-diagonals of A. BLAS-3: " "the number of columns in A and rows in B.") ("kl", value(&arg.KL)->default_value(32), "Specific matrix size: kl is only applicable to BLAS-2: The number of sub-diagonals " "of the banded matrix A.") ("ku", value(&arg.KU)->default_value(32), "Specific matrix size: ku is only applicable to BLAS-2: The number of super-diagonals " "of the banded matrix A.") ("lda", value(&arg.lda)->default_value(128), "Leading dimension of matrix A, is only applicable to BLAS-2 & BLAS-3.") ("ldb", value(&arg.ldb)->default_value(128), "Leading dimension of matrix B, is only applicable to BLAS-2 & BLAS-3.") ("ldc", value(&arg.ldc)->default_value(128), "Leading dimension of matrix C, is only applicable to BLAS-2 & BLAS-3.") ("ldd", value(&arg.ldd)->default_value(128), "Leading dimension of matrix D, is only applicable to BLAS-EX ") ("any_stride", value(&any_stride)->default_value(false), "Do not modify input strides based on leading dimensions") ("stride_a", value(&arg.stride_a)->default_value(128*128), "Specific stride of strided_batched matrix A, is only applicable to strided batched" "BLAS-2 and BLAS-3: second dimension * leading dimension.") ("stride_b", value(&arg.stride_b)->default_value(128*128), "Specific stride of strided_batched matrix B, is only applicable to strided batched" "BLAS-2 and BLAS-3: second dimension * leading dimension.") ("stride_c", value(&arg.stride_c)->default_value(128*128), "Specific stride of strided_batched matrix C, is only applicable to strided batched" "BLAS-2 and BLAS-3: second dimension * leading dimension.") ("stride_d", value(&arg.stride_d)->default_value(128*128), "Specific stride of strided_batched matrix D, is only applicable to strided batched" "BLAS_EX: second dimension * leading dimension.") ("alpha_stride", value(&arg.stride_c), "Batch alpha stride for gemv_batched and gemv_strided_batched in device pointer mode." " Alias for stride_c when using batch alpha/beta arrays.") ("beta_stride", value(&arg.stride_d), "Batch beta stride for gemv_batched and gemv_strided_batched in device pointer mode." " Alias for stride_d when using batch alpha/beta arrays.") ("stride_x", value(&arg.stride_x)->default_value(128*128), "Specific stride of strided_batched vector x, is only applicable to strided batched" "BLAS_2: second dimension.") ("stride_y", value(&arg.stride_y)->default_value(128*128), "Specific stride of strided_batched vector y, is only applicable to strided batched" "BLAS_2: leading dimension.") ("incx", value(&arg.incx)->default_value(1), "increment between values in x vector") ("incy", value(&arg.incy)->default_value(1), "increment between values in y vector") ("alpha", value(&arg.alpha)->default_value(1.0), "specifies the scalar alpha") ("alphai", value(&arg.alphai)->default_value(0.0), "specifies the imaginary part of the scalar alpha") ("beta", value(&arg.beta)->default_value(0.0), "specifies the scalar beta") ("betai", value(&arg.betai)->default_value(0.0), "specifies the imaginary part of the scalar beta") ("function,f", value(&function), "BLAS function to test.") ("precision,r", value(&precision)->default_value("f32_r"), "Precision. " "Options: h,s,d,c,z, f16_r,f32_r,f64_r,bf16_r,f32_c,f64_c,i8_r,i32_r") ("a_type", value(&a_type), "Precision of matrix A. " "Options: h,s,d,c,z,f16_r,f32_r,f64_r,bf16_r,f32_c,f64_c,i8_r,i32_r") ("b_type", value(&b_type), "Precision of matrix B. " "Options: h,s,d,c,z,f16_r,f32_r,f64_r,bf16_r,f32_c,f64_c,i8_r,i32_r") ("c_type", value(&c_type), "Precision of matrix C. " "Options: h,s,d,c,z,f16_r,f32_r,f64_r,bf16_r,f32_c,f64_c,i8_r,i32_r") ("d_type", value(&d_type), "Precision of matrix D. " "Options: h,s,d,c,z,f16_r,f32_r,f64_r,bf16_r,f32_c,f64_c,i8_r,i32_r") ("compute_type", value(&compute_type), "Precision of computation. " "Options: h,s,d,c,z,f16_r,f32_r,f64_r,bf16_r,f32_c,f64_c,i8_r,i32_r") ("initialization, init", value(&initialization)->default_value("hpl"), "Initialize with random integers, trig functions sin and cos, or hpl-like input. " "Options: rand_int, trig_float, hpl") ("transposeA", value(&arg.transA)->default_value('N'), "N = no transpose, T = transpose, C = conjugate transpose") ("transposeB", value(&arg.transB)->default_value('N'), "N = no transpose, T = transpose, C = conjugate transpose") ("side", value(&arg.side)->default_value('L'), "L = left, R = right. Only applicable to certain routines") ("uplo", value(&arg.uplo)->default_value('U'), "U = upper, L = lower. Only applicable to certain routines") // xsymv xsyrk xsyr2k xtrsm xtrsm_ex // xtrmm xtrsv ("diag", value(&arg.diag)->default_value('N'), "U = unit diagonal, N = non unit diagonal. Only applicable to certain routines") // xtrsm xtrsm_ex xtrsv xtrmm ("batch_count", value(&arg.batch_count)->default_value(1), "Number of matrices. Only applicable to batched and strided_batched routines") ("HMM", value(&arg.HMM)->default_value(false), "Parameter requesting the use of HipManagedMemory") ("test,t", value(&g_unit_check)->default_value(0), "Equality/tolerance check on GPU vs. CPU results? 0 = No, 1 = Yes (default: No). " "Warning: tests may require specific initialization to pass.") ("verify,v", value(&arg.norm_check)->default_value(0), "Norm check on GPU vs. CPU results? 0 = No, 1 = Yes (default: No)") ("iters,i", value(&arg.iters)->default_value(10), "Iterations to run inside timing loop") ("cold_iters,j", value(&arg.cold_iters)->default_value(2), "Cold Iterations to run before entering the timing loop") ("algo", value(&arg.algo)->default_value(0), "extended precision gemm algorithm") ("solution_index", value(&arg.solution_index)->default_value(0), "extended precision gemm solution index") ("flags", value(&flags)->default_value(rocblas_gemm_flags_none), "gemm_ex flags, see rocblas_gemm_flags enum in documentation") ("geam_ex_op", value(&geam_ex_op)->default_value(rocblas_geam_ex_operation_min_plus), "geam_ex_operation, 0: min_plus operation, 1: plus_min operation") ("atomics_allowed", bool_switch(&atomics_allowed)->default_value(false), "Atomic operations with non-determinism in results are allowed (default false)") ("atomics_not_allowed", bool_switch(&atomics_not_allowed)->default_value(true), "Atomic operations with non-determinism in results are not allowed (default true)") ("device", value(&device_id)->default_value(0), "Set default device to be used for subsequent program runs") ("parallel_devices", value(¶llel_devices)->default_value(0), "Set number of devices used for parallel runs (device 0 to parallel_devices-1)") ("outofplace", bool_switch(&arg.outofplace)->default_value(false), "for gemm_ex C and D are stored in separate memory, for trmm B and C are stored in separate memory") ("fortran", bool_switch(&fortran)->default_value(false), "Run using Fortran interface") ("api", value(&api)->default_value(0), "Use API, supercedes fortran flag (0==C, 1==C_64 ILP64, ...)") ("workspace", value(&arg.user_allocated_workspace)->default_value(0), "Set fixed workspace memory size instead of using rocblas managed memory") ("log_function_name", bool_switch(&log_function_name)->default_value(false), "Function name precedes other items.") ("log_datatype", bool_switch(&log_datatype)->default_value(false), "Include datatypes used in output.") ("use_hipblaslt", value(&arg.use_hipblaslt)->default_value(-1), "Whether to use hipblaslt (default: -1, always: 1, never: 0)") ("function_filter", value(&filter), "Simple strstr filter on function name only without wildcards") ("math_mode", value(&arg.math_mode)->default_value(rocblas_default_math), "extended precision gemm math mode") ("flush_batch_count", value(&arg.flush_batch_count)->default_value(1), "number of copies of arrays to allocate for cache flushing in timing code. Functions" " are called iters times in a timing loop. If the problem memory footprint is small" " enough, then arrays will be cached. flush_batch_count can be used to prevent caching." " For example, for sgemm with transA=transB=N:" " problem_memory_footprint = (m*k + k*n + m*n) * sizeof(float)." " To flush arrays before reuse set:" " flush_batch_count >= 1 + cache_size / problem_memory_footprint" " Note that in the calculation of flush_batch_count any padding from leading" " dimensions is not loaded to cache and not included in the problem_memory_footprint." " If you specify flush_batch_count you cannot also specify flush_memory_size") ("flush_memory_size", value(&arg.flush_memory_size)->default_value(0), "bytes of memory that will be occupied by arrays. Used only in timing code for cache flushing. Set to greater than" " cache size so arrays are flushed from cache before they are reused. When the size of arrays (the problem_memory_footprint)" " is smaller than flush_memory_size, then flush_batch_count copies of arrays are allocated where:" " flush_batch_count = flush_memory_size / problem_memory_footprint." " For sgemm with transA=transB=N" " problem_memory_footprint = (m*k + k*n + m*n) * sizeof(float). Note that any padding from leading" " dimensions is not loaded to cache and not included in the problem_memory_footprint." " If you specify flush_memory_size you cannot also specify flush_batch_count") ("name_filter", value(&name_filter), "Simple strstr filter on test name only without wildcards, only used with --yaml or --data") ("version", "Prints the version number") ("rocblas_tensile_commit_hash", "Prints the rocBLAS and Tensile commit-hashes") ("z", value(&eazy)->default_value(false), "Eazy way to set log_function_name and log_datatype (eye dialect form of easy)") ("help,h", "produces this help message"); // clang-format on // parse command line into arg structure and stack variables using desc variables_map vm; store(parse_command_line(argc, argv, desc), vm); notify(vm); if((argc <= 1 && !datafile) || vm.count("help")) { rocblas_cout << desc << std::endl; rocblas_cout << "Examples : ./rocblas-bench -f gemm -r s -m 4000 -n 4000 -k 4000 --lda " "4000 --ldb 4000 --ldc 4000 --transposeA N --transposeB T" << std::endl << std::endl << "\t " << "./rocblas-bench -f gemv -r s -m 10240 -n 10240 --lda 10240" << std::endl << std::endl << "\t " << "./rocblas-bench -f axpy -r d -n 102400000" << std::endl; return 0; } print_rocblas_version_string(); // version and commit hash if(vm.find("version") != vm.end() || vm.find("rocblas_tensile_commit_hash") != vm.end()) { return 0; } if((vm.count("alpha_stride") || vm.count("beta_stride")) && (arg.stride_c || arg.stride_d)) { arg.alpha_beta_stride = true; arg.pointer_mode_host = false; arg.pointer_mode_device = true; } // transfer local variable state arg.atomics_mode = rocblas_atomics_not_allowed; // two command line options so if either changed from default enable atomics if(atomics_allowed == true || atomics_not_allowed == false) arg.atomics_mode = rocblas_atomics_allowed; if(api) arg.api = rocblas_client_api(api); else if(fortran) arg.api = FORTRAN; static const char* fp16AltImplEnvStr = std::getenv("ROCBLAS_INTERNAL_FP16_ALT_IMPL"); static const int fp16AltImplEnv = (fp16AltImplEnvStr == NULL ? -1 : (std::atoi(fp16AltImplEnvStr) == 0 ? 0 : 1)); if(fp16AltImplEnv != -1) { if(fp16AltImplEnv == 0) flags &= ~rocblas_gemm_flags_fp16_alt_impl; else flags |= rocblas_gemm_flags_fp16_alt_impl; } static const char* fp16AltImplRoundEnvStr = std::getenv("ROCBLAS_INTERNAL_FP16_ALT_IMPL_RNZ"); static const int fp16AltImplRoundEnv = (fp16AltImplRoundEnvStr == NULL ? -1 : (std::atoi(fp16AltImplRoundEnvStr) == 0 ? 0 : 1)); if(fp16AltImplRoundEnv != -1) { if(fp16AltImplRoundEnv == 0) flags &= ~rocblas_gemm_flags_fp16_alt_impl_rnz; else flags |= rocblas_gemm_flags_fp16_alt_impl_rnz; } if(rocblas_internal_get_arch_name() != "gfx90a") { flags &= ~rocblas_gemm_flags_fp16_alt_impl; flags &= ~rocblas_gemm_flags_fp16_alt_impl_rnz; } arg.flags = rocblas_gemm_flags(flags); arg.geam_ex_op = rocblas_geam_ex_operation(geam_ex_op); if(eazy) { log_function_name = true; log_datatype = true; } ArgumentModel_set_log_function_name(log_function_name); ArgumentModel_set_log_datatype(log_datatype); // Device Query rocblas_int device_count = query_device_property(); rocblas_cout << std::endl; if(device_count <= device_id) throw std::invalid_argument("Invalid Device ID"); if(device_id >= 0) set_device(device_id); FrequencyMonitor& freq_monitor = getFrequencyMonitor(); freq_monitor.set_device_id(device_id); if(datafile) return rocblas_bench_datafile(filter, name_filter, any_stride); // single bench run // validate arguments std::transform(precision.begin(), precision.end(), precision.begin(), ::tolower); auto prec = string2rocblas_datatype(precision); if(prec == rocblas_datatype_invalid) throw std::invalid_argument("Invalid value for --precision " + precision); arg.a_type = a_type == "" ? prec : string2rocblas_datatype(a_type); if(arg.a_type == rocblas_datatype_invalid) throw std::invalid_argument("Invalid value for --a_type " + a_type); arg.b_type = b_type == "" ? prec : string2rocblas_datatype(b_type); if(arg.b_type == rocblas_datatype_invalid) throw std::invalid_argument("Invalid value for --b_type " + b_type); arg.c_type = c_type == "" ? prec : string2rocblas_datatype(c_type); if(arg.c_type == rocblas_datatype_invalid) throw std::invalid_argument("Invalid value for --c_type " + c_type); arg.d_type = d_type == "" ? prec : string2rocblas_datatype(d_type); if(arg.d_type == rocblas_datatype_invalid) throw std::invalid_argument("Invalid value for --d_type " + d_type); arg.compute_type = compute_type == "" ? prec : string2rocblas_datatype(compute_type); if(arg.compute_type == rocblas_datatype_invalid) throw std::invalid_argument("Invalid value for --compute_type " + compute_type); arg.initialization = string2rocblas_initialization(initialization); if(arg.initialization == static_cast(0)) // zero not in enum throw std::invalid_argument("Invalid value for --initialization " + initialization); if(arg.M < 0) throw std::invalid_argument("Invalid value for -m " + std::to_string(arg.M)); if(arg.N < 0) throw std::invalid_argument("Invalid value for -n " + std::to_string(arg.N)); if(arg.K < 0) throw std::invalid_argument("Invalid value for -k " + std::to_string(arg.K)); if(arg.norm_check < 0 || arg.norm_check > 1) throw std::invalid_argument("Invalid value for -v or --verify " + std::to_string(arg.norm_check)); int copied = snprintf(arg.function, sizeof(arg.function), "%s", function.c_str()); if(copied <= 0 || copied >= sizeof(arg.function)) throw std::invalid_argument("Invalid value for --function"); if(!parallel_devices) { std::string name_filter = ""; run_bench_test(true, arg, filter, name_filter, any_stride); } else run_bench_gpu_test(parallel_devices, arg, filter, any_stride); freeFrequencyMonitor(); int status = 0; // TODO: query for any failed tests rocblas_client_shutdown(); return status; } catch(const std::invalid_argument& exp) { rocblas_cerr << exp.what() << std::endl; return -1; }