Re: LW compiler optimizations
"David McClain (as dbm at refined-audiometrics dot com)" <[email protected]>
| Newsgroups | gmane.lisp.lispworks.general |
|---|---|
| Message-ID | <[email protected]> |
Examination of the disassembly of the Lisp code shows that boxing is still occurring on the result of the add to sum.
So I thought about the trick I discovered yesterday, and decided to try the sum being a 1 element array, now declared as a simple-array.
Sure enough:
(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 (make-array 1
:element-type 'double-float
:initial-element 0d0))
(nel (length fir)))
(declare ((simple-array double-float (1)) sum)
(fixnum nel))
(dotimes (ix nel)
(declare (fixnum ix))
(setf (aref sum 0)
(+ (aref sum 0)
(* (aref fir ix)
(aref vec (+ ix start2))))
))
(aref sum 0)))
The timing has dropped from 63 μs per iter to only 18.2 μs, or 0.4 ns/pair !! Matches the speed of vDSP through the FLI. So now there is a strong reason to stay in Lisp.
Yipee!!
> On Jan 14, 2025, at 15:35, David McClain (as dbm at refined-audiometrics dot com) <[email protected]> wrote:
>
> … 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
_______________________________________________
Lisp Hug - the mailing list for LispWorks users
[email protected]
http://www.lispworks.com/support/lisp-hug.html