CLIM mail archive

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

consing results



Thanks to messages from John Aspinall and Scott McKay, I learned that my key
problem was that output recording was on.  Turning it off improved matters a
lot.  Furthermore, Scott McKay suggested using the MEDIUM-DRAW functions, which
helped, too.  Unfortunately, MEDIUM-DRAW-ARROW doesn't exist, so a direct
comparison for that isn't possible.  Here are the final results:

Original Consing (output recording on)

draw-ellipse* => 361 words
draw-line*    => 158 words
draw-arrow*   => 607 words

Consing with output recording off, using 		    
 (with-output-recording-options (pane :record nil :draw t) ...)

draw-ellipse* =>  98 words
draw-line*    =>  56 words
draw-arrow*   => 326 words

Consing with output recording off, and using medium functions:

medium-draw-ellipse* =>  58 words
medium-draw-line*    =>  26 words

These results are for CLIM 2.0 in Lucid on a SPARC. Your mileage may vary.

It would be nice if the functions didn't cons at all, but this is a great
improvement, and I appreciate the help.

What do I give up by using MEDIUM-DRAW- functions instead of the higher-level
drawing functions?  It seems that all I give up is keyword arguments for things
like ink, which instead have to be done by WITH-DRAWING-OPTIONS.  Anything else?

Scott D. Anderson
anderson@cs.umass.edu

;;; ============================================================================
;;; The following is the code to reproduce the results above.

(in-package :clim-user)

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

;;; The following methods are irrelevant to the bug.

(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)))
	,conses))))

;;; ============================================================================
;;; 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))
      (format t "~2&Consing with output recording.~%")
      (let ((words (consing
		    (loop repeat times do
			  (draw-ellipse* pane w h 50 0 0 50 :ink +flipping-ink+)))))
	(format t "~&~d words consed, or about ~f words per call to draw-ellipse*.~%"
		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))))))

(define-cons-frame-command (com-test-consing-no-recording :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))
      (format t "~2&Consing with no output recording.~%")
      (let ((words (consing
		    (with-output-recording-options (pane :record nil :draw t)
		      (loop repeat times do
			    (draw-ellipse* pane w h 50 0 0 50 :ink +flipping-ink+))))))
	(format t "~&~d words consed, or about ~f words per call to draw-ellipse*.~%"
		words (/ words times)))
      (let ((words (consing
		    (with-output-recording-options (pane :record nil :draw t)
		      (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
		    (with-output-recording-options (pane :record nil :draw t)
		      (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))))))

(define-cons-frame-command (com-test-medium-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))
      (format t "~2&MEDIUM-DRAW consing with no output recording.~%")
      (let ((words (consing
		    (with-output-recording-options (pane :record nil :draw t)
		      (with-drawing-options (pane :ink +flipping-ink+)
			(loop repeat times do
			      (medium-draw-ellipse* pane w h 50 0 0 50 0 clim-utils:2pi t)))))))
	(format t "~&~d words consed, or about ~f words per call to medium-draw-ellipse*.~%"
		words (/ words times)))
      (let ((words (consing
		    (with-output-recording-options (pane :record nil :draw t)
		      (with-drawing-options (pane :ink +flipping-ink+)
			(loop repeat times do
			      (medium-draw-line* pane 0 0 w h)))))))
	(format t "~&~d words consed, or about ~f words per call to medium-draw-line*.~%"
		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*))

;Get the following output:

;> (doit)

;Consing with output recording.
;36142 words consed, or about 361.42 words per call to draw-ellipse*.
;15808 words consed, or about 158.08 words per call to draw-line*.
;60752 words consed, or about 607.52 words per call to draw-arrow*.

;Consing with no output recording.
;9814 words consed, or about 98.14 words per call to draw-ellipse*.
;5618 words consed, or about 56.18 words per call to draw-line*.
;32634 words consed, or about 326.34 words per call to draw-arrow*.

;MEDIUM-DRAW consing with no output recording.
;5840 words consed, or about 58.4 words per call to medium-draw-ellipse*.
;2640 words consed, or about 26.4 words per call to medium-draw-line*.
;NIL
;> 

Follow-Ups:

Main Index | Thread Index