Chaste Commit::675f9facbe008c5eacb9006feaeb6423206579ea
ExecutableSupport.cpp
1/*
2
3Copyright (c) 2005-2025, University of Oxford.
4All rights reserved.
5
6University of Oxford means the Chancellor, Masters and Scholars of the
7University of Oxford, having an administrative office at Wellington
8Square, Oxford OX1 2JD, UK.
9
10This file is part of Chaste.
11
12Redistribution and use in source and binary forms, with or without
13modification, 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
23THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
27LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
29GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32OF 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
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#ifdef PARMETIS_MAJOR_VERSION
91#if PARMETIS_MAJOR_VERSION != CHASTE_PARMETIS_REQUIRED
92#error "Wrong ParMETIS version found: " #CHASTE_PARMETIS_REQUIRED " requested but " #PARMETIS_MAJOR_VERSION " present"
93#endif
94#endif
95#endif
96
97#ifndef PARMETIS_MAJOR_VERSION
98// If there's no PARMETIS then assume we have Scotch
99#include <scotch/ptscotch.h>
100#endif
101
103
104void ExecutableSupport::SetOutputDirectory(const std::string& rOutputDirectory)
105{
106 if (FileFinder::IsAbsolutePath(rOutputDirectory))
107 {
109 }
110 else
111 {
113 }
114}
115
116void ExecutableSupport::InitializePetsc(int* pArgc, char*** pArgv)
117{
118 // Store the arguments in case other code needs them
121 // Initialise PETSc
122 PETSCEXCEPT(PetscInitialize(pArgc, pArgv, CHASTE_PETSC_NULLPTR, CHASTE_PETSC_NULLPTR));
123 // Set default output folder
125 {
126 // LCOV_EXCL_START
127 //depends on order of calls. Extract to method?
129 // LCOV_EXCL_STOP
130 }
131}
132
134{
135 // Compilation information
136 std::stringstream provenance_msg;
137 provenance_msg << "This version of Chaste was compiled on:\n";
138 provenance_msg << ChasteBuildInfo::GetBuildTime() << " by " << ChasteBuildInfo::GetBuilderUnameInfo() << " (uname)\n";
139 provenance_msg << "from revision number " << std::hex << ChasteBuildInfo::GetRevisionNumber() << std::dec << " with build type " << ChasteBuildInfo::GetBuildInformation() << ".\n\n";
140
141 // Only show one copy of copyright/header
143 {
144 std::cout << ChasteBuildInfo::GetLicenceText() << std::endl;
145
146 // Write provenance information to stdout
147 std::cout << provenance_msg.str() << std::flush;
148 }
149}
150
152{
154 {
155 // Information to show that Chaste is being run in parallel
157 std::cout << "Chaste launched on process " << PetscTools::GetMyRank()
158 << " of " << PetscTools::GetNumProcs() << "." << std::endl
159 << std::flush;
161 }
162}
163
164void ExecutableSupport::WriteMachineInfoFile(std::string fileBaseName)
165{
167 {
168 // LCOV_EXCL_START
169 //depends on order of calls. Extract to method?
171 // LCOV_EXCL_STOP
172 }
173 OutputFileHandler out_file_handler(mOutputDirectory, false);
174 std::stringstream file_name;
175 file_name << fileBaseName << "_" << PetscTools::GetMyRank() << ".txt";
176 out_stream out_file = out_file_handler.OpenOutputFile(file_name.str());
177 *out_file << "Process " << PetscTools::GetMyRank() << " of "
178 << PetscTools::GetNumProcs() << "." << std::endl
179 << std::flush;
180
181#ifdef _MSC_VER
182 //use native windows equivalent of system info. from uname and /proc/cpuinfo
183
184 //operating system and machine name
185 *out_file << "uname sysname = "
186 << "Microsoft Windows" << std::endl;
187#define INFO_BUFFER_SIZE 32767
188 TCHAR info_buffer[INFO_BUFFER_SIZE];
189 DWORD buffer_char_count = INFO_BUFFER_SIZE;
190 if (!GetComputerName(info_buffer, &buffer_char_count))
191 *out_file << "uname nodename = "
192 << "Windows machine name is unknown" << std::endl;
193 else
194 *out_file << "uname nodename = " << info_buffer << std::endl;
195 //more detailed operating system version information
196 OSVERSIONINFOEX os_info;
197 ZeroMemory(&os_info, sizeof(OSVERSIONINFO));
198 os_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
199 //copy os version info into the structure
200 GetVersionEx((OSVERSIONINFO*)&os_info);
201 //Pivot around Windows Vista (dwMajorVersion >= 6)
202 //See http://msdn.microsoft.com/en-us/library/ms724834%28v=vs.85%29.aspx for details
203 if (os_info.dwMajorVersion < 6)
204 { //earlier than Windows Vista
205 *out_file << "uname release = "
206 << "Microsoft Windows Server 2003 R2 (or earlier)" << std::endl;
207 }
208 else
209 {
210 //reverse chronological order (simply add newer OS version to the top)
211 if (os_info.dwMajorVersion > 6)
212 {
213 *out_file << "uname release = "
214 << "Microsoft Windows (Later than Microsoft Windows 8)" << std::endl;
215 }
216 else //os_info.dwMajorVersion == 6
217 {
218 if (os_info.dwMinorVersion == 2)
219 {
220 if (os_info.wProductType == VER_NT_WORKSTATION)
221 *out_file << "uname release = "
222 << "Microsoft Windows 8" << std::endl;
223 else
224 *out_file << "uname release = "
225 << "Microsoft Windows Server 2012" << std::endl;
226 }
227 else if (os_info.dwMinorVersion == 1)
228 {
229 if (os_info.wProductType == VER_NT_WORKSTATION)
230 *out_file << "uname release = "
231 << "Microsoft Windows 7" << std::endl;
232 else
233 *out_file << "uname release = "
234 << "Microsoft Windows Server 2008 R2" << std::endl;
235 }
236 else if (os_info.dwMinorVersion == 0)
237 {
238 if (os_info.wProductType == VER_NT_WORKSTATION)
239 *out_file << "uname release = "
240 << "Microsoft Windows Server 2008" << std::endl;
241 else
242 *out_file << "uname release = "
243 << "Microsoft Windows Vista" << std::endl;
244 }
245 }
246 }
247 *out_file << "uname version = " << os_info.dwMajorVersion << "." << os_info.dwMinorVersion << std::endl;
248
249 //hardware information
250 // See http://msdn.microsoft.com/en-us/library/ms724958%28v=vs.85%29.aspx for details of the SYSTEM_INFO structure
251 SYSTEM_INFO sys_info;
252 GetSystemInfo(&sys_info);
253 switch (sys_info.wProcessorArchitecture)
254 {
255 case PROCESSOR_ARCHITECTURE_AMD64:
256 *out_file << "uname machine = "
257 << "x64 (AMD or Intel)" << std::endl;
258 break;
259 case PROCESSOR_ARCHITECTURE_ARM:
260 *out_file << "uname machine = "
261 << "ARM" << std::endl;
262 break;
263 case PROCESSOR_ARCHITECTURE_IA64:
264 *out_file << "uname machine = "
265 << "Intel Itanium-based" << std::endl;
266 break;
267 case PROCESSOR_ARCHITECTURE_INTEL:
268 *out_file << "uname machine = "
269 << "x86" << std::endl;
270 break;
271 case PROCESSOR_ARCHITECTURE_UNKNOWN:
272 *out_file << "uname machine = "
273 << "Unknown Architecture" << std::endl;
274 break;
275 default:
276 *out_file << "uname machine = "
277 << "Other Architecture. Code = " << sys_info.wProcessorArchitecture << std::endl;
278 break;
279 }
280
281 *out_file << "\nInformation on number and type of processors:" << std::endl;
282 *out_file << sys_info.dwNumberOfProcessors;
283 *out_file << "\nInformation on processor caches, in the same order as above:" << std::endl;
284 *out_file << "Unknown" << std::endl;
285
286 //get physical memory
287 MEMORYSTATUSEX mem_status;
288 mem_status.dwLength = sizeof(mem_status);
289 GlobalMemoryStatusEx(&mem_status);
290 *out_file << "\nInformation on system memory:" << std::endl;
291 *out_file << mem_status.ullTotalPhys / 1024 << " kB" << std::endl;
292#else
293 struct utsname uts_info;
294 uname(&uts_info);
295
296 *out_file << "uname sysname = " << uts_info.sysname << std::endl
297 << std::flush;
298 *out_file << "uname nodename = " << uts_info.nodename << std::endl
299 << std::flush;
300 *out_file << "uname release = " << uts_info.release << std::endl
301 << std::flush;
302 *out_file << "uname version = " << uts_info.version << std::endl
303 << std::flush;
304 *out_file << "uname machine = " << uts_info.machine << std::endl
305 << std::flush;
306 char buffer[100];
307 FILE* system_info;
308
309#ifdef __APPLE__
310 *out_file << "\nInformation on number and type processors, and cache and memory sizes (in bytes)\n";
311 system_info = popen("sysctl hw.ncpu hw.physicalcpu machdep.cpu.brand_string hw.l1icachesize hw.l1dcachesize hw.l2cachesize hw.l3cachesize hw.memsize", "r");
312 while (fgets(buffer, 100, system_info) != NULL)
313 {
314 *out_file << buffer;
315 }
316 pclose(system_info);
317#else
318 //GNU
319 *out_file << "\nInformation on number and type of processors:\n";
320 system_info = popen("grep ^model.name /proc/cpuinfo", "r");
321 while (fgets(buffer, 100, system_info) != nullptr)
322 {
323 *out_file << buffer;
324 }
325 pclose(system_info);
326
327 *out_file << "\nInformation on processor caches, in the same order as above:\n";
328 system_info = popen("grep ^cache.size /proc/cpuinfo", "r");
329 while (fgets(buffer, 100, system_info) != nullptr)
330 {
331 *out_file << buffer;
332 }
333 pclose(system_info);
334
335 *out_file << "\nInformation on system memory:\n";
336 system_info = popen("grep ^MemTotal /proc/meminfo", "r");
337 while (fgets(buffer, 100, system_info) != nullptr)
338 {
339 *out_file << buffer;
340 }
341 pclose(system_info);
342#endif //end of __APPLE__ not defined
343#endif //end of _MSC_VER not defined
344
345 out_file->close();
346}
347
349{
351 {
352 // LCOV_EXCL_START
353 //depends on order of calls. Extract to method?
355 // LCOV_EXCL_STOP
356 }
357 OutputFileHandler out_file_handler(mOutputDirectory, false);
358 out_stream out_file = out_file_handler.OpenOutputFile("provenance_info_", PetscTools::GetMyRank(), ".txt");
359
360 // Compilation information
361 std::stringstream provenance_msg;
362 provenance_msg << "This version of Chaste was compiled on:\n";
363 provenance_msg << ChasteBuildInfo::GetBuildTime() << " by " << ChasteBuildInfo::GetBuilderUnameInfo() << " (uname)\n";
364 provenance_msg << "from revision number " << std::hex << ChasteBuildInfo::GetRevisionNumber() << std::dec << " with build type " << ChasteBuildInfo::GetBuildInformation() << ".\n\n";
365 *out_file << provenance_msg.str();
366
367 std::string output;
368 GetBuildInfo(output);
369 *out_file << output;
370
371 out_file->close();
372}
373
374void ExecutableSupport::GetBuildInfo(std::string& rInfo)
375{
376 std::stringstream output;
377 output << "<ChasteBuildInfo>\n";
378
379 output << "\t<ProvenanceInfo>\n";
380 output << "\t\t<VersionString>" << ChasteBuildInfo::GetVersionString() << "</VersionString> <!-- build specific -->\n";
381 output << "\t\t<IsWorkingCopyModified>" << ChasteBuildInfo::IsWorkingCopyModified() << "</IsWorkingCopyModified>\n";
382 output << "\t\t<BuildInformation>" << ChasteBuildInfo::GetBuildInformation() << "</BuildInformation>\n";
383 output << "\t\t<BuildTime>" << ChasteBuildInfo::GetBuildTime() << "</BuildTime>\n";
384 output << "\t\t<CurrentTime>" << ChasteGetCurrentTime() << "</CurrentTime>\n";
385 output << "\t\t<BuilderUnameInfo>" << ChasteBuildInfo::GetBuilderUnameInfo() << "</BuilderUnameInfo>\n";
386 output << "\t\t<ChasteTestOutputDirectory>" << OutputFileHandler::GetChasteTestOutputDirectory() << "</ChasteTestOutputDirectory>\n";
387
388 output << "\t\t<Projects>\n";
389 {
390 const std::map<std::string, std::string>& r_projects_modified = ChasteBuildInfo::rGetIfProjectsModified();
391 const std::map<std::string, std::string>& r_projects_versions = ChasteBuildInfo::rGetProjectVersions();
392 for (const auto& r_project_version : r_projects_versions)
393 {
394 // LCOV_EXCL_START
395 // No projects are checked out for continuous builds normally!
396 output << "\t\t\t<Project>" << std::endl;
397 output << "\t\t\t\t<Name>" << r_project_version.first << "</Name>" << std::endl;
398 output << "\t\t\t\t<Version>" << r_project_version.second << "</Version>" << std::endl;
399 output << "\t\t\t\t<Modified>" << r_projects_modified.at(r_project_version.first) << "</Modified>" << std::endl;
400 output << "\t\t\t</Project>" << std::endl;
401 // LCOV_EXCL_STOP
402 }
403 }
404 output << "\t\t</Projects>\n";
405
406 output << "\t</ProvenanceInfo>\n";
407
408 output << "\t<Compiler>\n";
409 output << "\t\t<NameAndVersion>" << ChasteBuildInfo::GetCompilerType() << ", version " << ChasteBuildInfo::GetCompilerVersion() << "</NameAndVersion>\n";
410 output << "\t\t<Flags>" << ChasteBuildInfo::GetCompilerFlags() << "</Flags>\n";
411 output << "\t</Compiler>\n";
412
413 output << "\t<Libraries>\n";
414
415 output << "\t\t<CompiledIn>\n";
416 output << "\t\t\t<PETSc>" << PETSC_VERSION_MAJOR << "." << PETSC_VERSION_MINOR << "." << PETSC_VERSION_SUBMINOR << "</PETSc>\n";
417 output << "\t\t\t<Boost>" << BOOST_VERSION / 100000 << "." << BOOST_VERSION / 100 % 1000 << "." << BOOST_VERSION % 100 << "</Boost>\n";
418 output << "\t\t\t<HDF5>" << H5_VERS_MAJOR << "." << H5_VERS_MINOR << "." << H5_VERS_RELEASE << "</HDF5>\n";
419#ifdef PARMETIS_MAJOR_VERSION
420 output << "\t\t\t<Parmetis>" << PARMETIS_MAJOR_VERSION << "." << PARMETIS_MINOR_VERSION;
421#ifdef PARMETIS_SUBMINOR_VERSION // they only added this in v4.? !!
422 output << "." << PARMETIS_SUBMINOR_VERSION;
423#endif
424 output << "</Parmetis>" << std::endl;
425#else //PARMETIS_MAJOR_VERSION
426 // Assume we have Scotch
427 output << "\t\t\t<Parmetis>[NONE]</Parmetis>" << std::endl;
428 output << "\t\t\t<PT-Scotch>" << SCOTCH_VERSION<<"."<<SCOTCH_RELEASE<<"."<<SCOTCH_PATCHLEVEL<<"</PT-Scotch>"<< std::endl;
429#endif //no PARMETIS_MAJOR_VERSION
430
431 output << "\t\t</CompiledIn>\n";
432
433 output << "\t\t<Binaries>\n";
434 output << "\t\t\t<XSD>" << ChasteBuildInfo::GetXsdVersion() << "</XSD>\n";
435 output << "\t\t</Binaries>\n";
436
437 output << "\t\t<Optional>\n";
438#ifdef CHASTE_CVODE
439 output << "\t\t\t<SUNDIALS>" << CHASTE_SUNDIALS_PACKAGE_VERSION << "</SUNDIALS>";
440#if CHASTE_SUNDIALS_VERSION < 30000
441 output << "<!-- includes Cvode of a different version number -->";
442#endif
443 output << std::endl;
444#else
445 output << "\t\t\t<SUNDIALS>no</SUNDIALS>\n";
446#endif
447#ifdef CHASTE_VTK
448 output << "\t\t\t<VTK>" << VTK_MAJOR_VERSION << "." << VTK_MINOR_VERSION << "</VTK>\n";
449#else
450 output << "\t\t\t<VTK>no</VTK>\n";
451#endif
452#ifdef CHASTE_XERCES
453 output << "\t\t\t<Xerces>" << XERCES_FULLVERSIONDOT << "</Xerces>\n"; // Note: not a requirement for cell-based so may not be present!
454#else
455 output << "\t\t\t<Xerces>no</Xerces>\n";
456#endif
457 output << "\t\t</Optional>\n";
458
459 output << "\t</Libraries>\n";
460
461 output << "\t<ChasteCodegenVersion>" << ChasteBuildInfo::GetChasteCodegenVersion() << "</ChasteCodegenVersion>\n";
462
463 output << "</ChasteBuildInfo>" << std::endl;
464 rInfo = output.str();
465}
466
467void ExecutableSupport::StandardStartup(int* pArgc, char*** pArgv)
468{
469 InitializePetsc(pArgc, pArgv);
472}
473
475{
476 InitializePetsc(pArgc, pArgv);
478}
479
480void ExecutableSupport::PrintError(const std::string& rMessage, bool masterOnly)
481{
482 if (!masterOnly || PetscTools::AmMaster())
483 {
484 // Write the error message to stderr
485 std::cerr << rMessage << std::endl;
486 }
487
488 // Write the error message to file
490 {
491 // LCOV_EXCL_START
492 //depends on order of calls. Extract to method?
494 // LCOV_EXCL_STOP
495 }
496 OutputFileHandler out_file_handler(mOutputDirectory, false);
497 out_stream out_file = out_file_handler.OpenOutputFile("chaste_errors_", PetscTools::GetMyRank(), ".txt", std::ios::out | std::ios::app);
498 *out_file << rMessage << std::endl;
499 out_file->close();
500}
501
502void ExecutableSupport::Print(const std::string& rMessage)
503{
505 {
506 // Write the error message to stdout
507 std::cout << rMessage << std::endl
508 << std::flush;
509 }
510}
511
513{
514 // Causes memory failure (and seg fault) in PETSc 3.2 with MPICH-1
516}
#define CHASTE_PETSC_NULLPTR
A macro to define PETSc null pointer based on the PETSc version.
static const std::map< std::string, std::string > & rGetIfProjectsModified()
static unsigned long long GetRevisionNumber()
static const char * GetBuilderUnameInfo()
static const char * GetCompilerFlags()
static const char * GetBuildTime()
static std::string GetChasteCodegenVersion()
static std::string GetVersionString()
static const char * GetBuildInformation()
static const std::map< std::string, std::string > & rGetProjectVersions()
static bool IsWorkingCopyModified()
static const char * GetCompilerVersion()
static const char * GetCompilerType()
static const char * GetXsdVersion()
static std::string GetLicenceText()
static CommandLineArguments * Instance()
static void Print(const std::string &rMessage)
static void SetOutputDirectory(const std::string &rOutputDirectory)
static void GetBuildInfo(std::string &rInfo)
static void WriteMachineInfoFile(std::string fileBaseName)
static void ShowParallelLaunching()
static void ShowCopyright()
static FileFinder mOutputDirectory
static void StartupWithoutShowingCopyright(int *pArgc, char ***pArgv)
static void StandardStartup(int *pArgc, char ***pArgv)
static void FinalizePetsc()
static void WriteProvenanceInfoFile()
static void PrintError(const std::string &rMessage, bool masterOnly=false)
static void InitializePetsc(int *pArgc, char ***pArgv)
static bool IsAbsolutePath(const std::string &rPath)
virtual void SetPath(const std::string &rPath, RelativeTo::Value relativeTo)
bool IsPathSet() const
static std::string GetChasteTestOutputDirectory()
out_stream OpenOutputFile(const std::string &rFileName, std::ios_base::openmode mode=std::ios::out|std::ios::trunc) const
static void CommonFinalize()
static bool AmMaster()
static bool IsParallel()
static void EndRoundRobin()
static unsigned GetMyRank()
static void BeginRoundRobin()
static unsigned GetNumProcs()