diff --git a/bin/calculate_floprate.py b/bin/calculate_floprate.py
index d149d2b0b2b48ac62c55b4e1e9e91f64336320e4..89fe97419379ec48606c4a459efdfe338f74a34c 100755
--- a/bin/calculate_floprate.py
+++ b/bin/calculate_floprate.py
@@ -14,20 +14,13 @@ def join_csv_files():
                     out.write("{} {}".format(match.group(1), line))
 
 
-def parse_data():
+def calculate_floprate():
     frame = pandas.read_csv('timings.csv', header=None, names=('rank', 'exec', 'kernel', 'what', 'value'), delimiter=' ')
     time = frame[frame.what == "time"]
     ops = frame[frame.what != "time"]
 
-    timedata = time.groupby(('rank', 'exec', 'kernel'))['value'].min().to_frame().reset_index().groupby(('exec', 'kernel'))['value'].max()
-    opsdata = ops.groupby(('rank', 'exec', 'kernel'))['value'].max().to_frame().reset_index().groupby(('exec', 'kernel'))['value'].max()
-
-    return timedata, opsdata
-
-
-def calculate_floprate():
-    join_csv_files()
-    time, ops = parse_data()
+    time = time.groupby(('rank', 'exec', 'kernel'))['value'].min().to_frame().reset_index().groupby(('exec', 'kernel'))['value'].max()
+    ops = ops.groupby(('rank', 'exec', 'kernel'))['value'].max().to_frame().reset_index().groupby(('exec', 'kernel'))['value'].max()
 
     with open('floprates.csv', 'w') as out:
         for key in time.keys():
@@ -37,5 +30,21 @@ def calculate_floprate():
                 out.write(" ".join([exe, kernel, str((ops[opexe][kernel] / time[exe][kernel]) / 1e9)]) + "\n")
 
 
+def calculate_doftimes():
+    frame = pandas.read_csv('timings.csv', header=None, names=('rank', 'exec', 'kernel', 'what', 'value'), delimiter=' ')
+    dofs = frame[frame.what == "dofs"]
+    time = frame[frame.what == "time"]
+
+    dofs = dofs.groupby(('rank', 'exec', 'kernel'))['value'].max().to_frame().reset_index().groupby(('exec', 'kernel'))['value'].max()
+    time = time.groupby(('rank', 'exec', 'kernel'))['value'].min().to_frame().reset_index().groupby(('exec', 'kernel'))['value'].max()
+
+    with open('doftimes.csv', 'w') as out:
+        for key in time.keys():
+            exe, kernel = key
+            out.write(" ".join([exe, kernel, str(dofs[exe]["dofs"] / time[exe][kernel])]) + "\n")
+
+
 if __name__ == '__main__':
+    join_csv_files()
     calculate_floprate()
+    calculate_doftimes()
diff --git a/python/dune/perftool/pdelab/driver.py b/python/dune/perftool/pdelab/driver.py
index 6b98676ece9461573baad93bda2ceefaf7cbd7ca..524ce57967e4c4c42f94d08b30c433ba2aab40ed 100644
--- a/python/dune/perftool/pdelab/driver.py
+++ b/python/dune/perftool/pdelab/driver.py
@@ -1164,10 +1164,18 @@ def define_timing_stream(name):
             ]
 
 
+@preamble
+def dump_dof_numbers(stream):
+    exe = name_exec()
+    return "{} << {} << \" dofs dofs \" << {}.size() << std::endl;".format(stream,
+                                                                           exe,
+                                                                           name_gfs(_driver_data['form'].coefficients()[0].ufl_element()))
+
+
 def name_timing_stream():
-    define_exec()
     name = "timestream"
     define_timing_stream(name)
+    dump_dof_numbers(name)
     return name
 
 
@@ -1417,8 +1425,14 @@ def setup_timer():
 
 
 @preamble
-def define_exec():
-    return "char* exec = argv[0];"
+def define_exec(name):
+    return "char* {} = argv[0];".format(name)
+
+
+def name_exec():
+    name = "exec"
+    define_exec(name)
+    return name
 
 
 @preamble