Debugging and Profiling mod_perl Applications
by Frank Wiles
|
Pages: 1, 2, 3
When to Use Apache::DB
Using print, die, and warn statements in your code will help you find and fix 99 percent of the bugs you may run across when building mod_perl applications. Too bad there is still that pesky remaining 1 percent that will make you tear your hair out in clumps and wish you had gone into selling insurance instead of programming. Luckily there is Apache::DB to help keep the glare off our collective heads at next year's Perl conference to a minimum.
Sometime, despite all of your attempts to see what is going wrong, you will find yourself in a situation where:
- Your code causes Apache to segfault and you can't for the life of you figure out why.
- It appears that your code segfaults inside of a subroutine or method you are calling in a CPAN module you are using.
- You have more debugging statements than actual code.
You could spend time hacking up your other installed modules, such as those from CPAN, with debugging statements--but this only means you will have to return later and remove all of it. You could take an easier route and debug your mod_perl application with a real source debugger.
Using the Perl debugger allows you to see directly into what is happening to your code and data. You can step through your code line by line, as Perl executes it. Because you are following the same flow, there is no chance that you are making any bad assumptions. You might even consider it WYSIWYG, albeit without a GUI.
Using Apache::DB
While Apache::DB works with both mod_perl 1.x and mod_perl 2.x, all of the examples in this article use mod_perl 2.0. Once you have installed Apache::DB from CPAN, using it is fairly simple. It does, however, require that you make a few Apache configuration changes. Assuming you have a mod_perl handler installed at /modperl/ on your system, your configuration needs to resemble this:
<Location /modperl>
SetHandler perl-script
PerlResponseHandler My::Modperl::Handler
PerlFixupHandler +Apache::DB
</Location>
You also need to modify either the appropriate <Perl></Perl> section or your startup.pl file to include:
use APR::Pool ();
use Apache::DB ();
Apache::DB->init();
If you are working in a mod_perl 1.0 environment, the only change is that you should not include the use APR::Pool (); directive.
Note that you must call Apache::DB->init(); prior to whatever code you are attempting to debug. To be safe, I always just put it as the very first thing in my startup.pl.
Once you have modified your configuration, the last step is to launch your Apache server with the -X command-line option. This option tells Apache to launch only one back-end process and to not fork into the background. If you don't use this option, you can't guarantee that your debugger has connected to same Apache child as your browser.
With this Apache daemon tying up your command prompt, simply browse to your application. As you will see, the shell running httpd has been replaced with a Perl debugging session. This debugging session is tied directly to your application and browser. If you look at your browser it will appear to hang waiting for a response; this is due to the fact your Apache server is waiting on you to work with the debugger.
Perl's debugger is very similar to other debuggers you may have used. You can step through your code line by line, skip entire subroutines, set break points, and display and/or change the value of variables with it.
It might be useful to read through man
perldebtut, a introductory tutorial on using the debugger. For a
more complete reference to all of the available commands, see man perldebug.
This list should be just enough to get you started:
| Command | Description |
|---|---|
p expression
|
This prints out the value of an expression or variable, just like the print directive in Perl. |
x expression
|
This evaluates an expression and prettily prints it for you. Use it to make complex data structures readable. |
s
|
This tells the debugger to take a single step. A step is a single statement. If the next statement is a subroutine, the debugger will treat it as only one statement; you will not be able to step through each statement of that subroutine and the flow will continue without descending into it. |
n
|
This tells the debugger to go to the next statement. If the next statement is a subroutine, you will descend into it and be able to step through each line of that subroutine. |
l line
|
Display a particular line of source code. |
M
|
Display all loaded modules. |
Code Profiling with Apache::DProf
Apache::DProf provides the necessary hooks for you to get some coarse profiling information about your code. By coarse, I mean only information on a subroutine level. It will show you the number of times a subroutine is called along with duration information.
Essentially, Apache::DProf wraps Devel::DProf for you, making your life much easier. It is possible to use Devel::DProf by itself, but it assumes that you are running a normal Perl program from the command line and not in a persistent mod_perl environment. This isn't optimal, because while you can shoehorn Devel::DProf into working, you'll end up profiling all of the code used at server startup when you really only care about the runtime code.
Using Apache::DProf is relatively straightforward. All you need to do is include PerlModule Apache::DProf in your httpd.conf and restart your server.

