[comp.lang.lisp] GC and time critical code?

mesard@bbn.com (Wayne Mesard) (03/24/88)

I'm working on a spec for a program that needs to take collect reaction
time data (from humans).  The program really wants to be written in Lisp
(as any well conceived program would :-), but I'm not clear about how
garbage collection will interfere with taking time data.  That is, what
if the system is doing GC when the subject "presses the stop button"?

I imagine this problem has been dealt with before.  Is there a way to
prevent this?  (Forcing a GC right before the critical code isn't a
guarantee, but I'm willing to entertain arguments that that's good
enough.)

Any comments would be appreciated.  Please mail to me.  I'll summarize
to the net unless it turns out that this is a naive question.

Thanks.

-- 
unsigned *Wayne_Mesard();                     MESARD@BBN.COM
                                              BBN Labs, Cambridge, MA

Are you absolutely sure that you want to do this? [ny] ummm_

jeff@aiva.ed.ac.uk (Jeff Dalton) (03/29/88)

In article <22550@bbn.COM> mesard@bbn.com writes:
>I'm working on a spec for a program that needs to take collect reaction
>time data (from humans).  The program really wants to be written in Lisp
>(as any well conceived program would :-), but I'm not clear about how
>garbage collection will interfere with taking time data.  That is, what
>if the system is doing GC when the subject "presses the stop button"?

This is a good question, which is probably why it keeps turning up.
There are, basically, three answers:

1. Use a Lisp that has a "nondisruptive" garbage collection strategy.
Some Lisps have garbaage collectors that do a little bit or work
fairly frequently, so that it's like having a slightly slower CONS
rather than long pauses for GC.  Incremental GC, "ephemeral" GC,
and perhaps some other strategies are largely nondisruptive, but
at present tend not to be used in implementations for general-
purpose machines.  It's possible that such techniques are fast enough
to be unnoticable even for your application.  The delays shouldn't
be worse than the paging and scheduling delays one accepts when
running multiple processes.

2. Preallocate enough storage so there is no need to GC.

3. Don't generate any (or very much) garbage.

The latter two techniques can be combined if you use explicit storage
management, with a pool of resources that you allocate and free.

Most Lisp systems give you a fair amount of control over when storage
is allocated.  That is, they try not to allocate storage on their own
but only when you call something like CONS.  But &REST parameters tend
to cause a list allocation, and some interpreters construct
environments when functions are called.  So you get rules like don't
use &REST, compile your code, etc.

Unfortunately, your program will be using numbers to represent
reaction times, and creating a number tends to allocate storage in
most Lisps even though you haven't done an explicit MAKE-NUMBER.
Some types/sizes of numbers may be represented directly (as part of a
pointer) rather than by an allocated object.  If these are suitable
for reaction times, you win.  Otherwise, you may have to preallocate
to make sure there is enough space for the numbers.

Jeff Dalton,                      JANET: J.Dalton@uk.ac.ed             
AI Applications Institute,        ARPA:  J.Dalton%uk.ac.ed@nss.cs.ucl.ac.uk
Edinburgh University.             UUCP:  ...!ukc!ed.ac.uk!J.Dalton

aarons@cvaxa.sussex.ac.uk (Aaron Sloman) (04/16/88)

In response to article <22550@bbn.COM> mesard@bbn.com
Jeff Dalton (jeff@aiva.ed.ac.uk) writes:

>From: jeff@aiva.ed.ac.uk (Jeff Dalton)
>Message-ID: <305@aiva.ed.ac.uk>
>Organization: Dept. of AI, Univ. of Edinburgh, UK

>Unfortunately, your program will be using numbers to represent
>reaction times, and creating a number tends to allocate storage in
>most Lisps even though you haven't done an explicit MAKE-NUMBER.

-----------------
Just for the record. In POPLOG Common Lisp (and also in the other Poplog
languages, namely POP-11, Prolog and ML) storage is NOT allocated for
integers or single-precision floating point numbers that can fit into 30
bits of store.

POPLOG divides data objects into two types: simple and compound.
Compound items are represented by pointers to structures in the heap,
whereas simple items (integers and single-precision decimals) are
represented by themselves.

Unlike some Lisp systems Poplog uses only two bits of a 32 bit
machine word to indicate what sort of object it is, i.e. pointer,
integer, or decimal. Hence 30 bits are available for integers
and decimals and arithmetic operations using them generate no
garbage collections. If very large integers (bignums), high
precision floating point numbers, ratios, or complex numbers
are used, then store is allocated, and some time will normally
have to be spent on garbage collection.

To be fair, Jeff did write
>Some types/sizes of numbers may be represented directly (as part of a
>pointer) rather than by an allocated object.  If these are suitable
>for reaction times, you win.

but he made it sound as if most Lisp systems would not be able to cope.
I presume that if Poplog can cope with quite a wide range of integers
and floats, other lisp systems on 32 bit machines can too? After all
reaction times are not going to be measured to a very high precision.

Aaron Sloman,
School of Cognitive Sciences, Univ of Sussex, Brighton, BN1 9QN, England
    ARPANET : aarons%uk.ac.sussex.cvaxa@nss.cs.ucl.ac.uk
    JANET     aarons@cvaxa.sussex.ac.uk
    BITNET:   aarons%uk.ac.sussex.cvaxa@uk.ac

As a last resort (it costs us more...)
    UUCP:     ...mcvax!ukc!cvaxa!aarons
            or aarons@cvaxa.uucp

richard@aiva.ed.ac.uk (Richard Tobin) (04/19/88)

In article <452@cvaxa.sussex.ac.uk>
 aarons@cvaxa.sussex.ac.uk (Aaron Sloman) writes:
>Jeff Dalton (jeff@aiva.ed.ac.uk) writes:
>>Unfortunately, your program will be using numbers to represent
>>reaction times, and creating a number tends to allocate storage in
>>most Lisps even though you haven't done an explicit MAKE-NUMBER.
>
>Just for the record. In POPLOG Common Lisp (and also in the other Poplog
>languages, namely POP-11, Prolog and ML) storage is NOT allocated for
>integers or single-precision floating point numbers that can fit into 30
>bits of store.

It is recommended (CLtL page 19) that the type short-float provide
such non-heap floats, so programs concerned to avoid garbage collection
should use this type for floats where possible.

POPLOG appears to provide two floating point formats: single (which
also serves as short) and double (which also serves as long).  Since
the precision of singles is only 22 bits, which is less than that
recommended (24 bits - see page 17), perhaps it would be more
appropriate to adopt the alternative divison, and have the types short
and single, with single serving as double and long.

On the other hand, "more appropriate" (the term used in CLtL) isn't
very precise, so I don't think one could say POPLOG is wrong here.

-- Richard
-- 
Richard Tobin,                         JANET: R.Tobin@uk.ac.ed             
AI Applications Institute,             ARPA:  R.Tobin%uk.ac.ed@nss.cs.ucl.ac.uk
Edinburgh University.                  UUCP:  ...!ukc!ed.ac.uk!R.Tobin

darrelj@sdcrdcf.UUCP (Darrel VanBuer) (04/19/88)

The range of numbers varies quite widely between different Lisp
implementations.  There are three catagories in many Lisps:
SMALLP  --  stored in a reserved range of (fake) pointers, these only cost a
	few cycles to add/subtract/shift to/from naked number
FIXP -- a full machine word with a pointer to it. 32 to 36 bits on most.
BIGNUM -- usually open ended, often implemented with arrays or lists

Implementation	SMALLP		FIXP		BIGNUM
==============	======		====		======
Interlisp 10	-1536..1535	36 bits		no
Interlisp VAX	-2^30..2^30-1	no		no
Interlisp D	-65535..65535	32 bits		yes
Interlisp 360	24 bits		32 bits		no
CWIC 360	-4096..12287	32 bits		no

I have also seen a few implementations with NO smallp.
Commonlisp only talks of FIXNUM and BIGNUM, but discourages knowing the
dividing line since it is unportable (though it suggests that fixnums should
provide at least 16 bits), and is even vague about how much of an efficiency
difference there is (or how you would split up the three catagories into the
two Commonlisp sets).
-- 
Darrel J. Van Buer, PhD; unisys; 2400 Colorado Ave; Santa Monica, CA 90406
(213)829-7511 x5449        KI6VY        darrel@CAM.UNISYS.COM   or
...{allegra,burdvax,cbosgd,hplabs,ihnp4}!sdcrdcf!darrelj

brengle@hpcltjb.HP.COM (Tim Brengle) (04/20/88)

Lucid Common LISP uses 30 bit "immediate" integers in a 32 bit word.

PSL 3.4 uses 28 bit immediate integers.

Both do a lot of work to make arithmetic FAST.  I know; I was part of the team
that worked on porting both of these to HP's Precision Architecture.

Tim Brengle
Hewlett-Packard Company

brengle@hplabs.hp.com

barmar@think.COM (Barry Margolin) (04/20/88)

In article <5243@sdcrdcf.UUCP> darrelj@sdcrdcf.UUCP (Darrel VanBuer) writes:
>Implementation	SMALLP		FIXP		BIGNUM
>==============	======		====		======
 Symbolics 3600 32 bits		no		yes

>I have also seen a few implementations with NO smallp.

It probably simplifies the implementation if you don't have to decide
at runtime whether to dereference a pointer or not.

>Commonlisp only talks of FIXNUM and BIGNUM, but discourages knowing the
>dividing line since it is unportable (though it suggests that fixnums should
>provide at least 16 bits), and is even vague about how much of an efficiency
>difference there is (or how you would split up the three catagories into the
>two Commonlisp sets).

Common Lisp seems to consider that the important difference between
FIXNUM and BIGNUM is the speed of the arithmetic.  In this case, the
difference between SMALLP and FIXP is not great, because both can
generally use hardware arithmetic instructions; FIXP just requires an
extra indirection first.  BIGNUM arithmetic is generally implemented
using subroutines (or, in the case of some Lisp Machines, microcode).
If speed is what you care about, FIXNUM = SMALLP U FIXP.

The other distinction, storage efficiency, can also be important;
that's what this whole discussion started with.  Unfortunately, the
Lisp implementations that most CL designers came from didn't have
FIXPs, so they didn't include this distinction in the language.  They
were used to implementations of SMALLP that were close enough to the
word size that it didn't pay to have another one-word integer type.  A
common way of implementing SMALLP in a typed-pointer Lisp is to
include some of the bits that would ordinarily be type bits in the
integer, by specifying that if the first N bits (where N is often 2)
of the type code are all 0 or all 1 the object is a SMALLP and the
rest of the bits of the type code are actually the high-order bits of
the number.  This allows SMALLP's to get very large without forcing
type codes to be too small.


Barry Margolin
Thinking Machines Corp.

barmar@think.com
uunet!think!barmar