Make "abnormal thread terminations" into "ClientLogoutsDueToNoReceives" and add this to the StatsManager

This reflects the actual use of this stat - it hasn't recorded general exceptions for some time.
Make the sim extra stats collector draw the data from the stats manager rather than maintaing this data itself.
TeleportWork
Justin Clark-Casey (justincc) 2013-07-29 23:18:29 +01:00
parent 7eee9eb312
commit 8efe4bfc2e
3 changed files with 89 additions and 27 deletions

View File

@ -27,6 +27,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text; using System.Text;
using OpenMetaverse; using OpenMetaverse;
using OpenMetaverse.StructuredData; using OpenMetaverse.StructuredData;
@ -39,8 +40,6 @@ namespace OpenSim.Framework.Monitoring
/// </summary> /// </summary>
public class SimExtraStatsCollector : BaseStatsCollector public class SimExtraStatsCollector : BaseStatsCollector
{ {
private long abnormalClientThreadTerminations;
// private long assetsInCache; // private long assetsInCache;
// private long texturesInCache; // private long texturesInCache;
// private long assetCacheMemoryUsage; // private long assetCacheMemoryUsage;
@ -73,11 +72,6 @@ namespace OpenSim.Framework.Monitoring
private volatile float activeScripts; private volatile float activeScripts;
private volatile float scriptLinesPerSecond; private volatile float scriptLinesPerSecond;
/// <summary>
/// Number of times that a client thread terminated because of an exception
/// </summary>
public long AbnormalClientThreadTerminations { get { return abnormalClientThreadTerminations; } }
// /// <summary> // /// <summary>
// /// These statistics are being collected by push rather than pull. Pull would be simpler, but I had the // /// These statistics are being collected by push rather than pull. Pull would be simpler, but I had the
// /// notion of providing some flow statistics (which pull wouldn't give us). Though admittedly these // /// notion of providing some flow statistics (which pull wouldn't give us). Though admittedly these
@ -166,11 +160,6 @@ namespace OpenSim.Framework.Monitoring
private IDictionary<UUID, PacketQueueStatsCollector> packetQueueStatsCollectors private IDictionary<UUID, PacketQueueStatsCollector> packetQueueStatsCollectors
= new Dictionary<UUID, PacketQueueStatsCollector>(); = new Dictionary<UUID, PacketQueueStatsCollector>();
public void AddAbnormalClientThreadTermination()
{
abnormalClientThreadTerminations++;
}
// public void AddAsset(AssetBase asset) // public void AddAsset(AssetBase asset)
// { // {
// assetsInCache++; // assetsInCache++;
@ -324,10 +313,12 @@ Asset service request failures: {3}" + Environment.NewLine,
sb.Append(Environment.NewLine); sb.Append(Environment.NewLine);
sb.Append("CONNECTION STATISTICS"); sb.Append("CONNECTION STATISTICS");
sb.Append(Environment.NewLine); sb.Append(Environment.NewLine);
sb.Append(
string.Format( List<Stat> stats = StatsManager.GetStatsFromEachContainer("clientstack", "ClientLogoutsDueToNoReceives");
"Abnormal client thread terminations: {0}" + Environment.NewLine,
abnormalClientThreadTerminations)); sb.AppendFormat(
"Client logouts due to no data receive timeout: {0}\n\n",
stats != null ? stats.Sum(s => s.Value).ToString() : "unknown");
// sb.Append(Environment.NewLine); // sb.Append(Environment.NewLine);
// sb.Append("INVENTORY STATISTICS"); // sb.Append("INVENTORY STATISTICS");
@ -338,7 +329,7 @@ Asset service request failures: {3}" + Environment.NewLine,
// InventoryServiceRetrievalFailures)); // InventoryServiceRetrievalFailures));
sb.Append(Environment.NewLine); sb.Append(Environment.NewLine);
sb.Append("FRAME STATISTICS"); sb.Append("SAMPLE FRAME STATISTICS");
sb.Append(Environment.NewLine); sb.Append(Environment.NewLine);
sb.Append("Dilatn SimFPS PhyFPS AgntUp RootAg ChldAg Prims AtvPrm AtvScr ScrLPS"); sb.Append("Dilatn SimFPS PhyFPS AgntUp RootAg ChldAg Prims AtvPrm AtvScr ScrLPS");
sb.Append(Environment.NewLine); sb.Append(Environment.NewLine);

View File

@ -271,7 +271,7 @@ namespace OpenSim.Framework.Monitoring
// Stat name is not unique across category/container/shortname key. // Stat name is not unique across category/container/shortname key.
// XXX: For now just return false. This is to avoid problems in regression tests where all tests // XXX: For now just return false. This is to avoid problems in regression tests where all tests
// in a class are run in the same instance of the VM. // in a class are run in the same instance of the VM.
if (TryGetStat(stat, out category, out container)) if (TryGetStatParents(stat, out category, out container))
return false; return false;
// We take a copy-on-write approach here of replacing dictionaries when keys are added or removed. // We take a copy-on-write approach here of replacing dictionaries when keys are added or removed.
@ -307,7 +307,7 @@ namespace OpenSim.Framework.Monitoring
lock (RegisteredStats) lock (RegisteredStats)
{ {
if (!TryGetStat(stat, out category, out container)) if (!TryGetStatParents(stat, out category, out container))
return false; return false;
newContainer = new SortedDictionary<string, Stat>(container); newContainer = new SortedDictionary<string, Stat>(container);
@ -323,12 +323,67 @@ namespace OpenSim.Framework.Monitoring
} }
} }
public static bool TryGetStats(string category, out SortedDictionary<string, SortedDictionary<string, Stat>> stats) public static bool TryGetStat(string category, string container, string statShortName, out Stat stat)
{ {
return RegisteredStats.TryGetValue(category, out stats); stat = null;
SortedDictionary<string, SortedDictionary<string, Stat>> categoryStats;
lock (RegisteredStats)
{
if (!TryGetStatsForCategory(category, out categoryStats))
return false;
SortedDictionary<string, Stat> containerStats;
if (!categoryStats.TryGetValue(container, out containerStats))
return false;
return containerStats.TryGetValue(statShortName, out stat);
}
} }
public static bool TryGetStat( public static bool TryGetStatsForCategory(
string category, out SortedDictionary<string, SortedDictionary<string, Stat>> stats)
{
lock (RegisteredStats)
return RegisteredStats.TryGetValue(category, out stats);
}
/// <summary>
/// Get the same stat for each container in a given category.
/// </summary>
/// <returns>
/// The stats if there were any to fetch. Otherwise null.
/// </returns>
/// <param name='category'></param>
/// <param name='statShortName'></param>
public static List<Stat> GetStatsFromEachContainer(string category, string statShortName)
{
SortedDictionary<string, SortedDictionary<string, Stat>> categoryStats;
lock (RegisteredStats)
{
if (!RegisteredStats.TryGetValue(category, out categoryStats))
return null;
List<Stat> stats = null;
foreach (SortedDictionary<string, Stat> containerStats in categoryStats.Values)
{
if (containerStats.ContainsKey(statShortName))
{
if (stats == null)
stats = new List<Stat>();
stats.Add(containerStats[statShortName]);
}
}
return stats;
}
}
public static bool TryGetStatParents(
Stat stat, Stat stat,
out SortedDictionary<string, SortedDictionary<string, Stat>> category, out SortedDictionary<string, SortedDictionary<string, Stat>> category,
out SortedDictionary<string, Stat> container) out SortedDictionary<string, Stat> container)

View File

@ -67,11 +67,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{ {
m_udpServer.AddScene(scene); m_udpServer.AddScene(scene);
StatsManager.RegisterStat(
new Stat(
"ClientLogoutsDueToNoReceives",
"Number of times a client has been logged out because no packets were received before the timeout.",
"",
"",
"clientstack",
scene.Name,
StatType.Pull,
MeasuresOfInterest.None,
stat => stat.Value = m_udpServer.ClientLogoutsDueToNoReceives,
StatVerbosity.Debug));
StatsManager.RegisterStat( StatsManager.RegisterStat(
new Stat( new Stat(
"IncomingUDPReceivesCount", "IncomingUDPReceivesCount",
"Number of UDP receives performed", "Number of UDP receives performed",
"Number of UDP receives performed", "",
"", "",
"clientstack", "clientstack",
scene.Name, scene.Name,
@ -84,7 +97,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
new Stat( new Stat(
"IncomingPacketsProcessedCount", "IncomingPacketsProcessedCount",
"Number of inbound LL protocol packets processed", "Number of inbound LL protocol packets processed",
"Number of inbound LL protocol packets processed", "",
"", "",
"clientstack", "clientstack",
scene.Name, scene.Name,
@ -97,7 +110,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
new Stat( new Stat(
"OutgoingUDPSendsCount", "OutgoingUDPSendsCount",
"Number of UDP sends performed", "Number of UDP sends performed",
"Number of UDP sends performed", "",
"", "",
"clientstack", "clientstack",
scene.Name, scene.Name,
@ -149,6 +162,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// <summary>Maximum transmission unit, or UDP packet size, for the LLUDP protocol</summary> /// <summary>Maximum transmission unit, or UDP packet size, for the LLUDP protocol</summary>
public const int MTU = 1400; public const int MTU = 1400;
/// <summary>Number of forced client logouts due to no receipt of packets before timeout.</summary>
public int ClientLogoutsDueToNoReceives { get; private set; }
/// <summary> /// <summary>
/// Default packet debug level given to new clients /// Default packet debug level given to new clients
/// </summary> /// </summary>
@ -1037,7 +1053,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
timeoutTicks = m_pausedAckTimeout; timeoutTicks = m_pausedAckTimeout;
if (client.IsActive && if (client.IsActive &&
(Environment.TickCount & Int32.MaxValue) - udpClient.TickLastPacketReceived > timeoutTicks) (Environment.TickCount & Int32.MaxValue) - udpClient.TickLastPacketReceived > -1)
{ {
// We must set IsActive synchronously so that we can stop the packet loop reinvoking this method, even // We must set IsActive synchronously so that we can stop the packet loop reinvoking this method, even
// though it's set later on by LLClientView.Close() // though it's set later on by LLClientView.Close()
@ -1778,7 +1794,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
"[LLUDPSERVER]: Ack timeout, disconnecting {0} agent for {1} in {2}", "[LLUDPSERVER]: Ack timeout, disconnecting {0} agent for {1} in {2}",
client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, m_scene.RegionInfo.RegionName); client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, m_scene.RegionInfo.RegionName);
StatsManager.SimExtraStats.AddAbnormalClientThreadTermination(); ClientLogoutsDueToNoReceives++;
if (!client.SceneAgent.IsChildAgent) if (!client.SceneAgent.IsChildAgent)
client.Kick("Simulator logged you out due to connection timeout"); client.Kick("Simulator logged you out due to connection timeout");