diff options
-rw-r--r-- | compiler/basicTypes/Unique.lhs | 10 | ||||
-rw-r--r-- | compiler/codeGen/CgProf.hs | 6 | ||||
-rw-r--r-- | compiler/codeGen/StgCmmProf.hs | 12 | ||||
-rw-r--r-- | compiler/deSugar/Coverage.lhs | 105 | ||||
-rw-r--r-- | compiler/deSugar/DsExpr.lhs | 5 | ||||
-rw-r--r-- | compiler/iface/BinIface.hs | 23 | ||||
-rw-r--r-- | compiler/main/DynFlags.hs | 2 | ||||
-rw-r--r-- | compiler/profiling/CostCentre.lhs | 91 | ||||
-rw-r--r-- | compiler/profiling/SCCfinal.lhs | 8 | ||||
-rw-r--r-- | docs/users_guide/ghci.xml | 3 | ||||
-rw-r--r-- | docs/users_guide/profiling.xml | 18 | ||||
-rw-r--r-- | docs/users_guide/runtime_control.xml | 8 | ||||
-rw-r--r-- | includes/rts/prof/CCS.h | 4 | ||||
-rw-r--r-- | rts/Profiling.c | 14 |
14 files changed, 199 insertions, 110 deletions
diff --git a/compiler/basicTypes/Unique.lhs b/compiler/basicTypes/Unique.lhs index 6fba95c0b5..f99a50cfeb 100644 --- a/compiler/basicTypes/Unique.lhs +++ b/compiler/basicTypes/Unique.lhs @@ -56,10 +56,10 @@ module Unique ( mkVarOccUnique, mkDataOccUnique, mkTvOccUnique, mkTcOccUnique, mkRegSingleUnique, mkRegPairUnique, mkRegClassUnique, mkRegSubUnique, + mkCostCentreUnique, mkBuiltinUnique, - mkPseudoUniqueC, - mkPseudoUniqueD, + mkPseudoUniqueD, mkPseudoUniqueE, mkPseudoUniqueH ) where @@ -359,11 +359,10 @@ mkPArrDataConUnique a = mkUnique ':' (2*a) initTyVarUnique :: Unique initTyVarUnique = mkUnique 't' 0 -mkPseudoUniqueC, mkPseudoUniqueD, mkPseudoUniqueE, mkPseudoUniqueH, +mkPseudoUniqueD, mkPseudoUniqueE, mkPseudoUniqueH, mkBuiltinUnique :: Int -> Unique mkBuiltinUnique i = mkUnique 'B' i -mkPseudoUniqueC i = mkUnique 'C' i -- used for getUnique on Regs mkPseudoUniqueD i = mkUnique 'D' i -- used in NCG for getUnique on RealRegs mkPseudoUniqueE i = mkUnique 'E' i -- used in NCG spiller to create spill VirtualRegs mkPseudoUniqueH i = mkUnique 'H' i -- used in NCG spiller to create spill VirtualRegs @@ -374,6 +373,9 @@ mkRegSubUnique = mkUnique 'S' mkRegPairUnique = mkUnique 'P' mkRegClassUnique = mkUnique 'L' +mkCostCentreUnique :: Int -> Unique +mkCostCentreUnique = mkUnique 'C' + mkVarOccUnique, mkDataOccUnique, mkTvOccUnique, mkTcOccUnique :: FastString -> Unique -- See Note [The Unique of an OccName] in OccName mkVarOccUnique fs = mkUnique 'i' (iBox (uniqueOfFS fs)) diff --git a/compiler/codeGen/CgProf.hs b/compiler/codeGen/CgProf.hs index 3e247ff4d6..92adf1afa7 100644 --- a/compiler/codeGen/CgProf.hs +++ b/compiler/codeGen/CgProf.hs @@ -170,11 +170,15 @@ emitCostCentreDecl cc = do -- All cost centres will be in the main package, since we -- don't normally use -auto-all or add SCCs to other packages. -- Hence don't emit the package name in the module here. + ; loc <- newByteStringCLit $ bytesFS $ mkFastString $ + showSDoc (ppr (costCentreSrcSpan cc)) + -- XXX going via FastString to get UTF-8 encoding is silly ; let lits = [ zero, -- StgInt ccID, label, -- char *label, modl, -- char *module, - zero, -- StgWord time_ticks + loc, -- char *srcloc, + zero, -- StgWord time_ticks zero64, -- StgWord64 mem_alloc is_caf, -- StgInt is_caf zero -- struct _CostCentre *link diff --git a/compiler/codeGen/StgCmmProf.hs b/compiler/codeGen/StgCmmProf.hs index d9b3583382..8ce1d5b372 100644 --- a/compiler/codeGen/StgCmmProf.hs +++ b/compiler/codeGen/StgCmmProf.hs @@ -58,6 +58,7 @@ import Constants -- Lots of field offsets import Outputable import Control.Monad +import Data.Char (ord) ----------------------------------------------------------------------------- -- @@ -217,18 +218,25 @@ emitCostCentreDecl cc = do ; modl <- newByteStringCLit (bytesFS $ Module.moduleNameFS $ Module.moduleName $ cc_mod cc) + ; loc <- newStringCLit (showSDoc (ppr (costCentreSrcSpan cc))) + -- XXX should UTF-8 encode -- All cost centres will be in the main package, since we -- don't normally use -auto-all or add SCCs to other packages. -- Hence don't emit the package name in the module here. ; let lits = [ zero, -- StgInt ccID, label, -- char *label, - modl, -- char *module, - zero, -- StgWord time_ticks + modl, -- char *module, + loc, -- char *srcloc, + zero, -- StgWord time_ticks zero64, -- StgWord64 mem_alloc + is_caf, -- StgInt is_caf zero -- struct _CostCentre *link ] ; emitDataLits (mkCCLabel cc) lits } + where + is_caf | isCafCC cc = mkIntCLit (ord 'c') -- 'c' == is a CAF + | otherwise = zero emitCostCentreStackDecl :: CostCentreStack -> FCode () emitCostCentreStackDecl ccs diff --git a/compiler/deSugar/Coverage.lhs b/compiler/deSugar/Coverage.lhs index fd2895d072..84cb6d628f 100644 --- a/compiler/deSugar/Coverage.lhs +++ b/compiler/deSugar/Coverage.lhs @@ -33,6 +33,7 @@ import HscTypes import Platform import StaticFlags import TyCon +import Unique import BasicTypes import MonadUtils import Maybes @@ -177,8 +178,7 @@ data TickDensity | TickAllFunctions -- for -prof-auto-all | TickTopFunctions -- for -prof-auto-top | TickExportedFunctions -- for -prof-auto-exported - -- maybe also: - -- | TickCallSites -- for stack tracing + | TickCallSites -- for stack tracing deriving Eq mkDensity :: DynFlags -> TickDensity @@ -188,8 +188,13 @@ mkDensity dflags | ProfAutoAll <- profAuto dflags = TickAllFunctions | ProfAutoTop <- profAuto dflags = TickTopFunctions | ProfAutoExports <- profAuto dflags = TickExportedFunctions + | ProfAutoCalls <- profAuto dflags = TickCallSites | otherwise = panic "desnity" - + -- ToDo: -fhpc is taking priority over -fprof-auto here. It seems + -- that coverage works perfectly well with profiling, but you don't + -- get any auto-generated SCCs. It would make perfect sense to + -- allow both of them, and indeed to combine some of the other flags + -- (-fprof-auto-calls -fprof-auto-top, for example) -- | Decide whether to add a tick to a binding or not. shouldTickBind :: TickDensity @@ -208,6 +213,7 @@ shouldTickBind density top_lev exported simple_pat inline TickTopFunctions -> top_lev && not inline TickExportedFunctions -> exported && not inline TickForCoverage -> True + TickCallSites -> False shouldTickPatBind :: TickDensity -> Bool -> Bool shouldTickPatBind density top_lev @@ -217,6 +223,7 @@ shouldTickPatBind density top_lev TickTopFunctions -> top_lev TickExportedFunctions -> False TickForCoverage -> False + TickCallSites -> False -- ----------------------------------------------------------------------------- -- Adding ticks to bindings @@ -323,38 +330,60 @@ bindTick density name pos fvs = do -- selectively add ticks to interesting expressions addTickLHsExpr :: LHsExpr Id -> TM (LHsExpr Id) -addTickLHsExpr (L pos e0) = do +addTickLHsExpr e@(L pos e0) = do d <- getDensity case d of + TickForBreakPoints | isGoodBreakExpr e0 -> tick_it TickForCoverage -> tick_it - TickForBreakPoints -> if isGoodBreakExpr e0 then tick_it else dont_tick_it + TickCallSites | isCallSite e0 -> tick_it _other -> dont_tick_it where tick_it = allocTickBox (ExpBox False) False False pos $ addTickHsExpr e0 - dont_tick_it = do e1 <- addTickHsExpr e0; return $ L pos e1 - --- Add a tick to the expression no matter what it is. There is one exception: --- for the debugger, if the expression is a 'let', then we don't want to add --- a tick here because there will definititely be a tick on the body anyway. -addTickLHsExprAlways :: LHsExpr Id -> TM (LHsExpr Id) -addTickLHsExprAlways (L pos e0) = do + dont_tick_it = addTickLHsExprNever e + +-- Add a tick to an expression which is the RHS of an equation or a binding. +-- We always consider these to be breakpoints, unless the expression is a 'let' +-- (because the body will definitely have a tick somewhere). ToDo: perhaps +-- we should treat 'case' and 'if' the same way? +addTickLHsExprRHS :: LHsExpr Id -> TM (LHsExpr Id) +addTickLHsExprRHS e@(L pos e0) = do d <- getDensity case d of - TickForBreakPoints | HsLet _ _ <- e0 -> dont_tick_it - | otherwise -> tick_it + TickForBreakPoints | HsLet{} <- e0 -> dont_tick_it + | otherwise -> tick_it TickForCoverage -> tick_it + TickCallSites | isCallSite e0 -> tick_it _other -> dont_tick_it where tick_it = allocTickBox (ExpBox False) False False pos $ addTickHsExpr e0 - dont_tick_it = do e1 <- addTickHsExpr e0; return $ L pos e1 - --- | A let body is ticked only if we're doing breakpoints. For coverage, the --- whole let is ticked, so there's no need to tick the body. + dont_tick_it = addTickLHsExprNever e + +-- The inner expression of an evaluation context: +-- let binds in [], ( [] ) +-- we never tick these if we're doing HPC, but otherwise +-- we treat it like an ordinary expression. +addTickLHsExprEvalInner :: LHsExpr Id -> TM (LHsExpr Id) +addTickLHsExprEvalInner e = do + d <- getDensity + case d of + TickForCoverage -> addTickLHsExprNever e + _otherwise -> addTickLHsExpr e + +-- | A let body is treated differently from addTickLHsExprEvalInner +-- above with TickForBreakPoints, because for breakpoints we always +-- want to tick the body, even if it is not a redex. See test +-- break012. This gives the user the opportunity to inspect the +-- values of the let-bound variables. addTickLHsExprLetBody :: LHsExpr Id -> TM (LHsExpr Id) -addTickLHsExprLetBody e - = ifDensity TickForBreakPoints - (addTickLHsExprAlways e) - (addTickLHsExprNever e) +addTickLHsExprLetBody e@(L pos e0) = do + d <- getDensity + case d of + TickForBreakPoints | HsLet{} <- e0 -> dont_tick_it + | otherwise -> tick_it + _other -> addTickLHsExprEvalInner e + where + tick_it = allocTickBox (ExpBox False) False False pos $ addTickHsExpr e0 + dont_tick_it = addTickLHsExprNever e -- version of addTick that does not actually add a tick, -- because the scope of this tick is completely subsumed by @@ -369,14 +398,19 @@ isGoodBreakExpr :: HsExpr Id -> Bool isGoodBreakExpr (HsApp {}) = True isGoodBreakExpr (OpApp {}) = True isGoodBreakExpr (NegApp {}) = True -isGoodBreakExpr (HsCase {}) = True isGoodBreakExpr (HsIf {}) = True +isGoodBreakExpr (HsCase {}) = True isGoodBreakExpr (RecordCon {}) = True isGoodBreakExpr (RecordUpd {}) = True isGoodBreakExpr (ArithSeq {}) = True isGoodBreakExpr (PArrSeq {}) = True isGoodBreakExpr _other = False +isCallSite :: HsExpr Id -> Bool +isCallSite HsApp{} = True +isCallSite OpApp{} = True +isCallSite _ = False + addTickLHsExprOptAlt :: Bool -> LHsExpr Id -> TM (LHsExpr Id) addTickLHsExprOptAlt oneOfMany (L pos e0) = ifDensity TickForCoverage @@ -413,16 +447,14 @@ addTickHsExpr (NegApp e neg) = (addTickLHsExpr e) (addTickSyntaxExpr hpcSrcSpan neg) addTickHsExpr (HsPar e) = - liftM HsPar $ - ifDensity TickForCoverage (addTickLHsExprNever e) - (addTickLHsExpr e) -addTickHsExpr (SectionL e1 e2) = + liftM HsPar (addTickLHsExprEvalInner e) +addTickHsExpr (SectionL e1 e2) = liftM2 SectionL (addTickLHsExpr e1) - (addTickLHsExpr e2) + (addTickLHsExprNever e2) addTickHsExpr (SectionR e1 e2) = liftM2 SectionR - (addTickLHsExpr e1) + (addTickLHsExprNever e1) (addTickLHsExpr e2) addTickHsExpr (ExplicitTuple es boxity) = liftM2 ExplicitTuple @@ -430,7 +462,8 @@ addTickHsExpr (ExplicitTuple es boxity) = (return boxity) addTickHsExpr (HsCase e mgs) = liftM2 HsCase - (addTickLHsExpr e) + (addTickLHsExpr e) -- not an EvalInner; e might not necessarily + -- be evaluated. (addTickMatchGroup False mgs) addTickHsExpr (HsIf cnd e1 e2 e3) = liftM3 (HsIf cnd) @@ -551,7 +584,7 @@ addTickGRHSBody isOneOfMany isLambda expr@(L pos e0) = do allocTickBox (ExpBox False) True{-count-} False{-not top-} pos $ addTickHsExpr e0 _otherwise -> - addTickLHsExprAlways expr + addTickLHsExprRHS expr addTickLStmts :: (Maybe (Bool -> BoxLabel)) -> [LStmt Id] -> TM [LStmt Id] addTickLStmts isGuard stmts = do @@ -574,7 +607,7 @@ addTickStmt _isGuard (LastStmt e ret) = do addTickStmt _isGuard (BindStmt pat e bind fail) = do liftM4 BindStmt (addTickLPat pat) - (addTickLHsExprAlways e) + (addTickLHsExprRHS e) (addTickSyntaxExpr hpcSrcSpan bind) (addTickSyntaxExpr hpcSrcSpan fail) addTickStmt isGuard (ExprStmt e bind' guard' ty) = do @@ -598,8 +631,8 @@ addTickStmt isGuard stmt@(TransStmt { trS_stmts = stmts , trS_ret = returnExpr, trS_bind = bindExpr , trS_fmap = liftMExpr }) = do t_s <- addTickLStmts isGuard stmts - t_y <- fmapMaybeM addTickLHsExprAlways by - t_u <- addTickLHsExprAlways using + t_y <- fmapMaybeM addTickLHsExprRHS by + t_u <- addTickLHsExprRHS using t_f <- addTickSyntaxExpr hpcSrcSpan returnExpr t_b <- addTickSyntaxExpr hpcSrcSpan bindExpr t_m <- addTickSyntaxExpr hpcSrcSpan liftMExpr @@ -616,7 +649,7 @@ addTickStmt isGuard stmt@(RecStmt {}) addTick :: Maybe (Bool -> BoxLabel) -> LHsExpr Id -> TM (LHsExpr Id) addTick isGuard e | Just fn <- isGuard = addBinTickLHsExpr fn e - | otherwise = addTickLHsExprAlways e + | otherwise = addTickLHsExprRHS e addTickStmtAndBinders :: Maybe (Bool -> BoxLabel) -> ([LStmt Id], a) -> TM ([LStmt Id], a) @@ -987,7 +1020,7 @@ mkTickish boxLabel countEntries topOnly pos fvs decl_path = cc_name | topOnly = head decl_path | otherwise = concat (intersperse "." decl_path) - cc = mkUserCC (mkFastString cc_name) (this_mod env) + cc = mkUserCC (mkFastString cc_name) (this_mod env) pos (mkCostCentreUnique c) count = countEntries && dopt Opt_ProfCountEntries (dflags env) diff --git a/compiler/deSugar/DsExpr.lhs b/compiler/deSugar/DsExpr.lhs index 8b41d3a2af..95645de5f2 100644 --- a/compiler/deSugar/DsExpr.lhs +++ b/compiler/deSugar/DsExpr.lhs @@ -309,10 +309,11 @@ dsExpr (ExplicitTuple tup_args boxity) mkConApp (tupleCon (boxityNormalTupleSort boxity) (length tup_args)) (map (Type . exprType) args ++ args) } -dsExpr (HsSCC cc expr) = do +dsExpr (HsSCC cc expr@(L loc _)) = do mod_name <- getModuleDs count <- doptDs Opt_ProfCountEntries - Tick (ProfNote (mkUserCC cc mod_name) count True) <$> dsLExpr expr + uniq <- newUnique + Tick (ProfNote (mkUserCC cc mod_name loc uniq) count True) <$> dsLExpr expr dsExpr (HsCoreAnn _ expr) = dsLExpr expr diff --git a/compiler/iface/BinIface.hs b/compiler/iface/BinIface.hs index eb6ca87ba3..792421daa5 100644 --- a/compiler/iface/BinIface.hs +++ b/compiler/iface/BinIface.hs @@ -938,26 +938,31 @@ instance Binary IsCafCC where _ -> do return NotCafCC instance Binary CostCentre where - put_ bh NoCostCentre = do + put_ bh (NormalCC aa ab ac _ad ae) = do putByte bh 0 - put_ bh (NormalCC aa ab ac) = do - putByte bh 1 put_ bh aa put_ bh ab put_ bh ac - put_ bh (AllCafsCC ae) = do - putByte bh 2 + put_ bh ae + put_ bh (AllCafsCC ae _af) = do + putByte bh 1 put_ bh ae get bh = do h <- getByte bh case h of - 0 -> do return NoCostCentre - 1 -> do aa <- get bh + 0 -> do aa <- get bh ab <- get bh ac <- get bh - return (NormalCC aa ab ac) + ae <- get bh + return (NormalCC aa ab ac noSrcSpan ae) _ -> do ae <- get bh - return (AllCafsCC ae) + return (AllCafsCC ae noSrcSpan) + + -- We ignore the SrcSpans in CostCentres when we serialise them, + -- and set the SrcSpans to noSrcSpan when deserialising. This is + -- ok, because we only need the SrcSpan when declaring the + -- CostCentre in the original module, it is not used by importing + -- modules. ------------------------------------------------------------------------- -- IfaceTypes and friends diff --git a/compiler/main/DynFlags.hs b/compiler/main/DynFlags.hs index 9d6d15c0df..947b320e97 100644 --- a/compiler/main/DynFlags.hs +++ b/compiler/main/DynFlags.hs @@ -589,6 +589,7 @@ data ProfAuto | ProfAutoAll -- ^ top-level and nested functions are annotated | ProfAutoTop -- ^ top-level functions annotated only | ProfAutoExports -- ^ exported functions annotated only + | ProfAutoCalls -- ^ annotate call-sites data Settings = Settings { sTargetPlatform :: Platform, -- Filled in by SysTools @@ -1637,6 +1638,7 @@ dynamic_flags = [ , Flag "fprof-auto" (noArg (\d -> d { profAuto = ProfAutoAll } )) , Flag "fprof-auto-top" (noArg (\d -> d { profAuto = ProfAutoTop } )) , Flag "fprof-auto-exported" (noArg (\d -> d { profAuto = ProfAutoExports } )) + , Flag "fprof-auto-calls" (noArg (\d -> d { profAuto = ProfAutoCalls } )) , Flag "fno-prof-auto" (noArg (\d -> d { profAuto = NoProfAuto } )) ------ Compiler flags ----------------------------------------------- diff --git a/compiler/profiling/CostCentre.lhs b/compiler/profiling/CostCentre.lhs index 2a44121dfd..a4d7d1a398 100644 --- a/compiler/profiling/CostCentre.lhs +++ b/compiler/profiling/CostCentre.lhs @@ -15,7 +15,6 @@ module CostCentre ( CostCentreStack, CollectedCCs, noCCS, currentCCS, dontCareCCS, - noCostCentre, noCCAttached, noCCSAttached, isCurrentCCS, maybeSingletonCCS, @@ -25,6 +24,7 @@ module CostCentre ( pprCostCentreCore, costCentreUserName, costCentreUserNameFS, + costCentreSrcSpan, cmpCostCentre -- used for removing dups in a list ) where @@ -35,6 +35,7 @@ import Module import Unique import Outputable import FastTypes +import SrcLoc import FastString import Util @@ -43,20 +44,30 @@ import Data.Data ----------------------------------------------------------------------------- -- Cost Centres --- | A Cost Centre is the argument of an _scc_ expression. +-- | A Cost Centre is a single @{-# SCC #-}@ annotation. data CostCentre - = NoCostCentre -- Having this constructor avoids having - -- to use "Maybe CostCentre" all the time. - - | NormalCC { - cc_name :: CcName, -- Name of the cost centre itself - cc_mod :: Module, -- Name of module defining this CC. + = NormalCC { + cc_key :: {-# UNPACK #-} !Int, + -- ^ Two cost centres may have the same name and + -- module but different SrcSpans, so we need a way to + -- distinguish them easily and give them different + -- object-code labels. So every CostCentre has a + -- Unique that is distinct from every other + -- CostCentre in the same module. + -- + -- XXX: should really be using Unique here, but we + -- need to derive Data below and there's no Data + -- instance for Unique. + cc_name :: CcName, -- ^ Name of the cost centre itself + cc_mod :: Module, -- ^ Name of module defining this CC. + cc_loc :: SrcSpan, cc_is_caf :: IsCafCC -- see below } | AllCafsCC { - cc_mod :: Module -- Name of module defining this CC. + cc_mod :: Module, -- Name of module defining this CC. + cc_loc :: SrcSpan } deriving (Data, Typeable) @@ -65,9 +76,6 @@ type CcName = FastString data IsCafCC = NotCafCC | CafCC deriving (Eq, Ord, Data, Typeable) -noCostCentre :: CostCentre -noCostCentre = NoCostCentre - instance Eq CostCentre where c1 == c2 = case c1 `cmpCostCentre` c2 of { EQ -> True; _ -> False } @@ -80,10 +88,10 @@ cmpCostCentre :: CostCentre -> CostCentre -> Ordering cmpCostCentre (AllCafsCC {cc_mod = m1}) (AllCafsCC {cc_mod = m2}) = m1 `compare` m2 -cmpCostCentre (NormalCC {cc_name = n1, cc_mod = m1, cc_is_caf = c1}) - (NormalCC {cc_name = n2, cc_mod = m2, cc_is_caf = c2}) - -- first key is module name, then the name, then the cafness - = (m1 `compare` m2) `thenCmp` (n1 `compare` n2) `thenCmp` (c1 `compare` c2) +cmpCostCentre NormalCC {cc_key = n1, cc_mod = m1} + NormalCC {cc_key = n2, cc_mod = m2} + -- first key is module name, then the integer key + = (m1 `compare` m2) `thenCmp` (n1 `compare` n2) cmpCostCentre other_1 other_2 = let @@ -92,18 +100,17 @@ cmpCostCentre other_1 other_2 in if tag1 <# tag2 then LT else GT where - tag_CC NoCostCentre = _ILIT(0) - tag_CC (NormalCC {}) = _ILIT(1) - tag_CC (AllCafsCC {}) = _ILIT(2) + tag_CC (NormalCC {}) = _ILIT(0) + tag_CC (AllCafsCC {}) = _ILIT(1) ----------------------------------------------------------------------------- -- Predicates on CostCentre isCafCC :: CostCentre -> Bool -isCafCC (AllCafsCC {}) = True +isCafCC (AllCafsCC {}) = True isCafCC (NormalCC {cc_is_caf = CafCC}) = True -isCafCC _ = False +isCafCC _ = False -- | Is this a cost-centre which records scc counts isSccCountCC :: CostCentre -> Bool @@ -112,7 +119,6 @@ isSccCountCC cc | isCafCC cc = False -- | Is this a cost-centre which can be sccd ? sccAbleCC :: CostCentre -> Bool -sccAbleCC NoCostCentre = panic "sccAbleCC:NoCostCentre" sccAbleCC cc | isCafCC cc = False | otherwise = True @@ -123,15 +129,17 @@ ccFromThisModule cc m = cc_mod cc == m ----------------------------------------------------------------------------- -- Building cost centres -mkUserCC :: FastString -> Module -> CostCentre -mkUserCC cc_name mod - = NormalCC { cc_name = cc_name, cc_mod = mod, +mkUserCC :: FastString -> Module -> SrcSpan -> Unique -> CostCentre +mkUserCC cc_name mod loc key + = NormalCC { cc_key = getKey key, cc_name = cc_name, cc_mod = mod, cc_loc = loc, cc_is_caf = NotCafCC {-might be changed-} } mkAutoCC :: Id -> Module -> IsCafCC -> CostCentre mkAutoCC id mod is_caf - = NormalCC { cc_name = str, cc_mod = mod, + = NormalCC { cc_key = getKey (getUnique id), + cc_name = str, cc_mod = mod, + cc_loc = nameSrcSpan (getName id), cc_is_caf = is_caf } where @@ -144,8 +152,8 @@ mkAutoCC id mod is_caf | otherwise = mkFastString $ showSDoc $ ftext (occNameFS (getOccName id)) <> char '_' <> pprUnique (getUnique name) -mkAllCafsCC :: Module -> CostCentre -mkAllCafsCC m = AllCafsCC { cc_mod = m } +mkAllCafsCC :: Module -> SrcSpan -> CostCentre +mkAllCafsCC m loc = AllCafsCC { cc_mod = m, cc_loc = loc } ----------------------------------------------------------------------------- -- Cost Centre Stacks @@ -198,10 +206,6 @@ noCCSAttached :: CostCentreStack -> Bool noCCSAttached NoCCS = True noCCSAttached _ = False -noCCAttached :: CostCentre -> Bool -noCCAttached NoCostCentre = True -noCCAttached _ = False - isCurrentCCS :: CostCentreStack -> Bool isCurrentCCS CurrentCCS = True isCurrentCCS _ = False @@ -253,16 +257,15 @@ instance Outputable CostCentre where -- Printing in Core pprCostCentreCore :: CostCentre -> SDoc -pprCostCentreCore NoCostCentre - = text "__no_cc" pprCostCentreCore (AllCafsCC {cc_mod = m}) = text "__sccC" <+> braces (ppr m) -pprCostCentreCore (NormalCC {cc_name = n, cc_mod = m, +pprCostCentreCore (NormalCC {cc_key = key, cc_name = n, cc_mod = m, cc_loc = loc, cc_is_caf = caf}) = text "__scc" <+> braces (hsep [ - ftext (zEncodeFS n), - ppr m, - pp_caf caf + ppr m <> char '.' <> ftext n, + ifPprDebug (ppr key), + pp_caf caf, + ifPprDebug (ppr loc) ]) pp_caf :: IsCafCC -> SDoc @@ -271,11 +274,11 @@ pp_caf _ = empty -- Printing as a C label ppCostCentreLbl :: CostCentre -> SDoc -ppCostCentreLbl (NoCostCentre) = text "NONE_cc" ppCostCentreLbl (AllCafsCC {cc_mod = m}) = ppr m <> text "_CAFs_cc" -ppCostCentreLbl (NormalCC {cc_name = n, cc_mod = m, cc_is_caf = is_caf}) - = ppr m <> char '_' <> ftext (zEncodeFS n) <> - text (case is_caf of { CafCC -> "_CAF"; _ -> "" }) <> text "_cc" +ppCostCentreLbl (NormalCC {cc_key = k, cc_name = n, cc_mod = m, + cc_is_caf = is_caf}) + = ppr m <> char '_' <> ftext (zEncodeFS n) <> char '_' <> + case is_caf of { CafCC -> ptext (sLit "CAF"); _ -> ppr (mkUniqueGrimily k)} <> text "_cc" -- This is the name to go in the user-displayed string, -- recorded in the cost centre declaration @@ -283,10 +286,12 @@ costCentreUserName :: CostCentre -> String costCentreUserName = unpackFS . costCentreUserNameFS costCentreUserNameFS :: CostCentre -> FastString -costCentreUserNameFS (NoCostCentre) = mkFastString "NO_CC" costCentreUserNameFS (AllCafsCC {}) = mkFastString "CAF" costCentreUserNameFS (NormalCC {cc_name = name, cc_is_caf = is_caf}) = case is_caf of CafCC -> mkFastString "CAF:" `appendFS` name _ -> name + +costCentreSrcSpan :: CostCentre -> SrcSpan +costCentreSrcSpan = cc_loc \end{code} diff --git a/compiler/profiling/SCCfinal.lhs b/compiler/profiling/SCCfinal.lhs index 96a21eb056..6fc44c1df9 100644 --- a/compiler/profiling/SCCfinal.lhs +++ b/compiler/profiling/SCCfinal.lhs @@ -32,6 +32,8 @@ import UniqSupply ( UniqSupply ) import ListSetOps ( removeDups ) import Outputable import DynFlags +import FastString +import SrcLoc stgMassageForProfiling @@ -60,7 +62,8 @@ stgMassageForProfiling dflags mod_name _us stg_binds fixed_cc_stacks ++ cc_stacks), stg_binds2) where - all_cafs_cc = mkAllCafsCC mod_name + span = mkGeneralSrcSpan (mkFastString "<entire-module>") -- XXX do better + all_cafs_cc = mkAllCafsCC mod_name span all_cafs_ccs = mkSingletonCCS all_cafs_cc ---------- @@ -244,8 +247,7 @@ thenMM_ expr cont = MassageM $ \mod ccs -> collectCC :: CostCentre -> MassageM () collectCC cc = MassageM $ \mod_name (local_ccs, extern_ccs, ccss) - -> ASSERT(not (noCCAttached cc)) - if (cc `ccFromThisModule` mod_name) then + -> if (cc `ccFromThisModule` mod_name) then ((cc : local_ccs, extern_ccs, ccss), ()) else -- must declare it "extern" ((local_ccs, cc : extern_ccs, ccss), ()) diff --git a/docs/users_guide/ghci.xml b/docs/users_guide/ghci.xml index eea6f86fa2..d09a794b11 100644 --- a/docs/users_guide/ghci.xml +++ b/docs/users_guide/ghci.xml @@ -1659,7 +1659,8 @@ a :: a particular call to <literal>head</literal> in your program resulted in the error can be a painstaking process, usually involving <literal>Debug.Trace.trace</literal>, or compiling with - profiling and using <literal>+RTS -xc</literal> (see <xref + profiling and using <literal>Debug.Trace.traceStack</literal> + or <literal>+RTS -xc</literal> (see <xref linkend="prof-time-options" />).</para> <para>The GHCi debugger offers a way to hopefully shed some light on diff --git a/docs/users_guide/profiling.xml b/docs/users_guide/profiling.xml index ee3b387e31..25db08045a 100644 --- a/docs/users_guide/profiling.xml +++ b/docs/users_guide/profiling.xml @@ -437,6 +437,24 @@ MAIN MAIN 102 0 0.0 0.0 100.0 1 <varlistentry> <term> + <option>-fprof-auto-calls</option>: + <indexterm><primary><option>-fprof-auto-calls</option></primary></indexterm> + </term> + <listitem> + <para>Adds an automatic <literal>SCC</literal> annotation to + all <emphasis>call sites</emphasis>. This is particularly + useful when using profiling for the purposes of generating + stack traces; see the + function <literal>traceStack</literal> in the + module <literal>Debug.Trace</literal>, or + the <literal>-xc</literal> RTS flag + (<xref linkend="rts-options-debugging" />) for more + details.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term> <option>-fprof-cafs</option>: <indexterm><primary><option>-fprof-cafs</option></primary></indexterm> </term> diff --git a/docs/users_guide/runtime_control.xml b/docs/users_guide/runtime_control.xml index 793ceec46b..7b2b469a0a 100644 --- a/docs/users_guide/runtime_control.xml +++ b/docs/users_guide/runtime_control.xml @@ -1290,7 +1290,7 @@ $ ./prog -f +RTS -H32m -S -RTS -h foo bar <listitem> <para>(Only available when the program is compiled for profiling.) When an exception is raised in the program, - this option causes the current cost-centre-stack to be + this option causes a stack trace to be dumped to <literal>stderr</literal>.</para> <para>This can be particularly useful for debugging: if your @@ -1337,6 +1337,12 @@ $ ./prog -f +RTS -H32m -S -RTS -h foo bar <para>Implementation details aside, the function names in the stack should hopefully give you enough clues to track down the bug.</para> + + <para> + See also the function <literal>traceStack</literal> in the + module <literal>Debug.Trace</literal> for another way to + view call stacks. + </para> </listitem> </varlistentry> diff --git a/includes/rts/prof/CCS.h b/includes/rts/prof/CCS.h index 9737fc9c18..36404aaf91 100644 --- a/includes/rts/prof/CCS.h +++ b/includes/rts/prof/CCS.h @@ -34,6 +34,7 @@ typedef struct _CostCentre { char * label; char * module; + char * srcloc; // used for accumulating costs at the end of the run... StgWord time_ticks; @@ -203,11 +204,12 @@ extern CostCentreStack * RTS_VAR(CCS_LIST); // registered CCS list * Declaring Cost Centres & Cost Centre Stacks. * -------------------------------------------------------------------------- */ -# define CC_DECLARE(cc_ident,name,mod,caf,is_local) \ +# define CC_DECLARE(cc_ident,name,mod,loc,caf,is_local) \ is_local CostCentre cc_ident[1] \ = {{ ccID : 0, \ label : name, \ module : mod, \ + srcloc : loc, \ time_ticks : 0, \ mem_alloc : 0, \ link : 0, \ diff --git a/rts/Profiling.c b/rts/Profiling.c index 7fb7f9e3cf..ed374b562f 100644 --- a/rts/Profiling.c +++ b/rts/Profiling.c @@ -87,13 +87,13 @@ Mutex ccs_mutex; * traverse pinned memory. */ -CC_DECLARE(CC_MAIN, "MAIN", "MAIN", CC_NOT_CAF, ); -CC_DECLARE(CC_SYSTEM, "SYSTEM", "SYSTEM", CC_NOT_CAF, ); -CC_DECLARE(CC_GC, "GC", "GC", CC_NOT_CAF, ); -CC_DECLARE(CC_OVERHEAD, "OVERHEAD_of", "PROFILING", CC_NOT_CAF, ); -CC_DECLARE(CC_DONT_CARE, "DONT_CARE", "MAIN", CC_NOT_CAF, ); -CC_DECLARE(CC_PINNED, "PINNED", "SYSTEM", CC_NOT_CAF, ); -CC_DECLARE(CC_IDLE, "IDLE", "IDLE", CC_NOT_CAF, ); +CC_DECLARE(CC_MAIN, "MAIN", "MAIN", "<built-in>", CC_NOT_CAF, ); +CC_DECLARE(CC_SYSTEM, "SYSTEM", "SYSTEM", "<built-in>", CC_NOT_CAF, ); +CC_DECLARE(CC_GC, "GC", "GC", "<built-in>", CC_NOT_CAF, ); +CC_DECLARE(CC_OVERHEAD, "OVERHEAD_of", "PROFILING", "<built-in>", CC_NOT_CAF, ); +CC_DECLARE(CC_DONT_CARE, "DONT_CARE", "MAIN", "<built-in>", CC_NOT_CAF, ); +CC_DECLARE(CC_PINNED, "PINNED", "SYSTEM", "<built-in>", CC_NOT_CAF, ); +CC_DECLARE(CC_IDLE, "IDLE", "IDLE", "<built-in>", CC_NOT_CAF, ); CCS_DECLARE(CCS_MAIN, CC_MAIN, ); CCS_DECLARE(CCS_SYSTEM, CC_SYSTEM, ); |