DEV Community

Dimitrios Kechagias
Dimitrios Kechagias

Posted on • Originally published at blogs.perl.org

Profiling Perl under Apache

At SpareRoom we still use Apache/mod_perl and, despite Devel::NYTProf::Apache's warnings about it not being maintained, it is still the best way for profiling Perl.

All you need to do really, for a mod_perl app, is to include this in your Apache config:

PerlPassEnv NYTPROF # Not needed for default settings.
PerlModule Devel::NYTProf::Apache
Enter fullscreen mode Exit fullscreen mode

You should also allow a single worker/child, and make sure it terminates cleanly before processing the output (nytprofhtml).

Since I want my dev/test environments to normally run with multiple workers and no profiler attached, I have a bash alias that exits apache and restarts it set-up for profiling. I thought I'd share an example of that, as I find it very useful.

First, a basic example pulled from what I used on our older CentOS/RedHat VM:

profile_apache() {
  systemctl stop httpd.service
  grep -q -F 'PerlModule Devel::NYTProf::Apache' /etc/httpd/conf/httpd.conf \
    || echo 'PerlModule Devel::NYTProf::Apache' >> /etc/httpd/conf/httpd.conf
  sed -i 's/^#PerlModule Devel/PerlModule Devel/g' /etc/httpd/conf/httpd.conf
  echo "Starting apache to collect profile data. Ctrl+c once to end."
  httpd -X
  echo "Restarting apache and creating html report."
  sed -i 's/^PerlModule Devel/#PerlModule Devel/g' /etc/httpd/conf/httpd.conf
  systemctl start httpd.service &
  nytprofhtml
  echo "Profile report in nytprof/index.html"
}
Enter fullscreen mode Exit fullscreen mode

It's mostly self-explanatory, the profile_apache command will shut down apache, add the PerlModule directive to the config if it's not there (or uncomment it) and launch an attached single worker instance of apache. It will wait until you send a SIGINT (e.g. press ctrl+C) before restoring/relaunching apache to the original configuration and producing the profiler report.

Now, if you have Debian/Ubuntu, you'd have to modify a bit. And if you are running on docker and sed -i gives you Device or resource busy errors (for trying to change mounted file inode from within container), you can use a method that copies instead of modifying in-place, such as sed -ci.

The alias becomes:

profile_apache() {
  apache2ctl stop && sleep 1
  grep -q -F 'PerlModule Devel::NYTProf::Apache' /etc/apache2/mods-available/perl.conf \
    || echo -e "\nPerlModule Devel::NYTProf::Apache" >> /etc/apache2/mods-available/perl.conf
  sed -ci 's/^#PerlModule Devel/PerlModule Devel/g' /etc/apache2/mods-available/perl.conf
  source /etc/apache2/envvars
  echo "Starting apache to collect profile data. Ctrl+c once to end."
  apache2 -X
  echo "Restarting apache and creating html report."
  sed -ci 's/^PerlModule Devel/#PerlModule Devel/g' /etc/apache2/mods-available/perl.conf
  apache2ctl start &
  nytprofhtml
  echo "Profile report in nytprof/index.html"
}
Enter fullscreen mode Exit fullscreen mode

This is the basic idea, although my alias does some extra things like putting the report in an apache-mounted directory and providing a browser link, removing the PerlRequire that preloads our .pm modules (it clashes with NYTProf) etc.

Top comments (2)

Collapse
 
drkd profile image
kd

I've tried mod_perl / nytprof exactly once. But every mod_perl code base I've worked with recently has some psgi compatibility layer - it's not that difficult in many cases - Plack::App::FakeApache may work out of the box for you. And it makes the whole management of the profile workflow so much easier. These days I have a bunch of scripts to provide a git-bisect like environment for profiles (I'm using some docker there because of how we're set up) which is extremely powerful for identifying where and how performance problems are introduced.

Collapse
 
dkechag profile image
Dimitrios Kechagias

We do run the code under a psgi-style layer for development purposes, so when you are working on a feature you can run performance analysis etc (and our modern code doesn't even need that, it's just clean APIs) - it's also how our perl tests work. However, when dealing with legacy code, or where modern and legacy interact, hitting profile_apache on the UAT environment is the fastest way to find out what's going on.