mirror of
https://github.com/python/cpython.git
synced 2025-08-03 16:39:00 +00:00
gh-109587: Allow "precompiled" perf-trampolines to largely mitigate the cost of enabling perf-trampolines (#109666)
This commit is contained in:
parent
3d2f1f0b83
commit
21f068d80c
8 changed files with 199 additions and 10 deletions
|
@ -353,6 +353,82 @@ class TestPerfProfiler(unittest.TestCase):
|
|||
self.assertNotIn(f"py::bar:{script}", stdout)
|
||||
self.assertNotIn(f"py::baz:{script}", stdout)
|
||||
|
||||
def test_pre_fork_compile(self):
|
||||
code = """if 1:
|
||||
import sys
|
||||
import os
|
||||
import sysconfig
|
||||
from _testinternalcapi import (
|
||||
compile_perf_trampoline_entry,
|
||||
perf_trampoline_set_persist_after_fork,
|
||||
)
|
||||
|
||||
def foo_fork():
|
||||
pass
|
||||
|
||||
def bar_fork():
|
||||
foo_fork()
|
||||
|
||||
def foo():
|
||||
pass
|
||||
|
||||
def bar():
|
||||
foo()
|
||||
|
||||
def compile_trampolines_for_all_functions():
|
||||
perf_trampoline_set_persist_after_fork(1)
|
||||
for _, obj in globals().items():
|
||||
if callable(obj) and hasattr(obj, '__code__'):
|
||||
compile_perf_trampoline_entry(obj.__code__)
|
||||
|
||||
if __name__ == "__main__":
|
||||
compile_trampolines_for_all_functions()
|
||||
pid = os.fork()
|
||||
if pid == 0:
|
||||
print(os.getpid())
|
||||
bar_fork()
|
||||
else:
|
||||
bar()
|
||||
"""
|
||||
|
||||
with temp_dir() as script_dir:
|
||||
script = make_script(script_dir, "perftest", code)
|
||||
with subprocess.Popen(
|
||||
[sys.executable, "-Xperf", script],
|
||||
universal_newlines=True,
|
||||
stderr=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
) as process:
|
||||
stdout, stderr = process.communicate()
|
||||
|
||||
self.assertEqual(process.returncode, 0)
|
||||
self.assertNotIn("Error:", stderr)
|
||||
child_pid = int(stdout.strip())
|
||||
perf_file = pathlib.Path(f"/tmp/perf-{process.pid}.map")
|
||||
perf_child_file = pathlib.Path(f"/tmp/perf-{child_pid}.map")
|
||||
self.assertTrue(perf_file.exists())
|
||||
self.assertTrue(perf_child_file.exists())
|
||||
|
||||
perf_file_contents = perf_file.read_text()
|
||||
self.assertIn(f"py::foo:{script}", perf_file_contents)
|
||||
self.assertIn(f"py::bar:{script}", perf_file_contents)
|
||||
self.assertIn(f"py::foo_fork:{script}", perf_file_contents)
|
||||
self.assertIn(f"py::bar_fork:{script}", perf_file_contents)
|
||||
|
||||
child_perf_file_contents = perf_child_file.read_text()
|
||||
self.assertIn(f"py::foo_fork:{script}", child_perf_file_contents)
|
||||
self.assertIn(f"py::bar_fork:{script}", child_perf_file_contents)
|
||||
|
||||
# Pre-compiled perf-map entries of a forked process must be
|
||||
# identical in both the parent and child perf-map files.
|
||||
perf_file_lines = perf_file_contents.split("\n")
|
||||
for line in perf_file_lines:
|
||||
if (
|
||||
f"py::foo_fork:{script}" in line
|
||||
or f"py::bar_fork:{script}" in line
|
||||
):
|
||||
self.assertIn(line, child_perf_file_contents)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue