STUArray woes

| No Comments | No TrackBacks

So a little while ago, I was trying to write a nice, clear version of the language shootout n-body problem, using the ST monad, and STUArrays. Though I ran into a snag; I was getting segmentation faults, for very small values of n (< 23), and not knowing enough about such things, I have no idea where to begin in diagnosing the problem. So, I shall post my code here, and hope that someone might have some ideas. I've talked to Don Stewart about it, but he hasn't got back to me yet.

(All the MUArray instance stuff is from Don's work, which I nicked)

So, here we have it:

> {-# OPTIONS -O2 -funbox-strict-fields #-}
> {-# LANGUAGE BangPatterns          #-}
> {-# LANGUAGE UnboxedTuples         #-}
> {-# LANGUAGE MagicHash             #-}
> {-# LANGUAGE MultiParamTypeClasses #-}
> 
> module Main where
> 
> import System.Environment
> import Data.Array.Base
> import GHC.Exts
> import GHC.ST
> import GHC.Arr
> import Control.Monad
> import Control.Monad.ST
> import Data.List
> import Foreign.Storable
> import Text.Printf
> import Data.STRef
> 
> 
> data Vec3 = V !Double !Double !Double deriving (Show)
> data Body = B {  
>                  pos ::  {-# UNPACK #-} !Vec3,
>                  vel ::  {-# UNPACK #-} !Vec3,
>                  mass :: !Double
>                } deriving (Show)
> 
> 
> main = do
>     n <- getArgs >>= \xs -> if null xs then return 1000 else (readIO.head) xs
>     let (e,e') = runST $ do
>             ps <- planets
>             offset ps
>             e1 <- energy ps
>             advn n ps
>             e2 <- energy ps
>             return (e1,e2)
>     prtnum e
>     prtnum e'
> 
> 
> offset ps = do
>     v <- newSTRef (V 0 0 0)
>     (B p ve m) <- readArray ps 0
>     forM_ [0..numPs] $ \i -> do
>         p <- readArray ps i
>         modifySTRef v (.+. momentum p)
>     modifySTRef v (./ solar_mass)
>     v' <- readSTRef v
>     writeArray ps 0 (B p (ve.-. v') m)
> 
>     
> 
> advn 0 ps = do
>     return ps
> advn n ps = do
>     advance deltat ps
>     -- e <- energy ps
>     -- unsafeIOToST (prtnum e)
>     advn (n-1) ps
> 
> advance dt ps = do
>     forM_ [0..numPs] $ \i -> do
>         (B p v m) <- readArray ps i
>         vvar <- newSTRef v
>         forM_ [i+1..numPs] $ \j -> do
>             (B p' v' m') <- readArray ps j
>             let dp = p .-. p'
>                 dst = mag dp
>                 magnit = dt / (dst * dst * dst)
>                 change = magnit *. dp
>                 sca1 = m' *. change
>                 sca2 = m *. change
>             -- writeArray ps I (B p (v .-. sca1) m)
>             modifySTRef vvar (.-. sca1)
>             writeArray ps j (B p' (v' .+. sca2) m')
>         vvar' <- readSTRef vvar
>         writeArray ps I (move dt (B p vvar' m))
> 
> 
> energy ps = do
>     e <- newSTRef (0 :: Double)
>     
>     forM_ [0..numPs] $ \i -> do
>         b1 <- readArray ps i
>         modifySTRef e ((+) (kinetic b)1)
>         
>         forM_ [i+1..numPs] $ \j -> do
>             b2 <- readArray ps j
>             let x = potential b1 b2
>             modifySTRef e (subtract x)
>     e' <- readSTRef e
>     return e'
> 
> 
> 
> move dt (B p v m) = B (p .+. dt *. v) v m
> 
> 
> 
> 
> -----------------------
> solar_mass, deltat, days_per_year :: Double
> days_per_year = 365.24
> dp = days_per_year
> solar_mass    = 4 * pi * pi
> deltat       = 0.01
> numPs       = length planets' - 1
> 
> planets'' = newArray_ (0,numPs) :: ST s (STUArray s Int Body)
>     -- (B (V 0 0 0) (V 0 0 0) 1)
> 
> planets = do
>     arr <- planets''
>     forM_ (zip [0..] planets') $ \(i,p) -> do
>         writeArray arr I p
>     return arr
> 
> planets' =
>     [B  (V  0.0
>             0.0
>             0.0) 
>         (V  0.0
>             0.0
>             0.0) 
>         solar_mass,
>         
>      B  (V  4.84143144246472090e+00
>             (-1.16032004402742839e+00)
>             (-1.03622044471123109e-01)) 
>         (V  (1.66007664274403694e-03*dp) 
>             (7.69901118419740425e-03*dp)
>             ((-6.90460016972063023e-05)*dp)) 
>         (9.54791938424326609e-04 * solar_mass),
>         
>      B  (V  8.34336671824457987e+00
>             4.12479856412430479e+00
>             (-4.03523417114321381e-01))
>         (V  ((-2.76742510726862411e-03)*dp)
>             (4.99852801234917238e-03*dp)
>             (2.30417297573763929e-05*dp)) 
>         (2.85885980666130812e-04 * solar_mass),
>         
>      B  (V  1.28943695621391310e+01
>             (-1.51111514016986312e+01)
>             (-2.23307578892655734e-01)) 
>         (V  (2.96460137564761618e-03*dp)
>             (2.37847173959480950e-03*dp)
>             ((-2.96589568540237556e-05)*dp)) 
>         (4.36624404335156298e-05 * solar_mass),
>         
>      B  (V  1.53796971148509165e+01
>             (-2.59193146099879641e+01)
>             1.79258772950371181e-01) 
>         (V  (2.68067772490389322e-03*dp)
>             (1.62824170038242295e-03*dp)
>             ((-9.51592254519715870e-05)*dp)) 
>         (5.15138902046611451e-05 * solar_mass)
>     ]
> 
> 
> -----------------------
> 
> infix 4 .-.
> infix 4 .+.
> -- infix 5 .*.
> infixr 5 *.
> infixl 5 ./
> 
> {-# INLINE (.+.) #-}
> {-# INLINE (.-.) #-}
> -- {-# INLINE (.*.) #-}
> V x y z .+. V x' y' z' = V (x+x') (y+y') (z+z')  
> V x y z .-. V x' y' z' = V (x-x') (y-y') (z-z')  
> -- V x y z .*. V x' y' z' = V (x*x') (y*y') (z*z')
> 
> {-# INLINE (*.) #-}
> n *. (V x y z) = V (n*x) (n*y) (n*z)
> {-# INLINE (./) #-}
> V x y z ./ n = V (x/n) (y/n) (z/n)
> 
> {-# INLINE momentum #-}
> momentum :: Body -> Vec3
> momentum (B _ v m) = m *. v
> 
> {-# INLINE kinetic #-}
> kinetic x =  0.5 * mass x * (mag2.vel) x
> 
> 
> potential a b =
>     let dst = dist' a b
>     in if dst <= 0
>         then 0
>         else (mass a * mass b) / dist' a b
> 
> {-# INLINE mag #-}
> mag :: Vec3 -> Double
> mag = sqrt . mag2
> 
> {-# INLINE mag2 #-}
> mag2 (V x y z) = x*x + y*y + z*z
> 
> {-# INLINE dist #-}
> dist v1 v2 = sqrt $ dist2 v1 v2
> 
> {-# INLINE dist2 #-}
> dist2 v1 v2 = mag2 $ v1 .-. v2
> 
> {-# INLINE dist' #-}
> dist' b1 b2 = dist (pos b1) (pos b2)
> 
> prtnum x = putStrLn $ printf "%.9f" x
> 
> --------------------
> bodyScale :: Int# -> Int#
> bodyScale n = (scale *# 7#) *# n
>      where I# scale = sizeOf (undefined :: Double)
> 
> instance MArray (STUArray s) Body (ST s) where
> 
>     {-# INLINE getBounds #-}
>     getBounds (STUArray l h _ _) = return (l,h)
> 
>     {-# INLINE getNumElements #-}
>     getNumElements (STUArray _ _ n _) = return n
> 
>     {-# INLINE unsafeNewArray_ #-}
>     unsafeNewArray_ (l,u) = unsafeNewArraySTUArray_ (l,u) bodyScale -- bytes 
> 
>     {-# INLINE newArray_ #-}
>     newArray_ bounds = newArray bounds (B (V 0 0 0) (V 0 0 0) 1)
>     
> 
>     {-# INLINE unsafeRead #-}
>     unsafeRead (STUArray _ _ _ arr) (I# i) = ST $ \s1 ->
>         let j = bodyScale i in
>         case readDoubleArray# arr j         s1 of { (# s2, xd    #) ->
>         case readDoubleArray# arr (j +# 1#) s2 of { (# s3, yd    #) ->
>         case readDoubleArray# arr (j +# 2#) s3 of { (# s4, zd    #) ->
>         case readDoubleArray# arr (j +# 3#) s4 of { (# s5, vxd   #) ->
>         case readDoubleArray# arr (j +# 4#) s5 of { (# s6, vyd   #) ->
>         case readDoubleArray# arr (j +# 5#) s6 of { (# s7, vzd   #) ->
>         case readDoubleArray# arr (j +# 6#) s7 of { (# s8, massd #) ->
>         (# s8, B { pos    = V (D# xd) (D# yd) (D# zd)
>                     , vel    = V (D# vxd) (D# vyd) (D# vzd)
>                     , mass = D# massd } #) }}}}}}}
> 
>     {-# INLINE unsafeWrite #-}
>     unsafeWrite (STUArray _ _ _ arr) (I# i)
>                 (B (V (D# xd) (D# yd) (D# zd)) (V (D# vxd) (D# vyd) (D# vzd)) (D# massd))
>         = ST $ \s1 ->
>         let j = bodyScale i in
>         case writeDoubleArray# arr j          xd   s1  of {s2 ->
>         case writeDoubleArray# arr (j +# 1#)  yd   s2  of {s3 ->
>         case writeDoubleArray# arr (j +# 2#)  zd   s3  of {s4 ->
>         case writeDoubleArray# arr (j +# 3#) vxd   s4  of {s5 ->
>         case writeDoubleArray# arr (j +# 4#) vyd   s5  of {s6 ->
>         case writeDoubleArray# arr (j +# 5#) vzd   s6  of {s7 ->
>         case writeDoubleArray# arr (j +# 6#) massd s7  of {s8 ->
>         (# s8, () #) }}}}}}}
> 

No TrackBacks

TrackBack URL: http://axman6.homeip.net/cgi-bin/mt/mt-tb.cgi/18

Leave a comment

February 2009

Sun Mon Tue Wed Thu Fri Sat
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
OpenID accepted here Learn more about OpenID
Powered by Movable Type 4.23-en

About this Entry

This page contains a single entry by Alex Mason published on January 30, 2009 9:41 PM.

Software lockdown! was the previous entry in this blog.

N-bodies speedup (50%!) is the next entry in this blog.

Find recent content on the main index or look in the archives to find all content.