From 218469c25852672b0199d20a2a3a626dd10991f3 Mon Sep 17 00:00:00 2001
From: Dominic Kempf <dominic.kempf@iwr.uni-heidelberg.de>
Date: Thu, 4 Oct 2018 13:16:38 +0200
Subject: [PATCH] Implement proper file locking to allow multiple processes to
 autotune the same stuff

---
 python/dune/perftool/sumfact/autotune.py | 46 ++++++++++++------------
 python/setup.py                          |  2 +-
 2 files changed, 25 insertions(+), 23 deletions(-)

diff --git a/python/dune/perftool/sumfact/autotune.py b/python/dune/perftool/sumfact/autotune.py
index 771b792a..2cdd2e08 100644
--- a/python/dune/perftool/sumfact/autotune.py
+++ b/python/dune/perftool/sumfact/autotune.py
@@ -11,6 +11,7 @@ from pytools import product
 import os
 import re
 import subprocess
+import filelock
 
 
 def get_cmake_cache_entry(entry):
@@ -193,28 +194,29 @@ def autotune_realization(sf):
     name = os.path.join(dir, "autotune_sumfact_{}".format(sf.function_name))
     filename = os.path.join(dir, "{}.cc".format(basename))
     logname = os.path.join(dir, "{}.log".format(basename))
-
-    # If the log file already exists, we can reuse the benchmark results
-    # and do not need to rerun it.
-    if not os.path.isfile(logname):
-        # Generate and compile a benchmark program
-        with cache_restoring():
-            generate_standalone_code(sf, filename, logname)
-
-        ret = subprocess.call(compiler_invocation(name, filename))
-        assert ret == 0
-
-        # Check whether the user specified an execution wrapper
-        call = []
-        wrapper = get_cmake_cache_entry("DUNE_PERFTOOL_BENCHMARK_WRAPPER")
-        if wrapper:
-            call.append(wrapper)
-
-        # Run the benchmark program
-        call.append(name)
-        devnull = open(os.devnull, 'w')
-        ret = subprocess.call(call, stdout=devnull, stderr=subprocess.STDOUT)
-        assert ret == 0
+    lock = "{}.lock".format(name)
+
+    # Generate and compile a benchmark program
+    with cache_restoring():
+        with filelock.FileLock(lock):
+            if not os.path.isfile(logname):
+                if os.path.isfile(filename):
+                    generate_standalone_code(sf, filename, logname)
+
+                ret = subprocess.call(compiler_invocation(name, filename))
+                assert ret == 0
+
+                # Check whether the user specified an execution wrapper
+                call = []
+                wrapper = get_cmake_cache_entry("DUNE_PERFTOOL_BENCHMARK_WRAPPER")
+                if wrapper:
+                    call.append(wrapper)
+
+                # Run the benchmark program
+                call.append(name)
+                devnull = open(os.devnull, 'w')
+                ret = subprocess.call(call, stdout=devnull, stderr=subprocess.STDOUT)
+                assert ret == 0
 
     # Extract the result form the log file
     return float(next(iter(open(logname, "r")))) / 1000000
diff --git a/python/setup.py b/python/setup.py
index 476a9f6f..e4517d2f 100644
--- a/python/setup.py
+++ b/python/setup.py
@@ -41,7 +41,7 @@ setup(name='dune.perftool',
                 'dune.perftool.ufl',
                 'dune.perftool.ufl.transformations',
                 ],
-      install_requires=['dune.testtools', 'sympy', 'frozendict', 'pytest', 'pytest-pep8'],
+      install_requires=['dune.testtools', 'sympy', 'frozendict', 'pytest', 'pytest-pep8', 'filelock'],
       cmdclass={'test': PyTest},
       entry_points = {
         "console_scripts": [
-- 
GitLab