File Coverage

blib/lib/B/Size2/Terse.pm
Criterion Covered Total %
statement 152 390 38.9
branch 39 136 28.6
condition 6 46 13.0
subroutine 18 47 38.3
pod 0 16 0.0
total 215 635 33.8


line stmt bran cond sub pod time code
1             # The original notice of B::Size:
2             # B::TerseSize.pm
3             # Copyright (c) 1999 Doug MacEachern. All rights reserved.
4             # This module is free software; you can redistribute and/or modify
5             # it under the same terms as Perl itself.
6              
7             # portions of this module are based on B::Terse, by Malcolm Beattie
8              
9             package B::Size2::Terse;
10              
11 2     2   1590 use strict;
  2         5  
  2         95  
12 2     2   13 use warnings;
  2         3  
  2         80  
13 2   50 2   11 use constant IS_MODPERL => ($ENV{MOD_PERL} || 0);
  2         4  
  2         167  
14 2 50 50 2   11 use constant MP2 => ($ENV{MOD_PERL_API_VERSION} || 0) == 2 ? 1 : 0;
  2         3  
  2         134  
15              
16 2     2   10 use B ();
  2         3  
  2         37  
17 2     2   12 use B::Size2 ();
  2         9  
  2         1086  
18              
19             our $VERSION = "2.07";
20              
21             my $opcount;
22             my $opsize;
23             my $copsize;
24             my $curcop;
25              
26             sub UNIVERSAL::op_size {
27 44567     44567 0 63932 $opcount++;
28 44567         100500 my $size = shift->size;
29 44567         49132 $opsize += $size;
30 44567         580398 $copsize += $size;
31             }
32              
33             my $mouse_attr =
34             qq( onclick='javascript: return false') .
35             qq( onmouseout='window.status=""; return true');
36              
37             sub op_html_name {
38 0     0 0 0 my($op, $sname) = @_;
39              
40 0         0 $sname =~ s/(\s+)$//;
41 0   0     0 my $pad = $1 || "";
42 0   0     0 my $desc = sprintf
43             qq(onmouseover='window.status="%s"; return true'),
44             B::OP::op_desc($op->type) || "unknown";
45 0 0       0 my $href = $curcop ? $curcop->line : "";
46              
47 0         0 return qq($sname$pad);
48             }
49              
50             sub peekop {
51 0     0 0 0 my $op = shift;
52              
53 0         0 my $size = $op->size;
54 0         0 $opcount++;
55 0         0 $opsize += $size;
56 0         0 $copsize += $size;
57 0         0 my $name;
58 0         0 my $sname = sprintf "%-13s", $op->name;
59              
60 0         0 if (IS_MODPERL) {
61             $name = op_html_name($op, $sname);
62             }
63             else {
64 0         0 $name = $sname;
65             }
66              
67 0         0 my $addr = sprintf "0x%lx", $$op;
68 0         0 $addr = qq($addr) if IS_MODPERL;
69              
70 0         0 return sprintf qq(%-6s $name $addr {%d bytes}),
71             B::class($op), $size;
72             }
73              
74             my $hr = "=" x 60;
75             my %filelex = ();
76              
77             sub package_size {
78 7     7 0 7739 my($package) = @_;
79              
80             #local *UNIVERSAL::op_size = \&universal_op_size;
81              
82 7         18 my %retval = ();
83 7         16 my $total_opsize = 0;
84 7         11 my $total_opcount = 0;
85 7         59 my $stash;
86             {
87 2     2   80 no strict;
  2         3  
  2         178  
  7         12  
88 7         10 $stash = \%{"$package\::"};
  7         37  
89             }
90              
91 7         330 for (keys %$stash) {
92 686         1574 my $name = $package . "::$_";
93 686         1034 my $has_code = 0;
94              
95             {
96 2     2   9 no strict;
  2         3  
  2         401  
  686         752  
97 686         663 $has_code = *{$name}{CODE}; #defined() expects CvROOT || CvXSUB
  686         2985  
98             }
99              
100 686 100       1579 unless ($has_code) { #CV_walk will measure
101 282         329 $total_opsize +=
102             B::Sizeof::GV + B::Sizeof::XPVGV + B::Sizeof::GP;
103             }
104              
105             #measure global variables
106 686         1037 for my $type (qw(ARRAY HASH SCALAR)) {
107 2058 100       8078 next if $name =~ /::$/; #stash
108 1860 100       4651 next unless /^[\w_]/;
109 1641 100       3423 next if /^_
110 1329         1412 my $ref = do {
111 2     2   12 no strict 'refs';
  2         3  
  2         1192  
112 1329         1203 *{$name}{$type};
  1329         4041  
113             };
114 1329 100       3094 next unless defined $ref;
115 464         1610 my $obj = B::svref_2object($ref);
116 464 100       2083 next if ref($obj) eq 'B::NULL';
117 45         154 my $tsize = $obj->size;
118 45         65 $total_opsize += $tsize;
119 45         412 $retval{"*${_}{$type}"} = {'size' => $tsize};
120             }
121              
122 686 100       1602 next unless defined $has_code;
123              
124 404         892 CV_walk('slow', $name, 'op_size');
125              
126 404         575 for (keys %{ $filelex{$package} }) {
  404         1911  
127 168         466 my $fsize = $filelex{$package}->{$_};
128 168         12998 $total_opsize += $opsize;
129 168         1107 $retval{"my ${_} = ...;"} =
130             {'size' => $fsize};
131             }
132 404         1123 %filelex = ();
133 404         438 $total_opsize += $opsize;
134 404         395 $total_opcount += $opcount;
135 404         2030 $retval{$_} = {'count' => $opcount, 'size' => $opsize};
136             }
137              
138 7         229 return (\%retval, $total_opcount, $total_opsize);
139             }
140              
141             my $b_objsym = \&B::objsym;
142              
143             sub objsym {
144 0     0 0 0 my $obj = shift;
145 0         0 my $value = $b_objsym->($obj);
146 0 0       0 return unless $value;
147 0         0 sprintf qq($value), $$obj;
148             }
149              
150             sub CV_walk {
151 404     404 0 677 my($order, $objname, $meth) = @_;
152              
153 404   50     718 $meth ||= 'terse_size';
154 404         838 my $cvref = \&{$objname};
  404         1075  
155 404         1414 my $cv = B::svref_2object($cvref);
156 404         2605 my($package, $func) = ($objname =~ /(.*)::([^:]+)$/);
157              
158 404         539 $opsize = B::Sizeof::GV + B::Sizeof::XPVGV + B::Sizeof::GP;
159 404         409 $opcount = 0;
160 404         631 $curcop = "";
161              
162 404         1616 my $gv = $cv->GV;
163 404         1299 $opsize += length $gv->NAME;
164              
165 404 100       1286 if (my $stash = $cv->is_alias($package)) {
166 31         77 return;
167             }
168              
169 373         499 $opsize += B::Sizeof::XPVCV;
170              
171 373         385 $opsize += B::Sizeof::SV;
172 373 100       1120 if ($cv->FLAGS & B::SVf_POK) {
173 19         74 $opsize += B::Sizeof::XPV + length $cv->PV;
174             }
175             else {
176 354         621 $opsize += B::Sizeof::XPVIV; #IVX == -1 for no prototype
177             }
178              
179 373         756 init_curpad_names($cvref);
180              
181 2     2   14 no strict;
  2         4  
  2         5623  
182 373         772 local *B::objesym = \&objsym if IS_MODPERL;
183              
184 373 50       729 if ($order eq 'exec') {
185 0         0 B::walkoptree_exec($cv->START, $meth);
186             } else {
187 373         2790 B::walkoptree_slow($cv->ROOT, $meth);
188             }
189              
190 373 50       1053 curcop_info() if $curcop;
191              
192 373         900 my($padsize, $padsummary) = PADLIST_size($cv);
193 373         549 $opsize += $padsize;
194              
195 373         1763 $padsummary;
196             }
197              
198             sub terse_size {
199 0     0 0 0 my($order, $objname) = @_;
200              
201 0         0 my $padsummary = CV_walk($order, $objname);
202              
203 0         0 print "\n$hr\nTotals: $opsize bytes | $opcount OPs\n$hr\n";
204              
205 0 0       0 if ($padsummary) {
206 0         0 print "\nPADLIST summary:\n";
207 0         0 print @$padsummary;
208             }
209             }
210              
211             my @curpad_names = ();
212              
213             sub init_curpad_names {
214 373     373 0 1177 my $cv = B::svref_2object(shift);
215 373         1481 my $padlist = $cv->PADLIST;
216 373 100       1342 return unless $padlist->can('ARRAY');
217 362         1828 my $padnames = ($padlist->ARRAY)[0];
218 362 50       1422 return unless $padnames->can('ARRAY');
219 362         6454 @curpad_names = $padnames->ARRAY;
220             }
221              
222             sub compile {
223 0     0 0 0 my $order = shift;
224 0         0 my @options = @_;
225 0 0       0 B::clearsym() if defined &B::clearsym;
226              
227 0 0       0 if (@options) {
228             return sub {
229 0     0   0 my $objname;
230 0         0 foreach $objname (@options) {
231 0 0       0 $objname = "main::$objname" unless $objname =~ /::/;
232 0         0 terse_size($order, $objname);
233             }
234             }
235 0         0 } else {
236 0 0       0 if ($order eq "exec") {
237 0     0   0 return sub { B::walkoptree_exec(B::main_start, "terse_size");
238 0 0       0 curcop_info() if $curcop}
239 0         0 } else {
240 0     0   0 return sub { B::walkoptree_slow(B::main_root, "terse_size");
241 0 0       0 curcop_info() if $curcop}
242 0         0 }
243             }
244             }
245              
246             sub indent {
247 0     0 0 0 my $level = shift;
248 0         0 return " " x $level;
249             }
250              
251             #thanks B::Deparse
252             sub padname {
253 6414     6414 0 6816 my($sv) = @_;
254 6414 100 66     24726 if (!( ref $sv && $sv->FLAGS & (B::SVf_POK | B::SVp_POK) != 0 )) {
255 6385         11512 return '?';
256             }
257 29         102 my $str = $sv->PVX;
258 29         75 my $ix = index($str, "\0");
259 29 50       76 $str = substr($str, 0, $ix) if $ix != -1;
260 29         53 return $str;
261             }
262              
263             sub B::OP::terse_size {
264 0     0   0 my ($op, $level) = @_;
265 0         0 my $t = $op->targ;
266 0         0 my $targ = "";
267 0 0       0 if ($t > 0) {
268 0         0 my $name = B::OP::op_name($op->targ);
269 0         0 my $desc = B::OP::op_desc($op->targ);
270 0 0       0 if ($op->type == 0) { #OP_NULL
271 0 0       0 $targ = $name eq $desc ? " [$name]" :
272             sprintf " [%s - %s]", $name, $desc;
273             }
274             else {
275 0         0 $targ = sprintf " [targ %d - %s]", $t,
276             padname($curpad_names[$t]);
277             }
278             }
279 0         0 print indent($level), peekop($op), $targ, "\n";
280             }
281              
282             sub B::SVOP::terse_size {
283 0     0   0 my ($op, $level) = @_;
284 0         0 print indent($level), peekop($op), " ";
285 0         0 $op->sv->terse_size(0);
286             }
287              
288             sub B::GVOP::terse_size {
289 0     0   0 my ($op, $level) = @_;
290 0         0 print indent($level), peekop($op), " ";
291 0         0 $op->gv->terse_size(0);
292             }
293              
294             sub B::PMOP::terse_size {
295 0     0   0 my ($op, $level) = @_;
296 0         0 my $precomp = $op->precomp;
297 0 0       0 print indent($level), peekop($op),
298             (defined($precomp) ? " /$precomp/\n" : " (regexp not compiled)\n");
299             }
300              
301             sub B::PVOP::terse_size {
302 0     0   0 my ($op, $level) = @_;
303 0         0 print indent($level), peekop($op), " ", B::cstring($op->pv), "\n";
304             }
305              
306             my $hr2 = "-" x 60;
307              
308             *cop_file = B::COP->can('file') || sub {
309             shift->filegv->SV->PV;
310             };
311              
312             sub curcop_info {
313 0     0 0 0 my $line = $curcop->line;
314 0         0 my $linestr = "line $line";
315              
316 0 0 0     0 if ($line > 0 && IS_MODPERL) {
317 0         0 my $anchor = "";
318 0 0       0 if ($line > 10) {
319 0         0 $anchor = "#" . ($line - 10);
320             }
321 0         0 my $window = sprintf "offset=%d&len=%d", $line - 100, $line + 100;
322 0         0 my $args = sprintf "noh_fileline=1&filename=%s&line=%d&$window",
323             cop_file($curcop), $line;
324 0         0 my $uri = MP2 ? Apache2::RequestUtil->request()->location() : Apache->request->location;
325 0         0 $linestr = qq($linestr);
326             }
327              
328 0         0 print "\n[$linestr size: $copsize bytes]\n";
329             }
330              
331             sub B::COP::terse_size {
332 0     0   0 my ($op, $level) = @_;
333              
334 0   0     0 my $label = $op->label || "";
335 0 0       0 if ($label) {
336 0         0 $label = " label ".B::cstring($label);
337             }
338              
339 0 0       0 curcop_info() if $curcop;
340              
341 0         0 $copsize = 0;
342 0         0 $curcop = $op;
343              
344 0         0 print "\n$hr2\n", indent($level), peekop($op), "$label\n";
345             }
346              
347              
348             sub B::PV::terse_size {
349 0     0   0 my ($sv, $level) = @_;
350 0         0 print indent($level);
351 0         0 my $pv = B::cstring($sv->PV);
352 0         0 B::Size2::escape_html(\$pv) if IS_MODPERL;
353 0         0 printf "%s %s\n", B::class($sv), $pv;
354             }
355              
356             sub B::AV::terse_size {
357 0     0   0 my ($sv, $level) = @_;
358 0         0 print indent($level);
359 0         0 printf "%s FILL %d\n", B::class($sv), $sv->FILL;
360             }
361              
362             sub B::GV::terse_size {
363 0     0   0 my ($gv, $level) = @_;
364 0         0 my $stash = $gv->STASH->NAME;
365 0 0       0 if ($stash eq "main") {
366 0         0 $stash = "";
367             } else {
368 0         0 $stash = $stash . "::";
369             }
370 0         0 print indent($level);
371 0         0 printf "%s *%s%s\n", B::class($gv), $stash, $gv->NAME;
372             }
373              
374             sub B::IV::terse_size {
375 0     0   0 my ($sv, $level) = @_;
376 0         0 print indent($level);
377 0         0 printf "%s %d\n", B::class($sv), $sv->IV;
378             }
379              
380             sub B::NV::terse_size {
381 0     0   0 my ($sv, $level) = @_;
382 0         0 print indent($level);
383 0         0 printf "%s %s\n", B::class($sv), $sv->NV;
384             }
385              
386             sub B::RV::terse_size {
387 0     0   0 my ($sv, $level) = @_;
388 0         0 print indent($level);
389 0         0 printf "%s \n", B::class($sv);
390             }
391              
392             sub B::NULL::terse_size {
393 0     0   0 my ($sv, $level) = @_;
394 0         0 print indent($level);
395 0         0 printf "%s \n", B::class($sv);
396             }
397              
398             sub B::SPECIAL::terse_size {
399 0     0   0 my ($sv, $level) = @_;
400 0         0 print indent($level);
401 0         0 printf "%s #%d %s\n", B::class($sv), $$sv, $B::specialsv_name[$$sv];
402             }
403              
404             my $padname_max = 0;
405              
406             sub PADLIST_size {
407 373     373 0 439 my $cv = shift;
408 373 50       1486 my $obj = UNIVERSAL::isa($cv, "B::CV") ? $cv : B::svref_2object($cv);
409              
410 373 100       2412 if (! $obj->PADLIST->isa('B::PADLIST')) {
411 11         41 return $obj->size;
412             }
413              
414 362         558 my $size = (B::Sizeof::AV + B::Sizeof::XPVAV) * 3; #padlist, names, values
415              
416              
417 362         1851 my($padnames, $padvals) = $obj->PADLIST->ARRAY;
418 362         10586 my @names = $padnames->ARRAY;
419 362         698 $padname_max = 0;
420 6414         10145 my @names_pv = map {
421 362         643 my $pv = padname($_);
422 6414 100       12308 $padname_max = length($pv) > $padname_max ?
423             length($pv) : $padname_max;
424 6414         13414 $pv;
425             } @names;
426              
427 362         5446 my @vals = $padvals->ARRAY;
428 362         1194 my $fill = $padnames->FILL;
429 362         546 my $fill_len = length $fill;
430 362         479 my @retval = ();
431 362         619 my $wantarray = wantarray;
432              
433 362         882 for (my $i = 0; $i <= $fill; $i++) {
434 6414         15675 my $entsize = $names[$i]->size;
435 6414         15096 my $is_fake = $names[$i]->FLAGS & B::SVf_FAKE;
436 6414 100       15380 if ($is_fake) {
437 242         296 $entsize += B::Sizeof::SV; # just a reference to outside scope
438 242         952 my $outside = $obj->OUTSIDE;
439 242 50 33     3019 if ($outside->can('GV') && B::class($outside->GV) eq 'SPECIAL') {
440 242         711 $filelex{ $obj->GV->STASH->NAME }->{ $names_pv[$i] } =
441             $vals[$i]->size;
442             }
443             else {
444             #XXX nested/anonsubs
445             }
446             }
447             else {
448 6172         14111 $entsize += $vals[$i]->size;
449             }
450 6414         7388 $size += $entsize;
451 6414 50       11928 next unless $wantarray;
452              
453 6414         36787 my $class = B::class($vals[$i]);
454 6414         16131 my $byteinfo = sprintf "[%-4s %3d bytes]",
455             $class, $entsize;
456              
457 2     2   21 no warnings;
  2         5  
  2         3621  
458 6414 100       26579 push @retval, sprintf "%${fill_len}d: %${padname_max}s %s %s\n",
459             $i,
460             $names_pv[$i],
461             $byteinfo,
462             $is_fake ? '__SvFAKE__' : $vals[$i]->sizeval;
463             }
464              
465 362 50       3483 return $wantarray ? ($size, \@retval) : $size;
466             }
467              
468             #hmm, I wonder if B::Deparse could be used instead
469             sub Apache::Status::noh_fileline {
470 0     0     my $r = shift;
471 0           my %args = $r->args;
472 0   0       my $offset = $args{offset} || 0;
473 0   0       my $len = $args{len} || 0;
474              
475 0           local *FH;
476 0           my $filename = $args{filename};
477 0           $r->send_http_header('text/html');
478              
479 0 0         unless (Apache::Status::status_config($r, "StatusTerseSize")) {
480 0           print "sorry, StatusTerseSize not enabled\n";
481 0           return 0;
482             }
483              
484 0 0         unless (exists $main::{"_<$filename"}) {
485             #useithreads doesnt gv_fetchfile()
486 0           my $in_inc = 0;
487 0           for (keys %INC) {
488 0 0         if ($INC{$_} eq $filename) {
489 0           $in_inc = 1;
490 0           $main::{"_<$filename"} = $_;
491 0           last;
492             }
493             }
494 0 0         unless ($in_inc) {
495 0           print "sorry, `$filename' is not a file used by Perl\n";
496 0           return 0;
497             }
498             }
499              
500 0           my $i = 0;
501 0           $r->print('
'); 
502 0 0         if ($offset > 0) {
503 0           printf "%4d..%d [...]\n", 1, $offset-1;
504             }
505 0 0         open FH, $filename or die $!;
506 0           while () {
507 0           $i++;
508 0 0 0       next if $len > 0 and $i > $len;
509 0 0 0       next if $offset > 0 and $i < $offset;
510 0           chomp;
511 0           s/^\t/ /; #indent proper
512 0           my $lineno = sprintf "%4d", $i;
513 0           B::Size2::escape_html(\$_);
514 0 0         my $line = ($i == $args{line}) ?
515             \qq($_) : \$_;
516 0           print qq($lineno: $$line\n);
517              
518             }
519 0 0 0       if ($len > 0 and $i > $len) {
520 0           printf "%4d..%d [...]\n", $len+1, $i;
521             }
522 0           close FH;
523              
524 0           0;
525             }
526              
527             sub Apache2::Status::noh_fileline {
528 0     0     my $r = shift;
529 0           my $args = $r->args;
530              
531 0           require CGI;
532 0           my $CGI = CGI->new($args);
533 0           my %params = map { $_ => $CGI->param($_) } $CGI->param();
  0            
534              
535 0   0       my $offset = $params{offset} || 0;
536 0   0       my $len = $params{len} || 0;
537              
538 0           local *FH;
539 0           my $filename = $params{filename};
540 0           $r->content_type('text/html');
541              
542 0 0         unless (Apache2::Status::status_config($r, "StatusTerseSize")) {
543 0           print "sorry, StatusTerseSize not enabled\n";
544 0           return 0;
545             }
546              
547 0 0         unless (exists $main::{"_<$filename"}) {
548             #useithreads doesnt gv_fetchfile()
549 0           my $in_inc = 0;
550 0           for (keys %INC) {
551 0 0         if ($INC{$_} eq $filename) {
552 0           $in_inc = 1;
553 0           $main::{"_<$filename"} = $_;
554 0           last;
555             }
556             }
557 0 0         unless ($in_inc) {
558 0           print "sorry, '$filename' is not a file used by Perl\n";
559 0           return 0;
560             }
561             }
562              
563 0           my $i = 0;
564 0           $r->print('
'); 
565 0 0         if ($offset > 0) {
566 0           printf "%4d..%d [...]\n", 1, $offset-1;
567             }
568 0 0         open FH, $filename or die $!;
569 0           while () {
570 0           $i++;
571 0 0 0       next if $len > 0 and $i > $len;
572 0 0 0       next if $offset > 0 and $i < $offset;
573 0           chomp;
574 0           s/^\t/ /; #indent proper
575 0           my $lineno = sprintf "%4d", $i;
576 0           B::Size2::escape_html(\$_);
577 0 0         my $line = ($i == $params{line}) ?
578             \qq($_) : \$_;
579 0           print qq($lineno: $$line\n);
580              
581             }
582 0 0 0       if ($len > 0 and $i > $len) {
583 0           printf "%4d..%d [...]\n", $len+1, $i;
584             }
585 0           close FH;
586              
587 0           0;
588             }
589              
590             sub max {
591 0     0 0   my($cur, $maybe) = @_;
592 0 0         $maybe > $cur ? $maybe : $cur;
593             }
594              
595             my %summary_cache = ();
596              
597             sub apache_package_size {
598 0     0 0   my $package = shift;
599 0           my($subs, $opcount, $opsize);
600 0           my $keys = 0;
601 0           my $cache = {};
602              
603             {
604 2     2   16 no strict 'refs';
  2         4  
  2         1417  
  0            
605 0           $keys = keys %{"$package\::"};
  0            
606             }
607              
608 0 0         if ($cache = $summary_cache{$package}) {
609 0 0         if ($cache->{'keys'} == $keys) {
610 0 0         return @{ $cache->{'data'} } if $cache->{'data'};
  0            
611             }
612             }
613              
614 0           $cache->{'keys'} = $keys;
615 0           $summary_cache{$package} = $cache;
616 0           @{ $cache->{'data'} } = B::Size2::Terse::package_size($package);
  0            
617             }
618              
619             sub status_memory_usage {
620 0     0 0   my($r, $q) = @_;
621              
622 0           if (MP2) {
623             unless (Apache2::Status::status_config($r, "StatusTerseSize")) {
624             return ["StatusTerseSize is not enabled"];
625             }
626             }
627             else {
628 0 0         unless (Apache::Status::status_config($r, "StatusTerseSize")) {
629 0           return ["StatusTerseSize is not enabled"];
630             }
631             }
632              
633 0 0         unless ($r->dir_config("StatusTerseSizeMainSummary")) {
634 0           return ["StatusTerseSizeMainSummary is not enabled"];
635             }
636              
637 0           my $script = MP2 ? $r->uri : $q->script_name;
638 0           my $stab = Devel::Symdump->rnew('main');
639 0           my %total;
640 0           my @retval = ('
'); 
641 0           my($clen, $slen, $nlen);
642              
643 0           for my $package ('main', $stab->packages) {
644 0           my($subs, $opcount, $opsize) = apache_package_size($package);
645 0           $total{$package} = {'count' => $opcount, 'size' => $opsize};
646 0           $nlen = max($nlen, length $package);
647 0           $slen = max($slen, length $opsize);
648 0           $clen = max($clen, length $opcount);
649             }
650              
651 0           for (sort { $total{$b}->{size} <=> $total{$a}->{size} } keys %total) {
  0            
652 0           my $link = qq();
653 0           push @retval,
654             sprintf "$link%-${nlen}s %${slen}d bytes | %${clen}d OPs\n",
655             $_, $total{$_}->{size}, $total{$_}->{count};
656             }
657 0           \@retval;
658             }
659              
660             if (MP2) {
661             Apache2::Status->menu_item(
662             'status_memory_usage' => "Memory Usage",
663             \&status_memory_usage,
664             );
665             }
666             elsif (IS_MODPERL and Apache->module("Apache::Status")) {
667             Apache::Status->menu_item(
668             'status_memory_usage' => "Memory Usage",
669             \&status_memory_usage,
670             );
671             }
672              
673             1;
674              
675             __END__