Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Add experimental "slow frames" stat, available in "show stats" and vi…

…a the monitoring module.

This increments a SlowFrames counter if a frame takes over 120% of maximum time.
This commit also introduces a generic OpenSim.Framework.Monitoring.Stat which is available to any code that wants to register a statistic.
This is more granualar than asking objects to create their own reports.
At some point this will supersede earlier IMonitor and IAlert facilities in MonitoringModule which are only available to scene code.
  • Loading branch information...
commit e717398f6c72bdb30e59468462f3a5f589c1bb35 1 parent a2ab3b8
Justin Clark-Casey authored October 04, 2012
13  OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs
@@ -355,10 +355,19 @@ public override string Report()
355 355
             sb.Append(Environment.NewLine);
356 356
             sb.Append(
357 357
                 string.Format(
358  
-                    "{0,6:0}  {1,6:0}  {2,6:0}  {3,6:0}  {4,6:0}  {5,6:0.0}  {6,6:0.0}  {7,6:0.0}  {8,6:0.0}  {9,6:0.0}  {10,6:0.0}",
  358
+                    "{0,6:0}  {1,6:0}  {2,6:0}  {3,6:0}  {4,6:0}  {5,6:0.0}  {6,6:0.0}  {7,6:0.0}  {8,6:0.0}  {9,6:0.0}  {10,6:0.0}\n\n",
359 359
                     inPacketsPerSecond, outPacketsPerSecond, pendingDownloads, pendingUploads, unackedBytes, totalFrameTime,
360 360
                     netFrameTime, physicsFrameTime, otherFrameTime, agentFrameTime, imageFrameTime));
361  
-            sb.Append(Environment.NewLine);
  361
+
  362
+            foreach (KeyValuePair<string, Stat> kvp in StatsManager.RegisteredStats)
  363
+            {
  364
+                Stat stat = kvp.Value;
  365
+
  366
+                if (stat.Category == "scene" && stat.Verbosity == StatVerbosity.Info)
  367
+                {
  368
+                    sb.AppendFormat("Slow frames ({0}): {1}\n", stat.Container, stat.Value);
  369
+                }
  370
+            }
362 371
 
363 372
             /*
364 373
             sb.Append(Environment.NewLine);
114  OpenSim/Framework/Monitoring/StatsManager.cs
@@ -25,6 +25,9 @@
25 25
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 26
  */
27 27
 
  28
+using System;
  29
+using System.Collections.Generic;
  30
+
28 31
 namespace OpenSim.Framework.Monitoring
29 32
 {
30 33
     /// <summary>
@@ -32,6 +35,14 @@ namespace OpenSim.Framework.Monitoring
32 35
     /// </summary>
33 36
     public class StatsManager
34 37
     {
  38
+        /// <summary>
  39
+        /// Registered stats.
  40
+        /// </summary>
  41
+        /// <remarks>
  42
+        /// Do not add or remove from this dictionary.
  43
+        /// </remarks>
  44
+        public static Dictionary<string, Stat> RegisteredStats = new Dictionary<string, Stat>();
  45
+
35 46
         private static AssetStatsCollector assetStats;
36 47
         private static UserStatsCollector userStats;
37 48
         private static SimExtraStatsCollector simExtraStats = new SimExtraStatsCollector();
@@ -61,5 +72,108 @@ public static UserStatsCollector StartCollectingUserStats()
61 72
 
62 73
             return userStats;
63 74
         }
  75
+
  76
+        public static bool RegisterStat(Stat stat)
  77
+        {
  78
+            lock (RegisteredStats)
  79
+            {
  80
+                if (RegisteredStats.ContainsKey(stat.UniqueName))
  81
+                {
  82
+                    // XXX: For now just return false.  This is to avoid problems in regression tests where all tests
  83
+                    // in a class are run in the same instance of the VM.
  84
+                    return false;
  85
+
  86
+//                    throw new Exception(
  87
+//                        "StatsManager already contains stat with ShortName {0} in Category {1}", stat.ShortName, stat.Category);
  88
+                }
  89
+
  90
+                // We take a replace-on-write approach here so that we don't need to generate a new Dictionary
  91
+                Dictionary<string, Stat> newRegisteredStats = new Dictionary<string, Stat>(RegisteredStats);
  92
+                newRegisteredStats[stat.UniqueName] = stat;
  93
+                RegisteredStats = newRegisteredStats;
  94
+            }
  95
+
  96
+            return true;
  97
+        }
  98
+
  99
+        public static bool DeregisterStat(Stat stat)
  100
+        {
  101
+            lock (RegisteredStats)
  102
+            {
  103
+                if (!RegisteredStats.ContainsKey(stat.UniqueName))
  104
+                    return false;
  105
+
  106
+                Dictionary<string, Stat> newRegisteredStats = new Dictionary<string, Stat>(RegisteredStats);
  107
+                newRegisteredStats.Remove(stat.UniqueName);
  108
+                RegisteredStats = newRegisteredStats;
  109
+
  110
+                return true;
  111
+            }
  112
+        }
  113
+    }
  114
+
  115
+    /// <summary>
  116
+    /// Verbosity of stat.
  117
+    /// </summary>
  118
+    /// <remarks>
  119
+    /// Info will always be displayed.
  120
+    /// </remarks>
  121
+    public enum StatVerbosity
  122
+    {
  123
+        Debug,
  124
+        Info
  125
+    }
  126
+
  127
+    /// <summary>
  128
+    /// Holds individual static details
  129
+    /// </summary>
  130
+    public class Stat
  131
+    {
  132
+        /// <summary>
  133
+        /// Unique stat name used for indexing.  Each ShortName in a Category must be unique.
  134
+        /// </summary>
  135
+        public string UniqueName { get; private set; }
  136
+
  137
+        /// <summary>
  138
+        /// Category of this stat (e.g. cache, scene, etc).
  139
+        /// </summary>
  140
+        public string Category { get; private set; }
  141
+
  142
+        /// <summary>
  143
+        /// Containing name for this stat.
  144
+        /// FIXME: In the case of a scene, this is currently the scene name (though this leaves
  145
+        /// us with a to-be-resolved problem of non-unique region names).
  146
+        /// </summary>
  147
+        /// <value>
  148
+        /// The container.
  149
+        /// </value>
  150
+        public string Container { get; private set; }
  151
+
  152
+        public StatVerbosity Verbosity { get; private set; }
  153
+        public string ShortName { get; private set; }
  154
+        public string Name { get; private set; }
  155
+        public string Description { get; private set; }
  156
+        public string UnitName { get; private set; }
  157
+
  158
+        public double Value { get; set; }
  159
+
  160
+        public Stat(
  161
+            string shortName, string name, string unitName, string category, string container, StatVerbosity verbosity, string description)
  162
+        {
  163
+            ShortName = shortName;
  164
+            Name = name;
  165
+            UnitName = unitName;
  166
+            Category = category;
  167
+            Container = container;
  168
+            Verbosity = verbosity;
  169
+            Description = description;
  170
+
  171
+            UniqueName = GenUniqueName(Container, Category, ShortName);
  172
+        }
  173
+
  174
+        public static string GenUniqueName(string container, string category, string shortName)
  175
+        {
  176
+            return string.Format("{0}+{1}+{2}", container, category, shortName);
  177
+        }
64 178
     }
65 179
 }
33  OpenSim/Region/Framework/Scenes/SimStatsReporter.cs
@@ -47,6 +47,7 @@ public class SimStatsReporter
47 47
             = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
48 48
 
49 49
         public const string LastReportedObjectUpdateStatName = "LastReportedObjectUpdates";
  50
+        public const string SlowFramesStatName = "SlowFrames";
50 51
 
51 52
         public delegate void SendStatResult(SimStats stats);
52 53
 
@@ -129,6 +130,16 @@ public float[] LastReportedSimStats
129 130
         }
130 131
 
131 132
         /// <summary>
  133
+        /// Number of frames that have taken longer to process than Scene.MIN_FRAME_TIME
  134
+        /// </summary>
  135
+        public Stat SlowFramesStat { get; private set; }
  136
+
  137
+        /// <summary>
  138
+        /// The threshold at which we log a slow frame.
  139
+        /// </summary>
  140
+        public int SlowFramesStatReportThreshold { get; private set; }
  141
+
  142
+        /// <summary>
132 143
         /// Extra sim statistics that are used by monitors but not sent to the client.
133 144
         /// </summary>
134 145
         /// <value>
@@ -225,6 +236,22 @@ public SimStatsReporter(Scene scene)
225 236
 
226 237
             if (StatsManager.SimExtraStats != null)
227 238
                 OnSendStatsResult += StatsManager.SimExtraStats.ReceiveClassicSimStatsPacket;
  239
+
  240
+            /// At the moment, we'll only report if a frame is over 120% of target, since commonly frames are a bit
  241
+            /// longer than ideal (which in itself is a concern).
  242
+            SlowFramesStatReportThreshold = (int)Math.Ceiling(m_scene.MinFrameTime * 1000 * 1.2);
  243
+
  244
+            SlowFramesStat
  245
+                = new Stat(
  246
+                    "SlowFrames",
  247
+                    "Slow Frames",
  248
+                    "frames",
  249
+                    "scene",
  250
+                    m_scene.Name,
  251
+                    StatVerbosity.Info,
  252
+                    "Number of frames where frame time has been significantly longer than the desired frame time.");
  253
+
  254
+            StatsManager.RegisterStat(SlowFramesStat);
228 255
         }
229 256
 
230 257
         public void Close()
@@ -418,6 +445,7 @@ SimStats simStats
418 445
                 lock (m_lastReportedExtraSimStats)
419 446
                 {
420 447
                     m_lastReportedExtraSimStats[LastReportedObjectUpdateStatName] = m_objectUpdates / m_statsUpdateFactor;
  448
+                    m_lastReportedExtraSimStats[SlowFramesStat.ShortName] = (float)SlowFramesStat.Value;
421 449
 
422 450
                     Dictionary<string, float> physicsStats = m_scene.PhysicsScene.GetStats();
423 451
     
@@ -535,6 +563,11 @@ public void AddunAckedBytes(int numBytes)
535 563
         public void addFrameMS(int ms)
536 564
         {
537 565
             m_frameMS += ms;
  566
+
  567
+            // At the moment, we'll only report if a frame is over 120% of target, since commonly frames are a bit
  568
+            // longer than ideal due to the inaccuracy of the Sleep in Scene.Update() (which in itself is a concern).
  569
+            if (ms > SlowFramesStatReportThreshold)
  570
+                SlowFramesStat.Value++;
538 571
         }
539 572
 
540 573
         public void AddSpareMS(int ms)

0 notes on commit e717398

Please sign in to comment.
Something went wrong with that request. Please try again.