Newer
Older
/**
* @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"
Monty Brandenberg
committed
#include "llprocinfo.h"
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
/// @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.
///
Monty Brandenberg
committed
/// @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);
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.
///
Monty Brandenberg
committed
/// @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.
///
Monty Brandenberg
committed
bool isExpired(time_type now, F64 & started, F64 & stopped, U64 & count,
Monty Brandenberg
committed
U64 & user_cpu, U64 & sys_cpu);
Monty Brandenberg
committed
/// Identical to the six-arugment form except it does without the
Monty Brandenberg
committed
/// CPU time return if the caller isn't interested in it.
bool isExpired(time_type now, F64 & started, F64 & stopped, U64 & count);
protected:
Monty Brandenberg
committed
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