Split lines with many copyright years
[alexxy/gromacs.git] / src / gromacs / listed_forces / manage_threading.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5  * Copyright (c) 2001-2004, The GROMACS development team.
6  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
7  * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
8  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
9  * and including many others, as listed in the AUTHORS file in the
10  * top-level source directory and at http://www.gromacs.org.
11  *
12  * GROMACS is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Lesser General Public License
14  * as published by the Free Software Foundation; either version 2.1
15  * of the License, or (at your option) any later version.
16  *
17  * GROMACS is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * Lesser General Public License for more details.
21  *
22  * You should have received a copy of the GNU Lesser General Public
23  * License along with GROMACS; if not, see
24  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
26  *
27  * If you want to redistribute modifications to GROMACS, please
28  * consider that scientific software is very special. Version
29  * control is crucial - bugs must be traceable. We will be happy to
30  * consider code for inclusion in the official distribution, but
31  * derived work must not be called official GROMACS. Details are found
32  * in the README & COPYING files - if they are missing, get the
33  * official version at http://www.gromacs.org.
34  *
35  * To help us fund GROMACS development, we humbly ask that you cite
36  * the research papers on the package. Check out http://www.gromacs.org.
37  */
38 /*! \internal \file
39  * \brief This file defines functions for managing threading of listed
40  * interactions.
41  *
42  * \author Mark Abraham <mark.j.abraham@gmail.com>
43  * \ingroup module_listed_forces
44  */
45 #include "gmxpre.h"
46
47 #include "manage_threading.h"
48
49 #include "config.h"
50
51 #include <cassert>
52 #include <cinttypes>
53 #include <climits>
54 #include <cstdlib>
55
56 #include <algorithm>
57 #include <string>
58
59 #include "gromacs/listed_forces/gpubonded.h"
60 #include "gromacs/mdlib/gmx_omp_nthreads.h"
61 #include "gromacs/pbcutil/ishift.h"
62 #include "gromacs/topology/ifunc.h"
63 #include "gromacs/utility/exceptions.h"
64 #include "gromacs/utility/fatalerror.h"
65 #include "gromacs/utility/gmxassert.h"
66 #include "gromacs/utility/smalloc.h"
67
68 #include "listed_internal.h"
69 #include "utilities.h"
70
71 /*! \brief struct for passing all data required for a function type */
72 typedef struct
73 {
74     const t_ilist* il;    /**< pointer to t_ilist entry corresponding to ftype */
75     int            ftype; /**< the function type index */
76     int            nat;   /**< nr of atoms involved in a single ftype interaction */
77 } ilist_data_t;
78
79 /*! \brief Divides listed interactions over threads
80  *
81  * This routine attempts to divide all interactions of the numType bondeds
82  * types stored in ild over the threads such that each thread has roughly
83  * equal load and different threads avoid touching the same atoms as much
84  * as possible.
85  */
86 static void divide_bondeds_by_locality(bonded_threading_t* bt, int numType, const ilist_data_t* ild)
87 {
88     int nat_tot, nat_sum;
89     int ind[F_NRE];    /* index into the ild[].il->iatoms */
90     int at_ind[F_NRE]; /* index of the first atom of the interaction at ind */
91     int f, t;
92
93     assert(numType <= F_NRE);
94
95     nat_tot = 0;
96     for (f = 0; f < numType; f++)
97     {
98         /* Sum #bondeds*#atoms_per_bond over all bonded types */
99         nat_tot += ild[f].il->nr / (ild[f].nat + 1) * ild[f].nat;
100         /* The start bound for thread 0 is 0 for all interactions */
101         ind[f] = 0;
102         /* Initialize the next atom index array */
103         assert(ild[f].il->nr > 0);
104         at_ind[f] = ild[f].il->iatoms[1];
105     }
106
107     nat_sum = 0;
108     /* Loop over the end bounds of the nthreads threads to determine
109      * which interactions threads 0 to nthreads shall calculate.
110      *
111      * NOTE: The cost of these combined loops is #interactions*numType.
112      * This code is running single threaded (difficult to parallelize
113      * over threads). So the relative cost of this function increases
114      * linearly with the number of threads. Since the inner-most loop
115      * is cheap and this is done only at DD repartitioning, the cost should
116      * be negligble. At high thread count many other parts of the code
117      * scale the same way, so it's (currently) not worth improving this.
118      */
119     for (t = 1; t <= bt->nthreads; t++)
120     {
121         int nat_thread;
122
123         /* Here we assume that the computational cost is proportional
124          * to the number of atoms in the interaction. This is a rough
125          * measure, but roughly correct. Usually there are very few
126          * interactions anyhow and there are distributed relatively
127          * uniformly. Proper and RB dihedrals are often distributed
128          * non-uniformly, but their cost is roughly equal.
129          */
130         nat_thread = (nat_tot * t) / bt->nthreads;
131
132         while (nat_sum < nat_thread)
133         {
134             /* To divide bonds based on atom order, we compare
135              * the index of the first atom in the bonded interaction.
136              * This works well, since the domain decomposition generates
137              * bondeds in order of the atoms by looking up interactions
138              * which are linked to the first atom in each interaction.
139              * It usually also works well without DD, since than the atoms
140              * in bonded interactions are usually in increasing order.
141              * If they are not assigned in increasing order, the balancing
142              * is still good, but the memory access and reduction cost will
143              * be higher.
144              */
145             int f_min;
146
147             /* Find out which of the types has the lowest atom index */
148             f_min = 0;
149             for (f = 1; f < numType; f++)
150             {
151                 if (at_ind[f] < at_ind[f_min])
152                 {
153                     f_min = f;
154                 }
155             }
156             assert(f_min >= 0 && f_min < numType);
157
158             /* Assign the interaction with the lowest atom index (of type
159              * index f_min) to thread t-1 by increasing ind.
160              */
161             ind[f_min] += ild[f_min].nat + 1;
162             nat_sum += ild[f_min].nat;
163
164             /* Update the first unassigned atom index for this type */
165             if (ind[f_min] < ild[f_min].il->nr)
166             {
167                 at_ind[f_min] = ild[f_min].il->iatoms[ind[f_min] + 1];
168             }
169             else
170             {
171                 /* We have assigned all interactions of this type.
172                  * Setting at_ind to INT_MAX ensures this type will not be
173                  * chosen in the for loop above during next iterations.
174                  */
175                 at_ind[f_min] = INT_MAX;
176             }
177         }
178
179         /* Store the bonded end boundaries (at index t) for thread t-1 */
180         for (f = 0; f < numType; f++)
181         {
182             bt->workDivision.setBound(ild[f].ftype, t, ind[f]);
183         }
184     }
185
186     for (f = 0; f < numType; f++)
187     {
188         assert(ind[f] == ild[f].il->nr);
189     }
190 }
191
192 //! Return whether function type \p ftype in \p idef has perturbed interactions
193 static bool ftypeHasPerturbedEntries(const t_idef& idef, int ftype)
194 {
195     GMX_ASSERT(idef.ilsort == ilsortNO_FE || idef.ilsort == ilsortFE_SORTED,
196                "Perturbed interations should be sorted here");
197
198     const t_ilist& ilist = idef.il[ftype];
199
200     return (idef.ilsort != ilsortNO_FE && idef.numNonperturbedInteractions[ftype] != ilist.nr);
201 }
202
203 //! Divides bonded interactions over threads and GPU
204 static void divide_bondeds_over_threads(bonded_threading_t* bt, bool useGpuForBondeds, const t_idef& idef)
205 {
206     ilist_data_t ild[F_NRE];
207
208     GMX_ASSERT(bt->nthreads > 0, "Must have positive number of threads");
209     const int numThreads = bt->nthreads;
210
211     bt->haveBondeds      = false;
212     int    numType       = 0;
213     size_t fTypeGpuIndex = 0;
214     for (int fType = 0; fType < F_NRE; fType++)
215     {
216         if (!ftype_is_bonded_potential(fType))
217         {
218             continue;
219         }
220
221         const t_ilist& il                     = idef.il[fType];
222         int            nrToAssignToCpuThreads = il.nr;
223
224         if (useGpuForBondeds && fTypeGpuIndex < gmx::fTypesOnGpu.size()
225             && gmx::fTypesOnGpu[fTypeGpuIndex] == fType)
226         {
227             fTypeGpuIndex++;
228
229             /* Perturbation is not implemented in the GPU bonded kernels.
230              * But instead of doing all on the CPU, we could do only
231              * the actually perturbed interactions on the CPU.
232              */
233             if (!ftypeHasPerturbedEntries(idef, fType))
234             {
235                 /* We will assign this interaction type to the GPU */
236                 nrToAssignToCpuThreads = 0;
237             }
238         }
239
240         if (nrToAssignToCpuThreads > 0)
241         {
242             bt->haveBondeds = true;
243         }
244
245         if (nrToAssignToCpuThreads == 0)
246         {
247             /* No interactions, avoid all the integer math below */
248             for (int t = 0; t <= numThreads; t++)
249             {
250                 bt->workDivision.setBound(fType, t, 0);
251             }
252         }
253         else if (numThreads <= bt->max_nthread_uniform || fType == F_DISRES)
254         {
255             /* On up to 4 threads, load balancing the bonded work
256              * is more important than minimizing the reduction cost.
257              */
258
259             const int stride = 1 + NRAL(fType);
260
261             for (int t = 0; t <= numThreads; t++)
262             {
263                 /* Divide equally over the threads */
264                 int nr_t = (((nrToAssignToCpuThreads / stride) * t) / numThreads) * stride;
265
266                 if (fType == F_DISRES)
267                 {
268                     /* Ensure that distance restraint pairs with the same label
269                      * end up on the same thread.
270                      */
271                     while (nr_t > 0 && nr_t < nrToAssignToCpuThreads
272                            && idef.iparams[il.iatoms[nr_t]].disres.label
273                                       == idef.iparams[il.iatoms[nr_t - stride]].disres.label)
274                     {
275                         nr_t += stride;
276                     }
277                 }
278
279                 bt->workDivision.setBound(fType, t, nr_t);
280             }
281         }
282         else
283         {
284             /* Add this fType to the list to be distributed */
285             int nat            = NRAL(fType);
286             ild[numType].ftype = fType;
287             ild[numType].il    = &il;
288             ild[numType].nat   = nat;
289
290             /* The first index for the thread division is always 0 */
291             bt->workDivision.setBound(fType, 0, 0);
292
293             numType++;
294         }
295     }
296
297     if (numType > 0)
298     {
299         divide_bondeds_by_locality(bt, numType, ild);
300     }
301
302     if (debug)
303     {
304         int f;
305
306         fprintf(debug, "Division of bondeds over threads:\n");
307         for (f = 0; f < F_NRE; f++)
308         {
309             if (ftype_is_bonded_potential(f) && idef.il[f].nr > 0)
310             {
311                 int t;
312
313                 fprintf(debug, "%16s", interaction_function[f].name);
314                 for (t = 0; t < numThreads; t++)
315                 {
316                     fprintf(debug, " %4d",
317                             (bt->workDivision.bound(f, t + 1) - bt->workDivision.bound(f, t))
318                                     / (1 + NRAL(f)));
319                 }
320                 fprintf(debug, "\n");
321             }
322         }
323     }
324 }
325
326 //! Construct a reduction mask for which parts (blocks) of the force array are touched on which thread task
327 static void calc_bonded_reduction_mask(int                       natoms,
328                                        f_thread_t*               f_thread,
329                                        const t_idef&             idef,
330                                        int                       thread,
331                                        const bonded_threading_t& bondedThreading)
332 {
333     static_assert(BITMASK_SIZE == GMX_OPENMP_MAX_THREADS,
334                   "For the error message below we assume these two are equal.");
335
336     if (bondedThreading.nthreads > BITMASK_SIZE)
337     {
338 #pragma omp master
339         gmx_fatal(FARGS,
340                   "You are using %d OpenMP threads, which is larger than GMX_OPENMP_MAX_THREADS "
341                   "(%d). Decrease the number of OpenMP threads or rebuild GROMACS with a larger "
342                   "value for GMX_OPENMP_MAX_THREADS passed to CMake.",
343                   bondedThreading.nthreads, GMX_OPENMP_MAX_THREADS);
344 #pragma omp barrier
345     }
346     GMX_ASSERT(bondedThreading.nthreads <= BITMASK_SIZE,
347                "We need at least nthreads bits in the mask");
348
349     int nblock = (natoms + reduction_block_size - 1) >> reduction_block_bits;
350
351     if (nblock > f_thread->block_nalloc)
352     {
353         f_thread->block_nalloc = over_alloc_large(nblock);
354         srenew(f_thread->mask, f_thread->block_nalloc);
355         srenew(f_thread->block_index, f_thread->block_nalloc);
356         // NOTE: It seems f_thread->f does not need to be aligned
357         sfree_aligned(f_thread->f);
358         snew_aligned(f_thread->f, f_thread->block_nalloc * reduction_block_size, 128);
359     }
360
361     gmx_bitmask_t* mask = f_thread->mask;
362
363     for (int b = 0; b < nblock; b++)
364     {
365         bitmask_clear(&mask[b]);
366     }
367
368     for (int ftype = 0; ftype < F_NRE; ftype++)
369     {
370         if (ftype_is_bonded_potential(ftype))
371         {
372             int nb = idef.il[ftype].nr;
373             if (nb > 0)
374             {
375                 int nat1 = interaction_function[ftype].nratoms + 1;
376
377                 int nb0 = bondedThreading.workDivision.bound(ftype, thread);
378                 int nb1 = bondedThreading.workDivision.bound(ftype, thread + 1);
379
380                 for (int i = nb0; i < nb1; i += nat1)
381                 {
382                     for (int a = 1; a < nat1; a++)
383                     {
384                         bitmask_set_bit(&mask[idef.il[ftype].iatoms[i + a] >> reduction_block_bits], thread);
385                     }
386                 }
387             }
388         }
389     }
390
391     /* Make an index of the blocks our thread touches, so we can do fast
392      * force buffer clearing.
393      */
394     f_thread->nblock_used = 0;
395     for (int b = 0; b < nblock; b++)
396     {
397         if (bitmask_is_set(mask[b], thread))
398         {
399             f_thread->block_index[f_thread->nblock_used++] = b;
400         }
401     }
402 }
403
404 void setup_bonded_threading(bonded_threading_t* bt, int numAtoms, bool useGpuForBondeds, const t_idef& idef)
405 {
406     int ctot = 0;
407
408     assert(bt->nthreads >= 1);
409
410     /* Divide the bonded interaction over the threads */
411     divide_bondeds_over_threads(bt, useGpuForBondeds, idef);
412
413     if (!bt->haveBondeds)
414     {
415         /* We don't have bondeds, so there is nothing to reduce */
416         return;
417     }
418
419     /* Determine to which blocks each thread's bonded force calculation
420      * contributes. Store this as a mask for each thread.
421      */
422 #pragma omp parallel for num_threads(bt->nthreads) schedule(static)
423     for (int t = 0; t < bt->nthreads; t++)
424     {
425         try
426         {
427             calc_bonded_reduction_mask(numAtoms, bt->f_t[t].get(), idef, t, *bt);
428         }
429         GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
430     }
431
432     /* Reduce the masks over the threads and determine which blocks
433      * we need to reduce over.
434      */
435     int nblock_tot = (numAtoms + reduction_block_size - 1) >> reduction_block_bits;
436     /* Ensure we have sufficient space for all blocks */
437     if (static_cast<size_t>(nblock_tot) > bt->block_index.size())
438     {
439         bt->block_index.resize(nblock_tot);
440     }
441     if (static_cast<size_t>(nblock_tot) > bt->mask.size())
442     {
443         bt->mask.resize(nblock_tot);
444     }
445     bt->nblock_used = 0;
446     for (int b = 0; b < nblock_tot; b++)
447     {
448         gmx_bitmask_t* mask = &bt->mask[b];
449
450         /* Generate the union over the threads of the bitmask */
451         bitmask_clear(mask);
452         for (int t = 0; t < bt->nthreads; t++)
453         {
454             bitmask_union(mask, bt->f_t[t]->mask[b]);
455         }
456         if (!bitmask_is_zero(*mask))
457         {
458             bt->block_index[bt->nblock_used++] = b;
459         }
460
461         if (debug)
462         {
463             int c = 0;
464             for (int t = 0; t < bt->nthreads; t++)
465             {
466                 if (bitmask_is_set(*mask, t))
467                 {
468                     c++;
469                 }
470             }
471             ctot += c;
472
473             if (gmx_debug_at)
474             {
475                 fprintf(debug, "block %d flags %s count %d\n", b, to_hex_string(*mask).c_str(), c);
476             }
477         }
478     }
479     if (debug)
480     {
481         fprintf(debug, "Number of %d atom blocks to reduce: %d\n", reduction_block_size, bt->nblock_used);
482         fprintf(debug, "Reduction density %.2f for touched blocks only %.2f\n",
483                 ctot * reduction_block_size / static_cast<double>(numAtoms),
484                 ctot / static_cast<double>(bt->nblock_used));
485     }
486 }
487
488 void tear_down_bonded_threading(bonded_threading_t* bt)
489 {
490     delete bt;
491 }
492
493 f_thread_t::f_thread_t(int numEnergyGroups) : grpp(numEnergyGroups)
494 {
495     snew(fshift, SHIFTS);
496 }
497
498 f_thread_t::~f_thread_t()
499 {
500     sfree(mask);
501     sfree(fshift);
502     sfree(block_index);
503     sfree_aligned(f);
504 }
505
506 bonded_threading_t::bonded_threading_t(const int numThreads, const int numEnergyGroups) :
507     nthreads(numThreads),
508     nblock_used(0),
509     haveBondeds(false),
510     workDivision(nthreads),
511     foreignLambdaWorkDivision(1)
512 {
513     f_t.resize(numThreads);
514 #pragma omp parallel for num_threads(nthreads) schedule(static)
515     for (int t = 0; t < nthreads; t++)
516     {
517         try
518         {
519             /* Note that thread 0 uses the global fshift and energy arrays,
520              * but to keep the code simple, we initialize all data here.
521              */
522             f_t[t] = std::make_unique<f_thread_t>(numEnergyGroups);
523         }
524         GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
525     }
526 }
527
528 bonded_threading_t* init_bonded_threading(FILE* fplog, const int nenergrp)
529 {
530     /* These thread local data structures are used for bondeds only.
531      *
532      * Note that we also use there structures when running single-threaded.
533      * This is because the bonded force buffer uses type rvec4, whereas
534      * the normal force buffer is uses type rvec. This leads to a little
535      * reduction overhead, but the speed gain in the bonded calculations
536      * of doing transposeScatterIncr/DecrU with aligment 4 instead of 3
537      * is much larger than the reduction overhead.
538      */
539     bonded_threading_t* bt = new bonded_threading_t(gmx_omp_nthreads_get(emntBonded), nenergrp);
540
541     /* The optimal value after which to switch from uniform to localized
542      * bonded interaction distribution is 3, 4 or 5 depending on the system
543      * and hardware.
544      */
545     const int max_nthread_uniform = 4;
546     char*     ptr;
547
548     if ((ptr = getenv("GMX_BONDED_NTHREAD_UNIFORM")) != nullptr)
549     {
550         sscanf(ptr, "%d", &bt->max_nthread_uniform);
551         if (fplog != nullptr)
552         {
553             fprintf(fplog, "\nMax threads for uniform bonded distribution set to %d by env.var.\n",
554                     bt->max_nthread_uniform);
555         }
556     }
557     else
558     {
559         bt->max_nthread_uniform = max_nthread_uniform;
560     }
561
562     return bt;
563 }