From 313770879be7a3759b5f5f2e9b4961d2cc09a783 Mon Sep 17 00:00:00 2001 From: maurycy <5383+maurycy@users.noreply.github.com> Date: Wed, 3 Dec 2025 01:53:48 +0100 Subject: [PATCH 1/2] --shuffle --shuffle-seed --- pyperformance/cli.py | 12 +++++++++- pyperformance/run.py | 16 ++++++++++++- pyperformance/tests/test_run_order.py | 34 +++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 pyperformance/tests/test_run_order.py diff --git a/pyperformance/cli.py b/pyperformance/cli.py index cac15c33..71cbc268 100644 --- a/pyperformance/cli.py +++ b/pyperformance/cli.py @@ -4,7 +4,6 @@ import sys from pyperf import _hooks - from pyperformance import __version__, _utils, is_dev, is_installed from pyperformance.commands import ( cmd_compare, @@ -148,6 +147,17 @@ def parse_args(): default=None, help="number of skipped values per run used to warmup the benchmark", ) + cmd.add_argument( + "--shuffle", + action="store_true", + help="Run selected benchmarks in random order", + ) + cmd.add_argument( + "--shuffle-seed", + type=int, + default=None, + help="Seed used when shuffling benchmarks (implies --shuffle)", + ) filter_opts(cmd) # show diff --git a/pyperformance/run.py b/pyperformance/run.py index 24c2c6d6..f1c37bfc 100644 --- a/pyperformance/run.py +++ b/pyperformance/run.py @@ -1,6 +1,7 @@ import hashlib import json import os +import random import sys import time import traceback @@ -67,13 +68,26 @@ def get_loops_from_file(filename): return loops +def order_benchmarks(benchmarks, *, shuffle=False, shuffle_seed=None): + seq = list(benchmarks) + if shuffle or shuffle_seed is not None: + rng = random.Random(shuffle_seed) + rng.shuffle(seq) + return seq + return sorted(seq) + + def run_benchmarks(should_run, python, options): if options.same_loops is not None: loops = get_loops_from_file(options.same_loops) else: loops = {} - to_run = sorted(should_run) + to_run = order_benchmarks( + should_run, + shuffle=getattr(options, "shuffle", False), + shuffle_seed=getattr(options, "shuffle_seed", None), + ) info = _pythoninfo.get_info(python) runid = get_run_id(info) diff --git a/pyperformance/tests/test_run_order.py b/pyperformance/tests/test_run_order.py new file mode 100644 index 00000000..6774ab9c --- /dev/null +++ b/pyperformance/tests/test_run_order.py @@ -0,0 +1,34 @@ +import unittest + +from pyperformance.run import order_benchmarks + + +class OrderBenchmarksTests(unittest.TestCase): + def setUp(self): + self.benchmarks = ["b", "a", "c"] + + def test_default_is_sorted(self): + ordered = order_benchmarks(self.benchmarks) + self.assertEqual(ordered, ["a", "b", "c"]) + + def test_shuffle_seed_implies_shuffle(self): + ordered = order_benchmarks(self.benchmarks, shuffle_seed=123) + self.assertEqual(ordered, ["c", "a", "b"]) + + def test_shuffle_flag_without_seed_changes_order(self): + sorted_expected = sorted(self.benchmarks) + + shuffled_orders = [] + for seed in range(10): + ordered = order_benchmarks(self.benchmarks, shuffle=True, shuffle_seed=seed) + self.assertCountEqual(ordered, self.benchmarks) + shuffled_orders.append(tuple(ordered)) + + self.assertTrue( + any(order != tuple(sorted_expected) for order in shuffled_orders), + "Shuffle should change order for at least one seed in range(10)", + ) + + +if __name__ == "__main__": + unittest.main() From 6b1298b9389731b67d9721ce2cc90a668306cd67 Mon Sep 17 00:00:00 2001 From: maurycy <5383+maurycy@users.noreply.github.com> Date: Fri, 5 Dec 2025 16:46:29 +0100 Subject: [PATCH 2/2] pre-commit run --all-files --- pyperformance/cli.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pyperformance/cli.py b/pyperformance/cli.py index 71cbc268..d011b57f 100644 --- a/pyperformance/cli.py +++ b/pyperformance/cli.py @@ -4,6 +4,7 @@ import sys from pyperf import _hooks + from pyperformance import __version__, _utils, is_dev, is_installed from pyperformance.commands import ( cmd_compare,