lucy-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Marvin Humphrey <mar...@rectangular.com>
Subject Re: [lucy-dev] Have Clownfish::Obj extend Perl SV
Date Fri, 12 Apr 2013 23:50:22 GMT
On Fri, Apr 12, 2013 at 6:07 AM, Nick Wellnhofer <wellnhofer@aevum.de> wrote:
> OK, I started to implement this optimization and I noticed that there are
> some places where refcounts are initialized in the 'core' code.

Yeah.  RawPosting, for one.  There used to be more.

> I think we should either use VTable#Init_Obj instead or move these functions
> to the host language code. My plan is to move VTable#Make_Obj and
> VTable#Init_Obj and convert the rest to use VTable#Init_Obj.

+1

The new scheme is not compatible with what I have planned for the Python
bindings (sharing the refcount).  We'll need to avoid direct manipulation of
refcounts within the core.

>>> If we allocate a Perl object then, I'd create the RV pointing to the inner
>>> object right away, store it in host_obj, and use it for refcounting. This
>>> saves a bit of memory and cycles if a Clownfish object is converted to a
>>> Perl object multiple times. Then we could also use sv_bless directly which
>>> is a bit slower than the code in S_lazy_init_host_obj but more
>>> forward-compatible (PL_sv_objcount will be deprecated in Perl 5.18, for
>>> example).
>>
>> So let me see if I understand correctly.  If we store that RV, can we
>> incref it and pass it into Perl-space an arbitrary number of times?  If so,
>> then it seems worthwhile to accept the extra RAM cost of caching the RV in
>> addition to the inner object SV.
>
> For some reason, I initially thought this could save RAM. But you're right,
> it's actually a memory/speed trade-off. I think it should work, but now I'm
> not sure whether it's worth the additional memory cost.

The most important invariant will be preserved no matter which option we
choose:

*   If the host language's object destruction mechanism is ever invoked, it
    must happen only once and at the true end of the Clownfish object's
    lifetime.  This behavior is what enables the crucial feature of adding
    member variables to host-space subclasses which persist for the lifetime
    of the Clownfish object.

A more straightforward technique would be to create a host object wrapper
every time the Clownfish object is passed back into the host, incrementing the
Clownfish refcount once for each host wrapper and decrementing it each time a
host wrapper is freed.  (SWISH3 and Ferret both use this approach.)  However,
allowing multiple host objects for a single Clownfish object is incompatible
with adding member vars to host subclasses, because those member vars are
associated with a host wrapper which may not live as long as the Clownfish
object it wraps.

In contrast, the decision to cache the RV or not is only an implementation
detail.  When Perl-space method implementations are trivial there is a
possibility that inner loops which invoke those methods could be sped up.

    package MyMatcher;
    use base qw( Lucy::Search::Matcher );

    sub score {0}   # <--- trivial method implementation

My suspicion, though, is that the cost of obtaining the RV will not matter
very often.

*   This only matters for inner loops in C space which call back into Perl
    (because they invoke methods on an instance of a host subclass for which a
    method has been overridden).
*   Obtaining an RV is reasonably cheap, because as you point out, Perl's
    arena allocator for SV heads is highly optimized.
*   If the method takes any arguments, the cost of preparing and parsing
    them will tend to swamp the cost of the obtaining the RV.
*   If the host implementation is non-trivial, the cost of obtaining the RV
    will be swamped.
*   No matter what, a loop which calls back into the host is going to be
    considerably slower than optimized C code.

So, while I don't think the memory cost of caching an extra SV head matters
too much, I'd come down slightly on the side of leaving things as they are now
where we cache only the inner object.  Reasonable people may disagree.
Especially if they go to the trouble of running some benchmarks.  :)

Marvin Humphrey

Mime
View raw message