aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Framework/Scenes/SimStatsReporter.cs')
-rwxr-xr-xOpenSim/Region/Framework/Scenes/SimStatsReporter.cs836
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
28using System;
29using System.Collections.Generic;
30using System.Timers;
31using OpenMetaverse.Packets;
32using OpenSim.Framework;
33using OpenSim.Framework.Monitoring;
34using OpenSim.Region.Framework.Interfaces;
35
36namespace 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}