Files
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

549 lines
19 KiB
C++

//
// MIT License
// Copyright (c) 2019 Jonathan R. Madsen
// 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
// 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.
//
// ---------------------------------------------------------------
//
// PTL implementation file
//
// Description:
//
// Here we copy the memory to GPU and call the GPU kernels
//
//============================================================================//
// C++
// includes all C, CUDA, and C++ header files
#include "sum.hh"
#include "ThreadPool.hh"
#include "profiler.hh"
typedef std::vector<float> farray_t;
typedef std::vector<int64_t> iarray_t;
#define PRINT_HERE(extra) \
printf("[%lu]> %s@'%s':%i %s\n", ThreadPool::get_this_thread_id(), __FUNCTION__, \
__FILE__, __LINE__, extra)
//============================================================================//
#if defined(PTL_USE_NVTX)
static nvtxEventAttributes_t nvtx_thrust_sum;
static nvtxEventAttributes_t nvtx_cuda_sum;
//----------------------------------------------------------------------------//
void
init_nvtx()
{
static bool first = true;
if(!first)
return;
first = false;
nvtx_thrust_sum.version = NVTX_VERSION;
nvtx_thrust_sum.size = NVTX_EVENT_ATTRIB_STRUCT_SIZE;
nvtx_thrust_sum.colorType = NVTX_COLOR_ARGB;
nvtx_thrust_sum.color = 0xff0000ff; /* blue? */
nvtx_thrust_sum.messageType = NVTX_MESSAGE_TYPE_ASCII;
nvtx_thrust_sum.message.ascii = "calc_coords";
nvtx_cuda_sum.version = NVTX_VERSION;
nvtx_cuda_sum.size = NVTX_EVENT_ATTRIB_STRUCT_SIZE;
nvtx_cuda_sum.colorType = NVTX_COLOR_ARGB;
nvtx_cuda_sum.color = 0xffff0000; /* red */
nvtx_cuda_sum.messageType = NVTX_MESSAGE_TYPE_ASCII;
nvtx_cuda_sum.message.ascii = "sort_intersections";
}
#endif
//============================================================================//
int
cuda_device_count()
{
int deviceCount = 0;
cudaError_t error_id = cudaGetDeviceCount(&deviceCount);
if(error_id != cudaSuccess)
return 0;
return deviceCount;
}
//============================================================================//
void
cuda_device_query()
{
static bool first = true;
if(first)
first = false;
else
return;
int deviceCount = 0;
int driverVersion = 0;
int runtimeVersion = 0;
cudaError_t error_id = cudaGetDeviceCount(&deviceCount);
if(error_id != cudaSuccess)
{
printf("cudaGetDeviceCount returned error code %d\n--> %s\n",
static_cast<int>(error_id), cudaGetErrorString(error_id));
if(deviceCount > 0)
{
cudaSetDevice(0);
cudaDeviceProp deviceProp;
cudaGetDeviceProperties(&deviceProp, 0);
printf("\nDevice %d: \"%s\"\n", 0, deviceProp.name);
// Console log
cudaDriverGetVersion(&driverVersion);
cudaRuntimeGetVersion(&runtimeVersion);
printf(" CUDA Driver Version / Runtime Version %d.%d / "
"%d.%d\n",
driverVersion / 1000, (driverVersion % 100) / 10,
runtimeVersion / 1000, (runtimeVersion % 100) / 10);
printf(" CUDA Capability Major/Minor version number: %d.%d\n",
deviceProp.major, deviceProp.minor);
}
return;
}
if(deviceCount == 0)
printf("No available CUDA device(s) detected\n");
else
printf("Detected %d CUDA capable devices\n", deviceCount);
for(int dev = 0; dev < deviceCount; ++dev)
{
cudaSetDevice(dev);
cudaDeviceProp deviceProp;
cudaGetDeviceProperties(&deviceProp, dev);
printf("\nDevice %d: \"%s\"\n", dev, deviceProp.name);
// Console log
cudaDriverGetVersion(&driverVersion);
cudaRuntimeGetVersion(&runtimeVersion);
// This only available in CUDA 4.0-4.2 (but these were only exposed in
// the CUDA Driver API)
int memoryClock;
int memBusWidth;
int L2CacheSize;
printf(" CUDA Driver Version / Runtime Version %d.%d / %d.%d\n",
driverVersion / 1000, (driverVersion % 100) / 10, runtimeVersion / 1000,
(runtimeVersion % 100) / 10);
printf(" CUDA Capability Major/Minor version number: %d.%d\n",
deviceProp.major, deviceProp.minor);
char msg[256];
#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
sprintf_s(msg, sizeof(msg),
" Total amount of global memory: %.0f MBytes "
"(%llu bytes)\n",
static_cast<float>(deviceProp.totalGlobalMem / 1048576.0f),
(unsigned long long) deviceProp.totalGlobalMem);
#else
snprintf(msg, sizeof(msg),
" Total amount of global memory: %.0f MBytes "
"(%llu bytes)\n",
static_cast<float>(deviceProp.totalGlobalMem / 1048576.0f),
(unsigned long long) deviceProp.totalGlobalMem);
#endif
printf("%s", msg);
printf(" GPU Max Clock rate: %.0f MHz (%0.2f "
"GHz)\n",
deviceProp.clockRate * 1e-3f, deviceProp.clockRate * 1e-6f);
#if CUDART_VERSION >= 5000
// This is supported in CUDA 5.0 (runtime API device properties)
printf(" Memory Clock rate: %.0f Mhz\n",
deviceProp.memoryClockRate * 1e-3f);
printf(" Memory Bus Width: %d-bit\n",
deviceProp.memoryBusWidth);
if(deviceProp.l2CacheSize)
{
printf(" L2 Cache Size: %d bytes\n",
deviceProp.l2CacheSize);
}
#else
getCudaAttribute<int>(&memoryClock, CU_DEVICE_ATTRIBUTE_MEMORY_CLOCK_RATE, dev);
printf(" Memory Clock rate: %.0f Mhz\n",
memoryClock * 1e-3f);
getCudaAttribute<int>(&memBusWidth, CU_DEVICE_ATTRIBUTE_GLOBAL_MEMORY_BUS_WIDTH,
dev);
printf(" Memory Bus Width: %d-bit\n", memBusWidth);
getCudaAttribute<int>(&L2CacheSize, CU_DEVICE_ATTRIBUTE_L2_CACHE_SIZE, dev);
if(L2CacheSize)
printf(" L2 Cache Size: %d bytes\n",
L2CacheSize);
#endif
printf(" Maximum Texture Dimension Size (x,y,z) 1D=(%d), 2D=(%d, "
"%d), 3D=(%d, %d, %d)\n",
deviceProp.maxTexture1D, deviceProp.maxTexture2D[0],
deviceProp.maxTexture2D[1], deviceProp.maxTexture3D[0],
deviceProp.maxTexture3D[1], deviceProp.maxTexture3D[2]);
printf(" Maximum Layered 1D Texture Size, (num) layers 1D=(%d), %d "
"layers\n",
deviceProp.maxTexture1DLayered[0], deviceProp.maxTexture1DLayered[1]);
printf(" Maximum Layered 2D Texture Size, (num) layers 2D=(%d, %d), %d "
"layers\n",
deviceProp.maxTexture2DLayered[0], deviceProp.maxTexture2DLayered[1],
deviceProp.maxTexture2DLayered[2]);
printf(" Total amount of constant memory: %lu bytes\n",
deviceProp.totalConstMem);
printf(" Total amount of shared memory per block: %lu bytes\n",
deviceProp.sharedMemPerBlock);
printf(" Total number of registers available per block: %d\n",
deviceProp.regsPerBlock);
printf(" Warp size: %d\n",
deviceProp.warpSize);
printf(" Maximum number of threads per multiprocessor: %d\n",
deviceProp.maxThreadsPerMultiProcessor);
printf(" Maximum number of threads per block: %d\n",
deviceProp.maxThreadsPerBlock);
printf(" Max dimension size of a thread block (x,y,z): (%d, %d, %d)\n",
deviceProp.maxThreadsDim[0], deviceProp.maxThreadsDim[1],
deviceProp.maxThreadsDim[2]);
printf(" Max dimension size of a grid size (x,y,z): (%d, %d, %d)\n",
deviceProp.maxGridSize[0], deviceProp.maxGridSize[1],
deviceProp.maxGridSize[2]);
printf(" Maximum memory pitch: %lu bytes\n",
deviceProp.memPitch);
printf(" Texture alignment: %lu bytes\n",
deviceProp.textureAlignment);
printf(" Concurrent copy and kernel execution: %s with %d copy "
"engine(s)\n",
(deviceProp.deviceOverlap ? "Yes" : "No"), deviceProp.asyncEngineCount);
printf(" Run time limit on kernels: %s\n",
deviceProp.kernelExecTimeoutEnabled ? "Yes" : "No");
printf(" Integrated GPU sharing Host Memory: %s\n",
deviceProp.integrated ? "Yes" : "No");
printf(" Support host page-locked memory mapping: %s\n",
deviceProp.canMapHostMemory ? "Yes" : "No");
printf(" Alignment requirement for Surfaces: %s\n",
deviceProp.surfaceAlignment ? "Yes" : "No");
printf(" Device has ECC support: %s\n",
deviceProp.ECCEnabled ? "Enabled" : "Disabled");
#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
printf(" CUDA Device Driver Mode (TCC or WDDM): %s\n",
deviceProp.tccDriver ? "TCC (Tesla Compute Cluster Driver)"
: "WDDM (Windows Display Driver Model)");
#endif
printf(" Device supports Unified Addressing (UVA): %s\n",
deviceProp.unifiedAddressing ? "Yes" : "No");
printf(" Device supports Compute Preemption: %s\n",
deviceProp.computePreemptionSupported ? "Yes" : "No");
printf(" Supports Cooperative Kernel Launch: %s\n",
deviceProp.cooperativeLaunch ? "Yes" : "No");
printf(" Supports MultiDevice Co-op Kernel Launch: %s\n",
deviceProp.cooperativeMultiDeviceLaunch ? "Yes" : "No");
printf(" Device PCI Domain ID / Bus ID / location ID: %d / %d / %d\n",
deviceProp.pciDomainID, deviceProp.pciBusID, deviceProp.pciDeviceID);
const char* sComputeMode[] = {
"Default (multiple host threads can use ::cudaSetDevice() with "
"device "
"simultaneously)",
"Exclusive (only one host thread in one process is able to use "
"::cudaSetDevice() with this device)",
"Prohibited (no host thread can use ::cudaSetDevice() with this "
"device)",
"Exclusive Process (many threads in one process is able to use "
"::cudaSetDevice() with this device)",
"Unknown",
NULL
};
printf(" Compute Mode:\n");
printf(" < %s >\n", sComputeMode[deviceProp.computeMode]);
}
printf("\n\n");
cudaDeviceSynchronize();
CUDA_CHECK_LAST_ERROR();
}
//============================================================================//
int
cuda_set_device(int device)
{
int deviceCount = cuda_device_count();
if(deviceCount == 0)
return -1;
// don't set to higher than number of devices
device = device % deviceCount;
// update thread-static variable
this_thread_device() = device;
// actually set the device
cudaSetDevice(device);
// return the modulus
return device;
}
//============================================================================//
int
cuda_multi_processor_count()
{
if(cuda_device_count() == 0)
return 0;
// keep from querying device
static thread_local cuda_device_info<int>* _instance = new cuda_device_info<int>();
// use the thread assigned devices
int device = this_thread_device();
if(_instance->find(device) != _instance->end())
return _instance->find(device)->second;
cudaSetDevice(device);
cudaDeviceProp deviceProp;
cudaGetDeviceProperties(&deviceProp, device);
return ((*_instance)[device] = deviceProp.multiProcessorCount);
}
//============================================================================//
int
cuda_max_threads_per_block()
{
if(cuda_device_count() == 0)
return 0;
// keep from querying device
static thread_local cuda_device_info<int>* _instance = new cuda_device_info<int>();
// use the thread assigned devices
int device = this_thread_device();
if(_instance->find(device) != _instance->end())
return _instance->find(device)->second;
cudaSetDevice(device);
cudaDeviceProp deviceProp;
cudaGetDeviceProperties(&deviceProp, device);
return ((*_instance)[device] = deviceProp.maxThreadsPerBlock);
}
//============================================================================//
int
cuda_warp_size()
{
if(cuda_device_count() == 0)
return 0;
// keep from querying device
static thread_local cuda_device_info<int>* _instance = new cuda_device_info<int>();
// use the thread assigned devices
int device = this_thread_device();
if(_instance->find(device) != _instance->end())
return _instance->find(device)->second;
cudaSetDevice(device);
cudaDeviceProp deviceProp;
cudaGetDeviceProperties(&deviceProp, device);
return ((*_instance)[device] = deviceProp.warpSize);
}
//============================================================================//
int
cuda_shared_memory_per_block()
{
if(cuda_device_count() == 0)
return 0;
// keep from querying device
static thread_local cuda_device_info<int>* _instance = new cuda_device_info<int>();
// use the thread assigned devices
int device = this_thread_device();
if(_instance->find(device) != _instance->end())
return _instance->find(device)->second;
cudaSetDevice(device);
cudaDeviceProp deviceProp;
cudaGetDeviceProperties(&deviceProp, device);
return ((*_instance)[device] = deviceProp.sharedMemPerBlock);
}
//============================================================================//
float
compute_sum(farray_t& cpu_data)
{
NVTX_RANGE_PUSH(&nvtx_cuda_sum);
static thread_local uint64_t tid = ThreadPool::get_this_thread_id();
static thread_local cudaStream_t& stream = cuda_streams::instance()->get(tid);
float _sum = 0.0f;
uintmax_t grainsize = static_cast<uintmax_t>(cuda_max_threads_per_block());
float* buffer = gpu_malloc<float>(grainsize);
if(cpu_data.size() > grainsize)
{
uintmax_t nitr = cpu_data.size() / grainsize;
uintmax_t nmod = cpu_data.size() % grainsize;
if(nmod > 0)
++nitr;
uintmax_t nrem = (nmod > 0) ? nmod : grainsize;
aligned_ptr<float> gpu_data = aligned_gpu_malloc<float, 512>(grainsize);
auto offset = 0;
for(uintmax_t i = 0; i < nitr; ++i)
{
uintmax_t size = grainsize;
if(i + 1 == nitr)
size = nrem;
async_gpu_memcpy(gpu_data.ptr, cpu_data.data() + offset, size, stream);
gpu_data.size = size;
float _tmp_sum = compute_sum_host(gpu_data, stream, false, buffer);
_sum += _tmp_sum;
offset += size;
}
gpu_data.free();
}
else
{
aligned_ptr<float> gpu_data = aligned_async_malloc_and_memcpy<float, 512>(
cpu_data.data(), cpu_data.size(), stream);
float _tmp_sum = compute_sum_host(gpu_data, stream, false, buffer);
_sum += _tmp_sum;
gpu_data.free();
}
cudaFree(buffer);
NVTX_RANGE_POP(stream);
return _sum;
}
//============================================================================//
float
compute_sum(thrust::host_vector<float>& cpu_data)
{
NVTX_RANGE_PUSH(&nvtx_thrust_sum);
static thread_local uint64_t tid = ThreadPool::get_this_thread_id();
static thread_local cudaStream_t& stream = cuda_streams::instance()->get(tid);
float* buffer = nullptr;
aligned_ptr<float> gpu_data = aligned_async_malloc_and_memcpy<float, 512>(
cpu_data.data(), cpu_data.size(), stream);
float _sum = compute_sum_host(gpu_data, stream, true, buffer);
NVTX_RANGE_POP(stream);
return _sum;
}
//============================================================================//
uint64_t
run_gpu(uint64_t n)
{
cuda_device_query();
set_this_thread_device();
// constants
const float factor = 1.0f;
const float epsilon = std::numeric_limits<float>::epsilon();
const uint64_t scale = 1;
const uint64_t size = scale * n;
// const solution
const float real_sum = factor * size;
auto check = [&](const float& calc_sum) {
uint64_t _ret = (abs(real_sum - calc_sum) < epsilon) ? 1 : 0;
if(_ret == 0)
printf("[%lu] > incorrect GPU summation. real = %g, calculated = %g\n",
ThreadPool::get_this_thread_id(), real_sum, calc_sum);
return _ret;
};
uint64_t ret = 0;
{
// data
// farray_t data(size, factor);
// computed results
// float calc_sum = compute_sum(data);
// check if same
// ret += check(calc_sum);
ret += 1;
// PRINT_HERE(std::string(std::string("calc : ") +
// std::to_string(calc_sum) +
// std::string(", ") +
// std::string("real : ") +
// std::to_string(real_sum)).c_str());
}
{
// data
thrust::host_vector<float> thrust_data(size, factor);
// solution
float real_sum = factor * size;
// computed results
float calc_sum = compute_sum(thrust_data);
// PRINT_HERE(std::string(std::string("calc : ") +
// std::to_string(calc_sum) +
// std::string(", ") +
// std::string("real : ") +
// std::to_string(real_sum)).c_str());
// check if same
ret += check(calc_sum);
}
return (ret < 2) ? 0 : 1;
}
//============================================================================//