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, led by
7 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
8 * and including many others, as listed in the AUTHORS file in the
9 * top-level source directory and at http://www.gromacs.org.
11 * GROMACS is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public License
13 * as published by the Free Software Foundation; either version 2.1
14 * of the License, or (at your option) any later version.
16 * GROMACS is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with GROMACS; if not, see
23 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
24 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 * If you want to redistribute modifications to GROMACS, please
27 * consider that scientific software is very special. Version
28 * control is crucial - bugs must be traceable. We will be happy to
29 * consider code for inclusion in the official distribution, but
30 * derived work must not be called official GROMACS. Details are found
31 * in the README & COPYING files - if they are missing, get the
32 * official version at http://www.gromacs.org.
34 * To help us fund GROMACS development, we humbly ask that you cite
35 * the research papers on the package. Check out http://www.gromacs.org.
38 * \brief Implements functionality for printing information about the
39 * currently running binary
41 * \ingroup module_utility
45 #include "binaryinformation.h"
50 // Needed for construction of the FFT library description string
59 #include <extrae_user_events.h>
73 /* This file is completely threadsafe - keep it that way! */
75 #include "buildinfo.h"
76 #include "gromacs/utility/arraysize.h"
77 #include "gromacs/utility/baseversion.h"
78 #include "gromacs/utility/exceptions.h"
79 #include "gromacs/utility/gmxassert.h"
80 #include "gromacs/utility/path.h"
81 #include "gromacs/utility/programcontext.h"
82 #include "gromacs/utility/stringutil.h"
83 #include "gromacs/utility/textwriter.h"
85 #include "cuda_version_information.h"
90 using gmx::formatString;
92 //! \cond Doxygen does not need to care about most of this stuff, and the macro usage is painful to document
94 int centeringOffset(int width, int length)
96 return std::max(width - length, 0) / 2;
99 std::string formatCentered(int width, const char *text)
101 const int offset = centeringOffset(width, std::strlen(text));
102 return formatString("%*s%s", offset, "", text);
105 void printCopyright(gmx::TextWriter *writer)
107 static const char * const Contributors[] = {
110 "Herman J.C. Berendsen",
116 "Christoph Junghans",
118 "Vincent Hindriksen",
119 "Dimitrios Karkoulis",
138 "Christian Wennberg",
141 static const char * const CopyrightText[] = {
142 "Copyright (c) 1991-2000, University of Groningen, The Netherlands.",
143 "Copyright (c) 2001-2017, The GROMACS development team at",
144 "Uppsala University, Stockholm University and",
145 "the Royal Institute of Technology, Sweden.",
146 "check out http://www.gromacs.org for more information."
148 static const char * const LicenseText[] = {
149 "GROMACS is free software; you can redistribute it and/or modify it",
150 "under the terms of the GNU Lesser General Public License",
151 "as published by the Free Software Foundation; either version 2.1",
152 "of the License, or (at your option) any later version."
155 #define NCONTRIBUTORS (int)asize(Contributors)
156 #define NCR (int)asize(CopyrightText)
158 // FAH has an exception permission from LGPL to allow digital signatures in Gromacs.
162 #define NLICENSE (int)asize(LicenseText)
165 // TODO a centering behaviour of TextWriter could be useful here
166 writer->writeLine(formatCentered(78, "GROMACS is written by:"));
167 for (int i = 0; i < NCONTRIBUTORS; )
169 for (int j = 0; j < 4 && i < NCONTRIBUTORS; ++j, ++i)
171 const int width = 18;
173 const int offset = centeringOffset(width, strlen(Contributors[i]));
174 GMX_RELEASE_ASSERT(strlen(Contributors[i]) + offset < asize(buf),
175 "Formatting buffer is not long enough");
176 std::fill(buf, buf+width, ' ');
177 std::strcpy(buf+offset, Contributors[i]);
178 writer->writeString(formatString(" %-*s", width, buf));
180 writer->ensureLineBreak();
182 writer->writeLine(formatCentered(78, "and the project leaders:"));
183 writer->writeLine(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();
190 for (int i = 0; i < NLICENSE; ++i)
192 writer->writeLine(LicenseText[i]);
196 // Construct a string that describes the library that provides FFT support to this build
197 const char *getFftDescriptionString()
199 // Define the FFT description string
201 # if GMX_NATIVE_WINDOWS
205 // Use the version string provided by libfftw3
209 return fftwf_version;
217 return "fftpack (built-in)";
221 void gmx_print_version_info(gmx::TextWriter *writer)
223 writer->writeLine(formatString("GROMACS version: %s", gmx_version()));
224 const char *const git_hash = gmx_version_git_full_hash();
225 if (git_hash[0] != '\0')
227 writer->writeLine(formatString("GIT SHA1 hash: %s", git_hash));
229 const char *const base_hash = gmx_version_git_central_base_hash();
230 if (base_hash[0] != '\0')
232 writer->writeLine(formatString("Branched from: %s", base_hash));
236 writer->writeLine("Precision: double");
238 writer->writeLine("Precision: single");
240 writer->writeLine(formatString("Memory model: %u bit", (unsigned)(8*sizeof(void *))));
243 writer->writeLine("MPI library: thread_mpi");
245 writer->writeLine("MPI library: MPI");
247 writer->writeLine("MPI library: none");
250 writer->writeLine(formatString("OpenMP support: enabled (GMX_OPENMP_MAX_THREADS = %d)", GMX_OPENMP_MAX_THREADS));
252 writer->writeLine("OpenMP support: disabled");
254 writer->writeLine(formatString("GPU support: %s", getGpuImplementationString()));
255 writer->writeLine(formatString("SIMD instructions: %s", GMX_SIMD_STRING));
256 writer->writeLine(formatString("FFT library: %s", getFftDescriptionString()));
257 writer->writeLine(formatString("RDTSCP usage: %s", HAVE_RDTSCP ? "enabled" : "disabled"));
259 writer->writeLine("TNG support: enabled");
261 writer->writeLine("TNG support: disabled");
264 writer->writeLine(formatString("Hwloc support: hwloc-%d.%d.%d",
265 HWLOC_API_VERSION>>16,
266 (HWLOC_API_VERSION>>8) & 0xFF,
267 HWLOC_API_VERSION & 0xFF));
269 writer->writeLine("Hwloc support: disabled");
272 unsigned major, minor, revision;
273 Extrae_get_version(&major, &minor, &revision);
274 writer->writeLine(formatString("Tracing support: enabled. Using Extrae-%d.%d.%d", major, minor, revision));
276 writer->writeLine("Tracing support: disabled");
280 writer->writeLine(formatString("Built on: %s", BUILD_TIME));
281 writer->writeLine(formatString("Built by: %s", BUILD_USER));
282 writer->writeLine(formatString("Build OS/arch: %s", BUILD_HOST));
283 writer->writeLine(formatString("Build CPU vendor: %s", BUILD_CPU_VENDOR));
284 writer->writeLine(formatString("Build CPU brand: %s", BUILD_CPU_BRAND));
285 writer->writeLine(formatString("Build CPU family: %d Model: %d Stepping: %d",
286 BUILD_CPU_FAMILY, BUILD_CPU_MODEL, BUILD_CPU_STEPPING));
287 /* TODO: The below strings can be quite long, so it would be nice to wrap
288 * them. Can wait for later, as the master branch has ready code to do all
290 writer->writeLine(formatString("Build CPU features: %s", BUILD_CPU_FEATURES));
291 writer->writeLine(formatString("C compiler: %s", BUILD_C_COMPILER));
292 writer->writeLine(formatString("C compiler flags: %s", BUILD_CFLAGS));
293 writer->writeLine(formatString("C++ compiler: %s", BUILD_CXX_COMPILER));
294 writer->writeLine(formatString("C++ compiler flags: %s", BUILD_CXXFLAGS));
296 /* MKL might be used for LAPACK/BLAS even if FFTs use FFTW, so keep it separate */
297 writer->writeLine(formatString("Linked with Intel MKL version %d.%d.%d.",
298 __INTEL_MKL__, __INTEL_MKL_MINOR__, __INTEL_MKL_UPDATE__));
300 #if GMX_GPU == GMX_GPU_OPENCL
301 writer->writeLine(formatString("OpenCL include dir: %s", OPENCL_INCLUDE_DIR));
302 writer->writeLine(formatString("OpenCL library: %s", OPENCL_LIBRARY));
303 writer->writeLine(formatString("OpenCL version: %s", OPENCL_VERSION_STRING));
305 #if GMX_GPU == GMX_GPU_CUDA
306 writer->writeLine(formatString("CUDA compiler: %s\n", CUDA_COMPILER_INFO));
307 writer->writeLine(formatString("CUDA compiler flags:%s\n", CUDA_COMPILER_FLAGS));
308 auto driverVersion = gmx::getCudaDriverVersion();
309 writer->writeLine(formatString("CUDA driver: %d.%d\n", driverVersion.first, driverVersion.second));
310 auto runtimeVersion = gmx::getCudaRuntimeVersion();
311 writer->writeLine(formatString("CUDA runtime: %d.%d\n", runtimeVersion.first, runtimeVersion.second));
322 BinaryInformationSettings::BinaryInformationSettings()
323 : bExtendedInfo_(false), bCopyright_(false),
324 bGeneratedByHeader_(false), prefix_(""), suffix_("")
328 void printBinaryInformation(FILE *fp,
329 const IProgramContext &programContext)
331 TextWriter writer(fp);
332 printBinaryInformation(&writer, programContext, BinaryInformationSettings());
335 void printBinaryInformation(FILE *fp,
336 const IProgramContext &programContext,
337 const BinaryInformationSettings &settings)
341 TextWriter writer(fp);
342 printBinaryInformation(&writer, programContext, settings);
344 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
347 void printBinaryInformation(TextWriter *writer,
348 const IProgramContext &programContext,
349 const BinaryInformationSettings &settings)
351 // TODO Perhaps the writer could be configured with the prefix and
352 // suffix strings from the settings?
353 const char *prefix = settings.prefix_;
354 const char *suffix = settings.suffix_;
355 const char *precisionString = "";
357 precisionString = " (double precision)";
359 const char *const name = programContext.displayName();
360 if (settings.bGeneratedByHeader_)
362 writer->writeLine(formatString("%sCreated by:%s", prefix, suffix));
364 // TODO: It would be nice to know here whether we are really running a
365 // Gromacs binary or some other binary that is calling Gromacs; we
366 // could then print "%s is part of GROMACS" or some alternative text.
368 = formatString(":-) GROMACS - %s, %s%s (-:", name, gmx_version(), precisionString);
370 = centeringOffset(78 - std::strlen(prefix) - std::strlen(suffix), title.length()) + 1;
371 writer->writeLine(formatString("%s%*c%s%s", prefix, indent, ' ', title.c_str(), suffix));
372 writer->writeLine(formatString("%s%s", prefix, suffix));
373 if (settings.bCopyright_)
375 GMX_RELEASE_ASSERT(prefix[0] == '\0' && suffix[0] == '\0',
376 "Prefix/suffix not supported with copyright");
377 printCopyright(writer);
378 writer->ensureEmptyLine();
379 // This line is printed again after the copyright notice to make it
380 // appear together with all the other information, so that it is not
381 // necessary to read stuff above the copyright notice.
382 // The line above the copyright notice puts the copyright notice is
384 writer->writeLine(formatString("%sGROMACS: %s, version %s%s%s", prefix, name,
385 gmx_version(), precisionString, suffix));
387 const char *const binaryPath = programContext.fullBinaryPath();
388 if (!gmx::isNullOrEmpty(binaryPath))
390 writer->writeLine(formatString("%sExecutable: %s%s", prefix, binaryPath, suffix));
392 const gmx::InstallationPrefixInfo installPrefix = programContext.installationPrefix();
393 if (!gmx::isNullOrEmpty(installPrefix.path))
395 writer->writeLine(formatString("%sData prefix: %s%s%s", prefix, installPrefix.path,
396 installPrefix.bSourceLayout ? " (source tree)" : "", suffix));
398 const std::string workingDir = Path::getWorkingDirectory();
399 if (!workingDir.empty())
401 writer->writeLine(formatString("%sWorking dir: %s%s", prefix, workingDir.c_str(), suffix));
403 const char *const commandLine = programContext.commandLine();
404 if (!gmx::isNullOrEmpty(commandLine))
406 writer->writeLine(formatString("%sCommand line:%s\n%s %s%s",
407 prefix, suffix, prefix, commandLine, suffix));
409 if (settings.bExtendedInfo_)
411 GMX_RELEASE_ASSERT(prefix[0] == '\0' && suffix[0] == '\0',
412 "Prefix/suffix not supported with extended info");
413 writer->ensureEmptyLine();
414 gmx_print_version_info(writer);