su2hmc
Loading...
Searching...
No Matches
Helper functions
Collaboration diagram for Helper functions:

Topics

 Site Indexing

Macros

#define MIN(x, y)
 Return the max of two values.
#define MAX(x, y)
 Return the min of two values.

Functions

void Transpose_z (Complex *out, const int, const int)
 In place transpose used to convert from AoS to SoA memory layout.
void Transpose_c (Complex_f *out, const int, const int)
 In place transpose used to convert from AoS to SoA memory layout.
void Transpose_d (double *out, const int, const int)
 In place transpose used to convert from AoS to SoA memory layout.
void Transpose_f (float *out, const int, const int)
 In place transpose used to convert from AoS to SoA memory layout.
void Transpose_I (int *out, const int, const int)
 In place transpose used to convert from AoS to SoA memory layout.
void Transpose_U (unsigned int *out, const int, const int)
 In place transpose used to convert from AoS to SoA memory layout.
double cureduce_sum_d (double *input, const unsigned int n, const unsigned short stream)
 Sum all terms in an array of doubles.
float cureduce_sum_f (float *input, const unsigned int n, const unsigned short stream)
 Sum all terms in an array of floats.
void cuTranspose_z (Complex *out, const int fast_in, const int fast_out, const dim3 dimGrid, const dim3 dimBlock)
 In place transpose used to convert from AoS to SoA memory layout.
void cuTranspose_c (Complex_f *out, const int fast_in, const int fast_out, const dim3 dimGrid, const dim3 dimBlock)
 In place transpose used to convert from AoS to SoA memory layout.
void cuTranspose_d (double *out, const int fast_in, const int fast_out, const dim3 dimGrid, const dim3 dimBlock)
 In place transpose used to convert from AoS to SoA memory layout.
void cuTranspose_f (float *out, const int fast_in, const int fast_out, const dim3 dimGrid, const dim3 dimBlock)
 In place transpose used to convert from AoS to SoA memory layout.
void cuTranspose_I (int *out, const int fast_in, const int fast_out, const dim3 dimGrid, const dim3 dimBlock)
 In place transpose used to convert from AoS to SoA memory layout.
void cuTranspose_U (unsigned int *out, const int fast_in, const int fast_out, const dim3 dimGrid, const dim3 dimBlock)
 In place transpose used to convert from AoS to SoA memory layout.
void cuMixed_Sumto (double *d, float *f, const unsigned int n, const dim3 dimGrid, const dim3 dimBlock)
 Add a single to a double value, and save the output in the double array For complex valued arrays, one may cast the complex<double> and complex<float> arrays to double and float arrays, and use 2N for the array length instead.
int Init (const int istart, const int ibound, const int iread, const float beta, const float fmu, const float akappa, const Complex_f ajq, const float c_sw, Complex *u[2], Complex *ut[2], Complex_f *ut_f[2], Complex gamval[20], Complex_f gamval_f[20], unsigned short gamin[16], double *dk[2], float *dk_f[2], unsigned int *iu, unsigned int *id)
 Initialises the system.
int C_gather (Complex_f *x, Complex_f *y, int n, unsigned int *table, unsigned int mu)
 Extracts all the single precision gauge links in the \(\mu\) direction only.
int Z_gather (Complex *x, Complex *y, int n, unsigned int *table, unsigned int mu)
 Extracts all the double precision gauge links in the \(\mu\) direction only.
int Fill_Small_Phi (int na, Complex *smallPhi, Complex *Phi)
 Copies necessary (2*4*kvol) elements of Phi into a vector variable.
int UpDownPart (const unsigned int na, Complex *X0, Complex *R1)
 Up/Down partitioning of the pseudofermion field.
int Reunitarise (Complex *ut[2])
 Reunitarises u11t and u12t as in conj(u11t[i])*u11t[i]+conj(u12t[i])*u12t[i]=1.
int ComplexConvert (Complex_f *a, Complex *b, const unsigned int len, const bool dtof, const unsigned short stride)
 takes an array of complex float and double precision numbers and converts the precision
void Init_CUDA (Complex *u11t, Complex *u12t, Complex gamval[20], Complex_f gamval_f[20], unsigned short gamin[16], double *dk4m, double *dk4p, unsigned int *iu, unsigned int *id)
 Initialise CUDA cuInit was taken already by CUDA (unsurprisingly).
void cuFill_Small_Phi (const unsigned int na, Complex *smallPhi, Complex *Phi, dim3 dimBlock, dim3 dimGrid)
 Copies necessary (2*4*kvol) elements of Phi into a vector variable.
void cuComplex_convert (Complex_f *a, Complex *b, const unsigned int len, const bool dtof, dim3 dimBlock, dim3 dimGrid)
 takes an array of complex float and double precision numbers and converts the precision
void cuReal_convert (float *a, double *b, const unsigned int len, const bool dtof, dim3 dimBlock, dim3 dimGrid)
 takes an array of real-valued float and double precision numbers and converts the precision
void cuUpDownPart (const unsigned int na, Complex *X0, Complex *R1, dim3 dimBlock, dim3 dimGrid)
 Up/Down partitioning of the pseudofermion field.
void cuReunitarise (Complex *ut[2], dim3 dimGrid, dim3 dimBlock)
 Reunitarises u11t and u12t as in conj(u11t[i])*u11t[i]+conj(u12t[i])*u12t[i]=1.
void blockInit (int x, int y, int z, int t, dim3 *dimBlock, dim3 *dimGrid)
 Initialises the CUDA grid and block size for a given lattice.
template<typename T>
__device__ __forceinline__ T conj (const T &z)
 Complex Conjugation.
void Q_allocate_f (Complex_f **p_f, Complex_f **x1_f, Complex_f **x2_f, Complex_f **r_f, Complex_f **X1_f)
 Allocates memory needed for Congradq. Just to improve readability Note that since C does not modify it's arguments, you need to pass a pointer to the pointer you want to assign the memory to. This is similar behaviour to cudaMalloc.
void Q_allocate (Complex **p, Complex **x1, Complex **x2, Complex *clover[2])
 Allocates double precision memory needed for Congradq. Just to improve readability Note that since C does not modify it's arguments, you need to pass a pointer to the pointer you want to assign the memory to. This is similar behaviour to cudaMalloc.
void P_allocate_f (Complex_f **p_f, Complex_f **r_f, Complex_f **x1_f, Complex_f **x2_f, Complex_f **xi_f)
 Allocates memory needed for Congradp. Just to improve readability Note that since C does not modify it's arguments, you need to pass a pointer to the pointer you want to assign the memory to. This is similar behaviour to cudaMalloc.
void P_allocate (Complex **p, Complex **r, Complex **x1, Complex **x2, Complex *clover[2])
 Allocates double precision memory needed for Congradp. Just to improve readability Note that since C does not modify it's arguments, you need to pass a pointer to the pointer you want to assign the memory to. This is similar behaviour to cudaMalloc.
void Q_free_f (Complex_f **p_f, Complex_f **x1_f, Complex_f **x2_f, Complex_f **r_f, Complex_f **X1_f)
 Frees memory needed for Congradq. Just to improve readability Note that since C does not modify it's arguments, you need to pass a pointer to the pointer you want to assign the memory to. This is similar behaviour to cudaMalloc.
void Q_free (Complex **p, Complex **x1, Complex **x2, Complex *clover[2])
 Frees double precision memory needed for Congradq. Just to improve readability Note that since C does not modify it's arguments, you need to pass a pointer to the pointer you want to assign the memory to. This is similar behaviour to cudaMalloc.
void P_free_f (Complex_f **p_f, Complex_f **r_f, Complex_f **x1_f, Complex_f **x2_f, Complex_f **xi_f)
 Frees memory needed for Congradp. Just to improve readability Note that since C does not modify it's arguments, you need to pass a pointer to the pointer you want to assign the memory to. This is similar behaviour to cudaMalloc.
void P_free (Complex **p, Complex **r, Complex **x1, Complex **x2, Complex *clover[2])
 Frees memory needed for Congradp. Just to improve readability Note that since C does not modify it's arguments, you need to pass a pointer to the pointer you want to assign the memory to. This is similar behaviour to cudaMalloc.
template<typename T>
__global__ void Kernels::Gather (T *x, T *y, const unsigned int n, unsigned int *table, const unsigned short mu)
 Extracts all the single precision gauge links in the \(\mu\) direction only.
template<typename T, unsigned int bsize>
__device__ void Device::warpReduce_sum (volatile T *sdata, const unsigned int tid)
 Performs a warp reduction for sum.
template<typename T>
__global__ void Kernels::Transpose (T *out, const T *in, const int fast_in, const int fast_out)
 Swaps the order of the gauge field so that it is now SoA instead of AoS and it is nice and coalesced in memory.
__global__ void Kernels::Mixed_Sumto (double *d, float *f, const unsigned int n)
 Sums a float array into a double array.
template<typename T, unsigned int bsize>
__global__ void Kernels::reduce_sum (T *g_in_data, T *g_out_data, const unsigned int n)
 Performs a block reduction for sum.
__global__ void Kernels::Real_convert (float *a, double *b, const unsigned int len, const bool dtof)
 takes an array of real float and double precision numbers and converts the precision
__global__ void Kernels::cuFill_Small_Phi (const unsigned int na, Complex *smallPhi, Complex *Phi)
 Copies necessary (2*4*kvol) elements of Phi into a vector variable.
__global__ void Kernels::cuUpDownPart (const unsigned int na, Complex *X0, Complex *R1)
 Up/Down partitioning of the pseudofermion field.
template<typename T>
__global__ void Kernels::cuReunitarise (complex< T > *u11t, complex< T > *u12t)
 Reunitarises u11t and u12t as in conj(u11t[i])*u11t[i]+conj(u12t[i])*u12t[i]=1.

Detailed Description

Macro Definition Documentation

◆ MAX

#define MAX ( x,
y )
Value:
(x>y?x:y)

Return the min of two values.

Parameters
[in]x,yvalues being checked

Definition at line 21 of file cusu2hmc.cu.

◆ MIN

#define MIN ( x,
y )
Value:
(x<y?x:y)

Return the max of two values.

Parameters
[in]x,yvalues being checked

Definition at line 14 of file cusu2hmc.cu.

Function Documentation

◆ blockInit()

void blockInit ( int x,
int y,
int z,
int t,
dim3 * dimBlock,
dim3 * dimGrid )

Initialises the CUDA grid and block size for a given lattice.

Parameters
[in]x,y,z,tLattice dimensions
[out]dimGrid,dimBlockCUDA grid/block size
Postcondition
dimGrid and dimBlock initialised

Definition at line 205 of file cusu2hmc.cu.

205 {
206
207 const char *funcname = "blockInit";
208
209 int device=-1; cudaGetDevice(&device);
210 cudaDeviceProp prop; cudaGetDeviceProperties(&prop, device);
211 //Threads per block
212 int tpb=prop.maxThreadsPerBlock/8;
213 //Warp size
214 int tpw=prop.warpSize;
215 int bx=1;
216 //Set bx to be the largest power of 2 less than x that fits in a block
217 while(bx<=x/2 && bx<tpb)
218 bx*=2;
219 int by=1;
220 //Set by to be the largest power of 2 less than y such that bx*by fits in a block
221 while(by<=y/2 && bx*by<tpb)
222 by*=2;
223
224 if(bx*by>=128){
225 *dimBlock=dim3(bx,by);
226 //If the block size neatly divides the lattice size we can create
227 //extra blocks safely
228 int res= ((nx*ny)/(bx*by) > 1) ? (nx*ny)/(bx*by) :1;
229 // int res = 1;
230 *dimGrid=dim3(nz,nt,res);
231 }
232 else{
233 int bz=1;
234 //Set by to be the largest power of 2 less than y such that bx*by fits in an optimal block
235 while(bz<z/2 && bx*by*bz<tpb)
236 bz*=2;
237 *dimBlock=dim3(bx,by,bz);
238
239 //If we have an awkward block size then flag it.
240 if(bx*by*bz%tpw!=0)
241 fprintf(stderr,"Alert %i in %s: Suboptimal block size for warp size %d. bx=%d by=%d bz=%d\n",
242 BLOCKALERT, funcname, tpw, bx, by,bz);
243 int res= ((nx*ny)/(bx*by) > 1) ? (nx*ny)/(bx*by) :1;
244 *dimGrid=dim3(z/bz,nt,res);
245 }
246 printf("Block: (%d,%d,%d)\tGrid: (%d,%d,%d)\n",dimBlock->x,dimBlock->y,dimBlock->z,dimGrid->x,dimGrid->y,dimGrid->z);
247}
#define BLOCKALERT
Alert with block size.
Definition errorcodes.h:161
#define nt
Lattice temporal extent. This also corresponds to the inverse temperature.
Definition sizes.h:92
#define nx
Lattice x extent.
Definition sizes.h:72
dim3 dimGrid
Default grid size. First component is normally nt. Second and third depend whatever is needed to get ...
Definition cusu2hmc.cu:27
#define nz
Lattice z extent. We normally use cubic lattices so this is the same as nx.
Definition sizes.h:86
#define ny
Lattice y extent. We normally use cubic lattices so this is the same as nx.
Definition sizes.h:80
dim3 dimBlock
Default block size. Usually 128.
Definition cusu2hmc.cu:25

References BLOCKALERT, dimBlock, dimGrid, nt, nx, ny, and nz.

Here is the caller graph for this function:

◆ C_gather()

int C_gather ( Complex_f * x,
Complex_f * y,
int n,
unsigned int * table,
unsigned int mu )
inline

Extracts all the single precision gauge links in the \(\mu\) direction only.

Parameters
[out]xThe output
[in]yThe gauge field for a particular colour
[in]nNumber of sites in the gauge field. This is typically kvol
[in]tableTable containing information on nearest neighbours. Usually id or iu
[in]muDirection we're interested in extracting
Returns
Zero on success, integer error code otherwise
Postcondition
Contents of x replaced with output

Definition at line 291 of file su2hmc.c.

292{
293 const char funcname[] = "C_gather";
294 //FORTRAN had a second parameter m giving the size of y (kvol+halo) normally
295 //Pointers mean that's not an issue for us so I'm leaving it out
296#pragma omp parallel for simd aligned (x,y,table:AVX)
297 for(unsigned int i=0; i<n; i++)
298 x[i]=y[table[i+kvol*mu]+kvolHalo*mu];
299 return 0;
300}
#define kvol
Sublattice volume.
Definition sizes.h:163
#define kvolHalo
Subvolume + halo size.
Definition sizes.h:234

References Complex_f, kvol, and kvolHalo.

Here is the caller graph for this function:

◆ ComplexConvert()

int ComplexConvert ( Complex_f * a,
Complex * b,
const unsigned int len,
const bool dtof,
const unsigned short stride )

takes an array of complex float and double precision numbers and converts the precision

Parameters
[in,out]aFloat array
[in,out]bDouble array
[in]lenNumber of elements to convert per stride. Striding needed to handle halo terms
[in]dtofIf true, convert double to float. Otherwise convert float to double
[in]strideFor terms with a halo, we need to convert in blocks of len separated by (len+halo)
Returns
Zero on success, integer error code otherwise
Postcondition
Depending on the value of dtof, either the contents of a or b are overwritten with those of the other array in the opposite precision.

Definition at line 420 of file coord.c.

420 {
421 const char funcname[] = "ComplexConvert";
422 switch(stride){
423 case(0):
424 fprintf(stderr,"Error %i in %s: Stride of %d is not valid.\nExiting...\n\n",STRDERROR,funcname,stride);
425#if (nproc>1)
426 MPI_Abort(comm,STRDERROR);
427#else
428 exit(STRDERROR);
429#endif
430 break;
431 case(1):
432#ifdef USE_GPU
433 cuComplex_convert(a,b,len*stride,dtof,dimBlock,dimGrid);
434#else
435 if(dtof)
436#pragma omp parallel for simd aligned(a,b:AVX)
437 for(unsigned int i=0;i<len*stride;i++)
438 a[i]=(Complex_f)b[i];
439 else
440#pragma omp parallel for simd aligned(a,b:AVX)
441 for(unsigned int i=0;i<len*stride;i++)
442 b[i]=(Complex)a[i];
443#endif
444 break;
445 default:
446 for(unsigned short j=0;j<stride;j++){
447#ifdef USE_GPU
448 cuComplex_convert(a+j*(len+halo),b+j*(len+halo),len,dtof,dimBlock,dimGrid);
449#else
450 if(dtof)
451#pragma omp parallel for simd aligned(a,b:AVX)
452 for(unsigned int i=0;i<len;i++)
453 a[i+j*(len+halo)]=(Complex_f)b[i+j*(len+halo)];
454 else
455#pragma omp parallel for simd aligned(a,b:AVX)
456 for(unsigned int i=0;i<len;i++)
457 b[i+j*(len+halo)]=(Complex)a[i+j*(len+halo)];
458#endif
459 }
460 break;
461 }
462 return 0;
463}
#define STRDERROR
Undefined stride.
Definition errorcodes.h:68
void cuComplex_convert(Complex_f *a, Complex *b, const unsigned int len, const bool dtof, dim3 dimBlock, dim3 dimGrid)
takes an array of complex float and double precision numbers and converts the precision
Definition cusu2hmc.cu:284
#define Complex
Double precision complex number.
Definition sizes.h:64
#define halo
Total Halo size.
Definition sizes.h:231
#define Complex_f
Single precision complex number.
Definition sizes.h:62

References Complex, Complex_f, cuComplex_convert(), dimBlock, dimGrid, halo, and STRDERROR.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ conj()

template<typename T>
__device__ __forceinline__ T conj ( const T & z)

Complex Conjugation.

Parameters
zNumber to be conjugated
Returns
Conjugate of z

Definition at line 33 of file cusu2hmc.cu.

33 {
34 return T(z.real(),-z.imag());
35}
Here is the caller graph for this function:

◆ cuComplex_convert()

void cuComplex_convert ( Complex_f * a,
Complex * b,
const unsigned int len,
const bool dtof,
dim3 dimBlock,
dim3 dimGrid )

takes an array of complex float and double precision numbers and converts the precision

Parameters
[in,out]aFloat array
[in,out]bDouble array
[in]lenNumber of elements to convert
[in]dtofIf true, convert double to float. Otherwise convert float to double
[in]dimGrid,dimBlockCUDA grid/block size
Postcondition
Depending on the value of dtof, either the contents of a or b are overwritten with those of the other array in the opposite precision.

Definition at line 284 of file cusu2hmc.cu.

284 {
285 const char *funcname = "cuComplex_convert";
286 Kernels::Real_convert<<<dimGrid,dimBlock>>>((float *)a,(double *)b,2*len,dtof);
287}
__global__ void Real_convert(float *a, double *b, const unsigned int len, const bool dtof)
takes an array of real float and double precision numbers and converts the precision
Definition cusu2hmc.cu:50

References Complex, Complex_f, dimBlock, dimGrid, and Kernels::Real_convert().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ cuFill_Small_Phi() [1/2]

void cuFill_Small_Phi ( const unsigned int na,
Complex * smallPhi,
Complex * Phi,
dim3 dimBlock,
dim3 dimGrid )

Copies necessary (2*4*kvol) elements of Phi into a vector variable.

Parameters
[in]naflavour index
[out]smallPhiThe partitioned output
[in]PhiThe pseudofermion field
[in]dimGrid,dimBlockCUDA grid/block size

Definition at line 288 of file cusu2hmc.cu.

288 {
290}
__global__ void cuFill_Small_Phi(const unsigned int na, Complex *smallPhi, Complex *Phi)
Copies necessary (2*4*kvol) elements of Phi into a vector variable.
Definition cusu2hmc.cu:76

References Complex, Kernels::cuFill_Small_Phi(), dimBlock, and dimGrid.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ cuFill_Small_Phi() [2/2]

__global__ void Kernels::cuFill_Small_Phi ( const unsigned int na,
Complex * smallPhi,
Complex * Phi )

Copies necessary (2*4*kvol) elements of Phi into a vector variable.

Parameters
naflavour index
smallPhiThe partitioned output
PhiThe pseudofermion field
Postcondition
Result written into smallPhi

Definition at line 76 of file cusu2hmc.cu.

77{
78 //BIG and small phi index
79 const unsigned int gsize = gridDim.x*gridDim.y*gridDim.z;
80 const unsigned int bsize = blockDim.x*blockDim.y*blockDim.z;
81 const unsigned int blockId = blockIdx.x+ blockIdx.y * gridDim.x+ gridDim.x * gridDim.y * blockIdx.z;
82 const unsigned int bthreadId= (threadIdx.z * blockDim.y+ threadIdx.y)* blockDim.x+ threadIdx.x;
83 const unsigned int gthreadId= blockId * bsize+bthreadId;
84
85 for(unsigned int i = gthreadId; i<kvol;i+=gsize*bsize)
86 for(unsigned short idirac = 0; idirac<ndirac; idirac++)
87 for(unsigned short ic= 0; ic<nc; ic++)
88 // PHI_index=i*16+j*2+k;
89 smallPhi[i + kvol * (ic + nc * idirac)] = Phi[i + kvol * (ic + nc * (idirac + ngorkov * na))];
90}
#define nc
Colours.
Definition sizes.h:182
#define ngorkov
Gor'kov indices.
Definition sizes.h:190
#define ndirac
Dirac indices.
Definition sizes.h:186

References Complex, kvol, nc, ndirac, and ngorkov.

Here is the caller graph for this function:

◆ cuMixed_Sumto()

void cuMixed_Sumto ( double * d,
float * f,
const unsigned int n,
const dim3 dimGrid,
const dim3 dimBlock )

Add a single to a double value, and save the output in the double array For complex valued arrays, one may cast the complex<double> and complex<float> arrays to double and float arrays, and use 2N for the array length instead.

Parameters
[in,out]dDouble array
[in]ffloat array
[in]nArray lengths
[in]dimGrid,dimBlockCUDA grid/block
Postcondition
d now contains the sum. (i.e. result is stored in place)

Definition at line 769 of file cumatrices.cu.

769 {
771 return;
772}
__global__ void Mixed_Sumto(double *d, float *f, const unsigned int n)
Sums a float array into a double array.

References dimBlock, dimGrid, and Kernels::Mixed_Sumto().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ cuReal_convert()

void cuReal_convert ( float * a,
double * b,
const unsigned int len,
const bool dtof,
dim3 dimBlock,
dim3 dimGrid )

takes an array of real-valued float and double precision numbers and converts the precision

Parameters
[in,out]aFloat array
[in,out]bDouble array
[in]lenNumber of elements to convert
[in]dtofIf true, convert double to float. Otherwise convert float to double
[in]dimGrid,dimBlockCUDA grid/block size
Postcondition
Depending on the value of dtof, either the contents of a or b are overwritten with those of the other array in the opposite precision.

Definition at line 280 of file cusu2hmc.cu.

280 {
281 const char *funcname = "cuComplex_convert";
283}

References dimBlock, dimGrid, and Kernels::Real_convert().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ cureduce_sum_d()

double cureduce_sum_d ( double * input,
const unsigned int n,
const unsigned short stream )

Sum all terms in an array of doubles.

Parameters
[in]inputInput array
[in]nNumber of terms
[in]streamWhat stream to use (useful for simultaneous reductions)
Returns
Sum of all terms in input

Definition at line 587 of file cumatrices.cu.

587 {
588 const unsigned int bsize=256;
589 unsigned int gsize=(n + (2 * bsize) - 1) / (2 * bsize);
590 double *cachein, *cacheout;
591 cudaMallocAsync(&cacheout,gsize*sizeof(double),streams[stream]);
592 Kernels::reduce_sum<double,bsize><<<gsize,bsize,bsize*sizeof(double),streams[stream]>>>(input,cacheout,n);
593 while(gsize>1){
594 cudaMallocAsync(&cachein,gsize*sizeof(double),streams[stream]);
595 cudaMemcpyAsync(cachein,cacheout,gsize*sizeof(double),cudaMemcpyDefault,streams[stream]);
596 cudaFreeAsync(cacheout,streams[stream]);
597 gsize>>=1;
598 cudaMallocAsync(&cacheout,gsize*sizeof(double),streams[stream]);
599 Kernels::reduce_sum<double,bsize><<<gsize,bsize,bsize*sizeof(double),streams[stream]>>>(cachein,cacheout,gsize);
600 cudaFreeAsync(cachein,streams[stream]);
601 }
602 double output=0;
603 cudaStreamSynchronize(streams[stream]);
604 cudaMemcpyAsync(&output,cacheout,sizeof(double),cudaMemcpyDefault,streams[stream]);
605 cudaStreamSynchronize(streams[stream]);
606 cudaFreeAsync(cacheout,streams[stream]);
607 return output;
608}
__global__ void reduce_sum(T *g_in_data, T *g_out_data, const unsigned int n)
Performs a block reduction for sum.
cudaStream_t streams[ndirac *ndim *nadj]
An array of concurrent GPU streams to keep it busy.
Definition cusu2hmc.cu:29

References Kernels::reduce_sum(), and streams.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ cureduce_sum_f()

float cureduce_sum_f ( float * input,
const unsigned int n,
const unsigned short stream )

Sum all terms in an array of floats.

Parameters
[in]inputInput array
[in]nNumber of terms
[in]streamWhat stream to use (useful for simultaneous reductions)
Returns
Sum of all terms in input

References Complex, Complex_f, dimBlock, and dimGrid.

◆ cuReunitarise() [1/2]

void cuReunitarise ( Complex * ut[2],
dim3 dimGrid,
dim3 dimBlock )

Reunitarises u11t and u12t as in conj(u11t[i])*u11t[i]+conj(u12t[i])*u12t[i]=1.

If you're looking at the FORTRAN code be careful. There are two header files for the /trial/ header. One with u11 u12 (which was included here originally) and the other with u11t and u12t.

Parameters
[in,out]utTrial fields to be reunitarised
[in]dimGrid,dimBlockCUDA grid/block size
Postcondition
ut replaced with reunitarised gauge fields

Definition at line 294 of file cusu2hmc.cu.

294 {
297}
__global__ void cuReunitarise(complex< T > *u11t, complex< T > *u12t)
Reunitarises u11t and u12t as in conj(u11t[i])*u11t[i]+conj(u12t[i])*u12t[i]=1.
Definition cusu2hmc.cu:129
#define cudaDeviceSynchronise()
Get rid of that bastardised yankee English.
Definition sizes.h:53

References Complex, cudaDeviceSynchronise, Kernels::cuReunitarise(), dimBlock, and dimGrid.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ cuReunitarise() [2/2]

template<typename T>
__global__ void Kernels::cuReunitarise ( complex< T > * u11t,
complex< T > * u12t )

Reunitarises u11t and u12t as in conj(u11t[i])*u11t[i]+conj(u12t[i])*u12t[i]=1.

If you're looking at the FORTRAN code be careful. There are two header files for the /trial/ header. One with u11 u12 (which was included here originally) and the other with u11t and u12t.

Parameters
[in,out]u11t,u12tTrial fields to be reunitarised
Postcondition
u11t and u12t replaced with reunitarised gauge fields

Definition at line 129 of file cusu2hmc.cu.

129 {
130 /*
131 * Reunitarises u11t and u12t as in conj(u11t[i])*u11t[i]+conj(u12t[i])*u12t[i]=1
132 *
133 * If you're looking at the FORTRAN code be careful. There are two header files
134 * for the /trial/ header. One with u11 u12 (which was included here originally)
135 * and the other with u11t and u12t.
136 *
137 * Globals:
138 * =======
139 * u11t, u12t
140 *
141 * Returns:
142 * ========
143 * Zero on success, integer error code otherwise
144 */
145 const unsigned int gsize = gridDim.x*gridDim.y*gridDim.z;
146 const unsigned int bsize = blockDim.x*blockDim.y*blockDim.z;
147 const unsigned int blockId = blockIdx.x+ blockIdx.y * gridDim.x+ gridDim.x * gridDim.y * blockIdx.z;
148 const unsigned int bthreadId= (threadIdx.z * blockDim.y+ threadIdx.y)* blockDim.x+ threadIdx.x;
149 const unsigned int gthreadId= blockId * bsize+bthreadId;
150 for(unsigned int i=gthreadId; i<kvol*ndim; i+=gsize*bsize){
151 //Declaring anorm inside the loop will hopefully let the compiler know it
152 //is safe to vectorise aggessively
153 double anorm=sqrt(conj(u11t[i])*u11t[i]+conj(u12t[i])*u12t[i]).real();
154 // Exception handling code. May be faster to leave out as the exit prevents vectorisation.
155 // if(anorm==0){
156 // fprintf(stderr, "Error %i in %s on rank %i: anorm = 0 for μ=%i and i=%i.\nExiting...\n\n",
157 // DIVZERO, funcname, rank, mu, i);
158 // MPI_Finalise();
159 // exit(DIVZERO);
160 // }
161 u11t[i]/=anorm;
162 u12t[i]/=anorm;
163 }
164}
__device__ __forceinline__ T conj(const T &z)
Complex Conjugation.
Definition cusu2hmc.cu:33
#define ndim
Dimensions.
Definition sizes.h:188

References conj(), kvol, and ndim.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ cuTranspose_c()

void cuTranspose_c ( Complex_f * out,
const int fast_in,
const int fast_out,
const dim3 dimGrid,
const dim3 dimBlock )

In place transpose used to convert from AoS to SoA memory layout.

Parameters
[in,out]outThe array being transposed
[in]fast_inThe old outermost/fastest index
[in]fast_outThe new outermost/fastest index
[in]dimGridCUDA grid layout
[in]dimBlockCUDA block layout
Postcondition
Result overwrites existing out with transposed array

Definition at line 732 of file cumatrices.cu.

732 {
733 Complex_f *holder;
734 cudaMalloc((void **)&holder,fast_in*fast_out*sizeof(Complex_f));
735 cudaMemcpy(holder,out,fast_in*fast_out*sizeof(Complex_f),cudaMemcpyDefault);
736 Kernels::Transpose<<<dimGrid,dimBlock>>>(out,holder,fast_in,fast_out);
738 cudaFree(holder);
739}
__global__ void Transpose(T *out, const T *in, const int fast_in, const int fast_out)
Swaps the order of the gauge field so that it is now SoA instead of AoS and it is nice and coalesced ...

References Complex_f, cudaDeviceSynchronise, dimBlock, dimGrid, and Kernels::Transpose().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ cuTranspose_d()

void cuTranspose_d ( double * out,
const int fast_in,
const int fast_out,
const dim3 dimGrid,
const dim3 dimBlock )

In place transpose used to convert from AoS to SoA memory layout.

Parameters
[in,out]outThe array being transposed
[in]fast_inThe old outermost/fastest index
[in]fast_outThe new outermost/fastest index
[in]dimGridCUDA grid layout
[in]dimBlockCUDA block layout
Postcondition
Result overwrites existing out with transposed array

Definition at line 740 of file cumatrices.cu.

740 {
741 double *holder;
742 cudaMalloc((void **)&holder,fast_in*fast_out*sizeof(double));
743 cudaMemcpy(holder,out,fast_in*fast_out*sizeof(double),cudaMemcpyDefault);
744 Kernels::Transpose<<<dimGrid,dimBlock>>>(out,holder,fast_in,fast_out);
745 cudaFree(holder);
746}

References dimBlock, dimGrid, and Kernels::Transpose().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ cuTranspose_f()

void cuTranspose_f ( float * out,
const int fast_in,
const int fast_out,
const dim3 dimGrid,
const dim3 dimBlock )

In place transpose used to convert from AoS to SoA memory layout.

Parameters
[in,out]outThe array being transposed
[in]fast_inThe old outermost/fastest index
[in]fast_outThe new outermost/fastest index
[in]dimGridCUDA grid layout
[in]dimBlockCUDA block layout
Postcondition
Result overwrites existing out with transposed array

Definition at line 747 of file cumatrices.cu.

747 {
748 float *holder;
749 cudaMalloc((void **)&holder,fast_in*fast_out*sizeof(float));
750 cudaMemcpy(holder,out,fast_in*fast_out*sizeof(float),cudaMemcpyDefault);
751 Kernels::Transpose<<<dimGrid,dimBlock>>>(out,holder,fast_in,fast_out);
752 cudaFree(holder);
753}

References dimBlock, dimGrid, and Kernels::Transpose().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ cuTranspose_I()

void cuTranspose_I ( int * out,
const int fast_in,
const int fast_out,
const dim3 dimGrid,
const dim3 dimBlock )

In place transpose used to convert from AoS to SoA memory layout.

Parameters
[in,out]outThe array being transposed
[in]fast_inThe old outermost/fastest index
[in]fast_outThe new outermost/fastest index
[in]dimGridCUDA grid layout
[in]dimBlockCUDA block layout
Postcondition
Result overwrites existing out with transposed array

Definition at line 754 of file cumatrices.cu.

754 {
755 int *holder;
756 cudaMalloc((void **)&holder,fast_in*fast_out*sizeof(int));
757 cudaMemcpy(holder,out,fast_in*fast_out*sizeof(int),cudaMemcpyDefault);
758 Kernels::Transpose<<<dimGrid,dimBlock>>>(out,holder,fast_in,fast_out);
759 cudaFree(holder);
760}

References dimBlock, dimGrid, and Kernels::Transpose().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ cuTranspose_U()

void cuTranspose_U ( unsigned int * out,
const int fast_in,
const int fast_out,
const dim3 dimGrid,
const dim3 dimBlock )

In place transpose used to convert from AoS to SoA memory layout.

Parameters
[in,out]outThe array being transposed
[in]fast_inThe old outermost/fastest index
[in]fast_outThe new outermost/fastest index
[in]dimGridCUDA grid layout
[in]dimBlockCUDA block layout
Postcondition
Result overwrites existing out with transposed array

Definition at line 761 of file cumatrices.cu.

761 {
762 unsigned int *holder;
763 cudaMalloc((void **)&holder,fast_in*fast_out*sizeof(unsigned int));
764 cudaMemcpy(holder,out,fast_in*fast_out*sizeof(unsigned int),cudaMemcpyDefault);
765 Kernels::Transpose<<<dimGrid,dimBlock>>>(out,holder,fast_in,fast_out);
766 cudaFree(holder);
767}

References dimBlock, dimGrid, and Kernels::Transpose().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ cuTranspose_z()

void cuTranspose_z ( Complex * out,
const int fast_in,
const int fast_out,
const dim3 dimGrid,
const dim3 dimBlock )

In place transpose used to convert from AoS to SoA memory layout.

Parameters
[in,out]outThe array being transposed
[in]fast_inThe old outermost/fastest index
[in]fast_outThe new outermost/fastest index
[in]dimGridCUDA grid layout
[in]dimBlockCUDA block layout
Postcondition
Result overwrites existing out with transposed array

Definition at line 725 of file cumatrices.cu.

725 {
726 Complex *holder;
727 cudaMalloc((void **)&holder,fast_in*fast_out*sizeof(Complex));
728 cudaMemcpy(holder,out,fast_in*fast_out*sizeof(Complex),cudaMemcpyDefault);
729 Kernels::Transpose<<<dimGrid,dimBlock>>>(out,holder,fast_in,fast_out);
730 cudaFree(holder);
731}

References Complex, dimBlock, dimGrid, and Kernels::Transpose().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ cuUpDownPart() [1/2]

void cuUpDownPart ( const unsigned int na,
Complex * X0,
Complex * R1,
dim3 dimBlock,
dim3 dimGrid )

Up/Down partitioning of the pseudofermion field.

Parameters
[in]naFlavour index
[out]X0Partitioned field
[in]R1Full pseudofermion field
[in]dimGrid,dimBlockCUDA grid/block size
Postcondition
Result written into X0

Definition at line 291 of file cusu2hmc.cu.

291 {
293}
__global__ void cuUpDownPart(const unsigned int na, Complex *X0, Complex *R1)
Up/Down partitioning of the pseudofermion field.
Definition cusu2hmc.cu:101

References Complex, Kernels::cuUpDownPart(), dimBlock, and dimGrid.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ cuUpDownPart() [2/2]

__global__ void Kernels::cuUpDownPart ( const unsigned int na,
Complex * X0,
Complex * R1 )

Up/Down partitioning of the pseudofermion field.

Parameters
[in]naFlavour index
[out]X0Partitioned field
[in]R1Full pseudofermion field
Postcondition
Result written to X0

Definition at line 101 of file cusu2hmc.cu.

101 {
102
103 const unsigned int gsize = gridDim.x*gridDim.y*gridDim.z;
104 const unsigned int bsize = blockDim.x*blockDim.y*blockDim.z;
105 const unsigned int blockId = blockIdx.x+ blockIdx.y * gridDim.x+ gridDim.x * gridDim.y * blockIdx.z;
106 const unsigned int bthreadId= (threadIdx.z * blockDim.y+ threadIdx.y)* blockDim.x+ threadIdx.x;
107 const unsigned int gthreadId= blockId * bsize+bthreadId;
108 //Up/down partitioning (using only pseudofermions of flavour 1)
109 for(unsigned int i = gthreadId; i<kvol;i+=gsize*bsize)
110 for(unsigned short idirac = 0; idirac < ndirac; idirac++){
111 //R1 has ngorkov spinors, but we only want the first four.
112 X0[i+kvol*(0+nc*(idirac+ndirac*na))]=R1[i+kvol*(0+nc*idirac)];
113 X0[i+kvol*(1+nc*(idirac+ndirac*na))]=R1[i+kvol*(1+nc*idirac)];
114 }
115}

References Complex, kvol, nc, and ndirac.

Here is the caller graph for this function:

◆ Fill_Small_Phi()

int Fill_Small_Phi ( int na,
Complex * smallPhi,
Complex * Phi )
inline

Copies necessary (2*4*kvol) elements of Phi into a vector variable.

Parameters
[in]naflavour index
[out]smallPhiThe partitioned output
[in]PhiThe pseudofermion field
Returns
Zero on success, integer error code otherwise
Postcondition
Result written into smallPhi

Definition at line 311 of file su2hmc.c.

312{
313 const char funcname[] = "Fill_Small_Phi";
314 //BIG and small phi index
315#ifdef USE_GPU
316 cuFill_Small_Phi(na,smallPhi,Phi,dimBlock,dimGrid);
317#else
318#pragma omp parallel for simd aligned(smallPhi,Phi:AVX) collapse(3)
319 for(unsigned int i = 0; i<kvol;i++)
320 for(unsigned short idirac = 0; idirac<ndirac; idirac++)
321 for(unsigned short ic= 0; ic<nc; ic++)
322 // PHI_index=i*16+j*2+k;
323 smallPhi[i+kvol*(ic+nc*idirac)]=Phi[i+kvol*(ic+nc*(idirac+ngorkov*na))];
324#endif
325 return 0;
326}
void cuFill_Small_Phi(const unsigned int na, Complex *smallPhi, Complex *Phi, dim3 dimBlock, dim3 dimGrid)
Copies necessary (2*4*kvol) elements of Phi into a vector variable.
Definition cusu2hmc.cu:288

References Complex, cuFill_Small_Phi(), dimBlock, dimGrid, kvol, nc, ndirac, and ngorkov.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ Gather()

template<typename T>
__global__ void Kernels::Gather ( T * x,
T * y,
const unsigned int n,
unsigned int * table,
const unsigned short mu )

Extracts all the single precision gauge links in the \(\mu\) direction only.

Parameters
[out]xThe output
[in]yThe gauge field for a particular colour
[in]nNumber of sites in the gauge field. This is typically kvol
[in]tableTable containing information on nearest neighbours. Usually id or iu
[in]muDirection we're interested in extracting

Definition at line 116 of file cuforce.cu.

117 {
118 //FORTRAN had a second parameter m giving the size of y (kvol+halo) normally
119 //Pointers mean that's not an issue for us so I'm leaving it out
120 const unsigned int gsize = gridDim.x*gridDim.y*gridDim.z;
121 const unsigned int bsize = blockDim.x*blockDim.y*blockDim.z;
122 const unsigned int blockId = blockIdx.x+ blockIdx.y * gridDim.x+ gridDim.x * gridDim.y * blockIdx.z;
123 const unsigned int bthreadId= (threadIdx.z * blockDim.y+ threadIdx.y)* blockDim.x+ threadIdx.x;
124 const unsigned int gthreadId= blockId * bsize+bthreadId;
125 const unsigned int kvbmu=kvolHalo*mu;
126 for(unsigned int i = gthreadId; i<kvol;i+=gsize*bsize)
127 x[i]=y[table[i+kvbmu]+kvbmu];
128 }

References kvol, and kvolHalo.

Here is the caller graph for this function:

◆ Init()

int Init ( const int istart,
const int ibound,
const int iread,
const float beta,
const float fmu,
const float akappa,
const Complex_f ajq,
const float c_sw,
Complex * u[2],
Complex * ut[2],
Complex_f * ut_f[2],
Complex gamval[20],
Complex_f gamval_f[20],
unsigned short gamin[16],
double * dk[2],
float * dk_f[2],
unsigned int * iu,
unsigned int * id )

Initialises the system.

Parameters
[in]istartZero for cold, >1 for hot, <1 for none
[in]iboundPeriodic boundary conditions
[in]ireadRead configuration from file
[in]betaInverse gauge coupling
[in]fmuChemical potential
[in]akappaHopping parameter
[in]ajqDiquark source
[in]c_swClover coefficient
[out]uGauge fields
[out]ut,ut_fDouble/float Trial gauge field
[out]dk,dk_f\(\left(1+\gamma_0\right)e^{-\mu}\) and \(\left(1-\gamma_0\right)^\mu\)
[out]iu,idUp halo indices
[out]gamval,gamval_fDouble/float precision gamma matrices rescaled by kappa
[out]gaminGamma matrix indices
Returns
Zero on success, integer error code otherwise
Postcondition
Contents of all out arguments overwritten

Definition at line 10 of file su2hmc.c.

13 {
14 const char funcname[] = "Init";
15
16#ifdef _OPENMP
17 omp_set_num_threads(nthreads);
18#ifdef __USE_MKL__
19 mkl_set_num_threads(nthreads);
20#endif
21#endif
22 //First things first, calculate a few constants for coordinates
23 Addrc(iu, id);
24 //And confirm they're legit
27#ifdef _DEBUG
28 printf("Checked addresses\n");
29#endif
30 double chem1=exp(-fmu); double chem2 = 1/chem1;
31 //CUDA this. Only limit will be the bus speed
32#pragma omp parallel for simd //aligned(dk[0],dk[1]:AVX)
33 for(unsigned int i = 0; i<kvol; i++){
34 dk[0][i]=akappa*chem1; dk[1][i]=akappa*chem2;
35 }
36 //Anti periodic Boundary Conditions. Flip the terms at the edge of the time
37 //direction
38 if(ibound == -1 && pcoord[3+ndim*rank]==npt-1){
39#ifdef _DEBUG
40 printf("Implementing antiperiodic boundary conditions on rank %i\n", rank);
41#endif
42#pragma omp parallel for simd //aligned(dk[0],dk[1]:AVX)
43 for(unsigned int k= kvol-1; k>=kvol-kvol3; k--){
44 //int k = kvol - kvol3 + i;
45 dk[1][k]*=-1;
46 dk[0][k]*=-1;
47 }
48 }
49 //These are constant so swap the halos when initialising and be done with it
50 //May need to add a synchronisation statement here first
51#if(npt>1)
52 DHalo_swap_dir(dk[1], 1, 3, UP);
53 DHalo_swap_dir(dk[0], 1, 3, UP);
54#endif
55 //Float versions
56#ifdef USE_GPU
57 cuReal_convert(dk_f[1],dk[1],kvol+halo,true,dimBlock,dimGrid);
58 cuReal_convert(dk_f[0],dk[0],kvol+halo,true,dimBlock,dimGrid);
59#else
60#pragma omp parallel for simd //aligned(dk[0],dk[1],dk_f[0],dk_f[1]:AVX)
61 for(unsigned int i=0;i<kvol+halo;i++){
62 dk_f[1][i]=(float)dk[1][i];
63 dk_f[0][i]=(float)dk[0][i];
64 }
65#endif
66 //What row of each dirac/sigma matrix contains the entry acting on element i of the spinor
67 unsigned short __attribute__((aligned(AVX))) gamin_t[4][4] = {{3,2,1,0},{3,2,1,0},{2,3,0,1},{2,3,0,1}};
68 //Gamma Matrices in Chiral Representation
69 //See Appendix 8.1.2 of Montvay and Munster
70 //_t is for temp. We copy these into the real gamvals later
71#ifdef USE_GPU
72 cudaMemcpy(gamin,gamin_t,4*4*sizeof(short),cudaMemcpyHostToDevice);
73#else
74 memcpy(gamin,gamin_t,4*4*sizeof(short));
75#endif
76 //Each row of the dirac matrix contains only one non-zero entry, so that's all we encode here
77 Complex __attribute__((aligned(AVX))) gamval_t[5][4] = {{-I,-I,I,I},{-1,1,1,-1},{-I,I,I,-I},{1,1,1,1},{1,1,-1,-1}};
78 //Each gamma matrix is rescaled by akappa by flattening the gamval array
79#if defined USE_BLAS
80 //Don't cuBLAS this. It is small and won't saturate the GPU. Let the CPU handle
81 //it and just copy it later
82 cblas_zdscal(5*4, akappa, gamval_t, 1);
83#else
84#pragma omp parallel for simd collapse(2) aligned(gamval,gamval_f:AVX)
85 for(unsigned short i=0;i<5;i++)
86 for(unsigned short j=0;j<4;j++)
87 gamval_t[i][j]*=akappa;
88#endif
89
90
91#ifdef USE_GPU
92 cudaMemcpy(gamval,gamval_t,5*4*sizeof(Complex),cudaMemcpyHostToDevice);
93 cuComplex_convert(gamval_f,gamval,20,true,dimBlockOne,dimGridOne);
94#else
95 memcpy(gamval,gamval_t,5*4*sizeof(Complex));
96 for(unsigned short i=0;i<5*4;i++)
97 gamval_f[i]=(Complex_f)gamval[i];
98#endif
99
100 if(iread){
101 if(!rank) printf("Calling Par_sread() for configuration: %i\n", iread);
102 Par_sread(iread, beta, fmu, akappa, ajq,c_sw,u[0],u[1],ut[0],ut[1]);
103 Par_ranset(&seed,iread);
104 }
105 else{
106 Par_ranset(&seed,iread);
107 if(istart==0){
108 //Initialise a cold start to zero
109 //memset is safe to use here because zero is zero
110#pragma omp parallel for simd //aligned(ut[0]:AVX)
111 //Leave it to the GPU?
112 for(unsigned int i=0; i<kvol;i++)
113 for(unsigned short mu=0;mu<ndim;mu++){
114 ut[0][i+kvolHalo*mu]=1+0*I; ut[1][i+kvolHalo*mu]=0+0*I;
115 }
116 }
117 else if(istart>0){
118 //Ideally, we can use gsl_ranlux as the PRNG
119#ifdef __RANLUX__
120 for(unsigned int i=0; i<kvol;i++)
121 for(unsigned short mu=0;mu<ndim;mu++){
122 ut[0][i+kvolHalo*mu]=2*(gsl_rng_uniform(ranlux_instd)-0.5+I*(gsl_rng_uniform(ranlux_instd)-0.5));
123 ut[1][i+kvolHalo*mu]=2*(gsl_rng_uniform(ranlux_instd)-0.5+I*(gsl_rng_uniform(ranlux_instd)-0.5));
124 }
125 //Last resort, Numerical Recipes' Ran2
126#else
127 for(unsigned int i=0; i<kvol;i++)
128 for(unsigned short mu=0;mu<ndim;mu++){
129 ut[0][i+kvolHalo*mu]=2*(ran2(&seed)-0.5+I*(ran2(&seed)-0.5));
130 ut[1][i+kvolHalo*mu]=2*(ran2(&seed)-0.5+I*(ran2(&seed)-0.5));
131 }
132#endif
133 }
134 else
135 fprintf(stderr,"Warning %i in %s: Gauge fields are not initialised.\n", NOINIT, funcname);
136
137#ifdef USE_GPU
138 int device=-1;
139 cudaGetDevice(&device);
140 //cudaMemPrefetchAsync(ut[0], ndim*kvol*sizeof(Complex),device,streams[0]);
141 //cudaMemPrefetchAsync(ut[1], ndim*kvol*sizeof(Complex),device,streams[1]);
142#endif
143 //Send trials to accelerator for reunitarisation
144 Reunitarise(ut);
145 //Get trials back
146#ifdef USE_GPU
147#if (nproc>1) //Strided for multi-GPU
148 for(unsigned short mu=0;mu<ndim;mu++){
149 cudaMemcpy(u[0]+kvol*mu, ut[0]+kvolHalo*mu, kvol*sizeof(Complex),cudaMemcpyDefault);
150 cudaMemcpy(u[1]+kvol*mu, ut[1]+kvolHalo*mu, kvol*sizeof(Complex),cudaMemcpyDefault);
151 }
152#else
153 cudaMemcpy(u[0], ut[0], ndim*kvol*sizeof(Complex),cudaMemcpyDefault);
154 cudaMemcpy(u[1], ut[1], ndim*kvol*sizeof(Complex),cudaMemcpyDefault);
155#endif
156#else
157 for(unsigned short mu=0;mu<ndim;mu++){
158 memcpy(u[0]+kvol*mu, ut[0]+kvolHalo*mu, kvol*sizeof(Complex));
159 memcpy(u[1]+kvol*mu, ut[1]+kvolHalo*mu, kvol*sizeof(Complex));
160 }
161#endif
162 }
163#ifdef _DEBUG
164 printf("Initialisation Complete\n");
165#endif
166 return 0;
167}
#define NOINIT
Not initialising the lattice.
Definition errorcodes.h:144
void cuReal_convert(float *a, double *b, const unsigned int len, const bool dtof, dim3 dimBlock, dim3 dimGrid)
takes an array of real-valued float and double precision numbers and converts the precision
Definition cusu2hmc.cu:280
int Reunitarise(Complex *ut[2])
Reunitarises u11t and u12t as in conj(u11t[i])*u11t[i]+conj(u12t[i])*u12t[i]=1.
Definition su2hmc.c:342
int Check_addr(unsigned int *table, int lns, int lnt, int imin, int imax)
Checks that the addresses are within bounds before an update.
Definition coord.c:305
int Addrc(unsigned int *iu, unsigned int *id)
Loads the addresses required during the update.
Definition coord.c:13
int Par_sread(const int iread, const float beta, const float fmu, const float akappa, const Complex_f ajq, const float c_sw, Complex *u11, Complex *u12, Complex *u11t, Complex *u12t)
Reads and assigns the gauges from file.
Definition par_mpi.c:114
int DHalo_swap_dir(double *d, int ncpt, int idir, int layer)
Swaps the halos along the axis given by idir in the direction given by layer.
int Par_ranset(unsigned long *seed, int iread)
Uses the rank to get a new seed. Copying from the FORTRAN description here c create new seeds in rang...
Definition random.c:64
#define UP
Flag for send up.
Definition par_mpi.h:39
int rank
The MPI rank.
Definition par_mpi.c:20
int * pcoord
The processor grid.
Definition par_mpi.c:17
unsigned long seed
RANLUX seed.
Definition random.c:18
gsl_rng * ranlux_instd
RANLUX instance.
Definition random.c:16
#define AVX
Alignment of arrays. 64 for AVX-512, 32 for AVX/AVX2. 16 for SSE. Since AVX is standard on modern x86...
Definition sizes.h:279
#define ksizet
Sublattice t extent.
Definition sizes.h:158
#define nthreads
Number of threads for OpenMP, which can be overwritten at runtime.
Definition sizes.h:144
#define ksize
Sublattice spatial extent for a cubic lattice.
Definition sizes.h:155
dim3 dimBlockOne
block size of one
Definition cusu2hmc.cu:22
dim3 dimGridOne
Grid size of one.
Definition cusu2hmc.cu:23
#define kvol3
Sublattice spatial volume.
Definition sizes.h:165
#define npt
Processor grid t extent.
Definition sizes.h:130
#define I
Define I in double precision using C standard notation.

References Addrc(), AVX, Check_addr(), Complex, Complex_f, cuComplex_convert(), cuReal_convert(), DHalo_swap_dir(), dimBlock, dimBlockOne, dimGrid, dimGridOne, halo, I, ksize, ksizet, kvol, kvol3, kvolHalo, ndim, NOINIT, npt, nthreads, Par_ranset(), Par_sread(), pcoord, rank, ranlux_instd, Reunitarise(), seed, and UP.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ Init_CUDA()

void Init_CUDA ( Complex * u11t,
Complex * u12t,
Complex gamval[20],
Complex_f gamval_f[20],
unsigned short gamin[16],
double * dk4m,
double * dk4p,
unsigned int * iu,
unsigned int * id )

Initialise CUDA cuInit was taken already by CUDA (unsurprisingly).

Parameters
[in]u11t,u12tTrial gauge fields
[in]gamval,gamval_fDouble/float precision gamma matrices rescaled by kappa
[in]gaminGamma matrix indices
[in]dk4m,dk4p\(e^{-\mu}\) and \(e^\mu\)
[in]iu,idUp/lower halo indices
Todo
CUDA 13 changed how setting devices work, so it's not just an integer any more. Those lines are commented out for now. They are not critical. Only hints for unified memory management.

Definition at line 248 of file cusu2hmc.cu.

249 {
250 const char *funcname = "Init_CUDA";
251 int device=-1;
252 cudaGetDevice(&device);
253 //Initialise streams for concurrent kernels
254 for(unsigned int i=0;i<(ndirac*nadj*ndim);i++)
255 cudaStreamCreate(&streams[i]);
256 //Set iu and id to mainly read in CUDA and prefetch them to the GPU
257 //cudaMemPrefetchAsync(iu,ndim*kvol*sizeof(int),device,streams[0]);
258 //cudaMemPrefetchAsync(id,ndim*kvol*sizeof(int),device,streams[1]);
259 //cudaMemAdvise(iu,ndim*kvol*sizeof(int),cudaMemAdviseSetReadMostly,device);
260 //cudaMemAdvise(id,ndim*kvol*sizeof(int),cudaMemAdviseSetReadMostly,device);
261
262 //Gamma matrices and indices on the GPU
263 //cudaMemcpy(gamin_d,gamin,4*4*sizeof(int),cudaMemcpyHostToDevice);
264 //cudaMemcpy(gamval_d,gamval,5*4*sizeof(Complex),cudaMemcpyHostToDevice);
265 //cudaMemcpy(gamval_f_d,gamval_f,5*4*sizeof(Complex_f),cudaMemcpyHostToDevice);
266 //cudaMemAdvise(gamin,4*4*sizeof(int),cudaMemAdviseSetReadMostly,device);
267 //cudaMemAdvise(gamval,5*4*sizeof(Complex),cudaMemAdviseSetReadMostly,device);
268
269 //More prefetching and marking as read-only (mostly)
270 //Prefetching Momentum Fields and Trial Fields to GPU
271 //cudaMemAdvise(dk4p,(kvol+halo)*sizeof(double),cudaMemAdviseSetReadMostly,device);
272 //cudaMemAdvise(dk4m,(kvol+halo)*sizeof(double),cudaMemAdviseSetReadMostly,device);
273
274 //cudaMemPrefetchAsync(dk4p,(kvol+halo)*sizeof(double),device,streams[2]);
275 //cudaMemPrefetchAsync(dk4m,(kvol+halo)*sizeof(double),device,streams[3]);
276
277 //cudaMemPrefetchAsync(u11t, ndim*kvol*sizeof(Complex),device,streams[4]);
278 //cudaMemPrefetchAsync(u12t, ndim*kvol*sizeof(Complex),device,streams[5]);
279}
#define nadj
adjacent spatial indices
Definition sizes.h:184

References Complex, Complex_f, nadj, ndim, ndirac, and streams.

Here is the caller graph for this function:

◆ Mixed_Sumto()

__global__ void Kernels::Mixed_Sumto ( double * d,
float * f,
const unsigned int n )

Sums a float array into a double array.

Parameters
[out]dThe double array
[in]fThe float array
[in]nThe size of the arrays

Definition at line 520 of file cumatrices.cu.

520 {
521 const unsigned int gsize = gridDim.x*gridDim.y*gridDim.z;
522 const unsigned int bsize = blockDim.x*blockDim.y*blockDim.z;
523 const unsigned int blockId = blockIdx.x+ blockIdx.y * gridDim.x+ gridDim.x * gridDim.y * blockIdx.z;
524 const unsigned int bthreadId= (threadIdx.z * blockDim.y+ threadIdx.y)* blockDim.x+ threadIdx.x;
525 const unsigned int gthreadId= blockId * bsize+bthreadId;
526
527 for(unsigned int i=gthreadId; i<n;i+=bsize*gsize)
528 d[i]+=(double)f[i];
529 return;
530 }
Here is the caller graph for this function:

◆ P_allocate()

void P_allocate ( Complex ** p,
Complex ** r,
Complex ** x1,
Complex ** x2,
Complex * clover[2] )

Allocates double precision memory needed for Congradp. Just to improve readability Note that since C does not modify it's arguments, you need to pass a pointer to the pointer you want to assign the memory to. This is similar behaviour to cudaMalloc.

Parameters
[out]pHolder for fermion field during inversion
[out]rResidue vector for conjugate gradient
[out]x1,x2\(M\) and \(M^\dagger M\)
[out]cloverClover Fields
Postcondition
Memory allocated

Definition at line 140 of file congrad.c.

140 {
141#ifdef USE_GPU
142#ifdef _DEBUG
143 cudaMallocManaged((void **)&clover[0], 6*kvol*sizeof(Complex),cudaMemAttachGlobal);
144 cudaMallocManaged((void **)&clover[1], 6*kvol*sizeof(Complex),cudaMemAttachGlobal);
145 cudaMallocManaged((void **)p, kfermHalo*sizeof(Complex), cudaMemAttachGlobal);
146 cudaMallocManaged((void **)r, kferm*sizeof(Complex), cudaMemAttachGlobal);
147 cudaMallocManaged((void **)x1, kfermHalo*sizeof(Complex), cudaMemAttachGlobal);
148 cudaMallocManaged((void **)x2, kferm*sizeof(Complex), cudaMemAttachGlobal);
149#else
150 cudaMallocAsync((void **)&clover[0], 6*kvol*sizeof(Complex),streams[0]);
151 cudaMallocAsync((void **)&clover[1], 6*kvol*sizeof(Complex),streams[1]);
152 cudaMallocAsync((void **)p, kfermHalo*sizeof(Complex),streams[2]);
153 cudaMallocAsync((void **)r, kferm*sizeof(Complex),streams[3]);
154 cudaMallocAsync((void **)x1, kfermHalo*sizeof(Complex),streams[4]);
155 cudaMallocAsync((void **)x2, kferm*sizeof(Complex),streams[5]);
156#endif
158#else
159 clover[0]=(Complex *)aligned_alloc(AVX,6*kvol*sizeof(Complex));
160 clover[1]=(Complex *)aligned_alloc(AVX,6*kvol*sizeof(Complex));
161 *p = aligned_alloc(AVX, kfermHalo*sizeof(Complex));
162 *r = aligned_alloc(AVX, kferm*sizeof(Complex));
163 *x1 = aligned_alloc(AVX, kfermHalo*sizeof(Complex));
164 *x2 = aligned_alloc(AVX, kferm*sizeof(Complex));
165#endif
166}
#define kferm
sublattice size including Gor'kov indices
Definition sizes.h:195
#define kfermHalo
Gor'kov lattice and halo.
Definition sizes.h:236

References AVX, Complex, cudaDeviceSynchronise, kferm, kfermHalo, kvol, and streams.

Here is the caller graph for this function:

◆ P_allocate_f()

void P_allocate_f ( Complex_f ** p_f,
Complex_f ** r_f,
Complex_f ** x1_f,
Complex_f ** x2_f,
Complex_f ** xi_f )

Allocates memory needed for Congradp. Just to improve readability Note that since C does not modify it's arguments, you need to pass a pointer to the pointer you want to assign the memory to. This is similar behaviour to cudaMalloc.

Parameters
[out]p_fHolder for fermion field during inversion
[out]r_fResidue vector for conjugate gradient
[out]x1_f,x2_f\(M\) and \(M^\dagger M\)
[out]xi_fAccumulator array for conjugate gradient
Postcondition
Memory allocated

Definition at line 103 of file congrad.c.

103 {
104#ifdef USE_GPU
105#ifdef _DEBUG
106 cudaMallocManaged((void **)p_f, kfermHalo*sizeof(Complex_f),cudaMemAttachGlobal);
107 cudaMallocManaged((void **)r_f, kferm*sizeof(Complex_f),cudaMemAttachGlobal);
108 cudaMallocManaged((void **)x1_f, kfermHalo*sizeof(Complex_f),cudaMemAttachGlobal);
109 cudaMallocManaged((void **)x2_f, kferm*sizeof(Complex_f),cudaMemAttachGlobal);
110 cudaMallocManaged((void **)xi_f, kferm*sizeof(Complex_f),cudaMemAttachGlobal);
111#else
112 cudaMalloc((void **)p_f, kfermHalo*sizeof(Complex_f));
113 cudaMalloc((void **)r_f, kferm*sizeof(Complex_f));
114 cudaMalloc((void **)x1_f, kfermHalo*sizeof(Complex_f));
115 cudaMalloc((void **)x2_f, kferm*sizeof(Complex_f));
116 cudaMalloc((void **)xi_f, kferm*sizeof(Complex_f));
117#endif
119#else
120 *p_f = aligned_alloc(AVX,kfermHalo*sizeof(Complex_f));
121 *r_f = aligned_alloc(AVX,kferm*sizeof(Complex_f));
122 *x1_f = aligned_alloc(AVX,kfermHalo*sizeof(Complex_f));
123 *x2_f = aligned_alloc(AVX,kferm*sizeof(Complex_f));
124 *xi_f = aligned_alloc(AVX,kferm*sizeof(Complex_f));
125#endif
126}

References AVX, Complex_f, cudaDeviceSynchronise, kferm, and kfermHalo.

Here is the caller graph for this function:

◆ P_free()

void P_free ( Complex ** p,
Complex ** r,
Complex ** x1,
Complex ** x2,
Complex * clover[2] )

Frees memory needed for Congradp. Just to improve readability Note that since C does not modify it's arguments, you need to pass a pointer to the pointer you want to assign the memory to. This is similar behaviour to cudaMalloc.

Parameters
[in,out]pHolder for fermion field during inversion
[in,out]x1,x2\(M\) and \(M^\dagger M\)
[in,out]rResidue vector for conjugate gradient
[in,out]cloverClover fields
Postcondition
Memory freed

Definition at line 263 of file congrad.c.

263 {
264#ifdef USE_GPU
265#ifdef _DEBUG
266 cudaFree(clover[0]); cudaFree(clover[1]);
267 cudaFree(*p);cudaFree(*r);cudaFree(*x1); cudaFree(*x2);
268#else
269 cudaFreeAsync(clover[0],streams[0]); cudaFreeAsync(clover[1],streams[1]);
270 cudaFreeAsync(*p,streams[2]);cudaFreeAsync(*r,streams[3]);cudaFreeAsync(*x1,streams[4]); cudaFreeAsync(*x2,streams[5]);
271#endif
272#else
273 free(*p); free(*r); free(*x1); free(*x2);
274 free(clover[0]); free(clover[1]);
275#endif
276}

References Complex, and streams.

Here is the caller graph for this function:

◆ P_free_f()

void P_free_f ( Complex_f ** p_f,
Complex_f ** r_f,
Complex_f ** x1_f,
Complex_f ** x2_f,
Complex_f ** xi_f )

Frees memory needed for Congradp. Just to improve readability Note that since C does not modify it's arguments, you need to pass a pointer to the pointer you want to assign the memory to. This is similar behaviour to cudaMalloc.

Parameters
[in,out]p_fHolder for fermion field during inversion
[in,out]r_fResidue vector for conjugate gradient
[in,out]x1_f,x2_f\(M\) and \(M^\dagger M\)
[in,out]xi_fConjugate gradient accumulator
Postcondition
Memory freed

Definition at line 243 of file congrad.c.

243 {
244#ifdef USE_GPU
245 cudaFree(*p_f); cudaFree(*r_f);cudaFree(*x1_f); cudaFree(*x2_f); cudaFree(*xi_f);
246#else
247 free(*p_f); free(*r_f); free(*x1_f); free(*x2_f); free(*xi_f);
248#endif
249}

References Complex_f.

Here is the caller graph for this function:

◆ Q_allocate()

void Q_allocate ( Complex ** p,
Complex ** x1,
Complex ** x2,
Complex * clover[2] )

Allocates double precision memory needed for Congradq. Just to improve readability Note that since C does not modify it's arguments, you need to pass a pointer to the pointer you want to assign the memory to. This is similar behaviour to cudaMalloc.

Parameters
[out]pHolder for fermion field during inversion
[out]x1,x2\(M\) and \(M^\dagger M\)
[out]cloverClover Fields
Postcondition
Memory allocated

Definition at line 64 of file congrad.c.

64 {
65 const char funcname[] = "Q_allocate";
66#ifdef USE_GPU
67#ifdef _DEBUG
68 cudaMallocManaged((void **)&clover[0], 6*kvol*sizeof(Complex),cudaMemAttachGlobal);
69 cudaMallocManaged((void **)&clover[1], 6*kvol*sizeof(Complex),cudaMemAttachGlobal);
70 cudaMallocManaged((void **)p, kferm2Halo*sizeof(Complex),cudaMemAttachGlobal);
71 cudaMallocManaged((void **)x1, kferm2Halo*sizeof(Complex),cudaMemAttachGlobal);
72 cudaMallocManaged((void **)x2, kferm2*sizeof(Complex),cudaMemAttachGlobal);
73#else
74 //First two have halo exchanges, so getting NCCL working is important
75 cudaMallocAsync((void **)&clover[0], 6*kvol*sizeof(Complex),streams[0]);
76 cudaMallocAsync((void **)&clover[1], 6*kvol*sizeof(Complex),streams[1]);
77 cudaMallocAsync((void **)p, kferm2Halo*sizeof(Complex),streams[2]);
78 cudaMallocAsync((void **)x1, kferm2Halo*sizeof(Complex),streams[3]);
79 cudaMallocAsync((void **)x2, kferm2*sizeof(Complex),streams[4]);
80#endif
81#else
82 clover[0]=(Complex *)aligned_alloc(AVX,6*kvol*sizeof(Complex));
83 clover[1]=(Complex *)aligned_alloc(AVX,6*kvol*sizeof(Complex));
84 *p=(Complex *)aligned_alloc(AVX,kferm2Halo*sizeof(Complex));
85 *x1=(Complex *)aligned_alloc(AVX,kferm2Halo*sizeof(Complex));
86 *x2=(Complex *)aligned_alloc(AVX,kferm2*sizeof(Complex));
87#endif
88 return;
89}
#define kferm2Halo
Dirac lattice and halo.
Definition sizes.h:238
#define kferm2
sublattice size including Dirac indices
Definition sizes.h:197

References AVX, Complex, kferm2, kferm2Halo, kvol, and streams.

Here is the caller graph for this function:

◆ Q_allocate_f()

void Q_allocate_f ( Complex_f ** p_f,
Complex_f ** x1_f,
Complex_f ** x2_f,
Complex_f ** r_f,
Complex_f ** X1_f )

Allocates memory needed for Congradq. Just to improve readability Note that since C does not modify it's arguments, you need to pass a pointer to the pointer you want to assign the memory to. This is similar behaviour to cudaMalloc.

Parameters
[out]p_fHolder for fermion field during inversion
[out]x1_f,x2_f\(M\) and \(M^\dagger M\)
[out]r_fResidue vector for conjugate gradient
[out]X1_fPseudofermion field
Postcondition
Memory allocated

Definition at line 23 of file congrad.c.

23 {
24 const char funcname[] = "Q_allocate";
25#ifdef USE_GPU
26#ifdef _DEBUG
27 cudaMallocManaged((void **)p_f, kferm2Halo*sizeof(Complex_f),cudaMemAttachGlobal);
28 cudaMallocManaged((void **)x1_f, kferm2Halo*sizeof(Complex_f),cudaMemAttachGlobal);
29 cudaMallocManaged((void **)x2_f, kferm2*sizeof(Complex_f),cudaMemAttachGlobal);
30
31 cudaMallocManaged((void **)r_f, kferm2*sizeof(Complex_f),cudaMemAttachGlobal);
32 cudaMallocManaged((void **)X1_f, kferm2*sizeof(Complex_f),cudaMemAttachGlobal);
33#else
34 //First two have halo exchanges, so getting NCCL working is important
35 cudaMallocAsync((void **)p_f, kferm2Halo*sizeof(Complex_f),streams[0]);
36 cudaMallocAsync((void **)x1_f, kferm2Halo*sizeof(Complex_f),streams[1]);
37 cudaMallocAsync((void **)x2_f, kferm2*sizeof(Complex_f),streams[2]);
38
39 cudaMallocAsync((void **)r_f, kferm2*sizeof(Complex_f),streams[3]);
40 cudaMallocAsync((void **)X1_f, kferm2*sizeof(Complex_f),streams[4]);
41#endif
42#else
43 *p_f=(Complex_f *)aligned_alloc(AVX,kferm2Halo*sizeof(Complex_f));
44 *x1_f=(Complex_f *)aligned_alloc(AVX,kferm2Halo*sizeof(Complex_f));
45 *x2_f=(Complex_f *)aligned_alloc(AVX,kferm2*sizeof(Complex_f));
46
47 *r_f=(Complex_f *)aligned_alloc(AVX,kferm2*sizeof(Complex_f));
48 *X1_f=(Complex_f *)aligned_alloc(AVX,kferm2*sizeof(Complex_f));
49#endif
50 return;
51}

References AVX, Complex_f, kferm2, kferm2Halo, and streams.

Here is the caller graph for this function:

◆ Q_free()

void Q_free ( Complex ** p,
Complex ** x1,
Complex ** x2,
Complex * clover[2] )

Frees double precision memory needed for Congradq. Just to improve readability Note that since C does not modify it's arguments, you need to pass a pointer to the pointer you want to assign the memory to. This is similar behaviour to cudaMalloc.

Parameters
[in,out]pHolder for fermion field during inversion
[in,out]x1,x2\(M\) and \(M^\dagger M\)
[in,out]cloverclover fields
Postcondition
Memory freed

Definition at line 211 of file congrad.c.

211 {
212 const char funcname[] = "Qree";
213#ifdef USE_GPU
214#ifdef _DEBUG
216 cudaFree(*x1);cudaFree(*x2); cudaFree(*p);
217 cudaFree(clover[0]); cudaFree(clover[1]);
218#else
219 //streams match the ones that allocated them.
220 cudaFreeAsync(clover[0],streams[0]); cudaFreeAsync(clover[1],streams[1]);
221 cudaFreeAsync(*p,streams[2]);cudaFreeAsync(*x1,streams[3]);cudaFreeAsync(*x2,streams[4]);
223#endif
224#else
225 free(*x1);free(*x2); free(*p);
226 free(clover[0]); free(clover[1]);
227#endif
228 return;
229}

References Complex, cudaDeviceSynchronise, and streams.

Here is the caller graph for this function:

◆ Q_free_f()

void Q_free_f ( Complex_f ** p_f,
Complex_f ** x1_f,
Complex_f ** x2_f,
Complex_f ** r_f,
Complex_f ** X1_f )

Frees memory needed for Congradq. Just to improve readability Note that since C does not modify it's arguments, you need to pass a pointer to the pointer you want to assign the memory to. This is similar behaviour to cudaMalloc.

Parameters
[in,out]p_fHolder for fermion field during inversion
[in,out]x1_f,x2_f\(M\) and \(M^\dagger M\)
[in,out]r_fResidue vector for conjugate gradient
[in,out]X1_fPseudofermion field
Postcondition
Memory freed

Definition at line 181 of file congrad.c.

181 {
182 const char funcname[] = "Q_free";
183#ifdef USE_GPU
184#ifdef _DEBUG
186 cudaFree(*x1_f);cudaFree(*x2_f); cudaFree(*p_f);
187 cudaFree(*r_f); cudaFree(*X1_f);
188#else
189 //streams match the ones that allocated them.
190 cudaFreeAsync(*p_f,streams[0]);cudaFreeAsync(*x1_f,streams[1]);cudaFreeAsync(*x2_f,streams[2]);
192 cudaFreeAsync(*r_f,streams[3]); cudaFreeAsync(*X1_f,streams[4]);
193#endif
194#else
195 free(*x1_f); free(*x2_f); free(*p_f); free(*r_f);free(*X1_f);
196#endif
197 return;
198}

References Complex_f, cudaDeviceSynchronise, and streams.

Here is the caller graph for this function:

◆ Real_convert()

__global__ void Kernels::Real_convert ( float * a,
double * b,
const unsigned int len,
const bool dtof )

takes an array of real float and double precision numbers and converts the precision

Parameters
[in,out]aFloat array
[in,out]bDouble array
[in]lenNumber of elements to convert
[in]dtofIf true, convert double to float. Otherwise convert float to double
Postcondition
Depending on the value of dtof, either the contents of a or b are overwritten with those of the other array in the opposite precision.

Definition at line 50 of file cusu2hmc.cu.

50 {
51 const unsigned int gsize = gridDim.x*gridDim.y*gridDim.z;
52 const unsigned int bsize = blockDim.x*blockDim.y*blockDim.z;
53 const unsigned int blockId = blockIdx.x+ blockIdx.y * gridDim.x+ gridDim.x * gridDim.y * blockIdx.z;
54 const unsigned int bthreadId= (threadIdx.z * blockDim.y+ threadIdx.y)* blockDim.x+ threadIdx.x;
55 const unsigned int gthreadId= blockId * bsize+bthreadId;
56
57 //True: Convert float to double
58 if(dtof)
59 for(unsigned int i = gthreadId; i<len;i+=gsize*bsize)
60 a[i]=(float)b[i];
61 //False: Convert double to float.
62 else
63 for(unsigned int i = gthreadId; i<len;i+=gsize*bsize)
64 b[i]=(double)a[i];
65}
Here is the caller graph for this function:

◆ reduce_sum()

template<typename T, unsigned int bsize>
__global__ void Kernels::reduce_sum ( T * g_in_data,
T * g_out_data,
const unsigned int n )

Performs a block reduction for sum.

Parameters
[in]g_in_dataThe input global data array
[out]g_out_dataThe output global data array
[in]nThe size of the input array
Postcondition
sum saved in zeroth entry of g_out_data

Definition at line 543 of file cumatrices.cu.

543 {
544 extern __shared__ T sdata[]; // stored in the shared memory
545
546 // Each thread loading one element from global onto shared memory
547 const unsigned short tid = threadIdx.x;
548 unsigned int i = blockIdx.x*(bsize*2) + tid;
549 const unsigned int gridSize = blockDim.x * 2 * gridDim.x;
550 sdata[tid] = 0;
551 while (i < n) {
552 sdata[tid] += g_in_data[i];
553 if (i + bsize < n) {
554 sdata[tid] += g_in_data[i + bsize];
555 }
556 i += gridSize;
557 }
558 __syncthreads();
559
560 // Perform reductions in steps, reducing thread synchronization
561 // CUDA warps aren't guaranteed to be 32, and AMD vary. warpSize from the compiler fixes that.
562 for(unsigned int s=bsize/2;s>=warpSize;s>>=1){
563 if (tid < s)
564 sdata[tid] += sdata[tid + s]; __syncthreads();
565 }
566#if defined(__HIP_PLATFORM_AMD__) || defined(__HIP_PLATFORM_HCC__)
567#define SU2_WARP_MASK 0xffffffffffffffffULL // 64-bit lane mask (HIP/AMD)
568#else
569#define SU2_WARP_MASK 0xffffffffU // 32-bit lane mask (CUDA)
570#endif
571 if (tid < warpSize)
572 //Device::warpReduce_sum<T,bsize>(sdata, tid);
573 {
574 T val = sdata[tid];
575 for (int offset = warpSize/2; offset > 0; offset >>= 1)
576 val += __shfl_down_sync(SU2_WARP_MASK, val, offset);
577 if (tid == 0) sdata[0] = val;
578 }
579
580 if (tid == 0){
581 g_out_data[blockIdx.x] = sdata[0];
582 }
583 }
Here is the caller graph for this function:

◆ Reunitarise()

int Reunitarise ( Complex * ut[2])
inline

Reunitarises u11t and u12t as in conj(u11t[i])*u11t[i]+conj(u12t[i])*u12t[i]=1.

If you're looking at the FORTRAN code be careful. There are two header files for the /trial/ header. One with u11 u12 (which was included here originally) and the other with u11t and u12t.

Parameters
[in,out]utTrial fields to be reunitarised
Returns
Zero on success, integer error code otherwise
Postcondition
ut replaced with reunitarised gauge fields

Definition at line 342 of file su2hmc.c.

342 {
343 const char funcname[] = "Reunitarise";
344#ifdef USE_GPU
346#else
347#pragma omp parallel for simd
348 for(unsigned short mu=0;mu<ndim;mu++)
349 for(unsigned int i=0; i<kvol; i++){
350 //Declaring anorm inside the loop will hopefully let the compiler know it
351 //is safe to vectorise aggressively
352 double anorm=sqrt(conj(ut[0][i+kvolHalo*mu])*ut[0][i+kvolHalo*mu]+conj(ut[1][i+kvolHalo*mu])*ut[1][i+kvolHalo*mu]);
353 ut[0][i+kvolHalo*mu]/=anorm; ut[1][i+kvolHalo*mu]/=anorm;
354 }
355#endif
356 return 0;
357}
void cuReunitarise(Complex *ut[2], dim3 dimGrid, dim3 dimBlock)
Reunitarises u11t and u12t as in conj(u11t[i])*u11t[i]+conj(u12t[i])*u12t[i]=1.
Definition cusu2hmc.cu:294

References Complex, conj(), cuReunitarise(), dimBlock, dimGrid, kvol, kvolHalo, and ndim.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ Transpose()

template<typename T>
__global__ void Kernels::Transpose ( T * out,
const T * in,
const int fast_in,
const int fast_out )

Swaps the order of the gauge field so that it is now SoA instead of AoS and it is nice and coalesced in memory.

Parameters
[out]outThe flipped array
[in]inThe original array
[in]fast_outThe size of the slowest moving dimension. This is the lattice site when read in from disk
[in]fast_inThe size of the fastest moving dimension. This is the direction index when read in from disk.

Definition at line 490 of file cumatrices.cu.

490 {
491 const unsigned int gsize = gridDim.x*gridDim.y*gridDim.z;
492 const unsigned int bsize = blockDim.x*blockDim.y*blockDim.z;
493 const unsigned int blockId = blockIdx.x+ blockIdx.y * gridDim.x+ gridDim.x * gridDim.y * blockIdx.z;
494 const unsigned int bthreadId= (threadIdx.z * blockDim.y+ threadIdx.y)* blockDim.x+ threadIdx.x;
495 const unsigned int gthreadId= blockId * bsize+bthreadId;
496
497 //The if/else here is only to ensure we maximise GPU bandwidth
498 //Typically this is used to write back to the AoS/Coalseced format
499 if(fast_out>fast_in){
500 for(unsigned int x=gthreadId;x<fast_out;x+=gsize*bsize)
501 for(unsigned int y=0; y<fast_in;y++)
502 out[y*fast_out+x]=in[x*fast_in+y];
503 }
504 //Typically this is used to write back to the SoA/saved config format
505 else{
506 for(unsigned int x=0; x<fast_out;x++)
507 for(unsigned int y=gthreadId;y<fast_in;y+=gsize*bsize)
508 out[y*fast_out+x]=in[x*fast_in+y];
509 }
510 }
Here is the caller graph for this function:

◆ Transpose_c()

void Transpose_c ( Complex_f * out,
const int fast_in,
const int fast_out )
inline

In place transpose used to convert from AoS to SoA memory layout.

Parameters
[in,out]outThe array being transposed
[in]fast_inThe old outermost/fastest index
[in]fast_outThe new outermost/fastest index
Postcondition
Result overwrites existing out with transposed array

Definition at line 836 of file matrices.c.

836 {
837 const volatile char funcname[]="Transpose_c";
838
839#ifdef USE_GPU
840 cuTranspose_c(out,fast_in,fast_out,dimGrid,dimBlock);
841#else
842 Complex_f *in = (Complex_f *)aligned_alloc(AVX,fast_in*fast_out*sizeof(Complex_f));
843 memcpy(in,out,fast_in*fast_out*sizeof(Complex_f));
844 //Typically this is used to write back to the AoS/Coalseced format
845 if(fast_out>fast_in){
846 for(int x=0;x<fast_out;x++)
847 for(int y=0; y<fast_in;y++)
848 out[y*fast_out+x]=in[x*fast_in+y];
849 }
850 //Typically this is used to write back to the SoA/saved config format
851 else{
852 for(int x=0; x<fast_out;x++)
853 for(int y=0;y<fast_in;y++)
854 out[y*fast_out+x]=in[x*fast_in+y];
855 }
856 free(in);
857#endif
858}
void cuTranspose_c(Complex_f *out, const int fast_in, const int fast_out, const dim3 dimGrid, const dim3 dimBlock)
In place transpose used to convert from AoS to SoA memory layout.

References AVX, Complex_f, cuTranspose_c(), dimBlock, and dimGrid.

Here is the call graph for this function:

◆ Transpose_d()

void Transpose_d ( double * out,
const int fast_in,
const int fast_out )
inline

In place transpose used to convert from AoS to SoA memory layout.

Parameters
[in,out]outThe array being transposed
[in]fast_inThe old outermost/fastest index
[in]fast_outThe new outermost/fastest index
Postcondition
Result overwrites existing out with transposed array

Definition at line 905 of file matrices.c.

905 {
906 const char funcname[]="Transpose_f";
907
908#ifdef USE_GPU
909 cuTranspose_d(out,fast_in,fast_out,dimGrid,dimBlock);
910#else
911 double *in = (double *)aligned_alloc(AVX,fast_in*fast_out*sizeof(double));
912 memcpy(in,out,fast_in*fast_out*sizeof(double));
913 //Typically this is used to write back to the AoS/Coalseced format
914 if(fast_out>fast_in){
915 for(int x=0;x<fast_out;x++)
916 for(int y=0; y<fast_in;y++)
917 out[y*fast_out+x]=in[x*fast_in+y];
918 }
919 //Typically this is used to write back to the SoA/saved config format
920 else{
921 for(int x=0; x<fast_out;x++)
922 for(int y=0;y<fast_in;y++)
923 out[y*fast_out+x]=in[x*fast_in+y];
924 }
925 free(in);
926#endif
927}
void cuTranspose_d(double *out, const int fast_in, const int fast_out, const dim3 dimGrid, const dim3 dimBlock)
In place transpose used to convert from AoS to SoA memory layout.

References AVX, cuTranspose_d(), dimBlock, and dimGrid.

Here is the call graph for this function:

◆ Transpose_f()

void Transpose_f ( float * out,
const int fast_in,
const int fast_out )
inline

In place transpose used to convert from AoS to SoA memory layout.

Parameters
[in,out]outThe array being transposed
[in]fast_inThe old outermost/fastest index
[in]fast_outThe new outermost/fastest index
Postcondition
Result overwrites existing out with transposed array

Definition at line 882 of file matrices.c.

882 {
883 const char funcname[]="Transpose_f";
884
885#ifdef USE_GPU
886 cuTranspose_f(out,fast_in,fast_out,dimGrid,dimBlock);
887#else
888 float *in = (float *)aligned_alloc(AVX,fast_in*fast_out*sizeof(float));
889 memcpy(in,out,fast_in*fast_out*sizeof(float));
890 //Typically this is used to write back to the AoS/Coalseced format
891 if(fast_out>fast_in){
892 for(int x=0;x<fast_out;x++)
893 for(int y=0; y<fast_in;y++)
894 out[y*fast_out+x]=in[x*fast_in+y];
895 }
896 //Typically this is used to write back to the SoA/saved config format
897 else{
898 for(int x=0; x<fast_out;x++)
899 for(int y=0;y<fast_in;y++)
900 out[y*fast_out+x]=in[x*fast_in+y];
901 }
902 free(in);
903#endif
904}
void cuTranspose_f(float *out, const int fast_in, const int fast_out, const dim3 dimGrid, const dim3 dimBlock)
In place transpose used to convert from AoS to SoA memory layout.

References AVX, cuTranspose_f(), dimBlock, and dimGrid.

Here is the call graph for this function:

◆ Transpose_I()

void Transpose_I ( int * out,
const int fast_in,
const int fast_out )
inline

In place transpose used to convert from AoS to SoA memory layout.

Parameters
[in,out]outThe array being transposed
[in]fast_inThe old outermost/fastest index
[in]fast_outThe new outermost/fastest index
Postcondition
Result overwrites existing out with transposed array

Definition at line 928 of file matrices.c.

928 {
929 const char funcname[]="Transpose_I";
930
931#ifdef USE_GPU
932 cuTranspose_I(out,fast_in,fast_out,dimGrid,dimBlock);
933#else
934 int *in = (int *)aligned_alloc(AVX,fast_in*fast_out*sizeof(int));
935 memcpy(in,out,fast_in*fast_out*sizeof(int));
936 //Typically this is used to write back to the AoS/Coalseced format
937 if(fast_out>fast_in){
938 for(int x=0;x<fast_out;x++)
939 for(int y=0; y<fast_in;y++)
940 out[y*fast_out+x]=in[x*fast_in+y];
941 }
942 //Typically this is used to write back to the SoA/saved config format
943 else{
944 for(int x=0; x<fast_out;x++)
945 for(int y=0;y<fast_in;y++)
946 out[y*fast_out+x]=in[x*fast_in+y];
947 }
948 free(in);
949#endif
950}
void cuTranspose_I(int *out, const int fast_in, const int fast_out, const dim3 dimGrid, const dim3 dimBlock)
In place transpose used to convert from AoS to SoA memory layout.

References AVX, cuTranspose_I(), dimBlock, and dimGrid.

Here is the call graph for this function:

◆ Transpose_U()

void Transpose_U ( unsigned int * out,
const int fast_in,
const int fast_out )
inline

In place transpose used to convert from AoS to SoA memory layout.

Parameters
[in,out]outThe array being transposed
[in]fast_inThe old outermost/fastest index
[in]fast_outThe new outermost/fastest index
Postcondition
Result overwrites existing out with transposed array

Definition at line 951 of file matrices.c.

951 {
952 const char funcname[]="Transpose_I";
953
954#ifdef USE_GPU
955 cuTranspose_U(out,fast_in,fast_out,dimGrid,dimBlock);
956#else
957 unsigned int *in = (unsigned int *)aligned_alloc(AVX,fast_in*fast_out*sizeof(unsigned int));
958 memcpy(in,out,fast_in*fast_out*sizeof(unsigned int));
959 //Typically this is used to write back to the AoS/Coalseced format
960 if(fast_out>fast_in){
961 for(unsigned int x=0;x<fast_out;x++)
962 for(unsigned int y=0; y<fast_in;y++)
963 out[y*fast_out+x]=in[x*fast_in+y];
964 }
965 //Typically this is used to write back to the SoA/saved config format
966 else{
967 for(unsigned int x=0; x<fast_out;x++)
968 for(unsigned int y=0;y<fast_in;y++)
969 out[y*fast_out+x]=in[x*fast_in+y];
970 }
971 free(in);
972#endif
973}
void cuTranspose_U(unsigned int *out, const int fast_in, const int fast_out, const dim3 dimGrid, const dim3 dimBlock)
In place transpose used to convert from AoS to SoA memory layout.

References AVX, cuTranspose_U(), dimBlock, and dimGrid.

Here is the call graph for this function:

◆ Transpose_z()

void Transpose_z ( Complex * out,
const int fast_in,
const int fast_out )
inline

In place transpose used to convert from AoS to SoA memory layout.

Parameters
[in,out]outThe array being transposed
[in]fast_inThe old outermost/fastest index
[in]fast_outThe new outermost/fastest index
Postcondition
Result overwrites existing out with transposed array

Definition at line 859 of file matrices.c.

859 {
860 const volatile char funcname[]="Transpose_c";
861
862#ifdef USE_GPU
863 cuTranspose_z(out,fast_in,fast_out,dimGrid,dimBlock);
864#else
865 Complex *in = (Complex *)aligned_alloc(AVX,fast_in*fast_out*sizeof(Complex));
866 memcpy(in,out,fast_in*fast_out*sizeof(Complex));
867 //Typically this is used to write back to the AoS/Coalseced format
868 if(fast_out>fast_in){
869 for(int x=0;x<fast_out;x++)
870 for(int y=0; y<fast_in;y++)
871 out[y*fast_out+x]=in[x*fast_in+y];
872 }
873 //Typically this is used to write back to the SoA/saved config format
874 else{
875 for(int x=0; x<fast_out;x++)
876 for(int y=0;y<fast_in;y++)
877 out[y*fast_out+x]=in[x*fast_in+y];
878 }
879 free(in);
880#endif
881}
void cuTranspose_z(Complex *out, const int fast_in, const int fast_out, const dim3 dimGrid, const dim3 dimBlock)
In place transpose used to convert from AoS to SoA memory layout.

References AVX, Complex, cuTranspose_z(), dimBlock, and dimGrid.

Here is the call graph for this function:

◆ UpDownPart()

int UpDownPart ( const unsigned int na,
Complex * X0,
Complex * R1 )
inline

Up/Down partitioning of the pseudofermion field.

Parameters
[in]naFlavour index
[out]X0Partitioned field
[in]R1Full pseudofermion field
Returns
Zero on success, integer error code otherwise
Postcondition
Result written into X0

Definition at line 327 of file su2hmc.c.

327 {
328#ifdef USE_GPU
329 cuUpDownPart(na,X0,R1,dimBlock,dimGrid);
331#else
332#pragma omp parallel for simd collapse(2) aligned(X0,R1:AVX)
333 for(unsigned int i=0; i<kvol; i++)
334 for(unsigned short idirac=0;idirac<ndirac;idirac++){
335 //R1 has ngorkov spinors, but we only want the first four.
336 X0[i+kvol*(0+nc*(idirac+ndirac*na))]=R1[i+kvol*(0+nc*idirac)];
337 X0[i+kvol*(1+nc*(idirac+ndirac*na))]=R1[i+kvol*(1+nc*idirac)];
338 }
339#endif
340 return 0;
341}
void cuUpDownPart(const unsigned int na, Complex *X0, Complex *R1, dim3 dimBlock, dim3 dimGrid)
Up/Down partitioning of the pseudofermion field.
Definition cusu2hmc.cu:291

References Complex, cudaDeviceSynchronise, cuUpDownPart(), dimBlock, dimGrid, kvol, nc, and ndirac.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ warpReduce_sum()

template<typename T, unsigned int bsize>
__device__ void Device::warpReduce_sum ( volatile T * sdata,
const unsigned int tid )

Performs a warp reduction for sum.

Parameters
[in,out]sdataThe shared data array
[in]tidThe thread ID
Postcondition
Sum written to zeroth index of sdata

Definition at line 21 of file cumatrices.cu.

21 {
22 if(bsize >= 64) sdata[tid] += sdata[tid + 32];
23 if(bsize >= 32) sdata[tid] += sdata[tid + 16];
24 if(bsize >= 16) sdata[tid] += sdata[tid + 8];
25 if(bsize >= 8) sdata[tid] += sdata[tid + 4];
26 if(bsize >= 4) sdata[tid] += sdata[tid + 2];
27 if(bsize >= 2) sdata[tid] += sdata[tid + 1];
28 }

◆ Z_gather()

int Z_gather ( Complex * x,
Complex * y,
int n,
unsigned int * table,
unsigned int mu )
inline

Extracts all the double precision gauge links in the \(\mu\) direction only.

Parameters
[out]xThe output
[in]yThe gauge field for a particular colour
[in]nNumber of sites in the gauge field. This is typically kvol
[in]tableTable containing information on nearest neighbours. Usually id or iu
[in]muDireciton we're interested in extracting
Returns
Zero on success, integer error code otherwise
Postcondition
Contents of x replaced with output

Definition at line 301 of file su2hmc.c.

302{
303 const char funcname[] = "Z_gather";
304 //FORTRAN had a second parameter m giving the size of y (kvol+halo) normally
305 //Pointers mean that's not an issue for us so I'm leaving it out
306#pragma omp parallel for simd aligned (x,y,table:AVX)
307 for(unsigned int i=0; i<n; i++)
308 x[i]=y[table[i+kvol*mu]+kvolHalo*mu];
309 return 0;
310}

References Complex, kvol, and kvolHalo.