----------------------------------------------------------------------------- -- -- Code generation for ticky-ticky profiling -- -- (c) The University of Glasgow 2004 -- ----------------------------------------------------------------------------- module CgTicky ( emitTickyCounter, tickyDynAlloc, tickyAllocHeap, tickyAllocPrim, tickyAllocThunk, tickyAllocPAP, tickyPushUpdateFrame, tickyUpdateFrameOmitted, tickyEnterDynCon, tickyEnterStaticCon, tickyEnterViaNode, tickyEnterFun, tickyEnterThunk, tickyUpdateBhCaf, tickyBlackHole, tickyUnboxedTupleReturn, tickyVectoredReturn, tickyReturnOldCon, tickyReturnNewCon, tickyKnownCallTooFewArgs, tickyKnownCallExact, tickyKnownCallExtraArgs, tickyUnknownCall, tickySlowCallPat, staticTickyHdr, ) where #include "HsVersions.h" #include "../includes/DerivedConstants.h" -- For REP_xxx constants, which are MachReps import ClosureInfo ( ClosureInfo, closureSize, slopSize, closureSMRep, closureUpdReqd, closureName, isStaticClosure ) import CgUtils import CgMonad import SMRep ( ClosureType(..), smRepClosureType, CgRep ) import Cmm import MachOp import CmmUtils ( zeroCLit, mkIntCLit, mkLblExpr, cmmIndexExpr ) import CLabel ( CLabel, mkRtsDataLabel, mkRednCountsLabel ) import Name ( isInternalName ) import Id ( Id, idType ) import StaticFlags ( opt_DoTickyProfiling ) import BasicTypes ( Arity ) import FastString ( FastString, mkFastString, LitString ) import Constants -- Lots of field offsets import Outputable -- Turgid imports for showTypeCategory import PrelNames import TcType ( Type, isDictTy, tcSplitTyConApp_maybe, tcSplitFunTy_maybe ) import TyCon ( isPrimTyCon, isTupleTyCon, isEnumerationTyCon, maybeTyConSingleCon ) import Maybe ----------------------------------------------------------------------------- -- -- Ticky-ticky profiling -- ----------------------------------------------------------------------------- staticTickyHdr :: [CmmLit] -- The ticky header words in a static closure -- Was SET_STATIC_TICKY_HDR staticTickyHdr | not opt_DoTickyProfiling = [] | otherwise = [zeroCLit] emitTickyCounter :: ClosureInfo -> [Id] -> Int -> Code emitTickyCounter cl_info args on_stk = ifTicky $ do { mod_name <- moduleName ; fun_descr_lit <- mkStringCLit (fun_descr mod_name) ; arg_descr_lit <- mkStringCLit arg_descr ; emitDataLits ticky_ctr_label -- Must match layout of StgEntCounter [ CmmInt 0 I16, CmmInt (fromIntegral (length args)) I16, -- Arity CmmInt (fromIntegral on_stk) I16, -- Words passed on stack CmmInt 0 I16, -- 2-byte gap fun_descr_lit, arg_descr_lit, zeroCLit, -- Entry count zeroCLit, -- Allocs zeroCLit -- Link ] } where name = closureName cl_info ticky_ctr_label = mkRednCountsLabel name arg_descr = map (showTypeCategory . idType) args fun_descr mod_name = ppr_for_ticky_name mod_name name -- When printing the name of a thing in a ticky file, we want to -- give the module name even for *local* things. We print -- just "x (M)" rather that "M.x" to distinguish them from the global kind. ppr_for_ticky_name mod_name name | isInternalName name = showSDocDebug (ppr name <+> (parens (ppr mod_name))) | otherwise = showSDocDebug (ppr name) -- ----------------------------------------------------------------------------- -- Ticky stack frames tickyPushUpdateFrame = ifTicky $ bumpTickyCounter SLIT("UPDF_PUSHED_ctr") tickyUpdateFrameOmitted = ifTicky $ bumpTickyCounter SLIT("UPDF_OMITTED_ctr") -- ----------------------------------------------------------------------------- -- Ticky entries tickyEnterDynCon = ifTicky $ bumpTickyCounter SLIT("ENT_DYN_CON_ctr") tickyEnterDynThunk = ifTicky $ bumpTickyCounter SLIT("ENT_DYN_THK_ctr") tickyEnterStaticCon = ifTicky $ bumpTickyCounter SLIT("ENT_STATIC_CON_ctr") tickyEnterStaticThunk = ifTicky $ bumpTickyCounter SLIT("ENT_STATIC_THK_ctr") tickyEnterViaNode = ifTicky $ bumpTickyCounter SLIT("ENT_VIA_NODE_ctr") tickyEnterThunk :: ClosureInfo -> Code tickyEnterThunk cl_info | isStaticClosure cl_info = tickyEnterStaticThunk | otherwise = tickyEnterDynThunk tickyBlackHole :: Bool{-updatable-} -> Code tickyBlackHole updatable = ifTicky (bumpTickyCounter ctr) where ctr | updatable = SLIT("UPD_BH_SINGLE_ENTRY_ctr") | otherwise = SLIT("UPD_BH_UPDATABLE_ctr") tickyUpdateBhCaf cl_info = ifTicky (bumpTickyCounter ctr) where ctr | closureUpdReqd cl_info = SLIT("UPD_CAF_BH_SINGLE_ENTRY_ctr") | otherwise = SLIT("UPD_CAF_BH_UPDATABLE_ctr") tickyEnterFun :: ClosureInfo -> Code tickyEnterFun cl_info = ifTicky $ do { bumpTickyCounter ctr ; fun_ctr_lbl <- getTickyCtrLabel ; registerTickyCtr fun_ctr_lbl ; bumpTickyCounter' fun_ctr_lbl } where ctr | isStaticClosure cl_info = SLIT("TICK_ENT_STATIC_FUN_DIRECT") | otherwise = SLIT("TICK_ENT_DYN_FUN_DIRECT") registerTickyCtr :: CLabel -> Code -- Register a ticky counter -- if ( ! f_ct.registeredp ) { -- f_ct.link = ticky_entry_ctrs; /* hook this one onto the front of the list */ -- ticky_entry_ctrs = & (f_ct); /* mark it as "registered" */ -- f_ct.registeredp = 1 } registerTickyCtr ctr_lbl = emitIf test (stmtsC register_stmts) where test = CmmMachOp (MO_Not I16) [CmmLoad (CmmLit (cmmLabelOffB ctr_lbl oFFSET_StgEntCounter_registeredp)) I16] register_stmts = [ CmmStore (CmmLit (cmmLabelOffB ctr_lbl oFFSET_StgEntCounter_link)) (CmmLoad ticky_entry_ctrs wordRep) , CmmStore ticky_entry_ctrs (mkLblExpr ctr_lbl) , CmmStore (CmmLit (cmmLabelOffB ctr_lbl oFFSET_StgEntCounter_registeredp)) (CmmLit (mkIntCLit 1)) ] ticky_entry_ctrs = mkLblExpr (mkRtsDataLabel SLIT("ticky_entry_ctrs")) tickyReturnOldCon, tickyReturnNewCon :: Arity -> Code tickyReturnOldCon arity = ifTicky $ do { bumpTickyCounter SLIT("RET_OLD_ctr") ; bumpHistogram SLIT("RET_OLD_hst") arity } tickyReturnNewCon arity | not opt_DoTickyProfiling = nopC | otherwise = ifTicky $ do { bumpTickyCounter SLIT("RET_NEW_ctr") ; bumpHistogram SLIT("RET_NEW_hst") arity } tickyUnboxedTupleReturn :: Int -> Code tickyUnboxedTupleReturn arity = ifTicky $ do { bumpTickyCounter SLIT("RET_UNBOXED_TUP_ctr") ; bumpHistogram SLIT("RET_UNBOXED_TUP_hst") arity } tickyVectoredReturn :: Int -> Code tickyVectoredReturn family_size = ifTicky $ do { bumpTickyCounter SLIT("VEC_RETURN_ctr") ; bumpHistogram SLIT("RET_VEC_RETURN_hst") family_size } -- ----------------------------------------------------------------------------- -- Ticky calls -- Ticks at a *call site*: tickyKnownCallTooFewArgs = ifTicky $ bumpTickyCounter SLIT("KNOWN_CALL_TOO_FEW_ARGS_ctr") tickyKnownCallExact = ifTicky $ bumpTickyCounter SLIT("KNOWN_CALL_ctr") tickyKnownCallExtraArgs = ifTicky $ bumpTickyCounter SLIT("KNOWN_CALL_EXTRA_ctr") tickyUnknownCall = ifTicky $ bumpTickyCounter SLIT("UNKNOWN_CALL_ctr") -- Tick for the call pattern at slow call site (i.e. in addition to -- tickyUnknownCall, tickyKnownCallExtraArgs, etc.) tickySlowCallPat :: [CgRep] -> Code tickySlowCallPat args = return () {- LATER: (introduces recursive module dependency now). case callPattern args of (str, True) -> bumpTickyCounter' (mkRtsSlowTickyCtrLabel pat) (str, False) -> bumpTickyCounter SLIT("TICK_SLOW_CALL_OTHER") callPattern :: [CgRep] -> (String,Bool) callPattern reps | match == length reps = (chars, True) | otherwise = (chars, False) where (_,match) = findMatch reps chars = map argChar reps argChar VoidArg = 'v' argChar PtrArg = 'p' argChar NonPtrArg = 'n' argChar LongArg = 'l' argChar FloatArg = 'f' argChar DoubleArg = 'd' -} -- ----------------------------------------------------------------------------- -- Ticky allocation tickyDynAlloc :: ClosureInfo -> Code -- Called when doing a dynamic heap allocation tickyDynAlloc cl_info = ifTicky $ case smRepClosureType (closureSMRep cl_info) of Constr -> tick_alloc_con ConstrNoCaf -> tick_alloc_con Fun -> tick_alloc_fun Thunk -> tick_alloc_thk ThunkSelector -> tick_alloc_thk where -- will be needed when we fill in stubs cl_size = closureSize cl_info slop_size = slopSize cl_info tick_alloc_thk | closureUpdReqd cl_info = tick_alloc_up_thk | otherwise = tick_alloc_se_thk tick_alloc_con = panic "ToDo: tick_alloc" tick_alloc_fun = panic "ToDo: tick_alloc" tick_alloc_up_thk = panic "ToDo: tick_alloc" tick_alloc_se_thk = panic "ToDo: tick_alloc" tickyAllocPrim :: CmmExpr -> CmmExpr -> CmmExpr -> Code tickyAllocPrim hdr goods slop = ifTicky $ panic "ToDo: tickyAllocPrim" tickyAllocThunk :: CmmExpr -> CmmExpr -> Code tickyAllocThunk goods slop = ifTicky $ panic "ToDo: tickyAllocThunk" tickyAllocPAP :: CmmExpr -> CmmExpr -> Code tickyAllocPAP goods slop = ifTicky $ panic "ToDo: tickyAllocPAP" tickyAllocHeap :: VirtualHpOffset -> Code -- Called when doing a heap check [TICK_ALLOC_HEAP] tickyAllocHeap hp = ifTicky $ do { ticky_ctr <- getTickyCtrLabel ; stmtsC $ if hp == 0 then [] -- Inside the stmtC to avoid control else [ -- dependency on the argument -- Bump the allcoation count in the StgEntCounter addToMem REP_StgEntCounter_allocs (CmmLit (cmmLabelOffB ticky_ctr oFFSET_StgEntCounter_allocs)) hp, -- Bump ALLOC_HEAP_ctr addToMemLbl cLongRep (mkRtsDataLabel SLIT("ALLOC_HEAP_ctr")) 1, -- Bump ALLOC_HEAP_tot addToMemLbl cLongRep (mkRtsDataLabel SLIT("ALLOC_HEAP_tot")) hp] } -- ----------------------------------------------------------------------------- -- Ticky utils ifTicky :: Code -> Code ifTicky code | opt_DoTickyProfiling = code | otherwise = nopC addToMemLbl :: MachRep -> CLabel -> Int -> CmmStmt addToMemLbl rep lbl n = addToMem rep (CmmLit (CmmLabel lbl)) n -- All the ticky-ticky counters are declared "unsigned long" in C bumpTickyCounter :: LitString -> Code bumpTickyCounter lbl = bumpTickyCounter' (mkRtsDataLabel lbl) bumpTickyCounter' :: CLabel -> Code bumpTickyCounter' lbl = stmtC (addToMemLbl cLongRep lbl 1) addToMemLong = addToMem cLongRep bumpHistogram :: LitString -> Int -> Code bumpHistogram lbl n = bumpHistogramE lbl (CmmLit (CmmInt (fromIntegral n) cLongRep)) bumpHistogramE :: LitString -> CmmExpr -> Code bumpHistogramE lbl n = do t <- newTemp cLongRep stmtC (CmmAssign t n) emitIf (CmmMachOp (MO_U_Le cLongRep) [CmmReg t, eight]) $ stmtC (CmmAssign t eight) stmtC (addToMemLong (cmmIndexExpr cLongRep (CmmLit (CmmLabel (mkRtsDataLabel lbl))) (CmmReg t)) 1) where eight = CmmLit (CmmInt 8 cLongRep) ------------------------------------------------------------------ -- Showing the "type category" for ticky-ticky profiling showTypeCategory :: Type -> Char {- {C,I,F,D} char, int, float, double T tuple S other single-constructor type {c,i,f,d} unboxed ditto t *unpacked* tuple s *unpacked" single-cons... v void# a primitive array E enumeration type + dictionary, unless it's a ... L List > function M other (multi-constructor) data-con type . other type - reserved for others to mark as "uninteresting" -} showTypeCategory ty = if isDictTy ty then '+' else case tcSplitTyConApp_maybe ty of Nothing -> if isJust (tcSplitFunTy_maybe ty) then '>' else '.' Just (tycon, _) -> let utc = getUnique tycon in if utc == charDataConKey then 'C' else if utc == intDataConKey then 'I' else if utc == floatDataConKey then 'F' else if utc == doubleDataConKey then 'D' else if utc == smallIntegerDataConKey || utc == largeIntegerDataConKey then 'J' else if utc == charPrimTyConKey then 'c' else if (utc == intPrimTyConKey || utc == wordPrimTyConKey || utc == addrPrimTyConKey) then 'i' else if utc == floatPrimTyConKey then 'f' else if utc == doublePrimTyConKey then 'd' else if isPrimTyCon tycon {- array, we hope -} then 'A' -- Bogus else if isEnumerationTyCon tycon then 'E' else if isTupleTyCon tycon then 'T' else if isJust (maybeTyConSingleCon tycon) then 'S' else if utc == listTyConKey then 'L' else 'M' -- oh, well...