diff options
author | David Mitchell <davem@iabyn.com> | 2012-12-02 12:59:37 +0000 |
---|---|---|
committer | David Mitchell <davem@iabyn.com> | 2012-12-04 11:03:38 +0000 |
commit | 75a9bf9690b77515a287eb483ea2709b73810c41 (patch) | |
tree | b708681f8c48b94d2c2e0d4d49ac49c70783a548 /inline.h | |
parent | b492a59ed90fecea7508c6bc9601fb08e0212721 (diff) | |
download | perl-75a9bf9690b77515a287eb483ea2709b73810c41.tar.gz |
make SvREFCNT_dec() more efficient
Historically, SvREFCNT_dec was just
#define SvREFCNT_dec(sv) sv_free((SV*)(sv))
then in 5.10.0, for GCC, the macro was partially inlined, avoiding a
function call for the refcnt > 1 case. Recently, the macro was turned into
an inline function, providing the function-call avoidance to other
platforms too. However, the macro/inline-function is quite big, and
appears over 500 times in the core source. Its action is logically
equivalent to:
if (sv) {
if (SvREFCNT(sv) > 1)
SvREFCNT(sv)--;
else if (SvREFCNT == 1) {
// normal case
SvREFCNT(sv)--;
sv_free2(sv);
}
else {
// exceptional case
sv_free(sv);
}
}
Where sv_free2() handles the "normal" quick cases, while sv_free()
handles the odd cases (e,g. a ref count already at 0 during global
destruction).
This means we have to plant code that potentially calls two different
subs, over 500 times.
This commit changes SvREFCNT_dec and sv_free2() to look like:
PERL_STATIC_INLINE void
S_SvREFCNT_dec(pTHX_ SV *sv)
{
if (sv) {
U32 rc = SvREFCNT(sv);
if (rc > 1)
SvREFCNT(sv) = rc - 1;
else
Perl_sv_free2(aTHX_ sv, rc);
}
}
Perl_sv_free2(pTHX_ SV *const sv, const U32 rc)
{
if (rc == 1) {
SvREFCNT(sv) = 0;
... do sv_clear, del_SV etc ...
return
}
/* handle exceptional rc == 0 */
...
}
So for the normal cases (rc > 1, rc == 1) there is the same amount of
testing and function calls, but the second test has been moved inside
the sv_free2() function.
This makes the perl executable about 10-15K smaller, and apparently a bit
faster (modulo the fact that most benchmarks are just measuring noise).
The refcount is passed as a second arg to sv_free2(), as on platforms
that pass the first few args in registers, it saves reading sv->sv_refcnt
again.
Diffstat (limited to 'inline.h')
-rw-r--r-- | inline.h | 11 |
1 files changed, 5 insertions, 6 deletions
@@ -55,12 +55,11 @@ PERL_STATIC_INLINE void S_SvREFCNT_dec(pTHX_ SV *sv) { if (sv) { - if (SvREFCNT(sv)) { - if (--(SvREFCNT(sv)) == 0) - Perl_sv_free2(aTHX_ sv); - } else { - sv_free(sv); - } + U32 rc = SvREFCNT(sv); + if (rc > 1) + SvREFCNT(sv) = rc - 1; + else + Perl_sv_free2(aTHX_ sv, rc); } } |