Add detection for ARMv7 cycle counter support
authorErik Lindahl <erik@kth.se>
Thu, 7 Jul 2016 11:45:47 +0000 (13:45 +0200)
committerMark Abraham <mark.j.abraham@gmail.com>
Fri, 8 Jul 2016 13:16:23 +0000 (15:16 +0200)
ARMv7 requires special kernel settings to allow cycle
counters to be read. This change adds a cmake setting
to enable/disable counters. On all architectures but ARMv7
it is enabled by default, and on ARMv7 we run a small test
program to see if the can be executed successfully. When
cross-compiling to ARMv7 counters will be disabled, but
either choice can be overridden by setting a value for
GMX_CYCLECOUNTERS in cmake.

Fixes #1933.

Change-Id: I1e217d7a09f84a6bcf4eb5bf4a656d430465c915

CMakeLists.txt
cmake/TestARMv7.cpp [new file with mode: 0644]
cmake/TestARMv7CycleCounters.cpp [new file with mode: 0644]
cmake/gmxDetectTargetArchitecture.cmake
cmake/gmxManageCycleCounters.cmake [new file with mode: 0644]
src/config.h.cmakein
src/gromacs/timing/cyclecounter.h

index 739fb14da8f9eb0cecea71adbcaa163eb551664c..047600e5ff48ae411db9fe4f3b3972fccc5c9258 100644 (file)
@@ -665,6 +665,9 @@ endif()
 include(gmxManageSimd)
 gmx_manage_simd()
 
+include(gmxManageCycleCounters)
+gmx_manage_cycle_counters()
+
 # Process QM/MM Settings
 if(${GMX_QMMM_PROGRAM} STREQUAL "GAUSSIAN")
     set(GMX_QMMM_GAUSSIAN 1)
diff --git a/cmake/TestARMv7.cpp b/cmake/TestARMv7.cpp
new file mode 100644 (file)
index 0000000..2b6a3ae
--- /dev/null
@@ -0,0 +1,8 @@
+int main()
+{
+#ifdef __ARM_ARCH_7A__
+    return 0;
+#else
+#error This compiler is not targetting 32-bit ARMv7
+#endif
+}
diff --git a/cmake/TestARMv7CycleCounters.cpp b/cmake/TestARMv7CycleCounters.cpp
new file mode 100644 (file)
index 0000000..81b9251
--- /dev/null
@@ -0,0 +1,12 @@
+int main()
+{
+#if defined(__ARM_ARCH_7A__) && defined(__GNUC__)
+    unsigned int cycles_lo, cycles_hi;
+    asm volatile("mrrc p15, 1, %0, %1, c14" : "=r" (cycles_lo), "=r" (cycles_hi));
+
+    // Return 0 (success) if low or high 32 bits contained anything non-trivial
+    return !(cycles_lo > 0 || cycles_hi > 0);
+#else
+#error This architecture/compiler does not support ARMv7 32-bit cycle counters
+#endif
+}
index 2a188c77b30f443474151d6b9196ea556f8ca1b4..4d5000b138fb95ddbbc066fca6cf6b02272d50b1 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2013,2014, by the GROMACS development team, led by
+# Copyright (c) 2013,2014,2016, 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.
@@ -53,6 +53,10 @@ function(gmx_detect_target_architecture)
         try_compile(GMX_TARGET_MIC ${CMAKE_BINARY_DIR}
             "${CMAKE_SOURCE_DIR}/cmake/TestMIC.c")
     endif()
+    if (NOT DEFINED GMX_TARGET_ARMV7)
+        try_compile(GMX_TARGET_ARMV7 ${CMAKE_BINARY_DIR}
+            "${CMAKE_SOURCE_DIR}/cmake/TestARMv7.cpp")
+    endif()
     if (NOT DEFINED GMX_TARGET_FUJITSU_SPARC64)
         try_compile(GMX_TARGET_FUJITSU_SPARC64 ${CMAKE_BINARY_DIR}
             "${CMAKE_SOURCE_DIR}/cmake/TestFujitsuSparc64.c")
diff --git a/cmake/gmxManageCycleCounters.cmake b/cmake/gmxManageCycleCounters.cmake
new file mode 100644 (file)
index 0000000..df3f0c7
--- /dev/null
@@ -0,0 +1,81 @@
+#
+# This file is part of the GROMACS molecular simulation package.
+#
+# Copyright (c) 2012,2013,2014,2015,2016, 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.
+#
+# 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.
+#
+# GROMACS is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with GROMACS; if not, see
+# http://www.gnu.org/licenses, or write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+#
+# If you want to redistribute modifications to GROMACS, please
+# consider that scientific software is very special. Version
+# control is crucial - bugs must be traceable. We will be happy to
+# consider code for inclusion in the official distribution, but
+# derived work must not be called official GROMACS. Details are found
+# in the README & COPYING files - if they are missing, get the
+# official version at http://www.gromacs.org.
+#
+# To help us fund GROMACS development, we humbly ask that you cite
+# the research papers on the package. Check out http://www.gromacs.org.
+
+# - Decide whether to use CPU cycle counters
+#
+# gmx_manage_cycle_counters()
+#
+# By default, we enable GMX_CYCLECOUNTERS for all architectures except ARMv7.
+# On ARMv7, we enable it if we are not cross-compiling and can run a small
+# test to confirm that the support is present in the kernel, otherwise we
+# disable it.
+#
+macro(gmx_manage_cycle_counters)
+
+    if(NOT DEFINED GMX_CYCLECOUNTERS)
+
+        if(GMX_TARGET_ARMV7)
+
+            if(NOT CMAKE_CROSSCOMPILING)
+
+                try_run(ARMV7_COUNTER_RUN_VAR ARMV7_COUNTER_COMPILE_VAR
+                        ${CMAKE_BINARY_DIR} "${CMAKE_SOURCE_DIR}/cmake/TestARMv7CycleCounters.cpp")
+
+                # Enable cycle counter usage if the test ran fine and exited with 0 return code
+                if(${ARMV7_COUNTER_COMPILE_VAR} AND ("${ARMV7_COUNTER_RUN_VAR}" EQUAL "0"))
+                    set(GMX_CYCLECOUNTERS ON CACHE BOOL "Use CPU cycle counters timing")
+                else()
+                    set(GMX_CYCLECOUNTERS OFF CACHE BOOL "Use CPU cycle counters for timing")
+                endif()
+
+            else()
+
+                # Disable cycle counters when cross-compiling for ARMv7
+                set(GMX_CYCLECOUNTERS OFF CACHE BOOL "Use CPU cycle counters for timing")
+
+            endif()
+
+        else()
+
+            # For now we (try to) enable cycle counters on all other platforms
+            set(GMX_CYCLECOUNTERS ON CACHE BOOL "Use CPU cycle counters timing")
+
+        endif()
+
+        mark_as_advanced(GMX_CYCLECOUNTERS)
+
+    endif()
+
+endmacro()
+
index d842a88ddc69c88211d708801209bdbb7e59e46f..c7bd5fb3dab936c13a5ce09708c54fcb0572acc3 100644 (file)
 /* Use ORCA for QM-MM calculations */
 #cmakedefine01 GMX_QMMM_ORCA
 
+/* Use cycle counters */
+#cmakedefine01 GMX_CYCLECOUNTERS
+
 /* Use sub-counters */
 #cmakedefine01 GMX_CYCLE_SUBCOUNTERS
 
index 06f8cb350bef8466c7982cbce8593c633594ddff..f2361a0c77d2a91c620bec29dea693aa6b12d6fe 100644 (file)
@@ -208,7 +208,12 @@ typedef long
  *  the difference between two gmx_cycles_t values returned from this
  *  routine.
  */
-#if ((defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__PATHSCALE__) || defined(__PGIC__)) && \
+#if (GMX_CYCLECOUNTERS == 0)
+static __inline__ gmx_cycles_t gmx_cycles_read(void)
+{
+    return 0;
+}
+#elif ((defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__PATHSCALE__) || defined(__PGIC__)) && \
     (defined(__i386__) || defined(__x86_64__)) && !defined(_CRAYC))
 static __inline__ gmx_cycles_t gmx_cycles_read(void)
 {
@@ -441,7 +446,12 @@ static gmx_cycles_t gmx_cycles_read(void)
  *       one when later linking to the library it might happen that the
  *       library supports cyclecounters but not the headers, or vice versa.
  */
-#if ((defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__PATHSCALE__) || defined(__PGIC__) || defined(_CRAYC)) && \
+#if (GMX_CYCLECOUNTERS == 0)
+static __inline__ int gmx_cycles_have_counter(void)
+{
+    return 0;
+}
+#elif ((defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__PATHSCALE__) || defined(__PGIC__) || defined(_CRAYC)) && \
     (defined(__i386__) || defined(__x86_64__)))
 static __inline__ int gmx_cycles_have_counter(void)
 {