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:
@@ -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)
|
||||
|
||||
|
||||
@@ -29,230 +29,236 @@
|
||||
// DESCRIPTION: Simple CUDA consumer rendering sample app
|
||||
//
|
||||
|
||||
#include <cuda_runtime.h>
|
||||
#include "cuda_consumer.h"
|
||||
#include "eglstrm_common.h"
|
||||
|
||||
#include <cuda_runtime.h>
|
||||
#include <math.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "eglstrm_common.h"
|
||||
|
||||
#if defined(EXTENSION_LIST)
|
||||
EXTENSION_LIST(EXTLST_EXTERN)
|
||||
#endif
|
||||
CUgraphicsResource cudaResource;
|
||||
|
||||
static int count_acq = 0;
|
||||
static int count_acq = 0;
|
||||
static double acquire_time[25000] = {0}, total_time_acq = 0;
|
||||
|
||||
static int count_rel = 0;
|
||||
static int count_rel = 0;
|
||||
static double rel_time[25000] = {0}, total_time_rel = 0;
|
||||
|
||||
void acquireApiStat(void);
|
||||
void acquireApiStat(void) {
|
||||
int i = 0;
|
||||
double min = 10000000, max = 0;
|
||||
double average_launch_time = 0, standard_deviation = 0;
|
||||
if (count_acq == 0) return;
|
||||
// lets compute the standard deviation
|
||||
min = max = acquire_time[1];
|
||||
average_launch_time = (total_time_acq - acquire_time[0]) / count_acq;
|
||||
for (i = 1; i < count_acq; i++) {
|
||||
standard_deviation += (acquire_time[i] - average_launch_time) *
|
||||
(acquire_time[i] - average_launch_time);
|
||||
if (acquire_time[i] < min) min = acquire_time[i];
|
||||
if (acquire_time[i] > max) max = acquire_time[i];
|
||||
}
|
||||
standard_deviation = sqrt(standard_deviation / count_acq);
|
||||
printf("acquire Avg: %lf\n", average_launch_time);
|
||||
printf("acquire SD: %lf\n", standard_deviation);
|
||||
printf("acquire min: %lf\n", min);
|
||||
printf("acquire max: %lf\n", max);
|
||||
void acquireApiStat(void)
|
||||
{
|
||||
int i = 0;
|
||||
double min = 10000000, max = 0;
|
||||
double average_launch_time = 0, standard_deviation = 0;
|
||||
if (count_acq == 0)
|
||||
return;
|
||||
// lets compute the standard deviation
|
||||
min = max = acquire_time[1];
|
||||
average_launch_time = (total_time_acq - acquire_time[0]) / count_acq;
|
||||
for (i = 1; i < count_acq; i++) {
|
||||
standard_deviation += (acquire_time[i] - average_launch_time) * (acquire_time[i] - average_launch_time);
|
||||
if (acquire_time[i] < min)
|
||||
min = acquire_time[i];
|
||||
if (acquire_time[i] > max)
|
||||
max = acquire_time[i];
|
||||
}
|
||||
standard_deviation = sqrt(standard_deviation / count_acq);
|
||||
printf("acquire Avg: %lf\n", average_launch_time);
|
||||
printf("acquire SD: %lf\n", standard_deviation);
|
||||
printf("acquire min: %lf\n", min);
|
||||
printf("acquire max: %lf\n", max);
|
||||
|
||||
min = max = rel_time[1];
|
||||
average_launch_time = (total_time_rel - rel_time[0]) / count_rel;
|
||||
for (i = 1; i < count_rel; i++) {
|
||||
standard_deviation += (rel_time[i] - average_launch_time) *
|
||||
(rel_time[i] - average_launch_time);
|
||||
if (rel_time[i] < min) min = rel_time[i];
|
||||
if (rel_time[i] > max) max = rel_time[i];
|
||||
}
|
||||
standard_deviation = sqrt(standard_deviation / count_rel);
|
||||
printf("release Avg: %lf\n", average_launch_time);
|
||||
printf("release SD: %lf\n", standard_deviation);
|
||||
printf("release min: %lf\n", min);
|
||||
printf("release max: %lf\n", max);
|
||||
min = max = rel_time[1];
|
||||
average_launch_time = (total_time_rel - rel_time[0]) / count_rel;
|
||||
for (i = 1; i < count_rel; i++) {
|
||||
standard_deviation += (rel_time[i] - average_launch_time) * (rel_time[i] - average_launch_time);
|
||||
if (rel_time[i] < min)
|
||||
min = rel_time[i];
|
||||
if (rel_time[i] > max)
|
||||
max = rel_time[i];
|
||||
}
|
||||
standard_deviation = sqrt(standard_deviation / count_rel);
|
||||
printf("release Avg: %lf\n", average_launch_time);
|
||||
printf("release SD: %lf\n", standard_deviation);
|
||||
printf("release min: %lf\n", min);
|
||||
printf("release max: %lf\n", max);
|
||||
}
|
||||
CUresult cudaConsumerAcquireFrame(test_cuda_consumer_s *cudaConsumer,
|
||||
int frameNumber) {
|
||||
CUresult cuStatus = CUDA_SUCCESS;
|
||||
CUeglFrame cudaEgl;
|
||||
struct timespec start, end;
|
||||
EGLint streamState = 0;
|
||||
double curTime;
|
||||
CUresult cudaConsumerAcquireFrame(test_cuda_consumer_s *cudaConsumer, int frameNumber)
|
||||
{
|
||||
CUresult cuStatus = CUDA_SUCCESS;
|
||||
CUeglFrame cudaEgl;
|
||||
struct timespec start, end;
|
||||
EGLint streamState = 0;
|
||||
double curTime;
|
||||
|
||||
if (!cudaConsumer) {
|
||||
printf("%s: Bad parameter\n", __func__);
|
||||
goto done;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
if (!eglQueryStreamKHR(cudaConsumer->eglDisplay, cudaConsumer->eglStream,
|
||||
EGL_STREAM_STATE_KHR, &streamState)) {
|
||||
printf("Cuda Consumer: eglQueryStreamKHR EGL_STREAM_STATE_KHR failed\n");
|
||||
cuStatus = CUDA_ERROR_UNKNOWN;
|
||||
goto done;
|
||||
}
|
||||
if (streamState == EGL_STREAM_STATE_DISCONNECTED_KHR) {
|
||||
printf("Cuda Consumer: EGL_STREAM_STATE_DISCONNECTED_KHR received\n");
|
||||
cuStatus = CUDA_ERROR_UNKNOWN;
|
||||
goto done;
|
||||
if (!cudaConsumer) {
|
||||
printf("%s: Bad parameter\n", __func__);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (streamState == EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (cudaConsumer->profileAPI) {
|
||||
getTime(&start);
|
||||
}
|
||||
cuStatus =
|
||||
cuEGLStreamConsumerAcquireFrame(&(cudaConsumer->cudaConn), &cudaResource,
|
||||
&cudaConsumer->consCudaStream, 16000);
|
||||
if (cudaConsumer->profileAPI) {
|
||||
getTime(&end);
|
||||
curTime = TIME_DIFF(end, start);
|
||||
acquire_time[count_acq++] = curTime;
|
||||
if (count_acq == 25000) count_acq = 0;
|
||||
total_time_acq += curTime;
|
||||
}
|
||||
if (cuStatus == CUDA_SUCCESS) {
|
||||
CUdeviceptr pDevPtr = 0;
|
||||
cudaError_t err;
|
||||
while (1) {
|
||||
if (!eglQueryStreamKHR(cudaConsumer->eglDisplay, cudaConsumer->eglStream, EGL_STREAM_STATE_KHR, &streamState)) {
|
||||
printf("Cuda Consumer: eglQueryStreamKHR EGL_STREAM_STATE_KHR failed\n");
|
||||
cuStatus = CUDA_ERROR_UNKNOWN;
|
||||
goto done;
|
||||
}
|
||||
if (streamState == EGL_STREAM_STATE_DISCONNECTED_KHR) {
|
||||
printf("Cuda Consumer: EGL_STREAM_STATE_DISCONNECTED_KHR received\n");
|
||||
cuStatus = CUDA_ERROR_UNKNOWN;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (streamState == EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (cudaConsumer->profileAPI) {
|
||||
getTime(&start);
|
||||
}
|
||||
cuStatus =
|
||||
cuGraphicsResourceGetMappedEglFrame(&cudaEgl, cudaResource, 0, 0);
|
||||
cuEGLStreamConsumerAcquireFrame(&(cudaConsumer->cudaConn), &cudaResource, &cudaConsumer->consCudaStream, 16000);
|
||||
if (cudaConsumer->profileAPI) {
|
||||
getTime(&end);
|
||||
curTime = TIME_DIFF(end, start);
|
||||
acquire_time[count_acq++] = curTime;
|
||||
if (count_acq == 25000)
|
||||
count_acq = 0;
|
||||
total_time_acq += curTime;
|
||||
}
|
||||
if (cuStatus == CUDA_SUCCESS) {
|
||||
CUdeviceptr pDevPtr = 0;
|
||||
cudaError_t err;
|
||||
|
||||
cuStatus = cuGraphicsResourceGetMappedEglFrame(&cudaEgl, cudaResource, 0, 0);
|
||||
if (cuStatus != CUDA_SUCCESS) {
|
||||
printf("Cuda get resource failed with %d\n", cuStatus);
|
||||
goto done;
|
||||
}
|
||||
pDevPtr = (CUdeviceptr)cudaEgl.frame.pPitch[0];
|
||||
|
||||
err = cudaConsumer_filter(cudaConsumer->consCudaStream,
|
||||
(char *)pDevPtr,
|
||||
WIDTH * 4,
|
||||
HEIGHT,
|
||||
PROD_DATA + frameNumber,
|
||||
CONS_DATA + frameNumber,
|
||||
frameNumber);
|
||||
if (err != cudaSuccess) {
|
||||
printf("Cuda Consumer: kernel failed with: %s\n", cudaGetErrorString(err));
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
return cuStatus;
|
||||
}
|
||||
|
||||
CUresult cudaConsumerReleaseFrame(test_cuda_consumer_s *cudaConsumer, int frameNumber)
|
||||
{
|
||||
CUresult cuStatus = CUDA_SUCCESS;
|
||||
struct timespec start, end;
|
||||
double curTime;
|
||||
|
||||
if (!cudaConsumer) {
|
||||
printf("%s: Bad parameter\n", __func__);
|
||||
goto done;
|
||||
}
|
||||
if (cudaConsumer->profileAPI) {
|
||||
getTime(&start);
|
||||
}
|
||||
cuStatus = cuEGLStreamConsumerReleaseFrame(&cudaConsumer->cudaConn, cudaResource, &cudaConsumer->consCudaStream);
|
||||
if (cudaConsumer->profileAPI) {
|
||||
getTime(&end);
|
||||
curTime = TIME_DIFF(end, start);
|
||||
rel_time[count_rel++] = curTime;
|
||||
if (count_rel == 25000)
|
||||
count_rel = 0;
|
||||
total_time_rel += curTime;
|
||||
}
|
||||
if (cuStatus != CUDA_SUCCESS) {
|
||||
printf("Cuda get resource failed with %d\n", cuStatus);
|
||||
goto done;
|
||||
printf("cuEGLStreamConsumerReleaseFrame failed, status:%d\n", cuStatus);
|
||||
goto done;
|
||||
}
|
||||
pDevPtr = (CUdeviceptr)cudaEgl.frame.pPitch[0];
|
||||
|
||||
err = cudaConsumer_filter(cudaConsumer->consCudaStream, (char *)pDevPtr,
|
||||
WIDTH * 4, HEIGHT, PROD_DATA + frameNumber,
|
||||
CONS_DATA + frameNumber, frameNumber);
|
||||
if (err != cudaSuccess) {
|
||||
printf("Cuda Consumer: kernel failed with: %s\n",
|
||||
cudaGetErrorString(err));
|
||||
goto done;
|
||||
done:
|
||||
return cuStatus;
|
||||
}
|
||||
|
||||
CUresult cudaDeviceCreateConsumer(test_cuda_consumer_s *cudaConsumer)
|
||||
{
|
||||
CUdevice device;
|
||||
CUresult status = CUDA_SUCCESS;
|
||||
|
||||
if (CUDA_SUCCESS != (status = cuInit(0))) {
|
||||
printf("Failed to initialize CUDA\n");
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
return cuStatus;
|
||||
}
|
||||
if (CUDA_SUCCESS != (status = cuDeviceGet(&device, cudaConsumer->cudaDevId))) {
|
||||
printf("failed to get CUDA device\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
CUresult cudaConsumerReleaseFrame(test_cuda_consumer_s *cudaConsumer,
|
||||
int frameNumber) {
|
||||
CUresult cuStatus = CUDA_SUCCESS;
|
||||
struct timespec start, end;
|
||||
double curTime;
|
||||
if (CUDA_SUCCESS != (status = cuCtxCreate(&cudaConsumer->context, 0, device))) {
|
||||
printf("failed to create CUDA context\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
if (!cudaConsumer) {
|
||||
printf("%s: Bad parameter\n", __func__);
|
||||
goto done;
|
||||
}
|
||||
if (cudaConsumer->profileAPI) {
|
||||
getTime(&start);
|
||||
}
|
||||
cuStatus = cuEGLStreamConsumerReleaseFrame(
|
||||
&cudaConsumer->cudaConn, cudaResource, &cudaConsumer->consCudaStream);
|
||||
if (cudaConsumer->profileAPI) {
|
||||
getTime(&end);
|
||||
curTime = TIME_DIFF(end, start);
|
||||
rel_time[count_rel++] = curTime;
|
||||
if (count_rel == 25000) count_rel = 0;
|
||||
total_time_rel += curTime;
|
||||
}
|
||||
if (cuStatus != CUDA_SUCCESS) {
|
||||
printf("cuEGLStreamConsumerReleaseFrame failed, status:%d\n", cuStatus);
|
||||
goto done;
|
||||
}
|
||||
int major = 0, minor = 0;
|
||||
char deviceName[256];
|
||||
cuDeviceGetAttribute(&major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, device);
|
||||
cuDeviceGetAttribute(&minor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, device);
|
||||
cuDeviceGetName(deviceName, 256, device);
|
||||
printf("CUDA Consumer on GPU Device %d: \"%s\" with compute capability "
|
||||
"%d.%d\n\n",
|
||||
device,
|
||||
deviceName,
|
||||
major,
|
||||
minor);
|
||||
|
||||
done:
|
||||
return cuStatus;
|
||||
}
|
||||
cuCtxPopCurrent(&cudaConsumer->context);
|
||||
if (major < 6) {
|
||||
printf("EGLStream_CUDA_CrossGPU requires SM 6.0 or higher arch GPU. "
|
||||
"Exiting...\n");
|
||||
exit(2); // EXIT_WAIVED
|
||||
}
|
||||
|
||||
CUresult cudaDeviceCreateConsumer(test_cuda_consumer_s *cudaConsumer) {
|
||||
CUdevice device;
|
||||
CUresult status = CUDA_SUCCESS;
|
||||
|
||||
if (CUDA_SUCCESS != (status = cuInit(0))) {
|
||||
printf("Failed to initialize CUDA\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
if (CUDA_SUCCESS !=
|
||||
(status = cuDeviceGet(&device, cudaConsumer->cudaDevId))) {
|
||||
printf("failed to get CUDA device\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
if (CUDA_SUCCESS !=
|
||||
(status = cuCtxCreate(&cudaConsumer->context, 0, device))) {
|
||||
printf("failed to create CUDA context\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
int major = 0, minor = 0;
|
||||
char deviceName[256];
|
||||
cuDeviceGetAttribute(&major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR,
|
||||
device);
|
||||
cuDeviceGetAttribute(&minor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR,
|
||||
device);
|
||||
cuDeviceGetName(deviceName, 256, device);
|
||||
printf(
|
||||
"CUDA Consumer on GPU Device %d: \"%s\" with compute capability "
|
||||
"%d.%d\n\n",
|
||||
device, deviceName, major, minor);
|
||||
|
||||
cuCtxPopCurrent(&cudaConsumer->context);
|
||||
if (major < 6) {
|
||||
printf(
|
||||
"EGLStream_CUDA_CrossGPU requires SM 6.0 or higher arch GPU. "
|
||||
"Exiting...\n");
|
||||
exit(2); // EXIT_WAIVED
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
CUresult cuda_consumer_init(test_cuda_consumer_s *cudaConsumer,
|
||||
TestArgs *args) {
|
||||
CUresult status = CUDA_SUCCESS;
|
||||
int bufferSize;
|
||||
CUresult cuda_consumer_init(test_cuda_consumer_s *cudaConsumer, TestArgs *args)
|
||||
{
|
||||
CUresult status = CUDA_SUCCESS;
|
||||
int bufferSize;
|
||||
|
||||
cudaConsumer->charCnt = args->charCnt;
|
||||
bufferSize = args->charCnt;
|
||||
cudaConsumer->charCnt = args->charCnt;
|
||||
bufferSize = args->charCnt;
|
||||
|
||||
cudaConsumer->pCudaCopyMem = (unsigned char *)malloc(bufferSize);
|
||||
if (cudaConsumer->pCudaCopyMem == NULL) {
|
||||
printf("Cuda Consumer: malloc failed\n");
|
||||
goto done;
|
||||
}
|
||||
cudaConsumer->pCudaCopyMem = (unsigned char *)malloc(bufferSize);
|
||||
if (cudaConsumer->pCudaCopyMem == NULL) {
|
||||
printf("Cuda Consumer: malloc failed\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
status = cuStreamCreate(&cudaConsumer->consCudaStream, 0);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
printf("Cuda Consumer: cuStreamCreate failed, status:%d\n", status);
|
||||
goto done;
|
||||
}
|
||||
status = cuStreamCreate(&cudaConsumer->consCudaStream, 0);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
printf("Cuda Consumer: cuStreamCreate failed, status:%d\n", status);
|
||||
goto done;
|
||||
}
|
||||
|
||||
atexit(acquireApiStat);
|
||||
atexit(acquireApiStat);
|
||||
done:
|
||||
return status;
|
||||
return status;
|
||||
}
|
||||
|
||||
CUresult cuda_consumer_Deinit(test_cuda_consumer_s *cudaConsumer) {
|
||||
if (cudaConsumer->pCudaCopyMem) {
|
||||
free(cudaConsumer->pCudaCopyMem);
|
||||
}
|
||||
return cuEGLStreamConsumerDisconnect(&cudaConsumer->cudaConn);
|
||||
CUresult cuda_consumer_Deinit(test_cuda_consumer_s *cudaConsumer)
|
||||
{
|
||||
if (cudaConsumer->pCudaCopyMem) {
|
||||
free(cudaConsumer->pCudaCopyMem);
|
||||
}
|
||||
return cuEGLStreamConsumerDisconnect(&cudaConsumer->cudaConn);
|
||||
}
|
||||
|
||||
@@ -32,35 +32,41 @@
|
||||
#ifndef _CUDA_CONSUMER_H_
|
||||
#define _CUDA_CONSUMER_H_
|
||||
|
||||
#include <cuda.h>
|
||||
#include <cuda_runtime.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "cudaEGL.h"
|
||||
#include "eglstrm_common.h"
|
||||
#include <cuda_runtime.h>
|
||||
#include <cuda.h>
|
||||
|
||||
typedef struct _test_cuda_consumer_s {
|
||||
CUcontext context;
|
||||
CUeglStreamConnection cudaConn;
|
||||
int cudaDevId;
|
||||
EGLDisplay eglDisplay;
|
||||
EGLStreamKHR eglStream;
|
||||
unsigned int charCnt;
|
||||
char *cudaBuf;
|
||||
bool profileAPI;
|
||||
unsigned char *pCudaCopyMem;
|
||||
CUstream consCudaStream;
|
||||
typedef struct _test_cuda_consumer_s
|
||||
{
|
||||
CUcontext context;
|
||||
CUeglStreamConnection cudaConn;
|
||||
int cudaDevId;
|
||||
EGLDisplay eglDisplay;
|
||||
EGLStreamKHR eglStream;
|
||||
unsigned int charCnt;
|
||||
char *cudaBuf;
|
||||
bool profileAPI;
|
||||
unsigned char *pCudaCopyMem;
|
||||
CUstream consCudaStream;
|
||||
} test_cuda_consumer_s;
|
||||
|
||||
CUresult cuda_consumer_init(test_cuda_consumer_s *cudaConsumer, TestArgs *args);
|
||||
CUresult cuda_consumer_Deinit(test_cuda_consumer_s *cudaConsumer);
|
||||
CUresult cudaConsumerAcquireFrame(test_cuda_consumer_s *data, int frameNumber);
|
||||
CUresult cudaConsumerReleaseFrame(test_cuda_consumer_s *data, int frameNumber);
|
||||
CUresult cudaDeviceCreateConsumer(test_cuda_consumer_s *cudaConsumer);
|
||||
cudaError_t cudaConsumer_filter(CUstream cStream, char *pSrc, int width,
|
||||
int height, char expectedVal, char newVal,
|
||||
int frameNumber);
|
||||
CUresult cuda_consumer_init(test_cuda_consumer_s *cudaConsumer, TestArgs *args);
|
||||
CUresult cuda_consumer_Deinit(test_cuda_consumer_s *cudaConsumer);
|
||||
CUresult cudaConsumerAcquireFrame(test_cuda_consumer_s *data, int frameNumber);
|
||||
CUresult cudaConsumerReleaseFrame(test_cuda_consumer_s *data, int frameNumber);
|
||||
CUresult cudaDeviceCreateConsumer(test_cuda_consumer_s *cudaConsumer);
|
||||
cudaError_t cudaConsumer_filter(CUstream cStream,
|
||||
char *pSrc,
|
||||
int width,
|
||||
int height,
|
||||
char expectedVal,
|
||||
char newVal,
|
||||
int frameNumber);
|
||||
cudaError_t cudaGetValueMismatch(void);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -29,260 +29,265 @@
|
||||
// DESCRIPTION: Simple cuda EGL stream producer app
|
||||
//
|
||||
|
||||
#include "cudaEGL.h"
|
||||
#include "cuda_producer.h"
|
||||
#include "eglstrm_common.h"
|
||||
|
||||
#include <cuda_runtime.h>
|
||||
|
||||
#include "cudaEGL.h"
|
||||
#include "eglstrm_common.h"
|
||||
#if defined(EXTENSION_LIST)
|
||||
EXTENSION_LIST(EXTLST_EXTERN)
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "cuda_runtime.h"
|
||||
#include "math.h"
|
||||
|
||||
int cudaPresentReturnData = INIT_DATA;
|
||||
int fakePresent = 0;
|
||||
CUeglFrame fakeFrame;
|
||||
int cudaPresentReturnData = INIT_DATA;
|
||||
int fakePresent = 0;
|
||||
CUeglFrame fakeFrame;
|
||||
CUdeviceptr cudaPtrFake;
|
||||
extern bool isCrossDevice;
|
||||
|
||||
void cudaProducerPrepareFrame(CUeglFrame *cudaEgl, CUdeviceptr cudaPtr,
|
||||
int bufferSize) {
|
||||
cudaEgl->frame.pPitch[0] = (void *)cudaPtr;
|
||||
cudaEgl->width = WIDTH;
|
||||
cudaEgl->depth = 0;
|
||||
cudaEgl->height = HEIGHT;
|
||||
cudaEgl->pitch = WIDTH * 4;
|
||||
cudaEgl->frameType = CU_EGL_FRAME_TYPE_PITCH;
|
||||
cudaEgl->planeCount = 1;
|
||||
cudaEgl->numChannels = 4;
|
||||
cudaEgl->eglColorFormat = CU_EGL_COLOR_FORMAT_ARGB;
|
||||
cudaEgl->cuFormat = CU_AD_FORMAT_UNSIGNED_INT8;
|
||||
void cudaProducerPrepareFrame(CUeglFrame *cudaEgl, CUdeviceptr cudaPtr, int bufferSize)
|
||||
{
|
||||
cudaEgl->frame.pPitch[0] = (void *)cudaPtr;
|
||||
cudaEgl->width = WIDTH;
|
||||
cudaEgl->depth = 0;
|
||||
cudaEgl->height = HEIGHT;
|
||||
cudaEgl->pitch = WIDTH * 4;
|
||||
cudaEgl->frameType = CU_EGL_FRAME_TYPE_PITCH;
|
||||
cudaEgl->planeCount = 1;
|
||||
cudaEgl->numChannels = 4;
|
||||
cudaEgl->eglColorFormat = CU_EGL_COLOR_FORMAT_ARGB;
|
||||
cudaEgl->cuFormat = CU_AD_FORMAT_UNSIGNED_INT8;
|
||||
}
|
||||
|
||||
static int count_present = 0, count_return = 0;
|
||||
static int count_present = 0, count_return = 0;
|
||||
static double present_time[25000] = {0}, total_time_present = 0;
|
||||
static double return_time[25000] = {0}, total_time_return = 0;
|
||||
|
||||
void presentApiStat(void);
|
||||
void presentApiStat(void) {
|
||||
int i = 0;
|
||||
double min = 10000000, max = 0;
|
||||
double average_launch_time = 0, standard_deviation = 0;
|
||||
if (count_present == 0) return;
|
||||
// lets compute the standard deviation
|
||||
min = max = present_time[1];
|
||||
average_launch_time = (total_time_present) / count_present;
|
||||
for (i = 1; i < count_present; i++) {
|
||||
standard_deviation += (present_time[i] - average_launch_time) *
|
||||
(present_time[i] - average_launch_time);
|
||||
if (present_time[i] < min) min = present_time[i];
|
||||
if (present_time[i] > max) max = present_time[i];
|
||||
}
|
||||
standard_deviation = sqrt(standard_deviation / count_present);
|
||||
printf("present Avg: %lf\n", average_launch_time);
|
||||
printf("present SD: %lf\n", standard_deviation);
|
||||
printf("present min: %lf\n", min);
|
||||
printf("present max: %lf\n", max);
|
||||
|
||||
min = max = return_time[1];
|
||||
average_launch_time = (total_time_return - return_time[0]) / count_return;
|
||||
for (i = 1; i < count_return; i++) {
|
||||
standard_deviation += (return_time[i] - average_launch_time) *
|
||||
(return_time[i] - average_launch_time);
|
||||
if (return_time[i] < min) min = return_time[i];
|
||||
if (return_time[i] > max) max = return_time[i];
|
||||
}
|
||||
standard_deviation = sqrt(standard_deviation / count_return);
|
||||
printf("return Avg: %lf\n", average_launch_time);
|
||||
printf("return SD: %lf\n", standard_deviation);
|
||||
printf("return min: %lf\n", min);
|
||||
printf("return max: %lf\n", max);
|
||||
}
|
||||
CUresult cudaProducerPresentFrame(test_cuda_producer_s *cudaProducer,
|
||||
CUeglFrame cudaEgl, int t) {
|
||||
static int flag = 0;
|
||||
CUresult status = CUDA_SUCCESS;
|
||||
struct timespec start, end;
|
||||
double curTime;
|
||||
CUdeviceptr pDevPtr = (CUdeviceptr)cudaEgl.frame.pPitch[0];
|
||||
cudaProducer_filter(cudaProducer->prodCudaStream, (char *)pDevPtr, WIDTH * 4,
|
||||
HEIGHT, cudaPresentReturnData, PROD_DATA + t, t);
|
||||
if (cudaProducer->profileAPI) {
|
||||
getTime(&start);
|
||||
}
|
||||
status = cuEGLStreamProducerPresentFrame(&cudaProducer->cudaConn, cudaEgl,
|
||||
&cudaProducer->prodCudaStream);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
printf("Cuda Producer: Present frame failed, status:%d\n", status);
|
||||
goto done;
|
||||
}
|
||||
flag++;
|
||||
if (cudaProducer->profileAPI && flag > 10) {
|
||||
getTime(&end);
|
||||
curTime = TIME_DIFF(end, start);
|
||||
present_time[count_present++] = curTime;
|
||||
if (count_present == 25000) count_present = 0;
|
||||
total_time_present += curTime;
|
||||
}
|
||||
done:
|
||||
return status;
|
||||
}
|
||||
|
||||
int flag = 0;
|
||||
CUresult cudaProducerReturnFrame(test_cuda_producer_s *cudaProducer,
|
||||
CUeglFrame cudaEgl, int t) {
|
||||
CUresult status = CUDA_SUCCESS;
|
||||
struct timespec start, end;
|
||||
double curTime;
|
||||
CUdeviceptr pDevPtr = 0;
|
||||
|
||||
pDevPtr = (CUdeviceptr)cudaEgl.frame.pPitch[0];
|
||||
if (cudaProducer->profileAPI) {
|
||||
getTime(&start);
|
||||
}
|
||||
|
||||
while (1) {
|
||||
status = cuEGLStreamProducerReturnFrame(&cudaProducer->cudaConn, &cudaEgl,
|
||||
&cudaProducer->prodCudaStream);
|
||||
if (status == CUDA_ERROR_LAUNCH_TIMEOUT) {
|
||||
continue;
|
||||
} else if (status != CUDA_SUCCESS) {
|
||||
printf("Cuda Producer: Return frame failed, status:%d\n", status);
|
||||
goto done;
|
||||
void presentApiStat(void)
|
||||
{
|
||||
int i = 0;
|
||||
double min = 10000000, max = 0;
|
||||
double average_launch_time = 0, standard_deviation = 0;
|
||||
if (count_present == 0)
|
||||
return;
|
||||
// lets compute the standard deviation
|
||||
min = max = present_time[1];
|
||||
average_launch_time = (total_time_present) / count_present;
|
||||
for (i = 1; i < count_present; i++) {
|
||||
standard_deviation += (present_time[i] - average_launch_time) * (present_time[i] - average_launch_time);
|
||||
if (present_time[i] < min)
|
||||
min = present_time[i];
|
||||
if (present_time[i] > max)
|
||||
max = present_time[i];
|
||||
}
|
||||
standard_deviation = sqrt(standard_deviation / count_present);
|
||||
printf("present Avg: %lf\n", average_launch_time);
|
||||
printf("present SD: %lf\n", standard_deviation);
|
||||
printf("present min: %lf\n", min);
|
||||
printf("present max: %lf\n", max);
|
||||
|
||||
min = max = return_time[1];
|
||||
average_launch_time = (total_time_return - return_time[0]) / count_return;
|
||||
for (i = 1; i < count_return; i++) {
|
||||
standard_deviation += (return_time[i] - average_launch_time) * (return_time[i] - average_launch_time);
|
||||
if (return_time[i] < min)
|
||||
min = return_time[i];
|
||||
if (return_time[i] > max)
|
||||
max = return_time[i];
|
||||
}
|
||||
standard_deviation = sqrt(standard_deviation / count_return);
|
||||
printf("return Avg: %lf\n", average_launch_time);
|
||||
printf("return SD: %lf\n", standard_deviation);
|
||||
printf("return min: %lf\n", min);
|
||||
printf("return max: %lf\n", max);
|
||||
}
|
||||
CUresult cudaProducerPresentFrame(test_cuda_producer_s *cudaProducer, CUeglFrame cudaEgl, int t)
|
||||
{
|
||||
static int flag = 0;
|
||||
CUresult status = CUDA_SUCCESS;
|
||||
struct timespec start, end;
|
||||
double curTime;
|
||||
CUdeviceptr pDevPtr = (CUdeviceptr)cudaEgl.frame.pPitch[0];
|
||||
cudaProducer_filter(
|
||||
cudaProducer->prodCudaStream, (char *)pDevPtr, WIDTH * 4, HEIGHT, cudaPresentReturnData, PROD_DATA + t, t);
|
||||
if (cudaProducer->profileAPI) {
|
||||
getTime(&start);
|
||||
}
|
||||
status = cuEGLStreamProducerPresentFrame(&cudaProducer->cudaConn, cudaEgl, &cudaProducer->prodCudaStream);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
printf("Cuda Producer: Present frame failed, status:%d\n", status);
|
||||
goto done;
|
||||
}
|
||||
flag++;
|
||||
if (cudaProducer->profileAPI && flag > 10) {
|
||||
getTime(&end);
|
||||
curTime = TIME_DIFF(end, start);
|
||||
present_time[count_present++] = curTime;
|
||||
if (count_present == 25000)
|
||||
count_present = 0;
|
||||
total_time_present += curTime;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (cudaProducer->profileAPI) {
|
||||
getTime(&end);
|
||||
curTime = TIME_DIFF(end, start);
|
||||
return_time[count_return++] = curTime;
|
||||
if (count_return == 25000) count_return = 0;
|
||||
total_time_return += curTime;
|
||||
}
|
||||
if (flag % 2 == 0) {
|
||||
cudaPresentReturnData++;
|
||||
}
|
||||
cudaProducer_filter(cudaProducer->prodCudaStream, (char *)pDevPtr, WIDTH * 4,
|
||||
HEIGHT, CONS_DATA + t, cudaPresentReturnData, t);
|
||||
flag++;
|
||||
done:
|
||||
return status;
|
||||
return status;
|
||||
}
|
||||
|
||||
CUresult cudaDeviceCreateProducer(test_cuda_producer_s *cudaProducer) {
|
||||
CUdevice device;
|
||||
CUresult status = CUDA_SUCCESS;
|
||||
int flag = 0;
|
||||
CUresult cudaProducerReturnFrame(test_cuda_producer_s *cudaProducer, CUeglFrame cudaEgl, int t)
|
||||
{
|
||||
CUresult status = CUDA_SUCCESS;
|
||||
struct timespec start, end;
|
||||
double curTime;
|
||||
CUdeviceptr pDevPtr = 0;
|
||||
|
||||
if (CUDA_SUCCESS != (status = cuInit(0))) {
|
||||
printf("Failed to initialize CUDA\n");
|
||||
return status;
|
||||
}
|
||||
pDevPtr = (CUdeviceptr)cudaEgl.frame.pPitch[0];
|
||||
if (cudaProducer->profileAPI) {
|
||||
getTime(&start);
|
||||
}
|
||||
|
||||
if (CUDA_SUCCESS !=
|
||||
(status = cuDeviceGet(&device, cudaProducer->cudaDevId))) {
|
||||
printf("failed to get CUDA device\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
if (CUDA_SUCCESS !=
|
||||
(status = cuCtxCreate(&cudaProducer->context, 0, device))) {
|
||||
printf("failed to create CUDA context\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
int major = 0, minor = 0;
|
||||
char deviceName[256];
|
||||
cuDeviceGetAttribute(&major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR,
|
||||
device);
|
||||
cuDeviceGetAttribute(&minor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR,
|
||||
device);
|
||||
cuDeviceGetName(deviceName, 256, device);
|
||||
printf(
|
||||
"CUDA Producer on GPU Device %d: \"%s\" with compute capability "
|
||||
"%d.%d\n\n",
|
||||
device, deviceName, major, minor);
|
||||
|
||||
cuCtxPopCurrent(&cudaProducer->context);
|
||||
|
||||
if (major < 6) {
|
||||
printf(
|
||||
"EGLStream_CUDA_CrossGPU requires SM 6.0 or higher arch GPU. "
|
||||
"Exiting...\n");
|
||||
exit(2); // EXIT_WAIVED
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
CUresult cudaProducerInit(test_cuda_producer_s *cudaProducer, TestArgs *args) {
|
||||
CUresult status = CUDA_SUCCESS;
|
||||
int bufferSize;
|
||||
|
||||
cudaProducer->charCnt = args->charCnt;
|
||||
bufferSize = cudaProducer->charCnt;
|
||||
|
||||
cudaProducer->tempBuff = (char *)malloc(bufferSize);
|
||||
if (!cudaProducer->tempBuff) {
|
||||
printf("Cuda Producer: Failed to allocate image buffer\n");
|
||||
status = CUDA_ERROR_UNKNOWN;
|
||||
goto done;
|
||||
}
|
||||
memset((void *)cudaProducer->tempBuff, INIT_DATA, cudaProducer->charCnt);
|
||||
|
||||
// Fill this init data
|
||||
status = cuMemAlloc(&cudaProducer->cudaPtr, bufferSize);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
printf("Cuda Producer: cuda Malloc failed, status:%d\n", status);
|
||||
goto done;
|
||||
}
|
||||
status = cuMemcpyHtoD(cudaProducer->cudaPtr, (void *)(cudaProducer->tempBuff),
|
||||
bufferSize);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
printf("Cuda Producer: cuMemCpy failed, status:%d\n", status);
|
||||
goto done;
|
||||
}
|
||||
|
||||
// Fill this init data
|
||||
status = cuMemAlloc(&cudaProducer->cudaPtr1, bufferSize);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
printf("Cuda Producer: cuda Malloc failed, status:%d\n", status);
|
||||
goto done;
|
||||
}
|
||||
status = cuMemcpyHtoD(cudaProducer->cudaPtr1,
|
||||
(void *)(cudaProducer->tempBuff), bufferSize);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
printf("Cuda Producer: cuMemCpy failed, status:%d\n", status);
|
||||
goto done;
|
||||
}
|
||||
|
||||
status = cuStreamCreate(&cudaProducer->prodCudaStream, 0);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
printf("Cuda Producer: cuStreamCreate failed, status:%d\n", status);
|
||||
goto done;
|
||||
}
|
||||
|
||||
// Fill this init data
|
||||
status = cuMemAlloc(&cudaPtrFake, 100);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
printf("Cuda Producer: cuda Malloc failed, status:%d\n", status);
|
||||
goto done;
|
||||
}
|
||||
|
||||
atexit(presentApiStat);
|
||||
while (1) {
|
||||
status = cuEGLStreamProducerReturnFrame(&cudaProducer->cudaConn, &cudaEgl, &cudaProducer->prodCudaStream);
|
||||
if (status == CUDA_ERROR_LAUNCH_TIMEOUT) {
|
||||
continue;
|
||||
}
|
||||
else if (status != CUDA_SUCCESS) {
|
||||
printf("Cuda Producer: Return frame failed, status:%d\n", status);
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (cudaProducer->profileAPI) {
|
||||
getTime(&end);
|
||||
curTime = TIME_DIFF(end, start);
|
||||
return_time[count_return++] = curTime;
|
||||
if (count_return == 25000)
|
||||
count_return = 0;
|
||||
total_time_return += curTime;
|
||||
}
|
||||
if (flag % 2 == 0) {
|
||||
cudaPresentReturnData++;
|
||||
}
|
||||
cudaProducer_filter(
|
||||
cudaProducer->prodCudaStream, (char *)pDevPtr, WIDTH * 4, HEIGHT, CONS_DATA + t, cudaPresentReturnData, t);
|
||||
flag++;
|
||||
done:
|
||||
return status;
|
||||
return status;
|
||||
}
|
||||
|
||||
CUresult cudaProducerDeinit(test_cuda_producer_s *cudaProducer) {
|
||||
if (cudaProducer->tempBuff) {
|
||||
free(cudaProducer->tempBuff);
|
||||
}
|
||||
if (cudaProducer->cudaPtr) {
|
||||
cuMemFree(cudaProducer->cudaPtr);
|
||||
}
|
||||
return cuEGLStreamProducerDisconnect(&cudaProducer->cudaConn);
|
||||
CUresult cudaDeviceCreateProducer(test_cuda_producer_s *cudaProducer)
|
||||
{
|
||||
CUdevice device;
|
||||
CUresult status = CUDA_SUCCESS;
|
||||
|
||||
if (CUDA_SUCCESS != (status = cuInit(0))) {
|
||||
printf("Failed to initialize CUDA\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
if (CUDA_SUCCESS != (status = cuDeviceGet(&device, cudaProducer->cudaDevId))) {
|
||||
printf("failed to get CUDA device\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
if (CUDA_SUCCESS != (status = cuCtxCreate(&cudaProducer->context, 0, device))) {
|
||||
printf("failed to create CUDA context\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
int major = 0, minor = 0;
|
||||
char deviceName[256];
|
||||
cuDeviceGetAttribute(&major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, device);
|
||||
cuDeviceGetAttribute(&minor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, device);
|
||||
cuDeviceGetName(deviceName, 256, device);
|
||||
printf("CUDA Producer on GPU Device %d: \"%s\" with compute capability "
|
||||
"%d.%d\n\n",
|
||||
device,
|
||||
deviceName,
|
||||
major,
|
||||
minor);
|
||||
|
||||
cuCtxPopCurrent(&cudaProducer->context);
|
||||
|
||||
if (major < 6) {
|
||||
printf("EGLStream_CUDA_CrossGPU requires SM 6.0 or higher arch GPU. "
|
||||
"Exiting...\n");
|
||||
exit(2); // EXIT_WAIVED
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
CUresult cudaProducerInit(test_cuda_producer_s *cudaProducer, TestArgs *args)
|
||||
{
|
||||
CUresult status = CUDA_SUCCESS;
|
||||
int bufferSize;
|
||||
|
||||
cudaProducer->charCnt = args->charCnt;
|
||||
bufferSize = cudaProducer->charCnt;
|
||||
|
||||
cudaProducer->tempBuff = (char *)malloc(bufferSize);
|
||||
if (!cudaProducer->tempBuff) {
|
||||
printf("Cuda Producer: Failed to allocate image buffer\n");
|
||||
status = CUDA_ERROR_UNKNOWN;
|
||||
goto done;
|
||||
}
|
||||
memset((void *)cudaProducer->tempBuff, INIT_DATA, cudaProducer->charCnt);
|
||||
|
||||
// Fill this init data
|
||||
status = cuMemAlloc(&cudaProducer->cudaPtr, bufferSize);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
printf("Cuda Producer: cuda Malloc failed, status:%d\n", status);
|
||||
goto done;
|
||||
}
|
||||
status = cuMemcpyHtoD(cudaProducer->cudaPtr, (void *)(cudaProducer->tempBuff), bufferSize);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
printf("Cuda Producer: cuMemCpy failed, status:%d\n", status);
|
||||
goto done;
|
||||
}
|
||||
|
||||
// Fill this init data
|
||||
status = cuMemAlloc(&cudaProducer->cudaPtr1, bufferSize);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
printf("Cuda Producer: cuda Malloc failed, status:%d\n", status);
|
||||
goto done;
|
||||
}
|
||||
status = cuMemcpyHtoD(cudaProducer->cudaPtr1, (void *)(cudaProducer->tempBuff), bufferSize);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
printf("Cuda Producer: cuMemCpy failed, status:%d\n", status);
|
||||
goto done;
|
||||
}
|
||||
|
||||
status = cuStreamCreate(&cudaProducer->prodCudaStream, 0);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
printf("Cuda Producer: cuStreamCreate failed, status:%d\n", status);
|
||||
goto done;
|
||||
}
|
||||
|
||||
// Fill this init data
|
||||
status = cuMemAlloc(&cudaPtrFake, 100);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
printf("Cuda Producer: cuda Malloc failed, status:%d\n", status);
|
||||
goto done;
|
||||
}
|
||||
|
||||
atexit(presentApiStat);
|
||||
done:
|
||||
return status;
|
||||
}
|
||||
|
||||
CUresult cudaProducerDeinit(test_cuda_producer_s *cudaProducer)
|
||||
{
|
||||
if (cudaProducer->tempBuff) {
|
||||
free(cudaProducer->tempBuff);
|
||||
}
|
||||
if (cudaProducer->cudaPtr) {
|
||||
cuMemFree(cudaProducer->cudaPtr);
|
||||
}
|
||||
return cuEGLStreamProducerDisconnect(&cudaProducer->cudaConn);
|
||||
}
|
||||
|
||||
@@ -33,36 +33,39 @@
|
||||
#define _CUDA_PRODUCER_H_
|
||||
#include <EGL/egl.h>
|
||||
#include <EGL/eglext.h>
|
||||
#include <cuda.h>
|
||||
#include <cuda_runtime.h>
|
||||
|
||||
#include "cudaEGL.h"
|
||||
#include "eglstrm_common.h"
|
||||
#include <cuda_runtime.h>
|
||||
#include <cuda.h>
|
||||
|
||||
typedef struct _test_cuda_producer_s {
|
||||
// Stream params
|
||||
CUcontext context;
|
||||
CUeglStreamConnection cudaConn;
|
||||
int cudaDevId;
|
||||
EGLStreamKHR eglStream;
|
||||
EGLDisplay eglDisplay;
|
||||
unsigned int charCnt;
|
||||
bool profileAPI;
|
||||
char *tempBuff;
|
||||
CUdeviceptr cudaPtr;
|
||||
CUdeviceptr cudaPtr1;
|
||||
CUstream prodCudaStream;
|
||||
typedef struct _test_cuda_producer_s
|
||||
{
|
||||
// Stream params
|
||||
CUcontext context;
|
||||
CUeglStreamConnection cudaConn;
|
||||
int cudaDevId;
|
||||
EGLStreamKHR eglStream;
|
||||
EGLDisplay eglDisplay;
|
||||
unsigned int charCnt;
|
||||
bool profileAPI;
|
||||
char *tempBuff;
|
||||
CUdeviceptr cudaPtr;
|
||||
CUdeviceptr cudaPtr1;
|
||||
CUstream prodCudaStream;
|
||||
} test_cuda_producer_s;
|
||||
|
||||
CUresult cudaProducerInit(test_cuda_producer_s *cudaProducer, TestArgs *args);
|
||||
CUresult cudaProducerPresentFrame(test_cuda_producer_s *parserArg,
|
||||
CUeglFrame cudaEgl, int t);
|
||||
CUresult cudaProducerReturnFrame(test_cuda_producer_s *parserArg,
|
||||
CUeglFrame cudaEgl, int t);
|
||||
CUresult cudaProducerDeinit(test_cuda_producer_s *cudaProducer);
|
||||
CUresult cudaDeviceCreateProducer(test_cuda_producer_s *cudaProducer);
|
||||
cudaError_t cudaProducer_filter(CUstream cStream, char *pSrc, int width,
|
||||
int height, char expectedVal, char newVal,
|
||||
int frameNumber);
|
||||
void cudaProducerPrepareFrame(CUeglFrame *cudaEgl, CUdeviceptr cudaPtr,
|
||||
int bufferSize);
|
||||
CUresult cudaProducerInit(test_cuda_producer_s *cudaProducer, TestArgs *args);
|
||||
CUresult cudaProducerPresentFrame(test_cuda_producer_s *parserArg, CUeglFrame cudaEgl, int t);
|
||||
CUresult cudaProducerReturnFrame(test_cuda_producer_s *parserArg, CUeglFrame cudaEgl, int t);
|
||||
CUresult cudaProducerDeinit(test_cuda_producer_s *cudaProducer);
|
||||
CUresult cudaDeviceCreateProducer(test_cuda_producer_s *cudaProducer);
|
||||
cudaError_t cudaProducer_filter(CUstream cStream,
|
||||
char *pSrc,
|
||||
int width,
|
||||
int height,
|
||||
char expectedVal,
|
||||
char newVal,
|
||||
int frameNumber);
|
||||
void cudaProducerPrepareFrame(CUeglFrame *cudaEgl, CUdeviceptr cudaPtr, int bufferSize);
|
||||
#endif
|
||||
|
||||
@@ -31,343 +31,343 @@
|
||||
|
||||
#include "eglstrm_common.h"
|
||||
|
||||
EGLStreamKHR g_producerEglStream = EGL_NO_STREAM_KHR;
|
||||
EGLStreamKHR g_consumerEglStream = EGL_NO_STREAM_KHR;
|
||||
EGLDisplay g_producerEglDisplay = EGL_NO_DISPLAY;
|
||||
EGLDisplay g_consumerEglDisplay = EGL_NO_DISPLAY;
|
||||
int cudaDevIndexProd = -1;
|
||||
int cudaDevIndexCons = -1;
|
||||
EGLStreamKHR g_producerEglStream = EGL_NO_STREAM_KHR;
|
||||
EGLStreamKHR g_consumerEglStream = EGL_NO_STREAM_KHR;
|
||||
EGLDisplay g_producerEglDisplay = EGL_NO_DISPLAY;
|
||||
EGLDisplay g_consumerEglDisplay = EGL_NO_DISPLAY;
|
||||
int cudaDevIndexProd = -1;
|
||||
int cudaDevIndexCons = -1;
|
||||
|
||||
#if defined(EXTENSION_LIST)
|
||||
EXTENSION_LIST(EXTLST_DECL)
|
||||
typedef void (*extlst_fnptr_t)(void);
|
||||
static struct {
|
||||
extlst_fnptr_t *fnptr;
|
||||
char const *name;
|
||||
bool is_dgpu; // This function is need only for dgpu case
|
||||
static struct
|
||||
{
|
||||
extlst_fnptr_t *fnptr;
|
||||
char const *name;
|
||||
bool is_dgpu; // This function is need only for dgpu case
|
||||
} extensionList[] = {EXTENSION_LIST(EXTLST_ENTRY)};
|
||||
|
||||
int eglSetupExtensions(bool isCrossDevice) {
|
||||
unsigned int i;
|
||||
int eglSetupExtensions(bool isCrossDevice)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < (sizeof(extensionList) / sizeof(*extensionList)); i++) {
|
||||
// load the dgpu function only if we are running cross device test
|
||||
if ((!extensionList[i].is_dgpu) ||
|
||||
(extensionList[i].is_dgpu == isCrossDevice)) {
|
||||
*extensionList[i].fnptr = eglGetProcAddress(extensionList[i].name);
|
||||
if (*extensionList[i].fnptr == NULL) {
|
||||
printf("Couldn't get address of %s()\n", extensionList[i].name);
|
||||
return 0;
|
||||
}
|
||||
for (i = 0; i < (sizeof(extensionList) / sizeof(*extensionList)); i++) {
|
||||
// load the dgpu function only if we are running cross device test
|
||||
if ((!extensionList[i].is_dgpu) || (extensionList[i].is_dgpu == isCrossDevice)) {
|
||||
*extensionList[i].fnptr = eglGetProcAddress(extensionList[i].name);
|
||||
if (*extensionList[i].fnptr == NULL) {
|
||||
printf("Couldn't get address of %s()\n", extensionList[i].name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int EGLStreamInit(bool isCrossDevice, int isConsumer,
|
||||
EGLNativeFileDescriptorKHR fileDesc) {
|
||||
static const EGLint streamAttrFIFOMode[] = {
|
||||
EGL_STREAM_FIFO_LENGTH_KHR, 5, EGL_SUPPORT_REUSE_NV, EGL_FALSE, EGL_NONE};
|
||||
EGLDisplay eglDisplay[2] = {0};
|
||||
EGLStreamKHR eglStream[2] = {0};
|
||||
EGLBoolean eglStatus;
|
||||
int EGLStreamInit(bool isCrossDevice, int isConsumer, EGLNativeFileDescriptorKHR fileDesc)
|
||||
{
|
||||
static const EGLint streamAttrFIFOMode[] = {
|
||||
EGL_STREAM_FIFO_LENGTH_KHR, 5, EGL_SUPPORT_REUSE_NV, EGL_FALSE, EGL_NONE};
|
||||
EGLDisplay eglDisplay[2] = {0};
|
||||
EGLStreamKHR eglStream[2] = {0};
|
||||
EGLBoolean eglStatus;
|
||||
|
||||
#define MAX_EGL_DEVICES 4
|
||||
|
||||
EGLDeviceEXT devices[MAX_EGL_DEVICES];
|
||||
EGLint numDevices = 0;
|
||||
EGLDeviceEXT devices[MAX_EGL_DEVICES];
|
||||
EGLint numDevices = 0;
|
||||
|
||||
eglStatus = eglQueryDevicesEXT(MAX_EGL_DEVICES, devices, &numDevices);
|
||||
if (eglStatus != EGL_TRUE) {
|
||||
printf("Error querying EGL devices\n");
|
||||
goto Done;
|
||||
}
|
||||
|
||||
if (numDevices == 0) {
|
||||
printf("No EGL devices found\n");
|
||||
eglStatus = EGL_FALSE;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
// If cross device, create discrete GPU stream first and then create the
|
||||
// integrated GPU stream to connect to it via fd. The other way round fails
|
||||
// in producer connect.
|
||||
//
|
||||
// TODO: Find out if this EGL behavior is by design.
|
||||
if (isConsumer) {
|
||||
int egl_device_id = 0;
|
||||
for (egl_device_id = 0; egl_device_id < numDevices; egl_device_id++) {
|
||||
EGLAttrib cuda_device;
|
||||
eglStatus = eglQueryDeviceAttribEXT(devices[egl_device_id],
|
||||
EGL_CUDA_DEVICE_NV, &cuda_device);
|
||||
if (eglStatus == EGL_TRUE) {
|
||||
cudaDevIndexCons = cuda_device; // We select first EGL-CUDA Capable
|
||||
// device for consumer.
|
||||
printf(
|
||||
"Found EGL-CUDA Capable device with CUDA Device id = %d out of "
|
||||
"egl_device_id = %d\n",
|
||||
(int)cudaDevIndexCons, egl_device_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (egl_device_id >= numDevices) {
|
||||
printf("No CUDA Capable EGL Device found.. Waiving execution\n");
|
||||
goto Done;
|
||||
}
|
||||
|
||||
g_consumerEglDisplay = eglGetPlatformDisplayEXT(
|
||||
EGL_PLATFORM_DEVICE_EXT, (void *)devices[egl_device_id], NULL);
|
||||
if (g_consumerEglDisplay == EGL_NO_DISPLAY) {
|
||||
printf("Could not get EGL display from device. \n");
|
||||
eglStatus = EGL_FALSE;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
eglStatus = eglInitialize(g_consumerEglDisplay, 0, 0);
|
||||
if (!eglStatus) {
|
||||
printf("EGL failed to initialize. \n");
|
||||
eglStatus = EGL_FALSE;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
g_consumerEglStream =
|
||||
eglCreateStreamKHR(g_consumerEglDisplay, streamAttrFIFOMode);
|
||||
if (g_consumerEglStream == EGL_NO_STREAM_KHR) {
|
||||
printf("Could not create EGL stream.\n");
|
||||
eglStatus = EGL_FALSE;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
eglStatus = eglStreamAttribKHR(g_consumerEglDisplay, g_consumerEglStream,
|
||||
EGL_CONSUMER_LATENCY_USEC_KHR, 16000);
|
||||
eglStatus = eglQueryDevicesEXT(MAX_EGL_DEVICES, devices, &numDevices);
|
||||
if (eglStatus != EGL_TRUE) {
|
||||
printf("eglStreamAttribKHR EGL_CONSUMER_LATENCY_USEC_KHR failed\n");
|
||||
goto Done;
|
||||
printf("Error querying EGL devices\n");
|
||||
goto Done;
|
||||
}
|
||||
|
||||
eglStatus =
|
||||
eglStreamAttribKHR(g_consumerEglDisplay, g_consumerEglStream,
|
||||
EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR, 16000);
|
||||
if (eglStatus != EGL_TRUE) {
|
||||
printf(
|
||||
"eglStreamAttribKHR EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR failed\n");
|
||||
goto Done;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isConsumer) { // Producer
|
||||
|
||||
if (fileDesc == EGL_NO_FILE_DESCRIPTOR_KHR) {
|
||||
printf("Cuda Producer received bad file descriptor\n");
|
||||
eglStatus = EGL_FALSE;
|
||||
goto Done;
|
||||
if (numDevices == 0) {
|
||||
printf("No EGL devices found\n");
|
||||
eglStatus = EGL_FALSE;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
int egl_device_id = 0;
|
||||
int egl_cuda_devices = 0;
|
||||
for (egl_device_id = 0; egl_device_id < numDevices; egl_device_id++) {
|
||||
EGLAttrib cuda_device = -1;
|
||||
eglStatus = eglQueryDeviceAttribEXT(devices[egl_device_id],
|
||||
EGL_CUDA_DEVICE_NV, &cuda_device);
|
||||
if (eglStatus == EGL_TRUE) {
|
||||
egl_cuda_devices++;
|
||||
if (isCrossDevice && (egl_cuda_devices > 1)) {
|
||||
// We select second EGL-CUDA Capable device for producer.
|
||||
cudaDevIndexProd = (int)cuda_device;
|
||||
printf(
|
||||
"Found EGL-CUDA Capable device with CUDA Device id = %d "
|
||||
"egl_device_id = %d \n",
|
||||
(int)cudaDevIndexProd, egl_device_id);
|
||||
break;
|
||||
// If cross device, create discrete GPU stream first and then create the
|
||||
// integrated GPU stream to connect to it via fd. The other way round fails
|
||||
// in producer connect.
|
||||
//
|
||||
// TODO: Find out if this EGL behavior is by design.
|
||||
if (isConsumer) {
|
||||
int egl_device_id = 0;
|
||||
for (egl_device_id = 0; egl_device_id < numDevices; egl_device_id++) {
|
||||
EGLAttrib cuda_device;
|
||||
eglStatus = eglQueryDeviceAttribEXT(devices[egl_device_id], EGL_CUDA_DEVICE_NV, &cuda_device);
|
||||
if (eglStatus == EGL_TRUE) {
|
||||
cudaDevIndexCons = cuda_device; // We select first EGL-CUDA Capable
|
||||
// device for consumer.
|
||||
printf("Found EGL-CUDA Capable device with CUDA Device id = %d out of "
|
||||
"egl_device_id = %d\n",
|
||||
(int)cudaDevIndexCons,
|
||||
egl_device_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!isCrossDevice) {
|
||||
// We select first EGL-CUDA Capable device for producer same as
|
||||
// consumer.
|
||||
cudaDevIndexProd = (int)cuda_device;
|
||||
printf(
|
||||
"Found EGL-CUDA Capable device with CUDA Device id = %d "
|
||||
"egl_device_id = %d \n",
|
||||
(int)cudaDevIndexProd, egl_device_id);
|
||||
break;
|
||||
|
||||
if (egl_device_id >= numDevices) {
|
||||
printf("No CUDA Capable EGL Device found.. Waiving execution\n");
|
||||
goto Done;
|
||||
}
|
||||
|
||||
g_consumerEglDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT, (void *)devices[egl_device_id], NULL);
|
||||
if (g_consumerEglDisplay == EGL_NO_DISPLAY) {
|
||||
printf("Could not get EGL display from device. \n");
|
||||
eglStatus = EGL_FALSE;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
eglStatus = eglInitialize(g_consumerEglDisplay, 0, 0);
|
||||
if (!eglStatus) {
|
||||
printf("EGL failed to initialize. \n");
|
||||
eglStatus = EGL_FALSE;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
g_consumerEglStream = eglCreateStreamKHR(g_consumerEglDisplay, streamAttrFIFOMode);
|
||||
if (g_consumerEglStream == EGL_NO_STREAM_KHR) {
|
||||
printf("Could not create EGL stream.\n");
|
||||
eglStatus = EGL_FALSE;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
eglStatus = eglStreamAttribKHR(g_consumerEglDisplay, g_consumerEglStream, EGL_CONSUMER_LATENCY_USEC_KHR, 16000);
|
||||
if (eglStatus != EGL_TRUE) {
|
||||
printf("eglStreamAttribKHR EGL_CONSUMER_LATENCY_USEC_KHR failed\n");
|
||||
goto Done;
|
||||
}
|
||||
|
||||
eglStatus =
|
||||
eglStreamAttribKHR(g_consumerEglDisplay, g_consumerEglStream, EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR, 16000);
|
||||
if (eglStatus != EGL_TRUE) {
|
||||
printf("eglStreamAttribKHR EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR failed\n");
|
||||
goto Done;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (egl_device_id >= numDevices) {
|
||||
printf("No CUDA Capable EGL Device found.. Waiving execution\n");
|
||||
goto Done;
|
||||
}
|
||||
if (!isConsumer) { // Producer
|
||||
|
||||
g_producerEglDisplay = eglGetPlatformDisplayEXT(
|
||||
EGL_PLATFORM_DEVICE_EXT, (void *)devices[egl_device_id], NULL);
|
||||
if (g_producerEglDisplay == EGL_NO_DISPLAY) {
|
||||
printf("Could not get EGL display from device. \n");
|
||||
eglStatus = EGL_FALSE;
|
||||
goto Done;
|
||||
}
|
||||
if (fileDesc == EGL_NO_FILE_DESCRIPTOR_KHR) {
|
||||
printf("Cuda Producer received bad file descriptor\n");
|
||||
eglStatus = EGL_FALSE;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
eglStatus = eglInitialize(g_producerEglDisplay, 0, 0);
|
||||
if (!eglStatus) {
|
||||
printf("EGL failed to initialize. \n");
|
||||
eglStatus = EGL_FALSE;
|
||||
goto Done;
|
||||
}
|
||||
int egl_device_id = 0;
|
||||
int egl_cuda_devices = 0;
|
||||
for (egl_device_id = 0; egl_device_id < numDevices; egl_device_id++) {
|
||||
EGLAttrib cuda_device = -1;
|
||||
eglStatus = eglQueryDeviceAttribEXT(devices[egl_device_id], EGL_CUDA_DEVICE_NV, &cuda_device);
|
||||
if (eglStatus == EGL_TRUE) {
|
||||
egl_cuda_devices++;
|
||||
if (isCrossDevice && (egl_cuda_devices > 1)) {
|
||||
// We select second EGL-CUDA Capable device for producer.
|
||||
cudaDevIndexProd = (int)cuda_device;
|
||||
printf("Found EGL-CUDA Capable device with CUDA Device id = %d "
|
||||
"egl_device_id = %d \n",
|
||||
(int)cudaDevIndexProd,
|
||||
egl_device_id);
|
||||
break;
|
||||
}
|
||||
if (!isCrossDevice) {
|
||||
// We select first EGL-CUDA Capable device for producer same as
|
||||
// consumer.
|
||||
cudaDevIndexProd = (int)cuda_device;
|
||||
printf("Found EGL-CUDA Capable device with CUDA Device id = %d "
|
||||
"egl_device_id = %d \n",
|
||||
(int)cudaDevIndexProd,
|
||||
egl_device_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_producerEglStream =
|
||||
eglCreateStreamFromFileDescriptorKHR(g_producerEglDisplay, fileDesc);
|
||||
close(fileDesc);
|
||||
if (egl_device_id >= numDevices) {
|
||||
printf("No CUDA Capable EGL Device found.. Waiving execution\n");
|
||||
goto Done;
|
||||
}
|
||||
|
||||
if (g_producerEglStream == EGL_NO_STREAM_KHR) {
|
||||
printf("CUDA Producer Could not create EGL stream.\n");
|
||||
eglStatus = EGL_FALSE;
|
||||
goto Done;
|
||||
} else {
|
||||
printf("Producer created EGLStream for the GPU.\n");
|
||||
g_producerEglDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT, (void *)devices[egl_device_id], NULL);
|
||||
if (g_producerEglDisplay == EGL_NO_DISPLAY) {
|
||||
printf("Could not get EGL display from device. \n");
|
||||
eglStatus = EGL_FALSE;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
eglStatus = eglInitialize(g_producerEglDisplay, 0, 0);
|
||||
if (!eglStatus) {
|
||||
printf("EGL failed to initialize. \n");
|
||||
eglStatus = EGL_FALSE;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
g_producerEglStream = eglCreateStreamFromFileDescriptorKHR(g_producerEglDisplay, fileDesc);
|
||||
close(fileDesc);
|
||||
|
||||
if (g_producerEglStream == EGL_NO_STREAM_KHR) {
|
||||
printf("CUDA Producer Could not create EGL stream.\n");
|
||||
eglStatus = EGL_FALSE;
|
||||
goto Done;
|
||||
}
|
||||
else {
|
||||
printf("Producer created EGLStream for the GPU.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Done:
|
||||
return eglStatus == EGL_TRUE ? 1 : 0;
|
||||
return eglStatus == EGL_TRUE ? 1 : 0;
|
||||
}
|
||||
|
||||
void EGLStreamFini(void) {
|
||||
if (g_producerEglStream != EGL_NO_STREAM_KHR) {
|
||||
eglDestroyStreamKHR(g_producerEglDisplay, g_producerEglStream);
|
||||
}
|
||||
if (g_consumerEglStream != g_producerEglStream) {
|
||||
if (g_consumerEglStream != EGL_NO_STREAM_KHR) {
|
||||
eglDestroyStreamKHR(g_consumerEglDisplay, g_consumerEglStream);
|
||||
void EGLStreamFini(void)
|
||||
{
|
||||
if (g_producerEglStream != EGL_NO_STREAM_KHR) {
|
||||
eglDestroyStreamKHR(g_producerEglDisplay, g_producerEglStream);
|
||||
}
|
||||
if (g_consumerEglStream != g_producerEglStream) {
|
||||
if (g_consumerEglStream != EGL_NO_STREAM_KHR) {
|
||||
eglDestroyStreamKHR(g_consumerEglDisplay, g_consumerEglStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int UnixSocketConnect(const char *socket_name) {
|
||||
int sock_fd = -1;
|
||||
struct sockaddr_un sock_addr;
|
||||
int wait_loop = 0;
|
||||
int UnixSocketConnect(const char *socket_name)
|
||||
{
|
||||
int sock_fd = -1;
|
||||
struct sockaddr_un sock_addr;
|
||||
int wait_loop = 0;
|
||||
|
||||
sock_fd = socket(PF_UNIX, SOCK_STREAM, 0);
|
||||
if (sock_fd < 0) {
|
||||
printf("%s: socket create failed.\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (verbose) printf("%s: send_fd: sock_fd: %d\n", __func__, sock_fd);
|
||||
|
||||
memset(&sock_addr, 0, sizeof(struct sockaddr_un));
|
||||
sock_addr.sun_family = AF_UNIX;
|
||||
strncpy(sock_addr.sun_path, socket_name, sizeof(sock_addr.sun_path) - 1);
|
||||
|
||||
while (connect(sock_fd, (const struct sockaddr *)&sock_addr,
|
||||
sizeof(struct sockaddr_un))) {
|
||||
if (wait_loop < 60) {
|
||||
if (!wait_loop)
|
||||
printf("Waiting for EGL stream producer ");
|
||||
else
|
||||
printf(".");
|
||||
fflush(stdout);
|
||||
sleep(1);
|
||||
wait_loop++;
|
||||
} else {
|
||||
printf("\n%s: Waiting timed out\n", __func__);
|
||||
return -1;
|
||||
sock_fd = socket(PF_UNIX, SOCK_STREAM, 0);
|
||||
if (sock_fd < 0) {
|
||||
printf("%s: socket create failed.\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (wait_loop) printf("\n");
|
||||
|
||||
if (verbose) printf("%s: Wait is done\n", __func__);
|
||||
if (verbose)
|
||||
printf("%s: send_fd: sock_fd: %d\n", __func__, sock_fd);
|
||||
|
||||
return sock_fd;
|
||||
memset(&sock_addr, 0, sizeof(struct sockaddr_un));
|
||||
sock_addr.sun_family = AF_UNIX;
|
||||
strncpy(sock_addr.sun_path, socket_name, sizeof(sock_addr.sun_path) - 1);
|
||||
|
||||
while (connect(sock_fd, (const struct sockaddr *)&sock_addr, sizeof(struct sockaddr_un))) {
|
||||
if (wait_loop < 60) {
|
||||
if (!wait_loop)
|
||||
printf("Waiting for EGL stream producer ");
|
||||
else
|
||||
printf(".");
|
||||
fflush(stdout);
|
||||
sleep(1);
|
||||
wait_loop++;
|
||||
}
|
||||
else {
|
||||
printf("\n%s: Waiting timed out\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (wait_loop)
|
||||
printf("\n");
|
||||
|
||||
if (verbose)
|
||||
printf("%s: Wait is done\n", __func__);
|
||||
|
||||
return sock_fd;
|
||||
}
|
||||
|
||||
/* Send <fd_to_send> (a file descriptor) to another process */
|
||||
/* over a unix domain socket named <socket_name>. */
|
||||
/* <socket_name> can be any nonexistant filename. */
|
||||
int EGLStreamSendfd(int send_fd, int fd_to_send) {
|
||||
struct msghdr msg;
|
||||
struct iovec iov[1];
|
||||
char ctrl_buf[CMSG_SPACE(sizeof(int))];
|
||||
struct cmsghdr *cmsg = NULL;
|
||||
void *data;
|
||||
int res;
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
int EGLStreamSendfd(int send_fd, int fd_to_send)
|
||||
{
|
||||
struct msghdr msg;
|
||||
struct iovec iov[1];
|
||||
char ctrl_buf[CMSG_SPACE(sizeof(int))];
|
||||
struct cmsghdr *cmsg = NULL;
|
||||
void *data;
|
||||
int res;
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
|
||||
iov[0].iov_len = 1; // must send at least 1 byte
|
||||
iov[0].iov_base = (void *)"x"; // any byte value (value ignored)
|
||||
msg.msg_iov = iov;
|
||||
msg.msg_iovlen = 1;
|
||||
iov[0].iov_len = 1; // must send at least 1 byte
|
||||
iov[0].iov_base = (void *)"x"; // any byte value (value ignored)
|
||||
msg.msg_iov = iov;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
memset(ctrl_buf, 0, sizeof(ctrl_buf));
|
||||
msg.msg_control = ctrl_buf;
|
||||
msg.msg_controllen = sizeof(ctrl_buf);
|
||||
memset(ctrl_buf, 0, sizeof(ctrl_buf));
|
||||
msg.msg_control = ctrl_buf;
|
||||
msg.msg_controllen = sizeof(ctrl_buf);
|
||||
|
||||
cmsg = CMSG_FIRSTHDR(&msg);
|
||||
cmsg->cmsg_level = SOL_SOCKET;
|
||||
cmsg->cmsg_type = SCM_RIGHTS;
|
||||
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
|
||||
data = CMSG_DATA(cmsg);
|
||||
*(int *)data = fd_to_send;
|
||||
cmsg = CMSG_FIRSTHDR(&msg);
|
||||
cmsg->cmsg_level = SOL_SOCKET;
|
||||
cmsg->cmsg_type = SCM_RIGHTS;
|
||||
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
|
||||
data = CMSG_DATA(cmsg);
|
||||
*(int *)data = fd_to_send;
|
||||
|
||||
msg.msg_controllen = cmsg->cmsg_len;
|
||||
msg.msg_controllen = cmsg->cmsg_len;
|
||||
|
||||
res = sendmsg(send_fd, &msg, 0);
|
||||
if (res <= 0) {
|
||||
printf("%s: sendmsg failed", __func__);
|
||||
return -1;
|
||||
}
|
||||
res = sendmsg(send_fd, &msg, 0);
|
||||
if (res <= 0) {
|
||||
printf("%s: sendmsg failed", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Listen on a unix domain socket named <socket_name>. */
|
||||
/* Connect to it and return connect_fd */
|
||||
int UnixSocketCreate(const char *socket_name) {
|
||||
int listen_fd;
|
||||
struct sockaddr_un sock_addr;
|
||||
int connect_fd;
|
||||
struct sockaddr_un connect_addr;
|
||||
socklen_t connect_addr_len = 0;
|
||||
int UnixSocketCreate(const char *socket_name)
|
||||
{
|
||||
int listen_fd;
|
||||
struct sockaddr_un sock_addr;
|
||||
int connect_fd;
|
||||
struct sockaddr_un connect_addr;
|
||||
socklen_t connect_addr_len = 0;
|
||||
|
||||
listen_fd = socket(PF_UNIX, SOCK_STREAM, 0);
|
||||
if (listen_fd < 0) {
|
||||
printf("%s: socket create failed", __func__);
|
||||
return -1;
|
||||
}
|
||||
listen_fd = socket(PF_UNIX, SOCK_STREAM, 0);
|
||||
if (listen_fd < 0) {
|
||||
printf("%s: socket create failed", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (verbose) printf("%s: listen_fd: %d\n", __func__, listen_fd);
|
||||
if (verbose)
|
||||
printf("%s: listen_fd: %d\n", __func__, listen_fd);
|
||||
|
||||
unlink(socket_name);
|
||||
unlink(socket_name);
|
||||
|
||||
memset(&sock_addr, 0, sizeof(struct sockaddr_un));
|
||||
sock_addr.sun_family = AF_UNIX;
|
||||
strncpy(sock_addr.sun_path, socket_name, sizeof(sock_addr.sun_path) - 1);
|
||||
memset(&sock_addr, 0, sizeof(struct sockaddr_un));
|
||||
sock_addr.sun_family = AF_UNIX;
|
||||
strncpy(sock_addr.sun_path, socket_name, sizeof(sock_addr.sun_path) - 1);
|
||||
|
||||
if (bind(listen_fd, (const struct sockaddr *)&sock_addr,
|
||||
sizeof(struct sockaddr_un))) {
|
||||
printf("i%s: bind error", __func__);
|
||||
return -1;
|
||||
}
|
||||
if (bind(listen_fd, (const struct sockaddr *)&sock_addr, sizeof(struct sockaddr_un))) {
|
||||
printf("i%s: bind error", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (listen(listen_fd, 1)) {
|
||||
printf("%s: listen error", __func__);
|
||||
return -1;
|
||||
}
|
||||
if (listen(listen_fd, 1)) {
|
||||
printf("%s: listen error", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
connect_fd =
|
||||
accept(listen_fd, (struct sockaddr *)&connect_addr, &connect_addr_len);
|
||||
connect_fd = accept(listen_fd, (struct sockaddr *)&connect_addr, &connect_addr_len);
|
||||
|
||||
if (verbose) printf("%s: connect_fd: %d\n", __func__, connect_fd);
|
||||
if (verbose)
|
||||
printf("%s: connect_fd: %d\n", __func__, connect_fd);
|
||||
|
||||
close(listen_fd);
|
||||
unlink(socket_name);
|
||||
if (connect_fd < 0) {
|
||||
printf("%s: accept failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
close(listen_fd);
|
||||
unlink(socket_name);
|
||||
if (connect_fd < 0) {
|
||||
printf("%s: accept failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return connect_fd;
|
||||
return connect_fd;
|
||||
}
|
||||
|
||||
/* receive a file descriptor from another process. */
|
||||
@@ -376,48 +376,49 @@ int UnixSocketCreate(const char *socket_name) {
|
||||
/* integer value in the other process, but the file */
|
||||
/* descriptors in each process will refer to the same file */
|
||||
/* object in the kernel. */
|
||||
int EGLStreamReceivefd(int connect_fd) {
|
||||
struct msghdr msg;
|
||||
struct iovec iov[1];
|
||||
char msg_buf[1];
|
||||
char ctrl_buf[CMSG_SPACE(sizeof(int))];
|
||||
struct cmsghdr *cmsg;
|
||||
void *data;
|
||||
int recvfd;
|
||||
int EGLStreamReceivefd(int connect_fd)
|
||||
{
|
||||
struct msghdr msg;
|
||||
struct iovec iov[1];
|
||||
char msg_buf[1];
|
||||
char ctrl_buf[CMSG_SPACE(sizeof(int))];
|
||||
struct cmsghdr *cmsg;
|
||||
void *data;
|
||||
int recvfd;
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
|
||||
iov[0].iov_base = msg_buf;
|
||||
iov[0].iov_len = sizeof(msg_buf);
|
||||
msg.msg_iov = iov;
|
||||
msg.msg_iovlen = 1;
|
||||
iov[0].iov_base = msg_buf;
|
||||
iov[0].iov_len = sizeof(msg_buf);
|
||||
msg.msg_iov = iov;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
msg.msg_control = ctrl_buf;
|
||||
msg.msg_controllen = sizeof(ctrl_buf);
|
||||
msg.msg_control = ctrl_buf;
|
||||
msg.msg_controllen = sizeof(ctrl_buf);
|
||||
|
||||
if (recvmsg(connect_fd, &msg, 0) <= 0) {
|
||||
printf("%s: recvmsg failed", __func__);
|
||||
return -1;
|
||||
}
|
||||
if (recvmsg(connect_fd, &msg, 0) <= 0) {
|
||||
printf("%s: recvmsg failed", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
cmsg = CMSG_FIRSTHDR(&msg);
|
||||
if (!cmsg) {
|
||||
printf("%s: NULL message header\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
if (cmsg->cmsg_level != SOL_SOCKET) {
|
||||
printf("%s: Message level is not SOL_SOCKET\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
if (cmsg->cmsg_type != SCM_RIGHTS) {
|
||||
printf("%s: Message type is not SCM_RIGHTS\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
cmsg = CMSG_FIRSTHDR(&msg);
|
||||
if (!cmsg) {
|
||||
printf("%s: NULL message header\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
if (cmsg->cmsg_level != SOL_SOCKET) {
|
||||
printf("%s: Message level is not SOL_SOCKET\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
if (cmsg->cmsg_type != SCM_RIGHTS) {
|
||||
printf("%s: Message type is not SCM_RIGHTS\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
data = CMSG_DATA(cmsg);
|
||||
recvfd = *(int *)data;
|
||||
data = CMSG_DATA(cmsg);
|
||||
recvfd = *(int *)data;
|
||||
|
||||
return recvfd;
|
||||
return recvfd;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -51,51 +51,49 @@
|
||||
|
||||
extern EGLStreamKHR g_producerEglStream;
|
||||
extern EGLStreamKHR g_consumerEglStream;
|
||||
extern EGLDisplay g_producerEglDisplay;
|
||||
extern EGLDisplay g_consumerEglDisplay;
|
||||
extern int cudaDevIndexCons;
|
||||
extern int cudaDevIndexProd;
|
||||
extern bool verbose;
|
||||
extern EGLDisplay g_producerEglDisplay;
|
||||
extern EGLDisplay g_consumerEglDisplay;
|
||||
extern int cudaDevIndexCons;
|
||||
extern int cudaDevIndexProd;
|
||||
extern bool verbose;
|
||||
|
||||
#define EXTENSION_LIST(T) \
|
||||
T(PFNEGLCREATESTREAMKHRPROC, eglCreateStreamKHR) \
|
||||
T(PFNEGLDESTROYSTREAMKHRPROC, eglDestroyStreamKHR) \
|
||||
T(PFNEGLQUERYSTREAMKHRPROC, eglQueryStreamKHR) \
|
||||
T(PFNEGLQUERYSTREAMU64KHRPROC, eglQueryStreamu64KHR) \
|
||||
T(PFNEGLQUERYSTREAMTIMEKHRPROC, eglQueryStreamTimeKHR) \
|
||||
T(PFNEGLSTREAMATTRIBKHRPROC, eglStreamAttribKHR) \
|
||||
T(PFNEGLSTREAMCONSUMERACQUIREKHRPROC, eglStreamConsumerAcquireKHR) \
|
||||
T(PFNEGLSTREAMCONSUMERRELEASEKHRPROC, eglStreamConsumerReleaseKHR) \
|
||||
T(PFNEGLSTREAMCONSUMERGLTEXTUREEXTERNALKHRPROC, \
|
||||
eglStreamConsumerGLTextureExternalKHR) \
|
||||
T(PFNEGLQUERYDEVICESEXTPROC, eglQueryDevicesEXT) \
|
||||
T(PFNEGLGETPLATFORMDISPLAYEXTPROC, eglGetPlatformDisplayEXT) \
|
||||
T(PFNEGLGETSTREAMFILEDESCRIPTORKHRPROC, eglGetStreamFileDescriptorKHR) \
|
||||
T(PFNEGLQUERYDEVICEATTRIBEXTPROC, eglQueryDeviceAttribEXT) \
|
||||
T(PFNEGLCREATESTREAMFROMFILEDESCRIPTORKHRPROC, \
|
||||
eglCreateStreamFromFileDescriptorKHR)
|
||||
#define EXTENSION_LIST(T) \
|
||||
T(PFNEGLCREATESTREAMKHRPROC, eglCreateStreamKHR) \
|
||||
T(PFNEGLDESTROYSTREAMKHRPROC, eglDestroyStreamKHR) \
|
||||
T(PFNEGLQUERYSTREAMKHRPROC, eglQueryStreamKHR) \
|
||||
T(PFNEGLQUERYSTREAMU64KHRPROC, eglQueryStreamu64KHR) \
|
||||
T(PFNEGLQUERYSTREAMTIMEKHRPROC, eglQueryStreamTimeKHR) \
|
||||
T(PFNEGLSTREAMATTRIBKHRPROC, eglStreamAttribKHR) \
|
||||
T(PFNEGLSTREAMCONSUMERACQUIREKHRPROC, eglStreamConsumerAcquireKHR) \
|
||||
T(PFNEGLSTREAMCONSUMERRELEASEKHRPROC, eglStreamConsumerReleaseKHR) \
|
||||
T(PFNEGLSTREAMCONSUMERGLTEXTUREEXTERNALKHRPROC, eglStreamConsumerGLTextureExternalKHR) \
|
||||
T(PFNEGLQUERYDEVICESEXTPROC, eglQueryDevicesEXT) \
|
||||
T(PFNEGLGETPLATFORMDISPLAYEXTPROC, eglGetPlatformDisplayEXT) \
|
||||
T(PFNEGLGETSTREAMFILEDESCRIPTORKHRPROC, eglGetStreamFileDescriptorKHR) \
|
||||
T(PFNEGLQUERYDEVICEATTRIBEXTPROC, eglQueryDeviceAttribEXT) \
|
||||
T(PFNEGLCREATESTREAMFROMFILEDESCRIPTORKHRPROC, eglCreateStreamFromFileDescriptorKHR)
|
||||
|
||||
#define EXTLST_DECL(tx, x) tx x = NULL;
|
||||
#define EXTLST_DECL(tx, x) tx x = NULL;
|
||||
#define EXTLST_EXTERN(tx, x) extern tx x;
|
||||
#define EXTLST_ENTRY(tx, x) {(extlst_fnptr_t *)&x, #x},
|
||||
#define EXTLST_ENTRY(tx, x) {(extlst_fnptr_t *)&x, #x},
|
||||
|
||||
#define MAX_STRING_SIZE 256
|
||||
#define INIT_DATA 0x01
|
||||
#define PROD_DATA 0x07
|
||||
#define CONS_DATA 0x04
|
||||
#define INIT_DATA 0x01
|
||||
#define PROD_DATA 0x07
|
||||
#define CONS_DATA 0x04
|
||||
|
||||
#define SOCK_PATH "/tmp/tegra_sw_egl_socket"
|
||||
|
||||
typedef struct _TestArgs {
|
||||
unsigned int charCnt;
|
||||
bool isProducer;
|
||||
typedef struct _TestArgs
|
||||
{
|
||||
unsigned int charCnt;
|
||||
bool isProducer;
|
||||
} TestArgs;
|
||||
|
||||
extern int WIDTH, HEIGHT;
|
||||
|
||||
int eglSetupExtensions(bool is_dgpu);
|
||||
int EGLStreamInit(bool isCrossDevice, int isConsumer,
|
||||
EGLNativeFileDescriptorKHR fileDesc);
|
||||
int eglSetupExtensions(bool is_dgpu);
|
||||
int EGLStreamInit(bool isCrossDevice, int isConsumer, EGLNativeFileDescriptorKHR fileDesc);
|
||||
void EGLStreamFini(void);
|
||||
|
||||
int EGLStreamSetAttr(EGLDisplay display, EGLStreamKHR eglStream);
|
||||
@@ -104,10 +102,8 @@ int EGLStreamSendfd(int send_fd, int fd_to_send);
|
||||
int UnixSocketCreate(const char *socket_name);
|
||||
int EGLStreamReceivefd(int connect_fd);
|
||||
|
||||
static clockid_t clock_id = CLOCK_MONOTONIC; // CLOCK_PROCESS_CPUTIME_ID;
|
||||
static double getMicrosecond(struct timespec t) {
|
||||
return ((t.tv_sec) * 1000000.0 + (t.tv_nsec) / 1.0e3);
|
||||
}
|
||||
static clockid_t clock_id = CLOCK_MONOTONIC; // CLOCK_PROCESS_CPUTIME_ID;
|
||||
static double getMicrosecond(struct timespec t) { return ((t.tv_sec) * 1000000.0 + (t.tv_nsec) / 1.0e3); }
|
||||
|
||||
static inline void getTime(struct timespec *t) { clock_gettime(clock_id, t); }
|
||||
#endif
|
||||
|
||||
@@ -31,191 +31,198 @@ EXTENSION_LIST(EXTLST_EXTERN)
|
||||
#endif
|
||||
#include <cuda.h>
|
||||
|
||||
int parseCmdLine(int argc, char *argv[], TestArgs *args);
|
||||
int parseCmdLine(int argc, char *argv[], TestArgs *args);
|
||||
void printUsage(void);
|
||||
int NUMTRIALS = 10;
|
||||
int profileAPIs = 0;
|
||||
int NUMTRIALS = 10;
|
||||
int profileAPIs = 0;
|
||||
|
||||
bool verbose = 0;
|
||||
bool verbose = 0;
|
||||
bool isCrossDevice = 0;
|
||||
|
||||
// Parse the command line options. Returns FAILURE on a parse error, SUCCESS
|
||||
// otherwise.
|
||||
int parseCmdLine(int argc, char *argv[], TestArgs *args) {
|
||||
int i;
|
||||
int parseCmdLine(int argc, char *argv[], TestArgs *args)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "-h") == 0) {
|
||||
printUsage();
|
||||
exit(0);
|
||||
} else if (strcmp(argv[i], "-n") == 0) {
|
||||
++i;
|
||||
if (sscanf(argv[i], "%d", &NUMTRIALS) != 1 || NUMTRIALS <= 0) {
|
||||
printf("Invalid trial count: %s should be > 0\n", argv[i]);
|
||||
return -1;
|
||||
}
|
||||
} else if (strcmp(argv[i], "-profile") == 0) {
|
||||
profileAPIs = 1;
|
||||
} else if (strcmp(argv[i], "-crossdev") == 0) {
|
||||
isCrossDevice = 1;
|
||||
} else if (strcmp(argv[i], "-width") == 0) {
|
||||
++i;
|
||||
if (sscanf(argv[i], "%d", &WIDTH) != 1 || (WIDTH <= 0)) {
|
||||
printf("Width should be greater than 0\n");
|
||||
return -1;
|
||||
}
|
||||
} else if (strcmp(argv[i], "-height") == 0) {
|
||||
++i;
|
||||
if (sscanf(argv[i], "%d", &HEIGHT) != 1 || (HEIGHT <= 0)) {
|
||||
printf("Width should be greater than 0\n");
|
||||
return -1;
|
||||
}
|
||||
} else if (0 == strcmp(&argv[i][1], "proctype")) {
|
||||
++i;
|
||||
if (!strcasecmp(argv[i], "prod")) {
|
||||
args->isProducer = 1;
|
||||
} else if (!strcasecmp(argv[i], "cons")) {
|
||||
args->isProducer = 0;
|
||||
} else {
|
||||
printf("%s: Bad Process Type: %s\n", __func__, argv[i]);
|
||||
return 1;
|
||||
}
|
||||
} else if (strcmp(argv[i], "-v") == 0) {
|
||||
verbose = 1;
|
||||
} else {
|
||||
printf("Unknown option: %s\n", argv[i]);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (isCrossDevice) {
|
||||
int deviceCount = 0;
|
||||
|
||||
CUresult error_id = cuInit(0);
|
||||
if (error_id != CUDA_SUCCESS) {
|
||||
printf("cuInit(0) returned %d\n", error_id);
|
||||
printf("Result = FAIL\n");
|
||||
exit(EXIT_FAILURE);
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "-h") == 0) {
|
||||
printUsage();
|
||||
exit(0);
|
||||
}
|
||||
else if (strcmp(argv[i], "-n") == 0) {
|
||||
++i;
|
||||
if (sscanf(argv[i], "%d", &NUMTRIALS) != 1 || NUMTRIALS <= 0) {
|
||||
printf("Invalid trial count: %s should be > 0\n", argv[i]);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if (strcmp(argv[i], "-profile") == 0) {
|
||||
profileAPIs = 1;
|
||||
}
|
||||
else if (strcmp(argv[i], "-crossdev") == 0) {
|
||||
isCrossDevice = 1;
|
||||
}
|
||||
else if (strcmp(argv[i], "-width") == 0) {
|
||||
++i;
|
||||
if (sscanf(argv[i], "%d", &WIDTH) != 1 || (WIDTH <= 0)) {
|
||||
printf("Width should be greater than 0\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if (strcmp(argv[i], "-height") == 0) {
|
||||
++i;
|
||||
if (sscanf(argv[i], "%d", &HEIGHT) != 1 || (HEIGHT <= 0)) {
|
||||
printf("Width should be greater than 0\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if (0 == strcmp(&argv[i][1], "proctype")) {
|
||||
++i;
|
||||
if (!strcasecmp(argv[i], "prod")) {
|
||||
args->isProducer = 1;
|
||||
}
|
||||
else if (!strcasecmp(argv[i], "cons")) {
|
||||
args->isProducer = 0;
|
||||
}
|
||||
else {
|
||||
printf("%s: Bad Process Type: %s\n", __func__, argv[i]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else if (strcmp(argv[i], "-v") == 0) {
|
||||
verbose = 1;
|
||||
}
|
||||
else {
|
||||
printf("Unknown option: %s\n", argv[i]);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
error_id = cuDeviceGetCount(&deviceCount);
|
||||
if (error_id != CUDA_SUCCESS) {
|
||||
printf("cuDeviceGetCount returned %d\n", (int)error_id);
|
||||
printf("Result = FAIL\n");
|
||||
exit(EXIT_FAILURE);
|
||||
if (isCrossDevice) {
|
||||
int deviceCount = 0;
|
||||
|
||||
CUresult error_id = cuInit(0);
|
||||
if (error_id != CUDA_SUCCESS) {
|
||||
printf("cuInit(0) returned %d\n", error_id);
|
||||
printf("Result = FAIL\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
error_id = cuDeviceGetCount(&deviceCount);
|
||||
if (error_id != CUDA_SUCCESS) {
|
||||
printf("cuDeviceGetCount returned %d\n", (int)error_id);
|
||||
printf("Result = FAIL\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int iGPUexists = 0;
|
||||
CUdevice dev;
|
||||
for (dev = 0; dev < deviceCount; ++dev) {
|
||||
int integrated = 0;
|
||||
CUresult error_result = cuDeviceGetAttribute(&integrated, CU_DEVICE_ATTRIBUTE_INTEGRATED, dev);
|
||||
|
||||
if (error_result != CUDA_SUCCESS) {
|
||||
printf("cuDeviceGetAttribute returned error : %d\n", (int)error_result);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (integrated) {
|
||||
iGPUexists = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!iGPUexists) {
|
||||
printf("No Integrated GPU found in the system.\n");
|
||||
printf("-crossdev option is only supported on systems with an Integrated "
|
||||
"GPU and a Discrete GPU\n");
|
||||
printf("Waiving the execution\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
int iGPUexists = 0;
|
||||
CUdevice dev;
|
||||
for (dev = 0; dev < deviceCount; ++dev) {
|
||||
int integrated = 0;
|
||||
CUresult error_result = cuDeviceGetAttribute(
|
||||
&integrated, CU_DEVICE_ATTRIBUTE_INTEGRATED, dev);
|
||||
|
||||
if (error_result != CUDA_SUCCESS) {
|
||||
printf("cuDeviceGetAttribute returned error : %d\n", (int)error_result);
|
||||
if (!eglSetupExtensions(isCrossDevice)) {
|
||||
printf("SetupExtentions failed \n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (integrated) {
|
||||
iGPUexists = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!iGPUexists) {
|
||||
printf("No Integrated GPU found in the system.\n");
|
||||
printf(
|
||||
"-crossdev option is only supported on systems with an Integrated "
|
||||
"GPU and a Discrete GPU\n");
|
||||
printf("Waiving the execution\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
if (!eglSetupExtensions(isCrossDevice)) {
|
||||
printf("SetupExtentions failed \n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
#define MAX_EGL_DEVICES 4
|
||||
EGLDeviceEXT devices[MAX_EGL_DEVICES];
|
||||
EGLint numDevices = 0;
|
||||
EGLBoolean eglStatus =
|
||||
eglQueryDevicesEXT(MAX_EGL_DEVICES, devices, &numDevices);
|
||||
if (eglStatus != EGL_TRUE) {
|
||||
printf("Error querying EGL devices\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (numDevices == 0) {
|
||||
printf("No EGL devices found\n");
|
||||
eglStatus = EGL_FALSE;
|
||||
exit(2); // EXIT_WAIVED
|
||||
}
|
||||
|
||||
int egl_device_id = 0;
|
||||
for (egl_device_id = 0; egl_device_id < numDevices; egl_device_id++) {
|
||||
EGLAttrib cuda_device;
|
||||
eglStatus = eglQueryDeviceAttribEXT(devices[egl_device_id],
|
||||
EGL_CUDA_DEVICE_NV, &cuda_device);
|
||||
if (eglStatus == EGL_TRUE) {
|
||||
break;
|
||||
EGLDeviceEXT devices[MAX_EGL_DEVICES];
|
||||
EGLint numDevices = 0;
|
||||
EGLBoolean eglStatus = eglQueryDevicesEXT(MAX_EGL_DEVICES, devices, &numDevices);
|
||||
if (eglStatus != EGL_TRUE) {
|
||||
printf("Error querying EGL devices\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (egl_device_id >= numDevices) {
|
||||
printf("No CUDA Capable EGL Device found.. Waiving execution\n");
|
||||
exit(2); // EXIT_WAIVED
|
||||
}
|
||||
|
||||
if (isCrossDevice) {
|
||||
if (numDevices == 1) {
|
||||
printf(
|
||||
"Found only one EGL device, cannot setup cross GPU streams. "
|
||||
"Waiving\n");
|
||||
eglStatus = EGL_FALSE;
|
||||
exit(2); // EXIT_WAIVED
|
||||
if (numDevices == 0) {
|
||||
printf("No EGL devices found\n");
|
||||
eglStatus = EGL_FALSE;
|
||||
exit(2); // EXIT_WAIVED
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
int egl_device_id = 0;
|
||||
for (egl_device_id = 0; egl_device_id < numDevices; egl_device_id++) {
|
||||
EGLAttrib cuda_device;
|
||||
eglStatus = eglQueryDeviceAttribEXT(devices[egl_device_id], EGL_CUDA_DEVICE_NV, &cuda_device);
|
||||
if (eglStatus == EGL_TRUE) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (egl_device_id >= numDevices) {
|
||||
printf("No CUDA Capable EGL Device found.. Waiving execution\n");
|
||||
exit(2); // EXIT_WAIVED
|
||||
}
|
||||
|
||||
if (isCrossDevice) {
|
||||
if (numDevices == 1) {
|
||||
printf("Found only one EGL device, cannot setup cross GPU streams. "
|
||||
"Waiving\n");
|
||||
eglStatus = EGL_FALSE;
|
||||
exit(2); // EXIT_WAIVED
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void launchProducer(TestArgs *args) {
|
||||
/* Cross-process creation of producer */
|
||||
char argsProducer[1024];
|
||||
char str[256];
|
||||
void launchProducer(TestArgs *args)
|
||||
{
|
||||
/* Cross-process creation of producer */
|
||||
char argsProducer[1024];
|
||||
char str[256];
|
||||
|
||||
strcpy(argsProducer, "./EGLStream_CUDA_CrossGPU -proctype prod ");
|
||||
strcpy(argsProducer, "./EGLStream_CUDA_CrossGPU -proctype prod ");
|
||||
|
||||
if (isCrossDevice) {
|
||||
sprintf(str, "-crossdev ");
|
||||
strcat(argsProducer, str);
|
||||
}
|
||||
if (isCrossDevice) {
|
||||
sprintf(str, "-crossdev ");
|
||||
strcat(argsProducer, str);
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
sprintf(str, "-v ");
|
||||
strcat(argsProducer, str);
|
||||
}
|
||||
if (verbose) {
|
||||
sprintf(str, "-v ");
|
||||
strcat(argsProducer, str);
|
||||
}
|
||||
|
||||
/*Make the process run in bg*/
|
||||
strcat(argsProducer, "& ");
|
||||
/*Make the process run in bg*/
|
||||
strcat(argsProducer, "& ");
|
||||
|
||||
printf("\n%s: Crossproc Producer command: %s \n", __func__, argsProducer);
|
||||
printf("\n%s: Crossproc Producer command: %s \n", __func__, argsProducer);
|
||||
|
||||
/*Create crossproc Producer*/
|
||||
system(argsProducer);
|
||||
/*Create crossproc Producer*/
|
||||
system(argsProducer);
|
||||
|
||||
/*Enable crossproc Consumer in the same process */
|
||||
args->isProducer = 0;
|
||||
/*Enable crossproc Consumer in the same process */
|
||||
args->isProducer = 0;
|
||||
}
|
||||
|
||||
void printUsage(void) {
|
||||
printf("Usage:\n");
|
||||
printf(" -h Print this help message\n");
|
||||
printf(" -n n Exit after running n trials. Set to 10 by default\n");
|
||||
printf(
|
||||
" -profile Profile time taken by ReleaseAPI. Not set by default\n");
|
||||
printf(" -crossdev Run with producer on idgpu and consumer on dgpu\n");
|
||||
printf(" -dgpu (same as -crossdev, deprecated)\n");
|
||||
printf(" -v verbose output\n");
|
||||
void printUsage(void)
|
||||
{
|
||||
printf("Usage:\n");
|
||||
printf(" -h Print this help message\n");
|
||||
printf(" -n n Exit after running n trials. Set to 10 by default\n");
|
||||
printf(" -profile Profile time taken by ReleaseAPI. Not set by default\n");
|
||||
printf(" -crossdev Run with producer on idgpu and consumer on dgpu\n");
|
||||
printf(" -dgpu (same as -crossdev, deprecated)\n");
|
||||
printf(" -v verbose output\n");
|
||||
}
|
||||
|
||||
@@ -41,100 +41,110 @@
|
||||
extern bool isCrossDevice;
|
||||
|
||||
__device__ static unsigned int numErrors = 0, errorFound = 0;
|
||||
__device__ void checkProducerDataGPU(char *data, int size, char expectedVal,
|
||||
int frameNumber) {
|
||||
if ((data[blockDim.x * blockIdx.x + threadIdx.x] != expectedVal) &&
|
||||
(!errorFound)) {
|
||||
printf("Producer FOUND:%d expected: %d at %d for trial %d %d\n",
|
||||
data[blockDim.x * blockIdx.x + threadIdx.x], expectedVal,
|
||||
(blockDim.x * blockIdx.x + threadIdx.x), frameNumber, numErrors);
|
||||
numErrors++;
|
||||
errorFound = 1;
|
||||
return;
|
||||
}
|
||||
__device__ void checkProducerDataGPU(char *data, int size, char expectedVal, int frameNumber)
|
||||
{
|
||||
if ((data[blockDim.x * blockIdx.x + threadIdx.x] != expectedVal) && (!errorFound)) {
|
||||
printf("Producer FOUND:%d expected: %d at %d for trial %d %d\n",
|
||||
data[blockDim.x * blockIdx.x + threadIdx.x],
|
||||
expectedVal,
|
||||
(blockDim.x * blockIdx.x + threadIdx.x),
|
||||
frameNumber,
|
||||
numErrors);
|
||||
numErrors++;
|
||||
errorFound = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
__device__ void checkConsumerDataGPU(char *data, int size, char expectedVal,
|
||||
int frameNumber) {
|
||||
if ((data[blockDim.x * blockIdx.x + threadIdx.x] != expectedVal) &&
|
||||
(!errorFound)) {
|
||||
printf("Consumer FOUND:%d expected: %d at %d for trial %d %d\n",
|
||||
data[blockDim.x * blockIdx.x + threadIdx.x], expectedVal,
|
||||
(blockDim.x * blockIdx.x + threadIdx.x), frameNumber, numErrors);
|
||||
numErrors++;
|
||||
errorFound = 1;
|
||||
return;
|
||||
}
|
||||
__device__ void checkConsumerDataGPU(char *data, int size, char expectedVal, int frameNumber)
|
||||
{
|
||||
if ((data[blockDim.x * blockIdx.x + threadIdx.x] != expectedVal) && (!errorFound)) {
|
||||
printf("Consumer FOUND:%d expected: %d at %d for trial %d %d\n",
|
||||
data[blockDim.x * blockIdx.x + threadIdx.x],
|
||||
expectedVal,
|
||||
(blockDim.x * blockIdx.x + threadIdx.x),
|
||||
frameNumber,
|
||||
numErrors);
|
||||
numErrors++;
|
||||
errorFound = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
__global__ void writeDataToBuffer(char *pSrc, char newVal) {
|
||||
pSrc[blockDim.x * blockIdx.x + threadIdx.x] = newVal;
|
||||
__global__ void writeDataToBuffer(char *pSrc, char newVal) { pSrc[blockDim.x * blockIdx.x + threadIdx.x] = newVal; }
|
||||
|
||||
__global__ void testKernelConsumer(char *pSrc, char size, char expectedVal, char newVal, int frameNumber)
|
||||
{
|
||||
checkConsumerDataGPU(pSrc, size, expectedVal, frameNumber);
|
||||
}
|
||||
|
||||
__global__ void testKernelConsumer(char *pSrc, char size, char expectedVal,
|
||||
char newVal, int frameNumber) {
|
||||
checkConsumerDataGPU(pSrc, size, expectedVal, frameNumber);
|
||||
}
|
||||
|
||||
__global__ void testKernelProducer(char *pSrc, char size, char expectedVal,
|
||||
char newVal, int frameNumber) {
|
||||
checkProducerDataGPU(pSrc, size, expectedVal, frameNumber);
|
||||
__global__ void testKernelProducer(char *pSrc, char size, char expectedVal, char newVal, int frameNumber)
|
||||
{
|
||||
checkProducerDataGPU(pSrc, size, expectedVal, frameNumber);
|
||||
}
|
||||
__global__ void getNumErrors(int *numErr) { *numErr = numErrors; }
|
||||
|
||||
cudaError_t cudaProducer_filter(cudaStream_t pStream, char *pSrc, int width,
|
||||
int height, char expectedVal, char newVal,
|
||||
int frameNumber) {
|
||||
// in case where consumer is on dgpu and producer is on igpu when return is
|
||||
// called the frame is not copied back to igpu. So the consumer changes is not
|
||||
// visible to producer
|
||||
if (isCrossDevice == 0) {
|
||||
testKernelProducer<<<(width * height) / 1024, 1024, 1, pStream>>>(
|
||||
cudaError_t cudaProducer_filter(cudaStream_t pStream,
|
||||
char *pSrc,
|
||||
int width,
|
||||
int height,
|
||||
char expectedVal,
|
||||
char newVal,
|
||||
int frameNumber)
|
||||
{
|
||||
// in case where consumer is on dgpu and producer is on igpu when return is
|
||||
// called the frame is not copied back to igpu. So the consumer changes is not
|
||||
// visible to producer
|
||||
if (isCrossDevice == 0) {
|
||||
testKernelProducer<<<(width * height) / 1024, 1024, 1, pStream>>>(
|
||||
pSrc, width * height, expectedVal, newVal, frameNumber);
|
||||
}
|
||||
writeDataToBuffer<<<(width * height) / 1024, 1024, 1, pStream>>>(pSrc, newVal);
|
||||
return cudaSuccess;
|
||||
};
|
||||
|
||||
cudaError_t cudaConsumer_filter(cudaStream_t cStream,
|
||||
char *pSrc,
|
||||
int width,
|
||||
int height,
|
||||
char expectedVal,
|
||||
char newVal,
|
||||
int frameNumber)
|
||||
{
|
||||
testKernelConsumer<<<(width * height) / 1024, 1024, 1, cStream>>>(
|
||||
pSrc, width * height, expectedVal, newVal, frameNumber);
|
||||
}
|
||||
writeDataToBuffer<<<(width * height) / 1024, 1024, 1, pStream>>>(pSrc,
|
||||
newVal);
|
||||
return cudaSuccess;
|
||||
writeDataToBuffer<<<(width * height) / 1024, 1024, 1, cStream>>>(pSrc, newVal);
|
||||
return cudaSuccess;
|
||||
};
|
||||
|
||||
cudaError_t cudaConsumer_filter(cudaStream_t cStream, char *pSrc, int width,
|
||||
int height, char expectedVal, char newVal,
|
||||
int frameNumber) {
|
||||
testKernelConsumer<<<(width * height) / 1024, 1024, 1, cStream>>>(
|
||||
pSrc, width * height, expectedVal, newVal, frameNumber);
|
||||
writeDataToBuffer<<<(width * height) / 1024, 1024, 1, cStream>>>(pSrc,
|
||||
newVal);
|
||||
return cudaSuccess;
|
||||
};
|
||||
|
||||
cudaError_t cudaGetValueMismatch() {
|
||||
int numErr_h;
|
||||
int *numErr_d = NULL;
|
||||
cudaError_t err = cudaSuccess;
|
||||
err = cudaMalloc(&numErr_d, sizeof(int));
|
||||
if (err != cudaSuccess) {
|
||||
printf("Cuda Main: cudaMalloc failed with %s\n", cudaGetErrorString(err));
|
||||
return err;
|
||||
}
|
||||
getNumErrors<<<1, 1>>>(numErr_d);
|
||||
err = cudaDeviceSynchronize();
|
||||
if (err != cudaSuccess) {
|
||||
printf("Cuda Main: cudaDeviceSynchronize failed with %s\n",
|
||||
cudaGetErrorString(err));
|
||||
}
|
||||
err = cudaMemcpy(&numErr_h, numErr_d, sizeof(int), cudaMemcpyDeviceToHost);
|
||||
if (err != cudaSuccess) {
|
||||
printf("Cuda Main: cudaMemcpy failed with %s\n", cudaGetErrorString(err));
|
||||
cudaFree(numErr_d);
|
||||
return err;
|
||||
}
|
||||
err = cudaFree(numErr_d);
|
||||
if (err != cudaSuccess) {
|
||||
printf("Cuda Main: cudaFree failed with %s\n", cudaGetErrorString(err));
|
||||
return err;
|
||||
}
|
||||
if (numErr_h > 0) {
|
||||
return cudaErrorUnknown;
|
||||
}
|
||||
return cudaSuccess;
|
||||
cudaError_t cudaGetValueMismatch()
|
||||
{
|
||||
int numErr_h;
|
||||
int *numErr_d = NULL;
|
||||
cudaError_t err = cudaSuccess;
|
||||
err = cudaMalloc(&numErr_d, sizeof(int));
|
||||
if (err != cudaSuccess) {
|
||||
printf("Cuda Main: cudaMalloc failed with %s\n", cudaGetErrorString(err));
|
||||
return err;
|
||||
}
|
||||
getNumErrors<<<1, 1>>>(numErr_d);
|
||||
err = cudaDeviceSynchronize();
|
||||
if (err != cudaSuccess) {
|
||||
printf("Cuda Main: cudaDeviceSynchronize failed with %s\n", cudaGetErrorString(err));
|
||||
}
|
||||
err = cudaMemcpy(&numErr_h, numErr_d, sizeof(int), cudaMemcpyDeviceToHost);
|
||||
if (err != cudaSuccess) {
|
||||
printf("Cuda Main: cudaMemcpy failed with %s\n", cudaGetErrorString(err));
|
||||
cudaFree(numErr_d);
|
||||
return err;
|
||||
}
|
||||
err = cudaFree(numErr_d);
|
||||
if (err != cudaSuccess) {
|
||||
printf("Cuda Main: cudaFree failed with %s\n", cudaGetErrorString(err));
|
||||
return err;
|
||||
}
|
||||
if (numErr_h > 0) {
|
||||
return cudaErrorUnknown;
|
||||
}
|
||||
return cudaSuccess;
|
||||
}
|
||||
|
||||
@@ -34,359 +34,345 @@
|
||||
EXTENSION_LIST(EXTLST_EXTERN)
|
||||
#endif
|
||||
|
||||
bool signal_stop = 0;
|
||||
bool signal_stop = 0;
|
||||
extern bool verbose;
|
||||
|
||||
static void sig_handler(int sig) {
|
||||
signal_stop = 1;
|
||||
printf("Signal: %d\n", sig);
|
||||
static void sig_handler(int sig)
|
||||
{
|
||||
signal_stop = 1;
|
||||
printf("Signal: %d\n", sig);
|
||||
}
|
||||
|
||||
void DoneCons(int consumerStatus, int send_fd) {
|
||||
EGLStreamFini();
|
||||
// get the final status from producer, combine and print
|
||||
int producerStatus = -1;
|
||||
if (-1 == recv(send_fd, (void *)&producerStatus, sizeof(int), 0)) {
|
||||
printf("%s: Cuda Consumer could not receive status from producer.\n",
|
||||
__func__);
|
||||
}
|
||||
close(send_fd);
|
||||
void DoneCons(int consumerStatus, int send_fd)
|
||||
{
|
||||
EGLStreamFini();
|
||||
// get the final status from producer, combine and print
|
||||
int producerStatus = -1;
|
||||
if (-1 == recv(send_fd, (void *)&producerStatus, sizeof(int), 0)) {
|
||||
printf("%s: Cuda Consumer could not receive status from producer.\n", __func__);
|
||||
}
|
||||
close(send_fd);
|
||||
|
||||
if (producerStatus == 0 && consumerStatus == 0) {
|
||||
printf("&&&& EGLStream_CUDA_CrossGPU PASSED\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
} else {
|
||||
printf("&&&& EGLStream_CUDA_CrossGPU FAILED\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (producerStatus == 0 && consumerStatus == 0) {
|
||||
printf("&&&& EGLStream_CUDA_CrossGPU PASSED\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
else {
|
||||
printf("&&&& EGLStream_CUDA_CrossGPU FAILED\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
void DoneProd(int producerStatus, int connect_fd) {
|
||||
EGLStreamFini();
|
||||
if (-1 == send(connect_fd, (void *)&producerStatus, sizeof(int), 0)) {
|
||||
printf("%s: Cuda Producer could not send status to consumer.\n", __func__);
|
||||
}
|
||||
close(connect_fd);
|
||||
if (producerStatus == 0) {
|
||||
exit(EXIT_SUCCESS);
|
||||
} else {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
void DoneProd(int producerStatus, int connect_fd)
|
||||
{
|
||||
EGLStreamFini();
|
||||
if (-1 == send(connect_fd, (void *)&producerStatus, sizeof(int), 0)) {
|
||||
printf("%s: Cuda Producer could not send status to consumer.\n", __func__);
|
||||
}
|
||||
close(connect_fd);
|
||||
if (producerStatus == 0) {
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
else {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
int WIDTH = 8192, HEIGHT = 8192;
|
||||
int main(int argc, char **argv) {
|
||||
TestArgs args = {0, false};
|
||||
CUresult curesult = CUDA_SUCCESS;
|
||||
unsigned int j = 0;
|
||||
cudaError_t err = cudaSuccess;
|
||||
EGLNativeFileDescriptorKHR fileDescriptor = EGL_NO_FILE_DESCRIPTOR_KHR;
|
||||
struct timespec start, end;
|
||||
CUeglFrame cudaEgl1, cudaEgl2;
|
||||
int consumerStatus = 0;
|
||||
int send_fd = -1;
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
TestArgs args = {0, false};
|
||||
CUresult curesult = CUDA_SUCCESS;
|
||||
unsigned int j = 0;
|
||||
cudaError_t err = cudaSuccess;
|
||||
EGLNativeFileDescriptorKHR fileDescriptor = EGL_NO_FILE_DESCRIPTOR_KHR;
|
||||
struct timespec start, end;
|
||||
CUeglFrame cudaEgl1, cudaEgl2;
|
||||
int consumerStatus = 0;
|
||||
int send_fd = -1;
|
||||
|
||||
if (parseCmdLine(argc, argv, &args) < 0) {
|
||||
printUsage();
|
||||
curesult = CUDA_ERROR_UNKNOWN;
|
||||
DoneCons(consumerStatus, send_fd);
|
||||
}
|
||||
|
||||
printf("Width : %u, height: %u and iterations: %u\n", WIDTH, HEIGHT,
|
||||
NUMTRIALS);
|
||||
|
||||
if (!args.isProducer) // Consumer code
|
||||
{
|
||||
test_cuda_consumer_s cudaConsumer;
|
||||
memset(&cudaConsumer, 0, sizeof(test_cuda_consumer_s));
|
||||
cudaConsumer.profileAPI = profileAPIs;
|
||||
|
||||
// Hook up Ctrl-C handler
|
||||
signal(SIGINT, sig_handler);
|
||||
|
||||
if (!EGLStreamInit(isCrossDevice, !args.isProducer,
|
||||
EGL_NO_FILE_DESCRIPTOR_KHR)) {
|
||||
printf("EGLStream Init failed.\n");
|
||||
curesult = CUDA_ERROR_UNKNOWN;
|
||||
consumerStatus = -1;
|
||||
DoneCons(consumerStatus, send_fd);
|
||||
}
|
||||
|
||||
cudaConsumer.cudaDevId = cudaDevIndexCons;
|
||||
curesult = cudaDeviceCreateConsumer(&cudaConsumer);
|
||||
if (curesult != CUDA_SUCCESS) {
|
||||
consumerStatus = -1;
|
||||
DoneCons(consumerStatus, send_fd);
|
||||
}
|
||||
|
||||
cuCtxPushCurrent(cudaConsumer.context);
|
||||
|
||||
launchProducer(&args);
|
||||
|
||||
args.charCnt = WIDTH * HEIGHT * 4;
|
||||
|
||||
curesult = cuda_consumer_init(&cudaConsumer, &args);
|
||||
if (curesult != CUDA_SUCCESS) {
|
||||
printf("Cuda Consumer: Init failed, status: %d\n", curesult);
|
||||
consumerStatus = -1;
|
||||
DoneCons(consumerStatus, send_fd);
|
||||
}
|
||||
|
||||
cuCtxPopCurrent(&cudaConsumer.context);
|
||||
|
||||
send_fd = UnixSocketConnect(SOCK_PATH);
|
||||
if (-1 == send_fd) {
|
||||
printf("%s: Cuda Consumer cannot create socket %s\n", __func__,
|
||||
SOCK_PATH);
|
||||
consumerStatus = -1;
|
||||
DoneCons(consumerStatus, send_fd);
|
||||
}
|
||||
|
||||
cuCtxPushCurrent(cudaConsumer.context);
|
||||
cudaConsumer.eglStream = g_consumerEglStream;
|
||||
cudaConsumer.eglDisplay = g_consumerEglDisplay;
|
||||
|
||||
// Send the EGL stream FD to producer
|
||||
fileDescriptor = eglGetStreamFileDescriptorKHR(cudaConsumer.eglDisplay,
|
||||
cudaConsumer.eglStream);
|
||||
if (EGL_NO_FILE_DESCRIPTOR_KHR == fileDescriptor) {
|
||||
printf("%s: Cuda Consumer could not get EGL file descriptor.\n",
|
||||
__func__);
|
||||
eglDestroyStreamKHR(cudaConsumer.eglDisplay, cudaConsumer.eglStream);
|
||||
consumerStatus = -1;
|
||||
DoneCons(consumerStatus, send_fd);
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
printf("%s: Cuda Consumer EGL stream FD obtained : %d.\n", __func__,
|
||||
fileDescriptor);
|
||||
|
||||
int res = -1;
|
||||
res = EGLStreamSendfd(send_fd, fileDescriptor);
|
||||
if (-1 == res) {
|
||||
printf("%s: Cuda Consumer could not send EGL file descriptor.\n",
|
||||
__func__);
|
||||
consumerStatus = -1;
|
||||
close(fileDescriptor);
|
||||
}
|
||||
|
||||
if (CUDA_SUCCESS !=
|
||||
(curesult = cuEGLStreamConsumerConnect(&(cudaConsumer.cudaConn),
|
||||
cudaConsumer.eglStream))) {
|
||||
printf("FAILED Connect CUDA consumer with error %d\n", curesult);
|
||||
consumerStatus = -1;
|
||||
DoneCons(consumerStatus, send_fd);
|
||||
}
|
||||
|
||||
j = 0;
|
||||
for (j = 0; j < NUMTRIALS; j++) {
|
||||
curesult = cudaConsumerAcquireFrame(&cudaConsumer, j);
|
||||
if (curesult != CUDA_SUCCESS) {
|
||||
printf("Cuda Consumer Test failed for frame = %d\n", j + 1);
|
||||
consumerStatus = -1;
|
||||
if (parseCmdLine(argc, argv, &args) < 0) {
|
||||
printUsage();
|
||||
curesult = CUDA_ERROR_UNKNOWN;
|
||||
DoneCons(consumerStatus, send_fd);
|
||||
}
|
||||
curesult = cudaConsumerReleaseFrame(&cudaConsumer, j);
|
||||
if (curesult != CUDA_SUCCESS) {
|
||||
printf("Cuda Consumer Test failed for frame = %d\n", j + 1);
|
||||
consumerStatus = -1;
|
||||
DoneCons(consumerStatus, send_fd);
|
||||
}
|
||||
|
||||
curesult = cudaConsumerAcquireFrame(&cudaConsumer, j);
|
||||
if (curesult != CUDA_SUCCESS) {
|
||||
printf("Cuda Consumer Test failed for frame = %d\n", j + 1);
|
||||
consumerStatus = -1;
|
||||
DoneCons(consumerStatus, send_fd);
|
||||
}
|
||||
curesult = cudaConsumerReleaseFrame(&cudaConsumer, j);
|
||||
if (curesult != CUDA_SUCCESS) {
|
||||
printf("Cuda Consumer Test failed for frame = %d\n", j + 1);
|
||||
consumerStatus = -1;
|
||||
DoneCons(consumerStatus, send_fd);
|
||||
}
|
||||
}
|
||||
cuCtxSynchronize();
|
||||
close(fileDescriptor);
|
||||
err = cudaGetValueMismatch();
|
||||
if (err != cudaSuccess) {
|
||||
printf("Consumer: App failed with value mismatch\n");
|
||||
curesult = CUDA_ERROR_UNKNOWN;
|
||||
consumerStatus = -1;
|
||||
DoneCons(consumerStatus, send_fd);
|
||||
}
|
||||
|
||||
EGLint streamState = 0;
|
||||
if (!eglQueryStreamKHR(cudaConsumer.eglDisplay, cudaConsumer.eglStream,
|
||||
EGL_STREAM_STATE_KHR, &streamState)) {
|
||||
printf("Main, eglQueryStreamKHR EGL_STREAM_STATE_KHR failed\n");
|
||||
curesult = CUDA_ERROR_UNKNOWN;
|
||||
consumerStatus = -1;
|
||||
DoneCons(consumerStatus, send_fd);
|
||||
printf("Width : %u, height: %u and iterations: %u\n", WIDTH, HEIGHT, NUMTRIALS);
|
||||
|
||||
if (!args.isProducer) // Consumer code
|
||||
{
|
||||
test_cuda_consumer_s cudaConsumer;
|
||||
memset(&cudaConsumer, 0, sizeof(test_cuda_consumer_s));
|
||||
cudaConsumer.profileAPI = profileAPIs;
|
||||
|
||||
// Hook up Ctrl-C handler
|
||||
signal(SIGINT, sig_handler);
|
||||
|
||||
if (!EGLStreamInit(isCrossDevice, !args.isProducer, EGL_NO_FILE_DESCRIPTOR_KHR)) {
|
||||
printf("EGLStream Init failed.\n");
|
||||
curesult = CUDA_ERROR_UNKNOWN;
|
||||
consumerStatus = -1;
|
||||
DoneCons(consumerStatus, send_fd);
|
||||
}
|
||||
|
||||
cudaConsumer.cudaDevId = cudaDevIndexCons;
|
||||
curesult = cudaDeviceCreateConsumer(&cudaConsumer);
|
||||
if (curesult != CUDA_SUCCESS) {
|
||||
consumerStatus = -1;
|
||||
DoneCons(consumerStatus, send_fd);
|
||||
}
|
||||
|
||||
cuCtxPushCurrent(cudaConsumer.context);
|
||||
|
||||
launchProducer(&args);
|
||||
|
||||
args.charCnt = WIDTH * HEIGHT * 4;
|
||||
|
||||
curesult = cuda_consumer_init(&cudaConsumer, &args);
|
||||
if (curesult != CUDA_SUCCESS) {
|
||||
printf("Cuda Consumer: Init failed, status: %d\n", curesult);
|
||||
consumerStatus = -1;
|
||||
DoneCons(consumerStatus, send_fd);
|
||||
}
|
||||
|
||||
cuCtxPopCurrent(&cudaConsumer.context);
|
||||
|
||||
send_fd = UnixSocketConnect(SOCK_PATH);
|
||||
if (-1 == send_fd) {
|
||||
printf("%s: Cuda Consumer cannot create socket %s\n", __func__, SOCK_PATH);
|
||||
consumerStatus = -1;
|
||||
DoneCons(consumerStatus, send_fd);
|
||||
}
|
||||
|
||||
cuCtxPushCurrent(cudaConsumer.context);
|
||||
cudaConsumer.eglStream = g_consumerEglStream;
|
||||
cudaConsumer.eglDisplay = g_consumerEglDisplay;
|
||||
|
||||
// Send the EGL stream FD to producer
|
||||
fileDescriptor = eglGetStreamFileDescriptorKHR(cudaConsumer.eglDisplay, cudaConsumer.eglStream);
|
||||
if (EGL_NO_FILE_DESCRIPTOR_KHR == fileDescriptor) {
|
||||
printf("%s: Cuda Consumer could not get EGL file descriptor.\n", __func__);
|
||||
eglDestroyStreamKHR(cudaConsumer.eglDisplay, cudaConsumer.eglStream);
|
||||
consumerStatus = -1;
|
||||
DoneCons(consumerStatus, send_fd);
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
printf("%s: Cuda Consumer EGL stream FD obtained : %d.\n", __func__, fileDescriptor);
|
||||
|
||||
int res = -1;
|
||||
res = EGLStreamSendfd(send_fd, fileDescriptor);
|
||||
if (-1 == res) {
|
||||
printf("%s: Cuda Consumer could not send EGL file descriptor.\n", __func__);
|
||||
consumerStatus = -1;
|
||||
close(fileDescriptor);
|
||||
}
|
||||
|
||||
if (CUDA_SUCCESS != (curesult = cuEGLStreamConsumerConnect(&(cudaConsumer.cudaConn), cudaConsumer.eglStream))) {
|
||||
printf("FAILED Connect CUDA consumer with error %d\n", curesult);
|
||||
consumerStatus = -1;
|
||||
DoneCons(consumerStatus, send_fd);
|
||||
}
|
||||
|
||||
j = 0;
|
||||
for (j = 0; j < NUMTRIALS; j++) {
|
||||
curesult = cudaConsumerAcquireFrame(&cudaConsumer, j);
|
||||
if (curesult != CUDA_SUCCESS) {
|
||||
printf("Cuda Consumer Test failed for frame = %d\n", j + 1);
|
||||
consumerStatus = -1;
|
||||
DoneCons(consumerStatus, send_fd);
|
||||
}
|
||||
curesult = cudaConsumerReleaseFrame(&cudaConsumer, j);
|
||||
if (curesult != CUDA_SUCCESS) {
|
||||
printf("Cuda Consumer Test failed for frame = %d\n", j + 1);
|
||||
consumerStatus = -1;
|
||||
DoneCons(consumerStatus, send_fd);
|
||||
}
|
||||
|
||||
curesult = cudaConsumerAcquireFrame(&cudaConsumer, j);
|
||||
if (curesult != CUDA_SUCCESS) {
|
||||
printf("Cuda Consumer Test failed for frame = %d\n", j + 1);
|
||||
consumerStatus = -1;
|
||||
DoneCons(consumerStatus, send_fd);
|
||||
}
|
||||
curesult = cudaConsumerReleaseFrame(&cudaConsumer, j);
|
||||
if (curesult != CUDA_SUCCESS) {
|
||||
printf("Cuda Consumer Test failed for frame = %d\n", j + 1);
|
||||
consumerStatus = -1;
|
||||
DoneCons(consumerStatus, send_fd);
|
||||
}
|
||||
}
|
||||
cuCtxSynchronize();
|
||||
close(fileDescriptor);
|
||||
err = cudaGetValueMismatch();
|
||||
if (err != cudaSuccess) {
|
||||
printf("Consumer: App failed with value mismatch\n");
|
||||
curesult = CUDA_ERROR_UNKNOWN;
|
||||
consumerStatus = -1;
|
||||
DoneCons(consumerStatus, send_fd);
|
||||
}
|
||||
|
||||
EGLint streamState = 0;
|
||||
if (!eglQueryStreamKHR(cudaConsumer.eglDisplay, cudaConsumer.eglStream, EGL_STREAM_STATE_KHR, &streamState)) {
|
||||
printf("Main, eglQueryStreamKHR EGL_STREAM_STATE_KHR failed\n");
|
||||
curesult = CUDA_ERROR_UNKNOWN;
|
||||
consumerStatus = -1;
|
||||
DoneCons(consumerStatus, send_fd);
|
||||
}
|
||||
|
||||
if (streamState != EGL_STREAM_STATE_DISCONNECTED_KHR) {
|
||||
if (CUDA_SUCCESS != (curesult = cuda_consumer_Deinit(&cudaConsumer))) {
|
||||
printf("Consumer Disconnect FAILED.\n");
|
||||
consumerStatus = -1;
|
||||
DoneCons(consumerStatus, send_fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
else // Producer
|
||||
{
|
||||
test_cuda_producer_s cudaProducer;
|
||||
memset(&cudaProducer, 0, sizeof(test_cuda_producer_s));
|
||||
cudaProducer.profileAPI = profileAPIs;
|
||||
int producerStatus = 0;
|
||||
|
||||
setenv("CUDA_EGL_PRODUCER_RETURN_WAIT_TIMEOUT", "1600", 0);
|
||||
|
||||
int connect_fd = -1;
|
||||
// Hook up Ctrl-C handler
|
||||
signal(SIGINT, sig_handler);
|
||||
|
||||
// Create connection to Consumer
|
||||
connect_fd = UnixSocketCreate(SOCK_PATH);
|
||||
if (-1 == connect_fd) {
|
||||
printf("%s: Cuda Producer could not create socket: %s.\n", __func__, SOCK_PATH);
|
||||
producerStatus = -1;
|
||||
DoneProd(producerStatus, connect_fd);
|
||||
}
|
||||
|
||||
// Get the file descriptor of the stream from the consumer process
|
||||
// and re-create the EGL stream from it
|
||||
fileDescriptor = EGLStreamReceivefd(connect_fd);
|
||||
if (-1 == fileDescriptor) {
|
||||
printf("%s: Cuda Producer could not receive EGL file descriptor \n", __func__);
|
||||
producerStatus = -1;
|
||||
DoneProd(producerStatus, connect_fd);
|
||||
}
|
||||
|
||||
if (!EGLStreamInit(isCrossDevice, 0, fileDescriptor)) {
|
||||
printf("EGLStream Init failed.\n");
|
||||
producerStatus = -1;
|
||||
curesult = CUDA_ERROR_UNKNOWN;
|
||||
DoneProd(producerStatus, connect_fd);
|
||||
}
|
||||
|
||||
cudaProducer.eglDisplay = g_producerEglDisplay;
|
||||
cudaProducer.eglStream = g_producerEglStream;
|
||||
cudaProducer.cudaDevId = cudaDevIndexProd;
|
||||
|
||||
curesult = cudaDeviceCreateProducer(&cudaProducer);
|
||||
if (curesult != CUDA_SUCCESS) {
|
||||
producerStatus = -1;
|
||||
DoneProd(producerStatus, connect_fd);
|
||||
}
|
||||
|
||||
args.charCnt = WIDTH * HEIGHT * 4;
|
||||
cuCtxPushCurrent(cudaProducer.context);
|
||||
curesult = cudaProducerInit(&cudaProducer, &args);
|
||||
if (curesult != CUDA_SUCCESS) {
|
||||
printf("Cuda Producer: Init failed, status: %d\n", curesult);
|
||||
producerStatus = -1;
|
||||
DoneProd(producerStatus, connect_fd);
|
||||
}
|
||||
|
||||
// wait for consumer to connect first
|
||||
int err = 0;
|
||||
int wait_loop = 0;
|
||||
EGLint streamState = 0;
|
||||
do {
|
||||
err =
|
||||
eglQueryStreamKHR(cudaProducer.eglDisplay, cudaProducer.eglStream, EGL_STREAM_STATE_KHR, &streamState);
|
||||
if ((0 != err) && (EGL_STREAM_STATE_CONNECTING_KHR != streamState)) {
|
||||
sleep(1);
|
||||
wait_loop++;
|
||||
}
|
||||
} while ((wait_loop < 10) && (0 != err) && (streamState != EGL_STREAM_STATE_CONNECTING_KHR));
|
||||
|
||||
if ((0 == err) || (wait_loop >= 10)) {
|
||||
printf("%s: Cuda Producer eglQueryStreamKHR EGL_STREAM_STATE_KHR failed.\n", __func__);
|
||||
producerStatus = -1;
|
||||
DoneProd(producerStatus, connect_fd);
|
||||
}
|
||||
|
||||
if (CUDA_SUCCESS
|
||||
!= (curesult =
|
||||
cuEGLStreamProducerConnect(&(cudaProducer.cudaConn), cudaProducer.eglStream, WIDTH, HEIGHT))) {
|
||||
printf("Connect CUDA producer FAILED with error %d\n", curesult);
|
||||
producerStatus = -1;
|
||||
DoneProd(producerStatus, connect_fd);
|
||||
}
|
||||
|
||||
printf("main - Cuda Producer and Consumer Initialized.\n");
|
||||
|
||||
cudaProducerPrepareFrame(&cudaEgl1, cudaProducer.cudaPtr, args.charCnt);
|
||||
cudaProducerPrepareFrame(&cudaEgl2, cudaProducer.cudaPtr1, args.charCnt);
|
||||
|
||||
j = 0;
|
||||
for (j = 0; j < NUMTRIALS; j++) {
|
||||
curesult = cudaProducerPresentFrame(&cudaProducer, cudaEgl1, j);
|
||||
if (curesult != CUDA_SUCCESS) {
|
||||
printf("Cuda Producer Test failed for frame = %d with cuda error:%d\n", j + 1, curesult);
|
||||
producerStatus = -1;
|
||||
DoneProd(producerStatus, connect_fd);
|
||||
}
|
||||
|
||||
curesult = cudaProducerPresentFrame(&cudaProducer, cudaEgl2, j);
|
||||
if (curesult != CUDA_SUCCESS) {
|
||||
printf("Cuda Producer Test failed for frame = %d with cuda error:%d\n", j + 1, curesult);
|
||||
producerStatus = -1;
|
||||
DoneProd(producerStatus, connect_fd);
|
||||
}
|
||||
|
||||
curesult = cudaProducerReturnFrame(&cudaProducer, cudaEgl1, j);
|
||||
if (curesult != CUDA_SUCCESS) {
|
||||
printf("Cuda Producer Test failed for frame = %d with cuda error:%d\n", j + 1, curesult);
|
||||
producerStatus = -1;
|
||||
DoneProd(producerStatus, connect_fd);
|
||||
}
|
||||
|
||||
curesult = cudaProducerReturnFrame(&cudaProducer, cudaEgl2, j);
|
||||
if (curesult != CUDA_SUCCESS) {
|
||||
printf("Cuda Producer Test failed for frame = %d with cuda error:%d\n", j + 1, curesult);
|
||||
producerStatus = -1;
|
||||
DoneProd(producerStatus, connect_fd);
|
||||
}
|
||||
}
|
||||
|
||||
cuCtxSynchronize();
|
||||
err = cudaGetValueMismatch();
|
||||
if (err != cudaSuccess) {
|
||||
printf("Prod: App failed with value mismatch\n");
|
||||
curesult = CUDA_ERROR_UNKNOWN;
|
||||
producerStatus = -1;
|
||||
DoneProd(producerStatus, connect_fd);
|
||||
}
|
||||
|
||||
printf("Tear Down Start.....\n");
|
||||
if (!eglQueryStreamKHR(cudaProducer.eglDisplay, cudaProducer.eglStream, EGL_STREAM_STATE_KHR, &streamState)) {
|
||||
printf("Main, eglQueryStreamKHR EGL_STREAM_STATE_KHR failed\n");
|
||||
curesult = CUDA_ERROR_UNKNOWN;
|
||||
producerStatus = -1;
|
||||
DoneProd(producerStatus, connect_fd);
|
||||
}
|
||||
|
||||
if (streamState != EGL_STREAM_STATE_DISCONNECTED_KHR) {
|
||||
if (CUDA_SUCCESS != (curesult = cudaProducerDeinit(&cudaProducer))) {
|
||||
printf("Producer Disconnect FAILED with %d\n", curesult);
|
||||
producerStatus = -1;
|
||||
DoneProd(producerStatus, connect_fd);
|
||||
}
|
||||
}
|
||||
unsetenv("CUDA_EGL_PRODUCER_RETURN_WAIT_TIMEOUT");
|
||||
}
|
||||
|
||||
if (streamState != EGL_STREAM_STATE_DISCONNECTED_KHR) {
|
||||
if (CUDA_SUCCESS != (curesult = cuda_consumer_Deinit(&cudaConsumer))) {
|
||||
printf("Consumer Disconnect FAILED.\n");
|
||||
consumerStatus = -1;
|
||||
DoneCons(consumerStatus, send_fd);
|
||||
}
|
||||
}
|
||||
} else // Producer
|
||||
{
|
||||
test_cuda_producer_s cudaProducer;
|
||||
memset(&cudaProducer, 0, sizeof(test_cuda_producer_s));
|
||||
cudaProducer.profileAPI = profileAPIs;
|
||||
int producerStatus = 0;
|
||||
|
||||
setenv("CUDA_EGL_PRODUCER_RETURN_WAIT_TIMEOUT", "1600", 0);
|
||||
|
||||
int connect_fd = -1;
|
||||
// Hook up Ctrl-C handler
|
||||
signal(SIGINT, sig_handler);
|
||||
|
||||
// Create connection to Consumer
|
||||
connect_fd = UnixSocketCreate(SOCK_PATH);
|
||||
if (-1 == connect_fd) {
|
||||
printf("%s: Cuda Producer could not create socket: %s.\n", __func__,
|
||||
SOCK_PATH);
|
||||
producerStatus = -1;
|
||||
DoneProd(producerStatus, connect_fd);
|
||||
}
|
||||
|
||||
// Get the file descriptor of the stream from the consumer process
|
||||
// and re-create the EGL stream from it
|
||||
fileDescriptor = EGLStreamReceivefd(connect_fd);
|
||||
if (-1 == fileDescriptor) {
|
||||
printf("%s: Cuda Producer could not receive EGL file descriptor \n",
|
||||
__func__);
|
||||
producerStatus = -1;
|
||||
DoneProd(producerStatus, connect_fd);
|
||||
}
|
||||
|
||||
if (!EGLStreamInit(isCrossDevice, 0, fileDescriptor)) {
|
||||
printf("EGLStream Init failed.\n");
|
||||
producerStatus = -1;
|
||||
curesult = CUDA_ERROR_UNKNOWN;
|
||||
DoneProd(producerStatus, connect_fd);
|
||||
}
|
||||
|
||||
cudaProducer.eglDisplay = g_producerEglDisplay;
|
||||
cudaProducer.eglStream = g_producerEglStream;
|
||||
cudaProducer.cudaDevId = cudaDevIndexProd;
|
||||
|
||||
curesult = cudaDeviceCreateProducer(&cudaProducer);
|
||||
if (curesult != CUDA_SUCCESS) {
|
||||
producerStatus = -1;
|
||||
DoneProd(producerStatus, connect_fd);
|
||||
}
|
||||
|
||||
args.charCnt = WIDTH * HEIGHT * 4;
|
||||
cuCtxPushCurrent(cudaProducer.context);
|
||||
curesult = cudaProducerInit(&cudaProducer, &args);
|
||||
if (curesult != CUDA_SUCCESS) {
|
||||
printf("Cuda Producer: Init failed, status: %d\n", curesult);
|
||||
producerStatus = -1;
|
||||
DoneProd(producerStatus, connect_fd);
|
||||
}
|
||||
|
||||
// wait for consumer to connect first
|
||||
int err = 0;
|
||||
int wait_loop = 0;
|
||||
EGLint streamState = 0;
|
||||
do {
|
||||
err = eglQueryStreamKHR(cudaProducer.eglDisplay, cudaProducer.eglStream,
|
||||
EGL_STREAM_STATE_KHR, &streamState);
|
||||
if ((0 != err) && (EGL_STREAM_STATE_CONNECTING_KHR != streamState)) {
|
||||
sleep(1);
|
||||
wait_loop++;
|
||||
}
|
||||
} while ((wait_loop < 10) && (0 != err) &&
|
||||
(streamState != EGL_STREAM_STATE_CONNECTING_KHR));
|
||||
|
||||
if ((0 == err) || (wait_loop >= 10)) {
|
||||
printf(
|
||||
"%s: Cuda Producer eglQueryStreamKHR EGL_STREAM_STATE_KHR failed.\n",
|
||||
__func__);
|
||||
producerStatus = -1;
|
||||
DoneProd(producerStatus, connect_fd);
|
||||
}
|
||||
|
||||
if (CUDA_SUCCESS != (curesult = cuEGLStreamProducerConnect(
|
||||
&(cudaProducer.cudaConn), cudaProducer.eglStream,
|
||||
WIDTH, HEIGHT))) {
|
||||
printf("Connect CUDA producer FAILED with error %d\n", curesult);
|
||||
producerStatus = -1;
|
||||
DoneProd(producerStatus, connect_fd);
|
||||
}
|
||||
|
||||
printf("main - Cuda Producer and Consumer Initialized.\n");
|
||||
|
||||
cudaProducerPrepareFrame(&cudaEgl1, cudaProducer.cudaPtr, args.charCnt);
|
||||
cudaProducerPrepareFrame(&cudaEgl2, cudaProducer.cudaPtr1, args.charCnt);
|
||||
|
||||
j = 0;
|
||||
for (j = 0; j < NUMTRIALS; j++) {
|
||||
curesult = cudaProducerPresentFrame(&cudaProducer, cudaEgl1, j);
|
||||
if (curesult != CUDA_SUCCESS) {
|
||||
printf("Cuda Producer Test failed for frame = %d with cuda error:%d\n",
|
||||
j + 1, curesult);
|
||||
producerStatus = -1;
|
||||
DoneProd(producerStatus, connect_fd);
|
||||
}
|
||||
|
||||
curesult = cudaProducerPresentFrame(&cudaProducer, cudaEgl2, j);
|
||||
if (curesult != CUDA_SUCCESS) {
|
||||
printf("Cuda Producer Test failed for frame = %d with cuda error:%d\n",
|
||||
j + 1, curesult);
|
||||
producerStatus = -1;
|
||||
DoneProd(producerStatus, connect_fd);
|
||||
}
|
||||
|
||||
curesult = cudaProducerReturnFrame(&cudaProducer, cudaEgl1, j);
|
||||
if (curesult != CUDA_SUCCESS) {
|
||||
printf("Cuda Producer Test failed for frame = %d with cuda error:%d\n",
|
||||
j + 1, curesult);
|
||||
producerStatus = -1;
|
||||
DoneProd(producerStatus, connect_fd);
|
||||
}
|
||||
|
||||
curesult = cudaProducerReturnFrame(&cudaProducer, cudaEgl2, j);
|
||||
if (curesult != CUDA_SUCCESS) {
|
||||
printf("Cuda Producer Test failed for frame = %d with cuda error:%d\n",
|
||||
j + 1, curesult);
|
||||
producerStatus = -1;
|
||||
DoneProd(producerStatus, connect_fd);
|
||||
}
|
||||
}
|
||||
|
||||
cuCtxSynchronize();
|
||||
err = cudaGetValueMismatch();
|
||||
if (err != cudaSuccess) {
|
||||
printf("Prod: App failed with value mismatch\n");
|
||||
curesult = CUDA_ERROR_UNKNOWN;
|
||||
producerStatus = -1;
|
||||
DoneProd(producerStatus, connect_fd);
|
||||
}
|
||||
|
||||
printf("Tear Down Start.....\n");
|
||||
if (!eglQueryStreamKHR(cudaProducer.eglDisplay, cudaProducer.eglStream,
|
||||
EGL_STREAM_STATE_KHR, &streamState)) {
|
||||
printf("Main, eglQueryStreamKHR EGL_STREAM_STATE_KHR failed\n");
|
||||
curesult = CUDA_ERROR_UNKNOWN;
|
||||
producerStatus = -1;
|
||||
DoneProd(producerStatus, connect_fd);
|
||||
}
|
||||
|
||||
if (streamState != EGL_STREAM_STATE_DISCONNECTED_KHR) {
|
||||
if (CUDA_SUCCESS != (curesult = cudaProducerDeinit(&cudaProducer))) {
|
||||
printf("Producer Disconnect FAILED with %d\n", curesult);
|
||||
producerStatus = -1;
|
||||
DoneProd(producerStatus, connect_fd);
|
||||
}
|
||||
}
|
||||
unsetenv("CUDA_EGL_PRODUCER_RETURN_WAIT_TIMEOUT");
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -30,7 +30,9 @@
|
||||
//
|
||||
|
||||
#include "cuda_consumer.h"
|
||||
|
||||
#include <helper_cuda_drvapi.h>
|
||||
|
||||
#include "eglstrm_common.h"
|
||||
|
||||
#if defined(EXTENSION_LIST)
|
||||
@@ -39,280 +41,288 @@ EXTENSION_LIST(EXTLST_EXTERN)
|
||||
|
||||
int checkbuf(FILE *fp1, FILE *fp2);
|
||||
|
||||
CUresult cudaConsumerTest(test_cuda_consumer_s *data, const char *fileName) {
|
||||
CUresult cuStatus = CUDA_SUCCESS;
|
||||
CUarray cudaArr = NULL;
|
||||
CUeglFrame cudaEgl;
|
||||
CUgraphicsResource cudaResource;
|
||||
unsigned int i;
|
||||
int check_result;
|
||||
FILE *pInFile1 = NULL, *pInFile2 = NULL, *file_p = NULL;
|
||||
EGLint streamState = 0;
|
||||
CUresult cudaConsumerTest(test_cuda_consumer_s *data, const char *fileName)
|
||||
{
|
||||
CUresult cuStatus = CUDA_SUCCESS;
|
||||
CUarray cudaArr = NULL;
|
||||
CUeglFrame cudaEgl;
|
||||
CUgraphicsResource cudaResource;
|
||||
unsigned int i;
|
||||
int check_result;
|
||||
FILE *pInFile1 = NULL, *pInFile2 = NULL, *file_p = NULL;
|
||||
EGLint streamState = 0;
|
||||
|
||||
if (!data) {
|
||||
printf("%s: Bad parameter\n", __func__);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!eglQueryStreamKHR(g_display, eglStream, EGL_STREAM_STATE_KHR,
|
||||
&streamState)) {
|
||||
printf("Cuda consumer, eglQueryStreamKHR EGL_STREAM_STATE_KHR failed\n");
|
||||
}
|
||||
if (streamState == EGL_STREAM_STATE_DISCONNECTED_KHR) {
|
||||
printf("CUDA Consumer: - EGL_STREAM_STATE_DISCONNECTED_KHR received\n");
|
||||
}
|
||||
|
||||
if (streamState == EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR) {
|
||||
cuStatus = cuEGLStreamConsumerAcquireFrame(&(data->cudaConn), &cudaResource,
|
||||
NULL, 16000);
|
||||
|
||||
if (cuStatus == CUDA_SUCCESS) {
|
||||
CUdeviceptr pDevPtr = 0;
|
||||
int bufferSize;
|
||||
unsigned char *pCudaCopyMem = NULL;
|
||||
unsigned int copyWidthInBytes = 0, copyHeight = 0;
|
||||
|
||||
file_p = fopen(fileName, "wb+");
|
||||
if (!file_p) {
|
||||
printf("WriteFrame: file open failed %s\n", fileName);
|
||||
cuStatus = CUDA_ERROR_UNKNOWN;
|
||||
if (!data) {
|
||||
printf("%s: Bad parameter\n", __func__);
|
||||
goto done;
|
||||
}
|
||||
cuStatus =
|
||||
cuGraphicsResourceGetMappedEglFrame(&cudaEgl, cudaResource, 0, 0);
|
||||
if (cuStatus != CUDA_SUCCESS) {
|
||||
printf("Cuda get resource failed with %d\n", cuStatus);
|
||||
goto done;
|
||||
}
|
||||
cuStatus = cuCtxSynchronize();
|
||||
if (cuStatus != CUDA_SUCCESS) {
|
||||
printf("cuCtxSynchronize failed \n");
|
||||
goto done;
|
||||
}
|
||||
if (!(cudaEgl.planeCount >= 1 && cudaEgl.planeCount <= 3)) {
|
||||
printf("Plane count is invalid\nExiting\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
for (i = 0; i < cudaEgl.planeCount; i++) {
|
||||
if (cudaEgl.frameType == CU_EGL_FRAME_TYPE_PITCH) {
|
||||
pDevPtr = (CUdeviceptr)cudaEgl.frame.pPitch[i];
|
||||
if (cudaEgl.planeCount == 1) {
|
||||
bufferSize = cudaEgl.pitch * cudaEgl.height;
|
||||
copyWidthInBytes = cudaEgl.pitch;
|
||||
copyHeight = data->height;
|
||||
} else if (i == 1 && cudaEgl.planeCount == 2) { // YUV 420
|
||||
// semi-planar
|
||||
bufferSize = cudaEgl.pitch * cudaEgl.height / 2;
|
||||
copyWidthInBytes = cudaEgl.pitch;
|
||||
copyHeight = data->height / 2;
|
||||
} else {
|
||||
bufferSize = data->width * data->height;
|
||||
copyWidthInBytes = data->width;
|
||||
copyHeight = data->height;
|
||||
if (i > 0) {
|
||||
bufferSize >>= 2;
|
||||
copyWidthInBytes >>= 1;
|
||||
copyHeight >>= 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cudaArr = cudaEgl.frame.pArray[i];
|
||||
if (cudaEgl.planeCount == 1) {
|
||||
bufferSize = data->width * data->height * 4;
|
||||
copyWidthInBytes = data->width * 4;
|
||||
copyHeight = data->height;
|
||||
} else if (i == 1 && cudaEgl.planeCount == 2) { // YUV 420
|
||||
// semi-planar
|
||||
bufferSize = data->width * data->height / 2;
|
||||
copyWidthInBytes = data->width;
|
||||
copyHeight = data->height / 2;
|
||||
} else {
|
||||
bufferSize = data->width * data->height;
|
||||
copyWidthInBytes = data->width;
|
||||
copyHeight = data->height;
|
||||
if (i > 0) {
|
||||
bufferSize >>= 2;
|
||||
copyWidthInBytes >>= 1;
|
||||
copyHeight >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (i == 0) {
|
||||
pCudaCopyMem = (unsigned char *)malloc(bufferSize);
|
||||
if (pCudaCopyMem == NULL) {
|
||||
printf("pCudaCopyMem malloc failed\n");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
memset(pCudaCopyMem, 0, bufferSize);
|
||||
if (data->pitchLinearOutput) {
|
||||
cuStatus = cuMemcpyDtoH(pCudaCopyMem, pDevPtr, bufferSize);
|
||||
if (cuStatus != CUDA_SUCCESS) {
|
||||
printf(
|
||||
"cuda_consumer: pitch linear Memcpy failed, bufferSize =%d\n",
|
||||
bufferSize);
|
||||
goto done;
|
||||
}
|
||||
cuStatus = cuCtxSynchronize();
|
||||
if (cuStatus != CUDA_SUCCESS) {
|
||||
printf("cuda_consumer: cuCtxSynchronize failed after memcpy \n");
|
||||
goto done;
|
||||
}
|
||||
} else {
|
||||
CUDA_MEMCPY3D cpdesc;
|
||||
memset(&cpdesc, 0, sizeof(cpdesc));
|
||||
cpdesc.srcXInBytes = cpdesc.srcY = cpdesc.srcZ = cpdesc.srcLOD = 0;
|
||||
cpdesc.srcMemoryType = CU_MEMORYTYPE_ARRAY;
|
||||
cpdesc.srcArray = cudaArr;
|
||||
cpdesc.dstXInBytes = cpdesc.dstY = cpdesc.dstZ = cpdesc.dstLOD = 0;
|
||||
cpdesc.dstMemoryType = CU_MEMORYTYPE_HOST;
|
||||
cpdesc.dstHost = (void *)pCudaCopyMem;
|
||||
cpdesc.WidthInBytes = copyWidthInBytes; // data->width * 4;
|
||||
cpdesc.Height = copyHeight; // data->height;
|
||||
cpdesc.Depth = 1;
|
||||
|
||||
cuStatus = cuMemcpy3D(&cpdesc);
|
||||
if (cuStatus != CUDA_SUCCESS) {
|
||||
printf(
|
||||
"Cuda consumer: cuMemCpy3D failed, copyWidthInBytes=%d, "
|
||||
"copyHight=%d\n",
|
||||
copyWidthInBytes, copyHeight);
|
||||
}
|
||||
cuStatus = cuCtxSynchronize();
|
||||
if (cuStatus != CUDA_SUCCESS) {
|
||||
printf("cuCtxSynchronize failed after memcpy \n");
|
||||
}
|
||||
}
|
||||
if (cuStatus == CUDA_SUCCESS) {
|
||||
if (fwrite(pCudaCopyMem, bufferSize, 1, file_p) != 1) {
|
||||
printf("Cuda consumer: output file write failed\n");
|
||||
cuStatus = CUDA_ERROR_UNKNOWN;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
pInFile1 = fopen(data->fileName1, "rb");
|
||||
if (!pInFile1) {
|
||||
printf("Failed to open file :%s\n", data->fileName1);
|
||||
goto done;
|
||||
}
|
||||
pInFile2 = fopen(data->fileName2, "rb");
|
||||
if (!pInFile2) {
|
||||
printf("Failed to open file :%s\n", data->fileName2);
|
||||
goto done;
|
||||
}
|
||||
rewind(file_p);
|
||||
check_result = checkbuf(file_p, pInFile1);
|
||||
if (check_result == -1) {
|
||||
rewind(file_p);
|
||||
check_result = checkbuf(file_p, pInFile2);
|
||||
if (check_result == -1) {
|
||||
printf("Frame received does not match any valid image: FAILED\n");
|
||||
} else {
|
||||
printf("Frame check Passed\n");
|
||||
}
|
||||
} else {
|
||||
printf("Frame check Passed\n");
|
||||
}
|
||||
if (pCudaCopyMem) {
|
||||
free(pCudaCopyMem);
|
||||
pCudaCopyMem = NULL;
|
||||
}
|
||||
cuStatus =
|
||||
cuEGLStreamConsumerReleaseFrame(&data->cudaConn, cudaResource, NULL);
|
||||
if (cuStatus != CUDA_SUCCESS) {
|
||||
printf("cuEGLStreamConsumerReleaseFrame failed with cuStatus = %d\n",
|
||||
cuStatus);
|
||||
goto done;
|
||||
}
|
||||
} else {
|
||||
printf("cuda AcquireFrame FAILED with cuStatus=%d\n", cuStatus);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
if (!eglQueryStreamKHR(g_display, eglStream, EGL_STREAM_STATE_KHR, &streamState)) {
|
||||
printf("Cuda consumer, eglQueryStreamKHR EGL_STREAM_STATE_KHR failed\n");
|
||||
}
|
||||
if (streamState == EGL_STREAM_STATE_DISCONNECTED_KHR) {
|
||||
printf("CUDA Consumer: - EGL_STREAM_STATE_DISCONNECTED_KHR received\n");
|
||||
}
|
||||
|
||||
if (streamState == EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR) {
|
||||
cuStatus = cuEGLStreamConsumerAcquireFrame(&(data->cudaConn), &cudaResource, NULL, 16000);
|
||||
|
||||
if (cuStatus == CUDA_SUCCESS) {
|
||||
CUdeviceptr pDevPtr = 0;
|
||||
int bufferSize;
|
||||
unsigned char *pCudaCopyMem = NULL;
|
||||
unsigned int copyWidthInBytes = 0, copyHeight = 0;
|
||||
|
||||
file_p = fopen(fileName, "wb+");
|
||||
if (!file_p) {
|
||||
printf("WriteFrame: file open failed %s\n", fileName);
|
||||
cuStatus = CUDA_ERROR_UNKNOWN;
|
||||
goto done;
|
||||
}
|
||||
cuStatus = cuGraphicsResourceGetMappedEglFrame(&cudaEgl, cudaResource, 0, 0);
|
||||
if (cuStatus != CUDA_SUCCESS) {
|
||||
printf("Cuda get resource failed with %d\n", cuStatus);
|
||||
goto done;
|
||||
}
|
||||
cuStatus = cuCtxSynchronize();
|
||||
if (cuStatus != CUDA_SUCCESS) {
|
||||
printf("cuCtxSynchronize failed \n");
|
||||
goto done;
|
||||
}
|
||||
if (!(cudaEgl.planeCount >= 1 && cudaEgl.planeCount <= 3)) {
|
||||
printf("Plane count is invalid\nExiting\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
for (i = 0; i < cudaEgl.planeCount; i++) {
|
||||
if (cudaEgl.frameType == CU_EGL_FRAME_TYPE_PITCH) {
|
||||
pDevPtr = (CUdeviceptr)cudaEgl.frame.pPitch[i];
|
||||
if (cudaEgl.planeCount == 1) {
|
||||
bufferSize = cudaEgl.pitch * cudaEgl.height;
|
||||
copyWidthInBytes = cudaEgl.pitch;
|
||||
copyHeight = data->height;
|
||||
}
|
||||
else if (i == 1 && cudaEgl.planeCount == 2) { // YUV 420
|
||||
// semi-planar
|
||||
bufferSize = cudaEgl.pitch * cudaEgl.height / 2;
|
||||
copyWidthInBytes = cudaEgl.pitch;
|
||||
copyHeight = data->height / 2;
|
||||
}
|
||||
else {
|
||||
bufferSize = data->width * data->height;
|
||||
copyWidthInBytes = data->width;
|
||||
copyHeight = data->height;
|
||||
if (i > 0) {
|
||||
bufferSize >>= 2;
|
||||
copyWidthInBytes >>= 1;
|
||||
copyHeight >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
cudaArr = cudaEgl.frame.pArray[i];
|
||||
if (cudaEgl.planeCount == 1) {
|
||||
bufferSize = data->width * data->height * 4;
|
||||
copyWidthInBytes = data->width * 4;
|
||||
copyHeight = data->height;
|
||||
}
|
||||
else if (i == 1 && cudaEgl.planeCount == 2) { // YUV 420
|
||||
// semi-planar
|
||||
bufferSize = data->width * data->height / 2;
|
||||
copyWidthInBytes = data->width;
|
||||
copyHeight = data->height / 2;
|
||||
}
|
||||
else {
|
||||
bufferSize = data->width * data->height;
|
||||
copyWidthInBytes = data->width;
|
||||
copyHeight = data->height;
|
||||
if (i > 0) {
|
||||
bufferSize >>= 2;
|
||||
copyWidthInBytes >>= 1;
|
||||
copyHeight >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (i == 0) {
|
||||
pCudaCopyMem = (unsigned char *)malloc(bufferSize);
|
||||
if (pCudaCopyMem == NULL) {
|
||||
printf("pCudaCopyMem malloc failed\n");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
memset(pCudaCopyMem, 0, bufferSize);
|
||||
if (data->pitchLinearOutput) {
|
||||
cuStatus = cuMemcpyDtoH(pCudaCopyMem, pDevPtr, bufferSize);
|
||||
if (cuStatus != CUDA_SUCCESS) {
|
||||
printf("cuda_consumer: pitch linear Memcpy failed, bufferSize =%d\n", bufferSize);
|
||||
goto done;
|
||||
}
|
||||
cuStatus = cuCtxSynchronize();
|
||||
if (cuStatus != CUDA_SUCCESS) {
|
||||
printf("cuda_consumer: cuCtxSynchronize failed after memcpy \n");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
else {
|
||||
CUDA_MEMCPY3D cpdesc;
|
||||
memset(&cpdesc, 0, sizeof(cpdesc));
|
||||
cpdesc.srcXInBytes = cpdesc.srcY = cpdesc.srcZ = cpdesc.srcLOD = 0;
|
||||
cpdesc.srcMemoryType = CU_MEMORYTYPE_ARRAY;
|
||||
cpdesc.srcArray = cudaArr;
|
||||
cpdesc.dstXInBytes = cpdesc.dstY = cpdesc.dstZ = cpdesc.dstLOD = 0;
|
||||
cpdesc.dstMemoryType = CU_MEMORYTYPE_HOST;
|
||||
cpdesc.dstHost = (void *)pCudaCopyMem;
|
||||
cpdesc.WidthInBytes = copyWidthInBytes; // data->width * 4;
|
||||
cpdesc.Height = copyHeight; // data->height;
|
||||
cpdesc.Depth = 1;
|
||||
|
||||
cuStatus = cuMemcpy3D(&cpdesc);
|
||||
if (cuStatus != CUDA_SUCCESS) {
|
||||
printf("Cuda consumer: cuMemCpy3D failed, copyWidthInBytes=%d, "
|
||||
"copyHight=%d\n",
|
||||
copyWidthInBytes,
|
||||
copyHeight);
|
||||
}
|
||||
cuStatus = cuCtxSynchronize();
|
||||
if (cuStatus != CUDA_SUCCESS) {
|
||||
printf("cuCtxSynchronize failed after memcpy \n");
|
||||
}
|
||||
}
|
||||
if (cuStatus == CUDA_SUCCESS) {
|
||||
if (fwrite(pCudaCopyMem, bufferSize, 1, file_p) != 1) {
|
||||
printf("Cuda consumer: output file write failed\n");
|
||||
cuStatus = CUDA_ERROR_UNKNOWN;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
pInFile1 = fopen(data->fileName1, "rb");
|
||||
if (!pInFile1) {
|
||||
printf("Failed to open file :%s\n", data->fileName1);
|
||||
goto done;
|
||||
}
|
||||
pInFile2 = fopen(data->fileName2, "rb");
|
||||
if (!pInFile2) {
|
||||
printf("Failed to open file :%s\n", data->fileName2);
|
||||
goto done;
|
||||
}
|
||||
rewind(file_p);
|
||||
check_result = checkbuf(file_p, pInFile1);
|
||||
if (check_result == -1) {
|
||||
rewind(file_p);
|
||||
check_result = checkbuf(file_p, pInFile2);
|
||||
if (check_result == -1) {
|
||||
printf("Frame received does not match any valid image: FAILED\n");
|
||||
}
|
||||
else {
|
||||
printf("Frame check Passed\n");
|
||||
}
|
||||
}
|
||||
else {
|
||||
printf("Frame check Passed\n");
|
||||
}
|
||||
if (pCudaCopyMem) {
|
||||
free(pCudaCopyMem);
|
||||
pCudaCopyMem = NULL;
|
||||
}
|
||||
cuStatus = cuEGLStreamConsumerReleaseFrame(&data->cudaConn, cudaResource, NULL);
|
||||
if (cuStatus != CUDA_SUCCESS) {
|
||||
printf("cuEGLStreamConsumerReleaseFrame failed with cuStatus = %d\n", cuStatus);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
else {
|
||||
printf("cuda AcquireFrame FAILED with cuStatus=%d\n", cuStatus);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
if (file_p) {
|
||||
fclose(file_p);
|
||||
file_p = NULL;
|
||||
}
|
||||
if (pInFile1) {
|
||||
fclose(pInFile1);
|
||||
pInFile1 = NULL;
|
||||
}
|
||||
if (pInFile1) {
|
||||
fclose(pInFile2);
|
||||
pInFile2 = NULL;
|
||||
}
|
||||
return cuStatus;
|
||||
}
|
||||
|
||||
int checkbuf(FILE *fp1, FILE *fp2) {
|
||||
int match = 0;
|
||||
int ch1, ch2;
|
||||
if (fp1 == NULL) {
|
||||
printf("Invalid file pointer for first file\n");
|
||||
return -1;
|
||||
} else if (fp2 == NULL) {
|
||||
printf("Invalid file pointer for second file\n");
|
||||
return -1;
|
||||
} else {
|
||||
ch1 = getc(fp1);
|
||||
ch2 = getc(fp2);
|
||||
while ((ch1 != EOF) && (ch2 != EOF) && (ch1 == ch2)) {
|
||||
ch1 = getc(fp1);
|
||||
ch2 = getc(fp2);
|
||||
if (file_p) {
|
||||
fclose(file_p);
|
||||
file_p = NULL;
|
||||
}
|
||||
if (ch1 == ch2) {
|
||||
match = 1;
|
||||
} else if (ch1 != ch2) {
|
||||
match = -1;
|
||||
if (pInFile1) {
|
||||
fclose(pInFile1);
|
||||
pInFile1 = NULL;
|
||||
}
|
||||
}
|
||||
return match;
|
||||
if (pInFile1) {
|
||||
fclose(pInFile2);
|
||||
pInFile2 = NULL;
|
||||
}
|
||||
return cuStatus;
|
||||
}
|
||||
|
||||
CUresult cudaDeviceCreateConsumer(test_cuda_consumer_s *cudaConsumer,
|
||||
CUdevice device) {
|
||||
CUresult status = CUDA_SUCCESS;
|
||||
if (CUDA_SUCCESS != (status = cuInit(0))) {
|
||||
printf("Failed to initialize CUDA\n");
|
||||
int checkbuf(FILE *fp1, FILE *fp2)
|
||||
{
|
||||
int match = 0;
|
||||
int ch1, ch2;
|
||||
if (fp1 == NULL) {
|
||||
printf("Invalid file pointer for first file\n");
|
||||
return -1;
|
||||
}
|
||||
else if (fp2 == NULL) {
|
||||
printf("Invalid file pointer for second file\n");
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
ch1 = getc(fp1);
|
||||
ch2 = getc(fp2);
|
||||
while ((ch1 != EOF) && (ch2 != EOF) && (ch1 == ch2)) {
|
||||
ch1 = getc(fp1);
|
||||
ch2 = getc(fp2);
|
||||
}
|
||||
if (ch1 == ch2) {
|
||||
match = 1;
|
||||
}
|
||||
else if (ch1 != ch2) {
|
||||
match = -1;
|
||||
}
|
||||
}
|
||||
return match;
|
||||
}
|
||||
|
||||
CUresult cudaDeviceCreateConsumer(test_cuda_consumer_s *cudaConsumer, CUdevice device)
|
||||
{
|
||||
CUresult status = CUDA_SUCCESS;
|
||||
if (CUDA_SUCCESS != (status = cuInit(0))) {
|
||||
printf("Failed to initialize CUDA\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
int major = 0, minor = 0;
|
||||
char deviceName[256];
|
||||
checkCudaErrors(cuDeviceGetAttribute(&major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, device));
|
||||
checkCudaErrors(cuDeviceGetAttribute(&minor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, device));
|
||||
checkCudaErrors(cuDeviceGetName(deviceName, 256, device));
|
||||
printf("CUDA Consumer on GPU Device %d: \"%s\" with compute capability "
|
||||
"%d.%d\n\n",
|
||||
device,
|
||||
deviceName,
|
||||
major,
|
||||
minor);
|
||||
|
||||
if (CUDA_SUCCESS != (status = cuCtxCreate(&cudaConsumer->context, 0, device))) {
|
||||
printf("failed to create CUDA context\n");
|
||||
return status;
|
||||
}
|
||||
checkCudaErrors(cuCtxPopCurrent(&cudaConsumer->context));
|
||||
return status;
|
||||
}
|
||||
|
||||
int major = 0, minor = 0;
|
||||
char deviceName[256];
|
||||
checkCudaErrors(cuDeviceGetAttribute(
|
||||
&major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, device));
|
||||
checkCudaErrors(cuDeviceGetAttribute(
|
||||
&minor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, device));
|
||||
checkCudaErrors(cuDeviceGetName(deviceName, 256, device));
|
||||
printf(
|
||||
"CUDA Consumer on GPU Device %d: \"%s\" with compute capability "
|
||||
"%d.%d\n\n",
|
||||
device, deviceName, major, minor);
|
||||
|
||||
if (CUDA_SUCCESS !=
|
||||
(status = cuCtxCreate(&cudaConsumer->context, 0, device))) {
|
||||
printf("failed to create CUDA context\n");
|
||||
return status;
|
||||
}
|
||||
checkCudaErrors(cuCtxPopCurrent(&cudaConsumer->context));
|
||||
return status;
|
||||
}
|
||||
|
||||
void cuda_consumer_init(test_cuda_consumer_s *cudaConsumer, TestArgs *args) {
|
||||
cudaConsumer->pitchLinearOutput = args->pitchLinearOutput;
|
||||
cudaConsumer->width = args->inputWidth;
|
||||
cudaConsumer->height = args->inputHeight;
|
||||
cudaConsumer->fileName1 = args->infile1;
|
||||
cudaConsumer->fileName2 = args->infile2;
|
||||
void cuda_consumer_init(test_cuda_consumer_s *cudaConsumer, TestArgs *args)
|
||||
{
|
||||
cudaConsumer->pitchLinearOutput = args->pitchLinearOutput;
|
||||
cudaConsumer->width = args->inputWidth;
|
||||
cudaConsumer->height = args->inputHeight;
|
||||
cudaConsumer->fileName1 = args->infile1;
|
||||
cudaConsumer->fileName2 = args->infile2;
|
||||
|
||||
cudaConsumer->outFile1 = const_cast<char *>("cuda_out1.yuv");
|
||||
cudaConsumer->outFile2 = const_cast<char *>("cuda_out2.yuv");
|
||||
cudaConsumer->outFile1 = const_cast<char *>("cuda_out1.yuv");
|
||||
cudaConsumer->outFile2 = const_cast<char *>("cuda_out2.yuv");
|
||||
}
|
||||
|
||||
CUresult cuda_consumer_deinit(test_cuda_consumer_s *cudaConsumer) {
|
||||
return cuEGLStreamConsumerDisconnect(&cudaConsumer->cudaConn);
|
||||
CUresult cuda_consumer_deinit(test_cuda_consumer_s *cudaConsumer)
|
||||
{
|
||||
return cuEGLStreamConsumerDisconnect(&cudaConsumer->cudaConn);
|
||||
}
|
||||
|
||||
@@ -35,28 +35,29 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "cudaEGL.h"
|
||||
#include "eglstrm_common.h"
|
||||
|
||||
extern EGLStreamKHR eglStream;
|
||||
extern EGLDisplay g_display;
|
||||
extern EGLDisplay g_display;
|
||||
|
||||
typedef struct _test_cuda_consumer_s {
|
||||
CUcontext context;
|
||||
CUeglStreamConnection cudaConn;
|
||||
bool pitchLinearOutput;
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
const char *fileName1;
|
||||
const char *fileName2;
|
||||
const char *outFile1;
|
||||
const char *outFile2;
|
||||
unsigned int frameCount;
|
||||
typedef struct _test_cuda_consumer_s
|
||||
{
|
||||
CUcontext context;
|
||||
CUeglStreamConnection cudaConn;
|
||||
bool pitchLinearOutput;
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
const char *fileName1;
|
||||
const char *fileName2;
|
||||
const char *outFile1;
|
||||
const char *outFile2;
|
||||
unsigned int frameCount;
|
||||
} test_cuda_consumer_s;
|
||||
|
||||
void cuda_consumer_init(test_cuda_consumer_s *cudaConsumer, TestArgs *args);
|
||||
void cuda_consumer_init(test_cuda_consumer_s *cudaConsumer, TestArgs *args);
|
||||
CUresult cuda_consumer_deinit(test_cuda_consumer_s *cudaConsumer);
|
||||
CUresult cudaConsumerTest(test_cuda_consumer_s *data, const char *outFile);
|
||||
CUresult cudaDeviceCreateConsumer(test_cuda_consumer_s *cudaConsumer,
|
||||
CUdevice device);
|
||||
CUresult cudaDeviceCreateConsumer(test_cuda_consumer_s *cudaConsumer, CUdevice device);
|
||||
#endif
|
||||
|
||||
@@ -30,7 +30,9 @@
|
||||
//
|
||||
|
||||
#include "cuda_producer.h"
|
||||
|
||||
#include <helper_cuda_drvapi.h>
|
||||
|
||||
#include "cudaEGL.h"
|
||||
#include "eglstrm_common.h"
|
||||
|
||||
@@ -38,369 +40,379 @@
|
||||
EXTENSION_LIST(EXTLST_EXTERN)
|
||||
#endif
|
||||
|
||||
static CUresult cudaProducerReadYUVFrame(FILE *file, unsigned int frameNum,
|
||||
unsigned int width,
|
||||
unsigned int height,
|
||||
unsigned char *pBuff) {
|
||||
int bOrderUV = 0;
|
||||
unsigned char *pYBuff, *pUBuff, *pVBuff, *pChroma;
|
||||
unsigned int frameSize = (width * height * 3) / 2;
|
||||
CUresult ret = CUDA_SUCCESS;
|
||||
unsigned int i;
|
||||
static CUresult cudaProducerReadYUVFrame(FILE *file,
|
||||
unsigned int frameNum,
|
||||
unsigned int width,
|
||||
unsigned int height,
|
||||
unsigned char *pBuff)
|
||||
{
|
||||
int bOrderUV = 0;
|
||||
unsigned char *pYBuff, *pUBuff, *pVBuff, *pChroma;
|
||||
unsigned int frameSize = (width * height * 3) / 2;
|
||||
CUresult ret = CUDA_SUCCESS;
|
||||
unsigned int i;
|
||||
|
||||
if (!pBuff || !file) return CUDA_ERROR_FILE_NOT_FOUND;
|
||||
if (!pBuff || !file)
|
||||
return CUDA_ERROR_FILE_NOT_FOUND;
|
||||
|
||||
pYBuff = pBuff;
|
||||
pYBuff = pBuff;
|
||||
|
||||
// YVU order in the buffer
|
||||
pVBuff = pYBuff + width * height;
|
||||
pUBuff = pVBuff + width * height / 4;
|
||||
// YVU order in the buffer
|
||||
pVBuff = pYBuff + width * height;
|
||||
pUBuff = pVBuff + width * height / 4;
|
||||
|
||||
if (fseek(file, frameNum * frameSize, SEEK_SET)) {
|
||||
printf("ReadYUVFrame: Error seeking file: %p\n", file);
|
||||
ret = CUDA_ERROR_NOT_PERMITTED;
|
||||
goto done;
|
||||
}
|
||||
// read Y U V separately
|
||||
for (i = 0; i < height; i++) {
|
||||
if (fread(pYBuff, width, 1, file) != 1) {
|
||||
printf("ReadYUVFrame: Error reading file: %p\n", file);
|
||||
ret = CUDA_ERROR_NOT_PERMITTED;
|
||||
goto done;
|
||||
if (fseek(file, frameNum * frameSize, SEEK_SET)) {
|
||||
printf("ReadYUVFrame: Error seeking file: %p\n", file);
|
||||
ret = CUDA_ERROR_NOT_PERMITTED;
|
||||
goto done;
|
||||
}
|
||||
pYBuff += width;
|
||||
}
|
||||
|
||||
pChroma = bOrderUV ? pUBuff : pVBuff;
|
||||
for (i = 0; i < height / 2; i++) {
|
||||
if (fread(pChroma, width / 2, 1, file) != 1) {
|
||||
printf("ReadYUVFrame: Error reading file: %p\n", file);
|
||||
ret = CUDA_ERROR_NOT_PERMITTED;
|
||||
goto done;
|
||||
}
|
||||
pChroma += width / 2;
|
||||
}
|
||||
|
||||
pChroma = bOrderUV ? pVBuff : pUBuff;
|
||||
for (i = 0; i < height / 2; i++) {
|
||||
if (fread(pChroma, width / 2, 1, file) != 1) {
|
||||
printf("ReadYUVFrame: Error reading file: %p\n", file);
|
||||
ret = CUDA_ERROR_NOT_PERMITTED;
|
||||
goto done;
|
||||
}
|
||||
pChroma += width / 2;
|
||||
}
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static CUresult cudaProducerReadARGBFrame(FILE *file, unsigned int frameNum,
|
||||
unsigned int width,
|
||||
unsigned int height,
|
||||
unsigned char *pBuff) {
|
||||
unsigned int frameSize = width * height * 4;
|
||||
CUresult ret = CUDA_SUCCESS;
|
||||
|
||||
if (!pBuff || !file) return CUDA_ERROR_FILE_NOT_FOUND;
|
||||
|
||||
if (fseek(file, frameNum * frameSize, SEEK_SET)) {
|
||||
printf("ReadYUVFrame: Error seeking file: %p\n", file);
|
||||
ret = CUDA_ERROR_NOT_PERMITTED;
|
||||
goto done;
|
||||
}
|
||||
|
||||
// read ARGB data
|
||||
if (fread(pBuff, frameSize, 1, file) != 1) {
|
||||
if (feof(file))
|
||||
printf("ReadARGBFrame: file read to the end\n");
|
||||
else
|
||||
printf("ReadARGBFrame: Error reading file: %p\n", file);
|
||||
ret = CUDA_ERROR_NOT_PERMITTED;
|
||||
goto done;
|
||||
}
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
CUresult cudaProducerTest(test_cuda_producer_s *cudaProducer, char *file) {
|
||||
int framenum = 0;
|
||||
CUarray cudaArr[3] = {0};
|
||||
CUdeviceptr cudaPtr[3] = {0, 0, 0};
|
||||
unsigned int bufferSize;
|
||||
CUresult cuStatus = CUDA_SUCCESS;
|
||||
unsigned int i, surfNum, uvOffset[3] = {0};
|
||||
unsigned int copyWidthInBytes[3] = {0, 0, 0}, copyHeight[3] = {0, 0, 0};
|
||||
CUeglColorFormat eglColorFormat;
|
||||
FILE *file_p;
|
||||
CUeglFrame cudaEgl;
|
||||
CUcontext oldContext;
|
||||
|
||||
file_p = fopen(file, "rb");
|
||||
if (!file_p) {
|
||||
printf("CudaProducer: Error opening file: %s\n", file);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (cudaProducer->pitchLinearOutput) {
|
||||
if (cudaProducer->isARGB) {
|
||||
cudaPtr[0] = cudaProducer->cudaPtrARGB[0];
|
||||
} else { // YUV case
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (i == 0) {
|
||||
bufferSize = cudaProducer->width * cudaProducer->height;
|
||||
} else {
|
||||
bufferSize = cudaProducer->width * cudaProducer->height / 4;
|
||||
// read Y U V separately
|
||||
for (i = 0; i < height; i++) {
|
||||
if (fread(pYBuff, width, 1, file) != 1) {
|
||||
printf("ReadYUVFrame: Error reading file: %p\n", file);
|
||||
ret = CUDA_ERROR_NOT_PERMITTED;
|
||||
goto done;
|
||||
}
|
||||
|
||||
cudaPtr[i] = cudaProducer->cudaPtrYUV[i];
|
||||
}
|
||||
pYBuff += width;
|
||||
}
|
||||
} else {
|
||||
|
||||
pChroma = bOrderUV ? pUBuff : pVBuff;
|
||||
for (i = 0; i < height / 2; i++) {
|
||||
if (fread(pChroma, width / 2, 1, file) != 1) {
|
||||
printf("ReadYUVFrame: Error reading file: %p\n", file);
|
||||
ret = CUDA_ERROR_NOT_PERMITTED;
|
||||
goto done;
|
||||
}
|
||||
pChroma += width / 2;
|
||||
}
|
||||
|
||||
pChroma = bOrderUV ? pVBuff : pUBuff;
|
||||
for (i = 0; i < height / 2; i++) {
|
||||
if (fread(pChroma, width / 2, 1, file) != 1) {
|
||||
printf("ReadYUVFrame: Error reading file: %p\n", file);
|
||||
ret = CUDA_ERROR_NOT_PERMITTED;
|
||||
goto done;
|
||||
}
|
||||
pChroma += width / 2;
|
||||
}
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static CUresult cudaProducerReadARGBFrame(FILE *file,
|
||||
unsigned int frameNum,
|
||||
unsigned int width,
|
||||
unsigned int height,
|
||||
unsigned char *pBuff)
|
||||
{
|
||||
unsigned int frameSize = width * height * 4;
|
||||
CUresult ret = CUDA_SUCCESS;
|
||||
|
||||
if (!pBuff || !file)
|
||||
return CUDA_ERROR_FILE_NOT_FOUND;
|
||||
|
||||
if (fseek(file, frameNum * frameSize, SEEK_SET)) {
|
||||
printf("ReadYUVFrame: Error seeking file: %p\n", file);
|
||||
ret = CUDA_ERROR_NOT_PERMITTED;
|
||||
goto done;
|
||||
}
|
||||
|
||||
// read ARGB data
|
||||
if (fread(pBuff, frameSize, 1, file) != 1) {
|
||||
if (feof(file))
|
||||
printf("ReadARGBFrame: file read to the end\n");
|
||||
else
|
||||
printf("ReadARGBFrame: Error reading file: %p\n", file);
|
||||
ret = CUDA_ERROR_NOT_PERMITTED;
|
||||
goto done;
|
||||
}
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
CUresult cudaProducerTest(test_cuda_producer_s *cudaProducer, char *file)
|
||||
{
|
||||
int framenum = 0;
|
||||
CUarray cudaArr[3] = {0};
|
||||
CUdeviceptr cudaPtr[3] = {0, 0, 0};
|
||||
unsigned int bufferSize;
|
||||
CUresult cuStatus = CUDA_SUCCESS;
|
||||
unsigned int i, surfNum, uvOffset[3] = {0};
|
||||
unsigned int copyWidthInBytes[3] = {0, 0, 0}, copyHeight[3] = {0, 0, 0};
|
||||
CUeglColorFormat eglColorFormat;
|
||||
FILE *file_p;
|
||||
CUeglFrame cudaEgl;
|
||||
CUcontext oldContext;
|
||||
|
||||
file_p = fopen(file, "rb");
|
||||
if (!file_p) {
|
||||
printf("CudaProducer: Error opening file: %s\n", file);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (cudaProducer->pitchLinearOutput) {
|
||||
if (cudaProducer->isARGB) {
|
||||
cudaPtr[0] = cudaProducer->cudaPtrARGB[0];
|
||||
}
|
||||
else { // YUV case
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (i == 0) {
|
||||
bufferSize = cudaProducer->width * cudaProducer->height;
|
||||
}
|
||||
else {
|
||||
bufferSize = cudaProducer->width * cudaProducer->height / 4;
|
||||
}
|
||||
|
||||
cudaPtr[i] = cudaProducer->cudaPtrYUV[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (cudaProducer->isARGB) {
|
||||
cudaArr[0] = cudaProducer->cudaArrARGB[0];
|
||||
}
|
||||
else {
|
||||
for (i = 0; i < 3; i++) {
|
||||
cudaArr[i] = cudaProducer->cudaArrYUV[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
uvOffset[0] = 0;
|
||||
if (cudaProducer->isARGB) {
|
||||
cudaArr[0] = cudaProducer->cudaArrARGB[0];
|
||||
} else {
|
||||
for (i = 0; i < 3; i++) {
|
||||
cudaArr[i] = cudaProducer->cudaArrYUV[i];
|
||||
}
|
||||
if (CUDA_SUCCESS
|
||||
!= cudaProducerReadARGBFrame(
|
||||
file_p, framenum, cudaProducer->width, cudaProducer->height, cudaProducer->pBuff)) {
|
||||
printf("cuda producer, read ARGB frame failed\n");
|
||||
goto done;
|
||||
}
|
||||
copyWidthInBytes[0] = cudaProducer->width * 4;
|
||||
copyHeight[0] = cudaProducer->height;
|
||||
surfNum = 1;
|
||||
eglColorFormat = CU_EGL_COLOR_FORMAT_ARGB;
|
||||
}
|
||||
}
|
||||
uvOffset[0] = 0;
|
||||
if (cudaProducer->isARGB) {
|
||||
if (CUDA_SUCCESS !=
|
||||
cudaProducerReadARGBFrame(file_p, framenum, cudaProducer->width,
|
||||
cudaProducer->height, cudaProducer->pBuff)) {
|
||||
printf("cuda producer, read ARGB frame failed\n");
|
||||
goto done;
|
||||
else {
|
||||
if (CUDA_SUCCESS
|
||||
!= cudaProducerReadYUVFrame(
|
||||
file_p, framenum, cudaProducer->width, cudaProducer->height, cudaProducer->pBuff)) {
|
||||
printf("cuda producer, reading YUV frame failed\n");
|
||||
goto done;
|
||||
}
|
||||
surfNum = 3;
|
||||
eglColorFormat = CU_EGL_COLOR_FORMAT_YUV420_PLANAR;
|
||||
copyWidthInBytes[0] = cudaProducer->width;
|
||||
copyHeight[0] = cudaProducer->height;
|
||||
copyWidthInBytes[1] = cudaProducer->width / 2;
|
||||
copyHeight[1] = cudaProducer->height / 2;
|
||||
copyWidthInBytes[2] = cudaProducer->width / 2;
|
||||
copyHeight[2] = cudaProducer->height / 2;
|
||||
uvOffset[1] = cudaProducer->width * cudaProducer->height;
|
||||
uvOffset[2] = uvOffset[1] + cudaProducer->width / 2 * cudaProducer->height / 2;
|
||||
}
|
||||
copyWidthInBytes[0] = cudaProducer->width * 4;
|
||||
copyHeight[0] = cudaProducer->height;
|
||||
surfNum = 1;
|
||||
eglColorFormat = CU_EGL_COLOR_FORMAT_ARGB;
|
||||
} else {
|
||||
if (CUDA_SUCCESS !=
|
||||
cudaProducerReadYUVFrame(file_p, framenum, cudaProducer->width,
|
||||
cudaProducer->height, cudaProducer->pBuff)) {
|
||||
printf("cuda producer, reading YUV frame failed\n");
|
||||
goto done;
|
||||
if (cudaProducer->pitchLinearOutput) {
|
||||
for (i = 0; i < surfNum; i++) {
|
||||
cuStatus = cuMemcpy(
|
||||
cudaPtr[i], (CUdeviceptr)(cudaProducer->pBuff + uvOffset[i]), copyWidthInBytes[i] * copyHeight[i]);
|
||||
|
||||
if (cuStatus != CUDA_SUCCESS) {
|
||||
printf("Cuda producer: cuMemCpy pitchlinear failed, cuStatus =%d\n", cuStatus);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// copy cudaProducer->pBuff to cudaArray
|
||||
CUDA_MEMCPY3D cpdesc;
|
||||
for (i = 0; i < surfNum; i++) {
|
||||
memset(&cpdesc, 0, sizeof(cpdesc));
|
||||
cpdesc.srcXInBytes = cpdesc.srcY = cpdesc.srcZ = cpdesc.srcLOD = 0;
|
||||
cpdesc.srcMemoryType = CU_MEMORYTYPE_HOST;
|
||||
cpdesc.srcHost = (void *)(cudaProducer->pBuff + uvOffset[i]);
|
||||
cpdesc.dstXInBytes = cpdesc.dstY = cpdesc.dstZ = cpdesc.dstLOD = 0;
|
||||
cpdesc.dstMemoryType = CU_MEMORYTYPE_ARRAY;
|
||||
cpdesc.dstArray = cudaArr[i];
|
||||
cpdesc.WidthInBytes = copyWidthInBytes[i];
|
||||
cpdesc.Height = copyHeight[i];
|
||||
cpdesc.Depth = 1;
|
||||
cuStatus = cuMemcpy3D(&cpdesc);
|
||||
if (cuStatus != CUDA_SUCCESS) {
|
||||
printf("Cuda producer: cuMemCpy failed, cuStatus =%d\n", cuStatus);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
surfNum = 3;
|
||||
eglColorFormat = CU_EGL_COLOR_FORMAT_YUV420_PLANAR;
|
||||
copyWidthInBytes[0] = cudaProducer->width;
|
||||
copyHeight[0] = cudaProducer->height;
|
||||
copyWidthInBytes[1] = cudaProducer->width / 2;
|
||||
copyHeight[1] = cudaProducer->height / 2;
|
||||
copyWidthInBytes[2] = cudaProducer->width / 2;
|
||||
copyHeight[2] = cudaProducer->height / 2;
|
||||
uvOffset[1] = cudaProducer->width * cudaProducer->height;
|
||||
uvOffset[2] =
|
||||
uvOffset[1] + cudaProducer->width / 2 * cudaProducer->height / 2;
|
||||
}
|
||||
if (cudaProducer->pitchLinearOutput) {
|
||||
for (i = 0; i < surfNum; i++) {
|
||||
cuStatus =
|
||||
cuMemcpy(cudaPtr[i], (CUdeviceptr)(cudaProducer->pBuff + uvOffset[i]),
|
||||
copyWidthInBytes[i] * copyHeight[i]);
|
||||
if (cudaProducer->pitchLinearOutput)
|
||||
cudaEgl.frame.pPitch[i] = (void *)cudaPtr[i];
|
||||
else
|
||||
cudaEgl.frame.pArray[i] = cudaArr[i];
|
||||
}
|
||||
cudaEgl.width = copyWidthInBytes[0];
|
||||
cudaEgl.depth = 1;
|
||||
cudaEgl.height = copyHeight[0];
|
||||
cudaEgl.pitch = cudaProducer->pitchLinearOutput ? cudaEgl.width : 0;
|
||||
cudaEgl.frameType = cudaProducer->pitchLinearOutput ? CU_EGL_FRAME_TYPE_PITCH : CU_EGL_FRAME_TYPE_ARRAY;
|
||||
cudaEgl.planeCount = surfNum;
|
||||
cudaEgl.numChannels = (eglColorFormat == CU_EGL_COLOR_FORMAT_ARGB) ? 4 : 1;
|
||||
cudaEgl.eglColorFormat = eglColorFormat;
|
||||
cudaEgl.cuFormat = CU_AD_FORMAT_UNSIGNED_INT8;
|
||||
|
||||
if (cuStatus != CUDA_SUCCESS) {
|
||||
printf("Cuda producer: cuMemCpy pitchlinear failed, cuStatus =%d\n",
|
||||
cuStatus);
|
||||
static int numFramesPresented = 0;
|
||||
// If there is a frame presented before we check if consumer
|
||||
// is done with it using cuEGLStreamProducerReturnFrame.
|
||||
while (numFramesPresented) {
|
||||
CUeglFrame returnedCudaEgl;
|
||||
cuStatus = cuEGLStreamProducerReturnFrame(&cudaProducer->cudaConn, &returnedCudaEgl, NULL);
|
||||
if (cuStatus == CUDA_ERROR_LAUNCH_TIMEOUT) {
|
||||
continue;
|
||||
}
|
||||
else if (cuStatus != CUDA_SUCCESS) {
|
||||
printf("cuda Producer return frame FAILED with custatus= %d\n", cuStatus);
|
||||
return cuStatus;
|
||||
}
|
||||
else {
|
||||
numFramesPresented--;
|
||||
}
|
||||
}
|
||||
|
||||
cuStatus = cuEGLStreamProducerPresentFrame(&cudaProducer->cudaConn, cudaEgl, NULL);
|
||||
if (cuStatus != CUDA_SUCCESS) {
|
||||
printf("cuda Producer present frame FAILED with custatus= %d\n", cuStatus);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// copy cudaProducer->pBuff to cudaArray
|
||||
CUDA_MEMCPY3D cpdesc;
|
||||
for (i = 0; i < surfNum; i++) {
|
||||
memset(&cpdesc, 0, sizeof(cpdesc));
|
||||
cpdesc.srcXInBytes = cpdesc.srcY = cpdesc.srcZ = cpdesc.srcLOD = 0;
|
||||
cpdesc.srcMemoryType = CU_MEMORYTYPE_HOST;
|
||||
cpdesc.srcHost = (void *)(cudaProducer->pBuff + uvOffset[i]);
|
||||
cpdesc.dstXInBytes = cpdesc.dstY = cpdesc.dstZ = cpdesc.dstLOD = 0;
|
||||
cpdesc.dstMemoryType = CU_MEMORYTYPE_ARRAY;
|
||||
cpdesc.dstArray = cudaArr[i];
|
||||
cpdesc.WidthInBytes = copyWidthInBytes[i];
|
||||
cpdesc.Height = copyHeight[i];
|
||||
cpdesc.Depth = 1;
|
||||
cuStatus = cuMemcpy3D(&cpdesc);
|
||||
if (cuStatus != CUDA_SUCCESS) {
|
||||
printf("Cuda producer: cuMemCpy failed, cuStatus =%d\n", cuStatus);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i = 0; i < surfNum; i++) {
|
||||
if (cudaProducer->pitchLinearOutput)
|
||||
cudaEgl.frame.pPitch[i] = (void *)cudaPtr[i];
|
||||
else
|
||||
cudaEgl.frame.pArray[i] = cudaArr[i];
|
||||
}
|
||||
cudaEgl.width = copyWidthInBytes[0];
|
||||
cudaEgl.depth = 1;
|
||||
cudaEgl.height = copyHeight[0];
|
||||
cudaEgl.pitch = cudaProducer->pitchLinearOutput ? cudaEgl.width : 0;
|
||||
cudaEgl.frameType = cudaProducer->pitchLinearOutput ? CU_EGL_FRAME_TYPE_PITCH
|
||||
: CU_EGL_FRAME_TYPE_ARRAY;
|
||||
cudaEgl.planeCount = surfNum;
|
||||
cudaEgl.numChannels = (eglColorFormat == CU_EGL_COLOR_FORMAT_ARGB) ? 4 : 1;
|
||||
cudaEgl.eglColorFormat = eglColorFormat;
|
||||
cudaEgl.cuFormat = CU_AD_FORMAT_UNSIGNED_INT8;
|
||||
|
||||
static int numFramesPresented = 0;
|
||||
// If there is a frame presented before we check if consumer
|
||||
// is done with it using cuEGLStreamProducerReturnFrame.
|
||||
while (numFramesPresented) {
|
||||
CUeglFrame returnedCudaEgl;
|
||||
cuStatus = cuEGLStreamProducerReturnFrame(&cudaProducer->cudaConn,
|
||||
&returnedCudaEgl, NULL);
|
||||
if (cuStatus == CUDA_ERROR_LAUNCH_TIMEOUT) {
|
||||
continue;
|
||||
} else if (cuStatus != CUDA_SUCCESS) {
|
||||
printf("cuda Producer return frame FAILED with custatus= %d\n", cuStatus);
|
||||
return cuStatus;
|
||||
} else {
|
||||
numFramesPresented--;
|
||||
}
|
||||
}
|
||||
|
||||
cuStatus =
|
||||
cuEGLStreamProducerPresentFrame(&cudaProducer->cudaConn, cudaEgl, NULL);
|
||||
if (cuStatus != CUDA_SUCCESS) {
|
||||
printf("cuda Producer present frame FAILED with custatus= %d\n", cuStatus);
|
||||
goto done;
|
||||
}
|
||||
numFramesPresented++;
|
||||
numFramesPresented++;
|
||||
|
||||
done:
|
||||
if (file_p) {
|
||||
fclose(file_p);
|
||||
file_p = NULL;
|
||||
}
|
||||
if (file_p) {
|
||||
fclose(file_p);
|
||||
file_p = NULL;
|
||||
}
|
||||
|
||||
return cuStatus;
|
||||
return cuStatus;
|
||||
}
|
||||
|
||||
CUresult cudaDeviceCreateProducer(test_cuda_producer_s *cudaProducer,
|
||||
CUdevice device) {
|
||||
CUresult status = CUDA_SUCCESS;
|
||||
if (CUDA_SUCCESS != (status = cuInit(0))) {
|
||||
printf("Failed to initialize CUDA\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
int major = 0, minor = 0;
|
||||
char deviceName[256];
|
||||
checkCudaErrors(cuDeviceGetAttribute(
|
||||
&major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, device));
|
||||
checkCudaErrors(cuDeviceGetAttribute(
|
||||
&minor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, device));
|
||||
checkCudaErrors(cuDeviceGetName(deviceName, 256, device));
|
||||
printf(
|
||||
"CUDA Producer on GPU Device %d: \"%s\" with compute capability "
|
||||
"%d.%d\n\n",
|
||||
device, deviceName, major, minor);
|
||||
|
||||
if (major < 6) {
|
||||
printf(
|
||||
"EGLStream_CUDA_Interop requires SM 6.0 or higher arch GPU. "
|
||||
"Exiting...\n");
|
||||
exit(2); // EXIT_WAIVED
|
||||
}
|
||||
|
||||
if (CUDA_SUCCESS !=
|
||||
(status = cuCtxCreate(&cudaProducer->context, 0, device))) {
|
||||
printf("failed to create CUDA context\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
status = cuMemAlloc(&cudaProducer->cudaPtrARGB[0], (WIDTH * HEIGHT * 4));
|
||||
if (status != CUDA_SUCCESS) {
|
||||
printf("Create CUDA pointer failed, cuStatus=%d\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
status = cuMemAlloc(&cudaProducer->cudaPtrYUV[0], (WIDTH * HEIGHT));
|
||||
if (status != CUDA_SUCCESS) {
|
||||
printf("Create CUDA pointer failed, cuStatus=%d\n", status);
|
||||
return status;
|
||||
}
|
||||
status = cuMemAlloc(&cudaProducer->cudaPtrYUV[1], (WIDTH * HEIGHT) / 4);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
printf("Create CUDA pointer failed, cuStatus=%d\n", status);
|
||||
return status;
|
||||
}
|
||||
status = cuMemAlloc(&cudaProducer->cudaPtrYUV[2], (WIDTH * HEIGHT) / 4);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
printf("Create CUDA pointer failed, cuStatus=%d\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
CUDA_ARRAY3D_DESCRIPTOR desc = {0};
|
||||
|
||||
desc.Format = CU_AD_FORMAT_UNSIGNED_INT8;
|
||||
desc.Depth = 1;
|
||||
desc.Flags = CUDA_ARRAY3D_SURFACE_LDST;
|
||||
desc.NumChannels = 4;
|
||||
desc.Width = WIDTH * 4;
|
||||
desc.Height = HEIGHT;
|
||||
status = cuArray3DCreate(&cudaProducer->cudaArrARGB[0], &desc);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
printf("Create CUDA array failed, cuStatus=%d\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (i == 0) {
|
||||
desc.NumChannels = 1;
|
||||
desc.Width = WIDTH;
|
||||
desc.Height = HEIGHT;
|
||||
} else { // U/V surface as planar
|
||||
desc.NumChannels = 1;
|
||||
desc.Width = WIDTH / 2;
|
||||
desc.Height = HEIGHT / 2;
|
||||
CUresult cudaDeviceCreateProducer(test_cuda_producer_s *cudaProducer, CUdevice device)
|
||||
{
|
||||
CUresult status = CUDA_SUCCESS;
|
||||
if (CUDA_SUCCESS != (status = cuInit(0))) {
|
||||
printf("Failed to initialize CUDA\n");
|
||||
return status;
|
||||
}
|
||||
status = cuArray3DCreate(&cudaProducer->cudaArrYUV[i], &desc);
|
||||
|
||||
int major = 0, minor = 0;
|
||||
char deviceName[256];
|
||||
checkCudaErrors(cuDeviceGetAttribute(&major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, device));
|
||||
checkCudaErrors(cuDeviceGetAttribute(&minor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, device));
|
||||
checkCudaErrors(cuDeviceGetName(deviceName, 256, device));
|
||||
printf("CUDA Producer on GPU Device %d: \"%s\" with compute capability "
|
||||
"%d.%d\n\n",
|
||||
device,
|
||||
deviceName,
|
||||
major,
|
||||
minor);
|
||||
|
||||
if (major < 6) {
|
||||
printf("EGLStream_CUDA_Interop requires SM 6.0 or higher arch GPU. "
|
||||
"Exiting...\n");
|
||||
exit(2); // EXIT_WAIVED
|
||||
}
|
||||
|
||||
if (CUDA_SUCCESS != (status = cuCtxCreate(&cudaProducer->context, 0, device))) {
|
||||
printf("failed to create CUDA context\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
status = cuMemAlloc(&cudaProducer->cudaPtrARGB[0], (WIDTH * HEIGHT * 4));
|
||||
if (status != CUDA_SUCCESS) {
|
||||
printf("Create CUDA array failed, cuStatus=%d\n", status);
|
||||
return status;
|
||||
printf("Create CUDA pointer failed, cuStatus=%d\n", status);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
cudaProducer->pBuff = (unsigned char *)malloc((WIDTH * HEIGHT * 4));
|
||||
if (!cudaProducer->pBuff) {
|
||||
printf("CudaProducer: Failed to allocate image buffer\n");
|
||||
}
|
||||
status = cuMemAlloc(&cudaProducer->cudaPtrYUV[0], (WIDTH * HEIGHT));
|
||||
if (status != CUDA_SUCCESS) {
|
||||
printf("Create CUDA pointer failed, cuStatus=%d\n", status);
|
||||
return status;
|
||||
}
|
||||
status = cuMemAlloc(&cudaProducer->cudaPtrYUV[1], (WIDTH * HEIGHT) / 4);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
printf("Create CUDA pointer failed, cuStatus=%d\n", status);
|
||||
return status;
|
||||
}
|
||||
status = cuMemAlloc(&cudaProducer->cudaPtrYUV[2], (WIDTH * HEIGHT) / 4);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
printf("Create CUDA pointer failed, cuStatus=%d\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
checkCudaErrors(cuCtxPopCurrent(&cudaProducer->context));
|
||||
return status;
|
||||
CUDA_ARRAY3D_DESCRIPTOR desc = {0};
|
||||
|
||||
desc.Format = CU_AD_FORMAT_UNSIGNED_INT8;
|
||||
desc.Depth = 1;
|
||||
desc.Flags = CUDA_ARRAY3D_SURFACE_LDST;
|
||||
desc.NumChannels = 4;
|
||||
desc.Width = WIDTH * 4;
|
||||
desc.Height = HEIGHT;
|
||||
status = cuArray3DCreate(&cudaProducer->cudaArrARGB[0], &desc);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
printf("Create CUDA array failed, cuStatus=%d\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (i == 0) {
|
||||
desc.NumChannels = 1;
|
||||
desc.Width = WIDTH;
|
||||
desc.Height = HEIGHT;
|
||||
}
|
||||
else { // U/V surface as planar
|
||||
desc.NumChannels = 1;
|
||||
desc.Width = WIDTH / 2;
|
||||
desc.Height = HEIGHT / 2;
|
||||
}
|
||||
status = cuArray3DCreate(&cudaProducer->cudaArrYUV[i], &desc);
|
||||
if (status != CUDA_SUCCESS) {
|
||||
printf("Create CUDA array failed, cuStatus=%d\n", status);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
cudaProducer->pBuff = (unsigned char *)malloc((WIDTH * HEIGHT * 4));
|
||||
if (!cudaProducer->pBuff) {
|
||||
printf("CudaProducer: Failed to allocate image buffer\n");
|
||||
}
|
||||
|
||||
checkCudaErrors(cuCtxPopCurrent(&cudaProducer->context));
|
||||
return status;
|
||||
}
|
||||
|
||||
void cudaProducerInit(test_cuda_producer_s *cudaProducer, EGLDisplay eglDisplay,
|
||||
EGLStreamKHR eglStream, TestArgs *args) {
|
||||
cudaProducer->fileName1 = args->infile1;
|
||||
cudaProducer->fileName2 = args->infile2;
|
||||
void cudaProducerInit(test_cuda_producer_s *cudaProducer, EGLDisplay eglDisplay, EGLStreamKHR eglStream, TestArgs *args)
|
||||
{
|
||||
cudaProducer->fileName1 = args->infile1;
|
||||
cudaProducer->fileName2 = args->infile2;
|
||||
|
||||
cudaProducer->frameCount = 2;
|
||||
cudaProducer->width = args->inputWidth;
|
||||
cudaProducer->height = args->inputHeight;
|
||||
cudaProducer->isARGB = args->isARGB;
|
||||
cudaProducer->pitchLinearOutput = args->pitchLinearOutput;
|
||||
cudaProducer->frameCount = 2;
|
||||
cudaProducer->width = args->inputWidth;
|
||||
cudaProducer->height = args->inputHeight;
|
||||
cudaProducer->isARGB = args->isARGB;
|
||||
cudaProducer->pitchLinearOutput = args->pitchLinearOutput;
|
||||
|
||||
// Set cudaProducer default parameters
|
||||
cudaProducer->eglDisplay = eglDisplay;
|
||||
cudaProducer->eglStream = eglStream;
|
||||
// Set cudaProducer default parameters
|
||||
cudaProducer->eglDisplay = eglDisplay;
|
||||
cudaProducer->eglStream = eglStream;
|
||||
}
|
||||
|
||||
CUresult cudaProducerDeinit(test_cuda_producer_s *cudaProducer) {
|
||||
if (cudaProducer->pBuff) free(cudaProducer->pBuff);
|
||||
CUresult cudaProducerDeinit(test_cuda_producer_s *cudaProducer)
|
||||
{
|
||||
if (cudaProducer->pBuff)
|
||||
free(cudaProducer->pBuff);
|
||||
|
||||
checkCudaErrors(cuMemFree(cudaProducer->cudaPtrARGB[0]));
|
||||
checkCudaErrors(cuMemFree(cudaProducer->cudaPtrYUV[0]));
|
||||
checkCudaErrors(cuMemFree(cudaProducer->cudaPtrYUV[1]));
|
||||
checkCudaErrors(cuMemFree(cudaProducer->cudaPtrYUV[2]));
|
||||
checkCudaErrors(cuArrayDestroy(cudaProducer->cudaArrARGB[0]));
|
||||
checkCudaErrors(cuArrayDestroy(cudaProducer->cudaArrYUV[0]));
|
||||
checkCudaErrors(cuArrayDestroy(cudaProducer->cudaArrYUV[1]));
|
||||
checkCudaErrors(cuArrayDestroy(cudaProducer->cudaArrYUV[2]));
|
||||
checkCudaErrors(cuMemFree(cudaProducer->cudaPtrARGB[0]));
|
||||
checkCudaErrors(cuMemFree(cudaProducer->cudaPtrYUV[0]));
|
||||
checkCudaErrors(cuMemFree(cudaProducer->cudaPtrYUV[1]));
|
||||
checkCudaErrors(cuMemFree(cudaProducer->cudaPtrYUV[2]));
|
||||
checkCudaErrors(cuArrayDestroy(cudaProducer->cudaArrARGB[0]));
|
||||
checkCudaErrors(cuArrayDestroy(cudaProducer->cudaArrYUV[0]));
|
||||
checkCudaErrors(cuArrayDestroy(cudaProducer->cudaArrYUV[1]));
|
||||
checkCudaErrors(cuArrayDestroy(cudaProducer->cudaArrYUV[2]));
|
||||
|
||||
return cuEGLStreamProducerDisconnect(&cudaProducer->cudaConn);
|
||||
return cuEGLStreamProducerDisconnect(&cudaProducer->cudaConn);
|
||||
}
|
||||
|
||||
@@ -33,36 +33,39 @@
|
||||
#define _CUDA_PRODUCER_H_
|
||||
#include <EGL/egl.h>
|
||||
#include <EGL/eglext.h>
|
||||
|
||||
#include "cudaEGL.h"
|
||||
#include "eglstrm_common.h"
|
||||
|
||||
extern EGLStreamKHR eglStream;
|
||||
extern EGLDisplay g_display;
|
||||
extern EGLDisplay g_display;
|
||||
|
||||
typedef struct _test_cuda_producer_s {
|
||||
// Stream params
|
||||
char *fileName1;
|
||||
char *fileName2;
|
||||
unsigned char *pBuff;
|
||||
int frameCount;
|
||||
bool isARGB;
|
||||
bool pitchLinearOutput;
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
CUcontext context;
|
||||
CUeglStreamConnection cudaConn;
|
||||
CUdeviceptr cudaPtrARGB[1];
|
||||
CUdeviceptr cudaPtrYUV[3];
|
||||
CUarray cudaArrARGB[1];
|
||||
CUarray cudaArrYUV[3];
|
||||
EGLStreamKHR eglStream;
|
||||
EGLDisplay eglDisplay;
|
||||
typedef struct _test_cuda_producer_s
|
||||
{
|
||||
// Stream params
|
||||
char *fileName1;
|
||||
char *fileName2;
|
||||
unsigned char *pBuff;
|
||||
int frameCount;
|
||||
bool isARGB;
|
||||
bool pitchLinearOutput;
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
CUcontext context;
|
||||
CUeglStreamConnection cudaConn;
|
||||
CUdeviceptr cudaPtrARGB[1];
|
||||
CUdeviceptr cudaPtrYUV[3];
|
||||
CUarray cudaArrARGB[1];
|
||||
CUarray cudaArrYUV[3];
|
||||
EGLStreamKHR eglStream;
|
||||
EGLDisplay eglDisplay;
|
||||
} test_cuda_producer_s;
|
||||
|
||||
void cudaProducerInit(test_cuda_producer_s *cudaProducer, EGLDisplay eglDisplay,
|
||||
EGLStreamKHR eglStream, TestArgs *args);
|
||||
void cudaProducerInit(test_cuda_producer_s *cudaProducer,
|
||||
EGLDisplay eglDisplay,
|
||||
EGLStreamKHR eglStream,
|
||||
TestArgs *args);
|
||||
CUresult cudaProducerTest(test_cuda_producer_s *parserArg, char *file);
|
||||
CUresult cudaProducerDeinit(test_cuda_producer_s *cudaProducer);
|
||||
CUresult cudaDeviceCreateProducer(test_cuda_producer_s *cudaProducer,
|
||||
CUdevice device);
|
||||
CUresult cudaDeviceCreateProducer(test_cuda_producer_s *cudaProducer, CUdevice device);
|
||||
#endif
|
||||
|
||||
@@ -32,107 +32,102 @@
|
||||
#include "eglstrm_common.h"
|
||||
|
||||
EGLStreamKHR eglStream;
|
||||
EGLDisplay g_display;
|
||||
EGLAttrib cudaIndex;
|
||||
EGLDisplay g_display;
|
||||
EGLAttrib cudaIndex;
|
||||
|
||||
#if defined(EXTENSION_LIST)
|
||||
EXTENSION_LIST(EXTLST_DECL)
|
||||
typedef void (*extlst_fnptr_t)(void);
|
||||
static struct {
|
||||
extlst_fnptr_t *fnptr;
|
||||
char const *name;
|
||||
static struct
|
||||
{
|
||||
extlst_fnptr_t *fnptr;
|
||||
char const *name;
|
||||
} extensionList[] = {EXTENSION_LIST(EXTLST_ENTRY)};
|
||||
|
||||
int eglSetupExtensions(void) {
|
||||
unsigned int i;
|
||||
int eglSetupExtensions(void)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < (sizeof(extensionList) / sizeof(*extensionList)); i++) {
|
||||
*extensionList[i].fnptr = eglGetProcAddress(extensionList[i].name);
|
||||
if (*extensionList[i].fnptr == NULL) {
|
||||
printf("Couldn't get address of %s()\n", extensionList[i].name);
|
||||
return 0;
|
||||
for (i = 0; i < (sizeof(extensionList) / sizeof(*extensionList)); i++) {
|
||||
*extensionList[i].fnptr = eglGetProcAddress(extensionList[i].name);
|
||||
if (*extensionList[i].fnptr == NULL) {
|
||||
printf("Couldn't get address of %s()\n", extensionList[i].name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int EGLStreamInit(int *cuda_device) {
|
||||
static const EGLint streamAttrMailboxMode[] = {EGL_SUPPORT_REUSE_NV,
|
||||
EGL_FALSE, EGL_NONE};
|
||||
EGLBoolean eglStatus;
|
||||
int EGLStreamInit(int *cuda_device)
|
||||
{
|
||||
static const EGLint streamAttrMailboxMode[] = {EGL_SUPPORT_REUSE_NV, EGL_FALSE, EGL_NONE};
|
||||
EGLBoolean eglStatus;
|
||||
#define MAX_EGL_DEVICES 4
|
||||
EGLint numDevices = 0;
|
||||
EGLDeviceEXT devices[MAX_EGL_DEVICES];
|
||||
eglStatus = eglQueryDevicesEXT(MAX_EGL_DEVICES, devices, &numDevices);
|
||||
if (eglStatus != EGL_TRUE) {
|
||||
printf("Error querying EGL devices\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (numDevices == 0) {
|
||||
printf("No EGL devices found.. Waiving\n");
|
||||
eglStatus = EGL_FALSE;
|
||||
exit(EXIT_WAIVED);
|
||||
}
|
||||
|
||||
int egl_device_id = 0;
|
||||
for (egl_device_id = 0; egl_device_id < numDevices; egl_device_id++) {
|
||||
eglStatus = eglQueryDeviceAttribEXT(devices[egl_device_id],
|
||||
EGL_CUDA_DEVICE_NV, &cudaIndex);
|
||||
if (eglStatus == EGL_TRUE) {
|
||||
*cuda_device = cudaIndex; // We select first EGL-CUDA Capable device.
|
||||
printf("Found EGL-CUDA Capable device with CUDA Device id = %d\n",
|
||||
(int)cudaIndex);
|
||||
break;
|
||||
EGLint numDevices = 0;
|
||||
EGLDeviceEXT devices[MAX_EGL_DEVICES];
|
||||
eglStatus = eglQueryDevicesEXT(MAX_EGL_DEVICES, devices, &numDevices);
|
||||
if (eglStatus != EGL_TRUE) {
|
||||
printf("Error querying EGL devices\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (egl_device_id >= numDevices) {
|
||||
printf("No CUDA Capable EGL Device found.. Waiving execution\n");
|
||||
exit(EXIT_WAIVED);
|
||||
}
|
||||
if (numDevices == 0) {
|
||||
printf("No EGL devices found.. Waiving\n");
|
||||
eglStatus = EGL_FALSE;
|
||||
exit(EXIT_WAIVED);
|
||||
}
|
||||
|
||||
g_display = eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT,
|
||||
(void *)devices[egl_device_id], NULL);
|
||||
if (g_display == EGL_NO_DISPLAY) {
|
||||
printf("Could not get EGL display from device. \n");
|
||||
eglStatus = EGL_FALSE;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
int egl_device_id = 0;
|
||||
for (egl_device_id = 0; egl_device_id < numDevices; egl_device_id++) {
|
||||
eglStatus = eglQueryDeviceAttribEXT(devices[egl_device_id], EGL_CUDA_DEVICE_NV, &cudaIndex);
|
||||
if (eglStatus == EGL_TRUE) {
|
||||
*cuda_device = cudaIndex; // We select first EGL-CUDA Capable device.
|
||||
printf("Found EGL-CUDA Capable device with CUDA Device id = %d\n", (int)cudaIndex);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
eglStatus = eglInitialize(g_display, 0, 0);
|
||||
if (!eglStatus) {
|
||||
printf("EGL failed to initialize. \n");
|
||||
eglStatus = EGL_FALSE;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (egl_device_id >= numDevices) {
|
||||
printf("No CUDA Capable EGL Device found.. Waiving execution\n");
|
||||
exit(EXIT_WAIVED);
|
||||
}
|
||||
|
||||
eglStream = eglCreateStreamKHR(g_display, streamAttrMailboxMode);
|
||||
if (eglStream == EGL_NO_STREAM_KHR) {
|
||||
printf("Could not create EGL stream.\n");
|
||||
eglStatus = EGL_FALSE;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
g_display = eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT, (void *)devices[egl_device_id], NULL);
|
||||
if (g_display == EGL_NO_DISPLAY) {
|
||||
printf("Could not get EGL display from device. \n");
|
||||
eglStatus = EGL_FALSE;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
printf("Created EGLStream %p\n", eglStream);
|
||||
eglStatus = eglInitialize(g_display, 0, 0);
|
||||
if (!eglStatus) {
|
||||
printf("EGL failed to initialize. \n");
|
||||
eglStatus = EGL_FALSE;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Set stream attribute
|
||||
if (!eglStreamAttribKHR(g_display, eglStream, EGL_CONSUMER_LATENCY_USEC_KHR,
|
||||
16000)) {
|
||||
printf(
|
||||
"Consumer: eglStreamAttribKHR EGL_CONSUMER_LATENCY_USEC_KHR failed\n");
|
||||
return 0;
|
||||
}
|
||||
if (!eglStreamAttribKHR(g_display, eglStream,
|
||||
EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR, 16000)) {
|
||||
printf(
|
||||
"Consumer: eglStreamAttribKHR EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR "
|
||||
"failed\n");
|
||||
return 0;
|
||||
}
|
||||
printf("EGLStream initialized\n");
|
||||
return 1;
|
||||
eglStream = eglCreateStreamKHR(g_display, streamAttrMailboxMode);
|
||||
if (eglStream == EGL_NO_STREAM_KHR) {
|
||||
printf("Could not create EGL stream.\n");
|
||||
eglStatus = EGL_FALSE;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
printf("Created EGLStream %p\n", eglStream);
|
||||
|
||||
// Set stream attribute
|
||||
if (!eglStreamAttribKHR(g_display, eglStream, EGL_CONSUMER_LATENCY_USEC_KHR, 16000)) {
|
||||
printf("Consumer: eglStreamAttribKHR EGL_CONSUMER_LATENCY_USEC_KHR failed\n");
|
||||
return 0;
|
||||
}
|
||||
if (!eglStreamAttribKHR(g_display, eglStream, EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR, 16000)) {
|
||||
printf("Consumer: eglStreamAttribKHR EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR "
|
||||
"failed\n");
|
||||
return 0;
|
||||
}
|
||||
printf("EGLStream initialized\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
void EGLStreamFini(void) { eglDestroyStreamKHR(g_display, eglStream); }
|
||||
|
||||
@@ -45,59 +45,56 @@
|
||||
#include "cudaEGL.h"
|
||||
#include "helper_cuda_drvapi.h"
|
||||
|
||||
#define EXTENSION_LIST(T) \
|
||||
T(PFNEGLCREATESTREAMKHRPROC, eglCreateStreamKHR) \
|
||||
T(PFNEGLDESTROYSTREAMKHRPROC, eglDestroyStreamKHR) \
|
||||
T(PFNEGLQUERYSTREAMKHRPROC, eglQueryStreamKHR) \
|
||||
T(PFNEGLQUERYSTREAMU64KHRPROC, eglQueryStreamu64KHR) \
|
||||
T(PFNEGLQUERYSTREAMTIMEKHRPROC, eglQueryStreamTimeKHR) \
|
||||
T(PFNEGLSTREAMATTRIBKHRPROC, eglStreamAttribKHR) \
|
||||
T(PFNEGLSTREAMCONSUMERACQUIREKHRPROC, eglStreamConsumerAcquireKHR) \
|
||||
T(PFNEGLSTREAMCONSUMERRELEASEKHRPROC, eglStreamConsumerReleaseKHR) \
|
||||
T(PFNEGLSTREAMCONSUMERGLTEXTUREEXTERNALKHRPROC, \
|
||||
eglStreamConsumerGLTextureExternalKHR) \
|
||||
T(PFNEGLGETSTREAMFILEDESCRIPTORKHRPROC, eglGetStreamFileDescriptorKHR) \
|
||||
T(PFNEGLQUERYDEVICESEXTPROC, eglQueryDevicesEXT) \
|
||||
T(PFNEGLGETPLATFORMDISPLAYEXTPROC, eglGetPlatformDisplayEXT) \
|
||||
T(PFNEGLQUERYDEVICEATTRIBEXTPROC, eglQueryDeviceAttribEXT) \
|
||||
T(PFNEGLCREATESTREAMFROMFILEDESCRIPTORKHRPROC, \
|
||||
eglCreateStreamFromFileDescriptorKHR)
|
||||
#define EXTENSION_LIST(T) \
|
||||
T(PFNEGLCREATESTREAMKHRPROC, eglCreateStreamKHR) \
|
||||
T(PFNEGLDESTROYSTREAMKHRPROC, eglDestroyStreamKHR) \
|
||||
T(PFNEGLQUERYSTREAMKHRPROC, eglQueryStreamKHR) \
|
||||
T(PFNEGLQUERYSTREAMU64KHRPROC, eglQueryStreamu64KHR) \
|
||||
T(PFNEGLQUERYSTREAMTIMEKHRPROC, eglQueryStreamTimeKHR) \
|
||||
T(PFNEGLSTREAMATTRIBKHRPROC, eglStreamAttribKHR) \
|
||||
T(PFNEGLSTREAMCONSUMERACQUIREKHRPROC, eglStreamConsumerAcquireKHR) \
|
||||
T(PFNEGLSTREAMCONSUMERRELEASEKHRPROC, eglStreamConsumerReleaseKHR) \
|
||||
T(PFNEGLSTREAMCONSUMERGLTEXTUREEXTERNALKHRPROC, eglStreamConsumerGLTextureExternalKHR) \
|
||||
T(PFNEGLGETSTREAMFILEDESCRIPTORKHRPROC, eglGetStreamFileDescriptorKHR) \
|
||||
T(PFNEGLQUERYDEVICESEXTPROC, eglQueryDevicesEXT) \
|
||||
T(PFNEGLGETPLATFORMDISPLAYEXTPROC, eglGetPlatformDisplayEXT) \
|
||||
T(PFNEGLQUERYDEVICEATTRIBEXTPROC, eglQueryDeviceAttribEXT) \
|
||||
T(PFNEGLCREATESTREAMFROMFILEDESCRIPTORKHRPROC, eglCreateStreamFromFileDescriptorKHR)
|
||||
|
||||
#define eglCreateStreamKHR my_eglCreateStreamKHR
|
||||
#define eglDestroyStreamKHR my_eglDestroyStreamKHR
|
||||
#define eglQueryStreamKHR my_eglQueryStreamKHR
|
||||
#define eglQueryStreamu64KHR my_eglQueryStreamu64KHR
|
||||
#define eglQueryStreamTimeKHR my_eglQueryStreamTimeKHR
|
||||
#define eglStreamAttribKHR my_eglStreamAttribKHR
|
||||
#define eglStreamConsumerAcquireKHR my_eglStreamConsumerAcquireKHR
|
||||
#define eglStreamConsumerReleaseKHR my_eglStreamConsumerReleaseKHR
|
||||
#define eglStreamConsumerGLTextureExternalKHR \
|
||||
my_eglStreamConsumerGLTextureExternalKHR
|
||||
#define eglGetStreamFileDescriptorKHR my_eglGetStreamFileDescriptorKHR
|
||||
#define eglCreateStreamFromFileDescriptorKHR \
|
||||
my_eglCreateStreamFromFileDescriptorKHR
|
||||
#define eglQueryDevicesEXT my_eglQueryDevicesEXT
|
||||
#define eglGetPlatformDisplayEXT my_eglGetPlatformDisplayEXT
|
||||
#define eglQueryDeviceAttribEXT my_eglQueryDeviceAttribEXT
|
||||
#define eglCreateStreamKHR my_eglCreateStreamKHR
|
||||
#define eglDestroyStreamKHR my_eglDestroyStreamKHR
|
||||
#define eglQueryStreamKHR my_eglQueryStreamKHR
|
||||
#define eglQueryStreamu64KHR my_eglQueryStreamu64KHR
|
||||
#define eglQueryStreamTimeKHR my_eglQueryStreamTimeKHR
|
||||
#define eglStreamAttribKHR my_eglStreamAttribKHR
|
||||
#define eglStreamConsumerAcquireKHR my_eglStreamConsumerAcquireKHR
|
||||
#define eglStreamConsumerReleaseKHR my_eglStreamConsumerReleaseKHR
|
||||
#define eglStreamConsumerGLTextureExternalKHR my_eglStreamConsumerGLTextureExternalKHR
|
||||
#define eglGetStreamFileDescriptorKHR my_eglGetStreamFileDescriptorKHR
|
||||
#define eglCreateStreamFromFileDescriptorKHR my_eglCreateStreamFromFileDescriptorKHR
|
||||
#define eglQueryDevicesEXT my_eglQueryDevicesEXT
|
||||
#define eglGetPlatformDisplayEXT my_eglGetPlatformDisplayEXT
|
||||
#define eglQueryDeviceAttribEXT my_eglQueryDeviceAttribEXT
|
||||
|
||||
#define EXTLST_DECL(tx, x) tx my_##x = NULL;
|
||||
#define EXTLST_DECL(tx, x) tx my_##x = NULL;
|
||||
#define EXTLST_EXTERN(tx, x) extern tx my_##x;
|
||||
#define EXTLST_ENTRY(tx, x) {(extlst_fnptr_t *)&my_##x, #x},
|
||||
#define EXTLST_ENTRY(tx, x) {(extlst_fnptr_t *)&my_##x, #x},
|
||||
|
||||
#define MAX_STRING_SIZE 256
|
||||
#define WIDTH 720
|
||||
#define HEIGHT 480
|
||||
#define WIDTH 720
|
||||
#define HEIGHT 480
|
||||
|
||||
typedef struct _TestArgs {
|
||||
char *infile1;
|
||||
char *infile2;
|
||||
bool isARGB;
|
||||
unsigned int inputWidth;
|
||||
unsigned int inputHeight;
|
||||
bool pitchLinearOutput;
|
||||
typedef struct _TestArgs
|
||||
{
|
||||
char *infile1;
|
||||
char *infile2;
|
||||
bool isARGB;
|
||||
unsigned int inputWidth;
|
||||
unsigned int inputHeight;
|
||||
bool pitchLinearOutput;
|
||||
} TestArgs;
|
||||
|
||||
int eglSetupExtensions(void);
|
||||
int EGLStreamInit(int *dev);
|
||||
int eglSetupExtensions(void);
|
||||
int EGLStreamInit(int *dev);
|
||||
void EGLStreamFini(void);
|
||||
#endif
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
//
|
||||
//
|
||||
|
||||
//#define EGL_EGLEXT_PROTOTYPES
|
||||
// #define EGL_EGLEXT_PROTOTYPES
|
||||
|
||||
#include "cudaEGL.h"
|
||||
#include "cuda_consumer.h"
|
||||
@@ -46,186 +46,187 @@ EXTENSION_LIST(EXTLST_EXTERN)
|
||||
|
||||
bool signal_stop = 0;
|
||||
|
||||
static void sig_handler(int sig) {
|
||||
signal_stop = 1;
|
||||
printf("Signal: %d\n", sig);
|
||||
static void sig_handler(int sig)
|
||||
{
|
||||
signal_stop = 1;
|
||||
printf("Signal: %d\n", sig);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
TestArgs args;
|
||||
CUresult curesult = CUDA_SUCCESS;
|
||||
unsigned int i, j;
|
||||
EGLint streamState = 0;
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
TestArgs args;
|
||||
CUresult curesult = CUDA_SUCCESS;
|
||||
unsigned int i, j;
|
||||
EGLint streamState = 0;
|
||||
|
||||
test_cuda_consumer_s cudaConsumer;
|
||||
test_cuda_producer_s cudaProducer;
|
||||
test_cuda_consumer_s cudaConsumer;
|
||||
test_cuda_producer_s cudaProducer;
|
||||
|
||||
memset(&cudaProducer, 0, sizeof(test_cuda_producer_s));
|
||||
memset(&cudaConsumer, 0, sizeof(test_cuda_consumer_s));
|
||||
memset(&cudaProducer, 0, sizeof(test_cuda_producer_s));
|
||||
memset(&cudaConsumer, 0, sizeof(test_cuda_consumer_s));
|
||||
|
||||
// Hook up Ctrl-C handler
|
||||
signal(SIGINT, sig_handler);
|
||||
if (!eglSetupExtensions()) {
|
||||
printf("SetupExtentions failed \n");
|
||||
curesult = CUDA_ERROR_UNKNOWN;
|
||||
goto done;
|
||||
}
|
||||
|
||||
checkCudaErrors(cuInit(0));
|
||||
|
||||
int count;
|
||||
|
||||
checkCudaErrors(cuDeviceGetCount(&count));
|
||||
printf("Found %d cuda devices\n", count);
|
||||
|
||||
CUdevice devId;
|
||||
|
||||
if (!EGLStreamInit(&devId)) {
|
||||
printf("EGLStream Init failed.\n");
|
||||
curesult = CUDA_ERROR_UNKNOWN;
|
||||
goto done;
|
||||
}
|
||||
curesult = cudaDeviceCreateProducer(&cudaProducer, devId);
|
||||
if (curesult != CUDA_SUCCESS) {
|
||||
goto done;
|
||||
}
|
||||
curesult = cudaDeviceCreateConsumer(&cudaConsumer, devId);
|
||||
if (curesult != CUDA_SUCCESS) {
|
||||
goto done;
|
||||
}
|
||||
checkCudaErrors(cuCtxPushCurrent(cudaConsumer.context));
|
||||
if (CUDA_SUCCESS != (curesult = cuEGLStreamConsumerConnect(
|
||||
&(cudaConsumer.cudaConn), eglStream))) {
|
||||
printf("FAILED Connect CUDA consumer with error %d\n", curesult);
|
||||
goto done;
|
||||
} else {
|
||||
printf("Connected CUDA consumer, CudaConsumer %p\n", cudaConsumer.cudaConn);
|
||||
}
|
||||
checkCudaErrors(cuCtxPopCurrent(&cudaConsumer.context));
|
||||
|
||||
checkCudaErrors(cuCtxPushCurrent(cudaProducer.context));
|
||||
if (CUDA_SUCCESS ==
|
||||
(curesult = cuEGLStreamProducerConnect(&(cudaProducer.cudaConn),
|
||||
eglStream, WIDTH, HEIGHT))) {
|
||||
printf("Connect CUDA producer Done, CudaProducer %p\n",
|
||||
cudaProducer.cudaConn);
|
||||
} else {
|
||||
printf("Connect CUDA producer FAILED with error %d\n", curesult);
|
||||
goto done;
|
||||
}
|
||||
checkCudaErrors(cuCtxPopCurrent(&cudaProducer.context));
|
||||
|
||||
// Initialize producer
|
||||
for (i = 0; i < NUM_TRAILS; i++) {
|
||||
if (streamState != EGL_STREAM_STATE_CONNECTING_KHR) {
|
||||
if (!eglQueryStreamKHR(g_display, eglStream, EGL_STREAM_STATE_KHR,
|
||||
&streamState)) {
|
||||
printf("main: eglQueryStreamKHR EGL_STREAM_STATE_KHR failed\n");
|
||||
// Hook up Ctrl-C handler
|
||||
signal(SIGINT, sig_handler);
|
||||
if (!eglSetupExtensions()) {
|
||||
printf("SetupExtentions failed \n");
|
||||
curesult = CUDA_ERROR_UNKNOWN;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
args.inputWidth = WIDTH;
|
||||
args.inputHeight = HEIGHT;
|
||||
if (i % 2 != 0) {
|
||||
args.isARGB = 1;
|
||||
args.infile1 = sdkFindFilePath("cuda_f_1.yuv", argv[0]);
|
||||
args.infile2 = sdkFindFilePath("cuda_f_2.yuv", argv[0]);
|
||||
} else {
|
||||
args.isARGB = 0;
|
||||
args.infile1 = sdkFindFilePath("cuda_yuv_f_1.yuv", argv[0]);
|
||||
args.infile2 = sdkFindFilePath("cuda_yuv_f_2.yuv", argv[0]);
|
||||
|
||||
checkCudaErrors(cuInit(0));
|
||||
|
||||
int count;
|
||||
|
||||
checkCudaErrors(cuDeviceGetCount(&count));
|
||||
printf("Found %d cuda devices\n", count);
|
||||
|
||||
CUdevice devId;
|
||||
|
||||
if (!EGLStreamInit(&devId)) {
|
||||
printf("EGLStream Init failed.\n");
|
||||
curesult = CUDA_ERROR_UNKNOWN;
|
||||
goto done;
|
||||
}
|
||||
if ((i % 4) < 2) {
|
||||
args.pitchLinearOutput = 1;
|
||||
} else {
|
||||
args.pitchLinearOutput = 0;
|
||||
curesult = cudaDeviceCreateProducer(&cudaProducer, devId);
|
||||
if (curesult != CUDA_SUCCESS) {
|
||||
goto done;
|
||||
}
|
||||
curesult = cudaDeviceCreateConsumer(&cudaConsumer, devId);
|
||||
if (curesult != CUDA_SUCCESS) {
|
||||
goto done;
|
||||
}
|
||||
checkCudaErrors(cuCtxPushCurrent(cudaConsumer.context));
|
||||
if (CUDA_SUCCESS != (curesult = cuEGLStreamConsumerConnect(&(cudaConsumer.cudaConn), eglStream))) {
|
||||
printf("FAILED Connect CUDA consumer with error %d\n", curesult);
|
||||
goto done;
|
||||
}
|
||||
else {
|
||||
printf("Connected CUDA consumer, CudaConsumer %p\n", cudaConsumer.cudaConn);
|
||||
}
|
||||
checkCudaErrors(cuCtxPopCurrent(&cudaConsumer.context));
|
||||
|
||||
checkCudaErrors(cuCtxPushCurrent(cudaProducer.context));
|
||||
if (CUDA_SUCCESS == (curesult = cuEGLStreamProducerConnect(&(cudaProducer.cudaConn), eglStream, WIDTH, HEIGHT))) {
|
||||
printf("Connect CUDA producer Done, CudaProducer %p\n", cudaProducer.cudaConn);
|
||||
}
|
||||
else {
|
||||
printf("Connect CUDA producer FAILED with error %d\n", curesult);
|
||||
goto done;
|
||||
}
|
||||
checkCudaErrors(cuCtxPopCurrent(&cudaProducer.context));
|
||||
|
||||
// Initialize producer
|
||||
for (i = 0; i < NUM_TRAILS; i++) {
|
||||
if (streamState != EGL_STREAM_STATE_CONNECTING_KHR) {
|
||||
if (!eglQueryStreamKHR(g_display, eglStream, EGL_STREAM_STATE_KHR, &streamState)) {
|
||||
printf("main: eglQueryStreamKHR EGL_STREAM_STATE_KHR failed\n");
|
||||
curesult = CUDA_ERROR_UNKNOWN;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
args.inputWidth = WIDTH;
|
||||
args.inputHeight = HEIGHT;
|
||||
if (i % 2 != 0) {
|
||||
args.isARGB = 1;
|
||||
args.infile1 = sdkFindFilePath("cuda_f_1.yuv", argv[0]);
|
||||
args.infile2 = sdkFindFilePath("cuda_f_2.yuv", argv[0]);
|
||||
}
|
||||
else {
|
||||
args.isARGB = 0;
|
||||
args.infile1 = sdkFindFilePath("cuda_yuv_f_1.yuv", argv[0]);
|
||||
args.infile2 = sdkFindFilePath("cuda_yuv_f_2.yuv", argv[0]);
|
||||
}
|
||||
if ((i % 4) < 2) {
|
||||
args.pitchLinearOutput = 1;
|
||||
}
|
||||
else {
|
||||
args.pitchLinearOutput = 0;
|
||||
}
|
||||
|
||||
checkCudaErrors(cuCtxPushCurrent(cudaProducer.context));
|
||||
cudaProducerInit(&cudaProducer, g_display, eglStream, &args);
|
||||
checkCudaErrors(cuCtxPopCurrent(&cudaProducer.context));
|
||||
|
||||
checkCudaErrors(cuCtxPushCurrent(cudaConsumer.context));
|
||||
cuda_consumer_init(&cudaConsumer, &args);
|
||||
checkCudaErrors(cuCtxPopCurrent(&cudaConsumer.context));
|
||||
|
||||
printf("main - Cuda Producer and Consumer Initialized.\n");
|
||||
|
||||
for (j = 0; j < 2; j++) {
|
||||
printf("Running for %s frame and %s input\n",
|
||||
args.isARGB ? "ARGB" : "YUV",
|
||||
args.pitchLinearOutput ? "Pitchlinear" : "BlockLinear");
|
||||
if (j == 0) {
|
||||
checkCudaErrors(cuCtxPushCurrent(cudaProducer.context));
|
||||
curesult = cudaProducerTest(&cudaProducer, cudaProducer.fileName1);
|
||||
if (curesult != CUDA_SUCCESS) {
|
||||
printf("Cuda Producer Test failed for frame = %d\n", j + 1);
|
||||
goto done;
|
||||
}
|
||||
checkCudaErrors(cuCtxPopCurrent(&cudaProducer.context));
|
||||
checkCudaErrors(cuCtxPushCurrent(cudaConsumer.context));
|
||||
curesult = cudaConsumerTest(&cudaConsumer, cudaConsumer.outFile1);
|
||||
if (curesult != CUDA_SUCCESS) {
|
||||
printf("Cuda Consumer Test failed for frame = %d\n", j + 1);
|
||||
goto done;
|
||||
}
|
||||
checkCudaErrors(cuCtxPopCurrent(&cudaConsumer.context));
|
||||
}
|
||||
else {
|
||||
checkCudaErrors(cuCtxPushCurrent(cudaProducer.context));
|
||||
curesult = cudaProducerTest(&cudaProducer, cudaProducer.fileName2);
|
||||
if (curesult != CUDA_SUCCESS) {
|
||||
printf("Cuda Producer Test failed for frame = %d\n", j + 1);
|
||||
goto done;
|
||||
}
|
||||
|
||||
checkCudaErrors(cuCtxPopCurrent(&cudaProducer.context));
|
||||
checkCudaErrors(cuCtxPushCurrent(cudaConsumer.context));
|
||||
curesult = cudaConsumerTest(&cudaConsumer, cudaConsumer.outFile2);
|
||||
if (curesult != CUDA_SUCCESS) {
|
||||
printf("Cuda Consumer Test failed for frame = %d\n", j + 1);
|
||||
goto done;
|
||||
}
|
||||
checkCudaErrors(cuCtxPopCurrent(&cudaConsumer.context));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
checkCudaErrors(cuCtxPushCurrent(cudaProducer.context));
|
||||
cudaProducerInit(&cudaProducer, g_display, eglStream, &args);
|
||||
if (CUDA_SUCCESS != (curesult = cudaProducerDeinit(&cudaProducer))) {
|
||||
printf("Producer Disconnect FAILED. \n");
|
||||
goto done;
|
||||
}
|
||||
checkCudaErrors(cuCtxPopCurrent(&cudaProducer.context));
|
||||
|
||||
checkCudaErrors(cuCtxPushCurrent(cudaConsumer.context));
|
||||
cuda_consumer_init(&cudaConsumer, &args);
|
||||
checkCudaErrors(cuCtxPopCurrent(&cudaConsumer.context));
|
||||
|
||||
printf("main - Cuda Producer and Consumer Initialized.\n");
|
||||
|
||||
for (j = 0; j < 2; j++) {
|
||||
printf("Running for %s frame and %s input\n",
|
||||
args.isARGB ? "ARGB" : "YUV",
|
||||
args.pitchLinearOutput ? "Pitchlinear" : "BlockLinear");
|
||||
if (j == 0) {
|
||||
checkCudaErrors(cuCtxPushCurrent(cudaProducer.context));
|
||||
curesult = cudaProducerTest(&cudaProducer, cudaProducer.fileName1);
|
||||
if (curesult != CUDA_SUCCESS) {
|
||||
printf("Cuda Producer Test failed for frame = %d\n", j + 1);
|
||||
goto done;
|
||||
}
|
||||
checkCudaErrors(cuCtxPopCurrent(&cudaProducer.context));
|
||||
checkCudaErrors(cuCtxPushCurrent(cudaConsumer.context));
|
||||
curesult = cudaConsumerTest(&cudaConsumer, cudaConsumer.outFile1);
|
||||
if (curesult != CUDA_SUCCESS) {
|
||||
printf("Cuda Consumer Test failed for frame = %d\n", j + 1);
|
||||
goto done;
|
||||
}
|
||||
checkCudaErrors(cuCtxPopCurrent(&cudaConsumer.context));
|
||||
} else {
|
||||
checkCudaErrors(cuCtxPushCurrent(cudaProducer.context));
|
||||
curesult = cudaProducerTest(&cudaProducer, cudaProducer.fileName2);
|
||||
if (curesult != CUDA_SUCCESS) {
|
||||
printf("Cuda Producer Test failed for frame = %d\n", j + 1);
|
||||
goto done;
|
||||
}
|
||||
|
||||
checkCudaErrors(cuCtxPopCurrent(&cudaProducer.context));
|
||||
checkCudaErrors(cuCtxPushCurrent(cudaConsumer.context));
|
||||
curesult = cudaConsumerTest(&cudaConsumer, cudaConsumer.outFile2);
|
||||
if (curesult != CUDA_SUCCESS) {
|
||||
printf("Cuda Consumer Test failed for frame = %d\n", j + 1);
|
||||
goto done;
|
||||
}
|
||||
checkCudaErrors(cuCtxPopCurrent(&cudaConsumer.context));
|
||||
}
|
||||
if (!eglQueryStreamKHR(g_display, eglStream, EGL_STREAM_STATE_KHR, &streamState)) {
|
||||
printf("Cuda consumer, eglQueryStreamKHR EGL_STREAM_STATE_KHR failed\n");
|
||||
curesult = CUDA_ERROR_UNKNOWN;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
checkCudaErrors(cuCtxPushCurrent(cudaProducer.context));
|
||||
if (CUDA_SUCCESS != (curesult = cudaProducerDeinit(&cudaProducer))) {
|
||||
printf("Producer Disconnect FAILED. \n");
|
||||
goto done;
|
||||
}
|
||||
checkCudaErrors(cuCtxPopCurrent(&cudaProducer.context));
|
||||
|
||||
if (!eglQueryStreamKHR(g_display, eglStream, EGL_STREAM_STATE_KHR,
|
||||
&streamState)) {
|
||||
printf("Cuda consumer, eglQueryStreamKHR EGL_STREAM_STATE_KHR failed\n");
|
||||
curesult = CUDA_ERROR_UNKNOWN;
|
||||
goto done;
|
||||
}
|
||||
if (streamState != EGL_STREAM_STATE_DISCONNECTED_KHR) {
|
||||
if (CUDA_SUCCESS != (curesult = cuda_consumer_deinit(&cudaConsumer))) {
|
||||
printf("Consumer Disconnect FAILED.\n");
|
||||
goto done;
|
||||
if (streamState != EGL_STREAM_STATE_DISCONNECTED_KHR) {
|
||||
if (CUDA_SUCCESS != (curesult = cuda_consumer_deinit(&cudaConsumer))) {
|
||||
printf("Consumer Disconnect FAILED.\n");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("Producer and Consumer Disconnected \n");
|
||||
printf("Producer and Consumer Disconnected \n");
|
||||
|
||||
done:
|
||||
if (!eglQueryStreamKHR(g_display, eglStream, EGL_STREAM_STATE_KHR,
|
||||
&streamState)) {
|
||||
printf("Cuda consumer, eglQueryStreamKHR EGL_STREAM_STATE_KHR failed\n");
|
||||
curesult = CUDA_ERROR_UNKNOWN;
|
||||
}
|
||||
if (streamState != EGL_STREAM_STATE_DISCONNECTED_KHR) {
|
||||
EGLStreamFini();
|
||||
}
|
||||
if (!eglQueryStreamKHR(g_display, eglStream, EGL_STREAM_STATE_KHR, &streamState)) {
|
||||
printf("Cuda consumer, eglQueryStreamKHR EGL_STREAM_STATE_KHR failed\n");
|
||||
curesult = CUDA_ERROR_UNKNOWN;
|
||||
}
|
||||
if (streamState != EGL_STREAM_STATE_DISCONNECTED_KHR) {
|
||||
EGLStreamFini();
|
||||
}
|
||||
|
||||
if (curesult == CUDA_SUCCESS) {
|
||||
printf("&&&& EGLStream interop test PASSED\n");
|
||||
} else {
|
||||
printf("&&&& EGLStream interop test FAILED\n");
|
||||
}
|
||||
return 0;
|
||||
if (curesult == CUDA_SUCCESS) {
|
||||
printf("&&&& EGLStream interop test PASSED\n");
|
||||
}
|
||||
else {
|
||||
printf("&&&& EGLStream interop test FAILED\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -38,15 +38,13 @@
|
||||
#endif
|
||||
|
||||
// Includes
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <helper_functions.h> // helper functions for timing, string parsing
|
||||
|
||||
#include <cuda_runtime.h> // CUDA Runtime
|
||||
#include <cuda_gl_interop.h> // CUDA OpenGL interop
|
||||
|
||||
#include <helper_cuda.h> // includes for CUDA initialization and error checking
|
||||
#include <cuda_runtime.h> // CUDA Runtime
|
||||
#include <helper_cuda.h> // includes for CUDA initialization and error checking
|
||||
#include <helper_functions.h> // helper functions for timing, string parsing
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "FunctionPointers_kernels.h"
|
||||
|
||||
@@ -70,441 +68,439 @@ void initializeData(char *file);
|
||||
|
||||
static const char *sSDKsample = "CUDA Function Pointers (SobelFilter)";
|
||||
|
||||
const char *filterMode[] = {"No Filtering", "Sobel Texture",
|
||||
"Sobel SMEM+Texture", NULL};
|
||||
const char *filterMode[] = {"No Filtering", "Sobel Texture", "Sobel SMEM+Texture", NULL};
|
||||
|
||||
static int wWidth = 512; // Window width
|
||||
static int wHeight = 512; // Window height
|
||||
static int imWidth = 0; // Image width
|
||||
static int wWidth = 512; // Window width
|
||||
static int wHeight = 512; // Window height
|
||||
static int imWidth = 0; // Image width
|
||||
static int imHeight = 0; // Image height
|
||||
static int blockOp = 0;
|
||||
static int pointOp = 1;
|
||||
static int blockOp = 0;
|
||||
static int pointOp = 1;
|
||||
|
||||
// Code to handle Auto verification
|
||||
const int frameCheckNumber = 4;
|
||||
int fpsCount = 0; // FPS count for averaging
|
||||
int fpsLimit = 8; // FPS limit for sampling
|
||||
unsigned int frameCount = 0;
|
||||
StopWatchInterface *timer = NULL;
|
||||
unsigned int g_Bpp;
|
||||
const int frameCheckNumber = 4;
|
||||
int fpsCount = 0; // FPS count for averaging
|
||||
int fpsLimit = 8; // FPS limit for sampling
|
||||
unsigned int frameCount = 0;
|
||||
StopWatchInterface *timer = NULL;
|
||||
unsigned int g_Bpp;
|
||||
|
||||
int g_TotalErrors = 0;
|
||||
|
||||
int *pArgc = NULL;
|
||||
int *pArgc = NULL;
|
||||
char **pArgv = NULL;
|
||||
|
||||
bool g_bQAReadback = false;
|
||||
|
||||
// Display Data
|
||||
static GLuint pbo_buffer = 0; // Front and back CA buffers
|
||||
struct cudaGraphicsResource
|
||||
*cuda_pbo_resource; // CUDA Graphics Resource (to transfer PBO)
|
||||
static GLuint pbo_buffer = 0; // Front and back CA buffers
|
||||
struct cudaGraphicsResource *cuda_pbo_resource; // CUDA Graphics Resource (to transfer PBO)
|
||||
|
||||
static GLuint texid = 0; // Texture for display
|
||||
unsigned char *pixels = NULL; // Image pixel data on the host
|
||||
float imageScale = 1.f; // Image exposure
|
||||
static GLuint texid = 0; // Texture for display
|
||||
unsigned char *pixels = NULL; // Image pixel data on the host
|
||||
float imageScale = 1.f; // Image exposure
|
||||
enum SobelDisplayMode g_SobelDisplayMode;
|
||||
|
||||
#define OFFSET(i) ((char *)NULL + (i))
|
||||
#define MAX(a, b) ((a > b) ? a : b)
|
||||
#define REFRESH_DELAY 10 // ms
|
||||
#define OFFSET(i) ((char *)NULL + (i))
|
||||
#define MAX(a, b) ((a > b) ? a : b)
|
||||
#define REFRESH_DELAY 10 // ms
|
||||
|
||||
void computeFPS() {
|
||||
frameCount++;
|
||||
fpsCount++;
|
||||
void computeFPS()
|
||||
{
|
||||
frameCount++;
|
||||
fpsCount++;
|
||||
|
||||
if (fpsCount == fpsLimit) {
|
||||
char fps[256];
|
||||
float ifps = 1.f / (sdkGetAverageTimerValue(&timer) / 1000.f);
|
||||
sprintf(fps, "FunctionPointers [CUDA Edge Detection] (%s): %3.1f fps",
|
||||
filterMode[g_SobelDisplayMode], ifps);
|
||||
if (fpsCount == fpsLimit) {
|
||||
char fps[256];
|
||||
float ifps = 1.f / (sdkGetAverageTimerValue(&timer) / 1000.f);
|
||||
sprintf(fps, "FunctionPointers [CUDA Edge Detection] (%s): %3.1f fps", filterMode[g_SobelDisplayMode], ifps);
|
||||
|
||||
glutSetWindowTitle(fps);
|
||||
fpsCount = 0;
|
||||
glutSetWindowTitle(fps);
|
||||
fpsCount = 0;
|
||||
|
||||
fpsLimit = (int)MAX(ifps, 1.f);
|
||||
sdkResetTimer(&timer);
|
||||
}
|
||||
fpsLimit = (int)MAX(ifps, 1.f);
|
||||
sdkResetTimer(&timer);
|
||||
}
|
||||
}
|
||||
|
||||
// This is the normal display path
|
||||
void display(void) {
|
||||
sdkStartTimer(&timer);
|
||||
void display(void)
|
||||
{
|
||||
sdkStartTimer(&timer);
|
||||
|
||||
// Sobel operation
|
||||
Pixel *data = NULL;
|
||||
// Sobel operation
|
||||
Pixel *data = NULL;
|
||||
|
||||
// map PBO to get CUDA device pointer
|
||||
checkCudaErrors(cudaGraphicsMapResources(1, &cuda_pbo_resource, 0));
|
||||
size_t num_bytes;
|
||||
checkCudaErrors(cudaGraphicsResourceGetMappedPointer(
|
||||
(void **)&data, &num_bytes, cuda_pbo_resource));
|
||||
// printf("CUDA mapped PBO: May access %ld bytes\n", num_bytes);
|
||||
// map PBO to get CUDA device pointer
|
||||
checkCudaErrors(cudaGraphicsMapResources(1, &cuda_pbo_resource, 0));
|
||||
size_t num_bytes;
|
||||
checkCudaErrors(cudaGraphicsResourceGetMappedPointer((void **)&data, &num_bytes, cuda_pbo_resource));
|
||||
// printf("CUDA mapped PBO: May access %ld bytes\n", num_bytes);
|
||||
|
||||
sobelFilter(data, imWidth, imHeight, g_SobelDisplayMode, imageScale, blockOp,
|
||||
pointOp);
|
||||
checkCudaErrors(cudaGraphicsUnmapResources(1, &cuda_pbo_resource, 0));
|
||||
sobelFilter(data, imWidth, imHeight, g_SobelDisplayMode, imageScale, blockOp, pointOp);
|
||||
checkCudaErrors(cudaGraphicsUnmapResources(1, &cuda_pbo_resource, 0));
|
||||
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, texid);
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo_buffer);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, imWidth, imHeight, GL_LUMINANCE,
|
||||
GL_UNSIGNED_BYTE, OFFSET(0));
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||
glBindTexture(GL_TEXTURE_2D, texid);
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo_buffer);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, imWidth, imHeight, GL_LUMINANCE, GL_UNSIGNED_BYTE, OFFSET(0));
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
glVertex2f(0, 0);
|
||||
glTexCoord2f(0, 0);
|
||||
glVertex2f(0, 1);
|
||||
glTexCoord2f(1, 0);
|
||||
glVertex2f(1, 1);
|
||||
glTexCoord2f(1, 1);
|
||||
glVertex2f(1, 0);
|
||||
glTexCoord2f(0, 1);
|
||||
glEnd();
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glBegin(GL_QUADS);
|
||||
glVertex2f(0, 0);
|
||||
glTexCoord2f(0, 0);
|
||||
glVertex2f(0, 1);
|
||||
glTexCoord2f(1, 0);
|
||||
glVertex2f(1, 1);
|
||||
glTexCoord2f(1, 1);
|
||||
glVertex2f(1, 0);
|
||||
glTexCoord2f(0, 1);
|
||||
glEnd();
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
glutSwapBuffers();
|
||||
glutSwapBuffers();
|
||||
|
||||
sdkStopTimer(&timer);
|
||||
computeFPS();
|
||||
sdkStopTimer(&timer);
|
||||
computeFPS();
|
||||
}
|
||||
|
||||
void timerEvent(int value) {
|
||||
if (glutGetWindow()) {
|
||||
glutPostRedisplay();
|
||||
glutTimerFunc(REFRESH_DELAY, timerEvent, 0);
|
||||
}
|
||||
void timerEvent(int value)
|
||||
{
|
||||
if (glutGetWindow()) {
|
||||
glutPostRedisplay();
|
||||
glutTimerFunc(REFRESH_DELAY, timerEvent, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void keyboard(unsigned char key, int /*x*/, int /*y*/) {
|
||||
char temp[256];
|
||||
void keyboard(unsigned char key, int /*x*/, int /*y*/)
|
||||
{
|
||||
char temp[256];
|
||||
|
||||
switch (key) {
|
||||
switch (key) {
|
||||
case 27:
|
||||
#if defined(__APPLE__) || defined(MACOSX)
|
||||
exit(EXIT_SUCCESS);
|
||||
exit(EXIT_SUCCESS);
|
||||
#else
|
||||
glutDestroyWindow(glutGetWindow());
|
||||
return;
|
||||
glutDestroyWindow(glutGetWindow());
|
||||
return;
|
||||
#endif
|
||||
break;
|
||||
break;
|
||||
|
||||
case '-':
|
||||
imageScale -= 0.1f;
|
||||
printf("brightness = %4.2f\n", imageScale);
|
||||
break;
|
||||
imageScale -= 0.1f;
|
||||
printf("brightness = %4.2f\n", imageScale);
|
||||
break;
|
||||
|
||||
case '=':
|
||||
imageScale += 0.1f;
|
||||
printf("brightness = %4.2f\n", imageScale);
|
||||
break;
|
||||
imageScale += 0.1f;
|
||||
printf("brightness = %4.2f\n", imageScale);
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
case 'I':
|
||||
g_SobelDisplayMode = SOBELDISPLAY_IMAGE;
|
||||
sprintf(temp, "Function Pointers [CUDA Edge Detection] (%s)",
|
||||
filterMode[g_SobelDisplayMode]);
|
||||
glutSetWindowTitle(temp);
|
||||
break;
|
||||
g_SobelDisplayMode = SOBELDISPLAY_IMAGE;
|
||||
sprintf(temp, "Function Pointers [CUDA Edge Detection] (%s)", filterMode[g_SobelDisplayMode]);
|
||||
glutSetWindowTitle(temp);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
case 'S':
|
||||
g_SobelDisplayMode = SOBELDISPLAY_SOBELSHARED;
|
||||
sprintf(temp, "Function Pointers [CUDA Edge Detection] (%s)",
|
||||
filterMode[g_SobelDisplayMode]);
|
||||
glutSetWindowTitle(temp);
|
||||
break;
|
||||
g_SobelDisplayMode = SOBELDISPLAY_SOBELSHARED;
|
||||
sprintf(temp, "Function Pointers [CUDA Edge Detection] (%s)", filterMode[g_SobelDisplayMode]);
|
||||
glutSetWindowTitle(temp);
|
||||
break;
|
||||
|
||||
case 't':
|
||||
case 'T':
|
||||
g_SobelDisplayMode = SOBELDISPLAY_SOBELTEX;
|
||||
sprintf(temp, "Function Pointers [CUDA Edge Detection] (%s)",
|
||||
filterMode[g_SobelDisplayMode]);
|
||||
glutSetWindowTitle(temp);
|
||||
break;
|
||||
g_SobelDisplayMode = SOBELDISPLAY_SOBELTEX;
|
||||
sprintf(temp, "Function Pointers [CUDA Edge Detection] (%s)", filterMode[g_SobelDisplayMode]);
|
||||
glutSetWindowTitle(temp);
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
case 'B':
|
||||
blockOp = (blockOp + 1) % LAST_BLOCK_FILTER;
|
||||
break;
|
||||
blockOp = (blockOp + 1) % LAST_BLOCK_FILTER;
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
case 'P':
|
||||
pointOp = (pointOp + 1) % LAST_POINT_FILTER;
|
||||
break;
|
||||
pointOp = (pointOp + 1) % LAST_POINT_FILTER;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void reshape(int x, int y) {
|
||||
glViewport(0, 0, x, y);
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glOrtho(0, 1, 0, 1, 0, 1);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
void reshape(int x, int y)
|
||||
{
|
||||
glViewport(0, 0, x, y);
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glOrtho(0, 1, 0, 1, 0, 1);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
}
|
||||
|
||||
void cleanup(void) {
|
||||
cudaGraphicsUnregisterResource(cuda_pbo_resource);
|
||||
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||
glDeleteBuffers(1, &pbo_buffer);
|
||||
glDeleteTextures(1, &texid);
|
||||
deleteTexture();
|
||||
|
||||
sdkDeleteTimer(&timer);
|
||||
}
|
||||
|
||||
void initializeData(char *file) {
|
||||
GLint bsize;
|
||||
unsigned int w, h;
|
||||
size_t file_length = strlen(file);
|
||||
|
||||
if (!strcmp(&file[file_length - 3], "pgm")) {
|
||||
if (sdkLoadPGM<unsigned char>(file, &pixels, &w, &h) != true) {
|
||||
printf("Failed to load PGM image file: %s\n", file);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
g_Bpp = 1;
|
||||
} else if (!strcmp(&file[file_length - 3], "ppm")) {
|
||||
if (sdkLoadPPM4(file, &pixels, &w, &h) != true) {
|
||||
printf("Failed to load PPM image file: %s\n", file);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
g_Bpp = 4;
|
||||
} else {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
imWidth = (int)w;
|
||||
imHeight = (int)h;
|
||||
setupTexture(imWidth, imHeight, pixels, g_Bpp);
|
||||
|
||||
// copy function pointer tables to host side for later use
|
||||
setupFunctionTables();
|
||||
|
||||
memset(pixels, 0x0, g_Bpp * sizeof(Pixel) * imWidth * imHeight);
|
||||
|
||||
if (!g_bQAReadback) {
|
||||
// use OpenGL Path
|
||||
glGenBuffers(1, &pbo_buffer);
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo_buffer);
|
||||
glBufferData(GL_PIXEL_UNPACK_BUFFER,
|
||||
g_Bpp * sizeof(Pixel) * imWidth * imHeight, pixels,
|
||||
GL_STREAM_DRAW);
|
||||
|
||||
glGetBufferParameteriv(GL_PIXEL_UNPACK_BUFFER, GL_BUFFER_SIZE, &bsize);
|
||||
|
||||
if ((GLuint)bsize != (g_Bpp * sizeof(Pixel) * imWidth * imHeight)) {
|
||||
printf("Buffer object (%d) has incorrect size (%d).\n",
|
||||
(unsigned)pbo_buffer, (unsigned)bsize);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
void cleanup(void)
|
||||
{
|
||||
cudaGraphicsUnregisterResource(cuda_pbo_resource);
|
||||
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||
glDeleteBuffers(1, &pbo_buffer);
|
||||
glDeleteTextures(1, &texid);
|
||||
deleteTexture();
|
||||
|
||||
// register this buffer object with CUDA
|
||||
checkCudaErrors(cudaGraphicsGLRegisterBuffer(
|
||||
&cuda_pbo_resource, pbo_buffer, cudaGraphicsMapFlagsWriteDiscard));
|
||||
|
||||
glGenTextures(1, &texid);
|
||||
glBindTexture(GL_TEXTURE_2D, texid);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, ((g_Bpp == 1) ? GL_LUMINANCE : GL_BGRA),
|
||||
imWidth, imHeight, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||
}
|
||||
sdkDeleteTimer(&timer);
|
||||
}
|
||||
|
||||
void loadDefaultImage(char *loc_exec) {
|
||||
printf("Reading image: teapot512.pgm\n");
|
||||
const char *image_filename = "teapot512.pgm";
|
||||
char *image_path = sdkFindFilePath(image_filename, loc_exec);
|
||||
void initializeData(char *file)
|
||||
{
|
||||
GLint bsize;
|
||||
unsigned int w, h;
|
||||
size_t file_length = strlen(file);
|
||||
|
||||
if (image_path == NULL) {
|
||||
printf("Failed to read image file: <%s>\n", image_filename);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (!strcmp(&file[file_length - 3], "pgm")) {
|
||||
if (sdkLoadPGM<unsigned char>(file, &pixels, &w, &h) != true) {
|
||||
printf("Failed to load PGM image file: %s\n", file);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
initializeData(image_path);
|
||||
free(image_path);
|
||||
g_Bpp = 1;
|
||||
}
|
||||
else if (!strcmp(&file[file_length - 3], "ppm")) {
|
||||
if (sdkLoadPPM4(file, &pixels, &w, &h) != true) {
|
||||
printf("Failed to load PPM image file: %s\n", file);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
g_Bpp = 4;
|
||||
}
|
||||
else {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
imWidth = (int)w;
|
||||
imHeight = (int)h;
|
||||
setupTexture(imWidth, imHeight, pixels, g_Bpp);
|
||||
|
||||
// copy function pointer tables to host side for later use
|
||||
setupFunctionTables();
|
||||
|
||||
memset(pixels, 0x0, g_Bpp * sizeof(Pixel) * imWidth * imHeight);
|
||||
|
||||
if (!g_bQAReadback) {
|
||||
// use OpenGL Path
|
||||
glGenBuffers(1, &pbo_buffer);
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo_buffer);
|
||||
glBufferData(GL_PIXEL_UNPACK_BUFFER, g_Bpp * sizeof(Pixel) * imWidth * imHeight, pixels, GL_STREAM_DRAW);
|
||||
|
||||
glGetBufferParameteriv(GL_PIXEL_UNPACK_BUFFER, GL_BUFFER_SIZE, &bsize);
|
||||
|
||||
if ((GLuint)bsize != (g_Bpp * sizeof(Pixel) * imWidth * imHeight)) {
|
||||
printf("Buffer object (%d) has incorrect size (%d).\n", (unsigned)pbo_buffer, (unsigned)bsize);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||
|
||||
// register this buffer object with CUDA
|
||||
checkCudaErrors(cudaGraphicsGLRegisterBuffer(&cuda_pbo_resource, pbo_buffer, cudaGraphicsMapFlagsWriteDiscard));
|
||||
|
||||
glGenTextures(1, &texid);
|
||||
glBindTexture(GL_TEXTURE_2D, texid);
|
||||
glTexImage2D(GL_TEXTURE_2D,
|
||||
0,
|
||||
((g_Bpp == 1) ? GL_LUMINANCE : GL_BGRA),
|
||||
imWidth,
|
||||
imHeight,
|
||||
0,
|
||||
GL_LUMINANCE,
|
||||
GL_UNSIGNED_BYTE,
|
||||
NULL);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void initGL(int *argc, char **argv) {
|
||||
glutInit(argc, argv);
|
||||
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
|
||||
glutInitWindowSize(wWidth, wHeight);
|
||||
glutCreateWindow("Function Pointers [CUDA Edge Detection]n");
|
||||
void loadDefaultImage(char *loc_exec)
|
||||
{
|
||||
printf("Reading image: teapot512.pgm\n");
|
||||
const char *image_filename = "teapot512.pgm";
|
||||
char *image_path = sdkFindFilePath(image_filename, loc_exec);
|
||||
|
||||
if (!isGLVersionSupported(1, 5) ||
|
||||
!areGLExtensionsSupported(
|
||||
"GL_ARB_vertex_buffer_object GL_ARB_pixel_buffer_object")) {
|
||||
fprintf(stderr, "Error: failed to get minimal extensions for demo\n");
|
||||
fprintf(stderr, "This sample requires:\n");
|
||||
fprintf(stderr, " OpenGL version 1.5\n");
|
||||
fprintf(stderr, " GL_ARB_vertex_buffer_object\n");
|
||||
fprintf(stderr, " GL_ARB_pixel_buffer_object\n");
|
||||
if (image_path == NULL) {
|
||||
printf("Failed to read image file: <%s>\n", image_filename);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
exit(EXIT_WAIVED);
|
||||
}
|
||||
initializeData(image_path);
|
||||
free(image_path);
|
||||
}
|
||||
|
||||
void runAutoTest(int argc, char *argv[]) {
|
||||
printf("[%s] (automated testing w/ readback)\n", sSDKsample);
|
||||
int devID = findCudaDevice(argc, (const char **)argv);
|
||||
void initGL(int *argc, char **argv)
|
||||
{
|
||||
glutInit(argc, argv);
|
||||
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
|
||||
glutInitWindowSize(wWidth, wHeight);
|
||||
glutCreateWindow("Function Pointers [CUDA Edge Detection]n");
|
||||
|
||||
loadDefaultImage(argv[0]);
|
||||
if (!isGLVersionSupported(1, 5)
|
||||
|| !areGLExtensionsSupported("GL_ARB_vertex_buffer_object GL_ARB_pixel_buffer_object")) {
|
||||
fprintf(stderr, "Error: failed to get minimal extensions for demo\n");
|
||||
fprintf(stderr, "This sample requires:\n");
|
||||
fprintf(stderr, " OpenGL version 1.5\n");
|
||||
fprintf(stderr, " GL_ARB_vertex_buffer_object\n");
|
||||
fprintf(stderr, " GL_ARB_pixel_buffer_object\n");
|
||||
|
||||
Pixel *d_result;
|
||||
checkCudaErrors(
|
||||
cudaMalloc((void **)&d_result, imWidth * imHeight * sizeof(Pixel)));
|
||||
|
||||
char *ref_file = NULL;
|
||||
char dump_file[256];
|
||||
|
||||
int mode = 0;
|
||||
mode = getCmdLineArgumentInt(argc, (const char **)argv, "mode");
|
||||
getCmdLineArgumentString(argc, (const char **)argv, "file", &ref_file);
|
||||
|
||||
switch (mode) {
|
||||
case 0:
|
||||
g_SobelDisplayMode = SOBELDISPLAY_IMAGE;
|
||||
sprintf(dump_file, "teapot512_orig.pgm");
|
||||
break;
|
||||
|
||||
case 1:
|
||||
g_SobelDisplayMode = SOBELDISPLAY_SOBELTEX;
|
||||
sprintf(dump_file, "teapot512_tex.pgm");
|
||||
break;
|
||||
|
||||
case 2:
|
||||
g_SobelDisplayMode = SOBELDISPLAY_SOBELSHARED;
|
||||
sprintf(dump_file, "teapot512_shared.pgm");
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("Invalid Filter Mode File\n");
|
||||
exit(EXIT_FAILURE);
|
||||
break;
|
||||
}
|
||||
|
||||
printf("AutoTest: %s <%s>\n", sSDKsample, filterMode[g_SobelDisplayMode]);
|
||||
sobelFilter(d_result, imWidth, imHeight, g_SobelDisplayMode, imageScale,
|
||||
blockOp, pointOp);
|
||||
checkCudaErrors(cudaDeviceSynchronize());
|
||||
|
||||
unsigned char *h_result =
|
||||
(unsigned char *)malloc(imWidth * imHeight * sizeof(Pixel));
|
||||
checkCudaErrors(cudaMemcpy(h_result, d_result,
|
||||
imWidth * imHeight * sizeof(Pixel),
|
||||
cudaMemcpyDeviceToHost));
|
||||
sdkSavePGM(dump_file, h_result, imWidth, imHeight);
|
||||
|
||||
if (!sdkComparePGM(dump_file, sdkFindFilePath(ref_file, argv[0]),
|
||||
MAX_EPSILON_ERROR, 0.15f, false)) {
|
||||
g_TotalErrors++;
|
||||
}
|
||||
|
||||
checkCudaErrors(cudaFree(d_result));
|
||||
free(h_result);
|
||||
|
||||
if (g_TotalErrors != 0) {
|
||||
printf("Test failed!\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
printf("Test passed!\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
exit(EXIT_WAIVED);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
pArgc = &argc;
|
||||
pArgv = argv;
|
||||
|
||||
#if defined(__linux__)
|
||||
setenv("DISPLAY", ":0", 0);
|
||||
#endif
|
||||
|
||||
printf("%s Starting...\n\n", argv[0]);
|
||||
|
||||
if (checkCmdLineFlag(argc, (const char **)argv, "help")) {
|
||||
printf("\nUsage: FunctionPointers (SobelFilter) <options>\n");
|
||||
printf("\t\t-mode=n (0=original, 1=texture, 2=smem + texture)\n");
|
||||
printf("\t\t-file=ref_orig.pgm (ref_tex.pgm, ref_shared.pgm)\n\n");
|
||||
|
||||
exit(EXIT_WAIVED);
|
||||
}
|
||||
|
||||
if (checkCmdLineFlag(argc, (const char **)argv, "file")) {
|
||||
g_bQAReadback = true;
|
||||
runAutoTest(argc, argv);
|
||||
}
|
||||
|
||||
// use command-line specified CUDA device, otherwise use device with highest
|
||||
// Gflops/s
|
||||
if (checkCmdLineFlag(argc, (const char **)argv, "device")) {
|
||||
printf(
|
||||
" This SDK does not explicitly support -device=n when running with "
|
||||
"OpenGL.\n");
|
||||
printf(
|
||||
" When specifying -device=n (n=0,1,2,....) the sample must not use "
|
||||
"OpenGL.\n");
|
||||
printf(" See details below to run without OpenGL:\n\n");
|
||||
printf(" > %s -device=n\n\n", argv[0]);
|
||||
printf("exiting...\n");
|
||||
|
||||
exit(EXIT_WAIVED);
|
||||
}
|
||||
|
||||
if (!g_bQAReadback) {
|
||||
// First initialize OpenGL context, so we can properly set the GL for CUDA.
|
||||
// This is necessary in order to achieve optimal performance with
|
||||
// OpenGL/CUDA interop.
|
||||
initGL(&argc, argv);
|
||||
|
||||
int dev = findCudaDevice(argc, (const char **)argv);
|
||||
|
||||
sdkCreateTimer(&timer);
|
||||
sdkResetTimer(&timer);
|
||||
|
||||
glutDisplayFunc(display);
|
||||
glutKeyboardFunc(keyboard);
|
||||
glutReshapeFunc(reshape);
|
||||
void runAutoTest(int argc, char *argv[])
|
||||
{
|
||||
printf("[%s] (automated testing w/ readback)\n", sSDKsample);
|
||||
int devID = findCudaDevice(argc, (const char **)argv);
|
||||
|
||||
loadDefaultImage(argv[0]);
|
||||
|
||||
// If code is not printing the USage, then we execute this path.
|
||||
printf("I: display Image (no filtering)\n");
|
||||
printf("T: display Sobel Edge Detection (Using Texture)\n");
|
||||
printf("S: display Sobel Edge Detection (Using SMEM+Texture)\n");
|
||||
printf("Use the '-' and '=' keys to change the brightness.\n");
|
||||
printf("b: switch block filter operation (Mean/Sobel)\n");
|
||||
printf("p: switch point filter operation (Threshold ON/OFF)\n");
|
||||
fflush(stdout);
|
||||
Pixel *d_result;
|
||||
checkCudaErrors(cudaMalloc((void **)&d_result, imWidth * imHeight * sizeof(Pixel)));
|
||||
|
||||
#if defined(__APPLE__) || defined(MACOSX)
|
||||
atexit(cleanup);
|
||||
#else
|
||||
glutCloseFunc(cleanup);
|
||||
char *ref_file = NULL;
|
||||
char dump_file[256];
|
||||
|
||||
int mode = 0;
|
||||
mode = getCmdLineArgumentInt(argc, (const char **)argv, "mode");
|
||||
getCmdLineArgumentString(argc, (const char **)argv, "file", &ref_file);
|
||||
|
||||
switch (mode) {
|
||||
case 0:
|
||||
g_SobelDisplayMode = SOBELDISPLAY_IMAGE;
|
||||
sprintf(dump_file, "teapot512_orig.pgm");
|
||||
break;
|
||||
|
||||
case 1:
|
||||
g_SobelDisplayMode = SOBELDISPLAY_SOBELTEX;
|
||||
sprintf(dump_file, "teapot512_tex.pgm");
|
||||
break;
|
||||
|
||||
case 2:
|
||||
g_SobelDisplayMode = SOBELDISPLAY_SOBELSHARED;
|
||||
sprintf(dump_file, "teapot512_shared.pgm");
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("Invalid Filter Mode File\n");
|
||||
exit(EXIT_FAILURE);
|
||||
break;
|
||||
}
|
||||
|
||||
printf("AutoTest: %s <%s>\n", sSDKsample, filterMode[g_SobelDisplayMode]);
|
||||
sobelFilter(d_result, imWidth, imHeight, g_SobelDisplayMode, imageScale, blockOp, pointOp);
|
||||
checkCudaErrors(cudaDeviceSynchronize());
|
||||
|
||||
unsigned char *h_result = (unsigned char *)malloc(imWidth * imHeight * sizeof(Pixel));
|
||||
checkCudaErrors(cudaMemcpy(h_result, d_result, imWidth * imHeight * sizeof(Pixel), cudaMemcpyDeviceToHost));
|
||||
sdkSavePGM(dump_file, h_result, imWidth, imHeight);
|
||||
|
||||
if (!sdkComparePGM(dump_file, sdkFindFilePath(ref_file, argv[0]), MAX_EPSILON_ERROR, 0.15f, false)) {
|
||||
g_TotalErrors++;
|
||||
}
|
||||
|
||||
checkCudaErrors(cudaFree(d_result));
|
||||
free(h_result);
|
||||
|
||||
if (g_TotalErrors != 0) {
|
||||
printf("Test failed!\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
printf("Test passed!\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
pArgc = &argc;
|
||||
pArgv = argv;
|
||||
|
||||
#if defined(__linux__)
|
||||
setenv("DISPLAY", ":0", 0);
|
||||
#endif
|
||||
|
||||
glutTimerFunc(REFRESH_DELAY, timerEvent, 0);
|
||||
glutMainLoop();
|
||||
}
|
||||
printf("%s Starting...\n\n", argv[0]);
|
||||
|
||||
if (checkCmdLineFlag(argc, (const char **)argv, "help")) {
|
||||
printf("\nUsage: FunctionPointers (SobelFilter) <options>\n");
|
||||
printf("\t\t-mode=n (0=original, 1=texture, 2=smem + texture)\n");
|
||||
printf("\t\t-file=ref_orig.pgm (ref_tex.pgm, ref_shared.pgm)\n\n");
|
||||
|
||||
exit(EXIT_WAIVED);
|
||||
}
|
||||
|
||||
if (checkCmdLineFlag(argc, (const char **)argv, "file")) {
|
||||
g_bQAReadback = true;
|
||||
runAutoTest(argc, argv);
|
||||
}
|
||||
|
||||
// use command-line specified CUDA device, otherwise use device with highest
|
||||
// Gflops/s
|
||||
if (checkCmdLineFlag(argc, (const char **)argv, "device")) {
|
||||
printf(" This SDK does not explicitly support -device=n when running with "
|
||||
"OpenGL.\n");
|
||||
printf(" When specifying -device=n (n=0,1,2,....) the sample must not use "
|
||||
"OpenGL.\n");
|
||||
printf(" See details below to run without OpenGL:\n\n");
|
||||
printf(" > %s -device=n\n\n", argv[0]);
|
||||
printf("exiting...\n");
|
||||
|
||||
exit(EXIT_WAIVED);
|
||||
}
|
||||
|
||||
if (!g_bQAReadback) {
|
||||
// First initialize OpenGL context, so we can properly set the GL for CUDA.
|
||||
// This is necessary in order to achieve optimal performance with
|
||||
// OpenGL/CUDA interop.
|
||||
initGL(&argc, argv);
|
||||
|
||||
int dev = findCudaDevice(argc, (const char **)argv);
|
||||
|
||||
sdkCreateTimer(&timer);
|
||||
sdkResetTimer(&timer);
|
||||
|
||||
glutDisplayFunc(display);
|
||||
glutKeyboardFunc(keyboard);
|
||||
glutReshapeFunc(reshape);
|
||||
|
||||
loadDefaultImage(argv[0]);
|
||||
|
||||
// If code is not printing the USage, then we execute this path.
|
||||
printf("I: display Image (no filtering)\n");
|
||||
printf("T: display Sobel Edge Detection (Using Texture)\n");
|
||||
printf("S: display Sobel Edge Detection (Using SMEM+Texture)\n");
|
||||
printf("Use the '-' and '=' keys to change the brightness.\n");
|
||||
printf("b: switch block filter operation (Mean/Sobel)\n");
|
||||
printf("p: switch point filter operation (Threshold ON/OFF)\n");
|
||||
fflush(stdout);
|
||||
|
||||
#if defined(__APPLE__) || defined(MACOSX)
|
||||
atexit(cleanup);
|
||||
#else
|
||||
glutCloseFunc(cleanup);
|
||||
#endif
|
||||
|
||||
glutTimerFunc(REFRESH_DELAY, timerEvent, 0);
|
||||
glutMainLoop();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,9 +25,9 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <cooperative_groups.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <cooperative_groups.h>
|
||||
|
||||
namespace cg = cooperative_groups;
|
||||
|
||||
@@ -36,9 +36,9 @@ namespace cg = cooperative_groups;
|
||||
#include "FunctionPointers_kernels.h"
|
||||
|
||||
// Texture object for reading image
|
||||
cudaTextureObject_t tex;
|
||||
cudaTextureObject_t tex;
|
||||
extern __shared__ unsigned char LocalBlock[];
|
||||
static cudaArray *array = NULL;
|
||||
static cudaArray *array = NULL;
|
||||
|
||||
#define RADIUS 1
|
||||
|
||||
@@ -47,7 +47,7 @@ static cudaArray *array = NULL;
|
||||
#define THRESHOLD 150.0f
|
||||
|
||||
#ifdef FIXED_BLOCKWIDTH
|
||||
#define BlockWidth 80
|
||||
#define BlockWidth 80
|
||||
#define SharedPitch 384
|
||||
#endif
|
||||
|
||||
@@ -55,59 +55,73 @@ static cudaArray *array = NULL;
|
||||
//__device__ unsigned char (*pointFunction)(unsigned char, float ) = NULL;
|
||||
// or by using typedef's like below:
|
||||
|
||||
typedef unsigned char (*blockFunction_t)(unsigned char, unsigned char,
|
||||
unsigned char, unsigned char,
|
||||
unsigned char, unsigned char,
|
||||
unsigned char, unsigned char,
|
||||
unsigned char, float);
|
||||
typedef unsigned char (*blockFunction_t)(unsigned char,
|
||||
unsigned char,
|
||||
unsigned char,
|
||||
unsigned char,
|
||||
unsigned char,
|
||||
unsigned char,
|
||||
unsigned char,
|
||||
unsigned char,
|
||||
unsigned char,
|
||||
float);
|
||||
|
||||
typedef unsigned char (*pointFunction_t)(unsigned char, float);
|
||||
|
||||
__device__ blockFunction_t blockFunction;
|
||||
|
||||
__device__ unsigned char ComputeSobel(unsigned char ul, // upper left
|
||||
unsigned char um, // upper middle
|
||||
unsigned char ur, // upper right
|
||||
unsigned char ml, // middle left
|
||||
unsigned char mm, // middle (unused)
|
||||
unsigned char mr, // middle right
|
||||
unsigned char ll, // lower left
|
||||
unsigned char lm, // lower middle
|
||||
unsigned char lr, // lower right
|
||||
float fScale) {
|
||||
short Horz = ur + 2 * mr + lr - ul - 2 * ml - ll;
|
||||
short Vert = ul + 2 * um + ur - ll - 2 * lm - lr;
|
||||
short Sum = (short)(fScale * (abs((int)Horz) + abs((int)Vert)));
|
||||
return (unsigned char)((Sum < 0) ? 0 : ((Sum > 255) ? 255 : Sum));
|
||||
__device__ unsigned char ComputeSobel(unsigned char ul, // upper left
|
||||
unsigned char um, // upper middle
|
||||
unsigned char ur, // upper right
|
||||
unsigned char ml, // middle left
|
||||
unsigned char mm, // middle (unused)
|
||||
unsigned char mr, // middle right
|
||||
unsigned char ll, // lower left
|
||||
unsigned char lm, // lower middle
|
||||
unsigned char lr, // lower right
|
||||
float fScale)
|
||||
{
|
||||
short Horz = ur + 2 * mr + lr - ul - 2 * ml - ll;
|
||||
short Vert = ul + 2 * um + ur - ll - 2 * lm - lr;
|
||||
short Sum = (short)(fScale * (abs((int)Horz) + abs((int)Vert)));
|
||||
return (unsigned char)((Sum < 0) ? 0 : ((Sum > 255) ? 255 : Sum));
|
||||
}
|
||||
|
||||
// define a function pointer and initialize to NULL
|
||||
__device__ unsigned char (*varFunction)(unsigned char, unsigned char,
|
||||
unsigned char, unsigned char,
|
||||
unsigned char, unsigned char,
|
||||
unsigned char, unsigned char,
|
||||
unsigned char, float x) = NULL;
|
||||
__device__ unsigned char (*varFunction)(unsigned char,
|
||||
unsigned char,
|
||||
unsigned char,
|
||||
unsigned char,
|
||||
unsigned char,
|
||||
unsigned char,
|
||||
unsigned char,
|
||||
unsigned char,
|
||||
unsigned char,
|
||||
float x) = NULL;
|
||||
|
||||
__device__ unsigned char ComputeBox(unsigned char ul, // upper left
|
||||
unsigned char um, // upper middle
|
||||
unsigned char ur, // upper right
|
||||
unsigned char ml, // middle left
|
||||
unsigned char mm, // middle...middle
|
||||
unsigned char mr, // middle right
|
||||
unsigned char ll, // lower left
|
||||
unsigned char lm, // lower middle
|
||||
unsigned char lr, // lower right
|
||||
float fscale) {
|
||||
short Sum = (short)(ul + um + ur + ml + mm + mr + ll + lm + lr) / 9;
|
||||
Sum *= fscale;
|
||||
return (unsigned char)((Sum < 0) ? 0 : ((Sum > 255) ? 255 : Sum));
|
||||
__device__ unsigned char ComputeBox(unsigned char ul, // upper left
|
||||
unsigned char um, // upper middle
|
||||
unsigned char ur, // upper right
|
||||
unsigned char ml, // middle left
|
||||
unsigned char mm, // middle...middle
|
||||
unsigned char mr, // middle right
|
||||
unsigned char ll, // lower left
|
||||
unsigned char lm, // lower middle
|
||||
unsigned char lr, // lower right
|
||||
float fscale)
|
||||
{
|
||||
short Sum = (short)(ul + um + ur + ml + mm + mr + ll + lm + lr) / 9;
|
||||
Sum *= fscale;
|
||||
return (unsigned char)((Sum < 0) ? 0 : ((Sum > 255) ? 255 : Sum));
|
||||
}
|
||||
__device__ unsigned char Threshold(unsigned char in, float thresh) {
|
||||
if (in > thresh) {
|
||||
return 0xFF;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
__device__ unsigned char Threshold(unsigned char in, float thresh)
|
||||
{
|
||||
if (in > thresh) {
|
||||
return 0xFF;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Declare function tables, one for the point function chosen, one for the
|
||||
@@ -119,8 +133,8 @@ __device__ pointFunction_t pointFunction_table[LAST_POINT_FILTER];
|
||||
// Declare device side function pointers. We retrieve them later with
|
||||
// cudaMemcpyFromSymbol to set our function tables above in some
|
||||
// particular order specified at runtime.
|
||||
__device__ blockFunction_t pComputeSobel = ComputeSobel;
|
||||
__device__ blockFunction_t pComputeBox = ComputeBox;
|
||||
__device__ blockFunction_t pComputeSobel = ComputeSobel;
|
||||
__device__ blockFunction_t pComputeBox = ComputeBox;
|
||||
__device__ pointFunction_t pComputeThreshold = Threshold;
|
||||
|
||||
// Allocate host side tables to mirror the device side, and later, we
|
||||
@@ -138,222 +152,210 @@ pointFunction_t h_pointFunction_table[2];
|
||||
// Following the block operation, a per-pixel operation,
|
||||
// pointed to by pPointFunction is performed before the final
|
||||
// pixel is produced.
|
||||
__global__ void SobelShared(uchar4 *pSobelOriginal, unsigned short SobelPitch,
|
||||
__global__ void SobelShared(uchar4 *pSobelOriginal,
|
||||
unsigned short SobelPitch,
|
||||
#ifndef FIXED_BLOCKWIDTH
|
||||
short BlockWidth, short SharedPitch,
|
||||
short BlockWidth,
|
||||
short SharedPitch,
|
||||
#endif
|
||||
short w, short h, float fScale, int blockOperation,
|
||||
pointFunction_t pPointFunction,
|
||||
cudaTextureObject_t tex) {
|
||||
// Handle to thread block group
|
||||
cg::thread_block cta = cg::this_thread_block();
|
||||
short u = 4 * blockIdx.x * BlockWidth;
|
||||
short v = blockIdx.y * blockDim.y + threadIdx.y;
|
||||
short ib;
|
||||
short w,
|
||||
short h,
|
||||
float fScale,
|
||||
int blockOperation,
|
||||
pointFunction_t pPointFunction,
|
||||
cudaTextureObject_t tex)
|
||||
{
|
||||
// Handle to thread block group
|
||||
cg::thread_block cta = cg::this_thread_block();
|
||||
short u = 4 * blockIdx.x * BlockWidth;
|
||||
short v = blockIdx.y * blockDim.y + threadIdx.y;
|
||||
short ib;
|
||||
|
||||
int SharedIdx = threadIdx.y * SharedPitch;
|
||||
|
||||
for (ib = threadIdx.x; ib < BlockWidth + 2 * RADIUS; ib += blockDim.x) {
|
||||
LocalBlock[SharedIdx + 4 * ib + 0] = tex2D<unsigned char>(
|
||||
tex, (float)(u + 4 * ib - RADIUS + 0), (float)(v - RADIUS));
|
||||
LocalBlock[SharedIdx + 4 * ib + 1] = tex2D<unsigned char>(
|
||||
tex, (float)(u + 4 * ib - RADIUS + 1), (float)(v - RADIUS));
|
||||
LocalBlock[SharedIdx + 4 * ib + 2] = tex2D<unsigned char>(
|
||||
tex, (float)(u + 4 * ib - RADIUS + 2), (float)(v - RADIUS));
|
||||
LocalBlock[SharedIdx + 4 * ib + 3] = tex2D<unsigned char>(
|
||||
tex, (float)(u + 4 * ib - RADIUS + 3), (float)(v - RADIUS));
|
||||
}
|
||||
|
||||
if (threadIdx.y < RADIUS * 2) {
|
||||
//
|
||||
// copy trailing RADIUS*2 rows of pixels into shared
|
||||
//
|
||||
SharedIdx = (blockDim.y + threadIdx.y) * SharedPitch;
|
||||
int SharedIdx = threadIdx.y * SharedPitch;
|
||||
|
||||
for (ib = threadIdx.x; ib < BlockWidth + 2 * RADIUS; ib += blockDim.x) {
|
||||
LocalBlock[SharedIdx + 4 * ib + 0] =
|
||||
tex2D<unsigned char>(tex, (float)(u + 4 * ib - RADIUS + 0),
|
||||
(float)(v + blockDim.y - RADIUS));
|
||||
LocalBlock[SharedIdx + 4 * ib + 1] =
|
||||
tex2D<unsigned char>(tex, (float)(u + 4 * ib - RADIUS + 1),
|
||||
(float)(v + blockDim.y - RADIUS));
|
||||
LocalBlock[SharedIdx + 4 * ib + 2] =
|
||||
tex2D<unsigned char>(tex, (float)(u + 4 * ib - RADIUS + 2),
|
||||
(float)(v + blockDim.y - RADIUS));
|
||||
LocalBlock[SharedIdx + 4 * ib + 3] =
|
||||
tex2D<unsigned char>(tex, (float)(u + 4 * ib - RADIUS + 3),
|
||||
(float)(v + blockDim.y - RADIUS));
|
||||
}
|
||||
}
|
||||
|
||||
cg::sync(cta);
|
||||
|
||||
u >>= 2; // index as uchar4 from here
|
||||
uchar4 *pSobel = (uchar4 *)(((char *)pSobelOriginal) + v * SobelPitch);
|
||||
SharedIdx = threadIdx.y * SharedPitch;
|
||||
|
||||
blockFunction = blockFunction_table[blockOperation];
|
||||
|
||||
for (ib = threadIdx.x; ib < BlockWidth; ib += blockDim.x) {
|
||||
uchar4 out;
|
||||
|
||||
unsigned char pix00 = LocalBlock[SharedIdx + 4 * ib + 0 * SharedPitch + 0];
|
||||
unsigned char pix01 = LocalBlock[SharedIdx + 4 * ib + 0 * SharedPitch + 1];
|
||||
unsigned char pix02 = LocalBlock[SharedIdx + 4 * ib + 0 * SharedPitch + 2];
|
||||
unsigned char pix10 = LocalBlock[SharedIdx + 4 * ib + 1 * SharedPitch + 0];
|
||||
unsigned char pix11 = LocalBlock[SharedIdx + 4 * ib + 1 * SharedPitch + 1];
|
||||
unsigned char pix12 = LocalBlock[SharedIdx + 4 * ib + 1 * SharedPitch + 2];
|
||||
unsigned char pix20 = LocalBlock[SharedIdx + 4 * ib + 2 * SharedPitch + 0];
|
||||
unsigned char pix21 = LocalBlock[SharedIdx + 4 * ib + 2 * SharedPitch + 1];
|
||||
unsigned char pix22 = LocalBlock[SharedIdx + 4 * ib + 2 * SharedPitch + 2];
|
||||
|
||||
out.x = (*blockFunction)(pix00, pix01, pix02, pix10, pix11, pix12, pix20,
|
||||
pix21, pix22, fScale);
|
||||
|
||||
pix00 = LocalBlock[SharedIdx + 4 * ib + 0 * SharedPitch + 3];
|
||||
pix10 = LocalBlock[SharedIdx + 4 * ib + 1 * SharedPitch + 3];
|
||||
pix20 = LocalBlock[SharedIdx + 4 * ib + 2 * SharedPitch + 3];
|
||||
out.y = (*blockFunction)(pix01, pix02, pix00, pix11, pix12, pix10, pix21,
|
||||
pix22, pix20, fScale);
|
||||
|
||||
pix01 = LocalBlock[SharedIdx + 4 * ib + 0 * SharedPitch + 4];
|
||||
pix11 = LocalBlock[SharedIdx + 4 * ib + 1 * SharedPitch + 4];
|
||||
pix21 = LocalBlock[SharedIdx + 4 * ib + 2 * SharedPitch + 4];
|
||||
out.z = (*blockFunction)(pix02, pix00, pix01, pix12, pix10, pix11, pix22,
|
||||
pix20, pix21, fScale);
|
||||
|
||||
pix02 = LocalBlock[SharedIdx + 4 * ib + 0 * SharedPitch + 5];
|
||||
pix12 = LocalBlock[SharedIdx + 4 * ib + 1 * SharedPitch + 5];
|
||||
pix22 = LocalBlock[SharedIdx + 4 * ib + 2 * SharedPitch + 5];
|
||||
out.w = (*blockFunction)(pix00, pix01, pix02, pix10, pix11, pix12, pix20,
|
||||
pix21, pix22, fScale);
|
||||
|
||||
if (pPointFunction != NULL) {
|
||||
out.x = (*pPointFunction)(out.x, THRESHOLD);
|
||||
out.y = (*pPointFunction)(out.y, THRESHOLD);
|
||||
out.z = (*pPointFunction)(out.z, THRESHOLD);
|
||||
out.w = (*pPointFunction)(out.w, THRESHOLD);
|
||||
LocalBlock[SharedIdx + 4 * ib + 0] =
|
||||
tex2D<unsigned char>(tex, (float)(u + 4 * ib - RADIUS + 0), (float)(v - RADIUS));
|
||||
LocalBlock[SharedIdx + 4 * ib + 1] =
|
||||
tex2D<unsigned char>(tex, (float)(u + 4 * ib - RADIUS + 1), (float)(v - RADIUS));
|
||||
LocalBlock[SharedIdx + 4 * ib + 2] =
|
||||
tex2D<unsigned char>(tex, (float)(u + 4 * ib - RADIUS + 2), (float)(v - RADIUS));
|
||||
LocalBlock[SharedIdx + 4 * ib + 3] =
|
||||
tex2D<unsigned char>(tex, (float)(u + 4 * ib - RADIUS + 3), (float)(v - RADIUS));
|
||||
}
|
||||
|
||||
if (u + ib < w / 4 && v < h) {
|
||||
pSobel[u + ib] = out;
|
||||
}
|
||||
}
|
||||
if (threadIdx.y < RADIUS * 2) {
|
||||
//
|
||||
// copy trailing RADIUS*2 rows of pixels into shared
|
||||
//
|
||||
SharedIdx = (blockDim.y + threadIdx.y) * SharedPitch;
|
||||
|
||||
cg::sync(cta);
|
||||
for (ib = threadIdx.x; ib < BlockWidth + 2 * RADIUS; ib += blockDim.x) {
|
||||
LocalBlock[SharedIdx + 4 * ib + 0] =
|
||||
tex2D<unsigned char>(tex, (float)(u + 4 * ib - RADIUS + 0), (float)(v + blockDim.y - RADIUS));
|
||||
LocalBlock[SharedIdx + 4 * ib + 1] =
|
||||
tex2D<unsigned char>(tex, (float)(u + 4 * ib - RADIUS + 1), (float)(v + blockDim.y - RADIUS));
|
||||
LocalBlock[SharedIdx + 4 * ib + 2] =
|
||||
tex2D<unsigned char>(tex, (float)(u + 4 * ib - RADIUS + 2), (float)(v + blockDim.y - RADIUS));
|
||||
LocalBlock[SharedIdx + 4 * ib + 3] =
|
||||
tex2D<unsigned char>(tex, (float)(u + 4 * ib - RADIUS + 3), (float)(v + blockDim.y - RADIUS));
|
||||
}
|
||||
}
|
||||
|
||||
cg::sync(cta);
|
||||
|
||||
u >>= 2; // index as uchar4 from here
|
||||
uchar4 *pSobel = (uchar4 *)(((char *)pSobelOriginal) + v * SobelPitch);
|
||||
SharedIdx = threadIdx.y * SharedPitch;
|
||||
|
||||
blockFunction = blockFunction_table[blockOperation];
|
||||
|
||||
for (ib = threadIdx.x; ib < BlockWidth; ib += blockDim.x) {
|
||||
uchar4 out;
|
||||
|
||||
unsigned char pix00 = LocalBlock[SharedIdx + 4 * ib + 0 * SharedPitch + 0];
|
||||
unsigned char pix01 = LocalBlock[SharedIdx + 4 * ib + 0 * SharedPitch + 1];
|
||||
unsigned char pix02 = LocalBlock[SharedIdx + 4 * ib + 0 * SharedPitch + 2];
|
||||
unsigned char pix10 = LocalBlock[SharedIdx + 4 * ib + 1 * SharedPitch + 0];
|
||||
unsigned char pix11 = LocalBlock[SharedIdx + 4 * ib + 1 * SharedPitch + 1];
|
||||
unsigned char pix12 = LocalBlock[SharedIdx + 4 * ib + 1 * SharedPitch + 2];
|
||||
unsigned char pix20 = LocalBlock[SharedIdx + 4 * ib + 2 * SharedPitch + 0];
|
||||
unsigned char pix21 = LocalBlock[SharedIdx + 4 * ib + 2 * SharedPitch + 1];
|
||||
unsigned char pix22 = LocalBlock[SharedIdx + 4 * ib + 2 * SharedPitch + 2];
|
||||
|
||||
out.x = (*blockFunction)(pix00, pix01, pix02, pix10, pix11, pix12, pix20, pix21, pix22, fScale);
|
||||
|
||||
pix00 = LocalBlock[SharedIdx + 4 * ib + 0 * SharedPitch + 3];
|
||||
pix10 = LocalBlock[SharedIdx + 4 * ib + 1 * SharedPitch + 3];
|
||||
pix20 = LocalBlock[SharedIdx + 4 * ib + 2 * SharedPitch + 3];
|
||||
out.y = (*blockFunction)(pix01, pix02, pix00, pix11, pix12, pix10, pix21, pix22, pix20, fScale);
|
||||
|
||||
pix01 = LocalBlock[SharedIdx + 4 * ib + 0 * SharedPitch + 4];
|
||||
pix11 = LocalBlock[SharedIdx + 4 * ib + 1 * SharedPitch + 4];
|
||||
pix21 = LocalBlock[SharedIdx + 4 * ib + 2 * SharedPitch + 4];
|
||||
out.z = (*blockFunction)(pix02, pix00, pix01, pix12, pix10, pix11, pix22, pix20, pix21, fScale);
|
||||
|
||||
pix02 = LocalBlock[SharedIdx + 4 * ib + 0 * SharedPitch + 5];
|
||||
pix12 = LocalBlock[SharedIdx + 4 * ib + 1 * SharedPitch + 5];
|
||||
pix22 = LocalBlock[SharedIdx + 4 * ib + 2 * SharedPitch + 5];
|
||||
out.w = (*blockFunction)(pix00, pix01, pix02, pix10, pix11, pix12, pix20, pix21, pix22, fScale);
|
||||
|
||||
if (pPointFunction != NULL) {
|
||||
out.x = (*pPointFunction)(out.x, THRESHOLD);
|
||||
out.y = (*pPointFunction)(out.y, THRESHOLD);
|
||||
out.z = (*pPointFunction)(out.z, THRESHOLD);
|
||||
out.w = (*pPointFunction)(out.w, THRESHOLD);
|
||||
}
|
||||
|
||||
if (u + ib < w / 4 && v < h) {
|
||||
pSobel[u + ib] = out;
|
||||
}
|
||||
}
|
||||
|
||||
cg::sync(cta);
|
||||
}
|
||||
|
||||
__global__ void SobelCopyImage(Pixel *pSobelOriginal, unsigned int Pitch, int w,
|
||||
int h, float fscale, cudaTextureObject_t tex) {
|
||||
unsigned char *pSobel =
|
||||
(unsigned char *)(((char *)pSobelOriginal) + blockIdx.x * Pitch);
|
||||
__global__ void
|
||||
SobelCopyImage(Pixel *pSobelOriginal, unsigned int Pitch, int w, int h, float fscale, cudaTextureObject_t tex)
|
||||
{
|
||||
unsigned char *pSobel = (unsigned char *)(((char *)pSobelOriginal) + blockIdx.x * Pitch);
|
||||
|
||||
for (int i = threadIdx.x; i < w; i += blockDim.x) {
|
||||
pSobel[i] = min(
|
||||
max((tex2D<unsigned char>(tex, (float)i, (float)blockIdx.x) * fscale),
|
||||
0.f),
|
||||
255.f);
|
||||
}
|
||||
for (int i = threadIdx.x; i < w; i += blockDim.x) {
|
||||
pSobel[i] = min(max((tex2D<unsigned char>(tex, (float)i, (float)blockIdx.x) * fscale), 0.f), 255.f);
|
||||
}
|
||||
}
|
||||
|
||||
// Perform block and pointer filtering using texture lookups.
|
||||
// The block and point operations are determined by the
|
||||
// input argument (see comment above for "SobelShared" function)
|
||||
__global__ void SobelTex(Pixel *pSobelOriginal, unsigned int Pitch, int w,
|
||||
int h, float fScale, int blockOperation,
|
||||
pointFunction_t pPointOperation,
|
||||
cudaTextureObject_t tex) {
|
||||
unsigned char *pSobel =
|
||||
(unsigned char *)(((char *)pSobelOriginal) + blockIdx.x * Pitch);
|
||||
unsigned char tmp = 0;
|
||||
__global__ void SobelTex(Pixel *pSobelOriginal,
|
||||
unsigned int Pitch,
|
||||
int w,
|
||||
int h,
|
||||
float fScale,
|
||||
int blockOperation,
|
||||
pointFunction_t pPointOperation,
|
||||
cudaTextureObject_t tex)
|
||||
{
|
||||
unsigned char *pSobel = (unsigned char *)(((char *)pSobelOriginal) + blockIdx.x * Pitch);
|
||||
unsigned char tmp = 0;
|
||||
|
||||
for (int i = threadIdx.x; i < w; i += blockDim.x) {
|
||||
unsigned char pix00 =
|
||||
tex2D<unsigned char>(tex, (float)i - 1, (float)blockIdx.x - 1);
|
||||
unsigned char pix01 =
|
||||
tex2D<unsigned char>(tex, (float)i + 0, (float)blockIdx.x - 1);
|
||||
unsigned char pix02 =
|
||||
tex2D<unsigned char>(tex, (float)i + 1, (float)blockIdx.x - 1);
|
||||
unsigned char pix10 =
|
||||
tex2D<unsigned char>(tex, (float)i - 1, (float)blockIdx.x + 0);
|
||||
unsigned char pix11 =
|
||||
tex2D<unsigned char>(tex, (float)i + 0, (float)blockIdx.x + 0);
|
||||
unsigned char pix12 =
|
||||
tex2D<unsigned char>(tex, (float)i + 1, (float)blockIdx.x + 0);
|
||||
unsigned char pix20 =
|
||||
tex2D<unsigned char>(tex, (float)i - 1, (float)blockIdx.x + 1);
|
||||
unsigned char pix21 =
|
||||
tex2D<unsigned char>(tex, (float)i + 0, (float)blockIdx.x + 1);
|
||||
unsigned char pix22 =
|
||||
tex2D<unsigned char>(tex, (float)i + 1, (float)blockIdx.x + 1);
|
||||
tmp = (*(blockFunction_table[blockOperation]))(
|
||||
pix00, pix01, pix02, pix10, pix11, pix12, pix20, pix21, pix22, fScale);
|
||||
for (int i = threadIdx.x; i < w; i += blockDim.x) {
|
||||
unsigned char pix00 = tex2D<unsigned char>(tex, (float)i - 1, (float)blockIdx.x - 1);
|
||||
unsigned char pix01 = tex2D<unsigned char>(tex, (float)i + 0, (float)blockIdx.x - 1);
|
||||
unsigned char pix02 = tex2D<unsigned char>(tex, (float)i + 1, (float)blockIdx.x - 1);
|
||||
unsigned char pix10 = tex2D<unsigned char>(tex, (float)i - 1, (float)blockIdx.x + 0);
|
||||
unsigned char pix11 = tex2D<unsigned char>(tex, (float)i + 0, (float)blockIdx.x + 0);
|
||||
unsigned char pix12 = tex2D<unsigned char>(tex, (float)i + 1, (float)blockIdx.x + 0);
|
||||
unsigned char pix20 = tex2D<unsigned char>(tex, (float)i - 1, (float)blockIdx.x + 1);
|
||||
unsigned char pix21 = tex2D<unsigned char>(tex, (float)i + 0, (float)blockIdx.x + 1);
|
||||
unsigned char pix22 = tex2D<unsigned char>(tex, (float)i + 1, (float)blockIdx.x + 1);
|
||||
tmp = (*(blockFunction_table[blockOperation]))(
|
||||
pix00, pix01, pix02, pix10, pix11, pix12, pix20, pix21, pix22, fScale);
|
||||
|
||||
if (pPointOperation != NULL) {
|
||||
tmp = (*pPointOperation)(tmp, 150.0);
|
||||
if (pPointOperation != NULL) {
|
||||
tmp = (*pPointOperation)(tmp, 150.0);
|
||||
}
|
||||
|
||||
pSobel[i] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void setupTexture(int iw, int ih, Pixel *data, int Bpp)
|
||||
{
|
||||
cudaChannelFormatDesc desc;
|
||||
|
||||
if (Bpp == 1) {
|
||||
desc = cudaCreateChannelDesc<unsigned char>();
|
||||
}
|
||||
else {
|
||||
desc = cudaCreateChannelDesc<uchar4>();
|
||||
}
|
||||
|
||||
pSobel[i] = tmp;
|
||||
}
|
||||
checkCudaErrors(cudaMallocArray(&array, &desc, iw, ih));
|
||||
checkCudaErrors(cudaMemcpy2DToArray(
|
||||
array, 0, 0, data, iw * Bpp * sizeof(Pixel), iw * Bpp * sizeof(Pixel), ih, cudaMemcpyHostToDevice));
|
||||
|
||||
cudaResourceDesc texRes;
|
||||
memset(&texRes, 0, sizeof(cudaResourceDesc));
|
||||
|
||||
texRes.resType = cudaResourceTypeArray;
|
||||
texRes.res.array.array = array;
|
||||
|
||||
cudaTextureDesc texDescr;
|
||||
memset(&texDescr, 0, sizeof(cudaTextureDesc));
|
||||
|
||||
checkCudaErrors(cudaCreateTextureObject(&tex, &texRes, &texDescr, NULL));
|
||||
}
|
||||
|
||||
extern "C" void setupTexture(int iw, int ih, Pixel *data, int Bpp) {
|
||||
cudaChannelFormatDesc desc;
|
||||
|
||||
if (Bpp == 1) {
|
||||
desc = cudaCreateChannelDesc<unsigned char>();
|
||||
} else {
|
||||
desc = cudaCreateChannelDesc<uchar4>();
|
||||
}
|
||||
|
||||
checkCudaErrors(cudaMallocArray(&array, &desc, iw, ih));
|
||||
checkCudaErrors(cudaMemcpy2DToArray(
|
||||
array, 0, 0, data, iw * Bpp * sizeof(Pixel), iw * Bpp * sizeof(Pixel), ih,
|
||||
cudaMemcpyHostToDevice));
|
||||
|
||||
cudaResourceDesc texRes;
|
||||
memset(&texRes, 0, sizeof(cudaResourceDesc));
|
||||
|
||||
texRes.resType = cudaResourceTypeArray;
|
||||
texRes.res.array.array = array;
|
||||
|
||||
cudaTextureDesc texDescr;
|
||||
memset(&texDescr, 0, sizeof(cudaTextureDesc));
|
||||
|
||||
checkCudaErrors(cudaCreateTextureObject(&tex, &texRes, &texDescr, NULL));
|
||||
}
|
||||
|
||||
extern "C" void deleteTexture(void) {
|
||||
checkCudaErrors(cudaFreeArray(array));
|
||||
checkCudaErrors(cudaDestroyTextureObject(tex));
|
||||
extern "C" void deleteTexture(void)
|
||||
{
|
||||
checkCudaErrors(cudaFreeArray(array));
|
||||
checkCudaErrors(cudaDestroyTextureObject(tex));
|
||||
}
|
||||
|
||||
// Copy the pointers from the function tables to the host side
|
||||
void setupFunctionTables() {
|
||||
// Dynamically assign the function table.
|
||||
// Copy the function pointers to their appropriate locations according to the
|
||||
// enum
|
||||
checkCudaErrors(cudaMemcpyFromSymbol(&h_blockFunction_table[SOBEL_FILTER],
|
||||
pComputeSobel, sizeof(blockFunction_t)));
|
||||
checkCudaErrors(cudaMemcpyFromSymbol(&h_blockFunction_table[BOX_FILTER],
|
||||
pComputeBox, sizeof(blockFunction_t)));
|
||||
void setupFunctionTables()
|
||||
{
|
||||
// Dynamically assign the function table.
|
||||
// Copy the function pointers to their appropriate locations according to the
|
||||
// enum
|
||||
checkCudaErrors(cudaMemcpyFromSymbol(&h_blockFunction_table[SOBEL_FILTER], pComputeSobel, sizeof(blockFunction_t)));
|
||||
checkCudaErrors(cudaMemcpyFromSymbol(&h_blockFunction_table[BOX_FILTER], pComputeBox, sizeof(blockFunction_t)));
|
||||
|
||||
// do the same for the point function, where the 2nd function is NULL ("no-op"
|
||||
// filter, skipped in kernel code)
|
||||
checkCudaErrors(cudaMemcpyFromSymbol(&h_pointFunction_table[THRESHOLD_FILTER],
|
||||
pComputeThreshold,
|
||||
sizeof(pointFunction_t)));
|
||||
h_pointFunction_table[NULL_FILTER] = NULL;
|
||||
// do the same for the point function, where the 2nd function is NULL ("no-op"
|
||||
// filter, skipped in kernel code)
|
||||
checkCudaErrors(
|
||||
cudaMemcpyFromSymbol(&h_pointFunction_table[THRESHOLD_FILTER], pComputeThreshold, sizeof(pointFunction_t)));
|
||||
h_pointFunction_table[NULL_FILTER] = NULL;
|
||||
|
||||
// now copy the function tables back to the device, so if we wish we can use
|
||||
// an index into the table to choose them
|
||||
// We have now set the order in the function table according to our enum.
|
||||
checkCudaErrors(
|
||||
cudaMemcpyToSymbol(blockFunction_table, h_blockFunction_table,
|
||||
sizeof(blockFunction_t) * LAST_BLOCK_FILTER));
|
||||
checkCudaErrors(
|
||||
cudaMemcpyToSymbol(pointFunction_table, h_pointFunction_table,
|
||||
sizeof(pointFunction_t) * LAST_POINT_FILTER));
|
||||
// now copy the function tables back to the device, so if we wish we can use
|
||||
// an index into the table to choose them
|
||||
// We have now set the order in the function table according to our enum.
|
||||
checkCudaErrors(
|
||||
cudaMemcpyToSymbol(blockFunction_table, h_blockFunction_table, sizeof(blockFunction_t) * LAST_BLOCK_FILTER));
|
||||
checkCudaErrors(
|
||||
cudaMemcpyToSymbol(pointFunction_table, h_pointFunction_table, sizeof(pointFunction_t) * LAST_POINT_FILTER));
|
||||
}
|
||||
|
||||
// Wrapper for the __global__ call that sets up the texture and threads
|
||||
@@ -363,40 +365,50 @@ void setupFunctionTables() {
|
||||
// blockFunction_table on the device side
|
||||
// pPointOp is itself a function pointer passed as a kernel argument, retrieved
|
||||
// from a host side copy of the function table
|
||||
extern "C" void sobelFilter(Pixel *odata, int iw, int ih,
|
||||
enum SobelDisplayMode mode, float fScale,
|
||||
int blockOperation, int pointOperation) {
|
||||
pointFunction_t pPointOp = h_pointFunction_table[pointOperation];
|
||||
extern "C" void sobelFilter(Pixel *odata,
|
||||
int iw,
|
||||
int ih,
|
||||
enum SobelDisplayMode mode,
|
||||
float fScale,
|
||||
int blockOperation,
|
||||
int pointOperation)
|
||||
{
|
||||
pointFunction_t pPointOp = h_pointFunction_table[pointOperation];
|
||||
|
||||
switch (mode) {
|
||||
switch (mode) {
|
||||
case SOBELDISPLAY_IMAGE:
|
||||
SobelCopyImage<<<ih, 384>>>(odata, iw, iw, ih, fScale, tex);
|
||||
break;
|
||||
SobelCopyImage<<<ih, 384>>>(odata, iw, iw, ih, fScale, tex);
|
||||
break;
|
||||
|
||||
case SOBELDISPLAY_SOBELTEX:
|
||||
SobelTex<<<ih, 384>>>(odata, iw, iw, ih, fScale, blockOperation, pPointOp,
|
||||
tex);
|
||||
break;
|
||||
SobelTex<<<ih, 384>>>(odata, iw, iw, ih, fScale, blockOperation, pPointOp, tex);
|
||||
break;
|
||||
|
||||
case SOBELDISPLAY_SOBELSHARED: {
|
||||
dim3 threads(16, 4);
|
||||
dim3 threads(16, 4);
|
||||
#ifndef FIXED_BLOCKWIDTH
|
||||
int BlockWidth = 80; // must be divisible by 16 for coalescing
|
||||
int BlockWidth = 80; // must be divisible by 16 for coalescing
|
||||
#endif
|
||||
dim3 blocks = dim3(iw / (4 * BlockWidth) + (0 != iw % (4 * BlockWidth)),
|
||||
ih / threads.y + (0 != ih % threads.y));
|
||||
int SharedPitch = ~0x3f & (4 * (BlockWidth + 2 * RADIUS) + 0x3f);
|
||||
int sharedMem = SharedPitch * (threads.y + 2 * RADIUS);
|
||||
dim3 blocks =
|
||||
dim3(iw / (4 * BlockWidth) + (0 != iw % (4 * BlockWidth)), ih / threads.y + (0 != ih % threads.y));
|
||||
int SharedPitch = ~0x3f & (4 * (BlockWidth + 2 * RADIUS) + 0x3f);
|
||||
int sharedMem = SharedPitch * (threads.y + 2 * RADIUS);
|
||||
|
||||
// for the shared kernel, width must be divisible by 4
|
||||
iw &= ~3;
|
||||
// for the shared kernel, width must be divisible by 4
|
||||
iw &= ~3;
|
||||
|
||||
SobelShared<<<blocks, threads, sharedMem>>>(
|
||||
(uchar4 *)odata, iw,
|
||||
SobelShared<<<blocks, threads, sharedMem>>>((uchar4 *)odata,
|
||||
iw,
|
||||
#ifndef FIXED_BLOCKWIDTH
|
||||
BlockWidth, SharedPitch,
|
||||
BlockWidth,
|
||||
SharedPitch,
|
||||
#endif
|
||||
iw, ih, fScale, blockOperation, pPointOp, tex);
|
||||
iw,
|
||||
ih,
|
||||
fScale,
|
||||
blockOperation,
|
||||
pPointOp,
|
||||
tex);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,11 +31,7 @@
|
||||
typedef unsigned char Pixel;
|
||||
|
||||
// global determines which filter to invoke
|
||||
enum SobelDisplayMode {
|
||||
SOBELDISPLAY_IMAGE = 0,
|
||||
SOBELDISPLAY_SOBELTEX,
|
||||
SOBELDISPLAY_SOBELSHARED
|
||||
};
|
||||
enum SobelDisplayMode { SOBELDISPLAY_IMAGE = 0, SOBELDISPLAY_SOBELTEX, SOBELDISPLAY_SOBELSHARED };
|
||||
|
||||
// Enums to set up the function table
|
||||
// note: if you change these be sure to recompile those files
|
||||
@@ -47,12 +43,16 @@ enum BLOCK_ENUM { THRESHOLD_FILTER = 0, NULL_FILTER, LAST_BLOCK_FILTER };
|
||||
|
||||
extern enum SobelDisplayMode g_SobelDisplayMode;
|
||||
|
||||
extern "C" void sobelFilter(Pixel *odata, int iw, int ih,
|
||||
enum SobelDisplayMode mode, float fScale,
|
||||
int blockOperation, int pointOperation);
|
||||
extern "C" void sobelFilter(Pixel *odata,
|
||||
int iw,
|
||||
int ih,
|
||||
enum SobelDisplayMode mode,
|
||||
float fScale,
|
||||
int blockOperation,
|
||||
int pointOperation);
|
||||
extern "C" void setupTexture(int iw, int ih, Pixel *data, int Bpp);
|
||||
extern "C" void deleteTexture(void);
|
||||
extern "C" void initFilter(void);
|
||||
void setupFunctionTables();
|
||||
void setupFunctionTables();
|
||||
|
||||
#endif
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -65,25 +65,27 @@
|
||||
|
||||
// This is the un-specialized struct. Note that we prevent instantiation of
|
||||
// this struct by making it abstract (i.e. with pure virtual methods).
|
||||
template <typename T>
|
||||
struct SharedMemory {
|
||||
// Ensure that we won't compile any un-specialized types
|
||||
virtual __device__ T &operator*() = 0;
|
||||
virtual __device__ T &operator[](int i) = 0;
|
||||
template <typename T> struct SharedMemory
|
||||
{
|
||||
// Ensure that we won't compile any un-specialized types
|
||||
virtual __device__ T &operator*() = 0;
|
||||
virtual __device__ T &operator[](int i) = 0;
|
||||
};
|
||||
|
||||
#define BUILD_SHAREDMEMORY_TYPE(t, n) \
|
||||
template <> \
|
||||
struct SharedMemory<t> { \
|
||||
__device__ t &operator*() { \
|
||||
extern __shared__ t n[]; \
|
||||
return *n; \
|
||||
} \
|
||||
__device__ t &operator[](int i) { \
|
||||
extern __shared__ t n[]; \
|
||||
return n[i]; \
|
||||
} \
|
||||
}
|
||||
#define BUILD_SHAREDMEMORY_TYPE(t, n) \
|
||||
template <> struct SharedMemory<t> \
|
||||
{ \
|
||||
__device__ t &operator*() \
|
||||
{ \
|
||||
extern __shared__ t n[]; \
|
||||
return *n; \
|
||||
} \
|
||||
__device__ t &operator[](int i) \
|
||||
{ \
|
||||
extern __shared__ t n[]; \
|
||||
return n[i]; \
|
||||
} \
|
||||
}
|
||||
|
||||
BUILD_SHAREDMEMORY_TYPE(int, s_int);
|
||||
BUILD_SHAREDMEMORY_TYPE(unsigned int, s_uint);
|
||||
|
||||
@@ -28,18 +28,17 @@
|
||||
#ifndef PIESTIMATOR_H
|
||||
#define PIESTIMATOR_H
|
||||
|
||||
template <typename Real>
|
||||
class PiEstimator {
|
||||
public:
|
||||
PiEstimator(unsigned int numSims, unsigned int device,
|
||||
unsigned int threadBlockSize, unsigned int seed);
|
||||
Real operator()();
|
||||
template <typename Real> class PiEstimator
|
||||
{
|
||||
public:
|
||||
PiEstimator(unsigned int numSims, unsigned int device, unsigned int threadBlockSize, unsigned int seed);
|
||||
Real operator()();
|
||||
|
||||
private:
|
||||
unsigned int m_seed;
|
||||
unsigned int m_numSims;
|
||||
unsigned int m_device;
|
||||
unsigned int m_threadBlockSize;
|
||||
private:
|
||||
unsigned int m_seed;
|
||||
unsigned int m_numSims;
|
||||
unsigned int m_device;
|
||||
unsigned int m_threadBlockSize;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -28,30 +28,31 @@
|
||||
#ifndef TEST_H
|
||||
#define TEST_H
|
||||
|
||||
template <typename Real>
|
||||
struct Test {
|
||||
Test() : pass(false){};
|
||||
template <typename Real> struct Test
|
||||
{
|
||||
Test()
|
||||
: pass(false) {};
|
||||
|
||||
int device;
|
||||
unsigned int numSims;
|
||||
unsigned int threadBlockSize;
|
||||
unsigned int seed;
|
||||
int device;
|
||||
unsigned int numSims;
|
||||
unsigned int threadBlockSize;
|
||||
unsigned int seed;
|
||||
|
||||
bool pass;
|
||||
double elapsedTime;
|
||||
bool pass;
|
||||
double elapsedTime;
|
||||
|
||||
bool operator()();
|
||||
bool operator()();
|
||||
};
|
||||
|
||||
// Defaults are arbitrary to give sensible runtime
|
||||
#define k_sims_min 100000
|
||||
#define k_sims_max 10000000
|
||||
#define k_sims_def 100000
|
||||
#define k_sims_qa 100000
|
||||
#define k_sims_min 100000
|
||||
#define k_sims_max 10000000
|
||||
#define k_sims_def 100000
|
||||
#define k_sims_qa 100000
|
||||
#define k_bsize_min 32
|
||||
#define k_bsize_def 128
|
||||
#define k_bsize_qa 128
|
||||
#define k_seed_def 1234
|
||||
#define k_bsize_qa 128
|
||||
#define k_seed_def 1234
|
||||
|
||||
// Target value
|
||||
#define PI 3.14159265359
|
||||
|
||||
@@ -40,7 +40,6 @@
|
||||
|
||||
#include <cuda_runtime.h>
|
||||
#include <helper_cuda.h>
|
||||
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
@@ -51,204 +50,208 @@
|
||||
static const char *printfFile = "MonteCarloEstimatePiInlineP.txt";
|
||||
|
||||
// Forward declarations
|
||||
void showHelp(const int argc, const char **argv);
|
||||
template <typename Real>
|
||||
void runTest(int argc, const char **argv);
|
||||
void showHelp(const int argc, const char **argv);
|
||||
template <typename Real> void runTest(int argc, const char **argv);
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
using std::invalid_argument;
|
||||
using std::string;
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
using std::invalid_argument;
|
||||
using std::string;
|
||||
|
||||
// Open the log file
|
||||
printf("Monte Carlo Estimate Pi (with inline PRNG)\n");
|
||||
printf("==========================================\n\n");
|
||||
// Open the log file
|
||||
printf("Monte Carlo Estimate Pi (with inline PRNG)\n");
|
||||
printf("==========================================\n\n");
|
||||
|
||||
// If help flag is set, display help and exit immediately
|
||||
if (checkCmdLineFlag(argc, (const char **)argv, "help")) {
|
||||
printf("Displaying help on console\n");
|
||||
showHelp(argc, (const char **)argv);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
// Check the precision (checked against the device capability later)
|
||||
try {
|
||||
char *value;
|
||||
|
||||
if (getCmdLineArgumentString(argc, (const char **)argv, "precision",
|
||||
&value)) {
|
||||
// Check requested precision is valid
|
||||
string prec(value);
|
||||
|
||||
if (prec.compare("single") == 0 || prec.compare("\"single\"") == 0) {
|
||||
runTest<float>(argc, (const char **)argv);
|
||||
} else if (prec.compare("double") == 0 ||
|
||||
prec.compare("\"double\"") == 0) {
|
||||
runTest<double>(argc, (const char **)argv);
|
||||
} else {
|
||||
printf(
|
||||
"specified precision (%s) is invalid, must be \"single\" or "
|
||||
"\"double\".\n",
|
||||
value);
|
||||
throw invalid_argument("precision");
|
||||
}
|
||||
} else {
|
||||
runTest<float>(argc, (const char **)argv);
|
||||
// If help flag is set, display help and exit immediately
|
||||
if (checkCmdLineFlag(argc, (const char **)argv, "help")) {
|
||||
printf("Displaying help on console\n");
|
||||
showHelp(argc, (const char **)argv);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
} catch (invalid_argument &e) {
|
||||
printf("invalid command line argument (%s)\n", e.what());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Finish
|
||||
exit(EXIT_SUCCESS);
|
||||
// Check the precision (checked against the device capability later)
|
||||
try {
|
||||
char *value;
|
||||
|
||||
if (getCmdLineArgumentString(argc, (const char **)argv, "precision", &value)) {
|
||||
// Check requested precision is valid
|
||||
string prec(value);
|
||||
|
||||
if (prec.compare("single") == 0 || prec.compare("\"single\"") == 0) {
|
||||
runTest<float>(argc, (const char **)argv);
|
||||
}
|
||||
else if (prec.compare("double") == 0 || prec.compare("\"double\"") == 0) {
|
||||
runTest<double>(argc, (const char **)argv);
|
||||
}
|
||||
else {
|
||||
printf("specified precision (%s) is invalid, must be \"single\" or "
|
||||
"\"double\".\n",
|
||||
value);
|
||||
throw invalid_argument("precision");
|
||||
}
|
||||
}
|
||||
else {
|
||||
runTest<float>(argc, (const char **)argv);
|
||||
}
|
||||
}
|
||||
catch (invalid_argument &e) {
|
||||
printf("invalid command line argument (%s)\n", e.what());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Finish
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
template <typename Real>
|
||||
void runTest(int argc, const char **argv) {
|
||||
using std::invalid_argument;
|
||||
using std::runtime_error;
|
||||
template <typename Real> void runTest(int argc, const char **argv)
|
||||
{
|
||||
using std::invalid_argument;
|
||||
using std::runtime_error;
|
||||
|
||||
try {
|
||||
Test<Real> test;
|
||||
int deviceCount = 0;
|
||||
cudaError_t cudaResult = cudaSuccess;
|
||||
try {
|
||||
Test<Real> test;
|
||||
int deviceCount = 0;
|
||||
cudaError_t cudaResult = cudaSuccess;
|
||||
|
||||
// by default specify GPU Device == 0
|
||||
test.device = 0;
|
||||
// by default specify GPU Device == 0
|
||||
test.device = 0;
|
||||
|
||||
// Get number of available devices
|
||||
cudaResult = cudaGetDeviceCount(&deviceCount);
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
printf("could not get device count (%s).\n",
|
||||
cudaGetErrorString(cudaResult));
|
||||
throw runtime_error("cudaGetDeviceCount");
|
||||
}
|
||||
|
||||
// (default parameters)
|
||||
test.numSims = k_sims_qa;
|
||||
test.threadBlockSize = k_bsize_qa;
|
||||
test.seed = k_seed_def;
|
||||
|
||||
{
|
||||
char *value = 0;
|
||||
|
||||
if (getCmdLineArgumentString(argc, argv, "device", &value)) {
|
||||
test.device = (int)atoi(value);
|
||||
|
||||
if (test.device >= deviceCount) {
|
||||
printf(
|
||||
"invalid target device specified on command line (device %d does "
|
||||
"not exist).\n",
|
||||
test.device);
|
||||
throw invalid_argument("device");
|
||||
}
|
||||
} else {
|
||||
test.device = gpuGetMaxGflopsDeviceId();
|
||||
}
|
||||
|
||||
if (getCmdLineArgumentString(argc, argv, "sims", &value)) {
|
||||
test.numSims = (unsigned int)atoi(value);
|
||||
printf("number of simulations = %d\n", test.numSims);
|
||||
|
||||
if (test.numSims < k_sims_min || test.numSims > k_sims_max) {
|
||||
printf(
|
||||
"specified number of simulations (%d) is invalid, must be "
|
||||
"between %d and %d.\n",
|
||||
test.numSims, k_sims_min, k_sims_max);
|
||||
throw invalid_argument("sims");
|
||||
}
|
||||
} else {
|
||||
test.numSims = k_sims_def;
|
||||
}
|
||||
|
||||
if (getCmdLineArgumentString(argc, argv, "block-size", &value)) {
|
||||
// Determine max threads per block
|
||||
cudaDeviceProp deviceProperties;
|
||||
cudaResult = cudaGetDeviceProperties(&deviceProperties, test.device);
|
||||
// Get number of available devices
|
||||
cudaResult = cudaGetDeviceCount(&deviceCount);
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
printf("unable to get device properties for device %d.\n",
|
||||
test.device);
|
||||
throw runtime_error("cudaGetDeviceProperties");
|
||||
printf("could not get device count (%s).\n", cudaGetErrorString(cudaResult));
|
||||
throw runtime_error("cudaGetDeviceCount");
|
||||
}
|
||||
|
||||
// Check requested size is valid
|
||||
test.threadBlockSize = (unsigned int)atoi(value);
|
||||
printf("block size = %d\n", test.threadBlockSize);
|
||||
// (default parameters)
|
||||
test.numSims = k_sims_qa;
|
||||
test.threadBlockSize = k_bsize_qa;
|
||||
test.seed = k_seed_def;
|
||||
|
||||
if (test.threadBlockSize < k_bsize_min ||
|
||||
test.threadBlockSize > static_cast<unsigned int>(
|
||||
deviceProperties.maxThreadsPerBlock)) {
|
||||
printf(
|
||||
"specified block size (%d) is invalid, must be between %d and %d "
|
||||
"for device %d.\n",
|
||||
test.threadBlockSize, k_bsize_min,
|
||||
deviceProperties.maxThreadsPerBlock, test.device);
|
||||
throw invalid_argument("block-size");
|
||||
{
|
||||
char *value = 0;
|
||||
|
||||
if (getCmdLineArgumentString(argc, argv, "device", &value)) {
|
||||
test.device = (int)atoi(value);
|
||||
|
||||
if (test.device >= deviceCount) {
|
||||
printf("invalid target device specified on command line (device %d does "
|
||||
"not exist).\n",
|
||||
test.device);
|
||||
throw invalid_argument("device");
|
||||
}
|
||||
}
|
||||
else {
|
||||
test.device = gpuGetMaxGflopsDeviceId();
|
||||
}
|
||||
|
||||
if (getCmdLineArgumentString(argc, argv, "sims", &value)) {
|
||||
test.numSims = (unsigned int)atoi(value);
|
||||
printf("number of simulations = %d\n", test.numSims);
|
||||
|
||||
if (test.numSims < k_sims_min || test.numSims > k_sims_max) {
|
||||
printf("specified number of simulations (%d) is invalid, must be "
|
||||
"between %d and %d.\n",
|
||||
test.numSims,
|
||||
k_sims_min,
|
||||
k_sims_max);
|
||||
throw invalid_argument("sims");
|
||||
}
|
||||
}
|
||||
else {
|
||||
test.numSims = k_sims_def;
|
||||
}
|
||||
|
||||
if (getCmdLineArgumentString(argc, argv, "block-size", &value)) {
|
||||
// Determine max threads per block
|
||||
cudaDeviceProp deviceProperties;
|
||||
cudaResult = cudaGetDeviceProperties(&deviceProperties, test.device);
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
printf("unable to get device properties for device %d.\n", test.device);
|
||||
throw runtime_error("cudaGetDeviceProperties");
|
||||
}
|
||||
|
||||
// Check requested size is valid
|
||||
test.threadBlockSize = (unsigned int)atoi(value);
|
||||
printf("block size = %d\n", test.threadBlockSize);
|
||||
|
||||
if (test.threadBlockSize < k_bsize_min
|
||||
|| test.threadBlockSize > static_cast<unsigned int>(deviceProperties.maxThreadsPerBlock)) {
|
||||
printf("specified block size (%d) is invalid, must be between %d and %d "
|
||||
"for device %d.\n",
|
||||
test.threadBlockSize,
|
||||
k_bsize_min,
|
||||
deviceProperties.maxThreadsPerBlock,
|
||||
test.device);
|
||||
throw invalid_argument("block-size");
|
||||
}
|
||||
|
||||
if (test.threadBlockSize & test.threadBlockSize - 1) {
|
||||
printf("specified block size (%d) is invalid, must be a power of two "
|
||||
"(see reduction function).\n",
|
||||
test.threadBlockSize);
|
||||
throw invalid_argument("block-size");
|
||||
}
|
||||
}
|
||||
else {
|
||||
test.threadBlockSize = k_bsize_def;
|
||||
}
|
||||
|
||||
if (getCmdLineArgumentString(argc, argv, "seed", &value)) {
|
||||
// Check requested seed is valid
|
||||
test.seed = (unsigned int)atoi(value);
|
||||
printf("seed = %d\n", test.seed);
|
||||
|
||||
if (test.seed == 0) {
|
||||
printf("specified seed (%d) is invalid, must be non-zero.\n", test.seed);
|
||||
throw invalid_argument("seed");
|
||||
}
|
||||
}
|
||||
else {
|
||||
test.seed = k_seed_def;
|
||||
}
|
||||
}
|
||||
|
||||
if (test.threadBlockSize & test.threadBlockSize - 1) {
|
||||
printf(
|
||||
"specified block size (%d) is invalid, must be a power of two "
|
||||
"(see reduction function).\n",
|
||||
test.threadBlockSize);
|
||||
throw invalid_argument("block-size");
|
||||
}
|
||||
} else {
|
||||
test.threadBlockSize = k_bsize_def;
|
||||
}
|
||||
// Execute
|
||||
test();
|
||||
}
|
||||
catch (invalid_argument &e) {
|
||||
printf("invalid command line argument (%s)\n", e.what());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
catch (runtime_error &e) {
|
||||
printf("runtime error (%s)\n", e.what());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (getCmdLineArgumentString(argc, argv, "seed", &value)) {
|
||||
// Check requested seed is valid
|
||||
test.seed = (unsigned int)atoi(value);
|
||||
printf("seed = %d\n", test.seed);
|
||||
void showHelp(int argc, const char **argv)
|
||||
{
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
using std::left;
|
||||
using std::setw;
|
||||
|
||||
if (test.seed == 0) {
|
||||
printf("specified seed (%d) is invalid, must be non-zero.\n",
|
||||
test.seed);
|
||||
throw invalid_argument("seed");
|
||||
}
|
||||
} else {
|
||||
test.seed = k_seed_def;
|
||||
}
|
||||
if (argc > 0) {
|
||||
cout << endl << argv[0] << endl;
|
||||
}
|
||||
|
||||
// Execute
|
||||
test();
|
||||
} catch (invalid_argument &e) {
|
||||
printf("invalid command line argument (%s)\n", e.what());
|
||||
exit(EXIT_FAILURE);
|
||||
} catch (runtime_error &e) {
|
||||
printf("runtime error (%s)\n", e.what());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
void showHelp(int argc, const char **argv) {
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
using std::left;
|
||||
using std::setw;
|
||||
|
||||
if (argc > 0) {
|
||||
cout << endl << argv[0] << endl;
|
||||
}
|
||||
|
||||
cout << endl << "Syntax:" << endl;
|
||||
cout << left;
|
||||
cout << " " << setw(20) << "--device=<device>"
|
||||
<< "Specify device to use for execution" << endl;
|
||||
cout << " " << setw(20) << "--sims=<N>"
|
||||
<< "Specify number of Monte Carlo simulations" << endl;
|
||||
cout << " " << setw(20) << "--block-size=<N>"
|
||||
<< "Specify number of threads per block" << endl;
|
||||
cout << " " << setw(20) << "--seed=<N>"
|
||||
<< "Specify the seed to use for the random number generator" << endl;
|
||||
cout << " " << setw(20) << "--precision=<P>"
|
||||
<< "Specify the precision (\"single\" or \"double\")" << endl;
|
||||
cout << endl;
|
||||
cout << " " << setw(20) << "--noprompt"
|
||||
<< "Skip prompt before exit" << endl;
|
||||
cout << endl;
|
||||
cout << endl << "Syntax:" << endl;
|
||||
cout << left;
|
||||
cout << " " << setw(20) << "--device=<device>"
|
||||
<< "Specify device to use for execution" << endl;
|
||||
cout << " " << setw(20) << "--sims=<N>"
|
||||
<< "Specify number of Monte Carlo simulations" << endl;
|
||||
cout << " " << setw(20) << "--block-size=<N>"
|
||||
<< "Specify number of threads per block" << endl;
|
||||
cout << " " << setw(20) << "--seed=<N>"
|
||||
<< "Specify the seed to use for the random number generator" << endl;
|
||||
cout << " " << setw(20) << "--precision=<P>"
|
||||
<< "Specify the precision (\"single\" or \"double\")" << endl;
|
||||
cout << endl;
|
||||
cout << " " << setw(20) << "--noprompt"
|
||||
<< "Skip prompt before exit" << endl;
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
@@ -25,15 +25,15 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "../inc/piestimator.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cooperative_groups.h>
|
||||
#include <cuda_runtime.h>
|
||||
#include <numeric>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <typeinfo>
|
||||
#include <cuda_runtime.h>
|
||||
#include <cooperative_groups.h>
|
||||
#include <vector>
|
||||
|
||||
#include "../inc/piestimator.h"
|
||||
|
||||
namespace cg = cooperative_groups;
|
||||
#include <curand_kernel.h>
|
||||
@@ -42,240 +42,240 @@ using std::string;
|
||||
using std::vector;
|
||||
|
||||
// RNG init kernel
|
||||
__global__ void initRNG(curandState *const rngStates, const unsigned int seed) {
|
||||
// Determine thread ID
|
||||
unsigned int tid = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
__global__ void initRNG(curandState *const rngStates, const unsigned int seed)
|
||||
{
|
||||
// Determine thread ID
|
||||
unsigned int tid = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
|
||||
// Initialise the RNG
|
||||
curand_init(seed, tid, 0, &rngStates[tid]);
|
||||
// Initialise the RNG
|
||||
curand_init(seed, tid, 0, &rngStates[tid]);
|
||||
}
|
||||
|
||||
__device__ unsigned int reduce_sum(unsigned int in, cg::thread_block cta) {
|
||||
extern __shared__ unsigned int sdata[];
|
||||
__device__ unsigned int reduce_sum(unsigned int in, cg::thread_block cta)
|
||||
{
|
||||
extern __shared__ unsigned int sdata[];
|
||||
|
||||
// Perform first level of reduction:
|
||||
// - Write to shared memory
|
||||
unsigned int ltid = threadIdx.x;
|
||||
// Perform first level of reduction:
|
||||
// - Write to shared memory
|
||||
unsigned int ltid = threadIdx.x;
|
||||
|
||||
sdata[ltid] = in;
|
||||
cg::sync(cta);
|
||||
sdata[ltid] = in;
|
||||
cg::sync(cta);
|
||||
|
||||
// Do reduction in shared mem
|
||||
for (unsigned int s = blockDim.x / 2; s > 0; s >>= 1) {
|
||||
if (ltid < s) {
|
||||
sdata[ltid] += sdata[ltid + s];
|
||||
// Do reduction in shared mem
|
||||
for (unsigned int s = blockDim.x / 2; s > 0; s >>= 1) {
|
||||
if (ltid < s) {
|
||||
sdata[ltid] += sdata[ltid + s];
|
||||
}
|
||||
|
||||
cg::sync(cta);
|
||||
}
|
||||
|
||||
cg::sync(cta);
|
||||
}
|
||||
|
||||
return sdata[0];
|
||||
return sdata[0];
|
||||
}
|
||||
|
||||
__device__ inline void getPoint(float &x, float &y, curandState &state) {
|
||||
x = curand_uniform(&state);
|
||||
y = curand_uniform(&state);
|
||||
__device__ inline void getPoint(float &x, float &y, curandState &state)
|
||||
{
|
||||
x = curand_uniform(&state);
|
||||
y = curand_uniform(&state);
|
||||
}
|
||||
__device__ inline void getPoint(double &x, double &y, curandState &state) {
|
||||
x = curand_uniform_double(&state);
|
||||
y = curand_uniform_double(&state);
|
||||
__device__ inline void getPoint(double &x, double &y, curandState &state)
|
||||
{
|
||||
x = curand_uniform_double(&state);
|
||||
y = curand_uniform_double(&state);
|
||||
}
|
||||
|
||||
// Estimator kernel
|
||||
template <typename Real>
|
||||
__global__ void computeValue(unsigned int *const results,
|
||||
curandState *const rngStates,
|
||||
const unsigned int numSims) {
|
||||
// Handle to thread block group
|
||||
cg::thread_block cta = cg::this_thread_block();
|
||||
// Determine thread ID
|
||||
unsigned int bid = blockIdx.x;
|
||||
unsigned int tid = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
unsigned int step = gridDim.x * blockDim.x;
|
||||
__global__ void computeValue(unsigned int *const results, curandState *const rngStates, const unsigned int numSims)
|
||||
{
|
||||
// Handle to thread block group
|
||||
cg::thread_block cta = cg::this_thread_block();
|
||||
// Determine thread ID
|
||||
unsigned int bid = blockIdx.x;
|
||||
unsigned int tid = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
unsigned int step = gridDim.x * blockDim.x;
|
||||
|
||||
// Initialise the RNG
|
||||
curandState localState = rngStates[tid];
|
||||
// Initialise the RNG
|
||||
curandState localState = rngStates[tid];
|
||||
|
||||
// Count the number of points which lie inside the unit quarter-circle
|
||||
unsigned int pointsInside = 0;
|
||||
// Count the number of points which lie inside the unit quarter-circle
|
||||
unsigned int pointsInside = 0;
|
||||
|
||||
for (unsigned int i = tid; i < numSims; i += step) {
|
||||
Real x;
|
||||
Real y;
|
||||
getPoint(x, y, localState);
|
||||
Real l2norm2 = x * x + y * y;
|
||||
for (unsigned int i = tid; i < numSims; i += step) {
|
||||
Real x;
|
||||
Real y;
|
||||
getPoint(x, y, localState);
|
||||
Real l2norm2 = x * x + y * y;
|
||||
|
||||
if (l2norm2 < static_cast<Real>(1)) {
|
||||
pointsInside++;
|
||||
if (l2norm2 < static_cast<Real>(1)) {
|
||||
pointsInside++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Reduce within the block
|
||||
pointsInside = reduce_sum(pointsInside, cta);
|
||||
// Reduce within the block
|
||||
pointsInside = reduce_sum(pointsInside, cta);
|
||||
|
||||
// Store the result
|
||||
if (threadIdx.x == 0) {
|
||||
results[bid] = pointsInside;
|
||||
}
|
||||
// Store the result
|
||||
if (threadIdx.x == 0) {
|
||||
results[bid] = pointsInside;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Real>
|
||||
PiEstimator<Real>::PiEstimator(unsigned int numSims, unsigned int device,
|
||||
unsigned int threadBlockSize, unsigned int seed)
|
||||
: m_numSims(numSims),
|
||||
m_device(device),
|
||||
m_threadBlockSize(threadBlockSize),
|
||||
m_seed(seed) {}
|
||||
PiEstimator<Real>::PiEstimator(unsigned int numSims,
|
||||
unsigned int device,
|
||||
unsigned int threadBlockSize,
|
||||
unsigned int seed)
|
||||
: m_numSims(numSims)
|
||||
, m_device(device)
|
||||
, m_threadBlockSize(threadBlockSize)
|
||||
, m_seed(seed)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename Real>
|
||||
Real PiEstimator<Real>::operator()() {
|
||||
cudaError_t cudaResult = cudaSuccess;
|
||||
struct cudaDeviceProp deviceProperties;
|
||||
struct cudaFuncAttributes funcAttributes;
|
||||
template <typename Real> Real PiEstimator<Real>::operator()()
|
||||
{
|
||||
cudaError_t cudaResult = cudaSuccess;
|
||||
struct cudaDeviceProp deviceProperties;
|
||||
struct cudaFuncAttributes funcAttributes;
|
||||
|
||||
// Get device properties
|
||||
cudaResult = cudaGetDeviceProperties(&deviceProperties, m_device);
|
||||
// Get device properties
|
||||
cudaResult = cudaGetDeviceProperties(&deviceProperties, m_device);
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not get device properties: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not get device properties: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
// Check precision is valid
|
||||
if (typeid(Real) == typeid(double) &&
|
||||
(deviceProperties.major < 1 ||
|
||||
(deviceProperties.major == 1 && deviceProperties.minor < 3))) {
|
||||
throw std::runtime_error("Device does not have double precision support");
|
||||
}
|
||||
// Check precision is valid
|
||||
if (typeid(Real) == typeid(double)
|
||||
&& (deviceProperties.major < 1 || (deviceProperties.major == 1 && deviceProperties.minor < 3))) {
|
||||
throw std::runtime_error("Device does not have double precision support");
|
||||
}
|
||||
|
||||
// Attach to GPU
|
||||
cudaResult = cudaSetDevice(m_device);
|
||||
// Attach to GPU
|
||||
cudaResult = cudaSetDevice(m_device);
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not set CUDA device: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not set CUDA device: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
// Determine how to divide the work between cores
|
||||
dim3 block;
|
||||
dim3 grid;
|
||||
block.x = m_threadBlockSize;
|
||||
grid.x = (m_numSims + m_threadBlockSize - 1) / m_threadBlockSize;
|
||||
// Determine how to divide the work between cores
|
||||
dim3 block;
|
||||
dim3 grid;
|
||||
block.x = m_threadBlockSize;
|
||||
grid.x = (m_numSims + m_threadBlockSize - 1) / m_threadBlockSize;
|
||||
|
||||
// Aim to launch around ten or more times as many blocks as there
|
||||
// are multiprocessors on the target device.
|
||||
unsigned int blocksPerSM = 10;
|
||||
unsigned int numSMs = deviceProperties.multiProcessorCount;
|
||||
// Aim to launch around ten or more times as many blocks as there
|
||||
// are multiprocessors on the target device.
|
||||
unsigned int blocksPerSM = 10;
|
||||
unsigned int numSMs = deviceProperties.multiProcessorCount;
|
||||
|
||||
while (grid.x > 2 * blocksPerSM * numSMs) {
|
||||
grid.x >>= 1;
|
||||
}
|
||||
while (grid.x > 2 * blocksPerSM * numSMs) {
|
||||
grid.x >>= 1;
|
||||
}
|
||||
|
||||
// Get initRNG function properties and check the maximum block size
|
||||
cudaResult = cudaFuncGetAttributes(&funcAttributes, initRNG);
|
||||
// Get initRNG function properties and check the maximum block size
|
||||
cudaResult = cudaFuncGetAttributes(&funcAttributes, initRNG);
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not get function attributes: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not get function attributes: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
if (block.x > (unsigned int)funcAttributes.maxThreadsPerBlock) {
|
||||
throw std::runtime_error(
|
||||
"Block X dimension is too large for initRNG kernel");
|
||||
}
|
||||
if (block.x > (unsigned int)funcAttributes.maxThreadsPerBlock) {
|
||||
throw std::runtime_error("Block X dimension is too large for initRNG kernel");
|
||||
}
|
||||
|
||||
// Get computeValue function properties and check the maximum block size
|
||||
cudaResult = cudaFuncGetAttributes(&funcAttributes, computeValue<Real>);
|
||||
// Get computeValue function properties and check the maximum block size
|
||||
cudaResult = cudaFuncGetAttributes(&funcAttributes, computeValue<Real>);
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not get function attributes: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not get function attributes: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
if (block.x > (unsigned int)funcAttributes.maxThreadsPerBlock) {
|
||||
throw std::runtime_error(
|
||||
"Block X dimension is too large for computeValue kernel");
|
||||
}
|
||||
if (block.x > (unsigned int)funcAttributes.maxThreadsPerBlock) {
|
||||
throw std::runtime_error("Block X dimension is too large for computeValue kernel");
|
||||
}
|
||||
|
||||
// Check the dimensions are valid
|
||||
if (block.x > (unsigned int)deviceProperties.maxThreadsDim[0]) {
|
||||
throw std::runtime_error("Block X dimension is too large for device");
|
||||
}
|
||||
// Check the dimensions are valid
|
||||
if (block.x > (unsigned int)deviceProperties.maxThreadsDim[0]) {
|
||||
throw std::runtime_error("Block X dimension is too large for device");
|
||||
}
|
||||
|
||||
if (grid.x > (unsigned int)deviceProperties.maxGridSize[0]) {
|
||||
throw std::runtime_error("Grid X dimension is too large for device");
|
||||
}
|
||||
if (grid.x > (unsigned int)deviceProperties.maxGridSize[0]) {
|
||||
throw std::runtime_error("Grid X dimension is too large for device");
|
||||
}
|
||||
|
||||
// Allocate memory for RNG states
|
||||
curandState *d_rngStates = 0;
|
||||
cudaResult =
|
||||
cudaMalloc((void **)&d_rngStates, grid.x * block.x * sizeof(curandState));
|
||||
// Allocate memory for RNG states
|
||||
curandState *d_rngStates = 0;
|
||||
cudaResult = cudaMalloc((void **)&d_rngStates, grid.x * block.x * sizeof(curandState));
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not allocate memory on device for RNG states: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not allocate memory on device for RNG states: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
// Allocate memory for result
|
||||
// Each thread block will produce one result
|
||||
unsigned int *d_results = 0;
|
||||
cudaResult = cudaMalloc((void **)&d_results, grid.x * sizeof(unsigned int));
|
||||
// Allocate memory for result
|
||||
// Each thread block will produce one result
|
||||
unsigned int *d_results = 0;
|
||||
cudaResult = cudaMalloc((void **)&d_results, grid.x * sizeof(unsigned int));
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not allocate memory on device for partial results: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not allocate memory on device for partial results: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
// Initialise RNG
|
||||
initRNG<<<grid, block>>>(d_rngStates, m_seed);
|
||||
// Initialise RNG
|
||||
initRNG<<<grid, block>>>(d_rngStates, m_seed);
|
||||
|
||||
// Count the points inside unit quarter-circle
|
||||
computeValue<Real><<<grid, block, block.x * sizeof(unsigned int)>>>(
|
||||
d_results, d_rngStates, m_numSims);
|
||||
// Count the points inside unit quarter-circle
|
||||
computeValue<Real><<<grid, block, block.x * sizeof(unsigned int)>>>(d_results, d_rngStates, m_numSims);
|
||||
|
||||
// Copy partial results back
|
||||
vector<unsigned int> results(grid.x);
|
||||
cudaResult = cudaMemcpy(&results[0], d_results, grid.x * sizeof(unsigned int),
|
||||
cudaMemcpyDeviceToHost);
|
||||
// Copy partial results back
|
||||
vector<unsigned int> results(grid.x);
|
||||
cudaResult = cudaMemcpy(&results[0], d_results, grid.x * sizeof(unsigned int), cudaMemcpyDeviceToHost);
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not copy partial results to host: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not copy partial results to host: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
// Complete sum-reduction on host
|
||||
Real value =
|
||||
static_cast<Real>(std::accumulate(results.begin(), results.end(), 0));
|
||||
// Complete sum-reduction on host
|
||||
Real value = static_cast<Real>(std::accumulate(results.begin(), results.end(), 0));
|
||||
|
||||
// Determine the proportion of points inside the quarter-circle,
|
||||
// i.e. the area of the unit quarter-circle
|
||||
value /= m_numSims;
|
||||
// Determine the proportion of points inside the quarter-circle,
|
||||
// i.e. the area of the unit quarter-circle
|
||||
value /= m_numSims;
|
||||
|
||||
// Value is currently an estimate of the area of a unit quarter-circle, so we
|
||||
// can scale to a full circle by multiplying by four. Now since the area of a
|
||||
// circle is pi * r^2, and r is one, the value will be an estimate for the
|
||||
// value of pi.
|
||||
value *= 4;
|
||||
// Value is currently an estimate of the area of a unit quarter-circle, so we
|
||||
// can scale to a full circle by multiplying by four. Now since the area of a
|
||||
// circle is pi * r^2, and r is one, the value will be an estimate for the
|
||||
// value of pi.
|
||||
value *= 4;
|
||||
|
||||
// Cleanup
|
||||
if (d_rngStates) {
|
||||
cudaFree(d_rngStates);
|
||||
d_rngStates = 0;
|
||||
}
|
||||
// Cleanup
|
||||
if (d_rngStates) {
|
||||
cudaFree(d_rngStates);
|
||||
d_rngStates = 0;
|
||||
}
|
||||
|
||||
if (d_results) {
|
||||
cudaFree(d_results);
|
||||
d_results = 0;
|
||||
}
|
||||
if (d_results) {
|
||||
cudaFree(d_results);
|
||||
d_results = 0;
|
||||
}
|
||||
|
||||
return value;
|
||||
return value;
|
||||
}
|
||||
|
||||
// Explicit template instantiation
|
||||
|
||||
@@ -28,83 +28,84 @@
|
||||
|
||||
#include "../inc/test.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <stdexcept>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
#include <typeinfo>
|
||||
#include <stdio.h>
|
||||
#include <helper_timer.h>
|
||||
#include <math.h>
|
||||
#include <cuda_runtime.h>
|
||||
#include <helper_timer.h>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <math.h>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <stdio.h>
|
||||
#include <typeinfo>
|
||||
|
||||
#include "../inc/piestimator.h"
|
||||
|
||||
template <typename Real>
|
||||
bool Test<Real>::operator()() {
|
||||
using std::endl;
|
||||
using std::setw;
|
||||
using std::stringstream;
|
||||
template <typename Real> bool Test<Real>::operator()()
|
||||
{
|
||||
using std::endl;
|
||||
using std::setw;
|
||||
using std::stringstream;
|
||||
|
||||
StopWatchInterface *timer = NULL;
|
||||
sdkCreateTimer(&timer);
|
||||
StopWatchInterface *timer = NULL;
|
||||
sdkCreateTimer(&timer);
|
||||
|
||||
// Get device properties
|
||||
struct cudaDeviceProp deviceProperties;
|
||||
cudaError_t cudaResult = cudaGetDeviceProperties(&deviceProperties, device);
|
||||
// Get device properties
|
||||
struct cudaDeviceProp deviceProperties;
|
||||
cudaError_t cudaResult = cudaGetDeviceProperties(&deviceProperties, device);
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
std::string msg("Could not get device properties: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
if (cudaResult != cudaSuccess) {
|
||||
std::string msg("Could not get device properties: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
// Evaluate on GPU
|
||||
printf("Estimating Pi on GPU (%s)\n\n", deviceProperties.name);
|
||||
PiEstimator<Real> estimator(numSims, device, threadBlockSize, seed);
|
||||
sdkStartTimer(&timer);
|
||||
Real result = estimator();
|
||||
sdkStopTimer(&timer);
|
||||
elapsedTime = sdkGetAverageTimerValue(&timer) / 1000.0f;
|
||||
// Evaluate on GPU
|
||||
printf("Estimating Pi on GPU (%s)\n\n", deviceProperties.name);
|
||||
PiEstimator<Real> estimator(numSims, device, threadBlockSize, seed);
|
||||
sdkStartTimer(&timer);
|
||||
Real result = estimator();
|
||||
sdkStopTimer(&timer);
|
||||
elapsedTime = sdkGetAverageTimerValue(&timer) / 1000.0f;
|
||||
|
||||
// Tolerance to compare result with expected
|
||||
// This is just to check that nothing has gone very wrong with the
|
||||
// test, the actual accuracy of the result depends on the number of
|
||||
// Monte Carlo trials
|
||||
const Real tolerance = static_cast<Real>(0.01);
|
||||
// Tolerance to compare result with expected
|
||||
// This is just to check that nothing has gone very wrong with the
|
||||
// test, the actual accuracy of the result depends on the number of
|
||||
// Monte Carlo trials
|
||||
const Real tolerance = static_cast<Real>(0.01);
|
||||
|
||||
// Display results
|
||||
Real abserror = fabs(result - static_cast<Real>(PI));
|
||||
Real relerror = abserror / static_cast<float>(PI);
|
||||
printf("Precision: %s\n",
|
||||
(typeid(Real) == typeid(double)) ? "double" : "single");
|
||||
printf("Number of sims: %d\n", numSims);
|
||||
printf("Tolerance: %e\n", tolerance);
|
||||
printf("GPU result: %e\n", result);
|
||||
printf("Expected: %e\n", PI);
|
||||
printf("Absolute error: %e\n", abserror);
|
||||
printf("Relative error: %e\n\n", relerror);
|
||||
// Display results
|
||||
Real abserror = fabs(result - static_cast<Real>(PI));
|
||||
Real relerror = abserror / static_cast<float>(PI);
|
||||
printf("Precision: %s\n", (typeid(Real) == typeid(double)) ? "double" : "single");
|
||||
printf("Number of sims: %d\n", numSims);
|
||||
printf("Tolerance: %e\n", tolerance);
|
||||
printf("GPU result: %e\n", result);
|
||||
printf("Expected: %e\n", PI);
|
||||
printf("Absolute error: %e\n", abserror);
|
||||
printf("Relative error: %e\n\n", relerror);
|
||||
|
||||
// Check result
|
||||
if (relerror > tolerance) {
|
||||
printf("computed result (%e) does not match expected result (%e).\n",
|
||||
result, PI);
|
||||
pass = false;
|
||||
} else {
|
||||
pass = true;
|
||||
}
|
||||
// Check result
|
||||
if (relerror > tolerance) {
|
||||
printf("computed result (%e) does not match expected result (%e).\n", result, PI);
|
||||
pass = false;
|
||||
}
|
||||
else {
|
||||
pass = true;
|
||||
}
|
||||
|
||||
// Print results
|
||||
printf(
|
||||
"MonteCarloEstimatePiInlineP, Performance = %.2f sims/s, Time = "
|
||||
"%.2f(ms), NumDevsUsed = %u, Blocksize = %u\n",
|
||||
numSims / elapsedTime, elapsedTime * 1000.0f, 1, threadBlockSize);
|
||||
// Print results
|
||||
printf("MonteCarloEstimatePiInlineP, Performance = %.2f sims/s, Time = "
|
||||
"%.2f(ms), NumDevsUsed = %u, Blocksize = %u\n",
|
||||
numSims / elapsedTime,
|
||||
elapsedTime * 1000.0f,
|
||||
1,
|
||||
threadBlockSize);
|
||||
|
||||
sdkDeleteTimer(&timer);
|
||||
sdkDeleteTimer(&timer);
|
||||
|
||||
return pass;
|
||||
return pass;
|
||||
}
|
||||
|
||||
// Explicit template instantiation
|
||||
|
||||
@@ -65,25 +65,27 @@
|
||||
|
||||
// This is the un-specialized struct. Note that we prevent instantiation of
|
||||
// this struct by making it abstract (i.e. with pure virtual methods).
|
||||
template <typename T>
|
||||
struct SharedMemory {
|
||||
// Ensure that we won't compile any un-specialized types
|
||||
virtual __device__ T &operator*() = 0;
|
||||
virtual __device__ T &operator[](int i) = 0;
|
||||
template <typename T> struct SharedMemory
|
||||
{
|
||||
// Ensure that we won't compile any un-specialized types
|
||||
virtual __device__ T &operator*() = 0;
|
||||
virtual __device__ T &operator[](int i) = 0;
|
||||
};
|
||||
|
||||
#define BUILD_SHAREDMEMORY_TYPE(t, n) \
|
||||
template <> \
|
||||
struct SharedMemory<t> { \
|
||||
__device__ t &operator*() { \
|
||||
extern __shared__ t n[]; \
|
||||
return *n; \
|
||||
} \
|
||||
__device__ t &operator[](int i) { \
|
||||
extern __shared__ t n[]; \
|
||||
return n[i]; \
|
||||
} \
|
||||
}
|
||||
#define BUILD_SHAREDMEMORY_TYPE(t, n) \
|
||||
template <> struct SharedMemory<t> \
|
||||
{ \
|
||||
__device__ t &operator*() \
|
||||
{ \
|
||||
extern __shared__ t n[]; \
|
||||
return *n; \
|
||||
} \
|
||||
__device__ t &operator[](int i) \
|
||||
{ \
|
||||
extern __shared__ t n[]; \
|
||||
return n[i]; \
|
||||
} \
|
||||
}
|
||||
|
||||
BUILD_SHAREDMEMORY_TYPE(int, s_int);
|
||||
BUILD_SHAREDMEMORY_TYPE(unsigned int, s_uint);
|
||||
|
||||
@@ -28,17 +28,16 @@
|
||||
#ifndef PIESTIMATOR_H
|
||||
#define PIESTIMATOR_H
|
||||
|
||||
template <typename Real>
|
||||
class PiEstimator {
|
||||
public:
|
||||
PiEstimator(unsigned int numSims, unsigned int device,
|
||||
unsigned int threadBlockSize);
|
||||
Real operator()();
|
||||
template <typename Real> class PiEstimator
|
||||
{
|
||||
public:
|
||||
PiEstimator(unsigned int numSims, unsigned int device, unsigned int threadBlockSize);
|
||||
Real operator()();
|
||||
|
||||
private:
|
||||
unsigned int m_numSims;
|
||||
unsigned int m_device;
|
||||
unsigned int m_threadBlockSize;
|
||||
private:
|
||||
unsigned int m_numSims;
|
||||
unsigned int m_device;
|
||||
unsigned int m_threadBlockSize;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -28,28 +28,29 @@
|
||||
#ifndef TEST_H
|
||||
#define TEST_H
|
||||
|
||||
template <typename Real>
|
||||
struct Test {
|
||||
Test() : pass(false){};
|
||||
template <typename Real> struct Test
|
||||
{
|
||||
Test()
|
||||
: pass(false) {};
|
||||
|
||||
int device;
|
||||
unsigned int numSims;
|
||||
unsigned int threadBlockSize;
|
||||
int device;
|
||||
unsigned int numSims;
|
||||
unsigned int threadBlockSize;
|
||||
|
||||
bool pass;
|
||||
double elapsedTime;
|
||||
bool pass;
|
||||
double elapsedTime;
|
||||
|
||||
bool operator()();
|
||||
bool operator()();
|
||||
};
|
||||
|
||||
// Defaults are arbitrary to give sensible runtime
|
||||
#define k_sims_min 100000
|
||||
#define k_sims_max 10000000
|
||||
#define k_sims_def 100000
|
||||
#define k_sims_qa 100000
|
||||
#define k_sims_min 100000
|
||||
#define k_sims_max 10000000
|
||||
#define k_sims_def 100000
|
||||
#define k_sims_qa 100000
|
||||
#define k_bsize_min 32
|
||||
#define k_bsize_def 128
|
||||
#define k_bsize_qa 128
|
||||
#define k_bsize_qa 128
|
||||
|
||||
// Target value
|
||||
#define PI 3.14159265359
|
||||
|
||||
@@ -39,196 +39,201 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <stdexcept>
|
||||
#include <cuda_runtime.h>
|
||||
#include <helper_timer.h>
|
||||
#include <helper_cuda.h>
|
||||
|
||||
#include <helper_timer.h>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <math.h>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "../inc/test.h"
|
||||
|
||||
// Forward declarations
|
||||
void showHelp(const int argc, const char **argv);
|
||||
template <typename Real>
|
||||
void runTest(int argc, const char **argv);
|
||||
void showHelp(const int argc, const char **argv);
|
||||
template <typename Real> void runTest(int argc, const char **argv);
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
using std::invalid_argument;
|
||||
using std::string;
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
using std::invalid_argument;
|
||||
using std::string;
|
||||
|
||||
// Open the log file
|
||||
printf("Monte Carlo Estimate Pi (with inline QRNG)\n");
|
||||
printf("==========================================\n\n");
|
||||
// Open the log file
|
||||
printf("Monte Carlo Estimate Pi (with inline QRNG)\n");
|
||||
printf("==========================================\n\n");
|
||||
|
||||
// If help flag is set, display help and exit immediately
|
||||
if (checkCmdLineFlag(argc, (const char **)argv, "help")) {
|
||||
printf("Displaying help on console\n");
|
||||
showHelp(argc, (const char **)argv);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
// Check the precision (checked against the device capability later)
|
||||
try {
|
||||
char *value;
|
||||
|
||||
if (getCmdLineArgumentString(argc, (const char **)argv, "precision",
|
||||
&value)) {
|
||||
// Check requested precision is valid
|
||||
string prec(value);
|
||||
|
||||
if (prec.compare("single") == 0 || prec.compare("\"single\"") == 0) {
|
||||
runTest<float>(argc, (const char **)argv);
|
||||
} else if (prec.compare("double") == 0 ||
|
||||
prec.compare("\"double\"") == 0) {
|
||||
runTest<double>(argc, (const char **)argv);
|
||||
} else {
|
||||
printf(
|
||||
"specified precision (%s) is invalid, must be \"single\" or "
|
||||
"\"double\".\n",
|
||||
value);
|
||||
throw invalid_argument("precision");
|
||||
}
|
||||
} else {
|
||||
runTest<float>(argc, (const char **)argv);
|
||||
// If help flag is set, display help and exit immediately
|
||||
if (checkCmdLineFlag(argc, (const char **)argv, "help")) {
|
||||
printf("Displaying help on console\n");
|
||||
showHelp(argc, (const char **)argv);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
} catch (invalid_argument &e) {
|
||||
printf("invalid command line argument (%s)\n", e.what());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Finish
|
||||
exit(EXIT_SUCCESS);
|
||||
// Check the precision (checked against the device capability later)
|
||||
try {
|
||||
char *value;
|
||||
|
||||
if (getCmdLineArgumentString(argc, (const char **)argv, "precision", &value)) {
|
||||
// Check requested precision is valid
|
||||
string prec(value);
|
||||
|
||||
if (prec.compare("single") == 0 || prec.compare("\"single\"") == 0) {
|
||||
runTest<float>(argc, (const char **)argv);
|
||||
}
|
||||
else if (prec.compare("double") == 0 || prec.compare("\"double\"") == 0) {
|
||||
runTest<double>(argc, (const char **)argv);
|
||||
}
|
||||
else {
|
||||
printf("specified precision (%s) is invalid, must be \"single\" or "
|
||||
"\"double\".\n",
|
||||
value);
|
||||
throw invalid_argument("precision");
|
||||
}
|
||||
}
|
||||
else {
|
||||
runTest<float>(argc, (const char **)argv);
|
||||
}
|
||||
}
|
||||
catch (invalid_argument &e) {
|
||||
printf("invalid command line argument (%s)\n", e.what());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Finish
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
template <typename Real>
|
||||
void runTest(int argc, const char **argv) {
|
||||
using std::invalid_argument;
|
||||
using std::runtime_error;
|
||||
template <typename Real> void runTest(int argc, const char **argv)
|
||||
{
|
||||
using std::invalid_argument;
|
||||
using std::runtime_error;
|
||||
|
||||
StopWatchInterface *timer = NULL;
|
||||
StopWatchInterface *timer = NULL;
|
||||
|
||||
try {
|
||||
Test<Real> test;
|
||||
int deviceCount = 0;
|
||||
cudaError_t cudaResult = cudaSuccess;
|
||||
try {
|
||||
Test<Real> test;
|
||||
int deviceCount = 0;
|
||||
cudaError_t cudaResult = cudaSuccess;
|
||||
|
||||
// by default specify GPU Device == 0
|
||||
test.device = 0;
|
||||
// by default specify GPU Device == 0
|
||||
test.device = 0;
|
||||
|
||||
// Get number of available devices
|
||||
cudaResult = cudaGetDeviceCount(&deviceCount);
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
printf("could not get device count.\n");
|
||||
throw runtime_error("cudaGetDeviceCount");
|
||||
}
|
||||
|
||||
// (default parameters)
|
||||
test.numSims = k_sims_qa;
|
||||
test.threadBlockSize = k_bsize_qa;
|
||||
|
||||
{
|
||||
char *value = 0;
|
||||
|
||||
if (getCmdLineArgumentString(argc, argv, "device", &value)) {
|
||||
test.device = (int)atoi(value);
|
||||
|
||||
if (test.device >= deviceCount) {
|
||||
printf(
|
||||
"invalid target device specified on command line (device %d does "
|
||||
"not exist).\n",
|
||||
test.device);
|
||||
throw invalid_argument("device");
|
||||
}
|
||||
} else {
|
||||
test.device = gpuGetMaxGflopsDeviceId();
|
||||
}
|
||||
|
||||
if (getCmdLineArgumentString(argc, argv, "sims", &value)) {
|
||||
test.numSims = (unsigned int)atoi(value);
|
||||
|
||||
if (test.numSims < k_sims_min || test.numSims > k_sims_max) {
|
||||
printf(
|
||||
"specified number of simulations (%d) is invalid, must be "
|
||||
"between %d and %d.\n",
|
||||
test.numSims, k_sims_min, k_sims_max);
|
||||
throw invalid_argument("sims");
|
||||
}
|
||||
} else {
|
||||
test.numSims = k_sims_def;
|
||||
}
|
||||
|
||||
if (getCmdLineArgumentString(argc, argv, "block-size", &value)) {
|
||||
// Determine max threads per block
|
||||
cudaDeviceProp deviceProperties;
|
||||
cudaResult = cudaGetDeviceProperties(&deviceProperties, test.device);
|
||||
// Get number of available devices
|
||||
cudaResult = cudaGetDeviceCount(&deviceCount);
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
printf("cound not get device properties for device %d.\n",
|
||||
test.device);
|
||||
throw runtime_error("cudaGetDeviceProperties");
|
||||
printf("could not get device count.\n");
|
||||
throw runtime_error("cudaGetDeviceCount");
|
||||
}
|
||||
|
||||
// Check requested size is valid
|
||||
test.threadBlockSize = (unsigned int)atoi(value);
|
||||
// (default parameters)
|
||||
test.numSims = k_sims_qa;
|
||||
test.threadBlockSize = k_bsize_qa;
|
||||
|
||||
if (test.threadBlockSize < k_bsize_min ||
|
||||
test.threadBlockSize > static_cast<unsigned int>(
|
||||
deviceProperties.maxThreadsPerBlock)) {
|
||||
printf(
|
||||
"specified block size (%d) is invalid, must be between %d and %d "
|
||||
"for device %d.\n",
|
||||
test.threadBlockSize, k_bsize_min,
|
||||
deviceProperties.maxThreadsPerBlock, test.device);
|
||||
throw invalid_argument("block-size");
|
||||
}
|
||||
{
|
||||
char *value = 0;
|
||||
|
||||
if (test.threadBlockSize & test.threadBlockSize - 1) {
|
||||
printf(
|
||||
"specified block size (%d) is invalid, must be a power of two "
|
||||
"(see reduction function).\n",
|
||||
test.threadBlockSize);
|
||||
throw invalid_argument("block-size");
|
||||
if (getCmdLineArgumentString(argc, argv, "device", &value)) {
|
||||
test.device = (int)atoi(value);
|
||||
|
||||
if (test.device >= deviceCount) {
|
||||
printf("invalid target device specified on command line (device %d does "
|
||||
"not exist).\n",
|
||||
test.device);
|
||||
throw invalid_argument("device");
|
||||
}
|
||||
}
|
||||
else {
|
||||
test.device = gpuGetMaxGflopsDeviceId();
|
||||
}
|
||||
|
||||
if (getCmdLineArgumentString(argc, argv, "sims", &value)) {
|
||||
test.numSims = (unsigned int)atoi(value);
|
||||
|
||||
if (test.numSims < k_sims_min || test.numSims > k_sims_max) {
|
||||
printf("specified number of simulations (%d) is invalid, must be "
|
||||
"between %d and %d.\n",
|
||||
test.numSims,
|
||||
k_sims_min,
|
||||
k_sims_max);
|
||||
throw invalid_argument("sims");
|
||||
}
|
||||
}
|
||||
else {
|
||||
test.numSims = k_sims_def;
|
||||
}
|
||||
|
||||
if (getCmdLineArgumentString(argc, argv, "block-size", &value)) {
|
||||
// Determine max threads per block
|
||||
cudaDeviceProp deviceProperties;
|
||||
cudaResult = cudaGetDeviceProperties(&deviceProperties, test.device);
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
printf("cound not get device properties for device %d.\n", test.device);
|
||||
throw runtime_error("cudaGetDeviceProperties");
|
||||
}
|
||||
|
||||
// Check requested size is valid
|
||||
test.threadBlockSize = (unsigned int)atoi(value);
|
||||
|
||||
if (test.threadBlockSize < k_bsize_min
|
||||
|| test.threadBlockSize > static_cast<unsigned int>(deviceProperties.maxThreadsPerBlock)) {
|
||||
printf("specified block size (%d) is invalid, must be between %d and %d "
|
||||
"for device %d.\n",
|
||||
test.threadBlockSize,
|
||||
k_bsize_min,
|
||||
deviceProperties.maxThreadsPerBlock,
|
||||
test.device);
|
||||
throw invalid_argument("block-size");
|
||||
}
|
||||
|
||||
if (test.threadBlockSize & test.threadBlockSize - 1) {
|
||||
printf("specified block size (%d) is invalid, must be a power of two "
|
||||
"(see reduction function).\n",
|
||||
test.threadBlockSize);
|
||||
throw invalid_argument("block-size");
|
||||
}
|
||||
}
|
||||
else {
|
||||
test.threadBlockSize = k_bsize_def;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
test.threadBlockSize = k_bsize_def;
|
||||
}
|
||||
// Execute
|
||||
test();
|
||||
}
|
||||
catch (invalid_argument &e) {
|
||||
printf("invalid command line argument (%s)\n", e.what());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
catch (runtime_error &e) {
|
||||
printf("runtime error (%s)\n", e.what());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
// Execute
|
||||
test();
|
||||
} catch (invalid_argument &e) {
|
||||
printf("invalid command line argument (%s)\n", e.what());
|
||||
exit(EXIT_FAILURE);
|
||||
} catch (runtime_error &e) {
|
||||
printf("runtime error (%s)\n", e.what());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
void showHelp(int argc, const char **argv) {
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
using std::left;
|
||||
using std::setw;
|
||||
void showHelp(int argc, const char **argv)
|
||||
{
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
using std::left;
|
||||
using std::setw;
|
||||
|
||||
if (argc > 0) {
|
||||
cout << endl << argv[0] << endl;
|
||||
}
|
||||
if (argc > 0) {
|
||||
cout << endl << argv[0] << endl;
|
||||
}
|
||||
|
||||
cout << endl << "Syntax:" << endl;
|
||||
cout << left;
|
||||
cout << " " << setw(20) << "--device=<device>"
|
||||
<< "Specify device to use for execution" << endl;
|
||||
cout << " " << setw(20) << "--sims=<N>"
|
||||
<< "Specify number of Monte Carlo simulations" << endl;
|
||||
cout << " " << setw(20) << "--block-size=<N>"
|
||||
<< "Specify number of threads per block" << endl;
|
||||
cout << " " << setw(20) << "--precision=<P>"
|
||||
<< "Specify the precision (\"single\" or \"double\")" << endl;
|
||||
cout << endl;
|
||||
cout << " " << setw(20) << "--noprompt"
|
||||
<< "Skip prompt before exit" << endl;
|
||||
cout << endl;
|
||||
cout << endl << "Syntax:" << endl;
|
||||
cout << left;
|
||||
cout << " " << setw(20) << "--device=<device>"
|
||||
<< "Specify device to use for execution" << endl;
|
||||
cout << " " << setw(20) << "--sims=<N>"
|
||||
<< "Specify number of Monte Carlo simulations" << endl;
|
||||
cout << " " << setw(20) << "--block-size=<N>"
|
||||
<< "Specify number of threads per block" << endl;
|
||||
cout << " " << setw(20) << "--precision=<P>"
|
||||
<< "Specify the precision (\"single\" or \"double\")" << endl;
|
||||
cout << endl;
|
||||
cout << " " << setw(20) << "--noprompt"
|
||||
<< "Skip prompt before exit" << endl;
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
@@ -26,15 +26,15 @@
|
||||
*/
|
||||
|
||||
|
||||
#include "../inc/piestimator.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cooperative_groups.h>
|
||||
#include <cuda_runtime.h>
|
||||
#include <numeric>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <typeinfo>
|
||||
#include <cuda_runtime.h>
|
||||
#include <cooperative_groups.h>
|
||||
#include <vector>
|
||||
|
||||
#include "../inc/piestimator.h"
|
||||
|
||||
namespace cg = cooperative_groups;
|
||||
#include <curand.h>
|
||||
@@ -46,346 +46,329 @@ using std::string;
|
||||
using std::vector;
|
||||
|
||||
// Helper templates to support float and double in same code
|
||||
template <typename L, typename R>
|
||||
struct TYPE_IS {
|
||||
static const bool test = false;
|
||||
template <typename L, typename R> struct TYPE_IS
|
||||
{
|
||||
static const bool test = false;
|
||||
};
|
||||
template <typename L>
|
||||
struct TYPE_IS<L, L> {
|
||||
static const bool test = true;
|
||||
template <typename L> struct TYPE_IS<L, L>
|
||||
{
|
||||
static const bool test = true;
|
||||
};
|
||||
template <bool, class L, class R>
|
||||
struct IF {
|
||||
typedef R type;
|
||||
template <bool, class L, class R> struct IF
|
||||
{
|
||||
typedef R type;
|
||||
};
|
||||
template <class L, class R>
|
||||
struct IF<true, L, R> {
|
||||
typedef L type;
|
||||
template <class L, class R> struct IF<true, L, R>
|
||||
{
|
||||
typedef L type;
|
||||
};
|
||||
|
||||
// RNG init kernel
|
||||
template <typename rngState_t, typename rngDirectionVectors_t>
|
||||
__global__ void initRNG(rngState_t *const rngStates,
|
||||
rngDirectionVectors_t *const rngDirections,
|
||||
unsigned int numDrawsPerDirection) {
|
||||
// Determine thread ID
|
||||
unsigned int tid = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
unsigned int step = gridDim.x * blockDim.x;
|
||||
__global__ void
|
||||
initRNG(rngState_t *const rngStates, rngDirectionVectors_t *const rngDirections, unsigned int numDrawsPerDirection)
|
||||
{
|
||||
// Determine thread ID
|
||||
unsigned int tid = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
unsigned int step = gridDim.x * blockDim.x;
|
||||
|
||||
// Determine offset to avoid overlapping sub-sequences
|
||||
unsigned int offset = tid * ((numDrawsPerDirection + step - 1) / step);
|
||||
// Determine offset to avoid overlapping sub-sequences
|
||||
unsigned int offset = tid * ((numDrawsPerDirection + step - 1) / step);
|
||||
|
||||
// Initialise the RNG
|
||||
curand_init(rngDirections[0], offset, &rngStates[tid]);
|
||||
curand_init(rngDirections[1], offset, &rngStates[tid + step]);
|
||||
// Initialise the RNG
|
||||
curand_init(rngDirections[0], offset, &rngStates[tid]);
|
||||
curand_init(rngDirections[1], offset, &rngStates[tid + step]);
|
||||
}
|
||||
|
||||
__device__ unsigned int reduce_sum(unsigned int in, cg::thread_block cta) {
|
||||
extern __shared__ unsigned int sdata[];
|
||||
__device__ unsigned int reduce_sum(unsigned int in, cg::thread_block cta)
|
||||
{
|
||||
extern __shared__ unsigned int sdata[];
|
||||
|
||||
// Perform first level of reduction:
|
||||
// - Write to shared memory
|
||||
unsigned int ltid = threadIdx.x;
|
||||
// Perform first level of reduction:
|
||||
// - Write to shared memory
|
||||
unsigned int ltid = threadIdx.x;
|
||||
|
||||
sdata[ltid] = in;
|
||||
cg::sync(cta);
|
||||
sdata[ltid] = in;
|
||||
cg::sync(cta);
|
||||
|
||||
// Do reduction in shared mem
|
||||
for (unsigned int s = blockDim.x / 2; s > 0; s >>= 1) {
|
||||
if (ltid < s) {
|
||||
sdata[ltid] += sdata[ltid + s];
|
||||
// Do reduction in shared mem
|
||||
for (unsigned int s = blockDim.x / 2; s > 0; s >>= 1) {
|
||||
if (ltid < s) {
|
||||
sdata[ltid] += sdata[ltid + s];
|
||||
}
|
||||
|
||||
cg::sync(cta);
|
||||
}
|
||||
|
||||
cg::sync(cta);
|
||||
}
|
||||
|
||||
return sdata[0];
|
||||
return sdata[0];
|
||||
}
|
||||
|
||||
__device__ inline void getPoint(float &x, float &y, curandStateSobol32 &state1,
|
||||
curandStateSobol32 &state2) {
|
||||
x = curand_uniform(&state1);
|
||||
y = curand_uniform(&state2);
|
||||
__device__ inline void getPoint(float &x, float &y, curandStateSobol32 &state1, curandStateSobol32 &state2)
|
||||
{
|
||||
x = curand_uniform(&state1);
|
||||
y = curand_uniform(&state2);
|
||||
}
|
||||
__device__ inline void getPoint(double &x, double &y,
|
||||
curandStateSobol64 &state1,
|
||||
curandStateSobol64 &state2) {
|
||||
x = curand_uniform_double(&state1);
|
||||
y = curand_uniform_double(&state2);
|
||||
__device__ inline void getPoint(double &x, double &y, curandStateSobol64 &state1, curandStateSobol64 &state2)
|
||||
{
|
||||
x = curand_uniform_double(&state1);
|
||||
y = curand_uniform_double(&state2);
|
||||
}
|
||||
|
||||
// Estimator kernel
|
||||
template <typename Real, typename rngState_t>
|
||||
__global__ void computeValue(unsigned int *const results,
|
||||
rngState_t *const rngStates,
|
||||
const unsigned int numSims) {
|
||||
// Handle to thread block group
|
||||
cg::thread_block cta = cg::this_thread_block();
|
||||
// Determine thread ID
|
||||
unsigned int bid = blockIdx.x;
|
||||
unsigned int tid = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
unsigned int step = gridDim.x * blockDim.x;
|
||||
__global__ void computeValue(unsigned int *const results, rngState_t *const rngStates, const unsigned int numSims)
|
||||
{
|
||||
// Handle to thread block group
|
||||
cg::thread_block cta = cg::this_thread_block();
|
||||
// Determine thread ID
|
||||
unsigned int bid = blockIdx.x;
|
||||
unsigned int tid = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
unsigned int step = gridDim.x * blockDim.x;
|
||||
|
||||
// Initialise the RNG
|
||||
rngState_t localState1 = rngStates[tid];
|
||||
rngState_t localState2 = rngStates[tid + step];
|
||||
// Initialise the RNG
|
||||
rngState_t localState1 = rngStates[tid];
|
||||
rngState_t localState2 = rngStates[tid + step];
|
||||
|
||||
// Count the number of points which lie inside the unit quarter-circle
|
||||
unsigned int pointsInside = 0;
|
||||
// Count the number of points which lie inside the unit quarter-circle
|
||||
unsigned int pointsInside = 0;
|
||||
|
||||
for (unsigned int i = tid; i < numSims; i += step) {
|
||||
Real x;
|
||||
Real y;
|
||||
getPoint(x, y, localState1, localState2);
|
||||
Real l2norm2 = x * x + y * y;
|
||||
for (unsigned int i = tid; i < numSims; i += step) {
|
||||
Real x;
|
||||
Real y;
|
||||
getPoint(x, y, localState1, localState2);
|
||||
Real l2norm2 = x * x + y * y;
|
||||
|
||||
if (l2norm2 < static_cast<Real>(1)) {
|
||||
pointsInside++;
|
||||
if (l2norm2 < static_cast<Real>(1)) {
|
||||
pointsInside++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Reduce within the block
|
||||
pointsInside = reduce_sum(pointsInside, cta);
|
||||
// Reduce within the block
|
||||
pointsInside = reduce_sum(pointsInside, cta);
|
||||
|
||||
// Store the result
|
||||
if (threadIdx.x == 0) {
|
||||
results[bid] = pointsInside;
|
||||
}
|
||||
// Store the result
|
||||
if (threadIdx.x == 0) {
|
||||
results[bid] = pointsInside;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Real>
|
||||
PiEstimator<Real>::PiEstimator(unsigned int numSims, unsigned int device,
|
||||
unsigned int threadBlockSize)
|
||||
: m_numSims(numSims),
|
||||
m_device(device),
|
||||
m_threadBlockSize(threadBlockSize) {}
|
||||
PiEstimator<Real>::PiEstimator(unsigned int numSims, unsigned int device, unsigned int threadBlockSize)
|
||||
: m_numSims(numSims)
|
||||
, m_device(device)
|
||||
, m_threadBlockSize(threadBlockSize)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename Real>
|
||||
Real PiEstimator<Real>::operator()() {
|
||||
cudaError_t cudaResult = cudaSuccess;
|
||||
struct cudaDeviceProp deviceProperties;
|
||||
struct cudaFuncAttributes funcAttributes;
|
||||
template <typename Real> Real PiEstimator<Real>::operator()()
|
||||
{
|
||||
cudaError_t cudaResult = cudaSuccess;
|
||||
struct cudaDeviceProp deviceProperties;
|
||||
struct cudaFuncAttributes funcAttributes;
|
||||
|
||||
// Determine type of generator to use (32- or 64-bit)
|
||||
typedef typename IF<TYPE_IS<Real, double>::test, curandStateSobol64_t,
|
||||
curandStateSobol32_t>::type curandStateSobol_sz;
|
||||
typedef
|
||||
typename IF<TYPE_IS<Real, double>::test, curandDirectionVectors64_t,
|
||||
curandDirectionVectors32_t>::type curandDirectionVectors_sz;
|
||||
// Determine type of generator to use (32- or 64-bit)
|
||||
typedef
|
||||
typename IF<TYPE_IS<Real, double>::test, curandStateSobol64_t, curandStateSobol32_t>::type curandStateSobol_sz;
|
||||
typedef typename IF<TYPE_IS<Real, double>::test, curandDirectionVectors64_t, curandDirectionVectors32_t>::type
|
||||
curandDirectionVectors_sz;
|
||||
|
||||
// Get device properties
|
||||
cudaResult = cudaGetDeviceProperties(&deviceProperties, m_device);
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not get device properties: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
// Check precision is valid
|
||||
if (typeid(Real) == typeid(double) &&
|
||||
(deviceProperties.major < 1 ||
|
||||
(deviceProperties.major == 1 && deviceProperties.minor < 3))) {
|
||||
throw std::runtime_error("Device does not have double precision support");
|
||||
}
|
||||
|
||||
// Attach to GPU
|
||||
cudaResult = cudaSetDevice(m_device);
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not set CUDA device: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
// Determine how to divide the work between cores
|
||||
dim3 block;
|
||||
dim3 grid;
|
||||
block.x = m_threadBlockSize;
|
||||
grid.x = (m_numSims + m_threadBlockSize - 1) / m_threadBlockSize;
|
||||
|
||||
// Aim to launch around ten or more times as many blocks as there
|
||||
// are multiprocessors on the target device.
|
||||
unsigned int blocksPerSM = 10;
|
||||
unsigned int numSMs = deviceProperties.multiProcessorCount;
|
||||
|
||||
while (grid.x > 2 * blocksPerSM * numSMs) {
|
||||
grid.x >>= 1;
|
||||
}
|
||||
|
||||
// Get initRNG function properties and check the maximum block size
|
||||
cudaResult = cudaFuncGetAttributes(
|
||||
&funcAttributes, initRNG<curandStateSobol_sz, curandDirectionVectors_sz>);
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not get function attributes: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
if (block.x > (unsigned int)funcAttributes.maxThreadsPerBlock) {
|
||||
throw std::runtime_error(
|
||||
"Block X dimension is too large for initRNG kernel");
|
||||
}
|
||||
|
||||
// Get computeValue function properties and check the maximum block size
|
||||
cudaResult = cudaFuncGetAttributes(&funcAttributes,
|
||||
computeValue<Real, curandStateSobol_sz>);
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not get function attributes: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
if (block.x > (unsigned int)funcAttributes.maxThreadsPerBlock) {
|
||||
throw std::runtime_error(
|
||||
"Block X dimension is too large for computeValue kernel");
|
||||
}
|
||||
|
||||
// Check the dimensions are valid
|
||||
if (block.x > (unsigned int)deviceProperties.maxThreadsDim[0]) {
|
||||
throw std::runtime_error("Block X dimension is too large for device");
|
||||
}
|
||||
|
||||
if (grid.x > (unsigned int)deviceProperties.maxGridSize[0]) {
|
||||
throw std::runtime_error("Grid X dimension is too large for device");
|
||||
}
|
||||
|
||||
// Allocate memory for RNG states and direction vectors
|
||||
curandStateSobol_sz *d_rngStates = 0;
|
||||
curandDirectionVectors_sz *d_rngDirections = 0;
|
||||
cudaResult = cudaMalloc((void **)&d_rngStates,
|
||||
2 * grid.x * block.x * sizeof(curandStateSobol_sz));
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not allocate memory on device for RNG states: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
cudaResult = cudaMalloc((void **)&d_rngDirections,
|
||||
2 * sizeof(curandDirectionVectors_sz));
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg(
|
||||
"Could not allocate memory on device for RNG direction vectors: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
// Allocate memory for result
|
||||
// Each thread block will produce one result
|
||||
unsigned int *d_results = 0;
|
||||
cudaResult = cudaMalloc((void **)&d_results, grid.x * sizeof(unsigned int));
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not allocate memory on device for partial results: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
// Generate direction vectors on the host and copy to the device
|
||||
if (typeid(Real) == typeid(float)) {
|
||||
curandDirectionVectors32_t *rngDirections;
|
||||
curandStatus_t curandResult = curandGetDirectionVectors32(
|
||||
&rngDirections, CURAND_DIRECTION_VECTORS_32_JOEKUO6);
|
||||
|
||||
if (curandResult != CURAND_STATUS_SUCCESS) {
|
||||
string msg(
|
||||
"Could not get direction vectors for quasi-random number "
|
||||
"generator: ");
|
||||
msg += curandResult;
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
cudaResult = cudaMemcpy(d_rngDirections, rngDirections,
|
||||
2 * sizeof(curandDirectionVectors32_t),
|
||||
cudaMemcpyHostToDevice);
|
||||
// Get device properties
|
||||
cudaResult = cudaGetDeviceProperties(&deviceProperties, m_device);
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not copy direction vectors to device: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
} else if (typeid(Real) == typeid(double)) {
|
||||
curandDirectionVectors64_t *rngDirections;
|
||||
curandStatus_t curandResult = curandGetDirectionVectors64(
|
||||
&rngDirections, CURAND_DIRECTION_VECTORS_64_JOEKUO6);
|
||||
|
||||
if (curandResult != CURAND_STATUS_SUCCESS) {
|
||||
string msg(
|
||||
"Could not get direction vectors for quasi-random number "
|
||||
"generator: ");
|
||||
msg += curandResult;
|
||||
throw std::runtime_error(msg);
|
||||
string msg("Could not get device properties: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
cudaResult = cudaMemcpy(d_rngDirections, rngDirections,
|
||||
2 * sizeof(curandDirectionVectors64_t),
|
||||
cudaMemcpyHostToDevice);
|
||||
// Check precision is valid
|
||||
if (typeid(Real) == typeid(double)
|
||||
&& (deviceProperties.major < 1 || (deviceProperties.major == 1 && deviceProperties.minor < 3))) {
|
||||
throw std::runtime_error("Device does not have double precision support");
|
||||
}
|
||||
|
||||
// Attach to GPU
|
||||
cudaResult = cudaSetDevice(m_device);
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not copy direction vectors to device: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
string msg("Could not set CUDA device: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
} else {
|
||||
string msg(
|
||||
"Could not get direction vectors for random number generator of "
|
||||
"specified type");
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
// Initialise RNG
|
||||
initRNG<<<grid, block>>>(d_rngStates, d_rngDirections, m_numSims);
|
||||
// Determine how to divide the work between cores
|
||||
dim3 block;
|
||||
dim3 grid;
|
||||
block.x = m_threadBlockSize;
|
||||
grid.x = (m_numSims + m_threadBlockSize - 1) / m_threadBlockSize;
|
||||
|
||||
// Count the points inside unit quarter-circle
|
||||
computeValue<Real><<<grid, block, block.x * sizeof(unsigned int)>>>(
|
||||
d_results, d_rngStates, m_numSims);
|
||||
// Aim to launch around ten or more times as many blocks as there
|
||||
// are multiprocessors on the target device.
|
||||
unsigned int blocksPerSM = 10;
|
||||
unsigned int numSMs = deviceProperties.multiProcessorCount;
|
||||
|
||||
// Copy partial results back
|
||||
vector<unsigned int> results(grid.x);
|
||||
cudaResult = cudaMemcpy(&results[0], d_results, grid.x * sizeof(unsigned int),
|
||||
cudaMemcpyDeviceToHost);
|
||||
while (grid.x > 2 * blocksPerSM * numSMs) {
|
||||
grid.x >>= 1;
|
||||
}
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not copy partial results to host: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
// Get initRNG function properties and check the maximum block size
|
||||
cudaResult = cudaFuncGetAttributes(&funcAttributes, initRNG<curandStateSobol_sz, curandDirectionVectors_sz>);
|
||||
|
||||
// Complete sum-reduction on host
|
||||
Real value =
|
||||
static_cast<Real>(std::accumulate(results.begin(), results.end(), 0));
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not get function attributes: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
// Determine the proportion of points inside the quarter-circle,
|
||||
// i.e. the area of the unit quarter-circle
|
||||
value /= m_numSims;
|
||||
if (block.x > (unsigned int)funcAttributes.maxThreadsPerBlock) {
|
||||
throw std::runtime_error("Block X dimension is too large for initRNG kernel");
|
||||
}
|
||||
|
||||
// Value is currently an estimate of the area of a unit quarter-circle, so we
|
||||
// can scale to a full circle by multiplying by four. Now since the area of a
|
||||
// circle is pi * r^2, and r is one, the value will be an estimate for the
|
||||
// value of pi.
|
||||
value *= 4;
|
||||
// Get computeValue function properties and check the maximum block size
|
||||
cudaResult = cudaFuncGetAttributes(&funcAttributes, computeValue<Real, curandStateSobol_sz>);
|
||||
|
||||
// Cleanup
|
||||
if (d_rngStates) {
|
||||
cudaFree(d_rngStates);
|
||||
d_rngStates = 0;
|
||||
}
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not get function attributes: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
if (d_rngDirections) {
|
||||
cudaFree(d_rngDirections);
|
||||
d_rngDirections = 0;
|
||||
}
|
||||
if (block.x > (unsigned int)funcAttributes.maxThreadsPerBlock) {
|
||||
throw std::runtime_error("Block X dimension is too large for computeValue kernel");
|
||||
}
|
||||
|
||||
if (d_results) {
|
||||
cudaFree(d_results);
|
||||
d_results = 0;
|
||||
}
|
||||
// Check the dimensions are valid
|
||||
if (block.x > (unsigned int)deviceProperties.maxThreadsDim[0]) {
|
||||
throw std::runtime_error("Block X dimension is too large for device");
|
||||
}
|
||||
|
||||
return value;
|
||||
if (grid.x > (unsigned int)deviceProperties.maxGridSize[0]) {
|
||||
throw std::runtime_error("Grid X dimension is too large for device");
|
||||
}
|
||||
|
||||
// Allocate memory for RNG states and direction vectors
|
||||
curandStateSobol_sz *d_rngStates = 0;
|
||||
curandDirectionVectors_sz *d_rngDirections = 0;
|
||||
cudaResult = cudaMalloc((void **)&d_rngStates, 2 * grid.x * block.x * sizeof(curandStateSobol_sz));
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not allocate memory on device for RNG states: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
cudaResult = cudaMalloc((void **)&d_rngDirections, 2 * sizeof(curandDirectionVectors_sz));
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not allocate memory on device for RNG direction vectors: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
// Allocate memory for result
|
||||
// Each thread block will produce one result
|
||||
unsigned int *d_results = 0;
|
||||
cudaResult = cudaMalloc((void **)&d_results, grid.x * sizeof(unsigned int));
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not allocate memory on device for partial results: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
// Generate direction vectors on the host and copy to the device
|
||||
if (typeid(Real) == typeid(float)) {
|
||||
curandDirectionVectors32_t *rngDirections;
|
||||
curandStatus_t curandResult = curandGetDirectionVectors32(&rngDirections, CURAND_DIRECTION_VECTORS_32_JOEKUO6);
|
||||
|
||||
if (curandResult != CURAND_STATUS_SUCCESS) {
|
||||
string msg("Could not get direction vectors for quasi-random number "
|
||||
"generator: ");
|
||||
msg += curandResult;
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
cudaResult =
|
||||
cudaMemcpy(d_rngDirections, rngDirections, 2 * sizeof(curandDirectionVectors32_t), cudaMemcpyHostToDevice);
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not copy direction vectors to device: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
}
|
||||
else if (typeid(Real) == typeid(double)) {
|
||||
curandDirectionVectors64_t *rngDirections;
|
||||
curandStatus_t curandResult = curandGetDirectionVectors64(&rngDirections, CURAND_DIRECTION_VECTORS_64_JOEKUO6);
|
||||
|
||||
if (curandResult != CURAND_STATUS_SUCCESS) {
|
||||
string msg("Could not get direction vectors for quasi-random number "
|
||||
"generator: ");
|
||||
msg += curandResult;
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
cudaResult =
|
||||
cudaMemcpy(d_rngDirections, rngDirections, 2 * sizeof(curandDirectionVectors64_t), cudaMemcpyHostToDevice);
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not copy direction vectors to device: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
}
|
||||
else {
|
||||
string msg("Could not get direction vectors for random number generator of "
|
||||
"specified type");
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
// Initialise RNG
|
||||
initRNG<<<grid, block>>>(d_rngStates, d_rngDirections, m_numSims);
|
||||
|
||||
// Count the points inside unit quarter-circle
|
||||
computeValue<Real><<<grid, block, block.x * sizeof(unsigned int)>>>(d_results, d_rngStates, m_numSims);
|
||||
|
||||
// Copy partial results back
|
||||
vector<unsigned int> results(grid.x);
|
||||
cudaResult = cudaMemcpy(&results[0], d_results, grid.x * sizeof(unsigned int), cudaMemcpyDeviceToHost);
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not copy partial results to host: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
// Complete sum-reduction on host
|
||||
Real value = static_cast<Real>(std::accumulate(results.begin(), results.end(), 0));
|
||||
|
||||
// Determine the proportion of points inside the quarter-circle,
|
||||
// i.e. the area of the unit quarter-circle
|
||||
value /= m_numSims;
|
||||
|
||||
// Value is currently an estimate of the area of a unit quarter-circle, so we
|
||||
// can scale to a full circle by multiplying by four. Now since the area of a
|
||||
// circle is pi * r^2, and r is one, the value will be an estimate for the
|
||||
// value of pi.
|
||||
value *= 4;
|
||||
|
||||
// Cleanup
|
||||
if (d_rngStates) {
|
||||
cudaFree(d_rngStates);
|
||||
d_rngStates = 0;
|
||||
}
|
||||
|
||||
if (d_rngDirections) {
|
||||
cudaFree(d_rngDirections);
|
||||
d_rngDirections = 0;
|
||||
}
|
||||
|
||||
if (d_results) {
|
||||
cudaFree(d_results);
|
||||
d_results = 0;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
// Explicit template instantiation
|
||||
|
||||
@@ -28,84 +28,84 @@
|
||||
|
||||
#include "../inc/test.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <stdexcept>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
#include <typeinfo>
|
||||
#include <stdio.h>
|
||||
#include <helper_timer.h>
|
||||
#include <cuda_runtime.h>
|
||||
|
||||
#include <helper_timer.h>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <math.h>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <stdio.h>
|
||||
#include <typeinfo>
|
||||
|
||||
#include "../inc/piestimator.h"
|
||||
|
||||
template <typename Real>
|
||||
bool Test<Real>::operator()() {
|
||||
using std::endl;
|
||||
using std::setw;
|
||||
using std::stringstream;
|
||||
template <typename Real> bool Test<Real>::operator()()
|
||||
{
|
||||
using std::endl;
|
||||
using std::setw;
|
||||
using std::stringstream;
|
||||
|
||||
StopWatchInterface *timer = NULL;
|
||||
sdkCreateTimer(&timer);
|
||||
StopWatchInterface *timer = NULL;
|
||||
sdkCreateTimer(&timer);
|
||||
|
||||
// Get device properties
|
||||
struct cudaDeviceProp deviceProperties;
|
||||
cudaError_t cudaResult = cudaGetDeviceProperties(&deviceProperties, device);
|
||||
// Get device properties
|
||||
struct cudaDeviceProp deviceProperties;
|
||||
cudaError_t cudaResult = cudaGetDeviceProperties(&deviceProperties, device);
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
std::string msg("Could not get device properties: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
if (cudaResult != cudaSuccess) {
|
||||
std::string msg("Could not get device properties: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
// Evaluate on GPU
|
||||
printf("Estimating Pi on GPU (%s)\n\n", deviceProperties.name);
|
||||
PiEstimator<Real> estimator(numSims, device, threadBlockSize);
|
||||
sdkStartTimer(&timer);
|
||||
Real result = estimator();
|
||||
sdkStopTimer(&timer);
|
||||
elapsedTime = sdkGetAverageTimerValue(&timer) / 1000.0f;
|
||||
// Evaluate on GPU
|
||||
printf("Estimating Pi on GPU (%s)\n\n", deviceProperties.name);
|
||||
PiEstimator<Real> estimator(numSims, device, threadBlockSize);
|
||||
sdkStartTimer(&timer);
|
||||
Real result = estimator();
|
||||
sdkStopTimer(&timer);
|
||||
elapsedTime = sdkGetAverageTimerValue(&timer) / 1000.0f;
|
||||
|
||||
// Tolerance to compare result with expected
|
||||
// This is just to check that nothing has gone very wrong with the
|
||||
// test, the actual accuracy of the result depends on the number of
|
||||
// Monte Carlo trials
|
||||
const Real tolerance = static_cast<Real>(0.01);
|
||||
// Tolerance to compare result with expected
|
||||
// This is just to check that nothing has gone very wrong with the
|
||||
// test, the actual accuracy of the result depends on the number of
|
||||
// Monte Carlo trials
|
||||
const Real tolerance = static_cast<Real>(0.01);
|
||||
|
||||
// Display results
|
||||
Real abserror = fabs(result - static_cast<Real>(PI));
|
||||
Real relerror = abserror / static_cast<Real>(PI);
|
||||
printf("Precision: %s\n",
|
||||
(typeid(Real) == typeid(double)) ? "double" : "single");
|
||||
printf("Number of sims: %d\n", numSims);
|
||||
printf("Tolerance: %e\n", tolerance);
|
||||
printf("GPU result: %e\n", result);
|
||||
printf("Expected: %e\n", PI);
|
||||
printf("Absolute error: %e\n", abserror);
|
||||
printf("Relative error: %e\n\n", relerror);
|
||||
// Display results
|
||||
Real abserror = fabs(result - static_cast<Real>(PI));
|
||||
Real relerror = abserror / static_cast<Real>(PI);
|
||||
printf("Precision: %s\n", (typeid(Real) == typeid(double)) ? "double" : "single");
|
||||
printf("Number of sims: %d\n", numSims);
|
||||
printf("Tolerance: %e\n", tolerance);
|
||||
printf("GPU result: %e\n", result);
|
||||
printf("Expected: %e\n", PI);
|
||||
printf("Absolute error: %e\n", abserror);
|
||||
printf("Relative error: %e\n\n", relerror);
|
||||
|
||||
// Check result
|
||||
if (relerror > tolerance) {
|
||||
printf("computed result (%e) does not match expected result (%e).\n",
|
||||
result, PI);
|
||||
pass = false;
|
||||
} else {
|
||||
pass = true;
|
||||
}
|
||||
// Check result
|
||||
if (relerror > tolerance) {
|
||||
printf("computed result (%e) does not match expected result (%e).\n", result, PI);
|
||||
pass = false;
|
||||
}
|
||||
else {
|
||||
pass = true;
|
||||
}
|
||||
|
||||
// Print results
|
||||
printf(
|
||||
"MonteCarloEstimatePiInlineQ, Performance = %.2f sims/s, Time = "
|
||||
"%.2f(ms), NumDevsUsed = %u, Blocksize = %u\n",
|
||||
numSims / elapsedTime, elapsedTime * 1000.0f, 1, threadBlockSize);
|
||||
// Print results
|
||||
printf("MonteCarloEstimatePiInlineQ, Performance = %.2f sims/s, Time = "
|
||||
"%.2f(ms), NumDevsUsed = %u, Blocksize = %u\n",
|
||||
numSims / elapsedTime,
|
||||
elapsedTime * 1000.0f,
|
||||
1,
|
||||
threadBlockSize);
|
||||
|
||||
sdkDeleteTimer(&timer);
|
||||
sdkDeleteTimer(&timer);
|
||||
|
||||
return pass;
|
||||
return pass;
|
||||
}
|
||||
|
||||
// Explicit template instantiation
|
||||
|
||||
@@ -65,25 +65,27 @@
|
||||
|
||||
// This is the un-specialized struct. Note that we prevent instantiation of
|
||||
// this struct by making it abstract (i.e. with pure virtual methods).
|
||||
template <typename T>
|
||||
struct SharedMemory {
|
||||
// Ensure that we won't compile any un-specialized types
|
||||
virtual __device__ T &operator*() = 0;
|
||||
virtual __device__ T &operator[](int i) = 0;
|
||||
template <typename T> struct SharedMemory
|
||||
{
|
||||
// Ensure that we won't compile any un-specialized types
|
||||
virtual __device__ T &operator*() = 0;
|
||||
virtual __device__ T &operator[](int i) = 0;
|
||||
};
|
||||
|
||||
#define BUILD_SHAREDMEMORY_TYPE(t, n) \
|
||||
template <> \
|
||||
struct SharedMemory<t> { \
|
||||
__device__ t &operator*() { \
|
||||
extern __shared__ t n[]; \
|
||||
return *n; \
|
||||
} \
|
||||
__device__ t &operator[](int i) { \
|
||||
extern __shared__ t n[]; \
|
||||
return n[i]; \
|
||||
} \
|
||||
}
|
||||
#define BUILD_SHAREDMEMORY_TYPE(t, n) \
|
||||
template <> struct SharedMemory<t> \
|
||||
{ \
|
||||
__device__ t &operator*() \
|
||||
{ \
|
||||
extern __shared__ t n[]; \
|
||||
return *n; \
|
||||
} \
|
||||
__device__ t &operator[](int i) \
|
||||
{ \
|
||||
extern __shared__ t n[]; \
|
||||
return n[i]; \
|
||||
} \
|
||||
}
|
||||
|
||||
BUILD_SHAREDMEMORY_TYPE(int, s_int);
|
||||
BUILD_SHAREDMEMORY_TYPE(unsigned int, s_uint);
|
||||
|
||||
@@ -28,18 +28,17 @@
|
||||
#ifndef PIESTIMATOR_H
|
||||
#define PIESTIMATOR_H
|
||||
|
||||
template <typename Real>
|
||||
class PiEstimator {
|
||||
public:
|
||||
PiEstimator(unsigned int numSims, unsigned int device,
|
||||
unsigned int threadBlockSize, unsigned int seed);
|
||||
Real operator()();
|
||||
template <typename Real> class PiEstimator
|
||||
{
|
||||
public:
|
||||
PiEstimator(unsigned int numSims, unsigned int device, unsigned int threadBlockSize, unsigned int seed);
|
||||
Real operator()();
|
||||
|
||||
private:
|
||||
unsigned int m_seed;
|
||||
unsigned int m_numSims;
|
||||
unsigned int m_device;
|
||||
unsigned int m_threadBlockSize;
|
||||
private:
|
||||
unsigned int m_seed;
|
||||
unsigned int m_numSims;
|
||||
unsigned int m_device;
|
||||
unsigned int m_threadBlockSize;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -28,30 +28,31 @@
|
||||
#ifndef TEST_H
|
||||
#define TEST_H
|
||||
|
||||
template <typename Real>
|
||||
struct Test {
|
||||
Test() : pass(false){};
|
||||
template <typename Real> struct Test
|
||||
{
|
||||
Test()
|
||||
: pass(false) {};
|
||||
|
||||
int device;
|
||||
unsigned int numSims;
|
||||
unsigned int threadBlockSize;
|
||||
unsigned int seed;
|
||||
int device;
|
||||
unsigned int numSims;
|
||||
unsigned int threadBlockSize;
|
||||
unsigned int seed;
|
||||
|
||||
bool pass;
|
||||
double elapsedTime;
|
||||
bool pass;
|
||||
double elapsedTime;
|
||||
|
||||
bool operator()();
|
||||
bool operator()();
|
||||
};
|
||||
|
||||
// Defaults are arbitrary to give sensible runtime
|
||||
#define k_sims_min 100000
|
||||
#define k_sims_max 10000000
|
||||
#define k_sims_def 100000
|
||||
#define k_sims_qa 100000
|
||||
#define k_sims_min 100000
|
||||
#define k_sims_max 10000000
|
||||
#define k_sims_def 100000
|
||||
#define k_sims_qa 100000
|
||||
#define k_bsize_min 32
|
||||
#define k_bsize_def 128
|
||||
#define k_bsize_qa 128
|
||||
#define k_seed_def 1234
|
||||
#define k_bsize_qa 128
|
||||
#define k_seed_def 1234
|
||||
|
||||
// Target value
|
||||
#define PI 3.14159265359
|
||||
|
||||
@@ -39,13 +39,13 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <stdexcept>
|
||||
#include <cuda_runtime.h>
|
||||
#include <helper_timer.h>
|
||||
#include <helper_cuda.h>
|
||||
#include <helper_timer.h>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <math.h>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "../inc/test.h"
|
||||
|
||||
@@ -53,198 +53,203 @@
|
||||
static const char *printfFile = "MonteCarloEstimatePiP.txt";
|
||||
|
||||
// Forward declarations
|
||||
void showHelp(const int argc, const char **argv);
|
||||
template <typename Real>
|
||||
void runTest(int argc, const char **argv);
|
||||
void showHelp(const int argc, const char **argv);
|
||||
template <typename Real> void runTest(int argc, const char **argv);
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
using std::invalid_argument;
|
||||
using std::string;
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
using std::invalid_argument;
|
||||
using std::string;
|
||||
|
||||
// Open the log file
|
||||
printf("Monte Carlo Estimate Pi (with batch PRNG)\n");
|
||||
printf("=========================================\n\n");
|
||||
// Open the log file
|
||||
printf("Monte Carlo Estimate Pi (with batch PRNG)\n");
|
||||
printf("=========================================\n\n");
|
||||
|
||||
// If help flag is set, display help and exit immediately
|
||||
if (checkCmdLineFlag(argc, (const char **)argv, "help")) {
|
||||
printf("Displaying help on console\n");
|
||||
showHelp(argc, (const char **)argv);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
// Check the precision (checked against the device capability later)
|
||||
try {
|
||||
char *value;
|
||||
|
||||
if (getCmdLineArgumentString(argc, (const char **)argv, "precision",
|
||||
&value)) {
|
||||
// Check requested precision is valid
|
||||
string prec(value);
|
||||
|
||||
if (prec.compare("single") == 0 || prec.compare("\"single\"") == 0) {
|
||||
runTest<float>(argc, (const char **)argv);
|
||||
} else if (prec.compare("double") == 0 ||
|
||||
prec.compare("\"double\"") == 0) {
|
||||
runTest<double>(argc, (const char **)argv);
|
||||
} else {
|
||||
printf("specified precision (%s) is invalid, must be \"single\".\n",
|
||||
value);
|
||||
throw invalid_argument("precision");
|
||||
}
|
||||
} else {
|
||||
runTest<float>(argc, (const char **)argv);
|
||||
// If help flag is set, display help and exit immediately
|
||||
if (checkCmdLineFlag(argc, (const char **)argv, "help")) {
|
||||
printf("Displaying help on console\n");
|
||||
showHelp(argc, (const char **)argv);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
} catch (invalid_argument &e) {
|
||||
printf("invalid command line argument (%s)\n", e.what());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Finish
|
||||
exit(EXIT_SUCCESS);
|
||||
// Check the precision (checked against the device capability later)
|
||||
try {
|
||||
char *value;
|
||||
|
||||
if (getCmdLineArgumentString(argc, (const char **)argv, "precision", &value)) {
|
||||
// Check requested precision is valid
|
||||
string prec(value);
|
||||
|
||||
if (prec.compare("single") == 0 || prec.compare("\"single\"") == 0) {
|
||||
runTest<float>(argc, (const char **)argv);
|
||||
}
|
||||
else if (prec.compare("double") == 0 || prec.compare("\"double\"") == 0) {
|
||||
runTest<double>(argc, (const char **)argv);
|
||||
}
|
||||
else {
|
||||
printf("specified precision (%s) is invalid, must be \"single\".\n", value);
|
||||
throw invalid_argument("precision");
|
||||
}
|
||||
}
|
||||
else {
|
||||
runTest<float>(argc, (const char **)argv);
|
||||
}
|
||||
}
|
||||
catch (invalid_argument &e) {
|
||||
printf("invalid command line argument (%s)\n", e.what());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Finish
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
template <typename Real>
|
||||
void runTest(int argc, const char **argv) {
|
||||
using std::invalid_argument;
|
||||
using std::runtime_error;
|
||||
template <typename Real> void runTest(int argc, const char **argv)
|
||||
{
|
||||
using std::invalid_argument;
|
||||
using std::runtime_error;
|
||||
|
||||
try {
|
||||
Test<Real> test;
|
||||
int deviceCount = 0;
|
||||
cudaError_t cudaResult = cudaSuccess;
|
||||
try {
|
||||
Test<Real> test;
|
||||
int deviceCount = 0;
|
||||
cudaError_t cudaResult = cudaSuccess;
|
||||
|
||||
// by default specify GPU Device == 0
|
||||
test.device = 0;
|
||||
// by default specify GPU Device == 0
|
||||
test.device = 0;
|
||||
|
||||
// Get number of available devices
|
||||
cudaResult = cudaGetDeviceCount(&deviceCount);
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
printf("could not get device count.\n");
|
||||
throw runtime_error("cudaGetDeviceCount");
|
||||
}
|
||||
|
||||
// (default parameters)
|
||||
test.numSims = k_sims_qa;
|
||||
test.threadBlockSize = k_bsize_qa;
|
||||
test.seed = k_seed_def;
|
||||
|
||||
{
|
||||
char *value = 0;
|
||||
|
||||
if (getCmdLineArgumentString(argc, argv, "device", &value)) {
|
||||
test.device = (int)atoi(value);
|
||||
|
||||
if (test.device >= deviceCount) {
|
||||
printf(
|
||||
"invalid target device specified on command line (device %d does "
|
||||
"not exist).\n",
|
||||
test.device);
|
||||
throw invalid_argument("device");
|
||||
}
|
||||
} else {
|
||||
test.device = gpuGetMaxGflopsDeviceId();
|
||||
}
|
||||
|
||||
if (getCmdLineArgumentString(argc, argv, "sims", &value)) {
|
||||
test.numSims = (unsigned int)atoi(value);
|
||||
|
||||
if (test.numSims < k_sims_min || test.numSims > k_sims_max) {
|
||||
printf(
|
||||
"specified number of simulations (%d) is invalid, must be "
|
||||
"between %d and %d.\n",
|
||||
test.numSims, k_sims_min, k_sims_max);
|
||||
throw invalid_argument("sims");
|
||||
}
|
||||
} else {
|
||||
test.numSims = k_sims_def;
|
||||
}
|
||||
|
||||
if (getCmdLineArgumentString(argc, argv, "block-size", &value)) {
|
||||
// Determine max threads per block
|
||||
cudaDeviceProp deviceProperties;
|
||||
cudaResult = cudaGetDeviceProperties(&deviceProperties, test.device);
|
||||
// Get number of available devices
|
||||
cudaResult = cudaGetDeviceCount(&deviceCount);
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
printf("cound not get device properties for device %d.\n",
|
||||
test.device);
|
||||
throw runtime_error("cudaGetDeviceProperties");
|
||||
printf("could not get device count.\n");
|
||||
throw runtime_error("cudaGetDeviceCount");
|
||||
}
|
||||
|
||||
// Check requested size is valid
|
||||
test.threadBlockSize = (unsigned int)atoi(value);
|
||||
// (default parameters)
|
||||
test.numSims = k_sims_qa;
|
||||
test.threadBlockSize = k_bsize_qa;
|
||||
test.seed = k_seed_def;
|
||||
|
||||
if (test.threadBlockSize < k_bsize_min ||
|
||||
test.threadBlockSize > static_cast<unsigned int>(
|
||||
deviceProperties.maxThreadsPerBlock)) {
|
||||
printf(
|
||||
"specified block size (%d) is invalid, must be between %d and %d "
|
||||
"for device %d.\n",
|
||||
test.threadBlockSize, k_bsize_min,
|
||||
deviceProperties.maxThreadsPerBlock, test.device);
|
||||
throw invalid_argument("block-size");
|
||||
{
|
||||
char *value = 0;
|
||||
|
||||
if (getCmdLineArgumentString(argc, argv, "device", &value)) {
|
||||
test.device = (int)atoi(value);
|
||||
|
||||
if (test.device >= deviceCount) {
|
||||
printf("invalid target device specified on command line (device %d does "
|
||||
"not exist).\n",
|
||||
test.device);
|
||||
throw invalid_argument("device");
|
||||
}
|
||||
}
|
||||
else {
|
||||
test.device = gpuGetMaxGflopsDeviceId();
|
||||
}
|
||||
|
||||
if (getCmdLineArgumentString(argc, argv, "sims", &value)) {
|
||||
test.numSims = (unsigned int)atoi(value);
|
||||
|
||||
if (test.numSims < k_sims_min || test.numSims > k_sims_max) {
|
||||
printf("specified number of simulations (%d) is invalid, must be "
|
||||
"between %d and %d.\n",
|
||||
test.numSims,
|
||||
k_sims_min,
|
||||
k_sims_max);
|
||||
throw invalid_argument("sims");
|
||||
}
|
||||
}
|
||||
else {
|
||||
test.numSims = k_sims_def;
|
||||
}
|
||||
|
||||
if (getCmdLineArgumentString(argc, argv, "block-size", &value)) {
|
||||
// Determine max threads per block
|
||||
cudaDeviceProp deviceProperties;
|
||||
cudaResult = cudaGetDeviceProperties(&deviceProperties, test.device);
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
printf("cound not get device properties for device %d.\n", test.device);
|
||||
throw runtime_error("cudaGetDeviceProperties");
|
||||
}
|
||||
|
||||
// Check requested size is valid
|
||||
test.threadBlockSize = (unsigned int)atoi(value);
|
||||
|
||||
if (test.threadBlockSize < k_bsize_min
|
||||
|| test.threadBlockSize > static_cast<unsigned int>(deviceProperties.maxThreadsPerBlock)) {
|
||||
printf("specified block size (%d) is invalid, must be between %d and %d "
|
||||
"for device %d.\n",
|
||||
test.threadBlockSize,
|
||||
k_bsize_min,
|
||||
deviceProperties.maxThreadsPerBlock,
|
||||
test.device);
|
||||
throw invalid_argument("block-size");
|
||||
}
|
||||
|
||||
if (test.threadBlockSize & test.threadBlockSize - 1) {
|
||||
printf("specified block size (%d) is invalid, must be a power of two "
|
||||
"(see reduction function).\n",
|
||||
test.threadBlockSize);
|
||||
throw invalid_argument("block-size");
|
||||
}
|
||||
}
|
||||
else {
|
||||
test.threadBlockSize = k_bsize_def;
|
||||
}
|
||||
|
||||
if (getCmdLineArgumentString(argc, argv, "seed", &value)) {
|
||||
// Check requested seed is valid
|
||||
test.seed = (unsigned int)atoi(value);
|
||||
|
||||
if (test.seed == 0) {
|
||||
printf("specified seed (%d) is invalid, must be non-zero.\n", test.seed);
|
||||
throw invalid_argument("seed");
|
||||
}
|
||||
}
|
||||
else {
|
||||
test.seed = k_seed_def;
|
||||
}
|
||||
}
|
||||
|
||||
if (test.threadBlockSize & test.threadBlockSize - 1) {
|
||||
printf(
|
||||
"specified block size (%d) is invalid, must be a power of two "
|
||||
"(see reduction function).\n",
|
||||
test.threadBlockSize);
|
||||
throw invalid_argument("block-size");
|
||||
}
|
||||
} else {
|
||||
test.threadBlockSize = k_bsize_def;
|
||||
}
|
||||
// Execute
|
||||
test();
|
||||
}
|
||||
catch (invalid_argument &e) {
|
||||
printf("invalid command line argument (%s)\n", e.what());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
catch (runtime_error &e) {
|
||||
printf("runtime error (%s)\n", e.what());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (getCmdLineArgumentString(argc, argv, "seed", &value)) {
|
||||
// Check requested seed is valid
|
||||
test.seed = (unsigned int)atoi(value);
|
||||
void showHelp(int argc, const char **argv)
|
||||
{
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
using std::left;
|
||||
using std::setw;
|
||||
|
||||
if (test.seed == 0) {
|
||||
printf("specified seed (%d) is invalid, must be non-zero.\n",
|
||||
test.seed);
|
||||
throw invalid_argument("seed");
|
||||
}
|
||||
} else {
|
||||
test.seed = k_seed_def;
|
||||
}
|
||||
if (argc > 0) {
|
||||
cout << endl << argv[0] << endl;
|
||||
}
|
||||
|
||||
// Execute
|
||||
test();
|
||||
} catch (invalid_argument &e) {
|
||||
printf("invalid command line argument (%s)\n", e.what());
|
||||
exit(EXIT_FAILURE);
|
||||
} catch (runtime_error &e) {
|
||||
printf("runtime error (%s)\n", e.what());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
void showHelp(int argc, const char **argv) {
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
using std::left;
|
||||
using std::setw;
|
||||
|
||||
if (argc > 0) {
|
||||
cout << endl << argv[0] << endl;
|
||||
}
|
||||
|
||||
cout << endl << "Syntax:" << endl;
|
||||
cout << left;
|
||||
cout << " " << setw(20) << "--device=<device>"
|
||||
<< "Specify device to use for execution" << endl;
|
||||
cout << " " << setw(20) << "--sims=<N>"
|
||||
<< "Specify number of Monte Carlo simulations" << endl;
|
||||
cout << " " << setw(20) << "--block-size=<N>"
|
||||
<< "Specify number of threads per block" << endl;
|
||||
cout << " " << setw(20) << "--seed=<N>"
|
||||
<< "Specify the seed to use for the random number generator" << endl;
|
||||
cout << " " << setw(20) << "--precision=<P>"
|
||||
<< "Specify the precision (\"single\" or \"double\")" << endl;
|
||||
cout << endl;
|
||||
cout << " " << setw(20) << "--noprompt"
|
||||
<< "Skip prompt before exit" << endl;
|
||||
cout << endl;
|
||||
cout << endl << "Syntax:" << endl;
|
||||
cout << left;
|
||||
cout << " " << setw(20) << "--device=<device>"
|
||||
<< "Specify device to use for execution" << endl;
|
||||
cout << " " << setw(20) << "--sims=<N>"
|
||||
<< "Specify number of Monte Carlo simulations" << endl;
|
||||
cout << " " << setw(20) << "--block-size=<N>"
|
||||
<< "Specify number of threads per block" << endl;
|
||||
cout << " " << setw(20) << "--seed=<N>"
|
||||
<< "Specify the seed to use for the random number generator" << endl;
|
||||
cout << " " << setw(20) << "--precision=<P>"
|
||||
<< "Specify the precision (\"single\" or \"double\")" << endl;
|
||||
cout << endl;
|
||||
cout << " " << setw(20) << "--noprompt"
|
||||
<< "Skip prompt before exit" << endl;
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
@@ -25,15 +25,15 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "../inc/piestimator.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cooperative_groups.h>
|
||||
#include <cuda_runtime.h>
|
||||
#include <numeric>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <typeinfo>
|
||||
#include <cuda_runtime.h>
|
||||
#include <cooperative_groups.h>
|
||||
#include <vector>
|
||||
|
||||
#include "../inc/piestimator.h"
|
||||
|
||||
namespace cg = cooperative_groups;
|
||||
#include <curand.h>
|
||||
@@ -41,251 +41,249 @@ namespace cg = cooperative_groups;
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
__device__ unsigned int reduce_sum(unsigned int in, cg::thread_block cta) {
|
||||
extern __shared__ unsigned int sdata[];
|
||||
__device__ unsigned int reduce_sum(unsigned int in, cg::thread_block cta)
|
||||
{
|
||||
extern __shared__ unsigned int sdata[];
|
||||
|
||||
// Perform first level of reduction:
|
||||
// - Write to shared memory
|
||||
unsigned int ltid = threadIdx.x;
|
||||
// Perform first level of reduction:
|
||||
// - Write to shared memory
|
||||
unsigned int ltid = threadIdx.x;
|
||||
|
||||
sdata[ltid] = in;
|
||||
cg::sync(cta);
|
||||
sdata[ltid] = in;
|
||||
cg::sync(cta);
|
||||
|
||||
// Do reduction in shared mem
|
||||
for (unsigned int s = blockDim.x / 2; s > 0; s >>= 1) {
|
||||
if (ltid < s) {
|
||||
sdata[ltid] += sdata[ltid + s];
|
||||
// Do reduction in shared mem
|
||||
for (unsigned int s = blockDim.x / 2; s > 0; s >>= 1) {
|
||||
if (ltid < s) {
|
||||
sdata[ltid] += sdata[ltid + s];
|
||||
}
|
||||
|
||||
cg::sync(cta);
|
||||
}
|
||||
|
||||
cg::sync(cta);
|
||||
}
|
||||
|
||||
return sdata[0];
|
||||
return sdata[0];
|
||||
}
|
||||
|
||||
// Estimator kernel
|
||||
template <typename Real>
|
||||
__global__ void computeValue(unsigned int *const results,
|
||||
const Real *const points,
|
||||
const unsigned int numSims) {
|
||||
// Handle to thread block group
|
||||
cg::thread_block cta = cg::this_thread_block();
|
||||
// Determine thread ID
|
||||
unsigned int bid = blockIdx.x;
|
||||
unsigned int tid = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
unsigned int step = gridDim.x * blockDim.x;
|
||||
__global__ void computeValue(unsigned int *const results, const Real *const points, const unsigned int numSims)
|
||||
{
|
||||
// Handle to thread block group
|
||||
cg::thread_block cta = cg::this_thread_block();
|
||||
// Determine thread ID
|
||||
unsigned int bid = blockIdx.x;
|
||||
unsigned int tid = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
unsigned int step = gridDim.x * blockDim.x;
|
||||
|
||||
// Shift the input/output pointers
|
||||
const Real *pointx = points + tid;
|
||||
const Real *pointy = pointx + numSims;
|
||||
// Shift the input/output pointers
|
||||
const Real *pointx = points + tid;
|
||||
const Real *pointy = pointx + numSims;
|
||||
|
||||
// Count the number of points which lie inside the unit quarter-circle
|
||||
unsigned int pointsInside = 0;
|
||||
// Count the number of points which lie inside the unit quarter-circle
|
||||
unsigned int pointsInside = 0;
|
||||
|
||||
for (unsigned int i = tid; i < numSims;
|
||||
i += step, pointx += step, pointy += step) {
|
||||
Real x = *pointx;
|
||||
Real y = *pointy;
|
||||
Real l2norm2 = x * x + y * y;
|
||||
for (unsigned int i = tid; i < numSims; i += step, pointx += step, pointy += step) {
|
||||
Real x = *pointx;
|
||||
Real y = *pointy;
|
||||
Real l2norm2 = x * x + y * y;
|
||||
|
||||
if (l2norm2 < static_cast<Real>(1)) {
|
||||
pointsInside++;
|
||||
if (l2norm2 < static_cast<Real>(1)) {
|
||||
pointsInside++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Reduce within the block
|
||||
pointsInside = reduce_sum(pointsInside, cta);
|
||||
// Reduce within the block
|
||||
pointsInside = reduce_sum(pointsInside, cta);
|
||||
|
||||
// Store the result
|
||||
if (threadIdx.x == 0) {
|
||||
results[bid] = pointsInside;
|
||||
}
|
||||
// Store the result
|
||||
if (threadIdx.x == 0) {
|
||||
results[bid] = pointsInside;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Real>
|
||||
PiEstimator<Real>::PiEstimator(unsigned int numSims, unsigned int device,
|
||||
unsigned int threadBlockSize, unsigned int seed)
|
||||
: m_numSims(numSims),
|
||||
m_device(device),
|
||||
m_threadBlockSize(threadBlockSize),
|
||||
m_seed(seed) {}
|
||||
PiEstimator<Real>::PiEstimator(unsigned int numSims,
|
||||
unsigned int device,
|
||||
unsigned int threadBlockSize,
|
||||
unsigned int seed)
|
||||
: m_numSims(numSims)
|
||||
, m_device(device)
|
||||
, m_threadBlockSize(threadBlockSize)
|
||||
, m_seed(seed)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename Real>
|
||||
Real PiEstimator<Real>::operator()() {
|
||||
cudaError_t cudaResult = cudaSuccess;
|
||||
struct cudaDeviceProp deviceProperties;
|
||||
struct cudaFuncAttributes funcAttributes;
|
||||
template <typename Real> Real PiEstimator<Real>::operator()()
|
||||
{
|
||||
cudaError_t cudaResult = cudaSuccess;
|
||||
struct cudaDeviceProp deviceProperties;
|
||||
struct cudaFuncAttributes funcAttributes;
|
||||
|
||||
// Get device properties
|
||||
cudaResult = cudaGetDeviceProperties(&deviceProperties, m_device);
|
||||
// Get device properties
|
||||
cudaResult = cudaGetDeviceProperties(&deviceProperties, m_device);
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not get device properties: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not get device properties: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
// Check precision is valid
|
||||
if (typeid(Real) == typeid(double) &&
|
||||
(deviceProperties.major < 1 ||
|
||||
(deviceProperties.major == 1 && deviceProperties.minor < 3))) {
|
||||
throw std::runtime_error("Device does not have double precision support");
|
||||
}
|
||||
// Check precision is valid
|
||||
if (typeid(Real) == typeid(double)
|
||||
&& (deviceProperties.major < 1 || (deviceProperties.major == 1 && deviceProperties.minor < 3))) {
|
||||
throw std::runtime_error("Device does not have double precision support");
|
||||
}
|
||||
|
||||
// Attach to GPU
|
||||
cudaResult = cudaSetDevice(m_device);
|
||||
// Attach to GPU
|
||||
cudaResult = cudaSetDevice(m_device);
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not set CUDA device: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not set CUDA device: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
// Determine how to divide the work between cores
|
||||
dim3 block;
|
||||
dim3 grid;
|
||||
block.x = m_threadBlockSize;
|
||||
grid.x = (m_numSims + m_threadBlockSize - 1) / m_threadBlockSize;
|
||||
// Determine how to divide the work between cores
|
||||
dim3 block;
|
||||
dim3 grid;
|
||||
block.x = m_threadBlockSize;
|
||||
grid.x = (m_numSims + m_threadBlockSize - 1) / m_threadBlockSize;
|
||||
|
||||
// Aim to launch around ten or more times as many blocks as there
|
||||
// are multiprocessors on the target device.
|
||||
unsigned int blocksPerSM = 10;
|
||||
unsigned int numSMs = deviceProperties.multiProcessorCount;
|
||||
// Aim to launch around ten or more times as many blocks as there
|
||||
// are multiprocessors on the target device.
|
||||
unsigned int blocksPerSM = 10;
|
||||
unsigned int numSMs = deviceProperties.multiProcessorCount;
|
||||
|
||||
while (grid.x > 2 * blocksPerSM * numSMs) {
|
||||
grid.x >>= 1;
|
||||
}
|
||||
while (grid.x > 2 * blocksPerSM * numSMs) {
|
||||
grid.x >>= 1;
|
||||
}
|
||||
|
||||
// Get computeValue function properties and check the maximum block size
|
||||
cudaResult = cudaFuncGetAttributes(&funcAttributes, computeValue<Real>);
|
||||
// Get computeValue function properties and check the maximum block size
|
||||
cudaResult = cudaFuncGetAttributes(&funcAttributes, computeValue<Real>);
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not get function attributes: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not get function attributes: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
if (block.x > (unsigned int)funcAttributes.maxThreadsPerBlock) {
|
||||
throw std::runtime_error(
|
||||
"Block X dimension is too large for computeValue kernel");
|
||||
}
|
||||
if (block.x > (unsigned int)funcAttributes.maxThreadsPerBlock) {
|
||||
throw std::runtime_error("Block X dimension is too large for computeValue kernel");
|
||||
}
|
||||
|
||||
// Check the dimensions are valid
|
||||
if (block.x > (unsigned int)deviceProperties.maxThreadsDim[0]) {
|
||||
throw std::runtime_error("Block X dimension is too large for device");
|
||||
}
|
||||
// Check the dimensions are valid
|
||||
if (block.x > (unsigned int)deviceProperties.maxThreadsDim[0]) {
|
||||
throw std::runtime_error("Block X dimension is too large for device");
|
||||
}
|
||||
|
||||
if (grid.x > (unsigned int)deviceProperties.maxGridSize[0]) {
|
||||
throw std::runtime_error("Grid X dimension is too large for device");
|
||||
}
|
||||
if (grid.x > (unsigned int)deviceProperties.maxGridSize[0]) {
|
||||
throw std::runtime_error("Grid X dimension is too large for device");
|
||||
}
|
||||
|
||||
// Allocate memory for points
|
||||
// Each simulation has two random numbers to give X and Y coordinate
|
||||
Real *d_points = 0;
|
||||
cudaResult = cudaMalloc((void **)&d_points, 2 * m_numSims * sizeof(Real));
|
||||
// Allocate memory for points
|
||||
// Each simulation has two random numbers to give X and Y coordinate
|
||||
Real *d_points = 0;
|
||||
cudaResult = cudaMalloc((void **)&d_points, 2 * m_numSims * sizeof(Real));
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not allocate memory on device for random numbers: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not allocate memory on device for random numbers: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
// Allocate memory for result
|
||||
// Each thread block will produce one result
|
||||
unsigned int *d_results = 0;
|
||||
cudaResult = cudaMalloc((void **)&d_results, grid.x * sizeof(unsigned int));
|
||||
// Allocate memory for result
|
||||
// Each thread block will produce one result
|
||||
unsigned int *d_results = 0;
|
||||
cudaResult = cudaMalloc((void **)&d_results, grid.x * sizeof(unsigned int));
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not allocate memory on device for partial results: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not allocate memory on device for partial results: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
// Generate random points in unit square
|
||||
curandStatus_t curandResult;
|
||||
curandGenerator_t prng;
|
||||
curandResult = curandCreateGenerator(&prng, CURAND_RNG_PSEUDO_DEFAULT);
|
||||
// Generate random points in unit square
|
||||
curandStatus_t curandResult;
|
||||
curandGenerator_t prng;
|
||||
curandResult = curandCreateGenerator(&prng, CURAND_RNG_PSEUDO_DEFAULT);
|
||||
|
||||
if (curandResult != CURAND_STATUS_SUCCESS) {
|
||||
string msg("Could not create pseudo-random number generator: ");
|
||||
msg += curandResult;
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
if (curandResult != CURAND_STATUS_SUCCESS) {
|
||||
string msg("Could not create pseudo-random number generator: ");
|
||||
msg += curandResult;
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
curandResult = curandSetPseudoRandomGeneratorSeed(prng, m_seed);
|
||||
curandResult = curandSetPseudoRandomGeneratorSeed(prng, m_seed);
|
||||
|
||||
if (curandResult != CURAND_STATUS_SUCCESS) {
|
||||
string msg("Could not set seed for pseudo-random number generator: ");
|
||||
msg += curandResult;
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
if (curandResult != CURAND_STATUS_SUCCESS) {
|
||||
string msg("Could not set seed for pseudo-random number generator: ");
|
||||
msg += curandResult;
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
if (typeid(Real) == typeid(float)) {
|
||||
curandResult =
|
||||
curandGenerateUniform(prng, (float *)d_points, 2 * m_numSims);
|
||||
} else if (typeid(Real) == typeid(double)) {
|
||||
curandResult =
|
||||
curandGenerateUniformDouble(prng, (double *)d_points, 2 * m_numSims);
|
||||
} else {
|
||||
string msg("Could not generate random numbers of specified type");
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
if (typeid(Real) == typeid(float)) {
|
||||
curandResult = curandGenerateUniform(prng, (float *)d_points, 2 * m_numSims);
|
||||
}
|
||||
else if (typeid(Real) == typeid(double)) {
|
||||
curandResult = curandGenerateUniformDouble(prng, (double *)d_points, 2 * m_numSims);
|
||||
}
|
||||
else {
|
||||
string msg("Could not generate random numbers of specified type");
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
if (curandResult != CURAND_STATUS_SUCCESS) {
|
||||
string msg("Could not generate pseudo-random numbers: ");
|
||||
msg += curandResult;
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
if (curandResult != CURAND_STATUS_SUCCESS) {
|
||||
string msg("Could not generate pseudo-random numbers: ");
|
||||
msg += curandResult;
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
curandResult = curandDestroyGenerator(prng);
|
||||
curandResult = curandDestroyGenerator(prng);
|
||||
|
||||
if (curandResult != CURAND_STATUS_SUCCESS) {
|
||||
string msg("Could not destroy pseudo-random number generator: ");
|
||||
msg += curandResult;
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
if (curandResult != CURAND_STATUS_SUCCESS) {
|
||||
string msg("Could not destroy pseudo-random number generator: ");
|
||||
msg += curandResult;
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
// Count the points inside unit quarter-circle
|
||||
computeValue<Real><<<grid, block, block.x * sizeof(unsigned int)>>>(
|
||||
d_results, d_points, m_numSims);
|
||||
// Count the points inside unit quarter-circle
|
||||
computeValue<Real><<<grid, block, block.x * sizeof(unsigned int)>>>(d_results, d_points, m_numSims);
|
||||
|
||||
// Copy partial results back
|
||||
vector<unsigned int> results(grid.x);
|
||||
cudaResult = cudaMemcpy(&results[0], d_results, grid.x * sizeof(unsigned int),
|
||||
cudaMemcpyDeviceToHost);
|
||||
// Copy partial results back
|
||||
vector<unsigned int> results(grid.x);
|
||||
cudaResult = cudaMemcpy(&results[0], d_results, grid.x * sizeof(unsigned int), cudaMemcpyDeviceToHost);
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not copy partial results to host: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not copy partial results to host: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
// Complete sum-reduction on host
|
||||
Real value =
|
||||
static_cast<Real>(std::accumulate(results.begin(), results.end(), 0));
|
||||
// Complete sum-reduction on host
|
||||
Real value = static_cast<Real>(std::accumulate(results.begin(), results.end(), 0));
|
||||
|
||||
// Determine the proportion of points inside the quarter-circle,
|
||||
// i.e. the area of the unit quarter-circle
|
||||
value /= m_numSims;
|
||||
// Determine the proportion of points inside the quarter-circle,
|
||||
// i.e. the area of the unit quarter-circle
|
||||
value /= m_numSims;
|
||||
|
||||
// Value is currently an estimate of the area of a unit quarter-circle, so we
|
||||
// can scale to a full circle by multiplying by four. Now since the area of a
|
||||
// circle is pi * r^2, and r is one, the value will be an estimate for the
|
||||
// value of pi.
|
||||
value *= 4;
|
||||
// Value is currently an estimate of the area of a unit quarter-circle, so we
|
||||
// can scale to a full circle by multiplying by four. Now since the area of a
|
||||
// circle is pi * r^2, and r is one, the value will be an estimate for the
|
||||
// value of pi.
|
||||
value *= 4;
|
||||
|
||||
// Cleanup
|
||||
if (d_points) {
|
||||
cudaFree(d_points);
|
||||
d_points = 0;
|
||||
}
|
||||
// Cleanup
|
||||
if (d_points) {
|
||||
cudaFree(d_points);
|
||||
d_points = 0;
|
||||
}
|
||||
|
||||
if (d_results) {
|
||||
cudaFree(d_results);
|
||||
d_results = 0;
|
||||
}
|
||||
if (d_results) {
|
||||
cudaFree(d_results);
|
||||
d_results = 0;
|
||||
}
|
||||
|
||||
return value;
|
||||
return value;
|
||||
}
|
||||
|
||||
// Explicit template instantiation
|
||||
|
||||
@@ -27,81 +27,82 @@
|
||||
|
||||
#include "../inc/test.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <stdexcept>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
#include <typeinfo>
|
||||
#include <stdio.h>
|
||||
#include <helper_timer.h>
|
||||
#include <cuda_runtime.h>
|
||||
#include <helper_timer.h>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <math.h>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <stdio.h>
|
||||
#include <typeinfo>
|
||||
|
||||
#include "../inc/piestimator.h"
|
||||
|
||||
template <typename Real>
|
||||
bool Test<Real>::operator()() {
|
||||
using std::endl;
|
||||
using std::setw;
|
||||
using std::stringstream;
|
||||
template <typename Real> bool Test<Real>::operator()()
|
||||
{
|
||||
using std::endl;
|
||||
using std::setw;
|
||||
using std::stringstream;
|
||||
|
||||
StopWatchInterface *timer = NULL;
|
||||
sdkCreateTimer(&timer);
|
||||
StopWatchInterface *timer = NULL;
|
||||
sdkCreateTimer(&timer);
|
||||
|
||||
// Get device properties
|
||||
struct cudaDeviceProp deviceProperties;
|
||||
cudaError_t cudaResult = cudaGetDeviceProperties(&deviceProperties, device);
|
||||
// Get device properties
|
||||
struct cudaDeviceProp deviceProperties;
|
||||
cudaError_t cudaResult = cudaGetDeviceProperties(&deviceProperties, device);
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
std::string msg("Could not get device properties: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
if (cudaResult != cudaSuccess) {
|
||||
std::string msg("Could not get device properties: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
// Evaluate on GPU
|
||||
printf("Estimating Pi on GPU (%s)\n\n", deviceProperties.name);
|
||||
PiEstimator<Real> estimator(numSims, device, threadBlockSize, seed);
|
||||
sdkStartTimer(&timer);
|
||||
Real result = estimator();
|
||||
sdkStopTimer(&timer);
|
||||
elapsedTime = sdkGetAverageTimerValue(&timer) / 1000.0f;
|
||||
// Evaluate on GPU
|
||||
printf("Estimating Pi on GPU (%s)\n\n", deviceProperties.name);
|
||||
PiEstimator<Real> estimator(numSims, device, threadBlockSize, seed);
|
||||
sdkStartTimer(&timer);
|
||||
Real result = estimator();
|
||||
sdkStopTimer(&timer);
|
||||
elapsedTime = sdkGetAverageTimerValue(&timer) / 1000.0f;
|
||||
|
||||
// Tolerance to compare result with expected
|
||||
// This is just to check that nothing has gone very wrong with the
|
||||
// test, the actual accuracy of the result depends on the number of
|
||||
// Monte Carlo trials
|
||||
const Real tolerance = static_cast<Real>(0.01);
|
||||
// Tolerance to compare result with expected
|
||||
// This is just to check that nothing has gone very wrong with the
|
||||
// test, the actual accuracy of the result depends on the number of
|
||||
// Monte Carlo trials
|
||||
const Real tolerance = static_cast<Real>(0.01);
|
||||
|
||||
// Display results
|
||||
Real abserror = fabs(result - static_cast<float>(PI));
|
||||
Real relerror = abserror / static_cast<float>(PI);
|
||||
printf("Precision: %s\n",
|
||||
(typeid(Real) == typeid(double)) ? "double" : "single");
|
||||
printf("Number of sims: %d\n", numSims);
|
||||
printf("Tolerance: %e\n", tolerance);
|
||||
printf("GPU result: %e\n", result);
|
||||
printf("Expected: %e\n", PI);
|
||||
printf("Absolute error: %e\n", abserror);
|
||||
printf("Relative error: %e\n\n", relerror);
|
||||
// Display results
|
||||
Real abserror = fabs(result - static_cast<float>(PI));
|
||||
Real relerror = abserror / static_cast<float>(PI);
|
||||
printf("Precision: %s\n", (typeid(Real) == typeid(double)) ? "double" : "single");
|
||||
printf("Number of sims: %d\n", numSims);
|
||||
printf("Tolerance: %e\n", tolerance);
|
||||
printf("GPU result: %e\n", result);
|
||||
printf("Expected: %e\n", PI);
|
||||
printf("Absolute error: %e\n", abserror);
|
||||
printf("Relative error: %e\n\n", relerror);
|
||||
|
||||
// Check result
|
||||
if (relerror > tolerance) {
|
||||
printf("computed result (%e) does not match expected result (%e).\n",
|
||||
result, PI);
|
||||
pass = false;
|
||||
} else {
|
||||
pass = true;
|
||||
}
|
||||
// Check result
|
||||
if (relerror > tolerance) {
|
||||
printf("computed result (%e) does not match expected result (%e).\n", result, PI);
|
||||
pass = false;
|
||||
}
|
||||
else {
|
||||
pass = true;
|
||||
}
|
||||
|
||||
// Print results
|
||||
printf(
|
||||
"MonteCarloEstimatePiP, Performance = %.2f sims/s, Time = %.2f(ms), "
|
||||
"NumDevsUsed = %u, Blocksize = %u\n",
|
||||
numSims / elapsedTime, elapsedTime * 1000.0f, 1, threadBlockSize);
|
||||
// Print results
|
||||
printf("MonteCarloEstimatePiP, Performance = %.2f sims/s, Time = %.2f(ms), "
|
||||
"NumDevsUsed = %u, Blocksize = %u\n",
|
||||
numSims / elapsedTime,
|
||||
elapsedTime * 1000.0f,
|
||||
1,
|
||||
threadBlockSize);
|
||||
|
||||
return pass;
|
||||
return pass;
|
||||
}
|
||||
|
||||
// Explicit template instantiation
|
||||
|
||||
@@ -65,25 +65,27 @@
|
||||
|
||||
// This is the un-specialized struct. Note that we prevent instantiation of
|
||||
// this struct by making it abstract (i.e. with pure virtual methods).
|
||||
template <typename T>
|
||||
struct SharedMemory {
|
||||
// Ensure that we won't compile any un-specialized types
|
||||
virtual __device__ T &operator*() = 0;
|
||||
virtual __device__ T &operator[](int i) = 0;
|
||||
template <typename T> struct SharedMemory
|
||||
{
|
||||
// Ensure that we won't compile any un-specialized types
|
||||
virtual __device__ T &operator*() = 0;
|
||||
virtual __device__ T &operator[](int i) = 0;
|
||||
};
|
||||
|
||||
#define BUILD_SHAREDMEMORY_TYPE(t, n) \
|
||||
template <> \
|
||||
struct SharedMemory<t> { \
|
||||
__device__ t &operator*() { \
|
||||
extern __shared__ t n[]; \
|
||||
return *n; \
|
||||
} \
|
||||
__device__ t &operator[](int i) { \
|
||||
extern __shared__ t n[]; \
|
||||
return n[i]; \
|
||||
} \
|
||||
}
|
||||
#define BUILD_SHAREDMEMORY_TYPE(t, n) \
|
||||
template <> struct SharedMemory<t> \
|
||||
{ \
|
||||
__device__ t &operator*() \
|
||||
{ \
|
||||
extern __shared__ t n[]; \
|
||||
return *n; \
|
||||
} \
|
||||
__device__ t &operator[](int i) \
|
||||
{ \
|
||||
extern __shared__ t n[]; \
|
||||
return n[i]; \
|
||||
} \
|
||||
}
|
||||
|
||||
BUILD_SHAREDMEMORY_TYPE(int, s_int);
|
||||
BUILD_SHAREDMEMORY_TYPE(unsigned int, s_uint);
|
||||
|
||||
@@ -27,17 +27,16 @@
|
||||
#ifndef PIESTIMATOR_H
|
||||
#define PIESTIMATOR_H
|
||||
|
||||
template <typename Real>
|
||||
class PiEstimator {
|
||||
public:
|
||||
PiEstimator(unsigned int numSims, unsigned int device,
|
||||
unsigned int threadBlockSize);
|
||||
Real operator()();
|
||||
template <typename Real> class PiEstimator
|
||||
{
|
||||
public:
|
||||
PiEstimator(unsigned int numSims, unsigned int device, unsigned int threadBlockSize);
|
||||
Real operator()();
|
||||
|
||||
private:
|
||||
unsigned int m_numSims;
|
||||
unsigned int m_device;
|
||||
unsigned int m_threadBlockSize;
|
||||
private:
|
||||
unsigned int m_numSims;
|
||||
unsigned int m_device;
|
||||
unsigned int m_threadBlockSize;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -28,28 +28,29 @@
|
||||
#ifndef TEST_H
|
||||
#define TEST_H
|
||||
|
||||
template <typename Real>
|
||||
struct Test {
|
||||
Test() : pass(false){};
|
||||
template <typename Real> struct Test
|
||||
{
|
||||
Test()
|
||||
: pass(false) {};
|
||||
|
||||
int device;
|
||||
unsigned int numSims;
|
||||
unsigned int threadBlockSize;
|
||||
int device;
|
||||
unsigned int numSims;
|
||||
unsigned int threadBlockSize;
|
||||
|
||||
bool pass;
|
||||
double elapsedTime;
|
||||
bool pass;
|
||||
double elapsedTime;
|
||||
|
||||
bool operator()();
|
||||
bool operator()();
|
||||
};
|
||||
|
||||
// Defaults are arbitrary to give sensible runtime
|
||||
#define k_sims_min 100000
|
||||
#define k_sims_max 10000000
|
||||
#define k_sims_def 100000
|
||||
#define k_sims_qa 100000
|
||||
#define k_sims_min 100000
|
||||
#define k_sims_max 10000000
|
||||
#define k_sims_def 100000
|
||||
#define k_sims_qa 100000
|
||||
#define k_bsize_min 32
|
||||
#define k_bsize_def 128
|
||||
#define k_bsize_qa 128
|
||||
#define k_bsize_qa 128
|
||||
|
||||
// Target value
|
||||
#define PI 3.14159265359
|
||||
|
||||
@@ -39,12 +39,12 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <stdexcept>
|
||||
#include <cuda_runtime.h>
|
||||
#include <helper_timer.h>
|
||||
#include <helper_cuda.h>
|
||||
#include <helper_timer.h>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "../inc/test.h"
|
||||
|
||||
@@ -52,181 +52,186 @@
|
||||
static const char *printfFile = "MonteCarloEstimatePiQ.txt";
|
||||
|
||||
// Forward declarations
|
||||
void showHelp(const int argc, const char **argv);
|
||||
template <typename Real>
|
||||
void runTest(int argc, const char **argv);
|
||||
void showHelp(const int argc, const char **argv);
|
||||
template <typename Real> void runTest(int argc, const char **argv);
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
using std::invalid_argument;
|
||||
using std::string;
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
using std::invalid_argument;
|
||||
using std::string;
|
||||
|
||||
// Open the log file
|
||||
printf("Monte Carlo Estimate Pi (with batch QRNG)\n");
|
||||
printf("=========================================\n\n");
|
||||
// Open the log file
|
||||
printf("Monte Carlo Estimate Pi (with batch QRNG)\n");
|
||||
printf("=========================================\n\n");
|
||||
|
||||
// If help flag is set, display help and exit immediately
|
||||
if (checkCmdLineFlag(argc, (const char **)argv, "help")) {
|
||||
printf("Displaying help on console\n");
|
||||
showHelp(argc, (const char **)argv);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
// Check the precision (checked against the device capability later)
|
||||
try {
|
||||
char *value;
|
||||
|
||||
if (getCmdLineArgumentString(argc, (const char **)argv, "precision",
|
||||
&value)) {
|
||||
// Check requested precision is valid
|
||||
string prec(value);
|
||||
|
||||
if (prec.compare("single") == 0 || prec.compare("\"single\"") == 0) {
|
||||
runTest<float>(argc, (const char **)argv);
|
||||
} else if (prec.compare("double") == 0 ||
|
||||
prec.compare("\"double\"") == 0) {
|
||||
runTest<double>(argc, (const char **)argv);
|
||||
} else {
|
||||
printf("specified precision (%s) is invalid, must be \"single\".\n",
|
||||
value);
|
||||
throw invalid_argument("precision");
|
||||
}
|
||||
} else {
|
||||
runTest<float>(argc, (const char **)argv);
|
||||
// If help flag is set, display help and exit immediately
|
||||
if (checkCmdLineFlag(argc, (const char **)argv, "help")) {
|
||||
printf("Displaying help on console\n");
|
||||
showHelp(argc, (const char **)argv);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
} catch (invalid_argument &e) {
|
||||
printf("invalid command line argument (%s)\n", e.what());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Finish
|
||||
exit(EXIT_SUCCESS);
|
||||
// Check the precision (checked against the device capability later)
|
||||
try {
|
||||
char *value;
|
||||
|
||||
if (getCmdLineArgumentString(argc, (const char **)argv, "precision", &value)) {
|
||||
// Check requested precision is valid
|
||||
string prec(value);
|
||||
|
||||
if (prec.compare("single") == 0 || prec.compare("\"single\"") == 0) {
|
||||
runTest<float>(argc, (const char **)argv);
|
||||
}
|
||||
else if (prec.compare("double") == 0 || prec.compare("\"double\"") == 0) {
|
||||
runTest<double>(argc, (const char **)argv);
|
||||
}
|
||||
else {
|
||||
printf("specified precision (%s) is invalid, must be \"single\".\n", value);
|
||||
throw invalid_argument("precision");
|
||||
}
|
||||
}
|
||||
else {
|
||||
runTest<float>(argc, (const char **)argv);
|
||||
}
|
||||
}
|
||||
catch (invalid_argument &e) {
|
||||
printf("invalid command line argument (%s)\n", e.what());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Finish
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
template <typename Real>
|
||||
void runTest(int argc, const char **argv) {
|
||||
using std::invalid_argument;
|
||||
using std::runtime_error;
|
||||
template <typename Real> void runTest(int argc, const char **argv)
|
||||
{
|
||||
using std::invalid_argument;
|
||||
using std::runtime_error;
|
||||
|
||||
try {
|
||||
Test<Real> test;
|
||||
int deviceCount = 0;
|
||||
cudaError_t cudaResult = cudaSuccess;
|
||||
try {
|
||||
Test<Real> test;
|
||||
int deviceCount = 0;
|
||||
cudaError_t cudaResult = cudaSuccess;
|
||||
|
||||
// by default specify GPU Device == 0
|
||||
test.device = 0;
|
||||
// by default specify GPU Device == 0
|
||||
test.device = 0;
|
||||
|
||||
// Get number of available devices
|
||||
cudaResult = cudaGetDeviceCount(&deviceCount);
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
printf("could not get device count.\n");
|
||||
throw runtime_error("cudaGetDeviceCount");
|
||||
}
|
||||
|
||||
// (default parameters)
|
||||
test.numSims = k_sims_qa;
|
||||
test.threadBlockSize = k_bsize_qa;
|
||||
|
||||
{
|
||||
char *value = 0;
|
||||
|
||||
if (getCmdLineArgumentString(argc, argv, "device", &value)) {
|
||||
test.device = (int)atoi(value);
|
||||
|
||||
if (test.device >= deviceCount) {
|
||||
printf(
|
||||
"invalid target device specified on command line (device %d does "
|
||||
"not exist).\n",
|
||||
test.device);
|
||||
throw invalid_argument("device");
|
||||
}
|
||||
} else {
|
||||
test.device = gpuGetMaxGflopsDeviceId();
|
||||
}
|
||||
|
||||
if (getCmdLineArgumentString(argc, argv, "sims", &value)) {
|
||||
test.numSims = (unsigned int)atoi(value);
|
||||
|
||||
if (test.numSims < k_sims_min || test.numSims > k_sims_max) {
|
||||
printf(
|
||||
"specified number of simulations (%d) is invalid, must be "
|
||||
"between %d and %d.\n",
|
||||
test.numSims, k_sims_min, k_sims_max);
|
||||
throw invalid_argument("sims");
|
||||
}
|
||||
} else {
|
||||
test.numSims = k_sims_def;
|
||||
}
|
||||
|
||||
if (getCmdLineArgumentString(argc, argv, "block-size", &value)) {
|
||||
// Determine max threads per block
|
||||
cudaDeviceProp deviceProperties;
|
||||
cudaResult = cudaGetDeviceProperties(&deviceProperties, test.device);
|
||||
// Get number of available devices
|
||||
cudaResult = cudaGetDeviceCount(&deviceCount);
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
printf("cound not get device properties for device %d.\n",
|
||||
test.device);
|
||||
throw runtime_error("cudaGetDeviceProperties");
|
||||
printf("could not get device count.\n");
|
||||
throw runtime_error("cudaGetDeviceCount");
|
||||
}
|
||||
|
||||
// Check requested size is valid
|
||||
test.threadBlockSize = (unsigned int)atoi(value);
|
||||
// (default parameters)
|
||||
test.numSims = k_sims_qa;
|
||||
test.threadBlockSize = k_bsize_qa;
|
||||
|
||||
if (test.threadBlockSize < k_bsize_min ||
|
||||
test.threadBlockSize > static_cast<unsigned int>(
|
||||
deviceProperties.maxThreadsPerBlock)) {
|
||||
printf(
|
||||
"specified block size (%d) is invalid, must be between %d and %d "
|
||||
"for device %d.\n",
|
||||
test.threadBlockSize, k_bsize_min,
|
||||
deviceProperties.maxThreadsPerBlock, test.device);
|
||||
throw invalid_argument("block-size");
|
||||
}
|
||||
{
|
||||
char *value = 0;
|
||||
|
||||
if (test.threadBlockSize & test.threadBlockSize - 1) {
|
||||
printf(
|
||||
"specified block size (%d) is invalid, must be a power of two "
|
||||
"(see reduction function).\n",
|
||||
test.threadBlockSize);
|
||||
throw invalid_argument("block-size");
|
||||
if (getCmdLineArgumentString(argc, argv, "device", &value)) {
|
||||
test.device = (int)atoi(value);
|
||||
|
||||
if (test.device >= deviceCount) {
|
||||
printf("invalid target device specified on command line (device %d does "
|
||||
"not exist).\n",
|
||||
test.device);
|
||||
throw invalid_argument("device");
|
||||
}
|
||||
}
|
||||
else {
|
||||
test.device = gpuGetMaxGflopsDeviceId();
|
||||
}
|
||||
|
||||
if (getCmdLineArgumentString(argc, argv, "sims", &value)) {
|
||||
test.numSims = (unsigned int)atoi(value);
|
||||
|
||||
if (test.numSims < k_sims_min || test.numSims > k_sims_max) {
|
||||
printf("specified number of simulations (%d) is invalid, must be "
|
||||
"between %d and %d.\n",
|
||||
test.numSims,
|
||||
k_sims_min,
|
||||
k_sims_max);
|
||||
throw invalid_argument("sims");
|
||||
}
|
||||
}
|
||||
else {
|
||||
test.numSims = k_sims_def;
|
||||
}
|
||||
|
||||
if (getCmdLineArgumentString(argc, argv, "block-size", &value)) {
|
||||
// Determine max threads per block
|
||||
cudaDeviceProp deviceProperties;
|
||||
cudaResult = cudaGetDeviceProperties(&deviceProperties, test.device);
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
printf("cound not get device properties for device %d.\n", test.device);
|
||||
throw runtime_error("cudaGetDeviceProperties");
|
||||
}
|
||||
|
||||
// Check requested size is valid
|
||||
test.threadBlockSize = (unsigned int)atoi(value);
|
||||
|
||||
if (test.threadBlockSize < k_bsize_min
|
||||
|| test.threadBlockSize > static_cast<unsigned int>(deviceProperties.maxThreadsPerBlock)) {
|
||||
printf("specified block size (%d) is invalid, must be between %d and %d "
|
||||
"for device %d.\n",
|
||||
test.threadBlockSize,
|
||||
k_bsize_min,
|
||||
deviceProperties.maxThreadsPerBlock,
|
||||
test.device);
|
||||
throw invalid_argument("block-size");
|
||||
}
|
||||
|
||||
if (test.threadBlockSize & test.threadBlockSize - 1) {
|
||||
printf("specified block size (%d) is invalid, must be a power of two "
|
||||
"(see reduction function).\n",
|
||||
test.threadBlockSize);
|
||||
throw invalid_argument("block-size");
|
||||
}
|
||||
}
|
||||
else {
|
||||
test.threadBlockSize = k_bsize_def;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
test.threadBlockSize = k_bsize_def;
|
||||
}
|
||||
// Execute
|
||||
test();
|
||||
}
|
||||
catch (invalid_argument &e) {
|
||||
printf("invalid command line argument (%s)\n", e.what());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
catch (runtime_error &e) {
|
||||
printf("runtime error (%s)\n", e.what());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
// Execute
|
||||
test();
|
||||
} catch (invalid_argument &e) {
|
||||
printf("invalid command line argument (%s)\n", e.what());
|
||||
exit(EXIT_FAILURE);
|
||||
} catch (runtime_error &e) {
|
||||
printf("runtime error (%s)\n", e.what());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
void showHelp(int argc, const char **argv) {
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
using std::left;
|
||||
using std::setw;
|
||||
void showHelp(int argc, const char **argv)
|
||||
{
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
using std::left;
|
||||
using std::setw;
|
||||
|
||||
if (argc > 0) {
|
||||
cout << endl << argv[0] << endl;
|
||||
}
|
||||
if (argc > 0) {
|
||||
cout << endl << argv[0] << endl;
|
||||
}
|
||||
|
||||
cout << endl << "Syntax:" << endl;
|
||||
cout << left;
|
||||
cout << " " << setw(20) << "--device=<device>"
|
||||
<< "Specify device to use for execution" << endl;
|
||||
cout << " " << setw(20) << "--sims=<N>"
|
||||
<< "Specify number of Monte Carlo simulations" << endl;
|
||||
cout << " " << setw(20) << "--block-size=<N>"
|
||||
<< "Specify number of threads per block" << endl;
|
||||
cout << " " << setw(20) << "--precision=<P>"
|
||||
<< "Specify the precision (\"single\" or \"double\")" << endl;
|
||||
cout << endl;
|
||||
cout << " " << setw(20) << "--noprompt"
|
||||
<< "Skip prompt before exit" << endl;
|
||||
cout << endl;
|
||||
cout << endl << "Syntax:" << endl;
|
||||
cout << left;
|
||||
cout << " " << setw(20) << "--device=<device>"
|
||||
<< "Specify device to use for execution" << endl;
|
||||
cout << " " << setw(20) << "--sims=<N>"
|
||||
<< "Specify number of Monte Carlo simulations" << endl;
|
||||
cout << " " << setw(20) << "--block-size=<N>"
|
||||
<< "Specify number of threads per block" << endl;
|
||||
cout << " " << setw(20) << "--precision=<P>"
|
||||
<< "Specify the precision (\"single\" or \"double\")" << endl;
|
||||
cout << endl;
|
||||
cout << " " << setw(20) << "--noprompt"
|
||||
<< "Skip prompt before exit" << endl;
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
@@ -25,15 +25,15 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "../inc/piestimator.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cooperative_groups.h>
|
||||
#include <cuda_runtime.h>
|
||||
#include <numeric>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <typeinfo>
|
||||
#include <cuda_runtime.h>
|
||||
#include <cooperative_groups.h>
|
||||
#include <vector>
|
||||
|
||||
#include "../inc/piestimator.h"
|
||||
|
||||
namespace cg = cooperative_groups;
|
||||
#include <curand.h>
|
||||
@@ -41,269 +41,264 @@ namespace cg = cooperative_groups;
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
__device__ unsigned int reduce_sum(unsigned int in, cg::thread_block cta) {
|
||||
extern __shared__ unsigned int sdata[];
|
||||
__device__ unsigned int reduce_sum(unsigned int in, cg::thread_block cta)
|
||||
{
|
||||
extern __shared__ unsigned int sdata[];
|
||||
|
||||
// Perform first level of reduction:
|
||||
// - Write to shared memory
|
||||
unsigned int ltid = threadIdx.x;
|
||||
// Perform first level of reduction:
|
||||
// - Write to shared memory
|
||||
unsigned int ltid = threadIdx.x;
|
||||
|
||||
sdata[ltid] = in;
|
||||
cg::sync(cta);
|
||||
sdata[ltid] = in;
|
||||
cg::sync(cta);
|
||||
|
||||
// Do reduction in shared mem
|
||||
for (unsigned int s = blockDim.x / 2; s > 0; s >>= 1) {
|
||||
if (ltid < s) {
|
||||
sdata[ltid] += sdata[ltid + s];
|
||||
// Do reduction in shared mem
|
||||
for (unsigned int s = blockDim.x / 2; s > 0; s >>= 1) {
|
||||
if (ltid < s) {
|
||||
sdata[ltid] += sdata[ltid + s];
|
||||
}
|
||||
|
||||
cg::sync(cta);
|
||||
}
|
||||
|
||||
cg::sync(cta);
|
||||
}
|
||||
|
||||
return sdata[0];
|
||||
return sdata[0];
|
||||
}
|
||||
|
||||
// Estimator kernel
|
||||
template <typename Real>
|
||||
__global__ void computeValue(unsigned int *const results,
|
||||
const Real *const points,
|
||||
const unsigned int numSims) {
|
||||
// Handle to thread block group
|
||||
cg::thread_block cta = cg::this_thread_block();
|
||||
// Determine thread ID
|
||||
unsigned int bid = blockIdx.x;
|
||||
unsigned int tid = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
unsigned int step = gridDim.x * blockDim.x;
|
||||
__global__ void computeValue(unsigned int *const results, const Real *const points, const unsigned int numSims)
|
||||
{
|
||||
// Handle to thread block group
|
||||
cg::thread_block cta = cg::this_thread_block();
|
||||
// Determine thread ID
|
||||
unsigned int bid = blockIdx.x;
|
||||
unsigned int tid = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
unsigned int step = gridDim.x * blockDim.x;
|
||||
|
||||
// Shift the input/output pointers
|
||||
const Real *pointx = points + tid;
|
||||
const Real *pointy = pointx + numSims;
|
||||
// Shift the input/output pointers
|
||||
const Real *pointx = points + tid;
|
||||
const Real *pointy = pointx + numSims;
|
||||
|
||||
// Count the number of points which lie inside the unit quarter-circle
|
||||
unsigned int pointsInside = 0;
|
||||
// Count the number of points which lie inside the unit quarter-circle
|
||||
unsigned int pointsInside = 0;
|
||||
|
||||
for (unsigned int i = tid; i < numSims;
|
||||
i += step, pointx += step, pointy += step) {
|
||||
Real x = *pointx;
|
||||
Real y = *pointy;
|
||||
Real l2norm2 = x * x + y * y;
|
||||
for (unsigned int i = tid; i < numSims; i += step, pointx += step, pointy += step) {
|
||||
Real x = *pointx;
|
||||
Real y = *pointy;
|
||||
Real l2norm2 = x * x + y * y;
|
||||
|
||||
if (l2norm2 < static_cast<Real>(1)) {
|
||||
pointsInside++;
|
||||
if (l2norm2 < static_cast<Real>(1)) {
|
||||
pointsInside++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Reduce within the block
|
||||
pointsInside = reduce_sum(pointsInside, cta);
|
||||
// Reduce within the block
|
||||
pointsInside = reduce_sum(pointsInside, cta);
|
||||
|
||||
// Store the result
|
||||
if (threadIdx.x == 0) {
|
||||
results[bid] = pointsInside;
|
||||
}
|
||||
// Store the result
|
||||
if (threadIdx.x == 0) {
|
||||
results[bid] = pointsInside;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Real>
|
||||
PiEstimator<Real>::PiEstimator(unsigned int numSims, unsigned int device,
|
||||
unsigned int threadBlockSize)
|
||||
: m_numSims(numSims),
|
||||
m_device(device),
|
||||
m_threadBlockSize(threadBlockSize) {}
|
||||
PiEstimator<Real>::PiEstimator(unsigned int numSims, unsigned int device, unsigned int threadBlockSize)
|
||||
: m_numSims(numSims)
|
||||
, m_device(device)
|
||||
, m_threadBlockSize(threadBlockSize)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename Real>
|
||||
Real PiEstimator<Real>::operator()() {
|
||||
cudaError_t cudaResult = cudaSuccess;
|
||||
struct cudaDeviceProp deviceProperties;
|
||||
struct cudaFuncAttributes funcAttributes;
|
||||
template <typename Real> Real PiEstimator<Real>::operator()()
|
||||
{
|
||||
cudaError_t cudaResult = cudaSuccess;
|
||||
struct cudaDeviceProp deviceProperties;
|
||||
struct cudaFuncAttributes funcAttributes;
|
||||
|
||||
// Get device properties
|
||||
cudaResult = cudaGetDeviceProperties(&deviceProperties, m_device);
|
||||
// Get device properties
|
||||
cudaResult = cudaGetDeviceProperties(&deviceProperties, m_device);
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not get device properties: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not get device properties: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
// Check precision is valid
|
||||
if (typeid(Real) == typeid(double) &&
|
||||
(deviceProperties.major < 1 ||
|
||||
(deviceProperties.major == 1 && deviceProperties.minor < 3))) {
|
||||
throw std::runtime_error("Device does not have double precision support");
|
||||
}
|
||||
// Check precision is valid
|
||||
if (typeid(Real) == typeid(double)
|
||||
&& (deviceProperties.major < 1 || (deviceProperties.major == 1 && deviceProperties.minor < 3))) {
|
||||
throw std::runtime_error("Device does not have double precision support");
|
||||
}
|
||||
|
||||
// Attach to GPU
|
||||
cudaResult = cudaSetDevice(m_device);
|
||||
// Attach to GPU
|
||||
cudaResult = cudaSetDevice(m_device);
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not set CUDA device: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not set CUDA device: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
// Determine how to divide the work between cores
|
||||
dim3 block;
|
||||
dim3 grid;
|
||||
block.x = m_threadBlockSize;
|
||||
grid.x = (m_numSims + m_threadBlockSize - 1) / m_threadBlockSize;
|
||||
// Determine how to divide the work between cores
|
||||
dim3 block;
|
||||
dim3 grid;
|
||||
block.x = m_threadBlockSize;
|
||||
grid.x = (m_numSims + m_threadBlockSize - 1) / m_threadBlockSize;
|
||||
|
||||
// Aim to launch around ten or more times as many blocks as there
|
||||
// are multiprocessors on the target device.
|
||||
unsigned int blocksPerSM = 10;
|
||||
unsigned int numSMs = deviceProperties.multiProcessorCount;
|
||||
// Aim to launch around ten or more times as many blocks as there
|
||||
// are multiprocessors on the target device.
|
||||
unsigned int blocksPerSM = 10;
|
||||
unsigned int numSMs = deviceProperties.multiProcessorCount;
|
||||
|
||||
while (grid.x > 2 * blocksPerSM * numSMs) {
|
||||
grid.x >>= 1;
|
||||
}
|
||||
while (grid.x > 2 * blocksPerSM * numSMs) {
|
||||
grid.x >>= 1;
|
||||
}
|
||||
|
||||
// Get computeValue function properties and check the maximum block size
|
||||
cudaResult = cudaFuncGetAttributes(&funcAttributes, computeValue<Real>);
|
||||
// Get computeValue function properties and check the maximum block size
|
||||
cudaResult = cudaFuncGetAttributes(&funcAttributes, computeValue<Real>);
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not get function attributes: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not get function attributes: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
if (block.x > (unsigned int)funcAttributes.maxThreadsPerBlock) {
|
||||
throw std::runtime_error(
|
||||
"Block X dimension is too large for computeValue kernel");
|
||||
}
|
||||
if (block.x > (unsigned int)funcAttributes.maxThreadsPerBlock) {
|
||||
throw std::runtime_error("Block X dimension is too large for computeValue kernel");
|
||||
}
|
||||
|
||||
// Check the dimensions are valid
|
||||
if (block.x > (unsigned int)deviceProperties.maxThreadsDim[0]) {
|
||||
throw std::runtime_error("Block X dimension is too large for device");
|
||||
}
|
||||
// Check the dimensions are valid
|
||||
if (block.x > (unsigned int)deviceProperties.maxThreadsDim[0]) {
|
||||
throw std::runtime_error("Block X dimension is too large for device");
|
||||
}
|
||||
|
||||
if (grid.x > (unsigned int)deviceProperties.maxGridSize[0]) {
|
||||
throw std::runtime_error("Grid X dimension is too large for device");
|
||||
}
|
||||
if (grid.x > (unsigned int)deviceProperties.maxGridSize[0]) {
|
||||
throw std::runtime_error("Grid X dimension is too large for device");
|
||||
}
|
||||
|
||||
// Allocate memory for points
|
||||
// Each simulation has two random numbers to give X and Y coordinate
|
||||
Real *d_points = 0;
|
||||
cudaResult = cudaMalloc((void **)&d_points, 2 * m_numSims * sizeof(Real));
|
||||
// Allocate memory for points
|
||||
// Each simulation has two random numbers to give X and Y coordinate
|
||||
Real *d_points = 0;
|
||||
cudaResult = cudaMalloc((void **)&d_points, 2 * m_numSims * sizeof(Real));
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not allocate memory on device for random numbers: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not allocate memory on device for random numbers: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
// Allocate memory for result
|
||||
// Each thread block will produce one result
|
||||
unsigned int *d_results = 0;
|
||||
cudaResult = cudaMalloc((void **)&d_results, grid.x * sizeof(unsigned int));
|
||||
// Allocate memory for result
|
||||
// Each thread block will produce one result
|
||||
unsigned int *d_results = 0;
|
||||
cudaResult = cudaMalloc((void **)&d_results, grid.x * sizeof(unsigned int));
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not allocate memory on device for partial results: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not allocate memory on device for partial results: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
// Generate random points in unit square
|
||||
curandStatus_t curandResult;
|
||||
curandGenerator_t qrng;
|
||||
// Generate random points in unit square
|
||||
curandStatus_t curandResult;
|
||||
curandGenerator_t qrng;
|
||||
|
||||
if (typeid(Real) == typeid(float)) {
|
||||
curandResult = curandCreateGenerator(&qrng, CURAND_RNG_QUASI_SOBOL32);
|
||||
} else if (typeid(Real) == typeid(double)) {
|
||||
curandResult = curandCreateGenerator(&qrng, CURAND_RNG_QUASI_SOBOL64);
|
||||
} else {
|
||||
string msg("Could not create random number generator of specified type");
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
if (typeid(Real) == typeid(float)) {
|
||||
curandResult = curandCreateGenerator(&qrng, CURAND_RNG_QUASI_SOBOL32);
|
||||
}
|
||||
else if (typeid(Real) == typeid(double)) {
|
||||
curandResult = curandCreateGenerator(&qrng, CURAND_RNG_QUASI_SOBOL64);
|
||||
}
|
||||
else {
|
||||
string msg("Could not create random number generator of specified type");
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
if (curandResult != CURAND_STATUS_SUCCESS) {
|
||||
string msg("Could not create quasi-random number generator: ");
|
||||
msg += curandResult;
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
if (curandResult != CURAND_STATUS_SUCCESS) {
|
||||
string msg("Could not create quasi-random number generator: ");
|
||||
msg += curandResult;
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
curandResult = curandSetQuasiRandomGeneratorDimensions(qrng, 2);
|
||||
curandResult = curandSetQuasiRandomGeneratorDimensions(qrng, 2);
|
||||
|
||||
if (curandResult != CURAND_STATUS_SUCCESS) {
|
||||
string msg(
|
||||
"Could not set number of dimensions for quasi-random number "
|
||||
"generator: ");
|
||||
msg += curandResult;
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
if (curandResult != CURAND_STATUS_SUCCESS) {
|
||||
string msg("Could not set number of dimensions for quasi-random number "
|
||||
"generator: ");
|
||||
msg += curandResult;
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
curandResult =
|
||||
curandSetGeneratorOrdering(qrng, CURAND_ORDERING_QUASI_DEFAULT);
|
||||
curandResult = curandSetGeneratorOrdering(qrng, CURAND_ORDERING_QUASI_DEFAULT);
|
||||
|
||||
if (curandResult != CURAND_STATUS_SUCCESS) {
|
||||
string msg("Could not set order for quasi-random number generator: ");
|
||||
msg += curandResult;
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
if (curandResult != CURAND_STATUS_SUCCESS) {
|
||||
string msg("Could not set order for quasi-random number generator: ");
|
||||
msg += curandResult;
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
if (typeid(Real) == typeid(float)) {
|
||||
curandResult =
|
||||
curandGenerateUniform(qrng, (float *)d_points, 2 * m_numSims);
|
||||
} else if (typeid(Real) == typeid(double)) {
|
||||
curandResult =
|
||||
curandGenerateUniformDouble(qrng, (double *)d_points, 2 * m_numSims);
|
||||
} else {
|
||||
string msg("Could not generate random numbers of specified type");
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
if (typeid(Real) == typeid(float)) {
|
||||
curandResult = curandGenerateUniform(qrng, (float *)d_points, 2 * m_numSims);
|
||||
}
|
||||
else if (typeid(Real) == typeid(double)) {
|
||||
curandResult = curandGenerateUniformDouble(qrng, (double *)d_points, 2 * m_numSims);
|
||||
}
|
||||
else {
|
||||
string msg("Could not generate random numbers of specified type");
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
if (curandResult != CURAND_STATUS_SUCCESS) {
|
||||
string msg("Could not generate quasi-random numbers: ");
|
||||
msg += curandResult;
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
if (curandResult != CURAND_STATUS_SUCCESS) {
|
||||
string msg("Could not generate quasi-random numbers: ");
|
||||
msg += curandResult;
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
curandResult = curandDestroyGenerator(qrng);
|
||||
curandResult = curandDestroyGenerator(qrng);
|
||||
|
||||
if (curandResult != CURAND_STATUS_SUCCESS) {
|
||||
string msg("Could not destroy quasi-random number generator: ");
|
||||
msg += curandResult;
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
if (curandResult != CURAND_STATUS_SUCCESS) {
|
||||
string msg("Could not destroy quasi-random number generator: ");
|
||||
msg += curandResult;
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
// Count the points inside unit quarter-circle
|
||||
computeValue<Real><<<grid, block, block.x * sizeof(unsigned int)>>>(
|
||||
d_results, d_points, m_numSims);
|
||||
// Count the points inside unit quarter-circle
|
||||
computeValue<Real><<<grid, block, block.x * sizeof(unsigned int)>>>(d_results, d_points, m_numSims);
|
||||
|
||||
// Copy partial results back
|
||||
vector<unsigned int> results(grid.x);
|
||||
cudaResult = cudaMemcpy(&results[0], d_results, grid.x * sizeof(unsigned int),
|
||||
cudaMemcpyDeviceToHost);
|
||||
// Copy partial results back
|
||||
vector<unsigned int> results(grid.x);
|
||||
cudaResult = cudaMemcpy(&results[0], d_results, grid.x * sizeof(unsigned int), cudaMemcpyDeviceToHost);
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not copy partial results to host: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not copy partial results to host: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
// Complete sum-reduction on host
|
||||
Real value =
|
||||
static_cast<Real>(std::accumulate(results.begin(), results.end(), 0));
|
||||
// Complete sum-reduction on host
|
||||
Real value = static_cast<Real>(std::accumulate(results.begin(), results.end(), 0));
|
||||
|
||||
// Determine the proportion of points inside the quarter-circle,
|
||||
// i.e. the area of the unit quarter-circle
|
||||
value /= m_numSims;
|
||||
// Determine the proportion of points inside the quarter-circle,
|
||||
// i.e. the area of the unit quarter-circle
|
||||
value /= m_numSims;
|
||||
|
||||
// Value is currently an estimate of the area of a unit quarter-circle, so we
|
||||
// can scale to a full circle by multiplying by four. Now since the area of a
|
||||
// circle is pi * r^2, and r is one, the value will be an estimate for the
|
||||
// value of pi.
|
||||
value *= 4;
|
||||
// Value is currently an estimate of the area of a unit quarter-circle, so we
|
||||
// can scale to a full circle by multiplying by four. Now since the area of a
|
||||
// circle is pi * r^2, and r is one, the value will be an estimate for the
|
||||
// value of pi.
|
||||
value *= 4;
|
||||
|
||||
// Cleanup
|
||||
if (d_points) {
|
||||
cudaFree(d_points);
|
||||
d_points = 0;
|
||||
}
|
||||
// Cleanup
|
||||
if (d_points) {
|
||||
cudaFree(d_points);
|
||||
d_points = 0;
|
||||
}
|
||||
|
||||
if (d_results) {
|
||||
cudaFree(d_results);
|
||||
d_results = 0;
|
||||
}
|
||||
if (d_results) {
|
||||
cudaFree(d_results);
|
||||
d_results = 0;
|
||||
}
|
||||
|
||||
return value;
|
||||
return value;
|
||||
}
|
||||
|
||||
// Explicit template instantiation
|
||||
|
||||
@@ -27,83 +27,84 @@
|
||||
|
||||
#include "../inc/test.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <stdexcept>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
#include <typeinfo>
|
||||
#include <stdio.h>
|
||||
#include <helper_timer.h>
|
||||
#include <cuda_runtime.h>
|
||||
#include <helper_timer.h>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <math.h>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <stdio.h>
|
||||
#include <typeinfo>
|
||||
|
||||
#include "../inc/piestimator.h"
|
||||
|
||||
template <typename Real>
|
||||
bool Test<Real>::operator()() {
|
||||
using std::endl;
|
||||
using std::setw;
|
||||
using std::stringstream;
|
||||
template <typename Real> bool Test<Real>::operator()()
|
||||
{
|
||||
using std::endl;
|
||||
using std::setw;
|
||||
using std::stringstream;
|
||||
|
||||
StopWatchInterface *timer = NULL;
|
||||
sdkCreateTimer(&timer);
|
||||
StopWatchInterface *timer = NULL;
|
||||
sdkCreateTimer(&timer);
|
||||
|
||||
// Get device properties
|
||||
struct cudaDeviceProp deviceProperties;
|
||||
cudaError_t cudaResult = cudaGetDeviceProperties(&deviceProperties, device);
|
||||
// Get device properties
|
||||
struct cudaDeviceProp deviceProperties;
|
||||
cudaError_t cudaResult = cudaGetDeviceProperties(&deviceProperties, device);
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
std::string msg("Could not get device properties: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
if (cudaResult != cudaSuccess) {
|
||||
std::string msg("Could not get device properties: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
// Evaluate on GPU
|
||||
printf("Estimating Pi on GPU (%s)\n\n", deviceProperties.name);
|
||||
PiEstimator<Real> estimator(numSims, device, threadBlockSize);
|
||||
sdkStartTimer(&timer);
|
||||
Real result = estimator();
|
||||
sdkStopTimer(&timer);
|
||||
elapsedTime = sdkGetAverageTimerValue(&timer) / 1000.0f;
|
||||
// Evaluate on GPU
|
||||
printf("Estimating Pi on GPU (%s)\n\n", deviceProperties.name);
|
||||
PiEstimator<Real> estimator(numSims, device, threadBlockSize);
|
||||
sdkStartTimer(&timer);
|
||||
Real result = estimator();
|
||||
sdkStopTimer(&timer);
|
||||
elapsedTime = sdkGetAverageTimerValue(&timer) / 1000.0f;
|
||||
|
||||
// Tolerance to compare result with expected
|
||||
// This is just to check that nothing has gone very wrong with the
|
||||
// test, the actual accuracy of the result depends on the number of
|
||||
// Monte Carlo trials
|
||||
const Real tolerance = static_cast<Real>(0.01);
|
||||
// Tolerance to compare result with expected
|
||||
// This is just to check that nothing has gone very wrong with the
|
||||
// test, the actual accuracy of the result depends on the number of
|
||||
// Monte Carlo trials
|
||||
const Real tolerance = static_cast<Real>(0.01);
|
||||
|
||||
// Display results
|
||||
Real abserror = fabs(result - static_cast<Real>(PI));
|
||||
Real relerror = abserror / static_cast<Real>(PI);
|
||||
printf("Precision: %s\n",
|
||||
(typeid(Real) == typeid(double)) ? "double" : "single");
|
||||
printf("Number of sims: %d\n", numSims);
|
||||
printf("Tolerance: %e\n", tolerance);
|
||||
printf("GPU result: %e\n", result);
|
||||
printf("Expected: %e\n", PI);
|
||||
printf("Absolute error: %e\n", abserror);
|
||||
printf("Relative error: %e\n\n", relerror);
|
||||
// Display results
|
||||
Real abserror = fabs(result - static_cast<Real>(PI));
|
||||
Real relerror = abserror / static_cast<Real>(PI);
|
||||
printf("Precision: %s\n", (typeid(Real) == typeid(double)) ? "double" : "single");
|
||||
printf("Number of sims: %d\n", numSims);
|
||||
printf("Tolerance: %e\n", tolerance);
|
||||
printf("GPU result: %e\n", result);
|
||||
printf("Expected: %e\n", PI);
|
||||
printf("Absolute error: %e\n", abserror);
|
||||
printf("Relative error: %e\n\n", relerror);
|
||||
|
||||
// Check result
|
||||
if (relerror > tolerance) {
|
||||
printf("computed result (%e) does not match expected result (%e).\n",
|
||||
result, PI);
|
||||
pass = false;
|
||||
} else {
|
||||
pass = true;
|
||||
}
|
||||
// Check result
|
||||
if (relerror > tolerance) {
|
||||
printf("computed result (%e) does not match expected result (%e).\n", result, PI);
|
||||
pass = false;
|
||||
}
|
||||
else {
|
||||
pass = true;
|
||||
}
|
||||
|
||||
// Print results
|
||||
printf(
|
||||
"MonteCarloEstimatePiQ, Performance = %.2f sims/s, Time = %.2f(ms), "
|
||||
"NumDevsUsed = %u, Blocksize = %u\n",
|
||||
numSims / elapsedTime, elapsedTime * 1000.0f, 1, threadBlockSize);
|
||||
// Print results
|
||||
printf("MonteCarloEstimatePiQ, Performance = %.2f sims/s, Time = %.2f(ms), "
|
||||
"NumDevsUsed = %u, Blocksize = %u\n",
|
||||
numSims / elapsedTime,
|
||||
elapsedTime * 1000.0f,
|
||||
1,
|
||||
threadBlockSize);
|
||||
|
||||
sdkDeleteTimer(&timer);
|
||||
sdkDeleteTimer(&timer);
|
||||
|
||||
return pass;
|
||||
return pass;
|
||||
}
|
||||
|
||||
// Explicit template instantiation
|
||||
|
||||
@@ -28,24 +28,24 @@
|
||||
#ifndef ASIANOPTION_H
|
||||
#define ASIANOPTION_H
|
||||
|
||||
template <typename Real>
|
||||
struct AsianOption {
|
||||
enum CallPut { Call, Put };
|
||||
template <typename Real> struct AsianOption
|
||||
{
|
||||
enum CallPut { Call, Put };
|
||||
|
||||
// Parameters
|
||||
Real spot;
|
||||
Real strike;
|
||||
Real r;
|
||||
Real sigma;
|
||||
Real tenor;
|
||||
Real dt;
|
||||
// Parameters
|
||||
Real spot;
|
||||
Real strike;
|
||||
Real r;
|
||||
Real sigma;
|
||||
Real tenor;
|
||||
Real dt;
|
||||
|
||||
// Value
|
||||
Real golden;
|
||||
Real value;
|
||||
// Value
|
||||
Real golden;
|
||||
Real value;
|
||||
|
||||
// Option type
|
||||
CallPut type;
|
||||
// Option type
|
||||
CallPut type;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -65,25 +65,27 @@
|
||||
|
||||
// This is the un-specialized struct. Note that we prevent instantiation of
|
||||
// this struct by making it abstract (i.e. with pure virtual methods).
|
||||
template <typename T>
|
||||
struct SharedMemory {
|
||||
// Ensure that we won't compile any un-specialized types
|
||||
virtual __device__ T &operator*() = 0;
|
||||
virtual __device__ T &operator[](int i) = 0;
|
||||
template <typename T> struct SharedMemory
|
||||
{
|
||||
// Ensure that we won't compile any un-specialized types
|
||||
virtual __device__ T &operator*() = 0;
|
||||
virtual __device__ T &operator[](int i) = 0;
|
||||
};
|
||||
|
||||
#define BUILD_SHAREDMEMORY_TYPE(t, n) \
|
||||
template <> \
|
||||
struct SharedMemory<t> { \
|
||||
__device__ t &operator*() { \
|
||||
extern __shared__ t n[]; \
|
||||
return *n; \
|
||||
} \
|
||||
__device__ t &operator[](int i) { \
|
||||
extern __shared__ t n[]; \
|
||||
return n[i]; \
|
||||
} \
|
||||
}
|
||||
#define BUILD_SHAREDMEMORY_TYPE(t, n) \
|
||||
template <> struct SharedMemory<t> \
|
||||
{ \
|
||||
__device__ t &operator*() \
|
||||
{ \
|
||||
extern __shared__ t n[]; \
|
||||
return *n; \
|
||||
} \
|
||||
__device__ t &operator[](int i) \
|
||||
{ \
|
||||
extern __shared__ t n[]; \
|
||||
return n[i]; \
|
||||
} \
|
||||
}
|
||||
|
||||
BUILD_SHAREDMEMORY_TYPE(int, s_int);
|
||||
BUILD_SHAREDMEMORY_TYPE(unsigned int, s_uint);
|
||||
|
||||
@@ -30,18 +30,17 @@
|
||||
|
||||
#include "asianoption.h"
|
||||
|
||||
template <typename Real>
|
||||
class PricingEngine {
|
||||
public:
|
||||
PricingEngine(unsigned int numSims, unsigned int device,
|
||||
unsigned int threadBlockSize, unsigned int seed);
|
||||
void operator()(AsianOption<Real> &option);
|
||||
template <typename Real> class PricingEngine
|
||||
{
|
||||
public:
|
||||
PricingEngine(unsigned int numSims, unsigned int device, unsigned int threadBlockSize, unsigned int seed);
|
||||
void operator()(AsianOption<Real> &option);
|
||||
|
||||
private:
|
||||
unsigned int m_seed;
|
||||
unsigned int m_numSims;
|
||||
unsigned int m_device;
|
||||
unsigned int m_threadBlockSize;
|
||||
private:
|
||||
unsigned int m_seed;
|
||||
unsigned int m_numSims;
|
||||
unsigned int m_device;
|
||||
unsigned int m_threadBlockSize;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -28,30 +28,31 @@
|
||||
#ifndef TEST_H
|
||||
#define TEST_H
|
||||
|
||||
template <typename Real>
|
||||
struct Test {
|
||||
Test() : pass(false){};
|
||||
template <typename Real> struct Test
|
||||
{
|
||||
Test()
|
||||
: pass(false) {};
|
||||
|
||||
int device;
|
||||
unsigned int numSims;
|
||||
unsigned int threadBlockSize;
|
||||
unsigned int seed;
|
||||
int device;
|
||||
unsigned int numSims;
|
||||
unsigned int threadBlockSize;
|
||||
unsigned int seed;
|
||||
|
||||
bool pass;
|
||||
double elapsedTime;
|
||||
bool pass;
|
||||
double elapsedTime;
|
||||
|
||||
bool operator()();
|
||||
bool operator()();
|
||||
};
|
||||
|
||||
// Defaults are arbitrary to give sensible runtime
|
||||
#define k_sims_min 100000
|
||||
#define k_sims_max 1000000
|
||||
#define k_sims_def 100000
|
||||
#define k_sims_qa 100000
|
||||
#define k_sims_min 100000
|
||||
#define k_sims_max 1000000
|
||||
#define k_sims_def 100000
|
||||
#define k_sims_qa 100000
|
||||
#define k_bsize_min 32
|
||||
#define k_bsize_def 128
|
||||
#define k_bsize_qa 128
|
||||
#define k_seed_def 1234
|
||||
#define k_seed_qa 1234
|
||||
#define k_bsize_qa 128
|
||||
#define k_seed_def 1234
|
||||
#define k_seed_qa 1234
|
||||
|
||||
#endif
|
||||
|
||||
@@ -41,209 +41,214 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <stdexcept>
|
||||
#include <cuda_runtime.h>
|
||||
#include <helper_timer.h>
|
||||
#include <helper_cuda.h>
|
||||
#include <helper_timer.h>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "../inc/test.h"
|
||||
|
||||
// Forward declarations
|
||||
void showHelp(const int argc, const char **argv);
|
||||
template <typename Real>
|
||||
void runTest(int argc, const char **argv);
|
||||
void showHelp(const int argc, const char **argv);
|
||||
template <typename Real> void runTest(int argc, const char **argv);
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
using std::invalid_argument;
|
||||
using std::string;
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
using std::invalid_argument;
|
||||
using std::string;
|
||||
|
||||
// Open the log file
|
||||
printf("Monte Carlo Single Asian Option (with PRNG)\n");
|
||||
printf("===========================================\n\n");
|
||||
// Open the log file
|
||||
printf("Monte Carlo Single Asian Option (with PRNG)\n");
|
||||
printf("===========================================\n\n");
|
||||
|
||||
// If help flag is set, display help and exit immediately
|
||||
if (checkCmdLineFlag(argc, (const char **)argv, "help")) {
|
||||
printf("Displaying help on console\n");
|
||||
showHelp(argc, (const char **)argv);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
// Check the precision (checked against the device capability later)
|
||||
try {
|
||||
char *value;
|
||||
|
||||
if (getCmdLineArgumentString(argc, (const char **)argv, "precision",
|
||||
&value)) {
|
||||
// Check requested precision is valid
|
||||
string prec(value);
|
||||
|
||||
if (prec.compare("single") == 0 || prec.compare("\"single\"") == 0) {
|
||||
runTest<float>(argc, (const char **)argv);
|
||||
} else if (prec.compare("double") == 0 ||
|
||||
prec.compare("\"double\"") == 0) {
|
||||
runTest<double>(argc, (const char **)argv);
|
||||
} else {
|
||||
printf(
|
||||
"specified precision (%s) is invalid, must be \"single\" or "
|
||||
"\"double\".\n",
|
||||
value);
|
||||
throw invalid_argument("precision");
|
||||
}
|
||||
} else {
|
||||
runTest<float>(argc, (const char **)argv);
|
||||
// If help flag is set, display help and exit immediately
|
||||
if (checkCmdLineFlag(argc, (const char **)argv, "help")) {
|
||||
printf("Displaying help on console\n");
|
||||
showHelp(argc, (const char **)argv);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
} catch (invalid_argument &e) {
|
||||
printf("invalid command line argument (%s)\n", e.what());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Finish
|
||||
exit(EXIT_SUCCESS);
|
||||
// Check the precision (checked against the device capability later)
|
||||
try {
|
||||
char *value;
|
||||
|
||||
if (getCmdLineArgumentString(argc, (const char **)argv, "precision", &value)) {
|
||||
// Check requested precision is valid
|
||||
string prec(value);
|
||||
|
||||
if (prec.compare("single") == 0 || prec.compare("\"single\"") == 0) {
|
||||
runTest<float>(argc, (const char **)argv);
|
||||
}
|
||||
else if (prec.compare("double") == 0 || prec.compare("\"double\"") == 0) {
|
||||
runTest<double>(argc, (const char **)argv);
|
||||
}
|
||||
else {
|
||||
printf("specified precision (%s) is invalid, must be \"single\" or "
|
||||
"\"double\".\n",
|
||||
value);
|
||||
throw invalid_argument("precision");
|
||||
}
|
||||
}
|
||||
else {
|
||||
runTest<float>(argc, (const char **)argv);
|
||||
}
|
||||
}
|
||||
catch (invalid_argument &e) {
|
||||
printf("invalid command line argument (%s)\n", e.what());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Finish
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
template <typename Real>
|
||||
void runTest(int argc, const char **argv) {
|
||||
using std::invalid_argument;
|
||||
using std::runtime_error;
|
||||
template <typename Real> void runTest(int argc, const char **argv)
|
||||
{
|
||||
using std::invalid_argument;
|
||||
using std::runtime_error;
|
||||
|
||||
try {
|
||||
Test<Real> test;
|
||||
int deviceCount = 0;
|
||||
cudaError_t cudaResult = cudaSuccess;
|
||||
try {
|
||||
Test<Real> test;
|
||||
int deviceCount = 0;
|
||||
cudaError_t cudaResult = cudaSuccess;
|
||||
|
||||
// by default specify GPU Device == 0
|
||||
test.device = 0;
|
||||
// by default specify GPU Device == 0
|
||||
test.device = 0;
|
||||
|
||||
// Get number of available devices
|
||||
cudaResult = cudaGetDeviceCount(&deviceCount);
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
printf("could not get device count.\n");
|
||||
throw runtime_error("cudaGetDeviceCount");
|
||||
}
|
||||
|
||||
// (default parameters)
|
||||
test.numSims = k_sims_qa;
|
||||
test.threadBlockSize = k_bsize_qa;
|
||||
test.seed = k_seed_qa;
|
||||
|
||||
{
|
||||
char *value = 0;
|
||||
|
||||
if (getCmdLineArgumentString(argc, argv, "device", &value)) {
|
||||
test.device = (int)atoi(value);
|
||||
|
||||
if (test.device >= deviceCount) {
|
||||
printf(
|
||||
"invalid target device specified on command line (device %d does "
|
||||
"not exist).\n",
|
||||
test.device);
|
||||
throw invalid_argument("device");
|
||||
}
|
||||
} else {
|
||||
test.device = gpuGetMaxGflopsDeviceId();
|
||||
}
|
||||
|
||||
if (getCmdLineArgumentString(argc, argv, "sims", &value)) {
|
||||
test.numSims = (unsigned int)atoi(value);
|
||||
|
||||
if (test.numSims < k_sims_min || test.numSims > k_sims_max) {
|
||||
printf(
|
||||
"specified number of simulations (%d) is invalid, must be "
|
||||
"between %d and %d.\n",
|
||||
test.numSims, k_sims_min, k_sims_max);
|
||||
throw invalid_argument("sims");
|
||||
}
|
||||
} else {
|
||||
test.numSims = k_sims_def;
|
||||
}
|
||||
|
||||
if (getCmdLineArgumentString(argc, argv, "block-size", &value)) {
|
||||
// Determine max threads per block
|
||||
cudaDeviceProp deviceProperties;
|
||||
cudaResult = cudaGetDeviceProperties(&deviceProperties, test.device);
|
||||
// Get number of available devices
|
||||
cudaResult = cudaGetDeviceCount(&deviceCount);
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
printf("cound not get device properties for device %d.\n",
|
||||
test.device);
|
||||
throw runtime_error("cudaGetDeviceProperties");
|
||||
printf("could not get device count.\n");
|
||||
throw runtime_error("cudaGetDeviceCount");
|
||||
}
|
||||
|
||||
// Check requested size is valid
|
||||
test.threadBlockSize = (unsigned int)atoi(value);
|
||||
// (default parameters)
|
||||
test.numSims = k_sims_qa;
|
||||
test.threadBlockSize = k_bsize_qa;
|
||||
test.seed = k_seed_qa;
|
||||
|
||||
if (test.threadBlockSize < k_bsize_min ||
|
||||
test.threadBlockSize > static_cast<unsigned int>(
|
||||
deviceProperties.maxThreadsPerBlock)) {
|
||||
printf(
|
||||
"specified block size (%d) is invalid, must be between %d and %d "
|
||||
"for device %d.\n",
|
||||
test.threadBlockSize, k_bsize_min,
|
||||
deviceProperties.maxThreadsPerBlock, test.device);
|
||||
throw invalid_argument("block-size");
|
||||
{
|
||||
char *value = 0;
|
||||
|
||||
if (getCmdLineArgumentString(argc, argv, "device", &value)) {
|
||||
test.device = (int)atoi(value);
|
||||
|
||||
if (test.device >= deviceCount) {
|
||||
printf("invalid target device specified on command line (device %d does "
|
||||
"not exist).\n",
|
||||
test.device);
|
||||
throw invalid_argument("device");
|
||||
}
|
||||
}
|
||||
else {
|
||||
test.device = gpuGetMaxGflopsDeviceId();
|
||||
}
|
||||
|
||||
if (getCmdLineArgumentString(argc, argv, "sims", &value)) {
|
||||
test.numSims = (unsigned int)atoi(value);
|
||||
|
||||
if (test.numSims < k_sims_min || test.numSims > k_sims_max) {
|
||||
printf("specified number of simulations (%d) is invalid, must be "
|
||||
"between %d and %d.\n",
|
||||
test.numSims,
|
||||
k_sims_min,
|
||||
k_sims_max);
|
||||
throw invalid_argument("sims");
|
||||
}
|
||||
}
|
||||
else {
|
||||
test.numSims = k_sims_def;
|
||||
}
|
||||
|
||||
if (getCmdLineArgumentString(argc, argv, "block-size", &value)) {
|
||||
// Determine max threads per block
|
||||
cudaDeviceProp deviceProperties;
|
||||
cudaResult = cudaGetDeviceProperties(&deviceProperties, test.device);
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
printf("cound not get device properties for device %d.\n", test.device);
|
||||
throw runtime_error("cudaGetDeviceProperties");
|
||||
}
|
||||
|
||||
// Check requested size is valid
|
||||
test.threadBlockSize = (unsigned int)atoi(value);
|
||||
|
||||
if (test.threadBlockSize < k_bsize_min
|
||||
|| test.threadBlockSize > static_cast<unsigned int>(deviceProperties.maxThreadsPerBlock)) {
|
||||
printf("specified block size (%d) is invalid, must be between %d and %d "
|
||||
"for device %d.\n",
|
||||
test.threadBlockSize,
|
||||
k_bsize_min,
|
||||
deviceProperties.maxThreadsPerBlock,
|
||||
test.device);
|
||||
throw invalid_argument("block-size");
|
||||
}
|
||||
|
||||
if (test.threadBlockSize & test.threadBlockSize - 1) {
|
||||
printf("specified block size (%d) is invalid, must be a power of two "
|
||||
"(see reduction function).\n",
|
||||
test.threadBlockSize);
|
||||
throw invalid_argument("block-size");
|
||||
}
|
||||
}
|
||||
else {
|
||||
test.threadBlockSize = k_bsize_def;
|
||||
}
|
||||
|
||||
if (getCmdLineArgumentString(argc, argv, "seed", &value)) {
|
||||
// Check requested seed is valid
|
||||
test.seed = (unsigned int)atoi(value);
|
||||
|
||||
if (test.seed == 0) {
|
||||
printf("specified seed (%d) is invalid, must be non-zero.\n", test.seed);
|
||||
throw invalid_argument("seed");
|
||||
}
|
||||
}
|
||||
else {
|
||||
test.seed = k_seed_def;
|
||||
}
|
||||
}
|
||||
|
||||
if (test.threadBlockSize & test.threadBlockSize - 1) {
|
||||
printf(
|
||||
"specified block size (%d) is invalid, must be a power of two "
|
||||
"(see reduction function).\n",
|
||||
test.threadBlockSize);
|
||||
throw invalid_argument("block-size");
|
||||
}
|
||||
} else {
|
||||
test.threadBlockSize = k_bsize_def;
|
||||
}
|
||||
|
||||
if (getCmdLineArgumentString(argc, argv, "seed", &value)) {
|
||||
// Check requested seed is valid
|
||||
test.seed = (unsigned int)atoi(value);
|
||||
|
||||
if (test.seed == 0) {
|
||||
printf("specified seed (%d) is invalid, must be non-zero.\n",
|
||||
test.seed);
|
||||
throw invalid_argument("seed");
|
||||
}
|
||||
} else {
|
||||
test.seed = k_seed_def;
|
||||
}
|
||||
// Execute
|
||||
test();
|
||||
}
|
||||
catch (invalid_argument &e) {
|
||||
printf("invalid command line argument (%s)\n", e.what());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
catch (runtime_error &e) {
|
||||
printf("runtime error (%s)\n", e.what());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
// Execute
|
||||
test();
|
||||
} catch (invalid_argument &e) {
|
||||
printf("invalid command line argument (%s)\n", e.what());
|
||||
exit(EXIT_FAILURE);
|
||||
} catch (runtime_error &e) {
|
||||
printf("runtime error (%s)\n", e.what());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
void showHelp(int argc, const char **argv) {
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
using std::left;
|
||||
using std::setw;
|
||||
void showHelp(int argc, const char **argv)
|
||||
{
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
using std::left;
|
||||
using std::setw;
|
||||
|
||||
if (argc > 0) {
|
||||
cout << endl << argv[0] << endl;
|
||||
}
|
||||
if (argc > 0) {
|
||||
cout << endl << argv[0] << endl;
|
||||
}
|
||||
|
||||
cout << endl << "Syntax:" << endl;
|
||||
cout << left;
|
||||
cout << " " << setw(20) << "--device=<device>"
|
||||
<< "Specify device to use for execution" << endl;
|
||||
cout << " " << setw(20) << "--sims=<N>"
|
||||
<< "Specify number of Monte Carlo simulations" << endl;
|
||||
cout << " " << setw(20) << "--block-size=<N>"
|
||||
<< "Specify number of threads per block" << endl;
|
||||
cout << " " << setw(20) << "--seed=<N>"
|
||||
<< "Specify the seed to use for the random number generator" << endl;
|
||||
cout << " " << setw(20) << "--precision=<P>"
|
||||
<< "Specify the precision (\"single\" or \"double\")" << endl;
|
||||
cout << endl;
|
||||
cout << " " << setw(20) << "--noprompt"
|
||||
<< "Skip prompt before exit" << endl;
|
||||
cout << endl;
|
||||
cout << endl << "Syntax:" << endl;
|
||||
cout << left;
|
||||
cout << " " << setw(20) << "--device=<device>"
|
||||
<< "Specify device to use for execution" << endl;
|
||||
cout << " " << setw(20) << "--sims=<N>"
|
||||
<< "Specify number of Monte Carlo simulations" << endl;
|
||||
cout << " " << setw(20) << "--block-size=<N>"
|
||||
<< "Specify number of threads per block" << endl;
|
||||
cout << " " << setw(20) << "--seed=<N>"
|
||||
<< "Specify the seed to use for the random number generator" << endl;
|
||||
cout << " " << setw(20) << "--precision=<P>"
|
||||
<< "Specify the precision (\"single\" or \"double\")" << endl;
|
||||
cout << endl;
|
||||
cout << " " << setw(20) << "--noprompt"
|
||||
<< "Skip prompt before exit" << endl;
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
@@ -25,15 +25,15 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "../inc/pricingengine.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cooperative_groups.h>
|
||||
#include <cuda_runtime.h>
|
||||
#include <numeric>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <typeinfo>
|
||||
#include <cuda_runtime.h>
|
||||
#include <cooperative_groups.h>
|
||||
#include <vector>
|
||||
|
||||
#include "../inc/pricingengine.h"
|
||||
|
||||
namespace cg = cooperative_groups;
|
||||
#include <curand_kernel.h>
|
||||
@@ -45,328 +45,323 @@ using std::string;
|
||||
using std::vector;
|
||||
|
||||
// RNG init kernel
|
||||
__global__ void initRNG(curandState *const rngStates, const unsigned int seed) {
|
||||
// Determine thread ID
|
||||
unsigned int tid = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
__global__ void initRNG(curandState *const rngStates, const unsigned int seed)
|
||||
{
|
||||
// Determine thread ID
|
||||
unsigned int tid = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
|
||||
// Initialise the RNG
|
||||
curand_init(seed, tid, 0, &rngStates[tid]);
|
||||
// Initialise the RNG
|
||||
curand_init(seed, tid, 0, &rngStates[tid]);
|
||||
}
|
||||
|
||||
__device__ inline float getPathStep(float &drift, float &diffusion,
|
||||
curandState &state) {
|
||||
return expf(drift + diffusion * curand_normal(&state));
|
||||
__device__ inline float getPathStep(float &drift, float &diffusion, curandState &state)
|
||||
{
|
||||
return expf(drift + diffusion * curand_normal(&state));
|
||||
}
|
||||
__device__ inline double getPathStep(double &drift, double &diffusion,
|
||||
curandState &state) {
|
||||
return exp(drift + diffusion * curand_normal_double(&state));
|
||||
__device__ inline double getPathStep(double &drift, double &diffusion, curandState &state)
|
||||
{
|
||||
return exp(drift + diffusion * curand_normal_double(&state));
|
||||
}
|
||||
|
||||
// Path generation kernel
|
||||
template <typename Real>
|
||||
__global__ void generatePaths(Real *const paths, curandState *const rngStates,
|
||||
__global__ void generatePaths(Real *const paths,
|
||||
curandState *const rngStates,
|
||||
const AsianOption<Real> *const option,
|
||||
const unsigned int numSims,
|
||||
const unsigned int numTimesteps) {
|
||||
// Determine thread ID
|
||||
unsigned int tid = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
unsigned int step = gridDim.x * blockDim.x;
|
||||
const unsigned int numSims,
|
||||
const unsigned int numTimesteps)
|
||||
{
|
||||
// Determine thread ID
|
||||
unsigned int tid = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
unsigned int step = gridDim.x * blockDim.x;
|
||||
|
||||
// Compute parameters
|
||||
Real drift =
|
||||
(option->r - static_cast<Real>(0.5) * option->sigma * option->sigma) *
|
||||
option->dt;
|
||||
Real diffusion = option->sigma * sqrt(option->dt);
|
||||
// Compute parameters
|
||||
Real drift = (option->r - static_cast<Real>(0.5) * option->sigma * option->sigma) * option->dt;
|
||||
Real diffusion = option->sigma * sqrt(option->dt);
|
||||
|
||||
// Initialise the RNG
|
||||
curandState localState = rngStates[tid];
|
||||
// Initialise the RNG
|
||||
curandState localState = rngStates[tid];
|
||||
|
||||
for (unsigned int i = tid; i < numSims; i += step) {
|
||||
// Shift the output pointer
|
||||
Real *output = paths + i;
|
||||
for (unsigned int i = tid; i < numSims; i += step) {
|
||||
// Shift the output pointer
|
||||
Real *output = paths + i;
|
||||
|
||||
// Simulate the path
|
||||
Real s = static_cast<Real>(1);
|
||||
// Simulate the path
|
||||
Real s = static_cast<Real>(1);
|
||||
|
||||
for (unsigned int t = 0; t < numTimesteps; t++, output += numSims) {
|
||||
s *= getPathStep(drift, diffusion, localState);
|
||||
*output = s;
|
||||
for (unsigned int t = 0; t < numTimesteps; t++, output += numSims) {
|
||||
s *= getPathStep(drift, diffusion, localState);
|
||||
*output = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Real>
|
||||
__device__ Real reduce_sum(Real in, cg::thread_block cta) {
|
||||
SharedMemory<Real> sdata;
|
||||
template <typename Real> __device__ Real reduce_sum(Real in, cg::thread_block cta)
|
||||
{
|
||||
SharedMemory<Real> sdata;
|
||||
|
||||
// Perform first level of reduction:
|
||||
// - Write to shared memory
|
||||
unsigned int ltid = threadIdx.x;
|
||||
// Perform first level of reduction:
|
||||
// - Write to shared memory
|
||||
unsigned int ltid = threadIdx.x;
|
||||
|
||||
sdata[ltid] = in;
|
||||
cg::sync(cta);
|
||||
sdata[ltid] = in;
|
||||
cg::sync(cta);
|
||||
|
||||
// Do reduction in shared mem
|
||||
for (unsigned int s = blockDim.x / 2; s > 0; s >>= 1) {
|
||||
if (ltid < s) {
|
||||
sdata[ltid] += sdata[ltid + s];
|
||||
// Do reduction in shared mem
|
||||
for (unsigned int s = blockDim.x / 2; s > 0; s >>= 1) {
|
||||
if (ltid < s) {
|
||||
sdata[ltid] += sdata[ltid + s];
|
||||
}
|
||||
|
||||
cg::sync(cta);
|
||||
}
|
||||
|
||||
cg::sync(cta);
|
||||
}
|
||||
|
||||
return sdata[0];
|
||||
return sdata[0];
|
||||
}
|
||||
|
||||
// Valuation kernel
|
||||
template <typename Real>
|
||||
__global__ void computeValue(Real *const values, const Real *const paths,
|
||||
__global__ void computeValue(Real *const values,
|
||||
const Real *const paths,
|
||||
const AsianOption<Real> *const option,
|
||||
const unsigned int numSims,
|
||||
const unsigned int numTimesteps) {
|
||||
// Handle to thread block group
|
||||
cg::thread_block cta = cg::this_thread_block();
|
||||
// Determine thread ID
|
||||
unsigned int bid = blockIdx.x;
|
||||
unsigned int tid = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
unsigned int step = gridDim.x * blockDim.x;
|
||||
const unsigned int numSims,
|
||||
const unsigned int numTimesteps)
|
||||
{
|
||||
// Handle to thread block group
|
||||
cg::thread_block cta = cg::this_thread_block();
|
||||
// Determine thread ID
|
||||
unsigned int bid = blockIdx.x;
|
||||
unsigned int tid = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
unsigned int step = gridDim.x * blockDim.x;
|
||||
|
||||
Real sumPayoffs = static_cast<Real>(0);
|
||||
Real sumPayoffs = static_cast<Real>(0);
|
||||
|
||||
for (unsigned int i = tid; i < numSims; i += step) {
|
||||
// Shift the input pointer
|
||||
const Real *path = paths + i;
|
||||
// Compute the arithmetic average
|
||||
Real avg = static_cast<Real>(0);
|
||||
for (unsigned int i = tid; i < numSims; i += step) {
|
||||
// Shift the input pointer
|
||||
const Real *path = paths + i;
|
||||
// Compute the arithmetic average
|
||||
Real avg = static_cast<Real>(0);
|
||||
|
||||
for (unsigned int t = 0; t < numTimesteps; t++, path += numSims) {
|
||||
avg += *path;
|
||||
for (unsigned int t = 0; t < numTimesteps; t++, path += numSims) {
|
||||
avg += *path;
|
||||
}
|
||||
|
||||
avg = avg * option->spot / numTimesteps;
|
||||
// Compute the payoff
|
||||
Real payoff = avg - option->strike;
|
||||
|
||||
if (option->type == AsianOption<Real>::Put) {
|
||||
payoff = -payoff;
|
||||
}
|
||||
|
||||
payoff = max(static_cast<Real>(0), payoff);
|
||||
// Accumulate payoff locally
|
||||
sumPayoffs += payoff;
|
||||
}
|
||||
|
||||
avg = avg * option->spot / numTimesteps;
|
||||
// Compute the payoff
|
||||
Real payoff = avg - option->strike;
|
||||
// Reduce within the block
|
||||
sumPayoffs = reduce_sum<Real>(sumPayoffs, cta);
|
||||
|
||||
if (option->type == AsianOption<Real>::Put) {
|
||||
payoff = -payoff;
|
||||
// Store the result
|
||||
if (threadIdx.x == 0) {
|
||||
values[bid] = sumPayoffs;
|
||||
}
|
||||
|
||||
payoff = max(static_cast<Real>(0), payoff);
|
||||
// Accumulate payoff locally
|
||||
sumPayoffs += payoff;
|
||||
}
|
||||
|
||||
// Reduce within the block
|
||||
sumPayoffs = reduce_sum<Real>(sumPayoffs, cta);
|
||||
|
||||
// Store the result
|
||||
if (threadIdx.x == 0) {
|
||||
values[bid] = sumPayoffs;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Real>
|
||||
PricingEngine<Real>::PricingEngine(unsigned int numSims, unsigned int device,
|
||||
PricingEngine<Real>::PricingEngine(unsigned int numSims,
|
||||
unsigned int device,
|
||||
unsigned int threadBlockSize,
|
||||
unsigned int seed)
|
||||
: m_numSims(numSims),
|
||||
m_device(device),
|
||||
m_threadBlockSize(threadBlockSize),
|
||||
m_seed(seed) {}
|
||||
: m_numSims(numSims)
|
||||
, m_device(device)
|
||||
, m_threadBlockSize(threadBlockSize)
|
||||
, m_seed(seed)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename Real>
|
||||
void PricingEngine<Real>::operator()(AsianOption<Real> &option) {
|
||||
cudaError_t cudaResult = cudaSuccess;
|
||||
struct cudaDeviceProp deviceProperties;
|
||||
struct cudaFuncAttributes funcAttributes;
|
||||
template <typename Real> void PricingEngine<Real>::operator()(AsianOption<Real> &option)
|
||||
{
|
||||
cudaError_t cudaResult = cudaSuccess;
|
||||
struct cudaDeviceProp deviceProperties;
|
||||
struct cudaFuncAttributes funcAttributes;
|
||||
|
||||
// Get device properties
|
||||
cudaResult = cudaGetDeviceProperties(&deviceProperties, m_device);
|
||||
// Get device properties
|
||||
cudaResult = cudaGetDeviceProperties(&deviceProperties, m_device);
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not get device properties: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not get device properties: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
// Check precision is valid
|
||||
unsigned int deviceVersion =
|
||||
deviceProperties.major * 10 + deviceProperties.minor;
|
||||
// Check precision is valid
|
||||
unsigned int deviceVersion = deviceProperties.major * 10 + deviceProperties.minor;
|
||||
|
||||
if (typeid(Real) == typeid(double) && deviceVersion < 13) {
|
||||
throw std::runtime_error("Device does not have double precision support");
|
||||
}
|
||||
if (typeid(Real) == typeid(double) && deviceVersion < 13) {
|
||||
throw std::runtime_error("Device does not have double precision support");
|
||||
}
|
||||
|
||||
// Attach to GPU
|
||||
cudaResult = cudaSetDevice(m_device);
|
||||
// Attach to GPU
|
||||
cudaResult = cudaSetDevice(m_device);
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not set CUDA device: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not set CUDA device: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
// Determine how to divide the work between cores
|
||||
dim3 block;
|
||||
dim3 grid;
|
||||
block.x = m_threadBlockSize;
|
||||
grid.x = (m_numSims + m_threadBlockSize - 1) / m_threadBlockSize;
|
||||
// Determine how to divide the work between cores
|
||||
dim3 block;
|
||||
dim3 grid;
|
||||
block.x = m_threadBlockSize;
|
||||
grid.x = (m_numSims + m_threadBlockSize - 1) / m_threadBlockSize;
|
||||
|
||||
// Aim to launch around ten or more times as many blocks as there
|
||||
// are multiprocessors on the target device.
|
||||
unsigned int blocksPerSM = 10;
|
||||
unsigned int numSMs = deviceProperties.multiProcessorCount;
|
||||
// Aim to launch around ten or more times as many blocks as there
|
||||
// are multiprocessors on the target device.
|
||||
unsigned int blocksPerSM = 10;
|
||||
unsigned int numSMs = deviceProperties.multiProcessorCount;
|
||||
|
||||
while (grid.x > 2 * blocksPerSM * numSMs) {
|
||||
grid.x >>= 1;
|
||||
}
|
||||
while (grid.x > 2 * blocksPerSM * numSMs) {
|
||||
grid.x >>= 1;
|
||||
}
|
||||
|
||||
// Get initRNG function properties and check the maximum block size
|
||||
cudaResult = cudaFuncGetAttributes(&funcAttributes, initRNG);
|
||||
// Get initRNG function properties and check the maximum block size
|
||||
cudaResult = cudaFuncGetAttributes(&funcAttributes, initRNG);
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not get function attributes: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not get function attributes: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
if (block.x > (unsigned int)funcAttributes.maxThreadsPerBlock) {
|
||||
throw std::runtime_error(
|
||||
"Block X dimension is too large for initRNG kernel");
|
||||
}
|
||||
if (block.x > (unsigned int)funcAttributes.maxThreadsPerBlock) {
|
||||
throw std::runtime_error("Block X dimension is too large for initRNG kernel");
|
||||
}
|
||||
|
||||
// Get generatePaths function properties and check the maximum block size
|
||||
cudaResult = cudaFuncGetAttributes(&funcAttributes, generatePaths<Real>);
|
||||
// Get generatePaths function properties and check the maximum block size
|
||||
cudaResult = cudaFuncGetAttributes(&funcAttributes, generatePaths<Real>);
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not get function attributes: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not get function attributes: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
if (block.x > (unsigned int)funcAttributes.maxThreadsPerBlock) {
|
||||
throw std::runtime_error(
|
||||
"Block X dimension is too large for generatePaths kernel");
|
||||
}
|
||||
if (block.x > (unsigned int)funcAttributes.maxThreadsPerBlock) {
|
||||
throw std::runtime_error("Block X dimension is too large for generatePaths kernel");
|
||||
}
|
||||
|
||||
// Get computeValue function properties and check the maximum block size
|
||||
cudaResult = cudaFuncGetAttributes(&funcAttributes, computeValue<Real>);
|
||||
// Get computeValue function properties and check the maximum block size
|
||||
cudaResult = cudaFuncGetAttributes(&funcAttributes, computeValue<Real>);
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not get function attributes: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not get function attributes: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
if (block.x > (unsigned int)funcAttributes.maxThreadsPerBlock) {
|
||||
throw std::runtime_error(
|
||||
"Block X dimension is too large for computeValue kernel");
|
||||
}
|
||||
if (block.x > (unsigned int)funcAttributes.maxThreadsPerBlock) {
|
||||
throw std::runtime_error("Block X dimension is too large for computeValue kernel");
|
||||
}
|
||||
|
||||
// Setup problem on GPU
|
||||
AsianOption<Real> *d_option = 0;
|
||||
cudaResult = cudaMalloc((void **)&d_option, sizeof(AsianOption<Real>));
|
||||
// Setup problem on GPU
|
||||
AsianOption<Real> *d_option = 0;
|
||||
cudaResult = cudaMalloc((void **)&d_option, sizeof(AsianOption<Real>));
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not allocate memory on device for option data: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not allocate memory on device for option data: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
cudaResult = cudaMemcpy(d_option, &option, sizeof(AsianOption<Real>),
|
||||
cudaMemcpyHostToDevice);
|
||||
cudaResult = cudaMemcpy(d_option, &option, sizeof(AsianOption<Real>), cudaMemcpyHostToDevice);
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not copy data to device: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not copy data to device: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
// Allocate memory for paths
|
||||
Real *d_paths = 0;
|
||||
int numTimesteps = static_cast<int>(option.tenor / option.dt);
|
||||
cudaResult =
|
||||
cudaMalloc((void **)&d_paths, m_numSims * numTimesteps * sizeof(Real));
|
||||
// Allocate memory for paths
|
||||
Real *d_paths = 0;
|
||||
int numTimesteps = static_cast<int>(option.tenor / option.dt);
|
||||
cudaResult = cudaMalloc((void **)&d_paths, m_numSims * numTimesteps * sizeof(Real));
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not allocate memory on device for paths: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not allocate memory on device for paths: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
// Allocate memory for RNG states
|
||||
curandState *d_rngStates = 0;
|
||||
cudaResult =
|
||||
cudaMalloc((void **)&d_rngStates, grid.x * block.x * sizeof(curandState));
|
||||
// Allocate memory for RNG states
|
||||
curandState *d_rngStates = 0;
|
||||
cudaResult = cudaMalloc((void **)&d_rngStates, grid.x * block.x * sizeof(curandState));
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not allocate memory on device for RNG state: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not allocate memory on device for RNG state: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
// Allocate memory for result
|
||||
Real *d_values = 0;
|
||||
cudaResult = cudaMalloc((void **)&d_values, grid.x * sizeof(Real));
|
||||
// Allocate memory for result
|
||||
Real *d_values = 0;
|
||||
cudaResult = cudaMalloc((void **)&d_values, grid.x * sizeof(Real));
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not allocate memory on device for partial results: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not allocate memory on device for partial results: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
// Initialise RNG
|
||||
initRNG<<<grid, block>>>(d_rngStates, m_seed);
|
||||
// Initialise RNG
|
||||
initRNG<<<grid, block>>>(d_rngStates, m_seed);
|
||||
|
||||
// Generate paths
|
||||
generatePaths<Real><<<grid, block>>>(d_paths, d_rngStates, d_option,
|
||||
m_numSims, numTimesteps);
|
||||
// Generate paths
|
||||
generatePaths<Real><<<grid, block>>>(d_paths, d_rngStates, d_option, m_numSims, numTimesteps);
|
||||
|
||||
// Compute value
|
||||
computeValue<<<grid, block, block.x * sizeof(Real)>>>(
|
||||
d_values, d_paths, d_option, m_numSims, numTimesteps);
|
||||
// Compute value
|
||||
computeValue<<<grid, block, block.x * sizeof(Real)>>>(d_values, d_paths, d_option, m_numSims, numTimesteps);
|
||||
|
||||
// Copy partial results back
|
||||
vector<Real> values(grid.x);
|
||||
cudaResult = cudaMemcpy(&values[0], d_values, grid.x * sizeof(Real),
|
||||
cudaMemcpyDeviceToHost);
|
||||
// Copy partial results back
|
||||
vector<Real> values(grid.x);
|
||||
cudaResult = cudaMemcpy(&values[0], d_values, grid.x * sizeof(Real), cudaMemcpyDeviceToHost);
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not copy partial results to host: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
if (cudaResult != cudaSuccess) {
|
||||
string msg("Could not copy partial results to host: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
// Complete sum-reduction on host
|
||||
option.value =
|
||||
std::accumulate(values.begin(), values.end(), static_cast<Real>(0));
|
||||
// Complete sum-reduction on host
|
||||
option.value = std::accumulate(values.begin(), values.end(), static_cast<Real>(0));
|
||||
|
||||
// Compute the mean
|
||||
option.value /= m_numSims;
|
||||
// Compute the mean
|
||||
option.value /= m_numSims;
|
||||
|
||||
// Discount to present value
|
||||
option.value *= exp(-option.r * option.tenor);
|
||||
// Discount to present value
|
||||
option.value *= exp(-option.r * option.tenor);
|
||||
|
||||
// Cleanup
|
||||
if (d_option) {
|
||||
cudaFree(d_option);
|
||||
d_option = 0;
|
||||
}
|
||||
// Cleanup
|
||||
if (d_option) {
|
||||
cudaFree(d_option);
|
||||
d_option = 0;
|
||||
}
|
||||
|
||||
if (d_paths) {
|
||||
cudaFree(d_paths);
|
||||
d_paths = 0;
|
||||
}
|
||||
if (d_paths) {
|
||||
cudaFree(d_paths);
|
||||
d_paths = 0;
|
||||
}
|
||||
|
||||
if (d_rngStates) {
|
||||
cudaFree(d_rngStates);
|
||||
d_rngStates = 0;
|
||||
}
|
||||
if (d_rngStates) {
|
||||
cudaFree(d_rngStates);
|
||||
d_rngStates = 0;
|
||||
}
|
||||
|
||||
if (d_values) {
|
||||
cudaFree(d_values);
|
||||
d_values = 0;
|
||||
}
|
||||
if (d_values) {
|
||||
cudaFree(d_values);
|
||||
d_values = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Explicit template instantiation
|
||||
|
||||
@@ -27,111 +27,110 @@
|
||||
|
||||
#include "../inc/test.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <stdexcept>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
#include <typeinfo>
|
||||
#include <stdio.h>
|
||||
#include <cuda_runtime.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <helper_timer.h>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <math.h>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <stdio.h>
|
||||
#include <typeinfo>
|
||||
|
||||
#include "../inc/asianoption.h"
|
||||
#include "../inc/pricingengine.h"
|
||||
|
||||
template <typename Real>
|
||||
bool Test<Real>::operator()() {
|
||||
using std::endl;
|
||||
using std::setw;
|
||||
using std::stringstream;
|
||||
template <typename Real> bool Test<Real>::operator()()
|
||||
{
|
||||
using std::endl;
|
||||
using std::setw;
|
||||
using std::stringstream;
|
||||
|
||||
StopWatchInterface *timer = NULL;
|
||||
sdkCreateTimer(&timer);
|
||||
StopWatchInterface *timer = NULL;
|
||||
sdkCreateTimer(&timer);
|
||||
|
||||
// Get device properties
|
||||
struct cudaDeviceProp deviceProperties;
|
||||
cudaError_t cudaResult = cudaGetDeviceProperties(&deviceProperties, device);
|
||||
// Get device properties
|
||||
struct cudaDeviceProp deviceProperties;
|
||||
cudaError_t cudaResult = cudaGetDeviceProperties(&deviceProperties, device);
|
||||
|
||||
if (cudaResult != cudaSuccess) {
|
||||
std::string msg("Could not get device properties: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
if (cudaResult != cudaSuccess) {
|
||||
std::string msg("Could not get device properties: ");
|
||||
msg += cudaGetErrorString(cudaResult);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
// This test prices a single Asian call option with European
|
||||
// exercise, with the priced averaged arithmetically on discrete
|
||||
// trading days (weekdays).
|
||||
AsianOption<Real> option;
|
||||
option.spot = static_cast<Real>(40);
|
||||
option.strike = static_cast<Real>(35);
|
||||
option.r = static_cast<Real>(0.03);
|
||||
option.sigma = static_cast<Real>(0.20);
|
||||
option.tenor = static_cast<Real>(1.0 / 3.0);
|
||||
option.dt = static_cast<Real>(1.0 / 261);
|
||||
option.type = AsianOption<Real>::Call;
|
||||
option.value = static_cast<Real>(0.0);
|
||||
option.golden = static_cast<Real>(5.162534);
|
||||
// This test prices a single Asian call option with European
|
||||
// exercise, with the priced averaged arithmetically on discrete
|
||||
// trading days (weekdays).
|
||||
AsianOption<Real> option;
|
||||
option.spot = static_cast<Real>(40);
|
||||
option.strike = static_cast<Real>(35);
|
||||
option.r = static_cast<Real>(0.03);
|
||||
option.sigma = static_cast<Real>(0.20);
|
||||
option.tenor = static_cast<Real>(1.0 / 3.0);
|
||||
option.dt = static_cast<Real>(1.0 / 261);
|
||||
option.type = AsianOption<Real>::Call;
|
||||
option.value = static_cast<Real>(0.0);
|
||||
option.golden = static_cast<Real>(5.162534);
|
||||
|
||||
// Evaluate on GPU
|
||||
printf("Pricing option on GPU (%s)\n\n", deviceProperties.name);
|
||||
PricingEngine<Real> pricer(numSims, device, threadBlockSize, seed);
|
||||
sdkStartTimer(&timer);
|
||||
pricer(option);
|
||||
sdkStopTimer(&timer);
|
||||
elapsedTime = sdkGetAverageTimerValue(&timer) / 1000.0f;
|
||||
// Evaluate on GPU
|
||||
printf("Pricing option on GPU (%s)\n\n", deviceProperties.name);
|
||||
PricingEngine<Real> pricer(numSims, device, threadBlockSize, seed);
|
||||
sdkStartTimer(&timer);
|
||||
pricer(option);
|
||||
sdkStopTimer(&timer);
|
||||
elapsedTime = sdkGetAverageTimerValue(&timer) / 1000.0f;
|
||||
|
||||
// Tolerance to compare result with expected
|
||||
// This is just to check that nothing has gone very wrong with the
|
||||
// test, the actual accuracy of the result depends on the number of
|
||||
// Monte Carlo trials
|
||||
const Real tolerance = static_cast<Real>(0.1);
|
||||
// Tolerance to compare result with expected
|
||||
// This is just to check that nothing has gone very wrong with the
|
||||
// test, the actual accuracy of the result depends on the number of
|
||||
// Monte Carlo trials
|
||||
const Real tolerance = static_cast<Real>(0.1);
|
||||
|
||||
// Display results
|
||||
stringstream output;
|
||||
output << "Precision: "
|
||||
<< ((typeid(Real) == typeid(double)) ? "double" : "single") << endl;
|
||||
output << "Number of sims: " << numSims << endl;
|
||||
output << endl;
|
||||
output << " Spot | Strike | r | sigma | tenor | "
|
||||
"Call/Put | Value | Expected |"
|
||||
<< endl;
|
||||
output << "-----------|------------|------------|------------|------------|--"
|
||||
"----------|------------|------------|"
|
||||
<< endl;
|
||||
output << setw(10) << option.spot << " | ";
|
||||
output << setw(10) << option.strike << " | ";
|
||||
output << setw(10) << option.r << " | ";
|
||||
output << setw(10) << option.sigma << " | ";
|
||||
output << setw(10) << option.tenor << " | ";
|
||||
output << setw(10)
|
||||
<< (option.type == AsianOption<Real>::Call ? "Call" : "Put") << " | ";
|
||||
output << setw(10) << option.value << " | ";
|
||||
output << setw(10) << option.golden << " |";
|
||||
// Display results
|
||||
stringstream output;
|
||||
output << "Precision: " << ((typeid(Real) == typeid(double)) ? "double" : "single") << endl;
|
||||
output << "Number of sims: " << numSims << endl;
|
||||
output << endl;
|
||||
output << " Spot | Strike | r | sigma | tenor | "
|
||||
"Call/Put | Value | Expected |"
|
||||
<< endl;
|
||||
output << "-----------|------------|------------|------------|------------|--"
|
||||
"----------|------------|------------|"
|
||||
<< endl;
|
||||
output << setw(10) << option.spot << " | ";
|
||||
output << setw(10) << option.strike << " | ";
|
||||
output << setw(10) << option.r << " | ";
|
||||
output << setw(10) << option.sigma << " | ";
|
||||
output << setw(10) << option.tenor << " | ";
|
||||
output << setw(10) << (option.type == AsianOption<Real>::Call ? "Call" : "Put") << " | ";
|
||||
output << setw(10) << option.value << " | ";
|
||||
output << setw(10) << option.golden << " |";
|
||||
|
||||
printf("%s\n\n", output.str().c_str());
|
||||
printf("%s\n\n", output.str().c_str());
|
||||
|
||||
// Check result
|
||||
if (fabs(option.value - option.golden) > tolerance) {
|
||||
printf("computed result (%e) does not match expected result (%e).\n",
|
||||
option.value, option.golden);
|
||||
pass = false;
|
||||
} else {
|
||||
pass = true;
|
||||
}
|
||||
// Check result
|
||||
if (fabs(option.value - option.golden) > tolerance) {
|
||||
printf("computed result (%e) does not match expected result (%e).\n", option.value, option.golden);
|
||||
pass = false;
|
||||
}
|
||||
else {
|
||||
pass = true;
|
||||
}
|
||||
|
||||
// Print results
|
||||
printf(
|
||||
"MonteCarloSingleAsianOptionP, Performance = %.2f sims/s, Time = "
|
||||
"%.2f(ms), NumDevsUsed = %u, Blocksize = %u\n",
|
||||
numSims / elapsedTime, elapsedTime * 1000.0f, 1, threadBlockSize);
|
||||
// Print results
|
||||
printf("MonteCarloSingleAsianOptionP, Performance = %.2f sims/s, Time = "
|
||||
"%.2f(ms), NumDevsUsed = %u, Blocksize = %u\n",
|
||||
numSims / elapsedTime,
|
||||
elapsedTime * 1000.0f,
|
||||
1,
|
||||
threadBlockSize);
|
||||
|
||||
sdkDeleteTimer(&timer);
|
||||
sdkDeleteTimer(&timer);
|
||||
|
||||
return pass;
|
||||
return pass;
|
||||
}
|
||||
|
||||
// Explicit template instantiation
|
||||
|
||||
@@ -83,7 +83,7 @@ This example demonstrates an efficient CUDA implementation of parallel prefix su
|
||||
This sample demonstrates an approach to the image segmentation trees construction. This method is based on Boruvka's MST algorithm.
|
||||
|
||||
### [shfl_scan](./shfl_scan)
|
||||
This example demonstrates how to use the shuffle intrinsic __shfl_up_sync to perform a scan operation across a thread block.
|
||||
This example demonstrates how to use the shuffle intrinsic __shfl_up_sync to perform a scan operation across a thread block.
|
||||
|
||||
### [sortingNetworks](./sortingNetworks)
|
||||
This sample implements bitonic sort and odd-even merge sort (also known as Batcher's sort), algorithms belonging to the class of sorting networks. While generally subefficient, for large sequences compared to algorithms with better asymptotic algorithmic complexity (i.e. merge sort or radix sort), this may be the preferred algorithms of choice for sorting batches of short-sized to mid-sized (key, value) array pairs. Refer to an excellent tutorial by H. W. Lang http://www.iti.fh-flensburg.de/lang/algorithmen/sortieren/networks/indexen.htm
|
||||
@@ -102,4 +102,3 @@ This sample shows how to perform a reduction operation on an array of values usi
|
||||
|
||||
### [threadMigration](./threadMigration)
|
||||
Simple program illustrating how to the CUDA Context Management API and uses the new CUDA 4.0 parameter passing and CUDA launch API. CUDA contexts can be created separately and attached independently to different threads.
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -54,15 +54,15 @@
|
||||
#endif
|
||||
|
||||
// CUDA utilities and system includes
|
||||
#include <cuda_runtime.h>
|
||||
#include <cuda_gl_interop.h>
|
||||
#include <cuda_runtime.h>
|
||||
|
||||
// Helper functions
|
||||
#include <helper_functions.h> // CUDA SDK Helper functions
|
||||
#include <helper_cuda.h> // CUDA device initialization helper functions
|
||||
#include <helper_cuda.h> // CUDA device initialization helper functions
|
||||
#include <helper_functions.h> // CUDA SDK Helper functions
|
||||
|
||||
#define MAX_EPSILON_ERROR 5.0f
|
||||
#define REFRESH_DELAY 10 // ms
|
||||
#define REFRESH_DELAY 10 // ms
|
||||
|
||||
const static char *sSDKsample = "CUDA Iterative Box Filter";
|
||||
|
||||
@@ -71,544 +71,559 @@ const char *sOriginal[] = {"teapot1024_14.ppm", "teapot1024_22.ppm", NULL};
|
||||
|
||||
const char *sReference[] = {"ref_14.ppm", "ref_22.ppm", NULL};
|
||||
|
||||
const char *image_filename = "teapot1024.ppm";
|
||||
int iterations = 1;
|
||||
int filter_radius = 14;
|
||||
int nthreads = 64;
|
||||
unsigned int width, height;
|
||||
unsigned int *h_img = NULL;
|
||||
const char *image_filename = "teapot1024.ppm";
|
||||
int iterations = 1;
|
||||
int filter_radius = 14;
|
||||
int nthreads = 64;
|
||||
unsigned int width, height;
|
||||
unsigned int *h_img = NULL;
|
||||
unsigned int *d_temp = NULL;
|
||||
|
||||
GLuint pbo; // OpenGL pixel buffer object
|
||||
struct cudaGraphicsResource *cuda_pbo_resource; // handles OpenGL-CUDA exchange
|
||||
GLuint texid; // Texture
|
||||
GLuint shader;
|
||||
GLuint pbo; // OpenGL pixel buffer object
|
||||
struct cudaGraphicsResource *cuda_pbo_resource; // handles OpenGL-CUDA exchange
|
||||
GLuint texid; // Texture
|
||||
GLuint shader;
|
||||
|
||||
StopWatchInterface *timer = NULL, *kernel_timer = NULL;
|
||||
|
||||
// Auto-Verification Code
|
||||
int fpsCount = 0; // FPS count for averaging
|
||||
int fpsLimit = 8; // FPS limit for sampling
|
||||
int g_Index = 0;
|
||||
int g_nFilterSign = 1;
|
||||
float avgFPS = 0.0f;
|
||||
unsigned int frameCount = 0;
|
||||
unsigned int g_TotalErrors = 0;
|
||||
bool g_bInteractive = false;
|
||||
int fpsCount = 0; // FPS count for averaging
|
||||
int fpsLimit = 8; // FPS limit for sampling
|
||||
int g_Index = 0;
|
||||
int g_nFilterSign = 1;
|
||||
float avgFPS = 0.0f;
|
||||
unsigned int frameCount = 0;
|
||||
unsigned int g_TotalErrors = 0;
|
||||
bool g_bInteractive = false;
|
||||
|
||||
int *pArgc = NULL;
|
||||
int *pArgc = NULL;
|
||||
char **pArgv = NULL;
|
||||
|
||||
extern "C" int runSingleTest(char *ref_file, char *exec_path);
|
||||
extern "C" int runBenchmark();
|
||||
extern "C" int runSingleTest(char *ref_file, char *exec_path);
|
||||
extern "C" int runBenchmark();
|
||||
extern "C" void loadImageData(int argc, char **argv);
|
||||
extern "C" void computeGold(float *id, float *od, int w, int h, int n);
|
||||
|
||||
// These are CUDA functions to handle allocation and launching the kernels
|
||||
extern "C" void initTexture(int width, int height, void *pImage, bool useRGBA);
|
||||
extern "C" void freeTextures();
|
||||
extern "C" double boxFilter(float *d_temp, float *d_dest,
|
||||
int width, int height, int radius, int iterations,
|
||||
int nthreads, StopWatchInterface *timer);
|
||||
extern "C" void initTexture(int width, int height, void *pImage, bool useRGBA);
|
||||
extern "C" void freeTextures();
|
||||
extern "C" double boxFilter(float *d_temp,
|
||||
float *d_dest,
|
||||
int width,
|
||||
int height,
|
||||
int radius,
|
||||
int iterations,
|
||||
int nthreads,
|
||||
StopWatchInterface *timer);
|
||||
|
||||
extern "C" double boxFilterRGBA(unsigned int *d_temp,
|
||||
unsigned int *d_dest, int width, int height,
|
||||
int radius, int iterations, int nthreads,
|
||||
extern "C" double boxFilterRGBA(unsigned int *d_temp,
|
||||
unsigned int *d_dest,
|
||||
int width,
|
||||
int height,
|
||||
int radius,
|
||||
int iterations,
|
||||
int nthreads,
|
||||
StopWatchInterface *timer);
|
||||
|
||||
// This varies the filter radius, so we can see automatic animation
|
||||
void varySigma() {
|
||||
filter_radius += g_nFilterSign;
|
||||
void varySigma()
|
||||
{
|
||||
filter_radius += g_nFilterSign;
|
||||
|
||||
if (filter_radius > 64) {
|
||||
filter_radius = 64; // clamp to 64 and then negate sign
|
||||
g_nFilterSign = -1;
|
||||
} else if (filter_radius < 0) {
|
||||
filter_radius = 0;
|
||||
g_nFilterSign = 1;
|
||||
}
|
||||
if (filter_radius > 64) {
|
||||
filter_radius = 64; // clamp to 64 and then negate sign
|
||||
g_nFilterSign = -1;
|
||||
}
|
||||
else if (filter_radius < 0) {
|
||||
filter_radius = 0;
|
||||
g_nFilterSign = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the Frames per second and print in the title bar
|
||||
void computeFPS() {
|
||||
frameCount++;
|
||||
fpsCount++;
|
||||
void computeFPS()
|
||||
{
|
||||
frameCount++;
|
||||
fpsCount++;
|
||||
|
||||
if (fpsCount == fpsLimit) {
|
||||
avgFPS = 1.0f / (sdkGetAverageTimerValue(&timer) / 1000.0f);
|
||||
fpsCount = 0;
|
||||
fpsLimit = (int)MAX(avgFPS, 1.0f);
|
||||
sdkResetTimer(&timer);
|
||||
}
|
||||
if (fpsCount == fpsLimit) {
|
||||
avgFPS = 1.0f / (sdkGetAverageTimerValue(&timer) / 1000.0f);
|
||||
fpsCount = 0;
|
||||
fpsLimit = (int)MAX(avgFPS, 1.0f);
|
||||
sdkResetTimer(&timer);
|
||||
}
|
||||
|
||||
char fps[256];
|
||||
sprintf(fps,
|
||||
"CUDA Rolling Box Filter <Animation=%s> (radius=%d, passes=%d): "
|
||||
"%3.1f fps",
|
||||
(!g_bInteractive ? "ON" : "OFF"), filter_radius, iterations, avgFPS);
|
||||
glutSetWindowTitle(fps);
|
||||
char fps[256];
|
||||
sprintf(fps,
|
||||
"CUDA Rolling Box Filter <Animation=%s> (radius=%d, passes=%d): "
|
||||
"%3.1f fps",
|
||||
(!g_bInteractive ? "ON" : "OFF"),
|
||||
filter_radius,
|
||||
iterations,
|
||||
avgFPS);
|
||||
glutSetWindowTitle(fps);
|
||||
|
||||
if (!g_bInteractive) {
|
||||
varySigma();
|
||||
}
|
||||
if (!g_bInteractive) {
|
||||
varySigma();
|
||||
}
|
||||
}
|
||||
|
||||
// display results using OpenGL
|
||||
void display() {
|
||||
sdkStartTimer(&timer);
|
||||
void display()
|
||||
{
|
||||
sdkStartTimer(&timer);
|
||||
|
||||
// execute filter, writing results to pbo
|
||||
unsigned int *d_result;
|
||||
// execute filter, writing results to pbo
|
||||
unsigned int *d_result;
|
||||
|
||||
checkCudaErrors(cudaGraphicsMapResources(1, &cuda_pbo_resource, 0));
|
||||
size_t num_bytes;
|
||||
checkCudaErrors(cudaGraphicsResourceGetMappedPointer(
|
||||
(void **)&d_result, &num_bytes, cuda_pbo_resource));
|
||||
boxFilterRGBA(d_temp, d_result, width, height, filter_radius,
|
||||
iterations, nthreads, kernel_timer);
|
||||
checkCudaErrors(cudaGraphicsMapResources(1, &cuda_pbo_resource, 0));
|
||||
size_t num_bytes;
|
||||
checkCudaErrors(cudaGraphicsResourceGetMappedPointer((void **)&d_result, &num_bytes, cuda_pbo_resource));
|
||||
boxFilterRGBA(d_temp, d_result, width, height, filter_radius, iterations, nthreads, kernel_timer);
|
||||
|
||||
checkCudaErrors(cudaGraphicsUnmapResources(1, &cuda_pbo_resource, 0));
|
||||
checkCudaErrors(cudaGraphicsUnmapResources(1, &cuda_pbo_resource, 0));
|
||||
|
||||
// OpenGL display code path
|
||||
{
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
// load texture from pbo
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, pbo);
|
||||
glBindTexture(GL_TEXTURE_2D, texid);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA,
|
||||
GL_UNSIGNED_BYTE, 0);
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
|
||||
|
||||
// fragment program is required to display floating point texture
|
||||
glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, shader);
|
||||
glEnable(GL_FRAGMENT_PROGRAM_ARB);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
// OpenGL display code path
|
||||
{
|
||||
glTexCoord2f(0.0f, 0.0f);
|
||||
glVertex2f(0.0f, 0.0f);
|
||||
glTexCoord2f(1.0f, 0.0f);
|
||||
glVertex2f(1.0f, 0.0f);
|
||||
glTexCoord2f(1.0f, 1.0f);
|
||||
glVertex2f(1.0f, 1.0f);
|
||||
glTexCoord2f(0.0f, 1.0f);
|
||||
glVertex2f(0.0f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
// load texture from pbo
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, pbo);
|
||||
glBindTexture(GL_TEXTURE_2D, texid);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, 0);
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
|
||||
|
||||
// fragment program is required to display floating point texture
|
||||
glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, shader);
|
||||
glEnable(GL_FRAGMENT_PROGRAM_ARB);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
{
|
||||
glTexCoord2f(0.0f, 0.0f);
|
||||
glVertex2f(0.0f, 0.0f);
|
||||
glTexCoord2f(1.0f, 0.0f);
|
||||
glVertex2f(1.0f, 0.0f);
|
||||
glTexCoord2f(1.0f, 1.0f);
|
||||
glVertex2f(1.0f, 1.0f);
|
||||
glTexCoord2f(0.0f, 1.0f);
|
||||
glVertex2f(0.0f, 1.0f);
|
||||
}
|
||||
glEnd();
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glDisable(GL_FRAGMENT_PROGRAM_ARB);
|
||||
}
|
||||
glEnd();
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glDisable(GL_FRAGMENT_PROGRAM_ARB);
|
||||
}
|
||||
|
||||
glutSwapBuffers();
|
||||
glutReportErrors();
|
||||
glutSwapBuffers();
|
||||
glutReportErrors();
|
||||
|
||||
sdkStopTimer(&timer);
|
||||
sdkStopTimer(&timer);
|
||||
|
||||
computeFPS();
|
||||
computeFPS();
|
||||
}
|
||||
|
||||
// Keyboard callback function for OpenGL (GLUT)
|
||||
void keyboard(unsigned char key, int /*x*/, int /*y*/) {
|
||||
switch (key) {
|
||||
void keyboard(unsigned char key, int /*x*/, int /*y*/)
|
||||
{
|
||||
switch (key) {
|
||||
case 27:
|
||||
#if defined(__APPLE__) || defined(MACOSX)
|
||||
exit(EXIT_SUCCESS);
|
||||
exit(EXIT_SUCCESS);
|
||||
#else
|
||||
glutDestroyWindow(glutGetWindow());
|
||||
return;
|
||||
glutDestroyWindow(glutGetWindow());
|
||||
return;
|
||||
#endif
|
||||
break;
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
case 'A':
|
||||
g_bInteractive = !g_bInteractive;
|
||||
printf("> Animation is %s\n", !g_bInteractive ? "ON" : "OFF");
|
||||
break;
|
||||
g_bInteractive = !g_bInteractive;
|
||||
printf("> Animation is %s\n", !g_bInteractive ? "ON" : "OFF");
|
||||
break;
|
||||
|
||||
case '=':
|
||||
case '+':
|
||||
if (filter_radius < (int)width - 1 && filter_radius < (int)height - 1) {
|
||||
filter_radius++;
|
||||
}
|
||||
if (filter_radius < (int)width - 1 && filter_radius < (int)height - 1) {
|
||||
filter_radius++;
|
||||
}
|
||||
|
||||
break;
|
||||
break;
|
||||
|
||||
case '-':
|
||||
if (filter_radius > 1) {
|
||||
filter_radius--;
|
||||
}
|
||||
if (filter_radius > 1) {
|
||||
filter_radius--;
|
||||
}
|
||||
|
||||
break;
|
||||
break;
|
||||
|
||||
case ']':
|
||||
iterations++;
|
||||
break;
|
||||
iterations++;
|
||||
break;
|
||||
|
||||
case '[':
|
||||
if (iterations > 1) {
|
||||
iterations--;
|
||||
}
|
||||
if (iterations > 1) {
|
||||
iterations--;
|
||||
}
|
||||
|
||||
break;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
printf("radius = %d, iterations = %d\n", filter_radius, iterations);
|
||||
printf("radius = %d, iterations = %d\n", filter_radius, iterations);
|
||||
}
|
||||
|
||||
// Timer Event so we can refresh the display
|
||||
void timerEvent(int value) {
|
||||
if (glutGetWindow()) {
|
||||
glutPostRedisplay();
|
||||
glutTimerFunc(REFRESH_DELAY, timerEvent, 0);
|
||||
}
|
||||
void timerEvent(int value)
|
||||
{
|
||||
if (glutGetWindow()) {
|
||||
glutPostRedisplay();
|
||||
glutTimerFunc(REFRESH_DELAY, timerEvent, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Resizing the window
|
||||
void reshape(int x, int y) {
|
||||
glViewport(0, 0, x, y);
|
||||
void reshape(int x, int y)
|
||||
{
|
||||
glViewport(0, 0, x, y);
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glOrtho(0.0, 1.0, 0.0, 1.0, 0.0, 1.0);
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glOrtho(0.0, 1.0, 0.0, 1.0, 0.0, 1.0);
|
||||
}
|
||||
|
||||
void initCuda(bool useRGBA) {
|
||||
checkCudaErrors(cudaMalloc((void **)&d_temp, (width * height * sizeof(unsigned int))));
|
||||
void initCuda(bool useRGBA)
|
||||
{
|
||||
checkCudaErrors(cudaMalloc((void **)&d_temp, (width * height * sizeof(unsigned int))));
|
||||
|
||||
// Refer to boxFilter_kernel.cu for implementation
|
||||
initTexture(width, height, h_img, useRGBA);
|
||||
// Refer to boxFilter_kernel.cu for implementation
|
||||
initTexture(width, height, h_img, useRGBA);
|
||||
|
||||
sdkCreateTimer(&timer);
|
||||
sdkCreateTimer(&kernel_timer);
|
||||
sdkCreateTimer(&timer);
|
||||
sdkCreateTimer(&kernel_timer);
|
||||
}
|
||||
|
||||
void cleanup() {
|
||||
sdkDeleteTimer(&timer);
|
||||
sdkDeleteTimer(&kernel_timer);
|
||||
void cleanup()
|
||||
{
|
||||
sdkDeleteTimer(&timer);
|
||||
sdkDeleteTimer(&kernel_timer);
|
||||
|
||||
if (h_img) {
|
||||
free(h_img);
|
||||
h_img = NULL;
|
||||
}
|
||||
if (h_img) {
|
||||
free(h_img);
|
||||
h_img = NULL;
|
||||
}
|
||||
|
||||
if (d_temp) {
|
||||
cudaFree(d_temp);
|
||||
d_temp = NULL;
|
||||
}
|
||||
if (d_temp) {
|
||||
cudaFree(d_temp);
|
||||
d_temp = NULL;
|
||||
}
|
||||
|
||||
// Refer to boxFilter_kernel.cu for implementation
|
||||
freeTextures();
|
||||
// Refer to boxFilter_kernel.cu for implementation
|
||||
freeTextures();
|
||||
|
||||
cudaGraphicsUnregisterResource(cuda_pbo_resource);
|
||||
cudaGraphicsUnregisterResource(cuda_pbo_resource);
|
||||
|
||||
glDeleteBuffers(1, &pbo);
|
||||
glDeleteTextures(1, &texid);
|
||||
glDeleteProgramsARB(1, &shader);
|
||||
glDeleteBuffers(1, &pbo);
|
||||
glDeleteTextures(1, &texid);
|
||||
glDeleteProgramsARB(1, &shader);
|
||||
}
|
||||
|
||||
// shader for displaying floating-point texture
|
||||
static const char *shader_code =
|
||||
"!!ARBfp1.0\n"
|
||||
"TEX result.color, fragment.texcoord, texture[0], 2D; \n"
|
||||
"END";
|
||||
static const char *shader_code = "!!ARBfp1.0\n"
|
||||
"TEX result.color, fragment.texcoord, texture[0], 2D; \n"
|
||||
"END";
|
||||
|
||||
GLuint compileASMShader(GLenum program_type, const char *code) {
|
||||
GLuint program_id;
|
||||
glGenProgramsARB(1, &program_id);
|
||||
glBindProgramARB(program_type, program_id);
|
||||
glProgramStringARB(program_type, GL_PROGRAM_FORMAT_ASCII_ARB,
|
||||
(GLsizei)strlen(code), (GLubyte *)code);
|
||||
GLuint compileASMShader(GLenum program_type, const char *code)
|
||||
{
|
||||
GLuint program_id;
|
||||
glGenProgramsARB(1, &program_id);
|
||||
glBindProgramARB(program_type, program_id);
|
||||
glProgramStringARB(program_type, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(code), (GLubyte *)code);
|
||||
|
||||
GLint error_pos;
|
||||
glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &error_pos);
|
||||
GLint error_pos;
|
||||
glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &error_pos);
|
||||
|
||||
if (error_pos != -1) {
|
||||
const GLubyte *error_string;
|
||||
error_string = glGetString(GL_PROGRAM_ERROR_STRING_ARB);
|
||||
printf("Program error at position: %d\n%s\n", (int)error_pos, error_string);
|
||||
return 0;
|
||||
}
|
||||
if (error_pos != -1) {
|
||||
const GLubyte *error_string;
|
||||
error_string = glGetString(GL_PROGRAM_ERROR_STRING_ARB);
|
||||
printf("Program error at position: %d\n%s\n", (int)error_pos, error_string);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return program_id;
|
||||
return program_id;
|
||||
}
|
||||
|
||||
// This is where we create the OpenGL PBOs, FBOs, and texture resources
|
||||
void initGLResources() {
|
||||
// create pixel buffer object
|
||||
glGenBuffers(1, &pbo);
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, pbo);
|
||||
glBufferData(GL_PIXEL_UNPACK_BUFFER_ARB, width * height * sizeof(GLubyte) * 4,
|
||||
h_img, GL_STREAM_DRAW_ARB);
|
||||
void initGLResources()
|
||||
{
|
||||
// create pixel buffer object
|
||||
glGenBuffers(1, &pbo);
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, pbo);
|
||||
glBufferData(GL_PIXEL_UNPACK_BUFFER_ARB, width * height * sizeof(GLubyte) * 4, h_img, GL_STREAM_DRAW_ARB);
|
||||
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
|
||||
|
||||
checkCudaErrors(cudaGraphicsGLRegisterBuffer(
|
||||
&cuda_pbo_resource, pbo, cudaGraphicsMapFlagsWriteDiscard));
|
||||
checkCudaErrors(cudaGraphicsGLRegisterBuffer(&cuda_pbo_resource, pbo, cudaGraphicsMapFlagsWriteDiscard));
|
||||
|
||||
// create texture for display
|
||||
glGenTextures(1, &texid);
|
||||
glBindTexture(GL_TEXTURE_2D, texid);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA,
|
||||
GL_UNSIGNED_BYTE, NULL);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
// create texture for display
|
||||
glGenTextures(1, &texid);
|
||||
glBindTexture(GL_TEXTURE_2D, texid);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
// load shader program
|
||||
shader = compileASMShader(GL_FRAGMENT_PROGRAM_ARB, shader_code);
|
||||
// load shader program
|
||||
shader = compileASMShader(GL_FRAGMENT_PROGRAM_ARB, shader_code);
|
||||
}
|
||||
|
||||
void initGL(int *argc, char **argv) {
|
||||
// initialize GLUT
|
||||
glutInit(argc, argv);
|
||||
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
|
||||
glutInitWindowSize(768, 768);
|
||||
glutCreateWindow("CUDA Rolling Box Filter");
|
||||
glutDisplayFunc(display);
|
||||
void initGL(int *argc, char **argv)
|
||||
{
|
||||
// initialize GLUT
|
||||
glutInit(argc, argv);
|
||||
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
|
||||
glutInitWindowSize(768, 768);
|
||||
glutCreateWindow("CUDA Rolling Box Filter");
|
||||
glutDisplayFunc(display);
|
||||
|
||||
glutKeyboardFunc(keyboard);
|
||||
glutReshapeFunc(reshape);
|
||||
glutTimerFunc(REFRESH_DELAY, timerEvent, 0);
|
||||
glutKeyboardFunc(keyboard);
|
||||
glutReshapeFunc(reshape);
|
||||
glutTimerFunc(REFRESH_DELAY, timerEvent, 0);
|
||||
|
||||
if (!isGLVersionSupported(2, 0) ||
|
||||
!areGLExtensionsSupported(
|
||||
"GL_ARB_vertex_buffer_object GL_ARB_pixel_buffer_object")) {
|
||||
printf("Error: failed to get minimal extensions for demo\n");
|
||||
printf("This sample requires:\n");
|
||||
printf(" OpenGL version 2.0\n");
|
||||
printf(" GL_ARB_vertex_buffer_object\n");
|
||||
printf(" GL_ARB_pixel_buffer_object\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (!isGLVersionSupported(2, 0)
|
||||
|| !areGLExtensionsSupported("GL_ARB_vertex_buffer_object GL_ARB_pixel_buffer_object")) {
|
||||
printf("Error: failed to get minimal extensions for demo\n");
|
||||
printf("This sample requires:\n");
|
||||
printf(" OpenGL version 2.0\n");
|
||||
printf(" GL_ARB_vertex_buffer_object\n");
|
||||
printf(" GL_ARB_pixel_buffer_object\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//! Run a simple benchmark test for CUDA
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int runBenchmark() {
|
||||
printf("[runBenchmark]: [%s]\n", sSDKsample);
|
||||
int runBenchmark()
|
||||
{
|
||||
printf("[runBenchmark]: [%s]\n", sSDKsample);
|
||||
|
||||
initCuda(true);
|
||||
initCuda(true);
|
||||
|
||||
unsigned int *d_result;
|
||||
checkCudaErrors(
|
||||
cudaMalloc((void **)&d_result, width * height * sizeof(unsigned int)));
|
||||
unsigned int *d_result;
|
||||
checkCudaErrors(cudaMalloc((void **)&d_result, width * height * sizeof(unsigned int)));
|
||||
|
||||
// warm-up
|
||||
boxFilterRGBA(d_temp, d_temp, width, height, filter_radius, iterations,
|
||||
nthreads, kernel_timer);
|
||||
checkCudaErrors(cudaDeviceSynchronize());
|
||||
// warm-up
|
||||
boxFilterRGBA(d_temp, d_temp, width, height, filter_radius, iterations, nthreads, kernel_timer);
|
||||
checkCudaErrors(cudaDeviceSynchronize());
|
||||
|
||||
sdkStartTimer(&kernel_timer);
|
||||
// Start round-trip timer and process iCycles loops on the GPU
|
||||
iterations = 1; // standard 1-pass filtering
|
||||
const int iCycles = 150;
|
||||
double dProcessingTime = 0.0;
|
||||
printf("\nRunning BoxFilterGPU for %d cycles...\n\n", iCycles);
|
||||
sdkStartTimer(&kernel_timer);
|
||||
// Start round-trip timer and process iCycles loops on the GPU
|
||||
iterations = 1; // standard 1-pass filtering
|
||||
const int iCycles = 150;
|
||||
double dProcessingTime = 0.0;
|
||||
printf("\nRunning BoxFilterGPU for %d cycles...\n\n", iCycles);
|
||||
|
||||
for (int i = 0; i < iCycles; i++) {
|
||||
dProcessingTime +=
|
||||
boxFilterRGBA(d_temp, d_temp, width, height, filter_radius,
|
||||
iterations, nthreads, kernel_timer);
|
||||
}
|
||||
for (int i = 0; i < iCycles; i++) {
|
||||
dProcessingTime +=
|
||||
boxFilterRGBA(d_temp, d_temp, width, height, filter_radius, iterations, nthreads, kernel_timer);
|
||||
}
|
||||
|
||||
// check if kernel execution generated an error and sync host
|
||||
getLastCudaError("Error: boxFilterRGBA Kernel execution FAILED");
|
||||
checkCudaErrors(cudaDeviceSynchronize());
|
||||
sdkStopTimer(&kernel_timer);
|
||||
// check if kernel execution generated an error and sync host
|
||||
getLastCudaError("Error: boxFilterRGBA Kernel execution FAILED");
|
||||
checkCudaErrors(cudaDeviceSynchronize());
|
||||
sdkStopTimer(&kernel_timer);
|
||||
|
||||
// Get average computation time
|
||||
dProcessingTime /= (double)iCycles;
|
||||
// Get average computation time
|
||||
dProcessingTime /= (double)iCycles;
|
||||
|
||||
// log testname, throughput, timing and config info to sample and master logs
|
||||
printf(
|
||||
"boxFilter-texture, Throughput = %.4f M RGBA Pixels/s, Time = %.5f s, "
|
||||
"Size = %u RGBA Pixels, NumDevsUsed = %u, Workgroup = %u\n",
|
||||
(1.0e-6 * width * height) / dProcessingTime, dProcessingTime,
|
||||
(width * height), 1, nthreads);
|
||||
printf("\n");
|
||||
// log testname, throughput, timing and config info to sample and master logs
|
||||
printf("boxFilter-texture, Throughput = %.4f M RGBA Pixels/s, Time = %.5f s, "
|
||||
"Size = %u RGBA Pixels, NumDevsUsed = %u, Workgroup = %u\n",
|
||||
(1.0e-6 * width * height) / dProcessingTime,
|
||||
dProcessingTime,
|
||||
(width * height),
|
||||
1,
|
||||
nthreads);
|
||||
printf("\n");
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// This test specifies a single test (where you specify radius and/or
|
||||
// iterations)
|
||||
int runSingleTest(char *ref_file, char *exec_path) {
|
||||
int nTotalErrors = 0;
|
||||
char dump_file[256];
|
||||
int runSingleTest(char *ref_file, char *exec_path)
|
||||
{
|
||||
int nTotalErrors = 0;
|
||||
char dump_file[256];
|
||||
|
||||
printf("[runSingleTest]: [%s]\n", sSDKsample);
|
||||
printf("[runSingleTest]: [%s]\n", sSDKsample);
|
||||
|
||||
initCuda(true);
|
||||
initCuda(true);
|
||||
|
||||
unsigned int *d_result;
|
||||
unsigned int *h_result =
|
||||
(unsigned int *)malloc(width * height * sizeof(unsigned int));
|
||||
checkCudaErrors(
|
||||
cudaMalloc((void **)&d_result, width * height * sizeof(unsigned int)));
|
||||
unsigned int *d_result;
|
||||
unsigned int *h_result = (unsigned int *)malloc(width * height * sizeof(unsigned int));
|
||||
checkCudaErrors(cudaMalloc((void **)&d_result, width * height * sizeof(unsigned int)));
|
||||
|
||||
// run the sample radius
|
||||
{
|
||||
printf("%s (radius=%d) (passes=%d) ", sSDKsample, filter_radius,
|
||||
iterations);
|
||||
boxFilterRGBA(d_temp, d_result, width, height, filter_radius,
|
||||
iterations, nthreads, kernel_timer);
|
||||
// run the sample radius
|
||||
{
|
||||
printf("%s (radius=%d) (passes=%d) ", sSDKsample, filter_radius, iterations);
|
||||
boxFilterRGBA(d_temp, d_result, width, height, filter_radius, iterations, nthreads, kernel_timer);
|
||||
|
||||
// check if kernel execution generated an error
|
||||
getLastCudaError("Error: boxFilterRGBA Kernel execution FAILED");
|
||||
checkCudaErrors(cudaDeviceSynchronize());
|
||||
// check if kernel execution generated an error
|
||||
getLastCudaError("Error: boxFilterRGBA Kernel execution FAILED");
|
||||
checkCudaErrors(cudaDeviceSynchronize());
|
||||
|
||||
// readback the results to system memory
|
||||
cudaMemcpy((unsigned char *)h_result, (unsigned char *)d_result,
|
||||
width * height * sizeof(unsigned int), cudaMemcpyDeviceToHost);
|
||||
// readback the results to system memory
|
||||
cudaMemcpy((unsigned char *)h_result,
|
||||
(unsigned char *)d_result,
|
||||
width * height * sizeof(unsigned int),
|
||||
cudaMemcpyDeviceToHost);
|
||||
|
||||
sprintf(dump_file, "teapot1024_%02d.ppm", filter_radius);
|
||||
sprintf(dump_file, "teapot1024_%02d.ppm", filter_radius);
|
||||
|
||||
sdkSavePPM4ub((const char *)dump_file, (unsigned char *)h_result, width,
|
||||
height);
|
||||
sdkSavePPM4ub((const char *)dump_file, (unsigned char *)h_result, width, height);
|
||||
|
||||
if (!sdkComparePPM(dump_file, sdkFindFilePath(ref_file, exec_path),
|
||||
MAX_EPSILON_ERROR, 0.15f, false)) {
|
||||
printf("Image is Different ");
|
||||
nTotalErrors++;
|
||||
} else {
|
||||
printf("Image is Matching ");
|
||||
if (!sdkComparePPM(dump_file, sdkFindFilePath(ref_file, exec_path), MAX_EPSILON_ERROR, 0.15f, false)) {
|
||||
printf("Image is Different ");
|
||||
nTotalErrors++;
|
||||
}
|
||||
else {
|
||||
printf("Image is Matching ");
|
||||
}
|
||||
|
||||
printf(" <%s>\n", ref_file);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
free(h_result);
|
||||
checkCudaErrors(cudaFree(d_result));
|
||||
|
||||
return nTotalErrors;
|
||||
}
|
||||
|
||||
void loadImageData(int argc, char **argv)
|
||||
{
|
||||
// load image (needed so we can get the width and height before we create the
|
||||
// window
|
||||
char *image_path = NULL;
|
||||
|
||||
if (argc >= 1) {
|
||||
image_path = sdkFindFilePath(image_filename, argv[0]);
|
||||
}
|
||||
|
||||
printf(" <%s>\n", ref_file);
|
||||
}
|
||||
printf("\n");
|
||||
if (image_path == 0) {
|
||||
printf("Error finding image file '%s'\n", image_filename);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
free(h_result);
|
||||
checkCudaErrors(cudaFree(d_result));
|
||||
sdkLoadPPM4(image_path, (unsigned char **)&h_img, &width, &height);
|
||||
|
||||
return nTotalErrors;
|
||||
if (!h_img) {
|
||||
printf("Error opening file '%s'\n", image_path);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
printf("Loaded '%s', %d x %d pixels\n", image_path, width, height);
|
||||
}
|
||||
|
||||
void loadImageData(int argc, char **argv) {
|
||||
// load image (needed so we can get the width and height before we create the
|
||||
// window
|
||||
char *image_path = NULL;
|
||||
|
||||
if (argc >= 1) {
|
||||
image_path = sdkFindFilePath(image_filename, argv[0]);
|
||||
}
|
||||
|
||||
if (image_path == 0) {
|
||||
printf("Error finding image file '%s'\n", image_filename);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
sdkLoadPPM4(image_path, (unsigned char **)&h_img, &width, &height);
|
||||
|
||||
if (!h_img) {
|
||||
printf("Error opening file '%s'\n", image_path);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
printf("Loaded '%s', %d x %d pixels\n", image_path, width, height);
|
||||
}
|
||||
|
||||
void printHelp() {
|
||||
printf("boxFilter usage\n");
|
||||
printf(" -threads=n (specify the # of of threads to use)\n");
|
||||
printf(" -radius=n (specify the filter radius n to use)\n");
|
||||
printf(" -passes=n (specify the number of passes n to use)\n");
|
||||
printf(" -file=name (specify reference file for comparison)\n");
|
||||
void printHelp()
|
||||
{
|
||||
printf("boxFilter usage\n");
|
||||
printf(" -threads=n (specify the # of of threads to use)\n");
|
||||
printf(" -radius=n (specify the filter radius n to use)\n");
|
||||
printf(" -passes=n (specify the number of passes n to use)\n");
|
||||
printf(" -file=name (specify reference file for comparison)\n");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Program main
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int main(int argc, char **argv) {
|
||||
int devID = 0;
|
||||
char *ref_file = NULL;
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int devID = 0;
|
||||
char *ref_file = NULL;
|
||||
|
||||
#if defined(__linux__)
|
||||
setenv("DISPLAY", ":0", 0);
|
||||
setenv("DISPLAY", ":0", 0);
|
||||
#endif
|
||||
|
||||
pArgc = &argc;
|
||||
pArgv = argv;
|
||||
pArgc = &argc;
|
||||
pArgv = argv;
|
||||
|
||||
// start logs
|
||||
printf("%s Starting...\n\n", argv[0]);
|
||||
// start logs
|
||||
printf("%s Starting...\n\n", argv[0]);
|
||||
|
||||
if (checkCmdLineFlag(argc, (const char **)argv, "help")) {
|
||||
printHelp();
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
// use command-line specified CUDA device, otherwise use device with highest
|
||||
// Gflops/s
|
||||
if (argc > 1) {
|
||||
if (checkCmdLineFlag(argc, (const char **)argv, "threads")) {
|
||||
nthreads = getCmdLineArgumentInt(argc, (const char **)argv, "threads");
|
||||
if (checkCmdLineFlag(argc, (const char **)argv, "help")) {
|
||||
printHelp();
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
if (checkCmdLineFlag(argc, (const char **)argv, "radius")) {
|
||||
filter_radius =
|
||||
getCmdLineArgumentInt(argc, (const char **)argv, "radius");
|
||||
// use command-line specified CUDA device, otherwise use device with highest
|
||||
// Gflops/s
|
||||
if (argc > 1) {
|
||||
if (checkCmdLineFlag(argc, (const char **)argv, "threads")) {
|
||||
nthreads = getCmdLineArgumentInt(argc, (const char **)argv, "threads");
|
||||
}
|
||||
|
||||
if (checkCmdLineFlag(argc, (const char **)argv, "radius")) {
|
||||
filter_radius = getCmdLineArgumentInt(argc, (const char **)argv, "radius");
|
||||
}
|
||||
|
||||
if (checkCmdLineFlag(argc, (const char **)argv, "passes")) {
|
||||
iterations = getCmdLineArgumentInt(argc, (const char **)argv, "passes");
|
||||
}
|
||||
|
||||
if (checkCmdLineFlag(argc, (const char **)argv, "file")) {
|
||||
getCmdLineArgumentString(argc, (const char **)argv, "file", (char **)&ref_file);
|
||||
}
|
||||
}
|
||||
|
||||
if (checkCmdLineFlag(argc, (const char **)argv, "passes")) {
|
||||
iterations = getCmdLineArgumentInt(argc, (const char **)argv, "passes");
|
||||
// load image to process
|
||||
loadImageData(argc, argv);
|
||||
devID = findCudaDevice(argc, (const char **)argv);
|
||||
|
||||
if (checkCmdLineFlag(argc, (const char **)argv, "benchmark")) {
|
||||
// This is a separate mode of the sample, where we are benchmark the kernels
|
||||
// for performance
|
||||
// Running CUDA kernels (boxfilter) in Benchmarking mode
|
||||
g_TotalErrors += runBenchmark();
|
||||
exit(g_TotalErrors == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (checkCmdLineFlag(argc, (const char **)argv, "file")) {
|
||||
getCmdLineArgumentString(argc, (const char **)argv, "file",
|
||||
(char **)&ref_file);
|
||||
else if (checkCmdLineFlag(argc, (const char **)argv, "radius")
|
||||
|| checkCmdLineFlag(argc, (const char **)argv, "passes")) {
|
||||
// This overrides the default mode. Users can specify the radius used by
|
||||
// the filter kernel
|
||||
g_TotalErrors += runSingleTest(ref_file, argv[0]);
|
||||
exit(g_TotalErrors == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Default mode running with OpenGL visualization and in automatic mode
|
||||
// the output automatically changes animation
|
||||
printf("\n");
|
||||
|
||||
// load image to process
|
||||
loadImageData(argc, argv);
|
||||
devID = findCudaDevice(argc, (const char **)argv);
|
||||
initGL(&argc, argv);
|
||||
|
||||
if (checkCmdLineFlag(argc, (const char **)argv, "benchmark")) {
|
||||
// This is a separate mode of the sample, where we are benchmark the kernels
|
||||
// for performance
|
||||
// Running CUDA kernels (boxfilter) in Benchmarking mode
|
||||
g_TotalErrors += runBenchmark();
|
||||
exit(g_TotalErrors == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
} else if (checkCmdLineFlag(argc, (const char **)argv, "radius") ||
|
||||
checkCmdLineFlag(argc, (const char **)argv, "passes")) {
|
||||
// This overrides the default mode. Users can specify the radius used by
|
||||
// the filter kernel
|
||||
g_TotalErrors += runSingleTest(ref_file, argv[0]);
|
||||
exit(g_TotalErrors == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
} else {
|
||||
// Default mode running with OpenGL visualization and in automatic mode
|
||||
// the output automatically changes animation
|
||||
printf("\n");
|
||||
|
||||
initGL(&argc, argv);
|
||||
|
||||
initCuda(true);
|
||||
initGLResources();
|
||||
initCuda(true);
|
||||
initGLResources();
|
||||
|
||||
// sets the callback function so it will call cleanup upon exit
|
||||
#if defined(__APPLE__) || defined(MACOSX)
|
||||
atexit(cleanup);
|
||||
atexit(cleanup);
|
||||
#else
|
||||
glutCloseFunc(cleanup);
|
||||
glutCloseFunc(cleanup);
|
||||
#endif
|
||||
|
||||
printf("Running Standard Demonstration with GLUT loop...\n\n");
|
||||
printf(
|
||||
"Press '+' and '-' to change filter width\n"
|
||||
"Press ']' and '[' to change number of iterations\n"
|
||||
"Press 'a' or 'A' to change animation ON/OFF\n\n");
|
||||
printf("Running Standard Demonstration with GLUT loop...\n\n");
|
||||
printf("Press '+' and '-' to change filter width\n"
|
||||
"Press ']' and '[' to change number of iterations\n"
|
||||
"Press 'a' or 'A' to change animation ON/OFF\n\n");
|
||||
|
||||
// Main OpenGL loop that will run visualization for every vsync
|
||||
glutMainLoop();
|
||||
}
|
||||
// Main OpenGL loop that will run visualization for every vsync
|
||||
glutMainLoop();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,82 +30,84 @@
|
||||
extern "C" void computeGold(float *id, float *od, int w, int h, int r);
|
||||
|
||||
// CPU implementation
|
||||
void hboxfilter_x(float *id, float *od, int w, int h, int r) {
|
||||
float scale = 1.0f / (2 * r + 1);
|
||||
void hboxfilter_x(float *id, float *od, int w, int h, int r)
|
||||
{
|
||||
float scale = 1.0f / (2 * r + 1);
|
||||
|
||||
for (int y = 0; y < h; y++) {
|
||||
float t;
|
||||
// do left edge
|
||||
t = id[y * w] * r;
|
||||
for (int y = 0; y < h; y++) {
|
||||
float t;
|
||||
// do left edge
|
||||
t = id[y * w] * r;
|
||||
|
||||
for (int x = 0; x < r + 1; x++) {
|
||||
t += id[y * w + x];
|
||||
for (int x = 0; x < r + 1; x++) {
|
||||
t += id[y * w + x];
|
||||
}
|
||||
|
||||
od[y * w] = t * scale;
|
||||
|
||||
for (int x = 1; x < r + 1; x++) {
|
||||
int c = y * w + x;
|
||||
t += id[c + r];
|
||||
t -= id[y * w];
|
||||
od[c] = t * scale;
|
||||
}
|
||||
|
||||
// main loop
|
||||
for (int x = r + 1; x < w - r; x++) {
|
||||
int c = y * w + x;
|
||||
t += id[c + r];
|
||||
t -= id[c - r - 1];
|
||||
od[c] = t * scale;
|
||||
}
|
||||
|
||||
// do right edge
|
||||
for (int x = w - r; x < w; x++) {
|
||||
int c = y * w + x;
|
||||
t += id[(y * w) + w - 1];
|
||||
t -= id[c - r - 1];
|
||||
od[c] = t * scale;
|
||||
}
|
||||
}
|
||||
|
||||
od[y * w] = t * scale;
|
||||
|
||||
for (int x = 1; x < r + 1; x++) {
|
||||
int c = y * w + x;
|
||||
t += id[c + r];
|
||||
t -= id[y * w];
|
||||
od[c] = t * scale;
|
||||
}
|
||||
|
||||
// main loop
|
||||
for (int x = r + 1; x < w - r; x++) {
|
||||
int c = y * w + x;
|
||||
t += id[c + r];
|
||||
t -= id[c - r - 1];
|
||||
od[c] = t * scale;
|
||||
}
|
||||
|
||||
// do right edge
|
||||
for (int x = w - r; x < w; x++) {
|
||||
int c = y * w + x;
|
||||
t += id[(y * w) + w - 1];
|
||||
t -= id[c - r - 1];
|
||||
od[c] = t * scale;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void hboxfilter_y(float *id, float *od, int w, int h, int r) {
|
||||
float scale = 1.0f / (2 * r + 1);
|
||||
void hboxfilter_y(float *id, float *od, int w, int h, int r)
|
||||
{
|
||||
float scale = 1.0f / (2 * r + 1);
|
||||
|
||||
for (int x = 0; x < w; x++) {
|
||||
float t;
|
||||
// do left edge
|
||||
t = id[x] * r;
|
||||
for (int x = 0; x < w; x++) {
|
||||
float t;
|
||||
// do left edge
|
||||
t = id[x] * r;
|
||||
|
||||
for (int y = 0; y < r + 1; y++) {
|
||||
t += id[y * w + x];
|
||||
for (int y = 0; y < r + 1; y++) {
|
||||
t += id[y * w + x];
|
||||
}
|
||||
|
||||
od[x] = t * scale;
|
||||
|
||||
for (int y = 1; y < r + 1; y++) {
|
||||
int c = y * w + x;
|
||||
t += id[c + r * w];
|
||||
t -= id[x];
|
||||
od[c] = t * scale;
|
||||
}
|
||||
|
||||
// main loop
|
||||
for (int y = r + 1; y < h - r; y++) {
|
||||
int c = y * w + x;
|
||||
t += id[c + r * w];
|
||||
t -= id[c - (r * w) - w];
|
||||
od[c] = t * scale;
|
||||
}
|
||||
|
||||
// do right edge
|
||||
for (int y = h - r; y < h; y++) {
|
||||
int c = y * w + x;
|
||||
t += id[(h - 1) * w + x];
|
||||
t -= id[c - (r * w) - w];
|
||||
od[c] = t * scale;
|
||||
}
|
||||
}
|
||||
|
||||
od[x] = t * scale;
|
||||
|
||||
for (int y = 1; y < r + 1; y++) {
|
||||
int c = y * w + x;
|
||||
t += id[c + r * w];
|
||||
t -= id[x];
|
||||
od[c] = t * scale;
|
||||
}
|
||||
|
||||
// main loop
|
||||
for (int y = r + 1; y < h - r; y++) {
|
||||
int c = y * w + x;
|
||||
t += id[c + r * w];
|
||||
t -= id[c - (r * w) - w];
|
||||
od[c] = t * scale;
|
||||
}
|
||||
|
||||
// do right edge
|
||||
for (int y = h - r; y < h; y++) {
|
||||
int c = y * w + x;
|
||||
t += id[(h - 1) * w + x];
|
||||
t -= id[c - (r * w) - w];
|
||||
od[c] = t * scale;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -117,7 +119,8 @@ void hboxfilter_y(float *id, float *od, int w, int h, int r) {
|
||||
//! @param r radius of filter
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void computeGold(float *image, float *temp, int w, int h, int r) {
|
||||
hboxfilter_x(image, temp, w, h, r);
|
||||
hboxfilter_y(temp, image, w, h, r);
|
||||
void computeGold(float *image, float *temp, int w, int h, int r)
|
||||
{
|
||||
hboxfilter_x(image, temp, w, h, r);
|
||||
hboxfilter_y(temp, image, w, h, r);
|
||||
}
|
||||
|
||||
@@ -28,14 +28,14 @@
|
||||
#ifndef _BOXFILTER_KERNEL_CH_
|
||||
#define _BOXFILTER_KERNEL_CH_
|
||||
|
||||
#include <helper_math.h>
|
||||
#include <helper_functions.h>
|
||||
#include <helper_math.h>
|
||||
|
||||
cudaTextureObject_t tex;
|
||||
cudaTextureObject_t texTempArray;
|
||||
cudaTextureObject_t rgbaTex;
|
||||
cudaTextureObject_t rgbaTexTempArray;
|
||||
cudaArray *d_array, *d_tempArray;
|
||||
cudaArray *d_array, *d_tempArray;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// These are CUDA Helper functions
|
||||
@@ -44,12 +44,12 @@ cudaArray *d_array, *d_tempArray;
|
||||
// call returns an error
|
||||
#define checkCudaErrors(err) __checkCudaErrors(err, __FILE__, __LINE__)
|
||||
|
||||
inline void __checkCudaErrors(cudaError err, const char *file, const int line) {
|
||||
if (cudaSuccess != err) {
|
||||
fprintf(stderr, "%s(%i) : CUDA Runtime API error %d: %s.\n", file, line,
|
||||
(int)err, cudaGetErrorString(err));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
inline void __checkCudaErrors(cudaError err, const char *file, const int line)
|
||||
{
|
||||
if (cudaSuccess != err) {
|
||||
fprintf(stderr, "%s(%i) : CUDA Runtime API error %d: %s.\n", file, line, (int)err, cudaGetErrorString(err));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -90,309 +90,309 @@ inline void __checkCudaErrors(cudaError err, const char *file, const int line) {
|
||||
*/
|
||||
|
||||
// process row
|
||||
__device__ void d_boxfilter_x(float *id, float *od, int w, int h, int r) {
|
||||
float scale = 1.0f / (float)((r << 1) + 1);
|
||||
__device__ void d_boxfilter_x(float *id, float *od, int w, int h, int r)
|
||||
{
|
||||
float scale = 1.0f / (float)((r << 1) + 1);
|
||||
|
||||
float t;
|
||||
// do left edge
|
||||
t = id[0] * r;
|
||||
float t;
|
||||
// do left edge
|
||||
t = id[0] * r;
|
||||
|
||||
for (int x = 0; x < (r + 1); x++) {
|
||||
t += id[x];
|
||||
}
|
||||
for (int x = 0; x < (r + 1); x++) {
|
||||
t += id[x];
|
||||
}
|
||||
|
||||
od[0] = t * scale;
|
||||
od[0] = t * scale;
|
||||
|
||||
for (int x = 1; x < (r + 1); x++) {
|
||||
t += id[x + r];
|
||||
t -= id[0];
|
||||
od[x] = t * scale;
|
||||
}
|
||||
for (int x = 1; x < (r + 1); x++) {
|
||||
t += id[x + r];
|
||||
t -= id[0];
|
||||
od[x] = t * scale;
|
||||
}
|
||||
|
||||
// main loop
|
||||
for (int x = (r + 1); x < w - r; x++) {
|
||||
t += id[x + r];
|
||||
t -= id[x - r - 1];
|
||||
od[x] = t * scale;
|
||||
}
|
||||
// main loop
|
||||
for (int x = (r + 1); x < w - r; x++) {
|
||||
t += id[x + r];
|
||||
t -= id[x - r - 1];
|
||||
od[x] = t * scale;
|
||||
}
|
||||
|
||||
// do right edge
|
||||
for (int x = w - r; x < w; x++) {
|
||||
t += id[w - 1];
|
||||
t -= id[x - r - 1];
|
||||
od[x] = t * scale;
|
||||
}
|
||||
// do right edge
|
||||
for (int x = w - r; x < w; x++) {
|
||||
t += id[w - 1];
|
||||
t -= id[x - r - 1];
|
||||
od[x] = t * scale;
|
||||
}
|
||||
}
|
||||
|
||||
// process column
|
||||
__device__ void d_boxfilter_y(float *id, float *od, int w, int h, int r) {
|
||||
float scale = 1.0f / (float)((r << 1) + 1);
|
||||
__device__ void d_boxfilter_y(float *id, float *od, int w, int h, int r)
|
||||
{
|
||||
float scale = 1.0f / (float)((r << 1) + 1);
|
||||
|
||||
float t;
|
||||
// do left edge
|
||||
t = id[0] * r;
|
||||
float t;
|
||||
// do left edge
|
||||
t = id[0] * r;
|
||||
|
||||
for (int y = 0; y < (r + 1); y++) {
|
||||
t += id[y * w];
|
||||
}
|
||||
for (int y = 0; y < (r + 1); y++) {
|
||||
t += id[y * w];
|
||||
}
|
||||
|
||||
od[0] = t * scale;
|
||||
od[0] = t * scale;
|
||||
|
||||
for (int y = 1; y < (r + 1); y++) {
|
||||
t += id[(y + r) * w];
|
||||
t -= id[0];
|
||||
od[y * w] = t * scale;
|
||||
}
|
||||
for (int y = 1; y < (r + 1); y++) {
|
||||
t += id[(y + r) * w];
|
||||
t -= id[0];
|
||||
od[y * w] = t * scale;
|
||||
}
|
||||
|
||||
// main loop
|
||||
for (int y = (r + 1); y < (h - r); y++) {
|
||||
t += id[(y + r) * w];
|
||||
t -= id[((y - r) * w) - w];
|
||||
od[y * w] = t * scale;
|
||||
}
|
||||
// main loop
|
||||
for (int y = (r + 1); y < (h - r); y++) {
|
||||
t += id[(y + r) * w];
|
||||
t -= id[((y - r) * w) - w];
|
||||
od[y * w] = t * scale;
|
||||
}
|
||||
|
||||
// do right edge
|
||||
for (int y = h - r; y < h; y++) {
|
||||
t += id[(h - 1) * w];
|
||||
t -= id[((y - r) * w) - w];
|
||||
od[y * w] = t * scale;
|
||||
}
|
||||
// do right edge
|
||||
for (int y = h - r; y < h; y++) {
|
||||
t += id[(h - 1) * w];
|
||||
t -= id[((y - r) * w) - w];
|
||||
od[y * w] = t * scale;
|
||||
}
|
||||
}
|
||||
|
||||
__global__ void d_boxfilter_x_global(float *id, float *od, int w, int h,
|
||||
int r) {
|
||||
unsigned int y = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
d_boxfilter_x(&id[y * w], &od[y * w], w, h, r);
|
||||
__global__ void d_boxfilter_x_global(float *id, float *od, int w, int h, int r)
|
||||
{
|
||||
unsigned int y = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
d_boxfilter_x(&id[y * w], &od[y * w], w, h, r);
|
||||
}
|
||||
|
||||
__global__ void d_boxfilter_y_global(float *id, float *od, int w, int h,
|
||||
int r) {
|
||||
unsigned int x = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
d_boxfilter_y(&id[x], &od[x], w, h, r);
|
||||
__global__ void d_boxfilter_y_global(float *id, float *od, int w, int h, int r)
|
||||
{
|
||||
unsigned int x = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
d_boxfilter_y(&id[x], &od[x], w, h, r);
|
||||
}
|
||||
|
||||
// texture version
|
||||
// texture fetches automatically clamp to edge of image
|
||||
__global__ void d_boxfilter_x_tex(float *od, int w, int h, int r,
|
||||
cudaTextureObject_t tex) {
|
||||
float scale = 1.0f / (float)((r << 1) + 1);
|
||||
unsigned int y = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
__global__ void d_boxfilter_x_tex(float *od, int w, int h, int r, cudaTextureObject_t tex)
|
||||
{
|
||||
float scale = 1.0f / (float)((r << 1) + 1);
|
||||
unsigned int y = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
|
||||
float t = 0.0f;
|
||||
float t = 0.0f;
|
||||
|
||||
for (int x = -r; x <= r; x++) {
|
||||
t += tex2D<float>(tex, x, y);
|
||||
}
|
||||
for (int x = -r; x <= r; x++) {
|
||||
t += tex2D<float>(tex, x, y);
|
||||
}
|
||||
|
||||
od[y * w] = t * scale;
|
||||
od[y * w] = t * scale;
|
||||
|
||||
for (int x = 1; x < w; x++) {
|
||||
t += tex2D<float>(tex, x + r, y);
|
||||
t -= tex2D<float>(tex, x - r - 1, y);
|
||||
od[y * w + x] = t * scale;
|
||||
}
|
||||
for (int x = 1; x < w; x++) {
|
||||
t += tex2D<float>(tex, x + r, y);
|
||||
t -= tex2D<float>(tex, x - r - 1, y);
|
||||
od[y * w + x] = t * scale;
|
||||
}
|
||||
}
|
||||
|
||||
__global__ void d_boxfilter_y_tex(float *od, int w, int h, int r,
|
||||
cudaTextureObject_t tex) {
|
||||
float scale = 1.0f / (float)((r << 1) + 1);
|
||||
unsigned int x = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
__global__ void d_boxfilter_y_tex(float *od, int w, int h, int r, cudaTextureObject_t tex)
|
||||
{
|
||||
float scale = 1.0f / (float)((r << 1) + 1);
|
||||
unsigned int x = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
|
||||
float t = 0.0f;
|
||||
float t = 0.0f;
|
||||
|
||||
for (int y = -r; y <= r; y++) {
|
||||
t += tex2D<float>(tex, x, y);
|
||||
}
|
||||
for (int y = -r; y <= r; y++) {
|
||||
t += tex2D<float>(tex, x, y);
|
||||
}
|
||||
|
||||
od[x] = t * scale;
|
||||
od[x] = t * scale;
|
||||
|
||||
for (int y = 1; y < h; y++) {
|
||||
t += tex2D<float>(tex, x, y + r);
|
||||
t -= tex2D<float>(tex, x, y - r - 1);
|
||||
od[y * w + x] = t * scale;
|
||||
}
|
||||
for (int y = 1; y < h; y++) {
|
||||
t += tex2D<float>(tex, x, y + r);
|
||||
t -= tex2D<float>(tex, x, y - r - 1);
|
||||
od[y * w + x] = t * scale;
|
||||
}
|
||||
}
|
||||
|
||||
// RGBA version
|
||||
// reads from 32-bit unsigned int array holding 8-bit RGBA
|
||||
|
||||
// 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));
|
||||
}
|
||||
|
||||
__device__ float4 rgbaIntToFloat(unsigned int c) {
|
||||
float4 rgba;
|
||||
rgba.x = (c & 0xff) * 0.003921568627f; // /255.0f;
|
||||
rgba.y = ((c >> 8) & 0xff) * 0.003921568627f; // /255.0f;
|
||||
rgba.z = ((c >> 16) & 0xff) * 0.003921568627f; // /255.0f;
|
||||
rgba.w = ((c >> 24) & 0xff) * 0.003921568627f; // /255.0f;
|
||||
return rgba;
|
||||
__device__ float4 rgbaIntToFloat(unsigned int c)
|
||||
{
|
||||
float4 rgba;
|
||||
rgba.x = (c & 0xff) * 0.003921568627f; // /255.0f;
|
||||
rgba.y = ((c >> 8) & 0xff) * 0.003921568627f; // /255.0f;
|
||||
rgba.z = ((c >> 16) & 0xff) * 0.003921568627f; // /255.0f;
|
||||
rgba.w = ((c >> 24) & 0xff) * 0.003921568627f; // /255.0f;
|
||||
return rgba;
|
||||
}
|
||||
|
||||
// row pass using texture lookups
|
||||
__global__ void d_boxfilter_rgba_x(unsigned int *od, int w, int h, int r,
|
||||
cudaTextureObject_t rgbaTex) {
|
||||
float scale = 1.0f / (float)((r << 1) + 1);
|
||||
unsigned int y = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
__global__ void d_boxfilter_rgba_x(unsigned int *od, int w, int h, int r, cudaTextureObject_t rgbaTex)
|
||||
{
|
||||
float scale = 1.0f / (float)((r << 1) + 1);
|
||||
unsigned int y = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
|
||||
// as long as address is always less than height, we do work
|
||||
if (y < h) {
|
||||
float4 t = make_float4(0.0f);
|
||||
// as long as address is always less than height, we do work
|
||||
if (y < h) {
|
||||
float4 t = make_float4(0.0f);
|
||||
|
||||
for (int x = -r; x <= r; x++) {
|
||||
t += tex2D<float4>(rgbaTex, x, y);
|
||||
for (int x = -r; x <= r; x++) {
|
||||
t += tex2D<float4>(rgbaTex, x, y);
|
||||
}
|
||||
|
||||
od[y * w] = rgbaFloatToInt(t * scale);
|
||||
|
||||
for (int x = 1; x < w; x++) {
|
||||
t += tex2D<float4>(rgbaTex, x + r, y);
|
||||
t -= tex2D<float4>(rgbaTex, x - r - 1, y);
|
||||
od[y * w + x] = rgbaFloatToInt(t * scale);
|
||||
}
|
||||
}
|
||||
|
||||
od[y * w] = rgbaFloatToInt(t * scale);
|
||||
|
||||
for (int x = 1; x < w; x++) {
|
||||
t += tex2D<float4>(rgbaTex, x + r, y);
|
||||
t -= tex2D<float4>(rgbaTex, x - r - 1, y);
|
||||
od[y * w + x] = rgbaFloatToInt(t * scale);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// column pass using coalesced global memory reads
|
||||
__global__ void d_boxfilter_rgba_y(unsigned int *id, unsigned int *od, int w,
|
||||
int h, int r) {
|
||||
unsigned int x = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
id = &id[x];
|
||||
od = &od[x];
|
||||
__global__ void d_boxfilter_rgba_y(unsigned int *id, unsigned int *od, int w, int h, int r)
|
||||
{
|
||||
unsigned int x = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
id = &id[x];
|
||||
od = &od[x];
|
||||
|
||||
float scale = 1.0f / (float)((r << 1) + 1);
|
||||
float scale = 1.0f / (float)((r << 1) + 1);
|
||||
|
||||
float4 t;
|
||||
// do left edge
|
||||
t = rgbaIntToFloat(id[0]) * r;
|
||||
float4 t;
|
||||
// do left edge
|
||||
t = rgbaIntToFloat(id[0]) * r;
|
||||
|
||||
for (int y = 0; y < (r + 1); y++) {
|
||||
t += rgbaIntToFloat(id[y * w]);
|
||||
}
|
||||
for (int y = 0; y < (r + 1); y++) {
|
||||
t += rgbaIntToFloat(id[y * w]);
|
||||
}
|
||||
|
||||
od[0] = rgbaFloatToInt(t * scale);
|
||||
od[0] = rgbaFloatToInt(t * scale);
|
||||
|
||||
for (int y = 1; y < (r + 1); y++) {
|
||||
t += rgbaIntToFloat(id[(y + r) * w]);
|
||||
t -= rgbaIntToFloat(id[0]);
|
||||
od[y * w] = rgbaFloatToInt(t * scale);
|
||||
}
|
||||
for (int y = 1; y < (r + 1); y++) {
|
||||
t += rgbaIntToFloat(id[(y + r) * w]);
|
||||
t -= rgbaIntToFloat(id[0]);
|
||||
od[y * w] = rgbaFloatToInt(t * scale);
|
||||
}
|
||||
|
||||
// main loop
|
||||
for (int y = (r + 1); y < (h - r); y++) {
|
||||
t += rgbaIntToFloat(id[(y + r) * w]);
|
||||
t -= rgbaIntToFloat(id[((y - r) * w) - w]);
|
||||
od[y * w] = rgbaFloatToInt(t * scale);
|
||||
}
|
||||
// main loop
|
||||
for (int y = (r + 1); y < (h - r); y++) {
|
||||
t += rgbaIntToFloat(id[(y + r) * w]);
|
||||
t -= rgbaIntToFloat(id[((y - r) * w) - w]);
|
||||
od[y * w] = rgbaFloatToInt(t * scale);
|
||||
}
|
||||
|
||||
// do right edge
|
||||
for (int y = h - r; y < h; y++) {
|
||||
t += rgbaIntToFloat(id[(h - 1) * w]);
|
||||
t -= rgbaIntToFloat(id[((y - r) * w) - w]);
|
||||
od[y * w] = rgbaFloatToInt(t * scale);
|
||||
}
|
||||
// do right edge
|
||||
for (int y = h - r; y < h; y++) {
|
||||
t += rgbaIntToFloat(id[(h - 1) * w]);
|
||||
t -= rgbaIntToFloat(id[((y - r) * w) - w]);
|
||||
od[y * w] = rgbaFloatToInt(t * scale);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void initTexture(int width, int height, void *pImage, bool useRGBA) {
|
||||
// copy image data to array
|
||||
cudaChannelFormatDesc channelDesc;
|
||||
if (useRGBA) {
|
||||
channelDesc =
|
||||
cudaCreateChannelDesc(8, 8, 8, 8, cudaChannelFormatKindUnsigned);
|
||||
} else {
|
||||
channelDesc =
|
||||
cudaCreateChannelDesc(32, 0, 0, 0, cudaChannelFormatKindFloat);
|
||||
}
|
||||
checkCudaErrors(cudaMallocArray(&d_array, &channelDesc, width, height));
|
||||
extern "C" void initTexture(int width, int height, void *pImage, bool useRGBA)
|
||||
{
|
||||
// copy image data to array
|
||||
cudaChannelFormatDesc channelDesc;
|
||||
if (useRGBA) {
|
||||
channelDesc = cudaCreateChannelDesc(8, 8, 8, 8, cudaChannelFormatKindUnsigned);
|
||||
}
|
||||
else {
|
||||
channelDesc = cudaCreateChannelDesc(32, 0, 0, 0, cudaChannelFormatKindFloat);
|
||||
}
|
||||
checkCudaErrors(cudaMallocArray(&d_array, &channelDesc, width, height));
|
||||
|
||||
size_t bytesPerElem = (useRGBA ? sizeof(uchar4) : sizeof(float));
|
||||
checkCudaErrors(cudaMemcpy2DToArray(
|
||||
d_array, 0, 0, pImage, width * bytesPerElem, width * bytesPerElem, height,
|
||||
cudaMemcpyHostToDevice));
|
||||
size_t bytesPerElem = (useRGBA ? sizeof(uchar4) : sizeof(float));
|
||||
checkCudaErrors(cudaMemcpy2DToArray(
|
||||
d_array, 0, 0, pImage, width * bytesPerElem, width * bytesPerElem, height, cudaMemcpyHostToDevice));
|
||||
|
||||
checkCudaErrors(cudaMallocArray(&d_tempArray, &channelDesc, width, height));
|
||||
checkCudaErrors(cudaMallocArray(&d_tempArray, &channelDesc, width, height));
|
||||
|
||||
// set texture parameters
|
||||
cudaResourceDesc texRes;
|
||||
memset(&texRes, 0, sizeof(cudaResourceDesc));
|
||||
// set texture parameters
|
||||
cudaResourceDesc texRes;
|
||||
memset(&texRes, 0, sizeof(cudaResourceDesc));
|
||||
|
||||
texRes.resType = cudaResourceTypeArray;
|
||||
texRes.res.array.array = d_array;
|
||||
texRes.resType = cudaResourceTypeArray;
|
||||
texRes.res.array.array = d_array;
|
||||
|
||||
cudaTextureDesc texDescr;
|
||||
memset(&texDescr, 0, sizeof(cudaTextureDesc));
|
||||
cudaTextureDesc texDescr;
|
||||
memset(&texDescr, 0, sizeof(cudaTextureDesc));
|
||||
|
||||
texDescr.normalizedCoords = false;
|
||||
texDescr.filterMode = cudaFilterModeLinear;
|
||||
texDescr.addressMode[0] = cudaAddressModeWrap;
|
||||
texDescr.addressMode[1] = cudaAddressModeWrap;
|
||||
texDescr.readMode = cudaReadModeNormalizedFloat;
|
||||
texDescr.normalizedCoords = false;
|
||||
texDescr.filterMode = cudaFilterModeLinear;
|
||||
texDescr.addressMode[0] = cudaAddressModeWrap;
|
||||
texDescr.addressMode[1] = cudaAddressModeWrap;
|
||||
texDescr.readMode = cudaReadModeNormalizedFloat;
|
||||
|
||||
checkCudaErrors(cudaCreateTextureObject(&rgbaTex, &texRes, &texDescr, NULL));
|
||||
checkCudaErrors(cudaCreateTextureObject(&rgbaTex, &texRes, &texDescr, NULL));
|
||||
|
||||
memset(&texRes, 0, sizeof(cudaResourceDesc));
|
||||
memset(&texRes, 0, sizeof(cudaResourceDesc));
|
||||
|
||||
texRes.resType = cudaResourceTypeArray;
|
||||
texRes.res.array.array = d_tempArray;
|
||||
texRes.resType = cudaResourceTypeArray;
|
||||
texRes.res.array.array = d_tempArray;
|
||||
|
||||
memset(&texDescr, 0, sizeof(cudaTextureDesc));
|
||||
memset(&texDescr, 0, sizeof(cudaTextureDesc));
|
||||
|
||||
texDescr.normalizedCoords = false;
|
||||
texDescr.filterMode = cudaFilterModeLinear;
|
||||
texDescr.addressMode[0] = cudaAddressModeClamp;
|
||||
texDescr.addressMode[1] = cudaAddressModeClamp;
|
||||
texDescr.readMode = cudaReadModeNormalizedFloat;
|
||||
texDescr.normalizedCoords = false;
|
||||
texDescr.filterMode = cudaFilterModeLinear;
|
||||
texDescr.addressMode[0] = cudaAddressModeClamp;
|
||||
texDescr.addressMode[1] = cudaAddressModeClamp;
|
||||
texDescr.readMode = cudaReadModeNormalizedFloat;
|
||||
|
||||
checkCudaErrors(
|
||||
cudaCreateTextureObject(&rgbaTexTempArray, &texRes, &texDescr, NULL));
|
||||
checkCudaErrors(cudaCreateTextureObject(&rgbaTexTempArray, &texRes, &texDescr, NULL));
|
||||
|
||||
memset(&texRes, 0, sizeof(cudaResourceDesc));
|
||||
memset(&texRes, 0, sizeof(cudaResourceDesc));
|
||||
|
||||
texRes.resType = cudaResourceTypeArray;
|
||||
texRes.res.array.array = d_array;
|
||||
texRes.resType = cudaResourceTypeArray;
|
||||
texRes.res.array.array = d_array;
|
||||
|
||||
memset(&texDescr, 0, sizeof(cudaTextureDesc));
|
||||
memset(&texDescr, 0, sizeof(cudaTextureDesc));
|
||||
|
||||
texDescr.normalizedCoords = true;
|
||||
texDescr.filterMode = cudaFilterModePoint;
|
||||
texDescr.addressMode[0] = cudaAddressModeWrap;
|
||||
texDescr.addressMode[1] = cudaAddressModeWrap;
|
||||
texDescr.readMode = cudaReadModeElementType;
|
||||
texDescr.normalizedCoords = true;
|
||||
texDescr.filterMode = cudaFilterModePoint;
|
||||
texDescr.addressMode[0] = cudaAddressModeWrap;
|
||||
texDescr.addressMode[1] = cudaAddressModeWrap;
|
||||
texDescr.readMode = cudaReadModeElementType;
|
||||
|
||||
checkCudaErrors(cudaCreateTextureObject(&tex, &texRes, &texDescr, NULL));
|
||||
checkCudaErrors(cudaCreateTextureObject(&tex, &texRes, &texDescr, NULL));
|
||||
|
||||
memset(&texRes, 0, sizeof(cudaResourceDesc));
|
||||
memset(&texRes, 0, sizeof(cudaResourceDesc));
|
||||
|
||||
texRes.resType = cudaResourceTypeArray;
|
||||
texRes.res.array.array = d_tempArray;
|
||||
texRes.resType = cudaResourceTypeArray;
|
||||
texRes.res.array.array = d_tempArray;
|
||||
|
||||
memset(&texDescr, 0, sizeof(cudaTextureDesc));
|
||||
memset(&texDescr, 0, sizeof(cudaTextureDesc));
|
||||
|
||||
texDescr.normalizedCoords = true;
|
||||
texDescr.filterMode = cudaFilterModePoint;
|
||||
texDescr.addressMode[0] = cudaAddressModeWrap;
|
||||
texDescr.addressMode[1] = cudaAddressModeWrap;
|
||||
texDescr.readMode = cudaReadModeElementType;
|
||||
texDescr.normalizedCoords = true;
|
||||
texDescr.filterMode = cudaFilterModePoint;
|
||||
texDescr.addressMode[0] = cudaAddressModeWrap;
|
||||
texDescr.addressMode[1] = cudaAddressModeWrap;
|
||||
texDescr.readMode = cudaReadModeElementType;
|
||||
|
||||
checkCudaErrors(
|
||||
cudaCreateTextureObject(&texTempArray, &texRes, &texDescr, NULL));
|
||||
checkCudaErrors(cudaCreateTextureObject(&texTempArray, &texRes, &texDescr, NULL));
|
||||
}
|
||||
|
||||
extern "C" void freeTextures() {
|
||||
checkCudaErrors(cudaDestroyTextureObject(tex));
|
||||
checkCudaErrors(cudaDestroyTextureObject(texTempArray));
|
||||
checkCudaErrors(cudaDestroyTextureObject(rgbaTex));
|
||||
checkCudaErrors(cudaDestroyTextureObject(rgbaTexTempArray));
|
||||
checkCudaErrors(cudaFreeArray(d_array));
|
||||
checkCudaErrors(cudaFreeArray(d_tempArray));
|
||||
extern "C" void freeTextures()
|
||||
{
|
||||
checkCudaErrors(cudaDestroyTextureObject(tex));
|
||||
checkCudaErrors(cudaDestroyTextureObject(texTempArray));
|
||||
checkCudaErrors(cudaDestroyTextureObject(rgbaTex));
|
||||
checkCudaErrors(cudaDestroyTextureObject(rgbaTexTempArray));
|
||||
checkCudaErrors(cudaFreeArray(d_array));
|
||||
checkCudaErrors(cudaFreeArray(d_tempArray));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -407,83 +407,100 @@ extern "C" void freeTextures() {
|
||||
iterations - number of iterations
|
||||
|
||||
*/
|
||||
extern "C" double boxFilter(float *d_temp, float *d_dest,
|
||||
int width, int height, int radius, int iterations,
|
||||
int nthreads, StopWatchInterface *timer) {
|
||||
// var for kernel timing
|
||||
double dKernelTime = 0.0;
|
||||
extern "C" double boxFilter(float *d_temp,
|
||||
float *d_dest,
|
||||
int width,
|
||||
int height,
|
||||
int radius,
|
||||
int iterations,
|
||||
int nthreads,
|
||||
StopWatchInterface *timer)
|
||||
{
|
||||
// var for kernel timing
|
||||
double dKernelTime = 0.0;
|
||||
|
||||
// sync host and start computation timer_kernel
|
||||
checkCudaErrors(cudaDeviceSynchronize());
|
||||
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
sdkResetTimer(&timer);
|
||||
// use texture for horizontal pass
|
||||
if (iterations > 1) {
|
||||
d_boxfilter_x_tex<<<height / nthreads, nthreads, 0>>>(
|
||||
d_temp, width, height, radius, texTempArray);
|
||||
} else {
|
||||
d_boxfilter_x_tex<<<height / nthreads, nthreads, 0>>>(
|
||||
d_temp, width, height, radius, tex);
|
||||
}
|
||||
|
||||
d_boxfilter_y_global<<<width / nthreads, nthreads, 0>>>(
|
||||
d_temp, d_dest, width, height, radius);
|
||||
|
||||
// sync host and stop computation timer_kernel
|
||||
// sync host and start computation timer_kernel
|
||||
checkCudaErrors(cudaDeviceSynchronize());
|
||||
dKernelTime += sdkGetTimerValue(&timer);
|
||||
|
||||
if (iterations > 1) {
|
||||
// copy result back from global memory to array
|
||||
checkCudaErrors(cudaMemcpy2DToArray(
|
||||
d_tempArray, 0, 0, d_dest, width * sizeof(float),
|
||||
width * sizeof(float), height, cudaMemcpyDeviceToDevice));
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
sdkResetTimer(&timer);
|
||||
// use texture for horizontal pass
|
||||
if (iterations > 1) {
|
||||
d_boxfilter_x_tex<<<height / nthreads, nthreads, 0>>>(d_temp, width, height, radius, texTempArray);
|
||||
}
|
||||
else {
|
||||
d_boxfilter_x_tex<<<height / nthreads, nthreads, 0>>>(d_temp, width, height, radius, tex);
|
||||
}
|
||||
|
||||
d_boxfilter_y_global<<<width / nthreads, nthreads, 0>>>(d_temp, d_dest, width, height, radius);
|
||||
|
||||
// sync host and stop computation timer_kernel
|
||||
checkCudaErrors(cudaDeviceSynchronize());
|
||||
dKernelTime += sdkGetTimerValue(&timer);
|
||||
|
||||
if (iterations > 1) {
|
||||
// copy result back from global memory to array
|
||||
checkCudaErrors(cudaMemcpy2DToArray(d_tempArray,
|
||||
0,
|
||||
0,
|
||||
d_dest,
|
||||
width * sizeof(float),
|
||||
width * sizeof(float),
|
||||
height,
|
||||
cudaMemcpyDeviceToDevice));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ((dKernelTime / 1000.) / (double)iterations);
|
||||
return ((dKernelTime / 1000.) / (double)iterations);
|
||||
}
|
||||
|
||||
// RGBA version
|
||||
extern "C" double boxFilterRGBA(unsigned int *d_temp,
|
||||
unsigned int *d_dest, int width, int height,
|
||||
int radius, int iterations, int nthreads,
|
||||
StopWatchInterface *timer) {
|
||||
// var for kernel computation timing
|
||||
double dKernelTime;
|
||||
extern "C" double boxFilterRGBA(unsigned int *d_temp,
|
||||
unsigned int *d_dest,
|
||||
int width,
|
||||
int height,
|
||||
int radius,
|
||||
int iterations,
|
||||
int nthreads,
|
||||
StopWatchInterface *timer)
|
||||
{
|
||||
// var for kernel computation timing
|
||||
double dKernelTime;
|
||||
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
// sync host and start kernel computation timer_kernel
|
||||
dKernelTime = 0.0;
|
||||
checkCudaErrors(cudaDeviceSynchronize());
|
||||
sdkResetTimer(&timer);
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
// sync host and start kernel computation timer_kernel
|
||||
dKernelTime = 0.0;
|
||||
checkCudaErrors(cudaDeviceSynchronize());
|
||||
sdkResetTimer(&timer);
|
||||
|
||||
// use texture for horizontal pass
|
||||
if (iterations > 1) {
|
||||
d_boxfilter_rgba_x<<<height / nthreads, nthreads, 0>>>(
|
||||
d_temp, width, height, radius, rgbaTexTempArray);
|
||||
} else {
|
||||
d_boxfilter_rgba_x<<<height / nthreads, nthreads, 0>>>(
|
||||
d_temp, width, height, radius, rgbaTex);
|
||||
// use texture for horizontal pass
|
||||
if (iterations > 1) {
|
||||
d_boxfilter_rgba_x<<<height / nthreads, nthreads, 0>>>(d_temp, width, height, radius, rgbaTexTempArray);
|
||||
}
|
||||
else {
|
||||
d_boxfilter_rgba_x<<<height / nthreads, nthreads, 0>>>(d_temp, width, height, radius, rgbaTex);
|
||||
}
|
||||
|
||||
d_boxfilter_rgba_y<<<width / nthreads, nthreads, 0>>>(d_temp, d_dest, width, height, radius);
|
||||
|
||||
// sync host and stop computation timer_kernel
|
||||
checkCudaErrors(cudaDeviceSynchronize());
|
||||
dKernelTime += sdkGetTimerValue(&timer);
|
||||
|
||||
if (iterations > 1) {
|
||||
// copy result back from global memory to array
|
||||
checkCudaErrors(cudaMemcpy2DToArray(d_tempArray,
|
||||
0,
|
||||
0,
|
||||
d_dest,
|
||||
width * sizeof(unsigned int),
|
||||
width * sizeof(unsigned int),
|
||||
height,
|
||||
cudaMemcpyDeviceToDevice));
|
||||
}
|
||||
}
|
||||
|
||||
d_boxfilter_rgba_y<<<width / nthreads, nthreads, 0>>>(d_temp, d_dest, width,
|
||||
height, radius);
|
||||
|
||||
// sync host and stop computation timer_kernel
|
||||
checkCudaErrors(cudaDeviceSynchronize());
|
||||
dKernelTime += sdkGetTimerValue(&timer);
|
||||
|
||||
if (iterations > 1) {
|
||||
// copy result back from global memory to array
|
||||
checkCudaErrors(cudaMemcpy2DToArray(
|
||||
d_tempArray, 0, 0, d_dest, width * sizeof(unsigned int),
|
||||
width * sizeof(unsigned int), height, cudaMemcpyDeviceToDevice));
|
||||
}
|
||||
}
|
||||
|
||||
return ((dKernelTime / 1000.) / (double)iterations);
|
||||
return ((dKernelTime / 1000.) / (double)iterations);
|
||||
}
|
||||
|
||||
#endif // #ifndef _BOXFILTER_KERNEL_H_
|
||||
#endif // #ifndef _BOXFILTER_KERNEL_H_
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <helper_cuda.h>
|
||||
#include <cooperative_groups.h>
|
||||
#include <helper_cuda.h>
|
||||
|
||||
namespace cg = cooperative_groups;
|
||||
#include "convolutionSeparable_common.h"
|
||||
@@ -37,178 +37,156 @@ namespace cg = cooperative_groups;
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
__constant__ float c_Kernel[KERNEL_LENGTH];
|
||||
|
||||
extern "C" void setConvolutionKernel(float *h_Kernel) {
|
||||
cudaMemcpyToSymbol(c_Kernel, h_Kernel, KERNEL_LENGTH * sizeof(float));
|
||||
extern "C" void setConvolutionKernel(float *h_Kernel)
|
||||
{
|
||||
cudaMemcpyToSymbol(c_Kernel, h_Kernel, KERNEL_LENGTH * sizeof(float));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Row convolution filter
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#define ROWS_BLOCKDIM_X 16
|
||||
#define ROWS_BLOCKDIM_Y 4
|
||||
#define ROWS_BLOCKDIM_X 16
|
||||
#define ROWS_BLOCKDIM_Y 4
|
||||
#define ROWS_RESULT_STEPS 8
|
||||
#define ROWS_HALO_STEPS 1
|
||||
#define ROWS_HALO_STEPS 1
|
||||
|
||||
__global__ void convolutionRowsKernel(float *d_Dst, float *d_Src, int imageW,
|
||||
int imageH, int pitch) {
|
||||
// Handle to thread block group
|
||||
cg::thread_block cta = cg::this_thread_block();
|
||||
__shared__ float
|
||||
s_Data[ROWS_BLOCKDIM_Y][(ROWS_RESULT_STEPS + 2 * ROWS_HALO_STEPS) *
|
||||
ROWS_BLOCKDIM_X];
|
||||
__global__ void convolutionRowsKernel(float *d_Dst, float *d_Src, int imageW, int imageH, int pitch)
|
||||
{
|
||||
// Handle to thread block group
|
||||
cg::thread_block cta = cg::this_thread_block();
|
||||
__shared__ float s_Data[ROWS_BLOCKDIM_Y][(ROWS_RESULT_STEPS + 2 * ROWS_HALO_STEPS) * ROWS_BLOCKDIM_X];
|
||||
|
||||
// Offset to the left halo edge
|
||||
const int baseX =
|
||||
(blockIdx.x * ROWS_RESULT_STEPS - ROWS_HALO_STEPS) * ROWS_BLOCKDIM_X +
|
||||
threadIdx.x;
|
||||
const int baseY = blockIdx.y * ROWS_BLOCKDIM_Y + threadIdx.y;
|
||||
// Offset to the left halo edge
|
||||
const int baseX = (blockIdx.x * ROWS_RESULT_STEPS - ROWS_HALO_STEPS) * ROWS_BLOCKDIM_X + threadIdx.x;
|
||||
const int baseY = blockIdx.y * ROWS_BLOCKDIM_Y + threadIdx.y;
|
||||
|
||||
d_Src += baseY * pitch + baseX;
|
||||
d_Dst += baseY * pitch + baseX;
|
||||
d_Src += baseY * pitch + baseX;
|
||||
d_Dst += baseY * pitch + baseX;
|
||||
|
||||
// Load main data
|
||||
#pragma unroll
|
||||
|
||||
for (int i = ROWS_HALO_STEPS; i < ROWS_HALO_STEPS + ROWS_RESULT_STEPS; i++) {
|
||||
s_Data[threadIdx.y][threadIdx.x + i * ROWS_BLOCKDIM_X] =
|
||||
d_Src[i * ROWS_BLOCKDIM_X];
|
||||
}
|
||||
for (int i = ROWS_HALO_STEPS; i < ROWS_HALO_STEPS + ROWS_RESULT_STEPS; i++) {
|
||||
s_Data[threadIdx.y][threadIdx.x + i * ROWS_BLOCKDIM_X] = d_Src[i * ROWS_BLOCKDIM_X];
|
||||
}
|
||||
|
||||
// Load left halo
|
||||
#pragma unroll
|
||||
|
||||
for (int i = 0; i < ROWS_HALO_STEPS; i++) {
|
||||
s_Data[threadIdx.y][threadIdx.x + i * ROWS_BLOCKDIM_X] =
|
||||
(baseX >= -i * ROWS_BLOCKDIM_X) ? d_Src[i * ROWS_BLOCKDIM_X] : 0;
|
||||
}
|
||||
for (int i = 0; i < ROWS_HALO_STEPS; i++) {
|
||||
s_Data[threadIdx.y][threadIdx.x + i * ROWS_BLOCKDIM_X] =
|
||||
(baseX >= -i * ROWS_BLOCKDIM_X) ? d_Src[i * ROWS_BLOCKDIM_X] : 0;
|
||||
}
|
||||
|
||||
// Load right halo
|
||||
#pragma unroll
|
||||
|
||||
for (int i = ROWS_HALO_STEPS + ROWS_RESULT_STEPS;
|
||||
i < ROWS_HALO_STEPS + ROWS_RESULT_STEPS + ROWS_HALO_STEPS; i++) {
|
||||
s_Data[threadIdx.y][threadIdx.x + i * ROWS_BLOCKDIM_X] =
|
||||
(imageW - baseX > i * ROWS_BLOCKDIM_X) ? d_Src[i * ROWS_BLOCKDIM_X] : 0;
|
||||
}
|
||||
|
||||
// Compute and store results
|
||||
cg::sync(cta);
|
||||
#pragma unroll
|
||||
|
||||
for (int i = ROWS_HALO_STEPS; i < ROWS_HALO_STEPS + ROWS_RESULT_STEPS; i++) {
|
||||
float sum = 0;
|
||||
|
||||
#pragma unroll
|
||||
|
||||
for (int j = -KERNEL_RADIUS; j <= KERNEL_RADIUS; j++) {
|
||||
sum += c_Kernel[KERNEL_RADIUS - j] *
|
||||
s_Data[threadIdx.y][threadIdx.x + i * ROWS_BLOCKDIM_X + j];
|
||||
for (int i = ROWS_HALO_STEPS + ROWS_RESULT_STEPS; i < ROWS_HALO_STEPS + ROWS_RESULT_STEPS + ROWS_HALO_STEPS; i++) {
|
||||
s_Data[threadIdx.y][threadIdx.x + i * ROWS_BLOCKDIM_X] =
|
||||
(imageW - baseX > i * ROWS_BLOCKDIM_X) ? d_Src[i * ROWS_BLOCKDIM_X] : 0;
|
||||
}
|
||||
|
||||
d_Dst[i * ROWS_BLOCKDIM_X] = sum;
|
||||
}
|
||||
// Compute and store results
|
||||
cg::sync(cta);
|
||||
#pragma unroll
|
||||
|
||||
for (int i = ROWS_HALO_STEPS; i < ROWS_HALO_STEPS + ROWS_RESULT_STEPS; i++) {
|
||||
float sum = 0;
|
||||
|
||||
#pragma unroll
|
||||
|
||||
for (int j = -KERNEL_RADIUS; j <= KERNEL_RADIUS; j++) {
|
||||
sum += c_Kernel[KERNEL_RADIUS - j] * s_Data[threadIdx.y][threadIdx.x + i * ROWS_BLOCKDIM_X + j];
|
||||
}
|
||||
|
||||
d_Dst[i * ROWS_BLOCKDIM_X] = sum;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void convolutionRowsGPU(float *d_Dst, float *d_Src, int imageW,
|
||||
int imageH) {
|
||||
assert(ROWS_BLOCKDIM_X * ROWS_HALO_STEPS >= KERNEL_RADIUS);
|
||||
assert(imageW % (ROWS_RESULT_STEPS * ROWS_BLOCKDIM_X) == 0);
|
||||
assert(imageH % ROWS_BLOCKDIM_Y == 0);
|
||||
extern "C" void convolutionRowsGPU(float *d_Dst, float *d_Src, int imageW, int imageH)
|
||||
{
|
||||
assert(ROWS_BLOCKDIM_X * ROWS_HALO_STEPS >= KERNEL_RADIUS);
|
||||
assert(imageW % (ROWS_RESULT_STEPS * ROWS_BLOCKDIM_X) == 0);
|
||||
assert(imageH % ROWS_BLOCKDIM_Y == 0);
|
||||
|
||||
dim3 blocks(imageW / (ROWS_RESULT_STEPS * ROWS_BLOCKDIM_X),
|
||||
imageH / ROWS_BLOCKDIM_Y);
|
||||
dim3 threads(ROWS_BLOCKDIM_X, ROWS_BLOCKDIM_Y);
|
||||
dim3 blocks(imageW / (ROWS_RESULT_STEPS * ROWS_BLOCKDIM_X), imageH / ROWS_BLOCKDIM_Y);
|
||||
dim3 threads(ROWS_BLOCKDIM_X, ROWS_BLOCKDIM_Y);
|
||||
|
||||
convolutionRowsKernel<<<blocks, threads>>>(d_Dst, d_Src, imageW, imageH,
|
||||
imageW);
|
||||
getLastCudaError("convolutionRowsKernel() execution failed\n");
|
||||
convolutionRowsKernel<<<blocks, threads>>>(d_Dst, d_Src, imageW, imageH, imageW);
|
||||
getLastCudaError("convolutionRowsKernel() execution failed\n");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Column convolution filter
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#define COLUMNS_BLOCKDIM_X 16
|
||||
#define COLUMNS_BLOCKDIM_Y 8
|
||||
#define COLUMNS_BLOCKDIM_X 16
|
||||
#define COLUMNS_BLOCKDIM_Y 8
|
||||
#define COLUMNS_RESULT_STEPS 8
|
||||
#define COLUMNS_HALO_STEPS 1
|
||||
#define COLUMNS_HALO_STEPS 1
|
||||
|
||||
__global__ void convolutionColumnsKernel(float *d_Dst, float *d_Src, int imageW,
|
||||
int imageH, int pitch) {
|
||||
// Handle to thread block group
|
||||
cg::thread_block cta = cg::this_thread_block();
|
||||
__shared__ float s_Data[COLUMNS_BLOCKDIM_X][(COLUMNS_RESULT_STEPS +
|
||||
2 * COLUMNS_HALO_STEPS) *
|
||||
COLUMNS_BLOCKDIM_Y +
|
||||
1];
|
||||
__global__ void convolutionColumnsKernel(float *d_Dst, float *d_Src, int imageW, int imageH, int pitch)
|
||||
{
|
||||
// Handle to thread block group
|
||||
cg::thread_block cta = cg::this_thread_block();
|
||||
__shared__ float s_Data[COLUMNS_BLOCKDIM_X]
|
||||
[(COLUMNS_RESULT_STEPS + 2 * COLUMNS_HALO_STEPS) * COLUMNS_BLOCKDIM_Y + 1];
|
||||
|
||||
// Offset to the upper halo edge
|
||||
const int baseX = blockIdx.x * COLUMNS_BLOCKDIM_X + threadIdx.x;
|
||||
const int baseY = (blockIdx.y * COLUMNS_RESULT_STEPS - COLUMNS_HALO_STEPS) *
|
||||
COLUMNS_BLOCKDIM_Y +
|
||||
threadIdx.y;
|
||||
d_Src += baseY * pitch + baseX;
|
||||
d_Dst += baseY * pitch + baseX;
|
||||
// Offset to the upper halo edge
|
||||
const int baseX = blockIdx.x * COLUMNS_BLOCKDIM_X + threadIdx.x;
|
||||
const int baseY = (blockIdx.y * COLUMNS_RESULT_STEPS - COLUMNS_HALO_STEPS) * COLUMNS_BLOCKDIM_Y + threadIdx.y;
|
||||
d_Src += baseY * pitch + baseX;
|
||||
d_Dst += baseY * pitch + baseX;
|
||||
|
||||
// Main data
|
||||
#pragma unroll
|
||||
|
||||
for (int i = COLUMNS_HALO_STEPS;
|
||||
i < COLUMNS_HALO_STEPS + COLUMNS_RESULT_STEPS; i++) {
|
||||
s_Data[threadIdx.x][threadIdx.y + i * COLUMNS_BLOCKDIM_Y] =
|
||||
d_Src[i * COLUMNS_BLOCKDIM_Y * pitch];
|
||||
}
|
||||
for (int i = COLUMNS_HALO_STEPS; i < COLUMNS_HALO_STEPS + COLUMNS_RESULT_STEPS; i++) {
|
||||
s_Data[threadIdx.x][threadIdx.y + i * COLUMNS_BLOCKDIM_Y] = d_Src[i * COLUMNS_BLOCKDIM_Y * pitch];
|
||||
}
|
||||
|
||||
// Upper halo
|
||||
#pragma unroll
|
||||
|
||||
for (int i = 0; i < COLUMNS_HALO_STEPS; i++) {
|
||||
s_Data[threadIdx.x][threadIdx.y + i * COLUMNS_BLOCKDIM_Y] =
|
||||
(baseY >= -i * COLUMNS_BLOCKDIM_Y)
|
||||
? d_Src[i * COLUMNS_BLOCKDIM_Y * pitch]
|
||||
: 0;
|
||||
}
|
||||
for (int i = 0; i < COLUMNS_HALO_STEPS; i++) {
|
||||
s_Data[threadIdx.x][threadIdx.y + i * COLUMNS_BLOCKDIM_Y] =
|
||||
(baseY >= -i * COLUMNS_BLOCKDIM_Y) ? d_Src[i * COLUMNS_BLOCKDIM_Y * pitch] : 0;
|
||||
}
|
||||
|
||||
// Lower halo
|
||||
#pragma unroll
|
||||
|
||||
for (int i = COLUMNS_HALO_STEPS + COLUMNS_RESULT_STEPS;
|
||||
i < COLUMNS_HALO_STEPS + COLUMNS_RESULT_STEPS + COLUMNS_HALO_STEPS;
|
||||
i++) {
|
||||
s_Data[threadIdx.x][threadIdx.y + i * COLUMNS_BLOCKDIM_Y] =
|
||||
(imageH - baseY > i * COLUMNS_BLOCKDIM_Y)
|
||||
? d_Src[i * COLUMNS_BLOCKDIM_Y * pitch]
|
||||
: 0;
|
||||
}
|
||||
|
||||
// Compute and store results
|
||||
cg::sync(cta);
|
||||
#pragma unroll
|
||||
|
||||
for (int i = COLUMNS_HALO_STEPS;
|
||||
i < COLUMNS_HALO_STEPS + COLUMNS_RESULT_STEPS; i++) {
|
||||
float sum = 0;
|
||||
#pragma unroll
|
||||
|
||||
for (int j = -KERNEL_RADIUS; j <= KERNEL_RADIUS; j++) {
|
||||
sum += c_Kernel[KERNEL_RADIUS - j] *
|
||||
s_Data[threadIdx.x][threadIdx.y + i * COLUMNS_BLOCKDIM_Y + j];
|
||||
for (int i = COLUMNS_HALO_STEPS + COLUMNS_RESULT_STEPS;
|
||||
i < COLUMNS_HALO_STEPS + COLUMNS_RESULT_STEPS + COLUMNS_HALO_STEPS;
|
||||
i++) {
|
||||
s_Data[threadIdx.x][threadIdx.y + i * COLUMNS_BLOCKDIM_Y] =
|
||||
(imageH - baseY > i * COLUMNS_BLOCKDIM_Y) ? d_Src[i * COLUMNS_BLOCKDIM_Y * pitch] : 0;
|
||||
}
|
||||
|
||||
d_Dst[i * COLUMNS_BLOCKDIM_Y * pitch] = sum;
|
||||
}
|
||||
// Compute and store results
|
||||
cg::sync(cta);
|
||||
#pragma unroll
|
||||
|
||||
for (int i = COLUMNS_HALO_STEPS; i < COLUMNS_HALO_STEPS + COLUMNS_RESULT_STEPS; i++) {
|
||||
float sum = 0;
|
||||
#pragma unroll
|
||||
|
||||
for (int j = -KERNEL_RADIUS; j <= KERNEL_RADIUS; j++) {
|
||||
sum += c_Kernel[KERNEL_RADIUS - j] * s_Data[threadIdx.x][threadIdx.y + i * COLUMNS_BLOCKDIM_Y + j];
|
||||
}
|
||||
|
||||
d_Dst[i * COLUMNS_BLOCKDIM_Y * pitch] = sum;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void convolutionColumnsGPU(float *d_Dst, float *d_Src, int imageW,
|
||||
int imageH) {
|
||||
assert(COLUMNS_BLOCKDIM_Y * COLUMNS_HALO_STEPS >= KERNEL_RADIUS);
|
||||
assert(imageW % COLUMNS_BLOCKDIM_X == 0);
|
||||
assert(imageH % (COLUMNS_RESULT_STEPS * COLUMNS_BLOCKDIM_Y) == 0);
|
||||
extern "C" void convolutionColumnsGPU(float *d_Dst, float *d_Src, int imageW, int imageH)
|
||||
{
|
||||
assert(COLUMNS_BLOCKDIM_Y * COLUMNS_HALO_STEPS >= KERNEL_RADIUS);
|
||||
assert(imageW % COLUMNS_BLOCKDIM_X == 0);
|
||||
assert(imageH % (COLUMNS_RESULT_STEPS * COLUMNS_BLOCKDIM_Y) == 0);
|
||||
|
||||
dim3 blocks(imageW / COLUMNS_BLOCKDIM_X,
|
||||
imageH / (COLUMNS_RESULT_STEPS * COLUMNS_BLOCKDIM_Y));
|
||||
dim3 threads(COLUMNS_BLOCKDIM_X, COLUMNS_BLOCKDIM_Y);
|
||||
dim3 blocks(imageW / COLUMNS_BLOCKDIM_X, imageH / (COLUMNS_RESULT_STEPS * COLUMNS_BLOCKDIM_Y));
|
||||
dim3 threads(COLUMNS_BLOCKDIM_X, COLUMNS_BLOCKDIM_Y);
|
||||
|
||||
convolutionColumnsKernel<<<blocks, threads>>>(d_Dst, d_Src, imageW, imageH,
|
||||
imageW);
|
||||
getLastCudaError("convolutionColumnsKernel() execution failed\n");
|
||||
convolutionColumnsKernel<<<blocks, threads>>>(d_Dst, d_Src, imageW, imageH, imageW);
|
||||
getLastCudaError("convolutionColumnsKernel() execution failed\n");
|
||||
}
|
||||
|
||||
@@ -34,22 +34,17 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Reference CPU convolution
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
extern "C" void convolutionRowCPU(float *h_Dst, float *h_Src, float *h_Kernel,
|
||||
int imageW, int imageH, int kernelR);
|
||||
extern "C" void convolutionRowCPU(float *h_Dst, float *h_Src, float *h_Kernel, int imageW, int imageH, int kernelR);
|
||||
|
||||
extern "C" void convolutionColumnCPU(float *h_Dst, float *h_Src,
|
||||
float *h_Kernel, int imageW, int imageH,
|
||||
int kernelR);
|
||||
extern "C" void convolutionColumnCPU(float *h_Dst, float *h_Src, float *h_Kernel, int imageW, int imageH, int kernelR);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// GPU convolution
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
extern "C" void setConvolutionKernel(float *h_Kernel);
|
||||
|
||||
extern "C" void convolutionRowsGPU(float *d_Dst, float *d_Src, int imageW,
|
||||
int imageH);
|
||||
extern "C" void convolutionRowsGPU(float *d_Dst, float *d_Src, int imageW, int imageH);
|
||||
|
||||
extern "C" void convolutionColumnsGPU(float *d_Dst, float *d_Src, int imageW,
|
||||
int imageH);
|
||||
extern "C" void convolutionColumnsGPU(float *d_Dst, float *d_Src, int imageW, int imageH);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -30,40 +30,39 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Reference row convolution filter
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
extern "C" void convolutionRowCPU(float *h_Dst, float *h_Src, float *h_Kernel,
|
||||
int imageW, int imageH, int kernelR) {
|
||||
for (int y = 0; y < imageH; y++)
|
||||
for (int x = 0; x < imageW; x++) {
|
||||
float sum = 0;
|
||||
extern "C" void convolutionRowCPU(float *h_Dst, float *h_Src, float *h_Kernel, int imageW, int imageH, int kernelR)
|
||||
{
|
||||
for (int y = 0; y < imageH; y++)
|
||||
for (int x = 0; x < imageW; x++) {
|
||||
float sum = 0;
|
||||
|
||||
for (int k = -kernelR; k <= kernelR; k++) {
|
||||
int d = x + k;
|
||||
for (int k = -kernelR; k <= kernelR; k++) {
|
||||
int d = x + k;
|
||||
|
||||
if (d >= 0 && d < imageW)
|
||||
sum += h_Src[y * imageW + d] * h_Kernel[kernelR - k];
|
||||
}
|
||||
if (d >= 0 && d < imageW)
|
||||
sum += h_Src[y * imageW + d] * h_Kernel[kernelR - k];
|
||||
}
|
||||
|
||||
h_Dst[y * imageW + x] = sum;
|
||||
}
|
||||
h_Dst[y * imageW + x] = sum;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Reference column convolution filter
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
extern "C" void convolutionColumnCPU(float *h_Dst, float *h_Src,
|
||||
float *h_Kernel, int imageW, int imageH,
|
||||
int kernelR) {
|
||||
for (int y = 0; y < imageH; y++)
|
||||
for (int x = 0; x < imageW; x++) {
|
||||
float sum = 0;
|
||||
extern "C" void convolutionColumnCPU(float *h_Dst, float *h_Src, float *h_Kernel, int imageW, int imageH, int kernelR)
|
||||
{
|
||||
for (int y = 0; y < imageH; y++)
|
||||
for (int x = 0; x < imageW; x++) {
|
||||
float sum = 0;
|
||||
|
||||
for (int k = -kernelR; k <= kernelR; k++) {
|
||||
int d = y + k;
|
||||
for (int k = -kernelR; k <= kernelR; k++) {
|
||||
int d = y + k;
|
||||
|
||||
if (d >= 0 && d < imageH)
|
||||
sum += h_Src[d * imageW + x] * h_Kernel[kernelR - k];
|
||||
}
|
||||
if (d >= 0 && d < imageH)
|
||||
sum += h_Src[d * imageW + x] * h_Kernel[kernelR - k];
|
||||
}
|
||||
|
||||
h_Dst[y * imageW + x] = sum;
|
||||
}
|
||||
h_Dst[y * imageW + x] = sum;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,149 +26,140 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* This sample implements a separable convolution filter
|
||||
* of a 2D image with an arbitrary kernel.
|
||||
*/
|
||||
* This sample implements a separable convolution filter
|
||||
* of a 2D image with an arbitrary kernel.
|
||||
*/
|
||||
|
||||
// CUDA runtime
|
||||
#include <cuda_runtime.h>
|
||||
|
||||
// Utilities and system includes
|
||||
#include <helper_functions.h>
|
||||
#include <helper_cuda.h>
|
||||
#include <helper_functions.h>
|
||||
|
||||
#include "convolutionSeparable_common.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Reference CPU convolution
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
extern "C" void convolutionRowCPU(float *h_Result, float *h_Data,
|
||||
float *h_Kernel, int imageW, int imageH,
|
||||
int kernelR);
|
||||
extern "C" void convolutionRowCPU(float *h_Result, float *h_Data, float *h_Kernel, int imageW, int imageH, int kernelR);
|
||||
|
||||
extern "C" void convolutionColumnCPU(float *h_Result, float *h_Data,
|
||||
float *h_Kernel, int imageW, int imageH,
|
||||
int kernelR);
|
||||
extern "C" void
|
||||
convolutionColumnCPU(float *h_Result, float *h_Data, float *h_Kernel, int imageW, int imageH, int kernelR);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Main program
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int main(int argc, char **argv) {
|
||||
// start logs
|
||||
printf("[%s] - Starting...\n", argv[0]);
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
// start logs
|
||||
printf("[%s] - Starting...\n", argv[0]);
|
||||
|
||||
float *h_Kernel, *h_Input, *h_Buffer, *h_OutputCPU, *h_OutputGPU;
|
||||
float *h_Kernel, *h_Input, *h_Buffer, *h_OutputCPU, *h_OutputGPU;
|
||||
|
||||
float *d_Input, *d_Output, *d_Buffer;
|
||||
float *d_Input, *d_Output, *d_Buffer;
|
||||
|
||||
const int imageW = 3072;
|
||||
const int imageH = 3072;
|
||||
const int iterations = 16;
|
||||
const int imageW = 3072;
|
||||
const int imageH = 3072;
|
||||
const int iterations = 16;
|
||||
|
||||
StopWatchInterface *hTimer = NULL;
|
||||
StopWatchInterface *hTimer = NULL;
|
||||
|
||||
// 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);
|
||||
|
||||
sdkCreateTimer(&hTimer);
|
||||
sdkCreateTimer(&hTimer);
|
||||
|
||||
printf("Image Width x Height = %i x %i\n\n", imageW, imageH);
|
||||
printf("Allocating and initializing host arrays...\n");
|
||||
h_Kernel = (float *)malloc(KERNEL_LENGTH * sizeof(float));
|
||||
h_Input = (float *)malloc(imageW * imageH * sizeof(float));
|
||||
h_Buffer = (float *)malloc(imageW * imageH * sizeof(float));
|
||||
h_OutputCPU = (float *)malloc(imageW * imageH * sizeof(float));
|
||||
h_OutputGPU = (float *)malloc(imageW * imageH * sizeof(float));
|
||||
srand(200);
|
||||
printf("Image Width x Height = %i x %i\n\n", imageW, imageH);
|
||||
printf("Allocating and initializing host arrays...\n");
|
||||
h_Kernel = (float *)malloc(KERNEL_LENGTH * sizeof(float));
|
||||
h_Input = (float *)malloc(imageW * imageH * sizeof(float));
|
||||
h_Buffer = (float *)malloc(imageW * imageH * sizeof(float));
|
||||
h_OutputCPU = (float *)malloc(imageW * imageH * sizeof(float));
|
||||
h_OutputGPU = (float *)malloc(imageW * imageH * sizeof(float));
|
||||
srand(200);
|
||||
|
||||
for (unsigned int i = 0; i < KERNEL_LENGTH; i++) {
|
||||
h_Kernel[i] = (float)(rand() % 16);
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < imageW * imageH; i++) {
|
||||
h_Input[i] = (float)(rand() % 16);
|
||||
}
|
||||
|
||||
printf("Allocating and initializing CUDA arrays...\n");
|
||||
checkCudaErrors(
|
||||
cudaMalloc((void **)&d_Input, imageW * imageH * sizeof(float)));
|
||||
checkCudaErrors(
|
||||
cudaMalloc((void **)&d_Output, imageW * imageH * sizeof(float)));
|
||||
checkCudaErrors(
|
||||
cudaMalloc((void **)&d_Buffer, imageW * imageH * sizeof(float)));
|
||||
|
||||
setConvolutionKernel(h_Kernel);
|
||||
checkCudaErrors(cudaMemcpy(d_Input, h_Input, imageW * imageH * sizeof(float),
|
||||
cudaMemcpyHostToDevice));
|
||||
|
||||
printf("Running GPU convolution (%u identical iterations)...\n\n",
|
||||
iterations);
|
||||
|
||||
for (int i = -1; i < iterations; i++) {
|
||||
// i == -1 -- warmup iteration
|
||||
if (i == 0) {
|
||||
checkCudaErrors(cudaDeviceSynchronize());
|
||||
sdkResetTimer(&hTimer);
|
||||
sdkStartTimer(&hTimer);
|
||||
for (unsigned int i = 0; i < KERNEL_LENGTH; i++) {
|
||||
h_Kernel[i] = (float)(rand() % 16);
|
||||
}
|
||||
|
||||
convolutionRowsGPU(d_Buffer, d_Input, imageW, imageH);
|
||||
for (unsigned i = 0; i < imageW * imageH; i++) {
|
||||
h_Input[i] = (float)(rand() % 16);
|
||||
}
|
||||
|
||||
convolutionColumnsGPU(d_Output, d_Buffer, imageW, imageH);
|
||||
}
|
||||
printf("Allocating and initializing CUDA arrays...\n");
|
||||
checkCudaErrors(cudaMalloc((void **)&d_Input, imageW * imageH * sizeof(float)));
|
||||
checkCudaErrors(cudaMalloc((void **)&d_Output, imageW * imageH * sizeof(float)));
|
||||
checkCudaErrors(cudaMalloc((void **)&d_Buffer, imageW * imageH * sizeof(float)));
|
||||
|
||||
checkCudaErrors(cudaDeviceSynchronize());
|
||||
sdkStopTimer(&hTimer);
|
||||
double gpuTime = 0.001 * sdkGetTimerValue(&hTimer) / (double)iterations;
|
||||
printf(
|
||||
"convolutionSeparable, Throughput = %.4f MPixels/sec, Time = %.5f s, "
|
||||
"Size = %u Pixels, NumDevsUsed = %i, Workgroup = %u\n",
|
||||
(1.0e-6 * (double)(imageW * imageH) / gpuTime), gpuTime,
|
||||
(imageW * imageH), 1, 0);
|
||||
setConvolutionKernel(h_Kernel);
|
||||
checkCudaErrors(cudaMemcpy(d_Input, h_Input, imageW * imageH * sizeof(float), cudaMemcpyHostToDevice));
|
||||
|
||||
printf("\nReading back GPU results...\n\n");
|
||||
checkCudaErrors(cudaMemcpy(h_OutputGPU, d_Output,
|
||||
imageW * imageH * sizeof(float),
|
||||
cudaMemcpyDeviceToHost));
|
||||
printf("Running GPU convolution (%u identical iterations)...\n\n", iterations);
|
||||
|
||||
printf("Checking the results...\n");
|
||||
printf(" ...running convolutionRowCPU()\n");
|
||||
convolutionRowCPU(h_Buffer, h_Input, h_Kernel, imageW, imageH, KERNEL_RADIUS);
|
||||
for (int i = -1; i < iterations; i++) {
|
||||
// i == -1 -- warmup iteration
|
||||
if (i == 0) {
|
||||
checkCudaErrors(cudaDeviceSynchronize());
|
||||
sdkResetTimer(&hTimer);
|
||||
sdkStartTimer(&hTimer);
|
||||
}
|
||||
|
||||
printf(" ...running convolutionColumnCPU()\n");
|
||||
convolutionColumnCPU(h_OutputCPU, h_Buffer, h_Kernel, imageW, imageH,
|
||||
KERNEL_RADIUS);
|
||||
convolutionRowsGPU(d_Buffer, d_Input, imageW, imageH);
|
||||
|
||||
printf(" ...comparing the results\n");
|
||||
double sum = 0, delta = 0;
|
||||
convolutionColumnsGPU(d_Output, d_Buffer, imageW, imageH);
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < imageW * imageH; i++) {
|
||||
delta +=
|
||||
(h_OutputGPU[i] - h_OutputCPU[i]) * (h_OutputGPU[i] - h_OutputCPU[i]);
|
||||
sum += h_OutputCPU[i] * h_OutputCPU[i];
|
||||
}
|
||||
checkCudaErrors(cudaDeviceSynchronize());
|
||||
sdkStopTimer(&hTimer);
|
||||
double gpuTime = 0.001 * sdkGetTimerValue(&hTimer) / (double)iterations;
|
||||
printf("convolutionSeparable, Throughput = %.4f MPixels/sec, Time = %.5f s, "
|
||||
"Size = %u Pixels, NumDevsUsed = %i, Workgroup = %u\n",
|
||||
(1.0e-6 * (double)(imageW * imageH) / gpuTime),
|
||||
gpuTime,
|
||||
(imageW * imageH),
|
||||
1,
|
||||
0);
|
||||
|
||||
double L2norm = sqrt(delta / sum);
|
||||
printf(" ...Relative L2 norm: %E\n\n", L2norm);
|
||||
printf("Shutting down...\n");
|
||||
printf("\nReading back GPU results...\n\n");
|
||||
checkCudaErrors(cudaMemcpy(h_OutputGPU, d_Output, imageW * imageH * sizeof(float), cudaMemcpyDeviceToHost));
|
||||
|
||||
checkCudaErrors(cudaFree(d_Buffer));
|
||||
checkCudaErrors(cudaFree(d_Output));
|
||||
checkCudaErrors(cudaFree(d_Input));
|
||||
free(h_OutputGPU);
|
||||
free(h_OutputCPU);
|
||||
free(h_Buffer);
|
||||
free(h_Input);
|
||||
free(h_Kernel);
|
||||
printf("Checking the results...\n");
|
||||
printf(" ...running convolutionRowCPU()\n");
|
||||
convolutionRowCPU(h_Buffer, h_Input, h_Kernel, imageW, imageH, KERNEL_RADIUS);
|
||||
|
||||
sdkDeleteTimer(&hTimer);
|
||||
printf(" ...running convolutionColumnCPU()\n");
|
||||
convolutionColumnCPU(h_OutputCPU, h_Buffer, h_Kernel, imageW, imageH, KERNEL_RADIUS);
|
||||
|
||||
if (L2norm > 1e-6) {
|
||||
printf("Test failed!\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
printf(" ...comparing the results\n");
|
||||
double sum = 0, delta = 0;
|
||||
|
||||
printf("Test passed\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
for (unsigned i = 0; i < imageW * imageH; i++) {
|
||||
delta += (h_OutputGPU[i] - h_OutputCPU[i]) * (h_OutputGPU[i] - h_OutputCPU[i]);
|
||||
sum += h_OutputCPU[i] * h_OutputCPU[i];
|
||||
}
|
||||
|
||||
double L2norm = sqrt(delta / sum);
|
||||
printf(" ...Relative L2 norm: %E\n\n", L2norm);
|
||||
printf("Shutting down...\n");
|
||||
|
||||
checkCudaErrors(cudaFree(d_Buffer));
|
||||
checkCudaErrors(cudaFree(d_Output));
|
||||
checkCudaErrors(cudaFree(d_Input));
|
||||
free(h_OutputGPU);
|
||||
free(h_OutputCPU);
|
||||
free(h_Buffer);
|
||||
free(h_Input);
|
||||
free(h_Kernel);
|
||||
|
||||
sdkDeleteTimer(&hTimer);
|
||||
|
||||
if (L2norm > 1e-6) {
|
||||
printf("Test failed!\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
printf("Test passed\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
@@ -25,10 +25,10 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <helper_cuda.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <helper_cuda.h>
|
||||
|
||||
#include "convolutionTexture_common.h"
|
||||
|
||||
@@ -52,111 +52,102 @@ inline int iAlignUp(int a, int b) { return (a % b != 0) ? (a - a % b + b) : a; }
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
__constant__ float c_Kernel[KERNEL_LENGTH];
|
||||
|
||||
extern "C" void setConvolutionKernel(float *h_Kernel) {
|
||||
cudaMemcpyToSymbol(c_Kernel, h_Kernel, KERNEL_LENGTH * sizeof(float));
|
||||
extern "C" void setConvolutionKernel(float *h_Kernel)
|
||||
{
|
||||
cudaMemcpyToSymbol(c_Kernel, h_Kernel, KERNEL_LENGTH * sizeof(float));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Loop unrolling templates, needed for best performance
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <int i>
|
||||
__device__ float convolutionRow(float x, float y, cudaTextureObject_t texSrc) {
|
||||
return tex2D<float>(texSrc, x + (float)(KERNEL_RADIUS - i), y) * c_Kernel[i] +
|
||||
convolutionRow<i - 1>(x, y, texSrc);
|
||||
template <int i> __device__ float convolutionRow(float x, float y, cudaTextureObject_t texSrc)
|
||||
{
|
||||
return tex2D<float>(texSrc, x + (float)(KERNEL_RADIUS - i), y) * c_Kernel[i] + convolutionRow<i - 1>(x, y, texSrc);
|
||||
}
|
||||
|
||||
template <>
|
||||
__device__ float convolutionRow<-1>(float x, float y,
|
||||
cudaTextureObject_t texSrc) {
|
||||
return 0;
|
||||
template <> __device__ float convolutionRow<-1>(float x, float y, cudaTextureObject_t texSrc) { return 0; }
|
||||
|
||||
template <int i> __device__ float convolutionColumn(float x, float y, cudaTextureObject_t texSrc)
|
||||
{
|
||||
return tex2D<float>(texSrc, x, y + (float)(KERNEL_RADIUS - i)) * c_Kernel[i]
|
||||
+ convolutionColumn<i - 1>(x, y, texSrc);
|
||||
}
|
||||
|
||||
template <int i>
|
||||
__device__ float convolutionColumn(float x, float y,
|
||||
cudaTextureObject_t texSrc) {
|
||||
return tex2D<float>(texSrc, x, y + (float)(KERNEL_RADIUS - i)) * c_Kernel[i] +
|
||||
convolutionColumn<i - 1>(x, y, texSrc);
|
||||
}
|
||||
|
||||
template <>
|
||||
__device__ float convolutionColumn<-1>(float x, float y,
|
||||
cudaTextureObject_t texSrc) {
|
||||
return 0;
|
||||
}
|
||||
template <> __device__ float convolutionColumn<-1>(float x, float y, cudaTextureObject_t texSrc) { return 0; }
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Row convolution filter
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
__global__ void convolutionRowsKernel(float *d_Dst, int imageW, int imageH,
|
||||
cudaTextureObject_t texSrc) {
|
||||
const int ix = IMAD(blockDim.x, blockIdx.x, threadIdx.x);
|
||||
const int iy = IMAD(blockDim.y, blockIdx.y, threadIdx.y);
|
||||
const float x = (float)ix + 0.5f;
|
||||
const float y = (float)iy + 0.5f;
|
||||
__global__ void convolutionRowsKernel(float *d_Dst, int imageW, int imageH, cudaTextureObject_t texSrc)
|
||||
{
|
||||
const int ix = IMAD(blockDim.x, blockIdx.x, threadIdx.x);
|
||||
const int iy = IMAD(blockDim.y, blockIdx.y, threadIdx.y);
|
||||
const float x = (float)ix + 0.5f;
|
||||
const float y = (float)iy + 0.5f;
|
||||
|
||||
if (ix >= imageW || iy >= imageH) {
|
||||
return;
|
||||
}
|
||||
if (ix >= imageW || iy >= imageH) {
|
||||
return;
|
||||
}
|
||||
|
||||
float sum = 0;
|
||||
float sum = 0;
|
||||
|
||||
#if (UNROLL_INNER)
|
||||
sum = convolutionRow<2 * KERNEL_RADIUS>(x, y, texSrc);
|
||||
sum = convolutionRow<2 * KERNEL_RADIUS>(x, y, texSrc);
|
||||
#else
|
||||
|
||||
for (int k = -KERNEL_RADIUS; k <= KERNEL_RADIUS; k++) {
|
||||
sum += tex2D<float>(texSrc, x + (float)k, y) * c_Kernel[KERNEL_RADIUS - k];
|
||||
}
|
||||
for (int k = -KERNEL_RADIUS; k <= KERNEL_RADIUS; k++) {
|
||||
sum += tex2D<float>(texSrc, x + (float)k, y) * c_Kernel[KERNEL_RADIUS - k];
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
d_Dst[IMAD(iy, imageW, ix)] = sum;
|
||||
d_Dst[IMAD(iy, imageW, ix)] = sum;
|
||||
}
|
||||
|
||||
extern "C" void convolutionRowsGPU(float *d_Dst, cudaArray *a_Src, int imageW,
|
||||
int imageH, cudaTextureObject_t texSrc) {
|
||||
dim3 threads(16, 12);
|
||||
dim3 blocks(iDivUp(imageW, threads.x), iDivUp(imageH, threads.y));
|
||||
extern "C" void convolutionRowsGPU(float *d_Dst, cudaArray *a_Src, int imageW, int imageH, cudaTextureObject_t texSrc)
|
||||
{
|
||||
dim3 threads(16, 12);
|
||||
dim3 blocks(iDivUp(imageW, threads.x), iDivUp(imageH, threads.y));
|
||||
|
||||
convolutionRowsKernel<<<blocks, threads>>>(d_Dst, imageW, imageH, texSrc);
|
||||
getLastCudaError("convolutionRowsKernel() execution failed\n");
|
||||
convolutionRowsKernel<<<blocks, threads>>>(d_Dst, imageW, imageH, texSrc);
|
||||
getLastCudaError("convolutionRowsKernel() execution failed\n");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Column convolution filter
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
__global__ void convolutionColumnsKernel(float *d_Dst, int imageW, int imageH,
|
||||
cudaTextureObject_t texSrc) {
|
||||
const int ix = IMAD(blockDim.x, blockIdx.x, threadIdx.x);
|
||||
const int iy = IMAD(blockDim.y, blockIdx.y, threadIdx.y);
|
||||
const float x = (float)ix + 0.5f;
|
||||
const float y = (float)iy + 0.5f;
|
||||
__global__ void convolutionColumnsKernel(float *d_Dst, int imageW, int imageH, cudaTextureObject_t texSrc)
|
||||
{
|
||||
const int ix = IMAD(blockDim.x, blockIdx.x, threadIdx.x);
|
||||
const int iy = IMAD(blockDim.y, blockIdx.y, threadIdx.y);
|
||||
const float x = (float)ix + 0.5f;
|
||||
const float y = (float)iy + 0.5f;
|
||||
|
||||
if (ix >= imageW || iy >= imageH) {
|
||||
return;
|
||||
}
|
||||
if (ix >= imageW || iy >= imageH) {
|
||||
return;
|
||||
}
|
||||
|
||||
float sum = 0;
|
||||
float sum = 0;
|
||||
|
||||
#if (UNROLL_INNER)
|
||||
sum = convolutionColumn<2 * KERNEL_RADIUS>(x, y, texSrc);
|
||||
sum = convolutionColumn<2 * KERNEL_RADIUS>(x, y, texSrc);
|
||||
#else
|
||||
|
||||
for (int k = -KERNEL_RADIUS; k <= KERNEL_RADIUS; k++) {
|
||||
sum += tex2D<float>(texSrc, x, y + (float)k) * c_Kernel[KERNEL_RADIUS - k];
|
||||
}
|
||||
for (int k = -KERNEL_RADIUS; k <= KERNEL_RADIUS; k++) {
|
||||
sum += tex2D<float>(texSrc, x, y + (float)k) * c_Kernel[KERNEL_RADIUS - k];
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
d_Dst[IMAD(iy, imageW, ix)] = sum;
|
||||
d_Dst[IMAD(iy, imageW, ix)] = sum;
|
||||
}
|
||||
|
||||
extern "C" void convolutionColumnsGPU(float *d_Dst, cudaArray *a_Src,
|
||||
int imageW, int imageH,
|
||||
cudaTextureObject_t texSrc) {
|
||||
dim3 threads(16, 12);
|
||||
dim3 blocks(iDivUp(imageW, threads.x), iDivUp(imageH, threads.y));
|
||||
extern "C" void
|
||||
convolutionColumnsGPU(float *d_Dst, cudaArray *a_Src, int imageW, int imageH, cudaTextureObject_t texSrc)
|
||||
{
|
||||
dim3 threads(16, 12);
|
||||
dim3 blocks(iDivUp(imageW, threads.x), iDivUp(imageH, threads.y));
|
||||
|
||||
convolutionColumnsKernel<<<blocks, threads>>>(d_Dst, imageW, imageH, texSrc);
|
||||
getLastCudaError("convolutionColumnsKernel() execution failed\n");
|
||||
convolutionColumnsKernel<<<blocks, threads>>>(d_Dst, imageW, imageH, texSrc);
|
||||
getLastCudaError("convolutionColumnsKernel() execution failed\n");
|
||||
}
|
||||
|
||||
@@ -39,23 +39,18 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Reference CPU convolution
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
extern "C" void convolutionRowsCPU(float *h_Dst, float *h_Src, float *h_Kernel,
|
||||
int imageW, int imageH, int kernelR);
|
||||
extern "C" void convolutionRowsCPU(float *h_Dst, float *h_Src, float *h_Kernel, int imageW, int imageH, int kernelR);
|
||||
|
||||
extern "C" void convolutionColumnsCPU(float *h_Dst, float *h_Src,
|
||||
float *h_Kernel, int imageW, int imageH,
|
||||
int kernelR);
|
||||
extern "C" void convolutionColumnsCPU(float *h_Dst, float *h_Src, float *h_Kernel, int imageW, int imageH, int kernelR);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// GPU texture-based convolution
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
extern "C" void setConvolutionKernel(float *h_Kernel);
|
||||
|
||||
extern "C" void convolutionRowsGPU(float *d_Dst, cudaArray *a_Src, int imageW,
|
||||
int imageH, cudaTextureObject_t texSrc);
|
||||
extern "C" void convolutionRowsGPU(float *d_Dst, cudaArray *a_Src, int imageW, int imageH, cudaTextureObject_t texSrc);
|
||||
|
||||
extern "C" void convolutionColumnsGPU(float *d_Dst, cudaArray *a_Src,
|
||||
int imageW, int imageH,
|
||||
cudaTextureObject_t texSrc);
|
||||
extern "C" void
|
||||
convolutionColumnsGPU(float *d_Dst, cudaArray *a_Src, int imageW, int imageH, cudaTextureObject_t texSrc);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -30,46 +30,49 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Reference row convolution filter
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
extern "C" void convolutionRowsCPU(float *h_Dst, float *h_Src, float *h_Kernel,
|
||||
int imageW, int imageH, int kernelR) {
|
||||
for (int y = 0; y < imageH; y++)
|
||||
for (int x = 0; x < imageW; x++) {
|
||||
float sum = 0;
|
||||
extern "C" void convolutionRowsCPU(float *h_Dst, float *h_Src, float *h_Kernel, int imageW, int imageH, int kernelR)
|
||||
{
|
||||
for (int y = 0; y < imageH; y++)
|
||||
for (int x = 0; x < imageW; x++) {
|
||||
float sum = 0;
|
||||
|
||||
for (int k = -kernelR; k <= kernelR; k++) {
|
||||
int d = x + k;
|
||||
for (int k = -kernelR; k <= kernelR; k++) {
|
||||
int d = x + k;
|
||||
|
||||
if (d < 0) d = 0;
|
||||
if (d < 0)
|
||||
d = 0;
|
||||
|
||||
if (d >= imageW) d = imageW - 1;
|
||||
if (d >= imageW)
|
||||
d = imageW - 1;
|
||||
|
||||
sum += h_Src[y * imageW + d] * h_Kernel[kernelR - k];
|
||||
}
|
||||
sum += h_Src[y * imageW + d] * h_Kernel[kernelR - k];
|
||||
}
|
||||
|
||||
h_Dst[y * imageW + x] = sum;
|
||||
}
|
||||
h_Dst[y * imageW + x] = sum;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Reference column convolution filter
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
extern "C" void convolutionColumnsCPU(float *h_Dst, float *h_Src,
|
||||
float *h_Kernel, int imageW, int imageH,
|
||||
int kernelR) {
|
||||
for (int y = 0; y < imageH; y++)
|
||||
for (int x = 0; x < imageW; x++) {
|
||||
float sum = 0;
|
||||
extern "C" void convolutionColumnsCPU(float *h_Dst, float *h_Src, float *h_Kernel, int imageW, int imageH, int kernelR)
|
||||
{
|
||||
for (int y = 0; y < imageH; y++)
|
||||
for (int x = 0; x < imageW; x++) {
|
||||
float sum = 0;
|
||||
|
||||
for (int k = -kernelR; k <= kernelR; k++) {
|
||||
int d = y + k;
|
||||
for (int k = -kernelR; k <= kernelR; k++) {
|
||||
int d = y + k;
|
||||
|
||||
if (d < 0) d = 0;
|
||||
if (d < 0)
|
||||
d = 0;
|
||||
|
||||
if (d >= imageH) d = imageH - 1;
|
||||
if (d >= imageH)
|
||||
d = imageH - 1;
|
||||
|
||||
sum += h_Src[d * imageW + x] * h_Kernel[kernelR - k];
|
||||
}
|
||||
sum += h_Src[d * imageW + x] * h_Kernel[kernelR - k];
|
||||
}
|
||||
|
||||
h_Dst[y * imageW + x] = sum;
|
||||
}
|
||||
h_Dst[y * imageW + x] = sum;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,174 +33,165 @@
|
||||
* Refer to the "Performance" section of convolutionSeparable whitepaper.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <cuda_runtime.h>
|
||||
|
||||
#include <helper_functions.h>
|
||||
#include <helper_cuda.h>
|
||||
#include <helper_functions.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "convolutionTexture_common.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Main program
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int main(int argc, char **argv) {
|
||||
float *h_Kernel, *h_Input, *h_Buffer, *h_OutputCPU, *h_OutputGPU;
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
float *h_Kernel, *h_Input, *h_Buffer, *h_OutputCPU, *h_OutputGPU;
|
||||
|
||||
cudaArray *a_Src;
|
||||
cudaTextureObject_t texSrc;
|
||||
cudaChannelFormatDesc floatTex = cudaCreateChannelDesc<float>();
|
||||
cudaArray *a_Src;
|
||||
cudaTextureObject_t texSrc;
|
||||
cudaChannelFormatDesc floatTex = cudaCreateChannelDesc<float>();
|
||||
|
||||
float *d_Output;
|
||||
float *d_Output;
|
||||
|
||||
float gpuTime;
|
||||
float gpuTime;
|
||||
|
||||
StopWatchInterface *hTimer = NULL;
|
||||
StopWatchInterface *hTimer = NULL;
|
||||
|
||||
const int imageW = 3072;
|
||||
const int imageH = 3072 / 2;
|
||||
const unsigned int iterations = 10;
|
||||
const int imageW = 3072;
|
||||
const int imageH = 3072 / 2;
|
||||
const unsigned int iterations = 10;
|
||||
|
||||
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);
|
||||
|
||||
sdkCreateTimer(&hTimer);
|
||||
sdkCreateTimer(&hTimer);
|
||||
|
||||
printf("Initializing data...\n");
|
||||
h_Kernel = (float *)malloc(KERNEL_LENGTH * sizeof(float));
|
||||
h_Input = (float *)malloc(imageW * imageH * sizeof(float));
|
||||
h_Buffer = (float *)malloc(imageW * imageH * sizeof(float));
|
||||
h_OutputCPU = (float *)malloc(imageW * imageH * sizeof(float));
|
||||
h_OutputGPU = (float *)malloc(imageW * imageH * sizeof(float));
|
||||
checkCudaErrors(cudaMallocArray(&a_Src, &floatTex, imageW, imageH));
|
||||
checkCudaErrors(
|
||||
cudaMalloc((void **)&d_Output, imageW * imageH * sizeof(float)));
|
||||
printf("Initializing data...\n");
|
||||
h_Kernel = (float *)malloc(KERNEL_LENGTH * sizeof(float));
|
||||
h_Input = (float *)malloc(imageW * imageH * sizeof(float));
|
||||
h_Buffer = (float *)malloc(imageW * imageH * sizeof(float));
|
||||
h_OutputCPU = (float *)malloc(imageW * imageH * sizeof(float));
|
||||
h_OutputGPU = (float *)malloc(imageW * imageH * sizeof(float));
|
||||
checkCudaErrors(cudaMallocArray(&a_Src, &floatTex, imageW, imageH));
|
||||
checkCudaErrors(cudaMalloc((void **)&d_Output, imageW * imageH * sizeof(float)));
|
||||
|
||||
cudaResourceDesc texRes;
|
||||
memset(&texRes, 0, sizeof(cudaResourceDesc));
|
||||
cudaResourceDesc texRes;
|
||||
memset(&texRes, 0, sizeof(cudaResourceDesc));
|
||||
|
||||
texRes.resType = cudaResourceTypeArray;
|
||||
texRes.res.array.array = a_Src;
|
||||
texRes.resType = cudaResourceTypeArray;
|
||||
texRes.res.array.array = a_Src;
|
||||
|
||||
cudaTextureDesc texDescr;
|
||||
memset(&texDescr, 0, sizeof(cudaTextureDesc));
|
||||
cudaTextureDesc texDescr;
|
||||
memset(&texDescr, 0, sizeof(cudaTextureDesc));
|
||||
|
||||
texDescr.normalizedCoords = false;
|
||||
texDescr.filterMode = cudaFilterModeLinear;
|
||||
texDescr.addressMode[0] = cudaAddressModeWrap;
|
||||
texDescr.addressMode[1] = cudaAddressModeWrap;
|
||||
texDescr.readMode = cudaReadModeElementType;
|
||||
texDescr.normalizedCoords = false;
|
||||
texDescr.filterMode = cudaFilterModeLinear;
|
||||
texDescr.addressMode[0] = cudaAddressModeWrap;
|
||||
texDescr.addressMode[1] = cudaAddressModeWrap;
|
||||
texDescr.readMode = cudaReadModeElementType;
|
||||
|
||||
checkCudaErrors(cudaCreateTextureObject(&texSrc, &texRes, &texDescr, NULL));
|
||||
checkCudaErrors(cudaCreateTextureObject(&texSrc, &texRes, &texDescr, NULL));
|
||||
|
||||
srand(2009);
|
||||
srand(2009);
|
||||
|
||||
for (unsigned int i = 0; i < KERNEL_LENGTH; i++) {
|
||||
h_Kernel[i] = (float)(rand() % 16);
|
||||
}
|
||||
for (unsigned int i = 0; i < KERNEL_LENGTH; i++) {
|
||||
h_Kernel[i] = (float)(rand() % 16);
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < imageW * imageH; i++) {
|
||||
h_Input[i] = (float)(rand() % 16);
|
||||
}
|
||||
for (unsigned int i = 0; i < imageW * imageH; i++) {
|
||||
h_Input[i] = (float)(rand() % 16);
|
||||
}
|
||||
|
||||
setConvolutionKernel(h_Kernel);
|
||||
checkCudaErrors(cudaMemcpyToArray(a_Src, 0, 0, h_Input,
|
||||
imageW * imageH * sizeof(float),
|
||||
cudaMemcpyHostToDevice));
|
||||
setConvolutionKernel(h_Kernel);
|
||||
checkCudaErrors(cudaMemcpyToArray(a_Src, 0, 0, h_Input, imageW * imageH * sizeof(float), cudaMemcpyHostToDevice));
|
||||
|
||||
printf("Running GPU rows convolution (%u identical iterations)...\n",
|
||||
iterations);
|
||||
checkCudaErrors(cudaDeviceSynchronize());
|
||||
sdkResetTimer(&hTimer);
|
||||
sdkStartTimer(&hTimer);
|
||||
printf("Running GPU rows convolution (%u identical iterations)...\n", iterations);
|
||||
checkCudaErrors(cudaDeviceSynchronize());
|
||||
sdkResetTimer(&hTimer);
|
||||
sdkStartTimer(&hTimer);
|
||||
|
||||
for (unsigned int i = 0; i < iterations; i++) {
|
||||
convolutionRowsGPU(d_Output, a_Src, imageW, imageH, texSrc);
|
||||
}
|
||||
for (unsigned int i = 0; i < iterations; i++) {
|
||||
convolutionRowsGPU(d_Output, a_Src, imageW, imageH, texSrc);
|
||||
}
|
||||
|
||||
checkCudaErrors(cudaDeviceSynchronize());
|
||||
sdkStopTimer(&hTimer);
|
||||
gpuTime = sdkGetTimerValue(&hTimer) / (float)iterations;
|
||||
printf("Average convolutionRowsGPU() time: %f msecs; //%f Mpix/s\n", gpuTime,
|
||||
imageW * imageH * 1e-6 / (0.001 * gpuTime));
|
||||
checkCudaErrors(cudaDeviceSynchronize());
|
||||
sdkStopTimer(&hTimer);
|
||||
gpuTime = sdkGetTimerValue(&hTimer) / (float)iterations;
|
||||
printf("Average convolutionRowsGPU() time: %f msecs; //%f Mpix/s\n",
|
||||
gpuTime,
|
||||
imageW * imageH * 1e-6 / (0.001 * gpuTime));
|
||||
|
||||
// While CUDA kernels can't write to textures directly, this copy is
|
||||
// inevitable
|
||||
printf("Copying convolutionRowGPU() output back to the texture...\n");
|
||||
checkCudaErrors(cudaDeviceSynchronize());
|
||||
sdkResetTimer(&hTimer);
|
||||
sdkStartTimer(&hTimer);
|
||||
checkCudaErrors(cudaMemcpyToArray(a_Src, 0, 0, d_Output,
|
||||
imageW * imageH * sizeof(float),
|
||||
cudaMemcpyDeviceToDevice));
|
||||
checkCudaErrors(cudaDeviceSynchronize());
|
||||
sdkStopTimer(&hTimer);
|
||||
gpuTime = sdkGetTimerValue(&hTimer);
|
||||
printf("cudaMemcpyToArray() time: %f msecs; //%f Mpix/s\n", gpuTime,
|
||||
imageW * imageH * 1e-6 / (0.001 * gpuTime));
|
||||
// While CUDA kernels can't write to textures directly, this copy is
|
||||
// inevitable
|
||||
printf("Copying convolutionRowGPU() output back to the texture...\n");
|
||||
checkCudaErrors(cudaDeviceSynchronize());
|
||||
sdkResetTimer(&hTimer);
|
||||
sdkStartTimer(&hTimer);
|
||||
checkCudaErrors(
|
||||
cudaMemcpyToArray(a_Src, 0, 0, d_Output, imageW * imageH * sizeof(float), cudaMemcpyDeviceToDevice));
|
||||
checkCudaErrors(cudaDeviceSynchronize());
|
||||
sdkStopTimer(&hTimer);
|
||||
gpuTime = sdkGetTimerValue(&hTimer);
|
||||
printf("cudaMemcpyToArray() time: %f msecs; //%f Mpix/s\n", gpuTime, imageW * imageH * 1e-6 / (0.001 * gpuTime));
|
||||
|
||||
printf("Running GPU columns convolution (%i iterations)\n", iterations);
|
||||
checkCudaErrors(cudaDeviceSynchronize());
|
||||
sdkResetTimer(&hTimer);
|
||||
sdkStartTimer(&hTimer);
|
||||
printf("Running GPU columns convolution (%i iterations)\n", iterations);
|
||||
checkCudaErrors(cudaDeviceSynchronize());
|
||||
sdkResetTimer(&hTimer);
|
||||
sdkStartTimer(&hTimer);
|
||||
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
convolutionColumnsGPU(d_Output, a_Src, imageW, imageH, texSrc);
|
||||
}
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
convolutionColumnsGPU(d_Output, a_Src, imageW, imageH, texSrc);
|
||||
}
|
||||
|
||||
checkCudaErrors(cudaDeviceSynchronize());
|
||||
sdkStopTimer(&hTimer);
|
||||
gpuTime = sdkGetTimerValue(&hTimer) / (float)iterations;
|
||||
printf("Average convolutionColumnsGPU() time: %f msecs; //%f Mpix/s\n",
|
||||
gpuTime, imageW * imageH * 1e-6 / (0.001 * gpuTime));
|
||||
checkCudaErrors(cudaDeviceSynchronize());
|
||||
sdkStopTimer(&hTimer);
|
||||
gpuTime = sdkGetTimerValue(&hTimer) / (float)iterations;
|
||||
printf("Average convolutionColumnsGPU() time: %f msecs; //%f Mpix/s\n",
|
||||
gpuTime,
|
||||
imageW * imageH * 1e-6 / (0.001 * gpuTime));
|
||||
|
||||
printf("Reading back GPU results...\n");
|
||||
checkCudaErrors(cudaMemcpy(h_OutputGPU, d_Output,
|
||||
imageW * imageH * sizeof(float),
|
||||
cudaMemcpyDeviceToHost));
|
||||
printf("Reading back GPU results...\n");
|
||||
checkCudaErrors(cudaMemcpy(h_OutputGPU, d_Output, imageW * imageH * sizeof(float), cudaMemcpyDeviceToHost));
|
||||
|
||||
printf("Checking the results...\n");
|
||||
printf("...running convolutionRowsCPU()\n");
|
||||
convolutionRowsCPU(h_Buffer, h_Input, h_Kernel, imageW, imageH,
|
||||
KERNEL_RADIUS);
|
||||
printf("Checking the results...\n");
|
||||
printf("...running convolutionRowsCPU()\n");
|
||||
convolutionRowsCPU(h_Buffer, h_Input, h_Kernel, imageW, imageH, KERNEL_RADIUS);
|
||||
|
||||
printf("...running convolutionColumnsCPU()\n");
|
||||
convolutionColumnsCPU(h_OutputCPU, h_Buffer, h_Kernel, imageW, imageH,
|
||||
KERNEL_RADIUS);
|
||||
printf("...running convolutionColumnsCPU()\n");
|
||||
convolutionColumnsCPU(h_OutputCPU, h_Buffer, h_Kernel, imageW, imageH, KERNEL_RADIUS);
|
||||
|
||||
double delta = 0;
|
||||
double sum = 0;
|
||||
double delta = 0;
|
||||
double sum = 0;
|
||||
|
||||
for (unsigned int i = 0; i < imageW * imageH; i++) {
|
||||
sum += h_OutputCPU[i] * h_OutputCPU[i];
|
||||
delta +=
|
||||
(h_OutputGPU[i] - h_OutputCPU[i]) * (h_OutputGPU[i] - h_OutputCPU[i]);
|
||||
}
|
||||
for (unsigned int i = 0; i < imageW * imageH; i++) {
|
||||
sum += h_OutputCPU[i] * h_OutputCPU[i];
|
||||
delta += (h_OutputGPU[i] - h_OutputCPU[i]) * (h_OutputGPU[i] - h_OutputCPU[i]);
|
||||
}
|
||||
|
||||
double L2norm = sqrt(delta / sum);
|
||||
printf("Relative L2 norm: %E\n", L2norm);
|
||||
printf("Shutting down...\n");
|
||||
double L2norm = sqrt(delta / sum);
|
||||
printf("Relative L2 norm: %E\n", L2norm);
|
||||
printf("Shutting down...\n");
|
||||
|
||||
checkCudaErrors(cudaFree(d_Output));
|
||||
checkCudaErrors(cudaFreeArray(a_Src));
|
||||
free(h_OutputGPU);
|
||||
free(h_Buffer);
|
||||
free(h_Input);
|
||||
free(h_Kernel);
|
||||
checkCudaErrors(cudaFree(d_Output));
|
||||
checkCudaErrors(cudaFreeArray(a_Src));
|
||||
free(h_OutputGPU);
|
||||
free(h_Buffer);
|
||||
free(h_Input);
|
||||
free(h_Kernel);
|
||||
|
||||
sdkDeleteTimer(&hTimer);
|
||||
sdkDeleteTimer(&hTimer);
|
||||
|
||||
if (L2norm > 1e-6) {
|
||||
printf("Test failed!\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (L2norm > 1e-6) {
|
||||
printf("Test failed!\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
printf("Test passed\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
printf("Test passed\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
@@ -34,11 +34,12 @@
|
||||
* conversions to different representations and memory management routines.
|
||||
*/
|
||||
|
||||
#include "Common.h"
|
||||
#include "BmpUtil.h"
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
|
||||
#pragma warning(disable : 4996) // disable deprecated warning
|
||||
#pragma warning(disable : 4996) // disable deprecated warning
|
||||
#endif
|
||||
|
||||
/**
|
||||
@@ -59,11 +60,12 @@ int clamp_0_255(int x) { return (x < 0) ? 0 : ((x > 255) ? 255 : x); }
|
||||
*
|
||||
* \return The closest to the input float integer value
|
||||
*/
|
||||
float round_f(float num) {
|
||||
float NumAbs = fabs(num);
|
||||
int NumAbsI = (int)(NumAbs + 0.5f);
|
||||
float sign = num > 0 ? 1.0f : -1.0f;
|
||||
return sign * NumAbsI;
|
||||
float round_f(float num)
|
||||
{
|
||||
float NumAbs = fabs(num);
|
||||
int NumAbsI = (int)(NumAbs + 0.5f);
|
||||
float sign = num > 0 ? 1.0f : -1.0f;
|
||||
return sign * NumAbsI;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -76,15 +78,16 @@ float round_f(float num) {
|
||||
*
|
||||
* \return Pointer to the created plane
|
||||
*/
|
||||
byte *MallocPlaneByte(int width, int height, int *pStepBytes) {
|
||||
byte *ptr;
|
||||
*pStepBytes = ((int)ceil(width / 16.0f)) * 16;
|
||||
//#ifdef __ALLOW_ALIGNED_MEMORY_MANAGEMENT
|
||||
// ptr = (byte *)_aligned_malloc(*pStepBytes * height, 16);
|
||||
//#else
|
||||
ptr = (byte *)malloc(*pStepBytes * height);
|
||||
//#endif
|
||||
return ptr;
|
||||
byte *MallocPlaneByte(int width, int height, int *pStepBytes)
|
||||
{
|
||||
byte *ptr;
|
||||
*pStepBytes = ((int)ceil(width / 16.0f)) * 16;
|
||||
// #ifdef __ALLOW_ALIGNED_MEMORY_MANAGEMENT
|
||||
// ptr = (byte *)_aligned_malloc(*pStepBytes * height, 16);
|
||||
// #else
|
||||
ptr = (byte *)malloc(*pStepBytes * height);
|
||||
// #endif
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -97,16 +100,17 @@ byte *MallocPlaneByte(int width, int height, int *pStepBytes) {
|
||||
*
|
||||
* \return Pointer to the created plane
|
||||
*/
|
||||
short *MallocPlaneShort(int width, int height, int *pStepBytes) {
|
||||
short *ptr;
|
||||
*pStepBytes = ((int)ceil((width * sizeof(short)) / 16.0f)) * 16;
|
||||
//#ifdef __ALLOW_ALIGNED_MEMORY_MANAGEMENT
|
||||
// ptr = (float *)_aligned_malloc(*pStepBytes * height, 16);
|
||||
//#else
|
||||
ptr = (short *)malloc(*pStepBytes * height);
|
||||
//#endif
|
||||
*pStepBytes = *pStepBytes / sizeof(short);
|
||||
return ptr;
|
||||
short *MallocPlaneShort(int width, int height, int *pStepBytes)
|
||||
{
|
||||
short *ptr;
|
||||
*pStepBytes = ((int)ceil((width * sizeof(short)) / 16.0f)) * 16;
|
||||
// #ifdef __ALLOW_ALIGNED_MEMORY_MANAGEMENT
|
||||
// ptr = (float *)_aligned_malloc(*pStepBytes * height, 16);
|
||||
// #else
|
||||
ptr = (short *)malloc(*pStepBytes * height);
|
||||
// #endif
|
||||
*pStepBytes = *pStepBytes / sizeof(short);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -119,16 +123,17 @@ short *MallocPlaneShort(int width, int height, int *pStepBytes) {
|
||||
*
|
||||
* \return Pointer to the created plane
|
||||
*/
|
||||
float *MallocPlaneFloat(int width, int height, int *pStepBytes) {
|
||||
float *ptr;
|
||||
*pStepBytes = ((int)ceil((width * sizeof(float)) / 16.0f)) * 16;
|
||||
//#ifdef __ALLOW_ALIGNED_MEMORY_MANAGEMENT
|
||||
// ptr = (float *)_aligned_malloc(*pStepBytes * height, 16);
|
||||
//#else
|
||||
ptr = (float *)malloc(*pStepBytes * height);
|
||||
//#endif
|
||||
*pStepBytes = *pStepBytes / sizeof(float);
|
||||
return ptr;
|
||||
float *MallocPlaneFloat(int width, int height, int *pStepBytes)
|
||||
{
|
||||
float *ptr;
|
||||
*pStepBytes = ((int)ceil((width * sizeof(float)) / 16.0f)) * 16;
|
||||
// #ifdef __ALLOW_ALIGNED_MEMORY_MANAGEMENT
|
||||
// ptr = (float *)_aligned_malloc(*pStepBytes * height, 16);
|
||||
// #else
|
||||
ptr = (float *)malloc(*pStepBytes * height);
|
||||
// #endif
|
||||
*pStepBytes = *pStepBytes / sizeof(float);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -143,13 +148,13 @@ float *MallocPlaneFloat(int width, int height, int *pStepBytes) {
|
||||
*
|
||||
* \return None
|
||||
*/
|
||||
void CopyByte2Float(byte *ImgSrc, int StrideB, float *ImgDst, int StrideF,
|
||||
ROI Size) {
|
||||
for (int i = 0; i < Size.height; i++) {
|
||||
for (int j = 0; j < Size.width; j++) {
|
||||
ImgDst[i * StrideF + j] = (float)ImgSrc[i * StrideB + j];
|
||||
void CopyByte2Float(byte *ImgSrc, int StrideB, float *ImgDst, int StrideF, ROI Size)
|
||||
{
|
||||
for (int i = 0; i < Size.height; i++) {
|
||||
for (int j = 0; j < Size.width; j++) {
|
||||
ImgDst[i * StrideF + j] = (float)ImgSrc[i * StrideB + j];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -164,14 +169,13 @@ void CopyByte2Float(byte *ImgSrc, int StrideB, float *ImgDst, int StrideF,
|
||||
*
|
||||
* \return None
|
||||
*/
|
||||
void CopyFloat2Byte(float *ImgSrc, int StrideF, byte *ImgDst, int StrideB,
|
||||
ROI Size) {
|
||||
for (int i = 0; i < Size.height; i++) {
|
||||
for (int j = 0; j < Size.width; j++) {
|
||||
ImgDst[i * StrideB + j] =
|
||||
(byte)clamp_0_255((int)(round_f(ImgSrc[i * StrideF + j])));
|
||||
void CopyFloat2Byte(float *ImgSrc, int StrideF, byte *ImgDst, int StrideB, ROI Size)
|
||||
{
|
||||
for (int i = 0; i < Size.height; i++) {
|
||||
for (int j = 0; j < Size.width; j++) {
|
||||
ImgDst[i * StrideB + j] = (byte)clamp_0_255((int)(round_f(ImgSrc[i * StrideF + j])));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -182,18 +186,19 @@ void CopyFloat2Byte(float *ImgSrc, int StrideF, byte *ImgDst, int StrideB,
|
||||
*
|
||||
* \return None
|
||||
*/
|
||||
void FreePlane(void *ptr) {
|
||||
//#ifdef __ALLOW_ALIGNED_MEMORY_MANAGEMENT
|
||||
// if (ptr)
|
||||
// {
|
||||
// _aligned_free(ptr);
|
||||
// }
|
||||
//#else
|
||||
if (ptr) {
|
||||
free(ptr);
|
||||
}
|
||||
void FreePlane(void *ptr)
|
||||
{
|
||||
// #ifdef __ALLOW_ALIGNED_MEMORY_MANAGEMENT
|
||||
// if (ptr)
|
||||
// {
|
||||
// _aligned_free(ptr);
|
||||
// }
|
||||
// #else
|
||||
if (ptr) {
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
//#endif
|
||||
// #endif
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -207,12 +212,13 @@ void FreePlane(void *ptr) {
|
||||
*
|
||||
* \return None
|
||||
*/
|
||||
void AddFloatPlane(float Value, float *ImgSrcDst, int StrideF, ROI Size) {
|
||||
for (int i = 0; i < Size.height; i++) {
|
||||
for (int j = 0; j < Size.width; j++) {
|
||||
ImgSrcDst[i * StrideF + j] += Value;
|
||||
void AddFloatPlane(float Value, float *ImgSrcDst, int StrideF, ROI Size)
|
||||
{
|
||||
for (int i = 0; i < Size.height; i++) {
|
||||
for (int j = 0; j < Size.width; j++) {
|
||||
ImgSrcDst[i * StrideF + j] += Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -226,12 +232,13 @@ void AddFloatPlane(float Value, float *ImgSrcDst, int StrideF, ROI Size) {
|
||||
*
|
||||
* \return None
|
||||
*/
|
||||
void MulFloatPlane(float Value, float *ImgSrcDst, int StrideF, ROI Size) {
|
||||
for (int i = 0; i < Size.height; i++) {
|
||||
for (int j = 0; j < Size.width; j++) {
|
||||
ImgSrcDst[i * StrideF + j] *= Value;
|
||||
void MulFloatPlane(float Value, float *ImgSrcDst, int StrideF, ROI Size)
|
||||
{
|
||||
for (int i = 0; i < Size.height; i++) {
|
||||
for (int j = 0; j < Size.width; j++) {
|
||||
ImgSrcDst[i * StrideF + j] *= Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -244,36 +251,37 @@ void MulFloatPlane(float Value, float *ImgSrcDst, int StrideF, ROI Size) {
|
||||
*
|
||||
* \return Status code
|
||||
*/
|
||||
int PreLoadBmp(char *FileName, int *Width, int *Height) {
|
||||
BMPFileHeader FileHeader;
|
||||
BMPInfoHeader InfoHeader;
|
||||
FILE *fh;
|
||||
int PreLoadBmp(char *FileName, int *Width, int *Height)
|
||||
{
|
||||
BMPFileHeader FileHeader;
|
||||
BMPInfoHeader InfoHeader;
|
||||
FILE *fh;
|
||||
|
||||
if (!(fh = fopen(FileName, "rb"))) {
|
||||
return 1; // invalid filename
|
||||
}
|
||||
if (!(fh = fopen(FileName, "rb"))) {
|
||||
return 1; // invalid filename
|
||||
}
|
||||
|
||||
fread(&FileHeader, sizeof(BMPFileHeader), 1, fh);
|
||||
fread(&FileHeader, sizeof(BMPFileHeader), 1, fh);
|
||||
|
||||
if (FileHeader._bm_signature != 0x4D42) {
|
||||
return 2; // invalid file format
|
||||
}
|
||||
if (FileHeader._bm_signature != 0x4D42) {
|
||||
return 2; // invalid file format
|
||||
}
|
||||
|
||||
fread(&InfoHeader, sizeof(BMPInfoHeader), 1, fh);
|
||||
fread(&InfoHeader, sizeof(BMPInfoHeader), 1, fh);
|
||||
|
||||
if (InfoHeader._bm_color_depth != 24) {
|
||||
return 3; // invalid color depth
|
||||
}
|
||||
if (InfoHeader._bm_color_depth != 24) {
|
||||
return 3; // invalid color depth
|
||||
}
|
||||
|
||||
if (InfoHeader._bm_compressed) {
|
||||
return 4; // invalid compression property
|
||||
}
|
||||
if (InfoHeader._bm_compressed) {
|
||||
return 4; // invalid compression property
|
||||
}
|
||||
|
||||
*Width = InfoHeader._bm_image_width;
|
||||
*Height = InfoHeader._bm_image_height;
|
||||
*Width = InfoHeader._bm_image_width;
|
||||
*Height = InfoHeader._bm_image_height;
|
||||
|
||||
fclose(fh);
|
||||
return 0;
|
||||
fclose(fh);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -287,28 +295,29 @@ int PreLoadBmp(char *FileName, int *Width, int *Height) {
|
||||
*
|
||||
* \return None
|
||||
*/
|
||||
void LoadBmpAsGray(char *FileName, int Stride, ROI ImSize, byte *Img) {
|
||||
BMPFileHeader FileHeader;
|
||||
BMPInfoHeader InfoHeader;
|
||||
FILE *fh;
|
||||
fh = fopen(FileName, "rb");
|
||||
void LoadBmpAsGray(char *FileName, int Stride, ROI ImSize, byte *Img)
|
||||
{
|
||||
BMPFileHeader FileHeader;
|
||||
BMPInfoHeader InfoHeader;
|
||||
FILE *fh;
|
||||
fh = fopen(FileName, "rb");
|
||||
|
||||
fread(&FileHeader, sizeof(BMPFileHeader), 1, fh);
|
||||
fread(&InfoHeader, sizeof(BMPInfoHeader), 1, fh);
|
||||
fread(&FileHeader, sizeof(BMPFileHeader), 1, fh);
|
||||
fread(&InfoHeader, sizeof(BMPInfoHeader), 1, fh);
|
||||
|
||||
for (int i = ImSize.height - 1; i >= 0; i--) {
|
||||
for (int j = 0; j < ImSize.width; j++) {
|
||||
int r = 0, g = 0, b = 0;
|
||||
fread(&b, 1, 1, fh);
|
||||
fread(&g, 1, 1, fh);
|
||||
fread(&r, 1, 1, fh);
|
||||
int val = (313524 * r + 615514 * g + 119537 * b + 524288) >> 20;
|
||||
Img[i * Stride + j] = (byte)clamp_0_255(val);
|
||||
for (int i = ImSize.height - 1; i >= 0; i--) {
|
||||
for (int j = 0; j < ImSize.width; j++) {
|
||||
int r = 0, g = 0, b = 0;
|
||||
fread(&b, 1, 1, fh);
|
||||
fread(&g, 1, 1, fh);
|
||||
fread(&r, 1, 1, fh);
|
||||
int val = (313524 * r + 615514 * g + 119537 * b + 524288) >> 20;
|
||||
Img[i * Stride + j] = (byte)clamp_0_255(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fh);
|
||||
return;
|
||||
fclose(fh);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -322,46 +331,47 @@ void LoadBmpAsGray(char *FileName, int Stride, ROI ImSize, byte *Img) {
|
||||
*
|
||||
* \return None
|
||||
*/
|
||||
void DumpBmpAsGray(char *FileName, byte *Img, int Stride, ROI ImSize) {
|
||||
FILE *fp = NULL;
|
||||
fp = fopen(FileName, "wb");
|
||||
void DumpBmpAsGray(char *FileName, byte *Img, int Stride, ROI ImSize)
|
||||
{
|
||||
FILE *fp = NULL;
|
||||
fp = fopen(FileName, "wb");
|
||||
|
||||
if (fp == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
BMPFileHeader FileHeader;
|
||||
BMPInfoHeader InfoHeader;
|
||||
|
||||
// init headers
|
||||
FileHeader._bm_signature = 0x4D42;
|
||||
FileHeader._bm_file_size = 54 + 3 * ImSize.width * ImSize.height;
|
||||
FileHeader._bm_reserved = 0;
|
||||
FileHeader._bm_bitmap_data = 0x36;
|
||||
InfoHeader._bm_bitmap_size = 0;
|
||||
InfoHeader._bm_color_depth = 24;
|
||||
InfoHeader._bm_compressed = 0;
|
||||
InfoHeader._bm_hor_resolution = 0;
|
||||
InfoHeader._bm_image_height = ImSize.height;
|
||||
InfoHeader._bm_image_width = ImSize.width;
|
||||
InfoHeader._bm_info_header_size = 40;
|
||||
InfoHeader._bm_num_colors_used = 0;
|
||||
InfoHeader._bm_num_important_colors = 0;
|
||||
InfoHeader._bm_num_of_planes = 1;
|
||||
InfoHeader._bm_ver_resolution = 0;
|
||||
|
||||
fwrite(&FileHeader, sizeof(BMPFileHeader), 1, fp);
|
||||
fwrite(&InfoHeader, sizeof(BMPInfoHeader), 1, fp);
|
||||
|
||||
for (int i = ImSize.height - 1; i >= 0; i--) {
|
||||
for (int j = 0; j < ImSize.width; j++) {
|
||||
fwrite(&(Img[i * Stride + j]), 1, 1, fp);
|
||||
fwrite(&(Img[i * Stride + j]), 1, 1, fp);
|
||||
fwrite(&(Img[i * Stride + j]), 1, 1, fp);
|
||||
if (fp == NULL) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
BMPFileHeader FileHeader;
|
||||
BMPInfoHeader InfoHeader;
|
||||
|
||||
// init headers
|
||||
FileHeader._bm_signature = 0x4D42;
|
||||
FileHeader._bm_file_size = 54 + 3 * ImSize.width * ImSize.height;
|
||||
FileHeader._bm_reserved = 0;
|
||||
FileHeader._bm_bitmap_data = 0x36;
|
||||
InfoHeader._bm_bitmap_size = 0;
|
||||
InfoHeader._bm_color_depth = 24;
|
||||
InfoHeader._bm_compressed = 0;
|
||||
InfoHeader._bm_hor_resolution = 0;
|
||||
InfoHeader._bm_image_height = ImSize.height;
|
||||
InfoHeader._bm_image_width = ImSize.width;
|
||||
InfoHeader._bm_info_header_size = 40;
|
||||
InfoHeader._bm_num_colors_used = 0;
|
||||
InfoHeader._bm_num_important_colors = 0;
|
||||
InfoHeader._bm_num_of_planes = 1;
|
||||
InfoHeader._bm_ver_resolution = 0;
|
||||
|
||||
fwrite(&FileHeader, sizeof(BMPFileHeader), 1, fp);
|
||||
fwrite(&InfoHeader, sizeof(BMPInfoHeader), 1, fp);
|
||||
|
||||
for (int i = ImSize.height - 1; i >= 0; i--) {
|
||||
for (int j = 0; j < ImSize.width; j++) {
|
||||
fwrite(&(Img[i * Stride + j]), 1, 1, fp);
|
||||
fwrite(&(Img[i * Stride + j]), 1, 1, fp);
|
||||
fwrite(&(Img[i * Stride + j]), 1, 1, fp);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -374,18 +384,19 @@ void DumpBmpAsGray(char *FileName, byte *Img, int Stride, ROI ImSize) {
|
||||
*
|
||||
* \return None
|
||||
*/
|
||||
void DumpBlockF(float *PlaneF, int StrideF, char *Fname) {
|
||||
FILE *fp = fopen(Fname, "wb");
|
||||
void DumpBlockF(float *PlaneF, int StrideF, char *Fname)
|
||||
{
|
||||
FILE *fp = fopen(Fname, "wb");
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
for (int j = 0; j < 8; j++) {
|
||||
fprintf(fp, "%.*f ", 14, PlaneF[i * StrideF + j]);
|
||||
for (int i = 0; i < 8; i++) {
|
||||
for (int j = 0; j < 8; j++) {
|
||||
fprintf(fp, "%.*f ", 14, PlaneF[i * StrideF + j]);
|
||||
}
|
||||
|
||||
fprintf(fp, "\n");
|
||||
}
|
||||
|
||||
fprintf(fp, "\n");
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -398,18 +409,19 @@ void DumpBlockF(float *PlaneF, int StrideF, char *Fname) {
|
||||
*
|
||||
* \return None
|
||||
*/
|
||||
void DumpBlock(byte *Plane, int Stride, char *Fname) {
|
||||
FILE *fp = fopen(Fname, "wb");
|
||||
void DumpBlock(byte *Plane, int Stride, char *Fname)
|
||||
{
|
||||
FILE *fp = fopen(Fname, "wb");
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
for (int j = 0; j < 8; j++) {
|
||||
fprintf(fp, "%.3d ", Plane[i * Stride + j]);
|
||||
for (int i = 0; i < 8; i++) {
|
||||
for (int j = 0; j < 8; j++) {
|
||||
fprintf(fp, "%.3d ", Plane[i * Stride + j]);
|
||||
}
|
||||
|
||||
fprintf(fp, "\n");
|
||||
}
|
||||
|
||||
fprintf(fp, "\n");
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -423,18 +435,19 @@ void DumpBlock(byte *Plane, int Stride, char *Fname) {
|
||||
*
|
||||
* \return Mean Square Error between images
|
||||
*/
|
||||
float CalculateMSE(byte *Img1, byte *Img2, int Stride, ROI Size) {
|
||||
uint32 Acc = 0;
|
||||
float CalculateMSE(byte *Img1, byte *Img2, int Stride, ROI Size)
|
||||
{
|
||||
uint32 Acc = 0;
|
||||
|
||||
for (int i = 0; i < Size.height; i++) {
|
||||
for (int j = 0; j < Size.width; j++) {
|
||||
int TmpDiff = Img1[i * Stride + j] - Img2[i * Stride + j];
|
||||
TmpDiff *= TmpDiff;
|
||||
Acc += TmpDiff;
|
||||
for (int i = 0; i < Size.height; i++) {
|
||||
for (int j = 0; j < Size.width; j++) {
|
||||
int TmpDiff = Img1[i * Stride + j] - Img2[i * Stride + j];
|
||||
TmpDiff *= TmpDiff;
|
||||
Acc += TmpDiff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ((float)Acc) / (Size.height * Size.width);
|
||||
return ((float)Acc) / (Size.height * Size.width);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -449,7 +462,8 @@ float CalculateMSE(byte *Img1, byte *Img2, int Stride, ROI Size) {
|
||||
*
|
||||
* \return Peak Signal to Noise Ratio between images
|
||||
*/
|
||||
float CalculatePSNR(byte *Img1, byte *Img2, int Stride, ROI Size) {
|
||||
float MSE = CalculateMSE(Img1, Img2, Stride, Size);
|
||||
return 10 * log10(255 * 255 / MSE);
|
||||
float CalculatePSNR(byte *Img1, byte *Img2, int Stride, ROI Size)
|
||||
{
|
||||
float MSE = CalculateMSE(Img1, Img2, Stride, Size);
|
||||
return 10 * log10(255 * 255 / MSE);
|
||||
}
|
||||
|
||||
@@ -42,43 +42,45 @@
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
typedef char int8;
|
||||
typedef short int16;
|
||||
typedef int int32;
|
||||
typedef unsigned char uint8;
|
||||
typedef char int8;
|
||||
typedef short int16;
|
||||
typedef int int32;
|
||||
typedef unsigned char uint8;
|
||||
typedef unsigned short uint16;
|
||||
typedef unsigned int uint32;
|
||||
typedef unsigned int uint32;
|
||||
|
||||
/**
|
||||
* \brief Bitmap file header structure
|
||||
*
|
||||
* Bitmap file header structure
|
||||
*/
|
||||
typedef struct {
|
||||
uint16 _bm_signature; //!< File signature, must be "BM"
|
||||
uint32 _bm_file_size; //!< File size
|
||||
uint32 _bm_reserved; //!< Reserved, must be zero
|
||||
uint32 _bm_bitmap_data; //!< Bitmap data
|
||||
* \brief Bitmap file header structure
|
||||
*
|
||||
* Bitmap file header structure
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint16 _bm_signature; //!< File signature, must be "BM"
|
||||
uint32 _bm_file_size; //!< File size
|
||||
uint32 _bm_reserved; //!< Reserved, must be zero
|
||||
uint32 _bm_bitmap_data; //!< Bitmap data
|
||||
} BMPFileHeader;
|
||||
|
||||
/**
|
||||
* \brief Bitmap info header structure
|
||||
*
|
||||
* Bitmap info header structure
|
||||
*/
|
||||
typedef struct {
|
||||
uint32 _bm_info_header_size; //!< Info header size, must be 40
|
||||
uint32 _bm_image_width; //!< Image width
|
||||
uint32 _bm_image_height; //!< Image height
|
||||
uint16 _bm_num_of_planes; //!< Amount of image planes, must be 1
|
||||
uint16 _bm_color_depth; //!< Color depth
|
||||
uint32 _bm_compressed; //!< Image compression, must be none
|
||||
uint32 _bm_bitmap_size; //!< Size of bitmap data
|
||||
uint32 _bm_hor_resolution; //!< Horizontal resolution, assumed to be 0
|
||||
uint32 _bm_ver_resolution; //!< Vertical resolution, assumed to be 0
|
||||
uint32 _bm_num_colors_used; //!< Number of colors used, assumed to be 0
|
||||
uint32 _bm_num_important_colors; //!< Number of important colors, assumed to
|
||||
//!be 0
|
||||
* \brief Bitmap info header structure
|
||||
*
|
||||
* Bitmap info header structure
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint32 _bm_info_header_size; //!< Info header size, must be 40
|
||||
uint32 _bm_image_width; //!< Image width
|
||||
uint32 _bm_image_height; //!< Image height
|
||||
uint16 _bm_num_of_planes; //!< Amount of image planes, must be 1
|
||||
uint16 _bm_color_depth; //!< Color depth
|
||||
uint32 _bm_compressed; //!< Image compression, must be none
|
||||
uint32 _bm_bitmap_size; //!< Size of bitmap data
|
||||
uint32 _bm_hor_resolution; //!< Horizontal resolution, assumed to be 0
|
||||
uint32 _bm_ver_resolution; //!< Vertical resolution, assumed to be 0
|
||||
uint32 _bm_num_colors_used; //!< Number of colors used, assumed to be 0
|
||||
uint32 _bm_num_important_colors; //!< Number of important colors, assumed to
|
||||
//! be 0
|
||||
} BMPInfoHeader;
|
||||
|
||||
#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
|
||||
@@ -88,38 +90,38 @@ typedef struct {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief Simple 2D size / region_of_interest structure
|
||||
*
|
||||
* Simple 2D size / region_of_interest structure
|
||||
*/
|
||||
typedef struct {
|
||||
int width; //!< ROI width
|
||||
int height; //!< ROI height
|
||||
* \brief Simple 2D size / region_of_interest structure
|
||||
*
|
||||
* Simple 2D size / region_of_interest structure
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
int width; //!< ROI width
|
||||
int height; //!< ROI height
|
||||
} ROI;
|
||||
|
||||
/**
|
||||
* One-byte unsigned integer type
|
||||
*/
|
||||
* One-byte unsigned integer type
|
||||
*/
|
||||
typedef unsigned char byte;
|
||||
|
||||
extern "C" {
|
||||
int clamp_0_255(int x);
|
||||
float round_f(float num);
|
||||
byte *MallocPlaneByte(int width, int height, int *pStepBytes);
|
||||
short *MallocPlaneShort(int width, int height, int *pStepBytes);
|
||||
float *MallocPlaneFloat(int width, int height, int *pStepBytes);
|
||||
void CopyByte2Float(byte *ImgSrc, int StrideB, float *ImgDst, int StrideF,
|
||||
ROI Size);
|
||||
void CopyFloat2Byte(float *ImgSrc, int StrideF, byte *ImgDst, int StrideB,
|
||||
ROI Size);
|
||||
void FreePlane(void *ptr);
|
||||
void AddFloatPlane(float Value, float *ImgSrcDst, int StrideF, ROI Size);
|
||||
void MulFloatPlane(float Value, float *ImgSrcDst, int StrideF, ROI Size);
|
||||
int PreLoadBmp(char *FileName, int *Width, int *Height);
|
||||
void LoadBmpAsGray(char *FileName, int Stride, ROI ImSize, byte *Img);
|
||||
void DumpBmpAsGray(char *FileName, byte *Img, int Stride, ROI ImSize);
|
||||
void DumpBlockF(float *PlaneF, int StrideF, char *Fname);
|
||||
void DumpBlock(byte *Plane, int Stride, char *Fname);
|
||||
float CalculateMSE(byte *Img1, byte *Img2, int Stride, ROI Size);
|
||||
float CalculatePSNR(byte *Img1, byte *Img2, int Stride, ROI Size);
|
||||
extern "C"
|
||||
{
|
||||
int clamp_0_255(int x);
|
||||
float round_f(float num);
|
||||
byte *MallocPlaneByte(int width, int height, int *pStepBytes);
|
||||
short *MallocPlaneShort(int width, int height, int *pStepBytes);
|
||||
float *MallocPlaneFloat(int width, int height, int *pStepBytes);
|
||||
void CopyByte2Float(byte *ImgSrc, int StrideB, float *ImgDst, int StrideF, ROI Size);
|
||||
void CopyFloat2Byte(float *ImgSrc, int StrideF, byte *ImgDst, int StrideB, ROI Size);
|
||||
void FreePlane(void *ptr);
|
||||
void AddFloatPlane(float Value, float *ImgSrcDst, int StrideF, ROI Size);
|
||||
void MulFloatPlane(float Value, float *ImgSrcDst, int StrideF, ROI Size);
|
||||
int PreLoadBmp(char *FileName, int *Width, int *Height);
|
||||
void LoadBmpAsGray(char *FileName, int Stride, ROI ImSize, byte *Img);
|
||||
void DumpBmpAsGray(char *FileName, byte *Img, int Stride, ROI ImSize);
|
||||
void DumpBlockF(float *PlaneF, int StrideF, char *Fname);
|
||||
void DumpBlock(byte *Plane, int Stride, char *Fname);
|
||||
float CalculateMSE(byte *Img1, byte *Img2, int Stride, ROI Size);
|
||||
float CalculatePSNR(byte *Img1, byte *Img2, int Stride, ROI Size);
|
||||
}
|
||||
|
||||
@@ -35,47 +35,46 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cuda_runtime.h>
|
||||
#include <helper_cuda.h> // helper functions for CUDA timing and initialization
|
||||
#include <helper_functions.h> // helper functions for timing, string parsing
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <cuda_runtime.h>
|
||||
#include <helper_cuda.h> // helper functions for CUDA timing and initialization
|
||||
#include <helper_functions.h> // helper functions for timing, string parsing
|
||||
|
||||
/**
|
||||
* The dimension of pixels block
|
||||
*/
|
||||
* The dimension of pixels block
|
||||
*/
|
||||
#define BLOCK_SIZE 8
|
||||
|
||||
/**
|
||||
* Square of dimension of pixels block
|
||||
*/
|
||||
* Square of dimension of pixels block
|
||||
*/
|
||||
#define BLOCK_SIZE2 64
|
||||
|
||||
/**
|
||||
* log_2{BLOCK_SIZE), used for quick multiplication or division by the
|
||||
* pixels block dimension via shifting
|
||||
*/
|
||||
* log_2{BLOCK_SIZE), used for quick multiplication or division by the
|
||||
* pixels block dimension via shifting
|
||||
*/
|
||||
#define BLOCK_SIZE_LOG2 3
|
||||
|
||||
/**
|
||||
* log_2{BLOCK_SIZE*BLOCK_SIZE), used for quick multiplication or division by
|
||||
* the
|
||||
* square of pixels block via shifting
|
||||
*/
|
||||
* log_2{BLOCK_SIZE*BLOCK_SIZE), used for quick multiplication or division by
|
||||
* the
|
||||
* square of pixels block via shifting
|
||||
*/
|
||||
#define BLOCK_SIZE2_LOG2 6
|
||||
|
||||
/**
|
||||
* This macro states that __mul24 operation is performed faster that traditional
|
||||
* multiplication for two integers on CUDA. Please undefine if it appears to be
|
||||
* wrong on your system
|
||||
*/
|
||||
* This macro states that __mul24 operation is performed faster that traditional
|
||||
* multiplication for two integers on CUDA. Please undefine if it appears to be
|
||||
* wrong on your system
|
||||
*/
|
||||
#define __MUL24_FASTER_THAN_ASTERIX
|
||||
|
||||
/**
|
||||
* Wrapper to the fastest integer multiplication function on CUDA
|
||||
*/
|
||||
* Wrapper to the fastest integer multiplication function on CUDA
|
||||
*/
|
||||
#ifdef __MUL24_FASTER_THAN_ASTERIX
|
||||
#define FMUL(x, y) (__mul24(x, y))
|
||||
#else
|
||||
@@ -83,6 +82,6 @@
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This macro allows using aligned memory management
|
||||
*/
|
||||
//#define __ALLOW_ALIGNED_MEMORY_MANAGEMENT
|
||||
* This macro allows using aligned memory management
|
||||
*/
|
||||
// #define __ALLOW_ALIGNED_MEMORY_MANAGEMENT
|
||||
|
||||
@@ -38,47 +38,53 @@
|
||||
* The routine that performs quantization of coefficients is also included.
|
||||
*/
|
||||
|
||||
#include "Common.h"
|
||||
#include "BmpUtil.h"
|
||||
#include "Common.h"
|
||||
|
||||
/**
|
||||
* This unitary matrix performs DCT of rows of the matrix to the left
|
||||
*/
|
||||
const float DCTv8matrix[BLOCK_SIZE2] = {
|
||||
0.3535533905932738f, 0.4903926402016152f, 0.4619397662556434f, 0.4157348061512726f, 0.3535533905932738f, 0.2777851165098011f, 0.1913417161825449f, 0.0975451610080642f,
|
||||
0.3535533905932738f, 0.4157348061512726f, 0.1913417161825449f, -0.0975451610080641f, -0.3535533905932737f, -0.4903926402016152f, -0.4619397662556434f, -0.2777851165098011f,
|
||||
0.3535533905932738f, 0.2777851165098011f, -0.1913417161825449f, -0.4903926402016152f, -0.3535533905932738f, 0.0975451610080642f, 0.4619397662556433f, 0.4157348061512727f,
|
||||
0.3535533905932738f, 0.0975451610080642f, -0.4619397662556434f, -0.2777851165098011f, 0.3535533905932737f, 0.4157348061512727f, -0.1913417161825450f, -0.4903926402016153f,
|
||||
0.3535533905932738f, -0.0975451610080641f, -0.4619397662556434f, 0.2777851165098009f, 0.3535533905932738f, -0.4157348061512726f, -0.1913417161825453f, 0.4903926402016152f,
|
||||
0.3535533905932738f, -0.2777851165098010f, -0.1913417161825452f, 0.4903926402016153f, -0.3535533905932733f, -0.0975451610080649f, 0.4619397662556437f, -0.4157348061512720f,
|
||||
0.3535533905932738f, -0.4157348061512727f, 0.1913417161825450f, 0.0975451610080640f, -0.3535533905932736f, 0.4903926402016152f, -0.4619397662556435f, 0.2777851165098022f,
|
||||
0.3535533905932738f, -0.4903926402016152f, 0.4619397662556433f, -0.4157348061512721f, 0.3535533905932733f, -0.2777851165098008f, 0.1913417161825431f, -0.0975451610080625f};
|
||||
0.3535533905932738f, 0.4903926402016152f, 0.4619397662556434f, 0.4157348061512726f, 0.3535533905932738f,
|
||||
0.2777851165098011f, 0.1913417161825449f, 0.0975451610080642f, 0.3535533905932738f, 0.4157348061512726f,
|
||||
0.1913417161825449f, -0.0975451610080641f, -0.3535533905932737f, -0.4903926402016152f, -0.4619397662556434f,
|
||||
-0.2777851165098011f, 0.3535533905932738f, 0.2777851165098011f, -0.1913417161825449f, -0.4903926402016152f,
|
||||
-0.3535533905932738f, 0.0975451610080642f, 0.4619397662556433f, 0.4157348061512727f, 0.3535533905932738f,
|
||||
0.0975451610080642f, -0.4619397662556434f, -0.2777851165098011f, 0.3535533905932737f, 0.4157348061512727f,
|
||||
-0.1913417161825450f, -0.4903926402016153f, 0.3535533905932738f, -0.0975451610080641f, -0.4619397662556434f,
|
||||
0.2777851165098009f, 0.3535533905932738f, -0.4157348061512726f, -0.1913417161825453f, 0.4903926402016152f,
|
||||
0.3535533905932738f, -0.2777851165098010f, -0.1913417161825452f, 0.4903926402016153f, -0.3535533905932733f,
|
||||
-0.0975451610080649f, 0.4619397662556437f, -0.4157348061512720f, 0.3535533905932738f, -0.4157348061512727f,
|
||||
0.1913417161825450f, 0.0975451610080640f, -0.3535533905932736f, 0.4903926402016152f, -0.4619397662556435f,
|
||||
0.2777851165098022f, 0.3535533905932738f, -0.4903926402016152f, 0.4619397662556433f, -0.4157348061512721f,
|
||||
0.3535533905932733f, -0.2777851165098008f, 0.1913417161825431f, -0.0975451610080625f};
|
||||
|
||||
/**
|
||||
* This unitary matrix performs DCT of columns of the matrix to the right
|
||||
*/
|
||||
const float DCTv8matrixT[BLOCK_SIZE2] = {
|
||||
0.3535533905932738f, 0.3535533905932738f, 0.3535533905932738f, 0.3535533905932738f, 0.3535533905932738f, 0.3535533905932738f, 0.3535533905932738f, 0.3535533905932738f,
|
||||
0.4903926402016152f, 0.4157348061512726f, 0.2777851165098011f, 0.0975451610080642f, -0.0975451610080641f, -0.2777851165098010f, -0.4157348061512727f, -0.4903926402016152f,
|
||||
0.4619397662556434f, 0.1913417161825449f, -0.1913417161825449f, -0.4619397662556434f, -0.4619397662556434f, -0.1913417161825452f, 0.1913417161825450f, 0.4619397662556433f,
|
||||
0.4157348061512726f, -0.0975451610080641f, -0.4903926402016152f, -0.2777851165098011f, 0.2777851165098009f, 0.4903926402016153f, 0.0975451610080640f, -0.4157348061512721f,
|
||||
0.3535533905932738f, -0.3535533905932737f, -0.3535533905932738f, 0.3535533905932737f, 0.3535533905932738f, -0.3535533905932733f, -0.3535533905932736f, 0.3535533905932733f,
|
||||
0.2777851165098011f, -0.4903926402016152f, 0.0975451610080642f, 0.4157348061512727f, -0.4157348061512726f, -0.0975451610080649f, 0.4903926402016152f, -0.2777851165098008f,
|
||||
0.1913417161825449f, -0.4619397662556434f, 0.4619397662556433f, -0.1913417161825450f, -0.1913417161825453f, 0.4619397662556437f, -0.4619397662556435f, 0.1913417161825431f,
|
||||
0.0975451610080642f, -0.2777851165098011f, 0.4157348061512727f, -0.4903926402016153f, 0.4903926402016152f, -0.4157348061512720f, 0.2777851165098022f, -0.0975451610080625f};
|
||||
0.3535533905932738f, 0.3535533905932738f, 0.3535533905932738f, 0.3535533905932738f, 0.3535533905932738f,
|
||||
0.3535533905932738f, 0.3535533905932738f, 0.3535533905932738f, 0.4903926402016152f, 0.4157348061512726f,
|
||||
0.2777851165098011f, 0.0975451610080642f, -0.0975451610080641f, -0.2777851165098010f, -0.4157348061512727f,
|
||||
-0.4903926402016152f, 0.4619397662556434f, 0.1913417161825449f, -0.1913417161825449f, -0.4619397662556434f,
|
||||
-0.4619397662556434f, -0.1913417161825452f, 0.1913417161825450f, 0.4619397662556433f, 0.4157348061512726f,
|
||||
-0.0975451610080641f, -0.4903926402016152f, -0.2777851165098011f, 0.2777851165098009f, 0.4903926402016153f,
|
||||
0.0975451610080640f, -0.4157348061512721f, 0.3535533905932738f, -0.3535533905932737f, -0.3535533905932738f,
|
||||
0.3535533905932737f, 0.3535533905932738f, -0.3535533905932733f, -0.3535533905932736f, 0.3535533905932733f,
|
||||
0.2777851165098011f, -0.4903926402016152f, 0.0975451610080642f, 0.4157348061512727f, -0.4157348061512726f,
|
||||
-0.0975451610080649f, 0.4903926402016152f, -0.2777851165098008f, 0.1913417161825449f, -0.4619397662556434f,
|
||||
0.4619397662556433f, -0.1913417161825450f, -0.1913417161825453f, 0.4619397662556437f, -0.4619397662556435f,
|
||||
0.1913417161825431f, 0.0975451610080642f, -0.2777851165098011f, 0.4157348061512727f, -0.4903926402016153f,
|
||||
0.4903926402016152f, -0.4157348061512720f, 0.2777851165098022f, -0.0975451610080625f};
|
||||
|
||||
/**
|
||||
* JPEG quality=0_of_12 quantization matrix
|
||||
*/
|
||||
float Q_GOLD[BLOCK_SIZE2] = {
|
||||
32.f, 33.f, 51.f, 81.f, 66.f, 39.f, 34.f, 17.f,
|
||||
33.f, 36.f, 48.f, 47.f, 28.f, 23.f, 12.f, 12.f,
|
||||
51.f, 48.f, 47.f, 28.f, 23.f, 12.f, 12.f, 12.f,
|
||||
81.f, 47.f, 28.f, 23.f, 12.f, 12.f, 12.f, 12.f,
|
||||
66.f, 28.f, 23.f, 12.f, 12.f, 12.f, 12.f, 12.f,
|
||||
39.f, 23.f, 12.f, 12.f, 12.f, 12.f, 12.f, 12.f,
|
||||
34.f, 12.f, 12.f, 12.f, 12.f, 12.f, 12.f, 12.f,
|
||||
17.f, 12.f, 12.f, 12.f, 12.f, 12.f, 12.f, 12.f};
|
||||
float Q_GOLD[BLOCK_SIZE2] = {32.f, 33.f, 51.f, 81.f, 66.f, 39.f, 34.f, 17.f, 33.f, 36.f, 48.f, 47.f, 28.f,
|
||||
23.f, 12.f, 12.f, 51.f, 48.f, 47.f, 28.f, 23.f, 12.f, 12.f, 12.f, 81.f, 47.f,
|
||||
28.f, 23.f, 12.f, 12.f, 12.f, 12.f, 66.f, 28.f, 23.f, 12.f, 12.f, 12.f, 12.f,
|
||||
12.f, 39.f, 23.f, 12.f, 12.f, 12.f, 12.f, 12.f, 12.f, 34.f, 12.f, 12.f, 12.f,
|
||||
12.f, 12.f, 12.f, 12.f, 17.f, 12.f, 12.f, 12.f, 12.f, 12.f, 12.f, 12.f};
|
||||
|
||||
/**
|
||||
**************************************************************************
|
||||
@@ -93,23 +99,19 @@ float Q_GOLD[BLOCK_SIZE2] = {
|
||||
*
|
||||
* \return None
|
||||
*/
|
||||
void mult8x8(const float *M1, int M1Stride, const float *M2, int M2Stride,
|
||||
float *Mres, int MresStride)
|
||||
void mult8x8(const float *M1, int M1Stride, const float *M2, int M2Stride, float *Mres, int MresStride)
|
||||
{
|
||||
for (int i = 0; i < BLOCK_SIZE; i++)
|
||||
{
|
||||
for (int j = 0; j < BLOCK_SIZE; j++)
|
||||
{
|
||||
float accumul = 0;
|
||||
for (int i = 0; i < BLOCK_SIZE; i++) {
|
||||
for (int j = 0; j < BLOCK_SIZE; j++) {
|
||||
float accumul = 0;
|
||||
|
||||
for (int k = 0; k < BLOCK_SIZE; k++)
|
||||
{
|
||||
accumul += M1[i * M1Stride + k] * M2[k * M2Stride + j];
|
||||
}
|
||||
for (int k = 0; k < BLOCK_SIZE; k++) {
|
||||
accumul += M1[i * M1Stride + k] * M2[k * M2Stride + j];
|
||||
}
|
||||
|
||||
Mres[i * MresStride + j] = accumul;
|
||||
Mres[i * MresStride + j] = accumul;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -125,25 +127,20 @@ void mult8x8(const float *M1, int M1Stride, const float *M2, int M2Stride,
|
||||
*
|
||||
* \return None
|
||||
*/
|
||||
extern "C" void computeDCT8x8Gold1(const float *fSrc, float *fDst, int Stride,
|
||||
ROI Size)
|
||||
extern "C" void computeDCT8x8Gold1(const float *fSrc, float *fDst, int Stride, ROI Size)
|
||||
{
|
||||
float tmpblock[BLOCK_SIZE2];
|
||||
float tmpblock[BLOCK_SIZE2];
|
||||
|
||||
// perform block wise DCT
|
||||
// DCT(A) = DCTv8matrixT * A * DCTv8matrix
|
||||
for (int i = 0; i + BLOCK_SIZE - 1 < Size.height; i += BLOCK_SIZE)
|
||||
{
|
||||
for (int j = 0; j + BLOCK_SIZE - 1 < Size.width; j += BLOCK_SIZE)
|
||||
{
|
||||
// tmpblock = DCTv8matrixT * A
|
||||
mult8x8(DCTv8matrixT, BLOCK_SIZE, fSrc + i * Stride + j, Stride, tmpblock,
|
||||
BLOCK_SIZE);
|
||||
// DCT(A) = tmpblock * DCTv8matrix
|
||||
mult8x8(tmpblock, BLOCK_SIZE, DCTv8matrix, BLOCK_SIZE,
|
||||
fDst + i * Stride + j, Stride);
|
||||
// perform block wise DCT
|
||||
// DCT(A) = DCTv8matrixT * A * DCTv8matrix
|
||||
for (int i = 0; i + BLOCK_SIZE - 1 < Size.height; i += BLOCK_SIZE) {
|
||||
for (int j = 0; j + BLOCK_SIZE - 1 < Size.width; j += BLOCK_SIZE) {
|
||||
// tmpblock = DCTv8matrixT * A
|
||||
mult8x8(DCTv8matrixT, BLOCK_SIZE, fSrc + i * Stride + j, Stride, tmpblock, BLOCK_SIZE);
|
||||
// DCT(A) = tmpblock * DCTv8matrix
|
||||
mult8x8(tmpblock, BLOCK_SIZE, DCTv8matrix, BLOCK_SIZE, fDst + i * Stride + j, Stride);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -159,25 +156,20 @@ extern "C" void computeDCT8x8Gold1(const float *fSrc, float *fDst, int Stride,
|
||||
*
|
||||
* \return None
|
||||
*/
|
||||
extern "C" void computeIDCT8x8Gold1(const float *fSrc, float *fDst, int Stride,
|
||||
ROI Size)
|
||||
extern "C" void computeIDCT8x8Gold1(const float *fSrc, float *fDst, int Stride, ROI Size)
|
||||
{
|
||||
float tmpblock[BLOCK_SIZE2];
|
||||
float tmpblock[BLOCK_SIZE2];
|
||||
|
||||
// perform block wise IDCT
|
||||
// IDCT(A) = DCTv8matrix * A * DCTv8matrixT
|
||||
for (int i = 0; i + BLOCK_SIZE - 1 < Size.height; i += BLOCK_SIZE)
|
||||
{
|
||||
for (int j = 0; j + BLOCK_SIZE - 1 < Size.width; j += BLOCK_SIZE)
|
||||
{
|
||||
// tmpblock = DCTv8matrix * A
|
||||
mult8x8(DCTv8matrix, BLOCK_SIZE, fSrc + i * Stride + j, Stride, tmpblock,
|
||||
BLOCK_SIZE);
|
||||
// DCT(A) = tmpblock * DCTv8matrixT;
|
||||
mult8x8(tmpblock, BLOCK_SIZE, DCTv8matrixT, BLOCK_SIZE,
|
||||
fDst + i * Stride + j, Stride);
|
||||
// perform block wise IDCT
|
||||
// IDCT(A) = DCTv8matrix * A * DCTv8matrixT
|
||||
for (int i = 0; i + BLOCK_SIZE - 1 < Size.height; i += BLOCK_SIZE) {
|
||||
for (int j = 0; j + BLOCK_SIZE - 1 < Size.width; j += BLOCK_SIZE) {
|
||||
// tmpblock = DCTv8matrix * A
|
||||
mult8x8(DCTv8matrix, BLOCK_SIZE, fSrc + i * Stride + j, Stride, tmpblock, BLOCK_SIZE);
|
||||
// DCT(A) = tmpblock * DCTv8matrixT;
|
||||
mult8x8(tmpblock, BLOCK_SIZE, DCTv8matrixT, BLOCK_SIZE, fDst + i * Stride + j, Stride);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -193,19 +185,16 @@ extern "C" void computeIDCT8x8Gold1(const float *fSrc, float *fDst, int Stride,
|
||||
*/
|
||||
extern "C" void quantizeGoldFloat(float *fSrcDst, int Stride, ROI Size)
|
||||
{
|
||||
// perform block wise in-place quantization using Q_GOLD
|
||||
// Q_GOLD(A) = round(A ./ Q_GOLD) .* Q_GOLD;
|
||||
for (int i = 0; i < Size.height; i++)
|
||||
{
|
||||
for (int j = 0; j < Size.width; j++)
|
||||
{
|
||||
int qx = j % BLOCK_SIZE;
|
||||
int qy = i % BLOCK_SIZE;
|
||||
float quantized =
|
||||
round_f(fSrcDst[i * Stride + j] / Q_GOLD[(qy << BLOCK_SIZE_LOG2) + qx]);
|
||||
fSrcDst[i * Stride + j] = quantized * Q_GOLD[(qy << BLOCK_SIZE_LOG2) + qx];
|
||||
// perform block wise in-place quantization using Q_GOLD
|
||||
// Q_GOLD(A) = round(A ./ Q_GOLD) .* Q_GOLD;
|
||||
for (int i = 0; i < Size.height; i++) {
|
||||
for (int j = 0; j < Size.width; j++) {
|
||||
int qx = j % BLOCK_SIZE;
|
||||
int qy = i % BLOCK_SIZE;
|
||||
float quantized = round_f(fSrcDst[i * Stride + j] / Q_GOLD[(qy << BLOCK_SIZE_LOG2) + qx]);
|
||||
fSrcDst[i * Stride + j] = quantized * Q_GOLD[(qy << BLOCK_SIZE_LOG2) + qx];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -221,33 +210,29 @@ extern "C" void quantizeGoldFloat(float *fSrcDst, int Stride, ROI Size)
|
||||
*/
|
||||
void quantizeGoldShort(short *fSrcDst, int Stride, ROI Size)
|
||||
{
|
||||
// perform block wise in-place quantization using Q_GOLD
|
||||
// Q_GOLD(A) = round(A ./ Q_GOLD) .* Q_GOLD;
|
||||
for (int i = 0; i < Size.height; i++)
|
||||
{
|
||||
for (int j = 0; j < Size.width; j++)
|
||||
{
|
||||
int qx = j % BLOCK_SIZE;
|
||||
int qy = i % BLOCK_SIZE;
|
||||
short temp = fSrcDst[i * Stride + j];
|
||||
short quant = (short)(Q_GOLD[(qy << BLOCK_SIZE_LOG2) + qx]);
|
||||
// perform block wise in-place quantization using Q_GOLD
|
||||
// Q_GOLD(A) = round(A ./ Q_GOLD) .* Q_GOLD;
|
||||
for (int i = 0; i < Size.height; i++) {
|
||||
for (int j = 0; j < Size.width; j++) {
|
||||
int qx = j % BLOCK_SIZE;
|
||||
int qy = i % BLOCK_SIZE;
|
||||
short temp = fSrcDst[i * Stride + j];
|
||||
short quant = (short)(Q_GOLD[(qy << BLOCK_SIZE_LOG2) + qx]);
|
||||
|
||||
if (temp < 0)
|
||||
{
|
||||
temp = -temp;
|
||||
temp += quant >> 1;
|
||||
temp /= quant;
|
||||
temp = -temp;
|
||||
}
|
||||
else
|
||||
{
|
||||
temp += quant >> 1;
|
||||
temp /= quant;
|
||||
}
|
||||
if (temp < 0) {
|
||||
temp = -temp;
|
||||
temp += quant >> 1;
|
||||
temp /= quant;
|
||||
temp = -temp;
|
||||
}
|
||||
else {
|
||||
temp += quant >> 1;
|
||||
temp /= quant;
|
||||
}
|
||||
|
||||
fSrcDst[i * Stride + j] = temp * quant;
|
||||
fSrcDst[i * Stride + j] = temp * quant;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Used in forward and inverse DCT.
|
||||
@@ -276,37 +261,32 @@ float C_norm = 0.3535533905932737f; // 1 / (8^0.5)
|
||||
*
|
||||
* \return None
|
||||
*/
|
||||
void SubroutineDCTvector(float *FirstIn, int StepIn, float *FirstOut,
|
||||
int StepOut)
|
||||
void SubroutineDCTvector(float *FirstIn, int StepIn, float *FirstOut, int StepOut)
|
||||
{
|
||||
float X07P = FirstIn[0 * StepIn] + FirstIn[7 * StepIn];
|
||||
float X16P = FirstIn[1 * StepIn] + FirstIn[6 * StepIn];
|
||||
float X25P = FirstIn[2 * StepIn] + FirstIn[5 * StepIn];
|
||||
float X34P = FirstIn[3 * StepIn] + FirstIn[4 * StepIn];
|
||||
float X07P = FirstIn[0 * StepIn] + FirstIn[7 * StepIn];
|
||||
float X16P = FirstIn[1 * StepIn] + FirstIn[6 * StepIn];
|
||||
float X25P = FirstIn[2 * StepIn] + FirstIn[5 * StepIn];
|
||||
float X34P = FirstIn[3 * StepIn] + FirstIn[4 * StepIn];
|
||||
|
||||
float X07M = FirstIn[0 * StepIn] - FirstIn[7 * StepIn];
|
||||
float X61M = FirstIn[6 * StepIn] - FirstIn[1 * StepIn];
|
||||
float X25M = FirstIn[2 * StepIn] - FirstIn[5 * StepIn];
|
||||
float X43M = FirstIn[4 * StepIn] - FirstIn[3 * StepIn];
|
||||
float X07M = FirstIn[0 * StepIn] - FirstIn[7 * StepIn];
|
||||
float X61M = FirstIn[6 * StepIn] - FirstIn[1 * StepIn];
|
||||
float X25M = FirstIn[2 * StepIn] - FirstIn[5 * StepIn];
|
||||
float X43M = FirstIn[4 * StepIn] - FirstIn[3 * StepIn];
|
||||
|
||||
float X07P34PP = X07P + X34P;
|
||||
float X07P34PM = X07P - X34P;
|
||||
float X16P25PP = X16P + X25P;
|
||||
float X16P25PM = X16P - X25P;
|
||||
float X07P34PP = X07P + X34P;
|
||||
float X07P34PM = X07P - X34P;
|
||||
float X16P25PP = X16P + X25P;
|
||||
float X16P25PM = X16P - X25P;
|
||||
|
||||
FirstOut[0 * StepOut] = C_norm * (X07P34PP + X16P25PP);
|
||||
FirstOut[2 * StepOut] = C_norm * (C_b * X07P34PM + C_e * X16P25PM);
|
||||
FirstOut[4 * StepOut] = C_norm * (X07P34PP - X16P25PP);
|
||||
FirstOut[6 * StepOut] = C_norm * (C_e * X07P34PM - C_b * X16P25PM);
|
||||
FirstOut[0 * StepOut] = C_norm * (X07P34PP + X16P25PP);
|
||||
FirstOut[2 * StepOut] = C_norm * (C_b * X07P34PM + C_e * X16P25PM);
|
||||
FirstOut[4 * StepOut] = C_norm * (X07P34PP - X16P25PP);
|
||||
FirstOut[6 * StepOut] = C_norm * (C_e * X07P34PM - C_b * X16P25PM);
|
||||
|
||||
FirstOut[1 * StepOut] =
|
||||
C_norm * (C_a * X07M - C_c * X61M + C_d * X25M - C_f * X43M);
|
||||
FirstOut[3 * StepOut] =
|
||||
C_norm * (C_c * X07M + C_f * X61M - C_a * X25M + C_d * X43M);
|
||||
FirstOut[5 * StepOut] =
|
||||
C_norm * (C_d * X07M + C_a * X61M + C_f * X25M - C_c * X43M);
|
||||
FirstOut[7 * StepOut] =
|
||||
C_norm * (C_f * X07M + C_d * X61M + C_c * X25M + C_a * X43M);
|
||||
FirstOut[1 * StepOut] = C_norm * (C_a * X07M - C_c * X61M + C_d * X25M - C_f * X43M);
|
||||
FirstOut[3 * StepOut] = C_norm * (C_c * X07M + C_f * X61M - C_a * X25M + C_d * X43M);
|
||||
FirstOut[5 * StepOut] = C_norm * (C_d * X07M + C_a * X61M + C_f * X25M - C_c * X43M);
|
||||
FirstOut[7 * StepOut] = C_norm * (C_f * X07M + C_d * X61M + C_c * X25M + C_a * X43M);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -322,38 +302,37 @@ void SubroutineDCTvector(float *FirstIn, int StepIn, float *FirstOut,
|
||||
*
|
||||
* \return None
|
||||
*/
|
||||
void SubroutineIDCTvector(float *FirstIn, int StepIn, float *FirstOut,
|
||||
int StepOut)
|
||||
void SubroutineIDCTvector(float *FirstIn, int StepIn, float *FirstOut, int StepOut)
|
||||
{
|
||||
float Y04P = FirstIn[0 * StepIn] + FirstIn[4 * StepIn];
|
||||
float Y2b6eP = C_b * FirstIn[2 * StepIn] + C_e * FirstIn[6 * StepIn];
|
||||
float Y04P = FirstIn[0 * StepIn] + FirstIn[4 * StepIn];
|
||||
float Y2b6eP = C_b * FirstIn[2 * StepIn] + C_e * FirstIn[6 * StepIn];
|
||||
|
||||
float Y04P2b6ePP = Y04P + Y2b6eP;
|
||||
float Y04P2b6ePM = Y04P - Y2b6eP;
|
||||
float Y7f1aP3c5dPP = C_f * FirstIn[7 * StepIn] + C_a * FirstIn[1 * StepIn] +
|
||||
C_c * FirstIn[3 * StepIn] + C_d * FirstIn[5 * StepIn];
|
||||
float Y7a1fM3d5cMP = C_a * FirstIn[7 * StepIn] - C_f * FirstIn[1 * StepIn] +
|
||||
C_d * FirstIn[3 * StepIn] - C_c * FirstIn[5 * StepIn];
|
||||
float Y04P2b6ePP = Y04P + Y2b6eP;
|
||||
float Y04P2b6ePM = Y04P - Y2b6eP;
|
||||
float Y7f1aP3c5dPP =
|
||||
C_f * FirstIn[7 * StepIn] + C_a * FirstIn[1 * StepIn] + C_c * FirstIn[3 * StepIn] + C_d * FirstIn[5 * StepIn];
|
||||
float Y7a1fM3d5cMP =
|
||||
C_a * FirstIn[7 * StepIn] - C_f * FirstIn[1 * StepIn] + C_d * FirstIn[3 * StepIn] - C_c * FirstIn[5 * StepIn];
|
||||
|
||||
float Y04M = FirstIn[0 * StepIn] - FirstIn[4 * StepIn];
|
||||
float Y2e6bM = C_e * FirstIn[2 * StepIn] - C_b * FirstIn[6 * StepIn];
|
||||
float Y04M = FirstIn[0 * StepIn] - FirstIn[4 * StepIn];
|
||||
float Y2e6bM = C_e * FirstIn[2 * StepIn] - C_b * FirstIn[6 * StepIn];
|
||||
|
||||
float Y04M2e6bMP = Y04M + Y2e6bM;
|
||||
float Y04M2e6bMM = Y04M - Y2e6bM;
|
||||
float Y1c7dM3f5aPM = C_c * FirstIn[1 * StepIn] - C_d * FirstIn[7 * StepIn] -
|
||||
C_f * FirstIn[3 * StepIn] - C_a * FirstIn[5 * StepIn];
|
||||
float Y1d7cP3a5fMM = C_d * FirstIn[1 * StepIn] + C_c * FirstIn[7 * StepIn] -
|
||||
C_a * FirstIn[3 * StepIn] + C_f * FirstIn[5 * StepIn];
|
||||
float Y04M2e6bMP = Y04M + Y2e6bM;
|
||||
float Y04M2e6bMM = Y04M - Y2e6bM;
|
||||
float Y1c7dM3f5aPM =
|
||||
C_c * FirstIn[1 * StepIn] - C_d * FirstIn[7 * StepIn] - C_f * FirstIn[3 * StepIn] - C_a * FirstIn[5 * StepIn];
|
||||
float Y1d7cP3a5fMM =
|
||||
C_d * FirstIn[1 * StepIn] + C_c * FirstIn[7 * StepIn] - C_a * FirstIn[3 * StepIn] + C_f * FirstIn[5 * StepIn];
|
||||
|
||||
FirstOut[0 * StepOut] = C_norm * (Y04P2b6ePP + Y7f1aP3c5dPP);
|
||||
FirstOut[7 * StepOut] = C_norm * (Y04P2b6ePP - Y7f1aP3c5dPP);
|
||||
FirstOut[4 * StepOut] = C_norm * (Y04P2b6ePM + Y7a1fM3d5cMP);
|
||||
FirstOut[3 * StepOut] = C_norm * (Y04P2b6ePM - Y7a1fM3d5cMP);
|
||||
FirstOut[0 * StepOut] = C_norm * (Y04P2b6ePP + Y7f1aP3c5dPP);
|
||||
FirstOut[7 * StepOut] = C_norm * (Y04P2b6ePP - Y7f1aP3c5dPP);
|
||||
FirstOut[4 * StepOut] = C_norm * (Y04P2b6ePM + Y7a1fM3d5cMP);
|
||||
FirstOut[3 * StepOut] = C_norm * (Y04P2b6ePM - Y7a1fM3d5cMP);
|
||||
|
||||
FirstOut[1 * StepOut] = C_norm * (Y04M2e6bMP + Y1c7dM3f5aPM);
|
||||
FirstOut[5 * StepOut] = C_norm * (Y04M2e6bMM - Y1d7cP3a5fMM);
|
||||
FirstOut[2 * StepOut] = C_norm * (Y04M2e6bMM + Y1d7cP3a5fMM);
|
||||
FirstOut[6 * StepOut] = C_norm * (Y04M2e6bMP - Y1c7dM3f5aPM);
|
||||
FirstOut[1 * StepOut] = C_norm * (Y04M2e6bMP + Y1c7dM3f5aPM);
|
||||
FirstOut[5 * StepOut] = C_norm * (Y04M2e6bMM - Y1d7cP3a5fMM);
|
||||
FirstOut[2 * StepOut] = C_norm * (Y04M2e6bMM + Y1d7cP3a5fMM);
|
||||
FirstOut[6 * StepOut] = C_norm * (Y04M2e6bMP - Y1c7dM3f5aPM);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -369,28 +348,21 @@ void SubroutineIDCTvector(float *FirstIn, int StepIn, float *FirstOut,
|
||||
*
|
||||
* \return None
|
||||
*/
|
||||
extern "C" void computeDCT8x8Gold2(const float *fSrc, float *fDst, int Stride,
|
||||
ROI Size)
|
||||
extern "C" void computeDCT8x8Gold2(const float *fSrc, float *fDst, int Stride, ROI Size)
|
||||
{
|
||||
for (int i = 0; i + BLOCK_SIZE - 1 < Size.height; i += BLOCK_SIZE)
|
||||
{
|
||||
for (int j = 0; j + BLOCK_SIZE - 1 < Size.width; j += BLOCK_SIZE)
|
||||
{
|
||||
// process rows
|
||||
for (int k = 0; k < BLOCK_SIZE; k++)
|
||||
{
|
||||
SubroutineDCTvector((float *)fSrc + (i + k) * Stride + j, 1,
|
||||
fDst + (i + k) * Stride + j, 1);
|
||||
}
|
||||
for (int i = 0; i + BLOCK_SIZE - 1 < Size.height; i += BLOCK_SIZE) {
|
||||
for (int j = 0; j + BLOCK_SIZE - 1 < Size.width; j += BLOCK_SIZE) {
|
||||
// process rows
|
||||
for (int k = 0; k < BLOCK_SIZE; k++) {
|
||||
SubroutineDCTvector((float *)fSrc + (i + k) * Stride + j, 1, fDst + (i + k) * Stride + j, 1);
|
||||
}
|
||||
|
||||
// process columns
|
||||
for (int k = 0; k < BLOCK_SIZE; k++)
|
||||
{
|
||||
SubroutineDCTvector(fDst + i * Stride + (j + k), Stride,
|
||||
fDst + i * Stride + (j + k), Stride);
|
||||
}
|
||||
// process columns
|
||||
for (int k = 0; k < BLOCK_SIZE; k++) {
|
||||
SubroutineDCTvector(fDst + i * Stride + (j + k), Stride, fDst + i * Stride + (j + k), Stride);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -406,26 +378,19 @@ extern "C" void computeDCT8x8Gold2(const float *fSrc, float *fDst, int Stride,
|
||||
*
|
||||
* \return None
|
||||
*/
|
||||
extern "C" void computeIDCT8x8Gold2(const float *fSrc, float *fDst, int Stride,
|
||||
ROI Size)
|
||||
extern "C" void computeIDCT8x8Gold2(const float *fSrc, float *fDst, int Stride, ROI Size)
|
||||
{
|
||||
for (int i = 0; i + BLOCK_SIZE - 1 < Size.height; i += BLOCK_SIZE)
|
||||
{
|
||||
for (int j = 0; j + BLOCK_SIZE - 1 < Size.width; j += BLOCK_SIZE)
|
||||
{
|
||||
// process rows
|
||||
for (int k = 0; k < BLOCK_SIZE; k++)
|
||||
{
|
||||
SubroutineIDCTvector((float *)fSrc + (i + k) * Stride + j, 1,
|
||||
fDst + (i + k) * Stride + j, 1);
|
||||
}
|
||||
for (int i = 0; i + BLOCK_SIZE - 1 < Size.height; i += BLOCK_SIZE) {
|
||||
for (int j = 0; j + BLOCK_SIZE - 1 < Size.width; j += BLOCK_SIZE) {
|
||||
// process rows
|
||||
for (int k = 0; k < BLOCK_SIZE; k++) {
|
||||
SubroutineIDCTvector((float *)fSrc + (i + k) * Stride + j, 1, fDst + (i + k) * Stride + j, 1);
|
||||
}
|
||||
|
||||
// process columns
|
||||
for (int k = 0; k < BLOCK_SIZE; k++)
|
||||
{
|
||||
SubroutineIDCTvector(fDst + i * Stride + (j + k), Stride,
|
||||
fDst + i * Stride + (j + k), Stride);
|
||||
}
|
||||
// process columns
|
||||
for (int k = 0; k < BLOCK_SIZE; k++) {
|
||||
SubroutineIDCTvector(fDst + i * Stride + (j + k), Stride, fDst + i * Stride + (j + k), Stride);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,11 +39,12 @@
|
||||
|
||||
#include "BmpUtil.h"
|
||||
|
||||
extern "C" {
|
||||
void computeDCT8x8Gold1(const float *fSrc, float *fDst, int Stride, ROI Size);
|
||||
void computeIDCT8x8Gold1(const float *fSrc, float *fDst, int Stride, ROI Size);
|
||||
void quantizeGoldFloat(float *fSrcDst, int Stride, ROI Size);
|
||||
void quantizeGoldShort(short *fSrcDst, int Stride, ROI Size);
|
||||
void computeDCT8x8Gold2(const float *fSrc, float *fDst, int Stride, ROI Size);
|
||||
void computeIDCT8x8Gold2(const float *fSrc, float *fDst, int Stride, ROI Size);
|
||||
extern "C"
|
||||
{
|
||||
void computeDCT8x8Gold1(const float *fSrc, float *fDst, int Stride, ROI Size);
|
||||
void computeIDCT8x8Gold1(const float *fSrc, float *fDst, int Stride, ROI Size);
|
||||
void quantizeGoldFloat(float *fSrcDst, int Stride, ROI Size);
|
||||
void quantizeGoldShort(short *fSrcDst, int Stride, ROI Size);
|
||||
void computeDCT8x8Gold2(const float *fSrc, float *fDst, int Stride, ROI Size);
|
||||
void computeIDCT8x8Gold2(const float *fSrc, float *fDst, int Stride, ROI Size);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -47,19 +47,23 @@ namespace cg = cooperative_groups;
|
||||
#include "Common.h"
|
||||
|
||||
/**
|
||||
* This unitary matrix performs discrete cosine transform of rows of the matrix
|
||||
* to the left
|
||||
*/
|
||||
* This unitary matrix performs discrete cosine transform of rows of the matrix
|
||||
* to the left
|
||||
*/
|
||||
__constant__ float DCTv8matrix[] = {
|
||||
0.3535533905932738f, 0.4903926402016152f, 0.4619397662556434f, 0.4157348061512726f, 0.3535533905932738f, 0.2777851165098011f, 0.1913417161825449f, 0.0975451610080642f,
|
||||
0.3535533905932738f, 0.4157348061512726f, 0.1913417161825449f, -0.0975451610080641f, -0.3535533905932737f, -0.4903926402016152f, -0.4619397662556434f, -0.2777851165098011f,
|
||||
0.3535533905932738f, 0.2777851165098011f, -0.1913417161825449f, -0.4903926402016152f, -0.3535533905932738f, 0.0975451610080642f, 0.4619397662556433f, 0.4157348061512727f,
|
||||
0.3535533905932738f, 0.0975451610080642f, -0.4619397662556434f, -0.2777851165098011f, 0.3535533905932737f, 0.4157348061512727f, -0.1913417161825450f, -0.4903926402016153f,
|
||||
0.3535533905932738f, -0.0975451610080641f, -0.4619397662556434f, 0.2777851165098009f, 0.3535533905932738f, -0.4157348061512726f, -0.1913417161825453f, 0.4903926402016152f,
|
||||
0.3535533905932738f, -0.2777851165098010f, -0.1913417161825452f, 0.4903926402016153f, -0.3535533905932733f, -0.0975451610080649f, 0.4619397662556437f, -0.4157348061512720f,
|
||||
0.3535533905932738f, -0.4157348061512727f, 0.1913417161825450f, 0.0975451610080640f, -0.3535533905932736f, 0.4903926402016152f, -0.4619397662556435f, 0.2777851165098022f,
|
||||
0.3535533905932738f, -0.4903926402016152f, 0.4619397662556433f, -0.4157348061512721f, 0.3535533905932733f, -0.2777851165098008f, 0.1913417161825431f, -0.0975451610080625f
|
||||
};
|
||||
0.3535533905932738f, 0.4903926402016152f, 0.4619397662556434f, 0.4157348061512726f, 0.3535533905932738f,
|
||||
0.2777851165098011f, 0.1913417161825449f, 0.0975451610080642f, 0.3535533905932738f, 0.4157348061512726f,
|
||||
0.1913417161825449f, -0.0975451610080641f, -0.3535533905932737f, -0.4903926402016152f, -0.4619397662556434f,
|
||||
-0.2777851165098011f, 0.3535533905932738f, 0.2777851165098011f, -0.1913417161825449f, -0.4903926402016152f,
|
||||
-0.3535533905932738f, 0.0975451610080642f, 0.4619397662556433f, 0.4157348061512727f, 0.3535533905932738f,
|
||||
0.0975451610080642f, -0.4619397662556434f, -0.2777851165098011f, 0.3535533905932737f, 0.4157348061512727f,
|
||||
-0.1913417161825450f, -0.4903926402016153f, 0.3535533905932738f, -0.0975451610080641f, -0.4619397662556434f,
|
||||
0.2777851165098009f, 0.3535533905932738f, -0.4157348061512726f, -0.1913417161825453f, 0.4903926402016152f,
|
||||
0.3535533905932738f, -0.2777851165098010f, -0.1913417161825452f, 0.4903926402016153f, -0.3535533905932733f,
|
||||
-0.0975451610080649f, 0.4619397662556437f, -0.4157348061512720f, 0.3535533905932738f, -0.4157348061512727f,
|
||||
0.1913417161825450f, 0.0975451610080640f, -0.3535533905932736f, 0.4903926402016152f, -0.4619397662556435f,
|
||||
0.2777851165098022f, 0.3535533905932738f, -0.4903926402016152f, 0.4619397662556433f, -0.4157348061512721f,
|
||||
0.3535533905932733f, -0.2777851165098008f, 0.1913417161825431f, -0.0975451610080625f};
|
||||
|
||||
// Temporary blocks
|
||||
__shared__ float CurBlockLocal1[BLOCK_SIZE2];
|
||||
@@ -80,73 +84,70 @@ __shared__ float CurBlockLocal2[BLOCK_SIZE2];
|
||||
*
|
||||
* \return None
|
||||
*/
|
||||
__global__ void CUDAkernel1DCT(float *Dst, int ImgWidth, int OffsetXBlocks,
|
||||
int OffsetYBlocks, cudaTextureObject_t TexSrc) {
|
||||
// Handle to thread block group
|
||||
cg::thread_block cta = cg::this_thread_block();
|
||||
// Block index
|
||||
const int bx = blockIdx.x + OffsetXBlocks;
|
||||
const int by = blockIdx.y + OffsetYBlocks;
|
||||
__global__ void
|
||||
CUDAkernel1DCT(float *Dst, int ImgWidth, int OffsetXBlocks, int OffsetYBlocks, cudaTextureObject_t TexSrc)
|
||||
{
|
||||
// Handle to thread block group
|
||||
cg::thread_block cta = cg::this_thread_block();
|
||||
// Block index
|
||||
const int bx = blockIdx.x + OffsetXBlocks;
|
||||
const int by = blockIdx.y + OffsetYBlocks;
|
||||
|
||||
// Thread index (current coefficient)
|
||||
const int tx = threadIdx.x;
|
||||
const int ty = threadIdx.y;
|
||||
// Thread index (current coefficient)
|
||||
const int tx = threadIdx.x;
|
||||
const int ty = threadIdx.y;
|
||||
|
||||
// Texture coordinates
|
||||
const float tex_x = (float)((bx << BLOCK_SIZE_LOG2) + tx) + 0.5f;
|
||||
const float tex_y = (float)((by << BLOCK_SIZE_LOG2) + ty) + 0.5f;
|
||||
// Texture coordinates
|
||||
const float tex_x = (float)((bx << BLOCK_SIZE_LOG2) + tx) + 0.5f;
|
||||
const float tex_y = (float)((by << BLOCK_SIZE_LOG2) + ty) + 0.5f;
|
||||
|
||||
// copy current image pixel to the first block
|
||||
CurBlockLocal1[(ty << BLOCK_SIZE_LOG2) + tx] =
|
||||
tex2D<float>(TexSrc, tex_x, tex_y);
|
||||
// copy current image pixel to the first block
|
||||
CurBlockLocal1[(ty << BLOCK_SIZE_LOG2) + tx] = tex2D<float>(TexSrc, tex_x, tex_y);
|
||||
|
||||
// synchronize threads to make sure the block is copied
|
||||
cg::sync(cta);
|
||||
// synchronize threads to make sure the block is copied
|
||||
cg::sync(cta);
|
||||
|
||||
// calculate the multiplication of DCTv8matrixT * A and place it in the second
|
||||
// block
|
||||
float curelem = 0;
|
||||
int DCTv8matrixIndex = 0 * BLOCK_SIZE + ty;
|
||||
int CurBlockLocal1Index = 0 * BLOCK_SIZE + tx;
|
||||
// calculate the multiplication of DCTv8matrixT * A and place it in the second
|
||||
// block
|
||||
float curelem = 0;
|
||||
int DCTv8matrixIndex = 0 * BLOCK_SIZE + ty;
|
||||
int CurBlockLocal1Index = 0 * BLOCK_SIZE + tx;
|
||||
#pragma unroll
|
||||
|
||||
for (int i = 0; i < BLOCK_SIZE; i++) {
|
||||
curelem +=
|
||||
DCTv8matrix[DCTv8matrixIndex] * CurBlockLocal1[CurBlockLocal1Index];
|
||||
DCTv8matrixIndex += BLOCK_SIZE;
|
||||
CurBlockLocal1Index += BLOCK_SIZE;
|
||||
}
|
||||
for (int i = 0; i < BLOCK_SIZE; i++) {
|
||||
curelem += DCTv8matrix[DCTv8matrixIndex] * CurBlockLocal1[CurBlockLocal1Index];
|
||||
DCTv8matrixIndex += BLOCK_SIZE;
|
||||
CurBlockLocal1Index += BLOCK_SIZE;
|
||||
}
|
||||
|
||||
CurBlockLocal2[(ty << BLOCK_SIZE_LOG2) + tx] = curelem;
|
||||
CurBlockLocal2[(ty << BLOCK_SIZE_LOG2) + tx] = curelem;
|
||||
|
||||
// synchronize threads to make sure the first 2 matrices are multiplied and
|
||||
// the result is stored in the second block
|
||||
cg::sync(cta);
|
||||
// synchronize threads to make sure the first 2 matrices are multiplied and
|
||||
// the result is stored in the second block
|
||||
cg::sync(cta);
|
||||
|
||||
// calculate the multiplication of (DCTv8matrixT * A) * DCTv8matrix and place
|
||||
// it in the first block
|
||||
curelem = 0;
|
||||
int CurBlockLocal2Index = (ty << BLOCK_SIZE_LOG2) + 0;
|
||||
DCTv8matrixIndex = 0 * BLOCK_SIZE + tx;
|
||||
// calculate the multiplication of (DCTv8matrixT * A) * DCTv8matrix and place
|
||||
// it in the first block
|
||||
curelem = 0;
|
||||
int CurBlockLocal2Index = (ty << BLOCK_SIZE_LOG2) + 0;
|
||||
DCTv8matrixIndex = 0 * BLOCK_SIZE + tx;
|
||||
#pragma unroll
|
||||
|
||||
for (int i = 0; i < BLOCK_SIZE; i++) {
|
||||
curelem +=
|
||||
CurBlockLocal2[CurBlockLocal2Index] * DCTv8matrix[DCTv8matrixIndex];
|
||||
CurBlockLocal2Index += 1;
|
||||
DCTv8matrixIndex += BLOCK_SIZE;
|
||||
}
|
||||
for (int i = 0; i < BLOCK_SIZE; i++) {
|
||||
curelem += CurBlockLocal2[CurBlockLocal2Index] * DCTv8matrix[DCTv8matrixIndex];
|
||||
CurBlockLocal2Index += 1;
|
||||
DCTv8matrixIndex += BLOCK_SIZE;
|
||||
}
|
||||
|
||||
CurBlockLocal1[(ty << BLOCK_SIZE_LOG2) + tx] = curelem;
|
||||
CurBlockLocal1[(ty << BLOCK_SIZE_LOG2) + tx] = curelem;
|
||||
|
||||
// synchronize threads to make sure the matrices are multiplied and the result
|
||||
// is stored back in the first block
|
||||
cg::sync(cta);
|
||||
// synchronize threads to make sure the matrices are multiplied and the result
|
||||
// is stored back in the first block
|
||||
cg::sync(cta);
|
||||
|
||||
// copy current coefficient to its place in the result array
|
||||
Dst[FMUL(((by << BLOCK_SIZE_LOG2) + ty), ImgWidth) +
|
||||
((bx << BLOCK_SIZE_LOG2) + tx)] =
|
||||
CurBlockLocal1[(ty << BLOCK_SIZE_LOG2) + tx];
|
||||
// copy current coefficient to its place in the result array
|
||||
Dst[FMUL(((by << BLOCK_SIZE_LOG2) + ty), ImgWidth) + ((bx << BLOCK_SIZE_LOG2) + tx)] =
|
||||
CurBlockLocal1[(ty << BLOCK_SIZE_LOG2) + tx];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -164,71 +165,68 @@ __global__ void CUDAkernel1DCT(float *Dst, int ImgWidth, int OffsetXBlocks,
|
||||
*
|
||||
* \return None
|
||||
*/
|
||||
__global__ void CUDAkernel1IDCT(float *Dst, int ImgWidth, int OffsetXBlocks,
|
||||
int OffsetYBlocks, cudaTextureObject_t TexSrc) {
|
||||
// Handle to thread block group
|
||||
cg::thread_block cta = cg::this_thread_block();
|
||||
// Block index
|
||||
int bx = blockIdx.x + OffsetXBlocks;
|
||||
int by = blockIdx.y + OffsetYBlocks;
|
||||
__global__ void
|
||||
CUDAkernel1IDCT(float *Dst, int ImgWidth, int OffsetXBlocks, int OffsetYBlocks, cudaTextureObject_t TexSrc)
|
||||
{
|
||||
// Handle to thread block group
|
||||
cg::thread_block cta = cg::this_thread_block();
|
||||
// Block index
|
||||
int bx = blockIdx.x + OffsetXBlocks;
|
||||
int by = blockIdx.y + OffsetYBlocks;
|
||||
|
||||
// Thread index (current image pixel)
|
||||
int tx = threadIdx.x;
|
||||
int ty = threadIdx.y;
|
||||
// Thread index (current image pixel)
|
||||
int tx = threadIdx.x;
|
||||
int ty = threadIdx.y;
|
||||
|
||||
// Texture coordinates
|
||||
const float tex_x = (float)((bx << BLOCK_SIZE_LOG2) + tx) + 0.5f;
|
||||
const float tex_y = (float)((by << BLOCK_SIZE_LOG2) + ty) + 0.5f;
|
||||
// Texture coordinates
|
||||
const float tex_x = (float)((bx << BLOCK_SIZE_LOG2) + tx) + 0.5f;
|
||||
const float tex_y = (float)((by << BLOCK_SIZE_LOG2) + ty) + 0.5f;
|
||||
|
||||
// copy current image pixel to the first block
|
||||
CurBlockLocal1[(ty << BLOCK_SIZE_LOG2) + tx] =
|
||||
tex2D<float>(TexSrc, tex_x, tex_y);
|
||||
// copy current image pixel to the first block
|
||||
CurBlockLocal1[(ty << BLOCK_SIZE_LOG2) + tx] = tex2D<float>(TexSrc, tex_x, tex_y);
|
||||
|
||||
// synchronize threads to make sure the block is copied
|
||||
cg::sync(cta);
|
||||
// synchronize threads to make sure the block is copied
|
||||
cg::sync(cta);
|
||||
|
||||
// calculate the multiplication of DCTv8matrix * A and place it in the second
|
||||
// block
|
||||
float curelem = 0;
|
||||
int DCTv8matrixIndex = (ty << BLOCK_SIZE_LOG2) + 0;
|
||||
int CurBlockLocal1Index = 0 * BLOCK_SIZE + tx;
|
||||
// calculate the multiplication of DCTv8matrix * A and place it in the second
|
||||
// block
|
||||
float curelem = 0;
|
||||
int DCTv8matrixIndex = (ty << BLOCK_SIZE_LOG2) + 0;
|
||||
int CurBlockLocal1Index = 0 * BLOCK_SIZE + tx;
|
||||
#pragma unroll
|
||||
|
||||
for (int i = 0; i < BLOCK_SIZE; i++) {
|
||||
curelem +=
|
||||
DCTv8matrix[DCTv8matrixIndex] * CurBlockLocal1[CurBlockLocal1Index];
|
||||
DCTv8matrixIndex += 1;
|
||||
CurBlockLocal1Index += BLOCK_SIZE;
|
||||
}
|
||||
for (int i = 0; i < BLOCK_SIZE; i++) {
|
||||
curelem += DCTv8matrix[DCTv8matrixIndex] * CurBlockLocal1[CurBlockLocal1Index];
|
||||
DCTv8matrixIndex += 1;
|
||||
CurBlockLocal1Index += BLOCK_SIZE;
|
||||
}
|
||||
|
||||
CurBlockLocal2[(ty << BLOCK_SIZE_LOG2) + tx] = curelem;
|
||||
CurBlockLocal2[(ty << BLOCK_SIZE_LOG2) + tx] = curelem;
|
||||
|
||||
// synchronize threads to make sure the first 2 matrices are multiplied and
|
||||
// the result is stored in the second block
|
||||
cg::sync(cta);
|
||||
// synchronize threads to make sure the first 2 matrices are multiplied and
|
||||
// the result is stored in the second block
|
||||
cg::sync(cta);
|
||||
|
||||
// calculate the multiplication of (DCTv8matrix * A) * DCTv8matrixT and place
|
||||
// it in the first block
|
||||
curelem = 0;
|
||||
int CurBlockLocal2Index = (ty << BLOCK_SIZE_LOG2) + 0;
|
||||
DCTv8matrixIndex = (tx << BLOCK_SIZE_LOG2) + 0;
|
||||
// calculate the multiplication of (DCTv8matrix * A) * DCTv8matrixT and place
|
||||
// it in the first block
|
||||
curelem = 0;
|
||||
int CurBlockLocal2Index = (ty << BLOCK_SIZE_LOG2) + 0;
|
||||
DCTv8matrixIndex = (tx << BLOCK_SIZE_LOG2) + 0;
|
||||
#pragma unroll
|
||||
|
||||
for (int i = 0; i < BLOCK_SIZE; i++) {
|
||||
curelem +=
|
||||
CurBlockLocal2[CurBlockLocal2Index] * DCTv8matrix[DCTv8matrixIndex];
|
||||
CurBlockLocal2Index += 1;
|
||||
DCTv8matrixIndex += 1;
|
||||
}
|
||||
for (int i = 0; i < BLOCK_SIZE; i++) {
|
||||
curelem += CurBlockLocal2[CurBlockLocal2Index] * DCTv8matrix[DCTv8matrixIndex];
|
||||
CurBlockLocal2Index += 1;
|
||||
DCTv8matrixIndex += 1;
|
||||
}
|
||||
|
||||
CurBlockLocal1[(ty << BLOCK_SIZE_LOG2) + tx] = curelem;
|
||||
CurBlockLocal1[(ty << BLOCK_SIZE_LOG2) + tx] = curelem;
|
||||
|
||||
// synchronize threads to make sure the matrices are multiplied and the result
|
||||
// is stored back in the first block
|
||||
cg::sync(cta);
|
||||
// synchronize threads to make sure the matrices are multiplied and the result
|
||||
// is stored back in the first block
|
||||
cg::sync(cta);
|
||||
|
||||
// copy current coefficient to its place in the result array
|
||||
Dst[FMUL(((by << BLOCK_SIZE_LOG2) + ty), ImgWidth) +
|
||||
((bx << BLOCK_SIZE_LOG2) + tx)] =
|
||||
CurBlockLocal1[(ty << BLOCK_SIZE_LOG2) + tx];
|
||||
// copy current coefficient to its place in the result array
|
||||
Dst[FMUL(((by << BLOCK_SIZE_LOG2) + ty), ImgWidth) + ((bx << BLOCK_SIZE_LOG2) + tx)] =
|
||||
CurBlockLocal1[(ty << BLOCK_SIZE_LOG2) + tx];
|
||||
}
|
||||
|
||||
@@ -47,41 +47,41 @@ namespace cg = cooperative_groups;
|
||||
#include "Common.h"
|
||||
|
||||
// Used in forward and inverse DCT
|
||||
#define C_a 1.387039845322148f //!< a = (2^0.5) * cos( pi / 16);
|
||||
#define C_b 1.306562964876377f //!< b = (2^0.5) * cos( pi / 8);
|
||||
#define C_c 1.175875602419359f //!< c = (2^0.5) * cos(3 * pi / 16);
|
||||
#define C_d 0.785694958387102f //!< d = (2^0.5) * cos(5 * pi / 16);
|
||||
#define C_e 0.541196100146197f //!< e = (2^0.5) * cos(3 * pi / 8);
|
||||
#define C_f 0.275899379282943f //!< f = (2^0.5) * cos(7 * pi / 16);
|
||||
#define C_a 1.387039845322148f //!< a = (2^0.5) * cos( pi / 16);
|
||||
#define C_b 1.306562964876377f //!< b = (2^0.5) * cos( pi / 8);
|
||||
#define C_c 1.175875602419359f //!< c = (2^0.5) * cos(3 * pi / 16);
|
||||
#define C_d 0.785694958387102f //!< d = (2^0.5) * cos(5 * pi / 16);
|
||||
#define C_e 0.541196100146197f //!< e = (2^0.5) * cos(3 * pi / 8);
|
||||
#define C_f 0.275899379282943f //!< f = (2^0.5) * cos(7 * pi / 16);
|
||||
|
||||
/**
|
||||
* Normalization constant that is used in forward and inverse DCT
|
||||
*/
|
||||
#define C_norm 0.3535533905932737f // 1 / (8^0.5)
|
||||
* Normalization constant that is used in forward and inverse DCT
|
||||
*/
|
||||
#define C_norm 0.3535533905932737f // 1 / (8^0.5)
|
||||
|
||||
/**
|
||||
* Width of data block (2nd kernel)
|
||||
*/
|
||||
* Width of data block (2nd kernel)
|
||||
*/
|
||||
#define KER2_BLOCK_WIDTH 32
|
||||
|
||||
/**
|
||||
* Height of data block (2nd kernel)
|
||||
*/
|
||||
* Height of data block (2nd kernel)
|
||||
*/
|
||||
#define KER2_BLOCK_HEIGHT 16
|
||||
|
||||
/**
|
||||
* LOG2 of width of data block (2nd kernel)
|
||||
*/
|
||||
* LOG2 of width of data block (2nd kernel)
|
||||
*/
|
||||
#define KER2_BW_LOG2 5
|
||||
|
||||
/**
|
||||
* LOG2 of height of data block (2nd kernel)
|
||||
*/
|
||||
* LOG2 of height of data block (2nd kernel)
|
||||
*/
|
||||
#define KER2_BH_LOG2 4
|
||||
|
||||
/**
|
||||
* Stride of shared memory buffer (2nd kernel)
|
||||
*/
|
||||
* Stride of shared memory buffer (2nd kernel)
|
||||
*/
|
||||
#define KER2_SMEMBLOCK_STRIDE (KER2_BLOCK_WIDTH + 1)
|
||||
|
||||
/**
|
||||
@@ -93,39 +93,40 @@ namespace cg = cooperative_groups;
|
||||
*
|
||||
* \return None
|
||||
*/
|
||||
__device__ void CUDAsubroutineInplaceDCTvector(float *Vect0, int Step) {
|
||||
float *Vect1 = Vect0 + Step;
|
||||
float *Vect2 = Vect1 + Step;
|
||||
float *Vect3 = Vect2 + Step;
|
||||
float *Vect4 = Vect3 + Step;
|
||||
float *Vect5 = Vect4 + Step;
|
||||
float *Vect6 = Vect5 + Step;
|
||||
float *Vect7 = Vect6 + Step;
|
||||
__device__ void CUDAsubroutineInplaceDCTvector(float *Vect0, int Step)
|
||||
{
|
||||
float *Vect1 = Vect0 + Step;
|
||||
float *Vect2 = Vect1 + Step;
|
||||
float *Vect3 = Vect2 + Step;
|
||||
float *Vect4 = Vect3 + Step;
|
||||
float *Vect5 = Vect4 + Step;
|
||||
float *Vect6 = Vect5 + Step;
|
||||
float *Vect7 = Vect6 + Step;
|
||||
|
||||
float X07P = (*Vect0) + (*Vect7);
|
||||
float X16P = (*Vect1) + (*Vect6);
|
||||
float X25P = (*Vect2) + (*Vect5);
|
||||
float X34P = (*Vect3) + (*Vect4);
|
||||
float X07P = (*Vect0) + (*Vect7);
|
||||
float X16P = (*Vect1) + (*Vect6);
|
||||
float X25P = (*Vect2) + (*Vect5);
|
||||
float X34P = (*Vect3) + (*Vect4);
|
||||
|
||||
float X07M = (*Vect0) - (*Vect7);
|
||||
float X61M = (*Vect6) - (*Vect1);
|
||||
float X25M = (*Vect2) - (*Vect5);
|
||||
float X43M = (*Vect4) - (*Vect3);
|
||||
float X07M = (*Vect0) - (*Vect7);
|
||||
float X61M = (*Vect6) - (*Vect1);
|
||||
float X25M = (*Vect2) - (*Vect5);
|
||||
float X43M = (*Vect4) - (*Vect3);
|
||||
|
||||
float X07P34PP = X07P + X34P;
|
||||
float X07P34PM = X07P - X34P;
|
||||
float X16P25PP = X16P + X25P;
|
||||
float X16P25PM = X16P - X25P;
|
||||
float X07P34PP = X07P + X34P;
|
||||
float X07P34PM = X07P - X34P;
|
||||
float X16P25PP = X16P + X25P;
|
||||
float X16P25PM = X16P - X25P;
|
||||
|
||||
(*Vect0) = C_norm * (X07P34PP + X16P25PP);
|
||||
(*Vect2) = C_norm * (C_b * X07P34PM + C_e * X16P25PM);
|
||||
(*Vect4) = C_norm * (X07P34PP - X16P25PP);
|
||||
(*Vect6) = C_norm * (C_e * X07P34PM - C_b * X16P25PM);
|
||||
(*Vect0) = C_norm * (X07P34PP + X16P25PP);
|
||||
(*Vect2) = C_norm * (C_b * X07P34PM + C_e * X16P25PM);
|
||||
(*Vect4) = C_norm * (X07P34PP - X16P25PP);
|
||||
(*Vect6) = C_norm * (C_e * X07P34PM - C_b * X16P25PM);
|
||||
|
||||
(*Vect1) = C_norm * (C_a * X07M - C_c * X61M + C_d * X25M - C_f * X43M);
|
||||
(*Vect3) = C_norm * (C_c * X07M + C_f * X61M - C_a * X25M + C_d * X43M);
|
||||
(*Vect5) = C_norm * (C_d * X07M + C_a * X61M + C_f * X25M - C_c * X43M);
|
||||
(*Vect7) = C_norm * (C_f * X07M + C_d * X61M + C_c * X25M + C_a * X43M);
|
||||
(*Vect1) = C_norm * (C_a * X07M - C_c * X61M + C_d * X25M - C_f * X43M);
|
||||
(*Vect3) = C_norm * (C_c * X07M + C_f * X61M - C_a * X25M + C_d * X43M);
|
||||
(*Vect5) = C_norm * (C_d * X07M + C_a * X61M + C_f * X25M - C_c * X43M);
|
||||
(*Vect7) = C_norm * (C_f * X07M + C_d * X61M + C_c * X25M + C_a * X43M);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -137,44 +138,41 @@ __device__ void CUDAsubroutineInplaceDCTvector(float *Vect0, int Step) {
|
||||
*
|
||||
* \return None
|
||||
*/
|
||||
__device__ void CUDAsubroutineInplaceIDCTvector(float *Vect0, int Step) {
|
||||
float *Vect1 = Vect0 + Step;
|
||||
float *Vect2 = Vect1 + Step;
|
||||
float *Vect3 = Vect2 + Step;
|
||||
float *Vect4 = Vect3 + Step;
|
||||
float *Vect5 = Vect4 + Step;
|
||||
float *Vect6 = Vect5 + Step;
|
||||
float *Vect7 = Vect6 + Step;
|
||||
__device__ void CUDAsubroutineInplaceIDCTvector(float *Vect0, int Step)
|
||||
{
|
||||
float *Vect1 = Vect0 + Step;
|
||||
float *Vect2 = Vect1 + Step;
|
||||
float *Vect3 = Vect2 + Step;
|
||||
float *Vect4 = Vect3 + Step;
|
||||
float *Vect5 = Vect4 + Step;
|
||||
float *Vect6 = Vect5 + Step;
|
||||
float *Vect7 = Vect6 + Step;
|
||||
|
||||
float Y04P = (*Vect0) + (*Vect4);
|
||||
float Y2b6eP = C_b * (*Vect2) + C_e * (*Vect6);
|
||||
float Y04P = (*Vect0) + (*Vect4);
|
||||
float Y2b6eP = C_b * (*Vect2) + C_e * (*Vect6);
|
||||
|
||||
float Y04P2b6ePP = Y04P + Y2b6eP;
|
||||
float Y04P2b6ePM = Y04P - Y2b6eP;
|
||||
float Y7f1aP3c5dPP =
|
||||
C_f * (*Vect7) + C_a * (*Vect1) + C_c * (*Vect3) + C_d * (*Vect5);
|
||||
float Y7a1fM3d5cMP =
|
||||
C_a * (*Vect7) - C_f * (*Vect1) + C_d * (*Vect3) - C_c * (*Vect5);
|
||||
float Y04P2b6ePP = Y04P + Y2b6eP;
|
||||
float Y04P2b6ePM = Y04P - Y2b6eP;
|
||||
float Y7f1aP3c5dPP = C_f * (*Vect7) + C_a * (*Vect1) + C_c * (*Vect3) + C_d * (*Vect5);
|
||||
float Y7a1fM3d5cMP = C_a * (*Vect7) - C_f * (*Vect1) + C_d * (*Vect3) - C_c * (*Vect5);
|
||||
|
||||
float Y04M = (*Vect0) - (*Vect4);
|
||||
float Y2e6bM = C_e * (*Vect2) - C_b * (*Vect6);
|
||||
float Y04M = (*Vect0) - (*Vect4);
|
||||
float Y2e6bM = C_e * (*Vect2) - C_b * (*Vect6);
|
||||
|
||||
float Y04M2e6bMP = Y04M + Y2e6bM;
|
||||
float Y04M2e6bMM = Y04M - Y2e6bM;
|
||||
float Y1c7dM3f5aPM =
|
||||
C_c * (*Vect1) - C_d * (*Vect7) - C_f * (*Vect3) - C_a * (*Vect5);
|
||||
float Y1d7cP3a5fMM =
|
||||
C_d * (*Vect1) + C_c * (*Vect7) - C_a * (*Vect3) + C_f * (*Vect5);
|
||||
float Y04M2e6bMP = Y04M + Y2e6bM;
|
||||
float Y04M2e6bMM = Y04M - Y2e6bM;
|
||||
float Y1c7dM3f5aPM = C_c * (*Vect1) - C_d * (*Vect7) - C_f * (*Vect3) - C_a * (*Vect5);
|
||||
float Y1d7cP3a5fMM = C_d * (*Vect1) + C_c * (*Vect7) - C_a * (*Vect3) + C_f * (*Vect5);
|
||||
|
||||
(*Vect0) = C_norm * (Y04P2b6ePP + Y7f1aP3c5dPP);
|
||||
(*Vect7) = C_norm * (Y04P2b6ePP - Y7f1aP3c5dPP);
|
||||
(*Vect4) = C_norm * (Y04P2b6ePM + Y7a1fM3d5cMP);
|
||||
(*Vect3) = C_norm * (Y04P2b6ePM - Y7a1fM3d5cMP);
|
||||
(*Vect0) = C_norm * (Y04P2b6ePP + Y7f1aP3c5dPP);
|
||||
(*Vect7) = C_norm * (Y04P2b6ePP - Y7f1aP3c5dPP);
|
||||
(*Vect4) = C_norm * (Y04P2b6ePM + Y7a1fM3d5cMP);
|
||||
(*Vect3) = C_norm * (Y04P2b6ePM - Y7a1fM3d5cMP);
|
||||
|
||||
(*Vect1) = C_norm * (Y04M2e6bMP + Y1c7dM3f5aPM);
|
||||
(*Vect5) = C_norm * (Y04M2e6bMM - Y1d7cP3a5fMM);
|
||||
(*Vect2) = C_norm * (Y04M2e6bMM + Y1d7cP3a5fMM);
|
||||
(*Vect6) = C_norm * (Y04M2e6bMP - Y1c7dM3f5aPM);
|
||||
(*Vect1) = C_norm * (Y04M2e6bMP + Y1c7dM3f5aPM);
|
||||
(*Vect5) = C_norm * (Y04M2e6bMM - Y1d7cP3a5fMM);
|
||||
(*Vect2) = C_norm * (Y04M2e6bMM + Y1d7cP3a5fMM);
|
||||
(*Vect6) = C_norm * (Y04M2e6bMP - Y1c7dM3f5aPM);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -192,40 +190,38 @@ __device__ void CUDAsubroutineInplaceIDCTvector(float *Vect0, int Step) {
|
||||
* \return None
|
||||
*/
|
||||
|
||||
__global__ void CUDAkernel2DCT(float *dst, float *src, int ImgStride) {
|
||||
// Handle to thread block group
|
||||
cg::thread_block cta = cg::this_thread_block();
|
||||
__global__ void CUDAkernel2DCT(float *dst, float *src, int ImgStride)
|
||||
{
|
||||
// Handle to thread block group
|
||||
cg::thread_block cta = cg::this_thread_block();
|
||||
|
||||
__shared__ float block[KER2_BLOCK_HEIGHT * KER2_SMEMBLOCK_STRIDE];
|
||||
__shared__ float block[KER2_BLOCK_HEIGHT * KER2_SMEMBLOCK_STRIDE];
|
||||
|
||||
int OffsThreadInRow = threadIdx.y * BLOCK_SIZE + threadIdx.x;
|
||||
int OffsThreadInCol = threadIdx.z * BLOCK_SIZE;
|
||||
src += FMUL(blockIdx.y * KER2_BLOCK_HEIGHT + OffsThreadInCol, ImgStride) +
|
||||
blockIdx.x * KER2_BLOCK_WIDTH + OffsThreadInRow;
|
||||
dst += FMUL(blockIdx.y * KER2_BLOCK_HEIGHT + OffsThreadInCol, ImgStride) +
|
||||
blockIdx.x * KER2_BLOCK_WIDTH + OffsThreadInRow;
|
||||
float *bl_ptr =
|
||||
block + OffsThreadInCol * KER2_SMEMBLOCK_STRIDE + OffsThreadInRow;
|
||||
int OffsThreadInRow = threadIdx.y * BLOCK_SIZE + threadIdx.x;
|
||||
int OffsThreadInCol = threadIdx.z * BLOCK_SIZE;
|
||||
src += FMUL(blockIdx.y * KER2_BLOCK_HEIGHT + OffsThreadInCol, ImgStride) + blockIdx.x * KER2_BLOCK_WIDTH
|
||||
+ OffsThreadInRow;
|
||||
dst += FMUL(blockIdx.y * KER2_BLOCK_HEIGHT + OffsThreadInCol, ImgStride) + blockIdx.x * KER2_BLOCK_WIDTH
|
||||
+ OffsThreadInRow;
|
||||
float *bl_ptr = block + OffsThreadInCol * KER2_SMEMBLOCK_STRIDE + OffsThreadInRow;
|
||||
|
||||
#pragma unroll
|
||||
|
||||
for (unsigned int i = 0; i < BLOCK_SIZE; i++)
|
||||
bl_ptr[i * KER2_SMEMBLOCK_STRIDE] = src[i * ImgStride];
|
||||
for (unsigned int i = 0; i < BLOCK_SIZE; i++)
|
||||
bl_ptr[i * KER2_SMEMBLOCK_STRIDE] = src[i * ImgStride];
|
||||
|
||||
cg::sync(cta);
|
||||
// process rows
|
||||
CUDAsubroutineInplaceDCTvector(
|
||||
block + (OffsThreadInCol + threadIdx.x) * KER2_SMEMBLOCK_STRIDE +
|
||||
OffsThreadInRow - threadIdx.x,
|
||||
1);
|
||||
cg::sync(cta);
|
||||
// process rows
|
||||
CUDAsubroutineInplaceDCTvector(
|
||||
block + (OffsThreadInCol + threadIdx.x) * KER2_SMEMBLOCK_STRIDE + OffsThreadInRow - threadIdx.x, 1);
|
||||
|
||||
cg::sync(cta);
|
||||
// process columns
|
||||
CUDAsubroutineInplaceDCTvector(bl_ptr, KER2_SMEMBLOCK_STRIDE);
|
||||
cg::sync(cta);
|
||||
// process columns
|
||||
CUDAsubroutineInplaceDCTvector(bl_ptr, KER2_SMEMBLOCK_STRIDE);
|
||||
|
||||
cg::sync(cta);
|
||||
for (unsigned int i = 0; i < BLOCK_SIZE; i++)
|
||||
dst[i * ImgStride] = bl_ptr[i * KER2_SMEMBLOCK_STRIDE];
|
||||
cg::sync(cta);
|
||||
for (unsigned int i = 0; i < BLOCK_SIZE; i++)
|
||||
dst[i * ImgStride] = bl_ptr[i * KER2_SMEMBLOCK_STRIDE];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -242,39 +238,37 @@ __global__ void CUDAkernel2DCT(float *dst, float *src, int ImgStride) {
|
||||
* \return None
|
||||
*/
|
||||
|
||||
__global__ void CUDAkernel2IDCT(float *dst, float *src, int ImgStride) {
|
||||
// Handle to thread block group
|
||||
cg::thread_block cta = cg::this_thread_block();
|
||||
__global__ void CUDAkernel2IDCT(float *dst, float *src, int ImgStride)
|
||||
{
|
||||
// Handle to thread block group
|
||||
cg::thread_block cta = cg::this_thread_block();
|
||||
|
||||
__shared__ float block[KER2_BLOCK_HEIGHT * KER2_SMEMBLOCK_STRIDE];
|
||||
__shared__ float block[KER2_BLOCK_HEIGHT * KER2_SMEMBLOCK_STRIDE];
|
||||
|
||||
int OffsThreadInRow = threadIdx.y * BLOCK_SIZE + threadIdx.x;
|
||||
int OffsThreadInCol = threadIdx.z * BLOCK_SIZE;
|
||||
src += FMUL(blockIdx.y * KER2_BLOCK_HEIGHT + OffsThreadInCol, ImgStride) +
|
||||
blockIdx.x * KER2_BLOCK_WIDTH + OffsThreadInRow;
|
||||
dst += FMUL(blockIdx.y * KER2_BLOCK_HEIGHT + OffsThreadInCol, ImgStride) +
|
||||
blockIdx.x * KER2_BLOCK_WIDTH + OffsThreadInRow;
|
||||
float *bl_ptr =
|
||||
block + OffsThreadInCol * KER2_SMEMBLOCK_STRIDE + OffsThreadInRow;
|
||||
int OffsThreadInRow = threadIdx.y * BLOCK_SIZE + threadIdx.x;
|
||||
int OffsThreadInCol = threadIdx.z * BLOCK_SIZE;
|
||||
src += FMUL(blockIdx.y * KER2_BLOCK_HEIGHT + OffsThreadInCol, ImgStride) + blockIdx.x * KER2_BLOCK_WIDTH
|
||||
+ OffsThreadInRow;
|
||||
dst += FMUL(blockIdx.y * KER2_BLOCK_HEIGHT + OffsThreadInCol, ImgStride) + blockIdx.x * KER2_BLOCK_WIDTH
|
||||
+ OffsThreadInRow;
|
||||
float *bl_ptr = block + OffsThreadInCol * KER2_SMEMBLOCK_STRIDE + OffsThreadInRow;
|
||||
|
||||
#pragma unroll
|
||||
|
||||
for (unsigned int i = 0; i < BLOCK_SIZE; i++)
|
||||
bl_ptr[i * KER2_SMEMBLOCK_STRIDE] = src[i * ImgStride];
|
||||
for (unsigned int i = 0; i < BLOCK_SIZE; i++)
|
||||
bl_ptr[i * KER2_SMEMBLOCK_STRIDE] = src[i * ImgStride];
|
||||
|
||||
cg::sync(cta);
|
||||
// process rows
|
||||
CUDAsubroutineInplaceIDCTvector(
|
||||
block + (OffsThreadInCol + threadIdx.x) * KER2_SMEMBLOCK_STRIDE +
|
||||
OffsThreadInRow - threadIdx.x,
|
||||
1);
|
||||
cg::sync(cta);
|
||||
// process rows
|
||||
CUDAsubroutineInplaceIDCTvector(
|
||||
block + (OffsThreadInCol + threadIdx.x) * KER2_SMEMBLOCK_STRIDE + OffsThreadInRow - threadIdx.x, 1);
|
||||
|
||||
cg::sync(cta);
|
||||
// process columns
|
||||
CUDAsubroutineInplaceIDCTvector(bl_ptr, KER2_SMEMBLOCK_STRIDE);
|
||||
cg::sync(cta);
|
||||
// process columns
|
||||
CUDAsubroutineInplaceIDCTvector(bl_ptr, KER2_SMEMBLOCK_STRIDE);
|
||||
|
||||
cg::sync(cta);
|
||||
cg::sync(cta);
|
||||
|
||||
for (unsigned int i = 0; i < BLOCK_SIZE; i++)
|
||||
dst[i * ImgStride] = bl_ptr[i * KER2_SMEMBLOCK_STRIDE];
|
||||
for (unsigned int i = 0; i < BLOCK_SIZE; i++)
|
||||
dst[i * ImgStride] = bl_ptr[i * KER2_SMEMBLOCK_STRIDE];
|
||||
}
|
||||
|
||||
@@ -41,18 +41,11 @@ namespace cg = cooperative_groups;
|
||||
#include "Common.h"
|
||||
|
||||
/**
|
||||
* JPEG quality=0_of_12 quantization matrix
|
||||
*/
|
||||
__constant__ short Q[] = {
|
||||
32, 33, 51, 81, 66, 39, 34, 17,
|
||||
33, 36, 48, 47, 28, 23, 12, 12,
|
||||
51, 48, 47, 28, 23, 12, 12, 12,
|
||||
81, 47, 28, 23, 12, 12, 12, 12,
|
||||
66, 28, 23, 12, 12, 12, 12, 12,
|
||||
39, 23, 12, 12, 12, 12, 12, 12,
|
||||
34, 12, 12, 12, 12, 12, 12, 12,
|
||||
17, 12, 12, 12, 12, 12, 12, 12
|
||||
};
|
||||
* JPEG quality=0_of_12 quantization matrix
|
||||
*/
|
||||
__constant__ short Q[] = {32, 33, 51, 81, 66, 39, 34, 17, 33, 36, 48, 47, 28, 23, 12, 12, 51, 48, 47, 28, 23, 12,
|
||||
12, 12, 81, 47, 28, 23, 12, 12, 12, 12, 66, 28, 23, 12, 12, 12, 12, 12, 39, 23, 12, 12,
|
||||
12, 12, 12, 12, 34, 12, 12, 12, 12, 12, 12, 12, 17, 12, 12, 12, 12, 12, 12, 12};
|
||||
|
||||
/**
|
||||
**************************************************************************
|
||||
@@ -64,26 +57,26 @@ __constant__ short Q[] = {
|
||||
*
|
||||
* \return None
|
||||
*/
|
||||
__global__ void CUDAkernelQuantizationFloat(float *SrcDst, int Stride) {
|
||||
// Block index
|
||||
int bx = blockIdx.x;
|
||||
int by = blockIdx.y;
|
||||
__global__ void CUDAkernelQuantizationFloat(float *SrcDst, int Stride)
|
||||
{
|
||||
// Block index
|
||||
int bx = blockIdx.x;
|
||||
int by = blockIdx.y;
|
||||
|
||||
// Thread index (current coefficient)
|
||||
int tx = threadIdx.x;
|
||||
int ty = threadIdx.y;
|
||||
// Thread index (current coefficient)
|
||||
int tx = threadIdx.x;
|
||||
int ty = threadIdx.y;
|
||||
|
||||
// copy current coefficient to the local variable
|
||||
float curCoef =
|
||||
SrcDst[(by * BLOCK_SIZE + ty) * Stride + (bx * BLOCK_SIZE + tx)];
|
||||
float curQuant = (float)Q[ty * BLOCK_SIZE + tx];
|
||||
// copy current coefficient to the local variable
|
||||
float curCoef = SrcDst[(by * BLOCK_SIZE + ty) * Stride + (bx * BLOCK_SIZE + tx)];
|
||||
float curQuant = (float)Q[ty * BLOCK_SIZE + tx];
|
||||
|
||||
// quantize the current coefficient
|
||||
float quantized = roundf(curCoef / curQuant);
|
||||
curCoef = quantized * curQuant;
|
||||
// quantize the current coefficient
|
||||
float quantized = roundf(curCoef / curQuant);
|
||||
curCoef = quantized * curQuant;
|
||||
|
||||
// copy quantized coefficient back to the DCT-plane
|
||||
SrcDst[(by * BLOCK_SIZE + ty) * Stride + (bx * BLOCK_SIZE + tx)] = curCoef;
|
||||
// copy quantized coefficient back to the DCT-plane
|
||||
SrcDst[(by * BLOCK_SIZE + ty) * Stride + (bx * BLOCK_SIZE + tx)] = curCoef;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -96,37 +89,38 @@ __global__ void CUDAkernelQuantizationFloat(float *SrcDst, int Stride) {
|
||||
*
|
||||
* \return None
|
||||
*/
|
||||
__global__ void CUDAkernelQuantizationShort(short *SrcDst, int Stride) {
|
||||
// Handle to thread block group
|
||||
cg::thread_block cta = cg::this_thread_block();
|
||||
// Block index
|
||||
int bx = blockIdx.x;
|
||||
int by = blockIdx.y;
|
||||
__global__ void CUDAkernelQuantizationShort(short *SrcDst, int Stride)
|
||||
{
|
||||
// Handle to thread block group
|
||||
cg::thread_block cta = cg::this_thread_block();
|
||||
// Block index
|
||||
int bx = blockIdx.x;
|
||||
int by = blockIdx.y;
|
||||
|
||||
// Thread index (current coefficient)
|
||||
int tx = threadIdx.x;
|
||||
int ty = threadIdx.y;
|
||||
// Thread index (current coefficient)
|
||||
int tx = threadIdx.x;
|
||||
int ty = threadIdx.y;
|
||||
|
||||
// copy current coefficient to the local variable
|
||||
short curCoef =
|
||||
SrcDst[(by * BLOCK_SIZE + ty) * Stride + (bx * BLOCK_SIZE + tx)];
|
||||
short curQuant = Q[ty * BLOCK_SIZE + tx];
|
||||
// copy current coefficient to the local variable
|
||||
short curCoef = SrcDst[(by * BLOCK_SIZE + ty) * Stride + (bx * BLOCK_SIZE + tx)];
|
||||
short curQuant = Q[ty * BLOCK_SIZE + tx];
|
||||
|
||||
// quantize the current coefficient
|
||||
if (curCoef < 0) {
|
||||
curCoef = -curCoef;
|
||||
curCoef += curQuant >> 1;
|
||||
curCoef /= curQuant;
|
||||
curCoef = -curCoef;
|
||||
} else {
|
||||
curCoef += curQuant >> 1;
|
||||
curCoef /= curQuant;
|
||||
}
|
||||
// quantize the current coefficient
|
||||
if (curCoef < 0) {
|
||||
curCoef = -curCoef;
|
||||
curCoef += curQuant >> 1;
|
||||
curCoef /= curQuant;
|
||||
curCoef = -curCoef;
|
||||
}
|
||||
else {
|
||||
curCoef += curQuant >> 1;
|
||||
curCoef /= curQuant;
|
||||
}
|
||||
|
||||
cg::sync(cta);
|
||||
cg::sync(cta);
|
||||
|
||||
curCoef = curCoef * curQuant;
|
||||
curCoef = curCoef * curQuant;
|
||||
|
||||
// copy quantized coefficient back to the DCT-plane
|
||||
SrcDst[(by * BLOCK_SIZE + ty) * Stride + (bx * BLOCK_SIZE + tx)] = curCoef;
|
||||
// copy quantized coefficient back to the DCT-plane
|
||||
SrcDst[(by * BLOCK_SIZE + ty) * Stride + (bx * BLOCK_SIZE + tx)] = curCoef;
|
||||
}
|
||||
|
||||
@@ -46,33 +46,33 @@ namespace cg = cooperative_groups;
|
||||
#include "Common.h"
|
||||
|
||||
/**
|
||||
* Width of data block (short kernel)
|
||||
*/
|
||||
* Width of data block (short kernel)
|
||||
*/
|
||||
#define KERS_BLOCK_WIDTH 32
|
||||
|
||||
/**
|
||||
* Height of data block (short kernel)
|
||||
*/
|
||||
* Height of data block (short kernel)
|
||||
*/
|
||||
#define KERS_BLOCK_HEIGHT 32
|
||||
|
||||
/**
|
||||
* LOG2 of width of data block (short kernel)
|
||||
*/
|
||||
* LOG2 of width of data block (short kernel)
|
||||
*/
|
||||
#define KERS_BW_LOG2 5
|
||||
|
||||
/**
|
||||
* LOG2 of height of data block (short kernel)
|
||||
*/
|
||||
* LOG2 of height of data block (short kernel)
|
||||
*/
|
||||
#define KERS_BH_LOG2 5
|
||||
|
||||
/**
|
||||
* Stride of shared memory buffer (short kernel)
|
||||
*/
|
||||
* Stride of shared memory buffer (short kernel)
|
||||
*/
|
||||
#define KERS_SMEMBLOCK_STRIDE (KERS_BLOCK_WIDTH + 2)
|
||||
|
||||
/**
|
||||
* Half of data block width (short kernel)
|
||||
*/
|
||||
* Half of data block width (short kernel)
|
||||
*/
|
||||
#define KERS_BLOCK_WIDTH_HALF (KERS_BLOCK_WIDTH / 2)
|
||||
|
||||
#define SIN_1_4 0x5A82
|
||||
@@ -91,25 +91,27 @@ namespace cg = cooperative_groups;
|
||||
#define OCOS_7_16 0x063E
|
||||
|
||||
/**
|
||||
* Package of 2 shorts into 1 int - designed to perform i/o by integers to avoid
|
||||
* bank conflicts
|
||||
*/
|
||||
union PackedShorts {
|
||||
struct __align__(8) {
|
||||
short hShort1;
|
||||
short hShort2;
|
||||
};
|
||||
unsigned int hInt;
|
||||
* Package of 2 shorts into 1 int - designed to perform i/o by integers to avoid
|
||||
* bank conflicts
|
||||
*/
|
||||
union PackedShorts
|
||||
{
|
||||
struct __align__(8)
|
||||
{
|
||||
short hShort1;
|
||||
short hShort2;
|
||||
};
|
||||
unsigned int hInt;
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts fixed point value to short value
|
||||
*/
|
||||
* Converts fixed point value to short value
|
||||
*/
|
||||
__device__ inline short unfixh(int x) { return (short)((x + 0x8000) >> 16); }
|
||||
|
||||
/**
|
||||
* Converts fixed point value to short value
|
||||
*/
|
||||
* Converts fixed point value to short value
|
||||
*/
|
||||
__device__ inline int unfixo(int x) { return (x + 0x1000) >> 13; }
|
||||
|
||||
/**
|
||||
@@ -122,74 +124,75 @@ __device__ inline int unfixo(int x) { return (x + 0x1000) >> 13; }
|
||||
*
|
||||
* \return None
|
||||
*/
|
||||
__device__ void CUDAshortInplaceDCT(short *SrcDst, int Stride) {
|
||||
int in0, in1, in2, in3, in4, in5, in6, in7;
|
||||
int tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
|
||||
int tmp10, tmp11, tmp12, tmp13;
|
||||
int tmp14, tmp15, tmp16, tmp17;
|
||||
int tmp25, tmp26;
|
||||
__device__ void CUDAshortInplaceDCT(short *SrcDst, int Stride)
|
||||
{
|
||||
int in0, in1, in2, in3, in4, in5, in6, in7;
|
||||
int tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
|
||||
int tmp10, tmp11, tmp12, tmp13;
|
||||
int tmp14, tmp15, tmp16, tmp17;
|
||||
int tmp25, tmp26;
|
||||
|
||||
int DoubleStride = Stride << 1;
|
||||
int DoubleStride = Stride << 1;
|
||||
|
||||
short *DstPtr = SrcDst;
|
||||
in0 = *DstPtr;
|
||||
DstPtr += Stride;
|
||||
in1 = *DstPtr;
|
||||
DstPtr += Stride;
|
||||
in2 = *DstPtr;
|
||||
DstPtr += Stride;
|
||||
in3 = *DstPtr;
|
||||
DstPtr += Stride;
|
||||
in4 = *DstPtr;
|
||||
DstPtr += Stride;
|
||||
in5 = *DstPtr;
|
||||
DstPtr += Stride;
|
||||
in6 = *DstPtr;
|
||||
DstPtr += Stride;
|
||||
in7 = *DstPtr;
|
||||
short *DstPtr = SrcDst;
|
||||
in0 = *DstPtr;
|
||||
DstPtr += Stride;
|
||||
in1 = *DstPtr;
|
||||
DstPtr += Stride;
|
||||
in2 = *DstPtr;
|
||||
DstPtr += Stride;
|
||||
in3 = *DstPtr;
|
||||
DstPtr += Stride;
|
||||
in4 = *DstPtr;
|
||||
DstPtr += Stride;
|
||||
in5 = *DstPtr;
|
||||
DstPtr += Stride;
|
||||
in6 = *DstPtr;
|
||||
DstPtr += Stride;
|
||||
in7 = *DstPtr;
|
||||
|
||||
tmp0 = in7 + in0;
|
||||
tmp1 = in6 + in1;
|
||||
tmp2 = in5 + in2;
|
||||
tmp3 = in4 + in3;
|
||||
tmp4 = in3 - in4;
|
||||
tmp5 = in2 - in5;
|
||||
tmp6 = in1 - in6;
|
||||
tmp7 = in0 - in7;
|
||||
tmp0 = in7 + in0;
|
||||
tmp1 = in6 + in1;
|
||||
tmp2 = in5 + in2;
|
||||
tmp3 = in4 + in3;
|
||||
tmp4 = in3 - in4;
|
||||
tmp5 = in2 - in5;
|
||||
tmp6 = in1 - in6;
|
||||
tmp7 = in0 - in7;
|
||||
|
||||
tmp10 = tmp3 + tmp0;
|
||||
tmp11 = tmp2 + tmp1;
|
||||
tmp12 = tmp1 - tmp2;
|
||||
tmp13 = tmp0 - tmp3;
|
||||
tmp10 = tmp3 + tmp0;
|
||||
tmp11 = tmp2 + tmp1;
|
||||
tmp12 = tmp1 - tmp2;
|
||||
tmp13 = tmp0 - tmp3;
|
||||
|
||||
tmp16 = unfixo(FMUL(tmp6 + tmp5, SIN_1_4));
|
||||
tmp15 = unfixo(FMUL(tmp6 - tmp5, COS_1_4));
|
||||
tmp16 = unfixo(FMUL(tmp6 + tmp5, SIN_1_4));
|
||||
tmp15 = unfixo(FMUL(tmp6 - tmp5, COS_1_4));
|
||||
|
||||
tmp4 <<= 2;
|
||||
tmp7 <<= 2;
|
||||
tmp4 <<= 2;
|
||||
tmp7 <<= 2;
|
||||
|
||||
tmp14 = tmp4 + tmp15;
|
||||
tmp25 = tmp4 - tmp15;
|
||||
tmp26 = tmp7 - tmp16;
|
||||
tmp17 = tmp7 + tmp16;
|
||||
tmp14 = tmp4 + tmp15;
|
||||
tmp25 = tmp4 - tmp15;
|
||||
tmp26 = tmp7 - tmp16;
|
||||
tmp17 = tmp7 + tmp16;
|
||||
|
||||
DstPtr = SrcDst;
|
||||
*DstPtr = unfixh(FMUL(tmp10 + tmp11, SIN_1_4));
|
||||
DstPtr += DoubleStride;
|
||||
*DstPtr = unfixh(FMUL(tmp13, COS_1_8) + FMUL(tmp12, SIN_1_8));
|
||||
DstPtr += DoubleStride;
|
||||
*DstPtr = unfixh(FMUL(tmp10 - tmp11, COS_1_4));
|
||||
DstPtr += DoubleStride;
|
||||
*DstPtr = unfixh(FMUL(tmp13, SIN_1_8) - FMUL(tmp12, COS_1_8));
|
||||
DstPtr = SrcDst;
|
||||
*DstPtr = unfixh(FMUL(tmp10 + tmp11, SIN_1_4));
|
||||
DstPtr += DoubleStride;
|
||||
*DstPtr = unfixh(FMUL(tmp13, COS_1_8) + FMUL(tmp12, SIN_1_8));
|
||||
DstPtr += DoubleStride;
|
||||
*DstPtr = unfixh(FMUL(tmp10 - tmp11, COS_1_4));
|
||||
DstPtr += DoubleStride;
|
||||
*DstPtr = unfixh(FMUL(tmp13, SIN_1_8) - FMUL(tmp12, COS_1_8));
|
||||
|
||||
DstPtr = SrcDst + Stride;
|
||||
*DstPtr = unfixh(FMUL(tmp17, OCOS_1_16) + FMUL(tmp14, OSIN_1_16));
|
||||
DstPtr += DoubleStride;
|
||||
*DstPtr = unfixh(FMUL(tmp26, OCOS_3_16) - FMUL(tmp25, OSIN_3_16));
|
||||
DstPtr += DoubleStride;
|
||||
*DstPtr = unfixh(FMUL(tmp26, OCOS_5_16) + FMUL(tmp25, OSIN_5_16));
|
||||
DstPtr += DoubleStride;
|
||||
*DstPtr = unfixh(FMUL(tmp17, OCOS_7_16) - FMUL(tmp14, OSIN_7_16));
|
||||
DstPtr = SrcDst + Stride;
|
||||
*DstPtr = unfixh(FMUL(tmp17, OCOS_1_16) + FMUL(tmp14, OSIN_1_16));
|
||||
DstPtr += DoubleStride;
|
||||
*DstPtr = unfixh(FMUL(tmp26, OCOS_3_16) - FMUL(tmp25, OSIN_3_16));
|
||||
DstPtr += DoubleStride;
|
||||
*DstPtr = unfixh(FMUL(tmp26, OCOS_5_16) + FMUL(tmp25, OSIN_5_16));
|
||||
DstPtr += DoubleStride;
|
||||
*DstPtr = unfixh(FMUL(tmp17, OCOS_7_16) - FMUL(tmp14, OSIN_7_16));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -201,67 +204,68 @@ __device__ void CUDAshortInplaceDCT(short *SrcDst, int Stride) {
|
||||
*
|
||||
* \return None
|
||||
*/
|
||||
__device__ void CUDAshortInplaceDCT(unsigned int *V8) {
|
||||
int in0, in1, in2, in3, in4, in5, in6, in7;
|
||||
int tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
|
||||
int tmp10, tmp11, tmp12, tmp13;
|
||||
int tmp14, tmp15, tmp16, tmp17;
|
||||
int tmp25, tmp26;
|
||||
PackedShorts sh0, sh1, sh2, sh3;
|
||||
__device__ void CUDAshortInplaceDCT(unsigned int *V8)
|
||||
{
|
||||
int in0, in1, in2, in3, in4, in5, in6, in7;
|
||||
int tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
|
||||
int tmp10, tmp11, tmp12, tmp13;
|
||||
int tmp14, tmp15, tmp16, tmp17;
|
||||
int tmp25, tmp26;
|
||||
PackedShorts sh0, sh1, sh2, sh3;
|
||||
|
||||
sh0.hInt = V8[0];
|
||||
sh1.hInt = V8[1];
|
||||
sh2.hInt = V8[2];
|
||||
sh3.hInt = V8[3];
|
||||
in0 = sh0.hShort1;
|
||||
in1 = sh0.hShort2;
|
||||
in2 = sh1.hShort1;
|
||||
in3 = sh1.hShort2;
|
||||
in4 = sh2.hShort1;
|
||||
in5 = sh2.hShort2;
|
||||
in6 = sh3.hShort1;
|
||||
in7 = sh3.hShort2;
|
||||
sh0.hInt = V8[0];
|
||||
sh1.hInt = V8[1];
|
||||
sh2.hInt = V8[2];
|
||||
sh3.hInt = V8[3];
|
||||
in0 = sh0.hShort1;
|
||||
in1 = sh0.hShort2;
|
||||
in2 = sh1.hShort1;
|
||||
in3 = sh1.hShort2;
|
||||
in4 = sh2.hShort1;
|
||||
in5 = sh2.hShort2;
|
||||
in6 = sh3.hShort1;
|
||||
in7 = sh3.hShort2;
|
||||
|
||||
tmp0 = in7 + in0;
|
||||
tmp1 = in6 + in1;
|
||||
tmp2 = in5 + in2;
|
||||
tmp3 = in4 + in3;
|
||||
tmp4 = in3 - in4;
|
||||
tmp5 = in2 - in5;
|
||||
tmp6 = in1 - in6;
|
||||
tmp7 = in0 - in7;
|
||||
tmp0 = in7 + in0;
|
||||
tmp1 = in6 + in1;
|
||||
tmp2 = in5 + in2;
|
||||
tmp3 = in4 + in3;
|
||||
tmp4 = in3 - in4;
|
||||
tmp5 = in2 - in5;
|
||||
tmp6 = in1 - in6;
|
||||
tmp7 = in0 - in7;
|
||||
|
||||
tmp10 = tmp3 + tmp0;
|
||||
tmp11 = tmp2 + tmp1;
|
||||
tmp12 = tmp1 - tmp2;
|
||||
tmp13 = tmp0 - tmp3;
|
||||
tmp10 = tmp3 + tmp0;
|
||||
tmp11 = tmp2 + tmp1;
|
||||
tmp12 = tmp1 - tmp2;
|
||||
tmp13 = tmp0 - tmp3;
|
||||
|
||||
sh0.hShort1 = unfixh(FMUL(tmp10 + tmp11, SIN_1_4));
|
||||
sh2.hShort1 = unfixh(FMUL(tmp10 - tmp11, COS_1_4));
|
||||
sh0.hShort1 = unfixh(FMUL(tmp10 + tmp11, SIN_1_4));
|
||||
sh2.hShort1 = unfixh(FMUL(tmp10 - tmp11, COS_1_4));
|
||||
|
||||
sh1.hShort1 = unfixh(FMUL(tmp13, COS_1_8) + FMUL(tmp12, SIN_1_8));
|
||||
sh3.hShort1 = unfixh(FMUL(tmp13, SIN_1_8) - FMUL(tmp12, COS_1_8));
|
||||
sh1.hShort1 = unfixh(FMUL(tmp13, COS_1_8) + FMUL(tmp12, SIN_1_8));
|
||||
sh3.hShort1 = unfixh(FMUL(tmp13, SIN_1_8) - FMUL(tmp12, COS_1_8));
|
||||
|
||||
tmp16 = unfixo(FMUL(tmp6 + tmp5, SIN_1_4));
|
||||
tmp15 = unfixo(FMUL(tmp6 - tmp5, COS_1_4));
|
||||
tmp16 = unfixo(FMUL(tmp6 + tmp5, SIN_1_4));
|
||||
tmp15 = unfixo(FMUL(tmp6 - tmp5, COS_1_4));
|
||||
|
||||
tmp4 <<= 2;
|
||||
tmp7 <<= 2;
|
||||
tmp4 <<= 2;
|
||||
tmp7 <<= 2;
|
||||
|
||||
tmp14 = tmp4 + tmp15;
|
||||
tmp25 = tmp4 - tmp15;
|
||||
tmp26 = tmp7 - tmp16;
|
||||
tmp17 = tmp7 + tmp16;
|
||||
tmp14 = tmp4 + tmp15;
|
||||
tmp25 = tmp4 - tmp15;
|
||||
tmp26 = tmp7 - tmp16;
|
||||
tmp17 = tmp7 + tmp16;
|
||||
|
||||
sh0.hShort2 = unfixh(FMUL(tmp17, OCOS_1_16) + FMUL(tmp14, OSIN_1_16));
|
||||
sh3.hShort2 = unfixh(FMUL(tmp17, OCOS_7_16) - FMUL(tmp14, OSIN_7_16));
|
||||
sh2.hShort2 = unfixh(FMUL(tmp26, OCOS_5_16) + FMUL(tmp25, OSIN_5_16));
|
||||
sh1.hShort2 = unfixh(FMUL(tmp26, OCOS_3_16) - FMUL(tmp25, OSIN_3_16));
|
||||
sh0.hShort2 = unfixh(FMUL(tmp17, OCOS_1_16) + FMUL(tmp14, OSIN_1_16));
|
||||
sh3.hShort2 = unfixh(FMUL(tmp17, OCOS_7_16) - FMUL(tmp14, OSIN_7_16));
|
||||
sh2.hShort2 = unfixh(FMUL(tmp26, OCOS_5_16) + FMUL(tmp25, OSIN_5_16));
|
||||
sh1.hShort2 = unfixh(FMUL(tmp26, OCOS_3_16) - FMUL(tmp25, OSIN_3_16));
|
||||
|
||||
V8[0] = sh0.hInt;
|
||||
V8[1] = sh1.hInt;
|
||||
V8[2] = sh2.hInt;
|
||||
V8[3] = sh3.hInt;
|
||||
V8[0] = sh0.hInt;
|
||||
V8[1] = sh1.hInt;
|
||||
V8[2] = sh2.hInt;
|
||||
V8[3] = sh3.hInt;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -274,73 +278,74 @@ __device__ void CUDAshortInplaceDCT(unsigned int *V8) {
|
||||
*
|
||||
* \return None
|
||||
*/
|
||||
__device__ void CUDAshortInplaceIDCT(short *SrcDst, int Stride) {
|
||||
int in0, in1, in2, in3, in4, in5, in6, in7;
|
||||
int tmp10, tmp11, tmp12, tmp13;
|
||||
int tmp20, tmp21, tmp22, tmp23;
|
||||
int tmp30, tmp31;
|
||||
int tmp40, tmp41, tmp42, tmp43;
|
||||
int tmp50, tmp51, tmp52, tmp53;
|
||||
__device__ void CUDAshortInplaceIDCT(short *SrcDst, int Stride)
|
||||
{
|
||||
int in0, in1, in2, in3, in4, in5, in6, in7;
|
||||
int tmp10, tmp11, tmp12, tmp13;
|
||||
int tmp20, tmp21, tmp22, tmp23;
|
||||
int tmp30, tmp31;
|
||||
int tmp40, tmp41, tmp42, tmp43;
|
||||
int tmp50, tmp51, tmp52, tmp53;
|
||||
|
||||
short *DstPtr = SrcDst;
|
||||
in0 = *DstPtr;
|
||||
DstPtr += Stride;
|
||||
in1 = *DstPtr;
|
||||
DstPtr += Stride;
|
||||
in2 = *DstPtr;
|
||||
DstPtr += Stride;
|
||||
in3 = *DstPtr;
|
||||
DstPtr += Stride;
|
||||
in4 = *DstPtr;
|
||||
DstPtr += Stride;
|
||||
in5 = *DstPtr;
|
||||
DstPtr += Stride;
|
||||
in6 = *DstPtr;
|
||||
DstPtr += Stride;
|
||||
in7 = *DstPtr;
|
||||
short *DstPtr = SrcDst;
|
||||
in0 = *DstPtr;
|
||||
DstPtr += Stride;
|
||||
in1 = *DstPtr;
|
||||
DstPtr += Stride;
|
||||
in2 = *DstPtr;
|
||||
DstPtr += Stride;
|
||||
in3 = *DstPtr;
|
||||
DstPtr += Stride;
|
||||
in4 = *DstPtr;
|
||||
DstPtr += Stride;
|
||||
in5 = *DstPtr;
|
||||
DstPtr += Stride;
|
||||
in6 = *DstPtr;
|
||||
DstPtr += Stride;
|
||||
in7 = *DstPtr;
|
||||
|
||||
tmp10 = FMUL(in0 + in4, COS_1_4);
|
||||
tmp11 = FMUL(in0 - in4, COS_1_4);
|
||||
tmp12 = FMUL(in2, SIN_1_8) - FMUL(in6, COS_1_8);
|
||||
tmp13 = FMUL(in6, SIN_1_8) + FMUL(in2, COS_1_8);
|
||||
tmp10 = FMUL(in0 + in4, COS_1_4);
|
||||
tmp11 = FMUL(in0 - in4, COS_1_4);
|
||||
tmp12 = FMUL(in2, SIN_1_8) - FMUL(in6, COS_1_8);
|
||||
tmp13 = FMUL(in6, SIN_1_8) + FMUL(in2, COS_1_8);
|
||||
|
||||
tmp20 = tmp10 + tmp13;
|
||||
tmp21 = tmp11 + tmp12;
|
||||
tmp22 = tmp11 - tmp12;
|
||||
tmp23 = tmp10 - tmp13;
|
||||
tmp20 = tmp10 + tmp13;
|
||||
tmp21 = tmp11 + tmp12;
|
||||
tmp22 = tmp11 - tmp12;
|
||||
tmp23 = tmp10 - tmp13;
|
||||
|
||||
tmp30 = unfixo(FMUL(in3 + in5, COS_1_4));
|
||||
tmp31 = unfixo(FMUL(in3 - in5, COS_1_4));
|
||||
tmp30 = unfixo(FMUL(in3 + in5, COS_1_4));
|
||||
tmp31 = unfixo(FMUL(in3 - in5, COS_1_4));
|
||||
|
||||
in1 <<= 2;
|
||||
in7 <<= 2;
|
||||
in1 <<= 2;
|
||||
in7 <<= 2;
|
||||
|
||||
tmp40 = in1 + tmp30;
|
||||
tmp41 = in7 + tmp31;
|
||||
tmp42 = in1 - tmp30;
|
||||
tmp43 = in7 - tmp31;
|
||||
tmp40 = in1 + tmp30;
|
||||
tmp41 = in7 + tmp31;
|
||||
tmp42 = in1 - tmp30;
|
||||
tmp43 = in7 - tmp31;
|
||||
|
||||
tmp50 = FMUL(tmp40, OCOS_1_16) + FMUL(tmp41, OSIN_1_16);
|
||||
tmp51 = FMUL(tmp40, OSIN_1_16) - FMUL(tmp41, OCOS_1_16);
|
||||
tmp52 = FMUL(tmp42, OCOS_5_16) + FMUL(tmp43, OSIN_5_16);
|
||||
tmp53 = FMUL(tmp42, OSIN_5_16) - FMUL(tmp43, OCOS_5_16);
|
||||
tmp50 = FMUL(tmp40, OCOS_1_16) + FMUL(tmp41, OSIN_1_16);
|
||||
tmp51 = FMUL(tmp40, OSIN_1_16) - FMUL(tmp41, OCOS_1_16);
|
||||
tmp52 = FMUL(tmp42, OCOS_5_16) + FMUL(tmp43, OSIN_5_16);
|
||||
tmp53 = FMUL(tmp42, OSIN_5_16) - FMUL(tmp43, OCOS_5_16);
|
||||
|
||||
DstPtr = SrcDst;
|
||||
*DstPtr = unfixh(tmp20 + tmp50);
|
||||
DstPtr += Stride;
|
||||
*DstPtr = unfixh(tmp21 + tmp53);
|
||||
DstPtr += Stride;
|
||||
*DstPtr = unfixh(tmp22 + tmp52);
|
||||
DstPtr += Stride;
|
||||
*DstPtr = unfixh(tmp23 + tmp51);
|
||||
DstPtr += Stride;
|
||||
*DstPtr = unfixh(tmp23 - tmp51);
|
||||
DstPtr += Stride;
|
||||
*DstPtr = unfixh(tmp22 - tmp52);
|
||||
DstPtr += Stride;
|
||||
*DstPtr = unfixh(tmp21 - tmp53);
|
||||
DstPtr += Stride;
|
||||
*DstPtr = unfixh(tmp20 - tmp50);
|
||||
DstPtr = SrcDst;
|
||||
*DstPtr = unfixh(tmp20 + tmp50);
|
||||
DstPtr += Stride;
|
||||
*DstPtr = unfixh(tmp21 + tmp53);
|
||||
DstPtr += Stride;
|
||||
*DstPtr = unfixh(tmp22 + tmp52);
|
||||
DstPtr += Stride;
|
||||
*DstPtr = unfixh(tmp23 + tmp51);
|
||||
DstPtr += Stride;
|
||||
*DstPtr = unfixh(tmp23 - tmp51);
|
||||
DstPtr += Stride;
|
||||
*DstPtr = unfixh(tmp22 - tmp52);
|
||||
DstPtr += Stride;
|
||||
*DstPtr = unfixh(tmp21 - tmp53);
|
||||
DstPtr += Stride;
|
||||
*DstPtr = unfixh(tmp20 - tmp50);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -352,67 +357,68 @@ __device__ void CUDAshortInplaceIDCT(short *SrcDst, int Stride) {
|
||||
*
|
||||
* \return None
|
||||
*/
|
||||
__device__ void CUDAshortInplaceIDCT(unsigned int *V8) {
|
||||
int in0, in1, in2, in3, in4, in5, in6, in7;
|
||||
int tmp10, tmp11, tmp12, tmp13;
|
||||
int tmp20, tmp21, tmp22, tmp23;
|
||||
int tmp30, tmp31;
|
||||
int tmp40, tmp41, tmp42, tmp43;
|
||||
int tmp50, tmp51, tmp52, tmp53;
|
||||
PackedShorts sh0, sh1, sh2, sh3;
|
||||
__device__ void CUDAshortInplaceIDCT(unsigned int *V8)
|
||||
{
|
||||
int in0, in1, in2, in3, in4, in5, in6, in7;
|
||||
int tmp10, tmp11, tmp12, tmp13;
|
||||
int tmp20, tmp21, tmp22, tmp23;
|
||||
int tmp30, tmp31;
|
||||
int tmp40, tmp41, tmp42, tmp43;
|
||||
int tmp50, tmp51, tmp52, tmp53;
|
||||
PackedShorts sh0, sh1, sh2, sh3;
|
||||
|
||||
sh0.hInt = V8[0];
|
||||
sh1.hInt = V8[1];
|
||||
sh2.hInt = V8[2];
|
||||
sh3.hInt = V8[3];
|
||||
in0 = sh0.hShort1;
|
||||
in1 = sh0.hShort2;
|
||||
in2 = sh1.hShort1;
|
||||
in3 = sh1.hShort2;
|
||||
in4 = sh2.hShort1;
|
||||
in5 = sh2.hShort2;
|
||||
in6 = sh3.hShort1;
|
||||
in7 = sh3.hShort2;
|
||||
sh0.hInt = V8[0];
|
||||
sh1.hInt = V8[1];
|
||||
sh2.hInt = V8[2];
|
||||
sh3.hInt = V8[3];
|
||||
in0 = sh0.hShort1;
|
||||
in1 = sh0.hShort2;
|
||||
in2 = sh1.hShort1;
|
||||
in3 = sh1.hShort2;
|
||||
in4 = sh2.hShort1;
|
||||
in5 = sh2.hShort2;
|
||||
in6 = sh3.hShort1;
|
||||
in7 = sh3.hShort2;
|
||||
|
||||
tmp10 = FMUL(in0 + in4, COS_1_4);
|
||||
tmp11 = FMUL(in0 - in4, COS_1_4);
|
||||
tmp12 = FMUL(in2, SIN_1_8) - FMUL(in6, COS_1_8);
|
||||
tmp13 = FMUL(in6, SIN_1_8) + FMUL(in2, COS_1_8);
|
||||
tmp10 = FMUL(in0 + in4, COS_1_4);
|
||||
tmp11 = FMUL(in0 - in4, COS_1_4);
|
||||
tmp12 = FMUL(in2, SIN_1_8) - FMUL(in6, COS_1_8);
|
||||
tmp13 = FMUL(in6, SIN_1_8) + FMUL(in2, COS_1_8);
|
||||
|
||||
tmp20 = tmp10 + tmp13;
|
||||
tmp21 = tmp11 + tmp12;
|
||||
tmp22 = tmp11 - tmp12;
|
||||
tmp23 = tmp10 - tmp13;
|
||||
tmp20 = tmp10 + tmp13;
|
||||
tmp21 = tmp11 + tmp12;
|
||||
tmp22 = tmp11 - tmp12;
|
||||
tmp23 = tmp10 - tmp13;
|
||||
|
||||
tmp30 = unfixo(FMUL(in3 + in5, COS_1_4));
|
||||
tmp31 = unfixo(FMUL(in3 - in5, COS_1_4));
|
||||
tmp30 = unfixo(FMUL(in3 + in5, COS_1_4));
|
||||
tmp31 = unfixo(FMUL(in3 - in5, COS_1_4));
|
||||
|
||||
in1 <<= 2;
|
||||
in7 <<= 2;
|
||||
in1 <<= 2;
|
||||
in7 <<= 2;
|
||||
|
||||
tmp40 = in1 + tmp30;
|
||||
tmp41 = in7 + tmp31;
|
||||
tmp42 = in1 - tmp30;
|
||||
tmp43 = in7 - tmp31;
|
||||
tmp40 = in1 + tmp30;
|
||||
tmp41 = in7 + tmp31;
|
||||
tmp42 = in1 - tmp30;
|
||||
tmp43 = in7 - tmp31;
|
||||
|
||||
tmp50 = FMUL(tmp40, OCOS_1_16) + FMUL(tmp41, OSIN_1_16);
|
||||
tmp51 = FMUL(tmp40, OSIN_1_16) - FMUL(tmp41, OCOS_1_16);
|
||||
tmp52 = FMUL(tmp42, OCOS_5_16) + FMUL(tmp43, OSIN_5_16);
|
||||
tmp53 = FMUL(tmp42, OSIN_5_16) - FMUL(tmp43, OCOS_5_16);
|
||||
tmp50 = FMUL(tmp40, OCOS_1_16) + FMUL(tmp41, OSIN_1_16);
|
||||
tmp51 = FMUL(tmp40, OSIN_1_16) - FMUL(tmp41, OCOS_1_16);
|
||||
tmp52 = FMUL(tmp42, OCOS_5_16) + FMUL(tmp43, OSIN_5_16);
|
||||
tmp53 = FMUL(tmp42, OSIN_5_16) - FMUL(tmp43, OCOS_5_16);
|
||||
|
||||
sh0.hShort1 = unfixh(tmp20 + tmp50);
|
||||
sh0.hShort2 = unfixh(tmp21 + tmp53);
|
||||
sh1.hShort1 = unfixh(tmp22 + tmp52);
|
||||
sh1.hShort2 = unfixh(tmp23 + tmp51);
|
||||
sh2.hShort1 = unfixh(tmp23 - tmp51);
|
||||
sh2.hShort2 = unfixh(tmp22 - tmp52);
|
||||
sh3.hShort1 = unfixh(tmp21 - tmp53);
|
||||
sh3.hShort2 = unfixh(tmp20 - tmp50);
|
||||
sh0.hShort1 = unfixh(tmp20 + tmp50);
|
||||
sh0.hShort2 = unfixh(tmp21 + tmp53);
|
||||
sh1.hShort1 = unfixh(tmp22 + tmp52);
|
||||
sh1.hShort2 = unfixh(tmp23 + tmp51);
|
||||
sh2.hShort1 = unfixh(tmp23 - tmp51);
|
||||
sh2.hShort2 = unfixh(tmp22 - tmp52);
|
||||
sh3.hShort1 = unfixh(tmp21 - tmp53);
|
||||
sh3.hShort2 = unfixh(tmp20 - tmp50);
|
||||
|
||||
V8[0] = sh0.hInt;
|
||||
V8[1] = sh1.hInt;
|
||||
V8[2] = sh2.hInt;
|
||||
V8[3] = sh3.hInt;
|
||||
V8[0] = sh0.hInt;
|
||||
V8[1] = sh1.hInt;
|
||||
V8[2] = sh2.hInt;
|
||||
V8[3] = sh3.hInt;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -431,53 +437,46 @@ __device__ void CUDAshortInplaceIDCT(unsigned int *V8) {
|
||||
*/
|
||||
|
||||
#define IMAD(a, b, c) (((a) * (b)) + (c))
|
||||
#define IMUL(a, b) ((a) * (b))
|
||||
#define IMUL(a, b) ((a) * (b))
|
||||
|
||||
__global__ void CUDAkernelShortDCT(short *SrcDst, int ImgStride) {
|
||||
// Handle to thread block group
|
||||
cg::thread_block cta = cg::this_thread_block();
|
||||
__shared__ short block[KERS_BLOCK_HEIGHT * KERS_SMEMBLOCK_STRIDE];
|
||||
int OffsThreadInRow = FMUL(threadIdx.y, BLOCK_SIZE) + threadIdx.x;
|
||||
int OffsThreadInCol = FMUL(threadIdx.z, BLOCK_SIZE);
|
||||
int OffsThrRowPermuted =
|
||||
(OffsThreadInRow & 0xFFFFFFE0) |
|
||||
((OffsThreadInRow << 1) | (OffsThreadInRow >> 4) & 0x1) & 0x1F;
|
||||
__global__ void CUDAkernelShortDCT(short *SrcDst, int ImgStride)
|
||||
{
|
||||
// Handle to thread block group
|
||||
cg::thread_block cta = cg::this_thread_block();
|
||||
__shared__ short block[KERS_BLOCK_HEIGHT * KERS_SMEMBLOCK_STRIDE];
|
||||
int OffsThreadInRow = FMUL(threadIdx.y, BLOCK_SIZE) + threadIdx.x;
|
||||
int OffsThreadInCol = FMUL(threadIdx.z, BLOCK_SIZE);
|
||||
int OffsThrRowPermuted =
|
||||
(OffsThreadInRow & 0xFFFFFFE0) | ((OffsThreadInRow << 1) | (OffsThreadInRow >> 4) & 0x1) & 0x1F;
|
||||
|
||||
SrcDst +=
|
||||
IMAD(IMAD(blockIdx.y, KERS_BLOCK_HEIGHT, OffsThreadInCol), ImgStride,
|
||||
IMAD(blockIdx.x, KERS_BLOCK_WIDTH, OffsThreadInRow * 2));
|
||||
short *bl_ptr =
|
||||
block + IMAD(OffsThreadInCol, KERS_SMEMBLOCK_STRIDE, OffsThreadInRow * 2);
|
||||
SrcDst += IMAD(IMAD(blockIdx.y, KERS_BLOCK_HEIGHT, OffsThreadInCol),
|
||||
ImgStride,
|
||||
IMAD(blockIdx.x, KERS_BLOCK_WIDTH, OffsThreadInRow * 2));
|
||||
short *bl_ptr = block + IMAD(OffsThreadInCol, KERS_SMEMBLOCK_STRIDE, OffsThreadInRow * 2);
|
||||
|
||||
// load data to shared memory (only first half of threads in each row performs
|
||||
// data moving (each thread moves 2 shorts)
|
||||
if (OffsThreadInRow < KERS_BLOCK_WIDTH_HALF) {
|
||||
// load data to shared memory (only first half of threads in each row performs
|
||||
// data moving (each thread moves 2 shorts)
|
||||
if (OffsThreadInRow < KERS_BLOCK_WIDTH_HALF) {
|
||||
#pragma unroll
|
||||
|
||||
for (int i = 0; i < BLOCK_SIZE; i++)
|
||||
((int *)bl_ptr)[i * (KERS_SMEMBLOCK_STRIDE / 2)] =
|
||||
((int *)SrcDst)[i * (ImgStride / 2)];
|
||||
}
|
||||
for (int i = 0; i < BLOCK_SIZE; i++)
|
||||
((int *)bl_ptr)[i * (KERS_SMEMBLOCK_STRIDE / 2)] = ((int *)SrcDst)[i * (ImgStride / 2)];
|
||||
}
|
||||
|
||||
cg::sync(cta);
|
||||
CUDAshortInplaceDCT(
|
||||
block + OffsThreadInCol * KERS_SMEMBLOCK_STRIDE + OffsThrRowPermuted,
|
||||
KERS_SMEMBLOCK_STRIDE);
|
||||
cg::sync(cta);
|
||||
CUDAshortInplaceDCT((unsigned int *)(block +
|
||||
OffsThreadInRow * KERS_SMEMBLOCK_STRIDE +
|
||||
OffsThreadInCol));
|
||||
cg::sync(cta);
|
||||
cg::sync(cta);
|
||||
CUDAshortInplaceDCT(block + OffsThreadInCol * KERS_SMEMBLOCK_STRIDE + OffsThrRowPermuted, KERS_SMEMBLOCK_STRIDE);
|
||||
cg::sync(cta);
|
||||
CUDAshortInplaceDCT((unsigned int *)(block + OffsThreadInRow * KERS_SMEMBLOCK_STRIDE + OffsThreadInCol));
|
||||
cg::sync(cta);
|
||||
|
||||
// store data to global memory (only first half of threads in each row
|
||||
// performs data moving (each thread moves 2 shorts)
|
||||
if (OffsThreadInRow < KERS_BLOCK_WIDTH_HALF) {
|
||||
// store data to global memory (only first half of threads in each row
|
||||
// performs data moving (each thread moves 2 shorts)
|
||||
if (OffsThreadInRow < KERS_BLOCK_WIDTH_HALF) {
|
||||
#pragma unroll
|
||||
|
||||
for (int i = 0; i < BLOCK_SIZE; i++)
|
||||
((int *)SrcDst)[i * (ImgStride / 2)] =
|
||||
((int *)bl_ptr)[i * (KERS_SMEMBLOCK_STRIDE / 2)];
|
||||
}
|
||||
for (int i = 0; i < BLOCK_SIZE; i++)
|
||||
((int *)SrcDst)[i * (ImgStride / 2)] = ((int *)bl_ptr)[i * (KERS_SMEMBLOCK_STRIDE / 2)];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -495,50 +494,43 @@ __global__ void CUDAkernelShortDCT(short *SrcDst, int ImgStride) {
|
||||
* \return None
|
||||
*/
|
||||
|
||||
__global__ void CUDAkernelShortIDCT(short *SrcDst, int ImgStride) {
|
||||
// Handle to thread block group
|
||||
cg::thread_block cta = cg::this_thread_block();
|
||||
__shared__ short block[KERS_BLOCK_HEIGHT * KERS_SMEMBLOCK_STRIDE];
|
||||
__global__ void CUDAkernelShortIDCT(short *SrcDst, int ImgStride)
|
||||
{
|
||||
// Handle to thread block group
|
||||
cg::thread_block cta = cg::this_thread_block();
|
||||
__shared__ short block[KERS_BLOCK_HEIGHT * KERS_SMEMBLOCK_STRIDE];
|
||||
|
||||
int OffsThreadInRow = IMAD(threadIdx.y, BLOCK_SIZE, threadIdx.x);
|
||||
int OffsThreadInCol = IMUL(threadIdx.z, BLOCK_SIZE);
|
||||
int OffsThrRowPermuted =
|
||||
(OffsThreadInRow & 0xFFFFFFE0) |
|
||||
((OffsThreadInRow << 1) | (OffsThreadInRow >> 4) & 0x1) & 0x1F;
|
||||
int OffsThreadInRow = IMAD(threadIdx.y, BLOCK_SIZE, threadIdx.x);
|
||||
int OffsThreadInCol = IMUL(threadIdx.z, BLOCK_SIZE);
|
||||
int OffsThrRowPermuted =
|
||||
(OffsThreadInRow & 0xFFFFFFE0) | ((OffsThreadInRow << 1) | (OffsThreadInRow >> 4) & 0x1) & 0x1F;
|
||||
|
||||
SrcDst +=
|
||||
IMAD(IMAD(blockIdx.y, KERS_BLOCK_HEIGHT, OffsThreadInCol), ImgStride,
|
||||
IMAD(blockIdx.x, KERS_BLOCK_WIDTH, OffsThreadInRow * 2));
|
||||
short *bl_ptr =
|
||||
block + IMAD(OffsThreadInCol, KERS_SMEMBLOCK_STRIDE, OffsThreadInRow * 2);
|
||||
SrcDst += IMAD(IMAD(blockIdx.y, KERS_BLOCK_HEIGHT, OffsThreadInCol),
|
||||
ImgStride,
|
||||
IMAD(blockIdx.x, KERS_BLOCK_WIDTH, OffsThreadInRow * 2));
|
||||
short *bl_ptr = block + IMAD(OffsThreadInCol, KERS_SMEMBLOCK_STRIDE, OffsThreadInRow * 2);
|
||||
|
||||
// load data to shared memory (only first half of threads in each row performs
|
||||
// data moving (each thread moves 2 shorts)
|
||||
if (OffsThreadInRow < KERS_BLOCK_WIDTH_HALF) {
|
||||
// load data to shared memory (only first half of threads in each row performs
|
||||
// data moving (each thread moves 2 shorts)
|
||||
if (OffsThreadInRow < KERS_BLOCK_WIDTH_HALF) {
|
||||
#pragma unroll
|
||||
|
||||
for (int i = 0; i < BLOCK_SIZE; i++)
|
||||
((int *)bl_ptr)[i * (KERS_SMEMBLOCK_STRIDE / 2)] =
|
||||
((int *)SrcDst)[i * (ImgStride / 2)];
|
||||
}
|
||||
for (int i = 0; i < BLOCK_SIZE; i++)
|
||||
((int *)bl_ptr)[i * (KERS_SMEMBLOCK_STRIDE / 2)] = ((int *)SrcDst)[i * (ImgStride / 2)];
|
||||
}
|
||||
|
||||
cg::sync(cta);
|
||||
CUDAshortInplaceIDCT(
|
||||
block + OffsThreadInCol * KERS_SMEMBLOCK_STRIDE + OffsThrRowPermuted,
|
||||
KERS_SMEMBLOCK_STRIDE);
|
||||
cg::sync(cta);
|
||||
CUDAshortInplaceIDCT(
|
||||
(unsigned int *)(block + OffsThreadInRow * KERS_SMEMBLOCK_STRIDE +
|
||||
OffsThreadInCol));
|
||||
cg::sync(cta);
|
||||
cg::sync(cta);
|
||||
CUDAshortInplaceIDCT(block + OffsThreadInCol * KERS_SMEMBLOCK_STRIDE + OffsThrRowPermuted, KERS_SMEMBLOCK_STRIDE);
|
||||
cg::sync(cta);
|
||||
CUDAshortInplaceIDCT((unsigned int *)(block + OffsThreadInRow * KERS_SMEMBLOCK_STRIDE + OffsThreadInCol));
|
||||
cg::sync(cta);
|
||||
|
||||
// store data to global memory (only first half of threads in each row
|
||||
// performs data moving (each thread moves 2 shorts)
|
||||
if (OffsThreadInRow < KERS_BLOCK_WIDTH_HALF) {
|
||||
// store data to global memory (only first half of threads in each row
|
||||
// performs data moving (each thread moves 2 shorts)
|
||||
if (OffsThreadInRow < KERS_BLOCK_WIDTH_HALF) {
|
||||
#pragma unroll
|
||||
|
||||
for (int i = 0; i < BLOCK_SIZE; i++)
|
||||
((int *)SrcDst)[i * (ImgStride / 2)] =
|
||||
((int *)bl_ptr)[i * (KERS_SMEMBLOCK_STRIDE / 2)];
|
||||
}
|
||||
for (int i = 0; i < BLOCK_SIZE; i++)
|
||||
((int *)SrcDst)[i * (ImgStride / 2)] = ((int *)bl_ptr)[i * (KERS_SMEMBLOCK_STRIDE / 2)];
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -61,163 +61,208 @@ namespace cg = cooperative_groups;
|
||||
//! @param g_pos index of eigenvalue (in ascending order)
|
||||
//! @param precision desired precision of eigenvalues
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
__global__ void bisectKernelLarge_MultIntervals(
|
||||
float *g_d, float *g_s, const unsigned int n, unsigned int *blocks_mult,
|
||||
unsigned int *blocks_mult_sum, float *g_left, float *g_right,
|
||||
unsigned int *g_left_count, unsigned int *g_right_count, float *g_lambda,
|
||||
unsigned int *g_pos, float precision) {
|
||||
// Handle to thread block group
|
||||
cg::thread_block cta = cg::this_thread_block();
|
||||
const unsigned int tid = threadIdx.x;
|
||||
__global__ void bisectKernelLarge_MultIntervals(float *g_d,
|
||||
float *g_s,
|
||||
const unsigned int n,
|
||||
unsigned int *blocks_mult,
|
||||
unsigned int *blocks_mult_sum,
|
||||
float *g_left,
|
||||
float *g_right,
|
||||
unsigned int *g_left_count,
|
||||
unsigned int *g_right_count,
|
||||
float *g_lambda,
|
||||
unsigned int *g_pos,
|
||||
float precision)
|
||||
{
|
||||
// Handle to thread block group
|
||||
cg::thread_block cta = cg::this_thread_block();
|
||||
const unsigned int tid = threadIdx.x;
|
||||
|
||||
// left and right limits of interval
|
||||
__shared__ float s_left[2 * MAX_THREADS_BLOCK];
|
||||
__shared__ float s_right[2 * MAX_THREADS_BLOCK];
|
||||
// left and right limits of interval
|
||||
__shared__ float s_left[2 * MAX_THREADS_BLOCK];
|
||||
__shared__ float s_right[2 * MAX_THREADS_BLOCK];
|
||||
|
||||
// number of eigenvalues smaller than interval limits
|
||||
__shared__ unsigned int s_left_count[2 * MAX_THREADS_BLOCK];
|
||||
__shared__ unsigned int s_right_count[2 * MAX_THREADS_BLOCK];
|
||||
// number of eigenvalues smaller than interval limits
|
||||
__shared__ unsigned int s_left_count[2 * MAX_THREADS_BLOCK];
|
||||
__shared__ unsigned int s_right_count[2 * MAX_THREADS_BLOCK];
|
||||
|
||||
// helper array for chunk compaction of second chunk
|
||||
__shared__ unsigned int s_compaction_list[2 * MAX_THREADS_BLOCK + 1];
|
||||
// compaction list helper for exclusive scan
|
||||
unsigned int *s_compaction_list_exc = s_compaction_list + 1;
|
||||
// helper array for chunk compaction of second chunk
|
||||
__shared__ unsigned int s_compaction_list[2 * MAX_THREADS_BLOCK + 1];
|
||||
// compaction list helper for exclusive scan
|
||||
unsigned int *s_compaction_list_exc = s_compaction_list + 1;
|
||||
|
||||
// flag if all threads are converged
|
||||
__shared__ unsigned int all_threads_converged;
|
||||
// number of active threads
|
||||
__shared__ unsigned int num_threads_active;
|
||||
// number of threads to employ for compaction
|
||||
__shared__ unsigned int num_threads_compaction;
|
||||
// flag if second chunk has to be compacted
|
||||
__shared__ unsigned int compact_second_chunk;
|
||||
// flag if all threads are converged
|
||||
__shared__ unsigned int all_threads_converged;
|
||||
// number of active threads
|
||||
__shared__ unsigned int num_threads_active;
|
||||
// number of threads to employ for compaction
|
||||
__shared__ unsigned int num_threads_compaction;
|
||||
// flag if second chunk has to be compacted
|
||||
__shared__ unsigned int compact_second_chunk;
|
||||
|
||||
// parameters of block of intervals processed by this block of threads
|
||||
__shared__ unsigned int c_block_start;
|
||||
__shared__ unsigned int c_block_end;
|
||||
__shared__ unsigned int c_block_offset_output;
|
||||
// parameters of block of intervals processed by this block of threads
|
||||
__shared__ unsigned int c_block_start;
|
||||
__shared__ unsigned int c_block_end;
|
||||
__shared__ unsigned int c_block_offset_output;
|
||||
|
||||
// midpoint of currently active interval of the thread
|
||||
float mid = 0.0f;
|
||||
// number of eigenvalues smaller than \a mid
|
||||
unsigned int mid_count = 0;
|
||||
// current interval parameter
|
||||
float left;
|
||||
float right;
|
||||
unsigned int left_count;
|
||||
unsigned int right_count;
|
||||
// helper for compaction, keep track which threads have a second child
|
||||
unsigned int is_active_second = 0;
|
||||
// midpoint of currently active interval of the thread
|
||||
float mid = 0.0f;
|
||||
// number of eigenvalues smaller than \a mid
|
||||
unsigned int mid_count = 0;
|
||||
// current interval parameter
|
||||
float left;
|
||||
float right;
|
||||
unsigned int left_count;
|
||||
unsigned int right_count;
|
||||
// helper for compaction, keep track which threads have a second child
|
||||
unsigned int is_active_second = 0;
|
||||
|
||||
// initialize common start conditions
|
||||
if (0 == tid) {
|
||||
c_block_start = blocks_mult[blockIdx.x];
|
||||
c_block_end = blocks_mult[blockIdx.x + 1];
|
||||
c_block_offset_output = blocks_mult_sum[blockIdx.x];
|
||||
|
||||
num_threads_active = c_block_end - c_block_start;
|
||||
s_compaction_list[0] = 0;
|
||||
num_threads_compaction = ceilPow2(num_threads_active);
|
||||
|
||||
all_threads_converged = 1;
|
||||
compact_second_chunk = 0;
|
||||
}
|
||||
|
||||
cg::sync(cta);
|
||||
|
||||
// read data into shared memory
|
||||
if (tid < num_threads_active) {
|
||||
s_left[tid] = g_left[c_block_start + tid];
|
||||
s_right[tid] = g_right[c_block_start + tid];
|
||||
s_left_count[tid] = g_left_count[c_block_start + tid];
|
||||
s_right_count[tid] = g_right_count[c_block_start + tid];
|
||||
}
|
||||
|
||||
cg::sync(cta);
|
||||
|
||||
// do until all threads converged
|
||||
while (true) {
|
||||
// for (int iter=0; iter < 0; iter++) {
|
||||
|
||||
// subdivide interval if currently active and not already converged
|
||||
subdivideActiveInterval(tid, s_left, s_right, s_left_count, s_right_count,
|
||||
num_threads_active, left, right, left_count,
|
||||
right_count, mid, all_threads_converged);
|
||||
|
||||
cg::sync(cta);
|
||||
|
||||
// stop if all eigenvalues have been found
|
||||
if (1 == all_threads_converged) {
|
||||
break;
|
||||
}
|
||||
|
||||
// compute number of eigenvalues smaller than mid for active and not
|
||||
// converged intervals, use all threads for loading data from gmem and
|
||||
// s_left and s_right as scratch space to store the data load from gmem
|
||||
// in shared memory
|
||||
mid_count = computeNumSmallerEigenvalsLarge(g_d, g_s, n, mid, tid,
|
||||
num_threads_active, s_left,
|
||||
s_right, (left == right), cta);
|
||||
|
||||
cg::sync(cta);
|
||||
|
||||
if (tid < num_threads_active) {
|
||||
// store intervals
|
||||
if (left != right) {
|
||||
storeNonEmptyIntervals(tid, num_threads_active, s_left, s_right,
|
||||
s_left_count, s_right_count, left, mid, right,
|
||||
left_count, mid_count, right_count, precision,
|
||||
compact_second_chunk, s_compaction_list_exc,
|
||||
is_active_second);
|
||||
} else {
|
||||
storeIntervalConverged(
|
||||
s_left, s_right, s_left_count, s_right_count, left, mid, right,
|
||||
left_count, mid_count, right_count, s_compaction_list_exc,
|
||||
compact_second_chunk, num_threads_active, is_active_second);
|
||||
}
|
||||
}
|
||||
|
||||
cg::sync(cta);
|
||||
|
||||
// compact second chunk of intervals if any of the threads generated
|
||||
// two child intervals
|
||||
if (1 == compact_second_chunk) {
|
||||
createIndicesCompaction(s_compaction_list_exc, num_threads_compaction,
|
||||
cta);
|
||||
|
||||
compactIntervals(s_left, s_right, s_left_count, s_right_count, mid, right,
|
||||
mid_count, right_count, s_compaction_list,
|
||||
num_threads_active, is_active_second);
|
||||
}
|
||||
|
||||
cg::sync(cta);
|
||||
|
||||
// update state variables
|
||||
// initialize common start conditions
|
||||
if (0 == tid) {
|
||||
num_threads_active += s_compaction_list[num_threads_active];
|
||||
num_threads_compaction = ceilPow2(num_threads_active);
|
||||
c_block_start = blocks_mult[blockIdx.x];
|
||||
c_block_end = blocks_mult[blockIdx.x + 1];
|
||||
c_block_offset_output = blocks_mult_sum[blockIdx.x];
|
||||
|
||||
compact_second_chunk = 0;
|
||||
all_threads_converged = 1;
|
||||
num_threads_active = c_block_end - c_block_start;
|
||||
s_compaction_list[0] = 0;
|
||||
num_threads_compaction = ceilPow2(num_threads_active);
|
||||
|
||||
all_threads_converged = 1;
|
||||
compact_second_chunk = 0;
|
||||
}
|
||||
|
||||
cg::sync(cta);
|
||||
|
||||
// clear
|
||||
s_compaction_list_exc[threadIdx.x] = 0;
|
||||
s_compaction_list_exc[threadIdx.x + blockDim.x] = 0;
|
||||
// read data into shared memory
|
||||
if (tid < num_threads_active) {
|
||||
s_left[tid] = g_left[c_block_start + tid];
|
||||
s_right[tid] = g_right[c_block_start + tid];
|
||||
s_left_count[tid] = g_left_count[c_block_start + tid];
|
||||
s_right_count[tid] = g_right_count[c_block_start + tid];
|
||||
}
|
||||
|
||||
cg::sync(cta);
|
||||
|
||||
} // end until all threads converged
|
||||
// do until all threads converged
|
||||
while (true) {
|
||||
// for (int iter=0; iter < 0; iter++) {
|
||||
|
||||
// write data back to global memory
|
||||
if (tid < num_threads_active) {
|
||||
unsigned int addr = c_block_offset_output + tid;
|
||||
// subdivide interval if currently active and not already converged
|
||||
subdivideActiveInterval(tid,
|
||||
s_left,
|
||||
s_right,
|
||||
s_left_count,
|
||||
s_right_count,
|
||||
num_threads_active,
|
||||
left,
|
||||
right,
|
||||
left_count,
|
||||
right_count,
|
||||
mid,
|
||||
all_threads_converged);
|
||||
|
||||
g_lambda[addr] = s_left[tid];
|
||||
g_pos[addr] = s_right_count[tid];
|
||||
}
|
||||
cg::sync(cta);
|
||||
|
||||
// stop if all eigenvalues have been found
|
||||
if (1 == all_threads_converged) {
|
||||
break;
|
||||
}
|
||||
|
||||
// compute number of eigenvalues smaller than mid for active and not
|
||||
// converged intervals, use all threads for loading data from gmem and
|
||||
// s_left and s_right as scratch space to store the data load from gmem
|
||||
// in shared memory
|
||||
mid_count = computeNumSmallerEigenvalsLarge(
|
||||
g_d, g_s, n, mid, tid, num_threads_active, s_left, s_right, (left == right), cta);
|
||||
|
||||
cg::sync(cta);
|
||||
|
||||
if (tid < num_threads_active) {
|
||||
// store intervals
|
||||
if (left != right) {
|
||||
storeNonEmptyIntervals(tid,
|
||||
num_threads_active,
|
||||
s_left,
|
||||
s_right,
|
||||
s_left_count,
|
||||
s_right_count,
|
||||
left,
|
||||
mid,
|
||||
right,
|
||||
left_count,
|
||||
mid_count,
|
||||
right_count,
|
||||
precision,
|
||||
compact_second_chunk,
|
||||
s_compaction_list_exc,
|
||||
is_active_second);
|
||||
}
|
||||
else {
|
||||
storeIntervalConverged(s_left,
|
||||
s_right,
|
||||
s_left_count,
|
||||
s_right_count,
|
||||
left,
|
||||
mid,
|
||||
right,
|
||||
left_count,
|
||||
mid_count,
|
||||
right_count,
|
||||
s_compaction_list_exc,
|
||||
compact_second_chunk,
|
||||
num_threads_active,
|
||||
is_active_second);
|
||||
}
|
||||
}
|
||||
|
||||
cg::sync(cta);
|
||||
|
||||
// compact second chunk of intervals if any of the threads generated
|
||||
// two child intervals
|
||||
if (1 == compact_second_chunk) {
|
||||
createIndicesCompaction(s_compaction_list_exc, num_threads_compaction, cta);
|
||||
|
||||
compactIntervals(s_left,
|
||||
s_right,
|
||||
s_left_count,
|
||||
s_right_count,
|
||||
mid,
|
||||
right,
|
||||
mid_count,
|
||||
right_count,
|
||||
s_compaction_list,
|
||||
num_threads_active,
|
||||
is_active_second);
|
||||
}
|
||||
|
||||
cg::sync(cta);
|
||||
|
||||
// update state variables
|
||||
if (0 == tid) {
|
||||
num_threads_active += s_compaction_list[num_threads_active];
|
||||
num_threads_compaction = ceilPow2(num_threads_active);
|
||||
|
||||
compact_second_chunk = 0;
|
||||
all_threads_converged = 1;
|
||||
}
|
||||
|
||||
cg::sync(cta);
|
||||
|
||||
// clear
|
||||
s_compaction_list_exc[threadIdx.x] = 0;
|
||||
s_compaction_list_exc[threadIdx.x + blockDim.x] = 0;
|
||||
|
||||
cg::sync(cta);
|
||||
|
||||
} // end until all threads converged
|
||||
|
||||
// write data back to global memory
|
||||
if (tid < num_threads_active) {
|
||||
unsigned int addr = c_block_offset_output + tid;
|
||||
|
||||
g_lambda[addr] = s_left[tid];
|
||||
g_pos[addr] = s_right_count[tid];
|
||||
}
|
||||
}
|
||||
|
||||
#endif // #ifndef _BISECT_KERNEL_LARGE_MULTI_H_
|
||||
#endif // #ifndef _BISECT_KERNEL_LARGE_MULTI_H_
|
||||
|
||||
@@ -57,104 +57,111 @@ namespace cg = cooperative_groups;
|
||||
//! right interval limit
|
||||
//! @param precision desired precision of eigenvalues
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
__global__ void bisectKernelLarge_OneIntervals(
|
||||
float *g_d, float *g_s, const unsigned int n, unsigned int num_intervals,
|
||||
float *g_left, float *g_right, unsigned int *g_pos, float precision) {
|
||||
// Handle to thread block group
|
||||
cg::thread_block cta = cg::this_thread_block();
|
||||
const unsigned int gtid = (blockDim.x * blockIdx.x) + threadIdx.x;
|
||||
__global__ void bisectKernelLarge_OneIntervals(float *g_d,
|
||||
float *g_s,
|
||||
const unsigned int n,
|
||||
unsigned int num_intervals,
|
||||
float *g_left,
|
||||
float *g_right,
|
||||
unsigned int *g_pos,
|
||||
float precision)
|
||||
{
|
||||
// Handle to thread block group
|
||||
cg::thread_block cta = cg::this_thread_block();
|
||||
const unsigned int gtid = (blockDim.x * blockIdx.x) + threadIdx.x;
|
||||
|
||||
__shared__ float s_left_scratch[MAX_THREADS_BLOCK];
|
||||
__shared__ float s_right_scratch[MAX_THREADS_BLOCK];
|
||||
__shared__ float s_left_scratch[MAX_THREADS_BLOCK];
|
||||
__shared__ float s_right_scratch[MAX_THREADS_BLOCK];
|
||||
|
||||
// active interval of thread
|
||||
// left and right limit of current interval
|
||||
float left, right;
|
||||
// number of threads smaller than the right limit (also corresponds to the
|
||||
// global index of the eigenvalues contained in the active interval)
|
||||
unsigned int right_count;
|
||||
// flag if current thread converged
|
||||
unsigned int converged = 0;
|
||||
// midpoint when current interval is subdivided
|
||||
float mid = 0.0f;
|
||||
// number of eigenvalues less than mid
|
||||
unsigned int mid_count = 0;
|
||||
// active interval of thread
|
||||
// left and right limit of current interval
|
||||
float left, right;
|
||||
// number of threads smaller than the right limit (also corresponds to the
|
||||
// global index of the eigenvalues contained in the active interval)
|
||||
unsigned int right_count;
|
||||
// flag if current thread converged
|
||||
unsigned int converged = 0;
|
||||
// midpoint when current interval is subdivided
|
||||
float mid = 0.0f;
|
||||
// number of eigenvalues less than mid
|
||||
unsigned int mid_count = 0;
|
||||
|
||||
// read data from global memory
|
||||
if (gtid < num_intervals) {
|
||||
left = g_left[gtid];
|
||||
right = g_right[gtid];
|
||||
right_count = g_pos[gtid];
|
||||
}
|
||||
|
||||
// flag to determine if all threads converged to eigenvalue
|
||||
__shared__ unsigned int converged_all_threads;
|
||||
|
||||
// initialized shared flag
|
||||
if (0 == threadIdx.x) {
|
||||
converged_all_threads = 0;
|
||||
}
|
||||
|
||||
cg::sync(cta);
|
||||
|
||||
// process until all threads converged to an eigenvalue
|
||||
// while( 0 == converged_all_threads) {
|
||||
while (true) {
|
||||
atomicExch(&converged_all_threads, 1);
|
||||
|
||||
// update midpoint for all active threads
|
||||
if ((gtid < num_intervals) && (0 == converged)) {
|
||||
mid = computeMidpoint(left, right);
|
||||
// read data from global memory
|
||||
if (gtid < num_intervals) {
|
||||
left = g_left[gtid];
|
||||
right = g_right[gtid];
|
||||
right_count = g_pos[gtid];
|
||||
}
|
||||
|
||||
// find number of eigenvalues that are smaller than midpoint
|
||||
mid_count = computeNumSmallerEigenvalsLarge(
|
||||
g_d, g_s, n, mid, gtid, num_intervals, s_left_scratch, s_right_scratch,
|
||||
converged, cta);
|
||||
// flag to determine if all threads converged to eigenvalue
|
||||
__shared__ unsigned int converged_all_threads;
|
||||
|
||||
cg::sync(cta);
|
||||
|
||||
// for all active threads
|
||||
if ((gtid < num_intervals) && (0 == converged)) {
|
||||
// udpate intervals -- always one child interval survives
|
||||
if (right_count == mid_count) {
|
||||
right = mid;
|
||||
} else {
|
||||
left = mid;
|
||||
}
|
||||
|
||||
// check for convergence
|
||||
float t0 = right - left;
|
||||
float t1 = max(abs(right), abs(left)) * precision;
|
||||
|
||||
if (t0 < min(precision, t1)) {
|
||||
float lambda = computeMidpoint(left, right);
|
||||
left = lambda;
|
||||
right = lambda;
|
||||
|
||||
converged = 1;
|
||||
} else {
|
||||
atomicExch(&converged_all_threads, 0);
|
||||
}
|
||||
// initialized shared flag
|
||||
if (0 == threadIdx.x) {
|
||||
converged_all_threads = 0;
|
||||
}
|
||||
|
||||
cg::sync(cta);
|
||||
|
||||
if (1 == converged_all_threads) {
|
||||
break;
|
||||
// process until all threads converged to an eigenvalue
|
||||
// while( 0 == converged_all_threads) {
|
||||
while (true) {
|
||||
atomicExch(&converged_all_threads, 1);
|
||||
|
||||
// update midpoint for all active threads
|
||||
if ((gtid < num_intervals) && (0 == converged)) {
|
||||
mid = computeMidpoint(left, right);
|
||||
}
|
||||
|
||||
// find number of eigenvalues that are smaller than midpoint
|
||||
mid_count = computeNumSmallerEigenvalsLarge(
|
||||
g_d, g_s, n, mid, gtid, num_intervals, s_left_scratch, s_right_scratch, converged, cta);
|
||||
|
||||
cg::sync(cta);
|
||||
|
||||
// for all active threads
|
||||
if ((gtid < num_intervals) && (0 == converged)) {
|
||||
// udpate intervals -- always one child interval survives
|
||||
if (right_count == mid_count) {
|
||||
right = mid;
|
||||
}
|
||||
else {
|
||||
left = mid;
|
||||
}
|
||||
|
||||
// check for convergence
|
||||
float t0 = right - left;
|
||||
float t1 = max(abs(right), abs(left)) * precision;
|
||||
|
||||
if (t0 < min(precision, t1)) {
|
||||
float lambda = computeMidpoint(left, right);
|
||||
left = lambda;
|
||||
right = lambda;
|
||||
|
||||
converged = 1;
|
||||
}
|
||||
else {
|
||||
atomicExch(&converged_all_threads, 0);
|
||||
}
|
||||
}
|
||||
|
||||
cg::sync(cta);
|
||||
|
||||
if (1 == converged_all_threads) {
|
||||
break;
|
||||
}
|
||||
|
||||
cg::sync(cta);
|
||||
}
|
||||
|
||||
// write data back to global memory
|
||||
cg::sync(cta);
|
||||
}
|
||||
|
||||
// write data back to global memory
|
||||
cg::sync(cta);
|
||||
|
||||
if (gtid < num_intervals) {
|
||||
// intervals converged so left and right interval limit are both identical
|
||||
// and identical to the eigenvalue
|
||||
g_left[gtid] = left;
|
||||
}
|
||||
if (gtid < num_intervals) {
|
||||
// intervals converged so left and right interval limit are both identical
|
||||
// and identical to the eigenvalue
|
||||
g_left[gtid] = left;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // #ifndef _BISECT_KERNEL_LARGE_ONEI_H_
|
||||
#endif // #ifndef _BISECT_KERNEL_LARGE_ONEI_H_
|
||||
|
||||
@@ -53,176 +53,219 @@ namespace cg = cooperative_groups;
|
||||
//! @param lu_eig_count number of eigenvalues that are smaller than \a lu
|
||||
//! @param epsilon desired accuracy of eigenvalues to compute
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
__global__ void bisectKernel(float *g_d, float *g_s, const unsigned int n,
|
||||
float *g_left, float *g_right,
|
||||
unsigned int *g_left_count,
|
||||
unsigned int *g_right_count, const float lg,
|
||||
const float ug, const unsigned int lg_eig_count,
|
||||
const unsigned int ug_eig_count, float epsilon) {
|
||||
// Handle to thread block group
|
||||
cg::thread_block cta = cg::this_thread_block();
|
||||
// intervals (store left and right because the subdivision tree is in general
|
||||
// not dense
|
||||
__shared__ float s_left[MAX_THREADS_BLOCK_SMALL_MATRIX];
|
||||
__shared__ float s_right[MAX_THREADS_BLOCK_SMALL_MATRIX];
|
||||
__global__ void bisectKernel(float *g_d,
|
||||
float *g_s,
|
||||
const unsigned int n,
|
||||
float *g_left,
|
||||
float *g_right,
|
||||
unsigned int *g_left_count,
|
||||
unsigned int *g_right_count,
|
||||
const float lg,
|
||||
const float ug,
|
||||
const unsigned int lg_eig_count,
|
||||
const unsigned int ug_eig_count,
|
||||
float epsilon)
|
||||
{
|
||||
// Handle to thread block group
|
||||
cg::thread_block cta = cg::this_thread_block();
|
||||
// intervals (store left and right because the subdivision tree is in general
|
||||
// not dense
|
||||
__shared__ float s_left[MAX_THREADS_BLOCK_SMALL_MATRIX];
|
||||
__shared__ float s_right[MAX_THREADS_BLOCK_SMALL_MATRIX];
|
||||
|
||||
// number of eigenvalues that are smaller than s_left / s_right
|
||||
// (correspondence is realized via indices)
|
||||
__shared__ unsigned int s_left_count[MAX_THREADS_BLOCK_SMALL_MATRIX];
|
||||
__shared__ unsigned int s_right_count[MAX_THREADS_BLOCK_SMALL_MATRIX];
|
||||
// number of eigenvalues that are smaller than s_left / s_right
|
||||
// (correspondence is realized via indices)
|
||||
__shared__ unsigned int s_left_count[MAX_THREADS_BLOCK_SMALL_MATRIX];
|
||||
__shared__ unsigned int s_right_count[MAX_THREADS_BLOCK_SMALL_MATRIX];
|
||||
|
||||
// helper for stream compaction
|
||||
__shared__ unsigned int s_compaction_list[MAX_THREADS_BLOCK_SMALL_MATRIX + 1];
|
||||
// helper for stream compaction
|
||||
__shared__ unsigned int s_compaction_list[MAX_THREADS_BLOCK_SMALL_MATRIX + 1];
|
||||
|
||||
// state variables for whole block
|
||||
// if 0 then compaction of second chunk of child intervals is not necessary
|
||||
// (because all intervals had exactly one non-dead child)
|
||||
__shared__ unsigned int compact_second_chunk;
|
||||
__shared__ unsigned int all_threads_converged;
|
||||
// state variables for whole block
|
||||
// if 0 then compaction of second chunk of child intervals is not necessary
|
||||
// (because all intervals had exactly one non-dead child)
|
||||
__shared__ unsigned int compact_second_chunk;
|
||||
__shared__ unsigned int all_threads_converged;
|
||||
|
||||
// number of currently active threads
|
||||
__shared__ unsigned int num_threads_active;
|
||||
// number of currently active threads
|
||||
__shared__ unsigned int num_threads_active;
|
||||
|
||||
// number of threads to use for stream compaction
|
||||
__shared__ unsigned int num_threads_compaction;
|
||||
// number of threads to use for stream compaction
|
||||
__shared__ unsigned int num_threads_compaction;
|
||||
|
||||
// helper for exclusive scan
|
||||
unsigned int *s_compaction_list_exc = s_compaction_list + 1;
|
||||
// helper for exclusive scan
|
||||
unsigned int *s_compaction_list_exc = s_compaction_list + 1;
|
||||
|
||||
// variables for currently processed interval
|
||||
// left and right limit of active interval
|
||||
float left = 0.0f;
|
||||
float right = 0.0f;
|
||||
unsigned int left_count = 0;
|
||||
unsigned int right_count = 0;
|
||||
// midpoint of active interval
|
||||
float mid = 0.0f;
|
||||
// number of eigenvalues smaller then mid
|
||||
unsigned int mid_count = 0;
|
||||
// affected from compaction
|
||||
unsigned int is_active_second = 0;
|
||||
// variables for currently processed interval
|
||||
// left and right limit of active interval
|
||||
float left = 0.0f;
|
||||
float right = 0.0f;
|
||||
unsigned int left_count = 0;
|
||||
unsigned int right_count = 0;
|
||||
// midpoint of active interval
|
||||
float mid = 0.0f;
|
||||
// number of eigenvalues smaller then mid
|
||||
unsigned int mid_count = 0;
|
||||
// affected from compaction
|
||||
unsigned int is_active_second = 0;
|
||||
|
||||
s_compaction_list[threadIdx.x] = 0;
|
||||
s_left[threadIdx.x] = 0;
|
||||
s_right[threadIdx.x] = 0;
|
||||
s_left_count[threadIdx.x] = 0;
|
||||
s_right_count[threadIdx.x] = 0;
|
||||
|
||||
cg::sync(cta);
|
||||
|
||||
// set up initial configuration
|
||||
if (0 == threadIdx.x) {
|
||||
s_left[0] = lg;
|
||||
s_right[0] = ug;
|
||||
s_left_count[0] = lg_eig_count;
|
||||
s_right_count[0] = ug_eig_count;
|
||||
|
||||
compact_second_chunk = 0;
|
||||
num_threads_active = 1;
|
||||
|
||||
num_threads_compaction = 1;
|
||||
}
|
||||
|
||||
// for all active threads read intervals from the last level
|
||||
// the number of (worst case) active threads per level l is 2^l
|
||||
while (true) {
|
||||
all_threads_converged = 1;
|
||||
cg::sync(cta);
|
||||
|
||||
is_active_second = 0;
|
||||
subdivideActiveInterval(threadIdx.x, s_left, s_right, s_left_count,
|
||||
s_right_count, num_threads_active, left, right,
|
||||
left_count, right_count, mid,
|
||||
all_threads_converged);
|
||||
|
||||
cg::sync(cta);
|
||||
|
||||
// check if done
|
||||
if (1 == all_threads_converged) {
|
||||
break;
|
||||
}
|
||||
|
||||
cg::sync(cta);
|
||||
|
||||
// compute number of eigenvalues smaller than mid
|
||||
// use all threads for reading the necessary matrix data from global
|
||||
// memory
|
||||
// use s_left and s_right as scratch space for diagonal and
|
||||
// superdiagonal of matrix
|
||||
mid_count = computeNumSmallerEigenvals(g_d, g_s, n, mid, threadIdx.x,
|
||||
num_threads_active, s_left, s_right,
|
||||
(left == right), cta);
|
||||
|
||||
cg::sync(cta);
|
||||
|
||||
// store intervals
|
||||
// for all threads store the first child interval in a continuous chunk of
|
||||
// memory, and the second child interval -- if it exists -- in a second
|
||||
// chunk; it is likely that all threads reach convergence up to
|
||||
// \a epsilon at the same level; furthermore, for higher level most / all
|
||||
// threads will have only one child, storing the first child compactly will
|
||||
// (first) avoid to perform a compaction step on the first chunk, (second)
|
||||
// make it for higher levels (when all threads / intervals have
|
||||
// exactly one child) unnecessary to perform a compaction of the second
|
||||
// chunk
|
||||
if (threadIdx.x < num_threads_active) {
|
||||
if (left != right) {
|
||||
// store intervals
|
||||
storeNonEmptyIntervals(threadIdx.x, num_threads_active, s_left, s_right,
|
||||
s_left_count, s_right_count, left, mid, right,
|
||||
left_count, mid_count, right_count, epsilon,
|
||||
compact_second_chunk, s_compaction_list_exc,
|
||||
is_active_second);
|
||||
} else {
|
||||
storeIntervalConverged(
|
||||
s_left, s_right, s_left_count, s_right_count, left, mid, right,
|
||||
left_count, mid_count, right_count, s_compaction_list_exc,
|
||||
compact_second_chunk, num_threads_active, is_active_second);
|
||||
}
|
||||
}
|
||||
|
||||
// necessary so that compact_second_chunk is up-to-date
|
||||
cg::sync(cta);
|
||||
|
||||
// perform compaction of chunk where second children are stored
|
||||
// scan of (num_threads_active / 2) elements, thus at most
|
||||
// (num_threads_active / 4) threads are needed
|
||||
if (compact_second_chunk > 0) {
|
||||
createIndicesCompaction(s_compaction_list_exc, num_threads_compaction,
|
||||
cta);
|
||||
|
||||
compactIntervals(s_left, s_right, s_left_count, s_right_count, mid, right,
|
||||
mid_count, right_count, s_compaction_list,
|
||||
num_threads_active, is_active_second);
|
||||
}
|
||||
s_compaction_list[threadIdx.x] = 0;
|
||||
s_left[threadIdx.x] = 0;
|
||||
s_right[threadIdx.x] = 0;
|
||||
s_left_count[threadIdx.x] = 0;
|
||||
s_right_count[threadIdx.x] = 0;
|
||||
|
||||
cg::sync(cta);
|
||||
|
||||
// set up initial configuration
|
||||
if (0 == threadIdx.x) {
|
||||
// update number of active threads with result of reduction
|
||||
num_threads_active += s_compaction_list[num_threads_active];
|
||||
s_left[0] = lg;
|
||||
s_right[0] = ug;
|
||||
s_left_count[0] = lg_eig_count;
|
||||
s_right_count[0] = ug_eig_count;
|
||||
|
||||
num_threads_compaction = ceilPow2(num_threads_active);
|
||||
compact_second_chunk = 0;
|
||||
num_threads_active = 1;
|
||||
|
||||
compact_second_chunk = 0;
|
||||
num_threads_compaction = 1;
|
||||
}
|
||||
|
||||
// for all active threads read intervals from the last level
|
||||
// the number of (worst case) active threads per level l is 2^l
|
||||
while (true) {
|
||||
all_threads_converged = 1;
|
||||
cg::sync(cta);
|
||||
|
||||
is_active_second = 0;
|
||||
subdivideActiveInterval(threadIdx.x,
|
||||
s_left,
|
||||
s_right,
|
||||
s_left_count,
|
||||
s_right_count,
|
||||
num_threads_active,
|
||||
left,
|
||||
right,
|
||||
left_count,
|
||||
right_count,
|
||||
mid,
|
||||
all_threads_converged);
|
||||
|
||||
cg::sync(cta);
|
||||
|
||||
// check if done
|
||||
if (1 == all_threads_converged) {
|
||||
break;
|
||||
}
|
||||
|
||||
cg::sync(cta);
|
||||
|
||||
// compute number of eigenvalues smaller than mid
|
||||
// use all threads for reading the necessary matrix data from global
|
||||
// memory
|
||||
// use s_left and s_right as scratch space for diagonal and
|
||||
// superdiagonal of matrix
|
||||
mid_count = computeNumSmallerEigenvals(
|
||||
g_d, g_s, n, mid, threadIdx.x, num_threads_active, s_left, s_right, (left == right), cta);
|
||||
|
||||
cg::sync(cta);
|
||||
|
||||
// store intervals
|
||||
// for all threads store the first child interval in a continuous chunk of
|
||||
// memory, and the second child interval -- if it exists -- in a second
|
||||
// chunk; it is likely that all threads reach convergence up to
|
||||
// \a epsilon at the same level; furthermore, for higher level most / all
|
||||
// threads will have only one child, storing the first child compactly will
|
||||
// (first) avoid to perform a compaction step on the first chunk, (second)
|
||||
// make it for higher levels (when all threads / intervals have
|
||||
// exactly one child) unnecessary to perform a compaction of the second
|
||||
// chunk
|
||||
if (threadIdx.x < num_threads_active) {
|
||||
if (left != right) {
|
||||
// store intervals
|
||||
storeNonEmptyIntervals(threadIdx.x,
|
||||
num_threads_active,
|
||||
s_left,
|
||||
s_right,
|
||||
s_left_count,
|
||||
s_right_count,
|
||||
left,
|
||||
mid,
|
||||
right,
|
||||
left_count,
|
||||
mid_count,
|
||||
right_count,
|
||||
epsilon,
|
||||
compact_second_chunk,
|
||||
s_compaction_list_exc,
|
||||
is_active_second);
|
||||
}
|
||||
else {
|
||||
storeIntervalConverged(s_left,
|
||||
s_right,
|
||||
s_left_count,
|
||||
s_right_count,
|
||||
left,
|
||||
mid,
|
||||
right,
|
||||
left_count,
|
||||
mid_count,
|
||||
right_count,
|
||||
s_compaction_list_exc,
|
||||
compact_second_chunk,
|
||||
num_threads_active,
|
||||
is_active_second);
|
||||
}
|
||||
}
|
||||
|
||||
// necessary so that compact_second_chunk is up-to-date
|
||||
cg::sync(cta);
|
||||
|
||||
// perform compaction of chunk where second children are stored
|
||||
// scan of (num_threads_active / 2) elements, thus at most
|
||||
// (num_threads_active / 4) threads are needed
|
||||
if (compact_second_chunk > 0) {
|
||||
createIndicesCompaction(s_compaction_list_exc, num_threads_compaction, cta);
|
||||
|
||||
compactIntervals(s_left,
|
||||
s_right,
|
||||
s_left_count,
|
||||
s_right_count,
|
||||
mid,
|
||||
right,
|
||||
mid_count,
|
||||
right_count,
|
||||
s_compaction_list,
|
||||
num_threads_active,
|
||||
is_active_second);
|
||||
}
|
||||
|
||||
cg::sync(cta);
|
||||
|
||||
if (0 == threadIdx.x) {
|
||||
// update number of active threads with result of reduction
|
||||
num_threads_active += s_compaction_list[num_threads_active];
|
||||
|
||||
num_threads_compaction = ceilPow2(num_threads_active);
|
||||
|
||||
compact_second_chunk = 0;
|
||||
}
|
||||
|
||||
cg::sync(cta);
|
||||
}
|
||||
|
||||
cg::sync(cta);
|
||||
}
|
||||
|
||||
cg::sync(cta);
|
||||
// write resulting intervals to global mem
|
||||
// for all threads write if they have been converged to an eigenvalue to
|
||||
// a separate array
|
||||
|
||||
// write resulting intervals to global mem
|
||||
// for all threads write if they have been converged to an eigenvalue to
|
||||
// a separate array
|
||||
|
||||
// at most n valid intervals
|
||||
if (threadIdx.x < n) {
|
||||
// intervals converged so left and right limit are identical
|
||||
g_left[threadIdx.x] = s_left[threadIdx.x];
|
||||
// left count is sufficient to have global order
|
||||
g_left_count[threadIdx.x] = s_left_count[threadIdx.x];
|
||||
}
|
||||
// at most n valid intervals
|
||||
if (threadIdx.x < n) {
|
||||
// intervals converged so left and right limit are identical
|
||||
g_left[threadIdx.x] = s_left[threadIdx.x];
|
||||
// left count is sufficient to have global order
|
||||
g_left_count[threadIdx.x] = s_left_count[threadIdx.x];
|
||||
}
|
||||
}
|
||||
|
||||
#endif // #ifndef _BISECT_KERNEL_SMALL_H_
|
||||
#endif // #ifndef _BISECT_KERNEL_SMALL_H_
|
||||
|
||||
@@ -28,117 +28,103 @@
|
||||
/* Computation of eigenvalues of a large symmetric, tridiagonal matrix */
|
||||
|
||||
// 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 "bisect_large.cuh"
|
||||
#include "config.h"
|
||||
#include "helper_cuda.h"
|
||||
#include "helper_functions.h"
|
||||
#include "matlab.h"
|
||||
#include "structs.h"
|
||||
#include "util.h"
|
||||
#include "matlab.h"
|
||||
|
||||
#include "bisect_large.cuh"
|
||||
|
||||
// includes, kernels
|
||||
#include "bisect_kernel_large.cuh"
|
||||
#include "bisect_kernel_large_onei.cuh"
|
||||
#include "bisect_kernel_large_multi.cuh"
|
||||
#include "bisect_kernel_large_onei.cuh"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//! Initialize variables and memory for result
|
||||
//! @param result handles to memory
|
||||
//! @param matrix_size size of the matrix
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void initResultDataLargeMatrix(ResultDataLarge &result,
|
||||
const unsigned int mat_size) {
|
||||
// helper variables to initialize memory
|
||||
unsigned int zero = 0;
|
||||
unsigned int mat_size_f = sizeof(float) * mat_size;
|
||||
unsigned int mat_size_ui = sizeof(unsigned int) * mat_size;
|
||||
void initResultDataLargeMatrix(ResultDataLarge &result, const unsigned int mat_size)
|
||||
{
|
||||
// helper variables to initialize memory
|
||||
unsigned int zero = 0;
|
||||
unsigned int mat_size_f = sizeof(float) * mat_size;
|
||||
unsigned int mat_size_ui = sizeof(unsigned int) * mat_size;
|
||||
|
||||
float *tempf = (float *)malloc(mat_size_f);
|
||||
unsigned int *tempui = (unsigned int *)malloc(mat_size_ui);
|
||||
float *tempf = (float *)malloc(mat_size_f);
|
||||
unsigned int *tempui = (unsigned int *)malloc(mat_size_ui);
|
||||
|
||||
for (unsigned int i = 0; i < mat_size; ++i) {
|
||||
tempf[i] = 0.0f;
|
||||
tempui[i] = 0;
|
||||
}
|
||||
for (unsigned int i = 0; i < mat_size; ++i) {
|
||||
tempf[i] = 0.0f;
|
||||
tempui[i] = 0;
|
||||
}
|
||||
|
||||
// number of intervals containing only one eigenvalue after the first step
|
||||
checkCudaErrors(cudaMalloc((void **)&result.g_num_one, sizeof(unsigned int)));
|
||||
checkCudaErrors(cudaMemcpy(result.g_num_one, &zero, sizeof(unsigned int),
|
||||
cudaMemcpyHostToDevice));
|
||||
// number of intervals containing only one eigenvalue after the first step
|
||||
checkCudaErrors(cudaMalloc((void **)&result.g_num_one, sizeof(unsigned int)));
|
||||
checkCudaErrors(cudaMemcpy(result.g_num_one, &zero, sizeof(unsigned int), cudaMemcpyHostToDevice));
|
||||
|
||||
// number of (thread) blocks of intervals with multiple eigenvalues after
|
||||
// the first iteration
|
||||
checkCudaErrors(
|
||||
cudaMalloc((void **)&result.g_num_blocks_mult, sizeof(unsigned int)));
|
||||
checkCudaErrors(cudaMemcpy(result.g_num_blocks_mult, &zero,
|
||||
sizeof(unsigned int), cudaMemcpyHostToDevice));
|
||||
// number of (thread) blocks of intervals with multiple eigenvalues after
|
||||
// the first iteration
|
||||
checkCudaErrors(cudaMalloc((void **)&result.g_num_blocks_mult, sizeof(unsigned int)));
|
||||
checkCudaErrors(cudaMemcpy(result.g_num_blocks_mult, &zero, sizeof(unsigned int), cudaMemcpyHostToDevice));
|
||||
|
||||
checkCudaErrors(cudaMalloc((void **)&result.g_left_one, mat_size_f));
|
||||
checkCudaErrors(cudaMalloc((void **)&result.g_right_one, mat_size_f));
|
||||
checkCudaErrors(cudaMalloc((void **)&result.g_pos_one, mat_size_ui));
|
||||
checkCudaErrors(cudaMalloc((void **)&result.g_left_one, mat_size_f));
|
||||
checkCudaErrors(cudaMalloc((void **)&result.g_right_one, mat_size_f));
|
||||
checkCudaErrors(cudaMalloc((void **)&result.g_pos_one, mat_size_ui));
|
||||
|
||||
checkCudaErrors(cudaMalloc((void **)&result.g_left_mult, mat_size_f));
|
||||
checkCudaErrors(cudaMalloc((void **)&result.g_right_mult, mat_size_f));
|
||||
checkCudaErrors(cudaMalloc((void **)&result.g_left_count_mult, mat_size_ui));
|
||||
checkCudaErrors(cudaMalloc((void **)&result.g_right_count_mult, mat_size_ui));
|
||||
checkCudaErrors(cudaMalloc((void **)&result.g_left_mult, mat_size_f));
|
||||
checkCudaErrors(cudaMalloc((void **)&result.g_right_mult, mat_size_f));
|
||||
checkCudaErrors(cudaMalloc((void **)&result.g_left_count_mult, mat_size_ui));
|
||||
checkCudaErrors(cudaMalloc((void **)&result.g_right_count_mult, mat_size_ui));
|
||||
|
||||
checkCudaErrors(
|
||||
cudaMemcpy(result.g_left_one, tempf, mat_size_f, cudaMemcpyHostToDevice));
|
||||
checkCudaErrors(cudaMemcpy(result.g_right_one, tempf, mat_size_f,
|
||||
cudaMemcpyHostToDevice));
|
||||
checkCudaErrors(cudaMemcpy(result.g_pos_one, tempui, mat_size_ui,
|
||||
cudaMemcpyHostToDevice));
|
||||
checkCudaErrors(cudaMemcpy(result.g_left_one, tempf, mat_size_f, cudaMemcpyHostToDevice));
|
||||
checkCudaErrors(cudaMemcpy(result.g_right_one, tempf, mat_size_f, cudaMemcpyHostToDevice));
|
||||
checkCudaErrors(cudaMemcpy(result.g_pos_one, tempui, mat_size_ui, cudaMemcpyHostToDevice));
|
||||
|
||||
checkCudaErrors(cudaMemcpy(result.g_left_mult, tempf, mat_size_f,
|
||||
cudaMemcpyHostToDevice));
|
||||
checkCudaErrors(cudaMemcpy(result.g_right_mult, tempf, mat_size_f,
|
||||
cudaMemcpyHostToDevice));
|
||||
checkCudaErrors(cudaMemcpy(result.g_left_count_mult, tempui, mat_size_ui,
|
||||
cudaMemcpyHostToDevice));
|
||||
checkCudaErrors(cudaMemcpy(result.g_right_count_mult, tempui, mat_size_ui,
|
||||
cudaMemcpyHostToDevice));
|
||||
checkCudaErrors(cudaMemcpy(result.g_left_mult, tempf, mat_size_f, cudaMemcpyHostToDevice));
|
||||
checkCudaErrors(cudaMemcpy(result.g_right_mult, tempf, mat_size_f, cudaMemcpyHostToDevice));
|
||||
checkCudaErrors(cudaMemcpy(result.g_left_count_mult, tempui, mat_size_ui, cudaMemcpyHostToDevice));
|
||||
checkCudaErrors(cudaMemcpy(result.g_right_count_mult, tempui, mat_size_ui, cudaMemcpyHostToDevice));
|
||||
|
||||
checkCudaErrors(cudaMalloc((void **)&result.g_blocks_mult, mat_size_ui));
|
||||
checkCudaErrors(cudaMemcpy(result.g_blocks_mult, tempui, mat_size_ui,
|
||||
cudaMemcpyHostToDevice));
|
||||
checkCudaErrors(cudaMalloc((void **)&result.g_blocks_mult_sum, mat_size_ui));
|
||||
checkCudaErrors(cudaMemcpy(result.g_blocks_mult_sum, tempui, mat_size_ui,
|
||||
cudaMemcpyHostToDevice));
|
||||
checkCudaErrors(cudaMalloc((void **)&result.g_blocks_mult, mat_size_ui));
|
||||
checkCudaErrors(cudaMemcpy(result.g_blocks_mult, tempui, mat_size_ui, cudaMemcpyHostToDevice));
|
||||
checkCudaErrors(cudaMalloc((void **)&result.g_blocks_mult_sum, mat_size_ui));
|
||||
checkCudaErrors(cudaMemcpy(result.g_blocks_mult_sum, tempui, mat_size_ui, cudaMemcpyHostToDevice));
|
||||
|
||||
checkCudaErrors(cudaMalloc((void **)&result.g_lambda_mult, mat_size_f));
|
||||
checkCudaErrors(cudaMemcpy(result.g_lambda_mult, tempf, mat_size_f,
|
||||
cudaMemcpyHostToDevice));
|
||||
checkCudaErrors(cudaMalloc((void **)&result.g_pos_mult, mat_size_ui));
|
||||
checkCudaErrors(cudaMemcpy(result.g_pos_mult, tempf, mat_size_ui,
|
||||
cudaMemcpyHostToDevice));
|
||||
checkCudaErrors(cudaMalloc((void **)&result.g_lambda_mult, mat_size_f));
|
||||
checkCudaErrors(cudaMemcpy(result.g_lambda_mult, tempf, mat_size_f, cudaMemcpyHostToDevice));
|
||||
checkCudaErrors(cudaMalloc((void **)&result.g_pos_mult, mat_size_ui));
|
||||
checkCudaErrors(cudaMemcpy(result.g_pos_mult, tempf, mat_size_ui, cudaMemcpyHostToDevice));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//! Cleanup result memory
|
||||
//! @param result handles to memory
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void cleanupResultDataLargeMatrix(ResultDataLarge &result) {
|
||||
checkCudaErrors(cudaFree(result.g_num_one));
|
||||
checkCudaErrors(cudaFree(result.g_num_blocks_mult));
|
||||
checkCudaErrors(cudaFree(result.g_left_one));
|
||||
checkCudaErrors(cudaFree(result.g_right_one));
|
||||
checkCudaErrors(cudaFree(result.g_pos_one));
|
||||
checkCudaErrors(cudaFree(result.g_left_mult));
|
||||
checkCudaErrors(cudaFree(result.g_right_mult));
|
||||
checkCudaErrors(cudaFree(result.g_left_count_mult));
|
||||
checkCudaErrors(cudaFree(result.g_right_count_mult));
|
||||
checkCudaErrors(cudaFree(result.g_blocks_mult));
|
||||
checkCudaErrors(cudaFree(result.g_blocks_mult_sum));
|
||||
checkCudaErrors(cudaFree(result.g_lambda_mult));
|
||||
checkCudaErrors(cudaFree(result.g_pos_mult));
|
||||
void cleanupResultDataLargeMatrix(ResultDataLarge &result)
|
||||
{
|
||||
checkCudaErrors(cudaFree(result.g_num_one));
|
||||
checkCudaErrors(cudaFree(result.g_num_blocks_mult));
|
||||
checkCudaErrors(cudaFree(result.g_left_one));
|
||||
checkCudaErrors(cudaFree(result.g_right_one));
|
||||
checkCudaErrors(cudaFree(result.g_pos_one));
|
||||
checkCudaErrors(cudaFree(result.g_left_mult));
|
||||
checkCudaErrors(cudaFree(result.g_right_mult));
|
||||
checkCudaErrors(cudaFree(result.g_left_count_mult));
|
||||
checkCudaErrors(cudaFree(result.g_right_count_mult));
|
||||
checkCudaErrors(cudaFree(result.g_blocks_mult));
|
||||
checkCudaErrors(cudaFree(result.g_blocks_mult_sum));
|
||||
checkCudaErrors(cudaFree(result.g_lambda_mult));
|
||||
checkCudaErrors(cudaFree(result.g_pos_mult));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -151,109 +137,130 @@ void cleanupResultDataLargeMatrix(ResultDataLarge &result) {
|
||||
//! @param ug upper limit of Gerschgorin interval
|
||||
//! @param iterations number of iterations (for timing)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void computeEigenvaluesLargeMatrix(const InputData &input,
|
||||
void computeEigenvaluesLargeMatrix(const InputData &input,
|
||||
const ResultDataLarge &result,
|
||||
const unsigned int mat_size,
|
||||
const float precision, const float lg,
|
||||
const float ug,
|
||||
const unsigned int iterations) {
|
||||
dim3 blocks(1, 1, 1);
|
||||
dim3 threads(MAX_THREADS_BLOCK, 1, 1);
|
||||
const unsigned int mat_size,
|
||||
const float precision,
|
||||
const float lg,
|
||||
const float ug,
|
||||
const unsigned int iterations)
|
||||
{
|
||||
dim3 blocks(1, 1, 1);
|
||||
dim3 threads(MAX_THREADS_BLOCK, 1, 1);
|
||||
|
||||
StopWatchInterface *timer_step1 = NULL;
|
||||
StopWatchInterface *timer_step2_one = NULL;
|
||||
StopWatchInterface *timer_step2_mult = NULL;
|
||||
StopWatchInterface *timer_total = NULL;
|
||||
sdkCreateTimer(&timer_step1);
|
||||
sdkCreateTimer(&timer_step2_one);
|
||||
sdkCreateTimer(&timer_step2_mult);
|
||||
sdkCreateTimer(&timer_total);
|
||||
StopWatchInterface *timer_step1 = NULL;
|
||||
StopWatchInterface *timer_step2_one = NULL;
|
||||
StopWatchInterface *timer_step2_mult = NULL;
|
||||
StopWatchInterface *timer_total = NULL;
|
||||
sdkCreateTimer(&timer_step1);
|
||||
sdkCreateTimer(&timer_step2_one);
|
||||
sdkCreateTimer(&timer_step2_mult);
|
||||
sdkCreateTimer(&timer_total);
|
||||
|
||||
sdkStartTimer(&timer_total);
|
||||
sdkStartTimer(&timer_total);
|
||||
|
||||
// do for multiple iterations to improve timing accuracy
|
||||
for (unsigned int iter = 0; iter < iterations; ++iter) {
|
||||
sdkStartTimer(&timer_step1);
|
||||
bisectKernelLarge<<<blocks, threads>>>(
|
||||
input.g_a, input.g_b, mat_size, lg, ug, 0, mat_size, precision,
|
||||
result.g_num_one, result.g_num_blocks_mult, result.g_left_one,
|
||||
result.g_right_one, result.g_pos_one, result.g_left_mult,
|
||||
result.g_right_mult, result.g_left_count_mult,
|
||||
result.g_right_count_mult, result.g_blocks_mult,
|
||||
result.g_blocks_mult_sum);
|
||||
// do for multiple iterations to improve timing accuracy
|
||||
for (unsigned int iter = 0; iter < iterations; ++iter) {
|
||||
sdkStartTimer(&timer_step1);
|
||||
bisectKernelLarge<<<blocks, threads>>>(input.g_a,
|
||||
input.g_b,
|
||||
mat_size,
|
||||
lg,
|
||||
ug,
|
||||
0,
|
||||
mat_size,
|
||||
precision,
|
||||
result.g_num_one,
|
||||
result.g_num_blocks_mult,
|
||||
result.g_left_one,
|
||||
result.g_right_one,
|
||||
result.g_pos_one,
|
||||
result.g_left_mult,
|
||||
result.g_right_mult,
|
||||
result.g_left_count_mult,
|
||||
result.g_right_count_mult,
|
||||
result.g_blocks_mult,
|
||||
result.g_blocks_mult_sum);
|
||||
|
||||
getLastCudaError("Kernel launch failed.");
|
||||
checkCudaErrors(cudaDeviceSynchronize());
|
||||
sdkStopTimer(&timer_step1);
|
||||
getLastCudaError("Kernel launch failed.");
|
||||
checkCudaErrors(cudaDeviceSynchronize());
|
||||
sdkStopTimer(&timer_step1);
|
||||
|
||||
// get the number of intervals containing one eigenvalue after the first
|
||||
// processing step
|
||||
unsigned int num_one_intervals;
|
||||
checkCudaErrors(cudaMemcpy(&num_one_intervals, result.g_num_one,
|
||||
sizeof(unsigned int), cudaMemcpyDeviceToHost));
|
||||
// get the number of intervals containing one eigenvalue after the first
|
||||
// processing step
|
||||
unsigned int num_one_intervals;
|
||||
checkCudaErrors(cudaMemcpy(&num_one_intervals, result.g_num_one, sizeof(unsigned int), cudaMemcpyDeviceToHost));
|
||||
|
||||
dim3 grid_onei;
|
||||
grid_onei.x = getNumBlocksLinear(num_one_intervals, MAX_THREADS_BLOCK);
|
||||
dim3 threads_onei;
|
||||
// use always max number of available threads to better balance load times
|
||||
// for matrix data
|
||||
threads_onei.x = MAX_THREADS_BLOCK;
|
||||
dim3 grid_onei;
|
||||
grid_onei.x = getNumBlocksLinear(num_one_intervals, MAX_THREADS_BLOCK);
|
||||
dim3 threads_onei;
|
||||
// use always max number of available threads to better balance load times
|
||||
// for matrix data
|
||||
threads_onei.x = MAX_THREADS_BLOCK;
|
||||
|
||||
// compute eigenvalues for intervals that contained only one eigenvalue
|
||||
// after the first processing step
|
||||
sdkStartTimer(&timer_step2_one);
|
||||
// compute eigenvalues for intervals that contained only one eigenvalue
|
||||
// after the first processing step
|
||||
sdkStartTimer(&timer_step2_one);
|
||||
|
||||
bisectKernelLarge_OneIntervals<<<grid_onei, threads_onei>>>(
|
||||
input.g_a, input.g_b, mat_size, num_one_intervals, result.g_left_one,
|
||||
result.g_right_one, result.g_pos_one, precision);
|
||||
bisectKernelLarge_OneIntervals<<<grid_onei, threads_onei>>>(input.g_a,
|
||||
input.g_b,
|
||||
mat_size,
|
||||
num_one_intervals,
|
||||
result.g_left_one,
|
||||
result.g_right_one,
|
||||
result.g_pos_one,
|
||||
precision);
|
||||
|
||||
getLastCudaError("bisectKernelLarge_OneIntervals() FAILED.");
|
||||
checkCudaErrors(cudaDeviceSynchronize());
|
||||
sdkStopTimer(&timer_step2_one);
|
||||
getLastCudaError("bisectKernelLarge_OneIntervals() FAILED.");
|
||||
checkCudaErrors(cudaDeviceSynchronize());
|
||||
sdkStopTimer(&timer_step2_one);
|
||||
|
||||
// process intervals that contained more than one eigenvalue after
|
||||
// the first processing step
|
||||
// process intervals that contained more than one eigenvalue after
|
||||
// the first processing step
|
||||
|
||||
// get the number of blocks of intervals that contain, in total when
|
||||
// each interval contains only one eigenvalue, not more than
|
||||
// MAX_THREADS_BLOCK threads
|
||||
unsigned int num_blocks_mult = 0;
|
||||
checkCudaErrors(cudaMemcpy(&num_blocks_mult, result.g_num_blocks_mult,
|
||||
sizeof(unsigned int), cudaMemcpyDeviceToHost));
|
||||
// get the number of blocks of intervals that contain, in total when
|
||||
// each interval contains only one eigenvalue, not more than
|
||||
// MAX_THREADS_BLOCK threads
|
||||
unsigned int num_blocks_mult = 0;
|
||||
checkCudaErrors(
|
||||
cudaMemcpy(&num_blocks_mult, result.g_num_blocks_mult, sizeof(unsigned int), cudaMemcpyDeviceToHost));
|
||||
|
||||
// setup the execution environment
|
||||
dim3 grid_mult(num_blocks_mult, 1, 1);
|
||||
dim3 threads_mult(MAX_THREADS_BLOCK, 1, 1);
|
||||
// setup the execution environment
|
||||
dim3 grid_mult(num_blocks_mult, 1, 1);
|
||||
dim3 threads_mult(MAX_THREADS_BLOCK, 1, 1);
|
||||
|
||||
sdkStartTimer(&timer_step2_mult);
|
||||
sdkStartTimer(&timer_step2_mult);
|
||||
|
||||
bisectKernelLarge_MultIntervals<<<grid_mult, threads_mult>>>(
|
||||
input.g_a, input.g_b, mat_size, result.g_blocks_mult,
|
||||
result.g_blocks_mult_sum, result.g_left_mult, result.g_right_mult,
|
||||
result.g_left_count_mult, result.g_right_count_mult,
|
||||
result.g_lambda_mult, result.g_pos_mult, precision);
|
||||
bisectKernelLarge_MultIntervals<<<grid_mult, threads_mult>>>(input.g_a,
|
||||
input.g_b,
|
||||
mat_size,
|
||||
result.g_blocks_mult,
|
||||
result.g_blocks_mult_sum,
|
||||
result.g_left_mult,
|
||||
result.g_right_mult,
|
||||
result.g_left_count_mult,
|
||||
result.g_right_count_mult,
|
||||
result.g_lambda_mult,
|
||||
result.g_pos_mult,
|
||||
precision);
|
||||
|
||||
getLastCudaError("bisectKernelLarge_MultIntervals() FAILED.");
|
||||
checkCudaErrors(cudaDeviceSynchronize());
|
||||
sdkStopTimer(&timer_step2_mult);
|
||||
}
|
||||
getLastCudaError("bisectKernelLarge_MultIntervals() FAILED.");
|
||||
checkCudaErrors(cudaDeviceSynchronize());
|
||||
sdkStopTimer(&timer_step2_mult);
|
||||
}
|
||||
|
||||
sdkStopTimer(&timer_total);
|
||||
sdkStopTimer(&timer_total);
|
||||
|
||||
printf("Average time step 1: %f ms\n",
|
||||
sdkGetTimerValue(&timer_step1) / (float)iterations);
|
||||
printf("Average time step 2, one intervals: %f ms\n",
|
||||
sdkGetTimerValue(&timer_step2_one) / (float)iterations);
|
||||
printf("Average time step 2, mult intervals: %f ms\n",
|
||||
sdkGetTimerValue(&timer_step2_mult) / (float)iterations);
|
||||
printf("Average time step 1: %f ms\n", sdkGetTimerValue(&timer_step1) / (float)iterations);
|
||||
printf("Average time step 2, one intervals: %f ms\n", sdkGetTimerValue(&timer_step2_one) / (float)iterations);
|
||||
printf("Average time step 2, mult intervals: %f ms\n", sdkGetTimerValue(&timer_step2_mult) / (float)iterations);
|
||||
|
||||
printf("Average time TOTAL: %f ms\n",
|
||||
sdkGetTimerValue(&timer_total) / (float)iterations);
|
||||
printf("Average time TOTAL: %f ms\n", sdkGetTimerValue(&timer_total) / (float)iterations);
|
||||
|
||||
sdkDeleteTimer(&timer_step1);
|
||||
sdkDeleteTimer(&timer_step2_one);
|
||||
sdkDeleteTimer(&timer_step2_mult);
|
||||
sdkDeleteTimer(&timer_total);
|
||||
sdkDeleteTimer(&timer_step1);
|
||||
sdkDeleteTimer(&timer_step2_one);
|
||||
sdkDeleteTimer(&timer_step2_mult);
|
||||
sdkDeleteTimer(&timer_total);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -264,105 +271,98 @@ void computeEigenvaluesLargeMatrix(const InputData &input,
|
||||
//! @param mat_size matrix size
|
||||
//! @param filename output filename
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool processResultDataLargeMatrix(const InputData &input,
|
||||
bool processResultDataLargeMatrix(const InputData &input,
|
||||
const ResultDataLarge &result,
|
||||
const unsigned int mat_size,
|
||||
const char *filename,
|
||||
const unsigned int user_defined,
|
||||
char *exec_path) {
|
||||
bool bCompareResult = false;
|
||||
const unsigned int mat_size_ui = sizeof(unsigned int) * mat_size;
|
||||
const unsigned int mat_size_f = sizeof(float) * mat_size;
|
||||
const unsigned int mat_size,
|
||||
const char *filename,
|
||||
const unsigned int user_defined,
|
||||
char *exec_path)
|
||||
{
|
||||
bool bCompareResult = false;
|
||||
const unsigned int mat_size_ui = sizeof(unsigned int) * mat_size;
|
||||
const unsigned int mat_size_f = sizeof(float) * mat_size;
|
||||
|
||||
// copy data from intervals that contained more than one eigenvalue after
|
||||
// the first processing step
|
||||
float *lambda_mult = (float *)malloc(sizeof(float) * mat_size);
|
||||
checkCudaErrors(cudaMemcpy(lambda_mult, result.g_lambda_mult,
|
||||
sizeof(float) * mat_size, cudaMemcpyDeviceToHost));
|
||||
unsigned int *pos_mult =
|
||||
(unsigned int *)malloc(sizeof(unsigned int) * mat_size);
|
||||
checkCudaErrors(cudaMemcpy(pos_mult, result.g_pos_mult,
|
||||
sizeof(unsigned int) * mat_size,
|
||||
cudaMemcpyDeviceToHost));
|
||||
// copy data from intervals that contained more than one eigenvalue after
|
||||
// the first processing step
|
||||
float *lambda_mult = (float *)malloc(sizeof(float) * mat_size);
|
||||
checkCudaErrors(cudaMemcpy(lambda_mult, result.g_lambda_mult, sizeof(float) * mat_size, cudaMemcpyDeviceToHost));
|
||||
unsigned int *pos_mult = (unsigned int *)malloc(sizeof(unsigned int) * mat_size);
|
||||
checkCudaErrors(cudaMemcpy(pos_mult, result.g_pos_mult, sizeof(unsigned int) * mat_size, cudaMemcpyDeviceToHost));
|
||||
|
||||
unsigned int *blocks_mult_sum =
|
||||
(unsigned int *)malloc(sizeof(unsigned int) * mat_size);
|
||||
checkCudaErrors(cudaMemcpy(blocks_mult_sum, result.g_blocks_mult_sum,
|
||||
sizeof(unsigned int) * mat_size,
|
||||
cudaMemcpyDeviceToHost));
|
||||
unsigned int *blocks_mult_sum = (unsigned int *)malloc(sizeof(unsigned int) * mat_size);
|
||||
checkCudaErrors(
|
||||
cudaMemcpy(blocks_mult_sum, result.g_blocks_mult_sum, sizeof(unsigned int) * mat_size, cudaMemcpyDeviceToHost));
|
||||
|
||||
unsigned int num_one_intervals;
|
||||
checkCudaErrors(cudaMemcpy(&num_one_intervals, result.g_num_one,
|
||||
sizeof(unsigned int), cudaMemcpyDeviceToHost));
|
||||
unsigned int num_one_intervals;
|
||||
checkCudaErrors(cudaMemcpy(&num_one_intervals, result.g_num_one, sizeof(unsigned int), cudaMemcpyDeviceToHost));
|
||||
|
||||
unsigned int sum_blocks_mult = mat_size - num_one_intervals;
|
||||
unsigned int sum_blocks_mult = mat_size - num_one_intervals;
|
||||
|
||||
// copy data for intervals that contained one eigenvalue after the first
|
||||
// processing step
|
||||
float *left_one = (float *)malloc(mat_size_f);
|
||||
float *right_one = (float *)malloc(mat_size_f);
|
||||
unsigned int *pos_one = (unsigned int *)malloc(mat_size_ui);
|
||||
checkCudaErrors(cudaMemcpy(left_one, result.g_left_one, mat_size_f,
|
||||
cudaMemcpyDeviceToHost));
|
||||
checkCudaErrors(cudaMemcpy(right_one, result.g_right_one, mat_size_f,
|
||||
cudaMemcpyDeviceToHost));
|
||||
checkCudaErrors(cudaMemcpy(pos_one, result.g_pos_one, mat_size_ui,
|
||||
cudaMemcpyDeviceToHost));
|
||||
// copy data for intervals that contained one eigenvalue after the first
|
||||
// processing step
|
||||
float *left_one = (float *)malloc(mat_size_f);
|
||||
float *right_one = (float *)malloc(mat_size_f);
|
||||
unsigned int *pos_one = (unsigned int *)malloc(mat_size_ui);
|
||||
checkCudaErrors(cudaMemcpy(left_one, result.g_left_one, mat_size_f, cudaMemcpyDeviceToHost));
|
||||
checkCudaErrors(cudaMemcpy(right_one, result.g_right_one, mat_size_f, cudaMemcpyDeviceToHost));
|
||||
checkCudaErrors(cudaMemcpy(pos_one, result.g_pos_one, mat_size_ui, cudaMemcpyDeviceToHost));
|
||||
|
||||
// extract eigenvalues
|
||||
float *eigenvals = (float *)malloc(mat_size_f);
|
||||
// extract eigenvalues
|
||||
float *eigenvals = (float *)malloc(mat_size_f);
|
||||
|
||||
// singleton intervals generated in the second step
|
||||
for (unsigned int i = 0; i < sum_blocks_mult; ++i) {
|
||||
eigenvals[pos_mult[i] - 1] = lambda_mult[i];
|
||||
}
|
||||
|
||||
// singleton intervals generated in the first step
|
||||
unsigned int index = 0;
|
||||
|
||||
for (unsigned int i = 0; i < num_one_intervals; ++i, ++index) {
|
||||
eigenvals[pos_one[i] - 1] = left_one[i];
|
||||
}
|
||||
|
||||
if (1 == user_defined) {
|
||||
// store result
|
||||
writeTridiagSymMatlab(filename, input.a, input.b + 1, eigenvals, mat_size);
|
||||
// getLastCudaError( sdkWriteFilef( filename, eigenvals, mat_size, 0.0f));
|
||||
|
||||
printf("User requests non-default argument(s), skipping self-check!\n");
|
||||
bCompareResult = true;
|
||||
} else {
|
||||
// compare with reference solution
|
||||
|
||||
float *reference = NULL;
|
||||
unsigned int input_data_size = 0;
|
||||
|
||||
char *ref_path = sdkFindFilePath("reference.dat", exec_path);
|
||||
assert(NULL != ref_path);
|
||||
sdkReadFile(ref_path, &reference, &input_data_size, false);
|
||||
assert(input_data_size == mat_size);
|
||||
|
||||
// there's an imprecision of Sturm count computation which makes an
|
||||
// additional offset necessary
|
||||
float tolerance = 1.0e-5f + 5.0e-6f;
|
||||
|
||||
if (sdkCompareL2fe(reference, eigenvals, mat_size, tolerance) == true) {
|
||||
bCompareResult = true;
|
||||
} else {
|
||||
bCompareResult = false;
|
||||
// singleton intervals generated in the second step
|
||||
for (unsigned int i = 0; i < sum_blocks_mult; ++i) {
|
||||
eigenvals[pos_mult[i] - 1] = lambda_mult[i];
|
||||
}
|
||||
|
||||
free(ref_path);
|
||||
free(reference);
|
||||
}
|
||||
// singleton intervals generated in the first step
|
||||
unsigned int index = 0;
|
||||
|
||||
freePtr(eigenvals);
|
||||
freePtr(lambda_mult);
|
||||
freePtr(pos_mult);
|
||||
freePtr(blocks_mult_sum);
|
||||
freePtr(left_one);
|
||||
freePtr(right_one);
|
||||
freePtr(pos_one);
|
||||
for (unsigned int i = 0; i < num_one_intervals; ++i, ++index) {
|
||||
eigenvals[pos_one[i] - 1] = left_one[i];
|
||||
}
|
||||
|
||||
return bCompareResult;
|
||||
if (1 == user_defined) {
|
||||
// store result
|
||||
writeTridiagSymMatlab(filename, input.a, input.b + 1, eigenvals, mat_size);
|
||||
// getLastCudaError( sdkWriteFilef( filename, eigenvals, mat_size, 0.0f));
|
||||
|
||||
printf("User requests non-default argument(s), skipping self-check!\n");
|
||||
bCompareResult = true;
|
||||
}
|
||||
else {
|
||||
// compare with reference solution
|
||||
|
||||
float *reference = NULL;
|
||||
unsigned int input_data_size = 0;
|
||||
|
||||
char *ref_path = sdkFindFilePath("reference.dat", exec_path);
|
||||
assert(NULL != ref_path);
|
||||
sdkReadFile(ref_path, &reference, &input_data_size, false);
|
||||
assert(input_data_size == mat_size);
|
||||
|
||||
// there's an imprecision of Sturm count computation which makes an
|
||||
// additional offset necessary
|
||||
float tolerance = 1.0e-5f + 5.0e-6f;
|
||||
|
||||
if (sdkCompareL2fe(reference, eigenvals, mat_size, tolerance) == true) {
|
||||
bCompareResult = true;
|
||||
}
|
||||
else {
|
||||
bCompareResult = false;
|
||||
}
|
||||
|
||||
free(ref_path);
|
||||
free(reference);
|
||||
}
|
||||
|
||||
freePtr(eigenvals);
|
||||
freePtr(lambda_mult);
|
||||
freePtr(pos_mult);
|
||||
freePtr(blocks_mult_sum);
|
||||
freePtr(left_one);
|
||||
freePtr(right_one);
|
||||
freePtr(pos_one);
|
||||
|
||||
return bCompareResult;
|
||||
}
|
||||
|
||||
@@ -30,53 +30,56 @@
|
||||
#ifndef _BISECT_LARGE_CUH_
|
||||
#define _BISECT_LARGE_CUH_
|
||||
|
||||
extern "C" {
|
||||
#include "structs.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//! Run the kernels to compute the eigenvalues for large matrices
|
||||
//! @param input handles to input data
|
||||
//! @param result handles to result data
|
||||
//! @param mat_size matrix size
|
||||
//! @param precision desired precision of eigenvalues
|
||||
//! @param lg lower limit of Gerschgorin interval
|
||||
//! @param ug upper limit of Gerschgorin interval
|
||||
//! @param iterations number of iterations (for timing)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void computeEigenvaluesLargeMatrix(const InputData &input,
|
||||
const ResultDataLarge &result,
|
||||
const unsigned int mat_size,
|
||||
const float precision, const float lg,
|
||||
const float ug,
|
||||
const unsigned int iterations);
|
||||
extern "C"
|
||||
{
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//! Initialize variables and memory for result
|
||||
//! @param result handles to memory
|
||||
//! @param matr_size size of the matrix
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void initResultDataLargeMatrix(ResultDataLarge &result,
|
||||
const unsigned int mat_size);
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//! Run the kernels to compute the eigenvalues for large matrices
|
||||
//! @param input handles to input data
|
||||
//! @param result handles to result data
|
||||
//! @param mat_size matrix size
|
||||
//! @param precision desired precision of eigenvalues
|
||||
//! @param lg lower limit of Gerschgorin interval
|
||||
//! @param ug upper limit of Gerschgorin interval
|
||||
//! @param iterations number of iterations (for timing)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void computeEigenvaluesLargeMatrix(const InputData &input,
|
||||
const ResultDataLarge &result,
|
||||
const unsigned int mat_size,
|
||||
const float precision,
|
||||
const float lg,
|
||||
const float ug,
|
||||
const unsigned int iterations);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//! Cleanup result memory
|
||||
//! @param result handles to memory
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void cleanupResultDataLargeMatrix(ResultDataLarge &result);
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//! Initialize variables and memory for result
|
||||
//! @param result handles to memory
|
||||
//! @param matr_size size of the matrix
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void initResultDataLargeMatrix(ResultDataLarge &result, const unsigned int mat_size);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//! Process the result, that is obtain result from device and do simple sanity
|
||||
//! checking
|
||||
//! @param input handles to input data
|
||||
//! @param result handles to result data
|
||||
//! @param mat_size matrix size
|
||||
//! @param filename output filename
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool processResultDataLargeMatrix(const InputData &input,
|
||||
const ResultDataLarge &result,
|
||||
const unsigned int mat_size,
|
||||
const char *filename,
|
||||
const unsigned int user_defined,
|
||||
char *exec_path);
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//! Cleanup result memory
|
||||
//! @param result handles to memory
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void cleanupResultDataLargeMatrix(ResultDataLarge &result);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//! Process the result, that is obtain result from device and do simple sanity
|
||||
//! checking
|
||||
//! @param input handles to input data
|
||||
//! @param result handles to result data
|
||||
//! @param mat_size matrix size
|
||||
//! @param filename output filename
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool processResultDataLargeMatrix(const InputData &input,
|
||||
const ResultDataLarge &result,
|
||||
const unsigned int mat_size,
|
||||
const char *filename,
|
||||
const unsigned int user_defined,
|
||||
char *exec_path);
|
||||
};
|
||||
|
||||
#endif // #ifndef _BISECT_LARGE_CUH_
|
||||
#endif // #ifndef _BISECT_LARGE_CUH_
|
||||
|
||||
@@ -28,18 +28,18 @@
|
||||
/* Computation of eigenvalues of a small symmetric, tridiagonal matrix */
|
||||
|
||||
// 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 "config.h"
|
||||
#include "structs.h"
|
||||
#include "helper_cuda.h"
|
||||
#include "helper_functions.h"
|
||||
#include "matlab.h"
|
||||
#include "structs.h"
|
||||
|
||||
// includes, kernels
|
||||
#include "bisect_kernel_small.cuh"
|
||||
@@ -58,32 +58,42 @@
|
||||
//! @param precision desired precision of eigenvalues
|
||||
//! @param iterations number of iterations for timing
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void computeEigenvaluesSmallMatrix(const InputData &input,
|
||||
ResultDataSmall &result,
|
||||
const unsigned int mat_size, const float lg,
|
||||
const float ug, const float precision,
|
||||
const unsigned int iterations) {
|
||||
StopWatchInterface *timer = NULL;
|
||||
sdkCreateTimer(&timer);
|
||||
sdkStartTimer(&timer);
|
||||
void computeEigenvaluesSmallMatrix(const InputData &input,
|
||||
ResultDataSmall &result,
|
||||
const unsigned int mat_size,
|
||||
const float lg,
|
||||
const float ug,
|
||||
const float precision,
|
||||
const unsigned int iterations)
|
||||
{
|
||||
StopWatchInterface *timer = NULL;
|
||||
sdkCreateTimer(&timer);
|
||||
sdkStartTimer(&timer);
|
||||
|
||||
for (unsigned int i = 0; i < iterations; ++i) {
|
||||
dim3 blocks(1, 1, 1);
|
||||
dim3 threads(MAX_THREADS_BLOCK_SMALL_MATRIX, 1, 1);
|
||||
for (unsigned int i = 0; i < iterations; ++i) {
|
||||
dim3 blocks(1, 1, 1);
|
||||
dim3 threads(MAX_THREADS_BLOCK_SMALL_MATRIX, 1, 1);
|
||||
|
||||
bisectKernel<<<blocks, threads>>>(input.g_a, input.g_b, mat_size,
|
||||
result.g_left, result.g_right,
|
||||
result.g_left_count, result.g_right_count,
|
||||
lg, ug, 0, mat_size, precision);
|
||||
}
|
||||
bisectKernel<<<blocks, threads>>>(input.g_a,
|
||||
input.g_b,
|
||||
mat_size,
|
||||
result.g_left,
|
||||
result.g_right,
|
||||
result.g_left_count,
|
||||
result.g_right_count,
|
||||
lg,
|
||||
ug,
|
||||
0,
|
||||
mat_size,
|
||||
precision);
|
||||
}
|
||||
|
||||
checkCudaErrors(cudaDeviceSynchronize());
|
||||
sdkStopTimer(&timer);
|
||||
getLastCudaError("Kernel launch failed");
|
||||
printf("Average time: %f ms (%i iterations)\n",
|
||||
sdkGetTimerValue(&timer) / (float)iterations, iterations);
|
||||
checkCudaErrors(cudaDeviceSynchronize());
|
||||
sdkStopTimer(&timer);
|
||||
getLastCudaError("Kernel launch failed");
|
||||
printf("Average time: %f ms (%i iterations)\n", sdkGetTimerValue(&timer) / (float)iterations, iterations);
|
||||
|
||||
sdkDeleteTimer(&timer);
|
||||
sdkDeleteTimer(&timer);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -91,56 +101,51 @@ void computeEigenvaluesSmallMatrix(const InputData &input,
|
||||
//! @param result handles to the necessary memory
|
||||
//! @param mat_size matrix_size
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void initResultSmallMatrix(ResultDataSmall &result,
|
||||
const unsigned int mat_size) {
|
||||
result.mat_size_f = sizeof(float) * mat_size;
|
||||
result.mat_size_ui = sizeof(unsigned int) * mat_size;
|
||||
void initResultSmallMatrix(ResultDataSmall &result, const unsigned int mat_size)
|
||||
{
|
||||
result.mat_size_f = sizeof(float) * mat_size;
|
||||
result.mat_size_ui = sizeof(unsigned int) * mat_size;
|
||||
|
||||
result.eigenvalues = (float *)malloc(result.mat_size_f);
|
||||
result.eigenvalues = (float *)malloc(result.mat_size_f);
|
||||
|
||||
// helper variables
|
||||
result.zero_f = (float *)malloc(result.mat_size_f);
|
||||
result.zero_ui = (unsigned int *)malloc(result.mat_size_ui);
|
||||
// helper variables
|
||||
result.zero_f = (float *)malloc(result.mat_size_f);
|
||||
result.zero_ui = (unsigned int *)malloc(result.mat_size_ui);
|
||||
|
||||
for (unsigned int i = 0; i < mat_size; ++i) {
|
||||
result.zero_f[i] = 0.0f;
|
||||
result.zero_ui[i] = 0;
|
||||
for (unsigned int i = 0; i < mat_size; ++i) {
|
||||
result.zero_f[i] = 0.0f;
|
||||
result.zero_ui[i] = 0;
|
||||
|
||||
result.eigenvalues[i] = 0.0f;
|
||||
}
|
||||
result.eigenvalues[i] = 0.0f;
|
||||
}
|
||||
|
||||
checkCudaErrors(cudaMalloc((void **)&result.g_left, result.mat_size_f));
|
||||
checkCudaErrors(cudaMalloc((void **)&result.g_right, result.mat_size_f));
|
||||
checkCudaErrors(cudaMalloc((void **)&result.g_left, result.mat_size_f));
|
||||
checkCudaErrors(cudaMalloc((void **)&result.g_right, result.mat_size_f));
|
||||
|
||||
checkCudaErrors(
|
||||
cudaMalloc((void **)&result.g_left_count, result.mat_size_ui));
|
||||
checkCudaErrors(
|
||||
cudaMalloc((void **)&result.g_right_count, result.mat_size_ui));
|
||||
checkCudaErrors(cudaMalloc((void **)&result.g_left_count, result.mat_size_ui));
|
||||
checkCudaErrors(cudaMalloc((void **)&result.g_right_count, result.mat_size_ui));
|
||||
|
||||
// initialize result memory
|
||||
checkCudaErrors(cudaMemcpy(result.g_left, result.zero_f, result.mat_size_f,
|
||||
cudaMemcpyHostToDevice));
|
||||
checkCudaErrors(cudaMemcpy(result.g_right, result.zero_f, result.mat_size_f,
|
||||
cudaMemcpyHostToDevice));
|
||||
checkCudaErrors(cudaMemcpy(result.g_right_count, result.zero_ui,
|
||||
result.mat_size_ui, cudaMemcpyHostToDevice));
|
||||
checkCudaErrors(cudaMemcpy(result.g_left_count, result.zero_ui,
|
||||
result.mat_size_ui, cudaMemcpyHostToDevice));
|
||||
// initialize result memory
|
||||
checkCudaErrors(cudaMemcpy(result.g_left, result.zero_f, result.mat_size_f, cudaMemcpyHostToDevice));
|
||||
checkCudaErrors(cudaMemcpy(result.g_right, result.zero_f, result.mat_size_f, cudaMemcpyHostToDevice));
|
||||
checkCudaErrors(cudaMemcpy(result.g_right_count, result.zero_ui, result.mat_size_ui, cudaMemcpyHostToDevice));
|
||||
checkCudaErrors(cudaMemcpy(result.g_left_count, result.zero_ui, result.mat_size_ui, cudaMemcpyHostToDevice));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//! Cleanup memory and variables for result for small matrices
|
||||
//! @param result handle to variables
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void cleanupResultSmallMatrix(ResultDataSmall &result) {
|
||||
freePtr(result.eigenvalues);
|
||||
freePtr(result.zero_f);
|
||||
freePtr(result.zero_ui);
|
||||
void cleanupResultSmallMatrix(ResultDataSmall &result)
|
||||
{
|
||||
freePtr(result.eigenvalues);
|
||||
freePtr(result.zero_f);
|
||||
freePtr(result.zero_ui);
|
||||
|
||||
checkCudaErrors(cudaFree(result.g_left));
|
||||
checkCudaErrors(cudaFree(result.g_right));
|
||||
checkCudaErrors(cudaFree(result.g_left_count));
|
||||
checkCudaErrors(cudaFree(result.g_right_count));
|
||||
checkCudaErrors(cudaFree(result.g_left));
|
||||
checkCudaErrors(cudaFree(result.g_right));
|
||||
checkCudaErrors(cudaFree(result.g_left_count));
|
||||
checkCudaErrors(cudaFree(result.g_right_count));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -151,32 +156,31 @@ void cleanupResultSmallMatrix(ResultDataSmall &result) {
|
||||
//! @param mat_size matrix size
|
||||
//! @param filename output filename
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void processResultSmallMatrix(const InputData &input,
|
||||
void processResultSmallMatrix(const InputData &input,
|
||||
const ResultDataSmall &result,
|
||||
const unsigned int mat_size,
|
||||
const char *filename) {
|
||||
const unsigned int mat_size_f = sizeof(float) * mat_size;
|
||||
const unsigned int mat_size_ui = sizeof(unsigned int) * mat_size;
|
||||
const unsigned int mat_size,
|
||||
const char *filename)
|
||||
{
|
||||
const unsigned int mat_size_f = sizeof(float) * mat_size;
|
||||
const unsigned int mat_size_ui = sizeof(unsigned int) * mat_size;
|
||||
|
||||
// copy data back to host
|
||||
float *left = (float *)malloc(mat_size_f);
|
||||
unsigned int *left_count = (unsigned int *)malloc(mat_size_ui);
|
||||
// copy data back to host
|
||||
float *left = (float *)malloc(mat_size_f);
|
||||
unsigned int *left_count = (unsigned int *)malloc(mat_size_ui);
|
||||
|
||||
checkCudaErrors(
|
||||
cudaMemcpy(left, result.g_left, mat_size_f, cudaMemcpyDeviceToHost));
|
||||
checkCudaErrors(cudaMemcpy(left_count, result.g_left_count, mat_size_ui,
|
||||
cudaMemcpyDeviceToHost));
|
||||
checkCudaErrors(cudaMemcpy(left, result.g_left, mat_size_f, cudaMemcpyDeviceToHost));
|
||||
checkCudaErrors(cudaMemcpy(left_count, result.g_left_count, mat_size_ui, cudaMemcpyDeviceToHost));
|
||||
|
||||
float *eigenvalues = (float *)malloc(mat_size_f);
|
||||
float *eigenvalues = (float *)malloc(mat_size_f);
|
||||
|
||||
for (unsigned int i = 0; i < mat_size; ++i) {
|
||||
eigenvalues[left_count[i]] = left[i];
|
||||
}
|
||||
for (unsigned int i = 0; i < mat_size; ++i) {
|
||||
eigenvalues[left_count[i]] = left[i];
|
||||
}
|
||||
|
||||
// save result in matlab format
|
||||
writeTridiagSymMatlab(filename, input.a, input.b + 1, eigenvalues, mat_size);
|
||||
// save result in matlab format
|
||||
writeTridiagSymMatlab(filename, input.a, input.b + 1, eigenvalues, mat_size);
|
||||
|
||||
freePtr(left);
|
||||
freePtr(left_count);
|
||||
freePtr(eigenvalues);
|
||||
freePtr(left);
|
||||
freePtr(left_count);
|
||||
freePtr(eigenvalues);
|
||||
}
|
||||
|
||||
@@ -30,51 +30,53 @@
|
||||
#ifndef _BISECT_SMALL_CUH_
|
||||
#define _BISECT_SMALL_CUH_
|
||||
|
||||
extern "C" {
|
||||
extern "C"
|
||||
{
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//! Determine eigenvalues for matrices smaller than MAX_SMALL_MATRIX
|
||||
//! @param TimingIterations number of iterations for timing
|
||||
//! @param input handles to input data of kernel
|
||||
//! @param result handles to result of kernel
|
||||
//! @param mat_size matrix size
|
||||
//! @param lg lower limit of Gerschgorin interval
|
||||
//! @param ug upper limit of Gerschgorin interval
|
||||
//! @param precision desired precision of eigenvalues
|
||||
//! @param iterations number of iterations for timing
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void computeEigenvaluesSmallMatrix(const InputData &input,
|
||||
ResultDataSmall &result,
|
||||
const unsigned int mat_size, const float lg,
|
||||
const float ug, const float precision,
|
||||
const unsigned int iterations);
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//! Determine eigenvalues for matrices smaller than MAX_SMALL_MATRIX
|
||||
//! @param TimingIterations number of iterations for timing
|
||||
//! @param input handles to input data of kernel
|
||||
//! @param result handles to result of kernel
|
||||
//! @param mat_size matrix size
|
||||
//! @param lg lower limit of Gerschgorin interval
|
||||
//! @param ug upper limit of Gerschgorin interval
|
||||
//! @param precision desired precision of eigenvalues
|
||||
//! @param iterations number of iterations for timing
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void computeEigenvaluesSmallMatrix(const InputData &input,
|
||||
ResultDataSmall &result,
|
||||
const unsigned int mat_size,
|
||||
const float lg,
|
||||
const float ug,
|
||||
const float precision,
|
||||
const unsigned int iterations);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//! Initialize variables and memory for the result for small matrices
|
||||
//! @param result handles to the necessary memory
|
||||
//! @param mat_size matrix_size
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void initResultSmallMatrix(ResultDataSmall &result,
|
||||
const unsigned int mat_size);
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//! Initialize variables and memory for the result for small matrices
|
||||
//! @param result handles to the necessary memory
|
||||
//! @param mat_size matrix_size
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void initResultSmallMatrix(ResultDataSmall &result, const unsigned int mat_size);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//! Cleanup memory and variables for result for small matrices
|
||||
//! @param result handle to variables
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void cleanupResultSmallMatrix(ResultDataSmall &result);
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//! Cleanup memory and variables for result for small matrices
|
||||
//! @param result handle to variables
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void cleanupResultSmallMatrix(ResultDataSmall &result);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//! Process the result obtained on the device, that is transfer to host and
|
||||
//! perform basic sanity checking
|
||||
//! @param input handles to input data
|
||||
//! @param result handles to result variables
|
||||
//! @param mat_size matrix size
|
||||
//! @param filename output filename
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void processResultSmallMatrix(const InputData &input,
|
||||
const ResultDataSmall &result,
|
||||
const unsigned int mat_size,
|
||||
const char *filename);
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//! Process the result obtained on the device, that is transfer to host and
|
||||
//! perform basic sanity checking
|
||||
//! @param input handles to input data
|
||||
//! @param result handles to result variables
|
||||
//! @param mat_size matrix size
|
||||
//! @param filename output filename
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void processResultSmallMatrix(const InputData &input,
|
||||
const ResultDataSmall &result,
|
||||
const unsigned int mat_size,
|
||||
const char *filename);
|
||||
}
|
||||
|
||||
#endif // #ifndef _BISECT_SMALL_CUH_
|
||||
#endif // #ifndef _BISECT_SMALL_CUH_
|
||||
|
||||
@@ -42,30 +42,32 @@ namespace cg = cooperative_groups;
|
||||
//! Compute the next lower power of two of n
|
||||
//! @param n number for which next higher power of two is sought
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
__device__ inline int floorPow2(int n) {
|
||||
// early out if already power of two
|
||||
if (0 == (n & (n - 1))) {
|
||||
return n;
|
||||
}
|
||||
__device__ inline int floorPow2(int n)
|
||||
{
|
||||
// early out if already power of two
|
||||
if (0 == (n & (n - 1))) {
|
||||
return n;
|
||||
}
|
||||
|
||||
int exp;
|
||||
frexp((float)n, &exp);
|
||||
return (1 << (exp - 1));
|
||||
int exp;
|
||||
frexp((float)n, &exp);
|
||||
return (1 << (exp - 1));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//! Compute the next higher power of two of n
|
||||
//! @param n number for which next higher power of two is sought
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
__device__ inline int ceilPow2(int n) {
|
||||
// early out if already power of two
|
||||
if (0 == (n & (n - 1))) {
|
||||
return n;
|
||||
}
|
||||
__device__ inline int ceilPow2(int n)
|
||||
{
|
||||
// early out if already power of two
|
||||
if (0 == (n & (n - 1))) {
|
||||
return n;
|
||||
}
|
||||
|
||||
int exp;
|
||||
frexp((float)n, &exp);
|
||||
return (1 << exp);
|
||||
int exp;
|
||||
frexp((float)n, &exp);
|
||||
return (1 << exp);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -74,16 +76,18 @@ __device__ inline int ceilPow2(int n) {
|
||||
//! @param left left / lower limit of interval
|
||||
//! @param right right / upper limit of interval
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
__device__ inline float computeMidpoint(const float left, const float right) {
|
||||
float mid;
|
||||
__device__ inline float computeMidpoint(const float left, const float right)
|
||||
{
|
||||
float mid;
|
||||
|
||||
if (sign_f(left) == sign_f(right)) {
|
||||
mid = left + (right - left) * 0.5f;
|
||||
} else {
|
||||
mid = (left + right) * 0.5f;
|
||||
}
|
||||
if (sign_f(left) == sign_f(right)) {
|
||||
mid = left + (right - left) * 0.5f;
|
||||
}
|
||||
else {
|
||||
mid = (left + right) * 0.5f;
|
||||
}
|
||||
|
||||
return mid;
|
||||
return mid;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -102,29 +106,37 @@ __device__ inline float computeMidpoint(const float left, const float right) {
|
||||
//! @param precision desired precision for eigenvalues
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <class S, class T>
|
||||
__device__ void storeInterval(unsigned int addr, float *s_left, float *s_right,
|
||||
T *s_left_count, T *s_right_count, float left,
|
||||
float right, S left_count, S right_count,
|
||||
float precision) {
|
||||
s_left_count[addr] = left_count;
|
||||
s_right_count[addr] = right_count;
|
||||
__device__ void storeInterval(unsigned int addr,
|
||||
float *s_left,
|
||||
float *s_right,
|
||||
T *s_left_count,
|
||||
T *s_right_count,
|
||||
float left,
|
||||
float right,
|
||||
S left_count,
|
||||
S right_count,
|
||||
float precision)
|
||||
{
|
||||
s_left_count[addr] = left_count;
|
||||
s_right_count[addr] = right_count;
|
||||
|
||||
// check if interval converged
|
||||
float t0 = abs(right - left);
|
||||
float t1 = max(abs(left), abs(right)) * precision;
|
||||
// check if interval converged
|
||||
float t0 = abs(right - left);
|
||||
float t1 = max(abs(left), abs(right)) * precision;
|
||||
|
||||
if (t0 <= max(MIN_ABS_INTERVAL, t1)) {
|
||||
// compute mid point
|
||||
float lambda = computeMidpoint(left, right);
|
||||
if (t0 <= max(MIN_ABS_INTERVAL, t1)) {
|
||||
// compute mid point
|
||||
float lambda = computeMidpoint(left, right);
|
||||
|
||||
// mark as converged
|
||||
s_left[addr] = lambda;
|
||||
s_right[addr] = lambda;
|
||||
} else {
|
||||
// store current limits
|
||||
s_left[addr] = left;
|
||||
s_right[addr] = right;
|
||||
}
|
||||
// mark as converged
|
||||
s_left[addr] = lambda;
|
||||
s_right[addr] = lambda;
|
||||
}
|
||||
else {
|
||||
// store current limits
|
||||
s_left[addr] = left;
|
||||
s_right[addr] = right;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -145,35 +157,42 @@ __device__ void storeInterval(unsigned int addr, float *s_left, float *s_right,
|
||||
//! @param converged flag if the current thread is already converged (that
|
||||
//! is count does not have to be computed)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
__device__ inline unsigned int computeNumSmallerEigenvals(
|
||||
float *g_d, float *g_s, const unsigned int n, const float x,
|
||||
const unsigned int tid, const unsigned int num_intervals_active, float *s_d,
|
||||
float *s_s, unsigned int converged, cg::thread_block cta) {
|
||||
float delta = 1.0f;
|
||||
unsigned int count = 0;
|
||||
__device__ inline unsigned int computeNumSmallerEigenvals(float *g_d,
|
||||
float *g_s,
|
||||
const unsigned int n,
|
||||
const float x,
|
||||
const unsigned int tid,
|
||||
const unsigned int num_intervals_active,
|
||||
float *s_d,
|
||||
float *s_s,
|
||||
unsigned int converged,
|
||||
cg::thread_block cta)
|
||||
{
|
||||
float delta = 1.0f;
|
||||
unsigned int count = 0;
|
||||
|
||||
cg::sync(cta);
|
||||
cg::sync(cta);
|
||||
|
||||
// read data into shared memory
|
||||
if (threadIdx.x < n) {
|
||||
s_d[threadIdx.x] = *(g_d + threadIdx.x);
|
||||
s_s[threadIdx.x] = *(g_s + threadIdx.x - 1);
|
||||
}
|
||||
|
||||
cg::sync(cta);
|
||||
|
||||
// perform loop only for active threads
|
||||
if ((tid < num_intervals_active) && (0 == converged)) {
|
||||
// perform (optimized) Gaussian elimination to determine the number
|
||||
// of eigenvalues that are smaller than n
|
||||
for (unsigned int k = 0; k < n; ++k) {
|
||||
delta = s_d[k] - x - (s_s[k] * s_s[k]) / delta;
|
||||
count += (delta < 0) ? 1 : 0;
|
||||
// read data into shared memory
|
||||
if (threadIdx.x < n) {
|
||||
s_d[threadIdx.x] = *(g_d + threadIdx.x);
|
||||
s_s[threadIdx.x] = *(g_s + threadIdx.x - 1);
|
||||
}
|
||||
|
||||
} // end if thread currently processing an interval
|
||||
cg::sync(cta);
|
||||
|
||||
return count;
|
||||
// perform loop only for active threads
|
||||
if ((tid < num_intervals_active) && (0 == converged)) {
|
||||
// perform (optimized) Gaussian elimination to determine the number
|
||||
// of eigenvalues that are smaller than n
|
||||
for (unsigned int k = 0; k < n; ++k) {
|
||||
delta = s_d[k] - x - (s_s[k] * s_s[k]) / delta;
|
||||
count += (delta < 0) ? 1 : 0;
|
||||
}
|
||||
|
||||
} // end if thread currently processing an interval
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -194,42 +213,49 @@ __device__ inline unsigned int computeNumSmallerEigenvals(
|
||||
//! @param converged flag if the current thread is already converged (that
|
||||
//! is count does not have to be computed)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
__device__ inline unsigned int computeNumSmallerEigenvalsLarge(
|
||||
float *g_d, float *g_s, const unsigned int n, const float x,
|
||||
const unsigned int tid, const unsigned int num_intervals_active, float *s_d,
|
||||
float *s_s, unsigned int converged, cg::thread_block cta) {
|
||||
float delta = 1.0f;
|
||||
unsigned int count = 0;
|
||||
__device__ inline unsigned int computeNumSmallerEigenvalsLarge(float *g_d,
|
||||
float *g_s,
|
||||
const unsigned int n,
|
||||
const float x,
|
||||
const unsigned int tid,
|
||||
const unsigned int num_intervals_active,
|
||||
float *s_d,
|
||||
float *s_s,
|
||||
unsigned int converged,
|
||||
cg::thread_block cta)
|
||||
{
|
||||
float delta = 1.0f;
|
||||
unsigned int count = 0;
|
||||
|
||||
unsigned int rem = n;
|
||||
unsigned int rem = n;
|
||||
|
||||
// do until whole diagonal and superdiagonal has been loaded and processed
|
||||
for (unsigned int i = 0; i < n; i += blockDim.x) {
|
||||
cg::sync(cta);
|
||||
// do until whole diagonal and superdiagonal has been loaded and processed
|
||||
for (unsigned int i = 0; i < n; i += blockDim.x) {
|
||||
cg::sync(cta);
|
||||
|
||||
// read new chunk of data into shared memory
|
||||
if ((i + threadIdx.x) < n) {
|
||||
s_d[threadIdx.x] = *(g_d + i + threadIdx.x);
|
||||
s_s[threadIdx.x] = *(g_s + i + threadIdx.x - 1);
|
||||
// read new chunk of data into shared memory
|
||||
if ((i + threadIdx.x) < n) {
|
||||
s_d[threadIdx.x] = *(g_d + i + threadIdx.x);
|
||||
s_s[threadIdx.x] = *(g_s + i + threadIdx.x - 1);
|
||||
}
|
||||
|
||||
cg::sync(cta);
|
||||
|
||||
if (tid < num_intervals_active) {
|
||||
// perform (optimized) Gaussian elimination to determine the number
|
||||
// of eigenvalues that are smaller than n
|
||||
for (unsigned int k = 0; k < min(rem, blockDim.x); ++k) {
|
||||
delta = s_d[k] - x - (s_s[k] * s_s[k]) / delta;
|
||||
// delta = (abs( delta) < (1.0e-10)) ? -(1.0e-10) : delta;
|
||||
count += (delta < 0) ? 1 : 0;
|
||||
}
|
||||
|
||||
} // end if thread currently processing an interval
|
||||
|
||||
rem -= blockDim.x;
|
||||
}
|
||||
|
||||
cg::sync(cta);
|
||||
|
||||
if (tid < num_intervals_active) {
|
||||
// perform (optimized) Gaussian elimination to determine the number
|
||||
// of eigenvalues that are smaller than n
|
||||
for (unsigned int k = 0; k < min(rem, blockDim.x); ++k) {
|
||||
delta = s_d[k] - x - (s_s[k] * s_s[k]) / delta;
|
||||
// delta = (abs( delta) < (1.0e-10)) ? -(1.0e-10) : delta;
|
||||
count += (delta < 0) ? 1 : 0;
|
||||
}
|
||||
|
||||
} // end if thread currently processing an interval
|
||||
|
||||
rem -= blockDim.x;
|
||||
}
|
||||
|
||||
return count;
|
||||
return count;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -258,39 +284,51 @@ __device__ inline unsigned int computeNumSmallerEigenvalsLarge(
|
||||
//! @is_active_interval mark is thread has a second non-empty child interval
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <class S, class T>
|
||||
__device__ void storeNonEmptyIntervals(
|
||||
unsigned int addr, const unsigned int num_threads_active, float *s_left,
|
||||
float *s_right, T *s_left_count, T *s_right_count, float left, float mid,
|
||||
float right, const S left_count, const S mid_count, const S right_count,
|
||||
float precision, unsigned int &compact_second_chunk,
|
||||
T *s_compaction_list_exc, unsigned int &is_active_second) {
|
||||
// check if both child intervals are valid
|
||||
if ((left_count != mid_count) && (mid_count != right_count)) {
|
||||
// store the left interval
|
||||
storeInterval(addr, s_left, s_right, s_left_count, s_right_count, left, mid,
|
||||
left_count, mid_count, precision);
|
||||
__device__ void storeNonEmptyIntervals(unsigned int addr,
|
||||
const unsigned int num_threads_active,
|
||||
float *s_left,
|
||||
float *s_right,
|
||||
T *s_left_count,
|
||||
T *s_right_count,
|
||||
float left,
|
||||
float mid,
|
||||
float right,
|
||||
const S left_count,
|
||||
const S mid_count,
|
||||
const S right_count,
|
||||
float precision,
|
||||
unsigned int &compact_second_chunk,
|
||||
T *s_compaction_list_exc,
|
||||
unsigned int &is_active_second)
|
||||
{
|
||||
// check if both child intervals are valid
|
||||
if ((left_count != mid_count) && (mid_count != right_count)) {
|
||||
// store the left interval
|
||||
storeInterval(addr, s_left, s_right, s_left_count, s_right_count, left, mid, left_count, mid_count, precision);
|
||||
|
||||
// mark that a second interval has been generated, only stored after
|
||||
// stream compaction of second chunk
|
||||
is_active_second = 1;
|
||||
s_compaction_list_exc[threadIdx.x] = 1;
|
||||
atomicExch(&compact_second_chunk, 1);
|
||||
} else {
|
||||
// only one non-empty child interval
|
||||
|
||||
// mark that no second child
|
||||
is_active_second = 0;
|
||||
s_compaction_list_exc[threadIdx.x] = 0;
|
||||
|
||||
// store the one valid child interval
|
||||
if (left_count != mid_count) {
|
||||
storeInterval(addr, s_left, s_right, s_left_count, s_right_count, left,
|
||||
mid, left_count, mid_count, precision);
|
||||
} else {
|
||||
storeInterval(addr, s_left, s_right, s_left_count, s_right_count, mid,
|
||||
right, mid_count, right_count, precision);
|
||||
// mark that a second interval has been generated, only stored after
|
||||
// stream compaction of second chunk
|
||||
is_active_second = 1;
|
||||
s_compaction_list_exc[threadIdx.x] = 1;
|
||||
atomicExch(&compact_second_chunk, 1);
|
||||
}
|
||||
else {
|
||||
// only one non-empty child interval
|
||||
|
||||
// mark that no second child
|
||||
is_active_second = 0;
|
||||
s_compaction_list_exc[threadIdx.x] = 0;
|
||||
|
||||
// store the one valid child interval
|
||||
if (left_count != mid_count) {
|
||||
storeInterval(
|
||||
addr, s_left, s_right, s_left_count, s_right_count, left, mid, left_count, mid_count, precision);
|
||||
}
|
||||
else {
|
||||
storeInterval(
|
||||
addr, s_left, s_right, s_left_count, s_right_count, mid, right, mid_count, right_count, precision);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//! Create indices for compaction, that is process \a s_compaction_list_exc
|
||||
@@ -303,42 +341,40 @@ __device__ void storeNonEmptyIntervals(
|
||||
//! @param num_threads_compaction number of threads to employ for compaction
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <class T>
|
||||
__device__ void createIndicesCompaction(T *s_compaction_list_exc,
|
||||
unsigned int num_threads_compaction,
|
||||
cg::thread_block cta) {
|
||||
unsigned int offset = 1;
|
||||
const unsigned int tid = threadIdx.x;
|
||||
__device__ void
|
||||
createIndicesCompaction(T *s_compaction_list_exc, unsigned int num_threads_compaction, cg::thread_block cta)
|
||||
{
|
||||
unsigned int offset = 1;
|
||||
const unsigned int tid = threadIdx.x;
|
||||
|
||||
// higher levels of scan tree
|
||||
for (int d = (num_threads_compaction >> 1); d > 0; d >>= 1) {
|
||||
cg::sync(cta);
|
||||
// higher levels of scan tree
|
||||
for (int d = (num_threads_compaction >> 1); d > 0; d >>= 1) {
|
||||
cg::sync(cta);
|
||||
|
||||
if (tid < d) {
|
||||
unsigned int ai = offset * (2 * tid + 1) - 1;
|
||||
unsigned int bi = offset * (2 * tid + 2) - 1;
|
||||
if (tid < d) {
|
||||
unsigned int ai = offset * (2 * tid + 1) - 1;
|
||||
unsigned int bi = offset * (2 * tid + 2) - 1;
|
||||
|
||||
s_compaction_list_exc[bi] =
|
||||
s_compaction_list_exc[bi] + s_compaction_list_exc[ai];
|
||||
s_compaction_list_exc[bi] = s_compaction_list_exc[bi] + s_compaction_list_exc[ai];
|
||||
}
|
||||
|
||||
offset <<= 1;
|
||||
}
|
||||
|
||||
offset <<= 1;
|
||||
}
|
||||
// traverse down tree: first down to level 2 across
|
||||
for (int d = 2; d < num_threads_compaction; d <<= 1) {
|
||||
offset >>= 1;
|
||||
cg::sync(cta);
|
||||
|
||||
// traverse down tree: first down to level 2 across
|
||||
for (int d = 2; d < num_threads_compaction; d <<= 1) {
|
||||
offset >>= 1;
|
||||
cg::sync(cta);
|
||||
if (tid < (d - 1)) {
|
||||
unsigned int ai = offset * (tid + 1) - 1;
|
||||
unsigned int bi = ai + (offset >> 1);
|
||||
|
||||
if (tid < (d - 1)) {
|
||||
unsigned int ai = offset * (tid + 1) - 1;
|
||||
unsigned int bi = ai + (offset >> 1);
|
||||
|
||||
s_compaction_list_exc[bi] =
|
||||
s_compaction_list_exc[bi] + s_compaction_list_exc[ai];
|
||||
s_compaction_list_exc[bi] = s_compaction_list_exc[bi] + s_compaction_list_exc[ai];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cg::sync(cta);
|
||||
cg::sync(cta);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@@ -359,24 +395,30 @@ __device__ void createIndicesCompaction(T *s_compaction_list_exc,
|
||||
//! @is_active_interval mark is thread has a second non-empty child interval
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <class T>
|
||||
__device__ void compactIntervals(float *s_left, float *s_right, T *s_left_count,
|
||||
T *s_right_count, float mid, float right,
|
||||
__device__ void compactIntervals(float *s_left,
|
||||
float *s_right,
|
||||
T *s_left_count,
|
||||
T *s_right_count,
|
||||
float mid,
|
||||
float right,
|
||||
unsigned int mid_count,
|
||||
unsigned int right_count, T *s_compaction_list,
|
||||
unsigned int right_count,
|
||||
T *s_compaction_list,
|
||||
unsigned int num_threads_active,
|
||||
unsigned int is_active_second) {
|
||||
const unsigned int tid = threadIdx.x;
|
||||
unsigned int is_active_second)
|
||||
{
|
||||
const unsigned int tid = threadIdx.x;
|
||||
|
||||
// perform compaction / copy data for all threads where the second
|
||||
// child is not dead
|
||||
if ((tid < num_threads_active) && (1 == is_active_second)) {
|
||||
unsigned int addr_w = num_threads_active + s_compaction_list[tid];
|
||||
// perform compaction / copy data for all threads where the second
|
||||
// child is not dead
|
||||
if ((tid < num_threads_active) && (1 == is_active_second)) {
|
||||
unsigned int addr_w = num_threads_active + s_compaction_list[tid];
|
||||
|
||||
s_left[addr_w] = mid;
|
||||
s_right[addr_w] = right;
|
||||
s_left_count[addr_w] = mid_count;
|
||||
s_right_count[addr_w] = right_count;
|
||||
}
|
||||
s_left[addr_w] = mid;
|
||||
s_right[addr_w] = right;
|
||||
s_left_count[addr_w] = mid_count;
|
||||
s_right_count[addr_w] = right_count;
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@@ -401,86 +443,102 @@ __device__ void compactIntervals(float *s_left, float *s_right, T *s_left_count,
|
||||
//! @param num_threads_active number of active threads / intervals
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <class T, class S>
|
||||
__device__ void storeIntervalConverged(float *s_left, float *s_right,
|
||||
T *s_left_count, T *s_right_count,
|
||||
float &left, float &mid, float &right,
|
||||
S &left_count, S &mid_count,
|
||||
S &right_count, T *s_compaction_list_exc,
|
||||
unsigned int &compact_second_chunk,
|
||||
const unsigned int num_threads_active) {
|
||||
const unsigned int tid = threadIdx.x;
|
||||
const unsigned int multiplicity = right_count - left_count;
|
||||
__device__ void storeIntervalConverged(float *s_left,
|
||||
float *s_right,
|
||||
T *s_left_count,
|
||||
T *s_right_count,
|
||||
float &left,
|
||||
float &mid,
|
||||
float &right,
|
||||
S &left_count,
|
||||
S &mid_count,
|
||||
S &right_count,
|
||||
T *s_compaction_list_exc,
|
||||
unsigned int &compact_second_chunk,
|
||||
const unsigned int num_threads_active)
|
||||
{
|
||||
const unsigned int tid = threadIdx.x;
|
||||
const unsigned int multiplicity = right_count - left_count;
|
||||
|
||||
// check multiplicity of eigenvalue
|
||||
if (1 == multiplicity) {
|
||||
// just re-store intervals, simple eigenvalue
|
||||
s_left[tid] = left;
|
||||
s_right[tid] = right;
|
||||
s_left_count[tid] = left_count;
|
||||
s_right_count[tid] = right_count;
|
||||
// check multiplicity of eigenvalue
|
||||
if (1 == multiplicity) {
|
||||
// just re-store intervals, simple eigenvalue
|
||||
s_left[tid] = left;
|
||||
s_right[tid] = right;
|
||||
s_left_count[tid] = left_count;
|
||||
s_right_count[tid] = right_count;
|
||||
|
||||
// mark that no second child / clear
|
||||
s_right_count[tid + num_threads_active] = 0;
|
||||
s_compaction_list_exc[tid] = 0;
|
||||
} else {
|
||||
// number of eigenvalues after the split less than mid
|
||||
mid_count = left_count + (multiplicity >> 1);
|
||||
// mark that no second child / clear
|
||||
s_right_count[tid + num_threads_active] = 0;
|
||||
s_compaction_list_exc[tid] = 0;
|
||||
}
|
||||
else {
|
||||
// number of eigenvalues after the split less than mid
|
||||
mid_count = left_count + (multiplicity >> 1);
|
||||
|
||||
// store left interval
|
||||
s_left[tid] = left;
|
||||
s_right[tid] = right;
|
||||
s_left_count[tid] = left_count;
|
||||
s_right_count[tid] = mid_count;
|
||||
// store left interval
|
||||
s_left[tid] = left;
|
||||
s_right[tid] = right;
|
||||
s_left_count[tid] = left_count;
|
||||
s_right_count[tid] = mid_count;
|
||||
|
||||
mid = left;
|
||||
mid = left;
|
||||
|
||||
// mark that second child interval exists
|
||||
s_right_count[tid + num_threads_active] = right_count;
|
||||
s_compaction_list_exc[tid] = 1;
|
||||
compact_second_chunk = 1;
|
||||
}
|
||||
// mark that second child interval exists
|
||||
s_right_count[tid + num_threads_active] = right_count;
|
||||
s_compaction_list_exc[tid] = 1;
|
||||
compact_second_chunk = 1;
|
||||
}
|
||||
}
|
||||
|
||||
template <class T, class S>
|
||||
__device__ void storeIntervalConverged(float *s_left, float *s_right,
|
||||
T *s_left_count, T *s_right_count,
|
||||
float &left, float &mid, float &right,
|
||||
S &left_count, S &mid_count,
|
||||
S &right_count, T *s_compaction_list_exc,
|
||||
unsigned int &compact_second_chunk,
|
||||
__device__ void storeIntervalConverged(float *s_left,
|
||||
float *s_right,
|
||||
T *s_left_count,
|
||||
T *s_right_count,
|
||||
float &left,
|
||||
float &mid,
|
||||
float &right,
|
||||
S &left_count,
|
||||
S &mid_count,
|
||||
S &right_count,
|
||||
T *s_compaction_list_exc,
|
||||
unsigned int &compact_second_chunk,
|
||||
const unsigned int num_threads_active,
|
||||
unsigned int &is_active_second) {
|
||||
const unsigned int tid = threadIdx.x;
|
||||
const unsigned int multiplicity = right_count - left_count;
|
||||
unsigned int &is_active_second)
|
||||
{
|
||||
const unsigned int tid = threadIdx.x;
|
||||
const unsigned int multiplicity = right_count - left_count;
|
||||
|
||||
// check multiplicity of eigenvalue
|
||||
if (1 == multiplicity) {
|
||||
// just re-store intervals, simple eigenvalue
|
||||
s_left[tid] = left;
|
||||
s_right[tid] = right;
|
||||
s_left_count[tid] = left_count;
|
||||
s_right_count[tid] = right_count;
|
||||
// check multiplicity of eigenvalue
|
||||
if (1 == multiplicity) {
|
||||
// just re-store intervals, simple eigenvalue
|
||||
s_left[tid] = left;
|
||||
s_right[tid] = right;
|
||||
s_left_count[tid] = left_count;
|
||||
s_right_count[tid] = right_count;
|
||||
|
||||
// mark that no second child / clear
|
||||
is_active_second = 0;
|
||||
s_compaction_list_exc[tid] = 0;
|
||||
} else {
|
||||
// number of eigenvalues after the split less than mid
|
||||
mid_count = left_count + (multiplicity >> 1);
|
||||
// mark that no second child / clear
|
||||
is_active_second = 0;
|
||||
s_compaction_list_exc[tid] = 0;
|
||||
}
|
||||
else {
|
||||
// number of eigenvalues after the split less than mid
|
||||
mid_count = left_count + (multiplicity >> 1);
|
||||
|
||||
// store left interval
|
||||
s_left[tid] = left;
|
||||
s_right[tid] = right;
|
||||
s_left_count[tid] = left_count;
|
||||
s_right_count[tid] = mid_count;
|
||||
// store left interval
|
||||
s_left[tid] = left;
|
||||
s_right[tid] = right;
|
||||
s_left_count[tid] = left_count;
|
||||
s_right_count[tid] = mid_count;
|
||||
|
||||
mid = left;
|
||||
mid = left;
|
||||
|
||||
// mark that second child interval exists
|
||||
is_active_second = 1;
|
||||
s_compaction_list_exc[tid] = 1;
|
||||
compact_second_chunk = 1;
|
||||
}
|
||||
// mark that second child interval exists
|
||||
is_active_second = 1;
|
||||
s_compaction_list_exc[tid] = 1;
|
||||
compact_second_chunk = 1;
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@@ -501,29 +559,38 @@ __device__ void storeIntervalConverged(float *s_left, float *s_right,
|
||||
//! converged
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <class T>
|
||||
__device__ void subdivideActiveInterval(
|
||||
const unsigned int tid, float *s_left, float *s_right, T *s_left_count,
|
||||
T *s_right_count, const unsigned int num_threads_active, float &left,
|
||||
float &right, unsigned int &left_count, unsigned int &right_count,
|
||||
float &mid, unsigned int &all_threads_converged) {
|
||||
// for all active threads
|
||||
if (tid < num_threads_active) {
|
||||
left = s_left[tid];
|
||||
right = s_right[tid];
|
||||
left_count = s_left_count[tid];
|
||||
right_count = s_right_count[tid];
|
||||
__device__ void subdivideActiveInterval(const unsigned int tid,
|
||||
float *s_left,
|
||||
float *s_right,
|
||||
T *s_left_count,
|
||||
T *s_right_count,
|
||||
const unsigned int num_threads_active,
|
||||
float &left,
|
||||
float &right,
|
||||
unsigned int &left_count,
|
||||
unsigned int &right_count,
|
||||
float &mid,
|
||||
unsigned int &all_threads_converged)
|
||||
{
|
||||
// for all active threads
|
||||
if (tid < num_threads_active) {
|
||||
left = s_left[tid];
|
||||
right = s_right[tid];
|
||||
left_count = s_left_count[tid];
|
||||
right_count = s_right_count[tid];
|
||||
|
||||
// check if thread already converged
|
||||
if (left != right) {
|
||||
mid = computeMidpoint(left, right);
|
||||
atomicExch(&all_threads_converged, 0);
|
||||
} else if ((right_count - left_count) > 1) {
|
||||
// mark as not converged if multiple eigenvalues enclosed
|
||||
// duplicate interval in storeIntervalsConverged()
|
||||
atomicExch(&all_threads_converged, 0);
|
||||
}
|
||||
// check if thread already converged
|
||||
if (left != right) {
|
||||
mid = computeMidpoint(left, right);
|
||||
atomicExch(&all_threads_converged, 0);
|
||||
}
|
||||
else if ((right_count - left_count) > 1) {
|
||||
// mark as not converged if multiple eigenvalues enclosed
|
||||
// duplicate interval in storeIntervalsConverged()
|
||||
atomicExch(&all_threads_converged, 0);
|
||||
}
|
||||
|
||||
} // end for all active threads
|
||||
} // end for all active threads
|
||||
}
|
||||
|
||||
#endif // #ifndef _BISECT_UTIL_H_
|
||||
#endif // #ifndef _BISECT_UTIL_H_
|
||||
|
||||
@@ -33,9 +33,9 @@
|
||||
// should be power of two
|
||||
#define MAX_THREADS_BLOCK 256
|
||||
|
||||
#define MAX_SMALL_MATRIX 512
|
||||
#define MAX_SMALL_MATRIX 512
|
||||
#define MAX_THREADS_BLOCK_SMALL_MATRIX 512
|
||||
|
||||
#define MIN_ABS_INTERVAL 5.0e-37
|
||||
|
||||
#endif // #ifndef _CONFIG_H_
|
||||
#endif // #ifndef _CONFIG_H_
|
||||
|
||||
@@ -27,13 +27,15 @@
|
||||
|
||||
/* Computation of Gerschgorin interval for symmetric, tridiagonal matrix */
|
||||
|
||||
|
||||
#include "gerschgorin.h"
|
||||
|
||||
#include <cfloat>
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cmath>
|
||||
#include <cfloat>
|
||||
|
||||
#include "util.h"
|
||||
#include "gerschgorin.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//! Compute Gerschgorin interval for symmetric, tridiagonal matrix
|
||||
@@ -43,40 +45,40 @@
|
||||
//! @param lg lower limit of Gerschgorin interval
|
||||
//! @param ug upper limit of Gerschgorin interval
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void computeGerschgorin(float *d, float *s, unsigned int n, float &lg,
|
||||
float &ug) {
|
||||
lg = FLT_MAX;
|
||||
ug = -FLT_MAX;
|
||||
void computeGerschgorin(float *d, float *s, unsigned int n, float &lg, float &ug)
|
||||
{
|
||||
lg = FLT_MAX;
|
||||
ug = -FLT_MAX;
|
||||
|
||||
// compute bounds
|
||||
for (unsigned int i = 1; i < (n - 1); ++i) {
|
||||
// sum over the absolute values of all elements of row i
|
||||
float sum_abs_ni = fabsf(s[i - 1]) + fabsf(s[i]);
|
||||
// compute bounds
|
||||
for (unsigned int i = 1; i < (n - 1); ++i) {
|
||||
// sum over the absolute values of all elements of row i
|
||||
float sum_abs_ni = fabsf(s[i - 1]) + fabsf(s[i]);
|
||||
|
||||
lg = min(lg, d[i] - sum_abs_ni);
|
||||
ug = max(ug, d[i] + sum_abs_ni);
|
||||
}
|
||||
lg = min(lg, d[i] - sum_abs_ni);
|
||||
ug = max(ug, d[i] + sum_abs_ni);
|
||||
}
|
||||
|
||||
// first and last row, only one superdiagonal element
|
||||
// first and last row, only one superdiagonal element
|
||||
|
||||
// first row
|
||||
lg = min(lg, d[0] - fabsf(s[0]));
|
||||
ug = max(ug, d[0] + fabsf(s[0]));
|
||||
// first row
|
||||
lg = min(lg, d[0] - fabsf(s[0]));
|
||||
ug = max(ug, d[0] + fabsf(s[0]));
|
||||
|
||||
// last row
|
||||
lg = min(lg, d[n - 1] - fabsf(s[n - 2]));
|
||||
ug = max(ug, d[n - 1] + fabsf(s[n - 2]));
|
||||
// last row
|
||||
lg = min(lg, d[n - 1] - fabsf(s[n - 2]));
|
||||
ug = max(ug, d[n - 1] + fabsf(s[n - 2]));
|
||||
|
||||
// increase interval to avoid side effects of fp arithmetic
|
||||
float bnorm = max(fabsf(ug), fabsf(lg));
|
||||
// increase interval to avoid side effects of fp arithmetic
|
||||
float bnorm = max(fabsf(ug), fabsf(lg));
|
||||
|
||||
// these values depend on the implementation of floating count that is
|
||||
// employed in the following
|
||||
float psi_0 = 11 * FLT_EPSILON * bnorm;
|
||||
float psi_n = 11 * FLT_EPSILON * bnorm;
|
||||
// these values depend on the implementation of floating count that is
|
||||
// employed in the following
|
||||
float psi_0 = 11 * FLT_EPSILON * bnorm;
|
||||
float psi_n = 11 * FLT_EPSILON * bnorm;
|
||||
|
||||
lg = lg - bnorm * 2 * n * FLT_EPSILON - psi_0;
|
||||
ug = ug + bnorm * 2 * n * FLT_EPSILON + psi_n;
|
||||
lg = lg - bnorm * 2 * n * FLT_EPSILON - psi_0;
|
||||
ug = ug + bnorm * 2 * n * FLT_EPSILON + psi_n;
|
||||
|
||||
ug = max(lg, ug);
|
||||
ug = max(lg, ug);
|
||||
}
|
||||
|
||||
@@ -38,7 +38,6 @@
|
||||
//! @param lg lower limit of Gerschgorin interval
|
||||
//! @param ug upper limit of Gerschgorin interval
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
extern "C" void computeGerschgorin(float *d, float *s, unsigned int n,
|
||||
float &lg, float &ug);
|
||||
extern "C" void computeGerschgorin(float *d, float *s, unsigned int n, float &lg, float &ug);
|
||||
|
||||
#endif // #ifndef _GERSCHGORIN_H_
|
||||
#endif // #ifndef _GERSCHGORIN_H_
|
||||
|
||||
@@ -30,24 +30,24 @@
|
||||
*/
|
||||
|
||||
// includes, system
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <float.h>
|
||||
#include <assert.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 "config.h"
|
||||
#include "structs.h"
|
||||
#include "matlab.h"
|
||||
#include "util.h"
|
||||
#include "gerschgorin.h"
|
||||
#include <helper_functions.h>
|
||||
|
||||
#include "bisect_small.cuh"
|
||||
#include "bisect_large.cuh"
|
||||
#include "bisect_small.cuh"
|
||||
#include "config.h"
|
||||
#include "gerschgorin.h"
|
||||
#include "matlab.h"
|
||||
#include "structs.h"
|
||||
#include "util.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// declaration, forward
|
||||
@@ -56,15 +56,16 @@ bool runTest(int argc, char **argv);
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Program main
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int main(int argc, char **argv) {
|
||||
bool bQAResults = false;
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
bool bQAResults = false;
|
||||
|
||||
printf("Starting eigenvalues\n");
|
||||
printf("Starting eigenvalues\n");
|
||||
|
||||
bQAResults = runTest(argc, argv);
|
||||
printf("Test %s\n", bQAResults ? "Succeeded!" : "Failed!");
|
||||
bQAResults = runTest(argc, argv);
|
||||
printf("Test %s\n", bQAResults ? "Succeeded!" : "Failed!");
|
||||
|
||||
exit(bQAResults ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
exit(bQAResults ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -75,69 +76,67 @@ int main(int argc, char **argv) {
|
||||
//! @param user_defined 1 if the matrix size has been requested by the user,
|
||||
//! 0 if the default size
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void initInputData(InputData &input, char *exec_path,
|
||||
const unsigned int mat_size,
|
||||
const unsigned int user_defined) {
|
||||
// allocate memory
|
||||
input.a = (float *)malloc(sizeof(float) * mat_size);
|
||||
input.b = (float *)malloc(sizeof(float) * mat_size);
|
||||
void initInputData(InputData &input, char *exec_path, const unsigned int mat_size, const unsigned int user_defined)
|
||||
{
|
||||
// allocate memory
|
||||
input.a = (float *)malloc(sizeof(float) * mat_size);
|
||||
input.b = (float *)malloc(sizeof(float) * mat_size);
|
||||
|
||||
if (1 == user_defined) {
|
||||
// initialize diagonal and superdiagonal entries with random values
|
||||
srand(278217421);
|
||||
if (1 == user_defined) {
|
||||
// initialize diagonal and superdiagonal entries with random values
|
||||
srand(278217421);
|
||||
|
||||
// srand( clock());
|
||||
for (unsigned int i = 0; i < mat_size; ++i) {
|
||||
input.a[i] = (float)(2.0 * (((double)rand() / (double)RAND_MAX) - 0.5));
|
||||
input.b[i] = (float)(2.0 * (((double)rand() / (double)RAND_MAX) - 0.5));
|
||||
// srand( clock());
|
||||
for (unsigned int i = 0; i < mat_size; ++i) {
|
||||
input.a[i] = (float)(2.0 * (((double)rand() / (double)RAND_MAX) - 0.5));
|
||||
input.b[i] = (float)(2.0 * (((double)rand() / (double)RAND_MAX) - 0.5));
|
||||
}
|
||||
|
||||
// the first element of s is used as padding on the device (thus the
|
||||
// whole vector is copied to the device but the kernels are launched
|
||||
// with (s+1) as start address
|
||||
input.b[0] = 0.0f;
|
||||
}
|
||||
else {
|
||||
// read default matrix
|
||||
unsigned int input_data_size = mat_size;
|
||||
char *diag_path = sdkFindFilePath("diagonal.dat", exec_path);
|
||||
assert(NULL != diag_path);
|
||||
sdkReadFile(diag_path, &(input.a), &input_data_size, false);
|
||||
|
||||
char *sdiag_path = sdkFindFilePath("superdiagonal.dat", exec_path);
|
||||
assert(NULL != sdiag_path);
|
||||
sdkReadFile(sdiag_path, &(input.b), &input_data_size, false);
|
||||
|
||||
free(diag_path);
|
||||
free(sdiag_path);
|
||||
}
|
||||
|
||||
// the first element of s is used as padding on the device (thus the
|
||||
// whole vector is copied to the device but the kernels are launched
|
||||
// with (s+1) as start address
|
||||
input.b[0] = 0.0f;
|
||||
} else {
|
||||
// read default matrix
|
||||
unsigned int input_data_size = mat_size;
|
||||
char *diag_path = sdkFindFilePath("diagonal.dat", exec_path);
|
||||
assert(NULL != diag_path);
|
||||
sdkReadFile(diag_path, &(input.a), &input_data_size, false);
|
||||
// allocate device memory for input
|
||||
checkCudaErrors(cudaMalloc((void **)&(input.g_a), sizeof(float) * mat_size));
|
||||
checkCudaErrors(cudaMalloc((void **)&(input.g_b_raw), sizeof(float) * mat_size));
|
||||
|
||||
char *sdiag_path = sdkFindFilePath("superdiagonal.dat", exec_path);
|
||||
assert(NULL != sdiag_path);
|
||||
sdkReadFile(sdiag_path, &(input.b), &input_data_size, false);
|
||||
// copy data to device
|
||||
checkCudaErrors(cudaMemcpy(input.g_a, input.a, sizeof(float) * mat_size, cudaMemcpyHostToDevice));
|
||||
checkCudaErrors(cudaMemcpy(input.g_b_raw, input.b, sizeof(float) * mat_size, cudaMemcpyHostToDevice));
|
||||
|
||||
free(diag_path);
|
||||
free(sdiag_path);
|
||||
}
|
||||
|
||||
// allocate device memory for input
|
||||
checkCudaErrors(cudaMalloc((void **)&(input.g_a), sizeof(float) * mat_size));
|
||||
checkCudaErrors(
|
||||
cudaMalloc((void **)&(input.g_b_raw), sizeof(float) * mat_size));
|
||||
|
||||
// copy data to device
|
||||
checkCudaErrors(cudaMemcpy(input.g_a, input.a, sizeof(float) * mat_size,
|
||||
cudaMemcpyHostToDevice));
|
||||
checkCudaErrors(cudaMemcpy(input.g_b_raw, input.b, sizeof(float) * mat_size,
|
||||
cudaMemcpyHostToDevice));
|
||||
|
||||
input.g_b = input.g_b_raw + 1;
|
||||
input.g_b = input.g_b_raw + 1;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//! Clean up input data, in particular allocated memory
|
||||
//! @param input handles to the input data
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void cleanupInputData(InputData &input) {
|
||||
freePtr(input.a);
|
||||
freePtr(input.b);
|
||||
void cleanupInputData(InputData &input)
|
||||
{
|
||||
freePtr(input.a);
|
||||
freePtr(input.b);
|
||||
|
||||
checkCudaErrors(cudaFree(input.g_a));
|
||||
input.g_a = NULL;
|
||||
checkCudaErrors(cudaFree(input.g_b_raw));
|
||||
input.g_b_raw = NULL;
|
||||
input.g_b = NULL;
|
||||
checkCudaErrors(cudaFree(input.g_a));
|
||||
input.g_a = NULL;
|
||||
checkCudaErrors(cudaFree(input.g_b_raw));
|
||||
input.g_b_raw = NULL;
|
||||
input.g_b = NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -147,26 +146,26 @@ void cleanupInputData(InputData &input) {
|
||||
//! @param matrix_size size of matrix, updated if specific size specified on
|
||||
//! command line
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void getMatrixSize(int argc, char **argv, unsigned int &mat_size,
|
||||
unsigned int &user_defined) {
|
||||
int temp = -1;
|
||||
void getMatrixSize(int argc, char **argv, unsigned int &mat_size, unsigned int &user_defined)
|
||||
{
|
||||
int temp = -1;
|
||||
|
||||
if (checkCmdLineFlag(argc, (const char **)argv, "matrix-size")) {
|
||||
temp = getCmdLineArgumentInt(argc, (const char **)argv, "matrix-size");
|
||||
}
|
||||
if (checkCmdLineFlag(argc, (const char **)argv, "matrix-size")) {
|
||||
temp = getCmdLineArgumentInt(argc, (const char **)argv, "matrix-size");
|
||||
}
|
||||
|
||||
if (temp > 0) {
|
||||
mat_size = (unsigned int)temp;
|
||||
// data type short is used in the kernel
|
||||
assert(mat_size < (1 << 16));
|
||||
if (temp > 0) {
|
||||
mat_size = (unsigned int)temp;
|
||||
// data type short is used in the kernel
|
||||
assert(mat_size < (1 << 16));
|
||||
|
||||
// mat_size should be large than 2
|
||||
assert(mat_size >= 2);
|
||||
// mat_size should be large than 2
|
||||
assert(mat_size >= 2);
|
||||
|
||||
user_defined = 1;
|
||||
}
|
||||
user_defined = 1;
|
||||
}
|
||||
|
||||
printf("Matrix size: %i x %i\n", mat_size, mat_size);
|
||||
printf("Matrix size: %i x %i\n", mat_size, mat_size);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -178,21 +177,21 @@ void getMatrixSize(int argc, char **argv, unsigned int &mat_size,
|
||||
//! @param user_defined 1 if the precision has been requested by the user,
|
||||
//! 0 if the default size
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void getPrecision(int argc, char **argv, float &precision,
|
||||
unsigned int &user_defined) {
|
||||
float temp = -1.0f;
|
||||
void getPrecision(int argc, char **argv, float &precision, unsigned int &user_defined)
|
||||
{
|
||||
float temp = -1.0f;
|
||||
|
||||
if (checkCmdLineFlag(argc, (const char **)argv, "precision")) {
|
||||
temp = getCmdLineArgumentFloat(argc, (const char **)argv, "precision");
|
||||
printf("Precision is between [0.001, 0.000001]\n");
|
||||
}
|
||||
if (checkCmdLineFlag(argc, (const char **)argv, "precision")) {
|
||||
temp = getCmdLineArgumentFloat(argc, (const char **)argv, "precision");
|
||||
printf("Precision is between [0.001, 0.000001]\n");
|
||||
}
|
||||
|
||||
if (temp > 1e-6 && temp <= 0.001) {
|
||||
precision = temp;
|
||||
user_defined = 1;
|
||||
}
|
||||
if (temp > 1e-6 && temp <= 0.001) {
|
||||
precision = temp;
|
||||
user_defined = 1;
|
||||
}
|
||||
|
||||
printf("Precision: %f\n", precision);
|
||||
printf("Precision: %f\n", precision);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -202,18 +201,19 @@ void getPrecision(int argc, char **argv, float &precision,
|
||||
//! @param iters_timing number of timing iterations, updated if user
|
||||
//! specific value
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void getItersTiming(int argc, char **argv, unsigned int &iters_timing) {
|
||||
int temp = -1;
|
||||
void getItersTiming(int argc, char **argv, unsigned int &iters_timing)
|
||||
{
|
||||
int temp = -1;
|
||||
|
||||
if (checkCmdLineFlag(argc, (const char **)argv, "iters-timing")) {
|
||||
temp = getCmdLineArgumentInt(argc, (const char **)argv, "iters-timing");
|
||||
}
|
||||
if (checkCmdLineFlag(argc, (const char **)argv, "iters-timing")) {
|
||||
temp = getCmdLineArgumentInt(argc, (const char **)argv, "iters-timing");
|
||||
}
|
||||
|
||||
if (temp > 0) {
|
||||
iters_timing = temp;
|
||||
}
|
||||
if (temp > 0) {
|
||||
iters_timing = temp;
|
||||
}
|
||||
|
||||
printf("Iterations to be timed: %i\n", iters_timing);
|
||||
printf("Iterations to be timed: %i\n", iters_timing);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -224,102 +224,102 @@ void getItersTiming(int argc, char **argv, unsigned int &iters_timing) {
|
||||
//! @param filename filename of result file, updated if user specified
|
||||
//! filename
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void getResultFilename(int argc, char **argv, char *&filename) {
|
||||
char *temp = NULL;
|
||||
getCmdLineArgumentString(argc, (const char **)argv, "filename-result", &temp);
|
||||
void getResultFilename(int argc, char **argv, char *&filename)
|
||||
{
|
||||
char *temp = NULL;
|
||||
getCmdLineArgumentString(argc, (const char **)argv, "filename-result", &temp);
|
||||
|
||||
if (NULL != temp) {
|
||||
filename = (char *)malloc(sizeof(char) * strlen(temp));
|
||||
strcpy(filename, temp);
|
||||
if (NULL != temp) {
|
||||
filename = (char *)malloc(sizeof(char) * strlen(temp));
|
||||
strcpy(filename, temp);
|
||||
|
||||
free(temp);
|
||||
}
|
||||
free(temp);
|
||||
}
|
||||
|
||||
printf("Result filename: '%s'\n", filename);
|
||||
printf("Result filename: '%s'\n", filename);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//! Run a simple test for CUDA
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool runTest(int argc, char **argv) {
|
||||
bool bCompareResult = false;
|
||||
bool runTest(int argc, char **argv)
|
||||
{
|
||||
bool bCompareResult = false;
|
||||
|
||||
findCudaDevice(argc, (const char **)argv);
|
||||
findCudaDevice(argc, (const char **)argv);
|
||||
|
||||
StopWatchInterface *timer = NULL;
|
||||
StopWatchInterface *timer_total = NULL;
|
||||
sdkCreateTimer(&timer);
|
||||
sdkCreateTimer(&timer_total);
|
||||
StopWatchInterface *timer = NULL;
|
||||
StopWatchInterface *timer_total = NULL;
|
||||
sdkCreateTimer(&timer);
|
||||
sdkCreateTimer(&timer_total);
|
||||
|
||||
// default
|
||||
unsigned int mat_size = 2048;
|
||||
// flag if the matrix size is due to explicit user request
|
||||
unsigned int user_defined = 0;
|
||||
// desired precision of eigenvalues
|
||||
float precision = 0.00001f;
|
||||
unsigned int iters_timing = 100;
|
||||
char *result_file = (char *)"eigenvalues.dat";
|
||||
// default
|
||||
unsigned int mat_size = 2048;
|
||||
// flag if the matrix size is due to explicit user request
|
||||
unsigned int user_defined = 0;
|
||||
// desired precision of eigenvalues
|
||||
float precision = 0.00001f;
|
||||
unsigned int iters_timing = 100;
|
||||
char *result_file = (char *)"eigenvalues.dat";
|
||||
|
||||
// check if there is a command line request for the matrix size
|
||||
getMatrixSize(argc, argv, mat_size, user_defined);
|
||||
// check if there is a command line request for the matrix size
|
||||
getMatrixSize(argc, argv, mat_size, user_defined);
|
||||
|
||||
// check if user requested specific precision
|
||||
getPrecision(argc, argv, precision, user_defined);
|
||||
// check if user requested specific precision
|
||||
getPrecision(argc, argv, precision, user_defined);
|
||||
|
||||
// check if user requested specific number of iterations for timing
|
||||
getItersTiming(argc, argv, iters_timing);
|
||||
// check if user requested specific number of iterations for timing
|
||||
getItersTiming(argc, argv, iters_timing);
|
||||
|
||||
// file name for result file
|
||||
getResultFilename(argc, argv, result_file);
|
||||
// file name for result file
|
||||
getResultFilename(argc, argv, result_file);
|
||||
|
||||
// set up input
|
||||
InputData input;
|
||||
initInputData(input, argv[0], mat_size, user_defined);
|
||||
// set up input
|
||||
InputData input;
|
||||
initInputData(input, argv[0], mat_size, user_defined);
|
||||
|
||||
// compute Gerschgorin interval
|
||||
float lg = FLT_MAX;
|
||||
float ug = -FLT_MAX;
|
||||
computeGerschgorin(input.a, input.b + 1, mat_size, lg, ug);
|
||||
printf("Gerschgorin interval: %f / %f\n", lg, ug);
|
||||
// compute Gerschgorin interval
|
||||
float lg = FLT_MAX;
|
||||
float ug = -FLT_MAX;
|
||||
computeGerschgorin(input.a, input.b + 1, mat_size, lg, ug);
|
||||
printf("Gerschgorin interval: %f / %f\n", lg, ug);
|
||||
|
||||
// two kernels, for small matrices a lot of overhead can be avoided
|
||||
if (mat_size <= MAX_SMALL_MATRIX) {
|
||||
// initialize memory for result
|
||||
ResultDataSmall result;
|
||||
initResultSmallMatrix(result, mat_size);
|
||||
// two kernels, for small matrices a lot of overhead can be avoided
|
||||
if (mat_size <= MAX_SMALL_MATRIX) {
|
||||
// initialize memory for result
|
||||
ResultDataSmall result;
|
||||
initResultSmallMatrix(result, mat_size);
|
||||
|
||||
// run the kernel
|
||||
computeEigenvaluesSmallMatrix(input, result, mat_size, lg, ug, precision,
|
||||
iters_timing);
|
||||
// run the kernel
|
||||
computeEigenvaluesSmallMatrix(input, result, mat_size, lg, ug, precision, iters_timing);
|
||||
|
||||
// get the result from the device and do some sanity checks,
|
||||
// save the result
|
||||
processResultSmallMatrix(input, result, mat_size, result_file);
|
||||
// get the result from the device and do some sanity checks,
|
||||
// save the result
|
||||
processResultSmallMatrix(input, result, mat_size, result_file);
|
||||
|
||||
// clean up
|
||||
cleanupResultSmallMatrix(result);
|
||||
// clean up
|
||||
cleanupResultSmallMatrix(result);
|
||||
|
||||
printf("User requests non-default argument(s), skipping self-check!\n");
|
||||
bCompareResult = true;
|
||||
} else {
|
||||
// initialize memory for result
|
||||
ResultDataLarge result;
|
||||
initResultDataLargeMatrix(result, mat_size);
|
||||
printf("User requests non-default argument(s), skipping self-check!\n");
|
||||
bCompareResult = true;
|
||||
}
|
||||
else {
|
||||
// initialize memory for result
|
||||
ResultDataLarge result;
|
||||
initResultDataLargeMatrix(result, mat_size);
|
||||
|
||||
// run the kernel
|
||||
computeEigenvaluesLargeMatrix(input, result, mat_size, precision, lg, ug,
|
||||
iters_timing);
|
||||
// run the kernel
|
||||
computeEigenvaluesLargeMatrix(input, result, mat_size, precision, lg, ug, iters_timing);
|
||||
|
||||
// get the result from the device and do some sanity checks
|
||||
// save the result if user specified matrix size
|
||||
bCompareResult = processResultDataLargeMatrix(
|
||||
input, result, mat_size, result_file, user_defined, argv[0]);
|
||||
// get the result from the device and do some sanity checks
|
||||
// save the result if user specified matrix size
|
||||
bCompareResult = processResultDataLargeMatrix(input, result, mat_size, result_file, user_defined, argv[0]);
|
||||
|
||||
// cleanup
|
||||
cleanupResultDataLargeMatrix(result);
|
||||
}
|
||||
// cleanup
|
||||
cleanupResultDataLargeMatrix(result);
|
||||
}
|
||||
|
||||
cleanupInputData(input);
|
||||
cleanupInputData(input);
|
||||
|
||||
return bCompareResult;
|
||||
return bCompareResult;
|
||||
}
|
||||
|
||||
@@ -26,20 +26,21 @@
|
||||
*/
|
||||
|
||||
//! includes, system
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
// includes, projcet
|
||||
#include "matlab.h"
|
||||
|
||||
// namespace, unnamed
|
||||
namespace {} // end namespace, unnamed
|
||||
namespace {
|
||||
} // namespace
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//! Write a tridiagonal, symmetric matrix in vector representation and
|
||||
@@ -52,18 +53,18 @@ namespace {} // end namespace, unnamed
|
||||
//! if these are sorted in ascending order
|
||||
//! @param n size of the matrix
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
void writeTridiagSymMatlab(const char *filename, float *d, float *s,
|
||||
float *eigenvals, const unsigned int n) {
|
||||
std::ofstream file(filename, std::ios::out);
|
||||
void writeTridiagSymMatlab(const char *filename, float *d, float *s, float *eigenvals, const unsigned int n)
|
||||
{
|
||||
std::ofstream file(filename, std::ios::out);
|
||||
|
||||
// write diagonal entries
|
||||
writeVectorMatlab(file, "d", d, n);
|
||||
// write diagonal entries
|
||||
writeVectorMatlab(file, "d", d, n);
|
||||
|
||||
// write superdiagonal entries
|
||||
writeVectorMatlab(file, "s", s, n - 1);
|
||||
// write superdiagonal entries
|
||||
writeVectorMatlab(file, "s", s, n - 1);
|
||||
|
||||
// write eigenvalues
|
||||
writeVectorMatlab(file, "eigvals", eigenvals, n);
|
||||
// write eigenvalues
|
||||
writeVectorMatlab(file, "eigvals", eigenvals, n);
|
||||
|
||||
file.close();
|
||||
file.close();
|
||||
}
|
||||
|
||||
@@ -26,17 +26,17 @@
|
||||
*/
|
||||
|
||||
/* Header for utility functionality.
|
||||
* Host code.
|
||||
*/
|
||||
* Host code.
|
||||
*/
|
||||
|
||||
#ifndef _MATLAB_H_
|
||||
#define _MATLAB_H_
|
||||
|
||||
// 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
|
||||
|
||||
@@ -51,8 +51,7 @@
|
||||
//! if these are sorted in ascending order
|
||||
//! @param n size of the matrix
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
extern "C" void writeTridiagSymMatlab(const char *filename, float *d, float *s,
|
||||
float *eigenvals, const unsigned int n);
|
||||
extern "C" void writeTridiagSymMatlab(const char *filename, float *d, float *s, float *eigenvals, const unsigned int n);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//! Write matrix to a file in Matlab format
|
||||
@@ -61,9 +60,7 @@ extern "C" void writeTridiagSymMatlab(const char *filename, float *d, float *s,
|
||||
//! @param mat matrix to write to the file
|
||||
//! @param mat_size size of the (square) matrix \a mat
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <class T, class S>
|
||||
void writeMatrixMatlab(T &file, const char *mat_name, S *&mat,
|
||||
const unsigned int mat_size);
|
||||
template <class T, class S> void writeMatrixMatlab(T &file, const char *mat_name, S *&mat, const unsigned int mat_size);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//! Write vector to a file in Matlab format
|
||||
@@ -72,9 +69,7 @@ void writeMatrixMatlab(T &file, const char *mat_name, S *&mat,
|
||||
//! @param vec matrix to write to the file
|
||||
//! @param vec_len length of the vector
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <class T, class S>
|
||||
void writeVectorMatlab(T &file, const char *vec_name, S *&vec,
|
||||
const unsigned int vec_len);
|
||||
template <class T, class S> void writeVectorMatlab(T &file, const char *vec_name, S *&vec, const unsigned int vec_len);
|
||||
|
||||
// implementations
|
||||
|
||||
@@ -85,24 +80,23 @@ void writeVectorMatlab(T &file, const char *vec_name, S *&vec,
|
||||
//! @param mat matrix to write to the file
|
||||
//! @param mat_size size of the (square) matrix \a mat
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <class T, class S>
|
||||
void writeMatrixMatlab(T &file, const char *mat_name, S *&mat,
|
||||
const unsigned int mat_size) {
|
||||
const unsigned int pitch = sizeof(S) * mat_size;
|
||||
template <class T, class S> void writeMatrixMatlab(T &file, const char *mat_name, S *&mat, const unsigned int mat_size)
|
||||
{
|
||||
const unsigned int pitch = sizeof(S) * mat_size;
|
||||
|
||||
file << mat_name << " = [";
|
||||
file << mat_name << " = [";
|
||||
|
||||
for (unsigned int i = 0; i < mat_size; ++i) {
|
||||
for (unsigned int j = 0; j < mat_size; ++j) {
|
||||
file << getMatrix(mat, pitch, i, j) << " ";
|
||||
for (unsigned int i = 0; i < mat_size; ++i) {
|
||||
for (unsigned int j = 0; j < mat_size; ++j) {
|
||||
file << getMatrix(mat, pitch, i, j) << " ";
|
||||
}
|
||||
|
||||
if (i != mat_size - 1) {
|
||||
file << "; ";
|
||||
}
|
||||
}
|
||||
|
||||
if (i != mat_size - 1) {
|
||||
file << "; ";
|
||||
}
|
||||
}
|
||||
|
||||
file << "];\n";
|
||||
file << "];\n";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -112,16 +106,15 @@ void writeMatrixMatlab(T &file, const char *mat_name, S *&mat,
|
||||
//! @param vec matrix to write to the file
|
||||
//! @param vec_len length of the vector
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <class T, class S>
|
||||
void writeVectorMatlab(T &file, const char *vec_name, S *&vec,
|
||||
const unsigned int vec_len) {
|
||||
file << vec_name << " = [";
|
||||
template <class T, class S> void writeVectorMatlab(T &file, const char *vec_name, S *&vec, const unsigned int vec_len)
|
||||
{
|
||||
file << vec_name << " = [";
|
||||
|
||||
for (unsigned int i = 0; i < vec_len; ++i) {
|
||||
file << vec[i] << " ";
|
||||
}
|
||||
for (unsigned int i = 0; i < vec_len; ++i) {
|
||||
file << vec[i] << " ";
|
||||
}
|
||||
|
||||
file << "];\n";
|
||||
file << "];\n";
|
||||
}
|
||||
|
||||
#endif // _MATLAB_H_
|
||||
#endif // _MATLAB_H_
|
||||
|
||||
@@ -30,100 +30,103 @@
|
||||
#ifndef _STRUCTS_H_
|
||||
#define _STRUCTS_H_
|
||||
|
||||
struct InputData {
|
||||
//! host side representation of diagonal
|
||||
float *a;
|
||||
//! host side representation superdiagonal
|
||||
float *b;
|
||||
struct InputData
|
||||
{
|
||||
//! host side representation of diagonal
|
||||
float *a;
|
||||
//! host side representation superdiagonal
|
||||
float *b;
|
||||
|
||||
//! device side representation of diagonal
|
||||
float *g_a;
|
||||
//! device side representation of superdiagonal
|
||||
float *g_b;
|
||||
//! helper variable pointing to the mem allocated for g_b which provides
|
||||
//! space for one additional element of padding at the beginning
|
||||
float *g_b_raw;
|
||||
//! device side representation of diagonal
|
||||
float *g_a;
|
||||
//! device side representation of superdiagonal
|
||||
float *g_b;
|
||||
//! helper variable pointing to the mem allocated for g_b which provides
|
||||
//! space for one additional element of padding at the beginning
|
||||
float *g_b_raw;
|
||||
};
|
||||
|
||||
struct ResultDataSmall {
|
||||
//! eigenvalues (host side)
|
||||
float *eigenvalues;
|
||||
struct ResultDataSmall
|
||||
{
|
||||
//! eigenvalues (host side)
|
||||
float *eigenvalues;
|
||||
|
||||
// left interval limits at the end of the computation
|
||||
float *g_left;
|
||||
// left interval limits at the end of the computation
|
||||
float *g_left;
|
||||
|
||||
// right interval limits at the end of the computation
|
||||
float *g_right;
|
||||
// right interval limits at the end of the computation
|
||||
float *g_right;
|
||||
|
||||
// number of eigenvalues smaller than the left interval limit
|
||||
unsigned int *g_left_count;
|
||||
// number of eigenvalues smaller than the left interval limit
|
||||
unsigned int *g_left_count;
|
||||
|
||||
// number of eigenvalues bigger than the right interval limit
|
||||
unsigned int *g_right_count;
|
||||
// number of eigenvalues bigger than the right interval limit
|
||||
unsigned int *g_right_count;
|
||||
|
||||
//! flag if algorithm converged
|
||||
unsigned int *g_converged;
|
||||
//! flag if algorithm converged
|
||||
unsigned int *g_converged;
|
||||
|
||||
// helper variables
|
||||
// helper variables
|
||||
|
||||
unsigned int mat_size_f;
|
||||
unsigned int mat_size_ui;
|
||||
unsigned int mat_size_f;
|
||||
unsigned int mat_size_ui;
|
||||
|
||||
float *zero_f;
|
||||
unsigned int *zero_ui;
|
||||
float *zero_f;
|
||||
unsigned int *zero_ui;
|
||||
};
|
||||
|
||||
struct ResultDataLarge {
|
||||
// number of intervals containing one eigenvalue after the first step
|
||||
unsigned int *g_num_one;
|
||||
struct ResultDataLarge
|
||||
{
|
||||
// number of intervals containing one eigenvalue after the first step
|
||||
unsigned int *g_num_one;
|
||||
|
||||
// number of (thread) blocks of intervals containing multiple eigenvalues
|
||||
// after the first step
|
||||
unsigned int *g_num_blocks_mult;
|
||||
// number of (thread) blocks of intervals containing multiple eigenvalues
|
||||
// after the first step
|
||||
unsigned int *g_num_blocks_mult;
|
||||
|
||||
//! left interval limits of intervals containing one eigenvalue after the
|
||||
//! first iteration step
|
||||
float *g_left_one;
|
||||
//! left interval limits of intervals containing one eigenvalue after the
|
||||
//! first iteration step
|
||||
float *g_left_one;
|
||||
|
||||
//! right interval limits of intervals containing one eigenvalue after the
|
||||
//! first iteration step
|
||||
float *g_right_one;
|
||||
//! right interval limits of intervals containing one eigenvalue after the
|
||||
//! first iteration step
|
||||
float *g_right_one;
|
||||
|
||||
//! interval indices (position in sorted listed of eigenvalues)
|
||||
//! of intervals containing one eigenvalue after the first iteration step
|
||||
unsigned int *g_pos_one;
|
||||
//! interval indices (position in sorted listed of eigenvalues)
|
||||
//! of intervals containing one eigenvalue after the first iteration step
|
||||
unsigned int *g_pos_one;
|
||||
|
||||
//! left interval limits of intervals containing multiple eigenvalues
|
||||
//! after the first iteration step
|
||||
float *g_left_mult;
|
||||
//! left interval limits of intervals containing multiple eigenvalues
|
||||
//! after the first iteration step
|
||||
float *g_left_mult;
|
||||
|
||||
//! right interval limits of intervals containing multiple eigenvalues
|
||||
//! after the first iteration step
|
||||
float *g_right_mult;
|
||||
//! right interval limits of intervals containing multiple eigenvalues
|
||||
//! after the first iteration step
|
||||
float *g_right_mult;
|
||||
|
||||
//! number of eigenvalues less than the left limit of the eigenvalue
|
||||
//! intervals containing multiple eigenvalues
|
||||
unsigned int *g_left_count_mult;
|
||||
//! number of eigenvalues less than the left limit of the eigenvalue
|
||||
//! intervals containing multiple eigenvalues
|
||||
unsigned int *g_left_count_mult;
|
||||
|
||||
//! number of eigenvalues less than the right limit of the eigenvalue
|
||||
//! intervals containing multiple eigenvalues
|
||||
unsigned int *g_right_count_mult;
|
||||
//! number of eigenvalues less than the right limit of the eigenvalue
|
||||
//! intervals containing multiple eigenvalues
|
||||
unsigned int *g_right_count_mult;
|
||||
|
||||
//! start addresses in g_left_mult etc. of blocks of intervals containing
|
||||
//! more than one eigenvalue after the first step
|
||||
unsigned int *g_blocks_mult;
|
||||
//! start addresses in g_left_mult etc. of blocks of intervals containing
|
||||
//! more than one eigenvalue after the first step
|
||||
unsigned int *g_blocks_mult;
|
||||
|
||||
//! accumulated number of intervals in g_left_mult etc. of blocks of
|
||||
//! intervals containing more than one eigenvalue after the first step
|
||||
unsigned int *g_blocks_mult_sum;
|
||||
//! accumulated number of intervals in g_left_mult etc. of blocks of
|
||||
//! intervals containing more than one eigenvalue after the first step
|
||||
unsigned int *g_blocks_mult_sum;
|
||||
|
||||
//! eigenvalues that have been generated in the second step from intervals
|
||||
//! that still contained multiple eigenvalues after the first step
|
||||
float *g_lambda_mult;
|
||||
//! eigenvalues that have been generated in the second step from intervals
|
||||
//! that still contained multiple eigenvalues after the first step
|
||||
float *g_lambda_mult;
|
||||
|
||||
//! eigenvalue index of intervals that have been generated in the second
|
||||
//! processing step
|
||||
unsigned int *g_pos_mult;
|
||||
//! eigenvalue index of intervals that have been generated in the second
|
||||
//! processing step
|
||||
unsigned int *g_pos_mult;
|
||||
};
|
||||
|
||||
#endif // #ifndef _STRUCTS_H_
|
||||
#endif // #ifndef _STRUCTS_H_
|
||||
|
||||
@@ -33,12 +33,12 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//! Safely free() for pointer
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
template <class T>
|
||||
inline void freePtr(T *&ptr) {
|
||||
if (NULL != ptr) {
|
||||
free(ptr);
|
||||
ptr = NULL;
|
||||
}
|
||||
template <class T> inline void freePtr(T *&ptr)
|
||||
{
|
||||
if (NULL != ptr) {
|
||||
free(ptr);
|
||||
ptr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -50,9 +50,10 @@ __host__
|
||||
__device__
|
||||
#endif
|
||||
T
|
||||
min(const T &lhs, const T &rhs) {
|
||||
min(const T &lhs, const T &rhs)
|
||||
{
|
||||
|
||||
return (lhs < rhs) ? lhs : rhs;
|
||||
return (lhs < rhs) ? lhs : rhs;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -64,9 +65,10 @@ __host__
|
||||
__device__
|
||||
#endif
|
||||
T
|
||||
max(const T &lhs, const T &rhs) {
|
||||
max(const T &lhs, const T &rhs)
|
||||
{
|
||||
|
||||
return (lhs < rhs) ? rhs : lhs;
|
||||
return (lhs < rhs) ? rhs : lhs;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -78,8 +80,9 @@ __host__
|
||||
__device__
|
||||
#endif
|
||||
T
|
||||
sign_i(const T &val) {
|
||||
return (val < 0) ? -1 : 1;
|
||||
sign_i(const T &val)
|
||||
{
|
||||
return (val < 0) ? -1 : 1;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -89,8 +92,9 @@ __host__
|
||||
__host__ __device__
|
||||
#endif
|
||||
inline float
|
||||
sign_f(const float &val) {
|
||||
return (val < 0.0f) ? -1.0f : 1.0f;
|
||||
sign_f(const float &val)
|
||||
{
|
||||
return (val < 0.0f) ? -1.0f : 1.0f;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -100,8 +104,9 @@ __host__ __device__
|
||||
__host__ __device__
|
||||
#endif
|
||||
inline double
|
||||
sign_d(const double &val) {
|
||||
return (val < 0.0) ? -1.0 : 1.0;
|
||||
sign_d(const double &val)
|
||||
{
|
||||
return (val < 0.0) ? -1.0 : 1.0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -112,22 +117,22 @@ template <class T>
|
||||
__host__ __device__
|
||||
#endif
|
||||
void
|
||||
swap(T &lhs, T &rhs) {
|
||||
swap(T &lhs, T &rhs)
|
||||
{
|
||||
|
||||
T temp = rhs;
|
||||
rhs = lhs;
|
||||
lhs = temp;
|
||||
T temp = rhs;
|
||||
rhs = lhs;
|
||||
lhs = temp;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//! Get the number of blocks that are required to process \a num_threads with
|
||||
//! \a num_threads_blocks threads per block
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
extern "C" inline unsigned int getNumBlocksLinear(
|
||||
const unsigned int num_threads, const unsigned int num_threads_block) {
|
||||
const unsigned int block_rem =
|
||||
((num_threads % num_threads_block) != 0) ? 1 : 0;
|
||||
return (num_threads / num_threads_block) + block_rem;
|
||||
extern "C" inline unsigned int getNumBlocksLinear(const unsigned int num_threads, const unsigned int num_threads_block)
|
||||
{
|
||||
const unsigned int block_rem = ((num_threads % num_threads_block) != 0) ? 1 : 0;
|
||||
return (num_threads / num_threads_block) + block_rem;
|
||||
}
|
||||
|
||||
#endif // #ifndef _UTIL_H_
|
||||
#endif // #ifndef _UTIL_H_
|
||||
|
||||
@@ -26,13 +26,14 @@
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <cooperative_groups.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <cooperative_groups.h>
|
||||
|
||||
namespace cg = cooperative_groups;
|
||||
#include <helper_cuda.h>
|
||||
|
||||
#include "histogram_common.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -40,59 +41,53 @@ namespace cg = cooperative_groups;
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define TAG_MASK 0xFFFFFFFFU
|
||||
inline __device__ void addByte(uint *s_WarpHist, uint data, uint threadTag) {
|
||||
atomicAdd(s_WarpHist + data, 1);
|
||||
inline __device__ void addByte(uint *s_WarpHist, uint data, uint threadTag) { atomicAdd(s_WarpHist + data, 1); }
|
||||
|
||||
inline __device__ void addWord(uint *s_WarpHist, uint data, uint tag)
|
||||
{
|
||||
addByte(s_WarpHist, (data >> 0) & 0xFFU, tag);
|
||||
addByte(s_WarpHist, (data >> 8) & 0xFFU, tag);
|
||||
addByte(s_WarpHist, (data >> 16) & 0xFFU, tag);
|
||||
addByte(s_WarpHist, (data >> 24) & 0xFFU, tag);
|
||||
}
|
||||
|
||||
inline __device__ void addWord(uint *s_WarpHist, uint data, uint tag) {
|
||||
addByte(s_WarpHist, (data >> 0) & 0xFFU, tag);
|
||||
addByte(s_WarpHist, (data >> 8) & 0xFFU, tag);
|
||||
addByte(s_WarpHist, (data >> 16) & 0xFFU, tag);
|
||||
addByte(s_WarpHist, (data >> 24) & 0xFFU, tag);
|
||||
}
|
||||
|
||||
__global__ void histogram256Kernel(uint *d_PartialHistograms, uint *d_Data,
|
||||
uint dataCount) {
|
||||
// Handle to thread block group
|
||||
cg::thread_block cta = cg::this_thread_block();
|
||||
// Per-warp subhistogram storage
|
||||
__shared__ uint s_Hist[HISTOGRAM256_THREADBLOCK_MEMORY];
|
||||
uint *s_WarpHist =
|
||||
s_Hist + (threadIdx.x >> LOG2_WARP_SIZE) * HISTOGRAM256_BIN_COUNT;
|
||||
__global__ void histogram256Kernel(uint *d_PartialHistograms, uint *d_Data, uint dataCount)
|
||||
{
|
||||
// Handle to thread block group
|
||||
cg::thread_block cta = cg::this_thread_block();
|
||||
// Per-warp subhistogram storage
|
||||
__shared__ uint s_Hist[HISTOGRAM256_THREADBLOCK_MEMORY];
|
||||
uint *s_WarpHist = s_Hist + (threadIdx.x >> LOG2_WARP_SIZE) * HISTOGRAM256_BIN_COUNT;
|
||||
|
||||
// Clear shared memory storage for current threadblock before processing
|
||||
#pragma unroll
|
||||
|
||||
for (uint i = 0;
|
||||
i < (HISTOGRAM256_THREADBLOCK_MEMORY / HISTOGRAM256_THREADBLOCK_SIZE);
|
||||
i++) {
|
||||
s_Hist[threadIdx.x + i * HISTOGRAM256_THREADBLOCK_SIZE] = 0;
|
||||
}
|
||||
|
||||
// Cycle through the entire data set, update subhistograms for each warp
|
||||
const uint tag = threadIdx.x << (UINT_BITS - LOG2_WARP_SIZE);
|
||||
|
||||
cg::sync(cta);
|
||||
|
||||
for (uint pos = UMAD(blockIdx.x, blockDim.x, threadIdx.x); pos < dataCount;
|
||||
pos += UMUL(blockDim.x, gridDim.x)) {
|
||||
uint data = d_Data[pos];
|
||||
addWord(s_WarpHist, data, tag);
|
||||
}
|
||||
|
||||
// Merge per-warp histograms into per-block and write to global memory
|
||||
cg::sync(cta);
|
||||
|
||||
for (uint bin = threadIdx.x; bin < HISTOGRAM256_BIN_COUNT;
|
||||
bin += HISTOGRAM256_THREADBLOCK_SIZE) {
|
||||
uint sum = 0;
|
||||
|
||||
for (uint i = 0; i < WARP_COUNT; i++) {
|
||||
sum += s_Hist[bin + i * HISTOGRAM256_BIN_COUNT] & TAG_MASK;
|
||||
for (uint i = 0; i < (HISTOGRAM256_THREADBLOCK_MEMORY / HISTOGRAM256_THREADBLOCK_SIZE); i++) {
|
||||
s_Hist[threadIdx.x + i * HISTOGRAM256_THREADBLOCK_SIZE] = 0;
|
||||
}
|
||||
|
||||
d_PartialHistograms[blockIdx.x * HISTOGRAM256_BIN_COUNT + bin] = sum;
|
||||
}
|
||||
// Cycle through the entire data set, update subhistograms for each warp
|
||||
const uint tag = threadIdx.x << (UINT_BITS - LOG2_WARP_SIZE);
|
||||
|
||||
cg::sync(cta);
|
||||
|
||||
for (uint pos = UMAD(blockIdx.x, blockDim.x, threadIdx.x); pos < dataCount; pos += UMUL(blockDim.x, gridDim.x)) {
|
||||
uint data = d_Data[pos];
|
||||
addWord(s_WarpHist, data, tag);
|
||||
}
|
||||
|
||||
// Merge per-warp histograms into per-block and write to global memory
|
||||
cg::sync(cta);
|
||||
|
||||
for (uint bin = threadIdx.x; bin < HISTOGRAM256_BIN_COUNT; bin += HISTOGRAM256_THREADBLOCK_SIZE) {
|
||||
uint sum = 0;
|
||||
|
||||
for (uint i = 0; i < WARP_COUNT; i++) {
|
||||
sum += s_Hist[bin + i * HISTOGRAM256_BIN_COUNT] & TAG_MASK;
|
||||
}
|
||||
|
||||
d_PartialHistograms[blockIdx.x * HISTOGRAM256_BIN_COUNT + bin] = sum;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -103,32 +98,31 @@ __global__ void histogram256Kernel(uint *d_PartialHistograms, uint *d_Data,
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#define MERGE_THREADBLOCK_SIZE 256
|
||||
|
||||
__global__ void mergeHistogram256Kernel(uint *d_Histogram,
|
||||
uint *d_PartialHistograms,
|
||||
uint histogramCount) {
|
||||
// Handle to thread block group
|
||||
cg::thread_block cta = cg::this_thread_block();
|
||||
__global__ void mergeHistogram256Kernel(uint *d_Histogram, uint *d_PartialHistograms, uint histogramCount)
|
||||
{
|
||||
// Handle to thread block group
|
||||
cg::thread_block cta = cg::this_thread_block();
|
||||
|
||||
uint sum = 0;
|
||||
uint sum = 0;
|
||||
|
||||
for (uint i = threadIdx.x; i < histogramCount; i += MERGE_THREADBLOCK_SIZE) {
|
||||
sum += d_PartialHistograms[blockIdx.x + i * HISTOGRAM256_BIN_COUNT];
|
||||
}
|
||||
|
||||
__shared__ uint data[MERGE_THREADBLOCK_SIZE];
|
||||
data[threadIdx.x] = sum;
|
||||
|
||||
for (uint stride = MERGE_THREADBLOCK_SIZE / 2; stride > 0; stride >>= 1) {
|
||||
cg::sync(cta);
|
||||
|
||||
if (threadIdx.x < stride) {
|
||||
data[threadIdx.x] += data[threadIdx.x + stride];
|
||||
for (uint i = threadIdx.x; i < histogramCount; i += MERGE_THREADBLOCK_SIZE) {
|
||||
sum += d_PartialHistograms[blockIdx.x + i * HISTOGRAM256_BIN_COUNT];
|
||||
}
|
||||
}
|
||||
|
||||
if (threadIdx.x == 0) {
|
||||
d_Histogram[blockIdx.x] = data[0];
|
||||
}
|
||||
__shared__ uint data[MERGE_THREADBLOCK_SIZE];
|
||||
data[threadIdx.x] = sum;
|
||||
|
||||
for (uint stride = MERGE_THREADBLOCK_SIZE / 2; stride > 0; stride >>= 1) {
|
||||
cg::sync(cta);
|
||||
|
||||
if (threadIdx.x < stride) {
|
||||
data[threadIdx.x] += data[threadIdx.x + stride];
|
||||
}
|
||||
}
|
||||
|
||||
if (threadIdx.x == 0) {
|
||||
d_Histogram[blockIdx.x] = data[0];
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -136,28 +130,26 @@ __global__ void mergeHistogram256Kernel(uint *d_Histogram,
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// histogram256kernel() intermediate results buffer
|
||||
static const uint PARTIAL_HISTOGRAM256_COUNT = 240;
|
||||
static uint *d_PartialHistograms;
|
||||
static uint *d_PartialHistograms;
|
||||
|
||||
// Internal memory allocation
|
||||
extern "C" void initHistogram256(void) {
|
||||
checkCudaErrors(cudaMalloc(
|
||||
(void **)&d_PartialHistograms,
|
||||
PARTIAL_HISTOGRAM256_COUNT * HISTOGRAM256_BIN_COUNT * sizeof(uint)));
|
||||
extern "C" void initHistogram256(void)
|
||||
{
|
||||
checkCudaErrors(
|
||||
cudaMalloc((void **)&d_PartialHistograms, PARTIAL_HISTOGRAM256_COUNT * HISTOGRAM256_BIN_COUNT * sizeof(uint)));
|
||||
}
|
||||
|
||||
// Internal memory deallocation
|
||||
extern "C" void closeHistogram256(void) {
|
||||
checkCudaErrors(cudaFree(d_PartialHistograms));
|
||||
}
|
||||
extern "C" void closeHistogram256(void) { checkCudaErrors(cudaFree(d_PartialHistograms)); }
|
||||
|
||||
extern "C" void histogram256(uint *d_Histogram, void *d_Data, uint byteCount) {
|
||||
assert(byteCount % sizeof(uint) == 0);
|
||||
histogram256Kernel<<<PARTIAL_HISTOGRAM256_COUNT,
|
||||
HISTOGRAM256_THREADBLOCK_SIZE>>>(
|
||||
d_PartialHistograms, (uint *)d_Data, byteCount / sizeof(uint));
|
||||
getLastCudaError("histogram256Kernel() execution failed\n");
|
||||
extern "C" void histogram256(uint *d_Histogram, void *d_Data, uint byteCount)
|
||||
{
|
||||
assert(byteCount % sizeof(uint) == 0);
|
||||
histogram256Kernel<<<PARTIAL_HISTOGRAM256_COUNT, HISTOGRAM256_THREADBLOCK_SIZE>>>(
|
||||
d_PartialHistograms, (uint *)d_Data, byteCount / sizeof(uint));
|
||||
getLastCudaError("histogram256Kernel() execution failed\n");
|
||||
|
||||
mergeHistogram256Kernel<<<HISTOGRAM256_BIN_COUNT, MERGE_THREADBLOCK_SIZE>>>(
|
||||
d_Histogram, d_PartialHistograms, PARTIAL_HISTOGRAM256_COUNT);
|
||||
getLastCudaError("mergeHistogram256Kernel() execution failed\n");
|
||||
mergeHistogram256Kernel<<<HISTOGRAM256_BIN_COUNT, MERGE_THREADBLOCK_SIZE>>>(
|
||||
d_Histogram, d_PartialHistograms, PARTIAL_HISTOGRAM256_COUNT);
|
||||
getLastCudaError("mergeHistogram256Kernel() execution failed\n");
|
||||
}
|
||||
|
||||
@@ -26,13 +26,14 @@
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <cooperative_groups.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <cooperative_groups.h>
|
||||
|
||||
namespace cg = cooperative_groups;
|
||||
#include <helper_cuda.h>
|
||||
|
||||
#include "histogram_common.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -48,78 +49,77 @@ typedef uint4 data_t;
|
||||
// Main computation pass: compute gridDim.x partial histograms
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Count a byte into shared-memory storage
|
||||
inline __device__ void addByte(uchar *s_ThreadBase, uint data) {
|
||||
s_ThreadBase[UMUL(data, HISTOGRAM64_THREADBLOCK_SIZE)]++;
|
||||
inline __device__ void addByte(uchar *s_ThreadBase, uint data)
|
||||
{
|
||||
s_ThreadBase[UMUL(data, HISTOGRAM64_THREADBLOCK_SIZE)]++;
|
||||
}
|
||||
|
||||
// Count four bytes of a word
|
||||
inline __device__ void addWord(uchar *s_ThreadBase, uint data) {
|
||||
// Only higher 6 bits of each byte matter, as this is a 64-bin histogram
|
||||
addByte(s_ThreadBase, (data >> 2) & 0x3FU);
|
||||
addByte(s_ThreadBase, (data >> 10) & 0x3FU);
|
||||
addByte(s_ThreadBase, (data >> 18) & 0x3FU);
|
||||
addByte(s_ThreadBase, (data >> 26) & 0x3FU);
|
||||
inline __device__ void addWord(uchar *s_ThreadBase, uint data)
|
||||
{
|
||||
// Only higher 6 bits of each byte matter, as this is a 64-bin histogram
|
||||
addByte(s_ThreadBase, (data >> 2) & 0x3FU);
|
||||
addByte(s_ThreadBase, (data >> 10) & 0x3FU);
|
||||
addByte(s_ThreadBase, (data >> 18) & 0x3FU);
|
||||
addByte(s_ThreadBase, (data >> 26) & 0x3FU);
|
||||
}
|
||||
|
||||
__global__ void histogram64Kernel(uint *d_PartialHistograms, data_t *d_Data,
|
||||
uint dataCount) {
|
||||
// Handle to thread block group
|
||||
cg::thread_block cta = cg::this_thread_block();
|
||||
// Encode thread index in order to avoid bank conflicts in s_Hist[] access:
|
||||
// each group of SHARED_MEMORY_BANKS threads accesses consecutive shared
|
||||
// memory banks
|
||||
// and the same bytes [0..3] within the banks
|
||||
// Because of this permutation block size should be a multiple of 4 *
|
||||
// SHARED_MEMORY_BANKS
|
||||
const uint threadPos = ((threadIdx.x & ~(SHARED_MEMORY_BANKS * 4 - 1)) << 0) |
|
||||
((threadIdx.x & (SHARED_MEMORY_BANKS - 1)) << 2) |
|
||||
((threadIdx.x & (SHARED_MEMORY_BANKS * 3)) >> 4);
|
||||
__global__ void histogram64Kernel(uint *d_PartialHistograms, data_t *d_Data, uint dataCount)
|
||||
{
|
||||
// Handle to thread block group
|
||||
cg::thread_block cta = cg::this_thread_block();
|
||||
// Encode thread index in order to avoid bank conflicts in s_Hist[] access:
|
||||
// each group of SHARED_MEMORY_BANKS threads accesses consecutive shared
|
||||
// memory banks
|
||||
// and the same bytes [0..3] within the banks
|
||||
// Because of this permutation block size should be a multiple of 4 *
|
||||
// SHARED_MEMORY_BANKS
|
||||
const uint threadPos = ((threadIdx.x & ~(SHARED_MEMORY_BANKS * 4 - 1)) << 0)
|
||||
| ((threadIdx.x & (SHARED_MEMORY_BANKS - 1)) << 2)
|
||||
| ((threadIdx.x & (SHARED_MEMORY_BANKS * 3)) >> 4);
|
||||
|
||||
// Per-thread histogram storage
|
||||
__shared__ uchar s_Hist[HISTOGRAM64_THREADBLOCK_SIZE * HISTOGRAM64_BIN_COUNT];
|
||||
uchar *s_ThreadBase = s_Hist + threadPos;
|
||||
// Per-thread histogram storage
|
||||
__shared__ uchar s_Hist[HISTOGRAM64_THREADBLOCK_SIZE * HISTOGRAM64_BIN_COUNT];
|
||||
uchar *s_ThreadBase = s_Hist + threadPos;
|
||||
|
||||
// Initialize shared memory (writing 32-bit words)
|
||||
#pragma unroll
|
||||
|
||||
for (uint i = 0; i < (HISTOGRAM64_BIN_COUNT / 4); i++) {
|
||||
((uint *)s_Hist)[threadIdx.x + i * HISTOGRAM64_THREADBLOCK_SIZE] = 0;
|
||||
}
|
||||
for (uint i = 0; i < (HISTOGRAM64_BIN_COUNT / 4); i++) {
|
||||
((uint *)s_Hist)[threadIdx.x + i * HISTOGRAM64_THREADBLOCK_SIZE] = 0;
|
||||
}
|
||||
|
||||
// Read data from global memory and submit to the shared-memory histogram
|
||||
// Since histogram counters are byte-sized, every single thread can't do more
|
||||
// than 255 submission
|
||||
cg::sync(cta);
|
||||
// Read data from global memory and submit to the shared-memory histogram
|
||||
// Since histogram counters are byte-sized, every single thread can't do more
|
||||
// than 255 submission
|
||||
cg::sync(cta);
|
||||
|
||||
for (uint pos = UMAD(blockIdx.x, blockDim.x, threadIdx.x); pos < dataCount;
|
||||
pos += UMUL(blockDim.x, gridDim.x)) {
|
||||
data_t data = d_Data[pos];
|
||||
addWord(s_ThreadBase, data.x);
|
||||
addWord(s_ThreadBase, data.y);
|
||||
addWord(s_ThreadBase, data.z);
|
||||
addWord(s_ThreadBase, data.w);
|
||||
}
|
||||
for (uint pos = UMAD(blockIdx.x, blockDim.x, threadIdx.x); pos < dataCount; pos += UMUL(blockDim.x, gridDim.x)) {
|
||||
data_t data = d_Data[pos];
|
||||
addWord(s_ThreadBase, data.x);
|
||||
addWord(s_ThreadBase, data.y);
|
||||
addWord(s_ThreadBase, data.z);
|
||||
addWord(s_ThreadBase, data.w);
|
||||
}
|
||||
|
||||
// Accumulate per-thread histograms into per-block and write to global memory
|
||||
cg::sync(cta);
|
||||
// Accumulate per-thread histograms into per-block and write to global memory
|
||||
cg::sync(cta);
|
||||
|
||||
if (threadIdx.x < HISTOGRAM64_BIN_COUNT) {
|
||||
uchar *s_HistBase =
|
||||
s_Hist + UMUL(threadIdx.x, HISTOGRAM64_THREADBLOCK_SIZE);
|
||||
if (threadIdx.x < HISTOGRAM64_BIN_COUNT) {
|
||||
uchar *s_HistBase = s_Hist + UMUL(threadIdx.x, HISTOGRAM64_THREADBLOCK_SIZE);
|
||||
|
||||
uint sum = 0;
|
||||
uint pos = 4 * (threadIdx.x & (SHARED_MEMORY_BANKS - 1));
|
||||
uint sum = 0;
|
||||
uint pos = 4 * (threadIdx.x & (SHARED_MEMORY_BANKS - 1));
|
||||
|
||||
#pragma unroll
|
||||
|
||||
for (uint i = 0; i < (HISTOGRAM64_THREADBLOCK_SIZE / 4); i++) {
|
||||
sum += s_HistBase[pos + 0] + s_HistBase[pos + 1] + s_HistBase[pos + 2] +
|
||||
s_HistBase[pos + 3];
|
||||
pos = (pos + 4) & (HISTOGRAM64_THREADBLOCK_SIZE - 1);
|
||||
}
|
||||
for (uint i = 0; i < (HISTOGRAM64_THREADBLOCK_SIZE / 4); i++) {
|
||||
sum += s_HistBase[pos + 0] + s_HistBase[pos + 1] + s_HistBase[pos + 2] + s_HistBase[pos + 3];
|
||||
pos = (pos + 4) & (HISTOGRAM64_THREADBLOCK_SIZE - 1);
|
||||
}
|
||||
|
||||
d_PartialHistograms[blockIdx.x * HISTOGRAM64_BIN_COUNT + threadIdx.x] = sum;
|
||||
}
|
||||
d_PartialHistograms[blockIdx.x * HISTOGRAM64_BIN_COUNT + threadIdx.x] = sum;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -130,32 +130,31 @@ __global__ void histogram64Kernel(uint *d_PartialHistograms, data_t *d_Data,
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#define MERGE_THREADBLOCK_SIZE 256
|
||||
|
||||
__global__ void mergeHistogram64Kernel(uint *d_Histogram,
|
||||
uint *d_PartialHistograms,
|
||||
uint histogramCount) {
|
||||
// Handle to thread block group
|
||||
cg::thread_block cta = cg::this_thread_block();
|
||||
__shared__ uint data[MERGE_THREADBLOCK_SIZE];
|
||||
__global__ void mergeHistogram64Kernel(uint *d_Histogram, uint *d_PartialHistograms, uint histogramCount)
|
||||
{
|
||||
// Handle to thread block group
|
||||
cg::thread_block cta = cg::this_thread_block();
|
||||
__shared__ uint data[MERGE_THREADBLOCK_SIZE];
|
||||
|
||||
uint sum = 0;
|
||||
uint sum = 0;
|
||||
|
||||
for (uint i = threadIdx.x; i < histogramCount; i += MERGE_THREADBLOCK_SIZE) {
|
||||
sum += d_PartialHistograms[blockIdx.x + i * HISTOGRAM64_BIN_COUNT];
|
||||
}
|
||||
|
||||
data[threadIdx.x] = sum;
|
||||
|
||||
for (uint stride = MERGE_THREADBLOCK_SIZE / 2; stride > 0; stride >>= 1) {
|
||||
cg::sync(cta);
|
||||
|
||||
if (threadIdx.x < stride) {
|
||||
data[threadIdx.x] += data[threadIdx.x + stride];
|
||||
for (uint i = threadIdx.x; i < histogramCount; i += MERGE_THREADBLOCK_SIZE) {
|
||||
sum += d_PartialHistograms[blockIdx.x + i * HISTOGRAM64_BIN_COUNT];
|
||||
}
|
||||
}
|
||||
|
||||
if (threadIdx.x == 0) {
|
||||
d_Histogram[blockIdx.x] = data[0];
|
||||
}
|
||||
data[threadIdx.x] = sum;
|
||||
|
||||
for (uint stride = MERGE_THREADBLOCK_SIZE / 2; stride > 0; stride >>= 1) {
|
||||
cg::sync(cta);
|
||||
|
||||
if (threadIdx.x < stride) {
|
||||
data[threadIdx.x] += data[threadIdx.x + stride];
|
||||
}
|
||||
}
|
||||
|
||||
if (threadIdx.x == 0) {
|
||||
d_Histogram[blockIdx.x] = data[0];
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -165,41 +164,37 @@ __global__ void mergeHistogram64Kernel(uint *d_Histogram,
|
||||
// MAX_PARTIAL_HISTOGRAM64_COUNT == 32768 and HISTOGRAM64_THREADBLOCK_SIZE == 64
|
||||
// amounts to max. 480MB of input data
|
||||
static const uint MAX_PARTIAL_HISTOGRAM64_COUNT = 32768;
|
||||
static uint *d_PartialHistograms;
|
||||
static uint *d_PartialHistograms;
|
||||
|
||||
// Internal memory allocation
|
||||
extern "C" void initHistogram64(void) {
|
||||
assert(HISTOGRAM64_THREADBLOCK_SIZE % (4 * SHARED_MEMORY_BANKS) == 0);
|
||||
checkCudaErrors(cudaMalloc(
|
||||
(void **)&d_PartialHistograms,
|
||||
MAX_PARTIAL_HISTOGRAM64_COUNT * HISTOGRAM64_BIN_COUNT * sizeof(uint)));
|
||||
extern "C" void initHistogram64(void)
|
||||
{
|
||||
assert(HISTOGRAM64_THREADBLOCK_SIZE % (4 * SHARED_MEMORY_BANKS) == 0);
|
||||
checkCudaErrors(cudaMalloc((void **)&d_PartialHistograms,
|
||||
MAX_PARTIAL_HISTOGRAM64_COUNT * HISTOGRAM64_BIN_COUNT * sizeof(uint)));
|
||||
}
|
||||
|
||||
// Internal memory deallocation
|
||||
extern "C" void closeHistogram64(void) {
|
||||
checkCudaErrors(cudaFree(d_PartialHistograms));
|
||||
}
|
||||
extern "C" void closeHistogram64(void) { checkCudaErrors(cudaFree(d_PartialHistograms)); }
|
||||
|
||||
// Round a / b to nearest higher integer value
|
||||
inline uint iDivUp(uint a, uint b) {
|
||||
return (a % b != 0) ? (a / b + 1) : (a / b);
|
||||
}
|
||||
inline uint iDivUp(uint a, uint b) { return (a % b != 0) ? (a / b + 1) : (a / b); }
|
||||
|
||||
// Snap a to nearest lower multiple of b
|
||||
inline uint iSnapDown(uint a, uint b) { return a - a % b; }
|
||||
|
||||
extern "C" void histogram64(uint *d_Histogram, void *d_Data, uint byteCount) {
|
||||
const uint histogramCount = iDivUp(
|
||||
byteCount, HISTOGRAM64_THREADBLOCK_SIZE * iSnapDown(255, sizeof(data_t)));
|
||||
extern "C" void histogram64(uint *d_Histogram, void *d_Data, uint byteCount)
|
||||
{
|
||||
const uint histogramCount = iDivUp(byteCount, HISTOGRAM64_THREADBLOCK_SIZE * iSnapDown(255, sizeof(data_t)));
|
||||
|
||||
assert(byteCount % sizeof(data_t) == 0);
|
||||
assert(histogramCount <= MAX_PARTIAL_HISTOGRAM64_COUNT);
|
||||
assert(byteCount % sizeof(data_t) == 0);
|
||||
assert(histogramCount <= MAX_PARTIAL_HISTOGRAM64_COUNT);
|
||||
|
||||
histogram64Kernel<<<histogramCount, HISTOGRAM64_THREADBLOCK_SIZE>>>(
|
||||
d_PartialHistograms, (data_t *)d_Data, byteCount / sizeof(data_t));
|
||||
getLastCudaError("histogram64Kernel() execution failed\n");
|
||||
histogram64Kernel<<<histogramCount, HISTOGRAM64_THREADBLOCK_SIZE>>>(
|
||||
d_PartialHistograms, (data_t *)d_Data, byteCount / sizeof(data_t));
|
||||
getLastCudaError("histogram64Kernel() execution failed\n");
|
||||
|
||||
mergeHistogram64Kernel<<<HISTOGRAM64_BIN_COUNT, MERGE_THREADBLOCK_SIZE>>>(
|
||||
d_Histogram, d_PartialHistograms, histogramCount);
|
||||
getLastCudaError("mergeHistogram64() execution failed\n");
|
||||
mergeHistogram64Kernel<<<HISTOGRAM64_BIN_COUNT, MERGE_THREADBLOCK_SIZE>>>(
|
||||
d_Histogram, d_PartialHistograms, histogramCount);
|
||||
getLastCudaError("mergeHistogram64() execution failed\n");
|
||||
}
|
||||
|
||||
@@ -31,17 +31,17 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Common definitions
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#define HISTOGRAM64_BIN_COUNT 64
|
||||
#define HISTOGRAM64_BIN_COUNT 64
|
||||
#define HISTOGRAM256_BIN_COUNT 256
|
||||
#define UINT_BITS 32
|
||||
typedef unsigned int uint;
|
||||
#define UINT_BITS 32
|
||||
typedef unsigned int uint;
|
||||
typedef unsigned char uchar;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// GPU-specific common definitions
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#define LOG2_WARP_SIZE 5U
|
||||
#define WARP_SIZE (1U << LOG2_WARP_SIZE)
|
||||
#define WARP_SIZE (1U << LOG2_WARP_SIZE)
|
||||
|
||||
// May change on future hardware, so better parametrize the code
|
||||
#define SHARED_MEMORY_BANKS 16
|
||||
@@ -59,7 +59,7 @@ typedef unsigned char uchar;
|
||||
// Shared memory per threadblock
|
||||
#define HISTOGRAM256_THREADBLOCK_MEMORY (WARP_COUNT * HISTOGRAM256_BIN_COUNT)
|
||||
|
||||
#define UMUL(a, b) ((a) * (b))
|
||||
#define UMUL(a, b) ((a) * (b))
|
||||
#define UMAD(a, b, c) (UMUL((a), (b)) + (c))
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -67,8 +67,7 @@ typedef unsigned char uchar;
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
extern "C" void histogram64CPU(uint *h_Histogram, void *h_Data, uint byteCount);
|
||||
|
||||
extern "C" void histogram256CPU(uint *h_Histogram, void *h_Data,
|
||||
uint byteCount);
|
||||
extern "C" void histogram256CPU(uint *h_Histogram, void *h_Data, uint byteCount);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// GPU histogram
|
||||
|
||||
@@ -26,34 +26,37 @@
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "histogram_common.h"
|
||||
|
||||
extern "C" void histogram64CPU(uint *h_Histogram, void *h_Data,
|
||||
uint byteCount) {
|
||||
for (uint i = 0; i < HISTOGRAM64_BIN_COUNT; i++) h_Histogram[i] = 0;
|
||||
extern "C" void histogram64CPU(uint *h_Histogram, void *h_Data, uint byteCount)
|
||||
{
|
||||
for (uint i = 0; i < HISTOGRAM64_BIN_COUNT; i++)
|
||||
h_Histogram[i] = 0;
|
||||
|
||||
assert(sizeof(uint) == 4 && (byteCount % 4) == 0);
|
||||
assert(sizeof(uint) == 4 && (byteCount % 4) == 0);
|
||||
|
||||
for (uint i = 0; i < (byteCount / 4); i++) {
|
||||
uint data = ((uint *)h_Data)[i];
|
||||
h_Histogram[(data >> 2) & 0x3FU]++;
|
||||
h_Histogram[(data >> 10) & 0x3FU]++;
|
||||
h_Histogram[(data >> 18) & 0x3FU]++;
|
||||
h_Histogram[(data >> 26) & 0x3FU]++;
|
||||
}
|
||||
for (uint i = 0; i < (byteCount / 4); i++) {
|
||||
uint data = ((uint *)h_Data)[i];
|
||||
h_Histogram[(data >> 2) & 0x3FU]++;
|
||||
h_Histogram[(data >> 10) & 0x3FU]++;
|
||||
h_Histogram[(data >> 18) & 0x3FU]++;
|
||||
h_Histogram[(data >> 26) & 0x3FU]++;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void histogram256CPU(uint *h_Histogram, void *h_Data,
|
||||
uint byteCount) {
|
||||
for (uint i = 0; i < HISTOGRAM256_BIN_COUNT; i++) h_Histogram[i] = 0;
|
||||
extern "C" void histogram256CPU(uint *h_Histogram, void *h_Data, uint byteCount)
|
||||
{
|
||||
for (uint i = 0; i < HISTOGRAM256_BIN_COUNT; i++)
|
||||
h_Histogram[i] = 0;
|
||||
|
||||
assert(sizeof(uint) == 4 && (byteCount % 4) == 0);
|
||||
assert(sizeof(uint) == 4 && (byteCount % 4) == 0);
|
||||
|
||||
for (uint i = 0; i < (byteCount / 4); i++) {
|
||||
uint data = ((uint *)h_Data)[i];
|
||||
h_Histogram[(data >> 0) & 0xFFU]++;
|
||||
h_Histogram[(data >> 8) & 0xFFU]++;
|
||||
h_Histogram[(data >> 16) & 0xFFU]++;
|
||||
h_Histogram[(data >> 24) & 0xFFU]++;
|
||||
}
|
||||
for (uint i = 0; i < (byteCount / 4); i++) {
|
||||
uint data = ((uint *)h_Data)[i];
|
||||
h_Histogram[(data >> 0) & 0xFFU]++;
|
||||
h_Histogram[(data >> 8) & 0xFFU]++;
|
||||
h_Histogram[(data >> 16) & 0xFFU]++;
|
||||
h_Histogram[(data >> 24) & 0xFFU]++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,205 +26,203 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* This sample implements 64-bin histogram calculation
|
||||
* of arbitrary-sized 8-bit data array
|
||||
*/
|
||||
* This sample implements 64-bin histogram calculation
|
||||
* of arbitrary-sized 8-bit data array
|
||||
*/
|
||||
|
||||
// CUDA Runtime
|
||||
#include <cuda_runtime.h>
|
||||
|
||||
// Utility and system includes
|
||||
#include <helper_cuda.h>
|
||||
#include <helper_functions.h> // helper for shared that are common to CUDA Samples
|
||||
#include <helper_functions.h> // helper for shared that are common to CUDA Samples
|
||||
|
||||
// project include
|
||||
#include "histogram_common.h"
|
||||
|
||||
const int numRuns = 16;
|
||||
const int numRuns = 16;
|
||||
const static char *sSDKsample = "[histogram]\0";
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
uchar *h_Data;
|
||||
uint *h_HistogramCPU, *h_HistogramGPU;
|
||||
uchar *d_Data;
|
||||
uint *d_Histogram;
|
||||
StopWatchInterface *hTimer = NULL;
|
||||
int PassFailFlag = 1;
|
||||
uint byteCount = 64 * 1048576;
|
||||
uint uiSizeMult = 1;
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
uchar *h_Data;
|
||||
uint *h_HistogramCPU, *h_HistogramGPU;
|
||||
uchar *d_Data;
|
||||
uint *d_Histogram;
|
||||
StopWatchInterface *hTimer = NULL;
|
||||
int PassFailFlag = 1;
|
||||
uint byteCount = 64 * 1048576;
|
||||
uint uiSizeMult = 1;
|
||||
|
||||
cudaDeviceProp deviceProp;
|
||||
deviceProp.major = 0;
|
||||
deviceProp.minor = 0;
|
||||
cudaDeviceProp deviceProp;
|
||||
deviceProp.major = 0;
|
||||
deviceProp.minor = 0;
|
||||
|
||||
// set logfile name and start logs
|
||||
printf("[%s] - Starting...\n", sSDKsample);
|
||||
// set logfile name and start logs
|
||||
printf("[%s] - Starting...\n", sSDKsample);
|
||||
|
||||
// Use command-line specified CUDA device, otherwise use device with highest
|
||||
// Gflops/s
|
||||
int dev = findCudaDevice(argc, (const char **)argv);
|
||||
// Use command-line specified CUDA device, otherwise use device with highest
|
||||
// Gflops/s
|
||||
int dev = findCudaDevice(argc, (const char **)argv);
|
||||
|
||||
checkCudaErrors(cudaGetDeviceProperties(&deviceProp, dev));
|
||||
checkCudaErrors(cudaGetDeviceProperties(&deviceProp, dev));
|
||||
|
||||
printf("CUDA device [%s] has %d Multi-Processors, Compute %d.%d\n",
|
||||
deviceProp.name, deviceProp.multiProcessorCount, deviceProp.major,
|
||||
deviceProp.minor);
|
||||
printf("CUDA device [%s] has %d Multi-Processors, Compute %d.%d\n",
|
||||
deviceProp.name,
|
||||
deviceProp.multiProcessorCount,
|
||||
deviceProp.major,
|
||||
deviceProp.minor);
|
||||
|
||||
sdkCreateTimer(&hTimer);
|
||||
sdkCreateTimer(&hTimer);
|
||||
|
||||
// Optional Command-line multiplier to increase size of array to histogram
|
||||
if (checkCmdLineFlag(argc, (const char **)argv, "sizemult")) {
|
||||
uiSizeMult = getCmdLineArgumentInt(argc, (const char **)argv, "sizemult");
|
||||
uiSizeMult = MAX(1, MIN(uiSizeMult, 10));
|
||||
byteCount *= uiSizeMult;
|
||||
}
|
||||
// Optional Command-line multiplier to increase size of array to histogram
|
||||
if (checkCmdLineFlag(argc, (const char **)argv, "sizemult")) {
|
||||
uiSizeMult = getCmdLineArgumentInt(argc, (const char **)argv, "sizemult");
|
||||
uiSizeMult = MAX(1, MIN(uiSizeMult, 10));
|
||||
byteCount *= uiSizeMult;
|
||||
}
|
||||
|
||||
printf("Initializing data...\n");
|
||||
printf("...allocating CPU memory.\n");
|
||||
h_Data = (uchar *)malloc(byteCount);
|
||||
h_HistogramCPU = (uint *)malloc(HISTOGRAM256_BIN_COUNT * sizeof(uint));
|
||||
h_HistogramGPU = (uint *)malloc(HISTOGRAM256_BIN_COUNT * sizeof(uint));
|
||||
printf("Initializing data...\n");
|
||||
printf("...allocating CPU memory.\n");
|
||||
h_Data = (uchar *)malloc(byteCount);
|
||||
h_HistogramCPU = (uint *)malloc(HISTOGRAM256_BIN_COUNT * sizeof(uint));
|
||||
h_HistogramGPU = (uint *)malloc(HISTOGRAM256_BIN_COUNT * sizeof(uint));
|
||||
|
||||
printf("...generating input data\n");
|
||||
srand(2009);
|
||||
printf("...generating input data\n");
|
||||
srand(2009);
|
||||
|
||||
for (uint i = 0; i < byteCount; i++) {
|
||||
h_Data[i] = rand() % 256;
|
||||
}
|
||||
for (uint i = 0; i < byteCount; i++) {
|
||||
h_Data[i] = rand() % 256;
|
||||
}
|
||||
|
||||
printf("...allocating GPU memory and copying input data\n\n");
|
||||
checkCudaErrors(cudaMalloc((void **)&d_Data, byteCount));
|
||||
checkCudaErrors(
|
||||
cudaMalloc((void **)&d_Histogram, HISTOGRAM256_BIN_COUNT * sizeof(uint)));
|
||||
checkCudaErrors(
|
||||
cudaMemcpy(d_Data, h_Data, byteCount, cudaMemcpyHostToDevice));
|
||||
printf("...allocating GPU memory and copying input data\n\n");
|
||||
checkCudaErrors(cudaMalloc((void **)&d_Data, byteCount));
|
||||
checkCudaErrors(cudaMalloc((void **)&d_Histogram, HISTOGRAM256_BIN_COUNT * sizeof(uint)));
|
||||
checkCudaErrors(cudaMemcpy(d_Data, h_Data, byteCount, cudaMemcpyHostToDevice));
|
||||
|
||||
{
|
||||
printf("Starting up 64-bin histogram...\n\n");
|
||||
initHistogram64();
|
||||
{
|
||||
printf("Starting up 64-bin histogram...\n\n");
|
||||
initHistogram64();
|
||||
|
||||
printf("Running 64-bin GPU histogram for %u bytes (%u runs)...\n\n",
|
||||
byteCount, numRuns);
|
||||
printf("Running 64-bin GPU histogram for %u bytes (%u runs)...\n\n", byteCount, numRuns);
|
||||
|
||||
for (int iter = -1; iter < numRuns; iter++) {
|
||||
// iter == -1 -- warmup iteration
|
||||
if (iter == 0) {
|
||||
cudaDeviceSynchronize();
|
||||
sdkResetTimer(&hTimer);
|
||||
sdkStartTimer(&hTimer);
|
||||
}
|
||||
|
||||
histogram64(d_Histogram, d_Data, byteCount);
|
||||
}
|
||||
|
||||
for (int iter = -1; iter < numRuns; iter++) {
|
||||
// iter == -1 -- warmup iteration
|
||||
if (iter == 0) {
|
||||
cudaDeviceSynchronize();
|
||||
sdkResetTimer(&hTimer);
|
||||
sdkStartTimer(&hTimer);
|
||||
}
|
||||
sdkStopTimer(&hTimer);
|
||||
double dAvgSecs = 1.0e-3 * (double)sdkGetTimerValue(&hTimer) / (double)numRuns;
|
||||
printf("histogram64() time (average) : %.5f sec, %.4f MB/sec\n\n",
|
||||
dAvgSecs,
|
||||
((double)byteCount * 1.0e-6) / dAvgSecs);
|
||||
printf("histogram64, Throughput = %.4f MB/s, Time = %.5f s, Size = %u Bytes, "
|
||||
"NumDevsUsed = %u, Workgroup = %u\n",
|
||||
(1.0e-6 * (double)byteCount / dAvgSecs),
|
||||
dAvgSecs,
|
||||
byteCount,
|
||||
1,
|
||||
HISTOGRAM64_THREADBLOCK_SIZE);
|
||||
|
||||
histogram64(d_Histogram, d_Data, byteCount);
|
||||
printf("\nValidating GPU results...\n");
|
||||
printf(" ...reading back GPU results\n");
|
||||
checkCudaErrors(
|
||||
cudaMemcpy(h_HistogramGPU, d_Histogram, HISTOGRAM64_BIN_COUNT * sizeof(uint), cudaMemcpyDeviceToHost));
|
||||
|
||||
printf(" ...histogram64CPU()\n");
|
||||
histogram64CPU(h_HistogramCPU, h_Data, byteCount);
|
||||
|
||||
printf(" ...comparing the results...\n");
|
||||
|
||||
for (uint i = 0; i < HISTOGRAM64_BIN_COUNT; i++)
|
||||
if (h_HistogramGPU[i] != h_HistogramCPU[i]) {
|
||||
PassFailFlag = 0;
|
||||
}
|
||||
|
||||
printf(PassFailFlag ? " ...64-bin histograms match\n\n" : " ***64-bin histograms do not match!!!***\n\n");
|
||||
|
||||
printf("Shutting down 64-bin histogram...\n\n\n");
|
||||
closeHistogram64();
|
||||
}
|
||||
|
||||
cudaDeviceSynchronize();
|
||||
sdkStopTimer(&hTimer);
|
||||
double dAvgSecs =
|
||||
1.0e-3 * (double)sdkGetTimerValue(&hTimer) / (double)numRuns;
|
||||
printf("histogram64() time (average) : %.5f sec, %.4f MB/sec\n\n", dAvgSecs,
|
||||
((double)byteCount * 1.0e-6) / dAvgSecs);
|
||||
printf(
|
||||
"histogram64, Throughput = %.4f MB/s, Time = %.5f s, Size = %u Bytes, "
|
||||
"NumDevsUsed = %u, Workgroup = %u\n",
|
||||
(1.0e-6 * (double)byteCount / dAvgSecs), dAvgSecs, byteCount, 1,
|
||||
HISTOGRAM64_THREADBLOCK_SIZE);
|
||||
{
|
||||
printf("Initializing 256-bin histogram...\n");
|
||||
initHistogram256();
|
||||
|
||||
printf("\nValidating GPU results...\n");
|
||||
printf(" ...reading back GPU results\n");
|
||||
checkCudaErrors(cudaMemcpy(h_HistogramGPU, d_Histogram,
|
||||
HISTOGRAM64_BIN_COUNT * sizeof(uint),
|
||||
cudaMemcpyDeviceToHost));
|
||||
printf("Running 256-bin GPU histogram for %u bytes (%u runs)...\n\n", byteCount, numRuns);
|
||||
|
||||
printf(" ...histogram64CPU()\n");
|
||||
histogram64CPU(h_HistogramCPU, h_Data, byteCount);
|
||||
for (int iter = -1; iter < numRuns; iter++) {
|
||||
// iter == -1 -- warmup iteration
|
||||
if (iter == 0) {
|
||||
checkCudaErrors(cudaDeviceSynchronize());
|
||||
sdkResetTimer(&hTimer);
|
||||
sdkStartTimer(&hTimer);
|
||||
}
|
||||
|
||||
printf(" ...comparing the results...\n");
|
||||
histogram256(d_Histogram, d_Data, byteCount);
|
||||
}
|
||||
|
||||
for (uint i = 0; i < HISTOGRAM64_BIN_COUNT; i++)
|
||||
if (h_HistogramGPU[i] != h_HistogramCPU[i]) {
|
||||
PassFailFlag = 0;
|
||||
}
|
||||
cudaDeviceSynchronize();
|
||||
sdkStopTimer(&hTimer);
|
||||
double dAvgSecs = 1.0e-3 * (double)sdkGetTimerValue(&hTimer) / (double)numRuns;
|
||||
printf("histogram256() time (average) : %.5f sec, %.4f MB/sec\n\n",
|
||||
dAvgSecs,
|
||||
((double)byteCount * 1.0e-6) / dAvgSecs);
|
||||
printf("histogram256, Throughput = %.4f MB/s, Time = %.5f s, Size = %u Bytes, "
|
||||
"NumDevsUsed = %u, Workgroup = %u\n",
|
||||
(1.0e-6 * (double)byteCount / dAvgSecs),
|
||||
dAvgSecs,
|
||||
byteCount,
|
||||
1,
|
||||
HISTOGRAM256_THREADBLOCK_SIZE);
|
||||
|
||||
printf(PassFailFlag ? " ...64-bin histograms match\n\n"
|
||||
: " ***64-bin histograms do not match!!!***\n\n");
|
||||
printf("\nValidating GPU results...\n");
|
||||
printf(" ...reading back GPU results\n");
|
||||
checkCudaErrors(
|
||||
cudaMemcpy(h_HistogramGPU, d_Histogram, HISTOGRAM256_BIN_COUNT * sizeof(uint), cudaMemcpyDeviceToHost));
|
||||
|
||||
printf("Shutting down 64-bin histogram...\n\n\n");
|
||||
closeHistogram64();
|
||||
}
|
||||
printf(" ...histogram256CPU()\n");
|
||||
histogram256CPU(h_HistogramCPU, h_Data, byteCount);
|
||||
|
||||
{
|
||||
printf("Initializing 256-bin histogram...\n");
|
||||
initHistogram256();
|
||||
printf(" ...comparing the results\n");
|
||||
|
||||
printf("Running 256-bin GPU histogram for %u bytes (%u runs)...\n\n",
|
||||
byteCount, numRuns);
|
||||
for (uint i = 0; i < HISTOGRAM256_BIN_COUNT; i++)
|
||||
if (h_HistogramGPU[i] != h_HistogramCPU[i]) {
|
||||
PassFailFlag = 0;
|
||||
}
|
||||
|
||||
for (int iter = -1; iter < numRuns; iter++) {
|
||||
// iter == -1 -- warmup iteration
|
||||
if (iter == 0) {
|
||||
checkCudaErrors(cudaDeviceSynchronize());
|
||||
sdkResetTimer(&hTimer);
|
||||
sdkStartTimer(&hTimer);
|
||||
}
|
||||
printf(PassFailFlag ? " ...256-bin histograms match\n\n" : " ***256-bin histograms do not match!!!***\n\n");
|
||||
|
||||
histogram256(d_Histogram, d_Data, byteCount);
|
||||
printf("Shutting down 256-bin histogram...\n\n\n");
|
||||
closeHistogram256();
|
||||
}
|
||||
|
||||
cudaDeviceSynchronize();
|
||||
sdkStopTimer(&hTimer);
|
||||
double dAvgSecs =
|
||||
1.0e-3 * (double)sdkGetTimerValue(&hTimer) / (double)numRuns;
|
||||
printf("histogram256() time (average) : %.5f sec, %.4f MB/sec\n\n",
|
||||
dAvgSecs, ((double)byteCount * 1.0e-6) / dAvgSecs);
|
||||
printf(
|
||||
"histogram256, Throughput = %.4f MB/s, Time = %.5f s, Size = %u Bytes, "
|
||||
"NumDevsUsed = %u, Workgroup = %u\n",
|
||||
(1.0e-6 * (double)byteCount / dAvgSecs), dAvgSecs, byteCount, 1,
|
||||
HISTOGRAM256_THREADBLOCK_SIZE);
|
||||
printf("Shutting down...\n");
|
||||
sdkDeleteTimer(&hTimer);
|
||||
checkCudaErrors(cudaFree(d_Histogram));
|
||||
checkCudaErrors(cudaFree(d_Data));
|
||||
free(h_HistogramGPU);
|
||||
free(h_HistogramCPU);
|
||||
free(h_Data);
|
||||
|
||||
printf("\nValidating GPU results...\n");
|
||||
printf(" ...reading back GPU results\n");
|
||||
checkCudaErrors(cudaMemcpy(h_HistogramGPU, d_Histogram,
|
||||
HISTOGRAM256_BIN_COUNT * sizeof(uint),
|
||||
cudaMemcpyDeviceToHost));
|
||||
printf("\nNOTE: The CUDA Samples are not meant for performance measurements. "
|
||||
"Results may vary when GPU Boost is enabled.\n\n");
|
||||
|
||||
printf(" ...histogram256CPU()\n");
|
||||
histogram256CPU(h_HistogramCPU, h_Data, byteCount);
|
||||
printf("%s - Test Summary\n", sSDKsample);
|
||||
|
||||
printf(" ...comparing the results\n");
|
||||
// pass or fail (for both 64 bit and 256 bit histograms)
|
||||
if (!PassFailFlag) {
|
||||
printf("Test failed!\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
for (uint i = 0; i < HISTOGRAM256_BIN_COUNT; i++)
|
||||
if (h_HistogramGPU[i] != h_HistogramCPU[i]) {
|
||||
PassFailFlag = 0;
|
||||
}
|
||||
|
||||
printf(PassFailFlag ? " ...256-bin histograms match\n\n"
|
||||
: " ***256-bin histograms do not match!!!***\n\n");
|
||||
|
||||
printf("Shutting down 256-bin histogram...\n\n\n");
|
||||
closeHistogram256();
|
||||
}
|
||||
|
||||
printf("Shutting down...\n");
|
||||
sdkDeleteTimer(&hTimer);
|
||||
checkCudaErrors(cudaFree(d_Histogram));
|
||||
checkCudaErrors(cudaFree(d_Data));
|
||||
free(h_HistogramGPU);
|
||||
free(h_HistogramCPU);
|
||||
free(h_Data);
|
||||
|
||||
printf(
|
||||
"\nNOTE: The CUDA Samples are not meant for performance measurements. "
|
||||
"Results may vary when GPU Boost is enabled.\n\n");
|
||||
|
||||
printf("%s - Test Summary\n", sSDKsample);
|
||||
|
||||
// pass or fail (for both 64 bit and 256 bit histograms)
|
||||
if (!PassFailFlag) {
|
||||
printf("Test failed!\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
printf("Test passed\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
printf("Test passed\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
@@ -29,100 +29,107 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
|
||||
#pragma warning(disable : 4996) // disable deprecated warning
|
||||
#pragma warning(disable : 4996) // disable deprecated warning
|
||||
#endif
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
typedef struct {
|
||||
short type;
|
||||
int size;
|
||||
short reserved1;
|
||||
short reserved2;
|
||||
int offset;
|
||||
typedef struct
|
||||
{
|
||||
short type;
|
||||
int size;
|
||||
short reserved1;
|
||||
short reserved2;
|
||||
int offset;
|
||||
} BMPHeader;
|
||||
|
||||
typedef struct {
|
||||
int size;
|
||||
int width;
|
||||
int height;
|
||||
short planes;
|
||||
short bitsPerPixel;
|
||||
unsigned compression;
|
||||
unsigned imageSize;
|
||||
int xPelsPerMeter;
|
||||
int yPelsPerMeter;
|
||||
int clrUsed;
|
||||
int clrImportant;
|
||||
typedef struct
|
||||
{
|
||||
int size;
|
||||
int width;
|
||||
int height;
|
||||
short planes;
|
||||
short bitsPerPixel;
|
||||
unsigned compression;
|
||||
unsigned imageSize;
|
||||
int xPelsPerMeter;
|
||||
int yPelsPerMeter;
|
||||
int clrUsed;
|
||||
int clrImportant;
|
||||
} BMPInfoHeader;
|
||||
|
||||
// Isolated definition
|
||||
typedef struct { unsigned char x, y, z, w; } uchar4;
|
||||
typedef struct
|
||||
{
|
||||
unsigned char x, y, z, w;
|
||||
} uchar4;
|
||||
|
||||
extern "C" void LoadBMPFile(uchar4 **dst, int *width, int *height,
|
||||
const char *name) {
|
||||
BMPHeader hdr;
|
||||
BMPInfoHeader infoHdr;
|
||||
int x, y;
|
||||
extern "C" void LoadBMPFile(uchar4 **dst, int *width, int *height, const char *name)
|
||||
{
|
||||
BMPHeader hdr;
|
||||
BMPInfoHeader infoHdr;
|
||||
int x, y;
|
||||
|
||||
FILE *fd;
|
||||
FILE *fd;
|
||||
|
||||
printf("Loading %s...\n", name);
|
||||
printf("Loading %s...\n", name);
|
||||
|
||||
if (sizeof(uchar4) != 4) {
|
||||
printf("***Bad uchar4 size***\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
if (!(fd = fopen(name, "rb"))) {
|
||||
printf("***BMP load error: file access denied***\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
fread(&hdr, sizeof(hdr), 1, fd);
|
||||
|
||||
if (hdr.type != 0x4D42) {
|
||||
printf("***BMP load error: bad file format***\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
fread(&infoHdr, sizeof(infoHdr), 1, fd);
|
||||
|
||||
if (infoHdr.bitsPerPixel != 24) {
|
||||
printf("***BMP load error: invalid color depth***\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
if (infoHdr.compression) {
|
||||
printf("***BMP load error: compressed image***\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
*width = infoHdr.width;
|
||||
*height = infoHdr.height;
|
||||
*dst = (uchar4 *)malloc(*width * *height * 4);
|
||||
|
||||
printf("BMP width: %u\n", infoHdr.width);
|
||||
printf("BMP height: %u\n", infoHdr.height);
|
||||
|
||||
fseek(fd, hdr.offset - sizeof(hdr) - sizeof(infoHdr), SEEK_CUR);
|
||||
|
||||
for (y = 0; y < infoHdr.height; y++) {
|
||||
for (x = 0; x < infoHdr.width; x++) {
|
||||
(*dst)[(y * infoHdr.width + x)].z = fgetc(fd);
|
||||
(*dst)[(y * infoHdr.width + x)].y = fgetc(fd);
|
||||
(*dst)[(y * infoHdr.width + x)].x = fgetc(fd);
|
||||
if (sizeof(uchar4) != 4) {
|
||||
printf("***Bad uchar4 size***\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
for (x = 0; x < (4 - (3 * infoHdr.width) % 4) % 4; x++) fgetc(fd);
|
||||
}
|
||||
if (!(fd = fopen(name, "rb"))) {
|
||||
printf("***BMP load error: file access denied***\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
if (ferror(fd)) {
|
||||
printf("***Unknown BMP load error.***\n");
|
||||
free(*dst);
|
||||
exit(EXIT_SUCCESS);
|
||||
} else
|
||||
printf("BMP file loaded successfully!\n");
|
||||
fread(&hdr, sizeof(hdr), 1, fd);
|
||||
|
||||
fclose(fd);
|
||||
if (hdr.type != 0x4D42) {
|
||||
printf("***BMP load error: bad file format***\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
fread(&infoHdr, sizeof(infoHdr), 1, fd);
|
||||
|
||||
if (infoHdr.bitsPerPixel != 24) {
|
||||
printf("***BMP load error: invalid color depth***\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
if (infoHdr.compression) {
|
||||
printf("***BMP load error: compressed image***\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
*width = infoHdr.width;
|
||||
*height = infoHdr.height;
|
||||
*dst = (uchar4 *)malloc(*width * *height * 4);
|
||||
|
||||
printf("BMP width: %u\n", infoHdr.width);
|
||||
printf("BMP height: %u\n", infoHdr.height);
|
||||
|
||||
fseek(fd, hdr.offset - sizeof(hdr) - sizeof(infoHdr), SEEK_CUR);
|
||||
|
||||
for (y = 0; y < infoHdr.height; y++) {
|
||||
for (x = 0; x < infoHdr.width; x++) {
|
||||
(*dst)[(y * infoHdr.width + x)].z = fgetc(fd);
|
||||
(*dst)[(y * infoHdr.width + x)].y = fgetc(fd);
|
||||
(*dst)[(y * infoHdr.width + x)].x = fgetc(fd);
|
||||
}
|
||||
|
||||
for (x = 0; x < (4 - (3 * infoHdr.width) % 4) % 4; x++)
|
||||
fgetc(fd);
|
||||
}
|
||||
|
||||
if (ferror(fd)) {
|
||||
printf("***Unknown BMP load error.***\n");
|
||||
free(*dst);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
else
|
||||
printf("BMP file loaded successfully!\n");
|
||||
|
||||
fclose(fd);
|
||||
}
|
||||
|
||||
@@ -35,10 +35,11 @@
|
||||
* See supplied whitepaper for more explanations.
|
||||
*/
|
||||
|
||||
#include <helper_cuda.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <helper_cuda.h>
|
||||
|
||||
#include "imageDenoising.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -52,21 +53,21 @@ int iDivUp(int a, int b) { return ((a % b) != 0) ? (a / b + 1) : (a / b); }
|
||||
|
||||
__device__ float lerpf(float a, float b, float c) { return a + (b - a) * c; }
|
||||
|
||||
__device__ float vecLen(float4 a, float4 b) {
|
||||
return ((b.x - a.x) * (b.x - a.x) + (b.y - a.y) * (b.y - a.y) +
|
||||
(b.z - a.z) * (b.z - a.z));
|
||||
__device__ float vecLen(float4 a, float4 b)
|
||||
{
|
||||
return ((b.x - a.x) * (b.x - a.x) + (b.y - a.y) * (b.y - a.y) + (b.z - a.z) * (b.z - a.z));
|
||||
}
|
||||
|
||||
__device__ TColor make_color(float r, float g, float b, float a) {
|
||||
return ((int)(a * 255.0f) << 24) | ((int)(b * 255.0f) << 16) |
|
||||
((int)(g * 255.0f) << 8) | ((int)(r * 255.0f) << 0);
|
||||
__device__ TColor make_color(float r, float g, float b, float a)
|
||||
{
|
||||
return ((int)(a * 255.0f) << 24) | ((int)(b * 255.0f) << 16) | ((int)(g * 255.0f) << 8) | ((int)(r * 255.0f) << 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Global data handlers and parameters
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Texture object and channel descriptor for image texture
|
||||
cudaTextureObject_t texImage;
|
||||
cudaTextureObject_t texImage;
|
||||
cudaChannelFormatDesc uchar4tex = cudaCreateChannelDesc<uchar4>();
|
||||
|
||||
// CUDA array descriptor
|
||||
@@ -77,36 +78,35 @@ cudaArray *a_Src;
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#include "imageDenoising_copy_kernel.cuh"
|
||||
#include "imageDenoising_knn_kernel.cuh"
|
||||
#include "imageDenoising_nlm_kernel.cuh"
|
||||
#include "imageDenoising_nlm2_kernel.cuh"
|
||||
#include "imageDenoising_nlm_kernel.cuh"
|
||||
|
||||
extern "C" cudaError_t CUDA_MallocArray(uchar4 **h_Src, int imageW,
|
||||
int imageH) {
|
||||
cudaError_t error;
|
||||
extern "C" cudaError_t CUDA_MallocArray(uchar4 **h_Src, int imageW, int imageH)
|
||||
{
|
||||
cudaError_t error;
|
||||
|
||||
error = cudaMallocArray(&a_Src, &uchar4tex, imageW, imageH);
|
||||
error = cudaMemcpy2DToArray(a_Src, 0, 0, *h_Src, sizeof(uchar4) * imageW,
|
||||
sizeof(uchar4) * imageW, imageH,
|
||||
cudaMemcpyHostToDevice);
|
||||
error = cudaMallocArray(&a_Src, &uchar4tex, imageW, imageH);
|
||||
error = cudaMemcpy2DToArray(
|
||||
a_Src, 0, 0, *h_Src, sizeof(uchar4) * imageW, sizeof(uchar4) * imageW, imageH, cudaMemcpyHostToDevice);
|
||||
|
||||
cudaResourceDesc texRes;
|
||||
memset(&texRes, 0, sizeof(cudaResourceDesc));
|
||||
cudaResourceDesc texRes;
|
||||
memset(&texRes, 0, sizeof(cudaResourceDesc));
|
||||
|
||||
texRes.resType = cudaResourceTypeArray;
|
||||
texRes.res.array.array = a_Src;
|
||||
texRes.resType = cudaResourceTypeArray;
|
||||
texRes.res.array.array = a_Src;
|
||||
|
||||
cudaTextureDesc texDescr;
|
||||
memset(&texDescr, 0, sizeof(cudaTextureDesc));
|
||||
cudaTextureDesc texDescr;
|
||||
memset(&texDescr, 0, sizeof(cudaTextureDesc));
|
||||
|
||||
texDescr.normalizedCoords = false;
|
||||
texDescr.filterMode = cudaFilterModeLinear;
|
||||
texDescr.addressMode[0] = cudaAddressModeWrap;
|
||||
texDescr.addressMode[1] = cudaAddressModeWrap;
|
||||
texDescr.readMode = cudaReadModeNormalizedFloat;
|
||||
texDescr.normalizedCoords = false;
|
||||
texDescr.filterMode = cudaFilterModeLinear;
|
||||
texDescr.addressMode[0] = cudaAddressModeWrap;
|
||||
texDescr.addressMode[1] = cudaAddressModeWrap;
|
||||
texDescr.readMode = cudaReadModeNormalizedFloat;
|
||||
|
||||
checkCudaErrors(cudaCreateTextureObject(&texImage, &texRes, &texDescr, NULL));
|
||||
checkCudaErrors(cudaCreateTextureObject(&texImage, &texRes, &texDescr, NULL));
|
||||
|
||||
return error;
|
||||
return error;
|
||||
}
|
||||
|
||||
extern "C" cudaError_t CUDA_FreeArray() { return cudaFreeArray(a_Src); }
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user