packages feed

ghc-prof-1.0.0: bin/dump.hs

{-# LANGUAGE OverloadedStrings #-}
module Main where
import Control.Applicative ((<$>))
import Data.Foldable
import Prelude hiding (concat, foldl)
import System.Console.GetOpt
import System.Environment (getArgs)
import Text.Printf

import Data.Scientific
import Data.Tree (drawTree)
import qualified Data.Attoparsec.Text.Lazy as ATL
import qualified Data.Text as T
import qualified Data.Text.Lazy.IO as TLIO

import GHC.Prof

main :: IO ()
main = do
  (opts, file:restArgs) <- parseOpts =<< getArgs
  text <- TLIO.readFile file
  case ATL.parse profile text of
    ATL.Fail unconsumed contexts reason ->
      fail $ show (unconsumed, contexts, reason)
    ATL.Done _ prof -> case optMode opts of
      AggregateMode ->
        traverse_ (putStrLn . makeAggregateCCName) $ aggregateCostCentres prof
      TreeMode -> case restArgs of
        [] ->
          traverse_ putStrLn $ drawTree . fmap makeCCName <$> costCentres prof
        name:modName:_ -> do
          case callSites (T.pack name) (T.pack modName) prof of
            Nothing -> putStrLn "failed to parse call sites"
            Just (callee, callers) -> do
              print callee
              traverse_ print callers
        _ -> fail "Invalid parameters"

makeCCName :: CostCentre -> String
makeCCName cc = printf "%s.%s:%d (%s,%s,%s,%s)"
  (T.unpack $ costCentreModule cc)
  (T.unpack $ costCentreName cc)
  (costCentreNo cc)
  (showScientific $ costCentreInhTime cc)
  (showScientific $ costCentreIndTime cc)
  (showScientific $ costCentreInhAlloc cc)
  (showScientific $ costCentreIndAlloc cc)

makeAggregateCCName :: AggregateCostCentre -> String
makeAggregateCCName aggregate = printf
  "%s%%\t%s%%\t%s.%s"
  (showScientific $ aggregateCostCentreTime aggregate)
  (showScientific $ aggregateCostCentreAlloc aggregate)
  (T.unpack $ aggregateCostCentreModule aggregate)
  (T.unpack $ aggregateCostCentreName aggregate)

showScientific :: Scientific -> String
showScientific = formatScientific Fixed Nothing

data Options = Options
  { optMode :: Mode
  }

defaultOptions :: Options
defaultOptions = Options
  { optMode = TreeMode
  }

data Mode = AggregateMode | TreeMode

options :: [OptDescr (Options -> Options)]
options =
  [ Option ['a'] ["aggregate"]
    (NoArg (\opts -> opts { optMode = AggregateMode }))
      "Aggregate mode"
  ]

parseOpts :: [String] -> IO (Options, [String])
parseOpts argv = case getOpt Permute options argv of
  (opts, rest, []) -> return (foldl (flip id) defaultOptions opts, rest)
  (_, _, errs) -> fail $ concat errs ++ usageInfo header options
  where
    header = "Usage: dump [OPTION...] ..."