diff options
author | Dan Lake | 2009-10-13 19:13:06 -0700 |
---|---|---|
committer | John Hurliman | 2009-10-13 19:32:59 -0700 |
commit | 5976ac16b0eedaeca2360010a3d6f7be4213700a (patch) | |
tree | 8f6a80582a4640b5be0c242fd7cf2f19db39a72a | |
parent | * Copied LocklessQueue.cs into OpenSim.Framework and added the .Count propert... (diff) | |
download | opensim-SC_OLD-5976ac16b0eedaeca2360010a3d6f7be4213700a.zip opensim-SC_OLD-5976ac16b0eedaeca2360010a3d6f7be4213700a.tar.gz opensim-SC_OLD-5976ac16b0eedaeca2360010a3d6f7be4213700a.tar.bz2 opensim-SC_OLD-5976ac16b0eedaeca2360010a3d6f7be4213700a.tar.xz |
Optimized heartbeat by calling Update() only on updated objects.
During the heartbeat loop, Update() is called on every SceneObjectGroup which in turn checks if any SceneObjectPart has changed. For large regions (> 100k prims) this work consumes 20-30% of a CPU even though there are only a few objects updating each frame.
There is only one other reason to check every object on every frame, and that is the case where a script has registered the object with an "at target" listener. We can easily track when an object is registered or unregistered with an AtTarget, so this is not a reason to check every object every heartbeat.
In the attached patch, I have added a dictionary to the scene which tracks the objects which have At Targets. Each heartbeat, the AtTarget() function will be called on every object registered with a listener for that event. Also, I added a dictionary to SceneGraph which stores references to objects which have been queued for updates during the heartbeat. At each heartbeat, Update() is called only on the objects which have generated updates during that beat.
-rw-r--r-- | OpenSim/Region/Framework/Scenes/Scene.cs | 82 | ||||
-rw-r--r-- | OpenSim/Region/Framework/Scenes/SceneGraph.cs | 28 | ||||
-rw-r--r-- | OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | 15 |
3 files changed, 52 insertions, 73 deletions
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 7944548..1ca0267 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs | |||
@@ -117,6 +117,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
117 | private volatile bool m_backingup = false; | 117 | private volatile bool m_backingup = false; |
118 | 118 | ||
119 | private Dictionary<UUID, ReturnInfo> m_returns = new Dictionary<UUID, ReturnInfo>(); | 119 | private Dictionary<UUID, ReturnInfo> m_returns = new Dictionary<UUID, ReturnInfo>(); |
120 | |||
121 | private Dictionary<UUID, SceneObjectGroup> m_groupsWithTargets = new Dictionary<UUID, SceneObjectGroup>(); | ||
120 | 122 | ||
121 | protected string m_simulatorVersion = "OpenSimulator Server"; | 123 | protected string m_simulatorVersion = "OpenSimulator Server"; |
122 | 124 | ||
@@ -246,8 +248,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
246 | 248 | ||
247 | private int m_update_physics = 1; | 249 | private int m_update_physics = 1; |
248 | private int m_update_entitymovement = 1; | 250 | private int m_update_entitymovement = 1; |
249 | private int m_update_entities = 1; // Run through all objects checking for updates | 251 | private int m_update_objects = 1; // Update objects which have scheduled themselves for updates |
250 | private int m_update_entitiesquick = 200; // Run through objects that have scheduled updates checking for updates | ||
251 | private int m_update_presences = 1; // Update scene presence movements | 252 | private int m_update_presences = 1; // Update scene presence movements |
252 | private int m_update_events = 1; | 253 | private int m_update_events = 1; |
253 | private int m_update_backup = 200; | 254 | private int m_update_backup = 200; |
@@ -979,28 +980,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
979 | maintc = Environment.TickCount; | 980 | maintc = Environment.TickCount; |
980 | 981 | ||
981 | TimeSpan SinceLastFrame = DateTime.Now - m_lastupdate; | 982 | TimeSpan SinceLastFrame = DateTime.Now - m_lastupdate; |
982 | // Aquire a lock so only one update call happens at once | ||
983 | //updateLock.WaitOne(); | ||
984 | float physicsFPS = 0; | 983 | float physicsFPS = 0; |
985 | //m_log.Info("sadfadf" + m_neighbours.Count.ToString()); | ||
986 | int agentsInScene = m_sceneGraph.GetRootAgentCount() + m_sceneGraph.GetChildAgentCount(); | ||
987 | |||
988 | if (agentsInScene > 21) | ||
989 | { | ||
990 | if (m_update_entities == 1) | ||
991 | { | ||
992 | m_update_entities = 5; | ||
993 | StatsReporter.SetUpdateMS(6000); | ||
994 | } | ||
995 | } | ||
996 | else | ||
997 | { | ||
998 | if (m_update_entities == 5) | ||
999 | { | ||
1000 | m_update_entities = 1; | ||
1001 | StatsReporter.SetUpdateMS(3000); | ||
1002 | } | ||
1003 | } | ||
1004 | 984 | ||
1005 | frameMS = Environment.TickCount; | 985 | frameMS = Environment.TickCount; |
1006 | try | 986 | try |
@@ -1013,30 +993,17 @@ namespace OpenSim.Region.Framework.Scenes | |||
1013 | m_frame = 0; | 993 | m_frame = 0; |
1014 | 994 | ||
1015 | otherMS = Environment.TickCount; | 995 | otherMS = Environment.TickCount; |
1016 | // run through all entities looking for updates (slow) | ||
1017 | if (m_frame % m_update_entities == 0) | ||
1018 | { | ||
1019 | /* // Adam Experimental | ||
1020 | if (m_updateEntitiesThread == null) | ||
1021 | { | ||
1022 | m_updateEntitiesThread = new Thread(m_sceneGraph.UpdateEntities); | ||
1023 | 996 | ||
1024 | ThreadTracker.Add(m_updateEntitiesThread); | 997 | // Check if any objects have reached their targets |
1025 | } | 998 | CheckAtTargets(); |
1026 | 999 | ||
1027 | if (m_updateEntitiesThread.ThreadState == ThreadState.Stopped) | 1000 | // Update SceneObjectGroups that have scheduled themselves for updates |
1028 | m_updateEntitiesThread.Start(); | 1001 | // Objects queue their updates onto all scene presences |
1029 | */ | 1002 | if (m_frame % m_update_objects == 0) |
1030 | 1003 | m_sceneGraph.UpdateObjectGroups(); | |
1031 | m_sceneGraph.UpdateEntities(); | ||
1032 | } | ||
1033 | 1004 | ||
1034 | // run through entities that have scheduled themselves for | 1005 | // Run through all ScenePresences looking for updates |
1035 | // updates looking for updates(faster) | 1006 | // Presence updates and queued object updates for each presence are sent to clients |
1036 | if (m_frame % m_update_entitiesquick == 0) | ||
1037 | m_sceneGraph.ProcessUpdates(); | ||
1038 | |||
1039 | // Run through scenepresences looking for updates | ||
1040 | if (m_frame % m_update_presences == 0) | 1007 | if (m_frame % m_update_presences == 0) |
1041 | m_sceneGraph.UpdatePresences(); | 1008 | m_sceneGraph.UpdatePresences(); |
1042 | 1009 | ||
@@ -1140,6 +1107,31 @@ namespace OpenSim.Region.Framework.Scenes | |||
1140 | } | 1107 | } |
1141 | } | 1108 | } |
1142 | 1109 | ||
1110 | |||
1111 | public void AddGroupTarget(SceneObjectGroup grp) | ||
1112 | { | ||
1113 | lock(m_groupsWithTargets) | ||
1114 | m_groupsWithTargets[grp.UUID] = grp; | ||
1115 | } | ||
1116 | |||
1117 | public void RemoveGroupTarget(SceneObjectGroup grp) | ||
1118 | { | ||
1119 | lock(m_groupsWithTargets) | ||
1120 | m_groupsWithTargets.Remove(grp.UUID); | ||
1121 | } | ||
1122 | |||
1123 | private void CheckAtTargets() | ||
1124 | { | ||
1125 | lock (m_groupsWithTargets) | ||
1126 | { | ||
1127 | foreach (KeyValuePair<UUID, SceneObjectGroup> kvp in m_groupsWithTargets) | ||
1128 | { | ||
1129 | kvp.Value.checkAtTargets(); | ||
1130 | } | ||
1131 | } | ||
1132 | } | ||
1133 | |||
1134 | |||
1143 | /// <summary> | 1135 | /// <summary> |
1144 | /// Send out simstats data to all clients | 1136 | /// Send out simstats data to all clients |
1145 | /// </summary> | 1137 | /// </summary> |
diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index 54ac792..9cd2247 100644 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs | |||
@@ -77,7 +77,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
77 | 77 | ||
78 | protected RegionInfo m_regInfo; | 78 | protected RegionInfo m_regInfo; |
79 | protected Scene m_parentScene; | 79 | protected Scene m_parentScene; |
80 | protected Dictionary<UUID, EntityBase> m_updateList = new Dictionary<UUID, EntityBase>(); | 80 | protected Dictionary<UUID, SceneObjectGroup> m_updateList = new Dictionary<UUID, SceneObjectGroup>(); |
81 | protected int m_numRootAgents = 0; | 81 | protected int m_numRootAgents = 0; |
82 | protected int m_numPrim = 0; | 82 | protected int m_numPrim = 0; |
83 | protected int m_numChildAgents = 0; | 83 | protected int m_numChildAgents = 0; |
@@ -155,16 +155,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
155 | } | 155 | } |
156 | } | 156 | } |
157 | 157 | ||
158 | protected internal void UpdateEntities() | ||
159 | { | ||
160 | List<EntityBase> updateEntities = GetEntities(); | ||
161 | |||
162 | foreach (EntityBase entity in updateEntities) | ||
163 | { | ||
164 | entity.Update(); | ||
165 | } | ||
166 | } | ||
167 | |||
168 | protected internal void UpdatePresences() | 158 | protected internal void UpdatePresences() |
169 | { | 159 | { |
170 | List<ScenePresence> updateScenePresences = GetScenePresences(); | 160 | List<ScenePresence> updateScenePresences = GetScenePresences(); |
@@ -365,12 +355,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
365 | } | 355 | } |
366 | 356 | ||
367 | /// <summary> | 357 | /// <summary> |
368 | /// Add an entity to the list of prims to process on the next update | 358 | /// Add an object to the list of prims to process on the next update |
369 | /// </summary> | 359 | /// </summary> |
370 | /// <param name="obj"> | 360 | /// <param name="obj"> |
371 | /// A <see cref="EntityBase"/> | 361 | /// A <see cref="SceneObjectGroup"/> |
372 | /// </param> | 362 | /// </param> |
373 | protected internal void AddToUpdateList(EntityBase obj) | 363 | protected internal void AddToUpdateList(SceneObjectGroup obj) |
374 | { | 364 | { |
375 | lock (m_updateList) | 365 | lock (m_updateList) |
376 | { | 366 | { |
@@ -381,18 +371,18 @@ namespace OpenSim.Region.Framework.Scenes | |||
381 | /// <summary> | 371 | /// <summary> |
382 | /// Process all pending updates | 372 | /// Process all pending updates |
383 | /// </summary> | 373 | /// </summary> |
384 | protected internal void ProcessUpdates() | 374 | protected internal void UpdateObjectGroups() |
385 | { | 375 | { |
386 | Dictionary<UUID, EntityBase> updates; | 376 | Dictionary<UUID, SceneObjectGroup> updates; |
387 | // Some updates add more updates to the updateList. | 377 | // Some updates add more updates to the updateList. |
388 | // Get the current list of updates and clear the list before iterating | 378 | // Get the current list of updates and clear the list before iterating |
389 | lock (m_updateList) | 379 | lock (m_updateList) |
390 | { | 380 | { |
391 | updates = new Dictionary<UUID, EntityBase>(m_updateList); | 381 | updates = new Dictionary<UUID, SceneObjectGroup>(m_updateList); |
392 | m_updateList.Clear(); | 382 | m_updateList.Clear(); |
393 | } | 383 | } |
394 | // Go through all timers | 384 | // Go through all updates |
395 | foreach (KeyValuePair<UUID, EntityBase> kvp in updates) | 385 | foreach (KeyValuePair<UUID, SceneObjectGroup> kvp in updates) |
396 | { | 386 | { |
397 | // Don't abort the whole update if one entity happens to give us an exception. | 387 | // Don't abort the whole update if one entity happens to give us an exception. |
398 | try | 388 | try |
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 6a10618..d4cef7d 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | |||
@@ -1234,6 +1234,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1234 | { | 1234 | { |
1235 | lock (m_targets) | 1235 | lock (m_targets) |
1236 | m_targets.Clear(); | 1236 | m_targets.Clear(); |
1237 | m_scene.RemoveGroupTarget(this); | ||
1237 | } | 1238 | } |
1238 | 1239 | ||
1239 | ScheduleGroupForFullUpdate(); | 1240 | ScheduleGroupForFullUpdate(); |
@@ -1864,12 +1865,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
1864 | m_rootPart.UpdateFlag = 1; | 1865 | m_rootPart.UpdateFlag = 1; |
1865 | lastPhysGroupPos = AbsolutePosition; | 1866 | lastPhysGroupPos = AbsolutePosition; |
1866 | } | 1867 | } |
1867 | //foreach (SceneObjectPart part in m_parts.Values) | ||
1868 | //{ | ||
1869 | //if (part.UpdateFlag == 0) part.UpdateFlag = 1; | ||
1870 | //} | ||
1871 | |||
1872 | checkAtTargets(); | ||
1873 | 1868 | ||
1874 | if (UsePhysics && ((Math.Abs(lastPhysGroupRot.W - GroupRotation.W) > 0.1) | 1869 | if (UsePhysics && ((Math.Abs(lastPhysGroupRot.W - GroupRotation.W) > 0.1) |
1875 | || (Math.Abs(lastPhysGroupRot.X - GroupRotation.X) > 0.1) | 1870 | || (Math.Abs(lastPhysGroupRot.X - GroupRotation.X) > 0.1) |
@@ -3114,6 +3109,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3114 | { | 3109 | { |
3115 | m_targets.Add(handle, waypoint); | 3110 | m_targets.Add(handle, waypoint); |
3116 | } | 3111 | } |
3112 | m_scene.AddGroupTarget(this); | ||
3117 | return (int)handle; | 3113 | return (int)handle; |
3118 | } | 3114 | } |
3119 | 3115 | ||
@@ -3121,12 +3117,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
3121 | { | 3117 | { |
3122 | lock (m_targets) | 3118 | lock (m_targets) |
3123 | { | 3119 | { |
3124 | if (m_targets.ContainsKey((uint)handle)) | 3120 | m_targets.Remove((uint)handle); |
3125 | m_targets.Remove((uint)handle); | 3121 | if (m_targets.Count == 0) |
3122 | m_scene.RemoveGroupTarget(this); | ||
3126 | } | 3123 | } |
3127 | } | 3124 | } |
3128 | 3125 | ||
3129 | private void checkAtTargets() | 3126 | public void checkAtTargets() |
3130 | { | 3127 | { |
3131 | if (m_scriptListens_atTarget || m_scriptListens_notAtTarget) | 3128 | if (m_scriptListens_atTarget || m_scriptListens_notAtTarget) |
3132 | { | 3129 | { |