diff --git a/GeoModelCore/GeoModelKernel/CMakeLists.txt b/GeoModelCore/GeoModelKernel/CMakeLists.txt
index 1a4bc0b1cb385dcbb79a4db433436c1bae1f6f8b..d0bbfb56521da288e08e92440ca7b04c3e47b4d9 100644
--- a/GeoModelCore/GeoModelKernel/CMakeLists.txt
+++ b/GeoModelCore/GeoModelKernel/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
+# Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
 
 # Find the header and source files.
 file( GLOB SOURCES src/*.cxx )
@@ -20,6 +20,19 @@ set_target_properties( GeoModelKernel PROPERTIES
    VERSION ${PROJECT_VERSION}
    SOVERSION ${PROJECT_VERSION_MAJOR} )
 
+# Code in this file makes heavy use of eigen and runs orders of magnitude
+# more slowly without optimization.  So force this to be optimized even
+# in debug builds.  If you need to debug it you might want to change this.
+# Specifying optimization via an attribute on the particular
+# function didn't work, because that still didn't allow inlining.
+if ( "${CMAKE_BUILD_TYPE}" STREQUAL "Debug" )
+  set_source_files_properties(
+     ${CMAKE_CURRENT_SOURCE_DIR}/src/GeoXF.cxx
+     PROPERTIES
+     COMPILE_FLAGS "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}"
+     COMPILE_DEFINITIONS "FLATTEN" )
+endif()
+
 # Set up an alias with the same name that you would get by "finding" a pre-built
 # version of the library.
 add_library( GeoModelCore::GeoModelKernel ALIAS GeoModelKernel )
diff --git a/GeoModelCore/GeoModelKernel/src/GeoXF.cxx b/GeoModelCore/GeoModelKernel/src/GeoXF.cxx
index a3038686e56f9cc8ca84954bc877413ea864ef12..23cac3f8806844d230ec637264e52b1bfcb85f0b 100755
--- a/GeoModelCore/GeoModelKernel/src/GeoXF.cxx
+++ b/GeoModelCore/GeoModelKernel/src/GeoXF.cxx
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
 */
 
 #include "GeoModelKernel/GeoXF.h"
@@ -134,11 +134,23 @@ namespace GeoXF
     return m_arg2->dimensionality ();
   }
 
+#if defined(FLATTEN) && defined(__GNUC__)
+// We compile this package with optimization, even in debug builds; otherwise,
+// the heavy use of Eigen makes it too slow.  However, from here we may call
+// to out-of-line Eigen code that is linked from other DSOs; in that case,
+// it would not be optimized.  Avoid this by forcing all Eigen code
+// to be inlined here if possible.
+__attribute__ ((flatten))
+#endif
   GeoTrf::Transform3D PreMult::operator        () (double x) const
   {
     return m_arg1 * (*m_arg2) (x);
   }
 
+#if defined(FLATTEN) && defined(__GNUC__)
+// See above.
+__attribute__ ((flatten))
+#endif
   GeoTrf::Transform3D PreMult::operator        () (const GeoGenfun::Argument & x) const
   {
     return m_arg1 * (*m_arg2) (x);
@@ -181,11 +193,19 @@ namespace GeoXF
     return m_arg1->dimensionality ();
   }
 
+#if defined(FLATTEN) && defined(__GNUC__)
+// See above.
+__attribute__ ((flatten))
+#endif
   GeoTrf::Transform3D PostMult::operator        () (double x) const
   {
     return (*m_arg1) (x) * m_arg2;
   }
 
+#if defined(FLATTEN) && defined(__GNUC__)
+// See above.
+__attribute__ ((flatten))
+#endif
   GeoTrf::Transform3D PostMult::operator        () (const GeoGenfun::Argument & x) const
   {
     return (*m_arg1) (x) * m_arg2;
@@ -202,6 +222,10 @@ namespace GeoXF
     delete m_function;
   }
 
+#if defined(FLATTEN) && defined(__GNUC__)
+// See above.
+__attribute__ ((flatten))
+#endif
   GeoTrf::Transform3D Pow::operator() (double x) const
   {
     //