2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5 * Copyright (c) 2001-2004, The GROMACS development team.
6 * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
7 * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
8 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
9 * and including many others, as listed in the AUTHORS file in the
10 * top-level source directory and at http://www.gromacs.org.
12 * GROMACS is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public License
14 * as published by the Free Software Foundation; either version 2.1
15 * of the License, or (at your option) any later version.
17 * GROMACS is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with GROMACS; if not, see
24 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
25 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 * If you want to redistribute modifications to GROMACS, please
28 * consider that scientific software is very special. Version
29 * control is crucial - bugs must be traceable. We will be happy to
30 * consider code for inclusion in the official distribution, but
31 * derived work must not be called official GROMACS. Details are found
32 * in the README & COPYING files - if they are missing, get the
33 * official version at http://www.gromacs.org.
35 * To help us fund GROMACS development, we humbly ask that you cite
36 * the research papers on the package. Check out http://www.gromacs.org.
39 * \brief Implements functionality for printing information about the
40 * currently running binary
42 * \ingroup module_utility
46 #include "binaryinformation.h"
50 #if GMX_FFT_FFTW3 || GMX_FFT_ARMPL_FFTW3
51 // Needed for construction of the FFT library description string
60 # include <extrae_user_events.h>
75 /* This file is completely threadsafe - keep it that way! */
77 #include "buildinfo.h"
78 #include "gromacs/utility/arraysize.h"
79 #include "gromacs/utility/baseversion.h"
80 #include "gromacs/utility/exceptions.h"
81 #include "gromacs/utility/gmxassert.h"
82 #include "gromacs/utility/path.h"
83 #include "gromacs/utility/programcontext.h"
84 #include "gromacs/utility/stringutil.h"
85 #include "gromacs/utility/sysinfo.h"
86 #include "gromacs/utility/textwriter.h"
88 #include "cuda_version_information.h"
93 using gmx::formatString
;
95 //! \cond Doxygen does not need to care about most of this stuff, and the macro usage is painful to document
97 int centeringOffset(int width
, int length
)
99 return std::max(width
- length
, 0) / 2;
102 std::string
formatCentered(int width
, const char* text
)
104 const int offset
= centeringOffset(width
, std::strlen(text
));
105 return formatString("%*s%s", offset
, "", text
);
108 void printCopyright(gmx::TextWriter
* writer
)
110 static const char* const Contributors
[] = { "Andrey Alekseenko",
114 "Herman J.C. Berendsen",
117 "Viacheslav Bolnykh",
125 "Vincent Hindriksen",
128 "Christoph Junghans",
130 "Dimitrios Karkoulis",
151 "Christian Wennberg",
154 static const char* const CopyrightText
[] = {
155 "Copyright (c) 1991-2000, University of Groningen, The Netherlands.",
156 "Copyright (c) 2001-2019, The GROMACS development team at",
157 "Uppsala University, Stockholm University and", "the Royal Institute of Technology, Sweden.",
158 "check out http://www.gromacs.org for more information."
161 #define NCONTRIBUTORS static_cast<int>(asize(Contributors))
162 #define NCR static_cast<int>(asize(CopyrightText))
164 // TODO a centering behaviour of TextWriter could be useful here
165 writer
->writeLine(formatCentered(78, "GROMACS is written by:"));
166 for (int i
= 0; i
< NCONTRIBUTORS
;)
168 for (int j
= 0; j
< 3 && i
< NCONTRIBUTORS
; ++j
, ++i
)
170 const int width
= 26;
171 std::array
<char, 30> buf
;
172 const int offset
= centeringOffset(width
, strlen(Contributors
[i
]));
173 GMX_RELEASE_ASSERT(static_cast<int>(strlen(Contributors
[i
])) + offset
< gmx::ssize(buf
),
174 "Formatting buffer is not long enough");
175 std::fill(buf
.begin(), buf
.begin() + offset
, ' ');
176 std::strncpy(buf
.data() + offset
, Contributors
[i
], gmx::ssize(buf
) - offset
);
177 writer
->writeString(formatString(" %-*s", width
, buf
.data()));
179 writer
->ensureLineBreak();
181 writer
->writeLine(formatCentered(78, "and the project leaders:"));
183 formatCentered(78, "Mark Abraham, Berk Hess, Erik Lindahl, and David van der Spoel"));
184 writer
->ensureEmptyLine();
185 for (int i
= 0; i
< NCR
; ++i
)
187 writer
->writeLine(CopyrightText
[i
]);
189 writer
->ensureEmptyLine();
191 // Folding At Home has different licence to allow digital
192 // signatures in GROMACS, so does not need to show the normal
193 // license statement.
196 writer
->writeLine("GROMACS is free software; you can redistribute it and/or modify it");
197 writer
->writeLine("under the terms of the GNU Lesser General Public License");
198 writer
->writeLine("as published by the Free Software Foundation; either version 2.1");
199 writer
->writeLine("of the License, or (at your option) any later version.");
203 // Construct a string that describes the library that provides FFT support to this build
204 const char* getFftDescriptionString()
206 // Define the FFT description string
207 #if GMX_FFT_FFTW3 || GMX_FFT_ARMPL_FFTW3
208 # if GMX_NATIVE_WINDOWS
212 // Use the version string provided by libfftw3
216 return fftwf_version
;
224 return "fftpack (built-in)";
228 void gmx_print_version_info(gmx::TextWriter
* writer
)
230 writer
->writeLine(formatString("GROMACS version: %s", gmx_version()));
231 const char* const git_hash
= gmx_version_git_full_hash();
232 if (git_hash
[0] != '\0')
234 writer
->writeLine(formatString("GIT SHA1 hash: %s", git_hash
));
236 const char* const base_hash
= gmx_version_git_central_base_hash();
237 if (base_hash
[0] != '\0')
239 writer
->writeLine(formatString("Branched from: %s", base_hash
));
241 const char* const releaseSourceChecksum
= gmxReleaseSourceChecksum();
242 const char* const currentSourceChecksum
= gmxCurrentSourceChecksum();
243 if (releaseSourceChecksum
[0] != '\0')
245 if (std::strcmp(releaseSourceChecksum
, "NoChecksumFile") == 0)
247 writer
->writeLine(formatString(
248 "The source code this program was compiled from has not been verified because "
249 "the reference checksum was missing during compilation. This means you have an "
250 "incomplete GROMACS distribution, please make sure to download an intact "
251 "source distribution and compile that before proceeding."));
252 writer
->writeLine(formatString("Computed checksum: %s", currentSourceChecksum
));
254 else if (std::strcmp(releaseSourceChecksum
, "NoPythonAvailable") == 0)
257 formatString("Build source could not be verified, because the checksum could "
258 "not be computed."));
260 else if (std::strcmp(releaseSourceChecksum
, currentSourceChecksum
) != 0)
262 writer
->writeLine(formatString(
263 "This program has been built from source code that has been altered and does "
264 "not match the code released as part of the official GROMACS version %s. If "
265 "you did not intend to use an altered GROMACS version, make sure to download "
266 "an intact source distribution and compile that before proceeding.",
268 writer
->writeLine(formatString(
269 "If you have modified the source code, you are strongly encouraged to set your "
270 "custom version suffix (using -DGMX_VERSION_STRING_OF_FORK) which will can "
271 "help later with scientific reproducibility but also when reporting bugs."));
272 writer
->writeLine(formatString("Release checksum: %s", releaseSourceChecksum
));
273 writer
->writeLine(formatString("Computed checksum: %s", currentSourceChecksum
));
277 writer
->writeLine(formatString("Verified release checksum is %s", releaseSourceChecksum
));
283 writer
->writeLine("Precision: double");
285 writer
->writeLine("Precision: single");
287 writer
->writeLine(formatString("Memory model: %u bit", static_cast<unsigned>(8 * sizeof(void*))));
290 writer
->writeLine("MPI library: thread_mpi");
292 writer
->writeLine("MPI library: MPI");
294 writer
->writeLine("MPI library: none");
297 writer
->writeLine(formatString("OpenMP support: enabled (GMX_OPENMP_MAX_THREADS = %d)",
298 GMX_OPENMP_MAX_THREADS
));
300 writer
->writeLine("OpenMP support: disabled");
302 writer
->writeLine(formatString("GPU support: %s", getGpuImplementationString()));
303 writer
->writeLine(formatString("SIMD instructions: %s", GMX_SIMD_STRING
));
304 writer
->writeLine(formatString("FFT library: %s", getFftDescriptionString()));
306 writer
->writeLine(formatString("RDTSCP usage: %s", GMX_USE_RDTSCP
? "enabled" : "disabled"));
309 writer
->writeLine("TNG support: enabled");
311 writer
->writeLine("TNG support: disabled");
314 writer
->writeLine(formatString("Hwloc support: hwloc-%s", HWLOC_VERSION
));
316 writer
->writeLine("Hwloc support: disabled");
319 unsigned major
, minor
, revision
;
320 Extrae_get_version(&major
, &minor
, &revision
);
321 writer
->writeLine(formatString("Tracing support: enabled. Using Extrae-%d.%d.%d", major
,
324 writer
->writeLine("Tracing support: disabled");
328 /* TODO: The below strings can be quite long, so it would be nice to wrap
329 * them. Can wait for later, as the master branch has ready code to do all
331 writer
->writeLine(formatString("C compiler: %s", BUILD_C_COMPILER
));
332 writer
->writeLine(formatString("C compiler flags: %s %s", BUILD_CFLAGS
,
333 CMAKE_BUILD_CONFIGURATION_C_FLAGS
));
334 writer
->writeLine(formatString("C++ compiler: %s", BUILD_CXX_COMPILER
));
335 writer
->writeLine(formatString("C++ compiler flags: %s %s", BUILD_CXXFLAGS
,
336 CMAKE_BUILD_CONFIGURATION_CXX_FLAGS
));
338 /* MKL might be used for LAPACK/BLAS even if FFTs use FFTW, so keep it separate */
339 writer
->writeLine(formatString("Linked with Intel MKL version %d.%d.%d.", __INTEL_MKL__
,
340 __INTEL_MKL_MINOR__
, __INTEL_MKL_UPDATE__
));
343 writer
->writeLine(formatString("OpenCL include dir: %s", OPENCL_INCLUDE_DIR
));
344 writer
->writeLine(formatString("OpenCL library: %s", OPENCL_LIBRARY
));
345 writer
->writeLine(formatString("OpenCL version: %s", OPENCL_VERSION_STRING
));
348 writer
->writeLine(formatString("CUDA compiler: %s", CUDA_COMPILER_INFO
));
349 writer
->writeLine(formatString("CUDA compiler flags:%s %s", CUDA_COMPILER_FLAGS
,
350 CMAKE_BUILD_CONFIGURATION_CXX_FLAGS
));
351 writer
->writeLine("CUDA driver: " + gmx::getCudaDriverVersionString());
352 writer
->writeLine("CUDA runtime: " + gmx::getCudaRuntimeVersionString());
363 BinaryInformationSettings::BinaryInformationSettings() :
364 bExtendedInfo_(false),
367 bGeneratedByHeader_(false),
373 void printBinaryInformation(FILE* fp
, const IProgramContext
& programContext
)
375 TextWriter
writer(fp
);
376 printBinaryInformation(&writer
, programContext
, BinaryInformationSettings());
379 void printBinaryInformation(FILE* fp
,
380 const IProgramContext
& programContext
,
381 const BinaryInformationSettings
& settings
)
385 TextWriter
writer(fp
);
386 printBinaryInformation(&writer
, programContext
, settings
);
388 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
391 void printBinaryInformation(TextWriter
* writer
,
392 const IProgramContext
& programContext
,
393 const BinaryInformationSettings
& settings
)
395 // TODO Perhaps the writer could be configured with the prefix and
396 // suffix strings from the settings?
397 const char* prefix
= settings
.prefix_
;
398 const char* suffix
= settings
.suffix_
;
399 const char* precisionString
= "";
401 precisionString
= " (double precision)";
403 const char* const name
= programContext
.displayName();
404 if (settings
.bGeneratedByHeader_
)
406 writer
->writeLine(formatString("%sCreated by:%s", prefix
, suffix
));
408 // TODO: It would be nice to know here whether we are really running a
409 // Gromacs binary or some other binary that is calling Gromacs; we
410 // could then print "%s is part of GROMACS" or some alternative text.
411 std::string title
= formatString(":-) GROMACS - %s, %s%s (-:", name
, gmx_version(), precisionString
);
413 centeringOffset(78 - std::strlen(prefix
) - std::strlen(suffix
), title
.length()) + 1;
414 writer
->writeLine(formatString("%s%*c%s%s", prefix
, indent
, ' ', title
.c_str(), suffix
));
415 writer
->writeLine(formatString("%s%s", prefix
, suffix
));
416 if (settings
.bCopyright_
)
418 GMX_RELEASE_ASSERT(prefix
[0] == '\0' && suffix
[0] == '\0',
419 "Prefix/suffix not supported with copyright");
420 printCopyright(writer
);
421 writer
->ensureEmptyLine();
422 // This line is printed again after the copyright notice to make it
423 // appear together with all the other information, so that it is not
424 // necessary to read stuff above the copyright notice.
425 // The line above the copyright notice puts the copyright notice is
427 writer
->writeLine(formatString("%sGROMACS: %s, version %s%s%s", prefix
, name
,
428 gmx_version(), precisionString
, suffix
));
430 const char* const binaryPath
= programContext
.fullBinaryPath();
431 if (!gmx::isNullOrEmpty(binaryPath
))
433 writer
->writeLine(formatString("%sExecutable: %s%s", prefix
, binaryPath
, suffix
));
435 const gmx::InstallationPrefixInfo installPrefix
= programContext
.installationPrefix();
436 if (!gmx::isNullOrEmpty(installPrefix
.path
))
438 writer
->writeLine(formatString("%sData prefix: %s%s%s", prefix
, installPrefix
.path
,
439 installPrefix
.bSourceLayout
? " (source tree)" : "", suffix
));
441 const std::string workingDir
= Path::getWorkingDirectory();
442 if (!workingDir
.empty())
444 writer
->writeLine(formatString("%sWorking dir: %s%s", prefix
, workingDir
.c_str(), suffix
));
446 if (settings
.bProcessId_
)
448 writer
->writeLine(formatString("%sProcess ID: %d%s", prefix
, gmx_getpid(), suffix
));
450 const char* const commandLine
= programContext
.commandLine();
451 if (!gmx::isNullOrEmpty(commandLine
))
453 writer
->writeLine(formatString("%sCommand line:%s\n%s %s%s", prefix
, suffix
, prefix
,
454 commandLine
, suffix
));
456 if (settings
.bExtendedInfo_
)
458 GMX_RELEASE_ASSERT(prefix
[0] == '\0' && suffix
[0] == '\0',
459 "Prefix/suffix not supported with extended info");
460 writer
->ensureEmptyLine();
461 gmx_print_version_info(writer
);