[racket-dev] [plt] Push #27909: master branch updated
On 12/11/2013 02:49 PM, Neil Toronto wrote:
> On 12/11/2013 01:55 PM, Stephen Bloch wrote:
>>> On Dec 11, 2013, at 2:36 PM, Neil Toronto wrote:
>>>
>>>> numeric primitives implemented in Typed Racket are faster than the
>>>> same primitives implemented in C.
>>
>> Whoa! How did that happen?
>
> Whoa! That's not what I meant! O_o
>
> I said "we might be getting close" to that. I haven't tried porting a
> numeric C primitive to TR yet, but I have a hunch that it'll still be
> slower. I'll try one now and report what I find.
>
> Neil ⊥
I can't figure out why `flsinh' is faster to call from untyped Racket
than `sinh'. All my tests with a Typed Racket `magnitude' show calls
from untyped code are significantly slower, except in the one case that
it computes Euclidean distance. That case is only twice as slow.
I've attached the benchmark program. The `magnitude*' function is more
or less a direct translation of `magnitude' from "number.c" into Typed
Racket. Here's a summary of the results I get on my computer, in
milliseconds, for 5 million calls from untyped Racket, by data type.
Function Flonum Rational Fixnum Integer Float-Complex
-------------------------------------------------------------------
magnitude* 385 419 378 414 686
magnitude 59 44 40 40 390
The only one that's close in relative terms is Float-Complex. The others
just call `abs'. The decompiled code doesn't show any inlining of
`magnitude', so this comparison should be good.
I'll bet checking the return value contract (which is unnecessary) is
the main slowdown. It has to check for number of values.
For comparison, here are the timings for running the benchmarks in TR
with #:no-optimize:
Function Flonum Rational Fixnum Integer Float-Complex
-------------------------------------------------------------------
magnitude* 45 70* 37 102* 318
magnitude 61 45 39 91* 394
* = unexpectedly high
Here's what I understand from comparing the numbers:
* Except for non-fixnum integers, calling `magnitude' in TR is just as
fast as in untyped Racket. I have no idea why it would be slower on big
integers. That's just weird.
* Calling `abs' in Racket is faster than calling `scheme_abs' in C,
except on rationals and big integers.
* Operating on flonums in Typed Racket, using generic numeric
functions, is faster than doing the same in C.
Overall, it looks like the TR code is within the same order of magnitude
(pun not intended) as the C code. I would love to try this benchmark
with either 1) a `magnitude*' with an `AnyValues' return type; or 2) a
contract boundary that doesn't check TR's return types for first-order
functions.
(I managed to make a `magnitude*' with type Number -> AnyValues, but TR
couldn't make a contract for it.)
Neil ⊥
-------------- next part --------------
#lang racket
(module typed-defs typed/racket
(require math/base)
(provide magnitude*)
(: magnitude* (Number -> Any))
(define (magnitude* z)
(cond [(real? z) (abs z)]
[else
(define r (abs (real-part z)))
(define i (abs (imag-part z)))
(cond [(eq? r 0) i]
[else
(let-values ([(r i) (if (i . < . r) (values i r) (values r i))])
(cond [(zero? r) (exact->inexact i)]
[(= i +inf.0) (if (eqv? r +nan.0) +nan.0 +inf.0)]
[else
(define q (/ r i))
(* i (sqrt (+ 1 (* q q))))]))])]))
)
;(module test typed/racket #:no-optimize
(module test racket
(require math/base
typed/racket/base
(submod ".." typed-defs))
(define x (random))
(define y (/ (random 10000) (+ 1 (random 10000))))
(define i (random-integer (- (expt 2 20)) (expt 2 20)))
(define n (let: loop : Integer ()
(define n (random-integer (- (expt 2 128)) (expt 2 128)))
(if (fixnum? n) (loop) n)))
(define z (make-rectangular (random) (random)))
(define-syntax-rule (test-one-arg-fun f x)
(begin
(printf "(~a ~a)~n" 'f 'x)
(for ([_ (in-range 5)])
(time (for ([_ (in-range 5000000)])
(f x))))
(newline)))
(test-one-arg-fun magnitude* x)
(test-one-arg-fun magnitude x)
(test-one-arg-fun magnitude* y)
(test-one-arg-fun magnitude y)
(test-one-arg-fun magnitude* i)
(test-one-arg-fun magnitude i)
(test-one-arg-fun magnitude* n)
(test-one-arg-fun magnitude n)
(test-one-arg-fun magnitude* z)
(test-one-arg-fun magnitude z)
)
(require 'test)