File Coverage

blib/lib/Catalyst/Plugin/MemoryUsage.pm
Criterion Covered Total %
statement 11 13 84.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 16 18 88.8


line stmt bran cond sub pod time code
1             package Catalyst::Plugin::MemoryUsage;
2             BEGIN {
3 2     2   64606 $Catalyst::Plugin::MemoryUsage::AUTHORITY = 'cpan:YANICK';
4             }
5             {
6             $Catalyst::Plugin::MemoryUsage::VERSION = '0.4.0';
7             }
8             #ABSTRACT: Profile memory usage of requests
9              
10 2     2   17 use strict;
  2         5  
  2         61  
11 2     2   10 use warnings;
  2         4  
  2         66  
12              
13 2     2   1671 use namespace::autoclean;
  2         47717  
  2         14  
14 2     2   858 use Moose::Role;
  0            
  0            
15             use MRO::Compat;
16              
17             use Memory::Usage;
18              
19             use Devel::CheckOS;
20             use Text::SimpleTable;
21             use Number::Bytes::Human qw/ format_bytes /;
22             use List::Util qw/ max /;
23              
24             our @SUPPORTED_OSES = qw/ Linux NetBSD /;
25              
26             our $os_not_supported = Devel::CheckOS::os_isnt( @SUPPORTED_OSES );
27              
28             if ( $os_not_supported ) {
29             warn "OS not supported by Catalyst::Plugin::MemoryUsage\n",
30             "\tStats will not be collected\n";
31             }
32              
33              
34             has memory_usage => (
35             is => 'rw',
36             default => sub { Memory::Usage->new },
37             );
38              
39             our $_memory_usage_report;
40             our $_memory_usage_record_actions;
41              
42              
43             after setup_finalize => sub {
44             my $c = shift;
45              
46             my %config = %{ $c->config->{'Plugin::MemoryUsage'} || {} };
47              
48             $_memory_usage_report =
49             exists $config{report} ? $config{report} : $c->debug;
50              
51             $_memory_usage_record_actions =
52             exists $config{action_milestones}
53             ? $config{action_milestones} : $c->debug;
54             };
55              
56              
57              
58              
59             sub reset_memory_usage {
60             my $self = shift;
61              
62             $self->memory_usage( Memory::Usage->new );
63             }
64              
65             sub memory_usage_report {
66             my $self = shift;
67              
68             my $title_width = max 10,
69             map { length $_->[1] } @{ $self->memory_usage->state };
70              
71             my $table = Text::SimpleTable->new(
72             [$title_width, ''],
73             [4, 'vsz'],
74             [4, 'delta'],
75             [4, 'rss'],
76             [4, 'delta'],
77             [4, 'shared'],
78             [4, 'delta'],
79             [4, 'code'],
80             [4, 'delta'],
81             [4, 'data'],
82             [4, 'delta'],
83             );
84              
85             my @previous;
86              
87             for my $s ( @{ $self->memory_usage->state } ) {
88             my ( undef, $msg, @sizes ) = @$s;
89              
90             my @data = map { $_ ? format_bytes( 1024 * $_) : '' } map {
91             ( $sizes[$_], @previous ? $sizes[$_] - $previous[$_] : 0 )
92             } 0..4;
93             @previous = @sizes;
94              
95             $table->row( $msg, @data );
96             }
97              
98             return $table->draw;
99             }
100              
101             unless ( $os_not_supported ) {
102              
103             after execute => sub {
104             return unless $_memory_usage_record_actions;
105              
106             my $c = shift;
107             $c->memory_usage->record( "after " . join " : ", @_ );
108             };
109              
110             around prepare => sub {
111             my $orig = shift;
112             my $self = shift;
113              
114             my $c = $self->$orig(@_);
115              
116             $c->memory_usage->record('preparing for the request')
117             if $_memory_usage_record_actions;
118              
119             return $c;
120             };
121              
122             after finalize => sub {
123             return unless $_memory_usage_report;
124              
125             my $c = shift;
126             $c->log->debug(
127             sprintf(qq{[%s] memory usage of request "%s" from "%s"\n},
128             [split m{::}, __PACKAGE__]->[-1],
129             $c->req->uri,
130             $c->req->address,
131             ),
132             $c->memory_usage_report
133             );
134             };
135              
136             }
137              
138             1;
139              
140             __END__
141              
142             =pod
143              
144             =head1 NAME
145              
146             Catalyst::Plugin::MemoryUsage - Profile memory usage of requests
147              
148             =head1 VERSION
149              
150             version 0.4.0
151              
152             =head1 SYNOPSIS
153              
154             In YourApp.pm:
155              
156             package YourApp;
157              
158             use Catalyst qw/
159             MemoryUsage
160             /;
161              
162             In a Controller class:
163              
164             sub foo :Path( '/foo' ) {
165             # ...
166            
167             something_big_and_scary();
168            
169             $c->memory_usage->record( 'finished running iffy code' );
170            
171             # ...
172             }
173              
174             In yourapp.conf:
175              
176             <Plugin::MemoryUsage>
177             report 1
178             action_milestones 1
179             </Plugin::MemoryUsage>
180              
181             =head1 DESCRIPTION
182              
183             C<Catalyst::Plugin::MemoryUsage> adds a memory usage profile to your debugging
184             log, which looks like this:
185              
186             [debug] [MemoryUsage] memory usage of request "http://localhost/index" from "127.0.0.1"
187             .--------------------------------------------------+------+------+------+------+------+------+------+------+------+------.
188             | | vsz | del- | rss | del- | sha- | del- | code | del- | data | del- |
189             | | | ta | | ta | red | ta | | ta | | ta |
190             +--------------------------------------------------+------+------+------+------+------+------+------+------+------+------+
191             | preparing for the request | 28M | | 22M | | 2.2M | | 1.1M | | 20M | |
192             | after TestApp::Controller::Root : root/_BEGIN | 28M | | 22M | | 2.2M | | 1.1M | | 20M | |
193             | after TestApp::Controller::Root : root/_AUTO | 28M | | 22M | | 2.2M | | 1.1M | | 20M | |
194             | in the middle of index | 28M | | 22M | | 2.2M | | 1.1M | | 20M | |
195             | after TestApp::Controller::Root : root/index | 28M | | 22M | | 2.2M | | 1.1M | | 20M | |
196             | after TestApp::Controller::Root : root/_ACTION | 28M | | 22M | | 2.2M | | 1.1M | | 20M | |
197             | after TestApp::Controller::Root : root/_END | 28M | | 22M | | 2.2M | | 1.1M | | 20M | |
198             | after TestApp::Controller::Root : root/_DISPATCH | 28M | | 22M | | 2.2M | | 1.1M | | 20M | |
199             '--------------------------------------------------+------+------+------+------+------+------+------+------+------+------'
200              
201             =head1 CONFIGURATION
202              
203             =head2 report
204              
205             If true, the memory usage is reported automatically (at debug level)
206             at the end of the request.
207              
208             Defaults to true if we are in debugging mode,
209             false otherwise.
210              
211             =head2 action_milestones
212              
213             If true, automatically adds milestones for each action, as seen in the
214             DESCRIPTION.
215              
216             Defaults to true if we are in debugging mode,
217             false otherwise.
218              
219             =head1 METHODS
220              
221             =head2 C<memory_usage()>
222              
223             Returns the L<Memory::Usage> object available to the context.
224              
225             To record more measure points for the memory profiling, use the C<record()>
226             method of that object:
227              
228             sub foo :Path {
229             my ( $self, $c) = @_;
230              
231             ...
232              
233             big_stuff();
234              
235             $c->memory_usage->record( "done with big_stuff()" );
236              
237             ...
238             }
239              
240             =head2 C<reset_memory_usage()>
241              
242             Discards the current C<Memory::Usage> object, along with its recorded data,
243             and replaces it by a shiny new one.
244              
245             =head1 BUGS AND LIMITATIONS
246              
247             C<Memory::Usage>, which is the module C<Catalyst::Plugin::MemoryUsage> relies
248             on to get its statistics, only work for Linux-based platforms. Consequently,
249             for the time being C<Catalyst::Plugin::MemoryUsage> only work on Linux and
250             NetBSD. This being said, patches are most welcome. :-)
251              
252             =head1 SEE ALSO
253              
254             L<Memory::Usage>
255              
256             =head1 AUTHOR
257              
258             Yanick Champoux <yanick@babyl.dyndns.org>
259              
260             =head1 COPYRIGHT AND LICENSE
261              
262             This software is copyright (c) 2010 by Yanick Champoux.
263              
264             This is free software; you can redistribute it and/or modify it under
265             the same terms as the Perl 5 programming language system itself.
266              
267             =cut