Reorganisation of the source tree
[ghc-hetmet.git] / compiler / codeGen / CgTicky.hs
diff --git a/compiler/codeGen/CgTicky.hs b/compiler/codeGen/CgTicky.hs
new file mode 100644 (file)
index 0000000..3e72981
--- /dev/null
@@ -0,0 +1,370 @@
+-----------------------------------------------------------------------------
+--
+-- 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...