Timothy R. Butler
Timothy R. Butler

Reputation: 1139

Compiling Perl for Faster FastCGI Operation

I've been exploring compiling Perl programs as a way to improve the initial startup time on a complex Perl CGI program. @Rurban's detailed overview was very helpful to me. Compiling my main process script yields a faster startup time using perlcc -o launcher launcher.fpl. The resultant process is at least 20% faster -- not overwhelming, but still meaningful.

Why am I trying to compile as oppose to simply optimize further? I've spent months using Devel::NYTProf to catch inefficient code, so I believe I've attacked most of the low hanging optimization fruit. The code is fast, once loaded and it is run via mod_fcgi FastCGI, so it stays persistently loaded. However, if it should happen to crash or if FastCGI needs to spawn a new process (either because the previous one has hit its maximum request level or there is enough demand that another worker is needed), the slow load time rears its ugly head. The first request on a new process may take 1-1.5 seconds, while subsequent requests clock in at under 200ms.

The issue: a lot of the program is in the form of Perl modules that the core "loader" dynamically loads based on what it is doing. The module loaded for the front page of my site is one of the slowest, for example. So, it stands to reason, some of the most important optimization would come from compiling those modules. However, using both perlcc -B Front.pm -o Front.pmc and perl -c Front.pm, I get an unhelpful segfault when I try to run the program:

[root@server code]# ./launcher.fpl
Segmentation fault (core dumped)

The compilation process provides no debug messages to suggest a problem. (To be clear: to keep things simple, in this example, launcher.fpl is not compiled, just straightforward Perl.) If I remove the pmc file so that launcher.fpl can load the uncompiled module once again, it loads without errors.

I've also tried:

perl -MO=Bytecode,-m,-oFront.pmc Front.pm

Which seems to work slightly better but produces this error when I try to run the program:

[root@server cgi-bin]# ./launcher.fpl
Number found where operator expected at /home/user/www/cgi-bin/Front.pm line 1, near "multi0.12"
Local: Sat Jul 10 14:58:18 2021: Dying from error.; At file: /home/user/www/cgi-bin/Front.pm; line: 1; id: 
Error: Unrecognized character \x08; marked by <-- HERE after ulti<-- HERE near column 36 at /home/user/www/cgi-bin/Front.pm line 1.
Compilation failed in require at /home/user/www/cgi-bin/Loader.pm line 117.

Loader.pm line 117 is where the Front.pm(c) module is required:

state $moduleFront = require Front;

This leads to two main questions: (1) am I going about this the right way to begin with and (2) if I am not on the wrong path entirely, is there a way to debug why my module segfaults if it is compiled?

Upvotes: 1

Views: 248

Answers (1)

ikegami
ikegami

Reputation: 385789

if it should happen to crash or if FastCGI needs to spawn a new process, the slow load time rears its ugly head.

That's not true; it should simply be a fork, which is instantaneous. (And even if it did take time, it would be between requests and not while a client is waiting.) There is no problem to solve here.

If you aren't forking, this is where you should be focusing your efforts. With forking, you can preload the modules your scripts use. The net effect over CGI is not only avoiding the time needed to load perl but the time needed to execute the modules as well.

Upvotes: 1

Related Questions