http://www.perlmonks.org?node_id=708990

fireartist has asked for the wisdom of the Perl Monks concerning the following question:

I've not attempted to use Inline::C since my last flirt, 3 years ago (Inline::C - object accessor failure) and my C knowledge is still almost non-existent.
However, I've got some methods which are called hundreds of thousands of times, and I'm trying to get the runtime down - and I'm hoping someone will offer to translate this particular one into Inline::C for me, so I can see if it makes a difference.
I've tried lots of variations of dealing with the SV** returned by hv_fetch() - but to be honest, I don't have a clue what I'm doing!
Here's the original perl method:
(btw - in the c-code, it would be sufficient to just check exists $self->{parent} rather than defined)

sub root { my $self = shift; while ( defined ( my $parent = $self->{parent} ) ) { $self = $parent; } return $self; }

Replies are listed 'Best First'.
Re: Inline::C hash access
by jettero (Monsignor) on Sep 04, 2008 at 11:55 UTC
    For the method shown here, I doubt it would make much difference, and if it did, it'd probably be to slow it down rather than speed it up. If you're going to write things in C to speed them up, then it helps to have the data in C structures and access it there. Otherwise you might as well just use perl instead of introducing additional access layers.

    Still, I could be wrong since the slowest part of perl is calling a sub. If you called your C function the hundreds of thousands of times from the C code (rather than from perl), it could possibly speed it up.

    UPDATE: also, I've completed my assignment. I hope I get an A on my homework. (In all seriousness, I've never tried Inline::C before. Normally I don't write complete solutions...)

    -Paul

      Thanks for this!

      I initially tried renaming the c function to "form", which is the real name I'm using - but got an error about a previous declaration of Perl_form, so it looks like the functions are being put in a global namespace - however that's not a real problem - I just named it back to "root", then added a *form = \&root and it worked fine.

      I found while trying to run my test suite, that the if( SvOK(sv) && SvTYPE(sv) == SVt_RV ) { } check was failing sometimes - I'm not sure why, so I'll have to investigate further. However, if I comment-out that check, all tests pass ok.

      Running my usual profiling script shows the Inline::C version only runs about 2-3% faster (for total script runtime) - however, I think I'll be able to modify your code to replace a few other often-used methods - so hopefully, eventually, I'll be able to significantly speed up my program. - Thanks once again!

        if( SvOK(sv) && SvTYPE(sv) == SVt_RV )
        That's not what you want - the SvTYPE just says what the SV's body physically consists of, and says nothing about whether it currently contains a valid RV. For example, if you do  $x = "foo"; $x = \$y; then the SvTYPE of $x is actually SVt_PV. You probably want:
        if (SvROK(sv)) ...

        Dave.

        This does seem to be covered in the pod (Inline::C), "If you use C function names that happen to be used internally by Perl, you will get a load error at run time. There is currently no functionality to prevent this or to warn you. For now, a list of Perl's internal symbols is packaged in the Inline module distribution under the filename 'symbols.perl'. Avoid using these in your code."

        Based on that, I'd say there's no work around other than what you did.

        -Paul

Re: Inline::C hash access
by betterworld (Curate) on Sep 04, 2008 at 12:03 UTC

    Have you considered storing the root directly, i.e. as $self->{root}?

    Of course, this will only work if the parents don't change over time.

      Actually storing the $root info into an item is a good idea, you just have to make sure that when the linked list (or whatever the structure is) is changed (eg. add/delete from the middle) the $root information is also updated.
      --
      seek $her, $from, $everywhere if exists $true{love};

      I've looked into this, but unfortunately the parent can change - and this involves a tree of lots of different types of objects - so keeping track of what type of children need updated sounds like a bug waiting to happen ;)

        This sounds like a place where a doubly-linked list could do the job. Each node knows the previous and the next node, thus you can easily descend/ascend the list whenever you need.
        --
        seek $her, $from, $everywhere if exists $true{love};