2023-08-14 21:17:55 +05:30
|
|
|
|
/*
|
|
|
|
|
|
Copyright (c) 2023 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.
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2025-08-15 16:09:19 -04:00
|
|
|
|
* @addtogroup hipMemcpyKernel hipMemcpyKernel
|
|
|
|
|
|
* @{
|
|
|
|
|
|
* @ingroup perfMemoryTest
|
|
|
|
|
|
* `hipMemcpy(void* dst, const void* src, size_t count, hipMemcpyKind kind)` -
|
|
|
|
|
|
* Copies data between host and device.
|
|
|
|
|
|
*/
|
2023-08-14 21:17:55 +05:30
|
|
|
|
|
|
|
|
|
|
#include <hip_test_common.hh>
|
|
|
|
|
|
|
|
|
|
|
|
#define SIMPLY_ASSIGN 0
|
|
|
|
|
|
#define USE_HIPTEST_SETNUMBLOCKS 0
|
|
|
|
|
|
|
2025-08-15 16:09:19 -04:00
|
|
|
|
template <class T> __global__ void vec_fill(T* x, T coef, int N) {
|
2023-08-14 21:17:55 +05:30
|
|
|
|
const int istart = threadIdx.x + blockIdx.x * blockDim.x;
|
|
|
|
|
|
const int ishift = blockDim.x * gridDim.x;
|
|
|
|
|
|
for (int i = istart; i < N; i += ishift) {
|
|
|
|
|
|
#if SIMPLY_ASSIGN
|
|
|
|
|
|
x[i] = coef;
|
|
|
|
|
|
#else
|
|
|
|
|
|
x[i] = coef * i;
|
|
|
|
|
|
#endif
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
__device__ void print_log(int i, double value, double expected) {
|
|
|
|
|
|
printf("failed at %d: val=%g, expected=%g\n", i, value, expected);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
__device__ void print_log(int i, int value, int expected) {
|
|
|
|
|
|
printf("failed at %d: val=%d, expected=%d\n", i, value, expected);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-15 16:09:19 -04:00
|
|
|
|
template <class T> __global__ void vec_verify(T* x, T coef, int N) {
|
2023-08-14 21:17:55 +05:30
|
|
|
|
const int istart = threadIdx.x + blockIdx.x * blockDim.x;
|
|
|
|
|
|
const int ishift = blockDim.x * gridDim.x;
|
|
|
|
|
|
for (int i = istart; i < N; i += ishift) {
|
|
|
|
|
|
#if SIMPLY_ASSIGN
|
|
|
|
|
|
if (x[i] != coef) {
|
|
|
|
|
|
print_log(i, x[i], coef);
|
|
|
|
|
|
}
|
|
|
|
|
|
#else
|
|
|
|
|
|
if (x[i] != coef * i) {
|
|
|
|
|
|
print_log(i, x[i], coef * i);
|
|
|
|
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-15 16:09:19 -04:00
|
|
|
|
template <class T>
|
|
|
|
|
|
__global__ void daxpy(T* __restrict__ x, T* __restrict__ y, const T coef, int Niter, int N) {
|
2023-08-14 21:17:55 +05:30
|
|
|
|
const int istart = threadIdx.x + blockIdx.x * blockDim.x;
|
|
|
|
|
|
const int ishift = blockDim.x * gridDim.x;
|
|
|
|
|
|
for (int iter = 0; iter < Niter; ++iter) {
|
|
|
|
|
|
T iv = coef * iter;
|
2025-08-15 16:09:19 -04:00
|
|
|
|
for (int i = istart; i < N; i += ishift) y[i] = iv * x[i] + y[i];
|
2023-08-14 21:17:55 +05:30
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-15 16:09:19 -04:00
|
|
|
|
template <class T> class hipPerfMemFill {
|
2023-08-14 21:17:55 +05:30
|
|
|
|
private:
|
|
|
|
|
|
static constexpr int NUM_START = 27;
|
2025-01-13 17:55:06 -05:00
|
|
|
|
static constexpr int NUM_SIZE = 4;
|
2023-08-14 21:17:55 +05:30
|
|
|
|
static constexpr int NUM_ITER = 10;
|
|
|
|
|
|
static constexpr double NUM_1GB = 1024.0 * 1024.0 * 1024.0;
|
|
|
|
|
|
size_t totalSizes_[NUM_SIZE];
|
|
|
|
|
|
hipDeviceProp_t props_;
|
|
|
|
|
|
const T coef_ = getCoefficient(3.14159);
|
|
|
|
|
|
const unsigned int threadsPerBlock_ = 64;
|
|
|
|
|
|
unsigned int blocksPerCU_;
|
|
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
hipPerfMemFill() {
|
|
|
|
|
|
for (int i = 0; i < NUM_SIZE; i++) {
|
2025-08-15 16:09:19 -04:00
|
|
|
|
// 128M, 256M, 512M, 1024M
|
2023-08-14 21:17:55 +05:30
|
|
|
|
totalSizes_[i] = 1ull << (i + NUM_START);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-15 16:09:19 -04:00
|
|
|
|
~hipPerfMemFill() {}
|
2023-08-14 21:17:55 +05:30
|
|
|
|
|
2025-08-15 16:09:19 -04:00
|
|
|
|
bool supportLargeBar() { return props_.isLargeBar != 0; }
|
2023-08-14 21:17:55 +05:30
|
|
|
|
|
2025-08-15 16:09:19 -04:00
|
|
|
|
bool supportManagedMemory() { return props_.managedMemory != 0; }
|
2023-08-14 21:17:55 +05:30
|
|
|
|
|
2025-08-15 16:09:19 -04:00
|
|
|
|
const T getCoefficient(double val) { return static_cast<T>(val); }
|
2023-08-14 21:17:55 +05:30
|
|
|
|
|
2025-08-15 16:09:19 -04:00
|
|
|
|
void setHostBuffer(T* A, T val, size_t size) {
|
2023-08-14 21:17:55 +05:30
|
|
|
|
size_t len = size / sizeof(T);
|
|
|
|
|
|
for (int i = 0; i < len; i++) {
|
|
|
|
|
|
A[i] = val;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool open(int deviceId) {
|
|
|
|
|
|
int nGpu = 0;
|
|
|
|
|
|
HIP_CHECK(hipGetDeviceCount(&nGpu));
|
|
|
|
|
|
if (nGpu < 1) {
|
|
|
|
|
|
printf("No GPU!");
|
|
|
|
|
|
return false;
|
|
|
|
|
|
} else if (deviceId >= nGpu) {
|
|
|
|
|
|
printf("Info: wrong GPU Id %d\n", deviceId);
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
HIP_CHECK(hipSetDevice(deviceId));
|
|
|
|
|
|
memset(&props_, 0, sizeof(props_));
|
|
|
|
|
|
HIP_CHECK(hipGetDeviceProperties(&props_, deviceId));
|
|
|
|
|
|
blocksPerCU_ = props_.multiProcessorCount * 4;
|
|
|
|
|
|
|
2025-08-15 16:09:19 -04:00
|
|
|
|
std::cout << "Info: running on device: id: " << deviceId << ", bus: 0x" << props_.pciBusID
|
|
|
|
|
|
<< " " << props_.name << " with " << props_.multiProcessorCount
|
|
|
|
|
|
<< " CUs, large bar: " << supportLargeBar()
|
|
|
|
|
|
<< ", managed memory: " << supportManagedMemory()
|
|
|
|
|
|
<< ", DeviceMallocFinegrained: " << supportDeviceMallocFinegrained() << std::endl;
|
2023-08-14 21:17:55 +05:30
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void log_host(const char* title, double GBytes, double sec) {
|
2025-08-15 16:09:19 -04:00
|
|
|
|
std::cout << title << " [" << std::setw(7) << GBytes << " GB]: cost " << std::setw(10) << sec
|
|
|
|
|
|
<< " s in bandwidth " << std::setw(10) << GBytes / sec << " [GB/s]" << std::endl;
|
2023-08-14 21:17:55 +05:30
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-15 16:09:19 -04:00
|
|
|
|
void log_kernel(const char* title, double GBytes, double sec, double sec_hv, double sec_kv) {
|
|
|
|
|
|
std::cout << title << " [" << std::setw(7) << GBytes << " GB]: cost " << std::setw(10) << sec
|
|
|
|
|
|
<< " s in bandwidth " << std::setw(10) << GBytes / sec << " [GB/s]"
|
|
|
|
|
|
<< ", hostVerify cost " << std::setw(10) << sec_hv << " s in bandwidth "
|
|
|
|
|
|
<< std::setw(10) << GBytes / sec_hv << " [GB/s]" << ", kernelVerify cost "
|
|
|
|
|
|
<< std::setw(10) << sec_kv << " s in bandwidth " << std::setw(10) << GBytes / sec_kv
|
|
|
|
|
|
<< " [GB/s]" << std::endl;
|
2023-08-14 21:17:55 +05:30
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-15 16:09:19 -04:00
|
|
|
|
void hostFill(size_t size, T* data, T coef, double* sec) {
|
2023-08-14 21:17:55 +05:30
|
|
|
|
size_t num = size / sizeof(T); // Size of elements
|
|
|
|
|
|
auto start = std::chrono::steady_clock::now();
|
|
|
|
|
|
for (int i = 0; i < num; ++i) {
|
|
|
|
|
|
#if SIMPLY_ASSIGN
|
|
|
|
|
|
data[i] = coef;
|
|
|
|
|
|
#else
|
|
|
|
|
|
data[i] = coef * i;
|
|
|
|
|
|
#endif
|
|
|
|
|
|
}
|
|
|
|
|
|
auto end = std::chrono::steady_clock::now();
|
|
|
|
|
|
std::chrono::duration<double> diff = end - start; // in second
|
|
|
|
|
|
*sec = diff.count();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-15 16:09:19 -04:00
|
|
|
|
void kernelFill(size_t size, T* data, T coef, double* sec) {
|
2023-08-14 21:17:55 +05:30
|
|
|
|
size_t num = size / sizeof(T); // Size of elements
|
|
|
|
|
|
unsigned blocks = setNumBlocks(num);
|
|
|
|
|
|
|
|
|
|
|
|
// kernel will be loaded first time
|
2025-08-15 16:09:19 -04:00
|
|
|
|
hipLaunchKernelGGL(HIP_KERNEL_NAME(vec_fill<T>), dim3(blocks), dim3(threadsPerBlock_), 0, 0,
|
|
|
|
|
|
data, 0, num);
|
2023-08-14 21:17:55 +05:30
|
|
|
|
HIP_CHECK(hipDeviceSynchronize());
|
|
|
|
|
|
|
|
|
|
|
|
auto start = std::chrono::steady_clock::now();
|
|
|
|
|
|
|
|
|
|
|
|
for (int iter = 0; iter < NUM_ITER; ++iter) {
|
2025-08-15 16:09:19 -04:00
|
|
|
|
hipLaunchKernelGGL(HIP_KERNEL_NAME(vec_fill<T>), dim3(blocks), dim3(threadsPerBlock_), 0, 0,
|
|
|
|
|
|
data, coef, num);
|
2023-08-14 21:17:55 +05:30
|
|
|
|
}
|
|
|
|
|
|
HIP_CHECK(hipDeviceSynchronize());
|
|
|
|
|
|
|
|
|
|
|
|
auto end = std::chrono::steady_clock::now();
|
|
|
|
|
|
std::chrono::duration<double> diff = end - start; // in second
|
2025-08-15 16:09:19 -04:00
|
|
|
|
*sec = diff.count() / NUM_ITER; // in second
|
2023-08-14 21:17:55 +05:30
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-15 16:09:19 -04:00
|
|
|
|
void hostVerify(size_t size, T* data, T coef, double* sec) {
|
2023-08-14 21:17:55 +05:30
|
|
|
|
size_t num = size / sizeof(T); // Size of elements
|
|
|
|
|
|
auto start = std::chrono::steady_clock::now();
|
|
|
|
|
|
for (int i = 0; i < num; ++i) {
|
|
|
|
|
|
#if SIMPLY_ASSIGN
|
|
|
|
|
|
if (data[i] != coef) {
|
|
|
|
|
|
std::cout << "hostVerify failed: i=" << i << ", data[i]=" << data[i]
|
|
|
|
|
|
<< ", expected=" << coef << std::endl;
|
|
|
|
|
|
REQUIRE(false);
|
|
|
|
|
|
}
|
|
|
|
|
|
#else
|
|
|
|
|
|
if (data[i] != coef * i) {
|
|
|
|
|
|
std::cout << "hostVerify failed: i=" << i << ", data[i]=" << data[i]
|
|
|
|
|
|
<< ", expected=" << coef * i << std::endl;
|
|
|
|
|
|
REQUIRE(false);
|
|
|
|
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
|
|
}
|
|
|
|
|
|
auto end = std::chrono::steady_clock::now();
|
|
|
|
|
|
std::chrono::duration<double> diff = end - start; // in second
|
|
|
|
|
|
*sec = diff.count();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-15 16:09:19 -04:00
|
|
|
|
void kernelVerify(size_t size, T* data, T coef, double* sec) {
|
2023-08-14 21:17:55 +05:30
|
|
|
|
size_t num = size / sizeof(T); // Size of elements
|
|
|
|
|
|
unsigned blocks = setNumBlocks(num);
|
|
|
|
|
|
|
|
|
|
|
|
// kernel will be loaded first time
|
2025-08-15 16:09:19 -04:00
|
|
|
|
hipLaunchKernelGGL(HIP_KERNEL_NAME(vec_verify<T>), dim3(blocks), dim3(threadsPerBlock_), 0, 0,
|
|
|
|
|
|
data, coef, num);
|
2023-08-14 21:17:55 +05:30
|
|
|
|
HIP_CHECK(hipDeviceSynchronize());
|
|
|
|
|
|
|
|
|
|
|
|
// Now all data verified. The following is to test bandwidth.
|
|
|
|
|
|
auto start = std::chrono::steady_clock::now();
|
|
|
|
|
|
|
|
|
|
|
|
for (int iter = 0; iter < NUM_ITER; ++iter) {
|
2025-08-15 16:09:19 -04:00
|
|
|
|
hipLaunchKernelGGL(HIP_KERNEL_NAME(vec_verify<T>), dim3(blocks), dim3(threadsPerBlock_), 0, 0,
|
|
|
|
|
|
data, coef, num);
|
2023-08-14 21:17:55 +05:30
|
|
|
|
}
|
|
|
|
|
|
HIP_CHECK(hipDeviceSynchronize());
|
|
|
|
|
|
|
|
|
|
|
|
auto end = std::chrono::steady_clock::now();
|
|
|
|
|
|
std::chrono::duration<double> diff = end - start; // in second
|
2025-08-15 16:09:19 -04:00
|
|
|
|
*sec = diff.count() / NUM_ITER; // in second
|
2023-08-14 21:17:55 +05:30
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool testLargeBarDeviceMemoryHostFill(size_t size) {
|
|
|
|
|
|
if (!supportLargeBar()) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
double GBytes = static_cast<double>(size) / NUM_1GB;
|
|
|
|
|
|
|
2025-08-15 16:09:19 -04:00
|
|
|
|
T* A;
|
2023-08-14 21:17:55 +05:30
|
|
|
|
HIP_CHECK(hipMalloc(&A, size));
|
|
|
|
|
|
double sec = 0;
|
|
|
|
|
|
hostFill(size, A, coef_, &sec); // Cpu can access device mem in LB
|
|
|
|
|
|
HIP_CHECK(hipFree(A));
|
|
|
|
|
|
|
|
|
|
|
|
log_host("Largebar: host fill", GBytes, sec);
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool testLargeBar() {
|
|
|
|
|
|
if (!supportLargeBar()) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
std::cout << "Test large bar device memory host filling" << std::endl;
|
|
|
|
|
|
for (int i = 0; i < NUM_SIZE; i++) {
|
|
|
|
|
|
if (!testLargeBarDeviceMemoryHostFill(totalSizes_[i])) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool testManagedMemoryHostFill(size_t size) {
|
|
|
|
|
|
if (!supportManagedMemory()) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
double GBytes = static_cast<double>(size) / NUM_1GB;
|
|
|
|
|
|
|
2025-08-15 16:09:19 -04:00
|
|
|
|
T* A;
|
2023-08-14 21:17:55 +05:30
|
|
|
|
HIP_CHECK(hipMallocManaged(&A, size));
|
|
|
|
|
|
double sec = 0;
|
|
|
|
|
|
hostFill(size, A, coef_, &sec); // Cpu can access HMM mem
|
|
|
|
|
|
HIP_CHECK(hipFree(A));
|
|
|
|
|
|
|
|
|
|
|
|
log_host("Managed: host fill", GBytes, sec);
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool testManagedMemoryKernelFill(size_t size) {
|
|
|
|
|
|
if (!supportManagedMemory()) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
double GBytes = static_cast<double>(size) / NUM_1GB;
|
|
|
|
|
|
|
2025-08-15 16:09:19 -04:00
|
|
|
|
T* A;
|
2023-08-14 21:17:55 +05:30
|
|
|
|
HIP_CHECK(hipMallocManaged(&A, size));
|
|
|
|
|
|
|
|
|
|
|
|
double sec = 0, sec_hv = 0, sec_kv = 0;
|
|
|
|
|
|
kernelFill(size, A, coef_, &sec);
|
|
|
|
|
|
// Managed memory can be verified by host
|
|
|
|
|
|
hostVerify(size, A, coef_, &sec_hv);
|
|
|
|
|
|
kernelVerify(size, A, coef_, &sec_kv);
|
|
|
|
|
|
HIP_CHECK(hipFree(A));
|
|
|
|
|
|
|
|
|
|
|
|
log_kernel("Managed: kernel fill", GBytes, sec, sec_hv, sec_kv);
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool testManagedMemory() {
|
|
|
|
|
|
if (!supportManagedMemory()) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
std::cout << "Test managed memory host filling" << std::endl;
|
|
|
|
|
|
for (int i = 0; i < NUM_SIZE; i++) {
|
|
|
|
|
|
if (!testManagedMemoryHostFill(totalSizes_[i])) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
std::cout << "Test managed memory kernel filling" << std::endl;
|
|
|
|
|
|
for (int i = 0; i < NUM_SIZE; i++) {
|
|
|
|
|
|
if (!testManagedMemoryKernelFill(totalSizes_[i])) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool testHostMemoryHostFill(size_t size, unsigned int flags) {
|
|
|
|
|
|
double GBytes = static_cast<double>(size) / NUM_1GB;
|
2025-08-15 16:09:19 -04:00
|
|
|
|
T* A;
|
2023-08-14 21:17:55 +05:30
|
|
|
|
HIP_CHECK(hipHostMalloc(&A, size, flags));
|
|
|
|
|
|
double sec = 0;
|
|
|
|
|
|
hostFill(size, A, coef_, &sec);
|
|
|
|
|
|
HIP_CHECK(hipHostFree(A));
|
|
|
|
|
|
|
|
|
|
|
|
log_host("Host: host fill", GBytes, sec);
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool testHostMemoryKernelFill(size_t size, unsigned int flags) {
|
|
|
|
|
|
double GBytes = static_cast<double>(size) / NUM_1GB;
|
|
|
|
|
|
|
2025-08-15 16:09:19 -04:00
|
|
|
|
T* A;
|
|
|
|
|
|
HIP_CHECK(hipHostMalloc(reinterpret_cast<void**>(&A), size, flags));
|
2023-08-14 21:17:55 +05:30
|
|
|
|
double sec = 0, sec_hv = 0, sec_kv = 0;
|
|
|
|
|
|
kernelFill(size, A, coef_, &sec);
|
|
|
|
|
|
hostVerify(size, A, coef_, &sec_hv);
|
|
|
|
|
|
kernelVerify(size, A, coef_, &sec_kv);
|
|
|
|
|
|
HIP_CHECK(hipHostFree(A));
|
|
|
|
|
|
|
|
|
|
|
|
log_kernel("Host: kernel fill", GBytes, sec, sec_hv, sec_kv);
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool testHostMemory() {
|
|
|
|
|
|
std::cout << "Test coherent host memory host filling" << std::endl;
|
|
|
|
|
|
for (int i = 0; i < NUM_SIZE; i++) {
|
|
|
|
|
|
if (!testHostMemoryHostFill(totalSizes_[i], hipHostMallocCoherent)) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
std::cout << "Test non-coherent host memory host filling" << std::endl;
|
|
|
|
|
|
for (int i = 0; i < NUM_SIZE; i++) {
|
|
|
|
|
|
if (!testHostMemoryHostFill(totalSizes_[i], hipHostMallocNonCoherent)) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
std::cout << "Test coherent host memory kernel filling" << std::endl;
|
|
|
|
|
|
for (int i = 0; i < NUM_SIZE; i++) {
|
|
|
|
|
|
if (!testHostMemoryKernelFill(totalSizes_[i], hipHostMallocCoherent)) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
std::cout << "Test non-coherent host memory kernel filling" << std::endl;
|
|
|
|
|
|
for (int i = 0; i < NUM_SIZE; i++) {
|
|
|
|
|
|
if (!testHostMemoryKernelFill(totalSizes_[i], hipHostMallocNonCoherent)) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* This function should be via device attribute query*/
|
|
|
|
|
|
bool supportDeviceMallocFinegrained() {
|
|
|
|
|
|
#ifdef __HIP_PLATFORM_AMD__
|
2025-08-15 16:09:19 -04:00
|
|
|
|
T* A = nullptr;
|
2023-08-14 21:17:55 +05:30
|
|
|
|
hipError_t err;
|
2025-08-15 16:09:19 -04:00
|
|
|
|
|
|
|
|
|
|
err =
|
|
|
|
|
|
hipExtMallocWithFlags(reinterpret_cast<void**>(&A), sizeof(T), hipDeviceMallocFinegrained);
|
2023-08-14 21:17:55 +05:30
|
|
|
|
if (err || !A) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
HIP_CHECK(hipFree(A));
|
|
|
|
|
|
return true;
|
|
|
|
|
|
#else
|
|
|
|
|
|
return false;
|
|
|
|
|
|
#endif
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
unsigned int setNumBlocks(size_t size) {
|
2025-08-15 16:09:19 -04:00
|
|
|
|
size_t num = size / sizeof(T);
|
2023-08-14 21:17:55 +05:30
|
|
|
|
|
|
|
|
|
|
#if USE_HIPTEST_SETNUMBLOCKS
|
|
|
|
|
|
return HipTest::setNumBlocks(blocksPerCU_, threadsPerBlock_, num);
|
|
|
|
|
|
#else
|
|
|
|
|
|
return (num + threadsPerBlock_ - 1) / threadsPerBlock_;
|
|
|
|
|
|
#endif
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef __HIP_PLATFORM_AMD__
|
|
|
|
|
|
bool testExtDeviceMemoryHostFill(size_t size, unsigned int flags) {
|
|
|
|
|
|
double GBytes = static_cast<double>(size) / NUM_1GB;
|
|
|
|
|
|
|
2025-08-15 16:09:19 -04:00
|
|
|
|
T* A = nullptr;
|
|
|
|
|
|
HIP_CHECK(hipExtMallocWithFlags(reinterpret_cast<void**>(&A), size, flags));
|
2023-08-14 21:17:55 +05:30
|
|
|
|
if (!A) {
|
2025-08-15 16:09:19 -04:00
|
|
|
|
std::cout << "failed hipExtMallocWithFlags() with size =" << size << " flags=" << std::hex
|
|
|
|
|
|
<< flags << std::endl;
|
2023-08-14 21:17:55 +05:30
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
double sec = 0;
|
|
|
|
|
|
hostFill(size, A, coef_, &sec); // Cpu can access this mem
|
|
|
|
|
|
HIP_CHECK(hipFree(A));
|
|
|
|
|
|
|
|
|
|
|
|
log_host("ExtDevice: host fill", GBytes, sec);
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool testExtDeviceMemoryKernelFill(size_t size, unsigned int flags) {
|
|
|
|
|
|
double GBytes = static_cast<double>(size) / NUM_1GB;
|
|
|
|
|
|
|
2025-08-15 16:09:19 -04:00
|
|
|
|
T* A = nullptr;
|
|
|
|
|
|
HIP_CHECK(hipExtMallocWithFlags(reinterpret_cast<void**>(&A), size, flags));
|
2023-08-14 21:17:55 +05:30
|
|
|
|
if (!A) {
|
2025-08-15 16:09:19 -04:00
|
|
|
|
std::cout << "failed hipExtMallocWithFlags() with size =" << size << " flags=" << std::hex
|
|
|
|
|
|
<< flags << std::endl;
|
2023-08-14 21:17:55 +05:30
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
double sec = 0, sec_hv = 0, sec_kv = 0;
|
|
|
|
|
|
kernelFill(size, A, coef_, &sec);
|
|
|
|
|
|
// Fine grained device memory can be verified by host
|
|
|
|
|
|
hostVerify(size, A, coef_, &sec_hv);
|
|
|
|
|
|
kernelVerify(size, A, coef_, &sec_kv);
|
|
|
|
|
|
HIP_CHECK(hipFree(A));
|
|
|
|
|
|
|
|
|
|
|
|
log_kernel("ExtDevice: kernel fill", GBytes, sec, sec_hv, sec_kv);
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool testExtDeviceMemory() {
|
2025-08-15 16:09:19 -04:00
|
|
|
|
std::cout << "Test fine grained device memory host filling" << std::endl;
|
2023-08-14 21:17:55 +05:30
|
|
|
|
for (int i = 0; i < NUM_SIZE; i++) {
|
2025-08-15 16:09:19 -04:00
|
|
|
|
if (!testExtDeviceMemoryHostFill(totalSizes_[i], hipDeviceMallocFinegrained)) {
|
2023-08-14 21:17:55 +05:30
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-15 16:09:19 -04:00
|
|
|
|
std::cout << "Test fine grained device memory kernel filling" << std::endl;
|
2023-08-14 21:17:55 +05:30
|
|
|
|
for (int i = 0; i < NUM_SIZE; i++) {
|
2025-08-15 16:09:19 -04:00
|
|
|
|
if (!testExtDeviceMemoryKernelFill(totalSizes_[i], hipDeviceMallocFinegrained)) {
|
2023-08-14 21:17:55 +05:30
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
bool run() {
|
|
|
|
|
|
if (supportLargeBar()) {
|
|
|
|
|
|
if (!testLargeBar()) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (supportManagedMemory()) {
|
|
|
|
|
|
if (!testManagedMemory()) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!testHostMemory()) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef __HIP_PLATFORM_AMD__
|
|
|
|
|
|
if (supportDeviceMallocFinegrained()) {
|
|
|
|
|
|
if (!testExtDeviceMemory()) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2025-08-15 16:09:19 -04:00
|
|
|
|
* Test Description
|
|
|
|
|
|
* ------------------------
|
|
|
|
|
|
* - Verify hipPerfMemFill status.
|
|
|
|
|
|
* Test source
|
|
|
|
|
|
* ------------------------
|
|
|
|
|
|
* - perftests/memory/hipPerfMemFill.cc
|
|
|
|
|
|
* Test requirements
|
|
|
|
|
|
* ------------------------
|
|
|
|
|
|
* - HIP_VERSION >= 5.6
|
|
|
|
|
|
*/
|
2023-08-14 21:17:55 +05:30
|
|
|
|
|
|
|
|
|
|
TEST_CASE("Perf_hipPerfMemFill_test") {
|
|
|
|
|
|
std::cout << "Test int" << std::endl;
|
|
|
|
|
|
hipPerfMemFill<int> hipPerfMemFillInt;
|
|
|
|
|
|
REQUIRE(true == hipPerfMemFillInt.open(0));
|
|
|
|
|
|
REQUIRE(true == hipPerfMemFillInt.run());
|
|
|
|
|
|
|
|
|
|
|
|
std::cout << "Test double" << std::endl;
|
|
|
|
|
|
hipPerfMemFill<double> hipPerfMemFillDouble;
|
|
|
|
|
|
REQUIRE(true == hipPerfMemFillDouble.open(0));
|
|
|
|
|
|
REQUIRE(true == hipPerfMemFillDouble.run());
|
|
|
|
|
|
}
|
2024-03-22 11:17:00 +01:00
|
|
|
|
|
|
|
|
|
|
/**
|
2025-08-15 16:09:19 -04:00
|
|
|
|
* End doxygen group perfMemoryTest.
|
|
|
|
|
|
* @}
|
|
|
|
|
|
*/
|