Daniel's Perl5 Page
Table of contents:- Perl Beste Practices (PBP)
- ModPerl
- Profiling
- Benchmark
- Memory holes
- File handling (*STDIN, *STDOUT, *STDERR too)
- Integrated Development Environment (IDE)
- Examples
Perl Best Practices (PBP)
Check code:perlcritic -1 mymodule.pm
Perl tidy setup (.perltidyrc):
-l=78
-i=4
-ci=4
-st
-se
-vt=2
-cti=0
-pt=1
-bt=1
-sbt=1
-bbt=1
-nsfs
-nolq
-wbb="% + - * / x 1= == >= <= = + !~ < > | & **= += *= &= <<= &&= -= /= |= >>= ||= .= %= ^= x= //="
VIM setup (.vimrc):
set background=dark
set ai
set showmatch
set tabstop=4
set shiftwidth=4
set expandtab
ModPerl
ModPerl does not handle all HTTP status codes correctly:...
sub fix_modperl_response {
my ($cgi, $header) = @_;
if ($ENV{MOD_PERL}) {
# special HTTP response codes:
my $stat200re = qr{(?:20[16789]|2[1-9])}xms;
my $stat300re = qr{(?:30[89]|3[1-9])}xms;
my $stat400re = qr{(?:41[89]|4[2-9])}xms;
my $stat500re = qr{(?:50[6-9]|5[1-9])}xms;
if (${header}{-Content_length} > 0
&& ${header}{-status} =~ /^(?:$stat200re|$stat300re|$stat400re|$stat500re)/xms
&& ${header}{-status} =~ /^(\d)/xms
) {
$cgi->r->status("${1}00");
}
}
return;
}
...
my $cgi = CGI->new();
my %header = { -status=> '201', -Content_length=>100 };
# yes, first print header and content:
print $cgi->header(%header);
...
# after that fix the HTTP status code in response:
fix_modperl_response($cgi, \%header);
...
ModPerl has some trouble to read request body data from stdin with <>
:
...
sub read_request_body {
my $body = q{};
while ( read STDIN, my $buffer, 1_048_576 ) {
$body .= $buffer;
}
return $body;
}
...
Profiling
To profile a Perl program with NYTProf change shebang to (or use Perl command line parameter '-d:NYTProf
'):
#!/usr/bin/perl -d:NYTProf
The NYTProf profiler creates a nytprof.out
file that can be converted to other formats like HTML or Callgrind, for example:
nytprofcg nytprof.out
The Callgrind file nytprof.callgrind
can be opened with kcachegrind
:
kcachegrind nytprof.callgrind
Benchmark
Sometimes it's unclear how fast code is and to check it use "Benchmark":#!/usr/bin/perl
use strict;
use warnings;
use Benchmark qw(cmpthese);
our $VERSION = '1.0';
sub read_file {
my ( $file, $bufsize ) = @_;
my $buffer;
if ( open my $fh, '<', $file ) {
binmode $fh;
while ( my $bytesread = read $fh, $buffer, $bufsize ) {
# do nothing yet
}
close($fh) || carp("Cannot close $file.");
}
else {
croak("Cannot open $file");
}
return;
}
my $fn = '/tmp/readtest.data';
cmpthese(
-2,
{
bufsize1024 => sub { read_file( $fn, 1_024 ); },
bufsize4096 => sub { read_file( $fn, 4_096 ); },
bufsize16384 => sub { read_file( $fn, 16_384 ); },
bufsize32768 => sub { read_file( $fn, 32_768 );},
bufsize65536 => sub { read_file( $fn, 65_536 ); },
bufsize1048576 => sub { read_file( $fn, 1_048_576 ); },
}
);
Memory holes
Long running Perl scripts like ModPerl CGI scripts or server scripts should be checked for memory holes.- weaken (Test::Weaken) - it's fast but inaccurate:
#!/usr/bin/perl use strict; use warnings; use Test::Weaken; our $VERSION = '1.0'; my $tester = leaks( { constructor => sub { my $o = MyPerlProgram->new(); $o->run(); return $o; } } ); if ($tester) { printf "%d objects were not freed\n", $tester->unfreed_count(); my $unfreed_proberefs = $tester->unfreed_proberefs(); foreach my $ref (@{$unfreed_proberefs}) { print "unfreed: $ref\n"; } printf "%d of %d objects were not freed\n", $tester->unfreed_count(), $tester->probe_count(); }
- leaktrace (Test::LeakTrace) - it's slow but very accurate:
#!/usr/bin/perl use strict; use warnings; use Test::LeakTrace; our $VERSION = '1.0'; leaks_cmp_ok { my $o = MyPerlProgram->new(); $o->run(); } '<', 1;
File handling (*STDIN, *STDOUT, *STDERR too)
- Read a file at once with
<>
(aka 'slurp mode'):
This works with any file handle.... use English qw( -no_match_vars ); # PBP says: use $RS instead of $/ ... local $RS = undef; # slurp mode on my $content = <>; # slurp *STDIN ...
- The best buffer size for fast read/write on XFS/EXT(3|4) is:
65_536
- To switch off annoying *STD(OUT|ERR) buffering write this:
... *STDOUT->autoflush(1); # the same as $|=1 or $OUTPUT_AUTOFLUSH=1; *STDERR->autoflush(1); ...
Integrated Development Environment (IDE)
- Eclipse: http://eclipse.org with EPIC:
Help → Install New Software... → http://e-p-i-c.sf.net/updates → install "EPIC Main Components" ... - Padre: http://padre.perlide.org/
- Komodo Edit: http://komodoide.com/komodo-edit/
- Komodo IDE: http://komodoide.com/ (Commercial)
Examples
- get a user certificate from DFN CERT LDAP by an email address: getdfnusercert.pl
© Daniel Rohde | created: November, 9th 2016 | changed: November, 23th 2017