diff options
Diffstat (limited to 'OpenSim/Region/Framework/Scenes/SimStatsReporter.cs')
-rwxr-xr-x | OpenSim/Region/Framework/Scenes/SimStatsReporter.cs | 836 |
1 files changed, 836 insertions, 0 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs b/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs new file mode 100755 index 0000000..2174e51 --- /dev/null +++ b/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs | |||
@@ -0,0 +1,836 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Timers; | ||
31 | using OpenMetaverse.Packets; | ||
32 | using OpenSim.Framework; | ||
33 | using OpenSim.Framework.Monitoring; | ||
34 | using OpenSim.Region.Framework.Interfaces; | ||
35 | |||
36 | namespace OpenSim.Region.Framework.Scenes | ||
37 | { | ||
38 | /// <summary> | ||
39 | /// Collect statistics from the scene to send to the client and for access by other monitoring tools. | ||
40 | /// </summary> | ||
41 | /// <remarks> | ||
42 | /// FIXME: This should be a monitoring region module | ||
43 | /// </remarks> | ||
44 | public class SimStatsReporter | ||
45 | { | ||
46 | private static readonly log4net.ILog m_log | ||
47 | = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); | ||
48 | |||
49 | public const string LastReportedObjectUpdateStatName = "LastReportedObjectUpdates"; | ||
50 | public const string SlowFramesStatName = "SlowFrames"; | ||
51 | |||
52 | public delegate void SendStatResult(SimStats stats); | ||
53 | |||
54 | public delegate void YourStatsAreWrong(); | ||
55 | |||
56 | public event SendStatResult OnSendStatsResult; | ||
57 | |||
58 | public event YourStatsAreWrong OnStatsIncorrect; | ||
59 | |||
60 | private SendStatResult handlerSendStatResult; | ||
61 | |||
62 | private YourStatsAreWrong handlerStatsIncorrect; | ||
63 | |||
64 | // Determines the size of the array that is used to collect StatBlocks | ||
65 | // for sending to the SimStats and SimExtraStatsCollector | ||
66 | private const int m_statisticArraySize = 28; | ||
67 | |||
68 | /// <summary> | ||
69 | /// These are the IDs of stats sent in the StatsPacket to the viewer. | ||
70 | /// </summary> | ||
71 | /// <remarks> | ||
72 | /// Some of these are not relevant to OpenSimulator since it is architected differently to other simulators | ||
73 | /// (e.g. script instructions aren't executed as part of the frame loop so 'script time' is tricky). | ||
74 | /// </remarks> | ||
75 | public enum Stats : uint | ||
76 | { | ||
77 | TimeDilation = 0, | ||
78 | SimFPS = 1, | ||
79 | PhysicsFPS = 2, | ||
80 | AgentUpdates = 3, | ||
81 | FrameMS = 4, | ||
82 | NetMS = 5, | ||
83 | OtherMS = 6, | ||
84 | PhysicsMS = 7, | ||
85 | AgentMS = 8, | ||
86 | ImageMS = 9, | ||
87 | ScriptMS = 10, | ||
88 | TotalPrim = 11, | ||
89 | ActivePrim = 12, | ||
90 | Agents = 13, | ||
91 | ChildAgents = 14, | ||
92 | ActiveScripts = 15, | ||
93 | ScriptLinesPerSecond = 16, | ||
94 | InPacketsPerSecond = 17, | ||
95 | OutPacketsPerSecond = 18, | ||
96 | PendingDownloads = 19, | ||
97 | PendingUploads = 20, | ||
98 | VirtualSizeKb = 21, | ||
99 | ResidentSizeKb = 22, | ||
100 | PendingLocalUploads = 23, | ||
101 | UnAckedBytes = 24, | ||
102 | PhysicsPinnedTasks = 25, | ||
103 | PhysicsLodTasks = 26, | ||
104 | SimPhysicsStepMs = 27, | ||
105 | SimPhysicsShapeMs = 28, | ||
106 | SimPhysicsOtherMs = 29, | ||
107 | SimPhysicsMemory = 30, | ||
108 | ScriptEps = 31, | ||
109 | SimSpareMs = 32, | ||
110 | SimSleepMs = 33, | ||
111 | SimIoPumpTime = 34, | ||
112 | FrameDilation = 35, | ||
113 | UsersLoggingIn = 36, | ||
114 | TotalGeoPrim = 37, | ||
115 | TotalMesh = 38, | ||
116 | ThreadCount = 39 | ||
117 | } | ||
118 | |||
119 | /// <summary> | ||
120 | /// This is for llGetRegionFPS | ||
121 | /// </summary> | ||
122 | public float LastReportedSimFPS | ||
123 | { | ||
124 | get { return lastReportedSimFPS; } | ||
125 | } | ||
126 | |||
127 | /// <summary> | ||
128 | /// Number of object updates performed in the last stats cycle | ||
129 | /// </summary> | ||
130 | /// <remarks> | ||
131 | /// This isn't sent out to the client but it is very useful data to detect whether viewers are being sent a | ||
132 | /// large number of object updates. | ||
133 | /// </remarks> | ||
134 | public float LastReportedObjectUpdates { get; private set; } | ||
135 | |||
136 | public float[] LastReportedSimStats | ||
137 | { | ||
138 | get { return lastReportedSimStats; } | ||
139 | } | ||
140 | |||
141 | /// <summary> | ||
142 | /// Number of frames that have taken longer to process than Scene.MIN_FRAME_TIME | ||
143 | /// </summary> | ||
144 | public Stat SlowFramesStat { get; private set; } | ||
145 | |||
146 | /// <summary> | ||
147 | /// The threshold at which we log a slow frame. | ||
148 | /// </summary> | ||
149 | public int SlowFramesStatReportThreshold { get; private set; } | ||
150 | |||
151 | /// <summary> | ||
152 | /// Extra sim statistics that are used by monitors but not sent to the client. | ||
153 | /// </summary> | ||
154 | /// <value> | ||
155 | /// The keys are the stat names. | ||
156 | /// </value> | ||
157 | private Dictionary<string, float> m_lastReportedExtraSimStats = new Dictionary<string, float>(); | ||
158 | |||
159 | // Sending a stats update every 3 seconds- | ||
160 | private int m_statsUpdatesEveryMS = 3000; | ||
161 | private float m_statsUpdateFactor; | ||
162 | private float m_timeDilation; | ||
163 | private int m_fps; | ||
164 | |||
165 | /// <summary> | ||
166 | /// Number of the last frame on which we processed a stats udpate. | ||
167 | /// </summary> | ||
168 | private uint m_lastUpdateFrame; | ||
169 | |||
170 | /// <summary> | ||
171 | /// Our nominal fps target, as expected in fps stats when a sim is running normally. | ||
172 | /// </summary> | ||
173 | private float m_nominalReportedFps = 55; | ||
174 | |||
175 | /// <summary> | ||
176 | /// Parameter to adjust reported scene fps | ||
177 | /// </summary> | ||
178 | /// <remarks> | ||
179 | /// Our scene loop runs slower than other server implementations, apparantly because we work somewhat differently. | ||
180 | /// However, we will still report an FPS that's closer to what people are used to seeing. A lower FPS might | ||
181 | /// affect clients and monitoring scripts/software. | ||
182 | /// </remarks> | ||
183 | private float m_reportedFpsCorrectionFactor = 5; | ||
184 | |||
185 | // saved last reported value so there is something available for llGetRegionFPS | ||
186 | private float lastReportedSimFPS; | ||
187 | private float[] lastReportedSimStats = new float[m_statisticArraySize]; | ||
188 | private float m_pfps; | ||
189 | |||
190 | /// <summary> | ||
191 | /// Number of agent updates requested in this stats cycle | ||
192 | /// </summary> | ||
193 | private int m_agentUpdates; | ||
194 | |||
195 | /// <summary> | ||
196 | /// Number of object updates requested in this stats cycle | ||
197 | /// </summary> | ||
198 | private int m_objectUpdates; | ||
199 | |||
200 | private int m_frameMS; | ||
201 | private int m_spareMS; | ||
202 | private int m_netMS; | ||
203 | private int m_agentMS; | ||
204 | private int m_physicsMS; | ||
205 | private int m_imageMS; | ||
206 | private int m_otherMS; | ||
207 | private int m_scriptMS; | ||
208 | |||
209 | private int m_rootAgents; | ||
210 | private int m_childAgents; | ||
211 | private int m_numPrim; | ||
212 | private int m_numGeoPrim; | ||
213 | private int m_numMesh; | ||
214 | private int m_inPacketsPerSecond; | ||
215 | private int m_outPacketsPerSecond; | ||
216 | private int m_activePrim; | ||
217 | private int m_unAckedBytes; | ||
218 | private int m_pendingDownloads; | ||
219 | private int m_pendingUploads = 0; // FIXME: Not currently filled in | ||
220 | private int m_activeScripts; | ||
221 | private int m_scriptLinesPerSecond; | ||
222 | |||
223 | private int m_objectCapacity = 45000; | ||
224 | |||
225 | // This is the number of frames that will be stored and then averaged for | ||
226 | // the Total, Simulation, Physics, and Network Frame Time; It is set to | ||
227 | // 10 by default but can be changed by the OpenSim.ini configuration file | ||
228 | // NumberOfFrames parameter | ||
229 | private int m_numberFramesStored; | ||
230 | |||
231 | // The arrays that will hold the time it took to run the past N frames, | ||
232 | // where N is the num_frames_to_average given by the configuration file | ||
233 | private double[] m_totalFrameTimeMilliseconds; | ||
234 | private double[] m_simulationFrameTimeMilliseconds; | ||
235 | private double[] m_physicsFrameTimeMilliseconds; | ||
236 | private double[] m_networkFrameTimeMilliseconds; | ||
237 | |||
238 | // The location of the next time in milliseconds that will be | ||
239 | // (over)written when the next frame completes | ||
240 | private int m_nextLocation = 0; | ||
241 | |||
242 | // The correct number of frames that have completed since the last stats | ||
243 | // update for physics | ||
244 | private int m_numberPhysicsFrames; | ||
245 | |||
246 | // The current number of users attempting to login to the region | ||
247 | private int m_usersLoggingIn; | ||
248 | |||
249 | // The last reported value of threads from the SmartThreadPool inside of | ||
250 | // XEngine | ||
251 | private int m_inUseThreads; | ||
252 | |||
253 | private Scene m_scene; | ||
254 | |||
255 | private RegionInfo ReportingRegion; | ||
256 | |||
257 | private Timer m_report = new Timer(); | ||
258 | |||
259 | private IEstateModule estateModule; | ||
260 | |||
261 | public SimStatsReporter(Scene scene) | ||
262 | : this(scene, Scene.m_defaultNumberFramesStored) | ||
263 | { | ||
264 | } | ||
265 | |||
266 | public SimStatsReporter(Scene scene, int numberOfFrames) | ||
267 | { | ||
268 | // Store the number of frames from the OpenSim.ini configuration file | ||
269 | m_numberFramesStored = numberOfFrames; | ||
270 | |||
271 | // Initialize the different frame time arrays to the correct sizes | ||
272 | m_totalFrameTimeMilliseconds = new double[m_numberFramesStored]; | ||
273 | m_simulationFrameTimeMilliseconds = new double[m_numberFramesStored]; | ||
274 | m_physicsFrameTimeMilliseconds = new double[m_numberFramesStored]; | ||
275 | m_networkFrameTimeMilliseconds = new double[m_numberFramesStored]; | ||
276 | |||
277 | // Initialize the current number of users logging into the region | ||
278 | m_usersLoggingIn = 0; | ||
279 | |||
280 | m_scene = scene; | ||
281 | m_reportedFpsCorrectionFactor = scene.MinFrameSeconds * m_nominalReportedFps; | ||
282 | m_statsUpdateFactor = (float)(m_statsUpdatesEveryMS / 1000); | ||
283 | ReportingRegion = scene.RegionInfo; | ||
284 | |||
285 | m_objectCapacity = scene.RegionInfo.ObjectCapacity; | ||
286 | m_report.AutoReset = true; | ||
287 | m_report.Interval = m_statsUpdatesEveryMS; | ||
288 | m_report.Elapsed += TriggerStatsHeartbeat; | ||
289 | m_report.Enabled = true; | ||
290 | |||
291 | if (StatsManager.SimExtraStats != null) | ||
292 | OnSendStatsResult += StatsManager.SimExtraStats.ReceiveClassicSimStatsPacket; | ||
293 | |||
294 | /// At the moment, we'll only report if a frame is over 120% of target, since commonly frames are a bit | ||
295 | /// longer than ideal (which in itself is a concern). | ||
296 | SlowFramesStatReportThreshold = (int)Math.Ceiling(scene.MinFrameTicks * 1.2); | ||
297 | |||
298 | SlowFramesStat | ||
299 | = new Stat( | ||
300 | "SlowFrames", | ||
301 | "Slow Frames", | ||
302 | "Number of frames where frame time has been significantly longer than the desired frame time.", | ||
303 | " frames", | ||
304 | "scene", | ||
305 | m_scene.Name, | ||
306 | StatType.Push, | ||
307 | null, | ||
308 | StatVerbosity.Info); | ||
309 | |||
310 | StatsManager.RegisterStat(SlowFramesStat); | ||
311 | |||
312 | } | ||
313 | |||
314 | |||
315 | public void Close() | ||
316 | { | ||
317 | m_report.Elapsed -= TriggerStatsHeartbeat; | ||
318 | m_report.Close(); | ||
319 | } | ||
320 | |||
321 | /// <summary> | ||
322 | /// Sets the number of milliseconds between stat updates. | ||
323 | /// </summary> | ||
324 | /// <param name='ms'></param> | ||
325 | public void SetUpdateMS(int ms) | ||
326 | { | ||
327 | m_statsUpdatesEveryMS = ms; | ||
328 | m_statsUpdateFactor = (float)(m_statsUpdatesEveryMS / 1000); | ||
329 | m_report.Interval = m_statsUpdatesEveryMS; | ||
330 | } | ||
331 | |||
332 | private void TriggerStatsHeartbeat(object sender, EventArgs args) | ||
333 | { | ||
334 | try | ||
335 | { | ||
336 | statsHeartBeat(sender, args); | ||
337 | } | ||
338 | catch (Exception e) | ||
339 | { | ||
340 | m_log.Warn(string.Format( | ||
341 | "[SIM STATS REPORTER] Update for {0} failed with exception ", | ||
342 | m_scene.RegionInfo.RegionName), e); | ||
343 | } | ||
344 | } | ||
345 | |||
346 | private void statsHeartBeat(object sender, EventArgs e) | ||
347 | { | ||
348 | double totalSumFrameTime; | ||
349 | double simulationSumFrameTime; | ||
350 | double physicsSumFrameTime; | ||
351 | double networkSumFrameTime; | ||
352 | float frameDilation; | ||
353 | int currentFrame; | ||
354 | |||
355 | if (!m_scene.Active) | ||
356 | return; | ||
357 | |||
358 | // Create arrays to hold the statistics for this current scene, | ||
359 | // these will be passed to the SimExtraStatsCollector, they are also | ||
360 | // sent to the SimStats class | ||
361 | SimStatsPacket.StatBlock[] sb = new | ||
362 | SimStatsPacket.StatBlock[m_statisticArraySize]; | ||
363 | SimStatsPacket.RegionBlock rb = new SimStatsPacket.RegionBlock(); | ||
364 | |||
365 | // Know what's not thread safe in Mono... modifying timers. | ||
366 | // m_log.Debug("Firing Stats Heart Beat"); | ||
367 | lock (m_report) | ||
368 | { | ||
369 | uint regionFlags = 0; | ||
370 | |||
371 | try | ||
372 | { | ||
373 | if (estateModule == null) | ||
374 | estateModule = m_scene.RequestModuleInterface<IEstateModule>(); | ||
375 | regionFlags = estateModule != null ? estateModule.GetRegionFlags() : (uint) 0; | ||
376 | } | ||
377 | catch (Exception) | ||
378 | { | ||
379 | // leave region flags at 0 | ||
380 | } | ||
381 | |||
382 | #region various statistic googly moogly | ||
383 | |||
384 | // ORIGINAL code commented out until we have time to add our own | ||
385 | // statistics to the statistics window, this will be done as a | ||
386 | // new section given the title of our current project | ||
387 | // We're going to lie about the FPS because we've been lying since 2008. The actual FPS is currently | ||
388 | // locked at a maximum of 11. Maybe at some point this can change so that we're not lying. | ||
389 | //int reportedFPS = (int)(m_fps * m_reportedFpsCorrectionFactor); | ||
390 | int reportedFPS = m_fps; | ||
391 | |||
392 | // save the reported value so there is something available for llGetRegionFPS | ||
393 | lastReportedSimFPS = reportedFPS / m_statsUpdateFactor; | ||
394 | |||
395 | // ORIGINAL code commented out until we have time to add our own | ||
396 | // statistics to the statistics window | ||
397 | //float physfps = ((m_pfps / 1000)); | ||
398 | float physfps = m_numberPhysicsFrames; | ||
399 | |||
400 | //if (physfps > 600) | ||
401 | //physfps = physfps - (physfps - 600); | ||
402 | |||
403 | if (physfps < 0) | ||
404 | physfps = 0; | ||
405 | |||
406 | #endregion | ||
407 | |||
408 | m_rootAgents = m_scene.SceneGraph.GetRootAgentCount(); | ||
409 | m_childAgents = m_scene.SceneGraph.GetChildAgentCount(); | ||
410 | m_numPrim = m_scene.SceneGraph.GetTotalObjectsCount(); | ||
411 | m_numGeoPrim = m_scene.SceneGraph.GetTotalPrimObjectsCount(); | ||
412 | m_numMesh = m_scene.SceneGraph.GetTotalMeshObjectsCount(); | ||
413 | m_activePrim = m_scene.SceneGraph.GetActiveObjectsCount(); | ||
414 | m_activeScripts = m_scene.SceneGraph.GetActiveScriptsCount(); | ||
415 | |||
416 | // FIXME: Checking for stat sanity is a complex approach. What we really need to do is fix the code | ||
417 | // so that stat numbers are always consistent. | ||
418 | CheckStatSanity(); | ||
419 | |||
420 | //Our time dilation is 0.91 when we're running a full speed, | ||
421 | // therefore to make sure we get an appropriate range, | ||
422 | // we have to factor in our error. (0.10f * statsUpdateFactor) | ||
423 | // multiplies the fix for the error times the amount of times it'll occur a second | ||
424 | // / 10 divides the value by the number of times the sim heartbeat runs (10fps) | ||
425 | // Then we divide the whole amount by the amount of seconds pass in between stats updates. | ||
426 | |||
427 | // 'statsUpdateFactor' is how often stats packets are sent in seconds. Used below to change | ||
428 | // values to X-per-second values. | ||
429 | |||
430 | uint thisFrame = m_scene.Frame; | ||
431 | uint numFrames = thisFrame - m_lastUpdateFrame; | ||
432 | float framesUpdated = (float)numFrames * m_reportedFpsCorrectionFactor; | ||
433 | m_lastUpdateFrame = thisFrame; | ||
434 | |||
435 | // Avoid div-by-zero if somehow we've not updated any frames. | ||
436 | if (framesUpdated == 0) | ||
437 | framesUpdated = 1; | ||
438 | |||
439 | for (int i = 0; i < m_statisticArraySize; i++) | ||
440 | { | ||
441 | sb[i] = new SimStatsPacket.StatBlock(); | ||
442 | } | ||
443 | |||
444 | // Resetting the sums of the frame times to prevent any errors | ||
445 | // in calculating the moving average for frame time | ||
446 | totalSumFrameTime = 0; | ||
447 | simulationSumFrameTime = 0; | ||
448 | physicsSumFrameTime = 0; | ||
449 | networkSumFrameTime = 0; | ||
450 | |||
451 | // Loop through all the frames that were stored for the current | ||
452 | // heartbeat to process the moving average of frame times | ||
453 | for (int i = 0; i < m_numberFramesStored; i++) | ||
454 | { | ||
455 | // Sum up each frame time in order to calculate the moving | ||
456 | // average of frame time | ||
457 | totalSumFrameTime += m_totalFrameTimeMilliseconds[i]; | ||
458 | simulationSumFrameTime += | ||
459 | m_simulationFrameTimeMilliseconds[i]; | ||
460 | physicsSumFrameTime += m_physicsFrameTimeMilliseconds[i]; | ||
461 | networkSumFrameTime += m_networkFrameTimeMilliseconds[i]; | ||
462 | } | ||
463 | |||
464 | // Get the index that represents the current frame based on the next one known; go back | ||
465 | // to the last index if next one is stated to restart at 0 | ||
466 | if (m_nextLocation == 0) | ||
467 | currentFrame = m_numberFramesStored - 1; | ||
468 | else | ||
469 | currentFrame = m_nextLocation - 1; | ||
470 | |||
471 | // Calculate the frame dilation; which is currently based on the ratio between the sum of the | ||
472 | // physics and simulation rate, and the set minimum time to run a scene's frame | ||
473 | frameDilation = (float)(m_simulationFrameTimeMilliseconds[currentFrame] + | ||
474 | m_physicsFrameTimeMilliseconds[currentFrame]) / m_scene.MinFrameTicks; | ||
475 | |||
476 | // ORIGINAL code commented out until we have time to add our own | ||
477 | sb[0].StatID = (uint) Stats.TimeDilation; | ||
478 | sb[0].StatValue = (Single.IsNaN(m_timeDilation)) ? 0.1f : m_timeDilation ; //((((m_timeDilation + (0.10f * statsUpdateFactor)) /10) / statsUpdateFactor)); | ||
479 | |||
480 | sb[1].StatID = (uint) Stats.SimFPS; | ||
481 | sb[1].StatValue = reportedFPS / m_statsUpdateFactor; | ||
482 | |||
483 | sb[2].StatID = (uint) Stats.PhysicsFPS; | ||
484 | sb[2].StatValue = physfps / m_statsUpdateFactor; | ||
485 | |||
486 | sb[3].StatID = (uint) Stats.AgentUpdates; | ||
487 | sb[3].StatValue = (m_agentUpdates / m_statsUpdateFactor); | ||
488 | |||
489 | sb[4].StatID = (uint) Stats.Agents; | ||
490 | sb[4].StatValue = m_rootAgents; | ||
491 | |||
492 | sb[5].StatID = (uint) Stats.ChildAgents; | ||
493 | sb[5].StatValue = m_childAgents; | ||
494 | |||
495 | sb[6].StatID = (uint) Stats.TotalPrim; | ||
496 | sb[6].StatValue = m_numPrim; | ||
497 | |||
498 | sb[7].StatID = (uint) Stats.ActivePrim; | ||
499 | sb[7].StatValue = m_activePrim; | ||
500 | |||
501 | // ORIGINAL code commented out until we have time to add our own | ||
502 | // statistics to the statistics window | ||
503 | sb[8].StatID = (uint)Stats.FrameMS; | ||
504 | //sb[8].StatValue = m_frameMS / framesUpdated; | ||
505 | sb[8].StatValue = (float) totalSumFrameTime / m_numberFramesStored; | ||
506 | |||
507 | sb[9].StatID = (uint)Stats.NetMS; | ||
508 | //sb[9].StatValue = m_netMS / framesUpdated; | ||
509 | sb[9].StatValue = (float) networkSumFrameTime / m_numberFramesStored; | ||
510 | |||
511 | sb[10].StatID = (uint)Stats.PhysicsMS; | ||
512 | //sb[10].StatValue = m_physicsMS / framesUpdated; | ||
513 | sb[10].StatValue = (float) physicsSumFrameTime / m_numberFramesStored; | ||
514 | |||
515 | sb[11].StatID = (uint)Stats.ImageMS ; | ||
516 | sb[11].StatValue = m_imageMS / framesUpdated; | ||
517 | |||
518 | sb[12].StatID = (uint)Stats.OtherMS; | ||
519 | //sb[12].StatValue = m_otherMS / framesUpdated; | ||
520 | sb[12].StatValue = (float) simulationSumFrameTime / m_numberFramesStored; | ||
521 | |||
522 | sb[13].StatID = (uint)Stats.InPacketsPerSecond; | ||
523 | sb[13].StatValue = (m_inPacketsPerSecond / m_statsUpdateFactor); | ||
524 | |||
525 | sb[14].StatID = (uint)Stats.OutPacketsPerSecond; | ||
526 | sb[14].StatValue = (m_outPacketsPerSecond / m_statsUpdateFactor); | ||
527 | |||
528 | sb[15].StatID = (uint)Stats.UnAckedBytes; | ||
529 | sb[15].StatValue = m_unAckedBytes; | ||
530 | |||
531 | sb[16].StatID = (uint)Stats.AgentMS; | ||
532 | sb[16].StatValue = m_agentMS / framesUpdated; | ||
533 | |||
534 | sb[17].StatID = (uint)Stats.PendingDownloads; | ||
535 | sb[17].StatValue = m_pendingDownloads; | ||
536 | |||
537 | sb[18].StatID = (uint)Stats.PendingUploads; | ||
538 | sb[18].StatValue = m_pendingUploads; | ||
539 | |||
540 | sb[19].StatID = (uint)Stats.ActiveScripts; | ||
541 | sb[19].StatValue = m_activeScripts; | ||
542 | |||
543 | sb[20].StatID = (uint)Stats.ScriptLinesPerSecond; | ||
544 | sb[20].StatValue = m_scriptLinesPerSecond / m_statsUpdateFactor; | ||
545 | |||
546 | sb[21].StatID = (uint)Stats.SimSpareMs; | ||
547 | sb[21].StatValue = m_spareMS / framesUpdated; | ||
548 | |||
549 | // Current ratio between the sum of physics and sim rate, and the | ||
550 | // minimum time to run a scene's frame | ||
551 | sb[22].StatID = (uint)Stats.FrameDilation; | ||
552 | sb[22].StatValue = frameDilation; | ||
553 | |||
554 | // Current number of users currently attemptint to login to region | ||
555 | sb[23].StatID = (uint)Stats.UsersLoggingIn; | ||
556 | sb[23].StatValue = m_usersLoggingIn; | ||
557 | |||
558 | // Total number of geometric primitives in the scene | ||
559 | sb[24].StatID = (uint)Stats.TotalGeoPrim; | ||
560 | sb[24].StatValue = m_numGeoPrim; | ||
561 | |||
562 | // Total number of mesh objects in the scene | ||
563 | sb[25].StatID = (uint)Stats.TotalMesh; | ||
564 | sb[25].StatValue = m_numMesh; | ||
565 | |||
566 | // Current number of threads that XEngine is using | ||
567 | sb[26].StatID = (uint)Stats.ThreadCount; | ||
568 | sb[26].StatValue = m_inUseThreads; | ||
569 | |||
570 | sb[27].StatID = (uint)Stats.ScriptMS; | ||
571 | sb[27].StatValue = (numFrames <= 0) ? 0 : ((float)m_scriptMS / numFrames); | ||
572 | |||
573 | for (int i = 0; i < m_statisticArraySize; i++) | ||
574 | { | ||
575 | lastReportedSimStats[i] = sb[i].StatValue; | ||
576 | } | ||
577 | |||
578 | SimStats simStats | ||
579 | = new SimStats( | ||
580 | ReportingRegion.RegionLocX, ReportingRegion.RegionLocY, regionFlags, (uint)m_objectCapacity, | ||
581 | rb, sb, m_scene.RegionInfo.originRegionID); | ||
582 | |||
583 | handlerSendStatResult = OnSendStatsResult; | ||
584 | if (handlerSendStatResult != null) | ||
585 | { | ||
586 | handlerSendStatResult(simStats); | ||
587 | } | ||
588 | |||
589 | // Extra statistics that aren't currently sent to clients | ||
590 | lock (m_lastReportedExtraSimStats) | ||
591 | { | ||
592 | m_lastReportedExtraSimStats[LastReportedObjectUpdateStatName] = m_objectUpdates / m_statsUpdateFactor; | ||
593 | m_lastReportedExtraSimStats[SlowFramesStat.ShortName] = (float)SlowFramesStat.Value; | ||
594 | |||
595 | Dictionary<string, float> physicsStats = m_scene.PhysicsScene.GetStats(); | ||
596 | |||
597 | if (physicsStats != null) | ||
598 | { | ||
599 | foreach (KeyValuePair<string, float> tuple in physicsStats) | ||
600 | { | ||
601 | // FIXME: An extremely dirty hack to divide MS stats per frame rather than per second | ||
602 | // Need to change things so that stats source can indicate whether they are per second or | ||
603 | // per frame. | ||
604 | if (tuple.Key.EndsWith("MS")) | ||
605 | m_lastReportedExtraSimStats[tuple.Key] = tuple.Value / framesUpdated; | ||
606 | else | ||
607 | m_lastReportedExtraSimStats[tuple.Key] = tuple.Value / m_statsUpdateFactor; | ||
608 | } | ||
609 | } | ||
610 | } | ||
611 | |||
612 | ResetValues(); | ||
613 | } | ||
614 | } | ||
615 | |||
616 | private void ResetValues() | ||
617 | { | ||
618 | // Reset the number of frames that the physics library has | ||
619 | // processed since the last stats report | ||
620 | m_numberPhysicsFrames = 0; | ||
621 | |||
622 | m_timeDilation = 0; | ||
623 | m_fps = 0; | ||
624 | m_pfps = 0; | ||
625 | m_agentUpdates = 0; | ||
626 | m_objectUpdates = 0; | ||
627 | //m_inPacketsPerSecond = 0; | ||
628 | //m_outPacketsPerSecond = 0; | ||
629 | m_unAckedBytes = 0; | ||
630 | m_scriptLinesPerSecond = 0; | ||
631 | |||
632 | m_frameMS = 0; | ||
633 | m_agentMS = 0; | ||
634 | m_netMS = 0; | ||
635 | m_physicsMS = 0; | ||
636 | m_imageMS = 0; | ||
637 | m_otherMS = 0; | ||
638 | m_scriptMS = 0; | ||
639 | m_spareMS = 0; | ||
640 | } | ||
641 | |||
642 | # region methods called from Scene | ||
643 | // The majority of these functions are additive | ||
644 | // so that you can easily change the amount of | ||
645 | // seconds in between sim stats updates | ||
646 | |||
647 | public void AddTimeDilation(float td) | ||
648 | { | ||
649 | //float tdsetting = td; | ||
650 | //if (tdsetting > 1.0f) | ||
651 | //tdsetting = (tdsetting - (tdsetting - 0.91f)); | ||
652 | |||
653 | //if (tdsetting < 0) | ||
654 | //tdsetting = 0.0f; | ||
655 | m_timeDilation = td; | ||
656 | } | ||
657 | |||
658 | internal void CheckStatSanity() | ||
659 | { | ||
660 | if (m_rootAgents < 0 || m_childAgents < 0) | ||
661 | { | ||
662 | handlerStatsIncorrect = OnStatsIncorrect; | ||
663 | if (handlerStatsIncorrect != null) | ||
664 | { | ||
665 | handlerStatsIncorrect(); | ||
666 | } | ||
667 | } | ||
668 | if (m_rootAgents == 0 && m_childAgents == 0) | ||
669 | { | ||
670 | m_unAckedBytes = 0; | ||
671 | } | ||
672 | } | ||
673 | |||
674 | public void AddFPS(int frames) | ||
675 | { | ||
676 | m_fps += frames; | ||
677 | } | ||
678 | |||
679 | public void AddPhysicsFPS(float frames) | ||
680 | { | ||
681 | m_pfps += frames; | ||
682 | } | ||
683 | |||
684 | public void AddObjectUpdates(int numUpdates) | ||
685 | { | ||
686 | m_objectUpdates += numUpdates; | ||
687 | } | ||
688 | |||
689 | public void AddAgentUpdates(int numUpdates) | ||
690 | { | ||
691 | m_agentUpdates += numUpdates; | ||
692 | } | ||
693 | |||
694 | public void AddInPackets(int numPackets) | ||
695 | { | ||
696 | m_inPacketsPerSecond = numPackets; | ||
697 | } | ||
698 | |||
699 | public void AddOutPackets(int numPackets) | ||
700 | { | ||
701 | m_outPacketsPerSecond = numPackets; | ||
702 | } | ||
703 | |||
704 | public void AddunAckedBytes(int numBytes) | ||
705 | { | ||
706 | m_unAckedBytes += numBytes; | ||
707 | if (m_unAckedBytes < 0) m_unAckedBytes = 0; | ||
708 | } | ||
709 | |||
710 | public void addFrameMS(int ms) | ||
711 | { | ||
712 | m_frameMS += ms; | ||
713 | |||
714 | // At the moment, we'll only report if a frame is over 120% of target, since commonly frames are a bit | ||
715 | // longer than ideal due to the inaccuracy of the Sleep in Scene.Update() (which in itself is a concern). | ||
716 | if (ms > SlowFramesStatReportThreshold) | ||
717 | SlowFramesStat.Value++; | ||
718 | } | ||
719 | |||
720 | public void AddSpareMS(int ms) | ||
721 | { | ||
722 | m_spareMS += ms; | ||
723 | } | ||
724 | |||
725 | public void addNetMS(int ms) | ||
726 | { | ||
727 | m_netMS += ms; | ||
728 | } | ||
729 | |||
730 | public void addAgentMS(int ms) | ||
731 | { | ||
732 | m_agentMS += ms; | ||
733 | } | ||
734 | |||
735 | public void addPhysicsMS(int ms) | ||
736 | { | ||
737 | m_physicsMS += ms; | ||
738 | } | ||
739 | |||
740 | public void addImageMS(int ms) | ||
741 | { | ||
742 | m_imageMS += ms; | ||
743 | } | ||
744 | |||
745 | public void addOtherMS(int ms) | ||
746 | { | ||
747 | m_otherMS += ms; | ||
748 | } | ||
749 | |||
750 | public void AddScriptMS(int ms) | ||
751 | { | ||
752 | m_scriptMS += ms; | ||
753 | } | ||
754 | |||
755 | public void addPhysicsFrame(int frames) | ||
756 | { | ||
757 | // Add the number of physics frames to the correct total physics | ||
758 | // frames | ||
759 | m_numberPhysicsFrames += frames; | ||
760 | } | ||
761 | |||
762 | public void addFrameTimeMilliseconds(double total, double simulation, | ||
763 | double physics, double network) | ||
764 | { | ||
765 | // Save the frame times from the current frame into the appropriate | ||
766 | // arrays | ||
767 | m_totalFrameTimeMilliseconds[m_nextLocation] = total; | ||
768 | m_simulationFrameTimeMilliseconds[m_nextLocation] = simulation; | ||
769 | m_physicsFrameTimeMilliseconds[m_nextLocation] = physics; | ||
770 | m_networkFrameTimeMilliseconds[m_nextLocation] = network; | ||
771 | |||
772 | // Update to the next location in the list | ||
773 | m_nextLocation++; | ||
774 | |||
775 | // Since the list will begin to overwrite the oldest frame values | ||
776 | // first, the next location needs to loop back to the beginning of the | ||
777 | // list whenever it reaches the end | ||
778 | m_nextLocation = m_nextLocation % m_numberFramesStored; | ||
779 | } | ||
780 | |||
781 | public void AddPendingDownloads(int count) | ||
782 | { | ||
783 | m_pendingDownloads += count; | ||
784 | |||
785 | if (m_pendingDownloads < 0) | ||
786 | m_pendingDownloads = 0; | ||
787 | |||
788 | //m_log.InfoFormat("[stats]: Adding {0} to pending downloads to make {1}", count, m_pendingDownloads); | ||
789 | } | ||
790 | |||
791 | public void addScriptLines(int count) | ||
792 | { | ||
793 | m_scriptLinesPerSecond += count; | ||
794 | } | ||
795 | |||
796 | public void AddPacketsStats(int inPackets, int outPackets, int unAckedBytes) | ||
797 | { | ||
798 | AddInPackets(inPackets); | ||
799 | AddOutPackets(outPackets); | ||
800 | AddunAckedBytes(unAckedBytes); | ||
801 | } | ||
802 | |||
803 | public void UpdateUsersLoggingIn(bool isLoggingIn) | ||
804 | { | ||
805 | // Determine whether the user has started logging in or has completed | ||
806 | // logging into the region | ||
807 | if (isLoggingIn) | ||
808 | { | ||
809 | // The user is starting to login to the region so increment the | ||
810 | // number of users attempting to login to the region | ||
811 | m_usersLoggingIn++; | ||
812 | } | ||
813 | else | ||
814 | { | ||
815 | // The user has finished logging into the region so decrement the | ||
816 | // number of users logging into the region | ||
817 | m_usersLoggingIn--; | ||
818 | } | ||
819 | } | ||
820 | |||
821 | public void SetThreadCount(int inUseThreads) | ||
822 | { | ||
823 | // Save the new number of threads to our member variable to send to | ||
824 | // the extra stats collector | ||
825 | m_inUseThreads = inUseThreads; | ||
826 | } | ||
827 | |||
828 | #endregion | ||
829 | |||
830 | public Dictionary<string, float> GetExtraSimStats() | ||
831 | { | ||
832 | lock (m_lastReportedExtraSimStats) | ||
833 | return new Dictionary<string, float>(m_lastReportedExtraSimStats); | ||
834 | } | ||
835 | } | ||
836 | } | ||