1 -----------------------------------------------------------------------------
3 -- Code generation for ticky-ticky profiling
5 -- (c) The University of Glasgow 2004-2006
7 -----------------------------------------------------------------------------
19 tickyUpdateFrameOmitted,
30 tickyUnboxedTupleReturn, tickyVectoredReturn,
31 tickyReturnOldCon, tickyReturnNewCon,
33 tickyKnownCallTooFewArgs, tickyKnownCallExact, tickyKnownCallExtraArgs,
34 tickyUnknownCall, tickySlowCallPat,
39 #include "HsVersions.h"
40 #include "../includes/DerivedConstants.h"
41 -- For REP_xxx constants, which are MachReps
61 -- Turgid imports for showTypeCategory
68 -----------------------------------------------------------------------------
70 -- Ticky-ticky profiling
72 -----------------------------------------------------------------------------
74 staticTickyHdr :: [CmmLit]
75 -- krc: not using this right now --
76 -- in the new version of ticky-ticky, we
77 -- don't change the closure layout.
78 -- leave it defined, though, to avoid breaking
82 emitTickyCounter :: ClosureInfo -> [Id] -> Int -> Code
83 emitTickyCounter cl_info args on_stk
85 do { mod_name <- getModuleName
86 ; fun_descr_lit <- mkStringCLit (fun_descr mod_name)
87 ; arg_descr_lit <- mkStringCLit arg_descr
88 ; emitDataLits ticky_ctr_label -- Must match layout of StgEntCounter
89 -- krc: note that all the fields are I32 now; some were I16 before,
90 -- but the code generator wasn't handling that properly and it led to chaos,
91 -- panic and disorder.
93 mkIntCLit (length args),-- Arity
94 mkIntCLit on_stk, -- Words passed on stack
97 zeroCLit, -- Entry count
102 name = closureName cl_info
103 ticky_ctr_label = mkRednCountsLabel name
104 arg_descr = map (showTypeCategory . idType) args
105 fun_descr mod_name = ppr_for_ticky_name mod_name name
107 -- When printing the name of a thing in a ticky file, we want to
108 -- give the module name even for *local* things. We print
109 -- just "x (M)" rather that "M.x" to distinguish them from the global kind.
110 ppr_for_ticky_name mod_name name
111 | isInternalName name = showSDocDebug (ppr name <+> (parens (ppr mod_name)))
112 | otherwise = showSDocDebug (ppr name)
114 -- -----------------------------------------------------------------------------
115 -- Ticky stack frames
117 tickyPushUpdateFrame = ifTicky $ bumpTickyCounter SLIT("UPDF_PUSHED_ctr")
118 tickyUpdateFrameOmitted = ifTicky $ bumpTickyCounter SLIT("UPDF_OMITTED_ctr")
120 -- -----------------------------------------------------------------------------
123 tickyEnterDynCon = ifTicky $ bumpTickyCounter SLIT("ENT_DYN_CON_ctr")
124 tickyEnterDynThunk = ifTicky $ bumpTickyCounter SLIT("ENT_DYN_THK_ctr")
125 tickyEnterStaticCon = ifTicky $ bumpTickyCounter SLIT("ENT_STATIC_CON_ctr")
126 tickyEnterStaticThunk = ifTicky $ bumpTickyCounter SLIT("ENT_STATIC_THK_ctr")
127 tickyEnterViaNode = ifTicky $ bumpTickyCounter SLIT("ENT_VIA_NODE_ctr")
129 tickyEnterThunk :: ClosureInfo -> Code
130 tickyEnterThunk cl_info
131 | isStaticClosure cl_info = tickyEnterStaticThunk
132 | otherwise = tickyEnterDynThunk
134 tickyBlackHole :: Bool{-updatable-} -> Code
135 tickyBlackHole updatable
136 = ifTicky (bumpTickyCounter ctr)
138 ctr | updatable = SLIT("UPD_BH_SINGLE_ENTRY_ctr")
139 | otherwise = SLIT("UPD_BH_UPDATABLE_ctr")
141 tickyUpdateBhCaf cl_info
142 = ifTicky (bumpTickyCounter ctr)
144 ctr | closureUpdReqd cl_info = SLIT("UPD_CAF_BH_SINGLE_ENTRY_ctr")
145 | otherwise = SLIT("UPD_CAF_BH_UPDATABLE_ctr")
147 tickyEnterFun :: ClosureInfo -> Code
148 tickyEnterFun cl_info
150 do { bumpTickyCounter ctr
151 ; fun_ctr_lbl <- getTickyCtrLabel
152 ; registerTickyCtr fun_ctr_lbl
153 ; bumpTickyCounter' (cmmLabelOffB fun_ctr_lbl oFFSET_StgEntCounter_entry_count)
156 ctr | isStaticClosure cl_info = SLIT("ENT_STATIC_FUN_DIRECT_ctr")
157 | otherwise = SLIT("ENT_DYN_FUN_DIRECT_ctr")
159 registerTickyCtr :: CLabel -> Code
160 -- Register a ticky counter
161 -- if ( ! f_ct.registeredp ) {
162 -- f_ct.link = ticky_entry_ctrs; /* hook this one onto the front of the list */
163 -- ticky_entry_ctrs = & (f_ct); /* mark it as "registered" */
164 -- f_ct.registeredp = 1 }
165 registerTickyCtr ctr_lbl
166 = emitIf test (stmtsC register_stmts)
168 -- krc: code generator doesn't handle Not, so we test for Eq 0 instead
169 test = CmmMachOp (MO_Eq wordRep)
170 [CmmLoad (CmmLit (cmmLabelOffB ctr_lbl
171 oFFSET_StgEntCounter_registeredp)) wordRep,
172 CmmLit (mkIntCLit 0)]
174 = [ CmmStore (CmmLit (cmmLabelOffB ctr_lbl oFFSET_StgEntCounter_link))
175 (CmmLoad ticky_entry_ctrs wordRep)
176 , CmmStore ticky_entry_ctrs (mkLblExpr ctr_lbl)
177 , CmmStore (CmmLit (cmmLabelOffB ctr_lbl
178 oFFSET_StgEntCounter_registeredp))
179 (CmmLit (mkIntCLit 1)) ]
180 ticky_entry_ctrs = mkLblExpr (mkRtsDataLabel SLIT("ticky_entry_ctrs"))
182 tickyReturnOldCon, tickyReturnNewCon :: Arity -> Code
183 tickyReturnOldCon arity
184 = ifTicky $ do { bumpTickyCounter SLIT("RET_OLD_ctr")
185 ; bumpHistogram SLIT("RET_OLD_hst") arity }
186 tickyReturnNewCon arity
187 | not opt_DoTickyProfiling = nopC
189 = ifTicky $ do { bumpTickyCounter SLIT("RET_NEW_ctr")
190 ; bumpHistogram SLIT("RET_NEW_hst") arity }
192 tickyUnboxedTupleReturn :: Int -> Code
193 tickyUnboxedTupleReturn arity
194 = ifTicky $ do { bumpTickyCounter SLIT("RET_UNBOXED_TUP_ctr")
195 ; bumpHistogram SLIT("RET_UNBOXED_TUP_hst") arity }
197 tickyVectoredReturn :: Int -> Code
198 tickyVectoredReturn family_size
199 = ifTicky $ do { bumpTickyCounter SLIT("VEC_RETURN_ctr")
200 ; bumpHistogram SLIT("RET_VEC_RETURN_hst") family_size }
202 -- -----------------------------------------------------------------------------
205 -- Ticks at a *call site*:
206 tickyKnownCallTooFewArgs = ifTicky $ bumpTickyCounter SLIT("KNOWN_CALL_TOO_FEW_ARGS_ctr")
207 tickyKnownCallExact = ifTicky $ bumpTickyCounter SLIT("KNOWN_CALL_ctr")
208 tickyKnownCallExtraArgs = ifTicky $ bumpTickyCounter SLIT("KNOWN_CALL_EXTRA_ARGS_ctr")
209 tickyUnknownCall = ifTicky $ bumpTickyCounter SLIT("UNKNOWN_CALL_ctr")
211 -- Tick for the call pattern at slow call site (i.e. in addition to
212 -- tickyUnknownCall, tickyKnownCallExtraArgs, etc.)
213 tickySlowCallPat :: [CgRep] -> Code
214 tickySlowCallPat args = return ()
215 {- LATER: (introduces recursive module dependency now).
216 case callPattern args of
217 (str, True) -> bumpTickyCounter' (mkRtsSlowTickyCtrLabel pat)
218 (str, False) -> bumpTickyCounter SLIT("TICK_SLOW_CALL_OTHER")
220 callPattern :: [CgRep] -> (String,Bool)
222 | match == length reps = (chars, True)
223 | otherwise = (chars, False)
224 where (_,match) = findMatch reps
225 chars = map argChar reps
227 argChar VoidArg = 'v'
229 argChar NonPtrArg = 'n'
230 argChar LongArg = 'l'
231 argChar FloatArg = 'f'
232 argChar DoubleArg = 'd'
235 -- -----------------------------------------------------------------------------
238 tickyDynAlloc :: ClosureInfo -> Code
239 -- Called when doing a dynamic heap allocation
240 tickyDynAlloc cl_info
242 case smRepClosureType (closureSMRep cl_info) of
243 Just Constr -> tick_alloc_con
244 Just ConstrNoCaf -> tick_alloc_con
245 Just Fun -> tick_alloc_fun
246 Just Thunk -> tick_alloc_thk
247 Just ThunkSelector -> tick_alloc_thk
251 -- will be needed when we fill in stubs
252 cl_size = closureSize cl_info
253 slop_size = slopSize cl_info
256 | closureUpdReqd cl_info = tick_alloc_up_thk
257 | otherwise = tick_alloc_se_thk
259 -- krc: changed from panic to return ()
260 -- just to get something working
261 tick_alloc_con = return ()
262 tick_alloc_fun = return ()
263 tick_alloc_up_thk = return ()
264 tick_alloc_se_thk = return ()
267 tickyAllocPrim :: CmmExpr -> CmmExpr -> CmmExpr -> Code
268 tickyAllocPrim hdr goods slop = ifTicky $ pprTrace "ToDo: tickyAllocPrim" empty (return ())
270 tickyAllocThunk :: CmmExpr -> CmmExpr -> Code
271 tickyAllocThunk goods slop = ifTicky $ pprTrace "ToDo: tickyAllocThunk" empty (return ())
273 tickyAllocPAP :: CmmExpr -> CmmExpr -> Code
274 tickyAllocPAP goods slop = ifTicky $ pprTrace "ToDo: tickyAllocPAP" empty (return ())
276 tickyAllocHeap :: VirtualHpOffset -> Code
277 -- Called when doing a heap check [TICK_ALLOC_HEAP]
280 do { ticky_ctr <- getTickyCtrLabel
282 if hp == 0 then [] -- Inside the stmtC to avoid control
283 else [ -- dependency on the argument
284 -- Bump the allcoation count in the StgEntCounter
285 addToMem REP_StgEntCounter_allocs
286 (CmmLit (cmmLabelOffB ticky_ctr
287 oFFSET_StgEntCounter_allocs)) hp,
288 -- Bump ALLOC_HEAP_ctr
289 addToMemLbl cLongRep (mkRtsDataLabel SLIT("ALLOC_HEAP_ctr")) 1,
290 -- Bump ALLOC_HEAP_tot
291 addToMemLbl cLongRep (mkRtsDataLabel SLIT("ALLOC_HEAP_tot")) hp] }
293 -- -----------------------------------------------------------------------------
296 ifTicky :: Code -> Code
298 | opt_DoTickyProfiling = code
301 addToMemLbl :: MachRep -> CLabel -> Int -> CmmStmt
302 addToMemLbl rep lbl n = addToMem rep (CmmLit (CmmLabel lbl)) n
304 -- All the ticky-ticky counters are declared "unsigned long" in C
305 bumpTickyCounter :: LitString -> Code
306 bumpTickyCounter lbl = bumpTickyCounter' (cmmLabelOffB (mkRtsDataLabel lbl) 0)
308 bumpTickyCounter' :: CmmLit -> Code
309 -- krc: note that we're incrementing the _entry_count_ field of the ticky counter
310 bumpTickyCounter' lhs = stmtC (addToMem cLongRep (CmmLit lhs) 1)
312 addToMemLong = addToMem cLongRep
314 bumpHistogram :: LitString -> Int -> Code
316 -- = bumpHistogramE lbl (CmmLit (CmmInt (fromIntegral n) cLongRep))
317 = return () -- TEMP SPJ Apr 07
319 bumpHistogramE :: LitString -> CmmExpr -> Code
321 = do t <- newTemp cLongRep
322 stmtC (CmmAssign t n)
323 emitIf (CmmMachOp (MO_U_Le cLongRep) [CmmReg t, eight]) $
324 stmtC (CmmAssign t eight)
325 stmtC (addToMemLong (cmmIndexExpr cLongRep
326 (CmmLit (CmmLabel (mkRtsDataLabel lbl)))
330 eight = CmmLit (CmmInt 8 cLongRep)
332 ------------------------------------------------------------------
333 -- Showing the "type category" for ticky-ticky profiling
335 showTypeCategory :: Type -> Char
336 {- {C,I,F,D} char, int, float, double
338 S other single-constructor type
339 {c,i,f,d} unboxed ditto
341 s *unpacked" single-cons...
347 + dictionary, unless it's a ...
350 M other (multi-constructor) data-con type
352 - reserved for others to mark as "uninteresting"
358 case tcSplitTyConApp_maybe ty of
359 Nothing -> if isJust (tcSplitFunTy_maybe ty)
364 let utc = getUnique tycon in
365 if utc == charDataConKey then 'C'
366 else if utc == intDataConKey then 'I'
367 else if utc == floatDataConKey then 'F'
368 else if utc == doubleDataConKey then 'D'
369 else if utc == smallIntegerDataConKey ||
370 utc == largeIntegerDataConKey then 'J'
371 else if utc == charPrimTyConKey then 'c'
372 else if (utc == intPrimTyConKey || utc == wordPrimTyConKey
373 || utc == addrPrimTyConKey) then 'i'
374 else if utc == floatPrimTyConKey then 'f'
375 else if utc == doublePrimTyConKey then 'd'
376 else if isPrimTyCon tycon {- array, we hope -} then 'A' -- Bogus
377 else if isEnumerationTyCon tycon then 'E'
378 else if isTupleTyCon tycon then 'T'
379 else if isJust (maybeTyConSingleCon tycon) then 'S'
380 else if utc == listTyConKey then 'L'
381 else 'M' -- oh, well...