Skip to content

Commit bd30fe8

Browse files
erichermantsee
authored andcommitted
Speed up newSViv()
newSViv() is not used a whole lot by the core. But it is frequently used in XS modules. In a nutshell, it allocates a new EMPTY SV just to call sv_setiv which calls sv_upgrade which in turn spends inordinate amounts of time looking at the properties of the SV to make it an SVt_IV. But the properties of that SV are always the same: a clean slate! Therefore, inlining the very simple bits of sv_setiv that are actually necessary gives a very tangible speed-up. It's not very easy to benchmark with with a language-level one-liner because newSViv() isn't too common in the core. Thus follow XS micro-benchmarks: Benchmark 1: Virtually no-op XS function. SV * echo_integer(int in) CODE: RETVAL = newSViv(in); OUTPUT: RETVAL $ dumbbench -i50 --pin-frequency -- ./perl -Ilib \ -MXS::APItest -e 'XS::APItest::echo_integer($_) for 1..1000000' Before: 3.2782e-01 seconds After: 3.0530e-01 seconds A small change, but considering the massive overhead of a function call, quite surprisingly noticeable. Benchmark 2: XS function that constructs multiple integer values. SV * echo_integer_array(int in) PREINIT: int i; AV *av; CODE: av = newAV(); RETVAL = newRV_noinc((SV *)av); av_extend(av, in-1); for (i = 0; i < in; ++i) av_store(av, i, newSViv(i)); OUTPUT: RETVAL $ dumbbench -i50 --pin-frequency -- ./perl -Ilib \ -MXS::APItest -e 'XS::APItest::echo_integer_array(100) for 1..10000' Before: 1.18363e-01 seconds After: 0.92050e-01 seconds While in the grand scheme of things, this might seem like a very small optimization, there are many XS modules that actually generate a lot of integer values, de-serializers being good examples.
1 parent de06ff5 commit bd30fe8

File tree

1 file changed

+16
-1
lines changed

1 file changed

+16
-1
lines changed

sv.c

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9359,7 +9359,22 @@ Perl_newSViv(pTHX_ const IV i)
93599359
SV *sv;
93609360

93619361
new_SV(sv);
9362-
sv_setiv(sv,i);
9362+
9363+
/* Inlining ONLY the small relevant subset of sv_setiv here
9364+
* for performance. Makes a significant difference. */
9365+
9366+
/* We're starting from SVt_FIRST, so provided that's
9367+
* actual 0, we don't have to unset any SV type flags
9368+
* to promote to SVt_IV. */
9369+
assert(SVt_FIRST == 0);
9370+
9371+
SET_SVANY_FOR_BODYLESS_IV(sv);
9372+
SvFLAGS(sv) |= SVt_IV;
9373+
(void)SvIOK_on(sv);
9374+
9375+
SvIV_set(sv, i);
9376+
SvTAINT(sv);
9377+
93639378
return sv;
93649379
}
93659380

0 commit comments

Comments
 (0)