Example #1
0
        private void Start()
        {
            Logger = base.Logger;

            _showCounter          = Config.Bind("General", "Toggle counter and reset stats", new KeyboardShortcut(KeyCode.U, KeyCode.LeftShift), "Key to enable and disable the plugin.");
            _shown                = Config.Bind("General", "Enable", false, "Monitor performance statistics and show them on the screen. When disabled the plugin has no effect on performance.");
            _showPluginStats      = Config.Bind("General", "Enable monitoring plugins", true, "Count time each plugin takes every frame to execute. Only detects MonoBehaviour event methods, so results might be lower than expected. Has a small performance penalty.");
            _showUnityMethodStats = Config.Bind("General", "Show detailed frame stats", true, "Show how much time was spent by Unity in each part of the frame, for example how long it took to run all Update methods.");

            try
            {
                var procMem      = MemoryInfo.QueryProcessMemStatus();
                var memorystatus = MemoryInfo.QuerySystemMemStatus();
                if (procMem.WorkingSetSize <= 0 || memorystatus.ullTotalPhys <= 0)
                {
                    throw new IOException("Empty data was returned");
                }

                _measureMemory = Config.Bind("General", "Show memory and GC stats", true,
                                             "Show memory usage of the process, free available physical memory and garbage collector statistics (if available).");
            }
            catch (Exception ex)
            {
                Logger.LogWarning("Memory statistics are not available - " + ex.Message);
            }

            _position     = Config.Bind("Interface", "Screen position", TextAnchor.LowerRight, "Which corner of the screen to display the statistics in.");
            _counterColor = Config.Bind("Interface", "Color of the text", CounterColors.White, "Color of the displayed stats. Outline has a performance hit but it always easy to see.");

            _position.SettingChanged     += (sender, args) => UpdateLooks();
            _counterColor.SettingChanged += (sender, args) => UpdateLooks();
            _shown.SettingChanged        += (sender, args) =>
            {
                UpdateLooks();
                SetCapturingEnabled(_shown.Value);
            };
            _showPluginStats.SettingChanged += (sender, args) => SetCapturingEnabled(_shown.Value);

            OnEnable();
        }
Example #2
0
            private IEnumerator Start()
            {
                _measurementStopwatch = new Stopwatch();
                var totalStopwatch   = new Stopwatch();
                var nanosecPerTick   = (float)(1000 * 1000 * 100) / Stopwatch.Frequency;
                var msScale          = 1f / (nanosecPerTick * 1000f);
                var gcPreviousAmount = 0L;

                while (true)
                {
                    // Waits until right after last Update
                    yield return(null);

                    _updateTime.Sample(TakeMeasurement());

                    // Waits until right after last OnGUI
                    yield return(_waitForEndOfFrame);

                    // If no OnGUI was executed somehow, make sure to log the render time
                    if (!_onGuiHit)
                    {
                        _renderTime.Sample(TakeMeasurement());
                        _onGuiHit = true;
                    }
                    CanProcessOnGui = false;

                    _onGuiTime.Sample(TakeMeasurement());
                    // Stop until FixedUpdate so it gets counted accurately (skip other end of frame stuff)
                    _measurementStopwatch.Reset();

                    // Get actual frame round-time
                    _frameTime.Sample(totalStopwatch.ElapsedTicks);
                    totalStopwatch.Reset();
                    totalStopwatch.Start();

                    // Calculate only once at end of frame so all data is from a single frame
                    var avgFrame = _frameTime.GetAverage();
                    var fps      = 1000000f / (avgFrame / nanosecPerTick);


                    fString.Append(fps, 2, 2).Append(" FPS");

                    if (_showUnityMethodStats.Value)
                    {
                        var avgFixed  = _fixedUpdateTime.GetAverage();
                        var avgUpdate = _updateTime.GetAverage();
                        var avgYield  = _yieldTime.GetAverage();
                        var avgLate   = _lateUpdateTime.GetAverage();
                        var avgRender = _renderTime.GetAverage();
                        var avgGui    = _onGuiTime.GetAverage();

                        var totalCapturedTicks = avgFixed + avgUpdate + avgYield + avgLate + avgRender + avgGui;
                        var otherTicks         = avgFrame - totalCapturedTicks;

                        // Print floats with 1 decimal precision i.e. XX.X and padding of 2,
                        // meaning we assume we always get XX.X value
                        fString.Append(", ").Append(avgFrame * msScale, 2, 2);
                        fString.Append("ms\nFixed: ").Append(avgFixed * msScale, 2, 2);
                        fString.Append("ms\nUpdate: ").Append(avgUpdate * msScale, 2, 2);
                        fString.Append("ms\nYield/anim: ").Append(avgYield * msScale, 2, 2);
                        fString.Append("ms\nLate: ").Append(avgLate * msScale, 2, 2);
                        fString.Append("ms\nRender/VSync: ").Append(avgRender * msScale, 2, 2);
                        fString.Append("ms\nOnGUI: ").Append(avgGui * msScale, 2, 2);
                        fString.Append("ms\nOther: ").Append(otherTicks * msScale, 2, 2).Append("ms");
                    }

                    if (_measureMemory != null && _measureMemory.Value)
                    {
                        var procMem    = MemoryInfo.QueryProcessMemStatus();
                        var currentMem = procMem.WorkingSetSize / 1024 / 1024;

                        var memorystatus = MemoryInfo.QuerySystemMemStatus();
                        var freeMem      = memorystatus.ullAvailPhys / 1024 / 1024;

                        fString.Append("\nRAM: ").Append((uint)currentMem).Append("MB used, ");
                        fString.Append((uint)freeMem).Append("MB free");

                        var totalGcMemBytes = GC.GetTotalMemory(false);
                        if (totalGcMemBytes != 0)
                        {
                            var gcDelta    = totalGcMemBytes - gcPreviousAmount;
                            var totalGcMem = totalGcMemBytes / 1024 / 1024;
                            _gcAddedSize.Sample(gcDelta);

                            fString.Append("\nGC: ").Append((int)totalGcMem).Append("MB (");
                            fString.Append(_gcAddedSize.GetAverageFloat() / 1024, 2, 4).Append("KB/s)");
                            //fString.Append(Mathf.RoundToInt(_gcAddedSize.GetAverage() * fps / 1024)).Append("KB/s)");

                            gcPreviousAmount = totalGcMemBytes;
                        }

                        // Check if current GC supports generations
                        var gcGens = GC.MaxGeneration;
                        if (gcGens > 0)
                        {
                            fString.Append("\nGC hits:");
                            for (var g = 0; g < gcGens; g++)
                            {
                                var collections = GC.CollectionCount(g);
                                fString.Append(' ').Append(g).Append(':').Append(collections);
                            }
                        }
                    }

                    var plugList = PluginCounter.SlowPlugins;
                    if (plugList != null)
                    {
                        if (plugList.Count > 0)
                        {
                            plugList.Sort(_comparer);
                            int len = plugList.Count;
                            for (int i = 0; i < len && i < 5; i++)
                            {
                                var kvav    = plugList[i];
                                var maxName = kvav.Key.Length > 20 ? 20 : kvav.Key.Length;
                                fString.Append("\n[").Append(kvav.Key, 0, maxName).Append(": ").Append(kvav.Value * msScale, 1, 2).Append("ms]");
                            }
                        }
                        else
                        {
                            fString.Append("\nNo slow plugins");
                        }
                    }

                    _frameOutputText = fString.Finalize();
                    _measurementStopwatch.Reset();
                }
            }
Example #3
0
            private IEnumerator Start()
            {
                _measurementStopwatch = new Stopwatch();
                var totalStopwatch = new Stopwatch();
                var nanosecPerTick = (float)(1000 * 1000 * 100) / Stopwatch.Frequency;
                var msScale = 1f / (nanosecPerTick * 1000f);

                while (true)
                {
                    // Waits until right after last Update
                    yield return null;

                    _updateTime.Sample(TakeMeasurement());

                    // Waits until right after last OnGUI
                    yield return new WaitForEndOfFrame();

                    // If no OnGUI was executed somehow, make sure to log the render time
                    if (!_onGuiHit)
                    {
                        _renderTime.Sample(TakeMeasurement());
                        _onGuiHit = true;
                    }
                    CanProcessOnGui = false;

                    _onGuiTime.Sample(TakeMeasurement());
                    // Stop until FixedUpdate so it gets counted accurately (skip other end of frame stuff)
                    _measurementStopwatch.Reset();

                    // Get actual frame round-time
                    _frameTime.Sample(totalStopwatch.ElapsedTicks);
                    totalStopwatch.Reset();
                    totalStopwatch.Start();

                    // Calculate only once at end of frame so all data is from a single frame
                    var avgFrame = _frameTime.GetAverage();
                    var fps = 1000000f / (avgFrame / nanosecPerTick);

                    // Reuse the SB to reduce amount of created garbage
                    _outputStringBuilder.Length = 0;

                    _outputStringBuilder.Append(fps.ToString("0.0"));
                    _outputStringBuilder.Append(" FPS");

                    if (_showUnityMethodStats.Value)
                    {
                        var avgFixed = _fixedUpdateTime.GetAverage();
                        var avgUpdate = _updateTime.GetAverage();
                        var avgYield = _yieldTime.GetAverage();
                        var avgLate = _lateUpdateTime.GetAverage();
                        var avgRender = _renderTime.GetAverage();
                        var avgGui = _onGuiTime.GetAverage();

                        var totalCapturedTicks = avgFixed + avgUpdate + avgYield + avgLate + avgRender + avgGui;
                        var otherTicks = avgFrame - totalCapturedTicks;

                        // todo split into append calls to reduce GC pressure? low impact
                        _outputStringBuilder.Append($", {avgFrame * msScale,5:0.0}ms\nFixed: {avgFixed * msScale,5:0.0}ms\nUpdate: {avgUpdate * msScale,5:0.0}ms\nYield/anim: {avgYield * msScale,5:0.0}ms\nLate: {avgLate * msScale,5:0.0}ms\nRender/VSync: {avgRender * msScale,5:0.0}ms\nOnGUI: {avgGui * msScale,5:0.0}ms\nOther: {otherTicks * msScale,5:0.0}ms");
                    }

                    if (_measureMemory != null && _measureMemory.Value)
                    {
                        _outputStringBuilder.AppendLine();

                        var procMem = MemoryInfo.QueryProcessMemStatus();
                        var currentMem = procMem.WorkingSetSize / 1024 / 1024;
                        _outputStringBuilder.Append($"RAM: {currentMem}MB used");

                        var totalGcMemBytes = GC.GetTotalMemory(false);
                        if (totalGcMemBytes != 0)
                        {
                            var totalGcMem = totalGcMemBytes / 1024 / 1024;
                            _outputStringBuilder.Append($" ({totalGcMem}MB in GC)");
                        }

                        var memorystatus = MemoryInfo.QuerySystemMemStatus();
                        var freeMem = memorystatus.ullAvailPhys / 1024 / 1024;
                        //var allMem = memorystatus.ullTotalPhys / 1024 / 1024;
                        _outputStringBuilder.Append($", {freeMem}MB free");

                        // Check if current GC supports generations
                        var gcGens = GC.MaxGeneration;
                        if (gcGens > 0)
                        {
                            _outputStringBuilder.AppendLine();
                            _outputStringBuilder.Append("GC hits:");
                            for (var g = 0; g < gcGens; g++)
                            {
                                var collections = GC.CollectionCount(g);
                                _outputStringBuilder.Append($" {g}:{collections}");
                            }
                        }
                    }

                    if (PluginCounter.StringOutput != null)
                    {
                        _outputStringBuilder.AppendLine();
                        _outputStringBuilder.Append(PluginCounter.StringOutput);
                    }

                    _frameOutputText = _outputStringBuilder.ToString();
                }
            }