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
-
Massive speed increase for class method calls (181%)
by Arthur Bergman