Performance Tuning in PHP

Post on 01-Sep-2014

38625 Views

Category:

Technology

5 Downloads

Preview:

Click to see full reader

DESCRIPTION

 

Transcript

Performance Tuning in PHP

PHPCAMP 200820th Sept.

Jignesh Thummar<jignesh.thummar@gmail.com>

Anatomy of PHP

PHP File

Zend Compiler

Execution at Zend Engine

● This cycle happens for all included files not only for main() script.

● Generally most of the time consumption take place at Compiler.

End User

Opcodes 0 EXT_STMT

1 ASSIGN !0, 'Enjoy+the+PHPCamp%2C+'

2 EXT_STMT

3 ASSIGN !1, 'Jignesh'

4 EXT_STMT

5 ZEND_ISSET_ISEMPTY_VAR 1 ~2 'name'

6 JMPZ ~2, ->11

7 EXT_STMT

8 CONCAT ~3 !0, !1

9 ASSIGN !2, ~3

10 JMP ->14

11 EXT_STMT

12 CONCAT ~5 !0, 'human'

13 ASSIGN !2, ~5

14 EXT_STMT

15 ECHO !2

16 EXT_STMT

17 RETURN 1

18* ZEND_HANDLE_EXCEPTION

<?php

$greet = 'Enjoy the PHPCamp, ';

$name = 'Jignesh';

if(isset($name)){

$say = $greet . $name;

}else{

$say = $greet . 'human';

}

echo $say;

?>

Opcodes generated using Vulcan Logic Disassembler (VLD) by Derick Rethans. http://pecl.php.net/packages/VLD/

Opcode/Compiler cache● Each PHP script (also for included files)

compiled only once and store into cache● during the next request it will not compile

again but directly pick it up from cache for execution

● reduce file I/O (stats calls) as it is being executed from the cache(memory) rather than disk

● the fastest and easiest solution for faster execution

Opcode/Compiler cache

hit/store

fetch

opcodes

Zend Compiler

PHP File

Parse/Execute Opcodes

End User

OpcodeCacher

Cache

APC● Alternate PHP Cache● A free, open source and robust framework

for caching and optimizing PHP intermediate code.

● maintained by core PHP developers● users

Yahoo!

Facebook

Wikipedia and many more

Installation$pecl install APC

OR Source Compilation

#wget http://pecl.php.net/get/APC

#tar -zxvf APC-3.0.x.tar.gz

#cd APC-3.0.x

#phpize

#./configure

#make

#make install

#cp modules/apc.so /full/path/to/ext/apc.so

Windows user

Download it from : http://pecl4win.php.net/

Enable APC● edit php.in : extension=apc.so● restart apache

Web console to monitor APC Info

copy apc.php from apc source directory to document root

.ini directives● apc.shm_size = 30 (in MB)● apc.stat = 1 (by default)

- check if files has been modified on every request

- if apc.stat = 0, requires restart webserver on update or

apc_clear_cache()

- use include('/webroot/conf.php') instead of include('conf.php')

● apc.filters = <regex> a comma separated POSIX regex. default value is “-”

● apc.cache_by_default = true false - files are only cached if matched by a positive filter

more .ini directives

– apc.ttl = 0 (by default) Time to Live in cache - seconds – apc.write_lock = 1 (by default) only one process at a time instead of waiting on a lock– apc.num_files_hint = 1000 (by default) maximum number of files expect to be stored in memory– apc.max_file_size = 1M (by default) maximum file size that will be allowed in the apc cache – apc.file_update_protection=1(protect for 2 sec)– apc.include_once_override = 0 (by default)

APC user cache● bool apc_add(string $key, mixed $var [, int $ttl ])● bool apc_store(string $key, mixed $var [, int $ttl ])● mixed apc_fetch(string $key)● bool apc_delete(string $key)

.ini settings

apc.user_ttl = 0

apc.user_entries_hint = 4096

page cache with APC<?php

$key = "PAGE::".$_SERVER['REQUEST_URI'];

$pagecontents = apc_fetch($key);

if($pagecontents) {

echo $pagecontents;

exit;

}

ob_start();

// write your code

$pagecontents = ob_get_flush();

apc_store($key, $pagecontents);

?>

handling constants through APC● bool apc_define_constants(string $key, array $constants

[, bool $case_sensitive])● bool apc_load_constants(string $key [,bool $case_sensitive])<?php

$constants = array(

'NAME' => 'Jignesh',

'AGE' => 24,

'LOCATION' => 'Pune',

);

apc_define_constants('jignesh_info', $constants);

apc_load_constants('jignesh_info');

echo NAME,',',AGE,',',LOCATION;

?>

more functions● bool apc_compile_file ( string $filename )● bool apc_clear_cache ([ string $cache_type ] )● array apc_cache_info ([string $cache_type[,bool $limited ] ] )● array apc_sma_info ([ bool $limited ] )

other opcode cacher● XCache : http://xcache.lighttpd.net● IonCube: http://www.ioncube.com/sa_encoder.php ● Zend Platform: http://www.zend.com/en/products/platform/ ● Turck MMCache:

http://turck-mmcache.sourceforge.net/index_old.html ● EAccelerator: http://www.eaccelerator.net/

Benchmarking

Apache Bench

‣ ab utility bundled with Apache

http_load

‣ http://www.acme.com/software/http_load/

Siege

‣ http://www.joedog.org/JoeDog/Siege

Benchmark PEAR package

‣ http://pear.php.net/package/Benchmark

Apache Bench$ab -c 20 -n 50 <webserver_url>

Concurrency Level: 20Time taken for tests: 0.48937 secondsComplete requests: 50Non-2xx responses: 52Total transferred: 10504 bytesHTML transferred: 0 bytesRequests per second: 1021.72 [#/sec] (mean)Time per request: 19.575 [ms] (mean)Time per request: 0.979 [ms] (mean, across all concurrent requests)Transfer rate: 204.34 [Kbytes/sec] received

http_load

$http_load -rate 20 -seconds 5 <file_name>

99 fetches, 2 max parallel, 9702 bytes, in 5.00098 seconds

98 mean bytes/connection

19.7961 fetches/sec, 1940.02 bytes/sec

msecs/connect: 0.470556 mean, 0.635 max, 0.221 min

msecs/first-response: 1.40029 mean, 2.106 max, 1.175 min

HTTP response codes:

code 200 -- 99

Siege$siege -b -r 20 -t 5S <server_url>

Transactions: 677 hitsAvailability: 100.00 %Elapsed time: 5.84 secsData transferred: 5.39 MBResponse time: 0.13 secsTransaction rate: 115.92 trans/secThroughput: 0.92 MB/secConcurrency: 14.67Successful transactions: 677Failed transactions: 0Longest transaction: 0.99Shortest transaction: 0.04

serving static contents

● Apache's mod_php is designed for dynamic contents. ● Every Apache child used fair chunk of memory when it's executed with mod_php.● Serving static content like image, JS, CSS, HTML etc. with mod_php is more costly● Other option: lighttpd thttpd Boa

And nowadays S3 (Amazon Web Services)

Lets tune PHP code

include/require_once - once more

lstat64("/srv/www/htdocs/incl_test", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0

lstat64("/srv/www/htdocs/incl_test/a.php", {st_mode=S_IFREG|0644, st_size=39, ...}) = 0

open("/srv/www/htdocs/incl_test/a.php", O_RDONLY) = 4

lstat64("/srv/www/htdocs/incl_test", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0

lstat64("/srv/www/htdocs/incl_test/a.php", {st_mode=S_IFREG|0644, st_size=39, ...}) = 0

open("/srv/www/htdocs/incl_test/a.php", O_RDONLY) = 4

In PHP 5.2>= this will allow PHP to avoid opening the file twice.

file path problem– While it is convenient and easy to do include “foo.php” and have it work, internally.– it leads to significant overhead in system.– Whenever possible you should use full paths, that require no resolution in PHP.getcwd("/srv/www/htdocs/perf_demo", 4096) = 26

lstat64("/srv/www/htdocs/incl_test/a.php", {st_mode=S_IFREG|0644, st_size=39, ...}) = 0

open("/srv/www/htdocs/incl_test/a.php", O_RDONLY) = 4

getcwd("/srv/www/htdocs/perf_demo", 4096) = 26

lstat64("/srv/www/htdocs/perf_demo/b.php", {st_mode=S_IFREG|0644, st_size=39, ...}) = 0

open("/srv/www/htdocs/perf_demo/b.php", O_RDONLY) = 4

Generate system calls using $strace -e trace=file php <file_name.php>

include_path

my include_path is ".:/usr/share/php5:/usr/share/php5/PEAR:/srv/www/"

How to fix this?

sessions

● session.auto_start = 1 (by default 0)● PHP's session extension by default store

sessions in to each file within single directory.

● many files into one directory reduce access speed

● instead, store session in different directory● session.save_path = “N;/var/lib/php5”● N – no. of directory level e.g.

/tmp/4/b/1/e/3/sess_14879g

sessions

● PHP's default session handler is file system● instead, it can be stored into cache● let's say in memcache● session.save_handler = memcache

session.save_path = “tcp://127.0.0.1:11211”● using APC's add/fetch/delete

static keyword

● makes them accessible without needing an instantiation of the class

● so it's faster● public static function a( ) is faster compare to

public function a( )● quick benchmark for it.

Class Constants● define( ) is expensive● Class Constants are parsed at compile time.

So no execution overhead.● faster lookup due to smaller hash.● benchmark for it

miss use of Constants

● $foo[name] = 'Jignesh'; ● converted into strtolower ● hash lookups● E_NOTICE error message generated● temporary string being generated on the

during the execution● And of course it's slower● Let's benchmark for it.

for() loop optimization

Don't use functions in for() loop.

<?php

for ( $i = 1; $i < count($array); $i++ ) { }

?>

instead use,

<?php

$count = count($array);

for ( $i = 1; $i < $count; $i++ ) { }

?>

which is faster?

What’s the difference between:

isset($user['NAME'])

and

array_key_exists('NAME', $user)

Let's generate opcodes, more opcode less performance

Performance Tips

● Mostly people have only one solution● habitual to use DATABASE for information storage● Improper use of this resource can lead to significant

and continuously increasing performance loss.● Try to cache at different level● Avoid reg-ex, PHP's string functions are faster● Avoid magic calls - __get/__set/__autoload/__call.● There are lots of PHP's built in functions; PEAR, PECL

packages● chances are there what you need is already available

What to do, when you are stuck?

● Use Benchmarking Tools● Find bottleneck in your code● It might take time to do optimization● There is no any golden rule for it

● make your hand dirty

Finally

Premature optimization is the root of all evil.- Donald Knuth

Resources

http://pecl.php.net/apc

Thanks

Any other idea?

top related