/Aurora/Modules/World/Sim Protection/PhysicsMonitor.cs
C# | 375 lines | 303 code | 35 blank | 37 comment | 28 complexity | 9568e2ed1153a9c4c79b455f93eb19a9 MD5 | raw file
1/* 2 * Copyright (c) Contributors, http://aurora-sim.org/ 3 * See CONTRIBUTORS.TXT for a full list of copyright holders. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * * Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * * Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * * Neither the name of the Aurora-Sim Project nor the 13 * names of its contributors may be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY 17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY 20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28using Aurora.Framework; 29using Aurora.Framework.ConsoleFramework; 30using Aurora.Framework.Modules; 31using Aurora.Framework.Physics; 32using Aurora.Framework.SceneInfo; 33using Aurora.Framework.Utilities; 34using Nini.Config; 35using OpenMetaverse; 36using System; 37using System.Collections.Generic; 38using System.Threading; 39using System.Timers; 40using System.Windows.Forms; 41using Timer = System.Timers.Timer; 42 43namespace Aurora.Modules.SimProtection 44{ 45 public class PhysicsMonitor : INonSharedRegionModule, IPhysicsMonitor 46 { 47 #region Private class 48 49 protected class PhysicsStats 50 { 51 public float StatAvatarUpdatePosAndVelocity; 52 public float StatCollisionAccountingTime; 53 public float StatCollisionOptimizedTime; 54 public float StatContactLoopTime; 55 public float StatFindContactsTime; 56 public float StatPhysicsMoveTime; 57 public float StatPhysicsTaintTime; 58 public float StatPrimUpdatePosAndVelocity; 59 public float StatSendCollisionsTime; 60 public float StatUnlockedArea; 61 } 62 63 #endregion 64 65 #region Declares 66 67 public bool m_collectingStats; 68 69 protected Dictionary<UUID, PhysicsStats> m_currentPhysicsStats = new Dictionary<UUID, PhysicsStats>(); 70 protected Dictionary<UUID, PhysicsStats> m_lastPhysicsStats = new Dictionary<UUID, PhysicsStats>(); 71 protected DateTime m_lastUpdated = DateTime.Now; 72 protected Timer m_physicsStatTimer; 73 protected IScene m_Scene; 74 protected int m_waitingForCollectionOfStats; 75 76 #endregion 77 78 #region IPhysicsMonitor Members 79 80 public virtual void AddPhysicsStats(UUID RegionID, PhysicsScene scene) 81 { 82 if (!m_collectingStats) 83 return; 84 lock (m_currentPhysicsStats) 85 { 86 PhysicsStats stats; 87 if (!m_currentPhysicsStats.TryGetValue(RegionID, out stats)) 88 { 89 stats = new PhysicsStats 90 { 91 StatAvatarUpdatePosAndVelocity = scene.StatAvatarUpdatePosAndVelocity, 92 StatCollisionOptimizedTime = scene.StatCollisionOptimizedTime, 93 StatPhysicsMoveTime = scene.StatPhysicsMoveTime, 94 StatPhysicsTaintTime = scene.StatPhysicsTaintTime, 95 StatPrimUpdatePosAndVelocity = scene.StatPrimUpdatePosAndVelocity, 96 StatSendCollisionsTime = scene.StatSendCollisionsTime, 97 StatUnlockedArea = scene.StatUnlockedArea, 98 StatFindContactsTime = scene.StatFindContactsTime, 99 StatContactLoopTime = scene.StatContactLoopTime, 100 StatCollisionAccountingTime = scene.StatCollisionAccountingTime 101 }; 102 } 103 else 104 { 105 stats.StatAvatarUpdatePosAndVelocity += scene.StatAvatarUpdatePosAndVelocity; 106 stats.StatCollisionOptimizedTime += scene.StatCollisionOptimizedTime; 107 stats.StatPhysicsMoveTime += scene.StatPhysicsMoveTime; 108 stats.StatPhysicsTaintTime += scene.StatPhysicsTaintTime; 109 stats.StatPrimUpdatePosAndVelocity += scene.StatPrimUpdatePosAndVelocity; 110 stats.StatSendCollisionsTime += scene.StatSendCollisionsTime; 111 stats.StatUnlockedArea += scene.StatUnlockedArea; 112 stats.StatFindContactsTime += scene.StatFindContactsTime; 113 stats.StatContactLoopTime += scene.StatContactLoopTime; 114 stats.StatCollisionAccountingTime += scene.StatCollisionAccountingTime; 115 } 116 117 m_currentPhysicsStats[RegionID] = stats; 118 119 PhysicsStats ProfilerStats = new PhysicsStats 120 { 121 StatAvatarUpdatePosAndVelocity = 122 scene.StatAvatarUpdatePosAndVelocity, 123 StatCollisionOptimizedTime = scene.StatCollisionOptimizedTime, 124 StatPhysicsMoveTime = scene.StatPhysicsMoveTime, 125 StatPhysicsTaintTime = scene.StatPhysicsTaintTime, 126 StatPrimUpdatePosAndVelocity = scene.StatPrimUpdatePosAndVelocity, 127 StatSendCollisionsTime = scene.StatSendCollisionsTime, 128 StatUnlockedArea = scene.StatUnlockedArea, 129 StatFindContactsTime = scene.StatFindContactsTime, 130 StatContactLoopTime = scene.StatContactLoopTime, 131 StatCollisionAccountingTime = scene.StatCollisionAccountingTime 132 }; 133 134 //Add the stats to the profiler 135 Profiler p = ProfilerManager.GetProfiler(); 136 p.AddStat("CurrentStatAvatarUpdatePosAndVelocity " + RegionID, 137 ProfilerStats.StatAvatarUpdatePosAndVelocity); 138 p.AddStat("CurrentStatCollisionOptimizedTime " + RegionID, 139 ProfilerStats.StatCollisionOptimizedTime); 140 p.AddStat("CurrentStatPhysicsMoveTime " + RegionID, 141 ProfilerStats.StatPhysicsMoveTime); 142 p.AddStat("CurrentStatPhysicsTaintTime " + RegionID, 143 ProfilerStats.StatPhysicsTaintTime); 144 p.AddStat("CurrentStatPrimUpdatePosAndVelocity " + RegionID, 145 ProfilerStats.StatPrimUpdatePosAndVelocity); 146 p.AddStat("CurrentStatSendCollisionsTime " + RegionID, 147 ProfilerStats.StatSendCollisionsTime); 148 p.AddStat("CurrentStatUnlockedArea " + RegionID, 149 ProfilerStats.StatUnlockedArea); 150 p.AddStat("CurrentStatFindContactsTime " + RegionID, 151 ProfilerStats.StatFindContactsTime); 152 p.AddStat("CurrentStatContactLoopTime " + RegionID, 153 ProfilerStats.StatContactLoopTime); 154 p.AddStat("CurrentStatCollisionAccountingTime " + RegionID, 155 ProfilerStats.StatCollisionAccountingTime); 156 } 157 } 158 159 #endregion 160 161 #region INonSharedRegionModule Members 162 163 public string Name 164 { 165 get { return "PhysicsMonitor"; } 166 } 167 168 public Type ReplaceableInterface 169 { 170 get { return null; } 171 } 172 173 public void Initialise(IConfigSource source) 174 { 175 if (m_physicsStatTimer == null) 176 { 177 m_physicsStatTimer = new Timer {Interval = 10000}; 178 m_physicsStatTimer.Elapsed += PhysicsStatsHeartbeat; 179 } 180 } 181 182 public void Close() 183 { 184 } 185 186 public void AddRegion(IScene scene) 187 { 188 m_Scene = scene; 189 scene.RegisterModuleInterface<IPhysicsMonitor>(this); 190 if (MainConsole.Instance != null) 191 { 192 MainConsole.Instance.Commands.AddCommand( 193 "physics stats", "physics stats", "physics stats <region>", PhysicsStatsCommand); 194 MainConsole.Instance.Commands.AddCommand( 195 "physics profiler", "physics profiler", "physics profiler <region>", PhysicsProfilerCommand); 196 MainConsole.Instance.Commands.AddCommand( 197 "physics current stats", "physics current stats", 198 "physics current stats <region> NOTE: these are not calculated and are in milliseconds per unknown time", 199 CurrentPhysicsStatsCommand); 200 } 201 } 202 203 public void RemoveRegion(IScene scene) 204 { 205 m_Scene = null; 206 scene.UnregisterModuleInterface<IPhysicsMonitor>(this); 207 } 208 209 public void RegionLoaded(IScene scene) 210 { 211 } 212 213 #endregion 214 215 protected virtual void PhysicsStatsCommand(string[] cmd) 216 { 217 if (cmd.Length == 3) 218 { 219 if (m_Scene.RegionInfo.RegionName != cmd[2]) 220 return; 221 } 222 223 //Set all the bools to true 224 m_collectingStats = true; 225 m_waitingForCollectionOfStats = 1; 226 //Start the timer as well 227 m_physicsStatTimer.Start(); 228 MainConsole.Instance.Info("Collecting Stats Now... Please wait..."); 229 while (m_waitingForCollectionOfStats > 0) 230 { 231 Thread.Sleep(50); 232 } 233 234 PhysicsStats stats = null; 235 while (stats == null) 236 { 237 m_lastPhysicsStats.TryGetValue(m_Scene.RegionInfo.RegionID, out stats); 238 } 239 DumpStatsToConsole(m_Scene, stats); 240 } 241 242 protected virtual void PhysicsProfilerCommand(string[] cmd) 243 { 244 if (cmd.Length == 3) 245 { 246 if (m_Scene.RegionInfo.RegionName != cmd[2]) 247 return; 248 } 249 250 //Set all the bools to true 251 m_collectingStats = true; 252 m_waitingForCollectionOfStats = 1; 253 //Start the timer as well 254 m_physicsStatTimer.Start(); 255 MainConsole.Instance.Info("Collecting Stats Now... Please wait..."); 256 while (m_waitingForCollectionOfStats > 0) 257 { 258 Thread.Sleep(50); 259 } 260 261 Thread thread = new Thread(StartThread); 262 thread.Start(new List<IScene>() {m_Scene}); 263 } 264 265 private void StartThread(object scenes) 266 { 267 Culture.SetCurrentCulture(); 268 try 269 { 270 List<IScene> scenesToRun = (List<IScene>) scenes; 271 Application.Run(new PhysicsProfilerForm(this, scenesToRun)); 272 } 273 catch (Exception ex) 274 { 275 MainConsole.Instance.Warn("There was an error opening the form: " + ex); 276 } 277 } 278 279 protected virtual void CurrentPhysicsStatsCommand(string[] cmd) 280 { 281 if (cmd.Length == 3) 282 { 283 if (m_Scene.RegionInfo.RegionName != cmd[2]) 284 return; 285 } 286 287 //Set all the bools to true 288 m_collectingStats = true; 289 m_waitingForCollectionOfStats = 1; 290 //Start the timer as well 291 m_physicsStatTimer.Start(); 292 MainConsole.Instance.Info("Collecting Stats Now... Please wait..."); 293 while (m_waitingForCollectionOfStats > 0) 294 { 295 Thread.Sleep(50); 296 } 297 298 PhysicsStats stats = null; 299 while (stats == null) 300 { 301 m_currentPhysicsStats.TryGetValue(m_Scene.RegionInfo.RegionID, out stats); 302 } 303 DumpStatsToConsole(m_Scene, stats); 304 } 305 306 protected virtual void DumpStatsToConsole(IScene scene, PhysicsStats stats) 307 { 308 MainConsole.Instance.Info("------ Physics Stats for region " + scene.RegionInfo.RegionName + " ------"); 309 MainConsole.Instance.Info(" All stats are in milliseconds spent per second."); 310 MainConsole.Instance.Info(" These are in the order they are run in the PhysicsScene."); 311 MainConsole.Instance.Info(" PhysicsTaintTime: " + stats.StatPhysicsTaintTime); 312 MainConsole.Instance.Info(" PhysicsMoveTime: " + stats.StatPhysicsMoveTime); 313 MainConsole.Instance.Info(" FindContactsTime: " + stats.StatFindContactsTime); 314 MainConsole.Instance.Info(" ContactLoopTime: " + stats.StatContactLoopTime); 315 MainConsole.Instance.Info(" CollisionAccountingTime: " + stats.StatCollisionAccountingTime); 316 MainConsole.Instance.Info(" CollisionOptimizedTime: " + stats.StatCollisionOptimizedTime); 317 MainConsole.Instance.Info(" SendCollisionsTime: " + stats.StatSendCollisionsTime); 318 MainConsole.Instance.Info(" AvatarUpdatePosAndVelocity: " + stats.StatAvatarUpdatePosAndVelocity); 319 MainConsole.Instance.Info(" PrimUpdatePosAndVelocity: " + stats.StatPrimUpdatePosAndVelocity); 320 MainConsole.Instance.Info(" UnlockedArea: " + stats.StatUnlockedArea); 321 MainConsole.Instance.Info(""); 322 } 323 324 protected virtual void PhysicsStatsHeartbeat(object sender, ElapsedEventArgs e) 325 { 326 if (!m_collectingStats || m_currentPhysicsStats.Count == 0) 327 return; 328 lock (m_currentPhysicsStats) 329 { 330 foreach (KeyValuePair<UUID, PhysicsStats> kvp in m_currentPhysicsStats) 331 { 332 //Save the stats in the last one so we can keep them for the console commands 333 //Divide by 10 so we get per second 334 m_lastPhysicsStats[kvp.Key] = kvp.Value; 335 m_lastPhysicsStats[kvp.Key].StatAvatarUpdatePosAndVelocity /= 10; 336 m_lastPhysicsStats[kvp.Key].StatCollisionOptimizedTime /= 10; 337 m_lastPhysicsStats[kvp.Key].StatPhysicsMoveTime /= 10; 338 m_lastPhysicsStats[kvp.Key].StatPhysicsTaintTime /= 10; 339 m_lastPhysicsStats[kvp.Key].StatPrimUpdatePosAndVelocity /= 10; 340 m_lastPhysicsStats[kvp.Key].StatSendCollisionsTime /= 10; 341 m_lastPhysicsStats[kvp.Key].StatUnlockedArea /= 10; 342 m_lastPhysicsStats[kvp.Key].StatFindContactsTime /= 10; 343 m_lastPhysicsStats[kvp.Key].StatContactLoopTime /= 10; 344 m_lastPhysicsStats[kvp.Key].StatCollisionAccountingTime /= 10; 345 //Add the stats to the profiler 346 Profiler p = ProfilerManager.GetProfiler(); 347 p.AddStat("StatAvatarUpdatePosAndVelocity " + kvp.Key, 348 m_lastPhysicsStats[kvp.Key].StatAvatarUpdatePosAndVelocity); 349 p.AddStat("StatCollisionOptimizedTime " + kvp.Key, 350 m_lastPhysicsStats[kvp.Key].StatCollisionOptimizedTime); 351 p.AddStat("StatPhysicsMoveTime " + kvp.Key, 352 m_lastPhysicsStats[kvp.Key].StatPhysicsMoveTime); 353 p.AddStat("StatPhysicsTaintTime " + kvp.Key, 354 m_lastPhysicsStats[kvp.Key].StatPhysicsTaintTime); 355 p.AddStat("StatPrimUpdatePosAndVelocity " + kvp.Key, 356 m_lastPhysicsStats[kvp.Key].StatPrimUpdatePosAndVelocity); 357 p.AddStat("StatSendCollisionsTime " + kvp.Key, 358 m_lastPhysicsStats[kvp.Key].StatSendCollisionsTime); 359 p.AddStat("StatUnlockedArea " + kvp.Key, 360 m_lastPhysicsStats[kvp.Key].StatUnlockedArea); 361 p.AddStat("StatFindContactsTime " + kvp.Key, 362 m_lastPhysicsStats[kvp.Key].StatFindContactsTime); 363 p.AddStat("StatContactLoopTime " + kvp.Key, 364 m_lastPhysicsStats[kvp.Key].StatContactLoopTime); 365 p.AddStat("StatCollisionAccountingTime " + kvp.Key, 366 m_lastPhysicsStats[kvp.Key].StatCollisionAccountingTime); 367 } 368 m_currentPhysicsStats.Clear(); 369 } 370 m_lastUpdated = DateTime.Now; 371 //If there are stats waiting, we just pulled them 372 m_waitingForCollectionOfStats--; 373 } 374 } 375}