< Summary

Class:DCL.MessageBenchmarkController
Assembly:DCL.Runtime
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/WorldRuntime/Debugging/Panels/MessageBenchmarkController.cs
Covered lines:0
Uncovered lines:170
Coverable lines:170
Total lines:453
Line coverage:0% (0 of 170)
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/DCL/WorldRuntime/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
 91        public float messagesTotalTime
 92        {
 093            get { return logicTotalTime + decodeTotalTime; }
 94        }
 95
 96        private float logicTotalTime;
 97        private float decodeTotalTime;
 98        private string msgBeingProcessed;
 99
 100        void Init()
 101        {
 0102            this.statsPanel = GetComponent<StatsPanel>();
 103
 0104            columnsList = Enum.GetValues(typeof(Columns)).Cast<Columns>().ToList();
 0105            rowsList = Enum.GetValues(typeof(Rows)).Cast<Rows>().ToList();
 106
 0107            statsPanel.PopulateTable(columnsList.Count - 1, rowsList.Count);
 108
 0109            ResetTracker();
 110
 111            //NOTE(Brian): Top-left cell, unused.
 0112            statsPanel.SetCellText(0, 0, "");
 113
 114            //NOTE(Brian): Column stuff (top horizontal header)
 0115            statsPanel.SetCellText((int) Columns.LOGIC_MS, 0, COLUMN_LOGIC_MS_TEXT);
 0116            statsPanel.SetCellText((int) Columns.DECODE_MS, 0, COLUMN_DECODE_MS_TEXT);
 0117            statsPanel.SetCellText((int) Columns.QUEUED_COUNT, 0, COLUMN_QUEUED_COUNT_TEXT);
 0118            statsPanel.SetCellText((int) Columns.RATIO, 0, COLUMN_RATIO_TEXT);
 0119            statsPanel.SetCellText((int) Columns.TOTAL_TIME, 0, COLUMN_RATIO_TIMES_MS_TEXT);
 120
 121            //NOTE(Brian): Row stuff (left vertical header)
 0122            statsPanel.SetCellText(0, (int) Rows.TOTAL, ROW_TOTAL_TEXT);
 0123            statsPanel.SetCellText(0, (int) Rows.BREAK_0, "");
 0124            statsPanel.SetCellText(0, (int) Rows.SCENE_LOAD, ROW_SCENE_LOAD_TEXT);
 0125            statsPanel.SetCellText(0, (int) Rows.SCENE_DESTROY, ROW_SCENE_DESTROY_TEXT);
 0126            statsPanel.SetCellText(0, (int) Rows.BREAK_1, "");
 0127            statsPanel.SetCellText(0, (int) Rows.ENTITY_CREATE, ROW_ENTITY_CREATE_TEXT);
 0128            statsPanel.SetCellText(0, (int) Rows.ENTITY_DESTROY, ROW_ENTITY_DESTROY_TEXT);
 0129            statsPanel.SetCellText(0, (int) Rows.ENTITY_REPARENT, ROW_ENTITY_REPARENT_TEXT);
 0130            statsPanel.SetCellText(0, (int) Rows.BREAK_2, "");
 0131            statsPanel.SetCellText(0, (int) Rows.ENTITY_COMPONENT_CREATE, ROW_ENTITY_COMPONENT_CREATE_TEXT);
 0132            statsPanel.SetCellText(0, (int) Rows.ENTITY_COMPONENT_DESTROY, ROW_ENTITY_COMPONENT_DESTROY_TEXT);
 0133            statsPanel.SetCellText(0, (int) Rows.BREAK_3, "");
 0134            statsPanel.SetCellText(0, (int) Rows.SHARED_COMPONENT_CREATE, ROW_SHARED_COMPONENT_CREATE_TEXT);
 0135            statsPanel.SetCellText(0, (int) Rows.SHARED_COMPONENT_ATTACH, ROW_SHARED_COMPONENT_ATTACH_TEXT);
 0136            statsPanel.SetCellText(0, (int) Rows.SHARED_COMPONENT_DISPOSE, ROW_SHARED_COMPONENT_DISPOSE_TEXT);
 0137            statsPanel.SetCellText(0, (int) Rows.SHARED_COMPONENT_UPDATE, ROW_SHARED_COMPONENT_UPDATE_TEXT);
 0138            statsPanel.SetCellText(0, (int) Rows.BREAK_4, "");
 0139            statsPanel.SetCellText(0, (int) Rows.MISC, ROW_MISC_TEXT);
 140
 0141            stringToRow = new Dictionary<string, Rows>();
 142
 0143            stringToRow.Add("Total", Rows.TOTAL);
 0144            stringToRow.Add("CreateEntity", Rows.ENTITY_CREATE);
 0145            stringToRow.Add("SetEntityParent", Rows.ENTITY_REPARENT);
 0146            stringToRow.Add("RemoveEntity", Rows.ENTITY_DESTROY);
 147
 0148            stringToRow.Add("UpdateEntityComponent", Rows.ENTITY_COMPONENT_CREATE);
 0149            stringToRow.Add("ComponentRemoved", Rows.ENTITY_COMPONENT_DESTROY);
 150
 0151            stringToRow.Add("AttachEntityComponent", Rows.SHARED_COMPONENT_ATTACH);
 0152            stringToRow.Add("ComponentCreated", Rows.SHARED_COMPONENT_CREATE);
 0153            stringToRow.Add("ComponentDisposed", Rows.SHARED_COMPONENT_DISPOSE);
 0154            stringToRow.Add("ComponentUpdated", Rows.SHARED_COMPONENT_UPDATE);
 155
 0156            stringToRow.Add("LoadScene", Rows.SCENE_LOAD);
 0157            stringToRow.Add("UnloadScene", Rows.SCENE_DESTROY);
 0158            stringToRow.Add("Misc", Rows.MISC);
 0159        }
 160
 161        private void Awake()
 162        {
 0163            i = this;
 0164        }
 165
 166        public void StartProfiling()
 167        {
 0168            if (enabled)
 169            {
 0170                return;
 171            }
 172
 0173            enabled = true;
 174
 0175            if (statsPanel == null)
 176            {
 0177                Init();
 178            }
 179            else
 180            {
 0181                ResetTracker();
 182            }
 183
 0184            ProfilingEvents.OnMessageWillQueue += OnMessageWillQueue;
 0185            ProfilingEvents.OnMessageWillDequeue += OnMessageWillDequeue;
 186
 0187            ProfilingEvents.OnMessageProcessStart += OnMessageProcessStart;
 0188            ProfilingEvents.OnMessageProcessEnds += OnMessageProcessEnds;
 189
 0190            ProfilingEvents.OnMessageDecodeStart += OnMessageDecodeStart;
 0191            ProfilingEvents.OnMessageDecodeEnds += OnMessageDecodeEnds;
 192
 0193            updateCoroutine = CoroutineStarter.Start(UpdateTotalMs());
 0194        }
 195
 196        private Coroutine updateCoroutine;
 197
 198        public void StopProfiling()
 199        {
 0200            if (!enabled)
 201            {
 0202                return;
 203            }
 204
 0205            enabled = false;
 206
 0207            ProfilingEvents.OnMessageWillQueue -= OnMessageWillQueue;
 0208            ProfilingEvents.OnMessageWillDequeue -= OnMessageWillDequeue;
 209
 0210            ProfilingEvents.OnMessageProcessStart -= OnMessageProcessStart;
 0211            ProfilingEvents.OnMessageProcessEnds -= OnMessageProcessEnds;
 212
 0213            ProfilingEvents.OnMessageDecodeStart -= OnMessageDecodeStart;
 0214            ProfilingEvents.OnMessageDecodeEnds -= OnMessageDecodeEnds;
 215
 0216            CoroutineStarter.Stop(updateCoroutine);
 0217        }
 218
 219        IEnumerator UpdateTotalMs()
 220        {
 0221            while (true)
 222            {
 0223                logicTotalTime = 0;
 0224                decodeTotalTime = 0;
 225
 0226                foreach (var strRowPair in stringToRow)
 227                {
 0228                    float processedCount = statsTracker[(Columns.PROCESSED_COUNT, strRowPair.Value)];
 229
 0230                    if (processedCount > 0)
 231                    {
 0232                        logicTotalTime += statsTracker[(Columns.LOGIC_MS, strRowPair.Value)] / processedCount;
 0233                        decodeTotalTime += statsTracker[(Columns.DECODE_MS, strRowPair.Value)] / processedCount;
 234                    }
 235                }
 236
 0237                statsPanel.SetCellText((int) Columns.LOGIC_MS, (int) Rows.TOTAL,
 238                    logicTotalTime.ToString("N3", CultureInfo.InvariantCulture) + "ms");
 0239                statsPanel.SetCellText((int) Columns.DECODE_MS, (int) Rows.TOTAL,
 240                    decodeTotalTime.ToString("N3", CultureInfo.InvariantCulture) + "ms");
 0241                yield return WaitForSecondsCache.Get(0.5f);
 242            }
 243        }
 244
 245        private void Update()
 246        {
 0247            if (Input.GetKeyUp(KeyCode.R))
 248            {
 0249                ResetTracker();
 250            }
 0251        }
 252
 253        private void OnMessageDecodeStart(string s)
 254        {
 0255            if (!stringToRow.ContainsKey(s))
 256            {
 0257                return;
 258            }
 259
 0260            if (!string.IsNullOrEmpty(msgBeingProcessed) && stringToRow.ContainsKey(msgBeingProcessed))
 261            {
 0262                s = msgBeingProcessed;
 263            }
 264
 0265            decodeTimeTracker[stringToRow[s]] = DCLTime.realtimeSinceStartup;
 0266        }
 267
 268        private void OnMessageDecodeEnds(string s)
 269        {
 0270            if (!stringToRow.ContainsKey(s))
 271            {
 0272                return;
 273            }
 274
 0275            if (!string.IsNullOrEmpty(msgBeingProcessed) && stringToRow.ContainsKey(msgBeingProcessed))
 276            {
 0277                s = msgBeingProcessed;
 278            }
 279
 0280            float dt = DCLTime.realtimeSinceStartup - decodeTimeTracker[stringToRow[s]];
 281
 0282            AvgTrackedValue(Columns.DECODE_MS, stringToRow[s], dt * 1000);
 0283        }
 284
 285        private void OnMessageProcessEnds(string s)
 286        {
 0287            if (!stringToRow.ContainsKey(s))
 288            {
 0289                return;
 290            }
 291
 0292            statsTracker[(Columns.PROCESSED_COUNT, stringToRow[s])]++;
 0293            statsTracker[(Columns.PROCESSED_COUNT, Rows.TOTAL)]++;
 294
 295            //NOTE(Brian): Process ratio
 0296            float current = statsTracker[(Columns.PROCESSED_COUNT, stringToRow[s])];
 0297            float total = statsTracker[(Columns.PROCESSED_COUNT, Rows.TOTAL)];
 0298            float finalRatio = current / total * 100;
 299
 0300            statsPanel.SetCellText((int) Columns.RATIO, (int) stringToRow[s],
 301                finalRatio.ToString("N1", CultureInfo.InvariantCulture) + "%");
 302
 303            //NOTE(Brian): Process total time
 0304            float totalSecs = statsTracker[(Columns.LOGIC_MS, stringToRow[s])] +
 305                              statsTracker[(Columns.DECODE_MS, stringToRow[s])];
 306
 0307            totalSecs /= 1000;
 308
 0309            statsPanel.SetCellText((int) Columns.TOTAL_TIME, (int) stringToRow[s],
 310                totalSecs.ToString("N2", CultureInfo.InvariantCulture) + "secs");
 311
 0312            float dt = DCLTime.realtimeSinceStartup - processTimeTracker[stringToRow[s]];
 313
 314            //NOTE(Brian): Hack because I expect decode events to be called inside process events,
 315            //             with the exception of scene load one.
 0316            if (stringToRow[s] != Rows.SCENE_LOAD)
 317            {
 0318                statsTracker[(Columns.LOGIC_MS, stringToRow[s])] += dt * 1000;
 319
 320                //NOTE(Brian): I substract decode from logic because <check last comment>
 0321                int processedCount = (int) statsTracker[(Columns.PROCESSED_COUNT, stringToRow[s])];
 0322                float avg = statsTracker[(Columns.LOGIC_MS, stringToRow[s])] -
 323                            statsTracker[(Columns.DECODE_MS, stringToRow[s])];
 324
 0325                if (processedCount > 0)
 326                {
 0327                    avg /= processedCount;
 328                }
 329
 0330                statsPanel.SetCellText((int) Columns.LOGIC_MS, (int) stringToRow[s],
 331                    avg.ToString("N3", CultureInfo.InvariantCulture) + "ms");
 0332                msgBeingProcessed = string.Empty;
 0333                return;
 334            }
 335
 0336            AvgTrackedValue(Columns.LOGIC_MS, stringToRow[s], dt * 1000);
 0337            msgBeingProcessed = string.Empty;
 0338        }
 339
 340        private void OnMessageProcessStart(string s)
 341        {
 0342            if (!stringToRow.ContainsKey(s))
 343            {
 0344                return;
 345            }
 346
 0347            msgBeingProcessed = s;
 0348            processTimeTracker[stringToRow[s]] = DCLTime.realtimeSinceStartup;
 0349        }
 350
 351        void SumTrackedValue(Columns x, Rows y, int delta)
 352        {
 0353            statsTracker[(x, y)] += delta;
 0354            statsPanel.SetCellText((int) x, (int) y, statsTracker[(x, y)].ToString(CultureInfo.InvariantCulture));
 0355        }
 356
 357        void AvgTrackedValue(Columns x, Rows y, float ms)
 358        {
 0359            int processedCount = (int) statsTracker[(Columns.PROCESSED_COUNT, y)];
 0360            float result = 0;
 361
 0362            if (processedCount > 0)
 363            {
 0364                statsTracker[(x, y)] += ms;
 0365                result = statsTracker[(x, y)] / processedCount;
 366            }
 367            else
 368            {
 369                //NOTE(Brian): If we aren't tracking TOTAL for this particular row, we use the overall msgs total
 370                //             for computing the avg. This is currently used by misc row.
 0371                processedCount = (int) statsTracker[(Columns.PROCESSED_COUNT, Rows.TOTAL)];
 0372                statsTracker[(x, y)] += ms;
 0373                result = statsTracker[(x, y)] / (processedCount > 0 ? processedCount : 1.0f);
 374            }
 375
 0376            statsPanel.SetCellText((int) x, (int) y, result.ToString("N3", CultureInfo.InvariantCulture) + "ms");
 0377        }
 378
 379        private void OnMessageWillDequeue(string obj)
 380        {
 0381            CountMessage(obj, -1);
 0382        }
 383
 384        private void OnMessageWillQueue(string obj)
 385        {
 0386            CountMessage(obj, 1);
 0387        }
 388
 389        void CountMessage(string obj, int delta)
 390        {
 0391            if (!stringToRow.ContainsKey(obj))
 392            {
 0393                return;
 394            }
 395
 0396            SumTrackedValue(Columns.QUEUED_COUNT, Rows.TOTAL, delta);
 0397            SumTrackedValue(Columns.QUEUED_COUNT, stringToRow[obj], delta);
 398
 0399            if (statsTracker[(Columns.QUEUED_COUNT, Rows.TOTAL)] < 0)
 0400                statsTracker[(Columns.QUEUED_COUNT, Rows.TOTAL)] = 0;
 401
 0402            if (statsTracker[(Columns.QUEUED_COUNT, stringToRow[obj])] < 0)
 0403                statsTracker[(Columns.QUEUED_COUNT, stringToRow[obj])] = 0;
 0404        }
 405
 406        void ResetTracker()
 407        {
 408            //TODO(Brian): Dictionary with enum keys will generate unneeded boxing, fix later.
 0409            if (statsTracker == null)
 410            {
 0411                statsTracker = new Dictionary<(Columns, Rows), float>();
 412            }
 413
 0414            if (processTimeTracker == null)
 415            {
 0416                processTimeTracker = new Dictionary<Rows, float>();
 417            }
 418
 0419            if (decodeTimeTracker == null)
 420            {
 0421                decodeTimeTracker = new Dictionary<Rows, float>();
 422            }
 423
 0424            for (int x = 1; x < columnsList.Count; x++)
 425            {
 0426                Columns c = columnsList[x];
 427
 428                //NOTE(Brian): Ignore queued when resetting to avoid queued count go < 0.
 0429                if (c == Columns.QUEUED_COUNT && DictionaryContainsColumn(statsTracker, c))
 430                {
 431                    continue;
 432                }
 433
 0434                for (int y = 1; y < rowsList.Count; y++)
 435                {
 0436                    statsTracker[(c, rowsList[y])] = 0;
 0437                    statsPanel.SetCellText(x, y, "");
 438                }
 439            }
 0440        }
 441
 442        private bool DictionaryContainsColumn(Dictionary<(Columns, Rows), float> dictionary, Columns col)
 443        {
 0444            return dictionary.Any(x => x.Key.Item1 == col);
 445        }
 446
 447        private bool DictionaryContainsRow(Dictionary<(Columns, Rows), float> dictionary, Columns col, Rows row)
 448        {
 449            //It's faster to check Col again than using DictionaryContainsColumn method
 0450            return dictionary.Any(x => x.Key.Item1 == col && x.Key.Item2 == row);
 451        }
 452    }
 453}