Ray,

1.  First, I reviewed my notes...the "rule of thumb" I abide by
     is "don't use AREF when lots of referencing is required".  In
     hast I extended this as a fact for the VEC3 case in this thread.
     The specific problem I had was a RANK = 3 problem where abandoning
     AREF and using displaced arrays and ELT results in a factor
     of 100 improvement in execution speed.  At the bottom of this
     e-mail two variations of SUB-ARRAY demonstrate this change.

2.  This AREF execution speed problem seems limited to array's
     with RANK > 1.  The following shows that for RANK = 1 arrays
     the timing is the same.

3.  Sorry about the mis-information.

mike

(setf size 100000
       tmpv
       (make-array size
                  :element-type '(complex single-float)
                  :initial-contents (let ((ans))
                                      (dotimes (n size ans)
                                        (push (complex (random 10.0) (random 10.0)) 
ans))))
       tmparef (make-array size :element-type '(complex single-float))
       tmpelt  (make-array size :element-type '(complex single-float))
       done t)
                        

(time (dotimes (monte 100) (dotimes (n size) (setf (aref tmparef n) (aref tmpv n)))))
(time (dotimes (monte 100) (dotimes (n size) (setf (elt tmpelt n)   (elt tmpv n)))))

; Evaluation took:
;   2.01 seconds of real time
;   1.72 seconds of user run time
;   0.28 seconds of system run time
;   6,130,503,328 CPU cycles
;   [Run times include 0.28 seconds GC run time]
;   0 page faults and
;   160,000,896 bytes consed.
;
; Compiling LAMBDA NIL:
; Compiling Top-Level Form:

; Evaluation took:
;   2.08 seconds of real time
;   1.85 seconds of user run time
;   0.23 seconds of system run time
;   6,358,848,844 CPU cycles
;   [Run times include 0.24 seconds GC run time]
;   0 page faults and
;   160,000,896 bytes consed.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;                     SUB-ARRAY VERSION USES AREF
(defun sub-array (array &rest index-specs)
   "
   SYNTAX
   ======
   (SUB-ARRAY ARRAY INDEX0-SPEC INDEX1-SPEC ... )

   INPUT
   -----
   ARRAY      An ARRAY of rank N
   INDEX-SPEC There must be one INDEX-SPEC for each dimension of ARRAY
              One of the following:
              (ISEQ START STEP STOP)
              :ALL    Expands to (ISEQ 0 1 (ARRAY-DIMENSION ARRAY N))
              :EVEN   Expands to (ISEQ 0 2 (ARRAY-DIMENSION ARRAY N))
              :ODD    Expands to (ISEQ 1 2 (ARRAY-DIMENSION ARRAY N))

   OUTPUT
   ------
   ARRY    A new array made up of the specified entries of ARRAY."

   ;; Idiot check
   (unless (= (array-rank array) (length index-specs))
     (error "Insufficient INDEX-SPECIFICATION for given ARRAY."))

   (multiple-value-bind (array-indexes array-dims)
       (apply #'translate-index-specs array index-specs)
     (let* (
         (new-array (make-array array-dims
                                :element-type (array-element-type array)))
         ;; and create a displaced array
         (new-array-displaced (make-array (array-total-size new-array)
                                          :element-type (array-element-type array)
                                          :displaced-to new-array)))
       ;; now populate and return the new-array
       (dotimes (n (array-total-size new-array) new-array)
        (setf (aref new-array-displaced n)
              (apply #'aref array (nth n array-indexes)))))))

;; (progn (setf tmpa (make-array '(201 360 18) :element-type '(complex single-float))) 
t)
;; (dotimes (a 201)
;;   (dotimes (b 360)
;;     (dotimes (c 18) (setf (aref tmpa a b c) (complex (+ a b c) 0.0)))))
;;
;; (progn (profile:unprofile)
;;        (profile:reset-time)
;;        (profile:profile-all)
;;        ;; (profile:profile aref apply setf)
;;        (sub-array tmpa :all (m:seq 0 10 359) :all)
;;        (profile:report-time)
;;        (profile:unprofile))
;;
;;   Consed    |   Calls   |    Secs   | Sec/Call  | Bytes/C.  | Name:
;; -----------------------------------------------------------------------
;;   6,252,136 |         1 |    27.100 |  27.10000 | 6,252,136 | SUB-ARRAY
;;   9,378,080 |         1 |     0.240 |   0.24000 | 9,378,080 | TRANSLATE-INDEX-SPECS
;;   5,338,584 |         1 |     0.040 |   0.04000 | 5,338,584 | CARTESIAN-PRODUCT
;;     385,672 |         1 |     0.020 |   0.02000 |   385,672 | CUMPROD
;;       1,752 |         2 |     0.000 |   0.00000 |       876 | ISEQ
;; -------------------------------------------------------------------
;;  21,356,224 |         6 |    27.400 |           |           | Total


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;           THIS VERSION USES ELT AND DISPLACED ARRAYS
(defun sub-array (array &rest index-specs)
   "
   SYNTAX
   ======
   (SUB-ARRAY ARRAY INDEX0-SPEC INDEX1-SPEC ... )

   INPUT
   -----
   ARRAY      An ARRAY of rank N
   INDEX-SPEC There must be one INDEX-SPEC for each dimension of ARRAY
              One of the following:
              (ISEQ START STEP STOP)
              :ALL    Expands to (ISEQ 0 1 (ARRAY-DIMENSION ARRAY N))
              :EVEN   Expands to (ISEQ 0 2 (ARRAY-DIMENSION ARRAY N))
              :ODD    Expands to (ISEQ 1 2 (ARRAY-DIMENSION ARRAY N))

   OUTPUT
   ------
   ARRY    A new array made up of the specified entries of ARRAY."

   ;; Idiot check
   (unless (= (array-rank array) (length index-specs))
     (error "Insufficient INDEX-SPECIFICATION for given ARRAY."))

   (multiple-value-bind (array-indexes array-dims row-major-indexes)
       (apply #'translate-index-specs array index-specs)
     (declare (ignore array-indexes))

     (let* ((da (sequence-displaced-to array))
           (new-vector (make-array (length row-major-indexes)
                                   :element-type (array-element-type array)
                                   :initial-contents
                                   ;; extract the decimated data
                                   (let ((new))
                                     (dolist (rmi row-major-indexes (nreverse new))
                                       (push (elt da rmi) new)))))
           (new-array (make-array array-dims
                                :element-type (array-element-type array)
                                :displaced-to new-vector)))

       new-array)))

;; (progn (setf tmpa (make-array '(201 360 18) :element-type '(complex single-float))) 
t)
;; (dotimes (a 201)
;;   (dotimes (b 360)
;;     (dotimes (c 18) (setf (aref tmpa a b c) (complex (+ a b c) 0.0)))))
;;
;; (progn (profile:unprofile)
;;        (profile:reset-time)
;;        (profile:profile-all)
;;        ;; (profile:profile aref apply setf)
;;        (sub-array tmpa :all (m:seq 0 10 359) :all)
;;        (profile:report-time)
;;        (profile:unprofile))
;;
;;   Consed    |   Calls   |    Secs   | Sec/Call  | Bytes/C.  | Name:
;; -----------------------------------------------------------------------
;;   9,378,080 |         1 |     0.140 |   0.14000 | 9,378,080 | TRANSLATE-INDEX-SPECS
;;   5,338,648 |         1 |     0.120 |   0.12000 | 5,338,648 | CARTESIAN-PRODUCT
;;   4,168,056 |         1 |     0.050 |   0.05000 | 4,168,056 | SUB-ARRAY
;;       1,752 |         2 |     0.000 |   0.00000 |       876 | ISEQ
;;          24 |         1 |     0.000 |   0.00000 |        24 | CUMPROD
;;          88 |         1 |     0.000 |   0.00000 |        88 | SEQUENCE-DISPLACED-TO
;; -------------------------------------------------------------------
;;  18,886,648 |         7 |     0.310 |           |           | Total
;;


Reply via email to