diff --git a/python/dune/perftool/compile.py b/python/dune/perftool/compile.py
index 6200538cd50d4958ba576aa55bb4f8c563a70bae..c9d1077ca430b729c5810b6bb50f1ad21d9852c7 100644
--- a/python/dune/perftool/compile.py
+++ b/python/dune/perftool/compile.py
@@ -76,8 +76,10 @@ def compile_form():
     from dune.perftool.options import get_option
     form = read_ufl(get_option("uflfile"))
 
+    from dune.perftool.generation import cache_context
     if get_option("driver_file"):
-        generate_driver(form, get_option("driver_file"))
+        with cache_context('driver'):
+            generate_driver(form, get_option("driver_file"))
 
     if get_option("operator_file"):
         from dune.perftool.pdelab.localoperator import generate_localoperator_kernels
diff --git a/python/dune/perftool/generation/cpp.py b/python/dune/perftool/generation/cpp.py
index 32efb653bb7c51cb2ab54a293b9eeba960d5fc49..92a771c4e6bb518666c962fb8e1938490ef55d36 100644
--- a/python/dune/perftool/generation/cpp.py
+++ b/python/dune/perftool/generation/cpp.py
@@ -7,6 +7,7 @@ from dune.perftool.generation import generator_factory
 from dune.perftool.cgen.clazz import AccessModifier
 
 symbol = generator_factory(item_tags=("symbol",))
+preamble = generator_factory(item_tags=("premable",), counted=True)
 
 
 def include_file(include, filetag=None):
@@ -16,10 +17,6 @@ def include_file(include, filetag=None):
     return gen(include)
 
 
-def preamble(tag):
-    return generator_factory(item_tags=(tag, "preamble"), counted=True)
-
-
 def initializer_list(obj, params, classtag=None):
     assert classtag
     gen = generator_factory(item_tags=(classtag, "initializer"), counted=True, cache_key_generator=lambda *a: a[0])
diff --git a/python/dune/perftool/pdelab/basis.py b/python/dune/perftool/pdelab/basis.py
index ac1195a5642c29a60daeb2919f6614bab49008a7..901e969a88b0d853bd49e82fbf829c2004aa8f3f 100644
--- a/python/dune/perftool/pdelab/basis.py
+++ b/python/dune/perftool/pdelab/basis.py
@@ -16,7 +16,7 @@ from dune.perftool.pdelab.geometry import (name_jacobian_inverse_transposed,
                                            )
 
 
-@preamble('blubb')
+@preamble
 def define_lfs_bound(lfs, bound):
     return 'auto {} = {}.size();'.format(bound, lfs)
 
diff --git a/python/dune/perftool/pdelab/driver.py b/python/dune/perftool/pdelab/driver.py
index 17d1fbac2cc6e0552ad9c8b299789505b12fa90a..a43b48c0e97d07e69f8f7b434dde2c224fe3799f 100644
--- a/python/dune/perftool/pdelab/driver.py
+++ b/python/dune/perftool/pdelab/driver.py
@@ -65,7 +65,7 @@ def name_inifile():
     return "argv[1]"
 
 
-@preamble('driver')
+@preamble
 def parse_initree(varname):
     include_file("dune/common/parametertree.hh", filetag="driver")
     include_file("dune/common/parametertreeparser.hh", filetag="driver")
@@ -80,7 +80,7 @@ def name_initree():
     return "initree"
 
 
-@preamble('driver')
+@preamble
 def define_dimension(name):
     return "static const int {} = {};".format(name, _form.cell().geometric_dimension())
 
@@ -91,7 +91,7 @@ def name_dimension():
     return "dim"
 
 
-@preamble('driver')
+@preamble
 def typedef_grid(name):
     dim = name_dimension()
     if any(_form.cell().cellname() in x for x in ["vertex", "interval", "quadrilateral", "hexalateral"]):
@@ -112,7 +112,7 @@ def type_grid():
     return "Grid"
 
 
-@preamble('driver')
+@preamble
 def define_grid(name):
     include_file("dune/testtools/gridconstruction.hh", filetag="driver")
     ini = name_initree()
@@ -127,7 +127,7 @@ def name_grid():
     return "grid"
 
 
-@preamble('driver')
+@preamble
 def typedef_leafview(name):
     grid = type_grid()
     return "typedef {}::LeafGridView {};".format(grid, name)
@@ -139,7 +139,7 @@ def type_leafview():
     return "GV"
 
 
-@preamble('driver')
+@preamble
 def define_leafview(name):
     _type = type_leafview()
     grid = name_grid()
@@ -152,7 +152,7 @@ def name_leafview():
     return "gv"
 
 
-@preamble('driver')
+@preamble
 def typedef_vtkwriter(name):
     include_file("dune/grid/io/file/vtk/subsamplingvtkwriter.hh", filetag="driver")
     gv = type_leafview()
@@ -165,7 +165,7 @@ def type_vtkwriter():
     return "VTKWriter"
 
 
-@preamble('driver')
+@preamble
 def define_subsamplinglevel(name):
     ini = name_initree()
     return "int {} = {}.get<int>(\"vtk.subsamplinglevel\", 0);".format(name, ini)
@@ -177,7 +177,7 @@ def name_subsamplinglevel():
     return "sublevel"
 
 
-@preamble('driver')
+@preamble
 def define_vtkwriter(name):
     _type = type_vtkwriter()
     gv = name_leafview()
@@ -191,7 +191,7 @@ def name_vtkwriter():
     return "vtkwriter"
 
 
-@preamble('driver')
+@preamble
 def typedef_domainfield(name):
     gridt = type_grid()
     return "typedef {}::ctype {};".format(gridt, name)
@@ -203,7 +203,7 @@ def type_domainfield():
     return "DF"
 
 
-@preamble('driver')
+@preamble
 def typedef_range(name):
     return "typedef double {};".format(name)
 
@@ -214,7 +214,7 @@ def type_range():
     return "R"
 
 
-@preamble('driver')
+@preamble
 def typedef_fem(expr, name):
     gv = type_leafview()
     df = type_domainfield()
@@ -235,7 +235,7 @@ def type_fem(expr):
     return name
 
 
-@preamble('driver')
+@preamble
 def define_fem(expr, name):
     femtype = type_fem(expr)
     gv = name_leafview()
@@ -249,7 +249,7 @@ def name_fem(expr):
     return name
 
 
-@preamble('driver')
+@preamble
 def typedef_vectorbackend(name):
     include_file("dune/pdelab/backend/istlvectorbackend.hh", filetag="driver")
     return "typedef Dune::PDELab::ISTLVectorBackend<Dune::PDELab::ISTLParameters::no_blocking, 1> {};".format(name)
@@ -266,7 +266,7 @@ def type_orderingtag():
     return "Dune::PDELab::LexicographicOrderingTag"
 
 
-@preamble('driver')
+@preamble
 def typedef_constraintsassembler(name):
     include_file("dune/pdelab/constraints/conforming.hh", filetag="driver")
     return "typedef Dune::PDELab::ConformingDirichletConstraints {};".format(name)
@@ -278,7 +278,7 @@ def type_constraintsassembler():
     return "ConstraintsAssembler"
 
 
-@preamble('driver')
+@preamble
 def typedef_constraintscontainer(expr, name):
     gfs = type_gfs(expr)
     r = type_range()
@@ -292,7 +292,7 @@ def type_constraintscontainer(expr):
     return name
 
 
-@preamble('driver')
+@preamble
 def define_constraintscontainer(expr, name):
     cctype = type_constraintscontainer(expr)
     return ["{} {};".format(cctype, name), "{}.clear();".format(name)]
@@ -305,7 +305,7 @@ def name_constraintscontainer(expr):
     return name
 
 
-@preamble('driver')
+@preamble
 def typedef_gfs(expr, name):
     vb = type_vectorbackend()
     from ufl import FiniteElement, MixedElement, VectorElement, EnrichedElement, RestrictedElement
@@ -338,7 +338,7 @@ def type_gfs(expr):
     return name
 
 
-@preamble('driver')
+@preamble
 def define_gfs(expr, name):
     gfstype = type_gfs(expr)
     from ufl import FiniteElement, MixedElement, VectorElement, EnrichedElement, RestrictedElement
@@ -366,7 +366,7 @@ def name_gfs(expr):
     return name
 
 
-@preamble('driver')
+@preamble
 def define_dofestimate(name):
     # Provide a worstcase estimate for the number of entries per row based on the given gridfunction space and cell geometry
     if isQuadrilateral(_form.coefficients()[0].element()):
@@ -385,7 +385,7 @@ def name_dofestimate():
     return "dofestimate"
 
 
-@preamble('driver')
+@preamble
 def typedef_matrixbackend(name):
     include_file("dune/pdelab/backend/istl/bcrsmatrixbackend.hh", filetag="driver")
     return "typedef Dune::PDELab::istl::BCRSMatrixBackend<> {};".format(name)
@@ -397,7 +397,7 @@ def type_matrixbackend():
     return "MatrixBackend"
 
 
-@preamble('driver')
+@preamble
 def define_matrixbackend(name):
     mbtype = type_matrixbackend()
     dof = name_dofestimate()
@@ -410,7 +410,7 @@ def name_matrixbackend():
     return "mb"
 
 
-@preamble('driver')
+@preamble
 def typedef_parameters(name):
     return "typedef LocalOperatorParameters {};".format(name)
 
@@ -421,7 +421,7 @@ def type_parameters():
     return "Params"
 
 
-@preamble('driver')
+@preamble
 def define_parameters(name):
     partype = type_parameters()
     return "{} {}();".format(partype, name)
@@ -433,7 +433,7 @@ def name_parameters():
     return "params"
 
 
-@preamble('driver')
+@preamble
 def typedef_localoperator(name):
     # No Parameter class here, yet
     # params = type_parameters()
@@ -449,7 +449,7 @@ def type_localoperator():
     return "LocalOperator"
 
 
-@preamble('driver')
+@preamble
 def define_localoperator(name):
     loptype = type_localoperator()
     ini = name_initree()
@@ -463,7 +463,7 @@ def name_localoperator():
     return "lop"
 
 
-@preamble('driver')
+@preamble
 def typedef_gridoperator(name):
     ugfs = type_gfs(_form.coefficients()[0].element())
     vgfs = type_gfs(_form.arguments()[0].element())
@@ -483,7 +483,7 @@ def type_gridoperator():
     return "GO"
 
 
-@preamble('driver')
+@preamble
 def define_gridoperator(name):
     gotype = type_gridoperator()
     ugfs = name_gfs(_form.coefficients()[0].element())
@@ -501,7 +501,7 @@ def name_gridoperator():
     return "go"
 
 
-@preamble('driver')
+@preamble
 def typedef_vector(name):
     gotype = type_gridoperator()
     return "typedef {}::Traits::Domain {};".format(gotype, name)
@@ -513,7 +513,7 @@ def type_vector():
     return "V"
 
 
-@preamble('driver')
+@preamble
 def define_vector(name):
     vtype = type_vector()
     gfs = name_gfs(_form.coefficients()[0].element())
@@ -526,7 +526,7 @@ def name_vector():
     return "x"
 
 
-@preamble('driver')
+@preamble
 def typedef_linearsolver(name):
     include_file("dune/pdelab/backend/istlsolverbackend.hh", filetag="driver")
     return "typedef Dune::PDELab::ISTLBackend_SEQ_UMFPack {};".format(name)
@@ -538,7 +538,7 @@ def type_linearsolver():
     return "LinearSolver"
 
 
-@preamble('driver')
+@preamble
 def define_linearsolver(name):
     lstype = type_linearsolver()
     return "{} {}(false);".format(lstype, name)
@@ -550,7 +550,7 @@ def name_linearsolver():
     return "ls"
 
 
-@preamble('driver')
+@preamble
 def define_reduction(name):
     ini = name_initree()
     return "double {} = {}.get<double>(\"reduction\", 1e-12);".format(name, ini)
@@ -577,7 +577,7 @@ def type_stationarylinearproblemsolver():
     return "SLP"
 
 
-@preamble('driver')
+@preamble
 def define_stationarylinearproblemsolver(name):
     slptype = type_stationarylinearproblemsolver()
     go = name_gridoperator()
@@ -593,7 +593,7 @@ def name_stationarylinearproblemsolver():
     return "slp"
 
 
-@preamble('driver')
+@preamble
 def dune_solve():
     from ufl.algorithms.predicates import is_multilinear
     # This is crap as it does check for linearity of the rank 1 form,
@@ -605,7 +605,7 @@ def dune_solve():
         raise NotImplementedError
 
 
-@preamble('driver')
+@preamble
 def define_vtkfile(name):
     ini = name_initree()
     include_file("string", filetag="driver")
@@ -618,7 +618,7 @@ def name_vtkfile():
     return "vtkfile"
 
 
-@preamble('driver')
+@preamble
 def vtkoutput():
     include_file("dune/pdelab/gridfunctionspace/vtk.hh", filetag="driver")
     vtkwriter = name_vtkwriter()
diff --git a/python/dune/perftool/pdelab/geometry.py b/python/dune/perftool/pdelab/geometry.py
index 15eeaa0432cfcf43ff712e6b782351298f5dc674..9dfdeee78275d4adbc820fcab7a77de2608b59fc 100644
--- a/python/dune/perftool/pdelab/geometry.py
+++ b/python/dune/perftool/pdelab/geometry.py
@@ -1,7 +1,7 @@
 from dune.perftool.generation import preamble, symbol
 
 
-@preamble('blubb')
+@preamble
 def define_geometry(name):
     return "auto {} = eg.geometry();".format(name)
 
@@ -18,7 +18,7 @@ def name_dimension():
     return "dim"
 
 
-@preamble('blubb')
+@preamble
 def define_jacobian_inverse_transposed(name):
     geo = name_geometry()
     return "auto {} = {}.jacobianInverseTransposed();".format(name,