Chaste  Release::2024.1
ExecutableSupport.cpp
1 /*
2 
3 Copyright (c) 2005-2021, University of Oxford.
4 All rights reserved.
5 
6 University of Oxford means the Chancellor, Masters and Scholars of the
7 University of Oxford, having an administrative office at Wellington
8 Square, Oxford OX1 2JD, UK.
9 
10 This file is part of Chaste.
11 
12 Redistribution and use in source and binary forms, with or without
13 modification, are permitted provided that the following conditions are met:
14  * Redistributions of source code must retain the above copyright notice,
15  this list of conditions and the following disclaimer.
16  * Redistributions in binary form must reproduce the above copyright notice,
17  this list of conditions and the following disclaimer in the documentation
18  and/or other materials provided with the distribution.
19  * Neither the name of the University of Oxford nor the names of its
20  contributors may be used to endorse or promote products derived from this
21  software without specific prior written permission.
22 
23 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
27 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
29 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 
34 */
35 
36 #include "ExecutableSupport.hpp"
37 
38 #include "Version.hpp"
39 
40 #include <iostream>
41 #include <sstream>
42 #ifdef _MSC_VER
43 #include <windows.h> // For system info on Windows
44 //GetCurrentTime clashes with a similarly-named API in <windows.h>
45 #define GetCurrentTime() ChasteBuildInfo::GetCurrentTime()
46 #define ChasteGetCurrentTime() GetCurrentTime()
47 #else
48 #include <sys/utsname.h> // For uname
49 #define ChasteGetCurrentTime() ChasteBuildInfo::GetCurrentTime()
50 #endif
51 #include <hdf5.h>
52 #include <parmetis.h>
53 
54 
55 #include "ChasteSerialization.hpp"
56 #include "CommandLineArguments.hpp"
57 #include "PetscException.hpp"
58 #include "PetscSetupUtils.hpp"
59 #include "PetscTools.hpp"
60 
61 #ifdef CHASTE_VTK
62 #define _BACKWARD_BACKWARD_WARNING_H 1 //Cut out the strstream deprecated warning for now (gcc4.3)
63 #include <vtkVersion.h>
64 #endif
65 
66 #ifdef CHASTE_CVODE
67 #include <sundials/sundials_config.h>
68 #if CHASTE_SUNDIALS_VERSION >= 20600
69 #if CHASTE_SUNDIALS_VERSION >= 30000
70 // SUNDIALS 3.0 upwards uses SUNDIALS_VERSION instead of SUNDIALS_PACKAGE_VERSION.
71 #define CHASTE_SUNDIALS_PACKAGE_VERSION SUNDIALS_VERSION
72 #else
73 // SUNDIALS 2.6 upwards defines SUNDIALS_PACKAGE_VERSION with quotes...
74 #include <boost/preprocessor/stringize.hpp>
75 #define CHASTE_SUNDIALS_PACKAGE_VERSION BOOST_PP_STRINGIZE(SUNDIALS_PACKAGE_VERSION)
76 #endif // SUNDIALS >= 3.0.0
77 #else
78 #define CHASTE_SUNDIALS_PACKAGE_VERSION SUNDIALS_PACKAGE_VERSION
79 #endif // SUNDIALS >= 2.6.0
80 #endif
81 
82 // Note: the following are not a requirement for cell-based Chaste so may not be present!
83 //#include <xsd/cxx/version.hxx>
84 #ifdef CHASTE_XERCES
85 #include <xercesc/util/XercesVersion.hpp>
86 #endif
87 
88 // Check whether the version of ParMETIS being used is the one we wanted
89 #ifdef CHASTE_PARMETIS_REQUIRED
90 #if PARMETIS_MAJOR_VERSION != CHASTE_PARMETIS_REQUIRED
91 #error "Wrong ParMETIS version found: " #CHASTE_PARMETIS_REQUIRED " requested but " #PARMETIS_MAJOR_VERSION " present"
92 #endif
93 #endif
94 
96 
97 void ExecutableSupport::SetOutputDirectory(const std::string& rOutputDirectory)
98 {
99  if (FileFinder::IsAbsolutePath(rOutputDirectory))
100  {
101  mOutputDirectory.SetPath(rOutputDirectory, RelativeTo::Absolute);
102  }
103  else
104  {
106  }
107 }
108 
109 void ExecutableSupport::InitializePetsc(int* pArgc, char*** pArgv)
110 {
111  // Store the arguments in case other code needs them
114  // Initialise PETSc
115  PETSCEXCEPT(PetscInitialize(pArgc, pArgv, PETSC_NULL, PETSC_NULL));
116  // Set default output folder
118  {
119  // LCOV_EXCL_START
120  //depends on order of calls. Extract to method?
122  // LCOV_EXCL_STOP
123  }
124 }
125 
127 {
128  // Compilation information
129  std::stringstream provenance_msg;
130  provenance_msg << "This version of Chaste was compiled on:\n";
131  provenance_msg << ChasteBuildInfo::GetBuildTime() << " by " << ChasteBuildInfo::GetBuilderUnameInfo() << " (uname)\n";
132  provenance_msg << "from revision number " << std::hex << ChasteBuildInfo::GetRevisionNumber() << std::dec << " with build type " << ChasteBuildInfo::GetBuildInformation() << ".\n\n";
133 
134  // Only show one copy of copyright/header
135  if (PetscTools::AmMaster())
136  {
137  std::cout << ChasteBuildInfo::GetLicenceText() << std::endl;
138 
139  // Write provenance information to stdout
140  std::cout << provenance_msg.str() << std::flush;
141  }
142 }
143 
145 {
147  {
148  // Information to show that Chaste is being run in parallel
150  std::cout << "Chaste launched on process " << PetscTools::GetMyRank()
151  << " of " << PetscTools::GetNumProcs() << "." << std::endl
152  << std::flush;
154  }
155 }
156 
157 void ExecutableSupport::WriteMachineInfoFile(std::string fileBaseName)
158 {
160  {
161  // LCOV_EXCL_START
162  //depends on order of calls. Extract to method?
164  // LCOV_EXCL_STOP
165  }
166  OutputFileHandler out_file_handler(mOutputDirectory, false);
167  std::stringstream file_name;
168  file_name << fileBaseName << "_" << PetscTools::GetMyRank() << ".txt";
169  out_stream out_file = out_file_handler.OpenOutputFile(file_name.str());
170  *out_file << "Process " << PetscTools::GetMyRank() << " of "
171  << PetscTools::GetNumProcs() << "." << std::endl
172  << std::flush;
173 
174 #ifdef _MSC_VER
175  //use native windows equivalent of system info. from uname and /proc/cpuinfo
176 
177  //operating system and machine name
178  *out_file << "uname sysname = "
179  << "Microsoft Windows" << std::endl;
180 #define INFO_BUFFER_SIZE 32767
181  TCHAR info_buffer[INFO_BUFFER_SIZE];
182  DWORD buffer_char_count = INFO_BUFFER_SIZE;
183  if (!GetComputerName(info_buffer, &buffer_char_count))
184  *out_file << "uname nodename = "
185  << "Windows machine name is unknown" << std::endl;
186  else
187  *out_file << "uname nodename = " << info_buffer << std::endl;
188  //more detailed operating system version information
189  OSVERSIONINFOEX os_info;
190  ZeroMemory(&os_info, sizeof(OSVERSIONINFO));
191  os_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
192  //copy os version info into the structure
193  GetVersionEx((OSVERSIONINFO*)&os_info);
194  //Pivot around Windows Vista (dwMajorVersion >= 6)
195  //See http://msdn.microsoft.com/en-us/library/ms724834%28v=vs.85%29.aspx for details
196  if (os_info.dwMajorVersion < 6)
197  { //earlier than Windows Vista
198  *out_file << "uname release = "
199  << "Microsoft Windows Server 2003 R2 (or earlier)" << std::endl;
200  }
201  else
202  {
203  //reverse chronological order (simply add newer OS version to the top)
204  if (os_info.dwMajorVersion > 6)
205  {
206  *out_file << "uname release = "
207  << "Microsoft Windows (Later than Microsoft Windows 8)" << std::endl;
208  }
209  else //os_info.dwMajorVersion == 6
210  {
211  if (os_info.dwMinorVersion == 2)
212  {
213  if (os_info.wProductType == VER_NT_WORKSTATION)
214  *out_file << "uname release = "
215  << "Microsoft Windows 8" << std::endl;
216  else
217  *out_file << "uname release = "
218  << "Microsoft Windows Server 2012" << std::endl;
219  }
220  else if (os_info.dwMinorVersion == 1)
221  {
222  if (os_info.wProductType == VER_NT_WORKSTATION)
223  *out_file << "uname release = "
224  << "Microsoft Windows 7" << std::endl;
225  else
226  *out_file << "uname release = "
227  << "Microsoft Windows Server 2008 R2" << std::endl;
228  }
229  else if (os_info.dwMinorVersion == 0)
230  {
231  if (os_info.wProductType == VER_NT_WORKSTATION)
232  *out_file << "uname release = "
233  << "Microsoft Windows Server 2008" << std::endl;
234  else
235  *out_file << "uname release = "
236  << "Microsoft Windows Vista" << std::endl;
237  }
238  }
239  }
240  *out_file << "uname version = " << os_info.dwMajorVersion << "." << os_info.dwMinorVersion << std::endl;
241 
242  //hardware information
243  // See http://msdn.microsoft.com/en-us/library/ms724958%28v=vs.85%29.aspx for details of the SYSTEM_INFO structure
244  SYSTEM_INFO sys_info;
245  GetSystemInfo(&sys_info);
246  switch (sys_info.wProcessorArchitecture)
247  {
248  case PROCESSOR_ARCHITECTURE_AMD64:
249  *out_file << "uname machine = "
250  << "x64 (AMD or Intel)" << std::endl;
251  break;
252  case PROCESSOR_ARCHITECTURE_ARM:
253  *out_file << "uname machine = "
254  << "ARM" << std::endl;
255  break;
256  case PROCESSOR_ARCHITECTURE_IA64:
257  *out_file << "uname machine = "
258  << "Intel Itanium-based" << std::endl;
259  break;
260  case PROCESSOR_ARCHITECTURE_INTEL:
261  *out_file << "uname machine = "
262  << "x86" << std::endl;
263  break;
264  case PROCESSOR_ARCHITECTURE_UNKNOWN:
265  *out_file << "uname machine = "
266  << "Unknown Architecture" << std::endl;
267  break;
268  default:
269  *out_file << "uname machine = "
270  << "Other Architecture. Code = " << sys_info.wProcessorArchitecture << std::endl;
271  break;
272  }
273 
274  *out_file << "\nInformation on number and type of processors:" << std::endl;
275  *out_file << sys_info.dwNumberOfProcessors;
276  *out_file << "\nInformation on processor caches, in the same order as above:" << std::endl;
277  *out_file << "Unknown" << std::endl;
278 
279  //get physical memory
280  MEMORYSTATUSEX mem_status;
281  mem_status.dwLength = sizeof(mem_status);
282  GlobalMemoryStatusEx(&mem_status);
283  *out_file << "\nInformation on system memory:" << std::endl;
284  *out_file << mem_status.ullTotalPhys / 1024 << " kB" << std::endl;
285 #else
286  struct utsname uts_info;
287  uname(&uts_info);
288 
289  *out_file << "uname sysname = " << uts_info.sysname << std::endl
290  << std::flush;
291  *out_file << "uname nodename = " << uts_info.nodename << std::endl
292  << std::flush;
293  *out_file << "uname release = " << uts_info.release << std::endl
294  << std::flush;
295  *out_file << "uname version = " << uts_info.version << std::endl
296  << std::flush;
297  *out_file << "uname machine = " << uts_info.machine << std::endl
298  << std::flush;
299  char buffer[100];
300  FILE* system_info;
301 
302 #ifdef __APPLE__
303  *out_file << "\nInformation on number and type processors, and cache and memory sizes (in bytes)\n";
304  system_info = popen("sysctl hw.ncpu hw.physicalcpu machdep.cpu.brand_string hw.l1icachesize hw.l1dcachesize hw.l2cachesize hw.l3cachesize hw.memsize", "r");
305  while (fgets(buffer, 100, system_info) != NULL)
306  {
307  *out_file << buffer;
308  }
309  fclose(system_info);
310 #else
311  //GNU
312  *out_file << "\nInformation on number and type of processors:\n";
313  system_info = popen("grep ^model.name /proc/cpuinfo", "r");
314  while (fgets(buffer, 100, system_info) != nullptr)
315  {
316  *out_file << buffer;
317  }
318  fclose(system_info);
319 
320  *out_file << "\nInformation on processor caches, in the same order as above:\n";
321  system_info = popen("grep ^cache.size /proc/cpuinfo", "r");
322  while (fgets(buffer, 100, system_info) != nullptr)
323  {
324  *out_file << buffer;
325  }
326  fclose(system_info);
327 
328  *out_file << "\nInformation on system memory:\n";
329  system_info = popen("grep ^MemTotal /proc/meminfo", "r");
330  while (fgets(buffer, 100, system_info) != nullptr)
331  {
332  *out_file << buffer;
333  }
334  fclose(system_info);
335 #endif //end of __APPLE__ not defined
336 #endif //end of _MSC_VER not defined
337 
338  out_file->close();
339 }
340 
342 {
344  {
345  // LCOV_EXCL_START
346  //depends on order of calls. Extract to method?
348  // LCOV_EXCL_STOP
349  }
350  OutputFileHandler out_file_handler(mOutputDirectory, false);
351  out_stream out_file = out_file_handler.OpenOutputFile("provenance_info_", PetscTools::GetMyRank(), ".txt");
352 
353  // Compilation information
354  std::stringstream provenance_msg;
355  provenance_msg << "This version of Chaste was compiled on:\n";
356  provenance_msg << ChasteBuildInfo::GetBuildTime() << " by " << ChasteBuildInfo::GetBuilderUnameInfo() << " (uname)\n";
357  provenance_msg << "from revision number " << std::hex << ChasteBuildInfo::GetRevisionNumber() << std::dec << " with build type " << ChasteBuildInfo::GetBuildInformation() << ".\n\n";
358  *out_file << provenance_msg.str();
359 
360  std::string output;
361  GetBuildInfo(output);
362  *out_file << output;
363 
364  out_file->close();
365 }
366 
367 void ExecutableSupport::GetBuildInfo(std::string& rInfo)
368 {
369  std::stringstream output;
370  output << "<ChasteBuildInfo>\n";
371 
372  output << "\t<ProvenanceInfo>\n";
373  output << "\t\t<VersionString>" << ChasteBuildInfo::GetVersionString() << "</VersionString> <!-- build specific -->\n";
374  output << "\t\t<IsWorkingCopyModified>" << ChasteBuildInfo::IsWorkingCopyModified() << "</IsWorkingCopyModified>\n";
375  output << "\t\t<BuildInformation>" << ChasteBuildInfo::GetBuildInformation() << "</BuildInformation>\n";
376  output << "\t\t<BuildTime>" << ChasteBuildInfo::GetBuildTime() << "</BuildTime>\n";
377  output << "\t\t<CurrentTime>" << ChasteGetCurrentTime() << "</CurrentTime>\n";
378  output << "\t\t<BuilderUnameInfo>" << ChasteBuildInfo::GetBuilderUnameInfo() << "</BuilderUnameInfo>\n";
379 
380  output << "\t\t<Projects>\n";
381  {
382  const std::map<std::string, std::string>& r_projects_modified = ChasteBuildInfo::rGetIfProjectsModified();
383  const std::map<std::string, std::string>& r_projects_versions = ChasteBuildInfo::rGetProjectVersions();
384  for (const auto& r_project_version : r_projects_versions)
385  {
386  // LCOV_EXCL_START
387  // No projects are checked out for continuous builds normally!
388  output << "\t\t\t<Project>" << std::endl;
389  output << "\t\t\t\t<Name>" << r_project_version.first << "</Name>" << std::endl;
390  output << "\t\t\t\t<Version>" << r_project_version.second << "</Version>" << std::endl;
391  output << "\t\t\t\t<Modified>" << r_projects_modified.at(r_project_version.first) << "</Modified>" << std::endl;
392  output << "\t\t\t</Project>" << std::endl;
393  // LCOV_EXCL_STOP
394  }
395  }
396  output << "\t\t</Projects>\n";
397 
398  output << "\t</ProvenanceInfo>\n";
399 
400  output << "\t<Compiler>\n";
401  output << "\t\t<NameAndVersion>" << ChasteBuildInfo::GetCompilerType() << ", version " << ChasteBuildInfo::GetCompilerVersion() << "</NameAndVersion>\n";
402  output << "\t\t<Flags>" << ChasteBuildInfo::GetCompilerFlags() << "</Flags>\n";
403  output << "\t</Compiler>\n";
404 
405  output << "\t<Libraries>\n";
406 
407  output << "\t\t<CompiledIn>\n";
408  output << "\t\t\t<PETSc>" << PETSC_VERSION_MAJOR << "." << PETSC_VERSION_MINOR << "." << PETSC_VERSION_SUBMINOR << "</PETSc>\n";
409  output << "\t\t\t<Boost>" << BOOST_VERSION / 100000 << "." << BOOST_VERSION / 100 % 1000 << "." << BOOST_VERSION % 100 << "</Boost>\n";
410  output << "\t\t\t<HDF5>" << H5_VERS_MAJOR << "." << H5_VERS_MINOR << "." << H5_VERS_RELEASE << "</HDF5>\n";
411  output << "\t\t\t<Parmetis>" << PARMETIS_MAJOR_VERSION << "." << PARMETIS_MINOR_VERSION;
412 #ifdef PARMETIS_SUBMINOR_VERSION // they only added this in v4.? !!
413  output << "." << PARMETIS_SUBMINOR_VERSION;
414 #endif
415  output << "</Parmetis>" << std::endl;
416  output << "\t\t</CompiledIn>\n";
417 
418  output << "\t\t<Binaries>\n";
419  output << "\t\t\t<XSD>" << ChasteBuildInfo::GetXsdVersion() << "</XSD>\n";
420  output << "\t\t</Binaries>\n";
421 
422  output << "\t\t<Optional>\n";
423 #ifdef CHASTE_CVODE
424  output << "\t\t\t<SUNDIALS>" << CHASTE_SUNDIALS_PACKAGE_VERSION << "</SUNDIALS>";
425 #if CHASTE_SUNDIALS_VERSION < 30000
426  output << "<!-- includes Cvode of a different version number -->";
427 #endif
428  output << std::endl;
429 #else
430  output << "\t\t\t<SUNDIALS>no</SUNDIALS>\n";
431 #endif
432 #ifdef CHASTE_VTK
433  output << "\t\t\t<VTK>" << VTK_MAJOR_VERSION << "." << VTK_MINOR_VERSION << "</VTK>\n";
434 #else
435  output << "\t\t\t<VTK>no</VTK>\n";
436 #endif
437 #ifdef CHASTE_XERCES
438  output << "\t\t\t<Xerces>" << XERCES_FULLVERSIONDOT << "</Xerces>\n"; // Note: not a requirement for cell-based so may not be present!
439 #else
440  output << "\t\t\t<Xerces>no</Xerces>\n";
441 #endif
442  output << "\t\t</Optional>\n";
443 
444  output << "\t</Libraries>\n";
445 
446  output << "</ChasteBuildInfo>" << std::endl;
447  rInfo = output.str();
448 }
449 
450 void ExecutableSupport::StandardStartup(int* pArgc, char*** pArgv)
451 {
452  InitializePetsc(pArgc, pArgv);
453  ShowCopyright();
455 }
456 
458 {
459  InitializePetsc(pArgc, pArgv);
461 }
462 
463 void ExecutableSupport::PrintError(const std::string& rMessage, bool masterOnly)
464 {
465  if (!masterOnly || PetscTools::AmMaster())
466  {
467  // Write the error message to stderr
468  std::cerr << rMessage << std::endl;
469  }
470 
471  // Write the error message to file
473  {
474  // LCOV_EXCL_START
475  //depends on order of calls. Extract to method?
477  // LCOV_EXCL_STOP
478  }
479  OutputFileHandler out_file_handler(mOutputDirectory, false);
480  out_stream out_file = out_file_handler.OpenOutputFile("chaste_errors_", PetscTools::GetMyRank(), ".txt", std::ios::out | std::ios::app);
481  *out_file << rMessage << std::endl;
482  out_file->close();
483 }
484 
485 void ExecutableSupport::Print(const std::string& rMessage)
486 {
487  if (PetscTools::AmMaster())
488  {
489  // Write the error message to stdout
490  std::cout << rMessage << std::endl
491  << std::flush;
492  }
493 }
494 
496 {
497  // Causes memory failure (and seg fault) in PETSc 3.2 with MPICH-1
499 }
static void FinalizePetsc()
static std::string GetLicenceText()
static const char * GetCompilerType()
static const char * GetBuildInformation()
static const std::map< std::string, std::string > & rGetIfProjectsModified()
static bool IsAbsolutePath(const std::string &rPath)
Definition: FileFinder.cpp:525
static void Print(const std::string &rMessage)
static bool AmMaster()
Definition: PetscTools.cpp:120
static void CommonFinalize()
bool IsPathSet() const
Definition: FileFinder.cpp:178
static const char * GetCompilerFlags()
static void ShowParallelLaunching()
static void WriteProvenanceInfoFile()
static const char * GetBuilderUnameInfo()
static const char * GetBuildTime()
static bool IsWorkingCopyModified()
static void EndRoundRobin()
Definition: PetscTools.cpp:164
static void PrintError(const std::string &rMessage, bool masterOnly=false)
static void BeginRoundRobin()
Definition: PetscTools.cpp:154
static void StandardStartup(int *pArgc, char ***pArgv)
out_stream OpenOutputFile(const std::string &rFileName, std::ios_base::openmode mode=std::ios::out|std::ios::trunc) const
static const char * GetXsdVersion()
static FileFinder mOutputDirectory
static void InitializePetsc(int *pArgc, char ***pArgv)
static bool IsParallel()
Definition: PetscTools.cpp:97
static void GetBuildInfo(std::string &rInfo)
static CommandLineArguments * Instance()
static const char * GetCompilerVersion()
static void StartupWithoutShowingCopyright(int *pArgc, char ***pArgv)
static unsigned GetNumProcs()
Definition: PetscTools.cpp:108
virtual void SetPath(const std::string &rPath, RelativeTo::Value relativeTo)
Definition: FileFinder.cpp:102
static std::string GetVersionString()
static void ShowCopyright()
static unsigned GetMyRank()
Definition: PetscTools.cpp:114
static void WriteMachineInfoFile(std::string fileBaseName)
static unsigned long long GetRevisionNumber()
static const std::map< std::string, std::string > & rGetProjectVersions()
static void SetOutputDirectory(const std::string &rOutputDirectory)