At 07:05 PM 9/3/2001 -0700, Brent Dax wrote:
># From: Dan Sugalski [mailto:[EMAIL PROTECTED]]
># At 05:30 PM 9/3/2001 -0700, Brent Dax wrote:
># >As far as expensiveness, I think this can be just as fast as
># our current
># >offset-into-the-pad method.
>#
># I was speaking in both speed and memory use when I was talking about
># expense. We'd need to maintain a hash structure for each pad,
># plus we'd
># need to either design the hash structure such that it didn't
># need absolute
># addresses (so we could build it at compile time, which could
># be a long time
># before runtime with a disk freeze or two and an FTP in the
># interim), or
># we'd need to patch the addresses up at runtime when we
># allocated a new pad.
>
>I assume we're willing to have more fixup time for runtime performance,
>correct?
Yes. But fixup is a runtime cost, so we need to weigh what the fixup costs
versus the return we get from it.
> Then consider this:
>
>array-of-array pad:
> curpad => a pointer to the current pad; same as in Perl 5
> offs => an offset into the current pad, representing a variable
>
> Accessing the address of the variable:
> curpad[offs]
>
>stash pad:
> hvaddr => the address of an HE, representing a variable
>
> Accessing the address of the variable:
> hvaddr->value
>
>Is either of these likely to be faster than the other? (Although I'm
>not an assembler hacker, I can't see the first being faster than the
>second.) If so, does the possible speed benefit outweigh any increased
>startup overhead?
Yes, and it's not just startup overhead.
At runtime, whenever we enter a scope we need to allocate a new pad. Every
time. (Well, OK, we can cache the last one we allocated in case we're not
entering recursively, but that's an optimization hack and ignorable in this
case) All the variables we might access need to be created and allocated
and suchlike stuff. Additionally the pad structure itself needs to be created.
Now, there's nothing we can do to skip variable creation. That's a fixed
cost. Pad creation, on the other hand...
If a pad is just an array of:
struct pad_entry {
perl_string *name;
IV type;
PMC *contents;
}
with maybe some other stuff thrown in, we can prebuild the whole pad, stick
it in the fixup section, and do a quick allocate/memcpy when we enter the
block. (The name is a pointer to a constant string, so copying it is safe)
On the other hand, if the pad is a hash, there's no way around having
pointers in it. Which means that allocating a new pad means both copying
and fixing up the template pad. Plus the pad is bigger, since we need to
keep the hash structure in there.
So going with the array-of-hashes means we have more data to allocate, more
data to copy, and more data to fix up, all of which make scope entry
slower. The only time we'd actually *access* the data by name is if we're
looking things up via MY in some way. (read or write) That, I expect, is
going to be a rather rare situation, in which case I can't see the extra
cost on each scope entry being worth it. Could be wrong, of course, but I'm
not seeing the win here.
># I'm not convinced the memory usage, and corresponding time to
># clone and/or
># set up the hash-based pad, is worth the relatively infrequent by-name
># access to variables in the pad. I could be wrong, though.
># We'll have to try
># it and see. (Shouldn't affect the bytecode, however, so we can try
># different methods and benchmark them as need be)
>
>By using something similar to temp() (where the SV* is temporarily
>replaced), cloning should only be necessary for situations in which two
>threads are running the same function at the same time.
Nope, I'm talking about recursion. When you do:
sub foo {
foo();
}
we need to clone foo's pad from the template, because we need a new one.
Otherwise that whole lexical variable/recursion thing doesn't work, which
is A Bad Thing. :)
Dan
--------------------------------------"it's like this"-------------------
Dan Sugalski even samurai
[EMAIL PROTECTED] have teddy bears and even
teddy bears get drunk