Loading [MathJax]/extensions/TeX/AMSmath.js
ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages Concepts
init.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2010-2022 The ESPResSo project
3 *
4 * This file is part of ESPResSo.
5 *
6 * ESPResSo is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * ESPResSo is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include "config/config.hpp"
21
22#ifdef CUDA
23
24#include "init.hpp"
25#include "utils.hpp"
26
27#include "communication.hpp"
28
29#include <mpi.h>
30
31#include <algorithm>
32#include <cstring>
33#include <iterator>
34#include <set>
35#include <vector>
36
37/** Helper class for device sets.
38 */
41 const EspressoGpuDevice &b) const {
42 auto const name_comp = strncmp(a.proc_name, b.proc_name, 63);
43 /* if both devices are from the same node, order by id */
44 return (name_comp == 0) ? a.id < b.id : name_comp < 0;
45 }
46};
47
48/** Gather list of CUDA devices on all nodes on the head node.
49 * It relies on <tt>MPI_Get_processor_name()</tt> to get a unique identifier
50 * of the physical node, as opposed to the logical rank of which there can
51 * be more than one per node.
52 */
53std::vector<EspressoGpuDevice> cuda_gather_gpus() {
54 /* List of local devices */
55 std::vector<EspressoGpuDevice> devices_local;
56 /* Global unique device list (only relevant on the head node) */
57 std::vector<EspressoGpuDevice> devices_global;
58
59 int n_devices = 0;
61 [&n_devices]() { n_devices = cuda_get_n_gpus(); });
62
63 int proc_name_len;
64 char proc_name[MPI_MAX_PROCESSOR_NAME];
65 MPI_Get_processor_name(proc_name, &proc_name_len);
66 proc_name[63] = '\0';
67
68 invoke_skip_cuda_exceptions([&devices_local, n_devices, &proc_name]() {
69 for (int i = 0; i < n_devices; ++i) {
70 auto device = cuda_get_device_props(i);
71 std::strncpy(device.proc_name, proc_name, 64);
72 device.proc_name[63] = '\0';
73 device.node = this_node;
74 devices_local.emplace_back(device);
75 }
76 });
77
78 auto const n_gpus = static_cast<int>(devices_local.size());
79 auto const n_nodes = ::communicator.size;
80
81 if (this_node == 0) {
82 std::set<EspressoGpuDevice, CompareDevices> device_set;
83 int *n_gpu_array = new int[static_cast<unsigned int>(n_nodes)];
84 MPI_Gather(&n_gpus, 1, MPI_INT, n_gpu_array, 1, MPI_INT, 0, MPI_COMM_WORLD);
85
86 /* insert local devices */
87 std::ranges::copy(devices_local,
88 std::inserter(device_set, device_set.begin()));
89
90 EspressoGpuDevice device;
91 MPI_Status s;
92 /* Get devices from other nodes */
93 for (int i = 1; i < n_nodes; ++i) {
94 for (int j = 0; j < n_gpu_array[i]; ++j) {
95 MPI_Recv(&device, sizeof(EspressoGpuDevice), MPI_BYTE, i, 0,
96 MPI_COMM_WORLD, &s);
97 device_set.insert(device);
98 }
99 }
100 /* Copy unique devices to result, if any */
101 std::ranges::copy(device_set, std::back_inserter(devices_global));
102 delete[] n_gpu_array;
103 } else {
104 /* Send number of devices to head node */
105 MPI_Gather(&n_gpus, 1, MPI_INT, nullptr, 1, MPI_INT, 0, MPI_COMM_WORLD);
106 /* Send devices to head node */
107 for (auto const &device : devices_local) {
108 MPI_Send(&device, sizeof(EspressoGpuDevice), MPI_BYTE, 0, 0,
109 MPI_COMM_WORLD);
110 }
111 }
112 return devices_global;
113}
114
120
121#endif // CUDA
Communicator communicator
int this_node
The number of this node.
This file contains the defaults for ESPResSo.
void invoke_skip_cuda_exceptions(F &&f, Args &&...args)
Invoke a function and silently ignore any thrown cuda_runtime_error error.
std::vector< EspressoGpuDevice > cuda_gather_gpus()
Gather list of CUDA devices on all nodes on the head node.
Definition init.cpp:53
void cuda_on_program_start()
Called on program start.
Definition init.cpp:115
EspressoGpuDevice cuda_get_device_props(int dev)
Get properties of a CUDA device.
Definition init_cuda.cu:74
int cuda_get_n_gpus()
Get the number of CUDA devices.
Definition init_cuda.cu:44
void cuda_init()
Initializes the CUDA stream.
Definition init_cuda.cu:42
int size
The MPI world size.
Helper class for device sets.
Definition init.cpp:39
bool operator()(const EspressoGpuDevice &a, const EspressoGpuDevice &b) const
Definition init.cpp:40
Struct to hold information relevant to ESPResSo about GPUs.
Definition init.hpp:35
char proc_name[64]
Node identification.
Definition init.hpp:41
int id
Local CUDA device id.
Definition init.hpp:37