FML
Global.cpp
Go to the documentation of this file.
1#include <chrono>
2#include <fstream>
3#include <iomanip>
4#include <iostream>
5#include <random>
6#include <stdarg.h>
7#include <sys/stat.h>
8#include <thread>
9#include <unistd.h>
10
11#include "Global.h"
12#include "SystemMemory.h"
13
14static std::string processor_name{"NameIsOnlyKnownWithMPI"};
15
16namespace FML {
17
19
20 // Initialize FML, set the few globals we have and init MPI
21 // and FFTW. If no auto setup you must init MPI and FFTW
22 // yourself and then call init_fml
23#ifndef NO_AUTO_FML_SETUP
25#endif
26
27#ifdef MEMORY_LOGGING
28 // If we use memory logging initialize it
29 [[maybe_unused]] MemoryLog * MemoryLog::instance = nullptr;
30#endif
31
32 // Number of MPI tasks and (max) OpenMP threads
33 int ThisTask = 0;
34 int NTasks = 1;
35 int NThreads = 1;
36
37 bool FFTWThreadsOK = false;
38 bool MPIThreadsOK = false;
39
40 // The local extent of the domain (global domain goes from 0 to 1)
41 double xmin_domain = 0.0;
42 double xmax_domain = 1.0;
43
44 // A simple random [0,1) generator
45 std::mt19937 generator;
46 double uniform_random() {
47 auto udist = std::uniform_real_distribution<double>(0.0, 1.0);
48 return udist(generator);
49 }
50
51 //============================================
52 /// Initialize MPI. This function is automatically
53 /// called unless NO_AUTO_MPI_SETUP is defined
54 //============================================
55 void init_mpi([[maybe_unused]] int * argc, [[maybe_unused]] char *** argv) {
56#ifdef USE_MPI
57#ifdef USE_OMP
58 int provided;
59 MPI_Init_thread(argc, argv, MPI_THREAD_FUNNELED, &provided);
60 MPIThreadsOK = provided >= MPI_THREAD_FUNNELED;
61#else
62 MPI_Init(argc, argv);
63#endif
64#endif
65 }
66
67 //============================================
68 /// Initialize the global variables within FML
69 /// We here assume MPI has been initialized
70 //============================================
71 void init_fml() {
72#ifdef USE_MPI
73 MPI_Comm_rank(MPI_COMM_WORLD, &ThisTask);
74 MPI_Comm_size(MPI_COMM_WORLD, &NTasks);
75 int plen;
76 char pname[MPI_MAX_PROCESSOR_NAME];
77 MPI_Get_processor_name(pname, &plen);
78 processor_name = std::string(pname);
79#else
80 ThisTask = 0;
81 NTasks = 1;
82 processor_name = "ComputerNameNotAvailiable";
83#endif
84
85 // Initialize OpenMP
86#ifdef USE_OMP
87#pragma omp parallel
88 {
89 int id = omp_get_thread_num();
90 if (id == 0)
91 NThreads = omp_get_num_threads();
92 }
93#else
94 NThreads = 1;
95#endif
96
97 // Set range for local domain
98 xmin_domain = ThisTask / double(NTasks);
99 xmax_domain = (ThisTask + 1) / double(NTasks);
100 }
101
102 /// Show some info about FML
103 void info() {
104 if (ThisTask == 0) {
105
106 std::cout << "\n";
107 std::cout << "#=====================================================\n";
108 std::cout << "# ________________ .____ \n";
109 std::cout << "# \\_ _____/ \\ | | \n";
110 std::cout << "# | __)/ \\ / \\| | \n";
111 std::cout << "# | \\/ Y \\ |___ \n";
112 std::cout << "# \\___ /\\____|__ /_______ \\ \n";
113 std::cout << "# \\/ \\/ \\/ \n";
114 std::cout << "#\n";
115
116 std::cout << "# Initializing FML, MPI and FFTW\n";
117#ifdef USE_MPI
118 std::cout << "# MPI is enabled. Running with " << NTasks << " MPI tasks\n";
119#else
120 std::cout << "# MPI is *not* enabled\n";
121#endif
122#ifdef USE_OMP
123 std::cout << "# OpenMP is enabled. Main task has " << NThreads << " threads availiable\n";
124#else
125 std::cout << "# OpenMP is *not* enabled\n";
126#endif
127#if defined(USE_MPI) && defined(USE_OMP)
128 std::cout << "# MPI + Threads is" << (FML::MPIThreadsOK ? " " : " *not* ") << "working\n";
129#endif
130#ifdef USE_FFTW
131 std::cout << "# FFTW is enabled. ";
132 std::cout << "Thread support is" << (FML::FFTWThreadsOK ? " " : " *not* ") << "enabled\n";
133#else
134 std::cout << "# FFTW is *not* enabled\n";
135#endif
136 std::cout << "#\n";
137 std::cout << "# List of tasks:\n";
138 }
139
140 for (int i = 0; i < NTasks; i++) {
141 if (FML::ThisTask == i) {
142 std::cout << "# Task " << std::setw(4) << i << " [" << processor_name << "]\n";
143 std::cout << "# x-domain [" << std::setw(8) << FML::xmin_domain << " , " << std::setw(8)
144 << FML::xmax_domain << ")" << std::endl;
145 }
146#ifdef USE_MPI
147 // Sleep to syncronize output to screen (this is not guaranteed to ensure syncronized output, but the only
148 // alternative is communiation and its not that important)
149 MPI_Barrier(MPI_COMM_WORLD);
150 std::this_thread::sleep_for(std::chrono::milliseconds(1));
151#endif
152 }
153
154 if (FML::ThisTask == 0) {
155 std::cout << std::flush;
156 std::cout << "#\n";
157 std::cout << "#=====================================================\n";
158 std::cout << "\n";
159 }
160
161#ifdef USE_MPI
162 MPI_Barrier(MPI_COMM_WORLD);
163 std::this_thread::sleep_for(std::chrono::milliseconds(1));
164#endif
165 }
166
167 //============================================
168 // Abort MPI
169 //============================================
170 void abort_mpi(int exit_code) {
171#ifdef USE_MPI
172 MPI_Abort(MPI_COMM_WORLD, exit_code);
173#endif
174 exit(exit_code);
175 }
176
177 //============================================
178 // End MPI
179 //============================================
181#ifdef USE_FFTW
182 // If we have MPI and FFTW then FFTW takes care of finalizing
183 return;
184#endif
185#ifdef USE_MPI
186 MPI_Finalize();
187#endif
188 }
189
190 //============================================
191 // Print function for MPI. Only task 0 prints
192 //============================================
193 void printf_mpi(const char * fmt, ...) {
194 if (FML::ThisTask == 0) {
195 va_list argp;
196 va_start(argp, fmt);
197 std::vfprintf(stdout, fmt, argp);
198 std::fflush(stdout);
199 va_end(argp);
200 }
201 }
202
203 //============================================
204 // Create a folder (only task 0 is allowed to
205 // do this)
206 //============================================
207 bool create_folder(std::string foldername) {
208 bool ok = true;
209 if (FML::ThisTask == 0) {
210 int status = mkdir(foldername.c_str(), 0777);
211 ok = not((status < 0) && (errno != EEXIST));
212 if (not ok) {
213 throw std::runtime_error("Failed to create snapshot folder [" + foldername + "]");
214 }
215 }
216 return ok;
217 }
218
219 //============================================
220 /// Fetch the resident set size currently and
221 /// the peak value so far of it. Returns bytes
222 //============================================
223 std::pair<double, double> get_system_memory_use() {
224 double currentSize_bytes = getCurrentRSS();
225 double peakSize_bytes = getPeakRSS();
226 return {currentSize_bytes, peakSize_bytes};
227 }
228
229 //============================================
230 /// Print the resident set size and the peak
231 /// value of it so far
232 //============================================
234 auto sysmem = FML::get_system_memory_use();
235 double cur_rss = sysmem.first / 1e6;
236 double peak_rss = sysmem.second / 1e6;
237 double min_cur_rss = cur_rss;
238 double max_cur_rss = cur_rss;
239 double min_peak = peak_rss;
240 double max_peak = peak_rss;
241 FML::MinOverTasks(&min_cur_rss);
242 FML::MaxOverTasks(&max_cur_rss);
243 FML::MinOverTasks(&min_peak);
244 FML::MaxOverTasks(&max_peak);
245 if (FML::ThisTask == 0) {
246 std::cout << "#=====================================================\n";
247 std::cout << "# System memory use (resident set size): \n";
248 std::cout << "# Current RSS: " << std::setw(15) << min_cur_rss << " MB (min over tasks)\n";
249 std::cout << "# Current RSS: " << std::setw(15) << max_cur_rss << " MB (max over tasks)\n";
250 std::cout << "# Peak RSS: " << std::setw(15) << min_peak << " MB (min over tasks)\n";
251 std::cout << "# Peak RSS: " << std::setw(15) << max_peak << " MB (max over tasks)\n";
252 std::cout << "#=====================================================\n";
253 }
254 }
255
256 // Make sure the most common types we use for comm gets instansiated
257#define TYPES(TYPE) \
258 template std::vector<TYPE> GatherFromTasks<TYPE>(TYPE *); \
259 template void MinOverTasks<TYPE>(TYPE *); \
260 template void MaxOverTasks<TYPE>(TYPE *); \
261 template void SumOverTasks<TYPE>(TYPE *); \
262 template void SumArrayOverTasks<TYPE>(TYPE *, int);
263 TYPES(char);
264 TYPES(int);
265 TYPES(unsigned int);
266 TYPES(long long);
267 TYPES(size_t);
268 TYPES(ptrdiff_t);
269 TYPES(float);
270 TYPES(double);
271 TYPES(long double);
272#undef TYPES
273
274} // namespace FML
275
276namespace FML {
277 namespace GRID {
278
279 void init_fftw([[maybe_unused]] int * argc, [[maybe_unused]] char *** argv) {
280#if defined(USE_FFTW) && defined(USE_FFTW_THREADS)
281 if (FML::MPIThreadsOK) {
282 FML::FFTWThreadsOK = INIT_FFTW_THREADS();
283 if (FML::FFTWThreadsOK) {
284 SET_FFTW_NTHREADS(FML::NThreads);
285 }
286 }
287#endif
288#if defined(USE_FFTW) && defined(USE_MPI)
289 INIT_FFTW_MPI();
290#endif
291 }
292
294#if defined(USE_FFTW) && defined(USE_MPI)
295 CLEANUP_FFTW_MPI();
296 MPI_Finalize();
297#endif
298 }
299
300 void set_fftw_nthreads([[maybe_unused]] int nthreads) {
301#if defined(USE_FFTW) && defined(USE_FFTW_THREADS)
303 SET_FFTW_NTHREADS(nthreads);
304#endif
305 }
306 } // namespace GRID
307} // namespace FML
static std::string processor_name
Definition: Global.cpp:14
size_t getCurrentRSS()
Returns the current resident set size (physical memory use) measured in bytes, or zero if the value c...
Definition: SystemMemory.h:82
size_t getPeakRSS()
Returns the peak (maximum so far) resident set size (physical memory use) measured in bytes,...
Definition: SystemMemory.h:41
Logs all heap allocations in the code that are larger than min_bytes_to_log.
Definition: MemoryLogging.h:45
Class for performing timings of the code using std::chrono.
Definition: Timings.h:22
void finalize_fftw()
Definition: Global.cpp:293
void init_fftw(int *argc, char ***argv)
Definition: Global.cpp:279
void set_fftw_nthreads(int nthreads)
Definition: Global.cpp:300
Definition: CAMBReader.h:10
bool create_folder(std::string foldername)
Definition: Global.cpp:207
double xmax_domain
The local extent of the domain (global domain goes from 0 to 1)
Definition: Global.cpp:42
void MinOverTasks(T *value)
Inplace min over tasks of a single value.
Definition: Global.h:134
std::pair< double, double > get_system_memory_use()
Fetch the resident set size currently and the peak value so far of it.
Definition: Global.cpp:223
int NThreads
Total number of threads availiable.
Definition: Global.cpp:35
bool MPIThreadsOK
If MPI and threads can work together with FFTW.
Definition: Global.cpp:38
void init_mpi(int *argc, char ***argv)
Initialize MPI.
Definition: Global.cpp:55
void MaxOverTasks(T *value)
Inplace max over tasks of a single value.
Definition: Global.h:121
TYPES(char)
void abort_mpi(int exit_code)
Definition: Global.cpp:170
int ThisTask
The MPI task number.
Definition: Global.cpp:33
FMLSetup & fmlsetup
Definition: Global.cpp:24
std::mt19937 generator
Definition: Global.cpp:45
void printf_mpi(const char *fmt,...)
Definition: Global.cpp:193
bool FFTWThreadsOK
Definition: Global.cpp:37
void finalize_mpi()
Definition: Global.cpp:180
void print_system_memory_use()
Print the resident set size and the peak value of it so far.
Definition: Global.cpp:233
FML::UTILS::Timings global_timer
Definition: Global.cpp:18
double uniform_random()
Definition: Global.cpp:46
void info()
Show some info about FML.
Definition: Global.cpp:103
double xmin_domain
The local extent of the domain (global domain goes from 0 to 1)
Definition: Global.cpp:41
int NTasks
Total number of MPI tasks.
Definition: Global.cpp:34
void init_fml()
Initialize the global variables within FML We here assume MPI has been initialized.
Definition: Global.cpp:71
Singleton for initializing and cleaning up FML Takes care of automatically initializing MPI and FFTW.
Definition: Global.h:333
static FMLSetup & init(int *argc=nullptr, char ***argv=nullptr)
Definition: Global.h:334