CLIM mail archive
[Prev][Next][Index][Thread]
Re: CLIM philosophy wrt to X.
Date: Tue, 27 Aug 1991 10:16-0400
From: Scott McKay <SWM@sapsucker.scrc.symbolics.com>
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
system.
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))
(time
(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
#'silica::draw-line*-internal))
(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.
k
0,,
References:
Main Index |
Thread Index