summaryrefslogtreecommitdiff
path: root/sv.c
diff options
context:
space:
mode:
authorEric Herman <eric@freesa.org>2014-11-28 15:08:04 +0100
committerSteffen Mueller <smueller@cpan.org>2014-11-28 15:45:47 +0100
commitbd30fe8921c88e4677c2279b442a56a11ae037b4 (patch)
treef5a7044e46aecfb36e954c98e1e5aef293c11928 /sv.c
parentde06ff5a50f29eaee3e72394fa1c2417689cac47 (diff)
downloadperl-bd30fe8921c88e4677c2279b442a56a11ae037b4.tar.gz
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.
Diffstat (limited to 'sv.c')
-rw-r--r--sv.c17
1 files changed, 16 insertions, 1 deletions
diff --git a/sv.c b/sv.c
index 4a2850e1f1..40b614e81e 100644
--- a/sv.c
+++ b/sv.c
@@ -9359,7 +9359,22 @@ Perl_newSViv(pTHX_ const IV i)
SV *sv;
new_SV(sv);
- sv_setiv(sv,i);
+
+ /* Inlining ONLY the small relevant subset of sv_setiv here
+ * for performance. Makes a significant difference. */
+
+ /* We're starting from SVt_FIRST, so provided that's
+ * actual 0, we don't have to unset any SV type flags
+ * to promote to SVt_IV. */
+ assert(SVt_FIRST == 0);
+
+ SET_SVANY_FOR_BODYLESS_IV(sv);
+ SvFLAGS(sv) |= SVt_IV;
+ (void)SvIOK_on(sv);
+
+ SvIV_set(sv, i);
+ SvTAINT(sv);
+
return sv;
}