diff --git a/cmake/scripts/distribute_testing.py b/cmake/scripts/distribute_testing.py
index 89d44285ce0ea42f11703baead5ad6284d8e8ae4..e50d678d63674678bf838c1cdf88a81ded15527f 100644
--- a/cmake/scripts/distribute_testing.py
+++ b/cmake/scripts/distribute_testing.py
@@ -8,10 +8,10 @@ import subprocess
 import time
 from contextlib import contextmanager
 import binpacking
-from multiprocessing import Pool
+from multiprocessing import Pool, cpu_count
 
 
-MAXTIME = 15*60
+MAXTIME = 4*60
 pickle_file = 'totals.pickle'
 
 
@@ -28,9 +28,9 @@ def elapsed_timer():
 def _compile(binary):
     with elapsed_timer() as timer:
         try:
-            subprocess.check_call(['ninja', '-j1', binary])
+            _ = subprocess.check_output(['ninja', '-j1', binary], universal_newlines=True, stderr=subprocess.STDOUT)
         except subprocess.CalledProcessError as cpe:
-            if not 'Timeout' in cpe:
+            if 'Timeout' not in cpe.output:
                 raise cpe
             print('Timeout in compile {}'.format(binary))
         return timer()
@@ -39,54 +39,80 @@ def _compile(binary):
 def _run_tests(tpl):
     binary, teststrings = tpl
     testtimes = 0
-    for test in teststrings.split('/'):
+    for test in teststrings.split(';'):
         with elapsed_timer() as timer:
             try:
-                out = subprocess.check_output(['ctest', '-j1', '-R', test])
+                _ = subprocess.check_output(['ctest', '-j1', '-N', '-R', test], universal_newlines=True,
+                                            stderr=subprocess.STDOUT)
             except subprocess.CalledProcessError as cpe:
-                if not 'Timeout' in cpe:
+                if 'Timeout' not in cpe.output:
                     raise cpe
+                # be pessimistic and double the timeout value as time for this run
+                testtimes += timer()
                 print('Timeout in {} from {}'.format(test, binary))
             testtimes += timer()
-        return testtimes
-
-
-def redo_timings(builddir, binaries, testnames, processes):
+    return testtimes
+
+
+def _redo(processes, keys, *args):
+    try:
+        with Pool(processes=processes) as pool:
+            result = pool.map(*args)
+        return {k: v for k,v in zip(keys, result)}
+    except subprocess.CalledProcessError as cpe:
+        print('*'*79)
+        print(cpe.stdout)
+        print(cpe.stderr)
+        print('*' * 79)
+        raise cpe
+
+def do_timings(builddir, pickledir, binaries, testnames, processes):
     os.chdir(builddir)
     testlimit = -1
-    binaries = binaries[:testlimit]
-    testnames = testnames[:testlimit]
 
-    with Pool(processes=processes) as pool:
-        compiles = pool.map(_compile, binaries)
-    with Pool(processes=processes) as pool:
-        testruns = pool.map(_run_tests, zip(binaries, testnames))
-
-    totals = [a+b for a,b in zip(compiles, testruns)]
+    binaries = binaries[:testlimit]
+    compiles_fn = os.path.join(pickledir, 'compiles_' + pickle_file)
+    try:
+        compiles = pickle.load(open(compiles_fn, 'rb'))
+        if set(compiles.keys()) != set(binaries):
+            print('redoing compiles due to mismatched binaries')
+            compiles = _redo(processes, binaries, _compile, binaries)
+    except FileNotFoundError:
+        print('redoing compiles due to missing pickle')
+        compiles = _redo(processes, binaries, _compile, binaries)
+    pickle.dump(compiles, open(compiles_fn, 'wb'))
 
+    testnames = testnames[:testlimit]
+    testruns_fn = os.path.join(pickledir, 'testruns_' + pickle_file)
+    try:
+        loaded_testnames, testruns = pickle.load(open(testruns_fn, 'rb'))
+        if set(compiles.keys()) != set(binaries) or loaded_testnames != testnames:
+            print('redoing tests due to mismatched binaries/testnames')
+            testruns = _redo(processes, binaries, _run_tests, zip(binaries, testnames))
+    except FileNotFoundError:
+        print('redoing tests due to missing pickle')
+        testruns = _redo(processes, binaries, _run_tests, zip(binaries, testnames))
+    pickle.dump((testnames, testruns), open(testruns_fn, 'wb'))
+
+    totals = {n: compiles[n]+testruns[n] for n in binaries}
+    pickle.dump(totals, open(os.path.join(pickledir, pickle_file), 'wb'))
     print('totals')
     pprint(totals)
-    pickle.dump(totals, open(os.path.join(builddir, pickle_file), 'wb'))
-    pickle.dump(compiles, open(os.path.join(builddir, 'compile_'+pickle_file), 'wb'))
-    pickle.dump(testruns, open(os.path.join(builddir, 'tests_' + pickle_file), 'wb'))
-    return {b: t for b, t in zip(binaries, totals)}
+    return totals
 
 
 # list comes with a leading empty entry
 testnames = sys.argv[4].split('/')[1:]
 builddir = sys.argv[1]
+pickledir = sys.argv[2]
 binaries = sys.argv[3].split(';')
-processes = 4
-
-try:
-    totals = pickle.load(open(os.path.join(builddir, pickle_file), 'rb'))
-    if totals.keys() != binaries:
-        totals = redo_timings(builddir, binaries, testnames, processes)
-except FileNotFoundError:
-    totals = redo_timings(builddir, binaries, testnames, processes)
+processes = cpu_count()
 
+totals = do_timings(builddir, pickledir, binaries, testnames, processes)
 builder_count = sys.argv[2]
 
 b = list(totals.keys())
-bins = binpacking.to_constant_volume(b,MAXTIME)
-pprint(bins)
\ No newline at end of file
+bins = binpacking.to_constant_volume(totals, MAXTIME)
+for idx, bin in enumerate(bins):
+    pprint('Bin {} vol: {}'.format(idx, sum(bin.values())))
+    pprint(bin)
\ No newline at end of file
diff --git a/dune/gdt/test/CMakeLists.txt b/dune/gdt/test/CMakeLists.txt
index 4d8baa8478255c726737bb5006bf6f6337fa317a..4d4c1f767c493f7cb90205b62f2256f28f0b2a4f 100644
--- a/dune/gdt/test/CMakeLists.txt
+++ b/dune/gdt/test/CMakeLists.txt
@@ -22,7 +22,7 @@ endforeach (target ${dxt_test_binaries})
 # message(STATUS "LL ${all_sorted_testnames}")
 
 add_custom_target(refresh_test_timings python3 ${CMAKE_SOURCE_DIR}/cmake/scripts/distribute_testing.py
-    "${CMAKE_BINARY_DIR}" ${DXT_TRAVIS_BUILDER} "${dxt_test_binaries}" "${all_sorted_testnames}" VERBATIM)
+    "${CMAKE_BINARY_DIR}" "${CMAKE_SOURCE_DIR}/cmake/scripts/" "${dxt_test_binaries}" "${all_sorted_testnames}" VERBATIM)
 
 # link spe10 data file if present
 if (NOT ${SPE10MODEL1DATA} STREQUAL "SPE10MODEL1DATA-NOTFOUND")