Add object count stats for new IncomingPacket and UDPPacketBuffer pools if they are enabled. Add count stats for existing LLUDP pool.

This introduces a pull stat type in addition to the push stat type.
A pull stat takes a method on construction which knows how to update the stat on request.
In this way, special interfaces for pull stat collection are not necessary.
0.7.4-extended
Justin Clark-Casey (justincc) 2012-10-23 01:50:05 +01:00
parent f39c2cd714
commit 5413bfec30
6 changed files with 153 additions and 14 deletions

View File

@ -248,6 +248,19 @@ namespace OpenSim.Framework.Monitoring
} }
} }
/// <summary>
/// Stat type.
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
public enum StatType
{
Push,
Pull
}
/// <summary> /// <summary>
/// Verbosity of stat. /// Verbosity of stat.
/// </summary> /// </summary>
@ -285,29 +298,65 @@ namespace OpenSim.Framework.Monitoring
/// </value> /// </value>
public string Container { get; private set; } public string Container { get; private set; }
public StatType StatType { get; private set; }
/// <summary>
/// Action used to update this stat when the value is requested if it's a pull type.
/// </summary>
public Action<Stat> PullAction { get; private set; }
public StatVerbosity Verbosity { get; private set; } public StatVerbosity Verbosity { get; private set; }
public string ShortName { get; private set; } public string ShortName { get; private set; }
public string Name { get; private set; } public string Name { get; private set; }
public string Description { get; private set; } public string Description { get; private set; }
public virtual string UnitName { 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;
/// <summary> /// <summary>
/// Constructor /// Constructor
/// </summary> /// </summary>
/// <param name='shortName'>Short name for the stat. Must not contain spaces. e.g. "LongFrames"</param> /// <param name='shortName'>Short name for the stat. Must not contain spaces. e.g. "LongFrames"</param>
/// <param name='name'>Human readable name for the stat. e.g. "Long frames"</param> /// <param name='name'>Human readable name for the stat. e.g. "Long frames"</param>
/// <param name='description'>Description of stat</param>
/// <param name='unitName'> /// <param name='unitName'>
/// Unit name for the stat. Should be preceeded by a space if the unit name isn't normally appeneded immediately to the value. /// 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" /// e.g. " frames"
/// </param> /// </param>
/// <param name='category'>Category under which this stat should appear, e.g. "scene". Do not capitalize.</param> /// <param name='category'>Category under which this stat should appear, e.g. "scene". Do not capitalize.</param>
/// <param name='container'>Entity to which this stat relates. e.g. scene name if this is a per scene stat.</param> /// <param name='container'>Entity to which this stat relates. e.g. scene name if this is a per scene stat.</param>
/// <param name='type'>Push or pull</param>
/// <param name='pullAction'>Pull stats need an action to update the stat on request. Push stats should set null here.</param>
/// <param name='verbosity'>Verbosity of stat. Controls whether it will appear in short stat display or only full display.</param> /// <param name='verbosity'>Verbosity of stat. Controls whether it will appear in short stat display or only full display.</param>
/// <param name='description'>Description of stat</param>
public 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<Stat> pullAction,
StatVerbosity verbosity)
{ {
if (StatsManager.SubCommands.Contains(category)) if (StatsManager.SubCommands.Contains(category))
throw new Exception( throw new Exception(
@ -315,11 +364,18 @@ namespace OpenSim.Framework.Monitoring
ShortName = shortName; ShortName = shortName;
Name = name; Name = name;
Description = description;
UnitName = unitName; UnitName = unitName;
Category = category; Category = category;
Container = container; 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; Verbosity = verbosity;
Description = description;
UniqueName = GenUniqueName(Container, Category, ShortName); UniqueName = GenUniqueName(Container, Category, ShortName);
} }
@ -361,8 +417,15 @@ namespace OpenSim.Framework.Monitoring
} }
public PercentageStat( public PercentageStat(
string shortName, string name, string category, string container, StatVerbosity verbosity, string description) string shortName,
: base(shortName, name, "%", category, container, verbosity, description) {} string name,
string description,
string category,
string container,
StatType type,
Action<Stat> pullAction,
StatVerbosity verbosity)
: base(shortName, name, description, "%", category, container, type, pullAction, verbosity) {}
public override string ToConsoleString() public override string ToConsoleString()
{ {

View File

@ -38,8 +38,23 @@ namespace OpenSim.Framework
/// </remarks> /// </remarks>
public class Pool<T> public class Pool<T>
{ {
/// <summary>
/// Number of objects in the pool.
/// </summary>
public int Count
{
get
{
lock (m_pool)
return m_pool.Count;
}
}
private Stack<T> m_pool; private Stack<T> m_pool;
/// <summary>
/// Maximum pool size. Beyond this, any returned objects are not pooled.
/// </summary>
private int m_maxPoolSize; private int m_maxPoolSize;
private Func<T> m_createFunction; private Func<T> m_createFunction;

View File

@ -278,7 +278,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
ThrottleRates = new ThrottleRates(configSource); ThrottleRates = new ThrottleRates(configSource);
if (UsePools) if (UsePools)
{
m_incomingPacketPool = new Pool<IncomingPacket>(() => new IncomingPacket(), 500); m_incomingPacketPool = new Pool<IncomingPacket>(() => 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() public void Start()

View File

@ -31,6 +31,7 @@ using System.Net.Sockets;
using System.Threading; using System.Threading;
using log4net; using log4net;
using OpenSim.Framework; using OpenSim.Framework;
using OpenSim.Framework.Monitoring;
namespace OpenMetaverse namespace OpenMetaverse
{ {
@ -107,9 +108,25 @@ namespace OpenMetaverse
public void StartInbound(int recvBufferSize, bool asyncPacketHandling) public void StartInbound(int recvBufferSize, bool asyncPacketHandling)
{ {
if (UsePools) if (UsePools)
{
m_pool = new Pool<UDPPacketBuffer>(() => new UDPPacketBuffer(), 500); m_pool = new Pool<UDPPacketBuffer>(() => 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 else
{
m_pool = null; m_pool = null;
}
m_asyncPacketHandling = asyncPacketHandling; m_asyncPacketHandling = asyncPacketHandling;

View File

@ -47,18 +47,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
private PercentageStat m_packetsReusedStat = new PercentageStat( private PercentageStat m_packetsReusedStat = new PercentageStat(
"PacketsReused", "PacketsReused",
"Packets reused", "Packets reused",
"Number of packets reused out of all requests to the packet pool",
"clientstack", "clientstack",
"packetpool", "packetpool",
StatVerbosity.Debug, StatType.Push,
"Number of packets reused out of all requests to the packet pool"); null,
StatVerbosity.Debug);
private PercentageStat m_blocksReusedStat = new PercentageStat( private PercentageStat m_blocksReusedStat = new PercentageStat(
"BlocksReused", "PacketDataBlocksReused",
"Blocks reused", "Packet data blocks reused",
"Number of data blocks reused out of all requests to the packet pool",
"clientstack", "clientstack",
"packetpool", "packetpool",
StatVerbosity.Debug, StatType.Push,
"Number of data blocks reused out of all requests to the packet pool"); null,
StatVerbosity.Debug);
/// <summary> /// <summary>
/// Pool of packets available for reuse. /// Pool of packets available for reuse.
@ -88,6 +92,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{ {
StatsManager.RegisterStat(m_packetsReusedStat); StatsManager.RegisterStat(m_packetsReusedStat);
StatsManager.RegisterStat(m_blocksReusedStat); 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));
} }
/// <summary> /// <summary>

View File

@ -245,11 +245,13 @@ namespace OpenSim.Region.Framework.Scenes
= new Stat( = new Stat(
"SlowFrames", "SlowFrames",
"Slow Frames", "Slow Frames",
"Number of frames where frame time has been significantly longer than the desired frame time.",
" frames", " frames",
"scene", "scene",
m_scene.Name, m_scene.Name,
StatVerbosity.Info, StatType.Push,
"Number of frames where frame time has been significantly longer than the desired frame time."); null,
StatVerbosity.Info);
StatsManager.RegisterStat(SlowFramesStat); StatsManager.RegisterStat(SlowFramesStat);
} }