Re: s48 and bibop garbage collector

Robert Ransom <[email protected]> Thu, 25 Feb 2010 17:15:55 -0800
Newsgroups gmane.lisp.scheme.scheme48
Message-ID <[email protected]>
On Thu, 25 Feb 2010 15:01:34 +0100
Vladimir Konrad <[email protected]> wrote:

> 
> Hello,
> 
> When I run a simple factorial function (iterative definition, file attached) for one million, like:
> 
> (define x (factorial 1000000))
> 
> the scheme48 (both, 1.8 and 1.9T) with bibop garbage collector starts to allocate a _lot_ of ram
> after a longish while (killed at around 3[GB] allocated).

The BIBOP collector allocates each large object (more than 2^16 bytes
long) in its own block of memory.  If it already has a large enough
block allocated, but unoccupied, it will use that block for the new
object; otherwise, it will use malloc(3) to allocate a new block, just
large enough for the new large object.  The BIBOP GC currently does not
call free(3) on these blocks of memory, even if they become unoccupied.

As a consequence, your ‘benchmark’ causes Scheme 48 to malloc(3) (and
hold on to) at least two blocks of each length divisible by 2^12, from
(2^16 + 2^12) to over 2^20.

> Also, should "-h" option limit the maximum heap even for twospace garbage collector, when the number != 0 ?
> 
> My understanding is that _yes it should_, but just want to make sure (I think it does not in this case).

It should limit the heap, but keep in mind that the heap does not
contain the interpreter, or any shared libraries that are loaded.

The twospace collector does not support the ‘-h 0’ unlimited-heap-size
option.

> (btw, I know that micro-benchmarks do not prove much, my guess is that there could be a bug in scheme48 and
> you might like to know.)

Yes, it's a bug, known at least since mid-January.



If you really want to calculate huge (multi-kilobyte) exact factorials,
the traditional technique for concatenating a huge sequence of strings
using only a two-string concatenation function is to accumulate them
into a list (with the earliest string at the tail of the list),
concatenating the last two strings (the two head-most strings) together
whenever the string at the head of the list is larger; this technique
can be adapted to bignum multiplication (use the logarithm of a bignum
as its size if you can't get its actual length in memory).

See the attachments for an example implementation.

> Please access the attached hyperlink for an important electronic communications disclaimer: http://www.lse.ac.uk/collections/planningAndCorporatePolicy/legalandComplianceTeam/legal/disclaimer.htm

No.
huge-factorial.scm (text/x-scheme, 972 B)
(define (int->x n) (cons (log n) n))
(define (reduce-xs/2 x1 x2) (cons (+ (car x1) (car x2))
				  (* (cdr x1) (cdr x2))))
(define (x-size x) (car x))
(define null-x '(0 . 0))

(define (add-x-to-reducer reducer x)
  (cond
   ((null? reducer)
    (cons x '()))
   (else
    (let* ((reducer-head (car reducer)))
      (if (>= (x-size x) (x-size reducer-head))
	  (add-x-to-reducer (cdr reducer) (reduce-xs/2 x reducer-head))
	  (cons x reducer))))))

(define (add-xs-to-reducer reducer xs)
  (do ((xs xs (cdr xs))
       (reducer reducer (add-x-to-reducer reducer (car xs))))
      ((null? xs) reducer)))

(define (finish-reducer reducer)
  (cond
   ((null? reducer)
    null-x)
   (else
    (do ((x (car reducer) (reduce-xs/2 x (car reducer)))
	 (reducer (cdr reducer) (cdr reducer)))
	((null? reducer) x)))))



(define (huge-factorial n)
  (do ((i 1 (+ i 1))
       (reducer '() (add-x-to-reducer reducer (int->x i))))
      ((> i n) (cdr (finish-reducer reducer)))))
string-concat.scm (text/x-scheme, 969 B)
(define (reduce-xs/2 x1 x2) (string-append x2 x1)) ;note reversed args
(define (x-size x) (string-length x))
(define null-x "")

(define (add-x-to-reducer reducer x)
  (cond
   ((null? reducer)
    (cons x '()))
   (else
    (let* ((reducer-head (car reducer)))
      (if (>= (x-size x) (x-size reducer-head))
	  (add-x-to-reducer (cdr reducer) (reduce-xs/2 x reducer-head))
	  (cons x reducer))))))

(define (add-xs-to-reducer reducer xs)
  (do ((xs xs (cdr xs))
       (reducer reducer (add-x-to-reducer reducer (car xs))))
      ((null? xs) reducer)))

(define (finish-reducer reducer)
  (cond
   ((null? reducer)
    null-x)
   (else
    (do ((x (car reducer) (reduce-xs/2 x (car reducer)))
	 (reducer (cdr reducer) (cdr reducer)))
	((null? reducer) x)))))



(define (test-string-reducer n)
  (do ((i 1 (+ i 1))
       (reducer
	(add-x-to-reducer '() "0")
	(add-xs-to-reducer reducer (list ", " (number->string i)))))
      ((> i n) (finish-reducer reducer))))