diff --git a/doc/benchmark.conf.sample b/doc/benchmark.conf.sample index 97bc5985..8b2c72df 100644 --- a/doc/benchmark.conf.sample +++ b/doc/benchmark.conf.sample @@ -51,6 +51,9 @@ pgo = True # PYTHON_JIT=0 can be used to disable the micro-op interpreter at runtime. jit = no +# Tail-calling interpreter? +tail_call_interp = False + # The space-separated list of libraries that are package-only, # i.e., locally installed but not on header and library paths. # For each such library, determine the install path and add an diff --git a/pyperformance/compile.py b/pyperformance/compile.py index 54219f06..c96dc4e0 100644 --- a/pyperformance/compile.py +++ b/pyperformance/compile.py @@ -295,6 +295,8 @@ def compile(self): config_args.append("--with-lto") if self.conf.jit: config_args.append(f"--enable-experimental-jit={self.conf.jit}") + if self.conf.tail_call_interp: + config_args.append("--with-tail-call-interp") if self.conf.pkg_only: config_args.extend(self.get_package_only_flags()) if self.conf.debug: @@ -830,6 +832,7 @@ def getint(section, key, default=None): conf.lto = getboolean("compile", "lto", True) conf.pgo = getboolean("compile", "pgo", True) conf.jit = getstr("compile", "jit", "") + conf.tail_call_interp = getboolean("compile", "tail_call_interp", False) conf.install = getboolean("compile", "install", True) conf.pkg_only = getstr("compile", "pkg_only", "").split() try: diff --git a/pyperformance/tests/test_compile.py b/pyperformance/tests/test_compile.py new file mode 100644 index 00000000..1c178d51 --- /dev/null +++ b/pyperformance/tests/test_compile.py @@ -0,0 +1,73 @@ +import os +import pathlib +import tempfile +import textwrap +import types +import unittest +from unittest import mock + +from pyperformance import compile as compile_mod + + +class ParseConfigTests(unittest.TestCase): + def test_parse_config_reads_tail_call_interp(self): + with tempfile.TemporaryDirectory() as tmpdir: + root = pathlib.Path(tmpdir) + config_path = root / "benchmark.conf" + config_path.write_text( + textwrap.dedent( + f"""\ + [config] + json_dir = {root / "json"} + + [scm] + repo_dir = {root / "cpython"} + + [compile] + bench_dir = {root / "bench"} + tail_call_interp = true + + [run_benchmark] + """ + ), + encoding="utf-8", + ) + + conf = compile_mod.parse_config(str(config_path), "compile") + + self.assertTrue(conf.tail_call_interp) + + +class CompileCommandTests(unittest.TestCase): + def test_compile_adds_tail_call_interp_flag(self): + conf = types.SimpleNamespace( + build_dir="/tmp/build", + repo_dir="/tmp/cpython", + prefix="", + debug=False, + lto=False, + pgo=True, + jit="", + tail_call_interp=True, + pkg_only=[], + jobs=0, + ) + app = types.SimpleNamespace( + branch="main", + logger=None, + safe_makedirs=mock.Mock(), + run=mock.Mock(), + ) + + compile_mod.Python(app, conf).compile() + + configure_call = app.run.call_args_list[0] + self.assertEqual( + configure_call.args, + (os.path.join(conf.repo_dir, "configure"), "--with-tail-call-interp"), + ) + self.assertEqual(configure_call.kwargs, {"cwd": "/tmp/build"}) + + +if __name__ == "__main__": + unittest.main()