From 55f889cc66d78268c530c65a5fd111395cc26dc5 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 16 Nov 2012 05:02:06 +0000 Subject: refactor: Move stat classes out of StatManager and into their own files for clarity. --- .../Framework/Monitoring/Stats/PercentageStat.cs | 88 ++++++++ OpenSim/Framework/Monitoring/Stats/Stat.cs | 238 +++++++++++++++++++++ 2 files changed, 326 insertions(+) create mode 100644 OpenSim/Framework/Monitoring/Stats/PercentageStat.cs create mode 100644 OpenSim/Framework/Monitoring/Stats/Stat.cs (limited to 'OpenSim/Framework/Monitoring/Stats') 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 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenSim.Framework.Monitoring +{ + public class PercentageStat : Stat + { + public long Antecedent { get; set; } + public long Consequent { get; set; } + + public override double Value + { + get + { + // Asking for an update here means that the updater cannot access this value without infinite recursion. + // XXX: A slightly messy but simple solution may be to flick a flag so we can tell if this is being + // called by the pull action and just return the value. + if (StatType == StatType.Pull) + PullAction(this); + + long c = Consequent; + + // Avoid any chance of a multi-threaded divide-by-zero + if (c == 0) + return 0; + + return (double)Antecedent / c * 100; + } + + set + { + throw new InvalidOperationException("Cannot set value on a PercentageStat"); + } + } + + public PercentageStat( + string shortName, + string name, + string description, + string category, + string container, + StatType type, + Action pullAction, + StatVerbosity verbosity) + : base(shortName, name, description, "%", category, container, type, pullAction, verbosity) {} + + public override string ToConsoleString() + { + StringBuilder sb = new StringBuilder(); + + sb.AppendFormat( + "{0}.{1}.{2} : {3:0.##}{4} ({5}/{6})", + Category, Container, ShortName, Value, UnitName, Antecedent, Consequent); + + AppendMeasuresOfInterest(sb); + + return sb.ToString(); + } + } +} \ 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 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenSim.Framework.Monitoring +{ + /// + /// Holds individual statistic details + /// + public class Stat + { + /// + /// Category of this stat (e.g. cache, scene, etc). + /// + public string Category { get; private set; } + + /// + /// Containing name for this stat. + /// FIXME: In the case of a scene, this is currently the scene name (though this leaves + /// us with a to-be-resolved problem of non-unique region names). + /// + /// + /// The container. + /// + public string Container { get; private set; } + + public StatType StatType { get; private set; } + + public MeasuresOfInterest MeasuresOfInterest { get; private set; } + + /// + /// Action used to update this stat when the value is requested if it's a pull type. + /// + public Action PullAction { get; private set; } + + public StatVerbosity Verbosity { get; private set; } + public string ShortName { get; private set; } + public string Name { get; private set; } + public string Description { get; private set; } + public virtual string UnitName { get; private set; } + + public virtual double Value + { + get + { + // Asking for an update here means that the updater cannot access this value without infinite recursion. + // XXX: A slightly messy but simple solution may be to flick a flag so we can tell if this is being + // called by the pull action and just return the value. + if (StatType == StatType.Pull) + PullAction(this); + + return m_value; + } + + set + { + m_value = value; + } + } + + private double m_value; + + /// + /// Historical samples for calculating measures of interest average. + /// + /// + /// Will be null if no measures of interest require samples. + /// + private static Queue m_samples; + + /// + /// Maximum number of statistical samples. + /// + /// + /// At the moment this corresponds to 1 minute since the sampling rate is every 2.5 seconds as triggered from + /// the main Watchdog. + /// + private static int m_maxSamples = 24; + + public Stat( + string shortName, + string name, + string description, + string unitName, + string category, + string container, + StatType type, + Action pullAction, + StatVerbosity verbosity) + : this( + shortName, + name, + description, + unitName, + category, + container, + type, + MeasuresOfInterest.None, + pullAction, + verbosity) + { + } + + /// + /// Constructor + /// + /// Short name for the stat. Must not contain spaces. e.g. "LongFrames" + /// Human readable name for the stat. e.g. "Long frames" + /// Description of stat + /// + /// Unit name for the stat. Should be preceeded by a space if the unit name isn't normally appeneded immediately to the value. + /// e.g. " frames" + /// + /// Category under which this stat should appear, e.g. "scene". Do not capitalize. + /// Entity to which this stat relates. e.g. scene name if this is a per scene stat. + /// Push or pull + /// Pull stats need an action to update the stat on request. Push stats should set null here. + /// Measures of interest + /// Verbosity of stat. Controls whether it will appear in short stat display or only full display. + public Stat( + string shortName, + string name, + string description, + string unitName, + string category, + string container, + StatType type, + MeasuresOfInterest moi, + Action pullAction, + StatVerbosity verbosity) + { + if (StatsManager.SubCommands.Contains(category)) + throw new Exception( + string.Format("Stat cannot be in category '{0}' since this is reserved for a subcommand", category)); + + ShortName = shortName; + Name = name; + Description = description; + UnitName = unitName; + Category = category; + Container = container; + StatType = type; + + if (StatType == StatType.Push && pullAction != null) + throw new Exception("A push stat cannot have a pull action"); + else + PullAction = pullAction; + + MeasuresOfInterest = moi; + + if ((moi & MeasuresOfInterest.AverageChangeOverTime) == MeasuresOfInterest.AverageChangeOverTime) + m_samples = new Queue(m_maxSamples); + + Verbosity = verbosity; + } + + /// + /// Record a value in the sample set. + /// + /// + /// Do not call this if MeasuresOfInterest.None + /// + public void RecordValue() + { + double newValue = Value; + + lock (m_samples) + { + if (m_samples.Count >= m_maxSamples) + m_samples.Dequeue(); + + m_samples.Enqueue(newValue); + } + } + + public virtual string ToConsoleString() + { + StringBuilder sb = new StringBuilder(); + sb.AppendFormat("{0}.{1}.{2} : {3}{4}", Category, Container, ShortName, Value, UnitName); + + AppendMeasuresOfInterest(sb); + + return sb.ToString(); + } + + protected void AppendMeasuresOfInterest(StringBuilder sb) + { + if ((MeasuresOfInterest & MeasuresOfInterest.AverageChangeOverTime) + == MeasuresOfInterest.AverageChangeOverTime) + { + double totalChange = 0; + double? lastSample = null; + + lock (m_samples) + { + foreach (double s in m_samples) + { + if (lastSample != null) + totalChange += s - (double)lastSample; + + lastSample = s; + } + } + + int divisor = m_samples.Count <= 1 ? 1 : m_samples.Count - 1; + + sb.AppendFormat(", {0:0.##}{1}/s", totalChange / divisor / (Watchdog.WATCHDOG_INTERVAL_MS / 1000), UnitName); + } + } + } +} \ No newline at end of file -- cgit v1.1