ghc-prof-1.4.1: tests/Regression.hs
{-# LANGUAGE CPP #-}
{-# LANGUAGE ViewPatterns #-}
module Main where
import Control.Applicative
import Control.Monad
import Data.Foldable
import Data.Monoid
import Data.Traversable
import System.Directory
import System.FilePath
import System.IO
import Prelude
import System.IO.Temp
import System.Process
import Test.Tasty
import Test.Tasty.HUnit
import qualified Data.Attoparsec.Text.Lazy as ATL
import qualified Data.Set as Set
import qualified Data.Text.Lazy.IO as TL
import qualified Data.Text.IO as T
import GHC.Prof
#if !MIN_VERSION_directory(1, 2, 3)
import Control.Exception
#endif
main :: IO ()
main = withSystemTempDirectory "test" $ \dir -> withCurrentDirectory dir $
defaultMain $ testCaseSteps "Regression tests" $ \step -> do
step "Generating profiling reports"
profiles <- generateProfiles
for_ profiles $ \prof -> do
step $ "Parsing " ++ prof
assertProfile prof
for_ profiles $ \prof -> do
step $ "Decode " ++ prof
assertDecode prof
step $ "Decode' " ++ prof
assertDecode' prof
generateProfiles :: IO [FilePath]
generateProfiles = do
withFile "hello.hs" WriteMode $ \h ->
hPutStrLn h $ unlines
[ "import Control.Exception"
, "main = evaluate $ fib 100000"
, "fib n = fibs !! n"
, "fibs = 0:1:zipWith (+) fibs (tail fibs)"
]
void $ readProcess "ghc" ["-prof", "-rtsopts", "-fforce-recomp", "hello.hs"] ""
for profilingFlags $ \(name, flag) -> do
void $ readProcess "./hello" ["+RTS", flag, "-RTS"] ""
let profName = "hello" <.> name <.> "prof"
renameFile "hello.prof" profName
return profName
profilingFlags :: [(String, String)]
profilingFlags =
[ ("standard", "-p")
, ("detailed", "-P")
, ("full", "-pa")
]
caseStudy :: Profile -> IO ()
caseStudy prof = do
let actual = Set.fromList $ map Similar $ aggregatedCostCentres prof
expected = Set.fromList $ map Similar $ profileTopCostCentres prof
assertBool
("Missing cost centre(s): " ++ show (Set.difference expected actual)) $
Set.isSubsetOf expected actual
assertProfile :: FilePath -> Assertion
assertProfile path = do
text <- TL.readFile path
case ATL.parse profile text of
ATL.Done _ prof -> caseStudy prof
ATL.Fail _ _ reason -> assertFailure reason
assertDecode :: FilePath -> Assertion
assertDecode path = do
text <- TL.readFile path
case decode text of
Right prof -> caseStudy prof
Left reason -> assertFailure reason
assertDecode' :: FilePath -> Assertion
assertDecode' path = do
text <- T.readFile path
case decode' text of
Right prof -> caseStudy prof
Left reason -> assertFailure reason
newtype Similar = Similar AggregatedCostCentre
instance Show Similar where
show (Similar a) = show a
instance Eq Similar where
Similar a == Similar b =
aggregatedCostCentreName a == aggregatedCostCentreName b
&& aggregatedCostCentreModule a == aggregatedCostCentreModule b
&& aggregatedCostCentreTime a == aggregatedCostCentreTime b
&& aggregatedCostCentreAlloc a == aggregatedCostCentreAlloc b
&& aggregatedCostCentreTicks a == aggregatedCostCentreTicks b
&& aggregatedCostCentreBytes a == aggregatedCostCentreBytes b
instance Ord Similar where
compare (Similar a) (Similar b) =
compare (aggregatedCostCentreName a) (aggregatedCostCentreName b)
<> compare (aggregatedCostCentreModule a) (aggregatedCostCentreModule b)
<> compare (aggregatedCostCentreTime a) (aggregatedCostCentreTime b)
<> compare (aggregatedCostCentreAlloc a) (aggregatedCostCentreAlloc b)
<> compare (aggregatedCostCentreTicks a) (aggregatedCostCentreTicks b)
<> compare (aggregatedCostCentreBytes a) (aggregatedCostCentreBytes b)
#if !MIN_VERSION_directory(1, 2, 3)
withCurrentDirectory :: FilePath -> IO a -> IO a
withCurrentDirectory dir io = bracket
(getCurrentDirectory <* setCurrentDirectory dir)
(setCurrentDirectory)
(const io)
#endif