File Coverage

blib/lib/Devel/InterpreterSize.pm
Criterion Covered Total %
statement 25 38 65.7
branch 3 10 30.0
condition 2 15 13.3
subroutine 8 9 88.8
pod n/a
total 38 72 52.7


line stmt bran cond sub pod time code
1             package Devel::InterpreterSize;
2 1     1   2110 use strict;
  1         3  
  1         73  
3 1     1   7 use warnings;
  1         1  
  1         41  
4 1     1   26 use Carp qw/ confess /;
  1         2  
  1         72  
5 1     1   5 use Config;
  1         1  
  1         50  
6 1     1   2943 use Class::Load qw/ load_class /;
  1         101377  
  1         2838  
7             # The following code is wholesale is nicked from Apache::SizeLimit::Core
8              
9             our $VERSION = '0.01';
10              
11             sub new {
12 1     1   3251 my $class = shift;
13 1 50       9 confess("Need Linux::Smaps or Linux::Pid or BSD::Resource, or your osname $Config{'osname'} is unsupported")
14             unless _can_check_size();
15 1         7 bless {@_}, $class;
16             }
17              
18             sub can_check_size {
19 0     0   0 _can_check_size();
20             }
21              
22             sub check_size {
23 1     1   2502 my $class = shift;
24              
25 1         140 my ($size, $share) = $class->_platform_check_size();
26              
27 0           return ($size, $share, $size - $share);
28             }
29              
30             our $USE_SMAPS;
31             BEGIN {
32 1     1   24 my ($major,$minor) = split(/\./, $Config{'osvers'});
33 1 50 0     26 if ($Config{'osname'} eq 'solaris' &&
    50 33        
    0 33        
      0        
34             (($major > 2) || ($major == 2 && $minor >= 6))) {
35 0         0 *_can_check_size = sub () { 1 };
36 0         0 *_platform_check_size = \&_solaris_2_6_size_check;
37 0         0 *_platform_getppid = \&_perl_getppid;
38             }
39             elsif ($Config{'osname'} eq 'linux' && load_class('Linux::Pid')) {
40 1         4266 *_platform_getppid = \&_linux_getppid;
41 1         3 *_can_check_size = sub () { 1 };
42 1 0 0     4 if (load_class('Linux::Smaps') && Linux::Smaps->new($$)) {
43 0         0 $USE_SMAPS = 1;
44 0         0 *_platform_check_size = \&_linux_smaps_size_check;
45             }
46             else {
47 0         0 $USE_SMAPS = 0;
48 0         0 *_platform_check_size = \&_linux_size_check;
49             }
50             }
51             elsif ($Config{'osname'} =~ /(?:darwin|bsd|aix)/i && load_class('BSD::Resource')) {
52             # on OSX, getrusage() is returning 0 for proc & shared size.
53 0         0 *_can_check_size = sub () { 1 };
54 0         0 *_platform_check_size = \&_bsd_size_check;
55 0         0 *_platform_getppid = \&_perl_getppid;
56             }
57             else {
58 0         0 *_can_check_size = sub () { 0 };
59             }
60             }
61            
62             sub _linux_smaps_size_check {
63             my $class = shift;
64            
65             return $class->_linux_size_check() unless $USE_SMAPS;
66            
67             my $s = Linux::Smaps->new($$)->all;
68             return ($s->size, $s->shared_clean + $s->shared_dirty);
69             }
70            
71             sub _linux_size_check {
72             my $class = shift;
73            
74             my ($size, $share) = (0, 0);
75            
76             if (open my $fh, '<', '/proc/self/statm') {
77             ($size, $share) = (split /\s/, scalar <$fh>)[0,2];
78             close $fh;
79             }
80             else {
81             $class->_error_log("Fatal Error: couldn't access /proc/self/status");
82             }
83            
84             # linux on intel x86 has 4KB page size...
85             return ($size * 4, $share * 4);
86             }
87            
88             sub _solaris_2_6_size_check {
89             my $class = shift;
90            
91             my $size = -s "/proc/self/as"
92             or $class->_error_log("Fatal Error: /proc/self/as doesn't exist or is empty");
93             $size = int($size / 1024);
94            
95             # return 0 for share, to avoid undef warnings
96             return ($size, 0);
97             }
98            
99             # rss is in KB but ixrss is in BYTES.
100             # This is true on at least FreeBSD, OpenBSD, & NetBSD
101             sub _bsd_size_check {
102            
103             my @results = BSD::Resource::getrusage();
104             my $max_rss = $results[2];
105             my $max_ixrss = int ( $results[3] / 1024 );
106            
107             return ($max_rss, $max_ixrss);
108             }
109            
110             sub _win32_size_check {
111             my $class = shift;
112            
113             # get handle on current process
114             my $get_current_process = Win32::API->new(
115             'kernel32',
116             'get_current_process',
117             [],
118             'I'
119             );
120             my $proc = $get_current_process->Call();
121            
122             # memory usage is bundled up in ProcessMemoryCounters structure
123             # populated by GetProcessMemoryInfo() win32 call
124             my $DWORD = 'B32'; # 32 bits
125             my $SIZE_T = 'I'; # unsigned integer
126            
127             # build a buffer structure to populate
128             my $pmem_struct = "$DWORD" x 2 . "$SIZE_T" x 8;
129             my $mem_counters
130             = pack( $pmem_struct, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 );
131            
132             # GetProcessMemoryInfo is in "psapi.dll"
133             my $get_process_memory_info = new Win32::API(
134             'psapi',
135             'GetProcessMemoryInfo',
136             [ 'I', 'P', 'I' ],
137             'I'
138             );
139            
140             my $bool = $get_process_memory_info->Call(
141             $proc,
142             $mem_counters,
143             length $mem_counters,
144             );
145              
146             # unpack ProcessMemoryCounters structure
147             my $peak_working_set_size =
148             (unpack($pmem_struct, $mem_counters))[2];
149              
150             # only care about peak working set size
151             my $size = int($peak_working_set_size / 1024);
152              
153             return ($size, 0);
154             }
155              
156             sub _perl_getppid { return getppid }
157             sub _linux_getppid { return Linux::Pid::getppid() }
158              
159             1;
160              
161             __END__