From e72a6d46e3daaf12b375aaaa5c8c91561dccac75 Mon Sep 17 00:00:00 2001 From: "Trevor L. McDonell" Date: Tue, 5 Mar 2013 19:16:57 +1100 Subject: [PATCH] display available and selected backend at demo startup ping AccelerateHS/accelerate#82 --- examples/crystal/Config.hs | 74 ++++++++++++++++++------- examples/crystal/Main.hs | 6 +- examples/fluid/src/Config.hs | 77 ++++++++++++++++++-------- examples/fluid/src/Main.hs | 6 +- examples/mandelbrot/Config.hs | 100 ++++++++++++++++++++++++---------- examples/mandelbrot/Main.hs | 2 +- examples/n-body/Config.hs | 62 +++++++++++++++------ examples/quickcheck/Config.hs | 6 +- examples/quickcheck/Main.hs | 2 +- examples/smoothlife/Config.hs | 52 +++++++++++++----- 10 files changed, 272 insertions(+), 115 deletions(-) diff --git a/examples/crystal/Config.hs b/examples/crystal/Config.hs index 2f0f67e..b680a50 100644 --- a/examples/crystal/Config.hs +++ b/examples/crystal/Config.hs @@ -3,13 +3,18 @@ module Config ( Options, optBackend, optSize, optZoom, optScale, optDegree, optBench, - processArgs, run + parseArgs, run ) where +import Data.Char +import Data.List import Data.Label import System.Exit import System.Console.GetOpt +import qualified Criterion.Main as Criterion +import qualified Criterion.Config as Criterion + import Data.Array.Accelerate ( Arrays, Acc ) import qualified Data.Array.Accelerate.Interpreter as Interp #ifdef ACCELERATE_CUDA_BACKEND @@ -59,14 +64,17 @@ run opts f = case _optBackend opts of CUDA -> CUDA.run1 f #endif - -options :: [OptDescr (Options -> Options)] -options = +backends :: [OptDescr (Options -> Options)] +backends = [ Option [] ["interpreter"] (NoArg (set optBackend Interpreter)) "reference implementation (sequential)" #ifdef ACCELERATE_CUDA_BACKEND , Option [] ["cuda"] (NoArg (set optBackend CUDA)) "implementation for NVIDIA GPUs (parallel)" #endif - , Option [] ["size"] (ReqArg (set optSize . read) "INT") "visualisation size (200)" + ] + +options :: [OptDescr (Options -> Options)] +options = backends ++ + [ Option [] ["size"] (ReqArg (set optSize . read) "INT") "visualisation size (200)" , Option [] ["zoom"] (ReqArg (set optZoom . read) "INT") "pixel replication factor (3)" , Option [] ["scale"] (ReqArg (set optScale . read) "FLOAT") "feature size of visualisation (30)" , Option [] ["degree"] (ReqArg (set optDegree . read) "INT") "number of waves to sum for each point (5)" @@ -75,19 +83,47 @@ options = ] -processArgs :: [String] -> IO (Options, [String]) -processArgs argv = - case getOpt' Permute options argv of - (o,_,n,[]) -> case foldl (flip id) defaultOptions o of - opts | False <- get optHelp opts -> return (opts, n) - opts | True <- get optBench opts -> return (opts, "--help":n) - _ -> putStrLn (helpMsg []) >> exitSuccess - (_,_,_,err) -> error (helpMsg err) +basicHeader :: String +basicHeader = unlines + [ "accelerate-crystal (c) [2011..2013] The Accelerate Team" + , "" + , "Usage: accelerate-crystal [OPTIONS]" + ] + +fancyHeader :: Options -> String +fancyHeader opts = unlines (header : table) where - helpMsg err = concat err ++ usageInfo header options - header = unlines - [ "accelerate-crystal (c) [2011..2012] The Accelerate Team" - , "" - , "Usage: accelerate-crystal [OPTIONS]" - ] + active this = if this == map toLower (show $ get optBackend opts) then "*" else "" + (ss,bs,ds) = unzip3 $ map (\(b,d) -> (active b, b, d)) $ concatMap extract backends + table = zipWith3 paste (sameLen ss) (sameLen bs) ds + paste x y z = " " ++ x ++ " " ++ y ++ " " ++ z + sameLen xs = flushLeft ((maximum . map length) xs) xs + flushLeft n xs = [ take n (x ++ repeat ' ') | x <- xs ] + -- + extract (Option _ los _ descr) = + let losFmt = intercalate ", " los + in case lines descr of + [] -> [(losFmt, "")] + (x:xs) -> (losFmt, x) : [ ("",x') | x' <- xs ] + -- + header = intercalate "\n" [ basicHeader, "Available backends:" ] + + +parseArgs :: [String] -> IO (Options, Criterion.Config, [String]) +parseArgs argv = + let + helpMsg err = concat err + ++ usageInfo basicHeader options + ++ usageInfo "\nGeneric criterion options:" Criterion.defaultOptions + + in case getOpt' Permute options argv of + (o,_,n,[]) -> do + + -- pass unrecognised options to criterion + (cconf, rest) <- Criterion.parseArgs Criterion.defaultConfig Criterion.defaultOptions n + case foldr id defaultOptions o of + opts | False <- get optHelp opts -> putStrLn (fancyHeader opts) >> return (opts, cconf, rest) + _ -> putStrLn (helpMsg []) >> exitSuccess + + (_,_,_,err) -> error (helpMsg err) diff --git a/examples/crystal/Main.hs b/examples/crystal/Main.hs index 83e0178..c3d70e7 100644 --- a/examples/crystal/Main.hs +++ b/examples/crystal/Main.hs @@ -15,7 +15,7 @@ import Data.Label import Foreign.Ptr import Control.Monad import Control.Exception -import Criterion.Main ( defaultMain, bench, whnf ) +import Criterion.Main ( defaultMainWith, bench, whnf ) import Foreign.ForeignPtr import System.Environment import System.IO.Unsafe @@ -167,7 +167,7 @@ frame render size zoom time = G.scale zoom' zoom' pic -- Main ----------------------------------------------------------------------- main :: IO () main - = do (config, nops) <- processArgs =<< getArgs + = do (config, crit, nops) <- parseArgs =<< getArgs let size = get optSize config zoom = get optZoom config scale = get optScale config @@ -178,7 +178,7 @@ main void . evaluate $ render (A.fromList Z [0]) if get optBench config - then withArgs nops $ defaultMain + then withArgs nops $ defaultMainWith crit (return ()) [ bench "crystal" $ whnf (force . render) (A.fromList Z [1.0]) ] #ifndef ACCELERATE_ENABLE_GUI diff --git a/examples/fluid/src/Config.hs b/examples/fluid/src/Config.hs index af7f167..7cd4411 100644 --- a/examples/fluid/src/Config.hs +++ b/examples/fluid/src/Config.hs @@ -12,18 +12,22 @@ module Config ( simulationWidth, simulationHeight, initialDensity, initialVelocity, displayScale, displayFramerate, optBench, - processArgs, run, run1 + parseArgs, run, run1 ) where import Type +import Data.Char +import Data.List import Data.IORef import Data.Label import Control.Monad import System.Console.GetOpt import System.Exit import Prelude as P +import qualified Criterion.Main as Criterion +import qualified Criterion.Config as Criterion import Data.Array.Accelerate as A import Data.Array.Accelerate.IO as A @@ -106,8 +110,8 @@ run1 opts f = case _optBackend opts of #endif -processArgs :: [String] -> IO (Options, [String]) -processArgs argv = do +parseArgs :: [String] -> IO (Options, Criterion.Config, [String]) +parseArgs argv = do -- Some additional options, which we will use to determine how to set up the -- initial conditions of the simulator. @@ -122,16 +126,18 @@ processArgs argv = do -- Parse the command-line options -- - let options :: [OptDescr (Options -> IO Options)] - options = - -- Backend execution setup + let backends :: [OptDescr (Options -> IO Options)] + backends = [ Option [] ["interpreter"] (NoArg (return . set optBackend Interpreter)) "reference implementation (sequential)" #ifdef ACCELERATE_CUDA_BACKEND , Option [] ["cuda"] (NoArg (return . set optBackend CUDA)) "implementation for NVIDIA GPUs (parallel)" #endif + ] + options :: [OptDescr (Options -> IO Options)] + options = backends ++ -- Simulation options - , Option [] ["viscosity"] (ReqArg (parse viscosity) "FLOAT") (describe viscosity "viscosity for velocity damping") + [ Option [] ["viscosity"] (ReqArg (parse viscosity) "FLOAT") (describe viscosity "viscosity for velocity damping") , Option [] ["diffusion"] (ReqArg (parse diffusion) "FLOAT") (describe diffusion "diffusion rate for mass dispersion") , Option [] ["delta"] (ReqArg (parse timestep) "FLOAT") (describe timestep "simulation time between each frame") , Option [] ["density"] (ReqArg (parse inputDensity) "FLOAT") (describe inputDensity "magnitude of user input density") @@ -154,32 +160,55 @@ processArgs argv = do parse f x = return . set f (read x) describe f msg = msg ++ " (" ++ show (get f defaultOptions) ++ ")" - helpMsg errs = concat errs ++ usageInfo header options ++ footer - header = unlines - [ "accelerate-fluid (c) 2011 Trevor L. McDonell" + + basicHeader = unlines + [ "accelerate-fluid (c) [2011..2013] The Accelerate Team" , "" , "Usage: accelerate-fluid [OPTIONS]" ] - footer = unlines + basicFooter = unlines [ "" , "Runtime usage:" - , "" - , " click add density sources to the image" - , " shift-click add velocity sources" - , " r reset the image" - , " d toggle display of density field" - , " v toggle display of velocity field lines" + , " click add density sources to the image" + , " shift-click add velocity sources" + , " r reset the image" + , " d toggle display of density field" + , " v toggle display of velocity field lines" ] - (opts, rest) + helpMsg errs = concat errs + ++ usageInfo basicHeader options + ++ usageInfo "\nGeneric criterion options:" Criterion.defaultOptions + + fancyHeader :: Options -> String + fancyHeader opts = unlines (header : table ++ lines basicFooter) + where + active this = if this == P.map toLower (show $ get optBackend opts) then "*" else "" + (ss,bs,ds) = P.unzip3 $ P.map (\(b,d) -> (active b, b, d)) $ concatMap extract backends + table = P.zipWith3 paste (sameLen ss) (sameLen bs) ds + paste x y z = " " ++ x ++ " " ++ y ++ " " ++ z + sameLen xs = flushLeft ((P.maximum . P.map P.length) xs) xs + flushLeft n xs = [ P.take n (x ++ repeat ' ') | x <- xs ] + -- + extract (Option _ los _ descr) = + let losFmt = intercalate ", " los + in case lines descr of + [] -> [(losFmt, "")] + (x:xs) -> (losFmt, x) : [ ("",x') | x' <- xs ] + -- + header = intercalate "\n" [ basicHeader, "Available backends:" ] + + (opts, crit, rest) <- case getOpt' RequireOrder options argv of (actions,_,n,[]) -> do - o <- foldl (>>=) (return defaultOptions) actions - case get optHelp o of - False -> return (o,n) - _ | True <- get optBench o -> return (o,"--help":n) - _ -> putStrLn (helpMsg []) >> exitSuccess + opts <- foldl (>>=) (return defaultOptions) actions + (cconf, rest) <- Criterion.parseArgs Criterion.defaultConfig Criterion.defaultOptions n + + case get optHelp opts of + False -> putStrLn (fancyHeader opts) >> return (opts, cconf, rest) + _ -> putStrLn (helpMsg []) >> exitSuccess + (_,_,_,errors) -> error (helpMsg errors) -- Extract option values, and set up the initial conditions @@ -278,5 +307,5 @@ processArgs argv = do density <- mkInitialDensity velocity <- mkInitialVelocity - return ( opts { _initialDensity = density, _initialVelocity = velocity }, rest ) + return ( opts { _initialDensity = density, _initialVelocity = velocity }, crit, rest ) diff --git a/examples/fluid/src/Main.hs b/examples/fluid/src/Main.hs index a5d7cbb..e5b08ab 100644 --- a/examples/fluid/src/Main.hs +++ b/examples/fluid/src/Main.hs @@ -12,7 +12,7 @@ import World import Fluid import Event import Data.Label -import Criterion.Main +import Criterion.Main ( defaultMainWith, bench, whnf ) import Control.Exception import System.Environment import Graphics.Gloss.Interface.IO.Game @@ -23,7 +23,7 @@ import Data.Array.Accelerate as A main :: IO () main = do - (opt,noms) <- processArgs =<< getArgs + (opt,crit,noms) <- parseArgs =<< getArgs let -- configuration parameters -- width = get simulationWidth opt * get displayScale opt @@ -71,7 +71,7 @@ main = do if get optBench opt #endif -- benchmark - then withArgs noms $ defaultMain + then withArgs noms $ defaultMainWith crit (return ()) [ bench "fluid" $ whnf simulate initialWorld ] -- simulate diff --git a/examples/mandelbrot/Config.hs b/examples/mandelbrot/Config.hs index 83a9d21..e47f516 100644 --- a/examples/mandelbrot/Config.hs +++ b/examples/mandelbrot/Config.hs @@ -5,15 +5,18 @@ module Config ( Options, optBackend, optSize, optLimit, optFramerate, optBench, - processArgs, run, run1 + parseArgs, run, run1 ) where -import qualified Criterion.Main as Crit -import qualified Criterion.Config as Crit +import Data.Char +import Data.List import Data.Label import System.Exit -import System.Console.GetOpt (OptDescr(..), ArgDescr(..), ArgOrder(Permute), getOpt', usageInfo) +import System.Console.GetOpt ( OptDescr(..), ArgDescr(..), ArgOrder(Permute), getOpt', usageInfo ) +import qualified Criterion.Main as Criterion +import qualified Criterion.Config as Criterion + import Data.Array.Accelerate ( Arrays, Acc ) import qualified Data.Array.Accelerate.Interpreter as Interp #ifdef ACCELERATE_CUDA_BACKEND @@ -69,13 +72,17 @@ run1 opts f = case _optBackend opts of #endif -options :: [OptDescr (Options -> Options)] -options = +backends :: [OptDescr (Options -> Options)] +backends = [ Option [] ["interpreter"] (NoArg (set optBackend Interpreter)) "reference implementation (sequential)" #ifdef ACCELERATE_CUDA_BACKEND , Option [] ["cuda"] (NoArg (set optBackend CUDA)) "implementation for NVIDIA GPUs (parallel)" #endif - , Option [] ["size"] (ReqArg (set optSize . read) "INT") "visualisation size (512)" + ] + +options :: [OptDescr (Options -> Options)] +options = backends ++ + [ Option [] ["size"] (ReqArg (set optSize . read) "INT") "visualisation size (512)" , Option [] ["limit"] (ReqArg (set optLimit . read) "INT") "iteration limit for escape (255)" , Option [] ["framerate"] (ReqArg (set optFramerate . read) "INT")"visualisation framerate (10)" , Option [] ["static"] (NoArg (set optFramerate 0)) "do not animate the image" @@ -84,26 +91,61 @@ options = ] --- | Two levels of argument parsing -- ours and criterions. -processArgs :: [String] -> IO (Options, Crit.Config, [String]) -processArgs argv = - case getOpt' Permute options argv of - (o,_,n,[]) -> do -- Pass unrecognized options onward: - (critConf,rst) <- Crit.parseArgs Crit.defaultConfig Crit.defaultOptions n - case foldl (flip id) defaultOptions o of - opts | False <- get optHelp opts -> return (opts, critConf, rst) - opts | True <- get optBench opts -> return (opts, critConf, "--help":rst) - _ -> putStrLn (helpMsg []) >> exitSuccess - - (_,_,_,err) -> error (helpMsg err) +basicHeader :: String +basicHeader = unlines + [ "accelerate-mandelbrot (c) [2011..2013] The Accelerate Team" + , "" + , "Usage: accelerate-mandelbrot [OPTIONS]" + ] + +basicFooter :: String +basicFooter = unlines + [ "" + , "Runtime usage:" + , " arrows translate display" + , " z ; zoom in" + , " x q zoom out" + , " f single precision calculations" + , " d double precision calculations (if supported)" + ] + +fancyHeader :: Options -> String +fancyHeader opts = unlines (header : table ++ footer) where - helpMsg err = concat err ++ usageInfo header options ++ - usageInfo "\nGeneric criterion options:" Crit.defaultOptions - header = unlines - [ "accelerate-mandelbrot (c) [2011..2012] The Accelerate Team" - , "" - , "Usage: accelerate-mandelbrot [OPTIONS]" - , "" - , "Translate the display using the arrow keys, zoom with 'z' and 'x'." - , "Switch between calculation using float or double with 'f' and 'd'." - ] + active this = if this == map toLower (show $ get optBackend opts) then "*" else "" + (ss,bs,ds) = unzip3 $ map (\(b,d) -> (active b, b, d)) $ concatMap extract backends + table = zipWith3 paste (sameLen ss) (sameLen bs) ds + paste x y z = " " ++ x ++ " " ++ y ++ " " ++ z + sameLen xs = flushLeft ((maximum . map length) xs) xs + flushLeft n xs = [ take n (x ++ repeat ' ') | x <- xs ] + -- + extract (Option _ los _ descr) = + let losFmt = intercalate ", " los + in case lines descr of + [] -> [(losFmt, "")] + (x:xs) -> (losFmt, x) : [ ("",x') | x' <- xs ] + -- + header = intercalate "\n" [ basicHeader, "Available backends:" ] + footer = lines basicFooter + + +-- | Two levels of argument parsing -- ours and criterions. +-- +parseArgs :: [String] -> IO (Options, Criterion.Config, [String]) +parseArgs argv = + let + helpMsg err = concat err + ++ usageInfo basicHeader options + ++ usageInfo "\nGeneric criterion options:" Criterion.defaultOptions + + in case getOpt' Permute options argv of + (o,_,n,[]) -> do + + -- pass unrecognised options to criterion + (cconf, rest) <- Criterion.parseArgs Criterion.defaultConfig Criterion.defaultOptions n + case foldr id defaultOptions o of + opts | False <- get optHelp opts -> putStrLn (fancyHeader opts) >> return (opts, cconf, rest) + _ -> putStrLn (helpMsg []) >> exitSuccess + + (_,_,_,err) -> error (helpMsg err) + diff --git a/examples/mandelbrot/Main.hs b/examples/mandelbrot/Main.hs index 29d44c3..9fe10bf 100644 --- a/examples/mandelbrot/Main.hs +++ b/examples/mandelbrot/Main.hs @@ -42,7 +42,7 @@ makePicture world = pic main :: IO () main = do - (config, critConf, nops) <- processArgs =<< getArgs + (config, critConf, nops) <- parseArgs =<< getArgs let world = initialWorld config view fps = get optFramerate config diff --git a/examples/n-body/Config.hs b/examples/n-body/Config.hs index 1aad71b..fc14c20 100644 --- a/examples/n-body/Config.hs +++ b/examples/n-body/Config.hs @@ -127,10 +127,10 @@ run1 config f = #endif --- | The set of available command-line options +-- | The set of backends available to execute the program -- -defaultOptions :: [OptDescr (Config -> Config)] -defaultOptions = +backends :: [OptDescr (Config -> Config)] +backends = [ Option [] ["interpreter"] (NoArg (set configBackend Interpreter)) "reference implementation (sequential)" @@ -140,8 +140,14 @@ defaultOptions = (NoArg (set configBackend CUDA)) "implementation for NVIDIA GPUs (parallel)" #endif + ] + - , Option ['s'] ["solver"] +-- | The set of available command-line options +-- +defaultOptions :: [OptDescr (Config -> Config)] +defaultOptions = backends ++ + [ Option ['s'] ["solver"] (ReqArg (set configSolver . solver) "ALGORITHM") ("solver to use, one of: " ++ intercalate ", " (map show [minBound .. maxBound :: Solver])) @@ -211,18 +217,39 @@ defaultOptions = -- | Process the command line options -- + +basicHeader :: String +basicHeader = unlines + [ "accelerate-nbody (c) [2012..2013] The Accelerate Team" + , "" + , "Usage: accelerate-nbody [OPTIONS]" + ] + +fancyHeader :: Config -> String +fancyHeader opts = unlines (header : table) + where + active this = if this == map toLower (show $ get configBackend opts) then "*" else "" + (ss,bs,ds) = unzip3 $ map (\(b,d) -> (active b, b, d)) $ concatMap extract backends + table = zipWith3 paste (sameLen ss) (sameLen bs) ds + paste x y z = " " ++ x ++ " " ++ y ++ " " ++ z + sameLen xs = flushLeft ((maximum . map length) xs) xs + flushLeft n xs = [ take n (x ++ repeat ' ') | x <- xs ] + -- + extract (Option _ los _ descr) = + let losFmt = intercalate ", " los + in case lines descr of + [] -> [(losFmt, "")] + (x:xs) -> (losFmt, x) : [ ("",x') | x' <- xs ] + -- + header = intercalate "\n" [ basicHeader, "Available backends:" ] + + parseArgs :: [String] -> IO (Config, Criterion.Config, [String]) -parseArgs argv - = let - helpMsg err = concat err - ++ usageInfo header defaultOptions - ++ usageInfo "\nGeneric criterion options:" Criterion.defaultOptions - - header = unlines - [ "accelerate-nbody (c) [2012] The Accelerate Team" - , "" - , "Usage: accelerate-nbody [OPTIONS]" - ] +parseArgs argv = + let + helpMsg err = concat err + ++ usageInfo basicHeader defaultOptions + ++ usageInfo "\nGeneric criterion options:" Criterion.defaultOptions in case getOpt' Permute defaultOptions argv of (o,_,n,[]) -> do @@ -230,9 +257,8 @@ parseArgs argv -- pass unrecognised options to criterion (cconf, rest) <- Criterion.parseArgs Criterion.defaultConfig Criterion.defaultOptions n case foldr id defaultConfig o of - conf | False <- get configHelp conf -> return (conf, cconf, rest) - conf | True <- get configBenchmark conf -> return (conf, cconf, "--help":rest) - _ -> putStrLn (helpMsg []) >> exitSuccess + conf | False <- get configHelp conf -> putStrLn (fancyHeader conf) >> return (conf, cconf, rest) + _ -> putStrLn (helpMsg []) >> exitSuccess (_,_,_,err) -> error (helpMsg err) diff --git a/examples/quickcheck/Config.hs b/examples/quickcheck/Config.hs index b695080..b619a07 100644 --- a/examples/quickcheck/Config.hs +++ b/examples/quickcheck/Config.hs @@ -6,7 +6,7 @@ module Config ( -- options & test configuration Options, - processArgs, + parseArgs, optBackend, double, float, int64, int32, int16, int8, -- running tests @@ -134,8 +134,8 @@ configureBackend opts = case _optBackend opts of #endif -processArgs :: [String] -> IO (Options, RunnerOptions) -processArgs argv = do +parseArgs :: [String] -> IO (Options, RunnerOptions) +parseArgs argv = do args <- interpretArgs argv (options, runner) <- case args of Left msg -> error msg diff --git a/examples/quickcheck/Main.hs b/examples/quickcheck/Main.hs index b1e3acf..d1cf60e 100644 --- a/examples/quickcheck/Main.hs +++ b/examples/quickcheck/Main.hs @@ -15,7 +15,7 @@ main :: IO () main = do -- process command line args, and print a brief usage message -- - (options, runner) <- processArgs =<< getArgs + (options, runner) <- parseArgs =<< getArgs -- the default execution order uses some knowledge of what functionality is -- required for each operation in the CUDA backend. diff --git a/examples/smoothlife/Config.hs b/examples/smoothlife/Config.hs index 09f76cf..e9431e5 100644 --- a/examples/smoothlife/Config.hs +++ b/examples/smoothlife/Config.hs @@ -7,6 +7,8 @@ module Config import Prelude as P hiding ((.), id, fst, snd) import qualified Prelude as P +import Data.Char +import Data.List import Data.Label import System.Exit import Control.Category @@ -106,8 +108,8 @@ run1 config f = -- | The set of available command-line options -- -defaultOptions :: [OptDescr (Config -> Config)] -defaultOptions = +backends :: [OptDescr (Config -> Config)] +backends = [ Option [] ["interpreter"] (NoArg (set configBackend Interpreter)) "reference implementation (sequential)" @@ -117,8 +119,12 @@ defaultOptions = (NoArg (set configBackend CUDA)) "implementation for NVIDIA GPUs (parallel)" #endif + ] + - , Option [] ["size"] +defaultOptions :: [OptDescr (Config -> Config)] +defaultOptions = backends ++ + [ Option [] ["size"] (ReqArg (set configWindowSize . read) "INT") (describe configWindowSize "visualisation size") @@ -189,29 +195,47 @@ defaultOptions = fst = lens P.fst (\a (_,b) -> (a,b)) snd = lens P.snd (\b (a,_) -> (a,b)) +basicHeader :: String +basicHeader = unlines + [ "accelerate-smoothlife (c) [2012..2013] The Accelerate Team" + , "" + , "Usage: accelerate-smoothlife [OPTIONS]" + ] + +fancyHeader :: Config -> String +fancyHeader opts = unlines (header : table) + where + active this = if this == map toLower (show $ get configBackend opts) then "*" else "" + (ss,bs,ds) = unzip3 $ map (\(b,d) -> (active b, b, d)) $ concatMap extract backends + table = zipWith3 paste (sameLen ss) (sameLen bs) ds + paste x y z = " " ++ x ++ " " ++ y ++ " " ++ z + sameLen xs = flushLeft ((maximum . map length) xs) xs + flushLeft n xs = [ take n (x ++ repeat ' ') | x <- xs ] + -- + extract (Option _ los _ descr) = + let losFmt = intercalate ", " los + in case lines descr of + [] -> [(losFmt, "")] + (x:xs) -> (losFmt, x) : [ ("",x') | x' <- xs ] + -- + header = intercalate "\n" [ basicHeader, "Available backends:" ] + parseArgs :: [String] -> IO (Config, Criterion.Config, [String]) parseArgs argv = let - helpMsg err = concat err - ++ usageInfo header defaultOptions + helpMsg err = concat err + ++ usageInfo basicHeader defaultOptions ++ usageInfo "\nGeneric criterion options:" Criterion.defaultOptions - header = unlines - [ "accelerate-smoothlife (c) [2012] The Accelerate Team" - , "" - , "Usage: accelerate-smoothlife [OPTIONS]" - ] - in case getOpt' Permute defaultOptions argv of (o,_,n,[]) -> do -- pass unrecognised options to criterion (cconf, rest) <- Criterion.parseArgs Criterion.defaultConfig Criterion.defaultOptions n case foldr id defaultConfig o of - conf | False <- get configHelp conf -> return (conf, cconf, rest) - conf | True <- get configBenchmark conf -> return (conf, cconf, "--help":rest) - _ -> putStrLn (helpMsg []) >> exitSuccess + conf | False <- get configHelp conf -> putStrLn (fancyHeader conf) >> return (conf, cconf, rest) + _ -> putStrLn (helpMsg []) >> exitSuccess (_,_,_,err) -> error (helpMsg err)