From 188221a90c7a054d390ddaa534d391f6370ac6bc Mon Sep 17 00:00:00 2001 From: Monty Brandenberg Date: Tue, 9 Apr 2013 23:44:59 +0000 Subject: SH-4088 Deadman timer switch started in llcommon. Unit test started. Will be used for mesh, inventory, etc., operation markers. --- indra/llcommon/lldeadmantimer.h | 171 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 indra/llcommon/lldeadmantimer.h (limited to 'indra/llcommon/lldeadmantimer.h') diff --git a/indra/llcommon/lldeadmantimer.h b/indra/llcommon/lldeadmantimer.h new file mode 100644 index 0000000000..84023723ab --- /dev/null +++ b/indra/llcommon/lldeadmantimer.h @@ -0,0 +1,171 @@ +/** +* @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" + + +/// @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: + /// 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. + /// + LLDeadmanTimer(F64 horizon); + + ~LLDeadmanTimer() + {} + +private: + LLDeadmanTimer(const LLDeadmanTimer &); // Not defined + void operator=(const LLDeadmanTimer &); // Not defined + +public: + /// 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(U64 now = U64L(0)); + + + /// 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(U64 now = U64L(0)); + + + /// 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. + /// 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. + /// + void ringBell(U64 now = U64L(0)); + + + /// Checks on the status of the timer 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. + /// This count is returned via the @see isExpired() method. + /// + /// @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 now Current time as returned by @see + /// LLTimer::getCurrentClockCount(). If zero, + /// method will lookup current time. + /// + /// @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(F64 & started, F64 & stopped, U64 & count, U64 now = U64L(0)); + +protected: + U64 mHorizon; + bool mActive; + bool mDone; + U64 mStarted; + U64 mExpires; + U64 mStopped; + U64 mCount; +}; + + +#endif // LL_DEADMANTIMER_H -- cgit v1.2.3 From e59d59878200d25dc6e94753026d986d2704ab8d Mon Sep 17 00:00:00 2001 From: Monty Brandenberg Date: Wed, 17 Apr 2013 18:30:46 -0400 Subject: SH-4090 Integrating deadman timer with mesh repo downloads. Timer interface violated my design rules and I paid for it with clumsiness and silent errors. Cleaned it up mainly removing the evil default values. Found better integration points in the mesh downloader and it's producing fairly consistent numbers on the MeshTest2 test region (about 5500 downloads, ~90 seconds, +/- 10 seconds). Will review with davep and do an early timer stop on teleport which invalidates a timing sequence. --- indra/llcommon/lldeadmantimer.h | 59 ++++++++++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 18 deletions(-) (limited to 'indra/llcommon/lldeadmantimer.h') diff --git a/indra/llcommon/lldeadmantimer.h b/indra/llcommon/lldeadmantimer.h index 84023723ab..8643b8cad8 100644 --- a/indra/llcommon/lldeadmantimer.h +++ b/indra/llcommon/lldeadmantimer.h @@ -76,6 +76,16 @@ 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 /// @@ -93,6 +103,18 @@ private: 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. /// @@ -100,8 +122,7 @@ public: /// LLTimer::getCurrentClockCount(). If zero, /// method will lookup current time. /// - void start(U64 now = U64L(0)); - + 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 @@ -111,28 +132,34 @@ public: /// LLTimer::getCurrentClockCount(). If zero, /// method will lookup current time. /// - void stop(U64 now = U64L(0)); - + 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. - /// This count is returned via the @see isExpired() method. + /// 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. /// - void ringBell(U64 now = U64L(0)); + /// @param count Count of events to be associated with + /// this bell ringing. + /// + void ringBell(time_type now, unsigned int count); - /// Checks on the status of the timer 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. /// 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 started If expired, the starting time of the event is /// returned to the caller via this reference. /// @@ -146,25 +173,21 @@ public: /// @param count If expired, the number of ringBell() calls /// made prior to expiration. /// - /// @param now Current time as returned by @see - /// LLTimer::getCurrentClockCount(). If zero, - /// method will lookup current time. - /// /// @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(F64 & started, F64 & stopped, U64 & count, U64 now = U64L(0)); + bool isExpired(time_type now, F64 & started, F64 & stopped, U64 & count); protected: - U64 mHorizon; + time_type mHorizon; bool mActive; bool mDone; - U64 mStarted; - U64 mExpires; - U64 mStopped; - U64 mCount; + time_type mStarted; + time_type mExpires; + time_type mStopped; + time_type mCount; }; -- cgit v1.2.3 From 11cca95187f01f594172ca950315dcd8d99dc2c3 Mon Sep 17 00:00:00 2001 From: Monty Brandenberg Date: Thu, 2 May 2013 21:59:53 +0000 Subject: SH-4161 Integrate cpu metrics into LLDeadmanTimer and then metrics viewer Integrated as a ctor-time option to LLDeadmanTimer and have mesh use this mode for the stats I'm gathering. --- indra/llcommon/lldeadmantimer.h | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) (limited to 'indra/llcommon/lldeadmantimer.h') diff --git a/indra/llcommon/lldeadmantimer.h b/indra/llcommon/lldeadmantimer.h index 8643b8cad8..a6022852b9 100644 --- a/indra/llcommon/lldeadmantimer.h +++ b/indra/llcommon/lldeadmantimer.h @@ -32,6 +32,7 @@ #include "linden_common.h" #include "lltimer.h" +#include "llprocinfo.h" /// @file lldeadmantimer.h @@ -93,7 +94,11 @@ public: /// call at which point the timer will consider itself /// expired. /// - LLDeadmanTimer(F64 horizon); + /// @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() {} @@ -173,21 +178,38 @@ public: /// @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, + LLProcInfo::time_type & user_cpu, LLProcInfo::time_type & sys_cpu); + + /// Identical to the six-arugment form except is 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; + 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; }; -- cgit v1.2.3 From 960139aa6f02f90c6102d3c5d5c38b5ebe689f9c Mon Sep 17 00:00:00 2001 From: Monty Brandenberg Date: Thu, 2 May 2013 19:12:59 -0400 Subject: SH-4161 Integrate cpu metrics into LLDeadmanTimer and then metrics viewer Normalize deadman timer's args on U64/F64. Internals remain the same. Modify mesh to collect and output enhanced CPU metrics. --- indra/llcommon/lldeadmantimer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/llcommon/lldeadmantimer.h') diff --git a/indra/llcommon/lldeadmantimer.h b/indra/llcommon/lldeadmantimer.h index a6022852b9..0dde16b717 100644 --- a/indra/llcommon/lldeadmantimer.h +++ b/indra/llcommon/lldeadmantimer.h @@ -190,7 +190,7 @@ public: /// left unchanged. /// bool isExpired(time_type now, F64 & started, F64 & stopped, U64 & count, - LLProcInfo::time_type & user_cpu, LLProcInfo::time_type & sys_cpu); + U64 & user_cpu, U64 & sys_cpu); /// Identical to the six-arugment form except is does without the /// CPU time return if the caller isn't interested in it. -- cgit v1.2.3 From b2d769534c82de2ac7b36f11ce6fab61f3e0d378 Mon Sep 17 00:00:00 2001 From: Monty Brandenberg Date: Mon, 18 Nov 2013 13:33:19 -0500 Subject: Code review updates. All comments so far. --- indra/llcommon/lldeadmantimer.h | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'indra/llcommon/lldeadmantimer.h') diff --git a/indra/llcommon/lldeadmantimer.h b/indra/llcommon/lldeadmantimer.h index 0dde16b717..980976e176 100644 --- a/indra/llcommon/lldeadmantimer.h +++ b/indra/llcommon/lldeadmantimer.h @@ -155,11 +155,9 @@ public: /// void ringBell(time_type now, unsigned int count); - /// Checks on the status of the timer 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. - /// This count is returned via the @see isExpired() method. + /// 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, @@ -192,7 +190,7 @@ public: bool isExpired(time_type now, F64 & started, F64 & stopped, U64 & count, U64 & user_cpu, U64 & sys_cpu); - /// Identical to the six-arugment form except is does without the + /// 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); -- cgit v1.2.3