Paste number 80464: Complex arithmetic benchmarks

Paste number 80464: Complex arithmetic benchmarks
Pasted by: pkhuong
When:1 year, 3 months ago
Share:Tweet this! | http://paste.lisp.org/+1Q34
Channel:#lisp
Paste contents:
Raw Source | XML | Display As
#|
Original
(COMPLEX IDENTITY (COMPLEX)) (single/double) 905 / 906
(COMPLEX - (COMPLEX)) (single/double) 2315 / 2304
(COMPLEX + (COMPLEX REAL)) (single/double) 1926 / 1921
(COMPLEX + (REAL COMPLEX)) (single/double) 1925 / 1920
(COMPLEX + (COMPLEX COMPLEX)) (single/double) 2434 / 2434
(COMPLEX - (COMPLEX REAL)) (single/double) 1926 / 1921
(COMPLEX - (REAL COMPLEX)) (single/double) 2441 / 2436
(COMPLEX - (COMPLEX COMPLEX)) (single/double) 2436 / 2436
(COMPLEX * (COMPLEX REAL)) (single/double) 1990 / 1928
(COMPLEX * (REAL COMPLEX)) (single/double) 1925 / 2027
(COMPLEX * (COMPLEX COMPLEX)) (single/double) 2952 / 2952
(COMPLEX / (COMPLEX (REAL 1))) (single/double) 7421 / 9842
(COMPLEX / (REAL (COMPLEX #C(1 1)))) (single/double) 14351 / 17680
(COMPLEX / ((COMPLEX #C(1 1)) (COMPLEX #C(-2 -2)))) (single/double) 12810 / 15565
(COMPLEX CONJUGATE (COMPLEX)) (single/double) 1422 / 1677
(T = (COMPLEX REAL)) (single/double) 2189 / 1932
(T = (REAL COMPLEX)) (single/double) 2189 / 1951
(T = (COMPLEX COMPLEX)) (single/double) 2189 / 2189

With VOPs:
(COMPLEX IDENTITY (COMPLEX)) (single/double) 653 / 771
(COMPLEX - (COMPLEX)) (single/double) 1421 / 1205
(COMPLEX + (COMPLEX REAL)) (single/double) 1022 / 915
(COMPLEX + (REAL COMPLEX)) (single/double) 1025 / 915
(COMPLEX + (COMPLEX COMPLEX)) (single/double) 910 / 923
(COMPLEX - (COMPLEX REAL)) (single/double) 1022 / 915
(COMPLEX - (REAL COMPLEX)) (single/double) 1025 / 934
(COMPLEX - (COMPLEX COMPLEX)) (single/double) 934 / 928
(COMPLEX * (COMPLEX REAL)) (single/double) 1143 / 1005
(COMPLEX * (REAL COMPLEX)) (single/double) 1264 / 1187
(COMPLEX * (COMPLEX COMPLEX)) (single/double) 2023 / 2190
(COMPLEX / (COMPLEX (REAL 1))) (single/double) 4857 / 4599
(COMPLEX / (REAL (COMPLEX #C(1 1)))) (single/double) 14871 / 17511
(COMPLEX / ((COMPLEX #C(1 1)) (COMPLEX #C(-2 -2)))) (single/double) 12815 / 14094
(COMPLEX CONJUGATE (COMPLEX)) (single/double) 1086 / 1275
(T = (COMPLEX REAL)) (single/double) 1667 / 1425 ; EQL is even better
(T = (REAL COMPLEX)) (single/double) 1585 / 1426
(T = (COMPLEX COMPLEX)) (single/double) 1473 / 1473

Few VOPs:
(COMPLEX IDENTITY (COMPLEX)) (single/double) 653 / 771
(COMPLEX - (COMPLEX)) (single/double) 1421 / 1205
(COMPLEX + (COMPLEX REAL)) (single/double) 2314 / 1509
(COMPLEX + (REAL COMPLEX)) (single/double) 3201 / 2430
(COMPLEX + (COMPLEX COMPLEX)) (single/double) 935 / 910
(COMPLEX - (COMPLEX REAL)) (single/double) 2313 / 1508
(COMPLEX - (REAL COMPLEX)) (single/double) 3201 / 2430
(COMPLEX - (COMPLEX COMPLEX)) (single/double) 935 / 910
(COMPLEX * (COMPLEX REAL)) (single/double) 1415 / 1416
(COMPLEX * (REAL COMPLEX)) (single/double) 2423 / 2424
(COMPLEX * (COMPLEX COMPLEX)) (single/double) 3461 / 3460
(COMPLEX / (COMPLEX (REAL 1))) (single/double) 4857 / 4597
(COMPLEX / (REAL (COMPLEX #C(1 1)))) (single/double) 12814 / 12706
(COMPLEX / ((COMPLEX #C(1 1)) (COMPLEX #C(-2 -2)))) (single/double) 15239 / 16009
(COMPLEX CONJUGATE (COMPLEX)) (single/double) 1086 / 1275
(T = (COMPLEX REAL)) (single/double) 1667 / 1426
(T = (REAL COMPLEX)) (single/double) 1586 / 1426
(T = (COMPLEX COMPLEX)) (single/double) 1461 / 1474
|#

;; for some reason the sequence below isn't open coded...

(in-package "SB-C")
(deftransform / ((x y) (single-float (complex single-float)) *)
  `(/ (complex x ,(coerce 0 'single-float)) y))
(deftransform / ((x y) (double-float (complex double-float)) *)
  `(/ (complex x ,(coerce 0 'double-float)) y))
;;; Define some transforms for complex operations. We do this in lieu
;;; of complex operation VOPs.
(macrolet ((frob (type)
             `(progn
                #-sb-xc-host
                (deftransform complex ((r) (,type))
                  `(complex r ,(coerce 0 ',type)))
               ;; negation
                #-x86-64
               (deftransform %negate ((z) ((complex ,type)) *)
                 '(complex (%negate (realpart z)) (%negate (imagpart z))))
               ;; complex addition and subtraction
               #-x86-64
               (deftransform + ((w z) ((complex ,type) (complex ,type)) *)
                 '(complex (+ (realpart w) (realpart z))
                           (+ (imagpart w) (imagpart z))))
               #-x86-64
               (deftransform - ((w z) ((complex ,type) (complex ,type)) *)
                 '(complex (- (realpart w) (realpart z))
                           (- (imagpart w) (imagpart z))))
               ;; Add and subtract a complex and a real.
               (deftransform + ((w z) ((complex ,type) real) *)
                 #-x86-64
                 '(complex (+ (realpart w) z) (imagpart w))
                 #+x86-64
                 `(+ w (complex z)))
               (deftransform + ((z w) (real (complex ,type)) *)
                 #-x86-64
                 '(complex (+ (realpart w) z) (imagpart w))
                 #+x86-64
                 `(+ (complex z) w))
               ;; Add and subtract a real and a complex number.
               (deftransform - ((w z) ((complex ,type) real) *)
                 #-x86-64
                 '(complex (- (realpart w) z) (imagpart w))
                 #+x86-64
                 `(- w (complex z)))
               (deftransform - ((z w) (real (complex ,type)) *)
                 #-x86-64
                 '(complex (- z (realpart w)) (- (imagpart w)))
                 #+x86-64
                 `(- (complex z) w))
               ;; Multiply and divide two complex numbers.
               (deftransform * ((x y) ((complex ,type) (complex ,type)) *)
                 '(let* ((rx (realpart x))
                         (ix (imagpart x))
                         (ry (realpart y))
                         (iy (imagpart y)))
                   (declare (ignorable ry iy))
                   #+x86-64
                   (+ (%pairwise-* (complex rx rx) y)
                      (%pairwise-* (complex ix ix) (%negate-real (%complex-swap y))))
                   #-x86-64
                    (complex (- (* rx ry) (* ix iy))
                             (+ (* rx iy) (* ix ry)))))
               (deftransform / ((x y) (,type (complex ,type)) *)
                 `(/ (complex x) y))
               (deftransform / ((x y) ((complex ,type) (complex ,type)) *)
                 '(let* ((rx (realpart x))
                         (ix (imagpart x))
                         (ry (realpart y))
                         (iy (imagpart y))
                         (swap (%complex-swap (%negate-real x))))
                   (declare (ignorable rx ix))
                   (multiple-value-call #'/
                     (if (> (abs ry) (abs iy))
                         (let* ((r (/ iy ry))
                                (dn (* ry (+ 1 (* r r)))))
                           (values (+ x (* swap r)) dn))
                         (let* ((r (/ ry iy))
                                (dn (* iy (+ 1 (* r r)))))
                           (values (+ (* x r) swap) dn))))))
               ;; Multiply a complex by a real or vice versa.
               (deftransform * ((w z) ((complex ,type) real) *)
                 #-x86-64
                 '(complex (* (realpart w) z) (* (imagpart w) z))
                 #+x86-64
                 '(%pairwise-* w (complex z z)))
               (deftransform * ((z w) (real (complex ,type)) *)
                 #-x86-64
                 '(complex (* (realpart w) z) (* (imagpart w) z))
                 #+x86-64
                 '(%pairwise-* (complex z z) w))
               ;; Divide a complex by a real.
               #-x86-64
               (deftransform / ((w z) ((complex ,type) real) *)
                 '(complex (/ (realpart w) z) (/ (imagpart w) z)))
               ;; conjugate of complex number
               #-x86-64
               (deftransform conjugate ((z) ((complex ,type)) *)
                 '(complex (realpart z) (- (imagpart z))))
               ;; CIS
               (deftransform cis ((z) ((,type)) *)
                 '(complex (cos z) (sin z)))
               ;; comparison
               #-x86-64
               (deftransform = ((w z) ((complex ,type) (complex ,type)) *)
                 '(and (= (realpart w) (realpart z))
                       (= (imagpart w) (imagpart z))))
               #-x86-64
               (deftransform = ((w z) ((complex ,type) real) *)
                 '(and (= (realpart w) z) (zerop (imagpart w))))
               #-x86-64
               (deftransform = ((w z) (real (complex ,type)) *)
                 '(and (= (realpart z) w) (zerop (imagpart z)))))))

  (frob single-float)
  (frob double-float))
(in-package "CL-USER")

(defun bench (n fun)
  (declare (type unsigned-byte n))
  (unless (functionp fun)
    (setf fun (fdefinition fun)))
  (aref (sort (map-into (make-array n :element-type `(unsigned-byte ,sb-vm:n-word-bits))
                        (lambda ()
                          (declare (type function fun))
                          (nth-value
                           1
                           (sb-vm::with-cycle-counter
                             (funcall fun)))))
              #'<)
        (truncate n 2)))

(defmacro test-fun (fun ret (&rest args) &key (n 100000) (m 256) (float-type 'double-float))
  (let* ((inits '())
         (types (prog1
                    (mapcar (lambda (type)
                              (push (and (consp type)
                                         (prog1 (second type)
                                           (setf type (car type))))
                                    inits)
                              (case type
                                (real
                                   float-type)
                                (complex
                                   `(complex ,float-type))
                                (t type)))
                            (cons ret args))
                  (setf inits (nreverse inits))))
         (vars (loop for x in types
                     collect (gensym "VEC"))))
    `(let ,(mapcar (lambda (var type init)
                     `(,var (make-array ,m :element-type ',type
                                        ,@(and init
                                               `(:initial-element ,(coerce init type))))))
            vars types inits)
       (declare ,@(mapcar (lambda (var type)
                            `(type (simple-array ,type (,m)) ,var))
                          vars types))
       (bench ,n (lambda ()
                   (declare (optimize speed))
                   (map-into ,(first vars) #',fun ,@(rest vars)))))))

(defun run ()
  (macrolet
      ((run (&body settings)
         `(progn
            ,@(loop for (ret fun . args) in settings
                    collect
                    `(format t "~S (single/double) ~A / ~A~%"
                             '(,ret ,fun ,args)
                              (test-fun ,fun ,ret ,args
                                   :float-type single-float)
                              (test-fun ,fun ,ret ,args
                                   :float-type double-float))))))
    (run (complex identity complex)
         (complex - complex)
         (complex + complex real)
         (complex + real complex)
         (complex + complex complex)
         (complex - complex real)
         (complex - real complex)
         (complex - complex complex)
         (complex * complex real)
         (complex * real complex)
         (complex * complex complex)
         (complex / complex (real 1))
         (complex / real (complex #c(1 1)))
         (complex / (complex #c(1 1)) (complex #c(-2 -2)))
         (complex conjugate complex)
         (t       = complex real)
         (t       = real complex)
         (t       = complex complex))))

This paste has no annotations.

Colorize as:
Show Line Numbers

Lisppaste pastes can be made by anyone at any time. Imagine a fearsomely comprehensive disclaimer of liability. Now fear, comprehensively.