[racket] Why parameterize is so sloooow?

From: Joe Marshall (jmarshall at alum.mit.edu)
Date: Fri Aug 16 08:49:25 EDT 2013

I meant that binding a parameter is different from an assign/unassign pair,
and that fetching the value involves something more than just dereferencing
the value cell.
On Aug 16, 2013 5:42 AM, "Matthew Flatt" <mflatt at cs.utah.edu> wrote:

> No, not if you mean "deep binding" in the sense of a list that has to
> be searched to find a parameter value.
>
> At Fri, 16 Aug 2013 05:23:52 -0700, Joe Marshall wrote:
> > Sounds like Racket is using a "deep binding" strategy rather than
> "shallow
> > binding".  I expect that SBCL uses shallow.
> >  On Aug 16, 2013 5:10 AM, "Matthew Flatt" <mflatt at cs.utah.edu> wrote:
> >
> > > At Fri, 16 Aug 2013 13:59:55 +0400, Roman Klochkov wrote:
> > > >
> > > > I compared parameterize with lexical var
> > > > ----
> > > > > (require rackunit)
> > > > > (define my-parameter (make-parameter (box 0)))
> > > > > (time
> > > >    (parameterize ([my-parameter (box 0)])
> > > >      (for ([x (in-range 10000000)])
> > > >        (set-box! (my-parameter)
> > > >                  (add1 (unbox (my-parameter)))))
> > > >      (check-equal? (unbox (my-parameter)) 10000000)))
> > > > cpu time: 3578 real time: 3610 gc time: 0
> > > > > (time
> > > >    (let ([my-parameter (box 0)])
> > > >      (for ([x (in-range 10000000)])
> > > >        (set-box! my-parameter
> > > >                  (add1 (unbox my-parameter))))
> > > >      (check-equal? (unbox my-parameter) 10000000)))
> > > > cpu time: 47 real time: 47 gc time: 0
> > > > ----
> > > >
> > > > 100 times difference!
> > > >
> > > > The same experiment with Common Lisp (SBCL):
> > > > ----
> > > > CL-USER> (setf *a* (list 0))
> > > > (0)
> > > > CL-USER> (time (progn (loop :for i :from 0 :below 10000000
> > > >             :do (setf (car *a*) (+ 1 (car *a*)))) (= (car *a*)
> > > 10000000)))
> > > > Evaluation took:
> > > >   0.063 seconds of real time
> > > >   0.062500 seconds of total run time (0.062500 user, 0.000000 system)
> > > >   98.41% CPU
> > > >   172,464,541 processor cycles
> > > >   0 bytes consed
> > > >
> > > > T
> > > > CL-USER> (let ((a (list 0))) (time (loop :for i :from 0 :below
> 10000000
> > > >             :do (setf (car a) (+ 1 (car a))))) (= (car a) 10000000))
> > > >
> > > > Evaluation took:
> > > >   0.047 seconds of real time
> > > >   0.046875 seconds of total run time (0.046875 user, 0.000000 system)
> > > >   100.00% CPU
> > > >   132,098,942 processor cycles
> > > >   0 bytes consed
> > > >
> > > > T
> > > > ----
> > > > Only 1.5 times.
> > > >
> > > > Is it undesirable to use parameterize as replacement for common lisp
> > > special
> > > > variables? What is it designed for then?
> > >
> > > Parameters in Racket are grouped together in a an extra layer called a
> > > "parameterization", which enables capture of the current values of all
> > > parameters. For example, when a new thread is created in Racket, then
> > > the new inherits all of the current parameter values from the creating
> > > thread. A lack of cleverness in that layer is probably the main effect
> > > on performance in yuor example.
> > >
> > > Using a raw, symbol-keyed continuation mark would be closer to a Common
> > > Lisp special variable, I think. On my machine:
> > >
> > >  ;; parameter
> > >  > (time
> > >     (parameterize ([my-parameter (box 0)])
> > >       (for ([x (in-range 10000000)])
> > >         (set-box! (my-parameter)
> > >                   (add1 (unbox (my-parameter)))))
> > >       (check-equal? (unbox (my-parameter)) 10000000)))
> > >  cpu time: 2539 real time: 2537 gc time: 0
> > >
> > >  ;; direct
> > >  > (time
> > >     (let ([my-parameter (box 0)])
> > >       (for ([x (in-range 10000000)])
> > >         (set-box! my-parameter
> > >                   (add1 (unbox my-parameter))))
> > >       (check-equal? (unbox my-parameter) 10000000)))
> > >  cpu time: 45 real time: 45 gc time: 0
> > >
> > >  ;; raw continuation mark:
> > >  > (time
> > >     (let ([my-parameter
> > >            (lambda ()
> > >              (continuation-mark-set-first #f 'my-parameter))])
> > >       (with-continuation-mark
> > >         'my-parameter
> > >         (box 0)
> > >         (begin
> > >           (for ([x (in-range 10000000)])
> > >             (set-box! (my-parameter)
> > >                       (add1 (unbox (my-parameter)))))
> > >           (check-equal? (unbox (my-parameter)) 10000000)))))
> > >  cpu time: 244 real time: 243 gc time: 0
> > >
> > > That's still a fact of 5 difference. I expect that dynamic binding and
> > > special variables have played a more prominent role in Common Lisp than
> > > parameters or even continuation-mark lookup in Racket, and so it would
> > > make sense that more work has been done in the SBCL to make them fast.
> > >
> > >
> > > ____________________
> > >   Racket Users list:
> > >   http://lists.racket-lang.org/users
> > >
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.racket-lang.org/users/archive/attachments/20130816/24b71f07/attachment-0001.html>

Posted on the users mailing list.