laziness, memoization and inlining

Simon Peyton-Jones simonpj at microsoft.com
Wed May 14 03:48:00 EDT 2008


Scott

| I'm experiencing some undesirable performance behavior, I suspect from
| inlining things that shouldn't be, defeating my memoization attempts.

This is bad, very bad.  I think Don is right. I believe the following is happening.  In your main program you have

   do   let mesh = memoMesh rawMesh
           display :: IO ()
            display = draw mesh >> stuff
        setDisplayCallback display
        glutMainLoop

So the effect is that 'display' is performed many times, by glutMainLoop.

Now 'display' is seen by GHC thus:
        display = \s -> draw mesh s >> stuff

The "\s" says "given the state of the world, s, I'll draw the mesh on it".  The "state hack" makes GHC think that a "\s" will only ever be called once (which is utterly false in this case), so it can inline mesh=memoMesh rawMesh.  Result disaster.


I bet you'll be fine if you compile your main module with -fno-state-hack.

But I should fix this, somehow.  It's coming up too often to justify the hack.  Can you make a Trac bug report, and include your message and this one?

Thanks for reporting it.

Simon



| -----Original Message-----
| From: glasgow-haskell-users-bounces at haskell.org [mailto:glasgow-haskell-users-bounces at haskell.org] On
| Behalf Of Scott Dillard
| Sent: 14 May 2008 00:13
| To: glasgow-haskell-users at haskell.org
| Subject: laziness, memoization and inlining
|
| Hi Everybody,
|
| I'm experiencing some undesirable performance behavior, I suspect from
| inlining things that shouldn't be, defeating my memoization attempts.
| I've been experimenting with purely functional 3D modeling code, so a
| mesh is (initially) something like
|
| > type Mesh = Map (Int,Int) (Int,Int)
|
| that is, a function from from an edge to the next edge around the
| face, where an edge is a pair of Ints (the vertices.)
|
| This nice and pure and everything, but its slow to read from. So I
| have another immutable pointer-based representation
|
| > data Edge = Edge { edgeOrg :: Int , edgeSym :: Edge , edgeNext :: Edge }
|
| which is something like a half-edge, for those familiar with such
| things. Its basically a big net made of circular lists that are tied
| together. I do the knot tying stuff to create this thing,
|
| > memoMesh :: Map (Int,Int) (Int,Int) -> Edge Int
| > memoMesh nexts = head $ Map.elems ties
| >   where
| >     ties = Map.mapWithKey (\ij _ -> make ij) nexts
| >     lookup ij = trace "hello" $ fromJust $ Map.lookup ij ties
| >     make ij@(i,j) = Edge i (lookup (j,i)) (lookup . fromJust $ Map.lookup ij nexts)
|
| The program first loads the model file and creates the Edge-based mesh
| using the memoMesh function. The result is then captured in the
| closure for the rendering callback in GLUT. When I compile with -O0 I
| see the "hello" traces only during the first drawing. Subsequent
| redraws are fast and output no traces. When I compile with -O1 or -O2,
| the traces get output on every redraw, and its very slow. I suspect
| all of the calls which create the mesh are inlined into the rendering
| callback, effectively rebuilding the mesh on every draw.
|
| I've tried littering NOINLINE pragmas all around, to no avail.
|
| The main function is something like
|
| > main = do
| >   initGlut ...
| >   rawMesh <- loadMeshFile ...
| >   let
| >     mesh = memoMesh rawMesh
| >     otherstuff = ...
| >     display =
| >       draw mesh >> amongOtherThings
| >   displayCallback $= display
| >   glutMainLoop
|
| Can someone help me understand what's going on here? Is there a nice
| solution to this, hopefully a single strategic pragma or something?
|
| Scott
| _______________________________________________
| Glasgow-haskell-users mailing list
| Glasgow-haskell-users at haskell.org
| http://www.haskell.org/mailman/listinfo/glasgow-haskell-users


More information about the Glasgow-haskell-users mailing list