diff --git a/python/dune/perftool/compile.py b/python/dune/perftool/compile.py
index 46d63854dce2fad1f717d99138b0fd300d3ee311..473e7b0ff364429a3124271bef0f4be3a31f5173 100644
--- a/python/dune/perftool/compile.py
+++ b/python/dune/perftool/compile.py
@@ -60,15 +60,15 @@ def generate_driver(form, filename):
     from dune.perftool.generation import retrieve_cache_items
     from cgen import FunctionDeclaration, FunctionBody, Block, Value
     driver_signature = FunctionDeclaration(Value('void', 'driver'), [Value('int', 'argc'), Value('char**', 'argv')])
-    driver_body = Block(contents=[i for i in retrieve_cache_items(("driver", "preamble"), union=False, make_generable=True)])
+    driver_body = Block(contents=[i for i in retrieve_cache_items("driver and preamble", make_generable=True)])
     driver = FunctionBody(driver_signature, driver_body)
 
     from dune.perftool.file import generate_file
     generate_file(filename, "driver", [driver])
 
     # Reset the caching data structure
-    from dune.perftool.generation import delete_cache
-    delete_cache()
+    from dune.perftool.generation import delete_cache_items
+    delete_cache_items()
 
 
 def compile_form():
diff --git a/python/dune/perftool/file.py b/python/dune/perftool/file.py
index ab6755700e7e312ce551c990a1d34c09dbc0ceb6..c49439ef61ca018933a9c4b1d82d3ea4d25fc1b8 100644
--- a/python/dune/perftool/file.py
+++ b/python/dune/perftool/file.py
@@ -28,7 +28,7 @@ def generate_file(filename, tag, content, headerguard=True):
 
         # Add the includes from the cache
         from dune.perftool.generation import retrieve_cache_items
-        for inc in retrieve_cache_items((tag, 'include'), union=False):
+        for inc in retrieve_cache_items('{} and include'.format(tag)):
             from cgen import Include
             assert isinstance(inc, Include)
             for line in inc.generate():
diff --git a/python/dune/perftool/generation/__init__.py b/python/dune/perftool/generation/__init__.py
index 34207521d3cf4c5c139bb6acc5803a49b60d9cef..9fd8a722ad0b979c197868f87262cb3e3acccfe6 100644
--- a/python/dune/perftool/generation/__init__.py
+++ b/python/dune/perftool/generation/__init__.py
@@ -3,7 +3,6 @@ from __future__ import absolute_import
 from dune.perftool.generation.cache import (generator_factory, # TODO get rid of this one, it is internal
                                             retrieve_cache_items,
                                             delete_cache_items,
-                                            delete_cache,
                                             )
 
 from dune.perftool.generation.cpp import (base_class,
diff --git a/python/dune/perftool/generation/cache.py b/python/dune/perftool/generation/cache.py
index f80933d4da345b81b619f50f176092a1da9b44d6..0780cd14a5e1ef55986d96afeb737f44e52d7d9f 100644
--- a/python/dune/perftool/generation/cache.py
+++ b/python/dune/perftool/generation/cache.py
@@ -164,36 +164,21 @@ def generator_factory(**factory_kwargs):
         return _dec
 
 
-def retrieve_cache_items(tags, union=True, make_generable=False):
-    """ Retrieve items from the cache.
+class _ConditionDict(dict):
+        def __init__(self, tags):
+            dict.__init__(self)
+            self.tags = tags
 
-    If union is True, all items that match one of the given tags are
-    returned. If unions is False, only items that match all tags are
-    returned. The items do remain in the cache.
+        def __getitem__(self, i):
+            return i in self.tags
+
+
+def _filter_cache_items(condition):
+    return {k: v for k, v in _cache.items() if eval(condition, _ConditionDict(v.tags))}
 
-    If make_generable is True, any strings are wrapped as cgen.Line
-    """
-    if isinstance(tags, str):
-        tags = (tags,)
-
-    choice = []
-
-    for item in _cache.values():
-        # Determine whether this item is a match with the given tags and the union parameter
-        match = False
-        if union:
-            for t in item.tags:
-                if t in tags:
-                    match = True
-        else:
-            match = True
-            for t in item.tags:
-                if t not in tags:
-                    match = False
 
-        # Append the item to the list
-        if match:
-            choice.append(item)
+def retrieve_cache_items(condition=True, make_generable=False):
+    choice = _filter_cache_items(condition).values()
 
     def as_generable(content):
         if make_generable:
@@ -211,6 +196,7 @@ def retrieve_cache_items(tags, union=True, make_generable=False):
         if not item.counted:
             yield as_generable(item.content)
 
+    # And now the sorted ones
     for item in sorted([i for i in choice if i.counted], key=lambda i: i.content[0]):
         from collections import Iterable
         if isinstance(item.content[1], Iterable) and not isinstance(item.content[1], str):
@@ -220,21 +206,10 @@ def retrieve_cache_items(tags, union=True, make_generable=False):
             yield as_generable(item.content[1])
 
 
-def delete_cache_items(tags, union=True):
-    """ Delete items from the cache.
-
-    If union is True, all items that match one of the given tags are
-    deleted. If unions is False, only items that match all tags are
-    deleted.
-    """
-    # TODO this implementation is horribly inefficient, but does the job
-    removing = retrieve_cache_items(tags, union)
-    global _cache
-    _cache = {k: v for k, v in _cache.items() if v not in removing}
-
+def delete_cache_items(condition=True, keep=False):
+    """ Delete items from the cache. """
+    if not keep:
+        condition = "not ({})".format(condition)
 
-def delete_cache(tags=[], union=True):
-    # TODO this implementation is horribly inefficient, but does the job
-    keeping = retrieve_cache_items(tags, union)
     global _cache
-    _cache = {k: v for k, v in _cache.items() if v in keeping}
+    _cache = _filter_cache_items(condition)
diff --git a/python/dune/perftool/generation/loopy.py b/python/dune/perftool/generation/loopy.py
index c7af711a471a7f9daf1972bfe6de7b050174d090..d4098dec3945ee92639609b9408af807b8e7d2fd 100644
--- a/python/dune/perftool/generation/loopy.py
+++ b/python/dune/perftool/generation/loopy.py
@@ -6,21 +6,21 @@ from dune.perftool.generation import generator_factory
 import loopy
 import numpy
 
-iname = generator_factory(item_tags=("loopy", "iname"))
-expr_instruction = generator_factory(item_tags=("loopy", "instruction", "exprinstruction"), no_deco=True)
-temporary_variable = generator_factory(item_tags=("loopy", "temporary"), on_store=lambda n: loopy.TemporaryVariable(n, dtype=numpy.float64), no_deco=True)
-c_instruction = generator_factory(item_tags=("loopy", "instruction", "cinstruction"), no_deco=True)
-valuearg = generator_factory(item_tags=("loopy", "argument", "valuearg"), on_store=lambda n: loopy.ValueArg(n), no_deco=True)
+iname = generator_factory(item_tags=("loopy", "kernel", "iname"))
+expr_instruction = generator_factory(item_tags=("loopy", "kernel", "instruction", "exprinstruction"), no_deco=True)
+temporary_variable = generator_factory(item_tags=("loopy", "kernel", "temporary"), on_store=lambda n: loopy.TemporaryVariable(n, dtype=numpy.float64), no_deco=True)
+c_instruction = generator_factory(item_tags=("loopy", "kernel", "instruction", "cinstruction"), no_deco=True)
+valuearg = generator_factory(item_tags=("loopy", "kernel", "argument", "valuearg"), on_store=lambda n: loopy.ValueArg(n), no_deco=True)
 
 
-@generator_factory(item_tags=("loopy", "argument", "globalarg"))
+@generator_factory(item_tags=("loopy", "kernel", "argument", "globalarg"))
 def globalarg(name, shape=loopy.auto):
     if isinstance(shape, str):
         shape = (shape,)
     return loopy.GlobalArg(name, numpy.float64, shape)
 
 
-@generator_factory(item_tags=("loopy", "domain"))
+@generator_factory(item_tags=("loopy", "kernel", "domain"))
 def domain(iname, shape):
     valuearg(shape)
     return "{{ [{0}] : 0<={0}<{1} }}".format(iname, shape)
diff --git a/python/dune/perftool/pdelab/localoperator.py b/python/dune/perftool/pdelab/localoperator.py
index 618c4ef87f362be733f5bebe07979c21d797e15b..e844820ef0183d1e0f4875d7eca517efd13f9a3a 100644
--- a/python/dune/perftool/pdelab/localoperator.py
+++ b/python/dune/perftool/pdelab/localoperator.py
@@ -125,10 +125,10 @@ class AssemblyMethod(ClassMember):
 def cgen_class_from_cache(tag, members=[]):
     from dune.perftool.generation import retrieve_cache_items
 
-    base_classes = [bc for bc in retrieve_cache_items(tags=(tag, "baseclass"), union=False)]
-    constructor_params = [bc for bc in retrieve_cache_items(tags=(tag, "constructor_param"), union=False)]
-    il = [i for i in retrieve_cache_items(tags=(tag, "initializer"), union=False)]
-    pm = [m for m in retrieve_cache_items(tags=(tag, "member"), union=False)]
+    base_classes = [bc for bc in retrieve_cache_items('{} and baseclass'.format(tag))]
+    constructor_params = [bc for bc in retrieve_cache_items('{} and constructor_param'.format(tag))]
+    il = [i for i in retrieve_cache_items('{} and initializer'.format(tag))]
+    pm = [m for m in retrieve_cache_items('{} and member'.format(tag))]
 
     from dune.perftool.cgen.clazz import Constructor
     constructor = Constructor(arg_decls=constructor_params, clsname=localoperator_type(), initializer_list=il)
@@ -143,8 +143,8 @@ def generate_localoperator_kernels(form):
     assert len(form.integrals()) == len(set(i.integral_type() for i in form.integrals()))
 
     # Reset the generation cache
-    from dune.perftool.generation import delete_cache
-    delete_cache()
+    from dune.perftool.generation import delete_cache_items
+    delete_cache_items()
 
     # Manage includes and base classes that we always need
     include_file('dune/pdelab/gridfunctionspace/gridfunctionspaceutilities.hh', filetag="operatorfile")