Author: Keith Winston
My test bed was a reasonable facsimile of what one would find on a Web host; specifically, a Compaq ProLiant DL380 server with the following specifications and software:
700Mhz Pentium III
1G RAM
Red Hat Enterprise Linux 3
Apache 2.0.46
MySQL 3.23.58
Perl 5.8.0
PHP 4.3.2
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 1,024 and writes a line of HTML to the screen. I choose five different run loads:
1 HTTP request100 HTTP requests (serially)
100 HTTP requests (10 concurrently)
1000 HTTP requests (serially)
1000 HTTP requests (10 concurrently)
For the MySQL test, each program runs a single HTTP request that reads and updates 5,000 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 5,000 records was initialized as follows:
+-------+--------------------------------+ | id | junktext | +-------+--------------------------------+ | 1 | XXXXXXXXX0XXXXXXXXX0XXXXXXXXX0 | +-------+--------------------------------+
The programs read each record from the table, convert the junktext column to lower case, then write 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, and PHP MySQL test
code.
Results
I ran each script using the ApacheBench program (version 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 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 decided to include 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. The problem with CGI is that it forks a new process and loads a copy of the Perl interpreter for each request, which uses 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 Perl 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).
HTML generation tests
CGI | mod_perl | mod_php | |
HTTP-1 | 0.1607 | 0.2392 | 0.1711 |
HTTP-100 | 16.6229 | 2.4346 | 1.6607 |
HTTP-100c | 16.4683 | 1.8337 | 1.5694 |
HTTP-1000 | 160.8190 | 16.2288 | 16.6460 |
HTTP-1000c | 161.1753 | 17.2127 | 15.6850 |
MySQL test
CGI | mod_perl | mod_php | |
MySQL-rw | 1.8157 | 1.4807 | 1.2189 |
Conclusions
I need to hedge my observations somewhat, because using object-oriented features of either language, adding third party modules or sessions to the mix, or using a different type of storage could alter the outcome.
That said, the results of these tests show that for many common Web programming tasks, PHP (mod_php) has a slight performance edge over Perl (mod_perl), based on the majority of the HTML generation tests. In the MySQL test, PHP also edged out Perl. I suspect the MySQL results are a reflection of the database drivers more than the interpreters.
Both mod_perl and mod_php have an enormous performance advantage over standard CGI, as expected. Standard CGI not only doesn’t scale very well, but gains no advantage from concurrency. Under load, it could bring a server to its knees quickly.
There are interesting and unique things about mod_perl. First, since it compiles a Perl program and keeps it cached in memory for subsequent uses, it performs better as the load goes up. For example, I ran the tests back-to-back, and the second and third tests were always faster than the first. If I waited some time between tests, the cache appeared to be cleared and mod_perl had to compile the program again. The numbers above are from back-to-back tests.
Mod_perl offers the ability to embed Perl code in the Apache configuration file. This provides more options for dynamic server configuration. PHP does not have an equivalent feature.
PHP provided consistent performance no matter how I tested it. 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, and there are several proprietary and 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. For small and medium-sized applications, the difference in their performance 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 in those scenarios.
Bottom line: Whether you opt for Perl or PHP, you win.
Category:
- Perl