CEPS  24.01
Cardiac ElectroPhysiology Simulator
CepsParallelTools.cpp
Go to the documentation of this file.
1 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2  This file is part of CEPS.
3 
4  CEPS is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation, either version 3 of the License, or
7  (at your option) any later version.
8 
9  CEPS is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with CEPS (see file LICENSE at root of project).
16  If not, see <https://www.gnu.org/licenses/>.
17 
18 
19  Copyright 2019-2024 Inria, Universite de Bordeaux
20 
21  Authors, in alphabetical order:
22 
23  Pierre-Elliott BECUE, Florian CARO, Yves COUDIERE(*), Andjela DAVIDOVIC,
24  Charlie DOUANLA-LONTSI, Marc FUENTES, Mehdi JUHOOR, Michael LEGUEBE(*),
25  Pauline MIGERDITICHAN, Valentin PANNETIER(*), Nejib ZEMZEMI.
26  * : currently active authors
27 
28 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
38 
39 #include <fstream>
40 #include <regex>
41 #include <unistd.h>
42 
43 CepsUInt
44 ceps::initialize(int argc, char* argv[])
45 {
46  CepsUInt err = 0U;
47  #ifdef CEPS_USE_PETSC
48  // This call is to make Petsc Quiet about extra options... that CEPS uses!
49  PetscOptionsSetValue(PETSC_NULL,"-options_left","0");
50  // PetscOptionsSetValue(PETSC_NULL,"-ksp_converged_reason",PETSC_NULL);
51  // PetscOptionsSetValue(PETSC_NULL,"-on_error_attach_debugger",PETSC_NULL);
52  // PetscOptionsSetValue(PETSC_NULL,"-objects_dump",PETSC_NULL);
53  // err = PetscInitialize(&argc, &argv, PETSC_NULL, PETSC_NULL);
54  // Tell Petsc to still shut up if option -v is in command line
55  err = PetscInitialize(0, 0, 0, 0);
56  #else
57  MPI_Init(&argc, &argv);
58  #endif
59 
60  std::set_terminate(ceps::finalizeWithError);
61 
62  flags = ceps::getNew<Flags>(argc,argv);
63 
64  if (ceps::isVerbose())
65  {
66  std::cout << std::endl;
67  std::cout << CepsString(CEPS_SEPARATOR_LENGTH+3, '=') << std::endl;
68  CepsString toWrite = " CEPS : Cardiac ElectroPhysiology Simulator";
69  CepsInt length = std::max(0,CEPS_SEPARATOR_LENGTH+2-CepsInt(toWrite.length()));
70  std::cout << toWrite << std::setw(length) << std::right << ",d88b.d88b," << std::endl;
71  toWrite = " (" + CepsString(CEPS_GIT_HASH) + ")";
72  length = std::max(0,CEPS_SEPARATOR_LENGTH+2-CepsInt(toWrite.length()));
73  std::cout << toWrite << std::setw(length) << std::right << "88888888888" << std::endl;
74  toWrite = " ";
75  length = std::max(0,CEPS_SEPARATOR_LENGTH+2-CepsInt(toWrite.length()));
76  std::cout << toWrite << std::setw(length) << std::right << "`Y8888888Y'" << std::endl;
77  toWrite = " Running with " + ceps::toString(ceps::getGridSize()) + " core(s) on";
78  length = std::max(0,CEPS_SEPARATOR_LENGTH+2-CepsInt(toWrite.length()));
79  std::cout << toWrite << std::setw(length) << std::right << "`Y888Y' " << std::endl;
80  CepsChar hn[1024];
81  gethostname(hn, 1024);
82  toWrite = " " + CepsString(hn);
83  length = std::max(0,CEPS_SEPARATOR_LENGTH+2-CepsInt(toWrite.length()));
84  std::cout << toWrite << std::setw(length) << std::right << "`Y' " << std::endl;
85  #ifdef CEPS_DEBUG_ENABLED
86  std::cout << std::endl;
87  std::cout << " CEPS was compiled in Debug mode." << std::endl;
88  std::cout << " Debug information can be found in file: " << flags->getDebugLogName() << std::endl;
89  #endif
90  if (ceps::isProfiling())
91  {
92  std::cout << std::endl;
93  std::cout << " Profiling is ON." << std::endl;
94  std::cout << " Profiling information can be found in file: " << flags->getProfilingLogName() << std::endl;
95  }
96  std::cout << CepsString(CEPS_SEPARATOR_LENGTH+3, '=') << std::endl;
97  }
98 
99  // Force call to finalize when quitting
100  std::atexit(&ceps::finalize);
101 
102  return err;
103 }
104 
105 void
107 {
108  if (ceps::isVerbose())
109  {
110  std::cout << CepsString(CEPS_SEPARATOR_LENGTH+3,'=') << std::endl;
111  std::cout << " Computation done, see you soon !" << std::endl;
112  std::cout << CepsString(CEPS_SEPARATOR_LENGTH+3,'=') << std::endl;
113  }
115  #ifdef CEPS_USE_PETSC
116  PetscFinalize();
117  #else
118  MPI_Finalize();
119  #endif
120  return;
121 }
122 
123 void
125 {
126 
127  std::exception_ptr eptr = std::current_exception();
128  try
129  {
130  if (eptr)
131  std::rethrow_exception(eptr);
132  }
133  catch (const CepsException& e)
134  {
135  if (ceps::isMaster())
136  {
137  std::cerr << e.errorMessage() << std::endl;
138  #ifdef CEPS_DEBUG_ENABLED
139  ceps::debugLog() << e.errorMessage(false) << std::endl;
140  #endif
141  }
142  // Insert breakpoint here for debug of CEPS_ABORT messages
143  }
144  catch (...)
145  {
146  if (ceps::isMaster())
147  std::cerr << "<!> Wrong termination <!>" << std::endl;
148  }
149  if (not flags->testing())
150  MPI_Abort(ceps::getCommunicator(),EXIT_FAILURE);
151 
152 }
153 
154 CepsUInt
156 {
157  int rank;
158  #ifdef CEPS_USE_PETSC
159  MPI_Comm_rank(PETSC_COMM_WORLD, &rank);
160  #else
161  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
162  #endif
163  return (CepsUInt) rank;
164 }
165 
166 CepsUInt
168 {
169  int gridSize;
170  #ifdef CEPS_USE_PETSC
171  MPI_Comm_size(PETSC_COMM_WORLD,&gridSize);
172  #else
173  MPI_Comm_size(MPI_COMM_WORLD ,&gridSize);
174  #endif
175  return (CepsUInt)gridSize;
176 }
177 
178 CepsBool
180 {
181  return (getRank() == CEPS_MASTER_PROC);
182 }
183 
184 CepsBool
186 {
187  return (getRank() == (getGridSize()-1));
188 }
189 
190 CepsBool
192 {
193  // true if we have more than 1 processor running
194  return (getGridSize() > 1);
195 }
196 
197 void
199 {
200  #ifdef CEPS_USE_PETSC
201  PetscBarrier(PETSC_NULL);
202  #else
203  MPI_Barrier(MPI_COMM_WORLD);
204  #endif
205 }
206 
207 void
209 {
210  if (ceps::isMaster())
211  std::cout << "Begin Round Robin (sequential block)" << std::endl;
212 
213  #ifdef CEPS_USE_PETSC
214  PetscSequentialPhaseBegin(PETSC_COMM_WORLD,1);
215  #else
216  barrier();
217  CepsUInt i, rank = getRank();
218  for (i=0; i<rank; i++)
219  barrier();
220  #endif
221 }
222 
223 void
225 {
226  #ifdef CEPS_USE_PETSC
227  PetscSequentialPhaseEnd(PETSC_COMM_WORLD,1);
228  #else
229  CepsUInt i, nbProc = getGridSize ();
230  for (i=getRank(); i<nbProc; i++)
231  barrier();
232  #endif
233 
234  barrier();
235  if (getRank()==getGridSize()-1)
236  std::cout << std::endl << "End Round Robin" << std::endl << std::endl;
237 }
238 
239 MPI_Comm
241 {
242  return *ceps::getPtrCommunicator();
243 }
244 
245 MPI_Comm*
247 {
248  #ifdef CEPS_USE_PETSC
249  return &PETSC_COMM_WORLD;
250  #else
251  return &MPI_COMM_WORLD;
252  #endif
253 }
254 
256 ceps::execute(CepsString command, CepsBool withErr, CepsBool abortOnErr)
257 {
258  CepsString output;
259 
260  if (withErr)
261  command += CepsString(" 2>&1");
262 
263  // Reading from popen file output
264  const int bufsize=128;
265  std::array<char, bufsize> buffer;
266  auto pipe = popen(command.c_str(),"r");
267 
268  int notOkExec = 0;
269 
270  if (pipe)
271  {
272  size_t count;
273  do
274  {
275  if ((count = fread(buffer.data(),1,bufsize,pipe))>0)
276  output.insert(output.end(),std::begin(buffer),std::next(std::begin(buffer),count));
277  } while(count > 0);
278  notOkExec = pclose(pipe);
279  }
280  if (not pipe or notOkExec)
281  {
282  CEPS_ABORT_IF(abortOnErr,
283  "Failed system call:\n " + command
284  );
285  }
286  return output;
287 }
#define CEPS_ABORT_IF(condition, message)
Stops the execution with a message if condition is true. If testing is enabled, only throws a runtime...
#define CEPS_SEPARATOR_LENGTH
#define CEPS_MASTER_PROC
std::basic_string< CepsChar > CepsString
C++ format string.
Definition: CepsTypes.hpp:128
char CepsChar
Char.
Definition: CepsTypes.hpp:125
bool CepsBool
Booleans.
Definition: CepsTypes.hpp:124
std::make_unsigned_t< CepsInt > CepsUInt
Unsigned version on CepsInt.
Definition: CepsTypes.hpp:109
int32_t CepsInt
Need 32 bit integer.
Definition: CepsTypes.hpp:106
Flags * flags
Global variable, used in every application.
Definition: ceps.cpp:34
CepsString errorMessage(CepsBool color=true) const
Nice display of error.
CepsBool testing() const
Tells if currently running in a test suite (switched in CepsGlobalFixture.hpp)
Definition: CepsFlags.cpp:189
CepsString getDebugLogName() const
Name has the form debug_PID.log (PID of master node)
Definition: CepsFlags.cpp:221
CepsString getProfilingLogName() const
Name has the form profiling_PID.log (PID of master node)
Definition: CepsFlags.cpp:227
CepsString execute(CepsString command, CepsBool withErr=false, CepsBool abortOnErr=false)
Not really a parallel thing. Calls system() and deals with return code.
CepsUInt getRank()
Returns current processor rank.
CepsString toString(_Tp value)
Convert a given value to a string (input has to be compatible with std::to_string)
Definition: CepsString.hpp:409
CepsBool isVerbose()
Check if the verbosity is enabled on the master proc (always false on slave procs).
Definition: CepsFlags.cpp:263
MPI_Comm getCommunicator()
Get the communicator.
CepsBool isLast()
Is calling process last in computing grid ?
CepsBool isParallel()
Is there more than 1 process currently working ?
std::ofstream & debugLog()
Get the DebugLog used in Ceps.
Definition: CepsFlags.cpp:245
const _Type & max(const CepsVector< _Type, _Alloc > &vec)
Returns the maximum of the vector, const version.
Definition: CepsVector.hpp:464
CepsUInt getGridSize()
Returns the number of process on the computing grid.
CepsUInt initialize(int argc, char *argv[])
Initializes parallel environment.
void finalize()
Finalizes parallel environment.
void barrier()
Explicit barrier: wait for all processors before continuing.
void beginSequential()
Begins a sequential block.
CepsBool isMaster()
Is calling process the master ?
MPI_Comm * getPtrCommunicator()
Get pointer to the communicator.
void endSequential()
End a sequential block.
CepsBool isProfiling()
Check if we are currently profiling on the master proc (always false on slave procs).
Definition: CepsFlags.cpp:257
void destroyObject(_Type &)
Destroy[delete] any type.
Definition: CepsMemory.hpp:116
void finalizeWithError()
Calls MPI_Abort, function used instead of std::terminate()