File Coverage

blib/lib/DBI/Profile.pm
Criterion Covered Total %
statement 144 159 90.5
branch 54 86 62.7
condition 19 31 61.2
subroutine 21 23 91.3
pod 3 11 27.2
total 241 310 77.7


line stmt bran cond sub pod time code
1             package DBI::Profile;
2              
3             =head1 NAME
4              
5             DBI::Profile - Performance profiling and benchmarking for the DBI
6              
7             =head1 SYNOPSIS
8              
9             The easiest way to enable DBI profiling is to set the DBI_PROFILE
10             environment variable to 2 and then run your code as usual:
11              
12             DBI_PROFILE=2 prog.pl
13              
14             This will profile your program and then output a textual summary
15             grouped by query when the program exits. You can also enable profiling by
16             setting the Profile attribute of any DBI handle:
17              
18             $dbh->{Profile} = 2;
19              
20             Then the summary will be printed when the handle is destroyed.
21              
22             Many other values apart from are possible - see L<"ENABLING A PROFILE"> below.
23              
24             =head1 DESCRIPTION
25              
26             The DBI::Profile module provides a simple interface to collect and
27             report performance and benchmarking data from the DBI.
28              
29             For a more elaborate interface, suitable for larger programs, see
30             L and L.
31             For Apache/mod_perl applications see
32             L.
33              
34             =head1 OVERVIEW
35              
36             Performance data collection for the DBI is built around several
37             concepts which are important to understand clearly.
38              
39             =over 4
40              
41             =item Method Dispatch
42              
43             Every method call on a DBI handle passes through a single 'dispatch'
44             function which manages all the common aspects of DBI method calls,
45             such as handling the RaiseError attribute.
46              
47             =item Data Collection
48              
49             If profiling is enabled for a handle then the dispatch code takes
50             a high-resolution timestamp soon after it is entered. Then, after
51             calling the appropriate method and just before returning, it takes
52             another high-resolution timestamp and calls a function to record
53             the information. That function is passed the two timestamps
54             plus the DBI handle and the name of the method that was called.
55             That data about a single DBI method call is called a I.
56              
57             =item Data Filtering
58              
59             If the method call was invoked by the DBI or by a driver then the call is
60             ignored for profiling because the time spent will be accounted for by the
61             original 'outermost' call for your code.
62              
63             For example, the calls that the selectrow_arrayref() method makes
64             to prepare() and execute() etc. are not counted individually
65             because the time spent in those methods is going to be allocated
66             to the selectrow_arrayref() method when it returns. If this was not
67             done then it would be very easy to double count time spent inside
68             the DBI.
69              
70             =item Data Storage Tree
71              
72             The profile data is accumulated as 'leaves on a tree'. The 'path' through the
73             branches of the tree to a particular leaf is determined dynamically for each sample.
74             This is a key feature of DBI profiling.
75              
76             For each profiled method call the DBI walks along the Path and uses each value
77             in the Path to step into and grow the Data tree.
78              
79             For example, if the Path is
80              
81             [ 'foo', 'bar', 'baz' ]
82              
83             then the new profile sample data will be I into the tree at
84              
85             $h->{Profile}->{Data}->{foo}->{bar}->{baz}
86              
87             But it's not very useful to merge all the call data into one leaf node (except
88             to get an overall 'time spent inside the DBI' total). It's more common to want
89             the Path to include dynamic values such as the current statement text and/or
90             the name of the method called to show what the time spent inside the DBI was for.
91              
92             The Path can contain some 'magic cookie' values that are automatically replaced
93             by corresponding dynamic values when they're used. These magic cookies always
94             start with a punctuation character.
95              
96             For example a value of 'C' in the Path causes the corresponding
97             entry in the Data to be the name of the method that was called.
98             For example, if the Path was:
99              
100             [ 'foo', '!MethodName', 'bar' ]
101              
102             and the selectall_arrayref() method was called, then the profile sample data
103             for that call will be merged into the tree at:
104              
105             $h->{Profile}->{Data}->{foo}->{selectall_arrayref}->{bar}
106              
107             =item Profile Data
108              
109             Profile data is stored at the 'leaves' of the tree as references
110             to an array of numeric values. For example:
111              
112             [
113             106, # 0: count of samples at this node
114             0.0312958955764771, # 1: total duration
115             0.000490069389343262, # 2: first duration
116             0.000176072120666504, # 3: shortest duration
117             0.00140702724456787, # 4: longest duration
118             1023115819.83019, # 5: time of first sample
119             1023115819.86576, # 6: time of last sample
120             ]
121              
122             After the first sample, later samples always update elements 0, 1, and 6, and
123             may update 3 or 4 depending on the duration of the sampled call.
124              
125             =back
126              
127             =head1 ENABLING A PROFILE
128              
129             Profiling is enabled for a handle by assigning to the Profile
130             attribute. For example:
131              
132             $h->{Profile} = DBI::Profile->new();
133              
134             The Profile attribute holds a blessed reference to a hash object
135             that contains the profile data and attributes relating to it.
136              
137             The class the Profile object is blessed into is expected to
138             provide at least a DESTROY method which will dump the profile data
139             to the DBI trace file handle (STDERR by default).
140              
141             All these examples have the same effect as each other:
142              
143             $h->{Profile} = 0;
144             $h->{Profile} = "/DBI::Profile";
145             $h->{Profile} = DBI::Profile->new();
146             $h->{Profile} = {};
147             $h->{Profile} = { Path => [] };
148              
149             Similarly, these examples have the same effect as each other:
150              
151             $h->{Profile} = 6;
152             $h->{Profile} = "6/DBI::Profile";
153             $h->{Profile} = "!Statement:!MethodName/DBI::Profile";
154             $h->{Profile} = { Path => [ '!Statement', '!MethodName' ] };
155              
156             If a non-blessed hash reference is given then the DBI::Profile
157             module is automatically C'd and the reference is blessed
158             into that class.
159              
160             If a string is given then it is processed like this:
161              
162             ($path, $module, $args) = split /\//, $string, 3
163              
164             @path = split /:/, $path
165             @args = split /:/, $args
166              
167             eval "require $module" if $module
168             $module ||= "DBI::Profile"
169              
170             $module->new( Path => \@Path, @args )
171              
172             So the first value is used to select the Path to be used (see below).
173             The second value, if present, is used as the name of a module which
174             will be loaded and it's C method called. If not present it
175             defaults to DBI::Profile. Any other values are passed as arguments
176             to the C method. For example: "C<2/DBIx::OtherProfile/Foo:42>".
177              
178             Numbers can be used as a shorthand way to enable common Path values.
179             The simplest way to explain how the values are interpreted is to show the code:
180              
181             push @Path, "DBI" if $path_elem & 0x01;
182             push @Path, "!Statement" if $path_elem & 0x02;
183             push @Path, "!MethodName" if $path_elem & 0x04;
184             push @Path, "!MethodClass" if $path_elem & 0x08;
185             push @Path, "!Caller2" if $path_elem & 0x10;
186              
187             So "2" is the same as "!Statement" and "6" (2+4) is the same as
188             "!Statement:!Method". Those are the two most commonly used values. Using a
189             negative number will reverse the path. Thus "-6" will group by method name then
190             statement.
191              
192             The splitting and parsing of string values assigned to the Profile
193             attribute may seem a little odd, but there's a good reason for it.
194             Remember that attributes can be embedded in the Data Source Name
195             string which can be passed in to a script as a parameter. For
196             example:
197              
198             dbi:DriverName(Profile=>2):dbname
199             dbi:DriverName(Profile=>{Username}:!Statement/MyProfiler/Foo:42):dbname
200              
201             And also, if the C environment variable is set then
202             The DBI arranges for every driver handle to share the same profile
203             object. When perl exits a single profile summary will be generated
204             that reflects (as nearly as practical) the total use of the DBI by
205             the application.
206              
207              
208             =head1 THE PROFILE OBJECT
209              
210             The DBI core expects the Profile attribute value to be a hash
211             reference and if the following values don't exist it will create
212             them as needed:
213              
214             =head2 Data
215              
216             A reference to a hash containing the collected profile data.
217              
218             =head2 Path
219              
220             The Path value is a reference to an array. Each element controls the
221             value to use at the corresponding level of the profile Data tree.
222              
223             If the value of Path is anything other than an array reference,
224             it is treated as if it was:
225              
226             [ '!Statement' ]
227              
228             The elements of Path array can be one of the following types:
229              
230             =head3 Special Constant
231              
232             B
233              
234             Use the current Statement text. Typically that's the value of the Statement
235             attribute for the handle the method was called with. Some methods, like
236             commit() and rollback(), are unrelated to a particular statement. For those
237             methods !Statement records an empty string.
238              
239             For statement handles this is always simply the string that was
240             given to prepare() when the handle was created. For database handles
241             this is the statement that was last prepared or executed on that
242             database handle. That can lead to a little 'fuzzyness' because, for
243             example, calls to the quote() method to build a new statement will
244             typically be associated with the previous statement. In practice
245             this isn't a significant issue and the dynamic Path mechanism can
246             be used to setup your own rules.
247              
248             B
249              
250             Use the name of the DBI method that the profile sample relates to.
251              
252             B
253              
254             Use the fully qualified name of the DBI method, including
255             the package, that the profile sample relates to. This shows you
256             where the method was implemented. For example:
257              
258             'DBD::_::db::selectrow_arrayref' =>
259             0.022902s
260             'DBD::mysql::db::selectrow_arrayref' =>
261             2.244521s / 99 = 0.022445s avg (first 0.022813s, min 0.022051s, max 0.028932s)
262              
263             The "DBD::_::db::selectrow_arrayref" shows that the driver has
264             inherited the selectrow_arrayref method provided by the DBI.
265              
266             But you'll note that there is only one call to
267             DBD::_::db::selectrow_arrayref but another 99 to
268             DBD::mysql::db::selectrow_arrayref. Currently the first
269             call doesn't record the true location. That may change.
270              
271             B
272              
273             Use a string showing the filename and line number of the code calling the method.
274              
275             B
276              
277             Use a string showing the filename and line number of the code calling the
278             method, as for !Caller, but also include filename and line number of the code
279             that called that. Calls from DBI:: and DBD:: packages are skipped.
280              
281             B
282              
283             Same as !Caller above except that only the filename is included, not the line number.
284              
285             B
286              
287             Same as !Caller2 above except that only the filenames are included, not the line number.
288              
289             B
290              
291             Use the current value of time(). Rarely used. See the more useful C below.
292              
293             B
294              
295             Where C is an integer. Use the current value of time() but with reduced precision.
296             The value used is determined in this way:
297              
298             int( time() / N ) * N
299              
300             This is a useful way to segregate a profile into time slots. For example:
301              
302             [ '!Time~60', '!Statement' ]
303              
304             =head3 Code Reference
305              
306             The subroutine is passed the handle it was called on and the DBI method name.
307             The current Statement is in $_. The statement string should not be modified,
308             so most subs start with C.
309              
310             The list of values it returns is used at that point in the Profile Path.
311              
312             The sub can 'veto' (reject) a profile sample by including a reference to undef
313             in the returned list. That can be useful when you want to only profile
314             statements that match a certain pattern, or only profile certain methods.
315              
316             =head3 Subroutine Specifier
317              
318             A Path element that begins with 'C<&>' is treated as the name of a subroutine
319             in the DBI::ProfileSubs namespace and replaced with the corresponding code reference.
320              
321             Currently this only works when the Path is specified by the C
322             environment variable.
323              
324             Also, currently, the only subroutine in the DBI::ProfileSubs namespace is
325             C<'&norm_std_n3'>. That's a very handy subroutine when profiling code that
326             doesn't use placeholders. See L for more information.
327              
328             =head3 Attribute Specifier
329              
330             A string enclosed in braces, such as 'C<{Username}>', specifies that the current
331             value of the corresponding database handle attribute should be used at that
332             point in the Path.
333              
334             =head3 Reference to a Scalar
335              
336             Specifies that the current value of the referenced scalar be used at that point
337             in the Path. This provides an efficient way to get 'contextual' values into
338             your profile.
339              
340             =head3 Other Values
341              
342             Any other values are stringified and used literally.
343              
344             (References, and values that begin with punctuation characters are reserved.)
345              
346              
347             =head1 REPORTING
348              
349             =head2 Report Format
350              
351             The current accumulated profile data can be formatted and output using
352              
353             print $h->{Profile}->format;
354              
355             To discard the profile data and start collecting fresh data
356             you can do:
357              
358             $h->{Profile}->{Data} = undef;
359              
360              
361             The default results format looks like this:
362              
363             DBI::Profile: 0.001015s 42.7% (5 calls) programname @ YYYY-MM-DD HH:MM:SS
364             '' =>
365             0.000024s / 2 = 0.000012s avg (first 0.000015s, min 0.000009s, max 0.000015s)
366             'SELECT mode,size,name FROM table' =>
367             0.000991s / 3 = 0.000330s avg (first 0.000678s, min 0.000009s, max 0.000678s)
368              
369             Which shows the total time spent inside the DBI, with a count of
370             the total number of method calls and the name of the script being
371             run, then a formatted version of the profile data tree.
372              
373             If the results are being formatted when the perl process is exiting
374             (which is usually the case when the DBI_PROFILE environment variable
375             is used) then the percentage of time the process spent inside the
376             DBI is also shown. If the process is not exiting then the percentage is
377             calculated using the time between the first and last call to the DBI.
378              
379             In the example above the paths in the tree are only one level deep and
380             use the Statement text as the value (that's the default behaviour).
381              
382             The merged profile data at the 'leaves' of the tree are presented
383             as total time spent, count, average time spent (which is simply total
384             time divided by the count), then the time spent on the first call,
385             the time spent on the fastest call, and finally the time spent on
386             the slowest call.
387              
388             The 'avg', 'first', 'min' and 'max' times are not particularly
389             useful when the profile data path only contains the statement text.
390             Here's an extract of a more detailed example using both statement
391             text and method name in the path:
392              
393             'SELECT mode,size,name FROM table' =>
394             'FETCH' =>
395             0.000076s
396             'fetchrow_hashref' =>
397             0.036203s / 108 = 0.000335s avg (first 0.000490s, min 0.000152s, max 0.002786s)
398              
399             Here you can see the 'avg', 'first', 'min' and 'max' for the
400             108 calls to fetchrow_hashref() become rather more interesting.
401             Also the data for FETCH just shows a time value because it was only
402             called once.
403              
404             Currently the profile data is output sorted by branch names. That
405             may change in a later version so the leaf nodes are sorted by total
406             time per leaf node.
407              
408              
409             =head2 Report Destination
410              
411             The default method of reporting is for the DESTROY method of the
412             Profile object to format the results and write them using:
413              
414             DBI->trace_msg($results, 0); # see $ON_DESTROY_DUMP below
415              
416             to write them to the DBI trace() filehandle (which defaults to
417             STDERR). To direct the DBI trace filehandle to write to a file
418             without enabling tracing the trace() method can be called with a
419             trace level of 0. For example:
420              
421             DBI->trace(0, $filename);
422              
423             The same effect can be achieved without changing the code by
424             setting the C environment variable to C<0=filename>.
425              
426             The $DBI::Profile::ON_DESTROY_DUMP variable holds a code ref
427             that's called to perform the output of the formatted results.
428             The default value is:
429              
430             $ON_DESTROY_DUMP = sub { DBI->trace_msg($results, 0) };
431              
432             Apart from making it easy to send the dump elsewhere, it can also
433             be useful as a simple way to disable dumping results.
434              
435             =head1 CHILD HANDLES
436              
437             Child handles inherit a reference to the Profile attribute value
438             of their parent. So if profiling is enabled for a database handle
439             then by default the statement handles created from it all contribute
440             to the same merged profile data tree.
441              
442              
443             =head1 PROFILE OBJECT METHODS
444              
445             =head2 format
446              
447             See L.
448              
449             =head2 as_node_path_list
450              
451             @ary = $dbh->{Profile}->as_node_path_list();
452             @ary = $dbh->{Profile}->as_node_path_list($node, $path);
453              
454             Returns the collected data ($dbh->{Profile}{Data}) restructured into a list of
455             array refs, one for each leaf node in the Data tree. This 'flat' structure is
456             often much simpler for applications to work with.
457              
458             The first element of each array ref is a reference to the leaf node.
459             The remaining elements are the 'path' through the data tree to that node.
460              
461             For example, given a data tree like this:
462              
463             {key1a}{key2a}[node1]
464             {key1a}{key2b}[node2]
465             {key1b}{key2a}{key3a}[node3]
466              
467             The as_node_path_list() method will return this list:
468              
469             [ [node1], 'key1a', 'key2a' ]
470             [ [node2], 'key1a', 'key2b' ]
471             [ [node3], 'key1b', 'key2a', 'key3a' ]
472              
473             The nodes are ordered by key, depth-first.
474              
475             The $node argument can be used to focus on a sub-tree.
476             If not specified it defaults to $dbh->{Profile}{Data}.
477              
478             The $path argument can be used to specify a list of path elements that will be
479             added to each element of the returned list. If not specified it defaults to a
480             ref to an empty array.
481              
482             =head2 as_text
483              
484             @txt = $dbh->{Profile}->as_text();
485             $txt = $dbh->{Profile}->as_text({
486             node => undef,
487             path => [],
488             separator => " > ",
489             format => '%1$s: %11$fs / %10$d = %2$fs avg (first %12$fs, min %13$fs, max %14$fs)'."\n";
490             sortsub => sub { ... },
491             );
492              
493             Returns the collected data ($dbh->{Profile}{Data}) reformatted into a list of formatted strings.
494             In scalar context the list is returned as a single concatenated string.
495              
496             A hashref can be used to pass in arguments, the default values are shown in the example above.
497              
498             The C and arguments are passed to as_node_path_list().
499              
500             The C argument is used to join the elements of the path for each leaf node.
501              
502             The C argument is used to pass in a ref to a sub that will order the list.
503             The subroutine will be passed a reference to the array returned by
504             as_node_path_list() and should sort the contents of the array in place.
505             The return value from the sub is ignored. For example, to sort the nodes by the
506             second level key you could use:
507              
508             sortsub => sub { my $ary=shift; @$ary = sort { $a->[2] cmp $b->[2] } @$ary }
509              
510             The C argument is a C format string that specifies the format
511             to use for each leaf node. It uses the explicit format parameter index
512             mechanism to specify which of the arguments should appear where in the string.
513             The arguments to sprintf are:
514              
515             1: path to node, joined with the separator
516             2: average duration (total duration/count)
517             (3 thru 9 are currently unused)
518             10: count
519             11: total duration
520             12: first duration
521             13: smallest duration
522             14: largest duration
523             15: time of first call
524             16: time of first call
525              
526             =head1 CUSTOM DATA MANIPULATION
527              
528             Recall that C<< $h->{Profile}->{Data} >> is a reference to the collected data.
529             Either to a 'leaf' array (when the Path is empty, i.e., DBI_PROFILE env var is 1),
530             or a reference to hash containing values that are either further hash
531             references or leaf array references.
532              
533             Sometimes it's useful to be able to summarise some or all of the collected data.
534             The dbi_profile_merge_nodes() function can be used to merge leaf node values.
535              
536             =head2 dbi_profile_merge_nodes
537              
538             use DBI qw(dbi_profile_merge_nodes);
539              
540             $time_in_dbi = dbi_profile_merge_nodes(my $totals=[], @$leaves);
541              
542             Merges profile data node. Given a reference to a destination array, and zero or
543             more references to profile data, merges the profile data into the destination array.
544             For example:
545              
546             $time_in_dbi = dbi_profile_merge_nodes(
547             my $totals=[],
548             [ 10, 0.51, 0.11, 0.01, 0.22, 1023110000, 1023110010 ],
549             [ 15, 0.42, 0.12, 0.02, 0.23, 1023110005, 1023110009 ],
550             );
551              
552             $totals will then contain
553              
554             [ 25, 0.93, 0.11, 0.01, 0.23, 1023110000, 1023110010 ]
555              
556             and $time_in_dbi will be 0.93;
557              
558             The second argument need not be just leaf nodes. If given a reference to a hash
559             then the hash is recursively searched for leaf nodes and all those found
560             are merged.
561              
562             For example, to get the time spent 'inside' the DBI during an http request,
563             your logging code run at the end of the request (i.e. mod_perl LogHandler)
564             could use:
565              
566             my $time_in_dbi = 0;
567             if (my $Profile = $dbh->{Profile}) { # if DBI profiling is enabled
568             $time_in_dbi = dbi_profile_merge_nodes(my $total=[], $Profile->{Data});
569             $Profile->{Data} = {}; # reset the profile data
570             }
571              
572             If profiling has been enabled then $time_in_dbi will hold the time spent inside
573             the DBI for that handle (and any other handles that share the same profile data)
574             since the last request.
575              
576             Prior to DBI 1.56 the dbi_profile_merge_nodes() function was called dbi_profile_merge().
577             That name still exists as an alias.
578              
579             =head1 CUSTOM DATA COLLECTION
580              
581             =head2 Using The Path Attribute
582              
583             XXX example to be added later using a selectall_arrayref call
584             XXX nested inside a fetch loop where the first column of the
585             XXX outer loop is bound to the profile Path using
586             XXX bind_column(1, \${ $dbh->{Profile}->{Path}->[0] })
587             XXX so you end up with separate profiles for each loop
588             XXX (patches welcome to add this to the docs :)
589              
590             =head2 Adding Your Own Samples
591              
592             The dbi_profile() function can be used to add extra sample data
593             into the profile data tree. For example:
594              
595             use DBI;
596             use DBI::Profile (dbi_profile dbi_time);
597              
598             my $t1 = dbi_time(); # floating point high-resolution time
599              
600             ... execute code you want to profile here ...
601              
602             my $t2 = dbi_time();
603             dbi_profile($h, $statement, $method, $t1, $t2);
604              
605             The $h parameter is the handle the extra profile sample should be
606             associated with. The $statement parameter is the string to use where
607             the Path specifies !Statement. If $statement is undef
608             then $h->{Statement} will be used. Similarly $method is the string
609             to use if the Path specifies !MethodName. There is no
610             default value for $method.
611              
612             The $h->{Profile}{Path} attribute is processed by dbi_profile() in
613             the usual way.
614              
615             The $h parameter is usually a DBI handle but it can also be a reference to a
616             hash, in which case the dbi_profile() acts on each defined value in the hash.
617             This is an efficient way to update multiple profiles with a single sample,
618             and is used by the L module.
619              
620             =head1 SUBCLASSING
621              
622             Alternate profile modules must subclass DBI::Profile to help ensure
623             they work with future versions of the DBI.
624              
625              
626             =head1 CAVEATS
627              
628             Applications which generate many different statement strings
629             (typically because they don't use placeholders) and profile with
630             !Statement in the Path (the default) will consume memory
631             in the Profile Data structure for each statement. Use a code ref
632             in the Path to return an edited (simplified) form of the statement.
633              
634             If a method throws an exception itself (not via RaiseError) then
635             it won't be counted in the profile.
636              
637             If a HandleError subroutine throws an exception (rather than returning
638             0 and letting RaiseError do it) then the method call won't be counted
639             in the profile.
640              
641             Time spent in DESTROY is added to the profile of the parent handle.
642              
643             Time spent in DBI->*() methods is not counted. The time spent in
644             the driver connect method, $drh->connect(), when it's called by
645             DBI->connect is counted if the DBI_PROFILE environment variable is set.
646              
647             Time spent fetching tied variables, $DBI::errstr, is counted.
648              
649             Time spent in FETCH for $h->{Profile} is not counted, so getting the profile
650             data doesn't alter it.
651              
652             DBI::PurePerl does not support profiling (though it could in theory).
653              
654             For asynchronous queries, time spent while the query is running on the
655             backend is not counted.
656              
657             A few platforms don't support the gettimeofday() high resolution
658             time function used by the DBI (and available via the dbi_time() function).
659             In which case you'll get integer resolution time which is mostly useless.
660              
661             On Windows platforms the dbi_time() function is limited to millisecond
662             resolution. Which isn't sufficiently fine for our needs, but still
663             much better than integer resolution. This limited resolution means
664             that fast method calls will often register as taking 0 time. And
665             timings in general will have much more 'jitter' depending on where
666             within the 'current millisecond' the start and end timing was taken.
667              
668             This documentation could be more clear. Probably needs to be reordered
669             to start with several examples and build from there. Trying to
670             explain the concepts first seems painful and to lead to just as
671             many forward references. (Patches welcome!)
672              
673             =cut
674              
675              
676 12     12   6578 use strict;
  12         18  
  12         520  
677 12     12   64 use vars qw(@ISA @EXPORT @EXPORT_OK $VERSION);
  12         17  
  12         793  
678 12     12   54 use Exporter ();
  12         13  
  12         136  
679 12     12   7228 use UNIVERSAL ();
  12         144  
  12         276  
680 12     12   51 use Carp;
  12         19  
  12         973  
681              
682 12     12   6122 use DBI qw(dbi_time dbi_profile dbi_profile_merge_nodes dbi_profile_merge);
  12         20  
  12         2051  
683              
684             $VERSION = "2.015065";
685              
686             @ISA = qw(Exporter);
687             @EXPORT = qw(
688             DBIprofile_Statement
689             DBIprofile_MethodName
690             DBIprofile_MethodClass
691             dbi_profile
692             dbi_profile_merge_nodes
693             dbi_profile_merge
694             dbi_time
695             );
696             @EXPORT_OK = qw(
697             format_profile_thingy
698             );
699              
700 12     12   73 use constant DBIprofile_Statement => '!Statement';
  12         17  
  12         1622  
701 12     12   54 use constant DBIprofile_MethodName => '!MethodName';
  12         23  
  12         565  
702 12     12   55 use constant DBIprofile_MethodClass => '!MethodClass';
  12         17  
  12         4406  
703              
704             our $ON_DESTROY_DUMP = sub { DBI->trace_msg(shift, 0) };
705             our $ON_FLUSH_DUMP = sub { DBI->trace_msg(shift, 0) };
706              
707             sub new {
708 20     20 0 32 my $class = shift;
709 20         63 my $profile = { @_ };
710 20         184 return bless $profile => $class;
711             }
712              
713              
714             sub _auto_new {
715 20     20   45 my $class = shift;
716 20         35 my ($arg) = @_;
717              
718             # This sub is called by DBI internals when a non-hash-ref is
719             # assigned to the Profile attribute. For example
720             # dbi:mysql(RaiseError=>1,Profile=>!Statement:!MethodName/DBIx::MyProfile/arg1:arg2):dbname
721             # This sub works out what to do and returns a suitable hash ref.
722              
723 20 50       82 $arg =~ s/^DBI::/2\/DBI::/
724             and carp "Automatically changed old-style DBI::Profile specification to $arg";
725              
726             # it's a path/module/k1:v1:k2:v2:... list
727 20         93 my ($path, $package, $args) = split /\//, $arg, 3;
728 20 100       82 my @args = (defined $args) ? split(/:/, $args, -1) : ();
729 20         27 my @Path;
730              
731 20         62 for my $element (split /:/, $path) {
732 18 100       95 if (DBI::looks_like_number($element)) {
    50          
733 16 50       66 my $reverse = ($element < 0) ? ($element=-$element, 1) : 0;
734 16         18 my @p;
735             # a single "DBI" is special-cased in format()
736 16 50       45 push @p, "DBI" if $element & 0x01;
737 16 100       98 push @p, DBIprofile_Statement if $element & 0x02;
738 16 100       50 push @p, DBIprofile_MethodName if $element & 0x04;
739 16 50       69 push @p, DBIprofile_MethodClass if $element & 0x08;
740 16 100       43 push @p, '!Caller2' if $element & 0x10;
741 16 50       75 push @Path, ($reverse ? reverse @p : @p);
742             }
743             elsif ($element =~ m/^&(\w.*)/) {
744 2         7 my $name = "DBI::ProfileSubs::$1"; # capture $1 early
745 2         1088 require DBI::ProfileSubs;
746 12     12   63 my $code = do { no strict; *{$name}{CODE} };
  12         17  
  12         15673  
  2         4  
  2         2  
  2         9  
747 2 50       7 if (defined $code) {
748 2         9 push @Path, $code;
749             }
750             else {
751 0         0 warn "$name: subroutine not found\n";
752 0         0 push @Path, $element;
753             }
754             }
755             else {
756 0         0 push @Path, $element;
757             }
758             }
759              
760 20 100       542 eval "require $package" if $package; # silently ignores errors
761 20   66     110 $package ||= $class;
762              
763 20         131 return $package->new(Path => \@Path, @args);
764             }
765              
766              
767             sub empty { # empty out profile data
768 20     20 0 31 my $self = shift;
769 20 50       52 DBI->trace_msg("profile data discarded\n",0) if $self->{Trace};
770 20         54 $self->{Data} = undef;
771             }
772              
773             sub filename { # baseclass method, see DBI::ProfileDumper
774 0     0 0 0 return undef;
775             }
776              
777             sub flush_to_disk { # baseclass method, see DBI::ProfileDumper & DashProfiler::Core
778 0     0 0 0 my $self = shift;
779 0 0       0 return unless $ON_FLUSH_DUMP;
780 0 0       0 return unless $self->{Data};
781 0         0 my $detail = $self->format();
782 0 0       0 $ON_FLUSH_DUMP->($detail) if $detail;
783             }
784              
785              
786             sub as_node_path_list {
787 84     84 1 78 my ($self, $node, $path) = @_;
788             # convert the tree into an array of arrays
789             # from
790             # {key1a}{key2a}[node1]
791             # {key1a}{key2b}[node2]
792             # {key1b}{key2a}{key3a}[node3]
793             # to
794             # [ [node1], 'key1a', 'key2a' ]
795             # [ [node2], 'key1a', 'key2b' ]
796             # [ [node3], 'key1b', 'key2a', 'key3a' ]
797              
798 84 50 66     174 $node ||= $self->{Data} or return;
799 84   100     113 $path ||= [];
800 84 100       130 if (ref $node eq 'HASH') { # recurse
801 48         59 $path = [ @$path, undef ];
802 76         69 return map {
803 48         87 $path->[-1] = $_;
804 76 50       145 ($node->{$_}) ? $self->as_node_path_list($node->{$_}, $path) : ()
805             } sort keys %$node;
806             }
807 36         106 return [ $node, @$path ];
808             }
809              
810              
811             sub as_text {
812 6     6 1 922 my ($self, $args_ref) = @_;
813 6   100     27 my $separator = $args_ref->{separator} || " > ";
814 6   50     22 my $format_path_element = $args_ref->{format_path_element}
815             || "%s"; # or e.g., " key%2$d='%s'"
816 6   100     17 my $format = $args_ref->{format}
817             || '%1$s: %11$fs / %10$d = %2$fs avg (first %12$fs, min %13$fs, max %14$fs)'."\n";
818              
819 6         19 my @node_path_list = $self->as_node_path_list(undef, $args_ref->{path});
820              
821 6 100       21 $args_ref->{sortsub}->(\@node_path_list) if $args_ref->{sortsub};
822              
823 6         33 my $eval = "qr/".quotemeta($separator)."/";
824 6   33     397 my $separator_re = eval($eval) || quotemeta($separator);
825             #warn "[$eval] = [$separator_re]";
826 6         11 my @text;
827 6         17 my @spare_slots = (undef) x 7;
828 6         10 for my $node_path (@node_path_list) {
829 20         28 my ($node, @path) = @$node_path;
830 20         17 my $idx = 0;
831 20         23 for (@path) {
832 56         53 s/[\r\n]+/ /g;
833 56         85 s/$separator_re/ /g;
834 56         39 ++$idx;
835 56 50       62 if ($format_path_element eq "%s") {
836 56         82 $_ = sprintf $format_path_element, $_;
837             } else {
838 0         0 $_ = sprintf $format_path_element, $_, $idx;
839             }
840             }
841 20 50       144 push @text, sprintf $format,
842             join($separator, @path), # 1=path
843             ($node->[0] ? $node->[1]/$node->[0] : 0), # 2=avg
844             @spare_slots,
845             @$node; # 10=count, 11=dur, 12=first_dur, 13=min, 14=max, 15=first_called, 16=last_called
846             }
847 6 50       13 return @text if wantarray;
848 6         34 return join "", @text;
849             }
850              
851              
852             sub format {
853 40     40 1 62 my $self = shift;
854 40   33     105 my $class = ref($self) || $self;
855              
856 40         57 my $prologue = "$class: ";
857 40         132 my $detail = $self->format_profile_thingy(
858             $self->{Data}, 0, " ",
859             my $path = [],
860             my $leaves = [],
861             )."\n";
862              
863 40 100       93 if (@$leaves) {
864 38         237 dbi_profile_merge_nodes(my $totals=[], @$leaves);
865 38         72 my ($count, $time_in_dbi, undef, undef, undef, $t1, $t2) = @$totals;
866 38         260 (my $progname = $0) =~ s:.*/::;
867 38 50       85 if ($count) {
868 38         136 $prologue .= sprintf "%fs ", $time_in_dbi;
869 38 50       87 my $perl_time = ($DBI::PERL_ENDING) ? time() - $^T : $t2-$t1;
870 38 100       144 $prologue .= sprintf "%.2f%% ", $time_in_dbi/$perl_time*100 if $perl_time;
871 38         1134 my @lt = localtime(time);
872 38         194 my $ts = sprintf "%d-%02d-%02d %02d:%02d:%02d",
873             1900+$lt[5], $lt[4]+1, @lt[3,2,1,0];
874 38         140 $prologue .= sprintf "(%d calls) $progname \@ $ts\n", $count;
875             }
876 38 50 100     204 if (@$leaves == 1 && ref($self->{Data}) eq 'HASH' && $self->{Data}->{DBI}) {
      66        
877 0         0 $detail = ""; # hide the "DBI" from DBI_PROFILE=1
878             }
879             }
880 40 50       67 return ($prologue, $detail) if wantarray;
881 40         131 return $prologue.$detail;
882             }
883              
884              
885             sub format_profile_leaf {
886 106     106 0 95 my ($self, $thingy, $depth, $pad, $path, $leaves) = @_;
887 106 50       203 croak "format_profile_leaf called on non-leaf ($thingy)"
888             unless UNIVERSAL::isa($thingy,'ARRAY');
889              
890 106 50       194 push @$leaves, $thingy if $leaves;
891 106         141 my ($count, $total_time, $first_time, $min, $max, $first_called, $last_called) = @$thingy;
892 106 100       524 return sprintf "%s%fs\n", ($pad x $depth), $total_time
893             if $count <= 1;
894 36 50       491 return sprintf "%s%fs / %d = %fs avg (first %fs, min %fs, max %fs)\n",
895             ($pad x $depth), $total_time, $count, $count ? $total_time/$count : 0,
896             $first_time, $min, $max;
897             }
898              
899              
900             sub format_profile_branch {
901 108     108 0 118 my ($self, $thingy, $depth, $pad, $path, $leaves) = @_;
902 108 50       203 croak "format_profile_branch called on non-branch ($thingy)"
903             unless UNIVERSAL::isa($thingy,'HASH');
904 108         87 my @chunk;
905 108         268 my @keys = sort keys %$thingy;
906 108         178 while ( @keys ) {
907 176         185 my $k = shift @keys;
908 176         167 my $v = $thingy->{$k};
909 176         177 push @$path, $k;
910 176         337 push @chunk, sprintf "%s'%s' =>\n%s",
911             ($pad x $depth), $k,
912             $self->format_profile_thingy($v, $depth+1, $pad, $path, $leaves);
913 176         377 pop @$path;
914             }
915 108         327 return join "", @chunk;
916             }
917              
918              
919             sub format_profile_thingy {
920 216     216 0 237 my ($self, $thingy, $depth, $pad, $path, $leaves) = @_;
921 216 100       316 return "undef" if not defined $thingy;
922 214 100       540 return $self->format_profile_leaf( $thingy, $depth, $pad, $path, $leaves)
923             if UNIVERSAL::isa($thingy,'ARRAY');
924 108 50       324 return $self->format_profile_branch($thingy, $depth, $pad, $path, $leaves)
925             if UNIVERSAL::isa($thingy,'HASH');
926 0         0 return "$thingy\n";
927             }
928              
929              
930             sub on_destroy {
931 50     50 0 56 my $self = shift;
932 50 50       106 return unless $ON_DESTROY_DUMP;
933 50 100       146 return unless $self->{Data};
934 38         100 my $detail = $self->format();
935 38 50       127 $ON_DESTROY_DUMP->($detail) if $detail;
936 38         90 $self->{Data} = undef;
937             }
938              
939             sub DESTROY {
940 56     56   30782 my $self = shift;
941 56         80 local $@;
942 56 50 50     302 DBI->trace_msg("profile data DESTROY\n",0)
943             if (($self->{Trace}||0) >= 2);
944 56         76 eval { $self->on_destroy };
  56         131  
945 56 50       1069 if ($@) {
946 0           chomp $@;
947 0   0       my $class = ref($self) || $self;
948 0           DBI->trace_msg("$class on_destroy failed: $@", 0);
949             }
950             }
951              
952             1;
953