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

[no subject]



So 7.1% of these function definitions take &rest arguments.  (Including
NIL specific &Restv, &Restl.)

Too many assumptions must be made for a realistic estimate of
the actual optimization value of specially handling &rest
lists to be made using these numbers.  These numbers all
refer to source code statistics, while the actual optimization
depends upon instruction stream characteristics.  However,
the fact that &Rest is used in a small minority of function
definitions, while APPLY is very rare strongly suggests that
their combined use in a single function call is very rare
indeed.  Consequently these statistics do not support the idea
that this case needs to be highly optimized.

The 70 Explorer LISP package (i.e.  Common Lisp) functions with &Rest
arguments are:

------------------------------------------------------
;;; Unclassified:

MAPHASH MAKE-CONCATENATED-STREAM ARRAY-ROW-MAJOR-INDEX
MAKE-BROADCAST-STREAM ADJUST-ARRAY ROOM

;;; IO Functions:

YES-OR-NO-P CERROR ERROR FORMAT WARN BREAK Y-OR-N-P

;;; Primitives perhaps known to the compiler:

APPEND MAPC = MAX NOTANY SBIT BIT < MAPCON /= MAPLIST LIST* MAPCAN AREF
ARRAY-IN-BOUNDS-P / CONCATENATE MAPCAR MAPL - VECTOR FUNCALL MIN XOR
EVERY NOTEVERY <= APPLY + MAP VALUES * >= SOME LIST NCONC IGNORE >

LOGIOR LOGEQV LOGXOR LOGAND LCM GCD BOOLE
CHAR-NOT-GREATERP CHAR-NOT-LESSP CHAR-NOT-EQUAL CHAR> CHAR< CHAR/=
CHAR-EQUAL CHAR= CHAR<= CHAR-LESSP CHAR-GREATERP CHAR>=
------------------------------------------------------

The overall importance of optimizing CONSing also depends upon the speed
of CONSing.  Since one of the most important known uses of APPLY where
&Rest arguments are an issue involves calling FORMAT it is important to
compare CONSing speed with I/O speed.  On an Explorer II, GC-ON,
everything compiled:

Function            Calls    Time   Normalized to 1,000,000 Calls
-------------------------------------------------------------------
(foo (cons 1 2)) 10,000,000  140.8       14.8
NIL               1,000,000    1.3        1.3
(foo 2)           1,000,000    4.53       4.53
(write-char #\a)     10,000    3.74     374.0
(probe-file ...)        100   43.7  437,000
[using a string as a pathname, non-local file,
connection already established.]

FOO is a null function needed to prevent optimization.
(dotimes (i 10000000) (cons 1 2)) is optimized to:
(dotimes (i 10000000) nil) so:
(dotimes (i 10000000) (foo (cons 1 2))) must be used
instead.  FOO is defined with:

(defun foo (x) x)

On the basis of this I conclude that the common idiom
(apply #'format ...) does not deserve special attention
to the number of CONSes performed in creating the &Rest list
for FORMAT.

=================================================================
The actual functions used to collect some of this data follow.

;;; -*- Mode:Common-Lisp; Package:USER; Base:10 -*-
(defvar *count* 0)
(defvar *not-count* 0)
(defvar *fns* nil)

(defun rest-p (x) 
  (cond ((and (not (macro-function x))
              (not (special-form-p x))
              (member '&rest (arglist x)))
         (push x *fns*)
         (incf *count*) t)
        (t (incf *not-count*)
           nil)))

(defun test (pkg)
  (setq *count* 0)
  (setq *not-count* 0)
  (setq *fns* nil)
  (apropos "" :package pkg :inherited nil :predicate #'rest-p :fboundp t :inheritors nil)
  (format t "~&There are ~a functions with &Rest arguments, ~a without in package ~a"
          *count* *not-count* pkg))

(defun file-search (file str)
  (let ((count 0)
        (lines 0))
    (with-open-file (stream file)
      (loop for line = (read-line stream nil nil)
            while line
            do (incf lines)
               (when (search str line :test #'char-equal)
                 (format t "~&~a" line)
                 (incf count))))
    (values count lines)))

(defun file-search-list (files str)
  (let ((count 0)
        (lines 0))
    (dolist (file files)
      (multiple-value-bind (a b) (file-search file str)
        (setq count (+ count a))
        (setq lines (+ lines b))
        (format t "~&File ~a Count ~a; lines  ~a Total count ~a, lines ~a" file a b count lines)))
    (format t "~&Grand Total count ~a; lines ~a" count lines)
    (values count lines)))

;;; (file-search-list (pathname "nil$disk:[nil.h]*.lsp") "(APPLY")