Add Oliver Fleetwood as a contributor
[alexxy/gromacs.git] / src / gromacs / utility / binaryinformation.cpp
index cb138cf36bf94d8fd759abd426747e91db754d03..a1bff11d524a2330f316d6605217e4feb219c3e2 100644 (file)
@@ -3,7 +3,8 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013,2014,2015,2016,2017,2018, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 
 #include "config.h"
 
-#if GMX_FFT_FFTW3
+#if GMX_FFT_FFTW3 || GMX_FFT_ARMPL_FFTW3
 // Needed for construction of the FFT library description string
-#include <fftw3.h>
+#    include <fftw3.h>
 #endif
 
-#ifdef HAVE_LIBMKL
-#include <mkl.h>
+#if HAVE_LIBMKL
+#    include <mkl.h>
 #endif
 
 #if HAVE_EXTRAE
-#include <extrae_user_events.h>
+#    include <extrae_user_events.h>
 #endif
 
 #if GMX_USE_HWLOC
-#include <hwloc.h>
+#    include <hwloc.h>
 #endif
 
 #include <cstdio>
@@ -68,6 +69,7 @@
 #include <cstring>
 
 #include <algorithm>
+#include <array>
 #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/sysinfo.h"
 #include "gromacs/utility/textwriter.h"
 
 #include "cuda_version_information.h"
+#include "sycl_version_information.h"
 
 namespace
 {
@@ -96,121 +100,128 @@ int centeringOffset(int width, int length)
     return std::max(width - length, 0) / 2;
 }
 
-std::string formatCentered(int width, const char *text)
+std::string formatCentered(int width, const chartext)
 {
     const int offset = centeringOffset(width, std::strlen(text));
     return formatString("%*s%s", offset, "", text);
 }
 
-void printCopyright(gmx::TextWriter *writer)
+void printCopyright(gmx::TextWriterwriter)
 {
-    static const char * const Contributors[] = {
-        "Emile Apol",
-        "Rossen Apostolov",
-        "Paul Bauer",
-        "Herman J.C. Berendsen",
-        "Par Bjelkmar",
-        "Aldert van Buuren",
-        "Rudi van Drunen",
-        "Anton Feenstra",
-        "Gerrit Groenhof",
-        "Aleksei Iupinov",
-        "Christoph Junghans",
-        "Anca Hamuraru",
-        "Vincent Hindriksen",
-        "Dimitrios Karkoulis",
-        "Peter Kasson",
-        "Jiri Kraus",
-        "Carsten Kutzner",
-        "Per Larsson",
-        "Justin A. Lemkul",
-        "Viveca Lindahl",
-        "Magnus Lundborg",
-        "Pieter Meulenhoff",
-        "Erik Marklund",
-        "Teemu Murtola",
-        "Szilard Pall",
-        "Sander Pronk",
-        "Roland Schulz",
-        "Alexey Shvetsov",
-        "Michael Shirts",
-        "Alfons Sijbers",
-        "Peter Tieleman",
-        "Teemu Virolainen",
-        "Christian Wennberg",
-        "Maarten Wolf"
-    };
-    static const char * const CopyrightText[] = {
+    // Contributors sorted alphabetically by last name
+    static const char* const Contributors[]  = { "Andrey Alekseenko",
+                                                "Emile Apol",
+                                                "Rossen Apostolov",
+                                                "Paul Bauer",
+                                                "Herman J.C. Berendsen",
+                                                "Par Bjelkmar",
+                                                "Christian Blau",
+                                                "Viacheslav Bolnykh",
+                                                "Kevin Boyd",
+                                                "Aldert van Buuren",
+                                                "Rudi van Drunen",
+                                                "Anton Feenstra",
+                                                "Oliver Fleetwood",
+                                                "Gaurav Garg",
+                                                "Gilles Gouaillardet",
+                                                "Alan Gray",
+                                                "Gerrit Groenhof",
+                                                "Anca Hamuraru",
+                                                "Vincent Hindriksen",
+                                                "M. Eric Irrgang",
+                                                "Aleksei Iupinov",
+                                                "Christoph Junghans",
+                                                "Joe Jordan",
+                                                "Dimitrios Karkoulis",
+                                                "Peter Kasson",
+                                                "Jiri Kraus",
+                                                "Carsten Kutzner",
+                                                "Per Larsson",
+                                                "Justin A. Lemkul",
+                                                "Viveca Lindahl",
+                                                "Magnus Lundborg",
+                                                "Erik Marklund",
+                                                "Pascal Merz",
+                                                "Pieter Meulenhoff",
+                                                "Teemu Murtola",
+                                                "Szilard Pall",
+                                                "Sander Pronk",
+                                                "Roland Schulz",
+                                                "Michael Shirts",
+                                                "Alexey Shvetsov",
+                                                "Alfons Sijbers",
+                                                "Peter Tieleman",
+                                                "Jon Vincent",
+                                                "Teemu Virolainen",
+                                                "Christian Wennberg",
+                                                "Maarten Wolf",
+                                                "Artem Zhmurov" };
+    static const char* const CopyrightText[] = {
         "Copyright (c) 1991-2000, University of Groningen, The Netherlands.",
-        "Copyright (c) 2001-2017, The GROMACS development team at",
+        "Copyright (c) 2001-2019, The GROMACS development team at",
         "Uppsala University, Stockholm University and",
         "the Royal Institute of Technology, Sweden.",
         "check out http://www.gromacs.org for more information."
     };
-    static const char * const LicenseText[] = {
-        "GROMACS is free software; you can redistribute it and/or modify it",
-        "under the terms of the GNU Lesser General Public License",
-        "as published by the Free Software Foundation; either version 2.1",
-        "of the License, or (at your option) any later version."
-    };
-
-#define NCONTRIBUTORS (int)asize(Contributors)
-#define NCR (int)asize(CopyrightText)
 
-// FAH has an exception permission from LGPL to allow digital signatures in Gromacs.
-#ifdef GMX_FAHCORE
-#define NLICENSE 0
-#else
-#define NLICENSE (int)asize(LicenseText)
-#endif
+#define NCONTRIBUTORS static_cast<int>(asize(Contributors))
+#define NCR static_cast<int>(asize(CopyrightText))
 
     // 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 i = 0; i < NCONTRIBUTORS;)
     {
-        for (int j = 0; j < 4 && i < NCONTRIBUTORS; ++j, ++i)
+        for (int j = 0; j < 3 && i < NCONTRIBUTORS; ++j, ++i)
         {
-            const int width = 18;
-            char      buf[30];
-            const int offset = centeringOffset(width, strlen(Contributors[i]));
-            GMX_RELEASE_ASSERT(strlen(Contributors[i]) + offset < asize(buf),
+            const int            width = 26;
+            std::array<char, 30> buf;
+            const int            offset = centeringOffset(width, strlen(Contributors[i]));
+            GMX_RELEASE_ASSERT(static_cast<int>(strlen(Contributors[i])) + offset < gmx::ssize(buf),
                                "Formatting buffer is not long enough");
-            std::fill(buf, buf+width, ' ');
-            std::strcpy(buf+offset, Contributors[i]);
-            writer->writeString(formatString(" %-*s", width, buf));
+            std::fill(buf.begin(), buf.begin() + offset, ' ');
+            std::strncpy(buf.data() + offset, Contributors[i], gmx::ssize(buf) - offset);
+            writer->writeString(formatString(" %-*s", width, buf.data()));
         }
         writer->ensureLineBreak();
     }
     writer->writeLine(formatCentered(78, "and the project leaders:"));
-    writer->writeLine(formatCentered(78, "Mark Abraham, Berk Hess, Erik Lindahl, and David van der Spoel"));
+    writer->writeLine(
+            formatCentered(78, "Mark Abraham, Berk Hess, Erik Lindahl, and David van der Spoel"));
     writer->ensureEmptyLine();
     for (int i = 0; i < NCR; ++i)
     {
         writer->writeLine(CopyrightText[i]);
     }
     writer->ensureEmptyLine();
-    for (int i = 0; i < NLICENSE; ++i)
+
+    // Folding At Home has different licence to allow digital
+    // signatures in GROMACS, so does not need to show the normal
+    // license statement.
+    if (!GMX_FAHCORE)
     {
-        writer->writeLine(LicenseText[i]);
+        writer->writeLine("GROMACS is free software; you can redistribute it and/or modify it");
+        writer->writeLine("under the terms of the GNU Lesser General Public License");
+        writer->writeLine("as published by the Free Software Foundation; either version 2.1");
+        writer->writeLine("of the License, or (at your option) any later version.");
     }
 }
 
-// Construct a string that describes the library that provides FFT support to this build
-const char *getFftDescriptionString()
+//! Construct a string that describes the library that provides CPU FFT support to this build
+const char* getCpuFftDescriptionString()
 {
 // Define the FFT description string
-#if GMX_FFT_FFTW3
-#  if GMX_NATIVE_WINDOWS
+#if GMX_FFT_FFTW3 || GMX_FFT_ARMPL_FFTW3
+#    if GMX_NATIVE_WINDOWS
     // Don't buy trouble
     return "fftw3";
-#  else
+#    else
     // Use the version string provided by libfftw3
-#    if GMX_DOUBLE
+#        if GMX_DOUBLE
     return fftw_version;
-#    else
+#        else
     return fftwf_version;
+#        endif
 #    endif
-#  endif
 #endif
 #if GMX_FFT_MKL
     return "Intel MKL";
@@ -220,96 +231,176 @@ const char *getFftDescriptionString()
 #endif
 };
 
-void gmx_print_version_info(gmx::TextWriter *writer)
+//! Construct a string that describes the library that provides GPU FFT support to this build
+const char* getGpuFftDescriptionString()
+{
+    if (GMX_GPU)
+    {
+        if (GMX_GPU_CUDA)
+        {
+            return "cuFFT";
+        }
+        else if (GMX_GPU_OPENCL)
+        {
+            return "clFFT";
+        }
+        else if (GMX_GPU_SYCL)
+        {
+            return "unknown";
+        }
+        else
+        {
+            GMX_RELEASE_ASSERT(false, "Unknown GPU configuration");
+            return "impossible";
+        }
+    }
+    else
+    {
+        return "none";
+    }
+};
+
+void gmx_print_version_info(gmx::TextWriter* writer)
 {
     writer->writeLine(formatString("GROMACS version:    %s", gmx_version()));
-    const char *const git_hash = gmx_version_git_full_hash();
+    const charconst git_hash = gmx_version_git_full_hash();
     if (git_hash[0] != '\0')
     {
         writer->writeLine(formatString("GIT SHA1 hash:      %s", git_hash));
     }
-    const char *const base_hash = gmx_version_git_central_base_hash();
+    const charconst base_hash = gmx_version_git_central_base_hash();
     if (base_hash[0] != '\0')
     {
         writer->writeLine(formatString("Branched from:      %s", base_hash));
     }
+    const char* const releaseSourceChecksum = gmxReleaseSourceChecksum();
+    const char* const currentSourceChecksum = gmxCurrentSourceChecksum();
+    if (releaseSourceChecksum[0] != '\0')
+    {
+        if (std::strcmp(releaseSourceChecksum, "NoChecksumFile") == 0)
+        {
+            writer->writeLine(formatString(
+                    "The source code this program was compiled from has not been verified because "
+                    "the reference checksum was missing during compilation. This means you have an "
+                    "incomplete GROMACS distribution, please make sure to download an intact "
+                    "source distribution and compile that before proceeding."));
+            writer->writeLine(formatString("Computed checksum: %s", currentSourceChecksum));
+        }
+        else if (std::strcmp(releaseSourceChecksum, "NoPythonAvailable") == 0)
+        {
+            writer->writeLine(
+                    formatString("Build source could not be verified, because the checksum could "
+                                 "not be computed."));
+        }
+        else if (std::strcmp(releaseSourceChecksum, currentSourceChecksum) != 0)
+        {
+            writer->writeLine(formatString(
+                    "This program has been built from source code that has been altered and does "
+                    "not match the code released as part of the official GROMACS version %s. If "
+                    "you did not intend to use an altered GROMACS version, make sure to download "
+                    "an intact source distribution and compile that before proceeding.",
+                    gmx_version()));
+            writer->writeLine(formatString(
+                    "If you have modified the source code, you are strongly encouraged to set your "
+                    "custom version suffix (using -DGMX_VERSION_STRING_OF_FORK) which will can "
+                    "help later with scientific reproducibility but also when reporting bugs."));
+            writer->writeLine(formatString("Release checksum: %s", releaseSourceChecksum));
+            writer->writeLine(formatString("Computed checksum: %s", currentSourceChecksum));
+        }
+        else
+        {
+            writer->writeLine(formatString("Verified release checksum is %s", releaseSourceChecksum));
+        }
+    }
+
 
 #if GMX_DOUBLE
     writer->writeLine("Precision:          double");
 #else
-    writer->writeLine("Precision:          single");
+    writer->writeLine("Precision:          mixed");
 #endif
-    writer->writeLine(formatString("Memory model:       %u bit", (unsigned)(8*sizeof(void *))));
+    writer->writeLine(formatString("Memory model:       %u bit", static_cast<unsigned>(8 * sizeof(void*))));
 
 #if GMX_THREAD_MPI
     writer->writeLine("MPI library:        thread_mpi");
 #elif GMX_MPI
+#    if HAVE_CUDA_AWARE_MPI
+    writer->writeLine("MPI library:        MPI (CUDA-aware)");
+#    else
     writer->writeLine("MPI library:        MPI");
+#    endif
 #else
     writer->writeLine("MPI library:        none");
 #endif
 #if GMX_OPENMP
-    writer->writeLine(formatString("OpenMP support:     enabled (GMX_OPENMP_MAX_THREADS = %d)", GMX_OPENMP_MAX_THREADS));
+    writer->writeLine(formatString("OpenMP support:     enabled (GMX_OPENMP_MAX_THREADS = %d)",
+                                   GMX_OPENMP_MAX_THREADS));
 #else
     writer->writeLine("OpenMP support:     disabled");
 #endif
     writer->writeLine(formatString("GPU support:        %s", getGpuImplementationString()));
     writer->writeLine(formatString("SIMD instructions:  %s", GMX_SIMD_STRING));
-    writer->writeLine(formatString("FFT library:        %s", getFftDescriptionString()));
-    writer->writeLine(formatString("RDTSCP usage:       %s", HAVE_RDTSCP ? "enabled" : "disabled"));
-#ifdef GMX_USE_TNG
+    writer->writeLine(formatString("CPU FFT library:    %s", getCpuFftDescriptionString()));
+    writer->writeLine(formatString("GPU FFT library:    %s", getGpuFftDescriptionString()));
+#if GMX_TARGET_X86
+    writer->writeLine(formatString("RDTSCP usage:       %s", GMX_USE_RDTSCP ? "enabled" : "disabled"));
+#endif
+#if GMX_USE_TNG
     writer->writeLine("TNG support:        enabled");
 #else
     writer->writeLine("TNG support:        disabled");
 #endif
 #if GMX_USE_HWLOC
-    writer->writeLine(formatString("Hwloc support:      hwloc-%d.%d.%d",
-                                   HWLOC_API_VERSION>>16,
-                                   (HWLOC_API_VERSION>>8) & 0xFF,
-                                   HWLOC_API_VERSION & 0xFF));
+    writer->writeLine(formatString("Hwloc support:      hwloc-%s", HWLOC_VERSION));
 #else
     writer->writeLine("Hwloc support:      disabled");
 #endif
 #if HAVE_EXTRAE
     unsigned major, minor, revision;
     Extrae_get_version(&major, &minor, &revision);
-    writer->writeLine(formatString("Tracing support:    enabled. Using Extrae-%d.%d.%d", major, minor, revision));
+    writer->writeLine(formatString(
+            "Tracing support:    enabled. Using Extrae-%d.%d.%d", major, minor, revision));
 #else
     writer->writeLine("Tracing support:    disabled");
 #endif
 
 
-    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. */
-    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 flags:   %s %s", BUILD_CFLAGS, CMAKE_BUILD_CONFIGURATION_C_FLAGS));
     writer->writeLine(formatString("C++ compiler:       %s", BUILD_CXX_COMPILER));
-    writer->writeLine(formatString("C++ compiler flags: %s", BUILD_CXXFLAGS));
-#ifdef HAVE_LIBMKL
+    writer->writeLine(formatString(
+            "C++ compiler flags: %s %s", BUILD_CXXFLAGS, CMAKE_BUILD_CONFIGURATION_CXX_FLAGS));
+#if HAVE_LIBMKL
     /* MKL might be used for LAPACK/BLAS even if FFTs use FFTW, so keep it separate */
-    writer->writeLine(formatString("Linked with Intel MKL version %d.%d.%d.",
-                                   __INTEL_MKL__, __INTEL_MKL_MINOR__, __INTEL_MKL_UPDATE__));
+    writer->writeLine(formatString(
+            "Intel MKL version:  %d.%d.%d", __INTEL_MKL__, __INTEL_MKL_MINOR__, __INTEL_MKL_UPDATE__));
 #endif
-#if GMX_GPU == GMX_GPU_OPENCL
+#if GMX_GPU_OPENCL
     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
+#if GMX_GPU_CUDA
     writer->writeLine(formatString("CUDA compiler:      %s", CUDA_COMPILER_INFO));
-    writer->writeLine(formatString("CUDA compiler flags:%s", CUDA_COMPILER_FLAGS));
+    writer->writeLine(formatString(
+            "CUDA compiler flags:%s %s", CUDA_COMPILER_FLAGS, CMAKE_BUILD_CONFIGURATION_CXX_FLAGS));
     writer->writeLine("CUDA driver:        " + gmx::getCudaDriverVersionString());
     writer->writeLine("CUDA runtime:       " + gmx::getCudaRuntimeVersionString());
 #endif
+#if GMX_SYCL_DPCPP
+    writer->writeLine(formatString("SYCL DPC++ flags:   %s", SYCL_DPCPP_COMPILER_FLAGS));
+    writer->writeLine("SYCL DPC++ version: " + gmx::getSyclCompilerVersion());
+#endif
+#if GMX_SYCL_HIPSYCL
+    writer->writeLine(formatString("hipSYCL launcher:   %s", SYCL_HIPSYCL_COMPILER_LAUNCHER));
+    writer->writeLine(formatString("hipSYCL flags:      %s", SYCL_HIPSYCL_COMPILER_FLAGS));
+    writer->writeLine(formatString("hipSYCL targets:    %s", SYCL_HIPSYCL_TARGETS));
+    writer->writeLine("hipSYCL version:    " + gmx::getSyclCompilerVersion());
+#endif
 }
 
 //! \endcond
@@ -319,44 +410,47 @@ void gmx_print_version_info(gmx::TextWriter *writer)
 namespace gmx
 {
 
-BinaryInformationSettings::BinaryInformationSettings()
-    : bExtendedInfo_(false), bCopyright_(false),
-      bGeneratedByHeader_(false), prefix_(""), suffix_("")
+BinaryInformationSettings::BinaryInformationSettings() :
+    bExtendedInfo_(false),
+    bCopyright_(false),
+    bProcessId_(false),
+    bGeneratedByHeader_(false),
+    prefix_(""),
+    suffix_("")
 {
 }
 
-void printBinaryInformation(FILE                  *fp,
-                            const IProgramContext &programContext)
+void printBinaryInformation(FILE* fp, const IProgramContext& programContext)
 {
     TextWriter writer(fp);
     printBinaryInformation(&writer, programContext, BinaryInformationSettings());
 }
 
-void printBinaryInformation(FILE                            *fp,
-                            const IProgramContext           &programContext,
-                            const BinaryInformationSettings &settings)
+void printBinaryInformation(FILE*                            fp,
+                            const IProgramContext&           programContext,
+                            const BinaryInformationSettingssettings)
 {
     try
     {
         TextWriter writer(fp);
         printBinaryInformation(&writer, programContext, settings);
     }
-    GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
+    GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
 }
 
-void printBinaryInformation(TextWriter                      *writer,
-                            const IProgramContext           &programContext,
-                            const BinaryInformationSettings &settings)
+void printBinaryInformation(TextWriter*                      writer,
+                            const IProgramContext&           programContext,
+                            const BinaryInformationSettingssettings)
 {
     // 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 charprefix          = settings.prefix_;
+    const charsuffix          = settings.suffix_;
+    const charprecisionString = "";
 #if GMX_DOUBLE
     precisionString = " (double precision)";
 #endif
-    const char *const name = programContext.displayName();
+    const charconst name = programContext.displayName();
     if (settings.bGeneratedByHeader_)
     {
         writer->writeLine(formatString("%sCreated by:%s", prefix, suffix));
@@ -364,10 +458,9 @@ void printBinaryInformation(TextWriter                      *writer,
     // 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
     // could then print "%s is part of GROMACS" or some alternative text.
-    std::string title
-        = formatString(":-) GROMACS - %s, %s%s (-:", name, gmx_version(), precisionString);
-    const int   indent
-        = centeringOffset(78 - std::strlen(prefix) - std::strlen(suffix), title.length()) + 1;
+    std::string title = formatString(":-) GROMACS - %s, %s%s (-:", name, gmx_version(), precisionString);
+    const int indent =
+            centeringOffset(78 - std::strlen(prefix) - std::strlen(suffix), title.length()) + 1;
     writer->writeLine(formatString("%s%*c%s%s", prefix, indent, ' ', title.c_str(), suffix));
     writer->writeLine(formatString("%s%s", prefix, suffix));
     if (settings.bCopyright_)
@@ -381,10 +474,10 @@ void printBinaryInformation(TextWriter                      *writer,
         // necessary to read stuff above the copyright notice.
         // The line above the copyright notice puts the copyright notice is
         // context, though.
-        writer->writeLine(formatString("%sGROMACS:      %s, version %s%s%s", 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();
+    const charconst binaryPath = programContext.fullBinaryPath();
     if (!gmx::isNullOrEmpty(binaryPath))
     {
         writer->writeLine(formatString("%sExecutable:   %s%s", prefix, binaryPath, suffix));
@@ -392,19 +485,26 @@ void printBinaryInformation(TextWriter                      *writer,
     const gmx::InstallationPrefixInfo installPrefix = programContext.installationPrefix();
     if (!gmx::isNullOrEmpty(installPrefix.path))
     {
-        writer->writeLine(formatString("%sData prefix:  %s%s%s", 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())
     {
         writer->writeLine(formatString("%sWorking dir:  %s%s", prefix, workingDir.c_str(), suffix));
     }
-    const char *const commandLine = programContext.commandLine();
+    if (settings.bProcessId_)
+    {
+        writer->writeLine(formatString("%sProcess ID:   %d%s", prefix, gmx_getpid(), suffix));
+    }
+    const char* const commandLine = programContext.commandLine();
     if (!gmx::isNullOrEmpty(commandLine))
     {
-        writer->writeLine(formatString("%sCommand line:%s\n%s  %s%s",
-                                       prefix, suffix, prefix, commandLine, suffix));
+        writer->writeLine(formatString(
+                "%sCommand line:%s\n%s  %s%s", prefix, suffix, prefix, commandLine, suffix));
     }
     if (settings.bExtendedInfo_)
     {