home *** CD-ROM | disk | FTP | other *** search
/ PC Professionell 2004 December / PCpro_2004_12.ISO / files / webserver / tsw / TSW_3.4.0.exe / Apache2 / perl / ProfileDumper.pm < prev    next >
Encoding:
Perl POD Document  |  2002-12-01  |  7.9 KB  |  272 lines

  1. package DBI::ProfileDumper;
  2. use strict;
  3.  
  4. =head1 NAME
  5.  
  6. DBI::ProfileDumper - profile DBI usage and output data to a file
  7.  
  8. =head1 SYNOPSIS
  9.  
  10. To profile an existing program using DBI::ProfileDumper, set the
  11. DBI_PROFILE environment variable and run your program as usual.  For
  12. example, using bash:
  13.  
  14.   DBI_PROFILE=DBI::ProfileDumper program.pl
  15.  
  16. Then analyze the generated file (F<dbi.prof>) with L<dbiprof|dbiprof>:
  17.  
  18.   dbiprof
  19.  
  20. You can also activate DBI::ProfileDumper from within your code:
  21.  
  22.   use DBI;
  23.  
  24.   # profile with default path (2) and output file (dbi.prof)
  25.   $dbh->{Profile} = "DBI::ProfileDumper";
  26.  
  27.   # same thing, spelled out
  28.   $dbh->{Profile} = "2/DBI::ProfileDumper/File/dbi.prof";
  29.  
  30.   # another way to say it
  31.   use DBI::Profile qw(DBIprofile_Statement);
  32.   $dbh->{Profile} = DBI::ProfileDumper->new(
  33.                       { Path => [ DBIprofile_Statement ]
  34.                         File => 'dbi.prof' });
  35.  
  36.   # using a custom path
  37.   $dbh->{Profile} = DBI::ProfileDumper->new({ Path => [ "foo", "bar" ],
  38.                                               File => 'dbi.prof' });
  39.  
  40.  
  41. =head1 DESCRIPTION
  42.  
  43. DBI::ProfileDumper is a subclass of L<DBI::Profile|DBI::Profile> which
  44. dumps profile data to disk instead of printing a summary to your
  45. screen.  You can then use L<dbiprof|dbiprof> to analyze the data in
  46. a number of interesting ways, or you can roll your own analysis using
  47. L<DBI::ProfileData|DBI::ProfileData>.
  48.  
  49. B<NOTE:> For Apache/mod_perl applications, use
  50. L<DBI::ProfileDumper::Apache|DBI::ProfileDumper::Apache>.
  51.  
  52. =head1 USAGE
  53.  
  54. One way to use this module is just to enable it in your C<$dbh>:
  55.  
  56.   $dbh->{Profile} = "DBI::ProfileDumper";
  57.  
  58. This will write out profile data by statement into a file called
  59. F<dbi.prof>.  If you want to modify either of these properties, you
  60. can construct the DBI::ProfileDumper object yourself:
  61.  
  62.   use DBI::Profile qw(DBIprofile_Statement);
  63.   $dbh->{Profile} = DBI::ProfileDumper->new(
  64.                       { Path => [ DBIprofile_Statement ]
  65.                         File => 'dbi.prof' });
  66.  
  67. The C<Path> option takes the same values as in
  68. L<DBI::Profile|DBI:Profile>.  The C<File> option gives the name of the
  69. file where results will be collected.  If it already exists it will be
  70. overwritten.
  71.  
  72. You can also activate this module by setting the DBI_PROFILE
  73. environment variable:
  74.  
  75.   $ENV{DBI_PROFILE} = "DBI::ProfileDumper";
  76.  
  77. This will cause all DBI handles to share the same profiling object.
  78.  
  79. =head1 METHODS
  80.  
  81. The following methods are available to be called using the profile
  82. object.  You can get access to the profile object from the Profile key
  83. in any DBI handle:
  84.  
  85.   my $profile = $dbh->{Profile};
  86.  
  87. =over 4
  88.  
  89. =item $profile->flush_to_disk()
  90.  
  91. Flushes all collected profile data to disk and empties the Data hash.
  92. This method may be called multiple times during a program run.
  93.  
  94. =item $profile->empty()
  95.  
  96. Clears the Data hash without writing to disk.
  97.  
  98. =back
  99.  
  100. =head1 DATA FORMAT
  101.  
  102. The data format written by DBI::ProfileDumper starts with a header
  103. containing the version number of the module used to generate it.  Then
  104. a block of variable declarations describes the profile.  After two
  105. newlines, the profile data forms the body of the file.  For example:
  106.  
  107.   DBI::ProfileDumper 1.0
  108.   Path = [ DBIprofile_Statement, DBIprofile_MethodName ]
  109.   Program = t/42profile_data.t
  110.   
  111.   + 1 SELECT name FROM users WHERE id = ?
  112.   + 2 prepare
  113.   = 1 0.0312958955764771 0.000490069389343262 0.000176072120666504 0.00140702724456787 1023115819.83019 1023115819.86576
  114.   + 2 execute
  115.   1 0.0312958955764771 0.000490069389343262 0.000176072120666504 0.00140702724456787 1023115819.83019 1023115819.86576
  116.   + 2 fetchrow_hashref
  117.   = 1 0.0312958955764771 0.000490069389343262 0.000176072120666504 0.00140702724456787 1023115819.83019 1023115819.86576
  118.   + 1 UPDATE users SET name = ? WHERE id = ?
  119.   + 2 prepare
  120.   = 1 0.0312958955764771 0.000490069389343262 0.000176072120666504 0.00140702724456787 1023115819.83019 1023115819.86576
  121.   + 2 execute
  122.   = 1 0.0312958955764771 0.000490069389343262 0.000176072120666504 0.00140702724456787 1023115819.83019 1023115819.86576
  123.  
  124. The lines beginning with C<+> signs signify keys.  The number after
  125. the C<+> sign shows the nesting level of the key.  Lines beginning
  126. with C<=> are the actual profile data, in the same order as
  127. in DBI::Profile.
  128.  
  129. Note that the same path may be present multiple times in the data file
  130. since C<format()> may be called more than once.  When read by
  131. DBI::ProfileData the data points will be merged to produce a single
  132. data set for each distinct path.
  133.  
  134. The key strings are transformed in three ways.  First, all backslashes
  135. are doubled.  Then all newlines and carriage-returns are transformed
  136. into C<\n> and C<\r> respectively.  Finally, any NULL bytes (C<\0>)
  137. are entirely removed.  When DBI::ProfileData reads the file the first
  138. two transformations will be reversed, but NULL bytes will not be
  139. restored.
  140.  
  141. =head1 AUTHOR
  142.  
  143. Sam Tregar <sam@tregar.com>
  144.  
  145. =head1 COPYRIGHT AND LICENSE
  146.  
  147. Copyright (C) 2002 Sam Tregar
  148.  
  149. This program is free software; you can redistribute it and/or modify
  150. it under the same terms as Perl 5 itself.
  151.  
  152. =cut
  153.  
  154. # inherit from DBI::Profile
  155. use DBI::Profile;
  156. use vars qw(@ISA $VERSION);
  157. @ISA = ("DBI::Profile");
  158. $VERSION = "1.0";
  159.  
  160. use Carp qw(croak);
  161. use Symbol;
  162.  
  163. # validate params and setup default
  164. sub new {
  165.     my $pkg = shift;
  166.     my $self = $pkg->SUPER::new(@_);
  167.  
  168.     # File defaults to dbi.prof
  169.     $self->{File} = "dbi.prof" unless exists $self->{File};
  170.  
  171.     return $self;
  172. }
  173.  
  174. # flush available data to disk
  175. sub flush_to_disk {
  176.     my $self = shift;
  177.     my $data = $self->{Data};
  178.  
  179.     my $fh = gensym;
  180.     if ($self->{_wrote_header}) {
  181.         # append more data to the file
  182.         open($fh, ">>$self->{File}") 
  183.           or croak("Unable to open '$self->{File}' for profile output: $!");
  184.     } else {
  185.         # create new file and write the header
  186.         open($fh, ">$self->{File}") 
  187.           or croak("Unable to open '$self->{File}' for profile output: $!");
  188.         $self->write_header($fh);
  189.         $self->{_wrote_header} = 1;
  190.     }
  191.  
  192.     $self->write_data($fh, $self->{Data}, 1);
  193.  
  194.     close($fh) or croak("Unable to close '$self->{File}': $!");
  195.  
  196.     $self->empty();
  197. }
  198.  
  199. # empty out profile data
  200. sub empty {
  201.     shift->{Data} = {};
  202. }
  203.  
  204. # write header to a filehandle
  205. sub write_header {
  206.     my ($self, $fh) = @_;
  207.  
  208.     # module name and version number
  209.     print $fh ref($self), " ", $self->VERSION, "\n";
  210.  
  211.     # print out Path
  212.     my @path_words;
  213.     foreach (@{$self->{Path}}) {
  214.         if ($_ eq DBI::Profile::DBIprofile_Statement) {
  215.             push @path_words, "DBIprofile_Statement";
  216.         } elsif ($_ eq DBI::Profile::DBIprofile_MethodName) {
  217.             push @path_words, "DBIprofile_MethodName";
  218.         } elsif ($_ eq DBI::Profile::DBIprofile_MethodClass) {
  219.             push @path_words, "DBIprofile_MethodClass";
  220.         } else {
  221.             push @path_words, $_;
  222.         }
  223.     }
  224.     print $fh "Path = [ ", join(', ', @path_words), " ]\n";
  225.  
  226.     # print out $0 and @ARGV
  227.     print $fh "Program = $0";
  228.     print $fh " ", join(", ", @ARGV) if @ARGV;
  229.     print $fh "\n";
  230.  
  231.     # all done
  232.     print $fh "\n";
  233. }
  234.  
  235. # write data in the proscribed format
  236. sub write_data {
  237.     my ($self, $fh, $data, $level) = @_;
  238.  
  239.     # produce an empty profile for invalid $data
  240.     return unless $data and UNIVERSAL::isa($data,'HASH');
  241.     
  242.     while (my ($key, $value) = each(%$data)) {
  243.         # output a key
  244.         print $fh "+ ", $level, " ", quote_key($key), "\n";
  245.         if (UNIVERSAL::isa($value,'ARRAY')) {
  246.             # output a data set for a leaf node
  247.             printf $fh "= %4d %.6f %.6f %.6f %.6f %.6f %.6f\n", @$value;
  248.         } else {
  249.             # recurse through keys - this could be rewritten to use a
  250.             # stack for some small performance gain
  251.             $self->write_data($fh, $value, $level + 1);
  252.         }
  253.     }
  254. }
  255.  
  256. # quote a key for output
  257. sub quote_key {
  258.     my $key = shift;
  259.     $key =~ s!\\!\\\\!g;
  260.     $key =~ s!\n!\\n!g;
  261.     $key =~ s!\r!\\r!g;
  262.     $key =~ s!\0!!g;
  263.     return $key;
  264. }
  265.  
  266. # flush data to disk when profile object goes out of scope
  267. sub on_destroy {
  268.     shift->flush_to_disk();
  269. }
  270.  
  271. 1;
  272.