Skip to content

Instantly share code, notes, and snippets.

@krakjoe
Created November 5, 2013 19:28
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save krakjoe/962e54c38b155f896b00 to your computer and use it in GitHub Desktop.
Save krakjoe/962e54c38b155f896b00 to your computer and use it in GitHub Desktop.
opcache.md

How does opcache make code faster ??

Opcache replaces APC as the defacto opcode cache for PHP.

An opcode cache improves performance by caching the opcodes produced during compilation, thereby eliminating the compilation step for every subsequent request for that same code.

In addition to this, Opcache performs optimization on the opcodes before they are stored.

Preparation

Zend uses a second pass during compilation, pass_two() has the following responsabilities:

  • resolve finally blocks
  • execute zend_extension op array handlers
  • set op1/op2 zval pointers from literal array for constant values (offset to address conversion)
  • resolve goto labels
  • set jmp_addr from opline_num (offset to address conversion)

In order to perform optimization some of these actions must be reversed:

  • set op1/op2 constant values from literal array (address to offset conversion)
  • set opline_num from jmp_addr (address to offset conversion)

Optimizer now has the op array in a state that it can manipulate easily, almost as it was before pass_two() was executed.

Pass 1

Optimizations:

  1. substitute persistent constants
  2. evaluate constant binary and unary operations
  3. optimize series of ZEND_ADD_STRING and ZEND_ADD_CHAR
  4. perform constant ZEND_CAST

Impact:

  1. constant values such as true, false and null are compiled to unique zvals, this replaces such values with persistent constants
  2. easier for us to write $day = 24 * 60 * 60, however, Zend is tripping over your lazyness !!!
  3. echo "Hello {$world}"; if $world is a constant the string may be [partly] constructed now
  4. casting constants is something that makes things easier for humans to read but produces pointless opcodes

Pass 2

Optimizations:

  1. convert non-numeric constants to numeric constants in numeric operators
  2. optimize constant conditional JMP
  3. optimize static break; and continue;

Impact:

  1. more magical casting that would otherwise occur at execution time
  2. a constant condidional JMP can be converted to a JMP or possibly removed
  3. saves address computation at execution time

Pass 3

Optimizations:

  1. convert $i = $i+expr to $i+=expr
  2. convert JMP series
  3. change $i++ to ++$i where possible

Impact:

  1. decreases the number of opcodes required to execute the same instructions
  2. Zend jumps around for all kinds of reasons, there isn't a kind of jump that doesn't have chance at optimization, some, including those in series can be removed completely.
  3. $i++ must store a value before it can return, a small gain perhaps, unless you are incremeenting a string

Pass 4

Optimizations:

  1. convert ZEND_INIT_FCALL_BY_NAME to ZEND_DO_FCALL

Impact:

  1. INIT_FCALL_BY_NAME has to perform a hash table lookup upon execution, performing the lookup one single time here impacts countless opcodes executing countless times !!

Pass 5

Optimizations:

  1. perform block optimizations

Impact:

  1. using a control flow graph, each block is optimized, and unreachable blocks removed

Pass 6

Optimizations:

  1. optimize temporary variables

Impact:

  1. Many temporary variables created during compilation are no longer required, compacting the array here saves space in shared memory and makes copy out much more efficient.

Pass 7

Optimizations:

  1. NOP removal

Impact:

  1. Everything that has so far been NOP'd will now be removed, compacting the op array to the least number of opcodes possible.

Pass 8

Optimizations:

  1. compact literal array

Impact:

  1. Many of the literals compiled have been optimized away or replaced, so are no longer needed

Finalization

Opcache must then run a pass_two() like operation on the op array to make it ready for execution:

  • set op1/op2 zval pointers from literal array for constant values (offset to address conversion)
  • set jmp_addr from opline_num (offset to address conversion)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment