rfc:jit
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revisionNext revisionBoth sides next revision | ||
rfc:jit [2019/02/04 08:37] – dmitry | rfc:jit [2019/02/13 09:27] – Minor fixes to State&compatibility zeev | ||
---|---|---|---|
Line 25: | Line 25: | ||
PHP JIT is implemented as an almost independent part of OPcache. It may be enabled/ | PHP JIT is implemented as an almost independent part of OPcache. It may be enabled/ | ||
- | When enabled, native code of PHP files is stored in an additional region of the OPcache shared memory and op_array-> | + | When enabled, native code of PHP files is stored in an additional region of the OPcache shared memory and op_array-> |
We use DynAsm (developed for LuaJIT project) for generation of native code. It's a very lightweight and advanced tool, but does assume good, and very low-level development knowledge of target assembler languages. | We use DynAsm (developed for LuaJIT project) for generation of native code. It's a very lightweight and advanced tool, but does assume good, and very low-level development knowledge of target assembler languages. | ||
+ | PHP JIT doesn' | ||
+ | |||
+ | If type of PHP variable is exactly inferred (in SSA) to LONG or DOUBLE, and it can't be accessed indirectly, JIT may store its value directly in CPU registers, avoiding memory stores and loads. PHP JIT liner-scan register allocation algorithm, tat combines high speed with reasonable quality. | ||
The quality of the JIT may be demonstrated on Mandelbrot benchmark published at https:// | The quality of the JIT may be demonstrated on Mandelbrot benchmark published at https:// | ||
Line 261: | Line 264: | ||
jmp .L10 | jmp .L10 | ||
</ | </ | ||
+ | |||
+ | In comparison to V8, HHVM, PyPy and most others modern JIT implementations PHP JIT is extremely simple, but anyway it increases the level of the whole PHP complexity, risk of new kind of bugs and cost of development and maintenance. | ||
===== Backward Incompatible Changes ===== | ===== Backward Incompatible Changes ===== | ||
Line 273: | Line 278: | ||
==== To Existing Extensions ==== | ==== To Existing Extensions ==== | ||
- | none | + | JIT is going to affect third party debuggers (e.g. xdebug) and profilers (e.g. XHProf, Blackfire, Tideways). |
+ | |||
+ | For debugging a particular request, it's possible to disable JIT (together with opcache) changing " | ||
+ | |||
+ | Run-time profiling should work even with JIT-ed code, but this might require development of additional tracing API and corresponding JIT extension, to generate tracing callbacks. | ||
==== To Opcache ==== | ==== To Opcache ==== | ||
Line 283: | Line 292: | ||
==== php.ini Defaults ==== | ==== php.ini Defaults ==== | ||
If there are any php.ini settings then list: | If there are any php.ini settings then list: | ||
- | * opcache.jit_buffer_size - size (in megabytes) | + | * opcache.jit_buffer_size - size of shared memory buffer reserved for native code generation |
* opcache.jit - JIT control options. Consists of 4 decimal digits - CRTO (Default 1205. Probably, better to change to 1235). | * opcache.jit - JIT control options. Consists of 4 decimal digits - CRTO (Default 1205. Probably, better to change to 1235). | ||
* O - Optimization level | * O - Optimization level | ||
Line 306: | Line 315: | ||
* 1 - enable AVX instruction generation | * 1 - enable AVX instruction generation | ||
* opcache.jit_debug - JIT debug control options, where each bit enabling some debugging options. Default - 0. | * opcache.jit_debug - JIT debug control options, where each bit enabling some debugging options. Default - 0. | ||
- | * (1<< | + | * (1<< |
* (1<< | * (1<< | ||
* (1<< | * (1<< | ||
- | * (1<<4) - allow debugging JIT-ed | + | * (1<<3) - print stubs assembler |
- | * (1<<5) - generate perf.map file to list JIt-ed functions in Linux perf report | + | * (1<<4) - generate perf.map file to list JIt-ed functions in Linux perf report |
+ | * (1<< | ||
* (1<< | * (1<< | ||
* (1<< | * (1<< | ||
- | * (1<< | + | * (1<< |
==== Performance ==== | ==== Performance ==== | ||
JIT makes bench.php more than two times faster: 0.140 sec vs 0.320 sec. It is expected to make most CPU-intensive workloads run significantly faster. | JIT makes bench.php more than two times faster: 0.140 sec vs 0.320 sec. It is expected to make most CPU-intensive workloads run significantly faster. | ||
+ | |||
+ | According to Nikita, PHP-Parser became ~1.3 times faster with JIT. Amphp hello-world.php got just 5% speedup. | ||
+ | |||
However, like the previous attempts - it currently doesn' | However, like the previous attempts - it currently doesn' | ||
+ | |||
+ | It's planned to provide additional effort, improving JIT for real-life apps, using profiling and speculative optimizations. | ||
+ | |||
+ | ==== JIT Debugging ==== | ||
+ | As any complication, | ||
+ | |||
+ | In case of crash, we may just run app under gdb until the crash, check that JIT is involved in crash backtrace and find the place: | ||
+ | |||
+ | < | ||
+ | $ gdb php | ||
+ | |||
+ | (gdb) r app.php | ||
+ | |||
+ | ... | ||
+ | |||
+ | (gdb) bt | ||
+ | |||
+ | #1 0xe960dc11 in ?? () | ||
+ | #2 0x08689524 in zend_execute (op_array=0xf4074460, | ||
+ | #3 0x085cb93b in zend_execute_scripts (type=8, retval=0x0, file_count=3) at Zend/ | ||
+ | #4 0x0855a890 in php_execute_script (primary_file=0xffffcbfc) at main/ | ||
+ | #5 0x0868ba25 in do_cli (argc=2, argv=0x9035820) at sapi/ | ||
+ | #6 0x0868c65b in main (argc=2, argv=0x9035820) at sapi/ | ||
+ | </ | ||
+ | |||
+ | Unknown function "??" | ||
+ | |||
+ | < | ||
+ | (gdb) p (char*)executor_global.current_execute_data.func.op_array.filename.val | ||
+ | (gdb) p executor_global.current_execute_data.opline.lineno | ||
+ | </ | ||
+ | |||
+ | Line number may be inaccurate, because JIT doesn' | ||
+ | We may disassemble the code around the bogus instruction to understand the real " | ||
+ | |||
+ | < | ||
+ | (gdb) disassemble 0xe960dc00, | ||
+ | </ | ||
+ | |||
+ | Also, it may be useful to analyse bytecode and assembler dump of the bogus JIT-ed function. | ||
+ | |||
+ | < | ||
+ | $ php --opcache.jit_debug=1 app.php | ||
+ | $ php --opcache.jit_debug=2 app.php | ||
+ | </ | ||
+ | |||
+ | To catch the mistake, we might need to trace the JIT code generator (when it generates the bogus code), or instrument it to generate breakpoint (int3 x86 instruction) and then trace the generated code. | ||
+ | |||
+ | PHP JIT may use GDB API to provide information about generated code to debugger. However, it works only for reasonable small scripts. In case of big amount of JIT-ed code, GDB just stuck registering functions. In case we can isolate the bogus code, we may debug JIT in more comfortable way. | ||
+ | |||
+ | < | ||
+ | $ gdb php | ||
+ | |||
+ | (gdb) r -dopcache.jit_debug=0x100 test.php | ||
+ | ... | ||
+ | |||
+ | (gdb) bt | ||
+ | |||
+ | #1 0xe960dc11 in JIT$foo () at test.php:2 | ||
+ | #2 0x08689524 in zend_execute (op_array=0xf4074460, | ||
+ | #3 0x085cb93b in zend_execute_scripts (type=8, retval=0x0, file_count=3) at Zend/ | ||
+ | #4 0x0855a890 in php_execute_script (primary_file=0xffffcbfc) at main/ | ||
+ | #5 0x0868ba25 in do_cli (argc=2, argv=0x9035820) at sapi/ | ||
+ | #6 0x0868c65b in main (argc=2, argv=0x9035820) at sapi/ | ||
+ | |||
+ | (gdb) disassemble | ||
+ | ... | ||
+ | (gdb) layout asm | ||
+ | </ | ||
+ | |||
+ | ===== State and compatibility ===== | ||
+ | Currently we only support x86 and x86_64 non-ZTS builds on POSIX platforms (tested on Linux). | ||
+ | We support only " | ||
+ | |||
+ | ZTS support is doable and shouldn' | ||
+ | |||
+ | LLVM and MSVC are not currently supported. Without JIT, bench.php is about 2 times faster on PHP built with GCC, compared to with LLVM or MSVC. LLVM and MSVC require support for "Call VM" (which was already implemented, | ||
+ | |||
+ | An alternative way to support all platforms and C compilers is generating a low-level VM (using the same JIT framework). This VM won't depend on C compiler extensions, and going to be compatible with JIT out of the box. As a side effect, interpretation should also become faster. This approach is used in the JVM template VM, the low level WebKit interpreter, | ||
===== Open Issues ===== | ===== Open Issues ===== | ||
Line 326: | Line 418: | ||
===== Proposed Voting Choices ===== | ===== Proposed Voting Choices ===== | ||
- | This project requires a 50%+1 majority. | + | Support for JIT is more a strategic PHP question. JIT definitely requires a lot of work, but it may be actively developed only as a part of PHP, with common effort. |
+ | |||
+ | This project requires a 2/3+1 majority. | ||
<doodle title=" | <doodle title=" | ||
Line 333: | Line 427: | ||
</ | </ | ||
- | As PHP 7.4 is already branched and its engine is not expected to be significantly changed (consequently requiring corresponding changes to the JIT implementation), | + | As PHP 7.4 is already branched and its engine is not expected to be significantly changed (consequently requiring corresponding changes to the JIT implementation), |
<doodle title=" | <doodle title=" |
rfc/jit.txt · Last modified: 2020/08/01 23:41 by carusogabriel