Re: [racket-users] Compiler question

2016-04-30 Thread Gustavo Massaccesi
> I tend to favor ((if x y z) foo) over (if x (y foo) (z foo)) because it avoids
> redundancy and localizes the choice. Apparently, that's a pessimising
> choice and I now don't feel like I have much intuition at all about how
> things will perform.


My recommendation is to write nice code, unless you are writing a hot
spot that is critical for the application. 99% of the time the program
is just waiting for user input or read data from the disk or
something, so write nice and idiomatic code that is easy to maintain.



*IF* you really need speed, try to avoid "((whatever) ...)". In many
situations, the optimizer can rewrite it under the hood. For example
((let (...) ... z) ...) is rewritten to (let (...) ... (z ...)), so
they are equivalent after optimizations. The second expression has
many advantages:

- If z is a Racket primitive, then the function z can use the JIT
implementation, that is faster that the C implementation. Also, some
of the primitives can be reduced at compile time, for example (list?
x) can be reduced to #t or #f if the optimizer can figure out the type
of x.

- If z is defined in Racket with a lambda, then the optimizer may
inline it. So it will avoid the function call, and the constants can
be propagated and many internal expressions can be reduced. If it's a
recursive functions, it may be inlined a few times, that has a similar
effect of a loop unrolling. (I think this is what is happening in your
example.)


The problem with ((if X Y Z) a b c) is that it's more complicated.
It's not possible to reduce it automatically to (if X (Y a b c) (Z a b
c)) because a, b or c may be big expressions and this will duplicate a
lot of code, or produce wrong results if one of them is something like
'(1 2 3).

An alternative os to reduce it to
  (let ([X_ X] [a_ a] [b_ b] [c_ c])
(if X_ (Y a_ b_ c_) (Z a_ b_ c_))
but this only is correct if Y and Z are simple expressions, for
example Y may be a mutable variable that is changed in c, or Y may be
an expression that changes the value of c, or ...

But I think that there are a few easy usual cases of ((if ...) ...)
that can be reduced. I have to think about them to try to get most of
them and don't forget any of the corner cases that are incorrect.


For now, *IF* you need speed, then check the details by hand and use
(if X (Y a b c) (Z a b c)), but perhaps in a future version of Racket
this optimization can be automatic.

Gustavo

PS: Another general recommendation: Try to avoid set!, because most of
the optimizations are disabled for mutable variables.

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [racket-users] Compiler question

2016-04-29 Thread Jerry Jackson
Thank you, Matthias. Thanks to Vincent and everyone else who answered as
well. I'll experiment with the coach.

Best regards,
--Jerry


On Fri, Apr 29, 2016 at 9:16 AM, Matthias Felleisen 
wrote:

>
> Jerry, you may not have understood Vincent's concise response.
>
> No reasonably expressive PL on Earth will allow you to predict
> the performance of micro-benchmarks (not to speak of large programs)
> within reasonable bounds. When compiler optimizations fail -- what
> you call "pessimizing style" -- the compiler simply generates different
> code. In a non-trivial programs, the contexts vary too much to predict
> performance. In one context, in-lining may succeed, in another a similar
> looking one may fail.
>
> We have known this for decades, and programmers have suffered from
> this problem for equally long.
>
> Vincent's dissertation does something about it. His "compiler coach"
> or "optimization coach" is NOT a profiler. It is a tool that explains
> the compiler's design decisions. In this particular case, it explains
> that the compiler can in-line a "directly apparent" call (as Matthew
> might call it) and will not in-line a "higher-order call" as I might
> refer to your choice of style.
>
> Take a look and experiment. It's NOT a profiler. I doesn't involve
> decompilation or looking at the expansion. It's pleasant to use. If
> you have feedback, please let us know
>
> -- Matthias
>
>
>
>
>
>
>
>
>
>
> On Apr 27, 2016, at 3:52 PM, Jerry Jackson  wrote:
>
> > I appreciate the responses; at this point, however, I'm trying to figure
> out what to do with my intuition. If those two pieces of code don't compile
> to the same thing, I'm not sure how I should approach code style. I tend to
> favor ((if x y z) foo) over (if x (y foo) (z foo)) because it avoids
> redundancy and localizes the choice. Apparently, that's a pessimising
> choice and I now don't feel like I have much intuition at all about how
> things will perform. Obviously, I can use profiling to track such things
> down but...
> >
> > I'd really be interested in how the two forms look when they've both
> been reduced to some canonical internal format.
> >
> > Thanks,
> > --Jerry
> >
> >
> >
> > On Wed, Apr 27, 2016 at 8:49 AM, Vincent St-Amour <
> stamo...@eecs.northwestern.edu> wrote:
> > When you have a program that's surprisingly fast (or slow), you can use
> > the optimization coach in DrRacket (in the "view" menu) to see what
> > optimizations Racket applies to your code.
> >
> > For your program, the coach confirms Matthew's diagnosis that inlining
> > is what makes `fib2` faster.
> >
> > Vincent
> >
> >
> > On Wed, 27 Apr 2016 08:42:03 -0500,
> > Jerry Jackson wrote:
> > >
> > > Hello all,
> > >
> > > I was experimenting a bit yesterday and discovered something that
> surprised me. Here are two fibonacci functions:
> > >
> > > (define fib1
> > >   (letrec ([aux (lambda (i n)
> > >   (if (< n 2)
> > >   1
> > >   (+ (fib1 i (- n 2)) (fib1 i (- n 1)])
> > > (let ([funs (vector aux aux)])
> > >   (lambda (index num)
> > > ((if (= index 0) aux (vector-ref funs index)) index num)
> > >
> > > (define fib2
> > >   (letrec ([aux (lambda (i n)
> > >   (if (< n 2)
> > >   1
> > >   (+ (fib2 i (- n 2)) (fib2 i (- n 1)])
> > > (let ([funs (vector aux aux)])
> > >   (lambda (index num)
> > > (if (= index 0)
> > > (aux index num)
> > > ((vector-ref funs index) index num))
> > >
> > > I expected them to behave basically identically (in fact, I thought
> they would probably generate the same code). However, that was not the case:
> > >
> > > > (time (fib1 0 40))
> > > cpu time: 4490 real time: 4489 gc time: 0
> > > 165580141
> > > > (time (fib1 1 40))
> > > cpu time: 5031 real time: 5027 gc time: 0
> > > 165580141
> > > > (time (fib2 0 40))
> > > cpu time: 3042 real time: 3040 gc time: 0
> > > 165580141
> > > > (time (fib2 1 40))
> > > cpu time: 5031 real time: 5027 gc time: 0
> > > 165580141
> > > > (time (fib1 0 40))
> > > cpu time: 4535 real time: 4532 gc time: 0
> > > 165580141
> > > > (time (fib2 0 40))
> > > cpu time: 3027 real time: 3025 gc time: 0
> > > 165580141
> > > >
> > >
> > > It looks like one of the functions is 1.5 times faster than the other
> (in the i == 0 case). Any ideas as to why?
> > >
> > > Thanks,
> > > --Jerry Jackson
> > >
> > > --
> > > You received this message because you are subscribed to the Google
> Groups "Racket Users" group.
> > > To unsubscribe from this group and stop receiving emails from it, send
> an email to racket-users+unsubscr...@googlegroups.com.
> > > For more options, visit https://groups.google.com/d/optout.
> >
> >
> > --
> > You received this message because you are subscribed to the Google
> Groups "Racket Users" group.
> > To unsubscribe from this group and stop receiving 

Re: [racket-users] Compiler question

2016-04-29 Thread Matthias Felleisen

Jerry, you may not have understood Vincent's concise response. 

No reasonably expressive PL on Earth will allow you to predict
the performance of micro-benchmarks (not to speak of large programs)
within reasonable bounds. When compiler optimizations fail -- what
you call "pessimizing style" -- the compiler simply generates different
code. In a non-trivial programs, the contexts vary too much to predict
performance. In one context, in-lining may succeed, in another a similar
looking one may fail. 

We have known this for decades, and programmers have suffered from 
this problem for equally long. 

Vincent's dissertation does something about it. His "compiler coach"
or "optimization coach" is NOT a profiler. It is a tool that explains
the compiler's design decisions. In this particular case, it explains
that the compiler can in-line a "directly apparent" call (as Matthew
might call it) and will not in-line a "higher-order call" as I might
refer to your choice of style. 

Take a look and experiment. It's NOT a profiler. I doesn't involve
decompilation or looking at the expansion. It's pleasant to use. If
you have feedback, please let us know

-- Matthias










On Apr 27, 2016, at 3:52 PM, Jerry Jackson  wrote:

> I appreciate the responses; at this point, however, I'm trying to figure out 
> what to do with my intuition. If those two pieces of code don't compile to 
> the same thing, I'm not sure how I should approach code style. I tend to 
> favor ((if x y z) foo) over (if x (y foo) (z foo)) because it avoids 
> redundancy and localizes the choice. Apparently, that's a pessimising choice 
> and I now don't feel like I have much intuition at all about how things will 
> perform. Obviously, I can use profiling to track such things down but...
> 
> I'd really be interested in how the two forms look when they've both been 
> reduced to some canonical internal format.
> 
> Thanks,
> --Jerry
> 
> 
> 
> On Wed, Apr 27, 2016 at 8:49 AM, Vincent St-Amour 
>  wrote:
> When you have a program that's surprisingly fast (or slow), you can use
> the optimization coach in DrRacket (in the "view" menu) to see what
> optimizations Racket applies to your code.
> 
> For your program, the coach confirms Matthew's diagnosis that inlining
> is what makes `fib2` faster.
> 
> Vincent
> 
> 
> On Wed, 27 Apr 2016 08:42:03 -0500,
> Jerry Jackson wrote:
> >
> > Hello all,
> >
> > I was experimenting a bit yesterday and discovered something that surprised 
> > me. Here are two fibonacci functions:
> >
> > (define fib1
> >   (letrec ([aux (lambda (i n)
> >   (if (< n 2)
> >   1
> >   (+ (fib1 i (- n 2)) (fib1 i (- n 1)])
> > (let ([funs (vector aux aux)])
> >   (lambda (index num)
> > ((if (= index 0) aux (vector-ref funs index)) index num)
> >
> > (define fib2
> >   (letrec ([aux (lambda (i n)
> >   (if (< n 2)
> >   1
> >   (+ (fib2 i (- n 2)) (fib2 i (- n 1)])
> > (let ([funs (vector aux aux)])
> >   (lambda (index num)
> > (if (= index 0)
> > (aux index num)
> > ((vector-ref funs index) index num))
> >
> > I expected them to behave basically identically (in fact, I thought they 
> > would probably generate the same code). However, that was not the case:
> >
> > > (time (fib1 0 40))
> > cpu time: 4490 real time: 4489 gc time: 0
> > 165580141
> > > (time (fib1 1 40))
> > cpu time: 5031 real time: 5027 gc time: 0
> > 165580141
> > > (time (fib2 0 40))
> > cpu time: 3042 real time: 3040 gc time: 0
> > 165580141
> > > (time (fib2 1 40))
> > cpu time: 5031 real time: 5027 gc time: 0
> > 165580141
> > > (time (fib1 0 40))
> > cpu time: 4535 real time: 4532 gc time: 0
> > 165580141
> > > (time (fib2 0 40))
> > cpu time: 3027 real time: 3025 gc time: 0
> > 165580141
> > >
> >
> > It looks like one of the functions is 1.5 times faster than the other (in 
> > the i == 0 case). Any ideas as to why?
> >
> > Thanks,
> > --Jerry Jackson
> >
> > --
> > You received this message because you are subscribed to the Google Groups 
> > "Racket Users" group.
> > To unsubscribe from this group and stop receiving emails from it, send an 
> > email to racket-users+unsubscr...@googlegroups.com.
> > For more options, visit https://groups.google.com/d/optout.
> 
> 
> -- 
> You received this message because you are subscribed to the Google Groups 
> "Racket Users" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to racket-users+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit 

Re: [racket-users] Compiler question

2016-04-27 Thread 'William J. Bowman' via Racket Users
On Wed, Apr 27, 2016 at 01:52:24PM -0600, Jerry Jackson wrote:
> I'd really be interested in how the two forms look when they've both been
> reduced to some canonical internal format.
You can use `raco expand` the result after macro expansion, and `raco decompile`
to look at the result of decompiling the bytecode.
If I understand correctly, the latter may include some optimizations,
but most optimizations are done by the JIT compiler.

E.g.
  > raco expand test.rkt | less
  > raco make test.rkt
  > raco decompile test.rkt | less

--
William J. Bowman

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


signature.asc
Description: PGP signature


Re: [racket-users] Compiler question

2016-04-27 Thread Jerry Jackson
I appreciate the responses; at this point, however, I'm trying to figure
out what to do with my intuition. If those two pieces of code don't compile
to the same thing, I'm not sure how I should approach code style. I tend to
favor ((if x y z) foo) over (if x (y foo) (z foo)) because it avoids
redundancy and localizes the choice. Apparently, that's a pessimising
choice and I now don't feel like I have much intuition at all about how
things will perform. Obviously, I can use profiling to track such things
down but...

I'd really be interested in how the two forms look when they've both been
reduced to some canonical internal format.

Thanks,
--Jerry



On Wed, Apr 27, 2016 at 8:49 AM, Vincent St-Amour <
stamo...@eecs.northwestern.edu> wrote:

> When you have a program that's surprisingly fast (or slow), you can use
> the optimization coach in DrRacket (in the "view" menu) to see what
> optimizations Racket applies to your code.
>
> For your program, the coach confirms Matthew's diagnosis that inlining
> is what makes `fib2` faster.
>
> Vincent
>
>
> On Wed, 27 Apr 2016 08:42:03 -0500,
> Jerry Jackson wrote:
> >
> > Hello all,
> >
> > I was experimenting a bit yesterday and discovered something that
> surprised me. Here are two fibonacci functions:
> >
> > (define fib1
> >   (letrec ([aux (lambda (i n)
> >   (if (< n 2)
> >   1
> >   (+ (fib1 i (- n 2)) (fib1 i (- n 1)])
> > (let ([funs (vector aux aux)])
> >   (lambda (index num)
> > ((if (= index 0) aux (vector-ref funs index)) index num)
> >
> > (define fib2
> >   (letrec ([aux (lambda (i n)
> >   (if (< n 2)
> >   1
> >   (+ (fib2 i (- n 2)) (fib2 i (- n 1)])
> > (let ([funs (vector aux aux)])
> >   (lambda (index num)
> > (if (= index 0)
> > (aux index num)
> > ((vector-ref funs index) index num))
> >
> > I expected them to behave basically identically (in fact, I thought they
> would probably generate the same code). However, that was not the case:
> >
> > > (time (fib1 0 40))
> > cpu time: 4490 real time: 4489 gc time: 0
> > 165580141
> > > (time (fib1 1 40))
> > cpu time: 5031 real time: 5027 gc time: 0
> > 165580141
> > > (time (fib2 0 40))
> > cpu time: 3042 real time: 3040 gc time: 0
> > 165580141
> > > (time (fib2 1 40))
> > cpu time: 5031 real time: 5027 gc time: 0
> > 165580141
> > > (time (fib1 0 40))
> > cpu time: 4535 real time: 4532 gc time: 0
> > 165580141
> > > (time (fib2 0 40))
> > cpu time: 3027 real time: 3025 gc time: 0
> > 165580141
> > >
> >
> > It looks like one of the functions is 1.5 times faster than the other
> (in the i == 0 case). Any ideas as to why?
> >
> > Thanks,
> > --Jerry Jackson
> >
> > --
> > You received this message because you are subscribed to the Google
> Groups "Racket Users" group.
> > To unsubscribe from this group and stop receiving emails from it, send
> an email to racket-users+unsubscr...@googlegroups.com.
> > For more options, visit https://groups.google.com/d/optout.
>

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [racket-users] Compiler question

2016-04-27 Thread Vincent St-Amour
When you have a program that's surprisingly fast (or slow), you can use
the optimization coach in DrRacket (in the "view" menu) to see what
optimizations Racket applies to your code.

For your program, the coach confirms Matthew's diagnosis that inlining
is what makes `fib2` faster.

Vincent


On Wed, 27 Apr 2016 08:42:03 -0500,
Jerry Jackson wrote:
> 
> Hello all,
> 
> I was experimenting a bit yesterday and discovered something that surprised 
> me. Here are two fibonacci functions:
> 
> (define fib1
>   (letrec ([aux (lambda (i n)
>   (if (< n 2)
>   1
>   (+ (fib1 i (- n 2)) (fib1 i (- n 1)])
> (let ([funs (vector aux aux)])
>   (lambda (index num)
> ((if (= index 0) aux (vector-ref funs index)) index num)
> 
> (define fib2
>   (letrec ([aux (lambda (i n)
>   (if (< n 2)
>   1
>   (+ (fib2 i (- n 2)) (fib2 i (- n 1)])
> (let ([funs (vector aux aux)])
>   (lambda (index num)
> (if (= index 0)
> (aux index num)
> ((vector-ref funs index) index num))
> 
> I expected them to behave basically identically (in fact, I thought they 
> would probably generate the same code). However, that was not the case:
> 
> > (time (fib1 0 40))
> cpu time: 4490 real time: 4489 gc time: 0
> 165580141
> > (time (fib1 1 40))
> cpu time: 5031 real time: 5027 gc time: 0
> 165580141
> > (time (fib2 0 40))
> cpu time: 3042 real time: 3040 gc time: 0
> 165580141
> > (time (fib2 1 40))
> cpu time: 5031 real time: 5027 gc time: 0
> 165580141
> > (time (fib1 0 40))
> cpu time: 4535 real time: 4532 gc time: 0
> 165580141
> > (time (fib2 0 40))
> cpu time: 3027 real time: 3025 gc time: 0
> 165580141
> > 
> 
> It looks like one of the functions is 1.5 times faster than the other (in the 
> i == 0 case). Any ideas as to why?
> 
> Thanks,
> --Jerry Jackson
> 
> -- 
> You received this message because you are subscribed to the Google Groups 
> "Racket Users" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to racket-users+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [racket-users] Compiler question

2016-04-27 Thread Matthew Flatt
The compiler inlines the call to `aux` in `fib2` because that call is
readily apparent. It's not so apparent in the other cases that the
function `aux` is always called.

At Wed, 27 Apr 2016 06:42:03 -0700 (PDT), Jerry Jackson wrote:
> Hello all,
> 
> I was experimenting a bit yesterday and discovered something that surprised 
> me. Here are two fibonacci functions:
> 
> (define fib1
>   (letrec ([aux (lambda (i n)
>   (if (< n 2)
>   1
>   (+ (fib1 i (- n 2)) (fib1 i (- n 1)])
> (let ([funs (vector aux aux)])
>   (lambda (index num)
> ((if (= index 0) aux (vector-ref funs index)) index num)
> 
> (define fib2
>   (letrec ([aux (lambda (i n)
>   (if (< n 2)
>   1
>   (+ (fib2 i (- n 2)) (fib2 i (- n 1)])
> (let ([funs (vector aux aux)])
>   (lambda (index num)
> (if (= index 0)
> (aux index num)
> ((vector-ref funs index) index num))
> 
> I expected them to behave basically identically (in fact, I thought they 
> would 
> probably generate the same code). However, that was not the case:
> 
> > (time (fib1 0 40))
> cpu time: 4490 real time: 4489 gc time: 0
> 165580141
> > (time (fib1 1 40))
> cpu time: 5031 real time: 5027 gc time: 0
> 165580141
> > (time (fib2 0 40))
> cpu time: 3042 real time: 3040 gc time: 0
> 165580141
> > (time (fib2 1 40))
> cpu time: 5031 real time: 5027 gc time: 0
> 165580141
> > (time (fib1 0 40))
> cpu time: 4535 real time: 4532 gc time: 0
> 165580141
> > (time (fib2 0 40))
> cpu time: 3027 real time: 3025 gc time: 0
> 165580141
> > 
> 
> It looks like one of the functions is 1.5 times faster than the other (in the 
> i == 0 case). Any ideas as to why?
> 
> Thanks,
> --Jerry Jackson
> 
> -- 
> You received this message because you are subscribed to the Google Groups 
> "Racket Users" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to racket-users+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.