Re: LW compiler optimizations
"David McClain (as dbm at refined-audiometrics dot com)" <[email protected]>
| Newsgroups | gmane.lisp.lispworks.general |
|---|---|
| Message-ID | <[email protected]> |
… however, still 3x slower than using FLI to call vDSP. But in fairness, had I initially achieved this level of speed from Lisp, then I probably wouldn’t have bothered with the FLI to vDSP, and just stayed in Lisp. I should try to examine vDSP dotprD() and see what they are doing. They claim that it is single-threaded, but a case could be made for parallelizing this code, especially given the large size of the FIR vector. These timings hint that they may be using some low-grade SIMD instructions. But I am thoroughly ignorant of the capabilities of the M1 architecture. Do they even have low-grade SIMD like the Intel MMX engine? > On Jan 14, 2025, at 15:21, David McClain (as dbm at refined-audiometrics dot com) <[email protected]> wrote: > > If I rewrite without the displaced array: > > (defun fir-dotpr-loop (fir vec &key (start2 0)) > ;; Fastest so far - 335 μs > ;; #F > (declare (optimize (speed 3) (safety 0) (float 0))) > (declare ((simple-array double-float (*)) fir vec) > (fixnum start2)) > (let* ((sum 0d0) > (nel (length fir))) > (declare (double-float sum) > (fixnum nel)) > (dotimes (ix nel) > (declare (fixnum ix)) > (setq sum > (+ sum > (* (aref fir ix) > (aref vec (+ ix start2)))) > )) > sum)) > > Then my timing drops to 63 μs per iteration, or 1.4 ns/pair. Now we are getting respectably close to C performance. But this indicates that using a displaced array costs me nearly 5x performance degradation, as opposed to your claim of 1% penalty. > > >> On Jan 14, 2025, at 15:04, David McClain <[email protected]> wrote: >> >> Just to remove any doubt, perhaps #F isn’t expanding the way I think it is (although I have looked at the expansion), but let’s redo with explicit OPTIMIZE: >> >> (defun fir-dotpr-loop (fir vec &key (start2 0)) >> ;; Fastest so far - 335 μs >> ;; #F >> (declare (optimize (speed 3) (safety 0) (float 0))) >> (declare ((simple-array double-float (*)) fir vec) >> (fixnum start2)) >> (let* ((sum 0d0) >> (nel (length fir)) >> (v (make-array nel >> :element-type 'double-float >> :displaced-to vec >> :displaced-index-offset start2))) >> (declare (double-float sum) >> (fixnum nel) >> ((vector double-float *) v) >> (dynamic-extent v)) >> (dotimes (ix nel) >> (declare (fixnum ix)) >> (setq sum >> (+ sum >> (* (aref fir ix) >> (aref v ix))))) >> sum)) >> >> Same timing results, 300 μs per iteration of the 1000 TIME test => 45,064 MAC pairs => 6.7 ns/pair >> >>> On Jan 14, 2025, at 14:52, David McClain (as dbm at refined-audiometrics dot com) <[email protected]> wrote: >>> >>> Thank you for sharing that. I tried the DOTIMES with a displaced array. And I incorporated your declare types. My timing is still > 15x slower than the vDSP called from Lisp. >>> >>> Per MAC-pair, my timing shows 6.7 ns/pair, on a 2021 M1 iMac. >>> >>> Specifically: >>> >>> (defun fir-dotpr-loop (fir vec &key (start2 0)) >>> ;; Fastest so far - 335 μs >>> #F >>> (declare ((simple-array double-float (*)) fir vec) >>> (fixnum start2)) >>> (let* ((sum 0d0) >>> (nel (length fir)) >>> (v (make-array nel >>> :element-type 'double-float >>> :displaced-to vec >>> :displaced-index-offset start2))) >>> (declare (double-float sum) >>> (fixnum nel) >>> ((vector double-float *) v) >>> (dynamic-extent v)) >>> (dotimes (ix nel) >>> (declare (fixnum ix)) >>> (setq sum >>> (+ sum >>> (* (aref fir ix) >>> (aref v ix))))) >>> sum)) >>> >>> ;; —————————————— >>> >>> (defparameter *nel* 5633) ;; * 2 arrays, * 4 steps = 45,064 MAC ops/test >>> (defparameter *tst-fir* (make-array *nel* >>> :allocation :pinnable >>> :element-type 'double-float >>> :initial-contents (map 'vector 'dfloat (vm:unoise *nel*)))) >>> (defparameter *tst-arr* (make-array (+ *nel* 1024) >>> :allocation :pinnable >>> :element-type 'double-float >>> :initial-contents (map 'vector 'dfloat (vm:unoise (+ *nel* 1024))))) >>> >>> (defun test-lisp-fir-dotpr-loop () >>> ;; 300 μs >>> (dotimes (ix 4) >>> (declare (fixnum ix)) >>> (let* ((start (* ix 256))) >>> (declare (fixnum start)) >>> (fir-dotpr-loop *tst-fir* *tst-arr* :start2 start) ;; simulate real part >>> (fir-dotpr-loop *tst-fir* *tst-arr* :start2 start)))) >>> >>> (time >>> ;; 300 μs/iter, 37.5 μs/vdot, 6.7 ns/MAC >>> ;; alloc 1,050 bytes/iter, 131 bytes/vdot >>> (loop repeat 1000 do (test-lisp-fir-dotpr-loop))) >>> >>> >>>> On Jan 14, 2025, at 10:47, Tim Bradshaw (as tfb at tfeb dot org) <[email protected]> wrote: >>>> >>>> https://github.com/tfeb/bench-df-aref >>>> >>>> I added some more variants since yesterday, and with the best of them LW is not slower than SBCL and neither is slower than C (or than my C): both are about 0.94ns/step on my M1 machine >>>> >>>> --tim >>>> >>>> _______________________________________________ >>>> Lisp Hug - the mailing list for LispWorks users >>>> [email protected] >>>> http://www.lispworks.com/support/lisp-hug.html >>> >>> >>> _______________________________________________ >>> Lisp Hug - the mailing list for LispWorks users >>> [email protected] >>> http://www.lispworks.com/support/lisp-hug.html >> > > > _______________________________________________ > Lisp Hug - the mailing list for LispWorks users > [email protected] > http://www.lispworks.com/support/lisp-hug.html _______________________________________________ Lisp Hug - the mailing list for LispWorks users [email protected] http://www.lispworks.com/support/lisp-hug.html