
sedillard:
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.
Hmm. I wonder if *this* is the no-state-hack at play. Does -fno-state-hack help?
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?
Is it possible to boil this down to a program that doesn't use GL? -- Don