If we look at the last callgraph again, we see that we are spending close to 40% of our time
parsing and compiling. We can eliminate that by using an opcode cache like APC.
Callgraph [mysql.out]
php.ini
extension = "apc.so"
apc.enabled=1
apc.shm_segments=1
apc.shm_size=32
apc.num_files_hint=1024
apc.gc_ttl=3600
apc.ttl=0
apc.mmap_file_mask=/tmp/apc.XXXXXX
apc.filters=
apc.stat=1
apc.enable_cli=0
805 requests/second. Callgraph?
Callgraph [apc.out]
If we look carefully we see that over 5000 requests we are opening 20000 files. Main script plus
4 includes on each request. This is because include_once and require_once don't play nice with
opcode caches right now. Changing to require brings us to 875 requests/second.
APC also has a no-stat mode. If you give it absolute paths, it can skip the stat() call.
php.ini
config.inc
<?php
$config = array(
'db' => 'mysql',
'db_user' => 'nobody41',
'db_pwd' => 'foobar',
'db_host' => 'localhost',
'db_db' => 'users',
'db_opts' => array(PDO::ERRMODE_EXCEPTION => true,
PDO::ATTR_PERSISTENT => true,
PDO::MYSQL_ATTR_DIRECT_QUERY=>1),
'path' => getcwd()
);
?>
index.php
<?php
require "./config.inc";
require $config['path']."/model.inc";
require $config['path']."/utils.inc";
require $config['path']."/head.inc";
head();
foreach(articles() as $row) {
$name = upper($row['name']);
echo <<<EOB
<tr><th>$name</th><td>{$row['age']}</td><td>{$row['entry']}</td></tr>
EOB;
}
boo();
foot();
?>
This takes us to 885 requests/second. We are down to 2 machines!