summaryrefslogtreecommitdiff
path: root/indra/llcommon/llstat.h
blob: 5d77215bebbdd2006a6301e36dbff96847043c1d (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
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
/** 
 * @file llstat.h
 * @brief Runtime statistics accumulation.
 *
 * $LicenseInfo:firstyear=2001&license=viewergpl$
 * 
 * Copyright (c) 2001-2009, Linden Research, Inc.
 * 
 * Second Life Viewer Source Code
 * The source code in this file ("Source Code") is provided by Linden Lab
 * to you under the terms of the GNU General Public License, version 2.0
 * ("GPL"), unless you have obtained a separate licensing agreement
 * ("Other License"), formally executed by you and Linden Lab.  Terms of
 * the GPL can be found in doc/GPL-license.txt in this distribution, or
 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
 * 
 * There are special exceptions to the terms and conditions of the GPL as
 * it is applied to this Source Code. View the full text of the exception
 * in the file doc/FLOSS-exception.txt in this software distribution, or
 * online at
 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
 * 
 * By copying, modifying or distributing this software, you acknowledge
 * that you have read and understood your obligations described above,
 * and agree to abide by those obligations.
 * 
 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
 * COMPLETENESS OR PERFORMANCE.
 * $/LicenseInfo$
 */

#ifndef LL_LLSTAT_H
#define LL_LLSTAT_H

#include <deque>
#include <map>

#include "lltimer.h"
#include "llframetimer.h"
#include "llfile.h"

class	LL_COMMON_API LLSD;

// Set this if longer stats are needed
#define ENABLE_LONG_TIME_STATS	0

//
// Accumulates statistics for an arbitrary length of time.
// Does this by maintaining a chain of accumulators, each one
// accumulation the results of the parent.  Can scale to arbitrary
// amounts of time with very low memory cost.
//

class LL_COMMON_API LLStatAccum
{
protected:
	LLStatAccum(bool use_frame_timer);
	virtual ~LLStatAccum();

public:
	enum TimeScale {
		SCALE_100MS,
		SCALE_SECOND,
		SCALE_MINUTE,
#if ENABLE_LONG_TIME_STATS
		SCALE_HOUR,
		SCALE_DAY,
		SCALE_WEEK,
#endif
		NUM_SCALES,			// Use to size storage arrays
		SCALE_PER_FRAME		// For latest frame information - should be after NUM_SCALES since this doesn't go into the time buckets
	};

	static U64 sScaleTimes[NUM_SCALES];

	virtual F32 meanValue(TimeScale scale) const;
		// see the subclasses for the specific meaning of value

	F32 meanValueOverLast100ms()  const { return meanValue(SCALE_100MS);  }
	F32 meanValueOverLastSecond() const	{ return meanValue(SCALE_SECOND); }
	F32 meanValueOverLastMinute() const	{ return meanValue(SCALE_MINUTE); }

	void reset(U64 when);

	void sum(F64 value);
	void sum(F64 value, U64 when);

	U64 getCurrentUsecs() const;
		// Get current microseconds based on timer type

	BOOL	mUseFrameTimer;
	BOOL	mRunning;

	U64		mLastTime;
	
	struct Bucket
	{
		Bucket() :
			accum(0.0),
			endTime(0),
			lastValid(false),
			lastAccum(0.0)
		{}

		F64	accum;
		U64	endTime;

		bool	lastValid;
		F64	lastAccum;
	};

	Bucket	mBuckets[NUM_SCALES];

	BOOL 	mLastSampleValid;
	F64 	mLastSampleValue;
};

class LL_COMMON_API LLStatMeasure : public LLStatAccum
	// gathers statistics about things that are measured
	// ex.: tempature, time dilation
{
public:
	LLStatMeasure(bool use_frame_timer = true);

	void sample(F64);
	void sample(S32 v) { sample((F64)v); }
	void sample(U32 v) { sample((F64)v); }
	void sample(S64 v) { sample((F64)v); }
	void sample(U64 v) { sample((F64)v); }
};


class LL_COMMON_API LLStatRate : public LLStatAccum
	// gathers statistics about things that can be counted over time
	// ex.: LSL instructions executed, messages sent, simulator frames completed
	// renders it in terms of rate of thing per second
{
public:
	LLStatRate(bool use_frame_timer = true);

	void count(U32);
		// used to note that n items have occured
	
	void mark();
		// used for counting the rate thorugh a point in the code
};


class LL_COMMON_API LLStatTime : public LLStatAccum
	// gathers statistics about time spent in a block of code
	// measure average duration per second in the block
{
public:
	LLStatTime( const std::string & key = "undefined" );

	U32		mFrameNumber;		// Current frame number
	U64		mTotalTimeInFrame;	// Total time (microseconds) accumulated during the last frame

	void	setKey( const std::string & key )		{ mKey = key;	};

	virtual F32 meanValue(TimeScale scale) const;

private:
	void start();				// Start and stop measuring time block
	void stop();

	std::string		mKey;		// Tag representing this time block

#if LL_DEBUG
	BOOL			mRunning;	// TRUE if start() has been called
#endif

	friend class LLPerfBlock;
};

// ----------------------------------------------------------------------------


// Use this class on the stack to record statistics about an area of code
class LL_COMMON_API LLPerfBlock
{
public:
    struct StatEntry
    {
            StatEntry(const std::string& key) : mStat(LLStatTime(key)), mCount(0) {}
            LLStatTime  mStat;
            U32         mCount;
    };
    typedef std::map<std::string, StatEntry*>		stat_map_t;

	// Use this constructor for pre-defined LLStatTime objects
	LLPerfBlock(LLStatTime* stat);

	// Use this constructor for dynamically created LLStatTime objects (not pre-defined) with a multi-part key
	LLPerfBlock( const char* key1, const char* key2 = NULL);


	~LLPerfBlock();

	static void setStatsEnabled( BOOL enable )		{ sStatsEnabled = enable;	};
	static S32  getStatsEnabled()					{ return sStatsEnabled;		};

	static void clearDynamicStats();		// Reset maps to clear out dynamic objects
	static void addStatsToLLSDandReset( LLSD & stats,		// Get current information and clear time bin
										LLStatAccum::TimeScale scale );

private:
	// Initialize dynamically created LLStatTime objects
    void initDynamicStat(const std::string& key);

	std::string				mLastPath;				// Save sCurrentStatPath when this is called
	LLStatTime * 			mPredefinedStat;		// LLStatTime object to get data
	StatEntry *				mDynamicStat;   		// StatEntryobject to get data

	static BOOL				sStatsEnabled;			// Normally FALSE
    static stat_map_t		sStatMap;				// Map full path string to LLStatTime objects
	static std::string		sCurrentStatPath;		// Something like "frame/physics/physics step"
};

// ----------------------------------------------------------------------------

class LL_COMMON_API LLPerfStats
{
public:
    LLPerfStats(const std::string& process_name = "unknown", S32 process_pid = 0);
    virtual ~LLPerfStats();

    virtual void init();    // Reset and start all stat timers
    virtual void updatePerFrameStats();
    // Override these function to add process-specific information to the performance log header and per-frame logging.
    virtual void addProcessHeaderInfo(LLSD& info) { /* not implemented */ }
    virtual void addProcessFrameInfo(LLSD& info, LLStatAccum::TimeScale scale) { /* not implemented */ }

    // High-resolution frame stats
    BOOL    frameStatsIsRunning()                                { return (mReportPerformanceStatEnd > 0.);        };
    F32     getReportPerformanceInterval() const                { return mReportPerformanceStatInterval;        };
    void    setReportPerformanceInterval( F32 interval )        { mReportPerformanceStatInterval = interval;    };
    void    setReportPerformanceDuration( F32 seconds );
    void    setProcessName(const std::string& process_name) { mProcessName = process_name; }
    void    setProcessPID(S32 process_pid) { mProcessPID = process_pid; }

protected:
    void    openPerfStatsFile();                    // Open file for high resolution metrics logging
    void    dumpIntervalPerformanceStats();

    llofstream      mFrameStatsFile;            // File for per-frame stats
    BOOL            mFrameStatsFileFailure;        // Flag to prevent repeat opening attempts
    BOOL            mSkipFirstFrameStats;        // Flag to skip one (partial) frame report
    std::string     mProcessName;
    S32             mProcessPID;

private:
    F32 mReportPerformanceStatInterval;    // Seconds between performance stats
    F64 mReportPerformanceStatEnd;        // End time (seconds) for performance stats
};

// ----------------------------------------------------------------------------
class LL_COMMON_API LLStat
{
private:
	typedef std::multimap<std::string, LLStat*> stat_map_t;
	static stat_map_t sStatList;

	void init();

public:
	LLStat(U32 num_bins = 32, BOOL use_frame_timer = FALSE);
	LLStat(std::string name, U32 num_bins = 32, BOOL use_frame_timer = FALSE);
	~LLStat();

	void reset();

	void start();	// Start the timer for the current "frame", otherwise uses the time tracked from
					// the last addValue
	void addValue(const F32 value = 1.f); // Adds the current value being tracked, and tracks the DT.
	void addValue(const S32 value) { addValue((F32)value); }
	void addValue(const U32 value) { addValue((F32)value); }

	void setBeginTime(const F64 time);
	void addValueTime(const F64 time, const F32 value = 1.f);
	
	S32 getCurBin() const;
	S32 getNextBin() const;
	
	F32 getCurrent() const;
	F32 getCurrentPerSec() const;
	F64 getCurrentBeginTime() const;
	F64 getCurrentTime() const;
	F32 getCurrentDuration() const;
	
	F32 getPrev(S32 age) const;				// Age is how many "addValues" previously - zero is current
	F32 getPrevPerSec(S32 age) const;		// Age is how many "addValues" previously - zero is current
	F64 getPrevBeginTime(S32 age) const;
	F64 getPrevTime(S32 age) const;
	
	F32 getBin(S32 bin) const;
	F32 getBinPerSec(S32 bin) const;
	F64 getBinBeginTime(S32 bin) const;
	F64 getBinTime(S32 bin) const;

	F32 getMax() const;
	F32 getMaxPerSec() const;
	
	F32 getMean() const;
	F32 getMeanPerSec() const;
	F32 getMeanDuration() const;

	F32 getMin() const;
	F32 getMinPerSec() const;
	F32 getMinDuration() const;

	F32 getSum() const;
	F32 getSumDuration() const;

	U32 getNumValues() const;
	S32 getNumBins() const;

	F64 getLastTime() const;
private:
	BOOL mUseFrameTimer;
	U32 mNumValues;
	U32 mNumBins;
	F32 mLastValue;
	F64 mLastTime;
	F32 *mBins;
	F64 *mBeginTime;
	F64 *mTime;
	F32 *mDT;
	S32 mCurBin;
	S32 mNextBin;
	
	std::string mName;

	static LLTimer sTimer;
	static LLFrameTimer sFrameTimer;
	
public:
	static LLStat* getStat(const std::string& name)
	{
		// return the first stat that matches 'name'
		stat_map_t::iterator iter = sStatList.find(name);
		if (iter != sStatList.end())
			return iter->second;
		else
			return NULL;
	}
};
	
#endif // LL_STAT_