Files
TheRock/rocm-libraries/projects/hipblaslt/clients/common/include/testing_auxiliary.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

3947 lines
185 KiB
C++

/*******************************************************************************
*
* MIT License
*
* Copyright (C) 2022-2026 Advanced Micro Devices, Inc.
*
* 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
#include <hipblaslt/hipblaslt.h>
#include <hipblaslt/hipblaslt-ext-op.h>
#include <hipblaslt/hipblaslt-ext.hpp> // Add check for hipblaslt-ext
#include "hipblaslt_test.hpp"
#include "flops.hpp"
#include "hipblaslt_datatype2string.hpp"
#include "hipblaslt_init.hpp"
#include "hipblaslt_math.hpp"
#include "hipblaslt_random.hpp"
#include "hipblaslt_vector.hpp"
#ifdef CODE_COVERAGE
#include "check_numerics_matrix.hpp"
#include "hipblaslt_internal.hpp"
#include "rocblaslt_mat_utils.hpp"
#include "rocroller_host.hpp"
#include "status.h"
#include "tensile_host.hpp"
#include "utility.hpp"
#endif
#include "unit.hpp"
#include "utility.hpp"
void testing_aux_handle_init_bad_arg(const Arguments& arg)
{
EXPECT_HIPBLAS_STATUS(hipblasLtCreate(nullptr), HIPBLAS_STATUS_INVALID_VALUE);
}
void testing_aux_handle_destroy_bad_arg(const Arguments& arg)
{
EXPECT_HIPBLAS_STATUS(hipblasLtDestroy(nullptr), HIPBLAS_STATUS_INVALID_VALUE);
}
void testing_aux_handle(const Arguments& arg)
{
hipblasLtHandle_t handle;
EXPECT_HIPBLAS_STATUS(hipblasLtCreate(&handle), HIPBLAS_STATUS_SUCCESS);
EXPECT_HIPBLAS_STATUS(hipblasLtDestroy(handle), HIPBLAS_STATUS_SUCCESS);
}
void testing_aux_mat_init_bad_arg(const Arguments& arg)
{
const int64_t row = 128;
const int64_t col = 128;
const int64_t ld = 128;
hipblasLtMatrixLayout_t m_descr;
EXPECT_HIPBLAS_STATUS(hipblasLtMatrixLayoutCreate(nullptr, arg.a_type, row, col, ld),
HIPBLAS_STATUS_INVALID_VALUE);
}
void testing_aux_mat_init(const Arguments& arg)
{
const int64_t row = 128;
const int64_t col = 128;
const int64_t ld = 128;
hipblaslt_local_handle handle{arg};
hipblaslt_local_matrix_layout mat(row, col, ld, arg.a_type);
EXPECT_HIPBLAS_STATUS(mat.status(), HIPBLAS_STATUS_SUCCESS);
}
void testing_aux_mat_destroy_bad_arg(const Arguments& arg)
{
EXPECT_HIPBLAS_STATUS(hipblasLtMatrixLayoutDestroy(nullptr), HIPBLAS_STATUS_INVALID_VALUE);
}
void testing_aux_mat_set_attr_bad_arg(const Arguments& arg)
{
const int64_t row = 128;
const int64_t col = 128;
const int64_t ld = 128;
int32_t data32;
int64_t data64;
uint32_t udata32;
uint64_t udata64;
hipblaslt_local_matrix_layout mat(row, col, ld, arg.a_type);
EXPECT_HIPBLAS_STATUS(mat.status(), HIPBLAS_STATUS_SUCCESS);
// Test with null matrix layout
EXPECT_HIPBLAS_STATUS(
hipblasLtMatrixLayoutSetAttribute(
nullptr, HIPBLASLT_MATRIX_LAYOUT_BATCH_COUNT, &data32, sizeof(int32_t)),
HIPBLAS_STATUS_NOT_INITIALIZED);
EXPECT_HIPBLAS_STATUS(hipblasLtMatrixLayoutSetAttribute(
mat, HIPBLASLT_MATRIX_LAYOUT_BATCH_COUNT, nullptr, sizeof(int32_t)),
HIPBLAS_STATUS_INVALID_VALUE);
// Test with zero size
EXPECT_HIPBLAS_STATUS(
hipblasLtMatrixLayoutSetAttribute(mat, HIPBLASLT_MATRIX_LAYOUT_BATCH_COUNT, &data32, 0),
HIPBLAS_STATUS_INVALID_VALUE);
// Test HIPBLASLT_MATRIX_LAYOUT_BATCH_COUNT with insufficient buffer size
data32 = 1;
EXPECT_HIPBLAS_STATUS(
hipblasLtMatrixLayoutSetAttribute(
mat, HIPBLASLT_MATRIX_LAYOUT_BATCH_COUNT, &data32, sizeof(int32_t) / 2),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(
hipblasLtMatrixLayoutSetAttribute(mat, HIPBLASLT_MATRIX_LAYOUT_BATCH_COUNT, &data32, 1),
HIPBLAS_STATUS_INVALID_VALUE);
// Test HIPBLASLT_MATRIX_LAYOUT_STRIDED_BATCH_OFFSET with insufficient buffer size
data64 = ld * col;
EXPECT_HIPBLAS_STATUS(
hipblasLtMatrixLayoutSetAttribute(
mat, HIPBLASLT_MATRIX_LAYOUT_STRIDED_BATCH_OFFSET, &data64, sizeof(int64_t) / 2),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(hipblasLtMatrixLayoutSetAttribute(
mat, HIPBLASLT_MATRIX_LAYOUT_STRIDED_BATCH_OFFSET, &data64, 1),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(
hipblasLtMatrixLayoutSetAttribute(
mat, HIPBLASLT_MATRIX_LAYOUT_STRIDED_BATCH_OFFSET, nullptr, sizeof(int64_t)),
HIPBLAS_STATUS_INVALID_VALUE);
// Test HIPBLASLT_MATRIX_LAYOUT_TYPE with insufficient buffer size
udata32 = static_cast<uint32_t>(arg.a_type);
EXPECT_HIPBLAS_STATUS(hipblasLtMatrixLayoutSetAttribute(
mat, HIPBLASLT_MATRIX_LAYOUT_TYPE, &udata32, sizeof(uint32_t) / 2),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(
hipblasLtMatrixLayoutSetAttribute(mat, HIPBLASLT_MATRIX_LAYOUT_TYPE, &udata32, 1),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(hipblasLtMatrixLayoutSetAttribute(
mat, HIPBLASLT_MATRIX_LAYOUT_TYPE, nullptr, sizeof(uint32_t)),
HIPBLAS_STATUS_INVALID_VALUE);
// Test HIPBLASLT_MATRIX_LAYOUT_ORDER with insufficient buffer size
data32 = HIPBLASLT_ORDER_COL;
EXPECT_HIPBLAS_STATUS(hipblasLtMatrixLayoutSetAttribute(
mat, HIPBLASLT_MATRIX_LAYOUT_ORDER, &data32, sizeof(int32_t) / 2),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(
hipblasLtMatrixLayoutSetAttribute(mat, HIPBLASLT_MATRIX_LAYOUT_ORDER, &data32, 1),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(hipblasLtMatrixLayoutSetAttribute(
mat, HIPBLASLT_MATRIX_LAYOUT_ORDER, nullptr, sizeof(int32_t)),
HIPBLAS_STATUS_INVALID_VALUE);
// Test HIPBLASLT_MATRIX_LAYOUT_ROWS with insufficient buffer size
udata64 = static_cast<uint64_t>(row);
EXPECT_HIPBLAS_STATUS(hipblasLtMatrixLayoutSetAttribute(
mat, HIPBLASLT_MATRIX_LAYOUT_ROWS, &udata64, sizeof(uint64_t) / 2),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(
hipblasLtMatrixLayoutSetAttribute(mat, HIPBLASLT_MATRIX_LAYOUT_ROWS, &udata64, 1),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(hipblasLtMatrixLayoutSetAttribute(
mat, HIPBLASLT_MATRIX_LAYOUT_ROWS, nullptr, sizeof(uint64_t)),
HIPBLAS_STATUS_INVALID_VALUE);
// Test HIPBLASLT_MATRIX_LAYOUT_COLS with insufficient buffer size
udata64 = static_cast<uint64_t>(col);
EXPECT_HIPBLAS_STATUS(hipblasLtMatrixLayoutSetAttribute(
mat, HIPBLASLT_MATRIX_LAYOUT_COLS, &udata64, sizeof(uint64_t) / 2),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(
hipblasLtMatrixLayoutSetAttribute(mat, HIPBLASLT_MATRIX_LAYOUT_COLS, &udata64, 1),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(hipblasLtMatrixLayoutSetAttribute(
mat, HIPBLASLT_MATRIX_LAYOUT_COLS, nullptr, sizeof(uint64_t)),
HIPBLAS_STATUS_INVALID_VALUE);
// Test HIPBLASLT_MATRIX_LAYOUT_LD with insufficient buffer size
data64 = ld;
EXPECT_HIPBLAS_STATUS(hipblasLtMatrixLayoutSetAttribute(
mat, HIPBLASLT_MATRIX_LAYOUT_LD, &data64, sizeof(int64_t) / 2),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(
hipblasLtMatrixLayoutSetAttribute(mat, HIPBLASLT_MATRIX_LAYOUT_LD, &data64, 1),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(hipblasLtMatrixLayoutSetAttribute(
mat, HIPBLASLT_MATRIX_LAYOUT_LD, nullptr, sizeof(int64_t)),
HIPBLAS_STATUS_INVALID_VALUE);
// Test with invalid attribute (assuming there's a MAX value for bounds checking)
EXPECT_HIPBLAS_STATUS(
hipblasLtMatrixLayoutSetAttribute(
mat, static_cast<hipblasLtMatrixLayoutAttribute_t>(999), &data32, sizeof(int32_t)),
HIPBLAS_STATUS_INVALID_VALUE);
}
void testing_aux_mat_get_attr_bad_arg(const Arguments& arg)
{
const int64_t row = 128;
const int64_t col = 128;
const int64_t ld = 128;
hipblaslt_local_matrix_layout mat(row, col, ld, arg.a_type);
EXPECT_HIPBLAS_STATUS(mat.status(), HIPBLAS_STATUS_SUCCESS);
int data;
int64_t data64;
size_t sizeWritten;
EXPECT_HIPBLAS_STATUS(
hipblasLtMatrixLayoutGetAttribute(
nullptr, HIPBLASLT_MATRIX_LAYOUT_BATCH_COUNT, &data, sizeof(int), &sizeWritten),
HIPBLAS_STATUS_NOT_INITIALIZED);
EXPECT_HIPBLAS_STATUS(
hipblasLtMatrixLayoutGetAttribute(
mat, HIPBLASLT_MATRIX_LAYOUT_BATCH_COUNT, nullptr, sizeof(int), &sizeWritten),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(hipblasLtMatrixLayoutGetAttribute(
mat, HIPBLASLT_MATRIX_LAYOUT_BATCH_COUNT, nullptr, 0, nullptr),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(hipblasLtMatrixLayoutGetAttribute(
mat, HIPBLASLT_MATRIX_LAYOUT_BATCH_COUNT, &data, 1, &sizeWritten),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(
hipblasLtMatrixLayoutGetAttribute(mat,
HIPBLASLT_MATRIX_LAYOUT_STRIDED_BATCH_OFFSET,
nullptr,
sizeof(int64_t),
&sizeWritten),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(
hipblasLtMatrixLayoutGetAttribute(
mat, HIPBLASLT_MATRIX_LAYOUT_STRIDED_BATCH_OFFSET, &data64, sizeof(int), &sizeWritten),
HIPBLAS_STATUS_INVALID_VALUE);
// test sizeWritten is nullptr, and the return state should be success
data = 0;
EXPECT_HIPBLAS_STATUS(
hipblasLtMatrixLayoutGetAttribute(
mat, HIPBLASLT_MATRIX_LAYOUT_BATCH_COUNT, &data, sizeof(int), nullptr),
HIPBLAS_STATUS_SUCCESS);
EXPECT_EQ(data, 1);
}
void testing_aux_mat_set_get_attr(const Arguments& arg)
{
const int64_t row = 128;
const int64_t col = 128;
const int64_t ld = 128;
hipblaslt_local_matrix_layout mat(row, col, ld, arg.a_type);
EXPECT_HIPBLAS_STATUS(mat.status(), HIPBLAS_STATUS_SUCCESS);
int32_t data, data_r;
size_t sizeWritten;
data = 2;
EXPECT_HIPBLAS_STATUS(hipblasLtMatrixLayoutSetAttribute(
mat, HIPBLASLT_MATRIX_LAYOUT_BATCH_COUNT, &data, sizeof(data)),
HIPBLAS_STATUS_SUCCESS);
EXPECT_HIPBLAS_STATUS(
hipblasLtMatrixLayoutGetAttribute(
mat, HIPBLASLT_MATRIX_LAYOUT_BATCH_COUNT, &data_r, sizeof(data), &sizeWritten),
HIPBLAS_STATUS_SUCCESS);
ASSERT_TRUE(data_r == data);
std::vector<int64_t> data64_v = {0, ld * col};
int64_t data64_r = 0;
for(int64_t data64 : data64_v)
{
EXPECT_HIPBLAS_STATUS(
hipblasLtMatrixLayoutSetAttribute(
mat, HIPBLASLT_MATRIX_LAYOUT_STRIDED_BATCH_OFFSET, &data64, sizeof(int64_t)),
HIPBLAS_STATUS_SUCCESS);
EXPECT_HIPBLAS_STATUS(
hipblasLtMatrixLayoutGetAttribute(mat,
HIPBLASLT_MATRIX_LAYOUT_STRIDED_BATCH_OFFSET,
&data64_r,
sizeof(int64_t),
&sizeWritten),
HIPBLAS_STATUS_SUCCESS);
ASSERT_TRUE(data64_r == data64);
}
}
void testing_aux_matmul_init_bad_arg(const Arguments& arg)
{
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescCreate(nullptr, arg.compute_type, arg.scale_type),
HIPBLAS_STATUS_INVALID_VALUE);
}
void testing_aux_matmul_init(const Arguments& arg)
{
const hipblasOperation_t opA = HIPBLAS_OP_T;
const hipblasOperation_t opB = HIPBLAS_OP_N;
hipblaslt_local_matmul_descr matmul(opA, opB, arg.compute_type, arg.scale_type);
EXPECT_HIPBLAS_STATUS(matmul.status(), HIPBLAS_STATUS_SUCCESS);
}
void testing_aux_matmul_set_attr_bad_arg(const Arguments& arg)
{
const hipblasOperation_t opA = HIPBLAS_OP_T;
const hipblasOperation_t opB = HIPBLAS_OP_N;
hipblaslt_local_matmul_descr matmul(opA, opB, arg.compute_type, arg.scale_type);
EXPECT_HIPBLAS_STATUS(matmul.status(), HIPBLAS_STATUS_SUCCESS);
hipblasLtEpilogue_t data = HIPBLASLT_EPILOGUE_RELU;
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescSetAttribute(
nullptr, HIPBLASLT_MATMUL_DESC_EPILOGUE, &data, sizeof(data)),
HIPBLAS_STATUS_NOT_INITIALIZED);
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescSetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_EPILOGUE, nullptr, sizeof(data)),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescSetAttribute(matmul, HIPBLASLT_MATMUL_DESC_EPILOGUE, &data, 1),
HIPBLAS_STATUS_INVALID_VALUE);
}
void testing_aux_matmul_get_attr_bad_arg(const Arguments& arg)
{
const hipblasOperation_t opA = HIPBLAS_OP_T;
const hipblasOperation_t opB = HIPBLAS_OP_N;
hipblaslt_local_matmul_descr matmul(opA, opB, arg.compute_type, arg.scale_type);
EXPECT_HIPBLAS_STATUS(matmul.status(), HIPBLAS_STATUS_SUCCESS);
hipblasLtEpilogue_t data = HIPBLASLT_EPILOGUE_RELU;
size_t sizeWritten;
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescGetAttribute(
nullptr, HIPBLASLT_MATMUL_DESC_EPILOGUE, &data, sizeof(data), &sizeWritten),
HIPBLAS_STATUS_NOT_INITIALIZED);
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescGetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_EPILOGUE, nullptr, sizeof(data), &sizeWritten),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescGetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_EPILOGUE, &data, 1, &sizeWritten),
HIPBLAS_STATUS_INVALID_VALUE);
void* dBias = nullptr;
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescGetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_BIAS_POINTER, &dBias, 4, &sizeWritten),
HIPBLAS_STATUS_INVALID_VALUE);
// test sizeWritten is nullptr, and the return state should be success
data = HIPBLASLT_EPILOGUE_RELU;
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescGetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_EPILOGUE, &data, sizeof(data), nullptr),
HIPBLAS_STATUS_SUCCESS);
// test return buffer value equals HIPBLASLT_EPILOGUE_DEFAULT
EXPECT_EQ(data, HIPBLASLT_EPILOGUE_DEFAULT);
}
void testing_aux_matmul_set_get_attr(const Arguments& arg)
{
size_t sizeWritten;
hipblasLtMatmulDesc_t matmul;
CHECK_HIPBLASLT_ERROR(hipblasLtMatmulDescCreate(&matmul, arg.compute_type, arg.scale_type));
int64_t m = 1;
int64_t n = 1;
int64_t k = 1;
// For HIPBLASLT_MATMUL_DESC_TRANSA
hipblasOperation_t transA = HIPBLAS_OP_T;
hipblasOperation_t transA_r = HIPBLAS_OP_N;
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescSetAttribute(matmul, HIPBLASLT_MATMUL_DESC_TRANSA, &transA, 0),
HIPBLAS_STATUS_INVALID_VALUE); // edge case
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescSetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_TRANSA, &transA, sizeof(int32_t) / 2),
HIPBLAS_STATUS_INVALID_VALUE); // edge case
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescSetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_TRANSA, &transA, sizeof(int32_t)),
HIPBLAS_STATUS_SUCCESS); // normal case
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescGetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_BIAS_POINTER, &transA_r, 0, nullptr),
HIPBLASLT_MATMUL_DESC_BIAS_POINTER); // edge case
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescGetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_TRANSA, &transA_r, sizeof(transA_r) / 2, &sizeWritten),
HIPBLAS_STATUS_INVALID_VALUE); // edge case
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescGetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_TRANSA, &transA_r, sizeof(transA_r), &sizeWritten),
HIPBLAS_STATUS_SUCCESS); // normal case
ASSERT_TRUE(transA_r == transA); // validate
// For HIPBLASLT_MATMUL_DESC_TRANSB
hipblasOperation_t transB = HIPBLAS_OP_N;
hipblasOperation_t transB_r = HIPBLAS_OP_T;
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescSetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_TRANSB, &transB, sizeof(int32_t) / 2),
HIPBLAS_STATUS_INVALID_VALUE); // edge case
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescSetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_TRANSB, &transB, sizeof(int32_t)),
HIPBLAS_STATUS_SUCCESS); // normal case
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescGetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_TRANSB, &transB_r, sizeof(transB_r) / 2, &sizeWritten),
HIPBLAS_STATUS_INVALID_VALUE); // edge case
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescGetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_TRANSB, &transB_r, sizeof(transB_r), &sizeWritten),
HIPBLAS_STATUS_SUCCESS); // normal case
ASSERT_TRUE(transB_r == transB); // validate
// for HIPBLASLT_MATMUL_DESC_EPILOGUE
hipblasLtEpilogue_t data = HIPBLASLT_EPILOGUE_DEFAULT;
hipblasLtEpilogue_t data_r = HIPBLASLT_EPILOGUE_RELU;
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescSetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_EPILOGUE, &data, sizeof(data)),
HIPBLAS_STATUS_SUCCESS);
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescGetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_EPILOGUE, &data_r, sizeof(data_r), &sizeWritten),
HIPBLAS_STATUS_SUCCESS);
ASSERT_TRUE(data_r == data);
// for HIPBLASLT_MATMUL_DESC_BIAS_POINTER set and get
void* d_bias;
void* d_bias_r;
CHECK_HIP_ERROR(hipMalloc(&d_bias, k * sizeof(hipblasLtHalf)));
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescSetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_BIAS_POINTER, &d_bias, sizeof(void*) / 2),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescSetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_BIAS_POINTER, &d_bias, sizeof(void*)),
HIPBLAS_STATUS_SUCCESS);
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescGetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_BIAS_POINTER, &d_bias_r, sizeof(d_bias_r), &sizeWritten),
HIPBLAS_STATUS_SUCCESS);
ASSERT_TRUE(d_bias_r == d_bias);
// for HIPBLASLT_MATMUL_DESC_A_SCALE_POINTER
// We create a new matmul_descr becasue we don't want to set matmulDesc->scaleAType as Scalar in advance.
// If we set it as Scalar, it will skip some cases, which is not what we desire for.
const hipblasOperation_t opA = HIPBLAS_OP_T;
const hipblasOperation_t opB = HIPBLAS_OP_N;
hipblaslt_local_matmul_descr matmul_descr(opA, opB, arg.compute_type, arg.scale_type);
EXPECT_HIPBLAS_STATUS(matmul_descr.status(), HIPBLAS_STATUS_SUCCESS);
float h_scale_a_for_desc_a_scale_pointer = 2.f; // Example scale value, adjust as needed
float* d_scale_a;
float* d_scale_a_r;
CHECK_HIP_ERROR(hipMalloc(&d_scale_a, sizeof(float)));
CHECK_HIP_ERROR(hipMemcpy(
d_scale_a, &h_scale_a_for_desc_a_scale_pointer, sizeof(float), hipMemcpyHostToDevice));
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescSetAttribute(
matmul_descr, HIPBLASLT_MATMUL_DESC_A_SCALE_POINTER, &d_scale_a, sizeof(float*) / 2),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescSetAttribute(
matmul_descr, HIPBLASLT_MATMUL_DESC_A_SCALE_POINTER, &d_scale_a, sizeof(float*)),
HIPBLAS_STATUS_SUCCESS);
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescGetAttribute(matmul_descr,
HIPBLASLT_MATMUL_DESC_A_SCALE_POINTER,
&d_scale_a_r,
sizeof(float*) / 2,
&sizeWritten),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescGetAttribute(matmul_descr,
HIPBLASLT_MATMUL_DESC_A_SCALE_POINTER,
&d_scale_a_r,
sizeof(float*),
&sizeWritten),
HIPBLAS_STATUS_SUCCESS);
ASSERT_TRUE(d_scale_a_r == d_scale_a); // validate
// HIPBLASLT_MATMUL_DESC_A_SCALE_MODE
hipblasLtMatmulMatrixScale_t scale_mode_a = HIPBLASLT_MATMUL_MATRIX_SCALE_VEC32_UE8M0;
hipblasLtMatmulMatrixScale_t scale_mode_a_r = HIPBLASLT_MATMUL_MATRIX_SCALE_END;
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescGetAttribute(matmul,
HIPBLASLT_MATMUL_DESC_A_SCALE_MODE,
&scale_mode_a_r,
sizeof(uint32_t),
&sizeWritten),
HIPBLAS_STATUS_INVALID_VALUE); // we didn't set it yet, so we get error
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescSetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_A_SCALE_MODE, &scale_mode_a, sizeof(uint32_t) / 2),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescSetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_A_SCALE_MODE, &scale_mode_a, sizeof(uint32_t)),
HIPBLAS_STATUS_SUCCESS);
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescGetAttribute(matmul,
HIPBLASLT_MATMUL_DESC_A_SCALE_MODE,
&scale_mode_a_r,
sizeof(uint32_t) / 2,
&sizeWritten),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescGetAttribute(matmul,
HIPBLASLT_MATMUL_DESC_A_SCALE_MODE,
&scale_mode_a_r,
sizeof(uint32_t),
&sizeWritten),
HIPBLAS_STATUS_SUCCESS);
ASSERT_TRUE(scale_mode_a_r == scale_mode_a); // validate
// HIPBLASLT_MATMUL_DESC_B_SCALE_MODE
hipblasLtMatmulMatrixScale_t scale_mode_b = HIPBLASLT_MATMUL_MATRIX_SCALE_VEC32_UE8M0;
hipblasLtMatmulMatrixScale_t scale_mode_b_r = HIPBLASLT_MATMUL_MATRIX_SCALE_END;
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescGetAttribute(matmul,
HIPBLASLT_MATMUL_DESC_B_SCALE_MODE,
&scale_mode_b_r,
sizeof(uint32_t),
&sizeWritten),
HIPBLAS_STATUS_INVALID_VALUE); // we didn't set it yet, so we get error
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescSetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_B_SCALE_MODE, &scale_mode_b, sizeof(uint32_t) / 2),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescSetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_B_SCALE_MODE, &scale_mode_b, sizeof(uint32_t)),
HIPBLAS_STATUS_SUCCESS);
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescGetAttribute(matmul,
HIPBLASLT_MATMUL_DESC_B_SCALE_MODE,
&scale_mode_b_r,
sizeof(uint32_t) / 2,
&sizeWritten),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescGetAttribute(matmul,
HIPBLASLT_MATMUL_DESC_B_SCALE_MODE,
&scale_mode_b_r,
sizeof(uint32_t),
&sizeWritten),
HIPBLAS_STATUS_SUCCESS);
ASSERT_TRUE(scale_mode_b_r == scale_mode_b); // validate
scale_mode_a = HIPBLASLT_MATMUL_MATRIX_SCALE_SCALAR_32F;
scale_mode_b = HIPBLASLT_MATMUL_MATRIX_SCALE_SCALAR_32F;
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescSetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_A_SCALE_MODE, &scale_mode_a, sizeof(uint32_t)),
HIPBLAS_STATUS_SUCCESS);
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescGetAttribute(matmul,
HIPBLASLT_MATMUL_DESC_A_SCALE_MODE,
&scale_mode_a_r,
sizeof(uint32_t),
&sizeWritten),
HIPBLAS_STATUS_SUCCESS);
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescSetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_B_SCALE_MODE, &scale_mode_b, sizeof(uint32_t)),
HIPBLAS_STATUS_SUCCESS);
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescGetAttribute(matmul,
HIPBLASLT_MATMUL_DESC_B_SCALE_MODE,
&scale_mode_b_r,
sizeof(uint32_t),
&sizeWritten),
HIPBLAS_STATUS_SUCCESS);
ASSERT_TRUE(scale_mode_a_r == scale_mode_a); // validate
ASSERT_TRUE(scale_mode_b_r == scale_mode_b); // ditto
scale_mode_a = HIPBLASLT_MATMUL_MATRIX_SCALE_OUTER_VEC_32F;
scale_mode_b = HIPBLASLT_MATMUL_MATRIX_SCALE_OUTER_VEC_32F;
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescSetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_A_SCALE_MODE, &scale_mode_a, sizeof(uint32_t)),
HIPBLAS_STATUS_SUCCESS);
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescGetAttribute(matmul,
HIPBLASLT_MATMUL_DESC_A_SCALE_MODE,
&scale_mode_a_r,
sizeof(uint32_t),
&sizeWritten),
HIPBLAS_STATUS_SUCCESS);
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescSetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_B_SCALE_MODE, &scale_mode_b, sizeof(uint32_t)),
HIPBLAS_STATUS_SUCCESS);
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescGetAttribute(matmul,
HIPBLASLT_MATMUL_DESC_B_SCALE_MODE,
&scale_mode_b_r,
sizeof(uint32_t),
&sizeWritten),
HIPBLAS_STATUS_SUCCESS);
ASSERT_TRUE(scale_mode_a_r == scale_mode_a); // validate
scale_mode_a = HIPBLASLT_MATMUL_MATRIX_SCALE_VEC16_UE4M3;
scale_mode_b = HIPBLASLT_MATMUL_MATRIX_SCALE_VEC16_UE4M3;
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescSetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_A_SCALE_MODE, &scale_mode_a, sizeof(uint32_t)),
HIPBLAS_STATUS_SUCCESS);
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescGetAttribute(matmul,
HIPBLASLT_MATMUL_DESC_A_SCALE_MODE,
&scale_mode_a_r,
sizeof(uint32_t),
&sizeWritten),
HIPBLAS_STATUS_SUCCESS);
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescSetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_B_SCALE_MODE, &scale_mode_b, sizeof(uint32_t)),
HIPBLAS_STATUS_SUCCESS);
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescGetAttribute(matmul,
HIPBLASLT_MATMUL_DESC_B_SCALE_MODE,
&scale_mode_b_r,
sizeof(uint32_t),
&sizeWritten),
HIPBLAS_STATUS_SUCCESS);
ASSERT_TRUE(
scale_mode_a_r
== HIPBLASLT_MATMUL_MATRIX_SCALE_VEC16_UE4M3); // validate round-trip
ASSERT_TRUE(scale_mode_b_r == HIPBLASLT_MATMUL_MATRIX_SCALE_VEC16_UE4M3); // ditto
hipStream_t stream;
CHECK_HIP_ERROR(hipStreamCreate(&stream));
// for HIPBLASLT_MATMUL_DESC_B_SCALE_POINTER
float h_scale_b = 3.f;
float* d_scale_b;
float* d_scale_b_r;
CHECK_HIP_ERROR(hipMalloc(&d_scale_b, sizeof(float)));
CHECK_HIP_ERROR(
hipMemcpyAsync(d_scale_b, &h_scale_b, sizeof(float), hipMemcpyHostToDevice, stream));
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescSetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_B_SCALE_POINTER, &d_scale_b, sizeof(float*) / 2),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescSetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_B_SCALE_POINTER, &d_scale_b, sizeof(float*)),
HIPBLAS_STATUS_SUCCESS);
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescGetAttribute(matmul,
HIPBLASLT_MATMUL_DESC_B_SCALE_POINTER,
&d_scale_b_r,
sizeof(float*) / 2,
&sizeWritten),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescGetAttribute(matmul,
HIPBLASLT_MATMUL_DESC_B_SCALE_POINTER,
&d_scale_b_r,
sizeof(float*),
&sizeWritten),
HIPBLAS_STATUS_SUCCESS);
ASSERT_TRUE(d_scale_b == d_scale_b_r); // validate
// for HIPBLASLT_MATMUL_DESC_C_SCALE_POINTER & HIPBLASLT_MATMUL_DESC_D_SCALE_POINTER
float h_scale_c = 3.f;
float h_scale_d = 3.f;
float* d_scale_c;
float* d_scale_d;
CHECK_HIP_ERROR(hipMalloc(&d_scale_c, sizeof(float)));
CHECK_HIP_ERROR(hipMalloc(&d_scale_d, sizeof(float)));
CHECK_HIP_ERROR(
hipMemcpyAsync(d_scale_c, &h_scale_c, sizeof(float), hipMemcpyHostToDevice, stream));
CHECK_HIP_ERROR(
hipMemcpyAsync(d_scale_d, &h_scale_d, sizeof(float), hipMemcpyHostToDevice, stream));
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescSetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_C_SCALE_POINTER, &d_scale_c, sizeof(float*) / 2),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescSetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_C_SCALE_POINTER, &d_scale_c, sizeof(float*)),
HIPBLAS_STATUS_SUCCESS);
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescSetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_D_SCALE_POINTER, &d_scale_d, sizeof(float*) / 2),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescSetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_D_SCALE_POINTER, &d_scale_d, sizeof(float*)),
HIPBLAS_STATUS_SUCCESS);
// for HIPBLASLT_MATMUL_DESC_EPILOGUE_AUX_SCALE_POINTER
float h_scale_e = 3.f;
float* d_scale_e;
CHECK_HIP_ERROR(hipMalloc(&d_scale_e, sizeof(float)));
CHECK_HIP_ERROR(
hipMemcpyAsync(d_scale_e, &h_scale_e, sizeof(float), hipMemcpyHostToDevice, stream));
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescSetAttribute(matmul,
HIPBLASLT_MATMUL_DESC_EPILOGUE_AUX_SCALE_POINTER,
&d_scale_e,
sizeof(float*) / 2),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescSetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_EPILOGUE_AUX_SCALE_POINTER, &d_scale_e, sizeof(float*)),
HIPBLAS_STATUS_SUCCESS);
// For HIPBLASLT_MATMUL_DESC_POINTER_MODE
hipblasLtPointerMode_t pMode = HIPBLASLT_POINTER_MODE_ALPHA_DEVICE_VECTOR_BETA_HOST;
hipblasLtPointerMode_t pMode_r = HIPBLASLT_POINTER_MODE_HOST;
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescSetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_POINTER_MODE, &pMode, sizeof(pMode) / 2),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescSetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_POINTER_MODE, &pMode, sizeof(pMode)),
HIPBLAS_STATUS_SUCCESS);
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescGetAttribute(matmul,
HIPBLASLT_MATMUL_DESC_POINTER_MODE,
&pMode_r,
sizeof(pMode_r) / 2,
&sizeWritten),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescGetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_POINTER_MODE, &pMode_r, sizeof(pMode_r), &sizeWritten),
HIPBLAS_STATUS_SUCCESS);
ASSERT_TRUE(pMode_r == pMode); // validate
// For HIPBLASLT_MATMUL_DESC_BIAS_DATA_TYPE Set Desc Bias Data Type
int32_t bias_data_type = HIP_R_16F;
int32_t bias_data_type_r = HIP_R_32F;
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescSetAttribute(matmul,
HIPBLASLT_MATMUL_DESC_BIAS_DATA_TYPE,
&bias_data_type,
sizeof(bias_data_type) / 2),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescSetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_BIAS_DATA_TYPE, &bias_data_type, sizeof(bias_data_type)),
HIPBLAS_STATUS_SUCCESS);
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescGetAttribute(matmul,
HIPBLASLT_MATMUL_DESC_BIAS_DATA_TYPE,
&bias_data_type_r,
sizeof(bias_data_type_r) / 2,
&sizeWritten),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescGetAttribute(matmul,
HIPBLASLT_MATMUL_DESC_BIAS_DATA_TYPE,
&bias_data_type_r,
sizeof(bias_data_type_r),
&sizeWritten),
HIPBLAS_STATUS_SUCCESS);
ASSERT_TRUE(bias_data_type_r == bias_data_type); // validate
// For HIPBLASLT_MATMUL_DESC_EPILOGUE_AUX_POINTER Set auxiliary buffer
void* d_aux_buffer;
CHECK_HIP_ERROR(hipMalloc(&d_aux_buffer, m * n * sizeof(hipblasLtHalf)));
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescSetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_EPILOGUE_AUX_POINTER, &d_aux_buffer, sizeof(void*) / 2),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescSetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_EPILOGUE_AUX_POINTER, &d_aux_buffer, sizeof(void*)),
HIPBLAS_STATUS_SUCCESS);
// For HIPBLASLT_MATMUL_DESC_EPILOGUE_AUX_LD Set auxiliary leading dimension (ld)
const int64_t aux_ld = m;
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescSetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_EPILOGUE_AUX_LD, &aux_ld, sizeof(aux_ld) / 2),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescSetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_EPILOGUE_AUX_LD, &aux_ld, sizeof(aux_ld)),
HIPBLAS_STATUS_SUCCESS);
// for HIPBLASLT_MATMUL_DESC_EPILOGUE_AUX_BATCH_STRIDE & Set Epilogue Aux Batch Stride
const int64_t aux_batch_stride = m * n;
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescSetAttribute(matmul,
HIPBLASLT_MATMUL_DESC_EPILOGUE_AUX_BATCH_STRIDE,
&aux_batch_stride,
sizeof(aux_batch_stride) / 2),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescSetAttribute(matmul,
HIPBLASLT_MATMUL_DESC_EPILOGUE_AUX_BATCH_STRIDE,
&aux_batch_stride,
sizeof(aux_batch_stride)),
HIPBLAS_STATUS_SUCCESS);
// for HIPBLASLT_MATMUL_DESC_AMAX_D_POINTER
void* d_out_amax;
void* d_out_amax_r;
CHECK_HIP_ERROR(hipMalloc(&d_out_amax, 1 * sizeof(float)));
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescSetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_AMAX_D_POINTER, &d_out_amax, sizeof(void*) / 2),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescSetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_AMAX_D_POINTER, &d_out_amax, sizeof(void*)),
HIPBLAS_STATUS_SUCCESS);
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescGetAttribute(matmul,
HIPBLASLT_MATMUL_DESC_AMAX_D_POINTER,
&d_out_amax_r,
sizeof(d_out_amax_r) / 2,
&sizeWritten),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescGetAttribute(matmul,
HIPBLASLT_MATMUL_DESC_AMAX_D_POINTER,
&d_out_amax_r,
sizeof(d_out_amax_r),
&sizeWritten),
HIPBLAS_STATUS_SUCCESS);
ASSERT_TRUE(d_out_amax == d_out_amax_r); // validate
// for HIPBLASLT_MATMUL_DESC_EPILOGUE_AUX_DATA_TYPE
hipDataType aux_type_r;
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescSetAttribute(matmul,
HIPBLASLT_MATMUL_DESC_EPILOGUE_AUX_DATA_TYPE,
&arg.aux_type,
sizeof(hipDataType) / 2),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescSetAttribute(matmul,
HIPBLASLT_MATMUL_DESC_EPILOGUE_AUX_DATA_TYPE,
&arg.aux_type,
sizeof(hipDataType)),
HIPBLAS_STATUS_SUCCESS);
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescGetAttribute(matmul,
HIPBLASLT_MATMUL_DESC_EPILOGUE_AUX_DATA_TYPE,
&aux_type_r,
sizeof(aux_type_r) / 2,
&sizeWritten),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescGetAttribute(matmul,
HIPBLASLT_MATMUL_DESC_EPILOGUE_AUX_DATA_TYPE,
&aux_type_r,
sizeof(aux_type_r),
&sizeWritten),
HIPBLAS_STATUS_SUCCESS);
ASSERT_TRUE(arg.aux_type == aux_type_r); // validate
// for HIPBLASLT_MATMUL_DESC_COMPUTE_INPUT_TYPE_A_EXT & HIPBLASLT_MATMUL_DESC_COMPUTE_INPUT_TYPE_B_EXT
hipDataType computeTypeA = HIP_R_16F;
hipDataType computeTypeA_r = HIP_R_32F;
hipDataType computeTypeB = HIP_R_16F;
hipDataType computeTypeB_r = HIP_R_32F;
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescSetAttribute(matmul,
HIPBLASLT_MATMUL_DESC_COMPUTE_INPUT_TYPE_A_EXT,
&computeTypeA,
sizeof(computeTypeA) / 2),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescSetAttribute(matmul,
HIPBLASLT_MATMUL_DESC_COMPUTE_INPUT_TYPE_A_EXT,
&computeTypeA,
sizeof(computeTypeA)),
HIPBLAS_STATUS_SUCCESS);
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescSetAttribute(matmul,
HIPBLASLT_MATMUL_DESC_COMPUTE_INPUT_TYPE_B_EXT,
&computeTypeB,
sizeof(computeTypeB) / 2),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescSetAttribute(matmul,
HIPBLASLT_MATMUL_DESC_COMPUTE_INPUT_TYPE_B_EXT,
&computeTypeB,
sizeof(computeTypeB)),
HIPBLAS_STATUS_SUCCESS);
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescGetAttribute(matmul,
HIPBLASLT_MATMUL_DESC_COMPUTE_INPUT_TYPE_A_EXT,
&computeTypeA_r,
sizeof(computeTypeA_r) / 2,
&sizeWritten),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescGetAttribute(matmul,
HIPBLASLT_MATMUL_DESC_COMPUTE_INPUT_TYPE_A_EXT,
&computeTypeA_r,
sizeof(computeTypeA_r),
&sizeWritten),
HIPBLAS_STATUS_SUCCESS);
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescGetAttribute(matmul,
HIPBLASLT_MATMUL_DESC_COMPUTE_INPUT_TYPE_B_EXT,
&computeTypeB_r,
sizeof(computeTypeB_r) / 2,
&sizeWritten),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescGetAttribute(matmul,
HIPBLASLT_MATMUL_DESC_COMPUTE_INPUT_TYPE_B_EXT,
&computeTypeB_r,
sizeof(computeTypeB_r),
&sizeWritten),
HIPBLAS_STATUS_SUCCESS);
ASSERT_TRUE(computeTypeA_r == computeTypeA);
ASSERT_TRUE(computeTypeB_r == computeTypeB);
// for default
void* default_ptr;
void* default_ptr_r;
CHECK_HIP_ERROR(hipMalloc(&default_ptr, sizeof(hipblasLtHalf)));
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescSetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_MAX, &default_ptr, sizeof(void*)),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulDescGetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_MAX, &default_ptr_r, sizeof(default_ptr_r), &sizeWritten),
HIPBLAS_STATUS_INVALID_VALUE);
CHECK_HIPBLASLT_ERROR(hipblasLtMatmulDescDestroy(matmul));
CHECK_HIP_ERROR(hipStreamDestroy(stream));
CHECK_HIP_ERROR(hipFree(d_scale_a));
CHECK_HIP_ERROR(hipFree(d_bias));
CHECK_HIP_ERROR(hipFree(d_scale_b));
CHECK_HIP_ERROR(hipFree(d_scale_c));
CHECK_HIP_ERROR(hipFree(d_scale_d));
CHECK_HIP_ERROR(hipFree(d_scale_e));
CHECK_HIP_ERROR(hipFree(d_aux_buffer));
CHECK_HIP_ERROR(hipFree(d_out_amax));
CHECK_HIP_ERROR(hipFree(default_ptr));
}
void testing_aux_matmul_pref_get_attr_bad_arg(const Arguments& arg)
{
hipblaslt_local_preference pref;
EXPECT_HIPBLAS_STATUS(pref.status(), HIPBLAS_STATUS_SUCCESS);
uint64_t data;
size_t sizeWritten;
// Test with null preference (should be INVALID_VALUE)
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulPreferenceGetAttribute(
nullptr, HIPBLASLT_MATMUL_PREF_MAX_WORKSPACE_BYTES, &data, sizeof(data), &sizeWritten),
HIPBLAS_STATUS_INVALID_VALUE);
// Test with sizeInBytes = 0 and sizeWritten = NULL (should be INVALID_VALUE)
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulPreferenceGetAttribute(
pref, HIPBLASLT_MATMUL_PREF_MAX_WORKSPACE_BYTES, &data, 0, nullptr),
HIPBLAS_STATUS_INVALID_VALUE);
// Test with non-zero sizeInBytes and buf = NULL (should be INVALID_VALUE)
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulPreferenceGetAttribute(pref,
HIPBLASLT_MATMUL_PREF_MAX_WORKSPACE_BYTES,
nullptr,
sizeof(uint64_t),
&sizeWritten),
HIPBLAS_STATUS_INVALID_VALUE);
// Test with correct size (should be SUCCESS)
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulPreferenceGetAttribute(
pref, HIPBLASLT_MATMUL_PREF_MAX_WORKSPACE_BYTES, &data, sizeof(uint64_t), &sizeWritten),
HIPBLAS_STATUS_SUCCESS);
}
void testing_aux_matmul_pref_get_attr(const Arguments& arg)
{
hipblaslt_local_preference pref;
EXPECT_HIPBLAS_STATUS(pref.status(), HIPBLAS_STATUS_SUCCESS);
uint64_t data_set = 1024;
uint64_t data_get = 0;
size_t sizeWritten;
// Test edge cases
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulPreferenceSetAttribute(
nullptr, HIPBLASLT_MATMUL_PREF_MAX_WORKSPACE_BYTES, &data_set, sizeof(data_set)),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulPreferenceSetAttribute(
pref, HIPBLASLT_MATMUL_PREF_MAX_WORKSPACE_BYTES, &data_set, 0),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulPreferenceGetAttribute(
pref, HIPBLASLT_MATMUL_PREF_MAX_WORKSPACE_BYTES, nullptr, 0, &sizeWritten),
HIPBLAS_STATUS_INVALID_VALUE);
// Set the attribute
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulPreferenceSetAttribute(
pref, HIPBLASLT_MATMUL_PREF_MAX_WORKSPACE_BYTES, &data_set, sizeof(data_set)),
HIPBLAS_STATUS_SUCCESS);
// Get the attribute
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulPreferenceGetAttribute(pref,
HIPBLASLT_MATMUL_PREF_MAX_WORKSPACE_BYTES,
&data_get,
sizeof(data_get),
&sizeWritten),
HIPBLAS_STATUS_SUCCESS);
// Verify that the get value matches the set value
ASSERT_TRUE(data_get == data_set);
ASSERT_TRUE(sizeWritten == sizeof(data_get));
// Test getting other attributes (assuming they have default values)
int32_t search_mode = 0;
int32_t search_mode_r = 1;
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulPreferenceSetAttribute(
pref, HIPBLASLT_MATMUL_PREF_SEARCH_MODE, &search_mode, sizeof(search_mode)),
HIPBLAS_STATUS_SUCCESS);
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulPreferenceGetAttribute(pref,
HIPBLASLT_MATMUL_PREF_SEARCH_MODE,
&search_mode_r,
sizeof(search_mode_r),
&sizeWritten),
HIPBLAS_STATUS_SUCCESS);
ASSERT_TRUE(data_get == data_set);
// Test default value
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulPreferenceSetAttribute(
pref, HIPBLASLT_MATMUL_PREF_MAX, &search_mode, sizeof(search_mode)),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulPreferenceGetAttribute(
pref, HIPBLASLT_MATMUL_PREF_MAX, &search_mode_r, sizeof(search_mode_r), &sizeWritten),
HIPBLAS_STATUS_INVALID_VALUE);
// You might want to add more attribute tests here
}
void testing_aux_matmul_sm_count_target(const Arguments& arg)
{
size_t sizeWritten = 0;
hipblasLtMatmulDesc_t matmul = nullptr;
CHECK_HIPBLASLT_ERROR(hipblasLtMatmulDescCreate(&matmul, arg.compute_type, arg.scale_type));
// Default value must be 0 ("use all CUs the device exposes").
int32_t value_r = -1;
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescGetAttribute(matmul,
HIPBLASLT_MATMUL_DESC_SM_COUNT_TARGET,
&value_r,
sizeof(value_r),
&sizeWritten),
HIPBLAS_STATUS_SUCCESS);
ASSERT_TRUE(value_r == 0);
ASSERT_TRUE(sizeWritten == sizeof(int32_t));
// Round-trip set/get with a valid value.
int32_t value_set = 80;
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescSetAttribute(matmul,
HIPBLASLT_MATMUL_DESC_SM_COUNT_TARGET,
&value_set,
sizeof(value_set)),
HIPBLAS_STATUS_SUCCESS);
value_r = 0;
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescGetAttribute(matmul,
HIPBLASLT_MATMUL_DESC_SM_COUNT_TARGET,
&value_r,
sizeof(value_r),
&sizeWritten),
HIPBLAS_STATUS_SUCCESS);
ASSERT_TRUE(value_r == value_set);
// Setting back to 0 (the "use all CUs" sentinel) must be accepted.
int32_t zero = 0;
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescSetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_SM_COUNT_TARGET, &zero, sizeof(zero)),
HIPBLAS_STATUS_SUCCESS);
// Negative values must be rejected and must leave the stored value unchanged.
int32_t negative = -5;
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescSetAttribute(matmul,
HIPBLASLT_MATMUL_DESC_SM_COUNT_TARGET,
&negative,
sizeof(negative)),
HIPBLAS_STATUS_INVALID_VALUE);
value_r = -1;
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescGetAttribute(matmul,
HIPBLASLT_MATMUL_DESC_SM_COUNT_TARGET,
&value_r,
sizeof(value_r),
&sizeWritten),
HIPBLAS_STATUS_SUCCESS);
ASSERT_TRUE(value_r == 0); // unchanged (last successful set was 0)
// Undersized buffer is INVALID_VALUE for both set and get.
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescSetAttribute(matmul,
HIPBLASLT_MATMUL_DESC_SM_COUNT_TARGET,
&value_set,
sizeof(int32_t) / 2),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescGetAttribute(matmul,
HIPBLASLT_MATMUL_DESC_SM_COUNT_TARGET,
&value_r,
sizeof(int32_t) / 2,
&sizeWritten),
HIPBLAS_STATUS_INVALID_VALUE);
CHECK_HIPBLASLT_ERROR(hipblasLtMatmulDescDestroy(matmul));
}
void testing_aux_matmul_streamk_tile_scheduling_ext(const Arguments& arg)
{
size_t sizeWritten = 0;
hipblasLtMatmulDesc_t matmul = nullptr;
CHECK_HIPBLASLT_ERROR(hipblasLtMatmulDescCreate(&matmul, arg.compute_type, arg.scale_type));
// Default is OFF (0); set sm_count_target > 0 to engage the heuristic.
int32_t value_r = -1;
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescGetAttribute(matmul,
HIPBLASLT_MATMUL_DESC_STREAMK_TILE_SCHEDULING_EXT,
&value_r,
sizeof(value_r),
&sizeWritten),
HIPBLAS_STATUS_SUCCESS);
ASSERT_TRUE(value_r == 0);
// ON then OFF round-trip.
int32_t enable = 1;
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescSetAttribute(matmul,
HIPBLASLT_MATMUL_DESC_STREAMK_TILE_SCHEDULING_EXT,
&enable,
sizeof(enable)),
HIPBLAS_STATUS_SUCCESS);
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescGetAttribute(matmul,
HIPBLASLT_MATMUL_DESC_STREAMK_TILE_SCHEDULING_EXT,
&value_r,
sizeof(value_r),
&sizeWritten),
HIPBLAS_STATUS_SUCCESS);
ASSERT_TRUE(value_r == 1);
// AUTO (2) is also accepted and round-trips.
int32_t auto_mode = 2;
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescSetAttribute(matmul,
HIPBLASLT_MATMUL_DESC_STREAMK_TILE_SCHEDULING_EXT,
&auto_mode,
sizeof(auto_mode)),
HIPBLAS_STATUS_SUCCESS);
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescGetAttribute(matmul,
HIPBLASLT_MATMUL_DESC_STREAMK_TILE_SCHEDULING_EXT,
&value_r,
sizeof(value_r),
&sizeWritten),
HIPBLAS_STATUS_SUCCESS);
ASSERT_TRUE(value_r == 2);
// Values outside {0,1,2} are rejected with INVALID_VALUE (previously
// any nonzero value was silently clamped to 1).
int32_t three = 3;
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescSetAttribute(matmul,
HIPBLASLT_MATMUL_DESC_STREAMK_TILE_SCHEDULING_EXT,
&three,
sizeof(three)),
HIPBLAS_STATUS_INVALID_VALUE);
int32_t negative = -1;
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescSetAttribute(matmul,
HIPBLASLT_MATMUL_DESC_STREAMK_TILE_SCHEDULING_EXT,
&negative,
sizeof(negative)),
HIPBLAS_STATUS_INVALID_VALUE);
int32_t disable = 0;
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescSetAttribute(matmul,
HIPBLASLT_MATMUL_DESC_STREAMK_TILE_SCHEDULING_EXT,
&disable,
sizeof(disable)),
HIPBLAS_STATUS_SUCCESS);
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulDescGetAttribute(matmul,
HIPBLASLT_MATMUL_DESC_STREAMK_TILE_SCHEDULING_EXT,
&value_r,
sizeof(value_r),
&sizeWritten),
HIPBLAS_STATUS_SUCCESS);
ASSERT_TRUE(value_r == 0);
CHECK_HIPBLASLT_ERROR(hipblasLtMatmulDescDestroy(matmul));
}
void testing_aux_matmul_pref_sm_count_target(const Arguments& arg)
{
hipblaslt_local_preference pref;
EXPECT_HIPBLAS_STATUS(pref.status(), HIPBLAS_STATUS_SUCCESS);
int32_t value_r = -1;
size_t sizeWritten = 0;
// Default value must be 0.
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulPreferenceGetAttribute(pref,
HIPBLASLT_MATMUL_PREF_SM_COUNT_TARGET,
&value_r,
sizeof(value_r),
&sizeWritten),
HIPBLAS_STATUS_SUCCESS);
ASSERT_TRUE(value_r == 0);
ASSERT_TRUE(sizeWritten == sizeof(int32_t));
// Round-trip set/get.
int32_t value_set = 132;
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulPreferenceSetAttribute(pref,
HIPBLASLT_MATMUL_PREF_SM_COUNT_TARGET,
&value_set,
sizeof(value_set)),
HIPBLAS_STATUS_SUCCESS);
value_r = 0;
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulPreferenceGetAttribute(pref,
HIPBLASLT_MATMUL_PREF_SM_COUNT_TARGET,
&value_r,
sizeof(value_r),
&sizeWritten),
HIPBLAS_STATUS_SUCCESS);
ASSERT_TRUE(value_r == value_set);
// Negative values must be rejected.
int32_t negative = -42;
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulPreferenceSetAttribute(pref,
HIPBLASLT_MATMUL_PREF_SM_COUNT_TARGET,
&negative,
sizeof(negative)),
HIPBLAS_STATUS_INVALID_VALUE);
// Undersized buffer is INVALID_VALUE for both setter and getter.
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulPreferenceSetAttribute(pref,
HIPBLASLT_MATMUL_PREF_SM_COUNT_TARGET,
&value_set,
sizeof(int32_t) / 2),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulPreferenceGetAttribute(pref,
HIPBLASLT_MATMUL_PREF_SM_COUNT_TARGET,
&value_r,
sizeof(int32_t) / 2,
&sizeWritten),
HIPBLAS_STATUS_INVALID_VALUE);
}
void testing_aux_matmul_alg_init_bad_arg(const Arguments& arg) {}
void testing_aux_matmul_alg_init(const Arguments& arg) {}
void testing_aux_get_sol_with_null_biasaddr(const Arguments& arg)
{
using InTypeA = hipblasLtHalf;
using InTypeB = hipblasLtHalf;
using OutType = hipblasLtHalf;
using AlphaType = hipblasLtFloat;
using BetaType = hipblasLtFloat;
hipStream_t stream;
hipblasLtHandle_t handle;
hipblasOperation_t trans_a = HIPBLAS_OP_N;
hipblasOperation_t trans_b = HIPBLAS_OP_T;
int64_t m = arg.M[0];
int64_t n = arg.N[0];
int64_t k = arg.K[0];
int64_t batch_count = 1;
float alpha = arg.alpha;
float beta = arg.beta;
void* d_a;
void* d_b;
void* d_c;
void* d_d;
void* a;
void* b;
void* c;
void* d;
CHECK_HIP_ERROR(hipStreamCreate(&stream));
CHECK_HIPBLASLT_ERROR(hipblasLtCreate(&handle));
CHECK_HIP_ERROR(hipMalloc(&d_a, m * k * batch_count * sizeof(InTypeA)));
CHECK_HIP_ERROR(hipMalloc(&d_b, n * k * batch_count * sizeof(InTypeB)));
CHECK_HIP_ERROR(hipMalloc(&d_c, m * n * batch_count * sizeof(OutType)));
CHECK_HIP_ERROR(hipMalloc(&d_d, m * n * batch_count * sizeof(OutType)));
CHECK_HIP_ERROR(hipHostMalloc(&a, m * k * batch_count * sizeof(InTypeA)));
CHECK_HIP_ERROR(hipHostMalloc(&b, n * k * batch_count * sizeof(InTypeB)));
CHECK_HIP_ERROR(hipHostMalloc(&c, m * n * batch_count * sizeof(OutType)));
CHECK_HIP_ERROR(hipHostMalloc(&d, m * n * batch_count * sizeof(OutType)));
CHECK_HIP_ERROR(hipMemcpyAsync(
d_a, a, m * k * batch_count * sizeof(InTypeA), hipMemcpyHostToDevice, stream));
CHECK_HIP_ERROR(hipMemcpyAsync(
d_b, b, n * k * batch_count * sizeof(InTypeB), hipMemcpyHostToDevice, stream));
CHECK_HIP_ERROR(hipMemcpyAsync(
d_c, c, m * n * batch_count * sizeof(OutType), hipMemcpyHostToDevice, stream));
hipblasLtMatrixLayout_t matA, matB, matC, matD;
CHECK_HIPBLASLT_ERROR(hipblasLtMatrixLayoutCreate(&matA, arg.a_type, m, k, m));
CHECK_HIPBLASLT_ERROR(hipblasLtMatrixLayoutCreate(&matB, arg.a_type, k, n, k));
CHECK_HIPBLASLT_ERROR(hipblasLtMatrixLayoutCreate(&matC, arg.a_type, m, n, m));
CHECK_HIPBLASLT_ERROR(hipblasLtMatrixLayoutCreate(&matD, arg.a_type, m, n, m));
hipblasLtMatmulDesc_t matmul;
hipblasLtEpilogue_t epilogue = HIPBLASLT_EPILOGUE_BIAS;
CHECK_HIPBLASLT_ERROR(hipblasLtMatmulDescCreate(&matmul, arg.compute_type, arg.scale_type));
CHECK_HIPBLASLT_ERROR(hipblasLtMatmulDescSetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_TRANSA, &trans_a, sizeof(int32_t)));
CHECK_HIPBLASLT_ERROR(hipblasLtMatmulDescSetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_TRANSB, &trans_b, sizeof(int32_t)));
CHECK_HIPBLASLT_ERROR(hipblasLtMatmulDescSetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_EPILOGUE, &epilogue, sizeof(epilogue)));
hipblasLtMatmulPreference_t pref;
CHECK_HIPBLASLT_ERROR(hipblasLtMatmulPreferenceCreate(&pref));
const int request_solutions = 1;
hipblasLtMatmulHeuristicResult_t heuristicResult[request_solutions];
int returnedAlgoCount = 0;
CHECK_HIPBLASLT_ERROR(hipblasLtMatmulAlgoGetHeuristic(handle,
matmul,
matA,
matB,
matC,
matD,
pref,
request_solutions,
heuristicResult,
&returnedAlgoCount));
CHECK_SOLUTION_FOUND(returnedAlgoCount);
CHECK_HIP_ERROR(hipFree(a));
CHECK_HIP_ERROR(hipFree(b));
CHECK_HIP_ERROR(hipFree(c));
CHECK_HIP_ERROR(hipFree(d));
CHECK_HIP_ERROR(hipFree(d_a));
CHECK_HIP_ERROR(hipFree(d_b));
CHECK_HIP_ERROR(hipFree(d_c));
CHECK_HIP_ERROR(hipFree(d_d));
CHECK_HIPBLASLT_ERROR(hipblasLtMatmulDescDestroy(matmul));
CHECK_HIPBLASLT_ERROR(hipblasLtMatrixLayoutDestroy(matA));
CHECK_HIPBLASLT_ERROR(hipblasLtMatrixLayoutDestroy(matB));
CHECK_HIPBLASLT_ERROR(hipblasLtMatrixLayoutDestroy(matC));
CHECK_HIPBLASLT_ERROR(hipblasLtMatrixLayoutDestroy(matD));
CHECK_HIPBLASLT_ERROR(hipblasLtMatmulPreferenceDestroy(pref));
CHECK_HIPBLASLT_ERROR(hipblasLtDestroy(handle));
CHECK_HIP_ERROR(hipStreamDestroy(stream));
}
// hipBLASLt API: For testing case of (alpha=0 && (A=NULL || B=NULL))
void testing_aux_get_sol_with_zero_alpha_null_a_b(const Arguments& arg)
{
using InTypeA = hipblasLtHalf;
using InTypeB = hipblasLtHalf;
using OutType = hipblasLtHalf;
using AlphaType = hipblasLtFloat;
using BetaType = hipblasLtFloat;
hipStream_t stream;
hipblasLtHandle_t handle;
hipblasOperation_t trans_a = HIPBLAS_OP_N;
hipblasOperation_t trans_b = HIPBLAS_OP_T;
int64_t m = arg.M[0];
int64_t n = arg.N[0];
int64_t k = arg.K[0];
int64_t batch_count = 1;
// Setting alpha = 0.
float alpha = 0;
float beta = arg.beta;
// Setting d_a, d_b as nullptr.
void* d_a = NULL;
void* d_b = NULL;
void* d_c;
void* d_d;
CHECK_HIP_ERROR(hipStreamCreate(&stream));
CHECK_HIPBLASLT_ERROR(hipblasLtCreate(&handle));
CHECK_HIP_ERROR(hipMalloc(&d_c, m * n * batch_count * sizeof(OutType)));
CHECK_HIP_ERROR(hipMalloc(&d_d, m * n * batch_count * sizeof(OutType)));
hipblasLtMatrixLayout_t matA, matB, matC, matD;
CHECK_HIPBLASLT_ERROR(hipblasLtMatrixLayoutCreate(&matA, arg.a_type, m, k, m));
CHECK_HIPBLASLT_ERROR(hipblasLtMatrixLayoutCreate(&matB, arg.a_type, k, n, k));
CHECK_HIPBLASLT_ERROR(hipblasLtMatrixLayoutCreate(&matC, arg.a_type, m, n, m));
CHECK_HIPBLASLT_ERROR(hipblasLtMatrixLayoutCreate(&matD, arg.a_type, m, n, m));
hipblasLtMatmulDesc_t matmul;
CHECK_HIPBLASLT_ERROR(hipblasLtMatmulDescCreate(&matmul, arg.compute_type, arg.scale_type));
CHECK_HIPBLASLT_ERROR(hipblasLtMatmulDescSetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_TRANSA, &trans_a, sizeof(int32_t)));
CHECK_HIPBLASLT_ERROR(hipblasLtMatmulDescSetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_TRANSB, &trans_b, sizeof(int32_t)));
hipblasLtEpilogue_t epilogue = HIPBLASLT_EPILOGUE_DEFAULT;
CHECK_HIPBLASLT_ERROR(hipblasLtMatmulDescSetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_EPILOGUE, &epilogue, sizeof(epilogue)));
// Set User Preference attributes
hipblasLtMatmulPreference_t pref;
CHECK_HIPBLASLT_ERROR(hipblasLtMatmulPreferenceCreate(&pref));
const int request_solutions = 1;
hipblasLtMatmulHeuristicResult_t heuristicResult[request_solutions];
int returnedAlgoCount = 0;
CHECK_HIPBLASLT_ERROR(hipblasLtMatmulAlgoGetHeuristic(handle,
matmul,
matA,
matB,
matC,
matD,
pref,
request_solutions,
heuristicResult,
&returnedAlgoCount));
CHECK_SOLUTION_FOUND(returnedAlgoCount);
// Validation for solution running.
CHECK_HIPBLASLT_ERROR(hipblasLtMatmul(handle,
matmul,
&alpha,
d_a,
matA,
d_b,
matB,
&beta,
d_c,
matC,
d_d,
matD,
&heuristicResult[0].algo,
nullptr,
0,
stream));
CHECK_HIP_ERROR(hipFree(d_c));
CHECK_HIP_ERROR(hipFree(d_d));
CHECK_HIPBLASLT_ERROR(hipblasLtMatmulDescDestroy(matmul));
CHECK_HIPBLASLT_ERROR(hipblasLtMatrixLayoutDestroy(matA));
CHECK_HIPBLASLT_ERROR(hipblasLtMatrixLayoutDestroy(matB));
CHECK_HIPBLASLT_ERROR(hipblasLtMatrixLayoutDestroy(matC));
CHECK_HIPBLASLT_ERROR(hipblasLtMatrixLayoutDestroy(matD));
CHECK_HIPBLASLT_ERROR(hipblasLtMatmulPreferenceDestroy(pref));
CHECK_HIPBLASLT_ERROR(hipblasLtDestroy(handle));
CHECK_HIP_ERROR(hipStreamDestroy(stream));
}
// hipBLASLtExt API: For testing case of (alpha=0 && (A=NULL || B=NULL))
void testing_aux_get_sol_with_zero_alpha_null_a_b_ext(const Arguments& arg)
{
using InTypeA = hipblasLtHalf;
using InTypeB = hipblasLtHalf;
using OutType = hipblasLtHalf;
using AlphaType = hipblasLtFloat;
using BetaType = hipblasLtFloat;
hipStream_t stream;
hipblasLtHandle_t handle;
hipblasOperation_t trans_a = HIPBLAS_OP_N;
hipblasOperation_t trans_b = HIPBLAS_OP_T;
int64_t m = arg.M[0];
int64_t n = arg.N[0];
int64_t k = arg.K[0];
int64_t batch_count = 1;
// Setting alpha = 0.
float alpha = 0;
float beta = arg.beta;
// Setting d_a, d_b as nullptr.
void* d_a = NULL;
void* d_b = NULL;
void* d_c;
void* d_d;
CHECK_HIP_ERROR(hipStreamCreate(&stream));
CHECK_HIPBLASLT_ERROR(hipblasLtCreate(&handle));
CHECK_HIP_ERROR(hipMalloc(&d_c, m * n * batch_count * sizeof(OutType)));
CHECK_HIP_ERROR(hipMalloc(&d_d, m * n * batch_count * sizeof(OutType)));
hipblaslt_ext::GemmPreference gemmPref;
hipblaslt_ext::Gemm gemm(
handle, trans_a, trans_b, arg.a_type, arg.a_type, arg.a_type, arg.a_type, arg.compute_type);
hipblaslt_ext::GemmEpilogue
epilogue; // No action needed, default is HIPBLASLT_EPILOGUE_DEFAULT. (Gemm only)
hipblaslt_ext::GemmInputs inputs;
inputs.setA(d_a);
inputs.setB(d_b);
inputs.setC(d_c);
inputs.setD(d_d);
inputs.setAlpha(&alpha);
inputs.setBeta(&beta);
gemm.setProblem(m, n, k, batch_count, epilogue, inputs);
const int request_solutions = 1;
std::vector<hipblasLtMatmulHeuristicResult_t> heuristicResult;
CHECK_HIPBLASLT_ERROR(gemm.algoGetHeuristic(request_solutions, gemmPref, heuristicResult));
CHECK_SOLUTION_FOUND(heuristicResult.size());
// Make sure to initialize every time when algo changes
CHECK_HIPBLASLT_ERROR(gemm.initialize(heuristicResult[0].algo, nullptr));
// Validation for solution running.
CHECK_HIPBLASLT_ERROR(gemm.run(stream));
CHECK_HIP_ERROR(hipFree(d_c));
CHECK_HIP_ERROR(hipFree(d_d));
CHECK_HIPBLASLT_ERROR(hipblasLtDestroy(handle));
CHECK_HIP_ERROR(hipStreamDestroy(stream));
}
void testing_aux_matmul_alg_get_attr_bad_arg(const Arguments& arg) {}
void testing_aux_matmul_alg_null_matmul(const Arguments& arg)
{
using InTypeA = hipblasLtHalf;
using InTypeB = hipblasLtHalf;
using OutType = hipblasLtHalf;
using AlphaType = hipblasLtFloat;
using BetaType = hipblasLtFloat;
hipStream_t stream;
hipblasLtHandle_t handle;
hipblasOperation_t trans_a = HIPBLAS_OP_N;
hipblasOperation_t trans_b = HIPBLAS_OP_T;
int64_t m = arg.M[0];
int64_t n = arg.N[0];
int64_t k = arg.K[0];
int64_t batch_count = 1;
float alpha = arg.alpha;
float beta = arg.beta;
void* d_a;
void* d_b;
void* d_c;
void* d_d;
void* a;
void* b;
void* c;
void* d;
CHECK_HIP_ERROR(hipStreamCreate(&stream));
CHECK_HIPBLASLT_ERROR(hipblasLtCreate(&handle));
CHECK_HIP_ERROR(hipMalloc(&d_a, m * k * batch_count * sizeof(InTypeA)));
CHECK_HIP_ERROR(hipMalloc(&d_b, n * k * batch_count * sizeof(InTypeB)));
CHECK_HIP_ERROR(hipMalloc(&d_c, m * n * batch_count * sizeof(OutType)));
CHECK_HIP_ERROR(hipMalloc(&d_d, m * n * batch_count * sizeof(OutType)));
CHECK_HIP_ERROR(hipHostMalloc(&a, m * k * batch_count * sizeof(InTypeA)));
CHECK_HIP_ERROR(hipHostMalloc(&b, n * k * batch_count * sizeof(InTypeB)));
CHECK_HIP_ERROR(hipHostMalloc(&c, m * n * batch_count * sizeof(OutType)));
CHECK_HIP_ERROR(hipHostMalloc(&d, m * n * batch_count * sizeof(OutType)));
CHECK_HIP_ERROR(hipMemcpyAsync(
d_a, a, m * k * batch_count * sizeof(InTypeA), hipMemcpyHostToDevice, stream));
CHECK_HIP_ERROR(hipMemcpyAsync(
d_b, b, n * k * batch_count * sizeof(InTypeB), hipMemcpyHostToDevice, stream));
CHECK_HIP_ERROR(hipMemcpyAsync(
d_c, c, m * n * batch_count * sizeof(OutType), hipMemcpyHostToDevice, stream));
hipblasLtMatrixLayout_t matA, matB, matC, matD;
CHECK_HIPBLASLT_ERROR(hipblasLtMatrixLayoutCreate(&matA, arg.a_type, m, k, m));
CHECK_HIPBLASLT_ERROR(hipblasLtMatrixLayoutCreate(&matB, arg.a_type, k, n, k));
CHECK_HIPBLASLT_ERROR(hipblasLtMatrixLayoutCreate(&matC, arg.a_type, m, n, m));
CHECK_HIPBLASLT_ERROR(hipblasLtMatrixLayoutCreate(&matD, arg.a_type, m, n, m));
hipblasLtMatmulDesc_t matmul;
CHECK_HIPBLASLT_ERROR(hipblasLtMatmulDescCreate(&matmul, arg.compute_type, arg.scale_type));
CHECK_HIPBLASLT_ERROR(hipblasLtMatmulDescSetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_TRANSA, &trans_a, sizeof(int32_t)));
CHECK_HIPBLASLT_ERROR(hipblasLtMatmulDescSetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_TRANSB, &trans_b, sizeof(int32_t)));
CHECK_HIPBLASLT_ERROR(hipblasLtMatmul(handle,
matmul,
&alpha,
d_a,
matA,
d_b,
matB,
&beta,
d_c,
matC,
d_d,
matD,
nullptr,
nullptr,
0,
0));
CHECK_HIP_ERROR(hipFree(a));
CHECK_HIP_ERROR(hipFree(b));
CHECK_HIP_ERROR(hipFree(c));
CHECK_HIP_ERROR(hipFree(d));
CHECK_HIP_ERROR(hipFree(d_a));
CHECK_HIP_ERROR(hipFree(d_b));
CHECK_HIP_ERROR(hipFree(d_c));
CHECK_HIP_ERROR(hipFree(d_d));
CHECK_HIPBLASLT_ERROR(hipblasLtMatmulDescDestroy(matmul));
CHECK_HIPBLASLT_ERROR(hipblasLtMatrixLayoutDestroy(matA));
CHECK_HIPBLASLT_ERROR(hipblasLtMatrixLayoutDestroy(matB));
CHECK_HIPBLASLT_ERROR(hipblasLtMatrixLayoutDestroy(matC));
CHECK_HIPBLASLT_ERROR(hipblasLtMatrixLayoutDestroy(matD));
CHECK_HIPBLASLT_ERROR(hipblasLtDestroy(handle));
CHECK_HIP_ERROR(hipStreamDestroy(stream));
}
void testing_aux_matmul_bad_ws_size(const Arguments& arg)
{
using InTypeA = hipblasLtHalf;
using InTypeB = hipblasLtHalf;
using OutType = hipblasLtHalf;
using AlphaType = hipblasLtFloat;
using BetaType = hipblasLtFloat;
hipStream_t stream;
hipblasLtHandle_t handle;
hipblasOperation_t trans_a = HIPBLAS_OP_N;
hipblasOperation_t trans_b = HIPBLAS_OP_N;
int64_t m = 2048;
int64_t n = 2048;
int64_t k = 2048;
int64_t batch_count = 1;
float alpha = arg.alpha;
float beta = arg.beta;
void* d_a;
void* d_b;
void* d_c;
void* d_d;
void* a;
void* b;
void* c;
void* d;
CHECK_HIP_ERROR(hipStreamCreate(&stream));
CHECK_HIPBLASLT_ERROR(hipblasLtCreate(&handle));
CHECK_HIP_ERROR(hipMalloc(&d_a, m * k * batch_count * sizeof(InTypeA)));
CHECK_HIP_ERROR(hipMalloc(&d_b, n * k * batch_count * sizeof(InTypeB)));
CHECK_HIP_ERROR(hipMalloc(&d_c, m * n * batch_count * sizeof(OutType)));
CHECK_HIP_ERROR(hipMalloc(&d_d, m * n * batch_count * sizeof(OutType)));
CHECK_HIP_ERROR(hipHostMalloc(&a, m * k * batch_count * sizeof(InTypeA)));
CHECK_HIP_ERROR(hipHostMalloc(&b, n * k * batch_count * sizeof(InTypeB)));
CHECK_HIP_ERROR(hipHostMalloc(&c, m * n * batch_count * sizeof(OutType)));
CHECK_HIP_ERROR(hipHostMalloc(&d, m * n * batch_count * sizeof(OutType)));
CHECK_HIP_ERROR(hipMemcpyAsync(
d_a, a, m * k * batch_count * sizeof(InTypeA), hipMemcpyHostToDevice, stream));
CHECK_HIP_ERROR(hipMemcpyAsync(
d_b, b, n * k * batch_count * sizeof(InTypeB), hipMemcpyHostToDevice, stream));
CHECK_HIP_ERROR(hipMemcpyAsync(
d_c, c, m * n * batch_count * sizeof(OutType), hipMemcpyHostToDevice, stream));
hipblasLtMatrixLayout_t matA, matB, matC, matD;
CHECK_HIPBLASLT_ERROR(hipblasLtMatrixLayoutCreate(&matA, arg.a_type, m, k, m));
CHECK_HIPBLASLT_ERROR(hipblasLtMatrixLayoutCreate(&matB, arg.a_type, k, n, k));
CHECK_HIPBLASLT_ERROR(hipblasLtMatrixLayoutCreate(&matC, arg.a_type, m, n, m));
CHECK_HIPBLASLT_ERROR(hipblasLtMatrixLayoutCreate(&matD, arg.a_type, m, n, m));
hipblasLtMatmulDesc_t matmul;
CHECK_HIPBLASLT_ERROR(hipblasLtMatmulDescCreate(&matmul, arg.compute_type, arg.scale_type));
CHECK_HIPBLASLT_ERROR(hipblasLtMatmulDescSetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_TRANSA, &trans_a, sizeof(int32_t)));
CHECK_HIPBLASLT_ERROR(hipblasLtMatmulDescSetAttribute(
matmul, HIPBLASLT_MATMUL_DESC_TRANSB, &trans_b, sizeof(int32_t)));
hipblasLtMatmulPreference_t pref;
CHECK_HIPBLASLT_ERROR(hipblasLtMatmulPreferenceCreate(&pref));
size_t max_workspace_size = 128 * 1024 * 1024;
EXPECT_HIPBLAS_STATUS(
hipblasLtMatmulPreferenceSetAttribute(pref,
HIPBLASLT_MATMUL_PREF_MAX_WORKSPACE_BYTES,
&max_workspace_size,
sizeof(max_workspace_size)),
HIPBLAS_STATUS_SUCCESS);
const int request_solutions = 1000;
hipblasLtMatmulHeuristicResult_t heuristicResult[request_solutions];
int returnedAlgoCount = 0;
CHECK_HIPBLASLT_ERROR(hipblasLtMatmulAlgoGetHeuristic(handle,
matmul,
matA,
matB,
matC,
matD,
pref,
request_solutions,
heuristicResult,
&returnedAlgoCount));
void* d_ws;
CHECK_HIP_ERROR(hipMalloc(&d_ws, 1));
for(int i = 0; i < returnedAlgoCount; i++)
{
if(heuristicResult[i].workspaceSize > 0)
{
//The normal behavior with insufficient ws size would be:
//1. run normally without crash and return HIPBLAS_STATUS_SUCCESS
//2. return HIPBLAS_STATUS_INVALID_VALUE
auto status = hipblasLtMatmul(handle,
matmul,
&alpha,
d_a,
matA,
d_b,
matB,
&beta,
d_c,
matC,
d_d,
matD,
&heuristicResult[i].algo,
d_ws,
1,
stream);
CHECK_SUCCESS((status == HIPBLAS_STATUS_SUCCESS)
|| (status == HIPBLAS_STATUS_INVALID_VALUE));
}
}
CHECK_HIP_ERROR(hipFree(d_ws));
CHECK_HIP_ERROR(hipFree(a));
CHECK_HIP_ERROR(hipFree(b));
CHECK_HIP_ERROR(hipFree(c));
CHECK_HIP_ERROR(hipFree(d));
CHECK_HIP_ERROR(hipFree(d_a));
CHECK_HIP_ERROR(hipFree(d_b));
CHECK_HIP_ERROR(hipFree(d_c));
CHECK_HIP_ERROR(hipFree(d_d));
CHECK_HIPBLASLT_ERROR(hipblasLtMatmulPreferenceDestroy(pref));
CHECK_HIPBLASLT_ERROR(hipblasLtMatmulDescDestroy(matmul));
CHECK_HIPBLASLT_ERROR(hipblasLtMatrixLayoutDestroy(matA));
CHECK_HIPBLASLT_ERROR(hipblasLtMatrixLayoutDestroy(matB));
CHECK_HIPBLASLT_ERROR(hipblasLtMatrixLayoutDestroy(matC));
CHECK_HIPBLASLT_ERROR(hipblasLtMatrixLayoutDestroy(matD));
CHECK_HIPBLASLT_ERROR(hipblasLtDestroy(handle));
CHECK_HIP_ERROR(hipStreamDestroy(stream));
}
void testing_aux_matmul_pref_init_bad_arg(const Arguments& arg)
{
hipblasLtMatmulPreference_t pref;
size_t workspace_size = 0;
EXPECT_HIPBLAS_STATUS(hipblasLtMatmulPreferenceCreate(nullptr), HIPBLAS_STATUS_INVALID_VALUE);
}
void testing_aux_matmul_pref_init(const Arguments& arg)
{
hipblaslt_local_preference pref;
EXPECT_HIPBLAS_STATUS(pref.status(), HIPBLAS_STATUS_SUCCESS);
}
void testing_aux_mat_copy(const Arguments& arg)
{
hipblasLtMatmulDesc_t matmul_src;
CHECK_HIPBLASLT_ERROR(hipblasLtMatmulDescCreate(&matmul_src, arg.compute_type, arg.scale_type));
hipblasLtMatmulDesc_t matmul_dest;
CHECK_HIPBLASLT_ERROR(hipblasLtMatmulDescCreate(&matmul_dest, HIPBLAS_COMPUTE_32F, HIP_R_32F));
EXPECT_HIPBLAS_STATUS(hipblaslt_ext::copyMatmul(nullptr, matmul_dest),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(hipblaslt_ext::copyMatmul(matmul_src, nullptr),
HIPBLAS_STATUS_INVALID_VALUE);
EXPECT_HIPBLAS_STATUS(hipblaslt_ext::copyMatmul(matmul_src, matmul_dest),
HIPBLAS_STATUS_SUCCESS);
CHECK_HIPBLASLT_ERROR(hipblasLtMatmulDescDestroy(matmul_src));
CHECK_HIPBLASLT_ERROR(hipblasLtMatmulDescDestroy(matmul_dest));
}
#ifdef CODE_COVERAGE
inline void testing_aux_auxiliary_func(const Arguments& arg)
{
// Test gpu_arch_match
int deviceId;
hipDeviceProp_t deviceProperties;
static_cast<void>(hipGetDevice(&deviceId));
static_cast<void>(hipGetDeviceProperties(&deviceProperties, deviceId));
ASSERT_TRUE(gpu_arch_match(deviceProperties.gcnArchName, ""));
ASSERT_TRUE(gpu_arch_match(deviceProperties.gcnArchName, "\\d"));
// Test hipblas_status_to_string
ASSERT_TRUE(hipblas_status_to_string(HIPBLAS_STATUS_SUCCESS) == "HIPBLAS_STATUS_SUCCESS");
ASSERT_TRUE(hipblas_status_to_string(HIPBLAS_STATUS_NOT_INITIALIZED)
== "HIPBLAS_STATUS_NOT_INITIALIZED");
ASSERT_TRUE(hipblas_status_to_string(HIPBLAS_STATUS_ALLOC_FAILED)
== "HIPBLAS_STATUS_ALLOC_FAILED");
ASSERT_TRUE(hipblas_status_to_string(HIPBLAS_STATUS_INVALID_VALUE)
== "HIPBLAS_STATUS_INVALID_VALUE");
ASSERT_TRUE(hipblas_status_to_string(HIPBLAS_STATUS_MAPPING_ERROR)
== "HIPBLAS_STATUS_MAPPING_ERROR");
ASSERT_TRUE(hipblas_status_to_string(HIPBLAS_STATUS_EXECUTION_FAILED)
== "HIPBLAS_STATUS_EXECUTION_FAILED");
ASSERT_TRUE(hipblas_status_to_string(HIPBLAS_STATUS_INTERNAL_ERROR)
== "HIPBLAS_STATUS_INTERNAL_ERROR");
ASSERT_TRUE(hipblas_status_to_string(HIPBLAS_STATUS_NOT_SUPPORTED)
== "HIPBLAS_STATUS_NOT_SUPPORTED");
ASSERT_TRUE(hipblas_status_to_string(HIPBLAS_STATUS_ARCH_MISMATCH)
== "HIPBLAS_STATUS_ARCH_MISMATCH");
ASSERT_TRUE(hipblas_status_to_string(HIPBLAS_STATUS_INVALID_ENUM)
== "HIPBLAS_STATUS_INVALID_ENUM");
ASSERT_TRUE(hipblas_status_to_string(HIPBLAS_STATUS_UNKNOWN) == "HIPBLAS_STATUS_UNKNOWN");
ASSERT_TRUE(hipblas_status_to_string(static_cast<hipblasStatus_t>(12))
== "<undefined hipblasStatus_t value>");
// Test hipblas_operation_to_string
ASSERT_TRUE(hipblas_operation_to_string(HIPBLAS_OP_N) == "N");
ASSERT_TRUE(hipblas_operation_to_string(HIPBLAS_OP_T) == "T");
ASSERT_TRUE(hipblas_operation_to_string(HIPBLAS_OP_C) == "C");
ASSERT_TRUE(hipblas_operation_to_string(static_cast<hipblasOperation_t>(114)) == "invalid");
// Test char_to_hipblas_operation
ASSERT_TRUE(char_to_hipblas_operation('N') == HIPBLAS_OP_N);
ASSERT_TRUE(char_to_hipblas_operation('n') == HIPBLAS_OP_N);
ASSERT_TRUE(char_to_hipblas_operation('T') == HIPBLAS_OP_T);
ASSERT_TRUE(char_to_hipblas_operation('t') == HIPBLAS_OP_T);
ASSERT_TRUE(char_to_hipblas_operation('C') == HIPBLAS_OP_C);
ASSERT_TRUE(char_to_hipblas_operation('c') == HIPBLAS_OP_C);
ASSERT_TRUE(char_to_hipblas_operation('X') == HIPBLASLT_OPERATION_INVALID);
// Test char_to_hipblas_operation
ASSERT_TRUE(char_to_hipblas_operation('N') == HIPBLAS_OP_N);
ASSERT_TRUE(char_to_hipblas_operation('n') == HIPBLAS_OP_N);
ASSERT_TRUE(char_to_hipblas_operation('T') == HIPBLAS_OP_T);
ASSERT_TRUE(char_to_hipblas_operation('t') == HIPBLAS_OP_T);
ASSERT_TRUE(char_to_hipblas_operation('C') == HIPBLAS_OP_C);
ASSERT_TRUE(char_to_hipblas_operation('c') == HIPBLAS_OP_C);
// Test hip_datatype_to_string
ASSERT_TRUE(hip_datatype_to_string(HIP_R_32F) == "f32_r");
ASSERT_TRUE(hip_datatype_to_string(HIP_R_64F) == "f64_r");
ASSERT_TRUE(hip_datatype_to_string(HIP_R_16F) == "f16_r");
ASSERT_TRUE(hip_datatype_to_string(HIP_R_16BF) == "bf16_r");
ASSERT_TRUE(hip_datatype_to_string(HIP_R_8I) == "i8_r");
ASSERT_TRUE(hip_datatype_to_string(HIP_R_32I) == "i32_r");
ASSERT_TRUE(hip_datatype_to_string(HIP_R_8F_E4M3_FNUZ) == "f8_fnuz_r");
ASSERT_TRUE(hip_datatype_to_string(HIP_R_8F_E5M2_FNUZ) == "bf8_fnuz_r");
ASSERT_TRUE(hip_datatype_to_string(HIP_R_8F_E4M3) == "f8_r");
ASSERT_TRUE(hip_datatype_to_string(HIP_R_8F_E5M2) == "bf8_r");
ASSERT_TRUE(hip_datatype_to_string(static_cast<hipDataType>(HIP_R_6F_E2M3)) == "f6_r");
ASSERT_TRUE(hip_datatype_to_string(static_cast<hipDataType>(HIP_R_6F_E3M2)) == "bf6_r");
ASSERT_TRUE(hip_datatype_to_string(static_cast<hipDataType>(HIP_R_4F_E2M1)) == "f4_r");
// Test hipblas_computetype_to_string
hipblas_computetype_to_string(HIPBLAS_COMPUTE_16F);
ASSERT_TRUE(hipblas_computetype_to_string(HIPBLAS_COMPUTE_16F) == "f16_r");
ASSERT_TRUE(hipblas_computetype_to_string(HIPBLAS_COMPUTE_32F) == "f32_r");
ASSERT_TRUE(hipblas_computetype_to_string(HIPBLAS_COMPUTE_32F_FAST_TF32) == "xf32_r");
ASSERT_TRUE(hipblas_computetype_to_string(HIPBLAS_COMPUTE_64F) == "f64_r");
ASSERT_TRUE(hipblas_computetype_to_string(HIPBLAS_COMPUTE_32I) == "i32_r");
ASSERT_TRUE(hipblas_computetype_to_string(HIPBLAS_COMPUTE_32F_FAST_16F) == "f32_f16_r");
ASSERT_TRUE(hipblas_computetype_to_string(HIPBLAS_COMPUTE_32F_FAST_16BF) == "f32_bf16_r");
ASSERT_TRUE(hipblas_computetype_to_string(HIPBLAS_COMPUTE_64F_PEDANTIC)
== "non-supported compute type");
// Test string_to_hip_datatype
ASSERT_TRUE(string_to_hip_datatype("f8_fnuz_r") == HIP_R_8F_E4M3_FNUZ);
ASSERT_TRUE(string_to_hip_datatype("bf8_fnuz_r") == HIP_R_8F_E5M2_FNUZ);
ASSERT_TRUE(string_to_hip_datatype("f8_r") == HIP_R_8F_E4M3);
ASSERT_TRUE(string_to_hip_datatype("bf8_r") == HIP_R_8F_E5M2);
ASSERT_TRUE(string_to_hip_datatype("f32_r") == HIP_R_32F);
ASSERT_TRUE(string_to_hip_datatype("f64_r") == HIP_R_64F);
ASSERT_TRUE(string_to_hip_datatype("f16_r") == HIP_R_16F);
ASSERT_TRUE(string_to_hip_datatype("bf16_r") == HIP_R_16BF);
ASSERT_TRUE(string_to_hip_datatype("i8_r") == HIP_R_8I);
ASSERT_TRUE(string_to_hip_datatype("f6_r") == static_cast<hipDataType>(HIP_R_6F_E2M3));
ASSERT_TRUE(string_to_hip_datatype("bf6_r") == static_cast<hipDataType>(HIP_R_6F_E3M2));
ASSERT_TRUE(string_to_hip_datatype("f4_r") == static_cast<hipDataType>(HIP_R_4F_E2M1));
ASSERT_TRUE(string_to_hip_datatype("i32_r") == HIP_R_32I);
ASSERT_TRUE(string_to_hip_datatype("") == HIPBLASLT_DATATYPE_INVALID);
// Test string_to_hip_datatype_assert
string_to_hip_datatype_assert("f8_fnuz_r");
// Test string_to_hipblas_computetype
ASSERT_TRUE(string_to_hipblas_computetype("f32_r") == HIPBLAS_COMPUTE_32F);
ASSERT_TRUE(string_to_hipblas_computetype("xf32_r") == HIPBLAS_COMPUTE_32F_FAST_TF32);
ASSERT_TRUE(string_to_hipblas_computetype("f64_r") == HIPBLAS_COMPUTE_64F);
ASSERT_TRUE(string_to_hipblas_computetype("i32_r") == HIPBLAS_COMPUTE_32I);
ASSERT_TRUE(string_to_hipblas_computetype("f32_f16_r") == HIPBLAS_COMPUTE_32F_FAST_16F);
ASSERT_TRUE(string_to_hipblas_computetype("f32_bf16_r") == HIPBLAS_COMPUTE_32F_FAST_16BF);
ASSERT_TRUE(string_to_hipblas_computetype("") == HIPBLASLT_COMPUTE_TYPE_INVALID);
// Test string_to_hipblas_computetype_assert
string_to_hipblas_computetype_assert("f32_r");
// Test string_to_epilogue_type
ASSERT_TRUE(string_to_epilogue_type("HIPBLASLT_EPILOGUE_RELU") == HIPBLASLT_EPILOGUE_RELU);
ASSERT_TRUE(string_to_epilogue_type("HIPBLASLT_EPILOGUE_BIAS") == HIPBLASLT_EPILOGUE_BIAS);
ASSERT_TRUE(string_to_epilogue_type("HIPBLASLT_EPILOGUE_RELU_BIAS")
== HIPBLASLT_EPILOGUE_RELU_BIAS);
ASSERT_TRUE(string_to_epilogue_type("HIPBLASLT_EPILOGUE_GELU") == HIPBLASLT_EPILOGUE_GELU);
ASSERT_TRUE(string_to_epilogue_type("HIPBLASLT_EPILOGUE_GELU_BIAS")
== HIPBLASLT_EPILOGUE_GELU_BIAS);
ASSERT_TRUE(string_to_epilogue_type("HIPBLASLT_EPILOGUE_RELU_AUX")
== HIPBLASLT_EPILOGUE_RELU_AUX);
ASSERT_TRUE(string_to_epilogue_type("HIPBLASLT_EPILOGUE_RELU_AUX_BIAS")
== HIPBLASLT_EPILOGUE_RELU_AUX_BIAS);
ASSERT_TRUE(string_to_epilogue_type("HIPBLASLT_EPILOGUE_GELU_AUX")
== HIPBLASLT_EPILOGUE_GELU_AUX);
ASSERT_TRUE(string_to_epilogue_type("HIPBLASLT_EPILOGUE_GELU_AUX_BIAS")
== HIPBLASLT_EPILOGUE_GELU_AUX_BIAS);
ASSERT_TRUE(string_to_epilogue_type("HIPBLASLT_EPILOGUE_RELU_AUX_BIAS")
== HIPBLASLT_EPILOGUE_RELU_AUX_BIAS);
ASSERT_TRUE(string_to_epilogue_type("HIPBLASLT_EPILOGUE_DGELU") == HIPBLASLT_EPILOGUE_DGELU);
ASSERT_TRUE(string_to_epilogue_type("HIPBLASLT_EPILOGUE_DGELU_BGRAD")
== HIPBLASLT_EPILOGUE_DGELU_BGRAD);
ASSERT_TRUE(string_to_epilogue_type("HIPBLASLT_EPILOGUE_DRELU") == HIPBLASLT_EPILOGUE_DRELU);
ASSERT_TRUE(string_to_epilogue_type("HIPBLASLT_EPILOGUE_DRELU_BGRAD")
== HIPBLASLT_EPILOGUE_DRELU_BGRAD);
ASSERT_TRUE(string_to_epilogue_type("HIPBLASLT_EPILOGUE_BGRADA") == HIPBLASLT_EPILOGUE_BGRADA);
ASSERT_TRUE(string_to_epilogue_type("HIPBLASLT_EPILOGUE_BGRADB") == HIPBLASLT_EPILOGUE_BGRADB);
ASSERT_TRUE(string_to_epilogue_type("HIPBLASLT_EPILOGUE_SWISH_EXT")
== HIPBLASLT_EPILOGUE_SWISH_EXT);
ASSERT_TRUE(string_to_epilogue_type("HIPBLASLT_EPILOGUE_SWISH_BIAS_EXT")
== HIPBLASLT_EPILOGUE_SWISH_BIAS_EXT);
ASSERT_TRUE(string_to_epilogue_type("HIPBLASLT_EPILOGUE_CLAMP_EXT")
== HIPBLASLT_EPILOGUE_CLAMP_EXT);
ASSERT_TRUE(string_to_epilogue_type("HIPBLASLT_EPILOGUE_CLAMP_BIAS_EXT")
== HIPBLASLT_EPILOGUE_CLAMP_BIAS_EXT);
ASSERT_TRUE(string_to_epilogue_type("HIPBLASLT_EPILOGUE_CLAMP_AUX_EXT")
== HIPBLASLT_EPILOGUE_CLAMP_AUX_EXT);
ASSERT_TRUE(string_to_epilogue_type("HIPBLASLT_EPILOGUE_CLAMP_AUX_BIAS_EXT")
== HIPBLASLT_EPILOGUE_CLAMP_AUX_BIAS_EXT);
ASSERT_TRUE(string_to_epilogue_type("HIPBLASLT_EPILOGUE_DEFAULT")
== HIPBLASLT_EPILOGUE_DEFAULT);
ASSERT_TRUE(string_to_epilogue_type("test") == static_cast<hipblasLtEpilogue_t>(0));
// Test string_to_epilogue_type_assert
ASSERT_TRUE(string_to_epilogue_type_assert("HIPBLASLT_EPILOGUE_RELU")
== HIPBLASLT_EPILOGUE_RELU);
// Test hipblaslt_isnan
uint32_t other_type_value = 5;
ASSERT_FALSE(hipblaslt_isnan(other_type_value));
float non_integral_nan = std::numeric_limits<float>::quiet_NaN();
ASSERT_TRUE(hipblaslt_isnan(non_integral_nan));
hipblaslt_f8_fnuz arg_hipblaslt_f8_fnuz;
arg_hipblaslt_f8_fnuz.__x = 0x80;
ASSERT_TRUE(hipblaslt_isnan(arg_hipblaslt_f8_fnuz));
hipblaslt_bf8_fnuz arg_hipblaslt_bf8_fnuz;
arg_hipblaslt_bf8_fnuz.__x = 0x80;
ASSERT_TRUE(hipblaslt_isnan(arg_hipblaslt_bf8_fnuz));
hipblaslt_f8 arg_hipblaslt_f8;
arg_hipblaslt_f8.__x = 0x7f;
ASSERT_TRUE(hipblaslt_isnan(arg_hipblaslt_f8));
arg_hipblaslt_f8.__x = 0x80;
ASSERT_FALSE(hipblaslt_isnan(arg_hipblaslt_f8));
ASSERT_TRUE(arg_hipblaslt_f8.is_zero());
hipblaslt_bf8 arg_hipblaslt_bf8;
arg_hipblaslt_bf8.__x = 0x7d;
ASSERT_TRUE(hipblaslt_isnan(arg_hipblaslt_bf8));
hipblasLtHalf pos_inf = static_cast<hipblasLtHalf>(INFINITY);
ASSERT_TRUE(hipblaslt_isinf(pos_inf));
hipblasLtHalf nan = static_cast<hipblasLtHalf>(NAN);
ASSERT_TRUE(hipblaslt_isnan(nan));
}
inline void testing_aux_float8_func(const Arguments& arg)
{
_Float16 f16 = 2.0;
// hipblaslt_f8_fnuz (FNUZ E4M3): zero only 0x00; 0x80 is NaN (is_inf matches for legacy API).
{
hipblaslt_f8_fnuz v(f16);
ASSERT_TRUE(f16 == static_cast<_Float16>(v));
v.__x = 0x00;
ASSERT_TRUE(v.is_zero());
ASSERT_FALSE(v.is_nan());
ASSERT_FALSE(v.is_inf());
v.__x = 0x80;
ASSERT_FALSE(v.is_zero());
ASSERT_TRUE(v.is_nan());
ASSERT_TRUE(v.is_inf());
ASSERT_TRUE(hipblaslt_isnan(v));
v.__x = 0x38;
ASSERT_FALSE(v.is_zero());
ASSERT_FALSE(v.is_nan());
ASSERT_FALSE(v.is_inf());
hipblaslt_f8_fnuz c;
c = v;
ASSERT_TRUE(c.__x == v.__x);
}
// hipblaslt_f8 (OCP E4M3): ±0 = 0x00/0x80; canonical NaN = 0x7f/0xff; no Inf.
{
hipblaslt_f8 v(f16);
ASSERT_TRUE(f16 == static_cast<_Float16>(v));
v.__x = 0x00;
ASSERT_TRUE(v.is_zero());
ASSERT_FALSE(v.is_nan());
ASSERT_FALSE(v.is_inf());
v.__x = 0x80;
ASSERT_TRUE(v.is_zero());
ASSERT_FALSE(v.is_nan());
ASSERT_FALSE(v.is_inf());
v.__x = 0x7f;
ASSERT_FALSE(v.is_zero());
ASSERT_TRUE(v.is_nan());
ASSERT_FALSE(v.is_inf());
ASSERT_TRUE(hipblaslt_isnan(v));
v.__x = 0xff;
ASSERT_FALSE(v.is_zero());
ASSERT_TRUE(v.is_nan());
ASSERT_FALSE(v.is_inf());
v.__x = 0x2a;
ASSERT_FALSE(v.is_zero());
ASSERT_FALSE(v.is_nan());
ASSERT_FALSE(v.is_inf());
hipblaslt_f8 c = v;
ASSERT_TRUE(c.__x == v.__x);
}
// hipblaslt_bf8_fnuz (FNUZ E5M2): same sentinel pattern as f8_fnuz.
{
hipblaslt_bf8_fnuz v(f16);
ASSERT_TRUE(f16 == static_cast<_Float16>(v));
v.__x = 0x00;
ASSERT_TRUE(v.is_zero());
ASSERT_FALSE(v.is_nan());
ASSERT_FALSE(v.is_inf());
v.__x = 0x80;
ASSERT_FALSE(v.is_zero());
ASSERT_TRUE(v.is_nan());
ASSERT_TRUE(v.is_inf());
ASSERT_TRUE(hipblaslt_isnan(v));
v.__x = 0x14;
ASSERT_FALSE(v.is_zero());
ASSERT_FALSE(v.is_nan());
ASSERT_FALSE(v.is_inf());
hipblaslt_bf8_fnuz c = v;
ASSERT_TRUE(c.__x == v.__x);
}
// hipblaslt_bf8 (OCP E5M2): ±0; Inf 0x7c/0xfc; NaN when exp=max and mantissa non-zero.
{
hipblaslt_bf8 v(f16);
ASSERT_TRUE(f16 == static_cast<_Float16>(v));
v.__x = 0x00;
ASSERT_TRUE(v.is_zero());
ASSERT_FALSE(v.is_nan());
ASSERT_FALSE(v.is_inf());
v.__x = 0x80;
ASSERT_TRUE(v.is_zero());
ASSERT_FALSE(v.is_nan());
ASSERT_FALSE(v.is_inf());
v.__x = 0x7c;
ASSERT_FALSE(v.is_zero());
ASSERT_FALSE(v.is_nan());
ASSERT_TRUE(v.is_inf());
v.__x = 0xfc;
ASSERT_FALSE(v.is_zero());
ASSERT_FALSE(v.is_nan());
ASSERT_TRUE(v.is_inf());
for(int b : {0x7d, 0x7e, 0x7f, 0xfd, 0xfe, 0xff})
{
v.__x = static_cast<decltype(v.__x)>(b);
ASSERT_FALSE(v.is_zero());
ASSERT_TRUE(v.is_nan());
ASSERT_FALSE(v.is_inf());
ASSERT_TRUE(hipblaslt_isnan(v));
}
v.__x = 0x08;
ASSERT_FALSE(v.is_zero());
ASSERT_FALSE(v.is_nan());
ASSERT_FALSE(v.is_inf());
hipblaslt_bf8 c = v;
ASSERT_TRUE(c.__x == v.__x);
}
// namespace std functions
// Test hipblaslt_f8_fnuz sin function
hipblaslt_f8_fnuz f8_fnuz_sin_val(f16);
hipblaslt_f8_fnuz f8_fnuz_sin_val_r = std::sin(f8_fnuz_sin_val);
ASSERT_TRUE(f8_fnuz_sin_val_r == hipblaslt_f8_fnuz(sinf(float(f8_fnuz_sin_val))));
// Test hipblaslt_f8_fnuz cos function
hipblaslt_f8_fnuz f8_fnuz_cos_val(f16);
hipblaslt_f8_fnuz f8_fnuz_cos_val_r = std::cos(f8_fnuz_cos_val);
ASSERT_TRUE(f8_fnuz_cos_val_r == hipblaslt_f8_fnuz(cosf(float(f8_fnuz_cos_val))));
// Test hipblaslt_f8 sin function
hipblaslt_f8 f8_sin_val(f16);
hipblaslt_f8 f8_sin_val_r = std::sin(f8_sin_val);
ASSERT_TRUE(f8_sin_val_r == hipblaslt_f8(sinf(float(f8_sin_val))));
// Test hipblaslt_f8 cos function
hipblaslt_f8 f8_cos_val(f16);
hipblaslt_f8 f8_cos_val_r = std::cos(f8_cos_val);
ASSERT_TRUE(f8_cos_val_r == hipblaslt_f8(cosf(float(f8_cos_val))));
// Test hipblaslt_bf8_fnuz sin function
hipblaslt_bf8_fnuz bf8_fnuz_sin_val(f16);
hipblaslt_bf8_fnuz bf8_fnuz_sin_val_r = std::sin(bf8_fnuz_sin_val);
ASSERT_TRUE(bf8_fnuz_sin_val_r == hipblaslt_bf8_fnuz(sinf(float(bf8_fnuz_sin_val))));
// Test hipblaslt_bf8_fnuz cos function
hipblaslt_bf8_fnuz bf8_fnuz_cos_val(f16);
hipblaslt_bf8_fnuz bf8_fnuz_cos_val_r = std::cos(bf8_fnuz_cos_val);
ASSERT_TRUE(bf8_fnuz_cos_val_r == hipblaslt_bf8_fnuz(cosf(float(bf8_fnuz_cos_val))));
// Test hipblaslt_bf8 sin function
hipblaslt_bf8 bf8_sin_val(f16);
hipblaslt_bf8 bf8_sin_val_r = std::sin(bf8_sin_val);
ASSERT_TRUE(bf8_sin_val_r == hipblaslt_bf8(sinf(float(bf8_sin_val))));
// Test hipblaslt_bf8 cos function
hipblaslt_bf8 bf8_cos_val(f16);
hipblaslt_bf8 bf8_cos_val_r = std::cos(bf8_cos_val);
ASSERT_TRUE(bf8_cos_val_r == hipblaslt_bf8(cosf(float(bf8_cos_val))));
// Test hipblaslt_f8_fnuz real function
hipblaslt_f8_fnuz f8_fnuz_real_val(f16);
hipblaslt_f8_fnuz f8_fnuz_real_val_r = std::real(f8_fnuz_real_val);
ASSERT_TRUE(f8_fnuz_real_val_r == hipblaslt_f8_fnuz(std::real(float(f8_fnuz_real_val))));
// Test hipblaslt_f8 real function
hipblaslt_f8 f8_real_val(f16);
hipblaslt_f8 f8_real_val_r = std::real(f8_real_val);
ASSERT_TRUE(f8_real_val_r == hipblaslt_f8(std::real(float(f8_real_val))));
// Test hipblaslt_bf8_fnuz real function
hipblaslt_bf8_fnuz bf8_fnuz_real_val(f16);
hipblaslt_bf8_fnuz bf8_fnuz_real_val_r = std::real(bf8_fnuz_real_val);
ASSERT_TRUE(bf8_fnuz_real_val_r == hipblaslt_bf8_fnuz(std::real(float(bf8_fnuz_real_val))));
// Test hipblaslt_bf8 real function
hipblaslt_bf8 bf8_real_val(f16);
hipblaslt_bf8 bf8_real_val_r = std::real(bf8_real_val);
ASSERT_TRUE(bf8_real_val_r == hipblaslt_bf8(std::real(float(bf8_real_val))));
// Test hipblaslt_f8_fnuz ostream operator
hipblaslt_f8_fnuz f8_fnuz_stream_val(f16);
std::ostringstream f8_fnuz_stream;
f8_fnuz_stream << f8_fnuz_stream_val;
std::ostringstream f8_fnuz_expected;
f8_fnuz_expected << float(f8_fnuz_stream_val);
ASSERT_TRUE(f8_fnuz_stream.str() == f8_fnuz_expected.str());
// Test hipblaslt_f8 ostream operator
hipblaslt_f8 f8_stream_val(f16);
std::ostringstream f8_stream;
f8_stream << f8_stream_val;
std::ostringstream f8_expected;
f8_expected << float(f8_stream_val);
ASSERT_TRUE(f8_stream.str() == f8_expected.str());
// Test hipblaslt_bf8_fnuz ostream operator
hipblaslt_bf8_fnuz bf8_fnuz_stream_val(f16);
std::ostringstream bf8_fnuz_stream;
bf8_fnuz_stream << bf8_fnuz_stream_val;
std::ostringstream bf8_fnuz_expected;
bf8_fnuz_expected << float(bf8_fnuz_stream_val);
ASSERT_TRUE(bf8_fnuz_stream.str() == bf8_fnuz_expected.str());
// Test hipblaslt_bf8 ostream operator
hipblaslt_bf8 bf8_stream_val(f16);
std::ostringstream bf8_stream;
bf8_stream << bf8_stream_val;
std::ostringstream bf8_expected;
bf8_expected << float(bf8_stream_val);
ASSERT_TRUE(bf8_stream.str() == bf8_expected.str());
// Test code for hipblaslt_float8.h operator overloads
_Float16 f16_a = 2.5;
_Float16 f16_b = 1.5;
float float_val = 3.0f;
int32_t int_val = 4;
double double_val = 5.0;
// Test addition operators with mixed types (float + f8 types)
hipblaslt_f8_fnuz f8_fnuz_val(f16_a);
hipblaslt_f8 f8_val(f16_a);
hipblaslt_bf8_fnuz bf8_fnuz_val(f16_a);
hipblaslt_bf8 bf8_val(f16_a);
// Test float + f8 types
float result_f = float_val + f8_fnuz_val;
ASSERT_TRUE(result_f == (float_val + float(f8_fnuz_val)));
result_f = float_val + f8_val;
ASSERT_TRUE(result_f == (float_val + float(f8_val)));
result_f = float_val + bf8_fnuz_val;
ASSERT_TRUE(result_f == (float_val + float(bf8_fnuz_val)));
result_f = float_val + bf8_val;
ASSERT_TRUE(result_f == (float_val + float(bf8_val)));
// Test f8 types + float
result_f = f8_fnuz_val + float_val;
ASSERT_TRUE(result_f == (float(f8_fnuz_val) + float_val));
result_f = f8_val + float_val;
ASSERT_TRUE(result_f == (float(f8_val) + float_val));
result_f = bf8_fnuz_val + float_val;
ASSERT_TRUE(result_f == (float(bf8_fnuz_val) + float_val));
result_f = bf8_val + float_val;
ASSERT_TRUE(result_f == (float(bf8_val) + float_val));
// Test mixed f8 types addition (returns float)
result_f = f8_fnuz_val + bf8_fnuz_val;
ASSERT_TRUE(result_f == (float(f8_fnuz_val) + float(bf8_fnuz_val)));
result_f = f8_val + bf8_val;
ASSERT_TRUE(result_f == (float(f8_val) + float(bf8_val)));
result_f = bf8_fnuz_val + f8_fnuz_val;
ASSERT_TRUE(result_f == (float(bf8_fnuz_val) + float(f8_fnuz_val)));
result_f = bf8_val + f8_val;
ASSERT_TRUE(result_f == (float(bf8_val) + float(f8_val)));
// Test same type addition (returns same type)
hipblaslt_f8_fnuz f8_fnuz_b(f16_b);
hipblaslt_f8_fnuz f8_fnuz_result = f8_fnuz_val + f8_fnuz_b;
ASSERT_TRUE(f8_fnuz_result == hipblaslt_f8_fnuz(float(f8_fnuz_val) + float(f8_fnuz_b)));
hipblaslt_f8 f8_b(f16_b);
hipblaslt_f8 f8_result = f8_val + f8_b;
ASSERT_TRUE(f8_result == hipblaslt_f8(float(f8_val) + float(f8_b)));
hipblaslt_bf8_fnuz bf8_fnuz_b(f16_b);
hipblaslt_bf8_fnuz bf8_fnuz_result = bf8_fnuz_val + bf8_fnuz_b;
ASSERT_TRUE(bf8_fnuz_result == hipblaslt_bf8_fnuz(float(bf8_fnuz_val) + float(bf8_fnuz_b)));
hipblaslt_bf8 bf8_b(f16_b);
hipblaslt_bf8 bf8_result = bf8_val + bf8_b;
ASSERT_TRUE(bf8_result == hipblaslt_bf8(float(bf8_val) + float(bf8_b)));
// Test += operators
hipblaslt_f8_fnuz f8_fnuz_copy = f8_fnuz_val;
f8_fnuz_copy += f8_fnuz_b;
ASSERT_TRUE(f8_fnuz_copy == hipblaslt_f8_fnuz(float(f8_fnuz_val) + float(f8_fnuz_b)));
hipblaslt_f8 f8_copy = f8_val;
f8_copy += f8_b;
ASSERT_TRUE(f8_copy == hipblaslt_f8(float(f8_val) + float(f8_b)));
hipblaslt_bf8_fnuz bf8_fnuz_copy = bf8_fnuz_val;
bf8_fnuz_copy += bf8_fnuz_b;
ASSERT_TRUE(bf8_fnuz_copy == hipblaslt_bf8_fnuz(float(bf8_fnuz_val) + float(bf8_fnuz_b)));
hipblaslt_bf8 bf8_copy = bf8_val;
bf8_copy += bf8_b;
ASSERT_TRUE(bf8_copy == hipblaslt_bf8(float(bf8_val) + float(bf8_b)));
// Test multiplication operators (all return float)
// Same type multiplication
result_f = f8_fnuz_val * f8_fnuz_b;
ASSERT_TRUE(result_f == (float(f8_fnuz_val) * float(f8_fnuz_b)));
result_f = f8_val * f8_b;
ASSERT_TRUE(result_f == (float(f8_val) * float(f8_b)));
// Test float * f8 types
result_f = float_val * f8_fnuz_val;
ASSERT_TRUE(result_f == (float_val * float(f8_fnuz_val)));
result_f = float_val * f8_val;
ASSERT_TRUE(result_f == (float_val * float(f8_val)));
// Test f8 types * float
result_f = f8_fnuz_val * float_val;
ASSERT_TRUE(result_f == (float(f8_fnuz_val) * float_val));
result_f = f8_val * float_val;
ASSERT_TRUE(result_f == (float(f8_val) * float_val));
// Test int32_t * f8 types
result_f = int_val * f8_fnuz_val;
ASSERT_TRUE(result_f == ((float)int_val * float(f8_fnuz_val)));
result_f = int_val * f8_val;
ASSERT_TRUE(result_f == ((float)int_val * float(f8_val)));
// Test double * f8 types
result_f = double_val * f8_fnuz_val;
ASSERT_TRUE(result_f == ((float)double_val * float(f8_fnuz_val)));
result_f = double_val * f8_val;
ASSERT_TRUE(result_f == ((float)double_val * float(f8_val)));
// Test bf8 type multiplication tests
result_f = bf8_fnuz_val * bf8_fnuz_b;
ASSERT_TRUE(result_f == (float(bf8_fnuz_val) * float(bf8_fnuz_b)));
result_f = bf8_val * bf8_b;
ASSERT_TRUE(result_f == (float(bf8_val) * float(bf8_b)));
result_f = float_val * bf8_fnuz_val;
ASSERT_TRUE(result_f == (float_val * float(bf8_fnuz_val)));
result_f = float_val * bf8_val;
ASSERT_TRUE(result_f == (float_val * float(bf8_val)));
result_f = bf8_fnuz_val * float_val;
ASSERT_TRUE(result_f == (float(bf8_fnuz_val) * float_val));
result_f = bf8_val * float_val;
ASSERT_TRUE(result_f == (float(bf8_val) * float_val));
result_f = int_val * bf8_fnuz_val;
ASSERT_TRUE(result_f == ((float)int_val * float(bf8_fnuz_val)));
result_f = int_val * bf8_val;
ASSERT_TRUE(result_f == ((float)int_val * float(bf8_val)));
result_f = double_val * bf8_fnuz_val;
ASSERT_TRUE(result_f == ((float)double_val * float(bf8_fnuz_val)));
result_f = double_val * bf8_val;
ASSERT_TRUE(result_f == ((float)double_val * float(bf8_val)));
// Test Mixed f8 and bf8 multiplication
result_f = f8_fnuz_val * bf8_fnuz_val;
ASSERT_TRUE(result_f == (float(f8_fnuz_val) * float(bf8_fnuz_val)));
result_f = f8_val * bf8_val;
ASSERT_TRUE(result_f == (float(f8_val) * float(bf8_val)));
result_f = bf8_fnuz_val * f8_fnuz_val;
ASSERT_TRUE(result_f == (float(bf8_fnuz_val) * float(f8_fnuz_val)));
result_f = bf8_val * f8_val;
ASSERT_TRUE(result_f == (float(bf8_val) * float(f8_val)));
// Test comparison operators
// Equality operators
bool result_b = (f8_fnuz_val == f8_fnuz_b);
ASSERT_TRUE(result_b == (f8_fnuz_val.__x == f8_fnuz_b.__x));
result_b = (f8_val == f8_b);
ASSERT_TRUE(result_b == (f8_val.__x == f8_b.__x));
result_b = (bf8_fnuz_val == bf8_fnuz_b);
ASSERT_TRUE(result_b == (bf8_fnuz_val.__x == bf8_fnuz_b.__x));
result_b = (bf8_val == bf8_b);
ASSERT_TRUE(result_b == (bf8_val.__x == bf8_b.__x));
// Test Inequality operators
result_b = (f8_fnuz_val != f8_fnuz_b);
ASSERT_TRUE(result_b == (f8_fnuz_val.__x != f8_fnuz_b.__x));
result_b = (f8_val != f8_b);
ASSERT_TRUE(result_b == (f8_val.__x != f8_b.__x));
result_b = (bf8_fnuz_val != bf8_fnuz_b);
ASSERT_TRUE(result_b == (bf8_fnuz_val.__x != bf8_fnuz_b.__x));
result_b = (bf8_val != bf8_b);
ASSERT_TRUE(result_b == (bf8_val.__x != bf8_b.__x));
// Test Greater than or equal operators
result_b = (f8_fnuz_val >= f8_fnuz_b);
ASSERT_TRUE(result_b == (static_cast<float>(f8_fnuz_val) >= static_cast<float>(f8_fnuz_b)));
result_b = (f8_val >= f8_b);
ASSERT_TRUE(result_b == (static_cast<float>(f8_val) >= static_cast<float>(f8_b)));
// Test Greater than operators
result_b = (f8_fnuz_val > f8_fnuz_b);
ASSERT_TRUE(result_b == (static_cast<float>(f8_fnuz_val) > static_cast<float>(f8_fnuz_b)));
result_b = (f8_val > f8_b);
ASSERT_TRUE(result_b == (static_cast<float>(f8_val) > static_cast<float>(f8_b)));
}
inline void testing_aux_hipblaslt_ext_op_func(const Arguments& arg)
{
ASSERT_TRUE(hipblasltGetTotalGranularityValue()
== hipblasltClientPerformanceArgs::totalGranularity);
ASSERT_TRUE(hipblasltGetTilesPerCuValue() == hipblasltClientPerformanceArgs::tilesPerCu);
ASSERT_TRUE(hipblasltGetTile0Granularity() == hipblasltClientPerformanceArgs::tile0Granularity);
ASSERT_TRUE(hipblasltGetTile1Granularity() == hipblasltClientPerformanceArgs::tile1Granularity);
ASSERT_TRUE(hipblasltGetCuGranularity() == hipblasltClientPerformanceArgs::cuGranularity);
ASSERT_TRUE(hipblasltGetWaveGranularity() == hipblasltClientPerformanceArgs::waveGranularity);
ASSERT_TRUE(hipblasltGetCUs() == hipblasltClientPerformanceArgs::CUs);
ASSERT_TRUE(hipblasltGetMemWriteBytesD() == hipblasltClientPerformanceArgs::memWriteBytesD);
ASSERT_TRUE(hipblasltGetMemReadBytes() == hipblasltClientPerformanceArgs::memReadBytes);
}
inline void testing_aux_rocblaslt_utility_func(const Arguments& arg)
{
// Test basic prefix functionality
std::string result = prefix("TEST_LAYER", "test_caller");
// Check that result is not empty
ASSERT_TRUE(!result.empty());
// Check that result contains expected components
ASSERT_TRUE(result.find("[HIPBLASLT]") != std::string::npos);
ASSERT_TRUE(result.find("[TEST_LAYER]") != std::string::npos);
ASSERT_TRUE(result.find("[test_caller]") != std::string::npos);
// Check date format pattern (YYYY-MM-DD)
std::regex date_pattern(R"(\[\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\])");
ASSERT_TRUE(std::regex_search(result, date_pattern));
// Check process ID is included (numeric value in brackets)
std::regex pid_pattern(R"(\[\d+\])");
ASSERT_TRUE(std::regex_search(result, pid_pattern));
// Test with different layer and caller names
std::string result2 = prefix("ERROR", "function_name");
ASSERT_TRUE(result2.find("[ERROR]") != std::string::npos);
ASSERT_TRUE(result2.find("[function_name]") != std::string::npos);
// Test with empty strings (edge case)
std::string result3 = prefix("", "");
ASSERT_TRUE(result3.find("[]") != std::string::npos); // Should contain empty brackets
ASSERT_TRUE(result3.find("[HIPBLASLT]")
!= std::string::npos); // HIPBLASLT should always be present
// Test format consistency - two calls should have similar structure
std::string result4 = prefix("LAYER1", "caller1");
std::string result5 = prefix("LAYER2", "caller2");
// Both should contain HIPBLASLT
ASSERT_TRUE(result4.find("[HIPBLASLT]") != std::string::npos);
ASSERT_TRUE(result5.find("[HIPBLASLT]") != std::string::npos);
// Both should match the expected format pattern
std::regex full_pattern(
R"(\[\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\]\[HIPBLASLT\]\[\d+\]\[.*\]\[.*\])");
ASSERT_TRUE(std::regex_match(result4, full_pattern));
ASSERT_TRUE(std::regex_match(result5, full_pattern));
// Test hipDataType_to_string function
ASSERT_TRUE(std::string_view{hipDataType_to_string(HIP_R_16F)} == "R_16F");
ASSERT_TRUE(std::string_view{hipDataType_to_string(HIP_R_16BF)} == "R_16BF");
ASSERT_TRUE(std::string_view{hipDataType_to_string(HIP_R_32F)} == "R_32F");
ASSERT_TRUE(std::string_view{hipDataType_to_string(HIP_R_64F)} == "R_64F");
ASSERT_TRUE(std::string_view{hipDataType_to_string(HIP_R_8F_E4M3_FNUZ)} == "R_8F_E4M3_FNUZ");
ASSERT_TRUE(std::string_view{hipDataType_to_string(HIP_R_8F_E5M2_FNUZ)} == "R_8F_E5M2_FNUZ");
ASSERT_TRUE(std::string_view{hipDataType_to_string(HIP_R_8F_E4M3)} == "R_8F_E4M3");
ASSERT_TRUE(std::string_view{hipDataType_to_string(HIP_R_8F_E5M2)} == "R_8F_E5M2");
ASSERT_TRUE(std::string_view{hipDataType_to_string(HIP_R_8I)} == "R_8I");
ASSERT_TRUE(std::string_view{hipDataType_to_string(static_cast<hipDataType>(HIP_R_6F_E2M3))}
== "R_6F_E2M3");
ASSERT_TRUE(std::string_view{hipDataType_to_string(static_cast<hipDataType>(HIP_R_6F_E3M2))}
== "R_6F_E3M2");
ASSERT_TRUE(std::string_view{hipDataType_to_string(static_cast<hipDataType>(HIP_R_4F_E2M1))}
== "R_4F_E2M1");
ASSERT_TRUE(std::string_view{hipDataType_to_string(static_cast<hipDataType>(999))}
== "Invalid");
ASSERT_TRUE(std::string_view{hipDataType_to_bench_string(HIP_R_32F)} == "f32_r");
ASSERT_TRUE(std::string_view{hipDataType_to_bench_string(HIP_R_64F)} == "f64_r");
ASSERT_TRUE(std::string_view{hipDataType_to_bench_string(HIP_R_16F)} == "f16_r");
ASSERT_TRUE(std::string_view{hipDataType_to_bench_string(HIP_R_16BF)} == "bf16_r");
ASSERT_TRUE(std::string_view{hipDataType_to_bench_string(HIP_R_8I)} == "i8_r");
ASSERT_TRUE(std::string_view{hipDataType_to_bench_string(HIP_R_32I)} == "i32_r");
ASSERT_TRUE(std::string_view{hipDataType_to_bench_string(HIP_R_8F_E4M3_FNUZ)} == "f8_r");
ASSERT_TRUE(std::string_view{hipDataType_to_bench_string(HIP_R_8F_E5M2_FNUZ)} == "bf8_r");
ASSERT_TRUE(std::string_view{hipDataType_to_bench_string(HIP_R_8F_E4M3)} == "f8_r");
ASSERT_TRUE(std::string_view{hipDataType_to_bench_string(HIP_R_8F_E5M2)} == "bf8_r");
ASSERT_TRUE(std::string_view{hipDataType_to_bench_string(HIP_R_8F_E5M2_FNUZ)} == "bf8_r");
ASSERT_TRUE(
std::string_view{hipDataType_to_bench_string(static_cast<hipDataType>(HIP_R_6F_E2M3))}
== "f6_r");
ASSERT_TRUE(
std::string_view{hipDataType_to_bench_string(static_cast<hipDataType>(HIP_R_6F_E3M2))}
== "bf6_r");
ASSERT_TRUE(
std::string_view{hipDataType_to_bench_string(static_cast<hipDataType>(HIP_R_4F_E2M1))}
== "f4_r");
ASSERT_TRUE(std::string_view{
hipDataType_to_bench_string(static_cast<hipDataType>(HIP_R_4F_E2M1 + 1))}
== "invalid");
// Test rocblaslt_compute_type_to_string
ASSERT_TRUE(std::string_view{rocblaslt_compute_type_to_string(rocblaslt_compute_f16)}
== "COMPUTE_16F");
ASSERT_TRUE(std::string_view{rocblaslt_compute_type_to_string(rocblaslt_compute_f32)}
== "COMPUTE_32F");
ASSERT_TRUE(std::string_view{rocblaslt_compute_type_to_string(rocblaslt_compute_f32_fast_xf32)}
== "COMPUTE_32XF");
ASSERT_TRUE(std::string_view{rocblaslt_compute_type_to_string(rocblaslt_compute_f64)}
== "COMPUTE_64F");
ASSERT_TRUE(std::string_view{rocblaslt_compute_type_to_string(rocblaslt_compute_i32)}
== "COMPUTE_32I");
ASSERT_TRUE(std::string_view{rocblaslt_compute_type_to_string(rocblaslt_compute_f32_fast_f16)}
== "COMPUTE_32F_16F");
ASSERT_TRUE(std::string_view{rocblaslt_compute_type_to_string(rocblaslt_compute_f32_fast_bf16)}
== "COMPUTE_32F_16BF");
ASSERT_TRUE(
std::string_view{rocblaslt_compute_type_to_string(static_cast<rocblaslt_compute_type>(999))}
== "Invalid");
// Test rocblaslt_matrix_layout_attributes_to_string
ASSERT_TRUE(std::string_view{rocblaslt_matrix_layout_attributes_to_string(
ROCBLASLT_MATRIX_LAYOUT_BATCH_COUNT)}
== "MATRIX_LAYOUT_BATCH_COUNT");
ASSERT_TRUE(std::string_view{rocblaslt_matrix_layout_attributes_to_string(
ROCBLASLT_MATRIX_LAYOUT_STRIDED_BATCH_OFFSET)}
== "MATRIX_LAYOUT_STRIDED_BATCH_OFFSET");
ASSERT_TRUE(
std::string_view{rocblaslt_matrix_layout_attributes_to_string(ROCBLASLT_MATRIX_LAYOUT_TYPE)}
== "ROCBLASLT_MATRIX_LAYOUT_TYPE");
ASSERT_TRUE(std::string_view{
rocblaslt_matrix_layout_attributes_to_string(ROCBLASLT_MATRIX_LAYOUT_ORDER)}
== "ROCBLASLT_MATRIX_LAYOUT_ORDER");
ASSERT_TRUE(
std::string_view{rocblaslt_matrix_layout_attributes_to_string(ROCBLASLT_MATRIX_LAYOUT_ROWS)}
== "ROCBLASLT_MATRIX_LAYOUT_ROWS");
ASSERT_TRUE(
std::string_view{rocblaslt_matrix_layout_attributes_to_string(ROCBLASLT_MATRIX_LAYOUT_COLS)}
== "ROCBLASLT_MATRIX_LAYOUT_COLS");
ASSERT_TRUE(
std::string_view{rocblaslt_matrix_layout_attributes_to_string(ROCBLASLT_MATRIX_LAYOUT_LD)}
== "ROCBLASLT_MATRIX_LAYOUT_LD");
ASSERT_TRUE(
std::string_view{rocblaslt_matrix_layout_attributes_to_string(ROCBLASLT_MATRIX_LAYOUT_MAX)}
== "ROCBLASLT_MATRIX_LAYOUT_MAX");
ASSERT_TRUE(std::string_view{rocblaslt_matrix_layout_attributes_to_string(
static_cast<rocblaslt_matrix_layout_attribute_>(999))}
== "Invalid");
// Test rocblaslt_matmul_desc_attributes_to_string
ASSERT_TRUE(
std::string_view{rocblaslt_matmul_desc_attributes_to_string(ROCBLASLT_MATMUL_DESC_TRANSA)}
== "MATMUL_DESC_TRANSA");
ASSERT_TRUE(
std::string_view{rocblaslt_matmul_desc_attributes_to_string(ROCBLASLT_MATMUL_DESC_TRANSB)}
== "MATMUL_DESC_TRANSB");
ASSERT_TRUE(
std::string_view{rocblaslt_matmul_desc_attributes_to_string(ROCBLASLT_MATMUL_DESC_EPILOGUE)}
== "MATMUL_DESC_EPILOGUE");
ASSERT_TRUE(std::string_view{
rocblaslt_matmul_desc_attributes_to_string(ROCBLASLT_MATMUL_DESC_BIAS_POINTER)}
== "MATMUL_DESC_BIAS_POINTER");
ASSERT_TRUE(std::string_view{rocblaslt_matmul_desc_attributes_to_string(
ROCBLASLT_MATMUL_DESC_BIAS_DATA_TYPE)}
== "MATMUL_DESC_BIAS_DATA_TYPE");
ASSERT_TRUE(std::string_view{rocblaslt_matmul_desc_attributes_to_string(
ROCBLASLT_MATMUL_DESC_A_SCALE_POINTER)}
== "MATMUL_DESC_A_SCALE_POINTER");
ASSERT_TRUE(std::string_view{rocblaslt_matmul_desc_attributes_to_string(
ROCBLASLT_MATMUL_DESC_B_SCALE_POINTER)}
== "MATMUL_DESC_B_SCALE_POINTER");
ASSERT_TRUE(std::string_view{rocblaslt_matmul_desc_attributes_to_string(
ROCBLASLT_MATMUL_DESC_C_SCALE_POINTER)}
== "MATMUL_DESC_C_SCALE_POINTER");
ASSERT_TRUE(std::string_view{rocblaslt_matmul_desc_attributes_to_string(
ROCBLASLT_MATMUL_DESC_D_SCALE_POINTER)}
== "MATMUL_DESC_D_SCALE_POINTER");
ASSERT_TRUE(std::string_view{rocblaslt_matmul_desc_attributes_to_string(
ROCBLASLT_MATMUL_DESC_EPILOGUE_AUX_POINTER)}
== "MATMUL_DESC_EPILOGUE_AUX_POINTER");
ASSERT_TRUE(std::string_view{rocblaslt_matmul_desc_attributes_to_string(
ROCBLASLT_MATMUL_DESC_EPILOGUE_AUX_LD)}
== "MATMUL_DESC_EPILOGUE_AUX_LD");
ASSERT_TRUE(std::string_view{rocblaslt_matmul_desc_attributes_to_string(
ROCBLASLT_MATMUL_DESC_EPILOGUE_AUX_BATCH_STRIDE)}
== "MATMUL_DESC_EPILOGUE_AUX_BATCH_STRIDE");
ASSERT_TRUE(std::string_view{
rocblaslt_matmul_desc_attributes_to_string(ROCBLASLT_MATMUL_DESC_POINTER_MODE)}
== "MATMUL_DESC_POINTER_MODE");
ASSERT_TRUE(std::string_view{rocblaslt_matmul_desc_attributes_to_string(
ROCBLASLT_MATMUL_DESC_AMAX_D_POINTER)}
== "MATMUL_DESC_AMAX_D_POINTER");
ASSERT_TRUE(std::string_view{rocblaslt_matmul_desc_attributes_to_string(
ROCBLASLT_MATMUL_DESC_EPILOGUE_AUX_DATA_TYPE)}
== "MATMUL_DESC_EPILOGUE_AUX_DATA_TYPE");
ASSERT_TRUE(std::string_view{rocblaslt_matmul_desc_attributes_to_string(
ROCBLASLT_MATMUL_DESC_COMPUTE_INPUT_TYPE_A_EXT)}
== "MATMUL_DESC_COMPUTE_INPUT_TYPE_A_EXT");
ASSERT_TRUE(std::string_view{rocblaslt_matmul_desc_attributes_to_string(
ROCBLASLT_MATMUL_DESC_COMPUTE_INPUT_TYPE_B_EXT)}
== "MATMUL_DESC_COMPUTE_INPUT_TYPE_B_EXT");
ASSERT_TRUE(std::string_view{rocblaslt_matmul_desc_attributes_to_string(
static_cast<rocblaslt_matmul_desc_attributes>(999))}
== "Invalid");
// Test hipblasOperation_to_string
ASSERT_TRUE(std::string_view{hipblasOperation_to_string(HIPBLAS_OP_N)} == "OP_N");
ASSERT_TRUE(std::string_view{hipblasOperation_to_string(HIPBLAS_OP_T)} == "OP_T");
ASSERT_TRUE(std::string_view{hipblasOperation_to_string(HIPBLAS_OP_C)} == "OP_C");
ASSERT_TRUE(std::string_view{hipblasOperation_to_string(static_cast<hipblasOperation_t>(999))}
== "Invalid");
// Test rocblaslt_layer_mode2string
ASSERT_TRUE(std::string_view{rocblaslt_layer_mode2string(rocblaslt_layer_mode_none)} == "None");
ASSERT_TRUE(std::string_view{rocblaslt_layer_mode2string(rocblaslt_layer_mode_log_error)}
== "Error");
ASSERT_TRUE(std::string_view{rocblaslt_layer_mode2string(rocblaslt_layer_mode_log_trace)}
== "Trace");
ASSERT_TRUE(std::string_view{rocblaslt_layer_mode2string(rocblaslt_layer_mode_log_hints)}
== "Hints");
ASSERT_TRUE(std::string_view{rocblaslt_layer_mode2string(rocblaslt_layer_mode_log_info)}
== "Info");
ASSERT_TRUE(std::string_view{rocblaslt_layer_mode2string(rocblaslt_layer_mode_log_api)}
== "Api");
ASSERT_TRUE(std::string_view{rocblaslt_layer_mode2string(rocblaslt_layer_mode_log_bench)}
== "Bench");
ASSERT_TRUE(std::string_view{rocblaslt_layer_mode2string(rocblaslt_layer_mode_log_profile)}
== "Profile");
ASSERT_TRUE(
std::string_view{rocblaslt_layer_mode2string(rocblaslt_layer_mode_log_extended_profile)}
== "ExtendedProfile");
ASSERT_TRUE(
std::string_view{rocblaslt_layer_mode2string(static_cast<rocblaslt_layer_mode>(999))}
== "Invalid");
// Test rocblaslt_epilogue_to_string
ASSERT_TRUE(std::string_view{rocblaslt_epilogue_to_string(ROCBLASLT_EPILOGUE_DEFAULT)}
== "EPILOGUE_DEFAULT");
ASSERT_TRUE(std::string_view{rocblaslt_epilogue_to_string(ROCBLASLT_EPILOGUE_RELU)}
== "EPILOGUE_RELU");
ASSERT_TRUE(std::string_view{rocblaslt_epilogue_to_string(ROCBLASLT_EPILOGUE_BIAS)}
== "EPILOGUE_BIAS");
ASSERT_TRUE(std::string_view{rocblaslt_epilogue_to_string(ROCBLASLT_EPILOGUE_RELU_BIAS)}
== "EPILOGUE_RELU_BIAS");
ASSERT_TRUE(std::string_view{rocblaslt_epilogue_to_string(ROCBLASLT_EPILOGUE_GELU)}
== "EPILOGUE_GELU");
ASSERT_TRUE(std::string_view{rocblaslt_epilogue_to_string(ROCBLASLT_EPILOGUE_DGELU)}
== "EPILOGUE_DGELU");
ASSERT_TRUE(std::string_view{rocblaslt_epilogue_to_string(ROCBLASLT_EPILOGUE_DRELU)}
== "EPILOGUE_DRELU");
ASSERT_TRUE(std::string_view{rocblaslt_epilogue_to_string(ROCBLASLT_EPILOGUE_GELU_BIAS)}
== "EPILOGUE_GELU_BIAS");
ASSERT_TRUE(std::string_view{rocblaslt_epilogue_to_string(ROCBLASLT_EPILOGUE_GELU_AUX)}
== "EPILOGUE_GELU_AUX");
ASSERT_TRUE(std::string_view{rocblaslt_epilogue_to_string(ROCBLASLT_EPILOGUE_GELU_AUX_BIAS)}
== "EPILOGUE_GELU_AUX_BIAS");
ASSERT_TRUE(std::string_view{rocblaslt_epilogue_to_string(ROCBLASLT_EPILOGUE_DGELU_BGRAD)}
== "EPILOGUE_DGELU_BGRAD");
ASSERT_TRUE(std::string_view{rocblaslt_epilogue_to_string(ROCBLASLT_EPILOGUE_BGRADA)}
== "EPILOGUE_BGRADA");
ASSERT_TRUE(std::string_view{rocblaslt_epilogue_to_string(ROCBLASLT_EPILOGUE_BGRADB)}
== "EPILOGUE_BGRADB");
ASSERT_TRUE(std::string_view{rocblaslt_epilogue_to_string(ROCBLASLT_EPILOGUE_DRELU_BGRAD)}
== "EPILOGUE_DRELU_BGRAD");
ASSERT_TRUE(std::string_view{rocblaslt_epilogue_to_string(ROCBLASLT_EPILOGUE_SWISH_EXT)}
== "EPILOGUE_SWISH_EXT");
ASSERT_TRUE(std::string_view{rocblaslt_epilogue_to_string(ROCBLASLT_EPILOGUE_SWISH_BIAS_EXT)}
== "EPILOGUE_SWISH_BIAS_EXT");
ASSERT_TRUE(std::string_view{rocblaslt_epilogue_to_string(static_cast<rocblaslt_epilogue>(999))}
== "Invalid epilogue");
// Test all valid rocblaslt_compute_type values
ASSERT_TRUE(std::string_view{rocblaslt_compute_type_string(rocblaslt_compute_f16)} == "f16_r");
ASSERT_TRUE(std::string_view{rocblaslt_compute_type_string(rocblaslt_compute_f32)} == "f32_r");
ASSERT_TRUE(std::string_view{rocblaslt_compute_type_string(rocblaslt_compute_f32_fast_xf32)}
== "xf32_r");
ASSERT_TRUE(std::string_view{rocblaslt_compute_type_string(rocblaslt_compute_i32)} == "i32_r");
ASSERT_TRUE(std::string_view{rocblaslt_compute_type_string(rocblaslt_compute_f64)} == "f64_r");
ASSERT_TRUE(std::string_view{rocblaslt_compute_type_string(rocblaslt_compute_f32_fast_f16)}
== "f32_f16_r");
ASSERT_TRUE(std::string_view{rocblaslt_compute_type_string(rocblaslt_compute_f32_fast_bf16)}
== "f32_bf16_r");
ASSERT_TRUE(std::string_view{rocblaslt_compute_type_string(rocblaslt_compute_f32_fast_f8)}
== "f32_f8_r");
ASSERT_TRUE(std::string_view{rocblaslt_compute_type_string(rocblaslt_compute_f32_fast_f8_fnuz)}
== "f32_f8_fnuz_r");
ASSERT_TRUE(std::string_view{rocblaslt_compute_type_string(rocblaslt_compute_f32_fast_bf8)}
== "f32_bf8_fnuz_r");
ASSERT_TRUE(std::string_view{rocblaslt_compute_type_string(rocblaslt_compute_f32_fast_bf8_fnuz)}
== "f32_bf8_r");
ASSERT_TRUE(std::string_view{rocblaslt_compute_type_string(rocblaslt_compute_f32_fast_f8bf8)}
== "f32_f8bf8_r");
ASSERT_TRUE(
std::string_view{rocblaslt_compute_type_string(rocblaslt_compute_f32_fast_f8bf8_fnuz)}
== "f32_f8bf8_fnuz_r");
ASSERT_TRUE(std::string_view{rocblaslt_compute_type_string(rocblaslt_compute_f32_fast_bf8f8)}
== "f32_bf8f8_r");
ASSERT_TRUE(
std::string_view{rocblaslt_compute_type_string(rocblaslt_compute_f32_fast_bf8f8_fnuz)}
== "f32_bf8f8_fnuz_r");
ASSERT_TRUE(
std::string_view{rocblaslt_compute_type_string(static_cast<rocblaslt_compute_type>(999))}
== "invalidType");
// Test rocblaslt_matrix_layout_to_string function
// Create test matrix layout structures
_rocblaslt_matrix_layout mat1, mat2, mat3, mat4;
// Test case 1: Single batch matrix (batch_count <= 1)
mat1.type = HIP_R_32F;
mat1.m = 128;
mat1.n = 256;
mat1.ld = 128;
mat1.batch_count = 1;
mat1.batch_stride = 0;
std::string mat1_result = rocblaslt_matrix_layout_to_string(&mat1);
ASSERT_TRUE(!mat1_result.empty());
ASSERT_TRUE(mat1_result.find("[type=R_32F") != std::string::npos);
ASSERT_TRUE(mat1_result.find("rows=128") != std::string::npos);
ASSERT_TRUE(mat1_result.find("cols=256") != std::string::npos);
ASSERT_TRUE(mat1_result.find("ld=128") != std::string::npos);
// Should NOT contain batch_count and batch_stride for single batch
ASSERT_TRUE(mat1_result.find("batch_count") == std::string::npos);
ASSERT_TRUE(mat1_result.find("batch_stride") == std::string::npos);
// Test case 2: Batch matrix (batch_count > 1)
mat2.type = HIP_R_16F;
mat2.m = 64;
mat2.n = 128;
mat2.ld = 64;
mat2.batch_count = 4;
mat2.batch_stride = 8192;
std::string mat2_result = rocblaslt_matrix_layout_to_string(&mat2);
ASSERT_TRUE(!mat2_result.empty());
ASSERT_TRUE(mat2_result.find("[type=R_16F") != std::string::npos);
ASSERT_TRUE(mat2_result.find("rows=64") != std::string::npos);
ASSERT_TRUE(mat2_result.find("cols=128") != std::string::npos);
ASSERT_TRUE(mat2_result.find("ld=64") != std::string::npos);
// Should contain batch_count and batch_stride for batch matrix
ASSERT_TRUE(mat2_result.find("batch_count=4") != std::string::npos);
ASSERT_TRUE(mat2_result.find("batch_stride=8192") != std::string::npos);
// Test case 3: Zero batch count
mat3.type = HIP_R_64F;
mat3.m = 32;
mat3.n = 64;
mat3.ld = 32;
mat3.batch_count = 0;
mat3.batch_stride = 0;
std::string mat3_result = rocblaslt_matrix_layout_to_string(&mat3);
ASSERT_TRUE(!mat3_result.empty());
ASSERT_TRUE(mat3_result.find("[type=R_64F") != std::string::npos);
ASSERT_TRUE(mat3_result.find("rows=32") != std::string::npos);
ASSERT_TRUE(mat3_result.find("cols=64") != std::string::npos);
ASSERT_TRUE(mat3_result.find("ld=32") != std::string::npos);
// batch_count <= 1, so should NOT contain batch info
ASSERT_TRUE(mat3_result.find("batch_count") == std::string::npos);
ASSERT_TRUE(mat3_result.find("batch_stride") == std::string::npos);
// Test case 4: Different data types
mat4.type = HIP_R_8F_E4M3_FNUZ;
mat4.m = 16;
mat4.n = 32;
mat4.ld = 16;
mat4.batch_count = 8;
mat4.batch_stride = 512;
std::string mat4_result = rocblaslt_matrix_layout_to_string(&mat4);
ASSERT_TRUE(!mat4_result.empty());
ASSERT_TRUE(mat4_result.find("[type=R_8F_E4M3_FNUZ") != std::string::npos);
ASSERT_TRUE(mat4_result.find("rows=16") != std::string::npos);
ASSERT_TRUE(mat4_result.find("cols=32") != std::string::npos);
ASSERT_TRUE(mat4_result.find("ld=16") != std::string::npos);
ASSERT_TRUE(mat4_result.find("batch_count=8") != std::string::npos);
ASSERT_TRUE(mat4_result.find("batch_stride=512") != std::string::npos);
// Test format consistency - all results should start with '[' and end with ']'
ASSERT_TRUE(mat1_result.front() == '[' && mat1_result.back() == ']');
ASSERT_TRUE(mat2_result.front() == '[' && mat2_result.back() == ']');
ASSERT_TRUE(mat3_result.front() == '[' && mat3_result.back() == ']');
ASSERT_TRUE(mat4_result.front() == '[' && mat4_result.back() == ']');
// Test edge case: Large dimensions
_rocblaslt_matrix_layout mat_large;
mat_large.type = HIP_R_16BF;
mat_large.m = 4096;
mat_large.n = 8192;
mat_large.ld = 4096;
mat_large.batch_count = 16;
mat_large.batch_stride = 33554432; // 4096 * 8192
std::string result_large = rocblaslt_matrix_layout_to_string(&mat_large);
ASSERT_TRUE(!result_large.empty());
ASSERT_TRUE(result_large.find("rows=4096") != std::string::npos);
ASSERT_TRUE(result_large.find("cols=8192") != std::string::npos);
ASSERT_TRUE(result_large.find("batch_count=16") != std::string::npos);
ASSERT_TRUE(result_large.find("batch_stride=33554432") != std::string::npos);
// Test rocblaslt_matmul_desc_to_string function
// Create test matmul descriptor structures
_rocblaslt_matmul_desc desc1, desc2, desc3, desc4;
// Test case 1: No bias, no epilogue extension (simplest case)
desc1.compute_type = rocblaslt_compute_f32;
desc1.scale_type = HIP_R_32F;
desc1.op_A = HIPBLAS_OP_N;
desc1.op_B = HIPBLAS_OP_T;
desc1.epilogue = ROCBLASLT_EPILOGUE_DEFAULT;
desc1.bias = nullptr;
desc1.bias_type = HIPBLASLT_DATATYPE_INVALID;
desc1.aux_type = HIPBLASLT_DATATYPE_INVALID;
desc1.e = nullptr;
desc1.lde = 0;
std::string desc_result1 = rocblaslt_matmul_desc_to_string(&desc1);
ASSERT_TRUE(!desc_result1.empty());
ASSERT_TRUE(desc_result1.find("[computeType=COMPUTE_32F") != std::string::npos);
ASSERT_TRUE(desc_result1.find("scaleType=R_32F") != std::string::npos);
ASSERT_TRUE(desc_result1.find("transA=OP_N") != std::string::npos);
ASSERT_TRUE(desc_result1.find("transB=OP_T") != std::string::npos);
ASSERT_TRUE(desc_result1.find("epilogue=EPILOGUE_DEFAULT") != std::string::npos);
ASSERT_TRUE(desc_result1.find("biasPointer=0x") != std::string::npos);
// Should NOT contain epilogue aux or bias type info
ASSERT_TRUE(desc_result1.find("epilogueAuxPointer") == std::string::npos);
ASSERT_TRUE(desc_result1.find("biasType") == std::string::npos);
ASSERT_TRUE(desc_result1.front() == '[' && desc_result1.back() == ']');
// Test case 2: With bias, no epilogue extension
desc2.compute_type = rocblaslt_compute_f16;
desc2.scale_type = HIP_R_16F;
desc2.op_A = HIPBLAS_OP_T;
desc2.op_B = HIPBLAS_OP_N;
desc2.epilogue = ROCBLASLT_EPILOGUE_BIAS;
desc2.bias = reinterpret_cast<void*>(0x12345678);
desc2.bias_type = HIP_R_16F;
desc2.aux_type = HIPBLASLT_DATATYPE_INVALID;
desc2.e = nullptr;
desc2.lde = 0;
std::string desc_result2 = rocblaslt_matmul_desc_to_string(&desc2);
ASSERT_TRUE(!desc_result2.empty());
ASSERT_TRUE(desc_result2.find("computeType=COMPUTE_16F") != std::string::npos);
ASSERT_TRUE(desc_result2.find("scaleType=R_16F") != std::string::npos);
ASSERT_TRUE(desc_result2.find("transA=OP_T") != std::string::npos);
ASSERT_TRUE(desc_result2.find("transB=OP_N") != std::string::npos);
ASSERT_TRUE(desc_result2.find("epilogue=EPILOGUE_BIAS") != std::string::npos);
ASSERT_TRUE(desc_result2.find("biasType=R_16F") != std::string::npos);
// Should NOT contain epilogue aux info
ASSERT_TRUE(desc_result2.find("epilogueAuxPointer") == std::string::npos);
ASSERT_TRUE(desc_result2.front() == '[' && desc_result2.back() == ']');
// Test case 3: No bias, with epilogue extension
desc3.compute_type = rocblaslt_compute_f32;
desc3.scale_type = HIP_R_32F;
desc3.op_A = HIPBLAS_OP_N;
desc3.op_B = HIPBLAS_OP_N;
desc3.epilogue = ROCBLASLT_EPILOGUE_GELU_AUX;
desc3.bias = nullptr;
desc3.bias_type = HIPBLASLT_DATATYPE_INVALID;
desc3.aux_type = HIP_R_32F;
desc3.e = reinterpret_cast<void*>(0x87654321);
desc3.lde = 128;
std::string desc_result3 = rocblaslt_matmul_desc_to_string(&desc3);
ASSERT_TRUE(!desc_result3.empty());
ASSERT_TRUE(desc_result3.find("computeType=COMPUTE_32F") != std::string::npos);
ASSERT_TRUE(desc_result3.find("epilogue=EPILOGUE_GELU_AUX") != std::string::npos);
ASSERT_TRUE(desc_result3.find("epilogueAuxPointer=0x") != std::string::npos);
ASSERT_TRUE(desc_result3.find("epilogueAuxLd=128") != std::string::npos);
ASSERT_TRUE(desc_result3.find("epilogueAuxDataType=R_32F") != std::string::npos);
// Should NOT contain bias type info
ASSERT_TRUE(desc_result3.find("biasType") == std::string::npos);
ASSERT_TRUE(desc_result3.front() == '[' && desc_result3.back() == ']');
// Test case 4: With bias and epilogue extension (most complex case)
desc4.compute_type = rocblaslt_compute_f64;
desc4.scale_type = HIP_R_64F;
desc4.op_A = HIPBLAS_OP_C;
desc4.op_B = HIPBLAS_OP_C;
desc4.epilogue = ROCBLASLT_EPILOGUE_GELU_AUX_BIAS;
desc4.bias = reinterpret_cast<void*>(0xABCDEF00);
desc4.bias_type = HIP_R_64F;
desc4.aux_type = HIP_R_64F;
desc4.e = reinterpret_cast<void*>(0x11223344);
desc4.lde = 256;
std::string desc_result4 = rocblaslt_matmul_desc_to_string(&desc4);
ASSERT_TRUE(!desc_result4.empty());
ASSERT_TRUE(desc_result4.find("computeType=COMPUTE_64F") != std::string::npos);
ASSERT_TRUE(desc_result4.find("scaleType=R_64F") != std::string::npos);
ASSERT_TRUE(desc_result4.find("transA=OP_C") != std::string::npos);
ASSERT_TRUE(desc_result4.find("transB=OP_C") != std::string::npos);
ASSERT_TRUE(desc_result4.find("epilogue=EPILOGUE_GELU_AUX_BIAS") != std::string::npos);
ASSERT_TRUE(desc_result4.find("biasType=R_64F") != std::string::npos);
ASSERT_TRUE(desc_result4.find("epilogueAuxPointer=0x") != std::string::npos);
ASSERT_TRUE(desc_result4.find("epilogueAuxLd=256") != std::string::npos);
ASSERT_TRUE(desc_result4.find("epilogueAuxDataType=R_64F") != std::string::npos);
ASSERT_TRUE(desc_result4.front() == '[' && desc_result4.back() == ']');
// Test case 5: Epilogue extension without aux_type
_rocblaslt_matmul_desc desc5;
desc5.compute_type = rocblaslt_compute_i32;
desc5.scale_type = HIP_R_32I;
desc5.op_A = HIPBLAS_OP_N;
desc5.op_B = HIPBLAS_OP_N;
desc5.epilogue = ROCBLASLT_EPILOGUE_DGELU_BGRAD;
desc5.bias = nullptr;
desc5.bias_type = HIPBLASLT_DATATYPE_INVALID;
desc5.aux_type = HIPBLASLT_DATATYPE_INVALID; // Invalid aux type
desc5.e = reinterpret_cast<void*>(0x55555555);
desc5.lde = 64;
std::string desc_result5 = rocblaslt_matmul_desc_to_string(&desc5);
ASSERT_TRUE(!desc_result5.empty());
ASSERT_TRUE(desc_result5.find("computeType=COMPUTE_32I") != std::string::npos);
ASSERT_TRUE(desc_result5.find("epilogue=EPILOGUE_DGELU_BGRAD") != std::string::npos);
ASSERT_TRUE(desc_result5.find("epilogueAuxPointer=0x") != std::string::npos);
ASSERT_TRUE(desc_result5.find("epilogueAuxLd=64") != std::string::npos);
// Should NOT contain epilogueAuxDataType since aux_type is invalid
ASSERT_TRUE(desc_result5.find("epilogueAuxDataType") == std::string::npos);
ASSERT_TRUE(desc_result5.front() == '[' && desc_result5.back() == ']');
// Test case 6: Epilogue extension without aux_type
_rocblaslt_matmul_desc desc6;
desc6.compute_type = rocblaslt_compute_i32;
desc6.scale_type = HIP_R_32I;
desc6.op_A = HIPBLAS_OP_N;
desc6.op_B = HIPBLAS_OP_N;
desc6.epilogue = ROCBLASLT_EPILOGUE_DRELU_BGRAD;
desc6.bias = nullptr;
desc6.bias_type = HIPBLASLT_DATATYPE_INVALID;
desc6.aux_type = HIPBLASLT_DATATYPE_INVALID; // Invalid aux type
desc6.e = reinterpret_cast<void*>(0x55555555);
desc6.lde = 64;
std::string desc_result6 = rocblaslt_matmul_desc_to_string(&desc6);
ASSERT_TRUE(!desc_result6.empty());
ASSERT_TRUE(desc_result6.find("computeType=COMPUTE_32I") != std::string::npos);
ASSERT_TRUE(desc_result6.find("epilogue=EPILOGUE_DRELU_BGRAD") != std::string::npos);
ASSERT_TRUE(desc_result6.find("epilogueAuxPointer=0x") != std::string::npos);
ASSERT_TRUE(desc_result6.find("epilogueAuxLd=64") != std::string::npos);
// Should NOT contain epilogueAuxDataType since aux_type is invalid
ASSERT_TRUE(desc_result6.find("epilogueAuxDataType") == std::string::npos);
ASSERT_TRUE(desc_result6.front() == '[' && desc_result6.back() == ']');
// Test different data types
_rocblaslt_matmul_desc desc7;
desc7.compute_type = rocblaslt_compute_f32_fast_bf16;
desc7.scale_type = HIP_R_16BF;
desc7.op_A = HIPBLAS_OP_N;
desc7.op_B = HIPBLAS_OP_T;
desc7.epilogue = ROCBLASLT_EPILOGUE_RELU_BIAS;
desc7.bias = reinterpret_cast<void*>(0x99999999);
desc7.bias_type = HIP_R_8F_E4M3_FNUZ;
desc7.aux_type = HIPBLASLT_DATATYPE_INVALID;
desc7.e = nullptr;
desc7.lde = 0;
std::string desc_result7 = rocblaslt_matmul_desc_to_string(&desc7);
ASSERT_TRUE(!desc_result7.empty());
ASSERT_TRUE(desc_result7.find("computeType=COMPUTE_32F_16BF") != std::string::npos);
ASSERT_TRUE(desc_result7.find("scaleType=R_16BF") != std::string::npos);
ASSERT_TRUE(desc_result7.find("epilogue=EPILOGUE_RELU_BIAS") != std::string::npos);
ASSERT_TRUE(desc_result7.find("biasType=R_8F_E4M3_FNUZ") != std::string::npos);
ASSERT_TRUE(desc_result7.front() == '[' && desc_result7.back() == ']');
// Test case 1: No exception (nullptr) - should return success
rocblaslt_status excep_result1 = exception_to_rocblaslt_status(nullptr);
ASSERT_TRUE(excep_result1 == rocblaslt_status_success);
// Test case 2: Catch rocblaslt_status exception - should return the status value
std::exception_ptr status_exception;
try
{
throw rocblaslt_status_invalid_handle;
}
catch(...)
{
status_exception = std::current_exception();
}
rocblaslt_status excep_result2 = exception_to_rocblaslt_status(status_exception);
ASSERT_TRUE(excep_result2 == rocblaslt_status_invalid_handle);
// Test case 3: Different rocblaslt_status values
std::exception_ptr status_exception2;
try
{
throw rocblaslt_status_not_initialized;
}
catch(...)
{
status_exception2 = std::current_exception();
}
rocblaslt_status excep_result3 = exception_to_rocblaslt_status(status_exception2);
ASSERT_TRUE(excep_result3 == rocblaslt_status_not_initialized);
// Test case 4: Catch std::bad_alloc - should return memory error
std::exception_ptr bad_alloc_exception;
try
{
throw std::bad_alloc();
}
catch(...)
{
bad_alloc_exception = std::current_exception();
}
rocblaslt_status excep_result4 = exception_to_rocblaslt_status(bad_alloc_exception);
ASSERT_TRUE(excep_result4 == rocblaslt_status_memory_error);
// Test all epilogue values that should return true (activation enabled)
ASSERT_TRUE(is_act_enabled(ROCBLASLT_EPILOGUE_RELU) == true);
ASSERT_TRUE(is_act_enabled(ROCBLASLT_EPILOGUE_RELU_BIAS) == true);
ASSERT_TRUE(is_act_enabled(ROCBLASLT_EPILOGUE_GELU) == true);
ASSERT_TRUE(is_act_enabled(ROCBLASLT_EPILOGUE_GELU_BIAS) == true);
ASSERT_TRUE(is_act_enabled(ROCBLASLT_EPILOGUE_GELU_AUX) == true);
ASSERT_TRUE(is_act_enabled(ROCBLASLT_EPILOGUE_GELU_AUX_BIAS) == true);
ASSERT_TRUE(is_act_enabled(ROCBLASLT_EPILOGUE_DGELU) == true);
ASSERT_TRUE(is_act_enabled(ROCBLASLT_EPILOGUE_DGELU_BGRAD) == true);
ASSERT_TRUE(is_act_enabled(ROCBLASLT_EPILOGUE_DRELU) == true);
ASSERT_TRUE(is_act_enabled(ROCBLASLT_EPILOGUE_DRELU_BGRAD) == true);
ASSERT_TRUE(is_act_enabled(ROCBLASLT_EPILOGUE_SWISH_EXT) == true);
ASSERT_TRUE(is_act_enabled(ROCBLASLT_EPILOGUE_SWISH_BIAS_EXT) == true);
ASSERT_TRUE(is_act_enabled(ROCBLASLT_EPILOGUE_CLAMP_EXT) == true);
ASSERT_TRUE(is_act_enabled(ROCBLASLT_EPILOGUE_CLAMP_BIAS_EXT) == true);
// Test all epilogue values that should return false (activation disabled)
ASSERT_TRUE(is_act_enabled(ROCBLASLT_EPILOGUE_DEFAULT) == false);
ASSERT_TRUE(is_act_enabled(ROCBLASLT_EPILOGUE_BIAS) == false);
}
inline void testing_aux_status_func(const Arguments& arg)
{
// Test get_rocblaslt_status_for_hip_status function
ASSERT_TRUE(get_rocblaslt_status_for_hip_status(hipSuccess) == rocblaslt_status_success);
ASSERT_TRUE(get_rocblaslt_status_for_hip_status(hipErrorMemoryAllocation)
== rocblaslt_status_memory_error);
ASSERT_TRUE(get_rocblaslt_status_for_hip_status(hipErrorLaunchOutOfResources)
== rocblaslt_status_memory_error);
ASSERT_TRUE(get_rocblaslt_status_for_hip_status(hipErrorInvalidDevicePointer)
== rocblaslt_status_invalid_pointer);
ASSERT_TRUE(get_rocblaslt_status_for_hip_status(hipErrorInvalidDevice)
== rocblaslt_status_invalid_handle);
ASSERT_TRUE(get_rocblaslt_status_for_hip_status(hipErrorInvalidResourceHandle)
== rocblaslt_status_invalid_handle);
ASSERT_TRUE(get_rocblaslt_status_for_hip_status(hipErrorInvalidValue)
== rocblaslt_status_internal_error);
ASSERT_TRUE(get_rocblaslt_status_for_hip_status(hipErrorNoDevice)
== rocblaslt_status_internal_error);
ASSERT_TRUE(get_rocblaslt_status_for_hip_status(hipErrorUnknown)
== rocblaslt_status_internal_error);
// Test default case with unknown/unmapped hip errors -> rocblaslt_status_internal_error
ASSERT_TRUE(get_rocblaslt_status_for_hip_status(static_cast<hipError_t>(999))
== rocblaslt_status_internal_error);
}
inline void testing_aux_hipblaslt_func(const Arguments& arg)
{
// Test RocBlasLtStatusToHIPStatus
ASSERT_TRUE(RocBlasLtStatusToHIPStatus(rocblaslt_status_success) == HIPBLAS_STATUS_SUCCESS);
ASSERT_TRUE(RocBlasLtStatusToHIPStatus(rocblaslt_status_invalid_handle)
== HIPBLAS_STATUS_NOT_INITIALIZED);
ASSERT_TRUE(RocBlasLtStatusToHIPStatus(rocblaslt_status_not_implemented)
== HIPBLAS_STATUS_INTERNAL_ERROR);
ASSERT_TRUE(RocBlasLtStatusToHIPStatus(rocblaslt_status_invalid_pointer)
== HIPBLAS_STATUS_INVALID_VALUE);
ASSERT_TRUE(RocBlasLtStatusToHIPStatus(rocblaslt_status_invalid_size)
== HIPBLAS_STATUS_INVALID_VALUE);
ASSERT_TRUE(RocBlasLtStatusToHIPStatus(rocblaslt_status_memory_error)
== HIPBLAS_STATUS_ALLOC_FAILED);
ASSERT_TRUE(RocBlasLtStatusToHIPStatus(rocblaslt_status_internal_error)
== HIPBLAS_STATUS_INTERNAL_ERROR);
ASSERT_TRUE(RocBlasLtStatusToHIPStatus(rocblaslt_status_invalid_value)
== HIPBLAS_STATUS_INVALID_VALUE);
ASSERT_TRUE(RocBlasLtStatusToHIPStatus(rocblaslt_status_arch_mismatch)
== HIPBLAS_STATUS_ARCH_MISMATCH);
// Test default case - should throw HIPBLAS_STATUS_INVALID_ENUM
bool exception_thrown = false;
hipblasStatus_t thrown_status = HIPBLAS_STATUS_SUCCESS;
try
{
RocBlasLtStatusToHIPStatus(static_cast<rocblaslt_status_>(999));
}
catch(hipblasStatus_t status)
{
exception_thrown = true;
thrown_status = status;
}
catch(...)
{
exception_thrown = true;
thrown_status = HIPBLAS_STATUS_INTERNAL_ERROR; // Unexpected exception type
}
ASSERT_TRUE(exception_thrown);
ASSERT_TRUE(thrown_status == HIPBLAS_STATUS_INVALID_ENUM);
// Test hipblasLtMatrixTransformDescSetAttribute function
hipblasLtMatrixTransformDesc_t transformDesc;
CHECK_HIPBLASLT_ERROR(hipblasLtMatrixTransformDescCreate(&transformDesc, HIP_R_32F));
// Test SCALE_TYPE attribute
hipDataType scaleDatatype{HIP_R_16F};
ASSERT_TRUE(hipblasLtMatrixTransformDescSetAttribute(transformDesc,
HIPBLASLT_MATRIX_TRANSFORM_DESC_SCALE_TYPE,
&scaleDatatype,
sizeof(scaleDatatype))
== HIPBLAS_STATUS_SUCCESS);
// Test POINTER_MODE attribute
hipblasLtPointerMode_t pointerMode{HIPBLASLT_POINTER_MODE_DEVICE};
ASSERT_TRUE(
hipblasLtMatrixTransformDescSetAttribute(transformDesc,
HIPBLASLT_MATRIX_TRANSFORM_DESC_POINTER_MODE,
&pointerMode,
sizeof(pointerMode))
== HIPBLAS_STATUS_SUCCESS);
// Test TRANSA attribute
hipblasOperation_t transA{HIPBLAS_OP_T};
ASSERT_TRUE(hipblasLtMatrixTransformDescSetAttribute(
transformDesc, HIPBLASLT_MATRIX_TRANSFORM_DESC_TRANSA, &transA, sizeof(transA))
== HIPBLAS_STATUS_SUCCESS);
// Test TRANSB attribute
hipblasOperation_t transB{HIPBLAS_OP_C};
ASSERT_TRUE(hipblasLtMatrixTransformDescSetAttribute(
transformDesc, HIPBLASLT_MATRIX_TRANSFORM_DESC_TRANSB, &transB, sizeof(transB))
== HIPBLAS_STATUS_SUCCESS);
// Test invalid buffer (nullptr)
ASSERT_TRUE(
hipblasLtMatrixTransformDescSetAttribute(
transformDesc, HIPBLASLT_MATRIX_TRANSFORM_DESC_SCALE_TYPE, nullptr, sizeof(hipDataType))
== HIPBLAS_STATUS_INVALID_VALUE);
// Test invalid size
ASSERT_TRUE(hipblasLtMatrixTransformDescSetAttribute(transformDesc,
HIPBLASLT_MATRIX_TRANSFORM_DESC_SCALE_TYPE,
&scaleDatatype,
sizeof(int16_t))
== HIPBLAS_STATUS_INVALID_VALUE);
// Test SCALE_TYPE attribute get
int32_t retrievedScaleType;
size_t sizeWritten;
ASSERT_TRUE(hipblasLtMatrixTransformDescGetAttribute(transformDesc,
HIPBLASLT_MATRIX_TRANSFORM_DESC_SCALE_TYPE,
&retrievedScaleType,
sizeof(retrievedScaleType),
&sizeWritten)
== HIPBLAS_STATUS_SUCCESS);
ASSERT_TRUE(static_cast<hipDataType>(retrievedScaleType) == HIP_R_16F);
ASSERT_TRUE(sizeWritten == sizeof(int32_t));
// Test POINTER_MODE attribute get
int32_t retrievedPointerMode;
ASSERT_TRUE(
hipblasLtMatrixTransformDescGetAttribute(transformDesc,
HIPBLASLT_MATRIX_TRANSFORM_DESC_POINTER_MODE,
&retrievedPointerMode,
sizeof(retrievedPointerMode),
&sizeWritten)
== HIPBLAS_STATUS_SUCCESS);
ASSERT_TRUE(static_cast<hipblasLtPointerMode_t>(retrievedPointerMode)
== HIPBLASLT_POINTER_MODE_DEVICE);
ASSERT_TRUE(sizeWritten == sizeof(int32_t));
// Test TRANSA attribute get
int32_t retrievedTransA;
ASSERT_TRUE(hipblasLtMatrixTransformDescGetAttribute(transformDesc,
HIPBLASLT_MATRIX_TRANSFORM_DESC_TRANSA,
&retrievedTransA,
sizeof(retrievedTransA),
&sizeWritten)
== HIPBLAS_STATUS_SUCCESS);
ASSERT_TRUE(static_cast<hipblasOperation_t>(retrievedTransA) == HIPBLAS_OP_T);
ASSERT_TRUE(sizeWritten == sizeof(int32_t));
// Test TRANSB attribute get
int32_t retrievedTransB;
ASSERT_TRUE(hipblasLtMatrixTransformDescGetAttribute(transformDesc,
HIPBLASLT_MATRIX_TRANSFORM_DESC_TRANSB,
&retrievedTransB,
sizeof(retrievedTransB),
&sizeWritten)
== HIPBLAS_STATUS_SUCCESS);
ASSERT_TRUE(static_cast<hipblasOperation_t>(retrievedTransB) == HIPBLAS_OP_C);
ASSERT_TRUE(sizeWritten == sizeof(int32_t));
// Test error cases: both sizeInBytes and sizeWritten are 0/nullptr
ASSERT_TRUE(hipblasLtMatrixTransformDescGetAttribute(transformDesc,
HIPBLASLT_MATRIX_TRANSFORM_DESC_SCALE_TYPE,
&retrievedScaleType,
0,
nullptr)
== HIPBLAS_STATUS_INVALID_VALUE);
// Test error case: sizeInBytes provided but sizeWritten is nullptr
ASSERT_TRUE(hipblasLtMatrixTransformDescGetAttribute(transformDesc,
HIPBLASLT_MATRIX_TRANSFORM_DESC_SCALE_TYPE,
&retrievedScaleType,
sizeof(retrievedScaleType),
nullptr)
== HIPBLAS_STATUS_INVALID_VALUE);
// Test error case: invalid size (not sizeof(int32_t))
ASSERT_TRUE(hipblasLtMatrixTransformDescGetAttribute(transformDesc,
HIPBLASLT_MATRIX_TRANSFORM_DESC_SCALE_TYPE,
&retrievedScaleType,
sizeof(int16_t),
&sizeWritten)
== HIPBLAS_STATUS_INVALID_VALUE);
// Test error case: invalid attribute (using default case)
ASSERT_TRUE(hipblasLtMatrixTransformDescGetAttribute(
transformDesc,
static_cast<hipblasLtMatrixTransformDescAttributes_t>(999),
&retrievedScaleType,
sizeof(retrievedScaleType),
&sizeWritten)
== HIPBLAS_STATUS_INVALID_VALUE);
CHECK_HIPBLASLT_ERROR(hipblasLtMatrixTransformDescDestroy(transformDesc));
}
inline void testing_aux_tensile_host_func(const Arguments& arg)
{
// Test hipDataType_to_tensile_type function
ASSERT_TRUE(hipDataType_to_tensile_type(HIP_R_16F) == rocisa::DataType::Half);
ASSERT_TRUE(hipDataType_to_tensile_type(HIP_R_32F) == rocisa::DataType::Float);
ASSERT_TRUE(hipDataType_to_tensile_type(HIP_R_64F) == rocisa::DataType::Double);
ASSERT_TRUE(hipDataType_to_tensile_type(HIP_R_16BF) == rocisa::DataType::BFloat16);
ASSERT_TRUE(hipDataType_to_tensile_type(HIP_R_8F_E4M3_FNUZ) == rocisa::DataType::Float8_fnuz);
ASSERT_TRUE(hipDataType_to_tensile_type(HIP_R_8F_E5M2_FNUZ) == rocisa::DataType::BFloat8_fnuz);
ASSERT_TRUE(hipDataType_to_tensile_type(HIP_R_8F_E4M3) == rocisa::DataType::Float8);
ASSERT_TRUE(hipDataType_to_tensile_type(HIP_R_8F_E5M2) == rocisa::DataType::BFloat8);
ASSERT_TRUE(hipDataType_to_tensile_type(HIP_R_8I) == rocisa::DataType::Int8);
ASSERT_TRUE(hipDataType_to_tensile_type(HIP_R_32I) == rocisa::DataType::Int32);
// Test rocComputeType_to_tensile_type function
ASSERT_TRUE(rocComputeType_to_tensile_type(rocblaslt_compute_f32_fast_xf32)
== rocisa::DataType::XFloat32);
ASSERT_TRUE(rocComputeType_to_tensile_type(rocblaslt_compute_f32_fast_f16)
== rocisa::DataType::Float);
ASSERT_TRUE(rocComputeType_to_tensile_type(rocblaslt_compute_f32_fast_bf16)
== rocisa::DataType::Float);
ASSERT_TRUE(rocComputeType_to_tensile_type(rocblaslt_compute_f16) == rocisa::DataType::Float);
ASSERT_TRUE(rocComputeType_to_tensile_type(rocblaslt_compute_f32) == rocisa::DataType::Float);
ASSERT_TRUE(rocComputeType_to_tensile_type(rocblaslt_compute_f32_fast_f8_fnuz)
== rocisa::DataType::Float);
ASSERT_TRUE(rocComputeType_to_tensile_type(rocblaslt_compute_f32_fast_bf8_fnuz)
== rocisa::DataType::Float);
ASSERT_TRUE(rocComputeType_to_tensile_type(rocblaslt_compute_f32_fast_f8bf8_fnuz)
== rocisa::DataType::Float);
ASSERT_TRUE(rocComputeType_to_tensile_type(rocblaslt_compute_f32_fast_bf8f8_fnuz)
== rocisa::DataType::Float);
ASSERT_TRUE(rocComputeType_to_tensile_type(rocblaslt_compute_f32_fast_f8)
== rocisa::DataType::Float);
ASSERT_TRUE(rocComputeType_to_tensile_type(rocblaslt_compute_f32_fast_bf8)
== rocisa::DataType::Float);
ASSERT_TRUE(rocComputeType_to_tensile_type(rocblaslt_compute_f32_fast_f8bf8)
== rocisa::DataType::Float);
ASSERT_TRUE(rocComputeType_to_tensile_type(rocblaslt_compute_f32_fast_bf8f8)
== rocisa::DataType::Float);
ASSERT_TRUE(rocComputeType_to_tensile_type(rocblaslt_compute_f64) == rocisa::DataType::Double);
ASSERT_TRUE(rocComputeType_to_tensile_type(rocblaslt_compute_i32) == rocisa::DataType::Int32);
}
inline void testing_aux_tuple_helper_equal_func(const Arguments& arg)
{
// Test tuple_helper equal functionality
// Test basic integer equality
auto tuple1 = std::make_tuple("key1", 42, "key2", 100);
auto tuple2 = std::make_tuple("key1", 42, "key2", 100);
auto tuple3 = std::make_tuple("key1", 42, "key2", 99);
tuple_helper::equal_t<decltype(tuple1)> equal_checker;
// Test equal tuples
ASSERT_TRUE(equal_checker(tuple1, tuple2));
// Test unequal tuples (different values)
ASSERT_FALSE(equal_checker(tuple1, tuple3));
// Test C-string equality
auto str_tuple1 = std::make_tuple("name", "test", "value", "data");
auto str_tuple2 = std::make_tuple("name", "test", "value", "data");
auto str_tuple3 = std::make_tuple("name", "test", "value", "different");
tuple_helper::equal_t<decltype(str_tuple1)> str_equal_checker;
// Test equal C-string tuples
ASSERT_TRUE(str_equal_checker(str_tuple1, str_tuple2));
// Test unequal C-string tuples
ASSERT_FALSE(str_equal_checker(str_tuple1, str_tuple3));
}
#ifdef HIPBLASLT_USE_ROCROLLER
inline void testing_aux_rocblaslt_rocroller_host_func(const Arguments& arg)
{
hipblasLtHandle_t handle;
CHECK_HIPBLASLT_ERROR(hipblasLtCreate(&handle));
hipblasLtMatmulDesc_t matmul;
CHECK_HIPBLASLT_ERROR(hipblasLtMatmulDescCreate(&matmul, arg.compute_type, arg.scale_type));
hipblasOperation_t opA = HIPBLAS_OP_T;
hipblasOperation_t opB = HIPBLAS_OP_N;
int64_t m = 1;
int64_t n = 1;
int64_t k = 1;
float alpha_v = arg.alpha;
void* alpha = &alpha_v;
float beta_v = arg.beta;
void* beta = &beta_v;
int64_t lda = 1;
int64_t ldb = 1;
int64_t ldc = 1;
int64_t ldd = 1;
int64_t lde = 1;
hipStream_t stream;
CHECK_HIP_ERROR(hipStreamCreate(&stream));
hipblasLtMatrixLayout_t matA, matB, matC, matD;
CHECK_HIPBLASLT_ERROR(hipblasLtMatrixLayoutCreate(&matA, arg.a_type, m, k, m));
CHECK_HIPBLASLT_ERROR(hipblasLtMatrixLayoutCreate(&matB, arg.a_type, k, n, k));
CHECK_HIPBLASLT_ERROR(hipblasLtMatrixLayoutCreate(&matC, arg.a_type, m, n, m));
CHECK_HIPBLASLT_ERROR(hipblasLtMatrixLayoutCreate(&matD, arg.a_type, m, n, m));
hipDataType a_type, b_type, c_type, d_type;
const int request_solutions = 1;
hipblasLtMatmulHeuristicResult_t heuristicResult[request_solutions];
int returnedAlgoCount = 0;
size_t max_workspace_size = 128 * 1024 * 1024;
hipblasLtMatmulPreference_t pref;
CHECK_HIPBLASLT_ERROR(hipblasLtMatmulPreferenceCreate(&pref));
CHECK_HIPBLASLT_ERROR(
hipblasLtMatmulPreferenceSetAttribute(pref,
HIPBLASLT_MATMUL_PREF_MAX_WORKSPACE_BYTES,
&max_workspace_size,
sizeof(max_workspace_size)));
void* d_workspace;
if(max_workspace_size > 0)
CHECK_HIP_ERROR(hipMalloc(&d_workspace, max_workspace_size));
CHECK_HIPBLASLT_ERROR(hipblasLtMatmulAlgoGetHeuristic(handle,
matmul,
matA,
matB,
matC,
matD,
pref,
request_solutions,
heuristicResult,
&returnedAlgoCount));
CHECK_SOLUTION_FOUND(returnedAlgoCount);
rocblaslt_matmul_desc matmul_descr = (rocblaslt_matmul_desc)matmul;
int64_t batch_count = 1;
void * A, *B, *C, *D, *E, *d_alphaVec; // device
CHECK_HIP_ERROR(hipMalloc(&A, m * k * batch_count * sizeof(int64_t)));
CHECK_HIP_ERROR(hipMalloc(&B, n * k * batch_count * sizeof(int64_t)));
CHECK_HIP_ERROR(hipMalloc(&C, m * n * batch_count * sizeof(int64_t)));
CHECK_HIP_ERROR(hipMalloc(&D, m * n * batch_count * sizeof(int64_t)));
CHECK_HIP_ERROR(hipMalloc(&E, m * n * batch_count * sizeof(int64_t)));
int64_t batch_stride_a = 0;
int64_t batch_stride_b = 0;
int64_t batch_stride_c = 0;
int64_t batch_stride_d = 0;
int64_t batch_stride_e = 0;
bool strided_batch = true;
bool grouped_gemm = true;
void* bias = nullptr;
hipDataType bias_type;
void* scaleAlphaVec = nullptr;
hipDataType aux_type;
bool gradient = false;
rocblaslt_compute_type compute_type;
rocblaslt_handle roc_handle = (rocblaslt_handle)handle;
hipblasLtBatchMode_t batchMode = HIPBLASLT_BATCH_MODE_STRIDED;
rocblaslt_status isValid = rocblaslt_matmul_valid_args(matmul_descr,
A,
B,
C,
D,
(rocblaslt_matrix_layout)matA,
(rocblaslt_matrix_layout)matB,
(rocblaslt_matrix_layout)matC,
(rocblaslt_matrix_layout)matD,
alpha,
beta,
m,
n,
k,
a_type,
lda,
batch_stride_a,
b_type,
ldb,
batch_stride_b,
c_type,
ldc,
batch_stride_c,
d_type,
ldd,
batch_stride_d,
lde,
batch_stride_e,
bias,
bias_type,
scaleAlphaVec,
E,
aux_type,
gradient,
compute_type,
false,
false);
ASSERT_TRUE(isValid == rocblaslt_status_continue);
RocblasltContractionProblem problem{opA,
opB,
m,
n,
k,
alpha,
a_type,
A, // A
nullptr,
lda, // arg.lda
batch_stride_a,
b_type,
B, // B
nullptr,
ldb, // arg.ldb
batch_stride_b,
beta,
c_type,
C, // C
nullptr,
ldc, // arg.ldc
batch_stride_c,
d_type,
D, // D
nullptr,
ldd, // arg.ldc
batch_stride_d,
E, // E
nullptr,
lde, //arg.lde
batch_stride_e,
batch_count,
strided_batch,
grouped_gemm,
gradient,
matmul_descr->compute_type,
HIPBLASLT_DATATYPE_INVALID,
bias,
matmul_descr->scaleA,
matmul_descr->scaleB,
matmul_descr->scaleC,
matmul_descr->scaleD,
matmul_descr->scaleE,
scaleAlphaVec,
matmul_descr->scaleAType,
matmul_descr->scaleBType,
arg.bias_type,
arg.aux_type,
matmul_descr->epilogue,
matmul_descr->amaxD,
nullptr,
max_workspace_size, // workspaceSize
HIPBLASLT_MATMUL_DESC_EPILOGUE_ACT_ARG0_EXT, // act0
HIPBLASLT_MATMUL_DESC_EPILOGUE_ACT_ARG1_EXT, // act1
stream, // stream
roc_handle->Synchronizer,
arg.swizzle_a, // swizzleA
arg.swizzle_b, // swizzleB
batchMode,
0}; // bias_stride
const hipblasLtMatmulAlgo_t* hip_algo = &heuristicResult[0].algo;
const rocblaslt_matmul_algo* roc_algo = (const rocblaslt_matmul_algo*)hip_algo;
ASSERT_TRUE(runRocRollerContractionProblem(roc_handle, nullptr, problem)
!= rocblaslt_status_success);
ASSERT_TRUE(runRocRollerContractionProblem(roc_handle, roc_algo, problem)
!= rocblaslt_status_success);
hipblasLtMatmulAlgo_t* hip_algo2 = &heuristicResult[0].algo;
rocblaslt_matmul_algo* roc_algo2 = (rocblaslt_matmul_algo*)hip_algo;
ASSERT_TRUE(isRocRollerSolutionSupported(roc_handle, problem, roc_algo2, &max_workspace_size)
!= rocblaslt_status_success);
// Free GPU memory allocations
CHECK_HIP_ERROR(hipFree(A));
CHECK_HIP_ERROR(hipFree(B));
CHECK_HIP_ERROR(hipFree(C));
CHECK_HIP_ERROR(hipFree(D));
CHECK_HIP_ERROR(hipFree(E));
// Free workspace
CHECK_HIP_ERROR(hipFree(d_workspace));
// Destroy preference object
CHECK_HIPBLASLT_ERROR(hipblasLtMatmulPreferenceDestroy(pref));
// Destroy handles
CHECK_HIPBLASLT_ERROR(hipblasLtMatmulDescDestroy(matmul));
CHECK_HIPBLASLT_ERROR(hipblasLtMatrixLayoutDestroy(matA));
CHECK_HIPBLASLT_ERROR(hipblasLtMatrixLayoutDestroy(matB));
CHECK_HIPBLASLT_ERROR(hipblasLtMatrixLayoutDestroy(matC));
CHECK_HIPBLASLT_ERROR(hipblasLtMatrixLayoutDestroy(matD));
CHECK_HIPBLASLT_ERROR(hipblasLtDestroy(handle));
CHECK_HIP_ERROR(hipStreamDestroy(stream));
}
#endif // HIPBLASLT_USE_ROCROLLER
// Coverage for the post-GEMM HIPBLASLT_CHECK_NUMERICS scanner: env-var parsing,
// public drain API, and the happy-path NaN detection round-trip.
inline void testing_aux_check_numerics_func(const Arguments& arg)
{
// setenv/unsetenv are not thread-safe; serialize the body so concurrent
// RUN_TEST_ON_THREADS_STREAMS threads can't interleave env mutations with
// hipblasLtCreate() reads of those vars.
static std::mutex env_mutex;
std::lock_guard<std::mutex> env_lock(env_mutex);
auto reset_env = []() {
unsetenv("HIPBLASLT_CHECK_NUMERICS");
unsetenv("HIPBLASLT_CHECK_NUMERICS_SCAN_EVERY");
unsetenv("HIPBLASLT_CHECK_NUMERICS_SCAN_FROM");
unsetenv("HIPBLASLT_CHECK_NUMERICS_SCAN_UNTIL");
};
auto with_env = [](std::initializer_list<std::pair<const char*, const char*>> env,
auto inspect) {
for(auto& kv : env)
setenv(kv.first, kv.second, 1);
hipblasLtHandle_t h = nullptr;
EXPECT_HIPBLAS_STATUS(hipblasLtCreate(&h), HIPBLAS_STATUS_SUCCESS);
inspect((rocblaslt_handle)h);
EXPECT_HIPBLAS_STATUS(hipblasLtDestroy(h), HIPBLAS_STATUS_SUCCESS);
};
reset_env();
EXPECT_HIPBLAS_STATUS(hipblasLtCheckNumericsDrain(nullptr, nullptr),
HIPBLAS_STATUS_NOT_INITIALIZED);
// Default handle (env unset): scanning disabled, drain returns 0.
{
hipblasLtHandle_t h = nullptr;
EXPECT_HIPBLAS_STATUS(hipblasLtCreate(&h), HIPBLAS_STATUS_SUCCESS);
rocblaslt_handle rh = (rocblaslt_handle)h;
ASSERT_TRUE(rh->check_numerics == hipblaslt_check_numerics_mode_no_check);
ASSERT_TRUE(rh->check_numerics_flag == nullptr);
uint32_t out = 99;
EXPECT_HIPBLAS_STATUS(hipblasLtCheckNumericsDrain(h, &out), HIPBLAS_STATUS_SUCCESS);
ASSERT_EQ(out, 0u);
EXPECT_HIPBLAS_STATUS(hipblasLtCheckNumericsDrain(h, nullptr), HIPBLAS_STATUS_SUCCESS);
EXPECT_HIPBLAS_STATUS(hipblasLtDestroy(h), HIPBLAS_STATUS_SUCCESS);
}
// HIPBLASLT_CHECK_NUMERICS string/numeric forms.
auto check_mode = [&](const char* val, hipblaslt_check_numerics_mode expected) {
reset_env();
setenv("HIPBLASLT_CHECK_NUMERICS", val, 1);
hipblasLtHandle_t h = nullptr;
EXPECT_HIPBLAS_STATUS(hipblasLtCreate(&h), HIPBLAS_STATUS_SUCCESS);
ASSERT_TRUE(((rocblaslt_handle)h)->check_numerics == expected);
EXPECT_HIPBLAS_STATUS(hipblasLtDestroy(h), HIPBLAS_STATUS_SUCCESS);
};
for(const char* v : {"0", "none", "off", "OFF", "", " ", "garbage", "4", "8"})
check_mode(v, hipblaslt_check_numerics_mode_no_check);
for(const char* v : {"1", "info", "INFO"})
check_mode(v, hipblaslt_check_numerics_mode_info);
for(const char* v : {"2", "Warn", " warn "})
check_mode(v, hipblaslt_check_numerics_mode_warn);
// SCAN_EVERY parsing: valid values, plus 0/negative/garbage -> 1.
reset_env();
with_env({{"HIPBLASLT_CHECK_NUMERICS", "1"}, {"HIPBLASLT_CHECK_NUMERICS_SCAN_EVERY", "5"}},
[](rocblaslt_handle rh) { ASSERT_EQ(rh->check_numerics_scan_every, 5u); });
for(const char* v : {"0", "-3", "abc"})
{
reset_env();
with_env({{"HIPBLASLT_CHECK_NUMERICS", "1"}, {"HIPBLASLT_CHECK_NUMERICS_SCAN_EVERY", v}},
[](rocblaslt_handle rh) { ASSERT_EQ(rh->check_numerics_scan_every, 1u); });
}
// SCAN_FROM / SCAN_UNTIL: valid window, inverted resets to defaults.
reset_env();
with_env({{"HIPBLASLT_CHECK_NUMERICS", "2"},
{"HIPBLASLT_CHECK_NUMERICS_SCAN_FROM", "10"},
{"HIPBLASLT_CHECK_NUMERICS_SCAN_UNTIL", "20"}},
[](rocblaslt_handle rh) {
ASSERT_EQ(rh->check_numerics_scan_from, 10u);
ASSERT_EQ(rh->check_numerics_scan_until, 20u);
});
reset_env();
with_env({{"HIPBLASLT_CHECK_NUMERICS", "2"},
{"HIPBLASLT_CHECK_NUMERICS_SCAN_FROM", "600"},
{"HIPBLASLT_CHECK_NUMERICS_SCAN_UNTIL", "500"}},
[](rocblaslt_handle rh) {
ASSERT_EQ(rh->check_numerics_scan_from, 1u);
ASSERT_EQ(rh->check_numerics_scan_until, ~uint32_t(0));
});
// Happy path: enable scanning, write NaN, scan_D, drain returns call_id 1.
reset_env();
setenv("HIPBLASLT_CHECK_NUMERICS", "1", 1);
{
hipblasLtHandle_t h = nullptr;
EXPECT_HIPBLAS_STATUS(hipblasLtCreate(&h), HIPBLAS_STATUS_SUCCESS);
rocblaslt_handle rh = (rocblaslt_handle)h;
ASSERT_TRUE(rh->check_numerics_flag != nullptr);
constexpr int64_t M = 4, N = 4;
float* d_buf = nullptr;
ASSERT_EQ(hipMalloc(&d_buf, M * N * sizeof(float)), hipSuccess);
std::vector<float> h_buf(M * N, std::numeric_limits<float>::quiet_NaN());
ASSERT_EQ(hipMemcpy(d_buf, h_buf.data(),
M * N * sizeof(float), hipMemcpyHostToDevice),
hipSuccess);
const uint32_t call_id = hipblaslt_check_numerics_begin_call(rh);
ASSERT_EQ(call_id, 1u);
ASSERT_TRUE(hipblaslt_check_numerics_scan_D(rh, nullptr, call_id,
M, N, 1, HIP_R_32F,
d_buf, M, M * N, false)
== rocblaslt_status_success);
uint32_t out = 0;
EXPECT_HIPBLAS_STATUS(hipblasLtCheckNumericsDrain(h, &out), HIPBLAS_STATUS_SUCCESS);
ASSERT_EQ(out, 1u);
// Second drain after reset: no NaN.
out = 99;
EXPECT_HIPBLAS_STATUS(hipblasLtCheckNumericsDrain(h, &out), HIPBLAS_STATUS_SUCCESS);
ASSERT_EQ(out, 0u);
ASSERT_EQ(hipFree(d_buf), hipSuccess);
EXPECT_HIPBLAS_STATUS(hipblasLtDestroy(h), HIPBLAS_STATUS_SUCCESS);
}
// Per-dtype dispatch coverage: every arm of the type switch in
// hipblaslt_check_numerics_output_D gets a 4x4 NaN-prefilled buffer and
// we assert the device flag captures call_id 1. Catches a regression in
// any single dtype's template instantiation that the f32 happy path
// above would miss.
auto scan_one_with_nan
= [&reset_env](hipDataType dt, const void* host_buf, size_t elem_size, uint32_t expected_drain) {
reset_env();
setenv("HIPBLASLT_CHECK_NUMERICS", "1", 1);
hipblasLtHandle_t h = nullptr;
EXPECT_HIPBLAS_STATUS(hipblasLtCreate(&h), HIPBLAS_STATUS_SUCCESS);
rocblaslt_handle rh = (rocblaslt_handle)h;
constexpr int64_t M = 4, N = 4;
void* d_buf = nullptr;
ASSERT_EQ(hipMalloc(&d_buf, M * N * elem_size), hipSuccess);
ASSERT_EQ(
hipMemcpy(d_buf, host_buf, M * N * elem_size, hipMemcpyHostToDevice),
hipSuccess);
const uint32_t call_id = hipblaslt_check_numerics_begin_call(rh);
ASSERT_EQ(call_id, 1u);
ASSERT_TRUE(hipblaslt_check_numerics_scan_D(
rh, nullptr, call_id, M, N, 1, dt, d_buf, M, M * N, false)
== rocblaslt_status_success);
uint32_t out = 0;
EXPECT_HIPBLAS_STATUS(hipblasLtCheckNumericsDrain(h, &out),
HIPBLAS_STATUS_SUCCESS);
ASSERT_EQ(out, expected_drain);
ASSERT_EQ(hipFree(d_buf), hipSuccess);
EXPECT_HIPBLAS_STATUS(hipblasLtDestroy(h), HIPBLAS_STATUS_SUCCESS);
};
{
std::vector<double> b(16, std::numeric_limits<double>::quiet_NaN());
scan_one_with_nan(HIP_R_64F, b.data(), sizeof(double), 1u);
}
{
std::vector<hipblasLtHalf> b(16, static_cast<hipblasLtHalf>(NAN));
scan_one_with_nan(HIP_R_16F, b.data(), sizeof(hipblasLtHalf), 1u);
}
{
// f32 quiet NaN truncates to bf16 0x7FC0 (exp=0xFF, mantissa nonzero) -- still NaN.
std::vector<hip_bfloat16> b(16,
hip_bfloat16(std::numeric_limits<float>::quiet_NaN()));
scan_one_with_nan(HIP_R_16BF, b.data(), sizeof(hip_bfloat16), 1u);
}
{
// FNUZ NaN bit pattern (all f8/bf8 fnuz: 0x80).
hipblaslt_f8_fnuz nv;
nv.__x = 0x80;
std::vector<hipblaslt_f8_fnuz> b(16, nv);
scan_one_with_nan(HIP_R_8F_E4M3_FNUZ, b.data(), sizeof(hipblaslt_f8_fnuz), 1u);
}
{
hipblaslt_bf8_fnuz nv;
nv.__x = 0x80;
std::vector<hipblaslt_bf8_fnuz> b(16, nv);
scan_one_with_nan(HIP_R_8F_E5M2_FNUZ, b.data(), sizeof(hipblaslt_bf8_fnuz), 1u);
}
{
// OCP E4M3 canonical NaN: 0x7f.
hipblaslt_f8 nv;
nv.__x = 0x7f;
std::vector<hipblaslt_f8> b(16, nv);
scan_one_with_nan(HIP_R_8F_E4M3, b.data(), sizeof(hipblaslt_f8), 1u);
}
{
// OCP E5M2 NaN: any of 0x7d/0x7e/0x7f (exp=11111, mant!=0). Use 0x7d
// to match hipblaslt_isnan coverage above.
hipblaslt_bf8 nv;
nv.__x = 0x7d;
std::vector<hipblaslt_bf8> b(16, nv);
scan_one_with_nan(HIP_R_8F_E5M2, b.data(), sizeof(hipblaslt_bf8), 1u);
}
// Default-arm silent skip: integer dtypes hit the dispatcher's `default`
// and must return success without touching the flag.
{
reset_env();
setenv("HIPBLASLT_CHECK_NUMERICS", "1", 1);
hipblasLtHandle_t h = nullptr;
EXPECT_HIPBLAS_STATUS(hipblasLtCreate(&h), HIPBLAS_STATUS_SUCCESS);
rocblaslt_handle rh = (rocblaslt_handle)h;
constexpr int64_t M = 4, N = 4;
// Any non-zero pattern; integer arms must NOT inspect it.
std::vector<int8_t> h_buf(M * N, static_cast<int8_t>(0xFF));
int8_t* d_buf = nullptr;
ASSERT_EQ(hipMalloc(&d_buf, M * N * sizeof(int8_t)), hipSuccess);
ASSERT_EQ(
hipMemcpy(d_buf, h_buf.data(), M * N * sizeof(int8_t), hipMemcpyHostToDevice),
hipSuccess);
const uint32_t call_id = hipblaslt_check_numerics_begin_call(rh);
ASSERT_TRUE(hipblaslt_check_numerics_scan_D(rh, nullptr, call_id, M, N, 1, HIP_R_8I,
d_buf, M, M * N, false)
== rocblaslt_status_success);
uint32_t out = 99;
EXPECT_HIPBLAS_STATUS(hipblasLtCheckNumericsDrain(h, &out), HIPBLAS_STATUS_SUCCESS);
ASSERT_EQ(out, 0u); // never tripped
ASSERT_EQ(hipFree(d_buf), hipSuccess);
EXPECT_HIPBLAS_STATUS(hipblasLtDestroy(h), HIPBLAS_STATUS_SUCCESS);
}
// STOP_ON_FIRST: env parses; the sticky short_circuit fires after the
// first NaN; re-drain returns the same call_id (sticky doesn't reset
// the device flag).
{
reset_env();
setenv("HIPBLASLT_CHECK_NUMERICS", "1", 1);
setenv("HIPBLASLT_CHECK_NUMERICS_STOP_ON_FIRST", "1", 1);
hipblasLtHandle_t h = nullptr;
EXPECT_HIPBLAS_STATUS(hipblasLtCreate(&h), HIPBLAS_STATUS_SUCCESS);
rocblaslt_handle rh = (rocblaslt_handle)h;
ASSERT_TRUE(rh->check_numerics_stop_on_first);
ASSERT_FALSE(rh->check_numerics_short_circuit.load());
constexpr int64_t M = 4, N = 4;
float* d_buf = nullptr;
ASSERT_EQ(hipMalloc(&d_buf, M * N * sizeof(float)), hipSuccess);
std::vector<float> h_buf(M * N, std::numeric_limits<float>::quiet_NaN());
ASSERT_EQ(hipMemcpy(d_buf, h_buf.data(), M * N * sizeof(float),
hipMemcpyHostToDevice),
hipSuccess);
const uint32_t cid = hipblaslt_check_numerics_begin_call(rh);
ASSERT_TRUE(hipblaslt_check_numerics_scan_D(rh, nullptr, cid, M, N, 1, HIP_R_32F,
d_buf, M, M * N, false)
== rocblaslt_status_success);
uint32_t out = 0;
EXPECT_HIPBLAS_STATUS(hipblasLtCheckNumericsDrain(h, &out), HIPBLAS_STATUS_SUCCESS);
ASSERT_EQ(out, cid);
// After the sticky drain, short_circuit is set so further scans bail.
ASSERT_TRUE(rh->check_numerics_short_circuit.load());
const uint32_t cid2 = hipblaslt_check_numerics_begin_call(rh);
ASSERT_TRUE(hipblaslt_check_numerics_scan_D(rh, nullptr, cid2, M, N, 1, HIP_R_32F,
d_buf, M, M * N, false)
== rocblaslt_status_success);
// Re-drain returns the same id (device flag was not memset).
out = 0;
EXPECT_HIPBLAS_STATUS(hipblasLtCheckNumericsDrain(h, &out), HIPBLAS_STATUS_SUCCESS);
ASSERT_EQ(out, cid);
ASSERT_EQ(hipFree(d_buf), hipSuccess);
EXPECT_HIPBLAS_STATUS(hipblasLtDestroy(h), HIPBLAS_STATUS_SUCCESS);
}
// SCAN_EVERY runtime: every=3 means scan_D only runs the kernel when
// call_id % 3 == 0. With 5 calls, only call_id 3 inspects the buffer,
// so drain returns 3.
{
reset_env();
setenv("HIPBLASLT_CHECK_NUMERICS", "1", 1);
setenv("HIPBLASLT_CHECK_NUMERICS_SCAN_EVERY", "3", 1);
hipblasLtHandle_t h = nullptr;
EXPECT_HIPBLAS_STATUS(hipblasLtCreate(&h), HIPBLAS_STATUS_SUCCESS);
rocblaslt_handle rh = (rocblaslt_handle)h;
ASSERT_EQ(rh->check_numerics_scan_every, 3u);
constexpr int64_t M = 4, N = 4;
float* d_buf = nullptr;
ASSERT_EQ(hipMalloc(&d_buf, M * N * sizeof(float)), hipSuccess);
std::vector<float> h_buf(M * N, std::numeric_limits<float>::quiet_NaN());
ASSERT_EQ(hipMemcpy(d_buf, h_buf.data(), M * N * sizeof(float),
hipMemcpyHostToDevice),
hipSuccess);
for(int i = 0; i < 5; ++i)
{
const uint32_t cid = hipblaslt_check_numerics_begin_call(rh);
ASSERT_TRUE(hipblaslt_check_numerics_scan_D(rh, nullptr, cid, M, N, 1, HIP_R_32F,
d_buf, M, M * N, false)
== rocblaslt_status_success);
}
uint32_t out = 0;
EXPECT_HIPBLAS_STATUS(hipblasLtCheckNumericsDrain(h, &out), HIPBLAS_STATUS_SUCCESS);
ASSERT_EQ(out, 3u);
ASSERT_EQ(hipFree(d_buf), hipSuccess);
EXPECT_HIPBLAS_STATUS(hipblasLtDestroy(h), HIPBLAS_STATUS_SUCCESS);
}
// SCAN_FROM/SCAN_UNTIL window: gates calls outside [from, until]. With
// from=3, until=4 and 5 NaN-bearing calls, drain returns 3 (the first
// in-window call).
{
reset_env();
setenv("HIPBLASLT_CHECK_NUMERICS", "1", 1);
setenv("HIPBLASLT_CHECK_NUMERICS_SCAN_FROM", "3", 1);
setenv("HIPBLASLT_CHECK_NUMERICS_SCAN_UNTIL", "4", 1);
hipblasLtHandle_t h = nullptr;
EXPECT_HIPBLAS_STATUS(hipblasLtCreate(&h), HIPBLAS_STATUS_SUCCESS);
rocblaslt_handle rh = (rocblaslt_handle)h;
ASSERT_EQ(rh->check_numerics_scan_from, 3u);
ASSERT_EQ(rh->check_numerics_scan_until, 4u);
constexpr int64_t M = 4, N = 4;
float* d_buf = nullptr;
ASSERT_EQ(hipMalloc(&d_buf, M * N * sizeof(float)), hipSuccess);
std::vector<float> h_buf(M * N, std::numeric_limits<float>::quiet_NaN());
ASSERT_EQ(hipMemcpy(d_buf, h_buf.data(), M * N * sizeof(float),
hipMemcpyHostToDevice),
hipSuccess);
for(int i = 0; i < 5; ++i)
{
const uint32_t cid = hipblaslt_check_numerics_begin_call(rh);
ASSERT_TRUE(hipblaslt_check_numerics_scan_D(rh, nullptr, cid, M, N, 1, HIP_R_32F,
d_buf, M, M * N, false)
== rocblaslt_status_success);
}
uint32_t out = 0;
EXPECT_HIPBLAS_STATUS(hipblasLtCheckNumericsDrain(h, &out), HIPBLAS_STATUS_SUCCESS);
ASSERT_EQ(out, 3u);
ASSERT_EQ(hipFree(d_buf), hipSuccess);
EXPECT_HIPBLAS_STATUS(hipblasLtDestroy(h), HIPBLAS_STATUS_SUCCESS);
}
reset_env();
}
#endif // CODE_COVERAGE