Maintaining the Perl 5 Core: Report for Month 22
Wed, 02-Sep-2015 by
Karen Pauley
edit post
_Dave Mitchell writes:_
I spent July mainly working on two things.
First, I continued to work on the whole issue of how subroutines are invoked and returned from, and especially how the various perl stacks are manipulated during this time, i.e. all the PUSHBLOCK/PUSHSUB stuff. I also started extending the work to other context types, such as loops.
I have mainly concentrated on removing unnecessary fields from the CXt_SUB context struct, and eliminating the ENTER / SAVE* .... / LEAVE that is normally wrapped around function calls, loops etc, instead storing the old save stack and tmps stack floors and old PL_comppad directly in new fields in the context struct. I've also streamlined the @_ processing and tweaked pp_entersub a lot.
The overall gain is that this code:
bc. sub f {}
f(),f(),f(),f(),f(),f(),f(),f(),f(),f() for 1..5_000_000;
runs in about 2/3 of the previous time,
and this:
bc. sub f { my ($x,$y,$z) = @_; 1 }
f(1,2,3),f(1,2,3),f(1,2,3),f(1,2,3),f(1,2,3),
f(1,2,3),f(1,2,3),f(1,2,3),f(1,2,3),f(1,2,3) for 1..1_000_000;
in about 3/4 of the previous time - i.e. the overhead of calling a subroutine has been substantially reduced.
Timings confirmed with perf and dumbbench, and Porting/bench.pl confirms that instruction reads, data reads and writes, branches, etc, are all reduced by a roughly similar amount.
As well as being faster, it simplifies the code (this branch produces a -O2 object file with about 500 bytes smaller text segment). It also fixes some leaks and crashes caused by dying during stack unwinding.
The second thing I worked on this month was a diversion while working on the PUSHLOOP part of the context stuff. I realised that things could be simplified if it wasn't necessary to save the GPf_ALIASED_SV flag each time, which eventually led me to work on a scheme I first proposed 4 months ago:
"http://nntp.perl.org/group/perl.perl5.porters/226488":http://nntp.perl.org/group/perl.perl5.porters/226488
which makes the 'common-variable' handling code of pp_aassign() (OPpASSIGN_COMMON flag set) more efficient and safe by, amongst other things, using a runtime mark and sweep stage to determine which (if any) RHS SVs need a mortal copy, rather than just blindly copying everything. It's still a work-in-progress, but already for something like ($a,$b) = ($b,$a), it only does one mortal copy rather than two, and is about 10% faster. And it's shown that the basic concept is sound,
The more I've looked into this, the more edge cases I spot. For example, you might think that something as simple as the following can be determined to be safe at compile time, and that it doesn't require any mortal copies made of the RHS:
bc. my ($x,$y) = @a;
Except that you'd be wrong; for example,
bc. f();
my ($x,$y) = @a;
print "($x,$y)\n"; # prints "(2,2)"
bc. sub f {
($x, $y) = (1,2);
use feature 'refaliasing';
\($a[0], $a[1]) = \($y,$x);
}
What with traditional aliasing (*x = ...; for $x (...)), the new refaliasing feature, and lvalue subs, there are many ways to fool OPpASSIGN_COMMON.
The approach I'm taking now is to mark more constructs as needing run-time handling, but to make the runtime checking and/or copying more efficient. In particular there will be three OPp* flags rather than just the one, that can signify whether:
* scalars on the LHS can be checked for safety just by checking that their refcounts are 1;
* there are scalars that need a full mark and sweep test for possible mortal copying;
* there is an aggregate on the LHS which, if non-empty, requires any remaining elements on the RHS to be mortalized to avoid premature freeing.
By splitting the actions required into three flags, it usually makes the run-time penalty much lower. It also allows me to remove the PL_sawalias mechanism, which incurs a small run-time overhead for every pp_gv, pp_gvsv and pp_nextstate.
**Summary**
bq. 52:55 #124156: death during unwinding causes crash
2:20 B::Utils and B::OP::parent
0:30 [perl #125702] Garbage Collection Segv in 5.21.10+
8:20 process p5p mailbox
41:29 re-implement OPpASSIGN_COMMON
**105:34 Total (HH::MM)**
As of 2015/07/31: since the beginning of the grant:
bq. 93.7 weeks
1343.0 total hours
14.3 average hours per week
There are 257 hours left on the grant.
Comments (0)