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

@@ -84,20 +84,20 @@ decomposition.
#endif
// includes, system
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <assert.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// includes, project
#include <helper_functions.h>
#include <helper_cuda.h>
#include <helper_functions.h>
// constants which are used in host and device code
#define INV_SQRT_2 0.70710678118654752440f;
const unsigned int LOG_NUM_BANKS = 4;
const unsigned int NUM_BANKS = 16;
const unsigned int NUM_BANKS = 16;
////////////////////////////////////////////////////////////////////////////////
// includes, kernels
@@ -111,256 +111,252 @@ bool getLevels(unsigned int len, unsigned int *levels);
////////////////////////////////////////////////////////////////////////////////
// Program main
////////////////////////////////////////////////////////////////////////////////
int main(int argc, char **argv) {
// run test
runTest(argc, argv);
int main(int argc, char **argv)
{
// run test
runTest(argc, argv);
}
////////////////////////////////////////////////////////////////////////////////
//! Perform the wavelet decomposition
////////////////////////////////////////////////////////////////////////////////
void runTest(int argc, char **argv) {
bool bResult = false; // flag for final validation of the results
void runTest(int argc, char **argv)
{
bool bResult = false; // flag for final validation of the results
char *s_fname = NULL, *r_gold_fname = NULL;
char r_fname[256];
const char usage[] = {
"\nUsage:\n"
" dwtHaar1D --signal=<signal_file> --result=<result_file> "
"--gold=<gold_file>\n\n"
" <signal_file> Input file containing the signal\n"
" <result_file> Output file storing the result of the wavelet "
"decomposition\n"
" <gold_file> Input file containing the reference result of the "
"wavelet decomposition\n"
"\nExample:\n"
" ./dwtHaar1D\n"
" --signal=signal.dat\n"
" --result=result.dat\n"
" --gold=regression.gold.dat\n"};
char *s_fname = NULL, *r_gold_fname = NULL;
char r_fname[256];
const char usage[] = {"\nUsage:\n"
" dwtHaar1D --signal=<signal_file> --result=<result_file> "
"--gold=<gold_file>\n\n"
" <signal_file> Input file containing the signal\n"
" <result_file> Output file storing the result of the wavelet "
"decomposition\n"
" <gold_file> Input file containing the reference result of the "
"wavelet decomposition\n"
"\nExample:\n"
" ./dwtHaar1D\n"
" --signal=signal.dat\n"
" --result=result.dat\n"
" --gold=regression.gold.dat\n"};
printf("%s Starting...\n\n", argv[0]);
printf("%s Starting...\n\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);
// file names, either specified as cmd line args or use default
if (argc == 4) {
char *tmp_sfname, *tmp_rfname, *tmp_goldfname;
// file names, either specified as cmd line args or use default
if (argc == 4) {
char *tmp_sfname, *tmp_rfname, *tmp_goldfname;
if ((getCmdLineArgumentString(argc, (const char **)argv, "signal",
&tmp_sfname) != true) ||
(getCmdLineArgumentString(argc, (const char **)argv, "result",
&tmp_rfname) != true) ||
(getCmdLineArgumentString(argc, (const char **)argv, "gold",
&tmp_goldfname) != true)) {
fprintf(stderr, "Invalid input syntax.\n%s", usage);
exit(EXIT_FAILURE);
if ((getCmdLineArgumentString(argc, (const char **)argv, "signal", &tmp_sfname) != true)
|| (getCmdLineArgumentString(argc, (const char **)argv, "result", &tmp_rfname) != true)
|| (getCmdLineArgumentString(argc, (const char **)argv, "gold", &tmp_goldfname) != true)) {
fprintf(stderr, "Invalid input syntax.\n%s", usage);
exit(EXIT_FAILURE);
}
s_fname = sdkFindFilePath(tmp_sfname, argv[0]);
r_gold_fname = sdkFindFilePath(tmp_goldfname, argv[0]);
strcpy(r_fname, tmp_rfname);
}
else {
s_fname = sdkFindFilePath("signal.dat", argv[0]);
r_gold_fname = sdkFindFilePath("regression.gold.dat", argv[0]);
strcpy(r_fname, "result.dat");
}
s_fname = sdkFindFilePath(tmp_sfname, argv[0]);
r_gold_fname = sdkFindFilePath(tmp_goldfname, argv[0]);
strcpy(r_fname, tmp_rfname);
} else {
s_fname = sdkFindFilePath("signal.dat", argv[0]);
r_gold_fname = sdkFindFilePath("regression.gold.dat", argv[0]);
strcpy(r_fname, "result.dat");
}
printf("source file = \"%s\"\n", s_fname);
printf("reference file = \"%s\"\n", r_fname);
printf("gold file = \"%s\"\n", r_gold_fname);
printf("source file = \"%s\"\n", s_fname);
printf("reference file = \"%s\"\n", r_fname);
printf("gold file = \"%s\"\n", r_gold_fname);
// read in signal
unsigned int slength = 0;
float *signal = NULL;
// read in signal
unsigned int slength = 0;
float *signal = NULL;
if (s_fname == NULL) {
fprintf(stderr, "Cannot find the file containing the signal.\n%s", usage);
if (s_fname == NULL) {
fprintf(stderr, "Cannot find the file containing the signal.\n%s", usage);
exit(EXIT_FAILURE);
}
exit(EXIT_FAILURE);
}
if (sdkReadFile(s_fname, &signal, &slength, false) == true) {
printf("Reading signal from \"%s\"\n", s_fname);
}
else {
exit(EXIT_FAILURE);
}
if (sdkReadFile(s_fname, &signal, &slength, false) == true) {
printf("Reading signal from \"%s\"\n", s_fname);
} else {
exit(EXIT_FAILURE);
}
// get the number of decompositions necessary to perform a full decomposition
unsigned int dlevels_complete = 0;
// get the number of decompositions necessary to perform a full decomposition
unsigned int dlevels_complete = 0;
if (true != getLevels(slength, &dlevels_complete)) {
// error message
fprintf(stderr, "Signal length not supported.\n");
// cleanup and abort
free(signal);
exit(EXIT_FAILURE);
}
// device in data
float *d_idata = NULL;
// device out data
float *d_odata = NULL;
// device approx_final data
float *approx_final = NULL;
// The very final approximation coefficient has to be written to the output
// data, all others are reused as input data in the next global step and
// therefore have to be written to the input data again.
// The following flag indicates where to copy approx_final data
// - 0 is input, 1 is output
int approx_is_input;
// allocate device mem
const unsigned int smem_size = sizeof(float) * slength;
checkCudaErrors(cudaMalloc((void **)&d_idata, smem_size));
checkCudaErrors(cudaMalloc((void **)&d_odata, smem_size));
checkCudaErrors(cudaMalloc((void **)&approx_final, smem_size));
// copy input data to device
checkCudaErrors(cudaMemcpy(d_idata, signal, smem_size, cudaMemcpyHostToDevice));
// total number of threads
// in the first decomposition step always one thread computes the average and
// detail signal for one pair of adjacent values
unsigned int num_threads_total_left = slength / 2;
// decomposition levels performed in the current / next step
unsigned int dlevels_step = dlevels_complete;
// 1D signal so the arrangement of elements is also 1D
dim3 block_size;
dim3 grid_size;
// number of decomposition levels left after one iteration on the device
unsigned int dlevels_left = dlevels_complete;
// if less or equal 1k elements, then the data can be processed in one block,
// this avoids the Wait-For-Idle (WFI) on host side which is necessary if the
// computation is split across multiple SM's if enough input data
if (dlevels_complete <= 10) {
// decomposition can be performed at once
block_size.x = num_threads_total_left;
approx_is_input = 0;
}
else {
// 512 threads per block
grid_size.x = (num_threads_total_left / 512);
block_size.x = 512;
// 512 threads corresponds to 10 decomposition steps
dlevels_step = 10;
dlevels_left -= 10;
approx_is_input = 1;
}
// Initialize d_odata to 0.0f
initValue<<<grid_size, block_size>>>(d_odata, 0.0f);
// do until full decomposition is accomplished
while (0 != num_threads_total_left) {
// double the number of threads as bytes
unsigned int mem_shared = (2 * block_size.x) * sizeof(float);
// extra memory requirements to avoid bank conflicts
mem_shared += ((2 * block_size.x) / NUM_BANKS) * sizeof(float);
// run kernel
dwtHaar1D<<<grid_size, block_size, mem_shared>>>(
d_idata, d_odata, approx_final, dlevels_step, num_threads_total_left, block_size.x);
// Copy approx_final to appropriate location
if (approx_is_input) {
checkCudaErrors(cudaMemcpy(d_idata, approx_final, grid_size.x * 4, cudaMemcpyDeviceToDevice));
}
else {
checkCudaErrors(cudaMemcpy(d_odata, approx_final, grid_size.x * 4, cudaMemcpyDeviceToDevice));
}
// update level variables
if (dlevels_left < 10) {
// approx_final = d_odata;
approx_is_input = 0;
}
// more global steps necessary
dlevels_step = (dlevels_left > 10) ? dlevels_left - 10 : dlevels_left;
dlevels_left -= 10;
// after each step only half the threads are used any longer
// therefore after 10 steps 2^10 less threads
num_threads_total_left = num_threads_total_left >> 10;
// update block and grid size
grid_size.x = (num_threads_total_left / 512) + (0 != (num_threads_total_left % 512)) ? 1 : 0;
if (grid_size.x <= 1) {
block_size.x = num_threads_total_left;
}
}
// get the result back from the server
// allocate mem for the result
float *odata = (float *)malloc(smem_size);
checkCudaErrors(cudaMemcpy(odata, d_odata, smem_size, cudaMemcpyDeviceToHost));
// post processing
// write file for regression test
if (r_fname == NULL) {
fprintf(stderr,
"Cannot write the output file storing the result of the wavelet "
"decomposition.\n%s",
usage);
exit(EXIT_FAILURE);
}
if (sdkWriteFile(r_fname, odata, slength, 0.001f, false) == true) {
printf("Writing result to \"%s\"\n", r_fname);
}
else {
exit(EXIT_FAILURE);
}
// load the reference solution
unsigned int len_reference = 0;
float *reference = NULL;
if (r_gold_fname == NULL) {
fprintf(stderr,
"Cannot read the file containing the reference result of the "
"wavelet decomposition.\n%s",
usage);
exit(EXIT_FAILURE);
}
if (sdkReadFile(r_gold_fname, &reference, &len_reference, false) == true) {
printf("Reading reference result from \"%s\"\n", r_gold_fname);
}
else {
exit(EXIT_FAILURE);
}
assert(slength == len_reference);
// compare the computed solution and the reference
bResult = (bool)sdkCompareL2fe(reference, odata, slength, 0.001f);
free(reference);
// free allocated host and device memory
checkCudaErrors(cudaFree(d_odata));
checkCudaErrors(cudaFree(d_idata));
checkCudaErrors(cudaFree(approx_final));
if (true != getLevels(slength, &dlevels_complete)) {
// error message
fprintf(stderr, "Signal length not supported.\n");
// cleanup and abort
free(signal);
exit(EXIT_FAILURE);
}
free(odata);
free(s_fname);
free(r_gold_fname);
// device in data
float *d_idata = NULL;
// device out data
float *d_odata = NULL;
// device approx_final data
float *approx_final = NULL;
// The very final approximation coefficient has to be written to the output
// data, all others are reused as input data in the next global step and
// therefore have to be written to the input data again.
// The following flag indicates where to copy approx_final data
// - 0 is input, 1 is output
int approx_is_input;
// allocate device mem
const unsigned int smem_size = sizeof(float) * slength;
checkCudaErrors(cudaMalloc((void **)&d_idata, smem_size));
checkCudaErrors(cudaMalloc((void **)&d_odata, smem_size));
checkCudaErrors(cudaMalloc((void **)&approx_final, smem_size));
// copy input data to device
checkCudaErrors(
cudaMemcpy(d_idata, signal, smem_size, cudaMemcpyHostToDevice));
// total number of threads
// in the first decomposition step always one thread computes the average and
// detail signal for one pair of adjacent values
unsigned int num_threads_total_left = slength / 2;
// decomposition levels performed in the current / next step
unsigned int dlevels_step = dlevels_complete;
// 1D signal so the arrangement of elements is also 1D
dim3 block_size;
dim3 grid_size;
// number of decomposition levels left after one iteration on the device
unsigned int dlevels_left = dlevels_complete;
// if less or equal 1k elements, then the data can be processed in one block,
// this avoids the Wait-For-Idle (WFI) on host side which is necessary if the
// computation is split across multiple SM's if enough input data
if (dlevels_complete <= 10) {
// decomposition can be performed at once
block_size.x = num_threads_total_left;
approx_is_input = 0;
} else {
// 512 threads per block
grid_size.x = (num_threads_total_left / 512);
block_size.x = 512;
// 512 threads corresponds to 10 decomposition steps
dlevels_step = 10;
dlevels_left -= 10;
approx_is_input = 1;
}
// Initialize d_odata to 0.0f
initValue<<<grid_size, block_size>>>(d_odata, 0.0f);
// do until full decomposition is accomplished
while (0 != num_threads_total_left) {
// double the number of threads as bytes
unsigned int mem_shared = (2 * block_size.x) * sizeof(float);
// extra memory requirements to avoid bank conflicts
mem_shared += ((2 * block_size.x) / NUM_BANKS) * sizeof(float);
// run kernel
dwtHaar1D<<<grid_size, block_size, mem_shared>>>(
d_idata, d_odata, approx_final, dlevels_step, num_threads_total_left,
block_size.x);
// Copy approx_final to appropriate location
if (approx_is_input) {
checkCudaErrors(cudaMemcpy(d_idata, approx_final, grid_size.x * 4,
cudaMemcpyDeviceToDevice));
} else {
checkCudaErrors(cudaMemcpy(d_odata, approx_final, grid_size.x * 4,
cudaMemcpyDeviceToDevice));
}
// update level variables
if (dlevels_left < 10) {
// approx_final = d_odata;
approx_is_input = 0;
}
// more global steps necessary
dlevels_step = (dlevels_left > 10) ? dlevels_left - 10 : dlevels_left;
dlevels_left -= 10;
// after each step only half the threads are used any longer
// therefore after 10 steps 2^10 less threads
num_threads_total_left = num_threads_total_left >> 10;
// update block and grid size
grid_size.x =
(num_threads_total_left / 512) + (0 != (num_threads_total_left % 512))
? 1
: 0;
if (grid_size.x <= 1) {
block_size.x = num_threads_total_left;
}
}
// get the result back from the server
// allocate mem for the result
float *odata = (float *)malloc(smem_size);
checkCudaErrors(
cudaMemcpy(odata, d_odata, smem_size, cudaMemcpyDeviceToHost));
// post processing
// write file for regression test
if (r_fname == NULL) {
fprintf(stderr,
"Cannot write the output file storing the result of the wavelet "
"decomposition.\n%s",
usage);
exit(EXIT_FAILURE);
}
if (sdkWriteFile(r_fname, odata, slength, 0.001f, false) == true) {
printf("Writing result to \"%s\"\n", r_fname);
} else {
exit(EXIT_FAILURE);
}
// load the reference solution
unsigned int len_reference = 0;
float *reference = NULL;
if (r_gold_fname == NULL) {
fprintf(stderr,
"Cannot read the file containing the reference result of the "
"wavelet decomposition.\n%s",
usage);
exit(EXIT_FAILURE);
}
if (sdkReadFile(r_gold_fname, &reference, &len_reference, false) == true) {
printf("Reading reference result from \"%s\"\n", r_gold_fname);
} else {
exit(EXIT_FAILURE);
}
assert(slength == len_reference);
// compare the computed solution and the reference
bResult = (bool)sdkCompareL2fe(reference, odata, slength, 0.001f);
free(reference);
// free allocated host and device memory
checkCudaErrors(cudaFree(d_odata));
checkCudaErrors(cudaFree(d_idata));
checkCudaErrors(cudaFree(approx_final));
free(signal);
free(odata);
free(s_fname);
free(r_gold_fname);
printf(bResult ? "Test success!\n" : "Test failure!\n");
printf(bResult ? "Test success!\n" : "Test failure!\n");
}
////////////////////////////////////////////////////////////////////////////////
@@ -373,17 +369,18 @@ void runTest(int argc, char **argv) {
//! @param levels number of decomposition levels necessary to perform a full
//! decomposition
////////////////////////////////////////////////////////////////////////////////
bool getLevels(unsigned int len, unsigned int *levels) {
bool retval = false;
bool getLevels(unsigned int len, unsigned int *levels)
{
bool retval = false;
// currently signals up to a length of 2^20 supported
for (unsigned int i = 0; i < 20; ++i) {
if (len == (1 << i)) {
*levels = i;
retval = true;
break;
// currently signals up to a length of 2^20 supported
for (unsigned int i = 0; i < 20; ++i) {
if (len == (1 << i)) {
*levels = i;
retval = true;
break;
}
}
}
return retval;
return retval;
}

View File

@@ -91,16 +91,17 @@ namespace cg = cooperative_groups;
//! @param od output data
//! @param value
////////////////////////////////////////////////////////////////////////////////
__global__ void initValue(float *od, float value) {
// Handle to thread block group
cg::thread_block cta = cg::this_thread_block();
// position of write into global memory
unsigned int index = (blockIdx.x * blockDim.x) + threadIdx.x;
__global__ void initValue(float *od, float value)
{
// Handle to thread block group
cg::thread_block cta = cg::this_thread_block();
// position of write into global memory
unsigned int index = (blockIdx.x * blockDim.x) + threadIdx.x;
od[index] = value;
od[index] = value;
// sync after each decomposition step
cg::sync(cta);
// sync after each decomposition step
cg::sync(cta);
}
////////////////////////////////////////////////////////////////////////////////
@@ -118,127 +119,130 @@ __global__ void initValue(float *od, float value) {
//! global memory
//! @param bdim block dimension
////////////////////////////////////////////////////////////////////////////////
__global__ void dwtHaar1D(float *id, float *od, float *approx_final,
__global__ void dwtHaar1D(float *id,
float *od,
float *approx_final,
const unsigned int dlevels,
const unsigned int slength_step_half,
const int bdim) {
// Handle to thread block group
cg::thread_block cta = cg::this_thread_block();
const int bdim)
{
// Handle to thread block group
cg::thread_block cta = cg::this_thread_block();
// shared memory for part of the signal
extern __shared__ float shared[];
// shared memory for part of the signal
extern __shared__ float shared[];
// thread runtime environment, 1D parametrization
const int gdim = gridDim.x;
// const int bdim = blockDim.x;
const int bid = blockIdx.x;
const int tid = threadIdx.x;
// thread runtime environment, 1D parametrization
const int gdim = gridDim.x;
// const int bdim = blockDim.x;
const int bid = blockIdx.x;
const int tid = threadIdx.x;
// global thread id (w.r.t. to total data set)
const int tid_global = (bid * bdim) + tid;
unsigned int idata = (bid * (2 * bdim)) + tid;
// global thread id (w.r.t. to total data set)
const int tid_global = (bid * bdim) + tid;
unsigned int idata = (bid * (2 * bdim)) + tid;
// read data from global memory
shared[tid] = id[idata];
shared[tid + bdim] = id[idata + bdim];
cg::sync(cta);
// read data from global memory
shared[tid] = id[idata];
shared[tid + bdim] = id[idata + bdim];
cg::sync(cta);
// this operation has a two way bank conflicts for all threads, this are two
// additional cycles for each warp -- all alternatives to avoid this bank
// conflict are more expensive than the one cycle introduced by serialization
float data0 = shared[2 * tid];
float data1 = shared[(2 * tid) + 1];
cg::sync(cta);
// this operation has a two way bank conflicts for all threads, this are two
// additional cycles for each warp -- all alternatives to avoid this bank
// conflict are more expensive than the one cycle introduced by serialization
float data0 = shared[2 * tid];
float data1 = shared[(2 * tid) + 1];
cg::sync(cta);
// detail coefficient, not further referenced so directly store in
// global memory
od[tid_global + slength_step_half] = (data0 - data1) * INV_SQRT_2;
// detail coefficient, not further referenced so directly store in
// global memory
od[tid_global + slength_step_half] = (data0 - data1) * INV_SQRT_2;
// offset to avoid bank conflicts
// see the scan example for a more detailed description
unsigned int atid = tid + (tid >> LOG_NUM_BANKS);
// offset to avoid bank conflicts
// see the scan example for a more detailed description
unsigned int atid = tid + (tid >> LOG_NUM_BANKS);
// approximation coefficient
// store in shared memory for further decomposition steps in this global step
shared[atid] = (data0 + data1) * INV_SQRT_2;
// approximation coefficient
// store in shared memory for further decomposition steps in this global step
shared[atid] = (data0 + data1) * INV_SQRT_2;
// all threads have to write approximation coefficient to shared memory before
// next steps can take place
cg::sync(cta);
// all threads have to write approximation coefficient to shared memory before
// next steps can take place
cg::sync(cta);
// early out if possible
// the compiler removes this part from the source because dlevels is
// a constant shader input
// note: syncthreads in bodies of branches can lead to dead-locks unless
// the condition evaluates the same way for ALL threads of a block, as in
// this case
if (dlevels > 1) {
// offset to second element in shared element which has to be used for the
// decomposition, effectively 2^(i - 1)
unsigned int offset_neighbor = 1;
// number of active threads per decomposition level
// identical to the offset for the detail coefficients
unsigned int num_threads = bdim >> 1;
// early out if possible
// the compiler removes this part from the source because dlevels is
// a constant shader input
// note: syncthreads in bodies of branches can lead to dead-locks unless
// the condition evaluates the same way for ALL threads of a block, as in
// this case
if (dlevels > 1) {
// offset to second element in shared element which has to be used for the
// decomposition, effectively 2^(i - 1)
unsigned int offset_neighbor = 1;
// number of active threads per decomposition level
// identical to the offset for the detail coefficients
unsigned int num_threads = bdim >> 1;
// index for the first element of the pair to process
// the representation is still compact (and therefore still tid * 2)
// because the first step operated on registers and only the result has been
// written to shared memory
unsigned int idata0 = tid * 2;
// index for the first element of the pair to process
// the representation is still compact (and therefore still tid * 2)
// because the first step operated on registers and only the result has been
// written to shared memory
unsigned int idata0 = tid * 2;
// offset levels to make the loop more efficient
for (unsigned int i = 1; i < dlevels; ++i) {
// Non-coalesced writes occur if the number of active threads becomes
// less than 16 for a block because the start address for the first
// block is not always aligned with 64 byte which is necessary for
// coalesced access. However, the problem only occurs at high levels
// with only a small number of active threads so that the total number of
// non-coalesced access is rather small and does not justify the
// computations which are necessary to avoid these uncoalesced writes
// (this has been tested and verified)
if (tid < num_threads) {
// update stride, with each decomposition level the stride grows by a
// factor of 2
unsigned int idata1 = idata0 + offset_neighbor;
// offset levels to make the loop more efficient
for (unsigned int i = 1; i < dlevels; ++i) {
// Non-coalesced writes occur if the number of active threads becomes
// less than 16 for a block because the start address for the first
// block is not always aligned with 64 byte which is necessary for
// coalesced access. However, the problem only occurs at high levels
// with only a small number of active threads so that the total number of
// non-coalesced access is rather small and does not justify the
// computations which are necessary to avoid these uncoalesced writes
// (this has been tested and verified)
if (tid < num_threads) {
// update stride, with each decomposition level the stride grows by a
// factor of 2
unsigned int idata1 = idata0 + offset_neighbor;
// position of write into global memory
unsigned int g_wpos = (num_threads * gdim) + (bid * num_threads) + tid;
// position of write into global memory
unsigned int g_wpos = (num_threads * gdim) + (bid * num_threads) + tid;
// compute wavelet decomposition step
// compute wavelet decomposition step
// offset to avoid bank conflicts
unsigned int c_idata0 = idata0 + (idata0 >> LOG_NUM_BANKS);
unsigned int c_idata1 = idata1 + (idata1 >> LOG_NUM_BANKS);
// offset to avoid bank conflicts
unsigned int c_idata0 = idata0 + (idata0 >> LOG_NUM_BANKS);
unsigned int c_idata1 = idata1 + (idata1 >> LOG_NUM_BANKS);
// detail coefficient, not further modified so directly store
// in global memory
od[g_wpos] = (shared[c_idata0] - shared[c_idata1]) * INV_SQRT_2;
// detail coefficient, not further modified so directly store
// in global memory
od[g_wpos] = (shared[c_idata0] - shared[c_idata1]) * INV_SQRT_2;
// approximation coefficient
// note that the representation in shared memory becomes rather sparse
// (with a lot of holes inbetween) but the storing scheme in global
// memory guarantees that the common representation (approx, detail_0,
// detail_1, ...)
// is achieved
shared[c_idata0] = (shared[c_idata0] + shared[c_idata1]) * INV_SQRT_2;
// approximation coefficient
// note that the representation in shared memory becomes rather sparse
// (with a lot of holes inbetween) but the storing scheme in global
// memory guarantees that the common representation (approx, detail_0,
// detail_1, ...)
// is achieved
shared[c_idata0] = (shared[c_idata0] + shared[c_idata1]) * INV_SQRT_2;
// update storage offset for details
num_threads = num_threads >> 1; // div 2
offset_neighbor <<= 1; // mul 2
idata0 = idata0 << 1; // mul 2
}
// update storage offset for details
num_threads = num_threads >> 1; // div 2
offset_neighbor <<= 1; // mul 2
idata0 = idata0 << 1; // mul 2
}
// sync after each decomposition step
cg::sync(cta);
}
// sync after each decomposition step
cg::sync(cta);
}
// write the top most level element for the next decomposition steps
// which are performed after an interlock synchronization on host side
if (0 == tid) {
approx_final[bid] = shared[0];
}
// write the top most level element for the next decomposition steps
// which are performed after an interlock synchronization on host side
if (0 == tid) {
approx_final[bid] = shared[0];
}
} // end early out if possible
} // end early out if possible
}
#endif // #ifndef _DWTHAAR1D_KERNEL_H_
#endif // #ifndef _DWTHAAR1D_KERNEL_H_