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,2021, 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"
89 #include "sycl_version_information.h"
94 using gmx::formatString;
96 //! \cond Doxygen does not need to care about most of this stuff, and the macro usage is painful to document
98 int centeringOffset(int width, int length)
100 return std::max(width - length, 0) / 2;
103 std::string formatCentered(int width, const char* text)
105 const int offset = centeringOffset(width, std::strlen(text));
106 return formatString("%*s%s", offset, "", text);
109 void printCopyright(gmx::TextWriter* writer)
111 // Contributors sorted alphabetically by last name
112 static const char* const Contributors[] = { "Andrey Alekseenko",
116 "Herman J.C. Berendsen",
119 "Viacheslav Bolnykh",
126 "Gilles Gouaillardet",
130 "Vincent Hindriksen",
133 "Christoph Junghans",
135 "Dimitrios Karkoulis",
156 "Christian Wennberg",
159 static const char* const CopyrightText[] = {
160 "Copyright (c) 1991-2000, University of Groningen, The Netherlands.",
161 "Copyright (c) 2001-2019, The GROMACS development team at",
162 "Uppsala University, Stockholm University and",
163 "the Royal Institute of Technology, Sweden.",
164 "check out http://www.gromacs.org for more information."
167 #define NCONTRIBUTORS static_cast<int>(asize(Contributors))
168 #define NCR static_cast<int>(asize(CopyrightText))
170 // TODO a centering behaviour of TextWriter could be useful here
171 writer->writeLine(formatCentered(78, "GROMACS is written by:"));
172 for (int i = 0; i < NCONTRIBUTORS;)
174 for (int j = 0; j < 3 && i < NCONTRIBUTORS; ++j, ++i)
176 const int width = 26;
177 std::array<char, 30> buf;
178 const int offset = centeringOffset(width, strlen(Contributors[i]));
179 GMX_RELEASE_ASSERT(static_cast<int>(strlen(Contributors[i])) + offset < gmx::ssize(buf),
180 "Formatting buffer is not long enough");
181 std::fill(buf.begin(), buf.begin() + offset, ' ');
182 std::strncpy(buf.data() + offset, Contributors[i], gmx::ssize(buf) - offset);
183 writer->writeString(formatString(" %-*s", width, buf.data()));
185 writer->ensureLineBreak();
187 writer->writeLine(formatCentered(78, "and the project leaders:"));
189 formatCentered(78, "Mark Abraham, Berk Hess, Erik Lindahl, and David van der Spoel"));
190 writer->ensureEmptyLine();
191 for (int i = 0; i < NCR; ++i)
193 writer->writeLine(CopyrightText[i]);
195 writer->ensureEmptyLine();
197 // Folding At Home has different licence to allow digital
198 // signatures in GROMACS, so does not need to show the normal
199 // license statement.
202 writer->writeLine("GROMACS is free software; you can redistribute it and/or modify it");
203 writer->writeLine("under the terms of the GNU Lesser General Public License");
204 writer->writeLine("as published by the Free Software Foundation; either version 2.1");
205 writer->writeLine("of the License, or (at your option) any later version.");
209 //! Construct a string that describes the library that provides CPU FFT support to this build
210 const char* getCpuFftDescriptionString()
212 // Define the FFT description string
213 #if GMX_FFT_FFTW3 || GMX_FFT_ARMPL_FFTW3
214 # if GMX_NATIVE_WINDOWS
218 // Use the version string provided by libfftw3
222 return fftwf_version;
230 return "fftpack (built-in)";
234 //! Construct a string that describes the library that provides GPU FFT support to this build
235 const char* getGpuFftDescriptionString()
243 else if (GMX_GPU_OPENCL)
247 else if (GMX_GPU_SYCL)
253 GMX_RELEASE_ASSERT(false, "Unknown GPU configuration");
263 void gmx_print_version_info(gmx::TextWriter* writer)
265 writer->writeLine(formatString("GROMACS version: %s", gmx_version()));
266 const char* const git_hash = gmx_version_git_full_hash();
267 if (git_hash[0] != '\0')
269 writer->writeLine(formatString("GIT SHA1 hash: %s", git_hash));
271 const char* const base_hash = gmx_version_git_central_base_hash();
272 if (base_hash[0] != '\0')
274 writer->writeLine(formatString("Branched from: %s", base_hash));
276 const char* const releaseSourceChecksum = gmxReleaseSourceChecksum();
277 const char* const currentSourceChecksum = gmxCurrentSourceChecksum();
278 if (releaseSourceChecksum[0] != '\0')
280 if (std::strcmp(releaseSourceChecksum, "NoChecksumFile") == 0)
282 writer->writeLine(formatString(
283 "The source code this program was compiled from has not been verified because "
284 "the reference checksum was missing during compilation. This means you have an "
285 "incomplete GROMACS distribution, please make sure to download an intact "
286 "source distribution and compile that before proceeding."));
287 writer->writeLine(formatString("Computed checksum: %s", currentSourceChecksum));
289 else if (std::strcmp(releaseSourceChecksum, "NoPythonAvailable") == 0)
292 formatString("Build source could not be verified, because the checksum could "
293 "not be computed."));
295 else if (std::strcmp(releaseSourceChecksum, currentSourceChecksum) != 0)
297 writer->writeLine(formatString(
298 "This program has been built from source code that has been altered and does "
299 "not match the code released as part of the official GROMACS version %s. If "
300 "you did not intend to use an altered GROMACS version, make sure to download "
301 "an intact source distribution and compile that before proceeding.",
303 writer->writeLine(formatString(
304 "If you have modified the source code, you are strongly encouraged to set your "
305 "custom version suffix (using -DGMX_VERSION_STRING_OF_FORK) which will can "
306 "help later with scientific reproducibility but also when reporting bugs."));
307 writer->writeLine(formatString("Release checksum: %s", releaseSourceChecksum));
308 writer->writeLine(formatString("Computed checksum: %s", currentSourceChecksum));
312 writer->writeLine(formatString("Verified release checksum is %s", releaseSourceChecksum));
318 writer->writeLine("Precision: double");
320 writer->writeLine("Precision: mixed");
322 writer->writeLine(formatString("Memory model: %u bit", static_cast<unsigned>(8 * sizeof(void*))));
325 writer->writeLine("MPI library: thread_mpi");
327 # if HAVE_CUDA_AWARE_MPI
328 writer->writeLine("MPI library: MPI (CUDA-aware)");
330 writer->writeLine("MPI library: MPI");
333 writer->writeLine("MPI library: none");
336 writer->writeLine(formatString("OpenMP support: enabled (GMX_OPENMP_MAX_THREADS = %d)",
337 GMX_OPENMP_MAX_THREADS));
339 writer->writeLine("OpenMP support: disabled");
341 writer->writeLine(formatString("GPU support: %s", getGpuImplementationString()));
342 writer->writeLine(formatString("SIMD instructions: %s", GMX_SIMD_STRING));
343 writer->writeLine(formatString("CPU FFT library: %s", getCpuFftDescriptionString()));
344 writer->writeLine(formatString("GPU FFT library: %s", getGpuFftDescriptionString()));
346 writer->writeLine(formatString("RDTSCP usage: %s", GMX_USE_RDTSCP ? "enabled" : "disabled"));
349 writer->writeLine("TNG support: enabled");
351 writer->writeLine("TNG support: disabled");
354 writer->writeLine(formatString("Hwloc support: hwloc-%s", HWLOC_VERSION));
356 writer->writeLine("Hwloc support: disabled");
359 unsigned major, minor, revision;
360 Extrae_get_version(&major, &minor, &revision);
361 writer->writeLine(formatString(
362 "Tracing support: enabled. Using Extrae-%d.%d.%d", major, minor, revision));
364 writer->writeLine("Tracing support: disabled");
368 /* TODO: The below strings can be quite long, so it would be nice to wrap
369 * them. Can wait for later, as the master branch has ready code to do all
371 writer->writeLine(formatString("C compiler: %s", BUILD_C_COMPILER));
372 writer->writeLine(formatString(
373 "C compiler flags: %s %s", BUILD_CFLAGS, CMAKE_BUILD_CONFIGURATION_C_FLAGS));
374 writer->writeLine(formatString("C++ compiler: %s", BUILD_CXX_COMPILER));
375 writer->writeLine(formatString(
376 "C++ compiler flags: %s %s", BUILD_CXXFLAGS, CMAKE_BUILD_CONFIGURATION_CXX_FLAGS));
378 /* MKL might be used for LAPACK/BLAS even if FFTs use FFTW, so keep it separate */
379 writer->writeLine(formatString(
380 "Intel MKL version: %d.%d.%d", __INTEL_MKL__, __INTEL_MKL_MINOR__, __INTEL_MKL_UPDATE__));
383 writer->writeLine(formatString("OpenCL include dir: %s", OPENCL_INCLUDE_DIR));
384 writer->writeLine(formatString("OpenCL library: %s", OPENCL_LIBRARY));
385 writer->writeLine(formatString("OpenCL version: %s", OPENCL_VERSION_STRING));
388 writer->writeLine(formatString("CUDA compiler: %s", CUDA_COMPILER_INFO));
389 writer->writeLine(formatString(
390 "CUDA compiler flags:%s %s", CUDA_COMPILER_FLAGS, CMAKE_BUILD_CONFIGURATION_CXX_FLAGS));
391 writer->writeLine("CUDA driver: " + gmx::getCudaDriverVersionString());
392 writer->writeLine("CUDA runtime: " + gmx::getCudaRuntimeVersionString());
395 writer->writeLine(formatString("SYCL DPC++ flags: %s", SYCL_DPCPP_COMPILER_FLAGS));
396 writer->writeLine("SYCL DPC++ version: " + gmx::getSyclCompilerVersion());
399 writer->writeLine(formatString("hipSYCL launcher: %s", SYCL_HIPSYCL_COMPILER_LAUNCHER));
400 writer->writeLine(formatString("hipSYCL flags: %s", SYCL_HIPSYCL_COMPILER_FLAGS));
401 writer->writeLine(formatString("hipSYCL targets: %s", SYCL_HIPSYCL_TARGETS));
402 writer->writeLine("hipSYCL version: " + gmx::getSyclCompilerVersion());
413 BinaryInformationSettings::BinaryInformationSettings() :
414 bExtendedInfo_(false),
417 bGeneratedByHeader_(false),
423 void printBinaryInformation(FILE* fp, const IProgramContext& programContext)
425 TextWriter writer(fp);
426 printBinaryInformation(&writer, programContext, BinaryInformationSettings());
429 void printBinaryInformation(FILE* fp,
430 const IProgramContext& programContext,
431 const BinaryInformationSettings& settings)
435 TextWriter writer(fp);
436 printBinaryInformation(&writer, programContext, settings);
438 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
441 void printBinaryInformation(TextWriter* writer,
442 const IProgramContext& programContext,
443 const BinaryInformationSettings& settings)
445 // TODO Perhaps the writer could be configured with the prefix and
446 // suffix strings from the settings?
447 const char* prefix = settings.prefix_;
448 const char* suffix = settings.suffix_;
449 const char* precisionString = "";
451 precisionString = " (double precision)";
453 const char* const name = programContext.displayName();
454 if (settings.bGeneratedByHeader_)
456 writer->writeLine(formatString("%sCreated by:%s", prefix, suffix));
458 // TODO: It would be nice to know here whether we are really running a
459 // Gromacs binary or some other binary that is calling Gromacs; we
460 // could then print "%s is part of GROMACS" or some alternative text.
461 std::string title = formatString(":-) GROMACS - %s, %s%s (-:", name, gmx_version(), precisionString);
463 centeringOffset(78 - std::strlen(prefix) - std::strlen(suffix), title.length()) + 1;
464 writer->writeLine(formatString("%s%*c%s%s", prefix, indent, ' ', title.c_str(), suffix));
465 writer->writeLine(formatString("%s%s", prefix, suffix));
466 if (settings.bCopyright_)
468 GMX_RELEASE_ASSERT(prefix[0] == '\0' && suffix[0] == '\0',
469 "Prefix/suffix not supported with copyright");
470 printCopyright(writer);
471 writer->ensureEmptyLine();
472 // This line is printed again after the copyright notice to make it
473 // appear together with all the other information, so that it is not
474 // necessary to read stuff above the copyright notice.
475 // The line above the copyright notice puts the copyright notice is
477 writer->writeLine(formatString(
478 "%sGROMACS: %s, version %s%s%s", prefix, name, gmx_version(), precisionString, suffix));
480 const char* const binaryPath = programContext.fullBinaryPath();
481 if (!gmx::isNullOrEmpty(binaryPath))
483 writer->writeLine(formatString("%sExecutable: %s%s", prefix, binaryPath, suffix));
485 const gmx::InstallationPrefixInfo installPrefix = programContext.installationPrefix();
486 if (!gmx::isNullOrEmpty(installPrefix.path))
488 writer->writeLine(formatString("%sData prefix: %s%s%s",
491 installPrefix.bSourceLayout ? " (source tree)" : "",
494 const std::string workingDir = Path::getWorkingDirectory();
495 if (!workingDir.empty())
497 writer->writeLine(formatString("%sWorking dir: %s%s", prefix, workingDir.c_str(), suffix));
499 if (settings.bProcessId_)
501 writer->writeLine(formatString("%sProcess ID: %d%s", prefix, gmx_getpid(), suffix));
503 const char* const commandLine = programContext.commandLine();
504 if (!gmx::isNullOrEmpty(commandLine))
506 writer->writeLine(formatString(
507 "%sCommand line:%s\n%s %s%s", prefix, suffix, prefix, commandLine, suffix));
509 if (settings.bExtendedInfo_)
511 GMX_RELEASE_ASSERT(prefix[0] == '\0' && suffix[0] == '\0',
512 "Prefix/suffix not supported with extended info");
513 writer->ensureEmptyLine();
514 gmx_print_version_info(writer);