bench.scm 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. ; -*- mode: scheme; coding: utf-8 -*-
  2. ; Replacement for Guile C-based array system - Benchmarks
  3. ; (c) Daniel Llorens - 2016-2021
  4. ; This library is free software; you can redistribute it and/or modify it under
  5. ; the terms of the GNU General Public License as published by the Free
  6. ; Software Foundation; either version 3 of the License, or (at your option) any
  7. ; later version.
  8. ; Run with $GUILE -L mod bench.scm
  9. (import (newra) (newra tools) (newra read)
  10. (only (newra print) ra-print) (newra test misc)
  11. (ice-9 popen) (ice-9 rdelim) (srfi :26) (srfi :8) (srfi :19)
  12. (only (srfi :1) fold iota) (rnrs bytevectors) (ice-9 match) (ice-9 format)
  13. (only (srfi :43) vector-copy!) (only (rnrs base) vector-map))
  14. (define (command-output cmd . args)
  15. (let* ((p (apply open-pipe* OPEN_READ cmd args))
  16. (s (read-delimited "" p))
  17. (ec (status:exit-val (close-pipe p))))
  18. (values s ec)))
  19. (format #t "Guile ~a\n~!" (version))
  20. (format #t "newra ~a ~a\n~!"
  21. (string-trim-both (command-output "git" "describe" "--always" "--dirty"))
  22. (date->string (current-date) "~4"))
  23. (define (format-header . x)
  24. (apply format #t
  25. (string-append (apply string-append "~30t" (map (const "~15@a") x))
  26. "\n")
  27. x))
  28. (define (format-line . x)
  29. (apply format #t
  30. (string-append (apply string-append "~30t" (map (const "~15,3f") x))
  31. "\n")
  32. x))
  33. ; -----------------------
  34. ; benchmarks
  35. ; -----------------------
  36. (let ((m #e1e5))
  37. (format #t "\nlookup\n==================\n")
  38. (for-each
  39. (lambda (type)
  40. (format #t "\n~a\n---------" type)
  41. (format-header "ra-ref" "ra-cell" "ra-appl" "array-ref")
  42. (for-each
  43. (lambda (rank)
  44. (let* ((n (inexact->exact (ceiling (expt m (/ rank)))))
  45. (nn (make-list rank n))
  46. (len (fold * 1 nn))
  47. (scale (* 1e3 (/ m len)))
  48. (ra (as-ra (make-ra-root (make-aseq) (apply c-dims nn)) #:type type))
  49. (a (ra->array ra))
  50. (ras 0)
  51. (as 0)
  52. ; FIXME test ra-ref / ra-cell / (ra ...)
  53. (raf-ref (case-lambda ((i) (set! ras (+ ras (ra-ref ra i))))
  54. ((i j) (set! ras (+ ras (ra-ref ra i j))))
  55. ((i j k) (set! ras (+ ras (ra-ref ra i j k))))
  56. ((i j k l) (set! ras (+ ras (ra-ref ra i j k l))))
  57. ((i j k l m) (set! ras (+ ras (ra-ref ra i j k l m))))))
  58. (raf-cell (case-lambda ((i) (set! ras (+ ras (ra-cell ra i))))
  59. ((i j) (set! ras (+ ras (ra-cell ra i j))))
  60. ((i j k) (set! ras (+ ras (ra-cell ra i j k))))
  61. ((i j k l) (set! ras (+ ras (ra-cell ra i j k l))))
  62. ((i j k l m) (set! ras (+ ras (ra-cell ra i j k l m))))))
  63. (raf-appl (case-lambda ((i) (set! ras (+ ras (ra i))))
  64. ((i j) (set! ras (+ ras (ra i j))))
  65. ((i j k) (set! ras (+ ras (ra i j k))))
  66. ((i j k l) (set! ras (+ ras (ra i j k l))))
  67. ((i j k l m) (set! ras (+ ras (ra i j k l m))))))
  68. (af (case-lambda ((i) (set! as (+ as (array-ref a i))))
  69. ((i j) (set! as (+ as (array-ref a i j))))
  70. ((i j k) (set! as (+ ras (array-ref a i j k))))
  71. ((i j k l) (set! as (+ ras (array-ref a i j k l))))
  72. ((i j k l m) (set! as (+ ras (array-ref a i j k l m)))))))
  73. (unless (= ras as) (throw 'error-in-ra-cell-array-ref-check))
  74. (format #t "rank ~a ~a:" rank nn)
  75. (format-line (* scale (time (ra-loop ra raf-ref)))
  76. (* scale (time (ra-loop ra raf-cell)))
  77. (* scale (time (ra-loop ra raf-appl)))
  78. (* scale (time (array-loop a af))))))
  79. (iota 5 1)))
  80. '(#t f64)))
  81. (let ((m #e1e5))
  82. (format #t "\niteration\n==================\n")
  83. (for-each
  84. (lambda (type)
  85. (for-each
  86. (lambda (nargs)
  87. (format #t "\n~a ~a args\n---------" type nargs)
  88. (format-header "ra-sfe" "array-sfe" "ra-map" "array-map" "ra-fe" "array-fe")
  89. (for-each
  90. (lambda (rank)
  91. (let* ((n (inexact->exact (ceiling (expt m (/ rank)))))
  92. (nn (make-list rank n))
  93. (len (fold * 1 nn))
  94. (scale (* 1e3 (/ m len)))
  95. (ra20 (make-ra-new type *unspecified* (apply c-dims nn)))
  96. (ra21 (ra-map*! ra-slice-for-each (make-ra-new type 0 (apply c-dims nn)) (cut random n)))
  97. (ra22 (ra-map*! ra-slice-for-each (make-ra-new type 0 (apply c-dims nn)) (cut random n)))
  98. (ra23 (ra-map*! ra-slice-for-each (make-ra-new type 0 (apply c-dims nn)) (cut random n)))
  99. (a20 (ra->array ra20))
  100. (a21 (ra->array ra21))
  101. (a22 (ra->array ra22))
  102. (a23 (ra->array ra23)))
  103. (let-syntax ((feop
  104. (syntax-rules ()
  105. ((_ fe a ...)
  106. (let ((k 0)) (fe (lambda (a ...) (set! k (+ k a ...))) a ...))))))
  107. (format #t "rank ~a ~a:" rank nn)
  108. (case nargs
  109. ((4)
  110. (format-line (* scale (time (ra-map*! ra-slice-for-each ra20 - ra21 ra22 ra23)))
  111. (* scale (time (array-map*! a20 - a21 a22 a23)))
  112. (* scale (time (ra-map! ra20 - ra21 ra22 ra23)))
  113. (* scale (time (array-map! a20 - a21 a22 a23)))
  114. (* scale (time (feop ra-for-each ra20 ra21 ra22 ra23)))
  115. (* scale (time (feop array-for-each a20 a21 a22 a23)))))
  116. ((3)
  117. (format-line (* scale (time (ra-map*! ra-slice-for-each ra20 - ra21 ra22)))
  118. (* scale (time (array-map*! a20 - a21 a22)))
  119. (* scale (time (ra-map! ra20 - ra21 ra22)))
  120. (* scale (time (array-map! a20 - a21 a22)))
  121. (* scale (time (feop ra-for-each ra20 ra21 ra22)))
  122. (* scale (time (feop array-for-each a20 a21 a22)))))
  123. ((2)
  124. (format-line (* scale (time (ra-map*! ra-slice-for-each ra20 - ra21)))
  125. (* scale (time (array-map*! a20 - a21)))
  126. (* scale (time (ra-map! ra20 - ra21)))
  127. (* scale (time (array-map! a20 - a21)))
  128. (* scale (time (feop ra-for-each ra20 ra21)))
  129. (* scale (time (feop array-for-each a20 a21)))))
  130. ((1)
  131. (format-line (* scale (time (ra-map*! ra-slice-for-each ra20 (cut random n))))
  132. (* scale (time (array-map*! a20 (cut random n))))
  133. (* scale (time (ra-map! ra20 (cut random n))))
  134. (* scale (time (array-map! a20 (cut random n))))
  135. (* scale (time (feop ra-for-each ra20)))
  136. (* scale (time (feop array-for-each a20)))))))))
  137. (iota 6 1)))
  138. (iota 4 1)))
  139. '(#t f64)))
  140. (let ((m #e5e5))
  141. (format #t "\ncopy\n==================\n")
  142. (for-each
  143. (match-lambda
  144. ((typesrc typedst transposed?)
  145. (format #t "\nsrc ~a -> dst ~a transposed: ~a\n---------" typesrc typedst transposed?)
  146. (format-header "ra" "array")
  147. (for-each
  148. (lambda (rank)
  149. (let* ((n (inexact->exact (ceiling (expt m (/ rank)))))
  150. (nn (make-list rank n))
  151. (len (fold * 1 nn))
  152. (scale (* 1e3 (/ m len)))
  153. (ra20 (make-ra-new typesrc *unspecified* (apply c-dims nn)))
  154. (ra21 (ra-map! (make-ra-new typedst 0 (apply c-dims nn)) (cut random n)))
  155. (ra21 (if transposed?
  156. (apply ra-transpose ra21 (reverse (iota rank)))
  157. ra21))
  158. (a20 (ra->array ra20))
  159. (a21 (ra->array ra21)))
  160. (format #t "rank ~a ~a:" rank nn)
  161. (format-line (* scale (time (ra-copy! ra20 ra21)))
  162. (* scale (time (array-copy! a21 a20))))))
  163. (iota 6 1))))
  164. '((#t #t #f)
  165. (f64 f64 #f)
  166. (#t f64 #f)
  167. (#t #t #t)
  168. (f64 f64 #t)
  169. (#t f64 #t))))
  170. (for-each
  171. (lambda (type native-copy! native-length)
  172. (let ((m #e1e7)
  173. (rank 1)
  174. (typesrc type)
  175. (typedst type))
  176. (format #t "\n~a ra-copy! array-copy! native-copy!\n==================\n" typesrc)
  177. (let* ((n (inexact->exact (ceiling (expt m (/ rank)))))
  178. (nn (make-list rank n))
  179. (len (fold * 1 nn))
  180. (scale (* 1e3 (/ m len)))
  181. (ra20 (make-ra-new typesrc *unspecified* (apply c-dims nn)))
  182. (ra21 (make-ra-new typedst 0 (apply c-dims nn)))
  183. (ra21 (ra-map! ra21 (cut random 256)))
  184. (a20 (ra->array ra20))
  185. (a21 (ra->array ra21)))
  186. (format #t "rank ~a ~a:" rank nn)
  187. (format-line (* scale (time (ra-copy! ra20 ra21)))
  188. (* scale (time (array-copy! a21 a20)))
  189. (* scale (time (native-copy! a21 0 a20 0 (native-length a21))))))))
  190. (list #t 'f64)
  191. (list vector-copy! bytevector-copy!)
  192. (list vector-length bytevector-length))
  193. (let ((m #e5e5))
  194. (format #t "\nra-fill! array-fill!\n==================\n")
  195. (for-each
  196. (lambda (type transposed?)
  197. (format #t "\ndst ~a transposed: ~a\n----------" type transposed?)
  198. (format-header "ra" "array")
  199. (for-each
  200. (lambda (rank)
  201. (let* ((n (inexact->exact (ceiling (expt m (/ rank)))))
  202. (nn (make-list rank n))
  203. (len (fold * 1 nn))
  204. (scale (* 1e3 (/ m len)))
  205. (ra20 (make-ra-new type *unspecified* (apply c-dims nn)))
  206. (ra20 (if transposed?
  207. (apply ra-transpose ra20 (reverse (iota rank)))
  208. ra20))
  209. (a20 (ra->array ra20)))
  210. (format #t "rank ~a ~a:" rank nn)
  211. (format-line (* scale (time (ra-fill! ra20 77)))
  212. (* scale (time (array-fill! a20 77))))))
  213. (iota 6 1)))
  214. (list #t 'f64 'u8 #t 'f64 'u8)
  215. (list #f #f #f #t #t #t)))
  216. (for-each
  217. (lambda (type native-fill!)
  218. (let ((m #e1e7)
  219. (rank 1))
  220. (format #t "\ndst ~a ra-fill! array-fill! native-fill!\n==================\n" type)
  221. (format-header "ra" "array" "native")
  222. (let* ((n (inexact->exact (ceiling (expt m (/ rank)))))
  223. (nn (make-list rank n))
  224. (len (fold * 1 nn))
  225. (scale (* 1e3 (/ m len)))
  226. (ra20 (make-ra-new type *unspecified* (apply c-dims nn)))
  227. (a20 (ra->array ra20)))
  228. (format #t "rank ~a ~a:" rank nn)
  229. (format-line (* scale (time (ra-fill! ra20 77)))
  230. (* scale (time (array-fill! a20 77)))
  231. (* scale (time (native-fill! a20 77)))))))
  232. ; would bench 'f64 but there's no f64vector-fill!
  233. (list #t 'u8)
  234. (list vector-fill! bytevector-fill!))
  235. (let ((m #e5e5))
  236. (format #t "\nra-equal? array-equal?\n==================\n")
  237. (for-each
  238. (lambda (type)
  239. (format #t "\ndst ~a\n----------" type)
  240. (format-header "ra" "array")
  241. (for-each
  242. (lambda (rank)
  243. (let* ((n (inexact->exact (ceiling (expt m (/ rank)))))
  244. (nn (make-list rank n))
  245. (len (fold * 1 nn))
  246. (scale (* 1e3 (/ m len)))
  247. (ra20 (ra-map! (make-ra-new type 0 (apply c-dims nn)) (cut random n)))
  248. (ra21 (ra-copy ra20))
  249. (ra22 (apply ra-amend! (ra-copy ra21) (+ n 1) (map car (ra-shape ra21))))
  250. (ra23 (apply ra-amend! (ra-copy ra21) (+ n 1) (map cadr (ra-shape ra21))))
  251. (a20 (ra->array ra20))
  252. (a21 (ra->array ra21))
  253. (a22 (ra->array ra22))
  254. (a23 (ra->array ra23)))
  255. (unless (ra-equal? ra20 ra21) (throw 'bad-ra-equal?-1))
  256. (unless (array-equal? a20 a21) (throw 'bad-array-equal?-1))
  257. (format #t "rank ~a ~a (#t):" rank nn)
  258. (format-line (* scale (time (ra-equal? ra20 ra21)))
  259. (* scale (time (array-equal? a20 a21))))
  260. (when (ra-equal? ra20 ra22) (throw 'bad-ra-equal?-2))
  261. (when (array-equal? a20 a22) (throw 'bad-array-equal?-2))
  262. (format #t "rank ~a ~a (#f1):" rank nn)
  263. (format-line (* scale (time (ra-equal? ra20 ra22)))
  264. (* scale (time (array-equal? a20 a22))))
  265. (when (ra-equal? ra20 ra23) (throw 'bad-ra-equal?-3))
  266. (when (array-equal? a20 a23) (throw 'bad-array-equal?-3))
  267. (format #t "rank ~a ~a (#f2):" rank nn)
  268. (format-line (* scale (time (ra-equal? ra20 ra23)))
  269. (* scale (time (array-equal? a20 a23))))))
  270. (iota 6 1)))
  271. (list #t 'f64)))
  272. (let ((m #e1e4))
  273. (format #t "\nprinting\n==================\n")
  274. (for-each
  275. (lambda (type)
  276. (format #t "\ndst ~a\n----------" type)
  277. (format-header "ra" "array1" "array2")
  278. (for-each
  279. (lambda (rank)
  280. (let* ((n (inexact->exact (ceiling (expt m (/ rank)))))
  281. (nn (make-list rank n))
  282. (len (fold * 1 nn))
  283. (scale (* 1e3 (/ m len)))
  284. (ra (ra-map! (make-ra-new type 0 (apply c-dims nn)) (cut random n)))
  285. (a (ra->array ra)))
  286. (format #t "rank ~a ~a:" rank nn)
  287. (format-line (* scale (time (call-with-output-file "/dev/null" (cut display ra <>))))
  288. (* scale (time (call-with-output-file "/dev/null" (cut array-print* a <>))))
  289. (* scale (time (call-with-output-file "/dev/null" (cut display a <>)))))))
  290. (iota 6 1)))
  291. (list #t 'f64)))
  292. (let ((m #e1e4))
  293. (format #t "\nreading\n==================\n")
  294. (for-each
  295. (lambda (type)
  296. (format #t "\ndst ~a\n----------" type)
  297. (format-header "ra1" "ra2" "array")
  298. (for-each
  299. (lambda (rank)
  300. (let* ((n (inexact->exact (ceiling (expt m (/ rank)))))
  301. (nn (make-list rank n))
  302. (len (fold * 1 nn))
  303. (scale (* 1e3 (/ m len)))
  304. (ra (ra-map! (make-ra-new type 0 (apply c-dims nn)) (cut random n)))
  305. (sra1 (call-with-output-string (cut ra-print ra <> #:dims? #t)))
  306. (sra2 (call-with-output-string (cut ra-print ra <> #:dims? #f)))
  307. (a (ra->array ra))
  308. (sa (call-with-output-string (cut display a <>))))
  309. (format #t "rank ~a ~a:" rank nn)
  310. (let ((rb #f) (b #f))
  311. (format-line (* scale (time (set! rb (call-with-input-string sra1 read))))
  312. (* scale (time (set! rb (call-with-input-string sra2 read))))
  313. (* scale (time (set! b (call-with-input-string sa read)))))
  314. (unless (array-equal? (ra->array rb) b) (throw 'bad-reading-benchmark)))))
  315. (iota 6 1)))
  316. (list #t 'f64)))
  317. (let ((m #e1e5))
  318. (format #t "\nlist->ra\n==================\n")
  319. (for-each
  320. (lambda (type)
  321. (format #t "\ndst ~a\n----------" type)
  322. (format-header "ra" "array" "ra/shape" "array/shape")
  323. (for-each
  324. (lambda (rank)
  325. (let* ((n (inexact->exact (ceiling (expt m (/ rank)))))
  326. (nn (make-list rank n))
  327. (len (fold * 1 nn))
  328. (scale (* 1e3 (/ m len)))
  329. (ra (ra-map! (make-ra-new type 0 (apply c-dims nn)) (cut random n)))
  330. (la (ra->list ra))
  331. (shape (map (lambda (len) (list 0 (- len 1))) nn)))
  332. (format #t "rank ~a ~a:" rank nn)
  333. (let ((rb #f) (b #f))
  334. (format-line (* scale (time (set! rb (list->ra rank la))))
  335. (* scale (time (set! b (list->array rank la))))
  336. (* scale (time (set! rb (list->typed-ra type shape la))))
  337. (* scale (time (set! b (list->typed-array type shape la)))))
  338. (unless (array-equal? (ra->array ra) b) (throw 'bad-ra->list-benchmark))
  339. (unless (array-equal? (ra->array rb) b) (throw 'bad-ra->list-benchmark)))))
  340. (iota 6 1)))
  341. (list #t 'f64)))
  342. (let ((m #e1e5))
  343. (format #t "\nra->list\n==================\n")
  344. (for-each
  345. (lambda (type)
  346. (format #t "\ndst ~a\n----------" type)
  347. (format-header "ra" "array")
  348. (for-each
  349. (lambda (rank)
  350. (let* ((n (inexact->exact (ceiling (expt m (/ rank)))))
  351. (nn (make-list rank n))
  352. (len (fold * 1 nn))
  353. (scale (* 1e3 (/ m len)))
  354. (ra (ra-map! (make-ra-new type 0 (apply c-dims nn)) (cut random n)))
  355. (array (ra->array ra))
  356. (la (ra->list ra)))
  357. (format #t "rank ~a ~a:" rank nn)
  358. (let ((lb #f) (b #f))
  359. (format-line (* scale (time (set! lb (ra->list ra))))
  360. (* scale (time (set! b (array->list array)))))
  361. (unless (equal? la b) (throw 'bad-ra->list-benchmark))
  362. (unless (equal? lb b) (throw 'bad-ra->list-benchmark)))))
  363. (iota 6 1)))
  364. (list #t 'f64)))
  365. (let ((m #e1e6))
  366. (format #t "\nra-fold\n==================\n")
  367. (format #t "handloop is flat let loop with inlined type-ref\n")
  368. (let-syntax
  369. ((%inline-type
  370. (syntax-rules ()
  371. ((_ type ref)
  372. (begin
  373. (format #t "\ndst ~a\n----------" type)
  374. (format-header "ra" "handloop")
  375. (for-each
  376. (lambda (rank)
  377. (let* ((n (inexact->exact (ceiling (expt m (/ rank)))))
  378. (nn (make-list rank n))
  379. (len (fold * 1 nn))
  380. (scale (* 1e3 (/ m len)))
  381. (ra (ra-copy type (apply ra-i nn)))
  382. (array (ra->array ra))
  383. (root (array-contents array))
  384. (expected (* m (- m 1) 1/2)))
  385. (format #t "rank ~a ~a:" rank nn)
  386. (let ((lb #f) (b #f))
  387. (format-line
  388. (* scale (time (set! lb (ra-fold + 0 ra))))
  389. (* scale (time (set! b (let loop ((a 0) (i 0)) (if (= i len) a (loop (+ a (ref root i)) (+ 1 i))))))))
  390. (unless (= lb expected) (throw 'bad-ra->list-benchmark))
  391. (unless (= b expected) (throw 'bad-ra->list-benchmark)))))
  392. '(1 2 3 6)))))))
  393. (%inline-type #t vector-ref)
  394. (%inline-type 'f64 f64vector-ref)))
  395. ; -----------------------
  396. ; ra-index-map!
  397. ; -----------------------
  398. (let ((m #e1e5))
  399. (format #t "\nra-index-map!\n==================\n")
  400. (for-each
  401. (lambda (type)
  402. (format #t "\ndst ~a\n----------" type)
  403. (format-header "ra" "array")
  404. (for-each
  405. (lambda (rank)
  406. (let* ((op (lambda x (apply + x)))
  407. (n (inexact->exact (ceiling (expt m (/ rank)))))
  408. (nn (make-list rank n))
  409. (len (fold * 1 nn))
  410. (scale (* 1e3 (/ m len)))
  411. (ra (ra-map! (make-ra-new type 0 (apply c-dims nn)) (cut random n)))
  412. (array (ra->array ra)))
  413. (format #t "rank ~a ~a:" rank nn)
  414. (format-line (* scale (time (ra-index-map! ra op)))
  415. (* scale (time (array-index-map! array op))))
  416. (unless (array-equal? (ra->array ra) array) (throw 'bad-ra-index-map!-benchmark))))
  417. (iota 3 1)))
  418. (list #t 'f64)))
  419. ; -----------------------
  420. ; some profiling...
  421. ; -----------------------
  422. (import (statprof))
  423. (format #t "\nstatprof...\n==================\n")
  424. (let* ((m #e5e4)
  425. (type #t)
  426. (rank 3)
  427. (n (inexact->exact (ceiling (expt (* 10 m) (/ rank)))))
  428. (nn (make-list rank n))
  429. (ra0 (make-ra-new type *unspecified* (apply c-dims nn)))
  430. (ra1 (ra-map! (make-ra-new type 0 (apply c-dims nn)) (cut random n)))
  431. (ra2 (ra-map! (make-ra-new type 0 (apply c-dims nn)) (cut random n)))
  432. (s (call-with-output-string (cut display ra1 <>)))
  433. (prof (lambda () (call-with-input-string s read)))
  434. (prof (lambda () (ra-fill! ra0 99)))
  435. (prof (lambda () (ra-copy! ra2 ra1)))
  436. (prof (lambda () (ra-map! ra0 * ra1 ra2)))
  437. )
  438. (statprof prof #:count-calls? #t)
  439. prof)