{-# LANGUAGE RecordWildCards, ViewPatterns #-} module Main(main) where import GHC.Prof import Control.Monad import Data.List.Extra import Data.Char import Data.Monoid import Data.Tree import qualified Data.Set as Set import qualified Data.Map as Map import qualified Data.Text.Lazy.IO as T import System.Environment import System.FilePath import System.Directory import Type import Config import Report import Data.Functor import Prelude main :: IO () main = do [arg] <- getArgs Right vals <- fmap (removeZero . valFromProfile) . decode <$> T.readFile arg b <- doesFileExist ".profiterole.yaml" config <- if b then readConfig ".profiterole.yaml" else return emptyConfig let roots = findRoots config vals let vals2 = mergeRoots $ liftRoots roots vals let arg0 = if takeExtension arg == ".prof" then dropExtension arg else arg let writeTo file x = do putStrLn $ "Writing to " ++ file ++ " ..." writeFile file x writeTo (arg0 <.> "profiterole.txt") $ unlines $ reportText vals2 writeTo (arg0 <.> "profiterole.html") $ unlines $ reportHTML vals2 putStrLn "Done" when False $ do -- Should check the time is not lost, if it is, suggest -P print $ sum $ map timeInd $ concatMap flatten vals2 print $ sum $ map (timeInh . rootLabel) vals2 --------------------------------------------------------------------- -- TRANSFORMATIONS removeZero :: Tree Val -> Tree Val removeZero (Node x xs) = Node x $ map removeZero $ filter (not . isZero . rootLabel) xs where isZero Val{..} = timeTot == 0 -- | A root has at least two distinct parents and isn't a local binding findRoots :: (String -> Maybe Config) -> Tree Val -> Set.Set String findRoots config x = Map.keysSet $ Map.filterWithKey (\k v -> case config k of Just Root -> True Just Bury -> False Nothing -> not (isLocal k) && Set.size v > 1) $ Map.fromListWith (<>) $ f x where f (Node v xs) = [(name $ rootLabel x, Set.singleton $ name v) | x <- xs] ++ concatMap f xs isLocal (word1 -> (_, x)) = any isAlpha x && '.' `elem` x liftRoots :: Set.Set String -> Tree Val -> [Tree Val] liftRoots = fs where fs set x = let (y,_,ys) = f set x in y:ys -- return (this tree, discount to apply up, new roots) f :: Set.Set String -> Tree Val -> (Tree Val, Double, [Tree Val]) f set (Node x ys) | name x `Set.member` set = (Node x{timeInh=0,timeInd=0} [], timeInh x, fs (Set.delete (name x) set) $ Node x ys) | otherwise = (Node x{timeInh = timeInh x - disc} child, disc, root) where (child, sum -> disc, concat -> root) = unzip3 $ map (f set) ys mergeRoots :: [Tree Val] -> [Tree Val] mergeRoots xs = Map.elems $ Map.fromListWith f [(name $ rootLabel x, x) | x <- xs] where f (Node x xs) (Node y ys) = Node (mergeVal x y) $ mergeRoots $ xs ++ ys