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
;;