summaryrefslogtreecommitdiff
path: root/rts/Proftimer.c
blob: 22ef1c417182e2c2a28c25ed7c37d1c3ad87515f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/* -----------------------------------------------------------------------------
 *
 * (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;
        }
    }
}