You are on page 1of 59

Performance Tuning PHP

Welcome! Performance Tuning PHP 2005-05-29 0

Performance Tuning PHP

January 23th 2004. Vancouver, Canada
Ilia Alshanetsky

© Copyright 2004 Ilia Alshanetsky [5/29/2005 3:48:38 PM]

Performance Tuning PHP

Compiling: CFLAGS Performance Tuning PHP 2005-05-29 1

The first step to tuning PHP begins with compiling an optimized version of PHP.

● • Enable all compiler optimizations with -O3

● • Make the compiler tune the code to your CPU via -march -mcpu Use
● • Try to make the compiler use CPU specific features -msse -mmmx -
Revised Build Procedure

export CFLAGS="-O3 -msse -mmmx -march=pentium3 -mcpu=pentium3 -funroll-loops -

make install [5/29/2005 3:48:42 PM]

Performance Tuning PHP

Compile what you need Performance Tuning PHP 2005-05-29 2

Avoid useless bloat and compile only the extensions you need.
Extensions that are rarely used, should be compiled as shared modules
and loaded by the few scripts requiring them.
--disable-all is your friend. [5/29/2005 3:48:45 PM]

Performance Tuning PHP

Static vs Dynamic Performance Tuning PHP 2005-05-29 3

For maximum performance compile PHP statically into apache (up to

20% speed increase)
Static Compile of PHP

./configure --with-apache=/path/to/apache_source

# Apache
./configure --activate-module=src/modules/php4/libphp4.a

Increased speed comes at a cost of a slightly longer installation procedure, requiring Apache recompile
every time PHP is upgraded. [5/29/2005 3:48:47 PM]

Performance Tuning PHP

Strip your binaries Performance Tuning PHP 2005-05-29 4

Eliminate waste by removing symbols from object files using strip


Saves disk space and more importantly memory needed to load the
library or run the binary. In case of PHP makes the binary or Apache
library 20-30% smaller. [5/29/2005 3:48:49 PM]

Performance Tuning PHP

PHP Configuration (php.ini) Performance Tuning PHP 2005-05-29 5

PHP configuration directives can have significant impact on

performance of PHP applications.
● • Make sure that register_globals is disabled (default since 4.2.0)
● • Disable magic_quotes_* directives.
● • make sure your applications will escape input when necessary
● • Turn off expose_php
● • Turn off register_argc_argv for non-cli SAPIs
● • Unless absolutely necessary do not enable
always_populate_raw_post_data [5/29/2005 3:48:51 PM]

Performance Tuning PHP

PHP Configuration Cont. Performance Tuning PHP 2005-05-29 6

For non-persistent SAPIs like CLI prevent long searches for php.ini, by
placing the file where PHP would look for it first.



./php-cgi-fcgi.ini [5/29/2005 3:48:53 PM]

Performance Tuning PHP

Apache Configuration Performance Tuning PHP 2005-05-29 7

Since the webserver plays an important part in the request

serving process, it is important to tune it. A big part of this is
the Apache child creation process.
● • StartServers set to avg. # of requests you'd expect.
● • MaxSpareServers keep this number high, to allow Apache to gracefully handle
traffic spikes.
● • MaxClients keep this number at about 2/5 of the maximum processes your server
can handle.
● • MaxRequestsPerChild ideally unlimited (0), but practically should be limited to
a large number. [5/29/2005 3:48:56 PM]

Performance Tuning PHP

Apache Configuration Cont. Performance Tuning PHP 2005-05-29 8

Reducing File IO
● • Keep DirectoryIndex file list as short as possible.
● • Whenever possible disable .htaccess via AllowOverride none
● • Use Options FollowSymLinks to simplify file access process
in Apache
● • Avoid using mod_rewrite or at least complex regexs
● • If logs are unnecessary disable them.
● • If logging is a must, log everything to 1 file, and break it up during
analysis stage. [5/29/2005 3:48:58 PM]

Performance Tuning PHP

Apache Configuration Cont. Performance Tuning PHP 2005-05-29 9

Eliminate Expensive System Calls

● • Do not enable ExtendedStatus (prevents 2 calls to
timing functions per request).
● • For Deny/Allow rules use IPs rather then domains. (prevents
superfluous DNS lookups).
● • Do not enable HostnameLookups (DNS is slow).
● • This can be done during log analysis when speed is not an issue.
● • Keep ServerSignature off (do not sent Apache identification
string) [5/29/2005 3:49:00 PM]

Performance Tuning PHP

KeepAlive Performance Tuning PHP 2005-05-29 10

In theory KeepAlive is supposed to make things faster, however if not

used carefully it can cripple the server.
● • Set KeepAlive timeout, KeepAliveTimeout as low as possible.

If the server is only serving dynamic requests, disable KeepAlive. [5/29/2005 3:49:03 PM]

Performance Tuning PHP

lingerd Performance Tuning PHP 2005-05-29 11

Lingerd is a daemon (service) designed to take over the job of properly closing network connections from an
http server like Apache.
Because of some technical complications in the way TCP/IP and HTTP work, each Apache process
currently wastes a lot of time "lingering" on client connections, after the page has been generated and sent.
Lingerd takes over this job, leaving the Apache process immediately free to handle a new connection. As a
result, Lingerd makes it possible to serve the same load using considerably fewer Apache processes.
Warning: will only work (properly) if KeepAlive is disabled. [5/29/2005 3:49:05 PM]

Performance Tuning PHP

Optimizing Content Serving Performance Tuning PHP 2005-05-29 12

Virtually any webpage is the combination of dynamic (php) and static

content (images, CSS, JavaScript, etc...)
For maximum performance it is best to separate the serving of dynamic
and static content.
● • Ability to disable KeepAlive for server handling dynamic data.
● • Simpler and Faster serving numerous static requests.
● • Allow more complex configuration (.htaccess, mod_rewrite) for dynamic data
without affecting static content
● • Easy distribution of the content serving load across servers. [5/29/2005 3:49:07 PM]

Performance Tuning PHP

Static Content Web Servers Performance Tuning PHP 2005-05-29 13

Web Servers ideal for serving static requests

TUX - kernel-based web server
● • Virtual Host support.

thttpd - tiny/turbo/throttling HTTP server

● • Non-blocking I/O is good.
● • Throttling capabilities. [5/29/2005 3:49:09 PM]

Performance Tuning PHP

OPcode Caching Performance Tuning PHP 2005-05-29 14

The first step in the script execution is the conversion of said script into
a series instructions (opcodes), which the Zend Engine can understand
and run.

Since scripts rarely change, an obvious optimization is to cache the

opcodes so that the scripts do not need to be parsed every time. [5/29/2005 3:49:11 PM]

Performance Tuning PHP

OPcode Caching Cont. Performance Tuning PHP 2005-05-29 15 [5/29/2005 3:49:14 PM]

Performance Tuning PHP

OPcode Cache Benefits Performance Tuning PHP 2005-05-29 16

● • Script parsing performed only once.

● • Significant reduction in FileIO.
● • Faster execution, thanks to optimized opcodes.
● • Elimination of certain function calls by the optimizer. [5/29/2005 3:49:16 PM]

Performance Tuning PHP

Cache Implementations Performance Tuning PHP 2005-05-29 17

● • Turck MMCache (GPL)

● • Implements many features beyond opcode caching.

● • Development halted.

● • APC (PHP)
● • Slow, but steady progress.

● • Weak optimizer.

● • ionCube PHP Accelerator

● • It works, but no new development in past year.

● • Free, but closed source.

● • Zend Cache (Proprietary)

● • Implements many features beyond opcode caching.

● • $$$ [5/29/2005 3:49:18 PM]

Performance Tuning PHP

Cache Benchmarks Performance Tuning PHP 2005-05-29 18 [5/29/2005 3:49:21 PM]

Performance Tuning PHP

Content Caching Performance Tuning PHP 2005-05-29 19

Often enough output of PHP scripts can remain static for an extended period of time. In these
cases, certain actions can be eliminated, resulting in a faster script execution.

When the content changes, generate static versions of the affected pages, taking PHP out of the
equation completely.

On demand
Same as pre-generation, only the content is not generated until the 1st request for the specified
content arrives. [5/29/2005 3:49:23 PM]

Performance Tuning PHP

Content Caching in PHP Performance Tuning PHP 2005-05-29 20

function cache_start()
global $cache_file_name, $age;

// a superbly creative way for creating cache files

$cache_file_name = __FILE__ . '_cache';

// default cache age

if (empty($age)) $age = 600;

// check if cache exists and if the cached data is still valid

if (@filemtime($cache_file_name) + $age > time()) {
// Yey! cache hit, output cached data and exit

// nothing in cache or cache is too old


function cache_end() (1 of 2) [5/29/2005 3:49:25 PM]
Performance Tuning PHP

global $cache_file_name;

// nothing to do
if (empty($cache_file_name)) return;

// fetch output of the script

$str = ob_get_clean();

// output data to the user, so they don't need to wait

// for the cache writing to complete
echo $str;

// write to cache
fwrite(fopen($cache_file_name.'_tmp', "w"), $str);
// atomic write
rename($cache_file_name.'_tmp', $cache_file_name);


// set cache termination code as the exit handler

// this way we don't need to modify the script
?> (2 of 2) [5/29/2005 3:49:25 PM]

Performance Tuning PHP

Content Caching in PHP Cont. Performance Tuning PHP 2005-05-29 21

require "./cache.php"; // our cache code

// Simple guestbook script.

$db = new sqlite_db("gb.sqlite");
$r = $db->array_query("SELECT * FROM guestbook", SQLITE_ASSOC);
foreach ($r as $row) {
echo $r->user . ' wrote on ' . date("Ymd", $r->date) . ":<br />\n";
echo $r->message . "<hr /><hr />";

Implementing cache without modifying the script

# Add to .htaccess
php_value auto_prepend_file "/path/to/cache.php"

# Or to virtual host entry in httpd.conf

php_admin_value auto_prepend_file "/path/to/cache.php" [5/29/2005 3:49:27 PM]

Performance Tuning PHP

Better Content Caching Performance Tuning PHP 2005-05-29 22

As nice as PHP caching is, it is still slow, and who wants to spend time
implementing it?
Fortunately, both Zend and MMcache developers have realized this need and developed a
content caching mechanism into their PHP acceleration packages.
MMCache Content Cache

mmcache_cache_page(__FILE__, 600); // MMcache cache

// Simple guestbook script.

$db = new sqlite_db("gb.sqlite");
$r = $db->array_query("SELECT * FROM guestbook", SQLITE_ASSOC);
foreach ($r as $row) {
echo $r->user . ' wrote on ' . date("Ymd", $r->date) . ":<br />\n";
echo $r->message . "<hr /><hr />";
?> [5/29/2005 3:49:29 PM]

Performance Tuning PHP

Why is it better? Performance Tuning PHP 2005-05-29 23

● • Faster (C is faster PHP).

● • Can easily store cache in memory or disk or both.
● • Better atomicity.
● • Supports zlib compression for cached pages.
● • Bypasses PHP completely.
● • No need to write/test/debug any code. [5/29/2005 3:49:31 PM]

Performance Tuning PHP

Partial Caching Performance Tuning PHP 2005-05-29 24

I'd like to use caching, but my content is completely dynamic and

cannot be time delayed.
Even the most dynamic pages, often have static elements generated by
PHP. Partial caching can accelerate the page generation by caching the
static portions of otherwise dynamic pages. [5/29/2005 3:49:33 PM]

Performance Tuning PHP

Partial Caching in Action Performance Tuning PHP 2005-05-29 25

// Authenticates a user and stores their id inside $uid
require "./";

function header()
if ($uid) echo "Welcome {$GLOBALS['user_nick']}";
echo rest_of_header();

function footer()
if ($uid)
echo "Logout: <a href='/logout.php'>{$GLOBALS['user_nick']}</a>";
echo rest_of_footer();

// cache the output of the header function

// we append $uid to they key to ensure each user has their own
// non conflicting entry.
mmcache_cache_output(__FILE__ . $uid, 'header();', 60 * 24);

// rest of the dynamic page (1 of 2) [5/29/2005 3:49:35 PM]

Performance Tuning PHP

// cache the output of the footer for 24 minutes (avg. session length)
mmcache_cache_output(__FILE__ . $uid, 'footer();', 60 * 24);
?> (2 of 2) [5/29/2005 3:49:35 PM]

Performance Tuning PHP

Content Reduction Performance Tuning PHP 2005-05-29 26

One way to make pages appear faster is to reduce the

amount of data that needs to be sent.

Benefits of Content Reduction

● • Less data to send, leads to smaller bandwidth bill.
● • Pages appear faster for the users, especially those on slower
● • Less network IO, frees up server processes faster. [5/29/2005 3:49:38 PM]

Performance Tuning PHP

Content Reduction: Compression Performance Tuning PHP 2005-05-29 27

The easiest way to reduce amount of sent data is by

compressing it.
● • Text output drastically reduced.
● • Requires no or very little modification to the code.
● • Supported by majority of modern browsers.

● • May increase CPU load by up to 10%
● • Some browsers claim to support it, but really don't. [5/29/2005 3:49:40 PM]

Performance Tuning PHP

Content Reduction: CSS Performance Tuning PHP 2005-05-29 28

Another way to reduce content, is to replace bulky legacy

HTML elements with CSS.
● • 20-30% smaller pages.
● • CSS can be moved to static files and be served independently.
● • In some cases makes the browser render page faster.
● • More flexible layout.

● • Can be A LOT of manual labor.
● • Older browsers (Netscape 4.0) do not support CSS.
● • Some CSS is rendered differently or is unsupported all together. [5/29/2005 3:49:42 PM]
Performance Tuning PHP

Content Reduction: Compacting Performance Tuning PHP 2005-05-29 29

HTML contains a large quantity of useless data such as whitespace,

comments etc... that is normally used to make the output readable to the
In production no one other then the browser will be reading the HTML we
can use the tidy extension to strip all the unnecessary bits.

● • 10-30% smaller pages.
● • While compressing HTML can fix HTML bugs.

● • Requires Tidy extension.
● • CPU costs make this useful only if the output is cached. [5/29/2005 3:49:44 PM]

Performance Tuning PHP

Tidy Example Performance Tuning PHP 2005-05-29 30

Compacting Tidy Config

indent: no
hide-endtags: yes
char-encoding: ascii
word-2000: yes
clean: yes
bare: yes
show-errors: 0
show-warnings: no
quiet: yes
drop-proprietary-attributes: yes
hide-comments: yes
wrap: 0

PHP script bit

ini_set("tidy.default_config", "/path/to/compact_tidy.cfg");
ini_set("tidy.clean_output", 1);
?> [5/29/2005 3:49:46 PM]

Performance Tuning PHP

File IO Performance Tuning PHP 2005-05-29 31

Most PHP scripts perform File IO operations, whether it be inclusion of

scripts or opening or writing to files. One common mistake made by
developers often makes these operations much slower then necessary.

How NOT to open files

include "file.php";
?> [5/29/2005 3:49:47 PM]

Performance Tuning PHP

File IO Cont. Performance Tuning PHP 2005-05-29 32

Always use full path file path when opening files, to avoid expensive
normalization of the file's path.

// or
include "./file.php";
?> (1 of 2) [5/29/2005 3:49:49 PM]
Performance Tuning PHP

This is very important even if you use opcode cache, since the paths of
includes and normal files will still need to be resolved. (2 of 2) [5/29/2005 3:49:49 PM]

Performance Tuning PHP

RAM Disk Performance Tuning PHP 2005-05-29 33

One way to accelerate File IO operations is by moving the files to a

RAM disk.
On Linux this is extremely simple todo using via tmpfs.
tmpfs acceleration

# Speed Up /tmp Directory

mount --bind -ttmpfs /tmp /tmp

# Accelerate Scripts Directory

mount --bind -ttmpfs /home/webroot /home/webroot [5/29/2005 3:49:51 PM]

Performance Tuning PHP

RAM Disk Cont. Performance Tuning PHP 2005-05-29 34

● • Significant improvement in all File IO operations.
● • Easy to use.

● • Can end up using A LOT of memory. [5/29/2005 3:49:53 PM]

Performance Tuning PHP

Sessions Performance Tuning PHP 2005-05-29 35

Common element of various PHP scripts are sessions.

Generic Session Optimizations
● • Don't use session.auto_start.
● • Do not enable session.use_trans_sid
● • Whenever possible set session.cache_limiter to
● • Assign each user (vhost) it's own sessions directory.
● • For large sites consider using session.save_path = "N;/path"
● • If possible avoid automatic garbage collection. [5/29/2005 3:49:55 PM]

Performance Tuning PHP

Sessions Cont. Performance Tuning PHP 2005-05-29 36

The surest way to accelerate sessions is by moving away from the files session handler to a
memory based one.

Memory Session Handlers

● • tmpfs
● • mount the session directory as a RAM disk.

● • not available on all OSes

● • --with-mm
● • available with every PHP version.

● • not thread-safe

● • mmcache
● • very fast

● • work on virtually all OSes and is thread-safe

● • you need mmcache [5/29/2005 3:49:57 PM]

Performance Tuning PHP

SQL Performance Tuning PHP 2005-05-29 37

Virtually every script uses some database system.

How it is used can be the difference between a fast
script and an extremely slow one.
All optimizations can be for naught if the SQL
queries executed are slow. [5/29/2005 3:50:00 PM]

Performance Tuning PHP

SQL: Explain Performance Tuning PHP 2005-05-29 38

Always use EXPLAIN to analyze your queries to determine if they

use proper indexes.
Slow Query

EXPLAIN select * from mm_users where login LIKE '%ilia%';

| table | type | possible_keys | key | key_len | ref | rows | Extra |
| mm_users | ALL | NULL | NULL | NULL | NULL | 27506 | where used |

Fast Query

EXPLAIN select * from mm_users where login LIKE 'ilia%';

| table | type | possible_keys | key | key_len | ref | rows | (1 of 2) [5/29/2005 3:50:02 PM]

Performance Tuning PHP

Extra |
| mm_users | range | login | login | 50 | NULL | 2 | where used
+ (2 of 2) [5/29/2005 3:50:02 PM]

Performance Tuning PHP

SQL: Query Chaining Performance Tuning PHP 2005-05-29 39

Executing one query at a time is boring (and slow), chain them and
execute many queries at once.
Query Chaining

// Slow Approach
for ($i = 0; $i < 10; $i++)
mysql_query("INSERT INTO foo VALUES({$i})");

// Faster MySQL/SQLite Specific approach

$query = "INSERT INTO foo VALUES";
$query = "(" . implode("),(", array_keys(array_fill(0, 10, 1))) . ")";
// INSERT INTO foo VALUES (0), (1), (2) ...

// Query Chaining
// for DBs that support it PostgreSQL, MSSQL, SQLite, MySQL 4.0+
$query = '';
for ($i = 0; $i < 10; $i++)
$query .= "INSERT INTO foo VALUES({$i});";
mysql_query($query); (1 of 2) [5/29/2005 3:50:04 PM]
Performance Tuning PHP

?> (2 of 2) [5/29/2005 3:50:04 PM]

Performance Tuning PHP

SQL: Avoiding Locks Performance Tuning PHP 2005-05-29 40

To ensure data integrity in certain situations you will need to use

locks. However, overuse of locks or improper implementation can
severely hinder the performance of your application.
● • If supported, whenever possible use row level locks instead of table locks.
● • When using table locks, try to lock as few tables as possible.
● • Whenever possible avoid locks all together. [5/29/2005 3:50:07 PM]

Performance Tuning PHP

SQL: MySQL 4.0 Performance Tuning PHP 2005-05-29 41

If you are using MySQL 3.23.X, consider switching to MySQL


Performance Advantages
● • Query Cache
● • Sub-Queries (as of 4.0.4)
● • Faster bulk inserts
● • Improved FULLTEXT [5/29/2005 3:50:08 PM]

Performance Tuning PHP

SQL: Joins Performance Tuning PHP 2005-05-29 42

Usage of joins allows simplification & acceleration of the script by

moving portions of the logic to the database engine.

// slow joinless approach
$a = sqlite_fetch_single($db, "SELECT id FROM foo WHERE name='ilia'");
$b = sqlite_array_query($db, "SELECT * FROM bar WHERE id={$a}");

// Fast Join implementation

$b = sqlite_array_query($db,
"SELECT b.* FROM foo f INNER JOIN bar b ON WHERE'ilia'");

Join Gotchas
● • Unoptimized joins can be VERY slow.
● • Internal (read) lock on all tables involved. [5/29/2005 3:50:11 PM]

Performance Tuning PHP

SQL: Sub-queries Performance Tuning PHP 2005-05-29 43

Like Joins, Sub-queries can be used to move some of the logic

from PHP into the database engine.

$b = sqlite_array_query($db,
"SELECT * FROM bar WHERE id=(SELECT id FROM foo WHERE name='ilia')");

In MySQL, the full support for sub-queries starts from version 4.1
In many instances it is better to use Joins rather then sub-queries. [5/29/2005 3:50:13 PM]

Performance Tuning PHP

SQL: Temporary Tables Performance Tuning PHP 2005-05-29 44

Temporary tables are memory buffers that can be used as in

between steps for data retrieval, to avoid complex (and slow) PHP

// Quickly fetch the ids of needed messages
thread_id={$_GET['th']} AND apr=1
ORDER BY id ASC LIMIT {$count}, {$_GET['start']}");

// Retrieve needed data by using the temporary table as base

$result = mysql_query("SELECT * FROM mtmp mt
INNER JOIN thread t ON
LEFT JOIN users u ON
LEFT JOIN level l ON
LEFT JOIN poll_opt_track pot ON (1 of 2) [5/29/2005 3:50:15 PM]

Performance Tuning PHP

AND pot.user_id="._uid."
?> (2 of 2) [5/29/2005 3:50:15 PM]

Performance Tuning PHP

SQL: Right Tool for the Job Performance Tuning PHP 2005-05-29 45

It is important that you choose the right database

system for your needs.
An overly complex database system, who's
features you do not use will only hinder performance.
At the same time be cautious with overly simple database
systems that lack features you may need. [5/29/2005 3:50:20 PM]

Performance Tuning PHP

Regular Expressions Performance Tuning PHP 2005-05-29 46

PHP being is often using for templating and as such often needs to
manipulate strings, which is often done with Regular Expressions.

Unfortunately, the flexibility that makes regular expressions so useful,

also makes them extremely slow. [5/29/2005 3:50:22 PM]

Performance Tuning PHP

Regular Expressions Cont. Performance Tuning PHP 2005-05-29 47

Significant speed gains can be made by replacing regular

expression with one or more string functions offered by

Common Alternatives
● • Replacement - str_replace, substr_replace, strtr, etc...
● • Matching - strpos, stripos, strchr, strrchr, etc..
● • Type Checking - ctype extension (enabled by default)
● • Comparison - strcmp, strncasecmp, etc... [5/29/2005 3:50:24 PM]

Performance Tuning PHP

Regular Expressions Cont. Performance Tuning PHP 2005-05-29 48

In some situations, regular expressions would take too long

to replace. Now you need to decide which regular
expression implementation you want ereg or PCRE.
● • PCRE
● • Much faster in most cases.

● • UTF-8 support.

● • Significantly greater functionality.

● • ereg
● • Always available.

● • Can operate on multi-byte strings w/mbstring extension. [5/29/2005 3:50:26 PM]

Performance Tuning PHP

Type Conversion Performance Tuning PHP 2005-05-29 49

PHP is a type less language, which can seamlessly manipulate variables

containing any sort of data.
However, forgetting about the underlying types can make your application slow and potentially
open to security vulnerabilities.
Forcing correct type via casting

$_GET['n_entries'] = (int) $_GET['n_entries'];

Type conversion prevents things like SQL injection due to unexpected input. It also optimizes
the application by providing PHP with a type it expects, rather having to internally perform type
conversions each time the variable is used. [5/29/2005 3:50:28 PM]

Performance Tuning PHP

References Tricks Performance Tuning PHP 2005-05-29 50

Optimize passing of large objects by passing them by reference (PHP 4).

function display_function(&$obj) { ... }

$obj = mysql_fetch_object($result);

When modifying complex or large variables inside a function/method.

function template_apply(&$str)
$str = str_replace(..., ..., $str);

Simplify and Speed up access to large multi-dimensional arrays (1 of 2) [5/29/2005 3:50:31 PM]

Performance Tuning PHP

$foo =& $bar['foo']['bar']['test'];
$foo['imp'] = implode(',', $foo);
$foo['imp'] = addslashes($foo['imp']);
?> (2 of 2) [5/29/2005 3:50:31 PM]

Performance Tuning PHP

Thank You Performance Tuning PHP 2005-05-29 51

Online Resources
Turck MMcache:

Contact Me
Ilia Alshanetsky [5/29/2005 3:50:33 PM]