From ebe5e1731d24e68ec7a8aa61a397f5febc1c2662 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Wed, 15 Feb 2012 01:45:25 +0000 Subject: [PATCH 1/2] In ObjectTortureTests, run garbage collector on Teardown and run scene loop update when scene objects have been deleted. At least on mono 2.6.4, running GC.Collect() is not guaranteed to force gc of all objects when run in the same method where those objects had references. Therefore, GC.Collect() is now being done in the per-script teardown of ObjectTortureTests. In addition, scene loop update is being run after garbage collection in order to clean out the viewer update list of scene objects in the SceneGraph. These measures mean that scene objects/parts are now garbage collected after a test run if deleted from the scene, resulting in a much better memory usage report (though probably still not very accurate). However, deletion takes a very long time - what's really needed is to find out now why the entire scene isn't being GC'd by this measure. This change hasn't yet been applied to the other stress tests. --- OpenSim/Region/Framework/Scenes/SceneGraph.cs | 10 ++--- .../Framework/Scenes/SceneObjectPart.cs | 3 ++ .../Scenes/Tests/SceneObjectBasicTests.cs | 41 ++++++++++++++++++- OpenSim/Tests/Common/Mock/TestScene.cs | 3 +- OpenSim/Tests/Torture/ObjectTortureTests.cs | 21 +++++++++- 5 files changed, 68 insertions(+), 10 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index 693a79e5df..e66678afb2 100644 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs @@ -359,7 +359,7 @@ namespace OpenSim.Region.Framework.Scenes m_log.ErrorFormat( "[SCENEGRAPH]: Tried to add scene object {0} to {1} with illegal UUID of {2}", sceneObject.Name, m_parentScene.RegionInfo.RegionName, UUID.Zero); - + return false; } @@ -368,12 +368,12 @@ namespace OpenSim.Region.Framework.Scenes // m_log.DebugFormat( // "[SCENEGRAPH]: Scene graph for {0} already contains object {1} in AddSceneObject()", // m_parentScene.RegionInfo.RegionName, sceneObject.UUID); - + return false; } - + // m_log.DebugFormat( -// "[SCENEGRAPH]: Adding scene object {0} {1}, with {2} parts on {3}", +// "[SCENEGRAPH]: Adding scene object {0} {1}, with {2} parts on {3}", // sceneObject.Name, sceneObject.UUID, sceneObject.Parts.Length, m_parentScene.RegionInfo.RegionName); SceneObjectPart[] parts = sceneObject.Parts; @@ -409,7 +409,7 @@ namespace OpenSim.Region.Framework.Scenes lock (SceneObjectGroupsByFullID) SceneObjectGroupsByFullID[sceneObject.UUID] = sceneObject; - + lock (SceneObjectGroupsByFullPartID) { foreach (SceneObjectPart part in parts) diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 4c339d9c8b..b130bf70dc 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -303,6 +303,9 @@ namespace OpenSim.Region.Framework.Scenes // ~SceneObjectPart() // { +// Console.WriteLine( +// "[SCENE OBJECT PART]: Destructor called for {0}, local id {1}, parent {2} {3}", +// Name, LocalId, ParentGroup.Name, ParentGroup.LocalId); // m_log.DebugFormat( // "[SCENE OBJECT PART]: Destructor called for {0}, local id {1}, parent {2} {3}", // Name, LocalId, ParentGroup.Name, ParentGroup.LocalId); diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs index 80f198d2d6..7737d8ea83 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs @@ -27,6 +27,7 @@ using System; using System.Reflection; +using System.Threading; using NUnit.Framework; using OpenMetaverse; using OpenSim.Framework; @@ -43,6 +44,42 @@ namespace OpenSim.Region.Framework.Scenes.Tests [TestFixture] public class SceneObjectBasicTests { +// [TearDown] +// public void TearDown() +// { +// Console.WriteLine("TearDown"); +// GC.Collect(); +// Thread.Sleep(3000); +// } + +// public class GcNotify +// { +// public static AutoResetEvent gcEvent = new AutoResetEvent(false); +// private static bool _initialized = false; +// +// public static void Initialize() +// { +// if (!_initialized) +// { +// _initialized = true; +// new GcNotify(); +// } +// } +// +// private GcNotify(){} +// +// ~GcNotify() +// { +// if (!Environment.HasShutdownStarted && +// !AppDomain.CurrentDomain.IsFinalizingForUnload()) +// { +// Console.WriteLine("GcNotify called"); +// gcEvent.Set(); +// new GcNotify(); +// } +// } +// } + /// /// Test adding an object to a scene. /// @@ -147,11 +184,11 @@ namespace OpenSim.Region.Framework.Scenes.Tests public void TestDeleteSceneObject() { TestHelpers.InMethod(); - + TestScene scene = SceneHelpers.SetupScene(); SceneObjectPart part = SceneHelpers.AddSceneObject(scene); scene.DeleteSceneObject(part.ParentGroup, false); - + SceneObjectPart retrievedPart = scene.GetSceneObjectPart(part.LocalId); Assert.That(retrievedPart, Is.Null); } diff --git a/OpenSim/Tests/Common/Mock/TestScene.cs b/OpenSim/Tests/Common/Mock/TestScene.cs index 328cd2b4e5..eea68c3b40 100644 --- a/OpenSim/Tests/Common/Mock/TestScene.cs +++ b/OpenSim/Tests/Common/Mock/TestScene.cs @@ -50,7 +50,8 @@ namespace OpenSim.Tests.Common.Mock ~TestScene() { - Console.WriteLine("TestScene destructor called for {0}", RegionInfo.RegionName); + //Console.WriteLine("TestScene destructor called for {0}", RegionInfo.RegionName); + Console.WriteLine("TestScene destructor called"); } /// diff --git a/OpenSim/Tests/Torture/ObjectTortureTests.cs b/OpenSim/Tests/Torture/ObjectTortureTests.cs index 74b336eeb9..e83186a929 100644 --- a/OpenSim/Tests/Torture/ObjectTortureTests.cs +++ b/OpenSim/Tests/Torture/ObjectTortureTests.cs @@ -49,6 +49,13 @@ namespace OpenSim.Tests.Torture [TestFixture] public class ObjectTortureTests { + [TearDown] + public void TearDown() + { + GC.Collect(); + GC.WaitForPendingFinalizers(); + } + // [Test] // public void Test0000Clean() // { @@ -141,8 +148,18 @@ namespace OpenSim.Tests.Torture string.Format("Object {0} could not be retrieved", i)); } - // This does not work to fire the SceneObjectGroup destructors - something else is hanging on to them. -// scene.DeleteAllSceneObjects(); + // When a scene object is added to a scene, it is placed in the update list for sending to viewers + // (though in this case we have none). When it is deleted, it is not removed from the update which is + // fine since it will later be ignored. + // + // However, that means that we need to manually run an update here to clear out that list so that deleted + // objects will be clean up by the garbage collector before the next stress test is run. + scene.Update(); + + // Currently, we need to do this in order to garbage collect the scene objects ready for the next test run. + // However, what we really need to do is find out why the entire scene is not garbage collected in + // teardown. + scene.DeleteAllSceneObjects(); Console.WriteLine( "Took {0}ms, {1}MB ({2} - {3}) to create {4} objects each containing {5} prim(s)", From c906128191a6801df46d5542c441ef37c5c456a9 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Thu, 16 Feb 2012 00:15:39 +0000 Subject: [PATCH 2/2] Fix some logic mistakes where firstly osNpcCreate() without options was creating npcs sensed as agents and secondly the OS_NPC_SENSE_AS_AGENT option was having the opposite effect. Hopefully makes progress on addressing http://opensimulator.org/mantis/view.php?id=5872 --- .../OptionalModules/World/NPC/NPCModule.cs | 4 ++-- .../Shared/Api/Implementation/OSSL_Api.cs | 4 ++-- .../Api/Implementation/Plugins/SensorRepeat.cs | 17 ++++++++++++++++- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs index 53593545ef..2052cdb6f4 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs @@ -121,8 +121,8 @@ namespace OpenSim.Region.OptionalModules.World.NPC npcAvatar.CircuitCode = (uint)Util.RandomClass.Next(0, int.MaxValue); m_log.DebugFormat( - "[NPC MODULE]: Creating NPC {0} {1} {2} at {3} in {4}", - firstname, lastname, npcAvatar.AgentId, position, scene.RegionInfo.RegionName); + "[NPC MODULE]: Creating NPC {0} {1} {2}, owner={3}, senseAsAgent={4} at {5} in {6}", + firstname, lastname, npcAvatar.AgentId, owner, senseAsAgent, position, scene.RegionInfo.RegionName); AgentCircuitData acd = new AgentCircuitData(); acd.AgentID = npcAvatar.AgentId; diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs index b1583ebb1e..646a97b44b 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs @@ -2233,7 +2233,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api CheckThreatLevel(ThreatLevel.High, "osNpcCreate"); m_host.AddScriptLPS(1); - return NpcCreate(firstname, lastname, position, notecard, false, true); + return NpcCreate(firstname, lastname, position, notecard, false, false); } public LSL_Key osNpcCreate(string firstname, string lastname, LSL_Vector position, string notecard, int options) @@ -2244,7 +2244,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return NpcCreate( firstname, lastname, position, notecard, (options & ScriptBaseClass.OS_NPC_NOT_OWNED) == 0, - (options & ScriptBaseClass.OS_NPC_SENSE_AS_AGENT) == 0); + (options & ScriptBaseClass.OS_NPC_SENSE_AS_AGENT) != 0); } private LSL_Key NpcCreate( diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs index 850f50b13d..5c1bdff9db 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs @@ -31,7 +31,6 @@ using System.Collections.Generic; using OpenMetaverse; using OpenSim.Framework; using log4net; - using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.ScriptEngine.Shared; @@ -41,6 +40,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins { public class SensorRepeat { +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + public AsyncCommandManager m_CmdManager; public SensorRepeat(AsyncCommandManager CmdManager) @@ -447,11 +448,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins Action senseEntity = new Action(presence => { +// m_log.DebugFormat( +// "[SENSOR REPEAT]: Inspecting scene presence {0}, type {1} on sensor sweep for {2}, type {3}", +// presence.Name, presence.PresenceType, ts.name, ts.type); + if ((ts.type & NPC) == 0 && presence.PresenceType == PresenceType.Npc) { INPC npcData = npcModule.GetNPC(presence.UUID, presence.Scene); if (npcData == null || !npcData.SenseAsAgent) + { +// m_log.DebugFormat( +// "[SENSOR REPEAT]: Discarding NPC {0} from agent sense sweep for script item id {1}", +// presence.Name, ts.itemID); return; + } } if ((ts.type & AGENT) == 0) @@ -464,7 +474,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins { INPC npcData = npcModule.GetNPC(presence.UUID, presence.Scene); if (npcData != null && npcData.SenseAsAgent) + { +// m_log.DebugFormat( +// "[SENSOR REPEAT]: Discarding NPC {0} from non-agent sense sweep for script item id {1}", +// presence.Name, ts.itemID); return; + } } }