Given the following functionally similar Perl modules, I was curious what the internal Perl differences in execution were.
To recap –  (from PerlDoc)
So given a set of modules that don’t define an import() function, one would expect that there would be little difference.
| use Module | 
require Module | 
main.pl
use Module1; 
use Module2; 
use Module1;      # add multiple use's to attempt to simulate having many use statements throughout many modules 
use Module1; 
use Module1; 
use Module1; 
use Module1; 
use Module1; 
 
BEGIN { 
print "::BEGIN\n"; 
} 
Module1::printit(); 
Module1.pm
package Module1; 
BEGIN { 
my $test = ”; 
print “Module1::BEGIN\n"; 
} 
sub printit { 
print "Module1::printit\n"; 
} 
1; 
Module2.pm
package Module2; 
use Module1; 
BEGIN { 
print “Module2::BEGIN\n”; 
} 
sub printit { 
print “Module2::printit\n”; 
} 
1;  | 
main.pl
require Module1; 
require MyOtherBegin; 
require Module1; 
require Module1; 
require Module1; 
require Module1; 
require Module1; 
require Module1; 
 
BEGIN { 
print "::BEGIN\n"; 
} 
MyBegin::printit(); 
Module1.pm
package Module1; 
BEGIN { 
my $test = ”; 
print “Module1::BEGIN\n"; 
} 
sub printit { 
print “Module1::printit\n"; 
} 
1; 
Module2.pm
package Module2; 
require Module1; 
BEGIN { 
print “Module2::BEGIN\n”; 
} 
sub printit { 
print “Module2::printit\n”; 
} 
1;  | 
program output
 
bash-3.00$ /usr/local/bin/perl main.pl 
Module1::BEGIN 
Module2::BEGIN 
::BEGIN 
Module1::printit 
  | 
program output
 
bash-3.00$ /usr/local/bin/perl main.pl 
::BEGIN 
Module1::BEGIN 
Module2::BEGIN 
Module1::printit 
  | 
dtrace output
 
== perl ========================================================== 
perl*::perl_alloc:main-enter 
perl*::perl_alloc:main-exit,  (0/0) (73 uS) 
perl*::perl_construct:main-enter 
perl*::perl_construct:main-exit,  (12/0) (543 uS) 
perl*::perl_parse:main-enter 
>> perl*::Perl_utilize:load-module-start (Module1) 
>> perl*::Perl_ck_require:load-module-start (Module1) 
<< perl*::Perl_ck_require:load-module-end (Module1.pm) (254/2) (3 uS) 
--> BEGIN, main.pl 
--> BEGIN, Module1.pm 
<-- BEGIN, Module1.pm (1/0) (102 uS) 
<-- BEGIN, main.pl (60/38) (763 uS) 
>> perl*::Perl_utilize:load-module-start (Module2) 
>> perl*::Perl_ck_require:load-module-start (Module2) 
<< perl*::Perl_ck_require:load-module-end (Module2.pm) (271/16) (2 uS) 
--> BEGIN, main.pl 
>> perl*::Perl_utilize:load-module-start (Module1) 
>> perl*::Perl_ck_require:load-module-start (Module1) 
<< perl*::Perl_ck_require:load-module-end (Module1.pm) (31/8) (2 uS) 
--> BEGIN, Module2.pm 
<-- BEGIN, Module2.pm (0/0) (4 uS) 
--> BEGIN, Module2.pm 
<-- BEGIN, Module2.pm (1/0) (11 uS) 
<-- BEGIN, main.pl (67/47) (399 uS) 
>> perl*::Perl_utilize:load-module-start (Module1) 
>> perl*::Perl_ck_require:load-module-start (Module1) 
<< perl*::Perl_ck_require:load-module-end (Module1.pm) (285/30) (2 uS) 
--> BEGIN, main.pl 
<-- BEGIN, main.pl (0/0) (3 uS) 
>> perl*::Perl_utilize:load-module-start (Module1) 
>> perl*::Perl_ck_require:load-module-start (Module1) 
<< perl*::Perl_ck_require:load-module-end (Module1.pm) (299/44) (2 uS) 
--> BEGIN, main.pl 
<-- BEGIN, main.pl (0/0) (3 uS) 
>> perl*::Perl_utilize:load-module-start (Module1) 
>> perl*::Perl_ck_require:load-module-start (Module1) 
<< perl*::Perl_ck_require:load-module-end (Module1.pm) (313/58) (2 uS) 
--> BEGIN, main.pl 
<-- BEGIN, main.pl (0/0) (3 uS) 
>> perl*::Perl_utilize:load-module-start (Module1) 
>> perl*::Perl_ck_require:load-module-start (Module1) 
<< perl*::Perl_ck_require:load-module-end (Module1.pm) (327/72) (2 uS) 
--> BEGIN, main.pl 
<-- BEGIN, main.pl (0/0) (3 uS) 
>> perl*::Perl_utilize:load-module-start (Module1) 
>> perl*::Perl_ck_require:load-module-start (Module1) 
<< perl*::Perl_ck_require:load-module-end (Module1.pm) (341/86) (2 uS) 
--> BEGIN, main.pl 
<-- BEGIN, main.pl (0/0) (3 uS) 
>> perl*::Perl_utilize:load-module-start (Module1) 
>> perl*::Perl_ck_require:load-module-start (Module1) 
<< perl*::Perl_ck_require:load-module-end (Module1.pm) (355/100) (2 uS) 
--> BEGIN, main.pl 
<-- BEGIN, main.pl (0/0) (3 uS) 
--> BEGIN, main.pl 
<-- BEGIN, main.pl (1/0) (10 uS) 
perl*::perl_parse:main-exit,  (373/132) (3464 uS) 
perl*::perl_run:main-enter 
--> printit, Module1.pm 
<-- printit, Module1.pm (0/0) (8 uS) 
perl*::perl_run:main-exit,  (0/0) (44 uS) 
perl*::perl_destruct:main-enter 
perl*::perl_destruct:main-exit,  (0/5) (20 uS) 
total, total (0/0) (4177 uS)Subs returned from: 
count  totaltime  mintime  avgtime  maxtime allocs  deallocs  func                 file 
1        8        8        8        8        0        0 printit              Module1.pm 
1      102      102      102      102        1        0 BEGIN                Module1.pm 
2       15        4        7       11        1        0 BEGIN                Module2.pm 
9     1190        3      132      763      128       85 BEGIN                main.pl 
count  totaltime  mintime  avgtime  maxtime allocs  deallocs  func                 file 
allocations / deallocations (complete program): 
(515 /      222) perl 
time to run perl:     6389 uS (time on CPU     4177 uS)  | 
dtrace output
 
== perl ========================================================== 
perl*::perl_alloc:main-enter 
perl*::perl_alloc:main-exit,  (0/0) (71 uS) 
perl*::perl_construct:main-enter 
perl*::perl_construct:main-exit,  (12/0) (583 uS) 
perl*::perl_parse:main-enter 
>> perl*::Perl_ck_require:load-module-start (Module1) 
<< perl*::Perl_ck_require:load-module-end (Module1.pm) (248/2) (3 uS) 
>> perl*::Perl_ck_require:load-module-start (Module2) 
<< perl*::Perl_ck_require:load-module-end (Module2.pm) (252/2) (2 uS) 
>> perl*::Perl_ck_require:load-module-start (Module1) 
<< perl*::Perl_ck_require:load-module-end (Module1.pm) (253/2) (1 uS) 
>> perl*::Perl_ck_require:load-module-start (Module1) 
<< perl*::Perl_ck_require:load-module-end (Module1.pm) (254/2) (2 uS) 
>> perl*::Perl_ck_require:load-module-start (Module1) 
<< perl*::Perl_ck_require:load-module-end (Module1.pm) (255/2) (1 uS) 
>> perl*::Perl_ck_require:load-module-start (Module1) 
<< perl*::Perl_ck_require:load-module-end (Module1.pm) (256/2) (1 uS) 
>> perl*::Perl_ck_require:load-module-start (Module1) 
<< perl*::Perl_ck_require:load-module-end (Module1.pm) (257/2) (2 uS) 
>> perl*::Perl_ck_require:load-module-start (Module1) 
<< perl*::Perl_ck_require:load-module-end (Module1.pm) (258/2) (1 uS) 
--> BEGIN, main.pl 
<-- BEGIN, main.pl (1/0) (100 uS) 
perl*::perl_parse:main-exit,  (285/28) (2319 uS) 
perl*::perl_run:main-enter 
--> BEGIN, Module1.pm 
<-- BEGIN, Module1.pm (1/0) (14 uS) 
>> perl*::Perl_ck_require:load-module-start (Module1) 
<< perl*::Perl_ck_require:load-module-end (Module1.pm) (69/46) (2 uS) 
--> BEGIN, Module2.pm 
<-- BEGIN, Module2.pm (1/0) (10 uS) 
--> printit, Module1.pm 
<-- printit, Module1.pm (0/0) (8 uS) 
perl*::perl_run:main-exit,  (99/73) (772 uS) 
perl*::perl_destruct:main-enter 
perl*::perl_destruct:main-exit,  (0/13) (36 uS) 
total, total (0/0) (3814 uS)Subs returned from: 
count  totaltime  mintime  avgtime  maxtime allocs  deallocs  func                 file 
1        8        0        8        8        0        0 printit              Module1.pm 
1       10        0       10       10        1        0 BEGIN                Module2.pm 
1       14        0       14       14        1        0 BEGIN                Module1.pm 
1      100        0      100      100        1        0 BEGIN                main.pl 
count  totaltime  mintime  avgtime  maxtime allocs  deallocs  func                 file 
allocations / deallocations (complete program): 
(399 /      114) perl 
time to run perl:     5368 uS (time on CPU     3814 uS)  | 
The (1/0) tuples in braces are counts of allocations and deallocations by the Perl interpreter in in that enter-return pair, and execution times are all using DTrace’s vtimestamp, so are adjusted for time on CPU.
This suggests to me that Perl use and require suffer from the same problems that are encountered when using #include’s inside header files in large scale C and C++, a massive, un-realized parser mess, due to the re-importation of dependencies for the short term convenience of the developer.
While the require output appears better, none the less (looking at the source code for Perl_ck_require) it does more than a nop the second time around (at minimum, its doing a single allocation, and converting the Module name to a File.pm). It is interesting (scary really) that the use case has many more allocations than the require case, but I presume that has to do with the sillyness of importing code into the same namespace several times. That main.pl’s BEGIN is parsed&allocated for 9 times, and Module2:BEGIN is parsed&allocated for twice – is not really what I had in mind.
For those of us working with large scale Perl code (in my case TWiki and Catalyst) it seems that there is not enough clarity, and there are opposing concerns for users that run Perl directly, incurring the parse and allocate steps each time, and those using accelerators such as mod_perl and speedy_cgi, who essentially start at the main-run phase (I think).
Reducing the above examples by removing the use or requires from everywhere except the top level main.pl, still shows an unexpected side effect that the use case has 34 more allocations and 26 deallocations – but… there is less going on. So it is possible, that the inconvenience of needing to manage the Perl module loading at the top level might be worth while, at least until Perl is changed to do what the ‘manual’ implies.
Another interesting side effect of replacing use with require, is that it moves the execution of the BEGIN from the parse phase to the execution phase – again reducing the effectiveness of Perl accelerators, but perhaps more inline with simplistic expectations.
Seems to me its time to move to bleadperl, and see if I can offer a fix.
The above tests are done using the dtrace enabled Perl 5.8.8  that is in my svn repository.
Like this:
Like Loading...
 
	
Related
	
	
		Author: Sven Dowideit
		
			You might remember me from tools like http://TWiki.org, http://Foswiki.org, https://github.com/docker/Boot2Docker, Docker documentation, or https://github.com/rancher/os			
				View all posts by Sven Dowideit