am 17. November 2008
Jeder LAMP Administrator steht irgendwann vor der Entscheidung, in welcher Form er PHP installieren möchte. Es gibt zum einen fertige Pakete, die bei jeder halbwegs modernen Linux Distribution mitgeliefert werden. Auf der anderen Seite gibt es noch die gute alte Methode, PHP aus dem Quellcode zu kompilieren. Beide Varianten haben Vor- und Nachteile.
Der klare Vorteil für fertige Pakete ist die schnelle und einfache Installation bzw. Deinstallation. Der Nachteil ist die Konfiguration. Man hat leider keinen Einfluss darauf, was zum Beispiel als Modul oder was als „Built in“ geliefert wird.
Ein anderes Thema, welches immer wieder gerne diskutiert wird, ist der angebliche Performance Vorteil bei selbst erstellten Kompilaten aus dem Quellcode. Da man bei diesen die letzte Prozessor-Optimierung ausnutzen kann. Dabei muss keine Rücksicht darauf genommen werden, ob das fertige PHP noch auf anderen Plattformen lauffähig ist.
Anhand eines Fallbeispiels versuche ich ein wenig Klarheit ins dunkle zu bringen. Dazu werde ich einmal PHP als Paket und einmal aus dem Quellcode installieren. Dazu dient eine neue Debian 4.0 Gnu/Linux Installation als Basis.
Auf PHP Accelatoren wird bewusst nicht in diesem Artikel eingegangen, da dieses Thema genug Material für einen eigenen bietet. Der hoffentlich bald von mir geschrieben wird.
Technische Server Daten:
cat /proc/cpuinfo
processor : 0
vendor_id : AuthenticAMD
cpu family : 15
model : 39
model name : AMD Opteron(tm) Processor 148
stepping : 1
cpu MHz : 2195.418
cache size : 1024 KB
fdiv_bug : no
hlt_bug : no
f00f_bug : no
coma_bug : no
fpu : yes
fpu_exception : yes
cpuid level : 1
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov
pat pse36 clflush mmx fxsr sse sse2 pni syscall nx mmxext fxsr_opt lm 3dnowext 3 dnow pni
bogomips : 4391.99
cat /proc/meminfo
MemTotal: 2067832 kB
MemFree: 86092 kB
Buffers: 203192 kB
Cached: 755372 kB
SwapCached: 56 kB
Active: 986748 kB
Inactive: 642788 kB
HighTotal: 0 kB
HighFree: 0 kB
LowTotal: 2067832 kB
LowFree: 86092 kB
SwapTotal: 3068392 kB
SwapFree: 3065036 kB
Dirty: 124 kB
Writeback: 0 kB
Mapped: 793220 kB
Slab: 320256 kB
CommitLimit: 4102308 kB
Committed_AS: 2016668 kB
PageTables: 12544 kB
VmallocTotal: 2039800 kB
VmallocUsed: 9164 kB
VmallocChunk: 2030440 kB
Der Test:
Bench.php von Sebastian Bergmann (http://sebastian-bergmann.de/archives/634-PHP-GCC-ICC-Benchmark.html).
Die Tests werden ausschließlich auf der Kommandozeile ausgeführt, um eventuelle Beeinflussung der Testergebnisse durch Netzwerkprobleme auszuschließen.
Die Durchführung:
Der Benchmark wird jeweils 5 mal durchgeführt, daraus wird dann der Mittelwert gebildet.
Kandidat 1: Das fertige PHP Paket
Die Installation könnte einfacher nicht sein, apt sein dank:
~# apt-get install php5-cli
~# php -v
PHP 5.2.0-8+etch13 (cli) (built: Oct 2 2008 08:26:18)
Copyright (c) 1997-2006 The PHP Group
Zend Engine v2.2.0, Copyright (c) 1998-2006 Zend Technologies

Konfiguration: php.ini
An den Standardeinstellung der php.ini werden keine Änderungen vorgenommen.
Durchführung und Ergebnisse:
~#php bench.php
|
Lauf 1 |
Lauf 2 |
Lauf 3 |
Lauf 4 |
Lauf 5 |
Average |
| Simple |
1.078 |
1.119 |
1.124 |
1.039 |
1.123 |
1.096 |
| Simplecall |
1.262 |
1.213 |
1.320 |
1.302 |
1.322 |
1.283 |
| Simpleucall |
1.839 |
1.858 |
1.865 |
1.822 |
1.861 |
1.849 |
| Simpleudcall |
2.221 |
2.204 |
2.683 |
2.909 |
2.317 |
2.466 |
| Mandel |
3.279 |
3.305 |
4.712 |
3.291 |
3.268 |
3.571 |
| mandel2 |
4.188 |
4.193 |
4.311 |
4.163 |
4.164 |
4.203 |
| ackermann(7) |
2.578 |
2.687 |
2.532 |
2.575 |
2.661 |
2.606 |
| ary(50000) |
0.160 |
0.157 |
0.158 |
0.159 |
0.157 |
0.1582 |
| ary2(50000) |
0.129 |
0.127 |
0.133 |
0.124 |
0.128 |
0.1282 |
| ary3(2000) |
2.066 |
1.983 |
1.818 |
1.848 |
1.907 |
1.9244 |
| fibo(30) |
5.598 |
5.611 |
5.728 |
5.713 |
5.663 |
5.6626 |
| hash1(50000) |
0.327 |
0.301 |
0.307 |
0.293 |
0.298 |
0.3052 |
| hash2(500) |
0.283 |
0.277 |
0.286 |
0.277 |
0.271 |
0.2788 |
| heapsort(20000) |
0.863 |
0.848 |
0.885 |
0.931 |
0.889 |
0.8832 |
| matrix(20) |
0.766 |
0.746 |
0.735 |
0.768 |
0.780 |
0.7590 |
| nestedloop(12) |
1.884 |
1.936 |
1.910 |
1.872 |
1.878 |
1.8960 |
| sieve(30) |
0.766 |
0.793 |
0.792 |
0.839 |
0.840 |
0.8060 |
| strcat(200000) |
0.306 |
0.309 |
0.309 |
0.302 |
0.350 |
0.3152 |
| Total |
29.592 |
29.666 |
31.608 |
30.227 |
29.878 |
30.19 |
Zum vergrößern, einfach auf Bild klicken

Kandidat 2: PHP aus dem Quellcode
Um keine verfälschten Messergebnisse zu bekommen, lade ich den etwas veralteten Quellcode von PHP 5.2.0 herunter. Dieser entspricht der Paketversion:
http://www.php.net/releases/
~# cd /usr/local/src
~# wget http://museum.php.net/php5/php-5.2.0.tar.bz2
~# bunzip2 php-5.2.0.tar.bz2
~# tar -xvf php-5.2.0.tar
~# apt-get install build-essential gcc flex bison libxml2-dev
Abhängig von der CPU ( siehe /proc/cpuinfo ) müssen jetzt die CFLAGS exportiert werden, in unserem Fall werden folgende verwendet:
~# export CHOST=”i686-pc-linux-gnu”
~# export CFLAGS=”-O3 -mtune=opteron -march=opteron -mcpu=opteron -mmmx -msse -msse2 -mfpmath=sse -fforce-addr -fomit-frame-pointer -foptimize-sibling-calls -funroll-loops -frerun-cse-after-loop -frerun-loop-opt -falign-functions=4″
~# export CXXFLAGS=$CFLAGS
Die optimalen Schalter für jede CPU können in der Compilerdokumentation entnommen werden:
• http://gcc.gnu.org/onlinedocs/gcc/
• http://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html#Optimize-Options
~# ./configure –prefix=/usr/local/php-5.2.0
~# make
~# make install
Prüfen auf richtige Version.
~# /usr/local/php-5.2.0/bin/php -v
PHP 5.2.0 (cgi) (built: Nov 12 2008 18:25:37)
Copyright (c) 1997-2006 The PHP Group
Zend Engine v2.2.0, Copyright (c) 1998-2006 Zend Technologies
Konfiguration: php.ini
An den Standardeinstellung der php.ini werden keine Änderungen vorgenommen.
Durchführung und Ergebnisse:
~# /usr/local/php-5.2.0/bin/php bench.php
|
Lauf 1 |
Lauf 2 |
Lauf 3 |
Lauf 4 |
Lauf 5 |
Average |
| Simple |
0.788 |
0.786 |
0.791 |
0.784 |
0.789 |
0.787 |
| Simplecall |
0.842 |
0.861 |
0.842 |
0.835 |
0.858 |
0.847 |
| Simpleucall |
1.434 |
1.437 |
1.413 |
1.430 |
1.452 |
1.433 |
| Simpleudcall |
1.625 |
1.661 |
1.647 |
1.654 |
1.660 |
1.649 |
| Mandel |
2.218 |
2.214 |
2.216 |
2.212 |
2.202 |
2.212 |
| mandel2 |
2.810 |
2.833 |
2.834 |
2.855 |
2.811 |
2.828 |
| ackermann(7) |
1.961 |
1.940 |
1.825 |
2.125 |
1.852 |
1.940 |
| ary(50000) |
0.140 |
0.139 |
0.140 |
0.138 |
0.144 |
0.140 |
| ary2(50000) |
0.109 |
0.108 |
0.106 |
0.107 |
0.107 |
0.107 |
| ary3(2000) |
1.378 |
1.503 |
1.583 |
1.526 |
1.543 |
1.506 |
| fibo(30) |
4.167 |
4.136 |
4.179 |
4.152 |
4.143 |
4.155 |
| hash1(50000) |
0.201 |
0.186 |
0.212 |
0.194 |
0.199 |
0.198 |
| hash2(500) |
0.204 |
0.203 |
0.508 |
0.569 |
0.206 |
0.338 |
| heapsort(20000) |
0.660 |
0.666 |
0.652 |
0.965 |
0.737 |
0.736 |
| matrix(20) |
0.601 |
0.587 |
0.585 |
0.594 |
0.584 |
0.590 |
| nestedloop(12) |
1.431 |
1.431 |
1.436 |
1.445 |
1.443 |
1.437 |
| sieve(30) |
0.684 |
0.692 |
0.696 |
0.641 |
0.689 |
0.680 |
| strcat(200000) |
0.088 |
0.089 |
0.088 |
0.087 |
0.090 |
0.088 |
| Total |
21.340 |
21.473 |
21.753 |
22.315 |
21.508 |
21.67 |
Zum vergrößern, einfach auf Bild klicken

Das Fazit:
Stellt man beide Testergebnisse nebeneinander, sieht man eine enormen Performancegewinn von durchschnittlich zirka 9 Sekunden. Dies ergibt einen Faktor von zirka 1,39.
|
Quellcode |
Paket |
| Simple |
0.787 |
1.096 |
| Simplecall |
0.847 |
1.283 |
| Simpleucall |
1.433 |
1.849 |
| Simpleudcall |
1.649 |
2.466 |
| Mandel |
2.212 |
3.571 |
| mandel2 |
2.828 |
4.203 |
| ackermann(7) |
1.940 |
2.606 |
| ary(50000) |
0.140 |
0.1582 |
| ary2(50000) |
0.107 |
0.1282 |
| ary3(2000) |
1.506 |
1.9244 |
| fibo(30) |
4.155 |
5.6626 |
| hash1(50000) |
0.198 |
0.3052 |
| hash2(500) |
0.338 |
0.2788 |
| heapsort(20000) |
0.736 |
0.8832 |
| matrix(20) |
0.590 |
0.7590 |
| nestedloop(12) |
1.437 |
1.8960 |
| sieve(30) |
0.680 |
0.8060 |
| strcat(200000) |
0.088 |
0.3152 |
| Total |
21.67 |
30,19 |
Zum vergrößern, einfach auf Bild klicken

Wer genug Zeit und Motivation mitbringt, kann durch ein selbstkompiliertes PHP, Performance gewinnen. Jedoch bin ich der Meinung das diese Art der Optimierung einer der letzten Schritte sein sollte, zuvor müssen die PHP Skripte und SQL Statements optimiert werden.