packages feed

fibon-0.2.0: tools/fibon-run/Fibon/Run/BenchmarkBundle.hs

module Fibon.Run.BenchmarkBundle (
    BenchmarkBundle(..)
  , mkBundle
  , bundleName
  , pathToBench
  , pathToCabalWorkDir
  , pathToExeBuildDir
  , pathToExe
  , pathToSizeInputFiles
  , pathToSizeOutputFiles
  , pathToAllInputFiles
  , pathToAllOutputFiles
  , pathToSizeDataFiles
  , pathToStdoutFile
  , pathToStderrFile
  , pathToExeRunDir
  , pathToStdinFile
  , prettyRunCommand
  , bundleProcessSpec
)
where

import Data.Char
import Data.List
import Fibon.Benchmarks
import Fibon.BenchmarkInstance
import Fibon.Timeout
import Fibon.Run.Config
import System.FilePath
import System.IO
import System.Process
import System.Info


data BenchmarkBundle = BenchmarkBundle {
      benchmark     :: FibonBenchmark
    , workDir       :: FilePath
    , benchDir      :: FilePath
    , unique        :: String
    , iters         :: Int
    , tuneSetting   :: TuneSetting
    , inputSize     :: InputSize
    , fullFlags     :: FlagConfig
    , benchDetails  :: BenchmarkInstance
    , timeout       :: Maybe Int
    , extraStats    :: Maybe FilePath
  } deriving (Show)

mkBundle :: RunConfig
         -> FibonBenchmark
         -> FilePath -- ^ working directory
         -> FilePath -- ^ benchmarks directory
         -> String   -- ^ unique id
         -> InputSize
         -> TuneSetting
         -> [(String, String)] -- ^ Environment variables
         -> BenchmarkBundle
mkBundle rc bm wd bmsDir uniq size tune progEnv =
  BenchmarkBundle {
      benchmark     = bm
    , workDir       = wd
    , benchDir      = bmsDir
    , unique        = uniq
    , iters         = (iterations rc)
    , tuneSetting   = tune
    , inputSize     = size
    , fullFlags     = flags configuration
    , benchDetails  = benchInstance bm size
    , timeout       = timeoutToMicroSeconds (limit configuration)
    , extraStats    = (extraStatsFile configuration)
  }
  where
    configuration = mkConfig rc bm size tune progEnv

bundleName :: BenchmarkBundle -> String
bundleName bb = concat $ intersperse "-"
  [(show $ benchmark bb), (show $ inputSize bb), (show $ tuneSetting bb)]

pathToBench :: BenchmarkBundle -> FilePath
pathToBench bb = (benchDir bb) </> ((benchPath . benchmark) bb)

pathToCabalWorkDir :: BenchmarkBundle -> FilePath
pathToCabalWorkDir bb = (workDir bb) </> (unique bb) </> (bundleName bb)

pathToExeBuildDir :: BenchmarkBundle -> FilePath
pathToExeBuildDir bb = 
  (pathToCabalWorkDir bb) </> "build" </> (exeName.benchDetails $ bb)

pathToExeRunDir :: BenchmarkBundle -> FilePath
pathToExeRunDir = pathToExeBuildDir

pathToExe :: BenchmarkBundle -> FilePath
pathToExe bb = (pathToExeBuildDir bb) </> (exeName.benchDetails $ bb)++ext
  where ext = if System.Info.os == "mingw32" then ".exe" else ""

pathToSizeInputFiles :: BenchmarkBundle -> FilePath
pathToSizeInputFiles = pathToSizeDataFiles "input"

pathToSizeOutputFiles :: BenchmarkBundle -> FilePath
pathToSizeOutputFiles = pathToSizeDataFiles "output"

pathToAllInputFiles :: BenchmarkBundle -> FilePath
pathToAllInputFiles = pathToAllDataFiles "input"

pathToAllOutputFiles :: BenchmarkBundle -> FilePath
pathToAllOutputFiles = pathToAllDataFiles "output"

pathToSizeDataFiles :: FilePath -> BenchmarkBundle -> FilePath
pathToSizeDataFiles subDir bb = pathToDataFiles size subDir bb
  where
  size = (map toLower $ show $ inputSize bb)

pathToAllDataFiles :: FilePath -> BenchmarkBundle -> FilePath
pathToAllDataFiles = pathToDataFiles "all"

pathToDataFiles :: FilePath -> FilePath -> BenchmarkBundle -> FilePath
pathToDataFiles size subDir bb =
  (pathToBench bb) </> "Fibon" </> "data" </> size </> subDir

pathToStdoutFile :: BenchmarkBundle -> FilePath
pathToStdoutFile = pathToStdioFile "stdout"

pathToStderrFile :: BenchmarkBundle -> FilePath
pathToStderrFile = pathToStdioFile "stderr"

pathToStdioFile :: String -> BenchmarkBundle -> FilePath
pathToStdioFile name bb =
  (pathToExeRunDir bb) </> (exeName.benchDetails $ bb) ++"."++name++".actual"

pathToStdinFile :: BenchmarkBundle -> FilePath -> FilePath
pathToStdinFile bb inFile = (pathToExeRunDir bb) </> inFile

benchExeAndArgs :: BenchmarkBundle -> (String, [String])
benchExeAndArgs bb = (exe, fullArgs)
  where
  exe      = pathToExe bb
  fullArgs = (runFlags . fullFlags) bb

prettyRunCommand :: BenchmarkBundle -> String
prettyRunCommand bb = cmd
  where
  cmd        = exe  ++ (concatMap (' ':) fullArgs)
  fullArgs   = args ++ stdioArgs
  (exe,args) = benchExeAndArgs bb
  stdioArgs  = [stdIn, stdOut, stdErr]
  stdIn      = case (stdinInput.benchDetails $ bb) of
                    Nothing -> ""
                    Just f  -> " < " ++ pathToStdinFile bb f
  stdOut     = "  > " ++ (pathToStdoutFile bb)
  stdErr     = " 2> " ++ (pathToStderrFile bb)

bundleProcessSpec :: BenchmarkBundle -> IO CreateProcess
bundleProcessSpec bb = do
  stdIn <-
    case  (stdinInput.benchDetails $ bb) of
      Nothing -> do return CreatePipe
      Just f  -> do h <- openFile (pathToStdinFile bb f) ReadMode
                    return (UseHandle h)
  out <- openFile (pathToStdoutFile bb) WriteMode
  err <- openFile (pathToStderrFile bb) WriteMode
  return $ (proc exe args) {
        cwd     = Just (pathToExeRunDir bb)
      , std_in  = stdIn
      , std_out = UseHandle out
      , std_err = UseHandle err
  }
  where
  (exe, args) = benchExeAndArgs bb