mirror of
https://github.com/NVIDIA/cuda-samples.git
synced 2026-10-25 22:28:17 +08:00
Apply consistent code formatting across the repo. Add clang-format and pre-commit hooks.
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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", <oIR1, <oIR1Size);
|
||||
getLTOIR(lto_compute, "lto_compute.cu", <oIR2, <oIR2Size);
|
||||
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", <oIR1, <oIR1Size);
|
||||
getLTOIR(lto_compute, "lto_compute.cu", <oIR2, <oIR2Size);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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
@@ -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));
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user