develooper Front page | perl.perl5.porters | Postings from April 2003

Massive speed increase for class method calls (181%)

Thread Next
From:
Arthur Bergman
Date:
April 2, 2003 06:24
Subject:
Massive speed increase for class method calls (181%)
Message ID:
B26ED130-6516-11D7-847C-003065D64CBE@nanisky.com
Hi,

Herr Schwern pointed out to me that method calls are slow (big news!), 
but that class method calls are nearly 2x as slow as object method 
calls, aka

Test->foo(); taking 2x the time of
my $foo = bless {}, "Test";
$foo->foo();


The reason for this is that for every single call we need to

a) See if the bareword is filehandle to support STDERR->print(""); 
notation (which IMHO should be deprecated)
This also uses the extremely high performance code *(PL_stack_base + 
TOPMARK + 1) = sv_2mortal(newRV((SV*)iogv)); on every method call!.

b) do a gv_stashpvn looking up the stash for this call

This patch speeds this up by adding a cache PL_stashcache that is used 
in to cache the packname  > stash conversion, it clears it when a stash 
is deleted and when a new gvio part is created (since then a filehandle 
might be created and then we need to do step a again.

Result on the test script

package Test;

sub test { return @_ }
package main;

use Benchmark;

$obj = bless {}, "Test";
timethese(shift || -3,
           {
            class_method     => sub { Test->test(42); },
            obj_method       => sub { $obj->test(42); },
	})

Is

unpatched
Benchmark: timing 3000000 iterations of class_method, obj_method...
class_method: 10 wallclock secs (10.12 usr +  0.00 sys = 10.12 CPU) @ 
296442.69/s (n=3000000)
obj_method:  5 wallclock secs ( 4.89 usr +  0.00 sys =  4.89 CPU) @ 
613496.93/s (n=3000000)

patched
class_method:  6 wallclock secs ( 5.57 usr +  0.00 sys =  5.57 CPU) @ 
538599.64/s (n=3000000)
obj_method:  5 wallclock secs ( 4.85 usr +  0.00 sys =  4.85 CPU) @ 
618556.70/s (n=3000000)


I believe this could go into 5.8.1 without a problem.

Arthur

PS. I can apply it myself but I thought it should be discussed first, 
all tests pass, no semantics have changed.

diff -r -u unpatched/embedvar.h patched/embedvar.h
--- unpatched/embedvar.h        2003-04-02 15:16:06.000000000 +0200
+++ patched/embedvar.h  2003-04-02 15:35:29.000000000 +0200
@@ -373,6 +373,7 @@
  #define PL_sort_RealCmp                (vTHX->Isort_RealCmp)
  #define PL_splitstr            (vTHX->Isplitstr)
  #define PL_srand_called                (vTHX->Isrand_called)
+#define PL_stashcache          (vTHX->Istashcache)
  #define PL_statusvalue         (vTHX->Istatusvalue)
  #define PL_statusvalue_vms     (vTHX->Istatusvalue_vms)
  #define PL_stderrgv            (vTHX->Istderrgv)
@@ -665,6 +666,7 @@
  #define PL_Isort_RealCmp       PL_sort_RealCmp
  #define PL_Isplitstr           PL_splitstr
  #define PL_Isrand_called       PL_srand_called
+#define PL_Istashcache         PL_stashcache
  #define PL_Istatusvalue                PL_statusvalue
  #define PL_Istatusvalue_vms    PL_statusvalue_vms
  #define PL_Istderrgv           PL_stderrgv
diff -r -u unpatched/gv.c patched/gv.c
--- unpatched/gv.c      2003-04-02 15:16:43.000000000 +0200
+++ patched/gv.c        2003-04-02 15:26:16.000000000 +0200
@@ -1121,6 +1121,9 @@
      sv_upgrade((SV *)io,SVt_PVIO);
      SvREFCNT(io) = 1;
      SvOBJECT_on(io);
+    /* Clear the stashcache because a new IO could overrule a
+       package name */
+    hv_clear(PL_stashcache);
      iogv = gv_fetchpv("FileHandle::", FALSE, SVt_PVHV);
      /* unless exists($main::{FileHandle}) and 
defined(%main::FileHandle::) */
      if (!(iogv && GvHV(iogv) && HvARRAY(GvHV(iogv))))
diff -r -u unpatched/hv.c patched/hv.c
--- unpatched/hv.c      2003-04-02 15:16:48.000000000 +0200
+++ patched/hv.c        2003-04-02 15:27:35.000000000 +0200
@@ -1739,6 +1739,8 @@
      hfreeentries(hv);
      Safefree(xhv->xhv_array /* HvARRAY(hv) */);
      if (HvNAME(hv)) {
+        if(PL_stashcache)
+            hv_delete_ent(PL_stashcache, 
sv_2mortal(newSVpv(HvNAME(hv),0)), G_DISCARD, 0);
         Safefree(HvNAME(hv));
         HvNAME(hv) = 0;
      }
diff -r -u unpatched/intrpvar.h patched/intrpvar.h
--- unpatched/intrpvar.h        2003-04-02 15:16:48.000000000 +0200
+++ patched/intrpvar.h  2003-04-02 15:21:42.000000000 +0200
@@ -506,6 +506,8 @@

  PERLVAR(IDBassertion,   SV *)

+PERLVAR(Istashcache,   HV *)           /* Cache to speed up 
S_method_common */
+
  /* Don't forget to add your variable also to perl_clone()! */

  /* New variables must be added to the very end, before this comment,
diff -r -u unpatched/perlapi.h patched/perlapi.h
--- unpatched/perlapi.h 2003-04-02 15:17:46.000000000 +0200
+++ patched/perlapi.h   2003-04-02 15:35:39.000000000 +0200
@@ -504,6 +504,8 @@
  #define PL_splitstr            (*Perl_Isplitstr_ptr(aTHX))
  #undef  PL_srand_called
  #define PL_srand_called                (*Perl_Isrand_called_ptr(aTHX))
+#undef  PL_stashcache
+#define PL_stashcache          (*Perl_Istashcache_ptr(aTHX))
  #undef  PL_statusvalue
  #define PL_statusvalue         (*Perl_Istatusvalue_ptr(aTHX))
  #undef  PL_statusvalue_vms
diff -r -u unpatched/perl.c patched/perl.c
--- unpatched/perl.c    2003-04-02 15:17:46.000000000 +0200
+++ patched/perl.c      2003-04-02 15:28:25.000000000 +0200
@@ -272,6 +272,8 @@
  #endif
          PL_clocktick = HZ;

+    PL_stashcache = newHV();
+
      ENTER;
  }

@@ -457,6 +459,9 @@
      PL_regex_pad = NULL;
  #endif

+    SvREFCNT_dec((SV*) PL_stashcache);
+    PL_stashcache = NULL;
+
      /* loosen bonds of global variables */

      if(PL_rsfp) {
diff -r -u unpatched/pp_hot.c patched/pp_hot.c
--- unpatched/pp_hot.c  2003-04-02 15:17:55.000000000 +0200
+++ patched/pp_hot.c    2003-04-02 15:58:49.000000000 +0200
@@ -2926,6 +2926,15 @@

         /* this isn't a reference */
         packname = Nullch;
+
+        if(SvOK(sv) && (packname = SvPV(sv, packlen))) {
+          HE* he = hv_fetch_ent(PL_stashcache, sv, 0, 0);
+          if (he) {
+            stash = HeVAL(he);
+            goto fetch;
+          }
+        }
+
         if (!SvOK(sv) ||
             !(packname = SvPV(sv, packlen)) ||
             !(iogv = gv_fetchpv(packname, FALSE, SVt_PVIO)) ||
@@ -2946,6 +2955,11 @@
             stash = gv_stashpvn(packname, packlen, FALSE);
             if (!stash)
                 packsv = sv;
+            else {
+              SvREFCNT_inc((SV*)stash);
+              if(!hv_store(PL_stashcache, packname, packlen, stash, 0))
+                SvREFCNT_dec((SV*)stash);
+            }
             goto fetch;
         }
         /* it _is_ a filehandle name -- replace with a reference */
diff -r -u unpatched/sv.c patched/sv.c
--- unpatched/sv.c      2003-04-02 15:17:58.000000000 +0200
+++ patched/sv.c        2003-04-02 15:22:10.000000000 +0200
@@ -11397,6 +11397,8 @@
      /* Pluggable optimizer */
      PL_peepp           = proto_perl->Tpeepp;

+    PL_stashcache       = newHV();
+
      if (!(flags & CLONEf_KEEP_PTR_TABLE)) {
          ptr_table_free(PL_ptr_table);
          PL_ptr_table = NULL;




Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About