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
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"
}
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"
}
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.
PS, <code> does not work on the bash code above (adds some colours, but renders everything in a single wrapping line with the regular font), so I had to use <pre>. If someone knows how to fix it (tried markdown ``` as well), I can add syntax highlighting - for now I cross-posted to dev.to to make it look right.
That is the opposite of not working. 🙂 You have to use it, like you would in any plain HTML document, together with
<pre>
for a block of code (as per the Notes section of that page, which for some reason I cannot link directly).Ah, thanks. I am sure I knew up to some point that <code> requires <pre> for multi-line and just forgot, as I've been using markdown the last few years (github, slack etc) and expect ``` in markdown mode to be all you need for multi-line code. That only adds <code> here though, so I have to remember to add <pre>.
Ah. That story is somewhat more complicated. These days when people say “Markdown” they mean a somewhat extended version of the syntax that most sites have converged on, whereas the Markdown plugin in use here is the O.G. Gruber Perl implementation which only supports indented code blocks and has never picked up support for fenced code blocks (as they are now called). Therefore it also always parses backticks as an inline code span, which renders as just a
<code>
tag. OG Markdown does support code blocks and does render them as<pre><code>
tags – but you have to use the old-school indentation-based way to indicate them.