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

Reduce garbage by using DYNAMIC-EXTEND?



The carefull use of DYNAMIC-EXTENT declarations can dramatically
reduce the generation of garbage. Common Lisp implementations may
ignore such declarations. However, from the perspective of a CL user
it is highly desirable to have a compiler able to deal with this
declaration.

MCL does a good job with the following code:

(time 
 (let ((array (make-array 1000)))
   ; encurrage compiler to stack-allocate array
   (declare (dynamic-extent array)) 
   (elt array 0)))

=> no garbage whatsoever. MCL has probably stack-allocated this array.
Now..

(time 
 (let ((array (make-array 1000 :initial-element 0)))
   (declare (dynamic-extent array))
   (elt array 0)))

=> 4008 bytes of memory allocated

Why does this create garbage? The size of the array can be determined
at compile time.

(defun MAKE-DYNAMIC-ARRAY (size)
  (let ((array (make-array size)))
    (declare (dynamic-extent array))
    (elt array 0)))

(time (make-dynamic-array 1000))

=> 4008 bytes of memory allocated.

In this case the size of the array could not be determined at compile
time.  What if we determine the size of the array with some compile-time 
computable expression:

(time 
 (let ((array (make-array (+ 128 128))))  ; size = simple expression with constants
   (declare (dynamic-extent array))
   (elt array 0)))

=> no garbage

(time 
 (let ((array (make-array (expt 2 8)))) ; size = more complex expression with constants 
   (declare (dynamic-extent array))
   (elt array 0)))

=> 1032 bytes of memory allocated.


What are the compiler's rules for stack-allocation? Is it
intrinsically impossible in CL to stack-allocate arrays if the size of
the array can only be determined at run time? If not, it would be
really great if MCL 2.1's stack-allocation scheme would be less
constrained and therefore more predictable.


  Alex Repenning