Chaste Commit::baa90ac2819b962188b7562f2326be23c47859a7
ExecutableSupport.cpp
1/*
2
3Copyright (c) 2005-2024, 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#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
97void ExecutableSupport::SetOutputDirectory(const std::string& rOutputDirectory)
98{
99 if (FileFinder::IsAbsolutePath(rOutputDirectory))
100 {
102 }
103 else
104 {
106 }
107}
108
109void 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, CHASTE_PETSC_NULLPTR, CHASTE_PETSC_NULLPTR));
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
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
157void 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 pclose(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 pclose(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 pclose(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 pclose(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
367void 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 output << "\t\t<ChasteTestOutputDirectory>" << OutputFileHandler::GetChasteTestOutputDirectory() << "</ChasteTestOutputDirectory>\n";
380
381 output << "\t\t<Projects>\n";
382 {
383 const std::map<std::string, std::string>& r_projects_modified = ChasteBuildInfo::rGetIfProjectsModified();
384 const std::map<std::string, std::string>& r_projects_versions = ChasteBuildInfo::rGetProjectVersions();
385 for (const auto& r_project_version : r_projects_versions)
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>" << r_projects_modified.at(r_project_version.first) << "</Modified>" << std::endl;
393 output << "\t\t\t</Project>" << std::endl;
394 // LCOV_EXCL_STOP
395 }
396 }
397 output << "\t\t</Projects>\n";
398
399 output << "\t</ProvenanceInfo>\n";
400
401 output << "\t<Compiler>\n";
402 output << "\t\t<NameAndVersion>" << ChasteBuildInfo::GetCompilerType() << ", version " << ChasteBuildInfo::GetCompilerVersion() << "</NameAndVersion>\n";
403 output << "\t\t<Flags>" << ChasteBuildInfo::GetCompilerFlags() << "</Flags>\n";
404 output << "\t</Compiler>\n";
405
406 output << "\t<Libraries>\n";
407
408 output << "\t\t<CompiledIn>\n";
409 output << "\t\t\t<PETSc>" << PETSC_VERSION_MAJOR << "." << PETSC_VERSION_MINOR << "." << PETSC_VERSION_SUBMINOR << "</PETSc>\n";
410 output << "\t\t\t<Boost>" << BOOST_VERSION / 100000 << "." << BOOST_VERSION / 100 % 1000 << "." << BOOST_VERSION % 100 << "</Boost>\n";
411 output << "\t\t\t<HDF5>" << H5_VERS_MAJOR << "." << H5_VERS_MINOR << "." << H5_VERS_RELEASE << "</HDF5>\n";
412 output << "\t\t\t<Parmetis>" << PARMETIS_MAJOR_VERSION << "." << PARMETIS_MINOR_VERSION;
413#ifdef PARMETIS_SUBMINOR_VERSION // they only added this in v4.? !!
414 output << "." << PARMETIS_SUBMINOR_VERSION;
415#endif
416 output << "</Parmetis>" << std::endl;
417 output << "\t\t</CompiledIn>\n";
418
419 output << "\t\t<Binaries>\n";
420 output << "\t\t\t<XSD>" << ChasteBuildInfo::GetXsdVersion() << "</XSD>\n";
421 output << "\t\t</Binaries>\n";
422
423 output << "\t\t<Optional>\n";
424#ifdef CHASTE_CVODE
425 output << "\t\t\t<SUNDIALS>" << CHASTE_SUNDIALS_PACKAGE_VERSION << "</SUNDIALS>";
426#if CHASTE_SUNDIALS_VERSION < 30000
427 output << "<!-- includes Cvode of a different version number -->";
428#endif
429 output << std::endl;
430#else
431 output << "\t\t\t<SUNDIALS>no</SUNDIALS>\n";
432#endif
433#ifdef CHASTE_VTK
434 output << "\t\t\t<VTK>" << VTK_MAJOR_VERSION << "." << VTK_MINOR_VERSION << "</VTK>\n";
435#else
436 output << "\t\t\t<VTK>no</VTK>\n";
437#endif
438#ifdef CHASTE_XERCES
439 output << "\t\t\t<Xerces>" << XERCES_FULLVERSIONDOT << "</Xerces>\n"; // Note: not a requirement for cell-based so may not be present!
440#else
441 output << "\t\t\t<Xerces>no</Xerces>\n";
442#endif
443 output << "\t\t</Optional>\n";
444
445 output << "\t</Libraries>\n";
446
447 output << "\t<ChasteCodegenVersion>" << ChasteBuildInfo::GetChasteCodegenVersion() << "</ChasteCodegenVersion>\n";
448
449 output << "</ChasteBuildInfo>" << std::endl;
450 rInfo = output.str();
451}
452
453void ExecutableSupport::StandardStartup(int* pArgc, char*** pArgv)
454{
455 InitializePetsc(pArgc, pArgv);
458}
459
461{
462 InitializePetsc(pArgc, pArgv);
464}
465
466void ExecutableSupport::PrintError(const std::string& rMessage, bool masterOnly)
467{
468 if (!masterOnly || PetscTools::AmMaster())
469 {
470 // Write the error message to stderr
471 std::cerr << rMessage << std::endl;
472 }
473
474 // Write the error message to file
476 {
477 // LCOV_EXCL_START
478 //depends on order of calls. Extract to method?
480 // LCOV_EXCL_STOP
481 }
482 OutputFileHandler out_file_handler(mOutputDirectory, false);
483 out_stream out_file = out_file_handler.OpenOutputFile("chaste_errors_", PetscTools::GetMyRank(), ".txt", std::ios::out | std::ios::app);
484 *out_file << rMessage << std::endl;
485 out_file->close();
486}
487
488void ExecutableSupport::Print(const std::string& rMessage)
489{
491 {
492 // Write the error message to stdout
493 std::cout << rMessage << std::endl
494 << std::flush;
495 }
496}
497
499{
500 // Causes memory failure (and seg fault) in PETSc 3.2 with MPICH-1
502}
#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()