2821e54cbdc53eb90504b4fcfedfba3c811b74a5
[alexxy/gromacs.git] / src / gromacs / mdlib / nbnxn_cuda / nbnxn_cuda.cu
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2012,2013,2014, by the GROMACS development team, led by
5  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6  * and including many others, as listed in the AUTHORS file in the
7  * top-level source directory and at http://www.gromacs.org.
8  *
9  * GROMACS is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * as published by the Free Software Foundation; either version 2.1
12  * of the License, or (at your option) any later version.
13  *
14  * GROMACS is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with GROMACS; if not, see
21  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
23  *
24  * If you want to redistribute modifications to GROMACS, please
25  * consider that scientific software is very special. Version
26  * control is crucial - bugs must be traceable. We will be happy to
27  * consider code for inclusion in the official distribution, but
28  * derived work must not be called official GROMACS. Details are found
29  * in the README & COPYING files - if they are missing, get the
30  * official version at http://www.gromacs.org.
31  *
32  * To help us fund GROMACS development, we humbly ask that you cite
33  * the research papers on the package. Check out http://www.gromacs.org.
34  */
35
36 #include <stdlib.h>
37 #include <assert.h>
38
39 #if defined(_MSVC)
40 #include <limits>
41 #endif
42
43 #include <cuda.h>
44
45 #include "types/simple.h"
46 #include "types/nbnxn_pairlist.h"
47 #include "types/nb_verlet.h"
48 #include "types/ishift.h"
49 #include "types/force_flags.h"
50 #include "../nbnxn_consts.h"
51
52 #ifdef TMPI_ATOMICS
53 #include "thread_mpi/atomic.h"
54 #endif
55
56 #include "nbnxn_cuda_types.h"
57 #include "../../gmxlib/cuda_tools/cudautils.cuh"
58 #include "nbnxn_cuda.h"
59 #include "nbnxn_cuda_data_mgmt.h"
60
61 #if defined TEXOBJ_SUPPORTED && __CUDA_ARCH__ >= 300
62 #define USE_TEXOBJ
63 #endif
64
65 /*! Texture reference for LJ C6/C12 parameters; bound to cu_nbparam_t.nbfp */
66 texture<float, 1, cudaReadModeElementType> nbfp_texref;
67
68 /*! Texture reference for LJ-PME parameters; bound to cu_nbparam_t.nbfp_comb */
69 texture<float, 1, cudaReadModeElementType> nbfp_comb_texref;
70
71 /*! Texture reference for Ewald coulomb force table; bound to cu_nbparam_t.coulomb_tab */
72 texture<float, 1, cudaReadModeElementType> coulomb_tab_texref;
73
74 /* Convenience defines */
75 #define NCL_PER_SUPERCL         (NBNXN_GPU_NCLUSTER_PER_SUPERCLUSTER)
76 #define CL_SIZE                 (NBNXN_GPU_CLUSTER_SIZE)
77
78 /***** The kernels come here *****/
79 #include "nbnxn_cuda_kernel_utils.cuh"
80
81 /* Top-level kernel generation: will generate through multiple inclusion the
82  * following flavors for all kernels:
83  * - force-only output;
84  * - force and energy output;
85  * - force-only with pair list pruning;
86  * - force and energy output with pair list pruning.
87  */
88 /** Force only **/
89 #include "nbnxn_cuda_kernels.cuh"
90 /** Force & energy **/
91 #define CALC_ENERGIES
92 #include "nbnxn_cuda_kernels.cuh"
93 #undef CALC_ENERGIES
94
95 /*** Pair-list pruning kernels ***/
96 /** Force only **/
97 #define PRUNE_NBL
98 #include "nbnxn_cuda_kernels.cuh"
99 /** Force & energy **/
100 #define CALC_ENERGIES
101 #include "nbnxn_cuda_kernels.cuh"
102 #undef CALC_ENERGIES
103 #undef PRUNE_NBL
104
105 /*! Nonbonded kernel function pointer type */
106 typedef void (*nbnxn_cu_kfunc_ptr_t)(const cu_atomdata_t,
107                                      const cu_nbparam_t,
108                                      const cu_plist_t,
109                                      bool);
110
111 /*********************************/
112
113 /* XXX always/never run the energy/pruning kernels -- only for benchmarking purposes */
114 static bool always_ener  = (getenv("GMX_GPU_ALWAYS_ENER") != NULL);
115 static bool never_ener   = (getenv("GMX_GPU_NEVER_ENER") != NULL);
116 static bool always_prune = (getenv("GMX_GPU_ALWAYS_PRUNE") != NULL);
117
118
119 /* Bit-pattern used for polling-based GPU synchronization. It is used as a float
120  * and corresponds to having the exponent set to the maximum (127 -- single
121  * precision) and the mantissa to 0.
122  */
123 static unsigned int poll_wait_pattern = (0x7FU << 23);
124
125 /*! Returns the number of blocks to be used for the nonbonded GPU kernel. */
126 static inline int calc_nb_kernel_nblock(int nwork_units, cuda_dev_info_t *dinfo)
127 {
128     int max_grid_x_size;
129
130     assert(dinfo);
131
132     max_grid_x_size = dinfo->prop.maxGridSize[0];
133
134     /* do we exceed the grid x dimension limit? */
135     if (nwork_units > max_grid_x_size)
136     {
137         gmx_fatal(FARGS, "Watch out, the input system is too large to simulate!\n"
138                   "The number of nonbonded work units (=number of super-clusters) exceeds the"
139                   "maximum grid size in x dimension (%d > %d)!", nwork_units, max_grid_x_size);
140     }
141
142     return nwork_units;
143 }
144
145
146 /* Constant arrays listing all kernel function pointers and enabling selection
147    of a kernel in an elegant manner. */
148
149 /*! Pointers to the non-bonded kernels organized in 2-dim arrays by:
150  *  electrostatics and VDW type.
151  *
152  *  Note that the row- and column-order of function pointers has to match the
153  *  order of corresponding enumerated electrostatics and vdw types, resp.,
154  *  defined in nbnxn_cuda_types.h.
155  */
156
157 /*! Force-only kernel function pointers. */
158 static const nbnxn_cu_kfunc_ptr_t nb_kfunc_noener_noprune_ptr[eelCuNR][evdwCuNR] =
159 {
160     { nbnxn_kernel_ElecCut_VdwLJ_F_cuda,            nbnxn_kernel_ElecCut_VdwLJFsw_F_cuda,            nbnxn_kernel_ElecCut_VdwLJPsw_F_cuda,            nbnxn_kernel_ElecCut_VdwLJEwCombGeom_F_cuda,            nbnxn_kernel_ElecCut_VdwLJEwCombLB_F_cuda            },
161     { nbnxn_kernel_ElecRF_VdwLJ_F_cuda,             nbnxn_kernel_ElecRF_VdwLJFsw_F_cuda,             nbnxn_kernel_ElecRF_VdwLJPsw_F_cuda,             nbnxn_kernel_ElecRF_VdwLJEwCombGeom_F_cuda,             nbnxn_kernel_ElecRF_VdwLJEwCombLB_F_cuda             },
162     { nbnxn_kernel_ElecEwQSTab_VdwLJ_F_cuda,        nbnxn_kernel_ElecEwQSTab_VdwLJFsw_F_cuda,        nbnxn_kernel_ElecEwQSTab_VdwLJPsw_F_cuda,        nbnxn_kernel_ElecEwQSTab_VdwLJEwCombGeom_F_cuda,        nbnxn_kernel_ElecEwQSTab_VdwLJEwCombLB_F_cuda        },
163     { nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJ_F_cuda, nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJFsw_F_cuda, nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJPsw_F_cuda, nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJEwCombGeom_F_cuda, nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJEwCombLB_F_cuda },
164     { nbnxn_kernel_ElecEw_VdwLJ_F_cuda,             nbnxn_kernel_ElecEw_VdwLJFsw_F_cuda,             nbnxn_kernel_ElecEw_VdwLJPsw_F_cuda,             nbnxn_kernel_ElecEw_VdwLJEwCombGeom_F_cuda,             nbnxn_kernel_ElecEw_VdwLJEwCombLB_F_cuda             },
165     { nbnxn_kernel_ElecEwTwinCut_VdwLJ_F_cuda,      nbnxn_kernel_ElecEwTwinCut_VdwLJFsw_F_cuda,      nbnxn_kernel_ElecEwTwinCut_VdwLJPsw_F_cuda,      nbnxn_kernel_ElecEwTwinCut_VdwLJEwCombGeom_F_cuda,      nbnxn_kernel_ElecEwTwinCut_VdwLJEwCombLB_F_cuda      }
166 };
167
168 /*! Force + energy kernel function pointers. */
169 static const nbnxn_cu_kfunc_ptr_t nb_kfunc_ener_noprune_ptr[eelCuNR][evdwCuNR] =
170 {
171     { nbnxn_kernel_ElecCut_VdwLJ_VF_cuda,            nbnxn_kernel_ElecCut_VdwLJFsw_VF_cuda,            nbnxn_kernel_ElecCut_VdwLJPsw_VF_cuda,            nbnxn_kernel_ElecCut_VdwLJEwCombGeom_VF_cuda,            nbnxn_kernel_ElecCut_VdwLJEwCombLB_VF_cuda              },
172     { nbnxn_kernel_ElecRF_VdwLJ_VF_cuda,             nbnxn_kernel_ElecRF_VdwLJFsw_VF_cuda,             nbnxn_kernel_ElecRF_VdwLJPsw_VF_cuda,             nbnxn_kernel_ElecRF_VdwLJEwCombGeom_VF_cuda,             nbnxn_kernel_ElecRF_VdwLJEwCombLB_VF_cuda               },
173     { nbnxn_kernel_ElecEwQSTab_VdwLJ_VF_cuda,        nbnxn_kernel_ElecEwQSTab_VdwLJFsw_VF_cuda,        nbnxn_kernel_ElecEwQSTab_VdwLJPsw_VF_cuda,        nbnxn_kernel_ElecEwQSTab_VdwLJEwCombGeom_VF_cuda,        nbnxn_kernel_ElecEwQSTab_VdwLJEwCombLB_VF_cuda          },
174     { nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJ_VF_cuda, nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJFsw_VF_cuda, nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJPsw_VF_cuda, nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJEwCombGeom_VF_cuda, nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJEwCombLB_VF_cuda     },
175     { nbnxn_kernel_ElecEw_VdwLJ_VF_cuda,             nbnxn_kernel_ElecEw_VdwLJFsw_VF_cuda,             nbnxn_kernel_ElecEw_VdwLJPsw_VF_cuda,             nbnxn_kernel_ElecEw_VdwLJEwCombGeom_VF_cuda,             nbnxn_kernel_ElecEw_VdwLJEwCombLB_VF_cuda               },
176     { nbnxn_kernel_ElecEwTwinCut_VdwLJ_VF_cuda,      nbnxn_kernel_ElecEwTwinCut_VdwLJFsw_VF_cuda,      nbnxn_kernel_ElecEwTwinCut_VdwLJPsw_VF_cuda,      nbnxn_kernel_ElecEwTwinCut_VdwLJEwCombGeom_VF_cuda,      nbnxn_kernel_ElecEwTwinCut_VdwLJEwCombLB_VF_cuda        }
177 };
178
179 /*! Force + pruning kernel function pointers. */
180 static const nbnxn_cu_kfunc_ptr_t nb_kfunc_noener_prune_ptr[eelCuNR][evdwCuNR] =
181 {
182     { nbnxn_kernel_ElecCut_VdwLJ_F_prune_cuda,             nbnxn_kernel_ElecCut_VdwLJFsw_F_prune_cuda,            nbnxn_kernel_ElecCut_VdwLJPsw_F_prune_cuda,            nbnxn_kernel_ElecCut_VdwLJEwCombGeom_F_prune_cuda,            nbnxn_kernel_ElecCut_VdwLJEwCombLB_F_prune_cuda            },
183     { nbnxn_kernel_ElecRF_VdwLJ_F_prune_cuda,              nbnxn_kernel_ElecRF_VdwLJFsw_F_prune_cuda,             nbnxn_kernel_ElecRF_VdwLJPsw_F_prune_cuda,             nbnxn_kernel_ElecRF_VdwLJEwCombGeom_F_prune_cuda,             nbnxn_kernel_ElecRF_VdwLJEwCombLB_F_prune_cuda             },
184     { nbnxn_kernel_ElecEwQSTab_VdwLJ_F_prune_cuda,         nbnxn_kernel_ElecEwQSTab_VdwLJFsw_F_prune_cuda,        nbnxn_kernel_ElecEwQSTab_VdwLJPsw_F_prune_cuda,        nbnxn_kernel_ElecEwQSTab_VdwLJEwCombGeom_F_prune_cuda,        nbnxn_kernel_ElecEwQSTab_VdwLJEwCombLB_F_prune_cuda        },
185     { nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJ_F_prune_cuda,  nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJFsw_F_prune_cuda, nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJPsw_F_prune_cuda, nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJEwCombGeom_F_prune_cuda, nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJEwCombLB_F_prune_cuda },
186     { nbnxn_kernel_ElecEw_VdwLJ_F_prune_cuda,              nbnxn_kernel_ElecEw_VdwLJFsw_F_prune_cuda,             nbnxn_kernel_ElecEw_VdwLJPsw_F_prune_cuda,             nbnxn_kernel_ElecEw_VdwLJEwCombGeom_F_prune_cuda,             nbnxn_kernel_ElecEw_VdwLJEwCombLB_F_prune_cuda             },
187     { nbnxn_kernel_ElecEwTwinCut_VdwLJ_F_prune_cuda,       nbnxn_kernel_ElecEwTwinCut_VdwLJFsw_F_prune_cuda,      nbnxn_kernel_ElecEwTwinCut_VdwLJPsw_F_prune_cuda,      nbnxn_kernel_ElecEwTwinCut_VdwLJEwCombGeom_F_prune_cuda,      nbnxn_kernel_ElecEwTwinCut_VdwLJEwCombLB_F_prune_cuda      }
188 };
189
190 /*! Force + energy + pruning kernel function pointers. */
191 static const nbnxn_cu_kfunc_ptr_t nb_kfunc_ener_prune_ptr[eelCuNR][evdwCuNR] =
192 {
193     { nbnxn_kernel_ElecCut_VdwLJ_VF_prune_cuda,            nbnxn_kernel_ElecCut_VdwLJFsw_VF_prune_cuda,            nbnxn_kernel_ElecCut_VdwLJPsw_VF_prune_cuda,            nbnxn_kernel_ElecCut_VdwLJEwCombGeom_VF_prune_cuda,            nbnxn_kernel_ElecCut_VdwLJEwCombLB_VF_prune_cuda            },
194     { nbnxn_kernel_ElecRF_VdwLJ_VF_prune_cuda,             nbnxn_kernel_ElecRF_VdwLJFsw_VF_prune_cuda,             nbnxn_kernel_ElecRF_VdwLJPsw_VF_prune_cuda,             nbnxn_kernel_ElecRF_VdwLJEwCombGeom_VF_prune_cuda,             nbnxn_kernel_ElecRF_VdwLJEwCombLB_VF_prune_cuda             },
195     { nbnxn_kernel_ElecEwQSTab_VdwLJ_VF_prune_cuda,        nbnxn_kernel_ElecEwQSTab_VdwLJFsw_VF_prune_cuda,        nbnxn_kernel_ElecEwQSTab_VdwLJPsw_VF_prune_cuda,        nbnxn_kernel_ElecEwQSTab_VdwLJEwCombGeom_VF_prune_cuda,        nbnxn_kernel_ElecEwQSTab_VdwLJEwCombLB_VF_prune_cuda        },
196     { nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJ_VF_prune_cuda, nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJFsw_VF_prune_cuda, nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJPsw_VF_prune_cuda, nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJEwCombGeom_VF_prune_cuda, nbnxn_kernel_ElecEwQSTabTwinCut_VdwLJEwCombLB_VF_prune_cuda },
197     { nbnxn_kernel_ElecEw_VdwLJ_VF_prune_cuda,             nbnxn_kernel_ElecEw_VdwLJFsw_VF_prune_cuda,             nbnxn_kernel_ElecEw_VdwLJPsw_VF_prune_cuda,             nbnxn_kernel_ElecEw_VdwLJEwCombGeom_VF_prune_cuda,             nbnxn_kernel_ElecEw_VdwLJEwCombLB_VF_prune_cuda             },
198     { nbnxn_kernel_ElecEwTwinCut_VdwLJ_VF_prune_cuda,      nbnxn_kernel_ElecEwTwinCut_VdwLJFsw_VF_prune_cuda,      nbnxn_kernel_ElecEwTwinCut_VdwLJPsw_VF_prune_cuda,      nbnxn_kernel_ElecEwTwinCut_VdwLJEwCombGeom_VF_prune_cuda,      nbnxn_kernel_ElecEwTwinCut_VdwLJEwCombLB_VF_prune_cuda      }
199 };
200
201 /*! Return a pointer to the kernel version to be executed at the current step. */
202 static inline nbnxn_cu_kfunc_ptr_t select_nbnxn_kernel(int  eeltype,
203                                                        int  evdwtype,
204                                                        bool bDoEne,
205                                                        bool bDoPrune)
206 {
207     nbnxn_cu_kfunc_ptr_t res;
208
209     assert(eeltype < eelCuNR);
210     assert(evdwtype < eelCuNR);
211
212     if (bDoEne)
213     {
214         if (bDoPrune)
215         {
216             res = nb_kfunc_ener_prune_ptr[eeltype][evdwtype];
217         }
218         else
219         {
220             res = nb_kfunc_ener_noprune_ptr[eeltype][evdwtype];
221         }
222     }
223     else
224     {
225         if (bDoPrune)
226         {
227             res = nb_kfunc_noener_prune_ptr[eeltype][evdwtype];
228         }
229         else
230         {
231             res = nb_kfunc_noener_noprune_ptr[eeltype][evdwtype];
232         }
233     }
234
235     return res;
236 }
237
238 /*! Calculates the amount of shared memory required by the CUDA kernel in use. */
239 static inline int calc_shmem_required()
240 {
241     int shmem;
242
243     /* size of shmem (force-buffers/xq/atom type preloading) */
244     /* NOTE: with the default kernel on sm3.0 we need shmem only for pre-loading */
245     /* i-atom x+q in shared memory */
246     shmem  = NCL_PER_SUPERCL * CL_SIZE * sizeof(float4);
247     /* cj in shared memory, for both warps separately */
248     shmem += 2 * NBNXN_GPU_JGROUP_SIZE * sizeof(int);
249 #ifdef IATYPE_SHMEM
250     /* i-atom types in shared memory */
251     shmem += NCL_PER_SUPERCL * CL_SIZE * sizeof(int);
252 #endif
253 #if __CUDA_ARCH__ < 300
254     /* force reduction buffers in shared memory */
255     shmem += CL_SIZE * CL_SIZE * 3 * sizeof(float);
256 #endif
257
258     return shmem;
259 }
260
261 /*! As we execute nonbonded workload in separate streams, before launching
262    the kernel we need to make sure that he following operations have completed:
263    - atomdata allocation and related H2D transfers (every nstlist step);
264    - pair list H2D transfer (every nstlist step);
265    - shift vector H2D transfer (every nstlist step);
266    - force (+shift force and energy) output clearing (every step).
267
268    These operations are issued in the local stream at the beginning of the step
269    and therefore always complete before the local kernel launch. The non-local
270    kernel is launched after the local on the same device/context, so this is
271    inherently scheduled after the operations in the local stream (including the
272    above "misc_ops").
273    However, for the sake of having a future-proof implementation, we use the
274    misc_ops_done event to record the point in time when the above  operations
275    are finished and synchronize with this event in the non-local stream.
276  */
277 void nbnxn_cuda_launch_kernel(nbnxn_cuda_ptr_t        cu_nb,
278                               const nbnxn_atomdata_t *nbatom,
279                               int                     flags,
280                               int                     iloc)
281 {
282     cudaError_t          stat;
283     int                  adat_begin, adat_len; /* local/nonlocal offset and length used for xq and f */
284     /* CUDA kernel launch-related stuff */
285     int                  shmem, nblock;
286     dim3                 dim_block, dim_grid;
287     nbnxn_cu_kfunc_ptr_t nb_kernel = NULL; /* fn pointer to the nonbonded kernel */
288
289     cu_atomdata_t       *adat    = cu_nb->atdat;
290     cu_nbparam_t        *nbp     = cu_nb->nbparam;
291     cu_plist_t          *plist   = cu_nb->plist[iloc];
292     cu_timers_t         *t       = cu_nb->timers;
293     cudaStream_t         stream  = cu_nb->stream[iloc];
294
295     bool                 bCalcEner   = flags & GMX_FORCE_VIRIAL;
296     bool                 bCalcFshift = flags & GMX_FORCE_VIRIAL;
297     bool                 bDoTime     = cu_nb->bDoTime;
298
299     /* turn energy calculation always on/off (for debugging/testing only) */
300     bCalcEner = (bCalcEner || always_ener) && !never_ener;
301
302     /* don't launch the kernel if there is no work to do */
303     if (plist->nsci == 0)
304     {
305         return;
306     }
307
308     /* calculate the atom data index range based on locality */
309     if (LOCAL_I(iloc))
310     {
311         adat_begin  = 0;
312         adat_len    = adat->natoms_local;
313     }
314     else
315     {
316         adat_begin  = adat->natoms_local;
317         adat_len    = adat->natoms - adat->natoms_local;
318     }
319
320     /* When we get here all misc operations issues in the local stream are done,
321        so we record that in the local stream and wait for it in the nonlocal one. */
322     if (cu_nb->bUseTwoStreams)
323     {
324         if (iloc == eintLocal)
325         {
326             stat = cudaEventRecord(cu_nb->misc_ops_done, stream);
327             CU_RET_ERR(stat, "cudaEventRecord on misc_ops_done failed");
328         }
329         else
330         {
331             stat = cudaStreamWaitEvent(stream, cu_nb->misc_ops_done, 0);
332             CU_RET_ERR(stat, "cudaStreamWaitEvent on misc_ops_done failed");
333         }
334     }
335
336     /* beginning of timed HtoD section */
337     if (bDoTime)
338     {
339         stat = cudaEventRecord(t->start_nb_h2d[iloc], stream);
340         CU_RET_ERR(stat, "cudaEventRecord failed");
341     }
342
343     /* HtoD x, q */
344     cu_copy_H2D_async(adat->xq + adat_begin, nbatom->x + adat_begin * 4,
345                       adat_len * sizeof(*adat->xq), stream);
346
347     if (bDoTime)
348     {
349         stat = cudaEventRecord(t->stop_nb_h2d[iloc], stream);
350         CU_RET_ERR(stat, "cudaEventRecord failed");
351     }
352
353     /* beginning of timed nonbonded calculation section */
354     if (bDoTime)
355     {
356         stat = cudaEventRecord(t->start_nb_k[iloc], stream);
357         CU_RET_ERR(stat, "cudaEventRecord failed");
358     }
359
360     /* get the pointer to the kernel flavor we need to use */
361     nb_kernel = select_nbnxn_kernel(nbp->eeltype,
362                                     nbp->vdwtype,
363                                     bCalcEner,
364                                     plist->bDoPrune || always_prune);
365
366     /* kernel launch config */
367     nblock    = calc_nb_kernel_nblock(plist->nsci, cu_nb->dev_info);
368     dim_block = dim3(CL_SIZE, CL_SIZE, 1);
369     dim_grid  = dim3(nblock, 1, 1);
370     shmem     = calc_shmem_required();
371
372     if (debug)
373     {
374         fprintf(debug, "GPU launch configuration:\n\tThread block: %dx%dx%d\n\t"
375                 "Grid: %dx%d\n\t#Super-clusters/clusters: %d/%d (%d)\n",
376                 dim_block.x, dim_block.y, dim_block.z,
377                 dim_grid.x, dim_grid.y, plist->nsci*NCL_PER_SUPERCL,
378                 NCL_PER_SUPERCL, plist->na_c);
379     }
380
381     nb_kernel<<< dim_grid, dim_block, shmem, stream>>> (*adat, *nbp, *plist, bCalcFshift);
382     CU_LAUNCH_ERR("k_calc_nb");
383
384     if (bDoTime)
385     {
386         stat = cudaEventRecord(t->stop_nb_k[iloc], stream);
387         CU_RET_ERR(stat, "cudaEventRecord failed");
388     }
389 }
390
391 void nbnxn_cuda_launch_cpyback(nbnxn_cuda_ptr_t        cu_nb,
392                                const nbnxn_atomdata_t *nbatom,
393                                int                     flags,
394                                int                     aloc)
395 {
396     cudaError_t stat;
397     int         adat_begin, adat_len, adat_end; /* local/nonlocal offset and length used for xq and f */
398     int         iloc = -1;
399
400     /* determine interaction locality from atom locality */
401     if (LOCAL_A(aloc))
402     {
403         iloc = eintLocal;
404     }
405     else if (NONLOCAL_A(aloc))
406     {
407         iloc = eintNonlocal;
408     }
409     else
410     {
411         char stmp[STRLEN];
412         sprintf(stmp, "Invalid atom locality passed (%d); valid here is only "
413                 "local (%d) or nonlocal (%d)", aloc, eatLocal, eatNonlocal);
414         gmx_incons(stmp);
415     }
416
417     cu_atomdata_t   *adat    = cu_nb->atdat;
418     cu_timers_t     *t       = cu_nb->timers;
419     bool             bDoTime = cu_nb->bDoTime;
420     cudaStream_t     stream  = cu_nb->stream[iloc];
421
422     bool             bCalcEner   = flags & GMX_FORCE_VIRIAL;
423     bool             bCalcFshift = flags & GMX_FORCE_VIRIAL;
424
425     /* don't launch copy-back if there was no work to do */
426     if (cu_nb->plist[iloc]->nsci == 0)
427     {
428         return;
429     }
430
431     /* calculate the atom data index range based on locality */
432     if (LOCAL_A(aloc))
433     {
434         adat_begin  = 0;
435         adat_len    = adat->natoms_local;
436         adat_end    = cu_nb->atdat->natoms_local;
437     }
438     else
439     {
440         adat_begin  = adat->natoms_local;
441         adat_len    = adat->natoms - adat->natoms_local;
442         adat_end    = cu_nb->atdat->natoms;
443     }
444
445     /* beginning of timed D2H section */
446     if (bDoTime)
447     {
448         stat = cudaEventRecord(t->start_nb_d2h[iloc], stream);
449         CU_RET_ERR(stat, "cudaEventRecord failed");
450     }
451
452     if (!cu_nb->bUseStreamSync)
453     {
454         /* For safety reasons set a few (5%) forces to NaN. This way even if the
455            polling "hack" fails with some future NVIDIA driver we'll get a crash. */
456         for (int i = adat_begin; i < 3*adat_end + 2; i += adat_len/20)
457         {
458 #ifdef NAN
459             nbatom->out[0].f[i] = NAN;
460 #else
461 #  ifdef _MSVC
462             if (numeric_limits<float>::has_quiet_NaN)
463             {
464                 nbatom->out[0].f[i] = numeric_limits<float>::quiet_NaN();
465             }
466             else
467 #  endif
468             {
469                 nbatom->out[0].f[i] = GMX_REAL_MAX;
470             }
471 #endif
472         }
473
474         /* Set the last four bytes of the force array to a bit pattern
475            which can't be the result of the force calculation:
476            max exponent (127) and zero mantissa. */
477         *(unsigned int*)&nbatom->out[0].f[adat_end*3 - 1] = poll_wait_pattern;
478     }
479
480     /* With DD the local D2H transfer can only start after the non-local
481        has been launched. */
482     if (iloc == eintLocal && cu_nb->bUseTwoStreams)
483     {
484         stat = cudaStreamWaitEvent(stream, cu_nb->nonlocal_done, 0);
485         CU_RET_ERR(stat, "cudaStreamWaitEvent on nonlocal_done failed");
486     }
487
488     /* DtoH f */
489     cu_copy_D2H_async(nbatom->out[0].f + adat_begin * 3, adat->f + adat_begin,
490                       (adat_len)*sizeof(*adat->f), stream);
491
492     /* After the non-local D2H is launched the nonlocal_done event can be
493        recorded which signals that the local D2H can proceed. This event is not
494        placed after the non-local kernel because we first need the non-local
495        data back first. */
496     if (iloc == eintNonlocal)
497     {
498         stat = cudaEventRecord(cu_nb->nonlocal_done, stream);
499         CU_RET_ERR(stat, "cudaEventRecord on nonlocal_done failed");
500     }
501
502     /* only transfer energies in the local stream */
503     if (LOCAL_I(iloc))
504     {
505         /* DtoH fshift */
506         if (bCalcFshift)
507         {
508             cu_copy_D2H_async(cu_nb->nbst.fshift, adat->fshift,
509                               SHIFTS * sizeof(*cu_nb->nbst.fshift), stream);
510         }
511
512         /* DtoH energies */
513         if (bCalcEner)
514         {
515             cu_copy_D2H_async(cu_nb->nbst.e_lj, adat->e_lj,
516                               sizeof(*cu_nb->nbst.e_lj), stream);
517             cu_copy_D2H_async(cu_nb->nbst.e_el, adat->e_el,
518                               sizeof(*cu_nb->nbst.e_el), stream);
519         }
520     }
521
522     if (bDoTime)
523     {
524         stat = cudaEventRecord(t->stop_nb_d2h[iloc], stream);
525         CU_RET_ERR(stat, "cudaEventRecord failed");
526     }
527 }
528
529 /* Atomic compare-exchange operation on unsigned values. It is used in
530  * polling wait for the GPU.
531  */
532 static inline bool atomic_cas(volatile unsigned int *ptr,
533                               unsigned int           oldval,
534                               unsigned int           newval)
535 {
536     assert(ptr);
537
538 #ifdef TMPI_ATOMICS
539     return tMPI_Atomic_cas((tMPI_Atomic_t *)ptr, oldval, newval);
540 #else
541     gmx_incons("Atomic operations not available, atomic_cas() should not have been called!");
542     return true;
543 #endif
544 }
545
546 void nbnxn_cuda_wait_gpu(nbnxn_cuda_ptr_t cu_nb,
547                          const nbnxn_atomdata_t *nbatom,
548                          int flags, int aloc,
549                          real *e_lj, real *e_el, rvec *fshift)
550 {
551     /* NOTE:  only implemented for single-precision at this time */
552     cudaError_t            stat;
553     int                    i, adat_end, iloc = -1;
554     volatile unsigned int *poll_word;
555
556     /* determine interaction locality from atom locality */
557     if (LOCAL_A(aloc))
558     {
559         iloc = eintLocal;
560     }
561     else if (NONLOCAL_A(aloc))
562     {
563         iloc = eintNonlocal;
564     }
565     else
566     {
567         char stmp[STRLEN];
568         sprintf(stmp, "Invalid atom locality passed (%d); valid here is only "
569                 "local (%d) or nonlocal (%d)", aloc, eatLocal, eatNonlocal);
570         gmx_incons(stmp);
571     }
572
573     cu_plist_t      *plist    = cu_nb->plist[iloc];
574     cu_timers_t     *timers   = cu_nb->timers;
575     wallclock_gpu_t *timings  = cu_nb->timings;
576     nb_staging       nbst     = cu_nb->nbst;
577
578     bool             bCalcEner   = flags & GMX_FORCE_VIRIAL;
579     bool             bCalcFshift = flags & GMX_FORCE_VIRIAL;
580
581     /* turn energy calculation always on/off (for debugging/testing only) */
582     bCalcEner = (bCalcEner || always_ener) && !never_ener;
583
584     /* don't launch wait/update timers & counters if there was no work to do
585
586        NOTE: if timing with multiple GPUs (streams) becomes possible, the
587        counters could end up being inconsistent due to not being incremented
588        on some of the nodes! */
589     if (cu_nb->plist[iloc]->nsci == 0)
590     {
591         return;
592     }
593
594     /* calculate the atom data index range based on locality */
595     if (LOCAL_A(aloc))
596     {
597         adat_end = cu_nb->atdat->natoms_local;
598     }
599     else
600     {
601         adat_end = cu_nb->atdat->natoms;
602     }
603
604     if (cu_nb->bUseStreamSync)
605     {
606         stat = cudaStreamSynchronize(cu_nb->stream[iloc]);
607         CU_RET_ERR(stat, "cudaStreamSynchronize failed in cu_blockwait_nb");
608     }
609     else
610     {
611         /* Busy-wait until we get the signal pattern set in last byte
612          * of the l/nl float vector. This pattern corresponds to a floating
613          * point number which can't be the result of the force calculation
614          * (maximum, 127 exponent and 0 mantissa).
615          * The polling uses atomic compare-exchange.
616          */
617         poll_word = (volatile unsigned int*)&nbatom->out[0].f[adat_end*3 - 1];
618         while (atomic_cas(poll_word, poll_wait_pattern, poll_wait_pattern))
619         {
620         }
621     }
622
623     /* timing data accumulation */
624     if (cu_nb->bDoTime)
625     {
626         /* only increase counter once (at local F wait) */
627         if (LOCAL_I(iloc))
628         {
629             timings->nb_c++;
630             timings->ktime[plist->bDoPrune ? 1 : 0][bCalcEner ? 1 : 0].c += 1;
631         }
632
633         /* kernel timings */
634         timings->ktime[plist->bDoPrune ? 1 : 0][bCalcEner ? 1 : 0].t +=
635             cu_event_elapsed(timers->start_nb_k[iloc], timers->stop_nb_k[iloc]);
636
637         /* X/q H2D and F D2H timings */
638         timings->nb_h2d_t += cu_event_elapsed(timers->start_nb_h2d[iloc],
639                                               timers->stop_nb_h2d[iloc]);
640         timings->nb_d2h_t += cu_event_elapsed(timers->start_nb_d2h[iloc],
641                                               timers->stop_nb_d2h[iloc]);
642
643         /* only count atdat and pair-list H2D at pair-search step */
644         if (plist->bDoPrune)
645         {
646             /* atdat transfer timing (add only once, at local F wait) */
647             if (LOCAL_A(aloc))
648             {
649                 timings->pl_h2d_c++;
650                 timings->pl_h2d_t += cu_event_elapsed(timers->start_atdat,
651                                                       timers->stop_atdat);
652             }
653
654             timings->pl_h2d_t += cu_event_elapsed(timers->start_pl_h2d[iloc],
655                                                   timers->stop_pl_h2d[iloc]);
656         }
657     }
658
659     /* add up energies and shift forces (only once at local F wait) */
660     if (LOCAL_I(iloc))
661     {
662         if (bCalcEner)
663         {
664             *e_lj += *nbst.e_lj;
665             *e_el += *nbst.e_el;
666         }
667
668         if (bCalcFshift)
669         {
670             for (i = 0; i < SHIFTS; i++)
671             {
672                 fshift[i][0] += nbst.fshift[i].x;
673                 fshift[i][1] += nbst.fshift[i].y;
674                 fshift[i][2] += nbst.fshift[i].z;
675             }
676         }
677     }
678
679     /* turn off pruning (doesn't matter if this is pair-search step or not) */
680     plist->bDoPrune = false;
681 }
682
683 /*! Return the reference to the nbfp texture. */
684 const struct texture<float, 1, cudaReadModeElementType> &nbnxn_cuda_get_nbfp_texref()
685 {
686     return nbfp_texref;
687 }
688
689 /*! Return the reference to the nbfp_comb texture. */
690 const struct texture<float, 1, cudaReadModeElementType> &nbnxn_cuda_get_nbfp_comb_texref()
691 {
692     return nbfp_comb_texref;
693 }
694
695 /*! Return the reference to the coulomb_tab. */
696 const struct texture<float, 1, cudaReadModeElementType> &nbnxn_cuda_get_coulomb_tab_texref()
697 {
698     return coulomb_tab_texref;
699 }
700
701 /*! Set up the cache configuration for the non-bonded kernels,
702  */
703 void nbnxn_cuda_set_cacheconfig(cuda_dev_info_t *devinfo)
704 {
705     cudaError_t stat;
706
707     for (int i = 0; i < eelCuNR; i++)
708     {
709         for (int j = 0; j < evdwCuNR; j++)
710         {
711             if (devinfo->prop.major >= 3)
712             {
713                 /* Default kernel on sm 3.x 48/16 kB Shared/L1 */
714                 stat = cudaFuncSetCacheConfig(nb_kfunc_ener_prune_ptr[i][j], cudaFuncCachePreferShared);
715                 stat = cudaFuncSetCacheConfig(nb_kfunc_ener_noprune_ptr[i][j], cudaFuncCachePreferShared);
716                 stat = cudaFuncSetCacheConfig(nb_kfunc_noener_prune_ptr[i][j], cudaFuncCachePreferShared);
717                 stat = cudaFuncSetCacheConfig(nb_kfunc_noener_noprune_ptr[i][j], cudaFuncCachePreferShared);
718             }
719             else
720             {
721                 /* On Fermi prefer L1 gives 2% higher performance */
722                 /* Default kernel on sm_2.x 16/48 kB Shared/L1 */
723                 stat = cudaFuncSetCacheConfig(nb_kfunc_ener_prune_ptr[i][j], cudaFuncCachePreferL1);
724                 stat = cudaFuncSetCacheConfig(nb_kfunc_ener_noprune_ptr[i][j], cudaFuncCachePreferL1);
725                 stat = cudaFuncSetCacheConfig(nb_kfunc_noener_prune_ptr[i][j], cudaFuncCachePreferL1);
726                 stat = cudaFuncSetCacheConfig(nb_kfunc_noener_noprune_ptr[i][j], cudaFuncCachePreferL1);
727             }
728             CU_RET_ERR(stat, "cudaFuncSetCacheConfig failed");
729         }
730     }
731 }