c4df4f17115cddfa9d8f727edb03e2680aa22ff1
[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->context, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR,
138        &array_format, tabsize, 1, 0, ftmp, &cl_error);
139      */
140
141     coul_tab = clCreateBuffer(
142             runData->context, CL_MEM_READ_ONLY | CL_MEM_HOST_WRITE_ONLY | CL_MEM_COPY_HOST_PTR,
143             tables.tableF.size() * sizeof(cl_float), const_cast<real*>(tables.tableF.data()), &cl_error);
144     GMX_RELEASE_ASSERT(cl_error == CL_SUCCESS,
145                        ("clCreateBuffer failed: " + ocl_get_error_string(cl_error)).c_str());
146
147     nbp->coulomb_tab_climg2d = coul_tab;
148     nbp->coulomb_tab_scale   = tables.scale;
149 }
150
151
152 /*! \brief Initializes the atomdata structure first time, it only gets filled at
153     pair-search.
154  */
155 static void init_atomdata_first(cl_atomdata_t* ad, int ntypes, gmx_device_runtime_data_t* runData)
156 {
157     cl_int cl_error;
158
159     ad->ntypes = ntypes;
160
161     ad->shift_vec = clCreateBuffer(runData->context, CL_MEM_READ_ONLY | CL_MEM_HOST_WRITE_ONLY,
162                                    SHIFTS * sizeof(nbnxn_atomdata_t::shift_vec[0]), nullptr, &cl_error);
163     GMX_RELEASE_ASSERT(cl_error == CL_SUCCESS,
164                        ("clCreateBuffer failed: " + ocl_get_error_string(cl_error)).c_str());
165     ad->bShiftVecUploaded = CL_FALSE;
166
167     ad->fshift = clCreateBuffer(runData->context, CL_MEM_READ_WRITE | CL_MEM_HOST_READ_ONLY,
168                                 SHIFTS * sizeof(nb_staging_t::fshift[0]), nullptr, &cl_error);
169     GMX_RELEASE_ASSERT(cl_error == CL_SUCCESS,
170                        ("clCreateBuffer failed: " + ocl_get_error_string(cl_error)).c_str());
171
172     ad->e_lj = clCreateBuffer(runData->context, CL_MEM_READ_WRITE | CL_MEM_HOST_READ_ONLY,
173                               sizeof(float), nullptr, &cl_error);
174     GMX_RELEASE_ASSERT(cl_error == CL_SUCCESS,
175                        ("clCreateBuffer failed: " + ocl_get_error_string(cl_error)).c_str());
176
177     ad->e_el = clCreateBuffer(runData->context, CL_MEM_READ_WRITE | CL_MEM_HOST_READ_ONLY,
178                               sizeof(float), nullptr, &cl_error);
179     GMX_RELEASE_ASSERT(cl_error == CL_SUCCESS,
180                        ("clCreateBuffer failed: " + ocl_get_error_string(cl_error)).c_str());
181
182     /* initialize to nullptr pointers to data that is not allocated here and will
183        need reallocation in nbnxn_gpu_init_atomdata */
184     ad->xq = nullptr;
185     ad->f  = nullptr;
186
187     /* size -1 indicates that the respective array hasn't been initialized yet */
188     ad->natoms = -1;
189     ad->nalloc = -1;
190 }
191
192 /*! \brief Copies all parameters related to the cut-off from ic to nbp
193  */
194 static void set_cutoff_parameters(cl_nbparam_t* nbp, const interaction_const_t* ic, const PairlistParams& listParams)
195 {
196     nbp->ewald_beta        = ic->ewaldcoeff_q;
197     nbp->sh_ewald          = ic->sh_ewald;
198     nbp->epsfac            = ic->epsfac;
199     nbp->two_k_rf          = 2.0 * ic->k_rf;
200     nbp->c_rf              = ic->c_rf;
201     nbp->rvdw_sq           = ic->rvdw * ic->rvdw;
202     nbp->rcoulomb_sq       = ic->rcoulomb * ic->rcoulomb;
203     nbp->rlistOuter_sq     = listParams.rlistOuter * listParams.rlistOuter;
204     nbp->rlistInner_sq     = listParams.rlistInner * listParams.rlistInner;
205     nbp->useDynamicPruning = listParams.useDynamicPruning;
206
207     nbp->sh_lj_ewald   = ic->sh_lj_ewald;
208     nbp->ewaldcoeff_lj = ic->ewaldcoeff_lj;
209
210     nbp->rvdw_switch      = ic->rvdw_switch;
211     nbp->dispersion_shift = ic->dispersion_shift;
212     nbp->repulsion_shift  = ic->repulsion_shift;
213     nbp->vdw_switch       = ic->vdw_switch;
214 }
215
216 /*! \brief Returns the kinds of electrostatics and Vdw OpenCL
217  *  kernels that will be used.
218  *
219  * Respectively, these values are from enum eelOcl and enum
220  * evdwOcl. */
221 static void map_interaction_types_to_gpu_kernel_flavors(const interaction_const_t* ic,
222                                                         int                        combRule,
223                                                         int*                       gpu_eeltype,
224                                                         int*                       gpu_vdwtype)
225 {
226     if (ic->vdwtype == evdwCUT)
227     {
228         switch (ic->vdw_modifier)
229         {
230             case eintmodNONE:
231             case eintmodPOTSHIFT:
232                 switch (combRule)
233                 {
234                     case ljcrNONE: *gpu_vdwtype = evdwOclCUT; break;
235                     case ljcrGEOM: *gpu_vdwtype = evdwOclCUTCOMBGEOM; break;
236                     case ljcrLB: *gpu_vdwtype = evdwOclCUTCOMBLB; break;
237                     default:
238                         gmx_incons(
239                                 "The requested LJ combination rule is not implemented in the "
240                                 "OpenCL GPU accelerated kernels!");
241                 }
242                 break;
243             case eintmodFORCESWITCH: *gpu_vdwtype = evdwOclFSWITCH; break;
244             case eintmodPOTSWITCH: *gpu_vdwtype = evdwOclPSWITCH; break;
245             default:
246                 gmx_incons(
247                         "The requested VdW interaction modifier is not implemented in the GPU "
248                         "accelerated kernels!");
249         }
250     }
251     else if (ic->vdwtype == evdwPME)
252     {
253         if (ic->ljpme_comb_rule == ljcrGEOM)
254         {
255             *gpu_vdwtype = evdwOclEWALDGEOM;
256         }
257         else
258         {
259             *gpu_vdwtype = evdwOclEWALDLB;
260         }
261     }
262     else
263     {
264         gmx_incons("The requested VdW type is not implemented in the GPU accelerated kernels!");
265     }
266
267     if (ic->eeltype == eelCUT)
268     {
269         *gpu_eeltype = eelOclCUT;
270     }
271     else if (EEL_RF(ic->eeltype))
272     {
273         *gpu_eeltype = eelOclRF;
274     }
275     else if ((EEL_PME(ic->eeltype) || ic->eeltype == eelEWALD))
276     {
277         *gpu_eeltype = nbnxn_gpu_pick_ewald_kernel_type(*ic);
278     }
279     else
280     {
281         /* Shouldn't happen, as this is checked when choosing Verlet-scheme */
282         gmx_incons(
283                 "The requested electrostatics type is not implemented in the GPU accelerated "
284                 "kernels!");
285     }
286 }
287
288 /*! \brief Initializes the nonbonded parameter data structure.
289  */
290 static void init_nbparam(cl_nbparam_t*                    nbp,
291                          const interaction_const_t*       ic,
292                          const PairlistParams&            listParams,
293                          const nbnxn_atomdata_t::Params&  nbatParams,
294                          const gmx_device_runtime_data_t* runData)
295 {
296     cl_int cl_error;
297
298     set_cutoff_parameters(nbp, ic, listParams);
299
300     map_interaction_types_to_gpu_kernel_flavors(ic, nbatParams.comb_rule, &(nbp->eeltype), &(nbp->vdwtype));
301
302     if (ic->vdwtype == evdwPME)
303     {
304         if (ic->ljpme_comb_rule == ljcrGEOM)
305         {
306             GMX_ASSERT(nbatParams.comb_rule == ljcrGEOM, "Combination rule mismatch!");
307         }
308         else
309         {
310             GMX_ASSERT(nbatParams.comb_rule == ljcrLB, "Combination rule mismatch!");
311         }
312     }
313     /* generate table for PME */
314     nbp->coulomb_tab_climg2d = nullptr;
315     if (nbp->eeltype == eelOclEWALD_TAB || nbp->eeltype == eelOclEWALD_TAB_TWIN)
316     {
317         GMX_RELEASE_ASSERT(ic->coulombEwaldTables, "Need valid Coulomb Ewald correction tables");
318         init_ewald_coulomb_force_table(*ic->coulombEwaldTables, nbp, runData);
319     }
320     else
321     // TODO: improvement needed.
322     // The image2d is created here even if eeltype is not eelCuEWALD_TAB or eelCuEWALD_TAB_TWIN
323     // because the OpenCL kernels don't accept nullptr values for image2D parameters.
324     {
325         /* Switched from using textures to using buffers */
326         // TODO: decide which alternative is most efficient - textures or buffers.
327         /*
328            cl_image_format array_format;
329
330            array_format.image_channel_data_type = CL_FLOAT;
331            array_format.image_channel_order     = CL_R;
332
333            nbp->coulomb_tab_climg2d = clCreateImage2D(runData->context, CL_MEM_READ_WRITE,
334             &array_format, 1, 1, 0, nullptr, &cl_error);
335          */
336
337         nbp->coulomb_tab_climg2d = clCreateBuffer(runData->context, CL_MEM_READ_ONLY,
338                                                   sizeof(cl_float), nullptr, &cl_error);
339         GMX_RELEASE_ASSERT(cl_error == CL_SUCCESS,
340                            ("clCreateBuffer failed: " + ocl_get_error_string(cl_error)).c_str());
341     }
342
343     const int nnbfp      = 2 * nbatParams.numTypes * nbatParams.numTypes;
344     const int nnbfp_comb = 2 * nbatParams.numTypes;
345
346     {
347         /* Switched from using textures to using buffers */
348         // TODO: decide which alternative is most efficient - textures or buffers.
349         /*
350            cl_image_format array_format;
351
352            array_format.image_channel_data_type = CL_FLOAT;
353            array_format.image_channel_order     = CL_R;
354
355            nbp->nbfp_climg2d = clCreateImage2D(runData->context, CL_MEM_READ_ONLY |
356            CL_MEM_COPY_HOST_PTR, &array_format, nnbfp, 1, 0, nbat->nbfp, &cl_error);
357          */
358
359         nbp->nbfp_climg2d = clCreateBuffer(
360                 runData->context, CL_MEM_READ_ONLY | CL_MEM_HOST_WRITE_ONLY | CL_MEM_COPY_HOST_PTR,
361                 nnbfp * sizeof(cl_float), const_cast<float*>(nbatParams.nbfp.data()), &cl_error);
362         GMX_RELEASE_ASSERT(cl_error == CL_SUCCESS,
363                            ("clCreateBuffer failed: " + ocl_get_error_string(cl_error)).c_str());
364
365         if (ic->vdwtype == evdwPME)
366         {
367             /* Switched from using textures to using buffers */
368             // TODO: decide which alternative is most efficient - textures or buffers.
369             /*  nbp->nbfp_comb_climg2d = clCreateImage2D(runData->context, CL_MEM_READ_WRITE |
370                CL_MEM_COPY_HOST_PTR, &array_format, nnbfp_comb, 1, 0, nbat->nbfp_comb, &cl_error);*/
371             nbp->nbfp_comb_climg2d = clCreateBuffer(
372                     runData->context, CL_MEM_READ_ONLY | CL_MEM_HOST_WRITE_ONLY | CL_MEM_COPY_HOST_PTR,
373                     nnbfp_comb * sizeof(cl_float), const_cast<float*>(nbatParams.nbfp_comb.data()),
374                     &cl_error);
375             GMX_RELEASE_ASSERT(cl_error == CL_SUCCESS,
376                                ("clCreateBuffer failed: " + ocl_get_error_string(cl_error)).c_str());
377         }
378         else
379         {
380             // TODO: improvement needed.
381             // The image2d is created here even if vdwtype is not evdwPME because the OpenCL kernels
382             // don't accept nullptr values for image2D parameters.
383             /* Switched from using textures to using buffers */
384             // TODO: decide which alternative is most efficient - textures or buffers.
385             /* nbp->nbfp_comb_climg2d = clCreateImage2D(runData->context, CL_MEM_READ_WRITE,
386                 &array_format, 1, 1, 0, nullptr, &cl_error);*/
387             nbp->nbfp_comb_climg2d = clCreateBuffer(runData->context, CL_MEM_READ_ONLY,
388                                                     sizeof(cl_float), nullptr, &cl_error);
389             GMX_RELEASE_ASSERT(cl_error == CL_SUCCESS,
390                                ("clCreateBuffer failed: " + ocl_get_error_string(cl_error)).c_str());
391         }
392     }
393 }
394
395 //! This function is documented in the header file
396 void gpu_pme_loadbal_update_param(const nonbonded_verlet_t* nbv, const interaction_const_t* ic)
397 {
398     if (!nbv || !nbv->useGpu())
399     {
400         return;
401     }
402     NbnxmGpu*     nb  = nbv->gpu_nbv;
403     cl_nbparam_t* nbp = nb->nbparam;
404
405     set_cutoff_parameters(nbp, ic, nbv->pairlistSets().params());
406
407     nbp->eeltype = nbnxn_gpu_pick_ewald_kernel_type(*ic);
408
409     GMX_RELEASE_ASSERT(ic->coulombEwaldTables, "Need valid Coulomb Ewald correction tables");
410     init_ewald_coulomb_force_table(*ic->coulombEwaldTables, nbp, nb->dev_rundata);
411 }
412
413 /*! \brief Initializes the pair list data structure.
414  */
415 static void init_plist(cl_plist_t* pl)
416 {
417     /* initialize to nullptr pointers to data that is not allocated here and will
418        need reallocation in nbnxn_gpu_init_pairlist */
419     pl->sci   = nullptr;
420     pl->cj4   = nullptr;
421     pl->imask = nullptr;
422     pl->excl  = nullptr;
423
424     /* size -1 indicates that the respective array hasn't been initialized yet */
425     pl->na_c          = -1;
426     pl->nsci          = -1;
427     pl->sci_nalloc    = -1;
428     pl->ncj4          = -1;
429     pl->cj4_nalloc    = -1;
430     pl->nimask        = -1;
431     pl->imask_nalloc  = -1;
432     pl->nexcl         = -1;
433     pl->excl_nalloc   = -1;
434     pl->haveFreshList = false;
435 }
436
437 /*! \brief Initializes the timings data structure.
438  */
439 static void init_timings(gmx_wallclock_gpu_nbnxn_t* t)
440 {
441     int i, j;
442
443     t->nb_h2d_t = 0.0;
444     t->nb_d2h_t = 0.0;
445     t->nb_c     = 0;
446     t->pl_h2d_t = 0.0;
447     t->pl_h2d_c = 0;
448     for (i = 0; i < 2; i++)
449     {
450         for (j = 0; j < 2; j++)
451         {
452             t->ktime[i][j].t = 0.0;
453             t->ktime[i][j].c = 0;
454         }
455     }
456
457     t->pruneTime.c        = 0;
458     t->pruneTime.t        = 0.0;
459     t->dynamicPruneTime.c = 0;
460     t->dynamicPruneTime.t = 0.0;
461 }
462
463
464 //! OpenCL notification callback function
465 static void CL_CALLBACK ocl_notify_fn(const char* pErrInfo,
466                                       const void gmx_unused* private_info,
467                                       size_t gmx_unused cb,
468                                       void gmx_unused* user_data)
469 {
470     if (pErrInfo != nullptr)
471     {
472         printf("%s\n", pErrInfo); // Print error/hint
473     }
474 }
475
476 /*! \brief Creates context for OpenCL GPU given by \p mygpu
477  *
478  * A fatal error results if creation fails.
479  *
480  * \param[inout] runtimeData runtime data including program and context
481  * \param[in]    devInfo     device info struct
482  * \param[in]    rank        MPI rank (for error reporting)
483  */
484 static void nbnxn_gpu_create_context(gmx_device_runtime_data_t* runtimeData,
485                                      const gmx_device_info_t*   devInfo,
486                                      int                        rank)
487 {
488     cl_context_properties context_properties[5];
489     cl_platform_id        platform_id;
490     cl_device_id          device_id;
491     cl_context            context;
492     cl_int                cl_error;
493
494     GMX_ASSERT(runtimeData, "Need a valid runtimeData object");
495     GMX_ASSERT(devInfo, "Need a valid device info object");
496
497     platform_id = devInfo->ocl_gpu_id.ocl_platform_id;
498     device_id   = devInfo->ocl_gpu_id.ocl_device_id;
499
500     int i                   = 0;
501     context_properties[i++] = CL_CONTEXT_PLATFORM;
502     context_properties[i++] = reinterpret_cast<cl_context_properties>(platform_id);
503     if (getenv("GMX_OCL_SHOW_DIAGNOSTICS"))
504     {
505         context_properties[i++] = CL_CONTEXT_SHOW_DIAGNOSTICS_INTEL;
506         context_properties[i++] =
507                 CL_CONTEXT_DIAGNOSTICS_LEVEL_BAD_INTEL | CL_CONTEXT_DIAGNOSTICS_LEVEL_NEUTRAL_INTEL;
508     }
509     context_properties[i++] = 0; /* Terminates the list of properties */
510
511     context = clCreateContext(context_properties, 1, &device_id, ocl_notify_fn, nullptr, &cl_error);
512     if (CL_SUCCESS != cl_error)
513     {
514         gmx_fatal(FARGS, "On rank %d failed to create context for GPU #%s:\n OpenCL error %d: %s",
515                   rank, devInfo->device_name, cl_error, ocl_get_error_string(cl_error).c_str());
516     }
517
518     runtimeData->context = context;
519 }
520
521 /*! \brief Initializes the OpenCL kernel pointers of the nbnxn_ocl_ptr_t input data structure. */
522 static cl_kernel nbnxn_gpu_create_kernel(NbnxmGpu* nb, const char* kernel_name)
523 {
524     cl_kernel kernel;
525     cl_int    cl_error;
526
527     kernel = clCreateKernel(nb->dev_rundata->program, kernel_name, &cl_error);
528     if (CL_SUCCESS != cl_error)
529     {
530         gmx_fatal(FARGS, "Failed to create kernel '%s' for GPU #%s: OpenCL error %d", kernel_name,
531                   nb->dev_info->device_name, cl_error);
532     }
533
534     return kernel;
535 }
536
537 /*! \brief Clears nonbonded shift force output array and energy outputs on the GPU.
538  */
539 static void nbnxn_ocl_clear_e_fshift(NbnxmGpu* nb)
540 {
541
542     cl_int           cl_error;
543     cl_atomdata_t*   adat = nb->atdat;
544     cl_command_queue ls   = nb->stream[InteractionLocality::Local];
545
546     size_t local_work_size[3]  = { 1, 1, 1 };
547     size_t global_work_size[3] = { 1, 1, 1 };
548
549     cl_int shifts = SHIFTS * 3;
550
551     cl_int arg_no;
552
553     cl_kernel zero_e_fshift = nb->kernel_zero_e_fshift;
554
555     local_work_size[0] = 64;
556     // Round the total number of threads up from the array size
557     global_work_size[0] = ((shifts + local_work_size[0] - 1) / local_work_size[0]) * local_work_size[0];
558
559     arg_no   = 0;
560     cl_error = clSetKernelArg(zero_e_fshift, arg_no++, sizeof(cl_mem), &(adat->fshift));
561     cl_error |= clSetKernelArg(zero_e_fshift, arg_no++, sizeof(cl_mem), &(adat->e_lj));
562     cl_error |= clSetKernelArg(zero_e_fshift, arg_no++, sizeof(cl_mem), &(adat->e_el));
563     cl_error |= clSetKernelArg(zero_e_fshift, arg_no++, sizeof(cl_uint), &shifts);
564     GMX_ASSERT(cl_error == CL_SUCCESS, ocl_get_error_string(cl_error).c_str());
565
566     cl_error = clEnqueueNDRangeKernel(ls, zero_e_fshift, 3, nullptr, global_work_size,
567                                       local_work_size, 0, nullptr, nullptr);
568     GMX_ASSERT(cl_error == CL_SUCCESS, ocl_get_error_string(cl_error).c_str());
569 }
570
571 /*! \brief Initializes the OpenCL kernel pointers of the nbnxn_ocl_ptr_t input data structure. */
572 static void nbnxn_gpu_init_kernels(NbnxmGpu* nb)
573 {
574     /* Init to 0 main kernel arrays */
575     /* They will be later on initialized in select_nbnxn_kernel */
576     // TODO: consider always creating all variants of the kernels here so that there is no
577     // need for late call to clCreateKernel -- if that gives any advantage?
578     memset(nb->kernel_ener_noprune_ptr, 0, sizeof(nb->kernel_ener_noprune_ptr));
579     memset(nb->kernel_ener_prune_ptr, 0, sizeof(nb->kernel_ener_prune_ptr));
580     memset(nb->kernel_noener_noprune_ptr, 0, sizeof(nb->kernel_noener_noprune_ptr));
581     memset(nb->kernel_noener_prune_ptr, 0, sizeof(nb->kernel_noener_prune_ptr));
582
583     /* Init pruning kernels
584      *
585      * TODO: we could avoid creating kernels if dynamic pruning is turned off,
586      * but ATM that depends on force flags not passed into the initialization.
587      */
588     nb->kernel_pruneonly[epruneFirst] = nbnxn_gpu_create_kernel(nb, "nbnxn_kernel_prune_opencl");
589     nb->kernel_pruneonly[epruneRolling] =
590             nbnxn_gpu_create_kernel(nb, "nbnxn_kernel_prune_rolling_opencl");
591
592     /* Init auxiliary kernels */
593     nb->kernel_zero_e_fshift = nbnxn_gpu_create_kernel(nb, "zero_e_fshift");
594 }
595
596 /*! \brief Initializes simulation constant data.
597  *
598  *  Initializes members of the atomdata and nbparam structs and
599  *  clears e/fshift output buffers.
600  */
601 static void nbnxn_ocl_init_const(NbnxmGpu*                       nb,
602                                  const interaction_const_t*      ic,
603                                  const PairlistParams&           listParams,
604                                  const nbnxn_atomdata_t::Params& nbatParams)
605 {
606     init_atomdata_first(nb->atdat, nbatParams.numTypes, nb->dev_rundata);
607     init_nbparam(nb->nbparam, ic, listParams, nbatParams, nb->dev_rundata);
608 }
609
610
611 //! This function is documented in the header file
612 NbnxmGpu* gpu_init(const gmx_device_info_t*   deviceInfo,
613                    const interaction_const_t* ic,
614                    const PairlistParams&      listParams,
615                    const nbnxn_atomdata_t*    nbat,
616                    const int                  rank,
617                    const bool                 bLocalAndNonlocal)
618 {
619     cl_int                      cl_error;
620     cl_command_queue_properties queue_properties;
621
622     GMX_ASSERT(ic, "Need a valid interaction constants object");
623
624     auto nb = new NbnxmGpu;
625     snew(nb->atdat, 1);
626     snew(nb->nbparam, 1);
627     snew(nb->plist[InteractionLocality::Local], 1);
628     if (bLocalAndNonlocal)
629     {
630         snew(nb->plist[InteractionLocality::NonLocal], 1);
631     }
632
633     nb->bUseTwoStreams = bLocalAndNonlocal;
634
635     nb->timers = new cl_timers_t();
636     snew(nb->timings, 1);
637
638     /* set device info, just point it to the right GPU among the detected ones */
639     nb->dev_info = deviceInfo;
640     snew(nb->dev_rundata, 1);
641
642     /* init nbst */
643     pmalloc(reinterpret_cast<void**>(&nb->nbst.e_lj), sizeof(*nb->nbst.e_lj));
644     pmalloc(reinterpret_cast<void**>(&nb->nbst.e_el), sizeof(*nb->nbst.e_el));
645     pmalloc(reinterpret_cast<void**>(&nb->nbst.fshift), SHIFTS * sizeof(*nb->nbst.fshift));
646
647     init_plist(nb->plist[InteractionLocality::Local]);
648
649     /* OpenCL timing disabled if GMX_DISABLE_GPU_TIMING is defined. */
650     nb->bDoTime = (getenv("GMX_DISABLE_GPU_TIMING") == nullptr);
651
652     /* Create queues only after bDoTime has been initialized */
653     if (nb->bDoTime)
654     {
655         queue_properties = CL_QUEUE_PROFILING_ENABLE;
656     }
657     else
658     {
659         queue_properties = 0;
660     }
661
662     nbnxn_gpu_create_context(nb->dev_rundata, nb->dev_info, rank);
663
664     /* local/non-local GPU streams */
665     nb->stream[InteractionLocality::Local] = clCreateCommandQueue(
666             nb->dev_rundata->context, nb->dev_info->ocl_gpu_id.ocl_device_id, queue_properties, &cl_error);
667     if (CL_SUCCESS != cl_error)
668     {
669         gmx_fatal(FARGS, "On rank %d failed to create context for GPU #%s: OpenCL error %d", rank,
670                   nb->dev_info->device_name, cl_error);
671     }
672
673     if (nb->bUseTwoStreams)
674     {
675         init_plist(nb->plist[InteractionLocality::NonLocal]);
676
677         nb->stream[InteractionLocality::NonLocal] =
678                 clCreateCommandQueue(nb->dev_rundata->context, nb->dev_info->ocl_gpu_id.ocl_device_id,
679                                      queue_properties, &cl_error);
680         if (CL_SUCCESS != cl_error)
681         {
682             gmx_fatal(FARGS, "On rank %d failed to create context for GPU #%s: OpenCL error %d",
683                       rank, nb->dev_info->device_name, cl_error);
684         }
685     }
686
687     if (nb->bDoTime)
688     {
689         init_timings(nb->timings);
690     }
691
692     nbnxn_ocl_init_const(nb, ic, listParams, nbat->params());
693
694     /* Enable LJ param manual prefetch for AMD or Intel or if we request through env. var.
695      * TODO: decide about NVIDIA
696      */
697     nb->bPrefetchLjParam = (getenv("GMX_OCL_DISABLE_I_PREFETCH") == nullptr)
698                            && ((nb->dev_info->deviceVendor == DeviceVendor::Amd)
699                                || (nb->dev_info->deviceVendor == DeviceVendor::Intel)
700                                || (getenv("GMX_OCL_ENABLE_I_PREFETCH") != nullptr));
701
702     /* NOTE: in CUDA we pick L1 cache configuration for the nbnxn kernels here,
703      * but sadly this is not supported in OpenCL (yet?). Consider adding it if
704      * it becomes supported.
705      */
706     nbnxn_gpu_compile_kernels(nb);
707     nbnxn_gpu_init_kernels(nb);
708
709     /* clear energy and shift force outputs */
710     nbnxn_ocl_clear_e_fshift(nb);
711
712     if (debug)
713     {
714         fprintf(debug, "Initialized OpenCL data structures.\n");
715     }
716
717     return nb;
718 }
719
720 /*! \brief Clears the first natoms_clear elements of the GPU nonbonded force output array.
721  */
722 static void nbnxn_ocl_clear_f(NbnxmGpu* nb, int natoms_clear)
723 {
724     if (natoms_clear == 0)
725     {
726         return;
727     }
728
729     cl_int gmx_used_in_debug cl_error;
730
731     cl_atomdata_t*   atomData = nb->atdat;
732     cl_command_queue ls       = nb->stream[InteractionLocality::Local];
733     cl_float         value    = 0.0F;
734
735     cl_error = clEnqueueFillBuffer(ls, atomData->f, &value, sizeof(cl_float), 0,
736                                    natoms_clear * sizeof(rvec), 0, nullptr, nullptr);
737     GMX_RELEASE_ASSERT(cl_error == CL_SUCCESS,
738                        ("clEnqueueFillBuffer failed: " + ocl_get_error_string(cl_error)).c_str());
739 }
740
741 //! This function is documented in the header file
742 void gpu_clear_outputs(NbnxmGpu* nb, bool computeVirial)
743 {
744     nbnxn_ocl_clear_f(nb, nb->atdat->natoms);
745     /* clear shift force array and energies if the outputs were
746        used in the current step */
747     if (computeVirial)
748     {
749         nbnxn_ocl_clear_e_fshift(nb);
750     }
751
752     /* kick off buffer clearing kernel to ensure concurrency with constraints/update */
753     cl_int gmx_unused cl_error;
754     cl_error = clFlush(nb->stream[InteractionLocality::Local]);
755     GMX_ASSERT(cl_error == CL_SUCCESS, ("clFlush failed: " + ocl_get_error_string(cl_error)).c_str());
756 }
757
758 //! This function is documented in the header file
759 void gpu_init_pairlist(NbnxmGpu* nb, const NbnxnPairlistGpu* h_plist, const InteractionLocality iloc)
760 {
761     char sbuf[STRLEN];
762     // Timing accumulation should happen only if there was work to do
763     // because getLastRangeTime() gets skipped with empty lists later
764     // which leads to the counter not being reset.
765     bool             bDoTime = (nb->bDoTime && !h_plist->sci.empty());
766     cl_command_queue stream  = nb->stream[iloc];
767     cl_plist_t*      d_plist = nb->plist[iloc];
768
769     if (d_plist->na_c < 0)
770     {
771         d_plist->na_c = h_plist->na_ci;
772     }
773     else
774     {
775         if (d_plist->na_c != h_plist->na_ci)
776         {
777             sprintf(sbuf, "In cu_init_plist: the #atoms per cell has changed (from %d to %d)",
778                     d_plist->na_c, h_plist->na_ci);
779             gmx_incons(sbuf);
780         }
781     }
782
783     gpu_timers_t::Interaction& iTimers = nb->timers->interaction[iloc];
784
785     if (bDoTime)
786     {
787         iTimers.pl_h2d.openTimingRegion(stream);
788         iTimers.didPairlistH2D = true;
789     }
790
791     // TODO most of this function is same in CUDA and OpenCL, move into the header
792     DeviceContext context = nb->dev_rundata->context;
793
794     reallocateDeviceBuffer(&d_plist->sci, h_plist->sci.size(), &d_plist->nsci, &d_plist->sci_nalloc, context);
795     copyToDeviceBuffer(&d_plist->sci, h_plist->sci.data(), 0, h_plist->sci.size(), stream,
796                        GpuApiCallBehavior::Async, bDoTime ? iTimers.pl_h2d.fetchNextEvent() : nullptr);
797
798     reallocateDeviceBuffer(&d_plist->cj4, h_plist->cj4.size(), &d_plist->ncj4, &d_plist->cj4_nalloc, context);
799     copyToDeviceBuffer(&d_plist->cj4, h_plist->cj4.data(), 0, h_plist->cj4.size(), stream,
800                        GpuApiCallBehavior::Async, bDoTime ? iTimers.pl_h2d.fetchNextEvent() : nullptr);
801
802     reallocateDeviceBuffer(&d_plist->imask, h_plist->cj4.size() * c_nbnxnGpuClusterpairSplit,
803                            &d_plist->nimask, &d_plist->imask_nalloc, context);
804
805     reallocateDeviceBuffer(&d_plist->excl, h_plist->excl.size(), &d_plist->nexcl,
806                            &d_plist->excl_nalloc, context);
807     copyToDeviceBuffer(&d_plist->excl, h_plist->excl.data(), 0, h_plist->excl.size(), stream,
808                        GpuApiCallBehavior::Async, bDoTime ? iTimers.pl_h2d.fetchNextEvent() : nullptr);
809
810     if (bDoTime)
811     {
812         iTimers.pl_h2d.closeTimingRegion(stream);
813     }
814
815     /* need to prune the pair list during the next step */
816     d_plist->haveFreshList = true;
817 }
818
819 //! This function is documented in the header file
820 void gpu_upload_shiftvec(NbnxmGpu* nb, const nbnxn_atomdata_t* nbatom)
821 {
822     cl_atomdata_t*   adat = nb->atdat;
823     cl_command_queue ls   = nb->stream[InteractionLocality::Local];
824
825     /* only if we have a dynamic box */
826     if (nbatom->bDynamicBox || !adat->bShiftVecUploaded)
827     {
828         ocl_copy_H2D_async(adat->shift_vec, nbatom->shift_vec.data(), 0,
829                            SHIFTS * sizeof(nbatom->shift_vec[0]), ls, nullptr);
830         adat->bShiftVecUploaded = CL_TRUE;
831     }
832 }
833
834 //! This function is documented in the header file
835 void gpu_init_atomdata(NbnxmGpu* nb, const nbnxn_atomdata_t* nbat)
836 {
837     cl_int           cl_error;
838     int              nalloc, natoms;
839     bool             realloced;
840     bool             bDoTime = nb->bDoTime;
841     cl_timers_t*     timers  = nb->timers;
842     cl_atomdata_t*   d_atdat = nb->atdat;
843     cl_command_queue ls      = nb->stream[InteractionLocality::Local];
844
845     natoms    = nbat->numAtoms();
846     realloced = false;
847
848     if (bDoTime)
849     {
850         /* time async copy */
851         timers->atdat.openTimingRegion(ls);
852     }
853
854     /* need to reallocate if we have to copy more atoms than the amount of space
855        available and only allocate if we haven't initialized yet, i.e d_atdat->natoms == -1 */
856     if (natoms > d_atdat->nalloc)
857     {
858         nalloc = over_alloc_small(natoms);
859
860         /* free up first if the arrays have already been initialized */
861         if (d_atdat->nalloc != -1)
862         {
863             freeDeviceBuffer(&d_atdat->f);
864             freeDeviceBuffer(&d_atdat->xq);
865             freeDeviceBuffer(&d_atdat->lj_comb);
866             freeDeviceBuffer(&d_atdat->atom_types);
867         }
868
869         d_atdat->f = clCreateBuffer(nb->dev_rundata->context, CL_MEM_READ_WRITE | CL_MEM_HOST_READ_ONLY,
870                                     nalloc * DIM * sizeof(nbat->out[0].f[0]), nullptr, &cl_error);
871         GMX_RELEASE_ASSERT(cl_error == CL_SUCCESS,
872                            ("clCreateBuffer failed: " + ocl_get_error_string(cl_error)).c_str());
873
874         d_atdat->xq = clCreateBuffer(nb->dev_rundata->context, CL_MEM_READ_ONLY | CL_MEM_HOST_WRITE_ONLY,
875                                      nalloc * sizeof(cl_float4), nullptr, &cl_error);
876         GMX_RELEASE_ASSERT(cl_error == CL_SUCCESS,
877                            ("clCreateBuffer failed: " + ocl_get_error_string(cl_error)).c_str());
878
879         if (useLjCombRule(nb->nbparam->vdwtype))
880         {
881             d_atdat->lj_comb = clCreateBuffer(nb->dev_rundata->context,
882                                               CL_MEM_READ_ONLY | CL_MEM_HOST_WRITE_ONLY,
883                                               nalloc * sizeof(cl_float2), nullptr, &cl_error);
884             GMX_RELEASE_ASSERT(cl_error == CL_SUCCESS,
885                                ("clCreateBuffer failed: " + ocl_get_error_string(cl_error)).c_str());
886         }
887         else
888         {
889             d_atdat->atom_types = clCreateBuffer(nb->dev_rundata->context,
890                                                  CL_MEM_READ_ONLY | CL_MEM_HOST_WRITE_ONLY,
891                                                  nalloc * sizeof(int), nullptr, &cl_error);
892             GMX_RELEASE_ASSERT(cl_error == CL_SUCCESS,
893                                ("clCreateBuffer failed: " + ocl_get_error_string(cl_error)).c_str());
894         }
895
896         d_atdat->nalloc = nalloc;
897         realloced       = true;
898     }
899
900     d_atdat->natoms       = natoms;
901     d_atdat->natoms_local = nbat->natoms_local;
902
903     /* need to clear GPU f output if realloc happened */
904     if (realloced)
905     {
906         nbnxn_ocl_clear_f(nb, nalloc);
907     }
908
909     if (useLjCombRule(nb->nbparam->vdwtype))
910     {
911         ocl_copy_H2D_async(d_atdat->lj_comb, nbat->params().lj_comb.data(), 0, natoms * sizeof(cl_float2),
912                            ls, bDoTime ? timers->atdat.fetchNextEvent() : nullptr);
913     }
914     else
915     {
916         ocl_copy_H2D_async(d_atdat->atom_types, nbat->params().type.data(), 0, natoms * sizeof(int),
917                            ls, bDoTime ? timers->atdat.fetchNextEvent() : nullptr);
918     }
919
920     if (bDoTime)
921     {
922         timers->atdat.closeTimingRegion(ls);
923     }
924
925     /* kick off the tasks enqueued above to ensure concurrency with the search */
926     cl_error = clFlush(ls);
927     GMX_RELEASE_ASSERT(cl_error == CL_SUCCESS,
928                        ("clFlush failed: " + ocl_get_error_string(cl_error)).c_str());
929 }
930
931 /*! \brief Releases an OpenCL kernel pointer */
932 static void free_kernel(cl_kernel* kernel_ptr)
933 {
934     cl_int gmx_unused cl_error;
935
936     GMX_ASSERT(kernel_ptr, "Need a valid kernel pointer");
937
938     if (*kernel_ptr)
939     {
940         cl_error = clReleaseKernel(*kernel_ptr);
941         GMX_RELEASE_ASSERT(cl_error == CL_SUCCESS,
942                            ("clReleaseKernel failed: " + ocl_get_error_string(cl_error)).c_str());
943
944         *kernel_ptr = nullptr;
945     }
946 }
947
948 /*! \brief Releases a list of OpenCL kernel pointers */
949 static void free_kernels(cl_kernel* kernels, int count)
950 {
951     int i;
952
953     for (i = 0; i < count; i++)
954     {
955         free_kernel(kernels + i);
956     }
957 }
958
959 /*! \brief Free the OpenCL runtime data (context and program).
960  *
961  *  The function releases the OpenCL context and program assuciated with the
962  *  device that the calling PP rank is running on.
963  *
964  *  \param runData [in]  porinter to the structure with runtime data.
965  */
966 static void free_gpu_device_runtime_data(gmx_device_runtime_data_t* runData)
967 {
968     if (runData == nullptr)
969     {
970         return;
971     }
972
973     cl_int gmx_unused cl_error;
974
975     if (runData->context)
976     {
977         cl_error = clReleaseContext(runData->context);
978         GMX_RELEASE_ASSERT(cl_error == CL_SUCCESS,
979                            ("clReleaseContext failed: " + ocl_get_error_string(cl_error)).c_str());
980         runData->context = nullptr;
981     }
982
983     if (runData->program)
984     {
985         cl_error = clReleaseProgram(runData->program);
986         GMX_RELEASE_ASSERT(cl_error == CL_SUCCESS,
987                            ("clReleaseProgram failed: " + ocl_get_error_string(cl_error)).c_str());
988         runData->program = nullptr;
989     }
990 }
991
992 //! This function is documented in the header file
993 void gpu_free(NbnxmGpu* nb)
994 {
995     if (nb == nullptr)
996     {
997         return;
998     }
999
1000     /* Free kernels */
1001     int kernel_count = sizeof(nb->kernel_ener_noprune_ptr) / sizeof(nb->kernel_ener_noprune_ptr[0][0]);
1002     free_kernels(nb->kernel_ener_noprune_ptr[0], kernel_count);
1003
1004     kernel_count = sizeof(nb->kernel_ener_prune_ptr) / sizeof(nb->kernel_ener_prune_ptr[0][0]);
1005     free_kernels(nb->kernel_ener_prune_ptr[0], kernel_count);
1006
1007     kernel_count = sizeof(nb->kernel_noener_noprune_ptr) / sizeof(nb->kernel_noener_noprune_ptr[0][0]);
1008     free_kernels(nb->kernel_noener_noprune_ptr[0], kernel_count);
1009
1010     kernel_count = sizeof(nb->kernel_noener_prune_ptr) / sizeof(nb->kernel_noener_prune_ptr[0][0]);
1011     free_kernels(nb->kernel_noener_prune_ptr[0], kernel_count);
1012
1013     free_kernel(&(nb->kernel_zero_e_fshift));
1014
1015     /* Free atdat */
1016     freeDeviceBuffer(&(nb->atdat->xq));
1017     freeDeviceBuffer(&(nb->atdat->f));
1018     freeDeviceBuffer(&(nb->atdat->e_lj));
1019     freeDeviceBuffer(&(nb->atdat->e_el));
1020     freeDeviceBuffer(&(nb->atdat->fshift));
1021     freeDeviceBuffer(&(nb->atdat->lj_comb));
1022     freeDeviceBuffer(&(nb->atdat->atom_types));
1023     freeDeviceBuffer(&(nb->atdat->shift_vec));
1024     sfree(nb->atdat);
1025
1026     /* Free nbparam */
1027     freeDeviceBuffer(&(nb->nbparam->nbfp_climg2d));
1028     freeDeviceBuffer(&(nb->nbparam->nbfp_comb_climg2d));
1029     freeDeviceBuffer(&(nb->nbparam->coulomb_tab_climg2d));
1030     sfree(nb->nbparam);
1031
1032     /* Free plist */
1033     auto* plist = nb->plist[InteractionLocality::Local];
1034     freeDeviceBuffer(&plist->sci);
1035     freeDeviceBuffer(&plist->cj4);
1036     freeDeviceBuffer(&plist->imask);
1037     freeDeviceBuffer(&plist->excl);
1038     sfree(plist);
1039     if (nb->bUseTwoStreams)
1040     {
1041         auto* plist_nl = nb->plist[InteractionLocality::NonLocal];
1042         freeDeviceBuffer(&plist_nl->sci);
1043         freeDeviceBuffer(&plist_nl->cj4);
1044         freeDeviceBuffer(&plist_nl->imask);
1045         freeDeviceBuffer(&plist_nl->excl);
1046         sfree(plist_nl);
1047     }
1048
1049     /* Free nbst */
1050     pfree(nb->nbst.e_lj);
1051     nb->nbst.e_lj = nullptr;
1052
1053     pfree(nb->nbst.e_el);
1054     nb->nbst.e_el = nullptr;
1055
1056     pfree(nb->nbst.fshift);
1057     nb->nbst.fshift = nullptr;
1058
1059     /* Free command queues */
1060     clReleaseCommandQueue(nb->stream[InteractionLocality::Local]);
1061     nb->stream[InteractionLocality::Local] = nullptr;
1062     if (nb->bUseTwoStreams)
1063     {
1064         clReleaseCommandQueue(nb->stream[InteractionLocality::NonLocal]);
1065         nb->stream[InteractionLocality::NonLocal] = nullptr;
1066     }
1067     /* Free other events */
1068     if (nb->nonlocal_done)
1069     {
1070         clReleaseEvent(nb->nonlocal_done);
1071         nb->nonlocal_done = nullptr;
1072     }
1073     if (nb->misc_ops_and_local_H2D_done)
1074     {
1075         clReleaseEvent(nb->misc_ops_and_local_H2D_done);
1076         nb->misc_ops_and_local_H2D_done = nullptr;
1077     }
1078
1079     free_gpu_device_runtime_data(nb->dev_rundata);
1080     sfree(nb->dev_rundata);
1081
1082     /* Free timers and timings */
1083     delete nb->timers;
1084     sfree(nb->timings);
1085     delete nb;
1086
1087     if (debug)
1088     {
1089         fprintf(debug, "Cleaned up OpenCL data structures.\n");
1090     }
1091 }
1092
1093 //! This function is documented in the header file
1094 gmx_wallclock_gpu_nbnxn_t* gpu_get_timings(NbnxmGpu* nb)
1095 {
1096     return (nb != nullptr && nb->bDoTime) ? nb->timings : nullptr;
1097 }
1098
1099 //! This function is documented in the header file
1100 void gpu_reset_timings(nonbonded_verlet_t* nbv)
1101 {
1102     if (nbv->gpu_nbv && nbv->gpu_nbv->bDoTime)
1103     {
1104         init_timings(nbv->gpu_nbv->timings);
1105     }
1106 }
1107
1108 //! This function is documented in the header file
1109 int gpu_min_ci_balanced(NbnxmGpu* nb)
1110 {
1111     return nb != nullptr ? gpu_min_ci_balanced_factor * nb->dev_info->compute_units : 0;
1112 }
1113
1114 //! This function is documented in the header file
1115 gmx_bool gpu_is_kernel_ewald_analytical(const NbnxmGpu* nb)
1116 {
1117     return ((nb->nbparam->eeltype == eelOclEWALD_ANA) || (nb->nbparam->eeltype == eelOclEWALD_ANA_TWIN));
1118 }
1119
1120 } // namespace Nbnxm