summaryrefslogtreecommitdiffstats
path: root/Python
diff options
context:
space:
mode:
authorgsallam <123525874+gsallam@users.noreply.github.com>2023-10-27 03:57:29 (GMT)
committerGitHub <noreply@github.com>2023-10-27 03:57:29 (GMT)
commit21f068d80c6cc5de75f9df70fdd733d0ce9c70de (patch)
treedaceefb593efea137dd642df968075b24c6d52f8 /Python
parent3d2f1f0b830d86f16f42c42b54d3ea4453dac318 (diff)
downloadcpython-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.c50
-rw-r--r--Python/sysmodule.c41
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 */