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