eb1234d5122a0ad1abc040d003a7bc9a58c93249
[alexxy/gromacs.git] / src / gromacs / nbnxm / opencl / nbnxm_ocl_data_mgmt.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2012,2013,2014,2015,2016 by the GROMACS development team.
5  * Copyright (c) 2017,2018,2019,2020, by the GROMACS development team, led by
6  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
7  * and including many others, as listed in the AUTHORS file in the
8  * top-level source directory and at http://www.gromacs.org.
9  *
10  * GROMACS is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public License
12  * as published by the Free Software Foundation; either version 2.1
13  * of the License, or (at your option) any later version.
14  *
15  * GROMACS is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with GROMACS; if not, see
22  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
23  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
24  *
25  * If you want to redistribute modifications to GROMACS, please
26  * consider that scientific software is very special. Version
27  * control is crucial - bugs must be traceable. We will be happy to
28  * consider code for inclusion in the official distribution, but
29  * derived work must not be called official GROMACS. Details are found
30  * in the README & COPYING files - if they are missing, get the
31  * official version at http://www.gromacs.org.
32  *
33  * To help us fund GROMACS development, we humbly ask that you cite
34  * the research papers on the package. Check out http://www.gromacs.org.
35  */
36 /*! \internal \file
37  *  \brief Define OpenCL implementation of nbnxm_gpu_data_mgmt.h
38  *
39  *  \author Anca Hamuraru <anca@streamcomputing.eu>
40  *  \author Dimitrios Karkoulis <dimitris.karkoulis@gmail.com>
41  *  \author Teemu Virolainen <teemu@streamcomputing.eu>
42  *  \author Szilárd Páll <pall.szilard@gmail.com>
43  *  \ingroup module_nbnxm
44  */
45 #include "gmxpre.h"
46
47 #include <assert.h>
48 #include <stdarg.h>
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52
53 #include <cmath>
54
55 #include "gromacs/gpu_utils/gpu_utils.h"
56 #include "gromacs/gpu_utils/oclutils.h"
57 #include "gromacs/hardware/gpu_hw_info.h"
58 #include "gromacs/math/vectypes.h"
59 #include "gromacs/mdlib/force_flags.h"
60 #include "gromacs/mdtypes/interaction_const.h"
61 #include "gromacs/mdtypes/md_enums.h"
62 #include "gromacs/nbnxm/atomdata.h"
63 #include "gromacs/nbnxm/gpu_data_mgmt.h"
64 #include "gromacs/nbnxm/gpu_jit_support.h"
65 #include "gromacs/nbnxm/nbnxm.h"
66 #include "gromacs/nbnxm/nbnxm_gpu.h"
67 #include "gromacs/nbnxm/pairlistsets.h"
68 #include "gromacs/pbcutil/ishift.h"
69 #include "gromacs/timing/gpu_timing.h"
70 #include "gromacs/utility/cstringutil.h"
71 #include "gromacs/utility/fatalerror.h"
72 #include "gromacs/utility/gmxassert.h"
73 #include "gromacs/utility/real.h"
74 #include "gromacs/utility/smalloc.h"
75
76 #include "nbnxm_ocl_internal.h"
77 #include "nbnxm_ocl_types.h"
78
79 namespace Nbnxm
80 {
81
82 /*! \brief Copies of values from cl_driver_diagnostics_intel.h,
83  * which isn't guaranteed to be available. */
84 /**@{*/
85 #define CL_CONTEXT_SHOW_DIAGNOSTICS_INTEL 0x4106
86 #define CL_CONTEXT_DIAGNOSTICS_LEVEL_GOOD_INTEL 0x1
87 #define CL_CONTEXT_DIAGNOSTICS_LEVEL_BAD_INTEL 0x2
88 #define CL_CONTEXT_DIAGNOSTICS_LEVEL_NEUTRAL_INTEL 0x4
89 /**@}*/
90
91 /*! \brief This parameter should be determined heuristically from the
92  * kernel execution times
93  *
94  * This value is best for small systems on a single AMD Radeon R9 290X
95  * (and about 5% faster than 40, which is the default for CUDA
96  * devices). Larger simulation systems were quite insensitive to the
97  * value of this parameter.
98  */
99 static unsigned int gpu_min_ci_balanced_factor = 50;
100
101
102 /*! \brief Returns true if LJ combination rules are used in the non-bonded kernels.
103  *
104  * Full doc in nbnxn_ocl_internal.h */
105 bool useLjCombRule(int vdwType)
106 {
107     return (vdwType == evdwOclCUTCOMBGEOM || vdwType == evdwOclCUTCOMBLB);
108 }
109
110 /*! \brief Tabulates the Ewald Coulomb force and initializes the size/scale
111  * and the table GPU array.
112  *
113  * If called with an already allocated table, it just re-uploads the
114  * table.
115  */
116 static void init_ewald_coulomb_force_table(const EwaldCorrectionTables&     tables,
117                                            cl_nbparam_t*                    nbp,
118                                            const gmx_device_runtime_data_t* runData)
119 {
120     cl_mem coul_tab;
121
122     cl_int cl_error;
123
124     if (nbp->coulomb_tab_climg2d != nullptr)
125     {
126         freeDeviceBuffer(&(nbp->coulomb_tab_climg2d));
127     }
128
129     /* Switched from using textures to using buffers */
130     // TODO: decide which alternative is most efficient - textures or buffers.
131     /*
132        cl_image_format array_format;
133
134        array_format.image_channel_data_type = CL_FLOAT;
135        array_format.image_channel_order     = CL_R;
136
137        coul_tab = clCreateImage2D(runData->deviceContext.context(), CL_MEM_READ_WRITE |
138        CL_MEM_COPY_HOST_PTR, &array_format, tabsize, 1, 0, ftmp, &cl_error);
139      */
140
141     coul_tab = clCreateBuffer(runData->deviceContext_.context(),
142                               CL_MEM_READ_ONLY | CL_MEM_HOST_WRITE_ONLY | CL_MEM_COPY_HOST_PTR,
143                               tables.tableF.size() * sizeof(cl_float),
144                               const_cast<real*>(tables.tableF.data()), &cl_error);
145     GMX_RELEASE_ASSERT(cl_error == CL_SUCCESS,
146                        ("clCreateBuffer failed: " + ocl_get_error_string(cl_error)).c_str());
147
148     nbp->coulomb_tab_climg2d = coul_tab;
149     nbp->coulomb_tab_scale   = tables.scale;
150 }
151
152
153 /*! \brief Initializes the atomdata structure first time, it only gets filled at
154     pair-search.
155  */
156 static void init_atomdata_first(cl_atomdata_t* ad, int ntypes, gmx_device_runtime_data_t* runData)
157 {
158     cl_int cl_error;
159
160     ad->ntypes = ntypes;
161
162     ad->shift_vec =
163             clCreateBuffer(runData->deviceContext_.context(), CL_MEM_READ_ONLY | CL_MEM_HOST_WRITE_ONLY,
164                            SHIFTS * sizeof(nbnxn_atomdata_t::shift_vec[0]), nullptr, &cl_error);
165     GMX_RELEASE_ASSERT(cl_error == CL_SUCCESS,
166                        ("clCreateBuffer failed: " + ocl_get_error_string(cl_error)).c_str());
167     ad->bShiftVecUploaded = CL_FALSE;
168
169     ad->fshift = clCreateBuffer(runData->deviceContext_.context(), CL_MEM_READ_WRITE | CL_MEM_HOST_READ_ONLY,
170                                 SHIFTS * sizeof(nb_staging_t::fshift[0]), nullptr, &cl_error);
171     GMX_RELEASE_ASSERT(cl_error == CL_SUCCESS,
172                        ("clCreateBuffer failed: " + ocl_get_error_string(cl_error)).c_str());
173
174     ad->e_lj = clCreateBuffer(runData->deviceContext_.context(), CL_MEM_READ_WRITE | CL_MEM_HOST_READ_ONLY,
175                               sizeof(float), nullptr, &cl_error);
176     GMX_RELEASE_ASSERT(cl_error == CL_SUCCESS,
177                        ("clCreateBuffer failed: " + ocl_get_error_string(cl_error)).c_str());
178
179     ad->e_el = clCreateBuffer(runData->deviceContext_.context(), CL_MEM_READ_WRITE | CL_MEM_HOST_READ_ONLY,
180                               sizeof(float), nullptr, &cl_error);
181     GMX_RELEASE_ASSERT(cl_error == CL_SUCCESS,
182                        ("clCreateBuffer failed: " + ocl_get_error_string(cl_error)).c_str());
183
184     /* initialize to nullptr pointers to data that is not allocated here and will
185        need reallocation in nbnxn_gpu_init_atomdata */
186     ad->xq = nullptr;
187     ad->f  = nullptr;
188
189     /* size -1 indicates that the respective array hasn't been initialized yet */
190     ad->natoms = -1;
191     ad->nalloc = -1;
192 }
193
194 /*! \brief Copies all parameters related to the cut-off from ic to nbp
195  */
196 static void set_cutoff_parameters(cl_nbparam_t* nbp, const interaction_const_t* ic, const PairlistParams& listParams)
197 {
198     nbp->ewald_beta        = ic->ewaldcoeff_q;
199     nbp->sh_ewald          = ic->sh_ewald;
200     nbp->epsfac            = ic->epsfac;
201     nbp->two_k_rf          = 2.0 * ic->k_rf;
202     nbp->c_rf              = ic->c_rf;
203     nbp->rvdw_sq           = ic->rvdw * ic->rvdw;
204     nbp->rcoulomb_sq       = ic->rcoulomb * ic->rcoulomb;
205     nbp->rlistOuter_sq     = listParams.rlistOuter * listParams.rlistOuter;
206     nbp->rlistInner_sq     = listParams.rlistInner * listParams.rlistInner;
207     nbp->useDynamicPruning = listParams.useDynamicPruning;
208
209     nbp->sh_lj_ewald   = ic->sh_lj_ewald;
210     nbp->ewaldcoeff_lj = ic->ewaldcoeff_lj;
211
212     nbp->rvdw_switch      = ic->rvdw_switch;
213     nbp->dispersion_shift = ic->dispersion_shift;
214     nbp->repulsion_shift  = ic->repulsion_shift;
215     nbp->vdw_switch       = ic->vdw_switch;
216 }
217
218 /*! \brief Returns the kinds of electrostatics and Vdw OpenCL
219  *  kernels that will be used.
220  *
221  * Respectively, these values are from enum eelOcl and enum
222  * evdwOcl. */
223 static void map_interaction_types_to_gpu_kernel_flavors(const interaction_const_t* ic,
224                                                         int                        combRule,
225                                                         int*                       gpu_eeltype,
226                                                         int*                       gpu_vdwtype)
227 {
228     if (ic->vdwtype == evdwCUT)
229     {
230         switch (ic->vdw_modifier)
231         {
232             case eintmodNONE:
233             case eintmodPOTSHIFT:
234                 switch (combRule)
235                 {
236                     case ljcrNONE: *gpu_vdwtype = evdwOclCUT; break;
237                     case ljcrGEOM: *gpu_vdwtype = evdwOclCUTCOMBGEOM; break;
238                     case ljcrLB: *gpu_vdwtype = evdwOclCUTCOMBLB; break;
239                     default:
240                         gmx_incons(
241                                 "The requested LJ combination rule is not implemented in the "
242                                 "OpenCL GPU accelerated kernels!");
243                 }
244                 break;
245             case eintmodFORCESWITCH: *gpu_vdwtype = evdwOclFSWITCH; break;
246             case eintmodPOTSWITCH: *gpu_vdwtype = evdwOclPSWITCH; break;
247             default:
248                 gmx_incons(
249                         "The requested VdW interaction modifier is not implemented in the GPU "
250                         "accelerated kernels!");
251         }
252     }
253     else if (ic->vdwtype == evdwPME)
254     {
255         if (ic->ljpme_comb_rule == ljcrGEOM)
256         {
257             *gpu_vdwtype = evdwOclEWALDGEOM;
258         }
259         else
260         {
261             *gpu_vdwtype = evdwOclEWALDLB;
262         }
263     }
264     else
265     {
266         gmx_incons("The requested VdW type is not implemented in the GPU accelerated kernels!");
267     }
268
269     if (ic->eeltype == eelCUT)
270     {
271         *gpu_eeltype = eelOclCUT;
272     }
273     else if (EEL_RF(ic->eeltype))
274     {
275         *gpu_eeltype = eelOclRF;
276     }
277     else if ((EEL_PME(ic->eeltype) || ic->eeltype == eelEWALD))
278     {
279         *gpu_eeltype = nbnxn_gpu_pick_ewald_kernel_type(*ic);
280     }
281     else
282     {
283         /* Shouldn't happen, as this is checked when choosing Verlet-scheme */
284         gmx_incons(
285                 "The requested electrostatics type is not implemented in the GPU accelerated "
286                 "kernels!");
287     }
288 }
289
290 /*! \brief Initializes the nonbonded parameter data structure.
291  */
292 static void init_nbparam(cl_nbparam_t*                    nbp,
293                          const interaction_const_t*       ic,
294                          const PairlistParams&            listParams,
295                          const nbnxn_atomdata_t::Params&  nbatParams,
296                          const gmx_device_runtime_data_t* runData)
297 {
298     cl_int cl_error;
299
300     set_cutoff_parameters(nbp, ic, listParams);
301
302     map_interaction_types_to_gpu_kernel_flavors(ic, nbatParams.comb_rule, &(nbp->eeltype), &(nbp->vdwtype));
303
304     if (ic->vdwtype == evdwPME)
305     {
306         if (ic->ljpme_comb_rule == ljcrGEOM)
307         {
308             GMX_ASSERT(nbatParams.comb_rule == ljcrGEOM, "Combination rule mismatch!");
309         }
310         else
311         {
312             GMX_ASSERT(nbatParams.comb_rule == ljcrLB, "Combination rule mismatch!");
313         }
314     }
315     /* generate table for PME */
316     nbp->coulomb_tab_climg2d = nullptr;
317     if (nbp->eeltype == eelOclEWALD_TAB || nbp->eeltype == eelOclEWALD_TAB_TWIN)
318     {
319         GMX_RELEASE_ASSERT(ic->coulombEwaldTables, "Need valid Coulomb Ewald correction tables");
320         init_ewald_coulomb_force_table(*ic->coulombEwaldTables, nbp, runData);
321     }
322     else
323     // TODO: improvement needed.
324     // The image2d is created here even if eeltype is not eelCuEWALD_TAB or eelCuEWALD_TAB_TWIN
325     // because the OpenCL kernels don't accept nullptr values for image2D parameters.
326     {
327         /* Switched from using textures to using buffers */
328         // TODO: decide which alternative is most efficient - textures or buffers.
329         /*
330            cl_image_format array_format;
331
332            array_format.image_channel_data_type = CL_FLOAT;
333            array_format.image_channel_order     = CL_R;
334
335            nbp->coulomb_tab_climg2d = clCreateImage2D(runData->deviceContext.context(),
336            CL_MEM_READ_WRITE, &array_format, 1, 1, 0, nullptr, &cl_error);
337          */
338
339         nbp->coulomb_tab_climg2d = clCreateBuffer(runData->deviceContext_.context(), CL_MEM_READ_ONLY,
340                                                   sizeof(cl_float), nullptr, &cl_error);
341         GMX_RELEASE_ASSERT(cl_error == CL_SUCCESS,
342                            ("clCreateBuffer failed: " + ocl_get_error_string(cl_error)).c_str());
343     }
344
345     const int nnbfp      = 2 * nbatParams.numTypes * nbatParams.numTypes;
346     const int nnbfp_comb = 2 * nbatParams.numTypes;
347
348     {
349         /* Switched from using textures to using buffers */
350         // TODO: decide which alternative is most efficient - textures or buffers.
351         /*
352            cl_image_format array_format;
353
354            array_format.image_channel_data_type = CL_FLOAT;
355            array_format.image_channel_order     = CL_R;
356
357            nbp->nbfp_climg2d = clCreateImage2D(runData->deviceContext_.context(), CL_MEM_READ_ONLY |
358            CL_MEM_COPY_HOST_PTR, &array_format, nnbfp, 1, 0, nbat->nbfp, &cl_error);
359          */
360
361         nbp->nbfp_climg2d = clCreateBuffer(
362                 runData->deviceContext_.context(),
363                 CL_MEM_READ_ONLY | CL_MEM_HOST_WRITE_ONLY | CL_MEM_COPY_HOST_PTR,
364                 nnbfp * sizeof(cl_float), const_cast<float*>(nbatParams.nbfp.data()), &cl_error);
365         GMX_RELEASE_ASSERT(cl_error == CL_SUCCESS,
366                            ("clCreateBuffer failed: " + ocl_get_error_string(cl_error)).c_str());
367
368         if (ic->vdwtype == evdwPME)
369         {
370             /* Switched from using textures to using buffers */
371             // TODO: decide which alternative is most efficient - textures or buffers.
372             /*  nbp->nbfp_comb_climg2d = clCreateImage2D(runData->deviceContext.context(), CL_MEM_READ_WRITE |
373                CL_MEM_COPY_HOST_PTR, &array_format, nnbfp_comb, 1, 0, nbat->nbfp_comb, &cl_error);*/
374             nbp->nbfp_comb_climg2d =
375                     clCreateBuffer(runData->deviceContext_.context(),
376                                    CL_MEM_READ_ONLY | CL_MEM_HOST_WRITE_ONLY | CL_MEM_COPY_HOST_PTR,
377                                    nnbfp_comb * sizeof(cl_float),
378                                    const_cast<float*>(nbatParams.nbfp_comb.data()), &cl_error);
379             GMX_RELEASE_ASSERT(cl_error == CL_SUCCESS,
380                                ("clCreateBuffer failed: " + ocl_get_error_string(cl_error)).c_str());
381         }
382         else
383         {
384             // TODO: improvement needed.
385             // The image2d is created here even if vdwtype is not evdwPME because the OpenCL kernels
386             // don't accept nullptr values for image2D parameters.
387             /* Switched from using textures to using buffers */
388             // TODO: decide which alternative is most efficient - textures or buffers.
389             /* nbp->nbfp_comb_climg2d = clCreateImage2D(runData->deviceContext.context(),
390                CL_MEM_READ_WRITE, &array_format, 1, 1, 0, nullptr, &cl_error);*/
391             nbp->nbfp_comb_climg2d = clCreateBuffer(runData->deviceContext_.context(), CL_MEM_READ_ONLY,
392                                                     sizeof(cl_float), nullptr, &cl_error);
393             GMX_RELEASE_ASSERT(cl_error == CL_SUCCESS,
394                                ("clCreateBuffer failed: " + ocl_get_error_string(cl_error)).c_str());
395         }
396     }
397 }
398
399 //! This function is documented in the header file
400 void gpu_pme_loadbal_update_param(const nonbonded_verlet_t* nbv, const interaction_const_t* ic)
401 {
402     if (!nbv || !nbv->useGpu())
403     {
404         return;
405     }
406     NbnxmGpu*     nb  = nbv->gpu_nbv;
407     cl_nbparam_t* nbp = nb->nbparam;
408
409     set_cutoff_parameters(nbp, ic, nbv->pairlistSets().params());
410
411     nbp->eeltype = nbnxn_gpu_pick_ewald_kernel_type(*ic);
412
413     GMX_RELEASE_ASSERT(ic->coulombEwaldTables, "Need valid Coulomb Ewald correction tables");
414     init_ewald_coulomb_force_table(*ic->coulombEwaldTables, nbp, nb->dev_rundata);
415 }
416
417 /*! \brief Initializes the pair list data structure.
418  */
419 static void init_plist(cl_plist_t* pl)
420 {
421     /* initialize to nullptr pointers to data that is not allocated here and will
422        need reallocation in nbnxn_gpu_init_pairlist */
423     pl->sci   = nullptr;
424     pl->cj4   = nullptr;
425     pl->imask = nullptr;
426     pl->excl  = nullptr;
427
428     /* size -1 indicates that the respective array hasn't been initialized yet */
429     pl->na_c          = -1;
430     pl->nsci          = -1;
431     pl->sci_nalloc    = -1;
432     pl->ncj4          = -1;
433     pl->cj4_nalloc    = -1;
434     pl->nimask        = -1;
435     pl->imask_nalloc  = -1;
436     pl->nexcl         = -1;
437     pl->excl_nalloc   = -1;
438     pl->haveFreshList = false;
439 }
440
441 /*! \brief Initializes the timings data structure.
442  */
443 static void init_timings(gmx_wallclock_gpu_nbnxn_t* t)
444 {
445     int i, j;
446
447     t->nb_h2d_t = 0.0;
448     t->nb_d2h_t = 0.0;
449     t->nb_c     = 0;
450     t->pl_h2d_t = 0.0;
451     t->pl_h2d_c = 0;
452     for (i = 0; i < 2; i++)
453     {
454         for (j = 0; j < 2; j++)
455         {
456             t->ktime[i][j].t = 0.0;
457             t->ktime[i][j].c = 0;
458         }
459     }
460
461     t->pruneTime.c        = 0;
462     t->pruneTime.t        = 0.0;
463     t->dynamicPruneTime.c = 0;
464     t->dynamicPruneTime.t = 0.0;
465 }
466
467 /*! \brief Initializes the OpenCL kernel pointers of the nbnxn_ocl_ptr_t input data structure. */
468 static cl_kernel nbnxn_gpu_create_kernel(NbnxmGpu* nb, const char* kernel_name)
469 {
470     cl_kernel kernel;
471     cl_int    cl_error;
472
473     kernel = clCreateKernel(nb->dev_rundata->program, kernel_name, &cl_error);
474     if (CL_SUCCESS != cl_error)
475     {
476         gmx_fatal(FARGS, "Failed to create kernel '%s' for GPU #%s: OpenCL error %d", kernel_name,
477                   nb->deviceInfo->device_name, cl_error);
478     }
479
480     return kernel;
481 }
482
483 /*! \brief Clears nonbonded shift force output array and energy outputs on the GPU.
484  */
485 static void nbnxn_ocl_clear_e_fshift(NbnxmGpu* nb)
486 {
487
488     cl_int           cl_error;
489     cl_atomdata_t*   adat = nb->atdat;
490     cl_command_queue ls   = nb->stream[InteractionLocality::Local];
491
492     size_t local_work_size[3]  = { 1, 1, 1 };
493     size_t global_work_size[3] = { 1, 1, 1 };
494
495     cl_int shifts = SHIFTS * 3;
496
497     cl_int arg_no;
498
499     cl_kernel zero_e_fshift = nb->kernel_zero_e_fshift;
500
501     local_work_size[0] = 64;
502     // Round the total number of threads up from the array size
503     global_work_size[0] = ((shifts + local_work_size[0] - 1) / local_work_size[0]) * local_work_size[0];
504
505     arg_no   = 0;
506     cl_error = clSetKernelArg(zero_e_fshift, arg_no++, sizeof(cl_mem), &(adat->fshift));
507     cl_error |= clSetKernelArg(zero_e_fshift, arg_no++, sizeof(cl_mem), &(adat->e_lj));
508     cl_error |= clSetKernelArg(zero_e_fshift, arg_no++, sizeof(cl_mem), &(adat->e_el));
509     cl_error |= clSetKernelArg(zero_e_fshift, arg_no++, sizeof(cl_uint), &shifts);
510     GMX_ASSERT(cl_error == CL_SUCCESS, ocl_get_error_string(cl_error).c_str());
511
512     cl_error = clEnqueueNDRangeKernel(ls, zero_e_fshift, 3, nullptr, global_work_size,
513                                       local_work_size, 0, nullptr, nullptr);
514     GMX_ASSERT(cl_error == CL_SUCCESS, ocl_get_error_string(cl_error).c_str());
515 }
516
517 /*! \brief Initializes the OpenCL kernel pointers of the nbnxn_ocl_ptr_t input data structure. */
518 static void nbnxn_gpu_init_kernels(NbnxmGpu* nb)
519 {
520     /* Init to 0 main kernel arrays */
521     /* They will be later on initialized in select_nbnxn_kernel */
522     // TODO: consider always creating all variants of the kernels here so that there is no
523     // need for late call to clCreateKernel -- if that gives any advantage?
524     memset(nb->kernel_ener_noprune_ptr, 0, sizeof(nb->kernel_ener_noprune_ptr));
525     memset(nb->kernel_ener_prune_ptr, 0, sizeof(nb->kernel_ener_prune_ptr));
526     memset(nb->kernel_noener_noprune_ptr, 0, sizeof(nb->kernel_noener_noprune_ptr));
527     memset(nb->kernel_noener_prune_ptr, 0, sizeof(nb->kernel_noener_prune_ptr));
528
529     /* Init pruning kernels
530      *
531      * TODO: we could avoid creating kernels if dynamic pruning is turned off,
532      * but ATM that depends on force flags not passed into the initialization.
533      */
534     nb->kernel_pruneonly[epruneFirst] = nbnxn_gpu_create_kernel(nb, "nbnxn_kernel_prune_opencl");
535     nb->kernel_pruneonly[epruneRolling] =
536             nbnxn_gpu_create_kernel(nb, "nbnxn_kernel_prune_rolling_opencl");
537
538     /* Init auxiliary kernels */
539     nb->kernel_zero_e_fshift = nbnxn_gpu_create_kernel(nb, "zero_e_fshift");
540 }
541
542 /*! \brief Initializes simulation constant data.
543  *
544  *  Initializes members of the atomdata and nbparam structs and
545  *  clears e/fshift output buffers.
546  */
547 static void nbnxn_ocl_init_const(NbnxmGpu*                       nb,
548                                  const interaction_const_t*      ic,
549                                  const PairlistParams&           listParams,
550                                  const nbnxn_atomdata_t::Params& nbatParams)
551 {
552     init_atomdata_first(nb->atdat, nbatParams.numTypes, nb->dev_rundata);
553     init_nbparam(nb->nbparam, ic, listParams, nbatParams, nb->dev_rundata);
554 }
555
556
557 //! This function is documented in the header file
558 NbnxmGpu* gpu_init(const DeviceInformation*   deviceInfo,
559                    const DeviceContext&       deviceContext,
560                    const interaction_const_t* ic,
561                    const PairlistParams&      listParams,
562                    const nbnxn_atomdata_t*    nbat,
563                    const int                  rank,
564                    const bool                 bLocalAndNonlocal)
565 {
566     cl_int                      cl_error;
567     cl_command_queue_properties queue_properties;
568
569     GMX_ASSERT(ic, "Need a valid interaction constants object");
570
571     auto nb = new NbnxmGpu;
572     snew(nb->atdat, 1);
573     snew(nb->nbparam, 1);
574     snew(nb->plist[InteractionLocality::Local], 1);
575     if (bLocalAndNonlocal)
576     {
577         snew(nb->plist[InteractionLocality::NonLocal], 1);
578     }
579
580     nb->bUseTwoStreams = bLocalAndNonlocal;
581
582     nb->timers = new cl_timers_t();
583     snew(nb->timings, 1);
584
585     /* set device info, just point it to the right GPU among the detected ones */
586     nb->deviceInfo  = deviceInfo;
587     nb->dev_rundata = new gmx_device_runtime_data_t(deviceContext);
588
589     /* init nbst */
590     pmalloc(reinterpret_cast<void**>(&nb->nbst.e_lj), sizeof(*nb->nbst.e_lj));
591     pmalloc(reinterpret_cast<void**>(&nb->nbst.e_el), sizeof(*nb->nbst.e_el));
592     pmalloc(reinterpret_cast<void**>(&nb->nbst.fshift), SHIFTS * sizeof(*nb->nbst.fshift));
593
594     init_plist(nb->plist[InteractionLocality::Local]);
595
596     /* OpenCL timing disabled if GMX_DISABLE_GPU_TIMING is defined. */
597     nb->bDoTime = (getenv("GMX_DISABLE_GPU_TIMING") == nullptr);
598
599     /* Create queues only after bDoTime has been initialized */
600     if (nb->bDoTime)
601     {
602         queue_properties = CL_QUEUE_PROFILING_ENABLE;
603     }
604     else
605     {
606         queue_properties = 0;
607     }
608
609     /* local/non-local GPU streams */
610     nb->stream[InteractionLocality::Local] =
611             clCreateCommandQueue(nb->dev_rundata->deviceContext_.context(),
612                                  nb->deviceInfo->oclDeviceId, queue_properties, &cl_error);
613     if (CL_SUCCESS != cl_error)
614     {
615         gmx_fatal(FARGS, "On rank %d failed to create context for GPU #%s: OpenCL error %d", rank,
616                   nb->deviceInfo->device_name, cl_error);
617     }
618
619     if (nb->bUseTwoStreams)
620     {
621         init_plist(nb->plist[InteractionLocality::NonLocal]);
622
623         nb->stream[InteractionLocality::NonLocal] =
624                 clCreateCommandQueue(nb->dev_rundata->deviceContext_.context(),
625                                      nb->deviceInfo->oclDeviceId, queue_properties, &cl_error);
626         if (CL_SUCCESS != cl_error)
627         {
628             gmx_fatal(FARGS, "On rank %d failed to create context for GPU #%s: OpenCL error %d",
629                       rank, nb->deviceInfo->device_name, cl_error);
630         }
631     }
632
633     if (nb->bDoTime)
634     {
635         init_timings(nb->timings);
636     }
637
638     nbnxn_ocl_init_const(nb, ic, listParams, nbat->params());
639
640     /* Enable LJ param manual prefetch for AMD or Intel or if we request through env. var.
641      * TODO: decide about NVIDIA
642      */
643     nb->bPrefetchLjParam = (getenv("GMX_OCL_DISABLE_I_PREFETCH") == nullptr)
644                            && ((nb->deviceInfo->deviceVendor == DeviceVendor::Amd)
645                                || (nb->deviceInfo->deviceVendor == DeviceVendor::Intel)
646                                || (getenv("GMX_OCL_ENABLE_I_PREFETCH") != nullptr));
647
648     /* NOTE: in CUDA we pick L1 cache configuration for the nbnxn kernels here,
649      * but sadly this is not supported in OpenCL (yet?). Consider adding it if
650      * it becomes supported.
651      */
652     nbnxn_gpu_compile_kernels(nb);
653     nbnxn_gpu_init_kernels(nb);
654
655     /* clear energy and shift force outputs */
656     nbnxn_ocl_clear_e_fshift(nb);
657
658     if (debug)
659     {
660         fprintf(debug, "Initialized OpenCL data structures.\n");
661     }
662
663     return nb;
664 }
665
666 /*! \brief Clears the first natoms_clear elements of the GPU nonbonded force output array.
667  */
668 static void nbnxn_ocl_clear_f(NbnxmGpu* nb, int natoms_clear)
669 {
670     if (natoms_clear == 0)
671     {
672         return;
673     }
674
675     cl_int gmx_used_in_debug cl_error;
676
677     cl_atomdata_t*   atomData = nb->atdat;
678     cl_command_queue ls       = nb->stream[InteractionLocality::Local];
679     cl_float         value    = 0.0F;
680
681     cl_error = clEnqueueFillBuffer(ls, atomData->f, &value, sizeof(cl_float), 0,
682                                    natoms_clear * sizeof(rvec), 0, nullptr, nullptr);
683     GMX_RELEASE_ASSERT(cl_error == CL_SUCCESS,
684                        ("clEnqueueFillBuffer failed: " + ocl_get_error_string(cl_error)).c_str());
685 }
686
687 //! This function is documented in the header file
688 void gpu_clear_outputs(NbnxmGpu* nb, bool computeVirial)
689 {
690     nbnxn_ocl_clear_f(nb, nb->atdat->natoms);
691     /* clear shift force array and energies if the outputs were
692        used in the current step */
693     if (computeVirial)
694     {
695         nbnxn_ocl_clear_e_fshift(nb);
696     }
697
698     /* kick off buffer clearing kernel to ensure concurrency with constraints/update */
699     cl_int gmx_unused cl_error;
700     cl_error = clFlush(nb->stream[InteractionLocality::Local]);
701     GMX_ASSERT(cl_error == CL_SUCCESS, ("clFlush failed: " + ocl_get_error_string(cl_error)).c_str());
702 }
703
704 //! This function is documented in the header file
705 void gpu_init_pairlist(NbnxmGpu* nb, const NbnxnPairlistGpu* h_plist, const InteractionLocality iloc)
706 {
707     char sbuf[STRLEN];
708     // Timing accumulation should happen only if there was work to do
709     // because getLastRangeTime() gets skipped with empty lists later
710     // which leads to the counter not being reset.
711     bool             bDoTime = (nb->bDoTime && !h_plist->sci.empty());
712     cl_command_queue stream  = nb->stream[iloc];
713     cl_plist_t*      d_plist = nb->plist[iloc];
714
715     if (d_plist->na_c < 0)
716     {
717         d_plist->na_c = h_plist->na_ci;
718     }
719     else
720     {
721         if (d_plist->na_c != h_plist->na_ci)
722         {
723             sprintf(sbuf, "In cu_init_plist: the #atoms per cell has changed (from %d to %d)",
724                     d_plist->na_c, h_plist->na_ci);
725             gmx_incons(sbuf);
726         }
727     }
728
729     gpu_timers_t::Interaction& iTimers = nb->timers->interaction[iloc];
730
731     if (bDoTime)
732     {
733         iTimers.pl_h2d.openTimingRegion(stream);
734         iTimers.didPairlistH2D = true;
735     }
736
737     // TODO most of this function is same in CUDA and OpenCL, move into the header
738     const DeviceContext& deviceContext = nb->dev_rundata->deviceContext_;
739
740     reallocateDeviceBuffer(&d_plist->sci, h_plist->sci.size(), &d_plist->nsci, &d_plist->sci_nalloc,
741                            deviceContext);
742     copyToDeviceBuffer(&d_plist->sci, h_plist->sci.data(), 0, h_plist->sci.size(), stream,
743                        GpuApiCallBehavior::Async, bDoTime ? iTimers.pl_h2d.fetchNextEvent() : nullptr);
744
745     reallocateDeviceBuffer(&d_plist->cj4, h_plist->cj4.size(), &d_plist->ncj4, &d_plist->cj4_nalloc,
746                            deviceContext);
747     copyToDeviceBuffer(&d_plist->cj4, h_plist->cj4.data(), 0, h_plist->cj4.size(), stream,
748                        GpuApiCallBehavior::Async, bDoTime ? iTimers.pl_h2d.fetchNextEvent() : nullptr);
749
750     reallocateDeviceBuffer(&d_plist->imask, h_plist->cj4.size() * c_nbnxnGpuClusterpairSplit,
751                            &d_plist->nimask, &d_plist->imask_nalloc, deviceContext);
752
753     reallocateDeviceBuffer(&d_plist->excl, h_plist->excl.size(), &d_plist->nexcl,
754                            &d_plist->excl_nalloc, deviceContext);
755     copyToDeviceBuffer(&d_plist->excl, h_plist->excl.data(), 0, h_plist->excl.size(), stream,
756                        GpuApiCallBehavior::Async, bDoTime ? iTimers.pl_h2d.fetchNextEvent() : nullptr);
757
758     if (bDoTime)
759     {
760         iTimers.pl_h2d.closeTimingRegion(stream);
761     }
762
763     /* need to prune the pair list during the next step */
764     d_plist->haveFreshList = true;
765 }
766
767 //! This function is documented in the header file
768 void gpu_upload_shiftvec(NbnxmGpu* nb, const nbnxn_atomdata_t* nbatom)
769 {
770     cl_atomdata_t*   adat = nb->atdat;
771     cl_command_queue ls   = nb->stream[InteractionLocality::Local];
772
773     /* only if we have a dynamic box */
774     if (nbatom->bDynamicBox || !adat->bShiftVecUploaded)
775     {
776         ocl_copy_H2D_async(adat->shift_vec, nbatom->shift_vec.data(), 0,
777                            SHIFTS * sizeof(nbatom->shift_vec[0]), ls, nullptr);
778         adat->bShiftVecUploaded = CL_TRUE;
779     }
780 }
781
782 //! This function is documented in the header file
783 void gpu_init_atomdata(NbnxmGpu* nb, const nbnxn_atomdata_t* nbat)
784 {
785     cl_int           cl_error;
786     int              nalloc, natoms;
787     bool             realloced;
788     bool             bDoTime = nb->bDoTime;
789     cl_timers_t*     timers  = nb->timers;
790     cl_atomdata_t*   d_atdat = nb->atdat;
791     cl_command_queue ls      = nb->stream[InteractionLocality::Local];
792
793     natoms    = nbat->numAtoms();
794     realloced = false;
795
796     if (bDoTime)
797     {
798         /* time async copy */
799         timers->atdat.openTimingRegion(ls);
800     }
801
802     /* need to reallocate if we have to copy more atoms than the amount of space
803        available and only allocate if we haven't initialized yet, i.e d_atdat->natoms == -1 */
804     if (natoms > d_atdat->nalloc)
805     {
806         nalloc = over_alloc_small(natoms);
807
808         /* free up first if the arrays have already been initialized */
809         if (d_atdat->nalloc != -1)
810         {
811             freeDeviceBuffer(&d_atdat->f);
812             freeDeviceBuffer(&d_atdat->xq);
813             freeDeviceBuffer(&d_atdat->lj_comb);
814             freeDeviceBuffer(&d_atdat->atom_types);
815         }
816
817         d_atdat->f = clCreateBuffer(nb->dev_rundata->deviceContext_.context(),
818                                     CL_MEM_READ_WRITE | CL_MEM_HOST_READ_ONLY,
819                                     nalloc * DIM * sizeof(nbat->out[0].f[0]), nullptr, &cl_error);
820         GMX_RELEASE_ASSERT(cl_error == CL_SUCCESS,
821                            ("clCreateBuffer failed: " + ocl_get_error_string(cl_error)).c_str());
822
823         d_atdat->xq = clCreateBuffer(nb->dev_rundata->deviceContext_.context(),
824                                      CL_MEM_READ_ONLY | CL_MEM_HOST_WRITE_ONLY,
825                                      nalloc * sizeof(cl_float4), nullptr, &cl_error);
826         GMX_RELEASE_ASSERT(cl_error == CL_SUCCESS,
827                            ("clCreateBuffer failed: " + ocl_get_error_string(cl_error)).c_str());
828
829         if (useLjCombRule(nb->nbparam->vdwtype))
830         {
831             d_atdat->lj_comb = clCreateBuffer(nb->dev_rundata->deviceContext_.context(),
832                                               CL_MEM_READ_ONLY | CL_MEM_HOST_WRITE_ONLY,
833                                               nalloc * sizeof(cl_float2), nullptr, &cl_error);
834             GMX_RELEASE_ASSERT(cl_error == CL_SUCCESS,
835                                ("clCreateBuffer failed: " + ocl_get_error_string(cl_error)).c_str());
836         }
837         else
838         {
839             d_atdat->atom_types = clCreateBuffer(nb->dev_rundata->deviceContext_.context(),
840                                                  CL_MEM_READ_ONLY | CL_MEM_HOST_WRITE_ONLY,
841                                                  nalloc * sizeof(int), nullptr, &cl_error);
842             GMX_RELEASE_ASSERT(cl_error == CL_SUCCESS,
843                                ("clCreateBuffer failed: " + ocl_get_error_string(cl_error)).c_str());
844         }
845
846         d_atdat->nalloc = nalloc;
847         realloced       = true;
848     }
849
850     d_atdat->natoms       = natoms;
851     d_atdat->natoms_local = nbat->natoms_local;
852
853     /* need to clear GPU f output if realloc happened */
854     if (realloced)
855     {
856         nbnxn_ocl_clear_f(nb, nalloc);
857     }
858
859     if (useLjCombRule(nb->nbparam->vdwtype))
860     {
861         ocl_copy_H2D_async(d_atdat->lj_comb, nbat->params().lj_comb.data(), 0, natoms * sizeof(cl_float2),
862                            ls, bDoTime ? timers->atdat.fetchNextEvent() : nullptr);
863     }
864     else
865     {
866         ocl_copy_H2D_async(d_atdat->atom_types, nbat->params().type.data(), 0, natoms * sizeof(int),
867                            ls, bDoTime ? timers->atdat.fetchNextEvent() : nullptr);
868     }
869
870     if (bDoTime)
871     {
872         timers->atdat.closeTimingRegion(ls);
873     }
874
875     /* kick off the tasks enqueued above to ensure concurrency with the search */
876     cl_error = clFlush(ls);
877     GMX_RELEASE_ASSERT(cl_error == CL_SUCCESS,
878                        ("clFlush failed: " + ocl_get_error_string(cl_error)).c_str());
879 }
880
881 /*! \brief Releases an OpenCL kernel pointer */
882 static void free_kernel(cl_kernel* kernel_ptr)
883 {
884     cl_int gmx_unused cl_error;
885
886     GMX_ASSERT(kernel_ptr, "Need a valid kernel pointer");
887
888     if (*kernel_ptr)
889     {
890         cl_error = clReleaseKernel(*kernel_ptr);
891         GMX_RELEASE_ASSERT(cl_error == CL_SUCCESS,
892                            ("clReleaseKernel failed: " + ocl_get_error_string(cl_error)).c_str());
893
894         *kernel_ptr = nullptr;
895     }
896 }
897
898 /*! \brief Releases a list of OpenCL kernel pointers */
899 static void free_kernels(cl_kernel* kernels, int count)
900 {
901     int i;
902
903     for (i = 0; i < count; i++)
904     {
905         free_kernel(kernels + i);
906     }
907 }
908
909 /*! \brief Free the OpenCL runtime data (context and program).
910  *
911  *  The function releases the OpenCL context and program assuciated with the
912  *  device that the calling PP rank is running on.
913  *
914  *  \param runData [in]  porinter to the structure with runtime data.
915  */
916 static void free_gpu_device_runtime_data(gmx_device_runtime_data_t* runData)
917 {
918     if (runData == nullptr)
919     {
920         return;
921     }
922
923     if (runData->program)
924     {
925         cl_int cl_error = clReleaseProgram(runData->program);
926         GMX_RELEASE_ASSERT(cl_error == CL_SUCCESS,
927                            ("clReleaseProgram failed: " + ocl_get_error_string(cl_error)).c_str());
928         runData->program = nullptr;
929     }
930 }
931
932 //! This function is documented in the header file
933 void gpu_free(NbnxmGpu* nb)
934 {
935     if (nb == nullptr)
936     {
937         return;
938     }
939
940     /* Free kernels */
941     int kernel_count = sizeof(nb->kernel_ener_noprune_ptr) / sizeof(nb->kernel_ener_noprune_ptr[0][0]);
942     free_kernels(nb->kernel_ener_noprune_ptr[0], kernel_count);
943
944     kernel_count = sizeof(nb->kernel_ener_prune_ptr) / sizeof(nb->kernel_ener_prune_ptr[0][0]);
945     free_kernels(nb->kernel_ener_prune_ptr[0], kernel_count);
946
947     kernel_count = sizeof(nb->kernel_noener_noprune_ptr) / sizeof(nb->kernel_noener_noprune_ptr[0][0]);
948     free_kernels(nb->kernel_noener_noprune_ptr[0], kernel_count);
949
950     kernel_count = sizeof(nb->kernel_noener_prune_ptr) / sizeof(nb->kernel_noener_prune_ptr[0][0]);
951     free_kernels(nb->kernel_noener_prune_ptr[0], kernel_count);
952
953     free_kernel(&(nb->kernel_zero_e_fshift));
954
955     /* Free atdat */
956     freeDeviceBuffer(&(nb->atdat->xq));
957     freeDeviceBuffer(&(nb->atdat->f));
958     freeDeviceBuffer(&(nb->atdat->e_lj));
959     freeDeviceBuffer(&(nb->atdat->e_el));
960     freeDeviceBuffer(&(nb->atdat->fshift));
961     freeDeviceBuffer(&(nb->atdat->lj_comb));
962     freeDeviceBuffer(&(nb->atdat->atom_types));
963     freeDeviceBuffer(&(nb->atdat->shift_vec));
964     sfree(nb->atdat);
965
966     /* Free nbparam */
967     freeDeviceBuffer(&(nb->nbparam->nbfp_climg2d));
968     freeDeviceBuffer(&(nb->nbparam->nbfp_comb_climg2d));
969     freeDeviceBuffer(&(nb->nbparam->coulomb_tab_climg2d));
970     sfree(nb->nbparam);
971
972     /* Free plist */
973     auto* plist = nb->plist[InteractionLocality::Local];
974     freeDeviceBuffer(&plist->sci);
975     freeDeviceBuffer(&plist->cj4);
976     freeDeviceBuffer(&plist->imask);
977     freeDeviceBuffer(&plist->excl);
978     sfree(plist);
979     if (nb->bUseTwoStreams)
980     {
981         auto* plist_nl = nb->plist[InteractionLocality::NonLocal];
982         freeDeviceBuffer(&plist_nl->sci);
983         freeDeviceBuffer(&plist_nl->cj4);
984         freeDeviceBuffer(&plist_nl->imask);
985         freeDeviceBuffer(&plist_nl->excl);
986         sfree(plist_nl);
987     }
988
989     /* Free nbst */
990     pfree(nb->nbst.e_lj);
991     nb->nbst.e_lj = nullptr;
992
993     pfree(nb->nbst.e_el);
994     nb->nbst.e_el = nullptr;
995
996     pfree(nb->nbst.fshift);
997     nb->nbst.fshift = nullptr;
998
999     /* Free command queues */
1000     clReleaseCommandQueue(nb->stream[InteractionLocality::Local]);
1001     nb->stream[InteractionLocality::Local] = nullptr;
1002     if (nb->bUseTwoStreams)
1003     {
1004         clReleaseCommandQueue(nb->stream[InteractionLocality::NonLocal]);
1005         nb->stream[InteractionLocality::NonLocal] = nullptr;
1006     }
1007     /* Free other events */
1008     if (nb->nonlocal_done)
1009     {
1010         clReleaseEvent(nb->nonlocal_done);
1011         nb->nonlocal_done = nullptr;
1012     }
1013     if (nb->misc_ops_and_local_H2D_done)
1014     {
1015         clReleaseEvent(nb->misc_ops_and_local_H2D_done);
1016         nb->misc_ops_and_local_H2D_done = nullptr;
1017     }
1018
1019     free_gpu_device_runtime_data(nb->dev_rundata);
1020     delete nb->dev_rundata;
1021
1022     /* Free timers and timings */
1023     delete nb->timers;
1024     sfree(nb->timings);
1025     delete nb;
1026
1027     if (debug)
1028     {
1029         fprintf(debug, "Cleaned up OpenCL data structures.\n");
1030     }
1031 }
1032
1033 //! This function is documented in the header file
1034 gmx_wallclock_gpu_nbnxn_t* gpu_get_timings(NbnxmGpu* nb)
1035 {
1036     return (nb != nullptr && nb->bDoTime) ? nb->timings : nullptr;
1037 }
1038
1039 //! This function is documented in the header file
1040 void gpu_reset_timings(nonbonded_verlet_t* nbv)
1041 {
1042     if (nbv->gpu_nbv && nbv->gpu_nbv->bDoTime)
1043     {
1044         init_timings(nbv->gpu_nbv->timings);
1045     }
1046 }
1047
1048 //! This function is documented in the header file
1049 int gpu_min_ci_balanced(NbnxmGpu* nb)
1050 {
1051     return nb != nullptr ? gpu_min_ci_balanced_factor * nb->deviceInfo->compute_units : 0;
1052 }
1053
1054 //! This function is documented in the header file
1055 gmx_bool gpu_is_kernel_ewald_analytical(const NbnxmGpu* nb)
1056 {
1057     return ((nb->nbparam->eeltype == eelOclEWALD_ANA) || (nb->nbparam->eeltype == eelOclEWALD_ANA_TWIN));
1058 }
1059
1060 } // namespace Nbnxm