module Data.Array.Accelerate.Debug (
dump_sharing, dump_simpl_stats, dump_simpl_iterations, verbose,
queryFlag, setFlag,
traceMessage, traceEvent, tracePure,
inline, ruleFired, knownBranch, betaReduce, substitution, simplifierDone, fusionDone,
resetSimplCount, simplCount,
) where
import Data.Function ( on )
import Data.IORef
import Data.Label
import Data.List ( groupBy, sortBy, isPrefixOf )
import Data.Ord ( comparing )
import Numeric
import Text.PrettyPrint
import System.CPUTime
import System.Environment
import System.IO.Unsafe ( unsafePerformIO )
import qualified Data.Map as Map
#if __GLASGOW_HASKELL__ >= 704
import Debug.Trace ( traceIO, traceEventIO )
#else
import Debug.Trace ( putTraceMsg )
traceIO :: String -> IO ()
traceIO = putTraceMsg
traceEventIO :: String -> IO ()
traceEventIO = traceIO
#endif
#if !MIN_VERSION_base(4,6,0)
modifyIORef' :: IORef a -> (a -> a) -> IO ()
modifyIORef' ref f = do
x <- readIORef ref
let x' = f x
x' `seq` writeIORef ref x'
#endif
data FlagSpec flag = Option String
flag
data Flags = Flags
{
_dump_sharing :: !Bool
, _dump_simpl_stats :: !Bool
, _dump_simpl_iterations :: !Bool
, _verbose :: !Bool
, _acc_sharing :: !(Maybe Bool)
, _exp_sharing :: !(Maybe Bool)
, _fusion :: !(Maybe Bool)
, _simplify :: !(Maybe Bool)
}
$(mkLabels [''Flags])
allFlags :: [FlagSpec (Flags -> Flags)]
allFlags
= map (enable 'd') dflags
++ map (enable 'f') fflags ++ map (disable 'f') fflags
where
enable p (Option f go) = Option ('-':p:f) (go True)
disable p (Option f go) = Option ('-':p:"no-"++f) (go False)
dflags :: [FlagSpec (Bool -> Flags -> Flags)]
dflags =
[
Option "dump-sharing" (set dump_sharing)
, Option "dump-simpl-stats" (set dump_simpl_stats)
, Option "dump-simpl-iterations" (set dump_simpl_iterations)
, Option "verbose" (set verbose)
]
fflags :: [FlagSpec (Bool -> Flags -> Flags)]
fflags =
[ Option "acc-sharing" (set' acc_sharing)
, Option "exp-sharing" (set' exp_sharing)
, Option "fusion" (set' fusion)
, Option "simplify" (set' simplify)
]
where
set' f v = set f (Just v)
initialise :: IO Flags
initialise = parse `fmap` getArgs
where
defaults = Flags False False False False Nothing Nothing Nothing Nothing
parse = foldl parse1 defaults
parse1 opts this =
case filter (\(Option flag _) -> this `isPrefixOf` flag) allFlags of
[Option _ go] -> go opts
_ -> opts
options :: IORef Flags
options = unsafePerformIO $ newIORef =<< initialise
queryFlag :: (Flags :-> a) -> IO a
queryFlag f = get f `fmap` readIORef options
setFlag :: (Flags :-> a) -> a -> IO ()
setFlag f v = modifyIORef' options (set f v)
when :: (Flags :-> Bool) -> IO () -> IO ()
#ifdef ACCELERATE_DEBUG
when f action = do
enabled <- queryFlag f
if enabled then action
else return ()
#else
when _ _ = return ()
#endif
traceMessage :: (Flags :-> Bool) -> String -> IO ()
#ifdef ACCELERATE_DEBUG
traceMessage f str
= when f
$ do psec <- getCPUTime
let sec = fromIntegral psec * 1E-12 :: Double
traceIO $ showFFloat (Just 2) sec (':':str)
#else
traceMessage _ _ = return ()
#endif
traceEvent :: (Flags :-> Bool) -> String -> IO ()
#ifdef ACCELERATE_DEBUG
traceEvent f str = when f (traceEventIO str)
#else
traceEvent _ _ = return ()
#endif
tracePure :: (Flags :-> Bool) -> String -> a -> a
#ifdef ACCELERATE_DEBUG
tracePure f msg next = unsafePerformIO (traceMessage f msg) `seq` next
#else
tracePure _ _ next = next
#endif
ruleFired, inline, knownBranch, betaReduce, substitution :: String -> a -> a
inline = annotate Inline
ruleFired = annotate RuleFired
knownBranch = annotate KnownBranch
betaReduce = annotate BetaReduce
substitution = annotate Substitution
simplifierDone, fusionDone :: a -> a
simplifierDone = tick SimplifierDone
fusionDone = tick FusionDone
tick :: Tick -> a -> a
#ifdef ACCELERATE_DEBUG
tick t next = unsafePerformIO (modifyIORef' statistics (simplTick t)) `seq` next
#else
tick _ next = next
#endif
annotate :: (Id -> Tick) -> String -> a -> a
annotate name ctx = tick (name (Id ctx))
data SimplStats
= Simple !Int
| Detail {
ticks :: !Int,
details :: !TickCount
}
instance Show SimplStats where
show = render . pprSimplCount
statistics :: IORef SimplStats
statistics = unsafePerformIO $ newIORef =<< initSimplCount
initSimplCount :: IO SimplStats
#ifdef ACCELERATE_DEBUG
initSimplCount = do
d <- queryFlag dump_simpl_stats
return $! if d then Detail { ticks = 0, details = Map.empty }
else Simple 0
#else
initSimplCount = return $! Simple 0
#endif
resetSimplCount :: IO ()
#ifdef ACCELERATE_DEBUG
resetSimplCount = writeIORef statistics =<< initSimplCount
#else
resetSimplCount = return ()
#endif
simplTick :: Tick -> SimplStats -> SimplStats
simplTick _ (Simple n) = Simple (n+1)
simplTick t (Detail n dts) = Detail (n+1) (dts `addTick` t)
pprSimplCount :: SimplStats -> Doc
pprSimplCount (Simple n) = text "Total ticks:" <+> int n
pprSimplCount (Detail n dts)
= vcat [ text "Total ticks:" <+> int n
, text ""
, pprTickCount dts
]
simplCount :: IO Doc
simplCount = pprSimplCount `fmap` readIORef statistics
type TickCount = Map.Map Tick Int
data Id = Id String
deriving (Eq, Ord)
data Tick
= Inline Id
| RuleFired Id
| KnownBranch Id
| BetaReduce Id
| Substitution Id
| SimplifierDone
| FusionDone
deriving (Eq, Ord)
addTick :: TickCount -> Tick -> TickCount
addTick tc t =
let x = 1 + Map.findWithDefault 0 t tc
in x `seq` Map.insert t x tc
pprTickCount :: TickCount -> Doc
pprTickCount counts =
vcat (map pprTickGroup groups)
where
groups = groupBy sameTag (Map.toList counts)
sameTag = (==) `on` tickToTag . fst
pprTickGroup :: [(Tick,Int)] -> Doc
pprTickGroup [] = error "pprTickGroup"
pprTickGroup group =
hang (int groupTotal <+> text groupName)
2 (vcat [ int n <+> pprTickCtx t | (t,n) <- sortBy (flip (comparing snd)) group ])
where
groupName = tickToStr (fst (head group))
groupTotal = sum [n | (_,n) <- group]
tickToTag :: Tick -> Int
tickToTag Inline{} = 0
tickToTag RuleFired{} = 1
tickToTag KnownBranch{} = 2
tickToTag BetaReduce{} = 3
tickToTag Substitution{} = 4
tickToTag SimplifierDone = 99
tickToTag FusionDone = 100
tickToStr :: Tick -> String
tickToStr Inline{} = "Inline"
tickToStr RuleFired{} = "RuleFired"
tickToStr KnownBranch{} = "KnownBranch"
tickToStr BetaReduce{} = "BetaReduce"
tickToStr Substitution{} = "Substitution"
tickToStr SimplifierDone = "SimplifierDone"
tickToStr FusionDone = "FusionDone"
pprTickCtx :: Tick -> Doc
pprTickCtx (Inline v) = pprId v
pprTickCtx (RuleFired v) = pprId v
pprTickCtx (KnownBranch v) = pprId v
pprTickCtx (BetaReduce v) = pprId v
pprTickCtx (Substitution v) = pprId v
pprTickCtx SimplifierDone = empty
pprTickCtx FusionDone = empty
pprId :: Id -> Doc
pprId (Id s) = text s