/* ----------------------------------------------------------------------------- * * (c) The GHC Team, 1998-1999 * * Profiling interval timer * * ---------------------------------------------------------------------------*/ #include "rts/PosixSource.h" #include "Rts.h" #include "Profiling.h" #include "Proftimer.h" #include "Capability.h" #include "Trace.h" /* * N.B. These flags must all always be accessed via atomics since even in the * non-threaded runtime the timer may be provided by way of a signal. */ #if defined(PROFILING) static bool do_prof_ticks = false; // enable profiling ticks #endif static bool do_heap_prof_ticks = false; // Whether the timer is currently ticking down static bool heap_prof_timer_active = false; // Whether the timer is enabled at all /* The heap_prof_timer_active flag controls whether heap profiling is enabled at all, once it is enabled, the `do_heap_prof_ticks` flag controls whether the counter is currently counting down. This is paused, for example, in Schedule.c. */ // Sampling of Ticky-Ticky profiler to eventlog #if defined(TICKY_TICKY) && defined(TRACING) static int ticks_to_ticky_sample = 0; bool performTickySample = false; #endif // Number of ticks until next heap census static int ticks_to_heap_profile; // Time for a heap profile on the next context switch bool performHeapProfile; void stopProfTimer( void ) { #if defined(PROFILING) RELAXED_STORE_ALWAYS(&do_prof_ticks, false); #endif } void startProfTimer( void ) { #if defined(PROFILING) RELAXED_STORE_ALWAYS(&do_prof_ticks, true); #endif } void stopHeapProfTimer( void ) { if (RtsFlags.ProfFlags.doHeapProfile){ RELAXED_STORE_ALWAYS(&heap_prof_timer_active, false); pauseHeapProfTimer(); } } void startHeapProfTimer( void ) { if (RtsFlags.ProfFlags.doHeapProfile){ RELAXED_STORE_ALWAYS(&heap_prof_timer_active, true); resumeHeapProfTimer(); } } void pauseHeapProfTimer ( void ) { RELAXED_STORE_ALWAYS(&do_heap_prof_ticks, false); } void resumeHeapProfTimer ( void ) { if (RtsFlags.ProfFlags.doHeapProfile && RtsFlags.ProfFlags.heapProfileIntervalTicks > 0) { RELAXED_STORE_ALWAYS(&do_heap_prof_ticks, true); } } void requestHeapCensus( void ){ // If no profiling mode is passed then just ignore the call. if (RtsFlags.ProfFlags.doHeapProfile){ RELAXED_STORE_ALWAYS(&performHeapProfile, true); } } void initProfTimer( void ) { performHeapProfile = false; ticks_to_heap_profile = RtsFlags.ProfFlags.heapProfileIntervalTicks; /* This might look a bit strange but the heap profile timer can be toggled on/off from within Haskell by calling the startHeapProf function from within Haskell */ if (RtsFlags.ProfFlags.startHeapProfileAtStartup){ startHeapProfTimer(); } } uint32_t total_ticks = 0; void handleProfTick(void) { #if defined(PROFILING) total_ticks++; if (RELAXED_LOAD_ALWAYS(&do_prof_ticks)) { uint32_t n; for (n=0; n < getNumCapabilities(); n++) { Capability *cap = getCapability(n); cap->r.rCCCS->time_ticks++; traceProfSampleCostCentre(cap, cap->r.rCCCS, total_ticks); } } #endif #if defined(TICKY_TICKY) && defined(TRACING) if (RtsFlags.TraceFlags.ticky) { ticks_to_ticky_sample--; if (ticks_to_ticky_sample <= 0) { ticks_to_ticky_sample = RtsFlags.ProfFlags.heapProfileIntervalTicks; performTickySample = true; } } #endif if (RELAXED_LOAD_ALWAYS(&do_heap_prof_ticks) && RELAXED_LOAD_ALWAYS(&heap_prof_timer_active)) { ticks_to_heap_profile--; if (ticks_to_heap_profile <= 0) { ticks_to_heap_profile = RtsFlags.ProfFlags.heapProfileIntervalTicks; performHeapProfile = true; } } }