2007-04-03

Linux Fedora 6 vs Solaris 10 (apache+php)

Recently we were doing internal basic performance tests of apache(+php) webserver on Fedora and Solaris 10. Both systems (working in 64bit mode) were installed on two identical, small servers (Intel CPU 3.2 GHz, RAM 512 MB). While this configuration is rather not popular in big datacenters we wanted to test both OSes (in performance terms). At the begin there were no OS tuning and both servers had the same httpd.conf. On Solaris 10 CoolStack 1.1 was installed and configured. The result (reqs/sec):



A few details:
  • there were almost all apache modules removed from httpd.conf
  • PHP was used with APC
  • the command we used: "ab -c 50 -n 100000 http://192.168.1.1/test.php"
  • sizeof (file1+file2+file3+file4+file5) = 5Kb
  • test.php is simple:


require ('file1');
echo "Status OK\n";
$ala = 0;
$ola = "";
for ($i=0; $i<500; $i++) {
$ala += $i;
$ola .= "dsagfd5y32432";
}
require ('file2');
$ola = md5($ola.$ala);
require ('file3');
require ('file4');
require ('file5');
?>

While Fedora is a little bit faster than Solaris 10 there is one reason why I would choose the latter. Yes, you guessed: dtrace. But lets start from the very begin. Just simple vmstat 1 to see the whole picture:

kthr memory page disk faults cpu
r b w swap free re mf pi po fr de sr cd -- -- -- in sy cs us sy id
...
60 0 30 469784 73808 1 454 0 0 0 0 0 0 0 0 0 10933 49181 1204 55 45 0
56 0 30 465332 72860 1 685 0 0 0 0 0 0 0 0 0 11040 48967 1143 55 45 0
55 0 30 461044 72232 0 0 0 0 0 0 0 0 0 0 0 10942 49198 1084 55 45 0
53 0 30 461044 72228 1 392 0 0 0 0 0 0 0 0 0 11137 49314 1347 55 45 0
57 0 30 451020 71284 1 340 0 0 0 0 0 0 0 0 0 11083 49109 1169 55 45 0
60 0 30 444872 70656 2 814 0 0 0 0 0 0 0 0 0 10893 48968 1141 55 45 0
57 0 30 444436 70128 0 0 0 0 0 0 0 0 0 0 0 11061 49538 1173 55 45 0
59 0 30 440296 69704 2 497 0 0 0 0 0 0 0 0 0 11023 48569 1559 55 45 0
60 0 30 436140 69152 1 628 0 0 0 0 0 0 0 0 0 11031 49290 1369 55 45 0
...

CPU saturated but time is divided between user space and system calls. I was wonder why almost half of the time is spent in syscalls:

bash-3.00# dtrace -n 'syscall::: {@[execname,probefunc] = count();}'
...
httpd fchdir 20000
httpd writev 20002
httpd stat64 20002
httpd shutdown 20002
httpd getsockname 20002
httpd pollsys 20031
httpd accept 20032
httpd lwp_sigmask 20124
httpd sigaction 20186
httpd open 20248
httpd setitimer 40000
httpd fcntl 40194
httpd close 40444
httpd read 60516
httpd getcwd 100000
httpd resolvepath 100062
httpd gtime 120000
httpd semsys 480000

No surprise that httpd is doing the hardest job. But the syscalls ! Semsys ?!?! Why ? Let's see:

bash-3.00# dtrace -n 'syscall::semsys:entry /execname == "httpd"/ {@[ustack()] = count();}' -n 'END {trunc(@,5)}'
dtrace: description 'syscall::semsys:entry ' matched 1 probe
dtrace: description 'END ' matched 1 probe
^C
CPU ID FUNCTION:NAME
0 2 :END


libc.so.1`syscall+0x13
apc.so`apc_sem_unlock+0x35
apc.so`apc_cache_release+0x3e
apc.so`apc_deactivate+0x37
apc.so`apc_request_shutdown+0x16
apc.so`zm_deactivate_apc+0x29
libphp5.so`module_registry_cleanup+0x21
libphp5.so`zend_hash_apply+0x3d
libphp5.so`zend_deactivate_modules+0x6c
libphp5.so`php_request_shutdown+0x2fd
libphp5.so`php_handler+0x3a6
httpd`ap_invoke_handler+0xee
httpd`ap_process_request+0x18d
httpd`0x8084011
httpd`ap_process_connection+0x76
httpd`0x808a4d1
httpd`0x808a78a
httpd`ap_mpm_run+0xc69
httpd`main+0x4ea
httpd`_start+0x80
1626

libc.so.1`syscall+0x13
apc.so`apc_sem_lock+0x35
apc.so`apc_cache_release+0x32
apc.so`apc_deactivate+0x37
apc.so`apc_request_shutdown+0x16
apc.so`zm_deactivate_apc+0x29
libphp5.so`module_registry_cleanup+0x21
libphp5.so`zend_hash_apply+0x3d
libphp5.so`zend_deactivate_modules+0x6c
libphp5.so`php_request_shutdown+0x2fd
libphp5.so`php_handler+0x3a6
httpd`ap_invoke_handler+0xee
httpd`ap_process_request+0x18d
httpd`0x8084011
httpd`ap_process_connection+0x76
httpd`0x808a4d1
httpd`0x808a78a
httpd`ap_mpm_run+0xc69
httpd`main+0x4ea
httpd`_start+0x80
1650

libc.so.1`syscall+0x13
apc.so`apc_sem_unlock+0x35
apc.so`apc_cache_release+0x3e
apc.so`apc_deactivate+0x37
apc.so`apc_request_shutdown+0x16
apc.so`zm_deactivate_apc+0x29
libphp5.so`module_registry_cleanup+0x21
libphp5.so`zend_hash_apply+0x3d
libphp5.so`zend_deactivate_modules+0x6c
libphp5.so`php_request_shutdown+0x2fd
libphp5.so`php_handler+0x3a6
httpd`ap_invoke_handler+0xee
httpd`ap_process_request+0x18d
httpd`0x8084011
httpd`ap_process_connection+0x76
httpd`0x808a4d1
httpd`0x808a78a
httpd`ap_mpm_run+0xc69
httpd`main+0x4ea
httpd`_start+0x80
1650

libc.so.1`syscall+0x13
apc.so`apc_sem_lock+0x35
apc.so`apc_cache_release+0x32
apc.so`apc_deactivate+0x37
apc.so`apc_request_shutdown+0x16
apc.so`zm_deactivate_apc+0x29
libphp5.so`module_registry_cleanup+0x21
libphp5.so`zend_hash_apply+0x3d
libphp5.so`zend_deactivate_modules+0x6c
libphp5.so`php_request_shutdown+0x2fd
libphp5.so`php_handler+0x3a6
httpd`ap_invoke_handler+0xee
httpd`ap_process_request+0x18d
httpd`0x8084011
httpd`ap_process_connection+0x76
httpd`0x808a4d1
httpd`0x808a78a
httpd`ap_mpm_run+0xc69
httpd`main+0x4ea
httpd`_start+0x80
1650

libc.so.1`syscall+0x13
apc.so`apc_sem_unlock+0x35
apc.so`apc_cache_release+0x3e
apc.so`apc_deactivate+0x37
apc.so`apc_request_shutdown+0x16
apc.so`zm_deactivate_apc+0x29
libphp5.so`module_registry_cleanup+0x21
libphp5.so`zend_hash_apply+0x3d
libphp5.so`zend_deactivate_modules+0x6c
libphp5.so`php_request_shutdown+0x2fd
libphp5.so`php_handler+0x3a6
httpd`ap_invoke_handler+0xee
httpd`ap_process_request+0x18d
httpd`0x8084011
httpd`ap_process_connection+0x76
httpd`0x808a4d1
httpd`0x808a78a
httpd`ap_mpm_run+0xc69
httpd`main+0x4ea
httpd`_start+0x80
1650

Well, at last I wanted to see what type of semsys:

bash-3.00# dtrace -n 'syscall::semsys:entry /execname == "httpd"/ {@[arg0] = count();}'
dtrace: description 'syscall::semsys:entry ' matched 1 probe
^C

2 240000

According to Solaris Dynamic Tracing Guide, "the system calls related to System V semaphores (semctl(2), semget(2), semids(2), semop(2), and semtimedop(2)) are implemented as suboperations of a single system call, semsys." Here "2" means SEMOP which basically a semop call.

During the tests I have shown above dtrace statistics to our PHP guru (he is sort of "nothing-but-Fedora" guy). He was really, really surprised !
I wasn't :-)