Apply consistent code formatting across the repo. Add clang-format and pre-commit hooks.

This commit is contained in:
Rob Armstrong
2025-03-27 10:30:07 -07:00
parent 2cd58fbc9a
commit ceab6e8bcc
782 changed files with 107230 additions and 106548 deletions

View File

@@ -32,149 +32,148 @@
// Utilities and system includes
// includes, system
#include <stdlib.h>
#include <curand.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <curand.h>
// Utilities and system includes
#include <helper_functions.h>
#include <helper_cuda.h>
#include <cuda_runtime.h>
#include <curand.h>
#include <helper_cuda.h>
#include <helper_functions.h>
float compareResults(int rand_n, float *h_RandGPU, float *h_RandCPU);
const int DEFAULT_RAND_N = 2400000;
const unsigned int DEFAULT_SEED = 777;
const int DEFAULT_RAND_N = 2400000;
const unsigned int DEFAULT_SEED = 777;
///////////////////////////////////////////////////////////////////////////////
// Main program
///////////////////////////////////////////////////////////////////////////////
int main(int argc, char **argv) {
// Start logs
printf("%s Starting...\n\n", argv[0]);
int main(int argc, char **argv)
{
// Start logs
printf("%s Starting...\n\n", argv[0]);
// initialize the GPU, either identified by --device
// or by picking the device with highest flop rate.
int devID = findCudaDevice(argc, (const char **)argv);
// initialize the GPU, either identified by --device
// or by picking the device with highest flop rate.
int devID = findCudaDevice(argc, (const char **)argv);
// parsing the number of random numbers to generate
int rand_n = DEFAULT_RAND_N;
// parsing the number of random numbers to generate
int rand_n = DEFAULT_RAND_N;
if (checkCmdLineFlag(argc, (const char **)argv, "count")) {
rand_n = getCmdLineArgumentInt(argc, (const char **)argv, "count");
}
printf("Allocating data for %i samples...\n", rand_n);
// parsing the seed
int seed = DEFAULT_SEED;
if (checkCmdLineFlag(argc, (const char **)argv, "seed")) {
seed = getCmdLineArgumentInt(argc, (const char **)argv, "seed");
}
printf("Seeding with %i ...\n", seed);
cudaStream_t stream;
checkCudaErrors(cudaStreamCreateWithFlags(&stream, cudaStreamNonBlocking));
float *d_Rand;
checkCudaErrors(cudaMalloc((void **)&d_Rand, rand_n * sizeof(float)));
curandGenerator_t prngGPU;
checkCudaErrors(curandCreateGenerator(&prngGPU, CURAND_RNG_PSEUDO_MTGP32));
checkCudaErrors(curandSetStream(prngGPU, stream));
checkCudaErrors(curandSetPseudoRandomGeneratorSeed(prngGPU, seed));
curandGenerator_t prngCPU;
checkCudaErrors(
curandCreateGeneratorHost(&prngCPU, CURAND_RNG_PSEUDO_MTGP32));
checkCudaErrors(curandSetPseudoRandomGeneratorSeed(prngCPU, seed));
//
// Example 1: Compare random numbers generated on GPU and CPU
float *h_RandGPU;
checkCudaErrors(cudaMallocHost(&h_RandGPU, rand_n * sizeof(float)));
printf("Generating random numbers on GPU...\n\n");
checkCudaErrors(curandGenerateUniform(prngGPU, (float *)d_Rand, rand_n));
printf("\nReading back the results...\n");
checkCudaErrors(cudaMemcpyAsync(h_RandGPU, d_Rand, rand_n * sizeof(float),
cudaMemcpyDeviceToHost, stream));
float *h_RandCPU = (float *)malloc(rand_n * sizeof(float));
printf("Generating random numbers on CPU...\n\n");
checkCudaErrors(curandGenerateUniform(prngCPU, (float *)h_RandCPU, rand_n));
checkCudaErrors(cudaStreamSynchronize(stream));
printf("Comparing CPU/GPU random numbers...\n\n");
float L1norm = compareResults(rand_n, h_RandGPU, h_RandCPU);
//
// Example 2: Timing of random number generation on GPU
const int numIterations = 10;
int i;
StopWatchInterface *hTimer;
sdkCreateTimer(&hTimer);
sdkResetTimer(&hTimer);
sdkStartTimer(&hTimer);
for (i = 0; i < numIterations; i++) {
checkCudaErrors(curandGenerateUniform(prngGPU, (float *)d_Rand, rand_n));
}
checkCudaErrors(cudaStreamSynchronize(stream));
sdkStopTimer(&hTimer);
double gpuTime = 1.0e-3 * sdkGetTimerValue(&hTimer) / (double)numIterations;
printf(
"MersenneTwisterGP11213, Throughput = %.4f GNumbers/s, Time = %.5f s, "
"Size = %u Numbers\n",
1.0e-9 * rand_n / gpuTime, gpuTime, rand_n);
printf("Shutting down...\n");
checkCudaErrors(curandDestroyGenerator(prngGPU));
checkCudaErrors(curandDestroyGenerator(prngCPU));
checkCudaErrors(cudaStreamDestroy(stream));
checkCudaErrors(cudaFree(d_Rand));
sdkDeleteTimer(&hTimer);
checkCudaErrors(cudaFreeHost(h_RandGPU));
free(h_RandCPU);
exit(L1norm < 1e-6 ? EXIT_SUCCESS : EXIT_FAILURE);
}
float compareResults(int rand_n, float *h_RandGPU, float *h_RandCPU) {
int i;
float rCPU, rGPU, delta;
float max_delta = 0.;
float sum_delta = 0.;
float sum_ref = 0.;
for (i = 0; i < rand_n; i++) {
rCPU = h_RandCPU[i];
rGPU = h_RandGPU[i];
delta = fabs(rCPU - rGPU);
sum_delta += delta;
sum_ref += fabs(rCPU);
if (delta >= max_delta) {
max_delta = delta;
if (checkCmdLineFlag(argc, (const char **)argv, "count")) {
rand_n = getCmdLineArgumentInt(argc, (const char **)argv, "count");
}
}
float L1norm = (float)(sum_delta / sum_ref);
printf("Max absolute error: %E\n", max_delta);
printf("L1 norm: %E\n\n", L1norm);
printf("Allocating data for %i samples...\n", rand_n);
return L1norm;
// parsing the seed
int seed = DEFAULT_SEED;
if (checkCmdLineFlag(argc, (const char **)argv, "seed")) {
seed = getCmdLineArgumentInt(argc, (const char **)argv, "seed");
}
printf("Seeding with %i ...\n", seed);
cudaStream_t stream;
checkCudaErrors(cudaStreamCreateWithFlags(&stream, cudaStreamNonBlocking));
float *d_Rand;
checkCudaErrors(cudaMalloc((void **)&d_Rand, rand_n * sizeof(float)));
curandGenerator_t prngGPU;
checkCudaErrors(curandCreateGenerator(&prngGPU, CURAND_RNG_PSEUDO_MTGP32));
checkCudaErrors(curandSetStream(prngGPU, stream));
checkCudaErrors(curandSetPseudoRandomGeneratorSeed(prngGPU, seed));
curandGenerator_t prngCPU;
checkCudaErrors(curandCreateGeneratorHost(&prngCPU, CURAND_RNG_PSEUDO_MTGP32));
checkCudaErrors(curandSetPseudoRandomGeneratorSeed(prngCPU, seed));
//
// Example 1: Compare random numbers generated on GPU and CPU
float *h_RandGPU;
checkCudaErrors(cudaMallocHost(&h_RandGPU, rand_n * sizeof(float)));
printf("Generating random numbers on GPU...\n\n");
checkCudaErrors(curandGenerateUniform(prngGPU, (float *)d_Rand, rand_n));
printf("\nReading back the results...\n");
checkCudaErrors(cudaMemcpyAsync(h_RandGPU, d_Rand, rand_n * sizeof(float), cudaMemcpyDeviceToHost, stream));
float *h_RandCPU = (float *)malloc(rand_n * sizeof(float));
printf("Generating random numbers on CPU...\n\n");
checkCudaErrors(curandGenerateUniform(prngCPU, (float *)h_RandCPU, rand_n));
checkCudaErrors(cudaStreamSynchronize(stream));
printf("Comparing CPU/GPU random numbers...\n\n");
float L1norm = compareResults(rand_n, h_RandGPU, h_RandCPU);
//
// Example 2: Timing of random number generation on GPU
const int numIterations = 10;
int i;
StopWatchInterface *hTimer;
sdkCreateTimer(&hTimer);
sdkResetTimer(&hTimer);
sdkStartTimer(&hTimer);
for (i = 0; i < numIterations; i++) {
checkCudaErrors(curandGenerateUniform(prngGPU, (float *)d_Rand, rand_n));
}
checkCudaErrors(cudaStreamSynchronize(stream));
sdkStopTimer(&hTimer);
double gpuTime = 1.0e-3 * sdkGetTimerValue(&hTimer) / (double)numIterations;
printf("MersenneTwisterGP11213, Throughput = %.4f GNumbers/s, Time = %.5f s, "
"Size = %u Numbers\n",
1.0e-9 * rand_n / gpuTime,
gpuTime,
rand_n);
printf("Shutting down...\n");
checkCudaErrors(curandDestroyGenerator(prngGPU));
checkCudaErrors(curandDestroyGenerator(prngCPU));
checkCudaErrors(cudaStreamDestroy(stream));
checkCudaErrors(cudaFree(d_Rand));
sdkDeleteTimer(&hTimer);
checkCudaErrors(cudaFreeHost(h_RandGPU));
free(h_RandCPU);
exit(L1norm < 1e-6 ? EXIT_SUCCESS : EXIT_FAILURE);
}
float compareResults(int rand_n, float *h_RandGPU, float *h_RandCPU)
{
int i;
float rCPU, rGPU, delta;
float max_delta = 0.;
float sum_delta = 0.;
float sum_ref = 0.;
for (i = 0; i < rand_n; i++) {
rCPU = h_RandCPU[i];
rGPU = h_RandGPU[i];
delta = fabs(rCPU - rGPU);
sum_delta += delta;
sum_ref += fabs(rCPU);
if (delta >= max_delta) {
max_delta = delta;
}
}
float L1norm = (float)(sum_delta / sum_ref);
printf("Max absolute error: %E\n", max_delta);
printf("L1 norm: %E\n\n", L1norm);
return L1norm;
}

View File

@@ -114,4 +114,3 @@ Example of using CUFFT. In this example, CUFFT is used to compute the 1D-convolu
### [watershedSegmentationNPP](./watershedSegmentationNPP)
An NPP CUDA Sample that demonstrates how to use the NPP watershed segmentation function.

File diff suppressed because it is too large Load Diff

View File

@@ -37,8 +37,8 @@
#define SWITCH_CHAR '-'
#define REFFUNC(funcname) ref_##funcname
#define TESTGEN(funcname) get_##funcname##_params
#define REFFUNC(funcname) ref_##funcname
#define TESTGEN(funcname) get_##funcname##_params
#define TESTPARAMS(funcname) funcname##TestParams
#define DEV_VER_DBL_SUPPORT (130)
@@ -54,10 +54,11 @@
//==============================================================================
#if defined(__cplusplus)
extern "C" {
extern "C"
{
#endif /* __cplusplus */
int getDeviceVersion(void);
size_t getDeviceMemory(void);
int getDeviceVersion(void);
size_t getDeviceMemory(void);
#if defined(__cplusplus)
}
#endif /* __cplusplus */
@@ -68,71 +69,58 @@ size_t getDeviceMemory(void);
static __inline__ int imax(int x, int y) { return (x > y) ? x : y; }
static __inline__ unsigned floatAsUInt(float x) {
volatile union {
float f;
unsigned i;
} xx;
xx.f = x;
return xx.i;
static __inline__ unsigned floatAsUInt(float x)
{
volatile union
{
float f;
unsigned i;
} xx;
xx.f = x;
return xx.i;
}
static __inline__ unsigned long long doubleAsULL(double x) {
volatile union {
double f;
unsigned long long i;
} xx;
xx.f = x;
return xx.i;
static __inline__ unsigned long long doubleAsULL(double x)
{
volatile union
{
double f;
unsigned long long i;
} xx;
xx.f = x;
return xx.i;
}
static __inline__ unsigned cuRand(void) {
/* George Marsaglia's fast inline random number generator */
static __inline__ unsigned cuRand(void)
{
/* George Marsaglia's fast inline random number generator */
#define CUDA_ZNEW (cuda_z = 36969 * (cuda_z & 65535) + (cuda_z >> 16))
#define CUDA_WNEW (cuda_w = 18000 * (cuda_w & 65535) + (cuda_w >> 16))
#define CUDA_MWC ((CUDA_ZNEW << 16) + CUDA_WNEW)
#define CUDA_SHR3 \
(cuda_jsr = cuda_jsr ^ (cuda_jsr << 17), \
cuda_jsr = cuda_jsr ^ (cuda_jsr >> 13), \
cuda_jsr = cuda_jsr ^ (cuda_jsr << 5))
#define CUDA_MWC ((CUDA_ZNEW << 16) + CUDA_WNEW)
#define CUDA_SHR3 \
(cuda_jsr = cuda_jsr ^ (cuda_jsr << 17), \
cuda_jsr = cuda_jsr ^ (cuda_jsr >> 13), \
cuda_jsr = cuda_jsr ^ (cuda_jsr << 5))
#define CUDA_CONG (cuda_jcong = 69069 * cuda_jcong + 1234567)
#define KISS ((CUDA_MWC ^ CUDA_CONG) + CUDA_SHR3)
static unsigned int cuda_z = 362436069, cuda_w = 521288629;
static unsigned int cuda_jsr = 123456789, cuda_jcong = 380116160;
return KISS;
#define KISS ((CUDA_MWC ^ CUDA_CONG) + CUDA_SHR3)
static unsigned int cuda_z = 362436069, cuda_w = 521288629;
static unsigned int cuda_jsr = 123456789, cuda_jcong = 380116160;
return KISS;
}
//==============================================================================
// cuGet and cuEqual versions
//==============================================================================
template <typename T_ELEM>
__inline__ __device__ __host__ T_ELEM cuGet(double);
template <>
__inline__ __device__ __host__ float cuGet<float>(double x) {
return float(x);
}
template <>
__inline__ __device__ __host__ double cuGet<double>(double x) {
return double(x);
}
template <typename T_ELEM> __inline__ __device__ __host__ T_ELEM cuGet(double);
template <> __inline__ __device__ __host__ float cuGet<float>(double x) { return float(x); }
template <> __inline__ __device__ __host__ double cuGet<double>(double x) { return double(x); }
template <typename T_ELEM>
__inline__ __device__ __host__ T_ELEM cuGet(double, double);
template <>
__inline__ __device__ __host__ float cuGet<float>(double x, double y) {
return float(x);
}
template <>
__inline__ __device__ __host__ double cuGet<double>(double x, double y) {
return double(x);
}
static __inline__ __device__ __host__ bool cuEqual(float x, float y) {
return (x == y);
}
static __inline__ __device__ __host__ bool cuEqual(double x, double y) {
return (x == y);
}
template <typename T_ELEM> __inline__ __device__ __host__ T_ELEM cuGet(double, double);
template <> __inline__ __device__ __host__ float cuGet<float>(double x, double y) { return float(x); }
template <> __inline__ __device__ __host__ double cuGet<double>(double x, double y) { return double(x); }
static __inline__ __device__ __host__ bool cuEqual(float x, float y) { return (x == y); }
static __inline__ __device__ __host__ bool cuEqual(double x, double y) { return (x == y); }
//==============================================================================
// Platform dependent timing utility
@@ -143,33 +131,36 @@ static __inline__ __device__ __host__ bool cuEqual(double x, double y) {
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
static __inline__ double second(void) {
LARGE_INTEGER t;
static double oofreq;
static int checkedForHighResTimer;
static BOOL hasHighResTimer;
static __inline__ double second(void)
{
LARGE_INTEGER t;
static double oofreq;
static int checkedForHighResTimer;
static BOOL hasHighResTimer;
if (!checkedForHighResTimer) {
hasHighResTimer = QueryPerformanceFrequency(&t);
oofreq = 1.0 / (double)t.QuadPart;
checkedForHighResTimer = 1;
}
if (!checkedForHighResTimer) {
hasHighResTimer = QueryPerformanceFrequency(&t);
oofreq = 1.0 / (double)t.QuadPart;
checkedForHighResTimer = 1;
}
if (hasHighResTimer) {
QueryPerformanceCounter(&t);
return (double)t.QuadPart * oofreq;
} else {
return (double)GetTickCount() / 1000.0;
}
if (hasHighResTimer) {
QueryPerformanceCounter(&t);
return (double)t.QuadPart * oofreq;
}
else {
return (double)GetTickCount() / 1000.0;
}
}
#elif defined(__linux__) || defined(__QNX__)
#include <stddef.h>
#include <sys/resource.h>
#include <sys/time.h>
static double second(void) {
struct timeval tv;
gettimeofday(&tv, NULL);
return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;
static double second(void)
{
struct timeval tv;
gettimeofday(&tv, NULL);
return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;
}
#elif defined(__APPLE__)
#include <stddef.h>
@@ -177,10 +168,11 @@ static double second(void) {
#include <sys/sysctl.h>
#include <sys/time.h>
#include <sys/types.h>
static double second(void) {
struct timeval tv;
gettimeofday(&tv, NULL);
return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;
static double second(void)
{
struct timeval tv;
gettimeofday(&tv, NULL);
return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;
}
#else
#error unsupported platform

View File

@@ -36,171 +36,178 @@
#include <ImageIO.h>
#include <ImagesCPU.h>
#include <ImagesNPP.h>
#include <string.h>
#include <fstream>
#include <iostream>
#include <cuda_runtime.h>
#include <npp.h>
#include <fstream>
#include <helper_cuda.h>
#include <helper_string.h>
#include <iostream>
#include <npp.h>
#include <string.h>
int main(int argc, char *argv[]) {
printf("%s Starting...\n\n", argv[0]);
int main(int argc, char *argv[])
{
printf("%s Starting...\n\n", argv[0]);
try {
std::string sFilename;
char *filePath;
NppStreamContext nppStreamCtx;
nppStreamCtx.hStream = 0; // The NULL stream by default, set this to whatever your stream ID is if not the NULL stream.
try {
std::string sFilename;
char *filePath;
NppStreamContext nppStreamCtx;
nppStreamCtx.hStream =
0; // The NULL stream by default, set this to whatever your stream ID is if not the NULL stream.
cudaError_t cudaError = cudaGetDevice(&nppStreamCtx.nCudaDeviceId);
if (cudaError != cudaSuccess)
{
printf("CUDA error: no devices supporting CUDA.\n");
return NPP_NOT_SUFFICIENT_COMPUTE_CAPABILITY;
cudaError_t cudaError = cudaGetDevice(&nppStreamCtx.nCudaDeviceId);
if (cudaError != cudaSuccess) {
printf("CUDA error: no devices supporting CUDA.\n");
return NPP_NOT_SUFFICIENT_COMPUTE_CAPABILITY;
}
const NppLibraryVersion *libVer = nppGetLibVersion();
printf("NPP Library Version %d.%d.%d\n", libVer->major, libVer->minor, libVer->build);
int driverVersion, runtimeVersion;
cudaDriverGetVersion(&driverVersion);
cudaRuntimeGetVersion(&runtimeVersion);
printf("CUDA Driver Version: %d.%d\n", driverVersion / 1000, (driverVersion % 100) / 10);
printf("CUDA Runtime Version: %d.%d\n\n", runtimeVersion / 1000, (runtimeVersion % 100) / 10);
cudaError = cudaDeviceGetAttribute(&nppStreamCtx.nCudaDevAttrComputeCapabilityMajor,
cudaDevAttrComputeCapabilityMajor,
nppStreamCtx.nCudaDeviceId);
if (cudaError != cudaSuccess)
return NPP_NOT_SUFFICIENT_COMPUTE_CAPABILITY;
cudaError = cudaDeviceGetAttribute(&nppStreamCtx.nCudaDevAttrComputeCapabilityMinor,
cudaDevAttrComputeCapabilityMinor,
nppStreamCtx.nCudaDeviceId);
if (cudaError != cudaSuccess)
return NPP_NOT_SUFFICIENT_COMPUTE_CAPABILITY;
cudaError = cudaStreamGetFlags(nppStreamCtx.hStream, &nppStreamCtx.nStreamFlags);
cudaDeviceProp oDeviceProperties;
cudaError = cudaGetDeviceProperties(&oDeviceProperties, nppStreamCtx.nCudaDeviceId);
nppStreamCtx.nMultiProcessorCount = oDeviceProperties.multiProcessorCount;
nppStreamCtx.nMaxThreadsPerMultiProcessor = oDeviceProperties.maxThreadsPerMultiProcessor;
nppStreamCtx.nMaxThreadsPerBlock = oDeviceProperties.maxThreadsPerBlock;
nppStreamCtx.nSharedMemPerBlock = oDeviceProperties.sharedMemPerBlock;
if (checkCmdLineFlag(argc, (const char **)argv, "input")) {
getCmdLineArgumentString(argc, (const char **)argv, "input", &filePath);
}
else {
filePath = sdkFindFilePath("teapot512.pgm", argv[0]);
}
if (filePath) {
sFilename = filePath;
}
else {
sFilename = "teapot512.pgm";
}
// if we specify the filename at the command line, then we only test
// sFilename[0].
int file_errors = 0;
std::ifstream infile(sFilename.data(), std::ifstream::in);
if (infile.good()) {
std::cout << "boxFilterNPP opened: <" << sFilename.data() << "> successfully!" << std::endl;
file_errors = 0;
infile.close();
}
else {
std::cout << "boxFilterNPP unable to open: <" << sFilename.data() << ">" << std::endl;
file_errors++;
infile.close();
}
if (file_errors > 0) {
exit(EXIT_FAILURE);
}
std::string sResultFilename = sFilename;
std::string::size_type dot = sResultFilename.rfind('.');
if (dot != std::string::npos) {
sResultFilename = sResultFilename.substr(0, dot);
}
sResultFilename += "_boxFilter.pgm";
if (checkCmdLineFlag(argc, (const char **)argv, "output")) {
char *outputFilePath;
getCmdLineArgumentString(argc, (const char **)argv, "output", &outputFilePath);
sResultFilename = outputFilePath;
}
// declare a host image object for an 8-bit grayscale image
npp::ImageCPU_8u_C1 oHostSrc;
// load gray-scale image from disk
npp::loadImage(sFilename, oHostSrc);
// declare a device image and copy construct from the host image,
// i.e. upload host to device
npp::ImageNPP_8u_C1 oDeviceSrc(oHostSrc);
// create struct with box-filter mask size
NppiSize oMaskSize = {5, 5};
NppiSize oSrcSize = {(int)oDeviceSrc.width(), (int)oDeviceSrc.height()};
NppiPoint oSrcOffset = {0, 0};
// create struct with ROI size
NppiSize oSizeROI = {(int)oDeviceSrc.width(), (int)oDeviceSrc.height()};
// allocate device image of appropriately reduced size
npp::ImageNPP_8u_C1 oDeviceDst(oSizeROI.width, oSizeROI.height);
// set anchor point inside the mask to (oMaskSize.width / 2,
// oMaskSize.height / 2) It should round down when odd
NppiPoint oAnchor = {oMaskSize.width / 2, oMaskSize.height / 2};
// run box filter
NPP_CHECK_NPP(nppiFilterBoxBorder_8u_C1R_Ctx(oDeviceSrc.data(),
oDeviceSrc.pitch(),
oSrcSize,
oSrcOffset,
oDeviceDst.data(),
oDeviceDst.pitch(),
oSizeROI,
oMaskSize,
oAnchor,
NPP_BORDER_REPLICATE,
nppStreamCtx));
// declare a host image for the result
npp::ImageCPU_8u_C1 oHostDst(oDeviceDst.size());
// and copy the device result data into it
oDeviceDst.copyTo(oHostDst.data(), oHostDst.pitch());
saveImage(sResultFilename, oHostDst);
std::cout << "Saved image: " << sResultFilename << std::endl;
nppiFree(oDeviceSrc.data());
nppiFree(oDeviceDst.data());
exit(EXIT_SUCCESS);
}
catch (npp::Exception &rException) {
std::cerr << "Program error! The following exception occurred: \n";
std::cerr << rException << std::endl;
std::cerr << "Aborting." << std::endl;
exit(EXIT_FAILURE);
}
catch (...) {
std::cerr << "Program error! An unknow type of exception occurred. \n";
std::cerr << "Aborting." << std::endl;
exit(EXIT_FAILURE);
return -1;
}
const NppLibraryVersion *libVer = nppGetLibVersion();
printf("NPP Library Version %d.%d.%d\n", libVer->major, libVer->minor, libVer->build);
int driverVersion, runtimeVersion;
cudaDriverGetVersion(&driverVersion);
cudaRuntimeGetVersion(&runtimeVersion);
printf("CUDA Driver Version: %d.%d\n", driverVersion/1000, (driverVersion%100)/10);
printf("CUDA Runtime Version: %d.%d\n\n", runtimeVersion/1000, (runtimeVersion%100)/10);
cudaError = cudaDeviceGetAttribute(&nppStreamCtx.nCudaDevAttrComputeCapabilityMajor,
cudaDevAttrComputeCapabilityMajor,
nppStreamCtx.nCudaDeviceId);
if (cudaError != cudaSuccess)
return NPP_NOT_SUFFICIENT_COMPUTE_CAPABILITY;
cudaError = cudaDeviceGetAttribute(&nppStreamCtx.nCudaDevAttrComputeCapabilityMinor,
cudaDevAttrComputeCapabilityMinor,
nppStreamCtx.nCudaDeviceId);
if (cudaError != cudaSuccess)
return NPP_NOT_SUFFICIENT_COMPUTE_CAPABILITY;
cudaError = cudaStreamGetFlags(nppStreamCtx.hStream, &nppStreamCtx.nStreamFlags);
cudaDeviceProp oDeviceProperties;
cudaError = cudaGetDeviceProperties(&oDeviceProperties, nppStreamCtx.nCudaDeviceId);
nppStreamCtx.nMultiProcessorCount = oDeviceProperties.multiProcessorCount;
nppStreamCtx.nMaxThreadsPerMultiProcessor = oDeviceProperties.maxThreadsPerMultiProcessor;
nppStreamCtx.nMaxThreadsPerBlock = oDeviceProperties.maxThreadsPerBlock;
nppStreamCtx.nSharedMemPerBlock = oDeviceProperties.sharedMemPerBlock;
if (checkCmdLineFlag(argc, (const char **)argv, "input")) {
getCmdLineArgumentString(argc, (const char **)argv, "input", &filePath);
} else {
filePath = sdkFindFilePath("teapot512.pgm", argv[0]);
}
if (filePath) {
sFilename = filePath;
} else {
sFilename = "teapot512.pgm";
}
// if we specify the filename at the command line, then we only test
// sFilename[0].
int file_errors = 0;
std::ifstream infile(sFilename.data(), std::ifstream::in);
if (infile.good()) {
std::cout << "boxFilterNPP opened: <" << sFilename.data()
<< "> successfully!" << std::endl;
file_errors = 0;
infile.close();
} else {
std::cout << "boxFilterNPP unable to open: <" << sFilename.data() << ">"
<< std::endl;
file_errors++;
infile.close();
}
if (file_errors > 0) {
exit(EXIT_FAILURE);
}
std::string sResultFilename = sFilename;
std::string::size_type dot = sResultFilename.rfind('.');
if (dot != std::string::npos) {
sResultFilename = sResultFilename.substr(0, dot);
}
sResultFilename += "_boxFilter.pgm";
if (checkCmdLineFlag(argc, (const char **)argv, "output")) {
char *outputFilePath;
getCmdLineArgumentString(argc, (const char **)argv, "output",
&outputFilePath);
sResultFilename = outputFilePath;
}
// declare a host image object for an 8-bit grayscale image
npp::ImageCPU_8u_C1 oHostSrc;
// load gray-scale image from disk
npp::loadImage(sFilename, oHostSrc);
// declare a device image and copy construct from the host image,
// i.e. upload host to device
npp::ImageNPP_8u_C1 oDeviceSrc(oHostSrc);
// create struct with box-filter mask size
NppiSize oMaskSize = {5, 5};
NppiSize oSrcSize = {(int)oDeviceSrc.width(), (int)oDeviceSrc.height()};
NppiPoint oSrcOffset = {0, 0};
// create struct with ROI size
NppiSize oSizeROI = {(int)oDeviceSrc.width(), (int)oDeviceSrc.height()};
// allocate device image of appropriately reduced size
npp::ImageNPP_8u_C1 oDeviceDst(oSizeROI.width, oSizeROI.height);
// set anchor point inside the mask to (oMaskSize.width / 2,
// oMaskSize.height / 2) It should round down when odd
NppiPoint oAnchor = {oMaskSize.width / 2, oMaskSize.height / 2};
// run box filter
NPP_CHECK_NPP(nppiFilterBoxBorder_8u_C1R_Ctx(
oDeviceSrc.data(), oDeviceSrc.pitch(), oSrcSize, oSrcOffset,
oDeviceDst.data(), oDeviceDst.pitch(), oSizeROI, oMaskSize, oAnchor,
NPP_BORDER_REPLICATE, nppStreamCtx));
// declare a host image for the result
npp::ImageCPU_8u_C1 oHostDst(oDeviceDst.size());
// and copy the device result data into it
oDeviceDst.copyTo(oHostDst.data(), oHostDst.pitch());
saveImage(sResultFilename, oHostDst);
std::cout << "Saved image: " << sResultFilename << std::endl;
nppiFree(oDeviceSrc.data());
nppiFree(oDeviceDst.data());
exit(EXIT_SUCCESS);
} catch (npp::Exception &rException) {
std::cerr << "Program error! The following exception occurred: \n";
std::cerr << rException << std::endl;
std::cerr << "Aborting." << std::endl;
exit(EXIT_FAILURE);
} catch (...) {
std::cerr << "Program error! An unknow type of exception occurred. \n";
std::cerr << "Aborting." << std::endl;
exit(EXIT_FAILURE);
return -1;
}
return 0;
return 0;
}

View File

@@ -36,215 +36,225 @@
#include <ImageIO.h>
#include <ImagesCPU.h>
#include <ImagesNPP.h>
#include <string.h>
#include <fstream>
#include <iostream>
#include <cuda_runtime.h>
#include <npp.h>
#include <fstream>
#include <helper_cuda.h>
#include <helper_string.h>
#include <iostream>
#include <npp.h>
#include <string.h>
inline int cudaDeviceInit(int argc, const char **argv) {
int deviceCount;
checkCudaErrors(cudaGetDeviceCount(&deviceCount));
inline int cudaDeviceInit(int argc, const char **argv)
{
int deviceCount;
checkCudaErrors(cudaGetDeviceCount(&deviceCount));
if (deviceCount == 0) {
std::cerr << "CUDA error: no devices supporting CUDA." << std::endl;
exit(EXIT_FAILURE);
}
if (deviceCount == 0) {
std::cerr << "CUDA error: no devices supporting CUDA." << std::endl;
exit(EXIT_FAILURE);
}
int dev = findCudaDevice(argc, argv);
int dev = findCudaDevice(argc, argv);
cudaDeviceProp deviceProp;
cudaGetDeviceProperties(&deviceProp, dev);
std::cerr << "cudaSetDevice GPU" << dev << " = " << deviceProp.name
<< std::endl;
cudaDeviceProp deviceProp;
cudaGetDeviceProperties(&deviceProp, dev);
std::cerr << "cudaSetDevice GPU" << dev << " = " << deviceProp.name << std::endl;
checkCudaErrors(cudaSetDevice(dev));
checkCudaErrors(cudaSetDevice(dev));
return dev;
return dev;
}
int main(int argc, char *argv[]) {
printf("%s Starting...\n\n", argv[0]);
int main(int argc, char *argv[])
{
printf("%s Starting...\n\n", argv[0]);
try {
std::string sFilename;
char *filePath;
try {
std::string sFilename;
char *filePath;
cudaDeviceInit(argc, (const char **)argv);
cudaDeviceInit(argc, (const char **)argv);
NppStreamContext nppStreamCtx;
nppStreamCtx.hStream = 0; // The NULL stream by default, set this to whatever your stream ID is if not the NULL stream.
NppStreamContext nppStreamCtx;
nppStreamCtx.hStream =
0; // The NULL stream by default, set this to whatever your stream ID is if not the NULL stream.
cudaError_t cudaError = cudaGetDevice(&nppStreamCtx.nCudaDeviceId);
if (cudaError != cudaSuccess)
{
printf("CUDA error: no devices supporting CUDA.\n");
return NPP_NOT_SUFFICIENT_COMPUTE_CAPABILITY;
cudaError_t cudaError = cudaGetDevice(&nppStreamCtx.nCudaDeviceId);
if (cudaError != cudaSuccess) {
printf("CUDA error: no devices supporting CUDA.\n");
return NPP_NOT_SUFFICIENT_COMPUTE_CAPABILITY;
}
const NppLibraryVersion *libVer = nppGetLibVersion();
printf("NPP Library Version %d.%d.%d\n", libVer->major, libVer->minor, libVer->build);
int driverVersion, runtimeVersion;
cudaDriverGetVersion(&driverVersion);
cudaRuntimeGetVersion(&runtimeVersion);
printf("CUDA Driver Version: %d.%d\n", driverVersion / 1000, (driverVersion % 100) / 10);
printf("CUDA Runtime Version: %d.%d\n\n", runtimeVersion / 1000, (runtimeVersion % 100) / 10);
cudaError = cudaDeviceGetAttribute(&nppStreamCtx.nCudaDevAttrComputeCapabilityMajor,
cudaDevAttrComputeCapabilityMajor,
nppStreamCtx.nCudaDeviceId);
if (cudaError != cudaSuccess)
return NPP_NOT_SUFFICIENT_COMPUTE_CAPABILITY;
cudaError = cudaDeviceGetAttribute(&nppStreamCtx.nCudaDevAttrComputeCapabilityMinor,
cudaDevAttrComputeCapabilityMinor,
nppStreamCtx.nCudaDeviceId);
if (cudaError != cudaSuccess)
return NPP_NOT_SUFFICIENT_COMPUTE_CAPABILITY;
cudaError = cudaStreamGetFlags(nppStreamCtx.hStream, &nppStreamCtx.nStreamFlags);
cudaDeviceProp oDeviceProperties;
cudaError = cudaGetDeviceProperties(&oDeviceProperties, nppStreamCtx.nCudaDeviceId);
nppStreamCtx.nMultiProcessorCount = oDeviceProperties.multiProcessorCount;
nppStreamCtx.nMaxThreadsPerMultiProcessor = oDeviceProperties.maxThreadsPerMultiProcessor;
nppStreamCtx.nMaxThreadsPerBlock = oDeviceProperties.maxThreadsPerBlock;
nppStreamCtx.nSharedMemPerBlock = oDeviceProperties.sharedMemPerBlock;
if (checkCmdLineFlag(argc, (const char **)argv, "input")) {
getCmdLineArgumentString(argc, (const char **)argv, "input", &filePath);
}
else {
filePath = sdkFindFilePath("teapot512.pgm", argv[0]);
}
if (filePath) {
sFilename = filePath;
}
else {
sFilename = "teapot512.pgm";
}
// if we specify the filename at the command line, then we only test
// sFilename[0].
int file_errors = 0;
std::ifstream infile(sFilename.data(), std::ifstream::in);
if (infile.good()) {
std::cout << "cannyEdgeDetectionNPP opened: <" << sFilename.data() << "> successfully!" << std::endl;
file_errors = 0;
infile.close();
}
else {
std::cout << "cannyEdgeDetectionNPP unable to open: <" << sFilename.data() << ">" << std::endl;
file_errors++;
infile.close();
}
if (file_errors > 0) {
exit(EXIT_FAILURE);
}
std::string sResultFilename = sFilename;
std::string::size_type dot = sResultFilename.rfind('.');
if (dot != std::string::npos) {
sResultFilename = sResultFilename.substr(0, dot);
}
sResultFilename += "_cannyEdgeDetection.pgm";
if (checkCmdLineFlag(argc, (const char **)argv, "output")) {
char *outputFilePath;
getCmdLineArgumentString(argc, (const char **)argv, "output", &outputFilePath);
sResultFilename = outputFilePath;
}
// declare a host image object for an 8-bit grayscale image
npp::ImageCPU_8u_C1 oHostSrc;
// load gray-scale image from disk
npp::loadImage(sFilename, oHostSrc);
// declare a device image and copy construct from the host image,
// i.e. upload host to device
npp::ImageNPP_8u_C1 oDeviceSrc(oHostSrc);
NppiSize oSrcSize = {(int)oDeviceSrc.width(), (int)oDeviceSrc.height()};
NppiPoint oSrcOffset = {0, 0};
// create struct with ROI size
NppiSize oSizeROI = {(int)oDeviceSrc.width(), (int)oDeviceSrc.height()};
// allocate device image of appropriately reduced size
npp::ImageNPP_8u_C1 oDeviceDst(oSizeROI.width, oSizeROI.height);
int nBufferSize = 0;
Npp8u *pScratchBufferNPP = 0;
// get necessary scratch buffer size and allocate that much device memory
NPP_CHECK_NPP(nppiFilterCannyBorderGetBufferSize(oSizeROI, &nBufferSize));
cudaMalloc((void **)&pScratchBufferNPP, nBufferSize);
// now run the canny edge detection filter
// Using nppiNormL2 will produce larger magnitude values allowing for finer
// control of threshold values while nppiNormL1 will be slightly faster.
// Also, selecting the sobel gradient filter allows up to a 5x5 kernel size
// which can produce more precise results but is a bit slower. Commonly
// nppiNormL2 and sobel gradient filter size of 3x3 are used. Canny
// recommends that the high threshold value should be about 3 times the low
// threshold value. The threshold range will depend on the range of
// magnitude values that the sobel gradient filter generates for a
// particular image.
Npp16s nLowThreshold = 72;
Npp16s nHighThreshold = 256;
if ((nBufferSize > 0) && (pScratchBufferNPP != 0)) {
NPP_CHECK_NPP(nppiFilterCannyBorder_8u_C1R_Ctx(oDeviceSrc.data(),
oDeviceSrc.pitch(),
oSrcSize,
oSrcOffset,
oDeviceDst.data(),
oDeviceDst.pitch(),
oSizeROI,
NPP_FILTER_SOBEL,
NPP_MASK_SIZE_3_X_3,
nLowThreshold,
nHighThreshold,
nppiNormL2,
NPP_BORDER_REPLICATE,
pScratchBufferNPP,
nppStreamCtx));
}
// free scratch buffer memory
cudaFree(pScratchBufferNPP);
// declare a host image for the result
npp::ImageCPU_8u_C1 oHostDst(oDeviceDst.size());
// and copy the device result data into it
oDeviceDst.copyTo(oHostDst.data(), oHostDst.pitch());
saveImage(sResultFilename, oHostDst);
std::cout << "Saved image: " << sResultFilename << std::endl;
nppiFree(oDeviceSrc.data());
nppiFree(oDeviceDst.data());
exit(EXIT_SUCCESS);
}
catch (npp::Exception &rException) {
std::cerr << "Program error! The following exception occurred: \n";
std::cerr << rException << std::endl;
std::cerr << "Aborting." << std::endl;
exit(EXIT_FAILURE);
}
catch (...) {
std::cerr << "Program error! An unknow type of exception occurred. \n";
std::cerr << "Aborting." << std::endl;
exit(EXIT_FAILURE);
return -1;
}
const NppLibraryVersion *libVer = nppGetLibVersion();
printf("NPP Library Version %d.%d.%d\n", libVer->major, libVer->minor, libVer->build);
int driverVersion, runtimeVersion;
cudaDriverGetVersion(&driverVersion);
cudaRuntimeGetVersion(&runtimeVersion);
printf("CUDA Driver Version: %d.%d\n", driverVersion/1000, (driverVersion%100)/10);
printf("CUDA Runtime Version: %d.%d\n\n", runtimeVersion/1000, (runtimeVersion%100)/10);
cudaError = cudaDeviceGetAttribute(&nppStreamCtx.nCudaDevAttrComputeCapabilityMajor,
cudaDevAttrComputeCapabilityMajor,
nppStreamCtx.nCudaDeviceId);
if (cudaError != cudaSuccess)
return NPP_NOT_SUFFICIENT_COMPUTE_CAPABILITY;
cudaError = cudaDeviceGetAttribute(&nppStreamCtx.nCudaDevAttrComputeCapabilityMinor,
cudaDevAttrComputeCapabilityMinor,
nppStreamCtx.nCudaDeviceId);
if (cudaError != cudaSuccess)
return NPP_NOT_SUFFICIENT_COMPUTE_CAPABILITY;
cudaError = cudaStreamGetFlags(nppStreamCtx.hStream, &nppStreamCtx.nStreamFlags);
cudaDeviceProp oDeviceProperties;
cudaError = cudaGetDeviceProperties(&oDeviceProperties, nppStreamCtx.nCudaDeviceId);
nppStreamCtx.nMultiProcessorCount = oDeviceProperties.multiProcessorCount;
nppStreamCtx.nMaxThreadsPerMultiProcessor = oDeviceProperties.maxThreadsPerMultiProcessor;
nppStreamCtx.nMaxThreadsPerBlock = oDeviceProperties.maxThreadsPerBlock;
nppStreamCtx.nSharedMemPerBlock = oDeviceProperties.sharedMemPerBlock;
if (checkCmdLineFlag(argc, (const char **)argv, "input")) {
getCmdLineArgumentString(argc, (const char **)argv, "input", &filePath);
} else {
filePath = sdkFindFilePath("teapot512.pgm", argv[0]);
}
if (filePath) {
sFilename = filePath;
} else {
sFilename = "teapot512.pgm";
}
// if we specify the filename at the command line, then we only test
// sFilename[0].
int file_errors = 0;
std::ifstream infile(sFilename.data(), std::ifstream::in);
if (infile.good()) {
std::cout << "cannyEdgeDetectionNPP opened: <" << sFilename.data()
<< "> successfully!" << std::endl;
file_errors = 0;
infile.close();
} else {
std::cout << "cannyEdgeDetectionNPP unable to open: <" << sFilename.data()
<< ">" << std::endl;
file_errors++;
infile.close();
}
if (file_errors > 0) {
exit(EXIT_FAILURE);
}
std::string sResultFilename = sFilename;
std::string::size_type dot = sResultFilename.rfind('.');
if (dot != std::string::npos) {
sResultFilename = sResultFilename.substr(0, dot);
}
sResultFilename += "_cannyEdgeDetection.pgm";
if (checkCmdLineFlag(argc, (const char **)argv, "output")) {
char *outputFilePath;
getCmdLineArgumentString(argc, (const char **)argv, "output",
&outputFilePath);
sResultFilename = outputFilePath;
}
// declare a host image object for an 8-bit grayscale image
npp::ImageCPU_8u_C1 oHostSrc;
// load gray-scale image from disk
npp::loadImage(sFilename, oHostSrc);
// declare a device image and copy construct from the host image,
// i.e. upload host to device
npp::ImageNPP_8u_C1 oDeviceSrc(oHostSrc);
NppiSize oSrcSize = {(int)oDeviceSrc.width(), (int)oDeviceSrc.height()};
NppiPoint oSrcOffset = {0, 0};
// create struct with ROI size
NppiSize oSizeROI = {(int)oDeviceSrc.width(), (int)oDeviceSrc.height()};
// allocate device image of appropriately reduced size
npp::ImageNPP_8u_C1 oDeviceDst(oSizeROI.width, oSizeROI.height);
int nBufferSize = 0;
Npp8u *pScratchBufferNPP = 0;
// get necessary scratch buffer size and allocate that much device memory
NPP_CHECK_NPP(nppiFilterCannyBorderGetBufferSize(oSizeROI, &nBufferSize));
cudaMalloc((void **)&pScratchBufferNPP, nBufferSize);
// now run the canny edge detection filter
// Using nppiNormL2 will produce larger magnitude values allowing for finer
// control of threshold values while nppiNormL1 will be slightly faster.
// Also, selecting the sobel gradient filter allows up to a 5x5 kernel size
// which can produce more precise results but is a bit slower. Commonly
// nppiNormL2 and sobel gradient filter size of 3x3 are used. Canny
// recommends that the high threshold value should be about 3 times the low
// threshold value. The threshold range will depend on the range of
// magnitude values that the sobel gradient filter generates for a
// particular image.
Npp16s nLowThreshold = 72;
Npp16s nHighThreshold = 256;
if ((nBufferSize > 0) && (pScratchBufferNPP != 0)) {
NPP_CHECK_NPP(nppiFilterCannyBorder_8u_C1R_Ctx(
oDeviceSrc.data(), oDeviceSrc.pitch(), oSrcSize, oSrcOffset,
oDeviceDst.data(), oDeviceDst.pitch(), oSizeROI, NPP_FILTER_SOBEL,
NPP_MASK_SIZE_3_X_3, nLowThreshold, nHighThreshold, nppiNormL2,
NPP_BORDER_REPLICATE, pScratchBufferNPP, nppStreamCtx));
}
// free scratch buffer memory
cudaFree(pScratchBufferNPP);
// declare a host image for the result
npp::ImageCPU_8u_C1 oHostDst(oDeviceDst.size());
// and copy the device result data into it
oDeviceDst.copyTo(oHostDst.data(), oHostDst.pitch());
saveImage(sResultFilename, oHostDst);
std::cout << "Saved image: " << sResultFilename << std::endl;
nppiFree(oDeviceSrc.data());
nppiFree(oDeviceDst.data());
exit(EXIT_SUCCESS);
} catch (npp::Exception &rException) {
std::cerr << "Program error! The following exception occurred: \n";
std::cerr << rException << std::endl;
std::cerr << "Aborting." << std::endl;
exit(EXIT_FAILURE);
} catch (...) {
std::cerr << "Program error! An unknow type of exception occurred. \n";
std::cerr << "Aborting." << std::endl;
exit(EXIT_FAILURE);
return -1;
}
return 0;
return 0;
}

View File

@@ -42,227 +42,261 @@
#include <cusparse.h>
// Utilities and system includes
#include <helper_cuda.h> // helper function CUDA error checking and initialization
#include <helper_functions.h> // helper for shared functions common to CUDA Samples
#include <helper_cuda.h> // helper function CUDA error checking and initialization
#include <helper_functions.h> // helper for shared functions common to CUDA Samples
const char *sSDKname = "conjugateGradient";
/* genTridiag: generate a random tridiagonal symmetric matrix */
void genTridiag(int *I, int *J, float *val, int N, int nz) {
I[0] = 0, J[0] = 0, J[1] = 1;
val[0] = (float)rand() / RAND_MAX + 10.0f;
val[1] = (float)rand() / RAND_MAX;
int start;
void genTridiag(int *I, int *J, float *val, int N, int nz)
{
I[0] = 0, J[0] = 0, J[1] = 1;
val[0] = (float)rand() / RAND_MAX + 10.0f;
val[1] = (float)rand() / RAND_MAX;
int start;
for (int i = 1; i < N; i++) {
if (i > 1) {
I[i] = I[i - 1] + 3;
} else {
I[1] = 2;
for (int i = 1; i < N; i++) {
if (i > 1) {
I[i] = I[i - 1] + 3;
}
else {
I[1] = 2;
}
start = (i - 1) * 3 + 2;
J[start] = i - 1;
J[start + 1] = i;
if (i < N - 1) {
J[start + 2] = i + 1;
}
val[start] = val[start - 1];
val[start + 1] = (float)rand() / RAND_MAX + 10.0f;
if (i < N - 1) {
val[start + 2] = (float)rand() / RAND_MAX;
}
}
start = (i - 1) * 3 + 2;
J[start] = i - 1;
J[start + 1] = i;
if (i < N - 1) {
J[start + 2] = i + 1;
}
val[start] = val[start - 1];
val[start + 1] = (float)rand() / RAND_MAX + 10.0f;
if (i < N - 1) {
val[start + 2] = (float)rand() / RAND_MAX;
}
}
I[N] = nz;
I[N] = nz;
}
int main(int argc, char **argv) {
int M = 0, N = 0, nz = 0, *I = NULL, *J = NULL;
float *val = NULL;
const float tol = 1e-5f;
const int max_iter = 10000;
float *x;
float *rhs;
float a, b, na, r0, r1;
int *d_col, *d_row;
float *d_val, *d_x, dot;
float *d_r, *d_p, *d_Ax;
int k;
float alpha, beta, alpham1;
int main(int argc, char **argv)
{
int M = 0, N = 0, nz = 0, *I = NULL, *J = NULL;
float *val = NULL;
const float tol = 1e-5f;
const int max_iter = 10000;
float *x;
float *rhs;
float a, b, na, r0, r1;
int *d_col, *d_row;
float *d_val, *d_x, dot;
float *d_r, *d_p, *d_Ax;
int k;
float alpha, beta, alpham1;
// This will pick the best possible CUDA capable device
cudaDeviceProp deviceProp;
int devID = findCudaDevice(argc, (const char **)argv);
// This will pick the best possible CUDA capable device
cudaDeviceProp deviceProp;
int devID = findCudaDevice(argc, (const char **)argv);
if (devID < 0) {
printf("exiting...\n");
exit(EXIT_SUCCESS);
}
checkCudaErrors(cudaGetDeviceProperties(&deviceProp, devID));
// Statistics about the GPU device
printf(
"> GPU device has %d Multi-Processors, SM %d.%d compute capabilities\n\n",
deviceProp.multiProcessorCount, deviceProp.major, deviceProp.minor);
/* Generate a random tridiagonal symmetric matrix in CSR format */
M = N = 1048576;
nz = (N - 2) * 3 + 4;
I = (int *)malloc(sizeof(int) * (N + 1));
J = (int *)malloc(sizeof(int) * nz);
val = (float *)malloc(sizeof(float) * nz);
genTridiag(I, J, val, N, nz);
x = (float *)malloc(sizeof(float) * N);
rhs = (float *)malloc(sizeof(float) * N);
for (int i = 0; i < N; i++) {
rhs[i] = 1.0;
x[i] = 0.0;
}
/* Get handle to the CUBLAS context */
cublasHandle_t cublasHandle = 0;
cublasStatus_t cublasStatus;
cublasStatus = cublasCreate(&cublasHandle);
checkCudaErrors(cublasStatus);
/* Get handle to the CUSPARSE context */
cusparseHandle_t cusparseHandle = 0;
checkCudaErrors(cusparseCreate(&cusparseHandle));
checkCudaErrors(cudaMalloc((void **)&d_col, nz * sizeof(int)));
checkCudaErrors(cudaMalloc((void **)&d_row, (N + 1) * sizeof(int)));
checkCudaErrors(cudaMalloc((void **)&d_val, nz * sizeof(float)));
checkCudaErrors(cudaMalloc((void **)&d_x, N * sizeof(float)));
checkCudaErrors(cudaMalloc((void **)&d_r, N * sizeof(float)));
checkCudaErrors(cudaMalloc((void **)&d_p, N * sizeof(float)));
checkCudaErrors(cudaMalloc((void **)&d_Ax, N * sizeof(float)));
/* Wrap raw data into cuSPARSE generic API objects */
cusparseSpMatDescr_t matA = NULL;
checkCudaErrors(cusparseCreateCsr(&matA, N, N, nz, d_row, d_col, d_val,
CUSPARSE_INDEX_32I, CUSPARSE_INDEX_32I,
CUSPARSE_INDEX_BASE_ZERO, CUDA_R_32F));
cusparseDnVecDescr_t vecx = NULL;
checkCudaErrors(cusparseCreateDnVec(&vecx, N, d_x, CUDA_R_32F));
cusparseDnVecDescr_t vecp = NULL;
checkCudaErrors(cusparseCreateDnVec(&vecp, N, d_p, CUDA_R_32F));
cusparseDnVecDescr_t vecAx = NULL;
checkCudaErrors(cusparseCreateDnVec(&vecAx, N, d_Ax, CUDA_R_32F));
/* Initialize problem data */
cudaMemcpy(d_col, J, nz * sizeof(int), cudaMemcpyHostToDevice);
cudaMemcpy(d_row, I, (N + 1) * sizeof(int), cudaMemcpyHostToDevice);
cudaMemcpy(d_val, val, nz * sizeof(float), cudaMemcpyHostToDevice);
cudaMemcpy(d_x, x, N * sizeof(float), cudaMemcpyHostToDevice);
cudaMemcpy(d_r, rhs, N * sizeof(float), cudaMemcpyHostToDevice);
alpha = 1.0;
alpham1 = -1.0;
beta = 0.0;
r0 = 0.;
/* Allocate workspace for cuSPARSE */
size_t bufferSize = 0;
checkCudaErrors(cusparseSpMV_bufferSize(
cusparseHandle, CUSPARSE_OPERATION_NON_TRANSPOSE, &alpha, matA, vecx,
&beta, vecAx, CUDA_R_32F, CUSPARSE_SPMV_ALG_DEFAULT, &bufferSize));
void *buffer = NULL;
checkCudaErrors(cudaMalloc(&buffer, bufferSize));
/* Begin CG */
checkCudaErrors(cusparseSpMV(cusparseHandle, CUSPARSE_OPERATION_NON_TRANSPOSE,
&alpha, matA, vecx, &beta, vecAx, CUDA_R_32F,
CUSPARSE_SPMV_ALG_DEFAULT, buffer));
cublasSaxpy(cublasHandle, N, &alpham1, d_Ax, 1, d_r, 1);
cublasStatus = cublasSdot(cublasHandle, N, d_r, 1, d_r, 1, &r1);
k = 1;
while (r1 > tol * tol && k <= max_iter) {
if (k > 1) {
b = r1 / r0;
cublasStatus = cublasSscal(cublasHandle, N, &b, d_p, 1);
cublasStatus = cublasSaxpy(cublasHandle, N, &alpha, d_r, 1, d_p, 1);
} else {
cublasStatus = cublasScopy(cublasHandle, N, d_r, 1, d_p, 1);
if (devID < 0) {
printf("exiting...\n");
exit(EXIT_SUCCESS);
}
checkCudaErrors(cusparseSpMV(
cusparseHandle, CUSPARSE_OPERATION_NON_TRANSPOSE, &alpha, matA, vecp,
&beta, vecAx, CUDA_R_32F, CUSPARSE_SPMV_ALG_DEFAULT, buffer));
cublasStatus = cublasSdot(cublasHandle, N, d_p, 1, d_Ax, 1, &dot);
a = r1 / dot;
checkCudaErrors(cudaGetDeviceProperties(&deviceProp, devID));
cublasStatus = cublasSaxpy(cublasHandle, N, &a, d_p, 1, d_x, 1);
na = -a;
cublasStatus = cublasSaxpy(cublasHandle, N, &na, d_Ax, 1, d_r, 1);
// Statistics about the GPU device
printf("> GPU device has %d Multi-Processors, SM %d.%d compute capabilities\n\n",
deviceProp.multiProcessorCount,
deviceProp.major,
deviceProp.minor);
r0 = r1;
/* Generate a random tridiagonal symmetric matrix in CSR format */
M = N = 1048576;
nz = (N - 2) * 3 + 4;
I = (int *)malloc(sizeof(int) * (N + 1));
J = (int *)malloc(sizeof(int) * nz);
val = (float *)malloc(sizeof(float) * nz);
genTridiag(I, J, val, N, nz);
x = (float *)malloc(sizeof(float) * N);
rhs = (float *)malloc(sizeof(float) * N);
for (int i = 0; i < N; i++) {
rhs[i] = 1.0;
x[i] = 0.0;
}
/* Get handle to the CUBLAS context */
cublasHandle_t cublasHandle = 0;
cublasStatus_t cublasStatus;
cublasStatus = cublasCreate(&cublasHandle);
checkCudaErrors(cublasStatus);
/* Get handle to the CUSPARSE context */
cusparseHandle_t cusparseHandle = 0;
checkCudaErrors(cusparseCreate(&cusparseHandle));
checkCudaErrors(cudaMalloc((void **)&d_col, nz * sizeof(int)));
checkCudaErrors(cudaMalloc((void **)&d_row, (N + 1) * sizeof(int)));
checkCudaErrors(cudaMalloc((void **)&d_val, nz * sizeof(float)));
checkCudaErrors(cudaMalloc((void **)&d_x, N * sizeof(float)));
checkCudaErrors(cudaMalloc((void **)&d_r, N * sizeof(float)));
checkCudaErrors(cudaMalloc((void **)&d_p, N * sizeof(float)));
checkCudaErrors(cudaMalloc((void **)&d_Ax, N * sizeof(float)));
/* Wrap raw data into cuSPARSE generic API objects */
cusparseSpMatDescr_t matA = NULL;
checkCudaErrors(cusparseCreateCsr(&matA,
N,
N,
nz,
d_row,
d_col,
d_val,
CUSPARSE_INDEX_32I,
CUSPARSE_INDEX_32I,
CUSPARSE_INDEX_BASE_ZERO,
CUDA_R_32F));
cusparseDnVecDescr_t vecx = NULL;
checkCudaErrors(cusparseCreateDnVec(&vecx, N, d_x, CUDA_R_32F));
cusparseDnVecDescr_t vecp = NULL;
checkCudaErrors(cusparseCreateDnVec(&vecp, N, d_p, CUDA_R_32F));
cusparseDnVecDescr_t vecAx = NULL;
checkCudaErrors(cusparseCreateDnVec(&vecAx, N, d_Ax, CUDA_R_32F));
/* Initialize problem data */
cudaMemcpy(d_col, J, nz * sizeof(int), cudaMemcpyHostToDevice);
cudaMemcpy(d_row, I, (N + 1) * sizeof(int), cudaMemcpyHostToDevice);
cudaMemcpy(d_val, val, nz * sizeof(float), cudaMemcpyHostToDevice);
cudaMemcpy(d_x, x, N * sizeof(float), cudaMemcpyHostToDevice);
cudaMemcpy(d_r, rhs, N * sizeof(float), cudaMemcpyHostToDevice);
alpha = 1.0;
alpham1 = -1.0;
beta = 0.0;
r0 = 0.;
/* Allocate workspace for cuSPARSE */
size_t bufferSize = 0;
checkCudaErrors(cusparseSpMV_bufferSize(cusparseHandle,
CUSPARSE_OPERATION_NON_TRANSPOSE,
&alpha,
matA,
vecx,
&beta,
vecAx,
CUDA_R_32F,
CUSPARSE_SPMV_ALG_DEFAULT,
&bufferSize));
void *buffer = NULL;
checkCudaErrors(cudaMalloc(&buffer, bufferSize));
/* Begin CG */
checkCudaErrors(cusparseSpMV(cusparseHandle,
CUSPARSE_OPERATION_NON_TRANSPOSE,
&alpha,
matA,
vecx,
&beta,
vecAx,
CUDA_R_32F,
CUSPARSE_SPMV_ALG_DEFAULT,
buffer));
cublasSaxpy(cublasHandle, N, &alpham1, d_Ax, 1, d_r, 1);
cublasStatus = cublasSdot(cublasHandle, N, d_r, 1, d_r, 1, &r1);
cudaDeviceSynchronize();
printf("iteration = %3d, residual = %e\n", k, sqrt(r1));
k++;
}
cudaMemcpy(x, d_x, N * sizeof(float), cudaMemcpyDeviceToHost);
k = 1;
float rsum, diff, err = 0.0;
while (r1 > tol * tol && k <= max_iter) {
if (k > 1) {
b = r1 / r0;
cublasStatus = cublasSscal(cublasHandle, N, &b, d_p, 1);
cublasStatus = cublasSaxpy(cublasHandle, N, &alpha, d_r, 1, d_p, 1);
}
else {
cublasStatus = cublasScopy(cublasHandle, N, d_r, 1, d_p, 1);
}
for (int i = 0; i < N; i++) {
rsum = 0.0;
checkCudaErrors(cusparseSpMV(cusparseHandle,
CUSPARSE_OPERATION_NON_TRANSPOSE,
&alpha,
matA,
vecp,
&beta,
vecAx,
CUDA_R_32F,
CUSPARSE_SPMV_ALG_DEFAULT,
buffer));
cublasStatus = cublasSdot(cublasHandle, N, d_p, 1, d_Ax, 1, &dot);
a = r1 / dot;
for (int j = I[i]; j < I[i + 1]; j++) {
rsum += val[j] * x[J[j]];
cublasStatus = cublasSaxpy(cublasHandle, N, &a, d_p, 1, d_x, 1);
na = -a;
cublasStatus = cublasSaxpy(cublasHandle, N, &na, d_Ax, 1, d_r, 1);
r0 = r1;
cublasStatus = cublasSdot(cublasHandle, N, d_r, 1, d_r, 1, &r1);
cudaDeviceSynchronize();
printf("iteration = %3d, residual = %e\n", k, sqrt(r1));
k++;
}
diff = fabs(rsum - rhs[i]);
cudaMemcpy(x, d_x, N * sizeof(float), cudaMemcpyDeviceToHost);
if (diff > err) {
err = diff;
float rsum, diff, err = 0.0;
for (int i = 0; i < N; i++) {
rsum = 0.0;
for (int j = I[i]; j < I[i + 1]; j++) {
rsum += val[j] * x[J[j]];
}
diff = fabs(rsum - rhs[i]);
if (diff > err) {
err = diff;
}
}
}
if (buffer) {
checkCudaErrors(cudaFree(buffer));
}
cusparseDestroy(cusparseHandle);
cublasDestroy(cublasHandle);
if (matA) {
checkCudaErrors(cusparseDestroySpMat(matA));
}
if (vecx) {
checkCudaErrors(cusparseDestroyDnVec(vecx));
}
if (vecAx) {
checkCudaErrors(cusparseDestroyDnVec(vecAx));
}
if (vecp) {
checkCudaErrors(cusparseDestroyDnVec(vecp));
}
if (buffer) {
checkCudaErrors(cudaFree(buffer));
}
free(I);
free(J);
free(val);
free(x);
free(rhs);
cudaFree(d_col);
cudaFree(d_row);
cudaFree(d_val);
cudaFree(d_x);
cudaFree(d_r);
cudaFree(d_p);
cudaFree(d_Ax);
cusparseDestroy(cusparseHandle);
cublasDestroy(cublasHandle);
if (matA) {
checkCudaErrors(cusparseDestroySpMat(matA));
}
if (vecx) {
checkCudaErrors(cusparseDestroyDnVec(vecx));
}
if (vecAx) {
checkCudaErrors(cusparseDestroyDnVec(vecAx));
}
if (vecp) {
checkCudaErrors(cusparseDestroyDnVec(vecp));
}
printf("Test Summary: Error amount = %f\n", err);
exit((k <= max_iter) ? 0 : 1);
free(I);
free(J);
free(val);
free(x);
free(rhs);
cudaFree(d_col);
cudaFree(d_row);
cudaFree(d_val);
cudaFree(d_x);
cudaFree(d_r);
cudaFree(d_p);
cudaFree(d_Ax);
printf("Test Summary: Error amount = %f\n", err);
exit((k <= max_iter) ? 0 : 1);
}

View File

@@ -42,8 +42,8 @@
#include <cusparse.h>
// Utilities and system includes
#include <helper_cuda.h> // helper function CUDA error checking and initialization
#include <helper_functions.h> // helper for shared functions common to CUDA Samples
#include <helper_cuda.h> // helper function CUDA error checking and initialization
#include <helper_functions.h> // helper for shared functions common to CUDA Samples
const char *sSDKname = "conjugateGradientCudaGraphs";
@@ -52,291 +52,235 @@ const char *sSDKname = "conjugateGradientCudaGraphs";
#endif
/* genTridiag: generate a random tridiagonal symmetric matrix */
void genTridiag(int *I, int *J, float *val, int N, int nz) {
I[0] = 0, J[0] = 0, J[1] = 1;
val[0] = (float)rand() / RAND_MAX + 10.0f;
val[1] = (float)rand() / RAND_MAX;
int start;
void genTridiag(int *I, int *J, float *val, int N, int nz)
{
I[0] = 0, J[0] = 0, J[1] = 1;
val[0] = (float)rand() / RAND_MAX + 10.0f;
val[1] = (float)rand() / RAND_MAX;
int start;
for (int i = 1; i < N; i++) {
if (i > 1) {
I[i] = I[i - 1] + 3;
} else {
I[1] = 2;
for (int i = 1; i < N; i++) {
if (i > 1) {
I[i] = I[i - 1] + 3;
}
else {
I[1] = 2;
}
start = (i - 1) * 3 + 2;
J[start] = i - 1;
J[start + 1] = i;
if (i < N - 1) {
J[start + 2] = i + 1;
}
val[start] = val[start - 1];
val[start + 1] = (float)rand() / RAND_MAX + 10.0f;
if (i < N - 1) {
val[start + 2] = (float)rand() / RAND_MAX;
}
}
start = (i - 1) * 3 + 2;
J[start] = i - 1;
J[start + 1] = i;
I[N] = nz;
}
if (i < N - 1) {
J[start + 2] = i + 1;
__global__ void initVectors(float *rhs, float *x, int N)
{
size_t gid = blockIdx.x * blockDim.x + threadIdx.x;
for (size_t i = gid; i < N; i += gridDim.x * blockDim.x) {
rhs[i] = 1.0;
x[i] = 0.0;
}
}
__global__ void r1_div_x(float *r1, float *r0, float *b)
{
int gid = blockIdx.x * blockDim.x + threadIdx.x;
if (gid == 0) {
b[0] = r1[0] / r0[0];
}
}
__global__ void a_minus(float *a, float *na)
{
int gid = blockIdx.x * blockDim.x + threadIdx.x;
if (gid == 0) {
na[0] = -(a[0]);
}
}
int main(int argc, char **argv)
{
int N = 0, nz = 0, *I = NULL, *J = NULL;
float *val = NULL;
const float tol = 1e-5f;
const int max_iter = 10000;
float *x;
float *rhs;
float r1;
int *d_col, *d_row;
float *d_val, *d_x;
float *d_r, *d_p, *d_Ax;
int k;
float alpha, beta, alpham1;
cudaStream_t stream1, streamForGraph;
// This will pick the best possible CUDA capable device
cudaDeviceProp deviceProp;
int devID = findCudaDevice(argc, (const char **)argv);
if (devID < 0) {
printf("exiting...\n");
exit(EXIT_SUCCESS);
}
val[start] = val[start - 1];
val[start + 1] = (float)rand() / RAND_MAX + 10.0f;
checkCudaErrors(cudaGetDeviceProperties(&deviceProp, devID));
if (i < N - 1) {
val[start + 2] = (float)rand() / RAND_MAX;
// Statistics about the GPU device
printf("> GPU device has %d Multi-Processors, SM %d.%d compute capabilities\n\n",
deviceProp.multiProcessorCount,
deviceProp.major,
deviceProp.minor);
/* Generate a random tridiagonal symmetric matrix in CSR format */
N = 1048576;
nz = (N - 2) * 3 + 4;
checkCudaErrors(cudaMallocHost(&I, sizeof(int) * (N + 1)));
checkCudaErrors(cudaMallocHost(&J, sizeof(int) * nz));
checkCudaErrors(cudaMallocHost(&val, sizeof(float) * nz));
genTridiag(I, J, val, N, nz);
checkCudaErrors(cudaMallocHost(&x, sizeof(float) * N));
rhs = (float *)malloc(sizeof(float) * N);
for (int i = 0; i < N; i++) {
rhs[i] = 1.0;
x[i] = 0.0;
}
}
I[N] = nz;
}
/* Get handle to the CUBLAS context */
cublasHandle_t cublasHandle = 0;
cublasStatus_t cublasStatus;
cublasStatus = cublasCreate(&cublasHandle);
__global__ void initVectors(float *rhs, float *x, int N) {
size_t gid = blockIdx.x * blockDim.x + threadIdx.x;
checkCudaErrors(cublasStatus);
for (size_t i = gid; i < N; i += gridDim.x * blockDim.x) {
rhs[i] = 1.0;
x[i] = 0.0;
}
}
/* Get handle to the CUSPARSE context */
cusparseHandle_t cusparseHandle = 0;
cusparseStatus_t cusparseStatus;
cusparseStatus = cusparseCreate(&cusparseHandle);
__global__ void r1_div_x(float *r1, float *r0, float *b) {
int gid = blockIdx.x * blockDim.x + threadIdx.x;
if (gid == 0) {
b[0] = r1[0] / r0[0];
}
}
checkCudaErrors(cusparseStatus);
__global__ void a_minus(float *a, float *na) {
int gid = blockIdx.x * blockDim.x + threadIdx.x;
if (gid == 0) {
na[0] = -(a[0]);
}
}
checkCudaErrors(cudaStreamCreate(&stream1));
int main(int argc, char **argv) {
int N = 0, nz = 0, *I = NULL, *J = NULL;
float *val = NULL;
const float tol = 1e-5f;
const int max_iter = 10000;
float *x;
float *rhs;
float r1;
checkCudaErrors(cudaMalloc((void **)&d_col, nz * sizeof(int)));
checkCudaErrors(cudaMalloc((void **)&d_row, (N + 1) * sizeof(int)));
checkCudaErrors(cudaMalloc((void **)&d_val, nz * sizeof(float)));
checkCudaErrors(cudaMalloc((void **)&d_x, N * sizeof(float)));
checkCudaErrors(cudaMalloc((void **)&d_r, N * sizeof(float)));
checkCudaErrors(cudaMalloc((void **)&d_p, N * sizeof(float)));
checkCudaErrors(cudaMalloc((void **)&d_Ax, N * sizeof(float)));
int *d_col, *d_row;
float *d_val, *d_x;
float *d_r, *d_p, *d_Ax;
int k;
float alpha, beta, alpham1;
float *d_r1, *d_r0, *d_dot, *d_a, *d_na, *d_b;
checkCudaErrors(cudaMalloc((void **)&d_r1, sizeof(float)));
checkCudaErrors(cudaMalloc((void **)&d_r0, sizeof(float)));
checkCudaErrors(cudaMalloc((void **)&d_dot, sizeof(float)));
checkCudaErrors(cudaMalloc((void **)&d_a, sizeof(float)));
checkCudaErrors(cudaMalloc((void **)&d_na, sizeof(float)));
checkCudaErrors(cudaMalloc((void **)&d_b, sizeof(float)));
cudaStream_t stream1, streamForGraph;
/* Wrap raw data into cuSPARSE generic API objects */
cusparseSpMatDescr_t matA = NULL;
checkCudaErrors(cusparseCreateCsr(&matA,
N,
N,
nz,
d_row,
d_col,
d_val,
CUSPARSE_INDEX_32I,
CUSPARSE_INDEX_32I,
CUSPARSE_INDEX_BASE_ZERO,
CUDA_R_32F));
cusparseDnVecDescr_t vecx = NULL;
checkCudaErrors(cusparseCreateDnVec(&vecx, N, d_x, CUDA_R_32F));
cusparseDnVecDescr_t vecp = NULL;
checkCudaErrors(cusparseCreateDnVec(&vecp, N, d_p, CUDA_R_32F));
cusparseDnVecDescr_t vecAx = NULL;
checkCudaErrors(cusparseCreateDnVec(&vecAx, N, d_Ax, CUDA_R_32F));
// This will pick the best possible CUDA capable device
cudaDeviceProp deviceProp;
int devID = findCudaDevice(argc, (const char **)argv);
/* Allocate workspace for cuSPARSE */
size_t bufferSize = 0;
checkCudaErrors(cusparseSpMV_bufferSize(cusparseHandle,
CUSPARSE_OPERATION_NON_TRANSPOSE,
&alpha,
matA,
vecx,
&beta,
vecAx,
CUDA_R_32F,
CUSPARSE_SPMV_ALG_DEFAULT,
&bufferSize));
void *buffer = NULL;
checkCudaErrors(cudaMalloc(&buffer, bufferSize));
if (devID < 0) {
printf("exiting...\n");
exit(EXIT_SUCCESS);
}
cusparseMatDescr_t descr = 0;
checkCudaErrors(cusparseCreateMatDescr(&descr));
checkCudaErrors(cudaGetDeviceProperties(&deviceProp, devID));
checkCudaErrors(cusparseSetMatType(descr, CUSPARSE_MATRIX_TYPE_GENERAL));
checkCudaErrors(cusparseSetMatIndexBase(descr, CUSPARSE_INDEX_BASE_ZERO));
// Statistics about the GPU device
printf(
"> GPU device has %d Multi-Processors, SM %d.%d compute capabilities\n\n",
deviceProp.multiProcessorCount, deviceProp.major, deviceProp.minor);
int numBlocks = 0, blockSize = 0;
checkCudaErrors(cudaOccupancyMaxPotentialBlockSize(&numBlocks, &blockSize, initVectors));
/* Generate a random tridiagonal symmetric matrix in CSR format */
N = 1048576;
nz = (N - 2) * 3 + 4;
checkCudaErrors(cudaMallocHost(&I, sizeof(int) * (N + 1)));
checkCudaErrors(cudaMallocHost(&J, sizeof(int) * nz));
checkCudaErrors(cudaMallocHost(&val, sizeof(float) * nz));
genTridiag(I, J, val, N, nz);
checkCudaErrors(cudaMemcpyAsync(d_col, J, nz * sizeof(int), cudaMemcpyHostToDevice, stream1));
checkCudaErrors(cudaMemcpyAsync(d_row, I, (N + 1) * sizeof(int), cudaMemcpyHostToDevice, stream1));
checkCudaErrors(cudaMemcpyAsync(d_val, val, nz * sizeof(float), cudaMemcpyHostToDevice, stream1));
checkCudaErrors(cudaMallocHost(&x, sizeof(float) * N));
rhs = (float *)malloc(sizeof(float) * N);
initVectors<<<numBlocks, blockSize, 0, stream1>>>(d_r, d_x, N);
for (int i = 0; i < N; i++) {
rhs[i] = 1.0;
x[i] = 0.0;
}
alpha = 1.0;
alpham1 = -1.0;
beta = 0.0;
/* Get handle to the CUBLAS context */
cublasHandle_t cublasHandle = 0;
cublasStatus_t cublasStatus;
cublasStatus = cublasCreate(&cublasHandle);
checkCudaErrors(cusparseSetStream(cusparseHandle, stream1));
checkCudaErrors(cusparseSpMV(cusparseHandle,
CUSPARSE_OPERATION_NON_TRANSPOSE,
&alpha,
matA,
vecx,
&beta,
vecAx,
CUDA_R_32F,
CUSPARSE_SPMV_ALG_DEFAULT,
buffer));
checkCudaErrors(cublasStatus);
checkCudaErrors(cublasSetStream(cublasHandle, stream1));
checkCudaErrors(cublasSaxpy(cublasHandle, N, &alpham1, d_Ax, 1, d_r, 1));
/* Get handle to the CUSPARSE context */
cusparseHandle_t cusparseHandle = 0;
cusparseStatus_t cusparseStatus;
cusparseStatus = cusparseCreate(&cusparseHandle);
checkCudaErrors(cublasSetPointerMode(cublasHandle, CUBLAS_POINTER_MODE_DEVICE));
checkCudaErrors(cublasSdot(cublasHandle, N, d_r, 1, d_r, 1, d_r1));
checkCudaErrors(cusparseStatus);
k = 1;
// First Iteration when k=1 starts
checkCudaErrors(cublasScopy(cublasHandle, N, d_r, 1, d_p, 1));
checkCudaErrors(cusparseSpMV(cusparseHandle,
CUSPARSE_OPERATION_NON_TRANSPOSE,
&alpha,
matA,
vecp,
&beta,
vecAx,
CUDA_R_32F,
CUSPARSE_SPMV_ALG_DEFAULT,
buffer));
checkCudaErrors(cudaStreamCreate(&stream1));
checkCudaErrors(cudaMalloc((void **)&d_col, nz * sizeof(int)));
checkCudaErrors(cudaMalloc((void **)&d_row, (N + 1) * sizeof(int)));
checkCudaErrors(cudaMalloc((void **)&d_val, nz * sizeof(float)));
checkCudaErrors(cudaMalloc((void **)&d_x, N * sizeof(float)));
checkCudaErrors(cudaMalloc((void **)&d_r, N * sizeof(float)));
checkCudaErrors(cudaMalloc((void **)&d_p, N * sizeof(float)));
checkCudaErrors(cudaMalloc((void **)&d_Ax, N * sizeof(float)));
float *d_r1, *d_r0, *d_dot, *d_a, *d_na, *d_b;
checkCudaErrors(cudaMalloc((void **)&d_r1, sizeof(float)));
checkCudaErrors(cudaMalloc((void **)&d_r0, sizeof(float)));
checkCudaErrors(cudaMalloc((void **)&d_dot, sizeof(float)));
checkCudaErrors(cudaMalloc((void **)&d_a, sizeof(float)));
checkCudaErrors(cudaMalloc((void **)&d_na, sizeof(float)));
checkCudaErrors(cudaMalloc((void **)&d_b, sizeof(float)));
/* Wrap raw data into cuSPARSE generic API objects */
cusparseSpMatDescr_t matA = NULL;
checkCudaErrors(cusparseCreateCsr(&matA, N, N, nz, d_row, d_col, d_val,
CUSPARSE_INDEX_32I, CUSPARSE_INDEX_32I,
CUSPARSE_INDEX_BASE_ZERO, CUDA_R_32F));
cusparseDnVecDescr_t vecx = NULL;
checkCudaErrors(cusparseCreateDnVec(&vecx, N, d_x, CUDA_R_32F));
cusparseDnVecDescr_t vecp = NULL;
checkCudaErrors(cusparseCreateDnVec(&vecp, N, d_p, CUDA_R_32F));
cusparseDnVecDescr_t vecAx = NULL;
checkCudaErrors(cusparseCreateDnVec(&vecAx, N, d_Ax, CUDA_R_32F));
/* Allocate workspace for cuSPARSE */
size_t bufferSize = 0;
checkCudaErrors(cusparseSpMV_bufferSize(
cusparseHandle, CUSPARSE_OPERATION_NON_TRANSPOSE, &alpha, matA, vecx,
&beta, vecAx, CUDA_R_32F, CUSPARSE_SPMV_ALG_DEFAULT, &bufferSize));
void *buffer = NULL;
checkCudaErrors(cudaMalloc(&buffer, bufferSize));
cusparseMatDescr_t descr = 0;
checkCudaErrors(cusparseCreateMatDescr(&descr));
checkCudaErrors(cusparseSetMatType(descr, CUSPARSE_MATRIX_TYPE_GENERAL));
checkCudaErrors(cusparseSetMatIndexBase(descr, CUSPARSE_INDEX_BASE_ZERO));
int numBlocks = 0, blockSize = 0;
checkCudaErrors(
cudaOccupancyMaxPotentialBlockSize(&numBlocks, &blockSize, initVectors));
checkCudaErrors(cudaMemcpyAsync(d_col, J, nz * sizeof(int),
cudaMemcpyHostToDevice, stream1));
checkCudaErrors(cudaMemcpyAsync(d_row, I, (N + 1) * sizeof(int),
cudaMemcpyHostToDevice, stream1));
checkCudaErrors(cudaMemcpyAsync(d_val, val, nz * sizeof(float),
cudaMemcpyHostToDevice, stream1));
initVectors<<<numBlocks, blockSize, 0, stream1>>>(d_r, d_x, N);
alpha = 1.0;
alpham1 = -1.0;
beta = 0.0;
checkCudaErrors(cusparseSetStream(cusparseHandle, stream1));
checkCudaErrors(cusparseSpMV(cusparseHandle, CUSPARSE_OPERATION_NON_TRANSPOSE,
&alpha, matA, vecx, &beta, vecAx, CUDA_R_32F,
CUSPARSE_SPMV_ALG_DEFAULT, buffer));
checkCudaErrors(cublasSetStream(cublasHandle, stream1));
checkCudaErrors(cublasSaxpy(cublasHandle, N, &alpham1, d_Ax, 1, d_r, 1));
checkCudaErrors(
cublasSetPointerMode(cublasHandle, CUBLAS_POINTER_MODE_DEVICE));
checkCudaErrors(cublasSdot(cublasHandle, N, d_r, 1, d_r, 1, d_r1));
k = 1;
// First Iteration when k=1 starts
checkCudaErrors(cublasScopy(cublasHandle, N, d_r, 1, d_p, 1));
checkCudaErrors(cusparseSpMV(cusparseHandle, CUSPARSE_OPERATION_NON_TRANSPOSE,
&alpha, matA, vecp, &beta, vecAx, CUDA_R_32F,
CUSPARSE_SPMV_ALG_DEFAULT, buffer));
checkCudaErrors(cublasSdot(cublasHandle, N, d_p, 1, d_Ax, 1, d_dot));
r1_div_x<<<1, 1, 0, stream1>>>(d_r1, d_dot, d_a);
checkCudaErrors(cublasSaxpy(cublasHandle, N, d_a, d_p, 1, d_x, 1));
a_minus<<<1, 1, 0, stream1>>>(d_a, d_na);
checkCudaErrors(cublasSaxpy(cublasHandle, N, d_na, d_Ax, 1, d_r, 1));
checkCudaErrors(cudaMemcpyAsync(d_r0, d_r1, sizeof(float),
cudaMemcpyDeviceToDevice, stream1));
checkCudaErrors(cublasSdot(cublasHandle, N, d_r, 1, d_r, 1, d_r1));
checkCudaErrors(cudaMemcpyAsync(&r1, d_r1, sizeof(float),
cudaMemcpyDeviceToHost, stream1));
checkCudaErrors(cudaStreamSynchronize(stream1));
printf("iteration = %3d, residual = %e\n", k, sqrt(r1));
// First Iteration when k=1 ends
k++;
#if WITH_GRAPH
cudaGraph_t initGraph;
checkCudaErrors(cudaStreamCreate(&streamForGraph));
checkCudaErrors(cublasSetStream(cublasHandle, stream1));
checkCudaErrors(cusparseSetStream(cusparseHandle, stream1));
checkCudaErrors(cudaStreamBeginCapture(stream1, cudaStreamCaptureModeGlobal));
r1_div_x<<<1, 1, 0, stream1>>>(d_r1, d_r0, d_b);
cublasSetPointerMode(cublasHandle, CUBLAS_POINTER_MODE_DEVICE);
checkCudaErrors(cublasSscal(cublasHandle, N, d_b, d_p, 1));
cublasSetPointerMode(cublasHandle, CUBLAS_POINTER_MODE_HOST);
checkCudaErrors(cublasSaxpy(cublasHandle, N, &alpha, d_r, 1, d_p, 1));
cublasSetPointerMode(cublasHandle, CUBLAS_POINTER_MODE_DEVICE);
checkCudaErrors(
cusparseSetPointerMode(cusparseHandle, CUSPARSE_POINTER_MODE_HOST));
checkCudaErrors(cusparseSpMV(cusparseHandle, CUSPARSE_OPERATION_NON_TRANSPOSE,
&alpha, matA, vecp, &beta, vecAx, CUDA_R_32F,
CUSPARSE_SPMV_ALG_DEFAULT, buffer));
checkCudaErrors(cudaMemsetAsync(d_dot, 0, sizeof(float), stream1));
checkCudaErrors(cublasSdot(cublasHandle, N, d_p, 1, d_Ax, 1, d_dot));
r1_div_x<<<1, 1, 0, stream1>>>(d_r1, d_dot, d_a);
checkCudaErrors(cublasSaxpy(cublasHandle, N, d_a, d_p, 1, d_x, 1));
a_minus<<<1, 1, 0, stream1>>>(d_a, d_na);
checkCudaErrors(cublasSaxpy(cublasHandle, N, d_na, d_Ax, 1, d_r, 1));
checkCudaErrors(cudaMemcpyAsync(d_r0, d_r1, sizeof(float),
cudaMemcpyDeviceToDevice, stream1));
checkCudaErrors(cudaMemsetAsync(d_r1, 0, sizeof(float), stream1));
checkCudaErrors(cublasSdot(cublasHandle, N, d_r, 1, d_r, 1, d_r1));
checkCudaErrors(cudaMemcpyAsync((float *)&r1, d_r1, sizeof(float),
cudaMemcpyDeviceToHost, stream1));
checkCudaErrors(cudaStreamEndCapture(stream1, &initGraph));
cudaGraphExec_t graphExec;
checkCudaErrors(cudaGraphInstantiate(&graphExec, initGraph, NULL, NULL, 0));
#endif
checkCudaErrors(cublasSetStream(cublasHandle, stream1));
checkCudaErrors(cusparseSetStream(cusparseHandle, stream1));
while (r1 > tol * tol && k <= max_iter) {
#if WITH_GRAPH
checkCudaErrors(cudaGraphLaunch(graphExec, streamForGraph));
checkCudaErrors(cudaStreamSynchronize(streamForGraph));
#else
r1_div_x<<<1, 1, 0, stream1>>>(d_r1, d_r0, d_b);
cublasSetPointerMode(cublasHandle, CUBLAS_POINTER_MODE_DEVICE);
checkCudaErrors(cublasSscal(cublasHandle, N, d_b, d_p, 1));
cublasSetPointerMode(cublasHandle, CUBLAS_POINTER_MODE_HOST);
checkCudaErrors(cublasSaxpy(cublasHandle, N, &alpha, d_r, 1, d_p, 1));
checkCudaErrors(cusparseSpMV(
cusparseHandle, CUSPARSE_OPERATION_NON_TRANSPOSE, &alpha, matA, vecp,
&beta, vecAx, CUDA_R_32F, CUSPARSE_SPMV_ALG_DEFAULT, buffer));
cublasSetPointerMode(cublasHandle, CUBLAS_POINTER_MODE_DEVICE);
checkCudaErrors(cublasSdot(cublasHandle, N, d_p, 1, d_Ax, 1, d_dot));
r1_div_x<<<1, 1, 0, stream1>>>(d_r1, d_dot, d_a);
@@ -344,81 +288,173 @@ int main(int argc, char **argv) {
checkCudaErrors(cublasSaxpy(cublasHandle, N, d_a, d_p, 1, d_x, 1));
a_minus<<<1, 1, 0, stream1>>>(d_a, d_na);
checkCudaErrors(cublasSaxpy(cublasHandle, N, d_na, d_Ax, 1, d_r, 1));
checkCudaErrors(cudaMemcpyAsync(d_r0, d_r1, sizeof(float),
cudaMemcpyDeviceToDevice, stream1));
checkCudaErrors(cudaMemcpyAsync(d_r0, d_r1, sizeof(float), cudaMemcpyDeviceToDevice, stream1));
checkCudaErrors(cublasSdot(cublasHandle, N, d_r, 1, d_r, 1, d_r1));
checkCudaErrors(cudaMemcpyAsync((float *)&r1, d_r1, sizeof(float),
cudaMemcpyDeviceToHost, stream1));
checkCudaErrors(cudaMemcpyAsync(&r1, d_r1, sizeof(float), cudaMemcpyDeviceToHost, stream1));
checkCudaErrors(cudaStreamSynchronize(stream1));
printf("iteration = %3d, residual = %e\n", k, sqrt(r1));
// First Iteration when k=1 ends
k++;
#if WITH_GRAPH
cudaGraph_t initGraph;
checkCudaErrors(cudaStreamCreate(&streamForGraph));
checkCudaErrors(cublasSetStream(cublasHandle, stream1));
checkCudaErrors(cusparseSetStream(cusparseHandle, stream1));
checkCudaErrors(cudaStreamBeginCapture(stream1, cudaStreamCaptureModeGlobal));
r1_div_x<<<1, 1, 0, stream1>>>(d_r1, d_r0, d_b);
cublasSetPointerMode(cublasHandle, CUBLAS_POINTER_MODE_DEVICE);
checkCudaErrors(cublasSscal(cublasHandle, N, d_b, d_p, 1));
cublasSetPointerMode(cublasHandle, CUBLAS_POINTER_MODE_HOST);
checkCudaErrors(cublasSaxpy(cublasHandle, N, &alpha, d_r, 1, d_p, 1));
cublasSetPointerMode(cublasHandle, CUBLAS_POINTER_MODE_DEVICE);
checkCudaErrors(cusparseSetPointerMode(cusparseHandle, CUSPARSE_POINTER_MODE_HOST));
checkCudaErrors(cusparseSpMV(cusparseHandle,
CUSPARSE_OPERATION_NON_TRANSPOSE,
&alpha,
matA,
vecp,
&beta,
vecAx,
CUDA_R_32F,
CUSPARSE_SPMV_ALG_DEFAULT,
buffer));
checkCudaErrors(cudaMemsetAsync(d_dot, 0, sizeof(float), stream1));
checkCudaErrors(cublasSdot(cublasHandle, N, d_p, 1, d_Ax, 1, d_dot));
r1_div_x<<<1, 1, 0, stream1>>>(d_r1, d_dot, d_a);
checkCudaErrors(cublasSaxpy(cublasHandle, N, d_a, d_p, 1, d_x, 1));
a_minus<<<1, 1, 0, stream1>>>(d_a, d_na);
checkCudaErrors(cublasSaxpy(cublasHandle, N, d_na, d_Ax, 1, d_r, 1));
checkCudaErrors(cudaMemcpyAsync(d_r0, d_r1, sizeof(float), cudaMemcpyDeviceToDevice, stream1));
checkCudaErrors(cudaMemsetAsync(d_r1, 0, sizeof(float), stream1));
checkCudaErrors(cublasSdot(cublasHandle, N, d_r, 1, d_r, 1, d_r1));
checkCudaErrors(cudaMemcpyAsync((float *)&r1, d_r1, sizeof(float), cudaMemcpyDeviceToHost, stream1));
checkCudaErrors(cudaStreamEndCapture(stream1, &initGraph));
cudaGraphExec_t graphExec;
checkCudaErrors(cudaGraphInstantiate(&graphExec, initGraph, NULL, NULL, 0));
#endif
checkCudaErrors(cublasSetStream(cublasHandle, stream1));
checkCudaErrors(cusparseSetStream(cusparseHandle, stream1));
while (r1 > tol * tol && k <= max_iter) {
#if WITH_GRAPH
checkCudaErrors(cudaGraphLaunch(graphExec, streamForGraph));
checkCudaErrors(cudaStreamSynchronize(streamForGraph));
#else
r1_div_x<<<1, 1, 0, stream1>>>(d_r1, d_r0, d_b);
cublasSetPointerMode(cublasHandle, CUBLAS_POINTER_MODE_DEVICE);
checkCudaErrors(cublasSscal(cublasHandle, N, d_b, d_p, 1));
cublasSetPointerMode(cublasHandle, CUBLAS_POINTER_MODE_HOST);
checkCudaErrors(cublasSaxpy(cublasHandle, N, &alpha, d_r, 1, d_p, 1));
checkCudaErrors(cusparseSpMV(cusparseHandle,
CUSPARSE_OPERATION_NON_TRANSPOSE,
&alpha,
matA,
vecp,
&beta,
vecAx,
CUDA_R_32F,
CUSPARSE_SPMV_ALG_DEFAULT,
buffer));
cublasSetPointerMode(cublasHandle, CUBLAS_POINTER_MODE_DEVICE);
checkCudaErrors(cublasSdot(cublasHandle, N, d_p, 1, d_Ax, 1, d_dot));
r1_div_x<<<1, 1, 0, stream1>>>(d_r1, d_dot, d_a);
checkCudaErrors(cublasSaxpy(cublasHandle, N, d_a, d_p, 1, d_x, 1));
a_minus<<<1, 1, 0, stream1>>>(d_a, d_na);
checkCudaErrors(cublasSaxpy(cublasHandle, N, d_na, d_Ax, 1, d_r, 1));
checkCudaErrors(cudaMemcpyAsync(d_r0, d_r1, sizeof(float), cudaMemcpyDeviceToDevice, stream1));
checkCudaErrors(cublasSdot(cublasHandle, N, d_r, 1, d_r, 1, d_r1));
checkCudaErrors(cudaMemcpyAsync((float *)&r1, d_r1, sizeof(float), cudaMemcpyDeviceToHost, stream1));
checkCudaErrors(cudaStreamSynchronize(stream1));
#endif
printf("iteration = %3d, residual = %e\n", k, sqrt(r1));
k++;
}
#if WITH_GRAPH
checkCudaErrors(cudaMemcpyAsync(x, d_x, N * sizeof(float), cudaMemcpyDeviceToHost, streamForGraph));
checkCudaErrors(cudaStreamSynchronize(streamForGraph));
#else
checkCudaErrors(cudaMemcpyAsync(x, d_x, N * sizeof(float), cudaMemcpyDeviceToHost, stream1));
checkCudaErrors(cudaStreamSynchronize(stream1));
#endif
printf("iteration = %3d, residual = %e\n", k, sqrt(r1));
k++;
}
#if WITH_GRAPH
checkCudaErrors(cudaMemcpyAsync(x, d_x, N * sizeof(float),
cudaMemcpyDeviceToHost, streamForGraph));
checkCudaErrors(cudaStreamSynchronize(streamForGraph));
#else
checkCudaErrors(cudaMemcpyAsync(x, d_x, N * sizeof(float),
cudaMemcpyDeviceToHost, stream1));
checkCudaErrors(cudaStreamSynchronize(stream1));
#endif
float rsum, diff, err = 0.0;
float rsum, diff, err = 0.0;
for (int i = 0; i < N; i++) {
rsum = 0.0;
for (int i = 0; i < N; i++) {
rsum = 0.0;
for (int j = I[i]; j < I[i + 1]; j++) {
rsum += val[j] * x[J[j]];
}
for (int j = I[i]; j < I[i + 1]; j++) {
rsum += val[j] * x[J[j]];
diff = fabs(rsum - rhs[i]);
if (diff > err) {
err = diff;
}
}
diff = fabs(rsum - rhs[i]);
if (diff > err) {
err = diff;
}
}
#if WITH_GRAPH
checkCudaErrors(cudaGraphExecDestroy(graphExec));
checkCudaErrors(cudaGraphDestroy(initGraph));
checkCudaErrors(cudaStreamDestroy(streamForGraph));
checkCudaErrors(cudaGraphExecDestroy(graphExec));
checkCudaErrors(cudaGraphDestroy(initGraph));
checkCudaErrors(cudaStreamDestroy(streamForGraph));
#endif
checkCudaErrors(cudaStreamDestroy(stream1));
cusparseDestroy(cusparseHandle);
cublasDestroy(cublasHandle);
checkCudaErrors(cudaStreamDestroy(stream1));
cusparseDestroy(cusparseHandle);
cublasDestroy(cublasHandle);
if (matA) {
checkCudaErrors(cusparseDestroySpMat(matA));
}
if (vecx) {
checkCudaErrors(cusparseDestroyDnVec(vecx));
}
if (vecAx) {
checkCudaErrors(cusparseDestroyDnVec(vecAx));
}
if (vecp) {
checkCudaErrors(cusparseDestroyDnVec(vecp));
}
if (matA) {
checkCudaErrors(cusparseDestroySpMat(matA));
}
if (vecx) {
checkCudaErrors(cusparseDestroyDnVec(vecx));
}
if (vecAx) {
checkCudaErrors(cusparseDestroyDnVec(vecAx));
}
if (vecp) {
checkCudaErrors(cusparseDestroyDnVec(vecp));
}
checkCudaErrors(cudaFreeHost(I));
checkCudaErrors(cudaFreeHost(J));
checkCudaErrors(cudaFreeHost(val));
checkCudaErrors(cudaFreeHost(x));
free(rhs);
checkCudaErrors(cudaFree(d_col));
checkCudaErrors(cudaFree(d_row));
checkCudaErrors(cudaFree(d_val));
checkCudaErrors(cudaFree(d_x));
checkCudaErrors(cudaFree(d_r));
checkCudaErrors(cudaFree(d_p));
checkCudaErrors(cudaFree(d_Ax));
checkCudaErrors(cudaFreeHost(I));
checkCudaErrors(cudaFreeHost(J));
checkCudaErrors(cudaFreeHost(val));
checkCudaErrors(cudaFreeHost(x));
free(rhs);
checkCudaErrors(cudaFree(d_col));
checkCudaErrors(cudaFree(d_row));
checkCudaErrors(cudaFree(d_val));
checkCudaErrors(cudaFree(d_x));
checkCudaErrors(cudaFree(d_r));
checkCudaErrors(cudaFree(d_p));
checkCudaErrors(cudaFree(d_Ax));
printf("Test Summary: Error amount = %f\n", err);
exit((k <= max_iter) ? 0 : 1);
printf("Test Summary: Error amount = %f\n", err);
exit((k <= max_iter) ? 0 : 1);
}

View File

@@ -32,57 +32,57 @@
*/
// includes, system
#include <cuda_runtime.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cuda_runtime.h>
// Utilities and system includes
#include <helper_cuda.h> // helper function CUDA error checking and initialization
#include <helper_functions.h> // helper for shared functions common to CUDA Samples
#include <cooperative_groups.h>
#include <cooperative_groups/reduce.h>
#include <helper_cuda.h> // helper function CUDA error checking and initialization
#include <helper_functions.h> // helper for shared functions common to CUDA Samples
namespace cg = cooperative_groups;
const char *sSDKname = "conjugateGradientMultiBlockCG";
#define ENABLE_CPU_DEBUG_CODE 0
#define THREADS_PER_BLOCK 512
#define THREADS_PER_BLOCK 512
/* genTridiag: generate a random tridiagonal symmetric matrix */
void genTridiag(int *I, int *J, float *val, int N, int nz) {
I[0] = 0, J[0] = 0, J[1] = 1;
val[0] = static_cast<float>(rand()) / RAND_MAX + 10.0f;
val[1] = static_cast<float>(rand()) / RAND_MAX;
int start;
void genTridiag(int *I, int *J, float *val, int N, int nz)
{
I[0] = 0, J[0] = 0, J[1] = 1;
val[0] = static_cast<float>(rand()) / RAND_MAX + 10.0f;
val[1] = static_cast<float>(rand()) / RAND_MAX;
int start;
for (int i = 1; i < N; i++) {
if (i > 1) {
I[i] = I[i - 1] + 3;
} else {
I[1] = 2;
for (int i = 1; i < N; i++) {
if (i > 1) {
I[i] = I[i - 1] + 3;
}
else {
I[1] = 2;
}
start = (i - 1) * 3 + 2;
J[start] = i - 1;
J[start + 1] = i;
if (i < N - 1) {
J[start + 2] = i + 1;
}
val[start] = val[start - 1];
val[start + 1] = static_cast<float>(rand()) / RAND_MAX + 10.0f;
if (i < N - 1) {
val[start + 2] = static_cast<float>(rand()) / RAND_MAX;
}
}
start = (i - 1) * 3 + 2;
J[start] = i - 1;
J[start + 1] = i;
if (i < N - 1) {
J[start + 2] = i + 1;
}
val[start] = val[start - 1];
val[start + 1] = static_cast<float>(rand()) / RAND_MAX + 10.0f;
if (i < N - 1) {
val[start + 2] = static_cast<float>(rand()) / RAND_MAX;
}
}
I[N] = nz;
I[N] = nz;
}
// I - contains location of the given non-zero element in the row of the matrix
@@ -90,213 +90,199 @@ void genTridiag(int *I, int *J, float *val, int N, int nz) {
// matrix val - contains values of the given non-zero elements of the matrix
// inputVecX - input vector to be multiplied
// outputVecY - resultant vector
void cpuSpMV(int *I, int *J, float *val, int nnz, int num_rows, float alpha,
float *inputVecX, float *outputVecY) {
for (int i = 0; i < num_rows; i++) {
int num_elems_this_row = I[i + 1] - I[i];
void cpuSpMV(int *I, int *J, float *val, int nnz, int num_rows, float alpha, float *inputVecX, float *outputVecY)
{
for (int i = 0; i < num_rows; i++) {
int num_elems_this_row = I[i + 1] - I[i];
float output = 0.0;
for (int j = 0; j < num_elems_this_row; j++) {
output += alpha * val[I[i] + j] * inputVecX[J[I[i] + j]];
}
outputVecY[i] = output;
}
return;
}
double dotProduct(float *vecA, float *vecB, int size) {
double result = 0.0;
for (int i = 0; i < size; i++) {
result = result + (vecA[i] * vecB[i]);
}
return result;
}
void scaleVector(float *vec, float alpha, int size) {
for (int i = 0; i < size; i++) {
vec[i] = alpha * vec[i];
}
}
void saxpy(float *x, float *y, float a, int size) {
for (int i = 0; i < size; i++) {
y[i] = a * x[i] + y[i];
}
}
void cpuConjugateGrad(int *I, int *J, float *val, float *x, float *Ax, float *p,
float *r, int nnz, int N, float tol) {
int max_iter = 10000;
float alpha = 1.0;
float alpham1 = -1.0;
float r0 = 0.0, b, a, na;
cpuSpMV(I, J, val, nnz, N, alpha, x, Ax);
saxpy(Ax, r, alpham1, N);
float r1 = dotProduct(r, r, N);
int k = 1;
while (r1 > tol * tol && k <= max_iter) {
if (k > 1) {
b = r1 / r0;
scaleVector(p, b, N);
saxpy(r, p, alpha, N);
} else {
for (int i = 0; i < N; i++) p[i] = r[i];
float output = 0.0;
for (int j = 0; j < num_elems_this_row; j++) {
output += alpha * val[I[i] + j] * inputVecX[J[I[i] + j]];
}
outputVecY[i] = output;
}
cpuSpMV(I, J, val, nnz, N, alpha, p, Ax);
float dot = dotProduct(p, Ax, N);
a = r1 / dot;
saxpy(p, x, a, N);
na = -a;
saxpy(Ax, r, na, N);
r0 = r1;
r1 = dotProduct(r, r, N);
printf("\nCPU code iteration = %3d, residual = %e\n", k, sqrt(r1));
k++;
}
return;
}
__device__ void gpuSpMV(int *I, int *J, float *val, int nnz, int num_rows,
float alpha, float *inputVecX, float *outputVecY,
cg::thread_block &cta, const cg::grid_group &grid) {
for (int i = grid.thread_rank(); i < num_rows; i += grid.size()) {
int row_elem = I[i];
int next_row_elem = I[i + 1];
int num_elems_this_row = next_row_elem - row_elem;
double dotProduct(float *vecA, float *vecB, int size)
{
double result = 0.0;
float output = 0.0;
for (int j = 0; j < num_elems_this_row; j++) {
// I or J or val arrays - can be put in shared memory
// as the access is random and reused in next calls of gpuSpMV function.
output += alpha * val[row_elem + j] * inputVecX[J[row_elem + j]];
for (int i = 0; i < size; i++) {
result = result + (vecA[i] * vecB[i]);
}
outputVecY[i] = output;
}
return result;
}
__device__ void gpuSaxpy(float *x, float *y, float a, int size,
const cg::grid_group &grid) {
for (int i = grid.thread_rank(); i < size; i += grid.size()) {
y[i] = a * x[i] + y[i];
}
void scaleVector(float *vec, float alpha, int size)
{
for (int i = 0; i < size; i++) {
vec[i] = alpha * vec[i];
}
}
__device__ void gpuDotProduct(float *vecA, float *vecB, double *result,
int size, const cg::thread_block &cta,
const cg::grid_group &grid) {
extern __shared__ double tmp[];
void saxpy(float *x, float *y, float a, int size)
{
for (int i = 0; i < size; i++) {
y[i] = a * x[i] + y[i];
}
}
double temp_sum = 0.0;
for (int i = grid.thread_rank(); i < size; i += grid.size()) {
temp_sum += static_cast<double>(vecA[i] * vecB[i]);
}
void cpuConjugateGrad(int *I, int *J, float *val, float *x, float *Ax, float *p, float *r, int nnz, int N, float tol)
{
int max_iter = 10000;
cg::thread_block_tile<32> tile32 = cg::tiled_partition<32>(cta);
float alpha = 1.0;
float alpham1 = -1.0;
float r0 = 0.0, b, a, na;
temp_sum = cg::reduce(tile32, temp_sum, cg::plus<double>());
cpuSpMV(I, J, val, nnz, N, alpha, x, Ax);
saxpy(Ax, r, alpham1, N);
if (tile32.thread_rank() == 0) {
tmp[tile32.meta_group_rank()] = temp_sum;
}
float r1 = dotProduct(r, r, N);
cg::sync(cta);
int k = 1;
if (tile32.meta_group_rank() == 0) {
temp_sum = tile32.thread_rank() < tile32.meta_group_size() ? tmp[tile32.thread_rank()] : 0.0;
temp_sum = cg::reduce(tile32, temp_sum, cg::plus<double>());
while (r1 > tol * tol && k <= max_iter) {
if (k > 1) {
b = r1 / r0;
scaleVector(p, b, N);
saxpy(r, p, alpha, N);
}
else {
for (int i = 0; i < N; i++)
p[i] = r[i];
}
cpuSpMV(I, J, val, nnz, N, alpha, p, Ax);
float dot = dotProduct(p, Ax, N);
a = r1 / dot;
saxpy(p, x, a, N);
na = -a;
saxpy(Ax, r, na, N);
r0 = r1;
r1 = dotProduct(r, r, N);
printf("\nCPU code iteration = %3d, residual = %e\n", k, sqrt(r1));
k++;
}
}
__device__ void gpuSpMV(int *I,
int *J,
float *val,
int nnz,
int num_rows,
float alpha,
float *inputVecX,
float *outputVecY,
cg::thread_block &cta,
const cg::grid_group &grid)
{
for (int i = grid.thread_rank(); i < num_rows; i += grid.size()) {
int row_elem = I[i];
int next_row_elem = I[i + 1];
int num_elems_this_row = next_row_elem - row_elem;
float output = 0.0;
for (int j = 0; j < num_elems_this_row; j++) {
// I or J or val arrays - can be put in shared memory
// as the access is random and reused in next calls of gpuSpMV function.
output += alpha * val[row_elem + j] * inputVecX[J[row_elem + j]];
}
outputVecY[i] = output;
}
}
__device__ void gpuSaxpy(float *x, float *y, float a, int size, const cg::grid_group &grid)
{
for (int i = grid.thread_rank(); i < size; i += grid.size()) {
y[i] = a * x[i] + y[i];
}
}
__device__ void gpuDotProduct(float *vecA,
float *vecB,
double *result,
int size,
const cg::thread_block &cta,
const cg::grid_group &grid)
{
extern __shared__ double tmp[];
double temp_sum = 0.0;
for (int i = grid.thread_rank(); i < size; i += grid.size()) {
temp_sum += static_cast<double>(vecA[i] * vecB[i]);
}
cg::thread_block_tile<32> tile32 = cg::tiled_partition<32>(cta);
temp_sum = cg::reduce(tile32, temp_sum, cg::plus<double>());
if (tile32.thread_rank() == 0) {
atomicAdd(result, temp_sum);
}
}
}
__device__ void gpuCopyVector(float *srcA, float *destB, int size,
const cg::grid_group &grid) {
for (int i = grid.thread_rank(); i < size; i += grid.size()) {
destB[i] = srcA[i];
}
}
__device__ void gpuScaleVectorAndSaxpy(const float *x, float *y, float a, float scale, int size,
const cg::grid_group &grid) {
for (int i = grid.thread_rank(); i < size; i += grid.size()) {
y[i] = a * x[i] + scale * y[i];
}
}
extern "C" __global__ void gpuConjugateGradient(int *I, int *J, float *val,
float *x, float *Ax, float *p,
float *r, double *dot_result,
int nnz, int N, float tol) {
cg::thread_block cta = cg::this_thread_block();
cg::grid_group grid = cg::this_grid();
int max_iter = 10000;
float alpha = 1.0;
float alpham1 = -1.0;
float r0 = 0.0, r1, b, a, na;
gpuSpMV(I, J, val, nnz, N, alpha, x, Ax, cta, grid);
cg::sync(grid);
gpuSaxpy(Ax, r, alpham1, N, grid);
cg::sync(grid);
gpuDotProduct(r, r, dot_result, N, cta, grid);
cg::sync(grid);
r1 = *dot_result;
int k = 1;
while (r1 > tol * tol && k <= max_iter) {
if (k > 1) {
b = r1 / r0;
gpuScaleVectorAndSaxpy(r, p, alpha, b, N, grid);
} else {
gpuCopyVector(r, p, N, grid);
tmp[tile32.meta_group_rank()] = temp_sum;
}
cg::sync(grid);
cg::sync(cta);
gpuSpMV(I, J, val, nnz, N, alpha, p, Ax, cta, grid);
if (tile32.meta_group_rank() == 0) {
temp_sum = tile32.thread_rank() < tile32.meta_group_size() ? tmp[tile32.thread_rank()] : 0.0;
temp_sum = cg::reduce(tile32, temp_sum, cg::plus<double>());
if (threadIdx.x == 0 && blockIdx.x == 0) *dot_result = 0.0;
if (tile32.thread_rank() == 0) {
atomicAdd(result, temp_sum);
}
}
}
__device__ void gpuCopyVector(float *srcA, float *destB, int size, const cg::grid_group &grid)
{
for (int i = grid.thread_rank(); i < size; i += grid.size()) {
destB[i] = srcA[i];
}
}
__device__ void
gpuScaleVectorAndSaxpy(const float *x, float *y, float a, float scale, int size, const cg::grid_group &grid)
{
for (int i = grid.thread_rank(); i < size; i += grid.size()) {
y[i] = a * x[i] + scale * y[i];
}
}
extern "C" __global__ void gpuConjugateGradient(int *I,
int *J,
float *val,
float *x,
float *Ax,
float *p,
float *r,
double *dot_result,
int nnz,
int N,
float tol)
{
cg::thread_block cta = cg::this_thread_block();
cg::grid_group grid = cg::this_grid();
int max_iter = 10000;
float alpha = 1.0;
float alpham1 = -1.0;
float r0 = 0.0, r1, b, a, na;
gpuSpMV(I, J, val, nnz, N, alpha, x, Ax, cta, grid);
cg::sync(grid);
gpuDotProduct(p, Ax, dot_result, N, cta, grid);
cg::sync(grid);
a = r1 / *dot_result;
gpuSaxpy(p, x, a, N, grid);
na = -a;
gpuSaxpy(Ax, r, na, N, grid);
r0 = r1;
cg::sync(grid);
if (threadIdx.x == 0 && blockIdx.x == 0) *dot_result = 0.0;
gpuSaxpy(Ax, r, alpham1, N, grid);
cg::sync(grid);
@@ -305,188 +291,237 @@ extern "C" __global__ void gpuConjugateGradient(int *I, int *J, float *val,
cg::sync(grid);
r1 = *dot_result;
k++;
}
int k = 1;
while (r1 > tol * tol && k <= max_iter) {
if (k > 1) {
b = r1 / r0;
gpuScaleVectorAndSaxpy(r, p, alpha, b, N, grid);
}
else {
gpuCopyVector(r, p, N, grid);
}
cg::sync(grid);
gpuSpMV(I, J, val, nnz, N, alpha, p, Ax, cta, grid);
if (threadIdx.x == 0 && blockIdx.x == 0)
*dot_result = 0.0;
cg::sync(grid);
gpuDotProduct(p, Ax, dot_result, N, cta, grid);
cg::sync(grid);
a = r1 / *dot_result;
gpuSaxpy(p, x, a, N, grid);
na = -a;
gpuSaxpy(Ax, r, na, N, grid);
r0 = r1;
cg::sync(grid);
if (threadIdx.x == 0 && blockIdx.x == 0)
*dot_result = 0.0;
cg::sync(grid);
gpuDotProduct(r, r, dot_result, N, cta, grid);
cg::sync(grid);
r1 = *dot_result;
k++;
}
}
bool areAlmostEqual(float a, float b, float maxRelDiff) {
float diff = fabsf(a - b);
float abs_a = fabsf(a);
float abs_b = fabsf(b);
float largest = abs_a > abs_b ? abs_a : abs_b;
bool areAlmostEqual(float a, float b, float maxRelDiff)
{
float diff = fabsf(a - b);
float abs_a = fabsf(a);
float abs_b = fabsf(b);
float largest = abs_a > abs_b ? abs_a : abs_b;
if (diff <= largest * maxRelDiff) {
return true;
} else {
printf("maxRelDiff = %.8e\n", maxRelDiff);
printf(
"diff %.8e > largest * maxRelDiff %.8e therefore %.8e and %.8e are not "
"same\n",
diff, largest * maxRelDiff, a, b);
return false;
}
if (diff <= largest * maxRelDiff) {
return true;
}
else {
printf("maxRelDiff = %.8e\n", maxRelDiff);
printf("diff %.8e > largest * maxRelDiff %.8e therefore %.8e and %.8e are not "
"same\n",
diff,
largest * maxRelDiff,
a,
b);
return false;
}
}
int main(int argc, char **argv) {
int N = 0, nz = 0, *I = NULL, *J = NULL;
float *val = NULL;
const float tol = 1e-5f;
float *x;
float *rhs;
float r1;
float *r, *p, *Ax;
cudaEvent_t start, stop;
int main(int argc, char **argv)
{
int N = 0, nz = 0, *I = NULL, *J = NULL;
float *val = NULL;
const float tol = 1e-5f;
float *x;
float *rhs;
float r1;
float *r, *p, *Ax;
cudaEvent_t start, stop;
printf("Starting [%s]...\n", sSDKname);
printf("Starting [%s]...\n", sSDKname);
// This will pick the best possible CUDA capable device
cudaDeviceProp deviceProp;
int devID = findCudaDevice(argc, (const char **)argv);
checkCudaErrors(cudaGetDeviceProperties(&deviceProp, devID));
// This will pick the best possible CUDA capable device
cudaDeviceProp deviceProp;
int devID = findCudaDevice(argc, (const char **)argv);
checkCudaErrors(cudaGetDeviceProperties(&deviceProp, devID));
if (!deviceProp.managedMemory) {
// This sample requires being run on a device that supports Unified Memory
fprintf(stderr, "Unified Memory not supported on this device\n");
exit(EXIT_WAIVED);
}
// This sample requires being run on a device that supports Cooperative Kernel
// Launch
if (!deviceProp.cooperativeLaunch) {
printf(
"\nSelected GPU (%d) does not support Cooperative Kernel Launch, "
"Waiving the run\n",
devID);
exit(EXIT_WAIVED);
}
// Statistics about the GPU device
printf(
"> GPU device has %d Multi-Processors, SM %d.%d compute capabilities\n\n",
deviceProp.multiProcessorCount, deviceProp.major, deviceProp.minor);
/* Generate a random tridiagonal symmetric matrix in CSR format */
N = 1048576;
nz = (N - 2) * 3 + 4;
cudaMallocManaged(reinterpret_cast<void **>(&I), sizeof(int) * (N + 1));
cudaMallocManaged(reinterpret_cast<void **>(&J), sizeof(int) * nz);
cudaMallocManaged(reinterpret_cast<void **>(&val), sizeof(float) * nz);
genTridiag(I, J, val, N, nz);
cudaMallocManaged(reinterpret_cast<void **>(&x), sizeof(float) * N);
cudaMallocManaged(reinterpret_cast<void **>(&rhs), sizeof(float) * N);
double *dot_result;
cudaMallocManaged(reinterpret_cast<void **>(&dot_result), sizeof(double));
*dot_result = 0.0;
// temp memory for CG
checkCudaErrors(
cudaMallocManaged(reinterpret_cast<void **>(&r), N * sizeof(float)));
checkCudaErrors(
cudaMallocManaged(reinterpret_cast<void **>(&p), N * sizeof(float)));
checkCudaErrors(
cudaMallocManaged(reinterpret_cast<void **>(&Ax), N * sizeof(float)));
cudaDeviceSynchronize();
checkCudaErrors(cudaEventCreate(&start));
checkCudaErrors(cudaEventCreate(&stop));
#if ENABLE_CPU_DEBUG_CODE
float *Ax_cpu = reinterpret_cast<float *>(malloc(sizeof(float) * N));
float *r_cpu = reinterpret_cast<float *>(malloc(sizeof(float) * N));
float *p_cpu = reinterpret_cast<float *>(malloc(sizeof(float) * N));
float *x_cpu = reinterpret_cast<float *>(malloc(sizeof(float) * N));
for (int i = 0; i < N; i++) {
r_cpu[i] = 1.0;
Ax_cpu[i] = x_cpu[i] = 0.0;
}
#endif
for (int i = 0; i < N; i++) {
r[i] = rhs[i] = 1.0;
x[i] = 0.0;
}
void *kernelArgs[] = {
(void *)&I, (void *)&J, (void *)&val, (void *)&x,
(void *)&Ax, (void *)&p, (void *)&r, (void *)&dot_result,
(void *)&nz, (void *)&N, (void *)&tol,
};
int sMemSize = sizeof(double) * ((THREADS_PER_BLOCK/32) + 1);
int numBlocksPerSm = 0;
int numThreads = THREADS_PER_BLOCK;
checkCudaErrors(cudaOccupancyMaxActiveBlocksPerMultiprocessor(
&numBlocksPerSm, gpuConjugateGradient, numThreads, sMemSize));
int numSms = deviceProp.multiProcessorCount;
dim3 dimGrid(numSms * numBlocksPerSm, 1, 1),
dimBlock(THREADS_PER_BLOCK, 1, 1);
checkCudaErrors(cudaEventRecord(start, 0));
checkCudaErrors(cudaLaunchCooperativeKernel((void *)gpuConjugateGradient,
dimGrid, dimBlock, kernelArgs,
sMemSize, NULL));
checkCudaErrors(cudaEventRecord(stop, 0));
checkCudaErrors(cudaDeviceSynchronize());
float time;
checkCudaErrors(cudaEventElapsedTime(&time, start, stop));
r1 = *dot_result;
printf("GPU Final, residual = %e, kernel execution time = %f ms\n", sqrt(r1),
time);
#if ENABLE_CPU_DEBUG_CODE
cpuConjugateGrad(I, J, val, x_cpu, Ax_cpu, p_cpu, r_cpu, nz, N, tol);
#endif
float rsum, diff, err = 0.0;
for (int i = 0; i < N; i++) {
rsum = 0.0;
for (int j = I[i]; j < I[i + 1]; j++) {
rsum += val[j] * x[J[j]];
if (!deviceProp.managedMemory) {
// This sample requires being run on a device that supports Unified Memory
fprintf(stderr, "Unified Memory not supported on this device\n");
exit(EXIT_WAIVED);
}
diff = fabs(rsum - rhs[i]);
if (diff > err) {
err = diff;
// This sample requires being run on a device that supports Cooperative Kernel
// Launch
if (!deviceProp.cooperativeLaunch) {
printf("\nSelected GPU (%d) does not support Cooperative Kernel Launch, "
"Waiving the run\n",
devID);
exit(EXIT_WAIVED);
}
}
checkCudaErrors(cudaFree(I));
checkCudaErrors(cudaFree(J));
checkCudaErrors(cudaFree(val));
checkCudaErrors(cudaFree(x));
checkCudaErrors(cudaFree(rhs));
checkCudaErrors(cudaFree(r));
checkCudaErrors(cudaFree(p));
checkCudaErrors(cudaFree(Ax));
checkCudaErrors(cudaFree(dot_result));
checkCudaErrors(cudaEventDestroy(start));
checkCudaErrors(cudaEventDestroy(stop));
// Statistics about the GPU device
printf("> GPU device has %d Multi-Processors, SM %d.%d compute capabilities\n\n",
deviceProp.multiProcessorCount,
deviceProp.major,
deviceProp.minor);
/* Generate a random tridiagonal symmetric matrix in CSR format */
N = 1048576;
nz = (N - 2) * 3 + 4;
cudaMallocManaged(reinterpret_cast<void **>(&I), sizeof(int) * (N + 1));
cudaMallocManaged(reinterpret_cast<void **>(&J), sizeof(int) * nz);
cudaMallocManaged(reinterpret_cast<void **>(&val), sizeof(float) * nz);
genTridiag(I, J, val, N, nz);
cudaMallocManaged(reinterpret_cast<void **>(&x), sizeof(float) * N);
cudaMallocManaged(reinterpret_cast<void **>(&rhs), sizeof(float) * N);
double *dot_result;
cudaMallocManaged(reinterpret_cast<void **>(&dot_result), sizeof(double));
*dot_result = 0.0;
// temp memory for CG
checkCudaErrors(cudaMallocManaged(reinterpret_cast<void **>(&r), N * sizeof(float)));
checkCudaErrors(cudaMallocManaged(reinterpret_cast<void **>(&p), N * sizeof(float)));
checkCudaErrors(cudaMallocManaged(reinterpret_cast<void **>(&Ax), N * sizeof(float)));
cudaDeviceSynchronize();
checkCudaErrors(cudaEventCreate(&start));
checkCudaErrors(cudaEventCreate(&stop));
#if ENABLE_CPU_DEBUG_CODE
free(Ax_cpu);
free(r_cpu);
free(p_cpu);
free(x_cpu);
float *Ax_cpu = reinterpret_cast<float *>(malloc(sizeof(float) * N));
float *r_cpu = reinterpret_cast<float *>(malloc(sizeof(float) * N));
float *p_cpu = reinterpret_cast<float *>(malloc(sizeof(float) * N));
float *x_cpu = reinterpret_cast<float *>(malloc(sizeof(float) * N));
for (int i = 0; i < N; i++) {
r_cpu[i] = 1.0;
Ax_cpu[i] = x_cpu[i] = 0.0;
}
#endif
printf("Test Summary: Error amount = %f \n", err);
fprintf(stdout, "&&&& conjugateGradientMultiBlockCG %s\n",
(sqrt(r1) < tol) ? "PASSED" : "FAILED");
exit((sqrt(r1) < tol) ? EXIT_SUCCESS : EXIT_FAILURE);
for (int i = 0; i < N; i++) {
r[i] = rhs[i] = 1.0;
x[i] = 0.0;
}
void *kernelArgs[] = {
(void *)&I,
(void *)&J,
(void *)&val,
(void *)&x,
(void *)&Ax,
(void *)&p,
(void *)&r,
(void *)&dot_result,
(void *)&nz,
(void *)&N,
(void *)&tol,
};
int sMemSize = sizeof(double) * ((THREADS_PER_BLOCK / 32) + 1);
int numBlocksPerSm = 0;
int numThreads = THREADS_PER_BLOCK;
checkCudaErrors(
cudaOccupancyMaxActiveBlocksPerMultiprocessor(&numBlocksPerSm, gpuConjugateGradient, numThreads, sMemSize));
int numSms = deviceProp.multiProcessorCount;
dim3 dimGrid(numSms * numBlocksPerSm, 1, 1), dimBlock(THREADS_PER_BLOCK, 1, 1);
checkCudaErrors(cudaEventRecord(start, 0));
checkCudaErrors(
cudaLaunchCooperativeKernel((void *)gpuConjugateGradient, dimGrid, dimBlock, kernelArgs, sMemSize, NULL));
checkCudaErrors(cudaEventRecord(stop, 0));
checkCudaErrors(cudaDeviceSynchronize());
float time;
checkCudaErrors(cudaEventElapsedTime(&time, start, stop));
r1 = *dot_result;
printf("GPU Final, residual = %e, kernel execution time = %f ms\n", sqrt(r1), time);
#if ENABLE_CPU_DEBUG_CODE
cpuConjugateGrad(I, J, val, x_cpu, Ax_cpu, p_cpu, r_cpu, nz, N, tol);
#endif
float rsum, diff, err = 0.0;
for (int i = 0; i < N; i++) {
rsum = 0.0;
for (int j = I[i]; j < I[i + 1]; j++) {
rsum += val[j] * x[J[j]];
}
diff = fabs(rsum - rhs[i]);
if (diff > err) {
err = diff;
}
}
checkCudaErrors(cudaFree(I));
checkCudaErrors(cudaFree(J));
checkCudaErrors(cudaFree(val));
checkCudaErrors(cudaFree(x));
checkCudaErrors(cudaFree(rhs));
checkCudaErrors(cudaFree(r));
checkCudaErrors(cudaFree(p));
checkCudaErrors(cudaFree(Ax));
checkCudaErrors(cudaFree(dot_result));
checkCudaErrors(cudaEventDestroy(start));
checkCudaErrors(cudaEventDestroy(stop));
#if ENABLE_CPU_DEBUG_CODE
free(Ax_cpu);
free(r_cpu);
free(p_cpu);
free(x_cpu);
#endif
printf("Test Summary: Error amount = %f \n", err);
fprintf(stdout, "&&&& conjugateGradientMultiBlockCG %s\n", (sqrt(r1) < tol) ? "PASSED" : "FAILED");
exit((sqrt(r1) < tol) ? EXIT_SUCCESS : EXIT_FAILURE);
}

View File

@@ -44,99 +44,90 @@
// includes, system
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// CUDA Runtime
#include <cuda_runtime.h>
// Using updated (v2) interfaces for CUBLAS and CUSPARSE
#include <cusparse.h>
#include <cublas_v2.h>
#include <cusparse.h>
// Utilities and system includes
#include <helper_functions.h> // shared functions common to CUDA Samples
#include <helper_cuda.h> // CUDA error checking
#include <helper_cuda.h> // CUDA error checking
#include <helper_functions.h> // shared functions common to CUDA Samples
const char *sSDKname = "conjugateGradientPrecond";
const char *sSDKname = "conjugateGradientPrecond";
/*
* Generate a matrix representing a second order regular Laplacian operator
* on a 2D domain in Compressed Sparse Row format.
*/
void genLaplace(int *row_ptr, int *col_ind, float *val, int M, int N, int nz,
float *rhs)
void genLaplace(int *row_ptr, int *col_ind, float *val, int M, int N, int nz, float *rhs)
{
assert(M==N);
int n=(int)sqrt((double)N);
assert(n*n==N);
assert(M == N);
int n = (int)sqrt((double)N);
assert(n * n == N);
printf("laplace dimension = %d\n", n);
int idx = 0;
// loop over degrees of freedom
for (int i = 0; i < N; i++)
{
for (int i = 0; i < N; i++) {
int ix = i % n;
int iy = i / n;
row_ptr[i] = idx;
// up
if (iy > 0)
{
val[idx] = 1.0;
if (iy > 0) {
val[idx] = 1.0;
col_ind[idx] = i - n;
idx++;
}
else
{
else {
rhs[i] -= 1.0;
}
// left
if (ix > 0) {
val[idx] = 1.0;
val[idx] = 1.0;
col_ind[idx] = i - 1;
idx++;
} else {
}
else {
rhs[i] -= 0.0;
}
// center
val[idx] = -4.0;
val[idx] = -4.0;
col_ind[idx] = i;
idx++;
//right
if (ix < n - 1)
{
val[idx] = 1.0;
// right
if (ix < n - 1) {
val[idx] = 1.0;
col_ind[idx] = i + 1;
idx++;
}
else
{
else {
rhs[i] -= 0.0;
}
// down
if (iy < n - 1)
{
val[idx] = 1.0;
if (iy < n - 1) {
val[idx] = 1.0;
col_ind[idx] = i + n;
idx++;
}
else
{
else {
rhs[i] -= 0.0;
}
}
row_ptr[N] = idx;
}
/*
@@ -145,41 +136,41 @@ void genLaplace(int *row_ptr, int *col_ind, float *val, int M, int N, int nz,
* b) using an Incomplete Cholesky preconditioner, and
* c) using an ILU0 preconditioner.
*/
int main(int argc, char **argv){
const int max_iter = 1000;
int k, M = 0, N = 0, nz = 0, *I = NULL, *J = NULL;
int *d_col, *d_row;
int qatest = 0;
const float tol = 1e-12f;
float *x, *rhs;
float r0, r1, alpha, beta;
float *d_val, *d_x;
float *d_zm1, *d_zm2, *d_rm2;
float *d_r, *d_p, *d_omega, *d_y;
float *val = NULL;
float *d_valsILU0;
float rsum, diff, err = 0.0;
float qaerr1, qaerr2 = 0.0;
float dot, numerator, denominator, nalpha;
const float floatone = 1.0;
int main(int argc, char **argv)
{
const int max_iter = 1000;
int k, M = 0, N = 0, nz = 0, *I = NULL, *J = NULL;
int *d_col, *d_row;
int qatest = 0;
const float tol = 1e-12f;
float *x, *rhs;
float r0, r1, alpha, beta;
float *d_val, *d_x;
float *d_zm1, *d_zm2, *d_rm2;
float *d_r, *d_p, *d_omega, *d_y;
float *val = NULL;
float *d_valsILU0;
float rsum, diff, err = 0.0;
float qaerr1, qaerr2 = 0.0;
float dot, numerator, denominator, nalpha;
const float floatone = 1.0;
const float floatzero = 0.0;
int nErrors = 0;
printf("conjugateGradientPrecond starting...\n");
/* QA testing mode */
if (checkCmdLineFlag(argc, (const char **)argv, "qatest")) {
qatest = 1;
}
/* QA testing mode */
if (checkCmdLineFlag(argc, (const char **)argv, "qatest")) {
qatest = 1;
}
/* This will pick the best possible CUDA capable device */
cudaDeviceProp deviceProp;
int devID = findCudaDevice(argc, (const char **)argv);
int devID = findCudaDevice(argc, (const char **)argv);
printf("GPU selected Device ID = %d \n", devID);
if (devID < 0)
{
if (devID < 0) {
printf("Invalid GPU device %d selected, exiting...\n", devID);
exit(EXIT_SUCCESS);
}
@@ -188,21 +179,22 @@ int main(int argc, char **argv){
/* Statistics about the GPU device */
printf("> GPU device has %d Multi-Processors, SM %d.%d compute capabilities\n\n",
deviceProp.multiProcessorCount, deviceProp.major, deviceProp.minor);
deviceProp.multiProcessorCount,
deviceProp.major,
deviceProp.minor);
/* Generate a Laplace matrix in CSR (Compressed Sparse Row) format */
M = N = 16384;
nz = 5 * N - 4 * (int)sqrt((double)N);
I = (int *)malloc(sizeof(int) * (N + 1)); // csr row pointers for matrix A
J = (int *)malloc(sizeof(int) * nz); // csr column indices for matrix A
val = (float *)malloc(sizeof(float) * nz); // csr values for matrix A
x = (float *)malloc(sizeof(float) * N);
rhs = (float *)malloc(sizeof(float) * N);
nz = 5 * N - 4 * (int)sqrt((double)N);
I = (int *)malloc(sizeof(int) * (N + 1)); // csr row pointers for matrix A
J = (int *)malloc(sizeof(int) * nz); // csr column indices for matrix A
val = (float *)malloc(sizeof(float) * nz); // csr values for matrix A
x = (float *)malloc(sizeof(float) * N);
rhs = (float *)malloc(sizeof(float) * N);
for (int i = 0; i < N; i++)
{
rhs[i] = 0.0; // Initialize RHS
x[i] = 0.0; // Initial solution approximation
for (int i = 0; i < N; i++) {
rhs[i] = 0.0; // Initialize RHS
x[i] = 0.0; // Initial solution approximation
}
genLaplace(I, J, val, M, N, nz, rhs);
@@ -236,7 +228,7 @@ int main(int argc, char **argv){
checkCudaErrors(cudaMalloc((void **)&d_rm2, (N) * sizeof(float)));
/* Wrap raw data into cuSPARSE generic API objects */
cusparseDnVecDescr_t vecp = NULL, vecX=NULL, vecY = NULL, vecR = NULL, vecZM1=NULL;
cusparseDnVecDescr_t vecp = NULL, vecX = NULL, vecY = NULL, vecR = NULL, vecZM1 = NULL;
checkCudaErrors(cusparseCreateDnVec(&vecp, N, d_p, CUDA_R_32F));
checkCudaErrors(cusparseCreateDnVec(&vecX, N, d_x, CUDA_R_32F));
checkCudaErrors(cusparseCreateDnVec(&vecY, N, d_y, CUDA_R_32F));
@@ -246,18 +238,12 @@ int main(int argc, char **argv){
checkCudaErrors(cusparseCreateDnVec(&vecomega, N, d_omega, CUDA_R_32F));
/* Initialize problem data */
checkCudaErrors(cudaMemcpy(
d_col, J, nz * sizeof(int), cudaMemcpyHostToDevice));
checkCudaErrors(cudaMemcpy(
d_row, I, (N + 1) * sizeof(int), cudaMemcpyHostToDevice));
checkCudaErrors(cudaMemcpy(
d_val, val, nz * sizeof(float), cudaMemcpyHostToDevice));
checkCudaErrors(cudaMemcpy(
d_val, val, nz * sizeof(float), cudaMemcpyHostToDevice));
checkCudaErrors(cudaMemcpy(
d_x, x, N*sizeof(float), cudaMemcpyHostToDevice));
checkCudaErrors(cudaMemcpy(
d_r, rhs, N * sizeof(float), cudaMemcpyHostToDevice));
checkCudaErrors(cudaMemcpy(d_col, J, nz * sizeof(int), cudaMemcpyHostToDevice));
checkCudaErrors(cudaMemcpy(d_row, I, (N + 1) * sizeof(int), cudaMemcpyHostToDevice));
checkCudaErrors(cudaMemcpy(d_val, val, nz * sizeof(float), cudaMemcpyHostToDevice));
checkCudaErrors(cudaMemcpy(d_val, val, nz * sizeof(float), cudaMemcpyHostToDevice));
checkCudaErrors(cudaMemcpy(d_x, x, N * sizeof(float), cudaMemcpyHostToDevice));
checkCudaErrors(cudaMemcpy(d_r, rhs, N * sizeof(float), cudaMemcpyHostToDevice));
cusparseSpMatDescr_t matA = NULL;
cusparseSpMatDescr_t matM_lower, matM_upper;
@@ -266,73 +252,108 @@ int main(int argc, char **argv){
cusparseFillMode_t fill_upper = CUSPARSE_FILL_MODE_UPPER;
cusparseDiagType_t diag_non_unit = CUSPARSE_DIAG_TYPE_NON_UNIT;
checkCudaErrors(cusparseCreateCsr(
&matA, N, N, nz, d_row, d_col, d_val, CUSPARSE_INDEX_32I,
CUSPARSE_INDEX_32I, CUSPARSE_INDEX_BASE_ZERO, CUDA_R_32F));
checkCudaErrors(cusparseCreateCsr(&matA,
N,
N,
nz,
d_row,
d_col,
d_val,
CUSPARSE_INDEX_32I,
CUSPARSE_INDEX_32I,
CUSPARSE_INDEX_BASE_ZERO,
CUDA_R_32F));
/* Copy A data to ILU(0) vals as input*/
checkCudaErrors(cudaMemcpy(
d_valsILU0, d_val, nz*sizeof(float), cudaMemcpyDeviceToDevice));
//Lower Part
checkCudaErrors( cusparseCreateCsr(&matM_lower, N, N, nz, d_row, d_col, d_valsILU0,
CUSPARSE_INDEX_32I, CUSPARSE_INDEX_32I,
CUSPARSE_INDEX_BASE_ZERO, CUDA_R_32F) );
checkCudaErrors(cudaMemcpy(d_valsILU0, d_val, nz * sizeof(float), cudaMemcpyDeviceToDevice));
checkCudaErrors( cusparseSpMatSetAttribute(matM_lower,
CUSPARSE_SPMAT_FILL_MODE,
&fill_lower, sizeof(fill_lower)) );
checkCudaErrors( cusparseSpMatSetAttribute(matM_lower,
CUSPARSE_SPMAT_DIAG_TYPE,
&diag_unit, sizeof(diag_unit)) );
// Lower Part
checkCudaErrors(cusparseCreateCsr(&matM_lower,
N,
N,
nz,
d_row,
d_col,
d_valsILU0,
CUSPARSE_INDEX_32I,
CUSPARSE_INDEX_32I,
CUSPARSE_INDEX_BASE_ZERO,
CUDA_R_32F));
checkCudaErrors(cusparseSpMatSetAttribute(matM_lower, CUSPARSE_SPMAT_FILL_MODE, &fill_lower, sizeof(fill_lower)));
checkCudaErrors(cusparseSpMatSetAttribute(matM_lower, CUSPARSE_SPMAT_DIAG_TYPE, &diag_unit, sizeof(diag_unit)));
// M_upper
checkCudaErrors( cusparseCreateCsr(&matM_upper, N, N, nz, d_row, d_col, d_valsILU0,
CUSPARSE_INDEX_32I, CUSPARSE_INDEX_32I,
CUSPARSE_INDEX_BASE_ZERO, CUDA_R_32F) );
checkCudaErrors( cusparseSpMatSetAttribute(matM_upper,
CUSPARSE_SPMAT_FILL_MODE,
&fill_upper, sizeof(fill_upper)) );
checkCudaErrors( cusparseSpMatSetAttribute(matM_upper,
CUSPARSE_SPMAT_DIAG_TYPE,
&diag_non_unit,
sizeof(diag_non_unit)) );
checkCudaErrors(cusparseCreateCsr(&matM_upper,
N,
N,
nz,
d_row,
d_col,
d_valsILU0,
CUSPARSE_INDEX_32I,
CUSPARSE_INDEX_32I,
CUSPARSE_INDEX_BASE_ZERO,
CUDA_R_32F));
checkCudaErrors(cusparseSpMatSetAttribute(matM_upper, CUSPARSE_SPMAT_FILL_MODE, &fill_upper, sizeof(fill_upper)));
checkCudaErrors(
cusparseSpMatSetAttribute(matM_upper, CUSPARSE_SPMAT_DIAG_TYPE, &diag_non_unit, sizeof(diag_non_unit)));
/* Create ILU(0) info object */
int bufferSizeLU = 0;
size_t bufferSizeMV, bufferSizeL, bufferSizeU;
void* d_bufferLU, *d_bufferMV, *d_bufferL, *d_bufferU;
void *d_bufferLU, *d_bufferMV, *d_bufferL, *d_bufferU;
cusparseSpSVDescr_t spsvDescrL, spsvDescrU;
cusparseMatDescr_t matLU;
cusparseMatDescr_t matLU;
csrilu02Info_t infoILU = NULL;
checkCudaErrors(cusparseCreateCsrilu02Info(&infoILU));
checkCudaErrors( cusparseCreateMatDescr(&matLU) );
checkCudaErrors( cusparseSetMatType(matLU, CUSPARSE_MATRIX_TYPE_GENERAL) );
checkCudaErrors( cusparseSetMatIndexBase(matLU, CUSPARSE_INDEX_BASE_ZERO) );
checkCudaErrors(cusparseCreateMatDescr(&matLU));
checkCudaErrors(cusparseSetMatType(matLU, CUSPARSE_MATRIX_TYPE_GENERAL));
checkCudaErrors(cusparseSetMatIndexBase(matLU, CUSPARSE_INDEX_BASE_ZERO));
/* Allocate workspace for cuSPARSE */
checkCudaErrors(cusparseSpMV_bufferSize(
cusparseHandle, CUSPARSE_OPERATION_NON_TRANSPOSE, &floatone, matA,
vecp, &floatzero, vecomega, CUDA_R_32F, CUSPARSE_SPMV_ALG_DEFAULT,
&bufferSizeMV));
checkCudaErrors( cudaMalloc(&d_bufferMV, bufferSizeMV) );
checkCudaErrors(cusparseSpMV_bufferSize(cusparseHandle,
CUSPARSE_OPERATION_NON_TRANSPOSE,
&floatone,
matA,
vecp,
&floatzero,
vecomega,
CUDA_R_32F,
CUSPARSE_SPMV_ALG_DEFAULT,
&bufferSizeMV));
checkCudaErrors(cudaMalloc(&d_bufferMV, bufferSizeMV));
checkCudaErrors(cusparseScsrilu02_bufferSize(
cusparseHandle, N, nz, matLU, d_val, d_row, d_col, infoILU, &bufferSizeLU));
checkCudaErrors( cudaMalloc(&d_bufferLU, bufferSizeLU) );
checkCudaErrors(
cusparseScsrilu02_bufferSize(cusparseHandle, N, nz, matLU, d_val, d_row, d_col, infoILU, &bufferSizeLU));
checkCudaErrors(cudaMalloc(&d_bufferLU, bufferSizeLU));
checkCudaErrors( cusparseSpSV_createDescr(&spsvDescrL) );
checkCudaErrors(cusparseSpSV_bufferSize(
cusparseHandle, CUSPARSE_OPERATION_NON_TRANSPOSE, &floatone, matM_lower, vecR, vecX, CUDA_R_32F,
CUSPARSE_SPSV_ALG_DEFAULT, spsvDescrL, &bufferSizeL));
checkCudaErrors( cudaMalloc(&d_bufferL, bufferSizeL) );
checkCudaErrors(cusparseSpSV_createDescr(&spsvDescrL));
checkCudaErrors(cusparseSpSV_bufferSize(cusparseHandle,
CUSPARSE_OPERATION_NON_TRANSPOSE,
&floatone,
matM_lower,
vecR,
vecX,
CUDA_R_32F,
CUSPARSE_SPSV_ALG_DEFAULT,
spsvDescrL,
&bufferSizeL));
checkCudaErrors(cudaMalloc(&d_bufferL, bufferSizeL));
checkCudaErrors( cusparseSpSV_createDescr(&spsvDescrU) );
checkCudaErrors( cusparseSpSV_bufferSize(
cusparseHandle, CUSPARSE_OPERATION_NON_TRANSPOSE, &floatone, matM_upper, vecR, vecX, CUDA_R_32F,
CUSPARSE_SPSV_ALG_DEFAULT, spsvDescrU, &bufferSizeU));
checkCudaErrors( cudaMalloc(&d_bufferU, bufferSizeU) );
checkCudaErrors(cusparseSpSV_createDescr(&spsvDescrU));
checkCudaErrors(cusparseSpSV_bufferSize(cusparseHandle,
CUSPARSE_OPERATION_NON_TRANSPOSE,
&floatone,
matM_upper,
vecR,
vecX,
CUDA_R_32F,
CUSPARSE_SPSV_ALG_DEFAULT,
spsvDescrU,
&bufferSizeU));
checkCudaErrors(cudaMalloc(&d_bufferU, bufferSizeU));
/* Conjugate gradient without preconditioning.
------------------------------------------
@@ -341,61 +362,58 @@ int main(int argc, char **argv){
"Matrix Computations 3rd ed.", Section 10.2.6 */
printf("Convergence of CG without preconditioning: \n");
k = 0;
k = 0;
r0 = 0;
checkCudaErrors(cublasSdot(cublasHandle, N, d_r, 1, d_r, 1, &r1));
while (r1 > tol * tol && k <= max_iter)
{
while (r1 > tol * tol && k <= max_iter) {
k++;
if (k == 1)
{
if (k == 1) {
checkCudaErrors(cublasScopy(cublasHandle, N, d_r, 1, d_p, 1));
}
else
{
else {
beta = r1 / r0;
checkCudaErrors(cublasSscal(cublasHandle, N, &beta, d_p, 1));
checkCudaErrors(cublasSaxpy(
cublasHandle, N, &floatone, d_r, 1, d_p, 1));
checkCudaErrors(cublasSaxpy(cublasHandle, N, &floatone, d_r, 1, d_p, 1));
}
checkCudaErrors(cusparseSpMV(
cusparseHandle, CUSPARSE_OPERATION_NON_TRANSPOSE, &floatone, matA,
vecp, &floatzero, vecomega, CUDA_R_32F, CUSPARSE_SPMV_ALG_DEFAULT,
d_bufferMV));
checkCudaErrors(cusparseSpMV(cusparseHandle,
CUSPARSE_OPERATION_NON_TRANSPOSE,
&floatone,
matA,
vecp,
&floatzero,
vecomega,
CUDA_R_32F,
CUSPARSE_SPMV_ALG_DEFAULT,
d_bufferMV));
checkCudaErrors(cublasSdot(cublasHandle, N, d_p, 1, d_omega, 1, &dot));
alpha = r1 / dot;
checkCudaErrors(cublasSaxpy(cublasHandle, N, &alpha, d_p, 1, d_x, 1));
nalpha = -alpha;
checkCudaErrors(cublasSaxpy(
cublasHandle, N, &nalpha, d_omega, 1, d_r, 1));
checkCudaErrors(cublasSaxpy(cublasHandle, N, &nalpha, d_omega, 1, d_r, 1));
r0 = r1;
checkCudaErrors(cublasSdot(cublasHandle, N, d_r, 1, d_r, 1, &r1));
}
printf(" iteration = %3d, residual = %e \n", k, sqrt(r1));
checkCudaErrors(cudaMemcpy(
x, d_x, N * sizeof(float), cudaMemcpyDeviceToHost));
checkCudaErrors(cudaMemcpy(x, d_x, N * sizeof(float), cudaMemcpyDeviceToHost));
/* check result */
err = 0.0;
for (int i = 0; i < N; i++)
{
for (int i = 0; i < N; i++) {
rsum = 0.0;
for (int j = I[i]; j < I[i + 1]; j++)
{
for (int j = I[i]; j < I[i + 1]; j++) {
rsum += val[j] * x[J[j]];
}
diff = fabs(rsum - rhs[i]);
if (diff > err)
{
if (diff > err) {
err = diff;
}
}
@@ -404,21 +422,17 @@ int main(int argc, char **argv){
nErrors += (k > max_iter) ? 1 : 0;
qaerr1 = err;
if (0)
{
if (0) {
// output result in matlab-style array
int n = (int)sqrt((double)N);
printf("a = [ ");
for (int iy = 0; iy < n; iy++)
{
for (int ix = 0; ix < n; ix++)
{
for (int iy = 0; iy < n; iy++) {
for (int ix = 0; ix < n; ix++) {
printf(" %f ", x[iy * n + ix]);
}
if (iy == n - 1)
{
if (iy == n - 1) {
printf(" ]");
}
@@ -436,110 +450,117 @@ int main(int argc, char **argv){
/* Perform analysis for ILU(0) */
checkCudaErrors(cusparseScsrilu02_analysis(
cusparseHandle, N, nz, descr, d_valsILU0, d_row, d_col, infoILU,
CUSPARSE_SOLVE_POLICY_USE_LEVEL, d_bufferLU));
cusparseHandle, N, nz, descr, d_valsILU0, d_row, d_col, infoILU, CUSPARSE_SOLVE_POLICY_USE_LEVEL, d_bufferLU));
/* generate the ILU(0) factors */
checkCudaErrors(cusparseScsrilu02(
cusparseHandle, N, nz, matLU, d_valsILU0, d_row, d_col, infoILU,
CUSPARSE_SOLVE_POLICY_USE_LEVEL, d_bufferLU));
cusparseHandle, N, nz, matLU, d_valsILU0, d_row, d_col, infoILU, CUSPARSE_SOLVE_POLICY_USE_LEVEL, d_bufferLU));
/* perform triangular solve analysis */
checkCudaErrors(cusparseSpSV_analysis(
cusparseHandle, CUSPARSE_OPERATION_NON_TRANSPOSE, &floatone,
matM_lower, vecR, vecX, CUDA_R_32F,
CUSPARSE_SPSV_ALG_DEFAULT, spsvDescrL, d_bufferL));
checkCudaErrors(cusparseSpSV_analysis(cusparseHandle,
CUSPARSE_OPERATION_NON_TRANSPOSE,
&floatone,
matM_lower,
vecR,
vecX,
CUDA_R_32F,
CUSPARSE_SPSV_ALG_DEFAULT,
spsvDescrL,
d_bufferL));
checkCudaErrors(cusparseSpSV_analysis(
cusparseHandle, CUSPARSE_OPERATION_NON_TRANSPOSE, &floatone,
matM_upper, vecR, vecX, CUDA_R_32F,
CUSPARSE_SPSV_ALG_DEFAULT, spsvDescrU, d_bufferU));
checkCudaErrors(cusparseSpSV_analysis(cusparseHandle,
CUSPARSE_OPERATION_NON_TRANSPOSE,
&floatone,
matM_upper,
vecR,
vecX,
CUDA_R_32F,
CUSPARSE_SPSV_ALG_DEFAULT,
spsvDescrU,
d_bufferU));
/* reset the initial guess of the solution to zero */
for (int i = 0; i < N; i++)
{
for (int i = 0; i < N; i++) {
x[i] = 0.0;
}
checkCudaErrors(cudaMemcpy(
d_r, rhs, N * sizeof(float), cudaMemcpyHostToDevice));
checkCudaErrors(cudaMemcpy(
d_x, x, N * sizeof(float), cudaMemcpyHostToDevice));
checkCudaErrors(cudaMemcpy(d_r, rhs, N * sizeof(float), cudaMemcpyHostToDevice));
checkCudaErrors(cudaMemcpy(d_x, x, N * sizeof(float), cudaMemcpyHostToDevice));
k = 0;
checkCudaErrors(cublasSdot(cublasHandle, N, d_r, 1, d_r, 1, &r1));
while (r1 > tol * tol && k <= max_iter)
{
while (r1 > tol * tol && k <= max_iter) {
// preconditioner application: d_zm1 = U^-1 L^-1 d_r
checkCudaErrors(cusparseSpSV_solve(cusparseHandle,
CUSPARSE_OPERATION_NON_TRANSPOSE, &floatone,
matM_lower, vecR, vecY, CUDA_R_32F,
CUSPARSE_SPSV_ALG_DEFAULT,
spsvDescrL) );
CUSPARSE_OPERATION_NON_TRANSPOSE,
&floatone,
matM_lower,
vecR,
vecY,
CUDA_R_32F,
CUSPARSE_SPSV_ALG_DEFAULT,
spsvDescrL));
checkCudaErrors(cusparseSpSV_solve(cusparseHandle,
CUSPARSE_OPERATION_NON_TRANSPOSE, &floatone, matM_upper,
vecY, vecZM1,
CUDA_R_32F,
CUSPARSE_SPSV_ALG_DEFAULT,
spsvDescrU));
CUSPARSE_OPERATION_NON_TRANSPOSE,
&floatone,
matM_upper,
vecY,
vecZM1,
CUDA_R_32F,
CUSPARSE_SPSV_ALG_DEFAULT,
spsvDescrU));
k++;
if (k == 1)
{
if (k == 1) {
checkCudaErrors(cublasScopy(cublasHandle, N, d_zm1, 1, d_p, 1));
}
else
{
checkCudaErrors(cublasSdot(
cublasHandle, N, d_r, 1, d_zm1, 1, &numerator));
checkCudaErrors(cublasSdot(
cublasHandle, N, d_rm2, 1, d_zm2, 1, &denominator));
else {
checkCudaErrors(cublasSdot(cublasHandle, N, d_r, 1, d_zm1, 1, &numerator));
checkCudaErrors(cublasSdot(cublasHandle, N, d_rm2, 1, d_zm2, 1, &denominator));
beta = numerator / denominator;
checkCudaErrors(cublasSscal(cublasHandle, N, &beta, d_p, 1));
checkCudaErrors(cublasSaxpy(
cublasHandle, N, &floatone, d_zm1, 1, d_p, 1));
checkCudaErrors(cublasSaxpy(cublasHandle, N, &floatone, d_zm1, 1, d_p, 1));
}
checkCudaErrors(cusparseSpMV(
cusparseHandle, CUSPARSE_OPERATION_NON_TRANSPOSE, &floatone, matA,
vecp, &floatzero, vecomega, CUDA_R_32F, CUSPARSE_SPMV_ALG_DEFAULT,
d_bufferMV));
checkCudaErrors(cublasSdot(
cublasHandle, N, d_r, 1, d_zm1, 1, &numerator));
checkCudaErrors(cublasSdot(
cublasHandle, N, d_p, 1, d_omega, 1, &denominator));
checkCudaErrors(cusparseSpMV(cusparseHandle,
CUSPARSE_OPERATION_NON_TRANSPOSE,
&floatone,
matA,
vecp,
&floatzero,
vecomega,
CUDA_R_32F,
CUSPARSE_SPMV_ALG_DEFAULT,
d_bufferMV));
checkCudaErrors(cublasSdot(cublasHandle, N, d_r, 1, d_zm1, 1, &numerator));
checkCudaErrors(cublasSdot(cublasHandle, N, d_p, 1, d_omega, 1, &denominator));
alpha = numerator / denominator;
checkCudaErrors(cublasSaxpy(cublasHandle, N, &alpha, d_p, 1, d_x, 1));
checkCudaErrors(cublasScopy(cublasHandle, N, d_r, 1, d_rm2, 1));
checkCudaErrors(cublasScopy(cublasHandle, N, d_zm1, 1, d_zm2, 1));
nalpha = -alpha;
checkCudaErrors(cublasSaxpy(
cublasHandle, N, &nalpha, d_omega, 1, d_r, 1));
checkCudaErrors(cublasSaxpy(cublasHandle, N, &nalpha, d_omega, 1, d_r, 1));
checkCudaErrors(cublasSdot(cublasHandle, N, d_r, 1, d_r, 1, &r1));
}
printf(" iteration = %3d, residual = %e \n", k, sqrt(r1));
checkCudaErrors(cudaMemcpy(
x, d_x, N * sizeof(float), cudaMemcpyDeviceToHost));
checkCudaErrors(cudaMemcpy(x, d_x, N * sizeof(float), cudaMemcpyDeviceToHost));
/* check result */
err = 0.0;
for (int i = 0; i < N; i++)
{
for (int i = 0; i < N; i++) {
rsum = 0.0;
for (int j = I[i]; j < I[i + 1]; j++)
{
for (int j = I[i]; j < I[i + 1]; j++) {
rsum += val[j] * x[J[j]];
}
diff = fabs(rsum - rhs[i]);
if (diff > err)
{
if (diff > err) {
err = diff;
}
}
@@ -601,8 +622,5 @@ int main(int argc, char **argv){
printf("Test Summary:\n");
printf(" Counted total of %d errors\n", nErrors);
printf(" qaerr1 = %f qaerr2 = %f\n\n", fabs(qaerr1), fabs(qaerr2));
exit((nErrors == 0 &&fabs(qaerr1) < 1e-5 && fabs(qaerr2) < 1e-5
? EXIT_SUCCESS
: EXIT_FAILURE));
exit((nErrors == 0 && fabs(qaerr1) < 1e-5 && fabs(qaerr2) < 1e-5 ? EXIT_SUCCESS : EXIT_FAILURE));
}

View File

@@ -42,232 +42,255 @@
#include <cusparse.h>
// Utilities and system includes
#include <helper_cuda.h> // helper function CUDA error checking and initialization
#include <helper_functions.h> // helper for shared functions common to CUDA Samples
#include <helper_cuda.h> // helper function CUDA error checking and initialization
#include <helper_functions.h> // helper for shared functions common to CUDA Samples
const char *sSDKname = "conjugateGradientUM";
/* genTridiag: generate a random tridiagonal symmetric matrix */
void genTridiag(int *I, int *J, float *val, int N, int nz) {
I[0] = 0, J[0] = 0, J[1] = 1;
val[0] = (float)rand() / RAND_MAX + 10.0f;
val[1] = (float)rand() / RAND_MAX;
int start;
void genTridiag(int *I, int *J, float *val, int N, int nz)
{
I[0] = 0, J[0] = 0, J[1] = 1;
val[0] = (float)rand() / RAND_MAX + 10.0f;
val[1] = (float)rand() / RAND_MAX;
int start;
for (int i = 1; i < N; i++) {
if (i > 1) {
I[i] = I[i - 1] + 3;
} else {
I[1] = 2;
for (int i = 1; i < N; i++) {
if (i > 1) {
I[i] = I[i - 1] + 3;
}
else {
I[1] = 2;
}
start = (i - 1) * 3 + 2;
J[start] = i - 1;
J[start + 1] = i;
if (i < N - 1) {
J[start + 2] = i + 1;
}
val[start] = val[start - 1];
val[start + 1] = (float)rand() / RAND_MAX + 10.0f;
if (i < N - 1) {
val[start + 2] = (float)rand() / RAND_MAX;
}
}
start = (i - 1) * 3 + 2;
J[start] = i - 1;
J[start + 1] = i;
if (i < N - 1) {
J[start + 2] = i + 1;
}
val[start] = val[start - 1];
val[start + 1] = (float)rand() / RAND_MAX + 10.0f;
if (i < N - 1) {
val[start + 2] = (float)rand() / RAND_MAX;
}
}
I[N] = nz;
I[N] = nz;
}
int main(int argc, char **argv) {
int N = 0, nz = 0, *I = NULL, *J = NULL;
float *val = NULL;
const float tol = 1e-5f;
const int max_iter = 10000;
float *x;
float *rhs;
float a, b, na, r0, r1;
float dot;
float *r, *p, *Ax;
int k;
float alpha, beta, alpham1;
int main(int argc, char **argv)
{
int N = 0, nz = 0, *I = NULL, *J = NULL;
float *val = NULL;
const float tol = 1e-5f;
const int max_iter = 10000;
float *x;
float *rhs;
float a, b, na, r0, r1;
float dot;
float *r, *p, *Ax;
int k;
float alpha, beta, alpham1;
printf("Starting [%s]...\n", sSDKname);
printf("Starting [%s]...\n", sSDKname);
// This will pick the best possible CUDA capable device
cudaDeviceProp deviceProp;
int devID = findCudaDevice(argc, (const char **)argv);
checkCudaErrors(cudaGetDeviceProperties(&deviceProp, devID));
// This will pick the best possible CUDA capable device
cudaDeviceProp deviceProp;
int devID = findCudaDevice(argc, (const char **)argv);
checkCudaErrors(cudaGetDeviceProperties(&deviceProp, devID));
if (!deviceProp.managedMemory) {
// This samples requires being run on a device that supports Unified Memory
fprintf(stderr, "Unified Memory not supported on this device\n");
exit(EXIT_WAIVED);
}
// Statistics about the GPU device
printf(
"> GPU device has %d Multi-Processors, SM %d.%d compute capabilities\n\n",
deviceProp.multiProcessorCount, deviceProp.major, deviceProp.minor);
/* Generate a random tridiagonal symmetric matrix in CSR format */
N = 1048576;
nz = (N - 2) * 3 + 4;
cudaMallocManaged((void **)&I, sizeof(int) * (N + 1));
cudaMallocManaged((void **)&J, sizeof(int) * nz);
cudaMallocManaged((void **)&val, sizeof(float) * nz);
genTridiag(I, J, val, N, nz);
cudaMallocManaged((void **)&x, sizeof(float) * N);
cudaMallocManaged((void **)&rhs, sizeof(float) * N);
for (int i = 0; i < N; i++) {
rhs[i] = 1.0;
x[i] = 0.0;
}
/* Get handle to the CUBLAS context */
cublasHandle_t cublasHandle = 0;
cublasStatus_t cublasStatus;
cublasStatus = cublasCreate(&cublasHandle);
checkCudaErrors(cublasStatus);
/* Get handle to the CUSPARSE context */
cusparseHandle_t cusparseHandle = 0;
cusparseStatus_t cusparseStatus;
cusparseStatus = cusparseCreate(&cusparseHandle);
checkCudaErrors(cusparseStatus);
cusparseMatDescr_t descr = 0;
cusparseStatus = cusparseCreateMatDescr(&descr);
checkCudaErrors(cusparseStatus);
cusparseSetMatType(descr, CUSPARSE_MATRIX_TYPE_GENERAL);
cusparseSetMatIndexBase(descr, CUSPARSE_INDEX_BASE_ZERO);
// temp memory for CG
checkCudaErrors(cudaMallocManaged((void **)&r, N * sizeof(float)));
checkCudaErrors(cudaMallocManaged((void **)&p, N * sizeof(float)));
checkCudaErrors(cudaMallocManaged((void **)&Ax, N * sizeof(float)));
/* Wrap raw data into cuSPARSE generic API objects */
cusparseSpMatDescr_t matA = NULL;
checkCudaErrors(cusparseCreateCsr(&matA, N, N, nz, I, J, val,
CUSPARSE_INDEX_32I, CUSPARSE_INDEX_32I,
CUSPARSE_INDEX_BASE_ZERO, CUDA_R_32F));
cusparseDnVecDescr_t vecx = NULL;
checkCudaErrors(cusparseCreateDnVec(&vecx, N, x, CUDA_R_32F));
cusparseDnVecDescr_t vecp = NULL;
checkCudaErrors(cusparseCreateDnVec(&vecp, N, p, CUDA_R_32F));
cusparseDnVecDescr_t vecAx = NULL;
checkCudaErrors(cusparseCreateDnVec(&vecAx, N, Ax, CUDA_R_32F));
cudaDeviceSynchronize();
for (int i = 0; i < N; i++) {
r[i] = rhs[i];
}
alpha = 1.0;
alpham1 = -1.0;
beta = 0.0;
r0 = 0.;
/* Allocate workspace for cuSPARSE */
size_t bufferSize = 0;
checkCudaErrors(cusparseSpMV_bufferSize(
cusparseHandle, CUSPARSE_OPERATION_NON_TRANSPOSE, &alpha, matA, vecx,
&beta, vecAx, CUDA_R_32F, CUSPARSE_SPMV_ALG_DEFAULT, &bufferSize));
void *buffer = NULL;
checkCudaErrors(cudaMalloc(&buffer, bufferSize));
checkCudaErrors(cusparseSpMV(cusparseHandle, CUSPARSE_OPERATION_NON_TRANSPOSE,
&alpha, matA, vecx, &beta, vecAx, CUDA_R_32F,
CUSPARSE_SPMV_ALG_DEFAULT, buffer));
cublasSaxpy(cublasHandle, N, &alpham1, Ax, 1, r, 1);
cublasStatus = cublasSdot(cublasHandle, N, r, 1, r, 1, &r1);
k = 1;
while (r1 > tol * tol && k <= max_iter) {
if (k > 1) {
b = r1 / r0;
cublasStatus = cublasSscal(cublasHandle, N, &b, p, 1);
cublasStatus = cublasSaxpy(cublasHandle, N, &alpha, r, 1, p, 1);
} else {
cublasStatus = cublasScopy(cublasHandle, N, r, 1, p, 1);
if (!deviceProp.managedMemory) {
// This samples requires being run on a device that supports Unified Memory
fprintf(stderr, "Unified Memory not supported on this device\n");
exit(EXIT_WAIVED);
}
checkCudaErrors(cusparseSpMV(
cusparseHandle, CUSPARSE_OPERATION_NON_TRANSPOSE, &alpha, matA, vecp,
&beta, vecAx, CUDA_R_32F, CUSPARSE_SPMV_ALG_DEFAULT, buffer));
cublasStatus = cublasSdot(cublasHandle, N, p, 1, Ax, 1, &dot);
a = r1 / dot;
// Statistics about the GPU device
printf("> GPU device has %d Multi-Processors, SM %d.%d compute capabilities\n\n",
deviceProp.multiProcessorCount,
deviceProp.major,
deviceProp.minor);
cublasStatus = cublasSaxpy(cublasHandle, N, &a, p, 1, x, 1);
na = -a;
cublasStatus = cublasSaxpy(cublasHandle, N, &na, Ax, 1, r, 1);
/* Generate a random tridiagonal symmetric matrix in CSR format */
N = 1048576;
nz = (N - 2) * 3 + 4;
cudaMallocManaged((void **)&I, sizeof(int) * (N + 1));
cudaMallocManaged((void **)&J, sizeof(int) * nz);
cudaMallocManaged((void **)&val, sizeof(float) * nz);
genTridiag(I, J, val, N, nz);
cudaMallocManaged((void **)&x, sizeof(float) * N);
cudaMallocManaged((void **)&rhs, sizeof(float) * N);
for (int i = 0; i < N; i++) {
rhs[i] = 1.0;
x[i] = 0.0;
}
/* Get handle to the CUBLAS context */
cublasHandle_t cublasHandle = 0;
cublasStatus_t cublasStatus;
cublasStatus = cublasCreate(&cublasHandle);
checkCudaErrors(cublasStatus);
/* Get handle to the CUSPARSE context */
cusparseHandle_t cusparseHandle = 0;
cusparseStatus_t cusparseStatus;
cusparseStatus = cusparseCreate(&cusparseHandle);
checkCudaErrors(cusparseStatus);
cusparseMatDescr_t descr = 0;
cusparseStatus = cusparseCreateMatDescr(&descr);
checkCudaErrors(cusparseStatus);
cusparseSetMatType(descr, CUSPARSE_MATRIX_TYPE_GENERAL);
cusparseSetMatIndexBase(descr, CUSPARSE_INDEX_BASE_ZERO);
// temp memory for CG
checkCudaErrors(cudaMallocManaged((void **)&r, N * sizeof(float)));
checkCudaErrors(cudaMallocManaged((void **)&p, N * sizeof(float)));
checkCudaErrors(cudaMallocManaged((void **)&Ax, N * sizeof(float)));
/* Wrap raw data into cuSPARSE generic API objects */
cusparseSpMatDescr_t matA = NULL;
checkCudaErrors(cusparseCreateCsr(
&matA, N, N, nz, I, J, val, CUSPARSE_INDEX_32I, CUSPARSE_INDEX_32I, CUSPARSE_INDEX_BASE_ZERO, CUDA_R_32F));
cusparseDnVecDescr_t vecx = NULL;
checkCudaErrors(cusparseCreateDnVec(&vecx, N, x, CUDA_R_32F));
cusparseDnVecDescr_t vecp = NULL;
checkCudaErrors(cusparseCreateDnVec(&vecp, N, p, CUDA_R_32F));
cusparseDnVecDescr_t vecAx = NULL;
checkCudaErrors(cusparseCreateDnVec(&vecAx, N, Ax, CUDA_R_32F));
r0 = r1;
cublasStatus = cublasSdot(cublasHandle, N, r, 1, r, 1, &r1);
cudaDeviceSynchronize();
printf("iteration = %3d, residual = %e\n", k, sqrt(r1));
k++;
}
printf("Final residual: %e\n", sqrt(r1));
fprintf(stdout, "&&&& conjugateGradientUM %s\n",
(sqrt(r1) < tol) ? "PASSED" : "FAILED");
float rsum, diff, err = 0.0;
for (int i = 0; i < N; i++) {
rsum = 0.0;
for (int j = I[i]; j < I[i + 1]; j++) {
rsum += val[j] * x[J[j]];
for (int i = 0; i < N; i++) {
r[i] = rhs[i];
}
diff = fabs(rsum - rhs[i]);
alpha = 1.0;
alpham1 = -1.0;
beta = 0.0;
r0 = 0.;
if (diff > err) {
err = diff;
/* Allocate workspace for cuSPARSE */
size_t bufferSize = 0;
checkCudaErrors(cusparseSpMV_bufferSize(cusparseHandle,
CUSPARSE_OPERATION_NON_TRANSPOSE,
&alpha,
matA,
vecx,
&beta,
vecAx,
CUDA_R_32F,
CUSPARSE_SPMV_ALG_DEFAULT,
&bufferSize));
void *buffer = NULL;
checkCudaErrors(cudaMalloc(&buffer, bufferSize));
checkCudaErrors(cusparseSpMV(cusparseHandle,
CUSPARSE_OPERATION_NON_TRANSPOSE,
&alpha,
matA,
vecx,
&beta,
vecAx,
CUDA_R_32F,
CUSPARSE_SPMV_ALG_DEFAULT,
buffer));
cublasSaxpy(cublasHandle, N, &alpham1, Ax, 1, r, 1);
cublasStatus = cublasSdot(cublasHandle, N, r, 1, r, 1, &r1);
k = 1;
while (r1 > tol * tol && k <= max_iter) {
if (k > 1) {
b = r1 / r0;
cublasStatus = cublasSscal(cublasHandle, N, &b, p, 1);
cublasStatus = cublasSaxpy(cublasHandle, N, &alpha, r, 1, p, 1);
}
else {
cublasStatus = cublasScopy(cublasHandle, N, r, 1, p, 1);
}
checkCudaErrors(cusparseSpMV(cusparseHandle,
CUSPARSE_OPERATION_NON_TRANSPOSE,
&alpha,
matA,
vecp,
&beta,
vecAx,
CUDA_R_32F,
CUSPARSE_SPMV_ALG_DEFAULT,
buffer));
cublasStatus = cublasSdot(cublasHandle, N, p, 1, Ax, 1, &dot);
a = r1 / dot;
cublasStatus = cublasSaxpy(cublasHandle, N, &a, p, 1, x, 1);
na = -a;
cublasStatus = cublasSaxpy(cublasHandle, N, &na, Ax, 1, r, 1);
r0 = r1;
cublasStatus = cublasSdot(cublasHandle, N, r, 1, r, 1, &r1);
cudaDeviceSynchronize();
printf("iteration = %3d, residual = %e\n", k, sqrt(r1));
k++;
}
}
cusparseDestroy(cusparseHandle);
cublasDestroy(cublasHandle);
if (matA) {
checkCudaErrors(cusparseDestroySpMat(matA));
}
if (vecx) {
checkCudaErrors(cusparseDestroyDnVec(vecx));
}
if (vecAx) {
checkCudaErrors(cusparseDestroyDnVec(vecAx));
}
if (vecp) {
checkCudaErrors(cusparseDestroyDnVec(vecp));
}
printf("Final residual: %e\n", sqrt(r1));
cudaFree(I);
cudaFree(J);
cudaFree(val);
cudaFree(x);
cudaFree(rhs);
cudaFree(r);
cudaFree(p);
cudaFree(Ax);
fprintf(stdout, "&&&& conjugateGradientUM %s\n", (sqrt(r1) < tol) ? "PASSED" : "FAILED");
printf("Test Summary: Error amount = %f, result = %s\n", err,
(k <= max_iter) ? "SUCCESS" : "FAILURE");
exit((k <= max_iter) ? EXIT_SUCCESS : EXIT_FAILURE);
float rsum, diff, err = 0.0;
for (int i = 0; i < N; i++) {
rsum = 0.0;
for (int j = I[i]; j < I[i + 1]; j++) {
rsum += val[j] * x[J[j]];
}
diff = fabs(rsum - rhs[i]);
if (diff > err) {
err = diff;
}
}
cusparseDestroy(cusparseHandle);
cublasDestroy(cublasHandle);
if (matA) {
checkCudaErrors(cusparseDestroySpMat(matA));
}
if (vecx) {
checkCudaErrors(cusparseDestroyDnVec(vecx));
}
if (vecAx) {
checkCudaErrors(cusparseDestroyDnVec(vecAx));
}
if (vecp) {
checkCudaErrors(cusparseDestroyDnVec(vecp));
}
cudaFree(I);
cudaFree(J);
cudaFree(val);
cudaFree(x);
cudaFree(rhs);
cudaFree(r);
cudaFree(p);
cudaFree(Ax);
printf("Test Summary: Error amount = %f, result = %s\n", err, (k <= max_iter) ? "SUCCESS" : "FAILURE");
exit((k <= max_iter) ? EXIT_SUCCESS : EXIT_FAILURE);
}

View File

@@ -56,529 +56,532 @@
#include <assert.h>
#include <ctype.h>
#include <cuda_runtime.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cuda_runtime.h>
#include "cublas_v2.h"
#include "cusolverDn.h"
#include "helper_cuda.h"
#include "helper_cusolver.h"
template <typename T_ELEM>
int loadMMSparseMatrix(char *filename, char elem_type, bool csrFormat, int *m,
int *n, int *nnz, T_ELEM **aVal, int **aRowInd,
int **aColInd, int extendSymMatrix);
int loadMMSparseMatrix(char *filename,
char elem_type,
bool csrFormat,
int *m,
int *n,
int *nnz,
T_ELEM **aVal,
int **aRowInd,
int **aColInd,
int extendSymMatrix);
void UsageDN(void) {
printf("<options>\n");
printf("-h : display this help\n");
printf("-R=<name> : choose a linear solver\n");
printf(" chol (cholesky factorization), this is default\n");
printf(" qr (QR factorization)\n");
printf(" lu (LU factorization)\n");
printf("-lda=<int> : leading dimension of A , m by default\n");
printf("-file=<filename>: filename containing a matrix in MM format\n");
printf("-device=<device_id> : <device_id> if want to run on specific GPU\n");
void UsageDN(void)
{
printf("<options>\n");
printf("-h : display this help\n");
printf("-R=<name> : choose a linear solver\n");
printf(" chol (cholesky factorization), this is default\n");
printf(" qr (QR factorization)\n");
printf(" lu (LU factorization)\n");
printf("-lda=<int> : leading dimension of A , m by default\n");
printf("-file=<filename>: filename containing a matrix in MM format\n");
printf("-device=<device_id> : <device_id> if want to run on specific GPU\n");
exit(0);
exit(0);
}
/*
* solve A*x = b by Cholesky factorization
*
*/
int linearSolverCHOL(cusolverDnHandle_t handle, int n, const double *Acopy,
int lda, const double *b, double *x) {
int bufferSize = 0;
int *info = NULL;
double *buffer = NULL;
double *A = NULL;
int h_info = 0;
double start, stop;
double time_solve;
cublasFillMode_t uplo = CUBLAS_FILL_MODE_LOWER;
int linearSolverCHOL(cusolverDnHandle_t handle, int n, const double *Acopy, int lda, const double *b, double *x)
{
int bufferSize = 0;
int *info = NULL;
double *buffer = NULL;
double *A = NULL;
int h_info = 0;
double start, stop;
double time_solve;
cublasFillMode_t uplo = CUBLAS_FILL_MODE_LOWER;
checkCudaErrors(cusolverDnDpotrf_bufferSize(handle, uplo, n, (double *)Acopy,
lda, &bufferSize));
checkCudaErrors(cusolverDnDpotrf_bufferSize(handle, uplo, n, (double *)Acopy, lda, &bufferSize));
checkCudaErrors(cudaMalloc(&info, sizeof(int)));
checkCudaErrors(cudaMalloc(&buffer, sizeof(double) * bufferSize));
checkCudaErrors(cudaMalloc(&A, sizeof(double) * lda * n));
checkCudaErrors(cudaMalloc(&info, sizeof(int)));
checkCudaErrors(cudaMalloc(&buffer, sizeof(double) * bufferSize));
checkCudaErrors(cudaMalloc(&A, sizeof(double) * lda * n));
// prepare a copy of A because potrf will overwrite A with L
checkCudaErrors(
cudaMemcpy(A, Acopy, sizeof(double) * lda * n, cudaMemcpyDeviceToDevice));
checkCudaErrors(cudaMemset(info, 0, sizeof(int)));
// prepare a copy of A because potrf will overwrite A with L
checkCudaErrors(cudaMemcpy(A, Acopy, sizeof(double) * lda * n, cudaMemcpyDeviceToDevice));
checkCudaErrors(cudaMemset(info, 0, sizeof(int)));
start = second();
start = second();
start = second();
start = second();
checkCudaErrors(
cusolverDnDpotrf(handle, uplo, n, A, lda, buffer, bufferSize, info));
checkCudaErrors(cusolverDnDpotrf(handle, uplo, n, A, lda, buffer, bufferSize, info));
checkCudaErrors(
cudaMemcpy(&h_info, info, sizeof(int), cudaMemcpyDeviceToHost));
checkCudaErrors(cudaMemcpy(&h_info, info, sizeof(int), cudaMemcpyDeviceToHost));
if (0 != h_info) {
fprintf(stderr, "Error: Cholesky factorization failed\n");
}
if (0 != h_info) {
fprintf(stderr, "Error: Cholesky factorization failed\n");
}
checkCudaErrors(
cudaMemcpy(x, b, sizeof(double) * n, cudaMemcpyDeviceToDevice));
checkCudaErrors(cudaMemcpy(x, b, sizeof(double) * n, cudaMemcpyDeviceToDevice));
checkCudaErrors(cusolverDnDpotrs(handle, uplo, n, 1, A, lda, x, n, info));
checkCudaErrors(cusolverDnDpotrs(handle, uplo, n, 1, A, lda, x, n, info));
checkCudaErrors(cudaDeviceSynchronize());
stop = second();
checkCudaErrors(cudaDeviceSynchronize());
stop = second();
time_solve = stop - start;
fprintf(stdout, "timing: cholesky = %10.6f sec\n", time_solve);
time_solve = stop - start;
fprintf(stdout, "timing: cholesky = %10.6f sec\n", time_solve);
if (info) {
checkCudaErrors(cudaFree(info));
}
if (buffer) {
checkCudaErrors(cudaFree(buffer));
}
if (A) {
checkCudaErrors(cudaFree(A));
}
if (info) {
checkCudaErrors(cudaFree(info));
}
if (buffer) {
checkCudaErrors(cudaFree(buffer));
}
if (A) {
checkCudaErrors(cudaFree(A));
}
return 0;
return 0;
}
/*
* solve A*x = b by LU with partial pivoting
*
*/
int linearSolverLU(cusolverDnHandle_t handle, int n, const double *Acopy,
int lda, const double *b, double *x) {
int bufferSize = 0;
int *info = NULL;
double *buffer = NULL;
double *A = NULL;
int *ipiv = NULL; // pivoting sequence
int h_info = 0;
double start, stop;
double time_solve;
int linearSolverLU(cusolverDnHandle_t handle, int n, const double *Acopy, int lda, const double *b, double *x)
{
int bufferSize = 0;
int *info = NULL;
double *buffer = NULL;
double *A = NULL;
int *ipiv = NULL; // pivoting sequence
int h_info = 0;
double start, stop;
double time_solve;
checkCudaErrors(cusolverDnDgetrf_bufferSize(handle, n, n, (double *)Acopy,
lda, &bufferSize));
checkCudaErrors(cusolverDnDgetrf_bufferSize(handle, n, n, (double *)Acopy, lda, &bufferSize));
checkCudaErrors(cudaMalloc(&info, sizeof(int)));
checkCudaErrors(cudaMalloc(&buffer, sizeof(double) * bufferSize));
checkCudaErrors(cudaMalloc(&A, sizeof(double) * lda * n));
checkCudaErrors(cudaMalloc(&ipiv, sizeof(int) * n));
checkCudaErrors(cudaMalloc(&info, sizeof(int)));
checkCudaErrors(cudaMalloc(&buffer, sizeof(double) * bufferSize));
checkCudaErrors(cudaMalloc(&A, sizeof(double) * lda * n));
checkCudaErrors(cudaMalloc(&ipiv, sizeof(int) * n));
// prepare a copy of A because getrf will overwrite A with L
checkCudaErrors(
cudaMemcpy(A, Acopy, sizeof(double) * lda * n, cudaMemcpyDeviceToDevice));
checkCudaErrors(cudaMemset(info, 0, sizeof(int)));
// prepare a copy of A because getrf will overwrite A with L
checkCudaErrors(cudaMemcpy(A, Acopy, sizeof(double) * lda * n, cudaMemcpyDeviceToDevice));
checkCudaErrors(cudaMemset(info, 0, sizeof(int)));
start = second();
start = second();
start = second();
start = second();
checkCudaErrors(cusolverDnDgetrf(handle, n, n, A, lda, buffer, ipiv, info));
checkCudaErrors(
cudaMemcpy(&h_info, info, sizeof(int), cudaMemcpyDeviceToHost));
checkCudaErrors(cusolverDnDgetrf(handle, n, n, A, lda, buffer, ipiv, info));
checkCudaErrors(cudaMemcpy(&h_info, info, sizeof(int), cudaMemcpyDeviceToHost));
if (0 != h_info) {
fprintf(stderr, "Error: LU factorization failed\n");
}
if (0 != h_info) {
fprintf(stderr, "Error: LU factorization failed\n");
}
checkCudaErrors(
cudaMemcpy(x, b, sizeof(double) * n, cudaMemcpyDeviceToDevice));
checkCudaErrors(
cusolverDnDgetrs(handle, CUBLAS_OP_N, n, 1, A, lda, ipiv, x, n, info));
checkCudaErrors(cudaDeviceSynchronize());
stop = second();
checkCudaErrors(cudaMemcpy(x, b, sizeof(double) * n, cudaMemcpyDeviceToDevice));
checkCudaErrors(cusolverDnDgetrs(handle, CUBLAS_OP_N, n, 1, A, lda, ipiv, x, n, info));
checkCudaErrors(cudaDeviceSynchronize());
stop = second();
time_solve = stop - start;
fprintf(stdout, "timing: LU = %10.6f sec\n", time_solve);
time_solve = stop - start;
fprintf(stdout, "timing: LU = %10.6f sec\n", time_solve);
if (info) {
checkCudaErrors(cudaFree(info));
}
if (buffer) {
checkCudaErrors(cudaFree(buffer));
}
if (A) {
checkCudaErrors(cudaFree(A));
}
if (ipiv) {
checkCudaErrors(cudaFree(ipiv));
}
if (info) {
checkCudaErrors(cudaFree(info));
}
if (buffer) {
checkCudaErrors(cudaFree(buffer));
}
if (A) {
checkCudaErrors(cudaFree(A));
}
if (ipiv) {
checkCudaErrors(cudaFree(ipiv));
}
return 0;
return 0;
}
/*
* solve A*x = b by QR
*
*/
int linearSolverQR(cusolverDnHandle_t handle, int n, const double *Acopy,
int lda, const double *b, double *x) {
cublasHandle_t cublasHandle = NULL; // used in residual evaluation
int bufferSize = 0;
int bufferSize_geqrf = 0;
int bufferSize_ormqr = 0;
int *info = NULL;
double *buffer = NULL;
double *A = NULL;
double *tau = NULL;
int h_info = 0;
double start, stop;
double time_solve;
const double one = 1.0;
int linearSolverQR(cusolverDnHandle_t handle, int n, const double *Acopy, int lda, const double *b, double *x)
{
cublasHandle_t cublasHandle = NULL; // used in residual evaluation
int bufferSize = 0;
int bufferSize_geqrf = 0;
int bufferSize_ormqr = 0;
int *info = NULL;
double *buffer = NULL;
double *A = NULL;
double *tau = NULL;
int h_info = 0;
double start, stop;
double time_solve;
const double one = 1.0;
checkCudaErrors(cublasCreate(&cublasHandle));
checkCudaErrors(cublasCreate(&cublasHandle));
checkCudaErrors(cusolverDnDgeqrf_bufferSize(handle, n, n, (double *)Acopy,
lda, &bufferSize_geqrf));
checkCudaErrors(cusolverDnDormqr_bufferSize(handle, CUBLAS_SIDE_LEFT,
CUBLAS_OP_T, n, 1, n, A, lda,
NULL, x, n, &bufferSize_ormqr));
checkCudaErrors(cusolverDnDgeqrf_bufferSize(handle, n, n, (double *)Acopy, lda, &bufferSize_geqrf));
checkCudaErrors(cusolverDnDormqr_bufferSize(
handle, CUBLAS_SIDE_LEFT, CUBLAS_OP_T, n, 1, n, A, lda, NULL, x, n, &bufferSize_ormqr));
printf("buffer_geqrf = %d, buffer_ormqr = %d \n", bufferSize_geqrf,
bufferSize_ormqr);
printf("buffer_geqrf = %d, buffer_ormqr = %d \n", bufferSize_geqrf, bufferSize_ormqr);
bufferSize = (bufferSize_geqrf > bufferSize_ormqr) ? bufferSize_geqrf
: bufferSize_ormqr;
bufferSize = (bufferSize_geqrf > bufferSize_ormqr) ? bufferSize_geqrf : bufferSize_ormqr;
checkCudaErrors(cudaMalloc(&info, sizeof(int)));
checkCudaErrors(cudaMalloc(&buffer, sizeof(double) * bufferSize));
checkCudaErrors(cudaMalloc(&A, sizeof(double) * lda * n));
checkCudaErrors(cudaMalloc((void **)&tau, sizeof(double) * n));
checkCudaErrors(cudaMalloc(&info, sizeof(int)));
checkCudaErrors(cudaMalloc(&buffer, sizeof(double) * bufferSize));
checkCudaErrors(cudaMalloc(&A, sizeof(double) * lda * n));
checkCudaErrors(cudaMalloc((void **)&tau, sizeof(double) * n));
// prepare a copy of A because getrf will overwrite A with L
checkCudaErrors(
cudaMemcpy(A, Acopy, sizeof(double) * lda * n, cudaMemcpyDeviceToDevice));
// prepare a copy of A because getrf will overwrite A with L
checkCudaErrors(cudaMemcpy(A, Acopy, sizeof(double) * lda * n, cudaMemcpyDeviceToDevice));
checkCudaErrors(cudaMemset(info, 0, sizeof(int)));
checkCudaErrors(cudaMemset(info, 0, sizeof(int)));
start = second();
start = second();
start = second();
start = second();
// compute QR factorization
checkCudaErrors(
cusolverDnDgeqrf(handle, n, n, A, lda, tau, buffer, bufferSize, info));
// compute QR factorization
checkCudaErrors(cusolverDnDgeqrf(handle, n, n, A, lda, tau, buffer, bufferSize, info));
checkCudaErrors(
cudaMemcpy(&h_info, info, sizeof(int), cudaMemcpyDeviceToHost));
checkCudaErrors(cudaMemcpy(&h_info, info, sizeof(int), cudaMemcpyDeviceToHost));
if (0 != h_info) {
fprintf(stderr, "Error: LU factorization failed\n");
}
if (0 != h_info) {
fprintf(stderr, "Error: LU factorization failed\n");
}
checkCudaErrors(
cudaMemcpy(x, b, sizeof(double) * n, cudaMemcpyDeviceToDevice));
checkCudaErrors(cudaMemcpy(x, b, sizeof(double) * n, cudaMemcpyDeviceToDevice));
// compute Q^T*b
checkCudaErrors(cusolverDnDormqr(handle, CUBLAS_SIDE_LEFT, CUBLAS_OP_T, n, 1,
n, A, lda, tau, x, n, buffer, bufferSize,
info));
// compute Q^T*b
checkCudaErrors(
cusolverDnDormqr(handle, CUBLAS_SIDE_LEFT, CUBLAS_OP_T, n, 1, n, A, lda, tau, x, n, buffer, bufferSize, info));
// x = R \ Q^T*b
checkCudaErrors(cublasDtrsm(cublasHandle, CUBLAS_SIDE_LEFT,
CUBLAS_FILL_MODE_UPPER, CUBLAS_OP_N,
CUBLAS_DIAG_NON_UNIT, n, 1, &one, A, lda, x, n));
checkCudaErrors(cudaDeviceSynchronize());
stop = second();
// x = R \ Q^T*b
checkCudaErrors(cublasDtrsm(cublasHandle,
CUBLAS_SIDE_LEFT,
CUBLAS_FILL_MODE_UPPER,
CUBLAS_OP_N,
CUBLAS_DIAG_NON_UNIT,
n,
1,
&one,
A,
lda,
x,
n));
checkCudaErrors(cudaDeviceSynchronize());
stop = second();
time_solve = stop - start;
fprintf(stdout, "timing: QR = %10.6f sec\n", time_solve);
time_solve = stop - start;
fprintf(stdout, "timing: QR = %10.6f sec\n", time_solve);
if (cublasHandle) {
checkCudaErrors(cublasDestroy(cublasHandle));
}
if (info) {
checkCudaErrors(cudaFree(info));
}
if (buffer) {
checkCudaErrors(cudaFree(buffer));
}
if (A) {
checkCudaErrors(cudaFree(A));
}
if (tau) {
checkCudaErrors(cudaFree(tau));
}
if (cublasHandle) {
checkCudaErrors(cublasDestroy(cublasHandle));
}
if (info) {
checkCudaErrors(cudaFree(info));
}
if (buffer) {
checkCudaErrors(cudaFree(buffer));
}
if (A) {
checkCudaErrors(cudaFree(A));
}
if (tau) {
checkCudaErrors(cudaFree(tau));
}
return 0;
return 0;
}
void parseCommandLineArguments(int argc, char *argv[], struct testOpts &opts) {
memset(&opts, 0, sizeof(opts));
void parseCommandLineArguments(int argc, char *argv[], struct testOpts &opts)
{
memset(&opts, 0, sizeof(opts));
if (checkCmdLineFlag(argc, (const char **)argv, "-h")) {
UsageDN();
}
if (checkCmdLineFlag(argc, (const char **)argv, "R")) {
char *solverType = NULL;
getCmdLineArgumentString(argc, (const char **)argv, "R", &solverType);
if (solverType) {
if ((STRCASECMP(solverType, "chol") != 0) &&
(STRCASECMP(solverType, "lu") != 0) &&
(STRCASECMP(solverType, "qr") != 0)) {
printf("\nIncorrect argument passed to -R option\n");
if (checkCmdLineFlag(argc, (const char **)argv, "-h")) {
UsageDN();
} else {
opts.testFunc = solverType;
}
}
}
if (checkCmdLineFlag(argc, (const char **)argv, "file")) {
char *fileName = 0;
getCmdLineArgumentString(argc, (const char **)argv, "file", &fileName);
if (checkCmdLineFlag(argc, (const char **)argv, "R")) {
char *solverType = NULL;
getCmdLineArgumentString(argc, (const char **)argv, "R", &solverType);
if (fileName) {
opts.sparse_mat_filename = fileName;
} else {
printf("\nIncorrect filename passed to -file \n ");
UsageDN();
}
}
if (checkCmdLineFlag(argc, (const char **)argv, "lda")) {
opts.lda = getCmdLineArgumentInt(argc, (const char **)argv, "lda");
}
}
int main(int argc, char *argv[]) {
struct testOpts opts;
cusolverDnHandle_t handle = NULL;
cublasHandle_t cublasHandle = NULL; // used in residual evaluation
cudaStream_t stream = NULL;
int rowsA = 0; // number of rows of A
int colsA = 0; // number of columns of A
int nnzA = 0; // number of nonzeros of A
int baseA = 0; // base index in CSR format
int lda = 0; // leading dimension in dense matrix
// CSR(A) from I/O
int *h_csrRowPtrA = NULL;
int *h_csrColIndA = NULL;
double *h_csrValA = NULL;
double *h_A = NULL; // dense matrix from CSR(A)
double *h_x = NULL; // a copy of d_x
double *h_b = NULL; // b = ones(m,1)
double *h_r = NULL; // r = b - A*x, a copy of d_r
double *d_A = NULL; // a copy of h_A
double *d_x = NULL; // x = A \ b
double *d_b = NULL; // a copy of h_b
double *d_r = NULL; // r = b - A*x
// the constants are used in residual evaluation, r = b - A*x
const double minus_one = -1.0;
const double one = 1.0;
double x_inf = 0.0;
double r_inf = 0.0;
double A_inf = 0.0;
int errors = 0;
parseCommandLineArguments(argc, argv, opts);
if (NULL == opts.testFunc) {
opts.testFunc = "chol"; // By default running Cholesky as NO solver
// selected with -R option.
}
findCudaDevice(argc, (const char **)argv);
printf("step 1: read matrix market format\n");
if (opts.sparse_mat_filename == NULL) {
opts.sparse_mat_filename = sdkFindFilePath("gr_900_900_crg.mtx", argv[0]);
if (opts.sparse_mat_filename != NULL)
printf("Using default input file [%s]\n", opts.sparse_mat_filename);
else
printf("Could not find gr_900_900_crg.mtx\n");
} else {
printf("Using input file [%s]\n", opts.sparse_mat_filename);
}
if (opts.sparse_mat_filename == NULL) {
fprintf(stderr, "Error: input matrix is not provided\n");
return EXIT_FAILURE;
}
if (loadMMSparseMatrix<double>(opts.sparse_mat_filename, 'd', true, &rowsA,
&colsA, &nnzA, &h_csrValA, &h_csrRowPtrA,
&h_csrColIndA, true)) {
exit(EXIT_FAILURE);
}
baseA = h_csrRowPtrA[0]; // baseA = {0,1}
printf("sparse matrix A is %d x %d with %d nonzeros, base=%d\n", rowsA, colsA,
nnzA, baseA);
if (rowsA != colsA) {
fprintf(stderr, "Error: only support square matrix\n");
exit(EXIT_FAILURE);
}
printf("step 2: convert CSR(A) to dense matrix\n");
lda = opts.lda ? opts.lda : rowsA;
if (lda < rowsA) {
fprintf(stderr, "Error: lda must be greater or equal to dimension of A\n");
exit(EXIT_FAILURE);
}
h_A = (double *)malloc(sizeof(double) * lda * colsA);
h_x = (double *)malloc(sizeof(double) * colsA);
h_b = (double *)malloc(sizeof(double) * rowsA);
h_r = (double *)malloc(sizeof(double) * rowsA);
assert(NULL != h_A);
assert(NULL != h_x);
assert(NULL != h_b);
assert(NULL != h_r);
memset(h_A, 0, sizeof(double) * lda * colsA);
for (int row = 0; row < rowsA; row++) {
const int start = h_csrRowPtrA[row] - baseA;
const int end = h_csrRowPtrA[row + 1] - baseA;
for (int colidx = start; colidx < end; colidx++) {
const int col = h_csrColIndA[colidx] - baseA;
const double Areg = h_csrValA[colidx];
h_A[row + col * lda] = Areg;
}
}
printf("step 3: set right hand side vector (b) to 1\n");
for (int row = 0; row < rowsA; row++) {
h_b[row] = 1.0;
}
// verify if A is symmetric or not.
if (0 == strcmp(opts.testFunc, "chol")) {
int issym = 1;
for (int j = 0; j < colsA; j++) {
for (int i = j; i < rowsA; i++) {
double Aij = h_A[i + j * lda];
double Aji = h_A[j + i * lda];
if (Aij != Aji) {
issym = 0;
break;
if (solverType) {
if ((STRCASECMP(solverType, "chol") != 0) && (STRCASECMP(solverType, "lu") != 0)
&& (STRCASECMP(solverType, "qr") != 0)) {
printf("\nIncorrect argument passed to -R option\n");
UsageDN();
}
else {
opts.testFunc = solverType;
}
}
}
}
if (!issym) {
printf("Error: A has no symmetric pattern, please use LU or QR \n");
exit(EXIT_FAILURE);
if (checkCmdLineFlag(argc, (const char **)argv, "file")) {
char *fileName = 0;
getCmdLineArgumentString(argc, (const char **)argv, "file", &fileName);
if (fileName) {
opts.sparse_mat_filename = fileName;
}
else {
printf("\nIncorrect filename passed to -file \n ");
UsageDN();
}
}
}
checkCudaErrors(cusolverDnCreate(&handle));
checkCudaErrors(cublasCreate(&cublasHandle));
checkCudaErrors(cudaStreamCreate(&stream));
checkCudaErrors(cusolverDnSetStream(handle, stream));
checkCudaErrors(cublasSetStream(cublasHandle, stream));
checkCudaErrors(cudaMalloc((void **)&d_A, sizeof(double) * lda * colsA));
checkCudaErrors(cudaMalloc((void **)&d_x, sizeof(double) * colsA));
checkCudaErrors(cudaMalloc((void **)&d_b, sizeof(double) * rowsA));
checkCudaErrors(cudaMalloc((void **)&d_r, sizeof(double) * rowsA));
printf("step 4: prepare data on device\n");
checkCudaErrors(cudaMemcpy(d_A, h_A, sizeof(double) * lda * colsA,
cudaMemcpyHostToDevice));
checkCudaErrors(
cudaMemcpy(d_b, h_b, sizeof(double) * rowsA, cudaMemcpyHostToDevice));
printf("step 5: solve A*x = b \n");
// d_A and d_b are read-only
if (0 == strcmp(opts.testFunc, "chol")) {
linearSolverCHOL(handle, rowsA, d_A, lda, d_b, d_x);
} else if (0 == strcmp(opts.testFunc, "lu")) {
linearSolverLU(handle, rowsA, d_A, lda, d_b, d_x);
} else if (0 == strcmp(opts.testFunc, "qr")) {
linearSolverQR(handle, rowsA, d_A, lda, d_b, d_x);
} else {
fprintf(stderr, "Error: %s is unknown function\n", opts.testFunc);
exit(EXIT_FAILURE);
}
printf("step 6: evaluate residual\n");
checkCudaErrors(
cudaMemcpy(d_r, d_b, sizeof(double) * rowsA, cudaMemcpyDeviceToDevice));
// r = b - A*x
checkCudaErrors(cublasDgemm_v2(cublasHandle, CUBLAS_OP_N, CUBLAS_OP_N, rowsA,
1, colsA, &minus_one, d_A, lda, d_x, rowsA,
&one, d_r, rowsA));
checkCudaErrors(
cudaMemcpy(h_x, d_x, sizeof(double) * colsA, cudaMemcpyDeviceToHost));
checkCudaErrors(
cudaMemcpy(h_r, d_r, sizeof(double) * rowsA, cudaMemcpyDeviceToHost));
x_inf = vec_norminf(colsA, h_x);
r_inf = vec_norminf(rowsA, h_r);
A_inf = mat_norminf(rowsA, colsA, h_A, lda);
printf("|b - A*x| = %E \n", r_inf);
printf("|A| = %E \n", A_inf);
printf("|x| = %E \n", x_inf);
printf("|b - A*x|/(|A|*|x|) = %E \n", r_inf / (A_inf * x_inf));
if (handle) {
checkCudaErrors(cusolverDnDestroy(handle));
}
if (cublasHandle) {
checkCudaErrors(cublasDestroy(cublasHandle));
}
if (stream) {
checkCudaErrors(cudaStreamDestroy(stream));
}
if (h_csrValA) {
free(h_csrValA);
}
if (h_csrRowPtrA) {
free(h_csrRowPtrA);
}
if (h_csrColIndA) {
free(h_csrColIndA);
}
if (h_A) {
free(h_A);
}
if (h_x) {
free(h_x);
}
if (h_b) {
free(h_b);
}
if (h_r) {
free(h_r);
}
if (d_A) {
checkCudaErrors(cudaFree(d_A));
}
if (d_x) {
checkCudaErrors(cudaFree(d_x));
}
if (d_b) {
checkCudaErrors(cudaFree(d_b));
}
if (d_r) {
checkCudaErrors(cudaFree(d_r));
}
return 0;
if (checkCmdLineFlag(argc, (const char **)argv, "lda")) {
opts.lda = getCmdLineArgumentInt(argc, (const char **)argv, "lda");
}
}
int main(int argc, char *argv[])
{
struct testOpts opts;
cusolverDnHandle_t handle = NULL;
cublasHandle_t cublasHandle = NULL; // used in residual evaluation
cudaStream_t stream = NULL;
int rowsA = 0; // number of rows of A
int colsA = 0; // number of columns of A
int nnzA = 0; // number of nonzeros of A
int baseA = 0; // base index in CSR format
int lda = 0; // leading dimension in dense matrix
// CSR(A) from I/O
int *h_csrRowPtrA = NULL;
int *h_csrColIndA = NULL;
double *h_csrValA = NULL;
double *h_A = NULL; // dense matrix from CSR(A)
double *h_x = NULL; // a copy of d_x
double *h_b = NULL; // b = ones(m,1)
double *h_r = NULL; // r = b - A*x, a copy of d_r
double *d_A = NULL; // a copy of h_A
double *d_x = NULL; // x = A \ b
double *d_b = NULL; // a copy of h_b
double *d_r = NULL; // r = b - A*x
// the constants are used in residual evaluation, r = b - A*x
const double minus_one = -1.0;
const double one = 1.0;
double x_inf = 0.0;
double r_inf = 0.0;
double A_inf = 0.0;
int errors = 0;
parseCommandLineArguments(argc, argv, opts);
if (NULL == opts.testFunc) {
opts.testFunc = "chol"; // By default running Cholesky as NO solver
// selected with -R option.
}
findCudaDevice(argc, (const char **)argv);
printf("step 1: read matrix market format\n");
if (opts.sparse_mat_filename == NULL) {
opts.sparse_mat_filename = sdkFindFilePath("gr_900_900_crg.mtx", argv[0]);
if (opts.sparse_mat_filename != NULL)
printf("Using default input file [%s]\n", opts.sparse_mat_filename);
else
printf("Could not find gr_900_900_crg.mtx\n");
}
else {
printf("Using input file [%s]\n", opts.sparse_mat_filename);
}
if (opts.sparse_mat_filename == NULL) {
fprintf(stderr, "Error: input matrix is not provided\n");
return EXIT_FAILURE;
}
if (loadMMSparseMatrix<double>(opts.sparse_mat_filename,
'd',
true,
&rowsA,
&colsA,
&nnzA,
&h_csrValA,
&h_csrRowPtrA,
&h_csrColIndA,
true)) {
exit(EXIT_FAILURE);
}
baseA = h_csrRowPtrA[0]; // baseA = {0,1}
printf("sparse matrix A is %d x %d with %d nonzeros, base=%d\n", rowsA, colsA, nnzA, baseA);
if (rowsA != colsA) {
fprintf(stderr, "Error: only support square matrix\n");
exit(EXIT_FAILURE);
}
printf("step 2: convert CSR(A) to dense matrix\n");
lda = opts.lda ? opts.lda : rowsA;
if (lda < rowsA) {
fprintf(stderr, "Error: lda must be greater or equal to dimension of A\n");
exit(EXIT_FAILURE);
}
h_A = (double *)malloc(sizeof(double) * lda * colsA);
h_x = (double *)malloc(sizeof(double) * colsA);
h_b = (double *)malloc(sizeof(double) * rowsA);
h_r = (double *)malloc(sizeof(double) * rowsA);
assert(NULL != h_A);
assert(NULL != h_x);
assert(NULL != h_b);
assert(NULL != h_r);
memset(h_A, 0, sizeof(double) * lda * colsA);
for (int row = 0; row < rowsA; row++) {
const int start = h_csrRowPtrA[row] - baseA;
const int end = h_csrRowPtrA[row + 1] - baseA;
for (int colidx = start; colidx < end; colidx++) {
const int col = h_csrColIndA[colidx] - baseA;
const double Areg = h_csrValA[colidx];
h_A[row + col * lda] = Areg;
}
}
printf("step 3: set right hand side vector (b) to 1\n");
for (int row = 0; row < rowsA; row++) {
h_b[row] = 1.0;
}
// verify if A is symmetric or not.
if (0 == strcmp(opts.testFunc, "chol")) {
int issym = 1;
for (int j = 0; j < colsA; j++) {
for (int i = j; i < rowsA; i++) {
double Aij = h_A[i + j * lda];
double Aji = h_A[j + i * lda];
if (Aij != Aji) {
issym = 0;
break;
}
}
}
if (!issym) {
printf("Error: A has no symmetric pattern, please use LU or QR \n");
exit(EXIT_FAILURE);
}
}
checkCudaErrors(cusolverDnCreate(&handle));
checkCudaErrors(cublasCreate(&cublasHandle));
checkCudaErrors(cudaStreamCreate(&stream));
checkCudaErrors(cusolverDnSetStream(handle, stream));
checkCudaErrors(cublasSetStream(cublasHandle, stream));
checkCudaErrors(cudaMalloc((void **)&d_A, sizeof(double) * lda * colsA));
checkCudaErrors(cudaMalloc((void **)&d_x, sizeof(double) * colsA));
checkCudaErrors(cudaMalloc((void **)&d_b, sizeof(double) * rowsA));
checkCudaErrors(cudaMalloc((void **)&d_r, sizeof(double) * rowsA));
printf("step 4: prepare data on device\n");
checkCudaErrors(cudaMemcpy(d_A, h_A, sizeof(double) * lda * colsA, cudaMemcpyHostToDevice));
checkCudaErrors(cudaMemcpy(d_b, h_b, sizeof(double) * rowsA, cudaMemcpyHostToDevice));
printf("step 5: solve A*x = b \n");
// d_A and d_b are read-only
if (0 == strcmp(opts.testFunc, "chol")) {
linearSolverCHOL(handle, rowsA, d_A, lda, d_b, d_x);
}
else if (0 == strcmp(opts.testFunc, "lu")) {
linearSolverLU(handle, rowsA, d_A, lda, d_b, d_x);
}
else if (0 == strcmp(opts.testFunc, "qr")) {
linearSolverQR(handle, rowsA, d_A, lda, d_b, d_x);
}
else {
fprintf(stderr, "Error: %s is unknown function\n", opts.testFunc);
exit(EXIT_FAILURE);
}
printf("step 6: evaluate residual\n");
checkCudaErrors(cudaMemcpy(d_r, d_b, sizeof(double) * rowsA, cudaMemcpyDeviceToDevice));
// r = b - A*x
checkCudaErrors(cublasDgemm_v2(
cublasHandle, CUBLAS_OP_N, CUBLAS_OP_N, rowsA, 1, colsA, &minus_one, d_A, lda, d_x, rowsA, &one, d_r, rowsA));
checkCudaErrors(cudaMemcpy(h_x, d_x, sizeof(double) * colsA, cudaMemcpyDeviceToHost));
checkCudaErrors(cudaMemcpy(h_r, d_r, sizeof(double) * rowsA, cudaMemcpyDeviceToHost));
x_inf = vec_norminf(colsA, h_x);
r_inf = vec_norminf(rowsA, h_r);
A_inf = mat_norminf(rowsA, colsA, h_A, lda);
printf("|b - A*x| = %E \n", r_inf);
printf("|A| = %E \n", A_inf);
printf("|x| = %E \n", x_inf);
printf("|b - A*x|/(|A|*|x|) = %E \n", r_inf / (A_inf * x_inf));
if (handle) {
checkCudaErrors(cusolverDnDestroy(handle));
}
if (cublasHandle) {
checkCudaErrors(cublasDestroy(cublasHandle));
}
if (stream) {
checkCudaErrors(cudaStreamDestroy(stream));
}
if (h_csrValA) {
free(h_csrValA);
}
if (h_csrRowPtrA) {
free(h_csrRowPtrA);
}
if (h_csrColIndA) {
free(h_csrColIndA);
}
if (h_A) {
free(h_A);
}
if (h_x) {
free(h_x);
}
if (h_b) {
free(h_b);
}
if (h_r) {
free(h_r);
}
if (d_A) {
checkCudaErrors(cudaFree(d_A));
}
if (d_x) {
checkCudaErrors(cudaFree(d_x));
}
if (d_b) {
checkCudaErrors(cudaFree(d_b));
}
if (d_r) {
checkCudaErrors(cudaFree(d_r));
}
return 0;
}

View File

@@ -1,128 +1,129 @@
/*
* Matrix Market I/O library for ANSI C
*
* See http://math.nist.gov/MatrixMarket for details.
*
*
*/
/*
* Matrix Market I/O library for ANSI C
*
* See http://math.nist.gov/MatrixMarket for details.
*
*
*/
/* avoid Windows warnings (for example: strcpy, fscanf, etc.) */
#if defined(_WIN32)
#if defined(_WIN32)
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// System includes
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Project includes
#include "mmio.h"
int mm_read_unsymmetric_sparse(const char *fname, int *M_, int *N_, int *nz_,
double **val_, int **I_, int **J_)
int mm_read_unsymmetric_sparse(const char *fname, int *M_, int *N_, int *nz_, double **val_, int **I_, int **J_)
{
FILE *f;
FILE *f;
MM_typecode matcode;
int M, N, nz;
int i;
double *val;
int *I, *J;
int M, N, nz;
int i;
double *val;
int *I, *J;
if ((f = fopen(fname, "r")) == NULL)
return -1;
if (mm_read_banner(f, &matcode) != 0)
{
return -1;
if (mm_read_banner(f, &matcode) != 0) {
printf("mm_read_unsymetric: Could not process Matrix Market banner ");
printf(" in file [%s]\n", fname);
return -1;
}
if ( !(mm_is_real(matcode) && mm_is_matrix(matcode) &&
mm_is_sparse(matcode)))
{
if (!(mm_is_real(matcode) && mm_is_matrix(matcode) && mm_is_sparse(matcode))) {
fprintf(stderr, "Sorry, this application does not support ");
fprintf(stderr, "Market Market type: [%s]\n",
mm_typecode_to_str(matcode));
fprintf(stderr, "Market Market type: [%s]\n", mm_typecode_to_str(matcode));
return -1;
}
/* find out size of sparse matrix: M, N, nz .... */
if (mm_read_mtx_crd_size(f, &M, &N, &nz) !=0)
{
if (mm_read_mtx_crd_size(f, &M, &N, &nz) != 0) {
fprintf(stderr, "read_unsymmetric_sparse(): could not parse matrix size.\n");
return -1;
}
*M_ = M;
*N_ = N;
*M_ = M;
*N_ = N;
*nz_ = nz;
/* reseve memory for matrices */
I = (int *) malloc(nz * sizeof(int));
J = (int *) malloc(nz * sizeof(int));
val = (double *) malloc(nz * sizeof(double));
I = (int *)malloc(nz * sizeof(int));
J = (int *)malloc(nz * sizeof(int));
val = (double *)malloc(nz * sizeof(double));
*val_ = val;
*I_ = I;
*J_ = J;
*I_ = I;
*J_ = J;
/* NOTE: when reading in doubles, ANSI C requires the use of the "l" */
/* specifier as in "%lg", "%lf", "%le", otherwise errors will occur */
/* (ANSI C X3.159-1989, Sec. 4.9.6.2, p. 136 lines 13-15) */
for (i=0; i<nz; i++)
{
for (i = 0; i < nz; i++) {
if (fscanf(f, "%d %d %lg\n", &I[i], &J[i], &val[i]) != 3) {
return -1;
}
I[i]--; /* adjust from 1-based to 0-based */
I[i]--; /* adjust from 1-based to 0-based */
J[i]--;
}
fclose(f);
return 0;
}
int mm_is_valid(MM_typecode matcode)
{
if (!mm_is_matrix(matcode)) return 0;
if (mm_is_dense(matcode) && mm_is_pattern(matcode)) return 0;
if (mm_is_real(matcode) && mm_is_hermitian(matcode)) return 0;
if (mm_is_pattern(matcode) && (mm_is_hermitian(matcode) ||
mm_is_skew(matcode))) return 0;
if (!mm_is_matrix(matcode))
return 0;
if (mm_is_dense(matcode) && mm_is_pattern(matcode))
return 0;
if (mm_is_real(matcode) && mm_is_hermitian(matcode))
return 0;
if (mm_is_pattern(matcode) && (mm_is_hermitian(matcode) || mm_is_skew(matcode)))
return 0;
return 1;
}
int mm_read_banner(FILE *f, MM_typecode *matcode)
{
char line[MM_MAX_LINE_LENGTH];
char banner[MM_MAX_TOKEN_LENGTH];
char mtx[MM_MAX_TOKEN_LENGTH];
char crd[MM_MAX_TOKEN_LENGTH];
char data_type[MM_MAX_TOKEN_LENGTH];
char storage_scheme[MM_MAX_TOKEN_LENGTH];
char line[MM_MAX_LINE_LENGTH];
char banner[MM_MAX_TOKEN_LENGTH];
char mtx[MM_MAX_TOKEN_LENGTH];
char crd[MM_MAX_TOKEN_LENGTH];
char data_type[MM_MAX_TOKEN_LENGTH];
char storage_scheme[MM_MAX_TOKEN_LENGTH];
char *p;
mm_clear_typecode(matcode);
mm_clear_typecode(matcode);
if (fgets(line, MM_MAX_LINE_LENGTH, f) == NULL)
if (fgets(line, MM_MAX_LINE_LENGTH, f) == NULL)
return MM_PREMATURE_EOF;
if (sscanf(line, "%s %s %s %s %s", banner, mtx, crd, data_type,
storage_scheme) != 5)
if (sscanf(line, "%s %s %s %s %s", banner, mtx, crd, data_type, storage_scheme) != 5)
return MM_PREMATURE_EOF;
for (p=mtx; *p!='\0'; *p=tolower(*p),p++); /* convert to lower case */
for (p=crd; *p!='\0'; *p=tolower(*p),p++);
for (p=data_type; *p!='\0'; *p=tolower(*p),p++);
for (p=storage_scheme; *p!='\0'; *p=tolower(*p),p++);
for (p = mtx; *p != '\0'; *p = tolower(*p), p++)
; /* convert to lower case */
for (p = crd; *p != '\0'; *p = tolower(*p), p++)
;
for (p = data_type; *p != '\0'; *p = tolower(*p), p++)
;
for (p = storage_scheme; *p != '\0'; *p = tolower(*p), p++)
;
/* check for banner */
if (strncmp(banner, MatrixMarketBanner, strlen(MatrixMarketBanner)) != 0)
@@ -130,7 +131,7 @@ int mm_read_banner(FILE *f, MM_typecode *matcode)
/* first field should be "mtx" */
if (strcmp(mtx, MM_MTX_STR) != 0)
return MM_UNSUPPORTED_TYPE;
return MM_UNSUPPORTED_TYPE;
mm_set_matrix(matcode);
@@ -140,46 +141,39 @@ int mm_read_banner(FILE *f, MM_typecode *matcode)
if (strcmp(crd, MM_SPARSE_STR) == 0)
mm_set_sparse(matcode);
else
if (strcmp(crd, MM_DENSE_STR) == 0)
mm_set_dense(matcode);
else if (strcmp(crd, MM_DENSE_STR) == 0)
mm_set_dense(matcode);
else
return MM_UNSUPPORTED_TYPE;
/* third field */
if (strcmp(data_type, MM_REAL_STR) == 0)
mm_set_real(matcode);
else
if (strcmp(data_type, MM_COMPLEX_STR) == 0)
else if (strcmp(data_type, MM_COMPLEX_STR) == 0)
mm_set_complex(matcode);
else
if (strcmp(data_type, MM_PATTERN_STR) == 0)
else if (strcmp(data_type, MM_PATTERN_STR) == 0)
mm_set_pattern(matcode);
else
if (strcmp(data_type, MM_INT_STR) == 0)
else if (strcmp(data_type, MM_INT_STR) == 0)
mm_set_integer(matcode);
else
return MM_UNSUPPORTED_TYPE;
/* fourth field */
if (strcmp(storage_scheme, MM_GENERAL_STR) == 0)
mm_set_general(matcode);
else
if (strcmp(storage_scheme, MM_SYMM_STR) == 0)
else if (strcmp(storage_scheme, MM_SYMM_STR) == 0)
mm_set_symmetric(matcode);
else
if (strcmp(storage_scheme, MM_HERM_STR) == 0)
else if (strcmp(storage_scheme, MM_HERM_STR) == 0)
mm_set_hermitian(matcode);
else
if (strcmp(storage_scheme, MM_SKEW_STR) == 0)
else if (strcmp(storage_scheme, MM_SKEW_STR) == 0)
mm_set_skew(matcode);
else
return MM_UNSUPPORTED_TYPE;
return 0;
}
@@ -188,36 +182,34 @@ int mm_write_mtx_crd_size(FILE *f, int M, int N, int nz)
{
if (fprintf(f, "%d %d %d\n", M, N, nz) != 3)
return MM_COULD_NOT_WRITE_FILE;
else
else
return 0;
}
int mm_read_mtx_crd_size(FILE *f, int *M, int *N, int *nz )
int mm_read_mtx_crd_size(FILE *f, int *M, int *N, int *nz)
{
char line[MM_MAX_LINE_LENGTH];
int num_items_read;
int num_items_read;
/* set return null parameter values, in case we exit with errors */
*M = *N = *nz = 0;
/* now continue scanning until you reach the end-of-comments */
do
{
if (fgets(line,MM_MAX_LINE_LENGTH,f) == NULL)
do {
if (fgets(line, MM_MAX_LINE_LENGTH, f) == NULL)
return MM_PREMATURE_EOF;
}while (line[0] == '%');
} while (line[0] == '%');
/* line[] is either blank or has M,N, nz */
if (sscanf(line, "%d %d %d", M, N, nz) == 3)
return 0;
else
do
{
num_items_read = fscanf(f, "%d %d %d", M, N, nz);
if (num_items_read == EOF) return MM_PREMATURE_EOF;
}
while (num_items_read != 3);
do {
num_items_read = fscanf(f, "%d %d %d", M, N, nz);
if (num_items_read == EOF)
return MM_PREMATURE_EOF;
} while (num_items_read != 3);
return 0;
}
@@ -226,28 +218,26 @@ int mm_read_mtx_crd_size(FILE *f, int *M, int *N, int *nz )
int mm_read_mtx_array_size(FILE *f, int *M, int *N)
{
char line[MM_MAX_LINE_LENGTH];
int num_items_read;
int num_items_read;
/* set return null parameter values, in case we exit with errors */
*M = *N = 0;
/* now continue scanning until you reach the end-of-comments */
do
{
if (fgets(line,MM_MAX_LINE_LENGTH,f) == NULL)
do {
if (fgets(line, MM_MAX_LINE_LENGTH, f) == NULL)
return MM_PREMATURE_EOF;
}while (line[0] == '%');
} while (line[0] == '%');
/* line[] is either blank or has M,N, nz */
if (sscanf(line, "%d %d", M, N) == 2)
return 0;
else /* we have a blank line */
do
{
num_items_read = fscanf(f, "%d %d", M, N);
if (num_items_read == EOF) return MM_PREMATURE_EOF;
}
while (num_items_read != 2);
do {
num_items_read = fscanf(f, "%d %d", M, N);
if (num_items_read == EOF)
return MM_PREMATURE_EOF;
} while (num_items_read != 2);
return 0;
}
@@ -256,75 +246,62 @@ int mm_write_mtx_array_size(FILE *f, int M, int N)
{
if (fprintf(f, "%d %d\n", M, N) != 2)
return MM_COULD_NOT_WRITE_FILE;
else
else
return 0;
}
/*-------------------------------------------------------------------------*/
/******************************************************************/
/* use when I[], J[], and val[]J, and val[] are already allocated */
/******************************************************************/
int mm_read_mtx_crd_data(FILE *f, int M, int N, int nz, int I[], int J[],
double val[], MM_typecode matcode)
int mm_read_mtx_crd_data(FILE *f, int M, int N, int nz, int I[], int J[], double val[], MM_typecode matcode)
{
int i;
if (mm_is_complex(matcode))
{
for (i=0; i<nz; i++)
if (fscanf(f, "%d %d %lg %lg", &I[i], &J[i], &val[2*i], &val[2*i+1])
!= 4) return MM_PREMATURE_EOF;
if (mm_is_complex(matcode)) {
for (i = 0; i < nz; i++)
if (fscanf(f, "%d %d %lg %lg", &I[i], &J[i], &val[2 * i], &val[2 * i + 1]) != 4)
return MM_PREMATURE_EOF;
}
else if (mm_is_real(matcode) || mm_is_integer(matcode))
{
for (i=0; i<nz; i++)
{
if (fscanf(f, "%d %d %lg\n", &I[i], &J[i], &val[i])
!= 3) return MM_PREMATURE_EOF;
else if (mm_is_real(matcode) || mm_is_integer(matcode)) {
for (i = 0; i < nz; i++) {
if (fscanf(f, "%d %d %lg\n", &I[i], &J[i], &val[i]) != 3)
return MM_PREMATURE_EOF;
}
}
else if (mm_is_pattern(matcode))
{
for (i=0; i<nz; i++)
if (fscanf(f, "%d %d", &I[i], &J[i])
!= 2) return MM_PREMATURE_EOF;
else if (mm_is_pattern(matcode)) {
for (i = 0; i < nz; i++)
if (fscanf(f, "%d %d", &I[i], &J[i]) != 2)
return MM_PREMATURE_EOF;
}
else
return MM_UNSUPPORTED_TYPE;
return 0;
}
int mm_read_mtx_crd_entry(FILE *f, int *I, int *J,
double *real, double *imag, MM_typecode matcode)
int mm_read_mtx_crd_entry(FILE *f, int *I, int *J, double *real, double *imag, MM_typecode matcode)
{
if (mm_is_complex(matcode))
{
if (fscanf(f, "%d %d %lg %lg", I, J, real, imag)
!= 4) return MM_PREMATURE_EOF;
if (mm_is_complex(matcode)) {
if (fscanf(f, "%d %d %lg %lg", I, J, real, imag) != 4)
return MM_PREMATURE_EOF;
}
else if (mm_is_real(matcode) || mm_is_integer(matcode))
{
if (fscanf(f, "%d %d %lg\n", I, J, real)
!= 3) return MM_PREMATURE_EOF;
else if (mm_is_real(matcode) || mm_is_integer(matcode)) {
if (fscanf(f, "%d %d %lg\n", I, J, real) != 3)
return MM_PREMATURE_EOF;
}
else if (mm_is_pattern(matcode))
{
if (fscanf(f, "%d %d", I, J) != 2) return MM_PREMATURE_EOF;
else if (mm_is_pattern(matcode)) {
if (fscanf(f, "%d %d", I, J) != 2)
return MM_PREMATURE_EOF;
}
else
return MM_UNSUPPORTED_TYPE;
return 0;
}
@@ -336,84 +313,78 @@ int mm_read_mtx_crd_entry(FILE *f, int *I, int *J,
(nz pairs of real/imaginary values)
************************************************************************/
int mm_read_mtx_crd(char *fname, int *M, int *N, int *nz, int **I, int **J,
double **val, MM_typecode *matcode)
int mm_read_mtx_crd(char *fname, int *M, int *N, int *nz, int **I, int **J, double **val, MM_typecode *matcode)
{
int ret_code;
int ret_code;
FILE *f;
if (strcmp(fname, "stdin") == 0) f=stdin;
else
if ((f = fopen(fname, "r")) == NULL)
if (strcmp(fname, "stdin") == 0)
f = stdin;
else if ((f = fopen(fname, "r")) == NULL)
return MM_COULD_NOT_READ_FILE;
if ((ret_code = mm_read_banner(f, matcode)) != 0)
return ret_code;
if (!(mm_is_valid(*matcode) && mm_is_sparse(*matcode) &&
mm_is_matrix(*matcode)))
if (!(mm_is_valid(*matcode) && mm_is_sparse(*matcode) && mm_is_matrix(*matcode)))
return MM_UNSUPPORTED_TYPE;
if ((ret_code = mm_read_mtx_crd_size(f, M, N, nz)) != 0)
return ret_code;
*I = (int *) malloc(*nz * sizeof(int));
*J = (int *) malloc(*nz * sizeof(int));
*I = (int *)malloc(*nz * sizeof(int));
*J = (int *)malloc(*nz * sizeof(int));
*val = NULL;
if (mm_is_complex(*matcode))
{
*val = (double *) malloc(*nz * 2 * sizeof(double));
ret_code = mm_read_mtx_crd_data(f, *M, *N, *nz, *I, *J, *val,
*matcode);
if (ret_code != 0) return ret_code;
if (mm_is_complex(*matcode)) {
*val = (double *)malloc(*nz * 2 * sizeof(double));
ret_code = mm_read_mtx_crd_data(f, *M, *N, *nz, *I, *J, *val, *matcode);
if (ret_code != 0)
return ret_code;
}
else if (mm_is_real(*matcode) || mm_is_integer(*matcode))
{
*val = (double *) malloc(*nz * sizeof(double));
ret_code = mm_read_mtx_crd_data(f, *M, *N, *nz, *I, *J, *val,
*matcode);
if (ret_code != 0) return ret_code;
else if (mm_is_real(*matcode) || mm_is_integer(*matcode)) {
*val = (double *)malloc(*nz * sizeof(double));
ret_code = mm_read_mtx_crd_data(f, *M, *N, *nz, *I, *J, *val, *matcode);
if (ret_code != 0)
return ret_code;
}
else if (mm_is_pattern(*matcode))
{
ret_code = mm_read_mtx_crd_data(f, *M, *N, *nz, *I, *J, *val,
*matcode);
if (ret_code != 0) return ret_code;
else if (mm_is_pattern(*matcode)) {
ret_code = mm_read_mtx_crd_data(f, *M, *N, *nz, *I, *J, *val, *matcode);
if (ret_code != 0)
return ret_code;
}
if (f != stdin) fclose(f);
if (f != stdin)
fclose(f);
return 0;
}
int mm_write_banner(FILE *f, MM_typecode matcode)
{
char *str = mm_typecode_to_str(matcode);
int ret_code;
int ret_code;
ret_code = fprintf(f, "%s %s\n", MatrixMarketBanner, str);
free(str);
if (ret_code !=2 )
if (ret_code != 2)
return MM_COULD_NOT_WRITE_FILE;
else
return 0;
}
int mm_write_mtx_crd(char fname[], int M, int N, int nz, int I[], int J[],
double val[], MM_typecode matcode)
int mm_write_mtx_crd(char fname[], int M, int N, int nz, int I[], int J[], double val[], MM_typecode matcode)
{
FILE *f;
int i;
int i;
if (strcmp(fname, "stdout") == 0)
if (strcmp(fname, "stdout") == 0)
f = stdout;
else
if ((f = fopen(fname, "w")) == NULL)
else if ((f = fopen(fname, "w")) == NULL)
return MM_COULD_NOT_WRITE_FILE;
/* print banner followed by typecode */
fprintf(f, "%s ", MatrixMarketBanner);
fprintf(f, "%s\n", mm_typecode_to_str(matcode));
@@ -423,54 +394,51 @@ int mm_write_mtx_crd(char fname[], int M, int N, int nz, int I[], int J[],
/* print values */
if (mm_is_pattern(matcode))
for (i=0; i<nz; i++)
for (i = 0; i < nz; i++)
fprintf(f, "%d %d\n", I[i], J[i]);
else
if (mm_is_integer(matcode))
for (i=0; i<nz; i++)
else if (mm_is_integer(matcode))
for (i = 0; i < nz; i++)
fprintf(f, "%d %d %d\n", I[i], J[i], (int)val[i]);
else
if (mm_is_real(matcode))
for (i=0; i<nz; i++)
else if (mm_is_real(matcode))
for (i = 0; i < nz; i++)
fprintf(f, "%d %d %20.16g\n", I[i], J[i], val[i]);
else
if (mm_is_complex(matcode))
for (i=0; i<nz; i++)
fprintf(f, "%d %d %20.16g %20.16g\n", I[i], J[i], val[2*i],
val[2*i+1]);
else
{
if (f != stdout) fclose(f);
else if (mm_is_complex(matcode))
for (i = 0; i < nz; i++)
fprintf(f, "%d %d %20.16g %20.16g\n", I[i], J[i], val[2 * i], val[2 * i + 1]);
else {
if (f != stdout)
fclose(f);
return MM_UNSUPPORTED_TYPE;
}
if (f !=stdout) fclose(f);
if (f != stdout)
fclose(f);
return 0;
}
/**
* Create a new copy of a string s. mm_strdup() is a common routine, but
* not part of ANSI C, so it is included here. Used by mm_typecode_to_str().
*
*/
* Create a new copy of a string s. mm_strdup() is a common routine, but
* not part of ANSI C, so it is included here. Used by mm_typecode_to_str().
*
*/
static char *mm_strdup(const char *s)
{
size_t len = strlen(s);
char *s2 = (char *) malloc((len+1)*sizeof(char));
return strcpy(s2, s);
size_t len = strlen(s);
char *s2 = (char *)malloc((len + 1) * sizeof(char));
return strcpy(s2, s);
}
char *mm_typecode_to_str(MM_typecode matcode)
char *mm_typecode_to_str(MM_typecode matcode)
{
char buffer[MM_MAX_LINE_LENGTH];
char buffer[MM_MAX_LINE_LENGTH];
char *types[4];
//char *mm_strdup(const char *);
//int error =0;
// char *mm_strdup(const char *);
// int error =0;
/* check for MTX type */
if (mm_is_matrix(matcode))
if (mm_is_matrix(matcode))
types[0] = MM_MTX_STR;
else
return NULL; // error=1;
@@ -478,8 +446,7 @@ char *mm_typecode_to_str(MM_typecode matcode)
/* check for CRD or ARR matrix */
if (mm_is_sparse(matcode))
types[1] = MM_SPARSE_STR;
else
if (mm_is_dense(matcode))
else if (mm_is_dense(matcode))
types[1] = MM_DENSE_STR;
else
return NULL;
@@ -487,14 +454,11 @@ char *mm_typecode_to_str(MM_typecode matcode)
/* check for element data type */
if (mm_is_real(matcode))
types[2] = MM_REAL_STR;
else
if (mm_is_complex(matcode))
else if (mm_is_complex(matcode))
types[2] = MM_COMPLEX_STR;
else
if (mm_is_pattern(matcode))
else if (mm_is_pattern(matcode))
types[2] = MM_PATTERN_STR;
else
if (mm_is_integer(matcode))
else if (mm_is_integer(matcode))
types[2] = MM_INT_STR;
else
return NULL;
@@ -503,19 +467,15 @@ char *mm_typecode_to_str(MM_typecode matcode)
/* check for symmetry type */
if (mm_is_general(matcode))
types[3] = MM_GENERAL_STR;
else
if (mm_is_symmetric(matcode))
else if (mm_is_symmetric(matcode))
types[3] = MM_SYMM_STR;
else
if (mm_is_hermitian(matcode))
else if (mm_is_hermitian(matcode))
types[3] = MM_HERM_STR;
else
if (mm_is_skew(matcode))
else if (mm_is_skew(matcode))
types[3] = MM_SKEW_STR;
else
return NULL;
sprintf(buffer,"%s %s %s %s", types[0], types[1], types[2], types[3]);
sprintf(buffer, "%s %s %s %s", types[0], types[1], types[2], types[3]);
return mm_strdup(buffer);
}

View File

@@ -1,141 +1,138 @@
/*
* Matrix Market I/O library for ANSI C
*
* See http://math.nist.gov/MatrixMarket for details.
*
*
*/
/*
* Matrix Market I/O library for ANSI C
*
* See http://math.nist.gov/MatrixMarket for details.
*
*
*/
#ifndef MM_IO_H
#define MM_IO_H
#include <stdio.h>
#if defined(__cplusplus)
extern "C" {
extern "C"
{
#endif /* __cplusplus */
#define MM_MAX_LINE_LENGTH 1025
#define MatrixMarketBanner "%%MatrixMarket"
#define MM_MAX_LINE_LENGTH 1025
#define MatrixMarketBanner "%%MatrixMarket"
#define MM_MAX_TOKEN_LENGTH 64
typedef char MM_typecode[4];
typedef char MM_typecode[4];
char *mm_typecode_to_str(MM_typecode matcode);
char *mm_typecode_to_str(MM_typecode matcode);
int mm_read_banner(FILE *f, MM_typecode *matcode);
int mm_read_mtx_crd_size(FILE *f, int *M, int *N, int *nz);
int mm_read_mtx_array_size(FILE *f, int *M, int *N);
int mm_read_banner(FILE *f, MM_typecode *matcode);
int mm_read_mtx_crd_size(FILE *f, int *M, int *N, int *nz);
int mm_read_mtx_array_size(FILE *f, int *M, int *N);
int mm_write_banner(FILE *f, MM_typecode matcode);
int mm_write_mtx_crd_size(FILE *f, int M, int N, int nz);
int mm_write_mtx_array_size(FILE *f, int M, int N);
int mm_write_banner(FILE *f, MM_typecode matcode);
int mm_write_mtx_crd_size(FILE *f, int M, int N, int nz);
int mm_write_mtx_array_size(FILE *f, int M, int N);
/********************* MM_typecode query fucntions ***************************/
/********************* MM_typecode query fucntions ***************************/
#define mm_is_matrix(typecode) ((typecode)[0]=='M')
#define mm_is_matrix(typecode) ((typecode)[0] == 'M')
#define mm_is_sparse(typecode) ((typecode)[1]=='C')
#define mm_is_coordinate(typecode)((typecode)[1]=='C')
#define mm_is_dense(typecode) ((typecode)[1]=='A')
#define mm_is_array(typecode) ((typecode)[1]=='A')
#define mm_is_sparse(typecode) ((typecode)[1] == 'C')
#define mm_is_coordinate(typecode) ((typecode)[1] == 'C')
#define mm_is_dense(typecode) ((typecode)[1] == 'A')
#define mm_is_array(typecode) ((typecode)[1] == 'A')
#define mm_is_complex(typecode) ((typecode)[2]=='C')
#define mm_is_real(typecode) ((typecode)[2]=='R')
#define mm_is_pattern(typecode) ((typecode)[2]=='P')
#define mm_is_integer(typecode) ((typecode)[2]=='I')
#define mm_is_complex(typecode) ((typecode)[2] == 'C')
#define mm_is_real(typecode) ((typecode)[2] == 'R')
#define mm_is_pattern(typecode) ((typecode)[2] == 'P')
#define mm_is_integer(typecode) ((typecode)[2] == 'I')
#define mm_is_symmetric(typecode)((typecode)[3]=='S')
#define mm_is_general(typecode) ((typecode)[3]=='G')
#define mm_is_skew(typecode) ((typecode)[3]=='K')
#define mm_is_hermitian(typecode)((typecode)[3]=='H')
#define mm_is_symmetric(typecode) ((typecode)[3] == 'S')
#define mm_is_general(typecode) ((typecode)[3] == 'G')
#define mm_is_skew(typecode) ((typecode)[3] == 'K')
#define mm_is_hermitian(typecode) ((typecode)[3] == 'H')
int mm_is_valid(MM_typecode matcode); /* too complex for a macro */
int mm_is_valid(MM_typecode matcode); /* too complex for a macro */
/********************* MM_typecode modify fucntions ***************************/
/********************* MM_typecode modify fucntions ***************************/
#define mm_set_matrix(typecode) ((*typecode)[0]='M')
#define mm_set_coordinate(typecode) ((*typecode)[1]='C')
#define mm_set_array(typecode) ((*typecode)[1]='A')
#define mm_set_dense(typecode) mm_set_array(typecode)
#define mm_set_sparse(typecode) mm_set_coordinate(typecode)
#define mm_set_matrix(typecode) ((*typecode)[0] = 'M')
#define mm_set_coordinate(typecode) ((*typecode)[1] = 'C')
#define mm_set_array(typecode) ((*typecode)[1] = 'A')
#define mm_set_dense(typecode) mm_set_array(typecode)
#define mm_set_sparse(typecode) mm_set_coordinate(typecode)
#define mm_set_complex(typecode)((*typecode)[2]='C')
#define mm_set_real(typecode) ((*typecode)[2]='R')
#define mm_set_pattern(typecode)((*typecode)[2]='P')
#define mm_set_integer(typecode)((*typecode)[2]='I')
#define mm_set_complex(typecode) ((*typecode)[2] = 'C')
#define mm_set_real(typecode) ((*typecode)[2] = 'R')
#define mm_set_pattern(typecode) ((*typecode)[2] = 'P')
#define mm_set_integer(typecode) ((*typecode)[2] = 'I')
#define mm_set_symmetric(typecode)((*typecode)[3]='S')
#define mm_set_general(typecode)((*typecode)[3]='G')
#define mm_set_skew(typecode) ((*typecode)[3]='K')
#define mm_set_hermitian(typecode)((*typecode)[3]='H')
#define mm_set_symmetric(typecode) ((*typecode)[3] = 'S')
#define mm_set_general(typecode) ((*typecode)[3] = 'G')
#define mm_set_skew(typecode) ((*typecode)[3] = 'K')
#define mm_set_hermitian(typecode) ((*typecode)[3] = 'H')
#define mm_clear_typecode(typecode) ((*typecode)[0]=(*typecode)[1]= \
(*typecode)[2]=' ',(*typecode)[3]='G')
#define mm_clear_typecode(typecode) ((*typecode)[0] = (*typecode)[1] = (*typecode)[2] = ' ', (*typecode)[3] = 'G')
#define mm_initialize_typecode(typecode) mm_clear_typecode(typecode)
/********************* Matrix Market error codes ***************************/
/********************* Matrix Market error codes ***************************/
#define MM_COULD_NOT_READ_FILE 11
#define MM_PREMATURE_EOF 12
#define MM_NOT_MTX 13
#define MM_NO_HEADER 14
#define MM_UNSUPPORTED_TYPE 15
#define MM_LINE_TOO_LONG 16
#define MM_COULD_NOT_WRITE_FILE 17
#define MM_COULD_NOT_READ_FILE 11
#define MM_PREMATURE_EOF 12
#define MM_NOT_MTX 13
#define MM_NO_HEADER 14
#define MM_UNSUPPORTED_TYPE 15
#define MM_LINE_TOO_LONG 16
#define MM_COULD_NOT_WRITE_FILE 17
/******************** Matrix Market internal definitions ********************
/******************** Matrix Market internal definitions ********************
MM_matrix_typecode: 4-character sequence
MM_matrix_typecode: 4-character sequence
ojbect sparse/ data storage
dense type scheme
ojbect sparse/ data storage
dense type scheme
string position: [0] [1] [2] [3]
string position: [0] [1] [2] [3]
Matrix typecode: M(atrix) C(oord) R(eal) G(eneral)
A(array) C(omplex) H(ermitian)
P(attern) S(ymmetric)
I(nteger) K(kew)
Matrix typecode: M(atrix) C(oord) R(eal) G(eneral)
A(array) C(omplex) H(ermitian)
P(attern) S(ymmetric)
I(nteger) K(kew)
***********************************************************************/
***********************************************************************/
#define MM_MTX_STR "matrix"
#define MM_ARRAY_STR "array"
#define MM_DENSE_STR "array"
#define MM_COORDINATE_STR "coordinate"
#define MM_SPARSE_STR "coordinate"
#define MM_COMPLEX_STR "complex"
#define MM_REAL_STR "real"
#define MM_INT_STR "integer"
#define MM_GENERAL_STR "general"
#define MM_SYMM_STR "symmetric"
#define MM_HERM_STR "hermitian"
#define MM_SKEW_STR "skew-symmetric"
#define MM_PATTERN_STR "pattern"
#define MM_MTX_STR "matrix"
#define MM_ARRAY_STR "array"
#define MM_DENSE_STR "array"
#define MM_COORDINATE_STR "coordinate"
#define MM_SPARSE_STR "coordinate"
#define MM_COMPLEX_STR "complex"
#define MM_REAL_STR "real"
#define MM_INT_STR "integer"
#define MM_GENERAL_STR "general"
#define MM_SYMM_STR "symmetric"
#define MM_HERM_STR "hermitian"
#define MM_SKEW_STR "skew-symmetric"
#define MM_PATTERN_STR "pattern"
/* high level routines */
int mm_read_mtx_crd(char *fname, int *M, int *N, int *nz, int **I, int **J,
double **val, MM_typecode *matcode);
/* high level routines */
int mm_read_mtx_crd(char *fname, int *M, int *N, int *nz, int **I, int **J, double **val, MM_typecode *matcode);
int mm_write_mtx_crd(char fname[], int M, int N, int nz, int I[], int J[],
double val[], MM_typecode matcode);
int mm_read_mtx_crd_data(FILE *f, int M, int N, int nz, int I[], int J[],
double val[], MM_typecode matcode);
int mm_read_mtx_crd_entry(FILE *f, int *I, int *J, double *real, double *img,
MM_typecode matcode);
int mm_write_mtx_crd(char fname[], int M, int N, int nz, int I[], int J[], double val[], MM_typecode matcode);
int mm_read_mtx_crd_data(FILE *f, int M, int N, int nz, int I[], int J[], double val[], MM_typecode matcode);
int mm_read_mtx_crd_entry(FILE *f, int *I, int *J, double *real, double *img, MM_typecode matcode);
int mm_read_unsymmetric_sparse(const char *fname, int *M_, int *N_, int *nz_,
double **val_, int **I_, int **J_);
int mm_read_unsymmetric_sparse(const char *fname, int *M_, int *N_, int *nz_, double **val_, int **I_, int **J_);
#if defined(__cplusplus)
}
#endif /* __cplusplus */
#endif /* __cplusplus */
#endif

View File

@@ -1,427 +1,375 @@
#include <cusolverDn.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "mmio.h"
#include <cusolverDn.h>
/* avoid Windows warnings (for example: strcpy, fscanf, etc.) */
#if defined(_WIN32)
#if defined(_WIN32)
#define _CRT_SECURE_NO_WARNINGS
#endif
/* various __inline__ __device__ function to initialize a T_ELEM */
template <typename T_ELEM> __inline__ T_ELEM cuGet (int );
template <> __inline__ float cuGet<float >(int x)
{
return float(x);
}
template <typename T_ELEM> __inline__ T_ELEM cuGet(int);
template <> __inline__ float cuGet<float>(int x) { return float(x); }
template <> __inline__ double cuGet<double>(int x)
{
return double(x);
}
template <> __inline__ double cuGet<double>(int x) { return double(x); }
template <> __inline__ cuComplex cuGet<cuComplex>(int x)
{
return (make_cuComplex( float(x), 0.0f ));
}
template <> __inline__ cuComplex cuGet<cuComplex>(int x) { return (make_cuComplex(float(x), 0.0f)); }
template <> __inline__ cuDoubleComplex cuGet<cuDoubleComplex>(int x)
template <> __inline__ cuDoubleComplex cuGet<cuDoubleComplex>(int x) { return (make_cuDoubleComplex(double(x), 0.0)); }
template <typename T_ELEM> __inline__ T_ELEM cuGet(int, int);
template <> __inline__ float cuGet<float>(int x, int y) { return float(x); }
template <> __inline__ double cuGet<double>(int x, int y) { return double(x); }
template <> __inline__ cuComplex cuGet<cuComplex>(int x, int y) { return make_cuComplex(float(x), float(y)); }
template <> __inline__ cuDoubleComplex cuGet<cuDoubleComplex>(int x, int y)
{
return (make_cuDoubleComplex( double(x), 0.0 ));
return (make_cuDoubleComplex(double(x), double(y)));
}
template <typename T_ELEM> __inline__ T_ELEM cuGet (int , int );
template <> __inline__ float cuGet<float >(int x, int y)
{
return float(x);
}
template <typename T_ELEM> __inline__ T_ELEM cuGet(float);
template <> __inline__ float cuGet<float>(float x) { return float(x); }
template <> __inline__ double cuGet<double>(int x, int y)
{
return double(x);
}
template <> __inline__ double cuGet<double>(float x) { return double(x); }
template <> __inline__ cuComplex cuGet<cuComplex>(int x, int y)
{
return make_cuComplex( float(x), float(y) );
}
template <> __inline__ cuComplex cuGet<cuComplex>(float x) { return (make_cuComplex(float(x), 0.0f)); }
template <> __inline__ cuDoubleComplex cuGet<cuDoubleComplex>(int x, int y)
template <> __inline__ cuDoubleComplex cuGet<cuDoubleComplex>(float x)
{
return (make_cuDoubleComplex( double(x), double(y) ));
return (make_cuDoubleComplex(double(x), 0.0));
}
template <typename T_ELEM> __inline__ T_ELEM cuGet (float );
template <> __inline__ float cuGet<float >(float x)
{
return float(x);
}
template <typename T_ELEM> __inline__ T_ELEM cuGet(float, float);
template <> __inline__ float cuGet<float>(float x, float y) { return float(x); }
template <> __inline__ double cuGet<double>(float x)
{
return double(x);
}
template <> __inline__ double cuGet<double>(float x, float y) { return double(x); }
template <> __inline__ cuComplex cuGet<cuComplex>(float x)
{
return (make_cuComplex( float(x), 0.0f ));
}
template <> __inline__ cuComplex cuGet<cuComplex>(float x, float y) { return (make_cuComplex(float(x), float(y))); }
template <> __inline__ cuDoubleComplex cuGet<cuDoubleComplex>(float x)
template <> __inline__ cuDoubleComplex cuGet<cuDoubleComplex>(float x, float y)
{
return (make_cuDoubleComplex( double(x), 0.0 ));
return (make_cuDoubleComplex(double(x), double(y)));
}
template <typename T_ELEM> __inline__ T_ELEM cuGet (float, float );
template <> __inline__ float cuGet<float >(float x, float y)
{
return float(x);
}
template <typename T_ELEM> __inline__ T_ELEM cuGet(double);
template <> __inline__ float cuGet<float>(double x) { return float(x); }
template <> __inline__ double cuGet<double>(float x, float y)
{
return double(x);
}
template <> __inline__ double cuGet<double>(double x) { return double(x); }
template <> __inline__ cuComplex cuGet<cuComplex>(float x, float y)
{
return (make_cuComplex( float(x), float(y) ));
}
template <> __inline__ cuComplex cuGet<cuComplex>(double x) { return (make_cuComplex(float(x), 0.0f)); }
template <> __inline__ cuDoubleComplex cuGet<cuDoubleComplex>(float x, float y)
template <> __inline__ cuDoubleComplex cuGet<cuDoubleComplex>(double x)
{
return (make_cuDoubleComplex( double(x), double(y) ));
return (make_cuDoubleComplex(double(x), 0.0));
}
template <typename T_ELEM> __inline__ T_ELEM cuGet (double );
template <> __inline__ float cuGet<float >(double x)
{
return float(x);
}
template <typename T_ELEM> __inline__ T_ELEM cuGet(double, double);
template <> __inline__ float cuGet<float>(double x, double y) { return float(x); }
template <> __inline__ double cuGet<double>(double x)
{
return double(x);
}
template <> __inline__ double cuGet<double>(double x, double y) { return double(x); }
template <> __inline__ cuComplex cuGet<cuComplex>(double x)
{
return (make_cuComplex( float(x), 0.0f ));
}
template <> __inline__ cuComplex cuGet<cuComplex>(double x, double y) { return (make_cuComplex(float(x), float(y))); }
template <> __inline__ cuDoubleComplex cuGet<cuDoubleComplex>(double x)
template <> __inline__ cuDoubleComplex cuGet<cuDoubleComplex>(double x, double y)
{
return (make_cuDoubleComplex( double(x), 0.0 ));
return (make_cuDoubleComplex(double(x), double(y)));
}
template <typename T_ELEM> __inline__ T_ELEM cuGet (double, double );
template <> __inline__ float cuGet<float >(double x, double y)
{
return float(x);
}
template <> __inline__ double cuGet<double>(double x, double y)
{
return double(x);
}
template <> __inline__ cuComplex cuGet<cuComplex>(double x, double y)
{
return (make_cuComplex( float(x), float(y) ));
}
template <> __inline__ cuDoubleComplex cuGet<cuDoubleComplex>(double x, double y)
{
return (make_cuDoubleComplex( double(x), double(y) ));
}
static void compress_index(
const int *Ind,
int nnz,
int m,
int *Ptr,
int base)
static void compress_index(const int *Ind, int nnz, int m, int *Ptr, int base)
{
int i;
/* initialize everything to zero */
for(i=0; i<m+1; i++){
Ptr[i]=0;
}
for (i = 0; i < m + 1; i++) {
Ptr[i] = 0;
}
/* count elements in every row */
Ptr[0]=base;
for(i=0; i<nnz; i++){
Ptr[Ind[i]+(1-base)]++;
}
Ptr[0] = base;
for (i = 0; i < nnz; i++) {
Ptr[Ind[i] + (1 - base)]++;
}
/* add all the values */
for(i=0; i<m; i++){
Ptr[i+1]+=Ptr[i];
}
for (i = 0; i < m; i++) {
Ptr[i + 1] += Ptr[i];
}
}
struct cooFormat {
int i ;
int j ;
int p ; // permutation
struct cooFormat
{
int i;
int j;
int p; // permutation
};
int cmp_cooFormat_csr( struct cooFormat *s, struct cooFormat *t)
int cmp_cooFormat_csr(struct cooFormat *s, struct cooFormat *t)
{
if ( s->i < t->i ){
return -1 ;
if (s->i < t->i) {
return -1;
}
else if ( s->i > t->i ){
return 1 ;
else if (s->i > t->i) {
return 1;
}
else{
return s->j - t->j ;
else {
return s->j - t->j;
}
}
int cmp_cooFormat_csc( struct cooFormat *s, struct cooFormat *t)
int cmp_cooFormat_csc(struct cooFormat *s, struct cooFormat *t)
{
if ( s->j < t->j ){
return -1 ;
if (s->j < t->j) {
return -1;
}
else if ( s->j > t->j ){
return 1 ;
else if (s->j > t->j) {
return 1;
}
else{
return s->i - t->i ;
else {
return s->i - t->i;
}
}
typedef int (*FUNPTR) (const void*, const void*) ;
typedef int (*FUNPTR2) ( struct cooFormat *s, struct cooFormat *t) ;
typedef int (*FUNPTR)(const void *, const void *);
typedef int (*FUNPTR2)(struct cooFormat *s, struct cooFormat *t);
static FUNPTR2 fptr_array[2] = {
static FUNPTR2 fptr_array[2] = {
cmp_cooFormat_csr,
cmp_cooFormat_csc,
};
static int verify_pattern(
int m,
int nnz,
int *csrRowPtr,
int *csrColInd)
static int verify_pattern(int m, int nnz, int *csrRowPtr, int *csrColInd)
{
int i, col, start, end, base_index;
int error_found = 0;
if (nnz != (csrRowPtr[m] - csrRowPtr[0])){
fprintf(stderr, "Error (nnz check failed): (csrRowPtr[%d]=%d - csrRowPtr[%d]=%d) != (nnz=%d)\n", 0, csrRowPtr[0], m, csrRowPtr[m], nnz);
if (nnz != (csrRowPtr[m] - csrRowPtr[0])) {
fprintf(stderr,
"Error (nnz check failed): (csrRowPtr[%d]=%d - csrRowPtr[%d]=%d) != (nnz=%d)\n",
0,
csrRowPtr[0],
m,
csrRowPtr[m],
nnz);
error_found = 1;
}
base_index = csrRowPtr[0];
if ((0 != base_index) && (1 != base_index)){
if ((0 != base_index) && (1 != base_index)) {
fprintf(stderr, "Error (base index check failed): base index = %d\n", base_index);
error_found = 1;
}
for (i=0; (!error_found) && (i<m); i++){
start = csrRowPtr[i ] - base_index;
end = csrRowPtr[i+1] - base_index;
if (start > end){
fprintf(stderr, "Error (corrupted row): csrRowPtr[%d] (=%d) > csrRowPtr[%d] (=%d)\n", i, start+base_index, i+1, end+base_index);
for (i = 0; (!error_found) && (i < m); i++) {
start = csrRowPtr[i] - base_index;
end = csrRowPtr[i + 1] - base_index;
if (start > end) {
fprintf(stderr,
"Error (corrupted row): csrRowPtr[%d] (=%d) > csrRowPtr[%d] (=%d)\n",
i,
start + base_index,
i + 1,
end + base_index);
error_found = 1;
}
for (col=start; col<end; col++){
if (csrColInd[col] < base_index){
for (col = start; col < end; col++) {
if (csrColInd[col] < base_index) {
fprintf(stderr, "Error (column vs. base index check failed): csrColInd[%d] < %d\n", col, base_index);
error_found = 1;
}
if ((col < (end-1)) && (csrColInd[col] >= csrColInd[col+1])){
fprintf(stderr, "Error (sorting of the column indecis check failed): (csrColInd[%d]=%d) >= (csrColInd[%d]=%d)\n", col, csrColInd[col], col+1, csrColInd[col+1]);
if ((col < (end - 1)) && (csrColInd[col] >= csrColInd[col + 1])) {
fprintf(
stderr,
"Error (sorting of the column indecis check failed): (csrColInd[%d]=%d) >= (csrColInd[%d]=%d)\n",
col,
csrColInd[col],
col + 1,
csrColInd[col + 1]);
error_found = 1;
}
}
}
return error_found ;
return error_found;
}
template <typename T_ELEM>
int loadMMSparseMatrix(
char *filename,
char elem_type,
bool csrFormat,
int *m,
int *n,
int *nnz,
T_ELEM **aVal,
int **aRowInd,
int **aColInd,
int extendSymMatrix)
int loadMMSparseMatrix(char *filename,
char elem_type,
bool csrFormat,
int *m,
int *n,
int *nnz,
T_ELEM **aVal,
int **aRowInd,
int **aColInd,
int extendSymMatrix)
{
MM_typecode matcode;
double *tempVal;
int *tempRowInd,*tempColInd;
double *tval;
int *trow,*tcol;
int *csrRowPtr, *cscColPtr;
int i,j,error,base,count;
MM_typecode matcode;
double *tempVal;
int *tempRowInd, *tempColInd;
double *tval;
int *trow, *tcol;
int *csrRowPtr, *cscColPtr;
int i, j, error, base, count;
struct cooFormat *work;
/* read the matrix */
/* read the matrix */
error = mm_read_mtx_crd(filename, m, n, nnz, &trow, &tcol, &tval, &matcode);
if (error) {
fprintf(stderr, "!!!! can not open file: '%s'\n", filename);
return 1;
return 1;
}
/* start error checking */
if (mm_is_complex(matcode) && ((elem_type != 'z') && (elem_type != 'c'))) {
fprintf(stderr, "!!!! complex matrix requires type 'z' or 'c'\n");
return 1;
return 1;
}
if (mm_is_dense(matcode) || mm_is_array(matcode) || mm_is_pattern(matcode) /*|| mm_is_integer(matcode)*/){
if (mm_is_dense(matcode) || mm_is_array(matcode) || mm_is_pattern(matcode) /*|| mm_is_integer(matcode)*/) {
fprintf(stderr, "!!!! dense, array, pattern and integer matrices are not supported\n");
return 1;
return 1;
}
/* if necessary symmetrize the pattern (transform from triangular to full) */
if ((extendSymMatrix) && (mm_is_symmetric(matcode) || mm_is_hermitian(matcode) || mm_is_skew(matcode))){
//count number of non-diagonal elements
count=0;
for(i=0; i<(*nnz); i++){
if (trow[i] != tcol[i]){
if ((extendSymMatrix) && (mm_is_symmetric(matcode) || mm_is_hermitian(matcode) || mm_is_skew(matcode))) {
// count number of non-diagonal elements
count = 0;
for (i = 0; i < (*nnz); i++) {
if (trow[i] != tcol[i]) {
count++;
}
}
//allocate space for the symmetrized matrix
tempRowInd = (int *)malloc((*nnz + count) * sizeof(int));
tempColInd = (int *)malloc((*nnz + count) * sizeof(int));
if (mm_is_real(matcode) || mm_is_integer(matcode)){
// allocate space for the symmetrized matrix
tempRowInd = (int *)malloc((*nnz + count) * sizeof(int));
tempColInd = (int *)malloc((*nnz + count) * sizeof(int));
if (mm_is_real(matcode) || mm_is_integer(matcode)) {
tempVal = (double *)malloc((*nnz + count) * sizeof(double));
}
else{
else {
tempVal = (double *)malloc(2 * (*nnz + count) * sizeof(double));
}
//copy the elements regular and transposed locations
for(j=0, i=0; i<(*nnz); i++){
tempRowInd[j]=trow[i];
tempColInd[j]=tcol[i];
if (mm_is_real(matcode) || mm_is_integer(matcode)){
tempVal[j]=tval[i];
// copy the elements regular and transposed locations
for (j = 0, i = 0; i < (*nnz); i++) {
tempRowInd[j] = trow[i];
tempColInd[j] = tcol[i];
if (mm_is_real(matcode) || mm_is_integer(matcode)) {
tempVal[j] = tval[i];
}
else{
tempVal[2*j] =tval[2*i];
tempVal[2*j+1]=tval[2*i+1];
else {
tempVal[2 * j] = tval[2 * i];
tempVal[2 * j + 1] = tval[2 * i + 1];
}
j++;
if (trow[i] != tcol[i]){
tempRowInd[j]=tcol[i];
tempColInd[j]=trow[i];
if (mm_is_real(matcode) || mm_is_integer(matcode)){
if (mm_is_skew(matcode)){
tempVal[j]=-tval[i];
if (trow[i] != tcol[i]) {
tempRowInd[j] = tcol[i];
tempColInd[j] = trow[i];
if (mm_is_real(matcode) || mm_is_integer(matcode)) {
if (mm_is_skew(matcode)) {
tempVal[j] = -tval[i];
}
else{
tempVal[j]= tval[i];
else {
tempVal[j] = tval[i];
}
}
else{
if(mm_is_hermitian(matcode)){
tempVal[2*j] = tval[2*i];
tempVal[2*j+1]=-tval[2*i+1];
else {
if (mm_is_hermitian(matcode)) {
tempVal[2 * j] = tval[2 * i];
tempVal[2 * j + 1] = -tval[2 * i + 1];
}
else{
tempVal[2*j] = tval[2*i];
tempVal[2*j+1]= tval[2*i+1];
else {
tempVal[2 * j] = tval[2 * i];
tempVal[2 * j + 1] = tval[2 * i + 1];
}
}
j++;
}
}
(*nnz)+=count;
//free temporary storage
(*nnz) += count;
// free temporary storage
free(trow);
free(tcol);
free(tval);
free(tval);
}
else{
tempRowInd=trow;
tempColInd=tcol;
tempVal =tval;
else {
tempRowInd = trow;
tempColInd = tcol;
tempVal = tval;
}
// life time of (trow, tcol, tval) is over.
// please use COO format (tempRowInd, tempColInd, tempVal)
// use qsort to sort COO format
work = (struct cooFormat *)malloc(sizeof(struct cooFormat)*(*nnz));
if (NULL == work){
// use qsort to sort COO format
work = (struct cooFormat *)malloc(sizeof(struct cooFormat) * (*nnz));
if (NULL == work) {
fprintf(stderr, "!!!! allocation error, malloc failed\n");
return 1;
}
for(i=0; i<(*nnz); i++){
for (i = 0; i < (*nnz); i++) {
work[i].i = tempRowInd[i];
work[i].j = tempColInd[i];
work[i].p = i; // permutation is identity
}
if (csrFormat){
/* create row-major ordering of indices (sorted by row and within each row by column) */
qsort(work, *nnz, sizeof(struct cooFormat), (FUNPTR)fptr_array[0] );
}else{
/* create column-major ordering of indices (sorted by column and within each column by row) */
qsort(work, *nnz, sizeof(struct cooFormat), (FUNPTR)fptr_array[1] );
if (csrFormat) {
/* create row-major ordering of indices (sorted by row and within each row by column) */
qsort(work, *nnz, sizeof(struct cooFormat), (FUNPTR)fptr_array[0]);
}
else {
/* create column-major ordering of indices (sorted by column and within each column by row) */
qsort(work, *nnz, sizeof(struct cooFormat), (FUNPTR)fptr_array[1]);
}
// (tempRowInd, tempColInd) is sorted either by row-major or by col-major
for(i=0; i<(*nnz); i++){
for (i = 0; i < (*nnz); i++) {
tempRowInd[i] = work[i].i;
tempColInd[i] = work[i].j;
}
// setup base
// setup base
// check if there is any row/col 0, if so base-0
// check if there is any row/col equal to matrix dimension m/n, if so base-1
int base0 = 0;
int base1 = 0;
for(i=0; i<(*nnz); i++){
for (i = 0; i < (*nnz); i++) {
const int row = tempRowInd[i];
const int col = tempColInd[i];
if ( (0 == row) || (0 == col) ){
if ((0 == row) || (0 == col)) {
base0 = 1;
}
if ( (*m == row) || (*n == col) ){
if ((*m == row) || (*n == col)) {
base1 = 1;
}
}
if ( base0 && base1 ){
if (base0 && base1) {
printf("Error: input matrix is base-0 and base-1 \n");
return 1;
}
base = 0;
if (base1){
if (base1) {
base = 1;
}
/* compress the appropriate indices */
if (csrFormat){
if (csrFormat) {
/* CSR format (assuming row-major format) */
csrRowPtr = (int *)malloc(((*m)+1) * sizeof(csrRowPtr[0]));
if (!csrRowPtr) return 1;
csrRowPtr = (int *)malloc(((*m) + 1) * sizeof(csrRowPtr[0]));
if (!csrRowPtr)
return 1;
compress_index(tempRowInd, *nnz, *m, csrRowPtr, base);
*aRowInd = csrRowPtr;
@@ -429,101 +377,97 @@ int loadMMSparseMatrix(
}
else {
/* CSC format (assuming column-major format) */
cscColPtr = (int *)malloc(((*n)+1) * sizeof(cscColPtr[0]));
if (!cscColPtr) return 1;
cscColPtr = (int *)malloc(((*n) + 1) * sizeof(cscColPtr[0]));
if (!cscColPtr)
return 1;
compress_index(tempColInd, *nnz, *n, cscColPtr, base);
*aColInd = cscColPtr;
*aRowInd = (int *)malloc((*nnz) * sizeof(int));
}
}
/* transfrom the matrix values of type double into one of the cusparse library types */
/* transfrom the matrix values of type double into one of the cusparse library types */
*aVal = (T_ELEM *)malloc((*nnz) * sizeof(T_ELEM));
for (i=0; i<(*nnz); i++) {
if (csrFormat){
for (i = 0; i < (*nnz); i++) {
if (csrFormat) {
(*aColInd)[i] = tempColInd[i];
}
else{
else {
(*aRowInd)[i] = tempRowInd[i];
}
if (mm_is_real(matcode) || mm_is_integer(matcode)){
(*aVal)[i] = cuGet<T_ELEM>( tempVal[ work[i].p ] );
if (mm_is_real(matcode) || mm_is_integer(matcode)) {
(*aVal)[i] = cuGet<T_ELEM>(tempVal[work[i].p]);
}
else{
(*aVal)[i] = cuGet<T_ELEM>(tempVal[2*work[i].p], tempVal[2*work[i].p+1]);
else {
(*aVal)[i] = cuGet<T_ELEM>(tempVal[2 * work[i].p], tempVal[2 * work[i].p + 1]);
}
}
/* check for corruption */
int error_found;
if (csrFormat){
if (csrFormat) {
error_found = verify_pattern(*m, *nnz, *aRowInd, *aColInd);
}else{
}
else {
error_found = verify_pattern(*n, *nnz, *aColInd, *aRowInd);
}
if (error_found){
if (error_found) {
fprintf(stderr, "!!!! verify_pattern failed\n");
return 1;
}
/* cleanup and exit */
free(work);
free(tempVal);
free(tempVal);
free(tempColInd);
free(tempRowInd);
return 0;
}
}
/* specific instantiation */
template int loadMMSparseMatrix<float>(
char *filename,
char elem_type,
bool csrFormat,
int *m,
int *n,
int *nnz,
float **aVal,
int **aRowInd,
int **aColInd,
int extendSymMatrix);
template int loadMMSparseMatrix<float>(char *filename,
char elem_type,
bool csrFormat,
int *m,
int *n,
int *nnz,
float **aVal,
int **aRowInd,
int **aColInd,
int extendSymMatrix);
template int loadMMSparseMatrix<double>(
char *filename,
char elem_type,
bool csrFormat,
int *m,
int *n,
int *nnz,
double **aVal,
int **aRowInd,
int **aColInd,
int extendSymMatrix);
template int loadMMSparseMatrix<cuComplex>(
char *filename,
char elem_type,
bool csrFormat,
int *m,
int *n,
int *nnz,
cuComplex **aVal,
int **aRowInd,
int **aColInd,
int extendSymMatrix);
template int loadMMSparseMatrix<cuDoubleComplex>(
char *filename,
char elem_type,
bool csrFormat,
int *m,
int *n,
int *nnz,
cuDoubleComplex **aVal,
int **aRowInd,
int **aColInd,
int extendSymMatrix);
template int loadMMSparseMatrix<double>(char *filename,
char elem_type,
bool csrFormat,
int *m,
int *n,
int *nnz,
double **aVal,
int **aRowInd,
int **aColInd,
int extendSymMatrix);
template int loadMMSparseMatrix<cuComplex>(char *filename,
char elem_type,
bool csrFormat,
int *m,
int *n,
int *nnz,
cuComplex **aVal,
int **aRowInd,
int **aColInd,
int extendSymMatrix);
template int loadMMSparseMatrix<cuDoubleComplex>(char *filename,
char elem_type,
bool csrFormat,
int *m,
int *n,
int *nnz,
cuDoubleComplex **aVal,
int **aRowInd,
int **aColInd,
int extendSymMatrix);

File diff suppressed because it is too large Load Diff

View File

@@ -1,112 +1,107 @@
/*
* Matrix Market I/O library for ANSI C
*
* See http://math.nist.gov/MatrixMarket for details.
*
*
*/
/*
* Matrix Market I/O library for ANSI C
*
* See http://math.nist.gov/MatrixMarket for details.
*
*
*/
/* avoid Windows warnings (for example: strcpy, fscanf, etc.) */
#if defined(_WIN32)
#if defined(_WIN32)
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include "mmio.h"
int mm_read_unsymmetric_sparse(const char *fname, int *M_, int *N_, int *nz_,
double **val_, int **I_, int **J_)
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int mm_read_unsymmetric_sparse(const char *fname, int *M_, int *N_, int *nz_, double **val_, int **I_, int **J_)
{
FILE *f;
FILE *f;
MM_typecode matcode;
int M, N, nz;
int i;
double *val;
int *I, *J;
int M, N, nz;
int i;
double *val;
int *I, *J;
if ((f = fopen(fname, "r")) == NULL)
return -1;
if (mm_read_banner(f, &matcode) != 0)
{
return -1;
if (mm_read_banner(f, &matcode) != 0) {
printf("mm_read_unsymetric: Could not process Matrix Market banner ");
printf(" in file [%s]\n", fname);
return -1;
}
if ( !(mm_is_real(matcode) && mm_is_matrix(matcode) &&
mm_is_sparse(matcode)))
{
if (!(mm_is_real(matcode) && mm_is_matrix(matcode) && mm_is_sparse(matcode))) {
fprintf(stderr, "Sorry, this application does not support ");
fprintf(stderr, "Market Market type: [%s]\n",
mm_typecode_to_str(matcode));
fprintf(stderr, "Market Market type: [%s]\n", mm_typecode_to_str(matcode));
return -1;
}
/* find out size of sparse matrix: M, N, nz .... */
if (mm_read_mtx_crd_size(f, &M, &N, &nz) !=0)
{
if (mm_read_mtx_crd_size(f, &M, &N, &nz) != 0) {
fprintf(stderr, "read_unsymmetric_sparse(): could not parse matrix size.\n");
return -1;
}
*M_ = M;
*N_ = N;
*M_ = M;
*N_ = N;
*nz_ = nz;
/* reserve memory for matrices */
I = (int *) malloc(nz * sizeof(int));
J = (int *) malloc(nz * sizeof(int));
val = (double *) malloc(nz * sizeof(double));
I = (int *)malloc(nz * sizeof(int));
J = (int *)malloc(nz * sizeof(int));
val = (double *)malloc(nz * sizeof(double));
*val_ = val;
*I_ = I;
*J_ = J;
*I_ = I;
*J_ = J;
/* NOTE: when reading in doubles, ANSI C requires the use of the "l" */
/* specifier as in "%lg", "%lf", "%le", otherwise errors will occur */
/* (ANSI C X3.159-1989, Sec. 4.9.6.2, p. 136 lines 13-15) */
for (i=0; i<nz; i++)
{
for (i = 0; i < nz; i++) {
if (fscanf(f, "%d %d %lg\n", &I[i], &J[i], &val[i]) != 3) {
return -1;
}
I[i]--; /* adjust from 1-based to 0-based */
I[i]--; /* adjust from 1-based to 0-based */
J[i]--;
}
fclose(f);
return 0;
}
int mm_is_valid(MM_typecode matcode)
{
if (!mm_is_matrix(matcode)) return 0;
if (mm_is_dense(matcode) && mm_is_pattern(matcode)) return 0;
if (mm_is_real(matcode) && mm_is_hermitian(matcode)) return 0;
if (mm_is_pattern(matcode) && (mm_is_hermitian(matcode) ||
mm_is_skew(matcode))) return 0;
if (!mm_is_matrix(matcode))
return 0;
if (mm_is_dense(matcode) && mm_is_pattern(matcode))
return 0;
if (mm_is_real(matcode) && mm_is_hermitian(matcode))
return 0;
if (mm_is_pattern(matcode) && (mm_is_hermitian(matcode) || mm_is_skew(matcode)))
return 0;
return 1;
}
int mm_read_banner(FILE *f, MM_typecode *matcode)
{
char line[MM_MAX_LINE_LENGTH];
char banner[MM_MAX_TOKEN_LENGTH];
char mtx[MM_MAX_TOKEN_LENGTH];
char crd[MM_MAX_TOKEN_LENGTH];
char data_type[MM_MAX_TOKEN_LENGTH];
char storage_scheme[MM_MAX_TOKEN_LENGTH];
char line[MM_MAX_LINE_LENGTH];
char banner[MM_MAX_TOKEN_LENGTH];
char mtx[MM_MAX_TOKEN_LENGTH];
char crd[MM_MAX_TOKEN_LENGTH];
char data_type[MM_MAX_TOKEN_LENGTH];
char storage_scheme[MM_MAX_TOKEN_LENGTH];
char *p;
@@ -115,14 +110,17 @@ int mm_read_banner(FILE *f, MM_typecode *matcode)
if (fgets(line, MM_MAX_LINE_LENGTH, f) == NULL)
return MM_PREMATURE_EOF;
if (sscanf(line, "%s %s %s %s %s", banner, mtx, crd, data_type,
storage_scheme) != 5)
if (sscanf(line, "%s %s %s %s %s", banner, mtx, crd, data_type, storage_scheme) != 5)
return MM_PREMATURE_EOF;
for (p=mtx; *p!='\0'; *p=tolower(*p),p++); /* convert to lower case */
for (p=crd; *p!='\0'; *p=tolower(*p),p++);
for (p=data_type; *p!='\0'; *p=tolower(*p),p++);
for (p=storage_scheme; *p!='\0'; *p=tolower(*p),p++);
for (p = mtx; *p != '\0'; *p = tolower(*p), p++)
; /* convert to lower case */
for (p = crd; *p != '\0'; *p = tolower(*p), p++)
;
for (p = data_type; *p != '\0'; *p = tolower(*p), p++)
;
for (p = storage_scheme; *p != '\0'; *p = tolower(*p), p++)
;
/* check for banner */
if (strncmp(banner, MatrixMarketBanner, strlen(MatrixMarketBanner)) != 0)
@@ -130,7 +128,7 @@ int mm_read_banner(FILE *f, MM_typecode *matcode)
/* first field should be "mtx" */
if (strcmp(mtx, MM_MTX_STR) != 0)
return MM_UNSUPPORTED_TYPE;
return MM_UNSUPPORTED_TYPE;
mm_set_matrix(matcode);
@@ -140,9 +138,8 @@ int mm_read_banner(FILE *f, MM_typecode *matcode)
if (strcmp(crd, MM_SPARSE_STR) == 0)
mm_set_sparse(matcode);
else
if (strcmp(crd, MM_DENSE_STR) == 0)
mm_set_dense(matcode);
else if (strcmp(crd, MM_DENSE_STR) == 0)
mm_set_dense(matcode);
else
return MM_UNSUPPORTED_TYPE;
@@ -150,14 +147,11 @@ int mm_read_banner(FILE *f, MM_typecode *matcode)
if (strcmp(data_type, MM_REAL_STR) == 0)
mm_set_real(matcode);
else
if (strcmp(data_type, MM_COMPLEX_STR) == 0)
else if (strcmp(data_type, MM_COMPLEX_STR) == 0)
mm_set_complex(matcode);
else
if (strcmp(data_type, MM_PATTERN_STR) == 0)
else if (strcmp(data_type, MM_PATTERN_STR) == 0)
mm_set_pattern(matcode);
else
if (strcmp(data_type, MM_INT_STR) == 0)
else if (strcmp(data_type, MM_INT_STR) == 0)
mm_set_integer(matcode);
else
return MM_UNSUPPORTED_TYPE;
@@ -166,14 +160,11 @@ int mm_read_banner(FILE *f, MM_typecode *matcode)
if (strcmp(storage_scheme, MM_GENERAL_STR) == 0)
mm_set_general(matcode);
else
if (strcmp(storage_scheme, MM_SYMM_STR) == 0)
else if (strcmp(storage_scheme, MM_SYMM_STR) == 0)
mm_set_symmetric(matcode);
else
if (strcmp(storage_scheme, MM_HERM_STR) == 0)
else if (strcmp(storage_scheme, MM_HERM_STR) == 0)
mm_set_hermitian(matcode);
else
if (strcmp(storage_scheme, MM_SKEW_STR) == 0)
else if (strcmp(storage_scheme, MM_SKEW_STR) == 0)
mm_set_skew(matcode);
else
return MM_UNSUPPORTED_TYPE;
@@ -189,32 +180,30 @@ int mm_write_mtx_crd_size(FILE *f, int M, int N, int nz)
return 0;
}
int mm_read_mtx_crd_size(FILE *f, int *M, int *N, int *nz )
int mm_read_mtx_crd_size(FILE *f, int *M, int *N, int *nz)
{
char line[MM_MAX_LINE_LENGTH];
int num_items_read;
int num_items_read;
/* set return null parameter values, in case we exit with errors */
*M = *N = *nz = 0;
/* now continue scanning until you reach the end-of-comments */
do
{
if (fgets(line,MM_MAX_LINE_LENGTH,f) == NULL)
do {
if (fgets(line, MM_MAX_LINE_LENGTH, f) == NULL)
return MM_PREMATURE_EOF;
}while (line[0] == '%');
} while (line[0] == '%');
/* line[] is either blank or has M,N, nz */
if (sscanf(line, "%d %d %d", M, N, nz) == 3)
return 0;
else
do
{
num_items_read = fscanf(f, "%d %d %d", M, N, nz);
if (num_items_read == EOF) return MM_PREMATURE_EOF;
}
while (num_items_read != 3);
do {
num_items_read = fscanf(f, "%d %d %d", M, N, nz);
if (num_items_read == EOF)
return MM_PREMATURE_EOF;
} while (num_items_read != 3);
return 0;
}
@@ -223,28 +212,26 @@ int mm_read_mtx_crd_size(FILE *f, int *M, int *N, int *nz )
int mm_read_mtx_array_size(FILE *f, int *M, int *N)
{
char line[MM_MAX_LINE_LENGTH];
int num_items_read;
int num_items_read;
/* set return null parameter values, in case we exit with errors */
*M = *N = 0;
/* now continue scanning until you reach the end-of-comments */
do
{
if (fgets(line,MM_MAX_LINE_LENGTH,f) == NULL)
do {
if (fgets(line, MM_MAX_LINE_LENGTH, f) == NULL)
return MM_PREMATURE_EOF;
}while (line[0] == '%');
} while (line[0] == '%');
/* line[] is either blank or has M,N, nz */
if (sscanf(line, "%d %d", M, N) == 2)
return 0;
else /* we have a blank line */
do
{
num_items_read = fscanf(f, "%d %d", M, N);
if (num_items_read == EOF) return MM_PREMATURE_EOF;
}
while (num_items_read != 2);
do {
num_items_read = fscanf(f, "%d %d", M, N);
if (num_items_read == EOF)
return MM_PREMATURE_EOF;
} while (num_items_read != 2);
return 0;
}
@@ -258,38 +245,31 @@ int mm_write_mtx_array_size(FILE *f, int M, int N)
}
/*-------------------------------------------------------------------------*/
/******************************************************************/
/* use when I[], J[], and val[]J, and val[] are already allocated */
/******************************************************************/
int mm_read_mtx_crd_data(FILE *f, int M, int N, int nz, int I[], int J[],
double val[], MM_typecode matcode)
int mm_read_mtx_crd_data(FILE *f, int M, int N, int nz, int I[], int J[], double val[], MM_typecode matcode)
{
int i;
if (mm_is_complex(matcode))
{
for (i=0; i<nz; i++)
if (fscanf(f, "%d %d %lg %lg", &I[i], &J[i], &val[2*i], &val[2*i+1])
!= 4) return MM_PREMATURE_EOF;
if (mm_is_complex(matcode)) {
for (i = 0; i < nz; i++)
if (fscanf(f, "%d %d %lg %lg", &I[i], &J[i], &val[2 * i], &val[2 * i + 1]) != 4)
return MM_PREMATURE_EOF;
}
else if (mm_is_real(matcode) || mm_is_integer(matcode))
{
for (i=0; i<nz; i++)
{
if (fscanf(f, "%d %d %lg\n", &I[i], &J[i], &val[i])
!= 3) return MM_PREMATURE_EOF;
else if (mm_is_real(matcode) || mm_is_integer(matcode)) {
for (i = 0; i < nz; i++) {
if (fscanf(f, "%d %d %lg\n", &I[i], &J[i], &val[i]) != 3)
return MM_PREMATURE_EOF;
}
}
else if (mm_is_pattern(matcode))
{
for (i=0; i<nz; i++)
if (fscanf(f, "%d %d", &I[i], &J[i])
!= 2) return MM_PREMATURE_EOF;
else if (mm_is_pattern(matcode)) {
for (i = 0; i < nz; i++)
if (fscanf(f, "%d %d", &I[i], &J[i]) != 2)
return MM_PREMATURE_EOF;
}
else
return MM_UNSUPPORTED_TYPE;
@@ -297,24 +277,20 @@ int mm_read_mtx_crd_data(FILE *f, int M, int N, int nz, int I[], int J[],
return 0;
}
int mm_read_mtx_crd_entry(FILE *f, int *I, int *J,
double *real, double *imag, MM_typecode matcode)
int mm_read_mtx_crd_entry(FILE *f, int *I, int *J, double *real, double *imag, MM_typecode matcode)
{
if (mm_is_complex(matcode))
{
if (fscanf(f, "%d %d %lg %lg", I, J, real, imag)
!= 4) return MM_PREMATURE_EOF;
if (mm_is_complex(matcode)) {
if (fscanf(f, "%d %d %lg %lg", I, J, real, imag) != 4)
return MM_PREMATURE_EOF;
}
else if (mm_is_real(matcode) || mm_is_integer(matcode))
{
if (fscanf(f, "%d %d %lg\n", I, J, real)
!= 3) return MM_PREMATURE_EOF;
else if (mm_is_real(matcode) || mm_is_integer(matcode)) {
if (fscanf(f, "%d %d %lg\n", I, J, real) != 3)
return MM_PREMATURE_EOF;
}
else if (mm_is_pattern(matcode))
{
if (fscanf(f, "%d %d", I, J) != 2) return MM_PREMATURE_EOF;
else if (mm_is_pattern(matcode)) {
if (fscanf(f, "%d %d", I, J) != 2)
return MM_PREMATURE_EOF;
}
else
return MM_UNSUPPORTED_TYPE;
@@ -331,82 +307,76 @@ int mm_read_mtx_crd_entry(FILE *f, int *I, int *J,
(nz pairs of real/imaginary values)
************************************************************************/
int mm_read_mtx_crd(char *fname, int *M, int *N, int *nz, int **I, int **J,
double **val, MM_typecode *matcode)
int mm_read_mtx_crd(char *fname, int *M, int *N, int *nz, int **I, int **J, double **val, MM_typecode *matcode)
{
int ret_code;
int ret_code;
FILE *f;
if (strcmp(fname, "stdin") == 0) f=stdin;
else
if ((f = fopen(fname, "r")) == NULL)
if (strcmp(fname, "stdin") == 0)
f = stdin;
else if ((f = fopen(fname, "r")) == NULL)
return MM_COULD_NOT_READ_FILE;
if ((ret_code = mm_read_banner(f, matcode)) != 0)
return ret_code;
if (!(mm_is_valid(*matcode) && mm_is_sparse(*matcode) &&
mm_is_matrix(*matcode)))
if (!(mm_is_valid(*matcode) && mm_is_sparse(*matcode) && mm_is_matrix(*matcode)))
return MM_UNSUPPORTED_TYPE;
if ((ret_code = mm_read_mtx_crd_size(f, M, N, nz)) != 0)
return ret_code;
*I = (int *) malloc(*nz * sizeof(int));
*J = (int *) malloc(*nz * sizeof(int));
*I = (int *)malloc(*nz * sizeof(int));
*J = (int *)malloc(*nz * sizeof(int));
*val = NULL;
if (mm_is_complex(*matcode))
{
*val = (double *) malloc(*nz * 2 * sizeof(double));
ret_code = mm_read_mtx_crd_data(f, *M, *N, *nz, *I, *J, *val,
*matcode);
if (ret_code != 0) return ret_code;
if (mm_is_complex(*matcode)) {
*val = (double *)malloc(*nz * 2 * sizeof(double));
ret_code = mm_read_mtx_crd_data(f, *M, *N, *nz, *I, *J, *val, *matcode);
if (ret_code != 0)
return ret_code;
}
else if (mm_is_real(*matcode) || mm_is_integer(*matcode))
{
*val = (double *) malloc(*nz * sizeof(double));
ret_code = mm_read_mtx_crd_data(f, *M, *N, *nz, *I, *J, *val,
*matcode);
if (ret_code != 0) return ret_code;
else if (mm_is_real(*matcode) || mm_is_integer(*matcode)) {
*val = (double *)malloc(*nz * sizeof(double));
ret_code = mm_read_mtx_crd_data(f, *M, *N, *nz, *I, *J, *val, *matcode);
if (ret_code != 0)
return ret_code;
}
else if (mm_is_pattern(*matcode))
{
ret_code = mm_read_mtx_crd_data(f, *M, *N, *nz, *I, *J, *val,
*matcode);
if (ret_code != 0) return ret_code;
else if (mm_is_pattern(*matcode)) {
ret_code = mm_read_mtx_crd_data(f, *M, *N, *nz, *I, *J, *val, *matcode);
if (ret_code != 0)
return ret_code;
}
if (f != stdin) fclose(f);
if (f != stdin)
fclose(f);
return 0;
}
int mm_write_banner(FILE *f, MM_typecode matcode)
{
char *str = mm_typecode_to_str(matcode);
int ret_code;
int ret_code;
ret_code = fprintf(f, "%s %s\n", MatrixMarketBanner, str);
free(str);
if (ret_code !=2 )
if (ret_code != 2)
return MM_COULD_NOT_WRITE_FILE;
else
return 0;
}
int mm_write_mtx_crd(char fname[], int M, int N, int nz, int I[], int J[],
double val[], MM_typecode matcode)
int mm_write_mtx_crd(char fname[], int M, int N, int nz, int I[], int J[], double val[], MM_typecode matcode)
{
FILE *f;
int i;
int i;
if (strcmp(fname, "stdout") == 0)
f = stdout;
else
if ((f = fopen(fname, "w")) == NULL)
else if ((f = fopen(fname, "w")) == NULL)
return MM_COULD_NOT_WRITE_FILE;
/* print banner followed by typecode */
@@ -418,53 +388,50 @@ int mm_write_mtx_crd(char fname[], int M, int N, int nz, int I[], int J[],
/* print values */
if (mm_is_pattern(matcode))
for (i=0; i<nz; i++)
for (i = 0; i < nz; i++)
fprintf(f, "%d %d\n", I[i], J[i]);
else
if (mm_is_integer(matcode))
for (i=0; i<nz; i++)
else if (mm_is_integer(matcode))
for (i = 0; i < nz; i++)
fprintf(f, "%d %d %d\n", I[i], J[i], (int)val[i]);
else
if (mm_is_real(matcode))
for (i=0; i<nz; i++)
else if (mm_is_real(matcode))
for (i = 0; i < nz; i++)
fprintf(f, "%d %d %20.16g\n", I[i], J[i], val[i]);
else
if (mm_is_complex(matcode))
for (i=0; i<nz; i++)
fprintf(f, "%d %d %20.16g %20.16g\n", I[i], J[i], val[2*i],
val[2*i+1]);
else
{
if (f != stdout) fclose(f);
else if (mm_is_complex(matcode))
for (i = 0; i < nz; i++)
fprintf(f, "%d %d %20.16g %20.16g\n", I[i], J[i], val[2 * i], val[2 * i + 1]);
else {
if (f != stdout)
fclose(f);
return MM_UNSUPPORTED_TYPE;
}
if (f !=stdout) fclose(f);
if (f != stdout)
fclose(f);
return 0;
}
/**
* Create a new copy of a string s. mm_strdup() is a common routine, but
* not part of ANSI C, so it is included here. Used by mm_typecode_to_str().
*
*/
* Create a new copy of a string s. mm_strdup() is a common routine, but
* not part of ANSI C, so it is included here. Used by mm_typecode_to_str().
*
*/
static char *mm_strdup(const char *s)
{
size_t len = strlen(s);
char *s2 = (char *) malloc((len+1)*sizeof(char));
char *s2 = (char *)malloc((len + 1) * sizeof(char));
return strcpy(s2, s);
}
char *mm_typecode_to_str(MM_typecode matcode)
char *mm_typecode_to_str(MM_typecode matcode)
{
char buffer[MM_MAX_LINE_LENGTH];
char buffer[MM_MAX_LINE_LENGTH];
char *types[4];
//char *mm_strdup(const char *);
//int error =0;
// char *mm_strdup(const char *);
// int error =0;
/* check for MTX type */
if (mm_is_matrix(matcode))
if (mm_is_matrix(matcode))
types[0] = MM_MTX_STR;
else
return NULL; // error=1;
@@ -472,8 +439,7 @@ char *mm_typecode_to_str(MM_typecode matcode)
/* check for CRD or ARR matrix */
if (mm_is_sparse(matcode))
types[1] = MM_SPARSE_STR;
else
if (mm_is_dense(matcode))
else if (mm_is_dense(matcode))
types[1] = MM_DENSE_STR;
else
return NULL;
@@ -481,14 +447,11 @@ char *mm_typecode_to_str(MM_typecode matcode)
/* check for element data type */
if (mm_is_real(matcode))
types[2] = MM_REAL_STR;
else
if (mm_is_complex(matcode))
else if (mm_is_complex(matcode))
types[2] = MM_COMPLEX_STR;
else
if (mm_is_pattern(matcode))
else if (mm_is_pattern(matcode))
types[2] = MM_PATTERN_STR;
else
if (mm_is_integer(matcode))
else if (mm_is_integer(matcode))
types[2] = MM_INT_STR;
else
return NULL;
@@ -497,19 +460,15 @@ char *mm_typecode_to_str(MM_typecode matcode)
/* check for symmetry type */
if (mm_is_general(matcode))
types[3] = MM_GENERAL_STR;
else
if (mm_is_symmetric(matcode))
else if (mm_is_symmetric(matcode))
types[3] = MM_SYMM_STR;
else
if (mm_is_hermitian(matcode))
else if (mm_is_hermitian(matcode))
types[3] = MM_HERM_STR;
else
if (mm_is_skew(matcode))
else if (mm_is_skew(matcode))
types[3] = MM_SKEW_STR;
else
return NULL;
sprintf(buffer,"%s %s %s %s", types[0], types[1], types[2], types[3]);
sprintf(buffer, "%s %s %s %s", types[0], types[1], types[2], types[3]);
return mm_strdup(buffer);
}

View File

@@ -1,141 +1,138 @@
/*
* Matrix Market I/O library for ANSI C
*
* See http://math.nist.gov/MatrixMarket for details.
*
*
*/
/*
* Matrix Market I/O library for ANSI C
*
* See http://math.nist.gov/MatrixMarket for details.
*
*
*/
#ifndef MM_IO_H
#define MM_IO_H
#include <stdio.h>
#if defined(__cplusplus)
extern "C" {
extern "C"
{
#endif /* __cplusplus */
#define MM_MAX_LINE_LENGTH 1025
#define MatrixMarketBanner "%%MatrixMarket"
#define MM_MAX_LINE_LENGTH 1025
#define MatrixMarketBanner "%%MatrixMarket"
#define MM_MAX_TOKEN_LENGTH 64
typedef char MM_typecode[4];
typedef char MM_typecode[4];
char *mm_typecode_to_str(MM_typecode matcode);
char *mm_typecode_to_str(MM_typecode matcode);
int mm_read_banner(FILE *f, MM_typecode *matcode);
int mm_read_mtx_crd_size(FILE *f, int *M, int *N, int *nz);
int mm_read_mtx_array_size(FILE *f, int *M, int *N);
int mm_read_banner(FILE *f, MM_typecode *matcode);
int mm_read_mtx_crd_size(FILE *f, int *M, int *N, int *nz);
int mm_read_mtx_array_size(FILE *f, int *M, int *N);
int mm_write_banner(FILE *f, MM_typecode matcode);
int mm_write_mtx_crd_size(FILE *f, int M, int N, int nz);
int mm_write_mtx_array_size(FILE *f, int M, int N);
int mm_write_banner(FILE *f, MM_typecode matcode);
int mm_write_mtx_crd_size(FILE *f, int M, int N, int nz);
int mm_write_mtx_array_size(FILE *f, int M, int N);
/********************* MM_typecode query fucntions ***************************/
/********************* MM_typecode query fucntions ***************************/
#define mm_is_matrix(typecode) ((typecode)[0]=='M')
#define mm_is_matrix(typecode) ((typecode)[0] == 'M')
#define mm_is_sparse(typecode) ((typecode)[1]=='C')
#define mm_is_coordinate(typecode)((typecode)[1]=='C')
#define mm_is_dense(typecode) ((typecode)[1]=='A')
#define mm_is_array(typecode) ((typecode)[1]=='A')
#define mm_is_sparse(typecode) ((typecode)[1] == 'C')
#define mm_is_coordinate(typecode) ((typecode)[1] == 'C')
#define mm_is_dense(typecode) ((typecode)[1] == 'A')
#define mm_is_array(typecode) ((typecode)[1] == 'A')
#define mm_is_complex(typecode) ((typecode)[2]=='C')
#define mm_is_real(typecode) ((typecode)[2]=='R')
#define mm_is_pattern(typecode) ((typecode)[2]=='P')
#define mm_is_integer(typecode) ((typecode)[2]=='I')
#define mm_is_complex(typecode) ((typecode)[2] == 'C')
#define mm_is_real(typecode) ((typecode)[2] == 'R')
#define mm_is_pattern(typecode) ((typecode)[2] == 'P')
#define mm_is_integer(typecode) ((typecode)[2] == 'I')
#define mm_is_symmetric(typecode)((typecode)[3]=='S')
#define mm_is_general(typecode) ((typecode)[3]=='G')
#define mm_is_skew(typecode) ((typecode)[3]=='K')
#define mm_is_hermitian(typecode)((typecode)[3]=='H')
#define mm_is_symmetric(typecode) ((typecode)[3] == 'S')
#define mm_is_general(typecode) ((typecode)[3] == 'G')
#define mm_is_skew(typecode) ((typecode)[3] == 'K')
#define mm_is_hermitian(typecode) ((typecode)[3] == 'H')
int mm_is_valid(MM_typecode matcode); /* too complex for a macro */
int mm_is_valid(MM_typecode matcode); /* too complex for a macro */
/********************* MM_typecode modify fucntions ***************************/
/********************* MM_typecode modify fucntions ***************************/
#define mm_set_matrix(typecode) ((*typecode)[0]='M')
#define mm_set_coordinate(typecode) ((*typecode)[1]='C')
#define mm_set_array(typecode) ((*typecode)[1]='A')
#define mm_set_dense(typecode) mm_set_array(typecode)
#define mm_set_sparse(typecode) mm_set_coordinate(typecode)
#define mm_set_matrix(typecode) ((*typecode)[0] = 'M')
#define mm_set_coordinate(typecode) ((*typecode)[1] = 'C')
#define mm_set_array(typecode) ((*typecode)[1] = 'A')
#define mm_set_dense(typecode) mm_set_array(typecode)
#define mm_set_sparse(typecode) mm_set_coordinate(typecode)
#define mm_set_complex(typecode)((*typecode)[2]='C')
#define mm_set_real(typecode) ((*typecode)[2]='R')
#define mm_set_pattern(typecode)((*typecode)[2]='P')
#define mm_set_integer(typecode)((*typecode)[2]='I')
#define mm_set_complex(typecode) ((*typecode)[2] = 'C')
#define mm_set_real(typecode) ((*typecode)[2] = 'R')
#define mm_set_pattern(typecode) ((*typecode)[2] = 'P')
#define mm_set_integer(typecode) ((*typecode)[2] = 'I')
#define mm_set_symmetric(typecode)((*typecode)[3]='S')
#define mm_set_general(typecode)((*typecode)[3]='G')
#define mm_set_skew(typecode) ((*typecode)[3]='K')
#define mm_set_hermitian(typecode)((*typecode)[3]='H')
#define mm_set_symmetric(typecode) ((*typecode)[3] = 'S')
#define mm_set_general(typecode) ((*typecode)[3] = 'G')
#define mm_set_skew(typecode) ((*typecode)[3] = 'K')
#define mm_set_hermitian(typecode) ((*typecode)[3] = 'H')
#define mm_clear_typecode(typecode) ((*typecode)[0]=(*typecode)[1]= \
(*typecode)[2]=' ',(*typecode)[3]='G')
#define mm_clear_typecode(typecode) ((*typecode)[0] = (*typecode)[1] = (*typecode)[2] = ' ', (*typecode)[3] = 'G')
#define mm_initialize_typecode(typecode) mm_clear_typecode(typecode)
/********************* Matrix Market error codes ***************************/
/********************* Matrix Market error codes ***************************/
#define MM_COULD_NOT_READ_FILE 11
#define MM_PREMATURE_EOF 12
#define MM_NOT_MTX 13
#define MM_NO_HEADER 14
#define MM_UNSUPPORTED_TYPE 15
#define MM_LINE_TOO_LONG 16
#define MM_COULD_NOT_WRITE_FILE 17
#define MM_COULD_NOT_READ_FILE 11
#define MM_PREMATURE_EOF 12
#define MM_NOT_MTX 13
#define MM_NO_HEADER 14
#define MM_UNSUPPORTED_TYPE 15
#define MM_LINE_TOO_LONG 16
#define MM_COULD_NOT_WRITE_FILE 17
/******************** Matrix Market internal definitions ********************
/******************** Matrix Market internal definitions ********************
MM_matrix_typecode: 4-character sequence
MM_matrix_typecode: 4-character sequence
ojbect sparse/ data storage
dense type scheme
ojbect sparse/ data storage
dense type scheme
string position: [0] [1] [2] [3]
string position: [0] [1] [2] [3]
Matrix typecode: M(atrix) C(oord) R(eal) G(eneral)
A(array) C(omplex) H(ermitian)
P(attern) S(ymmetric)
I(nteger) K(kew)
Matrix typecode: M(atrix) C(oord) R(eal) G(eneral)
A(array) C(omplex) H(ermitian)
P(attern) S(ymmetric)
I(nteger) K(kew)
***********************************************************************/
***********************************************************************/
#define MM_MTX_STR "matrix"
#define MM_ARRAY_STR "array"
#define MM_DENSE_STR "array"
#define MM_COORDINATE_STR "coordinate"
#define MM_SPARSE_STR "coordinate"
#define MM_COMPLEX_STR "complex"
#define MM_REAL_STR "real"
#define MM_INT_STR "integer"
#define MM_GENERAL_STR "general"
#define MM_SYMM_STR "symmetric"
#define MM_HERM_STR "hermitian"
#define MM_SKEW_STR "skew-symmetric"
#define MM_PATTERN_STR "pattern"
#define MM_MTX_STR "matrix"
#define MM_ARRAY_STR "array"
#define MM_DENSE_STR "array"
#define MM_COORDINATE_STR "coordinate"
#define MM_SPARSE_STR "coordinate"
#define MM_COMPLEX_STR "complex"
#define MM_REAL_STR "real"
#define MM_INT_STR "integer"
#define MM_GENERAL_STR "general"
#define MM_SYMM_STR "symmetric"
#define MM_HERM_STR "hermitian"
#define MM_SKEW_STR "skew-symmetric"
#define MM_PATTERN_STR "pattern"
/* high level routines */
int mm_read_mtx_crd(char *fname, int *M, int *N, int *nz, int **I, int **J,
double **val, MM_typecode *matcode);
/* high level routines */
int mm_read_mtx_crd(char *fname, int *M, int *N, int *nz, int **I, int **J, double **val, MM_typecode *matcode);
int mm_write_mtx_crd(char fname[], int M, int N, int nz, int I[], int J[],
double val[], MM_typecode matcode);
int mm_read_mtx_crd_data(FILE *f, int M, int N, int nz, int I[], int J[],
double val[], MM_typecode matcode);
int mm_read_mtx_crd_entry(FILE *f, int *I, int *J, double *real, double *img,
MM_typecode matcode);
int mm_write_mtx_crd(char fname[], int M, int N, int nz, int I[], int J[], double val[], MM_typecode matcode);
int mm_read_mtx_crd_data(FILE *f, int M, int N, int nz, int I[], int J[], double val[], MM_typecode matcode);
int mm_read_mtx_crd_entry(FILE *f, int *I, int *J, double *real, double *img, MM_typecode matcode);
int mm_read_unsymmetric_sparse(const char *fname, int *M_, int *N_, int *nz_,
double **val_, int **I_, int **J_);
int mm_read_unsymmetric_sparse(const char *fname, int *M_, int *N_, int *nz_, double **val_, int **I_, int **J_);
#if defined(__cplusplus)
}
#endif /* __cplusplus */
#endif /* __cplusplus */
#endif

View File

@@ -38,180 +38,125 @@
#endif
/* various __inline__ __device__ function to initialize a T_ELEM */
template <typename T_ELEM>
__inline__ T_ELEM cuGet(int);
template <>
__inline__ float cuGet<float>(int x) {
return float(x);
template <typename T_ELEM> __inline__ T_ELEM cuGet(int);
template <> __inline__ float cuGet<float>(int x) { return float(x); }
template <> __inline__ double cuGet<double>(int x) { return double(x); }
template <> __inline__ cuComplex cuGet<cuComplex>(int x) { return (make_cuComplex(float(x), 0.0f)); }
template <> __inline__ cuDoubleComplex cuGet<cuDoubleComplex>(int x) { return (make_cuDoubleComplex(double(x), 0.0)); }
template <typename T_ELEM> __inline__ T_ELEM cuGet(int, int);
template <> __inline__ float cuGet<float>(int x, int y) { return float(x); }
template <> __inline__ double cuGet<double>(int x, int y) { return double(x); }
template <> __inline__ cuComplex cuGet<cuComplex>(int x, int y) { return make_cuComplex(float(x), float(y)); }
template <> __inline__ cuDoubleComplex cuGet<cuDoubleComplex>(int x, int y)
{
return (make_cuDoubleComplex(double(x), double(y)));
}
template <>
__inline__ double cuGet<double>(int x) {
return double(x);
template <typename T_ELEM> __inline__ T_ELEM cuGet(float);
template <> __inline__ float cuGet<float>(float x) { return float(x); }
template <> __inline__ double cuGet<double>(float x) { return double(x); }
template <> __inline__ cuComplex cuGet<cuComplex>(float x) { return (make_cuComplex(float(x), 0.0f)); }
template <> __inline__ cuDoubleComplex cuGet<cuDoubleComplex>(float x)
{
return (make_cuDoubleComplex(double(x), 0.0));
}
template <>
__inline__ cuComplex cuGet<cuComplex>(int x) {
return (make_cuComplex(float(x), 0.0f));
template <typename T_ELEM> __inline__ T_ELEM cuGet(float, float);
template <> __inline__ float cuGet<float>(float x, float y) { return float(x); }
template <> __inline__ double cuGet<double>(float x, float y) { return double(x); }
template <> __inline__ cuComplex cuGet<cuComplex>(float x, float y) { return (make_cuComplex(float(x), float(y))); }
template <> __inline__ cuDoubleComplex cuGet<cuDoubleComplex>(float x, float y)
{
return (make_cuDoubleComplex(double(x), double(y)));
}
template <>
__inline__ cuDoubleComplex cuGet<cuDoubleComplex>(int x) {
return (make_cuDoubleComplex(double(x), 0.0));
template <typename T_ELEM> __inline__ T_ELEM cuGet(double);
template <> __inline__ float cuGet<float>(double x) { return float(x); }
template <> __inline__ double cuGet<double>(double x) { return double(x); }
template <> __inline__ cuComplex cuGet<cuComplex>(double x) { return (make_cuComplex(float(x), 0.0f)); }
template <> __inline__ cuDoubleComplex cuGet<cuDoubleComplex>(double x)
{
return (make_cuDoubleComplex(double(x), 0.0));
}
template <typename T_ELEM>
__inline__ T_ELEM cuGet(int, int);
template <>
__inline__ float cuGet<float>(int x, int y) {
return float(x);
template <typename T_ELEM> __inline__ T_ELEM cuGet(double, double);
template <> __inline__ float cuGet<float>(double x, double y) { return float(x); }
template <> __inline__ double cuGet<double>(double x, double y) { return double(x); }
template <> __inline__ cuComplex cuGet<cuComplex>(double x, double y) { return (make_cuComplex(float(x), float(y))); }
template <> __inline__ cuDoubleComplex cuGet<cuDoubleComplex>(double x, double y)
{
return (make_cuDoubleComplex(double(x), double(y)));
}
template <>
__inline__ double cuGet<double>(int x, int y) {
return double(x);
static void compress_index(const int *Ind, int nnz, int m, int *Ptr, int base)
{
int i;
/* initialize everything to zero */
for (i = 0; i < m + 1; i++) {
Ptr[i] = 0;
}
/* count elements in every row */
Ptr[0] = base;
for (i = 0; i < nnz; i++) {
Ptr[Ind[i] + (1 - base)]++;
}
/* add all the values */
for (i = 0; i < m; i++) {
Ptr[i + 1] += Ptr[i];
}
}
template <>
__inline__ cuComplex cuGet<cuComplex>(int x, int y) {
return make_cuComplex(float(x), float(y));
}
template <>
__inline__ cuDoubleComplex cuGet<cuDoubleComplex>(int x, int y) {
return (make_cuDoubleComplex(double(x), double(y)));
}
template <typename T_ELEM>
__inline__ T_ELEM cuGet(float);
template <>
__inline__ float cuGet<float>(float x) {
return float(x);
}
template <>
__inline__ double cuGet<double>(float x) {
return double(x);
}
template <>
__inline__ cuComplex cuGet<cuComplex>(float x) {
return (make_cuComplex(float(x), 0.0f));
}
template <>
__inline__ cuDoubleComplex cuGet<cuDoubleComplex>(float x) {
return (make_cuDoubleComplex(double(x), 0.0));
}
template <typename T_ELEM>
__inline__ T_ELEM cuGet(float, float);
template <>
__inline__ float cuGet<float>(float x, float y) {
return float(x);
}
template <>
__inline__ double cuGet<double>(float x, float y) {
return double(x);
}
template <>
__inline__ cuComplex cuGet<cuComplex>(float x, float y) {
return (make_cuComplex(float(x), float(y)));
}
template <>
__inline__ cuDoubleComplex cuGet<cuDoubleComplex>(float x, float y) {
return (make_cuDoubleComplex(double(x), double(y)));
}
template <typename T_ELEM>
__inline__ T_ELEM cuGet(double);
template <>
__inline__ float cuGet<float>(double x) {
return float(x);
}
template <>
__inline__ double cuGet<double>(double x) {
return double(x);
}
template <>
__inline__ cuComplex cuGet<cuComplex>(double x) {
return (make_cuComplex(float(x), 0.0f));
}
template <>
__inline__ cuDoubleComplex cuGet<cuDoubleComplex>(double x) {
return (make_cuDoubleComplex(double(x), 0.0));
}
template <typename T_ELEM>
__inline__ T_ELEM cuGet(double, double);
template <>
__inline__ float cuGet<float>(double x, double y) {
return float(x);
}
template <>
__inline__ double cuGet<double>(double x, double y) {
return double(x);
}
template <>
__inline__ cuComplex cuGet<cuComplex>(double x, double y) {
return (make_cuComplex(float(x), float(y)));
}
template <>
__inline__ cuDoubleComplex cuGet<cuDoubleComplex>(double x, double y) {
return (make_cuDoubleComplex(double(x), double(y)));
}
static void compress_index(const int *Ind, int nnz, int m, int *Ptr, int base) {
int i;
/* initialize everything to zero */
for (i = 0; i < m + 1; i++) {
Ptr[i] = 0;
}
/* count elements in every row */
Ptr[0] = base;
for (i = 0; i < nnz; i++) {
Ptr[Ind[i] + (1 - base)]++;
}
/* add all the values */
for (i = 0; i < m; i++) {
Ptr[i + 1] += Ptr[i];
}
}
struct cooFormat {
int i;
int j;
int p; // permutation
struct cooFormat
{
int i;
int j;
int p; // permutation
};
int cmp_cooFormat_csr(struct cooFormat *s, struct cooFormat *t) {
if (s->i < t->i) {
return -1;
} else if (s->i > t->i) {
return 1;
} else {
return s->j - t->j;
}
int cmp_cooFormat_csr(struct cooFormat *s, struct cooFormat *t)
{
if (s->i < t->i) {
return -1;
}
else if (s->i > t->i) {
return 1;
}
else {
return s->j - t->j;
}
}
int cmp_cooFormat_csc(struct cooFormat *s, struct cooFormat *t) {
if (s->j < t->j) {
return -1;
} else if (s->j > t->j) {
return 1;
} else {
return s->i - t->i;
}
int cmp_cooFormat_csc(struct cooFormat *s, struct cooFormat *t)
{
if (s->j < t->j) {
return -1;
}
else if (s->j > t->j) {
return 1;
}
else {
return s->i - t->i;
}
}
typedef int (*FUNPTR)(const void *, const void *);
@@ -222,280 +167,326 @@ static FUNPTR2 fptr_array[2] = {
cmp_cooFormat_csc,
};
static int verify_pattern(int m, int nnz, int *csrRowPtr, int *csrColInd) {
int i, col, start, end, base_index;
int error_found = 0;
static int verify_pattern(int m, int nnz, int *csrRowPtr, int *csrColInd)
{
int i, col, start, end, base_index;
int error_found = 0;
if (nnz != (csrRowPtr[m] - csrRowPtr[0])) {
fprintf(stderr,
"Error (nnz check failed): (csrRowPtr[%d]=%d - csrRowPtr[%d]=%d) "
"!= (nnz=%d)\n",
0, csrRowPtr[0], m, csrRowPtr[m], nnz);
error_found = 1;
}
base_index = csrRowPtr[0];
if ((0 != base_index) && (1 != base_index)) {
fprintf(stderr, "Error (base index check failed): base index = %d\n",
base_index);
error_found = 1;
}
for (i = 0; (!error_found) && (i < m); i++) {
start = csrRowPtr[i] - base_index;
end = csrRowPtr[i + 1] - base_index;
if (start > end) {
fprintf(
stderr,
"Error (corrupted row): csrRowPtr[%d] (=%d) > csrRowPtr[%d] (=%d)\n",
i, start + base_index, i + 1, end + base_index);
error_found = 1;
}
for (col = start; col < end; col++) {
if (csrColInd[col] < base_index) {
fprintf(
stderr,
"Error (column vs. base index check failed): csrColInd[%d] < %d\n",
col, base_index);
error_found = 1;
}
if ((col < (end - 1)) && (csrColInd[col] >= csrColInd[col + 1])) {
if (nnz != (csrRowPtr[m] - csrRowPtr[0])) {
fprintf(stderr,
"Error (sorting of the column indecis check failed): "
"(csrColInd[%d]=%d) >= (csrColInd[%d]=%d)\n",
col, csrColInd[col], col + 1, csrColInd[col + 1]);
"Error (nnz check failed): (csrRowPtr[%d]=%d - csrRowPtr[%d]=%d) "
"!= (nnz=%d)\n",
0,
csrRowPtr[0],
m,
csrRowPtr[m],
nnz);
error_found = 1;
}
}
}
return error_found;
base_index = csrRowPtr[0];
if ((0 != base_index) && (1 != base_index)) {
fprintf(stderr, "Error (base index check failed): base index = %d\n", base_index);
error_found = 1;
}
for (i = 0; (!error_found) && (i < m); i++) {
start = csrRowPtr[i] - base_index;
end = csrRowPtr[i + 1] - base_index;
if (start > end) {
fprintf(stderr,
"Error (corrupted row): csrRowPtr[%d] (=%d) > csrRowPtr[%d] (=%d)\n",
i,
start + base_index,
i + 1,
end + base_index);
error_found = 1;
}
for (col = start; col < end; col++) {
if (csrColInd[col] < base_index) {
fprintf(stderr, "Error (column vs. base index check failed): csrColInd[%d] < %d\n", col, base_index);
error_found = 1;
}
if ((col < (end - 1)) && (csrColInd[col] >= csrColInd[col + 1])) {
fprintf(stderr,
"Error (sorting of the column indecis check failed): "
"(csrColInd[%d]=%d) >= (csrColInd[%d]=%d)\n",
col,
csrColInd[col],
col + 1,
csrColInd[col + 1]);
error_found = 1;
}
}
}
return error_found;
}
template <typename T_ELEM>
int loadMMSparseMatrix(char *filename, char elem_type, bool csrFormat, int *m,
int *n, int *nnz, T_ELEM **aVal, int **aRowInd,
int **aColInd, int extendSymMatrix) {
MM_typecode matcode;
double *tempVal;
int *tempRowInd, *tempColInd;
double *tval;
int *trow, *tcol;
int *csrRowPtr, *cscColPtr;
int i, j, error, base, count;
struct cooFormat *work;
int loadMMSparseMatrix(char *filename,
char elem_type,
bool csrFormat,
int *m,
int *n,
int *nnz,
T_ELEM **aVal,
int **aRowInd,
int **aColInd,
int extendSymMatrix)
{
MM_typecode matcode;
double *tempVal;
int *tempRowInd, *tempColInd;
double *tval;
int *trow, *tcol;
int *csrRowPtr, *cscColPtr;
int i, j, error, base, count;
struct cooFormat *work;
/* read the matrix */
error = mm_read_mtx_crd(filename, m, n, nnz, &trow, &tcol, &tval, &matcode);
if (error) {
fprintf(stderr, "!!!! can not open file: '%s'\n", filename);
return 1;
}
/* start error checking */
if (mm_is_complex(matcode) && ((elem_type != 'z') && (elem_type != 'c'))) {
fprintf(stderr, "!!!! complex matrix requires type 'z' or 'c'\n");
return 1;
}
if (mm_is_dense(matcode) || mm_is_array(matcode) ||
mm_is_pattern(matcode) /*|| mm_is_integer(matcode)*/) {
fprintf(
stderr,
"!!!! dense, array, pattern and integer matrices are not supported\n");
return 1;
}
/* if necessary symmetrize the pattern (transform from triangular to full) */
if ((extendSymMatrix) && (mm_is_symmetric(matcode) ||
mm_is_hermitian(matcode) || mm_is_skew(matcode))) {
// count number of non-diagonal elements
count = 0;
for (i = 0; i < (*nnz); i++) {
if (trow[i] != tcol[i]) {
count++;
}
/* read the matrix */
error = mm_read_mtx_crd(filename, m, n, nnz, &trow, &tcol, &tval, &matcode);
if (error) {
fprintf(stderr, "!!!! can not open file: '%s'\n", filename);
return 1;
}
// allocate space for the symmetrized matrix
tempRowInd = (int *)malloc((*nnz + count) * sizeof(int));
tempColInd = (int *)malloc((*nnz + count) * sizeof(int));
if (mm_is_real(matcode) || mm_is_integer(matcode)) {
tempVal = (double *)malloc((*nnz + count) * sizeof(double));
} else {
tempVal = (double *)malloc(2 * (*nnz + count) * sizeof(double));
/* start error checking */
if (mm_is_complex(matcode) && ((elem_type != 'z') && (elem_type != 'c'))) {
fprintf(stderr, "!!!! complex matrix requires type 'z' or 'c'\n");
return 1;
}
// copy the elements regular and transposed locations
for (j = 0, i = 0; i < (*nnz); i++) {
tempRowInd[j] = trow[i];
tempColInd[j] = tcol[i];
if (mm_is_real(matcode) || mm_is_integer(matcode)) {
tempVal[j] = tval[i];
} else {
tempVal[2 * j] = tval[2 * i];
tempVal[2 * j + 1] = tval[2 * i + 1];
}
j++;
if (trow[i] != tcol[i]) {
tempRowInd[j] = tcol[i];
tempColInd[j] = trow[i];
if (mm_is_real(matcode) || mm_is_integer(matcode)) {
if (mm_is_skew(matcode)) {
tempVal[j] = -tval[i];
} else {
tempVal[j] = tval[i];
}
} else {
if (mm_is_hermitian(matcode)) {
tempVal[2 * j] = tval[2 * i];
tempVal[2 * j + 1] = -tval[2 * i + 1];
} else {
tempVal[2 * j] = tval[2 * i];
tempVal[2 * j + 1] = tval[2 * i + 1];
}
if (mm_is_dense(matcode) || mm_is_array(matcode) || mm_is_pattern(matcode) /*|| mm_is_integer(matcode)*/) {
fprintf(stderr, "!!!! dense, array, pattern and integer matrices are not supported\n");
return 1;
}
/* if necessary symmetrize the pattern (transform from triangular to full) */
if ((extendSymMatrix) && (mm_is_symmetric(matcode) || mm_is_hermitian(matcode) || mm_is_skew(matcode))) {
// count number of non-diagonal elements
count = 0;
for (i = 0; i < (*nnz); i++) {
if (trow[i] != tcol[i]) {
count++;
}
}
j++;
}
// allocate space for the symmetrized matrix
tempRowInd = (int *)malloc((*nnz + count) * sizeof(int));
tempColInd = (int *)malloc((*nnz + count) * sizeof(int));
if (mm_is_real(matcode) || mm_is_integer(matcode)) {
tempVal = (double *)malloc((*nnz + count) * sizeof(double));
}
else {
tempVal = (double *)malloc(2 * (*nnz + count) * sizeof(double));
}
// copy the elements regular and transposed locations
for (j = 0, i = 0; i < (*nnz); i++) {
tempRowInd[j] = trow[i];
tempColInd[j] = tcol[i];
if (mm_is_real(matcode) || mm_is_integer(matcode)) {
tempVal[j] = tval[i];
}
else {
tempVal[2 * j] = tval[2 * i];
tempVal[2 * j + 1] = tval[2 * i + 1];
}
j++;
if (trow[i] != tcol[i]) {
tempRowInd[j] = tcol[i];
tempColInd[j] = trow[i];
if (mm_is_real(matcode) || mm_is_integer(matcode)) {
if (mm_is_skew(matcode)) {
tempVal[j] = -tval[i];
}
else {
tempVal[j] = tval[i];
}
}
else {
if (mm_is_hermitian(matcode)) {
tempVal[2 * j] = tval[2 * i];
tempVal[2 * j + 1] = -tval[2 * i + 1];
}
else {
tempVal[2 * j] = tval[2 * i];
tempVal[2 * j + 1] = tval[2 * i + 1];
}
}
j++;
}
}
(*nnz) += count;
// free temporary storage
free(trow);
free(tcol);
free(tval);
}
(*nnz) += count;
// free temporary storage
free(trow);
free(tcol);
free(tval);
} else {
tempRowInd = trow;
tempColInd = tcol;
tempVal = tval;
}
// life time of (trow, tcol, tval) is over.
// please use COO format (tempRowInd, tempColInd, tempVal)
// use qsort to sort COO format
work = (struct cooFormat *)malloc(sizeof(struct cooFormat) * (*nnz));
if (NULL == work) {
fprintf(stderr, "!!!! allocation error, malloc failed\n");
return 1;
}
for (i = 0; i < (*nnz); i++) {
work[i].i = tempRowInd[i];
work[i].j = tempColInd[i];
work[i].p = i; // permutation is identity
}
if (csrFormat) {
/* create row-major ordering of indices (sorted by row and within each row
* by column) */
qsort(work, *nnz, sizeof(struct cooFormat), (FUNPTR)fptr_array[0]);
} else {
/* create column-major ordering of indices (sorted by column and within each
* column by row) */
qsort(work, *nnz, sizeof(struct cooFormat), (FUNPTR)fptr_array[1]);
}
// (tempRowInd, tempColInd) is sorted either by row-major or by col-major
for (i = 0; i < (*nnz); i++) {
tempRowInd[i] = work[i].i;
tempColInd[i] = work[i].j;
}
// setup base
// check if there is any row/col 0, if so base-0
// check if there is any row/col equal to matrix dimension m/n, if so base-1
int base0 = 0;
int base1 = 0;
for (i = 0; i < (*nnz); i++) {
const int row = tempRowInd[i];
const int col = tempColInd[i];
if ((0 == row) || (0 == col)) {
base0 = 1;
else {
tempRowInd = trow;
tempColInd = tcol;
tempVal = tval;
}
if ((*m == row) || (*n == col)) {
base1 = 1;
// life time of (trow, tcol, tval) is over.
// please use COO format (tempRowInd, tempColInd, tempVal)
// use qsort to sort COO format
work = (struct cooFormat *)malloc(sizeof(struct cooFormat) * (*nnz));
if (NULL == work) {
fprintf(stderr, "!!!! allocation error, malloc failed\n");
return 1;
}
for (i = 0; i < (*nnz); i++) {
work[i].i = tempRowInd[i];
work[i].j = tempColInd[i];
work[i].p = i; // permutation is identity
}
}
if (base0 && base1) {
printf("Error: input matrix is base-0 and base-1 \n");
return 1;
}
base = 0;
if (base1) {
base = 1;
}
/* compress the appropriate indices */
if (csrFormat) {
/* CSR format (assuming row-major format) */
csrRowPtr = (int *)malloc(((*m) + 1) * sizeof(csrRowPtr[0]));
if (!csrRowPtr) return 1;
compress_index(tempRowInd, *nnz, *m, csrRowPtr, base);
*aRowInd = csrRowPtr;
*aColInd = (int *)malloc((*nnz) * sizeof(int));
} else {
/* CSC format (assuming column-major format) */
cscColPtr = (int *)malloc(((*n) + 1) * sizeof(cscColPtr[0]));
if (!cscColPtr) return 1;
compress_index(tempColInd, *nnz, *n, cscColPtr, base);
*aColInd = cscColPtr;
*aRowInd = (int *)malloc((*nnz) * sizeof(int));
}
/* transfrom the matrix values of type double into one of the cusparse library
* types */
*aVal = (T_ELEM *)malloc((*nnz) * sizeof(T_ELEM));
for (i = 0; i < (*nnz); i++) {
if (csrFormat) {
(*aColInd)[i] = tempColInd[i];
} else {
(*aRowInd)[i] = tempRowInd[i];
/* create row-major ordering of indices (sorted by row and within each row
* by column) */
qsort(work, *nnz, sizeof(struct cooFormat), (FUNPTR)fptr_array[0]);
}
if (mm_is_real(matcode) || mm_is_integer(matcode)) {
(*aVal)[i] = cuGet<T_ELEM>(tempVal[work[i].p]);
} else {
(*aVal)[i] =
cuGet<T_ELEM>(tempVal[2 * work[i].p], tempVal[2 * work[i].p + 1]);
else {
/* create column-major ordering of indices (sorted by column and within each
* column by row) */
qsort(work, *nnz, sizeof(struct cooFormat), (FUNPTR)fptr_array[1]);
}
}
/* check for corruption */
int error_found;
if (csrFormat) {
error_found = verify_pattern(*m, *nnz, *aRowInd, *aColInd);
} else {
error_found = verify_pattern(*n, *nnz, *aColInd, *aRowInd);
}
if (error_found) {
fprintf(stderr, "!!!! verify_pattern failed\n");
return 1;
}
// (tempRowInd, tempColInd) is sorted either by row-major or by col-major
for (i = 0; i < (*nnz); i++) {
tempRowInd[i] = work[i].i;
tempColInd[i] = work[i].j;
}
/* cleanup and exit */
free(work);
free(tempVal);
free(tempColInd);
free(tempRowInd);
// setup base
// check if there is any row/col 0, if so base-0
// check if there is any row/col equal to matrix dimension m/n, if so base-1
int base0 = 0;
int base1 = 0;
for (i = 0; i < (*nnz); i++) {
const int row = tempRowInd[i];
const int col = tempColInd[i];
if ((0 == row) || (0 == col)) {
base0 = 1;
}
if ((*m == row) || (*n == col)) {
base1 = 1;
}
}
if (base0 && base1) {
printf("Error: input matrix is base-0 and base-1 \n");
return 1;
}
return 0;
base = 0;
if (base1) {
base = 1;
}
/* compress the appropriate indices */
if (csrFormat) {
/* CSR format (assuming row-major format) */
csrRowPtr = (int *)malloc(((*m) + 1) * sizeof(csrRowPtr[0]));
if (!csrRowPtr)
return 1;
compress_index(tempRowInd, *nnz, *m, csrRowPtr, base);
*aRowInd = csrRowPtr;
*aColInd = (int *)malloc((*nnz) * sizeof(int));
}
else {
/* CSC format (assuming column-major format) */
cscColPtr = (int *)malloc(((*n) + 1) * sizeof(cscColPtr[0]));
if (!cscColPtr)
return 1;
compress_index(tempColInd, *nnz, *n, cscColPtr, base);
*aColInd = cscColPtr;
*aRowInd = (int *)malloc((*nnz) * sizeof(int));
}
/* transfrom the matrix values of type double into one of the cusparse library
* types */
*aVal = (T_ELEM *)malloc((*nnz) * sizeof(T_ELEM));
for (i = 0; i < (*nnz); i++) {
if (csrFormat) {
(*aColInd)[i] = tempColInd[i];
}
else {
(*aRowInd)[i] = tempRowInd[i];
}
if (mm_is_real(matcode) || mm_is_integer(matcode)) {
(*aVal)[i] = cuGet<T_ELEM>(tempVal[work[i].p]);
}
else {
(*aVal)[i] = cuGet<T_ELEM>(tempVal[2 * work[i].p], tempVal[2 * work[i].p + 1]);
}
}
/* check for corruption */
int error_found;
if (csrFormat) {
error_found = verify_pattern(*m, *nnz, *aRowInd, *aColInd);
}
else {
error_found = verify_pattern(*n, *nnz, *aColInd, *aRowInd);
}
if (error_found) {
fprintf(stderr, "!!!! verify_pattern failed\n");
return 1;
}
/* cleanup and exit */
free(work);
free(tempVal);
free(tempColInd);
free(tempRowInd);
return 0;
}
/* specific instantiation */
template int loadMMSparseMatrix<float>(char *filename, char elem_type,
bool csrFormat, int *m, int *n, int *nnz,
float **aVal, int **aRowInd,
int **aColInd, int extendSymMatrix);
template int loadMMSparseMatrix<float>(char *filename,
char elem_type,
bool csrFormat,
int *m,
int *n,
int *nnz,
float **aVal,
int **aRowInd,
int **aColInd,
int extendSymMatrix);
template int loadMMSparseMatrix<double>(char *filename, char elem_type,
bool csrFormat, int *m, int *n,
int *nnz, double **aVal, int **aRowInd,
int **aColInd, int extendSymMatrix);
template int loadMMSparseMatrix<double>(char *filename,
char elem_type,
bool csrFormat,
int *m,
int *n,
int *nnz,
double **aVal,
int **aRowInd,
int **aColInd,
int extendSymMatrix);
template int loadMMSparseMatrix<cuComplex>(char *filename, char elem_type,
bool csrFormat, int *m, int *n,
int *nnz, cuComplex **aVal,
int **aRowInd, int **aColInd,
int extendSymMatrix);
template int loadMMSparseMatrix<cuComplex>(char *filename,
char elem_type,
bool csrFormat,
int *m,
int *n,
int *nnz,
cuComplex **aVal,
int **aRowInd,
int **aColInd,
int extendSymMatrix);
template int loadMMSparseMatrix<cuDoubleComplex>(
char *filename, char elem_type, bool csrFormat, int *m, int *n, int *nnz,
cuDoubleComplex **aVal, int **aRowInd, int **aColInd, int extendSymMatrix);
template int loadMMSparseMatrix<cuDoubleComplex>(char *filename,
char elem_type,
bool csrFormat,
int *m,
int *n,
int *nnz,
cuDoubleComplex **aVal,
int **aRowInd,
int **aColInd,
int extendSymMatrix);

View File

@@ -1,128 +1,126 @@
/*
* Matrix Market I/O library for ANSI C
*
* See http://math.nist.gov/MatrixMarket for details.
*
*
*/
/*
* Matrix Market I/O library for ANSI C
*
* See http://math.nist.gov/MatrixMarket for details.
*
*
*/
/* avoid Windows warnings (for example: strcpy, fscanf, etc.) */
#if defined(_WIN32)
#if defined(_WIN32)
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include "mmio.h"
int mm_read_unsymmetric_sparse(const char *fname, int *M_, int *N_, int *nz_,
double **val_, int **I_, int **J_)
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int mm_read_unsymmetric_sparse(const char *fname, int *M_, int *N_, int *nz_, double **val_, int **I_, int **J_)
{
FILE *f;
FILE *f;
MM_typecode matcode;
int M, N, nz;
int i;
double *val;
int *I, *J;
int M, N, nz;
int i;
double *val;
int *I, *J;
if ((f = fopen(fname, "r")) == NULL)
return -1;
if (mm_read_banner(f, &matcode) != 0)
{
return -1;
if (mm_read_banner(f, &matcode) != 0) {
printf("mm_read_unsymetric: Could not process Matrix Market banner ");
printf(" in file [%s]\n", fname);
return -1;
}
if ( !(mm_is_real(matcode) && mm_is_matrix(matcode) &&
mm_is_sparse(matcode)))
{
if (!(mm_is_real(matcode) && mm_is_matrix(matcode) && mm_is_sparse(matcode))) {
fprintf(stderr, "Sorry, this application does not support ");
fprintf(stderr, "Market Market type: [%s]\n",
mm_typecode_to_str(matcode));
fprintf(stderr, "Market Market type: [%s]\n", mm_typecode_to_str(matcode));
return -1;
}
/* find out size of sparse matrix: M, N, nz .... */
if (mm_read_mtx_crd_size(f, &M, &N, &nz) !=0)
{
if (mm_read_mtx_crd_size(f, &M, &N, &nz) != 0) {
fprintf(stderr, "read_unsymmetric_sparse(): could not parse matrix size.\n");
return -1;
}
*M_ = M;
*N_ = N;
*M_ = M;
*N_ = N;
*nz_ = nz;
/* reserve memory for matrices */
I = (int *) malloc(nz * sizeof(int));
J = (int *) malloc(nz * sizeof(int));
val = (double *) malloc(nz * sizeof(double));
I = (int *)malloc(nz * sizeof(int));
J = (int *)malloc(nz * sizeof(int));
val = (double *)malloc(nz * sizeof(double));
*val_ = val;
*I_ = I;
*J_ = J;
*I_ = I;
*J_ = J;
/* NOTE: when reading in doubles, ANSI C requires the use of the "l" */
/* specifier as in "%lg", "%lf", "%le", otherwise errors will occur */
/* (ANSI C X3.159-1989, Sec. 4.9.6.2, p. 136 lines 13-15) */
for (i=0; i<nz; i++)
{
for (i = 0; i < nz; i++) {
if (fscanf(f, "%d %d %lg\n", &I[i], &J[i], &val[i]) != 3) {
return -1;
}
I[i]--; /* adjust from 1-based to 0-based */
I[i]--; /* adjust from 1-based to 0-based */
J[i]--;
}
fclose(f);
return 0;
}
int mm_is_valid(MM_typecode matcode)
{
if (!mm_is_matrix(matcode)) return 0;
if (mm_is_dense(matcode) && mm_is_pattern(matcode)) return 0;
if (mm_is_real(matcode) && mm_is_hermitian(matcode)) return 0;
if (mm_is_pattern(matcode) && (mm_is_hermitian(matcode) ||
mm_is_skew(matcode))) return 0;
if (!mm_is_matrix(matcode))
return 0;
if (mm_is_dense(matcode) && mm_is_pattern(matcode))
return 0;
if (mm_is_real(matcode) && mm_is_hermitian(matcode))
return 0;
if (mm_is_pattern(matcode) && (mm_is_hermitian(matcode) || mm_is_skew(matcode)))
return 0;
return 1;
}
int mm_read_banner(FILE *f, MM_typecode *matcode)
{
char line[MM_MAX_LINE_LENGTH];
char banner[MM_MAX_TOKEN_LENGTH];
char mtx[MM_MAX_TOKEN_LENGTH];
char crd[MM_MAX_TOKEN_LENGTH];
char data_type[MM_MAX_TOKEN_LENGTH];
char storage_scheme[MM_MAX_TOKEN_LENGTH];
char line[MM_MAX_LINE_LENGTH];
char banner[MM_MAX_TOKEN_LENGTH];
char mtx[MM_MAX_TOKEN_LENGTH];
char crd[MM_MAX_TOKEN_LENGTH];
char data_type[MM_MAX_TOKEN_LENGTH];
char storage_scheme[MM_MAX_TOKEN_LENGTH];
char *p;
mm_clear_typecode(matcode);
mm_clear_typecode(matcode);
if (fgets(line, MM_MAX_LINE_LENGTH, f) == NULL)
if (fgets(line, MM_MAX_LINE_LENGTH, f) == NULL)
return MM_PREMATURE_EOF;
if (sscanf(line, "%s %s %s %s %s", banner, mtx, crd, data_type,
storage_scheme) != 5)
if (sscanf(line, "%s %s %s %s %s", banner, mtx, crd, data_type, storage_scheme) != 5)
return MM_PREMATURE_EOF;
for (p=mtx; *p!='\0'; *p=tolower(*p),p++); /* convert to lower case */
for (p=crd; *p!='\0'; *p=tolower(*p),p++);
for (p=data_type; *p!='\0'; *p=tolower(*p),p++);
for (p=storage_scheme; *p!='\0'; *p=tolower(*p),p++);
for (p = mtx; *p != '\0'; *p = tolower(*p), p++)
; /* convert to lower case */
for (p = crd; *p != '\0'; *p = tolower(*p), p++)
;
for (p = data_type; *p != '\0'; *p = tolower(*p), p++)
;
for (p = storage_scheme; *p != '\0'; *p = tolower(*p), p++)
;
/* check for banner */
if (strncmp(banner, MatrixMarketBanner, strlen(MatrixMarketBanner)) != 0)
@@ -130,7 +128,7 @@ int mm_read_banner(FILE *f, MM_typecode *matcode)
/* first field should be "mtx" */
if (strcmp(mtx, MM_MTX_STR) != 0)
return MM_UNSUPPORTED_TYPE;
return MM_UNSUPPORTED_TYPE;
mm_set_matrix(matcode);
@@ -140,46 +138,39 @@ int mm_read_banner(FILE *f, MM_typecode *matcode)
if (strcmp(crd, MM_SPARSE_STR) == 0)
mm_set_sparse(matcode);
else
if (strcmp(crd, MM_DENSE_STR) == 0)
mm_set_dense(matcode);
else if (strcmp(crd, MM_DENSE_STR) == 0)
mm_set_dense(matcode);
else
return MM_UNSUPPORTED_TYPE;
/* third field */
if (strcmp(data_type, MM_REAL_STR) == 0)
mm_set_real(matcode);
else
if (strcmp(data_type, MM_COMPLEX_STR) == 0)
else if (strcmp(data_type, MM_COMPLEX_STR) == 0)
mm_set_complex(matcode);
else
if (strcmp(data_type, MM_PATTERN_STR) == 0)
else if (strcmp(data_type, MM_PATTERN_STR) == 0)
mm_set_pattern(matcode);
else
if (strcmp(data_type, MM_INT_STR) == 0)
else if (strcmp(data_type, MM_INT_STR) == 0)
mm_set_integer(matcode);
else
return MM_UNSUPPORTED_TYPE;
/* fourth field */
if (strcmp(storage_scheme, MM_GENERAL_STR) == 0)
mm_set_general(matcode);
else
if (strcmp(storage_scheme, MM_SYMM_STR) == 0)
else if (strcmp(storage_scheme, MM_SYMM_STR) == 0)
mm_set_symmetric(matcode);
else
if (strcmp(storage_scheme, MM_HERM_STR) == 0)
else if (strcmp(storage_scheme, MM_HERM_STR) == 0)
mm_set_hermitian(matcode);
else
if (strcmp(storage_scheme, MM_SKEW_STR) == 0)
else if (strcmp(storage_scheme, MM_SKEW_STR) == 0)
mm_set_skew(matcode);
else
return MM_UNSUPPORTED_TYPE;
return 0;
}
@@ -188,36 +179,34 @@ int mm_write_mtx_crd_size(FILE *f, int M, int N, int nz)
{
if (fprintf(f, "%d %d %d\n", M, N, nz) != 3)
return MM_COULD_NOT_WRITE_FILE;
else
else
return 0;
}
int mm_read_mtx_crd_size(FILE *f, int *M, int *N, int *nz )
int mm_read_mtx_crd_size(FILE *f, int *M, int *N, int *nz)
{
char line[MM_MAX_LINE_LENGTH];
int num_items_read;
int num_items_read;
/* set return null parameter values, in case we exit with errors */
*M = *N = *nz = 0;
/* now continue scanning until you reach the end-of-comments */
do
{
if (fgets(line,MM_MAX_LINE_LENGTH,f) == NULL)
do {
if (fgets(line, MM_MAX_LINE_LENGTH, f) == NULL)
return MM_PREMATURE_EOF;
}while (line[0] == '%');
} while (line[0] == '%');
/* line[] is either blank or has M,N, nz */
if (sscanf(line, "%d %d %d", M, N, nz) == 3)
return 0;
else
do
{
num_items_read = fscanf(f, "%d %d %d", M, N, nz);
if (num_items_read == EOF) return MM_PREMATURE_EOF;
}
while (num_items_read != 3);
do {
num_items_read = fscanf(f, "%d %d %d", M, N, nz);
if (num_items_read == EOF)
return MM_PREMATURE_EOF;
} while (num_items_read != 3);
return 0;
}
@@ -226,28 +215,26 @@ int mm_read_mtx_crd_size(FILE *f, int *M, int *N, int *nz )
int mm_read_mtx_array_size(FILE *f, int *M, int *N)
{
char line[MM_MAX_LINE_LENGTH];
int num_items_read;
int num_items_read;
/* set return null parameter values, in case we exit with errors */
*M = *N = 0;
/* now continue scanning until you reach the end-of-comments */
do
{
if (fgets(line,MM_MAX_LINE_LENGTH,f) == NULL)
do {
if (fgets(line, MM_MAX_LINE_LENGTH, f) == NULL)
return MM_PREMATURE_EOF;
}while (line[0] == '%');
} while (line[0] == '%');
/* line[] is either blank or has M,N, nz */
if (sscanf(line, "%d %d", M, N) == 2)
return 0;
else /* we have a blank line */
do
{
num_items_read = fscanf(f, "%d %d", M, N);
if (num_items_read == EOF) return MM_PREMATURE_EOF;
}
while (num_items_read != 2);
do {
num_items_read = fscanf(f, "%d %d", M, N);
if (num_items_read == EOF)
return MM_PREMATURE_EOF;
} while (num_items_read != 2);
return 0;
}
@@ -256,43 +243,36 @@ int mm_write_mtx_array_size(FILE *f, int M, int N)
{
if (fprintf(f, "%d %d\n", M, N) != 2)
return MM_COULD_NOT_WRITE_FILE;
else
else
return 0;
}
/*-------------------------------------------------------------------------*/
/******************************************************************/
/* use when I[], J[], and val[]J, and val[] are already allocated */
/******************************************************************/
int mm_read_mtx_crd_data(FILE *f, int M, int N, int nz, int I[], int J[],
double val[], MM_typecode matcode)
int mm_read_mtx_crd_data(FILE *f, int M, int N, int nz, int I[], int J[], double val[], MM_typecode matcode)
{
int i;
if (mm_is_complex(matcode))
{
for (i=0; i<nz; i++)
if (fscanf(f, "%d %d %lg %lg", &I[i], &J[i], &val[2*i], &val[2*i+1])
!= 4) return MM_PREMATURE_EOF;
if (mm_is_complex(matcode)) {
for (i = 0; i < nz; i++)
if (fscanf(f, "%d %d %lg %lg", &I[i], &J[i], &val[2 * i], &val[2 * i + 1]) != 4)
return MM_PREMATURE_EOF;
}
else if (mm_is_real(matcode) || mm_is_integer(matcode))
{
for (i=0; i<nz; i++)
{
if (fscanf(f, "%d %d %lg\n", &I[i], &J[i], &val[i])
!= 3) return MM_PREMATURE_EOF;
else if (mm_is_real(matcode) || mm_is_integer(matcode)) {
for (i = 0; i < nz; i++) {
if (fscanf(f, "%d %d %lg\n", &I[i], &J[i], &val[i]) != 3)
return MM_PREMATURE_EOF;
}
}
else if (mm_is_pattern(matcode))
{
for (i=0; i<nz; i++)
if (fscanf(f, "%d %d", &I[i], &J[i])
!= 2) return MM_PREMATURE_EOF;
else if (mm_is_pattern(matcode)) {
for (i = 0; i < nz; i++)
if (fscanf(f, "%d %d", &I[i], &J[i]) != 2)
return MM_PREMATURE_EOF;
}
else
return MM_UNSUPPORTED_TYPE;
@@ -300,24 +280,20 @@ int mm_read_mtx_crd_data(FILE *f, int M, int N, int nz, int I[], int J[],
return 0;
}
int mm_read_mtx_crd_entry(FILE *f, int *I, int *J,
double *real, double *imag, MM_typecode matcode)
int mm_read_mtx_crd_entry(FILE *f, int *I, int *J, double *real, double *imag, MM_typecode matcode)
{
if (mm_is_complex(matcode))
{
if (fscanf(f, "%d %d %lg %lg", I, J, real, imag)
!= 4) return MM_PREMATURE_EOF;
if (mm_is_complex(matcode)) {
if (fscanf(f, "%d %d %lg %lg", I, J, real, imag) != 4)
return MM_PREMATURE_EOF;
}
else if (mm_is_real(matcode) || mm_is_integer(matcode))
{
if (fscanf(f, "%d %d %lg\n", I, J, real)
!= 3) return MM_PREMATURE_EOF;
else if (mm_is_real(matcode) || mm_is_integer(matcode)) {
if (fscanf(f, "%d %d %lg\n", I, J, real) != 3)
return MM_PREMATURE_EOF;
}
else if (mm_is_pattern(matcode))
{
if (fscanf(f, "%d %d", I, J) != 2) return MM_PREMATURE_EOF;
else if (mm_is_pattern(matcode)) {
if (fscanf(f, "%d %d", I, J) != 2)
return MM_PREMATURE_EOF;
}
else
return MM_UNSUPPORTED_TYPE;
@@ -334,82 +310,76 @@ int mm_read_mtx_crd_entry(FILE *f, int *I, int *J,
(nz pairs of real/imaginary values)
************************************************************************/
int mm_read_mtx_crd(char *fname, int *M, int *N, int *nz, int **I, int **J,
double **val, MM_typecode *matcode)
int mm_read_mtx_crd(char *fname, int *M, int *N, int *nz, int **I, int **J, double **val, MM_typecode *matcode)
{
int ret_code;
int ret_code;
FILE *f;
if (strcmp(fname, "stdin") == 0) f=stdin;
else
if ((f = fopen(fname, "r")) == NULL)
if (strcmp(fname, "stdin") == 0)
f = stdin;
else if ((f = fopen(fname, "r")) == NULL)
return MM_COULD_NOT_READ_FILE;
if ((ret_code = mm_read_banner(f, matcode)) != 0)
return ret_code;
if (!(mm_is_valid(*matcode) && mm_is_sparse(*matcode) &&
mm_is_matrix(*matcode)))
if (!(mm_is_valid(*matcode) && mm_is_sparse(*matcode) && mm_is_matrix(*matcode)))
return MM_UNSUPPORTED_TYPE;
if ((ret_code = mm_read_mtx_crd_size(f, M, N, nz)) != 0)
return ret_code;
*I = (int *) malloc(*nz * sizeof(int));
*J = (int *) malloc(*nz * sizeof(int));
*I = (int *)malloc(*nz * sizeof(int));
*J = (int *)malloc(*nz * sizeof(int));
*val = NULL;
if (mm_is_complex(*matcode))
{
*val = (double *) malloc(*nz * 2 * sizeof(double));
ret_code = mm_read_mtx_crd_data(f, *M, *N, *nz, *I, *J, *val,
*matcode);
if (ret_code != 0) return ret_code;
if (mm_is_complex(*matcode)) {
*val = (double *)malloc(*nz * 2 * sizeof(double));
ret_code = mm_read_mtx_crd_data(f, *M, *N, *nz, *I, *J, *val, *matcode);
if (ret_code != 0)
return ret_code;
}
else if (mm_is_real(*matcode) || mm_is_integer(*matcode))
{
*val = (double *) malloc(*nz * sizeof(double));
ret_code = mm_read_mtx_crd_data(f, *M, *N, *nz, *I, *J, *val,
*matcode);
if (ret_code != 0) return ret_code;
else if (mm_is_real(*matcode) || mm_is_integer(*matcode)) {
*val = (double *)malloc(*nz * sizeof(double));
ret_code = mm_read_mtx_crd_data(f, *M, *N, *nz, *I, *J, *val, *matcode);
if (ret_code != 0)
return ret_code;
}
else if (mm_is_pattern(*matcode))
{
ret_code = mm_read_mtx_crd_data(f, *M, *N, *nz, *I, *J, *val,
*matcode);
if (ret_code != 0) return ret_code;
else if (mm_is_pattern(*matcode)) {
ret_code = mm_read_mtx_crd_data(f, *M, *N, *nz, *I, *J, *val, *matcode);
if (ret_code != 0)
return ret_code;
}
if (f != stdin) fclose(f);
if (f != stdin)
fclose(f);
return 0;
}
int mm_write_banner(FILE *f, MM_typecode matcode)
{
char *str = mm_typecode_to_str(matcode);
int ret_code;
int ret_code;
ret_code = fprintf(f, "%s %s\n", MatrixMarketBanner, str);
free(str);
if (ret_code !=2 )
if (ret_code != 2)
return MM_COULD_NOT_WRITE_FILE;
else
return 0;
}
int mm_write_mtx_crd(char fname[], int M, int N, int nz, int I[], int J[],
double val[], MM_typecode matcode)
int mm_write_mtx_crd(char fname[], int M, int N, int nz, int I[], int J[], double val[], MM_typecode matcode)
{
FILE *f;
int i;
int i;
if (strcmp(fname, "stdout") == 0)
f = stdout;
else
if ((f = fopen(fname, "w")) == NULL)
else if ((f = fopen(fname, "w")) == NULL)
return MM_COULD_NOT_WRITE_FILE;
/* print banner followed by typecode */
@@ -421,50 +391,47 @@ int mm_write_mtx_crd(char fname[], int M, int N, int nz, int I[], int J[],
/* print values */
if (mm_is_pattern(matcode))
for (i=0; i<nz; i++)
for (i = 0; i < nz; i++)
fprintf(f, "%d %d\n", I[i], J[i]);
else
if (mm_is_integer(matcode))
for (i=0; i<nz; i++)
else if (mm_is_integer(matcode))
for (i = 0; i < nz; i++)
fprintf(f, "%d %d %d\n", I[i], J[i], (int)val[i]);
else
if (mm_is_real(matcode))
for (i=0; i<nz; i++)
else if (mm_is_real(matcode))
for (i = 0; i < nz; i++)
fprintf(f, "%d %d %20.16g\n", I[i], J[i], val[i]);
else
if (mm_is_complex(matcode))
for (i=0; i<nz; i++)
fprintf(f, "%d %d %20.16g %20.16g\n", I[i], J[i], val[2*i],
val[2*i+1]);
else
{
if (f != stdout) fclose(f);
else if (mm_is_complex(matcode))
for (i = 0; i < nz; i++)
fprintf(f, "%d %d %20.16g %20.16g\n", I[i], J[i], val[2 * i], val[2 * i + 1]);
else {
if (f != stdout)
fclose(f);
return MM_UNSUPPORTED_TYPE;
}
if (f !=stdout) fclose(f);
if (f != stdout)
fclose(f);
return 0;
}
/**
* Create a new copy of a string s. mm_strdup() is a common routine, but
* not part of ANSI C, so it is included here. Used by mm_typecode_to_str().
*
*/
* Create a new copy of a string s. mm_strdup() is a common routine, but
* not part of ANSI C, so it is included here. Used by mm_typecode_to_str().
*
*/
static char *mm_strdup(const char *s)
{
size_t len = strlen(s);
char *s2 = (char *) malloc((len+1)*sizeof(char));
char *s2 = (char *)malloc((len + 1) * sizeof(char));
return strcpy(s2, s);
}
char *mm_typecode_to_str(MM_typecode matcode)
char *mm_typecode_to_str(MM_typecode matcode)
{
char buffer[MM_MAX_LINE_LENGTH];
char buffer[MM_MAX_LINE_LENGTH];
char *types[4];
//char *mm_strdup(const char *);
//int error =0;
// char *mm_strdup(const char *);
// int error =0;
/* check for MTX type */
if (mm_is_matrix(matcode))
@@ -475,8 +442,7 @@ char *mm_typecode_to_str(MM_typecode matcode)
/* check for CRD or ARR matrix */
if (mm_is_sparse(matcode))
types[1] = MM_SPARSE_STR;
else
if (mm_is_dense(matcode))
else if (mm_is_dense(matcode))
types[1] = MM_DENSE_STR;
else
return NULL;
@@ -484,14 +450,11 @@ char *mm_typecode_to_str(MM_typecode matcode)
/* check for element data type */
if (mm_is_real(matcode))
types[2] = MM_REAL_STR;
else
if (mm_is_complex(matcode))
else if (mm_is_complex(matcode))
types[2] = MM_COMPLEX_STR;
else
if (mm_is_pattern(matcode))
else if (mm_is_pattern(matcode))
types[2] = MM_PATTERN_STR;
else
if (mm_is_integer(matcode))
else if (mm_is_integer(matcode))
types[2] = MM_INT_STR;
else
return NULL;
@@ -500,18 +463,15 @@ char *mm_typecode_to_str(MM_typecode matcode)
/* check for symmetry type */
if (mm_is_general(matcode))
types[3] = MM_GENERAL_STR;
else
if (mm_is_symmetric(matcode))
else if (mm_is_symmetric(matcode))
types[3] = MM_SYMM_STR;
else
if (mm_is_hermitian(matcode))
else if (mm_is_hermitian(matcode))
types[3] = MM_HERM_STR;
else
if (mm_is_skew(matcode))
else if (mm_is_skew(matcode))
types[3] = MM_SKEW_STR;
else
return NULL;
sprintf(buffer,"%s %s %s %s", types[0], types[1], types[2], types[3]);
sprintf(buffer, "%s %s %s %s", types[0], types[1], types[2], types[3]);
return mm_strdup(buffer);
}

View File

@@ -1,141 +1,138 @@
/*
* Matrix Market I/O library for ANSI C
*
* See http://math.nist.gov/MatrixMarket for details.
*
*
*/
/*
* Matrix Market I/O library for ANSI C
*
* See http://math.nist.gov/MatrixMarket for details.
*
*
*/
#ifndef MM_IO_H
#define MM_IO_H
#include <stdio.h>
#if defined(__cplusplus)
extern "C" {
extern "C"
{
#endif /* __cplusplus */
#define MM_MAX_LINE_LENGTH 1025
#define MatrixMarketBanner "%%MatrixMarket"
#define MM_MAX_LINE_LENGTH 1025
#define MatrixMarketBanner "%%MatrixMarket"
#define MM_MAX_TOKEN_LENGTH 64
typedef char MM_typecode[4];
typedef char MM_typecode[4];
char *mm_typecode_to_str(MM_typecode matcode);
char *mm_typecode_to_str(MM_typecode matcode);
int mm_read_banner(FILE *f, MM_typecode *matcode);
int mm_read_mtx_crd_size(FILE *f, int *M, int *N, int *nz);
int mm_read_mtx_array_size(FILE *f, int *M, int *N);
int mm_read_banner(FILE *f, MM_typecode *matcode);
int mm_read_mtx_crd_size(FILE *f, int *M, int *N, int *nz);
int mm_read_mtx_array_size(FILE *f, int *M, int *N);
int mm_write_banner(FILE *f, MM_typecode matcode);
int mm_write_mtx_crd_size(FILE *f, int M, int N, int nz);
int mm_write_mtx_array_size(FILE *f, int M, int N);
int mm_write_banner(FILE *f, MM_typecode matcode);
int mm_write_mtx_crd_size(FILE *f, int M, int N, int nz);
int mm_write_mtx_array_size(FILE *f, int M, int N);
/********************* MM_typecode query fucntions ***************************/
/********************* MM_typecode query fucntions ***************************/
#define mm_is_matrix(typecode) ((typecode)[0]=='M')
#define mm_is_matrix(typecode) ((typecode)[0] == 'M')
#define mm_is_sparse(typecode) ((typecode)[1]=='C')
#define mm_is_coordinate(typecode)((typecode)[1]=='C')
#define mm_is_dense(typecode) ((typecode)[1]=='A')
#define mm_is_array(typecode) ((typecode)[1]=='A')
#define mm_is_sparse(typecode) ((typecode)[1] == 'C')
#define mm_is_coordinate(typecode) ((typecode)[1] == 'C')
#define mm_is_dense(typecode) ((typecode)[1] == 'A')
#define mm_is_array(typecode) ((typecode)[1] == 'A')
#define mm_is_complex(typecode) ((typecode)[2]=='C')
#define mm_is_real(typecode) ((typecode)[2]=='R')
#define mm_is_pattern(typecode) ((typecode)[2]=='P')
#define mm_is_integer(typecode) ((typecode)[2]=='I')
#define mm_is_complex(typecode) ((typecode)[2] == 'C')
#define mm_is_real(typecode) ((typecode)[2] == 'R')
#define mm_is_pattern(typecode) ((typecode)[2] == 'P')
#define mm_is_integer(typecode) ((typecode)[2] == 'I')
#define mm_is_symmetric(typecode)((typecode)[3]=='S')
#define mm_is_general(typecode) ((typecode)[3]=='G')
#define mm_is_skew(typecode) ((typecode)[3]=='K')
#define mm_is_hermitian(typecode)((typecode)[3]=='H')
#define mm_is_symmetric(typecode) ((typecode)[3] == 'S')
#define mm_is_general(typecode) ((typecode)[3] == 'G')
#define mm_is_skew(typecode) ((typecode)[3] == 'K')
#define mm_is_hermitian(typecode) ((typecode)[3] == 'H')
int mm_is_valid(MM_typecode matcode); /* too complex for a macro */
int mm_is_valid(MM_typecode matcode); /* too complex for a macro */
/********************* MM_typecode modify fucntions ***************************/
/********************* MM_typecode modify fucntions ***************************/
#define mm_set_matrix(typecode) ((*typecode)[0]='M')
#define mm_set_coordinate(typecode) ((*typecode)[1]='C')
#define mm_set_array(typecode) ((*typecode)[1]='A')
#define mm_set_dense(typecode) mm_set_array(typecode)
#define mm_set_sparse(typecode) mm_set_coordinate(typecode)
#define mm_set_matrix(typecode) ((*typecode)[0] = 'M')
#define mm_set_coordinate(typecode) ((*typecode)[1] = 'C')
#define mm_set_array(typecode) ((*typecode)[1] = 'A')
#define mm_set_dense(typecode) mm_set_array(typecode)
#define mm_set_sparse(typecode) mm_set_coordinate(typecode)
#define mm_set_complex(typecode)((*typecode)[2]='C')
#define mm_set_real(typecode) ((*typecode)[2]='R')
#define mm_set_pattern(typecode)((*typecode)[2]='P')
#define mm_set_integer(typecode)((*typecode)[2]='I')
#define mm_set_complex(typecode) ((*typecode)[2] = 'C')
#define mm_set_real(typecode) ((*typecode)[2] = 'R')
#define mm_set_pattern(typecode) ((*typecode)[2] = 'P')
#define mm_set_integer(typecode) ((*typecode)[2] = 'I')
#define mm_set_symmetric(typecode)((*typecode)[3]='S')
#define mm_set_general(typecode)((*typecode)[3]='G')
#define mm_set_skew(typecode) ((*typecode)[3]='K')
#define mm_set_hermitian(typecode)((*typecode)[3]='H')
#define mm_set_symmetric(typecode) ((*typecode)[3] = 'S')
#define mm_set_general(typecode) ((*typecode)[3] = 'G')
#define mm_set_skew(typecode) ((*typecode)[3] = 'K')
#define mm_set_hermitian(typecode) ((*typecode)[3] = 'H')
#define mm_clear_typecode(typecode) ((*typecode)[0]=(*typecode)[1]= \
(*typecode)[2]=' ',(*typecode)[3]='G')
#define mm_clear_typecode(typecode) ((*typecode)[0] = (*typecode)[1] = (*typecode)[2] = ' ', (*typecode)[3] = 'G')
#define mm_initialize_typecode(typecode) mm_clear_typecode(typecode)
/********************* Matrix Market error codes ***************************/
/********************* Matrix Market error codes ***************************/
#define MM_COULD_NOT_READ_FILE 11
#define MM_PREMATURE_EOF 12
#define MM_NOT_MTX 13
#define MM_NO_HEADER 14
#define MM_UNSUPPORTED_TYPE 15
#define MM_LINE_TOO_LONG 16
#define MM_COULD_NOT_WRITE_FILE 17
#define MM_COULD_NOT_READ_FILE 11
#define MM_PREMATURE_EOF 12
#define MM_NOT_MTX 13
#define MM_NO_HEADER 14
#define MM_UNSUPPORTED_TYPE 15
#define MM_LINE_TOO_LONG 16
#define MM_COULD_NOT_WRITE_FILE 17
/******************** Matrix Market internal definitions ********************
/******************** Matrix Market internal definitions ********************
MM_matrix_typecode: 4-character sequence
MM_matrix_typecode: 4-character sequence
ojbect sparse/ data storage
dense type scheme
ojbect sparse/ data storage
dense type scheme
string position: [0] [1] [2] [3]
string position: [0] [1] [2] [3]
Matrix typecode: M(atrix) C(oord) R(eal) G(eneral)
A(array) C(omplex) H(ermitian)
P(attern) S(ymmetric)
I(nteger) K(kew)
Matrix typecode: M(atrix) C(oord) R(eal) G(eneral)
A(array) C(omplex) H(ermitian)
P(attern) S(ymmetric)
I(nteger) K(kew)
***********************************************************************/
***********************************************************************/
#define MM_MTX_STR "matrix"
#define MM_ARRAY_STR "array"
#define MM_DENSE_STR "array"
#define MM_COORDINATE_STR "coordinate"
#define MM_SPARSE_STR "coordinate"
#define MM_COMPLEX_STR "complex"
#define MM_REAL_STR "real"
#define MM_INT_STR "integer"
#define MM_GENERAL_STR "general"
#define MM_SYMM_STR "symmetric"
#define MM_HERM_STR "hermitian"
#define MM_SKEW_STR "skew-symmetric"
#define MM_PATTERN_STR "pattern"
#define MM_MTX_STR "matrix"
#define MM_ARRAY_STR "array"
#define MM_DENSE_STR "array"
#define MM_COORDINATE_STR "coordinate"
#define MM_SPARSE_STR "coordinate"
#define MM_COMPLEX_STR "complex"
#define MM_REAL_STR "real"
#define MM_INT_STR "integer"
#define MM_GENERAL_STR "general"
#define MM_SYMM_STR "symmetric"
#define MM_HERM_STR "hermitian"
#define MM_SKEW_STR "skew-symmetric"
#define MM_PATTERN_STR "pattern"
/* high level routines */
int mm_read_mtx_crd(char *fname, int *M, int *N, int *nz, int **I, int **J,
double **val, MM_typecode *matcode);
/* high level routines */
int mm_read_mtx_crd(char *fname, int *M, int *N, int *nz, int **I, int **J, double **val, MM_typecode *matcode);
int mm_write_mtx_crd(char fname[], int M, int N, int nz, int I[], int J[],
double val[], MM_typecode matcode);
int mm_read_mtx_crd_data(FILE *f, int M, int N, int nz, int I[], int J[],
double val[], MM_typecode matcode);
int mm_read_mtx_crd_entry(FILE *f, int *I, int *J, double *real, double *img,
MM_typecode matcode);
int mm_write_mtx_crd(char fname[], int M, int N, int nz, int I[], int J[], double val[], MM_typecode matcode);
int mm_read_mtx_crd_data(FILE *f, int M, int N, int nz, int I[], int J[], double val[], MM_typecode matcode);
int mm_read_mtx_crd_entry(FILE *f, int *I, int *J, double *real, double *img, MM_typecode matcode);
int mm_read_unsymmetric_sparse(const char *fname, int *M_, int *N_, int *nz_,
double **val_, int **I_, int **J_);
int mm_read_unsymmetric_sparse(const char *fname, int *M_, int *N_, int *nz_, double **val_, int **I_, int **J_);
#if defined(__cplusplus)
}
#endif /* __cplusplus */
#endif /* __cplusplus */
#endif

View File

@@ -1,427 +1,375 @@
#include <cusolverDn.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "mmio.h"
#include <cusolverDn.h>
/* avoid Windows warnings (for example: strcpy, fscanf, etc.) */
#if defined(_WIN32)
#if defined(_WIN32)
#define _CRT_SECURE_NO_WARNINGS
#endif
/* various __inline__ __device__ function to initialize a T_ELEM */
template <typename T_ELEM> __inline__ T_ELEM cuGet (int );
template <> __inline__ float cuGet<float >(int x)
{
return float(x);
}
template <typename T_ELEM> __inline__ T_ELEM cuGet(int);
template <> __inline__ float cuGet<float>(int x) { return float(x); }
template <> __inline__ double cuGet<double>(int x)
{
return double(x);
}
template <> __inline__ double cuGet<double>(int x) { return double(x); }
template <> __inline__ cuComplex cuGet<cuComplex>(int x)
{
return (make_cuComplex( float(x), 0.0f ));
}
template <> __inline__ cuComplex cuGet<cuComplex>(int x) { return (make_cuComplex(float(x), 0.0f)); }
template <> __inline__ cuDoubleComplex cuGet<cuDoubleComplex>(int x)
template <> __inline__ cuDoubleComplex cuGet<cuDoubleComplex>(int x) { return (make_cuDoubleComplex(double(x), 0.0)); }
template <typename T_ELEM> __inline__ T_ELEM cuGet(int, int);
template <> __inline__ float cuGet<float>(int x, int y) { return float(x); }
template <> __inline__ double cuGet<double>(int x, int y) { return double(x); }
template <> __inline__ cuComplex cuGet<cuComplex>(int x, int y) { return make_cuComplex(float(x), float(y)); }
template <> __inline__ cuDoubleComplex cuGet<cuDoubleComplex>(int x, int y)
{
return (make_cuDoubleComplex( double(x), 0.0 ));
return (make_cuDoubleComplex(double(x), double(y)));
}
template <typename T_ELEM> __inline__ T_ELEM cuGet (int , int );
template <> __inline__ float cuGet<float >(int x, int y)
{
return float(x);
}
template <typename T_ELEM> __inline__ T_ELEM cuGet(float);
template <> __inline__ float cuGet<float>(float x) { return float(x); }
template <> __inline__ double cuGet<double>(int x, int y)
{
return double(x);
}
template <> __inline__ double cuGet<double>(float x) { return double(x); }
template <> __inline__ cuComplex cuGet<cuComplex>(int x, int y)
{
return make_cuComplex( float(x), float(y) );
}
template <> __inline__ cuComplex cuGet<cuComplex>(float x) { return (make_cuComplex(float(x), 0.0f)); }
template <> __inline__ cuDoubleComplex cuGet<cuDoubleComplex>(int x, int y)
template <> __inline__ cuDoubleComplex cuGet<cuDoubleComplex>(float x)
{
return (make_cuDoubleComplex( double(x), double(y) ));
return (make_cuDoubleComplex(double(x), 0.0));
}
template <typename T_ELEM> __inline__ T_ELEM cuGet (float );
template <> __inline__ float cuGet<float >(float x)
{
return float(x);
}
template <typename T_ELEM> __inline__ T_ELEM cuGet(float, float);
template <> __inline__ float cuGet<float>(float x, float y) { return float(x); }
template <> __inline__ double cuGet<double>(float x)
{
return double(x);
}
template <> __inline__ double cuGet<double>(float x, float y) { return double(x); }
template <> __inline__ cuComplex cuGet<cuComplex>(float x)
{
return (make_cuComplex( float(x), 0.0f ));
}
template <> __inline__ cuComplex cuGet<cuComplex>(float x, float y) { return (make_cuComplex(float(x), float(y))); }
template <> __inline__ cuDoubleComplex cuGet<cuDoubleComplex>(float x)
template <> __inline__ cuDoubleComplex cuGet<cuDoubleComplex>(float x, float y)
{
return (make_cuDoubleComplex( double(x), 0.0 ));
return (make_cuDoubleComplex(double(x), double(y)));
}
template <typename T_ELEM> __inline__ T_ELEM cuGet (float, float );
template <> __inline__ float cuGet<float >(float x, float y)
{
return float(x);
}
template <typename T_ELEM> __inline__ T_ELEM cuGet(double);
template <> __inline__ float cuGet<float>(double x) { return float(x); }
template <> __inline__ double cuGet<double>(float x, float y)
{
return double(x);
}
template <> __inline__ double cuGet<double>(double x) { return double(x); }
template <> __inline__ cuComplex cuGet<cuComplex>(float x, float y)
{
return (make_cuComplex( float(x), float(y) ));
}
template <> __inline__ cuComplex cuGet<cuComplex>(double x) { return (make_cuComplex(float(x), 0.0f)); }
template <> __inline__ cuDoubleComplex cuGet<cuDoubleComplex>(float x, float y)
template <> __inline__ cuDoubleComplex cuGet<cuDoubleComplex>(double x)
{
return (make_cuDoubleComplex( double(x), double(y) ));
return (make_cuDoubleComplex(double(x), 0.0));
}
template <typename T_ELEM> __inline__ T_ELEM cuGet (double );
template <> __inline__ float cuGet<float >(double x)
{
return float(x);
}
template <typename T_ELEM> __inline__ T_ELEM cuGet(double, double);
template <> __inline__ float cuGet<float>(double x, double y) { return float(x); }
template <> __inline__ double cuGet<double>(double x)
{
return double(x);
}
template <> __inline__ double cuGet<double>(double x, double y) { return double(x); }
template <> __inline__ cuComplex cuGet<cuComplex>(double x)
{
return (make_cuComplex( float(x), 0.0f ));
}
template <> __inline__ cuComplex cuGet<cuComplex>(double x, double y) { return (make_cuComplex(float(x), float(y))); }
template <> __inline__ cuDoubleComplex cuGet<cuDoubleComplex>(double x)
template <> __inline__ cuDoubleComplex cuGet<cuDoubleComplex>(double x, double y)
{
return (make_cuDoubleComplex( double(x), 0.0 ));
return (make_cuDoubleComplex(double(x), double(y)));
}
template <typename T_ELEM> __inline__ T_ELEM cuGet (double, double );
template <> __inline__ float cuGet<float >(double x, double y)
{
return float(x);
}
template <> __inline__ double cuGet<double>(double x, double y)
{
return double(x);
}
template <> __inline__ cuComplex cuGet<cuComplex>(double x, double y)
{
return (make_cuComplex( float(x), float(y) ));
}
template <> __inline__ cuDoubleComplex cuGet<cuDoubleComplex>(double x, double y)
{
return (make_cuDoubleComplex( double(x), double(y) ));
}
static void compress_index(
const int *Ind,
int nnz,
int m,
int *Ptr,
int base)
static void compress_index(const int *Ind, int nnz, int m, int *Ptr, int base)
{
int i;
/* initialize everything to zero */
for(i=0; i<m+1; i++){
Ptr[i]=0;
}
for (i = 0; i < m + 1; i++) {
Ptr[i] = 0;
}
/* count elements in every row */
Ptr[0]=base;
for(i=0; i<nnz; i++){
Ptr[Ind[i]+(1-base)]++;
}
Ptr[0] = base;
for (i = 0; i < nnz; i++) {
Ptr[Ind[i] + (1 - base)]++;
}
/* add all the values */
for(i=0; i<m; i++){
Ptr[i+1]+=Ptr[i];
}
for (i = 0; i < m; i++) {
Ptr[i + 1] += Ptr[i];
}
}
struct cooFormat {
int i ;
int j ;
int p ; // permutation
struct cooFormat
{
int i;
int j;
int p; // permutation
};
int cmp_cooFormat_csr( struct cooFormat *s, struct cooFormat *t)
int cmp_cooFormat_csr(struct cooFormat *s, struct cooFormat *t)
{
if ( s->i < t->i ){
return -1 ;
if (s->i < t->i) {
return -1;
}
else if ( s->i > t->i ){
return 1 ;
else if (s->i > t->i) {
return 1;
}
else{
return s->j - t->j ;
else {
return s->j - t->j;
}
}
int cmp_cooFormat_csc( struct cooFormat *s, struct cooFormat *t)
int cmp_cooFormat_csc(struct cooFormat *s, struct cooFormat *t)
{
if ( s->j < t->j ){
return -1 ;
if (s->j < t->j) {
return -1;
}
else if ( s->j > t->j ){
return 1 ;
else if (s->j > t->j) {
return 1;
}
else{
return s->i - t->i ;
else {
return s->i - t->i;
}
}
typedef int (*FUNPTR) (const void*, const void*) ;
typedef int (*FUNPTR2) ( struct cooFormat *s, struct cooFormat *t) ;
typedef int (*FUNPTR)(const void *, const void *);
typedef int (*FUNPTR2)(struct cooFormat *s, struct cooFormat *t);
static FUNPTR2 fptr_array[2] = {
static FUNPTR2 fptr_array[2] = {
cmp_cooFormat_csr,
cmp_cooFormat_csc,
};
static int verify_pattern(
int m,
int nnz,
int *csrRowPtr,
int *csrColInd)
static int verify_pattern(int m, int nnz, int *csrRowPtr, int *csrColInd)
{
int i, col, start, end, base_index;
int error_found = 0;
if (nnz != (csrRowPtr[m] - csrRowPtr[0])){
fprintf(stderr, "Error (nnz check failed): (csrRowPtr[%d]=%d - csrRowPtr[%d]=%d) != (nnz=%d)\n", 0, csrRowPtr[0], m, csrRowPtr[m], nnz);
if (nnz != (csrRowPtr[m] - csrRowPtr[0])) {
fprintf(stderr,
"Error (nnz check failed): (csrRowPtr[%d]=%d - csrRowPtr[%d]=%d) != (nnz=%d)\n",
0,
csrRowPtr[0],
m,
csrRowPtr[m],
nnz);
error_found = 1;
}
base_index = csrRowPtr[0];
if ((0 != base_index) && (1 != base_index)){
if ((0 != base_index) && (1 != base_index)) {
fprintf(stderr, "Error (base index check failed): base index = %d\n", base_index);
error_found = 1;
}
for (i=0; (!error_found) && (i<m); i++){
start = csrRowPtr[i ] - base_index;
end = csrRowPtr[i+1] - base_index;
if (start > end){
fprintf(stderr, "Error (corrupted row): csrRowPtr[%d] (=%d) > csrRowPtr[%d] (=%d)\n", i, start+base_index, i+1, end+base_index);
for (i = 0; (!error_found) && (i < m); i++) {
start = csrRowPtr[i] - base_index;
end = csrRowPtr[i + 1] - base_index;
if (start > end) {
fprintf(stderr,
"Error (corrupted row): csrRowPtr[%d] (=%d) > csrRowPtr[%d] (=%d)\n",
i,
start + base_index,
i + 1,
end + base_index);
error_found = 1;
}
for (col=start; col<end; col++){
if (csrColInd[col] < base_index){
for (col = start; col < end; col++) {
if (csrColInd[col] < base_index) {
fprintf(stderr, "Error (column vs. base index check failed): csrColInd[%d] < %d\n", col, base_index);
error_found = 1;
}
if ((col < (end-1)) && (csrColInd[col] >= csrColInd[col+1])){
fprintf(stderr, "Error (sorting of the column indecis check failed): (csrColInd[%d]=%d) >= (csrColInd[%d]=%d)\n", col, csrColInd[col], col+1, csrColInd[col+1]);
if ((col < (end - 1)) && (csrColInd[col] >= csrColInd[col + 1])) {
fprintf(
stderr,
"Error (sorting of the column indecis check failed): (csrColInd[%d]=%d) >= (csrColInd[%d]=%d)\n",
col,
csrColInd[col],
col + 1,
csrColInd[col + 1]);
error_found = 1;
}
}
}
return error_found ;
return error_found;
}
template <typename T_ELEM>
int loadMMSparseMatrix(
char *filename,
char elem_type,
bool csrFormat,
int *m,
int *n,
int *nnz,
T_ELEM **aVal,
int **aRowInd,
int **aColInd,
int extendSymMatrix)
int loadMMSparseMatrix(char *filename,
char elem_type,
bool csrFormat,
int *m,
int *n,
int *nnz,
T_ELEM **aVal,
int **aRowInd,
int **aColInd,
int extendSymMatrix)
{
MM_typecode matcode;
double *tempVal;
int *tempRowInd,*tempColInd;
double *tval;
int *trow,*tcol;
int *csrRowPtr, *cscColPtr;
int i,j,error,base,count;
MM_typecode matcode;
double *tempVal;
int *tempRowInd, *tempColInd;
double *tval;
int *trow, *tcol;
int *csrRowPtr, *cscColPtr;
int i, j, error, base, count;
struct cooFormat *work;
/* read the matrix */
/* read the matrix */
error = mm_read_mtx_crd(filename, m, n, nnz, &trow, &tcol, &tval, &matcode);
if (error) {
fprintf(stderr, "!!!! can not open file: '%s'\n", filename);
return 1;
return 1;
}
/* start error checking */
if (mm_is_complex(matcode) && ((elem_type != 'z') && (elem_type != 'c'))) {
fprintf(stderr, "!!!! complex matrix requires type 'z' or 'c'\n");
return 1;
return 1;
}
if (mm_is_dense(matcode) || mm_is_array(matcode) || mm_is_pattern(matcode) /*|| mm_is_integer(matcode)*/){
if (mm_is_dense(matcode) || mm_is_array(matcode) || mm_is_pattern(matcode) /*|| mm_is_integer(matcode)*/) {
fprintf(stderr, "!!!! dense, array, pattern and integer matrices are not supported\n");
return 1;
return 1;
}
/* if necessary symmetrize the pattern (transform from triangular to full) */
if ((extendSymMatrix) && (mm_is_symmetric(matcode) || mm_is_hermitian(matcode) || mm_is_skew(matcode))){
//count number of non-diagonal elements
count=0;
for(i=0; i<(*nnz); i++){
if (trow[i] != tcol[i]){
if ((extendSymMatrix) && (mm_is_symmetric(matcode) || mm_is_hermitian(matcode) || mm_is_skew(matcode))) {
// count number of non-diagonal elements
count = 0;
for (i = 0; i < (*nnz); i++) {
if (trow[i] != tcol[i]) {
count++;
}
}
//allocate space for the symmetrized matrix
tempRowInd = (int *)malloc((*nnz + count) * sizeof(int));
tempColInd = (int *)malloc((*nnz + count) * sizeof(int));
if (mm_is_real(matcode) || mm_is_integer(matcode)){
// allocate space for the symmetrized matrix
tempRowInd = (int *)malloc((*nnz + count) * sizeof(int));
tempColInd = (int *)malloc((*nnz + count) * sizeof(int));
if (mm_is_real(matcode) || mm_is_integer(matcode)) {
tempVal = (double *)malloc((*nnz + count) * sizeof(double));
}
else{
else {
tempVal = (double *)malloc(2 * (*nnz + count) * sizeof(double));
}
//copy the elements regular and transposed locations
for(j=0, i=0; i<(*nnz); i++){
tempRowInd[j]=trow[i];
tempColInd[j]=tcol[i];
if (mm_is_real(matcode) || mm_is_integer(matcode)){
tempVal[j]=tval[i];
// copy the elements regular and transposed locations
for (j = 0, i = 0; i < (*nnz); i++) {
tempRowInd[j] = trow[i];
tempColInd[j] = tcol[i];
if (mm_is_real(matcode) || mm_is_integer(matcode)) {
tempVal[j] = tval[i];
}
else{
tempVal[2*j] =tval[2*i];
tempVal[2*j+1]=tval[2*i+1];
else {
tempVal[2 * j] = tval[2 * i];
tempVal[2 * j + 1] = tval[2 * i + 1];
}
j++;
if (trow[i] != tcol[i]){
tempRowInd[j]=tcol[i];
tempColInd[j]=trow[i];
if (mm_is_real(matcode) || mm_is_integer(matcode)){
if (mm_is_skew(matcode)){
tempVal[j]=-tval[i];
if (trow[i] != tcol[i]) {
tempRowInd[j] = tcol[i];
tempColInd[j] = trow[i];
if (mm_is_real(matcode) || mm_is_integer(matcode)) {
if (mm_is_skew(matcode)) {
tempVal[j] = -tval[i];
}
else{
tempVal[j]= tval[i];
else {
tempVal[j] = tval[i];
}
}
else{
if(mm_is_hermitian(matcode)){
tempVal[2*j] = tval[2*i];
tempVal[2*j+1]=-tval[2*i+1];
else {
if (mm_is_hermitian(matcode)) {
tempVal[2 * j] = tval[2 * i];
tempVal[2 * j + 1] = -tval[2 * i + 1];
}
else{
tempVal[2*j] = tval[2*i];
tempVal[2*j+1]= tval[2*i+1];
else {
tempVal[2 * j] = tval[2 * i];
tempVal[2 * j + 1] = tval[2 * i + 1];
}
}
j++;
}
}
(*nnz)+=count;
//free temporary storage
(*nnz) += count;
// free temporary storage
free(trow);
free(tcol);
free(tval);
free(tval);
}
else{
tempRowInd=trow;
tempColInd=tcol;
tempVal =tval;
else {
tempRowInd = trow;
tempColInd = tcol;
tempVal = tval;
}
// life time of (trow, tcol, tval) is over.
// please use COO format (tempRowInd, tempColInd, tempVal)
// use qsort to sort COO format
work = (struct cooFormat *)malloc(sizeof(struct cooFormat)*(*nnz));
if (NULL == work){
// use qsort to sort COO format
work = (struct cooFormat *)malloc(sizeof(struct cooFormat) * (*nnz));
if (NULL == work) {
fprintf(stderr, "!!!! allocation error, malloc failed\n");
return 1;
}
for(i=0; i<(*nnz); i++){
for (i = 0; i < (*nnz); i++) {
work[i].i = tempRowInd[i];
work[i].j = tempColInd[i];
work[i].p = i; // permutation is identity
}
if (csrFormat){
/* create row-major ordering of indices (sorted by row and within each row by column) */
qsort(work, *nnz, sizeof(struct cooFormat), (FUNPTR)fptr_array[0] );
}else{
/* create column-major ordering of indices (sorted by column and within each column by row) */
qsort(work, *nnz, sizeof(struct cooFormat), (FUNPTR)fptr_array[1] );
if (csrFormat) {
/* create row-major ordering of indices (sorted by row and within each row by column) */
qsort(work, *nnz, sizeof(struct cooFormat), (FUNPTR)fptr_array[0]);
}
else {
/* create column-major ordering of indices (sorted by column and within each column by row) */
qsort(work, *nnz, sizeof(struct cooFormat), (FUNPTR)fptr_array[1]);
}
// (tempRowInd, tempColInd) is sorted either by row-major or by col-major
for(i=0; i<(*nnz); i++){
for (i = 0; i < (*nnz); i++) {
tempRowInd[i] = work[i].i;
tempColInd[i] = work[i].j;
}
// setup base
// setup base
// check if there is any row/col 0, if so base-0
// check if there is any row/col equal to matrix dimension m/n, if so base-1
int base0 = 0;
int base1 = 0;
for(i=0; i<(*nnz); i++){
for (i = 0; i < (*nnz); i++) {
const int row = tempRowInd[i];
const int col = tempColInd[i];
if ( (0 == row) || (0 == col) ){
if ((0 == row) || (0 == col)) {
base0 = 1;
}
if ( (*m == row) || (*n == col) ){
if ((*m == row) || (*n == col)) {
base1 = 1;
}
}
if ( base0 && base1 ){
if (base0 && base1) {
printf("Error: input matrix is base-0 and base-1 \n");
return 1;
}
base = 0;
if (base1){
if (base1) {
base = 1;
}
/* compress the appropriate indices */
if (csrFormat){
if (csrFormat) {
/* CSR format (assuming row-major format) */
csrRowPtr = (int *)malloc(((*m)+1) * sizeof(csrRowPtr[0]));
if (!csrRowPtr) return 1;
csrRowPtr = (int *)malloc(((*m) + 1) * sizeof(csrRowPtr[0]));
if (!csrRowPtr)
return 1;
compress_index(tempRowInd, *nnz, *m, csrRowPtr, base);
*aRowInd = csrRowPtr;
@@ -429,101 +377,97 @@ int loadMMSparseMatrix(
}
else {
/* CSC format (assuming column-major format) */
cscColPtr = (int *)malloc(((*n)+1) * sizeof(cscColPtr[0]));
if (!cscColPtr) return 1;
cscColPtr = (int *)malloc(((*n) + 1) * sizeof(cscColPtr[0]));
if (!cscColPtr)
return 1;
compress_index(tempColInd, *nnz, *n, cscColPtr, base);
*aColInd = cscColPtr;
*aRowInd = (int *)malloc((*nnz) * sizeof(int));
}
}
/* transfrom the matrix values of type double into one of the cusparse library types */
/* transfrom the matrix values of type double into one of the cusparse library types */
*aVal = (T_ELEM *)malloc((*nnz) * sizeof(T_ELEM));
for (i=0; i<(*nnz); i++) {
if (csrFormat){
for (i = 0; i < (*nnz); i++) {
if (csrFormat) {
(*aColInd)[i] = tempColInd[i];
}
else{
else {
(*aRowInd)[i] = tempRowInd[i];
}
if (mm_is_real(matcode) || mm_is_integer(matcode)){
(*aVal)[i] = cuGet<T_ELEM>( tempVal[ work[i].p ] );
if (mm_is_real(matcode) || mm_is_integer(matcode)) {
(*aVal)[i] = cuGet<T_ELEM>(tempVal[work[i].p]);
}
else{
(*aVal)[i] = cuGet<T_ELEM>(tempVal[2*work[i].p], tempVal[2*work[i].p+1]);
else {
(*aVal)[i] = cuGet<T_ELEM>(tempVal[2 * work[i].p], tempVal[2 * work[i].p + 1]);
}
}
/* check for corruption */
int error_found;
if (csrFormat){
if (csrFormat) {
error_found = verify_pattern(*m, *nnz, *aRowInd, *aColInd);
}else{
}
else {
error_found = verify_pattern(*n, *nnz, *aColInd, *aRowInd);
}
if (error_found){
if (error_found) {
fprintf(stderr, "!!!! verify_pattern failed\n");
return 1;
}
/* cleanup and exit */
free(work);
free(tempVal);
free(tempVal);
free(tempColInd);
free(tempRowInd);
return 0;
}
}
/* specific instantiation */
template int loadMMSparseMatrix<float>(
char *filename,
char elem_type,
bool csrFormat,
int *m,
int *n,
int *nnz,
float **aVal,
int **aRowInd,
int **aColInd,
int extendSymMatrix);
template int loadMMSparseMatrix<float>(char *filename,
char elem_type,
bool csrFormat,
int *m,
int *n,
int *nnz,
float **aVal,
int **aRowInd,
int **aColInd,
int extendSymMatrix);
template int loadMMSparseMatrix<double>(
char *filename,
char elem_type,
bool csrFormat,
int *m,
int *n,
int *nnz,
double **aVal,
int **aRowInd,
int **aColInd,
int extendSymMatrix);
template int loadMMSparseMatrix<cuComplex>(
char *filename,
char elem_type,
bool csrFormat,
int *m,
int *n,
int *nnz,
cuComplex **aVal,
int **aRowInd,
int **aColInd,
int extendSymMatrix);
template int loadMMSparseMatrix<cuDoubleComplex>(
char *filename,
char elem_type,
bool csrFormat,
int *m,
int *n,
int *nnz,
cuDoubleComplex **aVal,
int **aRowInd,
int **aColInd,
int extendSymMatrix);
template int loadMMSparseMatrix<double>(char *filename,
char elem_type,
bool csrFormat,
int *m,
int *n,
int *nnz,
double **aVal,
int **aRowInd,
int **aColInd,
int extendSymMatrix);
template int loadMMSparseMatrix<cuComplex>(char *filename,
char elem_type,
bool csrFormat,
int *m,
int *n,
int *nnz,
cuComplex **aVal,
int **aRowInd,
int **aColInd,
int extendSymMatrix);
template int loadMMSparseMatrix<cuDoubleComplex>(char *filename,
char elem_type,
bool csrFormat,
int *m,
int *n,
int *nnz,
cuDoubleComplex **aVal,
int **aRowInd,
int **aColInd,
int extendSymMatrix);

View File

@@ -9,64 +9,56 @@
*
*/
#include <assert.h>
#include <ctype.h>
#include <cuda_runtime.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include "cusolverSp.h"
#include "cusolverSp_LOWLEVEL_PREVIEW.h"
#include <cuda_runtime.h>
#include "helper_cuda.h"
#include "helper_cusolver.h"
template <typename T_ELEM>
int loadMMSparseMatrix(
char *filename,
char elem_type,
bool csrFormat,
int *m,
int *n,
int *nnz,
T_ELEM **aVal,
int **aRowInd,
int **aColInd,
int extendSymMatrix);
int loadMMSparseMatrix(char *filename,
char elem_type,
bool csrFormat,
int *m,
int *n,
int *nnz,
T_ELEM **aVal,
int **aRowInd,
int **aColInd,
int extendSymMatrix);
void UsageSP(void)
{
printf( "<options>\n");
printf( "-h : display this help\n");
printf( "-file=<filename> : filename containing a matrix in MM format\n");
printf( "-device=<device_id> : <device_id> if want to run on specific GPU\n");
printf("<options>\n");
printf("-h : display this help\n");
printf("-file=<filename> : filename containing a matrix in MM format\n");
printf("-device=<device_id> : <device_id> if want to run on specific GPU\n");
exit( 0 );
exit(0);
}
void parseCommandLineArguments(int argc, char *argv[], struct testOpts &opts)
{
memset(&opts, 0, sizeof(opts));
if (checkCmdLineFlag(argc, (const char **)argv, "-h"))
{
if (checkCmdLineFlag(argc, (const char **)argv, "-h")) {
UsageSP();
}
if (checkCmdLineFlag(argc, (const char **)argv, "file"))
{
if (checkCmdLineFlag(argc, (const char **)argv, "file")) {
char *fileName = 0;
getCmdLineArgumentString(argc, (const char **)argv, "file", &fileName);
if (fileName)
{
if (fileName) {
opts.sparse_mat_filename = fileName;
}
else
{
else {
printf("\nIncorrect filename passed to -file \n ");
UsageSP();
}
@@ -74,16 +66,16 @@ void parseCommandLineArguments(int argc, char *argv[], struct testOpts &opts)
}
int main (int argc, char *argv[])
int main(int argc, char *argv[])
{
struct testOpts opts;
struct testOpts opts;
cusolverSpHandle_t cusolverSpH = NULL; // reordering, permutation and 1st LU factorization
cusparseHandle_t cusparseH = NULL; // residual evaluation
cudaStream_t stream = NULL;
cusparseMatDescr_t descrA = NULL; // A is a base-0 general matrix
cusparseHandle_t cusparseH = NULL; // residual evaluation
cudaStream_t stream = NULL;
cusparseMatDescr_t descrA = NULL; // A is a base-0 general matrix
csrcholInfoHost_t h_info = NULL; // opaque info structure for LU with parital pivoting
csrcholInfo_t d_info = NULL; // opaque info structure for LU with parital pivoting
csrcholInfo_t d_info = NULL; // opaque info structure for LU with parital pivoting
int rowsA = 0; // number of rows of A
int colsA = 0; // number of columns of A
@@ -91,76 +83,78 @@ int main (int argc, char *argv[])
int baseA = 0; // base index in CSR format
// CSR(A) from I/O
int *h_csrRowPtrA = NULL; // <int> n+1
int *h_csrColIndA = NULL; // <int> nnzA
double *h_csrValA = NULL; // <double> nnzA
int *h_csrRowPtrA = NULL; // <int> n+1
int *h_csrColIndA = NULL; // <int> nnzA
double *h_csrValA = NULL; // <double> nnzA
double *h_x = NULL; // <double> n, x = A \ b
double *h_b = NULL; // <double> n, b = ones(m,1)
double *h_r = NULL; // <double> n, r = b - A*x
size_t size_internal = 0;
size_t size_chol = 0; // size of working space for csrlu
void *buffer_cpu = NULL; // working space for Cholesky
void *buffer_gpu = NULL; // working space for Cholesky
size_t size_internal = 0;
size_t size_chol = 0; // size of working space for csrlu
void *buffer_cpu = NULL; // working space for Cholesky
void *buffer_gpu = NULL; // working space for Cholesky
int *d_csrRowPtrA = NULL; // <int> n+1
int *d_csrColIndA = NULL; // <int> nnzA
double *d_csrValA = NULL; // <double> nnzA
double *d_x = NULL; // <double> n, x = A \ b
double *d_b = NULL; // <double> n, a copy of h_b
double *d_r = NULL; // <double> n, r = b - A*x
int *d_csrRowPtrA = NULL; // <int> n+1
int *d_csrColIndA = NULL; // <int> nnzA
double *d_csrValA = NULL; // <double> nnzA
double *d_x = NULL; // <double> n, x = A \ b
double *d_b = NULL; // <double> n, a copy of h_b
double *d_r = NULL; // <double> n, r = b - A*x
// the constants used in residual evaluation, r = b - A*x
const double minus_one = -1.0;
const double one = 1.0;
const double one = 1.0;
// the constant used in cusolverSp
// singularity is -1 if A is invertible under tol
// tol determines the condition of singularity
int singularity = 0;
const double tol = 1.e-14;
int singularity = 0;
const double tol = 1.e-14;
double x_inf = 0.0; // |x|
double r_inf = 0.0; // |r|
double A_inf = 0.0; // |A|
int errors = 0;
double x_inf = 0.0; // |x|
double r_inf = 0.0; // |r|
double A_inf = 0.0; // |A|
int errors = 0;
parseCommandLineArguments(argc, argv, opts);
findCudaDevice(argc, (const char **)argv);
if (opts.sparse_mat_filename == NULL)
{
opts.sparse_mat_filename = sdkFindFilePath("lap2D_5pt_n100.mtx", argv[0]);
if (opts.sparse_mat_filename == NULL) {
opts.sparse_mat_filename = sdkFindFilePath("lap2D_5pt_n100.mtx", argv[0]);
if (opts.sparse_mat_filename != NULL)
printf("Using default input file [%s]\n", opts.sparse_mat_filename);
else
printf("Could not find lap2D_5pt_n100.mtx\n");
}
else
{
else {
printf("Using input file [%s]\n", opts.sparse_mat_filename);
}
printf("step 1: read matrix market format\n");
if (opts.sparse_mat_filename)
{
if (loadMMSparseMatrix<double>(opts.sparse_mat_filename, 'd', true , &rowsA, &colsA,
&nnzA, &h_csrValA, &h_csrRowPtrA, &h_csrColIndA, true))
{
if (opts.sparse_mat_filename) {
if (loadMMSparseMatrix<double>(opts.sparse_mat_filename,
'd',
true,
&rowsA,
&colsA,
&nnzA,
&h_csrValA,
&h_csrRowPtrA,
&h_csrColIndA,
true)) {
return 1;
}
baseA = h_csrRowPtrA[0]; // baseA = {0,1}
}
else
{
else {
fprintf(stderr, "Error: input matrix is not provided\n");
return 1;
}
if ( rowsA != colsA )
{
if (rowsA != colsA) {
fprintf(stderr, "Error: only support square matrix\n");
return 1;
}
@@ -180,32 +174,29 @@ int main (int argc, char *argv[])
checkCudaErrors(cusparseCreateMatDescr(&descrA));
checkCudaErrors(cusparseSetMatType(descrA, CUSPARSE_MATRIX_TYPE_GENERAL));
if (baseA)
{
if (baseA) {
checkCudaErrors(cusparseSetMatIndexBase(descrA, CUSPARSE_INDEX_BASE_ONE));
}
else
{
else {
checkCudaErrors(cusparseSetMatIndexBase(descrA, CUSPARSE_INDEX_BASE_ZERO));
}
h_x = (double*)malloc(sizeof(double)*colsA);
h_b = (double*)malloc(sizeof(double)*rowsA);
h_r = (double*)malloc(sizeof(double)*rowsA);
h_x = (double *)malloc(sizeof(double) * colsA);
h_b = (double *)malloc(sizeof(double) * rowsA);
h_r = (double *)malloc(sizeof(double) * rowsA);
assert(NULL != h_x);
assert(NULL != h_b);
assert(NULL != h_r);
checkCudaErrors(cudaMalloc((void **)&d_csrRowPtrA, sizeof(int)*(rowsA+1)));
checkCudaErrors(cudaMalloc((void **)&d_csrColIndA, sizeof(int)*nnzA));
checkCudaErrors(cudaMalloc((void **)&d_csrValA , sizeof(double)*nnzA));
checkCudaErrors(cudaMalloc((void **)&d_x, sizeof(double)*colsA));
checkCudaErrors(cudaMalloc((void **)&d_b, sizeof(double)*rowsA));
checkCudaErrors(cudaMalloc((void **)&d_r, sizeof(double)*rowsA));
checkCudaErrors(cudaMalloc((void **)&d_csrRowPtrA, sizeof(int) * (rowsA + 1)));
checkCudaErrors(cudaMalloc((void **)&d_csrColIndA, sizeof(int) * nnzA));
checkCudaErrors(cudaMalloc((void **)&d_csrValA, sizeof(double) * nnzA));
checkCudaErrors(cudaMalloc((void **)&d_x, sizeof(double) * colsA));
checkCudaErrors(cudaMalloc((void **)&d_b, sizeof(double) * rowsA));
checkCudaErrors(cudaMalloc((void **)&d_r, sizeof(double) * rowsA));
for(int row = 0 ; row < rowsA ; row++)
{
for (int row = 0; row < rowsA; row++) {
h_b[row] = 1.0;
}
@@ -213,69 +204,70 @@ int main (int argc, char *argv[])
checkCudaErrors(cusolverSpCreateCsrcholInfoHost(&h_info));
printf("step 3: analyze chol(A) to know structure of L\n");
checkCudaErrors(cusolverSpXcsrcholAnalysisHost(
cusolverSpH, rowsA, nnzA,
descrA, h_csrRowPtrA, h_csrColIndA,
h_info));
checkCudaErrors(
cusolverSpXcsrcholAnalysisHost(cusolverSpH, rowsA, nnzA, descrA, h_csrRowPtrA, h_csrColIndA, h_info));
printf("step 4: workspace for chol(A)\n");
checkCudaErrors(cusolverSpDcsrcholBufferInfoHost(
cusolverSpH, rowsA, nnzA,
descrA, h_csrValA, h_csrRowPtrA, h_csrColIndA,
h_info,
&size_internal,
&size_chol));
cusolverSpH, rowsA, nnzA, descrA, h_csrValA, h_csrRowPtrA, h_csrColIndA, h_info, &size_internal, &size_chol));
if (buffer_cpu)
{
free(buffer_cpu);
if (buffer_cpu) {
free(buffer_cpu);
}
buffer_cpu = (void*)malloc(sizeof(char)*size_chol);
buffer_cpu = (void *)malloc(sizeof(char) * size_chol);
assert(NULL != buffer_cpu);
printf("step 5: compute A = L*L^T \n");
checkCudaErrors(cusolverSpDcsrcholFactorHost(
cusolverSpH, rowsA, nnzA,
descrA, h_csrValA, h_csrRowPtrA, h_csrColIndA,
h_info,
buffer_cpu));
cusolverSpH, rowsA, nnzA, descrA, h_csrValA, h_csrRowPtrA, h_csrColIndA, h_info, buffer_cpu));
printf("step 6: check if the matrix is singular \n");
checkCudaErrors(cusolverSpDcsrcholZeroPivotHost(
cusolverSpH, h_info, tol, &singularity));
checkCudaErrors(cusolverSpDcsrcholZeroPivotHost(cusolverSpH, h_info, tol, &singularity));
if ( 0 <= singularity)
{
if (0 <= singularity) {
fprintf(stderr, "Error: A is not invertible, singularity=%d\n", singularity);
return 1;
}
printf("step 7: solve A*x = b \n");
checkCudaErrors(cusolverSpDcsrcholSolveHost(
cusolverSpH, rowsA, h_b, h_x, h_info, buffer_cpu));
checkCudaErrors(cusolverSpDcsrcholSolveHost(cusolverSpH, rowsA, h_b, h_x, h_info, buffer_cpu));
printf("step 8: evaluate residual r = b - A*x (result on CPU)\n");
// use GPU gemv to compute r = b - A*x
checkCudaErrors(cudaMemcpy(d_csrRowPtrA, h_csrRowPtrA, sizeof(int)*(rowsA+1), cudaMemcpyHostToDevice));
checkCudaErrors(cudaMemcpy(d_csrColIndA, h_csrColIndA, sizeof(int)*nnzA , cudaMemcpyHostToDevice));
checkCudaErrors(cudaMemcpy(d_csrValA , h_csrValA , sizeof(double)*nnzA , cudaMemcpyHostToDevice));
checkCudaErrors(cudaMemcpy(d_csrRowPtrA, h_csrRowPtrA, sizeof(int) * (rowsA + 1), cudaMemcpyHostToDevice));
checkCudaErrors(cudaMemcpy(d_csrColIndA, h_csrColIndA, sizeof(int) * nnzA, cudaMemcpyHostToDevice));
checkCudaErrors(cudaMemcpy(d_csrValA, h_csrValA, sizeof(double) * nnzA, cudaMemcpyHostToDevice));
checkCudaErrors(cudaMemcpy(d_r, h_b, sizeof(double)*rowsA, cudaMemcpyHostToDevice));
checkCudaErrors(cudaMemcpy(d_x, h_x, sizeof(double)*colsA, cudaMemcpyHostToDevice));
checkCudaErrors(cudaMemcpy(d_r, h_b, sizeof(double) * rowsA, cudaMemcpyHostToDevice));
checkCudaErrors(cudaMemcpy(d_x, h_x, sizeof(double) * colsA, cudaMemcpyHostToDevice));
/* Wrap raw data into cuSPARSE generic API objects */
cusparseSpMatDescr_t matA = NULL;
if (baseA)
{
checkCudaErrors(cusparseCreateCsr(
&matA, rowsA, colsA, nnzA, d_csrRowPtrA, d_csrColIndA, d_csrValA, CUSPARSE_INDEX_32I,
CUSPARSE_INDEX_32I, CUSPARSE_INDEX_BASE_ONE, CUDA_R_64F));
if (baseA) {
checkCudaErrors(cusparseCreateCsr(&matA,
rowsA,
colsA,
nnzA,
d_csrRowPtrA,
d_csrColIndA,
d_csrValA,
CUSPARSE_INDEX_32I,
CUSPARSE_INDEX_32I,
CUSPARSE_INDEX_BASE_ONE,
CUDA_R_64F));
}
else
{
checkCudaErrors(cusparseCreateCsr(
&matA, rowsA, colsA, nnzA, d_csrRowPtrA, d_csrColIndA, d_csrValA, CUSPARSE_INDEX_32I,
CUSPARSE_INDEX_32I, CUSPARSE_INDEX_BASE_ZERO, CUDA_R_64F));
else {
checkCudaErrors(cusparseCreateCsr(&matA,
rowsA,
colsA,
nnzA,
d_csrRowPtrA,
d_csrColIndA,
d_csrValA,
CUSPARSE_INDEX_32I,
CUSPARSE_INDEX_32I,
CUSPARSE_INDEX_BASE_ZERO,
CUDA_R_64F));
}
cusparseDnVecDescr_t vecx = NULL;
@@ -285,17 +277,31 @@ int main (int argc, char *argv[])
/* Allocate workspace for cuSPARSE */
size_t bufferSize = 0;
checkCudaErrors(cusparseSpMV_bufferSize(
cusparseH, CUSPARSE_OPERATION_NON_TRANSPOSE, &minus_one, matA, vecx,
&one, vecAx, CUDA_R_64F, CUSPARSE_SPMV_ALG_DEFAULT, &bufferSize));
checkCudaErrors(cusparseSpMV_bufferSize(cusparseH,
CUSPARSE_OPERATION_NON_TRANSPOSE,
&minus_one,
matA,
vecx,
&one,
vecAx,
CUDA_R_64F,
CUSPARSE_SPMV_ALG_DEFAULT,
&bufferSize));
void *buffer = NULL;
checkCudaErrors(cudaMalloc(&buffer, bufferSize));
checkCudaErrors(cusparseSpMV(
cusparseH, CUSPARSE_OPERATION_NON_TRANSPOSE, &minus_one, matA, vecx,
&one, vecAx, CUDA_R_64F, CUSPARSE_SPMV_ALG_DEFAULT, buffer));
checkCudaErrors(cusparseSpMV(cusparseH,
CUSPARSE_OPERATION_NON_TRANSPOSE,
&minus_one,
matA,
vecx,
&one,
vecAx,
CUDA_R_64F,
CUSPARSE_SPMV_ALG_DEFAULT,
buffer));
checkCudaErrors(cudaMemcpy(h_r, d_r, sizeof(double)*rowsA, cudaMemcpyDeviceToHost));
checkCudaErrors(cudaMemcpy(h_r, d_r, sizeof(double) * rowsA, cudaMemcpyDeviceToHost));
x_inf = vec_norminf(colsA, h_x);
r_inf = vec_norminf(rowsA, h_r);
@@ -304,97 +310,137 @@ int main (int argc, char *argv[])
printf("(CPU) |b - A*x| = %E \n", r_inf);
printf("(CPU) |A| = %E \n", A_inf);
printf("(CPU) |x| = %E \n", x_inf);
printf("(CPU) |b - A*x|/(|A|*|x|) = %E \n", r_inf/(A_inf * x_inf));
printf("(CPU) |b - A*x|/(|A|*|x|) = %E \n", r_inf / (A_inf * x_inf));
printf("step 9: create opaque info structure\n");
checkCudaErrors(cusolverSpCreateCsrcholInfo(&d_info));
checkCudaErrors(cudaMemcpy(d_csrRowPtrA, h_csrRowPtrA, sizeof(int)*(rowsA+1), cudaMemcpyHostToDevice));
checkCudaErrors(cudaMemcpy(d_csrColIndA, h_csrColIndA, sizeof(int)*nnzA , cudaMemcpyHostToDevice));
checkCudaErrors(cudaMemcpy(d_csrValA , h_csrValA , sizeof(double)*nnzA , cudaMemcpyHostToDevice));
checkCudaErrors(cudaMemcpy(d_b, h_b, sizeof(double)*rowsA, cudaMemcpyHostToDevice));
checkCudaErrors(cudaMemcpy(d_csrRowPtrA, h_csrRowPtrA, sizeof(int) * (rowsA + 1), cudaMemcpyHostToDevice));
checkCudaErrors(cudaMemcpy(d_csrColIndA, h_csrColIndA, sizeof(int) * nnzA, cudaMemcpyHostToDevice));
checkCudaErrors(cudaMemcpy(d_csrValA, h_csrValA, sizeof(double) * nnzA, cudaMemcpyHostToDevice));
checkCudaErrors(cudaMemcpy(d_b, h_b, sizeof(double) * rowsA, cudaMemcpyHostToDevice));
printf("step 10: analyze chol(A) to know structure of L\n");
checkCudaErrors(cusolverSpXcsrcholAnalysis(
cusolverSpH, rowsA, nnzA,
descrA, d_csrRowPtrA, d_csrColIndA,
d_info));
checkCudaErrors(cusolverSpXcsrcholAnalysis(cusolverSpH, rowsA, nnzA, descrA, d_csrRowPtrA, d_csrColIndA, d_info));
printf("step 11: workspace for chol(A)\n");
checkCudaErrors(cusolverSpDcsrcholBufferInfo(
cusolverSpH, rowsA, nnzA,
descrA, d_csrValA, d_csrRowPtrA, d_csrColIndA,
d_info,
&size_internal,
&size_chol));
cusolverSpH, rowsA, nnzA, descrA, d_csrValA, d_csrRowPtrA, d_csrColIndA, d_info, &size_internal, &size_chol));
if (buffer_gpu) {
checkCudaErrors(cudaFree(buffer_gpu));
}
checkCudaErrors(cudaMalloc(&buffer_gpu, sizeof(char)*size_chol));
checkCudaErrors(cudaMalloc(&buffer_gpu, sizeof(char) * size_chol));
printf("step 12: compute A = L*L^T \n");
checkCudaErrors(cusolverSpDcsrcholFactor(
cusolverSpH, rowsA, nnzA,
descrA, d_csrValA, d_csrRowPtrA, d_csrColIndA,
d_info,
buffer_gpu));
cusolverSpH, rowsA, nnzA, descrA, d_csrValA, d_csrRowPtrA, d_csrColIndA, d_info, buffer_gpu));
printf("step 13: check if the matrix is singular \n");
checkCudaErrors(cusolverSpDcsrcholZeroPivot(
cusolverSpH, d_info, tol, &singularity));
checkCudaErrors(cusolverSpDcsrcholZeroPivot(cusolverSpH, d_info, tol, &singularity));
if ( 0 <= singularity){
if (0 <= singularity) {
fprintf(stderr, "Error: A is not invertible, singularity=%d\n", singularity);
return 1;
}
printf("step 14: solve A*x = b \n");
checkCudaErrors(cusolverSpDcsrcholSolve(
cusolverSpH, rowsA, d_b, d_x, d_info, buffer_gpu));
checkCudaErrors(cusolverSpDcsrcholSolve(cusolverSpH, rowsA, d_b, d_x, d_info, buffer_gpu));
checkCudaErrors(cudaMemcpy(d_r, h_b, sizeof(double)*rowsA, cudaMemcpyHostToDevice));
checkCudaErrors(cudaMemcpy(d_r, h_b, sizeof(double) * rowsA, cudaMemcpyHostToDevice));
checkCudaErrors(cusparseSpMV(
cusparseH, CUSPARSE_OPERATION_NON_TRANSPOSE, &minus_one, matA, vecx,
&one, vecAx, CUDA_R_64F, CUSPARSE_SPMV_ALG_DEFAULT, buffer));
checkCudaErrors(cusparseSpMV(cusparseH,
CUSPARSE_OPERATION_NON_TRANSPOSE,
&minus_one,
matA,
vecx,
&one,
vecAx,
CUDA_R_64F,
CUSPARSE_SPMV_ALG_DEFAULT,
buffer));
checkCudaErrors(cudaMemcpy(h_r, d_r, sizeof(double)*rowsA, cudaMemcpyDeviceToHost));
checkCudaErrors(cudaMemcpy(h_r, d_r, sizeof(double) * rowsA, cudaMemcpyDeviceToHost));
r_inf = vec_norminf(rowsA, h_r);
printf("(GPU) |b - A*x| = %E \n", r_inf);
printf("(GPU) |b - A*x|/(|A|*|x|) = %E \n", r_inf/(A_inf * x_inf));
printf("(GPU) |b - A*x|/(|A|*|x|) = %E \n", r_inf / (A_inf * x_inf));
if (cusolverSpH) { checkCudaErrors(cusolverSpDestroy(cusolverSpH)); }
if (cusparseH ) { checkCudaErrors(cusparseDestroy(cusparseH)); }
if (stream ) { checkCudaErrors(cudaStreamDestroy(stream)); }
if (descrA ) { checkCudaErrors(cusparseDestroyMatDescr(descrA)); }
if (h_info ) { checkCudaErrors(cusolverSpDestroyCsrcholInfoHost(h_info)); }
if (d_info ) { checkCudaErrors(cusolverSpDestroyCsrcholInfo(d_info)); }
if (matA ) { checkCudaErrors(cusparseDestroySpMat(matA)); }
if (vecx ) { checkCudaErrors(cusparseDestroyDnVec(vecx)); }
if (vecAx ) { checkCudaErrors(cusparseDestroyDnVec(vecAx)); }
if (cusolverSpH) {
checkCudaErrors(cusolverSpDestroy(cusolverSpH));
}
if (cusparseH) {
checkCudaErrors(cusparseDestroy(cusparseH));
}
if (stream) {
checkCudaErrors(cudaStreamDestroy(stream));
}
if (descrA) {
checkCudaErrors(cusparseDestroyMatDescr(descrA));
}
if (h_info) {
checkCudaErrors(cusolverSpDestroyCsrcholInfoHost(h_info));
}
if (d_info) {
checkCudaErrors(cusolverSpDestroyCsrcholInfo(d_info));
}
if (matA) {
checkCudaErrors(cusparseDestroySpMat(matA));
}
if (vecx) {
checkCudaErrors(cusparseDestroyDnVec(vecx));
}
if (vecAx) {
checkCudaErrors(cusparseDestroyDnVec(vecAx));
}
if (h_csrValA ) { free(h_csrValA); }
if (h_csrRowPtrA) { free(h_csrRowPtrA); }
if (h_csrColIndA) { free(h_csrColIndA); }
if (h_csrValA) {
free(h_csrValA);
}
if (h_csrRowPtrA) {
free(h_csrRowPtrA);
}
if (h_csrColIndA) {
free(h_csrColIndA);
}
if (h_x ) { free(h_x); }
if (h_b ) { free(h_b); }
if (h_r ) { free(h_r); }
if (h_x) {
free(h_x);
}
if (h_b) {
free(h_b);
}
if (h_r) {
free(h_r);
}
if (buffer_cpu) { free(buffer_cpu); }
if (buffer_gpu) { checkCudaErrors(cudaFree(buffer_gpu)); }
if (buffer_cpu) {
free(buffer_cpu);
}
if (buffer_gpu) {
checkCudaErrors(cudaFree(buffer_gpu));
}
if (d_csrValA ) { checkCudaErrors(cudaFree(d_csrValA)); }
if (d_csrRowPtrA) { checkCudaErrors(cudaFree(d_csrRowPtrA)); }
if (d_csrColIndA) { checkCudaErrors(cudaFree(d_csrColIndA)); }
if (d_x) { checkCudaErrors(cudaFree(d_x)); }
if (d_b) { checkCudaErrors(cudaFree(d_b)); }
if (d_r) { checkCudaErrors(cudaFree(d_r)); }
if (d_csrValA) {
checkCudaErrors(cudaFree(d_csrValA));
}
if (d_csrRowPtrA) {
checkCudaErrors(cudaFree(d_csrRowPtrA));
}
if (d_csrColIndA) {
checkCudaErrors(cudaFree(d_csrColIndA));
}
if (d_x) {
checkCudaErrors(cudaFree(d_x));
}
if (d_b) {
checkCudaErrors(cudaFree(d_b));
}
if (d_r) {
checkCudaErrors(cudaFree(d_r));
}
return 0;
}

View File

@@ -1,128 +1,126 @@
/*
* Matrix Market I/O library for ANSI C
*
* See http://math.nist.gov/MatrixMarket for details.
*
*
*/
/*
* Matrix Market I/O library for ANSI C
*
* See http://math.nist.gov/MatrixMarket for details.
*
*
*/
/* avoid Windows warnings (for example: strcpy, fscanf, etc.) */
#if defined(_WIN32)
#if defined(_WIN32)
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include "mmio.h"
int mm_read_unsymmetric_sparse(const char *fname, int *M_, int *N_, int *nz_,
double **val_, int **I_, int **J_)
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int mm_read_unsymmetric_sparse(const char *fname, int *M_, int *N_, int *nz_, double **val_, int **I_, int **J_)
{
FILE *f;
FILE *f;
MM_typecode matcode;
int M, N, nz;
int i;
double *val;
int *I, *J;
int M, N, nz;
int i;
double *val;
int *I, *J;
if ((f = fopen(fname, "r")) == NULL)
return -1;
if (mm_read_banner(f, &matcode) != 0)
{
return -1;
if (mm_read_banner(f, &matcode) != 0) {
printf("mm_read_unsymetric: Could not process Matrix Market banner ");
printf(" in file [%s]\n", fname);
return -1;
}
if ( !(mm_is_real(matcode) && mm_is_matrix(matcode) &&
mm_is_sparse(matcode)))
{
if (!(mm_is_real(matcode) && mm_is_matrix(matcode) && mm_is_sparse(matcode))) {
fprintf(stderr, "Sorry, this application does not support ");
fprintf(stderr, "Market Market type: [%s]\n",
mm_typecode_to_str(matcode));
fprintf(stderr, "Market Market type: [%s]\n", mm_typecode_to_str(matcode));
return -1;
}
/* find out size of sparse matrix: M, N, nz .... */
if (mm_read_mtx_crd_size(f, &M, &N, &nz) !=0)
{
if (mm_read_mtx_crd_size(f, &M, &N, &nz) != 0) {
fprintf(stderr, "read_unsymmetric_sparse(): could not parse matrix size.\n");
return -1;
}
*M_ = M;
*N_ = N;
*M_ = M;
*N_ = N;
*nz_ = nz;
/* reserve memory for matrices */
I = (int *) malloc(nz * sizeof(int));
J = (int *) malloc(nz * sizeof(int));
val = (double *) malloc(nz * sizeof(double));
I = (int *)malloc(nz * sizeof(int));
J = (int *)malloc(nz * sizeof(int));
val = (double *)malloc(nz * sizeof(double));
*val_ = val;
*I_ = I;
*J_ = J;
*I_ = I;
*J_ = J;
/* NOTE: when reading in doubles, ANSI C requires the use of the "l" */
/* specifier as in "%lg", "%lf", "%le", otherwise errors will occur */
/* (ANSI C X3.159-1989, Sec. 4.9.6.2, p. 136 lines 13-15) */
for (i=0; i<nz; i++)
{
for (i = 0; i < nz; i++) {
if (fscanf(f, "%d %d %lg\n", &I[i], &J[i], &val[i]) != 3) {
return -1;
}
I[i]--; /* adjust from 1-based to 0-based */
I[i]--; /* adjust from 1-based to 0-based */
J[i]--;
}
fclose(f);
return 0;
}
int mm_is_valid(MM_typecode matcode)
{
if (!mm_is_matrix(matcode)) return 0;
if (mm_is_dense(matcode) && mm_is_pattern(matcode)) return 0;
if (mm_is_real(matcode) && mm_is_hermitian(matcode)) return 0;
if (mm_is_pattern(matcode) && (mm_is_hermitian(matcode) ||
mm_is_skew(matcode))) return 0;
if (!mm_is_matrix(matcode))
return 0;
if (mm_is_dense(matcode) && mm_is_pattern(matcode))
return 0;
if (mm_is_real(matcode) && mm_is_hermitian(matcode))
return 0;
if (mm_is_pattern(matcode) && (mm_is_hermitian(matcode) || mm_is_skew(matcode)))
return 0;
return 1;
}
int mm_read_banner(FILE *f, MM_typecode *matcode)
{
char line[MM_MAX_LINE_LENGTH];
char banner[MM_MAX_TOKEN_LENGTH];
char mtx[MM_MAX_TOKEN_LENGTH];
char crd[MM_MAX_TOKEN_LENGTH];
char data_type[MM_MAX_TOKEN_LENGTH];
char storage_scheme[MM_MAX_TOKEN_LENGTH];
char line[MM_MAX_LINE_LENGTH];
char banner[MM_MAX_TOKEN_LENGTH];
char mtx[MM_MAX_TOKEN_LENGTH];
char crd[MM_MAX_TOKEN_LENGTH];
char data_type[MM_MAX_TOKEN_LENGTH];
char storage_scheme[MM_MAX_TOKEN_LENGTH];
char *p;
mm_clear_typecode(matcode);
mm_clear_typecode(matcode);
if (fgets(line, MM_MAX_LINE_LENGTH, f) == NULL)
if (fgets(line, MM_MAX_LINE_LENGTH, f) == NULL)
return MM_PREMATURE_EOF;
if (sscanf(line, "%s %s %s %s %s", banner, mtx, crd, data_type,
storage_scheme) != 5)
if (sscanf(line, "%s %s %s %s %s", banner, mtx, crd, data_type, storage_scheme) != 5)
return MM_PREMATURE_EOF;
for (p=mtx; *p!='\0'; *p=tolower(*p),p++); /* convert to lower case */
for (p=crd; *p!='\0'; *p=tolower(*p),p++);
for (p=data_type; *p!='\0'; *p=tolower(*p),p++);
for (p=storage_scheme; *p!='\0'; *p=tolower(*p),p++);
for (p = mtx; *p != '\0'; *p = tolower(*p), p++)
; /* convert to lower case */
for (p = crd; *p != '\0'; *p = tolower(*p), p++)
;
for (p = data_type; *p != '\0'; *p = tolower(*p), p++)
;
for (p = storage_scheme; *p != '\0'; *p = tolower(*p), p++)
;
/* check for banner */
if (strncmp(banner, MatrixMarketBanner, strlen(MatrixMarketBanner)) != 0)
@@ -130,7 +128,7 @@ int mm_read_banner(FILE *f, MM_typecode *matcode)
/* first field should be "mtx" */
if (strcmp(mtx, MM_MTX_STR) != 0)
return MM_UNSUPPORTED_TYPE;
return MM_UNSUPPORTED_TYPE;
mm_set_matrix(matcode);
@@ -140,46 +138,39 @@ int mm_read_banner(FILE *f, MM_typecode *matcode)
if (strcmp(crd, MM_SPARSE_STR) == 0)
mm_set_sparse(matcode);
else
if (strcmp(crd, MM_DENSE_STR) == 0)
mm_set_dense(matcode);
else if (strcmp(crd, MM_DENSE_STR) == 0)
mm_set_dense(matcode);
else
return MM_UNSUPPORTED_TYPE;
/* third field */
if (strcmp(data_type, MM_REAL_STR) == 0)
mm_set_real(matcode);
else
if (strcmp(data_type, MM_COMPLEX_STR) == 0)
else if (strcmp(data_type, MM_COMPLEX_STR) == 0)
mm_set_complex(matcode);
else
if (strcmp(data_type, MM_PATTERN_STR) == 0)
else if (strcmp(data_type, MM_PATTERN_STR) == 0)
mm_set_pattern(matcode);
else
if (strcmp(data_type, MM_INT_STR) == 0)
else if (strcmp(data_type, MM_INT_STR) == 0)
mm_set_integer(matcode);
else
return MM_UNSUPPORTED_TYPE;
/* fourth field */
if (strcmp(storage_scheme, MM_GENERAL_STR) == 0)
mm_set_general(matcode);
else
if (strcmp(storage_scheme, MM_SYMM_STR) == 0)
else if (strcmp(storage_scheme, MM_SYMM_STR) == 0)
mm_set_symmetric(matcode);
else
if (strcmp(storage_scheme, MM_HERM_STR) == 0)
else if (strcmp(storage_scheme, MM_HERM_STR) == 0)
mm_set_hermitian(matcode);
else
if (strcmp(storage_scheme, MM_SKEW_STR) == 0)
else if (strcmp(storage_scheme, MM_SKEW_STR) == 0)
mm_set_skew(matcode);
else
return MM_UNSUPPORTED_TYPE;
return 0;
}
@@ -188,36 +179,34 @@ int mm_write_mtx_crd_size(FILE *f, int M, int N, int nz)
{
if (fprintf(f, "%d %d %d\n", M, N, nz) != 3)
return MM_COULD_NOT_WRITE_FILE;
else
else
return 0;
}
int mm_read_mtx_crd_size(FILE *f, int *M, int *N, int *nz )
int mm_read_mtx_crd_size(FILE *f, int *M, int *N, int *nz)
{
char line[MM_MAX_LINE_LENGTH];
int num_items_read;
int num_items_read;
/* set return null parameter values, in case we exit with errors */
*M = *N = *nz = 0;
/* now continue scanning until you reach the end-of-comments */
do
{
if (fgets(line,MM_MAX_LINE_LENGTH,f) == NULL)
do {
if (fgets(line, MM_MAX_LINE_LENGTH, f) == NULL)
return MM_PREMATURE_EOF;
}while (line[0] == '%');
} while (line[0] == '%');
/* line[] is either blank or has M,N, nz */
if (sscanf(line, "%d %d %d", M, N, nz) == 3)
return 0;
else
do
{
num_items_read = fscanf(f, "%d %d %d", M, N, nz);
if (num_items_read == EOF) return MM_PREMATURE_EOF;
}
while (num_items_read != 3);
do {
num_items_read = fscanf(f, "%d %d %d", M, N, nz);
if (num_items_read == EOF)
return MM_PREMATURE_EOF;
} while (num_items_read != 3);
return 0;
}
@@ -226,28 +215,26 @@ int mm_read_mtx_crd_size(FILE *f, int *M, int *N, int *nz )
int mm_read_mtx_array_size(FILE *f, int *M, int *N)
{
char line[MM_MAX_LINE_LENGTH];
int num_items_read;
int num_items_read;
/* set return null parameter values, in case we exit with errors */
*M = *N = 0;
/* now continue scanning until you reach the end-of-comments */
do
{
if (fgets(line,MM_MAX_LINE_LENGTH,f) == NULL)
do {
if (fgets(line, MM_MAX_LINE_LENGTH, f) == NULL)
return MM_PREMATURE_EOF;
}while (line[0] == '%');
} while (line[0] == '%');
/* line[] is either blank or has M,N, nz */
if (sscanf(line, "%d %d", M, N) == 2)
return 0;
else /* we have a blank line */
do
{
num_items_read = fscanf(f, "%d %d", M, N);
if (num_items_read == EOF) return MM_PREMATURE_EOF;
}
while (num_items_read != 2);
do {
num_items_read = fscanf(f, "%d %d", M, N);
if (num_items_read == EOF)
return MM_PREMATURE_EOF;
} while (num_items_read != 2);
return 0;
}
@@ -256,43 +243,36 @@ int mm_write_mtx_array_size(FILE *f, int M, int N)
{
if (fprintf(f, "%d %d\n", M, N) != 2)
return MM_COULD_NOT_WRITE_FILE;
else
else
return 0;
}
/*-------------------------------------------------------------------------*/
/******************************************************************/
/* use when I[], J[], and val[]J, and val[] are already allocated */
/******************************************************************/
int mm_read_mtx_crd_data(FILE *f, int M, int N, int nz, int I[], int J[],
double val[], MM_typecode matcode)
int mm_read_mtx_crd_data(FILE *f, int M, int N, int nz, int I[], int J[], double val[], MM_typecode matcode)
{
int i;
if (mm_is_complex(matcode))
{
for (i=0; i<nz; i++)
if (fscanf(f, "%d %d %lg %lg", &I[i], &J[i], &val[2*i], &val[2*i+1])
!= 4) return MM_PREMATURE_EOF;
if (mm_is_complex(matcode)) {
for (i = 0; i < nz; i++)
if (fscanf(f, "%d %d %lg %lg", &I[i], &J[i], &val[2 * i], &val[2 * i + 1]) != 4)
return MM_PREMATURE_EOF;
}
else if (mm_is_real(matcode) || mm_is_integer(matcode))
{
for (i=0; i<nz; i++)
{
if (fscanf(f, "%d %d %lg\n", &I[i], &J[i], &val[i])
!= 3) return MM_PREMATURE_EOF;
else if (mm_is_real(matcode) || mm_is_integer(matcode)) {
for (i = 0; i < nz; i++) {
if (fscanf(f, "%d %d %lg\n", &I[i], &J[i], &val[i]) != 3)
return MM_PREMATURE_EOF;
}
}
else if (mm_is_pattern(matcode))
{
for (i=0; i<nz; i++)
if (fscanf(f, "%d %d", &I[i], &J[i])
!= 2) return MM_PREMATURE_EOF;
else if (mm_is_pattern(matcode)) {
for (i = 0; i < nz; i++)
if (fscanf(f, "%d %d", &I[i], &J[i]) != 2)
return MM_PREMATURE_EOF;
}
else
return MM_UNSUPPORTED_TYPE;
@@ -300,24 +280,20 @@ int mm_read_mtx_crd_data(FILE *f, int M, int N, int nz, int I[], int J[],
return 0;
}
int mm_read_mtx_crd_entry(FILE *f, int *I, int *J,
double *real, double *imag, MM_typecode matcode)
int mm_read_mtx_crd_entry(FILE *f, int *I, int *J, double *real, double *imag, MM_typecode matcode)
{
if (mm_is_complex(matcode))
{
if (fscanf(f, "%d %d %lg %lg", I, J, real, imag)
!= 4) return MM_PREMATURE_EOF;
if (mm_is_complex(matcode)) {
if (fscanf(f, "%d %d %lg %lg", I, J, real, imag) != 4)
return MM_PREMATURE_EOF;
}
else if (mm_is_real(matcode) || mm_is_integer(matcode))
{
if (fscanf(f, "%d %d %lg\n", I, J, real)
!= 3) return MM_PREMATURE_EOF;
else if (mm_is_real(matcode) || mm_is_integer(matcode)) {
if (fscanf(f, "%d %d %lg\n", I, J, real) != 3)
return MM_PREMATURE_EOF;
}
else if (mm_is_pattern(matcode))
{
if (fscanf(f, "%d %d", I, J) != 2) return MM_PREMATURE_EOF;
else if (mm_is_pattern(matcode)) {
if (fscanf(f, "%d %d", I, J) != 2)
return MM_PREMATURE_EOF;
}
else
return MM_UNSUPPORTED_TYPE;
@@ -334,82 +310,76 @@ int mm_read_mtx_crd_entry(FILE *f, int *I, int *J,
(nz pairs of real/imaginary values)
************************************************************************/
int mm_read_mtx_crd(char *fname, int *M, int *N, int *nz, int **I, int **J,
double **val, MM_typecode *matcode)
int mm_read_mtx_crd(char *fname, int *M, int *N, int *nz, int **I, int **J, double **val, MM_typecode *matcode)
{
int ret_code;
int ret_code;
FILE *f;
if (strcmp(fname, "stdin") == 0) f=stdin;
else
if ((f = fopen(fname, "r")) == NULL)
if (strcmp(fname, "stdin") == 0)
f = stdin;
else if ((f = fopen(fname, "r")) == NULL)
return MM_COULD_NOT_READ_FILE;
if ((ret_code = mm_read_banner(f, matcode)) != 0)
return ret_code;
if (!(mm_is_valid(*matcode) && mm_is_sparse(*matcode) &&
mm_is_matrix(*matcode)))
if (!(mm_is_valid(*matcode) && mm_is_sparse(*matcode) && mm_is_matrix(*matcode)))
return MM_UNSUPPORTED_TYPE;
if ((ret_code = mm_read_mtx_crd_size(f, M, N, nz)) != 0)
return ret_code;
*I = (int *) malloc(*nz * sizeof(int));
*J = (int *) malloc(*nz * sizeof(int));
*I = (int *)malloc(*nz * sizeof(int));
*J = (int *)malloc(*nz * sizeof(int));
*val = NULL;
if (mm_is_complex(*matcode))
{
*val = (double *) malloc(*nz * 2 * sizeof(double));
ret_code = mm_read_mtx_crd_data(f, *M, *N, *nz, *I, *J, *val,
*matcode);
if (ret_code != 0) return ret_code;
if (mm_is_complex(*matcode)) {
*val = (double *)malloc(*nz * 2 * sizeof(double));
ret_code = mm_read_mtx_crd_data(f, *M, *N, *nz, *I, *J, *val, *matcode);
if (ret_code != 0)
return ret_code;
}
else if (mm_is_real(*matcode) || mm_is_integer(*matcode))
{
*val = (double *) malloc(*nz * sizeof(double));
ret_code = mm_read_mtx_crd_data(f, *M, *N, *nz, *I, *J, *val,
*matcode);
if (ret_code != 0) return ret_code;
else if (mm_is_real(*matcode) || mm_is_integer(*matcode)) {
*val = (double *)malloc(*nz * sizeof(double));
ret_code = mm_read_mtx_crd_data(f, *M, *N, *nz, *I, *J, *val, *matcode);
if (ret_code != 0)
return ret_code;
}
else if (mm_is_pattern(*matcode))
{
ret_code = mm_read_mtx_crd_data(f, *M, *N, *nz, *I, *J, *val,
*matcode);
if (ret_code != 0) return ret_code;
else if (mm_is_pattern(*matcode)) {
ret_code = mm_read_mtx_crd_data(f, *M, *N, *nz, *I, *J, *val, *matcode);
if (ret_code != 0)
return ret_code;
}
if (f != stdin) fclose(f);
if (f != stdin)
fclose(f);
return 0;
}
int mm_write_banner(FILE *f, MM_typecode matcode)
{
char *str = mm_typecode_to_str(matcode);
int ret_code;
int ret_code;
ret_code = fprintf(f, "%s %s\n", MatrixMarketBanner, str);
free(str);
if (ret_code !=2 )
if (ret_code != 2)
return MM_COULD_NOT_WRITE_FILE;
else
return 0;
}
int mm_write_mtx_crd(char fname[], int M, int N, int nz, int I[], int J[],
double val[], MM_typecode matcode)
int mm_write_mtx_crd(char fname[], int M, int N, int nz, int I[], int J[], double val[], MM_typecode matcode)
{
FILE *f;
int i;
int i;
if (strcmp(fname, "stdout") == 0)
f = stdout;
else
if ((f = fopen(fname, "w")) == NULL)
else if ((f = fopen(fname, "w")) == NULL)
return MM_COULD_NOT_WRITE_FILE;
/* print banner followed by typecode */
@@ -421,50 +391,47 @@ int mm_write_mtx_crd(char fname[], int M, int N, int nz, int I[], int J[],
/* print values */
if (mm_is_pattern(matcode))
for (i=0; i<nz; i++)
for (i = 0; i < nz; i++)
fprintf(f, "%d %d\n", I[i], J[i]);
else
if (mm_is_integer(matcode))
for (i=0; i<nz; i++)
else if (mm_is_integer(matcode))
for (i = 0; i < nz; i++)
fprintf(f, "%d %d %d\n", I[i], J[i], (int)val[i]);
else
if (mm_is_real(matcode))
for (i=0; i<nz; i++)
else if (mm_is_real(matcode))
for (i = 0; i < nz; i++)
fprintf(f, "%d %d %20.16g\n", I[i], J[i], val[i]);
else
if (mm_is_complex(matcode))
for (i=0; i<nz; i++)
fprintf(f, "%d %d %20.16g %20.16g\n", I[i], J[i], val[2*i],
val[2*i+1]);
else
{
if (f != stdout) fclose(f);
else if (mm_is_complex(matcode))
for (i = 0; i < nz; i++)
fprintf(f, "%d %d %20.16g %20.16g\n", I[i], J[i], val[2 * i], val[2 * i + 1]);
else {
if (f != stdout)
fclose(f);
return MM_UNSUPPORTED_TYPE;
}
if (f !=stdout) fclose(f);
if (f != stdout)
fclose(f);
return 0;
}
/**
* Create a new copy of a string s. mm_strdup() is a common routine, but
* not part of ANSI C, so it is included here. Used by mm_typecode_to_str().
*
*/
* Create a new copy of a string s. mm_strdup() is a common routine, but
* not part of ANSI C, so it is included here. Used by mm_typecode_to_str().
*
*/
static char *mm_strdup(const char *s)
{
size_t len = strlen(s);
char *s2 = (char *) malloc((len+1)*sizeof(char));
char *s2 = (char *)malloc((len + 1) * sizeof(char));
return strcpy(s2, s);
}
char *mm_typecode_to_str(MM_typecode matcode)
char *mm_typecode_to_str(MM_typecode matcode)
{
char buffer[MM_MAX_LINE_LENGTH];
char buffer[MM_MAX_LINE_LENGTH];
char *types[4];
//char *mm_strdup(const char *);
//int error =0;
// char *mm_strdup(const char *);
// int error =0;
/* check for MTX type */
if (mm_is_matrix(matcode))
@@ -475,8 +442,7 @@ char *mm_typecode_to_str(MM_typecode matcode)
/* check for CRD or ARR matrix */
if (mm_is_sparse(matcode))
types[1] = MM_SPARSE_STR;
else
if (mm_is_dense(matcode))
else if (mm_is_dense(matcode))
types[1] = MM_DENSE_STR;
else
return NULL;
@@ -484,14 +450,11 @@ char *mm_typecode_to_str(MM_typecode matcode)
/* check for element data type */
if (mm_is_real(matcode))
types[2] = MM_REAL_STR;
else
if (mm_is_complex(matcode))
else if (mm_is_complex(matcode))
types[2] = MM_COMPLEX_STR;
else
if (mm_is_pattern(matcode))
else if (mm_is_pattern(matcode))
types[2] = MM_PATTERN_STR;
else
if (mm_is_integer(matcode))
else if (mm_is_integer(matcode))
types[2] = MM_INT_STR;
else
return NULL;
@@ -500,18 +463,15 @@ char *mm_typecode_to_str(MM_typecode matcode)
/* check for symmetry type */
if (mm_is_general(matcode))
types[3] = MM_GENERAL_STR;
else
if (mm_is_symmetric(matcode))
else if (mm_is_symmetric(matcode))
types[3] = MM_SYMM_STR;
else
if (mm_is_hermitian(matcode))
else if (mm_is_hermitian(matcode))
types[3] = MM_HERM_STR;
else
if (mm_is_skew(matcode))
else if (mm_is_skew(matcode))
types[3] = MM_SKEW_STR;
else
return NULL;
sprintf(buffer,"%s %s %s %s", types[0], types[1], types[2], types[3]);
sprintf(buffer, "%s %s %s %s", types[0], types[1], types[2], types[3]);
return mm_strdup(buffer);
}

View File

@@ -1,141 +1,138 @@
/*
* Matrix Market I/O library for ANSI C
*
* See http://math.nist.gov/MatrixMarket for details.
*
*
*/
/*
* Matrix Market I/O library for ANSI C
*
* See http://math.nist.gov/MatrixMarket for details.
*
*
*/
#ifndef MM_IO_H
#define MM_IO_H
#include <stdio.h>
#if defined(__cplusplus)
extern "C" {
extern "C"
{
#endif /* __cplusplus */
#define MM_MAX_LINE_LENGTH 1025
#define MatrixMarketBanner "%%MatrixMarket"
#define MM_MAX_LINE_LENGTH 1025
#define MatrixMarketBanner "%%MatrixMarket"
#define MM_MAX_TOKEN_LENGTH 64
typedef char MM_typecode[4];
typedef char MM_typecode[4];
char *mm_typecode_to_str(MM_typecode matcode);
char *mm_typecode_to_str(MM_typecode matcode);
int mm_read_banner(FILE *f, MM_typecode *matcode);
int mm_read_mtx_crd_size(FILE *f, int *M, int *N, int *nz);
int mm_read_mtx_array_size(FILE *f, int *M, int *N);
int mm_read_banner(FILE *f, MM_typecode *matcode);
int mm_read_mtx_crd_size(FILE *f, int *M, int *N, int *nz);
int mm_read_mtx_array_size(FILE *f, int *M, int *N);
int mm_write_banner(FILE *f, MM_typecode matcode);
int mm_write_mtx_crd_size(FILE *f, int M, int N, int nz);
int mm_write_mtx_array_size(FILE *f, int M, int N);
int mm_write_banner(FILE *f, MM_typecode matcode);
int mm_write_mtx_crd_size(FILE *f, int M, int N, int nz);
int mm_write_mtx_array_size(FILE *f, int M, int N);
/********************* MM_typecode query fucntions ***************************/
/********************* MM_typecode query fucntions ***************************/
#define mm_is_matrix(typecode) ((typecode)[0]=='M')
#define mm_is_matrix(typecode) ((typecode)[0] == 'M')
#define mm_is_sparse(typecode) ((typecode)[1]=='C')
#define mm_is_coordinate(typecode)((typecode)[1]=='C')
#define mm_is_dense(typecode) ((typecode)[1]=='A')
#define mm_is_array(typecode) ((typecode)[1]=='A')
#define mm_is_sparse(typecode) ((typecode)[1] == 'C')
#define mm_is_coordinate(typecode) ((typecode)[1] == 'C')
#define mm_is_dense(typecode) ((typecode)[1] == 'A')
#define mm_is_array(typecode) ((typecode)[1] == 'A')
#define mm_is_complex(typecode) ((typecode)[2]=='C')
#define mm_is_real(typecode) ((typecode)[2]=='R')
#define mm_is_pattern(typecode) ((typecode)[2]=='P')
#define mm_is_integer(typecode) ((typecode)[2]=='I')
#define mm_is_complex(typecode) ((typecode)[2] == 'C')
#define mm_is_real(typecode) ((typecode)[2] == 'R')
#define mm_is_pattern(typecode) ((typecode)[2] == 'P')
#define mm_is_integer(typecode) ((typecode)[2] == 'I')
#define mm_is_symmetric(typecode)((typecode)[3]=='S')
#define mm_is_general(typecode) ((typecode)[3]=='G')
#define mm_is_skew(typecode) ((typecode)[3]=='K')
#define mm_is_hermitian(typecode)((typecode)[3]=='H')
#define mm_is_symmetric(typecode) ((typecode)[3] == 'S')
#define mm_is_general(typecode) ((typecode)[3] == 'G')
#define mm_is_skew(typecode) ((typecode)[3] == 'K')
#define mm_is_hermitian(typecode) ((typecode)[3] == 'H')
int mm_is_valid(MM_typecode matcode); /* too complex for a macro */
int mm_is_valid(MM_typecode matcode); /* too complex for a macro */
/********************* MM_typecode modify fucntions ***************************/
/********************* MM_typecode modify fucntions ***************************/
#define mm_set_matrix(typecode) ((*typecode)[0]='M')
#define mm_set_coordinate(typecode) ((*typecode)[1]='C')
#define mm_set_array(typecode) ((*typecode)[1]='A')
#define mm_set_dense(typecode) mm_set_array(typecode)
#define mm_set_sparse(typecode) mm_set_coordinate(typecode)
#define mm_set_matrix(typecode) ((*typecode)[0] = 'M')
#define mm_set_coordinate(typecode) ((*typecode)[1] = 'C')
#define mm_set_array(typecode) ((*typecode)[1] = 'A')
#define mm_set_dense(typecode) mm_set_array(typecode)
#define mm_set_sparse(typecode) mm_set_coordinate(typecode)
#define mm_set_complex(typecode)((*typecode)[2]='C')
#define mm_set_real(typecode) ((*typecode)[2]='R')
#define mm_set_pattern(typecode)((*typecode)[2]='P')
#define mm_set_integer(typecode)((*typecode)[2]='I')
#define mm_set_complex(typecode) ((*typecode)[2] = 'C')
#define mm_set_real(typecode) ((*typecode)[2] = 'R')
#define mm_set_pattern(typecode) ((*typecode)[2] = 'P')
#define mm_set_integer(typecode) ((*typecode)[2] = 'I')
#define mm_set_symmetric(typecode)((*typecode)[3]='S')
#define mm_set_general(typecode)((*typecode)[3]='G')
#define mm_set_skew(typecode) ((*typecode)[3]='K')
#define mm_set_hermitian(typecode)((*typecode)[3]='H')
#define mm_set_symmetric(typecode) ((*typecode)[3] = 'S')
#define mm_set_general(typecode) ((*typecode)[3] = 'G')
#define mm_set_skew(typecode) ((*typecode)[3] = 'K')
#define mm_set_hermitian(typecode) ((*typecode)[3] = 'H')
#define mm_clear_typecode(typecode) ((*typecode)[0]=(*typecode)[1]= \
(*typecode)[2]=' ',(*typecode)[3]='G')
#define mm_clear_typecode(typecode) ((*typecode)[0] = (*typecode)[1] = (*typecode)[2] = ' ', (*typecode)[3] = 'G')
#define mm_initialize_typecode(typecode) mm_clear_typecode(typecode)
/********************* Matrix Market error codes ***************************/
/********************* Matrix Market error codes ***************************/
#define MM_COULD_NOT_READ_FILE 11
#define MM_PREMATURE_EOF 12
#define MM_NOT_MTX 13
#define MM_NO_HEADER 14
#define MM_UNSUPPORTED_TYPE 15
#define MM_LINE_TOO_LONG 16
#define MM_COULD_NOT_WRITE_FILE 17
#define MM_COULD_NOT_READ_FILE 11
#define MM_PREMATURE_EOF 12
#define MM_NOT_MTX 13
#define MM_NO_HEADER 14
#define MM_UNSUPPORTED_TYPE 15
#define MM_LINE_TOO_LONG 16
#define MM_COULD_NOT_WRITE_FILE 17
/******************** Matrix Market internal definitions ********************
/******************** Matrix Market internal definitions ********************
MM_matrix_typecode: 4-character sequence
MM_matrix_typecode: 4-character sequence
ojbect sparse/ data storage
dense type scheme
ojbect sparse/ data storage
dense type scheme
string position: [0] [1] [2] [3]
string position: [0] [1] [2] [3]
Matrix typecode: M(atrix) C(oord) R(eal) G(eneral)
A(array) C(omplex) H(ermitian)
P(attern) S(ymmetric)
I(nteger) K(kew)
Matrix typecode: M(atrix) C(oord) R(eal) G(eneral)
A(array) C(omplex) H(ermitian)
P(attern) S(ymmetric)
I(nteger) K(kew)
***********************************************************************/
***********************************************************************/
#define MM_MTX_STR "matrix"
#define MM_ARRAY_STR "array"
#define MM_DENSE_STR "array"
#define MM_COORDINATE_STR "coordinate"
#define MM_SPARSE_STR "coordinate"
#define MM_COMPLEX_STR "complex"
#define MM_REAL_STR "real"
#define MM_INT_STR "integer"
#define MM_GENERAL_STR "general"
#define MM_SYMM_STR "symmetric"
#define MM_HERM_STR "hermitian"
#define MM_SKEW_STR "skew-symmetric"
#define MM_PATTERN_STR "pattern"
#define MM_MTX_STR "matrix"
#define MM_ARRAY_STR "array"
#define MM_DENSE_STR "array"
#define MM_COORDINATE_STR "coordinate"
#define MM_SPARSE_STR "coordinate"
#define MM_COMPLEX_STR "complex"
#define MM_REAL_STR "real"
#define MM_INT_STR "integer"
#define MM_GENERAL_STR "general"
#define MM_SYMM_STR "symmetric"
#define MM_HERM_STR "hermitian"
#define MM_SKEW_STR "skew-symmetric"
#define MM_PATTERN_STR "pattern"
/* high level routines */
int mm_read_mtx_crd(char *fname, int *M, int *N, int *nz, int **I, int **J,
double **val, MM_typecode *matcode);
/* high level routines */
int mm_read_mtx_crd(char *fname, int *M, int *N, int *nz, int **I, int **J, double **val, MM_typecode *matcode);
int mm_write_mtx_crd(char fname[], int M, int N, int nz, int I[], int J[],
double val[], MM_typecode matcode);
int mm_read_mtx_crd_data(FILE *f, int M, int N, int nz, int I[], int J[],
double val[], MM_typecode matcode);
int mm_read_mtx_crd_entry(FILE *f, int *I, int *J, double *real, double *img,
MM_typecode matcode);
int mm_write_mtx_crd(char fname[], int M, int N, int nz, int I[], int J[], double val[], MM_typecode matcode);
int mm_read_mtx_crd_data(FILE *f, int M, int N, int nz, int I[], int J[], double val[], MM_typecode matcode);
int mm_read_mtx_crd_entry(FILE *f, int *I, int *J, double *real, double *img, MM_typecode matcode);
int mm_read_unsymmetric_sparse(const char *fname, int *M_, int *N_, int *nz_,
double **val_, int **I_, int **J_);
int mm_read_unsymmetric_sparse(const char *fname, int *M_, int *N_, int *nz_, double **val_, int **I_, int **J_);
#if defined(__cplusplus)
}
#endif /* __cplusplus */
#endif /* __cplusplus */
#endif

View File

@@ -1,427 +1,375 @@
#include <cusolverDn.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "mmio.h"
#include <cusolverDn.h>
/* avoid Windows warnings (for example: strcpy, fscanf, etc.) */
#if defined(_WIN32)
#if defined(_WIN32)
#define _CRT_SECURE_NO_WARNINGS
#endif
/* various __inline__ __device__ function to initialize a T_ELEM */
template <typename T_ELEM> __inline__ T_ELEM cuGet (int );
template <> __inline__ float cuGet<float >(int x)
{
return float(x);
}
template <typename T_ELEM> __inline__ T_ELEM cuGet(int);
template <> __inline__ float cuGet<float>(int x) { return float(x); }
template <> __inline__ double cuGet<double>(int x)
{
return double(x);
}
template <> __inline__ double cuGet<double>(int x) { return double(x); }
template <> __inline__ cuComplex cuGet<cuComplex>(int x)
{
return (make_cuComplex( float(x), 0.0f ));
}
template <> __inline__ cuComplex cuGet<cuComplex>(int x) { return (make_cuComplex(float(x), 0.0f)); }
template <> __inline__ cuDoubleComplex cuGet<cuDoubleComplex>(int x)
template <> __inline__ cuDoubleComplex cuGet<cuDoubleComplex>(int x) { return (make_cuDoubleComplex(double(x), 0.0)); }
template <typename T_ELEM> __inline__ T_ELEM cuGet(int, int);
template <> __inline__ float cuGet<float>(int x, int y) { return float(x); }
template <> __inline__ double cuGet<double>(int x, int y) { return double(x); }
template <> __inline__ cuComplex cuGet<cuComplex>(int x, int y) { return make_cuComplex(float(x), float(y)); }
template <> __inline__ cuDoubleComplex cuGet<cuDoubleComplex>(int x, int y)
{
return (make_cuDoubleComplex( double(x), 0.0 ));
return (make_cuDoubleComplex(double(x), double(y)));
}
template <typename T_ELEM> __inline__ T_ELEM cuGet (int , int );
template <> __inline__ float cuGet<float >(int x, int y)
{
return float(x);
}
template <typename T_ELEM> __inline__ T_ELEM cuGet(float);
template <> __inline__ float cuGet<float>(float x) { return float(x); }
template <> __inline__ double cuGet<double>(int x, int y)
{
return double(x);
}
template <> __inline__ double cuGet<double>(float x) { return double(x); }
template <> __inline__ cuComplex cuGet<cuComplex>(int x, int y)
{
return make_cuComplex( float(x), float(y) );
}
template <> __inline__ cuComplex cuGet<cuComplex>(float x) { return (make_cuComplex(float(x), 0.0f)); }
template <> __inline__ cuDoubleComplex cuGet<cuDoubleComplex>(int x, int y)
template <> __inline__ cuDoubleComplex cuGet<cuDoubleComplex>(float x)
{
return (make_cuDoubleComplex( double(x), double(y) ));
return (make_cuDoubleComplex(double(x), 0.0));
}
template <typename T_ELEM> __inline__ T_ELEM cuGet (float );
template <> __inline__ float cuGet<float >(float x)
{
return float(x);
}
template <typename T_ELEM> __inline__ T_ELEM cuGet(float, float);
template <> __inline__ float cuGet<float>(float x, float y) { return float(x); }
template <> __inline__ double cuGet<double>(float x)
{
return double(x);
}
template <> __inline__ double cuGet<double>(float x, float y) { return double(x); }
template <> __inline__ cuComplex cuGet<cuComplex>(float x)
{
return (make_cuComplex( float(x), 0.0f ));
}
template <> __inline__ cuComplex cuGet<cuComplex>(float x, float y) { return (make_cuComplex(float(x), float(y))); }
template <> __inline__ cuDoubleComplex cuGet<cuDoubleComplex>(float x)
template <> __inline__ cuDoubleComplex cuGet<cuDoubleComplex>(float x, float y)
{
return (make_cuDoubleComplex( double(x), 0.0 ));
return (make_cuDoubleComplex(double(x), double(y)));
}
template <typename T_ELEM> __inline__ T_ELEM cuGet (float, float );
template <> __inline__ float cuGet<float >(float x, float y)
{
return float(x);
}
template <typename T_ELEM> __inline__ T_ELEM cuGet(double);
template <> __inline__ float cuGet<float>(double x) { return float(x); }
template <> __inline__ double cuGet<double>(float x, float y)
{
return double(x);
}
template <> __inline__ double cuGet<double>(double x) { return double(x); }
template <> __inline__ cuComplex cuGet<cuComplex>(float x, float y)
{
return (make_cuComplex( float(x), float(y) ));
}
template <> __inline__ cuComplex cuGet<cuComplex>(double x) { return (make_cuComplex(float(x), 0.0f)); }
template <> __inline__ cuDoubleComplex cuGet<cuDoubleComplex>(float x, float y)
template <> __inline__ cuDoubleComplex cuGet<cuDoubleComplex>(double x)
{
return (make_cuDoubleComplex( double(x), double(y) ));
return (make_cuDoubleComplex(double(x), 0.0));
}
template <typename T_ELEM> __inline__ T_ELEM cuGet (double );
template <> __inline__ float cuGet<float >(double x)
{
return float(x);
}
template <typename T_ELEM> __inline__ T_ELEM cuGet(double, double);
template <> __inline__ float cuGet<float>(double x, double y) { return float(x); }
template <> __inline__ double cuGet<double>(double x)
{
return double(x);
}
template <> __inline__ double cuGet<double>(double x, double y) { return double(x); }
template <> __inline__ cuComplex cuGet<cuComplex>(double x)
{
return (make_cuComplex( float(x), 0.0f ));
}
template <> __inline__ cuComplex cuGet<cuComplex>(double x, double y) { return (make_cuComplex(float(x), float(y))); }
template <> __inline__ cuDoubleComplex cuGet<cuDoubleComplex>(double x)
template <> __inline__ cuDoubleComplex cuGet<cuDoubleComplex>(double x, double y)
{
return (make_cuDoubleComplex( double(x), 0.0 ));
return (make_cuDoubleComplex(double(x), double(y)));
}
template <typename T_ELEM> __inline__ T_ELEM cuGet (double, double );
template <> __inline__ float cuGet<float >(double x, double y)
{
return float(x);
}
template <> __inline__ double cuGet<double>(double x, double y)
{
return double(x);
}
template <> __inline__ cuComplex cuGet<cuComplex>(double x, double y)
{
return (make_cuComplex( float(x), float(y) ));
}
template <> __inline__ cuDoubleComplex cuGet<cuDoubleComplex>(double x, double y)
{
return (make_cuDoubleComplex( double(x), double(y) ));
}
static void compress_index(
const int *Ind,
int nnz,
int m,
int *Ptr,
int base)
static void compress_index(const int *Ind, int nnz, int m, int *Ptr, int base)
{
int i;
/* initialize everything to zero */
for(i=0; i<m+1; i++){
Ptr[i]=0;
}
for (i = 0; i < m + 1; i++) {
Ptr[i] = 0;
}
/* count elements in every row */
Ptr[0]=base;
for(i=0; i<nnz; i++){
Ptr[Ind[i]+(1-base)]++;
}
Ptr[0] = base;
for (i = 0; i < nnz; i++) {
Ptr[Ind[i] + (1 - base)]++;
}
/* add all the values */
for(i=0; i<m; i++){
Ptr[i+1]+=Ptr[i];
}
for (i = 0; i < m; i++) {
Ptr[i + 1] += Ptr[i];
}
}
struct cooFormat {
int i ;
int j ;
int p ; // permutation
struct cooFormat
{
int i;
int j;
int p; // permutation
};
int cmp_cooFormat_csr( struct cooFormat *s, struct cooFormat *t)
int cmp_cooFormat_csr(struct cooFormat *s, struct cooFormat *t)
{
if ( s->i < t->i ){
return -1 ;
if (s->i < t->i) {
return -1;
}
else if ( s->i > t->i ){
return 1 ;
else if (s->i > t->i) {
return 1;
}
else{
return s->j - t->j ;
else {
return s->j - t->j;
}
}
int cmp_cooFormat_csc( struct cooFormat *s, struct cooFormat *t)
int cmp_cooFormat_csc(struct cooFormat *s, struct cooFormat *t)
{
if ( s->j < t->j ){
return -1 ;
if (s->j < t->j) {
return -1;
}
else if ( s->j > t->j ){
return 1 ;
else if (s->j > t->j) {
return 1;
}
else{
return s->i - t->i ;
else {
return s->i - t->i;
}
}
typedef int (*FUNPTR) (const void*, const void*) ;
typedef int (*FUNPTR2) ( struct cooFormat *s, struct cooFormat *t) ;
typedef int (*FUNPTR)(const void *, const void *);
typedef int (*FUNPTR2)(struct cooFormat *s, struct cooFormat *t);
static FUNPTR2 fptr_array[2] = {
static FUNPTR2 fptr_array[2] = {
cmp_cooFormat_csr,
cmp_cooFormat_csc,
};
static int verify_pattern(
int m,
int nnz,
int *csrRowPtr,
int *csrColInd)
static int verify_pattern(int m, int nnz, int *csrRowPtr, int *csrColInd)
{
int i, col, start, end, base_index;
int error_found = 0;
if (nnz != (csrRowPtr[m] - csrRowPtr[0])){
fprintf(stderr, "Error (nnz check failed): (csrRowPtr[%d]=%d - csrRowPtr[%d]=%d) != (nnz=%d)\n", 0, csrRowPtr[0], m, csrRowPtr[m], nnz);
if (nnz != (csrRowPtr[m] - csrRowPtr[0])) {
fprintf(stderr,
"Error (nnz check failed): (csrRowPtr[%d]=%d - csrRowPtr[%d]=%d) != (nnz=%d)\n",
0,
csrRowPtr[0],
m,
csrRowPtr[m],
nnz);
error_found = 1;
}
base_index = csrRowPtr[0];
if ((0 != base_index) && (1 != base_index)){
if ((0 != base_index) && (1 != base_index)) {
fprintf(stderr, "Error (base index check failed): base index = %d\n", base_index);
error_found = 1;
}
for (i=0; (!error_found) && (i<m); i++){
start = csrRowPtr[i ] - base_index;
end = csrRowPtr[i+1] - base_index;
if (start > end){
fprintf(stderr, "Error (corrupted row): csrRowPtr[%d] (=%d) > csrRowPtr[%d] (=%d)\n", i, start+base_index, i+1, end+base_index);
for (i = 0; (!error_found) && (i < m); i++) {
start = csrRowPtr[i] - base_index;
end = csrRowPtr[i + 1] - base_index;
if (start > end) {
fprintf(stderr,
"Error (corrupted row): csrRowPtr[%d] (=%d) > csrRowPtr[%d] (=%d)\n",
i,
start + base_index,
i + 1,
end + base_index);
error_found = 1;
}
for (col=start; col<end; col++){
if (csrColInd[col] < base_index){
for (col = start; col < end; col++) {
if (csrColInd[col] < base_index) {
fprintf(stderr, "Error (column vs. base index check failed): csrColInd[%d] < %d\n", col, base_index);
error_found = 1;
}
if ((col < (end-1)) && (csrColInd[col] >= csrColInd[col+1])){
fprintf(stderr, "Error (sorting of the column indecis check failed): (csrColInd[%d]=%d) >= (csrColInd[%d]=%d)\n", col, csrColInd[col], col+1, csrColInd[col+1]);
if ((col < (end - 1)) && (csrColInd[col] >= csrColInd[col + 1])) {
fprintf(
stderr,
"Error (sorting of the column indecis check failed): (csrColInd[%d]=%d) >= (csrColInd[%d]=%d)\n",
col,
csrColInd[col],
col + 1,
csrColInd[col + 1]);
error_found = 1;
}
}
}
return error_found ;
return error_found;
}
template <typename T_ELEM>
int loadMMSparseMatrix(
char *filename,
char elem_type,
bool csrFormat,
int *m,
int *n,
int *nnz,
T_ELEM **aVal,
int **aRowInd,
int **aColInd,
int extendSymMatrix)
int loadMMSparseMatrix(char *filename,
char elem_type,
bool csrFormat,
int *m,
int *n,
int *nnz,
T_ELEM **aVal,
int **aRowInd,
int **aColInd,
int extendSymMatrix)
{
MM_typecode matcode;
double *tempVal;
int *tempRowInd,*tempColInd;
double *tval;
int *trow,*tcol;
int *csrRowPtr, *cscColPtr;
int i,j,error,base,count;
MM_typecode matcode;
double *tempVal;
int *tempRowInd, *tempColInd;
double *tval;
int *trow, *tcol;
int *csrRowPtr, *cscColPtr;
int i, j, error, base, count;
struct cooFormat *work;
/* read the matrix */
/* read the matrix */
error = mm_read_mtx_crd(filename, m, n, nnz, &trow, &tcol, &tval, &matcode);
if (error) {
fprintf(stderr, "!!!! can not open file: '%s'\n", filename);
return 1;
return 1;
}
/* start error checking */
if (mm_is_complex(matcode) && ((elem_type != 'z') && (elem_type != 'c'))) {
fprintf(stderr, "!!!! complex matrix requires type 'z' or 'c'\n");
return 1;
return 1;
}
if (mm_is_dense(matcode) || mm_is_array(matcode) || mm_is_pattern(matcode) /*|| mm_is_integer(matcode)*/){
if (mm_is_dense(matcode) || mm_is_array(matcode) || mm_is_pattern(matcode) /*|| mm_is_integer(matcode)*/) {
fprintf(stderr, "!!!! dense, array, pattern and integer matrices are not supported\n");
return 1;
return 1;
}
/* if necessary symmetrize the pattern (transform from triangular to full) */
if ((extendSymMatrix) && (mm_is_symmetric(matcode) || mm_is_hermitian(matcode) || mm_is_skew(matcode))){
//count number of non-diagonal elements
count=0;
for(i=0; i<(*nnz); i++){
if (trow[i] != tcol[i]){
if ((extendSymMatrix) && (mm_is_symmetric(matcode) || mm_is_hermitian(matcode) || mm_is_skew(matcode))) {
// count number of non-diagonal elements
count = 0;
for (i = 0; i < (*nnz); i++) {
if (trow[i] != tcol[i]) {
count++;
}
}
//allocate space for the symmetrized matrix
tempRowInd = (int *)malloc((*nnz + count) * sizeof(int));
tempColInd = (int *)malloc((*nnz + count) * sizeof(int));
if (mm_is_real(matcode) || mm_is_integer(matcode)){
// allocate space for the symmetrized matrix
tempRowInd = (int *)malloc((*nnz + count) * sizeof(int));
tempColInd = (int *)malloc((*nnz + count) * sizeof(int));
if (mm_is_real(matcode) || mm_is_integer(matcode)) {
tempVal = (double *)malloc((*nnz + count) * sizeof(double));
}
else{
else {
tempVal = (double *)malloc(2 * (*nnz + count) * sizeof(double));
}
//copy the elements regular and transposed locations
for(j=0, i=0; i<(*nnz); i++){
tempRowInd[j]=trow[i];
tempColInd[j]=tcol[i];
if (mm_is_real(matcode) || mm_is_integer(matcode)){
tempVal[j]=tval[i];
// copy the elements regular and transposed locations
for (j = 0, i = 0; i < (*nnz); i++) {
tempRowInd[j] = trow[i];
tempColInd[j] = tcol[i];
if (mm_is_real(matcode) || mm_is_integer(matcode)) {
tempVal[j] = tval[i];
}
else{
tempVal[2*j] =tval[2*i];
tempVal[2*j+1]=tval[2*i+1];
else {
tempVal[2 * j] = tval[2 * i];
tempVal[2 * j + 1] = tval[2 * i + 1];
}
j++;
if (trow[i] != tcol[i]){
tempRowInd[j]=tcol[i];
tempColInd[j]=trow[i];
if (mm_is_real(matcode) || mm_is_integer(matcode)){
if (mm_is_skew(matcode)){
tempVal[j]=-tval[i];
if (trow[i] != tcol[i]) {
tempRowInd[j] = tcol[i];
tempColInd[j] = trow[i];
if (mm_is_real(matcode) || mm_is_integer(matcode)) {
if (mm_is_skew(matcode)) {
tempVal[j] = -tval[i];
}
else{
tempVal[j]= tval[i];
else {
tempVal[j] = tval[i];
}
}
else{
if(mm_is_hermitian(matcode)){
tempVal[2*j] = tval[2*i];
tempVal[2*j+1]=-tval[2*i+1];
else {
if (mm_is_hermitian(matcode)) {
tempVal[2 * j] = tval[2 * i];
tempVal[2 * j + 1] = -tval[2 * i + 1];
}
else{
tempVal[2*j] = tval[2*i];
tempVal[2*j+1]= tval[2*i+1];
else {
tempVal[2 * j] = tval[2 * i];
tempVal[2 * j + 1] = tval[2 * i + 1];
}
}
j++;
}
}
(*nnz)+=count;
//free temporary storage
(*nnz) += count;
// free temporary storage
free(trow);
free(tcol);
free(tval);
free(tval);
}
else{
tempRowInd=trow;
tempColInd=tcol;
tempVal =tval;
else {
tempRowInd = trow;
tempColInd = tcol;
tempVal = tval;
}
// life time of (trow, tcol, tval) is over.
// please use COO format (tempRowInd, tempColInd, tempVal)
// use qsort to sort COO format
work = (struct cooFormat *)malloc(sizeof(struct cooFormat)*(*nnz));
if (NULL == work){
// use qsort to sort COO format
work = (struct cooFormat *)malloc(sizeof(struct cooFormat) * (*nnz));
if (NULL == work) {
fprintf(stderr, "!!!! allocation error, malloc failed\n");
return 1;
}
for(i=0; i<(*nnz); i++){
for (i = 0; i < (*nnz); i++) {
work[i].i = tempRowInd[i];
work[i].j = tempColInd[i];
work[i].p = i; // permutation is identity
}
if (csrFormat){
/* create row-major ordering of indices (sorted by row and within each row by column) */
qsort(work, *nnz, sizeof(struct cooFormat), (FUNPTR)fptr_array[0] );
}else{
/* create column-major ordering of indices (sorted by column and within each column by row) */
qsort(work, *nnz, sizeof(struct cooFormat), (FUNPTR)fptr_array[1] );
if (csrFormat) {
/* create row-major ordering of indices (sorted by row and within each row by column) */
qsort(work, *nnz, sizeof(struct cooFormat), (FUNPTR)fptr_array[0]);
}
else {
/* create column-major ordering of indices (sorted by column and within each column by row) */
qsort(work, *nnz, sizeof(struct cooFormat), (FUNPTR)fptr_array[1]);
}
// (tempRowInd, tempColInd) is sorted either by row-major or by col-major
for(i=0; i<(*nnz); i++){
for (i = 0; i < (*nnz); i++) {
tempRowInd[i] = work[i].i;
tempColInd[i] = work[i].j;
}
// setup base
// setup base
// check if there is any row/col 0, if so base-0
// check if there is any row/col equal to matrix dimension m/n, if so base-1
int base0 = 0;
int base1 = 0;
for(i=0; i<(*nnz); i++){
for (i = 0; i < (*nnz); i++) {
const int row = tempRowInd[i];
const int col = tempColInd[i];
if ( (0 == row) || (0 == col) ){
if ((0 == row) || (0 == col)) {
base0 = 1;
}
if ( (*m == row) || (*n == col) ){
if ((*m == row) || (*n == col)) {
base1 = 1;
}
}
if ( base0 && base1 ){
if (base0 && base1) {
printf("Error: input matrix is base-0 and base-1 \n");
return 1;
}
base = 0;
if (base1){
if (base1) {
base = 1;
}
/* compress the appropriate indices */
if (csrFormat){
if (csrFormat) {
/* CSR format (assuming row-major format) */
csrRowPtr = (int *)malloc(((*m)+1) * sizeof(csrRowPtr[0]));
if (!csrRowPtr) return 1;
csrRowPtr = (int *)malloc(((*m) + 1) * sizeof(csrRowPtr[0]));
if (!csrRowPtr)
return 1;
compress_index(tempRowInd, *nnz, *m, csrRowPtr, base);
*aRowInd = csrRowPtr;
@@ -429,101 +377,97 @@ int loadMMSparseMatrix(
}
else {
/* CSC format (assuming column-major format) */
cscColPtr = (int *)malloc(((*n)+1) * sizeof(cscColPtr[0]));
if (!cscColPtr) return 1;
cscColPtr = (int *)malloc(((*n) + 1) * sizeof(cscColPtr[0]));
if (!cscColPtr)
return 1;
compress_index(tempColInd, *nnz, *n, cscColPtr, base);
*aColInd = cscColPtr;
*aRowInd = (int *)malloc((*nnz) * sizeof(int));
}
}
/* transfrom the matrix values of type double into one of the cusparse library types */
/* transfrom the matrix values of type double into one of the cusparse library types */
*aVal = (T_ELEM *)malloc((*nnz) * sizeof(T_ELEM));
for (i=0; i<(*nnz); i++) {
if (csrFormat){
for (i = 0; i < (*nnz); i++) {
if (csrFormat) {
(*aColInd)[i] = tempColInd[i];
}
else{
else {
(*aRowInd)[i] = tempRowInd[i];
}
if (mm_is_real(matcode) || mm_is_integer(matcode)){
(*aVal)[i] = cuGet<T_ELEM>( tempVal[ work[i].p ] );
if (mm_is_real(matcode) || mm_is_integer(matcode)) {
(*aVal)[i] = cuGet<T_ELEM>(tempVal[work[i].p]);
}
else{
(*aVal)[i] = cuGet<T_ELEM>(tempVal[2*work[i].p], tempVal[2*work[i].p+1]);
else {
(*aVal)[i] = cuGet<T_ELEM>(tempVal[2 * work[i].p], tempVal[2 * work[i].p + 1]);
}
}
/* check for corruption */
int error_found;
if (csrFormat){
if (csrFormat) {
error_found = verify_pattern(*m, *nnz, *aRowInd, *aColInd);
}else{
}
else {
error_found = verify_pattern(*n, *nnz, *aColInd, *aRowInd);
}
if (error_found){
if (error_found) {
fprintf(stderr, "!!!! verify_pattern failed\n");
return 1;
}
/* cleanup and exit */
free(work);
free(tempVal);
free(tempVal);
free(tempColInd);
free(tempRowInd);
return 0;
}
}
/* specific instantiation */
template int loadMMSparseMatrix<float>(
char *filename,
char elem_type,
bool csrFormat,
int *m,
int *n,
int *nnz,
float **aVal,
int **aRowInd,
int **aColInd,
int extendSymMatrix);
template int loadMMSparseMatrix<float>(char *filename,
char elem_type,
bool csrFormat,
int *m,
int *n,
int *nnz,
float **aVal,
int **aRowInd,
int **aColInd,
int extendSymMatrix);
template int loadMMSparseMatrix<double>(
char *filename,
char elem_type,
bool csrFormat,
int *m,
int *n,
int *nnz,
double **aVal,
int **aRowInd,
int **aColInd,
int extendSymMatrix);
template int loadMMSparseMatrix<cuComplex>(
char *filename,
char elem_type,
bool csrFormat,
int *m,
int *n,
int *nnz,
cuComplex **aVal,
int **aRowInd,
int **aColInd,
int extendSymMatrix);
template int loadMMSparseMatrix<cuDoubleComplex>(
char *filename,
char elem_type,
bool csrFormat,
int *m,
int *n,
int *nnz,
cuDoubleComplex **aVal,
int **aRowInd,
int **aColInd,
int extendSymMatrix);
template int loadMMSparseMatrix<double>(char *filename,
char elem_type,
bool csrFormat,
int *m,
int *n,
int *nnz,
double **aVal,
int **aRowInd,
int **aColInd,
int extendSymMatrix);
template int loadMMSparseMatrix<cuComplex>(char *filename,
char elem_type,
bool csrFormat,
int *m,
int *n,
int *nnz,
cuComplex **aVal,
int **aRowInd,
int **aColInd,
int extendSymMatrix);
template int loadMMSparseMatrix<cuDoubleComplex>(char *filename,
char elem_type,
bool csrFormat,
int *m,
int *n,
int *nnz,
cuDoubleComplex **aVal,
int **aRowInd,
int **aColInd,
int extendSymMatrix);

View File

@@ -38,412 +38,453 @@
#include "helper_cusolver.h"
template <typename T_ELEM>
int loadMMSparseMatrix(char *filename, char elem_type, bool csrFormat, int *m,
int *n, int *nnz, T_ELEM **aVal, int **aRowInd,
int **aColInd, int extendSymMatrix);
int loadMMSparseMatrix(char *filename,
char elem_type,
bool csrFormat,
int *m,
int *n,
int *nnz,
T_ELEM **aVal,
int **aRowInd,
int **aColInd,
int extendSymMatrix);
void UsageSP(void) {
printf("<options>\n");
printf("-h : display this help\n");
printf("-file=<filename> : filename containing a matrix in MM format\n");
printf("-device=<device_id> : <device_id> if want to run on specific GPU\n");
void UsageSP(void)
{
printf("<options>\n");
printf("-h : display this help\n");
printf("-file=<filename> : filename containing a matrix in MM format\n");
printf("-device=<device_id> : <device_id> if want to run on specific GPU\n");
exit(0);
exit(0);
}
void parseCommandLineArguments(int argc, char *argv[], struct testOpts &opts) {
memset(&opts, 0, sizeof(opts));
void parseCommandLineArguments(int argc, char *argv[], struct testOpts &opts)
{
memset(&opts, 0, sizeof(opts));
if (checkCmdLineFlag(argc, (const char **)argv, "-h")) {
UsageSP();
}
if (checkCmdLineFlag(argc, (const char **)argv, "file")) {
char *fileName = 0;
getCmdLineArgumentString(argc, (const char **)argv, "file", &fileName);
if (fileName) {
opts.sparse_mat_filename = fileName;
} else {
printf("\nIncorrect filename passed to -file \n ");
UsageSP();
if (checkCmdLineFlag(argc, (const char **)argv, "-h")) {
UsageSP();
}
}
}
int main(int argc, char *argv[]) {
struct testOpts opts;
cusolverSpHandle_t cusolverSpH =
NULL; // reordering, permutation and 1st LU factorization
cusparseHandle_t cusparseH = NULL; // residual evaluation
cudaStream_t stream = NULL;
cusparseMatDescr_t descrA = NULL; // A is a base-0 general matrix
if (checkCmdLineFlag(argc, (const char **)argv, "file")) {
char *fileName = 0;
getCmdLineArgumentString(argc, (const char **)argv, "file", &fileName);
csrqrInfoHost_t h_info =
NULL; // opaque info structure for LU with parital pivoting
csrqrInfo_t d_info =
NULL; // opaque info structure for LU with parital pivoting
int rowsA = 0; // number of rows of A
int colsA = 0; // number of columns of A
int nnzA = 0; // number of nonzeros of A
int baseA = 0; // base index in CSR format
// CSR(A) from I/O
int *h_csrRowPtrA = NULL; // <int> n+1
int *h_csrColIndA = NULL; // <int> nnzA
double *h_csrValA = NULL; // <double> nnzA
double *h_x = NULL; // <double> n, x = A \ b
double *h_b = NULL; // <double> n, b = ones(m,1)
double *h_bcopy = NULL; // <double> n, b = ones(m,1)
double *h_r = NULL; // <double> n, r = b - A*x
size_t size_internal = 0;
size_t size_chol = 0; // size of working space for csrlu
void *buffer_cpu = NULL; // working space for Cholesky
void *buffer_gpu = NULL; // working space for Cholesky
int *d_csrRowPtrA = NULL; // <int> n+1
int *d_csrColIndA = NULL; // <int> nnzA
double *d_csrValA = NULL; // <double> nnzA
double *d_x = NULL; // <double> n, x = A \ b
double *d_b = NULL; // <double> n, a copy of h_b
double *d_r = NULL; // <double> n, r = b - A*x
// the constants used in residual evaluation, r = b - A*x
const double minus_one = -1.0;
const double one = 1.0;
const double zero = 0.0;
// the constant used in cusolverSp
// singularity is -1 if A is invertible under tol
// tol determines the condition of singularity
int singularity = 0;
const double tol = 1.e-14;
double x_inf = 0.0; // |x|
double r_inf = 0.0; // |r|
double A_inf = 0.0; // |A|
parseCommandLineArguments(argc, argv, opts);
findCudaDevice(argc, (const char **)argv);
if (opts.sparse_mat_filename == NULL) {
opts.sparse_mat_filename = sdkFindFilePath("lap2D_5pt_n32.mtx", argv[0]);
if (opts.sparse_mat_filename != NULL)
printf("Using default input file [%s]\n", opts.sparse_mat_filename);
else
printf("Could not find lap2D_5pt_n32.mtx\n");
} else {
printf("Using input file [%s]\n", opts.sparse_mat_filename);
}
printf("step 1: read matrix market format\n");
if (opts.sparse_mat_filename) {
if (loadMMSparseMatrix<double>(opts.sparse_mat_filename, 'd', true, &rowsA,
&colsA, &nnzA, &h_csrValA, &h_csrRowPtrA,
&h_csrColIndA, true)) {
return 1;
if (fileName) {
opts.sparse_mat_filename = fileName;
}
else {
printf("\nIncorrect filename passed to -file \n ");
UsageSP();
}
}
baseA = h_csrRowPtrA[0]; // baseA = {0,1}
} else {
fprintf(stderr, "Error: input matrix is not provided\n");
return 1;
}
if (rowsA != colsA) {
fprintf(stderr, "Error: only support square matrix\n");
return 1;
}
printf("sparse matrix A is %d x %d with %d nonzeros, base=%d\n", rowsA, colsA,
nnzA, baseA);
checkCudaErrors(cusolverSpCreate(&cusolverSpH));
checkCudaErrors(cusparseCreate(&cusparseH));
checkCudaErrors(cudaStreamCreate(&stream));
checkCudaErrors(cusolverSpSetStream(cusolverSpH, stream));
checkCudaErrors(cusparseSetStream(cusparseH, stream));
checkCudaErrors(cusparseCreateMatDescr(&descrA));
checkCudaErrors(cusparseSetMatType(descrA, CUSPARSE_MATRIX_TYPE_GENERAL));
if (baseA) {
checkCudaErrors(cusparseSetMatIndexBase(descrA, CUSPARSE_INDEX_BASE_ONE));
} else {
checkCudaErrors(cusparseSetMatIndexBase(descrA, CUSPARSE_INDEX_BASE_ZERO));
}
h_x = (double *)malloc(sizeof(double) * colsA);
h_b = (double *)malloc(sizeof(double) * rowsA);
h_bcopy = (double *)malloc(sizeof(double) * rowsA);
h_r = (double *)malloc(sizeof(double) * rowsA);
assert(NULL != h_x);
assert(NULL != h_b);
assert(NULL != h_bcopy);
assert(NULL != h_r);
checkCudaErrors(
cudaMalloc((void **)&d_csrRowPtrA, sizeof(int) * (rowsA + 1)));
checkCudaErrors(cudaMalloc((void **)&d_csrColIndA, sizeof(int) * nnzA));
checkCudaErrors(cudaMalloc((void **)&d_csrValA, sizeof(double) * nnzA));
checkCudaErrors(cudaMalloc((void **)&d_x, sizeof(double) * colsA));
checkCudaErrors(cudaMalloc((void **)&d_b, sizeof(double) * rowsA));
checkCudaErrors(cudaMalloc((void **)&d_r, sizeof(double) * rowsA));
for (int row = 0; row < rowsA; row++) {
h_b[row] = 1.0;
}
memcpy(h_bcopy, h_b, sizeof(double) * rowsA);
printf("step 2: create opaque info structure\n");
checkCudaErrors(cusolverSpCreateCsrqrInfoHost(&h_info));
printf("step 3: analyze qr(A) to know structure of L\n");
checkCudaErrors(cusolverSpXcsrqrAnalysisHost(cusolverSpH, rowsA, colsA, nnzA,
descrA, h_csrRowPtrA,
h_csrColIndA, h_info));
printf("step 4: workspace for qr(A)\n");
checkCudaErrors(cusolverSpDcsrqrBufferInfoHost(
cusolverSpH, rowsA, colsA, nnzA, descrA, h_csrValA, h_csrRowPtrA,
h_csrColIndA, h_info, &size_internal, &size_chol));
if (buffer_cpu) {
free(buffer_cpu);
}
buffer_cpu = (void *)malloc(sizeof(char) * size_chol);
assert(NULL != buffer_cpu);
printf("step 5: compute A = L*L^T \n");
checkCudaErrors(cusolverSpDcsrqrSetupHost(cusolverSpH, rowsA, colsA, nnzA,
descrA, h_csrValA, h_csrRowPtrA,
h_csrColIndA, zero, h_info));
checkCudaErrors(cusolverSpDcsrqrFactorHost(cusolverSpH, rowsA, colsA, nnzA,
NULL, NULL, h_info, buffer_cpu));
printf("step 6: check if the matrix is singular \n");
checkCudaErrors(
cusolverSpDcsrqrZeroPivotHost(cusolverSpH, h_info, tol, &singularity));
if (0 <= singularity) {
fprintf(stderr, "Error: A is not invertible, singularity=%d\n",
singularity);
return 1;
}
printf("step 7: solve A*x = b \n");
checkCudaErrors(cusolverSpDcsrqrSolveHost(cusolverSpH, rowsA, colsA, h_b, h_x,
h_info, buffer_cpu));
printf("step 8: evaluate residual r = b - A*x (result on CPU)\n");
// use GPU gemv to compute r = b - A*x
checkCudaErrors(cudaMemcpy(d_csrRowPtrA, h_csrRowPtrA,
sizeof(int) * (rowsA + 1),
cudaMemcpyHostToDevice));
checkCudaErrors(cudaMemcpy(d_csrColIndA, h_csrColIndA, sizeof(int) * nnzA,
cudaMemcpyHostToDevice));
checkCudaErrors(cudaMemcpy(d_csrValA, h_csrValA, sizeof(double) * nnzA,
cudaMemcpyHostToDevice));
checkCudaErrors(
cudaMemcpy(d_r, h_bcopy, sizeof(double) * rowsA, cudaMemcpyHostToDevice));
checkCudaErrors(
cudaMemcpy(d_x, h_x, sizeof(double) * colsA, cudaMemcpyHostToDevice));
/* Wrap raw data into cuSPARSE generic API objects */
cusparseSpMatDescr_t matA = NULL;
if (baseA) {
checkCudaErrors(cusparseCreateCsr(&matA, rowsA, colsA, nnzA, d_csrRowPtrA,
d_csrColIndA, d_csrValA,
CUSPARSE_INDEX_32I, CUSPARSE_INDEX_32I,
CUSPARSE_INDEX_BASE_ONE, CUDA_R_64F));
} else {
checkCudaErrors(cusparseCreateCsr(&matA, rowsA, colsA, nnzA, d_csrRowPtrA,
d_csrColIndA, d_csrValA,
CUSPARSE_INDEX_32I, CUSPARSE_INDEX_32I,
CUSPARSE_INDEX_BASE_ZERO, CUDA_R_64F));
}
cusparseDnVecDescr_t vecx = NULL;
checkCudaErrors(cusparseCreateDnVec(&vecx, colsA, d_x, CUDA_R_64F));
cusparseDnVecDescr_t vecAx = NULL;
checkCudaErrors(cusparseCreateDnVec(&vecAx, rowsA, d_r, CUDA_R_64F));
/* Allocate workspace for cuSPARSE */
size_t bufferSize = 0;
checkCudaErrors(cusparseSpMV_bufferSize(
cusparseH, CUSPARSE_OPERATION_NON_TRANSPOSE, &minus_one, matA, vecx, &one,
vecAx, CUDA_R_64F, CUSPARSE_SPMV_ALG_DEFAULT, &bufferSize));
void *buffer = NULL;
checkCudaErrors(cudaMalloc(&buffer, bufferSize));
checkCudaErrors(cusparseSpMV(cusparseH, CUSPARSE_OPERATION_NON_TRANSPOSE,
&minus_one, matA, vecx, &one, vecAx, CUDA_R_64F,
CUSPARSE_SPMV_ALG_DEFAULT, buffer));
checkCudaErrors(
cudaMemcpy(h_r, d_r, sizeof(double) * rowsA, cudaMemcpyDeviceToHost));
x_inf = vec_norminf(colsA, h_x);
r_inf = vec_norminf(rowsA, h_r);
A_inf = csr_mat_norminf(rowsA, colsA, nnzA, descrA, h_csrValA, h_csrRowPtrA,
h_csrColIndA);
printf("(CPU) |b - A*x| = %E \n", r_inf);
printf("(CPU) |A| = %E \n", A_inf);
printf("(CPU) |x| = %E \n", x_inf);
printf("(CPU) |b - A*x|/(|A|*|x|) = %E \n", r_inf / (A_inf * x_inf));
printf("step 9: create opaque info structure\n");
checkCudaErrors(cusolverSpCreateCsrqrInfo(&d_info));
checkCudaErrors(cudaMemcpy(d_csrRowPtrA, h_csrRowPtrA,
sizeof(int) * (rowsA + 1),
cudaMemcpyHostToDevice));
checkCudaErrors(cudaMemcpy(d_csrColIndA, h_csrColIndA, sizeof(int) * nnzA,
cudaMemcpyHostToDevice));
checkCudaErrors(cudaMemcpy(d_csrValA, h_csrValA, sizeof(double) * nnzA,
cudaMemcpyHostToDevice));
checkCudaErrors(
cudaMemcpy(d_b, h_bcopy, sizeof(double) * rowsA, cudaMemcpyHostToDevice));
printf("step 10: analyze qr(A) to know structure of L\n");
checkCudaErrors(cusolverSpXcsrqrAnalysis(cusolverSpH, rowsA, colsA, nnzA,
descrA, d_csrRowPtrA, d_csrColIndA,
d_info));
printf("step 11: workspace for qr(A)\n");
checkCudaErrors(cusolverSpDcsrqrBufferInfo(
cusolverSpH, rowsA, colsA, nnzA, descrA, d_csrValA, d_csrRowPtrA,
d_csrColIndA, d_info, &size_internal, &size_chol));
printf("GPU buffer size = %lld bytes\n", (signed long long)size_chol);
if (buffer_gpu) {
checkCudaErrors(cudaFree(buffer_gpu));
}
checkCudaErrors(cudaMalloc(&buffer_gpu, sizeof(char) * size_chol));
printf("step 12: compute A = L*L^T \n");
checkCudaErrors(cusolverSpDcsrqrSetup(cusolverSpH, rowsA, colsA, nnzA, descrA,
d_csrValA, d_csrRowPtrA, d_csrColIndA,
zero, d_info));
checkCudaErrors(cusolverSpDcsrqrFactor(cusolverSpH, rowsA, colsA, nnzA, NULL,
NULL, d_info, buffer_gpu));
printf("step 13: check if the matrix is singular \n");
checkCudaErrors(
cusolverSpDcsrqrZeroPivot(cusolverSpH, d_info, tol, &singularity));
if (0 <= singularity) {
fprintf(stderr, "Error: A is not invertible, singularity=%d\n",
singularity);
return 1;
}
printf("step 14: solve A*x = b \n");
checkCudaErrors(cusolverSpDcsrqrSolve(cusolverSpH, rowsA, colsA, d_b, d_x,
d_info, buffer_gpu));
checkCudaErrors(
cudaMemcpy(d_r, h_bcopy, sizeof(double) * rowsA, cudaMemcpyHostToDevice));
checkCudaErrors(cusparseSpMV(cusparseH, CUSPARSE_OPERATION_NON_TRANSPOSE,
&minus_one, matA, vecx, &one, vecAx, CUDA_R_64F,
CUSPARSE_SPMV_ALG_DEFAULT, buffer));
checkCudaErrors(
cudaMemcpy(h_r, d_r, sizeof(double) * rowsA, cudaMemcpyDeviceToHost));
r_inf = vec_norminf(rowsA, h_r);
printf("(GPU) |b - A*x| = %E \n", r_inf);
printf("(GPU) |b - A*x|/(|A|*|x|) = %E \n", r_inf / (A_inf * x_inf));
if (cusolverSpH) {
checkCudaErrors(cusolverSpDestroy(cusolverSpH));
}
if (cusparseH) {
checkCudaErrors(cusparseDestroy(cusparseH));
}
if (stream) {
checkCudaErrors(cudaStreamDestroy(stream));
}
if (descrA) {
checkCudaErrors(cusparseDestroyMatDescr(descrA));
}
if (h_info) {
checkCudaErrors(cusolverSpDestroyCsrqrInfoHost(h_info));
}
if (d_info) {
checkCudaErrors(cusolverSpDestroyCsrqrInfo(d_info));
}
if (matA) {
checkCudaErrors(cusparseDestroySpMat(matA));
}
if (vecx) {
checkCudaErrors(cusparseDestroyDnVec(vecx));
}
if (vecAx) {
checkCudaErrors(cusparseDestroyDnVec(vecAx));
}
if (h_csrValA) {
free(h_csrValA);
}
if (h_csrRowPtrA) {
free(h_csrRowPtrA);
}
if (h_csrColIndA) {
free(h_csrColIndA);
}
if (h_x) {
free(h_x);
}
if (h_b) {
free(h_b);
}
if (h_bcopy) {
free(h_bcopy);
}
if (h_r) {
free(h_r);
}
if (buffer_cpu) {
free(buffer_cpu);
}
if (buffer_gpu) {
checkCudaErrors(cudaFree(buffer_gpu));
}
if (d_csrValA) {
checkCudaErrors(cudaFree(d_csrValA));
}
if (d_csrRowPtrA) {
checkCudaErrors(cudaFree(d_csrRowPtrA));
}
if (d_csrColIndA) {
checkCudaErrors(cudaFree(d_csrColIndA));
}
if (d_x) {
checkCudaErrors(cudaFree(d_x));
}
if (d_b) {
checkCudaErrors(cudaFree(d_b));
}
if (d_r) {
checkCudaErrors(cudaFree(d_r));
}
return 0;
}
int main(int argc, char *argv[])
{
struct testOpts opts;
cusolverSpHandle_t cusolverSpH = NULL; // reordering, permutation and 1st LU factorization
cusparseHandle_t cusparseH = NULL; // residual evaluation
cudaStream_t stream = NULL;
cusparseMatDescr_t descrA = NULL; // A is a base-0 general matrix
csrqrInfoHost_t h_info = NULL; // opaque info structure for LU with parital pivoting
csrqrInfo_t d_info = NULL; // opaque info structure for LU with parital pivoting
int rowsA = 0; // number of rows of A
int colsA = 0; // number of columns of A
int nnzA = 0; // number of nonzeros of A
int baseA = 0; // base index in CSR format
// CSR(A) from I/O
int *h_csrRowPtrA = NULL; // <int> n+1
int *h_csrColIndA = NULL; // <int> nnzA
double *h_csrValA = NULL; // <double> nnzA
double *h_x = NULL; // <double> n, x = A \ b
double *h_b = NULL; // <double> n, b = ones(m,1)
double *h_bcopy = NULL; // <double> n, b = ones(m,1)
double *h_r = NULL; // <double> n, r = b - A*x
size_t size_internal = 0;
size_t size_chol = 0; // size of working space for csrlu
void *buffer_cpu = NULL; // working space for Cholesky
void *buffer_gpu = NULL; // working space for Cholesky
int *d_csrRowPtrA = NULL; // <int> n+1
int *d_csrColIndA = NULL; // <int> nnzA
double *d_csrValA = NULL; // <double> nnzA
double *d_x = NULL; // <double> n, x = A \ b
double *d_b = NULL; // <double> n, a copy of h_b
double *d_r = NULL; // <double> n, r = b - A*x
// the constants used in residual evaluation, r = b - A*x
const double minus_one = -1.0;
const double one = 1.0;
const double zero = 0.0;
// the constant used in cusolverSp
// singularity is -1 if A is invertible under tol
// tol determines the condition of singularity
int singularity = 0;
const double tol = 1.e-14;
double x_inf = 0.0; // |x|
double r_inf = 0.0; // |r|
double A_inf = 0.0; // |A|
parseCommandLineArguments(argc, argv, opts);
findCudaDevice(argc, (const char **)argv);
if (opts.sparse_mat_filename == NULL) {
opts.sparse_mat_filename = sdkFindFilePath("lap2D_5pt_n32.mtx", argv[0]);
if (opts.sparse_mat_filename != NULL)
printf("Using default input file [%s]\n", opts.sparse_mat_filename);
else
printf("Could not find lap2D_5pt_n32.mtx\n");
}
else {
printf("Using input file [%s]\n", opts.sparse_mat_filename);
}
printf("step 1: read matrix market format\n");
if (opts.sparse_mat_filename) {
if (loadMMSparseMatrix<double>(opts.sparse_mat_filename,
'd',
true,
&rowsA,
&colsA,
&nnzA,
&h_csrValA,
&h_csrRowPtrA,
&h_csrColIndA,
true)) {
return 1;
}
baseA = h_csrRowPtrA[0]; // baseA = {0,1}
}
else {
fprintf(stderr, "Error: input matrix is not provided\n");
return 1;
}
if (rowsA != colsA) {
fprintf(stderr, "Error: only support square matrix\n");
return 1;
}
printf("sparse matrix A is %d x %d with %d nonzeros, base=%d\n", rowsA, colsA, nnzA, baseA);
checkCudaErrors(cusolverSpCreate(&cusolverSpH));
checkCudaErrors(cusparseCreate(&cusparseH));
checkCudaErrors(cudaStreamCreate(&stream));
checkCudaErrors(cusolverSpSetStream(cusolverSpH, stream));
checkCudaErrors(cusparseSetStream(cusparseH, stream));
checkCudaErrors(cusparseCreateMatDescr(&descrA));
checkCudaErrors(cusparseSetMatType(descrA, CUSPARSE_MATRIX_TYPE_GENERAL));
if (baseA) {
checkCudaErrors(cusparseSetMatIndexBase(descrA, CUSPARSE_INDEX_BASE_ONE));
}
else {
checkCudaErrors(cusparseSetMatIndexBase(descrA, CUSPARSE_INDEX_BASE_ZERO));
}
h_x = (double *)malloc(sizeof(double) * colsA);
h_b = (double *)malloc(sizeof(double) * rowsA);
h_bcopy = (double *)malloc(sizeof(double) * rowsA);
h_r = (double *)malloc(sizeof(double) * rowsA);
assert(NULL != h_x);
assert(NULL != h_b);
assert(NULL != h_bcopy);
assert(NULL != h_r);
checkCudaErrors(cudaMalloc((void **)&d_csrRowPtrA, sizeof(int) * (rowsA + 1)));
checkCudaErrors(cudaMalloc((void **)&d_csrColIndA, sizeof(int) * nnzA));
checkCudaErrors(cudaMalloc((void **)&d_csrValA, sizeof(double) * nnzA));
checkCudaErrors(cudaMalloc((void **)&d_x, sizeof(double) * colsA));
checkCudaErrors(cudaMalloc((void **)&d_b, sizeof(double) * rowsA));
checkCudaErrors(cudaMalloc((void **)&d_r, sizeof(double) * rowsA));
for (int row = 0; row < rowsA; row++) {
h_b[row] = 1.0;
}
memcpy(h_bcopy, h_b, sizeof(double) * rowsA);
printf("step 2: create opaque info structure\n");
checkCudaErrors(cusolverSpCreateCsrqrInfoHost(&h_info));
printf("step 3: analyze qr(A) to know structure of L\n");
checkCudaErrors(
cusolverSpXcsrqrAnalysisHost(cusolverSpH, rowsA, colsA, nnzA, descrA, h_csrRowPtrA, h_csrColIndA, h_info));
printf("step 4: workspace for qr(A)\n");
checkCudaErrors(cusolverSpDcsrqrBufferInfoHost(cusolverSpH,
rowsA,
colsA,
nnzA,
descrA,
h_csrValA,
h_csrRowPtrA,
h_csrColIndA,
h_info,
&size_internal,
&size_chol));
if (buffer_cpu) {
free(buffer_cpu);
}
buffer_cpu = (void *)malloc(sizeof(char) * size_chol);
assert(NULL != buffer_cpu);
printf("step 5: compute A = L*L^T \n");
checkCudaErrors(cusolverSpDcsrqrSetupHost(
cusolverSpH, rowsA, colsA, nnzA, descrA, h_csrValA, h_csrRowPtrA, h_csrColIndA, zero, h_info));
checkCudaErrors(cusolverSpDcsrqrFactorHost(cusolverSpH, rowsA, colsA, nnzA, NULL, NULL, h_info, buffer_cpu));
printf("step 6: check if the matrix is singular \n");
checkCudaErrors(cusolverSpDcsrqrZeroPivotHost(cusolverSpH, h_info, tol, &singularity));
if (0 <= singularity) {
fprintf(stderr, "Error: A is not invertible, singularity=%d\n", singularity);
return 1;
}
printf("step 7: solve A*x = b \n");
checkCudaErrors(cusolverSpDcsrqrSolveHost(cusolverSpH, rowsA, colsA, h_b, h_x, h_info, buffer_cpu));
printf("step 8: evaluate residual r = b - A*x (result on CPU)\n");
// use GPU gemv to compute r = b - A*x
checkCudaErrors(cudaMemcpy(d_csrRowPtrA, h_csrRowPtrA, sizeof(int) * (rowsA + 1), cudaMemcpyHostToDevice));
checkCudaErrors(cudaMemcpy(d_csrColIndA, h_csrColIndA, sizeof(int) * nnzA, cudaMemcpyHostToDevice));
checkCudaErrors(cudaMemcpy(d_csrValA, h_csrValA, sizeof(double) * nnzA, cudaMemcpyHostToDevice));
checkCudaErrors(cudaMemcpy(d_r, h_bcopy, sizeof(double) * rowsA, cudaMemcpyHostToDevice));
checkCudaErrors(cudaMemcpy(d_x, h_x, sizeof(double) * colsA, cudaMemcpyHostToDevice));
/* Wrap raw data into cuSPARSE generic API objects */
cusparseSpMatDescr_t matA = NULL;
if (baseA) {
checkCudaErrors(cusparseCreateCsr(&matA,
rowsA,
colsA,
nnzA,
d_csrRowPtrA,
d_csrColIndA,
d_csrValA,
CUSPARSE_INDEX_32I,
CUSPARSE_INDEX_32I,
CUSPARSE_INDEX_BASE_ONE,
CUDA_R_64F));
}
else {
checkCudaErrors(cusparseCreateCsr(&matA,
rowsA,
colsA,
nnzA,
d_csrRowPtrA,
d_csrColIndA,
d_csrValA,
CUSPARSE_INDEX_32I,
CUSPARSE_INDEX_32I,
CUSPARSE_INDEX_BASE_ZERO,
CUDA_R_64F));
}
cusparseDnVecDescr_t vecx = NULL;
checkCudaErrors(cusparseCreateDnVec(&vecx, colsA, d_x, CUDA_R_64F));
cusparseDnVecDescr_t vecAx = NULL;
checkCudaErrors(cusparseCreateDnVec(&vecAx, rowsA, d_r, CUDA_R_64F));
/* Allocate workspace for cuSPARSE */
size_t bufferSize = 0;
checkCudaErrors(cusparseSpMV_bufferSize(cusparseH,
CUSPARSE_OPERATION_NON_TRANSPOSE,
&minus_one,
matA,
vecx,
&one,
vecAx,
CUDA_R_64F,
CUSPARSE_SPMV_ALG_DEFAULT,
&bufferSize));
void *buffer = NULL;
checkCudaErrors(cudaMalloc(&buffer, bufferSize));
checkCudaErrors(cusparseSpMV(cusparseH,
CUSPARSE_OPERATION_NON_TRANSPOSE,
&minus_one,
matA,
vecx,
&one,
vecAx,
CUDA_R_64F,
CUSPARSE_SPMV_ALG_DEFAULT,
buffer));
checkCudaErrors(cudaMemcpy(h_r, d_r, sizeof(double) * rowsA, cudaMemcpyDeviceToHost));
x_inf = vec_norminf(colsA, h_x);
r_inf = vec_norminf(rowsA, h_r);
A_inf = csr_mat_norminf(rowsA, colsA, nnzA, descrA, h_csrValA, h_csrRowPtrA, h_csrColIndA);
printf("(CPU) |b - A*x| = %E \n", r_inf);
printf("(CPU) |A| = %E \n", A_inf);
printf("(CPU) |x| = %E \n", x_inf);
printf("(CPU) |b - A*x|/(|A|*|x|) = %E \n", r_inf / (A_inf * x_inf));
printf("step 9: create opaque info structure\n");
checkCudaErrors(cusolverSpCreateCsrqrInfo(&d_info));
checkCudaErrors(cudaMemcpy(d_csrRowPtrA, h_csrRowPtrA, sizeof(int) * (rowsA + 1), cudaMemcpyHostToDevice));
checkCudaErrors(cudaMemcpy(d_csrColIndA, h_csrColIndA, sizeof(int) * nnzA, cudaMemcpyHostToDevice));
checkCudaErrors(cudaMemcpy(d_csrValA, h_csrValA, sizeof(double) * nnzA, cudaMemcpyHostToDevice));
checkCudaErrors(cudaMemcpy(d_b, h_bcopy, sizeof(double) * rowsA, cudaMemcpyHostToDevice));
printf("step 10: analyze qr(A) to know structure of L\n");
checkCudaErrors(
cusolverSpXcsrqrAnalysis(cusolverSpH, rowsA, colsA, nnzA, descrA, d_csrRowPtrA, d_csrColIndA, d_info));
printf("step 11: workspace for qr(A)\n");
checkCudaErrors(cusolverSpDcsrqrBufferInfo(cusolverSpH,
rowsA,
colsA,
nnzA,
descrA,
d_csrValA,
d_csrRowPtrA,
d_csrColIndA,
d_info,
&size_internal,
&size_chol));
printf("GPU buffer size = %lld bytes\n", (signed long long)size_chol);
if (buffer_gpu) {
checkCudaErrors(cudaFree(buffer_gpu));
}
checkCudaErrors(cudaMalloc(&buffer_gpu, sizeof(char) * size_chol));
printf("step 12: compute A = L*L^T \n");
checkCudaErrors(cusolverSpDcsrqrSetup(
cusolverSpH, rowsA, colsA, nnzA, descrA, d_csrValA, d_csrRowPtrA, d_csrColIndA, zero, d_info));
checkCudaErrors(cusolverSpDcsrqrFactor(cusolverSpH, rowsA, colsA, nnzA, NULL, NULL, d_info, buffer_gpu));
printf("step 13: check if the matrix is singular \n");
checkCudaErrors(cusolverSpDcsrqrZeroPivot(cusolverSpH, d_info, tol, &singularity));
if (0 <= singularity) {
fprintf(stderr, "Error: A is not invertible, singularity=%d\n", singularity);
return 1;
}
printf("step 14: solve A*x = b \n");
checkCudaErrors(cusolverSpDcsrqrSolve(cusolverSpH, rowsA, colsA, d_b, d_x, d_info, buffer_gpu));
checkCudaErrors(cudaMemcpy(d_r, h_bcopy, sizeof(double) * rowsA, cudaMemcpyHostToDevice));
checkCudaErrors(cusparseSpMV(cusparseH,
CUSPARSE_OPERATION_NON_TRANSPOSE,
&minus_one,
matA,
vecx,
&one,
vecAx,
CUDA_R_64F,
CUSPARSE_SPMV_ALG_DEFAULT,
buffer));
checkCudaErrors(cudaMemcpy(h_r, d_r, sizeof(double) * rowsA, cudaMemcpyDeviceToHost));
r_inf = vec_norminf(rowsA, h_r);
printf("(GPU) |b - A*x| = %E \n", r_inf);
printf("(GPU) |b - A*x|/(|A|*|x|) = %E \n", r_inf / (A_inf * x_inf));
if (cusolverSpH) {
checkCudaErrors(cusolverSpDestroy(cusolverSpH));
}
if (cusparseH) {
checkCudaErrors(cusparseDestroy(cusparseH));
}
if (stream) {
checkCudaErrors(cudaStreamDestroy(stream));
}
if (descrA) {
checkCudaErrors(cusparseDestroyMatDescr(descrA));
}
if (h_info) {
checkCudaErrors(cusolverSpDestroyCsrqrInfoHost(h_info));
}
if (d_info) {
checkCudaErrors(cusolverSpDestroyCsrqrInfo(d_info));
}
if (matA) {
checkCudaErrors(cusparseDestroySpMat(matA));
}
if (vecx) {
checkCudaErrors(cusparseDestroyDnVec(vecx));
}
if (vecAx) {
checkCudaErrors(cusparseDestroyDnVec(vecAx));
}
if (h_csrValA) {
free(h_csrValA);
}
if (h_csrRowPtrA) {
free(h_csrRowPtrA);
}
if (h_csrColIndA) {
free(h_csrColIndA);
}
if (h_x) {
free(h_x);
}
if (h_b) {
free(h_b);
}
if (h_bcopy) {
free(h_bcopy);
}
if (h_r) {
free(h_r);
}
if (buffer_cpu) {
free(buffer_cpu);
}
if (buffer_gpu) {
checkCudaErrors(cudaFree(buffer_gpu));
}
if (d_csrValA) {
checkCudaErrors(cudaFree(d_csrValA));
}
if (d_csrRowPtrA) {
checkCudaErrors(cudaFree(d_csrRowPtrA));
}
if (d_csrColIndA) {
checkCudaErrors(cudaFree(d_csrColIndA));
}
if (d_x) {
checkCudaErrors(cudaFree(d_x));
}
if (d_b) {
checkCudaErrors(cudaFree(d_b));
}
if (d_r) {
checkCudaErrors(cudaFree(d_r));
}
return 0;
}

View File

@@ -1,128 +1,126 @@
/*
* Matrix Market I/O library for ANSI C
*
* See http://math.nist.gov/MatrixMarket for details.
*
*
*/
/*
* Matrix Market I/O library for ANSI C
*
* See http://math.nist.gov/MatrixMarket for details.
*
*
*/
/* avoid Windows warnings (for example: strcpy, fscanf, etc.) */
#if defined(_WIN32)
#if defined(_WIN32)
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include "mmio.h"
int mm_read_unsymmetric_sparse(const char *fname, int *M_, int *N_, int *nz_,
double **val_, int **I_, int **J_)
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int mm_read_unsymmetric_sparse(const char *fname, int *M_, int *N_, int *nz_, double **val_, int **I_, int **J_)
{
FILE *f;
FILE *f;
MM_typecode matcode;
int M, N, nz;
int i;
double *val;
int *I, *J;
int M, N, nz;
int i;
double *val;
int *I, *J;
if ((f = fopen(fname, "r")) == NULL)
return -1;
if (mm_read_banner(f, &matcode) != 0)
{
return -1;
if (mm_read_banner(f, &matcode) != 0) {
printf("mm_read_unsymetric: Could not process Matrix Market banner ");
printf(" in file [%s]\n", fname);
return -1;
}
if ( !(mm_is_real(matcode) && mm_is_matrix(matcode) &&
mm_is_sparse(matcode)))
{
if (!(mm_is_real(matcode) && mm_is_matrix(matcode) && mm_is_sparse(matcode))) {
fprintf(stderr, "Sorry, this application does not support ");
fprintf(stderr, "Market Market type: [%s]\n",
mm_typecode_to_str(matcode));
fprintf(stderr, "Market Market type: [%s]\n", mm_typecode_to_str(matcode));
return -1;
}
/* find out size of sparse matrix: M, N, nz .... */
if (mm_read_mtx_crd_size(f, &M, &N, &nz) !=0)
{
if (mm_read_mtx_crd_size(f, &M, &N, &nz) != 0) {
fprintf(stderr, "read_unsymmetric_sparse(): could not parse matrix size.\n");
return -1;
}
*M_ = M;
*N_ = N;
*M_ = M;
*N_ = N;
*nz_ = nz;
/* reserve memory for matrices */
I = (int *) malloc(nz * sizeof(int));
J = (int *) malloc(nz * sizeof(int));
val = (double *) malloc(nz * sizeof(double));
I = (int *)malloc(nz * sizeof(int));
J = (int *)malloc(nz * sizeof(int));
val = (double *)malloc(nz * sizeof(double));
*val_ = val;
*I_ = I;
*J_ = J;
*I_ = I;
*J_ = J;
/* NOTE: when reading in doubles, ANSI C requires the use of the "l" */
/* specifier as in "%lg", "%lf", "%le", otherwise errors will occur */
/* (ANSI C X3.159-1989, Sec. 4.9.6.2, p. 136 lines 13-15) */
for (i=0; i<nz; i++)
{
for (i = 0; i < nz; i++) {
if (fscanf(f, "%d %d %lg\n", &I[i], &J[i], &val[i]) != 3) {
return -1;
}
I[i]--; /* adjust from 1-based to 0-based */
I[i]--; /* adjust from 1-based to 0-based */
J[i]--;
}
fclose(f);
return 0;
}
int mm_is_valid(MM_typecode matcode)
{
if (!mm_is_matrix(matcode)) return 0;
if (mm_is_dense(matcode) && mm_is_pattern(matcode)) return 0;
if (mm_is_real(matcode) && mm_is_hermitian(matcode)) return 0;
if (mm_is_pattern(matcode) && (mm_is_hermitian(matcode) ||
mm_is_skew(matcode))) return 0;
if (!mm_is_matrix(matcode))
return 0;
if (mm_is_dense(matcode) && mm_is_pattern(matcode))
return 0;
if (mm_is_real(matcode) && mm_is_hermitian(matcode))
return 0;
if (mm_is_pattern(matcode) && (mm_is_hermitian(matcode) || mm_is_skew(matcode)))
return 0;
return 1;
}
int mm_read_banner(FILE *f, MM_typecode *matcode)
{
char line[MM_MAX_LINE_LENGTH];
char banner[MM_MAX_TOKEN_LENGTH];
char mtx[MM_MAX_TOKEN_LENGTH];
char crd[MM_MAX_TOKEN_LENGTH];
char data_type[MM_MAX_TOKEN_LENGTH];
char storage_scheme[MM_MAX_TOKEN_LENGTH];
char line[MM_MAX_LINE_LENGTH];
char banner[MM_MAX_TOKEN_LENGTH];
char mtx[MM_MAX_TOKEN_LENGTH];
char crd[MM_MAX_TOKEN_LENGTH];
char data_type[MM_MAX_TOKEN_LENGTH];
char storage_scheme[MM_MAX_TOKEN_LENGTH];
char *p;
mm_clear_typecode(matcode);
mm_clear_typecode(matcode);
if (fgets(line, MM_MAX_LINE_LENGTH, f) == NULL)
if (fgets(line, MM_MAX_LINE_LENGTH, f) == NULL)
return MM_PREMATURE_EOF;
if (sscanf(line, "%s %s %s %s %s", banner, mtx, crd, data_type,
storage_scheme) != 5)
if (sscanf(line, "%s %s %s %s %s", banner, mtx, crd, data_type, storage_scheme) != 5)
return MM_PREMATURE_EOF;
for (p=mtx; *p!='\0'; *p=tolower(*p),p++); /* convert to lower case */
for (p=crd; *p!='\0'; *p=tolower(*p),p++);
for (p=data_type; *p!='\0'; *p=tolower(*p),p++);
for (p=storage_scheme; *p!='\0'; *p=tolower(*p),p++);
for (p = mtx; *p != '\0'; *p = tolower(*p), p++)
; /* convert to lower case */
for (p = crd; *p != '\0'; *p = tolower(*p), p++)
;
for (p = data_type; *p != '\0'; *p = tolower(*p), p++)
;
for (p = storage_scheme; *p != '\0'; *p = tolower(*p), p++)
;
/* check for banner */
if (strncmp(banner, MatrixMarketBanner, strlen(MatrixMarketBanner)) != 0)
@@ -130,7 +128,7 @@ int mm_read_banner(FILE *f, MM_typecode *matcode)
/* first field should be "mtx" */
if (strcmp(mtx, MM_MTX_STR) != 0)
return MM_UNSUPPORTED_TYPE;
return MM_UNSUPPORTED_TYPE;
mm_set_matrix(matcode);
@@ -140,46 +138,39 @@ int mm_read_banner(FILE *f, MM_typecode *matcode)
if (strcmp(crd, MM_SPARSE_STR) == 0)
mm_set_sparse(matcode);
else
if (strcmp(crd, MM_DENSE_STR) == 0)
mm_set_dense(matcode);
else if (strcmp(crd, MM_DENSE_STR) == 0)
mm_set_dense(matcode);
else
return MM_UNSUPPORTED_TYPE;
/* third field */
if (strcmp(data_type, MM_REAL_STR) == 0)
mm_set_real(matcode);
else
if (strcmp(data_type, MM_COMPLEX_STR) == 0)
else if (strcmp(data_type, MM_COMPLEX_STR) == 0)
mm_set_complex(matcode);
else
if (strcmp(data_type, MM_PATTERN_STR) == 0)
else if (strcmp(data_type, MM_PATTERN_STR) == 0)
mm_set_pattern(matcode);
else
if (strcmp(data_type, MM_INT_STR) == 0)
else if (strcmp(data_type, MM_INT_STR) == 0)
mm_set_integer(matcode);
else
return MM_UNSUPPORTED_TYPE;
/* fourth field */
if (strcmp(storage_scheme, MM_GENERAL_STR) == 0)
mm_set_general(matcode);
else
if (strcmp(storage_scheme, MM_SYMM_STR) == 0)
else if (strcmp(storage_scheme, MM_SYMM_STR) == 0)
mm_set_symmetric(matcode);
else
if (strcmp(storage_scheme, MM_HERM_STR) == 0)
else if (strcmp(storage_scheme, MM_HERM_STR) == 0)
mm_set_hermitian(matcode);
else
if (strcmp(storage_scheme, MM_SKEW_STR) == 0)
else if (strcmp(storage_scheme, MM_SKEW_STR) == 0)
mm_set_skew(matcode);
else
return MM_UNSUPPORTED_TYPE;
return 0;
}
@@ -188,36 +179,34 @@ int mm_write_mtx_crd_size(FILE *f, int M, int N, int nz)
{
if (fprintf(f, "%d %d %d\n", M, N, nz) != 3)
return MM_COULD_NOT_WRITE_FILE;
else
else
return 0;
}
int mm_read_mtx_crd_size(FILE *f, int *M, int *N, int *nz )
int mm_read_mtx_crd_size(FILE *f, int *M, int *N, int *nz)
{
char line[MM_MAX_LINE_LENGTH];
int num_items_read;
int num_items_read;
/* set return null parameter values, in case we exit with errors */
*M = *N = *nz = 0;
/* now continue scanning until you reach the end-of-comments */
do
{
if (fgets(line,MM_MAX_LINE_LENGTH,f) == NULL)
do {
if (fgets(line, MM_MAX_LINE_LENGTH, f) == NULL)
return MM_PREMATURE_EOF;
}while (line[0] == '%');
} while (line[0] == '%');
/* line[] is either blank or has M,N, nz */
if (sscanf(line, "%d %d %d", M, N, nz) == 3)
return 0;
else
do
{
num_items_read = fscanf(f, "%d %d %d", M, N, nz);
if (num_items_read == EOF) return MM_PREMATURE_EOF;
}
while (num_items_read != 3);
do {
num_items_read = fscanf(f, "%d %d %d", M, N, nz);
if (num_items_read == EOF)
return MM_PREMATURE_EOF;
} while (num_items_read != 3);
return 0;
}
@@ -226,28 +215,26 @@ int mm_read_mtx_crd_size(FILE *f, int *M, int *N, int *nz )
int mm_read_mtx_array_size(FILE *f, int *M, int *N)
{
char line[MM_MAX_LINE_LENGTH];
int num_items_read;
int num_items_read;
/* set return null parameter values, in case we exit with errors */
*M = *N = 0;
/* now continue scanning until you reach the end-of-comments */
do
{
if (fgets(line,MM_MAX_LINE_LENGTH,f) == NULL)
do {
if (fgets(line, MM_MAX_LINE_LENGTH, f) == NULL)
return MM_PREMATURE_EOF;
}while (line[0] == '%');
} while (line[0] == '%');
/* line[] is either blank or has M,N, nz */
if (sscanf(line, "%d %d", M, N) == 2)
return 0;
else /* we have a blank line */
do
{
num_items_read = fscanf(f, "%d %d", M, N);
if (num_items_read == EOF) return MM_PREMATURE_EOF;
}
while (num_items_read != 2);
do {
num_items_read = fscanf(f, "%d %d", M, N);
if (num_items_read == EOF)
return MM_PREMATURE_EOF;
} while (num_items_read != 2);
return 0;
}
@@ -256,43 +243,36 @@ int mm_write_mtx_array_size(FILE *f, int M, int N)
{
if (fprintf(f, "%d %d\n", M, N) != 2)
return MM_COULD_NOT_WRITE_FILE;
else
else
return 0;
}
/*-------------------------------------------------------------------------*/
/******************************************************************/
/* use when I[], J[], and val[]J, and val[] are already allocated */
/******************************************************************/
int mm_read_mtx_crd_data(FILE *f, int M, int N, int nz, int I[], int J[],
double val[], MM_typecode matcode)
int mm_read_mtx_crd_data(FILE *f, int M, int N, int nz, int I[], int J[], double val[], MM_typecode matcode)
{
int i;
if (mm_is_complex(matcode))
{
for (i=0; i<nz; i++)
if (fscanf(f, "%d %d %lg %lg", &I[i], &J[i], &val[2*i], &val[2*i+1])
!= 4) return MM_PREMATURE_EOF;
if (mm_is_complex(matcode)) {
for (i = 0; i < nz; i++)
if (fscanf(f, "%d %d %lg %lg", &I[i], &J[i], &val[2 * i], &val[2 * i + 1]) != 4)
return MM_PREMATURE_EOF;
}
else if (mm_is_real(matcode) || mm_is_integer(matcode))
{
for (i=0; i<nz; i++)
{
if (fscanf(f, "%d %d %lg\n", &I[i], &J[i], &val[i])
!= 3) return MM_PREMATURE_EOF;
else if (mm_is_real(matcode) || mm_is_integer(matcode)) {
for (i = 0; i < nz; i++) {
if (fscanf(f, "%d %d %lg\n", &I[i], &J[i], &val[i]) != 3)
return MM_PREMATURE_EOF;
}
}
else if (mm_is_pattern(matcode))
{
for (i=0; i<nz; i++)
if (fscanf(f, "%d %d", &I[i], &J[i])
!= 2) return MM_PREMATURE_EOF;
else if (mm_is_pattern(matcode)) {
for (i = 0; i < nz; i++)
if (fscanf(f, "%d %d", &I[i], &J[i]) != 2)
return MM_PREMATURE_EOF;
}
else
return MM_UNSUPPORTED_TYPE;
@@ -300,24 +280,20 @@ int mm_read_mtx_crd_data(FILE *f, int M, int N, int nz, int I[], int J[],
return 0;
}
int mm_read_mtx_crd_entry(FILE *f, int *I, int *J,
double *real, double *imag, MM_typecode matcode)
int mm_read_mtx_crd_entry(FILE *f, int *I, int *J, double *real, double *imag, MM_typecode matcode)
{
if (mm_is_complex(matcode))
{
if (fscanf(f, "%d %d %lg %lg", I, J, real, imag)
!= 4) return MM_PREMATURE_EOF;
if (mm_is_complex(matcode)) {
if (fscanf(f, "%d %d %lg %lg", I, J, real, imag) != 4)
return MM_PREMATURE_EOF;
}
else if (mm_is_real(matcode) || mm_is_integer(matcode))
{
if (fscanf(f, "%d %d %lg\n", I, J, real)
!= 3) return MM_PREMATURE_EOF;
else if (mm_is_real(matcode) || mm_is_integer(matcode)) {
if (fscanf(f, "%d %d %lg\n", I, J, real) != 3)
return MM_PREMATURE_EOF;
}
else if (mm_is_pattern(matcode))
{
if (fscanf(f, "%d %d", I, J) != 2) return MM_PREMATURE_EOF;
else if (mm_is_pattern(matcode)) {
if (fscanf(f, "%d %d", I, J) != 2)
return MM_PREMATURE_EOF;
}
else
return MM_UNSUPPORTED_TYPE;
@@ -334,82 +310,76 @@ int mm_read_mtx_crd_entry(FILE *f, int *I, int *J,
(nz pairs of real/imaginary values)
************************************************************************/
int mm_read_mtx_crd(char *fname, int *M, int *N, int *nz, int **I, int **J,
double **val, MM_typecode *matcode)
int mm_read_mtx_crd(char *fname, int *M, int *N, int *nz, int **I, int **J, double **val, MM_typecode *matcode)
{
int ret_code;
int ret_code;
FILE *f;
if (strcmp(fname, "stdin") == 0) f=stdin;
else
if ((f = fopen(fname, "r")) == NULL)
if (strcmp(fname, "stdin") == 0)
f = stdin;
else if ((f = fopen(fname, "r")) == NULL)
return MM_COULD_NOT_READ_FILE;
if ((ret_code = mm_read_banner(f, matcode)) != 0)
return ret_code;
if (!(mm_is_valid(*matcode) && mm_is_sparse(*matcode) &&
mm_is_matrix(*matcode)))
if (!(mm_is_valid(*matcode) && mm_is_sparse(*matcode) && mm_is_matrix(*matcode)))
return MM_UNSUPPORTED_TYPE;
if ((ret_code = mm_read_mtx_crd_size(f, M, N, nz)) != 0)
return ret_code;
*I = (int *) malloc(*nz * sizeof(int));
*J = (int *) malloc(*nz * sizeof(int));
*I = (int *)malloc(*nz * sizeof(int));
*J = (int *)malloc(*nz * sizeof(int));
*val = NULL;
if (mm_is_complex(*matcode))
{
*val = (double *) malloc(*nz * 2 * sizeof(double));
ret_code = mm_read_mtx_crd_data(f, *M, *N, *nz, *I, *J, *val,
*matcode);
if (ret_code != 0) return ret_code;
if (mm_is_complex(*matcode)) {
*val = (double *)malloc(*nz * 2 * sizeof(double));
ret_code = mm_read_mtx_crd_data(f, *M, *N, *nz, *I, *J, *val, *matcode);
if (ret_code != 0)
return ret_code;
}
else if (mm_is_real(*matcode) || mm_is_integer(*matcode))
{
*val = (double *) malloc(*nz * sizeof(double));
ret_code = mm_read_mtx_crd_data(f, *M, *N, *nz, *I, *J, *val,
*matcode);
if (ret_code != 0) return ret_code;
else if (mm_is_real(*matcode) || mm_is_integer(*matcode)) {
*val = (double *)malloc(*nz * sizeof(double));
ret_code = mm_read_mtx_crd_data(f, *M, *N, *nz, *I, *J, *val, *matcode);
if (ret_code != 0)
return ret_code;
}
else if (mm_is_pattern(*matcode))
{
ret_code = mm_read_mtx_crd_data(f, *M, *N, *nz, *I, *J, *val,
*matcode);
if (ret_code != 0) return ret_code;
else if (mm_is_pattern(*matcode)) {
ret_code = mm_read_mtx_crd_data(f, *M, *N, *nz, *I, *J, *val, *matcode);
if (ret_code != 0)
return ret_code;
}
if (f != stdin) fclose(f);
if (f != stdin)
fclose(f);
return 0;
}
int mm_write_banner(FILE *f, MM_typecode matcode)
{
char *str = mm_typecode_to_str(matcode);
int ret_code;
int ret_code;
ret_code = fprintf(f, "%s %s\n", MatrixMarketBanner, str);
free(str);
if (ret_code !=2 )
if (ret_code != 2)
return MM_COULD_NOT_WRITE_FILE;
else
return 0;
}
int mm_write_mtx_crd(char fname[], int M, int N, int nz, int I[], int J[],
double val[], MM_typecode matcode)
int mm_write_mtx_crd(char fname[], int M, int N, int nz, int I[], int J[], double val[], MM_typecode matcode)
{
FILE *f;
int i;
int i;
if (strcmp(fname, "stdout") == 0)
f = stdout;
else
if ((f = fopen(fname, "w")) == NULL)
else if ((f = fopen(fname, "w")) == NULL)
return MM_COULD_NOT_WRITE_FILE;
/* print banner followed by typecode */
@@ -421,50 +391,47 @@ int mm_write_mtx_crd(char fname[], int M, int N, int nz, int I[], int J[],
/* print values */
if (mm_is_pattern(matcode))
for (i=0; i<nz; i++)
for (i = 0; i < nz; i++)
fprintf(f, "%d %d\n", I[i], J[i]);
else
if (mm_is_integer(matcode))
for (i=0; i<nz; i++)
else if (mm_is_integer(matcode))
for (i = 0; i < nz; i++)
fprintf(f, "%d %d %d\n", I[i], J[i], (int)val[i]);
else
if (mm_is_real(matcode))
for (i=0; i<nz; i++)
else if (mm_is_real(matcode))
for (i = 0; i < nz; i++)
fprintf(f, "%d %d %20.16g\n", I[i], J[i], val[i]);
else
if (mm_is_complex(matcode))
for (i=0; i<nz; i++)
fprintf(f, "%d %d %20.16g %20.16g\n", I[i], J[i], val[2*i],
val[2*i+1]);
else
{
if (f != stdout) fclose(f);
else if (mm_is_complex(matcode))
for (i = 0; i < nz; i++)
fprintf(f, "%d %d %20.16g %20.16g\n", I[i], J[i], val[2 * i], val[2 * i + 1]);
else {
if (f != stdout)
fclose(f);
return MM_UNSUPPORTED_TYPE;
}
if (f !=stdout) fclose(f);
if (f != stdout)
fclose(f);
return 0;
}
/**
* Create a new copy of a string s. mm_strdup() is a common routine, but
* not part of ANSI C, so it is included here. Used by mm_typecode_to_str().
*
*/
* Create a new copy of a string s. mm_strdup() is a common routine, but
* not part of ANSI C, so it is included here. Used by mm_typecode_to_str().
*
*/
static char *mm_strdup(const char *s)
{
size_t len = strlen(s);
char *s2 = (char *) malloc((len+1)*sizeof(char));
char *s2 = (char *)malloc((len + 1) * sizeof(char));
return strcpy(s2, s);
}
char *mm_typecode_to_str(MM_typecode matcode)
char *mm_typecode_to_str(MM_typecode matcode)
{
char buffer[MM_MAX_LINE_LENGTH];
char buffer[MM_MAX_LINE_LENGTH];
char *types[4];
//char *mm_strdup(const char *);
//int error =0;
// char *mm_strdup(const char *);
// int error =0;
/* check for MTX type */
if (mm_is_matrix(matcode))
@@ -475,8 +442,7 @@ char *mm_typecode_to_str(MM_typecode matcode)
/* check for CRD or ARR matrix */
if (mm_is_sparse(matcode))
types[1] = MM_SPARSE_STR;
else
if (mm_is_dense(matcode))
else if (mm_is_dense(matcode))
types[1] = MM_DENSE_STR;
else
return NULL;
@@ -484,14 +450,11 @@ char *mm_typecode_to_str(MM_typecode matcode)
/* check for element data type */
if (mm_is_real(matcode))
types[2] = MM_REAL_STR;
else
if (mm_is_complex(matcode))
else if (mm_is_complex(matcode))
types[2] = MM_COMPLEX_STR;
else
if (mm_is_pattern(matcode))
else if (mm_is_pattern(matcode))
types[2] = MM_PATTERN_STR;
else
if (mm_is_integer(matcode))
else if (mm_is_integer(matcode))
types[2] = MM_INT_STR;
else
return NULL;
@@ -500,18 +463,15 @@ char *mm_typecode_to_str(MM_typecode matcode)
/* check for symmetry type */
if (mm_is_general(matcode))
types[3] = MM_GENERAL_STR;
else
if (mm_is_symmetric(matcode))
else if (mm_is_symmetric(matcode))
types[3] = MM_SYMM_STR;
else
if (mm_is_hermitian(matcode))
else if (mm_is_hermitian(matcode))
types[3] = MM_HERM_STR;
else
if (mm_is_skew(matcode))
else if (mm_is_skew(matcode))
types[3] = MM_SKEW_STR;
else
return NULL;
sprintf(buffer,"%s %s %s %s", types[0], types[1], types[2], types[3]);
sprintf(buffer, "%s %s %s %s", types[0], types[1], types[2], types[3]);
return mm_strdup(buffer);
}

View File

@@ -1,141 +1,138 @@
/*
* Matrix Market I/O library for ANSI C
*
* See http://math.nist.gov/MatrixMarket for details.
*
*
*/
/*
* Matrix Market I/O library for ANSI C
*
* See http://math.nist.gov/MatrixMarket for details.
*
*
*/
#ifndef MM_IO_H
#define MM_IO_H
#include <stdio.h>
#if defined(__cplusplus)
extern "C" {
extern "C"
{
#endif /* __cplusplus */
#define MM_MAX_LINE_LENGTH 1025
#define MatrixMarketBanner "%%MatrixMarket"
#define MM_MAX_LINE_LENGTH 1025
#define MatrixMarketBanner "%%MatrixMarket"
#define MM_MAX_TOKEN_LENGTH 64
typedef char MM_typecode[4];
typedef char MM_typecode[4];
char *mm_typecode_to_str(MM_typecode matcode);
char *mm_typecode_to_str(MM_typecode matcode);
int mm_read_banner(FILE *f, MM_typecode *matcode);
int mm_read_mtx_crd_size(FILE *f, int *M, int *N, int *nz);
int mm_read_mtx_array_size(FILE *f, int *M, int *N);
int mm_read_banner(FILE *f, MM_typecode *matcode);
int mm_read_mtx_crd_size(FILE *f, int *M, int *N, int *nz);
int mm_read_mtx_array_size(FILE *f, int *M, int *N);
int mm_write_banner(FILE *f, MM_typecode matcode);
int mm_write_mtx_crd_size(FILE *f, int M, int N, int nz);
int mm_write_mtx_array_size(FILE *f, int M, int N);
int mm_write_banner(FILE *f, MM_typecode matcode);
int mm_write_mtx_crd_size(FILE *f, int M, int N, int nz);
int mm_write_mtx_array_size(FILE *f, int M, int N);
/********************* MM_typecode query fucntions ***************************/
/********************* MM_typecode query fucntions ***************************/
#define mm_is_matrix(typecode) ((typecode)[0]=='M')
#define mm_is_matrix(typecode) ((typecode)[0] == 'M')
#define mm_is_sparse(typecode) ((typecode)[1]=='C')
#define mm_is_coordinate(typecode)((typecode)[1]=='C')
#define mm_is_dense(typecode) ((typecode)[1]=='A')
#define mm_is_array(typecode) ((typecode)[1]=='A')
#define mm_is_sparse(typecode) ((typecode)[1] == 'C')
#define mm_is_coordinate(typecode) ((typecode)[1] == 'C')
#define mm_is_dense(typecode) ((typecode)[1] == 'A')
#define mm_is_array(typecode) ((typecode)[1] == 'A')
#define mm_is_complex(typecode) ((typecode)[2]=='C')
#define mm_is_real(typecode) ((typecode)[2]=='R')
#define mm_is_pattern(typecode) ((typecode)[2]=='P')
#define mm_is_integer(typecode) ((typecode)[2]=='I')
#define mm_is_complex(typecode) ((typecode)[2] == 'C')
#define mm_is_real(typecode) ((typecode)[2] == 'R')
#define mm_is_pattern(typecode) ((typecode)[2] == 'P')
#define mm_is_integer(typecode) ((typecode)[2] == 'I')
#define mm_is_symmetric(typecode)((typecode)[3]=='S')
#define mm_is_general(typecode) ((typecode)[3]=='G')
#define mm_is_skew(typecode) ((typecode)[3]=='K')
#define mm_is_hermitian(typecode)((typecode)[3]=='H')
#define mm_is_symmetric(typecode) ((typecode)[3] == 'S')
#define mm_is_general(typecode) ((typecode)[3] == 'G')
#define mm_is_skew(typecode) ((typecode)[3] == 'K')
#define mm_is_hermitian(typecode) ((typecode)[3] == 'H')
int mm_is_valid(MM_typecode matcode); /* too complex for a macro */
int mm_is_valid(MM_typecode matcode); /* too complex for a macro */
/********************* MM_typecode modify fucntions ***************************/
/********************* MM_typecode modify fucntions ***************************/
#define mm_set_matrix(typecode) ((*typecode)[0]='M')
#define mm_set_coordinate(typecode) ((*typecode)[1]='C')
#define mm_set_array(typecode) ((*typecode)[1]='A')
#define mm_set_dense(typecode) mm_set_array(typecode)
#define mm_set_sparse(typecode) mm_set_coordinate(typecode)
#define mm_set_matrix(typecode) ((*typecode)[0] = 'M')
#define mm_set_coordinate(typecode) ((*typecode)[1] = 'C')
#define mm_set_array(typecode) ((*typecode)[1] = 'A')
#define mm_set_dense(typecode) mm_set_array(typecode)
#define mm_set_sparse(typecode) mm_set_coordinate(typecode)
#define mm_set_complex(typecode)((*typecode)[2]='C')
#define mm_set_real(typecode) ((*typecode)[2]='R')
#define mm_set_pattern(typecode)((*typecode)[2]='P')
#define mm_set_integer(typecode)((*typecode)[2]='I')
#define mm_set_complex(typecode) ((*typecode)[2] = 'C')
#define mm_set_real(typecode) ((*typecode)[2] = 'R')
#define mm_set_pattern(typecode) ((*typecode)[2] = 'P')
#define mm_set_integer(typecode) ((*typecode)[2] = 'I')
#define mm_set_symmetric(typecode)((*typecode)[3]='S')
#define mm_set_general(typecode)((*typecode)[3]='G')
#define mm_set_skew(typecode) ((*typecode)[3]='K')
#define mm_set_hermitian(typecode)((*typecode)[3]='H')
#define mm_set_symmetric(typecode) ((*typecode)[3] = 'S')
#define mm_set_general(typecode) ((*typecode)[3] = 'G')
#define mm_set_skew(typecode) ((*typecode)[3] = 'K')
#define mm_set_hermitian(typecode) ((*typecode)[3] = 'H')
#define mm_clear_typecode(typecode) ((*typecode)[0]=(*typecode)[1]= \
(*typecode)[2]=' ',(*typecode)[3]='G')
#define mm_clear_typecode(typecode) ((*typecode)[0] = (*typecode)[1] = (*typecode)[2] = ' ', (*typecode)[3] = 'G')
#define mm_initialize_typecode(typecode) mm_clear_typecode(typecode)
/********************* Matrix Market error codes ***************************/
/********************* Matrix Market error codes ***************************/
#define MM_COULD_NOT_READ_FILE 11
#define MM_PREMATURE_EOF 12
#define MM_NOT_MTX 13
#define MM_NO_HEADER 14
#define MM_UNSUPPORTED_TYPE 15
#define MM_LINE_TOO_LONG 16
#define MM_COULD_NOT_WRITE_FILE 17
#define MM_COULD_NOT_READ_FILE 11
#define MM_PREMATURE_EOF 12
#define MM_NOT_MTX 13
#define MM_NO_HEADER 14
#define MM_UNSUPPORTED_TYPE 15
#define MM_LINE_TOO_LONG 16
#define MM_COULD_NOT_WRITE_FILE 17
/******************** Matrix Market internal definitions ********************
/******************** Matrix Market internal definitions ********************
MM_matrix_typecode: 4-character sequence
MM_matrix_typecode: 4-character sequence
ojbect sparse/ data storage
dense type scheme
ojbect sparse/ data storage
dense type scheme
string position: [0] [1] [2] [3]
string position: [0] [1] [2] [3]
Matrix typecode: M(atrix) C(oord) R(eal) G(eneral)
A(array) C(omplex) H(ermitian)
P(attern) S(ymmetric)
I(nteger) K(kew)
Matrix typecode: M(atrix) C(oord) R(eal) G(eneral)
A(array) C(omplex) H(ermitian)
P(attern) S(ymmetric)
I(nteger) K(kew)
***********************************************************************/
***********************************************************************/
#define MM_MTX_STR "matrix"
#define MM_ARRAY_STR "array"
#define MM_DENSE_STR "array"
#define MM_COORDINATE_STR "coordinate"
#define MM_SPARSE_STR "coordinate"
#define MM_COMPLEX_STR "complex"
#define MM_REAL_STR "real"
#define MM_INT_STR "integer"
#define MM_GENERAL_STR "general"
#define MM_SYMM_STR "symmetric"
#define MM_HERM_STR "hermitian"
#define MM_SKEW_STR "skew-symmetric"
#define MM_PATTERN_STR "pattern"
#define MM_MTX_STR "matrix"
#define MM_ARRAY_STR "array"
#define MM_DENSE_STR "array"
#define MM_COORDINATE_STR "coordinate"
#define MM_SPARSE_STR "coordinate"
#define MM_COMPLEX_STR "complex"
#define MM_REAL_STR "real"
#define MM_INT_STR "integer"
#define MM_GENERAL_STR "general"
#define MM_SYMM_STR "symmetric"
#define MM_HERM_STR "hermitian"
#define MM_SKEW_STR "skew-symmetric"
#define MM_PATTERN_STR "pattern"
/* high level routines */
int mm_read_mtx_crd(char *fname, int *M, int *N, int *nz, int **I, int **J,
double **val, MM_typecode *matcode);
/* high level routines */
int mm_read_mtx_crd(char *fname, int *M, int *N, int *nz, int **I, int **J, double **val, MM_typecode *matcode);
int mm_write_mtx_crd(char fname[], int M, int N, int nz, int I[], int J[],
double val[], MM_typecode matcode);
int mm_read_mtx_crd_data(FILE *f, int M, int N, int nz, int I[], int J[],
double val[], MM_typecode matcode);
int mm_read_mtx_crd_entry(FILE *f, int *I, int *J, double *real, double *img,
MM_typecode matcode);
int mm_write_mtx_crd(char fname[], int M, int N, int nz, int I[], int J[], double val[], MM_typecode matcode);
int mm_read_mtx_crd_data(FILE *f, int M, int N, int nz, int I[], int J[], double val[], MM_typecode matcode);
int mm_read_mtx_crd_entry(FILE *f, int *I, int *J, double *real, double *img, MM_typecode matcode);
int mm_read_unsymmetric_sparse(const char *fname, int *M_, int *N_, int *nz_,
double **val_, int **I_, int **J_);
int mm_read_unsymmetric_sparse(const char *fname, int *M_, int *N_, int *nz_, double **val_, int **I_, int **J_);
#if defined(__cplusplus)
}
#endif /* __cplusplus */
#endif /* __cplusplus */
#endif

View File

@@ -38,180 +38,125 @@
#endif
/* various __inline__ __device__ function to initialize a T_ELEM */
template <typename T_ELEM>
__inline__ T_ELEM cuGet(int);
template <>
__inline__ float cuGet<float>(int x) {
return float(x);
template <typename T_ELEM> __inline__ T_ELEM cuGet(int);
template <> __inline__ float cuGet<float>(int x) { return float(x); }
template <> __inline__ double cuGet<double>(int x) { return double(x); }
template <> __inline__ cuComplex cuGet<cuComplex>(int x) { return (make_cuComplex(float(x), 0.0f)); }
template <> __inline__ cuDoubleComplex cuGet<cuDoubleComplex>(int x) { return (make_cuDoubleComplex(double(x), 0.0)); }
template <typename T_ELEM> __inline__ T_ELEM cuGet(int, int);
template <> __inline__ float cuGet<float>(int x, int y) { return float(x); }
template <> __inline__ double cuGet<double>(int x, int y) { return double(x); }
template <> __inline__ cuComplex cuGet<cuComplex>(int x, int y) { return make_cuComplex(float(x), float(y)); }
template <> __inline__ cuDoubleComplex cuGet<cuDoubleComplex>(int x, int y)
{
return (make_cuDoubleComplex(double(x), double(y)));
}
template <>
__inline__ double cuGet<double>(int x) {
return double(x);
template <typename T_ELEM> __inline__ T_ELEM cuGet(float);
template <> __inline__ float cuGet<float>(float x) { return float(x); }
template <> __inline__ double cuGet<double>(float x) { return double(x); }
template <> __inline__ cuComplex cuGet<cuComplex>(float x) { return (make_cuComplex(float(x), 0.0f)); }
template <> __inline__ cuDoubleComplex cuGet<cuDoubleComplex>(float x)
{
return (make_cuDoubleComplex(double(x), 0.0));
}
template <>
__inline__ cuComplex cuGet<cuComplex>(int x) {
return (make_cuComplex(float(x), 0.0f));
template <typename T_ELEM> __inline__ T_ELEM cuGet(float, float);
template <> __inline__ float cuGet<float>(float x, float y) { return float(x); }
template <> __inline__ double cuGet<double>(float x, float y) { return double(x); }
template <> __inline__ cuComplex cuGet<cuComplex>(float x, float y) { return (make_cuComplex(float(x), float(y))); }
template <> __inline__ cuDoubleComplex cuGet<cuDoubleComplex>(float x, float y)
{
return (make_cuDoubleComplex(double(x), double(y)));
}
template <>
__inline__ cuDoubleComplex cuGet<cuDoubleComplex>(int x) {
return (make_cuDoubleComplex(double(x), 0.0));
template <typename T_ELEM> __inline__ T_ELEM cuGet(double);
template <> __inline__ float cuGet<float>(double x) { return float(x); }
template <> __inline__ double cuGet<double>(double x) { return double(x); }
template <> __inline__ cuComplex cuGet<cuComplex>(double x) { return (make_cuComplex(float(x), 0.0f)); }
template <> __inline__ cuDoubleComplex cuGet<cuDoubleComplex>(double x)
{
return (make_cuDoubleComplex(double(x), 0.0));
}
template <typename T_ELEM>
__inline__ T_ELEM cuGet(int, int);
template <>
__inline__ float cuGet<float>(int x, int y) {
return float(x);
template <typename T_ELEM> __inline__ T_ELEM cuGet(double, double);
template <> __inline__ float cuGet<float>(double x, double y) { return float(x); }
template <> __inline__ double cuGet<double>(double x, double y) { return double(x); }
template <> __inline__ cuComplex cuGet<cuComplex>(double x, double y) { return (make_cuComplex(float(x), float(y))); }
template <> __inline__ cuDoubleComplex cuGet<cuDoubleComplex>(double x, double y)
{
return (make_cuDoubleComplex(double(x), double(y)));
}
template <>
__inline__ double cuGet<double>(int x, int y) {
return double(x);
static void compress_index(const int *Ind, int nnz, int m, int *Ptr, int base)
{
int i;
/* initialize everything to zero */
for (i = 0; i < m + 1; i++) {
Ptr[i] = 0;
}
/* count elements in every row */
Ptr[0] = base;
for (i = 0; i < nnz; i++) {
Ptr[Ind[i] + (1 - base)]++;
}
/* add all the values */
for (i = 0; i < m; i++) {
Ptr[i + 1] += Ptr[i];
}
}
template <>
__inline__ cuComplex cuGet<cuComplex>(int x, int y) {
return make_cuComplex(float(x), float(y));
}
template <>
__inline__ cuDoubleComplex cuGet<cuDoubleComplex>(int x, int y) {
return (make_cuDoubleComplex(double(x), double(y)));
}
template <typename T_ELEM>
__inline__ T_ELEM cuGet(float);
template <>
__inline__ float cuGet<float>(float x) {
return float(x);
}
template <>
__inline__ double cuGet<double>(float x) {
return double(x);
}
template <>
__inline__ cuComplex cuGet<cuComplex>(float x) {
return (make_cuComplex(float(x), 0.0f));
}
template <>
__inline__ cuDoubleComplex cuGet<cuDoubleComplex>(float x) {
return (make_cuDoubleComplex(double(x), 0.0));
}
template <typename T_ELEM>
__inline__ T_ELEM cuGet(float, float);
template <>
__inline__ float cuGet<float>(float x, float y) {
return float(x);
}
template <>
__inline__ double cuGet<double>(float x, float y) {
return double(x);
}
template <>
__inline__ cuComplex cuGet<cuComplex>(float x, float y) {
return (make_cuComplex(float(x), float(y)));
}
template <>
__inline__ cuDoubleComplex cuGet<cuDoubleComplex>(float x, float y) {
return (make_cuDoubleComplex(double(x), double(y)));
}
template <typename T_ELEM>
__inline__ T_ELEM cuGet(double);
template <>
__inline__ float cuGet<float>(double x) {
return float(x);
}
template <>
__inline__ double cuGet<double>(double x) {
return double(x);
}
template <>
__inline__ cuComplex cuGet<cuComplex>(double x) {
return (make_cuComplex(float(x), 0.0f));
}
template <>
__inline__ cuDoubleComplex cuGet<cuDoubleComplex>(double x) {
return (make_cuDoubleComplex(double(x), 0.0));
}
template <typename T_ELEM>
__inline__ T_ELEM cuGet(double, double);
template <>
__inline__ float cuGet<float>(double x, double y) {
return float(x);
}
template <>
__inline__ double cuGet<double>(double x, double y) {
return double(x);
}
template <>
__inline__ cuComplex cuGet<cuComplex>(double x, double y) {
return (make_cuComplex(float(x), float(y)));
}
template <>
__inline__ cuDoubleComplex cuGet<cuDoubleComplex>(double x, double y) {
return (make_cuDoubleComplex(double(x), double(y)));
}
static void compress_index(const int *Ind, int nnz, int m, int *Ptr, int base) {
int i;
/* initialize everything to zero */
for (i = 0; i < m + 1; i++) {
Ptr[i] = 0;
}
/* count elements in every row */
Ptr[0] = base;
for (i = 0; i < nnz; i++) {
Ptr[Ind[i] + (1 - base)]++;
}
/* add all the values */
for (i = 0; i < m; i++) {
Ptr[i + 1] += Ptr[i];
}
}
struct cooFormat {
int i;
int j;
int p; // permutation
struct cooFormat
{
int i;
int j;
int p; // permutation
};
int cmp_cooFormat_csr(struct cooFormat *s, struct cooFormat *t) {
if (s->i < t->i) {
return -1;
} else if (s->i > t->i) {
return 1;
} else {
return s->j - t->j;
}
int cmp_cooFormat_csr(struct cooFormat *s, struct cooFormat *t)
{
if (s->i < t->i) {
return -1;
}
else if (s->i > t->i) {
return 1;
}
else {
return s->j - t->j;
}
}
int cmp_cooFormat_csc(struct cooFormat *s, struct cooFormat *t) {
if (s->j < t->j) {
return -1;
} else if (s->j > t->j) {
return 1;
} else {
return s->i - t->i;
}
int cmp_cooFormat_csc(struct cooFormat *s, struct cooFormat *t)
{
if (s->j < t->j) {
return -1;
}
else if (s->j > t->j) {
return 1;
}
else {
return s->i - t->i;
}
}
typedef int (*FUNPTR)(const void *, const void *);
@@ -222,280 +167,326 @@ static FUNPTR2 fptr_array[2] = {
cmp_cooFormat_csc,
};
static int verify_pattern(int m, int nnz, int *csrRowPtr, int *csrColInd) {
int i, col, start, end, base_index;
int error_found = 0;
static int verify_pattern(int m, int nnz, int *csrRowPtr, int *csrColInd)
{
int i, col, start, end, base_index;
int error_found = 0;
if (nnz != (csrRowPtr[m] - csrRowPtr[0])) {
fprintf(stderr,
"Error (nnz check failed): (csrRowPtr[%d]=%d - csrRowPtr[%d]=%d) "
"!= (nnz=%d)\n",
0, csrRowPtr[0], m, csrRowPtr[m], nnz);
error_found = 1;
}
base_index = csrRowPtr[0];
if ((0 != base_index) && (1 != base_index)) {
fprintf(stderr, "Error (base index check failed): base index = %d\n",
base_index);
error_found = 1;
}
for (i = 0; (!error_found) && (i < m); i++) {
start = csrRowPtr[i] - base_index;
end = csrRowPtr[i + 1] - base_index;
if (start > end) {
fprintf(
stderr,
"Error (corrupted row): csrRowPtr[%d] (=%d) > csrRowPtr[%d] (=%d)\n",
i, start + base_index, i + 1, end + base_index);
error_found = 1;
}
for (col = start; col < end; col++) {
if (csrColInd[col] < base_index) {
fprintf(
stderr,
"Error (column vs. base index check failed): csrColInd[%d] < %d\n",
col, base_index);
error_found = 1;
}
if ((col < (end - 1)) && (csrColInd[col] >= csrColInd[col + 1])) {
if (nnz != (csrRowPtr[m] - csrRowPtr[0])) {
fprintf(stderr,
"Error (sorting of the column indecis check failed): "
"(csrColInd[%d]=%d) >= (csrColInd[%d]=%d)\n",
col, csrColInd[col], col + 1, csrColInd[col + 1]);
"Error (nnz check failed): (csrRowPtr[%d]=%d - csrRowPtr[%d]=%d) "
"!= (nnz=%d)\n",
0,
csrRowPtr[0],
m,
csrRowPtr[m],
nnz);
error_found = 1;
}
}
}
return error_found;
base_index = csrRowPtr[0];
if ((0 != base_index) && (1 != base_index)) {
fprintf(stderr, "Error (base index check failed): base index = %d\n", base_index);
error_found = 1;
}
for (i = 0; (!error_found) && (i < m); i++) {
start = csrRowPtr[i] - base_index;
end = csrRowPtr[i + 1] - base_index;
if (start > end) {
fprintf(stderr,
"Error (corrupted row): csrRowPtr[%d] (=%d) > csrRowPtr[%d] (=%d)\n",
i,
start + base_index,
i + 1,
end + base_index);
error_found = 1;
}
for (col = start; col < end; col++) {
if (csrColInd[col] < base_index) {
fprintf(stderr, "Error (column vs. base index check failed): csrColInd[%d] < %d\n", col, base_index);
error_found = 1;
}
if ((col < (end - 1)) && (csrColInd[col] >= csrColInd[col + 1])) {
fprintf(stderr,
"Error (sorting of the column indecis check failed): "
"(csrColInd[%d]=%d) >= (csrColInd[%d]=%d)\n",
col,
csrColInd[col],
col + 1,
csrColInd[col + 1]);
error_found = 1;
}
}
}
return error_found;
}
template <typename T_ELEM>
int loadMMSparseMatrix(char *filename, char elem_type, bool csrFormat, int *m,
int *n, int *nnz, T_ELEM **aVal, int **aRowInd,
int **aColInd, int extendSymMatrix) {
MM_typecode matcode;
double *tempVal;
int *tempRowInd, *tempColInd;
double *tval;
int *trow, *tcol;
int *csrRowPtr, *cscColPtr;
int i, j, error, base, count;
struct cooFormat *work;
int loadMMSparseMatrix(char *filename,
char elem_type,
bool csrFormat,
int *m,
int *n,
int *nnz,
T_ELEM **aVal,
int **aRowInd,
int **aColInd,
int extendSymMatrix)
{
MM_typecode matcode;
double *tempVal;
int *tempRowInd, *tempColInd;
double *tval;
int *trow, *tcol;
int *csrRowPtr, *cscColPtr;
int i, j, error, base, count;
struct cooFormat *work;
/* read the matrix */
error = mm_read_mtx_crd(filename, m, n, nnz, &trow, &tcol, &tval, &matcode);
if (error) {
fprintf(stderr, "!!!! can not open file: '%s'\n", filename);
return 1;
}
/* start error checking */
if (mm_is_complex(matcode) && ((elem_type != 'z') && (elem_type != 'c'))) {
fprintf(stderr, "!!!! complex matrix requires type 'z' or 'c'\n");
return 1;
}
if (mm_is_dense(matcode) || mm_is_array(matcode) ||
mm_is_pattern(matcode) /*|| mm_is_integer(matcode)*/) {
fprintf(
stderr,
"!!!! dense, array, pattern and integer matrices are not supported\n");
return 1;
}
/* if necessary symmetrize the pattern (transform from triangular to full) */
if ((extendSymMatrix) && (mm_is_symmetric(matcode) ||
mm_is_hermitian(matcode) || mm_is_skew(matcode))) {
// count number of non-diagonal elements
count = 0;
for (i = 0; i < (*nnz); i++) {
if (trow[i] != tcol[i]) {
count++;
}
/* read the matrix */
error = mm_read_mtx_crd(filename, m, n, nnz, &trow, &tcol, &tval, &matcode);
if (error) {
fprintf(stderr, "!!!! can not open file: '%s'\n", filename);
return 1;
}
// allocate space for the symmetrized matrix
tempRowInd = (int *)malloc((*nnz + count) * sizeof(int));
tempColInd = (int *)malloc((*nnz + count) * sizeof(int));
if (mm_is_real(matcode) || mm_is_integer(matcode)) {
tempVal = (double *)malloc((*nnz + count) * sizeof(double));
} else {
tempVal = (double *)malloc(2 * (*nnz + count) * sizeof(double));
/* start error checking */
if (mm_is_complex(matcode) && ((elem_type != 'z') && (elem_type != 'c'))) {
fprintf(stderr, "!!!! complex matrix requires type 'z' or 'c'\n");
return 1;
}
// copy the elements regular and transposed locations
for (j = 0, i = 0; i < (*nnz); i++) {
tempRowInd[j] = trow[i];
tempColInd[j] = tcol[i];
if (mm_is_real(matcode) || mm_is_integer(matcode)) {
tempVal[j] = tval[i];
} else {
tempVal[2 * j] = tval[2 * i];
tempVal[2 * j + 1] = tval[2 * i + 1];
}
j++;
if (trow[i] != tcol[i]) {
tempRowInd[j] = tcol[i];
tempColInd[j] = trow[i];
if (mm_is_real(matcode) || mm_is_integer(matcode)) {
if (mm_is_skew(matcode)) {
tempVal[j] = -tval[i];
} else {
tempVal[j] = tval[i];
}
} else {
if (mm_is_hermitian(matcode)) {
tempVal[2 * j] = tval[2 * i];
tempVal[2 * j + 1] = -tval[2 * i + 1];
} else {
tempVal[2 * j] = tval[2 * i];
tempVal[2 * j + 1] = tval[2 * i + 1];
}
if (mm_is_dense(matcode) || mm_is_array(matcode) || mm_is_pattern(matcode) /*|| mm_is_integer(matcode)*/) {
fprintf(stderr, "!!!! dense, array, pattern and integer matrices are not supported\n");
return 1;
}
/* if necessary symmetrize the pattern (transform from triangular to full) */
if ((extendSymMatrix) && (mm_is_symmetric(matcode) || mm_is_hermitian(matcode) || mm_is_skew(matcode))) {
// count number of non-diagonal elements
count = 0;
for (i = 0; i < (*nnz); i++) {
if (trow[i] != tcol[i]) {
count++;
}
}
j++;
}
// allocate space for the symmetrized matrix
tempRowInd = (int *)malloc((*nnz + count) * sizeof(int));
tempColInd = (int *)malloc((*nnz + count) * sizeof(int));
if (mm_is_real(matcode) || mm_is_integer(matcode)) {
tempVal = (double *)malloc((*nnz + count) * sizeof(double));
}
else {
tempVal = (double *)malloc(2 * (*nnz + count) * sizeof(double));
}
// copy the elements regular and transposed locations
for (j = 0, i = 0; i < (*nnz); i++) {
tempRowInd[j] = trow[i];
tempColInd[j] = tcol[i];
if (mm_is_real(matcode) || mm_is_integer(matcode)) {
tempVal[j] = tval[i];
}
else {
tempVal[2 * j] = tval[2 * i];
tempVal[2 * j + 1] = tval[2 * i + 1];
}
j++;
if (trow[i] != tcol[i]) {
tempRowInd[j] = tcol[i];
tempColInd[j] = trow[i];
if (mm_is_real(matcode) || mm_is_integer(matcode)) {
if (mm_is_skew(matcode)) {
tempVal[j] = -tval[i];
}
else {
tempVal[j] = tval[i];
}
}
else {
if (mm_is_hermitian(matcode)) {
tempVal[2 * j] = tval[2 * i];
tempVal[2 * j + 1] = -tval[2 * i + 1];
}
else {
tempVal[2 * j] = tval[2 * i];
tempVal[2 * j + 1] = tval[2 * i + 1];
}
}
j++;
}
}
(*nnz) += count;
// free temporary storage
free(trow);
free(tcol);
free(tval);
}
(*nnz) += count;
// free temporary storage
free(trow);
free(tcol);
free(tval);
} else {
tempRowInd = trow;
tempColInd = tcol;
tempVal = tval;
}
// life time of (trow, tcol, tval) is over.
// please use COO format (tempRowInd, tempColInd, tempVal)
// use qsort to sort COO format
work = (struct cooFormat *)malloc(sizeof(struct cooFormat) * (*nnz));
if (NULL == work) {
fprintf(stderr, "!!!! allocation error, malloc failed\n");
return 1;
}
for (i = 0; i < (*nnz); i++) {
work[i].i = tempRowInd[i];
work[i].j = tempColInd[i];
work[i].p = i; // permutation is identity
}
if (csrFormat) {
/* create row-major ordering of indices (sorted by row and within each row
* by column) */
qsort(work, *nnz, sizeof(struct cooFormat), (FUNPTR)fptr_array[0]);
} else {
/* create column-major ordering of indices (sorted by column and within each
* column by row) */
qsort(work, *nnz, sizeof(struct cooFormat), (FUNPTR)fptr_array[1]);
}
// (tempRowInd, tempColInd) is sorted either by row-major or by col-major
for (i = 0; i < (*nnz); i++) {
tempRowInd[i] = work[i].i;
tempColInd[i] = work[i].j;
}
// setup base
// check if there is any row/col 0, if so base-0
// check if there is any row/col equal to matrix dimension m/n, if so base-1
int base0 = 0;
int base1 = 0;
for (i = 0; i < (*nnz); i++) {
const int row = tempRowInd[i];
const int col = tempColInd[i];
if ((0 == row) || (0 == col)) {
base0 = 1;
else {
tempRowInd = trow;
tempColInd = tcol;
tempVal = tval;
}
if ((*m == row) || (*n == col)) {
base1 = 1;
// life time of (trow, tcol, tval) is over.
// please use COO format (tempRowInd, tempColInd, tempVal)
// use qsort to sort COO format
work = (struct cooFormat *)malloc(sizeof(struct cooFormat) * (*nnz));
if (NULL == work) {
fprintf(stderr, "!!!! allocation error, malloc failed\n");
return 1;
}
for (i = 0; i < (*nnz); i++) {
work[i].i = tempRowInd[i];
work[i].j = tempColInd[i];
work[i].p = i; // permutation is identity
}
}
if (base0 && base1) {
printf("Error: input matrix is base-0 and base-1 \n");
return 1;
}
base = 0;
if (base1) {
base = 1;
}
/* compress the appropriate indices */
if (csrFormat) {
/* CSR format (assuming row-major format) */
csrRowPtr = (int *)malloc(((*m) + 1) * sizeof(csrRowPtr[0]));
if (!csrRowPtr) return 1;
compress_index(tempRowInd, *nnz, *m, csrRowPtr, base);
*aRowInd = csrRowPtr;
*aColInd = (int *)malloc((*nnz) * sizeof(int));
} else {
/* CSC format (assuming column-major format) */
cscColPtr = (int *)malloc(((*n) + 1) * sizeof(cscColPtr[0]));
if (!cscColPtr) return 1;
compress_index(tempColInd, *nnz, *n, cscColPtr, base);
*aColInd = cscColPtr;
*aRowInd = (int *)malloc((*nnz) * sizeof(int));
}
/* transfrom the matrix values of type double into one of the cusparse library
* types */
*aVal = (T_ELEM *)malloc((*nnz) * sizeof(T_ELEM));
for (i = 0; i < (*nnz); i++) {
if (csrFormat) {
(*aColInd)[i] = tempColInd[i];
} else {
(*aRowInd)[i] = tempRowInd[i];
/* create row-major ordering of indices (sorted by row and within each row
* by column) */
qsort(work, *nnz, sizeof(struct cooFormat), (FUNPTR)fptr_array[0]);
}
if (mm_is_real(matcode) || mm_is_integer(matcode)) {
(*aVal)[i] = cuGet<T_ELEM>(tempVal[work[i].p]);
} else {
(*aVal)[i] =
cuGet<T_ELEM>(tempVal[2 * work[i].p], tempVal[2 * work[i].p + 1]);
else {
/* create column-major ordering of indices (sorted by column and within each
* column by row) */
qsort(work, *nnz, sizeof(struct cooFormat), (FUNPTR)fptr_array[1]);
}
}
/* check for corruption */
int error_found;
if (csrFormat) {
error_found = verify_pattern(*m, *nnz, *aRowInd, *aColInd);
} else {
error_found = verify_pattern(*n, *nnz, *aColInd, *aRowInd);
}
if (error_found) {
fprintf(stderr, "!!!! verify_pattern failed\n");
return 1;
}
// (tempRowInd, tempColInd) is sorted either by row-major or by col-major
for (i = 0; i < (*nnz); i++) {
tempRowInd[i] = work[i].i;
tempColInd[i] = work[i].j;
}
/* cleanup and exit */
free(work);
free(tempVal);
free(tempColInd);
free(tempRowInd);
// setup base
// check if there is any row/col 0, if so base-0
// check if there is any row/col equal to matrix dimension m/n, if so base-1
int base0 = 0;
int base1 = 0;
for (i = 0; i < (*nnz); i++) {
const int row = tempRowInd[i];
const int col = tempColInd[i];
if ((0 == row) || (0 == col)) {
base0 = 1;
}
if ((*m == row) || (*n == col)) {
base1 = 1;
}
}
if (base0 && base1) {
printf("Error: input matrix is base-0 and base-1 \n");
return 1;
}
return 0;
base = 0;
if (base1) {
base = 1;
}
/* compress the appropriate indices */
if (csrFormat) {
/* CSR format (assuming row-major format) */
csrRowPtr = (int *)malloc(((*m) + 1) * sizeof(csrRowPtr[0]));
if (!csrRowPtr)
return 1;
compress_index(tempRowInd, *nnz, *m, csrRowPtr, base);
*aRowInd = csrRowPtr;
*aColInd = (int *)malloc((*nnz) * sizeof(int));
}
else {
/* CSC format (assuming column-major format) */
cscColPtr = (int *)malloc(((*n) + 1) * sizeof(cscColPtr[0]));
if (!cscColPtr)
return 1;
compress_index(tempColInd, *nnz, *n, cscColPtr, base);
*aColInd = cscColPtr;
*aRowInd = (int *)malloc((*nnz) * sizeof(int));
}
/* transfrom the matrix values of type double into one of the cusparse library
* types */
*aVal = (T_ELEM *)malloc((*nnz) * sizeof(T_ELEM));
for (i = 0; i < (*nnz); i++) {
if (csrFormat) {
(*aColInd)[i] = tempColInd[i];
}
else {
(*aRowInd)[i] = tempRowInd[i];
}
if (mm_is_real(matcode) || mm_is_integer(matcode)) {
(*aVal)[i] = cuGet<T_ELEM>(tempVal[work[i].p]);
}
else {
(*aVal)[i] = cuGet<T_ELEM>(tempVal[2 * work[i].p], tempVal[2 * work[i].p + 1]);
}
}
/* check for corruption */
int error_found;
if (csrFormat) {
error_found = verify_pattern(*m, *nnz, *aRowInd, *aColInd);
}
else {
error_found = verify_pattern(*n, *nnz, *aColInd, *aRowInd);
}
if (error_found) {
fprintf(stderr, "!!!! verify_pattern failed\n");
return 1;
}
/* cleanup and exit */
free(work);
free(tempVal);
free(tempColInd);
free(tempRowInd);
return 0;
}
/* specific instantiation */
template int loadMMSparseMatrix<float>(char *filename, char elem_type,
bool csrFormat, int *m, int *n, int *nnz,
float **aVal, int **aRowInd,
int **aColInd, int extendSymMatrix);
template int loadMMSparseMatrix<float>(char *filename,
char elem_type,
bool csrFormat,
int *m,
int *n,
int *nnz,
float **aVal,
int **aRowInd,
int **aColInd,
int extendSymMatrix);
template int loadMMSparseMatrix<double>(char *filename, char elem_type,
bool csrFormat, int *m, int *n,
int *nnz, double **aVal, int **aRowInd,
int **aColInd, int extendSymMatrix);
template int loadMMSparseMatrix<double>(char *filename,
char elem_type,
bool csrFormat,
int *m,
int *n,
int *nnz,
double **aVal,
int **aRowInd,
int **aColInd,
int extendSymMatrix);
template int loadMMSparseMatrix<cuComplex>(char *filename, char elem_type,
bool csrFormat, int *m, int *n,
int *nnz, cuComplex **aVal,
int **aRowInd, int **aColInd,
int extendSymMatrix);
template int loadMMSparseMatrix<cuComplex>(char *filename,
char elem_type,
bool csrFormat,
int *m,
int *n,
int *nnz,
cuComplex **aVal,
int **aRowInd,
int **aColInd,
int extendSymMatrix);
template int loadMMSparseMatrix<cuDoubleComplex>(
char *filename, char elem_type, bool csrFormat, int *m, int *n, int *nnz,
cuDoubleComplex **aVal, int **aRowInd, int **aColInd, int extendSymMatrix);
template int loadMMSparseMatrix<cuDoubleComplex>(char *filename,
char elem_type,
bool csrFormat,
int *m,
int *n,
int *nnz,
cuDoubleComplex **aVal,
int **aRowInd,
int **aColInd,
int extendSymMatrix);

View File

@@ -37,4 +37,3 @@ Download and install the [CUDA Toolkit 12.5](https://developer.nvidia.com/cuda-d
Make sure the dependencies mentioned in [Dependencies]() section above are installed.
## References (for more details)

File diff suppressed because it is too large Load Diff

View File

@@ -34,68 +34,79 @@
#include <nvscisync.h>
#include <vector>
#define checkNvSciErrors(call) \
do { \
NvSciError _status = call; \
if (NvSciError_Success != _status) { \
printf( \
"NVSCI call in file '%s' in line %i returned" \
" %d, expected %d\n", \
__FILE__, __LINE__, _status, NvSciError_Success); \
fflush(stdout); \
exit(EXIT_FAILURE); \
} \
} while (0)
#define checkNvSciErrors(call) \
do { \
NvSciError _status = call; \
if (NvSciError_Success != _status) { \
printf("NVSCI call in file '%s' in line %i returned" \
" %d, expected %d\n", \
__FILE__, \
__LINE__, \
_status, \
NvSciError_Success); \
fflush(stdout); \
exit(EXIT_FAILURE); \
} \
} while (0)
extern void rotateKernel(cudaTextureObject_t &texObj, const float angle,
unsigned int *d_outputData, const int imageWidth,
const int imageHeight, cudaStream_t stream);
extern void rotateKernel(cudaTextureObject_t &texObj,
const float angle,
unsigned int *d_outputData,
const int imageWidth,
const int imageHeight,
cudaStream_t stream);
extern void launchGrayScaleKernel(unsigned int *d_rgbaImage,
std::string image_filename, size_t imageWidth,
size_t imageHeight, cudaStream_t stream);
std::string image_filename,
size_t imageWidth,
size_t imageHeight,
cudaStream_t stream);
class cudaNvSci {
private:
int m_isMultiGPU;
int m_cudaNvSciSignalDeviceId;
int m_cudaNvSciWaitDeviceId;
unsigned char *image_data;
size_t m_bufSize;
size_t imageWidth;
size_t imageHeight;
class cudaNvSci
{
private:
int m_isMultiGPU;
int m_cudaNvSciSignalDeviceId;
int m_cudaNvSciWaitDeviceId;
unsigned char *image_data;
size_t m_bufSize;
size_t imageWidth;
size_t imageHeight;
public:
NvSciSyncModule syncModule;
NvSciBufModule buffModule;
NvSciSyncAttrList syncUnreconciledList[2];
NvSciSyncAttrList syncReconciledList;
NvSciSyncAttrList syncConflictList;
public:
NvSciSyncModule syncModule;
NvSciBufModule buffModule;
NvSciSyncAttrList syncUnreconciledList[2];
NvSciSyncAttrList syncReconciledList;
NvSciSyncAttrList syncConflictList;
NvSciBufAttrList rawBufUnreconciledList[2];
NvSciBufAttrList imageBufUnreconciledList[2];
NvSciBufAttrList rawBufReconciledList;
NvSciBufAttrList buffConflictList;
NvSciBufAttrList imageBufReconciledList;
NvSciBufAttrList imageBufConflictList;
NvSciBufAttrList buffAttrListOut;
NvSciBufAttrList rawBufUnreconciledList[2];
NvSciBufAttrList imageBufUnreconciledList[2];
NvSciBufAttrList rawBufReconciledList;
NvSciBufAttrList buffConflictList;
NvSciBufAttrList imageBufReconciledList;
NvSciBufAttrList imageBufConflictList;
NvSciBufAttrList buffAttrListOut;
NvSciSyncObj syncObj;
NvSciBufObj rawBufObj;
NvSciBufObj imageBufObj;
NvSciSyncFence *fence;
NvSciSyncObj syncObj;
NvSciBufObj rawBufObj;
NvSciBufObj imageBufObj;
NvSciSyncFence *fence;
cudaNvSci(int isMultiGPU, std::vector<int> &deviceIds,
unsigned char *image_data, size_t imageWidth, size_t imageHeight);
cudaNvSci(int isMultiGPU,
std::vector<int> &deviceIds,
unsigned char *image_data,
size_t imageWidth,
size_t imageHeight);
void initNvSci();
void initNvSci();
void runCudaNvSci(std::string &image_filename);
void runCudaNvSci(std::string &image_filename);
void createNvSciRawBufObj();
void createNvSciRawBufObj();
void createNvSciSyncObj();
void createNvSciSyncObj();
void createNvSciBufImageObj();
void createNvSciBufImageObj();
};
#endif // CUDANVSCI_H
#endif // CUDANVSCI_H

View File

@@ -30,91 +30,90 @@
#include <helper_image.h>
// convert floating point rgba color to 32-bit integer
__device__ unsigned int rgbaFloatToInt(float4 rgba) {
rgba.x = __saturatef(rgba.x); // clamp to [0.0, 1.0]
rgba.y = __saturatef(rgba.y);
rgba.z = __saturatef(rgba.z);
rgba.w = __saturatef(rgba.w);
return ((unsigned int)(rgba.w * 255.0f) << 24) |
((unsigned int)(rgba.z * 255.0f) << 16) |
((unsigned int)(rgba.y * 255.0f) << 8) |
((unsigned int)(rgba.x * 255.0f));
__device__ unsigned int rgbaFloatToInt(float4 rgba)
{
rgba.x = __saturatef(rgba.x); // clamp to [0.0, 1.0]
rgba.y = __saturatef(rgba.y);
rgba.z = __saturatef(rgba.z);
rgba.w = __saturatef(rgba.w);
return ((unsigned int)(rgba.w * 255.0f) << 24) | ((unsigned int)(rgba.z * 255.0f) << 16)
| ((unsigned int)(rgba.y * 255.0f) << 8) | ((unsigned int)(rgba.x * 255.0f));
}
////////////////////////////////////////////////////////////////////////////////
//! Rotate an image using texture lookups
//! @param outputData output data in global memory
////////////////////////////////////////////////////////////////////////////////
static __global__ void transformKernel(unsigned int *outputData, int width,
int height, float theta,
cudaTextureObject_t tex) {
// calculate normalized texture coordinates
unsigned int x = blockIdx.x * blockDim.x + threadIdx.x;
unsigned int y = blockIdx.y * blockDim.y + threadIdx.y;
static __global__ void
transformKernel(unsigned int *outputData, int width, int height, float theta, cudaTextureObject_t tex)
{
// calculate normalized texture coordinates
unsigned int x = blockIdx.x * blockDim.x + threadIdx.x;
unsigned int y = blockIdx.y * blockDim.y + threadIdx.y;
float u = (float)x - (float)width / 2;
float v = (float)y - (float)height / 2;
float tu = u * cosf(theta) - v * sinf(theta);
float tv = v * cosf(theta) + u * sinf(theta);
float u = (float)x - (float)width / 2;
float v = (float)y - (float)height / 2;
float tu = u * cosf(theta) - v * sinf(theta);
float tv = v * cosf(theta) + u * sinf(theta);
tu /= (float)width;
tv /= (float)height;
tu /= (float)width;
tv /= (float)height;
// read from texture and write to global memory
float4 pix = tex2D<float4>(tex, tu + 0.5f, tv + 0.5f);
unsigned int pixelInt = rgbaFloatToInt(pix);
outputData[y * width + x] = pixelInt;
// read from texture and write to global memory
float4 pix = tex2D<float4>(tex, tu + 0.5f, tv + 0.5f);
unsigned int pixelInt = rgbaFloatToInt(pix);
outputData[y * width + x] = pixelInt;
}
static __global__ void rgbToGrayscaleKernel(unsigned int *rgbaImage,
size_t imageWidth,
size_t imageHeight) {
size_t gidX = blockDim.x * blockIdx.x + threadIdx.x;
static __global__ void rgbToGrayscaleKernel(unsigned int *rgbaImage, size_t imageWidth, size_t imageHeight)
{
size_t gidX = blockDim.x * blockIdx.x + threadIdx.x;
uchar4 *pixArray = (uchar4 *)rgbaImage;
uchar4 *pixArray = (uchar4 *)rgbaImage;
for (int pixId = gidX; pixId < imageWidth * imageHeight;
pixId += gridDim.x * blockDim.x) {
uchar4 dataA = pixArray[pixId];
unsigned char grayscale =
(unsigned char)(dataA.x * 0.3 + dataA.y * 0.59 + dataA.z * 0.11);
uchar4 dataB = make_uchar4(grayscale, grayscale, grayscale, 0);
pixArray[pixId] = dataB;
}
for (int pixId = gidX; pixId < imageWidth * imageHeight; pixId += gridDim.x * blockDim.x) {
uchar4 dataA = pixArray[pixId];
unsigned char grayscale = (unsigned char)(dataA.x * 0.3 + dataA.y * 0.59 + dataA.z * 0.11);
uchar4 dataB = make_uchar4(grayscale, grayscale, grayscale, 0);
pixArray[pixId] = dataB;
}
}
void launchGrayScaleKernel(unsigned int *d_rgbaImage,
std::string image_filename, size_t imageWidth,
size_t imageHeight, cudaStream_t stream) {
int numThreadsPerBlock = 1024;
int numOfBlocks = (imageWidth * imageHeight) / numThreadsPerBlock;
std::string image_filename,
size_t imageWidth,
size_t imageHeight,
cudaStream_t stream)
{
int numThreadsPerBlock = 1024;
int numOfBlocks = (imageWidth * imageHeight) / numThreadsPerBlock;
rgbToGrayscaleKernel<<<numOfBlocks, numThreadsPerBlock, 0, stream>>>(
d_rgbaImage, imageWidth, imageHeight);
rgbToGrayscaleKernel<<<numOfBlocks, numThreadsPerBlock, 0, stream>>>(d_rgbaImage, imageWidth, imageHeight);
unsigned int *outputData;
checkCudaErrors(cudaMallocHost((void**)&outputData, sizeof(unsigned int) * imageWidth * imageHeight));
checkCudaErrors(cudaMemcpyAsync(
outputData, d_rgbaImage, sizeof(unsigned int) * imageWidth * imageHeight,
cudaMemcpyDeviceToHost, stream));
checkCudaErrors(cudaStreamSynchronize(stream));
unsigned int *outputData;
checkCudaErrors(cudaMallocHost((void **)&outputData, sizeof(unsigned int) * imageWidth * imageHeight));
checkCudaErrors(cudaMemcpyAsync(
outputData, d_rgbaImage, sizeof(unsigned int) * imageWidth * imageHeight, cudaMemcpyDeviceToHost, stream));
checkCudaErrors(cudaStreamSynchronize(stream));
char outputFilename[1024];
strcpy(outputFilename, image_filename.c_str());
strcpy(outputFilename + image_filename.length() - 4, "_out.ppm");
sdkSavePPM4ub(outputFilename, (unsigned char *)outputData, imageWidth,
imageHeight);
printf("Wrote '%s'\n", outputFilename);
char outputFilename[1024];
strcpy(outputFilename, image_filename.c_str());
strcpy(outputFilename + image_filename.length() - 4, "_out.ppm");
sdkSavePPM4ub(outputFilename, (unsigned char *)outputData, imageWidth, imageHeight);
printf("Wrote '%s'\n", outputFilename);
checkCudaErrors(cudaFreeHost(outputData));
checkCudaErrors(cudaFreeHost(outputData));
}
void rotateKernel(cudaTextureObject_t &texObj, const float angle,
unsigned int *d_outputData, const int imageWidth,
const int imageHeight, cudaStream_t stream) {
dim3 dimBlock(8, 8, 1);
dim3 dimGrid(imageWidth / dimBlock.x, imageHeight / dimBlock.y, 1);
void rotateKernel(cudaTextureObject_t &texObj,
const float angle,
unsigned int *d_outputData,
const int imageWidth,
const int imageHeight,
cudaStream_t stream)
{
dim3 dimBlock(8, 8, 1);
dim3 dimGrid(imageWidth / dimBlock.x, imageHeight / dimBlock.y, 1);
transformKernel<<<dimGrid, dimBlock, 0, stream>>>(d_outputData, imageWidth,
imageHeight, angle, texObj);
transformKernel<<<dimGrid, dimBlock, 0, stream>>>(d_outputData, imageWidth, imageHeight, angle, texObj);
}

View File

@@ -26,76 +26,77 @@
*/
#include <cuda.h>
#include <vector>
#include "cudaNvSci.h"
#include <helper_cuda.h>
#include <helper_image.h>
#include <vector>
void loadImageData(const std::string &filename, const char **argv,
unsigned char **image_data, uint32_t &imageWidth,
uint32_t &imageHeight) {
// load image (needed so we can get the width and height before we create
// the window
char *image_path = sdkFindFilePath(filename.c_str(), argv[0]);
#include "cudaNvSci.h"
if (image_path == 0) {
printf("Error finding image file '%s'\n", filename.c_str());
exit(EXIT_FAILURE);
}
void loadImageData(const std::string &filename,
const char **argv,
unsigned char **image_data,
uint32_t &imageWidth,
uint32_t &imageHeight)
{
// load image (needed so we can get the width and height before we create
// the window
char *image_path = sdkFindFilePath(filename.c_str(), argv[0]);
sdkLoadPPM4(image_path, image_data, &imageWidth, &imageHeight);
if (image_path == 0) {
printf("Error finding image file '%s'\n", filename.c_str());
exit(EXIT_FAILURE);
}
if (!image_data) {
printf("Error opening file '%s'\n", image_path);
exit(EXIT_FAILURE);
}
sdkLoadPPM4(image_path, image_data, &imageWidth, &imageHeight);
printf("Loaded '%s', %d x %d pixels\n", image_path, imageWidth, imageHeight);
if (!image_data) {
printf("Error opening file '%s'\n", image_path);
exit(EXIT_FAILURE);
}
printf("Loaded '%s', %d x %d pixels\n", image_path, imageWidth, imageHeight);
}
int main(int argc, const char **argv) {
int numOfGPUs = 0;
std::vector<int> deviceIds;
checkCudaErrors(cudaGetDeviceCount(&numOfGPUs));
int main(int argc, const char **argv)
{
int numOfGPUs = 0;
std::vector<int> deviceIds;
checkCudaErrors(cudaGetDeviceCount(&numOfGPUs));
printf("%d GPUs found\n", numOfGPUs);
if (!numOfGPUs) {
exit(EXIT_WAIVED);
} else {
for (int devID = 0; devID < numOfGPUs; devID++) {
int major = 0, minor = 0;
checkCudaErrors(cudaDeviceGetAttribute(
&major, cudaDevAttrComputeCapabilityMajor, devID));
checkCudaErrors(cudaDeviceGetAttribute(
&minor, cudaDevAttrComputeCapabilityMinor, devID));
if (major >= 6) {
deviceIds.push_back(devID);
}
printf("%d GPUs found\n", numOfGPUs);
if (!numOfGPUs) {
exit(EXIT_WAIVED);
}
if (deviceIds.size() == 0) {
printf(
"cudaNvSci requires one or more GPUs of Pascal(SM 6.0) or higher "
"archs\nWaiving..\n");
exit(EXIT_WAIVED);
else {
for (int devID = 0; devID < numOfGPUs; devID++) {
int major = 0, minor = 0;
checkCudaErrors(cudaDeviceGetAttribute(&major, cudaDevAttrComputeCapabilityMajor, devID));
checkCudaErrors(cudaDeviceGetAttribute(&minor, cudaDevAttrComputeCapabilityMinor, devID));
if (major >= 6) {
deviceIds.push_back(devID);
}
}
if (deviceIds.size() == 0) {
printf("cudaNvSci requires one or more GPUs of Pascal(SM 6.0) or higher "
"archs\nWaiving..\n");
exit(EXIT_WAIVED);
}
}
}
std::string image_filename = "teapot1024.ppm";
std::string image_filename = "teapot1024.ppm";
if (checkCmdLineFlag(argc, (const char **)argv, "file")) {
getCmdLineArgumentString(argc, (const char **)argv, "file",
(char **)&image_filename);
}
if (checkCmdLineFlag(argc, (const char **)argv, "file")) {
getCmdLineArgumentString(argc, (const char **)argv, "file", (char **)&image_filename);
}
uint32_t imageWidth = 0;
uint32_t imageHeight = 0;
unsigned char *image_data = NULL;
uint32_t imageWidth = 0;
uint32_t imageHeight = 0;
unsigned char *image_data = NULL;
loadImageData(image_filename, argv, &image_data, imageWidth, imageHeight);
loadImageData(image_filename, argv, &image_data, imageWidth, imageHeight);
cudaNvSci cudaNvSciApp(deviceIds.size() > 1, deviceIds, image_data,
imageWidth, imageHeight);
cudaNvSciApp.runCudaNvSci(image_filename);
cudaNvSci cudaNvSciApp(deviceIds.size() > 1, deviceIds, image_data, imageWidth, imageHeight);
cudaNvSciApp.runCudaNvSci(image_filename);
return EXIT_SUCCESS;
}
return EXIT_SUCCESS;
}

View File

@@ -36,285 +36,290 @@
#include <windows.h>
#endif
#include "FreeImage.h"
#include "Exceptions.h"
// Common Helpers
#include <string.h>
#include "Exceptions.h"
#include "FreeImage.h"
// Other Includes
#include <cuda_runtime.h>
#include <fstream>
#include <iostream>
#include <npp.h> // CUDA NPP Definitions
#include <string.h>
#include <cuda_runtime.h>
#include <npp.h> // CUDA NPP Definitions
// Other helpers
#include <helper_cuda.h> // helper for CUDA Error handling and initialization
#include <helper_string.h> // helper for string parsing
#include <helper_cuda.h> // helper for CUDA Error handling and initialization
#include <helper_string.h> // helper for string parsing
inline int cudaDeviceInit(int argc, const char **argv)
{
int deviceCount;
checkCudaErrors(cudaGetDeviceCount(&deviceCount));
inline int cudaDeviceInit(int argc, const char **argv) {
int deviceCount;
checkCudaErrors(cudaGetDeviceCount(&deviceCount));
if (deviceCount == 0) {
std::cerr << "CUDA error: no devices supporting CUDA." << std::endl;
exit(EXIT_FAILURE);
}
if (deviceCount == 0) {
std::cerr << "CUDA error: no devices supporting CUDA." << std::endl;
exit(EXIT_FAILURE);
}
int dev = findCudaDevice(argc, argv);
int dev = findCudaDevice(argc, argv);
cudaDeviceProp deviceProp;
cudaGetDeviceProperties(&deviceProp, dev);
std::cerr << "cudaSetDevice GPU" << dev << " = " << deviceProp.name << std::endl;
cudaDeviceProp deviceProp;
cudaGetDeviceProperties(&deviceProp, dev);
std::cerr << "cudaSetDevice GPU" << dev << " = " << deviceProp.name
<< std::endl;
checkCudaErrors(cudaSetDevice(dev));
checkCudaErrors(cudaSetDevice(dev));
return dev;
return dev;
}
// Error handler for FreeImage library.
// In case this handler is invoked, it throws an NPP exception.
extern "C" void FreeImageErrorHandler(FREE_IMAGE_FORMAT oFif,
const char *zMessage) {
throw npp::Exception(zMessage);
}
extern "C" void FreeImageErrorHandler(FREE_IMAGE_FORMAT oFif, const char *zMessage) { throw npp::Exception(zMessage); }
std::ostream &operator<<(std::ostream &rOutputStream, const FIBITMAP &rBitmap) {
unsigned int nImageWidth =
FreeImage_GetWidth(const_cast<FIBITMAP *>(&rBitmap));
unsigned int nImageHeight =
FreeImage_GetHeight(const_cast<FIBITMAP *>(&rBitmap));
unsigned int nPitch = FreeImage_GetPitch(const_cast<FIBITMAP *>(&rBitmap));
unsigned int nBPP = FreeImage_GetBPP(const_cast<FIBITMAP *>(&rBitmap));
std::ostream &operator<<(std::ostream &rOutputStream, const FIBITMAP &rBitmap)
{
unsigned int nImageWidth = FreeImage_GetWidth(const_cast<FIBITMAP *>(&rBitmap));
unsigned int nImageHeight = FreeImage_GetHeight(const_cast<FIBITMAP *>(&rBitmap));
unsigned int nPitch = FreeImage_GetPitch(const_cast<FIBITMAP *>(&rBitmap));
unsigned int nBPP = FreeImage_GetBPP(const_cast<FIBITMAP *>(&rBitmap));
FREE_IMAGE_COLOR_TYPE eType =
FreeImage_GetColorType(const_cast<FIBITMAP *>(&rBitmap));
FREE_IMAGE_COLOR_TYPE eType = FreeImage_GetColorType(const_cast<FIBITMAP *>(&rBitmap));
rOutputStream << "Size (" << nImageWidth << ", " << nImageHeight << ")\n";
rOutputStream << "Pitch " << nPitch << "\n";
rOutputStream << "Type ";
rOutputStream << "Size (" << nImageWidth << ", " << nImageHeight << ")\n";
rOutputStream << "Pitch " << nPitch << "\n";
rOutputStream << "Type ";
switch (eType) {
switch (eType) {
case FIC_MINISWHITE:
rOutputStream << "FIC_MINISWHITE\n";
break;
rOutputStream << "FIC_MINISWHITE\n";
break;
case FIC_MINISBLACK:
rOutputStream << "FIC_MINISBLACK\n";
break;
rOutputStream << "FIC_MINISBLACK\n";
break;
case FIC_RGB:
rOutputStream << "FIC_RGB\n";
break;
rOutputStream << "FIC_RGB\n";
break;
case FIC_PALETTE:
rOutputStream << "FIC_PALETTE\n";
break;
rOutputStream << "FIC_PALETTE\n";
break;
case FIC_RGBALPHA:
rOutputStream << "FIC_RGBALPHA\n";
break;
rOutputStream << "FIC_RGBALPHA\n";
break;
case FIC_CMYK:
rOutputStream << "FIC_CMYK\n";
break;
rOutputStream << "FIC_CMYK\n";
break;
default:
rOutputStream << "Unknown pixel format.\n";
}
rOutputStream << "Unknown pixel format.\n";
}
rOutputStream << "BPP " << nBPP << std::endl;
rOutputStream << "BPP " << nBPP << std::endl;
return rOutputStream;
return rOutputStream;
}
int main(int argc, char *argv[]) {
printf("%s Starting...\n\n", argv[0]);
int main(int argc, char *argv[])
{
printf("%s Starting...\n\n", argv[0]);
try {
std::string sFilename;
char *filePath;
try {
std::string sFilename;
char *filePath;
// set your own FreeImage error handler
FreeImage_SetOutputMessage(FreeImageErrorHandler);
// set your own FreeImage error handler
FreeImage_SetOutputMessage(FreeImageErrorHandler);
cudaDeviceInit(argc, (const char **)argv);
cudaDeviceInit(argc, (const char **)argv);
NppStreamContext nppStreamCtx;
nppStreamCtx.hStream = 0; // The NULL stream by default, set this to whatever your stream ID is if not the NULL stream.
NppStreamContext nppStreamCtx;
nppStreamCtx.hStream =
0; // The NULL stream by default, set this to whatever your stream ID is if not the NULL stream.
cudaError_t cudaError = cudaGetDevice(&nppStreamCtx.nCudaDeviceId);
if (cudaError != cudaSuccess)
{
printf("CUDA error: no devices supporting CUDA.\n");
return NPP_NOT_SUFFICIENT_COMPUTE_CAPABILITY;
cudaError_t cudaError = cudaGetDevice(&nppStreamCtx.nCudaDeviceId);
if (cudaError != cudaSuccess) {
printf("CUDA error: no devices supporting CUDA.\n");
return NPP_NOT_SUFFICIENT_COMPUTE_CAPABILITY;
}
const NppLibraryVersion *libVer = nppGetLibVersion();
printf("NPP Library Version %d.%d.%d\n", libVer->major, libVer->minor, libVer->build);
int driverVersion, runtimeVersion;
cudaDriverGetVersion(&driverVersion);
cudaRuntimeGetVersion(&runtimeVersion);
printf("CUDA Driver Version: %d.%d\n", driverVersion / 1000, (driverVersion % 100) / 10);
printf("CUDA Runtime Version: %d.%d\n\n", runtimeVersion / 1000, (runtimeVersion % 100) / 10);
cudaError = cudaDeviceGetAttribute(&nppStreamCtx.nCudaDevAttrComputeCapabilityMajor,
cudaDevAttrComputeCapabilityMajor,
nppStreamCtx.nCudaDeviceId);
if (cudaError != cudaSuccess)
return NPP_NOT_SUFFICIENT_COMPUTE_CAPABILITY;
cudaError = cudaDeviceGetAttribute(&nppStreamCtx.nCudaDevAttrComputeCapabilityMinor,
cudaDevAttrComputeCapabilityMinor,
nppStreamCtx.nCudaDeviceId);
if (cudaError != cudaSuccess)
return NPP_NOT_SUFFICIENT_COMPUTE_CAPABILITY;
cudaError = cudaStreamGetFlags(nppStreamCtx.hStream, &nppStreamCtx.nStreamFlags);
cudaDeviceProp oDeviceProperties;
cudaError = cudaGetDeviceProperties(&oDeviceProperties, nppStreamCtx.nCudaDeviceId);
nppStreamCtx.nMultiProcessorCount = oDeviceProperties.multiProcessorCount;
nppStreamCtx.nMaxThreadsPerMultiProcessor = oDeviceProperties.maxThreadsPerMultiProcessor;
nppStreamCtx.nMaxThreadsPerBlock = oDeviceProperties.maxThreadsPerBlock;
nppStreamCtx.nSharedMemPerBlock = oDeviceProperties.sharedMemPerBlock;
if (checkCmdLineFlag(argc, (const char **)argv, "input")) {
getCmdLineArgumentString(argc, (const char **)argv, "input", &filePath);
}
else {
filePath = sdkFindFilePath("teapot512.pgm", argv[0]);
}
if (filePath) {
sFilename = filePath;
}
else {
sFilename = "teapot512.pgm";
}
// if we specify the filename at the command line, then we only test
// sFilename otherwise we will check both sFilename[0,1]
int file_errors = 0;
std::ifstream infile(sFilename.data(), std::ifstream::in);
if (infile.good()) {
std::cout << "freeImageInteropNPP opened: <" << sFilename.data() << "> successfully!" << std::endl;
file_errors = 0;
infile.close();
}
else {
std::cout << "freeImageInteropNPP unable to open: <" << sFilename.data() << ">" << std::endl;
file_errors++;
infile.close();
}
if (file_errors > 0) {
exit(EXIT_FAILURE);
}
std::string sResultFilename = sFilename;
std::string::size_type dot = sResultFilename.rfind('.');
if (dot != std::string::npos) {
sResultFilename = sResultFilename.substr(0, dot);
}
sResultFilename += "_boxFilterFII.pgm";
if (checkCmdLineFlag(argc, (const char **)argv, "output")) {
char *outputFilePath;
getCmdLineArgumentString(argc, (const char **)argv, "output", &outputFilePath);
sResultFilename = outputFilePath;
}
FREE_IMAGE_FORMAT eFormat = FreeImage_GetFileType(sFilename.c_str());
// no signature? try to guess the file format from the file extension
if (eFormat == FIF_UNKNOWN) {
eFormat = FreeImage_GetFIFFromFilename(sFilename.c_str());
}
NPP_ASSERT(eFormat != FIF_UNKNOWN);
// check that the plugin has reading capabilities ...
FIBITMAP *pBitmap;
if (FreeImage_FIFSupportsReading(eFormat)) {
pBitmap = FreeImage_Load(eFormat, sFilename.c_str());
}
NPP_ASSERT(pBitmap != 0);
// Dump the bitmap information to the console
std::cout << (*pBitmap) << std::endl;
// make sure this is an 8-bit single channel image
NPP_ASSERT(FreeImage_GetColorType(pBitmap) == FIC_MINISBLACK);
NPP_ASSERT(FreeImage_GetBPP(pBitmap) == 8);
unsigned int nImageWidth = FreeImage_GetWidth(pBitmap);
unsigned int nImageHeight = FreeImage_GetHeight(pBitmap);
unsigned int nSrcPitch = FreeImage_GetPitch(pBitmap);
unsigned char *pSrcData = FreeImage_GetBits(pBitmap);
int nSrcPitchCUDA;
Npp8u *pSrcImageCUDA = nppiMalloc_8u_C1(nImageWidth, nImageHeight, &nSrcPitchCUDA);
NPP_ASSERT_NOT_NULL(pSrcImageCUDA);
// copy image loaded via FreeImage to into CUDA device memory, i.e.
// transfer the image-data up to the GPU's video-memory
NPP_CHECK_CUDA(cudaMemcpy2D(
pSrcImageCUDA, nSrcPitchCUDA, pSrcData, nSrcPitch, nImageWidth, nImageHeight, cudaMemcpyHostToDevice));
// define size of the box filter
const NppiSize oMaskSize = {7, 7};
const NppiPoint oMaskAchnor = {0, 0};
// compute maximal result image size
const NppiSize oSizeROI = {(int)nImageWidth - (oMaskSize.width - 1),
(int)nImageHeight - (oMaskSize.height - 1)};
// allocate result image memory
int nDstPitchCUDA;
Npp8u *pDstImageCUDA = nppiMalloc_8u_C1(oSizeROI.width, oSizeROI.height, &nDstPitchCUDA);
NPP_ASSERT_NOT_NULL(pDstImageCUDA);
NPP_CHECK_NPP(nppiFilterBox_8u_C1R_Ctx(pSrcImageCUDA,
nSrcPitchCUDA,
pDstImageCUDA,
nDstPitchCUDA,
oSizeROI,
oMaskSize,
oMaskAchnor,
nppStreamCtx));
// create the result image storage using FreeImage so we can easily
// save
FIBITMAP *pResultBitmap = FreeImage_Allocate(oSizeROI.width, oSizeROI.height, 8 /* bits per pixel */);
NPP_ASSERT_NOT_NULL(pResultBitmap);
unsigned int nResultPitch = FreeImage_GetPitch(pResultBitmap);
unsigned char *pResultData = FreeImage_GetBits(pResultBitmap);
NPP_CHECK_CUDA(cudaMemcpy2D(pResultData,
nResultPitch,
pDstImageCUDA,
nDstPitchCUDA,
oSizeROI.width,
oSizeROI.height,
cudaMemcpyDeviceToHost));
// now save the result image
bool bSuccess;
bSuccess = FreeImage_Save(FIF_PGM, pResultBitmap, sResultFilename.c_str(), 0) == TRUE;
NPP_ASSERT_MSG(bSuccess, "Failed to save result image.");
// free nppiImage
nppiFree(pSrcImageCUDA);
nppiFree(pDstImageCUDA);
exit(EXIT_SUCCESS);
}
const NppLibraryVersion *libVer = nppGetLibVersion();
printf("NPP Library Version %d.%d.%d\n", libVer->major, libVer->minor, libVer->build);
int driverVersion, runtimeVersion;
cudaDriverGetVersion(&driverVersion);
cudaRuntimeGetVersion(&runtimeVersion);
printf("CUDA Driver Version: %d.%d\n", driverVersion/1000, (driverVersion%100)/10);
printf("CUDA Runtime Version: %d.%d\n\n", runtimeVersion/1000, (runtimeVersion%100)/10);
cudaError = cudaDeviceGetAttribute(&nppStreamCtx.nCudaDevAttrComputeCapabilityMajor,
cudaDevAttrComputeCapabilityMajor,
nppStreamCtx.nCudaDeviceId);
if (cudaError != cudaSuccess)
return NPP_NOT_SUFFICIENT_COMPUTE_CAPABILITY;
cudaError = cudaDeviceGetAttribute(&nppStreamCtx.nCudaDevAttrComputeCapabilityMinor,
cudaDevAttrComputeCapabilityMinor,
nppStreamCtx.nCudaDeviceId);
if (cudaError != cudaSuccess)
return NPP_NOT_SUFFICIENT_COMPUTE_CAPABILITY;
cudaError = cudaStreamGetFlags(nppStreamCtx.hStream, &nppStreamCtx.nStreamFlags);
cudaDeviceProp oDeviceProperties;
cudaError = cudaGetDeviceProperties(&oDeviceProperties, nppStreamCtx.nCudaDeviceId);
nppStreamCtx.nMultiProcessorCount = oDeviceProperties.multiProcessorCount;
nppStreamCtx.nMaxThreadsPerMultiProcessor = oDeviceProperties.maxThreadsPerMultiProcessor;
nppStreamCtx.nMaxThreadsPerBlock = oDeviceProperties.maxThreadsPerBlock;
nppStreamCtx.nSharedMemPerBlock = oDeviceProperties.sharedMemPerBlock;
if (checkCmdLineFlag(argc, (const char **)argv, "input")) {
getCmdLineArgumentString(argc, (const char **)argv, "input", &filePath);
} else {
filePath = sdkFindFilePath("teapot512.pgm", argv[0]);
catch (npp::Exception &rException) {
std::cerr << "Program error! The following exception occurred: \n";
std::cerr << rException << std::endl;
std::cerr << "Aborting." << std::endl;
exit(EXIT_FAILURE);
}
if (filePath) {
sFilename = filePath;
} else {
sFilename = "teapot512.pgm";
catch (...) {
std::cerr << "Program error! An unknow type of exception occurred. \n";
std::cerr << "Aborting." << std::endl;
exit(EXIT_FAILURE);
}
// if we specify the filename at the command line, then we only test
// sFilename otherwise we will check both sFilename[0,1]
int file_errors = 0;
std::ifstream infile(sFilename.data(), std::ifstream::in);
if (infile.good()) {
std::cout << "freeImageInteropNPP opened: <" << sFilename.data()
<< "> successfully!" << std::endl;
file_errors = 0;
infile.close();
} else {
std::cout << "freeImageInteropNPP unable to open: <" << sFilename.data()
<< ">" << std::endl;
file_errors++;
infile.close();
}
if (file_errors > 0) {
exit(EXIT_FAILURE);
}
std::string sResultFilename = sFilename;
std::string::size_type dot = sResultFilename.rfind('.');
if (dot != std::string::npos) {
sResultFilename = sResultFilename.substr(0, dot);
}
sResultFilename += "_boxFilterFII.pgm";
if (checkCmdLineFlag(argc, (const char **)argv, "output")) {
char *outputFilePath;
getCmdLineArgumentString(argc, (const char **)argv, "output",
&outputFilePath);
sResultFilename = outputFilePath;
}
FREE_IMAGE_FORMAT eFormat = FreeImage_GetFileType(sFilename.c_str());
// no signature? try to guess the file format from the file extension
if (eFormat == FIF_UNKNOWN) {
eFormat = FreeImage_GetFIFFromFilename(sFilename.c_str());
}
NPP_ASSERT(eFormat != FIF_UNKNOWN);
// check that the plugin has reading capabilities ...
FIBITMAP *pBitmap;
if (FreeImage_FIFSupportsReading(eFormat)) {
pBitmap = FreeImage_Load(eFormat, sFilename.c_str());
}
NPP_ASSERT(pBitmap != 0);
// Dump the bitmap information to the console
std::cout << (*pBitmap) << std::endl;
// make sure this is an 8-bit single channel image
NPP_ASSERT(FreeImage_GetColorType(pBitmap) == FIC_MINISBLACK);
NPP_ASSERT(FreeImage_GetBPP(pBitmap) == 8);
unsigned int nImageWidth = FreeImage_GetWidth(pBitmap);
unsigned int nImageHeight = FreeImage_GetHeight(pBitmap);
unsigned int nSrcPitch = FreeImage_GetPitch(pBitmap);
unsigned char *pSrcData = FreeImage_GetBits(pBitmap);
int nSrcPitchCUDA;
Npp8u *pSrcImageCUDA =
nppiMalloc_8u_C1(nImageWidth, nImageHeight, &nSrcPitchCUDA);
NPP_ASSERT_NOT_NULL(pSrcImageCUDA);
// copy image loaded via FreeImage to into CUDA device memory, i.e.
// transfer the image-data up to the GPU's video-memory
NPP_CHECK_CUDA(cudaMemcpy2D(pSrcImageCUDA, nSrcPitchCUDA, pSrcData,
nSrcPitch, nImageWidth, nImageHeight,
cudaMemcpyHostToDevice));
// define size of the box filter
const NppiSize oMaskSize = {7, 7};
const NppiPoint oMaskAchnor = {0, 0};
// compute maximal result image size
const NppiSize oSizeROI = {(int)nImageWidth - (oMaskSize.width - 1),
(int)nImageHeight - (oMaskSize.height - 1)};
// allocate result image memory
int nDstPitchCUDA;
Npp8u *pDstImageCUDA =
nppiMalloc_8u_C1(oSizeROI.width, oSizeROI.height, &nDstPitchCUDA);
NPP_ASSERT_NOT_NULL(pDstImageCUDA);
NPP_CHECK_NPP(nppiFilterBox_8u_C1R_Ctx(pSrcImageCUDA, nSrcPitchCUDA,
pDstImageCUDA, nDstPitchCUDA, oSizeROI,
oMaskSize, oMaskAchnor, nppStreamCtx));
// create the result image storage using FreeImage so we can easily
// save
FIBITMAP *pResultBitmap = FreeImage_Allocate(
oSizeROI.width, oSizeROI.height, 8 /* bits per pixel */);
NPP_ASSERT_NOT_NULL(pResultBitmap);
unsigned int nResultPitch = FreeImage_GetPitch(pResultBitmap);
unsigned char *pResultData = FreeImage_GetBits(pResultBitmap);
NPP_CHECK_CUDA(cudaMemcpy2D(pResultData, nResultPitch, pDstImageCUDA,
nDstPitchCUDA, oSizeROI.width, oSizeROI.height,
cudaMemcpyDeviceToHost));
// now save the result image
bool bSuccess;
bSuccess = FreeImage_Save(FIF_PGM, pResultBitmap, sResultFilename.c_str(),
0) == TRUE;
NPP_ASSERT_MSG(bSuccess, "Failed to save result image.");
// free nppiImage
nppiFree(pSrcImageCUDA);
nppiFree(pDstImageCUDA);
exit(EXIT_SUCCESS);
} catch (npp::Exception &rException) {
std::cerr << "Program error! The following exception occurred: \n";
std::cerr << rException << std::endl;
std::cerr << "Aborting." << std::endl;
exit(EXIT_FAILURE);
} catch (...) {
std::cerr << "Program error! An unknow type of exception occurred. \n";
std::cerr << "Aborting." << std::endl;
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}

View File

@@ -36,288 +36,291 @@
#include <ImageIO.h>
#include <ImagesCPU.h>
#include <ImagesNPP.h>
#include <fstream>
#include <helper_cuda.h>
#include <iostream>
#include <npp.h>
#include <string.h>
#include <fstream>
#include <iostream>
#include <string>
#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
#define STRCASECMP _stricmp
#define STRCASECMP _stricmp
#define STRNCASECMP _strnicmp
#else
#define STRCASECMP strcasecmp
#define STRCASECMP strcasecmp
#define STRNCASECMP strncasecmp
#endif
inline int cudaDeviceInit(int argc, const char **argv) {
int deviceCount;
checkCudaErrors(cudaGetDeviceCount(&deviceCount));
inline int cudaDeviceInit(int argc, const char **argv)
{
int deviceCount;
checkCudaErrors(cudaGetDeviceCount(&deviceCount));
if (deviceCount == 0) {
std::cerr << "CUDA error: no devices supporting CUDA." << std::endl;
exit(EXIT_FAILURE);
}
if (deviceCount == 0) {
std::cerr << "CUDA error: no devices supporting CUDA." << std::endl;
exit(EXIT_FAILURE);
}
int dev = findCudaDevice(argc, argv);
int dev = findCudaDevice(argc, argv);
cudaDeviceProp deviceProp;
cudaGetDeviceProperties(&deviceProp, dev);
std::cerr << "cudaSetDevice GPU" << dev << " = " << deviceProp.name
<< std::endl;
cudaDeviceProp deviceProp;
cudaGetDeviceProperties(&deviceProp, dev);
std::cerr << "cudaSetDevice GPU" << dev << " = " << deviceProp.name << std::endl;
checkCudaErrors(cudaSetDevice(dev));
checkCudaErrors(cudaSetDevice(dev));
return dev;
return dev;
}
int main(int argc, char *argv[]) {
printf("%s Starting...\n\n", argv[0]);
int main(int argc, char *argv[])
{
printf("%s Starting...\n\n", argv[0]);
try {
std::string sFilename;
char *filePath;
try {
std::string sFilename;
char *filePath;
cudaDeviceInit(argc, (const char **)argv);
cudaDeviceInit(argc, (const char **)argv);
NppStreamContext nppStreamCtx;
nppStreamCtx.hStream = 0; // The NULL stream by default, set this to whatever your stream ID is if not the NULL stream.
NppStreamContext nppStreamCtx;
nppStreamCtx.hStream =
0; // The NULL stream by default, set this to whatever your stream ID is if not the NULL stream.
cudaError_t cudaError = cudaGetDevice(&nppStreamCtx.nCudaDeviceId);
if (cudaError != cudaSuccess)
{
printf("CUDA error: no devices supporting CUDA.\n");
return NPP_NOT_SUFFICIENT_COMPUTE_CAPABILITY;
}
cudaError_t cudaError = cudaGetDevice(&nppStreamCtx.nCudaDeviceId);
if (cudaError != cudaSuccess) {
printf("CUDA error: no devices supporting CUDA.\n");
return NPP_NOT_SUFFICIENT_COMPUTE_CAPABILITY;
}
const NppLibraryVersion *libVer = nppGetLibVersion();
const NppLibraryVersion *libVer = nppGetLibVersion();
printf("NPP Library Version %d.%d.%d\n", libVer->major, libVer->minor, libVer->build);
printf("NPP Library Version %d.%d.%d\n", libVer->major, libVer->minor, libVer->build);
int driverVersion, runtimeVersion;
cudaDriverGetVersion(&driverVersion);
cudaRuntimeGetVersion(&runtimeVersion);
int driverVersion, runtimeVersion;
cudaDriverGetVersion(&driverVersion);
cudaRuntimeGetVersion(&runtimeVersion);
printf("CUDA Driver Version: %d.%d\n", driverVersion/1000, (driverVersion%100)/10);
printf("CUDA Runtime Version: %d.%d\n\n", runtimeVersion/1000, (runtimeVersion%100)/10);
printf("CUDA Driver Version: %d.%d\n", driverVersion / 1000, (driverVersion % 100) / 10);
printf("CUDA Runtime Version: %d.%d\n\n", runtimeVersion / 1000, (runtimeVersion % 100) / 10);
cudaError = cudaDeviceGetAttribute(&nppStreamCtx.nCudaDevAttrComputeCapabilityMajor,
cudaDevAttrComputeCapabilityMajor,
nppStreamCtx.nCudaDeviceId);
if (cudaError != cudaSuccess)
return NPP_NOT_SUFFICIENT_COMPUTE_CAPABILITY;
cudaError = cudaDeviceGetAttribute(&nppStreamCtx.nCudaDevAttrComputeCapabilityMajor,
cudaDevAttrComputeCapabilityMajor,
nppStreamCtx.nCudaDeviceId);
if (cudaError != cudaSuccess)
return NPP_NOT_SUFFICIENT_COMPUTE_CAPABILITY;
cudaError = cudaDeviceGetAttribute(&nppStreamCtx.nCudaDevAttrComputeCapabilityMinor,
cudaDevAttrComputeCapabilityMinor,
nppStreamCtx.nCudaDeviceId);
if (cudaError != cudaSuccess)
return NPP_NOT_SUFFICIENT_COMPUTE_CAPABILITY;
cudaError = cudaDeviceGetAttribute(&nppStreamCtx.nCudaDevAttrComputeCapabilityMinor,
cudaDevAttrComputeCapabilityMinor,
nppStreamCtx.nCudaDeviceId);
if (cudaError != cudaSuccess)
return NPP_NOT_SUFFICIENT_COMPUTE_CAPABILITY;
cudaError = cudaStreamGetFlags(nppStreamCtx.hStream, &nppStreamCtx.nStreamFlags);
cudaError = cudaStreamGetFlags(nppStreamCtx.hStream, &nppStreamCtx.nStreamFlags);
cudaDeviceProp oDeviceProperties;
cudaDeviceProp oDeviceProperties;
cudaError = cudaGetDeviceProperties(&oDeviceProperties, nppStreamCtx.nCudaDeviceId);
cudaError = cudaGetDeviceProperties(&oDeviceProperties, nppStreamCtx.nCudaDeviceId);
nppStreamCtx.nMultiProcessorCount = oDeviceProperties.multiProcessorCount;
nppStreamCtx.nMaxThreadsPerMultiProcessor = oDeviceProperties.maxThreadsPerMultiProcessor;
nppStreamCtx.nMaxThreadsPerBlock = oDeviceProperties.maxThreadsPerBlock;
nppStreamCtx.nSharedMemPerBlock = oDeviceProperties.sharedMemPerBlock;
nppStreamCtx.nMultiProcessorCount = oDeviceProperties.multiProcessorCount;
nppStreamCtx.nMaxThreadsPerMultiProcessor = oDeviceProperties.maxThreadsPerMultiProcessor;
nppStreamCtx.nMaxThreadsPerBlock = oDeviceProperties.maxThreadsPerBlock;
nppStreamCtx.nSharedMemPerBlock = oDeviceProperties.sharedMemPerBlock;
if (checkCmdLineFlag(argc, (const char **)argv, "input")) {
getCmdLineArgumentString(argc, (const char **)argv, "input", &filePath);
} else {
filePath = sdkFindFilePath("teapot512.pgm", argv[0]);
}
if (checkCmdLineFlag(argc, (const char **)argv, "input")) {
getCmdLineArgumentString(argc, (const char **)argv, "input", &filePath);
}
else {
filePath = sdkFindFilePath("teapot512.pgm", argv[0]);
}
if (filePath) {
sFilename = filePath;
} else {
sFilename = "teapot512.pgm";
}
if (filePath) {
sFilename = filePath;
}
else {
sFilename = "teapot512.pgm";
}
// if we specify the filename at the command line, then we only test
// sFilename.
int file_errors = 0;
std::ifstream infile(sFilename.data(), std::ifstream::in);
// if we specify the filename at the command line, then we only test
// sFilename.
int file_errors = 0;
std::ifstream infile(sFilename.data(), std::ifstream::in);
if (infile.good()) {
std::cout << "histEqualizationNPP opened: <" << sFilename.data()
<< "> successfully!" << std::endl;
file_errors = 0;
infile.close();
} else {
std::cout << "histEqualizationNPP unable to open: <" << sFilename.data()
<< ">" << std::endl;
file_errors++;
infile.close();
}
if (infile.good()) {
std::cout << "histEqualizationNPP opened: <" << sFilename.data() << "> successfully!" << std::endl;
file_errors = 0;
infile.close();
}
else {
std::cout << "histEqualizationNPP unable to open: <" << sFilename.data() << ">" << std::endl;
file_errors++;
infile.close();
}
if (file_errors > 0) {
exit(EXIT_FAILURE);
}
if (file_errors > 0) {
exit(EXIT_FAILURE);
}
std::string dstFileName = sFilename;
std::string dstFileName = sFilename;
std::string::size_type dot = dstFileName.rfind('.');
std::string::size_type dot = dstFileName.rfind('.');
if (dot != std::string::npos) {
dstFileName = dstFileName.substr(0, dot);
}
if (dot != std::string::npos) {
dstFileName = dstFileName.substr(0, dot);
}
dstFileName += "_histEqualization.pgm";
dstFileName += "_histEqualization.pgm";
if (checkCmdLineFlag(argc, (const char **)argv, "output")) {
char *outputFilePath;
getCmdLineArgumentString(argc, (const char **)argv, "output",
&outputFilePath);
dstFileName = outputFilePath;
}
if (checkCmdLineFlag(argc, (const char **)argv, "output")) {
char *outputFilePath;
getCmdLineArgumentString(argc, (const char **)argv, "output", &outputFilePath);
dstFileName = outputFilePath;
}
npp::ImageCPU_8u_C1 oHostSrc;
npp::loadImage(sFilename, oHostSrc);
npp::ImageNPP_8u_C1 oDeviceSrc(oHostSrc);
npp::ImageCPU_8u_C1 oHostSrc;
npp::loadImage(sFilename, oHostSrc);
npp::ImageNPP_8u_C1 oDeviceSrc(oHostSrc);
//
// allocate arrays for histogram and levels
//
//
// allocate arrays for histogram and levels
//
const int binCount = 255;
const int levelCount = binCount + 1; // levels array has one more element
const int binCount = 255;
const int levelCount = binCount + 1; // levels array has one more element
Npp32s *histDevice = 0;
Npp32s *levelsDevice = 0;
Npp32s *histDevice = 0;
Npp32s *levelsDevice = 0;
NPP_CHECK_CUDA(cudaMalloc((void **)&histDevice, binCount * sizeof(Npp32s)));
NPP_CHECK_CUDA(
cudaMalloc((void **)&levelsDevice, levelCount * sizeof(Npp32s)));
NPP_CHECK_CUDA(cudaMalloc((void **)&histDevice, binCount * sizeof(Npp32s)));
NPP_CHECK_CUDA(cudaMalloc((void **)&levelsDevice, levelCount * sizeof(Npp32s)));
//
// compute histogram
//
//
// compute histogram
//
NppiSize oSizeROI = {(int)oDeviceSrc.width(),
(int)oDeviceSrc.height()}; // full image
// create device scratch buffer for nppiHistogram
size_t nDeviceBufferSize;
nppiHistogramEvenGetBufferSize_8u_C1R_Ctx(oSizeROI, levelCount,
&nDeviceBufferSize,
nppStreamCtx);
Npp8u *pDeviceBuffer;
NPP_CHECK_CUDA(cudaMalloc((void **)&pDeviceBuffer, nDeviceBufferSize));
NppiSize oSizeROI = {(int)oDeviceSrc.width(), (int)oDeviceSrc.height()}; // full image
// create device scratch buffer for nppiHistogram
size_t nDeviceBufferSize;
nppiHistogramEvenGetBufferSize_8u_C1R_Ctx(oSizeROI, levelCount, &nDeviceBufferSize, nppStreamCtx);
Npp8u *pDeviceBuffer;
NPP_CHECK_CUDA(cudaMalloc((void **)&pDeviceBuffer, nDeviceBufferSize));
// compute levels values on host
Npp32s levelsHost[levelCount];
NPP_CHECK_NPP(nppiEvenLevelsHost_32s(levelsHost, levelCount, 0, binCount));
// compute the histogram
NPP_CHECK_NPP(nppiHistogramEven_8u_C1R_Ctx(
oDeviceSrc.data(), oDeviceSrc.pitch(), oSizeROI, histDevice, levelCount,
0, binCount, pDeviceBuffer, nppStreamCtx));
// copy histogram and levels to host memory
Npp32s histHost[binCount];
NPP_CHECK_CUDA(cudaMemcpy(histHost, histDevice, binCount * sizeof(Npp32s),
cudaMemcpyDeviceToHost));
// compute levels values on host
Npp32s levelsHost[levelCount];
NPP_CHECK_NPP(nppiEvenLevelsHost_32s(levelsHost, levelCount, 0, binCount));
// compute the histogram
NPP_CHECK_NPP(nppiHistogramEven_8u_C1R_Ctx(oDeviceSrc.data(),
oDeviceSrc.pitch(),
oSizeROI,
histDevice,
levelCount,
0,
binCount,
pDeviceBuffer,
nppStreamCtx));
// copy histogram and levels to host memory
Npp32s histHost[binCount];
NPP_CHECK_CUDA(cudaMemcpy(histHost, histDevice, binCount * sizeof(Npp32s), cudaMemcpyDeviceToHost));
Npp32s lutHost[levelCount];
Npp32s lutHost[levelCount];
// fill LUT
{
Npp32s *pHostHistogram = histHost;
Npp32s totalSum = 0;
// fill LUT
{
Npp32s *pHostHistogram = histHost;
Npp32s totalSum = 0;
for (; pHostHistogram < histHost + binCount; ++pHostHistogram) {
totalSum += *pHostHistogram;
}
for (; pHostHistogram < histHost + binCount; ++pHostHistogram) {
totalSum += *pHostHistogram;
}
NPP_ASSERT(totalSum <= oSizeROI.width * oSizeROI.height);
NPP_ASSERT(totalSum <= oSizeROI.width * oSizeROI.height);
if (totalSum == 0) {
totalSum = 1;
}
if (totalSum == 0) {
totalSum = 1;
}
float multiplier = 1.0f / float(oSizeROI.width * oSizeROI.height) * 0xFF;
float multiplier = 1.0f / float(oSizeROI.width * oSizeROI.height) * 0xFF;
Npp32s runningSum = 0;
Npp32s *pLookupTable = lutHost;
Npp32s runningSum = 0;
Npp32s *pLookupTable = lutHost;
for (pHostHistogram = histHost; pHostHistogram < histHost + binCount;
++pHostHistogram) {
*pLookupTable = (Npp32s)(runningSum * multiplier + 0.5f);
pLookupTable++;
runningSum += *pHostHistogram;
}
for (pHostHistogram = histHost; pHostHistogram < histHost + binCount; ++pHostHistogram) {
*pLookupTable = (Npp32s)(runningSum * multiplier + 0.5f);
pLookupTable++;
runningSum += *pHostHistogram;
}
lutHost[binCount] = 0xFF; // last element is always 1
}
lutHost[binCount] = 0xFF; // last element is always 1
}
//
// apply LUT transformation to the image
//
// Create a device image for the result.
npp::ImageNPP_8u_C1 oDeviceDst(oDeviceSrc.size());
//
// apply LUT transformation to the image
//
// Create a device image for the result.
npp::ImageNPP_8u_C1 oDeviceDst(oDeviceSrc.size());
#if CUDART_VERSION >= 5000
// Note for CUDA 5.0, that nppiLUT_Linear_8u_C1R requires these pointers to
// be in GPU device memory
Npp32s *lutDevice = 0;
Npp32s *lvlsDevice = 0;
// Note for CUDA 5.0, that nppiLUT_Linear_8u_C1R requires these pointers to
// be in GPU device memory
Npp32s *lutDevice = 0;
Npp32s *lvlsDevice = 0;
NPP_CHECK_CUDA(
cudaMalloc((void **)&lutDevice, sizeof(Npp32s) * (levelCount)));
NPP_CHECK_CUDA(
cudaMalloc((void **)&lvlsDevice, sizeof(Npp32s) * (levelCount)));
NPP_CHECK_CUDA(cudaMalloc((void **)&lutDevice, sizeof(Npp32s) * (levelCount)));
NPP_CHECK_CUDA(cudaMalloc((void **)&lvlsDevice, sizeof(Npp32s) * (levelCount)));
NPP_CHECK_CUDA(cudaMemcpy(lutDevice, lutHost, sizeof(Npp32s) * (levelCount),
cudaMemcpyHostToDevice));
NPP_CHECK_CUDA(cudaMemcpy(lvlsDevice, levelsHost,
sizeof(Npp32s) * (levelCount),
cudaMemcpyHostToDevice));
NPP_CHECK_CUDA(cudaMemcpy(lutDevice, lutHost, sizeof(Npp32s) * (levelCount), cudaMemcpyHostToDevice));
NPP_CHECK_CUDA(cudaMemcpy(lvlsDevice, levelsHost, sizeof(Npp32s) * (levelCount), cudaMemcpyHostToDevice));
NPP_CHECK_NPP(nppiLUT_Linear_8u_C1R_Ctx(
oDeviceSrc.data(), oDeviceSrc.pitch(), oDeviceDst.data(),
oDeviceDst.pitch(), oSizeROI,
lutDevice, // value and level arrays are in host memory
lvlsDevice, levelCount,
nppStreamCtx));
NPP_CHECK_NPP(nppiLUT_Linear_8u_C1R_Ctx(oDeviceSrc.data(),
oDeviceSrc.pitch(),
oDeviceDst.data(),
oDeviceDst.pitch(),
oSizeROI,
lutDevice, // value and level arrays are in host memory
lvlsDevice,
levelCount,
nppStreamCtx));
NPP_CHECK_CUDA(cudaFree(lutDevice));
NPP_CHECK_CUDA(cudaFree(lvlsDevice));
NPP_CHECK_CUDA(cudaFree(lutDevice));
NPP_CHECK_CUDA(cudaFree(lvlsDevice));
#else
NPP_CHECK_NPP(nppiLUT_Linear_8u_C1R_Ctx(
oDeviceSrc.data(), oDeviceSrc.pitch(), oDeviceDst.data(),
oDeviceDst.pitch(), oSizeROI,
lutHost, // value and level arrays are in host memory
levelsHost, levelCount,
nppStreamCtx));
NPP_CHECK_NPP(nppiLUT_Linear_8u_C1R_Ctx(oDeviceSrc.data(),
oDeviceSrc.pitch(),
oDeviceDst.data(),
oDeviceDst.pitch(),
oSizeROI,
lutHost, // value and level arrays are in host memory
levelsHost,
levelCount,
nppStreamCtx));
#endif
// copy the result image back into the storage that contained the
// input image
npp::ImageCPU_8u_C1 oHostDst(oDeviceDst.size());
oDeviceDst.copyTo(oHostDst.data(), oHostDst.pitch());
// copy the result image back into the storage that contained the
// input image
npp::ImageCPU_8u_C1 oHostDst(oDeviceDst.size());
oDeviceDst.copyTo(oHostDst.data(), oHostDst.pitch());
cudaFree(histDevice);
cudaFree(levelsDevice);
cudaFree(pDeviceBuffer);
nppiFree(oDeviceSrc.data());
nppiFree(oDeviceDst.data());
cudaFree(histDevice);
cudaFree(levelsDevice);
cudaFree(pDeviceBuffer);
nppiFree(oDeviceSrc.data());
nppiFree(oDeviceDst.data());
// save the result
npp::saveImage(dstFileName.c_str(), oHostDst);
std::cout << "Saved image file " << dstFileName << std::endl;
exit(EXIT_SUCCESS);
} catch (npp::Exception &rException) {
std::cerr << "Program error! The following exception occurred: \n";
std::cerr << rException << std::endl;
std::cerr << "Aborting." << std::endl;
exit(EXIT_FAILURE);
} catch (...) {
std::cerr << "Program error! An unknow type of exception occurred. \n";
std::cerr << "Aborting." << std::endl;
exit(EXIT_FAILURE);
}
// save the result
npp::saveImage(dstFileName.c_str(), oHostDst);
std::cout << "Saved image file " << dstFileName << std::endl;
exit(EXIT_SUCCESS);
}
catch (npp::Exception &rException) {
std::cerr << "Program error! The following exception occurred: \n";
std::cerr << rException << std::endl;
std::cerr << "Aborting." << std::endl;
exit(EXIT_FAILURE);
}
catch (...) {
std::cerr << "Program error! An unknow type of exception occurred. \n";
std::cerr << "Aborting." << std::endl;
exit(EXIT_FAILURE);
}
return 0;
return 0;
}

View File

@@ -25,54 +25,51 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <cstring>
#include <cuda.h>
#include <iostream>
#include <nvJitLink.h>
#include <nvrtc.h>
#include <iostream>
#include <cstring>
#define NUM_THREADS 128
#define NUM_BLOCKS 32
#define NUM_BLOCKS 32
#define NVRTC_SAFE_CALL(x) \
do { \
nvrtcResult result = x; \
if (result != NVRTC_SUCCESS) { \
std::cerr << "\nerror: " #x " failed with error " \
<< nvrtcGetErrorString(result) << '\n'; \
exit(1); \
} \
} while(0)
#define CUDA_SAFE_CALL(x) \
do { \
CUresult result = x; \
if (result != CUDA_SUCCESS) { \
const char *msg; \
cuGetErrorName(result, &msg); \
std::cerr << "\nerror: " #x " failed with error " \
<< msg << '\n'; \
exit(1); \
} \
} while(0)
#define NVJITLINK_SAFE_CALL(h,x) \
do { \
nvJitLinkResult result = x; \
if (result != NVJITLINK_SUCCESS) { \
std::cerr << "\nerror: " #x " failed with error " \
<< result << '\n'; \
size_t lsize; \
result = nvJitLinkGetErrorLogSize(h, &lsize); \
if (result == NVJITLINK_SUCCESS && lsize > 0) { \
char *log = (char*)malloc(lsize); \
result = nvJitLinkGetErrorLog(h, log); \
if (result == NVJITLINK_SUCCESS) { \
std::cerr << "error log: " << log << '\n'; \
free(log); \
} \
} \
exit(1); \
} \
} while(0)
#define NVRTC_SAFE_CALL(x) \
do { \
nvrtcResult result = x; \
if (result != NVRTC_SUCCESS) { \
std::cerr << "\nerror: " #x " failed with error " << nvrtcGetErrorString(result) << '\n'; \
exit(1); \
} \
} while (0)
#define CUDA_SAFE_CALL(x) \
do { \
CUresult result = x; \
if (result != CUDA_SUCCESS) { \
const char *msg; \
cuGetErrorName(result, &msg); \
std::cerr << "\nerror: " #x " failed with error " << msg << '\n'; \
exit(1); \
} \
} while (0)
#define NVJITLINK_SAFE_CALL(h, x) \
do { \
nvJitLinkResult result = x; \
if (result != NVJITLINK_SUCCESS) { \
std::cerr << "\nerror: " #x " failed with error " << result << '\n'; \
size_t lsize; \
result = nvJitLinkGetErrorLogSize(h, &lsize); \
if (result == NVJITLINK_SUCCESS && lsize > 0) { \
char *log = (char *)malloc(lsize); \
result = nvJitLinkGetErrorLog(h, log); \
if (result == NVJITLINK_SUCCESS) { \
std::cerr << "error log: " << log << '\n'; \
free(log); \
} \
} \
exit(1); \
} \
} while (0)
const char *lto_saxpy = " \n\
extern __device__ float compute(float a, float x, float y); \n\
@@ -92,170 +89,171 @@ __device__ float compute(float a, float x, float y) { \n\
} \n";
// compile code into LTOIR, returning the IR and its size
static void getLTOIR (const char *code, const char *name,
char **ltoIR, size_t *ltoIRSize)
static void getLTOIR(const char *code, const char *name, char **ltoIR, size_t *ltoIRSize)
{
// Create an instance of nvrtcProgram with the code string.
nvrtcProgram prog;
NVRTC_SAFE_CALL(
nvrtcCreateProgram(&prog, // prog
code, // buffer
name, // name
0, // numHeaders
NULL, // headers
NULL)); // includeNames
// specify that LTO IR should be generated for LTO operation
const char *opts[] = {"-dlto",
"--relocatable-device-code=true"};
nvrtcResult compileResult = nvrtcCompileProgram(prog, // prog
2, // numOptions
opts); // options
// Obtain compilation log from the program.
size_t logSize;
NVRTC_SAFE_CALL(nvrtcGetProgramLogSize(prog, &logSize));
char *log = new char[logSize];
NVRTC_SAFE_CALL(nvrtcGetProgramLog(prog, log));
std::cout << log << '\n';
delete[] log;
if (compileResult != NVRTC_SUCCESS) {
exit(1);
}
// Obtain generated LTO IR from the program.
NVRTC_SAFE_CALL(nvrtcGetLTOIRSize(prog, ltoIRSize));
*ltoIR = new char[*ltoIRSize];
NVRTC_SAFE_CALL(nvrtcGetLTOIR(prog, *ltoIR));
// Destroy the program.
NVRTC_SAFE_CALL(nvrtcDestroyProgram(&prog));
// Create an instance of nvrtcProgram with the code string.
nvrtcProgram prog;
NVRTC_SAFE_CALL(nvrtcCreateProgram(&prog, // prog
code, // buffer
name, // name
0, // numHeaders
NULL, // headers
NULL)); // includeNames
// specify that LTO IR should be generated for LTO operation
const char *opts[] = {"-dlto", "--relocatable-device-code=true"};
nvrtcResult compileResult = nvrtcCompileProgram(prog, // prog
2, // numOptions
opts); // options
// Obtain compilation log from the program.
size_t logSize;
NVRTC_SAFE_CALL(nvrtcGetProgramLogSize(prog, &logSize));
char *log = new char[logSize];
NVRTC_SAFE_CALL(nvrtcGetProgramLog(prog, log));
std::cout << log << '\n';
delete[] log;
if (compileResult != NVRTC_SUCCESS) {
exit(1);
}
// Obtain generated LTO IR from the program.
NVRTC_SAFE_CALL(nvrtcGetLTOIRSize(prog, ltoIRSize));
*ltoIR = new char[*ltoIRSize];
NVRTC_SAFE_CALL(nvrtcGetLTOIR(prog, *ltoIR));
// Destroy the program.
NVRTC_SAFE_CALL(nvrtcDestroyProgram(&prog));
}
int main(int argc, char *argv[])
{
unsigned int cuda_major = 0;
unsigned int cuda_minor = 0;
nvJitLinkResult res = nvJitLinkVersion(&cuda_major, &cuda_minor);
if (res != NVJITLINK_SUCCESS) {
std::cerr << "Version check failed" << '\n';
} else {
std::cout << "CUDA " << cuda_major << "." << cuda_minor << '\n';
}
unsigned int cuda_major = 0;
unsigned int cuda_minor = 0;
nvJitLinkResult res = nvJitLinkVersion(&cuda_major, &cuda_minor);
if (res != NVJITLINK_SUCCESS) {
std::cerr << "Version check failed" << '\n';
}
else {
std::cout << "CUDA " << cuda_major << "." << cuda_minor << '\n';
}
char *ltoIR1;
char *ltoIR2;
size_t ltoIR1Size;
size_t ltoIR2Size;
// getLTOIR uses nvrtc to get the LTOIR.
// We could also use nvcc offline with -dlto -fatbin
// to generate the IR, but using nvrtc keeps the build simpler.
getLTOIR(lto_saxpy, "lto_saxpy.cu", &ltoIR1, &ltoIR1Size);
getLTOIR(lto_compute, "lto_compute.cu", &ltoIR2, &ltoIR2Size);
char *ltoIR1;
char *ltoIR2;
size_t ltoIR1Size;
size_t ltoIR2Size;
// getLTOIR uses nvrtc to get the LTOIR.
// We could also use nvcc offline with -dlto -fatbin
// to generate the IR, but using nvrtc keeps the build simpler.
getLTOIR(lto_saxpy, "lto_saxpy.cu", &ltoIR1, &ltoIR1Size);
getLTOIR(lto_compute, "lto_compute.cu", &ltoIR2, &ltoIR2Size);
CUdevice cuDevice;
CUcontext context;
CUmodule module;
CUfunction kernel;
CUDA_SAFE_CALL(cuInit(0));
CUDA_SAFE_CALL(cuDeviceGet(&cuDevice, 0));
CUDA_SAFE_CALL(cuCtxCreate(&context, 0, cuDevice));
CUdevice cuDevice;
CUcontext context;
CUmodule module;
CUfunction kernel;
CUDA_SAFE_CALL(cuInit(0));
CUDA_SAFE_CALL(cuDeviceGet(&cuDevice, 0));
CUDA_SAFE_CALL(cuCtxCreate(&context, 0, cuDevice));
// Dynamically determine the arch to link for
int major = 0;
int minor = 0;
CUDA_SAFE_CALL(cuDeviceGetAttribute(&major,
CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, cuDevice));
CUDA_SAFE_CALL(cuDeviceGetAttribute(&minor,
CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, cuDevice));
int arch = major*10 + minor;
char smbuf[16];
memset(smbuf,0,16);
sprintf(smbuf, "-arch=sm_%d", arch);
// Dynamically determine the arch to link for
int major = 0;
int minor = 0;
CUDA_SAFE_CALL(cuDeviceGetAttribute(&major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, cuDevice));
CUDA_SAFE_CALL(cuDeviceGetAttribute(&minor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, cuDevice));
int arch = major * 10 + minor;
char smbuf[16];
memset(smbuf, 0, 16);
sprintf(smbuf, "-arch=sm_%d", arch);
// Load the generated LTO IR and link them together
nvJitLinkHandle handle;
const char *lopts[] = {"-lto", smbuf};
NVJITLINK_SAFE_CALL(handle, nvJitLinkCreate(&handle, 2, lopts));
// Load the generated LTO IR and link them together
nvJitLinkHandle handle;
const char *lopts[] = {"-lto", smbuf};
NVJITLINK_SAFE_CALL(handle, nvJitLinkCreate(&handle, 2, lopts));
NVJITLINK_SAFE_CALL(handle, nvJitLinkAddData(handle, NVJITLINK_INPUT_LTOIR,
(void *)ltoIR1, ltoIR1Size, "lto_saxpy"));
NVJITLINK_SAFE_CALL(handle, nvJitLinkAddData(handle, NVJITLINK_INPUT_LTOIR,
(void *)ltoIR2, ltoIR2Size, "lto_compute"));
NVJITLINK_SAFE_CALL(handle,
nvJitLinkAddData(handle, NVJITLINK_INPUT_LTOIR, (void *)ltoIR1, ltoIR1Size, "lto_saxpy"));
NVJITLINK_SAFE_CALL(handle,
nvJitLinkAddData(handle, NVJITLINK_INPUT_LTOIR, (void *)ltoIR2, ltoIR2Size, "lto_compute"));
// The call to nvJitLinkComplete causes linker to link together the two
// LTO IR modules, do optimization on the linked LTO IR,
// and generate cubin from it.
NVJITLINK_SAFE_CALL(handle, nvJitLinkComplete(handle));
// The call to nvJitLinkComplete causes linker to link together the two
// LTO IR modules, do optimization on the linked LTO IR,
// and generate cubin from it.
NVJITLINK_SAFE_CALL(handle, nvJitLinkComplete(handle));
// check error log
size_t logSize;
NVJITLINK_SAFE_CALL(handle, nvJitLinkGetErrorLogSize(handle, &logSize));
if (logSize > 0) {
char *log = (char*)malloc(logSize+1);
NVJITLINK_SAFE_CALL(handle, nvJitLinkGetErrorLog(handle, log));
std::cout << "Error log: " << log << std::endl;
free(log);
}
// check error log
size_t logSize;
NVJITLINK_SAFE_CALL(handle, nvJitLinkGetErrorLogSize(handle, &logSize));
if (logSize > 0) {
char *log = (char *)malloc(logSize + 1);
NVJITLINK_SAFE_CALL(handle, nvJitLinkGetErrorLog(handle, log));
std::cout << "Error log: " << log << std::endl;
free(log);
}
// get linked cubin
size_t cubinSize;
NVJITLINK_SAFE_CALL(handle, nvJitLinkGetLinkedCubinSize(handle, &cubinSize));
void *cubin = malloc(cubinSize);
NVJITLINK_SAFE_CALL(handle, nvJitLinkGetLinkedCubin(handle, cubin));
// get linked cubin
size_t cubinSize;
NVJITLINK_SAFE_CALL(handle, nvJitLinkGetLinkedCubinSize(handle, &cubinSize));
void *cubin = malloc(cubinSize);
NVJITLINK_SAFE_CALL(handle, nvJitLinkGetLinkedCubin(handle, cubin));
NVJITLINK_SAFE_CALL(handle, nvJitLinkDestroy(&handle));
delete[] ltoIR1;
delete[] ltoIR2;
NVJITLINK_SAFE_CALL(handle, nvJitLinkDestroy(&handle));
delete[] ltoIR1;
delete[] ltoIR2;
// cubin is linked, so now load it
CUDA_SAFE_CALL(cuModuleLoadData(&module, cubin));
CUDA_SAFE_CALL(cuModuleGetFunction(&kernel, module, "saxpy"));
// Generate input for execution, and create output buffers.
size_t n = NUM_THREADS * NUM_BLOCKS;
size_t bufferSize = n * sizeof(float);
float a = 5.1f;
float *hX = new float[n], *hY = new float[n], *hOut = new float[n];
for (size_t i = 0; i < n; ++i) {
hX[i] = static_cast<float>(i);
hY[i] = static_cast<float>(i * 2);
}
CUdeviceptr dX, dY, dOut;
CUDA_SAFE_CALL(cuMemAlloc(&dX, bufferSize));
CUDA_SAFE_CALL(cuMemAlloc(&dY, bufferSize));
CUDA_SAFE_CALL(cuMemAlloc(&dOut, bufferSize));
CUDA_SAFE_CALL(cuMemcpyHtoD(dX, hX, bufferSize));
CUDA_SAFE_CALL(cuMemcpyHtoD(dY, hY, bufferSize));
// Execute SAXPY.
void *args[] = { &a, &dX, &dY, &dOut, &n };
CUDA_SAFE_CALL(
cuLaunchKernel(kernel,
NUM_BLOCKS, 1, 1, // grid dim
NUM_THREADS, 1, 1, // block dim
0, NULL, // shared mem and stream
args, 0)); // arguments
CUDA_SAFE_CALL(cuCtxSynchronize());
// Retrieve and print output.
CUDA_SAFE_CALL(cuMemcpyDtoH(hOut, dOut, bufferSize));
for (size_t i = 0; i < n; ++i) {
std::cout << a << " * " << hX[i] << " + " << hY[i]
<< " = " << hOut[i] << '\n';
}
// check last value to verify
if (hOut[n-1] == 29074.5) {
std::cout << "PASSED!\n";
} else {
std::cout << "values not expected?\n";
}
// Release resources.
CUDA_SAFE_CALL(cuMemFree(dX));
CUDA_SAFE_CALL(cuMemFree(dY));
CUDA_SAFE_CALL(cuMemFree(dOut));
CUDA_SAFE_CALL(cuModuleUnload(module));
CUDA_SAFE_CALL(cuCtxDestroy(context));
free(cubin);
delete[] hX;
delete[] hY;
delete[] hOut;
return 0;
// cubin is linked, so now load it
CUDA_SAFE_CALL(cuModuleLoadData(&module, cubin));
CUDA_SAFE_CALL(cuModuleGetFunction(&kernel, module, "saxpy"));
// Generate input for execution, and create output buffers.
size_t n = NUM_THREADS * NUM_BLOCKS;
size_t bufferSize = n * sizeof(float);
float a = 5.1f;
float *hX = new float[n], *hY = new float[n], *hOut = new float[n];
for (size_t i = 0; i < n; ++i) {
hX[i] = static_cast<float>(i);
hY[i] = static_cast<float>(i * 2);
}
CUdeviceptr dX, dY, dOut;
CUDA_SAFE_CALL(cuMemAlloc(&dX, bufferSize));
CUDA_SAFE_CALL(cuMemAlloc(&dY, bufferSize));
CUDA_SAFE_CALL(cuMemAlloc(&dOut, bufferSize));
CUDA_SAFE_CALL(cuMemcpyHtoD(dX, hX, bufferSize));
CUDA_SAFE_CALL(cuMemcpyHtoD(dY, hY, bufferSize));
// Execute SAXPY.
void *args[] = {&a, &dX, &dY, &dOut, &n};
CUDA_SAFE_CALL(cuLaunchKernel(kernel,
NUM_BLOCKS,
1,
1, // grid dim
NUM_THREADS,
1,
1, // block dim
0,
NULL, // shared mem and stream
args,
0)); // arguments
CUDA_SAFE_CALL(cuCtxSynchronize());
// Retrieve and print output.
CUDA_SAFE_CALL(cuMemcpyDtoH(hOut, dOut, bufferSize));
for (size_t i = 0; i < n; ++i) {
std::cout << a << " * " << hX[i] << " + " << hY[i] << " = " << hOut[i] << '\n';
}
// check last value to verify
if (hOut[n - 1] == 29074.5) {
std::cout << "PASSED!\n";
}
else {
std::cout << "values not expected?\n";
}
// Release resources.
CUDA_SAFE_CALL(cuMemFree(dX));
CUDA_SAFE_CALL(cuMemFree(dY));
CUDA_SAFE_CALL(cuMemFree(dOut));
CUDA_SAFE_CALL(cuModuleUnload(module));
CUDA_SAFE_CALL(cuCtxDestroy(context));
free(cubin);
delete[] hX;
delete[] hY;
delete[] hOut;
return 0;
}

View File

@@ -38,22 +38,22 @@
#endif
// includes, system
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <float.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// includes, project
#include <helper_functions.h>
#include <helper_cuda.h>
#include <helper_functions.h>
#include <helper_math.h>
// includes, library
#include <thrust/copy.h>
#include <thrust/device_vector.h>
#include <thrust/host_vector.h>
#include <thrust/scan.h>
#include <thrust/copy.h>
////////////////////////////////////////////////////////////////////////////////
// declaration, types
@@ -63,200 +63,203 @@ typedef unsigned char Bool;
enum { False = 0, True = 1 };
// 2D height field
struct HeightField {
int width;
float *height;
struct HeightField
{
int width;
float *height;
};
// Ray
struct Ray {
float3 origin;
float2 dir;
int length;
float oneOverLength;
struct Ray
{
float3 origin;
float2 dir;
int length;
float oneOverLength;
};
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// declaration, forward
int runTest(int argc, char **argv);
__global__ void computeAngles_kernel(const Ray, float *, cudaTextureObject_t);
__global__ void computeVisibilities_kernel(const float *, const float *, int,
Bool *);
void lineOfSight_gold(const HeightField, const Ray, Bool *);
int runTest(int argc, char **argv);
__global__ void computeAngles_kernel(const Ray, float *, cudaTextureObject_t);
__global__ void computeVisibilities_kernel(const float *, const float *, int, Bool *);
void lineOfSight_gold(const HeightField, const Ray, Bool *);
__device__ __host__ float2 getLocation(const Ray, int);
__device__ __host__ float getAngle(const Ray, float2, float);
__device__ __host__ float getAngle(const Ray, float2, float);
////////////////////////////////////////////////////////////////////////////////
// Program main
////////////////////////////////////////////////////////////////////////////////
int main(int argc, char **argv) {
int res = runTest(argc, argv);
int main(int argc, char **argv)
{
int res = runTest(argc, argv);
if (res != 1) {
printf("Test failed!\n");
exit(EXIT_FAILURE);
}
if (res != 1) {
printf("Test failed!\n");
exit(EXIT_FAILURE);
}
printf("Test passed\n");
exit(EXIT_SUCCESS);
printf("Test passed\n");
exit(EXIT_SUCCESS);
}
////////////////////////////////////////////////////////////////////////////////
//! Run a line-of-sight test for CUDA
////////////////////////////////////////////////////////////////////////////////
int runTest(int argc, char **argv) {
////////////////////////////////////////////////////////////////////////////
// Device initialization
int runTest(int argc, char **argv)
{
////////////////////////////////////////////////////////////////////////////
// Device initialization
printf("[%s] - Starting...\n", argv[0]);
printf("[%s] - Starting...\n", argv[0]);
// use command-line specified CUDA device, otherwise use device with highest
// Gflops/s
findCudaDevice(argc, (const char **)argv);
// use command-line specified CUDA device, otherwise use device with highest
// Gflops/s
findCudaDevice(argc, (const char **)argv);
////////////////////////////////////////////////////////////////////////////
// Timer
////////////////////////////////////////////////////////////////////////////
// Timer
// Create
StopWatchInterface *timer;
sdkCreateTimer(&timer);
// Create
StopWatchInterface *timer;
sdkCreateTimer(&timer);
// Number of iterations to get accurate timing
uint numIterations = 100;
// Number of iterations to get accurate timing
uint numIterations = 100;
////////////////////////////////////////////////////////////////////////////
// Height field
////////////////////////////////////////////////////////////////////////////
// Height field
HeightField heightField;
HeightField heightField;
// Allocate in host memory
int2 dim = make_int2(10000, 100);
heightField.width = dim.x;
thrust::host_vector<float> height(dim.x * dim.y);
heightField.height = (float *)&height[0];
// Allocate in host memory
int2 dim = make_int2(10000, 100);
heightField.width = dim.x;
thrust::host_vector<float> height(dim.x * dim.y);
heightField.height = (float *)&height[0];
//
// Fill in with an arbitrary sine surface
for (int x = 0; x < dim.x; ++x)
for (int y = 0; y < dim.y; ++y) {
float amp = 0.1f * (x + y);
float period = 2.0f + amp;
*(heightField.height + dim.x * y + x) =
amp * (sinf(sqrtf((float)(x * x + y * y)) * 2.0f * 3.1416f / period) +
1.0f);
//
// Fill in with an arbitrary sine surface
for (int x = 0; x < dim.x; ++x)
for (int y = 0; y < dim.y; ++y) {
float amp = 0.1f * (x + y);
float period = 2.0f + amp;
*(heightField.height + dim.x * y + x) =
amp * (sinf(sqrtf((float)(x * x + y * y)) * 2.0f * 3.1416f / period) + 1.0f);
}
// Allocate CUDA array in device memory
cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc(32, 0, 0, 0, cudaChannelFormatKindFloat);
cudaArray *heightFieldArray;
checkCudaErrors(cudaMallocArray(&heightFieldArray, &channelDesc, dim.x, dim.y));
// Initialize device memory
checkCudaErrors(cudaMemcpy2DToArray(heightFieldArray,
0,
0,
heightField.height,
dim.x * sizeof(float),
dim.x * sizeof(float),
dim.y,
cudaMemcpyHostToDevice));
cudaTextureObject_t heightFieldTex;
cudaResourceDesc texRes;
memset(&texRes, 0, sizeof(cudaResourceDesc));
texRes.resType = cudaResourceTypeArray;
texRes.res.array.array = heightFieldArray;
cudaTextureDesc texDescr;
memset(&texDescr, 0, sizeof(cudaTextureDesc));
texDescr.normalizedCoords = false;
texDescr.filterMode = cudaFilterModePoint;
texDescr.addressMode[0] = cudaAddressModeClamp;
texDescr.addressMode[1] = cudaAddressModeClamp;
texDescr.readMode = cudaReadModeElementType;
checkCudaErrors(cudaCreateTextureObject(&heightFieldTex, &texRes, &texDescr, NULL));
//////////////////////////////////////////////////////////////////////////////
// Ray (starts at origin and traverses the height field diagonally)
Ray ray;
ray.origin = make_float3(0, 0, 2.0f);
int2 dir = make_int2(dim.x - 1, dim.y - 1);
ray.dir = make_float2((float)dir.x, (float)dir.y);
ray.length = max(abs(dir.x), abs(dir.y));
ray.oneOverLength = 1.0f / ray.length;
//////////////////////////////////////////////////////////////////////////////
// View angles
// Allocate view angles for each point along the ray
thrust::device_vector<float> d_angles(ray.length);
// Allocate result of max-scan operation on the array of view angles
thrust::device_vector<float> d_scannedAngles(ray.length);
//////////////////////////////////////////////////////////////////////////////
// Visibility results
// Allocate visibility results for each point along the ray
thrust::device_vector<Bool> d_visibilities(ray.length);
thrust::host_vector<Bool> h_visibilities(ray.length);
thrust::host_vector<Bool> h_visibilitiesRef(ray.length);
//////////////////////////////////////////////////////////////////////////////
// Reference solution
lineOfSight_gold(heightField, ray, (Bool *)&h_visibilitiesRef[0]);
//////////////////////////////////////////////////////////////////////////////
// Device solution
// Execution configuration
dim3 block(256);
dim3 grid((uint)ceil(ray.length / (double)block.x));
// Compute device solution
printf("Line of sight\n");
sdkStartTimer(&timer);
for (uint i = 0; i < numIterations; ++i) {
// Compute view angle for each point along the ray
computeAngles_kernel<<<grid, block>>>(ray, thrust::raw_pointer_cast(&d_angles[0]), heightFieldTex);
getLastCudaError("Kernel execution failed");
// Perform a max-scan operation on the array of view angles
thrust::inclusive_scan(d_angles.begin(), d_angles.end(), d_scannedAngles.begin(), thrust::maximum<float>());
getLastCudaError("Kernel execution failed");
// Compute visibility results based on the array of view angles
// and its scanned version
computeVisibilities_kernel<<<grid, block>>>(thrust::raw_pointer_cast(&d_angles[0]),
thrust::raw_pointer_cast(&d_scannedAngles[0]),
ray.length,
thrust::raw_pointer_cast(&d_visibilities[0]));
getLastCudaError("Kernel execution failed");
}
// Allocate CUDA array in device memory
cudaChannelFormatDesc channelDesc =
cudaCreateChannelDesc(32, 0, 0, 0, cudaChannelFormatKindFloat);
cudaArray *heightFieldArray;
checkCudaErrors(
cudaMallocArray(&heightFieldArray, &channelDesc, dim.x, dim.y));
// Initialize device memory
checkCudaErrors(cudaMemcpy2DToArray(
heightFieldArray, 0, 0, heightField.height, dim.x * sizeof(float),
dim.x * sizeof(float), dim.y, cudaMemcpyHostToDevice));
cudaTextureObject_t heightFieldTex;
cudaResourceDesc texRes;
memset(&texRes, 0, sizeof(cudaResourceDesc));
texRes.resType = cudaResourceTypeArray;
texRes.res.array.array = heightFieldArray;
cudaTextureDesc texDescr;
memset(&texDescr, 0, sizeof(cudaTextureDesc));
texDescr.normalizedCoords = false;
texDescr.filterMode = cudaFilterModePoint;
texDescr.addressMode[0] = cudaAddressModeClamp;
texDescr.addressMode[1] = cudaAddressModeClamp;
texDescr.readMode = cudaReadModeElementType;
checkCudaErrors(
cudaCreateTextureObject(&heightFieldTex, &texRes, &texDescr, NULL));
//////////////////////////////////////////////////////////////////////////////
// Ray (starts at origin and traverses the height field diagonally)
Ray ray;
ray.origin = make_float3(0, 0, 2.0f);
int2 dir = make_int2(dim.x - 1, dim.y - 1);
ray.dir = make_float2((float)dir.x, (float)dir.y);
ray.length = max(abs(dir.x), abs(dir.y));
ray.oneOverLength = 1.0f / ray.length;
//////////////////////////////////////////////////////////////////////////////
// View angles
// Allocate view angles for each point along the ray
thrust::device_vector<float> d_angles(ray.length);
// Allocate result of max-scan operation on the array of view angles
thrust::device_vector<float> d_scannedAngles(ray.length);
//////////////////////////////////////////////////////////////////////////////
// Visibility results
// Allocate visibility results for each point along the ray
thrust::device_vector<Bool> d_visibilities(ray.length);
thrust::host_vector<Bool> h_visibilities(ray.length);
thrust::host_vector<Bool> h_visibilitiesRef(ray.length);
//////////////////////////////////////////////////////////////////////////////
// Reference solution
lineOfSight_gold(heightField, ray, (Bool *)&h_visibilitiesRef[0]);
//////////////////////////////////////////////////////////////////////////////
// Device solution
// Execution configuration
dim3 block(256);
dim3 grid((uint)ceil(ray.length / (double)block.x));
// Compute device solution
printf("Line of sight\n");
sdkStartTimer(&timer);
for (uint i = 0; i < numIterations; ++i) {
// Compute view angle for each point along the ray
computeAngles_kernel<<<grid, block>>>(
ray, thrust::raw_pointer_cast(&d_angles[0]), heightFieldTex);
cudaDeviceSynchronize();
sdkStopTimer(&timer);
getLastCudaError("Kernel execution failed");
// Perform a max-scan operation on the array of view angles
thrust::inclusive_scan(d_angles.begin(), d_angles.end(),
d_scannedAngles.begin(), thrust::maximum<float>());
getLastCudaError("Kernel execution failed");
// Copy visibility results back to the host
thrust::copy(d_visibilities.begin(), d_visibilities.end(), h_visibilities.begin());
// Compute visibility results based on the array of view angles
// and its scanned version
computeVisibilities_kernel<<<grid, block>>>(
thrust::raw_pointer_cast(&d_angles[0]),
thrust::raw_pointer_cast(&d_scannedAngles[0]), ray.length,
thrust::raw_pointer_cast(&d_visibilities[0]));
getLastCudaError("Kernel execution failed");
}
// Compare device visibility results against reference results
bool res = compareData(thrust::raw_pointer_cast(&h_visibilitiesRef[0]),
thrust::raw_pointer_cast(&h_visibilities[0]),
ray.length,
0.0f,
0.0f);
printf("Average time: %f ms\n\n", sdkGetTimerValue(&timer) / numIterations);
sdkResetTimer(&timer);
cudaDeviceSynchronize();
sdkStopTimer(&timer);
getLastCudaError("Kernel execution failed");
// Copy visibility results back to the host
thrust::copy(d_visibilities.begin(), d_visibilities.end(),
h_visibilities.begin());
// Compare device visibility results against reference results
bool res = compareData(thrust::raw_pointer_cast(&h_visibilitiesRef[0]),
thrust::raw_pointer_cast(&h_visibilities[0]),
ray.length, 0.0f, 0.0f);
printf("Average time: %f ms\n\n", sdkGetTimerValue(&timer) / numIterations);
sdkResetTimer(&timer);
// Cleanup memory
checkCudaErrors(cudaFreeArray(heightFieldArray));
return res;
// Cleanup memory
checkCudaErrors(cudaFreeArray(heightFieldArray));
return res;
}
////////////////////////////////////////////////////////////////////////////////
@@ -264,16 +267,16 @@ int runTest(int argc, char **argv) {
//! @param ray ray
//! @param angles view angles
////////////////////////////////////////////////////////////////////////////////
__global__ void computeAngles_kernel(const Ray ray, float *angles,
cudaTextureObject_t HeightFieldTex) {
uint i = blockDim.x * blockIdx.x + threadIdx.x;
__global__ void computeAngles_kernel(const Ray ray, float *angles, cudaTextureObject_t HeightFieldTex)
{
uint i = blockDim.x * blockIdx.x + threadIdx.x;
if (i < ray.length) {
float2 location = getLocation(ray, i + 1);
float height = tex2D<float>(HeightFieldTex, location.x, location.y);
float angle = getAngle(ray, location, height);
angles[i] = angle;
}
if (i < ray.length) {
float2 location = getLocation(ray, i + 1);
float height = tex2D<float>(HeightFieldTex, location.x, location.y);
float angle = getAngle(ray, location, height);
angles[i] = angle;
}
}
////////////////////////////////////////////////////////////////////////////////
@@ -284,14 +287,14 @@ __global__ void computeAngles_kernel(const Ray ray, float *angles,
//! @param visibilities boolean array indicating the visibility of each point
//! along the ray
////////////////////////////////////////////////////////////////////////////////
__global__ void computeVisibilities_kernel(const float *angles,
const float *scannedAngles,
int numAngles, Bool *visibilities) {
uint i = blockDim.x * blockIdx.x + threadIdx.x;
__global__ void
computeVisibilities_kernel(const float *angles, const float *scannedAngles, int numAngles, Bool *visibilities)
{
uint i = blockDim.x * blockIdx.x + threadIdx.x;
if (i < numAngles) {
visibilities[i] = scannedAngles[i] <= angles[i];
}
if (i < numAngles) {
visibilities[i] = scannedAngles[i] <= angles[i];
}
}
////////////////////////////////////////////////////////////////////////////////
@@ -301,24 +304,23 @@ __global__ void computeVisibilities_kernel(const float *angles,
//! @param visibilities boolean array indicating the visibility of each point
//! along the ray
////////////////////////////////////////////////////////////////////////////////
void lineOfSight_gold(const HeightField heightField, const Ray ray,
Bool *visibilities) {
float angleMax = asinf(-1.0f);
void lineOfSight_gold(const HeightField heightField, const Ray ray, Bool *visibilities)
{
float angleMax = asinf(-1.0f);
for (int i = 0; i < ray.length; ++i) {
float2 location = getLocation(ray, i + 1);
float height =
*(heightField.height + heightField.width * (int)floorf(location.y) +
(int)floorf(location.x));
float angle = getAngle(ray, location, height);
for (int i = 0; i < ray.length; ++i) {
float2 location = getLocation(ray, i + 1);
float height = *(heightField.height + heightField.width * (int)floorf(location.y) + (int)floorf(location.x));
float angle = getAngle(ray, location, height);
if (angle > angleMax) {
angleMax = angle;
visibilities[i] = True;
} else {
visibilities[i] = False;
if (angle > angleMax) {
angleMax = angle;
visibilities[i] = True;
}
else {
visibilities[i] = False;
}
}
}
}
////////////////////////////////////////////////////////////////////////////////
@@ -327,9 +329,10 @@ void lineOfSight_gold(const HeightField heightField, const Ray ray,
//! @param ray ray
//! @param i integer offset along the ray
////////////////////////////////////////////////////////////////////////////////
__device__ __host__ float2 getLocation(const Ray ray, int i) {
float step = i * ray.oneOverLength;
return make_float2(ray.origin.x, ray.origin.y) + ray.dir * step;
__device__ __host__ float2 getLocation(const Ray ray, int i)
{
float step = i * ray.oneOverLength;
return make_float2(ray.origin.x, ray.origin.y) + ray.dir * step;
}
////////////////////////////////////////////////////////////////////////////////
@@ -338,8 +341,8 @@ __device__ __host__ float2 getLocation(const Ray ray, int i) {
//! @param location 2D coordinates of the input point
//! @param height height of the input point
////////////////////////////////////////////////////////////////////////////////
__device__ __host__ float getAngle(const Ray ray, float2 location,
float height) {
float2 dir = location - make_float2(ray.origin.x, ray.origin.y);
return atanf((height - ray.origin.z) / length(dir));
__device__ __host__ float getAngle(const Ray ray, float2 location, float height)
{
float2 dir = location - make_float2(ray.origin.x, ray.origin.y);
return atanf((height - ray.origin.z) / length(dir));
}

View File

@@ -65,15 +65,15 @@
// Utilities and system includes
#include <assert.h>
#include <helper_string.h> // helper for shared functions common to CUDA Samples
#include <helper_string.h> // helper for shared functions common to CUDA Samples
// CUDA runtime
#include <cuda_runtime.h>
#include <cublas_v2.h>
#include <cuda_runtime.h>
// CUDA and CUBLAS functions
#include <helper_functions.h>
#include <helper_cuda.h>
#include <helper_functions.h>
#ifndef min
#define min(a, b) ((a < b) ? a : b)
@@ -83,8 +83,9 @@
#endif
// Optional Command-line multiplier for matrix sizes
typedef struct _matrixSize {
unsigned int uiWA, uiHA, uiWB, uiHB, uiWC, uiHC;
typedef struct _matrixSize
{
unsigned int uiWA, uiHA, uiWB, uiHB, uiWC, uiHC;
} sMatrixSize;
////////////////////////////////////////////////////////////////////////////////
@@ -96,270 +97,292 @@ typedef struct _matrixSize {
//! @param hA height of matrix A
//! @param wB width of matrix B
////////////////////////////////////////////////////////////////////////////////
void matrixMulCPU(float *C, const float *A, const float *B, unsigned int hA,
unsigned int wA, unsigned int wB) {
for (unsigned int i = 0; i < hA; ++i)
for (unsigned int j = 0; j < wB; ++j) {
double sum = 0;
void matrixMulCPU(float *C, const float *A, const float *B, unsigned int hA, unsigned int wA, unsigned int wB)
{
for (unsigned int i = 0; i < hA; ++i)
for (unsigned int j = 0; j < wB; ++j) {
double sum = 0;
for (unsigned int k = 0; k < wA; ++k) {
double a = A[i * wA + k];
double b = B[k * wB + j];
sum += a * b;
}
for (unsigned int k = 0; k < wA; ++k) {
double a = A[i * wA + k];
double b = B[k * wB + j];
sum += a * b;
}
C[i * wB + j] = (float)sum;
}
C[i * wB + j] = (float)sum;
}
}
// Allocates a matrix with random float entries.
void randomInit(float *data, int size) {
for (int i = 0; i < size; ++i) data[i] = rand() / (float)RAND_MAX;
void randomInit(float *data, int size)
{
for (int i = 0; i < size; ++i)
data[i] = rand() / (float)RAND_MAX;
}
void printDiff(float *data1, float *data2, int width, int height,
int iListLength, float fListTol) {
printf("Listing first %d Differences > %.6f...\n", iListLength, fListTol);
int i, j, k;
int error_count = 0;
void printDiff(float *data1, float *data2, int width, int height, int iListLength, float fListTol)
{
printf("Listing first %d Differences > %.6f...\n", iListLength, fListTol);
int i, j, k;
int error_count = 0;
for (j = 0; j < height; j++) {
if (error_count < iListLength) {
printf("\n Row %d:\n", j);
}
for (i = 0; i < width; i++) {
k = j * width + i;
float fDiff = fabs(data1[k] - data2[k]);
if (fDiff > fListTol) {
for (j = 0; j < height; j++) {
if (error_count < iListLength) {
printf(" Loc(%d,%d)\tCPU=%.5f\tGPU=%.5f\tDiff=%.6f\n", i, j,
data1[k], data2[k], fDiff);
printf("\n Row %d:\n", j);
}
error_count++;
}
}
}
for (i = 0; i < width; i++) {
k = j * width + i;
float fDiff = fabs(data1[k] - data2[k]);
printf(" \n Total Errors = %d\n", error_count);
if (fDiff > fListTol) {
if (error_count < iListLength) {
printf(" Loc(%d,%d)\tCPU=%.5f\tGPU=%.5f\tDiff=%.6f\n", i, j, data1[k], data2[k], fDiff);
}
error_count++;
}
}
}
printf(" \n Total Errors = %d\n", error_count);
}
void initializeCUDA(int argc, char **argv, int &devID, int &iSizeMultiple,
sMatrixSize &matrix_size) {
// By default, we use device 0, otherwise we override the device ID based on
// what is provided at the command line
cudaError_t error;
devID = 0;
void initializeCUDA(int argc, char **argv, int &devID, int &iSizeMultiple, sMatrixSize &matrix_size)
{
// By default, we use device 0, otherwise we override the device ID based on
// what is provided at the command line
cudaError_t error;
devID = 0;
devID = findCudaDevice(argc, (const char **)argv);
devID = findCudaDevice(argc, (const char **)argv);
if (checkCmdLineFlag(argc, (const char **)argv, "sizemult")) {
iSizeMultiple =
getCmdLineArgumentInt(argc, (const char **)argv, "sizemult");
}
if (checkCmdLineFlag(argc, (const char **)argv, "sizemult")) {
iSizeMultiple = getCmdLineArgumentInt(argc, (const char **)argv, "sizemult");
}
iSizeMultiple = min(iSizeMultiple, 10);
iSizeMultiple = max(iSizeMultiple, 1);
iSizeMultiple = min(iSizeMultiple, 10);
iSizeMultiple = max(iSizeMultiple, 1);
cudaDeviceProp deviceProp;
cudaDeviceProp deviceProp;
error = cudaGetDeviceProperties(&deviceProp, devID);
error = cudaGetDeviceProperties(&deviceProp, devID);
if (error != cudaSuccess) {
printf("cudaGetDeviceProperties returned error code %d, line(%d)\n", error,
__LINE__);
exit(EXIT_FAILURE);
}
if (error != cudaSuccess) {
printf("cudaGetDeviceProperties returned error code %d, line(%d)\n", error, __LINE__);
exit(EXIT_FAILURE);
}
printf("GPU Device %d: \"%s\" with compute capability %d.%d\n\n", devID,
deviceProp.name, deviceProp.major, deviceProp.minor);
printf("GPU Device %d: \"%s\" with compute capability %d.%d\n\n",
devID,
deviceProp.name,
deviceProp.major,
deviceProp.minor);
int block_size = 32;
int block_size = 32;
matrix_size.uiWA = 3 * block_size * iSizeMultiple;
matrix_size.uiHA = 4 * block_size * iSizeMultiple;
matrix_size.uiWB = 2 * block_size * iSizeMultiple;
matrix_size.uiHB = 3 * block_size * iSizeMultiple;
matrix_size.uiWC = 2 * block_size * iSizeMultiple;
matrix_size.uiHC = 4 * block_size * iSizeMultiple;
matrix_size.uiWA = 3 * block_size * iSizeMultiple;
matrix_size.uiHA = 4 * block_size * iSizeMultiple;
matrix_size.uiWB = 2 * block_size * iSizeMultiple;
matrix_size.uiHB = 3 * block_size * iSizeMultiple;
matrix_size.uiWC = 2 * block_size * iSizeMultiple;
matrix_size.uiHC = 4 * block_size * iSizeMultiple;
printf("MatrixA(%u,%u), MatrixB(%u,%u), MatrixC(%u,%u)\n", matrix_size.uiHA,
matrix_size.uiWA, matrix_size.uiHB, matrix_size.uiWB, matrix_size.uiHC,
matrix_size.uiWC);
printf("MatrixA(%u,%u), MatrixB(%u,%u), MatrixC(%u,%u)\n",
matrix_size.uiHA,
matrix_size.uiWA,
matrix_size.uiHB,
matrix_size.uiWB,
matrix_size.uiHC,
matrix_size.uiWC);
if (matrix_size.uiWA != matrix_size.uiHB ||
matrix_size.uiHA != matrix_size.uiHC ||
matrix_size.uiWB != matrix_size.uiWC) {
printf("ERROR: Matrix sizes do not match!\n");
exit(-1);
}
if (matrix_size.uiWA != matrix_size.uiHB || matrix_size.uiHA != matrix_size.uiHC
|| matrix_size.uiWB != matrix_size.uiWC) {
printf("ERROR: Matrix sizes do not match!\n");
exit(-1);
}
}
////////////////////////////////////////////////////////////////////////////////
//! Run a simple test matrix multiply using CUBLAS
////////////////////////////////////////////////////////////////////////////////
int matrixMultiply(int argc, char **argv, int devID, sMatrixSize &matrix_size) {
cudaDeviceProp deviceProp;
int matrixMultiply(int argc, char **argv, int devID, sMatrixSize &matrix_size)
{
cudaDeviceProp deviceProp;
checkCudaErrors(cudaGetDeviceProperties(&deviceProp, devID));
checkCudaErrors(cudaGetDeviceProperties(&deviceProp, devID));
int block_size = 32;
int block_size = 32;
// set seed for rand()
srand(2006);
// set seed for rand()
srand(2006);
// allocate host memory for matrices A and B
unsigned int size_A = matrix_size.uiWA * matrix_size.uiHA;
unsigned int mem_size_A = sizeof(float) * size_A;
float *h_A = (float *)malloc(mem_size_A);
unsigned int size_B = matrix_size.uiWB * matrix_size.uiHB;
unsigned int mem_size_B = sizeof(float) * size_B;
float *h_B = (float *)malloc(mem_size_B);
// allocate host memory for matrices A and B
unsigned int size_A = matrix_size.uiWA * matrix_size.uiHA;
unsigned int mem_size_A = sizeof(float) * size_A;
float *h_A = (float *)malloc(mem_size_A);
unsigned int size_B = matrix_size.uiWB * matrix_size.uiHB;
unsigned int mem_size_B = sizeof(float) * size_B;
float *h_B = (float *)malloc(mem_size_B);
// set seed for rand()
srand(2006);
// set seed for rand()
srand(2006);
// initialize host memory
randomInit(h_A, size_A);
randomInit(h_B, size_B);
// initialize host memory
randomInit(h_A, size_A);
randomInit(h_B, size_B);
// allocate device memory
float *d_A, *d_B, *d_C;
unsigned int size_C = matrix_size.uiWC * matrix_size.uiHC;
unsigned int mem_size_C = sizeof(float) * size_C;
// allocate device memory
float *d_A, *d_B, *d_C;
unsigned int size_C = matrix_size.uiWC * matrix_size.uiHC;
unsigned int mem_size_C = sizeof(float) * size_C;
// allocate host memory for the result
float *h_C = (float *)malloc(mem_size_C);
float *h_CUBLAS = (float *)malloc(mem_size_C);
// allocate host memory for the result
float *h_C = (float *)malloc(mem_size_C);
float *h_CUBLAS = (float *)malloc(mem_size_C);
checkCudaErrors(cudaMalloc((void **)&d_A, mem_size_A));
checkCudaErrors(cudaMalloc((void **)&d_B, mem_size_B));
checkCudaErrors(cudaMemcpy(d_A, h_A, mem_size_A, cudaMemcpyHostToDevice));
checkCudaErrors(cudaMemcpy(d_B, h_B, mem_size_B, cudaMemcpyHostToDevice));
checkCudaErrors(cudaMalloc((void **)&d_C, mem_size_C));
checkCudaErrors(cudaMalloc((void **)&d_A, mem_size_A));
checkCudaErrors(cudaMalloc((void **)&d_B, mem_size_B));
checkCudaErrors(cudaMemcpy(d_A, h_A, mem_size_A, cudaMemcpyHostToDevice));
checkCudaErrors(cudaMemcpy(d_B, h_B, mem_size_B, cudaMemcpyHostToDevice));
checkCudaErrors(cudaMalloc((void **)&d_C, mem_size_C));
// setup execution parameters
dim3 threads(block_size, block_size);
dim3 grid(matrix_size.uiWC / threads.x, matrix_size.uiHC / threads.y);
// setup execution parameters
dim3 threads(block_size, block_size);
dim3 grid(matrix_size.uiWC / threads.x, matrix_size.uiHC / threads.y);
// create and start timer
printf("Computing result using CUBLAS...");
// create and start timer
printf("Computing result using CUBLAS...");
// execute the kernel
int nIter = 30;
// execute the kernel
int nIter = 30;
// CUBLAS version 2.0
{
const float alpha = 1.0f;
const float beta = 0.0f;
cublasHandle_t handle;
cudaEvent_t start, stop;
// CUBLAS version 2.0
{
const float alpha = 1.0f;
const float beta = 0.0f;
cublasHandle_t handle;
cudaEvent_t start, stop;
checkCudaErrors(cublasCreate(&handle));
checkCudaErrors(cublasCreate(&handle));
// Perform warmup operation with cublas
checkCudaErrors(cublasSgemm(
handle, CUBLAS_OP_N, CUBLAS_OP_N, matrix_size.uiWB, matrix_size.uiHA,
matrix_size.uiWA, &alpha, d_B, matrix_size.uiWB, d_A, matrix_size.uiWA,
&beta, d_C, matrix_size.uiWB));
// Perform warmup operation with cublas
checkCudaErrors(cublasSgemm(handle,
CUBLAS_OP_N,
CUBLAS_OP_N,
matrix_size.uiWB,
matrix_size.uiHA,
matrix_size.uiWA,
&alpha,
d_B,
matrix_size.uiWB,
d_A,
matrix_size.uiWA,
&beta,
d_C,
matrix_size.uiWB));
// Allocate CUDA events that we'll use for timing
checkCudaErrors(cudaEventCreate(&start));
checkCudaErrors(cudaEventCreate(&stop));
// Allocate CUDA events that we'll use for timing
checkCudaErrors(cudaEventCreate(&start));
checkCudaErrors(cudaEventCreate(&stop));
// Record the start event
checkCudaErrors(cudaEventRecord(start, NULL));
// Record the start event
checkCudaErrors(cudaEventRecord(start, NULL));
for (int j = 0; j < nIter; j++) {
// note cublas is column primary!
// need to transpose the order
checkCudaErrors(cublasSgemm(
handle, CUBLAS_OP_N, CUBLAS_OP_N, matrix_size.uiWB, matrix_size.uiHA,
matrix_size.uiWA, &alpha, d_B, matrix_size.uiWB, d_A,
matrix_size.uiWA, &beta, d_C, matrix_size.uiWB));
for (int j = 0; j < nIter; j++) {
// note cublas is column primary!
// need to transpose the order
checkCudaErrors(cublasSgemm(handle,
CUBLAS_OP_N,
CUBLAS_OP_N,
matrix_size.uiWB,
matrix_size.uiHA,
matrix_size.uiWA,
&alpha,
d_B,
matrix_size.uiWB,
d_A,
matrix_size.uiWA,
&beta,
d_C,
matrix_size.uiWB));
}
printf("done.\n");
// Record the stop event
checkCudaErrors(cudaEventRecord(stop, NULL));
// Wait for the stop event to complete
checkCudaErrors(cudaEventSynchronize(stop));
float msecTotal = 0.0f;
checkCudaErrors(cudaEventElapsedTime(&msecTotal, start, stop));
// Compute and print the performance
float msecPerMatrixMul = msecTotal / nIter;
double flopsPerMatrixMul = 2.0 * (double)matrix_size.uiHC * (double)matrix_size.uiWC * (double)matrix_size.uiHB;
double gigaFlops = (flopsPerMatrixMul * 1.0e-9f) / (msecPerMatrixMul / 1000.0f);
printf("Performance= %.2f GFlop/s, Time= %.3f msec, Size= %.0f Ops\n",
gigaFlops,
msecPerMatrixMul,
flopsPerMatrixMul);
// copy result from device to host
checkCudaErrors(cudaMemcpy(h_CUBLAS, d_C, mem_size_C, cudaMemcpyDeviceToHost));
// Destroy the handle
checkCudaErrors(cublasDestroy(handle));
}
// compute reference solution
printf("Computing result using host CPU...");
float *reference = (float *)malloc(mem_size_C);
matrixMulCPU(reference, h_A, h_B, matrix_size.uiHA, matrix_size.uiWA, matrix_size.uiWB);
printf("done.\n");
// Record the stop event
checkCudaErrors(cudaEventRecord(stop, NULL));
// check result (CUBLAS)
bool resCUBLAS = sdkCompareL2fe(reference, h_CUBLAS, size_C, 1.0e-6f);
// Wait for the stop event to complete
checkCudaErrors(cudaEventSynchronize(stop));
if (resCUBLAS != true) {
printDiff(reference, h_CUBLAS, matrix_size.uiWC, matrix_size.uiHC, 100, 1.0e-5f);
}
float msecTotal = 0.0f;
checkCudaErrors(cudaEventElapsedTime(&msecTotal, start, stop));
printf("Comparing CUBLAS Matrix Multiply with CPU results: %s\n", (true == resCUBLAS) ? "PASS" : "FAIL");
// Compute and print the performance
float msecPerMatrixMul = msecTotal / nIter;
double flopsPerMatrixMul = 2.0 * (double)matrix_size.uiHC *
(double)matrix_size.uiWC *
(double)matrix_size.uiHB;
double gigaFlops =
(flopsPerMatrixMul * 1.0e-9f) / (msecPerMatrixMul / 1000.0f);
printf("Performance= %.2f GFlop/s, Time= %.3f msec, Size= %.0f Ops\n",
gigaFlops, msecPerMatrixMul, flopsPerMatrixMul);
printf("\nNOTE: The CUDA Samples are not meant for performance measurements. "
"Results may vary when GPU Boost is enabled.\n");
// copy result from device to host
checkCudaErrors(
cudaMemcpy(h_CUBLAS, d_C, mem_size_C, cudaMemcpyDeviceToHost));
// clean up memory
free(h_A);
free(h_B);
free(h_C);
free(reference);
checkCudaErrors(cudaFree(d_A));
checkCudaErrors(cudaFree(d_B));
checkCudaErrors(cudaFree(d_C));
// Destroy the handle
checkCudaErrors(cublasDestroy(handle));
}
// compute reference solution
printf("Computing result using host CPU...");
float *reference = (float *)malloc(mem_size_C);
matrixMulCPU(reference, h_A, h_B, matrix_size.uiHA, matrix_size.uiWA,
matrix_size.uiWB);
printf("done.\n");
// check result (CUBLAS)
bool resCUBLAS = sdkCompareL2fe(reference, h_CUBLAS, size_C, 1.0e-6f);
if (resCUBLAS != true) {
printDiff(reference, h_CUBLAS, matrix_size.uiWC, matrix_size.uiHC, 100,
1.0e-5f);
}
printf("Comparing CUBLAS Matrix Multiply with CPU results: %s\n",
(true == resCUBLAS) ? "PASS" : "FAIL");
printf(
"\nNOTE: The CUDA Samples are not meant for performance measurements. "
"Results may vary when GPU Boost is enabled.\n");
// clean up memory
free(h_A);
free(h_B);
free(h_C);
free(reference);
checkCudaErrors(cudaFree(d_A));
checkCudaErrors(cudaFree(d_B));
checkCudaErrors(cudaFree(d_C));
if (resCUBLAS == true) {
return EXIT_SUCCESS; // return value = 1
} else {
return EXIT_FAILURE; // return value = 0
}
if (resCUBLAS == true) {
return EXIT_SUCCESS; // return value = 1
}
else {
return EXIT_FAILURE; // return value = 0
}
}
////////////////////////////////////////////////////////////////////////////////
// Program main
////////////////////////////////////////////////////////////////////////////////
int main(int argc, char **argv) {
printf("[Matrix Multiply CUBLAS] - Starting...\n");
int main(int argc, char **argv)
{
printf("[Matrix Multiply CUBLAS] - Starting...\n");
int devID = 0, sizeMult = 5;
sMatrixSize matrix_size;
int devID = 0, sizeMult = 5;
sMatrixSize matrix_size;
initializeCUDA(argc, argv, devID, sizeMult, matrix_size);
initializeCUDA(argc, argv, devID, sizeMult, matrix_size);
int matrix_result = matrixMultiply(argc, argv, devID, matrix_size);
int matrix_result = matrixMultiply(argc, argv, devID, matrix_size);
return matrix_result;
return matrix_result;
}

File diff suppressed because it is too large Load Diff

View File

@@ -29,6 +29,7 @@
// library nvJPEG encoder supports single and multiple image encode.
#include <cuda_runtime_api.h>
#include "helper_nvJPEG.hxx"
@@ -43,133 +44,127 @@ bool is_interleaved(nvjpegOutputFormat_t format)
return false;
}
struct encode_params_t {
std::string input_dir;
std::string output_dir;
std::string format;
std::string subsampling;
int quality;
int huf;
int dev;
struct encode_params_t
{
std::string input_dir;
std::string output_dir;
std::string format;
std::string subsampling;
int quality;
int huf;
int dev;
};
nvjpegEncoderParams_t encode_params;
nvjpegHandle_t nvjpeg_handle;
nvjpegJpegState_t jpeg_state;
nvjpegEncoderState_t encoder_state;
nvjpegHandle_t nvjpeg_handle;
nvjpegJpegState_t jpeg_state;
nvjpegEncoderState_t encoder_state;
int decodeEncodeOneImage(std::string sImagePath, std::string sOutputPath, double &time, nvjpegOutputFormat_t output_format, nvjpegInputFormat_t input_format)
int decodeEncodeOneImage(std::string sImagePath,
std::string sOutputPath,
double &time,
nvjpegOutputFormat_t output_format,
nvjpegInputFormat_t input_format)
{
time = 0.;
time = 0.;
cudaEvent_t startEvent = NULL, stopEvent = NULL;
float loopTime = 0;
float loopTime = 0;
checkCudaErrors(cudaEventCreate(&startEvent, cudaEventBlockingSync));
checkCudaErrors(cudaEventCreate(&stopEvent, cudaEventBlockingSync));
// Get the file name, without extension.
// This will be used to rename the output file.
size_t position = sImagePath.rfind("/");
std::string sFileName = (std::string::npos == position)? sImagePath : sImagePath.substr(position + 1, sImagePath.size());
position = sFileName.rfind(".");
sFileName = (std::string::npos == position)? sFileName : sFileName.substr(0, position);
position = sFileName.rfind("/");
// This will be used to rename the output file.
size_t position = sImagePath.rfind("/");
std::string sFileName =
(std::string::npos == position) ? sImagePath : sImagePath.substr(position + 1, sImagePath.size());
position = sFileName.rfind(".");
sFileName = (std::string::npos == position) ? sFileName : sFileName.substr(0, position);
position = sFileName.rfind("/");
sFileName = (std::string::npos == position) ? sFileName : sFileName.substr(position + 1, sFileName.length());
position = sFileName.rfind("\\");
sFileName = (std::string::npos == position) ? sFileName : sFileName.substr(position + 1, sFileName.length());
position = sFileName.rfind("\\");
sFileName = (std::string::npos == position) ? sFileName : sFileName.substr(position+1, sFileName.length());
// Read an image from disk.
std::ifstream oInputStream(sImagePath.c_str(), std::ios::in | std::ios::binary | std::ios::ate);
if(!(oInputStream.is_open()))
{
if (!(oInputStream.is_open())) {
std::cerr << "Cannot open image: " << sImagePath << std::endl;
return 1;
}
// Get the size.
std::streamsize nSize = oInputStream.tellg();
oInputStream.seekg(0, std::ios::beg);
// Image buffers.
unsigned char * pBuffer = NULL;
double encoder_time = 0.;
// Image buffers.
unsigned char *pBuffer = NULL;
double encoder_time = 0.;
std::vector<char> vBuffer(nSize);
if (oInputStream.read(vBuffer.data(), nSize))
{
unsigned char * dpImage = (unsigned char *)vBuffer.data();
if (oInputStream.read(vBuffer.data(), nSize)) {
unsigned char *dpImage = (unsigned char *)vBuffer.data();
// Retrieve the componenet and size info.
int nComponent = 0;
int nComponent = 0;
nvjpegChromaSubsampling_t subsampling;
int widths[NVJPEG_MAX_COMPONENT];
int heights[NVJPEG_MAX_COMPONENT];
if (NVJPEG_STATUS_SUCCESS != nvjpegGetImageInfo(nvjpeg_handle, dpImage, nSize, &nComponent, &subsampling, widths, heights))
{
int widths[NVJPEG_MAX_COMPONENT];
int heights[NVJPEG_MAX_COMPONENT];
if (NVJPEG_STATUS_SUCCESS
!= nvjpegGetImageInfo(nvjpeg_handle, dpImage, nSize, &nComponent, &subsampling, widths, heights)) {
std::cerr << "Error decoding JPEG header: " << sImagePath << std::endl;
return 1;
}
// image information
std::cout << "Image is " << nComponent << " channels." << std::endl;
for (int i = 0; i < nComponent; i++)
{
std::cout << "Channel #" << i << " size: " << widths[i] << " x " << heights[i] << std::endl;
for (int i = 0; i < nComponent; i++) {
std::cout << "Channel #" << i << " size: " << widths[i] << " x " << heights[i] << std::endl;
}
switch (subsampling)
{
case NVJPEG_CSS_444:
std::cout << "YUV 4:4:4 chroma subsampling" << std::endl;
break;
case NVJPEG_CSS_440:
std::cout << "YUV 4:4:0 chroma subsampling" << std::endl;
break;
case NVJPEG_CSS_422:
std::cout << "YUV 4:2:2 chroma subsampling" << std::endl;
break;
case NVJPEG_CSS_420:
std::cout << "YUV 4:2:0 chroma subsampling" << std::endl;
break;
case NVJPEG_CSS_411:
std::cout << "YUV 4:1:1 chroma subsampling" << std::endl;
break;
case NVJPEG_CSS_410:
std::cout << "YUV 4:1:0 chroma subsampling" << std::endl;
break;
case NVJPEG_CSS_GRAY:
std::cout << "Grayscale JPEG " << std::endl;
break;
case NVJPEG_CSS_UNKNOWN:
std::cout << "Unknown chroma subsampling" << std::endl;
return 1;
switch (subsampling) {
case NVJPEG_CSS_444:
std::cout << "YUV 4:4:4 chroma subsampling" << std::endl;
break;
case NVJPEG_CSS_440:
std::cout << "YUV 4:4:0 chroma subsampling" << std::endl;
break;
case NVJPEG_CSS_422:
std::cout << "YUV 4:2:2 chroma subsampling" << std::endl;
break;
case NVJPEG_CSS_420:
std::cout << "YUV 4:2:0 chroma subsampling" << std::endl;
break;
case NVJPEG_CSS_411:
std::cout << "YUV 4:1:1 chroma subsampling" << std::endl;
break;
case NVJPEG_CSS_410:
std::cout << "YUV 4:1:0 chroma subsampling" << std::endl;
break;
case NVJPEG_CSS_GRAY:
std::cout << "Grayscale JPEG " << std::endl;
break;
case NVJPEG_CSS_UNKNOWN:
std::cout << "Unknown chroma subsampling" << std::endl;
return 1;
}
{
cudaError_t eCopy = cudaMalloc(&pBuffer, widths[0] * heights[0] * NVJPEG_MAX_COMPONENT);
if(cudaSuccess != eCopy)
{
if (cudaSuccess != eCopy) {
std::cerr << "cudaMalloc failed for component Y: " << cudaGetErrorString(eCopy) << std::endl;
return 1;
}
nvjpegImage_t imgdesc =
{
{
pBuffer,
pBuffer + widths[0]*heights[0],
pBuffer + widths[0]*heights[0]*2,
pBuffer + widths[0]*heights[0]*3
},
{
(unsigned int)(is_interleaved(output_format) ? widths[0] * 3 : widths[0]),
(unsigned int)widths[0],
(unsigned int)widths[0],
(unsigned int)widths[0]
}
};
nvjpegImage_t imgdesc = {{pBuffer,
pBuffer + widths[0] * heights[0],
pBuffer + widths[0] * heights[0] * 2,
pBuffer + widths[0] * heights[0] * 3},
{(unsigned int)(is_interleaved(output_format) ? widths[0] * 3 : widths[0]),
(unsigned int)widths[0],
(unsigned int)widths[0],
(unsigned int)widths[0]}};
int nReturnCode = 0;
cudaDeviceSynchronize();
@@ -182,52 +177,27 @@ int decodeEncodeOneImage(std::string sImagePath, std::string sOutputPath, double
nReturnCode = nvjpegDecodeGPU(nvjpeg_handle, NULL);*/
cudaDeviceSynchronize();
if(nReturnCode != 0)
{
if (nReturnCode != 0) {
std::cerr << "Error in nvjpegDecode." << std::endl;
return 1;
}
checkCudaErrors(cudaEventRecord(startEvent, NULL));
/////////////////////// encode ////////////////////
if (NVJPEG_OUTPUT_YUV == output_format)
{
checkCudaErrors(nvjpegEncodeYUV(nvjpeg_handle,
encoder_state,
encode_params,
&imgdesc,
subsampling,
widths[0],
heights[0],
NULL));
if (NVJPEG_OUTPUT_YUV == output_format) {
checkCudaErrors(nvjpegEncodeYUV(
nvjpeg_handle, encoder_state, encode_params, &imgdesc, subsampling, widths[0], heights[0], NULL));
}
else
{
checkCudaErrors(nvjpegEncodeImage(nvjpeg_handle,
encoder_state,
encode_params,
&imgdesc,
input_format,
widths[0],
heights[0],
NULL));
else {
checkCudaErrors(nvjpegEncodeImage(
nvjpeg_handle, encoder_state, encode_params, &imgdesc, input_format, widths[0], heights[0], NULL));
}
std::vector<unsigned char> obuffer;
size_t length;
checkCudaErrors(nvjpegEncodeRetrieveBitstream(
nvjpeg_handle,
encoder_state,
NULL,
&length,
NULL));
size_t length;
checkCudaErrors(nvjpegEncodeRetrieveBitstream(nvjpeg_handle, encoder_state, NULL, &length, NULL));
obuffer.resize(length);
checkCudaErrors(nvjpegEncodeRetrieveBitstream(
nvjpeg_handle,
encoder_state,
obuffer.data(),
&length,
NULL));
checkCudaErrors(nvjpegEncodeRetrieveBitstream(nvjpeg_handle, encoder_state, obuffer.data(), &length, NULL));
checkCudaErrors(cudaEventRecord(stopEvent, NULL));
checkCudaErrors(cudaEventSynchronize(stopEvent));
@@ -235,10 +205,10 @@ int decodeEncodeOneImage(std::string sImagePath, std::string sOutputPath, double
encoder_time = static_cast<double>(loopTime);
std::string output_filename = sOutputPath + "/" + sFileName + ".jpg";
char directory[120];
char mkdir_cmd[256];
char directory[120];
char mkdir_cmd[256];
std::string folder = sOutputPath;
output_filename = folder + "/"+ sFileName +".jpg";
output_filename = folder + "/" + sFileName + ".jpg";
#if !defined(_WIN32)
sprintf(directory, "%s", folder.c_str());
sprintf(mkdir_cmd, "mkdir -p %s 2> /dev/null", directory);
@@ -252,7 +222,7 @@ int decodeEncodeOneImage(std::string sImagePath, std::string sOutputPath, double
std::cout << "Writing JPEG file: " << output_filename << std::endl;
std::ofstream outputFile(output_filename.c_str(), std::ios::out | std::ios::binary);
outputFile.write(reinterpret_cast<const char *>(obuffer.data()), static_cast<int>(length));
// Free memory
checkCudaErrors(cudaFree(pBuffer));
}
@@ -265,75 +235,61 @@ int decodeEncodeOneImage(std::string sImagePath, std::string sOutputPath, double
int processArgs(encode_params_t param)
{
std::string sInputPath(param.input_dir);
std::string sOutputPath(param.output_dir);
std::string sFormat(param.format);
std::string sSubsampling(param.subsampling);
std::string sInputPath(param.input_dir);
std::string sOutputPath(param.output_dir);
std::string sFormat(param.format);
std::string sSubsampling(param.subsampling);
nvjpegOutputFormat_t oformat = NVJPEG_OUTPUT_RGB;
nvjpegInputFormat_t iformat = NVJPEG_INPUT_RGB;
nvjpegInputFormat_t iformat = NVJPEG_INPUT_RGB;
int error_code = 1;
if (sFormat == "yuv")
{
if (sFormat == "yuv") {
oformat = NVJPEG_OUTPUT_YUV;
}
else if (sFormat == "rgb")
{
}
else if (sFormat == "rgb") {
oformat = NVJPEG_OUTPUT_RGB;
iformat = NVJPEG_INPUT_RGB;
}
else if (sFormat == "bgr")
{
else if (sFormat == "bgr") {
oformat = NVJPEG_OUTPUT_BGR;
iformat = NVJPEG_INPUT_BGR;
}
else if (sFormat == "rgbi")
{
else if (sFormat == "rgbi") {
oformat = NVJPEG_OUTPUT_RGBI;
iformat = NVJPEG_INPUT_RGBI;
}
else if (sFormat == "bgri")
{
else if (sFormat == "bgri") {
oformat = NVJPEG_OUTPUT_BGRI;
iformat = NVJPEG_INPUT_BGRI;
}
else
{
else {
std::cerr << "Unknown or unsupported output format: " << sFormat << std::endl;
return error_code;
}
if (sSubsampling == "444")
{
if (sSubsampling == "444") {
checkCudaErrors(nvjpegEncoderParamsSetSamplingFactors(encode_params, NVJPEG_CSS_444, NULL));
}
else if (sSubsampling == "422")
{
else if (sSubsampling == "422") {
checkCudaErrors(nvjpegEncoderParamsSetSamplingFactors(encode_params, NVJPEG_CSS_422, NULL));
}
else if (sSubsampling == "420")
{
else if (sSubsampling == "420") {
checkCudaErrors(nvjpegEncoderParamsSetSamplingFactors(encode_params, NVJPEG_CSS_420, NULL));
}
else if (sSubsampling == "440")
{
else if (sSubsampling == "440") {
checkCudaErrors(nvjpegEncoderParamsSetSamplingFactors(encode_params, NVJPEG_CSS_440, NULL));
}
else if (sSubsampling == "411")
{
else if (sSubsampling == "411") {
checkCudaErrors(nvjpegEncoderParamsSetSamplingFactors(encode_params, NVJPEG_CSS_411, NULL));
}
else if (sSubsampling == "410")
{
else if (sSubsampling == "410") {
checkCudaErrors(nvjpegEncoderParamsSetSamplingFactors(encode_params, NVJPEG_CSS_410, NULL));
}
else if (sSubsampling == "400")
{
else if (sSubsampling == "400") {
checkCudaErrors(nvjpegEncoderParamsSetSamplingFactors(encode_params, NVJPEG_CSS_GRAY, NULL));
}
else
{
else {
std::cerr << "Unknown or unsupported subsampling: " << sSubsampling << std::endl;
return error_code;
}
@@ -355,144 +311,146 @@ int processArgs(encode_params_t param)
}*/
std::vector<std::string> inputFiles;
if (readInput(sInputPath, inputFiles))
{
if (readInput(sInputPath, inputFiles)) {
return error_code;
}
double total_time = 0., encoder_time = 0.;
int total_images = 0;
for (unsigned int i = 0; i < inputFiles.size(); i++)
{
double total_time = 0., encoder_time = 0.;
int total_images = 0;
for (unsigned int i = 0; i < inputFiles.size(); i++) {
std::string &sFileName = inputFiles[i];
std::cout << "Processing file: " << sFileName << std::endl;
int image_error_code = decodeEncodeOneImage(sFileName, sOutputPath, encoder_time, oformat, iformat);
if (image_error_code)
{
if (image_error_code) {
std::cerr << "Error processing file: " << sFileName << std::endl;
//return image_error_code;
// return image_error_code;
}
else
{
else {
total_images++;
total_time += encoder_time;
}
}
}
std::cout << "Total images processed: " << total_images << std::endl;
std::cout << "Total time spent on encoding: " << total_time << std::endl;
std::cout << "Avg time/image: " << total_time/total_images << std::endl;
std::cout << "Avg time/image: " << total_time / total_images << std::endl;
return 0;
}
// parse parameters
int findParamIndex(const char **argv, int argc, const char *parm) {
int count = 0;
int index = -1;
int findParamIndex(const char **argv, int argc, const char *parm)
{
int count = 0;
int index = -1;
for (int i = 0; i < argc; i++) {
if (strncmp(argv[i], parm, 100) == 0) {
index = i;
count++;
for (int i = 0; i < argc; i++) {
if (strncmp(argv[i], parm, 100) == 0) {
index = i;
count++;
}
}
if (count == 0 || count == 1) {
return index;
}
else {
std::cout << "Error, parameter " << parm << " has been specified more than once, exiting\n" << std::endl;
return -1;
}
}
if (count == 0 || count == 1) {
return index;
} else {
std::cout << "Error, parameter " << parm
<< " has been specified more than once, exiting\n"
<< std::endl;
return -1;
}
return -1;
}
int main(int argc, const char *argv[])
int main(int argc, const char *argv[])
{
int pidx;
int pidx;
if ((pidx = findParamIndex(argv, argc, "-h")) != -1 ||
(pidx = findParamIndex(argv, argc, "--help")) != -1) {
std::cout << "Usage: " << argv[0]
<< " -i images_dir [-o output_dir] [-device=device_id]"
"[-q quality][-s 420/444] [-fmt output_format] [-huf 0]\n";
std::cout << "Parameters: " << std::endl;
std::cout << "\timages_dir\t:\tPath to single image or directory of images" << std::endl;
std::cout << "\toutput_dir\t:\tWrite encoded images as jpeg to this directory" << std::endl;
std::cout << "\tdevice_id\t:\tWhich device to use for encoding" << std::endl;
std::cout << "\tQuality\t:\tUse image quality [default 70]" << std::endl;
std::cout << "\tsubsampling\t:\tUse Subsampling [420, 444]" << std::endl;
std::cout << "\toutput_format\t:\tnvJPEG output format for encoding. One "
"of [rgb, rgbi, bgr, bgri, yuv, y, unchanged]"
<< std::endl;
std::cout << "\tHuffman Optimization\t:\tUse Huffman optimization [default 0]" << std::endl;
return EXIT_SUCCESS;
}
encode_params_t params;
params.input_dir = "./";
if ((pidx = findParamIndex(argv, argc, "-i")) != -1) {
params.input_dir = argv[pidx + 1];
} else {
// Search in default paths for input images.
int found = getInputDir(params.input_dir, argv[0]);
if (!found)
{
std::cout << "Please specify input directory with encoded images"<< std::endl;
return EXIT_WAIVED;
if ((pidx = findParamIndex(argv, argc, "-h")) != -1 || (pidx = findParamIndex(argv, argc, "--help")) != -1) {
std::cout << "Usage: " << argv[0]
<< " -i images_dir [-o output_dir] [-device=device_id]"
"[-q quality][-s 420/444] [-fmt output_format] [-huf 0]\n";
std::cout << "Parameters: " << std::endl;
std::cout << "\timages_dir\t:\tPath to single image or directory of images" << std::endl;
std::cout << "\toutput_dir\t:\tWrite encoded images as jpeg to this directory" << std::endl;
std::cout << "\tdevice_id\t:\tWhich device to use for encoding" << std::endl;
std::cout << "\tQuality\t:\tUse image quality [default 70]" << std::endl;
std::cout << "\tsubsampling\t:\tUse Subsampling [420, 444]" << std::endl;
std::cout << "\toutput_format\t:\tnvJPEG output format for encoding. One "
"of [rgb, rgbi, bgr, bgri, yuv, y, unchanged]"
<< std::endl;
std::cout << "\tHuffman Optimization\t:\tUse Huffman optimization [default 0]" << std::endl;
return EXIT_SUCCESS;
}
}
if ((pidx = findParamIndex(argv, argc, "-o")) != -1) {
params.output_dir = argv[pidx + 1];
} else {
// by-default write the folder named "output" in cwd
params.output_dir = "encode_output";
}
params.dev = 0;
params.dev = findCudaDevice(argc, argv);
params.quality = 70;
if ((pidx = findParamIndex(argv, argc, "-q")) != -1) {
params.quality = std::atoi(argv[pidx + 1]);
}
encode_params_t params;
if ((pidx = findParamIndex(argv, argc, "-s")) != -1) {
params.subsampling = argv[pidx + 1];
} else {
// by-default use subsampling as 420
params.subsampling = "420";
}
if ((pidx = findParamIndex(argv, argc, "-fmt")) != -1) {
params.format = argv[pidx + 1];
} else {
// by-default use output format yuv
params.format = "yuv";
}
params.input_dir = "./";
if ((pidx = findParamIndex(argv, argc, "-i")) != -1) {
params.input_dir = argv[pidx + 1];
}
else {
// Search in default paths for input images.
int found = getInputDir(params.input_dir, argv[0]);
if (!found) {
std::cout << "Please specify input directory with encoded images" << std::endl;
return EXIT_WAIVED;
}
}
if ((pidx = findParamIndex(argv, argc, "-o")) != -1) {
params.output_dir = argv[pidx + 1];
}
else {
// by-default write the folder named "output" in cwd
params.output_dir = "encode_output";
}
params.dev = 0;
params.dev = findCudaDevice(argc, argv);
params.huf = 0;
if ((pidx = findParamIndex(argv, argc, "-huf")) != -1) {
params.huf = std::atoi(argv[pidx + 1]);
}
params.quality = 70;
if ((pidx = findParamIndex(argv, argc, "-q")) != -1) {
params.quality = std::atoi(argv[pidx + 1]);
}
if ((pidx = findParamIndex(argv, argc, "-s")) != -1) {
params.subsampling = argv[pidx + 1];
}
else {
// by-default use subsampling as 420
params.subsampling = "420";
}
if ((pidx = findParamIndex(argv, argc, "-fmt")) != -1) {
params.format = argv[pidx + 1];
}
else {
// by-default use output format yuv
params.format = "yuv";
}
params.huf = 0;
if ((pidx = findParamIndex(argv, argc, "-huf")) != -1) {
params.huf = std::atoi(argv[pidx + 1]);
}
cudaDeviceProp props;
checkCudaErrors(cudaGetDeviceProperties(&props, params.dev));
printf("Using GPU %d (%s, %d SMs, %d th/SM max, CC %d.%d, ECC %s)\n",
params.dev, props.name, props.multiProcessorCount,
props.maxThreadsPerMultiProcessor, props.major, props.minor,
props.ECCEnabled ? "on" : "off");
params.dev,
props.name,
props.multiProcessorCount,
props.maxThreadsPerMultiProcessor,
props.major,
props.minor,
props.ECCEnabled ? "on" : "off");
nvjpegDevAllocator_t dev_allocator = {&dev_malloc, &dev_free};
checkCudaErrors(nvjpegCreate(NVJPEG_BACKEND_DEFAULT, &dev_allocator, &nvjpeg_handle));
checkCudaErrors(nvjpegJpegStateCreate(nvjpeg_handle, &jpeg_state));
checkCudaErrors(nvjpegEncoderStateCreate(nvjpeg_handle, &encoder_state, NULL));
checkCudaErrors(nvjpegEncoderParamsCreate(nvjpeg_handle, &encode_params, NULL));
// sample input parameters
checkCudaErrors(nvjpegEncoderParamsSetQuality(encode_params, params.quality, NULL));
checkCudaErrors(nvjpegEncoderParamsSetOptimizedHuffman(encode_params, params.huf, NULL));

View File

@@ -34,4 +34,3 @@ Download and install the [CUDA Toolkit 12.5](https://developer.nvidia.com/cuda-d
Make sure the dependencies mentioned in [Dependencies]() section above are installed.
## References (for more details)

File diff suppressed because it is too large Load Diff

View File

@@ -35,125 +35,124 @@ int cuda_iDivUp(int a, int b) { return (a + (b - 1)) / b; }
// complex math functions
__device__ float2 conjugate(float2 arg) { return make_float2(arg.x, -arg.y); }
__device__ float2 complex_exp(float arg) {
return make_float2(cosf(arg), sinf(arg));
}
__device__ float2 complex_exp(float arg) { return make_float2(cosf(arg), sinf(arg)); }
__device__ float2 complex_add(float2 a, float2 b) {
return make_float2(a.x + b.x, a.y + b.y);
}
__device__ float2 complex_add(float2 a, float2 b) { return make_float2(a.x + b.x, a.y + b.y); }
__device__ float2 complex_mult(float2 ab, float2 cd) {
return make_float2(ab.x * cd.x - ab.y * cd.y, ab.x * cd.y + ab.y * cd.x);
__device__ float2 complex_mult(float2 ab, float2 cd)
{
return make_float2(ab.x * cd.x - ab.y * cd.y, ab.x * cd.y + ab.y * cd.x);
}
// generate wave heightfield at time t based on initial heightfield and
// dispersion relationship
__global__ void generateSpectrumKernel(float2 *h0, float2 *ht,
__global__ void generateSpectrumKernel(float2 *h0,
float2 *ht,
unsigned int in_width,
unsigned int out_width,
unsigned int out_height, float t,
float patchSize) {
unsigned int x = blockIdx.x * blockDim.x + threadIdx.x;
unsigned int y = blockIdx.y * blockDim.y + threadIdx.y;
unsigned int in_index = y * in_width + x;
unsigned int in_mindex =
(out_height - y) * in_width + (out_width - x); // mirrored
unsigned int out_index = y * out_width + x;
unsigned int out_height,
float t,
float patchSize)
{
unsigned int x = blockIdx.x * blockDim.x + threadIdx.x;
unsigned int y = blockIdx.y * blockDim.y + threadIdx.y;
unsigned int in_index = y * in_width + x;
unsigned int in_mindex = (out_height - y) * in_width + (out_width - x); // mirrored
unsigned int out_index = y * out_width + x;
// calculate wave vector
float2 k;
k.x = (-(int)out_width / 2.0f + x) * (2.0f * CUDART_PI_F / patchSize);
k.y = (-(int)out_width / 2.0f + y) * (2.0f * CUDART_PI_F / patchSize);
// calculate wave vector
float2 k;
k.x = (-(int)out_width / 2.0f + x) * (2.0f * CUDART_PI_F / patchSize);
k.y = (-(int)out_width / 2.0f + y) * (2.0f * CUDART_PI_F / patchSize);
// calculate dispersion w(k)
float k_len = sqrtf(k.x * k.x + k.y * k.y);
float w = sqrtf(9.81f * k_len);
// calculate dispersion w(k)
float k_len = sqrtf(k.x * k.x + k.y * k.y);
float w = sqrtf(9.81f * k_len);
if ((x < out_width) && (y < out_height)) {
float2 h0_k = h0[in_index];
float2 h0_mk = h0[in_mindex];
if ((x < out_width) && (y < out_height)) {
float2 h0_k = h0[in_index];
float2 h0_mk = h0[in_mindex];
// output frequency-space complex values
ht[out_index] =
complex_add(complex_mult(h0_k, complex_exp(w * t)),
complex_mult(conjugate(h0_mk), complex_exp(-w * t)));
// ht[out_index] = h0_k;
}
// output frequency-space complex values
ht[out_index] =
complex_add(complex_mult(h0_k, complex_exp(w * t)), complex_mult(conjugate(h0_mk), complex_exp(-w * t)));
// ht[out_index] = h0_k;
}
}
// update height map values based on output of FFT
__global__ void updateHeightmapKernel(float *heightMap, float2 *ht,
unsigned int width) {
unsigned int x = blockIdx.x * blockDim.x + threadIdx.x;
unsigned int y = blockIdx.y * blockDim.y + threadIdx.y;
unsigned int i = y * width + x;
__global__ void updateHeightmapKernel(float *heightMap, float2 *ht, unsigned int width)
{
unsigned int x = blockIdx.x * blockDim.x + threadIdx.x;
unsigned int y = blockIdx.y * blockDim.y + threadIdx.y;
unsigned int i = y * width + x;
// cos(pi * (m1 + m2))
float sign_correction = ((x + y) & 0x01) ? -1.0f : 1.0f;
// cos(pi * (m1 + m2))
float sign_correction = ((x + y) & 0x01) ? -1.0f : 1.0f;
heightMap[i] = ht[i].x * sign_correction;
heightMap[i] = ht[i].x * sign_correction;
}
// update height map values based on output of FFT
__global__ void updateHeightmapKernel_y(float *heightMap, float2 *ht,
unsigned int width) {
unsigned int x = blockIdx.x * blockDim.x + threadIdx.x;
unsigned int y = blockIdx.y * blockDim.y + threadIdx.y;
unsigned int i = y * width + x;
__global__ void updateHeightmapKernel_y(float *heightMap, float2 *ht, unsigned int width)
{
unsigned int x = blockIdx.x * blockDim.x + threadIdx.x;
unsigned int y = blockIdx.y * blockDim.y + threadIdx.y;
unsigned int i = y * width + x;
// cos(pi * (m1 + m2))
float sign_correction = ((x + y) & 0x01) ? -1.0f : 1.0f;
// cos(pi * (m1 + m2))
float sign_correction = ((x + y) & 0x01) ? -1.0f : 1.0f;
heightMap[i] = ht[i].y * sign_correction;
heightMap[i] = ht[i].y * sign_correction;
}
// generate slope by partial differences in spatial domain
__global__ void calculateSlopeKernel(float *h, float2 *slopeOut,
unsigned int width, unsigned int height) {
unsigned int x = blockIdx.x * blockDim.x + threadIdx.x;
unsigned int y = blockIdx.y * blockDim.y + threadIdx.y;
unsigned int i = y * width + x;
__global__ void calculateSlopeKernel(float *h, float2 *slopeOut, unsigned int width, unsigned int height)
{
unsigned int x = blockIdx.x * blockDim.x + threadIdx.x;
unsigned int y = blockIdx.y * blockDim.y + threadIdx.y;
unsigned int i = y * width + x;
float2 slope = make_float2(0.0f, 0.0f);
float2 slope = make_float2(0.0f, 0.0f);
if ((x > 0) && (y > 0) && (x < width - 1) && (y < height - 1)) {
slope.x = h[i + 1] - h[i - 1];
slope.y = h[i + width] - h[i - width];
}
if ((x > 0) && (y > 0) && (x < width - 1) && (y < height - 1)) {
slope.x = h[i + 1] - h[i - 1];
slope.y = h[i + width] - h[i - width];
}
slopeOut[i] = slope;
slopeOut[i] = slope;
}
// wrapper functions
extern "C" void cudaGenerateSpectrumKernel(float2 *d_h0, float2 *d_ht,
extern "C" void cudaGenerateSpectrumKernel(float2 *d_h0,
float2 *d_ht,
unsigned int in_width,
unsigned int out_width,
unsigned int out_height,
float animTime, float patchSize) {
dim3 block(8, 8, 1);
dim3 grid(cuda_iDivUp(out_width, block.x), cuda_iDivUp(out_height, block.y),
1);
generateSpectrumKernel<<<grid, block>>>(d_h0, d_ht, in_width, out_width,
out_height, animTime, patchSize);
float animTime,
float patchSize)
{
dim3 block(8, 8, 1);
dim3 grid(cuda_iDivUp(out_width, block.x), cuda_iDivUp(out_height, block.y), 1);
generateSpectrumKernel<<<grid, block>>>(d_h0, d_ht, in_width, out_width, out_height, animTime, patchSize);
}
extern "C" void cudaUpdateHeightmapKernel(float *d_heightMap, float2 *d_ht,
unsigned int width,
unsigned int height, bool autoTest) {
dim3 block(8, 8, 1);
dim3 grid(cuda_iDivUp(width, block.x), cuda_iDivUp(height, block.y), 1);
if (autoTest) {
updateHeightmapKernel_y<<<grid, block>>>(d_heightMap, d_ht, width);
} else {
updateHeightmapKernel<<<grid, block>>>(d_heightMap, d_ht, width);
}
extern "C" void
cudaUpdateHeightmapKernel(float *d_heightMap, float2 *d_ht, unsigned int width, unsigned int height, bool autoTest)
{
dim3 block(8, 8, 1);
dim3 grid(cuda_iDivUp(width, block.x), cuda_iDivUp(height, block.y), 1);
if (autoTest) {
updateHeightmapKernel_y<<<grid, block>>>(d_heightMap, d_ht, width);
}
else {
updateHeightmapKernel<<<grid, block>>>(d_heightMap, d_ht, width);
}
}
extern "C" void cudaCalculateSlopeKernel(float *hptr, float2 *slopeOut,
unsigned int width,
unsigned int height) {
dim3 block(8, 8, 1);
dim3 grid2(cuda_iDivUp(width, block.x), cuda_iDivUp(height, block.y), 1);
calculateSlopeKernel<<<grid2, block>>>(hptr, slopeOut, width, height);
extern "C" void cudaCalculateSlopeKernel(float *hptr, float2 *slopeOut, unsigned int width, unsigned int height)
{
dim3 block(8, 8, 1);
dim3 grid2(cuda_iDivUp(width, block.x), cuda_iDivUp(height, block.y), 1);
calculateSlopeKernel<<<grid2, block>>>(hptr, slopeOut, width, height);
}

View File

@@ -34,4 +34,3 @@ Download and install the [CUDA Toolkit 12.5](https://developer.nvidia.com/cuda-d
Make sure the dependencies mentioned in [Dependencies]() section above are installed.
## References (for more details)

File diff suppressed because it is too large Load Diff

View File

@@ -28,282 +28,287 @@
// Utilities and System includes
// Includes
#include <curand.h>
#include <stdexcept>
#include <sstream>
#include "rng.h"
#include <curand.h>
#include <sstream>
#include <stdexcept>
// Shared Library Test Functions
#include <helper_timer.h>
#include <helper_cuda.h>
#include <helper_timer.h>
const unsigned int RNG::s_maxQrngDimensions = 20000;
RNG::RNG(unsigned long prngSeed, unsigned int qrngDimensions,
unsigned int nSamples)
: m_prngSeed(prngSeed),
m_qrngDimensions(qrngDimensions),
m_nSamplesBatchTarget(nSamples),
m_nSamplesRemaining(0) {
using std::invalid_argument;
using std::runtime_error;
using std::string;
RNG::RNG(unsigned long prngSeed, unsigned int qrngDimensions, unsigned int nSamples)
: m_prngSeed(prngSeed)
, m_qrngDimensions(qrngDimensions)
, m_nSamplesBatchTarget(nSamples)
, m_nSamplesRemaining(0)
{
using std::invalid_argument;
using std::runtime_error;
using std::string;
if (m_prngSeed == 0) {
throw invalid_argument("PRNG seed must be non-zero");
}
if (m_prngSeed == 0) {
throw invalid_argument("PRNG seed must be non-zero");
}
if (m_qrngDimensions == 0) {
throw invalid_argument("QRNG dimensions must be non-zero");
}
if (m_qrngDimensions == 0) {
throw invalid_argument("QRNG dimensions must be non-zero");
}
if (m_nSamplesBatchTarget == 0) {
throw invalid_argument("RNG batch size must be non-zero");
}
if (m_nSamplesBatchTarget == 0) {
throw invalid_argument("RNG batch size must be non-zero");
}
if (m_nSamplesBatchTarget < s_maxQrngDimensions) {
throw invalid_argument(
"RNG batch size must be greater than RNG::s_maxQrngDimensions");
}
if (m_nSamplesBatchTarget < s_maxQrngDimensions) {
throw invalid_argument("RNG batch size must be greater than RNG::s_maxQrngDimensions");
}
curandStatus_t curandResult;
cudaError_t cudaResult;
curandStatus_t curandResult;
cudaError_t cudaResult;
// Allocate sample array in host mem
m_h_samples = (float *)malloc(m_nSamplesBatchTarget * sizeof(float));
// Allocate sample array in host mem
m_h_samples = (float *)malloc(m_nSamplesBatchTarget * sizeof(float));
if (m_h_samples == NULL) {
throw runtime_error("Could not allocate host memory for RNG::m_h_samples");
}
if (m_h_samples == NULL) {
throw runtime_error("Could not allocate host memory for RNG::m_h_samples");
}
// Allocate sample array in device mem
cudaResult =
cudaMalloc((void **)&m_d_samples, m_nSamplesBatchTarget * sizeof(float));
// Allocate sample array in device mem
cudaResult = cudaMalloc((void **)&m_d_samples, m_nSamplesBatchTarget * sizeof(float));
if (cudaResult != cudaSuccess) {
string msg("Could not allocate device memory for RNG::m_d_samples: ");
msg += cudaGetErrorString(cudaResult);
throw runtime_error(msg);
}
if (cudaResult != cudaSuccess) {
string msg("Could not allocate device memory for RNG::m_d_samples: ");
msg += cudaGetErrorString(cudaResult);
throw runtime_error(msg);
}
// Create the Random Number Generators
curandResult = curandCreateGenerator(&m_prng, CURAND_RNG_PSEUDO_XORWOW);
// Create the Random Number Generators
curandResult = curandCreateGenerator(&m_prng, CURAND_RNG_PSEUDO_XORWOW);
if (curandResult != CURAND_STATUS_SUCCESS) {
string msg("Could not create pseudo-random number generator: ");
msg += curandResult;
throw runtime_error(msg);
}
if (curandResult != CURAND_STATUS_SUCCESS) {
string msg("Could not create pseudo-random number generator: ");
msg += curandResult;
throw runtime_error(msg);
}
curandResult = curandCreateGenerator(&m_qrng, CURAND_RNG_QUASI_SOBOL32);
curandResult = curandCreateGenerator(&m_qrng, CURAND_RNG_QUASI_SOBOL32);
if (curandResult != CURAND_STATUS_SUCCESS) {
string msg("Could not create quasi-random number generator: ");
msg += curandResult;
throw runtime_error(msg);
}
if (curandResult != CURAND_STATUS_SUCCESS) {
string msg("Could not create quasi-random number generator: ");
msg += curandResult;
throw runtime_error(msg);
}
curandResult =
curandCreateGenerator(&m_sqrng, CURAND_RNG_QUASI_SCRAMBLED_SOBOL32);
curandResult = curandCreateGenerator(&m_sqrng, CURAND_RNG_QUASI_SCRAMBLED_SOBOL32);
if (curandResult != CURAND_STATUS_SUCCESS) {
string msg("Could not create scrambled quasi-random number generator: ");
msg += curandResult;
throw runtime_error(msg);
}
if (curandResult != CURAND_STATUS_SUCCESS) {
string msg("Could not create scrambled quasi-random number generator: ");
msg += curandResult;
throw runtime_error(msg);
}
// Setup initial parameters
resetSeed();
updateDimensions();
setBatchSize();
// Setup initial parameters
resetSeed();
updateDimensions();
setBatchSize();
// Set default RNG to be pseudo-random (XORWOW)
m_pCurrent = &m_prng;
// Set default RNG to be pseudo-random (XORWOW)
m_pCurrent = &m_prng;
}
RNG::~RNG() {
curandDestroyGenerator(m_prng);
curandDestroyGenerator(m_qrng);
curandDestroyGenerator(m_sqrng);
RNG::~RNG()
{
curandDestroyGenerator(m_prng);
curandDestroyGenerator(m_qrng);
curandDestroyGenerator(m_sqrng);
if (m_d_samples) {
cudaFree(m_d_samples);
}
if (m_d_samples) {
cudaFree(m_d_samples);
}
if (m_h_samples) {
free(m_h_samples);
}
if (m_h_samples) {
free(m_h_samples);
}
}
void RNG::generateBatch(void) {
using std::runtime_error;
using std::string;
void RNG::generateBatch(void)
{
using std::runtime_error;
using std::string;
cudaError_t cudaResult;
curandStatus_t curandResult;
cudaError_t cudaResult;
curandStatus_t curandResult;
// Generate random numbers
curandResult =
curandGenerateUniform(*m_pCurrent, m_d_samples, m_nSamplesBatchActual);
// Generate random numbers
curandResult = curandGenerateUniform(*m_pCurrent, m_d_samples, m_nSamplesBatchActual);
if (curandResult != CURAND_STATUS_SUCCESS) {
string msg("Could not generate random numbers: ");
msg += curandResult;
throw runtime_error(msg);
}
if (curandResult != CURAND_STATUS_SUCCESS) {
string msg("Could not generate random numbers: ");
msg += curandResult;
throw runtime_error(msg);
}
// Copy random numbers to host
cudaResult =
cudaMemcpy(m_h_samples, m_d_samples,
m_nSamplesBatchActual * sizeof(float), cudaMemcpyDeviceToHost);
// Copy random numbers to host
cudaResult = cudaMemcpy(m_h_samples, m_d_samples, m_nSamplesBatchActual * sizeof(float), cudaMemcpyDeviceToHost);
if (cudaResult != cudaSuccess) {
string msg("Could not copy random numbers to host: ");
msg += cudaGetErrorString(cudaResult);
throw runtime_error(msg);
}
if (cudaResult != cudaSuccess) {
string msg("Could not copy random numbers to host: ");
msg += cudaGetErrorString(cudaResult);
throw runtime_error(msg);
}
}
float RNG::getNextU01(void) {
if (m_nSamplesRemaining == 0) {
generateBatch();
m_nSamplesRemaining = m_nSamplesBatchActual;
}
float RNG::getNextU01(void)
{
if (m_nSamplesRemaining == 0) {
generateBatch();
m_nSamplesRemaining = m_nSamplesBatchActual;
}
if (m_pCurrent == &m_prng) {
return m_h_samples[m_nSamplesBatchActual - m_nSamplesRemaining--];
} else {
unsigned int index = m_nSamplesBatchActual - m_nSamplesRemaining--;
unsigned int samplesPerDim = m_nSamplesBatchActual / m_qrngDimensions;
unsigned int dimOffset = (index % m_qrngDimensions) * samplesPerDim;
unsigned int drawOffset = index / m_qrngDimensions;
return m_h_samples[dimOffset + drawOffset];
}
if (m_pCurrent == &m_prng) {
return m_h_samples[m_nSamplesBatchActual - m_nSamplesRemaining--];
}
else {
unsigned int index = m_nSamplesBatchActual - m_nSamplesRemaining--;
unsigned int samplesPerDim = m_nSamplesBatchActual / m_qrngDimensions;
unsigned int dimOffset = (index % m_qrngDimensions) * samplesPerDim;
unsigned int drawOffset = index / m_qrngDimensions;
return m_h_samples[dimOffset + drawOffset];
}
}
void RNG::getInfoString(std::string &msg) {
using std::stringstream;
void RNG::getInfoString(std::string &msg)
{
using std::stringstream;
stringstream ss;
stringstream ss;
if (m_pCurrent == &m_prng) {
ss << "XORWOW (seed=" << m_prngSeed << ")";
} else if (m_pCurrent == &m_qrng) {
ss << "Sobol (dimensions=" << m_qrngDimensions << ")";
} else if (m_pCurrent == &m_sqrng) {
ss << "Scrambled Sobol (dimensions=" << m_qrngDimensions << ")";
} else {
ss << "Invalid RNG";
}
if (m_pCurrent == &m_prng) {
ss << "XORWOW (seed=" << m_prngSeed << ")";
}
else if (m_pCurrent == &m_qrng) {
ss << "Sobol (dimensions=" << m_qrngDimensions << ")";
}
else if (m_pCurrent == &m_sqrng) {
ss << "Scrambled Sobol (dimensions=" << m_qrngDimensions << ")";
}
else {
ss << "Invalid RNG";
}
msg.assign(ss.str());
msg.assign(ss.str());
}
void RNG::selectRng(RNG::RngType type) {
switch (type) {
void RNG::selectRng(RNG::RngType type)
{
switch (type) {
case Quasi:
m_pCurrent = &m_qrng;
break;
m_pCurrent = &m_qrng;
break;
case ScrambledQuasi:
m_pCurrent = &m_sqrng;
break;
m_pCurrent = &m_sqrng;
break;
case Pseudo:
default:
m_pCurrent = &m_prng;
break;
}
m_pCurrent = &m_prng;
break;
}
setBatchSize();
setBatchSize();
}
void RNG::resetSeed(void) {
using std::runtime_error;
void RNG::resetSeed(void)
{
using std::runtime_error;
curandStatus_t curandResult;
curandResult = curandSetPseudoRandomGeneratorSeed(m_prng, m_prngSeed);
curandStatus_t curandResult;
curandResult = curandSetPseudoRandomGeneratorSeed(m_prng, m_prngSeed);
if (curandResult != CURAND_STATUS_SUCCESS) {
std::string msg("Could not set pseudo-random number generator seed: ");
msg += curandResult;
throw runtime_error(msg);
}
if (curandResult != CURAND_STATUS_SUCCESS) {
std::string msg("Could not set pseudo-random number generator seed: ");
msg += curandResult;
throw runtime_error(msg);
}
curandResult = curandSetGeneratorOffset(m_prng, 0);
curandResult = curandSetGeneratorOffset(m_prng, 0);
if (curandResult != CURAND_STATUS_SUCCESS) {
std::string msg("Could not set pseudo-random number generator offset: ");
msg += curandResult;
throw runtime_error(msg);
}
if (curandResult != CURAND_STATUS_SUCCESS) {
std::string msg("Could not set pseudo-random number generator offset: ");
msg += curandResult;
throw runtime_error(msg);
}
setBatchSize();
setBatchSize();
}
void RNG::resetDimensions(void) {
m_qrngDimensions = 1;
updateDimensions();
setBatchSize();
}
void RNG::incrementDimensions(void) {
if (++m_qrngDimensions > s_maxQrngDimensions) {
void RNG::resetDimensions(void)
{
m_qrngDimensions = 1;
}
updateDimensions();
setBatchSize();
updateDimensions();
setBatchSize();
}
void RNG::updateDimensions(void) {
using std::runtime_error;
void RNG::incrementDimensions(void)
{
if (++m_qrngDimensions > s_maxQrngDimensions) {
m_qrngDimensions = 1;
}
curandStatus_t curandResult;
curandResult =
curandSetQuasiRandomGeneratorDimensions(m_qrng, m_qrngDimensions);
if (curandResult != CURAND_STATUS_SUCCESS) {
std::string msg("Could not set quasi-random number generator dimensions: ");
msg += curandResult;
throw runtime_error(msg);
}
curandResult = curandSetGeneratorOffset(m_qrng, 0);
if (curandResult != CURAND_STATUS_SUCCESS) {
std::string msg("Could not set quasi-random number generator offset: ");
msg += curandResult;
throw runtime_error(msg);
}
curandResult =
curandSetQuasiRandomGeneratorDimensions(m_sqrng, m_qrngDimensions);
if (curandResult != CURAND_STATUS_SUCCESS) {
std::string msg(
"Could not set scrambled quasi-random number generator dimensions: ");
msg += curandResult;
throw runtime_error(msg);
}
curandResult = curandSetGeneratorOffset(m_sqrng, 0);
if (curandResult != CURAND_STATUS_SUCCESS) {
std::string msg(
"Could not set scrambled quasi-random number generator offset: ");
msg += curandResult;
throw runtime_error(msg);
}
updateDimensions();
setBatchSize();
}
void RNG::setBatchSize(void) {
if (m_pCurrent == &m_prng) {
m_nSamplesBatchActual = m_nSamplesBatchTarget;
} else {
m_nSamplesBatchActual =
(m_nSamplesBatchTarget / m_qrngDimensions) * m_qrngDimensions;
}
void RNG::updateDimensions(void)
{
using std::runtime_error;
m_nSamplesRemaining = 0;
curandStatus_t curandResult;
curandResult = curandSetQuasiRandomGeneratorDimensions(m_qrng, m_qrngDimensions);
if (curandResult != CURAND_STATUS_SUCCESS) {
std::string msg("Could not set quasi-random number generator dimensions: ");
msg += curandResult;
throw runtime_error(msg);
}
curandResult = curandSetGeneratorOffset(m_qrng, 0);
if (curandResult != CURAND_STATUS_SUCCESS) {
std::string msg("Could not set quasi-random number generator offset: ");
msg += curandResult;
throw runtime_error(msg);
}
curandResult = curandSetQuasiRandomGeneratorDimensions(m_sqrng, m_qrngDimensions);
if (curandResult != CURAND_STATUS_SUCCESS) {
std::string msg("Could not set scrambled quasi-random number generator dimensions: ");
msg += curandResult;
throw runtime_error(msg);
}
curandResult = curandSetGeneratorOffset(m_sqrng, 0);
if (curandResult != CURAND_STATUS_SUCCESS) {
std::string msg("Could not set scrambled quasi-random number generator offset: ");
msg += curandResult;
throw runtime_error(msg);
}
}
void RNG::setBatchSize(void)
{
if (m_pCurrent == &m_prng) {
m_nSamplesBatchActual = m_nSamplesBatchTarget;
}
else {
m_nSamplesBatchActual = (m_nSamplesBatchTarget / m_qrngDimensions) * m_qrngDimensions;
}
m_nSamplesRemaining = 0;
}

View File

@@ -31,42 +31,42 @@
// RNGs
class RNG
{
public:
enum RngType {Pseudo, Quasi, ScrambledQuasi};
RNG(unsigned long prngSeed, unsigned int qrngDimensions, unsigned int nSamples);
virtual ~RNG();
public:
enum RngType { Pseudo, Quasi, ScrambledQuasi };
RNG(unsigned long prngSeed, unsigned int qrngDimensions, unsigned int nSamples);
virtual ~RNG();
float getNextU01(void);
void getInfoString(std::string &msg);
void selectRng(RngType type);
void resetSeed(void);
void resetDimensions(void);
void incrementDimensions(void);
float getNextU01(void);
void getInfoString(std::string &msg);
void selectRng(RngType type);
void resetSeed(void);
void resetDimensions(void);
void incrementDimensions(void);
private:
// Generators
curandGenerator_t *m_pCurrent;
curandGenerator_t m_prng;
curandGenerator_t m_qrng;
curandGenerator_t m_sqrng;
private:
// Generators
curandGenerator_t *m_pCurrent;
curandGenerator_t m_prng;
curandGenerator_t m_qrng;
curandGenerator_t m_sqrng;
// Parameters
unsigned long m_prngSeed;
unsigned int m_qrngDimensions;
// Parameters
unsigned long m_prngSeed;
unsigned int m_qrngDimensions;
// Batches
const unsigned int m_nSamplesBatchTarget;
unsigned int m_nSamplesBatchActual;
unsigned int m_nSamplesRemaining;
void generateBatch(void);
// Batches
const unsigned int m_nSamplesBatchTarget;
unsigned int m_nSamplesBatchActual;
unsigned int m_nSamplesRemaining;
void generateBatch(void);
// Helpers
void updateDimensions(void);
void setBatchSize(void);
// Helpers
void updateDimensions(void);
void setBatchSize(void);
// Buffers
float *m_h_samples;
float *m_d_samples;
// Buffers
float *m_h_samples;
float *m_d_samples;
static const unsigned int s_maxQrngDimensions;
static const unsigned int s_maxQrngDimensions;
};

View File

@@ -45,211 +45,209 @@
#define N (275)
/* Host implementation of a simple version of sgemm */
static void simple_sgemm(int n, float alpha, const float *A, const float *B,
float beta, float *C) {
int i;
int j;
int k;
static void simple_sgemm(int n, float alpha, const float *A, const float *B, float beta, float *C)
{
int i;
int j;
int k;
for (i = 0; i < n; ++i) {
for (j = 0; j < n; ++j) {
float prod = 0;
for (i = 0; i < n; ++i) {
for (j = 0; j < n; ++j) {
float prod = 0;
for (k = 0; k < n; ++k) {
prod += A[k * n + i] * B[j * n + k];
}
for (k = 0; k < n; ++k) {
prod += A[k * n + i] * B[j * n + k];
}
C[j * n + i] = alpha * prod + beta * C[j * n + i];
C[j * n + i] = alpha * prod + beta * C[j * n + i];
}
}
}
}
/* Main */
int main(int argc, char **argv) {
cublasStatus_t status;
float *h_A;
float *h_B;
float *h_C;
float *h_C_ref;
float *d_A = 0;
float *d_B = 0;
float *d_C = 0;
float alpha = 1.0f;
float beta = 0.0f;
int n2 = N * N;
int i;
float error_norm;
float ref_norm;
float diff;
cublasHandle_t handle;
int main(int argc, char **argv)
{
cublasStatus_t status;
float *h_A;
float *h_B;
float *h_C;
float *h_C_ref;
float *d_A = 0;
float *d_B = 0;
float *d_C = 0;
float alpha = 1.0f;
float beta = 0.0f;
int n2 = N * N;
int i;
float error_norm;
float ref_norm;
float diff;
cublasHandle_t handle;
int dev = findCudaDevice(argc, (const char **)argv);
int dev = findCudaDevice(argc, (const char **)argv);
if (dev == -1) {
return EXIT_FAILURE;
}
if (dev == -1) {
return EXIT_FAILURE;
}
/* Initialize CUBLAS */
printf("simpleCUBLAS test running..\n");
/* Initialize CUBLAS */
printf("simpleCUBLAS test running..\n");
status = cublasCreate(&handle);
status = cublasCreate(&handle);
if (status != CUBLAS_STATUS_SUCCESS) {
fprintf(stderr, "!!!! CUBLAS initialization error\n");
return EXIT_FAILURE;
}
if (status != CUBLAS_STATUS_SUCCESS) {
fprintf(stderr, "!!!! CUBLAS initialization error\n");
return EXIT_FAILURE;
}
/* Allocate host memory for the matrices */
h_A = reinterpret_cast<float *>(malloc(n2 * sizeof(h_A[0])));
/* Allocate host memory for the matrices */
h_A = reinterpret_cast<float *>(malloc(n2 * sizeof(h_A[0])));
if (h_A == 0) {
fprintf(stderr, "!!!! host memory allocation error (A)\n");
return EXIT_FAILURE;
}
if (h_A == 0) {
fprintf(stderr, "!!!! host memory allocation error (A)\n");
return EXIT_FAILURE;
}
h_B = reinterpret_cast<float *>(malloc(n2 * sizeof(h_B[0])));
h_B = reinterpret_cast<float *>(malloc(n2 * sizeof(h_B[0])));
if (h_B == 0) {
fprintf(stderr, "!!!! host memory allocation error (B)\n");
return EXIT_FAILURE;
}
if (h_B == 0) {
fprintf(stderr, "!!!! host memory allocation error (B)\n");
return EXIT_FAILURE;
}
h_C = reinterpret_cast<float *>(malloc(n2 * sizeof(h_C[0])));
h_C = reinterpret_cast<float *>(malloc(n2 * sizeof(h_C[0])));
if (h_C == 0) {
fprintf(stderr, "!!!! host memory allocation error (C)\n");
return EXIT_FAILURE;
}
if (h_C == 0) {
fprintf(stderr, "!!!! host memory allocation error (C)\n");
return EXIT_FAILURE;
}
/* Fill the matrices with test data */
for (i = 0; i < n2; i++) {
h_A[i] = rand() / static_cast<float>(RAND_MAX);
h_B[i] = rand() / static_cast<float>(RAND_MAX);
h_C[i] = rand() / static_cast<float>(RAND_MAX);
}
/* Fill the matrices with test data */
for (i = 0; i < n2; i++) {
h_A[i] = rand() / static_cast<float>(RAND_MAX);
h_B[i] = rand() / static_cast<float>(RAND_MAX);
h_C[i] = rand() / static_cast<float>(RAND_MAX);
}
/* Allocate device memory for the matrices */
if (cudaMalloc(reinterpret_cast<void **>(&d_A), n2 * sizeof(d_A[0])) !=
cudaSuccess) {
fprintf(stderr, "!!!! device memory allocation error (allocate A)\n");
return EXIT_FAILURE;
}
/* Allocate device memory for the matrices */
if (cudaMalloc(reinterpret_cast<void **>(&d_A), n2 * sizeof(d_A[0])) != cudaSuccess) {
fprintf(stderr, "!!!! device memory allocation error (allocate A)\n");
return EXIT_FAILURE;
}
if (cudaMalloc(reinterpret_cast<void **>(&d_B), n2 * sizeof(d_B[0])) !=
cudaSuccess) {
fprintf(stderr, "!!!! device memory allocation error (allocate B)\n");
return EXIT_FAILURE;
}
if (cudaMalloc(reinterpret_cast<void **>(&d_B), n2 * sizeof(d_B[0])) != cudaSuccess) {
fprintf(stderr, "!!!! device memory allocation error (allocate B)\n");
return EXIT_FAILURE;
}
if (cudaMalloc(reinterpret_cast<void **>(&d_C), n2 * sizeof(d_C[0])) !=
cudaSuccess) {
fprintf(stderr, "!!!! device memory allocation error (allocate C)\n");
return EXIT_FAILURE;
}
if (cudaMalloc(reinterpret_cast<void **>(&d_C), n2 * sizeof(d_C[0])) != cudaSuccess) {
fprintf(stderr, "!!!! device memory allocation error (allocate C)\n");
return EXIT_FAILURE;
}
/* Initialize the device matrices with the host matrices */
status = cublasSetVector(n2, sizeof(h_A[0]), h_A, 1, d_A, 1);
/* Initialize the device matrices with the host matrices */
status = cublasSetVector(n2, sizeof(h_A[0]), h_A, 1, d_A, 1);
if (status != CUBLAS_STATUS_SUCCESS) {
fprintf(stderr, "!!!! device access error (write A)\n");
return EXIT_FAILURE;
}
if (status != CUBLAS_STATUS_SUCCESS) {
fprintf(stderr, "!!!! device access error (write A)\n");
return EXIT_FAILURE;
}
status = cublasSetVector(n2, sizeof(h_B[0]), h_B, 1, d_B, 1);
status = cublasSetVector(n2, sizeof(h_B[0]), h_B, 1, d_B, 1);
if (status != CUBLAS_STATUS_SUCCESS) {
fprintf(stderr, "!!!! device access error (write B)\n");
return EXIT_FAILURE;
}
if (status != CUBLAS_STATUS_SUCCESS) {
fprintf(stderr, "!!!! device access error (write B)\n");
return EXIT_FAILURE;
}
status = cublasSetVector(n2, sizeof(h_C[0]), h_C, 1, d_C, 1);
status = cublasSetVector(n2, sizeof(h_C[0]), h_C, 1, d_C, 1);
if (status != CUBLAS_STATUS_SUCCESS) {
fprintf(stderr, "!!!! device access error (write C)\n");
return EXIT_FAILURE;
}
if (status != CUBLAS_STATUS_SUCCESS) {
fprintf(stderr, "!!!! device access error (write C)\n");
return EXIT_FAILURE;
}
/* Performs operation using plain C code */
simple_sgemm(N, alpha, h_A, h_B, beta, h_C);
h_C_ref = h_C;
/* Performs operation using plain C code */
simple_sgemm(N, alpha, h_A, h_B, beta, h_C);
h_C_ref = h_C;
/* Performs operation using cublas */
status = cublasSgemm(handle, CUBLAS_OP_N, CUBLAS_OP_N, N, N, N, &alpha, d_A,
N, d_B, N, &beta, d_C, N);
/* Performs operation using cublas */
status = cublasSgemm(handle, CUBLAS_OP_N, CUBLAS_OP_N, N, N, N, &alpha, d_A, N, d_B, N, &beta, d_C, N);
if (status != CUBLAS_STATUS_SUCCESS) {
fprintf(stderr, "!!!! kernel execution error.\n");
return EXIT_FAILURE;
}
if (status != CUBLAS_STATUS_SUCCESS) {
fprintf(stderr, "!!!! kernel execution error.\n");
return EXIT_FAILURE;
}
/* Allocate host memory for reading back the result from device memory */
h_C = reinterpret_cast<float *>(malloc(n2 * sizeof(h_C[0])));
/* Allocate host memory for reading back the result from device memory */
h_C = reinterpret_cast<float *>(malloc(n2 * sizeof(h_C[0])));
if (h_C == 0) {
fprintf(stderr, "!!!! host memory allocation error (C)\n");
return EXIT_FAILURE;
}
if (h_C == 0) {
fprintf(stderr, "!!!! host memory allocation error (C)\n");
return EXIT_FAILURE;
}
/* Read the result back */
status = cublasGetVector(n2, sizeof(h_C[0]), d_C, 1, h_C, 1);
/* Read the result back */
status = cublasGetVector(n2, sizeof(h_C[0]), d_C, 1, h_C, 1);
if (status != CUBLAS_STATUS_SUCCESS) {
fprintf(stderr, "!!!! device access error (read C)\n");
return EXIT_FAILURE;
}
if (status != CUBLAS_STATUS_SUCCESS) {
fprintf(stderr, "!!!! device access error (read C)\n");
return EXIT_FAILURE;
}
/* Check result against reference */
error_norm = 0;
ref_norm = 0;
/* Check result against reference */
error_norm = 0;
ref_norm = 0;
for (i = 0; i < n2; ++i) {
diff = h_C_ref[i] - h_C[i];
error_norm += diff * diff;
ref_norm += h_C_ref[i] * h_C_ref[i];
}
for (i = 0; i < n2; ++i) {
diff = h_C_ref[i] - h_C[i];
error_norm += diff * diff;
ref_norm += h_C_ref[i] * h_C_ref[i];
}
error_norm = static_cast<float>(sqrt(static_cast<double>(error_norm)));
ref_norm = static_cast<float>(sqrt(static_cast<double>(ref_norm)));
error_norm = static_cast<float>(sqrt(static_cast<double>(error_norm)));
ref_norm = static_cast<float>(sqrt(static_cast<double>(ref_norm)));
if (fabs(ref_norm) < 1e-7) {
fprintf(stderr, "!!!! reference norm is 0\n");
return EXIT_FAILURE;
}
if (fabs(ref_norm) < 1e-7) {
fprintf(stderr, "!!!! reference norm is 0\n");
return EXIT_FAILURE;
}
/* Memory clean up */
free(h_A);
free(h_B);
free(h_C);
free(h_C_ref);
/* Memory clean up */
free(h_A);
free(h_B);
free(h_C);
free(h_C_ref);
if (cudaFree(d_A) != cudaSuccess) {
fprintf(stderr, "!!!! memory free error (A)\n");
return EXIT_FAILURE;
}
if (cudaFree(d_A) != cudaSuccess) {
fprintf(stderr, "!!!! memory free error (A)\n");
return EXIT_FAILURE;
}
if (cudaFree(d_B) != cudaSuccess) {
fprintf(stderr, "!!!! memory free error (B)\n");
return EXIT_FAILURE;
}
if (cudaFree(d_B) != cudaSuccess) {
fprintf(stderr, "!!!! memory free error (B)\n");
return EXIT_FAILURE;
}
if (cudaFree(d_C) != cudaSuccess) {
fprintf(stderr, "!!!! memory free error (C)\n");
return EXIT_FAILURE;
}
if (cudaFree(d_C) != cudaSuccess) {
fprintf(stderr, "!!!! memory free error (C)\n");
return EXIT_FAILURE;
}
/* Shutdown */
status = cublasDestroy(handle);
/* Shutdown */
status = cublasDestroy(handle);
if (status != CUBLAS_STATUS_SUCCESS) {
fprintf(stderr, "!!!! shutdown error (A)\n");
return EXIT_FAILURE;
}
if (status != CUBLAS_STATUS_SUCCESS) {
fprintf(stderr, "!!!! shutdown error (A)\n");
return EXIT_FAILURE;
}
if (error_norm / ref_norm < 1e-6f) {
printf("simpleCUBLAS test passed.\n");
exit(EXIT_SUCCESS);
} else {
printf("simpleCUBLAS test failed.\n");
exit(EXIT_FAILURE);
}
if (error_norm / ref_norm < 1e-6f) {
printf("simpleCUBLAS test passed.\n");
exit(EXIT_SUCCESS);
}
else {
printf("simpleCUBLAS test failed.\n");
exit(EXIT_FAILURE);
}
}

View File

@@ -42,260 +42,263 @@
#include <helper_cuda.h>
/* Matrix size */
//#define N (275)
// #define N (275)
#define N (1024)
// Restricting the max used GPUs as input matrix is not so large
#define MAX_NUM_OF_GPUS 2
/* Host implementation of a simple version of sgemm */
static void simple_sgemm(int n, float alpha, const float *A, const float *B,
float beta, float *C) {
int i;
int j;
int k;
static void simple_sgemm(int n, float alpha, const float *A, const float *B, float beta, float *C)
{
int i;
int j;
int k;
for (i = 0; i < n; ++i) {
for (j = 0; j < n; ++j) {
float prod = 0;
for (i = 0; i < n; ++i) {
for (j = 0; j < n; ++j) {
float prod = 0;
for (k = 0; k < n; ++k) {
prod += A[k * n + i] * B[j * n + k];
}
for (k = 0; k < n; ++k) {
prod += A[k * n + i] * B[j * n + k];
}
C[j * n + i] = alpha * prod + beta * C[j * n + i];
C[j * n + i] = alpha * prod + beta * C[j * n + i];
}
}
}
}
void findMultipleBestGPUs(int &num_of_devices, int *device_ids) {
// Find the best CUDA capable GPU device
int current_device = 0;
void findMultipleBestGPUs(int &num_of_devices, int *device_ids)
{
// Find the best CUDA capable GPU device
int current_device = 0;
int device_count;
checkCudaErrors(cudaGetDeviceCount(&device_count));
typedef struct gpu_perf_t {
uint64_t compute_perf;
int device_id;
} gpu_perf;
int device_count;
checkCudaErrors(cudaGetDeviceCount(&device_count));
typedef struct gpu_perf_t
{
uint64_t compute_perf;
int device_id;
} gpu_perf;
gpu_perf *gpu_stats = (gpu_perf *)malloc(sizeof(gpu_perf) * device_count);
gpu_perf *gpu_stats = (gpu_perf *)malloc(sizeof(gpu_perf) * device_count);
cudaDeviceProp deviceProp;
int devices_prohibited = 0;
while (current_device < device_count) {
cudaGetDeviceProperties(&deviceProp, current_device);
cudaDeviceProp deviceProp;
int devices_prohibited = 0;
while (current_device < device_count) {
cudaGetDeviceProperties(&deviceProp, current_device);
// If this GPU is not running on Compute Mode prohibited,
// then we can add it to the list
int sm_per_multiproc;
if (deviceProp.computeMode != cudaComputeModeProhibited) {
if (deviceProp.major == 9999 && deviceProp.minor == 9999) {
sm_per_multiproc = 1;
} else {
sm_per_multiproc =
_ConvertSMVer2Cores(deviceProp.major, deviceProp.minor);
}
// If this GPU is not running on Compute Mode prohibited,
// then we can add it to the list
int sm_per_multiproc;
if (deviceProp.computeMode != cudaComputeModeProhibited) {
if (deviceProp.major == 9999 && deviceProp.minor == 9999) {
sm_per_multiproc = 1;
}
else {
sm_per_multiproc = _ConvertSMVer2Cores(deviceProp.major, deviceProp.minor);
}
gpu_stats[current_device].compute_perf =
(uint64_t)deviceProp.multiProcessorCount * sm_per_multiproc *
deviceProp.clockRate;
gpu_stats[current_device].device_id = current_device;
} else {
devices_prohibited++;
}
++current_device;
}
if (devices_prohibited == device_count) {
fprintf(stderr,
"gpuGetMaxGflopsDeviceId() CUDA error:"
" all devices have compute mode prohibited.\n");
exit(EXIT_FAILURE);
} else {
gpu_perf temp_elem;
// Sort the GPUs by highest compute perf.
for (int i = 0; i < current_device - 1; i++) {
for (int j = 0; j < current_device - i - 1; j++) {
if (gpu_stats[j].compute_perf < gpu_stats[j + 1].compute_perf) {
temp_elem = gpu_stats[j];
gpu_stats[j] = gpu_stats[j + 1];
gpu_stats[j + 1] = temp_elem;
gpu_stats[current_device].compute_perf =
(uint64_t)deviceProp.multiProcessorCount * sm_per_multiproc * deviceProp.clockRate;
gpu_stats[current_device].device_id = current_device;
}
else {
devices_prohibited++;
}
}
}
for (int i = 0; i < num_of_devices; i++) {
device_ids[i] = gpu_stats[i].device_id;
++current_device;
}
}
free(gpu_stats);
if (devices_prohibited == device_count) {
fprintf(stderr,
"gpuGetMaxGflopsDeviceId() CUDA error:"
" all devices have compute mode prohibited.\n");
exit(EXIT_FAILURE);
}
else {
gpu_perf temp_elem;
// Sort the GPUs by highest compute perf.
for (int i = 0; i < current_device - 1; i++) {
for (int j = 0; j < current_device - i - 1; j++) {
if (gpu_stats[j].compute_perf < gpu_stats[j + 1].compute_perf) {
temp_elem = gpu_stats[j];
gpu_stats[j] = gpu_stats[j + 1];
gpu_stats[j + 1] = temp_elem;
}
}
}
for (int i = 0; i < num_of_devices; i++) {
device_ids[i] = gpu_stats[i].device_id;
}
}
free(gpu_stats);
}
/* Main */
int main(int argc, char **argv) {
cublasStatus_t status;
float *h_A;
float *h_B;
float *h_C;
float *h_C_ref;
float *d_A = 0;
float *d_B = 0;
float *d_C = 0;
float alpha = 1.0f;
float beta = 0.0f;
int n2 = N * N;
int i;
float error_norm;
float ref_norm;
float diff;
cublasXtHandle_t handle;
int *devices = NULL;
int main(int argc, char **argv)
{
cublasStatus_t status;
float *h_A;
float *h_B;
float *h_C;
float *h_C_ref;
float *d_A = 0;
float *d_B = 0;
float *d_C = 0;
float alpha = 1.0f;
float beta = 0.0f;
int n2 = N * N;
int i;
float error_norm;
float ref_norm;
float diff;
cublasXtHandle_t handle;
int *devices = NULL;
int num_of_devices = 0;
int num_of_devices = 0;
checkCudaErrors(cudaGetDeviceCount(&num_of_devices));
checkCudaErrors(cudaGetDeviceCount(&num_of_devices));
if (num_of_devices > MAX_NUM_OF_GPUS) {
num_of_devices = MAX_NUM_OF_GPUS;
}
devices = (int *)malloc(sizeof(int) * num_of_devices);
if (num_of_devices > MAX_NUM_OF_GPUS) {
num_of_devices = MAX_NUM_OF_GPUS;
}
devices = (int *)malloc(sizeof(int) * num_of_devices);
findMultipleBestGPUs(num_of_devices, devices);
cudaDeviceProp deviceProp;
printf("Using %d GPUs\n", num_of_devices);
for (i = 0; i < num_of_devices; i++) {
checkCudaErrors(cudaGetDeviceProperties(&deviceProp, devices[i]));
printf("GPU ID = %d, Name = %s \n", devices[i], deviceProp.name);
}
findMultipleBestGPUs(num_of_devices, devices);
cudaDeviceProp deviceProp;
printf("Using %d GPUs\n", num_of_devices);
for (i = 0; i < num_of_devices; i++) {
checkCudaErrors(cudaGetDeviceProperties(&deviceProp, devices[i]));
printf("GPU ID = %d, Name = %s \n", devices[i], deviceProp.name);
}
/* Initialize CUBLAS */
printf("simpleCUBLASXT test running..\n");
/* Initialize CUBLAS */
printf("simpleCUBLASXT test running..\n");
status = cublasXtCreate(&handle);
status = cublasXtCreate(&handle);
if (status != CUBLAS_STATUS_SUCCESS) {
fprintf(stderr, "!!!! CUBLASXT initialization error\n");
return EXIT_FAILURE;
}
if (status != CUBLAS_STATUS_SUCCESS) {
fprintf(stderr, "!!!! CUBLASXT initialization error\n");
return EXIT_FAILURE;
}
/* Select devices for use in CUBLASXT math functions */
status = cublasXtDeviceSelect(handle, num_of_devices, devices);
/* Select devices for use in CUBLASXT math functions */
status = cublasXtDeviceSelect(handle, num_of_devices, devices);
if (status != CUBLAS_STATUS_SUCCESS) {
fprintf(stderr, "!!!! CUBLASXT device selection error\n");
return EXIT_FAILURE;
}
if (status != CUBLAS_STATUS_SUCCESS) {
fprintf(stderr, "!!!! CUBLASXT device selection error\n");
return EXIT_FAILURE;
}
/* Optional: Set a block size for CUBLASXT math functions */
status = cublasXtSetBlockDim(handle, 64);
/* Optional: Set a block size for CUBLASXT math functions */
status = cublasXtSetBlockDim(handle, 64);
if (status != CUBLAS_STATUS_SUCCESS) {
fprintf(stderr, "!!!! CUBLASXT set block dimension error\n");
return EXIT_FAILURE;
}
if (status != CUBLAS_STATUS_SUCCESS) {
fprintf(stderr, "!!!! CUBLASXT set block dimension error\n");
return EXIT_FAILURE;
}
/* Allocate host memory for the matrices */
h_A = (float *)malloc(n2 * sizeof(h_A[0]));
/* Allocate host memory for the matrices */
h_A = (float *)malloc(n2 * sizeof(h_A[0]));
if (h_A == 0) {
fprintf(stderr, "!!!! host memory allocation error (A)\n");
return EXIT_FAILURE;
}
if (h_A == 0) {
fprintf(stderr, "!!!! host memory allocation error (A)\n");
return EXIT_FAILURE;
}
h_B = (float *)malloc(n2 * sizeof(h_B[0]));
h_B = (float *)malloc(n2 * sizeof(h_B[0]));
if (h_B == 0) {
fprintf(stderr, "!!!! host memory allocation error (B)\n");
return EXIT_FAILURE;
}
if (h_B == 0) {
fprintf(stderr, "!!!! host memory allocation error (B)\n");
return EXIT_FAILURE;
}
h_C_ref = (float *)malloc(n2 * sizeof(h_C[0]));
h_C_ref = (float *)malloc(n2 * sizeof(h_C[0]));
if (h_C_ref == 0) {
fprintf(stderr, "!!!! host memory allocation error (C_ref)\n");
return EXIT_FAILURE;
}
if (h_C_ref == 0) {
fprintf(stderr, "!!!! host memory allocation error (C_ref)\n");
return EXIT_FAILURE;
}
h_C = (float *)malloc(n2 * sizeof(h_C[0]));
h_C = (float *)malloc(n2 * sizeof(h_C[0]));
if (h_C == 0) {
fprintf(stderr, "!!!! host memory allocation error (C)\n");
return EXIT_FAILURE;
}
if (h_C == 0) {
fprintf(stderr, "!!!! host memory allocation error (C)\n");
return EXIT_FAILURE;
}
/* Fill the matrices with test data */
for (i = 0; i < n2; i++) {
h_A[i] = rand() / (float)RAND_MAX;
h_B[i] = rand() / (float)RAND_MAX;
h_C[i] = rand() / (float)RAND_MAX;
h_C_ref[i] = h_C[i];
}
/* Fill the matrices with test data */
for (i = 0; i < n2; i++) {
h_A[i] = rand() / (float)RAND_MAX;
h_B[i] = rand() / (float)RAND_MAX;
h_C[i] = rand() / (float)RAND_MAX;
h_C_ref[i] = h_C[i];
}
/* Performs operation using plain C code */
simple_sgemm(N, alpha, h_A, h_B, beta, h_C_ref);
/* Performs operation using plain C code */
simple_sgemm(N, alpha, h_A, h_B, beta, h_C_ref);
/* Performs operation using cublas */
status = cublasXtSgemm(handle, CUBLAS_OP_N, CUBLAS_OP_N, N, N, N, &alpha, h_A,
N, h_B, N, &beta, h_C, N);
/* Performs operation using cublas */
status = cublasXtSgemm(handle, CUBLAS_OP_N, CUBLAS_OP_N, N, N, N, &alpha, h_A, N, h_B, N, &beta, h_C, N);
if (status != CUBLAS_STATUS_SUCCESS) {
fprintf(stderr, "!!!! kernel execution error.\n");
return EXIT_FAILURE;
}
if (status != CUBLAS_STATUS_SUCCESS) {
fprintf(stderr, "!!!! kernel execution error.\n");
return EXIT_FAILURE;
}
/* Check result against reference */
error_norm = 0;
ref_norm = 0;
/* Check result against reference */
error_norm = 0;
ref_norm = 0;
for (i = 0; i < n2; ++i) {
diff = h_C_ref[i] - h_C[i];
error_norm += diff * diff;
ref_norm += h_C_ref[i] * h_C_ref[i];
}
for (i = 0; i < n2; ++i) {
diff = h_C_ref[i] - h_C[i];
error_norm += diff * diff;
ref_norm += h_C_ref[i] * h_C_ref[i];
}
error_norm = (float)sqrt((double)error_norm);
ref_norm = (float)sqrt((double)ref_norm);
error_norm = (float)sqrt((double)error_norm);
ref_norm = (float)sqrt((double)ref_norm);
if (fabs(ref_norm) < 1e-7) {
fprintf(stderr, "!!!! reference norm is 0\n");
return EXIT_FAILURE;
}
if (fabs(ref_norm) < 1e-7) {
fprintf(stderr, "!!!! reference norm is 0\n");
return EXIT_FAILURE;
}
/* Memory clean up */
free(h_A);
free(h_B);
free(h_C);
free(h_C_ref);
/* Memory clean up */
free(h_A);
free(h_B);
free(h_C);
free(h_C_ref);
if (cudaFree(d_A) != cudaSuccess) {
fprintf(stderr, "!!!! memory free error (A)\n");
return EXIT_FAILURE;
}
if (cudaFree(d_A) != cudaSuccess) {
fprintf(stderr, "!!!! memory free error (A)\n");
return EXIT_FAILURE;
}
if (cudaFree(d_B) != cudaSuccess) {
fprintf(stderr, "!!!! memory free error (B)\n");
return EXIT_FAILURE;
}
if (cudaFree(d_B) != cudaSuccess) {
fprintf(stderr, "!!!! memory free error (B)\n");
return EXIT_FAILURE;
}
if (cudaFree(d_C) != cudaSuccess) {
fprintf(stderr, "!!!! memory free error (C)\n");
return EXIT_FAILURE;
}
if (cudaFree(d_C) != cudaSuccess) {
fprintf(stderr, "!!!! memory free error (C)\n");
return EXIT_FAILURE;
}
/* Shutdown */
status = cublasXtDestroy(handle);
/* Shutdown */
status = cublasXtDestroy(handle);
if (status != CUBLAS_STATUS_SUCCESS) {
fprintf(stderr, "!!!! shutdown error (A)\n");
return EXIT_FAILURE;
}
if (status != CUBLAS_STATUS_SUCCESS) {
fprintf(stderr, "!!!! shutdown error (A)\n");
return EXIT_FAILURE;
}
if (error_norm / ref_norm < 1e-6f) {
printf("simpleCUBLASXT test passed.\n");
exit(EXIT_SUCCESS);
} else {
printf("simpleCUBLASXT test failed.\n");
exit(EXIT_FAILURE);
}
if (error_norm / ref_norm < 1e-6f) {
printf("simpleCUBLASXT test passed.\n");
exit(EXIT_SUCCESS);
}
else {
printf("simpleCUBLASXT test failed.\n");
exit(EXIT_FAILURE);
}
}

View File

@@ -51,7 +51,7 @@
// configurable parameters
// dimension of matrix
#define N 4
#define N 4
#define BATCH_SIZE 10000
// use double precision data type
@@ -70,348 +70,349 @@
// helper functions
// wrapper around cublas<t>getrfBatched()
cublasStatus_t cublasXgetrfBatched(cublasHandle_t handle, int n,
DATA_TYPE* const A[], int lda, int* P,
int* info, int batchSize) {
cublasStatus_t
cublasXgetrfBatched(cublasHandle_t handle, int n, DATA_TYPE *const A[], int lda, int *P, int *info, int batchSize)
{
#ifdef DOUBLE_PRECISION
return cublasDgetrfBatched(handle, n, A, lda, P, info, batchSize);
return cublasDgetrfBatched(handle, n, A, lda, P, info, batchSize);
#else
return cublasSgetrfBatched(handle, n, A, lda, P, info, batchSize);
return cublasSgetrfBatched(handle, n, A, lda, P, info, batchSize);
#endif
}
// wrapper around malloc
// clears the allocated memory to 0
// terminates the program if malloc fails
void* xmalloc(size_t size) {
void* ptr = malloc(size);
if (ptr == NULL) {
printf("> ERROR: malloc for size %zu failed..\n", size);
exit(EXIT_FAILURE);
}
memset(ptr, 0, size);
return ptr;
void *xmalloc(size_t size)
{
void *ptr = malloc(size);
if (ptr == NULL) {
printf("> ERROR: malloc for size %zu failed..\n", size);
exit(EXIT_FAILURE);
}
memset(ptr, 0, size);
return ptr;
}
// initalize identity matrix
void initIdentityMatrix(DATA_TYPE* mat) {
// clear the matrix
memset(mat, 0, N * N * sizeof(DATA_TYPE));
void initIdentityMatrix(DATA_TYPE *mat)
{
// clear the matrix
memset(mat, 0, N * N * sizeof(DATA_TYPE));
// set all diagonals to 1
for (int i = 0; i < N; i++) {
mat[(i * N) + i] = 1.0;
}
// set all diagonals to 1
for (int i = 0; i < N; i++) {
mat[(i * N) + i] = 1.0;
}
}
// initialize matrix with all elements as 0
void initZeroMatrix(DATA_TYPE* mat) {
memset(mat, 0, N * N * sizeof(DATA_TYPE));
}
void initZeroMatrix(DATA_TYPE *mat) { memset(mat, 0, N * N * sizeof(DATA_TYPE)); }
// fill random value in column-major matrix
void initRandomMatrix(DATA_TYPE* mat) {
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
mat[(j * N) + i] =
(DATA_TYPE)1.0 + ((DATA_TYPE)rand() / (DATA_TYPE)RAND_MAX);
void initRandomMatrix(DATA_TYPE *mat)
{
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
mat[(j * N) + i] = (DATA_TYPE)1.0 + ((DATA_TYPE)rand() / (DATA_TYPE)RAND_MAX);
}
}
}
// diagonal dominant matrix to insure it is invertible matrix
for (int i = 0; i < N; i++) {
mat[(i * N) + i] += (DATA_TYPE)N;
}
// diagonal dominant matrix to insure it is invertible matrix
for (int i = 0; i < N; i++) {
mat[(i * N) + i] += (DATA_TYPE)N;
}
}
// print column-major matrix
void printMatrix(DATA_TYPE* mat) {
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
printf("%20.16f ", mat[(j * N) + i]);
void printMatrix(DATA_TYPE *mat)
{
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
printf("%20.16f ", mat[(j * N) + i]);
}
printf("\n");
}
printf("\n");
}
printf("\n");
}
// matrix mulitplication
void matrixMultiply(DATA_TYPE* res, DATA_TYPE* mat1, DATA_TYPE* mat2) {
initZeroMatrix(res);
void matrixMultiply(DATA_TYPE *res, DATA_TYPE *mat1, DATA_TYPE *mat2)
{
initZeroMatrix(res);
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
for (int k = 0; k < N; k++) {
res[(j * N) + i] += mat1[(k * N) + i] * mat2[(j * N) + k];
}
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
for (int k = 0; k < N; k++) {
res[(j * N) + i] += mat1[(k * N) + i] * mat2[(j * N) + k];
}
}
}
}
}
// check matrix equality
bool checkRelativeError(DATA_TYPE* mat1, DATA_TYPE* mat2, DATA_TYPE maxError) {
DATA_TYPE err = (DATA_TYPE)0.0;
DATA_TYPE refNorm = (DATA_TYPE)0.0;
DATA_TYPE relError = (DATA_TYPE)0.0;
DATA_TYPE relMaxError = (DATA_TYPE)0.0;
bool checkRelativeError(DATA_TYPE *mat1, DATA_TYPE *mat2, DATA_TYPE maxError)
{
DATA_TYPE err = (DATA_TYPE)0.0;
DATA_TYPE refNorm = (DATA_TYPE)0.0;
DATA_TYPE relError = (DATA_TYPE)0.0;
DATA_TYPE relMaxError = (DATA_TYPE)0.0;
for (int i = 0; i < N * N; i++) {
refNorm = abs(mat1[i]);
err = abs(mat1[i] - mat2[i]);
for (int i = 0; i < N * N; i++) {
refNorm = abs(mat1[i]);
err = abs(mat1[i] - mat2[i]);
if (refNorm != 0.0 && err > 0.0) {
relError = err / refNorm;
relMaxError = MAX(relMaxError, relError);
if (refNorm != 0.0 && err > 0.0) {
relError = err / refNorm;
relMaxError = MAX(relMaxError, relError);
}
if (relMaxError > maxError)
return false;
}
if (relMaxError > maxError) return false;
}
return true;
return true;
}
// decode lower and upper matrix from single matrix
// returned by getrfBatched()
void getLUdecoded(DATA_TYPE* mat, DATA_TYPE* L, DATA_TYPE* U) {
// init L as identity matrix
initIdentityMatrix(L);
void getLUdecoded(DATA_TYPE *mat, DATA_TYPE *L, DATA_TYPE *U)
{
// init L as identity matrix
initIdentityMatrix(L);
// copy lower triangular values from mat to L (skip diagonal)
for (int i = 0; i < N; i++) {
for (int j = 0; j < i; j++) {
L[(j * N) + i] = mat[(j * N) + i];
// copy lower triangular values from mat to L (skip diagonal)
for (int i = 0; i < N; i++) {
for (int j = 0; j < i; j++) {
L[(j * N) + i] = mat[(j * N) + i];
}
}
}
// init U as all zero
initZeroMatrix(U);
// init U as all zero
initZeroMatrix(U);
// copy upper triangular values from mat to U
for (int i = 0; i < N; i++) {
for (int j = i; j < N; j++) {
U[(j * N) + i] = mat[(j * N) + i];
// copy upper triangular values from mat to U
for (int i = 0; i < N; i++) {
for (int j = i; j < N; j++) {
U[(j * N) + i] = mat[(j * N) + i];
}
}
}
}
// generate permutation matrix from pivot vector
void getPmatFromPivot(DATA_TYPE* Pmat, int* P) {
int pivot[N];
void getPmatFromPivot(DATA_TYPE *Pmat, int *P)
{
int pivot[N];
// pivot vector in base-1
// convert it to base-0
for (int i = 0; i < N; i++) {
P[i]--;
}
// pivot vector in base-1
// convert it to base-0
for (int i = 0; i < N; i++) {
P[i]--;
}
// generate permutation vector from pivot
// initialize pivot with identity sequence
for (int k = 0; k < N; k++) {
pivot[k] = k;
}
// generate permutation vector from pivot
// initialize pivot with identity sequence
for (int k = 0; k < N; k++) {
pivot[k] = k;
}
// swap the indices according to pivot vector
for (int k = 0; k < N; k++) {
int q = P[k];
// swap the indices according to pivot vector
for (int k = 0; k < N; k++) {
int q = P[k];
// swap pivot(k) and pivot(q)
int s = pivot[k];
int t = pivot[q];
pivot[k] = t;
pivot[q] = s;
}
// swap pivot(k) and pivot(q)
int s = pivot[k];
int t = pivot[q];
pivot[k] = t;
pivot[q] = s;
}
// generate permutation matrix from pivot vector
initZeroMatrix(Pmat);
for (int i = 0; i < N; i++) {
int j = pivot[i];
Pmat[(j * N) + i] = (DATA_TYPE)1.0;
}
// generate permutation matrix from pivot vector
initZeroMatrix(Pmat);
for (int i = 0; i < N; i++) {
int j = pivot[i];
Pmat[(j * N) + i] = (DATA_TYPE)1.0;
}
}
int main(int argc, char** argv) {
// cuBLAS variables
cublasStatus_t status;
cublasHandle_t handle;
int main(int argc, char **argv)
{
// cuBLAS variables
cublasStatus_t status;
cublasHandle_t handle;
// host variables
size_t matSize = N * N * sizeof(DATA_TYPE);
// host variables
size_t matSize = N * N * sizeof(DATA_TYPE);
DATA_TYPE* h_AarrayInput;
DATA_TYPE* h_AarrayOutput;
DATA_TYPE* h_ptr_array[BATCH_SIZE];
DATA_TYPE *h_AarrayInput;
DATA_TYPE *h_AarrayOutput;
DATA_TYPE *h_ptr_array[BATCH_SIZE];
int* h_pivotArray;
int* h_infoArray;
int *h_pivotArray;
int *h_infoArray;
// device variables
DATA_TYPE* d_Aarray;
DATA_TYPE** d_ptr_array;
// device variables
DATA_TYPE *d_Aarray;
DATA_TYPE **d_ptr_array;
int* d_pivotArray;
int* d_infoArray;
int *d_pivotArray;
int *d_infoArray;
int err_count = 0;
int err_count = 0;
// seed the rand() function with time
srand(12345);
// seed the rand() function with time
srand(12345);
// find cuda device
printf("> initializing..\n");
int dev = findCudaDevice(argc, (const char**)argv);
if (dev == -1) {
return (EXIT_FAILURE);
}
// find cuda device
printf("> initializing..\n");
int dev = findCudaDevice(argc, (const char **)argv);
if (dev == -1) {
return (EXIT_FAILURE);
}
// initialize cuBLAS
status = cublasCreate(&handle);
if (status != CUBLAS_STATUS_SUCCESS) {
printf("> ERROR: cuBLAS initialization failed..\n");
return (EXIT_FAILURE);
}
// initialize cuBLAS
status = cublasCreate(&handle);
if (status != CUBLAS_STATUS_SUCCESS) {
printf("> ERROR: cuBLAS initialization failed..\n");
return (EXIT_FAILURE);
}
#ifdef DOUBLE_PRECISION
printf("> using DOUBLE precision..\n");
printf("> using DOUBLE precision..\n");
#else
printf("> using SINGLE precision..\n");
printf("> using SINGLE precision..\n");
#endif
#ifdef PIVOT
printf("> pivot ENABLED..\n");
printf("> pivot ENABLED..\n");
#else
printf("> pivot DISABLED..\n");
printf("> pivot DISABLED..\n");
#endif
// allocate memory for host variables
h_AarrayInput = (DATA_TYPE*)xmalloc(BATCH_SIZE * matSize);
h_AarrayOutput = (DATA_TYPE*)xmalloc(BATCH_SIZE * matSize);
// allocate memory for host variables
h_AarrayInput = (DATA_TYPE *)xmalloc(BATCH_SIZE * matSize);
h_AarrayOutput = (DATA_TYPE *)xmalloc(BATCH_SIZE * matSize);
h_pivotArray = (int*)xmalloc(N * BATCH_SIZE * sizeof(int));
h_infoArray = (int*)xmalloc(BATCH_SIZE * sizeof(int));
h_pivotArray = (int *)xmalloc(N * BATCH_SIZE * sizeof(int));
h_infoArray = (int *)xmalloc(BATCH_SIZE * sizeof(int));
// allocate memory for device variables
checkCudaErrors(cudaMalloc((void**)&d_Aarray, BATCH_SIZE * matSize));
checkCudaErrors(
cudaMalloc((void**)&d_pivotArray, N * BATCH_SIZE * sizeof(int)));
checkCudaErrors(cudaMalloc((void**)&d_infoArray, BATCH_SIZE * sizeof(int)));
checkCudaErrors(
cudaMalloc((void**)&d_ptr_array, BATCH_SIZE * sizeof(DATA_TYPE*)));
// allocate memory for device variables
checkCudaErrors(cudaMalloc((void **)&d_Aarray, BATCH_SIZE * matSize));
checkCudaErrors(cudaMalloc((void **)&d_pivotArray, N * BATCH_SIZE * sizeof(int)));
checkCudaErrors(cudaMalloc((void **)&d_infoArray, BATCH_SIZE * sizeof(int)));
checkCudaErrors(cudaMalloc((void **)&d_ptr_array, BATCH_SIZE * sizeof(DATA_TYPE *)));
// fill matrix with random data
printf("> generating random matrices..\n");
for (int i = 0; i < BATCH_SIZE; i++) {
initRandomMatrix(h_AarrayInput + (i * N * N));
}
// copy data to device from host
printf("> copying data from host memory to GPU memory..\n");
checkCudaErrors(cudaMemcpy(d_Aarray, h_AarrayInput, BATCH_SIZE * matSize,
cudaMemcpyHostToDevice));
// create pointer array for matrices
for (int i = 0; i < BATCH_SIZE; i++) h_ptr_array[i] = d_Aarray + (i * N * N);
// copy pointer array to device memory
checkCudaErrors(cudaMemcpy(d_ptr_array, h_ptr_array,
BATCH_SIZE * sizeof(DATA_TYPE*),
cudaMemcpyHostToDevice));
// perform LU decomposition
printf("> performing LU decomposition..\n");
#ifdef PIVOT
status = cublasXgetrfBatched(handle, N, d_ptr_array, N, d_pivotArray,
d_infoArray, BATCH_SIZE);
#else
status = cublasXgetrfBatched(handle, N, d_ptr_array, N, NULL, d_infoArray,
BATCH_SIZE);
#endif /* PIVOT */
if (status != CUBLAS_STATUS_SUCCESS) {
printf("> ERROR: cublasDgetrfBatched() failed with error %s..\n",
_cudaGetErrorEnum(status));
return (EXIT_FAILURE);
}
// copy data to host from device
printf("> copying data from GPU memory to host memory..\n");
checkCudaErrors(cudaMemcpy(h_AarrayOutput, d_Aarray, BATCH_SIZE * matSize,
cudaMemcpyDeviceToHost));
checkCudaErrors(cudaMemcpy(h_infoArray, d_infoArray, BATCH_SIZE * sizeof(int),
cudaMemcpyDeviceToHost));
#ifdef PIVOT
checkCudaErrors(cudaMemcpy(h_pivotArray, d_pivotArray,
N * BATCH_SIZE * sizeof(int),
cudaMemcpyDeviceToHost));
#endif /* PIVOT */
// verify the result
printf("> verifying the result..\n");
for (int i = 0; i < BATCH_SIZE; i++) {
if (h_infoArray[i] == 0) {
DATA_TYPE* A = h_AarrayInput + (i * N * N);
DATA_TYPE* LU = h_AarrayOutput + (i * N * N);
DATA_TYPE L[N * N];
DATA_TYPE U[N * N];
getLUdecoded(LU, L, U);
// test P * A = L * U
int* P = h_pivotArray + (i * N);
DATA_TYPE Pmat[N * N];
#ifdef PIVOT
getPmatFromPivot(Pmat, P);
#else
initIdentityMatrix(Pmat);
#endif /* PIVOT */
// perform matrix multiplication
DATA_TYPE PxA[N * N];
DATA_TYPE LxU[N * N];
matrixMultiply(PxA, Pmat, A);
matrixMultiply(LxU, L, U);
// check for equality of matrices
if (!checkRelativeError(PxA, LxU, (DATA_TYPE)MAX_ERROR)) {
printf("> ERROR: accuracy check failed for matrix number %05d..\n",
i + 1);
err_count++;
}
} else if (h_infoArray[i] > 0) {
printf(
"> execution for matrix %05d is successful, but U is singular and "
"U(%d,%d) = 0..\n",
i + 1, h_infoArray[i] - 1, h_infoArray[i] - 1);
} else // (h_infoArray[i] < 0)
{
printf("> ERROR: matrix %05d have an illegal value at index %d = %lf..\n",
i + 1, -h_infoArray[i],
*(h_AarrayInput + (i * N * N) + (-h_infoArray[i])));
// fill matrix with random data
printf("> generating random matrices..\n");
for (int i = 0; i < BATCH_SIZE; i++) {
initRandomMatrix(h_AarrayInput + (i * N * N));
}
}
// free device variables
checkCudaErrors(cudaFree(d_ptr_array));
checkCudaErrors(cudaFree(d_infoArray));
checkCudaErrors(cudaFree(d_pivotArray));
checkCudaErrors(cudaFree(d_Aarray));
// copy data to device from host
printf("> copying data from host memory to GPU memory..\n");
checkCudaErrors(cudaMemcpy(d_Aarray, h_AarrayInput, BATCH_SIZE * matSize, cudaMemcpyHostToDevice));
// free host variables
if (h_infoArray) free(h_infoArray);
if (h_pivotArray) free(h_pivotArray);
if (h_AarrayOutput) free(h_AarrayOutput);
if (h_AarrayInput) free(h_AarrayInput);
// create pointer array for matrices
for (int i = 0; i < BATCH_SIZE; i++)
h_ptr_array[i] = d_Aarray + (i * N * N);
// destroy cuBLAS handle
status = cublasDestroy(handle);
if (status != CUBLAS_STATUS_SUCCESS) {
printf("> ERROR: cuBLAS uninitialization failed..\n");
return (EXIT_FAILURE);
}
// copy pointer array to device memory
checkCudaErrors(cudaMemcpy(d_ptr_array, h_ptr_array, BATCH_SIZE * sizeof(DATA_TYPE *), cudaMemcpyHostToDevice));
if (err_count > 0) {
printf("> TEST FAILED for %d matrices, with precision: %g\n", err_count,
MAX_ERROR);
return (EXIT_FAILURE);
}
// perform LU decomposition
printf("> performing LU decomposition..\n");
#ifdef PIVOT
status = cublasXgetrfBatched(handle, N, d_ptr_array, N, d_pivotArray, d_infoArray, BATCH_SIZE);
#else
status = cublasXgetrfBatched(handle, N, d_ptr_array, N, NULL, d_infoArray, BATCH_SIZE);
#endif /* PIVOT */
if (status != CUBLAS_STATUS_SUCCESS) {
printf("> ERROR: cublasDgetrfBatched() failed with error %s..\n", _cudaGetErrorEnum(status));
return (EXIT_FAILURE);
}
printf("> TEST SUCCESSFUL, with precision: %g\n", MAX_ERROR);
return (EXIT_SUCCESS);
// copy data to host from device
printf("> copying data from GPU memory to host memory..\n");
checkCudaErrors(cudaMemcpy(h_AarrayOutput, d_Aarray, BATCH_SIZE * matSize, cudaMemcpyDeviceToHost));
checkCudaErrors(cudaMemcpy(h_infoArray, d_infoArray, BATCH_SIZE * sizeof(int), cudaMemcpyDeviceToHost));
#ifdef PIVOT
checkCudaErrors(cudaMemcpy(h_pivotArray, d_pivotArray, N * BATCH_SIZE * sizeof(int), cudaMemcpyDeviceToHost));
#endif /* PIVOT */
// verify the result
printf("> verifying the result..\n");
for (int i = 0; i < BATCH_SIZE; i++) {
if (h_infoArray[i] == 0) {
DATA_TYPE *A = h_AarrayInput + (i * N * N);
DATA_TYPE *LU = h_AarrayOutput + (i * N * N);
DATA_TYPE L[N * N];
DATA_TYPE U[N * N];
getLUdecoded(LU, L, U);
// test P * A = L * U
int *P = h_pivotArray + (i * N);
DATA_TYPE Pmat[N * N];
#ifdef PIVOT
getPmatFromPivot(Pmat, P);
#else
initIdentityMatrix(Pmat);
#endif /* PIVOT */
// perform matrix multiplication
DATA_TYPE PxA[N * N];
DATA_TYPE LxU[N * N];
matrixMultiply(PxA, Pmat, A);
matrixMultiply(LxU, L, U);
// check for equality of matrices
if (!checkRelativeError(PxA, LxU, (DATA_TYPE)MAX_ERROR)) {
printf("> ERROR: accuracy check failed for matrix number %05d..\n", i + 1);
err_count++;
}
}
else if (h_infoArray[i] > 0) {
printf("> execution for matrix %05d is successful, but U is singular and "
"U(%d,%d) = 0..\n",
i + 1,
h_infoArray[i] - 1,
h_infoArray[i] - 1);
}
else // (h_infoArray[i] < 0)
{
printf("> ERROR: matrix %05d have an illegal value at index %d = %lf..\n",
i + 1,
-h_infoArray[i],
*(h_AarrayInput + (i * N * N) + (-h_infoArray[i])));
}
}
// free device variables
checkCudaErrors(cudaFree(d_ptr_array));
checkCudaErrors(cudaFree(d_infoArray));
checkCudaErrors(cudaFree(d_pivotArray));
checkCudaErrors(cudaFree(d_Aarray));
// free host variables
if (h_infoArray)
free(h_infoArray);
if (h_pivotArray)
free(h_pivotArray);
if (h_AarrayOutput)
free(h_AarrayOutput);
if (h_AarrayInput)
free(h_AarrayInput);
// destroy cuBLAS handle
status = cublasDestroy(handle);
if (status != CUBLAS_STATUS_SUCCESS) {
printf("> ERROR: cuBLAS uninitialization failed..\n");
return (EXIT_FAILURE);
}
if (err_count > 0) {
printf("> TEST FAILED for %d matrices, with precision: %g\n", err_count, MAX_ERROR);
return (EXIT_FAILURE);
}
printf("> TEST SUCCESSFUL, with precision: %g\n", MAX_ERROR);
return (EXIT_SUCCESS);
}

View File

@@ -41,12 +41,11 @@
#include <helper_functions.h>
// Complex data type
typedef float2 Complex;
typedef float2 Complex;
static __device__ __host__ inline Complex ComplexAdd(Complex, Complex);
static __device__ __host__ inline Complex ComplexScale(Complex, float);
static __device__ __host__ inline Complex ComplexMul(Complex, Complex);
static __global__ void ComplexPointwiseMulAndScale(Complex *, const Complex *,
int, float);
static __global__ void ComplexPointwiseMulAndScale(Complex *, const Complex *, int, float);
// Filtering functions
void Convolve(const Complex *, int, const Complex *, int, Complex *);
@@ -59,7 +58,7 @@ int PadData(const Complex *, Complex **, int, const Complex *, Complex **, int);
void runTest(int argc, char **argv);
// The filter size is assumed to be a number smaller than the signal size
#define SIGNAL_SIZE 50
#define SIGNAL_SIZE 50
#define FILTER_KERNEL_SIZE 11
////////////////////////////////////////////////////////////////////////////////
@@ -70,152 +69,143 @@ int main(int argc, char **argv) { runTest(argc, argv); }
////////////////////////////////////////////////////////////////////////////////
//! Run a simple test for CUDA
////////////////////////////////////////////////////////////////////////////////
void runTest(int argc, char **argv) {
printf("[simpleCUFFT] is starting...\n");
void runTest(int argc, char **argv)
{
printf("[simpleCUFFT] is starting...\n");
findCudaDevice(argc, (const char **)argv);
findCudaDevice(argc, (const char **)argv);
// Allocate host memory for the signal
Complex *h_signal =
reinterpret_cast<Complex *>(malloc(sizeof(Complex) * SIGNAL_SIZE));
// Allocate host memory for the signal
Complex *h_signal = reinterpret_cast<Complex *>(malloc(sizeof(Complex) * SIGNAL_SIZE));
// Initialize the memory for the signal
for (unsigned int i = 0; i < SIGNAL_SIZE; ++i) {
h_signal[i].x = rand() / static_cast<float>(RAND_MAX);
h_signal[i].y = 0;
}
// Initialize the memory for the signal
for (unsigned int i = 0; i < SIGNAL_SIZE; ++i) {
h_signal[i].x = rand() / static_cast<float>(RAND_MAX);
h_signal[i].y = 0;
}
// Allocate host memory for the filter
Complex *h_filter_kernel =
reinterpret_cast<Complex *>(malloc(sizeof(Complex) * FILTER_KERNEL_SIZE));
// Allocate host memory for the filter
Complex *h_filter_kernel = reinterpret_cast<Complex *>(malloc(sizeof(Complex) * FILTER_KERNEL_SIZE));
// Initialize the memory for the filter
for (unsigned int i = 0; i < FILTER_KERNEL_SIZE; ++i) {
h_filter_kernel[i].x = rand() / static_cast<float>(RAND_MAX);
h_filter_kernel[i].y = 0;
}
// Initialize the memory for the filter
for (unsigned int i = 0; i < FILTER_KERNEL_SIZE; ++i) {
h_filter_kernel[i].x = rand() / static_cast<float>(RAND_MAX);
h_filter_kernel[i].y = 0;
}
// Pad signal and filter kernel
Complex *h_padded_signal;
Complex *h_padded_filter_kernel;
int new_size =
PadData(h_signal, &h_padded_signal, SIGNAL_SIZE, h_filter_kernel,
&h_padded_filter_kernel, FILTER_KERNEL_SIZE);
int mem_size = sizeof(Complex) * new_size;
// Pad signal and filter kernel
Complex *h_padded_signal;
Complex *h_padded_filter_kernel;
int new_size =
PadData(h_signal, &h_padded_signal, SIGNAL_SIZE, h_filter_kernel, &h_padded_filter_kernel, FILTER_KERNEL_SIZE);
int mem_size = sizeof(Complex) * new_size;
// Allocate device memory for signal
Complex *d_signal;
checkCudaErrors(cudaMalloc(reinterpret_cast<void **>(&d_signal), mem_size));
// Copy host memory to device
checkCudaErrors(
cudaMemcpy(d_signal, h_padded_signal, mem_size, cudaMemcpyHostToDevice));
// Allocate device memory for signal
Complex *d_signal;
checkCudaErrors(cudaMalloc(reinterpret_cast<void **>(&d_signal), mem_size));
// Copy host memory to device
checkCudaErrors(cudaMemcpy(d_signal, h_padded_signal, mem_size, cudaMemcpyHostToDevice));
// Allocate device memory for filter kernel
Complex *d_filter_kernel;
checkCudaErrors(
cudaMalloc(reinterpret_cast<void **>(&d_filter_kernel), mem_size));
// Allocate device memory for filter kernel
Complex *d_filter_kernel;
checkCudaErrors(cudaMalloc(reinterpret_cast<void **>(&d_filter_kernel), mem_size));
// Copy host memory to device
checkCudaErrors(cudaMemcpy(d_filter_kernel, h_padded_filter_kernel, mem_size,
cudaMemcpyHostToDevice));
// Copy host memory to device
checkCudaErrors(cudaMemcpy(d_filter_kernel, h_padded_filter_kernel, mem_size, cudaMemcpyHostToDevice));
// CUFFT plan simple API
cufftHandle plan;
checkCudaErrors(cufftPlan1d(&plan, new_size, CUFFT_C2C, 1));
// CUFFT plan simple API
cufftHandle plan;
checkCudaErrors(cufftPlan1d(&plan, new_size, CUFFT_C2C, 1));
// CUFFT plan advanced API
cufftHandle plan_adv;
size_t workSize;
long long int new_size_long = new_size;
// CUFFT plan advanced API
cufftHandle plan_adv;
size_t workSize;
long long int new_size_long = new_size;
checkCudaErrors(cufftCreate(&plan_adv));
checkCudaErrors(cufftXtMakePlanMany(plan_adv, 1, &new_size_long, NULL, 1, 1,
CUDA_C_32F, NULL, 1, 1, CUDA_C_32F, 1,
&workSize, CUDA_C_32F));
printf("Temporary buffer size %li bytes\n", workSize);
checkCudaErrors(cufftCreate(&plan_adv));
checkCudaErrors(cufftXtMakePlanMany(
plan_adv, 1, &new_size_long, NULL, 1, 1, CUDA_C_32F, NULL, 1, 1, CUDA_C_32F, 1, &workSize, CUDA_C_32F));
printf("Temporary buffer size %li bytes\n", workSize);
// Transform signal and kernel
printf("Transforming signal cufftExecC2C\n");
checkCudaErrors(cufftExecC2C(plan, reinterpret_cast<cufftComplex *>(d_signal),
reinterpret_cast<cufftComplex *>(d_signal),
CUFFT_FORWARD));
checkCudaErrors(cufftExecC2C(
plan_adv, reinterpret_cast<cufftComplex *>(d_filter_kernel),
reinterpret_cast<cufftComplex *>(d_filter_kernel), CUFFT_FORWARD));
// Transform signal and kernel
printf("Transforming signal cufftExecC2C\n");
checkCudaErrors(cufftExecC2C(
plan, reinterpret_cast<cufftComplex *>(d_signal), reinterpret_cast<cufftComplex *>(d_signal), CUFFT_FORWARD));
checkCudaErrors(cufftExecC2C(plan_adv,
reinterpret_cast<cufftComplex *>(d_filter_kernel),
reinterpret_cast<cufftComplex *>(d_filter_kernel),
CUFFT_FORWARD));
// Multiply the coefficients together and normalize the result
printf("Launching ComplexPointwiseMulAndScale<<< >>>\n");
ComplexPointwiseMulAndScale<<<32, 256>>>(d_signal, d_filter_kernel, new_size,
1.0f / new_size);
// Multiply the coefficients together and normalize the result
printf("Launching ComplexPointwiseMulAndScale<<< >>>\n");
ComplexPointwiseMulAndScale<<<32, 256>>>(d_signal, d_filter_kernel, new_size, 1.0f / new_size);
// Check if kernel execution generated and error
getLastCudaError("Kernel execution failed [ ComplexPointwiseMulAndScale ]");
// Check if kernel execution generated and error
getLastCudaError("Kernel execution failed [ ComplexPointwiseMulAndScale ]");
// Transform signal back
printf("Transforming signal back cufftExecC2C\n");
checkCudaErrors(cufftExecC2C(plan, reinterpret_cast<cufftComplex *>(d_signal),
reinterpret_cast<cufftComplex *>(d_signal),
CUFFT_INVERSE));
// Transform signal back
printf("Transforming signal back cufftExecC2C\n");
checkCudaErrors(cufftExecC2C(
plan, reinterpret_cast<cufftComplex *>(d_signal), reinterpret_cast<cufftComplex *>(d_signal), CUFFT_INVERSE));
// Copy device memory to host
Complex *h_convolved_signal = h_padded_signal;
checkCudaErrors(cudaMemcpy(h_convolved_signal, d_signal, mem_size,
cudaMemcpyDeviceToHost));
// Copy device memory to host
Complex *h_convolved_signal = h_padded_signal;
checkCudaErrors(cudaMemcpy(h_convolved_signal, d_signal, mem_size, cudaMemcpyDeviceToHost));
// Allocate host memory for the convolution result
Complex *h_convolved_signal_ref =
reinterpret_cast<Complex *>(malloc(sizeof(Complex) * SIGNAL_SIZE));
// Allocate host memory for the convolution result
Complex *h_convolved_signal_ref = reinterpret_cast<Complex *>(malloc(sizeof(Complex) * SIGNAL_SIZE));
// Convolve on the host
Convolve(h_signal, SIGNAL_SIZE, h_filter_kernel, FILTER_KERNEL_SIZE,
h_convolved_signal_ref);
// Convolve on the host
Convolve(h_signal, SIGNAL_SIZE, h_filter_kernel, FILTER_KERNEL_SIZE, h_convolved_signal_ref);
// check result
bool bTestResult = sdkCompareL2fe(
reinterpret_cast<float *>(h_convolved_signal_ref),
reinterpret_cast<float *>(h_convolved_signal), 2 * SIGNAL_SIZE, 1e-5f);
// check result
bool bTestResult = sdkCompareL2fe(reinterpret_cast<float *>(h_convolved_signal_ref),
reinterpret_cast<float *>(h_convolved_signal),
2 * SIGNAL_SIZE,
1e-5f);
// Destroy CUFFT context
checkCudaErrors(cufftDestroy(plan));
checkCudaErrors(cufftDestroy(plan_adv));
// Destroy CUFFT context
checkCudaErrors(cufftDestroy(plan));
checkCudaErrors(cufftDestroy(plan_adv));
// cleanup memory
free(h_signal);
free(h_filter_kernel);
free(h_padded_signal);
free(h_padded_filter_kernel);
free(h_convolved_signal_ref);
checkCudaErrors(cudaFree(d_signal));
checkCudaErrors(cudaFree(d_filter_kernel));
// cleanup memory
free(h_signal);
free(h_filter_kernel);
free(h_padded_signal);
free(h_padded_filter_kernel);
free(h_convolved_signal_ref);
checkCudaErrors(cudaFree(d_signal));
checkCudaErrors(cudaFree(d_filter_kernel));
exit(bTestResult ? EXIT_SUCCESS : EXIT_FAILURE);
exit(bTestResult ? EXIT_SUCCESS : EXIT_FAILURE);
}
// Pad data
int PadData(const Complex *signal, Complex **padded_signal, int signal_size,
const Complex *filter_kernel, Complex **padded_filter_kernel,
int filter_kernel_size) {
int minRadius = filter_kernel_size / 2;
int maxRadius = filter_kernel_size - minRadius;
int new_size = signal_size + maxRadius;
int PadData(const Complex *signal,
Complex **padded_signal,
int signal_size,
const Complex *filter_kernel,
Complex **padded_filter_kernel,
int filter_kernel_size)
{
int minRadius = filter_kernel_size / 2;
int maxRadius = filter_kernel_size - minRadius;
int new_size = signal_size + maxRadius;
// Pad signal
Complex *new_data =
reinterpret_cast<Complex *>(malloc(sizeof(Complex) * new_size));
memcpy(new_data + 0, signal, signal_size * sizeof(Complex));
memset(new_data + signal_size, 0, (new_size - signal_size) * sizeof(Complex));
*padded_signal = new_data;
// Pad signal
Complex *new_data = reinterpret_cast<Complex *>(malloc(sizeof(Complex) * new_size));
memcpy(new_data + 0, signal, signal_size * sizeof(Complex));
memset(new_data + signal_size, 0, (new_size - signal_size) * sizeof(Complex));
*padded_signal = new_data;
// Pad filter
new_data = reinterpret_cast<Complex *>(malloc(sizeof(Complex) * new_size));
memcpy(new_data + 0, filter_kernel + minRadius, maxRadius * sizeof(Complex));
memset(new_data + maxRadius, 0,
(new_size - filter_kernel_size) * sizeof(Complex));
memcpy(new_data + new_size - minRadius, filter_kernel,
minRadius * sizeof(Complex));
*padded_filter_kernel = new_data;
// Pad filter
new_data = reinterpret_cast<Complex *>(malloc(sizeof(Complex) * new_size));
memcpy(new_data + 0, filter_kernel + minRadius, maxRadius * sizeof(Complex));
memset(new_data + maxRadius, 0, (new_size - filter_kernel_size) * sizeof(Complex));
memcpy(new_data + new_size - minRadius, filter_kernel, minRadius * sizeof(Complex));
*padded_filter_kernel = new_data;
return new_size;
return new_size;
}
////////////////////////////////////////////////////////////////////////////////
@@ -223,27 +213,29 @@ int PadData(const Complex *signal, Complex **padded_signal, int signal_size,
////////////////////////////////////////////////////////////////////////////////
// Computes convolution on the host
void Convolve(const Complex *signal, int signal_size,
const Complex *filter_kernel, int filter_kernel_size,
Complex *filtered_signal) {
int minRadius = filter_kernel_size / 2;
int maxRadius = filter_kernel_size - minRadius;
void Convolve(const Complex *signal,
int signal_size,
const Complex *filter_kernel,
int filter_kernel_size,
Complex *filtered_signal)
{
int minRadius = filter_kernel_size / 2;
int maxRadius = filter_kernel_size - minRadius;
// Loop over output element indices
for (int i = 0; i < signal_size; ++i) {
filtered_signal[i].x = filtered_signal[i].y = 0;
// Loop over output element indices
for (int i = 0; i < signal_size; ++i) {
filtered_signal[i].x = filtered_signal[i].y = 0;
// Loop over convolution indices
for (int j = -maxRadius + 1; j <= minRadius; ++j) {
int k = i + j;
// Loop over convolution indices
for (int j = -maxRadius + 1; j <= minRadius; ++j) {
int k = i + j;
if (k >= 0 && k < signal_size) {
filtered_signal[i] =
ComplexAdd(filtered_signal[i],
ComplexMul(signal[k], filter_kernel[minRadius - j]));
}
if (k >= 0 && k < signal_size) {
filtered_signal[i] =
ComplexAdd(filtered_signal[i], ComplexMul(signal[k], filter_kernel[minRadius - j]));
}
}
}
}
}
////////////////////////////////////////////////////////////////////////////////
@@ -251,36 +243,39 @@ void Convolve(const Complex *signal, int signal_size,
////////////////////////////////////////////////////////////////////////////////
// Complex addition
static __device__ __host__ inline Complex ComplexAdd(Complex a, Complex b) {
Complex c;
c.x = a.x + b.x;
c.y = a.y + b.y;
return c;
static __device__ __host__ inline Complex ComplexAdd(Complex a, Complex b)
{
Complex c;
c.x = a.x + b.x;
c.y = a.y + b.y;
return c;
}
// Complex scale
static __device__ __host__ inline Complex ComplexScale(Complex a, float s) {
Complex c;
c.x = s * a.x;
c.y = s * a.y;
return c;
static __device__ __host__ inline Complex ComplexScale(Complex a, float s)
{
Complex c;
c.x = s * a.x;
c.y = s * a.y;
return c;
}
// Complex multiplication
static __device__ __host__ inline Complex ComplexMul(Complex a, Complex b) {
Complex c;
c.x = a.x * b.x - a.y * b.y;
c.y = a.x * b.y + a.y * b.x;
return c;
static __device__ __host__ inline Complex ComplexMul(Complex a, Complex b)
{
Complex c;
c.x = a.x * b.x - a.y * b.y;
c.y = a.x * b.y + a.y * b.x;
return c;
}
// Complex pointwise multiplication
static __global__ void ComplexPointwiseMulAndScale(Complex *a, const Complex *b,
int size, float scale) {
const int numThreads = blockDim.x * gridDim.x;
const int threadID = blockIdx.x * blockDim.x + threadIdx.x;
static __global__ void ComplexPointwiseMulAndScale(Complex *a, const Complex *b, int size, float scale)
{
const int numThreads = blockDim.x * gridDim.x;
const int threadID = blockIdx.x * blockDim.x + threadIdx.x;
for (int i = threadID; i < size; i += numThreads) {
a[i] = ComplexScale(ComplexMul(a[i], b[i]), scale);
}
for (int i = threadID; i < size; i += numThreads) {
a[i] = ComplexScale(ComplexMul(a[i], b[i]), scale);
}
}

View File

@@ -38,343 +38,338 @@
// System includes
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// CUDA runtime
#include <cuda_runtime.h>
//CUFFT Header file
// CUFFT Header file
#include <cufftXt.h>
// helper functions and utilities to work with CUDA
#include <helper_functions.h>
#include <helper_cuda.h>
#include <helper_functions.h>
// Complex data type
typedef float2 Complex;
// Data configuration
const int GPU_COUNT = 2;
const int BSZ_Y = 4;
const int BSZ_X = 4;
const int BSZ_Y = 4;
const int BSZ_X = 4;
// Forward Declaration
void solvePoissonEquation(cudaLibXtDesc *, cudaLibXtDesc *, float **, int, int);
__global__ void solvePoisson(cufftComplex *, cufftComplex *, float *, int, int,
int n_gpu);
__global__ void solvePoisson(cufftComplex *, cufftComplex *, float *, int, int, int n_gpu);
///////////////////////////////////////////////////////////////////////////////
// Program main
////////////////////////////////////////////////////////////////////////////////
int main(int argc, char **argv) {
printf(
"\nPoisson equation using CUFFT library on Multiple GPUs is "
"starting...\n\n");
int main(int argc, char **argv)
{
printf("\nPoisson equation using CUFFT library on Multiple GPUs is "
"starting...\n\n");
int GPU_N;
checkCudaErrors(cudaGetDeviceCount(&GPU_N));
int GPU_N;
checkCudaErrors(cudaGetDeviceCount(&GPU_N));
if (GPU_N < GPU_COUNT) {
printf("No. of GPU on node %d\n", GPU_N);
printf("Two GPUs are required to run simpleCUFFT_2d_MGPU sample code\n");
exit(EXIT_WAIVED);
}
int *major_minor = (int *)malloc(sizeof(int) * GPU_N * 2);
int found2IdenticalGPUs = 0;
int nGPUs = 2;
int *whichGPUs;
whichGPUs = (int *)malloc(sizeof(int) * nGPUs);
for (int i = 0; i < GPU_N; i++) {
cudaDeviceProp deviceProp;
checkCudaErrors(cudaGetDeviceProperties(&deviceProp, i));
major_minor[i * 2] = deviceProp.major;
major_minor[i * 2 + 1] = deviceProp.minor;
printf("GPU Device %d: \"%s\" with compute capability %d.%d\n", i,
deviceProp.name, deviceProp.major, deviceProp.minor);
}
for (int i = 0; i < GPU_N; i++) {
for (int j = i + 1; j < GPU_N; j++) {
if ((major_minor[i * 2] == major_minor[j * 2]) &&
(major_minor[i * 2 + 1] == major_minor[j * 2 + 1])) {
whichGPUs[0] = i;
whichGPUs[1] = j;
found2IdenticalGPUs = 1;
break;
}
}
if (found2IdenticalGPUs) {
break;
}
}
free(major_minor);
if (!found2IdenticalGPUs) {
printf(
"No Two GPUs with same architecture found\nWaiving simpleCUFFT_2d_MGPU "
"sample\n");
exit(EXIT_WAIVED);
}
int N = 64;
float xMAX = 1.0f, xMIN = 0.0f, yMIN = 0.0f, h = (xMAX - xMIN) / ((float)N),
s = 0.1f, s2 = s * s;
float *x, *y, *f, *u_a, r2;
x = (float *)malloc(sizeof(float) * N * N);
y = (float *)malloc(sizeof(float) * N * N);
f = (float *)malloc(sizeof(float) * N * N);
u_a = (float *)malloc(sizeof(float) * N * N);
for (int j = 0; j < N; j++)
for (int i = 0; i < N; i++) {
x[N * j + i] = xMIN + i * h;
y[N * j + i] = yMIN + j * h;
r2 = (x[N * j + i] - 0.5f) * (x[N * j + i] - 0.5f) +
(y[N * j + i] - 0.5f) * (y[N * j + i] - 0.5f);
f[N * j + i] = (r2 - 2 * s2) / (s2 * s2) * exp(-r2 / (2 * s2));
u_a[N * j + i] = exp(-r2 / (2 * s2)); // analytical solution
if (GPU_N < GPU_COUNT) {
printf("No. of GPU on node %d\n", GPU_N);
printf("Two GPUs are required to run simpleCUFFT_2d_MGPU sample code\n");
exit(EXIT_WAIVED);
}
float *k, *d_k[GPU_COUNT];
k = (float *)malloc(sizeof(float) * N);
for (int i = 0; i <= N / 2; i++) {
k[i] = i * 2 * (float)M_PI;
}
for (int i = N / 2 + 1; i < N; i++) {
k[i] = (i - N) * 2 * (float)M_PI;
}
int *major_minor = (int *)malloc(sizeof(int) * GPU_N * 2);
int found2IdenticalGPUs = 0;
int nGPUs = 2;
int *whichGPUs;
whichGPUs = (int *)malloc(sizeof(int) * nGPUs);
// Create a complex variable on host
Complex *h_f = (Complex *)malloc(sizeof(Complex) * N * N);
for (int i = 0; i < GPU_N; i++) {
cudaDeviceProp deviceProp;
checkCudaErrors(cudaGetDeviceProperties(&deviceProp, i));
major_minor[i * 2] = deviceProp.major;
major_minor[i * 2 + 1] = deviceProp.minor;
printf("GPU Device %d: \"%s\" with compute capability %d.%d\n",
i,
deviceProp.name,
deviceProp.major,
deviceProp.minor);
}
// Initialize the memory for the signal
for (int i = 0; i < (N * N); i++) {
h_f[i].x = f[i];
h_f[i].y = 0.0f;
}
for (int i = 0; i < GPU_N; i++) {
for (int j = i + 1; j < GPU_N; j++) {
if ((major_minor[i * 2] == major_minor[j * 2]) && (major_minor[i * 2 + 1] == major_minor[j * 2 + 1])) {
whichGPUs[0] = i;
whichGPUs[1] = j;
found2IdenticalGPUs = 1;
break;
}
}
if (found2IdenticalGPUs) {
break;
}
}
// cufftCreate() - Create an empty plan
cufftResult result;
cufftHandle planComplex;
result = cufftCreate(&planComplex);
if (result != CUFFT_SUCCESS) {
printf("cufftCreate failed\n");
exit(EXIT_FAILURE);
}
free(major_minor);
if (!found2IdenticalGPUs) {
printf("No Two GPUs with same architecture found\nWaiving simpleCUFFT_2d_MGPU "
"sample\n");
exit(EXIT_WAIVED);
}
// cufftXtSetGPUs() - Define which GPUs to use
result = cufftXtSetGPUs(planComplex, nGPUs, whichGPUs);
int N = 64;
float xMAX = 1.0f, xMIN = 0.0f, yMIN = 0.0f, h = (xMAX - xMIN) / ((float)N), s = 0.1f, s2 = s * s;
float *x, *y, *f, *u_a, r2;
if (result == CUFFT_INVALID_DEVICE) {
printf("This sample requires two GPUs on the same board.\n");
printf("No such board was found. Waiving sample.\n");
exit(EXIT_WAIVED);
} else if (result != CUFFT_SUCCESS) {
printf("cufftXtSetGPUs failed\n");
exit(EXIT_FAILURE);
}
x = (float *)malloc(sizeof(float) * N * N);
y = (float *)malloc(sizeof(float) * N * N);
f = (float *)malloc(sizeof(float) * N * N);
u_a = (float *)malloc(sizeof(float) * N * N);
// Print the device information to run the code
printf("\nRunning on GPUs\n");
for (int i = 0; i < 2; i++) {
cudaDeviceProp deviceProp;
checkCudaErrors(cudaGetDeviceProperties(&deviceProp, whichGPUs[i]));
printf("GPU Device %d: \"%s\" with compute capability %d.%d\n",
whichGPUs[i], deviceProp.name, deviceProp.major, deviceProp.minor);
}
for (int j = 0; j < N; j++)
for (int i = 0; i < N; i++) {
x[N * j + i] = xMIN + i * h;
y[N * j + i] = yMIN + j * h;
r2 = (x[N * j + i] - 0.5f) * (x[N * j + i] - 0.5f) + (y[N * j + i] - 0.5f) * (y[N * j + i] - 0.5f);
f[N * j + i] = (r2 - 2 * s2) / (s2 * s2) * exp(-r2 / (2 * s2));
u_a[N * j + i] = exp(-r2 / (2 * s2)); // analytical solution
}
size_t *worksize;
worksize = (size_t *)malloc(sizeof(size_t) * nGPUs);
float *k, *d_k[GPU_COUNT];
k = (float *)malloc(sizeof(float) * N);
for (int i = 0; i <= N / 2; i++) {
k[i] = i * 2 * (float)M_PI;
}
for (int i = N / 2 + 1; i < N; i++) {
k[i] = (i - N) * 2 * (float)M_PI;
}
// cufftMakePlan2d() - Create the plan
result = cufftMakePlan2d(planComplex, N, N, CUFFT_C2C, worksize);
if (result != CUFFT_SUCCESS) {
printf("*MakePlan* failed\n");
exit(EXIT_FAILURE);
}
// Create a complex variable on host
Complex *h_f = (Complex *)malloc(sizeof(Complex) * N * N);
for (int i = 0; i < nGPUs; i++) {
cudaSetDevice(whichGPUs[i]);
cudaMalloc((void **)&d_k[i], sizeof(float) * N);
cudaMemcpy(d_k[i], k, sizeof(float) * N, cudaMemcpyHostToDevice);
}
// Initialize the memory for the signal
for (int i = 0; i < (N * N); i++) {
h_f[i].x = f[i];
h_f[i].y = 0.0f;
}
// Create a variable on device
// d_f - variable on device to store the input data
// d_d_f - variable that store the natural order of d_f data
// d_out - device output
cudaLibXtDesc *d_f, *d_d_f, *d_out;
// cufftCreate() - Create an empty plan
cufftResult result;
cufftHandle planComplex;
result = cufftCreate(&planComplex);
if (result != CUFFT_SUCCESS) {
printf("cufftCreate failed\n");
exit(EXIT_FAILURE);
}
// cufftXtMalloc() - Malloc data on multiple GPUs
// cufftXtSetGPUs() - Define which GPUs to use
result = cufftXtSetGPUs(planComplex, nGPUs, whichGPUs);
result = cufftXtMalloc(planComplex, (cudaLibXtDesc **)&d_f,
CUFFT_XT_FORMAT_INPLACE);
if (result != CUFFT_SUCCESS) {
printf("*XtMalloc failed\n");
exit(EXIT_FAILURE);
}
if (result == CUFFT_INVALID_DEVICE) {
printf("This sample requires two GPUs on the same board.\n");
printf("No such board was found. Waiving sample.\n");
exit(EXIT_WAIVED);
}
else if (result != CUFFT_SUCCESS) {
printf("cufftXtSetGPUs failed\n");
exit(EXIT_FAILURE);
}
result = cufftXtMalloc(planComplex, (cudaLibXtDesc **)&d_d_f,
CUFFT_XT_FORMAT_INPLACE);
if (result != CUFFT_SUCCESS) {
printf("*XtMalloc failed\n");
exit(EXIT_FAILURE);
}
// Print the device information to run the code
printf("\nRunning on GPUs\n");
for (int i = 0; i < 2; i++) {
cudaDeviceProp deviceProp;
checkCudaErrors(cudaGetDeviceProperties(&deviceProp, whichGPUs[i]));
printf("GPU Device %d: \"%s\" with compute capability %d.%d\n",
whichGPUs[i],
deviceProp.name,
deviceProp.major,
deviceProp.minor);
}
result = cufftXtMalloc(planComplex, (cudaLibXtDesc **)&d_out,
CUFFT_XT_FORMAT_INPLACE);
if (result != CUFFT_SUCCESS) {
printf("*XtMalloc failed\n");
exit(EXIT_FAILURE);
}
size_t *worksize;
worksize = (size_t *)malloc(sizeof(size_t) * nGPUs);
// cufftXtMemcpy() - Copy the data from host to device
result = cufftXtMemcpy(planComplex, d_f, h_f, CUFFT_COPY_HOST_TO_DEVICE);
if (result != CUFFT_SUCCESS) {
printf("*XtMemcpy failed\n");
exit(EXIT_FAILURE);
}
// cufftMakePlan2d() - Create the plan
result = cufftMakePlan2d(planComplex, N, N, CUFFT_C2C, worksize);
if (result != CUFFT_SUCCESS) {
printf("*MakePlan* failed\n");
exit(EXIT_FAILURE);
}
// cufftXtExecDescriptorC2C() - Execute FFT on data on multiple GPUs
printf("Forward 2d FFT on multiple GPUs\n");
result = cufftXtExecDescriptorC2C(planComplex, d_f, d_f, CUFFT_FORWARD);
if (result != CUFFT_SUCCESS) {
printf("*XtExecC2C failed\n");
exit(EXIT_FAILURE);
}
for (int i = 0; i < nGPUs; i++) {
cudaSetDevice(whichGPUs[i]);
cudaMalloc((void **)&d_k[i], sizeof(float) * N);
cudaMemcpy(d_k[i], k, sizeof(float) * N, cudaMemcpyHostToDevice);
}
// cufftXtMemcpy() - Copy the data to natural order on GPUs
result = cufftXtMemcpy(planComplex, d_d_f, d_f, CUFFT_COPY_DEVICE_TO_DEVICE);
if (result != CUFFT_SUCCESS) {
printf("*XtMemcpy failed\n");
exit(EXIT_FAILURE);
}
// Create a variable on device
// d_f - variable on device to store the input data
// d_d_f - variable that store the natural order of d_f data
// d_out - device output
cudaLibXtDesc *d_f, *d_d_f, *d_out;
printf("Solve Poisson Equation\n");
solvePoissonEquation(d_d_f, d_out, d_k, N, nGPUs);
// cufftXtMalloc() - Malloc data on multiple GPUs
printf("Inverse 2d FFT on multiple GPUs\n");
// cufftXtExecDescriptorC2C() - Execute inverse FFT on data on multiple GPUs
result = cufftXtExecDescriptorC2C(planComplex, d_out, d_out, CUFFT_INVERSE);
if (result != CUFFT_SUCCESS) {
printf("*XtExecC2C failed\n");
exit(EXIT_FAILURE);
}
result = cufftXtMalloc(planComplex, (cudaLibXtDesc **)&d_f, CUFFT_XT_FORMAT_INPLACE);
if (result != CUFFT_SUCCESS) {
printf("*XtMalloc failed\n");
exit(EXIT_FAILURE);
}
// Create a variable on host to copy the data from device
// h_d_out - variable store the output of device
Complex *h_d_out = (Complex *)malloc(sizeof(Complex) * N * N);
result = cufftXtMalloc(planComplex, (cudaLibXtDesc **)&d_d_f, CUFFT_XT_FORMAT_INPLACE);
if (result != CUFFT_SUCCESS) {
printf("*XtMalloc failed\n");
exit(EXIT_FAILURE);
}
// cufftXtMemcpy() - Copy data from multiple GPUs to host
result =
cufftXtMemcpy(planComplex, h_d_out, d_out, CUFFT_COPY_DEVICE_TO_HOST);
if (result != CUFFT_SUCCESS) {
printf("*XtMemcpy failed\n");
exit(EXIT_FAILURE);
}
result = cufftXtMalloc(planComplex, (cudaLibXtDesc **)&d_out, CUFFT_XT_FORMAT_INPLACE);
if (result != CUFFT_SUCCESS) {
printf("*XtMalloc failed\n");
exit(EXIT_FAILURE);
}
float *out = (float *)malloc(sizeof(float) * N * N);
float constant = h_d_out[0].x / N * N;
for (int i = 0; i < N * N; i++) {
// subtract u[0] to force the arbitrary constant to be 0
out[i] = (h_d_out[i].x / (N * N)) - constant;
}
// cufftXtMemcpy() - Copy the data from host to device
result = cufftXtMemcpy(planComplex, d_f, h_f, CUFFT_COPY_HOST_TO_DEVICE);
if (result != CUFFT_SUCCESS) {
printf("*XtMemcpy failed\n");
exit(EXIT_FAILURE);
}
// cleanup memory
// cufftXtExecDescriptorC2C() - Execute FFT on data on multiple GPUs
printf("Forward 2d FFT on multiple GPUs\n");
result = cufftXtExecDescriptorC2C(planComplex, d_f, d_f, CUFFT_FORWARD);
if (result != CUFFT_SUCCESS) {
printf("*XtExecC2C failed\n");
exit(EXIT_FAILURE);
}
free(h_f);
free(k);
free(out);
free(h_d_out);
free(x);
free(whichGPUs);
free(y);
free(f);
free(u_a);
free(worksize);
// cufftXtMemcpy() - Copy the data to natural order on GPUs
result = cufftXtMemcpy(planComplex, d_d_f, d_f, CUFFT_COPY_DEVICE_TO_DEVICE);
if (result != CUFFT_SUCCESS) {
printf("*XtMemcpy failed\n");
exit(EXIT_FAILURE);
}
// cudaXtFree() - Free GPU memory
for (int i = 0; i < GPU_COUNT; i++) {
cudaFree(d_k[i]);
}
result = cufftXtFree(d_out);
if (result != CUFFT_SUCCESS) {
printf("*XtFree failed\n");
exit(EXIT_FAILURE);
}
result = cufftXtFree(d_f);
if (result != CUFFT_SUCCESS) {
printf("*XtFree failed\n");
exit(EXIT_FAILURE);
}
result = cufftXtFree(d_d_f);
if (result != CUFFT_SUCCESS) {
printf("*XtFree failed\n");
exit(EXIT_FAILURE);
}
printf("Solve Poisson Equation\n");
solvePoissonEquation(d_d_f, d_out, d_k, N, nGPUs);
// cufftDestroy() - Destroy FFT plan
result = cufftDestroy(planComplex);
if (result != CUFFT_SUCCESS) {
printf("cufftDestroy failed: code %d\n", (int)result);
exit(EXIT_FAILURE);
}
printf("Inverse 2d FFT on multiple GPUs\n");
// cufftXtExecDescriptorC2C() - Execute inverse FFT on data on multiple GPUs
result = cufftXtExecDescriptorC2C(planComplex, d_out, d_out, CUFFT_INVERSE);
if (result != CUFFT_SUCCESS) {
printf("*XtExecC2C failed\n");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
// Create a variable on host to copy the data from device
// h_d_out - variable store the output of device
Complex *h_d_out = (Complex *)malloc(sizeof(Complex) * N * N);
// cufftXtMemcpy() - Copy data from multiple GPUs to host
result = cufftXtMemcpy(planComplex, h_d_out, d_out, CUFFT_COPY_DEVICE_TO_HOST);
if (result != CUFFT_SUCCESS) {
printf("*XtMemcpy failed\n");
exit(EXIT_FAILURE);
}
float *out = (float *)malloc(sizeof(float) * N * N);
float constant = h_d_out[0].x / N * N;
for (int i = 0; i < N * N; i++) {
// subtract u[0] to force the arbitrary constant to be 0
out[i] = (h_d_out[i].x / (N * N)) - constant;
}
// cleanup memory
free(h_f);
free(k);
free(out);
free(h_d_out);
free(x);
free(whichGPUs);
free(y);
free(f);
free(u_a);
free(worksize);
// cudaXtFree() - Free GPU memory
for (int i = 0; i < GPU_COUNT; i++) {
cudaFree(d_k[i]);
}
result = cufftXtFree(d_out);
if (result != CUFFT_SUCCESS) {
printf("*XtFree failed\n");
exit(EXIT_FAILURE);
}
result = cufftXtFree(d_f);
if (result != CUFFT_SUCCESS) {
printf("*XtFree failed\n");
exit(EXIT_FAILURE);
}
result = cufftXtFree(d_d_f);
if (result != CUFFT_SUCCESS) {
printf("*XtFree failed\n");
exit(EXIT_FAILURE);
}
// cufftDestroy() - Destroy FFT plan
result = cufftDestroy(planComplex);
if (result != CUFFT_SUCCESS) {
printf("cufftDestroy failed: code %d\n", (int)result);
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
////////////////////////////////////////////////////////////////////////////////////
// Launch kernel on multiple GPU
///////////////////////////////////////////////////////////////////////////////////
void solvePoissonEquation(cudaLibXtDesc *d_ft, cudaLibXtDesc *d_ft_k, float **k,
int N, int nGPUs) {
int device;
dim3 dimGrid(int(N / BSZ_X), int((N / 2) / BSZ_Y));
dim3 dimBlock(BSZ_X, BSZ_Y);
void solvePoissonEquation(cudaLibXtDesc *d_ft, cudaLibXtDesc *d_ft_k, float **k, int N, int nGPUs)
{
int device;
dim3 dimGrid(int(N / BSZ_X), int((N / 2) / BSZ_Y));
dim3 dimBlock(BSZ_X, BSZ_Y);
for (int i = 0; i < nGPUs; i++) {
device = d_ft_k->descriptor->GPUs[i];
cudaSetDevice(device);
solvePoisson<<<dimGrid, dimBlock>>>(
(cufftComplex *)d_ft->descriptor->data[i],
(cufftComplex *)d_ft_k->descriptor->data[i], k[i], N, i, nGPUs);
}
for (int i = 0; i < nGPUs; i++) {
device = d_ft_k->descriptor->GPUs[i];
cudaSetDevice(device);
solvePoisson<<<dimGrid, dimBlock>>>(
(cufftComplex *)d_ft->descriptor->data[i], (cufftComplex *)d_ft_k->descriptor->data[i], k[i], N, i, nGPUs);
}
// Wait for device to finish all operation
for (int i = 0; i < nGPUs; i++) {
device = d_ft_k->descriptor->GPUs[i];
cudaSetDevice(device);
cudaDeviceSynchronize();
// Wait for device to finish all operation
for (int i = 0; i < nGPUs; i++) {
device = d_ft_k->descriptor->GPUs[i];
cudaSetDevice(device);
cudaDeviceSynchronize();
// Check if kernel execution generated and error
getLastCudaError("Kernel execution failed [ solvePoisson ]");
}
// Check if kernel execution generated and error
getLastCudaError("Kernel execution failed [ solvePoisson ]");
}
}
////////////////////////////////////////////////////////////////////////////////
// Kernel for Solving Poisson equation on GPU
////////////////////////////////////////////////////////////////////////////////
__global__ void solvePoisson(cufftComplex *ft, cufftComplex *ft_k, float *k,
int N, int gpu_id, int n_gpu) {
int i = threadIdx.x + blockIdx.x * blockDim.x;
int j = threadIdx.y + blockIdx.y * blockDim.y;
int index = j * N + i;
if (i < N && j < N / n_gpu) {
float k2 =
k[i] * k[i] + k[j + gpu_id * N / n_gpu] * k[j + gpu_id * N / n_gpu];
if (i == 0 && j == 0 && gpu_id == 0) {
k2 = 1.0f;
}
__global__ void solvePoisson(cufftComplex *ft, cufftComplex *ft_k, float *k, int N, int gpu_id, int n_gpu)
{
int i = threadIdx.x + blockIdx.x * blockDim.x;
int j = threadIdx.y + blockIdx.y * blockDim.y;
int index = j * N + i;
if (i < N && j < N / n_gpu) {
float k2 = k[i] * k[i] + k[j + gpu_id * N / n_gpu] * k[j + gpu_id * N / n_gpu];
if (i == 0 && j == 0 && gpu_id == 0) {
k2 = 1.0f;
}
ft_k[index].x = -ft[index].x * 1 / k2;
ft_k[index].y = -ft[index].y * 1 / k2;
}
ft_k[index].x = -ft[index].x * 1 / k2;
ft_k[index].y = -ft[index].y * 1 / k2;
}
}

View File

@@ -28,21 +28,20 @@
/* Example showing the use of CUFFT for fast 1D-convolution using FFT. */
// System includes
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// CUDA runtime
#include <cuda_runtime.h>
//CUFFT Header file
// CUFFT Header file
#include <cufftXt.h>
// helper functions and utilities to work with CUDA
#include <helper_functions.h>
#include <helper_cuda.h>
#include <helper_functions.h>
// Complex data type
typedef float2 Complex;
@@ -50,8 +49,7 @@ typedef float2 Complex;
static __device__ __host__ inline Complex ComplexAdd(Complex, Complex);
static __device__ __host__ inline Complex ComplexScale(Complex, float);
static __device__ __host__ inline Complex ComplexMul(Complex, Complex);
static __global__ void ComplexPointwiseMulAndScale(cufftComplex *,
cufftComplex *, int, float);
static __global__ void ComplexPointwiseMulAndScale(cufftComplex *, cufftComplex *, int, float);
// Kernel for GPU
void multiplyCoefficient(cudaLibXtDesc *, cudaLibXtDesc *, int, float, int);
@@ -66,299 +64,286 @@ int PadData(const Complex *, Complex **, int, const Complex *, Complex **, int);
// Data configuration
// The filter size is assumed to be a number smaller than the signal size
///////////////////////////////////////////////////////////////////////////////
const int SIGNAL_SIZE = 1018;
const int SIGNAL_SIZE = 1018;
const int FILTER_KERNEL_SIZE = 11;
const int GPU_COUNT = 2;
const int GPU_COUNT = 2;
////////////////////////////////////////////////////////////////////////////////
// Program main
////////////////////////////////////////////////////////////////////////////////
int main(int argc, char **argv) {
printf("\n[simpleCUFFT_MGPU] is starting...\n\n");
int main(int argc, char **argv)
{
printf("\n[simpleCUFFT_MGPU] is starting...\n\n");
int GPU_N;
checkCudaErrors(cudaGetDeviceCount(&GPU_N));
int GPU_N;
checkCudaErrors(cudaGetDeviceCount(&GPU_N));
if (GPU_N < GPU_COUNT) {
printf("No. of GPU on node %d\n", GPU_N);
printf("Two GPUs are required to run simpleCUFFT_MGPU sample code\n");
exit(EXIT_WAIVED);
}
int *major_minor = (int *)malloc(sizeof(int) * GPU_N * 2);
int found2IdenticalGPUs = 0;
int nGPUs = 2;
int *whichGPUs;
whichGPUs = (int *)malloc(sizeof(int) * nGPUs);
for (int i = 0; i < GPU_N; i++) {
cudaDeviceProp deviceProp;
checkCudaErrors(cudaGetDeviceProperties(&deviceProp, i));
major_minor[i * 2] = deviceProp.major;
major_minor[i * 2 + 1] = deviceProp.minor;
printf("GPU Device %d: \"%s\" with compute capability %d.%d\n", i,
deviceProp.name, deviceProp.major, deviceProp.minor);
}
for (int i = 0; i < GPU_N; i++) {
for (int j = i + 1; j < GPU_N; j++) {
if ((major_minor[i * 2] == major_minor[j * 2]) &&
(major_minor[i * 2 + 1] == major_minor[j * 2 + 1])) {
whichGPUs[0] = i;
whichGPUs[1] = j;
found2IdenticalGPUs = 1;
break;
}
if (GPU_N < GPU_COUNT) {
printf("No. of GPU on node %d\n", GPU_N);
printf("Two GPUs are required to run simpleCUFFT_MGPU sample code\n");
exit(EXIT_WAIVED);
}
if (found2IdenticalGPUs) {
break;
int *major_minor = (int *)malloc(sizeof(int) * GPU_N * 2);
int found2IdenticalGPUs = 0;
int nGPUs = 2;
int *whichGPUs;
whichGPUs = (int *)malloc(sizeof(int) * nGPUs);
for (int i = 0; i < GPU_N; i++) {
cudaDeviceProp deviceProp;
checkCudaErrors(cudaGetDeviceProperties(&deviceProp, i));
major_minor[i * 2] = deviceProp.major;
major_minor[i * 2 + 1] = deviceProp.minor;
printf("GPU Device %d: \"%s\" with compute capability %d.%d\n",
i,
deviceProp.name,
deviceProp.major,
deviceProp.minor);
}
}
free(major_minor);
if (!found2IdenticalGPUs) {
printf(
"No Two GPUs with same architecture found\nWaiving simpleCUFFT_2d_MGPU "
"sample\n");
exit(EXIT_WAIVED);
}
for (int i = 0; i < GPU_N; i++) {
for (int j = i + 1; j < GPU_N; j++) {
if ((major_minor[i * 2] == major_minor[j * 2]) && (major_minor[i * 2 + 1] == major_minor[j * 2 + 1])) {
whichGPUs[0] = i;
whichGPUs[1] = j;
found2IdenticalGPUs = 1;
break;
}
}
if (found2IdenticalGPUs) {
break;
}
}
// Allocate host memory for the signal
Complex *h_signal = (Complex *)malloc(sizeof(Complex) * SIGNAL_SIZE);
free(major_minor);
if (!found2IdenticalGPUs) {
printf("No Two GPUs with same architecture found\nWaiving simpleCUFFT_2d_MGPU "
"sample\n");
exit(EXIT_WAIVED);
}
// Initialize the memory for the signal
for (int i = 0; i < SIGNAL_SIZE; ++i) {
h_signal[i].x = rand() / (float)RAND_MAX;
h_signal[i].y = 0;
}
// Allocate host memory for the signal
Complex *h_signal = (Complex *)malloc(sizeof(Complex) * SIGNAL_SIZE);
// Allocate host memory for the filter
Complex *h_filter_kernel =
(Complex *)malloc(sizeof(Complex) * FILTER_KERNEL_SIZE);
// Initialize the memory for the signal
for (int i = 0; i < SIGNAL_SIZE; ++i) {
h_signal[i].x = rand() / (float)RAND_MAX;
h_signal[i].y = 0;
}
// Initialize the memory for the filter
for (int i = 0; i < FILTER_KERNEL_SIZE; ++i) {
h_filter_kernel[i].x = rand() / (float)RAND_MAX;
h_filter_kernel[i].y = 0;
}
// Allocate host memory for the filter
Complex *h_filter_kernel = (Complex *)malloc(sizeof(Complex) * FILTER_KERNEL_SIZE);
// Pad signal and filter kernel
Complex *h_padded_signal;
Complex *h_padded_filter_kernel;
int new_size =
PadData(h_signal, &h_padded_signal, SIGNAL_SIZE, h_filter_kernel,
&h_padded_filter_kernel, FILTER_KERNEL_SIZE);
// Initialize the memory for the filter
for (int i = 0; i < FILTER_KERNEL_SIZE; ++i) {
h_filter_kernel[i].x = rand() / (float)RAND_MAX;
h_filter_kernel[i].y = 0;
}
// cufftCreate() - Create an empty plan
cufftResult result;
cufftHandle plan_input;
checkCudaErrors(cufftCreate(&plan_input));
// Pad signal and filter kernel
Complex *h_padded_signal;
Complex *h_padded_filter_kernel;
int new_size =
PadData(h_signal, &h_padded_signal, SIGNAL_SIZE, h_filter_kernel, &h_padded_filter_kernel, FILTER_KERNEL_SIZE);
// cufftXtSetGPUs() - Define which GPUs to use
result = cufftXtSetGPUs(plan_input, nGPUs, whichGPUs);
// cufftCreate() - Create an empty plan
cufftResult result;
cufftHandle plan_input;
checkCudaErrors(cufftCreate(&plan_input));
if (result == CUFFT_INVALID_DEVICE) {
printf("This sample requires two GPUs on the same board.\n");
printf("No such board was found. Waiving sample.\n");
exit(EXIT_WAIVED);
} else if (result != CUFFT_SUCCESS) {
printf("cufftXtSetGPUs failed\n");
exit(EXIT_FAILURE);
}
// cufftXtSetGPUs() - Define which GPUs to use
result = cufftXtSetGPUs(plan_input, nGPUs, whichGPUs);
// Print the device information to run the code
printf("\nRunning on GPUs\n");
for (int i = 0; i < nGPUs; i++) {
cudaDeviceProp deviceProp;
checkCudaErrors(cudaGetDeviceProperties(&deviceProp, whichGPUs[i]));
printf("GPU Device %d: \"%s\" with compute capability %d.%d\n",
whichGPUs[i], deviceProp.name, deviceProp.major, deviceProp.minor);
}
if (result == CUFFT_INVALID_DEVICE) {
printf("This sample requires two GPUs on the same board.\n");
printf("No such board was found. Waiving sample.\n");
exit(EXIT_WAIVED);
}
else if (result != CUFFT_SUCCESS) {
printf("cufftXtSetGPUs failed\n");
exit(EXIT_FAILURE);
}
size_t *worksize;
worksize = (size_t *)malloc(sizeof(size_t) * nGPUs);
// Print the device information to run the code
printf("\nRunning on GPUs\n");
for (int i = 0; i < nGPUs; i++) {
cudaDeviceProp deviceProp;
checkCudaErrors(cudaGetDeviceProperties(&deviceProp, whichGPUs[i]));
printf("GPU Device %d: \"%s\" with compute capability %d.%d\n",
whichGPUs[i],
deviceProp.name,
deviceProp.major,
deviceProp.minor);
}
// cufftMakePlan1d() - Create the plan
checkCudaErrors(
cufftMakePlan1d(plan_input, new_size, CUFFT_C2C, 1, worksize));
size_t *worksize;
worksize = (size_t *)malloc(sizeof(size_t) * nGPUs);
// cufftXtMalloc() - Malloc data on multiple GPUs
cudaLibXtDesc *d_signal;
checkCudaErrors(cufftXtMalloc(plan_input, (cudaLibXtDesc **)&d_signal,
CUFFT_XT_FORMAT_INPLACE));
cudaLibXtDesc *d_out_signal;
checkCudaErrors(cufftXtMalloc(plan_input, (cudaLibXtDesc **)&d_out_signal,
CUFFT_XT_FORMAT_INPLACE));
cudaLibXtDesc *d_filter_kernel;
checkCudaErrors(cufftXtMalloc(plan_input, (cudaLibXtDesc **)&d_filter_kernel,
CUFFT_XT_FORMAT_INPLACE));
cudaLibXtDesc *d_out_filter_kernel;
checkCudaErrors(cufftXtMalloc(plan_input,
(cudaLibXtDesc **)&d_out_filter_kernel,
CUFFT_XT_FORMAT_INPLACE));
// cufftMakePlan1d() - Create the plan
checkCudaErrors(cufftMakePlan1d(plan_input, new_size, CUFFT_C2C, 1, worksize));
// cufftXtMemcpy() - Copy data from host to multiple GPUs
checkCudaErrors(cufftXtMemcpy(plan_input, d_signal, h_padded_signal,
CUFFT_COPY_HOST_TO_DEVICE));
checkCudaErrors(cufftXtMemcpy(plan_input, d_filter_kernel,
h_padded_filter_kernel,
CUFFT_COPY_HOST_TO_DEVICE));
// cufftXtMalloc() - Malloc data on multiple GPUs
cudaLibXtDesc *d_signal;
checkCudaErrors(cufftXtMalloc(plan_input, (cudaLibXtDesc **)&d_signal, CUFFT_XT_FORMAT_INPLACE));
cudaLibXtDesc *d_out_signal;
checkCudaErrors(cufftXtMalloc(plan_input, (cudaLibXtDesc **)&d_out_signal, CUFFT_XT_FORMAT_INPLACE));
cudaLibXtDesc *d_filter_kernel;
checkCudaErrors(cufftXtMalloc(plan_input, (cudaLibXtDesc **)&d_filter_kernel, CUFFT_XT_FORMAT_INPLACE));
cudaLibXtDesc *d_out_filter_kernel;
checkCudaErrors(cufftXtMalloc(plan_input, (cudaLibXtDesc **)&d_out_filter_kernel, CUFFT_XT_FORMAT_INPLACE));
// cufftXtExecDescriptorC2C() - Execute FFT on data on multiple GPUs
checkCudaErrors(
cufftXtExecDescriptorC2C(plan_input, d_signal, d_signal, CUFFT_FORWARD));
checkCudaErrors(cufftXtExecDescriptorC2C(plan_input, d_filter_kernel,
d_filter_kernel, CUFFT_FORWARD));
// cufftXtMemcpy() - Copy data from host to multiple GPUs
checkCudaErrors(cufftXtMemcpy(plan_input, d_signal, h_padded_signal, CUFFT_COPY_HOST_TO_DEVICE));
checkCudaErrors(cufftXtMemcpy(plan_input, d_filter_kernel, h_padded_filter_kernel, CUFFT_COPY_HOST_TO_DEVICE));
// cufftXtMemcpy() - Copy the data to natural order on GPUs
checkCudaErrors(cufftXtMemcpy(plan_input, d_out_signal, d_signal,
CUFFT_COPY_DEVICE_TO_DEVICE));
checkCudaErrors(cufftXtMemcpy(plan_input, d_out_filter_kernel,
d_filter_kernel, CUFFT_COPY_DEVICE_TO_DEVICE));
// cufftXtExecDescriptorC2C() - Execute FFT on data on multiple GPUs
checkCudaErrors(cufftXtExecDescriptorC2C(plan_input, d_signal, d_signal, CUFFT_FORWARD));
checkCudaErrors(cufftXtExecDescriptorC2C(plan_input, d_filter_kernel, d_filter_kernel, CUFFT_FORWARD));
printf("\n\nValue of Library Descriptor\n");
printf("Number of GPUs %d\n", d_out_signal->descriptor->nGPUs);
printf("Device id %d %d\n", d_out_signal->descriptor->GPUs[0],
d_out_signal->descriptor->GPUs[1]);
printf("Data size on GPU %ld %ld\n",
(long)(d_out_signal->descriptor->size[0] / sizeof(cufftComplex)),
(long)(d_out_signal->descriptor->size[1] / sizeof(cufftComplex)));
// cufftXtMemcpy() - Copy the data to natural order on GPUs
checkCudaErrors(cufftXtMemcpy(plan_input, d_out_signal, d_signal, CUFFT_COPY_DEVICE_TO_DEVICE));
checkCudaErrors(cufftXtMemcpy(plan_input, d_out_filter_kernel, d_filter_kernel, CUFFT_COPY_DEVICE_TO_DEVICE));
// Multiply the coefficients together and normalize the result
printf("Launching ComplexPointwiseMulAndScale<<< >>>\n");
multiplyCoefficient(d_out_signal, d_out_filter_kernel, new_size,
1.0f / new_size, nGPUs);
printf("\n\nValue of Library Descriptor\n");
printf("Number of GPUs %d\n", d_out_signal->descriptor->nGPUs);
printf("Device id %d %d\n", d_out_signal->descriptor->GPUs[0], d_out_signal->descriptor->GPUs[1]);
printf("Data size on GPU %ld %ld\n",
(long)(d_out_signal->descriptor->size[0] / sizeof(cufftComplex)),
(long)(d_out_signal->descriptor->size[1] / sizeof(cufftComplex)));
// cufftXtExecDescriptorC2C() - Execute inverse FFT on data on multiple GPUs
printf("Transforming signal back cufftExecC2C\n");
checkCudaErrors(cufftXtExecDescriptorC2C(plan_input, d_out_signal,
d_out_signal, CUFFT_INVERSE));
// Multiply the coefficients together and normalize the result
printf("Launching ComplexPointwiseMulAndScale<<< >>>\n");
multiplyCoefficient(d_out_signal, d_out_filter_kernel, new_size, 1.0f / new_size, nGPUs);
// Create host pointer pointing to padded signal
Complex *h_convolved_signal = h_padded_signal;
// cufftXtExecDescriptorC2C() - Execute inverse FFT on data on multiple GPUs
printf("Transforming signal back cufftExecC2C\n");
checkCudaErrors(cufftXtExecDescriptorC2C(plan_input, d_out_signal, d_out_signal, CUFFT_INVERSE));
// Allocate host memory for the convolution result
Complex *h_convolved_signal_ref =
(Complex *)malloc(sizeof(Complex) * SIGNAL_SIZE);
// Create host pointer pointing to padded signal
Complex *h_convolved_signal = h_padded_signal;
// cufftXtMemcpy() - Copy data from multiple GPUs to host
checkCudaErrors(cufftXtMemcpy(plan_input, h_convolved_signal, d_out_signal,
CUFFT_COPY_DEVICE_TO_HOST));
// Allocate host memory for the convolution result
Complex *h_convolved_signal_ref = (Complex *)malloc(sizeof(Complex) * SIGNAL_SIZE);
// Convolve on the host
Convolve(h_signal, SIGNAL_SIZE, h_filter_kernel, FILTER_KERNEL_SIZE,
h_convolved_signal_ref);
// cufftXtMemcpy() - Copy data from multiple GPUs to host
checkCudaErrors(cufftXtMemcpy(plan_input, h_convolved_signal, d_out_signal, CUFFT_COPY_DEVICE_TO_HOST));
// Compare CPU and GPU result
bool bTestResult =
sdkCompareL2fe((float *)h_convolved_signal_ref,
(float *)h_convolved_signal, 2 * SIGNAL_SIZE, 1e-5f);
printf("\nvalue of TestResult %d\n", bTestResult);
// Convolve on the host
Convolve(h_signal, SIGNAL_SIZE, h_filter_kernel, FILTER_KERNEL_SIZE, h_convolved_signal_ref);
// Cleanup memory
free(whichGPUs);
free(worksize);
free(h_signal);
free(h_filter_kernel);
free(h_padded_signal);
free(h_padded_filter_kernel);
free(h_convolved_signal_ref);
// Compare CPU and GPU result
bool bTestResult =
sdkCompareL2fe((float *)h_convolved_signal_ref, (float *)h_convolved_signal, 2 * SIGNAL_SIZE, 1e-5f);
printf("\nvalue of TestResult %d\n", bTestResult);
// cudaXtFree() - Free GPU memory
checkCudaErrors(cufftXtFree(d_signal));
checkCudaErrors(cufftXtFree(d_filter_kernel));
checkCudaErrors(cufftXtFree(d_out_signal));
checkCudaErrors(cufftXtFree(d_out_filter_kernel));
// Cleanup memory
free(whichGPUs);
free(worksize);
free(h_signal);
free(h_filter_kernel);
free(h_padded_signal);
free(h_padded_filter_kernel);
free(h_convolved_signal_ref);
// cufftDestroy() - Destroy FFT plan
checkCudaErrors(cufftDestroy(plan_input));
// cudaXtFree() - Free GPU memory
checkCudaErrors(cufftXtFree(d_signal));
checkCudaErrors(cufftXtFree(d_filter_kernel));
checkCudaErrors(cufftXtFree(d_out_signal));
checkCudaErrors(cufftXtFree(d_out_filter_kernel));
exit(bTestResult ? EXIT_SUCCESS : EXIT_FAILURE);
// cufftDestroy() - Destroy FFT plan
checkCudaErrors(cufftDestroy(plan_input));
exit(bTestResult ? EXIT_SUCCESS : EXIT_FAILURE);
}
///////////////////////////////////////////////////////////////////////////////////
// Function for padding original data
//////////////////////////////////////////////////////////////////////////////////
int PadData(const Complex *signal, Complex **padded_signal, int signal_size,
const Complex *filter_kernel, Complex **padded_filter_kernel,
int filter_kernel_size) {
int minRadius = filter_kernel_size / 2;
int maxRadius = filter_kernel_size - minRadius;
int new_size = signal_size + maxRadius;
int PadData(const Complex *signal,
Complex **padded_signal,
int signal_size,
const Complex *filter_kernel,
Complex **padded_filter_kernel,
int filter_kernel_size)
{
int minRadius = filter_kernel_size / 2;
int maxRadius = filter_kernel_size - minRadius;
int new_size = signal_size + maxRadius;
// Pad signal
Complex *new_data = (Complex *)malloc(sizeof(Complex) * new_size);
memcpy(new_data + 0, signal, signal_size * sizeof(Complex));
memset(new_data + signal_size, 0, (new_size - signal_size) * sizeof(Complex));
*padded_signal = new_data;
// Pad signal
Complex *new_data = (Complex *)malloc(sizeof(Complex) * new_size);
memcpy(new_data + 0, signal, signal_size * sizeof(Complex));
memset(new_data + signal_size, 0, (new_size - signal_size) * sizeof(Complex));
*padded_signal = new_data;
// Pad filter
new_data = (Complex *)malloc(sizeof(Complex) * new_size);
memcpy(new_data + 0, filter_kernel + minRadius, maxRadius * sizeof(Complex));
memset(new_data + maxRadius, 0,
(new_size - filter_kernel_size) * sizeof(Complex));
memcpy(new_data + new_size - minRadius, filter_kernel,
minRadius * sizeof(Complex));
*padded_filter_kernel = new_data;
// Pad filter
new_data = (Complex *)malloc(sizeof(Complex) * new_size);
memcpy(new_data + 0, filter_kernel + minRadius, maxRadius * sizeof(Complex));
memset(new_data + maxRadius, 0, (new_size - filter_kernel_size) * sizeof(Complex));
memcpy(new_data + new_size - minRadius, filter_kernel, minRadius * sizeof(Complex));
*padded_filter_kernel = new_data;
return new_size;
return new_size;
}
////////////////////////////////////////////////////////////////////////////////
// Filtering operations - Computing Convolution on the host
////////////////////////////////////////////////////////////////////////////////
void Convolve(const Complex *signal, int signal_size,
const Complex *filter_kernel, int filter_kernel_size,
Complex *filtered_signal) {
int minRadius = filter_kernel_size / 2;
int maxRadius = filter_kernel_size - minRadius;
void Convolve(const Complex *signal,
int signal_size,
const Complex *filter_kernel,
int filter_kernel_size,
Complex *filtered_signal)
{
int minRadius = filter_kernel_size / 2;
int maxRadius = filter_kernel_size - minRadius;
// Loop over output element indices
for (int i = 0; i < signal_size; ++i) {
filtered_signal[i].x = filtered_signal[i].y = 0;
// Loop over output element indices
for (int i = 0; i < signal_size; ++i) {
filtered_signal[i].x = filtered_signal[i].y = 0;
// Loop over convolution indices
for (int j = -maxRadius + 1; j <= minRadius; ++j) {
int k = i + j;
// Loop over convolution indices
for (int j = -maxRadius + 1; j <= minRadius; ++j) {
int k = i + j;
if (k >= 0 && k < signal_size) {
filtered_signal[i] =
ComplexAdd(filtered_signal[i],
ComplexMul(signal[k], filter_kernel[minRadius - j]));
}
if (k >= 0 && k < signal_size) {
filtered_signal[i] =
ComplexAdd(filtered_signal[i], ComplexMul(signal[k], filter_kernel[minRadius - j]));
}
}
}
}
}
////////////////////////////////////////////////////////////////////////////////
// Launch Kernel on multiple GPU
////////////////////////////////////////////////////////////////////////////////
void multiplyCoefficient(cudaLibXtDesc *d_signal,
cudaLibXtDesc *d_filter_kernel, int new_size,
float val, int nGPUs) {
int device;
// Launch the ComplexPointwiseMulAndScale<<< >>> kernel on multiple GPU
for (int i = 0; i < nGPUs; i++) {
device = d_signal->descriptor->GPUs[i];
void multiplyCoefficient(cudaLibXtDesc *d_signal, cudaLibXtDesc *d_filter_kernel, int new_size, float val, int nGPUs)
{
int device;
// Launch the ComplexPointwiseMulAndScale<<< >>> kernel on multiple GPU
for (int i = 0; i < nGPUs; i++) {
device = d_signal->descriptor->GPUs[i];
// Set device
checkCudaErrors(cudaSetDevice(device));
// Set device
checkCudaErrors(cudaSetDevice(device));
// Perform GPU computations
ComplexPointwiseMulAndScale<<<32, 256>>>(
(cufftComplex *)d_signal->descriptor->data[i],
(cufftComplex *)d_filter_kernel->descriptor->data[i],
int(d_signal->descriptor->size[i] / sizeof(cufftComplex)), val);
}
// Perform GPU computations
ComplexPointwiseMulAndScale<<<32, 256>>>((cufftComplex *)d_signal->descriptor->data[i],
(cufftComplex *)d_filter_kernel->descriptor->data[i],
int(d_signal->descriptor->size[i] / sizeof(cufftComplex)),
val);
}
// Wait for device to finish all operation
for (int i = 0; i < nGPUs; i++) {
device = d_signal->descriptor->GPUs[i];
checkCudaErrors(cudaSetDevice(device));
cudaDeviceSynchronize();
// Check if kernel execution generated and error
getLastCudaError("Kernel execution failed [ ComplexPointwiseMulAndScale ]");
}
// Wait for device to finish all operation
for (int i = 0; i < nGPUs; i++) {
device = d_signal->descriptor->GPUs[i];
checkCudaErrors(cudaSetDevice(device));
cudaDeviceSynchronize();
// Check if kernel execution generated and error
getLastCudaError("Kernel execution failed [ ComplexPointwiseMulAndScale ]");
}
}
////////////////////////////////////////////////////////////////////////////////
@@ -366,35 +351,37 @@ void multiplyCoefficient(cudaLibXtDesc *d_signal,
////////////////////////////////////////////////////////////////////////////////
// Complex addition
static __device__ __host__ inline Complex ComplexAdd(Complex a, Complex b) {
Complex c;
c.x = a.x + b.x;
c.y = a.y + b.y;
return c;
static __device__ __host__ inline Complex ComplexAdd(Complex a, Complex b)
{
Complex c;
c.x = a.x + b.x;
c.y = a.y + b.y;
return c;
}
// Complex scale
static __device__ __host__ inline Complex ComplexScale(Complex a, float s) {
Complex c;
c.x = s * a.x;
c.y = s * a.y;
return c;
static __device__ __host__ inline Complex ComplexScale(Complex a, float s)
{
Complex c;
c.x = s * a.x;
c.y = s * a.y;
return c;
}
// Complex multiplication
static __device__ __host__ inline Complex ComplexMul(Complex a, Complex b) {
Complex c;
c.x = a.x * b.x - a.y * b.y;
c.y = a.x * b.y + a.y * b.x;
return c;
static __device__ __host__ inline Complex ComplexMul(Complex a, Complex b)
{
Complex c;
c.x = a.x * b.x - a.y * b.y;
c.y = a.x * b.y + a.y * b.x;
return c;
}
// Complex pointwise multiplication
static __global__ void ComplexPointwiseMulAndScale(cufftComplex *a,
cufftComplex *b, int size,
float scale) {
const int numThreads = blockDim.x * gridDim.x;
const int threadID = blockIdx.x * blockDim.x + threadIdx.x;
for (int i = threadID; i < size; i += numThreads) {
a[i] = ComplexScale(ComplexMul(a[i], b[i]), scale);
}
static __global__ void ComplexPointwiseMulAndScale(cufftComplex *a, cufftComplex *b, int size, float scale)
{
const int numThreads = blockDim.x * gridDim.x;
const int threadID = blockIdx.x * blockDim.x + threadIdx.x;
for (int i = threadID; i < size; i += numThreads) {
a[i] = ComplexScale(ComplexMul(a[i], b[i]), scale);
}
}

View File

@@ -26,54 +26,48 @@
*/
/*
* Example showing the use of CUFFT for fast 1D-convolution using FFT.
/*
* Example showing the use of CUFFT for fast 1D-convolution using FFT.
* This sample is the same as simpleCUFFT, except that it uses a callback
* function to perform the pointwise multiply and scale, on input to the
* inverse transform.
*
*/
*
*/
// includes, system
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// includes, project
#include <cuda_runtime.h>
#include <cufft.h>
#include <cufftXt.h>
#include <helper_functions.h>
#include <helper_cuda.h>
#include <helper_functions.h>
// Complex data type
typedef float2 Complex;
typedef float2 Complex;
static __device__ __host__ inline Complex ComplexAdd(Complex, Complex);
static __device__ __host__ inline Complex ComplexScale(Complex, float);
static __device__ __host__ inline Complex ComplexMul(Complex, Complex);
// This is the callback routine prototype
static __device__ cufftComplex ComplexPointwiseMulAndScale(void *a,
size_t index,
void *cb_info,
void *sharedmem);
static __device__ cufftComplex ComplexPointwiseMulAndScale(void *a, size_t index, void *cb_info, void *sharedmem);
typedef struct _cb_params {
Complex *filter;
float scale;
typedef struct _cb_params
{
Complex *filter;
float scale;
} cb_params;
// This is the callback routine. It does complex pointwise multiplication with
// scaling.
static __device__ cufftComplex ComplexPointwiseMulAndScale(void *a,
size_t index,
void *cb_info,
void *sharedmem) {
cb_params *my_params = (cb_params *)cb_info;
return (cufftComplex)ComplexScale(
ComplexMul(((Complex *)a)[index], (my_params->filter)[index]),
my_params->scale);
static __device__ cufftComplex ComplexPointwiseMulAndScale(void *a, size_t index, void *cb_info, void *sharedmem)
{
cb_params *my_params = (cb_params *)cb_info;
return (cufftComplex)ComplexScale(ComplexMul(((Complex *)a)[index], (my_params->filter)[index]), my_params->scale);
}
// Define the device pointer to the callback routine. The host code will fetch
@@ -90,193 +84,183 @@ int PadData(const Complex *, Complex **, int, const Complex *, Complex **, int);
int runTest(int argc, char **argv);
// The filter size is assumed to be a number smaller than the signal size
#define SIGNAL_SIZE 50
#define SIGNAL_SIZE 50
#define FILTER_KERNEL_SIZE 11
////////////////////////////////////////////////////////////////////////////////
// Program main
////////////////////////////////////////////////////////////////////////////////
int main(int argc, char **argv) {
struct cudaDeviceProp properties;
int device;
checkCudaErrors(cudaGetDevice(&device));
checkCudaErrors(cudaGetDeviceProperties(&properties, device));
if (!(properties.major >= 2)) {
printf("simpleCUFFT_callback requires CUDA architecture SM2.0 or higher\n");
return EXIT_WAIVED;
}
int main(int argc, char **argv)
{
struct cudaDeviceProp properties;
int device;
checkCudaErrors(cudaGetDevice(&device));
checkCudaErrors(cudaGetDeviceProperties(&properties, device));
if (!(properties.major >= 2)) {
printf("simpleCUFFT_callback requires CUDA architecture SM2.0 or higher\n");
return EXIT_WAIVED;
}
return runTest(argc, argv);
return runTest(argc, argv);
}
////////////////////////////////////////////////////////////////////////////////
//! Run a simple test for CUFFT callbacks
////////////////////////////////////////////////////////////////////////////////
int runTest(int argc, char **argv) {
printf("[simpleCUFFT_callback] is starting...\n");
int runTest(int argc, char **argv)
{
printf("[simpleCUFFT_callback] is starting...\n");
findCudaDevice(argc, (const char **)argv);
findCudaDevice(argc, (const char **)argv);
// Allocate host memory for the signal
Complex *h_signal = (Complex *)malloc(sizeof(Complex) * SIGNAL_SIZE);
// Allocate host memory for the signal
Complex *h_signal = (Complex *)malloc(sizeof(Complex) * SIGNAL_SIZE);
// Initialize the memory for the signal
for (unsigned int i = 0; i < SIGNAL_SIZE; ++i) {
h_signal[i].x = rand() / (float)RAND_MAX;
h_signal[i].y = 0;
}
// Initialize the memory for the signal
for (unsigned int i = 0; i < SIGNAL_SIZE; ++i) {
h_signal[i].x = rand() / (float)RAND_MAX;
h_signal[i].y = 0;
}
// Allocate host memory for the filter
Complex *h_filter_kernel =
(Complex *)malloc(sizeof(Complex) * FILTER_KERNEL_SIZE);
// Allocate host memory for the filter
Complex *h_filter_kernel = (Complex *)malloc(sizeof(Complex) * FILTER_KERNEL_SIZE);
// Initialize the memory for the filter
for (unsigned int i = 0; i < FILTER_KERNEL_SIZE; ++i) {
h_filter_kernel[i].x = rand() / (float)RAND_MAX;
h_filter_kernel[i].y = 0;
}
// Initialize the memory for the filter
for (unsigned int i = 0; i < FILTER_KERNEL_SIZE; ++i) {
h_filter_kernel[i].x = rand() / (float)RAND_MAX;
h_filter_kernel[i].y = 0;
}
// Pad signal and filter kernel
Complex *h_padded_signal;
Complex *h_padded_filter_kernel;
int new_size =
PadData(h_signal, &h_padded_signal, SIGNAL_SIZE, h_filter_kernel,
&h_padded_filter_kernel, FILTER_KERNEL_SIZE);
int mem_size = sizeof(Complex) * new_size;
// Pad signal and filter kernel
Complex *h_padded_signal;
Complex *h_padded_filter_kernel;
int new_size =
PadData(h_signal, &h_padded_signal, SIGNAL_SIZE, h_filter_kernel, &h_padded_filter_kernel, FILTER_KERNEL_SIZE);
int mem_size = sizeof(Complex) * new_size;
// Allocate device memory for signal
Complex *d_signal;
checkCudaErrors(cudaMalloc((void **)&d_signal, mem_size));
// Copy host memory to device
checkCudaErrors(
cudaMemcpy(d_signal, h_padded_signal, mem_size, cudaMemcpyHostToDevice));
// Allocate device memory for signal
Complex *d_signal;
checkCudaErrors(cudaMalloc((void **)&d_signal, mem_size));
// Copy host memory to device
checkCudaErrors(cudaMemcpy(d_signal, h_padded_signal, mem_size, cudaMemcpyHostToDevice));
// Allocate device memory for filter kernel
Complex *d_filter_kernel;
checkCudaErrors(cudaMalloc((void **)&d_filter_kernel, mem_size));
// Allocate device memory for filter kernel
Complex *d_filter_kernel;
checkCudaErrors(cudaMalloc((void **)&d_filter_kernel, mem_size));
// Copy host memory to device
checkCudaErrors(cudaMemcpy(d_filter_kernel, h_padded_filter_kernel, mem_size,
cudaMemcpyHostToDevice));
// Copy host memory to device
checkCudaErrors(cudaMemcpy(d_filter_kernel, h_padded_filter_kernel, mem_size, cudaMemcpyHostToDevice));
// Create one CUFFT plan for the forward transforms, and one for the reverse
// transform with load callback.
cufftHandle plan, cb_plan;
size_t work_size;
// Create one CUFFT plan for the forward transforms, and one for the reverse
// transform with load callback.
cufftHandle plan, cb_plan;
size_t work_size;
checkCudaErrors(cufftCreate(&plan));
checkCudaErrors(cufftCreate(&cb_plan));
checkCudaErrors(cufftCreate(&plan));
checkCudaErrors(cufftCreate(&cb_plan));
checkCudaErrors(cufftMakePlan1d(plan, new_size, CUFFT_C2C, 1, &work_size));
checkCudaErrors(cufftMakePlan1d(cb_plan, new_size, CUFFT_C2C, 1, &work_size));
checkCudaErrors(cufftMakePlan1d(plan, new_size, CUFFT_C2C, 1, &work_size));
checkCudaErrors(cufftMakePlan1d(cb_plan, new_size, CUFFT_C2C, 1, &work_size));
// Define a structure used to pass in the device address of the filter kernel,
// and the scale factor
cb_params h_params;
// Define a structure used to pass in the device address of the filter kernel,
// and the scale factor
cb_params h_params;
h_params.filter = d_filter_kernel;
h_params.scale = 1.0f / new_size;
h_params.filter = d_filter_kernel;
h_params.scale = 1.0f / new_size;
// Allocate device memory for parameters
cb_params *d_params;
checkCudaErrors(cudaMalloc((void **)&d_params, sizeof(cb_params)));
// Allocate device memory for parameters
cb_params *d_params;
checkCudaErrors(cudaMalloc((void **)&d_params, sizeof(cb_params)));
// Copy host memory to device
checkCudaErrors(cudaMemcpy(d_params, &h_params, sizeof(cb_params),
cudaMemcpyHostToDevice));
// Copy host memory to device
checkCudaErrors(cudaMemcpy(d_params, &h_params, sizeof(cb_params), cudaMemcpyHostToDevice));
// The host needs to get a copy of the device pointer to the callback
cufftCallbackLoadC hostCopyOfCallbackPtr;
// The host needs to get a copy of the device pointer to the callback
cufftCallbackLoadC hostCopyOfCallbackPtr;
checkCudaErrors(cudaMemcpyFromSymbol(&hostCopyOfCallbackPtr, myOwnCallbackPtr,
sizeof(hostCopyOfCallbackPtr)));
checkCudaErrors(cudaMemcpyFromSymbol(&hostCopyOfCallbackPtr, myOwnCallbackPtr, sizeof(hostCopyOfCallbackPtr)));
// Now associate the load callback with the plan.
cufftResult status =
cufftXtSetCallback(cb_plan, (void **)&hostCopyOfCallbackPtr,
CUFFT_CB_LD_COMPLEX, (void **)&d_params);
if (status == CUFFT_LICENSE_ERROR) {
printf("This sample requires a valid license file.\n");
printf(
"The file was either not found, out of date, or otherwise invalid.\n");
return EXIT_WAIVED;
}
// Now associate the load callback with the plan.
cufftResult status =
cufftXtSetCallback(cb_plan, (void **)&hostCopyOfCallbackPtr, CUFFT_CB_LD_COMPLEX, (void **)&d_params);
if (status == CUFFT_LICENSE_ERROR) {
printf("This sample requires a valid license file.\n");
printf("The file was either not found, out of date, or otherwise invalid.\n");
return EXIT_WAIVED;
}
checkCudaErrors(cufftXtSetCallback(cb_plan, (void **)&hostCopyOfCallbackPtr,
CUFFT_CB_LD_COMPLEX, (void **)&d_params));
checkCudaErrors(
cufftXtSetCallback(cb_plan, (void **)&hostCopyOfCallbackPtr, CUFFT_CB_LD_COMPLEX, (void **)&d_params));
// Transform signal and kernel
printf("Transforming signal cufftExecC2C\n");
checkCudaErrors(cufftExecC2C(plan, (cufftComplex *)d_signal,
(cufftComplex *)d_signal, CUFFT_FORWARD));
checkCudaErrors(cufftExecC2C(plan, (cufftComplex *)d_filter_kernel,
(cufftComplex *)d_filter_kernel, CUFFT_FORWARD));
// Transform signal and kernel
printf("Transforming signal cufftExecC2C\n");
checkCudaErrors(cufftExecC2C(plan, (cufftComplex *)d_signal, (cufftComplex *)d_signal, CUFFT_FORWARD));
checkCudaErrors(
cufftExecC2C(plan, (cufftComplex *)d_filter_kernel, (cufftComplex *)d_filter_kernel, CUFFT_FORWARD));
// Transform signal back, using the callback to do the pointwise multiply on
// the way in.
printf("Transforming signal back cufftExecC2C\n");
checkCudaErrors(cufftExecC2C(cb_plan, (cufftComplex *)d_signal,
(cufftComplex *)d_signal, CUFFT_INVERSE));
// Transform signal back, using the callback to do the pointwise multiply on
// the way in.
printf("Transforming signal back cufftExecC2C\n");
checkCudaErrors(cufftExecC2C(cb_plan, (cufftComplex *)d_signal, (cufftComplex *)d_signal, CUFFT_INVERSE));
// Copy device memory to host
Complex *h_convolved_signal = h_padded_signal;
checkCudaErrors(cudaMemcpy(h_convolved_signal, d_signal, mem_size,
cudaMemcpyDeviceToHost));
// Copy device memory to host
Complex *h_convolved_signal = h_padded_signal;
checkCudaErrors(cudaMemcpy(h_convolved_signal, d_signal, mem_size, cudaMemcpyDeviceToHost));
// Allocate host memory for the convolution result
Complex *h_convolved_signal_ref =
(Complex *)malloc(sizeof(Complex) * SIGNAL_SIZE);
// Allocate host memory for the convolution result
Complex *h_convolved_signal_ref = (Complex *)malloc(sizeof(Complex) * SIGNAL_SIZE);
// Convolve on the host
Convolve(h_signal, SIGNAL_SIZE, h_filter_kernel, FILTER_KERNEL_SIZE,
h_convolved_signal_ref);
// Convolve on the host
Convolve(h_signal, SIGNAL_SIZE, h_filter_kernel, FILTER_KERNEL_SIZE, h_convolved_signal_ref);
// check result
bool bTestResult =
sdkCompareL2fe((float *)h_convolved_signal_ref,
(float *)h_convolved_signal, 2 * SIGNAL_SIZE, 1e-5f);
// check result
bool bTestResult =
sdkCompareL2fe((float *)h_convolved_signal_ref, (float *)h_convolved_signal, 2 * SIGNAL_SIZE, 1e-5f);
// Destroy CUFFT context
checkCudaErrors(cufftDestroy(plan));
checkCudaErrors(cufftDestroy(cb_plan));
// Destroy CUFFT context
checkCudaErrors(cufftDestroy(plan));
checkCudaErrors(cufftDestroy(cb_plan));
// cleanup memory
free(h_signal);
free(h_filter_kernel);
free(h_padded_signal);
free(h_padded_filter_kernel);
free(h_convolved_signal_ref);
checkCudaErrors(cudaFree(d_signal));
checkCudaErrors(cudaFree(d_filter_kernel));
checkCudaErrors(cudaFree(d_params));
// cleanup memory
free(h_signal);
free(h_filter_kernel);
free(h_padded_signal);
free(h_padded_filter_kernel);
free(h_convolved_signal_ref);
checkCudaErrors(cudaFree(d_signal));
checkCudaErrors(cudaFree(d_filter_kernel));
checkCudaErrors(cudaFree(d_params));
return bTestResult ? EXIT_SUCCESS : EXIT_FAILURE;
return bTestResult ? EXIT_SUCCESS : EXIT_FAILURE;
}
// Pad data
int PadData(const Complex *signal, Complex **padded_signal, int signal_size,
const Complex *filter_kernel, Complex **padded_filter_kernel,
int filter_kernel_size) {
int minRadius = filter_kernel_size / 2;
int maxRadius = filter_kernel_size - minRadius;
int new_size = signal_size + maxRadius;
int PadData(const Complex *signal,
Complex **padded_signal,
int signal_size,
const Complex *filter_kernel,
Complex **padded_filter_kernel,
int filter_kernel_size)
{
int minRadius = filter_kernel_size / 2;
int maxRadius = filter_kernel_size - minRadius;
int new_size = signal_size + maxRadius;
// Pad signal
Complex *new_data = (Complex *)malloc(sizeof(Complex) * new_size);
memcpy(new_data + 0, signal, signal_size * sizeof(Complex));
memset(new_data + signal_size, 0, (new_size - signal_size) * sizeof(Complex));
*padded_signal = new_data;
// Pad signal
Complex *new_data = (Complex *)malloc(sizeof(Complex) * new_size);
memcpy(new_data + 0, signal, signal_size * sizeof(Complex));
memset(new_data + signal_size, 0, (new_size - signal_size) * sizeof(Complex));
*padded_signal = new_data;
// Pad filter
new_data = (Complex *)malloc(sizeof(Complex) * new_size);
memcpy(new_data + 0, filter_kernel + minRadius, maxRadius * sizeof(Complex));
memset(new_data + maxRadius, 0,
(new_size - filter_kernel_size) * sizeof(Complex));
memcpy(new_data + new_size - minRadius, filter_kernel,
minRadius * sizeof(Complex));
*padded_filter_kernel = new_data;
// Pad filter
new_data = (Complex *)malloc(sizeof(Complex) * new_size);
memcpy(new_data + 0, filter_kernel + minRadius, maxRadius * sizeof(Complex));
memset(new_data + maxRadius, 0, (new_size - filter_kernel_size) * sizeof(Complex));
memcpy(new_data + new_size - minRadius, filter_kernel, minRadius * sizeof(Complex));
*padded_filter_kernel = new_data;
return new_size;
return new_size;
}
////////////////////////////////////////////////////////////////////////////////
@@ -284,27 +268,29 @@ int PadData(const Complex *signal, Complex **padded_signal, int signal_size,
////////////////////////////////////////////////////////////////////////////////
// Computes convolution on the host
void Convolve(const Complex *signal, int signal_size,
const Complex *filter_kernel, int filter_kernel_size,
Complex *filtered_signal) {
int minRadius = filter_kernel_size / 2;
int maxRadius = filter_kernel_size - minRadius;
void Convolve(const Complex *signal,
int signal_size,
const Complex *filter_kernel,
int filter_kernel_size,
Complex *filtered_signal)
{
int minRadius = filter_kernel_size / 2;
int maxRadius = filter_kernel_size - minRadius;
// Loop over output element indices
for (int i = 0; i < signal_size; ++i) {
filtered_signal[i].x = filtered_signal[i].y = 0;
// Loop over output element indices
for (int i = 0; i < signal_size; ++i) {
filtered_signal[i].x = filtered_signal[i].y = 0;
// Loop over convolution indices
for (int j = -maxRadius + 1; j <= minRadius; ++j) {
int k = i + j;
// Loop over convolution indices
for (int j = -maxRadius + 1; j <= minRadius; ++j) {
int k = i + j;
if (k >= 0 && k < signal_size) {
filtered_signal[i] =
ComplexAdd(filtered_signal[i],
ComplexMul(signal[k], filter_kernel[minRadius - j]));
}
if (k >= 0 && k < signal_size) {
filtered_signal[i] =
ComplexAdd(filtered_signal[i], ComplexMul(signal[k], filter_kernel[minRadius - j]));
}
}
}
}
}
////////////////////////////////////////////////////////////////////////////////
@@ -312,25 +298,28 @@ void Convolve(const Complex *signal, int signal_size,
////////////////////////////////////////////////////////////////////////////////
// Complex addition
static __device__ __host__ inline Complex ComplexAdd(Complex a, Complex b) {
Complex c;
c.x = a.x + b.x;
c.y = a.y + b.y;
return c;
static __device__ __host__ inline Complex ComplexAdd(Complex a, Complex b)
{
Complex c;
c.x = a.x + b.x;
c.y = a.y + b.y;
return c;
}
// Complex scale
static __device__ __host__ inline Complex ComplexScale(Complex a, float s) {
Complex c;
c.x = s * a.x;
c.y = s * a.y;
return c;
static __device__ __host__ inline Complex ComplexScale(Complex a, float s)
{
Complex c;
c.x = s * a.x;
c.y = s * a.y;
return c;
}
// Complex multiplication
static __device__ __host__ inline Complex ComplexMul(Complex a, Complex b) {
Complex c;
c.x = a.x * b.x - a.y * b.y;
c.y = a.x * b.y + a.y * b.x;
return c;
static __device__ __host__ inline Complex ComplexMul(Complex a, Complex b)
{
Complex c;
c.x = a.x * b.x - a.y * b.y;
c.y = a.x * b.y + a.y * b.x;
return c;
}

View File

@@ -27,42 +27,42 @@
#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
# define WINDOWS_LEAN_AND_MEAN
# define NOMINMAX
# include <windows.h>
# pragma warning(disable:4819)
#define WINDOWS_LEAN_AND_MEAN
#define NOMINMAX
#include <windows.h>
#pragma warning(disable : 4819)
#endif
#include <fstream>
#include <helper_cuda.h>
#include <npp.h>
#include <stdio.h>
#include <string.h>
#include <fstream>
#include <npp.h>
#include <helper_cuda.h>
// Note: If you want to view these images we HIGHLY recommend using imagej which is free on the internet and works on most platforms
// because it is one of the few image viewing apps that can display 32 bit integer image data. While it normalizes the data
// to floating point values for viewing it still provides a good representation of the relative brightness of each label value.
// Note: If you want to view these images we HIGHLY recommend using imagej which is free on the internet and works on
// most platforms
// because it is one of the few image viewing apps that can display 32 bit integer image data. While it
// normalizes the data to floating point values for viewing it still provides a good representation of the
// relative brightness of each label value.
//
// The files read and written by this sample app use RAW image format, that is, only the image data itself exists in the files
// with no image format information. When viewing RAW files with imagej just enter the image size and bit depth values that
// are part of the file name when requested by imagej.
// The files read and written by this sample app use RAW image format, that is, only the image data itself exists
// in the files with no image format information. When viewing RAW files with imagej just enter the image size
// and bit depth values that are part of the file name when requested by imagej.
//
#define NUMBER_OF_IMAGES 3
Npp8u * pInputImageDev[NUMBER_OF_IMAGES];
Npp8u * pInputImageHost[NUMBER_OF_IMAGES];
Npp8u * pSegmentationScratchBufferDev[NUMBER_OF_IMAGES];
Npp8u * pSegmentsDev[NUMBER_OF_IMAGES];
Npp8u * pSegmentsHost[NUMBER_OF_IMAGES];
Npp32u * pSegmentLabelsOutputBufferDev[NUMBER_OF_IMAGES];
Npp32u * pSegmentLabelsOutputBufferHost[NUMBER_OF_IMAGES];
Npp8u *pInputImageDev[NUMBER_OF_IMAGES];
Npp8u *pInputImageHost[NUMBER_OF_IMAGES];
Npp8u *pSegmentationScratchBufferDev[NUMBER_OF_IMAGES];
Npp8u *pSegmentsDev[NUMBER_OF_IMAGES];
Npp8u *pSegmentsHost[NUMBER_OF_IMAGES];
Npp32u *pSegmentLabelsOutputBufferDev[NUMBER_OF_IMAGES];
Npp32u *pSegmentLabelsOutputBufferHost[NUMBER_OF_IMAGES];
void tearDown() // Clean up and tear down
{
for (int j = 0; j < NUMBER_OF_IMAGES; j++)
{
for (int j = 0; j < NUMBER_OF_IMAGES; j++) {
if (pSegmentLabelsOutputBufferDev[j] != 0)
cudaFree(pSegmentLabelsOutputBufferDev[j]);
if (pSegmentationScratchBufferDev[j] != 0)
@@ -80,129 +80,120 @@ void tearDown() // Clean up and tear down
}
}
const std::string& SegmentsOutputFile0 = "teapot_Segments_8Way_512x512_8u.raw";
const std::string& SegmentsOutputFile1 = "CT_skull_Segments_8Way_512x512_8u.raw";
const std::string& SegmentsOutputFile2 = "Rocks_Segments_8Way_512x512_8u.raw";
const std::string &SegmentsOutputFile0 = "teapot_Segments_8Way_512x512_8u.raw";
const std::string &SegmentsOutputFile1 = "CT_skull_Segments_8Way_512x512_8u.raw";
const std::string &SegmentsOutputFile2 = "Rocks_Segments_8Way_512x512_8u.raw";
const std::string& SegmentBoundariesOutputFile0 = "teapot_SegmentBoundaries_8Way_512x512_8u.raw";
const std::string& SegmentBoundariesOutputFile1 = "CT_skull_SegmentBoundaries_8Way_512x512_8u.raw";
const std::string& SegmentBoundariesOutputFile2 = "Rocks_SegmentBoundaries_8Way_512x512_8u.raw";
const std::string &SegmentBoundariesOutputFile0 = "teapot_SegmentBoundaries_8Way_512x512_8u.raw";
const std::string &SegmentBoundariesOutputFile1 = "CT_skull_SegmentBoundaries_8Way_512x512_8u.raw";
const std::string &SegmentBoundariesOutputFile2 = "Rocks_SegmentBoundaries_8Way_512x512_8u.raw";
const std::string& SegmentsWithContrastingBoundariesOutputFile0 = "teapot_SegmentsWithContrastingBoundaries_8Way_512x512_8u.raw";
const std::string& SegmentsWithContrastingBoundariesOutputFile1 = "CT_skull_SegmentsWithContrastingBoundaries_8Way_512x512_8u.raw";
const std::string& SegmentsWithContrastingBoundariesOutputFile2 = "Rocks_SegmentsWithContrastingBoundaries_8Way_512x512_8u.raw";
const std::string &SegmentsWithContrastingBoundariesOutputFile0 =
"teapot_SegmentsWithContrastingBoundaries_8Way_512x512_8u.raw";
const std::string &SegmentsWithContrastingBoundariesOutputFile1 =
"CT_skull_SegmentsWithContrastingBoundaries_8Way_512x512_8u.raw";
const std::string &SegmentsWithContrastingBoundariesOutputFile2 =
"Rocks_SegmentsWithContrastingBoundaries_8Way_512x512_8u.raw";
const std::string& CompressedSegmentLabelsOutputFile0 = "teapot_CompressedSegmentLabels_8Way_512x512_32u.raw";
const std::string& CompressedSegmentLabelsOutputFile1 = "CT_skull_CompressedSegmentLabels_8Way_512x512_32u.raw";
const std::string& CompressedSegmentLabelsOutputFile2 = "Rocks_CompressedSegmentLabels_8Way_512x512_32u.raw";
const std::string &CompressedSegmentLabelsOutputFile0 = "teapot_CompressedSegmentLabels_8Way_512x512_32u.raw";
const std::string &CompressedSegmentLabelsOutputFile1 = "CT_skull_CompressedSegmentLabels_8Way_512x512_32u.raw";
const std::string &CompressedSegmentLabelsOutputFile2 = "Rocks_CompressedSegmentLabels_8Way_512x512_32u.raw";
int
loadRaw8BitImage(Npp8u * pImage, int nWidth, int nHeight, int nImage)
int loadRaw8BitImage(Npp8u *pImage, int nWidth, int nHeight, int nImage)
{
FILE * bmpFile;
FILE *bmpFile;
size_t nSize;
if (nImage == 0)
{
if (nWidth != 512 || nHeight != 512)
if (nImage == 0) {
if (nWidth != 512 || nHeight != 512)
return -1;
const char* fileName = "teapot_512x512_8u_Gray.raw";
const char* InputFile = sdkFindFilePath(fileName, ".");
if (InputFile == NULL)
{
printf("%s file not found.. exiting\n", fileName);
exit(EXIT_WAIVED);
const char *fileName = "teapot_512x512_8u_Gray.raw";
const char *InputFile = sdkFindFilePath(fileName, ".");
if (InputFile == NULL) {
printf("%s file not found.. exiting\n", fileName);
exit(EXIT_WAIVED);
}
bmpFile = fopen(InputFile, "rb");
}
else if (nImage == 1)
{
if (nWidth != 512 || nHeight != 512)
else if (nImage == 1) {
if (nWidth != 512 || nHeight != 512)
return -1;
const char* fileName = "CT_skull_512x512_8u_Gray.raw";
const char* InputFile = sdkFindFilePath(fileName, ".");
if (InputFile == NULL)
{
printf("%s file not found.. exiting\n", fileName);
exit(EXIT_WAIVED);
const char *fileName = "CT_skull_512x512_8u_Gray.raw";
const char *InputFile = sdkFindFilePath(fileName, ".");
if (InputFile == NULL) {
printf("%s file not found.. exiting\n", fileName);
exit(EXIT_WAIVED);
}
bmpFile = fopen(InputFile, "rb");
}
else if (nImage == 2)
{
if (nWidth != 512 || nHeight != 512)
else if (nImage == 2) {
if (nWidth != 512 || nHeight != 512)
return -1;
const char* fileName = "Rocks_512x512_8u_Gray.raw";
const char* InputFile = sdkFindFilePath(fileName, ".");
if (InputFile == NULL)
{
printf("%s file not found.. exiting\n", fileName);
exit(EXIT_WAIVED);
const char *fileName = "Rocks_512x512_8u_Gray.raw";
const char *InputFile = sdkFindFilePath(fileName, ".");
if (InputFile == NULL) {
printf("%s file not found.. exiting\n", fileName);
exit(EXIT_WAIVED);
}
bmpFile = fopen(InputFile, "rb");
}
else
{
printf ("Input file load failed.\n");
else {
printf("Input file load failed.\n");
return -1;
}
if (bmpFile == NULL)
{
printf ("Input file load failed.\n");
if (bmpFile == NULL) {
printf("Input file load failed.\n");
return -1;
}
nSize = fread(pImage, 1, nWidth * nHeight, bmpFile);
if (nSize < nWidth * nHeight)
{
printf ("Input file load failed.\n");
fclose(bmpFile);
if (nSize < nWidth * nHeight) {
printf("Input file load failed.\n");
fclose(bmpFile);
return -1;
}
fclose(bmpFile);
printf ("Input file load succeeded.\n");
printf("Input file load succeeded.\n");
return 0;
}
int
main( int argc, char** argv )
int main(int argc, char **argv)
{
size_t aSegmentationScratchBufferSize[NUMBER_OF_IMAGES];
int aSegmentLabelsOutputBufferSize[NUMBER_OF_IMAGES];
size_t aSegmentationScratchBufferSize[NUMBER_OF_IMAGES];
int aSegmentLabelsOutputBufferSize[NUMBER_OF_IMAGES];
cudaError_t cudaError;
NppStatus nppStatus;
cudaError_t cudaError;
NppStatus nppStatus;
NppStreamContext nppStreamCtx;
FILE * bmpFile;
NppiNorm eNorm = nppiNormInf; // default to 8 way neighbor search
FILE *bmpFile;
NppiNorm eNorm = nppiNormInf; // default to 8 way neighbor search
for (int j = 0; j < NUMBER_OF_IMAGES; j++)
{
pInputImageDev[j] = 0;
pInputImageHost[j] = 0;
pSegmentationScratchBufferDev[j] = 0;
pSegmentLabelsOutputBufferDev[j] = 0;
for (int j = 0; j < NUMBER_OF_IMAGES; j++) {
pInputImageDev[j] = 0;
pInputImageHost[j] = 0;
pSegmentationScratchBufferDev[j] = 0;
pSegmentLabelsOutputBufferDev[j] = 0;
pSegmentLabelsOutputBufferHost[j] = 0;
pSegmentsDev[j] = 0;
pSegmentsHost[j] = 0;
pSegmentsDev[j] = 0;
pSegmentsHost[j] = 0;
}
nppStreamCtx.hStream = 0; // The NULL stream by default, set this to whatever your stream ID is if not the NULL stream.
nppStreamCtx.hStream =
0; // The NULL stream by default, set this to whatever your stream ID is if not the NULL stream.
cudaError = cudaGetDevice(&nppStreamCtx.nCudaDeviceId);
if (cudaError != cudaSuccess)
{
if (cudaError != cudaSuccess) {
printf("CUDA error: no devices supporting CUDA.\n");
return NPP_NOT_SUFFICIENT_COMPUTE_CAPABILITY;
}
const NppLibraryVersion *libVer = nppGetLibVersion();
const NppLibraryVersion *libVer = nppGetLibVersion();
printf("NPP Library Version %d.%d.%d\n", libVer->major, libVer->minor, libVer->build);
@@ -210,17 +201,17 @@ main( int argc, char** argv )
cudaDriverGetVersion(&driverVersion);
cudaRuntimeGetVersion(&runtimeVersion);
printf("CUDA Driver Version: %d.%d\n", driverVersion/1000, (driverVersion%100)/10);
printf("CUDA Runtime Version: %d.%d\n\n", runtimeVersion/1000, (runtimeVersion%100)/10);
printf("CUDA Driver Version: %d.%d\n", driverVersion / 1000, (driverVersion % 100) / 10);
printf("CUDA Runtime Version: %d.%d\n\n", runtimeVersion / 1000, (runtimeVersion % 100) / 10);
cudaError = cudaDeviceGetAttribute(&nppStreamCtx.nCudaDevAttrComputeCapabilityMajor,
cudaDevAttrComputeCapabilityMajor,
cudaError = cudaDeviceGetAttribute(&nppStreamCtx.nCudaDevAttrComputeCapabilityMajor,
cudaDevAttrComputeCapabilityMajor,
nppStreamCtx.nCudaDeviceId);
if (cudaError != cudaSuccess)
return NPP_NOT_SUFFICIENT_COMPUTE_CAPABILITY;
cudaError = cudaDeviceGetAttribute(&nppStreamCtx.nCudaDevAttrComputeCapabilityMinor,
cudaDevAttrComputeCapabilityMinor,
cudaError = cudaDeviceGetAttribute(&nppStreamCtx.nCudaDevAttrComputeCapabilityMinor,
cudaDevAttrComputeCapabilityMinor,
nppStreamCtx.nCudaDeviceId);
if (cudaError != cudaSuccess)
return NPP_NOT_SUFFICIENT_COMPUTE_CAPABILITY;
@@ -231,79 +222,98 @@ main( int argc, char** argv )
cudaError = cudaGetDeviceProperties(&oDeviceProperties, nppStreamCtx.nCudaDeviceId);
nppStreamCtx.nMultiProcessorCount = oDeviceProperties.multiProcessorCount;
nppStreamCtx.nMultiProcessorCount = oDeviceProperties.multiProcessorCount;
nppStreamCtx.nMaxThreadsPerMultiProcessor = oDeviceProperties.maxThreadsPerMultiProcessor;
nppStreamCtx.nMaxThreadsPerBlock = oDeviceProperties.maxThreadsPerBlock;
nppStreamCtx.nSharedMemPerBlock = oDeviceProperties.sharedMemPerBlock;
nppStreamCtx.nMaxThreadsPerBlock = oDeviceProperties.maxThreadsPerBlock;
nppStreamCtx.nSharedMemPerBlock = oDeviceProperties.sharedMemPerBlock;
NppiSize oSizeROI[NUMBER_OF_IMAGES];
for (int nImage = 0; nImage < NUMBER_OF_IMAGES; nImage++)
{
if (nImage == 0)
{
oSizeROI[nImage].width = 512;
for (int nImage = 0; nImage < NUMBER_OF_IMAGES; nImage++) {
if (nImage == 0) {
oSizeROI[nImage].width = 512;
oSizeROI[nImage].height = 512;
}
else if (nImage == 1)
{
oSizeROI[nImage].width = 512;
else if (nImage == 1) {
oSizeROI[nImage].width = 512;
oSizeROI[nImage].height = 512;
}
else if (nImage == 2)
{
oSizeROI[nImage].width = 512;
else if (nImage == 2) {
oSizeROI[nImage].width = 512;
oSizeROI[nImage].height = 512;
}
// cudaMallocPitch OR cudaMalloc can be used here, in this sample case width == pitch.
cudaError = cudaMalloc ((void**)&pInputImageDev[nImage], oSizeROI[nImage].width * sizeof(Npp8u) * oSizeROI[nImage].height);
cudaError = cudaMalloc((void **)&pInputImageDev[nImage],
oSizeROI[nImage].width * sizeof(Npp8u) * oSizeROI[nImage].height);
if (cudaError != cudaSuccess)
return NPP_MEMORY_ALLOCATION_ERR;
cudaError = cudaMalloc ((void**)&pSegmentsDev[nImage], oSizeROI[nImage].width * sizeof(Npp32u) * oSizeROI[nImage].height);
cudaError = cudaMalloc((void **)&pSegmentsDev[nImage],
oSizeROI[nImage].width * sizeof(Npp32u) * oSizeROI[nImage].height);
if (cudaError != cudaSuccess)
return NPP_MEMORY_ALLOCATION_ERR;
pInputImageHost[nImage] = reinterpret_cast<Npp8u *>(malloc(oSizeROI[nImage].width * sizeof(Npp8u) * oSizeROI[nImage].height));
pSegmentsHost[nImage] = reinterpret_cast<Npp8u *>(malloc(oSizeROI[nImage].width * sizeof(Npp32u) * oSizeROI[nImage].height));
pInputImageHost[nImage] =
reinterpret_cast<Npp8u *>(malloc(oSizeROI[nImage].width * sizeof(Npp8u) * oSizeROI[nImage].height));
pSegmentsHost[nImage] =
reinterpret_cast<Npp8u *>(malloc(oSizeROI[nImage].width * sizeof(Npp32u) * oSizeROI[nImage].height));
nppStatus = nppiSegmentWatershedGetBufferSize_8u_C1R(oSizeROI[nImage], &aSegmentationScratchBufferSize[nImage]);
cudaError = cudaMalloc ((void **)&pSegmentationScratchBufferDev[nImage], aSegmentationScratchBufferSize[nImage]);
cudaError = cudaMalloc((void **)&pSegmentationScratchBufferDev[nImage], aSegmentationScratchBufferSize[nImage]);
if (cudaError != cudaSuccess)
return NPP_MEMORY_ALLOCATION_ERR;
// Output label marker buffers are only needed if you want to same the generated segmentation labels, they ARE compatible with NPP UF generated labels.
// Requesting segmentation output may slightly decrease segmentation function performance. Regardless of the pitch of the segmentation image
// the segment labels output buffer will have a pitch of oSizeROI[nImage].width * sizeof(Npp32u).
// Output label marker buffers are only needed if you want to same the generated segmentation labels, they ARE
// compatible with NPP UF generated labels. Requesting segmentation output may slightly decrease segmentation
// function performance. Regardless of the pitch of the segmentation image the segment labels output buffer
// will have a pitch of oSizeROI[nImage].width * sizeof(Npp32u).
aSegmentLabelsOutputBufferSize[nImage] = oSizeROI[nImage].width * sizeof(Npp32u) * oSizeROI[nImage].height;
cudaError = cudaMalloc ((void **)&pSegmentLabelsOutputBufferDev[nImage], aSegmentLabelsOutputBufferSize[nImage]);
cudaError = cudaMalloc((void **)&pSegmentLabelsOutputBufferDev[nImage], aSegmentLabelsOutputBufferSize[nImage]);
if (cudaError != cudaSuccess)
return NPP_MEMORY_ALLOCATION_ERR;
pSegmentLabelsOutputBufferHost[nImage] = reinterpret_cast<Npp32u *>(malloc(oSizeROI[nImage].width * sizeof(Npp32u) * oSizeROI[nImage].height));
pSegmentLabelsOutputBufferHost[nImage] =
reinterpret_cast<Npp32u *>(malloc(oSizeROI[nImage].width * sizeof(Npp32u) * oSizeROI[nImage].height));
if (loadRaw8BitImage(pInputImageHost[nImage], oSizeROI[nImage].width * sizeof(Npp8u), oSizeROI[nImage].height, nImage) == 0)
{
cudaError = cudaMemcpy2DAsync(pInputImageDev[nImage], oSizeROI[nImage].width * sizeof(Npp8u), pInputImageHost[nImage],
oSizeROI[nImage].width * sizeof(Npp8u), oSizeROI[nImage].width * sizeof(Npp8u), oSizeROI[nImage].height,
cudaMemcpyHostToDevice, nppStreamCtx.hStream);
if (loadRaw8BitImage(
pInputImageHost[nImage], oSizeROI[nImage].width * sizeof(Npp8u), oSizeROI[nImage].height, nImage)
== 0) {
cudaError = cudaMemcpy2DAsync(pInputImageDev[nImage],
oSizeROI[nImage].width * sizeof(Npp8u),
pInputImageHost[nImage],
oSizeROI[nImage].width * sizeof(Npp8u),
oSizeROI[nImage].width * sizeof(Npp8u),
oSizeROI[nImage].height,
cudaMemcpyHostToDevice,
nppStreamCtx.hStream);
// Make a second copy of the unaltered input image since this function works in place and we want to reuse the input image multiple times.
cudaError = cudaMemcpy2DAsync(pSegmentsDev[nImage], oSizeROI[nImage].width * sizeof(Npp8u), pInputImageHost[nImage],
oSizeROI[nImage].width * sizeof(Npp8u), oSizeROI[nImage].width * sizeof(Npp8u), oSizeROI[nImage].height,
cudaMemcpyHostToDevice, nppStreamCtx.hStream);
// Make a second copy of the unaltered input image since this function works in place and we want to reuse
// the input image multiple times.
cudaError = cudaMemcpy2DAsync(pSegmentsDev[nImage],
oSizeROI[nImage].width * sizeof(Npp8u),
pInputImageHost[nImage],
oSizeROI[nImage].width * sizeof(Npp8u),
oSizeROI[nImage].width * sizeof(Npp8u),
oSizeROI[nImage].height,
cudaMemcpyHostToDevice,
nppStreamCtx.hStream);
nppStatus = nppiSegmentWatershed_8u_C1IR_Ctx(pSegmentsDev[nImage], oSizeROI[nImage].width * sizeof(Npp8u),
pSegmentLabelsOutputBufferDev[nImage], oSizeROI[nImage].width * sizeof(Npp32u), eNorm,
NPP_WATERSHED_SEGMENT_BOUNDARIES_NONE, oSizeROI[nImage], pSegmentationScratchBufferDev[nImage], nppStreamCtx);
nppStatus = nppiSegmentWatershed_8u_C1IR_Ctx(pSegmentsDev[nImage],
oSizeROI[nImage].width * sizeof(Npp8u),
pSegmentLabelsOutputBufferDev[nImage],
oSizeROI[nImage].width * sizeof(Npp32u),
eNorm,
NPP_WATERSHED_SEGMENT_BOUNDARIES_NONE,
oSizeROI[nImage],
pSegmentationScratchBufferDev[nImage],
nppStreamCtx);
if (nppStatus != NPP_SUCCESS)
{
if (nppStatus != NPP_SUCCESS) {
if (nImage == 0)
printf("Lena segments 8Way 512x512 8u failed.\n");
else if (nImage == 1)
@@ -315,26 +325,29 @@ main( int argc, char** argv )
}
// Now compress the label markers output to make them easier to view.
int nCompressedLabelsScratchBufferSize;
Npp8u * pCompressedLabelsScratchBufferDev;
int nCompressedLabelsScratchBufferSize;
Npp8u *pCompressedLabelsScratchBufferDev;
nppStatus = nppiCompressMarkerLabelsGetBufferSize_32u_C1R(oSizeROI[nImage].width * oSizeROI[nImage].height, &nCompressedLabelsScratchBufferSize);
nppStatus = nppiCompressMarkerLabelsGetBufferSize_32u_C1R(oSizeROI[nImage].width * oSizeROI[nImage].height,
&nCompressedLabelsScratchBufferSize);
if (nppStatus != NPP_NO_ERROR)
return nppStatus;
cudaError = cudaMalloc ((void **)&pCompressedLabelsScratchBufferDev, nCompressedLabelsScratchBufferSize);
cudaError = cudaMalloc((void **)&pCompressedLabelsScratchBufferDev, nCompressedLabelsScratchBufferSize);
if (cudaError != cudaSuccess)
return NPP_MEMORY_ALLOCATION_ERR;
int nCompressedLabelCount = 0;
nppStatus = nppiCompressMarkerLabelsUF_32u_C1IR_Ctx(pSegmentLabelsOutputBufferDev[nImage], oSizeROI[nImage].width * sizeof(Npp32u), oSizeROI[nImage],
oSizeROI[nImage].width * oSizeROI[nImage].height, &nCompressedLabelCount,
nppStatus = nppiCompressMarkerLabelsUF_32u_C1IR_Ctx(pSegmentLabelsOutputBufferDev[nImage],
oSizeROI[nImage].width * sizeof(Npp32u),
oSizeROI[nImage],
oSizeROI[nImage].width * oSizeROI[nImage].height,
&nCompressedLabelCount,
pCompressedLabelsScratchBufferDev,
nppStreamCtx);
if (nppStatus != NPP_SUCCESS)
{
if (nppStatus != NPP_SUCCESS) {
if (nImage == 0)
printf("teapot_CompressedLabelMarkersUF_8Way_512x512_32u failed.\n");
else if (nImage == 1)
@@ -346,19 +359,28 @@ main( int argc, char** argv )
}
// Copy segmented image to host
cudaError = cudaMemcpy2DAsync(pSegmentsHost[nImage], oSizeROI[nImage].width * sizeof(Npp8u),
pSegmentsDev[nImage], oSizeROI[nImage].width * sizeof(Npp8u), oSizeROI[nImage].width * sizeof(Npp8u), oSizeROI[nImage].height,
cudaMemcpyDeviceToHost, nppStreamCtx.hStream);
cudaError = cudaMemcpy2DAsync(pSegmentsHost[nImage],
oSizeROI[nImage].width * sizeof(Npp8u),
pSegmentsDev[nImage],
oSizeROI[nImage].width * sizeof(Npp8u),
oSizeROI[nImage].width * sizeof(Npp8u),
oSizeROI[nImage].height,
cudaMemcpyDeviceToHost,
nppStreamCtx.hStream);
// Copy segment labels image to host
cudaError = cudaMemcpy2DAsync(pSegmentLabelsOutputBufferHost[nImage], oSizeROI[nImage].width * sizeof(Npp32u),
pSegmentLabelsOutputBufferDev[nImage], oSizeROI[nImage].width * sizeof(Npp32u), oSizeROI[nImage].width * sizeof(Npp32u), oSizeROI[nImage].height,
cudaMemcpyDeviceToHost, nppStreamCtx.hStream);
cudaError = cudaMemcpy2DAsync(pSegmentLabelsOutputBufferHost[nImage],
oSizeROI[nImage].width * sizeof(Npp32u),
pSegmentLabelsOutputBufferDev[nImage],
oSizeROI[nImage].width * sizeof(Npp32u),
oSizeROI[nImage].width * sizeof(Npp32u),
oSizeROI[nImage].height,
cudaMemcpyDeviceToHost,
nppStreamCtx.hStream);
// Wait host image read backs to complete, not necessary if no need to synchronize
if ((cudaError = cudaStreamSynchronize(nppStreamCtx.hStream)) != cudaSuccess)
{
printf ("Post segmentation cudaStreamSynchronize failed\n");
if ((cudaError = cudaStreamSynchronize(nppStreamCtx.hStream)) != cudaSuccess) {
printf("Post segmentation cudaStreamSynchronize failed\n");
tearDown();
return -1;
}
@@ -374,12 +396,12 @@ main( int argc, char** argv )
else if (nImage == 2)
bmpFile = fopen(SegmentsOutputFile2.c_str(), "wb");
if (bmpFile == NULL)
if (bmpFile == NULL)
return -1;
size_t nSize = 0;
for (int j = 0; j < oSizeROI[nImage].height; j++)
{
nSize += fwrite(&pSegmentsHost[nImage][j * oSizeROI[nImage].width], sizeof(Npp8u), oSizeROI[nImage].width, bmpFile);
for (int j = 0; j < oSizeROI[nImage].height; j++) {
nSize += fwrite(
&pSegmentsHost[nImage][j * oSizeROI[nImage].width], sizeof(Npp8u), oSizeROI[nImage].width, bmpFile);
}
fclose(bmpFile);
@@ -398,12 +420,14 @@ main( int argc, char** argv )
else if (nImage == 2)
bmpFile = fopen(CompressedSegmentLabelsOutputFile2.c_str(), "wb");
if (bmpFile == NULL)
if (bmpFile == NULL)
return -1;
nSize = 0;
for (int j = 0; j < oSizeROI[nImage].height; j++)
{
nSize += fwrite(&pSegmentLabelsOutputBufferHost[nImage][j * oSizeROI[nImage].width], sizeof(Npp32u), oSizeROI[nImage].width, bmpFile);
for (int j = 0; j < oSizeROI[nImage].height; j++) {
nSize += fwrite(&pSegmentLabelsOutputBufferHost[nImage][j * oSizeROI[nImage].width],
sizeof(Npp32u),
oSizeROI[nImage].width,
bmpFile);
}
fclose(bmpFile);
@@ -416,18 +440,29 @@ main( int argc, char** argv )
// Now generate a segment boundaries only output image
// Make a second copy of the unaltered input image since this function works in place and we want to reuse the input image multiple times.
cudaError = cudaMemcpy2DAsync(pSegmentsDev[nImage], oSizeROI[nImage].width * sizeof(Npp8u), pInputImageHost[nImage],
oSizeROI[nImage].width * sizeof(Npp8u), oSizeROI[nImage].width * sizeof(Npp8u), oSizeROI[nImage].height,
cudaMemcpyHostToDevice, nppStreamCtx.hStream);
// Make a second copy of the unaltered input image since this function works in place and we want to reuse
// the input image multiple times.
cudaError = cudaMemcpy2DAsync(pSegmentsDev[nImage],
oSizeROI[nImage].width * sizeof(Npp8u),
pInputImageHost[nImage],
oSizeROI[nImage].width * sizeof(Npp8u),
oSizeROI[nImage].width * sizeof(Npp8u),
oSizeROI[nImage].height,
cudaMemcpyHostToDevice,
nppStreamCtx.hStream);
// We already generated segment labels images to skip that this time
nppStatus = nppiSegmentWatershed_8u_C1IR_Ctx(pSegmentsDev[nImage], oSizeROI[nImage].width * sizeof(Npp8u),
0, 0, eNorm,
NPP_WATERSHED_SEGMENT_BOUNDARIES_ONLY, oSizeROI[nImage], pSegmentationScratchBufferDev[nImage], nppStreamCtx);
nppStatus = nppiSegmentWatershed_8u_C1IR_Ctx(pSegmentsDev[nImage],
oSizeROI[nImage].width * sizeof(Npp8u),
0,
0,
eNorm,
NPP_WATERSHED_SEGMENT_BOUNDARIES_ONLY,
oSizeROI[nImage],
pSegmentationScratchBufferDev[nImage],
nppStreamCtx);
if (nppStatus != NPP_SUCCESS)
{
if (nppStatus != NPP_SUCCESS) {
if (nImage == 0)
printf("Lena segment boundaries 8Way 512x512 8u failed.\n");
else if (nImage == 1)
@@ -439,14 +474,18 @@ main( int argc, char** argv )
}
// Copy segment boundaries image to host
cudaError = cudaMemcpy2DAsync(pSegmentsHost[nImage], oSizeROI[nImage].width * sizeof(Npp8u),
pSegmentsDev[nImage], oSizeROI[nImage].width * sizeof(Npp8u), oSizeROI[nImage].width * sizeof(Npp8u), oSizeROI[nImage].height,
cudaMemcpyDeviceToHost, nppStreamCtx.hStream);
cudaError = cudaMemcpy2DAsync(pSegmentsHost[nImage],
oSizeROI[nImage].width * sizeof(Npp8u),
pSegmentsDev[nImage],
oSizeROI[nImage].width * sizeof(Npp8u),
oSizeROI[nImage].width * sizeof(Npp8u),
oSizeROI[nImage].height,
cudaMemcpyDeviceToHost,
nppStreamCtx.hStream);
// Wait host image read backs to complete, not necessary if no need to synchronize
if ((cudaError = cudaStreamSynchronize(nppStreamCtx.hStream)) != cudaSuccess)
{
printf ("Post segmentation cudaStreamSynchronize failed\n");
if ((cudaError = cudaStreamSynchronize(nppStreamCtx.hStream)) != cudaSuccess) {
printf("Post segmentation cudaStreamSynchronize failed\n");
tearDown();
return -1;
}
@@ -458,12 +497,12 @@ main( int argc, char** argv )
else if (nImage == 2)
bmpFile = fopen(SegmentBoundariesOutputFile2.c_str(), "wb");
if (bmpFile == NULL)
if (bmpFile == NULL)
return -1;
nSize = 0;
for (int j = 0; j < oSizeROI[nImage].height; j++)
{
nSize += fwrite(&pSegmentsHost[nImage][j * oSizeROI[nImage].width], sizeof(Npp8u), oSizeROI[nImage].width, bmpFile);
for (int j = 0; j < oSizeROI[nImage].height; j++) {
nSize += fwrite(
&pSegmentsHost[nImage][j * oSizeROI[nImage].width], sizeof(Npp8u), oSizeROI[nImage].width, bmpFile);
}
fclose(bmpFile);
@@ -476,18 +515,29 @@ main( int argc, char** argv )
// Now generate a segmented with contrasting boundaries output image
// Make a second copy of the unaltered input image since this function works in place and we want to reuse the input image multiple times.
cudaError = cudaMemcpy2DAsync(pSegmentsDev[nImage], oSizeROI[nImage].width * sizeof(Npp8u), pInputImageHost[nImage],
oSizeROI[nImage].width * sizeof(Npp8u), oSizeROI[nImage].width * sizeof(Npp8u), oSizeROI[nImage].height,
cudaMemcpyHostToDevice, nppStreamCtx.hStream);
// Make a second copy of the unaltered input image since this function works in place and we want to reuse
// the input image multiple times.
cudaError = cudaMemcpy2DAsync(pSegmentsDev[nImage],
oSizeROI[nImage].width * sizeof(Npp8u),
pInputImageHost[nImage],
oSizeROI[nImage].width * sizeof(Npp8u),
oSizeROI[nImage].width * sizeof(Npp8u),
oSizeROI[nImage].height,
cudaMemcpyHostToDevice,
nppStreamCtx.hStream);
// We already generated segment labels images to skip that this time
nppStatus = nppiSegmentWatershed_8u_C1IR_Ctx(pSegmentsDev[nImage], oSizeROI[nImage].width * sizeof(Npp8u),
0, 0, eNorm,
NPP_WATERSHED_SEGMENT_BOUNDARIES_CONTRAST, oSizeROI[nImage], pSegmentationScratchBufferDev[nImage], nppStreamCtx);
nppStatus = nppiSegmentWatershed_8u_C1IR_Ctx(pSegmentsDev[nImage],
oSizeROI[nImage].width * sizeof(Npp8u),
0,
0,
eNorm,
NPP_WATERSHED_SEGMENT_BOUNDARIES_CONTRAST,
oSizeROI[nImage],
pSegmentationScratchBufferDev[nImage],
nppStreamCtx);
if (nppStatus != NPP_SUCCESS)
{
if (nppStatus != NPP_SUCCESS) {
if (nImage == 0)
printf("Lena segments with contrasting boundaries 8Way 512x512 8u failed.\n");
else if (nImage == 1)
@@ -499,14 +549,18 @@ main( int argc, char** argv )
}
// Copy segment boundaries image to host
cudaError = cudaMemcpy2DAsync(pSegmentsHost[nImage], oSizeROI[nImage].width * sizeof(Npp8u),
pSegmentsDev[nImage], oSizeROI[nImage].width * sizeof(Npp8u), oSizeROI[nImage].width * sizeof(Npp8u), oSizeROI[nImage].height,
cudaMemcpyDeviceToHost, nppStreamCtx.hStream);
cudaError = cudaMemcpy2DAsync(pSegmentsHost[nImage],
oSizeROI[nImage].width * sizeof(Npp8u),
pSegmentsDev[nImage],
oSizeROI[nImage].width * sizeof(Npp8u),
oSizeROI[nImage].width * sizeof(Npp8u),
oSizeROI[nImage].height,
cudaMemcpyDeviceToHost,
nppStreamCtx.hStream);
// Wait host image read backs to complete, not necessary if no need to synchronize
if ((cudaError = cudaStreamSynchronize(nppStreamCtx.hStream)) != cudaSuccess)
{
printf ("Post segmentation cudaStreamSynchronize failed\n");
if ((cudaError = cudaStreamSynchronize(nppStreamCtx.hStream)) != cudaSuccess) {
printf("Post segmentation cudaStreamSynchronize failed\n");
tearDown();
return -1;
}
@@ -518,12 +572,12 @@ main( int argc, char** argv )
else if (nImage == 2)
bmpFile = fopen(SegmentsWithContrastingBoundariesOutputFile2.c_str(), "wb");
if (bmpFile == NULL)
if (bmpFile == NULL)
return -1;
nSize = 0;
for (int j = 0; j < oSizeROI[nImage].height; j++)
{
nSize += fwrite(&pSegmentsHost[nImage][j * oSizeROI[nImage].width], sizeof(Npp8u), oSizeROI[nImage].width, bmpFile);
for (int j = 0; j < oSizeROI[nImage].height; j++) {
nSize += fwrite(
&pSegmentsHost[nImage][j * oSizeROI[nImage].width], sizeof(Npp8u), oSizeROI[nImage].width, bmpFile);
}
fclose(bmpFile);