Add an optional mechanism for physics modules to collect and return arbitrary stats.

If active, the physics module can return arbitrary stat counters that can be seen via the MonitoringModule
(http://opensimulator.org/wiki/Monitoring_Module)
This is only active in OdeScene if collect_stats = true in [ODEPhysicsSettings].
This patch allows OdeScene to collect elapsed time information for calls to the ODE native collision methods to assess what proportion of time this takes compared to total physics processing.
This data is returned as ODENativeCollisionFrameMS in the monitoring module, updated every 3 seconds.
The performance effect of collecting stats is probably extremely minor, dwarfed by the rest of the physics code.
0.7.4.1
Justin Clark-Casey (justincc) 2012-05-31 01:52:26 +01:00
parent bf0b8170f7
commit 0b02a4d42e
6 changed files with 271 additions and 71 deletions

View File

@ -28,6 +28,7 @@
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.IO; using System.IO;
using System.Reflection; using System.Reflection;
using System.Text; using System.Text;

View File

@ -49,7 +49,16 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
public bool Enabled { get; private set; } public bool Enabled { get; private set; }
private Scene m_scene; private Scene m_scene;
private readonly List<IMonitor> m_monitors = new List<IMonitor>();
/// <summary>
/// These are monitors where we know the static details in advance.
/// </summary>
/// <remarks>
/// Dynamic monitors also exist (we don't know any of the details of what stats we get back here)
/// but these are currently hardcoded.
/// </remarks>
private readonly List<IMonitor> m_staticMonitors = new List<IMonitor>();
private readonly List<IAlert> m_alerts = new List<IAlert>(); private readonly List<IAlert> m_alerts = new List<IAlert>();
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
@ -84,9 +93,18 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
public void DebugMonitors(string module, string[] args) public void DebugMonitors(string module, string[] args)
{ {
foreach (IMonitor monitor in m_monitors) foreach (IMonitor monitor in m_staticMonitors)
{ {
m_log.Info("[MonitorModule]: " + m_scene.RegionInfo.RegionName + " reports " + monitor.GetFriendlyName() + " = " + monitor.GetFriendlyValue()); m_log.InfoFormat(
"[MONITOR MODULE]: {0} reports {1} = {2}",
m_scene.RegionInfo.RegionName, monitor.GetFriendlyName(), monitor.GetFriendlyValue());
}
foreach (KeyValuePair<string, float> tuple in m_scene.StatsReporter.GetExtraSimStats())
{
m_log.InfoFormat(
"[MONITOR MODULE]: {0} reports {1} = {2}",
m_scene.RegionInfo.RegionName, tuple.Key, tuple.Value);
} }
} }
@ -106,11 +124,12 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
{ {
string monID = (string) request["monitor"]; string monID = (string) request["monitor"];
foreach (IMonitor monitor in m_monitors) foreach (IMonitor monitor in m_staticMonitors)
{ {
string elemName = monitor.ToString(); string elemName = monitor.ToString();
if (elemName.StartsWith(monitor.GetType().Namespace)) if (elemName.StartsWith(monitor.GetType().Namespace))
elemName = elemName.Substring(monitor.GetType().Namespace.Length + 1); elemName = elemName.Substring(monitor.GetType().Namespace.Length + 1);
if (elemName == monID || monitor.ToString() == monID) if (elemName == monID || monitor.ToString() == monID)
{ {
Hashtable ereply3 = new Hashtable(); Hashtable ereply3 = new Hashtable();
@ -123,6 +142,9 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
} }
} }
// FIXME: Arguably this should also be done with dynamic monitors but I'm not sure what the above code
// is even doing. Why are we inspecting the type of the monitor???
// No monitor with that name // No monitor with that name
Hashtable ereply2 = new Hashtable(); Hashtable ereply2 = new Hashtable();
@ -134,12 +156,18 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
} }
string xml = "<data>"; string xml = "<data>";
foreach (IMonitor monitor in m_monitors) foreach (IMonitor monitor in m_staticMonitors)
{ {
string elemName = monitor.GetName(); string elemName = monitor.GetName();
xml += "<" + elemName + ">" + monitor.GetValue().ToString() + "</" + elemName + ">"; xml += "<" + elemName + ">" + monitor.GetValue().ToString() + "</" + elemName + ">";
// m_log.DebugFormat("[MONITOR MODULE]: {0} = {1}", elemName, monitor.GetValue()); // m_log.DebugFormat("[MONITOR MODULE]: {0} = {1}", elemName, monitor.GetValue());
} }
foreach (KeyValuePair<string, float> tuple in m_scene.StatsReporter.GetExtraSimStats())
{
xml += "<" + tuple.Key + ">" + tuple.Value + "</" + tuple.Key + ">";
}
xml += "</data>"; xml += "</data>";
Hashtable ereply = new Hashtable(); Hashtable ereply = new Hashtable();
@ -156,20 +184,20 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
if (!Enabled) if (!Enabled)
return; return;
m_monitors.Add(new AgentCountMonitor(m_scene)); m_staticMonitors.Add(new AgentCountMonitor(m_scene));
m_monitors.Add(new ChildAgentCountMonitor(m_scene)); m_staticMonitors.Add(new ChildAgentCountMonitor(m_scene));
m_monitors.Add(new GCMemoryMonitor()); m_staticMonitors.Add(new GCMemoryMonitor());
m_monitors.Add(new ObjectCountMonitor(m_scene)); m_staticMonitors.Add(new ObjectCountMonitor(m_scene));
m_monitors.Add(new PhysicsFrameMonitor(m_scene)); m_staticMonitors.Add(new PhysicsFrameMonitor(m_scene));
m_monitors.Add(new PhysicsUpdateFrameMonitor(m_scene)); m_staticMonitors.Add(new PhysicsUpdateFrameMonitor(m_scene));
m_monitors.Add(new PWSMemoryMonitor()); m_staticMonitors.Add(new PWSMemoryMonitor());
m_monitors.Add(new ThreadCountMonitor()); m_staticMonitors.Add(new ThreadCountMonitor());
m_monitors.Add(new TotalFrameMonitor(m_scene)); m_staticMonitors.Add(new TotalFrameMonitor(m_scene));
m_monitors.Add(new EventFrameMonitor(m_scene)); m_staticMonitors.Add(new EventFrameMonitor(m_scene));
m_monitors.Add(new LandFrameMonitor(m_scene)); m_staticMonitors.Add(new LandFrameMonitor(m_scene));
m_monitors.Add(new LastFrameTimeMonitor(m_scene)); m_staticMonitors.Add(new LastFrameTimeMonitor(m_scene));
m_monitors.Add( m_staticMonitors.Add(
new GenericMonitor( new GenericMonitor(
m_scene, m_scene,
"TimeDilationMonitor", "TimeDilationMonitor",
@ -177,7 +205,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
m => m.Scene.StatsReporter.LastReportedSimStats[0], m => m.Scene.StatsReporter.LastReportedSimStats[0],
m => m.GetValue().ToString())); m => m.GetValue().ToString()));
m_monitors.Add( m_staticMonitors.Add(
new GenericMonitor( new GenericMonitor(
m_scene, m_scene,
"SimFPSMonitor", "SimFPSMonitor",
@ -185,7 +213,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
m => m.Scene.StatsReporter.LastReportedSimStats[1], m => m.Scene.StatsReporter.LastReportedSimStats[1],
m => string.Format("{0}", m.GetValue()))); m => string.Format("{0}", m.GetValue())));
m_monitors.Add( m_staticMonitors.Add(
new GenericMonitor( new GenericMonitor(
m_scene, m_scene,
"PhysicsFPSMonitor", "PhysicsFPSMonitor",
@ -193,7 +221,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
m => m.Scene.StatsReporter.LastReportedSimStats[2], m => m.Scene.StatsReporter.LastReportedSimStats[2],
m => string.Format("{0}", m.GetValue()))); m => string.Format("{0}", m.GetValue())));
m_monitors.Add( m_staticMonitors.Add(
new GenericMonitor( new GenericMonitor(
m_scene, m_scene,
"AgentUpdatesPerSecondMonitor", "AgentUpdatesPerSecondMonitor",
@ -201,15 +229,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
m => m.Scene.StatsReporter.LastReportedSimStats[3], m => m.Scene.StatsReporter.LastReportedSimStats[3],
m => string.Format("{0} per second", m.GetValue()))); m => string.Format("{0} per second", m.GetValue())));
m_monitors.Add( m_staticMonitors.Add(
new GenericMonitor(
m_scene,
"ObjectUpdatesPerSecondMonitor",
"Object Updates",
m => m.Scene.StatsReporter.LastReportedObjectUpdates,
m => string.Format("{0} per second", m.GetValue())));
m_monitors.Add(
new GenericMonitor( new GenericMonitor(
m_scene, m_scene,
"ActiveObjectCountMonitor", "ActiveObjectCountMonitor",
@ -217,7 +237,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
m => m.Scene.StatsReporter.LastReportedSimStats[7], m => m.Scene.StatsReporter.LastReportedSimStats[7],
m => string.Format("{0}", m.GetValue()))); m => string.Format("{0}", m.GetValue())));
m_monitors.Add( m_staticMonitors.Add(
new GenericMonitor( new GenericMonitor(
m_scene, m_scene,
"ActiveScriptsMonitor", "ActiveScriptsMonitor",
@ -225,7 +245,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
m => m.Scene.StatsReporter.LastReportedSimStats[19], m => m.Scene.StatsReporter.LastReportedSimStats[19],
m => string.Format("{0}", m.GetValue()))); m => string.Format("{0}", m.GetValue())));
m_monitors.Add( m_staticMonitors.Add(
new GenericMonitor( new GenericMonitor(
m_scene, m_scene,
"ScriptEventsPerSecondMonitor", "ScriptEventsPerSecondMonitor",
@ -233,7 +253,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
m => m.Scene.StatsReporter.LastReportedSimStats[20], m => m.Scene.StatsReporter.LastReportedSimStats[20],
m => string.Format("{0} per second", m.GetValue()))); m => string.Format("{0} per second", m.GetValue())));
m_monitors.Add( m_staticMonitors.Add(
new GenericMonitor( new GenericMonitor(
m_scene, m_scene,
"InPacketsPerSecondMonitor", "InPacketsPerSecondMonitor",
@ -241,7 +261,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
m => m.Scene.StatsReporter.LastReportedSimStats[13], m => m.Scene.StatsReporter.LastReportedSimStats[13],
m => string.Format("{0} per second", m.GetValue()))); m => string.Format("{0} per second", m.GetValue())));
m_monitors.Add( m_staticMonitors.Add(
new GenericMonitor( new GenericMonitor(
m_scene, m_scene,
"OutPacketsPerSecondMonitor", "OutPacketsPerSecondMonitor",
@ -249,7 +269,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
m => m.Scene.StatsReporter.LastReportedSimStats[14], m => m.Scene.StatsReporter.LastReportedSimStats[14],
m => string.Format("{0} per second", m.GetValue()))); m => string.Format("{0} per second", m.GetValue())));
m_monitors.Add( m_staticMonitors.Add(
new GenericMonitor( new GenericMonitor(
m_scene, m_scene,
"UnackedBytesMonitor", "UnackedBytesMonitor",
@ -257,7 +277,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
m => m.Scene.StatsReporter.LastReportedSimStats[15], m => m.Scene.StatsReporter.LastReportedSimStats[15],
m => string.Format("{0}", m.GetValue()))); m => string.Format("{0}", m.GetValue())));
m_monitors.Add( m_staticMonitors.Add(
new GenericMonitor( new GenericMonitor(
m_scene, m_scene,
"PendingDownloadsMonitor", "PendingDownloadsMonitor",
@ -265,7 +285,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
m => m.Scene.StatsReporter.LastReportedSimStats[17], m => m.Scene.StatsReporter.LastReportedSimStats[17],
m => string.Format("{0}", m.GetValue()))); m => string.Format("{0}", m.GetValue())));
m_monitors.Add( m_staticMonitors.Add(
new GenericMonitor( new GenericMonitor(
m_scene, m_scene,
"PendingUploadsMonitor", "PendingUploadsMonitor",
@ -273,7 +293,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
m => m.Scene.StatsReporter.LastReportedSimStats[18], m => m.Scene.StatsReporter.LastReportedSimStats[18],
m => string.Format("{0}", m.GetValue()))); m => string.Format("{0}", m.GetValue())));
m_monitors.Add( m_staticMonitors.Add(
new GenericMonitor( new GenericMonitor(
m_scene, m_scene,
"TotalFrameTimeMonitor", "TotalFrameTimeMonitor",
@ -281,7 +301,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
m => m.Scene.StatsReporter.LastReportedSimStats[8], m => m.Scene.StatsReporter.LastReportedSimStats[8],
m => string.Format("{0} ms", m.GetValue()))); m => string.Format("{0} ms", m.GetValue())));
m_monitors.Add( m_staticMonitors.Add(
new GenericMonitor( new GenericMonitor(
m_scene, m_scene,
"NetFrameTimeMonitor", "NetFrameTimeMonitor",
@ -289,7 +309,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
m => m.Scene.StatsReporter.LastReportedSimStats[9], m => m.Scene.StatsReporter.LastReportedSimStats[9],
m => string.Format("{0} ms", m.GetValue()))); m => string.Format("{0} ms", m.GetValue())));
m_monitors.Add( m_staticMonitors.Add(
new GenericMonitor( new GenericMonitor(
m_scene, m_scene,
"PhysicsFrameTimeMonitor", "PhysicsFrameTimeMonitor",
@ -297,7 +317,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
m => m.Scene.StatsReporter.LastReportedSimStats[10], m => m.Scene.StatsReporter.LastReportedSimStats[10],
m => string.Format("{0} ms", m.GetValue()))); m => string.Format("{0} ms", m.GetValue())));
m_monitors.Add( m_staticMonitors.Add(
new GenericMonitor( new GenericMonitor(
m_scene, m_scene,
"SimulationFrameTimeMonitor", "SimulationFrameTimeMonitor",
@ -305,7 +325,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
m => m.Scene.StatsReporter.LastReportedSimStats[12], m => m.Scene.StatsReporter.LastReportedSimStats[12],
m => string.Format("{0} ms", m.GetValue()))); m => string.Format("{0} ms", m.GetValue())));
m_monitors.Add( m_staticMonitors.Add(
new GenericMonitor( new GenericMonitor(
m_scene, m_scene,
"AgentFrameTimeMonitor", "AgentFrameTimeMonitor",
@ -313,7 +333,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
m => m.Scene.StatsReporter.LastReportedSimStats[16], m => m.Scene.StatsReporter.LastReportedSimStats[16],
m => string.Format("{0} ms", m.GetValue()))); m => string.Format("{0} ms", m.GetValue())));
m_monitors.Add( m_staticMonitors.Add(
new GenericMonitor( new GenericMonitor(
m_scene, m_scene,
"ImagesFrameTimeMonitor", "ImagesFrameTimeMonitor",
@ -321,7 +341,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
m => m.Scene.StatsReporter.LastReportedSimStats[11], m => m.Scene.StatsReporter.LastReportedSimStats[11],
m => string.Format("{0} ms", m.GetValue()))); m => string.Format("{0} ms", m.GetValue())));
m_alerts.Add(new DeadlockAlert(m_monitors.Find(x => x is LastFrameTimeMonitor) as LastFrameTimeMonitor)); m_alerts.Add(new DeadlockAlert(m_staticMonitors.Find(x => x is LastFrameTimeMonitor) as LastFrameTimeMonitor));
foreach (IAlert alert in m_alerts) foreach (IAlert alert in m_alerts)
{ {

View File

@ -26,7 +26,7 @@
*/ */
using System; using System;
//using System.Collections.Generic; using System.Collections.Generic;
using System.Timers; using System.Timers;
using OpenMetaverse.Packets; using OpenMetaverse.Packets;
using OpenSim.Framework; using OpenSim.Framework;
@ -35,10 +35,18 @@ using OpenSim.Region.Framework.Interfaces;
namespace OpenSim.Region.Framework.Scenes namespace OpenSim.Region.Framework.Scenes
{ {
/// <summary>
/// Collect statistics from the scene to send to the client and for access by other monitoring tools.
/// </summary>
/// <remarks>
/// FIXME: This should be a monitoring region module
/// </remarks>
public class SimStatsReporter public class SimStatsReporter
{ {
// private static readonly log4net.ILog m_log private static readonly log4net.ILog m_log
// = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
public const string LastReportedObjectUpdateStatName = "LastReportedObjectUpdates";
public delegate void SendStatResult(SimStats stats); public delegate void SendStatResult(SimStats stats);
@ -100,6 +108,14 @@ namespace OpenSim.Region.Framework.Scenes
get { return lastReportedSimStats; } get { return lastReportedSimStats; }
} }
/// <summary>
/// Extra sim statistics that are used by monitors but not sent to the client.
/// </summary>
/// <value>
/// The keys are the stat names.
/// </value>
private Dictionary<string, float> m_lastReportedExtraSimStats = new Dictionary<string, float>();
// Sending a stats update every 3 seconds- // Sending a stats update every 3 seconds-
private int statsUpdatesEveryMS = 3000; private int statsUpdatesEveryMS = 3000;
private float statsUpdateFactor = 0; private float statsUpdateFactor = 0;
@ -334,7 +350,20 @@ namespace OpenSim.Region.Framework.Scenes
} }
// Extra statistics that aren't currently sent to clients // Extra statistics that aren't currently sent to clients
LastReportedObjectUpdates = m_objectUpdates / statsUpdateFactor; lock (m_lastReportedExtraSimStats)
{
m_lastReportedExtraSimStats[LastReportedObjectUpdateStatName] = m_objectUpdates / statsUpdateFactor;
Dictionary<string, float> physicsStats = m_scene.PhysicsScene.GetStats();
if (physicsStats != null)
{
foreach (KeyValuePair<string, float> tuple in physicsStats)
{
m_lastReportedExtraSimStats[tuple.Key] = tuple.Value / statsUpdateFactor;
}
}
}
resetvalues(); resetvalues();
} }
@ -487,7 +516,10 @@ namespace OpenSim.Region.Framework.Scenes
public void AddPendingDownloads(int count) public void AddPendingDownloads(int count)
{ {
m_pendingDownloads += count; m_pendingDownloads += count;
if (m_pendingDownloads < 0) m_pendingDownloads = 0;
if (m_pendingDownloads < 0)
m_pendingDownloads = 0;
//m_log.InfoFormat("[stats]: Adding {0} to pending downloads to make {1}", count, m_pendingDownloads); //m_log.InfoFormat("[stats]: Adding {0} to pending downloads to make {1}", count, m_pendingDownloads);
} }
@ -509,5 +541,11 @@ namespace OpenSim.Region.Framework.Scenes
} }
#endregion #endregion
public Dictionary<string, float> GetExtraSimStats()
{
lock (m_lastReportedExtraSimStats)
return new Dictionary<string, float>(m_lastReportedExtraSimStats);
}
} }
} }

View File

@ -192,8 +192,22 @@ namespace OpenSim.Region.Physics.Manager
public abstract void AddPhysicsActorTaint(PhysicsActor prim); public abstract void AddPhysicsActorTaint(PhysicsActor prim);
/// <summary>
/// Perform a simulation of the current physics scene over the given timestep.
/// </summary>
/// <param name="timeStep"></param>
/// <returns>The number of frames simulated over that period.</returns>
public abstract float Simulate(float timeStep); public abstract float Simulate(float timeStep);
/// <summary>
/// Get statistics about this scene.
/// </summary>
/// <remarks>This facility is currently experimental and subject to change.</remarks>
/// <returns>
/// A dictionary where the key is the statistic name. If no statistics are supplied then returns null.
/// </returns>
public virtual Dictionary<string, float> GetStats() { return null; }
public abstract void GetResults(); public abstract void GetResults();
public abstract void SetTerrain(float[] heightMap); public abstract void SetTerrain(float[] heightMap);

View File

@ -131,6 +131,41 @@ namespace OpenSim.Region.Physics.OdePlugin
/// </remarks> /// </remarks>
internal static Object UniversalColliderSyncObject = new Object(); internal static Object UniversalColliderSyncObject = new Object();
/// <summary>
/// Is stats collecting enabled for this ODE scene?
/// </summary>
public bool CollectStats { get; set; }
/// <summary>
/// Statistics for this scene.
/// </summary>
private Dictionary<string, float> m_stats = new Dictionary<string, float>();
/// <summary>
/// Stat name for recording the number of milliseconds that ODE spends in native collision code.
/// </summary>
public const string ODENativeCollisionFrameMsStatName = "ODENativeCollisionFrameMS";
/// <summary>
/// Used to hold tick numbers for stat collection purposes.
/// </summary>
private int m_nativeCollisionTickRecorder;
/// <summary>
/// A messy way to tell if we need to avoid adding a collision time because this was already done in the callback.
/// </summary>
private bool m_inCollisionTiming;
/// <summary>
/// Used in calculating physics frame time dilation
/// </summary>
private int tickCountFrameRun;
/// <summary>
/// Used in calculating physics frame time dilation
/// </summary>
private int latertickcount;
private Random fluidRandomizer = new Random(Environment.TickCount); private Random fluidRandomizer = new Random(Environment.TickCount);
private const uint m_regionWidth = Constants.RegionSize; private const uint m_regionWidth = Constants.RegionSize;
@ -345,9 +380,6 @@ namespace OpenSim.Region.Physics.OdePlugin
private OdePrim cp1; private OdePrim cp1;
private OdeCharacter cc2; private OdeCharacter cc2;
private OdePrim cp2; private OdePrim cp2;
private int tickCountFrameRun;
private int latertickcount=0;
//private int cStartStop = 0; //private int cStartStop = 0;
//private string cDictKey = ""; //private string cDictKey = "";
@ -440,6 +472,8 @@ namespace OpenSim.Region.Physics.OdePlugin
// Initialize the mesh plugin // Initialize the mesh plugin
public override void Initialise(IMesher meshmerizer, IConfigSource config) public override void Initialise(IMesher meshmerizer, IConfigSource config)
{ {
m_stats[ODENativeCollisionFrameMsStatName] = 0;
mesher = meshmerizer; mesher = meshmerizer;
m_config = config; m_config = config;
// Defaults // Defaults
@ -464,6 +498,8 @@ namespace OpenSim.Region.Physics.OdePlugin
IConfig physicsconfig = m_config.Configs["ODEPhysicsSettings"]; IConfig physicsconfig = m_config.Configs["ODEPhysicsSettings"];
if (physicsconfig != null) if (physicsconfig != null)
{ {
CollectStats = physicsconfig.GetBoolean("collect_stats", false);
gravityx = physicsconfig.GetFloat("world_gravityx", 0f); gravityx = physicsconfig.GetFloat("world_gravityx", 0f);
gravityy = physicsconfig.GetFloat("world_gravityy", 0f); gravityy = physicsconfig.GetFloat("world_gravityy", 0f);
gravityz = physicsconfig.GetFloat("world_gravityz", -9.8f); gravityz = physicsconfig.GetFloat("world_gravityz", -9.8f);
@ -764,6 +800,62 @@ namespace OpenSim.Region.Physics.OdePlugin
#region Collision Detection #region Collision Detection
/// <summary>
/// Collides two geometries.
/// </summary>
/// <returns></returns>
/// <param name='geom1'></param>
/// <param name='geom2'>/param>
/// <param name='maxContacts'></param>
/// <param name='contactsArray'></param>
/// <param name='contactGeomSize'></param>
private int CollideGeoms(
IntPtr geom1, IntPtr geom2, int maxContacts, Ode.NET.d.ContactGeom[] contactsArray, int contactGeomSize)
{
int count;
lock (OdeScene.UniversalColliderSyncObject)
{
// We do this inside the lock so that we don't count any delay in acquiring it
if (CollectStats)
m_nativeCollisionTickRecorder = Util.EnvironmentTickCount();
count = d.Collide(geom1, geom2, maxContacts, contactsArray, contactGeomSize);
}
// We do this outside the lock so that any waiting threads aren't held up, though the effect is probably
// negligable
if (CollectStats)
m_stats[ODENativeCollisionFrameMsStatName]
+= Util.EnvironmentTickCountSubtract(m_nativeCollisionTickRecorder);
return count;
}
/// <summary>
/// Collide two spaces or a space and a geometry.
/// </summary>
/// <param name='space1'></param>
/// <param name='space2'>/param>
/// <param name='data'></param>
private void CollideSpaces(IntPtr space1, IntPtr space2, IntPtr data)
{
if (CollectStats)
{
m_inCollisionTiming = true;
m_nativeCollisionTickRecorder = Util.EnvironmentTickCount();
}
d.SpaceCollide2(space1, space2, data, nearCallback);
if (CollectStats && m_inCollisionTiming)
{
m_stats[ODENativeCollisionFrameMsStatName]
+= Util.EnvironmentTickCountSubtract(m_nativeCollisionTickRecorder);
m_inCollisionTiming = false;
}
}
/// <summary> /// <summary>
/// This is our near callback. A geometry is near a body /// This is our near callback. A geometry is near a body
/// </summary> /// </summary>
@ -772,6 +864,13 @@ namespace OpenSim.Region.Physics.OdePlugin
/// <param name="g2">another geometry or space</param> /// <param name="g2">another geometry or space</param>
private void near(IntPtr space, IntPtr g1, IntPtr g2) private void near(IntPtr space, IntPtr g1, IntPtr g2)
{ {
if (CollectStats && m_inCollisionTiming)
{
m_stats[ODENativeCollisionFrameMsStatName]
+= Util.EnvironmentTickCountSubtract(m_nativeCollisionTickRecorder);
m_inCollisionTiming = false;
}
// m_log.DebugFormat("[PHYSICS]: Colliding {0} and {1} in {2}", g1, g2, space); // m_log.DebugFormat("[PHYSICS]: Colliding {0} and {1} in {2}", g1, g2, space);
// no lock here! It's invoked from within Simulate(), which is thread-locked // no lock here! It's invoked from within Simulate(), which is thread-locked
@ -789,7 +888,7 @@ namespace OpenSim.Region.Physics.OdePlugin
// contact points in the space // contact points in the space
try try
{ {
d.SpaceCollide2(g1, g2, IntPtr.Zero, nearCallback); CollideSpaces(g1, g2, IntPtr.Zero);
} }
catch (AccessViolationException) catch (AccessViolationException)
{ {
@ -832,6 +931,7 @@ namespace OpenSim.Region.Physics.OdePlugin
// Figure out how many contact points we have // Figure out how many contact points we have
int count = 0; int count = 0;
try try
{ {
// Colliding Geom To Geom // Colliding Geom To Geom
@ -843,8 +943,7 @@ namespace OpenSim.Region.Physics.OdePlugin
if (b1 != IntPtr.Zero && b2 != IntPtr.Zero && d.AreConnectedExcluding(b1, b2, d.JointType.Contact)) if (b1 != IntPtr.Zero && b2 != IntPtr.Zero && d.AreConnectedExcluding(b1, b2, d.JointType.Contact))
return; return;
lock (OdeScene.UniversalColliderSyncObject) count = CollideGeoms(g1, g2, contacts.Length, contacts, d.ContactGeom.SizeOf);
count = d.Collide(g1, g2, contacts.Length, contacts, d.ContactGeom.SizeOf);
if (count > contacts.Length) if (count > contacts.Length)
m_log.Error("[ODE SCENE]: Got " + count + " contacts when we asked for a maximum of " + contacts.Length); m_log.Error("[ODE SCENE]: Got " + count + " contacts when we asked for a maximum of " + contacts.Length);
@ -1578,7 +1677,7 @@ namespace OpenSim.Region.Physics.OdePlugin
// and we'll run it again on all of them. // and we'll run it again on all of them.
try try
{ {
d.SpaceCollide2(space, chr.Shell, IntPtr.Zero, nearCallback); CollideSpaces(space, chr.Shell, IntPtr.Zero);
} }
catch (AccessViolationException) catch (AccessViolationException)
{ {
@ -1593,6 +1692,9 @@ namespace OpenSim.Region.Physics.OdePlugin
//} //}
} }
// if (framecount % 55 == 0)
// m_log.DebugFormat("Processed {0} collisions", _perloopContact.Count);
List<OdePrim> removeprims = null; List<OdePrim> removeprims = null;
foreach (OdePrim chr in _activeprims) foreach (OdePrim chr in _activeprims)
{ {
@ -1604,7 +1706,7 @@ namespace OpenSim.Region.Physics.OdePlugin
{ {
if (space != IntPtr.Zero && chr.prim_geom != IntPtr.Zero && chr.m_taintremove == false) if (space != IntPtr.Zero && chr.prim_geom != IntPtr.Zero && chr.m_taintremove == false)
{ {
d.SpaceCollide2(space, chr.prim_geom, IntPtr.Zero, nearCallback); CollideSpaces(space, chr.prim_geom, IntPtr.Zero);
} }
else else
{ {
@ -2689,7 +2791,7 @@ namespace OpenSim.Region.Physics.OdePlugin
/// It calls the methods that report back to the object owners.. (scenepresence, SceneObjectGroup) /// It calls the methods that report back to the object owners.. (scenepresence, SceneObjectGroup)
/// </summary> /// </summary>
/// <param name="timeStep"></param> /// <param name="timeStep"></param>
/// <returns></returns> /// <returns>The number of frames simulated over that period.</returns>
public override float Simulate(float timeStep) public override float Simulate(float timeStep)
{ {
if (framecount >= int.MaxValue) if (framecount >= int.MaxValue)
@ -3190,7 +3292,7 @@ namespace OpenSim.Region.Physics.OdePlugin
public override bool IsThreaded public override bool IsThreaded
{ {
// for now we won't be multithreaded // for now we won't be multithreaded
get { return (false); } get { return false; }
} }
#region ODE Specific Terrain Fixes #region ODE Specific Terrain Fixes
@ -3955,5 +4057,22 @@ namespace OpenSim.Region.Physics.OdePlugin
ds.SetViewpoint(ref xyz, ref hpr); ds.SetViewpoint(ref xyz, ref hpr);
} }
#endif #endif
public override Dictionary<string, float> GetStats()
{
if (!CollectStats)
return null;
Dictionary<string, float> returnStats;
lock (OdeLock)
{
returnStats = new Dictionary<string, float>(m_stats);
m_stats[ODENativeCollisionFrameMsStatName] = 0;
}
return returnStats;
}
} }
} }

View File

@ -675,6 +675,25 @@
[ODEPhysicsSettings] [ODEPhysicsSettings]
; ##
; ## Physics stats settings
;
; If collect_stats is enabled, then extra stat information is collected which is accessible via the MonitorModule
; (see http://opensimulator.org/wiki/Monitoring_Module for more details).
collect_stats = false
; ##
; ## Physics logging settings - logfiles are saved to *.DIF files
; ##
; default is false
;physics_logging = true
;; every n simulation iterations, the physics snapshot file is updated
;physics_logging_interval = 50
;; append to existing physics logfile, or overwrite existing logfiles?
;physics_logging_append_existing_logfile = true
;## ;##
;## World Settings ;## World Settings
;## ;##
@ -823,17 +842,6 @@
; number^2 physical level of detail of the sculpt texture. 16x16 - 256 verticies ; number^2 physical level of detail of the sculpt texture. 16x16 - 256 verticies
mesh_physical_lod = 16 mesh_physical_lod = 16
; ##
; ## Physics logging settings - logfiles are saved to *.DIF files
; ##
; default is false
;physics_logging = true
;; every n simulation iterations, the physics snapshot file is updated
;physics_logging_interval = 50
;; append to existing physics logfile, or overwrite existing logfiles?
;physics_logging_append_existing_logfile = true
; ## ; ##
; ## Joint support ; ## Joint support
; ## ; ##