[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