From 50902535bc98f352c04b8ca5b23bc30d81bc7657 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo <ilija.tovilo@me.com> Date: Sat, 27 Aug 2022 18:16:10 +0200 Subject: [PATCH 1/2] Add basic introduction to OPcache and map_ptr --- Book/php7/zend_engine/zend_opcache.rst | 83 ++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/Book/php7/zend_engine/zend_opcache.rst b/Book/php7/zend_engine/zend_opcache.rst index 6331ceeb..f9cb24c5 100644 --- a/Book/php7/zend_engine/zend_opcache.rst +++ b/Book/php7/zend_engine/zend_opcache.rst @@ -1,2 +1,85 @@ Zend OPCache ============ + +While PHP is an interpreter, it does not interpret PHP source code directly. Instead, the source code is first parsed +into an abstract syntax tree (AST), which is then compiled to OPcodes (and used to generate classes and other data +structures), which are then passed to the Zend virtual machine (Zend VM) to actually be interpreted. + +As you can see, there are quite a few steps involved to run a single PHP file. Without an additional extension, PHP +will perform all of these steps for every single loaded file in every single request. Since usually PHP files don't +change between requests both the parsing and compilation steps will always yield the same result. OPcache is an +extension that caches the OPcodes and data structures like classes between requests to improve performance. The AST is +not used after the compilation step (with the exception of constant expressions) and thus does not need to be cached. + +Normally, all the memory allocated during the processing of a request gets freed after the request has been processed. +So to store the compiled OPcodes for future requests OPcache puts them in a shared memory segment (shm) that can not +only be accessed by the same process after the request has finished but also by other processes handling other +requests. This means that if you are using php-fpm with many children they will only store the OPcodes for each PHP +file once in shm. + +This comes with a significant restriction: The OPcodes and other data structures in shm must not be mutated by any +child request (at least not unless these changes should also affect the other processes). If any changes to shm are +made there is a locking mechanism to avoid data races. + +The classes and OParrays (arrays of OPcodes, i.e. functions) in shm are mostly immutable. There are currently three +exceptions: + +* ``zend_persistent_script.dynamic_members`` stores information about the state of the cached script +* ``zend_class_entry.inheritance_cache`` is extended if a new combination of parent class and interfaces is encountered +* ``zend_op_array.handler`` can be replaced at runtime by the tracing JIT to start executing JITted code + +map_ptr +------- + +As mentioned in the introduction, shm is shared for all child processes. Thus, no changes can be made to the data +structures living in shm unless 1. the changes are supposed to be reflected in all child processes and 2. the shm +segment has been locked before any changes are written to avoid data races. + +Sometimes the data structures contain a field that should be unique per process or request. The ``map_ptr`` mechanism +can be used to achieve this. In short, instead of storing a pointer to per-process data directly (as that would affect +all processes), a unique offset is assigned during compilation. During runtime, local memory is allocated to hold +enough space for all the entries referenced in these offsets. Each offset then corresponds to an item in the local +memory segment without needing to know the per-process location of the exact element. + +Here is an example from php-src. Classes can contain data that needs to be evaluated at runtime, called +``mutable_data``. This ``mutable_data`` contains fields like ``default_properties_table``, ``constants_table`` and more. +``ZEND_MAP_PTR_DEF`` can be used to declare a field that holds the offset into local memory. + + struct _zend_class_entry { + // ... + ZEND_MAP_PTR_DEF(zend_class_mutable_data*, mutable_data); + // ... + }; + +``ZEND_MAP_PTR_INIT`` assigns a value directly to the underlying offset field. This must only be done when the +structure is not yet in shm. + + ZEND_MAP_PTR_INIT(ce->mutable_data, NULL); + +``ZEND_MAP_PTR_NEW`` can be used to generate a new offset and store it in the given field. This must only be done when +the structure is not yet in shm. + + ZEND_MAP_PTR_NEW(ce->mutable_data); + +Once an offset has been assigned to the map ptr ``ZEND_MAP_PTR_SET_IMM`` can be used to assign the value in local memory +with the given offset stored in the map ptr. + + ZEND_MAP_PTR_SET_IMM(class_type->mutable_data, mutable_data); + +And to retrieve the value from local memory ``ZEND_MAP_PTR_GET_IMM`` can be used. + + zend_class_mutable_data *mutable_data = ZEND_MAP_PTR_GET_IMM(class_type->mutable_data); + +To summarize, with this mechanism, the relative offset ``mutable_data`` is the same for each process. The local map +itself lives at a different address in each process. The associated item will be retrieved by adding the given offset +to the base of the map. + +The map ptr can also store real pointers. This can be useful when the data structure doesn't live in shm and thus +doesn't need to store the value in a separate map. The fact that pointers are aligned by their size is used to +differenciate between offsets and real pointers. The offset start at 1, 9, 17, etc (assuming a 64-bit pointer size). +However, pointers (unless padding was removed) would not get aligned this way. Instead, they would be stored in +addresses that end with 0x0 or 0x8 given that they are 8-byte aligned. + +To store a real pointer you can use the ``ZEND_MAP_PTR_INIT`` macro. To retrieve a pointer regardless of whether a real +pointer or an offset is stored use the ``ZEND_MAP_PTR_GET`` macro. There's also the ``ZEND_MAP_PTR_SET`` macro that will +call ``ZEND_MAP_PTR_SET_IMM`` or ``ZEND_MAP_PTR_INIT`` depending on whether an offset is already stored in the map ptr. From a4babcbda938a99527b64c8bb245ed3cf08bd214 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo <ilija.tovilo@me.com> Date: Mon, 29 Aug 2022 20:33:13 +0200 Subject: [PATCH 2/2] Process feedback, add diagram --- Book/php7/zend_engine/images/map_ptr.png | Bin 0 -> 35695 bytes Book/php7/zend_engine/zend_opcache.rst | 101 ++++++++++++++--------- 2 files changed, 60 insertions(+), 41 deletions(-) create mode 100644 Book/php7/zend_engine/images/map_ptr.png diff --git a/Book/php7/zend_engine/images/map_ptr.png b/Book/php7/zend_engine/images/map_ptr.png new file mode 100644 index 0000000000000000000000000000000000000000..3b394dc0c6621c997557bb7425e417139a6bbc03 GIT binary patch literal 35695 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 b{BPK+w4d*K4(vgzgu(Q*jFFEop(6edEAm{C literal 0 HcmV?d00001 diff --git a/Book/php7/zend_engine/zend_opcache.rst b/Book/php7/zend_engine/zend_opcache.rst index f9cb24c5..c65c3d7b 100644 --- a/Book/php7/zend_engine/zend_opcache.rst +++ b/Book/php7/zend_engine/zend_opcache.rst @@ -1,49 +1,66 @@ -Zend OPCache +Zend Opcache ============ While PHP is an interpreter, it does not interpret PHP source code directly. Instead, the source code is first parsed -into an abstract syntax tree (AST), which is then compiled to OPcodes (and used to generate classes and other data +into an abstract syntax tree (AST), which is then compiled to opcodes (and used to generate classes and other data structures), which are then passed to the Zend virtual machine (Zend VM) to actually be interpreted. As you can see, there are quite a few steps involved to run a single PHP file. Without an additional extension, PHP will perform all of these steps for every single loaded file in every single request. Since usually PHP files don't -change between requests both the parsing and compilation steps will always yield the same result. OPcache is an -extension that caches the OPcodes and data structures like classes between requests to improve performance. The AST is +change between requests both the parsing and compilation steps will always yield the same result. Opcache is an +extension that caches the opcodes and data structures like classes between requests to improve performance. The AST is not used after the compilation step (with the exception of constant expressions) and thus does not need to be cached. Normally, all the memory allocated during the processing of a request gets freed after the request has been processed. -So to store the compiled OPcodes for future requests OPcache puts them in a shared memory segment (shm) that can not -only be accessed by the same process after the request has finished but also by other processes handling other -requests. This means that if you are using php-fpm with many children they will only store the OPcodes for each PHP -file once in shm. +So to store the compiled opcodes for future requests opcache puts them in a shared memory segment (SHM) that can not +only be accessed by the same process after the request has finished but also by other processes handling other requests. +This means that if you are using php-fpm with many children they will only store the opcodes for each PHP file once in +SHM. -This comes with a significant restriction: The OPcodes and other data structures in shm must not be mutated by any -child request (at least not unless these changes should also affect the other processes). If any changes to shm are +This comes with a significant restriction: The opcodes and other data structures in SHM must not be mutated by any +child request (at least not unless these changes should also affect the other processes). If any changes to SHM are made there is a locking mechanism to avoid data races. -The classes and OParrays (arrays of OPcodes, i.e. functions) in shm are mostly immutable. There are currently three -exceptions: +The classes and OParrays (arrays of opcodes, i.e. functions) in SHM are mostly immutable. There are currently the +following exceptions: * ``zend_persistent_script.dynamic_members`` stores information about the state of the cached script * ``zend_class_entry.inheritance_cache`` is extended if a new combination of parent class and interfaces is encountered -* ``zend_op_array.handler`` can be replaced at runtime by the tracing JIT to start executing JITted code +* ``zend_op.handler`` can be replaced at runtime by the tracing JIT to start executing JITted code +* ``zend_string.gc.refcount`` for persistent strings can be replaced with map ptr offset to cache class lookups by name map_ptr ------- -As mentioned in the introduction, shm is shared for all child processes. Thus, no changes can be made to the data -structures living in shm unless 1. the changes are supposed to be reflected in all child processes and 2. the shm +As mentioned in the introduction, SHM is shared for all child processes. Thus, no changes can be made to the data +structures living in SHM unless 1. the changes are supposed to be reflected in all child processes and 2. the SHM segment has been locked before any changes are written to avoid data races. -Sometimes the data structures contain a field that should be unique per process or request. The ``map_ptr`` mechanism +Sometimes the data structures contain a field that should be different per process or request. The ``map_ptr`` mechanism can be used to achieve this. In short, instead of storing a pointer to per-process data directly (as that would affect -all processes), a unique offset is assigned during compilation. During runtime, local memory is allocated to hold -enough space for all the entries referenced in these offsets. Each offset then corresponds to an item in the local -memory segment without needing to know the per-process location of the exact element. +all processes but each having different addresses for this process specific data), a unique offset is assigned during +compilation. During runtime, local memory is allocated to hold enough space for all the entries referenced in these +offsets. Each offset then corresponds to an item in the local memory segment without needing to know the per-process +location of the exact element. -Here is an example from php-src. Classes can contain data that needs to be evaluated at runtime, called -``mutable_data``. This ``mutable_data`` contains fields like ``default_properties_table``, ``constants_table`` and more. -``ZEND_MAP_PTR_DEF`` can be used to declare a field that holds the offset into local memory. +The map ptr can also store real pointers. This can be useful when the data structure doesn't live in SHM and thus +doesn't need to store the value in a separate map. The fact that pointers are aligned by their size is used to +differentiate between offsets and real pointers. The offsets start at 1, 9, 17, etc (assuming a 64-bit pointer size). +However, pointers (unless padding was removed) would not get aligned this way. Instead, they would be stored in +addresses that end with 0x0 or 0x8 given that they are 8-byte aligned. The macro ``ZEND_MAP_PTR_IS_OFFSET`` will be used +internally to check if the ``0b1`` byte is set. If it is, the value stored is an offset. Otherwise it's a direct +pointer. + +Here is an example from php-src. + +.. image:: ./images/map_ptr.png + :align: center + +Classes can contain data that needs to be evaluated at runtime, called ``mutable_data``. This ``mutable_data`` contains +fields like ``default_properties_table``, ``constants_table`` and more. ``ZEND_MAP_PTR_DEF`` can be used to declare a +field that holds the offset into local memory or direct pointer. + +:: struct _zend_class_entry { // ... @@ -51,35 +68,37 @@ Here is an example from php-src. Classes can contain data that needs to be evalu // ... }; -``ZEND_MAP_PTR_INIT`` assigns a value directly to the underlying offset field. This must only be done when the -structure is not yet in shm. +``ZEND_MAP_PTR_INIT`` assigns a value directly to the underlying offset field. This must only be done when the structure +is not yet in SHM. In practice, this marco should usually only be used to initialize the map ptr to ``NULL``. + +:: ZEND_MAP_PTR_INIT(ce->mutable_data, NULL); ``ZEND_MAP_PTR_NEW`` can be used to generate a new offset and store it in the given field. This must only be done when -the structure is not yet in shm. +the structure is not yet in SHM. This step can be skipped if the data structure is not intended to be stored in SHM and +thus doesn't need any pointer indirection. + +:: ZEND_MAP_PTR_NEW(ce->mutable_data); -Once an offset has been assigned to the map ptr ``ZEND_MAP_PTR_SET_IMM`` can be used to assign the value in local memory -with the given offset stored in the map ptr. +To assign a pointer to the map ptr you can use the ``ZEND_MAP_PTR_SET`` macro. It will automatically store it in the +local map (through ``ZEND_MAP_PTR_SET_IMM``) or in the map ptr itself (through ``ZEND_MAP_PTR_INIT``) depending on +whether it contains an offset or a real pointer (or ``NULL``). ``ZEND_MAP_PTR_SET_IMM`` should usually not be called +directly as it assumes the underlying value is an offset, which is not a always a safe assumption. - ZEND_MAP_PTR_SET_IMM(class_type->mutable_data, mutable_data); +:: -And to retrieve the value from local memory ``ZEND_MAP_PTR_GET_IMM`` can be used. + ZEND_MAP_PTR_SET(ce->mutable_data, mutable_data); - zend_class_mutable_data *mutable_data = ZEND_MAP_PTR_GET_IMM(class_type->mutable_data); +``ZEND_MAP_PTR_GET`` can be used to retrieve the pointer regardless of whether it's stored as an indirect of direct +pointer. Once again, there's ``ZEND_MAP_PTR_GET_IMM`` which usually shouldn't be called directly. -To summarize, with this mechanism, the relative offset ``mutable_data`` is the same for each process. The local map -itself lives at a different address in each process. The associated item will be retrieved by adding the given offset -to the base of the map. +:: -The map ptr can also store real pointers. This can be useful when the data structure doesn't live in shm and thus -doesn't need to store the value in a separate map. The fact that pointers are aligned by their size is used to -differenciate between offsets and real pointers. The offset start at 1, 9, 17, etc (assuming a 64-bit pointer size). -However, pointers (unless padding was removed) would not get aligned this way. Instead, they would be stored in -addresses that end with 0x0 or 0x8 given that they are 8-byte aligned. + zend_mutable_data *mutable_data = ZEND_MAP_PTR_GET(ce->mutable_data); -To store a real pointer you can use the ``ZEND_MAP_PTR_INIT`` macro. To retrieve a pointer regardless of whether a real -pointer or an offset is stored use the ``ZEND_MAP_PTR_GET`` macro. There's also the ``ZEND_MAP_PTR_SET`` macro that will -call ``ZEND_MAP_PTR_SET_IMM`` or ``ZEND_MAP_PTR_INIT`` depending on whether an offset is already stored in the map ptr. +To summarize, with the map ptr mechanism the relative offset to ``mutable_data`` is the same for each process. The local +map itself lives at a different address in each process. The associated item will be retrieved by adding the given offset +to the base of the local map.