-
-
Notifications
You must be signed in to change notification settings - Fork 121
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Enable Perf Trampoline Pre-fork Compile
Summary: [**Motivation**](https://docs.google.com/document/d/1XpBXcBz2VMGBIu9QrLO-6znTIrHWIn8HLI6zfLJ9ang/edit?usp=sharing) The perf-trampoline rolled out and enabled on a small number of boxes right now. The main blocker to enabling it globally is that it’s a ~1.5% gCPU regression. Most of the regression comes from us having to update the /tmp/perf-<pid>.map files. We can mitigate this cost by following the JIT model, and generating the trampolines during bootstrap. Here are the proposed steps for implementation: **During Bootstrap:** - Maintain a set of code objects (named `perf_trampoline_reg_units`), akin to `jit_reg_units`, but intended for items not included in the JIT list. - Create a new function (`compile_perf_trampoline_entries`) that iterates through `perf_trampoline_reg_units` and invokes _`PyPerfTrampoline_CompileCode` for each entry. - Call `compile_perf_trampoline_entries` during bootstrap. **Pre-fork Stage:** - Check if pre-fork perf-trampoline compilation is enabled. If so: - Copy the perfmap file from the parent's perf-map to the child's perf-map. - Refrain from re-initializing the perf-trampoline in the child process to prevent redundant recompilation. - Modify the JIT code to bypass copying perf-map files if the pre-fork perf-trampoline compilation is activated. **Other** - I added an env variable (`PERFTRAMPOLINEPREFORKCOMPILATION`) and a flag `perf_trampoline_prefork_compilation` to enable this feature at the process level. **We need to decide which part should be upstreamed.** Reviewed By: czardoz Differential Revision: D48612681 fbshipit-source-id: 9e1eb884328d453cfadaf0f2a0ac3f05af3996f4
- Loading branch information
1 parent
b0a8b5e
commit 8fa7e0d
Showing
12 changed files
with
282 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
import pathlib | ||
import subprocess | ||
import sys | ||
import sysconfig | ||
import unittest | ||
|
||
from test.support.os_helper import temp_dir | ||
from test.support.script_helper import assert_python_ok, make_script | ||
|
||
try: | ||
from cinder import _is_compile_perf_trampoline_pre_fork_enabled | ||
except: | ||
raise unittest.SkipTest("pre-fork perf-trampoline compilation is not enabled") | ||
|
||
|
||
def supports_trampoline_profiling(): | ||
perf_trampoline = sysconfig.get_config_var("PY_HAVE_PERF_TRAMPOLINE") | ||
if not perf_trampoline: | ||
return False | ||
return int(perf_trampoline) == 1 | ||
|
||
|
||
if not supports_trampoline_profiling(): | ||
raise unittest.SkipTest("perf trampoline profiling not supported") | ||
|
||
if not _is_compile_perf_trampoline_pre_fork_enabled(): | ||
raise unittest.SkipTest("pre-fork perf-trampoline compilation is not enabled") | ||
|
||
|
||
class TestPerfTrampolinePreCompile(unittest.TestCase): | ||
def setUp(self): | ||
super().setUp() | ||
self.perf_files = set(pathlib.Path("/tmp/").glob("perf-*.map")) | ||
|
||
def tearDown(self) -> None: | ||
super().tearDown() | ||
files_to_delete = ( | ||
set(pathlib.Path("/tmp/").glob("perf-*.map")) - self.perf_files | ||
) | ||
for file in files_to_delete: | ||
file.unlink() | ||
|
||
def test_trampoline_works(self): | ||
code = """if 1: | ||
import sys | ||
import os | ||
import sysconfig | ||
from cinder import _compile_perf_trampoline_pre_fork | ||
def foo_fork(): | ||
pass | ||
def bar_fork(): | ||
foo_fork() | ||
def baz_fork(): | ||
bar_fork() | ||
def foo(): | ||
pass | ||
def bar(): | ||
foo() | ||
def baz(): | ||
bar() | ||
if __name__ == "__main__": | ||
_compile_perf_trampoline_pre_fork() | ||
pid = os.fork() | ||
if pid == 0: | ||
print(os.getpid()) | ||
baz_fork() | ||
else: | ||
baz() | ||
""" | ||
rc, out, err = assert_python_ok("-c", code) | ||
with temp_dir() as script_dir: | ||
script = make_script(script_dir, "perftest", code) | ||
with subprocess.Popen( | ||
[ | ||
sys.executable, | ||
"-X", | ||
"perf-trampoline-prefork-compilation", | ||
"-X", | ||
"perf", | ||
script, | ||
], | ||
universal_newlines=True, | ||
stderr=subprocess.PIPE, | ||
stdout=subprocess.PIPE, | ||
) as process: | ||
stdout, stderr = process.communicate() | ||
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::baz:{script}", perf_file_contents) | ||
self.assertIn(f"py::foo_fork:{script}", perf_file_contents) | ||
self.assertIn(f"py::bar_fork:{script}", perf_file_contents) | ||
self.assertIn(f"py::baz_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) | ||
self.assertIn(f"py::baz_fork:{script}", child_perf_file_contents) | ||
|
||
# For pre-compiled entries, the entries of a forked process should | ||
# appear exactly the same in both the parent and child processes. | ||
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 | ||
or f"py::baz_fork:{script}" in line | ||
): | ||
self.assertIn(line, child_perf_file_contents) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.