Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Trig functions for vtables

7 views
Skip to first unread message

Dan Sugalski

unread,
Sep 22, 2003, 1:45:29 PM9/22/03
to perl6-i...@perl.org
Okay, since it seems reasonable to hang the trig functions off of PMCs,
we'd best get a list of the functions we want. I can think of:

pow
logarithm
square root (yes, I know, it's for speed)

Normal and hyperbolic versions of:
sine
cosine
tangent
cotangent
arcsine
arccosine
arctangent
arccotangent

There are, I'm sure, others. The base version of these, which all classes
will share unless overridden, will just get the double value of the PMC in
question and perform the operation on that, so we only have to do this
once by default, but classes can override it if they really, really want
to.

Dan

Brent Dax

unread,
Sep 22, 2003, 5:41:29 PM9/22/03
to perl6-i...@perl.org
(Forgot to send this to the list. Again. *sighs*)

Dan Sugalski:
# Okay, since it seems reasonable to hang the trig functions off of
PMCs,
# we'd best get a list of the functions we want. I can think of:
#
# pow
# logarithm
# square root (yes, I know, it's for speed)
#
# Normal and hyperbolic versions of:
# sine
# cosine
# tangent
# cotangent
# arcsine
# arccosine
# arctangent
# arccotangent

Okay, reality check. How often are we going to use acosh? Is it really
worth the space in the vtable for that few calls? And why can't we just
use find_method?

Basically, where do you draw the line between a vtable method and a
find_method method? Unless the line is "methods that everything should
support", I'd say it's been crossed when you add acosh to the vtable.
And if that *is* where the line is, don't be surprised when vtables
cross the megabyte line.

I'm really starting to wonder: why do we have only one type of vtable?
Why are Closures, Pointers, and Scratchpads forced to implement acosh,
splice, pop, or even get_float? And why are PerlInts forced to
implement invoke and can_keyed?

Vtable.tbl already divides vtables into sections. I suggest we take
this a step further and express these sections in the vtables itself.
Sections that a particular object didn't need would be loaded with a
default, in which all of the methods would throw an exception.

The result would mean that something like:
pmc->vtable->add

Might become:
pmc->vtable->math->add

And:
pmc->vtable->add_keyed

Might become:
pmc->vtable->keyed->math->add

This would make it easier to implement non-keyed objects, and the extra
dereference would be lost in the overhead of dealing with keys and
aggregates anyway.

Best of all, if a PMC class doesn't need math calls, it can simply put
this in its vtable definition, in place of the curlies delimiting the
set of math calls:

&Parrot_pmc_default_math_vtable

--Brent Dax <br...@brentdax.com>
Perl and Parrot hacker

"Yeah, and my underwear is flame-retardant--that doesn't mean I'm gonna
set myself on fire to prove it."

Luke Palmer

unread,
Sep 22, 2003, 6:08:24 PM9/22/03
to Brent Dax, perl6-i...@perl.org
Brent Dax writes:
> Dan Sugalski:
> # Okay, since it seems reasonable to hang the trig functions off of
> PMCs,
> # we'd best get a list of the functions we want. I can think of:
> #
> # pow
> # logarithm
> # square root (yes, I know, it's for speed)
> #
> # Normal and hyperbolic versions of:
> # sine
> # cosine
> # tangent
> # cotangent
> # arcsine
> # arccosine
> # arctangent
> # arccotangent
>
> Okay, reality check. How often are we going to use acosh? Is it really
> worth the space in the vtable for that few calls? And why can't we just
> use find_method?

And let's not forget our handy trig identities. We definitely don't
need all those vtable. Technically, all we need are sine and arccosine.
I think putting in cosine, arcsine, and [arc]?tangent would be nice,
too. Cotangent is easy, and is so infrequently used that it's kind of
silly to include. And hyperbolics are very infrequently used, and can
be implemented in terms of exp, which in turn can be implemented in
terms of pow, but shouldn't.

> Basically, where do you draw the line between a vtable method and a
> find_method method? Unless the line is "methods that everything should
> support", I'd say it's been crossed when you add acosh to the vtable.
> And if that *is* where the line is, don't be surprised when vtables
> cross the megabyte line.

But that's not even the line. There are a lot of methods in there which
a lot of classes don't support. Now that we have find_method, it might
be a good idea to define our critera for vtable functions, and then
prune the vtable accordingly. Maybe.

> I'm really starting to wonder: why do we have only one type of vtable?
> Why are Closures, Pointers, and Scratchpads forced to implement acosh,
> splice, pop, or even get_float? And why are PerlInts forced to
> implement invoke and can_keyed?
>
> Vtable.tbl already divides vtables into sections. I suggest we take
> this a step further and express these sections in the vtables itself.
> Sections that a particular object didn't need would be loaded with a
> default, in which all of the methods would throw an exception.
>
> The result would mean that something like:
> pmc->vtable->add
>
> Might become:
> pmc->vtable->math->add
>
> And:
> pmc->vtable->add_keyed
>
> Might become:
> pmc->vtable->keyed->math->add
>
> This would make it easier to implement non-keyed objects, and the extra
> dereference would be lost in the overhead of dealing with keys and
> aggregates anyway.
>
> Best of all, if a PMC class doesn't need math calls, it can simply put
> this in its vtable definition, in place of the curlies delimiting the
> set of math calls:
>
> &Parrot_pmc_default_math_vtable

Hmm.

I think that's a pretty good idea. Of course, the indirections cost,
but we have to give space part of the tradeoff somewhere.

On another, related, but not too related, note...

That is to say,

<rant>

When I went and tried to implement the Infinity pmc, I ran into a lot of
problems. I just wanted a value that could be put into a perlscalar
that could act like an infinitely large (or small) integer. I ended up
copying tons of code from PerlInt, etc. just to get the polymorphism to
work (for some reason putting it all up into perlscalar died big-time).

As far as the var/value split, we need something to support that.
'fetch' and 'store' would be really nice, as sort-of unkeyed variants of
get_pmc_keyed. If something like this already exists, some ops to
actually manipulate it would be nice. Then one could implement Infinity
(or even PerlNum) as a non-polymorphic object, and let PerlScalar handle
the polymorphism. Which, as far as adding new typed, I think would be a
Very Good Thing.

</rant>

Luke

Gregor N. Purdy

unread,
Sep 22, 2003, 11:50:01 PM9/22/03
to Luke Palmer, Brent Dax, perl6-i...@perl.org
On a related note, I wonder how all this fits in with
methods and multimethods?

If we consider the current trig.ops as being equivalent
to, e.g. (expressed with approximate Perl 6 isms):

multi sub sin(Num $arg) : returns Num;
multi sub cos(Num $arg) : returns Num;


<ASIDE>

And, at some level I do think some of the more primitive
Perl 6 builtins should be expressed in a Perl syntax that
indicates "this is an op, go to it!" (like I implemented
in Jako. For example, the file 'string.jako' has guts
that look like this:

module string
{
sub concat :op (str dest, str s);
sub int index :op (str input, str pattern, int start);
sub int length :op (str dest);
sub str substr :op (str s, int i, int l);
}

(if the sub name != the op name, then you can use :op='foo')

This ends up corresponding nicely to related syntax for
NCI. For example, here is Curses.jako:

module Curses
:fnlib = "libcurses.so"
{
sub int initscr :fn ();
sub int endwin :fn ();
sub int curs_set :fn (int x);

sub int addstr :fn (str s);
sub int refresh :fn ();
sub int move :fn (int x, int y);

sub int getch :fn ();
sub int box :fn (int screen, int v, int h);
sub int hline :fn (int ch, int n);
}
(if the func name != the sub name, then you can use :fn='bar')

</ASIDE>


Now, along comes the Perl6Scalar PMC, which implements

multi sub sin(Perl6Scalar $arg) : returns Perl6Scalar;
multi sub cos(Perl6Scalar $arg) : returns Perl6Scalar;

In short, it would be nice if

PMC == Class with opaque implementation

(in our case its a C implementation, but I suppose as
soon as someone implements a class in Python and another
person uses it in Perl, its opaque in Perl). Hmm...
"Opaque" smells kind of like "closed", although maybe not
exactly.

Now, along comes some new class that doesn't implement its
own sin(), etc. What should happen? Well, if it is known to
be convertible without loss of information to something that
does have sin(), etc. then things should just work. If they
don't work fast enough, then someone can go to the trouble
to implement the appropriat multi sub in C. As long as we
never implicitly apply a lossy conversion, things should work
fine.

The deeper into the internals we can carry off the similarity
while still being Fast as All Get Out (TM), the better.


Regards,

-- Gregor

--
Gregor Purdy gre...@focusresearch.com
Focus Research, Inc. http://www.focusresearch.com/

Leopold Toetsch

unread,
Sep 23, 2003, 4:08:19 AM9/23/03
to Brent Dax, perl6-i...@perl.org
Brent Dax <br...@brentdax.com> wrote:

> Okay, reality check. How often are we going to use acosh? Is it really
> worth the space in the vtable for that few calls? And why can't we just
> use find_method?

Dan was talking about one vtable slot, holding another vtable for trig
and log functions. The newly added vtable->data seems to be that. This
trig_log (or data) pointer is shared by all scalar classes. So that
takes one additional pointer per vtable and one additional trig_vtable.

WRT methods: I did propose a scheme, to implement trig and log methods
via find_method, even with a rather low overhead of one *Array* lookup.
Doing an hash lookup still suffers badly as shown in the constant
key/string discussion, but would be possible too - if needed.

> I'm really starting to wonder: why do we have only one type of vtable?
> Why are Closures, Pointers, and Scratchpads forced to implement acosh,

they won't.

> Vtable.tbl already divides vtables into sections. I suggest we take
> this a step further and express these sections in the vtables itself.
> Sections that a particular object didn't need would be loaded with a
> default, in which all of the methods would throw an exception.

That's what happening anyway. All unimplemented stuff has a default hook
throwing an exception.

> The result would mean that something like:
> pmc->vtable->add

> Might become:
> pmc->vtable->math->add

Seems too expensive to me for the normal math stuff.

> And:
> pmc->vtable->add_keyed

Forget add_keyed ;-)

> --Brent Dax <br...@brentdax.com>
> Perl and Parrot hacker

leo

Nicholas Clark

unread,
Sep 23, 2003, 7:32:50 AM9/23/03
to Luke Palmer, Brent Dax, perl6-i...@perl.org
On Mon, Sep 22, 2003 at 04:08:24PM -0600, Luke Palmer wrote:

> And let's not forget our handy trig identities. We definitely don't
> need all those vtable. Technically, all we need are sine and arccosine.

I believe that atan2() is more useful than arccosine, as it returns
information about which quadrant the angle is in
(to save you working it out)

Er, but this doesn't really add to the informed debate.
[except that maybe Dan should be suggesting atan2() rather than arctangent]

Nicholas Clark

Dan Sugalski

unread,
Sep 23, 2003, 8:14:24 AM9/23/03
to Gregor N. Purdy, Luke Palmer, Brent Dax, perl6-i...@perl.org
On Mon, 22 Sep 2003, Gregor N. Purdy wrote:

> On a related note, I wonder how all this fits in with
> methods and multimethods?

One-arg vtable methods don't have to do multimethod stuff, since you're
calling the vtable method on the argument, so it can do the right thing
without checking.

Two arg vtable methods get less pleasant. I've some code that should go in
soon to start the multimethod dispatching in as fast and space-efficient
way as I know how.

Dan

Brent Dax

unread,
Sep 23, 2003, 11:20:49 AM9/23/03
to l...@toetsch.at, perl6-i...@perl.org
Leopold Toetsch:
# Dan was talking about one vtable slot, holding another vtable for trig
# and log functions. The newly added vtable->data seems to be that. This
# trig_log (or data) pointer is shared by all scalar classes. So that
# takes one additional pointer per vtable and one additional
trig_vtable.

I didn't catch this bit before.

# > Vtable.tbl already divides vtables into sections. I suggest we take
# > this a step further and express these sections in the vtables
itself.
# > Sections that a particular object didn't need would be loaded with a
# > default, in which all of the methods would throw an exception.
#
# That's what happening anyway. All unimplemented stuff has a default
hook
# throwing an exception.

The indirection would allow for a default set. It's the difference
between eight default pointers per vtable (to default sections) and
eighty default pointers (to default implementations). If there are a
lot of PMCs that use several sections of defaults (and this seems to be
the case), it's a win spacewise.

# > The result would mean that something like:
# > pmc->vtable->add
#
# > Might become:
# > pmc->vtable->math->add
#
# Seems too expensive to me for the normal math stuff.

Perhaps, although one dereference doesn't seem to painful to me.

Since we are doing trig in another section--I didn't catch that
before--it seems that this'll be okay. However, I do encourage everyone
to consider whether we should only be putting trig in separate tables,
or if we should be putting other methods too, as I've proposed.

--Brent Dax <br...@brentdax.com>
Perl and Parrot hacker

Dan Sugalski

unread,
Sep 23, 2003, 11:37:24 AM9/23/03
to Brent Dax, l...@toetsch.at, perl6-i...@perl.org
On Tue, 23 Sep 2003, Brent Dax wrote:

> Leopold Toetsch:


> # That's what happening anyway. All unimplemented stuff has a default
> hook
> # throwing an exception.
>
> The indirection would allow for a default set. It's the difference
> between eight default pointers per vtable (to default sections) and
> eighty default pointers (to default implementations). If there are a
> lot of PMCs that use several sections of defaults (and this seems to be
> the case), it's a win spacewise.

Each indirection potentially blows the processor pipeline, which costs up
to 15 cycles depending on the processor. It's not normally that bad, more
like 5-7 cycles, but still, it's the equivalent of a fault to main memory.

I'm comfortable burning the memory for now. We can revisit this later if
it turns out to be a real problem, but until then things stay the way they
are.

Dan

Dave Whipp

unread,
Sep 23, 2003, 11:44:18 AM9/23/03
to perl6-i...@perl.org
"Brent Dax" <br...@brentdax.com> wrote:
> # > The result would mean that something like:
> # > pmc->vtable->add
> #
> # > Might become:
> # > pmc->vtable->math->add
> #
> # Seems too expensive to me for the normal math stuff.
>
> Perhaps, although one dereference doesn't seem to painful to me.

Is there any reason we can't do both? Many cpu architectures have variable
length instructions (aka extension opcodes), why couldn't we have:

pmc->vtable->add
pmc->vtable->extensions.trig->cosine

This way we get both fast core ops, and lesser ops with one extra
indirection

Dave.


0 new messages