Skip to content

Commit 54c5c48

Browse files
committed
Merge branch 'fix/timing' into 'master'
save execution time on futures inside runners See merge request qt/adaptive!130
2 parents 99c80fe + 3cc16fd commit 54c5c48

File tree

3 files changed

+47
-26
lines changed

3 files changed

+47
-26
lines changed

adaptive/runner.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
import abc
1212

1313
from .notebook_integration import live_plot, live_info, in_ipynb
14-
from .utils import timed
1514

1615
try:
1716
import ipyparallel
@@ -105,8 +104,7 @@ class BaseRunner(metaclass=abc.ABCMeta):
105104
Methods
106105
-------
107106
overhead : callable
108-
The overhead in percent of using Adaptive. This includes the
109-
overhead of the executor. Essentially, this is
107+
The overhead in percent of using Adaptive. Essentially, this is
110108
``100 * (1 - total_elapsed_function_time / self.elapsed_time())``.
111109
112110
"""
@@ -130,8 +128,7 @@ def __init__(self, learner, goal, *,
130128
self.learner = learner
131129
self.log = [] if log else None
132130

133-
# Function timing
134-
self.function = functools.partial(timed, self.learner.function)
131+
# Timing
135132
self.start_time = time.time()
136133
self.end_time = None
137134
self._elapsed_function_time = 0
@@ -190,7 +187,8 @@ def _process_futures(self, done_futs):
190187
for fut in done_futs:
191188
x = self.pending_points.pop(fut)
192189
try:
193-
y, t = fut.result()
190+
y = fut.result()
191+
t = time.time() - fut.start_time # total execution time
194192
except Exception as e:
195193
self.tracebacks[x] = traceback.format_exc()
196194
self.to_retry[x] = self.to_retry.get(x, 0) + 1
@@ -218,7 +216,9 @@ def _get_futures(self):
218216
points, _ = self._ask(n_new_tasks)
219217

220218
for x in points:
221-
self.pending_points[self._submit(x)] = x
219+
fut = self._submit(x)
220+
fut.start_time = time.time() # so we can measure execution time
221+
self.pending_points[fut] = x
222222

223223
# Collect and results and add them to the learner
224224
futures = list(self.pending_points.keys())
@@ -332,7 +332,7 @@ def __init__(self, learner, goal, *,
332332
self._run()
333333

334334
def _submit(self, x):
335-
return self.executor.submit(self.function, x)
335+
return self.executor.submit(self.learner.function, x)
336336

337337
def _run(self):
338338
first_completed = concurrent.FIRST_COMPLETED
@@ -471,9 +471,9 @@ def goal(_):
471471
def _submit(self, x):
472472
ioloop = self.ioloop
473473
if inspect.iscoroutinefunction(self.learner.function):
474-
return ioloop.create_task(self.function(x))
474+
return ioloop.create_task(self.learner.function(x))
475475
else:
476-
return ioloop.run_in_executor(self.executor, self.function, x)
476+
return ioloop.run_in_executor(self.executor, self.learner.function, x)
477477

478478
def status(self):
479479
"""Return the runner status as a string.

adaptive/tests/test_runner.py

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,39 @@
22

33
import asyncio
44

5-
from ..learner import Learner2D
5+
import pytest
6+
7+
from ..learner import Learner1D, Learner2D
68
from ..runner import simple, BlockingRunner, AsyncRunner, SequentialExecutor
79

810

9-
def test_nonconforming_output():
11+
def blocking_runner(learner, goal):
12+
BlockingRunner(learner, goal, executor=SequentialExecutor())
13+
14+
15+
def async_runner(learner, goal):
16+
runner = AsyncRunner(learner, goal, executor=SequentialExecutor())
17+
asyncio.get_event_loop().run_until_complete(runner.task)
18+
19+
20+
runners = [simple, blocking_runner, async_runner]
21+
22+
def trivial_goal(learner):
23+
return learner.npoints > 10
24+
25+
@pytest.mark.parametrize('runner', runners)
26+
def test_simple(runner):
27+
"""Test that the runners actually run."""
28+
29+
def f(x):
30+
return x
31+
learner = Learner1D(f, (-1, 1))
32+
runner(learner, lambda l: l.npoints > 10)
33+
assert len(learner.data) > 10
34+
35+
36+
@pytest.mark.parametrize('runner', runners)
37+
def test_nonconforming_output(runner):
1038
"""Test that using a runner works with a 2D learner, even when the
1139
learned function outputs a 1-vector. This tests against the regression
1240
flagged in https://gitlab.kwant-project.org/qt/adaptive/issues/58.
@@ -15,15 +43,14 @@ def test_nonconforming_output():
1543
def f(x):
1644
return [0]
1745

18-
def goal(l):
19-
return l.npoints > 10
46+
runner(Learner2D(f, [(-1, 1), (-1, 1)]), trivial_goal)
2047

21-
learner = Learner2D(f, [(-1, 1), (-1, 1)])
22-
simple(learner, goal)
2348

24-
learner = Learner2D(f, [(-1, 1), (-1, 1)])
25-
BlockingRunner(learner, goal, executor=SequentialExecutor())
49+
def test_aync_def_function():
2650

27-
learner = Learner2D(f, [(-1, 1), (-1, 1)])
28-
runner = AsyncRunner(learner, goal, executor=SequentialExecutor())
51+
async def f(x):
52+
return x
53+
54+
learner = Learner1D(f, (-1, 1))
55+
runner = AsyncRunner(learner, trivial_goal)
2956
asyncio.get_event_loop().run_until_complete(runner.task)

adaptive/utils.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,6 @@
88
import time
99

1010

11-
def timed(f, *args, **kwargs):
12-
t_start = time.time()
13-
result = f(*args, **kwargs)
14-
return result, time.time() - t_start
15-
16-
1711
def named_product(**items):
1812
names = items.keys()
1913
vals = items.values()

0 commit comments

Comments
 (0)