aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-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.cs260
3 files changed, 326 insertions, 260 deletions
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 eae7505..0762b01 100644
--- a/OpenSim/Framework/Monitoring/StatsManager.cs
+++ b/OpenSim/Framework/Monitoring/StatsManager.cs
@@ -301,264 +301,4 @@ namespace OpenSim.Framework.Monitoring
301 Debug, 301 Debug,
302 Info 302 Info
303 } 303 }
304
305 /// <summary>
306 /// Holds individual static details
307 /// </summary>
308 public class Stat
309 {
310 /// <summary>
311 /// Category of this stat (e.g. cache, scene, etc).
312 /// </summary>
313 public string Category { get; private set; }
314
315 /// <summary>
316 /// Containing name for this stat.
317 /// FIXME: In the case of a scene, this is currently the scene name (though this leaves
318 /// us with a to-be-resolved problem of non-unique region names).
319 /// </summary>
320 /// <value>
321 /// The container.
322 /// </value>
323 public string Container { get; private set; }
324
325 public StatType StatType { get; private set; }
326
327 public MeasuresOfInterest MeasuresOfInterest { get; private set; }
328
329 /// <summary>
330 /// Action used to update this stat when the value is requested if it's a pull type.
331 /// </summary>
332 public Action<Stat> PullAction { get; private set; }
333
334 public StatVerbosity Verbosity { get; private set; }
335 public string ShortName { get; private set; }
336 public string Name { get; private set; }
337 public string Description { get; private set; }
338 public virtual string UnitName { get; private set; }
339
340 public virtual double Value
341 {
342 get
343 {
344 // Asking for an update here means that the updater cannot access this value without infinite recursion.
345 // XXX: A slightly messy but simple solution may be to flick a flag so we can tell if this is being
346 // called by the pull action and just return the value.
347 if (StatType == StatType.Pull)
348 PullAction(this);
349
350 return m_value;
351 }
352
353 set
354 {
355 m_value = value;
356 }
357 }
358
359 private double m_value;
360
361 /// <summary>
362 /// Historical samples for calculating measures of interest average.
363 /// </summary>
364 /// <remarks>
365 /// Will be null if no measures of interest require samples.
366 /// </remarks>
367 private static Queue<double> m_samples;
368
369 /// <summary>
370 /// Maximum number of statistical samples.
371 /// </summary>
372 /// <remarks>
373 /// At the moment this corresponds to 1 minute since the sampling rate is every 2.5 seconds as triggered from
374 /// the main Watchdog.
375 /// </remarks>
376 private static int m_maxSamples = 24;
377
378 public Stat(
379 string shortName,
380 string name,
381 string description,
382 string unitName,
383 string category,
384 string container,
385 StatType type,
386 Action<Stat> pullAction,
387 StatVerbosity verbosity)
388 : this(
389 shortName,
390 name,
391 description,
392 unitName,
393 category,
394 container,
395 type,
396 MeasuresOfInterest.None,
397 pullAction,
398 verbosity)
399 {
400 }
401
402 /// <summary>
403 /// Constructor
404 /// </summary>
405 /// <param name='shortName'>Short name for the stat. Must not contain spaces. e.g. "LongFrames"</param>
406 /// <param name='name'>Human readable name for the stat. e.g. "Long frames"</param>
407 /// <param name='description'>Description of stat</param>
408 /// <param name='unitName'>
409 /// Unit name for the stat. Should be preceeded by a space if the unit name isn't normally appeneded immediately to the value.
410 /// e.g. " frames"
411 /// </param>
412 /// <param name='category'>Category under which this stat should appear, e.g. "scene". Do not capitalize.</param>
413 /// <param name='container'>Entity to which this stat relates. e.g. scene name if this is a per scene stat.</param>
414 /// <param name='type'>Push or pull</param>
415 /// <param name='pullAction'>Pull stats need an action to update the stat on request. Push stats should set null here.</param>
416 /// <param name='moi'>Measures of interest</param>
417 /// <param name='verbosity'>Verbosity of stat. Controls whether it will appear in short stat display or only full display.</param>
418 public Stat(
419 string shortName,
420 string name,
421 string description,
422 string unitName,
423 string category,
424 string container,
425 StatType type,
426 MeasuresOfInterest moi,
427 Action<Stat> pullAction,
428 StatVerbosity verbosity)
429 {
430 if (StatsManager.SubCommands.Contains(category))
431 throw new Exception(
432 string.Format("Stat cannot be in category '{0}' since this is reserved for a subcommand", category));
433
434 ShortName = shortName;
435 Name = name;
436 Description = description;
437 UnitName = unitName;
438 Category = category;
439 Container = container;
440 StatType = type;
441
442 if (StatType == StatType.Push && pullAction != null)
443 throw new Exception("A push stat cannot have a pull action");
444 else
445 PullAction = pullAction;
446
447 MeasuresOfInterest = moi;
448
449 if ((moi & MeasuresOfInterest.AverageChangeOverTime) == MeasuresOfInterest.AverageChangeOverTime)
450 m_samples = new Queue<double>(m_maxSamples);
451
452 Verbosity = verbosity;
453 }
454
455 /// <summary>
456 /// Record a value in the sample set.
457 /// </summary>
458 /// <remarks>
459 /// Do not call this if MeasuresOfInterest.None
460 /// </remarks>
461 public void RecordValue()
462 {
463 double newValue = Value;
464
465 lock (m_samples)
466 {
467 if (m_samples.Count >= m_maxSamples)
468 m_samples.Dequeue();
469
470 m_samples.Enqueue(newValue);
471 }
472 }
473
474 public virtual string ToConsoleString()
475 {
476 StringBuilder sb = new StringBuilder();
477 sb.AppendFormat("{0}.{1}.{2} : {3}{4}", Category, Container, ShortName, Value, UnitName);
478
479 AppendMeasuresOfInterest(sb);
480
481 return sb.ToString();
482 }
483
484 protected void AppendMeasuresOfInterest(StringBuilder sb)
485 {
486 if ((MeasuresOfInterest & MeasuresOfInterest.AverageChangeOverTime)
487 == MeasuresOfInterest.AverageChangeOverTime)
488 {
489 double totalChange = 0;
490 double? lastSample = null;
491
492 lock (m_samples)
493 {
494 foreach (double s in m_samples)
495 {
496 if (lastSample != null)
497 totalChange += s - (double)lastSample;
498
499 lastSample = s;
500 }
501 }
502
503 int divisor = m_samples.Count <= 1 ? 1 : m_samples.Count - 1;
504
505 sb.AppendFormat(", {0:0.##}{1}/s", totalChange / divisor / (Watchdog.WATCHDOG_INTERVAL_MS / 1000), UnitName);
506 }
507 }
508 }
509
510 public class PercentageStat : Stat
511 {
512 public long Antecedent { get; set; }
513 public long Consequent { get; set; }
514
515 public override double Value
516 {
517 get
518 {
519 // Asking for an update here means that the updater cannot access this value without infinite recursion.
520 // XXX: A slightly messy but simple solution may be to flick a flag so we can tell if this is being
521 // called by the pull action and just return the value.
522 if (StatType == StatType.Pull)
523 PullAction(this);
524
525 long c = Consequent;
526
527 // Avoid any chance of a multi-threaded divide-by-zero
528 if (c == 0)
529 return 0;
530
531 return (double)Antecedent / c * 100;
532 }
533
534 set
535 {
536 throw new InvalidOperationException("Cannot set value on a PercentageStat");
537 }
538 }
539
540 public PercentageStat(
541 string shortName,
542 string name,
543 string description,
544 string category,
545 string container,
546 StatType type,
547 Action<Stat> pullAction,
548 StatVerbosity verbosity)
549 : base(shortName, name, description, "%", category, container, type, pullAction, verbosity) {}
550
551 public override string ToConsoleString()
552 {
553 StringBuilder sb = new StringBuilder();
554
555 sb.AppendFormat(
556 "{0}.{1}.{2} : {3:0.##}{4} ({5}/{6})",
557 Category, Container, ShortName, Value, UnitName, Antecedent, Consequent);
558
559 AppendMeasuresOfInterest(sb);
560
561 return sb.ToString();
562 }
563 }
564} \ No newline at end of file 304} \ No newline at end of file