From 475a84618e00c72bc49ea8ba96d8a4f159215c4a Mon Sep 17 00:00:00 2001 From: palkeo Date: Mon, 8 Jun 2020 16:50:35 +1200 Subject: [PATCH 1/3] Don't shuffle each batch, instead reverse them half the time. I consistently see batch shuffling taking 1% CPU on a real-world application, and this is a simple fix to make this overhead disappear. Suggested by @njsmith. --- trio/_core/_run.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/trio/_core/_run.py b/trio/_core/_run.py index a10d6cb57f..56c617372f 100644 --- a/trio/_core/_run.py +++ b/trio/_core/_run.py @@ -2084,7 +2084,10 @@ def unrolled_run(runner, async_fn, args, host_uses_signal_set_wakeup_fd=False): # seeded for tests. batch.sort(key=lambda t: t._counter) runner.runq.clear() - _r.shuffle(batch) + # 50% chance of reversing the batch, this way each task + # can appear before/after any other task. + if _r.random() < 0.5: + batch = batch[::-1] while batch: task = batch.pop() GLOBAL_RUN_CONTEXT.task = task From c8128f3c2f07c71ad2e5add401a3f6efb64a0a23 Mon Sep 17 00:00:00 2001 From: palkeo Date: Mon, 8 Jun 2020 17:20:34 +1200 Subject: [PATCH 2/3] Make test_scheduler_determinist much less likely to fail. The scheduler is still non-deterministic, but exhibit much less variety of behavior, making the test a lot more likely to fail. So we increase the size of the traces. --- trio/tests/test_scheduler_determinism.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trio/tests/test_scheduler_determinism.py b/trio/tests/test_scheduler_determinism.py index 67b2447f0a..e2d3167e45 100644 --- a/trio/tests/test_scheduler_determinism.py +++ b/trio/tests/test_scheduler_determinism.py @@ -6,7 +6,7 @@ async def scheduler_trace(): trace = [] async def tracer(name): - for i in range(10): + for i in range(50): trace.append((name, i)) await trio.sleep(0) From a67aaf6db0b6925c0afd2ae2d80a9ffefd61a66f Mon Sep 17 00:00:00 2001 From: palkeo Date: Mon, 8 Jun 2020 23:29:53 +1200 Subject: [PATCH 3/3] Keep the old shuffle() behavior on hypothesis & reverse in-place. --- trio/_core/_run.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/trio/_core/_run.py b/trio/_core/_run.py index 56c617372f..465aebe6f5 100644 --- a/trio/_core/_run.py +++ b/trio/_core/_run.py @@ -2076,6 +2076,7 @@ def unrolled_run(runner, async_fn, args, host_uses_signal_set_wakeup_fd=False): # tie-breaker and the non-deterministic ordering of # task._notify_queues.) batch = list(runner.runq) + runner.runq.clear() if _ALLOW_DETERMINISTIC_SCHEDULING: # We're running under Hypothesis, and pytest-trio has patched # this in to make the scheduler deterministic and avoid flaky @@ -2083,11 +2084,12 @@ def unrolled_run(runner, async_fn, args, host_uses_signal_set_wakeup_fd=False): # operation, since we'll shuffle the list and _r is only # seeded for tests. batch.sort(key=lambda t: t._counter) - runner.runq.clear() - # 50% chance of reversing the batch, this way each task - # can appear before/after any other task. - if _r.random() < 0.5: - batch = batch[::-1] + _r.shuffle(batch) + else: + # 50% chance of reversing the batch, this way each task + # can appear before/after any other task. + if _r.random() < 0.5: + batch.reverse() while batch: task = batch.pop() GLOBAL_RUN_CONTEXT.task = task