aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Framework/Monitoring
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Framework/Monitoring/Properties/AssemblyInfo.cs33
-rw-r--r--OpenSim/Framework/Monitoring/Stats/PercentageStat.cs88
-rw-r--r--OpenSim/Framework/Monitoring/Stats/Stat.cs238
-rw-r--r--OpenSim/Framework/Monitoring/StatsManager.cs150
-rw-r--r--OpenSim/Framework/Monitoring/Watchdog.cs4
5 files changed, 402 insertions, 111 deletions
diff --git a/OpenSim/Framework/Monitoring/Properties/AssemblyInfo.cs b/OpenSim/Framework/Monitoring/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..1f2bb40
--- /dev/null
+++ b/OpenSim/Framework/Monitoring/Properties/AssemblyInfo.cs
@@ -0,0 +1,33 @@
1using System.Reflection;
2using System.Runtime.CompilerServices;
3using System.Runtime.InteropServices;
4
5// General Information about an assembly is controlled through the following
6// set of attributes. Change these attribute values to modify the information
7// associated with an assembly.
8[assembly: AssemblyTitle("OpenSim.Framework.Monitoring")]
9[assembly: AssemblyDescription("")]
10[assembly: AssemblyConfiguration("")]
11[assembly: AssemblyCompany("http://opensimulator.org")]
12[assembly: AssemblyProduct("OpenSim")]
13[assembly: AssemblyCopyright("OpenSimulator developers")]
14[assembly: AssemblyTrademark("")]
15[assembly: AssemblyCulture("")]
16
17// Setting ComVisible to false makes the types in this assembly not visible
18// to COM components. If you need to access a type in this assembly from
19// COM, set the ComVisible attribute to true on that type.
20[assembly: ComVisible(false)]
21
22// The following GUID is for the ID of the typelib if this project is exposed to COM
23[assembly: Guid("74506fe3-2f9d-44c1-94c9-a30f79d9e0cb")]
24
25// Version information for an assembly consists of the following four values:
26//
27// Major Version
28// Minor Version
29// Build Number
30// Revision
31//
32[assembly: AssemblyVersion("0.7.5.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/OpenSim/Framework/Monitoring/Stats/PercentageStat.cs b/OpenSim/Framework/Monitoring/Stats/PercentageStat.cs
new file mode 100644
index 0000000..60bed55
--- /dev/null
+++ b/OpenSim/Framework/Monitoring/Stats/PercentageStat.cs
@@ -0,0 +1,88 @@
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.Text;
31
32namespace OpenSim.Framework.Monitoring
33{
34 public class PercentageStat : Stat
35 {
36 public long Antecedent { get; set; }
37 public long Consequent { get; set; }
38
39 public override double Value
40 {
41 get
42 {
43 // Asking for an update here means that the updater cannot access this value without infinite recursion.
44 // XXX: A slightly messy but simple solution may be to flick a flag so we can tell if this is being
45 // called by the pull action and just return the value.
46 if (StatType == StatType.Pull)
47 PullAction(this);
48
49 long c = Consequent;
50
51 // Avoid any chance of a multi-threaded divide-by-zero
52 if (c == 0)
53 return 0;
54
55 return (double)Antecedent / c * 100;
56 }
57
58 set
59 {
60 throw new InvalidOperationException("Cannot set value on a PercentageStat");
61 }
62 }
63
64 public PercentageStat(
65 string shortName,
66 string name,
67 string description,
68 string category,
69 string container,
70 StatType type,
71 Action<Stat> pullAction,
72 StatVerbosity verbosity)
73 : base(shortName, name, description, "%", category, container, type, pullAction, verbosity) {}
74
75 public override string ToConsoleString()
76 {
77 StringBuilder sb = new StringBuilder();
78
79 sb.AppendFormat(
80 "{0}.{1}.{2} : {3:0.##}{4} ({5}/{6})",
81 Category, Container, ShortName, Value, UnitName, Antecedent, Consequent);
82
83 AppendMeasuresOfInterest(sb);
84
85 return sb.ToString();
86 }
87 }
88} \ No newline at end of file
diff --git a/OpenSim/Framework/Monitoring/Stats/Stat.cs b/OpenSim/Framework/Monitoring/Stats/Stat.cs
new file mode 100644
index 0000000..f91251b
--- /dev/null
+++ b/OpenSim/Framework/Monitoring/Stats/Stat.cs
@@ -0,0 +1,238 @@
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.Text;
31
32namespace OpenSim.Framework.Monitoring
33{
34 /// <summary>
35 /// Holds individual statistic details
36 /// </summary>
37 public class Stat
38 {
39 /// <summary>
40 /// Category of this stat (e.g. cache, scene, etc).
41 /// </summary>
42 public string Category { get; private set; }
43
44 /// <summary>
45 /// Containing name for this stat.
46 /// FIXME: In the case of a scene, this is currently the scene name (though this leaves
47 /// us with a to-be-resolved problem of non-unique region names).
48 /// </summary>
49 /// <value>
50 /// The container.
51 /// </value>
52 public string Container { get; private set; }
53
54 public StatType StatType { get; private set; }
55
56 public MeasuresOfInterest MeasuresOfInterest { get; private set; }
57
58 /// <summary>
59 /// Action used to update this stat when the value is requested if it's a pull type.
60 /// </summary>
61 public Action<Stat> PullAction { get; private set; }
62
63 public StatVerbosity Verbosity { get; private set; }
64 public string ShortName { get; private set; }
65 public string Name { get; private set; }
66 public string Description { get; private set; }
67 public virtual string UnitName { get; private set; }
68
69 public virtual double Value
70 {
71 get
72 {
73 // Asking for an update here means that the updater cannot access this value without infinite recursion.
74 // XXX: A slightly messy but simple solution may be to flick a flag so we can tell if this is being
75 // called by the pull action and just return the value.
76 if (StatType == StatType.Pull)
77 PullAction(this);
78
79 return m_value;
80 }
81
82 set
83 {
84 m_value = value;
85 }
86 }
87
88 private double m_value;
89
90 /// <summary>
91 /// Historical samples for calculating measures of interest average.
92 /// </summary>
93 /// <remarks>
94 /// Will be null if no measures of interest require samples.
95 /// </remarks>
96 private static Queue<double> m_samples;
97
98 /// <summary>
99 /// Maximum number of statistical samples.
100 /// </summary>
101 /// <remarks>
102 /// At the moment this corresponds to 1 minute since the sampling rate is every 2.5 seconds as triggered from
103 /// the main Watchdog.
104 /// </remarks>
105 private static int m_maxSamples = 24;
106
107 public Stat(
108 string shortName,
109 string name,
110 string description,
111 string unitName,
112 string category,
113 string container,
114 StatType type,
115 Action<Stat> pullAction,
116 StatVerbosity verbosity)
117 : this(
118 shortName,
119 name,
120 description,
121 unitName,
122 category,
123 container,
124 type,
125 MeasuresOfInterest.None,
126 pullAction,
127 verbosity)
128 {
129 }
130
131 /// <summary>
132 /// Constructor
133 /// </summary>
134 /// <param name='shortName'>Short name for the stat. Must not contain spaces. e.g. "LongFrames"</param>
135 /// <param name='name'>Human readable name for the stat. e.g. "Long frames"</param>
136 /// <param name='description'>Description of stat</param>
137 /// <param name='unitName'>
138 /// Unit name for the stat. Should be preceeded by a space if the unit name isn't normally appeneded immediately to the value.
139 /// e.g. " frames"
140 /// </param>
141 /// <param name='category'>Category under which this stat should appear, e.g. "scene". Do not capitalize.</param>
142 /// <param name='container'>Entity to which this stat relates. e.g. scene name if this is a per scene stat.</param>
143 /// <param name='type'>Push or pull</param>
144 /// <param name='pullAction'>Pull stats need an action to update the stat on request. Push stats should set null here.</param>
145 /// <param name='moi'>Measures of interest</param>
146 /// <param name='verbosity'>Verbosity of stat. Controls whether it will appear in short stat display or only full display.</param>
147 public Stat(
148 string shortName,
149 string name,
150 string description,
151 string unitName,
152 string category,
153 string container,
154 StatType type,
155 MeasuresOfInterest moi,
156 Action<Stat> pullAction,
157 StatVerbosity verbosity)
158 {
159 if (StatsManager.SubCommands.Contains(category))
160 throw new Exception(
161 string.Format("Stat cannot be in category '{0}' since this is reserved for a subcommand", category));
162
163 ShortName = shortName;
164 Name = name;
165 Description = description;
166 UnitName = unitName;
167 Category = category;
168 Container = container;
169 StatType = type;
170
171 if (StatType == StatType.Push && pullAction != null)
172 throw new Exception("A push stat cannot have a pull action");
173 else
174 PullAction = pullAction;
175
176 MeasuresOfInterest = moi;
177
178 if ((moi & MeasuresOfInterest.AverageChangeOverTime) == MeasuresOfInterest.AverageChangeOverTime)
179 m_samples = new Queue<double>(m_maxSamples);
180
181 Verbosity = verbosity;
182 }
183
184 /// <summary>
185 /// Record a value in the sample set.
186 /// </summary>
187 /// <remarks>
188 /// Do not call this if MeasuresOfInterest.None
189 /// </remarks>
190 public void RecordValue()
191 {
192 double newValue = Value;
193
194 lock (m_samples)
195 {
196 if (m_samples.Count >= m_maxSamples)
197 m_samples.Dequeue();
198
199 m_samples.Enqueue(newValue);
200 }
201 }
202
203 public virtual string ToConsoleString()
204 {
205 StringBuilder sb = new StringBuilder();
206 sb.AppendFormat("{0}.{1}.{2} : {3}{4}", Category, Container, ShortName, Value, UnitName);
207
208 AppendMeasuresOfInterest(sb);
209
210 return sb.ToString();
211 }
212
213 protected void AppendMeasuresOfInterest(StringBuilder sb)
214 {
215 if ((MeasuresOfInterest & MeasuresOfInterest.AverageChangeOverTime)
216 == MeasuresOfInterest.AverageChangeOverTime)
217 {
218 double totalChange = 0;
219 double? lastSample = null;
220
221 lock (m_samples)
222 {
223 foreach (double s in m_samples)
224 {
225 if (lastSample != null)
226 totalChange += s - (double)lastSample;
227
228 lastSample = s;
229 }
230 }
231
232 int divisor = m_samples.Count <= 1 ? 1 : m_samples.Count - 1;
233
234 sb.AppendFormat(", {0:0.##}{1}/s", totalChange / divisor / (Watchdog.WATCHDOG_INTERVAL_MS / 1000), UnitName);
235 }
236 }
237 }
238} \ No newline at end of file
diff --git a/OpenSim/Framework/Monitoring/StatsManager.cs b/OpenSim/Framework/Monitoring/StatsManager.cs
index 31989e5..0762b01 100644
--- a/OpenSim/Framework/Monitoring/StatsManager.cs
+++ b/OpenSim/Framework/Monitoring/StatsManager.cs
@@ -27,6 +27,7 @@
27 27
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Text;
30 31
31namespace OpenSim.Framework.Monitoring 32namespace OpenSim.Framework.Monitoring
32{ 33{
@@ -207,7 +208,7 @@ namespace OpenSim.Framework.Monitoring
207 return false; 208 return false;
208 209
209 newContainer = new Dictionary<string, Stat>(container); 210 newContainer = new Dictionary<string, Stat>(container);
210 newContainer.Remove(stat.UniqueName); 211 newContainer.Remove(stat.ShortName);
211 212
212 newCategory = new Dictionary<string, Dictionary<string, Stat>>(category); 213 newCategory = new Dictionary<string, Dictionary<string, Stat>>(category);
213 newCategory.Remove(stat.Container); 214 newCategory.Remove(stat.Container);
@@ -246,129 +247,58 @@ namespace OpenSim.Framework.Monitoring
246 247
247 return false; 248 return false;
248 } 249 }
250
251 public static void RecordStats()
252 {
253 lock (RegisteredStats)
254 {
255 foreach (Dictionary<string, Dictionary<string, Stat>> category in RegisteredStats.Values)
256 {
257 foreach (Dictionary<string, Stat> container in category.Values)
258 {
259 foreach (Stat stat in container.Values)
260 {
261 if (stat.MeasuresOfInterest != MeasuresOfInterest.None)
262 stat.RecordValue();
263 }
264 }
265 }
266 }
267 }
249 } 268 }
250 269
251 /// <summary> 270 /// <summary>
252 /// Verbosity of stat. 271 /// Stat type.
253 /// </summary> 272 /// </summary>
254 /// <remarks> 273 /// <remarks>
255 /// Info will always be displayed. 274 /// A push stat is one which is continually updated and so it's value can simply by read.
275 /// A pull stat is one where reading the value triggers a collection method - the stat is not continually updated.
256 /// </remarks> 276 /// </remarks>
257 public enum StatVerbosity 277 public enum StatType
258 { 278 {
259 Debug, 279 Push,
260 Info 280 Pull
261 } 281 }
262 282
263 /// <summary> 283 /// <summary>
264 /// Holds individual static details 284 /// Measures of interest for this stat.
265 /// </summary> 285 /// </summary>
266 public class Stat 286 [Flags]
287 public enum MeasuresOfInterest
267 { 288 {
268 /// <summary> 289 None,
269 /// Unique stat name used for indexing. Each ShortName in a Category must be unique. 290 AverageChangeOverTime
270 /// </summary>
271 public string UniqueName { get; private set; }
272
273 /// <summary>
274 /// Category of this stat (e.g. cache, scene, etc).
275 /// </summary>
276 public string Category { get; private set; }
277
278 /// <summary>
279 /// Containing name for this stat.
280 /// FIXME: In the case of a scene, this is currently the scene name (though this leaves
281 /// us with a to-be-resolved problem of non-unique region names).
282 /// </summary>
283 /// <value>
284 /// The container.
285 /// </value>
286 public string Container { get; private set; }
287
288 public StatVerbosity Verbosity { get; private set; }
289 public string ShortName { get; private set; }
290 public string Name { get; private set; }
291 public string Description { get; private set; }
292 public virtual string UnitName { get; private set; }
293
294 public virtual double Value { get; set; }
295
296 /// <summary>
297 /// Constructor
298 /// </summary>
299 /// <param name='shortName'>Short name for the stat. Must not contain spaces. e.g. "LongFrames"</param>
300 /// <param name='name'>Human readable name for the stat. e.g. "Long frames"</param>
301 /// <param name='unitName'>
302 /// Unit name for the stat. Should be preceeded by a space if the unit name isn't normally appeneded immediately to the value.
303 /// e.g. " frames"
304 /// </param>
305 /// <param name='category'>Category under which this stat should appear, e.g. "scene". Do not capitalize.</param>
306 /// <param name='container'>Entity to which this stat relates. e.g. scene name if this is a per scene stat.</param>
307 /// <param name='verbosity'>Verbosity of stat. Controls whether it will appear in short stat display or only full display.</param>
308 /// <param name='description'>Description of stat</param>
309 public Stat(
310 string shortName, string name, string unitName, string category, string container, StatVerbosity verbosity, string description)
311 {
312 if (StatsManager.SubCommands.Contains(category))
313 throw new Exception(
314 string.Format("Stat cannot be in category '{0}' since this is reserved for a subcommand", category));
315
316 ShortName = shortName;
317 Name = name;
318 UnitName = unitName;
319 Category = category;
320 Container = container;
321 Verbosity = verbosity;
322 Description = description;
323
324 UniqueName = GenUniqueName(Container, Category, ShortName);
325 }
326
327 public static string GenUniqueName(string container, string category, string shortName)
328 {
329 return string.Format("{0}+{1}+{2}", container, category, shortName);
330 }
331
332 public virtual string ToConsoleString()
333 {
334 return string.Format(
335 "{0}.{1}.{2} : {3}{4}", Category, Container, ShortName, Value, UnitName);
336 }
337 } 291 }
338 292
339 public class PercentageStat : Stat 293 /// <summary>
294 /// Verbosity of stat.
295 /// </summary>
296 /// <remarks>
297 /// Info will always be displayed.
298 /// </remarks>
299 public enum StatVerbosity
340 { 300 {
341 public int Antecedent { get; set; } 301 Debug,
342 public int Consequent { get; set; } 302 Info
343
344 public override double Value
345 {
346 get
347 {
348 int c = Consequent;
349
350 // Avoid any chance of a multi-threaded divide-by-zero
351 if (c == 0)
352 return 0;
353
354 return (double)Antecedent / c * 100;
355 }
356
357 set
358 {
359 throw new Exception("Cannot set value on a PercentageStat");
360 }
361 }
362
363 public PercentageStat(
364 string shortName, string name, string category, string container, StatVerbosity verbosity, string description)
365 : base(shortName, name, "%", category, container, verbosity, description) {}
366
367 public override string ToConsoleString()
368 {
369 return string.Format(
370 "{0}.{1}.{2} : {3:0.##}{4} ({5}/{6})",
371 Category, Container, ShortName, Value, UnitName, Antecedent, Consequent);
372 }
373 } 303 }
374} \ No newline at end of file 304} \ No newline at end of file
diff --git a/OpenSim/Framework/Monitoring/Watchdog.cs b/OpenSim/Framework/Monitoring/Watchdog.cs
index a20326d..3f992b1 100644
--- a/OpenSim/Framework/Monitoring/Watchdog.cs
+++ b/OpenSim/Framework/Monitoring/Watchdog.cs
@@ -39,7 +39,7 @@ namespace OpenSim.Framework.Monitoring
39 public static class Watchdog 39 public static class Watchdog
40 { 40 {
41 /// <summary>Timer interval in milliseconds for the watchdog timer</summary> 41 /// <summary>Timer interval in milliseconds for the watchdog timer</summary>
42 const double WATCHDOG_INTERVAL_MS = 2500.0d; 42 public const double WATCHDOG_INTERVAL_MS = 2500.0d;
43 43
44 /// <summary>Default timeout in milliseconds before a thread is considered dead</summary> 44 /// <summary>Default timeout in milliseconds before a thread is considered dead</summary>
45 public const int DEFAULT_WATCHDOG_TIMEOUT_MS = 5000; 45 public const int DEFAULT_WATCHDOG_TIMEOUT_MS = 5000;
@@ -380,6 +380,8 @@ namespace OpenSim.Framework.Monitoring
380 if (MemoryWatchdog.Enabled) 380 if (MemoryWatchdog.Enabled)
381 MemoryWatchdog.Update(); 381 MemoryWatchdog.Update();
382 382
383 StatsManager.RecordStats();
384
383 m_watchdogTimer.Start(); 385 m_watchdogTimer.Start();
384 } 386 }
385 } 387 }