CLIM mail archive

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

reducing time overhead of text display (in 1.1)



    Date: Sat, 18 Dec 1993 16:38 EST
    From: Daniel D Suthers <suthers+@pitt.edu>

I'm keeping this lengthy message addressed to the whole group, because
we may all be able to learn something useful here.

    I suppose I should supply some code with that prior post.  I also did
    some further tests to clarify where the major difference is.  (All
    code is compiled.) To summarize, approximately:

      .02 seconds are required to write a continuous string of length 2153 to
		  *standard-output*

      2 seconds are required to indent and format this same string using my 
		indent&format to *standard-output*

      7 seconds are required to indent and format this same string using my 
		indent&format to *standard-output* to a CLIM window.

If you send me your indent&format code, I wouldn't mind checking it out
myself.  These numbers don't match up at all with what I get in Genera.

    - so basic overhead of clim window is 5 seconds

      20 seconds are required to indent and format a string of similar
	    length but segmented into dozens of parts with nested presentations. 

    - so overhead of presentations is appx. 13 seconds. 

This argues very strongly for custom output recording for this
application.

      27 seconds more are required to use clim indenting-output and
	 filling-output instead of my home-brew on this same segmented string.

    - so additional overhead of clim formatting is another 7 seconds.

INDENTING-OUTPUT is very fast.  FILLING-OUTPUT is not.  The reasons
that FILLING-OUTPUT is slow are a little complicated, but it's mostly
because it needs to work incrementally.

    This is why I'm asking for advice: I can save some time by writing my
    own code but the biggest killers are presentations. How can I make
    them faster?

Summary: avoid making them until you need them.  I can't help you
directly on this because of time constraints.  It's not hard or terrible
time-consuming, but it could take a few days.

    ----------------------------------------------------------------------
    Now the code. In the CLIM version of formatting, the first relevant code is: 

	     (clim:stream-increment-cursor-position*
	      stream 0 *text-presentation-top-margin*)
	     (clim:indenting-output
	      (stream *text-presentation-left-margin*)
	      (clim:filling-output 
	       (stream 
		:fill-width (list text-presentation-right-margin ':character))
	       (display-text-dispatcher
		media parent stream graphic-x-offset graphic-y-offset selected-p)))

    The dispatcher eventually reaches our own macro call:

      (present-with-display-record
       (string stream
	       :media-parent parent
	       :enclosing-x-offset x-offset
	       :enclosing-y-offset y-offset
	       :single-box *text-single-box-highlighting*)
       (display-literal-string string stream 
			       :in-selected-context in-selected-context))

    Which macroexpands into:

    (LET* ((DISPLAYED-ELEMENT STRING)
	   (PRESENTATION-TYPE (CLIM:PRESENTATION-TYPE DISPLAYED-ELEMENT))
	   (DISPLAY-OBJECT
	     (IF (STRINGP DISPLAYED-ELEMENT)            ; <----- This looks
		 (MAKE-INSTANCE 'STRING-DISPLAY-RECORD) ; <----- suspicious, 
		 DISPLAYED-ELEMENT)))                   ; <----- but see below.
      (COND (DISPLAY-OBJECT
	     (SETF (DISPLAYED-ELEMENT DISPLAY-OBJECT) DISPLAYED-ELEMENT
		   (MEDIA-PARENT DISPLAY-OBJECT)      PARENT
		   (DISPLAY-STREAM DISPLAY-OBJECT)    STREAM
		   (PRESENTATION-TYPE DISPLAY-OBJECT) PRESENTATION-TYPE
		   (ENCLOSING-X-OFFSET DISPLAY-OBJECT) X-OFFSET
		   (ENCLOSING-Y-OFFSET DISPLAY-OBJECT) Y-OFFSET)
	     (SETF (OUTPUT-RECORD DISPLAY-OBJECT)
		   (CLIM:UPDATING-OUTPUT (STREAM)
		     (SETF (PRESENTATION DISPLAY-OBJECT)
			   (CLIM:WITH-OUTPUT-AS-PRESENTATION
			     (:STREAM STREAM
				      :TYPE PRESENTATION-TYPE
				      :OBJECT DISPLAY-OBJECT
				      :SINGLE-BOX *TEXT-SINGLE-BOX-HIGHLIGHTING*
				      :ALLOW-SENSITIVE-INFERIORS T)
			     (DISPLAY-LITERAL-STRING STRING         
						     STREAM
						     :IN-SELECTED-CONTEXT
						     IN-SELECTED-CONTEXT))))))
	    (DISPLAYED-ELEMENT
	     (CERROR "Does nothing."
		     "PRESENT-WITH-DISPLAY-RECORD: ~S, child of ~S, is not a
    media-instance."
		     DISPLAYED-ELEMENT
		     PARENT))))

In the code above, what is the call to UPDATING-OUTPUT for?  It doesn't
supply either a unique-id or a cache-value, so that would normally mean
that it is the *outermost* call in redisplay.  But nothing inside it is
an updating output record.  And it surely doesn't add any information
that CLIM can use.  My advice?  If you don't need it, flush it -- it's
*doubling* the number of output records you are creating.

If you are calling REDISPLAY on (OUTPUT-RECORD DISPLAY-OBJECT) objects,
then I guess you'll have to keep it, but it still seems very odd that
there are neither lower-level calls to UPDATING-OUTPUT nor a unique-id
or cache-value.

    and where display-literal-string is



    (defun DISPLAY-LITERAL-STRING (string stream &key (in-selected-context nil))
      (clim:with-end-of-page-action (:allow stream)
	(clim:with-end-of-line-action (:allow stream)
	  (if in-selected-context
	      (clim:with-text-face (:bold stream)
		(write-string string stream))
	      (write-string string stream))


WITH-END-OF-PAGE-ACTION and WITH-END-OF-LINE-ACTION are not free.  Hoist
them out to a higher level.

    OK, wondering whether our proliferate creation of display-record
    instances is to blame, I removed creation and references to these
    instances from the macro, without changing anything else. The
    expansion is now:

    (LET* ((DISPLAYED-ELEMENT STRING)
	   (PRESENTATION-TYPE (CLIM:PRESENTATION-TYPE DISPLAYED-ELEMENT))
	   (DISPLAY-OBJECT DISPLAYED-ELEMENT))
      (COND (DISPLAY-OBJECT
	     (CLIM:UPDATING-OUTPUT (STREAM)
	       (CLIM:WITH-OUTPUT-AS-PRESENTATION
		 (:STREAM STREAM
			  :TYPE PRESENTATION-TYPE
			  :OBJECT DISPLAY-OBJECT
			  :SINGLE-BOX *TEXT-SINGLE-BOX-HIGHLIGHTING*
			  :ALLOW-SENSITIVE-INFERIORS T) ; no difference if nil
		 (DISPLAY-LITERAL-STRING STRING
					 STREAM
					 :IN-SELECTED-CONTEXT
					 IN-SELECTED-CONTEXT))))
	    (DISPLAYED-ELEMENT
	     (CERROR "Does nothing."
		     "PRESENT-WITH-DISPLAY-RECORD: ~S, child of ~S, is not a
    media-instance."
		     DISPLAYED-ELEMENT
		     PARENT))))

Try getting rid of the call to UPDATING-OUTPUT, and move the inner uses
of WITH-END-OF-PAGE-ACTION and WITH-END-OF-LINE-ACTION outside.  My
guess is that you will see an improvement of at least a factor of 2, and
very possibly more than that.

    I still get ...

      Elapsed Real Time = 27.08 seconds
      Total Run Time    = 27.02 seconds
      User Run Time     = 20.10 seconds
      System Run Time   = 6.92 seconds
      Process Page Faults    =          0
      Dynamic Bytes Consed   =          0
      Ephemeral Bytes Consed =  2,778,008
      There were 6 ephemeral GCs

    i.e., no difference. This with CLIM's indenting/formatting. When I
    changed the code to use my own indent&format function (by removing the
    clim:indenting-output & clim:filling-output idiom and replacing the
    write-string with my function), I'd typically get:

      Elapsed Real Time = 20.24 seconds
      Total Run Time    = 20.17 seconds
      User Run Time     = 15.52 seconds
      System Run Time   = 4.65 seconds
      Process Page Faults    =          3
      Dynamic Bytes Consed   =          0
      Ephemeral Bytes Consed =  2,116,352
      There were 4 ephemeral GCs

    a savings of 7 seconds. 

If you think your indent&format code is generally useful, you should
consider posting it.  I for one will never claim that CLIM's version of
FILLING-OUTPUT is the ne plus ultra of its genre.

    Sorry if this is a lot of detail for a post, but I want to minimize
    the need for iteration.

    --------------------------------------------------
     Dan Suthers           | LRDC, room 505A
     suthers+@pitt.edu     | 3939 O'Hara Street
     (412) 624-7036 office | University of Pittsburgh
     (412) 624-9149 fax    | Pittsburgh, PA 15260
    --------------------------------------------------


References:

Main Index | Thread Index