Add very basic test which invokes the scene update loop once and checks the frame number.

This makes Scene.Update() match its original description of performing a single update, which also matches the semantics of SOG and ScenePresence.
0.7.1-dev
Justin Clark-Casey (justincc) 2011-02-18 21:54:44 +00:00
parent e774679f62
commit 88da253c94
3 changed files with 232 additions and 165 deletions

View File

@ -129,7 +129,16 @@ namespace OpenSim.Region.Framework.Scenes
protected ICapabilitiesModule m_capsModule; protected ICapabilitiesModule m_capsModule;
// Central Update Loop // Central Update Loop
protected int m_fps = 10; protected int m_fps = 10;
protected uint m_frame;
/// <summary>
/// Current scene frame number
/// </summary>
public uint Frame
{
get;
protected set;
}
protected float m_timespan = 0.089f; protected float m_timespan = 0.089f;
protected DateTime m_lastupdate = DateTime.UtcNow; protected DateTime m_lastupdate = DateTime.UtcNow;
@ -1183,7 +1192,8 @@ namespace OpenSim.Region.Framework.Scenes
try try
{ {
Update(); while (!shuttingdown)
Update();
m_lastUpdate = Util.EnvironmentTickCount(); m_lastUpdate = Util.EnvironmentTickCount();
m_firstHeartbeat = false; m_firstHeartbeat = false;
@ -1200,188 +1210,177 @@ namespace OpenSim.Region.Framework.Scenes
Watchdog.RemoveThread(); Watchdog.RemoveThread();
} }
/// <summary>
/// Performs per-frame updates on the scene, this should be the central scene loop
/// </summary>
public override void Update() public override void Update()
{ {
float physicsFPS; TimeSpan SinceLastFrame = DateTime.UtcNow - m_lastupdate;
int maintc; float physicsFPS = 0f;
while (!shuttingdown) int maintc = Util.EnvironmentTickCount();
int tmpFrameMS = maintc;
tempOnRezMS = eventMS = backupMS = terrainMS = landMS = 0;
// Increment the frame counter
++Frame;
try
{ {
TimeSpan SinceLastFrame = DateTime.UtcNow - m_lastupdate; // Check if any objects have reached their targets
physicsFPS = 0f; CheckAtTargets();
maintc = Util.EnvironmentTickCount(); // Update SceneObjectGroups that have scheduled themselves for updates
int tmpFrameMS = maintc; // Objects queue their updates onto all scene presences
tempOnRezMS = eventMS = backupMS = terrainMS = landMS = 0; if (Frame % m_update_objects == 0)
m_sceneGraph.UpdateObjectGroups();
// Increment the frame counter // Run through all ScenePresences looking for updates
++m_frame; // Presence updates and queued object updates for each presence are sent to clients
if (Frame % m_update_presences == 0)
m_sceneGraph.UpdatePresences();
try // Coarse locations relate to positions of green dots on the mini-map (on a SecondLife client)
if (Frame % m_update_coarse_locations == 0)
{ {
// Check if any objects have reached their targets List<Vector3> coarseLocations;
CheckAtTargets(); List<UUID> avatarUUIDs;
SceneGraph.GetCoarseLocations(out coarseLocations, out avatarUUIDs, 60);
// Update SceneObjectGroups that have scheduled themselves for updates // Send coarse locations to clients
// Objects queue their updates onto all scene presences ForEachScenePresence(delegate(ScenePresence presence)
if (m_frame % m_update_objects == 0)
m_sceneGraph.UpdateObjectGroups();
// Run through all ScenePresences looking for updates
// Presence updates and queued object updates for each presence are sent to clients
if (m_frame % m_update_presences == 0)
m_sceneGraph.UpdatePresences();
// Coarse locations relate to positions of green dots on the mini-map (on a SecondLife client)
if (m_frame % m_update_coarse_locations == 0)
{ {
List<Vector3> coarseLocations; presence.SendCoarseLocations(coarseLocations, avatarUUIDs);
List<UUID> avatarUUIDs; });
SceneGraph.GetCoarseLocations(out coarseLocations, out avatarUUIDs, 60); }
// Send coarse locations to clients
ForEachScenePresence(delegate(ScenePresence presence) int tmpPhysicsMS2 = Util.EnvironmentTickCount();
{ if ((Frame % m_update_physics == 0) && m_physics_enabled)
presence.SendCoarseLocations(coarseLocations, avatarUUIDs); m_sceneGraph.UpdatePreparePhysics();
}); physicsMS2 = Util.EnvironmentTickCountSubtract(tmpPhysicsMS2);
// Apply any pending avatar force input to the avatar's velocity
if (Frame % m_update_entitymovement == 0)
m_sceneGraph.UpdateScenePresenceMovement();
// Perform the main physics update. This will do the actual work of moving objects and avatars according to their
// velocity
int tmpPhysicsMS = Util.EnvironmentTickCount();
if (Frame % m_update_physics == 0)
{
if (m_physics_enabled)
physicsFPS = m_sceneGraph.UpdatePhysics(Math.Max(SinceLastFrame.TotalSeconds, m_timespan));
if (SynchronizeScene != null)
SynchronizeScene(this);
}
physicsMS = Util.EnvironmentTickCountSubtract(tmpPhysicsMS);
// Delete temp-on-rez stuff
if (Frame % 1000 == 0 && !m_cleaningTemps)
{
int tmpTempOnRezMS = Util.EnvironmentTickCount();
m_cleaningTemps = true;
Util.FireAndForget(delegate { CleanTempObjects(); m_cleaningTemps = false; });
tempOnRezMS = Util.EnvironmentTickCountSubtract(tmpTempOnRezMS);
}
if (RegionStatus != RegionStatus.SlaveScene)
{
if (Frame % m_update_events == 0)
{
int evMS = Util.EnvironmentTickCount();
UpdateEvents();
eventMS = Util.EnvironmentTickCountSubtract(evMS); ;
} }
int tmpPhysicsMS2 = Util.EnvironmentTickCount(); if (Frame % m_update_backup == 0)
if ((m_frame % m_update_physics == 0) && m_physics_enabled)
m_sceneGraph.UpdatePreparePhysics();
physicsMS2 = Util.EnvironmentTickCountSubtract(tmpPhysicsMS2);
// Apply any pending avatar force input to the avatar's velocity
if (m_frame % m_update_entitymovement == 0)
m_sceneGraph.UpdateScenePresenceMovement();
// Perform the main physics update. This will do the actual work of moving objects and avatars according to their
// velocity
int tmpPhysicsMS = Util.EnvironmentTickCount();
if (m_frame % m_update_physics == 0)
{ {
if (m_physics_enabled) int backMS = Util.EnvironmentTickCount();
physicsFPS = m_sceneGraph.UpdatePhysics(Math.Max(SinceLastFrame.TotalSeconds, m_timespan)); UpdateStorageBackup();
if (SynchronizeScene != null) backupMS = Util.EnvironmentTickCountSubtract(backMS);
SynchronizeScene(this);
}
physicsMS = Util.EnvironmentTickCountSubtract(tmpPhysicsMS);
// Delete temp-on-rez stuff
if (m_frame % 1000 == 0 && !m_cleaningTemps)
{
int tmpTempOnRezMS = Util.EnvironmentTickCount();
m_cleaningTemps = true;
Util.FireAndForget(delegate { CleanTempObjects(); m_cleaningTemps = false; });
tempOnRezMS = Util.EnvironmentTickCountSubtract(tmpTempOnRezMS);
} }
if (RegionStatus != RegionStatus.SlaveScene) if (Frame % m_update_terrain == 0)
{ {
if (m_frame % m_update_events == 0) int terMS = Util.EnvironmentTickCount();
{ UpdateTerrain();
int evMS = Util.EnvironmentTickCount(); terrainMS = Util.EnvironmentTickCountSubtract(terMS);
UpdateEvents();
eventMS = Util.EnvironmentTickCountSubtract(evMS); ;
}
if (m_frame % m_update_backup == 0)
{
int backMS = Util.EnvironmentTickCount();
UpdateStorageBackup();
backupMS = Util.EnvironmentTickCountSubtract(backMS);
}
if (m_frame % m_update_terrain == 0)
{
int terMS = Util.EnvironmentTickCount();
UpdateTerrain();
terrainMS = Util.EnvironmentTickCountSubtract(terMS);
}
//if (m_frame % m_update_land == 0)
//{
// int ldMS = Util.EnvironmentTickCount();
// UpdateLand();
// landMS = Util.EnvironmentTickCountSubtract(ldMS);
//}
frameMS = Util.EnvironmentTickCountSubtract(tmpFrameMS);
otherMS = tempOnRezMS + eventMS + backupMS + terrainMS + landMS;
lastCompletedFrame = Util.EnvironmentTickCount();
// if (m_frame%m_update_avatars == 0)
// UpdateInWorldTime();
StatsReporter.AddPhysicsFPS(physicsFPS);
StatsReporter.AddTimeDilation(TimeDilation);
StatsReporter.AddFPS(1);
StatsReporter.SetRootAgents(m_sceneGraph.GetRootAgentCount());
StatsReporter.SetChildAgents(m_sceneGraph.GetChildAgentCount());
StatsReporter.SetObjects(m_sceneGraph.GetTotalObjectsCount());
StatsReporter.SetActiveObjects(m_sceneGraph.GetActiveObjectsCount());
StatsReporter.addFrameMS(frameMS);
StatsReporter.addPhysicsMS(physicsMS + physicsMS2);
StatsReporter.addOtherMS(otherMS);
StatsReporter.SetActiveScripts(m_sceneGraph.GetActiveScriptsCount());
StatsReporter.addScriptLines(m_sceneGraph.GetScriptLPS());
} }
if (LoginsDisabled && m_frame == 20) //if (Frame % m_update_land == 0)
{ //{
// In 99.9% of cases it is a bad idea to manually force garbage collection. However, // int ldMS = Util.EnvironmentTickCount();
// this is a rare case where we know we have just went through a long cycle of heap // UpdateLand();
// allocations, and there is no more work to be done until someone logs in // landMS = Util.EnvironmentTickCountSubtract(ldMS);
GC.Collect(); //}
IConfig startupConfig = m_config.Configs["Startup"]; frameMS = Util.EnvironmentTickCountSubtract(tmpFrameMS);
if (startupConfig == null || !startupConfig.GetBoolean("StartDisabled", false)) otherMS = tempOnRezMS + eventMS + backupMS + terrainMS + landMS;
{ lastCompletedFrame = Util.EnvironmentTickCount();
m_log.DebugFormat("[REGION]: Enabling logins for {0}", RegionInfo.RegionName);
LoginsDisabled = false; // if (Frame%m_update_avatars == 0)
m_sceneGridService.InformNeighborsThatRegionisUp(RequestModuleInterface<INeighbourService>(), RegionInfo); // UpdateInWorldTime();
} StatsReporter.AddPhysicsFPS(physicsFPS);
StatsReporter.AddTimeDilation(TimeDilation);
StatsReporter.AddFPS(1);
StatsReporter.SetRootAgents(m_sceneGraph.GetRootAgentCount());
StatsReporter.SetChildAgents(m_sceneGraph.GetChildAgentCount());
StatsReporter.SetObjects(m_sceneGraph.GetTotalObjectsCount());
StatsReporter.SetActiveObjects(m_sceneGraph.GetActiveObjectsCount());
StatsReporter.addFrameMS(frameMS);
StatsReporter.addPhysicsMS(physicsMS + physicsMS2);
StatsReporter.addOtherMS(otherMS);
StatsReporter.SetActiveScripts(m_sceneGraph.GetActiveScriptsCount());
StatsReporter.addScriptLines(m_sceneGraph.GetScriptLPS());
}
if (LoginsDisabled && Frame == 20)
{
// In 99.9% of cases it is a bad idea to manually force garbage collection. However,
// this is a rare case where we know we have just went through a long cycle of heap
// allocations, and there is no more work to be done until someone logs in
GC.Collect();
IConfig startupConfig = m_config.Configs["Startup"];
if (startupConfig == null || !startupConfig.GetBoolean("StartDisabled", false))
{
m_log.DebugFormat("[REGION]: Enabling logins for {0}", RegionInfo.RegionName);
LoginsDisabled = false;
m_sceneGridService.InformNeighborsThatRegionisUp(RequestModuleInterface<INeighbourService>(), RegionInfo);
} }
} }
catch (NotImplementedException)
{
throw;
}
catch (AccessViolationException e)
{
m_log.Error("[REGION]: Failed with exception " + e.ToString() + " On Region: " + RegionInfo.RegionName);
}
//catch (NullReferenceException e)
//{
// m_log.Error("[REGION]: Failed with exception " + e.ToString() + " On Region: " + RegionInfo.RegionName);
//}
catch (InvalidOperationException e)
{
m_log.Error("[REGION]: Failed with exception " + e.ToString() + " On Region: " + RegionInfo.RegionName);
}
catch (Exception e)
{
m_log.Error("[REGION]: Failed with exception " + e.ToString() + " On Region: " + RegionInfo.RegionName);
}
finally
{
m_lastupdate = DateTime.UtcNow;
}
maintc = Util.EnvironmentTickCountSubtract(maintc);
maintc = (int)(m_timespan * 1000) - maintc;
if (maintc > 0)
Thread.Sleep(maintc);
// Tell the watchdog that this thread is still alive
Watchdog.UpdateThread();
} }
catch (NotImplementedException)
{
throw;
}
catch (AccessViolationException e)
{
m_log.Error("[REGION]: Failed with exception " + e.ToString() + " On Region: " + RegionInfo.RegionName);
}
//catch (NullReferenceException e)
//{
// m_log.Error("[REGION]: Failed with exception " + e.ToString() + " On Region: " + RegionInfo.RegionName);
//}
catch (InvalidOperationException e)
{
m_log.Error("[REGION]: Failed with exception " + e.ToString() + " On Region: " + RegionInfo.RegionName);
}
catch (Exception e)
{
m_log.Error("[REGION]: Failed with exception " + e.ToString() + " On Region: " + RegionInfo.RegionName);
}
finally
{
m_lastupdate = DateTime.UtcNow;
}
maintc = Util.EnvironmentTickCountSubtract(maintc);
maintc = (int)(m_timespan * 1000) - maintc;
if (maintc > 0)
Thread.Sleep(maintc);
// Tell the watchdog that this thread is still alive
Watchdog.UpdateThread();
} }
public void AddGroupTarget(SceneObjectGroup grp) public void AddGroupTarget(SceneObjectGroup grp)
{ {
lock (m_groupsWithTargets) lock (m_groupsWithTargets)

View File

@ -116,9 +116,6 @@ namespace OpenSim.Region.Framework.Scenes.Tests
agent.ChildrenCapSeeds = new Dictionary<ulong, string>(); agent.ChildrenCapSeeds = new Dictionary<ulong, string>();
agent.child = true; agent.child = true;
if (scene.PresenceService == null)
Console.WriteLine("Presence Service is null");
scene.PresenceService.LoginAgent(agent.AgentID.ToString(), agent.SessionID, agent.SecureSessionID); scene.PresenceService.LoginAgent(agent.AgentID.ToString(), agent.SessionID, agent.SecureSessionID);
string reason; string reason;

View File

@ -0,0 +1,71 @@
/*
* 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 System.Text;
using System.Threading;
using System.Timers;
using Timer=System.Timers.Timer;
using Nini.Config;
using NUnit.Framework;
using NUnit.Framework.SyntaxHelpers;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Framework.Communications;
using OpenSim.Region.Framework.Scenes;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.CoreModules.World.Serialiser;
using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation;
using OpenSim.Tests.Common;
using OpenSim.Tests.Common.Mock;
using OpenSim.Tests.Common.Setup;
namespace OpenSim.Region.Framework.Scenes.Tests
{
/// <summary>
/// Scene presence tests
/// </summary>
[TestFixture]
public class SceneTests
{
/// <summary>
/// Very basic scene update test. Should become more elaborate with time.
/// </summary>
[Test]
public void TestUpdateScene()
{
TestHelper.InMethod();
Scene scene = SceneSetupHelpers.SetupScene();
scene.Update();
Assert.That(scene.Frame, Is.EqualTo(1));
}
}
}