diff --git a/OpenSim/Framework/Monitoring/StatsManager.cs b/OpenSim/Framework/Monitoring/StatsManager.cs index 31989e50ad..116b2c0cfe 100644 --- a/OpenSim/Framework/Monitoring/StatsManager.cs +++ b/OpenSim/Framework/Monitoring/StatsManager.cs @@ -248,6 +248,19 @@ namespace OpenSim.Framework.Monitoring } } + /// + /// Stat type. + /// + /// + /// A push stat is one which is continually updated and so it's value can simply by read. + /// A pull stat is one where reading the value triggers a collection method - the stat is not continually updated. + /// + public enum StatType + { + Push, + Pull + } + /// /// Verbosity of stat. /// @@ -285,29 +298,65 @@ namespace OpenSim.Framework.Monitoring /// public string Container { get; private set; } + public StatType StatType { 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; 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; /// /// 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. /// Verbosity of stat. Controls whether it will appear in short stat display or only full display. - /// Description of stat public Stat( - string shortName, string name, string unitName, string category, string container, StatVerbosity verbosity, string description) + string shortName, + string name, + string description, + string unitName, + string category, + string container, + StatType type, + Action pullAction, + StatVerbosity verbosity) { if (StatsManager.SubCommands.Contains(category)) throw new Exception( @@ -315,11 +364,18 @@ namespace OpenSim.Framework.Monitoring 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; + Verbosity = verbosity; - Description = description; UniqueName = GenUniqueName(Container, Category, ShortName); } @@ -361,8 +417,15 @@ namespace OpenSim.Framework.Monitoring } public PercentageStat( - string shortName, string name, string category, string container, StatVerbosity verbosity, string description) - : base(shortName, name, "%", category, container, verbosity, description) {} + 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() { diff --git a/OpenSim/Framework/Pool.cs b/OpenSim/Framework/Pool.cs index 1ca06c3065..5484f5c2d5 100644 --- a/OpenSim/Framework/Pool.cs +++ b/OpenSim/Framework/Pool.cs @@ -38,8 +38,23 @@ namespace OpenSim.Framework /// public class Pool { + /// + /// Number of objects in the pool. + /// + public int Count + { + get + { + lock (m_pool) + return m_pool.Count; + } + } + private Stack m_pool; + /// + /// Maximum pool size. Beyond this, any returned objects are not pooled. + /// private int m_maxPoolSize; private Func m_createFunction; diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index 419de66e7b..bcfd3920e9 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -278,7 +278,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP ThrottleRates = new ThrottleRates(configSource); if (UsePools) + { m_incomingPacketPool = new Pool(() => new IncomingPacket(), 500); + + StatsManager.RegisterStat( + new Stat( + "IncomingPacketPoolCount", + "Objects within incoming packet pool", + "The number of objects currently stored within the incoming packet pool", + "", + "clientstack", + "packetpool", + StatType.Pull, + stat => stat.Value = m_incomingPacketPool.Count, + StatVerbosity.Debug)); + } } public void Start() diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs index 6e6b3ef1b5..18abfd6a63 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs @@ -31,6 +31,7 @@ using System.Net.Sockets; using System.Threading; using log4net; using OpenSim.Framework; +using OpenSim.Framework.Monitoring; namespace OpenMetaverse { @@ -107,9 +108,25 @@ namespace OpenMetaverse public void StartInbound(int recvBufferSize, bool asyncPacketHandling) { if (UsePools) + { m_pool = new Pool(() => new UDPPacketBuffer(), 500); + + StatsManager.RegisterStat( + new Stat( + "UDPPacketBufferPoolCount", + "Objects within the UDPPacketBuffer pool", + "The number of objects currently stored within the UDPPacketBuffer pool", + "", + "clientstack", + "packetpool", + StatType.Pull, + stat => stat.Value = m_pool.Count, + StatVerbosity.Debug)); + } else + { m_pool = null; + } m_asyncPacketHandling = asyncPacketHandling; diff --git a/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs b/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs index 2a3d14f69f..9f22fb48ec 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs @@ -47,18 +47,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP private PercentageStat m_packetsReusedStat = new PercentageStat( "PacketsReused", "Packets reused", + "Number of packets reused out of all requests to the packet pool", "clientstack", "packetpool", - StatVerbosity.Debug, - "Number of packets reused out of all requests to the packet pool"); + StatType.Push, + null, + StatVerbosity.Debug); private PercentageStat m_blocksReusedStat = new PercentageStat( - "BlocksReused", - "Blocks reused", + "PacketDataBlocksReused", + "Packet data blocks reused", + "Number of data blocks reused out of all requests to the packet pool", "clientstack", "packetpool", - StatVerbosity.Debug, - "Number of data blocks reused out of all requests to the packet pool"); + StatType.Push, + null, + StatVerbosity.Debug); /// /// Pool of packets available for reuse. @@ -88,6 +92,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP { StatsManager.RegisterStat(m_packetsReusedStat); StatsManager.RegisterStat(m_blocksReusedStat); + + StatsManager.RegisterStat( + new Stat( + "PacketsPoolCount", + "Objects within the packet pool", + "The number of objects currently stored within the packet pool", + "", + "clientstack", + "packetpool", + StatType.Pull, + stat => { lock (pool) { stat.Value = pool.Count; } }, + StatVerbosity.Debug)); + + StatsManager.RegisterStat( + new Stat( + "PacketDataBlocksPoolCount", + "Objects within the packet data block pool", + "The number of objects currently stored within the packet data block pool", + "", + "clientstack", + "packetpool", + StatType.Pull, + stat => { lock (DataBlocks) { stat.Value = DataBlocks.Count; } }, + StatVerbosity.Debug)); } /// diff --git a/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs b/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs index 2addb5bab8..b9d615e804 100644 --- a/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs +++ b/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs @@ -245,11 +245,13 @@ namespace OpenSim.Region.Framework.Scenes = new Stat( "SlowFrames", "Slow Frames", + "Number of frames where frame time has been significantly longer than the desired frame time.", " frames", "scene", m_scene.Name, - StatVerbosity.Info, - "Number of frames where frame time has been significantly longer than the desired frame time."); + StatType.Push, + null, + StatVerbosity.Info); StatsManager.RegisterStat(SlowFramesStat); }