#include <cstring>
#include <algorithm>
+#include <string>
/* This file is completely threadsafe - keep it that way! */
#include "gromacs/utility/path.h"
#include "gromacs/utility/programcontext.h"
#include "gromacs/utility/stringutil.h"
+#include "gromacs/utility/textwriter.h"
#include "cuda_version_information.h"
namespace
{
+using gmx::formatString;
+
//! \cond Doxygen does not need to care about most of this stuff, and the macro usage is painful to document
int centeringOffset(int width, int length)
return std::max(width - length, 0) / 2;
}
-void printCentered(FILE *fp, int width, const char *text)
+std::string formatCentered(int width, const char *text)
{
const int offset = centeringOffset(width, std::strlen(text));
- fprintf(fp, "%*s%s", offset, "", text);
+ return formatString("%*s%s", offset, "", text);
}
-void printCopyright(FILE *fp)
+void printCopyright(gmx::TextWriter *writer)
{
static const char * const Contributors[] = {
"Emile Apol",
#define NLICENSE (int)asize(LicenseText)
#endif
- printCentered(fp, 78, "GROMACS is written by:");
- fprintf(fp, "\n");
+ // TODO a centering behaviour of TextWriter could be useful here
+ writer->writeLine(formatCentered(78, "GROMACS is written by:"));
for (int i = 0; i < NCONTRIBUTORS; )
{
for (int j = 0; j < 4 && i < NCONTRIBUTORS; ++j, ++i)
"Formatting buffer is not long enough");
std::fill(buf, buf+width, ' ');
std::strcpy(buf+offset, Contributors[i]);
- fprintf(fp, " %-*s", width, buf);
+ writer->writeString(formatString(" %-*s", width, buf));
}
- fprintf(fp, "\n");
+ writer->ensureLineBreak();
}
- printCentered(fp, 78, "and the project leaders:");
- fprintf(fp, "\n");
- printCentered(fp, 78, "Mark Abraham, Berk Hess, Erik Lindahl, and David van der Spoel");
- fprintf(fp, "\n\n");
+ writer->writeLine(formatCentered(78, "and the project leaders:"));
+ writer->writeLine(formatCentered(78, "Mark Abraham, Berk Hess, Erik Lindahl, and David van der Spoel"));
+ writer->ensureEmptyLine();
for (int i = 0; i < NCR; ++i)
{
- fprintf(fp, "%s\n", CopyrightText[i]);
+ writer->writeLine(CopyrightText[i]);
}
- fprintf(fp, "\n");
+ writer->ensureEmptyLine();
for (int i = 0; i < NLICENSE; ++i)
{
- fprintf(fp, "%s\n", LicenseText[i]);
+ writer->writeLine(LicenseText[i]);
}
}
#endif
};
-void gmx_print_version_info(FILE *fp)
+void gmx_print_version_info(gmx::TextWriter *writer)
{
- fprintf(fp, "GROMACS version: %s\n", gmx_version());
+ writer->writeLine(formatString("GROMACS version: %s", gmx_version()));
const char *const git_hash = gmx_version_git_full_hash();
if (git_hash[0] != '\0')
{
- fprintf(fp, "GIT SHA1 hash: %s\n", git_hash);
+ writer->writeLine(formatString("GIT SHA1 hash: %s", git_hash));
}
const char *const base_hash = gmx_version_git_central_base_hash();
if (base_hash[0] != '\0')
{
- fprintf(fp, "Branched from: %s\n", base_hash);
+ writer->writeLine(formatString("Branched from: %s", base_hash));
}
#if GMX_DOUBLE
- fprintf(fp, "Precision: double\n");
+ writer->writeLine("Precision: double");
#else
- fprintf(fp, "Precision: single\n");
+ writer->writeLine("Precision: single");
#endif
- fprintf(fp, "Memory model: %u bit\n", (unsigned)(8*sizeof(void *)));
+ writer->writeLine(formatString("Memory model: %u bit", (unsigned)(8*sizeof(void *))));
#if GMX_THREAD_MPI
- fprintf(fp, "MPI library: thread_mpi\n");
+ writer->writeLine("MPI library: thread_mpi");
#elif GMX_MPI
- fprintf(fp, "MPI library: MPI\n");
+ writer->writeLine("MPI library: MPI");
#else
- fprintf(fp, "MPI library: none\n");
+ writer->writeLine("MPI library: none");
#endif
#if GMX_OPENMP
- fprintf(fp, "OpenMP support: enabled (GMX_OPENMP_MAX_THREADS = %d)\n", GMX_OPENMP_MAX_THREADS);
+ writer->writeLine(formatString("OpenMP support: enabled (GMX_OPENMP_MAX_THREADS = %d)", GMX_OPENMP_MAX_THREADS));
#else
- fprintf(fp, "OpenMP support: disabled\n");
+ writer->writeLine("OpenMP support: disabled");
#endif
- fprintf(fp, "GPU support: %s\n", getGpuImplementationString());
- fprintf(fp, "SIMD instructions: %s\n", GMX_SIMD_STRING);
- fprintf(fp, "FFT library: %s\n", getFftDescriptionString());
+ writer->writeLine(formatString("GPU support: %s", getGpuImplementationString()));
+ writer->writeLine(formatString("SIMD instructions: %s", GMX_SIMD_STRING));
+ writer->writeLine(formatString("FFT library: %s", getFftDescriptionString()));
#ifdef HAVE_RDTSCP
- fprintf(fp, "RDTSCP usage: enabled\n");
+ writer->writeLine("RDTSCP usage: enabled");
#else
- fprintf(fp, "RDTSCP usage: disabled\n");
+ writer->writeLine("RDTSCP usage: disabled");
#endif
#ifdef GMX_USE_TNG
- fprintf(fp, "TNG support: enabled\n");
+ writer->writeLine("TNG support: enabled");
#else
- fprintf(fp, "TNG support: disabled\n");
+ writer->writeLine("TNG support: disabled");
#endif
#if GMX_HWLOC
- fprintf(fp, "Hwloc support: hwloc-%d.%d.%d\n",
- HWLOC_API_VERSION>>16,
- (HWLOC_API_VERSION>>8) & 0xFF,
- HWLOC_API_VERSION & 0xFF);
+ writer->writeLine(formatString("Hwloc support: hwloc-%d.%d.%d",
+ HWLOC_API_VERSION>>16,
+ (HWLOC_API_VERSION>>8) & 0xFF,
+ HWLOC_API_VERSION & 0xFF));
#else
- fprintf(fp, "Hwloc support: disabled\n");
+ writer->writeLine("Hwloc support: disabled");
#endif
#if HAVE_EXTRAE
unsigned major, minor, revision;
Extrae_get_version(&major, &minor, &revision);
- fprintf(fp, "Tracing support: enabled. Using Extrae-%d.%d.%d\n", major, minor, revision);
+ writer->writeLine(formatString("Tracing support: enabled. Using Extrae-%d.%d.%d", major, minor, revision));
#else
- fprintf(fp, "Tracing support: disabled\n");
+ writer->writeLine("Tracing support: disabled");
#endif
- fprintf(fp, "Built on: %s\n", BUILD_TIME);
- fprintf(fp, "Built by: %s\n", BUILD_USER);
- fprintf(fp, "Build OS/arch: %s\n", BUILD_HOST);
- fprintf(fp, "Build CPU vendor: %s\n", BUILD_CPU_VENDOR);
- fprintf(fp, "Build CPU brand: %s\n", BUILD_CPU_BRAND);
- fprintf(fp, "Build CPU family: %d Model: %d Stepping: %d\n",
- BUILD_CPU_FAMILY, BUILD_CPU_MODEL, BUILD_CPU_STEPPING);
+ writer->writeLine(formatString("Built on: %s", BUILD_TIME));
+ writer->writeLine(formatString("Built by: %s", BUILD_USER));
+ writer->writeLine(formatString("Build OS/arch: %s", BUILD_HOST));
+ writer->writeLine(formatString("Build CPU vendor: %s", BUILD_CPU_VENDOR));
+ writer->writeLine(formatString("Build CPU brand: %s", BUILD_CPU_BRAND));
+ writer->writeLine(formatString("Build CPU family: %d Model: %d Stepping: %d",
+ BUILD_CPU_FAMILY, BUILD_CPU_MODEL, BUILD_CPU_STEPPING));
/* TODO: The below strings can be quite long, so it would be nice to wrap
* them. Can wait for later, as the master branch has ready code to do all
* that. */
- fprintf(fp, "Build CPU features: %s\n", BUILD_CPU_FEATURES);
- fprintf(fp, "C compiler: %s\n", BUILD_C_COMPILER);
- fprintf(fp, "C compiler flags: %s\n", BUILD_CFLAGS);
- fprintf(fp, "C++ compiler: %s\n", BUILD_CXX_COMPILER);
- fprintf(fp, "C++ compiler flags: %s\n", BUILD_CXXFLAGS);
+ writer->writeLine(formatString("Build CPU features: %s", BUILD_CPU_FEATURES));
+ writer->writeLine(formatString("C compiler: %s", BUILD_C_COMPILER));
+ writer->writeLine(formatString("C compiler flags: %s", BUILD_CFLAGS));
+ writer->writeLine(formatString("C++ compiler: %s", BUILD_CXX_COMPILER));
+ writer->writeLine(formatString("C++ compiler flags: %s", BUILD_CXXFLAGS));
#ifdef HAVE_LIBMKL
/* MKL might be used for LAPACK/BLAS even if FFTs use FFTW, so keep it separate */
- fprintf(fp, "Linked with Intel MKL version %d.%d.%d.\n",
- __INTEL_MKL__, __INTEL_MKL_MINOR__, __INTEL_MKL_UPDATE__);
+ writer->writeLine(formatString("Linked with Intel MKL version %d.%d.%d.",
+ __INTEL_MKL__, __INTEL_MKL_MINOR__, __INTEL_MKL_UPDATE__));
#endif
#if GMX_GPU == GMX_GPU_OPENCL
- fprintf(fp, "OpenCL include dir: %s\n", OPENCL_INCLUDE_DIR);
- fprintf(fp, "OpenCL library: %s\n", OPENCL_LIBRARY);
- fprintf(fp, "OpenCL version: %s\n", OPENCL_VERSION_STRING);
+ writer->writeLine(formatString("OpenCL include dir: %s", OPENCL_INCLUDE_DIR));
+ writer->writeLine(formatString("OpenCL library: %s", OPENCL_LIBRARY));
+ writer->writeLine(formatString("OpenCL version: %s", OPENCL_VERSION_STRING));
#endif
#if GMX_GPU == GMX_GPU_CUDA
- gmx_print_version_info_cuda_gpu(fp);
+ writer->writeLine(formatString("CUDA compiler: %s\n", CUDA_NVCC_COMPILER_INFO));
+ writer->writeLine(formatString("CUDA compiler flags:%s\n", CUDA_NVCC_COMPILER_FLAGS));
+ auto driverVersion = gmx::getCudaDriverVersion();
+ writer->writeLine(formatString("CUDA driver: %d.%d\n", driverVersion.first, driverVersion.second));
+ auto runtimeVersion = gmx::getCudaRuntimeVersion();
+ writer->writeLine(formatString("CUDA runtime: %d.%d\n", runtimeVersion.first, runtimeVersion.second));
#endif
}
void printBinaryInformation(FILE *fp,
const IProgramContext &programContext)
{
- printBinaryInformation(fp, programContext, BinaryInformationSettings());
+ TextWriter writer(fp);
+ printBinaryInformation(&writer, programContext, BinaryInformationSettings());
}
void printBinaryInformation(FILE *fp,
const IProgramContext &programContext,
const BinaryInformationSettings &settings)
{
+ try
+ {
+ TextWriter writer(fp);
+ printBinaryInformation(&writer, programContext, settings);
+ }
+ GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
+}
+
+void printBinaryInformation(TextWriter *writer,
+ const IProgramContext &programContext,
+ const BinaryInformationSettings &settings)
+{
+ // TODO Perhaps the writer could be configured with the prefix and
+ // suffix strings from the settings?
const char *prefix = settings.prefix_;
const char *suffix = settings.suffix_;
const char *precisionString = "";
const char *const name = programContext.displayName();
if (settings.bGeneratedByHeader_)
{
- fprintf(fp, "%sCreated by:%s\n", prefix, suffix);
+ writer->writeLine(formatString("%sCreated by:%s", prefix, suffix));
}
// TODO: It would be nice to know here whether we are really running a
// Gromacs binary or some other binary that is calling Gromacs; we
= formatString(":-) GROMACS - %s, %s%s (-:", name, gmx_version(), precisionString);
const int indent
= centeringOffset(78 - std::strlen(prefix) - std::strlen(suffix), title.length()) + 1;
- fprintf(fp, "%s%*c%s%s\n", prefix, indent, ' ', title.c_str(), suffix);
- fprintf(fp, "%s%s\n", prefix, suffix);
+ writer->writeLine(formatString("%s%*c%s%s", prefix, indent, ' ', title.c_str(), suffix));
+ writer->writeLine(formatString("%s%s", prefix, suffix));
if (settings.bCopyright_)
{
GMX_RELEASE_ASSERT(prefix[0] == '\0' && suffix[0] == '\0',
"Prefix/suffix not supported with copyright");
- printCopyright(fp);
- fprintf(fp, "\n");
+ printCopyright(writer);
+ writer->ensureEmptyLine();
// This line is printed again after the copyright notice to make it
// appear together with all the other information, so that it is not
// necessary to read stuff above the copyright notice.
// The line above the copyright notice puts the copyright notice is
// context, though.
- fprintf(fp, "%sGROMACS: %s, version %s%s%s\n", prefix, name,
- gmx_version(), precisionString, suffix);
+ writer->writeLine(formatString("%sGROMACS: %s, version %s%s%s", prefix, name,
+ gmx_version(), precisionString, suffix));
}
const char *const binaryPath = programContext.fullBinaryPath();
if (!gmx::isNullOrEmpty(binaryPath))
{
- fprintf(fp, "%sExecutable: %s%s\n", prefix, binaryPath, suffix);
+ writer->writeLine(formatString("%sExecutable: %s%s", prefix, binaryPath, suffix));
}
const gmx::InstallationPrefixInfo installPrefix = programContext.installationPrefix();
if (!gmx::isNullOrEmpty(installPrefix.path))
{
- fprintf(fp, "%sData prefix: %s%s%s\n", prefix, installPrefix.path,
- installPrefix.bSourceLayout ? " (source tree)" : "", suffix);
+ writer->writeLine(formatString("%sData prefix: %s%s%s", prefix, installPrefix.path,
+ installPrefix.bSourceLayout ? " (source tree)" : "", suffix));
}
const std::string workingDir = Path::getWorkingDirectory();
if (!workingDir.empty())
{
- fprintf(fp, "%sWorking dir: %s%s\n", prefix, workingDir.c_str(), suffix);
+ writer->writeLine(formatString("%sWorking dir: %s%s", prefix, workingDir.c_str(), suffix));
}
const char *const commandLine = programContext.commandLine();
if (!gmx::isNullOrEmpty(commandLine))
{
- fprintf(fp, "%sCommand line:%s\n%s %s%s\n",
- prefix, suffix, prefix, commandLine, suffix);
+ writer->writeLine(formatString("%sCommand line:%s\n%s %s%s",
+ prefix, suffix, prefix, commandLine, suffix));
}
if (settings.bExtendedInfo_)
{
GMX_RELEASE_ASSERT(prefix[0] == '\0' && suffix[0] == '\0',
"Prefix/suffix not supported with extended info");
- fprintf(fp, "\n");
- gmx_print_version_info(fp);
+ writer->ensureEmptyLine();
+ gmx_print_version_info(writer);
}
}