Re: [flexi-streams-devel] New release 0.11.1

Vodonosov Anton vodonosov at mail.ru
Sat Apr 21 18:33:02 UTC 2007


Hi!

Edi, as far as I understand external format 
with multibyte encodings and cr-lf style newlines
are not optimized because its difficult to predict
number of characters that will fit into buffer.

We can solve it if we will always have few reserved
bytes in buffer. 20 will be sufficient for any encoding.
I.e. loop while we have at least 20 free bytes in buffer.

This solution is implemented in the attached patch (against 0.11.2).

The patch also contains some additions in tests. As for
separate tests for READ-SEQUENCE/WRITE-SEQUENCE,
maybe thay are useless - I noticed that, at least in CLISP, 
WRITE-LINE is implemented using WRITE-SEQUENCE. So in 
case of errors in WRITE-SEQUENCE both WRITE-LINE and 
WRITE-SEQUENCE tests fail.

In regard to the way I reused existing WRITE-CHAR code
in STREAM-WRITE-SEQUENCE. I do not like mach working 
throught temporary stream, for example we have redundant 
slot access in WRITE-BYTE*. I've tried to keep changes small 
and not disturb other code. Maybe with some refactoring 
it will be possible to have more clean and efficient code.

For example WRITE-CHAR code will not use WRITE-BYTE* directly
but use instead some BYTE-WRITER-FUN passed as a parameter.
Also external format may be distinguished as a separate 
entity responsible for byte/character conversions.

BTW, I've started changing STREAM-WRITE-SEQUENCE with the 
version provided below. It is more efficient, but it isn't
thread safe.

(defmacro dyna-let-f-global (symbol func-to-bind &body body)
  "Something similar to FLET for global functions but with dynamic extent"
  `(let ((old-fdef (fdefinition ,symbol)))
    (unwind-protect (progn 
              (setf (fdefinition ,symbol) ,func-to-bind)
              , at body)
      (setf (fdefinition ,symbol) old-fdef))))

(defmethod stream-write-sequence ((stream flexi-output-stream) (sequence string) start end &key)
  (declare (optimize speed) (type (integer 0 *) start end fill-pointer src-ptr))
; (declare (optimize speed) (type (integer 0 *) start end))
  (let ((buffer (make-array (+ +buffer-size+ 20) :element-type 'octet)))
    ;; use repeated calls to WRITE-SEQUENCE for arrays of octets
    (loop with src-ptr = start 
      while (< src-ptr end)
      do
      (let ((fill-pointer 0))
        (dyna-let-f-global 'write-byte* (lambda (byte stream) 
                          (declare (ignore stream) (type (integer 0 *) fill-pointer) (type octet byte)) 
                          (setf (aref buffer fill-pointer) byte) (incf fill-pointer))
          (loop while (and (< src-ptr end) (< fill-pointer +buffer-size+))
            do (stream-write-char stream (aref sequence src-ptr)) (incf src-ptr)))
        (write-sequence buffer (flexi-stream-stream stream)
                :start 0 :end fill-pointer))))
  sequence)

Here are some performance tests. 
Tested in CLISP on Windows XP.

(asdf:operate 'asdf:load-op :flexi-streams)
(asdf:oos 'asdf:test-op :flexi-streams)

(defparameter long-str "")
;; populate it with some Russian characters
(dotimes (i 10)  
  (setf long-str 
	(concatenate 'string 
		     long-str 
		     "Достаточно длинная строка на русском языке. 
Ее длина составляет порядка ста символов")))

(defun time-test(external-format)
  (with-open-file (stream "/cygdrive/c/usr/projects/flexi-dev/test-output.txt" 
			  :direction :output 
			  :element-type '(unsigned-byte 8) 
			  :buffered nil) ; :buffered is a CLISP extension
    (with-open-stream (fstream (flex:make-flexi-stream stream 
						       :external-format external-format))
      (loop for i from 0 below 200 do
	    (stream-write-sequence long-str fstream)))))


;; original flexi-streams-0.11.2 
;; =============================

(time (time-test :utf-8))
;; Real time: 12.178 sec.
;; Run time: 12.093 sec.
;; Space: 430660 Bytes
;; GC: 1, GC time: 0.015 sec.

(time (time-test :koi8-r))
;; Real time: 0.246 sec.
;; Run time: 0.25 sec.
;; Space: 1820584 Bytes
;; GC: 2, GC time: 0.048 sec.

;; with temp flexi stream
;; ======================

(time (time-test :utf-8))
;; Real time: 1.08 sec.
;; Run time: 1.079 sec.
;; Space: 1791632 Bytes
;; GC: 2, GC time: 0.063 sec.

(time (time-test :koi8-r))
;; Real time: 0.861 sec.
;; Run time: 0.875 sec.
;; Space: 1795636 Bytes
;; GC: 2, GC time: 0.048 sec.

;; with dyna-let-f-global
;; ======================

(time (time-test :utf-8))
;; Real time: 0.639 sec.
;; Run time: 0.641 sec.
;; Space: 1734832 Bytes
;; GC: 2, GC time: 0.062 sec.

(time (time-test :koi8-r))
;; Real time: 0.567 sec.
;; Run time: 0.563 sec.
;; Space: 1734836 Bytes
;; GC: 2, GC time: 0.062 sec.

Best regards,
-Anton

-----Original Message-----
From: Edi Weitz <edi at agharta.de>
To: flexi-streams-devel at common-lisp.net
Date: Thu, 22 Mar 2007 22:58:27 +0100
Subject: [flexi-streams-devel] New release 0.11.1

> 
> ChangeLog:
> 
>   Version 0.11.1
>   2007-03-22
>   More ugliness for a bit of output performance in special cases
> 
> Download:
> 
>   http://weitz.de/files/flexi-streams.tar.gz
> 
> Cheers,
> Edi.
> _______________________________________________
> flexi-streams-devel mailing list
> flexi-streams-devel at common-lisp.net
> http://common-lisp.net/cgi-bin/mailman/listinfo/flexi-streams-devel
> 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: flexi-patch.diff
Type: application/octet-stream
Size: 15340 bytes
Desc: not available
URL: <https://mailman.common-lisp.net/pipermail/flexi-streams-devel/attachments/20070421/d1572c25/attachment.obj>


More information about the Flexi-streams-devel mailing list