diff options
author | Ned Batchelder <ned@nedbatchelder.com> | 2022-06-05 08:24:02 -0400 |
---|---|---|
committer | Ned Batchelder <ned@nedbatchelder.com> | 2022-06-05 08:24:02 -0400 |
commit | d9fd5e4c2d02cdc12c836ed0bb27cad9f9837aef (patch) | |
tree | 8db0ee99b7a52f9b2787210c3b7c7e1b26595bd3 /lab | |
parent | f84573ddb6599273e76b7a5d4040bc5e14e4890d (diff) | |
download | python-coveragepy-git-d9fd5e4c2d02cdc12c836ed0bb27cad9f9837aef.tar.gz |
test(benchmark): more refactoring
Diffstat (limited to 'lab')
-rw-r--r-- | lab/benchmark.py | 180 |
1 files changed, 102 insertions, 78 deletions
diff --git a/lab/benchmark.py b/lab/benchmark.py index 05c95af6..8bde9bf4 100644 --- a/lab/benchmark.py +++ b/lab/benchmark.py @@ -159,6 +159,7 @@ class ToxProject(ProjectToTest): return self.run_tox(env, env.pyver.toxenv, "--skip-pkg-install") def run_with_coverage(self, env, pip_args, cov_options): + assert not cov_options, f"ToxProject.run_with_coverage can't take cov_options={cov_options!r}" self.run_tox(env, env.pyver.toxenv, "--notest") env.shell.run_command( f".tox/{env.pyver.toxenv}/bin/python -m pip install {pip_args}" @@ -286,6 +287,16 @@ class AdHocPython(PyVersion): self.slug = slug self.toxenv = None +@dataclasses.dataclass +class Coverage: + """A version of coverage.py to use, maybe None.""" + # Short word for messages, directories, etc + slug: str + # Arguments for "pip install ..." + pip_args: Optional[str] = None + # Tweaks to the .coveragerc file + options: Optional[str] = None + @dataclasses.dataclass class Env: @@ -296,67 +307,78 @@ class Env: shell: ShellSession -def run_experiment( - py_versions: List[PyVersion], - cov_versions: List[Tuple[str, Optional[str], Optional[str]]], - projects: List[ProjectToTest], - num_runs: int = 3, - rows: Optional[List[str]] = None, - column: Optional[str] = None, - ratios: Iterable[Tuple[str, str, str]] = (), -): - """Run test suites under different conditions.""" - - result_data: Dict[Tuple[str, str, str], float] = {} - results = [] - for proj in projects: - print(f"Testing with {proj.slug}") - with ShellSession(f"output_{proj.slug}.log") as shell: - proj.get_source(shell) - - for pyver in py_versions: - print(f"Making venv for {proj.slug} {pyver.slug}") - venv_dir = f"venv_{proj.slug}_{pyver.slug}" - shell.run_command(f"{pyver.command} -m venv {venv_dir}") - python = Path.cwd() / f"{venv_dir}/bin/python" - shell.run_command(f"{python} -V") - env = Env(pyver, python, shell) - - with change_dir(Path(proj.slug)): - print(f"Prepping for {proj.slug} {pyver.slug}") - proj.prep_environment(env) - for cov_slug, cov_pip, cov_options in cov_versions: - durations = [] - for run_num in range(num_runs): - print( - f"Running tests, cov={cov_slug}, {run_num+1} of {num_runs}" +ResultData = Dict[Tuple[str, str, str], float] + +class Experiment: + """A particular time experiment to run.""" + + def __init__( + self, + py_versions: List[PyVersion], + cov_versions: List[Coverage], + projects: List[ProjectToTest], + ): + self.py_versions = py_versions + self.cov_versions = cov_versions + self.projects = projects + self.result_data: ResultData = {} + + def run(self, num_runs: int = 3) -> None: + results = [] + for proj in self.projects: + print(f"Testing with {proj.slug}") + with ShellSession(f"output_{proj.slug}.log") as shell: + proj.get_source(shell) + + for pyver in self.py_versions: + print(f"Making venv for {proj.slug} {pyver.slug}") + venv_dir = f"venv_{proj.slug}_{pyver.slug}" + shell.run_command(f"{pyver.command} -m venv {venv_dir}") + python = Path.cwd() / f"{venv_dir}/bin/python" + shell.run_command(f"{python} -V") + env = Env(pyver, python, shell) + + with change_dir(Path(proj.slug)): + print(f"Prepping for {proj.slug} {pyver.slug}") + proj.prep_environment(env) + for cov_ver in self.cov_versions: + durations = [] + for run_num in range(num_runs): + print( + f"Running tests, cov={cov_ver.slug}, {run_num+1} of {num_runs}" + ) + if cov_ver.pip_args is None: + dur = proj.run_no_coverage(env) + else: + dur = proj.run_with_coverage( + env, cov_ver.pip_args, cov_ver.options, + ) + print(f"Tests took {dur:.3f}s") + durations.append(dur) + med = statistics.median(durations) + result = ( + f"Median for {proj.slug}, {pyver.slug}, " + + f"cov={cov_ver.slug}: {med:.3f}s" ) - if cov_pip is None: - dur = proj.run_no_coverage(env) - else: - dur = proj.run_with_coverage(env, cov_pip, cov_options) - print(f"Tests took {dur:.3f}s") - durations.append(dur) - med = statistics.median(durations) - result = ( - f"Median for {proj.slug}, {pyver.slug}, " - + f"cov={cov_slug}: {med:.3f}s" - ) - print(f"## {result}") - results.append(result) - result_key = (proj.slug, pyver.slug, cov_slug) - result_data[result_key] = med - - print("# Results") - for result in results: - print(result) - - if rows: - assert column + print(f"## {result}") + results.append(result) + result_key = (proj.slug, pyver.slug, cov_ver.slug) + self.result_data[result_key] = med + + print("# Results") + for result in results: + print(result) + + def show_results( + self, + rows: List[str], + column: str, + ratios: Iterable[Tuple[str, str, str]] = (), + ) -> None: dimensions = { - "cov": [cov_slug for cov_slug, _, _ in cov_versions], - "pyver": [pyver.slug for pyver in py_versions], - "proj": [proj.slug for proj in projects], + "cov": [cov_ver.slug for cov_ver in self.cov_versions], + "pyver": [pyver.slug for pyver in self.py_versions], + "proj": [proj.slug for proj in self.projects], } table_axes = [dimensions[rowname] for rowname in rows] @@ -381,12 +403,12 @@ def run_experiment( for col in dimensions[column]: key = (*tup, col) key = tuple(key[i] for i in remap) - result_time = result_data[key] + result_time = self.result_data[key] # type: ignore row.append(f"{result_time:.3f} s") col_data[col] = result_time for _, num, denom in ratios: ratio = col_data[num] / col_data[denom] - row.append(f"{ratio:.3f}") + row.append(f"{int(ratio * 100):d}%") print(as_table_row(row)) @@ -399,16 +421,16 @@ rmrf(PERF_DIR) with change_dir(PERF_DIR): if 1: - run_experiment( + exp = Experiment( py_versions=[ Python(3, 10), Python(3, 11), - AdHocPython("/usr/local/cpython", "gh93493"), + #AdHocPython("/usr/local/cpython", "gh93493"), ], cov_versions=[ - ("none", None, None), - ("6.4.1", "coverage==6.4.1", ""), - # ( + Coverage("none"), + Coverage("6.4.1", "coverage==6.4.1"), + # Coverage( # "tip timid", # "git+https://github.com/nedbat/coveragepy.git@master", # "timid=True", @@ -421,24 +443,26 @@ with change_dir(PERF_DIR): SlipcoverBenchmark("bm_sudoku.py"), SlipcoverBenchmark("bm_spectral_norm.py"), ], - num_runs=3, + ) + exp.run(num_runs=3) + exp.show_results( rows=["cov", "proj"], column="pyver", ratios=[ ("3.11 vs 3.10", "python3.11", "python3.10"), - ("fix vs 3.10", "gh93493", "python3.10"), + #("fix vs 3.10", "gh93493", "python3.10"), ], ) if 0: - run_experiment( + exp = Experiment( py_versions=[ PyPy(3, 9), ], cov_versions=[ - ("none", None, None), - ("6.4", "coverage==6.4", ""), - ( + Coverage("none", None, None), + Coverage("6.4", "coverage==6.4", ""), + Coverage( "PR 1381", "git+https://github.com/cfbolz/coveragepy.git@f_trace_lines", "", @@ -447,21 +471,21 @@ with change_dir(PERF_DIR): projects=[ ProjectPytestHtml(), ], - num_runs=3, ) + exp.run(num_runs=3) if 0: - run_experiment( + exp = Experiment( py_versions=[ PyPy(3, 9), ], cov_versions=[ - ("none", None, None), - ("6.4", "coverage", ""), - ("tip", "git+https://github.com/nedbat/coveragepy.git@master", ""), + Coverage("none", None, None), + Coverage("6.4", "coverage", ""), + Coverage("tip", "git+https://github.com/nedbat/coveragepy.git@master", ""), ], projects=[ AdHocProject("/src/bugs/bug1339/bug1339.py"), ], - num_runs=7, ) + exp.run(num_runs=7) |