[Rd] iterative list rm [Was: R-devel Digest, Vol 83, Issue 2]
Romain Francois
romain.francois at dbmail.com
Sun Jan 3 08:36:52 CET 2010
On 01/03/2010 02:04 AM, Simon Urbanek wrote:
>
>
> On Jan 2, 2010, at 5:41 PM, Romain Francois wrote:
>
>> On 01/02/2010 11:12 PM, Duncan Murdoch wrote:
>>>
>>> On 02/01/2010 3:16 PM, Laurent Gautier wrote:
>>>> On 1/2/10 8:53 PM, Duncan Murdoch wrote:
>>>>> Simon Urbanek wrote:
>>>>>> On Jan 2, 2010, at 12:17 PM, Laurent Gautier wrote:
>>>>>>
>>>>>>> On 1/2/10 5:56 PM, Duncan Murdoch wrote:
>>>>>>>> On 02/01/2010 11:36 AM, Laurent Gautier wrote:
>>>>>>>>> [Disclaimer: what is below reflects my understanding from reading
>>>>>>>>> the
>>>>>>>>> R source, others will correct where deemed necessary]
>>>>>>>>>
>>>>>>>>> On 1/2/10 12:00 PM, r-devel-request at r-project.org wrote:
>>>>>>> (...)
>>>>>>>
>>>>>>>>>> I'd also be interested if there is some ideas on the relative
>>>>>>>>>> efficiency
>>>>>>>>>> of the preserve/release mechanism compared to PROTECT/UNPROTECT.
>>>>>>>>> PROTECT/UNPROTECT is trading granularity for speed. It is a stack
>>>>>>>>> with
>>>>>>>>> only tow operations possible:
>>>>>>>>> - push 1 object into the stack
>>>>>>>>> - pull (unprotect) N last objects from the stack
>>>>>>>> UNPROTECT_PTR is also possible, which does a linear search through
>>>>>>>> the
>>>>>>>> stack and unprotects something possibly deep within it. There is also
>>>>>>>> REPROTECT which allows you to replace an entry within the stack.
>>>>>>>>
>>>>>>>> I would guess that UNPROTECT_PTR is more efficient than
>>>>>>>> RecursiveRelease
>>>>>>>> because it doesn't use so much stack space when it needs to go deep
>>>>>>>> into
>>>>>>>> the stack to release, but it is possible the compiler recognizes the
>>>>>>>> tail recursion and RecursiveRelease is implemented efficiently. In
>>>>>>>> that
>>>>>>>> case it could be more efficient than UNPROTECT_PTR, which has to move
>>>>>>>> all the other entries down to fill the newly vacated space. Really
>>>>>>>> the
>>>>>>>> only reliable way to answer efficiency questions like this is to try
>>>>>>>> both ways and see which works better in your application.
>>>>>>> Thanks. I did not know about UNPROTECT_PTR.
>>>>>>> I had concerns over the stack usage, but so far it did not prove too
>>>>>>> much of a problem. Still, why isn't the tail recursion explicitly
>>>>>>> made an iteration then ? This would take the "may be the compiler
>>>>>>> figures it out, may be not" variable out of the equation.
>>>>>>>
>>>>>> Careful - the protection stack (bookkeeping by R) has nothing to do
>>>>>> with the C function call stack hence it has nothing to do with the
>>>>>> compiler. The protection stack is global so usually you don't run out
>>>>>> of it unless something goes horribly wrong (=infinite loop).
>>>>> I think Laurent was referring to RecursiveRelease, which could use a lot
>>>>> of C stack if you choose to release something that is deep in the list,
>>>>> since it checks the head, and if that doesn't match, calls itself again
>>>>> on the rest of the list. (I checked, and at least one version of gcc
>>>>> doesn't recognize the tail recursion: it really does generate a
>>>>> recursive call.)
>>>>>
>>>>> Laurent asked why it isn't optimized to avoid the recursion: I think the
>>>>> answer is simply because it is so rarely used that nobody has bothered.
>>>>
>>>> Yes, I was referring to RecursiveRelease. Sorry if this was not clear.
>>>>
>>>> What are the chances for a patch to be accepted ? At first sight(*),
>>>> making that tail recursion an iterative function is not a major
>>>> undertaking, and reviewing the patch be fairly straightforward... but
>>>> I can always use that time otherwise if the answer to the question is
>>>> "nil".
>>>
>>> I don't think I would want to review such a patch (I don't know the
>>> memory manager well, I don't know that there is really a case where it
>>> matters enough to be worth doing), so I'd say if you don't get a message
>>> from a core member volunteering to do so, you should assume it won't be
>>> accepted. But that doesn't mean you shouldn't write the code for your
>>> own internal use and edification, and if you can put together a demo
>>> that shows it really makes a big difference in a realistic situation,
>>> you might get a different response.
>>>
>>> Duncan Murdoch
>>
>> From what I understand, this has little to do with the memory manager, and resumes to the simple problem "how to remove an object from a list".
>>
>> Something like this, using the amazing inline and inspect packages:
>>
>> require( inline )
>> require( inspect )
>>
>> remover<- cfunction(signature( list = "language", object = "environment" ), '
>> if( !isNull( list ) ){
>> SEXP x = list ;
>> SEXP y ;
>> while( CAR(x) != object&& CADR(x) != R_NilValue ){
>> y = x ;
>> x = CDR(x) ;
>> }
>> if( CAR(x) == object ) SETCDR(y, CDR(x) ) ;
>> }
>> return list ;
>
> That blows up if the object is the first in the list BTW. You probably meant more something like
>
> static SEXP ReleaseObj(SEXP object, SEXP list) {
> if (!isNull(list)) {
> if (CAR(list) != object) {
> SEXP c = list;
> while (!isNull(CDR(c))) {
> if (CADR(c) == object) {
> CDR(c) = CDDR(c);
> break;
> }
> c = CDR(c);
> }
> } else return CDR(list);
> }
> return list;
> }
>
> (For non-core replace CDR(c) with SETCDR(c) although that goes through the write barrier).
>
> Cheers,
> Simon
Thanks. And sorry for not testing this case. (oops)
Romain
--
Romain Francois
Professional R Enthusiast
+33(0) 6 28 91 30 30
http://romainfrancois.blog.free.fr
|- http://tr.im/IW9B : C++ exceptions at the R level
|- http://tr.im/IlMh : CPP package: exposing C++ objects
`- http://tr.im/HlX9 : new package : bibtex
More information about the R-devel
mailing list