Update instructions in containers.rst
[gromacs.git] / src / gromacs / utility / binaryinformation.cpp
blob7127a5b4d500b01d2fdfd0de52de2fcfa3c2e541
1 /*
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.
38 /*! \internal \file
39 * \brief Implements functionality for printing information about the
40 * currently running binary
42 * \ingroup module_utility
44 #include "gmxpre.h"
46 #include "binaryinformation.h"
48 #include "config.h"
50 #if GMX_FFT_FFTW3 || GMX_FFT_ARMPL_FFTW3
51 // Needed for construction of the FFT library description string
52 # include <fftw3.h>
53 #endif
55 #ifdef HAVE_LIBMKL
56 # include <mkl.h>
57 #endif
59 #if HAVE_EXTRAE
60 # include <extrae_user_events.h>
61 #endif
63 #if GMX_USE_HWLOC
64 # include <hwloc.h>
65 #endif
67 #include <cstdio>
68 #include <cstdlib>
69 #include <cstring>
71 #include <algorithm>
72 #include <array>
73 #include <string>
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"
90 namespace
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",
111 "Emile Apol",
112 "Rossen Apostolov",
113 "Paul Bauer",
114 "Herman J.C. Berendsen",
115 "Par Bjelkmar",
116 "Christian Blau",
117 "Viacheslav Bolnykh",
118 "Kevin Boyd",
119 "Aldert van Buuren",
120 "Rudi van Drunen",
121 "Anton Feenstra",
122 "Alan Gray",
123 "Gerrit Groenhof",
124 "Anca Hamuraru",
125 "Vincent Hindriksen",
126 "M. Eric Irrgang",
127 "Aleksei Iupinov",
128 "Christoph Junghans",
129 "Joe Jordan",
130 "Dimitrios Karkoulis",
131 "Peter Kasson",
132 "Jiri Kraus",
133 "Carsten Kutzner",
134 "Per Larsson",
135 "Justin A. Lemkul",
136 "Viveca Lindahl",
137 "Magnus Lundborg",
138 "Erik Marklund",
139 "Pascal Merz",
140 "Pieter Meulenhoff",
141 "Teemu Murtola",
142 "Szilard Pall",
143 "Sander Pronk",
144 "Roland Schulz",
145 "Michael Shirts",
146 "Alexey Shvetsov",
147 "Alfons Sijbers",
148 "Peter Tieleman",
149 "Jon Vincent",
150 "Teemu Virolainen",
151 "Christian Wennberg",
152 "Maarten Wolf",
153 "Artem Zhmurov" };
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:"));
182 writer->writeLine(
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.
194 if (!GMX_FAHCORE)
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
209 // Don't buy trouble
210 return "fftw3";
211 # else
212 // Use the version string provided by libfftw3
213 # if GMX_DOUBLE
214 return fftw_version;
215 # else
216 return fftwf_version;
217 # endif
218 # endif
219 #endif
220 #if GMX_FFT_MKL
221 return "Intel MKL";
222 #endif
223 #if GMX_FFT_FFTPACK
224 return "fftpack (built-in)";
225 #endif
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)
256 writer->writeLine(
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.",
267 gmx_version()));
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));
275 else
277 writer->writeLine(formatString("Verified release checksum is %s", releaseSourceChecksum));
282 #if GMX_DOUBLE
283 writer->writeLine("Precision: double");
284 #else
285 writer->writeLine("Precision: single");
286 #endif
287 writer->writeLine(formatString("Memory model: %u bit", static_cast<unsigned>(8 * sizeof(void*))));
289 #if GMX_THREAD_MPI
290 writer->writeLine("MPI library: thread_mpi");
291 #elif GMX_MPI
292 writer->writeLine("MPI library: MPI");
293 #else
294 writer->writeLine("MPI library: none");
295 #endif
296 #if GMX_OPENMP
297 writer->writeLine(formatString("OpenMP support: enabled (GMX_OPENMP_MAX_THREADS = %d)",
298 GMX_OPENMP_MAX_THREADS));
299 #else
300 writer->writeLine("OpenMP support: disabled");
301 #endif
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()));
305 #if GMX_TARGET_X86
306 writer->writeLine(formatString("RDTSCP usage: %s", GMX_USE_RDTSCP ? "enabled" : "disabled"));
307 #endif
308 #if GMX_USE_TNG
309 writer->writeLine("TNG support: enabled");
310 #else
311 writer->writeLine("TNG support: disabled");
312 #endif
313 #if GMX_USE_HWLOC
314 writer->writeLine(formatString("Hwloc support: hwloc-%s", HWLOC_VERSION));
315 #else
316 writer->writeLine("Hwloc support: disabled");
317 #endif
318 #if HAVE_EXTRAE
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,
322 minor, revision));
323 #else
324 writer->writeLine("Tracing support: disabled");
325 #endif
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
330 * that. */
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));
337 #ifdef HAVE_LIBMKL
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__));
341 #endif
342 #if GMX_GPU_OPENCL
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));
346 #endif
347 #if GMX_GPU_CUDA
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());
353 #endif
356 //! \endcond
358 } // namespace
360 namespace gmx
363 BinaryInformationSettings::BinaryInformationSettings() :
364 bExtendedInfo_(false),
365 bCopyright_(false),
366 bProcessId_(false),
367 bGeneratedByHeader_(false),
368 prefix_(""),
369 suffix_("")
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 = "";
400 #if GMX_DOUBLE
401 precisionString = " (double precision)";
402 #endif
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);
412 const int indent =
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
426 // context, though.
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);
465 } // namespace gmx