content: {-# LANGUAGE ViewPatterns, TupleSections, RecordWildCards #-}
  import Data.Monoid
  import Data.Char
  import System.Directory
  import System.FilePath
  import Text.Printf
  import Control.Monad
  import Options.Applicative
  import Data.Map (Map,(!))
  import qualified Data.Map as Map
  
  -- HINT: lambdacube-compiler-test-suite --overall-time performance +RTS -tcurrent.log --machine-readable
  -- output: current.log overall-time.txt
  
  data Config
    = Config
    { resultPath :: String
    , output :: Maybe String
    }
  
  sample :: Parser Config
  sample = Config
    <$> pure "performance"
    <*> optional (strOption (long "output" <> short 'o' <> metavar "FILENAME" <> help "output file name"))
  
  main :: IO ()
  main = comparePerf =<< execParser opts
    where
      opts = info (helper <*> sample)
        ( fullDesc
       <> progDesc "compares LambdaCube 3D compiper performance"
       <> header ("LambdaCube 3D compiler performance report"))
  
  comparePerf :: Config -> IO ()
  comparePerf cfg@Config{..} = do
    -- read current result
    overallTime <- read <$> readFile "overall-time.txt" :: IO Double
    let toDouble = read :: String -> Double
        toInteger = read :: String -> Integer
    new <- Map.fromList . (:) ("overall_time",show overallTime) . read . unlines . tail . lines <$> readFile "current.log" :: IO (Map String String)
    let totalAlloc a = toInteger $ a ! "bytes allocated"
        peakAlloc a = toInteger $ a ! "peak_megabytes_allocated"
        totalAllocF a = toDouble $ a ! "bytes allocated"
        peakAllocF a = toDouble $ a ! "peak_megabytes_allocated"
        overallTime a = toDouble $ a ! "overall_time"
  
    putStrLn $ printf "%-20s time: % 6.3fs \tpeak mem: % 6d MBytes total alloc: %d bytes" "CURRENT" (overallTime new) (peakAlloc new) (totalAlloc new)
    -- read previous results
    perfs <- filter ((".perf" ==) . takeExtension) <$> getDirectoryContents "performance" >>= mapM (\n -> (n,) . read <$> readFile (resultPath </> n)) :: IO [(String,Map String String)]
    forM_ perfs $ \(name,old) -> do
      putStrLn $ printf "%-20s time: %+6.3f%% \tpeak mem: %+6.3f%% \ttotal alloc: %+6.3f%%"
        name (100*(overallTime new / overallTime old - 1)) (100*(peakAllocF new / peakAllocF old - 1)) (100*(totalAllocF new / totalAllocF old - 1))
    case output of
      Nothing -> return ()
      Just n -> writeFile (resultPath </> n ++ ".perf") $ show new
  