-
Notifications
You must be signed in to change notification settings - Fork 8k
Increase SEG_ALLOC_SIZE_MAX to 64MB to support OPcache JIT on Solaris #20719
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: PHP-8.4
Are you sure you want to change the base?
Conversation
The SysV shared memory allocator in OPcache hardcodes a maximum segment size of 32MB (SEG_ALLOC_SIZE_MAX). With JIT enabled, OPcache reserves 64MB (ZEND_JIT_DEFAULT_BUFFER_SIZE) from the last segment, causing startup to fail with "Insufficient shared memory!". This patch increases SEG_ALLOC_SIZE_MAX to 64MB so the reserved JIT buffer fits in a single segment. Behavior on other platforms using mmap remains unaffected. Fixes php#20718.
|
Won't this issue just immediately re-appear when configuring a larger buffer size? E.g. add |
|
PHP 8.3 has the same issue, it's just enabled in a different way ( |
|
So, I think the maximum segment size should be bumped way up, at least on 64-bit architectures. Alternatively, we can request a bigger segment size only when JIT is enabled (though I don't really see a benefit over just always allocating bigger chunks). Something like: diff --git a/ext/opcache/shared_alloc_shm.c b/ext/opcache/shared_alloc_shm.c
index 09a357d189e..2f7c9ba4217 100644
--- a/ext/opcache/shared_alloc_shm.c
+++ b/ext/opcache/shared_alloc_shm.c
@@ -20,6 +20,9 @@
*/
#include "zend_shared_alloc.h"
+#ifdef HAVE_JIT
+# include "jit/zend_jit.h"
+#endif
#ifdef USE_SHM
@@ -50,6 +53,23 @@ typedef struct {
int shm_id;
} zend_shared_segment_shm;
+#ifdef HAVE_JIT
+static size_t ceil_to_power_of_2(size_t n)
+{
+ ZEND_ASSERT(n);
+
+ size_t m = n;
+ uint32_t r = 0;
+ while (m >>= 1) {
+ r++;
+ }
+ if (n != (((size_t)1) << r)) {
+ r++;
+ }
+ return ((size_t)1) << r;
+}
+#endif
+
static int create_segments(size_t requested_size, zend_shared_segment_shm ***shared_segments_p, int *shared_segments_count, const char **error_in)
{
int i;
@@ -61,6 +81,12 @@ static int create_segments(size_t requested_size, zend_shared_segment_shm ***sha
zend_shared_segment_shm *shared_segments;
seg_allocate_size = SEG_ALLOC_SIZE_MAX;
+#ifdef HAVE_JIT
+ if (JIT_G(on) && JIT_G(buffer_size) > seg_allocate_size) {
+ /* The JIT buffer must be allocated in a contiguous chunk. */
+ seg_allocate_size = ceil_to_power_of_2(JIT_G(buffer_size));
+ }
+#endif
/* determine segment size we _really_ need:
* no more than to include requested_size
*/ |
Yes, adding |
With your patch I'm getting "Fatal Error Insufficient shared memory!" error from these two tests: Zend/tests/return_types/internal_functions001.phpt |
Using both, your patch and SEG_ALLOC_SIZE_MAX set 64MB allows to pass all tests...l |
|
I think it's probably better to just bump the limit to something much bigger. Big allocations are not a big concern in 64-bit address space anymore. Maybe @dstogov can comment as the original author. |
The SysV shared memory allocator in OPcache hardcodes a maximum segment size of 32MB (SEG_ALLOC_SIZE_MAX). With JIT enabled, OPcache reserves 64MB (ZEND_JIT_DEFAULT_BUFFER_SIZE) from the last segment, causing startup to fail with "Insufficient shared memory!".
This patch increases SEG_ALLOC_SIZE_MAX to 64MB so the reserved JIT buffer fits in a single segment. Behavior on other platforms using mmap remains unaffected.
Fixes #20718.