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
573 lines
19 KiB
C++
573 lines
19 KiB
C++
/*******************************************************************************
|
|
*
|
|
* MIT License
|
|
*
|
|
* Copyright (C) 2021-2026 Advanced Micro Devices, Inc. All rights reserved.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*
|
|
*******************************************************************************/
|
|
|
|
// HIP RTC (Runtime Compilation) regression tests
|
|
//
|
|
// These tests validate that the HIP RTC workflow continues to function
|
|
// correctly across different HIP/ROCm versions and code changes. They test:
|
|
// - Runtime kernel compilation and loading
|
|
// - Error handling and diagnostic reporting
|
|
// - Module management and kernel execution
|
|
// - Support for different data types
|
|
|
|
#include <cstdlib>
|
|
#include <gtest/gtest.h>
|
|
#include <hip/hip_runtime.h>
|
|
#include <hip/hiprtc.h>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include <rocwmma/rocwmma.hpp>
|
|
|
|
#include "regression/reg_common.hpp"
|
|
|
|
// ============================================================================
|
|
// Kernel Sources
|
|
// ============================================================================
|
|
|
|
// Simple vector addition kernel for integer validation
|
|
// Note: extern "C" linkage is required for hipModuleGetFunction() to find the kernel
|
|
static const char* vectorAddSource = R"(
|
|
extern "C"
|
|
__global__ void vectorAdd(const int* a, const int* b, int* c, int n)
|
|
{
|
|
int idx = blockIdx.x * blockDim.x + threadIdx.x;
|
|
if (idx < n)
|
|
{
|
|
c[idx] = a[idx] + b[idx];
|
|
}
|
|
}
|
|
)";
|
|
|
|
// Intentionally broken kernel source for error handling tests
|
|
static const char* brokenKernelSource = R"(
|
|
extern "C"
|
|
__global__ void brokenKernel(int* data)
|
|
{
|
|
// Syntax error: missing semicolon
|
|
int idx = blockIdx.x * blockDim.x + threadIdx.x
|
|
}
|
|
)";
|
|
|
|
// Vector multiplication kernel for float validation
|
|
static const char* vectorMultiplySource = R"(
|
|
extern "C"
|
|
__global__ void vectorMultiply(const float* a, const float* b, float* c, int n)
|
|
{
|
|
int idx = blockIdx.x * blockDim.x + threadIdx.x;
|
|
if (idx < n)
|
|
{
|
|
c[idx] = a[idx] * b[idx];
|
|
}
|
|
}
|
|
)";
|
|
|
|
// ============================================================================
|
|
// Test Suite
|
|
// ============================================================================
|
|
|
|
class HipRTC_BasicFunctionality : public ::testing::Test
|
|
{
|
|
protected:
|
|
void SetUp() override
|
|
{
|
|
// Check if a ROCm device is available
|
|
int deviceCount = 0;
|
|
CHECK_HIP_ERROR(hipGetDeviceCount(&deviceCount));
|
|
|
|
if(deviceCount == 0)
|
|
{
|
|
GTEST_SKIP() << "No ROCm-capable device available";
|
|
}
|
|
}
|
|
};
|
|
|
|
// ============================================================================
|
|
// Test 1: Basic Compile and Execute
|
|
// ============================================================================
|
|
// Tests the complete HIP RTC workflow:
|
|
// - Create program from source
|
|
// - Compile with appropriate options
|
|
// - Extract compiled code
|
|
// - Load module and get function
|
|
// - Launch kernel and verify results
|
|
// - Proper resource cleanup
|
|
|
|
TEST_F(HipRTC_BasicFunctionality, BasicCompileAndExecute)
|
|
{
|
|
// Test parameters
|
|
const int n = 1024;
|
|
const int blockSize = 256;
|
|
const int gridSize = rocwmma::ceil_div(n, blockSize);
|
|
|
|
// Initialize host data
|
|
std::vector<int> h_a(n);
|
|
std::vector<int> h_b(n);
|
|
std::vector<int> h_c(n);
|
|
std::vector<int> h_reference(n);
|
|
|
|
// Fill with sequential values for predictable debugging
|
|
for(int i = 0; i < n; i++)
|
|
{
|
|
h_a[i] = i;
|
|
h_b[i] = i * 2;
|
|
}
|
|
|
|
// Compute reference result on CPU
|
|
vectorAddCPU(h_a.data(), h_b.data(), h_reference.data(), n);
|
|
|
|
// Allocate device memory
|
|
int* d_a;
|
|
int* d_b;
|
|
int* d_c;
|
|
CHECK_HIP_ERROR(hipMalloc(&d_a, n * sizeof(int)));
|
|
CHECK_HIP_ERROR(hipMalloc(&d_b, n * sizeof(int)));
|
|
CHECK_HIP_ERROR(hipMalloc(&d_c, n * sizeof(int)));
|
|
|
|
// Copy input data to device
|
|
CHECK_HIP_ERROR(hipMemcpy(d_a, h_a.data(), n * sizeof(int), hipMemcpyHostToDevice));
|
|
CHECK_HIP_ERROR(hipMemcpy(d_b, h_b.data(), n * sizeof(int), hipMemcpyHostToDevice));
|
|
|
|
// Create HIP RTC program
|
|
hiprtcProgram prog;
|
|
ASSERT_HIPRTC_SUCCESS(hiprtcCreateProgram(&prog, vectorAddSource, nullptr, 0, nullptr, nullptr));
|
|
|
|
// Build compile options
|
|
auto options = buildCompileOptions();
|
|
int numOptions = options.size();
|
|
|
|
// Compile the program
|
|
hiprtcResult compileResult = hiprtcCompileProgram(prog, numOptions, options.data());
|
|
|
|
// Handle compilation errors
|
|
if(compileResult != HIPRTC_SUCCESS)
|
|
{
|
|
std::size_t log_size;
|
|
hiprtcGetProgramLogSize(prog, &log_size);
|
|
std::string log(log_size, '\0');
|
|
hiprtcGetProgramLog(prog, &log[0]);
|
|
FAIL() << "Compilation failed:\n" << log;
|
|
}
|
|
|
|
// Extract compiled code
|
|
std::size_t code_size;
|
|
ASSERT_HIPRTC_SUCCESS(hiprtcGetCodeSize(prog, &code_size));
|
|
std::vector<char> code(code_size);
|
|
ASSERT_HIPRTC_SUCCESS(hiprtcGetCode(prog, code.data()));
|
|
|
|
// Load module and get function
|
|
hipModule_t module;
|
|
hipFunction_t func;
|
|
CHECK_HIP_ERROR(hipModuleLoadData(&module, code.data()));
|
|
CHECK_HIP_ERROR(hipModuleGetFunction(&func, module, "vectorAdd"));
|
|
|
|
// Set up kernel parameters using parameter buffer
|
|
struct
|
|
{
|
|
int* d_a;
|
|
int* d_b;
|
|
int* d_c;
|
|
int n;
|
|
} args{d_a, d_b, d_c, n};
|
|
|
|
std::size_t args_size = sizeof(args);
|
|
|
|
void* config[] = {HIP_LAUNCH_PARAM_BUFFER_POINTER,
|
|
&args,
|
|
HIP_LAUNCH_PARAM_BUFFER_SIZE,
|
|
&args_size,
|
|
HIP_LAUNCH_PARAM_END};
|
|
|
|
// Launch kernel
|
|
CHECK_HIP_ERROR(hipModuleLaunchKernel(func,
|
|
gridSize,
|
|
1,
|
|
1,
|
|
blockSize,
|
|
1,
|
|
1,
|
|
0,
|
|
nullptr,
|
|
nullptr,
|
|
(void**)&config));
|
|
|
|
// Wait for completion
|
|
CHECK_HIP_ERROR(hipDeviceSynchronize());
|
|
|
|
// Copy results back to host
|
|
CHECK_HIP_ERROR(hipMemcpy(h_c.data(), d_c, n * sizeof(int), hipMemcpyDeviceToHost));
|
|
|
|
// Verify results
|
|
for(int i = 0; i < n; i++)
|
|
{
|
|
EXPECT_EQ(h_c[i], h_reference[i]) << "Mismatch at index " << i;
|
|
}
|
|
|
|
// Cleanup
|
|
CHECK_HIP_ERROR(hipModuleUnload(module));
|
|
ASSERT_HIPRTC_SUCCESS(hiprtcDestroyProgram(&prog));
|
|
CHECK_HIP_ERROR(hipFree(d_a));
|
|
CHECK_HIP_ERROR(hipFree(d_b));
|
|
CHECK_HIP_ERROR(hipFree(d_c));
|
|
}
|
|
|
|
// ============================================================================
|
|
// Test 2: Compilation Error Handling
|
|
// ============================================================================
|
|
// Tests that compilation errors are properly detected and reported:
|
|
// - Intentional syntax error in kernel
|
|
// - Compilation failure is detected
|
|
// - Error log is populated with diagnostics
|
|
// - No crashes or undefined behavior
|
|
|
|
TEST_F(HipRTC_BasicFunctionality, CompilationErrorHandling)
|
|
{
|
|
// Create program with broken source
|
|
hiprtcProgram prog;
|
|
ASSERT_HIPRTC_SUCCESS(hiprtcCreateProgram(&prog, brokenKernelSource, nullptr, 0, nullptr, nullptr));
|
|
|
|
// Build compile options
|
|
auto options = buildCompileOptions();
|
|
int numOptions = options.size();
|
|
|
|
// Attempt compilation - expect it to fail
|
|
hiprtcResult compileResult = hiprtcCompileProgram(prog, numOptions, options.data());
|
|
|
|
// Verify compilation failed
|
|
EXPECT_NE(compileResult, HIPRTC_SUCCESS) << "Compilation should have failed for broken kernel";
|
|
|
|
// Get compilation log
|
|
std::size_t log_size;
|
|
ASSERT_HIPRTC_SUCCESS(hiprtcGetProgramLogSize(prog, &log_size));
|
|
|
|
// Log should contain error diagnostics
|
|
EXPECT_GT(log_size, 0) << "Compilation log should not be empty for failed compilation";
|
|
|
|
if(log_size > 0)
|
|
{
|
|
std::string log(log_size, '\0');
|
|
ASSERT_HIPRTC_SUCCESS(hiprtcGetProgramLog(prog, &log[0]));
|
|
|
|
// Verify log contains useful error information
|
|
EXPECT_FALSE(log.empty()) << "Compilation log should contain error diagnostics";
|
|
}
|
|
|
|
// Cleanup
|
|
ASSERT_HIPRTC_SUCCESS(hiprtcDestroyProgram(&prog));
|
|
}
|
|
|
|
// ============================================================================
|
|
// Test 3: Multiple Kernel Compilations
|
|
// ============================================================================
|
|
// Tests that multiple independent kernel compilations work correctly:
|
|
// - Compile and execute first kernel
|
|
// - Compile and execute second kernel
|
|
// - Verify no interference between compilations
|
|
// - Test complete cleanup between sessions
|
|
|
|
TEST_F(HipRTC_BasicFunctionality, MultipleKernelCompilations)
|
|
{
|
|
const int n = 512;
|
|
const int blockSize = 256;
|
|
const int gridSize = rocwmma::ceil_div(n, blockSize);
|
|
|
|
// ========== First Kernel: Vector Add ==========
|
|
|
|
// Initialize data for first kernel
|
|
std::vector<int> h_a1(n);
|
|
std::vector<int> h_b1(n);
|
|
std::vector<int> h_c1(n);
|
|
std::vector<int> h_ref1(n);
|
|
|
|
for(int i = 0; i < n; i++)
|
|
{
|
|
h_a1[i] = i;
|
|
h_b1[i] = 100 - i;
|
|
}
|
|
vectorAddCPU(h_a1.data(), h_b1.data(), h_ref1.data(), n);
|
|
|
|
// Allocate device memory for first kernel
|
|
int* d_a1;
|
|
int* d_b1;
|
|
int* d_c1;
|
|
CHECK_HIP_ERROR(hipMalloc(&d_a1, n * sizeof(int)));
|
|
CHECK_HIP_ERROR(hipMalloc(&d_b1, n * sizeof(int)));
|
|
CHECK_HIP_ERROR(hipMalloc(&d_c1, n * sizeof(int)));
|
|
CHECK_HIP_ERROR(hipMemcpy(d_a1, h_a1.data(), n * sizeof(int), hipMemcpyHostToDevice));
|
|
CHECK_HIP_ERROR(hipMemcpy(d_b1, h_b1.data(), n * sizeof(int), hipMemcpyHostToDevice));
|
|
|
|
// Compile and execute first kernel
|
|
hiprtcProgram prog1;
|
|
ASSERT_HIPRTC_SUCCESS(hiprtcCreateProgram(&prog1, vectorAddSource, nullptr, 0, nullptr, nullptr));
|
|
|
|
// Build compile options
|
|
auto options = buildCompileOptions();
|
|
int numOptions = options.size();
|
|
|
|
// Compile the program
|
|
hiprtcResult compileResult1 = hiprtcCompileProgram(prog1, numOptions, options.data());
|
|
|
|
// Handle compilation errors
|
|
if(compileResult1 != HIPRTC_SUCCESS)
|
|
{
|
|
std::size_t log_size;
|
|
hiprtcGetProgramLogSize(prog1, &log_size);
|
|
std::string log(log_size, '\0');
|
|
hiprtcGetProgramLog(prog1, &log[0]);
|
|
FAIL() << "Compilation failed:\n" << log;
|
|
}
|
|
|
|
std::size_t code_size1;
|
|
ASSERT_HIPRTC_SUCCESS(hiprtcGetCodeSize(prog1, &code_size1));
|
|
std::vector<char> code1(code_size1);
|
|
ASSERT_HIPRTC_SUCCESS(hiprtcGetCode(prog1, code1.data()));
|
|
|
|
hipModule_t module1;
|
|
hipFunction_t func1;
|
|
CHECK_HIP_ERROR(hipModuleLoadData(&module1, code1.data()));
|
|
CHECK_HIP_ERROR(hipModuleGetFunction(&func1, module1, "vectorAdd"));
|
|
|
|
struct
|
|
{
|
|
int* d_a;
|
|
int* d_b;
|
|
int* d_c;
|
|
int n;
|
|
} args1{d_a1, d_b1, d_c1, n};
|
|
|
|
std::size_t args_size1 = sizeof(args1);
|
|
void* config1[] = {HIP_LAUNCH_PARAM_BUFFER_POINTER,
|
|
&args1,
|
|
HIP_LAUNCH_PARAM_BUFFER_SIZE,
|
|
&args_size1,
|
|
HIP_LAUNCH_PARAM_END};
|
|
|
|
CHECK_HIP_ERROR(hipModuleLaunchKernel(func1, gridSize, 1, 1, blockSize, 1, 1, 0, nullptr, nullptr, (void**)&config1));
|
|
CHECK_HIP_ERROR(hipDeviceSynchronize());
|
|
CHECK_HIP_ERROR(hipMemcpy(h_c1.data(), d_c1, n * sizeof(int), hipMemcpyDeviceToHost));
|
|
|
|
// Verify first kernel results
|
|
for(int i = 0; i < n; i++)
|
|
{
|
|
EXPECT_EQ(h_c1[i], h_ref1[i]) << "First kernel: Mismatch at index " << i;
|
|
}
|
|
|
|
// Cleanup first kernel
|
|
CHECK_HIP_ERROR(hipModuleUnload(module1));
|
|
ASSERT_HIPRTC_SUCCESS(hiprtcDestroyProgram(&prog1));
|
|
CHECK_HIP_ERROR(hipFree(d_a1));
|
|
CHECK_HIP_ERROR(hipFree(d_b1));
|
|
CHECK_HIP_ERROR(hipFree(d_c1));
|
|
|
|
// ========== Second Kernel: Vector Multiply ==========
|
|
|
|
// Initialize data for second kernel
|
|
std::vector<float> h_a2(n);
|
|
std::vector<float> h_b2(n);
|
|
std::vector<float> h_c2(n);
|
|
std::vector<float> h_ref2(n);
|
|
|
|
for(int i = 0; i < n; i++)
|
|
{
|
|
h_a2[i] = static_cast<float>(i) * 0.5f;
|
|
h_b2[i] = 2.0f;
|
|
}
|
|
vectorMultiplyCPU(h_a2.data(), h_b2.data(), h_ref2.data(), n);
|
|
|
|
// Allocate device memory for second kernel
|
|
float* d_a2;
|
|
float* d_b2;
|
|
float* d_c2;
|
|
CHECK_HIP_ERROR(hipMalloc(&d_a2, n * sizeof(float)));
|
|
CHECK_HIP_ERROR(hipMalloc(&d_b2, n * sizeof(float)));
|
|
CHECK_HIP_ERROR(hipMalloc(&d_c2, n * sizeof(float)));
|
|
CHECK_HIP_ERROR(hipMemcpy(d_a2, h_a2.data(), n * sizeof(float), hipMemcpyHostToDevice));
|
|
CHECK_HIP_ERROR(hipMemcpy(d_b2, h_b2.data(), n * sizeof(float), hipMemcpyHostToDevice));
|
|
|
|
// Compile and execute second kernel
|
|
hiprtcProgram prog2;
|
|
ASSERT_HIPRTC_SUCCESS(hiprtcCreateProgram(&prog2, vectorMultiplySource, nullptr, 0, nullptr, nullptr));
|
|
// Compile the program
|
|
hiprtcResult compileResult2 = hiprtcCompileProgram(prog2, numOptions, options.data());
|
|
|
|
// Handle compilation errors
|
|
if(compileResult2 != HIPRTC_SUCCESS)
|
|
{
|
|
std::size_t log_size;
|
|
hiprtcGetProgramLogSize(prog2, &log_size);
|
|
std::string log(log_size, '\0');
|
|
hiprtcGetProgramLog(prog2, &log[0]);
|
|
FAIL() << "Compilation failed:\n" << log;
|
|
}
|
|
|
|
|
|
std::size_t code_size2;
|
|
ASSERT_HIPRTC_SUCCESS(hiprtcGetCodeSize(prog2, &code_size2));
|
|
std::vector<char> code2(code_size2);
|
|
ASSERT_HIPRTC_SUCCESS(hiprtcGetCode(prog2, code2.data()));
|
|
|
|
hipModule_t module2;
|
|
hipFunction_t func2;
|
|
CHECK_HIP_ERROR(hipModuleLoadData(&module2, code2.data()));
|
|
CHECK_HIP_ERROR(hipModuleGetFunction(&func2, module2, "vectorMultiply"));
|
|
|
|
struct
|
|
{
|
|
float* d_a;
|
|
float* d_b;
|
|
float* d_c;
|
|
int n;
|
|
} args2{d_a2, d_b2, d_c2, n};
|
|
|
|
std::size_t args_size2 = sizeof(args2);
|
|
void* config2[] = {HIP_LAUNCH_PARAM_BUFFER_POINTER,
|
|
&args2,
|
|
HIP_LAUNCH_PARAM_BUFFER_SIZE,
|
|
&args_size2,
|
|
HIP_LAUNCH_PARAM_END};
|
|
|
|
CHECK_HIP_ERROR(hipModuleLaunchKernel(func2, gridSize, 1, 1, blockSize, 1, 1, 0, nullptr, nullptr, (void**)&config2));
|
|
CHECK_HIP_ERROR(hipDeviceSynchronize());
|
|
CHECK_HIP_ERROR(hipMemcpy(h_c2.data(), d_c2, n * sizeof(float), hipMemcpyDeviceToHost));
|
|
|
|
// Verify second kernel results with floating-point tolerance
|
|
for(int i = 0; i < n; i++)
|
|
{
|
|
EXPECT_NEAR(h_c2[i], h_ref2[i], 1e-5f) << "Second kernel: Mismatch at index " << i;
|
|
}
|
|
|
|
// Cleanup second kernel
|
|
CHECK_HIP_ERROR(hipModuleUnload(module2));
|
|
ASSERT_HIPRTC_SUCCESS(hiprtcDestroyProgram(&prog2));
|
|
CHECK_HIP_ERROR(hipFree(d_a2));
|
|
CHECK_HIP_ERROR(hipFree(d_b2));
|
|
CHECK_HIP_ERROR(hipFree(d_c2));
|
|
}
|
|
|
|
// ============================================================================
|
|
// Test 4: Float Type Test
|
|
// ============================================================================
|
|
// Tests HIP RTC with floating-point data types:
|
|
// - Compile kernel using float types
|
|
// - Execute and verify with appropriate tolerance
|
|
// - Validate floating-point operations
|
|
|
|
TEST_F(HipRTC_BasicFunctionality, FloatTypeTest)
|
|
{
|
|
const int n = 1024;
|
|
const int blockSize = 256;
|
|
const int gridSize = rocwmma::ceil_div(n, blockSize);
|
|
|
|
// Initialize host data
|
|
std::vector<float> h_a(n);
|
|
std::vector<float> h_b(n);
|
|
std::vector<float> h_c(n);
|
|
std::vector<float> h_reference(n);
|
|
|
|
for(int i = 0; i < n; i++)
|
|
{
|
|
h_a[i] = static_cast<float>(i) * 0.1f;
|
|
h_b[i] = static_cast<float>(i) * 0.2f;
|
|
}
|
|
|
|
vectorMultiplyCPU(h_a.data(), h_b.data(), h_reference.data(), n);
|
|
|
|
// Allocate device memory
|
|
float* d_a;
|
|
float* d_b;
|
|
float* d_c;
|
|
CHECK_HIP_ERROR(hipMalloc(&d_a, n * sizeof(float)));
|
|
CHECK_HIP_ERROR(hipMalloc(&d_b, n * sizeof(float)));
|
|
CHECK_HIP_ERROR(hipMalloc(&d_c, n * sizeof(float)));
|
|
CHECK_HIP_ERROR(hipMemcpy(d_a, h_a.data(), n * sizeof(float), hipMemcpyHostToDevice));
|
|
CHECK_HIP_ERROR(hipMemcpy(d_b, h_b.data(), n * sizeof(float), hipMemcpyHostToDevice));
|
|
|
|
// Create and compile program
|
|
hiprtcProgram prog;
|
|
ASSERT_HIPRTC_SUCCESS(hiprtcCreateProgram(&prog, vectorMultiplySource, nullptr, 0, nullptr, nullptr));
|
|
|
|
// Build compile options
|
|
auto options = buildCompileOptions();
|
|
int numOptions = options.size();
|
|
|
|
// Compile the program
|
|
hiprtcResult compileResult = hiprtcCompileProgram(prog, numOptions, options.data());
|
|
|
|
// Handle compilation errors
|
|
if(compileResult != HIPRTC_SUCCESS)
|
|
{
|
|
std::size_t log_size;
|
|
hiprtcGetProgramLogSize(prog, &log_size);
|
|
std::string log(log_size, '\0');
|
|
hiprtcGetProgramLog(prog, &log[0]);
|
|
FAIL() << "Compilation failed:\n" << log;
|
|
}
|
|
|
|
// Extract code
|
|
std::size_t code_size;
|
|
ASSERT_HIPRTC_SUCCESS(hiprtcGetCodeSize(prog, &code_size));
|
|
std::vector<char> code(code_size);
|
|
ASSERT_HIPRTC_SUCCESS(hiprtcGetCode(prog, code.data()));
|
|
|
|
// Load and execute
|
|
hipModule_t module;
|
|
hipFunction_t func;
|
|
CHECK_HIP_ERROR(hipModuleLoadData(&module, code.data()));
|
|
CHECK_HIP_ERROR(hipModuleGetFunction(&func, module, "vectorMultiply"));
|
|
|
|
struct
|
|
{
|
|
float* d_a;
|
|
float* d_b;
|
|
float* d_c;
|
|
int n;
|
|
} args{d_a, d_b, d_c, n};
|
|
|
|
std::size_t args_size = sizeof(args);
|
|
void* config[] = {HIP_LAUNCH_PARAM_BUFFER_POINTER,
|
|
&args,
|
|
HIP_LAUNCH_PARAM_BUFFER_SIZE,
|
|
&args_size,
|
|
HIP_LAUNCH_PARAM_END};
|
|
|
|
CHECK_HIP_ERROR(hipModuleLaunchKernel(func, gridSize, 1, 1, blockSize, 1, 1, 0, nullptr, nullptr, (void**)&config));
|
|
CHECK_HIP_ERROR(hipDeviceSynchronize());
|
|
CHECK_HIP_ERROR(hipMemcpy(h_c.data(), d_c, n * sizeof(float), hipMemcpyDeviceToHost));
|
|
|
|
// Verify with floating-point tolerance
|
|
for(int i = 0; i < n; i++)
|
|
{
|
|
EXPECT_NEAR(h_c[i], h_reference[i], 1e-5f) << "Mismatch at index " << i;
|
|
}
|
|
|
|
// Cleanup
|
|
CHECK_HIP_ERROR(hipModuleUnload(module));
|
|
ASSERT_HIPRTC_SUCCESS(hiprtcDestroyProgram(&prog));
|
|
CHECK_HIP_ERROR(hipFree(d_a));
|
|
CHECK_HIP_ERROR(hipFree(d_b));
|
|
CHECK_HIP_ERROR(hipFree(d_c));
|
|
}
|