< Summary

Class:DCL.MessageBenchmarkController
Assembly:MainScripts
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/Debugging/Panels/MessageBenchmarkController.cs
Covered lines:0
Uncovered lines:169
Coverable lines:169
Total lines:433
Line coverage:0% (0 of 169)
Covered branches:0
Total branches:0

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
Init()0%2100%
Awake()0%2100%
StartProfiling()0%12300%
StopProfiling()0%6200%
UpdateTotalMs()0%30500%
Update()0%6200%
OnMessageDecodeStart(...)0%20400%
OnMessageDecodeEnds(...)0%20400%
OnMessageProcessEnds(...)0%20400%
OnMessageProcessStart(...)0%6200%
SumTrackedValue(...)0%2100%
AvgTrackedValue(...)0%20400%
OnMessageWillDequeue(...)0%2100%
OnMessageWillQueue(...)0%2100%
CountMessage(...)0%20400%
ResetTracker()0%72800%
DictionaryContainsColumn(...)0%2100%
DictionaryContainsRow(...)0%2100%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/Debugging/Panels/MessageBenchmarkController.cs

#LineLine coverage
 1using System;
 2using System.Collections;
 3using System.Collections.Generic;
 4using System.Globalization;
 5using System.Linq;
 6using UnityEngine;
 7
 8namespace DCL
 9{
 10    public interface IBenchmarkController
 11    {
 12        void StartProfiling();
 13        void StopProfiling();
 14    }
 15
 16    [RequireComponent(typeof(StatsPanel))]
 17    public class MessageBenchmarkController : MonoBehaviour, IBenchmarkController
 18    {
 019        public static MessageBenchmarkController i { get; private set; }
 20
 21        public enum Columns
 22        {
 23            NONE,
 24            LOGIC_MS,
 25            DECODE_MS,
 26            QUEUED_COUNT,
 27            RATIO,
 28            TOTAL_TIME,
 29            PROCESSED_COUNT,
 30        }
 31
 32        public enum Rows
 33        {
 34            HEADER,
 35            TOTAL,
 36            BREAK_0,
 37            SCENE_LOAD,
 38            SCENE_DESTROY,
 39            BREAK_1,
 40            ENTITY_CREATE,
 41            ENTITY_DESTROY,
 42            ENTITY_REPARENT,
 43            BREAK_2,
 44            ENTITY_COMPONENT_CREATE,
 45            ENTITY_COMPONENT_DESTROY,
 46            BREAK_3,
 47            SHARED_COMPONENT_CREATE,
 48            SHARED_COMPONENT_UPDATE,
 49            SHARED_COMPONENT_DISPOSE,
 50            SHARED_COMPONENT_ATTACH,
 51            BREAK_4,
 52            MISC,
 53        }
 54
 55        const string COLUMN_MESSAGE_TYPE_TEXT = "Message type";
 56        const string COLUMN_LOGIC_MS_TEXT = "Process";
 57        const string COLUMN_DECODE_MS_TEXT = "Decode";
 58        const string COLUMN_QUEUED_COUNT_TEXT = "Queued";
 59        const string COLUMN_PROCESSED_COUNT_TEXT = "Processed";
 60        const string COLUMN_RATIO_TEXT = "Ratio";
 61        const string COLUMN_RATIO_TIMES_MS_TEXT = "Total Time";
 62
 63        const string ROW_TOTAL_TEXT = "Total";
 64
 65        const string ROW_ENTITY_CREATE_TEXT = "Entity Create";
 66        const string ROW_ENTITY_DESTROY_TEXT = "Entity Destroy";
 67        const string ROW_ENTITY_REPARENT_TEXT = "Entity Reparent";
 68
 69        const string ROW_SCENE_LOAD_TEXT = "Scene Load";
 70        const string ROW_SCENE_DESTROY_TEXT = "Scene Destroy";
 71
 72        const string ROW_ENTITY_COMPONENT_CREATE_TEXT = "Entity Comp. Create / Update";
 73        const string ROW_ENTITY_COMPONENT_UPDATE_TEXT = "";
 74        const string ROW_ENTITY_COMPONENT_DESTROY_TEXT = "Entity Component Destroy";
 75
 76        const string ROW_SHARED_COMPONENT_CREATE_TEXT = "Shared Component Create";
 77        const string ROW_SHARED_COMPONENT_UPDATE_TEXT = "Shared Component Update";
 78        const string ROW_SHARED_COMPONENT_DISPOSE_TEXT = "Shared Component Destroy";
 79        const string ROW_SHARED_COMPONENT_ATTACH_TEXT = "Shared Component Attach";
 80        const string ROW_MISC_TEXT = "Misc";
 81
 82        StatsPanel statsPanel;
 83
 84        Dictionary<(Columns, Rows), float> statsTracker;
 85        Dictionary<Rows, float> processTimeTracker;
 86        Dictionary<Rows, float> decodeTimeTracker;
 87        List<Columns> columnsList;
 88        List<Rows> rowsList;
 89        Dictionary<string, Rows> stringToRow;
 90
 091        public float messagesTotalTime { get { return logicTotalTime + decodeTotalTime; } }
 92
 93        private float logicTotalTime;
 94        private float decodeTotalTime;
 95        private string msgBeingProcessed;
 96
 97        void Init()
 98        {
 099            this.statsPanel = GetComponent<StatsPanel>();
 100
 0101            columnsList = Enum.GetValues(typeof(Columns)).Cast<Columns>().ToList();
 0102            rowsList = Enum.GetValues(typeof(Rows)).Cast<Rows>().ToList();
 103
 0104            statsPanel.PopulateTable(columnsList.Count - 1, rowsList.Count);
 105
 0106            ResetTracker();
 107
 108            //NOTE(Brian): Top-left cell, unused.
 0109            statsPanel.SetCellText(0, 0, "");
 110
 111            //NOTE(Brian): Column stuff (top horizontal header)
 0112            statsPanel.SetCellText((int) Columns.LOGIC_MS, 0, COLUMN_LOGIC_MS_TEXT);
 0113            statsPanel.SetCellText((int) Columns.DECODE_MS, 0, COLUMN_DECODE_MS_TEXT);
 0114            statsPanel.SetCellText((int) Columns.QUEUED_COUNT, 0, COLUMN_QUEUED_COUNT_TEXT);
 0115            statsPanel.SetCellText((int) Columns.RATIO, 0, COLUMN_RATIO_TEXT);
 0116            statsPanel.SetCellText((int) Columns.TOTAL_TIME, 0, COLUMN_RATIO_TIMES_MS_TEXT);
 117
 118            //NOTE(Brian): Row stuff (left vertical header)
 0119            statsPanel.SetCellText(0, (int) Rows.TOTAL, ROW_TOTAL_TEXT);
 0120            statsPanel.SetCellText(0, (int) Rows.BREAK_0, "");
 0121            statsPanel.SetCellText(0, (int) Rows.SCENE_LOAD, ROW_SCENE_LOAD_TEXT);
 0122            statsPanel.SetCellText(0, (int) Rows.SCENE_DESTROY, ROW_SCENE_DESTROY_TEXT);
 0123            statsPanel.SetCellText(0, (int) Rows.BREAK_1, "");
 0124            statsPanel.SetCellText(0, (int) Rows.ENTITY_CREATE, ROW_ENTITY_CREATE_TEXT);
 0125            statsPanel.SetCellText(0, (int) Rows.ENTITY_DESTROY, ROW_ENTITY_DESTROY_TEXT);
 0126            statsPanel.SetCellText(0, (int) Rows.ENTITY_REPARENT, ROW_ENTITY_REPARENT_TEXT);
 0127            statsPanel.SetCellText(0, (int) Rows.BREAK_2, "");
 0128            statsPanel.SetCellText(0, (int) Rows.ENTITY_COMPONENT_CREATE, ROW_ENTITY_COMPONENT_CREATE_TEXT);
 0129            statsPanel.SetCellText(0, (int) Rows.ENTITY_COMPONENT_DESTROY, ROW_ENTITY_COMPONENT_DESTROY_TEXT);
 0130            statsPanel.SetCellText(0, (int) Rows.BREAK_3, "");
 0131            statsPanel.SetCellText(0, (int) Rows.SHARED_COMPONENT_CREATE, ROW_SHARED_COMPONENT_CREATE_TEXT);
 0132            statsPanel.SetCellText(0, (int) Rows.SHARED_COMPONENT_ATTACH, ROW_SHARED_COMPONENT_ATTACH_TEXT);
 0133            statsPanel.SetCellText(0, (int) Rows.SHARED_COMPONENT_DISPOSE, ROW_SHARED_COMPONENT_DISPOSE_TEXT);
 0134            statsPanel.SetCellText(0, (int) Rows.SHARED_COMPONENT_UPDATE, ROW_SHARED_COMPONENT_UPDATE_TEXT);
 0135            statsPanel.SetCellText(0, (int) Rows.BREAK_4, "");
 0136            statsPanel.SetCellText(0, (int) Rows.MISC, ROW_MISC_TEXT);
 137
 0138            stringToRow = new Dictionary<string, Rows>();
 139
 0140            stringToRow.Add("Total", Rows.TOTAL);
 0141            stringToRow.Add("CreateEntity", Rows.ENTITY_CREATE);
 0142            stringToRow.Add("SetEntityParent", Rows.ENTITY_REPARENT);
 0143            stringToRow.Add("RemoveEntity", Rows.ENTITY_DESTROY);
 144
 0145            stringToRow.Add("UpdateEntityComponent", Rows.ENTITY_COMPONENT_CREATE);
 0146            stringToRow.Add("ComponentRemoved", Rows.ENTITY_COMPONENT_DESTROY);
 147
 0148            stringToRow.Add("AttachEntityComponent", Rows.SHARED_COMPONENT_ATTACH);
 0149            stringToRow.Add("ComponentCreated", Rows.SHARED_COMPONENT_CREATE);
 0150            stringToRow.Add("ComponentDisposed", Rows.SHARED_COMPONENT_DISPOSE);
 0151            stringToRow.Add("ComponentUpdated", Rows.SHARED_COMPONENT_UPDATE);
 152
 0153            stringToRow.Add("LoadScene", Rows.SCENE_LOAD);
 0154            stringToRow.Add("UnloadScene", Rows.SCENE_DESTROY);
 0155            stringToRow.Add("Misc", Rows.MISC);
 0156        }
 157
 0158        private void Awake() { i = this; }
 159
 160        public void StartProfiling()
 161        {
 0162            if (enabled)
 163            {
 0164                return;
 165            }
 166
 0167            enabled = true;
 168
 0169            if (statsPanel == null)
 170            {
 0171                Init();
 0172            }
 173            else
 174            {
 0175                ResetTracker();
 176            }
 177
 0178            ProfilingEvents.OnMessageWillQueue += OnMessageWillQueue;
 0179            ProfilingEvents.OnMessageWillDequeue += OnMessageWillDequeue;
 180
 0181            ProfilingEvents.OnMessageProcessStart += OnMessageProcessStart;
 0182            ProfilingEvents.OnMessageProcessEnds += OnMessageProcessEnds;
 183
 0184            ProfilingEvents.OnMessageDecodeStart += OnMessageDecodeStart;
 0185            ProfilingEvents.OnMessageDecodeEnds += OnMessageDecodeEnds;
 186
 0187            updateCoroutine = CoroutineStarter.Start(UpdateTotalMs());
 0188        }
 189
 190        private Coroutine updateCoroutine;
 191
 192        public void StopProfiling()
 193        {
 0194            if (!enabled)
 195            {
 0196                return;
 197            }
 198
 0199            enabled = false;
 200
 0201            ProfilingEvents.OnMessageWillQueue -= OnMessageWillQueue;
 0202            ProfilingEvents.OnMessageWillDequeue -= OnMessageWillDequeue;
 203
 0204            ProfilingEvents.OnMessageProcessStart -= OnMessageProcessStart;
 0205            ProfilingEvents.OnMessageProcessEnds -= OnMessageProcessEnds;
 206
 0207            ProfilingEvents.OnMessageDecodeStart -= OnMessageDecodeStart;
 0208            ProfilingEvents.OnMessageDecodeEnds -= OnMessageDecodeEnds;
 209
 0210            CoroutineStarter.Stop(updateCoroutine);
 0211        }
 212
 213        IEnumerator UpdateTotalMs()
 214        {
 0215            while (true)
 216            {
 0217                logicTotalTime = 0;
 0218                decodeTotalTime = 0;
 219
 0220                foreach (var strRowPair in stringToRow)
 221                {
 0222                    float processedCount = statsTracker[(Columns.PROCESSED_COUNT, strRowPair.Value)];
 223
 0224                    if (processedCount > 0)
 225                    {
 0226                        logicTotalTime += statsTracker[(Columns.LOGIC_MS, strRowPair.Value)] / processedCount;
 0227                        decodeTotalTime += statsTracker[(Columns.DECODE_MS, strRowPair.Value)] / processedCount;
 228                    }
 229                }
 230
 0231                statsPanel.SetCellText((int) Columns.LOGIC_MS, (int) Rows.TOTAL, logicTotalTime.ToString("N3", CultureIn
 0232                statsPanel.SetCellText((int) Columns.DECODE_MS, (int) Rows.TOTAL, decodeTotalTime.ToString("N3", Culture
 0233                yield return WaitForSecondsCache.Get(0.5f);
 234            }
 235        }
 236
 237        private void Update()
 238        {
 0239            if (Input.GetKeyUp(KeyCode.R))
 240            {
 0241                ResetTracker();
 242            }
 0243        }
 244
 245        private void OnMessageDecodeStart(string s)
 246        {
 0247            if (!stringToRow.ContainsKey(s))
 248            {
 0249                return;
 250            }
 251
 0252            if (!string.IsNullOrEmpty(msgBeingProcessed) && stringToRow.ContainsKey(msgBeingProcessed))
 253            {
 0254                s = msgBeingProcessed;
 255            }
 256
 0257            decodeTimeTracker[stringToRow[s]] = DCLTime.realtimeSinceStartup;
 0258        }
 259
 260        private void OnMessageDecodeEnds(string s)
 261        {
 0262            if (!stringToRow.ContainsKey(s))
 263            {
 0264                return;
 265            }
 266
 0267            if (!string.IsNullOrEmpty(msgBeingProcessed) && stringToRow.ContainsKey(msgBeingProcessed))
 268            {
 0269                s = msgBeingProcessed;
 270            }
 271
 0272            float dt = DCLTime.realtimeSinceStartup - decodeTimeTracker[stringToRow[s]];
 273
 0274            AvgTrackedValue(Columns.DECODE_MS, stringToRow[s], dt * 1000);
 0275        }
 276
 277        private void OnMessageProcessEnds(string s)
 278        {
 0279            if (!stringToRow.ContainsKey(s))
 280            {
 0281                return;
 282            }
 283
 0284            statsTracker[(Columns.PROCESSED_COUNT, stringToRow[s])]++;
 0285            statsTracker[(Columns.PROCESSED_COUNT, Rows.TOTAL)]++;
 286
 287            //NOTE(Brian): Process ratio
 0288            float current = statsTracker[(Columns.PROCESSED_COUNT, stringToRow[s])];
 0289            float total = statsTracker[(Columns.PROCESSED_COUNT, Rows.TOTAL)];
 0290            float finalRatio = current / total * 100;
 291
 0292            statsPanel.SetCellText((int) Columns.RATIO, (int) stringToRow[s], finalRatio.ToString("N1", CultureInfo.Inva
 293
 294            //NOTE(Brian): Process total time
 0295            float totalSecs = statsTracker[(Columns.LOGIC_MS, stringToRow[s])] +
 296                              statsTracker[(Columns.DECODE_MS, stringToRow[s])];
 297
 0298            totalSecs /= 1000;
 299
 0300            statsPanel.SetCellText((int) Columns.TOTAL_TIME, (int) stringToRow[s], totalSecs.ToString("N2", CultureInfo.
 301
 0302            float dt = DCLTime.realtimeSinceStartup - processTimeTracker[stringToRow[s]];
 303
 304            //NOTE(Brian): Hack because I expect decode events to be called inside process events,
 305            //             with the exception of scene load one.
 0306            if (stringToRow[s] != Rows.SCENE_LOAD)
 307            {
 0308                statsTracker[(Columns.LOGIC_MS, stringToRow[s])] += dt * 1000;
 309
 310                //NOTE(Brian): I substract decode from logic because <check last comment>
 0311                int processedCount = (int) statsTracker[(Columns.PROCESSED_COUNT, stringToRow[s])];
 0312                float avg = statsTracker[(Columns.LOGIC_MS, stringToRow[s])] -
 313                            statsTracker[(Columns.DECODE_MS, stringToRow[s])];
 314
 0315                if (processedCount > 0)
 316                {
 0317                    avg /= processedCount;
 318                }
 319
 0320                statsPanel.SetCellText((int) Columns.LOGIC_MS, (int) stringToRow[s], avg.ToString("N3", CultureInfo.Inva
 0321                msgBeingProcessed = string.Empty;
 0322                return;
 323            }
 324
 0325            AvgTrackedValue(Columns.LOGIC_MS, stringToRow[s], dt * 1000);
 0326            msgBeingProcessed = string.Empty;
 0327        }
 328
 329        private void OnMessageProcessStart(string s)
 330        {
 0331            if (!stringToRow.ContainsKey(s))
 332            {
 0333                return;
 334            }
 335
 0336            msgBeingProcessed = s;
 0337            processTimeTracker[stringToRow[s]] = DCLTime.realtimeSinceStartup;
 0338        }
 339
 340        void SumTrackedValue(Columns x, Rows y, int delta)
 341        {
 0342            statsTracker[(x, y)] += delta;
 0343            statsPanel.SetCellText((int) x, (int) y, statsTracker[(x, y)].ToString(CultureInfo.InvariantCulture));
 0344        }
 345
 346        void AvgTrackedValue(Columns x, Rows y, float ms)
 347        {
 0348            int processedCount = (int) statsTracker[(Columns.PROCESSED_COUNT, y)];
 0349            float result = 0;
 350
 0351            if (processedCount > 0)
 352            {
 0353                statsTracker[(x, y)] += ms;
 0354                result = statsTracker[(x, y)] / processedCount;
 0355            }
 356            else
 357            {
 358                //NOTE(Brian): If we aren't tracking TOTAL for this particular row, we use the overall msgs total
 359                //             for computing the avg. This is currently used by misc row.
 0360                processedCount = (int) statsTracker[(Columns.PROCESSED_COUNT, Rows.TOTAL)];
 0361                statsTracker[(x, y)] += ms;
 0362                result = statsTracker[(x, y)] / (processedCount > 0 ? processedCount : 1.0f);
 363            }
 364
 0365            statsPanel.SetCellText((int) x, (int) y, result.ToString("N3", CultureInfo.InvariantCulture) + "ms");
 0366        }
 367
 0368        private void OnMessageWillDequeue(string obj) { CountMessage(obj, -1); }
 369
 0370        private void OnMessageWillQueue(string obj) { CountMessage(obj, 1); }
 371
 372        void CountMessage(string obj, int delta)
 373        {
 0374            if (!stringToRow.ContainsKey(obj))
 375            {
 0376                return;
 377            }
 378
 0379            SumTrackedValue(Columns.QUEUED_COUNT, Rows.TOTAL, delta);
 0380            SumTrackedValue(Columns.QUEUED_COUNT, stringToRow[obj], delta);
 381
 0382            if (statsTracker[(Columns.QUEUED_COUNT, Rows.TOTAL)] < 0)
 0383                statsTracker[(Columns.QUEUED_COUNT, Rows.TOTAL)] = 0;
 384
 0385            if (statsTracker[(Columns.QUEUED_COUNT, stringToRow[obj])] < 0)
 0386                statsTracker[(Columns.QUEUED_COUNT, stringToRow[obj])] = 0;
 0387        }
 388
 389        void ResetTracker()
 390        {
 391            //TODO(Brian): Dictionary with enum keys will generate unneeded boxing, fix later.
 0392            if (statsTracker == null)
 393            {
 0394                statsTracker = new Dictionary<(Columns, Rows), float>();
 395            }
 396
 0397            if (processTimeTracker == null)
 398            {
 0399                processTimeTracker = new Dictionary<Rows, float>();
 400            }
 401
 0402            if (decodeTimeTracker == null)
 403            {
 0404                decodeTimeTracker = new Dictionary<Rows, float>();
 405            }
 406
 0407            for (int x = 1; x < columnsList.Count; x++)
 408            {
 0409                Columns c = columnsList[x];
 410
 411                //NOTE(Brian): Ignore queued when resetting to avoid queued count go < 0.
 0412                if (c == Columns.QUEUED_COUNT && DictionaryContainsColumn(statsTracker, c))
 413                {
 414                    continue;
 415                }
 416
 0417                for (int y = 1; y < rowsList.Count; y++)
 418                {
 0419                    statsTracker[(c, rowsList[y])] = 0;
 0420                    statsPanel.SetCellText(x, y, "");
 421                }
 422            }
 0423        }
 424
 0425        private bool DictionaryContainsColumn(Dictionary<(Columns, Rows), float> dictionary, Columns col) { return dicti
 426
 427        private bool DictionaryContainsRow(Dictionary<(Columns, Rows), float> dictionary, Columns col, Rows row)
 428        {
 429            //It's faster to check Col again than using DictionaryContainsColumn method
 0430            return dictionary.Any(x => x.Key.Item1 == col && x.Key.Item2 == row);
 431        }
 432    }
 433}