Merge branch 'master' into careminster

Conflicts:
	OpenSim/Region/Framework/Scenes/SimStatsReporter.cs
avinationmerge
Melanie 2012-06-02 01:40:42 +01:00
commit 522f36345d
3 changed files with 270 additions and 93 deletions

View File

@ -1512,10 +1512,6 @@ namespace OpenSim.Region.Framework.Scenes
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());
// frameMS currently records work frame times, not total frame times (work + any required sleep to
// reach min frame time.
@ -1524,7 +1520,6 @@ namespace OpenSim.Region.Framework.Scenes
StatsReporter.addAgentMS(agentMS);
StatsReporter.addPhysicsMS(physicsMS + physicsMS2);
StatsReporter.addOtherMS(otherMS);
StatsReporter.SetActiveScripts(m_sceneGraph.GetActiveScriptsCount());
StatsReporter.addScriptLines(m_sceneGraph.GetScriptLPS());
if (LoginsDisabled && Frame == 20)

View File

@ -222,6 +222,10 @@ namespace OpenSim.Region.Framework.Scenes
m_report.Close();
}
/// <summary>
/// Sets the number of milliseconds between stat updates.
/// </summary>
/// <param name='ms'></param>
public void SetUpdateMS(int ms)
{
statsUpdatesEveryMS = ms;
@ -297,6 +301,16 @@ namespace OpenSim.Region.Framework.Scenes
sleeptime = m_sleeptimeMS * perframe;
}
m_rootAgents = m_scene.SceneGraph.GetRootAgentCount();
m_childAgents = m_scene.SceneGraph.GetChildAgentCount();
m_numPrim = m_scene.SceneGraph.GetTotalObjectsCount();
m_activePrim = m_scene.SceneGraph.GetActiveObjectsCount();
m_activeScripts = m_scene.SceneGraph.GetActiveScriptsCount();
// FIXME: Checking for stat sanity is a complex approach. What we really need to do is fix the code
// so that stat numbers are always consistent.
CheckStatSanity();
// other MS is actually simulation time
// m_otherMS = m_frameMS - m_physicsMS - m_imageMS - m_netMS - m_agentMS;
// m_imageMS m_netMS are not included in m_frameMS
@ -462,13 +476,6 @@ namespace OpenSim.Region.Framework.Scenes
m_timeDilation = td;
}
public void SetRootAgents(int rootAgents)
{
m_rootAgents = rootAgents;
CheckStatSanity();
}
internal void CheckStatSanity()
{
if (m_rootAgents < 0 || m_childAgents < 0)
@ -485,22 +492,6 @@ namespace OpenSim.Region.Framework.Scenes
}
}
public void SetChildAgents(int childAgents)
{
m_childAgents = childAgents;
CheckStatSanity();
}
public void SetObjects(int objects)
{
m_numPrim = objects;
}
public void SetActiveObjects(int objects)
{
m_activePrim = objects;
}
public void AddFPS(int frames)
{
m_fps += frames;
@ -587,11 +578,6 @@ namespace OpenSim.Region.Framework.Scenes
m_scriptLinesPerSecond += count;
}
public void SetActiveScripts(int count)
{
m_activeScripts = count;
}
public void AddPacketsStats(int inPackets, int outPackets, int unAckedBytes)
{
AddInPackets(inPackets);

View File

@ -30,20 +30,21 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;
using System.IO;
using System.Diagnostics;
using log4net;
using Nini.Config;
using Ode.NET;
using OpenMetaverse;
#if USE_DRAWSTUFF
using Drawstuff.NET;
#endif
using OpenSim.Framework;
using OpenSim.Region.Physics.Manager;
using OpenMetaverse;
namespace OpenSim.Region.Physics.OdePlugin
{
@ -54,15 +55,15 @@ namespace OpenSim.Region.Physics.OdePlugin
End = 2
}
public struct sCollisionData
{
public uint ColliderLocalId;
public uint CollidedWithLocalId;
public int NumberOfCollisions;
public int CollisionType;
public int StatusIndicator;
public int lastframe;
}
// public struct sCollisionData
// {
// public uint ColliderLocalId;
// public uint CollidedWithLocalId;
// public int NumberOfCollisions;
// public int CollisionType;
// public int StatusIndicator;
// public int lastframe;
// }
[Flags]
public enum CollisionCategories : int
@ -142,20 +143,114 @@ namespace OpenSim.Region.Physics.OdePlugin
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.
/// Stat name for total number of avatars in this ODE scene.
/// </summary>
public const string ODENativeCollisionFrameMsStatName = "ODENativeCollisionFrameMS";
public const string ODETotalAvatarsStatName = "ODETotalAvatars";
/// <summary>
/// Stat name for total number of prims in this ODE scene.
/// </summary>
public const string ODETotalPrimsStatName = "ODETotalPrims";
/// <summary>
/// Stat name for total number of prims with active physics in this ODE scene.
/// </summary>
public const string ODEActivePrimsStatName = "ODEActivePrims";
/// <summary>
/// Stat name for the total time spent in ODE frame processing.
/// </summary>
/// <remarks>
/// A sanity check for the main scene loop physics time.
/// </remarks>
public const string ODETotalFrameMsStatName = "ODETotalFrameMS";
/// <summary>
/// Stat name for time spent processing avatar taints per frame
/// </summary>
public const string ODEAvatarTaintMsStatName = "ODEAvatarTaintFrameMS";
/// <summary>
/// Stat name for time spent processing prim taints per frame
/// </summary>
public const string ODEPrimTaintMsStatName = "ODEPrimTaintFrameMS";
/// <summary>
/// Stat name for time spent calculating avatar forces per frame.
/// </summary>
public const string ODEAvatarForcesFrameMsStatName = "ODEAvatarForcesFrameMS";
/// <summary>
/// Stat name for time spent calculating prim forces per frame
/// </summary>
public const string ODEPrimForcesFrameMsStatName = "ODEPrimForcesFrameMS";
/// <summary>
/// Stat name for time spent fulfilling raycasting requests per frame
/// </summary>
public const string ODERaycastingFrameMsStatName = "ODERaycastingFrameMS";
/// <summary>
/// Stat name for time spent in native code that actually steps through the simulation.
/// </summary>
public const string ODENativeStepFrameMsStatName = "ODENativeStepFrameMS";
/// <summary>
/// Stat name for the number of milliseconds that ODE spends in native space collision code.
/// </summary>
public const string ODENativeSpaceCollisionFrameMsStatName = "ODENativeSpaceCollisionFrameMS";
/// <summary>
/// Stat name for milliseconds that ODE spends in native geom collision code.
/// </summary>
public const string ODENativeGeomCollisionFrameMsStatName = "ODENativeGeomCollisionFrameMS";
/// <summary>
/// Time spent in collision processing that is not spent in native space or geom collision code.
/// </summary>
public const string ODEOtherCollisionFrameMsStatName = "ODEOtherCollisionFrameMS";
/// <summary>
/// Stat name for time spent notifying listeners of collisions
/// </summary>
public const string ODECollisionNotificationFrameMsStatName = "ODECollisionNotificationFrameMS";
/// <summary>
/// Stat name for milliseconds spent updating avatar position and velocity
/// </summary>
public const string ODEAvatarUpdateFrameMsStatName = "ODEAvatarUpdateFrameMS";
/// <summary>
/// Stat name for the milliseconds spent updating prim position and velocity
/// </summary>
public const string ODEPrimUpdateFrameMsStatName = "ODEPrimUpdateFrameMS";
/// <summary>
/// Stat name for avatar collisions with another entity.
/// </summary>
public const string ODEAvatarContactsStatsName = "ODEAvatarContacts";
/// <summary>
/// Stat name for prim collisions with another entity.
/// </summary>
public const string ODEPrimContactsStatName = "ODEPrimContacts";
/// <summary>
/// Used to hold tick numbers for stat collection purposes.
/// </summary>
private int m_nativeCollisionTickRecorder;
private int m_nativeCollisionStartTick;
/// <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>
/// A temporary holder for the number of avatar collisions in a frame, so we can work out how many object
/// collisions occured using the _perloopcontact if stats collection is enabled.
/// </summary>
private int m_tempAvatarCollisionsThisFrame;
/// <summary>
/// Used in calculating physics frame time dilation
/// </summary>
@ -472,7 +567,7 @@ namespace OpenSim.Region.Physics.OdePlugin
// Initialize the mesh plugin
public override void Initialise(IMesher meshmerizer, IConfigSource config)
{
m_stats[ODENativeCollisionFrameMsStatName] = 0;
InitializeExtraStats();
mesher = meshmerizer;
m_config = config;
@ -818,7 +913,7 @@ namespace OpenSim.Region.Physics.OdePlugin
{
// We do this inside the lock so that we don't count any delay in acquiring it
if (CollectStats)
m_nativeCollisionTickRecorder = Util.EnvironmentTickCount();
m_nativeCollisionStartTick = Util.EnvironmentTickCount();
count = d.Collide(geom1, geom2, maxContacts, contactsArray, contactGeomSize);
}
@ -826,8 +921,8 @@ namespace OpenSim.Region.Physics.OdePlugin
// 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);
m_stats[ODENativeGeomCollisionFrameMsStatName]
+= Util.EnvironmentTickCountSubtract(m_nativeCollisionStartTick);
return count;
}
@ -843,15 +938,15 @@ namespace OpenSim.Region.Physics.OdePlugin
if (CollectStats)
{
m_inCollisionTiming = true;
m_nativeCollisionTickRecorder = Util.EnvironmentTickCount();
m_nativeCollisionStartTick = Util.EnvironmentTickCount();
}
d.SpaceCollide2(space1, space2, data, nearCallback);
if (CollectStats && m_inCollisionTiming)
{
m_stats[ODENativeCollisionFrameMsStatName]
+= Util.EnvironmentTickCountSubtract(m_nativeCollisionTickRecorder);
m_stats[ODENativeSpaceCollisionFrameMsStatName]
+= Util.EnvironmentTickCountSubtract(m_nativeCollisionStartTick);
m_inCollisionTiming = false;
}
}
@ -866,8 +961,8 @@ namespace OpenSim.Region.Physics.OdePlugin
{
if (CollectStats && m_inCollisionTiming)
{
m_stats[ODENativeCollisionFrameMsStatName]
+= Util.EnvironmentTickCountSubtract(m_nativeCollisionTickRecorder);
m_stats[ODENativeSpaceCollisionFrameMsStatName]
+= Util.EnvironmentTickCountSubtract(m_nativeCollisionStartTick);
m_inCollisionTiming = false;
}
@ -945,6 +1040,10 @@ namespace OpenSim.Region.Physics.OdePlugin
count = CollideGeoms(g1, g2, contacts.Length, contacts, d.ContactGeom.SizeOf);
// All code after this is only relevant if we have any collisions
if (count <= 0)
return;
if (count > contacts.Length)
m_log.Error("[ODE SCENE]: Got " + count + " contacts when we asked for a maximum of " + contacts.Length);
}
@ -1212,14 +1311,12 @@ namespace OpenSim.Region.Physics.OdePlugin
{
_perloopContact.Add(curContact);
// If we're colliding against terrain
if (name1 == "Terrain" || name2 == "Terrain")
{
// If we're moving
if ((p2.PhysicsActorType == (int) ActorTypes.Agent) &&
(Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f))
{
// Use the movement terrain contact
// Avatar is moving on terrain, use the movement terrain contact
AvatarMovementTerrainContact.geom = curContact;
if (m_global_contactcount < maxContactsbeforedeath)
@ -1232,7 +1329,7 @@ namespace OpenSim.Region.Physics.OdePlugin
{
if (p2.PhysicsActorType == (int)ActorTypes.Agent)
{
// Use the non moving terrain contact
// Avatar is standing on terrain, use the non moving terrain contact
TerrainContact.geom = curContact;
if (m_global_contactcount < maxContactsbeforedeath)
@ -1327,13 +1424,11 @@ namespace OpenSim.Region.Physics.OdePlugin
}
else
{
// we're colliding with prim or avatar
// check if we're moving
if ((p2.PhysicsActorType == (int)ActorTypes.Agent))
{
if ((Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f))
{
// Use the Movement prim contact
// Avatar is moving on a prim, use the Movement prim contact
AvatarMovementprimContact.geom = curContact;
if (m_global_contactcount < maxContactsbeforedeath)
@ -1344,9 +1439,8 @@ namespace OpenSim.Region.Physics.OdePlugin
}
else
{
// Use the non movement contact
// Avatar is standing still on a prim, use the non movement contact
contact.geom = curContact;
_perloopContact.Add(curContact);
if (m_global_contactcount < maxContactsbeforedeath)
{
@ -1454,7 +1548,7 @@ namespace OpenSim.Region.Physics.OdePlugin
break;
}
}
//m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth));
//m_log.DebugFormat("[Collision]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth));
//m_log.DebugFormat("[Collision]: <{0},{1},{2}>", Math.Abs(contactGeom.normal.X - contact.normal.X), Math.Abs(contactGeom.normal.Y - contact.normal.Y), Math.Abs(contactGeom.normal.Z - contact.normal.Z));
}
}
@ -1692,8 +1786,11 @@ namespace OpenSim.Region.Physics.OdePlugin
//}
}
// if (framecount % 55 == 0)
// m_log.DebugFormat("Processed {0} collisions", _perloopContact.Count);
if (CollectStats)
{
m_tempAvatarCollisionsThisFrame = _perloopContact.Count;
m_stats[ODEAvatarContactsStatsName] += m_tempAvatarCollisionsThisFrame;
}
List<OdePrim> removeprims = null;
foreach (OdePrim chr in _activeprims)
@ -1727,6 +1824,9 @@ namespace OpenSim.Region.Physics.OdePlugin
}
}
if (CollectStats)
m_stats[ODEPrimContactsStatName] += _perloopContact.Count - m_tempAvatarCollisionsThisFrame;
if (removeprims != null)
{
foreach (OdePrim chr in removeprims)
@ -2785,21 +2885,23 @@ namespace OpenSim.Region.Physics.OdePlugin
/// <summary>
/// This is our main simulate loop
/// </summary>
/// <remarks>
/// It's thread locked by a Mutex in the scene.
/// It holds Collisions, it instructs ODE to step through the physical reactions
/// It moves the objects around in memory
/// It calls the methods that report back to the object owners.. (scenepresence, SceneObjectGroup)
/// </summary>
/// </remarks>
/// <param name="timeStep"></param>
/// <returns>The number of frames simulated over that period.</returns>
public override float Simulate(float timeStep)
{
int startFrameTick = CollectStats ? Util.EnvironmentTickCount() : 0;
int tempTick = 0, tempTick2 = 0;
if (framecount >= int.MaxValue)
framecount = 0;
//if (m_worldOffset != Vector3.Zero)
// return 0;
framecount++;
float fps = 0;
@ -2807,7 +2909,7 @@ namespace OpenSim.Region.Physics.OdePlugin
float timeLeft = timeStep;
//m_log.Info(timeStep.ToString());
// step_time += timeStep;
// step_time += timeSte
//
// // If We're loaded down by something else,
// // or debugging with the Visual Studio project on pause
@ -2873,6 +2975,9 @@ namespace OpenSim.Region.Physics.OdePlugin
{
try
{
if (CollectStats)
tempTick = Util.EnvironmentTickCount();
lock (_taintedActors)
{
foreach (OdeCharacter character in _taintedActors)
@ -2881,6 +2986,13 @@ namespace OpenSim.Region.Physics.OdePlugin
_taintedActors.Clear();
}
if (CollectStats)
{
tempTick2 = Util.EnvironmentTickCount();
m_stats[ODEAvatarTaintMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick);
tempTick = tempTick2;
}
lock (_taintedPrims)
{
foreach (OdePrim prim in _taintedPrims)
@ -2911,6 +3023,13 @@ namespace OpenSim.Region.Physics.OdePlugin
_taintedPrims.Clear();
}
if (CollectStats)
{
tempTick2 = Util.EnvironmentTickCount();
m_stats[ODEPrimTaintMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick);
tempTick = tempTick2;
}
// Move characters
foreach (OdeCharacter actor in _characters)
actor.Move(defects);
@ -2930,6 +3049,13 @@ namespace OpenSim.Region.Physics.OdePlugin
defects.Clear();
}
if (CollectStats)
{
tempTick2 = Util.EnvironmentTickCount();
m_stats[ODEAvatarForcesFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick);
tempTick = tempTick2;
}
// Move other active objects
foreach (OdePrim prim in _activeprims)
{
@ -2937,14 +3063,35 @@ namespace OpenSim.Region.Physics.OdePlugin
prim.Move(timeStep);
}
if (CollectStats)
{
tempTick2 = Util.EnvironmentTickCount();
m_stats[ODEPrimForcesFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick);
tempTick = tempTick2;
}
//if ((framecount % m_randomizeWater) == 0)
// randomizeWater(waterlevel);
//int RayCastTimeMS = m_rayCastManager.ProcessQueuedRequests();
m_rayCastManager.ProcessQueuedRequests();
if (CollectStats)
{
tempTick2 = Util.EnvironmentTickCount();
m_stats[ODERaycastingFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick);
tempTick = tempTick2;
}
collision_optimized();
if (CollectStats)
{
tempTick2 = Util.EnvironmentTickCount();
m_stats[ODEOtherCollisionFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick);
tempTick = tempTick2;
}
foreach (PhysicsActor obj in _collisionEventPrim.Values)
{
// m_log.DebugFormat("[PHYSICS]: Assessing {0} {1} for collision events", obj.SOPName, obj.LocalID);
@ -2970,8 +3117,18 @@ namespace OpenSim.Region.Physics.OdePlugin
m_global_contactcount = 0;
if (CollectStats)
{
tempTick2 = Util.EnvironmentTickCount();
m_stats[ODECollisionNotificationFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick);
tempTick = tempTick2;
}
d.WorldQuickStep(world, ODE_STEPSIZE);
if (CollectStats)
m_stats[ODENativeStepFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick);
d.JointGroupEmpty(contactgroup);
}
catch (Exception e)
@ -2982,6 +3139,9 @@ namespace OpenSim.Region.Physics.OdePlugin
timeLeft -= ODE_STEPSIZE;
}
if (CollectStats)
tempTick = Util.EnvironmentTickCount();
foreach (OdeCharacter actor in _characters)
{
if (actor.bad)
@ -3005,6 +3165,13 @@ namespace OpenSim.Region.Physics.OdePlugin
defects.Clear();
}
if (CollectStats)
{
tempTick2 = Util.EnvironmentTickCount();
m_stats[ODEAvatarUpdateFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick);
tempTick = tempTick2;
}
//if (timeStep < 0.2f)
foreach (OdePrim prim in _activeprims)
@ -3018,6 +3185,9 @@ namespace OpenSim.Region.Physics.OdePlugin
}
}
if (CollectStats)
m_stats[ODEPrimUpdateFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick);
//DumpJointInfo();
// Finished with all sim stepping. If requested, dump world state to file for debugging.
@ -3039,7 +3209,7 @@ namespace OpenSim.Region.Physics.OdePlugin
d.WorldExportDIF(world, fname, physics_logging_append_existing_logfile, prefix);
}
latertickcount = Util.EnvironmentTickCount() - tickCountFrameRun;
latertickcount = Util.EnvironmentTickCountSubtract(tickCountFrameRun);
// OpenSimulator above does 10 fps. 10 fps = means that the main thread loop and physics
// has a max of 100 ms to run theoretically.
@ -3059,6 +3229,9 @@ namespace OpenSim.Region.Physics.OdePlugin
tickCountFrameRun = Util.EnvironmentTickCount();
}
if (CollectStats)
m_stats[ODETotalFrameMsStatName] += Util.EnvironmentTickCountSubtract(startFrameTick);
return fps;
}
@ -3868,26 +4041,19 @@ namespace OpenSim.Region.Physics.OdePlugin
public override Dictionary<uint, float> GetTopColliders()
{
Dictionary<uint, float> returncolliders = new Dictionary<uint, float>();
int cnt = 0;
Dictionary<uint, float> topColliders;
lock (_prims)
{
foreach (OdePrim prm in _prims)
{
if (prm.CollisionScore > 0)
{
returncolliders.Add(prm.LocalID, prm.CollisionScore);
cnt++;
prm.CollisionScore = 0f;
if (cnt > 25)
{
break;
}
}
}
List<OdePrim> orderedPrims = new List<OdePrim>(_prims);
orderedPrims.OrderByDescending(p => p.CollisionScore).Take(25);
topColliders = orderedPrims.ToDictionary(p => p.LocalID, p => p.CollisionScore);
foreach (OdePrim p in _prims)
p.CollisionScore = 0;
}
return returncolliders;
return topColliders;
}
public override bool SupportsRayCast()
@ -4069,10 +4235,40 @@ namespace OpenSim.Region.Physics.OdePlugin
{
returnStats = new Dictionary<string, float>(m_stats);
m_stats[ODENativeCollisionFrameMsStatName] = 0;
// FIXME: This is a SUPER DUMB HACK until we can establish stats that aren't subject to a division by
// 3 from the SimStatsReporter.
returnStats[ODETotalAvatarsStatName] = _characters.Count * 3;
returnStats[ODETotalPrimsStatName] = _prims.Count * 3;
returnStats[ODEActivePrimsStatName] = _activeprims.Count * 3;
InitializeExtraStats();
}
returnStats[ODEOtherCollisionFrameMsStatName]
= returnStats[ODEOtherCollisionFrameMsStatName]
- returnStats[ODENativeSpaceCollisionFrameMsStatName]
- returnStats[ODENativeGeomCollisionFrameMsStatName];
return returnStats;
}
private void InitializeExtraStats()
{
m_stats[ODETotalFrameMsStatName] = 0;
m_stats[ODEAvatarTaintMsStatName] = 0;
m_stats[ODEPrimTaintMsStatName] = 0;
m_stats[ODEAvatarForcesFrameMsStatName] = 0;
m_stats[ODEPrimForcesFrameMsStatName] = 0;
m_stats[ODERaycastingFrameMsStatName] = 0;
m_stats[ODENativeStepFrameMsStatName] = 0;
m_stats[ODENativeSpaceCollisionFrameMsStatName] = 0;
m_stats[ODENativeGeomCollisionFrameMsStatName] = 0;
m_stats[ODEOtherCollisionFrameMsStatName] = 0;
m_stats[ODECollisionNotificationFrameMsStatName] = 0;
m_stats[ODEAvatarContactsStatsName] = 0;
m_stats[ODEPrimContactsStatName] = 0;
m_stats[ODEAvatarUpdateFrameMsStatName] = 0;
m_stats[ODEPrimUpdateFrameMsStatName] = 0;
}
}
}