mirror of
https://github.com/NVIDIA/cuda-samples.git
synced 2026-10-25 22:28:17 +08:00
Apply consistent code formatting across the repo. Add clang-format and pre-commit hooks.
This commit is contained in:
@@ -30,4 +30,3 @@ cuMemcpyDtoH, cuDeviceCanAccessPeer, cuModuleGetFunction, cuMemSetAccess, cuMemR
|
||||
Download and install the [CUDA Toolkit 12.5](https://developer.nvidia.com/cuda-downloads) for your corresponding platform.
|
||||
|
||||
## References (for more details)
|
||||
|
||||
|
||||
@@ -29,172 +29,172 @@
|
||||
|
||||
static size_t round_up(size_t x, size_t y) { return ((x + y - 1) / y) * y; }
|
||||
|
||||
CUresult simpleMallocMultiDeviceMmap(
|
||||
CUdeviceptr *dptr, size_t *allocationSize, size_t size,
|
||||
const std::vector<CUdevice> &residentDevices,
|
||||
const std::vector<CUdevice> &mappingDevices, size_t align) {
|
||||
CUresult status = CUDA_SUCCESS;
|
||||
size_t min_granularity = 0;
|
||||
size_t stripeSize;
|
||||
CUresult simpleMallocMultiDeviceMmap(CUdeviceptr *dptr,
|
||||
size_t *allocationSize,
|
||||
size_t size,
|
||||
const std::vector<CUdevice> &residentDevices,
|
||||
const std::vector<CUdevice> &mappingDevices,
|
||||
size_t align)
|
||||
{
|
||||
CUresult status = CUDA_SUCCESS;
|
||||
size_t min_granularity = 0;
|
||||
size_t stripeSize;
|
||||
|
||||
// Setup the properties common for all the chunks
|
||||
// The allocations will be device pinned memory.
|
||||
// This property structure describes the physical location where the memory
|
||||
// will be allocated via cuMemCreate allong with additional properties In this
|
||||
// case, the allocation will be pinnded device memory local to a given device.
|
||||
CUmemAllocationProp prop = {};
|
||||
prop.type = CU_MEM_ALLOCATION_TYPE_PINNED;
|
||||
prop.location.type = CU_MEM_LOCATION_TYPE_DEVICE;
|
||||
// Setup the properties common for all the chunks
|
||||
// The allocations will be device pinned memory.
|
||||
// This property structure describes the physical location where the memory
|
||||
// will be allocated via cuMemCreate allong with additional properties In this
|
||||
// case, the allocation will be pinnded device memory local to a given device.
|
||||
CUmemAllocationProp prop = {};
|
||||
prop.type = CU_MEM_ALLOCATION_TYPE_PINNED;
|
||||
prop.location.type = CU_MEM_LOCATION_TYPE_DEVICE;
|
||||
|
||||
// Get the minimum granularity needed for the resident devices
|
||||
// (the max of the minimum granularity of each participating device)
|
||||
for (int idx = 0; idx < residentDevices.size(); idx++) {
|
||||
size_t granularity = 0;
|
||||
// Get the minimum granularity needed for the resident devices
|
||||
// (the max of the minimum granularity of each participating device)
|
||||
for (int idx = 0; idx < residentDevices.size(); idx++) {
|
||||
size_t granularity = 0;
|
||||
|
||||
// get the minnimum granularity for residentDevices[idx]
|
||||
prop.location.id = residentDevices[idx];
|
||||
status = cuMemGetAllocationGranularity(&granularity, &prop,
|
||||
CU_MEM_ALLOC_GRANULARITY_MINIMUM);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
goto done;
|
||||
}
|
||||
if (min_granularity < granularity) {
|
||||
min_granularity = granularity;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the minimum granularity needed for the accessing devices
|
||||
// (the max of the minimum granularity of each participating device)
|
||||
for (size_t idx = 0; idx < mappingDevices.size(); idx++) {
|
||||
size_t granularity = 0;
|
||||
|
||||
// get the minnimum granularity for mappingDevices[idx]
|
||||
prop.location.id = mappingDevices[idx];
|
||||
status = cuMemGetAllocationGranularity(&granularity, &prop,
|
||||
CU_MEM_ALLOC_GRANULARITY_MINIMUM);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
goto done;
|
||||
}
|
||||
if (min_granularity < granularity) {
|
||||
min_granularity = granularity;
|
||||
}
|
||||
}
|
||||
|
||||
// Round up the size such that we can evenly split it into a stripe size tha
|
||||
// meets the granularity requirements Essentially size = N *
|
||||
// residentDevices.size() * min_granularity is the requirement, since each
|
||||
// piece of the allocation will be stripeSize = N * min_granularity and the
|
||||
// min_granularity requirement applies to each stripeSize piece of the
|
||||
// allocation.
|
||||
size = round_up(size, residentDevices.size() * min_granularity);
|
||||
stripeSize = size / residentDevices.size();
|
||||
|
||||
// Return the rounded up size to the caller for use in the free
|
||||
if (allocationSize) {
|
||||
*allocationSize = size;
|
||||
}
|
||||
|
||||
// Reserve the required contiguous VA space for the allocations
|
||||
status = cuMemAddressReserve(dptr, size, align, 0, 0);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
// Create and map the backings on each gpu
|
||||
// note: reusing CUmemAllocationProp prop from earlier with prop.type &
|
||||
// prop.location.type already specified.
|
||||
for (size_t idx = 0; idx < residentDevices.size(); idx++) {
|
||||
CUresult status2 = CUDA_SUCCESS;
|
||||
|
||||
// Set the location for this chunk to this device
|
||||
prop.location.id = residentDevices[idx];
|
||||
|
||||
// Create the allocation as a pinned allocation on this device
|
||||
CUmemGenericAllocationHandle allocationHandle;
|
||||
status = cuMemCreate(&allocationHandle, stripeSize, &prop, 0);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
goto done;
|
||||
// get the minnimum granularity for residentDevices[idx]
|
||||
prop.location.id = residentDevices[idx];
|
||||
status = cuMemGetAllocationGranularity(&granularity, &prop, CU_MEM_ALLOC_GRANULARITY_MINIMUM);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
goto done;
|
||||
}
|
||||
if (min_granularity < granularity) {
|
||||
min_granularity = granularity;
|
||||
}
|
||||
}
|
||||
|
||||
// Assign the chunk to the appropriate VA range and release the handle.
|
||||
// After mapping the memory, it can be referenced by virtual address.
|
||||
// Since we do not need to make any other mappings of this memory or export
|
||||
// it, we no longer need and can release the allocationHandle. The
|
||||
// allocation will be kept live until it is unmapped.
|
||||
status = cuMemMap(*dptr + (stripeSize * idx), stripeSize, 0,
|
||||
allocationHandle, 0);
|
||||
|
||||
// the handle needs to be released even if the mapping failed.
|
||||
status2 = cuMemRelease(allocationHandle);
|
||||
if (status == CUDA_SUCCESS) {
|
||||
// cuMemRelease should not have failed here
|
||||
// as the handle was just allocated successfully
|
||||
// however return an error if it does.
|
||||
status = status2;
|
||||
}
|
||||
|
||||
// Cleanup in case of any mapping failures.
|
||||
if (status != CUDA_SUCCESS) {
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// Each accessDescriptor will describe the mapping requirement for a single
|
||||
// device
|
||||
std::vector<CUmemAccessDesc> accessDescriptors;
|
||||
accessDescriptors.resize(mappingDevices.size());
|
||||
|
||||
// Prepare the access descriptor array indicating where and how the backings
|
||||
// should be visible.
|
||||
// Get the minimum granularity needed for the accessing devices
|
||||
// (the max of the minimum granularity of each participating device)
|
||||
for (size_t idx = 0; idx < mappingDevices.size(); idx++) {
|
||||
// Specify which device we are adding mappings for.
|
||||
accessDescriptors[idx].location.type = CU_MEM_LOCATION_TYPE_DEVICE;
|
||||
accessDescriptors[idx].location.id = mappingDevices[idx];
|
||||
size_t granularity = 0;
|
||||
|
||||
// Specify both read and write access.
|
||||
accessDescriptors[idx].flags = CU_MEM_ACCESS_FLAGS_PROT_READWRITE;
|
||||
// get the minnimum granularity for mappingDevices[idx]
|
||||
prop.location.id = mappingDevices[idx];
|
||||
status = cuMemGetAllocationGranularity(&granularity, &prop, CU_MEM_ALLOC_GRANULARITY_MINIMUM);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
goto done;
|
||||
}
|
||||
if (min_granularity < granularity) {
|
||||
min_granularity = granularity;
|
||||
}
|
||||
}
|
||||
|
||||
// Apply the access descriptors to the whole VA range.
|
||||
status = cuMemSetAccess(*dptr, size, &accessDescriptors[0],
|
||||
accessDescriptors.size());
|
||||
// Round up the size such that we can evenly split it into a stripe size tha
|
||||
// meets the granularity requirements Essentially size = N *
|
||||
// residentDevices.size() * min_granularity is the requirement, since each
|
||||
// piece of the allocation will be stripeSize = N * min_granularity and the
|
||||
// min_granularity requirement applies to each stripeSize piece of the
|
||||
// allocation.
|
||||
size = round_up(size, residentDevices.size() * min_granularity);
|
||||
stripeSize = size / residentDevices.size();
|
||||
|
||||
// Return the rounded up size to the caller for use in the free
|
||||
if (allocationSize) {
|
||||
*allocationSize = size;
|
||||
}
|
||||
|
||||
// Reserve the required contiguous VA space for the allocations
|
||||
status = cuMemAddressReserve(dptr, size, align, 0, 0);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
goto done;
|
||||
goto done;
|
||||
}
|
||||
|
||||
// Create and map the backings on each gpu
|
||||
// note: reusing CUmemAllocationProp prop from earlier with prop.type &
|
||||
// prop.location.type already specified.
|
||||
for (size_t idx = 0; idx < residentDevices.size(); idx++) {
|
||||
CUresult status2 = CUDA_SUCCESS;
|
||||
|
||||
// Set the location for this chunk to this device
|
||||
prop.location.id = residentDevices[idx];
|
||||
|
||||
// Create the allocation as a pinned allocation on this device
|
||||
CUmemGenericAllocationHandle allocationHandle;
|
||||
status = cuMemCreate(&allocationHandle, stripeSize, &prop, 0);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
// Assign the chunk to the appropriate VA range and release the handle.
|
||||
// After mapping the memory, it can be referenced by virtual address.
|
||||
// Since we do not need to make any other mappings of this memory or export
|
||||
// it, we no longer need and can release the allocationHandle. The
|
||||
// allocation will be kept live until it is unmapped.
|
||||
status = cuMemMap(*dptr + (stripeSize * idx), stripeSize, 0, allocationHandle, 0);
|
||||
|
||||
// the handle needs to be released even if the mapping failed.
|
||||
status2 = cuMemRelease(allocationHandle);
|
||||
if (status == CUDA_SUCCESS) {
|
||||
// cuMemRelease should not have failed here
|
||||
// as the handle was just allocated successfully
|
||||
// however return an error if it does.
|
||||
status = status2;
|
||||
}
|
||||
|
||||
// Cleanup in case of any mapping failures.
|
||||
if (status != CUDA_SUCCESS) {
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// Each accessDescriptor will describe the mapping requirement for a single
|
||||
// device
|
||||
std::vector<CUmemAccessDesc> accessDescriptors;
|
||||
accessDescriptors.resize(mappingDevices.size());
|
||||
|
||||
// Prepare the access descriptor array indicating where and how the backings
|
||||
// should be visible.
|
||||
for (size_t idx = 0; idx < mappingDevices.size(); idx++) {
|
||||
// Specify which device we are adding mappings for.
|
||||
accessDescriptors[idx].location.type = CU_MEM_LOCATION_TYPE_DEVICE;
|
||||
accessDescriptors[idx].location.id = mappingDevices[idx];
|
||||
|
||||
// Specify both read and write access.
|
||||
accessDescriptors[idx].flags = CU_MEM_ACCESS_FLAGS_PROT_READWRITE;
|
||||
}
|
||||
|
||||
// Apply the access descriptors to the whole VA range.
|
||||
status = cuMemSetAccess(*dptr, size, &accessDescriptors[0], accessDescriptors.size());
|
||||
if (status != CUDA_SUCCESS) {
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
if (status != CUDA_SUCCESS) {
|
||||
if (*dptr) {
|
||||
simpleFreeMultiDeviceMmap(*dptr, size);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
if (*dptr) {
|
||||
simpleFreeMultiDeviceMmap(*dptr, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
return status;
|
||||
}
|
||||
|
||||
CUresult simpleFreeMultiDeviceMmap(CUdeviceptr dptr, size_t size) {
|
||||
CUresult status = CUDA_SUCCESS;
|
||||
CUresult simpleFreeMultiDeviceMmap(CUdeviceptr dptr, size_t size)
|
||||
{
|
||||
CUresult status = CUDA_SUCCESS;
|
||||
|
||||
// Unmap the mapped virtual memory region
|
||||
// Since the handles to the mapped backing stores have already been released
|
||||
// by cuMemRelease, and these are the only/last mappings referencing them,
|
||||
// The backing stores will be freed.
|
||||
// Since the memory has been unmapped after this call, accessing the specified
|
||||
// va range will result in a fault (unitll it is remapped).
|
||||
status = cuMemUnmap(dptr, size);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
// Free the virtual address region. This allows the virtual address region
|
||||
// to be reused by future cuMemAddressReserve calls. This also allows the
|
||||
// virtual address region to be used by other allocation made through
|
||||
// opperating system calls like malloc & mmap.
|
||||
status = cuMemAddressFree(dptr, size);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
// Unmap the mapped virtual memory region
|
||||
// Since the handles to the mapped backing stores have already been released
|
||||
// by cuMemRelease, and these are the only/last mappings referencing them,
|
||||
// The backing stores will be freed.
|
||||
// Since the memory has been unmapped after this call, accessing the specified
|
||||
// va range will result in a fault (unitll it is remapped).
|
||||
status = cuMemUnmap(dptr, size);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
// Free the virtual address region. This allows the virtual address region
|
||||
// to be reused by future cuMemAddressReserve calls. This also allows the
|
||||
// virtual address region to be used by other allocation made through
|
||||
// opperating system calls like malloc & mmap.
|
||||
status = cuMemAddressFree(dptr, size);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
return status;
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -63,10 +63,12 @@
|
||||
//! handle
|
||||
//! is not needed after its mappings are set up.
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
CUresult simpleMallocMultiDeviceMmap(
|
||||
CUdeviceptr *dptr, size_t *allocationSize, size_t size,
|
||||
const std::vector<CUdevice> &residentDevices,
|
||||
const std::vector<CUdevice> &mappingDevices, size_t align = 0);
|
||||
CUresult simpleMallocMultiDeviceMmap(CUdeviceptr *dptr,
|
||||
size_t *allocationSize,
|
||||
size_t size,
|
||||
const std::vector<CUdevice> &residentDevices,
|
||||
const std::vector<CUdevice> &mappingDevices,
|
||||
size_t align = 0);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//! Frees resources allocated by simpleMallocMultiDeviceMmap
|
||||
|
||||
@@ -36,11 +36,11 @@
|
||||
*/
|
||||
|
||||
// Includes
|
||||
#include <cstring>
|
||||
#include <cuda.h>
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
// includes, project
|
||||
#include <helper_cuda_drvapi.h>
|
||||
@@ -54,115 +54,111 @@
|
||||
using namespace std;
|
||||
|
||||
// Variables
|
||||
CUdevice cuDevice;
|
||||
CUcontext cuContext;
|
||||
CUmodule cuModule;
|
||||
CUfunction vecAdd_kernel;
|
||||
float *h_A;
|
||||
float *h_B;
|
||||
float *h_C;
|
||||
CUdevice cuDevice;
|
||||
CUcontext cuContext;
|
||||
CUmodule cuModule;
|
||||
CUfunction vecAdd_kernel;
|
||||
float *h_A;
|
||||
float *h_B;
|
||||
float *h_C;
|
||||
CUdeviceptr d_A;
|
||||
CUdeviceptr d_B;
|
||||
CUdeviceptr d_C;
|
||||
size_t allocationSize = 0;
|
||||
size_t allocationSize = 0;
|
||||
|
||||
// Functions
|
||||
int CleanupNoFailure();
|
||||
int CleanupNoFailure();
|
||||
void RandomInit(float *, int);
|
||||
|
||||
//define input fatbin file
|
||||
// define input fatbin file
|
||||
#ifndef FATBIN_FILE
|
||||
#define FATBIN_FILE "vectorAdd_kernel64.fatbin"
|
||||
#endif
|
||||
|
||||
// collect all of the devices whose memory can be mapped from cuDevice.
|
||||
vector<CUdevice> getBackingDevices(CUdevice cuDevice) {
|
||||
int num_devices;
|
||||
vector<CUdevice> getBackingDevices(CUdevice cuDevice)
|
||||
{
|
||||
int num_devices;
|
||||
|
||||
checkCudaErrors(cuDeviceGetCount(&num_devices));
|
||||
checkCudaErrors(cuDeviceGetCount(&num_devices));
|
||||
|
||||
vector<CUdevice> backingDevices;
|
||||
backingDevices.push_back(cuDevice);
|
||||
for (int dev = 0; dev < num_devices; dev++) {
|
||||
int capable = 0;
|
||||
int attributeVal = 0;
|
||||
vector<CUdevice> backingDevices;
|
||||
backingDevices.push_back(cuDevice);
|
||||
for (int dev = 0; dev < num_devices; dev++) {
|
||||
int capable = 0;
|
||||
int attributeVal = 0;
|
||||
|
||||
// The mapping device is already in the backingDevices vector
|
||||
if (dev == cuDevice) {
|
||||
continue;
|
||||
// The mapping device is already in the backingDevices vector
|
||||
if (dev == cuDevice) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Only peer capable devices can map each others memory
|
||||
checkCudaErrors(cuDeviceCanAccessPeer(&capable, cuDevice, dev));
|
||||
if (!capable) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// The device needs to support virtual address management for the required
|
||||
// apis to work
|
||||
checkCudaErrors(
|
||||
cuDeviceGetAttribute(&attributeVal, CU_DEVICE_ATTRIBUTE_VIRTUAL_ADDRESS_MANAGEMENT_SUPPORTED, cuDevice));
|
||||
if (attributeVal == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
backingDevices.push_back(dev);
|
||||
}
|
||||
|
||||
// Only peer capable devices can map each others memory
|
||||
checkCudaErrors(cuDeviceCanAccessPeer(&capable, cuDevice, dev));
|
||||
if (!capable) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// The device needs to support virtual address management for the required
|
||||
// apis to work
|
||||
checkCudaErrors(cuDeviceGetAttribute(
|
||||
&attributeVal, CU_DEVICE_ATTRIBUTE_VIRTUAL_ADDRESS_MANAGEMENT_SUPPORTED,
|
||||
cuDevice));
|
||||
if (attributeVal == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
backingDevices.push_back(dev);
|
||||
}
|
||||
return backingDevices;
|
||||
return backingDevices;
|
||||
}
|
||||
|
||||
// Host code
|
||||
int main(int argc, char **argv) {
|
||||
printf("Vector Addition (Driver API)\n");
|
||||
int N = 50000;
|
||||
size_t size = N * sizeof(float);
|
||||
int attributeVal = 0;
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
printf("Vector Addition (Driver API)\n");
|
||||
int N = 50000;
|
||||
size_t size = N * sizeof(float);
|
||||
int attributeVal = 0;
|
||||
|
||||
// Initialize
|
||||
checkCudaErrors(cuInit(0));
|
||||
// Initialize
|
||||
checkCudaErrors(cuInit(0));
|
||||
|
||||
cuDevice = findCudaDeviceDRV(argc, (const char **)argv);
|
||||
cuDevice = findCudaDeviceDRV(argc, (const char **)argv);
|
||||
|
||||
// Check that the selected device supports virtual address management
|
||||
checkCudaErrors(cuDeviceGetAttribute(
|
||||
&attributeVal, CU_DEVICE_ATTRIBUTE_VIRTUAL_ADDRESS_MANAGEMENT_SUPPORTED,
|
||||
cuDevice));
|
||||
printf("Device %d VIRTUAL ADDRESS MANAGEMENT SUPPORTED = %d.\n", cuDevice,
|
||||
attributeVal);
|
||||
if (attributeVal == 0) {
|
||||
printf("Device %d doesn't support VIRTUAL ADDRESS MANAGEMENT.\n", cuDevice);
|
||||
exit(EXIT_WAIVED);
|
||||
}
|
||||
// Check that the selected device supports virtual address management
|
||||
checkCudaErrors(
|
||||
cuDeviceGetAttribute(&attributeVal, CU_DEVICE_ATTRIBUTE_VIRTUAL_ADDRESS_MANAGEMENT_SUPPORTED, cuDevice));
|
||||
printf("Device %d VIRTUAL ADDRESS MANAGEMENT SUPPORTED = %d.\n", cuDevice, attributeVal);
|
||||
if (attributeVal == 0) {
|
||||
printf("Device %d doesn't support VIRTUAL ADDRESS MANAGEMENT.\n", cuDevice);
|
||||
exit(EXIT_WAIVED);
|
||||
}
|
||||
|
||||
// The vector addition happens on cuDevice, so the allocations need to be
|
||||
// mapped there.
|
||||
vector<CUdevice> mappingDevices;
|
||||
mappingDevices.push_back(cuDevice);
|
||||
// The vector addition happens on cuDevice, so the allocations need to be
|
||||
// mapped there.
|
||||
vector<CUdevice> mappingDevices;
|
||||
mappingDevices.push_back(cuDevice);
|
||||
|
||||
// Collect devices accessible by the mapping device (cuDevice) into the
|
||||
// backingDevices vector.
|
||||
vector<CUdevice> backingDevices = getBackingDevices(cuDevice);
|
||||
// Collect devices accessible by the mapping device (cuDevice) into the
|
||||
// backingDevices vector.
|
||||
vector<CUdevice> backingDevices = getBackingDevices(cuDevice);
|
||||
|
||||
// Create context
|
||||
checkCudaErrors(cuCtxCreate(&cuContext, 0, cuDevice));
|
||||
// Create context
|
||||
checkCudaErrors(cuCtxCreate(&cuContext, 0, cuDevice));
|
||||
|
||||
// first search for the module path before we load the results
|
||||
string module_path;
|
||||
|
||||
std::ostringstream fatbin;
|
||||
|
||||
if (!findFatbinPath(FATBIN_FILE, module_path, argv, fatbin))
|
||||
{
|
||||
if (!findFatbinPath(FATBIN_FILE, module_path, argv, fatbin)) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
printf("> initCUDA loading module: <%s>\n", module_path.c_str());
|
||||
}
|
||||
|
||||
if (!fatbin.str().size())
|
||||
{
|
||||
if (!fatbin.str().size()) {
|
||||
printf("fatbin file empty. exiting..\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
@@ -204,13 +200,10 @@ int main(int argc, char **argv) {
|
||||
int threadsPerBlock = 256;
|
||||
int blocksPerGrid = (N + threadsPerBlock - 1) / threadsPerBlock;
|
||||
|
||||
void *args[] = { &d_A, &d_B, &d_C, &N };
|
||||
void *args[] = {&d_A, &d_B, &d_C, &N};
|
||||
|
||||
// Launch the CUDA kernel
|
||||
checkCudaErrors(cuLaunchKernel(vecAdd_kernel, blocksPerGrid, 1, 1,
|
||||
threadsPerBlock, 1, 1,
|
||||
0,
|
||||
NULL, args, NULL));
|
||||
checkCudaErrors(cuLaunchKernel(vecAdd_kernel, blocksPerGrid, 1, 1, threadsPerBlock, 1, 1, 0, NULL, args, NULL));
|
||||
|
||||
// Copy result from device memory to host memory
|
||||
// h_C contains the result in host memory
|
||||
@@ -219,20 +212,18 @@ int main(int argc, char **argv) {
|
||||
// Verify result
|
||||
int i;
|
||||
|
||||
for (i = 0; i < N; ++i)
|
||||
{
|
||||
for (i = 0; i < N; ++i) {
|
||||
float sum = h_A[i] + h_B[i];
|
||||
|
||||
if (fabs(h_C[i] - sum) > 1e-7f)
|
||||
{
|
||||
if (fabs(h_C[i] - sum) > 1e-7f) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
CleanupNoFailure();
|
||||
printf("%s\n", (i==N) ? "Result = PASS" : "Result = FAIL");
|
||||
printf("%s\n", (i == N) ? "Result = PASS" : "Result = FAIL");
|
||||
|
||||
exit((i==N) ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
exit((i == N) ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int CleanupNoFailure()
|
||||
@@ -243,18 +234,15 @@ int CleanupNoFailure()
|
||||
checkCudaErrors(simpleFreeMultiDeviceMmap(d_C, allocationSize));
|
||||
|
||||
// Free host memory
|
||||
if (h_A)
|
||||
{
|
||||
if (h_A) {
|
||||
free(h_A);
|
||||
}
|
||||
|
||||
if (h_B)
|
||||
{
|
||||
if (h_B) {
|
||||
free(h_B);
|
||||
}
|
||||
|
||||
if (h_C)
|
||||
{
|
||||
if (h_C) {
|
||||
free(h_C);
|
||||
}
|
||||
|
||||
@@ -265,8 +253,7 @@ int CleanupNoFailure()
|
||||
// Allocates an array with random float entries.
|
||||
void RandomInit(float *data, int n)
|
||||
{
|
||||
for (int i = 0; i < n; ++i)
|
||||
{
|
||||
for (int i = 0; i < n; ++i) {
|
||||
data[i] = rand() / (float)RAND_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,9 +34,10 @@
|
||||
*/
|
||||
|
||||
// Device code
|
||||
extern "C" __global__ void VecAdd_kernel(const float *A, const float *B,
|
||||
float *C, int N) {
|
||||
int i = blockDim.x * blockIdx.x + threadIdx.x;
|
||||
extern "C" __global__ void VecAdd_kernel(const float *A, const float *B, float *C, int N)
|
||||
{
|
||||
int i = blockDim.x * blockIdx.x + threadIdx.x;
|
||||
|
||||
if (i < N) C[i] = A[i] + B[i];
|
||||
if (i < N)
|
||||
C[i] = A[i] + B[i];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user