HILA
Loading...
Searching...
No Matches
initialize.cpp
1
2#include <cstring>
3#include "hila.h"
4
5// define these global var here - somehow NULL needed for ostream
6std::ostream hila::out(NULL);
7std::ostream hila::out0(NULL);
8std::ofstream hila::output_file;
9bool hila::about_to_finish = false;
10bool hila::check_input = false;
11int hila::check_with_nodes;
12const char *hila::input_file;
14
15
16void vector_type_info();
17
18#include <limits.h>
19#include <errno.h>
20
21int get_onoff(std::string flag)
22{
23 // Check if flag has been set
24 if (hila::cmdline.flag_set(flag.c_str()))
25 {
26 std::string opt = hila::cmdline.get_string(flag.c_str());
27 if (opt.compare("on") == 0)
28 return 1;
29 else if (opt.compare("off") == 0)
30 return -1;
31 else
32 {
33 hila::out0 << "Command line argument " << flag << " requires value on/off\n";
35 return 0;
36 }
37 }
38 else
39 return 0;
40}
41
42/////////////////////////////////////////////////////////////////////////////////
43/// Initial setup routines
44/////////////////////////////////////////////////////////////////////////////////
45
46#if (defined(__GNUC__) && !defined(DARWIN)) // || defined(__bg__)
47#include <malloc.h>
48#endif
49
50// #define DEBUG_NAN
51
52#ifdef DEBUG_NAN
53#include <fenv.h>
54#endif
55
56void setup_partitions();
57
58/**
59 * @brief Read in command line arguments. Initialise default stream and MPI communication
60 *
61 * @param argc Number of command line arguments
62 * @param argv List of command line arguments
63 */
64
65void hila::initialize(int argc, char **argv) {
66
67#if (defined(__GNUC__) && !defined(DARWIN) && !defined(_MAC_OSX_)) // || defined(__bg__)
68 /* First, adjust malloc so that glibc free() does not
69 * release space to the system, increasing the performance
70 * of the glib malloc substantially. The memory use is cyclic,
71 * so we can just sit on the max memory.
72 */
73 // mallopt( M_MMAP_MAX, 0 ); /* don't use mmap */
74 /* HACK: don't release memory by calling sbrk */
75 mallopt(M_TRIM_THRESHOLD, -1);
76
77#ifdef DEBUG_NAN
78 feenableexcept(FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW);
79#endif
80#endif
81
82 // initialize MPI so that hila::myrank() etc. works
83 initialize_communications(argc, &argv);
84
85 // Default output file - we're happy with this unless partitions
86 // or otherwise indicated
87 // This channels outf to std::cout
88 hila::out.rdbuf(std::cout.rdbuf());
89
90 // set the timing so that gettime() returns time from this point
91 hila::inittime();
92
93 // open hila::out0 only for node 0
94 if (hila::myrank() == 0)
95 hila::out0.rdbuf(std::cout.rdbuf());
96
97 // Set the inbuilt command-line flags and their corresponding help texts
98 hila::cmdline.add_flag("-t","cpu time limit");
99 hila::cmdline.add_flag("-o","output filename (default: stdout)");
100 hila::cmdline.add_flag("-i","input filename (overrides the 1st hila::input() name)\nuse '-i -' for standard input");
101 hila::cmdline.add_flag("-device","in GPU runs using only 1 GPU, choose this GPU number (default 0)");
102 hila::cmdline.add_flag("-check","check input & layout with <nodes>-nodes & exit\nonly with 1 real MPI node (don't use mpirun)");
103 hila::cmdline.add_flag("-n","number of nodes used in layout check, only relevant with -check");
104 hila::cmdline.add_flag("-partitions","number of partitioned lattice streams");
105 hila::cmdline.add_flag("-sync","synchronize partition runs (on/off) (default = off)");
106
107 // Init command line - after MPI has been started, so
108 // that all nodes do this. First feed argc and argv to the
109 // global cmdline class instance and parse for the preset flags.
110 hila::cmdline.initialise_args(argc, argv);
111 // The values can now be requested from hila::cmdline.
112
113 // check the "-check" -input early
114 // do it only with 1 node
115 if (lattice.nodes.number == 1) {
116 // Check whether '-check' was found and only then search for '-n'
117 if (hila::cmdline.flag_present("-check")) {
118 long nodes;
119 if (hila::cmdline.flag_present("-n")) {
120 nodes = hila::cmdline.get_int("-n");
121 }
122 else
123 nodes = 1;
124
125 hila::check_input = true;
126 if (nodes <= 0)
127 nodes = 1;
128 hila::check_with_nodes = nodes;
129 hila::out << "****** INPUT AND LAYOUT CHECK ******" << std::endl;
130
131 // reset node variables
132 lattice.mynode.rank = 0;
133 lattice.nodes.number = hila::check_with_nodes;
134 }
135 }
136
137#if defined(CUDA) || defined(HIP)
138 if (!hila::check_input) {
139 long device;
140 if (hila::cmdline.flag_set("-device"))
141 device = hila::cmdline.get_int("-device");
142 else
143 device = 0;
144 hila::out0 << "Chose device " << device << "\n";
145
146 initialize_gpu(lattice.mynode.rank, device);
147 }
148#endif
149
150 setup_partitions();
151
152 // check the output file if partitions not used
153 if (hila::partitions.number() == 1) {
154 int do_exit = 0;
155 if (hila::myrank() == 0) {
156 if (hila::cmdline.flag_present("-o")) {
157 // Quits if '-o' was left without an argument
158 std::string name;
159 if (hila::cmdline.flag_set("-o"))
160 name = hila::cmdline.get_string("-o");
161 else
162 {
163 hila::out0 << "The name of the output file must be provided after flag '-o'!\n";
164 do_exit = 1;
165 }
166 // If found, open the file for the output
167 if (!hila::check_input) {
168 hila::output_file.open(name, std::ios::out | std::ios::app);
169 if (hila::output_file.fail()) {
170 hila::out << "Cannot open output file " << name << '\n';
171 do_exit = 1;
172 } else {
173 hila::out0 << "Output is now directed to the file '"
174 << name << "'.\n";
175 hila::out.flush();
176 hila::out.rdbuf(
177 hila::output_file.rdbuf()); // output now points to output_redirect
178
179 if (hila::myrank() == 0)
180 hila::out0.rdbuf(hila::out.rdbuf());
181 }
182 }
183 }
184 }
185 hila::broadcast(do_exit);
186 if (do_exit)
188 }
189
190 if (hila::myrank() == 0) {
191 print_dashed_line(u8"HILA ⩩ lattice framework");
192 hila::out0 << "Running program " << argv[0] << "\n";
193 hila::out0 << "with command line arguments '";
194 for (int i = 1; i < argc; i++)
195 hila::out0 << argv[i] << ' ';
196 hila::out0 << "'\n";
197 hila::out0 << "Code version: ";
198#if defined(GIT_SHA_VALUE)
199#define xstr(s) makestr(s)
200#define makestr(s) #s
201 hila::out0 << "git SHA " << xstr(GIT_SHA_VALUE) << '\n';
202#else
203 hila::out0 << "no git information available\n";
204#endif
205 hila::out0 << "Compiled " << __DATE__ << " at " << __TIME__ << '\n';
206
207 hila::out0 << "with options: EVEN_SITES_FIRST";
208#ifndef EVEN_SITES_FIRST
209 hila::out0 << "=0";
210#endif
211#ifdef SPECIAL_BOUNDARY_CONDITIONS
212 hila::out0 << " SPECIAL_BOUNDARY_CONDITIONS";
213#endif
214 hila::out0 << '\n';
215
216 hila::timestamp("Starting");
217 }
218
219 // Check if flag set and parse
220 if (hila::cmdline.flag_present("-t")) {
221 // Following quits if '-t' is given without an integer argument
222 long cputime = hila::cmdline.get_int("-t");
223 if (cputime > 0) {
224 hila::out0 << "CPU time limit " << cputime << " seconds\n";
225 hila::setup_timelimit(cputime);
226 }
227 }
228 else {
229 hila::out0 << "No runtime limit given\n";
230 }
231
232
233 hila::input_file = nullptr;
234 if (hila::cmdline.flag_present("-i"))
235 {
236 // Quits if '-i' given without a string argument
237 // Copy to a static variable to preserve the memory address
238 static const std::string input_string = hila::cmdline.get_string("-i");
239 hila::input_file = input_string.c_str();
240 hila::out0 << "Input file from command line: " << hila::input_file << "\n";
241 }
242
243
244#if defined(OPENMP)
245 hila::out0 << "Using option OPENMP - with " << omp_get_max_threads() << " threads\n";
246#endif
247
248
249#if defined(CUDA) || defined(HIP)
250 hila::out0 << "Using thread blocks of size " << N_threads << " threads\n";
251
252#if defined(GPU_AWARE_MPI)
253 hila::out0 << "Using GPU_AWARE_MPI\n";
254#else
255 hila::out0 << "Not using GPU_AWARE_MPI\n";
256#endif
257
258#if !defined(GPU_VECTOR_REDUCTION_THREAD_BLOCKS) || GPU_VECTOR_REDUCTION_THREAD_BLOCKS <= 0
259 hila::out0 << "ReductionVector with atomic operations (GPU_VECTOR_REDUCTION_THREAD_BLOCKS=0)\n";
260#else
261 hila::out0 << "ReductionVector with " << GPU_VECTOR_REDUCTION_THREAD_BLOCKS
262 << " thread blocks\n";
263#endif
264
265 if (!hila::check_input)
266 gpu_device_info();
267#endif
268
269
270#ifdef AVX
271 vector_type_info();
272#endif
273
274 /* basic static node variables */
275#if defined(CUDA) && !defined(PIZDAINT)
276 // localhost_info(&g_local_nodeid, &g_num_local_nodes);
277#endif
278
279#if (defined(__GNUC__) && !defined(DARWIN)) // || defined(__bg__)
280 hila::out0 << "GNU c-library performance: not returning allocated memory\n";
281#endif
282}
283
284
285///////////////////////////////////////////////////////////////
286/// Force quit for multinode processes -- kill all nodes
287/// No synchronisation done
288///////////////////////////////////////////////////////////////
289void hila::terminate(int status) {
290 hila::timestamp("Terminate");
291 print_dashed_line();
292 hila::about_to_finish = true; // avoid destructors
293 if (is_comm_initialized()) {
294 finish_communications();
295 }
296 exit(1);
297}
298
299////////////////////////////////////////////////////////////////
300/// Print message and force quit
301////////////////////////////////////////////////////////////////
302
303void hila::error(const char *msg) {
304 hila::out0 << "Error: " << msg << '\n';
306}
307
308void hila::error(const std::string &msg) {
309 hila::error(msg.c_str());
310}
311
312/**
313 * @brief Normal, controlled exit - all nodes must call this.
314 * Prints timing information and information about communications
315 */
317 report_timers();
318
319 for (const lattice_struct *latp : lattices) {
320
321
322 int64_t gathers = latp->n_gather_done;
323 int64_t avoided = latp->n_gather_avoided;
324
325 if (gathers + avoided > 0) {
326 hila::out0 << " COMMS from node 0: " << gathers << " done, " << avoided << "("
327 << 100.0 * avoided / (avoided + gathers) << "%) optimized away\n";
328 } else {
329 hila::out0 << " No communications done from node 0\n";
330 }
331 }
332
333
334#if defined(CUDA) || defined(HIP)
335 gpuMemPoolReport();
336#endif
337
338 if (hila::partitions.number() > 1) {
339 hila::timestamp("Waiting to sync partitions");
340 }
341
342 // hip seems to want this?
343 FFT_delete_plans();
344
346 hila::timestamp("Finishing");
347
348 hila::about_to_finish = true;
349
350 finish_communications();
351
352 print_dashed_line();
353 exit(0);
354}
355
356/******************************************************
357 * Open parameter file - moved here in order to
358 * enable partition division if requested
359 */
360#if 0
361
362FILE *open_parameter_file()
363{
364 static char parameter[] = "parameter";
365 FILE *fil = NULL;
366
367 if (mynode == 0) {
368#ifdef SUBLATTICES
369 if (n_partitions > 1) {
370 char parameter_name[50];
371 /* First, try opening parameter99 etc. */
372 sprintf(parameter_name,"%s%d",parameter,this_partition);
373 fil = fopen(parameter_name,"r");
374
375 if (fil != NULL) {
376 fprintf(outf," READING PARAMETERS FROM %s\n",parameter_name);
377 }
378 }
379#endif
380 if (fil == NULL) {
381 fil = fopen(parameter,"r");
382 if (fil == NULL) {
383 halt(" ** No parameter file?");
384 }
385 }
386 } // mynode == 0
387 return( fil );
388}
389
390#endif
391
392/******************************************************
393 * Sublattice division
394 * Handle command line arguments
395 * partitions=nn
396 * sync=yes / sync=no
397 * out=name
398 * here
399 */
400
401void setup_partitions() {
402
403 // get partitions cmdlinearg first
404 if (hila::cmdline.flag_present("-partitions")) {
405 // Following quits if '-partitions' is given without an integer argument
406 long lnum = hila::cmdline.get_int("-partitions");
407 if (lnum <= 0) {
408 hila::out0 << "partitions=<number> command line argument value must be positive "
409 "integer (or argument omitted)\n";
411 }
412 else
413 hila::partitions._number = lnum;
414 }
415 else
416 hila::partitions._number = 1;
417
418 if (hila::partitions.number() == 1)
419 return;
420
421 hila::out0 << " Dividing nodes into " << hila::partitions.number() << " partitions\n";
422
423 if (hila::number_of_nodes() % hila::partitions.number()) {
424 hila::out0 << "** " << hila::number_of_nodes() << " nodes not evenly divisible into "
425 << hila::partitions.number() << " partitions\n";
427 }
428
429#if defined(BLUEGENE_LAYOUT)
430 hila::partitions._mylattice = bg_layout_partitions(hila::partitions.number());
431#else // generic
432 hila::partitions._mylattice =
433 (hila::myrank() * hila::partitions.number()) / hila::number_of_nodes();
434 /* and divide system into partitions */
435 if (!hila::check_input)
436 split_into_partitions(hila::partitions.mylattice());
437#endif
438 std::string fname;
439 if (hila::cmdline.flag_present("-o"))
440 {
441 std::string opt = hila::cmdline.get_string("-o");
442 fname = opt + std::to_string(hila::partitions.mylattice());
443 }
444 else
445 fname = DEFAULT_OUTPUT_NAME + std::to_string(hila::partitions.mylattice());
446
447 // now need to open output file
448
449 hila::out.flush(); // this should be cout at this stage
450
451 // all nodes open the file -- perhaps not? Leave only node 0
452 int do_exit = 0;
453 if (hila::myrank() == 0 && !hila::check_input) {
454 hila::output_file.open(fname, std::ios::out | std::ios::app);
455 if (hila::output_file.fail()) {
456 std::cout << "Cannot open output file " << fname << '\n';
457 do_exit = 1;
458 }
459 }
460
461 hila::broadcast(do_exit);
462
463 if (do_exit)
465
466 hila::out.flush();
467 if (!hila::check_input) {
468 hila::out.rdbuf(hila::output_file.rdbuf());
469 // output now points to output_redirect
470 if (hila::myrank() == 0) {
471 hila::out0.rdbuf(hila::out.rdbuf());
472 }
473 }
474 hila::out0 << " ---- SPLIT " << hila::number_of_nodes() << " nodes into "
475 << hila::partitions.number() << " partitions, this " << hila::partitions.mylattice()
476 << " ----\n";
477
478
479 /* Default sync is no */
480 if (hila::cmdline.flag_present("-sync"))
481 {
482 std::string onoffopt = hila::cmdline.get_string("-sync");
483 if (get_onoff(onoffopt) == 1)
484 {
485 hila::partitions._sync = true;
486 hila::out0 << "Synchronising partition trajectories\n";
487 }
488 }
489 else
490 {
491 hila::partitions._sync = false;
492 hila::out0 << "Not synchronising the partition trajectories\n"
493 << "Use '-sync on' command line argument to override\n";
494 }
495}
496
497/////////////////////////////////////////////////////////////////////////////
498
499#ifdef AVX
500void vector_type_info() {
501
502 hila::out0 << "Using VCL vector class with instruction set level INSTRSET=" << INSTRSET
503 << " <=> ";
504
505 switch (INSTRSET) {
506 case 2:
507 hila::out0 << "SSE2";
508 break;
509 case 3:
510 hila::out0 << "SSE3";
511 break;
512 case 4:
513 hila::out0 << "SSSE3";
514 break;
515 case 5:
516 hila::out0 << "SSE4.1";
517 break;
518 case 6:
519 hila::out0 << "SSE4.2";
520 break;
521 case 7:
522 hila::out0 << "AVX";
523 break;
524 case 8:
525 hila::out0 << "AVX2";
526 break;
527 case 9:
528 hila::out0 << "AVX512F";
529 break;
530 case 10:
531 hila::out0 << "AVX512BW/DQ/VL";
532 break;
533 default:
534 hila::out0 << "Unknown";
535 break;
536 }
537 hila::out0 << '\n';
538 if (INSTRSET < 8)
539 hila::out0 << " (You probably should use options '-mavx2 -fmad' in compilation)\n";
540}
541
542
543#endif
544
545void print_dashed_line(const std::string &text) {
546 static constexpr int linelength = 60;
547
548 if (hila::myrank() == 0) {
549
550 if (text.size() == 0) {
551 for (int i = 0; i < linelength; i++)
552 hila::out << '-';
553
554 } else {
555
556 hila::out << "----- " << text << ' ';
557 for (int i = 7 + text.size(); i < linelength; i++)
558 hila::out << '-';
559 }
560 hila::out << '\n';
561 }
562}
Define the logger class here.
Definition logger.h:8
logger_class log
Now declare the logger.
int myrank()
rank of this node
Definition com_mpi.cpp:235
int number_of_nodes()
how many nodes there are
Definition com_mpi.cpp:246
void synchronize()
synchronize mpi
Definition com_mpi.cpp:255
std::ostream out
this is our default output file stream
std::ostream out0
This writes output only from main process (node 0)
std::ofstream output_file
this is just a hook to store output file, if it is in use
Definition initialize.cpp:8
void initialize(int argc, char **argv)
Read in command line arguments. Initialise default stream and MPI communication.
T broadcast(T &var, int rank=0)
Broadcast the value of var to all MPI ranks from rank (default=0).
Definition com_mpi.h:153
void finishrun()
Normal, controlled exit - all nodes must call this. Prints timing information and information about c...
void terminate(int status)
#define DEFAULT_OUTPUT_NAME
Default output file name.
Definition params.h:40