diff --git a/cmake/modules/DuneCodegenMacros.cmake b/cmake/modules/DuneCodegenMacros.cmake
index 69de840ca0d3a02d4e9a6519f94af308330b6859..6a02c01633260e251d0516024acf29efebb27b88 100644
--- a/cmake/modules/DuneCodegenMacros.cmake
+++ b/cmake/modules/DuneCodegenMacros.cmake
@@ -71,6 +71,13 @@
 #    Regeneration is triggered correctly if the UFL file or the
 #    form compiler changed.
 #
+# .. cmake_variable:: DUNE_CODEGEN_PROFILING
+#
+#    Set this variable from your opts file to enable statistic profiling of
+#    the code generation process. This usually introduces additional cost.
+#    A cProfile file for post processing will be written whenever the code
+#    generator is run.
+#
 
 add_custom_target(generation)
 
@@ -163,11 +170,25 @@ function(add_generated_executable)
                        )
   parse_python_data(PREFIX depdata INPUT ${depdata})
 
+  if(DUNE_CODEGEN_PROFILING)
+    # This is a bit silly, but cProfile only finds entry point scripts
+    # if their full path is provided. So we resort to using which.
+    dune_execute_process(COMMAND which generate_operators
+                         OUTPUT_VARIABLE fullcommand
+                         OUTPUT_STRIP_TRAILING_WHITESPACE
+                         )
+  endif()
+	
   # Define build rules for all operator header files and gather a list of them
   set(header_deps)
   foreach(op ${depdata___operators})
+    set(GENERATION_COMMAND generate_operators)
+    if(DUNE_CODEGEN_PROFILING)
+      set(GENERATION_COMMAND python -m cProfile -o ${depdata___${op}}.prof ${fullcommand})
+    endif()
+	
     add_custom_command(OUTPUT ${depdata___${op}}
-                       COMMAND ${CMAKE_BINARY_DIR}/run-in-dune-env generate_operators
+                       COMMAND ${CMAKE_BINARY_DIR}/run-in-dune-env ${GENERATION_COMMAND}
                                --project-basedir ${CMAKE_BINARY_DIR}
                                ${GEN_FORM_COMPILER_ARGS}
                                --uflfile ${GEN_UFLFILE}
diff --git a/python/dune/codegen/sumfact/geometry.py b/python/dune/codegen/sumfact/geometry.py
index 3a9a5a5ad9a6ea240bfc4ffc2534f610e12eb97d..08e9d43e8fe685b3b24b60bd10be418b5f078ad7 100644
--- a/python/dune/codegen/sumfact/geometry.py
+++ b/python/dune/codegen/sumfact/geometry.py
@@ -525,6 +525,7 @@ def name_meshwidth():
     return name
 
 
+@kernel_cached
 def _name_jacobian(i, j, restriction, visitor):
     """Return the (i, j) component of the jacobian of the geometry mapping
 
@@ -534,8 +535,6 @@ def _name_jacobian(i, j, restriction, visitor):
     Note: At the moment this only works for the mappings from reference cells
     to the cell and not for the geometry mappings of intersections.
     """
-    do_predicates = visitor.do_predicates
-
     # Create matrix sequence with derivative in j direction
     matrix_sequence = construct_basis_matrix_sequence(derivative=j,
                                                       facedir=get_facedir(restriction),