summaryrefslogtreecommitdiff
path: root/indra/llcommon/lldeadmantimer.h
blob: 3f10420d41d0d8521be415d34e16a7979212f02c (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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
/**
* @file   lldeadmantimer.h
* @brief  Interface to a simple event timer with a deadman's switch
* @author monty@lindenlab.com
*
* $LicenseInfo:firstyear=2013&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2013, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
* $/LicenseInfo$
*/

#ifndef LL_DEADMANTIMER_H
#define LL_DEADMANTIMER_H


#include "linden_common.h"

#include "lltimer.h"
#include "llprocinfo.h"


/// @file lldeadmantimer.h
///
/// There are interesting user-experienced events in the viewer that
/// would seem to have well-defined start and stop points but which
/// actually lack such milestones in the code.  Such events (like
/// time to load meshes after logging in, initial inventory load,
/// display name fetch) can be defined somewhat after-the-fact by
/// noticing when we no longer perform operations towards their
/// completion.  This class is intended to help in such applications.
///
/// What it implements is a deadman's switch (also known as a
/// keepalive switch and a doorbell switch).  The basic operation is
/// as follows:
///
/// * LLDeadmanTimer is instantiated with a horizon value in seconds,
///   one for each event of interest.
/// * When an event starts, @see start() is invoked to begin a
///   timing operation.
/// * As operations are performed in service of the event (issuing
///   HTTP requests, receiving responses), @see ringBell() is invoked
///   to inform the timer that the operation is still active.
/// * If the operation is canceled or otherwise terminated, @see
///   stop() can be called to end the timing operation.
/// * Concurrent with the ringBell() calls, the program makes
///   periodic (shorter than the horizon but not too short) calls
///   to @see isExpired() to see if the event has expired due to
///   either a stop() call or lack of activity (defined as a ringBell()
///   call in the previous 'horizon' seconds).  If it has expired,
///   the caller also receives start, stop and count values for the
///   event which the application can then report in whatever manner
///   it sees fit.
/// * The timer becomes passive after an isExpired() call that returns
///   true.  It can then be restarted with a new start() call.
///
/// Threading:  Instances are not thread-safe.  They also use
/// timing code from lltimer.h which is also unsafe.
///
/// Allocation:  Not refcounted, may be stack or heap allocated.
///

class LL_COMMON_API LLDeadmanTimer
{
public:
    /// Public types

    /// Low-level time type chosen for compatibility with
    /// LLTimer::getCurrentClockCount() which is the basis
    /// of time operations in this class.  This is likely
    /// to change in a future version in a move to TSC-based
    /// timing.
    typedef U64 time_type;

public:
    /// Construct and initialize an LLDeadmanTimer
    ///
    /// @param horizon  Time, in seconds, after the last @see ringBell()
    ///                 call at which point the timer will consider itself
    ///                 expired.
    ///
    /// @param inc_cpu  If true, gather system and user cpu stats while
    ///                 running the timer.  This does require more syscalls
    ///                 during updates.  If false, cpu usage data isn't
    ///                 collected and will be zero if queried.
    LLDeadmanTimer(F64 horizon, bool inc_cpu);

    ~LLDeadmanTimer()
        {}

private:
    LLDeadmanTimer(const LLDeadmanTimer &);             // Not defined
    void operator=(const LLDeadmanTimer &);             // Not defined

public:
    /// Get the current time.  Zero-basis for this time
    /// representation is not defined and is different on
    /// different platforms.  Do not attempt to compute
    /// negative times relative to the first value returned,
    /// there may not be enough 'front porch' on the range
    /// to prevent wraparound.
    ///
    /// Note:  Implementation is expected to change in a
    /// future release as well.
    ///
    static time_type getNow();

    /// Begin timing.  If the timer is already active, it is reset
    /// and timing begins now.
    ///
    /// @param now      Current time as returned by @see
    ///                 LLTimer::getCurrentClockCount().  If zero,
    ///                 method will lookup current time.
    ///
    void start(time_type now);

    /// End timing.  Actively declare the end of the event independent
    /// of the deadman's switch operation.  @see isExpired() will return
    /// true and appropriate values will be returned.
    ///
    /// @param now      Current time as returned by @see
    ///                 LLTimer::getCurrentClockCount().  If zero,
    ///                 method will lookup current time.
    ///
    void stop(time_type now);

    /// Declare that something interesting happened.  This has two
    /// effects on an unexpired-timer.  1)  The expiration time
    /// is extended for 'horizon' seconds after the 'now' value.
    /// 2)  An internal counter associated with the event is incremented
    /// by the @ref count parameter.  This count is returned via the
    /// @see isExpired() method.
    ///
    /// @param now      Current time as returned by @see
    ///                 LLTimer::getCurrentClockCount().  If zero,
    ///                 method will lookup current time.
    ///
    /// @param count    Count of events to be associated with
    ///                 this bell ringing.
    ///
    void ringBell(time_type now, unsigned int count);

    /// Checks the status of the timer.  If the timer has expired,
    /// also returns various timer-related stats.  Unlike ringBell(),
    /// does not extend the horizon, it only checks for expiration.
    ///
    /// @param now      Current time as returned by @see
    ///                 LLTimer::getCurrentClockCount().  If zero,
    ///                 method will lookup current time.
    ///
    /// @param started  If expired, the starting time of the event is
    ///                 returned to the caller via this reference.
    ///
    /// @param stopped  If expired, the ending time of the event is
    ///                 returned to the caller via this reference.
    ///                 Ending time will be that provided in the
    ///                 stop() method or the last ringBell() call
    ///                 leading to expiration, whichever (stop() call
    ///                 or notice of expiration) happened first.
    ///
    /// @param count    If expired, the number of ringBell() calls
    ///                 made prior to expiration.
    ///
    /// @param user_cpu Amount of CPU spent in user mode by the process
    ///                 during the event.  Value in microseconds and will
    ///                 read zero if not enabled by the constructor.
    ///
    /// @param sys_cpu  Amount of CPU spent in system mode by the process.
    ///
    /// @return         true if the timer has expired, false otherwise.
    ///                 If true, it also returns the started,
    ///                 stopped and count values otherwise these are
    ///                 left unchanged.
    ///
    bool isExpired(time_type now, F64 & started, F64 & stopped, U64 & count,
                   U64 & user_cpu, U64 & sys_cpu);

    /// Identical to the six-arugment form except it does without the
    /// CPU time return if the caller isn't interested in it.
    bool isExpired(time_type now, F64 & started, F64 & stopped, U64 & count);

protected:
    time_type                   mHorizon;
    bool                        mActive;
    bool                        mDone;
    time_type                   mStarted;
    time_type                   mExpires;
    time_type                   mStopped;
    time_type                   mCount;

    const bool                  mIncCPU;        // Include CPU metrics in timer
    LLProcInfo::time_type       mUStartCPU;
    LLProcInfo::time_type       mUEndCPU;
    LLProcInfo::time_type       mSStartCPU;
    LLProcInfo::time_type       mSEndCPU;
};


#endif  // LL_DEADMANTIMER_H