{-# LANGUAGE PatternGuards #-} module Main where import Criterion.Measurement ( secs ) import qualified Data.Map as M import Data.List ( nub, intersect, sort, groupBy ) import Text.Read import System.Environment ( getArgs ) import Control.Monad ( liftM, foldM ) import Text.Printf ( printf ) main = do (arg : args) <- getArgs if arg == "--diff" then doDiff args else doTable arg args doTable file args = do bs <- readLog file table <- foldM procArg (mkTable secs bs) args outputHTML table doDiff (file1 : file2 : args) = do bs1 <- readLog file1 bs2 <- readLog file2 let t = intersectTable ratio cmp (mkTable secs bs1) (mkTable secs bs2) table <- foldM procArg t args outputHTML table where ratio d = printf "%.3f" d cmp d1 d2 = d1 / d2 dropPrefix :: String -> String -> Maybe String dropPrefix "" cs = Just cs dropPrefix (p : ps) (c : cs) | p == c = dropPrefix ps cs | otherwise = Nothing procArg t arg | Just s <- dropPrefix "--type=" arg = return $ filterColumns (\cfg -> cfgDatatype cfg == s) t data Cfg = Cfg { cfgLibrary :: String , cfgSubsystem :: String , cfgDatatype :: String } deriving ( Eq, Ord ) data Library = Library String Int [Subsystem] data Subsystem = Subsystem String Int [String] on :: (b -> b -> c) -> (a -> b) -> a -> a -> c on f g x y = f (g x) (g y) eqOn :: Eq b => (a -> b) -> a -> a -> Bool eqOn = on (==) groupCfgs :: [Cfg] -> [Library] groupCfgs = map mk_library . groupBy (eqOn cfgLibrary) where mk_library cfgs@(c:_) = let subs = map mk_subsystem $ groupBy (eqOn cfgSubsystem) cfgs in Library (cfgLibrary c) (sum [n | Subsystem _ n _ <- subs]) subs mk_subsystem cfgs@(c:_) = let cols = map cfgDatatype cfgs in Subsystem (cfgSubsystem c) (length cols) cols instance Show Cfg where showsPrec _ cfg = showString (cfgLibrary cfg) . sub (cfgSubsystem cfg) . showChar '.' . showString (cfgDatatype cfg) where sub "" = id sub s = showChar '.' . showString s data Entry a = Entry { eCfg :: Cfg , eName :: String , eData :: a } data Table = Table { tRows :: [String] , tColumns :: [Cfg] , tCells :: M.Map String Row , tShowCell :: Double -> String } type Row = M.Map Cfg Double mkTable :: (Double -> String) -> [Entry Double] -> Table mkTable show es = Table { tRows = nub $ map eName es , tColumns = sort $ nub $ map eCfg es , tCells = M.fromListWith M.union [(eName e, unit e) | e <- es] , tShowCell = show } where unit e = M.singleton (eCfg e) (eData e) structure :: Table -> [Library] structure = groupCfgs . tColumns cells :: Table -> [(String, [Maybe Double])] cells (Table { tRows = names , tColumns = cfgs , tCells = t }) = concatMap row_cells names where row_cells name = case M.lookup name t of Just row -> [(name, map (cell row) cfgs)] Nothing -> [] cell row cfg = M.lookup cfg row outputHTML :: Table -> IO () outputHTML t = do putStrLn "
" putStrLn $ htmlTable t putStrLn "" htmlTable :: Table -> String htmlTable t = unlines [ "