{-# LANGUAGE CPP #-}
{-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeOperators #-}
#ifdef ACCELERATE_DEBUG
#if __GLASGOW_HASKELL >= 800
{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}
#endif
#else
{-# OPTIONS_GHC -fno-warn-unused-binds #-}
{-# OPTIONS_GHC -fno-warn-unused-do-bind #-}
{-# OPTIONS_GHC -fno-warn-unused-imports #-}
#endif
module Data.Array.Accelerate.Debug.Flags (
Flags, Mode,
acc_sharing, exp_sharing, fusion, simplify, flush_cache, force_recomp, fast_math, verbose,
dump_phases, dump_sharing, dump_simpl_stats, dump_simpl_iterations, dump_vectorisation,
dump_dot, dump_simpl_dot, dump_gc, dump_gc_stats, debug_cc, dump_cc, dump_ld, dump_asm,
dump_exec, dump_sched,
accInit,
queryFlag, setFlag, setFlag', setFlags, clearFlag, clearFlags,
when, unless,
) where
import Control.Monad.IO.Class
import Data.IORef
import Data.Label
import Data.Label.Derive
import Data.List
import System.Environment
import System.IO.Unsafe
import Text.PrettyPrint hiding ( Mode )
import qualified Control.Monad as M ( when, unless )
import Foreign.C
import Foreign.Marshal
import Foreign.Ptr
import GHC.Foreign as GHC
import GHC.IO.Encoding ( getFileSystemEncoding )
import Debug.Trace
data FlagSpec flag = Option String
flag
data OptKind f
= NoArg f
| IntArg (Int -> f)
data Flags = Flags
{
_acc_sharing :: !(Maybe Bool)
, _exp_sharing :: !(Maybe Bool)
, _fusion :: !(Maybe Bool)
, _simplify :: !(Maybe Bool)
, _unfolding_use_threshold :: !(Maybe Int)
, _flush_cache :: !(Maybe Bool)
, _force_recomp :: !(Maybe Bool)
, _fast_math :: !(Maybe Bool)
, _verbose :: !Bool
, _dump_phases :: !Bool
, _dump_sharing :: !Bool
, _dump_simpl_stats :: !Bool
, _dump_simpl_iterations :: !Bool
, _dump_vectorisation :: !Bool
, _dump_dot :: !Bool
, _dump_simpl_dot :: !Bool
, _dump_gc :: !Bool
, _dump_gc_stats :: !Bool
, _debug_cc :: !Bool
, _dump_cc :: !Bool
, _dump_ld :: !Bool
, _dump_asm :: !Bool
, _dump_exec :: !Bool
, _dump_sched :: !Bool
}
$(mkLabelsWith defaultNaming True False False True ''Flags)
allFlags :: [FlagSpec (OptKind (Flags -> Flags))]
allFlags
= map (enableB 'd') dflags
++ map (enableB 'f') fflagsB ++ map (disableB 'f') fflagsB
++ map (enableI 'f') fflagsI
where
enableI p (Option f go) = Option ('-':p:f) (IntArg go)
enableB p (Option f go) = Option ('-':p:f) (NoArg (go True))
disableB p (Option f go) = Option ('-':p:"no-"++f) (NoArg (go False))
fflagsB :: [FlagSpec (Bool -> Flags -> Flags)]
fflagsB =
[ Option "acc-sharing" (set' acc_sharing)
, Option "exp-sharing" (set' exp_sharing)
, Option "fusion" (set' fusion)
, Option "simplify" (set' simplify)
, Option "flush-cache" (set' flush_cache)
, Option "force-recomp" (set' force_recomp)
, Option "fast-math" (set' fast_math)
]
where
set' f v = set f (Just v)
fflagsI :: [FlagSpec (Int -> Flags -> Flags)]
fflagsI =
[ Option "unfolding-use-threshold" (set' unfolding_use_threshold)
]
where
set' f v = set f (Just v)
dflags :: [FlagSpec (Bool -> Flags -> Flags)]
dflags =
[ Option "verbose" (set verbose)
, Option "dump-phases" (set dump_phases)
, Option "dump-sharing" (set dump_sharing)
, Option "dump-simpl-stats" (set dump_simpl_stats)
, Option "dump-simpl-iterations" (set dump_simpl_iterations)
, Option "dump-vectorisation" (set dump_vectorisation)
, Option "dump-dot" (set dump_dot)
, Option "dump-simpl-dot" (set dump_simpl_dot)
, Option "dump-gc" (set dump_gc)
, Option "dump-gc-stats" (set dump_gc_stats)
, Option "debug-cc" (set debug_cc)
, Option "dump-cc" (set dump_cc)
, Option "dump-ld" (set dump_ld)
, Option "dump-asm" (set dump_asm)
, Option "dump-exec" (set dump_exec)
, Option "dump-sched" (set dump_sched)
]
class DebugFlag a where
def :: a
instance DebugFlag Bool where
{-# INLINE def #-}
def = False
instance DebugFlag (Maybe a) where
{-# INLINE def #-}
def = Nothing
accInit :: IO ()
#ifdef ACCELERATE_DEBUG
accInit = _flags `seq` return ()
#else
accInit = getUpdateArgs >> return ()
#endif
#ifdef ACCELERATE_DEBUG
initialiseFlags :: IO Flags
initialiseFlags = do
argv <- getUpdateArgs
env <- maybe [] words `fmap` lookupEnv "ACCELERATE_FLAGS"
return $ parse (env ++ argv)
where
defaults :: Flags
defaults = Flags def def def def def def def def def def def def def def def def def def def def def def def def
parse :: [String] -> Flags
parse = foldl parse1 defaults
parse1 :: Flags -> String -> Flags
parse1 opts this =
case filter (\(Option flag _) -> prefix `isPrefixOf` flag) allFlags of
[Option _ f] -> apply f
[] -> trace unknown opts
alts -> case find (\(Option flag _) -> flag == prefix) alts of
Just (Option _ f) -> apply f
Nothing -> trace (ambiguous alts) opts
where
apply :: OptKind (Flags -> Flags) -> Flags
apply (NoArg f) = f opts
apply (IntArg f) = f (read suffix) opts
(prefix,rest) = break (== '=') this
suffix = if null rest then [] else tail rest
unknown = render $ text "Unknown option:" <+> quotes (text this)
ambiguous alts = render $
vcat [ text "Ambiguous option:" <+> quotes (text this)
, text ""
, text "Did you mean one of these?"
, nest 4 $ vcat (map (\(Option s _) -> text s) alts)
]
#endif
getUpdateArgs :: IO [String]
getUpdateArgs = do
argv <- getArgs
let (before, r1) = span (/= "+ACC") argv
(flags, r2) = span (/= "-ACC") $ dropWhile (== "+ACC") r1
after = dropWhile (== "-ACC") r2
#ifdef ACCELERATE_DEBUG
prog <- getProgName
setProgArgv (prog : before ++ after)
#else
M.unless (null flags)
$ error "Data.Array.Accelerate: Debugging options are disabled. Reinstall package 'accelerate' with '-fdebug' to enable them."
#endif
return flags
#ifdef ACCELERATE_DEBUG
{-# NOINLINE _flags #-}
_flags :: IORef Flags
_flags = unsafePerformIO $ newIORef =<< initialiseFlags
#endif
{-# INLINE queryFlag #-}
queryFlag :: DebugFlag a => (Flags :-> a) -> IO a
#ifdef ACCELERATE_DEBUG
queryFlag f = get f `fmap` readIORef _flags
#else
queryFlag _ = return def
#endif
type Mode = Flags :-> Bool
setFlag, clearFlag :: Mode -> IO ()
setFlag f = setFlags [f]
clearFlag f = clearFlags [f]
setFlag' :: (Flags :-> a) -> a -> IO ()
#ifdef ACCELERATE_DEBUG
setFlag' f v = modifyIORef _flags (set f v)
#else
setFlag' _ _ = return ()
#endif
setFlags, clearFlags :: [Mode] -> IO ()
#ifdef ACCELERATE_DEBUG
setFlags f = modifyIORef _flags (\opt -> foldr (flip set True) opt f)
clearFlags f = modifyIORef _flags (\opt -> foldr (flip set False) opt f)
#else
setFlags _ = return ()
clearFlags _ = return ()
#endif
{-# INLINEABLE when #-}
when :: MonadIO m => Mode -> m () -> m ()
when f s = do
yes <- liftIO $ queryFlag f
M.when yes s
{-# INLINEABLE unless #-}
unless :: MonadIO m => Mode -> m () -> m ()
unless f s = do
yes <- liftIO $ queryFlag f
M.unless yes s
#ifdef ACCELERATE_DEBUG
setProgArgv :: [String] -> IO ()
setProgArgv argv = do
enc <- getFileSystemEncoding
vs <- mapM (GHC.newCString enc) argv >>= newArray0 nullPtr
c_setProgArgv (genericLength argv) vs
foreign import ccall unsafe "setProgArgv"
c_setProgArgv :: CInt -> Ptr CString -> IO ()
#endif