[racket] fl vs. unsafe-fl
Hello,
I was wondering whether operations with flonums and flvectors work
slower than their unsafe- counterparts in intensive numerical tasks.
Here is an example: res = a+b*c
#lang racket
(require racket/flonum
racket/unsafe/ops)
(define n 1000)
(define k 100000)
(define a (make-flvector n 1.0))
(define b (make-flvector n 2.0))
(define c (make-flvector n 3.0))
(define res (make-flvector n))
(define (test-perf)
(for ((i (in-range k)))
(for ((j (in-range n)))
(flvector-set!
res j (fl+ (flvector-ref a j)
(fl* (flvector-ref b j)
(flvector-ref c j)))))))
(define (test-perf-unsafe-ops)
(for ((i (in-range k)))
(for ((j (in-range n)))
(flvector-set!
res j (unsafe-fl+ (flvector-ref a j)
(unsafe-fl* (flvector-ref b j)
(flvector-ref c j)))))))
(define (test-perf-unsafe-flvec)
(for ((i (in-range k)))
(for ((j (in-range n)))
(unsafe-flvector-set!
res j (fl+ (unsafe-flvector-ref a j)
(fl* (unsafe-flvector-ref b j)
(unsafe-flvector-ref c j)))))))
(define (test-perf-unsafe-all)
(for ((i (in-range k)))
(for ((j (in-range n)))
(unsafe-flvector-set!
res j (unsafe-fl+ (unsafe-flvector-ref a j)
(unsafe-fl* (unsafe-flvector-ref b j)
(unsafe-flvector-ref c j)))))))
(time (test-perf))
(time (test-perf-unsafe-ops))
(time (test-perf-unsafe-flvec))
(time (test-perf-unsafe-all))
Result (Racket 6.1.0.2, Linux 64-bit):
cpu time: 1704 real time: 1704 gc time: 0
cpu time: 1692 real time: 1692 gc time: 0
cpu time: 736 real time: 738 gc time: 0
cpu time: 684 real time: 682 gc time: 0
It turns out that replacing arithmetical operations
on flonums with their unsafe- counterparts makes no difference,
unless flvector access is unsafe- too; and even then, making
flvector access unsafe makes a huge improvement, while acceleration
from unsafe ops is about 7%.
I can imagine that the Racket's JIT skips checking the types of
arguments of fl+ and fl* because it figures that since they come
from flvectors, they must be flonums. Am I correct?
If I am correct, then are unsafe-fl arithmetical operations important
at all? Because in numerical programs, nearly every flonum is either
a constant, or a value taken from flvector, or a function argument
that can be traced to the same.
Regards,
Dmitry