gcl-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Gcl-devel] Re: A ha


From: Camm Maguire
Subject: [Gcl-devel] Re: A ha
Date: 02 Nov 2005 19:14:21 -0500
User-agent: Gnus/5.09 (Gnus v5.9.0) Emacs/21.2

Greetings!

Robert Boyer <address@hidden> writes:

> I think I am finally starting to get it.
> 
> If the value that the child wishes to return to the parent is not on the
> stack and if all the storage allocation of the child has been done on the
> stack, then the value in question must have been a valid pointer to an object
> back in the parent.  So far so good.
> 
> But meanwhile the parent has been running.  Maybe the parent gave up all its
> pointers to the value in question and it got garbage collected or, even
> worse, allocated as something new.  It seems there needs to be knowledge of
> which objects are being passed to the child and a holding on to them in the
> parent, for gc purposes, until the child returns.
> 

Yes there is an issue here when using the lower level interface
(si::fork, si::background, si::with-read-values) which I do not think
we can protect against.  If we can, we should, but I don't see how at
the moment.  

I've been mentally targeting the higher level interface (si::p-let,
si::p-and, and si::p-or) as these have ready analogs in well-defined
lisp.  When one writes

(let ((a (foo)) (b (bar)))
        (baz a b))

there is nothing that can be done in baz to affect the operation of
foo and bar, i.e. the memory image waits for the (possibly parallel)
execution of foo and bar, and then proceeds to execute baz.  If foo
and bar are purely functional then (as implied by the use of let as
opposed to let*), there is nothing that can happen in the memory image
to lose existing references to values that may be returned by foo and
bar.  Likewise in p-let, the parent does nothing at all until both foo
and bar complete in separate children and return their values.  One
could have alternatively had the parent only fork one child to do bar
while it did foo, but then the issue you refer to would be possible.
Similarly with p-and and p-or, the parent memory image is completely
quiet while the children are running.

If one choses to use the lower level interface, one could always do

(defvar *a* '(1 2))
(setq x (si::background (progn (sleep 30) *a*)))
(setq *a* '(3 4))
(si::gbc t)
(sleep 30)
(read (cdr x))

and get a nasty surprise.  One could try to parse the backgrounded
form, but it could always be an opaque function.

One could argue that all communication should proceed via a print/read
for this reason, but then the logic of programs might be effected, as
eq relationships are *never* maintained.  In other words, in addition
to benefits relating to memory management, there is a program
correctness argument for allowing children to return pointers IMHO.

To this end, might note in passing that if when we do print/read, and
we do so in fasd format, then shared internal structure will be
preserved in the result returned to the parent.

Here are a few more examples on the effect on latency of the new
strategy: 

=============================================================================
(defun bar nil (si::p-let ((a (fib 19)) (b (fib 19))) (values a b)))

BAR

>(compile 'bar)

;; Compiling ./gazonk19.lsp.
;; End of Pass 1.  
;; End of Pass 2.  
;; OPTIMIZE levels: Safety=0 (No runtime error checking), Space=0, Speed=3, 
(Debug quality ignored)
;; Finished compiling ./gazonk19.o.
Loading /fix/t1/camm/debian/gcl/tmp/tmp/foo/unixport/gazonk19.o
start address -T 0x12663f8 Finished loading 
/fix/t1/camm/debian/gcl/tmp/tmp/foo/unixport/gazonk19.o
#<compiled-function BAR>
NIL
NIL

>(let ((si::*child-stack-alloc* 0)) (time (dotimes (i 10) (bar))))

real time       :      0.130 secs
run-gbc time    :      0.000 secs
child run time  :      0.000 secs
gbc time        :      0.000 secs
NIL

>(let ((si::*child-stack-alloc* 1)) (time (dotimes (i 10) (bar))))

real time       :      0.100 secs
run-gbc time    :      0.000 secs
child run time  :      0.000 secs
gbc time        :      0.000 secs
NIL

>(defvar *a*)

*A*

>(setq *a* (loop for i below 500 collect (random 99)) x nil)

NIL

>(defun bar1 nil (si::p-let ((a (member 38 *a*)) (b (member 52 *a*))) (values a 
>b)))

BAR1

>(compile 'bar1)

;; Compiling ./gazonk19.lsp.
;; End of Pass 1.  
;; End of Pass 2.  
;; OPTIMIZE levels: Safety=0 (No runtime error checking), Space=0, Speed=3, 
(Debug quality ignored)
;; Finished compiling ./gazonk19.o.
Loading /fix/t1/camm/debian/gcl/tmp/tmp/foo/unixport/gazonk19.o
start address -T 0x1196fd0 Finished loading 
/fix/t1/camm/debian/gcl/tmp/tmp/foo/unixport/gazonk19.o
#<compiled-function BAR1>
NIL
NIL

>(let ((si::*child-stack-alloc* 0)) (time (dotimes (i 10) (bar1))))

real time       :      0.050 secs
run-gbc time    :      0.040 secs
child run time  :      0.000 secs
gbc time        :      0.000 secs
NIL

>(let ((si::*child-stack-alloc* 1)) (time (dotimes (i 10) (bar1))))

real time       :      0.020 secs
run-gbc time    :      0.000 secs
child run time  :      0.000 secs
gbc time        :      0.000 secs
NIL

>

=============================================================================

I've been testing this successfully thus far.  If committed, I may
need to change the output of fork a little.  Instead of an id and a
stream, it appears better to return an id and a fixnum representing
the pipe, and then use the special functions
si::write-pointer-object/si::read-pointer-object to get the data
either directly or through prin1/read.  It also avoids the overhead of
the stream creation unless needed, which is unfortunately quite
expensive at present.

Take care,
        

> Utterly ingenious.  I'm not sure I see it entirely clearly, but I see some of
> it.
> 
> Thanks,
> 
> Bob
> 
> 
> 
> 
> 
> 

-- 
Camm Maguire                                            address@hidden
==========================================================================
"The earth is but one country, and mankind its citizens."  --  Baha'u'llah




reply via email to

[Prev in Thread] Current Thread [Next in Thread]