From: Marco Antoniotti
Subject: CL I/O performance (Was: Playing sparcaudio directly from lisp)
Date: 
Message-ID: <9301081511.AA19973@maya.cs.nyu.edu>
'(Good morning)

In article <············@cs.cmu.edu> ······@cs.cmu.edu (Mark Kantrowitz) writes:

   From: ······@cs.cmu.edu (Mark Kantrowitz)
   Newsgroups: comp.lang.lisp
   Keywords: Lucid sparcaudio
   Date: 8 Jan 93 00:24:04 GMT
   References: <·····················@cs.cornell.edu>
   Sender: ····@cs.cmu.edu (Usenet News System)
   Organization: School of Computer Science, Carnegie Mellon
   Lines: 163
   Nntp-Posting-Host: glinda.oz.cs.cmu.edu

   In article <·····················@cs.cornell.edu> ·····@cs.cornell.edu (T. V. Raman) writes:
   >I plan to start using sparc audio extensively inside a clos program,

   I wrote the following code for Allegro CL. As you can see by
   experimentation with the code and variations on it, playing the sound
   files from Lisp is much too slow. Lisp file IO just isn't fast enough.
   If you're going to play sound files, you'll have to do much of the
   work in C, and then use a foreign function interface to run the code. 

This is an interesting remark. I ran through the code and I sincerely
do not understand why a Lisp application should be "slower" doing
IO than a C/C++ application.

As far as my experience is concerned the only "slow" call is the 'elt'
in read-ascii-string. The functions do not seem to cons a lot.

   (defun read-ascii-string (file-stream num-bytes)
     (let ((result (make-string num-bytes)))
       (dotimes (i num-bytes)
	 (setf (elt result i) (code-char (read-byte file-stream))))
       (string-right-trim (list (code-char 0)) result)))

   (defun read-32-bit-integer (file-stream)
     (let ((result 0))
       (dotimes (i 4)
	 (setf result (ash result 8))
	 (incf result (read-byte file-stream)))
       result))

   ;;; (...)

   (defun play-sounds (&optional (sounds '("AA" "r"))
				 &key (blocked nil)
				 (sound-dir *phoneme-directory*)
				 (audio-dev "/dev/audio"))
     (cond (blocked
	    (with-open-file (out *temp-sound-file*
				 :direction :output
				 :if-exists :supersede
				 :if-does-not-exist :create
				 :element-type 'unsigned-byte)
	      (write-sounds sounds sound-dir out))
	    (excl:run-shell-command (format nil "cat ~a > ~a" 
					    *temp-sound-file* audio-dev)))
	   (t
	    (with-open-file (out audio-dev
				 :direction :output
				 :if-exists :overwrite
				 :element-type 'unsigned-byte)
	      (write-sounds sounds sound-dir out)))))


Here is my question. Are there any benchmarks around for I/O done in
CL vs. the usual foes (i.e. C/C++)? I believe this would be another
valuable piece of information regarding CL implementations.

Thanks for your time,
have a nice day

Marco
From: Doug Cutting
Subject: Re: CL I/O performance (Was: Playing sparcaudio directly from lisp)
Date: 
Message-ID: <CUTTING.93Jan11105659@skye.parc.xerox.com>
In article <··················@maya.cs.nyu.edu> ·······@maya.CS.nyu.EDU (Marco Antoniotti) writes:
> In article <············@cs.cmu.edu> ······@cs.cmu.edu (Mark Kantrowitz) writes:
>    I wrote the following code for Allegro CL. As you can see by
>    experimentation with the code and variations on it, playing the sound
>    files from Lisp is much too slow. Lisp file IO just isn't fast enough.
>    If you're going to play sound files, you'll have to do much of the
>    work in C, and then use a foreign function interface to run the code. 
> 
> This is an interesting remark. I ran through the code and I sincerely
> do not understand why a Lisp application should be "slower" doing
> IO than a C/C++ application.
> 
> As far as my experience is concerned the only "slow" call is the 'elt'
> in read-ascii-string. The functions do not seem to cons a lot.

There are several things in Common Lisp which make it difficult to
implement I/O as quickly as does C.  These include:

1. CL I/O functions can't specialize on the stream argument.

CL allows for many different types of streams (string, file,
concatenated, etc).  This suggests a CLOS implementation of the stream
functions, with a one method dispatch overhead for each call.
Unfortunately, the stream argument to most calls is optional, and
hence cannot be specialized.  Hence a CLOS implementation of CL I/O
must have a DEFUN'ed veneer to do the argument defaulting.  A cleanup
proposal (STREAM-DEFINITION-BY-USER) was made to standardize the
generic function level interface, but it has not been adopted.

2. CL stream types can't be adequately declared.

The compiler might be able optimize calls to (READ-BYTE S) if it knew
that S was the result of (OPEN P :element-type '(UNSIGNED-BYTE 8)),
but one cannot declare the ELEMENT-TYPEs of FILE-STREAMs.

3. 32-bit quantities, natural for file I/O, are usually bignums in CL.

When performing binary I/O, care must be taken to structure things so
that 32-bit quantities are not encountered (16- and 24-bit quantities
are fixnums in most implementations).  Some CL implementations may
provide unboxed 32-bit quantities which substantially ameliorates this
problem.  A rather ugly workaround we've used, when reading 32-bit
quantities which are usually fixnums, is the following:

(defun write-byte32 (byte32 stream)
  (declare (type (unsigned-byte 32) byte32))
  (if (typep byte32 'fixnum)
      (progn
        (byte16-write (ash (the fixnum byte32) -16) stream)
        (byte16-write (logand (the fixnum byte32) #xffff) stream))
    (progn (byte16-write (ash byte32 -16) stream)
           (byte16-write (logand byte32 #xffff) stream))))

(defun read-byte32 (stream)
  (let ((hi16 (byte16-read stream))
        (lo16 (byte16-read stream)))
    (declare (type (unsigned-byte 16) hi16 lo16))
    (if (< hi16 (ash most-positive-fixnum -16))
        (the (or (unsigned-byte 16) fixnum)
          (logior (the (or (unsigned-byte 16) fixnum) (ash hi16 16)) lo16))
      (the (unsigned-byte 32) 
        (+ (the (unsigned-byte 32) (ash hi16 16)) lo16)))))

> Here is my question. Are there any benchmarks around for I/O done in
> CL vs. the usual foes (i.e. C/C++)? I believe this would be another
> valuable piece of information regarding CL implementations.

Not that I know of, though I agree that this is a gap which needs filling.

	Doug