From 4f25d438add8a42bf23f7aaa37c5c1394074fd99 Mon Sep 17 00:00:00 2001
From: Dominic Kempf <dominic.kempf@iwr.uni-heidelberg.de>
Date: Fri, 28 Sep 2018 14:46:26 +0200
Subject: [PATCH] Introduce an asynchronous minimization function

---
 python/dune/perftool/sumfact/vectorization.py | 36 ++++++++++++++++---
 1 file changed, 32 insertions(+), 4 deletions(-)

diff --git a/python/dune/perftool/sumfact/vectorization.py b/python/dune/perftool/sumfact/vectorization.py
index 58df262f..0b3c068e 100644
--- a/python/dune/perftool/sumfact/vectorization.py
+++ b/python/dune/perftool/sumfact/vectorization.py
@@ -30,6 +30,7 @@ import itertools as it
 import loopy as lp
 import numpy as np
 import math
+import sys
 
 
 @generator_factory(item_tags=("vecinfo", "dryrundata"), cache_key_generator=lambda o, n: o)
@@ -160,6 +161,33 @@ def stringify_vectorization_strategy(strategy):
     return result
 
 
+def minimize(iterable, key=lambda x: x):
+    """ A minimization function that is capable of asynchronous
+    evaluation of the iterable if the python version supports it.
+    """
+    version = sys.version_info
+    if version.major == 3 and version.minor > 5:
+        import asyncio
+        from concurrent.futures import ThreadPoolExecutor
+
+        loop = asyncio.get_event_loop()
+        executor = ThreadPoolExecutor(max_workers=1)
+
+        @asyncio.coroutine
+        def key_coro(i):
+            return loop.run_in_executor(executor, key, i)
+
+        tasks = {}
+        for i in iterable:
+            tasks[i] = asyncio.async(key_coro(i), loop=loop)
+
+        loop.run_until_complete(asyncio.gather(*tasks.values()))
+
+        return min(tasks.items(), key=lambda t: t[1].result())[0]
+    else:
+        return min(iterable, key=key)
+
+
 def short_stringify_vectorization_strategy(strategy):
     """ A short string decribing the vectorization strategy. This is used
     in costmodel validation plots to describe what a data point does
@@ -272,7 +300,7 @@ def level1_optimal_vectorization_strategy(sumfacts, width):
         # Print the achieved cost and the target cost on the screen
         set_form_option("vectorization_strategy", "model")
         target = float(get_form_option("vectorization_target"))
-        qp = min(optimal_strategies, key=lambda qp: abs(strategy_cost((qp, optimal_strategies[qp])) - target))
+        qp = minimize(optimal_strategies, key=lambda qp: abs(strategy_cost((qp, optimal_strategies[qp])) - target))
         cost = strategy_cost((qp, optimal_strategies[qp]))
 
         print("The target cost was:   {}".format(target))
@@ -300,7 +328,7 @@ def level1_optimal_vectorization_strategy(sumfacts, width):
         with open("mapping.csv", 'a') as f:
             f.write(" ".join((identifier, str(cost), short_stringify_vectorization_strategy((qp, optimal_strategies[qp])))) + "\n")
     else:
-        qp = min(optimal_strategies, key=lambda qp: strategy_cost((qp, optimal_strategies[qp])))
+        qp = minimize(optimal_strategies, key=lambda qp: strategy_cost((qp, optimal_strategies[qp])))
 
     return qp, optimal_strategies[qp]
 
@@ -316,8 +344,8 @@ def level2_optimal_vectorization_strategy(sumfacts, width, qp):
         key_sumfacts = frozenset(sf for sf in sumfacts if sf.parallel_key == key)
 
         # Minimize over all the opportunities for the subset given by the current key
-        key_strategy = min(level2_optimal_vectorization_strategy_generator(key_sumfacts, width, qp),
-                           key=fixedqp_strategy_costfunction(qp))
+        key_strategy = minimize(level2_optimal_vectorization_strategy_generator(key_sumfacts, width, qp),
+                                key=fixedqp_strategy_costfunction(qp))
         sfdict = add_to_frozendict(sfdict, key_strategy)
 
     return sfdict
-- 
GitLab