[Haskell-cafe] Time performance with inlining and space performance with newtype?

Rob Stewart robstewart57 at gmail.com
Fri Oct 9 14:06:32 UTC 2015


To add third case:

1. which optimising GHC passes does SPECIALIZE enable? Taking the
example from the GHC docs
https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/pragmas.html#specialize-pragma
:

    hammeredLookup :: Ord key => [(key, value)] -> key -> value
    {-# SPECIALIZE hammeredLookup :: [(Widget, value)] -> Widget -> value #-}

This means that the type class dictionary for Ord will not be passed
as a (hidden) argument in Core to `hammeredLookup` when Widget is the
key. The GHC docs about overloading
https://wiki.haskell.org/Performance/Overloading says "The presence of
overloading can prevent many other optimisations, such as Strictness,
from kicking in". So we lose the strictness GHC optimiser in the
absence of SPECIALIZE rules on overloaded functions. Other than
strictness analysis, what other GHC optimisations are being missed
when overloading is not dealt with using monomorphism? And what are
the specific runtime overheads of passing type class constraints as
dictionaries to overloaded functions at runtime?

--
Rob


On 9 October 2015 at 12:30, Rob Stewart <robstewart57 at gmail.com> wrote:
> Hi,
>
> I'm in search of clarifications and descriptions about code
> optimisations that are recommended in GHC docs, regarding inlining and
> newtype vs data.
>
> 1. Inlining small and often used functions
>
> See https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/pragmas.html
> , Section "7.22.6.1. INLINE pragma". It says:
>
> "GHC tries to inline functions/values that are 'small enough', thus
> avoiding the call overhead and possibly exposing other more-wonderful
> optimisations."
>
> I understand the reason for function inlining with other languages
> like C, as it avoids the construction of new stack frames and
> coordinating stack pointers for each function call. In Haskell, rather
> than call stack we've got evaluation stacks.
>
> Here are my questions: what exactly is the call overhead of a
> non-inlned Haskell function? What additional runtime work needs to
> happen when calling to a non-inlined function? Specifically what other
> GHC optimisations are possible only if function inlining happens
> first? Can anyone provide a simple example where 1) a function is not
> inlined, versus 2) when that function is inlined, which demonstrates
> two things: 1) a GHC report of the additional optimisations that were
> applied because of inlining and 2) shorter program runtime as a result
> of inlining.
>
> 2. Calculating the memory costs of a data type
>
> As Don Stewart nicely explains on SO
> http://stackoverflow.com/a/5889784/1526266 , we should always use
> newtype when we have only a single constructor which has a single
> field. His example is this:
>
>     data Book = Book Int Int
>     newtype Book = Book (Int, Int)
>
> With newtype, the `Book` construct is guaranteed to be erased at
> compile time, to have the same representation as `(Int,Int)`. How to I
> measure the memory space costs of having `Book Int Int` hanging around
> at runtime, as opposed to just `(Int,Int)`? How many bytes does it
> cost to store `Book 4 5`? How many bytes does it cost to store `(4,5)`
> ? Can I ask GHC to tell me how many bytes the storage of each object
> would require? Or more generally, would looking at GHC Core for all my
> data structures inform me of the memory space costs for each of them?
>
> Thanks
>
> --
> Rob


More information about the Haskell-Cafe mailing list