/Aurora/Modules/World/Sim Protection/PhysicsMonitor.cs

https://bitbucket.org/VirtualReality/software-testing · 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. using Aurora.Framework;
  28. using Aurora.Framework.ConsoleFramework;
  29. using Aurora.Framework.Modules;
  30. using Aurora.Framework.Physics;
  31. using Aurora.Framework.SceneInfo;
  32. using Aurora.Framework.Utilities;
  33. using Nini.Config;
  34. using OpenMetaverse;
  35. using System;
  36. using System.Collections.Generic;
  37. using System.Threading;
  38. using System.Timers;
  39. using System.Windows.Forms;
  40. using Timer = System.Timers.Timer;
  41. namespace Aurora.Modules.SimProtection
  42. {
  43. public class PhysicsMonitor : INonSharedRegionModule, IPhysicsMonitor
  44. {
  45. #region Private class
  46. protected class PhysicsStats
  47. {
  48. public float StatAvatarUpdatePosAndVelocity;
  49. public float StatCollisionAccountingTime;
  50. public float StatCollisionOptimizedTime;
  51. public float StatContactLoopTime;
  52. public float StatFindContactsTime;
  53. public float StatPhysicsMoveTime;
  54. public float StatPhysicsTaintTime;
  55. public float StatPrimUpdatePosAndVelocity;
  56. public float StatSendCollisionsTime;
  57. public float StatUnlockedArea;
  58. }
  59. #endregion
  60. #region Declares
  61. public bool m_collectingStats;
  62. protected Dictionary<UUID, PhysicsStats> m_currentPhysicsStats = new Dictionary<UUID, PhysicsStats>();
  63. protected Dictionary<UUID, PhysicsStats> m_lastPhysicsStats = new Dictionary<UUID, PhysicsStats>();
  64. protected DateTime m_lastUpdated = DateTime.Now;
  65. protected Timer m_physicsStatTimer;
  66. protected IScene m_Scene;
  67. protected int m_waitingForCollectionOfStats;
  68. #endregion
  69. #region IPhysicsMonitor Members
  70. public virtual void AddPhysicsStats(UUID RegionID, PhysicsScene scene)
  71. {
  72. if (!m_collectingStats)
  73. return;
  74. lock (m_currentPhysicsStats)
  75. {
  76. PhysicsStats stats;
  77. if (!m_currentPhysicsStats.TryGetValue(RegionID, out stats))
  78. {
  79. stats = new PhysicsStats
  80. {
  81. StatAvatarUpdatePosAndVelocity = scene.StatAvatarUpdatePosAndVelocity,
  82. StatCollisionOptimizedTime = scene.StatCollisionOptimizedTime,
  83. StatPhysicsMoveTime = scene.StatPhysicsMoveTime,
  84. StatPhysicsTaintTime = scene.StatPhysicsTaintTime,
  85. StatPrimUpdatePosAndVelocity = scene.StatPrimUpdatePosAndVelocity,
  86. StatSendCollisionsTime = scene.StatSendCollisionsTime,
  87. StatUnlockedArea = scene.StatUnlockedArea,
  88. StatFindContactsTime = scene.StatFindContactsTime,
  89. StatContactLoopTime = scene.StatContactLoopTime,
  90. StatCollisionAccountingTime = scene.StatCollisionAccountingTime
  91. };
  92. }
  93. else
  94. {
  95. stats.StatAvatarUpdatePosAndVelocity += scene.StatAvatarUpdatePosAndVelocity;
  96. stats.StatCollisionOptimizedTime += scene.StatCollisionOptimizedTime;
  97. stats.StatPhysicsMoveTime += scene.StatPhysicsMoveTime;
  98. stats.StatPhysicsTaintTime += scene.StatPhysicsTaintTime;
  99. stats.StatPrimUpdatePosAndVelocity += scene.StatPrimUpdatePosAndVelocity;
  100. stats.StatSendCollisionsTime += scene.StatSendCollisionsTime;
  101. stats.StatUnlockedArea += scene.StatUnlockedArea;
  102. stats.StatFindContactsTime += scene.StatFindContactsTime;
  103. stats.StatContactLoopTime += scene.StatContactLoopTime;
  104. stats.StatCollisionAccountingTime += scene.StatCollisionAccountingTime;
  105. }
  106. m_currentPhysicsStats[RegionID] = stats;
  107. PhysicsStats ProfilerStats = new PhysicsStats
  108. {
  109. StatAvatarUpdatePosAndVelocity =
  110. scene.StatAvatarUpdatePosAndVelocity,
  111. StatCollisionOptimizedTime = scene.StatCollisionOptimizedTime,
  112. StatPhysicsMoveTime = scene.StatPhysicsMoveTime,
  113. StatPhysicsTaintTime = scene.StatPhysicsTaintTime,
  114. StatPrimUpdatePosAndVelocity = scene.StatPrimUpdatePosAndVelocity,
  115. StatSendCollisionsTime = scene.StatSendCollisionsTime,
  116. StatUnlockedArea = scene.StatUnlockedArea,
  117. StatFindContactsTime = scene.StatFindContactsTime,
  118. StatContactLoopTime = scene.StatContactLoopTime,
  119. StatCollisionAccountingTime = scene.StatCollisionAccountingTime
  120. };
  121. //Add the stats to the profiler
  122. Profiler p = ProfilerManager.GetProfiler();
  123. p.AddStat("CurrentStatAvatarUpdatePosAndVelocity " + RegionID,
  124. ProfilerStats.StatAvatarUpdatePosAndVelocity);
  125. p.AddStat("CurrentStatCollisionOptimizedTime " + RegionID,
  126. ProfilerStats.StatCollisionOptimizedTime);
  127. p.AddStat("CurrentStatPhysicsMoveTime " + RegionID,
  128. ProfilerStats.StatPhysicsMoveTime);
  129. p.AddStat("CurrentStatPhysicsTaintTime " + RegionID,
  130. ProfilerStats.StatPhysicsTaintTime);
  131. p.AddStat("CurrentStatPrimUpdatePosAndVelocity " + RegionID,
  132. ProfilerStats.StatPrimUpdatePosAndVelocity);
  133. p.AddStat("CurrentStatSendCollisionsTime " + RegionID,
  134. ProfilerStats.StatSendCollisionsTime);
  135. p.AddStat("CurrentStatUnlockedArea " + RegionID,
  136. ProfilerStats.StatUnlockedArea);
  137. p.AddStat("CurrentStatFindContactsTime " + RegionID,
  138. ProfilerStats.StatFindContactsTime);
  139. p.AddStat("CurrentStatContactLoopTime " + RegionID,
  140. ProfilerStats.StatContactLoopTime);
  141. p.AddStat("CurrentStatCollisionAccountingTime " + RegionID,
  142. ProfilerStats.StatCollisionAccountingTime);
  143. }
  144. }
  145. #endregion
  146. #region INonSharedRegionModule Members
  147. public string Name
  148. {
  149. get { return "PhysicsMonitor"; }
  150. }
  151. public Type ReplaceableInterface
  152. {
  153. get { return null; }
  154. }
  155. public void Initialise(IConfigSource source)
  156. {
  157. if (m_physicsStatTimer == null)
  158. {
  159. m_physicsStatTimer = new Timer {Interval = 10000};
  160. m_physicsStatTimer.Elapsed += PhysicsStatsHeartbeat;
  161. }
  162. }
  163. public void Close()
  164. {
  165. }
  166. public void AddRegion(IScene scene)
  167. {
  168. m_Scene = scene;
  169. scene.RegisterModuleInterface<IPhysicsMonitor>(this);
  170. if (MainConsole.Instance != null)
  171. {
  172. MainConsole.Instance.Commands.AddCommand(
  173. "physics stats", "physics stats", "physics stats <region>", PhysicsStatsCommand);
  174. MainConsole.Instance.Commands.AddCommand(
  175. "physics profiler", "physics profiler", "physics profiler <region>", PhysicsProfilerCommand);
  176. MainConsole.Instance.Commands.AddCommand(
  177. "physics current stats", "physics current stats",
  178. "physics current stats <region> NOTE: these are not calculated and are in milliseconds per unknown time",
  179. CurrentPhysicsStatsCommand);
  180. }
  181. }
  182. public void RemoveRegion(IScene scene)
  183. {
  184. m_Scene = null;
  185. scene.UnregisterModuleInterface<IPhysicsMonitor>(this);
  186. }
  187. public void RegionLoaded(IScene scene)
  188. {
  189. }
  190. #endregion
  191. protected virtual void PhysicsStatsCommand(string[] cmd)
  192. {
  193. if (cmd.Length == 3)
  194. {
  195. if (m_Scene.RegionInfo.RegionName != cmd[2])
  196. return;
  197. }
  198. //Set all the bools to true
  199. m_collectingStats = true;
  200. m_waitingForCollectionOfStats = 1;
  201. //Start the timer as well
  202. m_physicsStatTimer.Start();
  203. MainConsole.Instance.Info("Collecting Stats Now... Please wait...");
  204. while (m_waitingForCollectionOfStats > 0)
  205. {
  206. Thread.Sleep(50);
  207. }
  208. PhysicsStats stats = null;
  209. while (stats == null)
  210. {
  211. m_lastPhysicsStats.TryGetValue(m_Scene.RegionInfo.RegionID, out stats);
  212. }
  213. DumpStatsToConsole(m_Scene, stats);
  214. }
  215. protected virtual void PhysicsProfilerCommand(string[] cmd)
  216. {
  217. if (cmd.Length == 3)
  218. {
  219. if (m_Scene.RegionInfo.RegionName != cmd[2])
  220. return;
  221. }
  222. //Set all the bools to true
  223. m_collectingStats = true;
  224. m_waitingForCollectionOfStats = 1;
  225. //Start the timer as well
  226. m_physicsStatTimer.Start();
  227. MainConsole.Instance.Info("Collecting Stats Now... Please wait...");
  228. while (m_waitingForCollectionOfStats > 0)
  229. {
  230. Thread.Sleep(50);
  231. }
  232. Thread thread = new Thread(StartThread);
  233. thread.Start(new List<IScene>() {m_Scene});
  234. }
  235. private void StartThread(object scenes)
  236. {
  237. Culture.SetCurrentCulture();
  238. try
  239. {
  240. List<IScene> scenesToRun = (List<IScene>) scenes;
  241. Application.Run(new PhysicsProfilerForm(this, scenesToRun));
  242. }
  243. catch (Exception ex)
  244. {
  245. MainConsole.Instance.Warn("There was an error opening the form: " + ex);
  246. }
  247. }
  248. protected virtual void CurrentPhysicsStatsCommand(string[] cmd)
  249. {
  250. if (cmd.Length == 3)
  251. {
  252. if (m_Scene.RegionInfo.RegionName != cmd[2])
  253. return;
  254. }
  255. //Set all the bools to true
  256. m_collectingStats = true;
  257. m_waitingForCollectionOfStats = 1;
  258. //Start the timer as well
  259. m_physicsStatTimer.Start();
  260. MainConsole.Instance.Info("Collecting Stats Now... Please wait...");
  261. while (m_waitingForCollectionOfStats > 0)
  262. {
  263. Thread.Sleep(50);
  264. }
  265. PhysicsStats stats = null;
  266. while (stats == null)
  267. {
  268. m_currentPhysicsStats.TryGetValue(m_Scene.RegionInfo.RegionID, out stats);
  269. }
  270. DumpStatsToConsole(m_Scene, stats);
  271. }
  272. protected virtual void DumpStatsToConsole(IScene scene, PhysicsStats stats)
  273. {
  274. MainConsole.Instance.Info("------ Physics Stats for region " + scene.RegionInfo.RegionName + " ------");
  275. MainConsole.Instance.Info(" All stats are in milliseconds spent per second.");
  276. MainConsole.Instance.Info(" These are in the order they are run in the PhysicsScene.");
  277. MainConsole.Instance.Info(" PhysicsTaintTime: " + stats.StatPhysicsTaintTime);
  278. MainConsole.Instance.Info(" PhysicsMoveTime: " + stats.StatPhysicsMoveTime);
  279. MainConsole.Instance.Info(" FindContactsTime: " + stats.StatFindContactsTime);
  280. MainConsole.Instance.Info(" ContactLoopTime: " + stats.StatContactLoopTime);
  281. MainConsole.Instance.Info(" CollisionAccountingTime: " + stats.StatCollisionAccountingTime);
  282. MainConsole.Instance.Info(" CollisionOptimizedTime: " + stats.StatCollisionOptimizedTime);
  283. MainConsole.Instance.Info(" SendCollisionsTime: " + stats.StatSendCollisionsTime);
  284. MainConsole.Instance.Info(" AvatarUpdatePosAndVelocity: " + stats.StatAvatarUpdatePosAndVelocity);
  285. MainConsole.Instance.Info(" PrimUpdatePosAndVelocity: " + stats.StatPrimUpdatePosAndVelocity);
  286. MainConsole.Instance.Info(" UnlockedArea: " + stats.StatUnlockedArea);
  287. MainConsole.Instance.Info("");
  288. }
  289. protected virtual void PhysicsStatsHeartbeat(object sender, ElapsedEventArgs e)
  290. {
  291. if (!m_collectingStats || m_currentPhysicsStats.Count == 0)
  292. return;
  293. lock (m_currentPhysicsStats)
  294. {
  295. foreach (KeyValuePair<UUID, PhysicsStats> kvp in m_currentPhysicsStats)
  296. {
  297. //Save the stats in the last one so we can keep them for the console commands
  298. //Divide by 10 so we get per second
  299. m_lastPhysicsStats[kvp.Key] = kvp.Value;
  300. m_lastPhysicsStats[kvp.Key].StatAvatarUpdatePosAndVelocity /= 10;
  301. m_lastPhysicsStats[kvp.Key].StatCollisionOptimizedTime /= 10;
  302. m_lastPhysicsStats[kvp.Key].StatPhysicsMoveTime /= 10;
  303. m_lastPhysicsStats[kvp.Key].StatPhysicsTaintTime /= 10;
  304. m_lastPhysicsStats[kvp.Key].StatPrimUpdatePosAndVelocity /= 10;
  305. m_lastPhysicsStats[kvp.Key].StatSendCollisionsTime /= 10;
  306. m_lastPhysicsStats[kvp.Key].StatUnlockedArea /= 10;
  307. m_lastPhysicsStats[kvp.Key].StatFindContactsTime /= 10;
  308. m_lastPhysicsStats[kvp.Key].StatContactLoopTime /= 10;
  309. m_lastPhysicsStats[kvp.Key].StatCollisionAccountingTime /= 10;
  310. //Add the stats to the profiler
  311. Profiler p = ProfilerManager.GetProfiler();
  312. p.AddStat("StatAvatarUpdatePosAndVelocity " + kvp.Key,
  313. m_lastPhysicsStats[kvp.Key].StatAvatarUpdatePosAndVelocity);
  314. p.AddStat("StatCollisionOptimizedTime " + kvp.Key,
  315. m_lastPhysicsStats[kvp.Key].StatCollisionOptimizedTime);
  316. p.AddStat("StatPhysicsMoveTime " + kvp.Key,
  317. m_lastPhysicsStats[kvp.Key].StatPhysicsMoveTime);
  318. p.AddStat("StatPhysicsTaintTime " + kvp.Key,
  319. m_lastPhysicsStats[kvp.Key].StatPhysicsTaintTime);
  320. p.AddStat("StatPrimUpdatePosAndVelocity " + kvp.Key,
  321. m_lastPhysicsStats[kvp.Key].StatPrimUpdatePosAndVelocity);
  322. p.AddStat("StatSendCollisionsTime " + kvp.Key,
  323. m_lastPhysicsStats[kvp.Key].StatSendCollisionsTime);
  324. p.AddStat("StatUnlockedArea " + kvp.Key,
  325. m_lastPhysicsStats[kvp.Key].StatUnlockedArea);
  326. p.AddStat("StatFindContactsTime " + kvp.Key,
  327. m_lastPhysicsStats[kvp.Key].StatFindContactsTime);
  328. p.AddStat("StatContactLoopTime " + kvp.Key,
  329. m_lastPhysicsStats[kvp.Key].StatContactLoopTime);
  330. p.AddStat("StatCollisionAccountingTime " + kvp.Key,
  331. m_lastPhysicsStats[kvp.Key].StatCollisionAccountingTime);
  332. }
  333. m_currentPhysicsStats.Clear();
  334. }
  335. m_lastUpdated = DateTime.Now;
  336. //If there are stats waiting, we just pulled them
  337. m_waitingForCollectionOfStats--;
  338. }
  339. }
  340. }