Description
Description
Towards the bottom of Perl_sv_clear
, which is frequently a very hot function, there is the following comment:
/* unrolled SvREFCNT_dec and sv_free2 follows: */
Sounds good, makes sense that it would unroll SvREFCNT_dec
and sv_free2
.
But that's not actually what it does:
/* unrolled SvREFCNT_dec and sv_free2 follows: */
if (!sv)
continue;
if (!SvREFCNT(sv)) {
sv_free(sv);
continue;
}
.....
At least nowadays, sv_free
means calling Perl_sv_free
:
void
Perl_sv_free(pTHX_ SV *const sv)
{
SvREFCNT_dec(sv);
}
SvREFCNT_dec
is an inline function in sv_inline.h
:
PERL_STATIC_INLINE void
Perl_SvREFCNT_dec(pTHX_ SV *sv)
{
if (LIKELY(sv != NULL)) {
U32 rc = SvREFCNT(sv);
if (LIKELY(rc > 1))
SvREFCNT(sv) = rc - 1;
else
Perl_sv_free2(aTHX_ sv, rc);
}
}
So instead of unrolling SvREFCNT_dec
and sv_free2
, it calls a function (probably inlined)
to call SvREFCNT_dec
which likely will call sv_free2
. That's not unrolled at all!
The likely impact of this is some SV freeing is taking longer than it strictly has to. Looking at
gcov coverage when running the test harness, there are 35099459 calls to Perl_sv_free
and
797851111 calls to Perl_sv_free2
, so maybe ~4% of cleared SVs.
Expected behavior
I haven't sat down to figure this out. It seems like the status quo in Perl_sv_clear
must be
wrong though and either the comment should be amended, (more likely) the call to sv_free
is intended to be a recursive call back to sv_free2
, or some other code change should happen.
Besides Perl_sv_clear
, only ext/Opcode/Opcode.xs and dist/Storable/Storable.xs seem
to call sv_free
directly. Probably they should be using SvREFCNT_dec
or calling sv_free2
instead.
Perl configuration
blead