CLIM mail archive


consing of graphics operations

   Date: Mon, 9 May 1994 19:43:13 -0400
   From: "Scott D. Anderson" <>

   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?

Um, CLIM is doing output recording.  It has to put the output 
records someplace.

If you are doing animation and motion sorts of things, turn off
output recording using WITH-OUTPUT-RECORDING-OPTIONS or draw directly
on the medium (rather than the stream), using MEDIUM-DRAW-xxx for
the best performance.

   ;;; ============================================================================
   ;;; 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