Merge branch release-2016
[alexxy/gromacs.git] / src / gromacs / utility / binaryinformation.cpp
index 9feb963c50ba81e5c961bdc5103896880830e85b..f805b1f003ee681b9dfef83d2088888755056fb2 100644 (file)
@@ -68,6 +68,7 @@
 #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)
@@ -92,13 +96,13 @@ 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",
@@ -157,8 +161,8 @@ void printCopyright(FILE *fp)
 #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)
@@ -170,22 +174,21 @@ void printCopyright(FILE *fp)
                                "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]);
     }
 }
 
@@ -214,96 +217,101 @@ const char *getFftDescriptionString()
 #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
 }
 
@@ -323,13 +331,28 @@ BinaryInformationSettings::BinaryInformationSettings()
 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 = "";
@@ -339,7 +362,7 @@ void printBinaryInformation(FILE                            *fp,
     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
@@ -348,50 +371,50 @@ void printBinaryInformation(FILE                            *fp,
         = 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);
     }
 }