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,2018, 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
[] = {
111 "Herman J.C. Berendsen",
118 "Christoph Junghans",
120 "Vincent Hindriksen",
121 "Dimitrios Karkoulis",
140 "Christian Wennberg",
143 static const char * const CopyrightText
[] = {
144 "Copyright (c) 1991-2000, University of Groningen, The Netherlands.",
145 "Copyright (c) 2001-2017, The GROMACS development team at",
146 "Uppsala University, Stockholm University and",
147 "the Royal Institute of Technology, Sweden.",
148 "check out http://www.gromacs.org for more information."
150 static const char * const LicenseText
[] = {
151 "GROMACS is free software; you can redistribute it and/or modify it",
152 "under the terms of the GNU Lesser General Public License",
153 "as published by the Free Software Foundation; either version 2.1",
154 "of the License, or (at your option) any later version."
157 #define NCONTRIBUTORS static_cast<int>(asize(Contributors))
158 #define NCR static_cast<int>(asize(CopyrightText))
160 // FAH has an exception permission from LGPL to allow digital signatures in Gromacs.
164 #define NLICENSE static_cast<int>(asize(LicenseText))
167 // TODO a centering behaviour of TextWriter could be useful here
168 writer
->writeLine(formatCentered(78, "GROMACS is written by:"));
169 for (int i
= 0; i
< NCONTRIBUTORS
; )
171 for (int j
= 0; j
< 4 && i
< NCONTRIBUTORS
; ++j
, ++i
)
173 const int width
= 18;
175 const int offset
= centeringOffset(width
, strlen(Contributors
[i
]));
176 GMX_RELEASE_ASSERT(strlen(Contributors
[i
]) + offset
< asize(buf
),
177 "Formatting buffer is not long enough");
178 std::fill(buf
, buf
+width
, ' ');
179 std::strcpy(buf
+offset
, Contributors
[i
]);
180 writer
->writeString(formatString(" %-*s", width
, buf
));
182 writer
->ensureLineBreak();
184 writer
->writeLine(formatCentered(78, "and the project leaders:"));
185 writer
->writeLine(formatCentered(78, "Mark Abraham, Berk Hess, Erik Lindahl, and David van der Spoel"));
186 writer
->ensureEmptyLine();
187 for (int i
= 0; i
< NCR
; ++i
)
189 writer
->writeLine(CopyrightText
[i
]);
191 writer
->ensureEmptyLine();
192 for (int i
= 0; i
< NLICENSE
; ++i
)
194 writer
->writeLine(LicenseText
[i
]);
198 // Construct a string that describes the library that provides FFT support to this build
199 const char *getFftDescriptionString()
201 // Define the FFT description string
203 # if GMX_NATIVE_WINDOWS
207 // Use the version string provided by libfftw3
211 return fftwf_version
;
219 return "fftpack (built-in)";
223 void gmx_print_version_info(gmx::TextWriter
*writer
)
225 writer
->writeLine(formatString("GROMACS version: %s", gmx_version()));
226 const char *const git_hash
= gmx_version_git_full_hash();
227 if (git_hash
[0] != '\0')
229 writer
->writeLine(formatString("GIT SHA1 hash: %s", git_hash
));
231 const char *const base_hash
= gmx_version_git_central_base_hash();
232 if (base_hash
[0] != '\0')
234 writer
->writeLine(formatString("Branched from: %s", base_hash
));
238 writer
->writeLine("Precision: double");
240 writer
->writeLine("Precision: single");
242 writer
->writeLine(formatString("Memory model: %u bit", static_cast<unsigned>(8*sizeof(void *))));
245 writer
->writeLine("MPI library: thread_mpi");
247 writer
->writeLine("MPI library: MPI");
249 writer
->writeLine("MPI library: none");
252 writer
->writeLine(formatString("OpenMP support: enabled (GMX_OPENMP_MAX_THREADS = %d)", GMX_OPENMP_MAX_THREADS
));
254 writer
->writeLine("OpenMP support: disabled");
256 writer
->writeLine(formatString("GPU support: %s", getGpuImplementationString()));
257 writer
->writeLine(formatString("SIMD instructions: %s", GMX_SIMD_STRING
));
258 writer
->writeLine(formatString("FFT library: %s", getFftDescriptionString()));
259 writer
->writeLine(formatString("RDTSCP usage: %s", HAVE_RDTSCP
? "enabled" : "disabled"));
261 writer
->writeLine("TNG support: enabled");
263 writer
->writeLine("TNG support: disabled");
266 writer
->writeLine(formatString("Hwloc support: hwloc-%s", HWLOC_VERSION
));
268 writer
->writeLine("Hwloc support: disabled");
271 unsigned major
, minor
, revision
;
272 Extrae_get_version(&major
, &minor
, &revision
);
273 writer
->writeLine(formatString("Tracing support: enabled. Using Extrae-%d.%d.%d", major
, minor
, revision
));
275 writer
->writeLine("Tracing support: disabled");
279 writer
->writeLine(formatString("Built on: %s", BUILD_TIME
));
280 writer
->writeLine(formatString("Built by: %s", BUILD_USER
));
281 writer
->writeLine(formatString("Build OS/arch: %s", BUILD_HOST
));
282 writer
->writeLine(formatString("Build CPU vendor: %s", BUILD_CPU_VENDOR
));
283 writer
->writeLine(formatString("Build CPU brand: %s", BUILD_CPU_BRAND
));
284 writer
->writeLine(formatString("Build CPU family: %d Model: %d Stepping: %d",
285 BUILD_CPU_FAMILY
, BUILD_CPU_MODEL
, BUILD_CPU_STEPPING
));
286 /* TODO: The below strings can be quite long, so it would be nice to wrap
287 * them. Can wait for later, as the master branch has ready code to do all
289 writer
->writeLine(formatString("Build CPU features: %s", BUILD_CPU_FEATURES
));
290 writer
->writeLine(formatString("C compiler: %s", BUILD_C_COMPILER
));
291 writer
->writeLine(formatString("C compiler flags: %s", BUILD_CFLAGS
));
292 writer
->writeLine(formatString("C++ compiler: %s", BUILD_CXX_COMPILER
));
293 writer
->writeLine(formatString("C++ compiler flags: %s", BUILD_CXXFLAGS
));
295 /* MKL might be used for LAPACK/BLAS even if FFTs use FFTW, so keep it separate */
296 writer
->writeLine(formatString("Linked with Intel MKL version %d.%d.%d.",
297 __INTEL_MKL__
, __INTEL_MKL_MINOR__
, __INTEL_MKL_UPDATE__
));
299 #if GMX_GPU == GMX_GPU_OPENCL
300 writer
->writeLine(formatString("OpenCL include dir: %s", OPENCL_INCLUDE_DIR
));
301 writer
->writeLine(formatString("OpenCL library: %s", OPENCL_LIBRARY
));
302 writer
->writeLine(formatString("OpenCL version: %s", OPENCL_VERSION_STRING
));
304 #if GMX_GPU == GMX_GPU_CUDA
305 writer
->writeLine(formatString("CUDA compiler: %s", CUDA_COMPILER_INFO
));
306 writer
->writeLine(formatString("CUDA compiler flags:%s", CUDA_COMPILER_FLAGS
));
307 writer
->writeLine("CUDA driver: " + gmx::getCudaDriverVersionString());
308 writer
->writeLine("CUDA runtime: " + gmx::getCudaRuntimeVersionString());
319 BinaryInformationSettings::BinaryInformationSettings()
320 : bExtendedInfo_(false), bCopyright_(false),
321 bGeneratedByHeader_(false), prefix_(""), suffix_("")
325 void printBinaryInformation(FILE *fp
,
326 const IProgramContext
&programContext
)
328 TextWriter
writer(fp
);
329 printBinaryInformation(&writer
, programContext
, BinaryInformationSettings());
332 void printBinaryInformation(FILE *fp
,
333 const IProgramContext
&programContext
,
334 const BinaryInformationSettings
&settings
)
338 TextWriter
writer(fp
);
339 printBinaryInformation(&writer
, programContext
, settings
);
341 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
;
344 void printBinaryInformation(TextWriter
*writer
,
345 const IProgramContext
&programContext
,
346 const BinaryInformationSettings
&settings
)
348 // TODO Perhaps the writer could be configured with the prefix and
349 // suffix strings from the settings?
350 const char *prefix
= settings
.prefix_
;
351 const char *suffix
= settings
.suffix_
;
352 const char *precisionString
= "";
354 precisionString
= " (double precision)";
356 const char *const name
= programContext
.displayName();
357 if (settings
.bGeneratedByHeader_
)
359 writer
->writeLine(formatString("%sCreated by:%s", prefix
, suffix
));
361 // TODO: It would be nice to know here whether we are really running a
362 // Gromacs binary or some other binary that is calling Gromacs; we
363 // could then print "%s is part of GROMACS" or some alternative text.
365 = formatString(":-) GROMACS - %s, %s%s (-:", name
, gmx_version(), precisionString
);
367 = centeringOffset(78 - std::strlen(prefix
) - std::strlen(suffix
), title
.length()) + 1;
368 writer
->writeLine(formatString("%s%*c%s%s", prefix
, indent
, ' ', title
.c_str(), suffix
));
369 writer
->writeLine(formatString("%s%s", prefix
, suffix
));
370 if (settings
.bCopyright_
)
372 GMX_RELEASE_ASSERT(prefix
[0] == '\0' && suffix
[0] == '\0',
373 "Prefix/suffix not supported with copyright");
374 printCopyright(writer
);
375 writer
->ensureEmptyLine();
376 // This line is printed again after the copyright notice to make it
377 // appear together with all the other information, so that it is not
378 // necessary to read stuff above the copyright notice.
379 // The line above the copyright notice puts the copyright notice is
381 writer
->writeLine(formatString("%sGROMACS: %s, version %s%s%s", prefix
, name
,
382 gmx_version(), precisionString
, suffix
));
384 const char *const binaryPath
= programContext
.fullBinaryPath();
385 if (!gmx::isNullOrEmpty(binaryPath
))
387 writer
->writeLine(formatString("%sExecutable: %s%s", prefix
, binaryPath
, suffix
));
389 const gmx::InstallationPrefixInfo installPrefix
= programContext
.installationPrefix();
390 if (!gmx::isNullOrEmpty(installPrefix
.path
))
392 writer
->writeLine(formatString("%sData prefix: %s%s%s", prefix
, installPrefix
.path
,
393 installPrefix
.bSourceLayout
? " (source tree)" : "", suffix
));
395 const std::string workingDir
= Path::getWorkingDirectory();
396 if (!workingDir
.empty())
398 writer
->writeLine(formatString("%sWorking dir: %s%s", prefix
, workingDir
.c_str(), suffix
));
400 const char *const commandLine
= programContext
.commandLine();
401 if (!gmx::isNullOrEmpty(commandLine
))
403 writer
->writeLine(formatString("%sCommand line:%s\n%s %s%s",
404 prefix
, suffix
, prefix
, commandLine
, suffix
));
406 if (settings
.bExtendedInfo_
)
408 GMX_RELEASE_ASSERT(prefix
[0] == '\0' && suffix
[0] == '\0',
409 "Prefix/suffix not supported with extended info");
410 writer
->ensureEmptyLine();
411 gmx_print_version_info(writer
);