Chaste  Release::2018.1
ExecutableSupport.cpp
1 /*
2 
3 Copyright (c) 2005-2018, 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 #include <boost/foreach.hpp>
55 typedef std::pair<std::string, std::string> StringPair;
56 
57 #include "ChasteSerialization.hpp"
58 #include "CommandLineArguments.hpp"
59 #include "Exception.hpp"
60 #include "PetscException.hpp"
61 #include "PetscSetupUtils.hpp"
62 #include "PetscTools.hpp"
63 
64 #ifdef CHASTE_VTK
65 #define _BACKWARD_BACKWARD_WARNING_H 1 //Cut out the strstream deprecated warning for now (gcc4.3)
66 #include <vtkVersion.h>
67 #endif
68 
69 #ifdef CHASTE_CVODE
70 #include <sundials/sundials_config.h>
71 #if CHASTE_SUNDIALS_VERSION >= 20600
72 #if CHASTE_SUNDIALS_VERSION >= 30000
73 // SUNDIALS 3.0 upwards uses SUNDIALS_VERSION instead of SUNDIALS_PACKAGE_VERSION.
74 #define CHASTE_SUNDIALS_PACKAGE_VERSION SUNDIALS_VERSION
75 #else
76 // SUNDIALS 2.6 upwards defines SUNDIALS_PACKAGE_VERSION with quotes...
77 #include <boost/preprocessor/stringize.hpp>
78 #define CHASTE_SUNDIALS_PACKAGE_VERSION BOOST_PP_STRINGIZE(SUNDIALS_PACKAGE_VERSION)
79 #endif // SUNDIALS >= 3.0.0
80 #else
81 #define CHASTE_SUNDIALS_PACKAGE_VERSION SUNDIALS_PACKAGE_VERSION
82 #endif // SUNDIALS >= 2.6.0
83 #endif
84 
85 // Note: the following are not a requirement for cell-based Chaste so may not be present!
86 //#include <xsd/cxx/version.hxx>
87 #ifdef CHASTE_XERCES
88 #include <xercesc/util/XercesVersion.hpp>
89 #endif
90 
91 // Check whether the version of ParMETIS being used is the one we wanted
92 #ifdef CHASTE_PARMETIS_REQUIRED
93 #if PARMETIS_MAJOR_VERSION != CHASTE_PARMETIS_REQUIRED
94 #error "Wrong ParMETIS version found: " #CHASTE_PARMETIS_REQUIRED " requested but " #PARMETIS_MAJOR_VERSION " present"
95 #endif
96 #endif
97 
99 
100 void ExecutableSupport::SetOutputDirectory(const std::string& rOutputDirectory)
101 {
102  if (FileFinder::IsAbsolutePath(rOutputDirectory))
103  {
104  mOutputDirectory.SetPath(rOutputDirectory, RelativeTo::Absolute);
105  }
106  else
107  {
109  }
110 }
111 
112 void ExecutableSupport::InitializePetsc(int* pArgc, char*** pArgv)
113 {
114  // Store the arguments in case other code needs them
117  // Initialise PETSc
118  PETSCEXCEPT(PetscInitialize(pArgc, pArgv, PETSC_NULL, PETSC_NULL));
119  // Set default output folder
121  {
122  // LCOV_EXCL_START
123  //depends on order of calls. Extract to method?
125  // LCOV_EXCL_STOP
126  }
127 }
128 
130 {
131  // Compilation information
132  std::stringstream provenance_msg;
133  provenance_msg << "This version of Chaste was compiled on:\n";
134  provenance_msg << ChasteBuildInfo::GetBuildTime() << " by " << ChasteBuildInfo::GetBuilderUnameInfo() << " (uname)\n";
135  provenance_msg << "from revision number " << std::hex << ChasteBuildInfo::GetRevisionNumber() << std::dec << " with build type " << ChasteBuildInfo::GetBuildInformation() << ".\n\n";
136 
137  // Only show one copy of copyright/header
138  if (PetscTools::AmMaster())
139  {
140  std::cout << ChasteBuildInfo::GetLicenceText() << std::endl;
141 
142  // Write provenance information to stdout
143  std::cout << provenance_msg.str() << std::flush;
144  }
145 }
146 
148 {
150  {
151  // Information to show that Chaste is being run in parallel
153  std::cout << "Chaste launched on process " << PetscTools::GetMyRank()
154  << " of " << PetscTools::GetNumProcs() << "." << std::endl
155  << std::flush;
157  }
158 }
159 
160 void ExecutableSupport::WriteMachineInfoFile(std::string fileBaseName)
161 {
163  {
164  // LCOV_EXCL_START
165  //depends on order of calls. Extract to method?
167  // LCOV_EXCL_STOP
168  }
169  OutputFileHandler out_file_handler(mOutputDirectory, false);
170  std::stringstream file_name;
171  file_name << fileBaseName << "_" << PetscTools::GetMyRank() << ".txt";
172  out_stream out_file = out_file_handler.OpenOutputFile(file_name.str());
173  *out_file << "Process " << PetscTools::GetMyRank() << " of "
174  << PetscTools::GetNumProcs() << "." << std::endl
175  << std::flush;
176 
177 #ifdef _MSC_VER
178  //use native windows equivalent of system info. from uname and /proc/cpuinfo
179 
180  //operating system and machine name
181  *out_file << "uname sysname = "
182  << "Microsoft Windows" << std::endl;
183 #define INFO_BUFFER_SIZE 32767
184  TCHAR info_buffer[INFO_BUFFER_SIZE];
185  DWORD buffer_char_count = INFO_BUFFER_SIZE;
186  if (!GetComputerName(info_buffer, &buffer_char_count))
187  *out_file << "uname nodename = "
188  << "Windows machine name is unknown" << std::endl;
189  else
190  *out_file << "uname nodename = " << info_buffer << std::endl;
191  //more detailed operating system version information
192  OSVERSIONINFOEX os_info;
193  ZeroMemory(&os_info, sizeof(OSVERSIONINFO));
194  os_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
195  //copy os version info into the structure
196  GetVersionEx((OSVERSIONINFO*)&os_info);
197  //Pivot around Windows Vista (dwMajorVersion >= 6)
198  //See http://msdn.microsoft.com/en-us/library/ms724834%28v=vs.85%29.aspx for details
199  if (os_info.dwMajorVersion < 6)
200  { //earlier than Windows Vista
201  *out_file << "uname release = "
202  << "Microsoft Windows Server 2003 R2 (or earlier)" << std::endl;
203  }
204  else
205  {
206  //reverse chronological order (simply add newer OS version to the top)
207  if (os_info.dwMajorVersion > 6)
208  {
209  *out_file << "uname release = "
210  << "Microsoft Windows (Later than Microsoft Windows 8)" << std::endl;
211  }
212  else //os_info.dwMajorVersion == 6
213  {
214  if (os_info.dwMinorVersion == 2)
215  {
216  if (os_info.wProductType == VER_NT_WORKSTATION)
217  *out_file << "uname release = "
218  << "Microsoft Windows 8" << std::endl;
219  else
220  *out_file << "uname release = "
221  << "Microsoft Windows Server 2012" << std::endl;
222  }
223  else if (os_info.dwMinorVersion == 1)
224  {
225  if (os_info.wProductType == VER_NT_WORKSTATION)
226  *out_file << "uname release = "
227  << "Microsoft Windows 7" << std::endl;
228  else
229  *out_file << "uname release = "
230  << "Microsoft Windows Server 2008 R2" << std::endl;
231  }
232  else if (os_info.dwMinorVersion == 0)
233  {
234  if (os_info.wProductType == VER_NT_WORKSTATION)
235  *out_file << "uname release = "
236  << "Microsoft Windows Server 2008" << std::endl;
237  else
238  *out_file << "uname release = "
239  << "Microsoft Windows Vista" << std::endl;
240  }
241  }
242  }
243  *out_file << "uname version = " << os_info.dwMajorVersion << "." << os_info.dwMinorVersion << std::endl;
244 
245  //hardware information
246  // See http://msdn.microsoft.com/en-us/library/ms724958%28v=vs.85%29.aspx for details of the SYSTEM_INFO structure
247  SYSTEM_INFO sys_info;
248  GetSystemInfo(&sys_info);
249  switch (sys_info.wProcessorArchitecture)
250  {
251  case PROCESSOR_ARCHITECTURE_AMD64:
252  *out_file << "uname machine = "
253  << "x64 (AMD or Intel)" << std::endl;
254  break;
255  case PROCESSOR_ARCHITECTURE_ARM:
256  *out_file << "uname machine = "
257  << "ARM" << std::endl;
258  break;
259  case PROCESSOR_ARCHITECTURE_IA64:
260  *out_file << "uname machine = "
261  << "Intel Itanium-based" << std::endl;
262  break;
263  case PROCESSOR_ARCHITECTURE_INTEL:
264  *out_file << "uname machine = "
265  << "x86" << std::endl;
266  break;
267  case PROCESSOR_ARCHITECTURE_UNKNOWN:
268  *out_file << "uname machine = "
269  << "Unknown Architecture" << std::endl;
270  break;
271  default:
272  *out_file << "uname machine = "
273  << "Other Architecture. Code = " << sys_info.wProcessorArchitecture << std::endl;
274  break;
275  }
276 
277  *out_file << "\nInformation on number and type of processors:" << std::endl;
278  *out_file << sys_info.dwNumberOfProcessors;
279  *out_file << "\nInformation on processor caches, in the same order as above:" << std::endl;
280  *out_file << "Unknown" << std::endl;
281 
282  //get physical memory
283  MEMORYSTATUSEX mem_status;
284  mem_status.dwLength = sizeof(mem_status);
285  GlobalMemoryStatusEx(&mem_status);
286  *out_file << "\nInformation on system memory:" << std::endl;
287  *out_file << mem_status.ullTotalPhys / 1024 << " kB" << std::endl;
288 #else
289  struct utsname uts_info;
290  uname(&uts_info);
291 
292  *out_file << "uname sysname = " << uts_info.sysname << std::endl
293  << std::flush;
294  *out_file << "uname nodename = " << uts_info.nodename << std::endl
295  << std::flush;
296  *out_file << "uname release = " << uts_info.release << std::endl
297  << std::flush;
298  *out_file << "uname version = " << uts_info.version << std::endl
299  << std::flush;
300  *out_file << "uname machine = " << uts_info.machine << std::endl
301  << std::flush;
302  char buffer[100];
303  FILE* system_info;
304 
305 #ifdef __APPLE__
306  *out_file << "\nInformation on number and type processors, and cache and memory sizes (in bytes)\n";
307  system_info = popen("sysctl hw.ncpu hw.physicalcpu machdep.cpu.brand_string hw.l1icachesize hw.l1dcachesize hw.l2cachesize hw.l3cachesize hw.memsize", "r");
308  while (fgets(buffer, 100, system_info) != NULL)
309  {
310  *out_file << buffer;
311  }
312  fclose(system_info);
313 #else
314  //GNU
315  *out_file << "\nInformation on number and type of processors:\n";
316  system_info = popen("grep ^model.name /proc/cpuinfo", "r");
317  while (fgets(buffer, 100, system_info) != nullptr)
318  {
319  *out_file << buffer;
320  }
321  fclose(system_info);
322 
323  *out_file << "\nInformation on processor caches, in the same order as above:\n";
324  system_info = popen("grep ^cache.size /proc/cpuinfo", "r");
325  while (fgets(buffer, 100, system_info) != nullptr)
326  {
327  *out_file << buffer;
328  }
329  fclose(system_info);
330 
331  *out_file << "\nInformation on system memory:\n";
332  system_info = popen("grep ^MemTotal /proc/meminfo", "r");
333  while (fgets(buffer, 100, system_info) != nullptr)
334  {
335  *out_file << buffer;
336  }
337  fclose(system_info);
338 #endif //end of __APPLE__ not defined
339 #endif //end of _MSC_VER not defined
340 
341  out_file->close();
342 }
343 
345 {
347  {
348  // LCOV_EXCL_START
349  //depends on order of calls. Extract to method?
351  // LCOV_EXCL_STOP
352  }
353  OutputFileHandler out_file_handler(mOutputDirectory, false);
354  out_stream out_file = out_file_handler.OpenOutputFile("provenance_info_", PetscTools::GetMyRank(), ".txt");
355 
356  // Compilation information
357  std::stringstream provenance_msg;
358  provenance_msg << "This version of Chaste was compiled on:\n";
359  provenance_msg << ChasteBuildInfo::GetBuildTime() << " by " << ChasteBuildInfo::GetBuilderUnameInfo() << " (uname)\n";
360  provenance_msg << "from revision number " << std::hex << ChasteBuildInfo::GetRevisionNumber() << std::dec << " with build type " << ChasteBuildInfo::GetBuildInformation() << ".\n\n";
361  *out_file << provenance_msg.str();
362 
363  std::string output;
364  GetBuildInfo(output);
365  *out_file << output;
366 
367  out_file->close();
368 }
369 
370 void ExecutableSupport::GetBuildInfo(std::string& rInfo)
371 {
372  std::stringstream output;
373  output << "<ChasteBuildInfo>\n";
374 
375  output << "\t<ProvenanceInfo>\n";
376  output << "\t\t<VersionString>" << ChasteBuildInfo::GetVersionString() << "</VersionString> <!-- build specific -->\n";
377  output << "\t\t<IsWorkingCopyModified>" << ChasteBuildInfo::IsWorkingCopyModified() << "</IsWorkingCopyModified>\n";
378  output << "\t\t<BuildInformation>" << ChasteBuildInfo::GetBuildInformation() << "</BuildInformation>\n";
379  output << "\t\t<BuildTime>" << ChasteBuildInfo::GetBuildTime() << "</BuildTime>\n";
380  output << "\t\t<CurrentTime>" << ChasteGetCurrentTime() << "</CurrentTime>\n";
381  output << "\t\t<BuilderUnameInfo>" << ChasteBuildInfo::GetBuilderUnameInfo() << "</BuilderUnameInfo>\n";
382  output << "\t\t<Projects>\n";
383  // A bit ugly! \todo Can neaten up with tuples in C++11
384  std::map<std::string, std::string> projects_modified = ChasteBuildInfo::rGetIfProjectsModified();
385  BOOST_FOREACH (const StringPair& r_project_version, ChasteBuildInfo::rGetProjectVersions())
386  {
387  // LCOV_EXCL_START
388  // No projects are checked out for continuous builds normally!
389  output << "\t\t\t<Project>" << std::endl;
390  output << "\t\t\t\t<Name>" << r_project_version.first << "</Name>" << std::endl;
391  output << "\t\t\t\t<Version>" << r_project_version.second << "</Version>" << std::endl;
392  output << "\t\t\t\t<Modified>" << projects_modified[r_project_version.first] << "</Modified>" << std::endl;
393  output << "\t\t\t</Project>" << std::endl;
394  // LCOV_EXCL_STOP
395  }
396  output << "\t\t</Projects>\n";
397  output << "\t</ProvenanceInfo>\n";
398 
399  output << "\t<Compiler>\n";
400  output << "\t\t<NameAndVersion>" << ChasteBuildInfo::GetCompilerType() << ", version " << ChasteBuildInfo::GetCompilerVersion() << "</NameAndVersion>\n";
401  output << "\t\t<Flags>" << ChasteBuildInfo::GetCompilerFlags() << "</Flags>\n";
402  output << "\t</Compiler>\n";
403 
404  output << "\t<Libraries>\n";
405 
406  output << "\t\t<CompiledIn>\n";
407  output << "\t\t\t<PETSc>" << PETSC_VERSION_MAJOR << "." << PETSC_VERSION_MINOR << "." << PETSC_VERSION_SUBMINOR << "</PETSc>\n";
408  output << "\t\t\t<Boost>" << BOOST_VERSION / 100000 << "." << BOOST_VERSION / 100 % 1000 << "." << BOOST_VERSION % 100 << "</Boost>\n";
409  output << "\t\t\t<HDF5>" << H5_VERS_MAJOR << "." << H5_VERS_MINOR << "." << H5_VERS_RELEASE << "</HDF5>\n";
410  output << "\t\t\t<Parmetis>" << PARMETIS_MAJOR_VERSION << "." << PARMETIS_MINOR_VERSION;
411 #ifdef PARMETIS_SUBMINOR_VERSION // they only added this in v4.? !!
412  output << "." << PARMETIS_SUBMINOR_VERSION;
413 #endif
414  output << "</Parmetis>" << std::endl;
415  output << "\t\t</CompiledIn>\n";
416 
417  output << "\t\t<Binaries>\n";
418  output << "\t\t\t<XSD>" << ChasteBuildInfo::GetXsdVersion() << "</XSD>\n";
419  output << "\t\t</Binaries>\n";
420 
421  output << "\t\t<Optional>\n";
422 #ifdef CHASTE_CVODE
423  output << "\t\t\t<SUNDIALS>" << CHASTE_SUNDIALS_PACKAGE_VERSION << "</SUNDIALS>";
424 #if CHASTE_SUNDIALS_VERSION < 30000
425  output << "<!-- includes Cvode of a different version number -->";
426 #endif
427  output << std::endl;
428 #else
429  output << "\t\t\t<SUNDIALS>no</SUNDIALS>\n";
430 #endif
431 #ifdef CHASTE_VTK
432  output << "\t\t\t<VTK>" << VTK_MAJOR_VERSION << "." << VTK_MINOR_VERSION << "</VTK>\n";
433 #else
434  output << "\t\t\t<VTK>no</VTK>\n";
435 #endif
436 #ifdef CHASTE_XERCES
437  output << "\t\t\t<Xerces>" << XERCES_FULLVERSIONDOT << "</Xerces>\n"; // Note: not a requirement for cell-based so may not be present!
438 #else
439  output << "\t\t\t<Xerces>no</Xerces>\n";
440 #endif
441  output << "\t\t</Optional>\n";
442 
443  output << "\t</Libraries>\n";
444 
445  output << "</ChasteBuildInfo>" << std::endl;
446  rInfo = output.str();
447 }
448 
449 void ExecutableSupport::StandardStartup(int* pArgc, char*** pArgv)
450 {
451  InitializePetsc(pArgc, pArgv);
452  ShowCopyright();
454 }
455 
457 {
458  InitializePetsc(pArgc, pArgv);
460 }
461 
462 void ExecutableSupport::PrintError(const std::string& rMessage, bool masterOnly)
463 {
464  if (!masterOnly || PetscTools::AmMaster())
465  {
466  // Write the error message to stderr
467  std::cerr << rMessage << std::endl;
468  }
469 
470  // Write the error message to file
472  {
473  // LCOV_EXCL_START
474  //depends on order of calls. Extract to method?
476  // LCOV_EXCL_STOP
477  }
478  OutputFileHandler out_file_handler(mOutputDirectory, false);
479  out_stream out_file = out_file_handler.OpenOutputFile("chaste_errors_", PetscTools::GetMyRank(), ".txt", std::ios::out | std::ios::app);
480  *out_file << rMessage << std::endl;
481  out_file->close();
482 }
483 
484 void ExecutableSupport::Print(const std::string& rMessage)
485 {
486  if (PetscTools::AmMaster())
487  {
488  // Write the error message to stdout
489  std::cout << rMessage << std::endl
490  << std::flush;
491  }
492 }
493 
495 {
496  // Causes memory failure (and seg fault) in PETSc 3.2 with MPICH-1
498 }
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
bool IsPathSet() const
Definition: FileFinder.cpp:178
static void Print(const std::string &rMessage)
static bool AmMaster()
Definition: PetscTools.cpp:120
static void CommonFinalize()
static const char * GetCompilerFlags()
static void ShowParallelLaunching()
static void WriteProvenanceInfoFile()
out_stream OpenOutputFile(const std::string &rFileName, std::ios_base::openmode mode=std::ios::out|std::ios::trunc) const
static const char * GetBuilderUnameInfo()
static const char * GetBuildTime()
static bool IsWorkingCopyModified()
static void EndRoundRobin()
Definition: PetscTools.cpp:160
static void PrintError(const std::string &rMessage, bool masterOnly=false)
static void BeginRoundRobin()
Definition: PetscTools.cpp:150
static void StandardStartup(int *pArgc, char ***pArgv)
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)