Commit de7d20d0 authored by Matthias Werner's avatar Matthias Werner

helper-lib -> src/inc. unified error checking.

parent 9c242d13
......@@ -27,5 +27,4 @@ message(">> Setting up ${CMAKE_BUILD_TYPE} build")
# or
#add_definitions(-D_GLIBCXX_USE_CXX11_ABI=1)
add_subdirectory(lib/helper/src)
add_subdirectory(src)
......@@ -64,17 +64,17 @@ namespace ClFFT
findClDevice(CL_DEVICE_TYPE_GPU, &platform, &device);
props[1] = (cl_context_properties)platform;
ctx = clCreateContext( props, 1, &device, nullptr, nullptr, &err );
clCheckError(err);
CHECK_CL(err);
clfftSetupData fftSetup;
clSafeCall(clfftInitSetupData(&fftSetup));
clSafeCall(clfftSetup(&fftSetup));
CHECK_CL(clfftInitSetupData(&fftSetup));
CHECK_CL(clfftSetup(&fftSetup));
}
void destroy() {
if(ctx) {
std::cout << "Destroying clFFT and OpenCL Context ..." << std::endl;
clSafeCall( clfftTeardown( ) );
clSafeCall(clReleaseContext( ctx ));
CHECK_CL( clfftTeardown( ) );
CHECK_CL(clReleaseContext( ctx ));
ctx = 0;
}
}
......@@ -90,7 +90,7 @@ namespace ClFFT
template<clfftDim FFTDim, size_t Ndim>
constexpr void makePlan(clfftPlanHandle& plan, const std::array<unsigned,Ndim>& e){
size_t clLengths[3] = {e[0], Ndim==2?e[1]:1, Ndim==3?e[2]:1};
clSafeCall(clfftCreateDefaultPlan(&plan, context.ctx, FFTDim, clLengths));
CHECK_CL(clfftCreateDefaultPlan(&plan, context.ctx, FFTDim, clLengths));
}
/**
......@@ -141,7 +141,7 @@ namespace ClFFT
if(context.ctx==0)
context.create();
queue_ = clCreateCommandQueue( context.ctx, context.device, 0, &err );
clCheckError(err);
CHECK_CL(err);
n_ = std::accumulate(extents_.begin(), extents_.end(), 1, std::multiplies<unsigned>());
......@@ -180,10 +180,10 @@ namespace ClFFT
size_t size1 = 0;
size_t size2 = 0;
init_forward();
clSafeCall(clfftGetTmpBufSize( plan_, &size1 ));
CHECK_CL(clfftGetTmpBufSize( plan_, &size1 ));
init_backward();
clSafeCall(clfftGetTmpBufSize( plan_, &size2 ));
clSafeCall(clfftDestroyPlan( &plan_ ));
CHECK_CL(clfftGetTmpBufSize( plan_, &size2 ));
CHECK_CL(clfftDestroyPlan( &plan_ ));
return std::max(size1,size2);
}
......@@ -210,17 +210,17 @@ namespace ClFFT
// create FFT plan handle
void init_forward() {
makePlan<FFTDim>(plan_, extents_);
clSafeCall(clfftSetPlanPrecision(plan_, traits::FFTPrecision<TPrecision>::value));
clSafeCall(clfftSetLayout(plan_,
CHECK_CL(clfftSetPlanPrecision(plan_, traits::FFTPrecision<TPrecision>::value));
CHECK_CL(clfftSetLayout(plan_,
traits::FFTLayout<IsComplex>::value,
traits::FFTLayout<IsComplex>::value_transformed));
clSafeCall(clfftSetResultLocation(plan_, traits::FFTInplace<IsInplace>::value));
CHECK_CL(clfftSetResultLocation(plan_, traits::FFTInplace<IsInplace>::value));
if(Padding){
clSafeCall(clfftSetPlanInStride(plan_, FFTDim, strides));
clSafeCall(clfftSetPlanOutStride(plan_, FFTDim, transform_strides));
clSafeCall(clfftSetPlanDistance(plan_, dist, transform_dist));
CHECK_CL(clfftSetPlanInStride(plan_, FFTDim, strides));
CHECK_CL(clfftSetPlanOutStride(plan_, FFTDim, transform_strides));
CHECK_CL(clfftSetPlanDistance(plan_, dist, transform_dist));
}
clSafeCall(clfftBakePlan(plan_,
CHECK_CL(clfftBakePlan(plan_,
1, // number of queues
&queue_,
nullptr, // callback
......@@ -230,16 +230,16 @@ namespace ClFFT
// recreates plan if needed
void init_backward() {
if(IsComplex==false){
clSafeCall(clfftSetLayout(plan_,
CHECK_CL(clfftSetLayout(plan_,
traits::FFTLayout<IsComplex>::value_transformed,
traits::FFTLayout<IsComplex>::value));
if(Padding){
clSafeCall(clfftSetPlanOutStride(plan_, FFTDim, strides));
clSafeCall(clfftSetPlanInStride(plan_, FFTDim, transform_strides));
clSafeCall(clfftSetPlanDistance(plan_, transform_dist, dist));
CHECK_CL(clfftSetPlanOutStride(plan_, FFTDim, strides));
CHECK_CL(clfftSetPlanInStride(plan_, FFTDim, transform_strides));
CHECK_CL(clfftSetPlanDistance(plan_, transform_dist, dist));
}
clSafeCall(clfftBakePlan(plan_,
CHECK_CL(clfftBakePlan(plan_,
1, // number of queues
&queue_,
0, // callback
......@@ -248,7 +248,7 @@ namespace ClFFT
}
void execute_forward() {
clSafeCall(clfftEnqueueTransform(plan_,
CHECK_CL(clfftEnqueueTransform(plan_,
CLFFT_FORWARD,
1, // numQueuesAndEvents
&queue_,
......@@ -258,10 +258,10 @@ namespace ClFFT
&data_, // input
IsInplace ? &data_ : &data_transform_, // output
0)); // tmpBuffer
clSafeCall(clFinish(queue_));
CHECK_CL(clFinish(queue_));
}
void execute_backward() {
clSafeCall(clfftEnqueueTransform(plan_,
CHECK_CL(clfftEnqueueTransform(plan_,
CLFFT_BACKWARD,
1, // numQueuesAndEvents
&queue_,
......@@ -271,14 +271,14 @@ namespace ClFFT
IsInplace ? &data_ : &data_transform_, // input
IsInplace ? &data_ : &data_, // output
nullptr)); // tmpBuffer
clSafeCall(clFinish(queue_));
CHECK_CL(clFinish(queue_));
}
template<typename THostData>
void upload(THostData* input) {
if(Padding && NDim>1)
{
//printf("pitch=%zu w=%zu h=%zu\n", pitch, w, h);
clSafeCall(clEnqueueWriteBufferRect( queue_,
CHECK_CL(clEnqueueWriteBufferRect( queue_,
data_,
CL_TRUE, // blocking_write
offset, // buffer origin
......@@ -293,7 +293,7 @@ namespace ClFFT
nullptr, // event_wait_list
nullptr )); // event
}else{
clSafeCall(clEnqueueWriteBuffer( queue_,
CHECK_CL(clEnqueueWriteBuffer( queue_,
data_,
CL_TRUE, // blocking_write
0, // offset
......@@ -308,7 +308,7 @@ namespace ClFFT
void download(THostData* output) {
if(Padding && NDim>1)
{
clSafeCall(clEnqueueReadBufferRect( queue_,
CHECK_CL(clEnqueueReadBufferRect( queue_,
data_,
CL_TRUE, // blocking_write
offset, // buffer origin
......@@ -323,7 +323,7 @@ namespace ClFFT
nullptr, // event_wait_list
nullptr )); // event
}else{
clSafeCall(clEnqueueReadBuffer( queue_,
CHECK_CL(clEnqueueReadBuffer( queue_,
data_,
CL_TRUE, // blocking_write
0, // offset
......@@ -336,13 +336,13 @@ namespace ClFFT
}
void destroy() {
clSafeCall( clFinish(queue_) );
clSafeCall( clReleaseMemObject( data_ ) );
CHECK_CL( clFinish(queue_) );
CHECK_CL( clReleaseMemObject( data_ ) );
if(IsInplace==false)
clSafeCall( clReleaseMemObject( data_transform_ ) );
CHECK_CL( clReleaseMemObject( data_transform_ ) );
clSafeCall(clfftDestroyPlan( &plan_ ));
clSafeCall( clReleaseCommandQueue( queue_ ) );
CHECK_CL(clfftDestroyPlan( &plan_ ));
CHECK_CL( clReleaseCommandQueue( queue_ ) );
data_ = 0;
data_transform_ = 0;
plan_ = 0;
......@@ -350,10 +350,10 @@ namespace ClFFT
}
};
typedef gearshifft::FFT<gearshifft::FFT_Inplace_Real, ClFFTImpl, TimerCPU> Inplace_Real;
typedef gearshifft::FFT<gearshifft::FFT_Outplace_Real, ClFFTImpl, TimerCPU> Outplace_Real;
typedef gearshifft::FFT<gearshifft::FFT_Inplace_Complex, ClFFTImpl, TimerCPU> Inplace_Complex;
typedef gearshifft::FFT<gearshifft::FFT_Outplace_Complex, ClFFTImpl, TimerCPU> Outplace_Complex;
typedef gearshifft::FFT<gearshifft::FFT_Inplace_Real, ClFFTImpl, helper::TimerCPU> Inplace_Real;
typedef gearshifft::FFT<gearshifft::FFT_Outplace_Real, ClFFTImpl, helper::TimerCPU> Outplace_Real;
typedef gearshifft::FFT<gearshifft::FFT_Inplace_Complex, ClFFTImpl, helper::TimerCPU> Inplace_Complex;
typedef gearshifft::FFT<gearshifft::FFT_Outplace_Complex, ClFFTImpl, helper::TimerCPU> Outplace_Complex;
} // namespace ClFFT
} // gearshifft
......
......@@ -8,9 +8,8 @@
#include <vector>
#include <utility> // pair
#define clSafeCall( err ) gearshifft::ClFFT::__clSafeCall( err, __FILE__, __LINE__ )
#define clFFTSafeCall( err ) gearshifft::ClFFT::__clSafeCall( err, __FILE__, __LINE__ )
#define clCheckError(err) gearshifft::ClFFT::__clSafeCall( err, __FILE__, __LINE__ )
#define CHECK_CL( err ) gearshifft::ClFFT::check_error( err, __FILE__, __LINE__ )
#define STRINGIFY(A) #A
#define clFFTStatusCase(s) case s: return STRINGIFY(s)
......@@ -105,11 +104,11 @@ namespace gearshifft {
}
}
template<typename T>
inline void __clSafeCall( T err, const char *file, const int line )
inline void check_error( T err, const char *file, const int line )
{
if ( CL_SUCCESS != err )
{
fprintf( stderr, "clSafeCall() failed at %s:%i : %s\n",
fprintf( stderr, "OpenCL error at %s:%i : %s\n",
file, line, getOpenCLErrorString( err ) );
throw std::runtime_error("OpenCL Error: " + std::string(getOpenCLErrorString(err))+ " "+std::to_string(err));
......@@ -189,8 +188,8 @@ namespace gearshifft {
break;
}
if(!found){
clSafeCall(clGetPlatformIDs( 1, platform, NULL ));
clSafeCall(clGetDeviceIDs( *platform, CL_DEVICE_TYPE_DEFAULT, 1, device, NULL ));
CHECK_CL(clGetPlatformIDs( 1, platform, NULL ));
CHECK_CL(clGetDeviceIDs( *platform, CL_DEVICE_TYPE_DEFAULT, 1, device, NULL ));
}
return 0;
}
......
......@@ -186,11 +186,11 @@ namespace CuFFT {
void malloc() {
if(IsInplace){
CHECK_ERROR(cudaMalloc(&data_, data_size_));
CHECK_CUDA(cudaMalloc(&data_, data_size_));
data_transform_ = reinterpret_cast<ComplexType*>(data_);
}else{
CHECK_ERROR(cudaMalloc(&data_, data_size_));
CHECK_ERROR(cudaMalloc(&data_transform_, data_transform_size_));
CHECK_CUDA(cudaMalloc(&data_, data_size_));
CHECK_CUDA(cudaMalloc(&data_transform_, data_transform_size_));
}
}
......@@ -222,9 +222,9 @@ namespace CuFFT {
size_t w = extents_[NDim-1] * sizeof(THostData);
size_t h = n_ * sizeof(THostData) / w;
size_t pitch = (extents_[NDim-1]/2+1) * sizeof(ComplexType);
CHECK_ERROR(cudaMemcpy2D(data_, pitch, input, w, w, h, cudaMemcpyHostToDevice));
CHECK_CUDA(cudaMemcpy2D(data_, pitch, input, w, w, h, cudaMemcpyHostToDevice));
}else{
CHECK_ERROR(cudaMemcpy(data_, input, data_size_, cudaMemcpyHostToDevice));
CHECK_CUDA(cudaMemcpy(data_, input, data_size_, cudaMemcpyHostToDevice));
}
}
......@@ -235,24 +235,24 @@ namespace CuFFT {
size_t w = extents_[NDim-1] * sizeof(THostData);
size_t h = n_ * sizeof(THostData) / w;
size_t pitch = (extents_[NDim-1]/2+1) * sizeof(ComplexType);
CHECK_ERROR(cudaMemcpy2D(output, w, data_, pitch, w, h, cudaMemcpyDeviceToHost));
CHECK_CUDA(cudaMemcpy2D(output, w, data_, pitch, w, h, cudaMemcpyDeviceToHost));
}else{
CHECK_ERROR(cudaMemcpy(output, data_, data_size_, cudaMemcpyDeviceToHost));
CHECK_CUDA(cudaMemcpy(output, data_, data_size_, cudaMemcpyDeviceToHost));
}
}
void destroy() {
CHECK_ERROR( cudaFree(data_) );
CHECK_CUDA( cudaFree(data_) );
if(IsInplace==false)
CHECK_ERROR( cudaFree(data_transform_) );
CHECK_CUDA( cudaFree(data_transform_) );
CHECK_CUFFT( cufftDestroy(plan_) );
}
};
typedef gearshifft::FFT<gearshifft::FFT_Inplace_Real, CuFFTImpl, TimerGPU> Inplace_Real;
typedef gearshifft::FFT<gearshifft::FFT_Outplace_Real, CuFFTImpl, TimerGPU> Outplace_Real;
typedef gearshifft::FFT<gearshifft::FFT_Inplace_Complex, CuFFTImpl, TimerGPU> Inplace_Complex;
typedef gearshifft::FFT<gearshifft::FFT_Outplace_Complex, CuFFTImpl, TimerGPU> Outplace_Complex;
typedef gearshifft::FFT<gearshifft::FFT_Inplace_Real, CuFFTImpl, helper::TimerGPU> Inplace_Real;
typedef gearshifft::FFT<gearshifft::FFT_Outplace_Real, CuFFTImpl, helper::TimerGPU> Outplace_Real;
typedef gearshifft::FFT<gearshifft::FFT_Inplace_Complex, CuFFTImpl, helper::TimerGPU> Inplace_Complex;
typedef gearshifft::FFT<gearshifft::FFT_Outplace_Complex, CuFFTImpl, helper::TimerGPU> Outplace_Complex;
} // namespace CuFFT
} // namespace gearshifft
......
#ifndef CUFFT_HELPER_HPP_
#define CUFFT_HELPER_HPP_
#include "helper.h"
#include <cuda_runtime.h>
#include <stdio.h>
#include <stdlib.h>
#include <cufft.h>
#define CHECK_CUFFT(ans) gearshifft::CuFFT::check_error((ans), #ans, __FILE__, __LINE__)
#ifndef CUDA_DISABLE_ERROR_CHECKING
#define CHECK_CUDA(ans) gearshifft::CuFFT::check_cuda((ans), #ans, __FILE__, __LINE__)
#define CHECK_CUFFT(ans) gearshifft::CuFFT::check_cufft((ans), #ans, __FILE__, __LINE__)
#define CHECK_LAST(msg) gearshifft::CuFFT::check_cuda_last(msg, __FILE__, __LINE__)
#else
#define CHECK_CUDA(ans) {}
#define CHECK_CUFFT(ans) {}
#define CHECK_LAST(msg) {}
#endif
namespace gearshifft {
namespace CuFFT {
inline
void check_cuda(cudaError_t code, const char *func, const char *file, int line)
{
if (code != cudaSuccess)
{
fprintf(stderr,"CUDA Error '%s' at %s:%d (%s)\n", cudaGetErrorString(code), file, line, func);
cudaDeviceReset();
exit(static_cast<unsigned int>(code));
}
}
inline
void check_cuda_last(const char *msg, const char *file, int line)
{
cudaError_t code = cudaGetLastError();
if (code != cudaSuccess)
{
fprintf(stderr,"CUDA Error '%s' at %s:%d (%s)\n", cudaGetErrorString(code), file, line, msg);
cudaDeviceReset();
exit(static_cast<unsigned int>(code));
}
}
static const char* cufftResultToString(cufftResult error)
{
switch (error)
......@@ -47,7 +79,8 @@ namespace CuFFT {
return "<unknown>";
}
void check_error(cufftResult code, const char *func, const char *file, int line)
inline
void check_cufft(cufftResult code, const char *func, const char *file, int line)
{
if (code)
{
......
......@@ -59,10 +59,10 @@ namespace gearshifft
using TPrecision = typename Precision<typename TVector::value_type,
TFFT::IsComplex >::type;
assert(vec.data());
Statistics& stats = results.stats;
helper::Statistics& stats = results.stats;
TimeStatistics<TDeviceTimer> timer_dev(&stats); // or OpenCL timer
TimeStatistics<TimerCPU> timer_cpu(&stats);
helper::TimeStatistics<TDeviceTimer> timer_dev(&stats);
helper::TimeStatistics<helper::TimerCPU> timer_cpu(&stats);
int i_gpu = timer_dev.append("Device Runtime");
int i_cpu_alloc = timer_cpu.append("CPU Alloc");
int i_gpu_upload = timer_dev.append("Device Upload");
......
......@@ -32,7 +32,7 @@ namespace gearshifft
{
struct Results
{
Statistics stats;
helper::Statistics stats;
size_t alloc_mem_in_bytes = 0;
size_t plan_mem_in_bytes = 0;
};
......
......@@ -5,21 +5,28 @@
#include "timer.h"
#include "timestatistics.h"
typedef Timer<TimerCPU_> TimerCPU;
#if defined(CUDA_ENABLED) && defined(OPENCL_ENABLED)
#error "Either CUDA_ENABLED or OPENCL_ENABLED can be set, but not both."
#endif
#ifdef CUDA_ENABLED
#include "timer_cuda.h"
typedef Timer<TimerCUDA_> TimerGPU;
#endif
#ifdef OPENCL_ENABLED
#include "timer_opencl.h"
typedef Timer<TimerOpenCL_> TimerGPU;
#endif
namespace gearshifft {
namespace helper {
typedef Timer<TimerCPU_> TimerCPU;
#ifdef CUDA_ENABLED
typedef Timer<TimerCUDA_> TimerGPU;
#endif
#ifdef OPENCL_ENABLED
typedef Timer<TimerOpenCL_> TimerGPU;
#endif
} // helper
} // gearshifft
#endif /* HELPER_H_ */
......@@ -6,12 +6,15 @@
#include <iostream>
#include <iomanip>
class Statistics
{
namespace gearshifft {
namespace helper {
class Statistics
{
public:
Statistics();
virtual
~Statistics();
~Statistics();
int add(const std::string& label, const std::string& unit="", bool invert=false, double factor=1.0);
int append(const std::string& label, const std::string& unit="", bool invert=false, double factor=1.0);
......@@ -46,46 +49,46 @@ class Statistics
std::vector<double> _max;
std::vector<double> _sum;
std::vector<double> _sumsq;
};
};
std::ostream& operator<<(std::ostream& os, const Statistics& stats);
std::ostream& operator<<(std::ostream& os, const Statistics& stats);
//-----------------------------------------------------------------------------
inline int Statistics::getLength() const {
return _labels.size();
}
inline const std::string& Statistics::getLabel(int i) const {
check_index(i);
return _labels[i];
}
inline const std::string& Statistics::getUnit(int i) const {
check_index(i);
return _units[i];
}
inline double Statistics::getMin(int i) const {
check_index(i);
return _min[i];
}
inline double Statistics::getMax(int i) const {
check_index(i);
return _max[i];
}
inline int
Statistics::getCount (int i) const
{
check_index(i);
return _count[i];
}
inline double Statistics::getAverage(int i) const {
check_index(i);
return _sum[i]/_count[i];
}
inline int Statistics::getLength() const {
return _labels.size();
}
inline const std::string& Statistics::getLabel(int i) const {
check_index(i);
return _labels[i];
}
inline const std::string& Statistics::getUnit(int i) const {
check_index(i);
return _units[i];
}
inline double Statistics::getMin(int i) const {
check_index(i);
return _min[i];
}
inline double Statistics::getMax(int i) const {
check_index(i);
return _max[i];
}
inline int
Statistics::getCount (int i) const {
check_index(i);
return _count[i];
}
inline double Statistics::getAverage(int i) const {
check_index(i);
return _sum[i]/_count[i];
}
} // helper
} // gearshifft
#endif /* STATISTICS_H_ */
#ifndef TIMER_H_
#define TIMER_H_
#include <chrono>
#include <stdexcept>
namespace gearshifft {
namespace helper {
template<typename TimerImpl>
struct Timer : public TimerImpl {
bool started = false;
void startTimer() {
TimerImpl::startTimer();
started = true;
}
double stopTimer() {
if(started==false)
throw std::runtime_error("Timer must be started before.");
started = false;
return TimerImpl::stopTimer();
}
};
// Wall time
struct TimerCPU_ {
typedef std::chrono::high_resolution_clock clock;
clock::time_point start;
double time = 0.0;
void startTimer() {
start = clock::now();
}
double stopTimer() {
auto diff = clock::now() - start;
return (time = std::chrono::duration<double, std::milli> (diff).count());
}
};
} // helper
} // gearshifft
#endif /* TIMER_H_ */
#ifndef TIMER_CUDA_H_
#define TIMER_CUDA_H_
#include "cufft_helper.hpp"
#include <cuda_runtime.h>
namespace gearshifft {
namespace helper {
struct TimerCUDA_ {
double time = 0.0;
cudaEvent_t gpustart = 0;
cudaEvent_t gpustop = 0;
void startTimer() {
if(gpustart==0){
CHECK_CUDA(cudaEventCreate(&gpustart));
}
if(gpustop==0){
CHECK_CUDA(cudaEventCreate(&gpustop));
}
CHECK_CUDA( cudaEventRecord(gpustart) );
}
double stopTimer() {
float milliseconds = 0;
CHECK_CUDA(cudaEventRecord(gpustop));
CHECK_CUDA(cudaEventSynchronize(gpustop));
CHECK_CUDA(cudaEventElapsedTime(&milliseconds, gpustart, gpustop));
return (time = static_cast<double>(milliseconds));
}
~TimerCUDA_() {
if(gpustart){
CHECK_CUDA(cudaEventDestroy(gpustart));
}
if(gpustop){
CHECK_CUDA(cudaEventDestroy(gpustop));
}
}
};
} //
} // gearshifft
#endif /* TIMER_CUDA_H_ */
#ifndef TIMER_OPENCL_H_
#define TIMER_OPENCL_H_
#include "clfft_helper.hpp"
#include <CL/cl.h>
namespace gearshifft {
namespace helper {
/**
* @todo OpenCL Timer
*/
struct TimerOpenCL_ {
double time = 0.0;
void startTimer(){
}
double stopTimer(){
return time;
}
};
}