File Coverage

blib/lib/Devel/FindGlobals.pm
Criterion Covered Total %
statement 4 6 66.6
branch n/a
condition n/a
subroutine 2 2 100.0
pod n/a
total 6 8 75.0


line stmt bran cond sub pod time code
1             package Devel::FindGlobals;
2              
3 1     1   28009 use strict;
  1         2  
  1         35  
4 1     1   435 use Devel::Size qw(size total_size);
  0            
  0            
5              
6             use base 'Exporter';
7             our @EXPORT = qw(find_globals find_globals_sizes print_globals_sizes);
8              
9             # may be overriden
10             our @TYPES = qw(SCALAR ARRAY HASH);
11             # for pretty output
12             our %SYMS = (
13             SCALAR => '$',
14             ARRAY => '@',
15             HASH => '%',
16             CODE => '&',
17             );
18              
19             our $VERSION = 0.03;
20              
21             {
22             # we don't want to hit a variable more than once, because we
23             # can get in a loop
24             my %seen = ();
25              
26             sub _seen {
27             my($sym) = @_;
28             if ($seen{$sym}) {
29             return 1;
30             } else {
31             $seen{$sym} = 1;
32             return 0;
33             }
34             }
35              
36             sub _reset_seen {
37             %seen = ();
38             }
39             }
40              
41              
42             =head1 NAME
43              
44             Devel::FindGlobals - Find global variables and their size
45              
46             =head1 SYNOPSIS
47              
48             use Devel::FindGlobals;
49             print print_globals_sizes();
50              
51             =head1 DESCRIPTION
52              
53             This module just runs around and over the symbol table, finds global variables,
54             gets their sizes with Devel::Size, and then prints them out.
55              
56             find_globals() just finds the globals (and returns a hashref), and
57             find_globals_sizes() returns the globals and the sizes in a hashref.
58             print_globals_sizes() prints out that data in a pretty table.
59              
60             find_globals() hashref is of the form $hash->{TYPE}{NAME}, where TYPE
61             is SCALAR, ARRAY, HASH (types stored in @Devel::FindGlobals::TYPES).
62              
63             find_globals_sizes() hashref is the same, except that the value of the
64             record is not C<1> but an arrayref of size and total_size (size is the
65             size of the variable itself, and total_size counts up all the other
66             members of the variable, for arrayrefs and hashrefs).
67              
68             print_globals_sizes() accepts an OPTIONS hash. Currently recognized
69             options are:
70              
71             =over 4
72              
73             =item * ignore_files
74              
75             Ignore file globals (like C<$main::_).
76             Default value is true.
77              
78             =item * ignore_undef_scalars
79              
80             Ignore scalars that exist, but are not defined. Default value is true.
81              
82             =item * exclude_match
83              
84             An arrayref of strings to match; e.g., ['^VERSION$', '^Debug']. Will not print
85             variables matching any of the expressions.
86              
87             =item * include_match
88              
89             Same as exclude_match, except for variables to exclusively include, instead of
90             strings to exclude.
91              
92             =item * lexicals
93              
94             A hashref of C reference> for lexical variables to include in the report.
95              
96             =back
97              
98             =head1 BUGS
99              
100             Code references, being not handled by Devel::Size, are not handled by this module.
101              
102             =cut
103              
104             sub print_globals_sizes {
105             my %opts = &_get_opts;
106             my $all = &find_globals_sizes;
107              
108             my $output = '';
109              
110             if (ref $opts{lexicals}) {
111             $output .= sprintf "\n%-45.45s %15s %15s\n" . ('=' x 80) . "\n",
112             "Name of lexical variable", "Size", "Total Size";
113              
114             for my $name (sort keys %{$opts{lexicals}}) {
115             $output .= sprintf "%-45s %15d %15d\n", $name,
116             size($opts{lexicals}{$name}),
117             total_size($opts{lexicals}{$name});
118             }
119             }
120              
121             for my $type (@TYPES) {
122             $output .= sprintf "\n%-45.45s %15s %15s\n" . ('=' x 80) . "\n",
123             "Name of $type variable", "Size", "Total Size";
124              
125             for my $full (sort keys %{$all->{$type}}) {
126             # list strings to explicitly exclude ...
127             if (ref $opts{exclude_match} &&
128             grep { $full =~ /$_/ } @{$opts{exclude_match}}) {
129             next;
130             }
131              
132             # ... or include
133             if (ref $opts{include_match} &&
134             !grep { $full =~ /$_/ } @{$opts{include_match}}) {
135             next;
136             }
137              
138             # files are stores in special scalars, we don't care, usually
139             if ($opts{ignore_files}) {
140             next if $full =~ /^main::_
141             }
142              
143             # many scalars end up being created for subs etc. ...
144             if ($opts{ignore_undef_scalars} && $type eq 'SCALAR') {
145             next unless defined $$full;
146             }
147              
148             (my $print = $full) =~ s/([^[:print:]]|\s)/sprintf("%%%02X", ord $1)/ge;
149             $print = $SYMS{$type} . $print if $SYMS{$type};
150              
151             $output .= sprintf "%-45.45s %15d %15d\n",
152             $print, @{$all->{$type}{$full}};
153             }
154             }
155             return $output;
156             }
157              
158              
159             # get the sizes for each global (size == size of *V, total_size == size of entire
160             # structure (e.g., references))
161             sub find_globals_sizes {
162             my $all = find_globals();
163              
164             no strict 'refs';
165             for my $type (@TYPES) {
166             for my $full (keys %{$all->{$type}}) {
167             local $^W;
168             $all->{$type}{$full} = [
169             size(*{$full}{$type}),
170             total_size(*{$full}{$type})
171             ];
172             }
173             }
174              
175             return $all;
176             }
177              
178             # recursively find all the global variables and stick them in a hashref
179             sub find_globals {
180             my($sym, $all) = @_;
181             $sym ||= 'main::';
182             if (!$all) {
183             &_reset_seen;
184             $all = {};
185             }
186              
187             return if _seen($sym);
188              
189             no strict 'refs';
190             for my $name (keys %$sym) {
191              
192             if ($name =~ /::$/) { # new symbol table
193             my $new = $sym eq 'main::' ? $name : $sym . $name;
194             find_globals($new, $all);
195             next;
196             }
197              
198             my $full = "$sym$name";
199             next if _seen($full);
200              
201             for my $type (@TYPES) {
202             if (defined *{$full}{$type}) {
203             $all->{$type}{$full} = 1;
204             }
205             }
206             }
207              
208             return $all;
209             }
210              
211             sub _get_opts {
212             my %opts = @_;
213             $opts{ignore_files} = 1 unless defined $opts{ignore_files};
214             $opts{ignore_undef_scalars} = 1 unless defined $opts{ignore_undef_scalars};
215             return %opts;
216             }
217              
218             1;
219              
220             =head1 AUTHOR
221              
222             Chris Nandor Epudge@pobox.comE, http://pudge.net/
223              
224             Copyright (c) 2002-2004 Chris Nandor. All rights reserved. This program
225             is free software; you can redistribute it and/or modify it under the same
226             terms as Perl itself.
227              
228             =head1 SEE ALSO
229              
230             perl(1), perlguts(1), Devel::Size.
231              
232             =cut
233              
234             __END__