[gambit-list] Simple benchmark of |->integer| and |->flonum| on integer, flonum and rational input. For the further if you have any idea of a definition faster than (inexact->exact (floor n)) feel free to share :)
Mikael
mikael.rcv at gmail.com
Wed Apr 24 16:14:26 EDT 2013
Just for reference:
Here's a test of improving performance by throwing the task out in C as a
quick hack:
Results:
64bit:
for integer (fixnum) (doesn't apply)
for flonum 14,287,125 - good
for rational (doesn't apply)
for bignum integer 1 (doesn't apply)
for bignum integer 2 (doesn't apply)
32bit:
for integer (fixnum) (doesn't apply)
for flonum 13,993,639 - good
for rational (doesn't apply)
for bignum integer 1 (doesn't apply)
for bignum integer 2 (doesn't apply)
Interesting that they were so close, as this is a 32bit install.
Also interesting that this runs at ~39% the speed of (exact->inexact
[fixnum]).
So a general definition could be made out of this by
(define (->integer n)
(if (flonum? n)
(c-flonum-to-int n)
(inexact->exact (floor n))))
Though appears like a hack and it's a minus that it requires C compilation.
If you have any more general definition at hand feel free to share.
(define c-flonum-to-int (c-lambda (double) int64 "___result = (___S64)
___arg1;"))
(define c-flonum-to-int32 (c-lambda (double) int32 "___result = (___S32)
___arg1;"))
(define (c-flonum-to-int-test1) (test (lambda () (c-flonum-to-int 5 ))))
(define (c-flonum-to-int-test2) (test (lambda () (c-flonum-to-int 5. ))))
(define (c-flonum-to-int-test3) (test (lambda () (c-flonum-to-int 10/7))))
(define (c-flonum-to-int-test4) (test (lambda () (c-flonum-to-int 1e25))))
(define (c-flonum-to-int-test5) (test (lambda () (c-flonum-to-int
10000000000000000000000000))))
(define (c-flonum-to-int-test32-1) (test (lambda () (c-flonum-to-int32 5
))))
(define (c-flonum-to-int-test32-2) (test (lambda () (c-flonum-to-int32 5.
))))
(define (c-flonum-to-int-test32-3) (test (lambda () (c-flonum-to-int32
10/7))))
(define (c-flonum-to-int-test32-4) (test (lambda () (c-flonum-to-int32
1e25))))
(define (c-flonum-to-int-test32-5) (test (lambda () (c-flonum-to-int32
10000000000000000000000000))))
2013/4/24 Mikael <mikael.rcv at gmail.com>
> Ah, realized that Gambit makes a difference internally between 1e25
> and 10000000000000000000000000 . So added a test also for the latter.
>
>
> Got 6,794,405 per second for |->integer| - fair enough!
>
> And got 384,459 for |->flonum| - could be faster.
>
>
> > (->integer-test5)
> 6794405.8
> > (->flonum-test5)
> 384459.2
>
>
> Def:
> (define (->integer-test5) (test (->integer 10000000000000000000000000)))
>
> (define (->flonum-test5) (test (->flonum 10000000000000000000000000)))
>
>
>
>
> 2013/4/24 Mikael <mikael.rcv at gmail.com>
>
>> Dear list,
>>
>> I was keeping this question in the back of my mind for several years so
>> taking the occasion to reflect it now:
>>
>> Here follows the result of a simple benchmark of (exact->inexact n) and (exact->inexact
>> (floor n)) where n is a flonum, fixnum or bignum integer, or rational.
>>
>> The code was executed in compiled form, with both safe and
>> interrupts-enabled set and without any consideration to C compiler flags
>> beyond -O1 , to reflect the environment of a typical application (not for
>> instance a specialized number crunching environment).
>>
>> I remember a conversation on this topic like ~4y ago but don't remember
>> any conclusion from it.
>>
>>
>> Looking at these numbers, I think they're great and all you can ask for,
>> with two exceptions, being to-integer conversion of a flonum or integer
>> bignum.
>>
>> To get a better idea I experimented with heap size and live percent
>> setting with those two, and got about the same results.
>>
>>
>> If you are aware of any definition of |->integer| that would perform much
>> better, please feel free to share!
>>
>>
>>
>>
>> Result:
>>
>> On a laptop CPU core, here's how many of the respective operation Gambit
>> performs per second
>>
>> ->integer of an integer (fixnum) 13,804,449
>> ->integer of a flonum 260,932 (perhaps performs much
>> better with another definition?)
>> ->integer of a rational 10,130,272
>> ->integer of an integer (bignum) 598,228 (perhaps performs much
>> better with another definition?)
>>
>>
>> ->flonum of an integer (fixnum) 36,550,882
>> ->flonum of a flonum 47,756,845
>> ->flonum of a rational 334,976
>> ->flonum of an integer (bignum) 51,075,409
>>
>>
>>
>>
>> Test code:
>>
>>
>> (declare (block) (standard-bindings) (extended-bindings))
>>
>> (define (noop) (void))
>>
>> (define (->integer n)
>> (lambda ()
>> (inexact->exact (floor n))))
>>
>> (define (->flonum n)
>> (lambda ()
>> (exact->inexact n)))
>>
>> (define (test t #!optional (seconds 5))
>> (let* ((at 0)
>> (th (thread-start! (make-thread (lambda () (let loop ()
>> (t)
>> (set! at (fx+ at 1))
>> (loop)))))))
>> (thread-sleep! seconds)
>> (let ((r at))
>> (thread-terminate! th)
>> (exact->inexact (/ r seconds)))))
>>
>>
>> (define (noop-test) (test noop))
>>
>> (define (->integer-test1) (test (->integer 5 )))
>> (define (->integer-test2) (test (->integer 5. )))
>> (define (->integer-test3) (test (->integer 10/7)))
>> (define (->integer-test4) (test (->integer 1e25)))
>>
>> (define (->flonum-test1) (test (->flonum 5 )))
>> (define (->flonum-test2) (test (->flonum 5. )))
>> (define (->flonum-test3) (test (->flonum 10/7)))
>> (define (->flonum-test4) (test (->flonum 1e25)))
>>
>>
>> Test output:
>>
>> > (time (noop-test))
>> (time (noop-test))
>> 5040 ms real time
>> 4932 ms cpu time (4896 user, 36 system)
>> no collections
>> 2112 bytes allocated
>> 6 minor faults
>> no major faults
>> 57985446.4
>> > (time (->integer-test1))
>> (time (->integer-test1))
>> 5019 ms real time
>> 4884 ms cpu time (4872 user, 12 system)
>> no collections
>> 1232 bytes allocated
>> no minor faults
>> no major faults
>> 13804449.
>> > (time (->integer-test2))
>> (time (->integer-test2))
>> 5000 ms real time
>> 4792 ms cpu time (4656 user, 136 system)
>> 81 collections accounting for 187 ms real time (120 user, 52 system)
>> 1607420656 bytes allocated
>> 5110 minor faults
>> no major faults
>> 260932.6
>> > (time (->integer-test3))
>> (time (->integer-test3))
>> 5015 ms real time
>> 4888 ms cpu time (4872 user, 16 system)
>> no collections
>> 2240 bytes allocated
>> no minor faults
>> no major faults
>> 10130272.8
>> > (time (->integer-test4))
>> (time (->integer-test4))
>> 5003 ms real time
>> 4680 ms cpu time (4536 user, 144 system)
>> 158 collections accounting for 401 ms real time (304 user, 60 system)
>> 3110877424 bytes allocated
>> no minor faults
>> no major faults
>> 598228.8
>> > (time (->flonum-test1))
>> (time (->flonum-test1))
>> 5011 ms real time
>> 4740 ms cpu time (4460 user, 280 system)
>> 297 collections accounting for 736 ms real time (524 user, 124 system)
>> 5848140864 bytes allocated
>> no minor faults
>> no major faults
>> 36550882.2
>> > (time (->flonum-test2))
>> (time (->flonum-test2))
>> 5001 ms real time
>> 4840 ms cpu time (4800 user, 40 system)
>> no collections
>> 2088 bytes allocated
>> no minor faults
>> no major faults
>> 47756845.8
>> > (time (->flonum-test3))
>> (time (->flonum-test3))
>> 5005 ms real time
>> 4972 ms cpu time (4920 user, 52 system)
>> 65 collections accounting for 147 ms real time (120 user, 16 system)
>> 1286350504 bytes allocated
>> no minor faults
>> no major faults
>> 334976.6
>> > (time (->flonum-test4))
>> (time (->flonum-test4))
>> 5002 ms real time
>> 4876 ms cpu time (4848 user, 28 system)
>> no collections
>> 2080 bytes allocated
>> no minor faults
>> no major faults
>> 51075409.8
>>
>>
>>
>> 2013/4/24 Bradley Lucier <lucier at math.purdue.edu>
>>
>>> On 04/24/2013 01:33 PM, Mikael wrote:
>>>
>>> Hi Brad!
>>>
>>> 2013/4/24 Bradley Lucier <lucier at math.purdue.edu>
>>>
>>>> On 04/24/2013 12:37 PM, Zhen Shen wrote:
>>>>
>>>
>>> [...]
>>>
>>>
>>>> > Now, doing (declare (flonum)) at the top level, does this stop gambit
>>>> > from boxing flonums across function calls?
>>>>
>>>> No. Gambit keeps flonums unboxed inside a basic block, whenever
>>>> there's
>>>> a jump (or the possibility of a jump), Gambit boxes up all the
>>>> still-needed flonums.
>>>>
>>>
>>> What about fixnums, would they remain unboxed in a loop?
>>>
>>>
>>> Yes. Fixnums are always "immediate" (not boxed) values.
>>>
>>>
>>>
>>> Also btw, are there any tricks that can be applied to make it keep
>>> flonums and fixnums unboxed in loops, like, (declare (not
>>> interrupts-enabled)) or (not safe)?
>>>
>>>
>>> Use (declare (not safe)) and flonum-specific operations to keep flonums
>>> unboxed in a basic block. There's no way to keep them unboxed across jumps.
>>> (With generic operations, flonums are boxed even in a basic block.)
>>>
>>> Or, you can use an f64vector as an explicit "box" for your flonum and
>>> write monstrous code like this.
>>>
>>> (define (Array-sum a)
>>> (f64vector-ref (Array-reduce (lambda (result y)
>>> (f64vector-set! result 0 (fl+
>>> (f64vector-ref result 0) y))
>>> result)
>>> (f64vector 0.)
>>> a)
>>> 0))
>>>
>>> Brad
>>>
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.iro.umontreal.ca/pipermail/gambit-list/attachments/20130424/4de6949c/attachment.htm>
More information about the Gambit-list
mailing list