[plt-scheme] ->d Performance

From: Robby Findler (robby at eecs.northwestern.edu)
Date: Sat Apr 11 16:39:22 EDT 2009

Yeah, that's pretty bad. Below is a smaller example showing that there
about a 16x slowdown for using ->d as compared to ->, even without
doing anything special. And if you change the integer? into (and/c
number? integer?) in the ->d contract, the slowdown is 35x. I did
spent a fair amount of time trying to make -> go fast, but I just
haven't had time to do the same for ->d.

#lang scheme/load

(module m scheme
  (provide/contract
   [f (-> integer? integer? integer?)]
   [g (->d ([x integer?]
            [y integer?])
           ()
           [r integer?])])

  (define (f x y) x)
  (define (g x y) x))

(module n scheme
  (require 'm)
  (define (run f)
    (time
     (let loop ([i 10000])
       (unless (zero? i)
         (f 1 2) (f 3 4) (f 5 6) (f 7 8) (f 9 10)
         (loop (- i 1))))))

  (run f)
  (run g))

(require 'n)




On Sat, Apr 11, 2009 at 3:29 PM, Doug Williams
<m.douglas.williams at gmail.com> wrote:
> Here is a graphical example where you can see the difference in speed.
>
> The life-bitblt-slower.ss requires matrix-slower.ss (with ->d and no bounds
> checking in the body of the code) and is really slow.
>
> The life-bitblt-faster.ss requires matrix-faster.ss (with -> and bounds
> checking in the body of the code) and performs okay.
>
> Other than the contract and the corresponding presence or ansence of bounds
> checking (to give the same functionality), the code is identical. [The only
> difference between life-bitblt-slower.ss and life-bitblt-faster.ss is the
> require statement.]
>
> The life-bitblt-vector.ss version does the matrix abstraction internally
> (using a vector) and doesn't use any external module (or contracts) at all.
> It is by far the fastest, but it's kind of an apples and oranges comparison
> with the others. I'm not sure how much of the speedup is due to the matrix
> abstraction into a module or the contracts.
>
> They all do better compiled. But it interesting to see the speed difference.
>
> Note that the code used the science and animated-canvas collections from
> PLaneT and will download them the first time any of them are run, which
> takes some time.
>
> Doug
>
> On Sat, Apr 11, 2009 at 1:55 PM, Robby Findler <robby at eecs.northwestern.edu>
> wrote:
>>
>> ->d actually evaluates the expressions (and/c
>> exact-nonnegative-integer? (</c (matrix-rows matrix))) each time you
>> call the function, and that evaluation involves building up a contract
>> combinator (and doing various error checking) before actually checking
>> the contract. That's where the extra overhead comes from. In
>> comparison with the -> contract, all of that work is done once, before
>> the contract is even attached to the value. I have experimented with
>> various optimizations to avoid this work, but there is a lot to do to
>> make that happen.
>>
>> Robby
>>
>> On Sat, Apr 11, 2009 at 2:51 PM, Doug Williams
>> <m.douglas.williams at gmail.com> wrote:
>> > Yes, the -> is fine. And, so is doing the same bounds check in my own
>> > procedure. I was surprised that the ->d was so much slower. I use
>> > contracts
>> > regularly and was trying to expand my usage of them.
>> >
>> > On Sat, Apr 11, 2009 at 12:46 PM, Robby Findler
>> > <robby at eecs.northwestern.edu> wrote:
>> >>
>> >> ->d is definitely substantially slower than the other because the
>> >> wrappers are more complex. Are you finding the performance overhead of
>> >> the ordinary -> acceptable?
>> >>
>> >> Robby
>> >>
>> >> On Sat, Apr 11, 2009 at 1:17 PM, Doug Williams
>> >> <m.douglas.williams at gmail.com> wrote:
>> >> > I would like to use ->d to impose a precondition for a function.  For
>> >> > example:
>> >> >
>> >> >  (matrix-ref
>> >> >   (->d ((matrix matrix?)
>> >> >         (i (and/c exact-nonnegative-integer? (</c (matrix-rows
>> >> > matrix))))
>> >> >         (j (and/c exact-nonnegative-integer? (</c (matrix-cols
>> >> > matrix)))))
>> >> >        ()
>> >> >        (result any/c)))
>> >> >
>> >> > or
>> >> >
>> >> >  (matrix-ref
>> >> >   (->d ((matrix matrix?)
>> >> >         (i exact-nonnegative-integer?)
>> >> >         (j exact-nonnegative-integer?))
>> >> >        ()
>> >> >        #:pre-cond (and (< i (matrix-rows matrix))
>> >> >                        (< j (matrix-cols matrix)))
>> >> >        (result any/c)))
>> >> >
>> >> > instead of just
>> >> >
>> >> >  (matrix-ref
>> >> >   (-> matrix? exact-nonnegative-integer? exact-nonnegative-integer?
>> >> > any/c))
>> >> >
>> >> > The first two do work, but are really, really slow.
>> >> >
>> >> > I like having the bounds check in the contract (as opposed to bounds
>> >> > check
>> >> > in the matrix-ref code, but can't accept the performance hit. Any
>> >> > ideas?
>> >> >
>> >> > Doug
>> >> >
>> >> >
>> >> > _________________________________________________
>> >> >  For list-related administrative tasks:
>> >> >  http://list.cs.brown.edu/mailman/listinfo/plt-scheme
>> >> >
>> >> >
>> >
>> >
>
>


Posted on the users mailing list.