Perl is commonly used for web scripting because it is quick and easy to write, and very easy to change. Compiled languages usually take a lot more time and effort to write and debug and can be time-consuming to change. But compiled code often runs faster (sometimes a lot faster) than bytecode-interpreted languages such as Perl or Java. In most projects it is programmer time that is paramount, because programmers are expensive, but some projects demand performance above all other considerations. How do we compare the performance of a Perl script to that of a C program?
We know we can use the Benchmark module to compare Perl code. There are equivalent tools for C also, but how are we going to use two different tools and keep the comparison fair? Since Perl is a glue language in addition to its own merits, we can glue the C code into Perl and then use the Benchmark module to run the benchmark.
To simplify the task, we are going to demonstrate only the fact that C is more suitable than Perl for mathematical and memory-manipulation tasks. The purpose is to show how to use the best of both worlds.
We will use a very simple task that we will implement in Perl and C: the factorial function written both recursivly and iteratively. If you have ever taken a basic programming course you will be familiar with this example.
In mathematical language, we define the factorial function as follows:
1! = 1 N! = N * (N-1)!
So if we start from 1 and go up, we get these numbers:
1! = 1 2! = (2)(1) = 2 3! = (3)(2)(1) = 6 4! = (4)(3)(2)(1) = 24 ... and so on.
The factorial grows very fast—e.g., 10! = 3,628,800 and 12! = 4.790016e+08 (479 million)—so you can imagine that the calculation of the factorial of large numbers is a memory-intensive operation.
Now since we have a recursive definition of the solution:
fact(1) = 1; fact(N) = N * fact(N-1)
the easiest way to implement it is to write a recursive function. In Perl we just reproduce the definition:
sub factorial_recursive_perl { return 1 if $_[0] < 2; return $_[0] * factorial_recursive_perl($_[0] - 1); }
Computer science teaches us that while recursive functions are often easy to write they are usually slower to run than their iterative equivalents. The iterative implementation is as easy as the recursive one in our example, and it should run much faster, since there is no function-call overhead. This is the iterative algorithm to calculate fact(N):
result = 1 for (i = 2; i <= N; i++) { result *= i; }
By adjusting it to use idiomatic Perl, we get the following function:
sub factorial_iterative_perl { my $return = 1; $return *= $_ for 2..$_[0]; return $return; }
The implementations in C are again similar to the algorithm itself:
double factorial_recursive_c(int x) { if (x < 2) return 1; return x * factorial_recursive_c(x - 1); } double factorial_iterative_c(int x) { int i; double result = 1; for (i = 2; i <= x; i++) result *= i; return result; }
To jump ahead, when we run the final benchmark we get the following results:
Benchmark: timing 300000 iterations of iterative_c, iterative_perl, recursive_c, recursive_perl... iterative_c: 0 wallclock secs ( 0.47 usr + 0.00 sys = 0.47 CPU) recursive_c: 2 wallclock secs ( 1.15 usr + 0.00 sys = 1.15 CPU) iterative_perl: 28 wallclock secs (26.34 usr + 0.00 sys = 26.34 CPU) recursive_perl: 75 wallclock secs (74.64 usr + 0.11 sys = 74.75 CPU)
All functions under test were executing 100!, which is 9.33262154439441e+157 using scientific notation.
The iterative implementation is about two and a half times as fast in C and three times as fast in Perl, where function calls are more expensive. Comparing C to Perl, the iterative implementation in C is about 56 times faster than the same algorithm implemented in Perl, and in the case of the recursive algorithm, C is 65 times faster.
There are at least three approaches to embedding other languages into Perl: XS, SWIG, and Inline.pm. We will implement the C functions we've written using the XS and Inline.pm techniques in the following sections. While SWIG is easier to use than XS for simple tasks, it's not as powerful as XS and it's not bundled with Perl. If you work on code that may later be distributed on CPAN, you'd better use XS or Inline.pm.
 
Continue to: