Login | Register For Free | Help
Search for: (Advanced)

Mailing List Archive: Perl: porters

optimise by not Copy()ing @_ ?

 

 

Perl porters RSS feed   Index | Next | Previous | View Threaded


nick at ccl4

Aug 16, 2012, 9:03 AM

Post #1 of 11 (265 views)
Permalink
optimise by not Copy()ing @_ ?

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
Attachments: instrumentation (2.31 KB)


xdaveg at gmail

Aug 16, 2012, 12:02 PM

Post #2 of 11 (261 views)
Permalink
Re: optimise by not Copy()ing @_ ? [In reply to]

On Thu, Aug 16, 2012 at 12:03 PM, Nicholas Clark <nick [at] ccl4> wrote:
>
> So, is this a crazy idea to investigate further? What did I miss? - ie
> what could possibly go wrong?

Changing the size of @_ within a sub would also need to trigger a copy.

-- David


sprout at cpan

Aug 16, 2012, 12:44 PM

Post #3 of 11 (261 views)
Permalink
Re: optimise by not Copy()ing @_ ? [In reply to]

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

Make sure the stack base is placed beyond the end of @_ for the sub-
routine. Otherwise the first nextstate will wipe out the arguments.
But the stack will have to be reallocated more often, so it might not
be a big savings after all.

Simply flagging the AV as being a "stacked" AV with a stack offset
instead of a pointer stored in xav_alloc would be the simplest
approach to dealing with stack reallocations.

> Is anyone else interested in exploring this?

Not now. File an RT ticket. :-)


nick at ccl4

Aug 17, 2012, 5:49 AM

Post #4 of 11 (257 views)
Permalink
Re: optimise by not Copy()ing @_ ? [In reply to]

On Thu, Aug 16, 2012 at 03:02:18PM -0400, David Golden wrote:
> On Thu, Aug 16, 2012 at 12:03 PM, Nicholas Clark <nick [at] ccl4> wrote:
> >
> > So, is this a crazy idea to investigate further? What did I miss? - ie
> > what could possibly go wrong?
>
> Changing the size of @_ within a sub would also need to trigger a copy.

That's already caught by AvREIFY() being true on @_:

$ gdb --args ./perl -e 'sub foo {push @_, 1} foo'
GNU gdb (GDB) 7.0.1-debian
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/nick/Perl/perl/perl...done.
(gdb) b Perl_av_reify
Breakpoint 1 at 0x595278: file av.c, line 32.
(gdb) r
Starting program: /home/nick/Perl/perl/perl -e sub\ foo\ \{push\ @_,\ 1\}\ foo
[Thread debugging using libthread_db enabled]

Breakpoint 1, Perl_av_reify (my_perl=0xa25010, av=0xa46498) at av.c:32
32 PERL_ARGS_ASSERT_AV_REIFY;
(gdb) where
#0 Perl_av_reify (my_perl=0xa25010, av=0xa46498) at av.c:32
#1 0x000000000059822d in Perl_av_store (my_perl=0xa25010, av=0xa46498, key=0,
val=0xa27ca0) at av.c:352
#2 0x000000000064591c in Perl_pp_push (my_perl=0xa25010) at pp.c:5049
#3 0x000000000054319d in Perl_runops_debug (my_perl=0xa25010) at dump.c:2126
#4 0x000000000045a661 in S_run_body (my_perl=0xa25010, oldscope=1)
at perl.c:2388
#5 0x0000000000459732 in perl_run (my_perl=0xa25010) at perl.c:2305
#6 0x000000000041de4d in main (argc=3, argv=0x7fffffffea98,
env=0x7fffffffeab8) at perlmain.c:114
(gdb) up
#1 0x000000000059822d in Perl_av_store (my_perl=0xa25010, av=0xa46498, key=0,
val=0xa27ca0) at av.c:352
352 av_reify(av);
(gdb) call Perl_sv_dump(my_perl, av)
SV = PVAV(0xa29c98) at 0xa46498
REFCNT = 2
FLAGS = ()
ARRAY = 0x0
FILL = -1
MAX = -1
ARYLEN = 0x0
FLAGS = (REIFY)
(gdb) call Perl_sv_dump(my_perl, val)
SV = IV(0xa27c90) at 0xa27ca0
REFCNT = 1
FLAGS = (IOK,pIOK)
IV = 1


I think that all the manipulations of @_ that matter are already trapped and
end up in Perl_av_reify. (Those that extend it, or manipulate it in place)

Nicholas Clark


nick at ccl4

Aug 17, 2012, 5:54 AM

Post #5 of 11 (257 views)
Permalink
Re: optimise by not Copy()ing @_ ? [In reply to]

On Thu, Aug 16, 2012 at 07:44:13PM -0000, Father Chrysostomos wrote:
> Nicholas Clark asked:
> > So, is this a crazy idea to investigate further? What did I miss? - ie
> > what could possibly go wrong?
>
> Make sure the stack base is placed beyond the end of @_ for the sub-
> routine. Otherwise the first nextstate will wipe out the arguments.

Good point.

> But the stack will have to be reallocated more often, so it might not
> be a big savings after all.

Yes, but I assumed that the stack would stabilise on a new (slightly larger)
size. If that's wrong, you're right, it's not worth it.

> Simply flagging the AV as being a "stacked" AV with a stack offset
> instead of a pointer stored in xav_alloc would be the simplest
> approach to dealing with stack reallocations.

True. But that then means that code which assumes that it can directly
read AvARRAY(av)[0] etc will break. Having AvARRAY() point into the stack
preserves the illusion. Then again, is there any way for @_ to reach XS
code with AvREIFY() still true? Taking a reference to @_ calls Perl_av_reify.
Short of XS code directly using get_av("_"), is there any way for XS code
to get at it?

Nicholas Clark


pagaltzis at gmx

Aug 17, 2012, 1:42 PM

Post #6 of 11 (257 views)
Permalink
Re: optimise by not Copy()ing @_ ? [In reply to]

* Nicholas Clark <nick [at] ccl4> [2012-08-17 14:50]:
> I think that all the manipulations of @_ that matter are already
> trapped and end up in Perl_av_reify. (Those that extend it, or
> manipulate it in place)

Does that include `my $self = shift;`?


dcmertens.perl at gmail

Aug 17, 2012, 7:28 PM

Post #7 of 11 (259 views)
Permalink
Re: optimise by not Copy()ing @_ ? [In reply to]

I have not looked at the C code, but I believe the answer is "no".

Camel4 Chapter 27 (Functions) says this about caller on page 832: "A side
effect of the current implementation is that the effects of only C<shift
@_> can be undone (but not C<pop> or C<splice>),..." That is in the context
of C<@DB::args>, so may not apply. But it is corroborated with what
Extending and Embedding Perl has to say about ARRAY and ALLOC (section 4.4).

That is my best guess. :-)

David
On Aug 17, 2012 3:42 PM, "Aristotle Pagaltzis" <pagaltzis [at] gmx> wrote:

> * Nicholas Clark <nick [at] ccl4> [2012-08-17 14:50]:
> > I think that all the manipulations of @_ that matter are already
> > trapped and end up in Perl_av_reify. (Those that extend it, or
> > manipulate it in place)
>
> Does that include `my $self = shift;`?
>


davem at iabyn

Aug 18, 2012, 4:01 AM

Post #8 of 11 (260 views)
Permalink
Re: optimise by not Copy()ing @_ ? [In reply to]

On Fri, Aug 17, 2012 at 10:42:38PM +0200, Aristotle Pagaltzis wrote:
> * Nicholas Clark <nick [at] ccl4> [2012-08-17 14:50]:
> > I think that all the manipulations of @_ that matter are already
> > trapped and end up in Perl_av_reify. (Those that extend it, or
> > manipulate it in place)
>
> Does that include `my $self = shift;`?

use Devel::Peek;
sub f {
Dump *_{ARRAY};
my $self = shift;
Dump *_{ARRAY};
}
f(1,2,3);

$ perl5160t /tmp/p 2>&1 | grep REIFY
FLAGS = (REIFY)
FLAGS = (REIFY)
$

So, no.


--
You're only as old as you look.


pagaltzis at gmx

Aug 18, 2012, 9:27 AM

Post #9 of 11 (256 views)
Permalink
Re: optimise by not Copy()ing @_ ? [In reply to]

* Dave Mitchell <davem [at] iabyn> [2012-08-18 13:05]:
> On Fri, Aug 17, 2012 at 10:42:38PM +0200, Aristotle Pagaltzis wrote:
> > * Nicholas Clark <nick [at] ccl4> [2012-08-17 14:50]:
> > > I think that all the manipulations of @_ that matter are already
> > > trapped and end up in Perl_av_reify. (Those that extend it, or
> > > manipulate it in place)
> >
> > Does that include `my $self = shift;`?
>
> use Devel::Peek;
> sub f {
> Dump *_{ARRAY};
> my $self = shift;
> Dump *_{ARRAY};
> }
> f(1,2,3);
>
> $ perl5160t /tmp/p 2>&1 | grep REIFY
> FLAGS = (REIFY)
> FLAGS = (REIFY)
> $
>
> So, no.

Thanks.


sprout at cpan

Aug 19, 2012, 2:27 PM

Post #10 of 11 (258 views)
Permalink
Re: optimise by not Copy()ing @_ ? [In reply to]

On Aug 17, 2012, at 5:54 AM, Nicholas Clark wrote:

> On Thu, Aug 16, 2012 at 07:44:13PM -0000, Father Chrysostomos wrote:
>> Nicholas Clark asked:
>>> So, is this a crazy idea to investigate further? What did I miss? - ie
>>> what could possibly go wrong?
>>
>> Make sure the stack base is placed beyond the end of @_ for the sub-
>> routine. Otherwise the first nextstate will wipe out the arguments.
>
> Good point.
>
>> But the stack will have to be reallocated more often, so it might not
>> be a big savings after all.
>
> Yes, but I assumed that the stack would stabilise on a new (slightly larger)
> size.

What worries me is that any stack reallocation would be more expensive, it being larger, and that could especially have an impact on deeply nested routines that pass thousands of items to each other. I don’t know how common such code is. And I don‘t even know how to begin to benchmark any of this.

> If that's wrong, you're right, it's not worth it.
>
>> Simply flagging the AV as being a "stacked" AV with a stack offset
>> instead of a pointer stored in xav_alloc would be the simplest
>> approach to dealing with stack reallocations.
>
> True. But that then means that code which assumes that it can directly
> read AvARRAY(av)[0] etc will break. Having AvARRAY() point into the stack
> preserves the illusion.

AvARRAY can be re#defined.

> Then again, is there any way for @_ to reach XS
> code with AvREIFY() still true? Taking a reference to @_ calls Perl_av_reify.
> Short of XS code directly using get_av("_"), is there any way for XS code
> to get at it?

GvAV(gv_fetchpvs("_"))

And the return value from gv_fetchpvs("_") can be stored and used later.


davem at iabyn

Aug 20, 2012, 3:11 AM

Post #11 of 11 (248 views)
Permalink
Re: optimise by not Copy()ing @_ ? [In reply to]

On Sun, Aug 19, 2012 at 02:27:45PM -0700, Father Chrysostomos wrote:
> On Aug 17, 2012, at 5:54 AM, Nicholas Clark wrote:
> > Then again, is there any way for @_ to reach XS
> > code with AvREIFY() still true? Taking a reference to @_ calls Perl_av_reify.
> > Short of XS code directly using get_av("_"), is there any way for XS code
> > to get at it?
>
> GvAV(gv_fetchpvs("_"))
>
> And the return value from gv_fetchpvs("_") can be stored and used later.

And also, presumably:

GvAV(PL_defgv)

--
A walk of a thousand miles begins with a single step...
then continues for another 1,999,999 or so.

Perl porters RSS feed   Index | Next | Previous | View Threaded
 
 


Interested in having your list archived? Contact Gossamer Threads
 
  Web Applications & Managed Hosting Powered by Gossamer Threads Inc.