CLIM mail archive


consing of graphics operations

My question is about consing during graphics operations.  I know that certain
CLIM operations, such as with-output-as-presentation will cons, but what about
drawing lines and circles?  I have an application which is doing some animation
of an ongoing simulation, and I want to have the objects move from place to
place by drawing and undrawing them with +flipping-ink+.

I'm using CLIM 2.0 in Lucid on a SPARC.  The code I've given below yields the
following consing measurements:

about 365 words per call to draw-circle*.
about 158 words per call to draw-line*.
about 596 words per call to draw-arrow*.

This seems awfully high to me. Is it reasonable?  I can't think of why these
operations would need to cons.  Is there a way to reduce the amount of consing
they do?

Thanks very much,

Scott D. Anderson

;;; ============================================================================
;;; Code to test the amount of consing.  Load the following code, turn off
;;; ephemeral GC with the function lcl:egc-off, run the doit function, and
;;; click on the test-consing menu item.

(in-package :clim-user)

(define-application-frame cons-frame ()
   (menu :command-menu)
   (display :application
	    :window-class 'display-window
	    :incremental-redisplay nil
	    :display-function 'draw-display-pane)))

;;; The following methods make the format go to the lisp listener, rather than
;;; to the frame

(defmethod frame-standard-input ((frame cons-frame)) *terminal-io*)
(defmethod frame-standard-output ((frame cons-frame)) *terminal-io*)

(defmethod draw-display-pane ((application cons-frame) stream)
  (window-clear stream))

(define-cons-frame-command (com-exit :menu T) ()
  (frame-exit *application-frame*))

;;; ============================================================================
;;; The following is a macro to find out how much something conses.

(defmacro consing (&body body)
  "Executes `body' in a way that allows consing to be measured.  Returns the
number of words consed.

This uses lcl:gc-size, as shown on page 5-33 of the Lucid User's Manual.
Ephemeral GC is turned off at the beginning, if necessary, and returned to its
original state afterwards.  See the functions egc-off and egc-on.

Known bugs:  This macro will return weird results if a GC occurs during the
body.  It seems too risky to turn off GC.  This macro is best used in the body
of a compiled function, as the examples above were."
  (let ((gc-on? (gensym))
	(isize  (gensym))
	(conses (gensym)))      
    `(let ((,gc-on?  (lcl:egc-state)))
      (if ,gc-on? (lcl:egc-off))
      (let ((,isize (lcl:gc-size)) ,conses)
	(unwind-protect (progn ,@body)
	  (setf ,conses (floor (- (lcl:gc-size) ,isize) 4))
	  (if ,gc-on? (lcl:egc-on)))

;;; ============================================================================
;;; Consing is exhibited by the following command:

(define-cons-frame-command (com-test-consing :menu t) ()
  (let ((pane  (get-frame-pane *application-frame* 'display))
	(times 100))
    (multiple-value-bind (w h) (window-inside-size pane)
      (setf w (round w 2)
	    h (round h 2))
      (let ((words (consing
		    (loop repeat times collect nil))))
	(format t "~&~d words consed in a simple loop.~%" words))
      (let ((words (consing
		    (loop repeat times do
			  (draw-circle* pane w h 50 :ink +flipping-ink+)))))
	(format t "~&~d words consed, or about ~f words per call to draw-circle*.~%"
		words (/ words times)))
      (let ((words (consing
		    (loop repeat times do
			  (draw-line* pane 0 0 w h :ink +flipping-ink+)))))
	(format t "~&~d words consed, or about ~f words per call to draw-line*.~%"
		words (/ words times)))
      (let ((words (consing
		    (loop repeat times do
			  (draw-arrow* pane 0 0 w h :ink +flipping-ink+)))))
	(format t "~&~d words consed, or about ~f words per call to draw-arrow*.~%"
		words (/ words times))))))

;;; ============================================================================

(defvar *cons-frame* nil)

;;; Call this in the lisp listener

(defun doit ()
  (setf *cons-frame* (make-application-frame 'cons-frame))
  (run-frame-top-level *cons-frame*))


Main Index | Thread Index