aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llcommon
diff options
context:
space:
mode:
Diffstat (limited to 'linden/indra/llcommon')
-rw-r--r--linden/indra/llcommon/CMakeLists.txt7
-rw-r--r--linden/indra/llcommon/indra_constants.h1
-rw-r--r--linden/indra/llcommon/llcommon.cpp4
-rw-r--r--linden/indra/llcommon/llfasttimer.h1
-rw-r--r--linden/indra/llcommon/llfindlocale.cpp4
-rw-r--r--linden/indra/llcommon/llfindlocale.h4
-rw-r--r--linden/indra/llcommon/llkeythrottle.h2
-rw-r--r--linden/indra/llcommon/llprocessor.h20
-rw-r--r--linden/indra/llcommon/llsdserialize.cpp2
-rw-r--r--linden/indra/llcommon/llsdserialize_xml.cpp13
-rw-r--r--linden/indra/llcommon/llstat.cpp562
-rw-r--r--linden/indra/llcommon/llstat.h142
-rw-r--r--linden/indra/llcommon/llstatenums.h17
-rw-r--r--linden/indra/llcommon/llstl.h5
-rw-r--r--linden/indra/llcommon/llstring.h37
-rw-r--r--linden/indra/llcommon/llthread.cpp4
-rw-r--r--linden/indra/llcommon/llthread.h4
-rw-r--r--linden/indra/llcommon/lltimer.cpp53
-rw-r--r--linden/indra/llcommon/lltimer.h5
-rw-r--r--linden/indra/llcommon/llversionserver.h4
-rw-r--r--linden/indra/llcommon/llversionviewer.h4
21 files changed, 743 insertions, 152 deletions
diff --git a/linden/indra/llcommon/CMakeLists.txt b/linden/indra/llcommon/CMakeLists.txt
index 8810549..4001e1f 100644
--- a/linden/indra/llcommon/CMakeLists.txt
+++ b/linden/indra/llcommon/CMakeLists.txt
@@ -187,3 +187,10 @@ set_source_files_properties(${llcommon_HEADER_FILES}
187list(APPEND llcommon_SOURCE_FILES ${llcommon_HEADER_FILES}) 187list(APPEND llcommon_SOURCE_FILES ${llcommon_HEADER_FILES})
188 188
189add_library (llcommon ${llcommon_SOURCE_FILES}) 189add_library (llcommon ${llcommon_SOURCE_FILES})
190target_link_libraries(
191 llcommon
192 ${APRUTIL_LIBRARIES}
193 ${APR_LIBRARIES}
194 ${EXPAT_LIBRARIES}
195 ${ZLIB_LIBRARIES}
196 )
diff --git a/linden/indra/llcommon/indra_constants.h b/linden/indra/llcommon/indra_constants.h
index 1c48a5c..fcb2aaf 100644
--- a/linden/indra/llcommon/indra_constants.h
+++ b/linden/indra/llcommon/indra_constants.h
@@ -251,6 +251,7 @@ const U8 GOD_NOT = 0;
251const LLUUID LL_UUID_ALL_AGENTS("44e87126-e794-4ded-05b3-7c42da3d5cdb"); 251const LLUUID LL_UUID_ALL_AGENTS("44e87126-e794-4ded-05b3-7c42da3d5cdb");
252 252
253// Governor Linden's agent id. 253// Governor Linden's agent id.
254const LLUUID ALEXANDRIA_LINDEN_ID("ba2a564a-f0f1-4b82-9c61-b7520bfcd09f");
254const LLUUID GOVERNOR_LINDEN_ID("3d6181b0-6a4b-97ef-18d8-722652995cf1"); 255const LLUUID GOVERNOR_LINDEN_ID("3d6181b0-6a4b-97ef-18d8-722652995cf1");
255const LLUUID REALESTATE_LINDEN_ID("3d6181b0-6a4b-97ef-18d8-722652995cf1"); 256const LLUUID REALESTATE_LINDEN_ID("3d6181b0-6a4b-97ef-18d8-722652995cf1");
256// Maintenance's group id. 257// Maintenance's group id.
diff --git a/linden/indra/llcommon/llcommon.cpp b/linden/indra/llcommon/llcommon.cpp
index b21b687..cdaa7f9 100644
--- a/linden/indra/llcommon/llcommon.cpp
+++ b/linden/indra/llcommon/llcommon.cpp
@@ -46,7 +46,7 @@ void LLCommon::initClass()
46 sAprInitialized = TRUE; 46 sAprInitialized = TRUE;
47 } 47 }
48 LLTimer::initClass(); 48 LLTimer::initClass();
49 LLThreadSafeRefCount::initClass(); 49 LLThreadSafeRefCount::initThreadSafeRefCount();
50// LLWorkerThread::initClass(); 50// LLWorkerThread::initClass();
51// LLFrameCallbackManager::initClass(); 51// LLFrameCallbackManager::initClass();
52} 52}
@@ -56,7 +56,7 @@ void LLCommon::cleanupClass()
56{ 56{
57// LLFrameCallbackManager::cleanupClass(); 57// LLFrameCallbackManager::cleanupClass();
58// LLWorkerThread::cleanupClass(); 58// LLWorkerThread::cleanupClass();
59 LLThreadSafeRefCount::cleanupClass(); 59 LLThreadSafeRefCount::cleanupThreadSafeRefCount();
60 LLTimer::cleanupClass(); 60 LLTimer::cleanupClass();
61 if (sAprInitialized) 61 if (sAprInitialized)
62 { 62 {
diff --git a/linden/indra/llcommon/llfasttimer.h b/linden/indra/llcommon/llfasttimer.h
index 8ad2667..80ed26b 100644
--- a/linden/indra/llcommon/llfasttimer.h
+++ b/linden/indra/llcommon/llfasttimer.h
@@ -165,6 +165,7 @@ public:
165 FTM_FILTER, 165 FTM_FILTER,
166 FTM_REFRESH, 166 FTM_REFRESH,
167 FTM_SORT, 167 FTM_SORT,
168 FTM_PICK,
168 169
169 // Temp 170 // Temp
170 FTM_TEMP1, 171 FTM_TEMP1,
diff --git a/linden/indra/llcommon/llfindlocale.cpp b/linden/indra/llcommon/llfindlocale.cpp
index 47da974..344041c 100644
--- a/linden/indra/llcommon/llfindlocale.cpp
+++ b/linden/indra/llcommon/llfindlocale.cpp
@@ -180,10 +180,10 @@ canonise_fl(FL_Locale *l) {
180#define ML(pn,sn) MAKELANGID(LANG_##pn, SUBLANG_##pn##_##sn) 180#define ML(pn,sn) MAKELANGID(LANG_##pn, SUBLANG_##pn##_##sn)
181#define MLN(pn) MAKELANGID(LANG_##pn, SUBLANG_DEFAULT) 181#define MLN(pn) MAKELANGID(LANG_##pn, SUBLANG_DEFAULT)
182#define RML(pn,sn) MAKELANGID(LANG_##pn, SUBLANG_##sn) 182#define RML(pn,sn) MAKELANGID(LANG_##pn, SUBLANG_##sn)
183typedef struct { 183struct IDToCode {
184 LANGID id; 184 LANGID id;
185 char* code; 185 char* code;
186} IDToCode; 186};
187static const IDToCode both_to_code[] = { 187static const IDToCode both_to_code[] = {
188 {ML(ENGLISH,US), "en_US.ISO_8859-1"}, 188 {ML(ENGLISH,US), "en_US.ISO_8859-1"},
189 {ML(ENGLISH,CAN), "en_CA"}, /* english / canadian */ 189 {ML(ENGLISH,CAN), "en_CA"}, /* english / canadian */
diff --git a/linden/indra/llcommon/llfindlocale.h b/linden/indra/llcommon/llfindlocale.h
index 6cc2dbb..bc253c3 100644
--- a/linden/indra/llcommon/llfindlocale.h
+++ b/linden/indra/llcommon/llfindlocale.h
@@ -36,11 +36,11 @@ typedef const char* FL_Lang;
36typedef const char* FL_Country; 36typedef const char* FL_Country;
37typedef const char* FL_Variant; 37typedef const char* FL_Variant;
38 38
39typedef struct { 39struct FL_Locale {
40 FL_Lang lang; 40 FL_Lang lang;
41 FL_Country country; 41 FL_Country country;
42 FL_Variant variant; 42 FL_Variant variant;
43} FL_Locale; 43};
44 44
45typedef enum { 45typedef enum {
46 /* for some reason we failed to even guess: this should never happen */ 46 /* for some reason we failed to even guess: this should never happen */
diff --git a/linden/indra/llcommon/llkeythrottle.h b/linden/indra/llcommon/llkeythrottle.h
index eb1519a..25d0fe0 100644
--- a/linden/indra/llcommon/llkeythrottle.h
+++ b/linden/indra/llcommon/llkeythrottle.h
@@ -243,7 +243,7 @@ public:
243 } 243 }
244 244
245 // Set the throttling behavior 245 // Set the throttling behavior
246 void setParameters( U32 limit, F32 interval, BOOL realtime ) 246 void setParameters( U32 limit, F32 interval, BOOL realtime = TRUE )
247 { 247 {
248 // limit is the maximum number of keys 248 // limit is the maximum number of keys
249 // allowed per interval (in seconds or frames) 249 // allowed per interval (in seconds or frames)
diff --git a/linden/indra/llcommon/llprocessor.h b/linden/indra/llcommon/llprocessor.h
index 6abbd96..06dc72a 100644
--- a/linden/indra/llcommon/llprocessor.h
+++ b/linden/indra/llcommon/llprocessor.h
@@ -58,7 +58,7 @@
58#endif 58#endif
59 59
60 60
61typedef struct ProcessorExtensions 61struct ProcessorExtensions
62{ 62{
63 bool FPU_FloatingPointUnit; 63 bool FPU_FloatingPointUnit;
64 bool VME_Virtual8086ModeEnhancements; 64 bool VME_Virtual8086ModeEnhancements;
@@ -97,9 +97,9 @@ typedef struct ProcessorExtensions
97 bool _3DNOW_InstructionExtensions; 97 bool _3DNOW_InstructionExtensions;
98 bool _E3DNOW_InstructionExtensions; 98 bool _E3DNOW_InstructionExtensions;
99 bool AA64_AMD64BitArchitecture; 99 bool AA64_AMD64BitArchitecture;
100} ProcessorExtensions; 100};
101 101
102typedef struct ProcessorCache 102struct ProcessorCache
103{ 103{
104 bool bPresent; 104 bool bPresent;
105 char strSize[32]; /* Flawfinder: ignore */ 105 char strSize[32]; /* Flawfinder: ignore */
@@ -107,24 +107,24 @@ typedef struct ProcessorCache
107 unsigned int uiLineSize; 107 unsigned int uiLineSize;
108 bool bSectored; 108 bool bSectored;
109 char strCache[128]; /* Flawfinder: ignore */ 109 char strCache[128]; /* Flawfinder: ignore */
110} ProcessorCache; 110};
111 111
112typedef struct ProcessorL1Cache 112struct ProcessorL1Cache
113{ 113{
114 ProcessorCache Instruction; 114 ProcessorCache Instruction;
115 ProcessorCache Data; 115 ProcessorCache Data;
116} ProcessorL1Cache; 116};
117 117
118typedef struct ProcessorTLB 118struct ProcessorTLB
119{ 119{
120 bool bPresent; 120 bool bPresent;
121 char strPageSize[32]; /* Flawfinder: ignore */ 121 char strPageSize[32]; /* Flawfinder: ignore */
122 unsigned int uiAssociativeWays; 122 unsigned int uiAssociativeWays;
123 unsigned int uiEntries; 123 unsigned int uiEntries;
124 char strTLB[128]; /* Flawfinder: ignore */ 124 char strTLB[128]; /* Flawfinder: ignore */
125} ProcessorTLB; 125};
126 126
127typedef struct ProcessorInfo 127struct ProcessorInfo
128{ 128{
129 char strVendor[16]; /* Flawfinder: ignore */ 129 char strVendor[16]; /* Flawfinder: ignore */
130 unsigned int uiFamily; 130 unsigned int uiFamily;
@@ -148,7 +148,7 @@ typedef struct ProcessorInfo
148 ProcessorCache _Trace; 148 ProcessorCache _Trace;
149 ProcessorTLB _Instruction; 149 ProcessorTLB _Instruction;
150 ProcessorTLB _Data; 150 ProcessorTLB _Data;
151} ProcessorInfo; 151};
152 152
153 153
154// CProcessor 154// CProcessor
diff --git a/linden/indra/llcommon/llsdserialize.cpp b/linden/indra/llcommon/llsdserialize.cpp
index d42842d..f21ff68 100644
--- a/linden/indra/llcommon/llsdserialize.cpp
+++ b/linden/indra/llcommon/llsdserialize.cpp
@@ -324,7 +324,7 @@ S32 LLSDParser::parse(std::istream& istr, LLSD& data, S32 max_bytes)
324S32 LLSDParser::parseLines(std::istream& istr, LLSD& data) 324S32 LLSDParser::parseLines(std::istream& istr, LLSD& data)
325{ 325{
326 mCheckLimits = false; 326 mCheckLimits = false;
327 mParseLines = false; // was true, Emergency fix DEV-17785 parsing newline failure 327 mParseLines = true;
328 return doParse(istr, data); 328 return doParse(istr, data);
329} 329}
330 330
diff --git a/linden/indra/llcommon/llsdserialize_xml.cpp b/linden/indra/llcommon/llsdserialize_xml.cpp
index 690ab67..9c3f85e 100644
--- a/linden/indra/llcommon/llsdserialize_xml.cpp
+++ b/linden/indra/llcommon/llsdserialize_xml.cpp
@@ -461,11 +461,11 @@ S32 LLSDXMLParser::Impl::parseLines(std::istream& input, LLSD& data)
461 input.clear(); 461 input.clear();
462 } 462 }
463 463
464 // Don't parse the NULL at the end which might be added if \n was absorbed by getline() 464 // Re-insert with the \n that was absorbed by getline()
465 char * text = (char *) buffer; 465 char * text = (char *) buffer;
466 if ( text[num_read - 1] == 0) 466 if ( text[num_read - 1] == 0)
467 { 467 {
468 num_read--; 468 text[num_read - 1] = '\n';
469 } 469 }
470 } 470 }
471 471
@@ -808,12 +808,11 @@ void LLSDXMLParser::parsePart(const char *buf, int len)
808// virtual 808// virtual
809S32 LLSDXMLParser::doParse(std::istream& input, LLSD& data) const 809S32 LLSDXMLParser::doParse(std::istream& input, LLSD& data) const
810{ 810{
811// Remove code - emergency fix DEV-17785 parsing newline failure 811 if (mParseLines)
812// if (mParseLines) 812 {
813// {
814 // Use line-based reading (faster code) 813 // Use line-based reading (faster code)
815// return impl.parseLines(input, data); 814 return impl.parseLines(input, data);
816// } 815 }
817 816
818 return impl.parse(input, data); 817 return impl.parse(input, data);
819} 818}
diff --git a/linden/indra/llcommon/llstat.cpp b/linden/indra/llcommon/llstat.cpp
index 4b79fcb..706acdb 100644
--- a/linden/indra/llcommon/llstat.cpp
+++ b/linden/indra/llcommon/llstat.cpp
@@ -31,55 +31,288 @@
31#include "linden_common.h" 31#include "linden_common.h"
32 32
33#include "llstat.h" 33#include "llstat.h"
34#include "lllivefile.h"
35#include "llerrorcontrol.h"
34#include "llframetimer.h" 36#include "llframetimer.h"
35#include "timing.h" 37#include "timing.h"
38#include "llsd.h"
39#include "llsdserialize.h"
40#include "llstl.h"
41#include "u64.h"
36 42
37class LLStatAccum::impl 43
44// statics
45BOOL LLPerfBlock::sStatsEnabled = FALSE; // Flag for detailed information
46LLPerfBlock::stat_map_t LLPerfBlock::sStatMap; // Map full path string to LLStatTime objects, tracks all active objects
47std::string LLPerfBlock::sCurrentStatPath = ""; // Something like "/total_time/physics/physics step"
48
49//------------------------------------------------------------------------
50// Live config file to trigger stats logging
51static const char STATS_CONFIG_FILE_NAME[] = "/dev/shm/simperf/simperf_proc_config.llsd";
52static const F32 STATS_CONFIG_REFRESH_RATE = 5.0; // seconds
53
54class LLStatsConfigFile : public LLLiveFile
38{ 55{
39public: 56public:
40 static const TimeScale IMPL_NUM_SCALES = (TimeScale)(SCALE_TWO_MINUTE + 1); 57 LLStatsConfigFile()
41 static U64 sScaleTimes[IMPL_NUM_SCALES]; 58 : LLLiveFile(filename(), STATS_CONFIG_REFRESH_RATE),
59 mChanged(false), mStatsp(NULL) { }
42 60
43 BOOL mUseFrameTimer; 61 static std::string filename();
62
63protected:
64 /* virtual */ void loadFile();
44 65
45 BOOL mRunning; 66public:
46 U64 mLastTime; 67 void init(LLPerfStats* statsp);
47 68 static LLStatsConfigFile& instance();
48 struct Bucket 69 // return the singleton stats config file
49 {
50 F64 accum;
51 U64 endTime;
52 70
53 BOOL lastValid; 71 bool mChanged;
54 F64 lastAccum;
55 };
56 72
57 Bucket mBuckets[IMPL_NUM_SCALES]; 73protected:
74 LLPerfStats* mStatsp;
75};
58 76
59 BOOL mLastSampleValid; 77std::string LLStatsConfigFile::filename()
60 F64 mLastSampleValue; 78{
79 return STATS_CONFIG_FILE_NAME;
80}
61 81
82void LLStatsConfigFile::init(LLPerfStats* statsp)
83{
84 mStatsp = statsp;
85}
62 86
63 impl(bool useFrameTimer); 87LLStatsConfigFile& LLStatsConfigFile::instance()
88{
89 static LLStatsConfigFile the_file;
90 return the_file;
91}
64 92
65 void reset(U64 when);
66 93
67 void sum(F64 value); 94/* virtual */
68 void sum(F64 value, U64 when); 95// Load and parse the stats configuration file
96void LLStatsConfigFile::loadFile()
97{
98 if (!mStatsp)
99 {
100 llwarns << "Tries to load performance configure file without initializing LPerfStats" << llendl;
101 return;
102 }
103 mChanged = true;
104
105 LLSD stats_config;
106 {
107 llifstream file(filename().c_str());
108 if (file.is_open())
109 {
110 LLSDSerialize::fromXML(stats_config, file);
111 if (stats_config.isUndefined())
112 {
113 llinfos << "Performance statistics configuration file ill-formed, not recording statistics" << llendl;
114 mStatsp->setReportPerformanceDuration( 0.f );
115 return;
116 }
117 }
118 else
119 { // File went away, turn off stats if it was on
120 if ( mStatsp->frameStatsIsRunning() )
121 {
122 llinfos << "Performance statistics configuration file deleted, not recording statistics" << llendl;
123 mStatsp->setReportPerformanceDuration( 0.f );
124 }
125 return;
126 }
127 }
128
129 F32 duration = 0.f;
130 F32 interval = 0.f;
131
132 const char * w = "duration";
133 if (stats_config.has(w))
134 {
135 duration = (F32)stats_config[w].asReal();
136 }
137 w = "interval";
138 if (stats_config.has(w))
139 {
140 interval = (F32)stats_config[w].asReal();
141 }
142
143 mStatsp->setReportPerformanceDuration( duration );
144 mStatsp->setReportPerformanceInterval( interval );
145
146 if ( duration > 0 )
147 {
148 if ( interval == 0.f )
149 {
150 llinfos << "Recording performance stats every frame for " << duration << " sec" << llendl;
151 }
152 else
153 {
154 llinfos << "Recording performance stats every " << interval << " seconds for " << duration << " seconds" << llendl;
155 }
156 }
157 else
158 {
159 llinfos << "Performance stats recording turned off" << llendl;
160 }
161}
69 162
70 F32 meanValue(TimeScale scale) const;
71 163
72 U64 getCurrentUsecs() const; 164//------------------------------------------------------------------------
73 // Get current microseconds based on timer type
74};
75 165
166LLPerfStats::LLPerfStats(const std::string& process_name, S32 process_pid) :
167 mFrameStatsFileFailure(FALSE),
168 mSkipFirstFrameStats(FALSE),
169 mProcessName(process_name),
170 mProcessPID(process_pid),
171 mReportPerformanceStatInterval(1.f),
172 mReportPerformanceStatEnd(0.0)
173{ }
76 174
77U64 LLStatAccum::impl::sScaleTimes[IMPL_NUM_SCALES] = 175LLPerfStats::~LLPerfStats()
176{
177 LLPerfBlock::clearDynamicStats();
178 mFrameStatsFile.close();
179}
180
181void LLPerfStats::init()
182{
183 // Initialize the stats config file instance.
184 (void) LLStatsConfigFile::instance().init(this);
185 (void) LLStatsConfigFile::instance().checkAndReload();
186}
187
188// Open file for statistics
189void LLPerfStats::openPerfStatsFile()
190{
191 if ( !mFrameStatsFile
192 && !mFrameStatsFileFailure )
193 {
194 std::string stats_file = llformat("/dev/shm/simperf/%s_proc.%d.llsd", mProcessName.c_str(), mProcessPID);
195 mFrameStatsFile.close();
196 mFrameStatsFile.clear();
197 mFrameStatsFile.open(stats_file, llofstream::out);
198 if ( mFrameStatsFile.fail() )
199 {
200 llinfos << "Error opening statistics log file " << stats_file << llendl;
201 mFrameStatsFileFailure = TRUE;
202 }
203 else
204 {
205 LLSD process_info = LLSD::emptyMap();
206 process_info["name"] = mProcessName;
207 process_info["pid"] = (LLSD::Integer) mProcessPID;
208 process_info["stat_rate"] = (LLSD::Integer) mReportPerformanceStatInterval;
209 // Add process-specific info.
210 addProcessHeaderInfo(process_info);
211
212 mFrameStatsFile << LLSDNotationStreamer(process_info) << std::endl;
213 }
214 }
215}
216
217// Dump out performance metrics over some time interval
218void LLPerfStats::dumpIntervalPerformanceStats()
219{
220 // Ensure output file is OK
221 openPerfStatsFile();
222
223 if ( mFrameStatsFile )
224 {
225 LLSD stats = LLSD::emptyMap();
226
227 LLStatAccum::TimeScale scale;
228 if ( getReportPerformanceInterval() == 0.f )
229 {
230 scale = LLStatAccum::SCALE_PER_FRAME;
231 }
232 else if ( getReportPerformanceInterval() < 0.5f )
233 {
234 scale = LLStatAccum::SCALE_100MS;
235 }
236 else
237 {
238 scale = LLStatAccum::SCALE_SECOND;
239 }
240
241 // Write LLSD into log
242 stats["utc_time"] = (LLSD::String) LLError::utcTime();
243 stats["timestamp"] = U64_to_str((totalTime() / 1000) + (gUTCOffset * 1000)); // milliseconds since epoch
244 stats["frame_number"] = (LLSD::Integer) LLFrameTimer::getFrameCount();
245
246 // Add process-specific frame info.
247 addProcessFrameInfo(stats, scale);
248 LLPerfBlock::addStatsToLLSDandReset( stats, scale );
249
250 mFrameStatsFile << LLSDNotationStreamer(stats) << std::endl;
251 }
252}
253
254// Set length of performance stat recording
255void LLPerfStats::setReportPerformanceDuration( F32 seconds )
256{
257 if ( seconds <= 0.f )
258 {
259 mReportPerformanceStatEnd = 0.0;
260 LLPerfBlock::setStatsEnabled( FALSE );
261 mFrameStatsFile.close();
262 LLPerfBlock::clearDynamicStats();
263 }
264 else
265 {
266 mReportPerformanceStatEnd = LLFrameTimer::getElapsedSeconds() + ((F64) seconds);
267 // Clear failure flag to try and create the log file once
268 mFrameStatsFileFailure = FALSE;
269 LLPerfBlock::setStatsEnabled( TRUE );
270 mSkipFirstFrameStats = TRUE; // Skip the first report (at the end of this frame)
271 }
272}
273
274void LLPerfStats::updatePerFrameStats()
275{
276 (void) LLStatsConfigFile::instance().checkAndReload();
277 static LLFrameTimer performance_stats_timer;
278 if ( frameStatsIsRunning() )
279 {
280 if ( mReportPerformanceStatInterval == 0 )
281 { // Record info every frame
282 if ( mSkipFirstFrameStats )
283 { // Skip the first time - was started this frame
284 mSkipFirstFrameStats = FALSE;
285 }
286 else
287 {
288 dumpIntervalPerformanceStats();
289 }
290 }
291 else
292 {
293 performance_stats_timer.setTimerExpirySec( getReportPerformanceInterval() );
294 if (performance_stats_timer.checkExpirationAndReset( mReportPerformanceStatInterval ))
295 {
296 dumpIntervalPerformanceStats();
297 }
298 }
299
300 if ( LLFrameTimer::getElapsedSeconds() > mReportPerformanceStatEnd )
301 { // Reached end of time, clear it to stop reporting
302 setReportPerformanceDuration(0.f); // Don't set mReportPerformanceStatEnd directly
303 llinfos << "Recording performance stats completed" << llendl;
304 }
305 }
306}
307
308
309//------------------------------------------------------------------------
310
311U64 LLStatAccum::sScaleTimes[NUM_SCALES] =
78{ 312{
79 USEC_PER_SEC / 10, // 100 millisec 313 USEC_PER_SEC / 10, // 100 millisec
80 USEC_PER_SEC * 1, // seconds 314 USEC_PER_SEC * 1, // seconds
81 USEC_PER_SEC * 60, // minutes 315 USEC_PER_SEC * 60, // minutes
82 USEC_PER_SEC * 60 * 2 // two minutes
83#if ENABLE_LONG_TIME_STATS 316#if ENABLE_LONG_TIME_STATS
84 // enable these when more time scales are desired 317 // enable these when more time scales are desired
85 USEC_PER_SEC * 60*60, // hours 318 USEC_PER_SEC * 60*60, // hours
@@ -89,19 +322,27 @@ U64 LLStatAccum::impl::sScaleTimes[IMPL_NUM_SCALES] =
89}; 322};
90 323
91 324
92LLStatAccum::impl::impl(bool useFrameTimer) 325
326LLStatAccum::LLStatAccum(bool useFrameTimer)
327 : mUseFrameTimer(useFrameTimer),
328 mRunning(FALSE),
329 mLastSampleValue(0.0),
330 mLastSampleValid(FALSE)
331{
332}
333
334LLStatAccum::~LLStatAccum()
93{ 335{
94 mUseFrameTimer = useFrameTimer;
95 mRunning = FALSE;
96 mLastSampleValid = FALSE;
97} 336}
98 337
99void LLStatAccum::impl::reset(U64 when) 338
339
340void LLStatAccum::reset(U64 when)
100{ 341{
101 mRunning = TRUE; 342 mRunning = TRUE;
102 mLastTime = when; 343 mLastTime = when;
103 344
104 for (int i = 0; i < IMPL_NUM_SCALES; ++i) 345 for (int i = 0; i < NUM_SCALES; ++i)
105 { 346 {
106 mBuckets[i].accum = 0.0; 347 mBuckets[i].accum = 0.0;
107 mBuckets[i].endTime = when + sScaleTimes[i]; 348 mBuckets[i].endTime = when + sScaleTimes[i];
@@ -109,12 +350,12 @@ void LLStatAccum::impl::reset(U64 when)
109 } 350 }
110} 351}
111 352
112void LLStatAccum::impl::sum(F64 value) 353void LLStatAccum::sum(F64 value)
113{ 354{
114 sum(value, getCurrentUsecs()); 355 sum(value, getCurrentUsecs());
115} 356}
116 357
117void LLStatAccum::impl::sum(F64 value, U64 when) 358void LLStatAccum::sum(F64 value, U64 when)
118{ 359{
119 if (!mRunning) 360 if (!mRunning)
120 { 361 {
@@ -131,7 +372,10 @@ void LLStatAccum::impl::sum(F64 value, U64 when)
131 return; 372 return;
132 } 373 }
133 374
134 for (int i = 0; i < IMPL_NUM_SCALES; ++i) 375 // how long is this value for
376 U64 timeSpan = when - mLastTime;
377
378 for (int i = 0; i < NUM_SCALES; ++i)
135 { 379 {
136 Bucket& bucket = mBuckets[i]; 380 Bucket& bucket = mBuckets[i];
137 381
@@ -143,8 +387,6 @@ void LLStatAccum::impl::sum(F64 value, U64 when)
143 { 387 {
144 U64 timeScale = sScaleTimes[i]; 388 U64 timeScale = sScaleTimes[i];
145 389
146 U64 timeSpan = when - mLastTime;
147 // how long is this value for
148 U64 timeLeft = when - bucket.endTime; 390 U64 timeLeft = when - bucket.endTime;
149 // how much time is left after filling this bucket 391 // how much time is left after filling this bucket
150 392
@@ -173,13 +415,18 @@ void LLStatAccum::impl::sum(F64 value, U64 when)
173} 415}
174 416
175 417
176F32 LLStatAccum::impl::meanValue(TimeScale scale) const 418F32 LLStatAccum::meanValue(TimeScale scale) const
177{ 419{
178 if (!mRunning) 420 if (!mRunning)
179 { 421 {
180 return 0.0; 422 return 0.0;
181 } 423 }
182 if (scale < 0 || scale >= IMPL_NUM_SCALES) 424 if ( scale == SCALE_PER_FRAME )
425 { // Per-frame not supported here
426 scale = SCALE_100MS;
427 }
428
429 if (scale < 0 || scale >= NUM_SCALES)
183 { 430 {
184 llwarns << "llStatAccum::meanValue called for unsupported scale: " 431 llwarns << "llStatAccum::meanValue called for unsupported scale: "
185 << scale << llendl; 432 << scale << llendl;
@@ -209,7 +456,7 @@ F32 LLStatAccum::impl::meanValue(TimeScale scale) const
209} 456}
210 457
211 458
212U64 LLStatAccum::impl::getCurrentUsecs() const 459U64 LLStatAccum::getCurrentUsecs() const
213{ 460{
214 if (mUseFrameTimer) 461 if (mUseFrameTimer)
215 { 462 {
@@ -222,25 +469,44 @@ U64 LLStatAccum::impl::getCurrentUsecs() const
222} 469}
223 470
224 471
472// ------------------------------------------------------------------------
225 473
226 474LLStatRate::LLStatRate(bool use_frame_timer)
227 475 : LLStatAccum(use_frame_timer)
228LLStatAccum::LLStatAccum(bool useFrameTimer)
229 : m(* new impl(useFrameTimer))
230{ 476{
231} 477}
232 478
233LLStatAccum::~LLStatAccum() 479void LLStatRate::count(U32 value)
234{ 480{
235 delete &m; 481 sum((F64)value * sScaleTimes[SCALE_SECOND]);
236} 482}
237 483
238F32 LLStatAccum::meanValue(TimeScale scale) const 484
239{ 485void LLStatRate::mark()
240 return m.meanValue(scale); 486 {
241} 487 // Effectively the same as count(1), but sets mLastSampleValue
488 U64 when = getCurrentUsecs();
489
490 if ( mRunning
491 && (when > mLastTime) )
492 { // Set mLastSampleValue to the time from the last mark()
493 F64 duration = ((F64)(when - mLastTime)) / sScaleTimes[SCALE_SECOND];
494 if ( duration > 0.0 )
495 {
496 mLastSampleValue = 1.0 / duration;
497 }
498 else
499 {
500 mLastSampleValue = 0.0;
501 }
502 }
503
504 sum( (F64) sScaleTimes[SCALE_SECOND], when);
505 }
242 506
243 507
508// ------------------------------------------------------------------------
509
244 510
245LLStatMeasure::LLStatMeasure(bool use_frame_timer) 511LLStatMeasure::LLStatMeasure(bool use_frame_timer)
246 : LLStatAccum(use_frame_timer) 512 : LLStatAccum(use_frame_timer)
@@ -249,53 +515,209 @@ LLStatMeasure::LLStatMeasure(bool use_frame_timer)
249 515
250void LLStatMeasure::sample(F64 value) 516void LLStatMeasure::sample(F64 value)
251{ 517{
252 U64 when = m.getCurrentUsecs(); 518 U64 when = getCurrentUsecs();
253 519
254 if (m.mLastSampleValid) 520 if (mLastSampleValid)
255 { 521 {
256 F64 avgValue = (value + m.mLastSampleValue) / 2.0; 522 F64 avgValue = (value + mLastSampleValue) / 2.0;
257 F64 interval = (F64)(when - m.mLastTime); 523 F64 interval = (F64)(when - mLastTime);
258 524
259 m.sum(avgValue * interval, when); 525 sum(avgValue * interval, when);
260 } 526 }
261 else 527 else
262 { 528 {
263 m.reset(when); 529 reset(when);
264 } 530 }
265 531
266 m.mLastSampleValid = TRUE; 532 mLastSampleValid = TRUE;
267 m.mLastSampleValue = value; 533 mLastSampleValue = value;
268} 534}
269 535
270 536
271LLStatRate::LLStatRate(bool use_frame_timer) 537// ------------------------------------------------------------------------
272 : LLStatAccum(use_frame_timer) 538
539LLStatTime::LLStatTime(const std::string & key)
540 : LLStatAccum(false),
541 mFrameNumber(LLFrameTimer::getFrameCount()),
542 mTotalTimeInFrame(0),
543 mKey(key)
544#if LL_DEBUG
545 , mRunning(FALSE)
546#endif
273{ 547{
274} 548}
275 549
276void LLStatRate::count(U32 value) 550void LLStatTime::start()
551{
552 // Reset frame accumluation if the frame number has changed
553 U32 frame_number = LLFrameTimer::getFrameCount();
554 if ( frame_number != mFrameNumber )
555 {
556 mFrameNumber = frame_number;
557 mTotalTimeInFrame = 0;
558 }
559
560 sum(0.0);
561
562#if LL_DEBUG
563 // Shouldn't be running already
564 llassert( !mRunning );
565 mRunning = TRUE;
566#endif
567}
568
569void LLStatTime::stop()
570{
571 U64 end_time = getCurrentUsecs();
572 U64 duration = end_time - mLastTime;
573 sum(F64(duration), end_time);
574 //llinfos << "mTotalTimeInFrame incremented from " << mTotalTimeInFrame << " to " << (mTotalTimeInFrame + duration) << llendl;
575 mTotalTimeInFrame += duration;
576
577#if LL_DEBUG
578 mRunning = FALSE;
579#endif
580}
581
582/* virtual */ F32 LLStatTime::meanValue(TimeScale scale) const
277{ 583{
278 m.sum((F64)value * impl::sScaleTimes[SCALE_SECOND]); 584 if ( LLStatAccum::SCALE_PER_FRAME == scale )
585 {
586 return mTotalTimeInFrame;
587 }
588 else
589 {
590 return LLStatAccum::meanValue(scale);
591 }
279} 592}
280 593
281 594
282LLStatTime::LLStatTime(bool use_frame_timer) 595// ------------------------------------------------------------------------
283 : LLStatAccum(use_frame_timer) 596
597
598// Use this constructor for pre-defined LLStatTime objects
599LLPerfBlock::LLPerfBlock(LLStatTime* stat ) : mPredefinedStat(stat), mDynamicStat(NULL)
284{ 600{
601 if (mPredefinedStat)
602 {
603 // If dynamic stats are turned on, this will create a separate entry in the stat map.
604 initDynamicStat(mPredefinedStat->mKey);
605
606 // Start predefined stats. These stats are not part of the stat map.
607 mPredefinedStat->start();
608 }
285} 609}
286 610
287void LLStatTime::start() 611// Use this constructor for dynamically created LLStatTime objects (not pre-defined) with a multi-part key.
612// These are also turned on or off via the switch passed in
613LLPerfBlock::LLPerfBlock( const char* key1, const char* key2 ) : mPredefinedStat(NULL), mDynamicStat(NULL)
288{ 614{
289 m.sum(0.0); 615 if (!sStatsEnabled) return;
616
617 if (NULL == key2 || strlen(key2) == 0)
618 {
619 initDynamicStat(key1);
620 }
621 else
622 {
623 std::ostringstream key;
624 key << key1 << "_" << key2;
625 initDynamicStat(key.str());
626 }
290} 627}
291 628
292void LLStatTime::stop() 629void LLPerfBlock::initDynamicStat(const std::string& key)
630{
631 // Early exit if dynamic stats aren't enabled.
632 if (!sStatsEnabled) return;
633
634 mLastPath = sCurrentStatPath; // Save and restore current path
635 sCurrentStatPath += "/" + key; // Add key to current path
636
637 // See if the LLStatTime object already exists
638 stat_map_t::iterator iter = sStatMap.find(sCurrentStatPath);
639 if ( iter == sStatMap.end() )
640 {
641 // StatEntry object doesn't exist, so create it
642 mDynamicStat = new StatEntry( key );
643 sStatMap[ sCurrentStatPath ] = mDynamicStat; // Set the entry for this path
644 }
645 else
646 {
647 // Found this path in the map, use the object there
648 mDynamicStat = (*iter).second; // Get StatEntry for the current path
649 }
650
651 if (mDynamicStat)
652 {
653 mDynamicStat->mStat.start();
654 mDynamicStat->mCount++;
655 }
656 else
657 {
658 llwarns << "Initialized NULL dynamic stat at '" << sCurrentStatPath << "'" << llendl;
659 sCurrentStatPath = mLastPath;
660 }
661}
662
663
664// Destructor does the time accounting
665LLPerfBlock::~LLPerfBlock()
666{
667 if (mPredefinedStat) mPredefinedStat->stop();
668 if (mDynamicStat)
669 {
670 mDynamicStat->mStat.stop();
671 sCurrentStatPath = mLastPath; // Restore the path in case sStatsEnabled changed during this block
672 }
673}
674
675
676// Clear the map of any dynamic stats. Static routine
677void LLPerfBlock::clearDynamicStats()
678{
679 std::for_each(sStatMap.begin(), sStatMap.end(), DeletePairedPointer());
680 sStatMap.clear();
681}
682
683// static - Extract the stat info into LLSD
684void LLPerfBlock::addStatsToLLSDandReset( LLSD & stats,
685 LLStatAccum::TimeScale scale )
293{ 686{
294 U64 endTime = m.getCurrentUsecs(); 687 // If we aren't in per-frame scale, we need to go from second to microsecond.
295 m.sum((F64)(endTime - m.mLastTime), endTime); 688 U32 scale_adjustment = 1;
689 if (LLStatAccum::SCALE_PER_FRAME != scale)
690 {
691 scale_adjustment = USEC_PER_SEC;
692 }
693 stat_map_t::iterator iter = sStatMap.begin();
694 for ( ; iter != sStatMap.end(); ++iter )
695 { // Put the entry into LLSD "/full/path/to/stat/" = microsecond total time
696 const std::string & stats_full_path = (*iter).first;
697
698 StatEntry * stat = (*iter).second;
699 if (stat)
700 {
701 if (stat->mCount > 0)
702 {
703 stats[stats_full_path] = LLSD::emptyMap();
704 stats[stats_full_path]["us"] = (LLSD::Integer) (scale_adjustment * stat->mStat.meanValue(scale));
705 if (stat->mCount > 1)
706 {
707 stats[stats_full_path]["count"] = (LLSD::Integer) stat->mCount;
708 }
709 stat->mCount = 0;
710 }
711 }
712 else
713 { // WTF? Shouldn't have a NULL pointer in the map.
714 llwarns << "Unexpected NULL dynamic stat at '" << stats_full_path << "'" << llendl;
715 }
716 }
296} 717}
297 718
298 719
720// ------------------------------------------------------------------------
299 721
300LLTimer LLStat::sTimer; 722LLTimer LLStat::sTimer;
301LLFrameTimer LLStat::sFrameTimer; 723LLFrameTimer LLStat::sFrameTimer;
diff --git a/linden/indra/llcommon/llstat.h b/linden/indra/llcommon/llstat.h
index 0a7e014..63813e2 100644
--- a/linden/indra/llcommon/llstat.h
+++ b/linden/indra/llcommon/llstat.h
@@ -33,9 +33,13 @@
33#define LL_LLSTAT_H 33#define LL_LLSTAT_H
34 34
35#include <deque> 35#include <deque>
36#include <map>
36 37
37#include "lltimer.h" 38#include "lltimer.h"
38#include "llframetimer.h" 39#include "llframetimer.h"
40#include "llfile.h"
41
42class LLSD;
39 43
40// Set this if longer stats are needed 44// Set this if longer stats are needed
41#define ENABLE_LONG_TIME_STATS 0 45#define ENABLE_LONG_TIME_STATS 0
@@ -58,25 +62,50 @@ public:
58 SCALE_100MS, 62 SCALE_100MS,
59 SCALE_SECOND, 63 SCALE_SECOND,
60 SCALE_MINUTE, 64 SCALE_MINUTE,
61 SCALE_TWO_MINUTE,
62#if ENABLE_LONG_TIME_STATS 65#if ENABLE_LONG_TIME_STATS
63 SCALE_HOUR, 66 SCALE_HOUR,
64 SCALE_DAY, 67 SCALE_DAY,
65 SCALE_WEEK, 68 SCALE_WEEK,
66#endif 69#endif
67 NUM_SCALES 70 NUM_SCALES, // Use to size storage arrays
71 SCALE_PER_FRAME // For latest frame information - should be after NUM_SCALES since this doesn't go into the time buckets
68 }; 72 };
69 73
70 F32 meanValue(TimeScale scale) const; 74 static U64 sScaleTimes[NUM_SCALES];
75
76 virtual F32 meanValue(TimeScale scale) const;
71 // see the subclasses for the specific meaning of value 77 // see the subclasses for the specific meaning of value
72 78
73 F32 meanValueOverLast100ms() const { return meanValue(SCALE_100MS); } 79 F32 meanValueOverLast100ms() const { return meanValue(SCALE_100MS); }
74 F32 meanValueOverLastSecond() const { return meanValue(SCALE_SECOND); } 80 F32 meanValueOverLastSecond() const { return meanValue(SCALE_SECOND); }
75 F32 meanValueOverLastMinute() const { return meanValue(SCALE_MINUTE); } 81 F32 meanValueOverLastMinute() const { return meanValue(SCALE_MINUTE); }
76 82
77protected: 83 void reset(U64 when);
78 class impl; 84
79 impl& m; 85 void sum(F64 value);
86 void sum(F64 value, U64 when);
87
88 U64 getCurrentUsecs() const;
89 // Get current microseconds based on timer type
90
91 BOOL mUseFrameTimer;
92 BOOL mRunning;
93
94 U64 mLastTime;
95
96 struct Bucket
97 {
98 F64 accum;
99 U64 endTime;
100
101 BOOL lastValid;
102 F64 lastAccum;
103 };
104
105 Bucket mBuckets[NUM_SCALES];
106
107 BOOL mLastSampleValid;
108 F64 mLastSampleValue;
80}; 109};
81 110
82class LLStatMeasure : public LLStatAccum 111class LLStatMeasure : public LLStatAccum
@@ -105,39 +134,120 @@ public:
105 void count(U32); 134 void count(U32);
106 // used to note that n items have occured 135 // used to note that n items have occured
107 136
108 void mark() { count(1); } 137 void mark();
109 // used for counting the rate thorugh a point in the code 138 // used for counting the rate thorugh a point in the code
110}; 139};
111 140
112 141
113class LLTimeBlock;
114
115class LLStatTime : public LLStatAccum 142class LLStatTime : public LLStatAccum
116 // gathers statistics about time spent in a block of code 143 // gathers statistics about time spent in a block of code
117 // measure average duration per second in the block 144 // measure average duration per second in the block
118{ 145{
119public: 146public:
120 LLStatTime(bool use_frame_timer = false); 147 LLStatTime( const std::string & key = "undefined" );
148
149 U32 mFrameNumber; // Current frame number
150 U64 mTotalTimeInFrame; // Total time (microseconds) accumulated during the last frame
151
152 void setKey( const std::string & key ) { mKey = key; };
153
154 virtual F32 meanValue(TimeScale scale) const;
121 155
122private: 156private:
123 void start(); 157 void start(); // Start and stop measuring time block
124 void stop(); 158 void stop();
125 friend class LLTimeBlock; 159
160 std::string mKey; // Tag representing this time block
161
162#if LL_DEBUG
163 BOOL mRunning; // TRUE if start() has been called
164#endif
165
166 friend class LLPerfBlock;
126}; 167};
127 168
128class LLTimeBlock 169// ----------------------------------------------------------------------------
170
171
172// Use this class on the stack to record statistics about an area of code
173class LLPerfBlock
129{ 174{
130public: 175public:
131 LLTimeBlock(LLStatTime& stat) : mStat(stat) { mStat.start(); } 176 struct StatEntry
132 ~LLTimeBlock() { mStat.stop(); } 177 {
178 StatEntry(const std::string& key) : mStat(LLStatTime(key)), mCount(0) {}
179 LLStatTime mStat;
180 U32 mCount;
181 };
182 typedef std::map<std::string, StatEntry*> stat_map_t;
183
184 // Use this constructor for pre-defined LLStatTime objects
185 LLPerfBlock(LLStatTime* stat);
186
187 // Use this constructor for dynamically created LLStatTime objects (not pre-defined) with a multi-part key
188 LLPerfBlock( const char* key1, const char* key2 = NULL);
189
190
191 ~LLPerfBlock();
192
193 static void setStatsEnabled( BOOL enable ) { sStatsEnabled = enable; };
194 static S32 getStatsEnabled() { return sStatsEnabled; };
195
196 static void clearDynamicStats(); // Reset maps to clear out dynamic objects
197 static void addStatsToLLSDandReset( LLSD & stats, // Get current information and clear time bin
198 LLStatAccum::TimeScale scale );
199
133private: 200private:
134 LLStatTime& mStat; 201 // Initialize dynamically created LLStatTime objects
202 void initDynamicStat(const std::string& key);
203
204 std::string mLastPath; // Save sCurrentStatPath when this is called
205 LLStatTime * mPredefinedStat; // LLStatTime object to get data
206 StatEntry * mDynamicStat; // StatEntryobject to get data
207
208 static BOOL sStatsEnabled; // Normally FALSE
209 static stat_map_t sStatMap; // Map full path string to LLStatTime objects
210 static std::string sCurrentStatPath; // Something like "frame/physics/physics step"
135}; 211};
136 212
213// ----------------------------------------------------------------------------
137 214
215class LLPerfStats
216{
217public:
218 LLPerfStats(const std::string& process_name = "unknown", S32 process_pid = 0);
219 virtual ~LLPerfStats();
220
221 virtual void init(); // Reset and start all stat timers
222 virtual void updatePerFrameStats();
223 // Override these function to add process-specific information to the performance log header and per-frame logging.
224 virtual void addProcessHeaderInfo(LLSD& info) { /* not implemented */ }
225 virtual void addProcessFrameInfo(LLSD& info, LLStatAccum::TimeScale scale) { /* not implemented */ }
226
227 // High-resolution frame stats
228 BOOL frameStatsIsRunning() { return (mReportPerformanceStatEnd > 0.); };
229 F32 getReportPerformanceInterval() const { return mReportPerformanceStatInterval; };
230 void setReportPerformanceInterval( F32 interval ) { mReportPerformanceStatInterval = interval; };
231 void setReportPerformanceDuration( F32 seconds );
232 void setProcessName(const std::string& process_name) { mProcessName = process_name; }
233 void setProcessPID(S32 process_pid) { mProcessPID = process_pid; }
138 234
235protected:
236 void openPerfStatsFile(); // Open file for high resolution metrics logging
237 void dumpIntervalPerformanceStats();
238
239 llofstream mFrameStatsFile; // File for per-frame stats
240 BOOL mFrameStatsFileFailure; // Flag to prevent repeat opening attempts
241 BOOL mSkipFirstFrameStats; // Flag to skip one (partial) frame report
242 std::string mProcessName;
243 S32 mProcessPID;
139 244
245private:
246 F32 mReportPerformanceStatInterval; // Seconds between performance stats
247 F64 mReportPerformanceStatEnd; // End time (seconds) for performance stats
248};
140 249
250// ----------------------------------------------------------------------------
141class LLStat 251class LLStat
142{ 252{
143public: 253public:
diff --git a/linden/indra/llcommon/llstatenums.h b/linden/indra/llcommon/llstatenums.h
index 6866586..1d9b863 100644
--- a/linden/indra/llcommon/llstatenums.h
+++ b/linden/indra/llcommon/llstatenums.h
@@ -33,38 +33,41 @@
33 33
34enum 34enum
35{ 35{
36 LL_SIM_STAT_TIME_DILATION, 36 LL_SIM_STAT_TIME_DILATION, // 0
37 LL_SIM_STAT_FPS, 37 LL_SIM_STAT_FPS,
38 LL_SIM_STAT_PHYSFPS, 38 LL_SIM_STAT_PHYSFPS,
39 LL_SIM_STAT_AGENTUPS, 39 LL_SIM_STAT_AGENTUPS,
40 LL_SIM_STAT_FRAMEMS, 40 LL_SIM_STAT_FRAMEMS,
41 LL_SIM_STAT_NETMS, 41 LL_SIM_STAT_NETMS, // 5
42 LL_SIM_STAT_SIMOTHERMS, 42 LL_SIM_STAT_SIMOTHERMS,
43 LL_SIM_STAT_SIMPHYSICSMS, 43 LL_SIM_STAT_SIMPHYSICSMS,
44 LL_SIM_STAT_AGENTMS, 44 LL_SIM_STAT_AGENTMS,
45 LL_SIM_STAT_IMAGESMS, 45 LL_SIM_STAT_IMAGESMS,
46 LL_SIM_STAT_SCRIPTMS, 46 LL_SIM_STAT_SCRIPTMS, // 10
47 LL_SIM_STAT_NUMTASKS, 47 LL_SIM_STAT_NUMTASKS,
48 LL_SIM_STAT_NUMTASKSACTIVE, 48 LL_SIM_STAT_NUMTASKSACTIVE,
49 LL_SIM_STAT_NUMAGENTMAIN, 49 LL_SIM_STAT_NUMAGENTMAIN,
50 LL_SIM_STAT_NUMAGENTCHILD, 50 LL_SIM_STAT_NUMAGENTCHILD,
51 LL_SIM_STAT_NUMSCRIPTSACTIVE, 51 LL_SIM_STAT_NUMSCRIPTSACTIVE, // 15
52 LL_SIM_STAT_LSLIPS, 52 LL_SIM_STAT_LSLIPS,
53 LL_SIM_STAT_INPPS, 53 LL_SIM_STAT_INPPS,
54 LL_SIM_STAT_OUTPPS, 54 LL_SIM_STAT_OUTPPS,
55 LL_SIM_STAT_PENDING_DOWNLOADS, 55 LL_SIM_STAT_PENDING_DOWNLOADS,
56 LL_SIM_STAT_PENDING_UPLOADS, 56 LL_SIM_STAT_PENDING_UPLOADS, // 20
57 LL_SIM_STAT_VIRTUAL_SIZE_KB, 57 LL_SIM_STAT_VIRTUAL_SIZE_KB,
58 LL_SIM_STAT_RESIDENT_SIZE_KB, 58 LL_SIM_STAT_RESIDENT_SIZE_KB,
59 LL_SIM_STAT_PENDING_LOCAL_UPLOADS, 59 LL_SIM_STAT_PENDING_LOCAL_UPLOADS,
60 LL_SIM_STAT_TOTAL_UNACKED_BYTES, 60 LL_SIM_STAT_TOTAL_UNACKED_BYTES,
61 LL_SIM_STAT_PHYSICS_PINNED_TASKS, 61 LL_SIM_STAT_PHYSICS_PINNED_TASKS, // 25
62 LL_SIM_STAT_PHYSICS_LOD_TASKS, 62 LL_SIM_STAT_PHYSICS_LOD_TASKS,
63 LL_SIM_STAT_SIMPHYSICSSTEPMS, 63 LL_SIM_STAT_SIMPHYSICSSTEPMS,
64 LL_SIM_STAT_SIMPHYSICSSHAPEMS, 64 LL_SIM_STAT_SIMPHYSICSSHAPEMS,
65 LL_SIM_STAT_SIMPHYSICSOTHERMS, 65 LL_SIM_STAT_SIMPHYSICSOTHERMS,
66 LL_SIM_STAT_SIMPHYSICSMEMORY, 66 LL_SIM_STAT_SIMPHYSICSMEMORY, // 30
67 LL_SIM_STAT_SCRIPT_EPS, 67 LL_SIM_STAT_SCRIPT_EPS,
68 LL_SIM_STAT_SIMSPARETIME,
69 LL_SIM_STAT_SIMSLEEPTIME,
70 LL_SIM_STAT_IOPUMPTIME,
68}; 71};
69 72
70#endif 73#endif
diff --git a/linden/indra/llcommon/llstl.h b/linden/indra/llcommon/llstl.h
index 4486727..70a2cc0 100644
--- a/linden/indra/llcommon/llstl.h
+++ b/linden/indra/llcommon/llstl.h
@@ -79,6 +79,9 @@ struct compare_pointer_contents
79// The general form is: 79// The general form is:
80// 80//
81// std::for_each(cont.begin(), cont.end(), DeletePointer()); 81// std::for_each(cont.begin(), cont.end(), DeletePointer());
82// somemap.clear();
83//
84// Don't forget to clear()!
82 85
83struct DeletePointer 86struct DeletePointer
84{ 87{
@@ -95,7 +98,7 @@ struct DeletePointerArray
95 } 98 }
96}; 99};
97 100
98// DeletePointer is a simple helper for deleting all pointers in a map. 101// DeletePairedPointer is a simple helper for deleting all pointers in a map.
99// The general form is: 102// The general form is:
100// 103//
101// std::for_each(somemap.begin(), somemap.end(), DeletePairedPointer()); 104// std::for_each(somemap.begin(), somemap.end(), DeletePairedPointer());
diff --git a/linden/indra/llcommon/llstring.h b/linden/indra/llcommon/llstring.h
index 7b08fd3..5e75188 100644
--- a/linden/indra/llcommon/llstring.h
+++ b/linden/indra/llcommon/llstring.h
@@ -133,26 +133,32 @@ struct char_traits<U16>
133class LLStringOps 133class LLStringOps
134{ 134{
135public: 135public:
136 static char toUpper(char elem) { return toupper(elem); } 136 static char toUpper(char elem) { return toupper((unsigned char)elem); }
137 static llwchar toUpper(llwchar elem) { return towupper(elem); } 137 static llwchar toUpper(llwchar elem) { return towupper(elem); }
138 138
139 static char toLower(char elem) { return tolower(elem); } 139 static char toLower(char elem) { return tolower((unsigned char)elem); }
140 static llwchar toLower(llwchar elem) { return towlower(elem); } 140 static llwchar toLower(llwchar elem) { return towlower(elem); }
141 141
142 static BOOL isSpace(char elem) { return isspace(elem) != 0; } 142 static bool isSpace(char elem) { return isspace((unsigned char)elem) != 0; }
143 static BOOL isSpace(llwchar elem) { return iswspace(elem) != 0; } 143 static bool isSpace(llwchar elem) { return iswspace(elem) != 0; }
144 144
145 static BOOL isUpper(char elem) { return isupper(elem) != 0; } 145 static bool isUpper(char elem) { return isupper((unsigned char)elem) != 0; }
146 static BOOL isUpper(llwchar elem) { return iswupper(elem) != 0; } 146 static bool isUpper(llwchar elem) { return iswupper(elem) != 0; }
147 147
148 static BOOL isLower(char elem) { return islower(elem) != 0; } 148 static bool isLower(char elem) { return islower((unsigned char)elem) != 0; }
149 static BOOL isLower(llwchar elem) { return iswlower(elem) != 0; } 149 static bool isLower(llwchar elem) { return iswlower(elem) != 0; }
150
151 static bool isDigit(char a) { return isdigit((unsigned char)a) != 0; }
152 static bool isDigit(llwchar a) { return iswdigit(a) != 0; }
153
154 static bool isPunct(char a) { return ispunct((unsigned char)a) != 0; }
155 static bool isPunct(llwchar a) { return iswpunct(a) != 0; }
156
157 static bool isAlnum(char a) { return isalnum((unsigned char)a) != 0; }
158 static bool isAlnum(llwchar a) { return iswalnum(a) != 0; }
150 159
151 static S32 collate(const char* a, const char* b) { return strcoll(a, b); } 160 static S32 collate(const char* a, const char* b) { return strcoll(a, b); }
152 static S32 collate(const llwchar* a, const llwchar* b); 161 static S32 collate(const llwchar* a, const llwchar* b);
153
154 static BOOL isDigit(char a) { return isdigit(a) != 0; }
155 static BOOL isDigit(llwchar a) { return iswdigit(a) != 0; }
156}; 162};
157 163
158/** 164/**
@@ -194,7 +200,7 @@ public:
194 typedef std::map<LLFormatMapString, LLFormatMapString> format_map_t; 200 typedef std::map<LLFormatMapString, LLFormatMapString> format_map_t;
195 static S32 format(std::basic_string<T>& s, const format_map_t& fmt_map); 201 static S32 format(std::basic_string<T>& s, const format_map_t& fmt_map);
196 202
197 static BOOL isValidIndex(const std::basic_string<T>& string, size_type i) 203 static bool isValidIndex(const std::basic_string<T>& string, size_type i)
198 { 204 {
199 return !string.empty() && (0 <= i) && (i <= string.size()); 205 return !string.empty() && (0 <= i) && (i <= string.size());
200 } 206 }
@@ -1155,13 +1161,6 @@ BOOL LLStringUtilBase<T>::convertToU32(const std::basic_string<T>& string, U32&
1155 std::basic_istringstream<T> i_stream((std::basic_string<T>)temp); 1161 std::basic_istringstream<T> i_stream((std::basic_string<T>)temp);
1156 if(i_stream >> v) 1162 if(i_stream >> v)
1157 { 1163 {
1158 //TODO: figure out overflow reporting here
1159 //if( ULONG_MAX == v )
1160 //{
1161 // // Underflow or overflow
1162 // return FALSE;
1163 //}
1164
1165 value = v; 1164 value = v;
1166 return TRUE; 1165 return TRUE;
1167 } 1166 }
diff --git a/linden/indra/llcommon/llthread.cpp b/linden/indra/llcommon/llthread.cpp
index 822adc2..8bc9aac 100644
--- a/linden/indra/llcommon/llthread.cpp
+++ b/linden/indra/llcommon/llthread.cpp
@@ -359,7 +359,7 @@ void LLCondition::broadcast()
359LLMutex* LLThreadSafeRefCount::sMutex = 0; 359LLMutex* LLThreadSafeRefCount::sMutex = 0;
360 360
361//static 361//static
362void LLThreadSafeRefCount::initClass() 362void LLThreadSafeRefCount::initThreadSafeRefCount()
363{ 363{
364 if (!sMutex) 364 if (!sMutex)
365 { 365 {
@@ -368,7 +368,7 @@ void LLThreadSafeRefCount::initClass()
368} 368}
369 369
370//static 370//static
371void LLThreadSafeRefCount::cleanupClass() 371void LLThreadSafeRefCount::cleanupThreadSafeRefCount()
372{ 372{
373 delete sMutex; 373 delete sMutex;
374 sMutex = NULL; 374 sMutex = NULL;
diff --git a/linden/indra/llcommon/llthread.h b/linden/indra/llcommon/llthread.h
index 9da3134..923de56 100644
--- a/linden/indra/llcommon/llthread.h
+++ b/linden/indra/llcommon/llthread.h
@@ -191,8 +191,8 @@ void LLThread::unlockData()
191class LLThreadSafeRefCount 191class LLThreadSafeRefCount
192{ 192{
193public: 193public:
194 static void initClass(); // creates sMutex 194 static void initThreadSafeRefCount(); // creates sMutex
195 static void cleanupClass(); // destroys sMutex 195 static void cleanupThreadSafeRefCount(); // destroys sMutex
196 196
197private: 197private:
198 static LLMutex* sMutex; 198 static LLMutex* sMutex;
diff --git a/linden/indra/llcommon/lltimer.cpp b/linden/indra/llcommon/lltimer.cpp
index 967570d..47edfd0 100644
--- a/linden/indra/llcommon/lltimer.cpp
+++ b/linden/indra/llcommon/lltimer.cpp
@@ -83,15 +83,20 @@ void ms_sleep(U32 ms)
83{ 83{
84 Sleep(ms); 84 Sleep(ms);
85} 85}
86
87U32 micro_sleep(U64 us, U32 max_yields)
88{
89 // max_yields is unused; just fiddle with it to avoid warnings.
90 max_yields = 0;
91 ms_sleep(us / 1000);
92 return 0;
93}
86#elif LL_LINUX || LL_SOLARIS || LL_DARWIN 94#elif LL_LINUX || LL_SOLARIS || LL_DARWIN
87void ms_sleep(U32 ms) 95static void _sleep_loop(struct timespec& thiswait)
88{ 96{
89 long mslong = ms; // tv_nsec is a long 97 struct timespec nextwait;
90 struct timespec thiswait, nextwait;
91 bool sleep_more = false; 98 bool sleep_more = false;
92 99
93 thiswait.tv_sec = ms / 1000;
94 thiswait.tv_nsec = (mslong % 1000) * 1000000l;
95 do { 100 do {
96 int result = nanosleep(&thiswait, &nextwait); 101 int result = nanosleep(&thiswait, &nextwait);
97 102
@@ -127,6 +132,44 @@ void ms_sleep(U32 ms)
127 } 132 }
128 } while (sleep_more); 133 } while (sleep_more);
129} 134}
135
136U32 micro_sleep(U64 us, U32 max_yields)
137{
138 U64 start = get_clock_count();
139 // This is kernel dependent. Currently, our kernel generates software clock
140 // interrupts at 250 Hz (every 4,000 microseconds).
141 const U64 KERNEL_SLEEP_INTERVAL_US = 4000;
142
143 S32 num_sleep_intervals = (us - (KERNEL_SLEEP_INTERVAL_US >> 1)) / KERNEL_SLEEP_INTERVAL_US;
144 if (num_sleep_intervals > 0)
145 {
146 U64 sleep_time = (num_sleep_intervals * KERNEL_SLEEP_INTERVAL_US) - (KERNEL_SLEEP_INTERVAL_US >> 1);
147 struct timespec thiswait;
148 thiswait.tv_sec = sleep_time / 1000000;
149 thiswait.tv_nsec = (sleep_time % 1000000) * 1000l;
150 _sleep_loop(thiswait);
151 }
152
153 U64 current_clock = get_clock_count();
154 U32 yields = 0;
155 while ( (yields < max_yields)
156 && (current_clock - start < us) )
157 {
158 sched_yield();
159 ++yields;
160 current_clock = get_clock_count();
161 }
162 return yields;
163}
164
165void ms_sleep(U32 ms)
166{
167 long mslong = ms; // tv_nsec is a long
168 struct timespec thiswait;
169 thiswait.tv_sec = ms / 1000;
170 thiswait.tv_nsec = (mslong % 1000) * 1000000l;
171 _sleep_loop(thiswait);
172}
130#else 173#else
131# error "architecture not supported" 174# error "architecture not supported"
132#endif 175#endif
diff --git a/linden/indra/llcommon/lltimer.h b/linden/indra/llcommon/lltimer.h
index 8d94276..766645b 100644
--- a/linden/indra/llcommon/lltimer.h
+++ b/linden/indra/llcommon/lltimer.h
@@ -39,6 +39,8 @@
39 39
40#include "stdtypes.h" 40#include "stdtypes.h"
41 41
42#include <string>
43#include <list>
42// units conversions 44// units conversions
43#ifndef USEC_PER_SEC 45#ifndef USEC_PER_SEC
44 const U32 USEC_PER_SEC = 1000000; 46 const U32 USEC_PER_SEC = 1000000;
@@ -115,6 +117,7 @@ void update_clock_frequencies();
115 117
116// Sleep for milliseconds 118// Sleep for milliseconds
117void ms_sleep(U32 ms); 119void ms_sleep(U32 ms);
120U32 micro_sleep(U64 us, U32 max_yields = 0xFFFFFFFF);
118 121
119// Returns the correct UTC time in seconds, like time(NULL). 122// Returns the correct UTC time in seconds, like time(NULL).
120// Useful on the viewer, which may have its local clock set wrong. 123// Useful on the viewer, which may have its local clock set wrong.
@@ -184,7 +187,7 @@ protected:
184 187
185private: 188private:
186 //list of active timers 189 //list of active timers
187 static std::list<LLEventTimer*> sActiveList; 190 static std::list<LLEventTimer*> sActiveList; // TODO should this be a vector
188}; 191};
189 192
190#endif 193#endif
diff --git a/linden/indra/llcommon/llversionserver.h b/linden/indra/llcommon/llversionserver.h
index 0b88ce8..2861428 100644
--- a/linden/indra/llcommon/llversionserver.h
+++ b/linden/indra/llcommon/llversionserver.h
@@ -34,8 +34,8 @@
34 34
35const S32 LL_VERSION_MAJOR = 1; 35const S32 LL_VERSION_MAJOR = 1;
36const S32 LL_VERSION_MINOR = 24; 36const S32 LL_VERSION_MINOR = 24;
37const S32 LL_VERSION_PATCH = 0; 37const S32 LL_VERSION_PATCH = 9;
38const S32 LL_VERSION_BUILD = 93453; 38const S32 LL_VERSION_BUILD = 98650;
39 39
40const char * const LL_CHANNEL = "Second Life Server"; 40const char * const LL_CHANNEL = "Second Life Server";
41 41
diff --git a/linden/indra/llcommon/llversionviewer.h b/linden/indra/llcommon/llversionviewer.h
index 66462b3..6e7d6ce 100644
--- a/linden/indra/llcommon/llversionviewer.h
+++ b/linden/indra/llcommon/llversionviewer.h
@@ -33,8 +33,8 @@
33#define LL_LLVERSIONVIEWER_H 33#define LL_LLVERSIONVIEWER_H
34 34
35const S32 LL_VERSION_MAJOR = 1; 35const S32 LL_VERSION_MAJOR = 1;
36const S32 LL_VERSION_MINOR = 21; 36const S32 LL_VERSION_MINOR = 22;
37const S32 LL_VERSION_PATCH = 6; 37const S32 LL_VERSION_PATCH = 0;
38const S32 LL_VERSION_BUILD = 0; 38const S32 LL_VERSION_BUILD = 0;
39 39
40const char * const LL_CHANNEL = "Second Life Release"; 40const char * const LL_CHANNEL = "Second Life Release";