[Haskell-cafe] Puzzled about inlining and specialise inline under ghc -O2

2012-03-22 Thread Rafal Kolanski
Dear Haskell-Cafe,

I'm computing a histogram of a bunch of symbols with up to 8 bits of
information each, stored in a unboxed vector of Word8. The histogram is
represented as an unboxed vector of Int with size 2^bits. I compute the
histogram by folding an increment function.

The problem: depending on what types and what annotations I give to the
increment and histogram function (see below), the GC gets through a
different amount of memory. I'm using GHC 7.0.3 and -O2. I'd like to
better understand how and why the optimisation does/doesn't kick in.

Here are the functions with the most generic types I can think of:

import qualified Data.Vector.Unboxed as UV
import qualified Data.Vector.Unboxed.Mutable as UMV
import Control.Monad.Primitive (PrimMonad, PrimState)

increment :: (PrimMonad m, UMV.Unbox a, Num a, Integral b) =
UMV.MVector (PrimState m) a - b - m (UMV.MVector (PrimState m) a)
increment v x = do
n - UMV.read v (fromIntegral x)
UMV.write v (fromIntegral x) (n+1)
return v

histogram :: (Integral a, UMV.Unbox a) = Int - UV.Vector a -
UV.Vector Int
histogram bitsPerSym v = runST $ do
a - UMV.replicate (2^bitsPerSym) (0::Int)
a' - UV.foldM' increment a v
UV.unsafeFreeze a'

Running my test load, I get: total alloc =  33,206,568 bytes

Looking at the core, ghc is not specialising the functions, even if I
tell it to inline them. So let's brutally change the types to be as
specific as I need for my application:

increment :: UMV.MVector s Int - Word8 - ST s (UMV.MVector s Int)
histogram :: Int - UV.Vector Word8 - UV.Vector Int

result: total alloc =  19,581,152 bytes

and if I put INLINE pragmas for both functions: 16,952,512 bytes

I should be able to achieve the same effect with SPECIALISE INLINE
pragmas, right? Let's try that:

{-# SPECIALISE INLINE increment :: UMV.MVector s Int - Word8 - ST s
(UMV.MVector s Int) #-}
{-# SPECIALISE INLINE histogram :: Int - UV.Vector Word8 - UV.Vector
Int #-}

result: 33,139,856 bytes
(GHC can't figure out application of the first rule, giving:
  Warning: RULE left-hand side too complicated to desugar)

So unfortunately my most generic form won't work here, I need to
specialise increment to be in ST (which sucks, because I want it to work
for both IO and ST):

increment :: (UMV.Unbox a, Num a, Integral b) =
UMV.MVector s a - b - ST s (UMV.MVector s a)
{-# SPECIALISE INLINE increment :: UMV.MVector s Int - Word8 - ST s
(UMV.MVector s Int) #-}

result: 17,016,192 bytes

This is very close to the most specific function instantiations and
INLINE, but:
- I've lost being generic between ST and IO
- it's still a little bigger than the specific instances + INLINE

So my questions are: what is going on? Can I have genericity between ST
and IO while keeping the low GC usage? How come SPECIALISE INLINE does
not give the same result as specific instances + INLINE?

Obviously, for this example, I don't really *need* increment to work
inside IO, since I'm using runST... but I want to understand what
is going on. Profiling Haskell performance and memory usage has always
been difficult for me.

Much thanks in advance,

Rafal Kolanski.

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Puzzled

2007-10-06 Thread Peter Verswyvelen
Ouch, now I really feel stupid, because I *knew* about the stricter 
foldl' version.


But great to know about the new strictness on vars! I really should get 
GHC 6.8 RC1 for Windows...


I just got puzzled why mysum worked better than sum for some reason... 
mysym looks like an identical unfolded version of sum to me, yet it 
behaved differently. mysum, also being non-strict, did *not* stack 
overflow. Maybe because it is a simpler / more unfolded version, so it 
needs to keep less euh unevaluated thunks (how are these called?) on 
the stack? So I would also have gotten a stack overflow with mysum, it 
just needed more iterations?


Many thanks,
Peter


Bertram Felgenhauer wrote:

Peter Verswyvelen wrote:
  
The following code, when compiled with GHC 6.6.1 --make -O gives a stack 
overflow when I enter 100 as a command line argument:


(please don't look at the efficiency of the code, it can of course be 
improved a lot both in time performance and numeric precision...)


import System

leibnizPI :: Integer - Double
leibnizPI n = sum (map leibnizTerm [0..n]) where
   leibnizTerm n = let i = fromIntegral n
   in 4 * (((-1) ** i) / (2*i+1))
main = do
 args - getArgs
 let n = read (head args)
 print (leibnizPI n)

However, if I replace

main = print (leibnizPI 100)

is does not stack overflow.

Now, if I leave the original main, but replace sum in leibnizPI by

mysum xs = aux 0 xs
   where
 aux s (x:xs) = aux (s+x) xs
 aux s [] = s

Then I don't get a stack overflow.

However, I do get a stack overflow when I compile it without -O, in all 
cases.


This puzzles me. I don't see any non-tail calls in my code...

I guess it has to do with strictness? 
http://www.haskell.org/haskellwiki/Performance/Strictness



Yes.

The problem is that without optimizations, both  sum  and  mysum
build a large unevaluated expression of the form

((..((0+x1)+x2)+...)+xn)

The stack overflow happens when this expression gets evaluated. At that
point, the outermost (+) demands the result of the (+) on the next level,
and so on.

To prevent this you need a stricter version of sum. You can build one
with foldl':

  

import Data.List

sum' :: Num a = [a] - a
sum' = foldl' (+) 0



Arguably this is the correct definition of sum. The problem you
had is fairly common.

  
Why isn't it possible to annotate strictness on the type signature in 
Haskell as in Clean? Is this on the TODO list?



Strictness is independent from the type in Haskell (but see the fourth
solution presented below). You can explicitely make one value at least
as strict as another using  seq:

  

mysum' xs = aux 0 xs
   where
 aux s (x:xs) = let s' = s+x in s' `seq` aux s' xs
 aux s [] = s



In ghc, you can mark arguments as strict

  

mysum'' xs = aux 0 xs
   where
 aux !s (x:xs) = aux (s+x) xs
 aux !s [] = s



This is a language extension, you need -fbang-patterns
to allow it, or with a recent ghc (6.7, 6.9 or a 6.8 rc)
a {-# LANGUAGE BangPatterns #-} pragma, or -XBangPatterns.

A fourth possibility, which is Haskell 98 again, is to declare an
auxiliary data type with a strict field:

  

data Strict a = Strict !a

mysum''' xs = aux (Strict 0) xs
  where
aux (Strict s) (x:xs) = aux (Strict (s+x)) xs
aux (Strict s) [] = s



Hope that helps,

Bertram
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


  


___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Puzzled

2007-10-06 Thread Chaddaï Fouché
2007/10/6, Peter Verswyvelen [EMAIL PROTECTED]:
  But great to know about the new strictness on vars! I really should get GHC
 6.8 RC1 for Windows...

Just in case you misunderstood : this functionality was already there
in GHC 6.4, it's just the new syntax to active it that is available
only in recent versions of GHC : this new syntax will hopefully be
adopted by others Haskell compilers and thus become a
compiler-agnostic way of specifying extensions to Haskell98 (so that
others compiler than GHC can tell you why they won't compile this
wonderful code that use all the latest extensions that have been
included into your release candidate of GHC, much better than the old
way where they just told you the syntax was wrong, isn't it ?).

-- 
Jedaï
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Puzzled

2007-10-06 Thread Stuart Cook
On 10/6/07, Bertram Felgenhauer [EMAIL PROTECTED] wrote:
 This is a language extension, you need -fbang-patterns
 to allow it, or with a recent ghc (6.7, 6.9 or a 6.8 rc)
 a {-# LANGUAGE BangPatterns #-} pragma, or -XBangPatterns.

LANGUAGE pragmas (including BangPatterns) work just fine in 6.6, by the way.


Stuart
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Puzzled

2007-10-06 Thread Brent Yorgey
Just to be clear, I doubt the difference had anything to do with
tail-recursion per se.   My guess is that with the mysum version, ghc was
able to do some strictness analysis/optimization that it wasn't able to do
(for whatever reason) with the first version.  The best solution (as others
have pointed out) is to create a strict version of sum with foldl'.

On 10/6/07, Peter Verswyvelen [EMAIL PROTECTED] wrote:

  Ouch, now I really feel stupid, because I *knew* about the stricter
 foldl' version.

 But great to know about the new strictness on vars! I really should get
 GHC 6.8 RC1 for Windows...

 I just got puzzled why mysum worked better than sum for some reason...
 mysym looks like an identical unfolded version of sum to me, yet it behaved
 differently. mysum, also being non-strict, did *not* stack overflow. Maybe
 because it is a simpler / more unfolded version, so it needs to keep less
 euh unevaluated thunks (how are these called?) on the stack? So I would
 also have gotten a stack overflow with mysum, it just needed more
 iterations?

 Many thanks,
 Peter


 Bertram Felgenhauer wrote:

 Peter Verswyvelen wrote:

  The following code, when compiled with GHC 6.6.1 --make -O gives a stack
 overflow when I enter 100 as a command line argument:

 (please don't look at the efficiency of the code, it can of course be
 improved a lot both in time performance and numeric precision...)

 import System

 leibnizPI :: Integer - Double
 leibnizPI n = sum (map leibnizTerm [0..n]) where
leibnizTerm n = let i = fromIntegral n
in 4 * (((-1) ** i) / (2*i+1))
 main = do
  args - getArgs
  let n = read (head args)
  print (leibnizPI n)

 However, if I replace

 main = print (leibnizPI 100)

 is does not stack overflow.

 Now, if I leave the original main, but replace sum in leibnizPI by

 mysum xs = aux 0 xs
where
  aux s (x:xs) = aux (s+x) xs
  aux s [] = s

 Then I don't get a stack overflow.

 However, I do get a stack overflow when I compile it without -O, in all
 cases.

 This puzzles me. I don't see any non-tail calls in my code...

 I guess it has to do with strictness?
 http://www.haskell.org/haskellwiki/Performance/Strictness

  Yes.

 The problem is that without optimizations, both  sum  and  mysum
 build a large unevaluated expression of the form

 ((..((0+x1)+x2)+...)+xn)

 The stack overflow happens when this expression gets evaluated. At that
 point, the outermost (+) demands the result of the (+) on the next level,
 and so on.

 To prevent this you need a stricter version of sum. You can build one
 with foldl':

import Data.List

 sum' :: Num a = [a] - a
 sum' = foldl' (+) 0

  Arguably this is the correct definition of sum. The problem you
 had is fairly common.

Why isn't it possible to annotate strictness on the type signature in
 Haskell as in Clean? Is this on the TODO list?

  Strictness is independent from the type in Haskell (but see the fourth
 solution presented below). You can explicitely make one value at least
 as strict as another using  seq:

mysum' xs = aux 0 xs
where
  aux s (x:xs) = let s' = s+x in s' `seq` aux s' xs
  aux s [] = s

  In ghc, you can mark arguments as strict

mysum'' xs = aux 0 xs
where
  aux !s (x:xs) = aux (s+x) xs
  aux !s [] = s

  This is a language extension, you need -fbang-patterns
 to allow it, or with a recent ghc (6.7, 6.9 or a 6.8 rc)
 a {-# LANGUAGE BangPatterns #-} pragma, or -XBangPatterns.

 A fourth possibility, which is Haskell 98 again, is to declare an
 auxiliary data type with a strict field:

data Strict a = Strict !a

 mysum''' xs = aux (Strict 0) xs
   where
 aux (Strict s) (x:xs) = aux (Strict (s+x)) xs
 aux (Strict s) [] = s

  Hope that helps,

 Bertram
 ___
 Haskell-Cafe mailing list
 [EMAIL PROTECTED]://www.haskell.org/mailman/listinfo/haskell-cafe




 ___
 Haskell-Cafe mailing list
 Haskell-Cafe@haskell.org
 http://www.haskell.org/mailman/listinfo/haskell-cafe


___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


[Haskell-cafe] Puzzled

2007-10-05 Thread Peter Verswyvelen
The following code, when compiled with GHC 6.6.1 --make -O gives a stack 
overflow when I enter 100 as a command line argument:


(please don't look at the efficiency of the code, it can of course be 
improved a lot both in time performance and numeric precision...)


import System

leibnizPI :: Integer - Double
leibnizPI n = sum (map leibnizTerm [0..n]) where
   leibnizTerm n = let i = fromIntegral n
   in 4 * (((-1) ** i) / (2*i+1))
main = do
 args - getArgs
 let n = read (head args)
 print (leibnizPI n)

However, if I replace

main = print (leibnizPI 100)

is does not stack overflow.

Now, if I leave the original main, but replace sum in leibnizPI by

mysum xs = aux 0 xs
   where
 aux s (x:xs) = aux (s+x) xs
 aux s [] = s

then I don't get a stack overflow.

However, I do get a stack overflow when I compile it without -O, in all 
cases.


This puzzles me. I don't see any non-tail calls in my code...

I guess it has to do with strictness? 
http://www.haskell.org/haskellwiki/Performance/Strictness


Why isn't it possible to annotate strictness on the type signature in 
Haskell as in Clean? Is this on the TODO list?


Many thanks,
Peter


___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Puzzled

2007-10-05 Thread Bertram Felgenhauer
Peter Verswyvelen wrote:
 The following code, when compiled with GHC 6.6.1 --make -O gives a stack 
 overflow when I enter 100 as a command line argument:

 (please don't look at the efficiency of the code, it can of course be 
 improved a lot both in time performance and numeric precision...)

 import System

 leibnizPI :: Integer - Double
 leibnizPI n = sum (map leibnizTerm [0..n]) where
leibnizTerm n = let i = fromIntegral n
in 4 * (((-1) ** i) / (2*i+1))
 main = do
  args - getArgs
  let n = read (head args)
  print (leibnizPI n)

 However, if I replace

 main = print (leibnizPI 100)

 is does not stack overflow.

 Now, if I leave the original main, but replace sum in leibnizPI by

 mysum xs = aux 0 xs
where
  aux s (x:xs) = aux (s+x) xs
  aux s [] = s

 Then I don't get a stack overflow.

 However, I do get a stack overflow when I compile it without -O, in all 
 cases.

 This puzzles me. I don't see any non-tail calls in my code...

 I guess it has to do with strictness? 
 http://www.haskell.org/haskellwiki/Performance/Strictness

Yes.

The problem is that without optimizations, both  sum  and  mysum
build a large unevaluated expression of the form

((..((0+x1)+x2)+...)+xn)

The stack overflow happens when this expression gets evaluated. At that
point, the outermost (+) demands the result of the (+) on the next level,
and so on.

To prevent this you need a stricter version of sum. You can build one
with foldl':

 import Data.List
 
 sum' :: Num a = [a] - a
 sum' = foldl' (+) 0

Arguably this is the correct definition of sum. The problem you
had is fairly common.

 Why isn't it possible to annotate strictness on the type signature in 
 Haskell as in Clean? Is this on the TODO list?

Strictness is independent from the type in Haskell (but see the fourth
solution presented below). You can explicitely make one value at least
as strict as another using  seq:

 mysum' xs = aux 0 xs
where
  aux s (x:xs) = let s' = s+x in s' `seq` aux s' xs
  aux s [] = s

In ghc, you can mark arguments as strict

 mysum'' xs = aux 0 xs
where
  aux !s (x:xs) = aux (s+x) xs
  aux !s [] = s

This is a language extension, you need -fbang-patterns
to allow it, or with a recent ghc (6.7, 6.9 or a 6.8 rc)
a {-# LANGUAGE BangPatterns #-} pragma, or -XBangPatterns.

A fourth possibility, which is Haskell 98 again, is to declare an
auxiliary data type with a strict field:

 data Strict a = Strict !a

 mysum''' xs = aux (Strict 0) xs
   where
 aux (Strict s) (x:xs) = aux (Strict (s+x)) xs
 aux (Strict s) [] = s

Hope that helps,

Bertram
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


[Haskell-cafe] Puzzled by error with forall quantifier.

2004-02-02 Thread Theodore S. Norvell
Can anyone explain the following error message from Hug98
(with extensions enabled)?
I have

 class Space t
 class Space t = HasY v t
   where
 assignY :: v - t - t
 getY :: t - v
 varY :: forall w . Space w = v - (t-t) - (w-w)
I get an error on the last definition quantifier does not
mention type variable v (and if I quantify v, then it complains
that t is not quantified).
The idea I'm trying to express is that for any instance of HasY v t
there should be a function varY with type
 v - (t-t) - (w-w)
for some type w of class Space.
Any help much appreciated.

Is there any kind of tutorial introduction to forall out there?

Cheers,
Theo Norvell
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Puzzled by error with forall quantifier.

2004-02-02 Thread Iavor S. Diatchki
hello,
just skip the forall.   free type variables are implicitly 
forall-quantified.
the forall keyword is used for functions that need to take polymorphic 
functions
as arguments, but that's advanced stuff.
so in short, this should work:

 class Space t
 class Space t = HasY v t
   where
 assignY :: v - t - t
 getY :: t - v
 varY ::  Space w = v - (t-t) - (w-w)
the next problem you are likely to run into is ambiguities,
and you might want to take a look at functional dependencies.
hope this helps
iavor
Theodore S. Norvell wrote:

Can anyone explain the following error message from Hug98
(with extensions enabled)?
I have

 class Space t
 class Space t = HasY v t
   where
 assignY :: v - t - t
 getY :: t - v
 varY :: forall w . Space w = v - (t-t) - (w-w)
I get an error on the last definition quantifier does not
mention type variable v (and if I quantify v, then it complains
that t is not quantified).
The idea I'm trying to express is that for any instance of HasY v t
there should be a function varY with type
 v - (t-t) - (w-w)
for some type w of class Space.
Any help much appreciated.

Is there any kind of tutorial introduction to forall out there?

Cheers,
Theo Norvell
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe


--
==
| Iavor S. Diatchki, Ph.D. student   | 
| Department of Computer Science and Engineering |
| School of OGI at OHSU  |
| http://www.cse.ogi.edu/~diatchki   |
==

___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Puzzled by error with forall quantifier.

2004-02-02 Thread Theodore S. Norvell
Iavor S. Diatchki wrote:

just skip the forall.   free type variables are implicitly 
forall-quantified.
Of course!  Thanks.  The problem is that I actually wanted exists.
However as the type that exists is functionally dependent on other the
parameters to the class I think I can deal with it using functional
dependencies, as you suggest.
Sorry for the elementary question.

Cheers,
Theo Norvell
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe