Use DeviceStream init(...) function to create streams
[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->deviceStreams[InteractionLocality::Local].stream();
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 bool                 bLocalAndNonlocal)
564 {
565     GMX_ASSERT(ic, "Need a valid interaction constants object");
566
567     auto nb = new NbnxmGpu;
568     snew(nb->atdat, 1);
569     snew(nb->nbparam, 1);
570     snew(nb->plist[InteractionLocality::Local], 1);
571     if (bLocalAndNonlocal)
572     {
573         snew(nb->plist[InteractionLocality::NonLocal], 1);
574     }
575
576     nb->bUseTwoStreams = bLocalAndNonlocal;
577
578     nb->timers = new cl_timers_t();
579     snew(nb->timings, 1);
580
581     /* set device info, just point it to the right GPU among the detected ones */
582     nb->deviceInfo  = deviceInfo;
583     nb->dev_rundata = new gmx_device_runtime_data_t(deviceContext);
584
585     /* init nbst */
586     pmalloc(reinterpret_cast<void**>(&nb->nbst.e_lj), sizeof(*nb->nbst.e_lj));
587     pmalloc(reinterpret_cast<void**>(&nb->nbst.e_el), sizeof(*nb->nbst.e_el));
588     pmalloc(reinterpret_cast<void**>(&nb->nbst.fshift), SHIFTS * sizeof(*nb->nbst.fshift));
589
590     init_plist(nb->plist[InteractionLocality::Local]);
591
592     /* OpenCL timing disabled if GMX_DISABLE_GPU_TIMING is defined. */
593     nb->bDoTime = (getenv("GMX_DISABLE_GPU_TIMING") == nullptr);
594
595     /* local/non-local GPU streams */
596     nb->deviceStreams[InteractionLocality::Local].init(*nb->deviceInfo, nb->dev_rundata->deviceContext_,
597                                                        DeviceStreamPriority::Normal, nb->bDoTime);
598
599     if (nb->bUseTwoStreams)
600     {
601         init_plist(nb->plist[InteractionLocality::NonLocal]);
602
603         nb->deviceStreams[InteractionLocality::NonLocal].init(
604                 *nb->deviceInfo, nb->dev_rundata->deviceContext_, DeviceStreamPriority::High, nb->bDoTime);
605     }
606
607     if (nb->bDoTime)
608     {
609         init_timings(nb->timings);
610     }
611
612     nbnxn_ocl_init_const(nb, ic, listParams, nbat->params());
613
614     /* Enable LJ param manual prefetch for AMD or Intel or if we request through env. var.
615      * TODO: decide about NVIDIA
616      */
617     nb->bPrefetchLjParam = (getenv("GMX_OCL_DISABLE_I_PREFETCH") == nullptr)
618                            && ((nb->deviceInfo->deviceVendor == DeviceVendor::Amd)
619                                || (nb->deviceInfo->deviceVendor == DeviceVendor::Intel)
620                                || (getenv("GMX_OCL_ENABLE_I_PREFETCH") != nullptr));
621
622     /* NOTE: in CUDA we pick L1 cache configuration for the nbnxn kernels here,
623      * but sadly this is not supported in OpenCL (yet?). Consider adding it if
624      * it becomes supported.
625      */
626     nbnxn_gpu_compile_kernels(nb);
627     nbnxn_gpu_init_kernels(nb);
628
629     /* clear energy and shift force outputs */
630     nbnxn_ocl_clear_e_fshift(nb);
631
632     if (debug)
633     {
634         fprintf(debug, "Initialized OpenCL data structures.\n");
635     }
636
637     return nb;
638 }
639
640 /*! \brief Clears the first natoms_clear elements of the GPU nonbonded force output array.
641  */
642 static void nbnxn_ocl_clear_f(NbnxmGpu* nb, int natoms_clear)
643 {
644     if (natoms_clear == 0)
645     {
646         return;
647     }
648
649     cl_int gmx_used_in_debug cl_error;
650
651     cl_atomdata_t*   atomData = nb->atdat;
652     cl_command_queue ls       = nb->deviceStreams[InteractionLocality::Local].stream();
653     cl_float         value    = 0.0F;
654
655     cl_error = clEnqueueFillBuffer(ls, atomData->f, &value, sizeof(cl_float), 0,
656                                    natoms_clear * sizeof(rvec), 0, nullptr, nullptr);
657     GMX_RELEASE_ASSERT(cl_error == CL_SUCCESS,
658                        ("clEnqueueFillBuffer failed: " + ocl_get_error_string(cl_error)).c_str());
659 }
660
661 //! This function is documented in the header file
662 void gpu_clear_outputs(NbnxmGpu* nb, bool computeVirial)
663 {
664     nbnxn_ocl_clear_f(nb, nb->atdat->natoms);
665     /* clear shift force array and energies if the outputs were
666        used in the current step */
667     if (computeVirial)
668     {
669         nbnxn_ocl_clear_e_fshift(nb);
670     }
671
672     /* kick off buffer clearing kernel to ensure concurrency with constraints/update */
673     cl_int gmx_unused cl_error;
674     cl_error = clFlush(nb->deviceStreams[InteractionLocality::Local].stream());
675     GMX_ASSERT(cl_error == CL_SUCCESS, ("clFlush failed: " + ocl_get_error_string(cl_error)).c_str());
676 }
677
678 //! This function is documented in the header file
679 void gpu_init_pairlist(NbnxmGpu* nb, const NbnxnPairlistGpu* h_plist, const InteractionLocality iloc)
680 {
681     char sbuf[STRLEN];
682     // Timing accumulation should happen only if there was work to do
683     // because getLastRangeTime() gets skipped with empty lists later
684     // which leads to the counter not being reset.
685     bool                bDoTime      = (nb->bDoTime && !h_plist->sci.empty());
686     const DeviceStream& deviceStream = nb->deviceStreams[iloc];
687     cl_plist_t*         d_plist      = nb->plist[iloc];
688
689     if (d_plist->na_c < 0)
690     {
691         d_plist->na_c = h_plist->na_ci;
692     }
693     else
694     {
695         if (d_plist->na_c != h_plist->na_ci)
696         {
697             sprintf(sbuf, "In cu_init_plist: the #atoms per cell has changed (from %d to %d)",
698                     d_plist->na_c, h_plist->na_ci);
699             gmx_incons(sbuf);
700         }
701     }
702
703     gpu_timers_t::Interaction& iTimers = nb->timers->interaction[iloc];
704
705     if (bDoTime)
706     {
707         iTimers.pl_h2d.openTimingRegion(deviceStream);
708         iTimers.didPairlistH2D = true;
709     }
710
711     // TODO most of this function is same in CUDA and OpenCL, move into the header
712     const DeviceContext& deviceContext = nb->dev_rundata->deviceContext_;
713
714     reallocateDeviceBuffer(&d_plist->sci, h_plist->sci.size(), &d_plist->nsci, &d_plist->sci_nalloc,
715                            deviceContext);
716     copyToDeviceBuffer(&d_plist->sci, h_plist->sci.data(), 0, h_plist->sci.size(), deviceStream,
717                        GpuApiCallBehavior::Async, bDoTime ? iTimers.pl_h2d.fetchNextEvent() : nullptr);
718
719     reallocateDeviceBuffer(&d_plist->cj4, h_plist->cj4.size(), &d_plist->ncj4, &d_plist->cj4_nalloc,
720                            deviceContext);
721     copyToDeviceBuffer(&d_plist->cj4, h_plist->cj4.data(), 0, h_plist->cj4.size(), deviceStream,
722                        GpuApiCallBehavior::Async, bDoTime ? iTimers.pl_h2d.fetchNextEvent() : nullptr);
723
724     reallocateDeviceBuffer(&d_plist->imask, h_plist->cj4.size() * c_nbnxnGpuClusterpairSplit,
725                            &d_plist->nimask, &d_plist->imask_nalloc, deviceContext);
726
727     reallocateDeviceBuffer(&d_plist->excl, h_plist->excl.size(), &d_plist->nexcl,
728                            &d_plist->excl_nalloc, deviceContext);
729     copyToDeviceBuffer(&d_plist->excl, h_plist->excl.data(), 0, h_plist->excl.size(), deviceStream,
730                        GpuApiCallBehavior::Async, bDoTime ? iTimers.pl_h2d.fetchNextEvent() : nullptr);
731
732     if (bDoTime)
733     {
734         iTimers.pl_h2d.closeTimingRegion(deviceStream);
735     }
736
737     /* need to prune the pair list during the next step */
738     d_plist->haveFreshList = true;
739 }
740
741 //! This function is documented in the header file
742 void gpu_upload_shiftvec(NbnxmGpu* nb, const nbnxn_atomdata_t* nbatom)
743 {
744     cl_atomdata_t*   adat = nb->atdat;
745     cl_command_queue ls   = nb->deviceStreams[InteractionLocality::Local].stream();
746
747     /* only if we have a dynamic box */
748     if (nbatom->bDynamicBox || !adat->bShiftVecUploaded)
749     {
750         ocl_copy_H2D_async(adat->shift_vec, nbatom->shift_vec.data(), 0,
751                            SHIFTS * sizeof(nbatom->shift_vec[0]), ls, nullptr);
752         adat->bShiftVecUploaded = CL_TRUE;
753     }
754 }
755
756 //! This function is documented in the header file
757 void gpu_init_atomdata(NbnxmGpu* nb, const nbnxn_atomdata_t* nbat)
758 {
759     cl_int              cl_error;
760     int                 nalloc, natoms;
761     bool                realloced;
762     bool                bDoTime      = nb->bDoTime;
763     cl_timers_t*        timers       = nb->timers;
764     cl_atomdata_t*      d_atdat      = nb->atdat;
765     const DeviceStream& deviceStream = nb->deviceStreams[InteractionLocality::Local];
766
767     natoms    = nbat->numAtoms();
768     realloced = false;
769
770     if (bDoTime)
771     {
772         /* time async copy */
773         timers->atdat.openTimingRegion(deviceStream);
774     }
775
776     /* need to reallocate if we have to copy more atoms than the amount of space
777        available and only allocate if we haven't initialized yet, i.e d_atdat->natoms == -1 */
778     if (natoms > d_atdat->nalloc)
779     {
780         nalloc = over_alloc_small(natoms);
781
782         /* free up first if the arrays have already been initialized */
783         if (d_atdat->nalloc != -1)
784         {
785             freeDeviceBuffer(&d_atdat->f);
786             freeDeviceBuffer(&d_atdat->xq);
787             freeDeviceBuffer(&d_atdat->lj_comb);
788             freeDeviceBuffer(&d_atdat->atom_types);
789         }
790
791         d_atdat->f = clCreateBuffer(nb->dev_rundata->deviceContext_.context(),
792                                     CL_MEM_READ_WRITE | CL_MEM_HOST_READ_ONLY,
793                                     nalloc * DIM * sizeof(nbat->out[0].f[0]), nullptr, &cl_error);
794         GMX_RELEASE_ASSERT(cl_error == CL_SUCCESS,
795                            ("clCreateBuffer failed: " + ocl_get_error_string(cl_error)).c_str());
796
797         d_atdat->xq = clCreateBuffer(nb->dev_rundata->deviceContext_.context(),
798                                      CL_MEM_READ_ONLY | CL_MEM_HOST_WRITE_ONLY,
799                                      nalloc * sizeof(cl_float4), nullptr, &cl_error);
800         GMX_RELEASE_ASSERT(cl_error == CL_SUCCESS,
801                            ("clCreateBuffer failed: " + ocl_get_error_string(cl_error)).c_str());
802
803         if (useLjCombRule(nb->nbparam->vdwtype))
804         {
805             d_atdat->lj_comb = clCreateBuffer(nb->dev_rundata->deviceContext_.context(),
806                                               CL_MEM_READ_ONLY | CL_MEM_HOST_WRITE_ONLY,
807                                               nalloc * sizeof(cl_float2), nullptr, &cl_error);
808             GMX_RELEASE_ASSERT(cl_error == CL_SUCCESS,
809                                ("clCreateBuffer failed: " + ocl_get_error_string(cl_error)).c_str());
810         }
811         else
812         {
813             d_atdat->atom_types = clCreateBuffer(nb->dev_rundata->deviceContext_.context(),
814                                                  CL_MEM_READ_ONLY | CL_MEM_HOST_WRITE_ONLY,
815                                                  nalloc * sizeof(int), nullptr, &cl_error);
816             GMX_RELEASE_ASSERT(cl_error == CL_SUCCESS,
817                                ("clCreateBuffer failed: " + ocl_get_error_string(cl_error)).c_str());
818         }
819
820         d_atdat->nalloc = nalloc;
821         realloced       = true;
822     }
823
824     d_atdat->natoms       = natoms;
825     d_atdat->natoms_local = nbat->natoms_local;
826
827     /* need to clear GPU f output if realloc happened */
828     if (realloced)
829     {
830         nbnxn_ocl_clear_f(nb, nalloc);
831     }
832
833     if (useLjCombRule(nb->nbparam->vdwtype))
834     {
835         ocl_copy_H2D_async(d_atdat->lj_comb, nbat->params().lj_comb.data(), 0, natoms * sizeof(cl_float2),
836                            deviceStream.stream(), bDoTime ? timers->atdat.fetchNextEvent() : nullptr);
837     }
838     else
839     {
840         ocl_copy_H2D_async(d_atdat->atom_types, nbat->params().type.data(), 0, natoms * sizeof(int),
841                            deviceStream.stream(), bDoTime ? timers->atdat.fetchNextEvent() : nullptr);
842     }
843
844     if (bDoTime)
845     {
846         timers->atdat.closeTimingRegion(deviceStream);
847     }
848
849     /* kick off the tasks enqueued above to ensure concurrency with the search */
850     cl_error = clFlush(deviceStream.stream());
851     GMX_RELEASE_ASSERT(cl_error == CL_SUCCESS,
852                        ("clFlush failed: " + ocl_get_error_string(cl_error)).c_str());
853 }
854
855 /*! \brief Releases an OpenCL kernel pointer */
856 static void free_kernel(cl_kernel* kernel_ptr)
857 {
858     cl_int gmx_unused cl_error;
859
860     GMX_ASSERT(kernel_ptr, "Need a valid kernel pointer");
861
862     if (*kernel_ptr)
863     {
864         cl_error = clReleaseKernel(*kernel_ptr);
865         GMX_RELEASE_ASSERT(cl_error == CL_SUCCESS,
866                            ("clReleaseKernel failed: " + ocl_get_error_string(cl_error)).c_str());
867
868         *kernel_ptr = nullptr;
869     }
870 }
871
872 /*! \brief Releases a list of OpenCL kernel pointers */
873 static void free_kernels(cl_kernel* kernels, int count)
874 {
875     int i;
876
877     for (i = 0; i < count; i++)
878     {
879         free_kernel(kernels + i);
880     }
881 }
882
883 /*! \brief Free the OpenCL runtime data (context and program).
884  *
885  *  The function releases the OpenCL context and program assuciated with the
886  *  device that the calling PP rank is running on.
887  *
888  *  \param runData [in]  porinter to the structure with runtime data.
889  */
890 static void free_gpu_device_runtime_data(gmx_device_runtime_data_t* runData)
891 {
892     if (runData == nullptr)
893     {
894         return;
895     }
896
897     if (runData->program)
898     {
899         cl_int cl_error = clReleaseProgram(runData->program);
900         GMX_RELEASE_ASSERT(cl_error == CL_SUCCESS,
901                            ("clReleaseProgram failed: " + ocl_get_error_string(cl_error)).c_str());
902         runData->program = nullptr;
903     }
904 }
905
906 //! This function is documented in the header file
907 void gpu_free(NbnxmGpu* nb)
908 {
909     if (nb == nullptr)
910     {
911         return;
912     }
913
914     /* Free kernels */
915     int kernel_count = sizeof(nb->kernel_ener_noprune_ptr) / sizeof(nb->kernel_ener_noprune_ptr[0][0]);
916     free_kernels(nb->kernel_ener_noprune_ptr[0], kernel_count);
917
918     kernel_count = sizeof(nb->kernel_ener_prune_ptr) / sizeof(nb->kernel_ener_prune_ptr[0][0]);
919     free_kernels(nb->kernel_ener_prune_ptr[0], kernel_count);
920
921     kernel_count = sizeof(nb->kernel_noener_noprune_ptr) / sizeof(nb->kernel_noener_noprune_ptr[0][0]);
922     free_kernels(nb->kernel_noener_noprune_ptr[0], kernel_count);
923
924     kernel_count = sizeof(nb->kernel_noener_prune_ptr) / sizeof(nb->kernel_noener_prune_ptr[0][0]);
925     free_kernels(nb->kernel_noener_prune_ptr[0], kernel_count);
926
927     free_kernel(&(nb->kernel_zero_e_fshift));
928
929     /* Free atdat */
930     freeDeviceBuffer(&(nb->atdat->xq));
931     freeDeviceBuffer(&(nb->atdat->f));
932     freeDeviceBuffer(&(nb->atdat->e_lj));
933     freeDeviceBuffer(&(nb->atdat->e_el));
934     freeDeviceBuffer(&(nb->atdat->fshift));
935     freeDeviceBuffer(&(nb->atdat->lj_comb));
936     freeDeviceBuffer(&(nb->atdat->atom_types));
937     freeDeviceBuffer(&(nb->atdat->shift_vec));
938     sfree(nb->atdat);
939
940     /* Free nbparam */
941     freeDeviceBuffer(&(nb->nbparam->nbfp_climg2d));
942     freeDeviceBuffer(&(nb->nbparam->nbfp_comb_climg2d));
943     freeDeviceBuffer(&(nb->nbparam->coulomb_tab_climg2d));
944     sfree(nb->nbparam);
945
946     /* Free plist */
947     auto* plist = nb->plist[InteractionLocality::Local];
948     freeDeviceBuffer(&plist->sci);
949     freeDeviceBuffer(&plist->cj4);
950     freeDeviceBuffer(&plist->imask);
951     freeDeviceBuffer(&plist->excl);
952     sfree(plist);
953     if (nb->bUseTwoStreams)
954     {
955         auto* plist_nl = nb->plist[InteractionLocality::NonLocal];
956         freeDeviceBuffer(&plist_nl->sci);
957         freeDeviceBuffer(&plist_nl->cj4);
958         freeDeviceBuffer(&plist_nl->imask);
959         freeDeviceBuffer(&plist_nl->excl);
960         sfree(plist_nl);
961     }
962
963     /* Free nbst */
964     pfree(nb->nbst.e_lj);
965     nb->nbst.e_lj = nullptr;
966
967     pfree(nb->nbst.e_el);
968     nb->nbst.e_el = nullptr;
969
970     pfree(nb->nbst.fshift);
971     nb->nbst.fshift = nullptr;
972
973     /* Free other events */
974     if (nb->nonlocal_done)
975     {
976         clReleaseEvent(nb->nonlocal_done);
977         nb->nonlocal_done = nullptr;
978     }
979     if (nb->misc_ops_and_local_H2D_done)
980     {
981         clReleaseEvent(nb->misc_ops_and_local_H2D_done);
982         nb->misc_ops_and_local_H2D_done = nullptr;
983     }
984
985     free_gpu_device_runtime_data(nb->dev_rundata);
986     delete nb->dev_rundata;
987
988     /* Free timers and timings */
989     delete nb->timers;
990     sfree(nb->timings);
991     delete nb;
992
993     if (debug)
994     {
995         fprintf(debug, "Cleaned up OpenCL data structures.\n");
996     }
997 }
998
999 //! This function is documented in the header file
1000 gmx_wallclock_gpu_nbnxn_t* gpu_get_timings(NbnxmGpu* nb)
1001 {
1002     return (nb != nullptr && nb->bDoTime) ? nb->timings : nullptr;
1003 }
1004
1005 //! This function is documented in the header file
1006 void gpu_reset_timings(nonbonded_verlet_t* nbv)
1007 {
1008     if (nbv->gpu_nbv && nbv->gpu_nbv->bDoTime)
1009     {
1010         init_timings(nbv->gpu_nbv->timings);
1011     }
1012 }
1013
1014 //! This function is documented in the header file
1015 int gpu_min_ci_balanced(NbnxmGpu* nb)
1016 {
1017     return nb != nullptr ? gpu_min_ci_balanced_factor * nb->deviceInfo->compute_units : 0;
1018 }
1019
1020 //! This function is documented in the header file
1021 gmx_bool gpu_is_kernel_ewald_analytical(const NbnxmGpu* nb)
1022 {
1023     return ((nb->nbparam->eeltype == eelOclEWALD_ANA) || (nb->nbparam->eeltype == eelOclEWALD_ANA_TWIN));
1024 }
1025
1026 } // namespace Nbnxm