fibon-0.1.0: tools/fibon-run/Fibon/Run/Main.hs
module Main (
main
)
where
import Control.Monad
import Control.Exception
import Data.Char
import Data.List
import Data.Time.Clock
import Data.Time.Format
import Data.Time.LocalTime
import Fibon.Benchmarks
import Fibon.Result
import Fibon.Run.Actions
import Fibon.Run.CommandLine
import Fibon.Run.Config
import Fibon.Run.Manifest
import Fibon.Run.BenchmarkBundle
import qualified Fibon.Run.Log as Log
import System.Directory
import System.Exit
import System.Environment
import System.FilePath
import System.Locale
import Text.Printf
main :: IO ()
main = do
opts <- parseArgsOrDie
currentDir <- getCurrentDirectory
initConfig <- selectConfig (optConfig opts)
let runConfig = mergeConfigOpts initConfig opts
workingDir = currentDir </> "run"
benchRoot = currentDir </> "benchmarks/Fibon/Benchmarks"
logPath = currentDir </> "log"
action = optAction opts
uniq <- chooseUniqueName workingDir (configId runConfig)
(logFile, outFile, summaryFile) <- Log.setupLogger logPath logPath uniq
startTime <- timeStamp
Log.notice ("Starting Run at " ++ startTime)
Log.notice ("Logging output to " ++ logFile)
Log.notice ("Logging result to " ++ outFile)
Log.notice ("Logging summary to " ++ summaryFile)
mapM_ (runAndReport action) (makeBundles runConfig workingDir benchRoot uniq)
endTime <- timeStamp
Log.notice ("Finished Run at " ++ endTime)
Log.notice ("Logged output to " ++ logFile)
Log.notice ("Logged result to " ++ outFile)
Log.notice ("Logged summary to " ++ summaryFile)
parseArgsOrDie :: IO Opt
parseArgsOrDie = do
args <- getArgs
case parseCommandLine args of
Left msg -> putStrLn msg >> exitFailure
Right opts -> do
case optHelpMsg opts of
Just msg -> putStrLn msg >> exitSuccess
Nothing -> return opts
runAndReport :: Action -> BenchmarkBundle -> IO ()
runAndReport action bundle = do
Log.notice $ "Benchmark: "++ (bundleName bundle)++ " action="++(show action)
case action of
Sanity -> run sanityCheckBundle (const $ return ())
Build -> run buildBundle (\(BuildData time _size) -> do
Log.info (printf "Build completed in %0.2f seconds" time)
)
Run -> run runBundle (\fr@(FibonResult n _bd rd) -> do
-- Log.notice (show rr)
Log.result(show fr)
Log.summary(printf "%s %.4f" n ((meanTime . summary) rd))
)
return ()
where
run :: Show a => ActionRunner a -> (a -> IO ()) -> IO ()
run = runAndLogErrors bundle
runAndLogErrors :: Show a
=> BenchmarkBundle
-> ActionRunner a
-> (a -> IO ())
-> IO ()
runAndLogErrors bundle act cont = do
result <- try (act bundle)
-- result could fail from an IOError, or from a failure in the RunMonad
case result of
Left ioe -> logError (show (ioe :: IOError))
Right res ->
case res of
Left e -> logError (show e) >> return ()
Right r -> cont r
where
name = bundleName bundle
logError s = do Log.warn $ "Error running: " ++ name
Log.warn $ " =====> " ++ s
selectConfig :: ConfigId -> IO RunConfig
selectConfig configName =
case find ((== configName) . configId) configManifest of
Just c -> do return c
Nothing -> do
Log.error $ "Unknown config: " ++ configName
Log.error $ "Available configs:\n " ++ configNames
exitFailure
where configNames = concat (intersperse "\n " $ map configId configManifest)
makeBundles :: RunConfig
-> FilePath -- ^ Working directory
-> FilePath -- ^ Benchmark base path
-> String -- ^ Unique Id
-> [BenchmarkBundle]
makeBundles rc workingDir benchRoot uniq = map bundle bms
where
bundle (bm, size, tune) =
mkBundle rc bm workingDir benchRoot uniq size tune
bms = sort
[(bm, size, tune) |
size <- (sizeList rc),
bm <- expandBenchList $ runList rc,
tune <- (tuneList rc)]
expandBenchList :: [BenchmarkRunSelection] -> [FibonBenchmark]
expandBenchList = concatMap expand
where
expand (RunSingle b) = [b]
expand (RunGroup g) = filter (\b -> benchGroup b == g) allBenchmarks
chooseUniqueName :: FilePath -> String -> IO String
chooseUniqueName workingDir configName = do
wdExists <- doesDirectoryExist workingDir
unless wdExists (createDirectory workingDir)
dirs <- getDirectoryContents workingDir
let numbered = filter (\x -> length x > 0) $ map (takeWhile isDigit) dirs
case numbered of
[] -> return $ format (0 :: Int)
_ -> return $ (format . (+1) . read . last . sort) numbered
where
format :: Int -> String
format d = printf "%03d.%s" d configName
timeStamp :: IO String
timeStamp = do
tz <- getCurrentTimeZone
t <- getCurrentTime
return $ formatTime defaultTimeLocale "%F %T" (utcToLocalTime tz t)
mergeConfigOpts :: RunConfig -> Opt -> RunConfig
mergeConfigOpts rc opt = rc {
tuneList = maybe (tuneList rc) (:[]) (optTuneSetting opt)
, sizeList = maybe (sizeList rc) (:[]) (optSizeSetting opt)
, runList = maybe (runList rc) id (optBenchmarks opt)
, iterations = maybe (iterations rc) id (optIterations opt)
}
{-
dumpConfig :: RunConfig -> IO ()
dumpConfig rc = do
--putStrLn $ show $ map (uncurry benchInstance) $ sort bms
putStrLn $ show bms
mapM_ (dumpInstance rc) bms
where
bms = sort
[(bm, size, tune) |
size <- (sizeList rc),
bm <- expandBenchList $ runList rc,
tune <- (tuneList rc)]
dumpInstance :: RunConfig -> (FibonBenchmark, InputSize, TuneSetting)->IO ()
dumpInstance rc inst@(bm, size, tune) = do
putStrLn (take 68 $ repeat '-')
putStrLn (show inst)
putStrLn (take 68 $ repeat '-')
putStrLn (show $ mkFlagConfig rc bm size tune)
-}