[Haskell-cafe] Code runs 7x FASTER with profiling

Neil Mayhew neil_mayhew at users.sourceforge.net
Fri Dec 8 14:18:42 UTC 2017


On 2017-12-08 01:52 AM, Sven Panne wrote:

    … making something a CAF is not always an optimization: If your
    evaluated CAF uses e.g. hundreds of MB it might be preferable to
    /not/ have it as a CAF, but to to recompute it instead.

Good point. However, I think it would be very hard for the compiler to 
detect which CAFs use a lot of memory and aren’t referred to very often.

    If I haven’t missed something recently, CAFs can’t be garbage
    collected, but I would be happy to be corrected here. :-)

There’s a helpful discussion on the Haskell Wiki here 
<https://wiki.haskell.org/Constant_applicative_form>. In particular, it 
says:

    A CAF … may only be accessible from within the code of one or more
    functions. In order for the garbage collector to be able to reclaim
    such structures, we associate with each function a list of the CAFs
    to which it refers. When garbage collecting a reference to the
    function we collect the CAFs on its list.

In my case, since the function itself is top-level, I assume the CAF 
can’t be garbage-collected.

        Enabling profiling shouldn’t change the meaning of a program.

    It doesn’t change the meaning, that would really be a desaster, it
    just changes the performance characteristics. This is still not
    nice, but not much different from using different levels of
    optimization: Doing or not doing e.g. strictness analysis might
    change the space complexity etc.

Yes, I see you’re right. However, I guess I was using ‘meaning’ loosely 
to mean ‘is a CAF’ and I assumed a CAF would always be floated. The 
above-mentioned wiki page says, “A CAF can always be lifted to the top 
level of the program.” However, I realize “can” is not the same as “should”.

        I remember back in the day having to be careful with regexes in
        Python to make sure they were always precompiled outside of
        loops and functions, but one of the nice things about Haskell is
        that one can usually let the compiler take care of this.
        (Nowadays Python gets around this by caching compiled regexes,
        but I prefer Haskell’s statically-optimized approach.)

    I think totally relying on the compiler for performance is a common
    misconception, because things are often more tricky than initially
    thought. In our example: Time vs. space tradeoff, and there is no
    universally “right” solution.

Good point. Having great optimization isn’t a justification for complete 
mental laziness on the part of the programmer! However, I did find the 
behaviour in this case surprising and unintuitive, given ghc’s usual 
ability to optimize things, and having it change on me when I enabled 
profiling left me wondering where to go next. The code I presented here 
is considerably simplified from the original program, and represents a 
lot of work already expended trying to get to the root of the problem.

​
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/haskell-cafe/attachments/20171208/c0ed1b53/attachment.html>


More information about the Haskell-Cafe mailing list