Optware / Optware-ng

279 stars 52 forks source link

php-opcache not working [with solution] #210

Closed viktike closed 6 years ago

viktike commented 6 years ago

I've noticed, that PHP zend_extension opcache.so is not working on most of my routers. When I try to load it, it SIGSEGV: Fatal Error: Unable to allocate shared memory segment XXX bytes: unknown: No such file or directory (2) I've managed to fix it with a minor change to the file: php-5.6.31/ext/opcache/zend_shared_alloc.c

I replaced the line #define TMP_DIR "/tmp" with #define TMP_DIR "/opt/tmp" and recompiled, and it now works.

If possible, apply this fix, and thanks again.

viktike commented 6 years ago
Zend OPcache

Opcode Caching => Up and Running
Optimization => Enabled
Startup => OK
Shared memory model => mmap
Cache hits => 0
Cache misses => 0
Used memory => 5353992
Free memory => 61754872
Wasted memory => 0
Interned Strings Used memory => 378552
Interned Strings Free memory => 3815752
Cached scripts => 0
Cached keys => 0
Max keys => 3907
OOM restarts => 0
Hash keys restarts => 0
Manual restarts => 0

Directive => Local Value => Master Value
opcache.blacklist_filename => no value => no value
opcache.consistency_checks => 0 => 0
opcache.dups_fix => Off => Off
opcache.enable => On => On
opcache.enable_cli => On => On
opcache.enable_file_override => Off => Off
opcache.error_log => no value => no value
opcache.fast_shutdown => 0 => 0
opcache.file_update_protection => 2 => 2
opcache.force_restart_timeout => 180 => 180
opcache.inherited_hack => On => On
opcache.interned_strings_buffer => 4 => 4
opcache.load_comments => 1 => 1
opcache.log_verbosity_level => 1 => 1
opcache.max_accelerated_files => 2000 => 2000
opcache.max_file_size => 0 => 0
opcache.max_wasted_percentage => 5 => 5
opcache.memory_consumption => 64 => 64
opcache.optimization_level => 0x7FFFBFFF => 0x7FFFBFFF
opcache.preferred_memory_model => posix => posix
opcache.protect_memory => 0 => 0
opcache.restrict_api => no value => no value
opcache.revalidate_freq => 2 => 2
opcache.revalidate_path => Off => Off
opcache.save_comments => 1 => 1
opcache.use_cwd => On => On
opcache.validate_permission => Off => Off
opcache.validate_root => Off => Off
opcache.validate_timestamps => On => On
alllexx88 commented 6 years ago

I replaced the line

define TMP_DIR "/tmp"

with

define TMP_DIR "/opt/tmp"

and recompiled, and it now works.

Good catch, thanks! Will apply your fix a bit later

viktike commented 6 years ago

So this must be related to the ramdisk/tmpfs:

mount | grep /tmp
tmpfs on /tmp type tmpfs (rw)
/dev/sdc1 on /tmp/mnt/storage type ext3 (rw,data=ordered)
alllexx88 commented 6 years ago

Yes, looks like /tmp ramdisk is too small for opcache

viktike commented 6 years ago

Which is quite strange, since it's only used for lock files, actual cache is in memory. And there is some free space in /tmp:

df -h | grep /tmp
tmpfs                 125M   68M   58M  54% /tmp

Instead of the size, I would guess maybe the filesystem type (tmpfs) is problem, which is also strange, many normal distros come with tmpfs /tmp

alllexx88 commented 6 years ago

If I'm not mistaken, looks like cache is actually stored in TMP_DIR:

        if (!g_shared_alloc_handler) {
                /* try memory handlers in order */
                for (he = handler_table; he->name; he++) {
                        res = zend_shared_alloc_try(he, requested_size, &ZSMMG(shared_segments), &ZSMMG(shared_segments_count), &error_in);
                        if (res) {
                                /* this model works! */
                                break;
                        }
                }
        }

        if (!g_shared_alloc_handler) {
                no_memory_bailout(requested_size, error_in);
                return ALLOC_FAILURE;
        }

In the code above it's checking for working (ones that can allocate sufficient storage) shared memory handlers. As a guess, probably, if there's enough free RAM, it stores cache there' otherwise -- falls back to storing it in TMP_DIR.

alllexx88 commented 6 years ago

Though it may be unrelated: I'm not familiar with opcache internals

alllexx88 commented 6 years ago

Ok, the fix is in the feeds, so I'm closing the issue, thanks

alllexx88 commented 6 years ago

Looks like opcache isn't still fully working: launching php-fcgi produces the same error:

[root@unknown root]$ /opt/bin/php-fcgi
Wed Sep 20 10:41:17 2017 (21947): Fatal Error Unable to allocate shared memory segment of 67108864 bytes: unknown: No such file or directory (2)

Reopening the issue...

viktike commented 6 years ago

Hmm, it's not the case with my device. However it's MIPSel instead of ARM. I have a theory: as I said, I compiled this extension on the device. Maybe the solution wasn't the patch, but the fact it was a native compilation instead of cross-compilation. Please see the attached screenshot of it working. opcache

viktike commented 6 years ago

The /opt/bin/php-fcgi command return no error, The /opt/bin/php -v command shows:

AirPort:~ root$ /opt/bin/php -v
PHP 5.6.31 (cli) (built: Aug 15 2017 08:57:37)
Copyright (c) 1997-2016 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies
    with Zend OPcache v7.0.6-dev, Copyright (c) 1999-2016, by Zend Technologies
alllexx88 commented 6 years ago

I have a theory: as I said, I compiled this extension on the device. Maybe the solution wasn't the patch, but the fact it was a native compilation instead of cross-compilation.

Can you please try the opcache.so from the feeds to make sure?

viktike commented 6 years ago

I've tried it. Sure it doesn't work:

php -v
Wed Sep 20 10:14:24 2017 (4143): Fatal Error Unable to allocate shared memory segment of 67108864 bytes: unknown: No such file or directory (2)

So here is what I did before:

alllexx88 commented 6 years ago

Also, can you please post your main/php_config.h from the php source dir? Maybe, there're something badly wrong in the cross-generated config file

viktike commented 6 years ago

I have no such file there.

AirPort:/tmp/mnt/storage/php/php-5.6.31/ext/opcache root$ phpize
Configuring for:
PHP Api Version:         20131106
Zend Module Api No:      20131226
Zend Extension Api No:   220131226
AirPort:/tmp/mnt/storage/php/php-5.6.31/ext/opcache root$ ./configure --prefix=/opt
checking for grep that handles long lines and -e... /opt/bin/grep
checking for egrep... /opt/bin/grep -E
checking for a sed that does not truncate output... /opt/bin/sed
checking for cc... cc
checking whether the C compiler works... yes
checking for C compiler default output file name... a.out
checking for suffix of executables...
checking whether we are cross compiling... no
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether cc accepts -g... yes
checking for cc option to accept ISO C89... none needed
checking how to run the C preprocessor... cc -E
checking for icc... no
checking for suncc... no
checking whether cc understands -c and -o together... yes
checking for system library directory... lib
checking if compiler supports -R... yes
checking build system type... mipsel-unknown-linux-gnu
checking host system type... mipsel-unknown-linux-gnu
checking target system type... mipsel-unknown-linux-gnu
checking for PHP prefix... /opt
checking for PHP includes... -I/opt/include/php -I/opt/include/php/main -I/opt/include/php/TSRM -I/opt/include/php/Zend -I/opt/include/php/ext -I/opt/include/php/ext/date/lib
checking for PHP extension directory... /opt/lib/php/extensions
checking for PHP installed headers prefix... /opt/include/php
checking if debug is enabled... no
checking if zts is enabled... no
checking for re2c... no
configure: WARNING: You will need re2c 0.13.4 or later if you want to regenerate PHP parsers.
checking for gawk... gawk
checking whether to enable Zend OPcache support... yes, shared
checking for mprotect... yes
checking for sysvipc shared memory support... yes
checking for mmap() using MAP_ANON shared memory support... yes
checking for mmap() using /dev/zero shared memory support... yes
checking for mmap() using shm_open() shared memory support... no
checking for mmap() using regular file shared memory support... yes
checking "whether flock struct is linux ordered"... "yes"
checking "whether flock struct is BSD ordered"... "no"
checking how to print strings... printf
checking for a sed that does not truncate output... (cached) /opt/bin/sed
checking for fgrep... /opt/bin/grep -F
checking for ld used by cc... /opt/bin/ld
checking if the linker (/opt/bin/ld) is GNU ld... yes
checking for BSD- or MS-compatible name lister (nm)... /opt/bin/nm -B
checking the name lister (/opt/bin/nm -B) interface... BSD nm
checking whether ln -s works... yes
checking the maximum length of command line arguments... 32768
checking how to convert mipsel-unknown-linux-gnu file names to mipsel-unknown-linux-gnu format... func_convert_file_noop
checking how to convert mipsel-unknown-linux-gnu file names to toolchain format... func_convert_file_noop
checking for /opt/bin/ld option to reload object files... -r
checking for objdump... objdump
checking how to recognize dependent libraries... pass_all
checking for dlltool... no
checking how to associate runtime and link libraries... printf %s\n
checking for ar... ar
checking for archiver @FILE support... @
checking for strip... strip
checking for ranlib... ranlib
checking for gawk... (cached) gawk
checking command to parse /opt/bin/nm -B output from cc object... ok
checking for sysroot... no
checking for a working dd... /opt/bin/dd
checking how to truncate binary pipes... /opt/bin/dd bs=4096 count=1
checking for mt... mt
checking if mt is a manifest tool... no
checking for ANSI C header files... yes
checking for sys/types.h... yes
checking for sys/stat.h... yes
checking for stdlib.h... yes
checking for string.h... yes
checking for memory.h... yes
checking for strings.h... yes
checking for inttypes.h... yes
checking for stdint.h... yes
checking for unistd.h... yes
checking for dlfcn.h... yes
checking for objdir... .libs
checking if cc supports -fno-rtti -fno-exceptions... no
checking for cc option to produce PIC... -fPIC -DPIC
checking if cc PIC flag -fPIC -DPIC works... yes
checking if cc static flag -static works... yes
checking if cc supports -c -o file.o... yes
checking if cc supports -c -o file.o... (cached) yes
checking whether the cc linker (/opt/bin/ld) supports shared libraries... yes
checking whether -lc should be explicitly linked in... no
checking dynamic linker characteristics... GNU/Linux ld.so
checking how to hardcode library paths into programs... immediate
checking whether stripping libraries is possible... yes
checking if libtool supports shared libraries... yes
checking whether to build shared libraries... yes
checking whether to build static libraries... no
configure: creating ./config.status
config.status: creating config.h
config.status: executing libtool commands
AirPort:/tmp/mnt/storage/php/php-5.6.31/ext/opcache root$ cd ..
AirPort:/tmp/mnt/storage/php/php-5.6.31/ext root$ cd ..
AirPort:/tmp/mnt/storage/php/php-5.6.31 root$ cd main/
AirPort:/tmp/mnt/storage/php/php-5.6.31/main root$
AirPort:/tmp/mnt/storage/php/php-5.6.31/main root$ cat php_config.h
cat: php_config.h: No such file or directory
alllexx88 commented 6 years ago

Ah, you're not configuring entire php: just the opcache extension. Then please post /tmp/mnt/storage/php/php-5.6.31/ext/opcache/config.h

viktike commented 6 years ago

Sorry, can't attach .h files, so here it is:

AirPort:/tmp/mnt/storage/php/php-5.6.31/ext/opcache root$ cat config.h
/* config.h.  Generated from config.h.in by configure.  */
/* config.h.in.  Generated from configure.in by autoheader.  */

/* Whether to build opcache as dynamic module */
#define COMPILE_DL_OPCACHE 1

/* Define to 1 if you have the <dlfcn.h> header file. */
#define HAVE_DLFCN_H 1

/* Struct flock is BSD-type */
/* #undef HAVE_FLOCK_BSD */

/* Struct flock is Linux-type */
#define HAVE_FLOCK_LINUX /**/

/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1

/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1

/* Define if you have mprotect() function */
#define HAVE_MPROTECT 1

/* Define if you have SysV IPC SHM support */
#define HAVE_SHM_IPC 1

/* Define if you have mmap(MAP_ANON) SHM support */
#define HAVE_SHM_MMAP_ANON 1

/* Define if you have mmap() SHM support */
#define HAVE_SHM_MMAP_FILE 1

/* Define if you have POSIX mmap() SHM support */
/* #undef HAVE_SHM_MMAP_POSIX */

/* Define if you have mmap("/dev/zero") SHM support */
#define HAVE_SHM_MMAP_ZERO 1

/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1

/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1

/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1

/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1

/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1

/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1

/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1

/* Define to the sub-directory where libtool stores uninstalled libraries. */
#define LT_OBJDIR ".libs/"

/* Define to 1 if your C compiler doesn't accept -c and -o together. */
/* #undef NO_MINUS_C_MINUS_O */

/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT ""

/* Define to the full name of this package. */
#define PACKAGE_NAME ""

/* Define to the full name and version of this package. */
#define PACKAGE_STRING ""

/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME ""

/* Define to the home page for this package. */
#define PACKAGE_URL ""

/* Define to the version of this package. */
#define PACKAGE_VERSION ""

/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
AirPort:/tmp/mnt/storage/php/php-5.6.31/ext/opcache root$
alllexx88 commented 6 years ago

This config is largely different from main/php-config.h that's being generated during cross-compilation. Especially in the shared memory portion (mmap and such). After some patching (see 1d0edcaee3d37972f9c2a8608b139a25f73b29a9), while building opcache extension separately, using phpize as you do natively, I'm getting a similar config. Also, it appears to work fine too 😄 At least, on an ARMv7 router. After the feeds are built, php-opcache will be available as a separate package (and opcache.so removed from php package)

viktike commented 6 years ago

Ok, I can test that one as well on MIPSel, once available.

alllexx88 commented 6 years ago

@viktike I've tested php-opcache on armv7, i686 and mipsel platforms: it works well. Does it work for you?

viktike commented 6 years ago

It works.

alllexx88 commented 6 years ago

Good.