Discussion:
Using a faster version of sv_derived_from?
(too old to reply)
Marvin Humphrey
2006-04-13 15:57:01 UTC
Permalink
There are lots of perl/XS calls, and using the function
sv_derived_from to check that the right type of object was passed
is very slow. Are there any safe alternatives/work arounds? Oh, the
SV is also overloaded:)
There's sv_isa, which should be cheaper than sv_derived_from at the
expense of not testing inheritance relationships. I dunno if the
overload affects impacts the ability to use it.

Moving stuff safely across the Perl/C boundary can be expensive. Can
you change the algorithm so that objects don't have to cross so often?

Marvin Humphrey
Rectangular Research
http://www.rectangular.com/
Jeremy White
2006-04-13 17:42:13 UTC
Permalink
Post by Marvin Humphrey
There's sv_isa, which should be cheaper than sv_derived_from at the
expense of not testing inheritance relationships. I dunno if the overload
affects impacts the ability to use it.
Yeah, it's cheaper - but not cheap enough:) I was playing around with trying
to upgrade the SV, and stuffing data in the free slots, then using those
slots to validate the type. Seemed to work for simple examples, but blew up
when used in the real world - overloading makes things more complicated.
Post by Marvin Humphrey
Moving stuff safely across the Perl/C boundary can be expensive. Can you
change the algorithm so that objects don't have to cross so often?
Not really, as the object is exposed to the end user.

Cheers,

jez.
Marvin Humphrey
2006-04-13 17:58:25 UTC
Permalink
Post by Jeremy White
Post by Marvin Humphrey
There's sv_isa, which should be cheaper than sv_derived_from at
the expense of not testing inheritance relationships. I dunno if
the overload affects impacts the ability to use it.
Yeah, it's cheaper - but not cheap enough:) I was playing around
with trying to upgrade the SV, and stuffing data in the free slots,
then using those slots to validate the type. Seemed to work for
simple examples, but blew up when used in the real world -
overloading makes things more complicated.
Post by Marvin Humphrey
Moving stuff safely across the Perl/C boundary can be expensive.
Can you change the algorithm so that objects don't have to cross
so often?
Not really, as the object is exposed to the end user.
Maybe you could do something insane and heroic, like keep a registry
of pointer addresses that represent qualified objects. Something
like what David Golden does with Class::InsideOut to provide thread
safety. Add each object to the registry when it is created, delete
it when it's DESTROYed. It would require a lot of code, but I'll bet
it would be faster than sv_derived_from. How desperate are you?

Marvin Humphrey
Rectangular Research
http://www.rectangular.com/
Marvin Humphrey
2006-04-13 18:55:46 UTC
Permalink
Post by Marvin Humphrey
Maybe you could do something insane and heroic, like keep a
registry of pointer addresses that represent qualified objects.
Something like what David Golden does with Class::InsideOut to
provide thread safety. Add each object to the registry when it is
created, delete it when it's DESTROYed. It would require a lot of
code, but I'll bet it would be faster than sv_derived_from. How
desperate are you?
Now you've got me thinking, Jeremy.

Right now, KinoSearch isn't thread-safe. However, if I make it so, a
web-spidering app could have separate fetcher threads dealing with
individual http requests and not getting hung up on slow servers.
That's a killer feature... so I'm desperate enough to try something
difficult.

There's no way for me to make all the C-struct based classes in
KinoSearch thread safe without a registry. Some of them have mutex
locking requirements -- you don't want two indexers modifying the
same index at the same time, for instance.

I'm thinking that there ought to be one giant registry structure, a
private variable that springs into being when "use KinoSearch;" is
invoked, that registers ALL KinoSearch related objects across all
threads. What form should this data structure take? A linked list?
A hashtable? Thinking out loud...

typedef struct registration {
SV **ref;
U32 class_id;
SV* (*clone)(SV*);
void (*deregister)(SV*);
struct registration *next;
} Registration;

KinoSearch is designed to use as few objects as possible, so I think
the overhead of creating this registry might be workable --
especially if all the calls to sv_derived_from can be eliminated.

Marvin Humphrey
Rectangular Research
http://www.rectangular.com/
Jeremy White
2006-04-14 09:19:18 UTC
Permalink
Post by Marvin Humphrey
Maybe you could do something insane and heroic, like keep a registry of
pointer addresses that represent qualified objects. Something like what
David Golden does with Class::InsideOut to provide thread safety. Add
each object to the registry when it is created, delete it when it's
DESTROYed. It would require a lot of code, but I'll bet it would be
faster than sv_derived_from. How desperate are you?
After some more playing, I was able to get a 16x speed up by removing the
use of sv_derived_from. The solution isn't "safe" - but works for most
cases. I added a member to the structure which contains a known value - this
can be used to identity the type of pointer. With a few additional checks on
the SV (is it an RV and does it have the correct flags) you can reduce the
case where you'll get a dodgy pointer (and thus a segfault).

Your suggestion of using a registry to keep track of valid pointers is an
interesting idea, as it would solve the above segfault problem.
Post by Marvin Humphrey
Right now, KinoSearch isn't thread-safe. However, if I make it so, a
web-spidering app could have separate fetcher threads dealing with
individual http requests and not getting hung up on slow servers. That's
a killer feature... so I'm desperate enough to try something difficult.
There's no way for me to make all the C-struct based classes in KinoSearch
thread safe without a registry. Some of them have mutex locking
requirements -- you don't want two indexers modifying the same index at
the same time, for instance.
Interesting. The C-stucts in my module have to be thread safe as perl
threads could be accessing them as well as pure C based threads. Access to
the structure is controlled by a standard pthread mutex. Couldn't you use
the same approach?
Post by Marvin Humphrey
I'm thinking that there ought to be one giant registry structure, a
private variable that springs into being when "use KinoSearch;" is
invoked, that registers ALL KinoSearch related objects across all threads.
What form should this data structure take? A linked list? A hashtable?
Thinking out loud...
typedef struct registration {
SV **ref;
U32 class_id;
SV* (*clone)(SV*);
void (*deregister)(SV*);
struct registration *next;
} Registration;
KinoSearch is designed to use as few objects as possible, so I think the
overhead of creating this registry might be workable -- especially if all
the calls to sv_derived_from can be eliminated.
How many objects are you talking about?

Cheers,

jez.
Nick Ing-Simmons
2006-04-18 19:54:37 UTC
Permalink
Post by Marvin Humphrey
Post by Jeremy White
Post by Marvin Humphrey
There's sv_isa, which should be cheaper than sv_derived_from at
the expense of not testing inheritance relationships. I dunno if
the overload affects impacts the ability to use it.
Yeah, it's cheaper - but not cheap enough:) I was playing around
with trying to upgrade the SV, and stuffing data in the free slots,
then using those slots to validate the type. Seemed to work for
simple examples, but blew up when used in the real world -
overloading makes things more complicated.
Post by Marvin Humphrey
Moving stuff safely across the Perl/C boundary can be expensive.
Can you change the algorithm so that objects don't have to cross
so often?
Not really, as the object is exposed to the end user.
Well you can still _allow_ that low level access (with the speed hit)
but provide C-side constructs which "do more".
For example Audio::Data allows user code to get/set individual sample
values but also provides C methods/overload to work on a whole "track"

If you do need speed, there is a trade-off between safety and speed.
In the limit you don't _need_ to check anything at all.
If perl is calling your XS it is because this "is" one of your objects.
Nothing is faster than doing no check at all ;-)

Downside is that if user corrupts the C-side structure,
or "blesses" something else into your class or calls not-as method
you get a segfault or other bad behaviour.

Another approach is to have the C struct (or C++ object)
associated with the perl object via "MAGIC". I think geting the C
pointer via mg_ptr is slightly faster than sv_isa.
Post by Marvin Humphrey
Maybe you could do something insane and heroic, like keep a registry
of pointer addresses that represent qualified objects. Something
like what David Golden does with Class::InsideOut to provide thread
safety. Add each object to the registry when it is created, delete
it when it's DESTROYed. It would require a lot of code, but I'll bet
it would be faster than sv_derived_from. How desperate are you?
But probably akin to sv_isa and subject to same kind of restrictions
Post by Marvin Humphrey
Marvin Humphrey
Rectangular Research
http://www.rectangular.com/
Loading...