CLIM mail archive


Re: CLIM philosophy wrt to X.

  Date: Tue, 27 Aug 1991 10:16-0400
  From: Scott McKay <>
  Subject: RE: CLIM philosophy wrt to X.
  To: jmorrill@BBN.COM, clim@BBN.COM
      Date: Mon, 26 Aug 1991 17:58 EDT
      From: Jeff Morrill <jmorrill@BBN.COM>
      The solution to the issue of buffered output, I hope, 
      is to put a big caveat in the CLIM documentation that 
      buffering is something that users must solve for themselves 
      via careful placement of FORCE-OUTPUTs.  This might ruffle
      some feathers for some purists who yearn for truly platform-
      independent behavior, but I am not a purist.
      I don't understand what WITH-BUFFERED-OUTPUT would do other
      than perform a FORCE-OUTPUT at the end.  I hope no one is
      suggesting that this macro will implement buffered output on 
      platforms that do not implement buffering in the native window 
  The real intention of WITH-BUFFERED-OUTPUT is to allow programmers to
  turn *off* output buffering on platforms that normally have it on.  That
  is, WITH-BUFFERED-OUTPUT does not implement buffering itself, it just
  allows it to happen on those hosts that already support it.
I just don't see where i'd turn buffering off since it would slow my
application X, on Lucid, down, or why writing with-buffered-output is so
superior to force-output.  I just checked in 135,000 lines of lisp, there
were 600 calls to "(draw-..." and 39 calls to "force-output".

      I agree with Ken that DRAW-<thing>* is too slow already.  
      It is nice to have something fairly high level that takes
      every keyword imaginable.  But on the other hand, how often
      will anyone use all those things?  I have programs written
      in CLIM 0.9 which may do 100,000 draw operations at once, every one
      with the same options as the last one.  And every time
      through the loop, draw-<thing>* processes piles of stuff 
      (alu, transformation, stipple, ...) that only need to
      be processed once, if at all.  For such applications, we
      could use some low-budget functionality which could take
      advantage of what WITH-DRAWING-OPTIONS can set up.  Sometimes
      we use DRAW-<thing>*-INTERNAL, but even this is overkill for
      98% of the output operations.
  You and I must write different sorts of programs, but I have only rarely
  resorted to this level of I/O.  I imagine that your applications must be
  display intensive, whereas mine are compute intensive.
Our applications are both display and compute intensive, and probably give
CLIM an extensive workout.

      Right now, our use of CLIM includes a trap door to go
      directly to the native window system (CLX, Genera) for speed.  
      One gets acceptable speed, but at the cost of no output recording.
      Let us get away from adding yet another burden to the output
      protocol, and let us move toward a small kernel of low-level
      operations that do the simple things exceptionally well.  
  WITH-BUFFERED-OUTPUT adds virtually no measurable cost, as DCPL already
  pointed out.  It's simply a SLOT-VALUE plus a branch.
  As for "exceptionally well", keep in mind CLIM is a high level UI
  substrate. It imposes some measure of overhead on any operation.  The
  higher you go, the more overhead you pay.  There is *no way* to avoid
  this, no matter how hard you try.  At Symbolics on CLIM 1.0, we made a
  pretty fair effort to reduce this overhead as best as we could, but the
  mere fact that CLIM uses Lisp instead of C, CLOS instead of C++, means
  that anyone will *always* be able to find a faster way, either by
  sacrificing portality or features.  You can't have it both ways, even
  though that would be nice.

There is a problem with this.  CLIM is nice and portable, but unless my X
applicaton is a success, i'll never get the chance to port it to anything.
While people who develop applications may use CLIM for it's portability,
users may not care about portability so much, they certainly care about
performance.  I would hope that some of the higherlevelness of CLIM could
be compiled out.  Here is a simple example:

;;; Timings are done on a Sun 4, Lucid 4.0, CLIM 0.9. The X server is a Sun 3/50.
;;; Timings were done doing (test-* stream 250), so about 500 lines are drawn.
(defun picture (stream size line-drawer)
  ;; This fills in a SIZE sized box with a fan of lines.
  (declare (fixnum size)
	   (compiled-function line-drawer))
   (dotimes (x size)
     (let ((y (- size x)))
       (funcall line-drawer stream x size y 0)
       (funcall line-drawer stream size x 0 y)))))

(defun test-0 (stream size)
  ;; This just shows that picture, itself, doesn't cons.
  (window-clear stream)
  (picture stream size #'ignore))

(defun test-1 (stream size)
  ;; Using regular draw-line*
  ;; 1020 lines/sec, 288 bytes/line consed.
  (window-clear stream)
  (with-output-recording-options (stream :record-p nil :draw-p t)
    (picture stream size #'draw-line*))
  (force-output stream))

(defun test-2 (stream size)
  ;; Going to the medium, and an optimization we don't have in Lucid.
  ;; 1250 lines/sec, 240 bytes/line consed.
  (window-clear stream)
  (with-output-recording-options (stream :record-p nil :draw-p t)
    (picture (sheet-medium stream) size
  (force-output stream))

(defun test-3 (stream size)
  ;; Asking the stream how to draw fast.
  ;; 4166 lines/sec, 8 bytes/line consed.
  (window-clear stream)
  (with-output-recording-options (stream :record-p nil :draw-p t)
    (picture stream size (drawing-guts-draw-line* stream)))
  (force-output stream))

DRAWING-GUTS-DRAW-LINE* is a method that returns a (DRAW-LINE* STREAM X1 Y1
X2 Y2) function that is optimized for the environment in which it is
called.  It's contract is that it can only be used in the same environment.
This give high performance but lets us use CLIM to set the environment up
the way we want.  This might be a good way to get the highlevelness of CLIM
and some good performance too.

We have CLIM applications where we just can't pay this factor of 4.




Main Index | Thread Index