Comment 2 for bug 586940

Revision history for this message
Nikodemus Siivola (nikodemus) wrote :

This patch causes a notable drop in output performance, since OUT-SYNONYM-OF is called quite a lot -- often needlessly -- and OUTPUT-STREAM-P is a generic function.

While I agree that this patch is in principle a good thing, other code needs to change as well for this to go in.

As an example:

(defun rush (stream n object)
  (declare (fixnum n))
  (loop repeat n
        do (print object stream)))

(with-open-file (f "/tmp/rush.tmp" :if-exists :supersede :direction :output)
  (time (rush f 10000000 42)))

Without the patch this runs in under 3.9 seconds run-time and 4.2 real-time on my system. With the patch it takes 6.4 seconds run-time and 6.6 seconds real-time.

Adding

(defun %write-char (character stream)
  (with-out-stream/no-synonym stream
    (ansi-stream-out character)
    (stream-write-char character)))

-- like WRITE-CHAR, but doesn't deal with output stream designators -- and changing PRINT to

(defun print (object &optional stream)
  #!+sb-doc
  "Output a newline, the mostly READable printed representation of OBJECT, and
  space to the specified STREAM."
  (let ((stream (out-synonym-of stream))
        (*print-escape* t))
    (%write-char #\newline stream)
    (output-object object stream)
    (%write-char #\space stream)
    object))

and similarly using %WRITE-CHAR instead of WRITE-CHAR in %OUTPUT-REASONABLE-INTEGER-IN-BASE makes the test-case run in 4.0 run-time and 4.3 real-time -- which is an acceptable cost, IMO.

So, all output functions underneath the user-callable layer need to be audited so that OUT-SYNONYM-OF is not called uselessly, instead of using WRITE-CHAR/STRING/WHATEVER using corresponding %WRITE-FOO functions which need to be written.