Author: timbo
Date: Tue Dec 13 08:05:21 2005
New Revision: 2308
Modified:
dbi/trunk/Changes
dbi/trunk/DBI.xs
dbi/trunk/lib/DBI/Profile.pm
dbi/trunk/lib/DBI/ProfileData.pm
dbi/trunk/t/40profile.t
Log:
Changed dbi_profile_merge() to be able to recurse and merge
sub-trees of profile data.
Added documentation for dbi_profile_merge(), including how to
measure the time spent inside the DBI for an http request.
Modified: dbi/trunk/Changes
==============================================================================
--- dbi/trunk/Changes (original)
+++ dbi/trunk/Changes Tue Dec 13 08:05:21 2005
@@ -9,6 +9,12 @@ DBI::Changes - List of significant chang
Fixed Makefile.PL options for gcc bug introduced in 1.49.
Fixed handle magic order to keep DBD::Oracle happy.
+ Changed dbi_profile_merge() to be able to recurse and merge
+ sub-trees of profile data.
+
+ Added documentation for dbi_profile_merge(), including how to
+ measure the time spent inside the DBI for an http request.
+
=head2 Changes in DBI 1.49 (svn rev 2287), 29th November 2005
Fixed assorted attribute handling bugs in DBD::Proxy.
Modified: dbi/trunk/DBI.xs
==============================================================================
--- dbi/trunk/DBI.xs (original)
+++ dbi/trunk/DBI.xs Tue Dec 13 08:05:21 2005
@@ -2315,11 +2315,10 @@ dbi_profile_merge(SV *dest, SV *incremen
AV *d_av, *i_av;
SV *tmp;
double i_nv;
- if (!SvROK(dest) || SvTYPE(SvRV(dest)) != SVt_PVAV
- || !SvROK(increment) || SvTYPE(SvRV(increment)) != SVt_PVAV)
- croak("dbi_profile_merge(%s, %s) requires array refs",
- neatsvpv(dest,0), neatsvpv(dest,0));
- i_av = (AV*)SvRV(increment);
+ int i_is_earlier;
+
+ if (!SvROK(dest) || SvTYPE(SvRV(dest)) != SVt_PVAV)
+ croak("dbi_profile_merge(%s, ...) requires array ref",
neatsvpv(dest,0));
d_av = (AV*)SvRV(dest);
if (av_len(d_av) < DBIprof_max_index) {
@@ -2327,11 +2326,29 @@ dbi_profile_merge(SV *dest, SV *incremen
av_extend(d_av, DBIprof_max_index);
for(idx=0; idx<=DBIprof_max_index; ++idx) {
tmp = *av_fetch(d_av, idx, 1);
- if (!SvOK(tmp))
- sv_setiv(tmp, 0);
+ if (!SvOK(tmp) && idx != DBIprof_MIN_TIME && idx !=
DBIprof_FIRST_CALLED)
+ sv_setnv(tmp, 0.0); /* leave 'min' values as undef */
}
}
+ if (!SvOK(increment))
+ return;
+
+ if (SvROK(increment) && SvTYPE(SvRV(increment)) == SVt_PVHV) {
+ HV *hv = (HV*)SvRV(increment);
+ char *key;
+ I32 keylen = 0;
+ hv_iterinit(hv);
+ while ( (tmp = hv_iternextsv(hv, &key, &keylen)) != NULL ) {
+ dbi_profile_merge(dest, tmp);
+ };
+ return;
+ }
+
+ if (!SvROK(increment) || SvTYPE(SvRV(increment)) != SVt_PVAV)
+ croak("dbi_profile_merge: increment not an array or hash ref");
+ i_av = (AV*)SvRV(increment);
+
tmp = *av_fetch(d_av, DBIprof_COUNT, 1);
sv_setiv( tmp, SvIV(tmp) + SvIV( *av_fetch(i_av, DBIprof_COUNT, 1)) );
@@ -2340,7 +2357,7 @@ dbi_profile_merge(SV *dest, SV *incremen
i_nv = SvNV(*av_fetch(i_av, DBIprof_MIN_TIME, 1));
tmp = *av_fetch(d_av, DBIprof_MIN_TIME, 1);
- if (i_nv < SvNV(tmp)) sv_setnv(tmp, i_nv);
+ if (!SvOK(tmp) || i_nv < SvNV(tmp)) sv_setnv(tmp, i_nv);
i_nv = SvNV(*av_fetch(i_av, DBIprof_MAX_TIME, 1));
tmp = *av_fetch(d_av, DBIprof_MAX_TIME, 1);
@@ -2348,11 +2365,16 @@ dbi_profile_merge(SV *dest, SV *incremen
i_nv = SvNV(*av_fetch(i_av, DBIprof_FIRST_CALLED, 1));
tmp = *av_fetch(d_av, DBIprof_FIRST_CALLED, 1);
- if (i_nv < SvNV(tmp)) {
+ i_is_earlier = (!SvOK(tmp) || i_nv < SvNV(tmp));
+ if (i_is_earlier)
sv_setnv(tmp, i_nv);
+
+ i_nv = SvNV(*av_fetch(i_av, DBIprof_FIRST_TIME, 1));
+ tmp = *av_fetch(d_av, DBIprof_FIRST_TIME, 1);
+ if (i_is_earlier || !SvOK(tmp)) {
/* If the increment has an earlier DBIprof_FIRST_CALLED
- then we use the DBIprof_FIRST_TIME from the increment */
- sv_setnv( tmp, SvNV( *av_fetch(i_av, DBIprof_FIRST_TIME, 1)) );
+ then we set the DBIprof_FIRST_TIME from the increment */
+ sv_setnv(tmp, i_nv);
}
i_nv = SvNV(*av_fetch(i_av, DBIprof_LAST_CALLED, 1));
@@ -3788,15 +3810,20 @@ dbi_profile_merge(dest, ...)
SV * dest
CODE:
{
- (void)cv;
if (!SvROK(dest) || SvTYPE(SvRV(dest)) != SVt_PVAV)
croak("dbi_profile_merge(%s,...) not an array reference",
neatsvpv(dest,0));
- /* items==2 for dest + 1 arg, ST(0) is dest, ST(1) is first arg */
- while (--items >= 1) {
- SV *thingy = ST(items); /* currently has to be an array ref */
- dbi_profile_merge(dest, thingy);
+ if (items <= 1) {
+ (void)cv;
+ RETVAL = 0;
+ }
+ else {
+ /* items==2 for dest + 1 arg, ST(0) is dest, ST(1) is first arg */
+ while (--items >= 1) {
+ SV *thingy = ST(items);
+ dbi_profile_merge(dest, thingy);
+ }
+ RETVAL = newSVsv(*av_fetch((AV*)SvRV(dest), DBIprof_TOTAL_TIME, 1));
}
- RETVAL = newSVsv(*av_fetch((AV*)SvRV(dest), DBIprof_TOTAL_TIME, 1));
}
OUTPUT:
RETVAL
Modified: dbi/trunk/lib/DBI/Profile.pm
==============================================================================
--- dbi/trunk/lib/DBI/Profile.pm (original)
+++ dbi/trunk/lib/DBI/Profile.pm Tue Dec 13 08:05:21 2005
@@ -381,6 +381,52 @@ then by default the statement handles cr
to the same merged profile data tree.
+=head1 CUSTOM DATA MANIPULATION
+
+Recall that C<$h->{Profile}->{Data}> is a reference to the collected data.
+Either to a 'leaf' array (when the Path is empty, i.e., DBI_PROFILE env var is
1),
+or a reference to hash containing values that are either further hash
+references or leaf array references.
+
+Sometimes it's useful to be able to summarise some or all of the collected
data.
+The dbi_profile_merge() function can be used to merge leaf node values.
+
+=head2 dbi_profile_merge
+
+ use DBI qw(dbi_profile_merge);
+
+ $time_in_dbi = dbi_profile_merge(my $totals=[], @$leaves);
+
+Merges profile data node. Given a reference to a destination array, and zero or
+more references to profile data, merges the profile data into the destination
array.
+For example:
+
+ $time_in_dbi = dbi_profile_merge(
+ my $totals=[],
+ [ 10, 0.51, 0.11, 0.01, 0.22, 1023110000, 1023110010 ],
+ [ 15, 0.42, 0.12, 0.02, 0.23, 1023110005, 1023110009 ],
+ );
+
+$totals will then contain
+
+ [ 25, 0.93, 0.11, 0.01, 0.23, 1023110000, 1023110010 ]
+
+and $time_in_dbi will be 0.93;
+
+For example, to get the time spent 'inside' the DBI during an http request,
+your logging code run at the end of the request (i.e. mod_perl LogHandler)
+could use:
+
+ my $time_in_dbi = 0;
+ if (my $Profile = $dbh->{Profile}) { # if DBI profiling is enabled
+ $time_in_dbi = dbi_profile_merge(my $total=[], $Profile->{Data});
+ $Profile->{Data} = {}; # reset the profile data
+ }
+
+If profiling has been enabled then $time_in_dbi will hold the time spent inside
+the DBI for that handle (and any other handles that share the same profile
data)
+since the last request.
+
=head1 CUSTOM DATA COLLECTION
=head2 Using The Path Attribute
Modified: dbi/trunk/lib/DBI/ProfileData.pm
==============================================================================
--- dbi/trunk/lib/DBI/ProfileData.pm (original)
+++ dbi/trunk/lib/DBI/ProfileData.pm Tue Dec 13 08:05:21 2005
@@ -261,30 +261,6 @@ sub _read_body {
}
}
-# takes an existing node and merges in new data points
-sub _merge_data { # XXX use dbi_profile_merge instead
- my ($self, $node, $data) = @_;
-
- # add counts and total duration
- $node->[COUNT] += $data->[COUNT];
- $node->[TOTAL] += $data->[TOTAL];
-
- # first duration untouched
-
- # take new shortest duration if shorter
- $node->[SHORTEST] = $data->[SHORTEST]
- if $data->[SHORTEST] < $node->[SHORTEST];
-
- # take new longest duration if longer
- $node->[LONGEST] = $data->[LONGEST]
- if $data->[LONGEST] > $node->[LONGEST];
-
- # time of first event untouched
-
- # take time of last event
- $node->[LAST_AT] = $data->[LAST_AT];
-}
-
=item $copy = $prof->clone();
Modified: dbi/trunk/t/40profile.t
==============================================================================
--- dbi/trunk/t/40profile.t (original)
+++ dbi/trunk/t/40profile.t Tue Dec 13 08:05:21 2005
@@ -26,7 +26,7 @@ BEGIN {
}
use Test;
-BEGIN { plan tests => 60; }
+BEGIN { plan tests => 64; }
use Data::Dumper;
$Data::Dumper::Indent = 1;
@@ -194,6 +194,23 @@ my $t1 = DBI::dbi_time;
dbi_profile($dbh, "Hi, mom", "fetchhash_bang", $t1, $t1 + 1);
ok(exists $data->{foo}{"Hi, mom"});
+my $total_time = dbi_profile_merge(
+ my $totals=[],
+ [ 10, 0.51, 0.11, 0.01, 0.22, 1023110000, 1023110010 ],
+ [ 15, 0.42, 0.12, 0.02, 0.23, 1023110005, 1023110009 ],
+);
+ok("@$totals", "25 0.93 0.11 0.01 0.23 1023110000 1023110010");
+ok($total_time, 0.93);
+
+$total_time = dbi_profile_merge(
+ $totals=[], {
+ foo => [ 10, 1.51, 0.11, 0.01, 0.22, 1023110000, 1023110010 ],
+ bar => [ 17, 1.42, 0.12, 0.02, 0.23, 1023110005, 1023110009 ],
+ }
+);
+ok("@$totals", "27 2.93 0.11 0.01 0.23 1023110000 1023110010");
+ok($total_time, 2.93);
+
# check that output went into the log file
DBI->trace(0, "STDOUT"); # close current log to flush it
ok(-s $LOG_FILE);