rattle-0.2: benchmark/Benchmark/VsMake.hs
{-# LANGUAGE RecordWildCards #-}
module Benchmark.VsMake(
VsMake(..), vsMake, Args,
) where
import Benchmark.Args
import System.Directory.Extra
import Development.Rattle
import Development.Shake.Command
import System.Time.Extra
import Control.Exception
import System.FilePath
import Data.List
import Data.IORef
import Data.Maybe
import System.IO.Extra
import Control.Monad.Extra
data VsMake = VsMake
{repo :: String
,generate :: IO String
,generateVersion :: Int
,clean :: IO ()
,broken :: [String]
,make :: CmdArgument
,rattle :: CmdArgument
,master :: String
}
gitCheckout :: VsMake -> Int -> IO String
gitCheckout VsMake{..} i = do
Stdout x <- cmd "git reset --hard" ["origin/" ++ master ++ "~" ++ show i]
-- HEAD is now at 41fbba1 Warning
pure $ words x !! 4
generateName :: VsMake -> String -> IO FilePath
generateName VsMake{..} commit = do
tdir <- getTemporaryDirectory
pure $ tdir </> takeBaseName repo ++ "." ++ commit ++ "." ++ show generateVersion ++ ".txt"
timed :: IORef Seconds -> String -> Int -> Int -> IO () -> IO ()
timed ref msg j commit act = do
(t, _) <- duration act
appendFile "vsmake.log" $ intercalate "\t" [msg, show j, show commit, show t] ++ "\n"
putStrLn $ msg ++ " " ++ show j ++ " (" ++ show commit ++ ") = " ++ showDuration t
modifyIORef' ref (+ t)
vsMake :: VsMake -> Args -> IO ()
vsMake vs@VsMake{..} Args{..} = withTempDir $ \dir -> do
let counted = maybe id take count
let commitList = reverse [0..fromMaybe 10 commits]
let checkout i act = do
commit <- gitCheckout vs i
when (commit `notElem` broken) $
flip onException (putStrLn $ "AT COMMIT " ++ commit) $
act commit
let stderr = [EchoStderr False | no_stderr]
withCurrentDirectory dir $ do
-- don't pass a depth argument, or git changes the length of the shown commit hashes
-- which messes up caching and broken hashes
cmd_ "git clone" repo "."
-- generate all the Rattle files
when ("generate" `elemOrNull` step) $ do
putStrLn "GENERATING RATTLE SCRIPTS"
forM_ (counted commitList) $ \i -> do
putChar '.' >> hFlush stdout
checkout i $ \commit -> do
file <- generateName vs commit
unlessM (doesFileExist file) $ do
res <- generate
evaluate $ length res
writeFile file res
putStrLn ""
-- for different levels of parallelism
replicateM_ (fromMaybe 1 repeat_) $
forM_ (threads `orNull` [1..4]) $ \j -> do
makeTime <- newIORef 0
rattleTime <- newIORef 0
-- first build with make
when ("make" `elemOrNull` step) $ do
putStrLn "BUILDING WITH MAKE"
clean
forM_ (counted $ commitList ++ [0]) $ \i ->
checkout i $ \_ ->
timed makeTime "make" j i $ cmd_ make ["-j" ++ show j] (EchoStdout False) stderr
-- now with rattle
when ("rattle" `elemOrNull` step) $ do
putStrLn "BUILDING WITH RATTLE"
clean
whenM (doesDirectoryExist ".rattle") $
removeDirectoryRecursive ".rattle"
forM_ (counted $ commitList ++ [0]) $ \i ->
checkout i $ \commit -> do
file <- generateName vs commit
cmds <- lines <$> readFile' file
let opts = rattleOptions{rattleProcesses=j, rattleUI=Just RattleQuiet, rattleNamedDirs=[], rattleShare=False}
timed rattleTime "rattle" j i $ rattleRun opts $ forM_ cmds $ cmd rattle stderr
make <- readIORef makeTime
rattle <- readIORef rattleTime
putStrLn $ "TOTALS: make = " ++ showDuration make ++ ", rattle = " ++ showDuration rattle
copyFile (dir </> "vsmake.log") "vsmake.log"