예제 #1
0
        private void statsHeartBeat(object sender, EventArgs e)
        {
            if (!m_scene.Active)
            {
                return;
            }

            // dont do it if if still been done

            if (Monitor.TryEnter(m_statsLock))
            {
                // m_log.Debug("Firing Stats Heart Beat");
                float[] newvalues = new float[(int)StatsIndex.ArraySize];

                uint regionFlags = 0;

                try
                {
                    if (estateModule == null)
                    {
                        estateModule = m_scene.RequestModuleInterface <IEstateModule>();
                    }
                    regionFlags = estateModule != null?estateModule.GetRegionFlags() : (uint)0;
                }
                catch (Exception)
                {
                    // leave region flags at 0
                }

                #region various statistic googly moogly
                double timeTmp = m_lastUpdateTS;
                m_lastUpdateTS = Util.GetTimeStampMS();
                float updateElapsed = (float)((m_lastUpdateTS - timeTmp) / 1000.0);

                // factor to consider updates integration time
                float updateTimeFactor = 1.0f / updateElapsed;

                // scene frame stats
                float reportedFPS;
                float physfps;
                float timeDilation;
                float agentMS;
                float physicsMS;
                float otherMS;
                float sleeptime;
                float scriptTimeMS;
                float totalFrameTime;

                float invFrameElapsed;

                // get a copy under lock and reset
                lock (m_statsFrameLock)
                {
                    timeDilation   = m_timeDilation;
                    reportedFPS    = m_fps;
                    physfps        = m_pfps;
                    agentMS        = m_agentMS;
                    physicsMS      = m_physicsMS;
                    otherMS        = m_otherMS;
                    sleeptime      = m_sleeptimeMS;
                    scriptTimeMS   = m_scriptTimeMS;
                    totalFrameTime = m_frameMS;
                    // still not inv
                    invFrameElapsed = (float)((m_FrameStatsTS - m_prevFrameStatsTS) / 1000.0);

                    ResetFrameStats();
                }

                if (invFrameElapsed / updateElapsed < 0.8)
                {
                    // scene is in trouble, its account of time is most likely wrong
                    // can even be in stall
                    invFrameElapsed = updateTimeFactor;
                }
                else
                {
                    invFrameElapsed = 1.0f / invFrameElapsed;
                }

                float perframefactor;
                if (reportedFPS <= 0)
                {
                    reportedFPS    = 0.0f;
                    physfps        = 0.0f;
                    perframefactor = 1.0f;
                    timeDilation   = 0.0f;
                }
                else
                {
                    timeDilation  /= reportedFPS;
                    reportedFPS   *= m_statisticsFPSfactor;
                    perframefactor = 1.0f / (float)reportedFPS;
                    reportedFPS   *= invFrameElapsed;
                    physfps       *= invFrameElapsed * m_statisticsFPSfactor;
                }

                // some engines track frame time with error related to the simulation step size
                if (physfps > reportedFPS)
                {
                    physfps = reportedFPS;
                }

                // save the reported value so there is something available for llGetRegionFPS
                lastReportedSimFPS = reportedFPS;

                // scale frame stats

                totalFrameTime *= perframefactor;
                sleeptime      *= perframefactor;
                otherMS        *= perframefactor;
                physicsMS      *= perframefactor;
                agentMS        *= perframefactor;
                scriptTimeMS   *= perframefactor;

                // estimate spare time
                float sparetime;
                sparetime = m_targetFrameTime - (physicsMS + agentMS + otherMS);

                if (sparetime < 0)
                {
                    sparetime = 0;
                }
                else if (sparetime > totalFrameTime)
                {
                    sparetime = totalFrameTime;
                }

                #endregion
                SceneGraph SG = m_scene.SceneGraph;
                OnStatsIncorrect?.Invoke(); // number of agents may still drift so fix

                m_activeScripts        = SG.GetActiveScriptsCount();
                m_scriptLinesPerSecond = SG.GetScriptLPS();

                newvalues[(int)StatsIndex.TimeDilation]        = (Single.IsNaN(timeDilation)) ? 0.0f : (float)Math.Round(timeDilation, 3);
                newvalues[(int)StatsIndex.SimFPS]              = (float)Math.Round(reportedFPS, 1);
                newvalues[(int)StatsIndex.PhysicsFPS]          = (float)Math.Round(physfps, 1);
                newvalues[(int)StatsIndex.AgentUpdates]        = m_agentUpdates * updateTimeFactor;
                newvalues[(int)StatsIndex.Agents]              = SG.GetRootAgentCount();
                newvalues[(int)StatsIndex.ChildAgents]         = SG.GetChildAgentCount();
                newvalues[(int)StatsIndex.TotalPrim]           = SG.GetTotalPrimObjectsCount();
                newvalues[(int)StatsIndex.ActivePrim]          = SG.GetActiveObjectsCount();
                newvalues[(int)StatsIndex.FrameMS]             = totalFrameTime;
                newvalues[(int)StatsIndex.NetMS]               = (float)Math.Round(m_netMS * perframefactor, 3);
                newvalues[(int)StatsIndex.PhysicsMS]           = (float)Math.Round(physicsMS, 3);
                newvalues[(int)StatsIndex.ImageMS]             = (float)Math.Round(m_imageMS * perframefactor, 3);
                newvalues[(int)StatsIndex.OtherMS]             = (float)Math.Round(otherMS, 3);
                newvalues[(int)StatsIndex.InPacketsPerSecond]  = (float)Math.Round(m_inPacketsPerSecond * updateTimeFactor);
                newvalues[(int)StatsIndex.OutPacketsPerSecond] = (float)Math.Round(m_outPacketsPerSecond * updateTimeFactor);
                newvalues[(int)StatsIndex.UnAckedBytes]        = m_unAckedBytes;
                newvalues[(int)StatsIndex.AgentMS]             = agentMS;
                newvalues[(int)StatsIndex.PendingDownloads]    = m_pendingDownloads;
                newvalues[(int)StatsIndex.PendingUploads]      = m_pendingUploads;
                newvalues[(int)StatsIndex.ActiveScripts]       = m_activeScripts;
                newvalues[(int)StatsIndex.SimSleepMs]          = (float)Math.Round(sleeptime, 3);
                newvalues[(int)StatsIndex.SimSpareMs]          = (float)Math.Round(sparetime, 3);
                newvalues[(int)StatsIndex.SimPhysicsStepMs]    = 20; // this should came from phys engine
                newvalues[(int)StatsIndex.ScriptMS]            = scriptTimeMS;
                newvalues[(int)StatsIndex.ScriptEps]           = (float)Math.Round(m_scriptEventsPerSecond * updateTimeFactor);

                // add extra stats for internal use
                newvalues[(int)StatsIndex.LSLScriptLinesPerSecond] = (float)Math.Round(m_scriptLinesPerSecond * updateTimeFactor, 3);
                newvalues[(int)StatsIndex.FrameDilation2]          = (Single.IsNaN(timeDilation)) ? 0.1f : (float)Math.Round(timeDilation, 1);
                newvalues[(int)StatsIndex.UsersLoggingIn]          = m_usersLoggingIn;
                newvalues[(int)StatsIndex.TotalGeoPrim]            = SG.GetTotalPrimObjectsCount();
                newvalues[(int)StatsIndex.TotalMesh] = SG.GetTotalMeshObjectsCount();
                newvalues[(int)StatsIndex.ScriptEngineThreadCount] = m_inUseThreads;
                newvalues[(int)StatsIndex.NPCs] = SG.GetRootNPCCount();

                lastReportedSimStats = newvalues;

                OnSendStatsResult?.Invoke(new SimStats(
                                              ReportingRegion.RegionLocX, ReportingRegion.RegionLocY,
                                              ReportingRegion.RegionSizeX, ReportingRegion.RegionSizeY,
                                              regionFlags, (uint)m_objectCapacity,
                                              newvalues,
                                              m_scene.RegionInfo.originRegionID,
                                              m_scene.RegionInfo.RegionName)
                                          );

                // Extra statistics that aren't currently sent elsewhere
                if (m_scene.PhysicsScene != null)
                {
                    lock (m_lastReportedExtraSimStats)
                    {
                        m_lastReportedExtraSimStats["LastReportedObjectUpdates"] = m_objectUpdates * updateTimeFactor;
                        m_lastReportedExtraSimStats[SlowFramesStat.ShortName]    = (float)SlowFramesStat.Value;

                        Dictionary <string, float> physicsStats = m_scene.PhysicsScene.GetStats();

                        if (physicsStats != null)
                        {
                            foreach (KeyValuePair <string, float> tuple in physicsStats)
                            {
                                // FIXME: An extremely dirty hack to divide MS stats per frame rather than per second
                                // Need to change things so that stats source can indicate whether they are per second or
                                // per frame.
                                if (tuple.Key.EndsWith("MS"))
                                {
                                    m_lastReportedExtraSimStats[tuple.Key] = tuple.Value * perframefactor;
                                }
                                else
                                {
                                    m_lastReportedExtraSimStats[tuple.Key] = tuple.Value * updateTimeFactor;
                                }
                            }
                        }
                    }
                }

//                LastReportedObjectUpdates = m_objectUpdates / m_statsUpdateFactor;
                ResetValues();
                Monitor.Exit(m_statsLock);
            }
        }