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}