diff options
author | gsallam <123525874+gsallam@users.noreply.github.com> | 2023-10-27 03:57:29 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-10-27 03:57:29 (GMT) |
commit | 21f068d80c6cc5de75f9df70fdd733d0ce9c70de (patch) | |
tree | daceefb593efea137dd642df968075b24c6d52f8 /Python | |
parent | 3d2f1f0b830d86f16f42c42b54d3ea4453dac318 (diff) | |
download | cpython-21f068d80c6cc5de75f9df70fdd733d0ce9c70de.zip cpython-21f068d80c6cc5de75f9df70fdd733d0ce9c70de.tar.gz cpython-21f068d80c6cc5de75f9df70fdd733d0ce9c70de.tar.bz2 |
gh-109587: Allow "precompiled" perf-trampolines to largely mitigate the cost of enabling perf-trampolines (#109666)
Diffstat (limited to 'Python')
-rw-r--r-- | Python/perf_trampoline.c | 50 | ||||
-rw-r--r-- | Python/sysmodule.c | 41 |
2 files changed, 84 insertions, 7 deletions
diff --git a/Python/perf_trampoline.c b/Python/perf_trampoline.c index 209a23b..4912239 100644 --- a/Python/perf_trampoline.c +++ b/Python/perf_trampoline.c @@ -193,7 +193,7 @@ typedef struct trampoline_api_st trampoline_api_t; #define perf_code_arena _PyRuntime.ceval.perf.code_arena #define trampoline_api _PyRuntime.ceval.perf.trampoline_api #define perf_map_file _PyRuntime.ceval.perf.map_file - +#define persist_after_fork _PyRuntime.ceval.perf.persist_after_fork static void perf_map_write_entry(void *state, const void *code_addr, @@ -361,6 +361,26 @@ default_eval: } #endif // PY_HAVE_PERF_TRAMPOLINE +int PyUnstable_PerfTrampoline_CompileCode(PyCodeObject *co) +{ +#ifdef PY_HAVE_PERF_TRAMPOLINE + py_trampoline f = NULL; + assert(extra_code_index != -1); + int ret = _PyCode_GetExtra((PyObject *)co, extra_code_index, (void **)&f); + if (ret != 0 || f == NULL) { + py_trampoline new_trampoline = compile_trampoline(); + if (new_trampoline == NULL) { + return 0; + } + trampoline_api.write_state(trampoline_api.state, new_trampoline, + perf_code_arena->code_size, co); + return _PyCode_SetExtra((PyObject *)co, extra_code_index, + (void *)new_trampoline); + } +#endif // PY_HAVE_PERF_TRAMPOLINE + return 0; +} + int _PyIsPerfTrampolineActive(void) { @@ -448,16 +468,34 @@ _PyPerfTrampoline_Fini(void) return 0; } +int +PyUnstable_PerfTrampoline_SetPersistAfterFork(int enable){ +#ifdef PY_HAVE_PERF_TRAMPOLINE + persist_after_fork = enable; + return persist_after_fork; +#endif + return 0; +} + PyStatus _PyPerfTrampoline_AfterFork_Child(void) { #ifdef PY_HAVE_PERF_TRAMPOLINE - // Restart trampoline in file in child. - int was_active = _PyIsPerfTrampolineActive(); - _PyPerfTrampoline_Fini(); PyUnstable_PerfMapState_Fini(); - if (was_active) { - _PyPerfTrampoline_Init(1); + if (persist_after_fork) { + char filename[256]; + pid_t parent_pid = getppid(); + snprintf(filename, sizeof(filename), "/tmp/perf-%d.map", parent_pid); + if (PyUnstable_CopyPerfMapFile(filename) != 0) { + return PyStatus_Error("Failed to copy perf map file."); + } + } else { + // Restart trampoline in file in child. + int was_active = _PyIsPerfTrampolineActive(); + _PyPerfTrampoline_Fini(); + if (was_active) { + _PyPerfTrampoline_Init(1); + } } #endif return PyStatus_Ok(); diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 3debe7f..4008a28 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -2361,7 +2361,7 @@ PyAPI_FUNC(int) PyUnstable_WritePerfMapEntry( #ifndef MS_WINDOWS if (perf_map_state.perf_map == NULL) { int ret = PyUnstable_PerfMapState_Init(); - if(ret != 0){ + if (ret != 0){ return ret; } } @@ -2388,6 +2388,45 @@ PyAPI_FUNC(void) PyUnstable_PerfMapState_Fini(void) { #endif } +PyAPI_FUNC(int) PyUnstable_CopyPerfMapFile(const char* parent_filename) { +#ifndef MS_WINDOWS + FILE* from = fopen(parent_filename, "r"); + if (!from) { + return -1; + } + if (perf_map_state.perf_map == NULL) { + int ret = PyUnstable_PerfMapState_Init(); + if (ret != 0) { + return ret; + } + } + char buf[4096]; + PyThread_acquire_lock(perf_map_state.map_lock, 1); + int fflush_result = 0, result = 0; + while (1) { + size_t bytes_read = fread(buf, 1, sizeof(buf), from); + size_t bytes_written = fwrite(buf, 1, bytes_read, perf_map_state.perf_map); + fflush_result = fflush(perf_map_state.perf_map); + if (fflush_result != 0 || bytes_read == 0 || bytes_written < bytes_read) { + result = -1; + goto close_and_release; + } + if (bytes_read < sizeof(buf) && feof(from)) { + goto close_and_release; + } + } +close_and_release: + fclose(from); + PyThread_release_lock(perf_map_state.map_lock); + return result; +#endif + return 0; +} + +#ifdef __cplusplus +} +#endif + static PyMethodDef sys_methods[] = { /* Might as well keep this in alphabetic order */ |