From 71cef5ec828987cf43fcac103682bccba4a4601b Mon Sep 17 00:00:00 2001 From: Diego Russo Date: Tue, 23 Apr 2024 15:01:13 +0100 Subject: [PATCH 1/5] gh-126195: Use pthread_jit_write_protect_np on macOS Replace mprotect with pthread_jit_write_protect_np on MacOS Apple Silicon. Improve JIT performance by ~1.4% on this platform. --- Python/jit.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Python/jit.c b/Python/jit.c index 90f693dfb7c41b..c3e6aea4037f58 100644 --- a/Python/jit.c +++ b/Python/jit.c @@ -56,9 +56,16 @@ jit_alloc(size_t size) int flags = MEM_COMMIT | MEM_RESERVE; unsigned char *memory = VirtualAlloc(NULL, size, flags, PAGE_READWRITE); int failed = memory == NULL; +#elif defined(__APPLE__) && defined(__aarch64__) + int flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_JIT; + int prot = PROT_READ | PROT_WRITE | PROT_EXEC; + unsigned char *memory = mmap(NULL, size, prot, flags, -1, 0); + int failed = memory == MAP_FAILED; + pthread_jit_write_protect_np(0); #else int flags = MAP_ANONYMOUS | MAP_PRIVATE; - unsigned char *memory = mmap(NULL, size, PROT_READ | PROT_WRITE, flags, -1, 0); + int prot = PROT_READ | PROT_WRITE; + unsigned char *memory = mmap(NULL, size, prot, flags, -1, 0); int failed = memory == MAP_FAILED; #endif if (failed) { @@ -101,6 +108,10 @@ mark_executable(unsigned char *memory, size_t size) } int old; int failed = !VirtualProtect(memory, size, PAGE_EXECUTE_READ, &old); +#elif defined(__APPLE__) && defined(__aarch64__) + int failed = 0; + __builtin___clear_cache((char *)memory, (char *)memory + size); + pthread_jit_write_protect_np(1); #else __builtin___clear_cache((char *)memory, (char *)memory + size); int failed = mprotect(memory, size, PROT_EXEC | PROT_READ); From 24719d70d3dfc41a825050db907986ff9d752a59 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Wed, 30 Oct 2024 18:16:13 +0000 Subject: [PATCH 2/5] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../2024-10-30-18-16-10.gh-issue-126195.6ezBpr.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-10-30-18-16-10.gh-issue-126195.6ezBpr.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-10-30-18-16-10.gh-issue-126195.6ezBpr.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-30-18-16-10.gh-issue-126195.6ezBpr.rst new file mode 100644 index 00000000000000..45a79e9877fdf5 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-30-18-16-10.gh-issue-126195.6ezBpr.rst @@ -0,0 +1 @@ +Improve JIT performance by 1.4% on macOS Apple Silicon. Patch by Diego Russo. From 507e6628e47d733605e6b2cd078ebda4eb5aeb7e Mon Sep 17 00:00:00 2001 From: Diego Russo Date: Fri, 8 Nov 2024 14:02:42 +0000 Subject: [PATCH 3/5] Address Brandt feedback --- Python/jit.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/Python/jit.c b/Python/jit.c index c3e6aea4037f58..dbaef80049c0d6 100644 --- a/Python/jit.c +++ b/Python/jit.c @@ -56,15 +56,13 @@ jit_alloc(size_t size) int flags = MEM_COMMIT | MEM_RESERVE; unsigned char *memory = VirtualAlloc(NULL, size, flags, PAGE_READWRITE); int failed = memory == NULL; -#elif defined(__APPLE__) && defined(__aarch64__) - int flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_JIT; - int prot = PROT_READ | PROT_WRITE | PROT_EXEC; - unsigned char *memory = mmap(NULL, size, prot, flags, -1, 0); - int failed = memory == MAP_FAILED; - pthread_jit_write_protect_np(0); #else int flags = MAP_ANONYMOUS | MAP_PRIVATE; int prot = PROT_READ | PROT_WRITE; +# ifdef MAP_JIT + flags |= MAP_JIT; + prot |= PROT_EXEC; +# endif unsigned char *memory = mmap(NULL, size, prot, flags, -1, 0); int failed = memory == MAP_FAILED; #endif @@ -108,13 +106,12 @@ mark_executable(unsigned char *memory, size_t size) } int old; int failed = !VirtualProtect(memory, size, PAGE_EXECUTE_READ, &old); -#elif defined(__APPLE__) && defined(__aarch64__) - int failed = 0; - __builtin___clear_cache((char *)memory, (char *)memory + size); - pthread_jit_write_protect_np(1); #else + int failed = 0; __builtin___clear_cache((char *)memory, (char *)memory + size); - int failed = mprotect(memory, size, PROT_EXEC | PROT_READ); +# ifndef MAP_JIT + failed = mprotect(memory, size, PROT_EXEC | PROT_READ); +# endif #endif if (failed) { jit_error("unable to protect executable memory"); @@ -510,6 +507,9 @@ _PyJIT_Compile(_PyExecutorObject *executor, const _PyUOpInstruction trace[], siz if (memory == NULL) { return -1; } +#ifdef MAP_JIT + pthread_jit_write_protect_np(0); +#endif // Update the offsets of each instruction: for (size_t i = 0; i < length; i++) { state.instruction_starts[i] += (uintptr_t)memory; @@ -540,7 +540,11 @@ _PyJIT_Compile(_PyExecutorObject *executor, const _PyUOpInstruction trace[], siz data += group->data_size; assert(code == memory + code_size); assert(data == memory + code_size + data_size); - if (mark_executable(memory, total_size)) { + int status = mark_executable(memory, total_size); +#ifdef MAP_JIT + pthread_jit_write_protect_np(1); +#endif + if (status) { jit_free(memory, total_size); return -1; } From 138525d12dfc74e0516f77a97a12a3ae50dc26f7 Mon Sep 17 00:00:00 2001 From: Diego Russo Date: Sat, 9 Nov 2024 01:48:58 +0000 Subject: [PATCH 4/5] Address Brandt's feedback --- .../2024-10-30-18-16-10.gh-issue-126195.6ezBpr.rst | 2 +- Python/jit.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-10-30-18-16-10.gh-issue-126195.6ezBpr.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-30-18-16-10.gh-issue-126195.6ezBpr.rst index 45a79e9877fdf5..01424d8a545d78 100644 --- a/Misc/NEWS.d/next/Core_and_Builtins/2024-10-30-18-16-10.gh-issue-126195.6ezBpr.rst +++ b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-30-18-16-10.gh-issue-126195.6ezBpr.rst @@ -1 +1 @@ -Improve JIT performance by 1.4% on macOS Apple Silicon. Patch by Diego Russo. +Improve JIT performance by 1.4% on macOS Apple Silicon by using platform-specific memory protection APIs. Patch by Diego Russo. diff --git a/Python/jit.c b/Python/jit.c index dbaef80049c0d6..12b487e215f2dd 100644 --- a/Python/jit.c +++ b/Python/jit.c @@ -109,9 +109,9 @@ mark_executable(unsigned char *memory, size_t size) #else int failed = 0; __builtin___clear_cache((char *)memory, (char *)memory + size); -# ifndef MAP_JIT +#ifndef MAP_JIT failed = mprotect(memory, size, PROT_EXEC | PROT_READ); -# endif +#endif #endif if (failed) { jit_error("unable to protect executable memory"); From 7974378717c41dba3e6b0a31c972f8572f96b121 Mon Sep 17 00:00:00 2001 From: Diego Russo Date: Mon, 11 Nov 2024 10:08:57 +0000 Subject: [PATCH 5/5] Address feedback --- Python/jit.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Python/jit.c b/Python/jit.c index 12b487e215f2dd..7dd0da7a45055a 100644 --- a/Python/jit.c +++ b/Python/jit.c @@ -540,11 +540,10 @@ _PyJIT_Compile(_PyExecutorObject *executor, const _PyUOpInstruction trace[], siz data += group->data_size; assert(code == memory + code_size); assert(data == memory + code_size + data_size); - int status = mark_executable(memory, total_size); #ifdef MAP_JIT pthread_jit_write_protect_np(1); #endif - if (status) { + if (mark_executable(memory, total_size)) { jit_free(memory, total_size); return -1; }