Author: timbo
Date: Mon Apr 16 11:37:58 2007
New Revision: 9418

Added:
   dbi/trunk/dbilogstrip.PL   (contents, props changed)
Modified:
   dbi/trunk/Changes
   dbi/trunk/DBI.pm
   dbi/trunk/DBI.xs
   dbi/trunk/MANIFEST
   dbi/trunk/Makefile.PL
   dbi/trunk/dbiprof.PL
   dbi/trunk/dbiproxy.PL
   dbi/trunk/dumpmethods.pl
   dbi/trunk/goferperf.pl   (props changed)
   dbi/trunk/lib/DBI/PurePerl.pm
   dbi/trunk/t/01basics.t
   dbi/trunk/t/02dbidrv.t
   dbi/trunk/test.pl

Log:
Moved _new_handle and TIEHASH to C.
Now 20% faster (for $null_dbh->prepare('') while $i--;)
Added dbilogstrip utility (gets installed) to filter DBI logs.


Modified: dbi/trunk/Changes
==============================================================================
--- dbi/trunk/Changes   (original)
+++ dbi/trunk/Changes   Mon Apr 16 11:37:58 2007
@@ -53,9 +53,12 @@
   Changed DBD::NullP to be slightly more useful for testing.
   Changed File::Spec prerequisite to not require a minimum version.
   Changed tests to work with other DBMs thanks to ZMAN.
+  Changed some handle creation code from perl to C code,
+    so handle creation cost reduced by ~20%.
   Many assorted Gofer related bug fixes, enhancements and docs.
 
   Added goferperf.pl utility (doesn't get installed).
+  Added dbilogstrip utility (gets installed)
   Added support for DBI Profile Path to contain refs to scalars
     which will be de-ref'd for each profile sample.
 

Modified: dbi/trunk/DBI.pm
==============================================================================
--- dbi/trunk/DBI.pm    (original)
+++ dbi/trunk/DBI.pm    Mon Apr 16 11:37:58 2007
@@ -778,6 +778,7 @@
     $drh = eval { $driver_class->driver($attr || {}) };
     unless ($drh && ref $drh && !$@) {
        my $advice = "";
+        $@ ||= "$driver_class->driver didn't return a handle";
        # catch people on case in-sensitive systems using the wrong case
        $advice = "\nPerhaps the capitalisation of DBD '$driver' isn't right."
                if $@ =~ /locate object method/;
@@ -1136,13 +1137,14 @@
     my $loops ||= $attr->{dbi_loops} || 5;
     my $par   ||= $attr->{dbi_par}   || 1;     # parallelism
     my $verb  ||= $attr->{dbi_verb}  || 1;
+    my $meth  ||= $attr->{dbi_meth}  || 'connect';
     print "$dsn: testing $loops sets of $par connections:\n";
-    require Benchmark;
     require "FileHandle.pm";   # don't let toke.c create empty FileHandle 
package
-    $| = 1;
-    my $t0 = new Benchmark;            # not currently used
+    local $| = 1;
     my $drh = $class->install_driver($dsn) or Carp::croak("Can't install $dsn 
driver\n");
-    my $t1 = new Benchmark;
+    # test the connection and warm up caches etc
+    $drh->connect($dsn,$dbuser,$dbpass) or Carp::croak("connect failed: 
$DBI::errstr");
+    my $t1 = dbi_time();
     my $loop;
     for $loop (1..$loops) {
        my @cons;
@@ -1150,58 +1152,30 @@
        for (1..$par) {
            print "$_ ";
            push @cons, ($drh->connect($dsn,$dbuser,$dbpass)
-                   or Carp::croak("Can't connect # $_: $DBI::errstr\n"));
+                   or Carp::croak("connect failed: $DBI::errstr\n"));
        }
        print "\nDisconnecting...\n" if $verb;
        for (@cons) {
-           $_->disconnect or warn "bad disconnect $DBI::errstr"
+           $_->disconnect or warn "disconnect failed: $DBI::errstr"
        }
     }
-    my $t2 = new Benchmark;
-    my $td = Benchmark::timediff($t2, $t1);
-    printf "Made %2d connections in %s\n", $loops*$par, 
Benchmark::timestr($td);
-       print "\n";
+    my $t2 = dbi_time();
+    my $td = $t2 - $t1;
+    printf "$meth %d and disconnect them, %d times: %.4fs / %d = %.4fs\n",
+        $par, $loops, $td, $loops*$par, $td/($loops*$par);
     return $td;
 }
 
 
 # Help people doing DBI->errstr, might even document it one day
-# XXX probably best moved to cheaper XS code
+# XXX probably best moved to cheaper XS code if this gets documented
 sub err    { $DBI::err    }
 sub errstr { $DBI::errstr }
 
 
 # --- Private Internal Function for Creating New DBI Handles
 
-sub _new_handle {
-    my ($class, $parent, $attr, $imp_data, $imp_class) = @_;
-
-    Carp::croak('Usage: DBI::_new_handle'
-           .'($class_name, parent_handle, \%attr, $imp_data)'."\n"
-           .'got: ('.join(", ",$class, $parent, $attr, $imp_data).")\n")
-       unless (@_ == 5 and (!$parent or ref $parent)
-                       and ref $attr eq 'HASH'
-                       and $imp_class);
-
-    $attr->{ImplementorClass} = $imp_class
-       or Carp::croak("_new_handle($class): 'ImplementorClass' attribute not 
given");
-
-    DBI->trace_msg("    New $class (for $imp_class, parent=$parent, 
id=".($imp_data||'').")\n")
-       if $DBI::dbi_debug >= 3;
-
-    # This is how we create a DBI style Object:
-    my (%hash, $i, $h);
-    $i = tie    %hash, $class, $attr;  # ref to inner hash (for driver)
-    $h = bless \%hash, $class;         # ref to outer hash (for application)
-    # The above tie and bless may migrate down into _setup_handle()...
-    # Now add magic so DBI method dispatch works
-    DBI::_setup_handle($h, $imp_class, $parent, $imp_data);
-
-    return $h unless wantarray;
-    ($h, $i);
-}
-# XXX minimum constructors for the tie's (alias to XS version)
-sub DBI::st::TIEHASH { bless $_[1] => $_[0] };
+# XXX move to PurePerl?
 *DBI::dr::TIEHASH = \&DBI::st::TIEHASH;
 *DBI::db::TIEHASH = \&DBI::st::TIEHASH;
 
@@ -7228,16 +7202,21 @@
 
 =head2 Tracing Tips
 
-You can add tracing to your own application code using the
-L</trace_msg> method.
+You can add tracing to your own application code using the L</trace_msg> 
method.
+
+It can sometimes be handy to compare trace files from two different runs of the
+same script. However using a tool like C<diff> on the original log output
+doesn't work well because the trace file is full of object addresses that may
+differ on each run.
 
-It can sometimes be handy to compare trace files from two different
-runs of the same script. However using a tool like C<diff> doesn't work
-well because the trace file is full of object addresses that may
-differ each run. Here's a handy little command to strip those out:
+The DBI includes a handy utility called dbilogstrip that can be used to
+'normalize' the log content. It can be used as a filter like this:
 
-  perl -pe 's/\b0x[\da-f]{6,}/0xNNNN/gi; s/\b[\da-f]{6,}/<long number>/gi'
+    DBI_TRACE=2 perl yourscript.pl ...args1... 2>&1 | dbilogstrip > 
dbitrace1.log
+    DBI_TRACE=2 perl yourscript.pl ...args2... 2>&1 | dbilogstrip > 
dbitrace2.log
+    diff -u dbitrace1.log dbitrace2.log
 
+See L<dbilogstrip> for more information.
 
 =head1 DBI ENVIRONMENT VARIABLES
 

Modified: dbi/trunk/DBI.xs
==============================================================================
--- dbi/trunk/DBI.xs    (original)
+++ dbi/trunk/DBI.xs    Mon Apr 16 11:37:58 2007
@@ -1150,7 +1150,7 @@
     /* Use DBI magic on inner handle to carry handle attributes        */
     sv_magic(SvRV(h), dbih_imp_sv, DBI_MAGIC, Nullch, 0);
     SvREFCNT_dec(dbih_imp_sv); /* since sv_magic() incremented it      */
-    SvRMAGICAL_on(SvRV(h));    /* so magic gets sv_clear'd ok          */
+    SvRMAGICAL_on(SvRV(h));    /* so DBI magic gets sv_clear'd ok      */
 
     DBI_SET_LAST_HANDLE(h);
 
@@ -1179,6 +1179,10 @@
 dbih_dumphandle(SV *h, const char *msg, int level)
 {
     D_imp_xxh(h);
+    if (level >= 9) {
+        dTHX;
+        sv_dump(h);
+    }
     dbih_dumpcom(imp_xxh, msg, level);
 }
 
@@ -3872,6 +3876,58 @@
 
 
 void
+_new_handle(class, parent, attr_ref, imp_datasv, imp_class)
+    SV *       class
+    SV *       parent
+    SV *       attr_ref
+    SV *       imp_datasv
+    SV *       imp_class
+    PPCODE:
+    dTHX;
+    dPERINTERP;
+    HV *outer;
+    SV *outer_ref;
+    GV *class_stash = gv_stashsv(class, GV_ADDWARN);
+    (void)cv;
+
+    if (DBIS_TRACE_LEVEL >= 3) {
+        PerlIO_printf(DBILOGFP, "    New %s (for %s, parent=%s, id=%s)\n",
+            neatsvpv(class,0), SvPV_nolen(imp_class), neatsvpv(parent,0), 
neatsvpv(imp_datasv,0));
+    }
+
+    hv_store(SvRV(attr_ref), "ImplementorClass", 16, SvREFCNT_inc(imp_class), 
0);
+
+    /* make attr into inner handle by blessing it into class */
+    sv_bless(attr_ref, class_stash);
+    /* tie new outer hash to inner handle */
+    outer = newHV(); /* create new hash to be outer handle */
+    outer_ref = newRV_noinc((SV*)outer);
+    /* make outer hash into a handle by blessing it into class */
+    sv_bless(outer_ref, class_stash);
+    /* tie outer handle to inner handle */
+    sv_magic((SV*)outer, attr_ref, PERL_MAGIC_tied, Nullch, 0);
+    /*SvREFCNT_dec(attr_ref);  /* because sv_magic() incremented it */
+
+    /*
+        my (%outer, $i, $h);
+        $i = tie    %outer, $class, $attr;  # ref to inner hash (for driver)
+        $h = bless \%outer, $class;         # ref to outer hash (for 
application)
+        DBI::_setup_handle($h, $imp_class, $parent, $imp_data);
+        return $h unless wantarray;
+        return ($h, $i);
+    */
+    dbih_setup_handle(outer_ref, SvPV_nolen(imp_class), parent, 
SvOK(imp_datasv) ? imp_datasv : Nullsv);
+
+    /* return outer handle, plus inner handle if not in scalar context */
+    sv_2mortal(outer_ref);
+    EXTEND(SP, 2);
+    PUSHs(outer_ref);
+    if (GIMME != G_SCALAR) {
+        PUSHs(attr_ref);
+    }
+
+
+void
 _setup_handle(sv, imp_class, parent, imp_datasv)
     SV *       sv
     char *     imp_class
@@ -4592,6 +4648,17 @@
     }
 
 
+MODULE = DBI   PACKAGE = DBI::st
+
+void
+TIEHASH(class, inner_ref)
+    SV * class
+    SV * inner_ref
+    CODE:
+    HV *stash = gv_stashsv(class, GV_ADDWARN); /* a new hash is supplied to 
us, we just need to bless and apply tie magic */
+    sv_bless(inner_ref, stash);
+    ST(0) = inner_ref;
+
 MODULE = DBI   PACKAGE = DBD::_::common
 
 

Modified: dbi/trunk/MANIFEST
==============================================================================
--- dbi/trunk/MANIFEST  (original)
+++ dbi/trunk/MANIFEST  Mon Apr 16 11:37:58 2007
@@ -15,6 +15,7 @@
 dbd_xsh.h                      Prototypes for standard Driver.xst interface
 dbi_sql.h                      Definitions based on SQL CLI / ODBC (#inc'd by 
DBIXS.h)
 dbipport.h                     Perl portability macros (from Devel::PPort)
+dbilogstrip.PL                  Utility to normalise DBI logs so they can be 
compared with diff
 dbiprof.PL
 dbiproxy.PL                    Frontend for DBI::ProxyServer
 dbivport.h                     DBI version portability macros (for drivers to 
copy)

Modified: dbi/trunk/Makefile.PL
==============================================================================
--- dbi/trunk/Makefile.PL       (original)
+++ dbi/trunk/Makefile.PL       Mon Apr 16 11:37:58 2007
@@ -126,11 +126,11 @@
         "File::Spec" => 0,
         "Scalar::Util" => 0,
     },
-    EXE_FILES => [ "dbiproxy$ext_pl", "dbiprof$ext_pl" ],
+    EXE_FILES => [ "dbiproxy$ext_pl", "dbiprof$ext_pl", "dbilogstrip$ext_pl" ],
     DIR => [ ],
     dynamic_lib => { OTHERLDFLAGS => "$::opt_g" },
     clean => { FILES=> "\$(DISTVNAME) Perl.xsi t/zv*_*.t"
-                       ." dbiproxy$ext_pl dbiprof$ext_pl dbitrace.log dbi.prof 
ndtest.prt" },
+                ." dbiproxy$ext_pl dbiprof$ext_pl dbilogstrip$ext_pl 
dbitrace.log dbi.prof ndtest.prt" },
     dist  => {
        DIST_DEFAULT=> 'clean distcheck disttest tardist',
        PREOP => '$(MAKE) -f Makefile.old distdir',
@@ -310,7 +310,7 @@
        $(CP) Roadmap.pod $(roadmap_pm)
 
 checkkeywords:
-       $(RM_F) blib
+       $(RM_RF) blib
        find . -type f \( -name .svn -prune -o -name \*.pm -o -name \*.PL -o 
-name \*.pl \) \
             -exec bash -c '[ -z "$$(svn pg svn:keywords {})" ] && echo svn 
propset svn:keywords \"Id Revision\" {}' \;
 };

Added: dbi/trunk/dbilogstrip.PL
==============================================================================
--- (empty file)
+++ dbi/trunk/dbilogstrip.PL    Mon Apr 16 11:37:58 2007
@@ -0,0 +1,34 @@
+# -*- perl -*-
+my $file = $ARGV[0] || 'dbilogstrip';
+
+my $script = <<'SCRIPT';
+~startperl~
+
+use strict;
+
+while (<>) {
+    # normalize hex addresses: 0xDEADHEAD => 0x
+    s/ \b 0x [0-9a-f]+ /0x/gx;
+    # normalize process id number
+    s/ \b pid \W? \d+ /pidN/gx;
+
+} continue {
+    print or die "-p destination: $!\n";
+}
+
+
+SCRIPT
+
+require Config;
+my $config = {};
+$config->{'startperl'} = $Config::Config{'startperl'};
+
+$script =~ s/\~(\w+)\~/$config->{$1}/eg;
+if (!(open(FILE, ">$file"))  ||
+    !(print FILE $script)  ||
+    !(close(FILE))) {
+    die "Error while writing $file: $!\n";
+}
+chmod 0755, $file;
+print "Extracted $file from ",__FILE__," with variable substitutions.\n";
+

Modified: dbi/trunk/dbiprof.PL
==============================================================================
--- dbi/trunk/dbiprof.PL        (original)
+++ dbi/trunk/dbiprof.PL        Mon Apr 16 11:37:58 2007
@@ -1,6 +1,6 @@
 # -*- perl -*-
 
-my $file = 'dbiprof';
+my $file = $ARGV[0] || 'dbiprof';
 
 my $script = <<'SCRIPT';
 ~startperl~
@@ -246,4 +246,5 @@
     !(close(FILE))) {
     die "Error while writing $file: $!\n";
 }
+chmod 0755, $file;
 print "Extracted $file from ",__FILE__," with variable substitutions.\n";

Modified: dbi/trunk/dbiproxy.PL
==============================================================================
--- dbi/trunk/dbiproxy.PL       (original)
+++ dbi/trunk/dbiproxy.PL       Mon Apr 16 11:37:58 2007
@@ -1,6 +1,6 @@
 # -*- perl -*-
 
-my $file = 'dbiproxy';
+my $file = $ARGV[0] || 'dbiproxy';
 
 my $script = <<'SCRIPT';
 ~startperl~
@@ -187,6 +187,7 @@
 
 L<DBI::ProxyServer(3)>, L<DBD::Proxy(3)>, L<DBI(3)>
 
+=cut
 SCRIPT
 
 
@@ -200,4 +201,5 @@
     !(close(FILE))) {
     die "Error while writing $file: $!\n";
 }
+chmod 0755, $file;
 print "Extracted $file from ",__FILE__," with variable substitutions.\n";

Modified: dbi/trunk/dumpmethods.pl
==============================================================================
--- dbi/trunk/dumpmethods.pl    (original)
+++ dbi/trunk/dumpmethods.pl    Mon Apr 16 11:37:58 2007
@@ -41,7 +41,7 @@
         my $O = $info->{O}||0;
         my @ima_flags = map { ($O & $_) ? $bit2hex{$_} : () } @bit2hex_bitkeys;
 
-        printf "\$h->$fullmeth($proto)  @ima_flags # 0x%04x\n", $O;
+        printf "\$h->%s(%s)  %s # 0x%04x\n", $fullmeth, $proto, "@ima_flags", 
$O;
     }
 }   
 

Modified: dbi/trunk/lib/DBI/PurePerl.pm
==============================================================================
--- dbi/trunk/lib/DBI/PurePerl.pm       (original)
+++ dbi/trunk/lib/DBI/PurePerl.pm       Mon Apr 16 11:37:58 2007
@@ -436,6 +436,28 @@
     }
 }
 
+
+sub _new_handle {
+    my ($class, $parent, $attr, $imp_data, $imp_class) = @_;
+
+    DBI->trace_msg("    New $class (for $imp_class, parent=$parent, 
id=".($imp_data||'').")\n")
+        if $DBI::dbi_debug >= 3;
+
+    $attr->{ImplementorClass} = $imp_class
+        or Carp::croak("_new_handle($class): 'ImplementorClass' attribute not 
given");
+
+    # This is how we create a DBI style Object:
+    # %outer gets tied to %$attr (which becomes the 'inner' handle)
+    my (%outer, $i, $h);
+    $i = tie    %outer, $class, $attr;  # ref to inner hash (for driver)
+    $h = bless \%outer, $class;         # ref to outer hash (for application)
+    # The above tie and bless may migrate down into _setup_handle()...
+    # Now add magic so DBI method dispatch works
+    DBI::_setup_handle($h, $imp_class, $parent, $imp_data);
+    return $h unless wantarray;
+    return ($h, $i);
+}
+
 sub _setup_handle {
     my($h, $imp_class, $parent, $imp_data) = @_;
     my $h_inner = tied(%$h) || $h;
@@ -635,6 +657,8 @@
     return time();
 }
 
+sub DBI::st::TIEHASH { bless $_[1] => $_[0] };
+
 package
        DBI::var;
 

Modified: dbi/trunk/t/01basics.t
==============================================================================
--- dbi/trunk/t/01basics.t      (original)
+++ dbi/trunk/t/01basics.t      Mon Apr 16 11:37:58 2007
@@ -148,20 +148,6 @@
 ## ----------------------------------------------------------------------------
 ## testing DBI functions
 
-## testing dbi_debug
-
-cmp_ok($DBI::dbi_debug, '==',  0, "... DBI::dbi_debug's initial state is 0");
-
-SKIP: {
-    my $null = File::Spec->devnull();
-    skip "cannot find : $null", 2 unless ($^O eq "MSWin32" || -e $null);
-
-    DBI->trace(15,$null);
-    cmp_ok($DBI::dbi_debug, '==', 15, "... DBI::dbi_debug is 15");
-    DBI->trace(0, undef);
-    cmp_ok($DBI::dbi_debug, '==',  0, "... DBI::dbi_debug is 0");
-}
-
 ## test DBI->internal
 
 my $switch = DBI->internal;
@@ -317,4 +303,18 @@
        like("@installed_drivers", qr/Sponge/, '... make sure at least one of 
them is DBI::Spounge');
 }
 
+## testing dbi_debug
+
+cmp_ok($DBI::dbi_debug, '==',  0, "... DBI::dbi_debug's initial state is 0");
+
+SKIP: {
+    my $null = File::Spec->devnull();
+    skip "cannot find : $null", 2 unless ($^O eq "MSWin32" || -e $null);
+
+    DBI->trace(15,$null);
+    cmp_ok($DBI::dbi_debug, '==', 15, "... DBI::dbi_debug is 15");
+    DBI->trace(0, undef);
+    cmp_ok($DBI::dbi_debug, '==',  0, "... DBI::dbi_debug is 0");
+}
+
 1;

Modified: dbi/trunk/t/02dbidrv.t
==============================================================================
--- dbi/trunk/t/02dbidrv.t      (original)
+++ dbi/trunk/t/02dbidrv.t      Mon Apr 16 11:37:58 2007
@@ -198,7 +198,8 @@
 SKIP: {
     skip "Kids attribute not supported under DBI::PurePerl", 1 if 
$DBI::PurePerl;
     
-    cmp_ok($drh->{Kids}, '==', 0, '... this Driver does not yet have any 
Kids');
+    cmp_ok($drh->{Kids}, '==', 0, '... this Driver does not yet have any Kids')
+        or $drh->dump_handle("bad Kids",3);
 }
 
 # copied up to drh from dbh when dbh was DESTROYd

Modified: dbi/trunk/test.pl
==============================================================================
--- dbi/trunk/test.pl   (original)
+++ dbi/trunk/test.pl   Mon Apr 16 11:37:58 2007
@@ -94,14 +94,14 @@
     
     # new experimental connect_test_perf method
     DBI->connect_test_perf("dbi:$driver:", '', '', {
-       dbi_loops=>5, dbi_par=>20, dbi_verb=>1
+       dbi_loops=>3, dbi_par=>20, dbi_verb=>1
     });
 
     require Benchmark;
     print "Testing handle creation speed...\n";
     my $null_dbh = DBI->connect('dbi:NullP:','','');
     my $null_sth = $null_dbh->prepare('');     # create one to warm up
-    $count = 10_000;
+    $count = 20_000;
     my $i = $count;
     my $t1 = new Benchmark;
     $null_dbh->prepare('') while $i--;

Reply via email to