develooper Front page | perl.perl5.porters | Postings from August 2012

optimise by not Copy()ing @_ ?

Thread Next
From:
Nicholas Clark
Date:
August 16, 2012 09:03
Subject:
optimise by not Copy()ing @_ ?
Message ID:
20120816160304.GV9834@plum.flirble.org
While chatting with David Golden about subroutine entry, he commented on
Copy(). I thought that we didn't copy things. I'm wrong (and I used to know
this too)

pp_entersub has this:

	    cx->blk_sub.savearray = GvAV(PL_defgv);
	    GvAV(PL_defgv) = MUTABLE_AV(SvREFCNT_inc_simple(av));
	    CX_CURPAD_SAVE(cx->blk_sub);
	    cx->blk_sub.argarray = av;
	    ++MARK;

	    if (items > AvMAX(av) + 1) {
		SV **ary = AvALLOC(av);
		if (AvARRAY(av) != ary) {
		    AvMAX(av) += AvARRAY(av) - AvALLOC(av);
		    AvARRAY(av) = ary;
		}
		if (items > AvMAX(av) + 1) {
		    AvMAX(av) = items - 1;
		    Renew(ary,items,SV*);
		    AvALLOC(av) = ary;
		    AvARRAY(av) = ary;
		}
	    }
	    Copy(MARK,AvARRAY(av),items,SV*);
	    AvFILLp(av) = items - 1;
	
	    while (items--) {
		if (*MARK)
		    SvTEMP_off(*MARK);
		MARK++;
	    }

Specifically, that Copy() copies the block of pointers to SVs (the
subroutine's arguments) from the perl stack into the sub's @_
Note, what does happen which is non-standard is that AvREIFY() is set on @_
which signals that the reference counts on those SVs are not (yet) bumped.
If anything "interesting" happens to the array @_, the reference counts are
bumped [and the flag AvREIFY() replace with the usual AvREAL()]

So I wondered - do we actually need to make that copy?
Would it be feasible to make the AV for @_ point directly at the section of
the caller's stack?

This would actually avoid both the copy, and allocating space to copy to.
AvREFIY() [or something stronger] would still be set, so it should be
possible to adapt av_reify() to allocate some space at the place where it
runs through bumping up reference counts.

The only (big) problem I can see is that it's not the *caller's* stack, it's
everyone's stack. And so activity within the called subroutine can cause the
stack to be extended, which can move it, which would mean duff pointers in
@_ in this case.

But I assume that that can be solved by

a) storing the address of the stack base in the PVAV
b) adapting Perl_stack_grow() to run up the context stack looking for
   subroutines, and for each inspect cx->blk_sub.argarray
   If it's in the current stack, move it if the stack moves


So then the question comes down to cost/benefit. With a bit of
"instrumentation" (attached), I see that a full clean build and testsuite
makes

Calls to Perl_stack_grow:	   14882
(Re)allocations of @_:		  465192
Re-use of existing @_:		93588410
Calls to Perl_av_reify:		   67502

So that's potentially a lot of copies saved.
However, whilst @_ is (re)allocated 31 times more often than Perl_stack_grow
is called [which would seem to be a saving], Perl_av_reify is called about
1/7th of the number of times [which moves the cost somewhere else]


So, is this a crazy idea to investigate further? What did I miss? - ie
what could possibly go wrong?

Is anyone else interested in exploring this?

Nicholas Clark

Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About