LAMP vs. LAMP Rematch

Two very popular and widely used languages for building dynamic web sites are Perl and PHP. They make up two thirds of the "P" in the Linux Apache, MySQL, Perl/PHP/Python (LAMP) stack. How does their performance, using mod_perl and mod_php, compare for everyday web programming? I attempted to find out.

New in the rematch

In the rematch, I updated the Perl HTML code based on suggestions from comments to the orignal article. It should create a more accurate comparison with PHP. Though the main goal is to compare the performance of mod_perl and mod_php, I added a TCL CGI program to compare against Perl CGI. Finally, the hardware used for testing was significantly faster.

The machine

My new test bed was a DELL PowerEdge 2850 server with the following specifications and software:
 

3.2 Ghz Intel Xeon
4G RAM
Red Hat Enterprise Linux 3
Apache 2.0.46
MySQL 3.23.58
Perl 5.8.0
PHP 4.3.2
TCL 8.3.5

 

This system is a monster compared to the 700 Mhz server from the original test. I expected the results to reflect it.

The method

For testing, I created two programs in Perl and two in PHP that produced identical results using logic as similar as I could make them. One program generates HTML and the second reads and updates a MySQL database.

For the HTML generation test, each program counts from 1 to 1024 and writes a line of HTML to the screen. I choose five different run loads:
 

1 HTTP request
100 HTTP requests (serially)
100 HTTP requests (10 concurrently)
1000 HTTP requests (serially)
1000 HTTP requests (10 concurrently)
 

 

For the MySQL test, I ran a single HTTP request that read and updated 5000 records in a table. To communicate with MySQL, I used the standard PHP interface and Perl DBI. Here is the structure of the test table:
 

+----------+----------+------+-----+---------+----------------+
| Field    | Type     | Null | Key | Default | Extra          |
+----------+----------+------+-----+---------+----------------+
| id       | int(11)  |      | PRI | NULL    | auto_increment |
| junktext | char(30) | YES  |     | NULL    |                |
+----------+----------+------+-----+---------+----------------+

 

Each of the 5000 records was initialized as follows:
 

+-------+--------------------------------+
| id    | junktext                       |
+-------+--------------------------------+
| 1     | XXXXXXXXX0XXXXXXXXX0XXXXXXXXX0 |
+-------+--------------------------------+

 

The programs read each record from the table, converted the junktext column to lower case, then wrote it back. The goal was to test the database drivers and overhead in Perl and PHP.

I performed no tuning on any component of the LAMP stack as delivered from Red Hat. In a hosted environment, being able to change system components is a rare luxury. For your reading pleasure, I present the Perl HTML test code, Perl MySQL test code, PHP HTML test code, PHP MySQL test code, and TCL HTML test code.

Results

I ran benchmarks using the ApacheBench program (2.0.40) -- part of the standard Apache package -- which measures the time for each HTTP request to be processed and reports totals and averages. I ran each benchmark three times and took the mean of the results. All tests were run on an internal network, where both client and server were isolated from the vagaries of the Internet.

As a baseline, I included the execution of each Perl program as a regular Common Gateway Interface (CGI) program. CGI was one of the first methods of creating dynamic web content. There are still many CGI programs working their magic on the web. Since I have been coding some TCL lately, I also ran the HTML tests using TCL CGI.

The problem with CGI is that it forks a new process and loads a copy of the Perl or TCL interpreter for each request, using gobs of memory. Mod_perl includes the Perl interpreter within Apache. Both mod_perl and mod_php run inside the Apache process that is handling the page, providing more efficient execution.

Following are the results of the CGI, mod_perl, and mod_php tests. The number after HTTP in column one indicates the number of requests for that test. A number followed by a c indicates that 10 concurrent requests were run for that test. All times are in seconds (lower is better).

Additional TCL note: I did not run the MySQL test with TCL because TCL does not come with a native MySQL interface. Unlike Perl and PHP, you have to install third party software to talk to MySQL. This highlights a weakness of TCL. The native interfaces that ship other languages reflect to some extent the depth of their communities and popularity. That doesn't mean TCL can't talk to MySQL or do anything any other language can, it just means it takes more effort.

HTML generation tests
 

  TCL CGI Perl CGI mod_perl mod_php
HTTP-1 0.2962 0.6515 0.5339 0.5072
HTTP-100 2.8881 5.3519 0.7068 0.5396
HTTP-100c 2.4584 3.9263 0.3806 0.4048
HTTP-1000 29.4226 52.3125 5.5057 5.4534
HTTP-1000c 24.8832 39.2487 3.96627 4.3705

MySQL test
 

  Perl CGI mod_perl mod_php
MySQL-rw 0.5680 0.5478 0.4206

Conclusions and commentary

I need to hedge my observations somewhat because using object oriented features of either language, adding third party modules, or sessions to the mix could alter the outcome.

That said, the results of these tests show that for serial HTML generation. PHP (mod_php) was slightly faster than Perl (mod_perl). But, for concurrent HTML generation, the more likely real world scenario, Perl was slightly faster than PHP. I attribute the better showing for Perl in the rematch to the code rewrite. The mod_perl code cache really shined as the load increased. In the MySQL test, PHP maintained a small edge over Perl. I suspect the MySQL results reflect the extra overhead of the Perl DBI interface versus the direct interface from PHP. However, DBI seems to be the standard connection method for databases in Perl.

Both mod_perl and mod_php have an enormous performance advantage over TCL CGI and Perl CGI. I was not surprised to see TCL CGI perform better than Perl CGI since the TCL interpreter is much smaller than Perl. CGI not only doesn't scale very well, but gains little advantage from concurrency. Under load, it could bring a server to its knees.

One unique feature of mod_perl is the ability to embed Perl code in the Apache configuration file. This provides more options for dynamic server configuration. To my knowledge, PHP does not have an equivalent feature.

PHP provided consistent performance. It was designed from the start as a dynamic web language and excels in that role.

For tweakers, there are a number of ways to increase Perl and PHP performance with Apache. For Perl, there is the FastCGI module. For PHP, there are proprietary, free (as in beer), and open source PHP cache accelerators. These are advanced options and require additional work to set up.

No lose scenario

Both Perl and PHP are robust and powerful languages for creating web applications. They both offer large libraries of code, database drivers, and third party add-ons. For small and medium sized applications, the difference would be hard to notice. Extrapolating these results to high traffic applications is not a good idea because too many other factors come into play. Whether you opt for Perl or PHP in your web development adventures, you win.


By  Linux Box Admin