su2hmc
Loading...
Searching...
No Matches
cusu2hmc.cu
Go to the documentation of this file.
1
6#include <cuda_runtime.h>
7#include <su2hmc.h>
14#define MIN(x,y) (x<y?x:y)
21#define MAX(x,y) (x>y?x:y)
22dim3 dimBlockOne = dim3(1,1,1);
23dim3 dimGridOne= dim3(1,1,1);
24//Worst case scenario, each block contains 256 threads. This should be tuned later
25dim3 dimBlock = dim3(1,1,1);
26//dim3 dimBlock = 1;
27dim3 dimGrid= dim3(1,1,1);
28//dim3 dimBlock=dimBlockOne; dim3 dimGrid=dimGridOne;
29cudaStream_t streams[ndirac*ndim*nadj];
30
31//Device function
32template <typename T>
33__device__ __forceinline__ T conj(const T& z){
34 return T(z.real(),-z.imag());
35}
36//CUDA Kernels
37namespace Kernels{
50__global__ void Real_convert(float *a, double *b, const unsigned int len, const bool dtof){
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}
66
76__global__ void cuFill_Small_Phi(const unsigned int na, Complex *smallPhi, Complex *Phi)
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}
91
101__global__ void cuUpDownPart(const unsigned int na, Complex *X0, Complex *R1){
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}
116
128template <typename T>
129__global__ void cuReunitarise(complex<T> *u11t, complex<T> * u12t){
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}
165
176__global__ void cuGauge_Update(const double d, double *pp, Complex *u11t, Complex *u12t,int mu){
177 const unsigned int gsize = gridDim.x*gridDim.y*gridDim.z;
178 const unsigned int bsize = blockDim.x*blockDim.y*blockDim.z;
179 const unsigned int blockId = blockIdx.x+ blockIdx.y * gridDim.x+ gridDim.x * gridDim.y * blockIdx.z;
180 const unsigned int bthreadId= (threadIdx.z * blockDim.y+ threadIdx.y)* blockDim.x+ threadIdx.x;
181 const unsigned int gthreadId= blockId * bsize+bthreadId;
182 for(unsigned int i=gthreadId;i<kvol;i+=gsize*bsize){
183 //Sticking to what was in the FORTRAN for variable names.
184 //CCC for cosine SSS for sine AAA for...
185 //Re-exponentiating the force field. Can be done analytically in SU(2)
186 //using sine and cosine which is nice
187 const unsigned int ind = i+kvol*mu;
188 double AAA = d*sqrt(pp[ind]*pp[ind]\
189 +pp[i+kvol*(1*ndim+mu)]*pp[i+kvol*(1*ndim+mu)]\
190 +pp[i+kvol*(2*ndim+mu)]*pp[i+kvol*(2*ndim+mu)]);
191 double CCC = cos(AAA);
192 double SSS = d*sin(AAA)/AAA;
193 Complex a11 = CCC+I*SSS*pp[i+kvol*(2*ndim+mu)];
194 Complex a12 = pp[i+kvol*(1*ndim+mu)]*SSS + I*SSS*pp[ind];
195 //b11 and b12 are u11t and u12t terms, so we'll use u12t directly
196 //but use b11 for u11t to prevent RAW dependency
197 Complex b11 = u11t[ind];
198 u11t[ind] = a11*b11-a12*conj(u12t[ind]);
199 u12t[ind] = a11*u12t[ind]+a12*conj(b11);
200 }
201}
202}
203
204//Calling functions
205void blockInit(int x, int y, int z, int t, dim3 *dimBlock, dim3 *dimGrid){
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}
248void Init_CUDA(Complex *u11t, Complex *u12t,Complex gamval[20], Complex_f gamval_f[20], unsigned short gamin[16], double*dk4m,\
249 double *dk4p, unsigned int *iu, unsigned int *id){
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}
280void cuReal_convert(float *a, double *b, const unsigned int len, const bool dtof, dim3 dimBlock, dim3 dimGrid){
281 const char *funcname = "cuComplex_convert";
283}
284void cuComplex_convert(Complex_f *a, Complex *b, const unsigned int len, const bool dtof, dim3 dimBlock, dim3 dimGrid){
285 const char *funcname = "cuComplex_convert";
286 Kernels::Real_convert<<<dimGrid,dimBlock>>>((float *)a,(double *)b,2*len,dtof);
287}
288void cuFill_Small_Phi(const unsigned int na, Complex *smallPhi, Complex *Phi, dim3 dimBlock, dim3 dimGrid){
290}
291void cuUpDownPart(const unsigned int na, Complex *X0, Complex *R1,dim3 dimBlock, dim3 dimGrid){
293}
298void cuGauge_Update(const double d, double *pp, Complex *ut[2], dim3 dimGrid, dim3 dimBlock){
299 for(int mu=0;mu<ndim;mu++)
300 Kernels::cuGauge_Update<<<dimGrid,dimBlock,0,streams[mu]>>>(d,pp,ut[0],ut[1],mu);
302}
303
304template __device__ __forceinline__ complex<float> conj(const complex<float>& z);
305template __device__ __forceinline__ complex<double> conj(const complex<double>& z);
#define BLOCKALERT
Alert with block size.
Definition errorcodes.h:161
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.
Definition cusu2hmc.cu:205
__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
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
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).
Definition cusu2hmc.cu:248
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
__device__ __forceinline__ T conj(const T &z)
Complex Conjugation.
Definition cusu2hmc.cu:33
__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
__global__ void cuUpDownPart(const unsigned int na, Complex *X0, Complex *R1)
Up/Down partitioning of the pseudofermion field.
Definition cusu2hmc.cu:101
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
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
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
__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
void cuGauge_Update(const double d, double *pp, Complex *ut[2], dim3 dimGrid, dim3 dimBlock)
CUDA wrapper for the gauge update during the integration step of the HMC.
Definition cusu2hmc.cu:298
__global__ void cuGauge_Update(const double d, double *pp, Complex *u11t, Complex *u12t, int mu)
Gauge update for the integration step of the HMC.
Definition cusu2hmc.cu:176
CUDA Kernels.
Definition cubosonic.cu:47
#define nc
Colours.
Definition sizes.h:182
#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
#define ngorkov
Gor'kov indices.
Definition sizes.h:190
#define nadj
adjacent spatial indices
Definition sizes.h:184
#define kvol
Sublattice volume.
Definition sizes.h:163
#define Complex
Double precision complex number.
Definition sizes.h:64
#define ndirac
Dirac indices.
Definition sizes.h:186
#define cudaDeviceSynchronise()
Get rid of that bastardised yankee English.
Definition sizes.h:53
dim3 dimBlockOne
block size of one
Definition cusu2hmc.cu:22
dim3 dimGridOne
Grid size of one.
Definition cusu2hmc.cu:23
#define Complex_f
Single precision complex number.
Definition sizes.h:62
dim3 dimGrid
Default grid size. First component is normally nt. Second and third depend whatever is needed to get ...
Definition cusu2hmc.cu:27
#define ndim
Dimensions.
Definition sizes.h:188
#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
Function declarations for most of the routines.
cudaStream_t streams[ndirac *ndim *nadj]
An array of concurrent GPU streams to keep it busy.
Definition cusu2hmc.cu:29
#define I
Define I in double precision using C standard notation.