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

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

View File

@@ -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)

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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");
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

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

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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); }

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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();
}
}

View File

@@ -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;
}
}
}

View File

@@ -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

View File

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

View File

@@ -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);

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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

View File

@@ -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);

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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

View File

@@ -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);

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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

View File

@@ -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);

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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);

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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

View File

@@ -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.

View File

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

View File

@@ -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();
}
}

View File

@@ -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);
}

View File

@@ -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_

View File

@@ -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");
}

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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);
}

View File

@@ -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");
}

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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);
}
}
}
}
}

View File

@@ -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

View File

@@ -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];
}

View File

@@ -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];
}

View File

@@ -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;
}

View File

@@ -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)];
}
}

View File

@@ -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_

View File

@@ -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_

View File

@@ -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_

View File

@@ -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;
}

View File

@@ -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_

View File

@@ -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);
}

View File

@@ -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_

View File

@@ -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_

View File

@@ -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_

View File

@@ -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);
}

View File

@@ -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_

View File

@@ -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;
}

View File

@@ -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();
}

View File

@@ -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_

View File

@@ -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_

View File

@@ -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_

View File

@@ -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");
}

View File

@@ -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");
}

View File

@@ -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

View File

@@ -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]++;
}
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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