From e717398f6c72bdb30e59468462f3a5f589c1bb35 Mon Sep 17 00:00:00 2001
From: Justin Clark-Casey (justincc)
Date: Thu, 4 Oct 2012 00:32:42 +0100
Subject: Add experimental "slow frames" stat, available in "show stats" and
via the monitoring module.
This increments a SlowFrames counter if a frame takes over 120% of maximum time.
This commit also introduces a generic OpenSim.Framework.Monitoring.Stat which is available to any code that wants to register a statistic.
This is more granualar than asking objects to create their own reports.
At some point this will supersede earlier IMonitor and IAlert facilities in MonitoringModule which are only available to scene code.
---
.../Region/Framework/Scenes/SimStatsReporter.cs | 33 ++++++++++++++++++++++
1 file changed, 33 insertions(+)
(limited to 'OpenSim/Region')
diff --git a/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs b/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs
index 96317c3..b7b5ea2 100644
--- a/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs
+++ b/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs
@@ -47,6 +47,7 @@ namespace OpenSim.Region.Framework.Scenes
= log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
public const string LastReportedObjectUpdateStatName = "LastReportedObjectUpdates";
+ public const string SlowFramesStatName = "SlowFrames";
public delegate void SendStatResult(SimStats stats);
@@ -129,6 +130,16 @@ namespace OpenSim.Region.Framework.Scenes
}
///
+ /// Number of frames that have taken longer to process than Scene.MIN_FRAME_TIME
+ ///
+ public Stat SlowFramesStat { get; private set; }
+
+ ///
+ /// The threshold at which we log a slow frame.
+ ///
+ public int SlowFramesStatReportThreshold { get; private set; }
+
+ ///
/// Extra sim statistics that are used by monitors but not sent to the client.
///
///
@@ -225,6 +236,22 @@ namespace OpenSim.Region.Framework.Scenes
if (StatsManager.SimExtraStats != null)
OnSendStatsResult += StatsManager.SimExtraStats.ReceiveClassicSimStatsPacket;
+
+ /// At the moment, we'll only report if a frame is over 120% of target, since commonly frames are a bit
+ /// longer than ideal (which in itself is a concern).
+ SlowFramesStatReportThreshold = (int)Math.Ceiling(m_scene.MinFrameTime * 1000 * 1.2);
+
+ SlowFramesStat
+ = new Stat(
+ "SlowFrames",
+ "Slow Frames",
+ "frames",
+ "scene",
+ m_scene.Name,
+ StatVerbosity.Info,
+ "Number of frames where frame time has been significantly longer than the desired frame time.");
+
+ StatsManager.RegisterStat(SlowFramesStat);
}
public void Close()
@@ -418,6 +445,7 @@ namespace OpenSim.Region.Framework.Scenes
lock (m_lastReportedExtraSimStats)
{
m_lastReportedExtraSimStats[LastReportedObjectUpdateStatName] = m_objectUpdates / m_statsUpdateFactor;
+ m_lastReportedExtraSimStats[SlowFramesStat.ShortName] = (float)SlowFramesStat.Value;
Dictionary physicsStats = m_scene.PhysicsScene.GetStats();
@@ -535,6 +563,11 @@ namespace OpenSim.Region.Framework.Scenes
public void addFrameMS(int ms)
{
m_frameMS += ms;
+
+ // At the moment, we'll only report if a frame is over 120% of target, since commonly frames are a bit
+ // longer than ideal due to the inaccuracy of the Sleep in Scene.Update() (which in itself is a concern).
+ if (ms > SlowFramesStatReportThreshold)
+ SlowFramesStat.Value++;
}
public void AddSpareMS(int ms)
--
cgit v1.1
From 3d36a6d55cb0bba408f5447d4596c12564366030 Mon Sep 17 00:00:00 2001
From: Justin Clark-Casey (justincc)
Date: Thu, 4 Oct 2012 01:27:40 +0100
Subject: Add generic PercentageStat.
Not yet used.
---
OpenSim/Region/Framework/Scenes/SimStatsReporter.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'OpenSim/Region')
diff --git a/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs b/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs
index b7b5ea2..2addb5b 100644
--- a/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs
+++ b/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs
@@ -245,7 +245,7 @@ namespace OpenSim.Region.Framework.Scenes
= new Stat(
"SlowFrames",
"Slow Frames",
- "frames",
+ " frames",
"scene",
m_scene.Name,
StatVerbosity.Info,
--
cgit v1.1
From aa52c8b20fc041ee505301301a14192ecb8776de Mon Sep 17 00:00:00 2001
From: Justin Clark-Casey (justincc)
Date: Thu, 4 Oct 2012 02:17:57 +0100
Subject: Output monitor data in response to console command on
MainConsole.Instance rather than m_log
This should really be happening for all console commands (though many don't).
However, things might get difficult if both a console command and other code invoke the same paths.
---
OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
(limited to 'OpenSim/Region')
diff --git a/OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs b/OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs
index e135c21..e411585 100644
--- a/OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs
@@ -95,14 +95,14 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
{
foreach (IMonitor monitor in m_staticMonitors)
{
- m_log.InfoFormat(
+ MainConsole.Instance.OutputFormat(
"[MONITOR MODULE]: {0} reports {1} = {2}",
m_scene.RegionInfo.RegionName, monitor.GetFriendlyName(), monitor.GetFriendlyValue());
}
foreach (KeyValuePair tuple in m_scene.StatsReporter.GetExtraSimStats())
{
- m_log.InfoFormat(
+ MainConsole.Instance.OutputFormat(
"[MONITOR MODULE]: {0} reports {1} = {2}",
m_scene.RegionInfo.RegionName, tuple.Key, tuple.Value);
}
--
cgit v1.1
From b977f962fab9be0c823b0b3ae9b4777241c9f22c Mon Sep 17 00:00:00 2001
From: Melanie
Date: Thu, 4 Oct 2012 15:20:04 +0200
Subject: Allow default animation to be stopped to be replaced with another
one. Fixes Mantis #6327
---
.../Framework/Scenes/Animation/AnimationSet.cs | 27 ++++++++++++++--------
.../Scenes/Animation/ScenePresenceAnimator.cs | 18 ++++++++++-----
2 files changed, 29 insertions(+), 16 deletions(-)
(limited to 'OpenSim/Region')
diff --git a/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs b/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs
index 33041e9..ad421ee 100644
--- a/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs
+++ b/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs
@@ -87,7 +87,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation
{
if (m_defaultAnimation.AnimID == animID)
{
- ResetDefaultAnimation();
+ m_defaultAnimation = new OpenSim.Framework.Animation(UUID.Zero, 1, UUID.Zero);
}
else if (HasAnimation(animID))
{
@@ -149,19 +149,26 @@ namespace OpenSim.Region.Framework.Scenes.Animation
{
lock (m_animations)
{
- animIDs = new UUID[m_animations.Count + 1];
- sequenceNums = new int[m_animations.Count + 1];
- objectIDs = new UUID[m_animations.Count + 1];
+ int defaultSize = 0;
+ if (m_defaultAnimation.AnimID != UUID.Zero)
+ defaultSize++;
- animIDs[0] = m_defaultAnimation.AnimID;
- sequenceNums[0] = m_defaultAnimation.SequenceNum;
- objectIDs[0] = m_defaultAnimation.ObjectID;
+ animIDs = new UUID[m_animations.Count + defaultSize];
+ sequenceNums = new int[m_animations.Count + defaultSize];
+ objectIDs = new UUID[m_animations.Count + defaultSize];
+
+ if (m_defaultAnimation.AnimID != UUID.Zero)
+ {
+ animIDs[0] = m_defaultAnimation.AnimID;
+ sequenceNums[0] = m_defaultAnimation.SequenceNum;
+ objectIDs[0] = m_defaultAnimation.ObjectID;
+ }
for (int i = 0; i < m_animations.Count; ++i)
{
- animIDs[i + 1] = m_animations[i].AnimID;
- sequenceNums[i + 1] = m_animations[i].SequenceNum;
- objectIDs[i + 1] = m_animations[i].ObjectID;
+ animIDs[i + defaultSize] = m_animations[i].AnimID;
+ sequenceNums[i + defaultSize] = m_animations[i].SequenceNum;
+ objectIDs[i + defaultSize] = m_animations[i].ObjectID;
}
}
}
diff --git a/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs b/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs
index ff53f45..bb33f07 100644
--- a/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs
+++ b/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs
@@ -408,13 +408,19 @@ namespace OpenSim.Region.Framework.Scenes.Animation
{
lock (m_animations)
{
- CurrentMovementAnimation = DetermineMovementAnimation();
+ string newMovementAnimation = DetermineMovementAnimation();
+ if (CurrentMovementAnimation != newMovementAnimation)
+ {
+ CurrentMovementAnimation = DetermineMovementAnimation();
-// m_log.DebugFormat(
-// "[SCENE PRESENCE ANIMATOR]: Determined animation {0} for {1} in UpdateMovementAnimations()",
-// CurrentMovementAnimation, m_scenePresence.Name);
+// m_log.DebugFormat(
+// "[SCENE PRESENCE ANIMATOR]: Determined animation {0} for {1} in UpdateMovementAnimations()",
+// CurrentMovementAnimation, m_scenePresence.Name);
- TrySetMovementAnimation(CurrentMovementAnimation);
+ // Only set it if it's actually changed, give a script
+ // a chance to stop a default animation
+ TrySetMovementAnimation(CurrentMovementAnimation);
+ }
}
}
@@ -536,4 +542,4 @@ namespace OpenSim.Region.Framework.Scenes.Animation
SendAnimPack(animIDs, sequenceNums, objectIDs);
}
}
-}
\ No newline at end of file
+}
--
cgit v1.1
From f0178a6a413e35a45efcb0f7f0eeffc0daed15fe Mon Sep 17 00:00:00 2001
From: Justin Clark-Casey (justincc)
Date: Fri, 5 Oct 2012 01:12:56 +0100
Subject: refactor: Move OpenSim.Framework.PacketPool to
OpenSim.Region.Clientstack.Linden.UDP
This is to allow it to use OpenSim.Framework.Monitoring in the future.
This is also a better location since the packet pool is linden udp specific
---
.../Region/ClientStack/Linden/UDP/PacketPool.cs | 249 +++++++++++++++++++++
1 file changed, 249 insertions(+)
create mode 100644 OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs
(limited to 'OpenSim/Region')
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs b/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs
new file mode 100644
index 0000000..fc9406b
--- /dev/null
+++ b/OpenSim/Region/ClientStack/Linden/UDP/PacketPool.cs
@@ -0,0 +1,249 @@
+/*
+ * 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.Reflection;
+using OpenMetaverse;
+using OpenMetaverse.Packets;
+using log4net;
+
+namespace OpenSim.Region.ClientStack.LindenUDP
+{
+ public sealed class PacketPool
+ {
+ private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+
+ private static readonly PacketPool instance = new PacketPool();
+
+ private bool packetPoolEnabled = true;
+ private bool dataBlockPoolEnabled = true;
+
+ ///
+ /// Pool of packets available for reuse.
+ ///
+ private readonly Dictionary> pool = new Dictionary>();
+
+ private static Dictionary> DataBlocks =
+ new Dictionary>();
+
+ static PacketPool()
+ {
+ }
+
+ public static PacketPool Instance
+ {
+ get { return instance; }
+ }
+
+ public bool RecyclePackets
+ {
+ set { packetPoolEnabled = value; }
+ get { return packetPoolEnabled; }
+ }
+
+ public bool RecycleDataBlocks
+ {
+ set { dataBlockPoolEnabled = value; }
+ get { return dataBlockPoolEnabled; }
+ }
+
+ public Packet GetPacket(PacketType type)
+ {
+ Packet packet;
+
+ if (!packetPoolEnabled)
+ return Packet.BuildPacket(type);
+
+ lock (pool)
+ {
+ if (!pool.ContainsKey(type) || pool[type] == null || (pool[type]).Count == 0)
+ {
+ // Creating a new packet if we cannot reuse an old package
+ packet = Packet.BuildPacket(type);
+ }
+ else
+ {
+ // Recycle old packages
+ packet = (pool[type]).Pop();
+ }
+ }
+
+ return packet;
+ }
+
+ // private byte[] decoded_header = new byte[10];
+ private static PacketType GetType(byte[] bytes)
+ {
+ byte[] decoded_header = new byte[10 + 8];
+ ushort id;
+ PacketFrequency freq;
+
+ if ((bytes[0] & Helpers.MSG_ZEROCODED) != 0)
+ {
+ Helpers.ZeroDecode(bytes, 16, decoded_header);
+ }
+ else
+ {
+ Buffer.BlockCopy(bytes, 0, decoded_header, 0, 10);
+ }
+
+ if (decoded_header[6] == 0xFF)
+ {
+ if (decoded_header[7] == 0xFF)
+ {
+ id = (ushort) ((decoded_header[8] << 8) + decoded_header[9]);
+ freq = PacketFrequency.Low;
+ }
+ else
+ {
+ id = decoded_header[7];
+ freq = PacketFrequency.Medium;
+ }
+ }
+ else
+ {
+ id = decoded_header[6];
+ freq = PacketFrequency.High;
+ }
+
+ return Packet.GetType(id, freq);
+ }
+
+ public Packet GetPacket(byte[] bytes, ref int packetEnd, byte[] zeroBuffer)
+ {
+ PacketType type = GetType(bytes);
+
+ Array.Clear(zeroBuffer, 0, zeroBuffer.Length);
+
+ int i = 0;
+ Packet packet = GetPacket(type);
+ if (packet == null)
+ m_log.WarnFormat("[PACKETPOOL]: Failed to get packet of type {0}", type);
+ else
+ packet.FromBytes(bytes, ref i, ref packetEnd, zeroBuffer);
+
+ return packet;
+ }
+
+ ///
+ /// Return a packet to the packet pool
+ ///
+ ///
+ public void ReturnPacket(Packet packet)
+ {
+ if (dataBlockPoolEnabled)
+ {
+ switch (packet.Type)
+ {
+ case PacketType.ObjectUpdate:
+ ObjectUpdatePacket oup = (ObjectUpdatePacket)packet;
+
+ foreach (ObjectUpdatePacket.ObjectDataBlock oupod in oup.ObjectData)
+ ReturnDataBlock(oupod);
+
+ oup.ObjectData = null;
+ break;
+
+ case PacketType.ImprovedTerseObjectUpdate:
+ ImprovedTerseObjectUpdatePacket itoup = (ImprovedTerseObjectUpdatePacket)packet;
+
+ foreach (ImprovedTerseObjectUpdatePacket.ObjectDataBlock itoupod in itoup.ObjectData)
+ ReturnDataBlock(itoupod);
+
+ itoup.ObjectData = null;
+ break;
+ }
+ }
+
+ if (packetPoolEnabled)
+ {
+ switch (packet.Type)
+ {
+ // List pooling packets here
+ case PacketType.PacketAck:
+ case PacketType.ObjectUpdate:
+ case PacketType.ImprovedTerseObjectUpdate:
+ lock (pool)
+ {
+ PacketType type = packet.Type;
+
+ if (!pool.ContainsKey(type))
+ {
+ pool[type] = new Stack();
+ }
+
+ if ((pool[type]).Count < 50)
+ {
+ (pool[type]).Push(packet);
+ }
+ }
+ break;
+
+ // Other packets wont pool
+ default:
+ return;
+ }
+ }
+ }
+
+ public static T GetDataBlock() where T: new()
+ {
+ lock (DataBlocks)
+ {
+ Stack