module FindBench(findLocalBenchmarks) where --module Main where import Control.Exception import Control.Monad (filterM, when, liftM) import Data.List import System.Directory import System.FilePath import System.IO {- -- for standalone testing main = do findLocalBenchmarks "benchmarks" -} benchmarksModule = ["Fibon", "Benchmarks"] benchmarksInstanceModule = "Fibon.Instance" findLocalBenchmarks :: FilePath -> IO () findLocalBenchmarks baseDir = do let searchPath = join ([pathSeparator]) (baseDir : benchmarksModule) putStr $ "Looking for benchmarks in "++searchPath groups <- sort `liftM` bmGroups searchPath bms <- bmInstances searchPath groups let allBms = (sort . concat) bms qualifiedBms = concat $ zipWith (\g bs -> map ((,)g) (sort bs)) groups bms outFile = searchPath ++ ".hs" when (null groups) printNoBenchmarksWarning putStrLn $ "... found ("++ (show.length$ allBms)++")" putStrLn $ " writing benchmark manifest to "++outFile createDirectoryIfMissing True (baseDir "Fibon") h <- openFile outFile WriteMode hPutStrLn h moduleHeader hPutStrLn h $ moduleImports (join "." benchmarksModule) qualifiedBms hPutStrLn h "" hPutStrLn h $ benchDataDecl allBms hPutStrLn h "" hPutStrLn h $ groupDataDecl groups hPutStrLn h "" hPutStrLn h $ allBenchmarksDecl allBms hPutStrLn h "" hPutStrLn h $ benchGroupDecl qualifiedBms hPutStrLn h "" hPutStrLn h $ benchInstanceDecl qualifiedBms hPutStrLn h "" hPutStrLn h $ benchPathDecl qualifiedBms hClose h bmGroups :: FilePath -> IO [FilePath] bmGroups baseDir = do dirs <- try (getDirectoryContents baseDir) :: IO (Either IOError [FilePath]) case dirs of Left _ -> return [] Right ds -> removeBadEntries baseDir ds bmInstances :: FilePath -> [FilePath] -> IO [[String]] bmInstances baseDir groups = do let paths = map (baseDir ) groups bms <- mapM getDirectoryContents paths mapM (\(p, bm) -> removeBadEntries p bm) (zip paths bms) removeDotFiles :: [FilePath] -> [FilePath] removeDotFiles = filter (\d -> not ("." `isPrefixOf` d)) removeBadEntries :: FilePath -> [FilePath] -> IO [FilePath] removeBadEntries baseDir dirs = do let paths = map (baseDir ) dirs noFiles <- filterM (\d -> doesDirectoryExist (baseDir d)) dirs let noUnderscores = filter (\d -> not ("_" `isPrefixOf` d)) noFiles return (removeDotFiles noUnderscores) moduleHeader :: String moduleHeader = join "\n" [ "module "++modName++" (", " FibonBenchmark(..)", " , FibonGroup(..)", " , allBenchmarks", " , benchGroup", " , benchInstance", " , benchPath", ")", "where", "import Fibon.InputSize", "import Fibon.BenchmarkInstance", "import System.FilePath" ] where modName = join "." benchmarksModule moduleImports :: String -> [(String, String)] -> String moduleImports baseMod bms = join "\n" imports where imports = map importStmt bms importStmt (g,bm) = "import qualified " ++baseMod++"."++g++"."++bm++"."++benchmarksInstanceModule ++" as "++(importAs g bm) importAs :: String -> String -> String importAs _grp modu = modu ++ "_bm" groupName :: String -> String groupName g = g benchDataDecl :: [String] -> String benchDataDecl bms = "data FibonBenchmark = " ++ datas bms ++ derivings where derivings = "\n deriving(Read, Show, Eq, Ord, Enum)" datas [] = "NoBenchmarksFound" datas bms = "\n " ++ (join ("\n | ") bms) groupDataDecl :: [String] -> String groupDataDecl grps = "data FibonGroup = " ++ datas grps ++ derivings where derivings = "\n deriving(Read, Show, Eq, Ord, Enum)" datas [] = "NoGroupsFound" datas grps = "\n "++ (join ("\n | ") (map groupName grps)) allBenchmarksDecl :: [String] -> String allBenchmarksDecl bms = "allBenchmarks :: [FibonBenchmark]\n"++ "allBenchmarks = [\n "++ (join ("\n , ") bms) ++ "\n ]" benchGroupDecl :: [(String, String)] -> String benchGroupDecl [] = benchGroupTypeDecl ++ "benchGroup = "++ emptyError benchGroupDecl qBms = benchGroupTypeDecl ++ (join ("\n") $ map defn qBms) where defn (g,bm) = "benchGroup " ++ bm ++ " = " ++ (groupName g) benchGroupTypeDecl :: String benchGroupTypeDecl = "benchGroup :: FibonBenchmark -> FibonGroup\n" benchInstanceDecl :: [(String, String)] -> String benchInstanceDecl [] = benchInstanceTypeDecl ++ "benchInstance = "++ emptyError benchInstanceDecl qBms = benchInstanceTypeDecl ++ (join ("\n") $ map defn qBms) where defn (g,bm) = "benchInstance " ++ bm ++ " = " ++ (importAs g bm) ++ ".mkInstance" benchInstanceTypeDecl :: String benchInstanceTypeDecl = "benchInstance :: FibonBenchmark -> InputSize -> BenchmarkInstance\n" benchPathDecl :: [(String, String)] -> String benchPathDecl [] = benchPathTypeDecl ++ "benchPath = " ++ emptyError benchPathDecl qBms = benchPathTypeDecl ++ (join ("\n") $ map defn qBms) where defn (g,bm) = "benchPath " ++ bm ++ " = " ++ s g ++ " " ++ s bm s x = "\"" ++ x ++"\"" benchPathTypeDecl :: String benchPathTypeDecl = "benchPath :: FibonBenchmark -> FilePath\n" join :: String -> [String] -> String join s ss = concat (intersperse s ss) emptyError :: String emptyError = "error \"No benchmarks found. Need to re-run cabal config step\"" printNoBenchmarksWarning :: IO () printNoBenchmarksWarning = do putStrLn "\n" putStrLn banner putStrLn $cap("! No benchmarks found.") putStrLn $cap("! You will not be able to run collect results with fibon-run") putStrLn banner putStrLn "" where banner = line++"WARNING"++line line = take 30 (repeat '-') cap s = s ++ take ((length banner) - (length s) - 1) (repeat ' ') ++ "!"