[
  {
    "path": ".gitignore",
    "content": "# =============== #\n# Unity generated #\n# =============== #\n[Ll]ibrary/\n[Tt]emp/\n[Oo]bj/\n[Bb]uild/\n[Bb]uilds/\n[Uu]nity[Pp]ackage[Mm]anager/\n[Ll]ogs/\n[Pp]ackages/[Mm]icrosoft*/\n*.pidb.meta\n*.pdb.meta\n*.mdb.meta\n*.apk\n*.unitypackage\n*.log\napp.config\npackages.config\n# Unity3D Generated File On Crash Reports #\nsysinfo.txt\n \n# ===================================== #\n# Visual Studio / MonoDevelop / Rider etc. generated #\n# ===================================== #\nExportedObj/\n.consulo/\n.vs/\n*.csproj\n*.unityproj\n*.sln\n*.suo\n*.tmp\n*.user\n*.userprefs\n*.pidb\n*.booproj\n*.svd\n*.pdb\n*.mdb\n*.opendb\n*.VC.db\n.idea\n \n# ============ #\n# OS generated #\n# ============ #\n.DS_Store\n.DS_Store?\n._*\n.Spotlight-V100\n.Trashes\nehthumbs.db\nThumbs.db"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog\nAll notable changes to the webrtc package will be documented in this file.\n\nThe format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)\nand this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).\n\n## [0.1.2-preview] - 2021-09-23\n### Changed\n- Deferred drawing the GUI so it pollutes the data less.\n- Fixed an issue where \"Domain unloader\" wasn't found as it was renamed to \"Domain Unloader\".\n\n## [0.1.1-preview] - 2020-10-03\n### Changed\n- Fixed documentation references.\n- Removed square brackets from the name of the entries in this window.\n\n\n## [0.1.0-preview] - 2020-06-10\n- Initial Release."
  },
  {
    "path": "CHANGELOG.md.meta",
    "content": "fileFormatVersion: 2\nguid: 249ab3ebb372f234e98dbac31f5e3265\nTextScriptImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing\n\n## All contributions are subject to the [Unity Contribution Agreement(UCA)](https://unity3d.com/legal/licenses/Unity_Contribution_Agreement)\nBy making a pull request, you are confirming agreement to the terms and conditions of the UCA, including that your Contributions are your original creation and that you have complete right and authority to make your Contributions.\n\n## Once you have a change ready following these ground rules. Simply make a pull request\n"
  },
  {
    "path": "CONTRIBUTING.md.meta",
    "content": "fileFormatVersion: 2\nguid: 2b6a7b8e81611044a8d28e71c0e71043\nTextScriptImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "Documentation~/TableOfContents.md",
    "content": "* [About the Editor Iteration Profiler](index.md)\n* [Using the Editor Iteration Profiler](editor-iteration-profiler.md)\n* [Exporting data](exporting-data.md)\n"
  },
  {
    "path": "Documentation~/editor-iteration-profiler.md",
    "content": "# Using the Editor Iteration Profiler\nOnce you’ve installed the Editor Iteration Profiler, navigate to __Window &gt; Analysis &gt; Editor Iteration Profiler &gt; Show Window__. This opens the EIP in its own window. \n\n![](images/editor-iteration-profiler-window.png) <br/>\n*The Editor Iteration profiler window*\n\n## Editor Iteration Profiler controls\nThe controls for the EIP are in the toolbar at the top of the window. You can use these controls to navigate through the data and export it.\n\n|**Control**|**Function**|\n|---|---|\n|**Enable**|Enables the Editor Iteration Profiler and starts collecting data. When you select this button, the EIP also enables the Profiler and sets it to run with the __Editor__ as its profiling target.| \n|**Deep Profile**|Collects all information on managed calls. For more information on deep profiling, see the documentation on the [Profiler window](https://docs.unity3d.com/Manual/ProfilerWindow.html#deep-profiling).|\n|**Flatten**|Collapses events in the table that contain multiple parent items with one child. This is useful if you are investigating GUI code or have performed Deep Profiling.|\n|**User Code**|Filters out Unity engine code and displays information related to your own code.|\n|**Clear**|Removes all recorded events from the EIP.|\n|**Collapse All**|Recursively collapses all events in the table.|\n|**Print to Console**|Logs all data to the console in a plain text format.|\n|**Export**|Export all of the data in the EIP. You can choose from HTML, JSON, CSV, Plaintext, or HTML Performance Report. For more information on this see the documentation on [Exporting data](exporting-data.md).|\n|**Export Profiler Data**|Export the data in the EIP for the selected Profiler frame, or choose a range of Profiler frames to export the EIP data for. When you select **Multiple Frames**, the beginning and end limits are inclusive. For more information, see the documentation on [How to export data](exporting-data#how-to-export-data.md)|\n"
  },
  {
    "path": "Documentation~/exporting-data.md",
    "content": "# Exporting Data\n\nYou can export the data that the Editor Iteration Profiler captures in several different file formats so that you can inspect the performance of your application in greater detail. The following file formats are available:\n\n* [.html](exporting-data#html.md)\n* [.json](exporting-data#json.md) (for [chrome tracing](http://www.chromium.org/developers/how-tos/trace-event-profiling-tool))\n* [.csv](exporting-data#csv.md)\n* [Plain text](exporting-data#plain-text.md)\n* [HTML Performance Report](exporting-data#html-report.md)\n\n<a name=\"how-to\"></a>\n\n## How to export data\nTo export all of the data that the EIP has captured, select __Export__ in the toolbar at the top of the EIP window, and then choose the format you want to export the data in. The EIP then displays a Save dialog box, where you can choose where to save the data to.\n\nTo export the data that the EIP has captured for a particular frame in the Profiler, select that frame in the Profiler window. Then in the EIP window’s toolbar, select __Export Profiler Data &gt; Export Selected Frame__ and choose the format you’d like to export the data to. The EIP then displays a Save dialog box, where you can choose where to save the data to.\n\nYou can also export the data the EIP has captured for a range of Profiler frames. To do this, select __Export Profiler Data &gt; Multiple Frames__ in the EIP window’s toolbar, and then choose the format you’d like to export the data to. The EIP then displays a dialog box that you can use to set the beginning and end range for the frames you want to export the data for.\n\n![](images/export-profiler-frame-selection.png) <br/>\n*The frame range selector dialog box*\n\nSelect the __Export__ button and then the EIP displays a Save dialog box where you can choose where to save the data to.\n\n<a name=\"html\"></a>\n\n## HTML export option\nThe __HTML__ export option exports the EIP data to a .html format that you can then open in a web browser and inspect further. It contains the same data in the EIP window, but also displays a percentage of how much time was spent on each event. \n\n![](images/export-html.png) <br/>\n*EIP data in HTML format*\n\n> [!NOTE]\n> Events in square brackets are leaf items without any children.\n\n<a name=\"json\"></a>\n\n## JSON export option\nThe __JSON__ export option exports the EIP data to a .json format, which you can then use to visualize the data with the [Chrome Tracing](http://www.chromium.org/developers/how-tos/trace-event-profiling-tool) tool. To use Chrome Tracing, go to `chrome://tracing` in a Chromium-based web browser(Google Chrome, Microsoft Edge Chromium, Opera, etc.), and then import the .json file.\n\n![](images/export-chrome-tracing.png) <br/>\n*EIP data in .json format imported into Chrome Tracing*\n\n<a name=\"csv\"></a>\n\n## CSV export option\nThe __CSV__ export option exports the EIP data to a .csv format which you can then use to import the data into other programs, such as Excel or a Python library. \n\n> [!NOTE] \n>This file contains a header in which environment information is stored (system specs, date etc.)\n\n<a name=\"plain-text\"></a>\n\n## Plaintext export option\nThe __Plaintext__ export option exports the EIP data into a plain text file format. This is the same data that you can display in the console if you select __Print to Console__ button in the EIP window’s toolbar. It also gives you the option to isolate the data and remove other information which is in the `Editor.log` file.\n\n<a name=\"html-report\"> </a>\n\n## HTML Performance Report export option\nThe __HTML Performance Report__ displays the EIP data in a similar way to the HTML export option, but additionally groups together information and also reduces the number of levels you need to click through to get to important information.\n\n![](images/export-html-performance-report.png) <br/>\n*HTML Performance Report view*\n\nItems in curly brackets `{}` represent items that have children that the EIP hid because the parents were under the minimum set threshold, which is currently set to a hard-coded value of 1%.\n\nThe colored items represent ‘buckets’ of similar data, which the EIP groups in one place for convenience. The EIP does not add the total time of these to the original time, and it gives an estimate for that iteration.\n"
  },
  {
    "path": "Documentation~/index.md",
    "content": "# About Editor Iteration Profiler\nThe Editor Iteration Profiler (EIP) is a tool that you can use alongside [Unity's built-in Profiler](https://docs.unity3d.com/Manual/Profiler.html) to monitor Editor iteration (domain reload) times. It helps you to understand why Unity takes a long time to compile your scripts or enter Play Mode. \n\nAn iteration is a process that contains instructions that it repeats until a condition is met. Unity relies on a variety of iteration types. The EIP uses the data from the Profiler to monitor iterations that relate to the scripting side of Unity, specifically:\n\n* Entering and exiting Play Mode\n* Assembly reloads\n* Script compilations\n\nDuring these iterations, the Profiler also monitors Asset import time. \n\nThe EIP saves all of this information in a separate window which you can then use to navigate through the data the Profiler produces. What’s more, the data that the EIP collects persists for the lifetime of the Editor, unlike the built-in Profiler which is limited to storing a set number of frames. \n\nYou can then [export the captured data](exporting-data.md) to either HTML, JSON, CSV, or plain text format. In addition to these formats, you can export the data to a HTML Performance Report, which groups the data together to make it easier to see areas you can optimize.\n\n## Preview package\nThis package is available as a preview, so it is not ready for production use. The features and documentation in this package might change before it is verified for release.\n\n## Package contents\nThe following table describes the package folder structure:\n\n|**Location**|**Description**|\n|---|---|\n|`Editor`| Contains the code for this package.|\n|`Documentation~`| Contains the documentation for the package.|\n\n\n## Installation\nTo install this package, perform the following steps:\n\n* Download the repository from GitHub\n* Place it into your Project’s `Packages` folder\n\n## Requirements\nThis version of Editor Iteration Profiler is compatible with the following versions of the Unity Editor:\n\n* 2019.3 and later\n\n## Known limitations\nThe Editor Iteration Profiler package has the following known limitations:\n\n* During Deep Profiling the system might run out of memory and freeze the whole Editor for extended periods of time, especially in large Projects.\n* If the script compilation taxes more than 600 frames, the EIP might not capture all data.\n\n## Feedback and troubleshooting\nPlease report bugs/suggestions at https://github.com/Unity-Technologies/com.unity.editoriterationprofiler/issues .\n\nIf you encounter any problems with the EIP, either select the __Clear__ button in the toolbar of the EIP window, or go to __Window &gt; Analysis &gt; Editor Iteration Profiler &gt; Purge Cache__ to clear the EIP’s cache. This usually resolves most issues.\n"
  },
  {
    "path": "Editor/DataCollector.cs",
    "content": "using System;\nusing UnityEditor.EditorIterationProfiler.API;\nusing UnityEngine.Assertions;\n\nnamespace UnityEditor.EditorIterationProfiler\n{\n    [Serializable]\n    class DataCollector : IEventSubscriber\n    {\n        IIterationList m_IterationList;\n        IProfilerDataCollector m_ProfilerDataCollector;\n\n        public DataCollector(IProfilerDataCollector profilerCollector, IIterationList iterationList)\n        {\n            Initialize(profilerCollector, iterationList);\n        }\n\n        void Initialize(IProfilerDataCollector profilerCollector, IIterationList iterationList)\n        {\n            m_IterationList = iterationList;\n            m_ProfilerDataCollector = profilerCollector;\n        }\n\n        public void Subscribe()\n        {\n            UnityEditorEvents.Subscribe();\n            UnityEditorEvents.EditorEvent += EditorEvent;\n        }\n\n        public void Unsubscribe()\n        {\n            UnityEditorEvents.Unsubscribe();\n            UnityEditorEvents.EditorEvent -= EditorEvent;\n        }\n\n        void EditorEvent(UnityEditorEvents.Event evt, string data)\n        {\n            Assert.IsNotNull(m_IterationList);\n\n            if (!UnityProfiling.EditorProfilingEnabled)\n            {\n                return;\n            }\n\n            //Debug.Log($\"EditorEvent: {evt} {data}\");\n\n            switch (evt)\n            {\n                case UnityEditorEvents.Event.ScriptCompilationStarted:\n                {\n                    m_IterationList.NewIteration(IterationEventKind.ScriptCompilation);\n\n                    var assetImportEvent = m_IterationList.LastIterationEventRoot.StartEvent(IterationEventKind.AssetImport);\n                    m_ProfilerDataCollector.Collect(IterationEventKind.AssetImport, m_IterationList.LastIterationEventRoot, assetImportEvent);\n\n                    var scriptCompilationEvent = m_IterationList.LastIterationEventRoot.StartEvent(IterationEventKind.ScriptCompilation);\n\n                    scriptCompilationEvent.SetStartTime();\n                    break;\n                }\n\n                case UnityEditorEvents.Event.ScriptCompilationFinished:\n                {\n                    m_IterationList.LastIterationEventRoot.FinishEvent(IterationEventKind.ScriptCompilation);\n                    break;\n                }\n\n                case UnityEditorEvents.Event.AssemblyCompilationStarted:\n                {\n                    var eventData = m_IterationList.LastIterationEventRoot.StartEvent(IterationEventKind.AssemblyCompilation, data, null);\n                    m_IterationList.LastIterationEventRoot.SetParent(eventData, IterationEventKind.ScriptCompilation);\n\n                    //m_ProfilerDataCollector.Collect(IterationEventKind.AssemblyCompilationStart, m_IterationList.LastIterationEventRoot, eventData);\n\n                    eventData.SetStartTime();\n                    break;\n                }\n\n                case UnityEditorEvents.Event.AssemblyCompilationFinished:\n                {\n                    //var ev = m_IterationList.LastIterationEventRoot.FindLastEvent(IterationEventKind.ScriptCompilation);\n                    //m_ProfilerDataCollector.Collect(IterationEventKind.AssemblyCompilationFinish, m_IterationList.LastIterationEventRoot, ev);\n                    m_IterationList.LastIterationEventRoot.FinishEvent(data);\n                    break;\n                }\n\n                case UnityEditorEvents.Event.AssemblyReloadStarted:\n                {\n                    if (m_IterationList.LastIterationEventRoot != null)\n                    {\n                        var enterPlayModeEvent = m_IterationList.LastIterationEventRoot.FindLastEvent(IterationEventKind.EnterPlayMode);\n\n                        // If this assembly reload is part of a enter play mode iteration,\n                        // then do no add the event, as it happens in the same frame and\n                        // profiling data will contain the domain reload event data.\n                        if (enterPlayModeEvent != null)\n                        {\n                            return;\n                        }\n\n                        var eventData = m_IterationList.LastIterationEventRoot.StartEvent(IterationEventKind.AssemblyReload);\n                        m_ProfilerDataCollector.Collect(IterationEventKind.AssemblyReload, m_IterationList.LastIterationEventRoot, eventData);\n                    }\n                    break;\n                }\n\n                case UnityEditorEvents.Event.AssemblyReloadFinished:\n                {\n                    break;\n                }\n\n                case UnityEditorEvents.Event.EnteringPlayMode:\n                {\n                    m_IterationList.NewIteration(IterationEventKind.EnterPlayMode);\n                    var eventData = m_IterationList.LastIterationEventRoot.StartEvent(IterationEventKind.EnterPlayMode);\n                    m_ProfilerDataCollector.Collect(IterationEventKind.EnterPlayMode, m_IterationList.LastIterationEventRoot, eventData);\n                    break;\n                }\n\n                case UnityEditorEvents.Event.EnteredPlayMode:\n                {\n                    break;\n                }\n\n                case UnityEditorEvents.Event.ExitingPlayMode:\n                {\n                    m_IterationList.NewIteration(IterationEventKind.ExitPlayMode);\n                    var eventData = m_IterationList.LastIterationEventRoot.StartEvent(IterationEventKind.ExitPlayMode);\n                    m_ProfilerDataCollector.Collect(IterationEventKind.ExitPlayMode, m_IterationList.LastIterationEventRoot, eventData);\n                    break;\n                }\n\n                case UnityEditorEvents.Event.ExitedPlayMode:\n                {\n                    break;\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Editor/DataCollector.cs.meta",
    "content": "fileFormatVersion: 2\nguid: ea639bdc1b7738841a40c85658e414f1\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "Editor/EditorIterationProfiler.API/IEditorIterationProfilerController.cs",
    "content": "﻿namespace UnityEditor.EditorIterationProfiler.API\n{\n    public interface IEditorIterationProfilerController\n    {\n        IIterationList IterationList { get; }\n        IDataReporterProvider DataReporterProvider { get; }\n\n        EditorIterationProfilerSettings Settings { get; }\n    }\n}\n"
  },
  {
    "path": "Editor/EditorIterationProfiler.API/IEditorIterationProfilerController.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 3b753f26d3c16a64fb73f79a76bfc62c\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "Editor/EditorIterationProfiler.API/IEventSubscriber.cs",
    "content": "﻿namespace UnityEditor.EditorIterationProfiler\n{\n    public interface IEventSubscriber\n    {\n        void Subscribe();\n        void Unsubscribe();\n    }\n}\n"
  },
  {
    "path": "Editor/EditorIterationProfiler.API/IEventSubscriber.cs.meta",
    "content": "fileFormatVersion: 2\nguid: dfbe793476c38d545acebf95bef144a9\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "Editor/EditorIterationProfiler.API/IIterationList.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing UnityEditor.EditorIterationProfiler.Formatting;\n\nnamespace UnityEditor.EditorIterationProfiler\n{\n    public interface IIterationList\n    {\n        List<IterationEventRoot> IterationEventRoots { get; }\n        IterationEventRoot LastIterationEventRoot { get; }\n        List<IterationEventKind> IterationEventKinds { get; }\n        Action<IIterationList> Updated { get; set; }\n        void NewIteration(IterationEventKind kind);\n        void NotifyUpdated();\n    }\n}\n"
  },
  {
    "path": "Editor/EditorIterationProfiler.API/IIterationList.cs.meta",
    "content": "fileFormatVersion: 2\nguid: b3881855ff94b2a419205af6f42f003b\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "Editor/EditorIterationProfiler.API/IProfilerDataCollector.cs",
    "content": "﻿namespace UnityEditor.EditorIterationProfiler.API\n{\n    public interface IProfilerDataCollector : IEventSubscriber\n    {\n        void Collect(IterationEventKind iterationEventKind, IterationEventRoot iterationEventRoot, EventData rootEvent);\n        void Clear();\n    }\n}\n"
  },
  {
    "path": "Editor/EditorIterationProfiler.API/IProfilerDataCollector.cs.meta",
    "content": "fileFormatVersion: 2\nguid: a368e7eb7b9059c429c7bb9837c8f3fa\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "Editor/EditorIterationProfiler.API.meta",
    "content": "fileFormatVersion: 2\nguid: 69bdb52499db5994ca64e22a6bc04cf5\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "Editor/EditorIterationProfilerAnalytics.cs",
    "content": "using System.Collections;\nusing System.Collections.Generic;\nusing UnityEngine;\nusing UnityEngine.Analytics;\n\nnamespace UnityEditor.EditorIterationProfiler\n{\n    class EditorIterationProfilerAnalytics\n    {\n        const string k_VendorKey = \"unity.editoriterationprofiler\";\n\n        static bool s_ExportEventRegistered;\n        static bool s_InteractionEventRegistered;\n        const int k_MaxEventsPerHour = 1000;\n        const int k_MaxNumberOfElements = 1000;\n        const string k_ExportEventName = \"eipExport\";\n        const string k_InteractionEventName = \"eipInteraction\";\n\n        static bool EnableAnalytics()\n        {\n            AnalyticsResult resultExport = EditorAnalytics.RegisterEventWithLimit(k_ExportEventName, k_MaxEventsPerHour, k_MaxNumberOfElements, k_VendorKey);\n            AnalyticsResult resultInteraction = EditorAnalytics.RegisterEventWithLimit(k_InteractionEventName, k_MaxEventsPerHour, k_MaxNumberOfElements, k_VendorKey);\n\n            if (resultExport == AnalyticsResult.Ok)\n            {\n                s_ExportEventRegistered = true;\n            }\n\n            if (resultExport == AnalyticsResult.Ok)\n            {\n                s_InteractionEventRegistered = true;\n            }\n\n            return s_ExportEventRegistered && s_InteractionEventRegistered;\n        }\n\n        internal enum ExportStatus\n        {\n            Started,\n            Finished,\n            Error\n        }\n\n        internal enum ExportType\n        {\n            Selected,\n            MultiWindow,\n            Multi,\n            Captured,\n            CapturedAll\n        }\n\n        struct ExportEventData\n        {\n            public string guid;\n            public string format;\n            public string type;\n            public string status;\n        }\n\n        struct InteractionEventData\n        {\n            public bool eipState;\n            public bool isPlaying;\n            public bool deepProfile;\n            public bool flatten;\n            public bool userCode;\n        }\n\n        public static void SendExportEvent(string format, string type, string status, string guid)\n        {\n            if (!UnityEngine.Analytics.Analytics.enabled || !EnableAnalytics())\n            {\n                return;\n            }\n\n            var data = new ExportEventData()\n            {\n                format = format,\n                type = type,\n                status = status,\n                guid = guid\n            };\n\n            EditorAnalytics.SendEventWithLimit(k_ExportEventName, data);\n        }\n\n        public static void SendInteractionEvent(bool state, bool isPlaying, bool deepProfile, bool flatten, bool userCode)\n        {\n            if (!UnityEngine.Analytics.Analytics.enabled || !EnableAnalytics())\n            {\n                return;\n            }\n\n            var data = new InteractionEventData()\n            {\n                eipState = state,\n                isPlaying = isPlaying,\n                deepProfile = deepProfile,\n                flatten = flatten,\n                userCode = userCode\n            };\n\n            EditorAnalytics.SendEventWithLimit(k_InteractionEventName, data);\n        }\n\n    }\n}\n"
  },
  {
    "path": "Editor/EditorIterationProfilerAnalytics.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 5248670f7ba3f2c419bab949189a46bc\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "Editor/EditorIterationProfilerController.cs",
    "content": "﻿using System.Collections.Generic;\nusing UnityEditor.EditorIterationProfiler.API;\nusing UnityEngine;\nusing UnityEngine.Assertions;\n\nnamespace UnityEditor.EditorIterationProfiler\n{\n    public class EditorIterationProfilerController : ScriptableObject, IEditorIterationProfilerController\n    {\n        [SerializeField]\n        IterationList m_IterationList;\n        public IIterationList IterationList => m_IterationList;\n\n        [SerializeField]\n        ProfilerDataCollector m_ProfilerDataCollector;\n        public IProfilerDataCollector ProfilerDataCollector => m_ProfilerDataCollector;\n\n        [SerializeField]\n        DataReporterProvider m_DataReporterProvider;\n        public IDataReporterProvider DataReporterProvider => m_DataReporterProvider;\n\n        [SerializeField]\n        EditorIterationProfilerSettings m_Settings;\n        public EditorIterationProfilerSettings Settings => m_Settings;\n\n        [SerializeField]\n        DataCollector m_DataCollector;\n\n        public EditorIterationProfilerController()\n        {\n            m_IterationList = new IterationList();\n\n            m_ProfilerDataCollector = new ProfilerDataCollector(m_IterationList);\n\n            m_DataCollector = new DataCollector(m_ProfilerDataCollector, m_IterationList);\n\n            m_DataReporterProvider = new DataReporterProvider();\n\n            m_Settings = new EditorIterationProfilerSettings();\n        }\n\n        public EditorIterationProfilerController(IIterationList iterationList, IProfilerDataCollector profilerDataCollector)\n        {\n            m_IterationList = iterationList as IterationList;\n\n            m_ProfilerDataCollector = profilerDataCollector as ProfilerDataCollector;\n\n            m_DataCollector = new DataCollector(m_ProfilerDataCollector, m_IterationList);\n\n            m_DataReporterProvider = new DataReporterProvider();\n\n            m_Settings = new EditorIterationProfilerSettings();\n        }\n\n        void OnEnable()\n        {\n            m_DataCollector.Subscribe();\n            m_ProfilerDataCollector.Subscribe();\n        }\n\n        void OnDisable()\n        {\n            m_DataCollector.Unsubscribe();\n            m_ProfilerDataCollector.Unsubscribe();\n        }\n\n        internal void Initialize()\n        {\n            m_IterationList.Reload();\n        }\n\n        public void Clear()\n        {\n            m_IterationList.Clear();\n            m_ProfilerDataCollector.Clear();\n        }\n    }\n}\n"
  },
  {
    "path": "Editor/EditorIterationProfilerController.cs.meta",
    "content": "fileFormatVersion: 2\nguid: a7e1f201c78caea4ab211abb5ca49032\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "Editor/EditorIterationProfilerIntegration.cs",
    "content": "﻿using System.Linq;\nusing UnityEditor.EditorIterationProfiler.API;\nusing UnityEngine;\nusing Object = UnityEngine.Object;\n\nnamespace UnityEditor.EditorIterationProfiler\n{\n    [InitializeOnLoad]\n    public static class EditorIterationProfilerIntegration\n    {\n        static EditorIterationProfilerController s_Instance;\n        public static IEditorIterationProfilerController Instance\n        {\n            get\n            {\n                if (s_Instance != null)\n                {\n                    return s_Instance;\n                }\n\n                FindOrCreateInstance();\n                return s_Instance;\n            }\n        }\n\n        static EditorIterationProfilerIntegration()\n        { \n            EditorApplication.delayCall += Initialize;\n        }\n\n        internal static void Initialize()\n        {\n            FindOrCreateInstance();\n        }\n\n        static void FindOrCreateInstance()\n        {\n            EditorIterationProfilerController[] instances = Resources.FindObjectsOfTypeAll<EditorIterationProfilerController>();\n\n            if (instances != null)\n            {\n                s_Instance = instances.FirstOrDefault();\n            }\n\n            if (s_Instance == null)\n            {\n                s_Instance = ScriptableObject.CreateInstance<EditorIterationProfilerController>();\n                s_Instance.hideFlags = HideFlags.DontSave;\n            }\n            s_Instance.Initialize();\n        }\n\n        public static void Clear()\n        {\n            s_Instance.Clear();\n        }\n\n\n        [MenuItem(\"Window/Analysis/Editor Iteration Profiler/Purge Caches\", priority = 21)]\n        public static void PurgeScriptableObjects()\n        {\n            Debug.Log(\"Caches Purged!\", s_Instance);\n\n            if (s_Instance != null)\n            {\n                Clear();\n            }\n\n            EditorIterationProfilerController[] instances = Resources.FindObjectsOfTypeAll<EditorIterationProfilerController>();\n            foreach (var instance in instances)\n            {\n                Object.DestroyImmediate(instance);\n            }\n\n            FindOrCreateInstance();\n        }\n    }\n}\n"
  },
  {
    "path": "Editor/EditorIterationProfilerIntegration.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 9920ea31757240744bbf4d4b9c7f9f14\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "Editor/EditorIterationProfilerSettings.cs",
    "content": "﻿using System;\nusing System.Text;\nusing UnityEditor.Compilation;\nusing UnityEngine;\n\nnamespace UnityEditor.EditorIterationProfiler.API\n{\n    [Serializable]\n    public class EditorIterationProfilerSettings\n    {\n        [field: SerializeField]\n        public bool DeepProfile { get; set; }\n\n        [field: SerializeField]\n        public bool Flatten { get; set; }\n\n        [field: SerializeField]\n        public bool UserCode { get; set; }\n\n        internal string UnityVersion => Application.unityVersion;\n        internal string ProductName => PlayerSettings.productName;\n        internal string Time => DateTime.UtcNow + \" UTC\";\n        internal bool FastEnterPlayMode => EditorSettings.enterPlayModeOptionsEnabled;\n        internal string Platform => Application.platform.ToString();\n#if UNITY_2020_OR_NEWER\n        internal string CodeOptimization => CompilationPipeline.codeOptimization.ToString();\n#endif\n        internal string SystemInfo => UnityEngine.SystemInfo.processorType.TrimEnd() + \"; \" + UnityEngine.SystemInfo.systemMemorySize / 1000 + \" GB RAM\";\n\n        public override string ToString()\n        {\n            var sb = new StringBuilder();\n\n            sb.AppendLine($\"Time: {EditorIterationProfilerIntegration.Instance.Settings.Time}\");\n            sb.AppendLine($\"Unity Version: {EditorIterationProfilerIntegration.Instance.Settings.UnityVersion}\");\n            sb.AppendLine($\"Platform: {EditorIterationProfilerIntegration.Instance.Settings.Platform}\");\n            sb.AppendLine($\"System Specs: {EditorIterationProfilerIntegration.Instance.Settings.SystemInfo}\");\n            sb.AppendLine($\"Product Name: {EditorIterationProfilerIntegration.Instance.Settings.ProductName}\");\n            sb.AppendLine($\"Deep Profile: {EditorIterationProfilerIntegration.Instance.Settings.DeepProfile}\");\n            sb.AppendLine($\"Flatten: {EditorIterationProfilerIntegration.Instance.Settings.Flatten}\");\n            sb.AppendLine($\"User Code: {EditorIterationProfilerIntegration.Instance.Settings.UserCode}\");\n            sb.AppendLine($\"Fast EnterPlayMode: {EditorIterationProfilerIntegration.Instance.Settings.FastEnterPlayMode}\");\n#if UNITY_2020_OR_NEWER\n           sb.Append($\"Editor Code Optimization: {EditorIterationProfilerIntegration.Instance.Settings.CodeOptimization}\");\n#endif\n            return sb.ToString();\n        }\n    }\n}\n"
  },
  {
    "path": "Editor/EditorIterationProfilerSettings.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 0635b7d495ef2fa4a97e5eb88021bacf\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "Editor/EditorIterationProfilerTreeView.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing UnityEditor.IMGUI.Controls;\nusing UnityEngine;\nusing UnityEngine.Assertions;\n\nnamespace UnityEditor.EditorIterationProfiler\n{\n    [Serializable]\n    class EditorIterationProfilerTreeViewItem : TreeViewItem\n    {\n        public string Details\n        {\n            get; set;\n        }\n        public double Duration\n        {\n            get; set;\n        }\n    }\n\n    public class EditorIterationProfilerTreeView : TreeView\n    {\n        enum ColumnId\n        {\n            Event,\n            Details,\n            Duration,\n        }\n\n        static readonly ColumnId[] k_ColumnTypes =\n        {\n            ColumnId.Event,\n            ColumnId.Details,\n            ColumnId.Duration,\n        };\n\n        bool m_UserCodeOnly;\n        public bool UserCodeOnly\n        {\n            get => m_UserCodeOnly; \n            set\n            {\n                m_UserCodeOnly = value;\n                EditorIterationProfilerIntegration.Instance.Settings.UserCode = value;\n            }\n        }\n\n        bool m_Flatten;\n        public bool Flatten\n        {\n            get => m_Flatten;\n            set\n            {\n                m_Flatten = value;\n                EditorIterationProfilerIntegration.Instance.Settings.Flatten = value;\n            }\n        }\n\n        public EditorIterationProfilerTreeView(TreeViewState state, MultiColumnHeader header) : base(state, header)\n        {\n            if (header == null)\n            {\n                throw new ArgumentNullException(nameof(header), \"Header is null\");\n            }\n\n            showAlternatingRowBackgrounds = true;\n            showBorder = true;\n\n            header.sortingChanged += OnSortingChanged;\n\n            UserCodeOnly = EditorPrefs.GetBool(EditorIterationProfilerWindow.Styles.k_UserCodePref);\n            Flatten = EditorPrefs.GetBool(EditorIterationProfilerWindow.Styles.k_FlattenPref);\n            EditorIterationProfilerIntegration.Instance.IterationList.Updated += iterationList => Reload();\n            Reload();\n        }\n\n        void OnSortingChanged(MultiColumnHeader multiColumnHeader)\n        {\n            var index = multiColumnHeader.sortedColumnIndex;\n            var columnTypes = k_ColumnTypes[index];\n            if (hasSearch)\n            {\n                //Sort(GetRows(), columnTypes, multiColumnHeader.IsSortedAscending(index));\n            }\n            else\n            {\n                //SortHierarchical(rootItem, columnTypes, multiColumnHeader.IsSortedAscending(index));\n            }\n            Reload();\n        }\n\n        static void Sort(IList<TreeViewItem> rows, ColumnId columnId, bool ascending)\n        {\n            if (rows == null)\n            {\n                return;\n            }\n\n            IList<TreeViewItem> sortedRows;\n            switch (columnId)\n            {\n                case ColumnId.Details:\n                {\n                    sortedRows = rows.Order(x => ((EditorIterationProfilerTreeViewItem)x).Details, ascending).ToList();\n                    break;\n                }\n                case ColumnId.Duration:\n                {\n                    sortedRows = rows.Order(x => ((EditorIterationProfilerTreeViewItem)x).Duration, ascending).ToList();\n                    break;\n                }\n                default:\n                {\n                    sortedRows = rows.Order(x => ((EditorIterationProfilerTreeViewItem)x).displayName, ascending).ToList();\n                    break;\n                }\n            }\n\n            rows.Clear();\n            foreach (var r in sortedRows)\n            {\n                rows.Add(r);\n            }\n        }\n\n        static void SortHierarchical(TreeViewItem root, ColumnId columnId, bool ascending = true)\n        {\n            if (root == null)\n            {\n                return;\n            }\n\n            SortItems(root.children, columnId, ascending);\n        }\n\n        static void SortItems(IList<TreeViewItem> children, ColumnId columnId, bool ascending = true)\n        {\n            if (children == null)\n            {\n                return;\n            }\n\n            IList<TreeViewItem> sortedRows;\n            switch (columnId)\n            {\n                case ColumnId.Details:\n                {\n                    sortedRows = children.Order(x => ((EditorIterationProfilerTreeViewItem)x).Details, ascending).ToList();\n                    break;\n                }\n                case ColumnId.Duration:\n                {\n                    sortedRows = children.Order(x => ((EditorIterationProfilerTreeViewItem)x).Duration, ascending).ToList();\n                    break;\n                }\n                default:\n                {\n                    sortedRows = children.Order(x => ((EditorIterationProfilerTreeViewItem)x).displayName, ascending).ToList();\n                    break;\n                }\n            }\n\n            children.Clear();\n            foreach (var r in sortedRows)\n            {\n                children.Add(r);\n            }\n\n            foreach (var c in children)\n            {\n                SortItems(c.children, columnId, ascending);\n            }\n        }\n\n        protected override void DoubleClickedItem(int id)\n        {\n            if (hasSearch && state.selectedIDs.Count != 0)\n            {\n                ClearSearch();\n                CollapseAll();\n                FrameItem(id);\n            }\n            else\n            {\n                SetExpanded(id, !IsExpanded(id));\n            }\n        }\n\n        internal void ClearSearch()\n        {\n            searchString = string.Empty;\n        }\n\n        protected override TreeViewItem BuildRoot()\n        {\n            var root = new EditorIterationProfilerTreeViewItem { id = 0, depth = -1, displayName = \"Root\", Details = null };\n            var allItems = new List<TreeViewItem>();\n\n            var iterationList = EditorIterationProfilerIntegration.Instance.IterationList;\n            var idCounter = 1;\n            var iterationCounter = 1;\n\n            var eventDataFlagsFilter = EventDataFlags.None;\n\n            if (UserCodeOnly)\n            {\n                eventDataFlagsFilter |= EventDataFlags.UserCode;\n            }\n\n            if (Flatten)\n            {\n                eventDataFlagsFilter |= EventDataFlags.Flatten;\n            }\n\n            for (var i = 0; i < iterationList.IterationEventRoots.Count; ++i)\n            {\n                var eventDataList = iterationList.IterationEventRoots[i];\n                var iterationItem = new EditorIterationProfilerTreeViewItem { id = idCounter++, depth = 0, displayName = string.Empty };\n                double iterationDuration = 0;\n\n                allItems.Add(iterationItem);\n\n                foreach (var eventData in eventDataList.Events)\n                {\n                    if (eventData.ParentIndex < 0)\n                    {\n                        iterationDuration += eventData.Duration;\n                        AddEventDataRecursive(eventData, allItems, ref idCounter, 1, eventDataFlagsFilter);\n                    }\n                }\n\n                iterationItem.displayName = $\"Iteration Event {iterationCounter++} ({iterationList.IterationEventKinds[i]})\";\n                iterationItem.Duration = iterationDuration;\n            }\n\n            SetupParentsAndChildrenFromDepths(root, allItems);\n\n            return root;\n        }\n\n        static bool ShouldAddTreeViewItem(EventData eventData, EventDataFlags filter)\n        {\n            var flags = eventData.Flags;\n\n            if (eventData.Kind != IterationEventKind.None)\n            {\n                return true;\n            }\n\n            if (filter == EventDataFlags.None)\n            {\n                return true;\n            }\n\n            if (filter.HasFlag(EventDataFlags.UserCode) && filter.HasFlag(EventDataFlags.Flatten))\n            {\n                if ((flags & filter).HasFlag(EventDataFlags.UserCode))\n                {\n                    if ((flags & filter).HasFlag(EventDataFlags.Flatten))\n                    {\n                        return false;\n                    }\n                    return true;\n                }\n                return false;\n            }\n\n            if ((flags & filter).HasFlag(EventDataFlags.UserCode))\n            {\n                return true;\n            }\n\n            if (!(flags & filter).HasFlag(EventDataFlags.Flatten))\n            {\n                if (filter.HasFlag(EventDataFlags.Flatten))\n                {\n                    return true;\n                }\n            }\n\n            return false;\n        }\n\n        static void AddEventDataRecursive(EventData eventData, List<TreeViewItem> treeViewItems, ref int idCounter, int depth, EventDataFlags eventDataFlagsFilter)\n        {\n            if (ShouldAddTreeViewItem(eventData, eventDataFlagsFilter))\n            {\n                treeViewItems.Add(new EditorIterationProfilerTreeViewItem\n                {\n                    id = idCounter++,\n                    depth = depth++,\n                    displayName = eventData.DisplayName,\n                    Details = eventData.Details,\n                    Duration = eventData.Duration\n                });\n            }\n\n            if (eventData.Children == null)\n            {\n                return;\n            }\n\n            foreach (var child in eventData.Children)\n            {\n                AddEventDataRecursive(child, treeViewItems, ref idCounter, depth, eventDataFlagsFilter);\n            }\n        }\n\n        protected override void RowGUI(RowGUIArgs args)\n        {\n            var item = (EditorIterationProfilerTreeViewItem)args.item;\n\n            for (var i = 0; i < args.GetNumVisibleColumns(); ++i)\n            {\n                CellGUI(args.GetCellRect(i), item, args.GetColumn(i), ref args);\n            }\n        }\n\n        void CellGUI(Rect cellRect, EditorIterationProfilerTreeViewItem item, int column, ref RowGUIArgs args)\n        {\n            args.rowRect = cellRect;\n\n            switch (column)\n            {\n                case 0:\n                {\n                    base.RowGUI(args);\n                    break;\n                }\n                case 1:\n                {\n                    if (!string.IsNullOrEmpty(item.Details))\n                    {\n                        DefaultGUI.Label(cellRect, item.Details, args.selected, args.focused);\n                    }\n\n                    break;\n                }\n                case 2:\n                {\n                    DefaultGUI.LabelRightAligned(cellRect, $\"{item.Duration:0.000}\", args.selected, args.focused);\n                    break;\n                }\n            }\n        }\n\n        public static MultiColumnHeaderState CreateDefaultMultiColumnHeaderState()\n        {\n            var columns = new[]\n            {\n                new MultiColumnHeaderState.Column\n                {\n                    headerContent = new GUIContent(\"Event\"),\n                    headerTextAlignment = TextAlignment.Left,\n                    sortingArrowAlignment = TextAlignment.Left,\n                    minWidth = 250,\n                    autoResize = true,\n                    allowToggleVisibility = false\n                },\n                new MultiColumnHeaderState.Column\n                {\n                    headerContent = new GUIContent(\"Details\"),\n                    headerTextAlignment = TextAlignment.Left,\n                    sortingArrowAlignment = TextAlignment.Center,\n                    minWidth = 100,\n                    autoResize = false,\n                    allowToggleVisibility = true\n                },\n                new MultiColumnHeaderState.Column\n                {\n                    headerContent = new GUIContent(\"Duration (ms)\"),\n                    headerTextAlignment = TextAlignment.Left,\n                    sortingArrowAlignment = TextAlignment.Right,\n                    minWidth = 100,\n                    autoResize = false,\n                    allowToggleVisibility = false\n                }\n            };\n\n            Assert.AreEqual(columns.Length, k_ColumnTypes.Length, L10n.Tr($\"Number of columns should match number of {k_ColumnTypes}\"));\n\n            return new MultiColumnHeaderState(columns);\n        }\n    }\n\n    static class ExtensionMethods\n    {\n        public static IOrderedEnumerable<T> Order<T, TKey>(this IEnumerable<T> source, Func<T, TKey> selector, bool ascending)\n        {\n            if (ascending)\n            {\n                return source.OrderBy(selector);\n            }\n\n            return source.OrderByDescending(selector);\n        }\n\n        public static IOrderedEnumerable<T> ThenBy<T, TKey>(this IOrderedEnumerable<T> source, Func<T, TKey> selector, bool ascending)\n        {\n            if (ascending)\n            {\n                return source.ThenBy(selector);\n            }\n            else\n            {\n                return source.ThenByDescending(selector);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Editor/EditorIterationProfilerTreeView.cs.meta",
    "content": "fileFormatVersion: 2\nguid: e6651dd15ebe6e1478d78afed8ff3dee\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "Editor/EditorIterationProfilerWindow.cs",
    "content": "﻿using System;\nusing System.IO;\nusing System.Reflection;\nusing UnityEditor.EditorIterationProfiler.Formatting;\nusing UnityEditor.IMGUI.Controls;\nusing UnityEditorInternal;\nusing UnityEngine;\nusing UnityEngine.Assertions;\nusing ExportStatus = UnityEditor.EditorIterationProfiler.EditorIterationProfilerAnalytics.ExportStatus;\nusing ExportType = UnityEditor.EditorIterationProfiler.EditorIterationProfilerAnalytics.ExportType;\n\nnamespace UnityEditor.EditorIterationProfiler\n{\n\n    public class EditorIterationProfilerWindow : EditorWindow\n    {\n        internal static class Styles\n        {\n            public static readonly GUIContent k_EnableProfiler = EditorGUIUtility.TrTextContent(\"Enable\");\n            public static readonly GUIContent k_ClearProfilerData = EditorGUIUtility.TrTextContent(\"Clear\");\n            public static readonly GUIContent k_DeepProfile = EditorGUIUtility.TrTextContent(\"Deep Profile\", \"Show all managed calls\");\n            public static readonly GUIContent k_UserCode = EditorGUIUtility.TrTextContent(\"User Code\", \"Only show user code\");\n            public static readonly GUIContent k_Flatten = EditorGUIUtility.TrTextContent(\"Flatten\", \"Flatten markers\");\n            public static readonly GUIContent k_CollapseAll = EditorGUIUtility.TrTextContent(\"Collapse All\", \"Collapse all foldouts\");\n            public static readonly GUIContent k_LogConsole = EditorGUIUtility.TrTextContent(\"Print to Console\", \"Prints plaintext into the log and console\");\n            public static readonly GUIContent k_Export = EditorGUIUtility.TrTextContent(\"Export...\", \"Exports the data captured by the Editor Iteration Profiler\");\n            public static readonly GUIContent k_ExportProfiler = EditorGUIUtility.TrTextContent(\"Export Profiler Data...\", \"Exports the selected frame or the last frame in the Profiler\");\n\n            public const string k_EditorIterationProfilerPrefix = \"EIP_\";\n            public const string k_EnableProfilerPref = k_EditorIterationProfilerPrefix + \"ProfilingEnabled\";\n            public const string k_EnableDeepProfile = k_EditorIterationProfilerPrefix + \"DeepProfilingEnabled\";\n            public const string k_UserCodePref = k_EditorIterationProfilerPrefix + \"UserCodeOnly\";\n            public const string k_FlattenPref = k_EditorIterationProfilerPrefix + \"Flatten\";\n\n            public const string k_EventHeaderWidthSizePref = k_EditorIterationProfilerPrefix + \"EventHeaderWidthSizePref\";\n            public const string k_DetailsHeaderWidthSizePref = k_EditorIterationProfilerPrefix + \"DetailsWidthSizePref\";\n            public const string k_DurationHeaderWidthSizePref = k_EditorIterationProfilerPrefix + \"HeaderWidthSizePref\";\n\n            public const float k_SingleLineHeight =\n#if UNITY_2019_3_OR_NEWER\n                18;\n#else\n                16;\n#endif\n        }\n\n        [NonSerialized]\n        bool m_Initialized;\n        [SerializeField]\n        MultiColumnHeaderState m_MultiColumnHeaderState;\n        [SerializeField]\n        TreeViewState m_TreeViewState;\n        EditorIterationProfilerTreeView m_TreeView;\n        SearchField m_SearchField;\n\n        bool isWindowReady = false;\n\n        [MenuItem(\"Window/Analysis/Editor Iteration Profiler/Show Window\", priority = 8)]\n        static void ShowProfilerWindow()\n        {\n            var window = GetWindow<EditorIterationProfilerWindow>(\"Editor Iteration Profiler\");\n            window.minSize = new Vector2(500, 300);\n        }\n\n        void OnEnable()\n        {\n            isWindowReady = false;\n            EditorApplication.delayCall += OnEnableInitialize;\n        }\n\n        void OnEnableInitialize()\n        {\n            if (!m_Initialized)\n            {\n                InitializeButtonStateFromPrefs();\n\n                if (m_TreeViewState == null)\n                {\n                    m_TreeViewState = new TreeViewState();\n                }\n\n                bool firstInit = m_MultiColumnHeaderState == null;\n                var headerState = EditorIterationProfilerTreeView.CreateDefaultMultiColumnHeaderState();\n\n                if (MultiColumnHeaderState.CanOverwriteSerializedFields(m_MultiColumnHeaderState, headerState))\n                {\n                    MultiColumnHeaderState.OverwriteSerializedFields(m_MultiColumnHeaderState, headerState);\n                }\n\n                m_MultiColumnHeaderState = headerState;\n                InitializeHeaderStateFromPrefs(headerState);\n\n                var multiColumnHeader = new MultiColumnHeader(headerState);\n                if (firstInit)\n                {\n                    multiColumnHeader.ResizeToFit();\n                }\n\n                m_TreeView = new EditorIterationProfilerTreeView(m_TreeViewState, multiColumnHeader);\n\n                m_SearchField = new SearchField();\n                m_SearchField.downOrUpArrowKeyPressed += m_TreeView.SetFocusAndEnsureSelectedItem;\n\n                m_Initialized = true;\n\n                isWindowReady = true;\n            }\n        }\n\n        void DrawToolbar()\n        {\n            GUILayout.BeginHorizontal(EditorStyles.toolbar);\n\n            UnityProfiling.EditorProfilingEnabled = GUILayout.Toggle(UnityProfiling.EditorProfilingEnabled, Styles.k_EnableProfiler, EditorStyles.toolbarButton);\n\n            UnityProfiling.SetProfileDeepScripts(GUILayout.Toggle(ProfilerDriver.deepProfiling, Styles.k_DeepProfile, EditorStyles.toolbarButton));\n\n            var flatten = GUILayout.Toggle(m_TreeView.Flatten, Styles.k_Flatten, EditorStyles.toolbarButton);\n\n            var userCodeOnly = GUILayout.Toggle(m_TreeView.UserCodeOnly, Styles.k_UserCode, EditorStyles.toolbarButton);\n\n            GUILayout.Space(5);\n\n            if (GUILayout.Button(Styles.k_ClearProfilerData, EditorStyles.toolbarButton))\n            {\n                EditorIterationProfilerIntegration.Clear();\n            }\n\n            if (GUILayout.Button(Styles.k_CollapseAll, EditorStyles.toolbarButton))\n            {\n                m_TreeView.CollapseAll();\n            }\n\n            if (GUILayout.Button(Styles.k_LogConsole, EditorStyles.toolbarButton))\n            {\n                var reporter = EditorIterationProfilerIntegration.Instance.DataReporterProvider.TryGetDataReporter(\"EditorLogReporter\");\n                reporter.Report(EditorIterationProfilerIntegration.Instance.IterationList);\n            }\n\n            if (EditorGUILayout.DropdownButton(Styles.k_Export, FocusType.Passive, EditorStyles.toolbarPopup))\n            {\n                var menu = new GenericMenu();\n\n                var exporters = EditorIterationProfilerIntegration.Instance.DataReporterProvider.GetAllReporters<IFileDataReporter>();\n\n                foreach (var exporter in exporters)\n                {\n                    menu.AddItem(new GUIContent(exporter.Name), false, () => ReportExtension(exporter, EditorIterationProfilerIntegration.Instance.IterationList, ExportType.Captured));\n                }\n\n                menu.AddSeparator(\"\");\n\n                menu.AddItem(new GUIContent(\"Export all available formats\"), false, () => ReportAllExtensions(EditorIterationProfilerIntegration.Instance.IterationList));\n\n                var dropDownRect = EditorGUILayout.GetControlRect();\n                dropDownRect.x += 500;\n                dropDownRect.y += 18;\n\n                menu.DropDown(dropDownRect);\n            }\n\n            if (EditorGUILayout.DropdownButton(Styles.k_ExportProfiler, FocusType.Passive, EditorStyles.toolbarPopup))\n            {\n                var menu = new GenericMenu();\n\n                var exporters = EditorIterationProfilerIntegration.Instance.DataReporterProvider.GetAllReporters<IFileDataReporter>();\n\n                var assembly = typeof(Editor).Assembly;\n                var windowType = assembly.GetType(\"UnityEditor.ProfilerWindow\");\n                var profilerWindow = GetWindow(windowType);\n                var currentFrameInfo = windowType.GetField(\"m_CurrentFrame\", BindingFlags.NonPublic | BindingFlags.Instance);\n                Assert.IsNotNull(currentFrameInfo);\n\n                int currentFrameIndex = (int)currentFrameInfo.GetValue(profilerWindow);\n\n                foreach (var exporter in exporters)\n                {\n                    menu.AddItem(new GUIContent(\"Selected Frame/\" + exporter.Name), false, () => ReportSelectedFrame(exporter, currentFrameIndex));\n                }\n\n                menu.AddSeparator(\"\");\n\n                foreach (var exporter in exporters)\n                {\n                    menu.AddItem(new GUIContent(\"Multiple Frames/\" + exporter.Name), false, () =>\n                    {\n                        var window = GetWindow<ProfilerMultiFrameSelector>();\n                        window.Initialize(exporter);\n                    });\n                }\n\n                var dropDownRect = EditorGUILayout.GetControlRect();\n                dropDownRect.x += 600;\n                dropDownRect.y += 18;\n\n                menu.DropDown(dropDownRect);\n            }\n\n            GUILayout.Space(5);\n\n            GUILayout.FlexibleSpace();\n\n            if (m_TreeView.UserCodeOnly != userCodeOnly)\n            {\n                EditorIterationProfilerAnalytics.SendInteractionEvent(UnityProfiling.EditorProfilingEnabled, EditorApplication.isPlaying, ProfilerDriver.deepProfiling, EditorIterationProfilerIntegration.Instance.Settings.Flatten, EditorIterationProfilerIntegration.Instance.Settings.UserCode);\n\n                m_TreeView.UserCodeOnly = userCodeOnly;\n                EditorPrefs.SetBool(Styles.k_UserCodePref, m_TreeView.UserCodeOnly);\n                m_TreeView.Reload();\n            }\n\n            if (m_TreeView.Flatten != flatten)\n            {\n                EditorIterationProfilerAnalytics.SendInteractionEvent(UnityProfiling.EditorProfilingEnabled, EditorApplication.isPlaying, ProfilerDriver.deepProfiling, EditorIterationProfilerIntegration.Instance.Settings.Flatten, EditorIterationProfilerIntegration.Instance.Settings.UserCode);\n\n                m_TreeView.Flatten = flatten;\n                EditorPrefs.SetBool(Styles.k_FlattenPref, m_TreeView.Flatten);\n                m_TreeView.Reload();\n            }\n\n            DrawSearchBar();\n            GUILayout.EndHorizontal();\n        }\n\n        public static void ReportMultipleFrames(IFileDataReporter reporter, int beginRange, int endRange, string guid)\n        {\n            var exportType = ExportType.Multi;\n            if (beginRange == -1)\n            {\n                ReportSelectedFrame(reporter, beginRange, exportType, guid);\n                return;\n            }\n\n            EditorIterationProfilerAnalytics.SendExportEvent(reporter.Name, exportType.ToString(), ExportStatus.Started.ToString(), guid);\n\n            var path = EditorUtility.SaveFolderPanel($\"Export frames to folder\", \"\", reporter.Extension);\n\n            for (int i = beginRange - 1; i < endRange; ++i)\n            {\n                var list = new IterationList();\n\n                var hfdv = UnityProfiling.GetFrame(i, 0);\n                if (!hfdv.valid)\n                {\n                    hfdv = UnityProfiling.GetFrame(-1, 0);\n\n                    if (!hfdv.valid)\n                    {\n                        EditorIterationProfilerAnalytics.SendExportEvent(reporter.Name, exportType.ToString(), ExportStatus.Error.ToString(), guid);\n                        Debug.LogError($\"There was an issue getting the frame {i}\");\n                        return;\n                    }\n                }\n\n                list.NewIteration(IterationEventKind.None);\n\n                Assert.IsNotNull(list.LastIterationEventRoot);\n                list.LastIterationEventRoot.StartEvent(IterationEventKind.None);\n\n                ProfilerDataCollector.ReadProfilingData(list.LastIterationEventRoot, list.LastIterationEventRoot.FindLastEvent(IterationEventKind.None), hfdv, hfdv.GetRootItemID(), EventDataFlags.None, false);\n\n                var lastEvent = list.LastIterationEventRoot.FindLastEvent(IterationEventKind.None);\n\n                Assert.IsNotNull(lastEvent);\n\n                lastEvent.SetStartFinishTimeFromChildren();\n                lastEvent.Identifier = $\"Data (Frame {i + 1})\";\n\n                var filename = \"EditorIterationData_\" + $\"Frame{i + 1}_\" + $\"{DateTime.Now.ToString(\"MMddyyyy_HHmmss\")}\" + $\".{reporter.Extension}\";\n\n                if (path.Length != 0)\n                {\n                    reporter.Report(list, Path.Combine(path, filename));\n                }\n            }\n\n            if (path.Length != 0)\n            {\n                EditorIterationProfilerAnalytics.SendExportEvent(reporter.Name, exportType.ToString(), ExportStatus.Finished.ToString(), guid);\n            }\n        }\n\n        static void ReportSelectedFrame(IFileDataReporter reporter, int currentFrameIndex, ExportType exportType = ExportType.Selected, string guid = \"\")\n        {\n            if (string.IsNullOrEmpty(guid))\n            {\n                guid = Guid.NewGuid().ToString();\n                EditorIterationProfilerAnalytics.SendExportEvent(reporter.Name, exportType.ToString(), ExportStatus.Started.ToString(), guid);\n            }\n\n            var list = new IterationList();\n\n            var hfdv = UnityProfiling.GetFrame(currentFrameIndex, 0);\n            if (!hfdv.valid)\n            {\n                hfdv = UnityProfiling.GetFrame(-1, 0);\n\n                if (!hfdv.valid)\n                {\n                    EditorIterationProfilerAnalytics.SendExportEvent(reporter.Name, exportType.ToString(), ExportStatus.Error.ToString(), guid);\n                    Debug.LogError($\"There was an issue getting the frame {currentFrameIndex}\");\n                    return;\n                }\n            }\n\n            list.NewIteration(IterationEventKind.None);\n\n            Assert.IsNotNull(list.LastIterationEventRoot);\n            list.LastIterationEventRoot.StartEvent(IterationEventKind.None);\n\n            ProfilerDataCollector.ReadProfilingData(list.LastIterationEventRoot, list.LastIterationEventRoot.FindLastEvent(IterationEventKind.None), hfdv, hfdv.GetRootItemID(), EventDataFlags.None, false);\n\n            var lastEvent = list.LastIterationEventRoot.FindLastEvent(IterationEventKind.None);\n\n            Assert.IsNotNull(lastEvent);\n\n            lastEvent.SetStartFinishTimeFromChildren();\n            lastEvent.Identifier = $\"Data (Frame {currentFrameIndex + 1})\";\n\n            ReportExtension(reporter, list, exportType, guid);\n        }\n\n        static void ReportAllExtensions(IIterationList iterationList)\n        {\n            var guid = Guid.NewGuid().ToString();\n\n            var path = EditorUtility.SaveFolderPanel($\"Export frames to folder\", \"\", \"\");\n            var extensions = EditorIterationProfilerIntegration.Instance.DataReporterProvider.GetAllReporters<IFileDataReporter>();\n\n            foreach (var extension in extensions)\n            {\n                ReportExtension(extension, iterationList, ExportType.CapturedAll, guid, path);\n            }\n        }\n\n        static void ReportExtension(IFileDataReporter fileReporterType, IIterationList iterationList, ExportType exportType, string guid = \"\", string folderPath = \"\")\n        {\n            if (string.IsNullOrEmpty(guid))\n            {\n                guid = Guid.NewGuid().ToString();\n            }\n\n            if(ExportType.Selected != exportType)\n            {\n                EditorIterationProfilerAnalytics.SendExportEvent(fileReporterType.Name, exportType.ToString(), ExportStatus.Started.ToString(), guid);\n            }\n\n            var reporter = EditorIterationProfilerIntegration.Instance.DataReporterProvider.TryGetReporter<IFileDataReporter>(fileReporterType.GetType());\n            if (reporter == null)\n            {\n                return;\n            }\n\n            var filename = \"EditorIterationData_\" + $\"{reporter.Name.Replace(\" \", \"\")}_\" + $\"{DateTime.Now.ToString(\"MMddyyyy_HHmmss\")}\" + $\".{reporter.Extension}\";\n\n            string path;\n            if (string.IsNullOrEmpty(folderPath))\n            {\n                path = EditorUtility.SaveFilePanel($\"Export {reporter.Extension}\", \"\", filename, reporter.Extension);\n            }\n            else\n            {\n                path = Path.Combine(folderPath, filename);\n            }\n\n            if (path.Length != 0)\n            {\n                reporter.Report(iterationList, path);\n\n                EditorIterationProfilerAnalytics.SendExportEvent(reporter.Name, exportType.ToString(), ExportStatus.Finished.ToString(), guid);\n            }\n        }\n\n        void DrawSearchBar()\n        {\n            var rect = GUILayoutUtility.GetRect(50f, 300f, Styles.k_SingleLineHeight, Styles.k_SingleLineHeight, EditorStyles.toolbarSearchField);\n\n            var searchLength = m_TreeView.searchString?.Length ?? 0;\n            m_TreeView.searchString = m_SearchField.OnToolbarGUI(rect, m_TreeView.searchString);\n            if (searchLength > 0 && !m_TreeView.hasSearch)\n            {\n                m_TreeView.CollapseAll();\n                try\n                {\n                    m_TreeView.FrameItem(m_TreeView.state.lastClickedID);\n                }\n                catch (ArgumentException)\n                {\n                    m_TreeView.state.lastClickedID = -1;\n                }\n            }\n        }\n\n        void DrawTreeView()\n        {\n            var rect = GUILayoutUtility.GetRect(GUIContent.none, GUIStyle.none, GUILayout.ExpandHeight(true), GUILayout.ExpandWidth(true));\n            m_TreeView.OnGUI(rect);\n        }\n\n        void OnLostFocus()\n        {\n            EditorIterationProfilerAnalytics.SendInteractionEvent(UnityProfiling.EditorProfilingEnabled, EditorApplication.isPlaying, ProfilerDriver.deepProfiling, EditorIterationProfilerIntegration.Instance.Settings.Flatten, EditorIterationProfilerIntegration.Instance.Settings.UserCode);\n        }\n\n        void OnGUI()\n        {\n            if(!isWindowReady)\n            {\n                return;\n            }\n\n            DrawToolbar();\n\n            DrawTreeView();\n\n            UpdatePrefs();\n        }\n\n        static void InitializeButtonStateFromPrefs()\n        {\n            if (!EditorPrefs.HasKey(Styles.k_EnableProfilerPref))\n            {\n                EditorPrefs.SetBool(Styles.k_EnableProfilerPref, false);\n            }\n\n            if (!EditorPrefs.HasKey(Styles.k_UserCodePref))\n            {\n                EditorPrefs.SetBool(Styles.k_UserCodePref, false);\n            }\n\n            if (!EditorPrefs.HasKey(Styles.k_FlattenPref))\n            {\n                EditorPrefs.SetBool(Styles.k_FlattenPref, false);\n            }\n\n            if (!EditorPrefs.HasKey(Styles.k_EnableDeepProfile))\n            {\n                EditorPrefs.SetBool(Styles.k_EnableDeepProfile, false);\n            }\n\n            UnityProfiling.EditorProfilingEnabled = EditorPrefs.GetBool(Styles.k_EnableProfilerPref);\n            UnityProfiling.SetProfileDeepScripts(EditorPrefs.GetBool(Styles.k_EnableDeepProfile));\n        }\n\n        static void InitializeHeaderStateFromPrefs(MultiColumnHeaderState state)\n        {\n            int columnIndex = 0;\n            if (!EditorPrefs.HasKey(Styles.k_EventHeaderWidthSizePref))\n            {\n                EditorPrefs.SetFloat(Styles.k_EventHeaderWidthSizePref, state.columns[columnIndex++].minWidth);\n            }\n\n            if (!EditorPrefs.HasKey(Styles.k_DetailsHeaderWidthSizePref))\n            {\n                EditorPrefs.SetFloat(Styles.k_DetailsHeaderWidthSizePref, state.columns[columnIndex++].minWidth);\n            }\n\n            if (!EditorPrefs.HasKey(Styles.k_DurationHeaderWidthSizePref))\n            {\n                EditorPrefs.SetFloat(Styles.k_DurationHeaderWidthSizePref, state.columns[columnIndex].minWidth);\n            }\n\n            columnIndex = 0;\n            state.columns[columnIndex++].width = EditorPrefs.GetFloat(Styles.k_EventHeaderWidthSizePref);\n            state.columns[columnIndex++].width = EditorPrefs.GetFloat(Styles.k_DetailsHeaderWidthSizePref);\n            state.columns[columnIndex].width = EditorPrefs.GetFloat(Styles.k_DurationHeaderWidthSizePref);\n        }\n\n        void UpdatePrefs()\n        {\n            EditorPrefs.SetFloat(Styles.k_EventHeaderWidthSizePref, m_MultiColumnHeaderState.columns[0].width);\n            EditorPrefs.SetFloat(Styles.k_DetailsHeaderWidthSizePref, m_MultiColumnHeaderState.columns[1].width);\n            EditorPrefs.SetFloat(Styles.k_DurationHeaderWidthSizePref, m_MultiColumnHeaderState.columns[2].width);\n            EditorPrefs.SetBool(Styles.k_EnableProfilerPref, UnityProfiling.EditorProfilingEnabled);\n        }\n\n        [MenuItem(\"Window/Analysis/Editor Iteration Profiler/Clear Editor Preferences\", priority = 20)]\n        static void DeleteAllEIPPrefKeys()\n        {\n            if (EditorUtility.DisplayDialog(\"Delete EIP Editor Preferences\", \"Delete EIP Editor Preferences?\", \"Yes\", \"No\"))\n            {\n                EditorPrefs.DeleteKey(Styles.k_DurationHeaderWidthSizePref);\n                EditorPrefs.DeleteKey(Styles.k_DetailsHeaderWidthSizePref);\n                EditorPrefs.DeleteKey(Styles.k_EventHeaderWidthSizePref);\n                EditorPrefs.DeleteKey(Styles.k_UserCodePref);\n                EditorPrefs.DeleteKey(Styles.k_EnableDeepProfile);\n                EditorPrefs.DeleteKey(Styles.k_EnableProfilerPref);\n\n                Debug.Log(\"EIP Editor Preferences deleted\");\n            }\n        }\n    }\n\n    class ProfilerMultiFrameSelector : EditorWindow\n    {\n        public static readonly GUIContent k_RangeBeginning = EditorGUIUtility.TrTextContent(\"Range Beginning\", \"Range beginning, value is inclusive.\");\n        public static readonly GUIContent k_RangeEnd = EditorGUIUtility.TrTextContent(\"Range End\", \"Range end, value is inclusive.\");\n        public static readonly GUIContent k_WindowTitle = EditorGUIUtility.TrTextContent(\"Multi-Frame Exporter\");\n\n        IFileDataReporter m_Exporter;\n\n        int m_FirstRange = -1;\n        int m_SecondRange = -1;\n\n        string m_EventGuid;\n\n        static void OpenWindow()\n        {\n            GetWindow<ProfilerMultiFrameSelector>();\n        }\n\n        public void Initialize(IFileDataReporter exporter)\n        {\n            m_Exporter = exporter;\n\n            m_EventGuid = Guid.NewGuid().ToString();\n            EditorIterationProfilerAnalytics.SendExportEvent(exporter.Name, ExportType.MultiWindow.ToString(), ExportStatus.Started.ToString(), m_EventGuid);\n        }\n\n        public void OnDestroy()\n        {\n            EditorIterationProfilerAnalytics.SendExportEvent(m_Exporter.Name, ExportType.MultiWindow.ToString(), ExportStatus.Finished.ToString(), m_EventGuid);\n        }\n\n        void OnEnable()\n        {\n            maxSize = new Vector2(300, 125);\n            minSize = new Vector2(300, 125);\n\n            titleContent = k_WindowTitle;\n            ShowUtility();\n        }\n\n        void OnGUI()\n        {\n            m_FirstRange = EditorGUILayout.IntField(k_RangeBeginning, m_FirstRange);\n            m_SecondRange = EditorGUILayout.IntField(k_RangeEnd, m_SecondRange);\n            EditorGUILayout.HelpBox(\"Integers only. The limits are INCLUSIVE. If frame does not exist it won't be exported. -1 is the newest frame, however you can't do -1 and 15, for example; only -1 and -1.\", MessageType.Info);\n\n            if (m_FirstRange > m_SecondRange)\n            {\n                int x = m_FirstRange;\n                m_FirstRange = m_SecondRange;\n                m_SecondRange = x;\n            }\n\n            bool areValid = (m_FirstRange == m_SecondRange && m_FirstRange == -1 || m_FirstRange >= 0 && m_SecondRange >= 0);\n            EditorGUI.BeginDisabledGroup(!areValid);\n            if (GUILayout.Button(\"Export\"))\n            {\n                Debug.Log($\"Exporting Frames [{m_FirstRange},{m_SecondRange}] ({Mathf.Abs(m_SecondRange) - Mathf.Abs(m_FirstRange) + 1} frames)\");\n                EditorIterationProfilerWindow.ReportMultipleFrames(m_Exporter, m_FirstRange, m_SecondRange, m_EventGuid);\n                Close();\n            }\n\n            EditorGUI.EndDisabledGroup();\n        }\n    }\n}\n"
  },
  {
    "path": "Editor/EditorIterationProfilerWindow.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 906f7aecdbdac3e4ba9518ba48388df9\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "Editor/EventData.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing UnityEngine;\n\nnamespace UnityEditor.EditorIterationProfiler\n{\n    [Flags]\n    public enum EventDataFlags\n    {\n        None = 0,\n        UserCode = 1 << 0,\n        Flatten = 1 << 1,\n    }\n\n    [Serializable]\n    public class EventData\n    {\n        [field: NonSerialized]\n        public List<EventData> Children { get; set; } = new List<EventData>();\n\n        public int Index { get; }\n        public int ParentIndex { get; set; }\n        public string Identifier { get; set; }\n        public double StartTime { get; set; }\n        public double FinishTime { get; set; }\n        public EventDataFlags Flags { get; set; }\n        public IterationEventKind Kind { get; }\n\n        [SerializeField]\n        string m_Metadata;\n\n        public string Details => m_Metadata;\n\n        public string DisplayName\n        {\n            get\n            {\n                if (Kind == IterationEventKind.None)\n                {\n                    return $\"{Identifier}\";\n                }\n\n                string kindString = Kind.ToString();\n\n                if (kindString == Identifier)\n                {\n                    return kindString;\n                }\n\n                return $\"{kindString}: {Identifier}\";\n            }\n        }\n\n        public double Duration => FinishTime - StartTime;\n\n        static double CurrentTime\n        {\n            get\n            {\n                long timeStamp = Stopwatch.GetTimestamp() / TimeSpan.TicksPerMillisecond;\n                return timeStamp;\n            }\n        }\n\n        public EventData(IterationEventKind kind, string identifier, string metadata, int index)\n        {\n            Kind = kind;\n            Flags = EventDataFlags.None;\n            Identifier = identifier;\n            m_Metadata = metadata;\n            Index = index;\n            ParentIndex = -1;\n            StartTime = -1.0f;\n            FinishTime = -1.0f;\n        }\n\n        public EventData(string identifier, string metadata, int index, double startTime, double finishTime, EventDataFlags flags)\n        {\n            Kind = IterationEventKind.None;\n            Identifier = identifier;\n            m_Metadata = metadata;\n            Index = index;\n            ParentIndex = -1;\n            StartTime = startTime;\n            FinishTime = finishTime;\n            Flags = flags;\n        }\n\n        public void SetStartTime()\n        {\n            StartTime = CurrentTime;\n            FinishTime = StartTime;\n        }\n\n        public void Finish()\n        {\n            if (StartTime > 0.0f)\n            {\n                FinishTime = CurrentTime;\n            }\n        }\n\n        public void SetStartFinishTimeFromChildren()\n        {\n            if (Children.Count == 0)\n            {\n                return;\n            }\n\n            StartTime = Children.First().StartTime;\n            FinishTime = Children.First().FinishTime;\n\n            foreach (var child in Children)\n            {\n                StartTime = Math.Min(child.StartTime, StartTime);\n                FinishTime = Math.Max(child.FinishTime, FinishTime);\n            }\n        }\n\n        public void PostProcess(bool flatten = false)\n        {\n            if (Children.Count == 0)\n            {\n                return;\n            }\n\n            if (flatten && Children.Count == 1)\n            {\n                Flags |= EventDataFlags.Flatten;\n            }\n\n            foreach (var child in Children)\n            {\n                child.PostProcess(Children.Count == 1);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Editor/EventData.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 7ffe19a10dc4360459985d005f84ceab\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "Editor/Formatters/Aggregator.cs",
    "content": "﻿using System;\nusing System.Text;\nusing System.Text.RegularExpressions;\nusing static System.Double;\n\nnamespace UnityEditor.EditorIterationProfiler.Formatting\n{\n    public class Aggregator\n    {\n        public string Name { get; private set; }\n        public double Time { get; private set; }\n        public double TotalTime { get; private set; }\n        public Regex Pattern { get; private set; }\n        public int Depth { get; private set; }\n        public int Calls { get; private set; }\n        public bool IsRoot => !string.IsNullOrEmpty(Name) && m_Sb.Length != 0;\n        public double Percentage => (Math.Abs(TotalTime) < Epsilon || Math.Abs(Time) < Epsilon) ? 0 : Time / TotalTime * 100;\n\n        StringBuilder m_Sb;\n\n        public Aggregator(int depth, string name, Regex pattern)\n        {\n            m_Sb = new StringBuilder();\n\n            Time = 0;\n            TotalTime = 0;\n            Calls = 0;\n            Name = name;\n            Depth = depth;\n            Pattern = pattern;\n        }\n\n        public void Aggregate(string s, bool isCall = false)\n        {\n            m_Sb.Append(s);\n\n            if (isCall)\n            {\n                ++Calls;\n            }\n        }\n\n        public void Aggregate(double time)\n        {\n            ++Calls;\n            Time += time;\n        }\n\n        public void Aggregate(string s, double time)\n        {\n            Aggregate(s);\n            Aggregate(time);\n        }\n\n        public void Reset()\n        {\n            Calls = 0;\n            m_Sb.Clear();\n            Time = 0;\n            TotalTime = 0;\n        }\n\n        public void Reset(double totalTime)\n        {\n            Calls = 0;\n            m_Sb.Clear();\n            Time = 0;\n            TotalTime = totalTime;\n        }\n\n        public override string ToString()\n        {\n            return m_Sb.ToString();\n        }\n    }\n\n    public class HTMLAggregator : Aggregator\n    {\n        public string Style { get; private set;}\n\n        public HTMLAggregator(int depth, string name, Regex pattern, string style) : base(depth, name, pattern)\n        {\n            Style = style;\n        }\n    }\n}\n"
  },
  {
    "path": "Editor/Formatters/Aggregator.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 25551dbb66e6c084ab84c7a8e6cfc2e2\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "Editor/Formatters/DataReporterProvider.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing UnityEditor.EditorIterationProfiler.Formatting;\nusing UnityEngine.Assertions;\n\nnamespace UnityEditor.EditorIterationProfiler\n{\n    public interface IDataReporterProvider\n    {\n        IList<T> GetAllReporters<T>() where T : IDataReporter;\n        T TryGetReporter<T>(Type type) where T : IDataReporter;\n        bool IsFileExtensionSupported(string extension);\n        IDataReporter TryGetDataReporter(string typeName);\n        IFileDataReporter TryGetDataFileReporter(string typeName);\n    }\n\n    public class DataReporterProvider : IDataReporterProvider\n    {\n        HashSet<IDataReporter> m_DataReporters;\n        HashSet<IFileDataReporter> m_DataFileReporters;\n\n        public DataReporterProvider()\n        {\n            InitializeDataFileReporters();\n\n            InitializeDataReporters();\n        }\n\n        void InitializeDataFileReporters()\n        {\n            m_DataFileReporters = new HashSet<IFileDataReporter>();\n\n            foreach (var rep in TypeCache.GetTypesDerivedFrom(typeof(IFileDataReporter)))\n            {\n                if (rep.GetConstructors().Length > 0)\n                {\n                    var instance = (IFileDataReporter)Activator.CreateInstance(rep);\n\n                    var processedExtension = SanitizeExtension(instance.Extension);\n\n                    if (processedExtension != instance.Extension)\n                    {\n                        throw new ArgumentException($\"Extension must be lowercase characters only ({rep})\");\n                    }\n                    else\n                    {\n                        m_DataFileReporters.Add(instance);\n                    }\n                }\n            }\n        }\n\n        void InitializeDataReporters()\n        {\n            m_DataReporters = new HashSet<IDataReporter>();\n\n            foreach (var rep in TypeCache.GetTypesDerivedFrom(typeof(IDataReporter)))\n            {\n                if (rep.GetConstructors().Length > 0)\n                {\n                    var instance = (IDataReporter)Activator.CreateInstance(rep);\n\n                    if (!(instance is FileReporter))\n                    {\n                        m_DataReporters.Add(instance);\n                    }\n                }\n            }\n        }\n\n        public IList<T> GetAllReporters<T>() where T : IDataReporter\n        {\n            if (typeof(T) == typeof(IDataReporter))\n            {\n                return (IList<T>)m_DataReporters.ToList();\n            }\n\n            if (typeof(T) == typeof(IFileDataReporter))\n            {\n                return (IList<T>)m_DataFileReporters.ToList();\n            }\n\n            return default;\n        }\n\n        public T TryGetReporter<T>(Type type) where T : IDataReporter\n        {\n            if (typeof(T) == typeof(IDataReporter))\n            {\n                return (T)m_DataReporters.FirstOrDefault(x => x.GetType() == type);\n            }\n\n            if (typeof(T) == typeof(IFileDataReporter))\n            {\n                return (T)m_DataFileReporters.FirstOrDefault(x => x.GetType() == type);\n            }\n\n            return default;\n        }\n\n        public IDataReporter TryGetDataReporter(string typeName)\n        {\n            return m_DataReporters.FirstOrDefault(reporter => reporter.GetType().Name == typeName);\n        }\n\n        public IFileDataReporter TryGetDataFileReporter(string typeName)\n        {\n            return m_DataFileReporters.FirstOrDefault(reporter => reporter.GetType().Name == typeName);\n        }\n\n        public bool IsFileExtensionSupported(string extension)\n        {\n            return m_DataFileReporters.Any(reporter => reporter.Extension == SanitizeExtension(extension));\n        }\n\n        static string SanitizeExtension(string extension)\n        {\n            Assert.IsNotNull(extension, \"Extension cannot be null\");\n\n            if (extension.StartsWith(\".\"))\n            {\n                return extension.Substring(1);\n            }\n\n            extension = extension.ToLower();\n\n            return extension;\n        }\n    }\n}\n"
  },
  {
    "path": "Editor/Formatters/DataReporterProvider.cs.meta",
    "content": "fileFormatVersion: 2\nguid: ff2c9a40c83aa784bb9b3ff6047ee281\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "Editor/Formatters/DataReporters.cs",
    "content": "﻿namespace UnityEditor.EditorIterationProfiler.Formatting\n{\n    public interface IDataReporter\n    {\n        string GetFormatString(in IIterationList iterationList);\n        void Report(in IIterationList iterationList, string path = null);\n    }\n\n    public interface IFileDataReporter : IDataReporter\n    {\n        string Extension { get; }\n        string Name { get; }\n        new void Report(in IIterationList iterationList, string path);\n    }\n}\n"
  },
  {
    "path": "Editor/Formatters/DataReporters.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 81edb0b5aa41ccd48ad73a8a21e67758\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "Editor/Formatters/FileReporter.cs",
    "content": "﻿using System;\nusing System.IO;\nusing UnityEngine;\n\nnamespace UnityEditor.EditorIterationProfiler.Formatting\n{\n    public abstract class FileReporter : Formatter, IFileDataReporter\n    {\n        string m_Extension = null;\n        public virtual string Extension => m_Extension;\n\n        string m_Name = null;\n        public virtual string Name => m_Name;\n\n        public virtual void Report(in IIterationList iterationList, string path)\n        {\n            ReportToFile(GetFormatString(iterationList), path);\n        }\n\n        protected virtual void ReportToFile(string message, string path)\n        {\n            if (path == null)\n            {\n                throw new ArgumentNullException(nameof(path), \"Path cannot be null\");\n            }\n\n            File.WriteAllText(path, message);\n\n            Debug.Log($\"\\\"{path}\\\" exported!\");\n        }\n\n        public abstract override string ToString();\n    }\n}\n"
  },
  {
    "path": "Editor/Formatters/FileReporter.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 9d728ac882039e643be468b5db8f65b9\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "Editor/Formatters/Formatter.cs",
    "content": "﻿using System;\nusing System.Text;\nusing static System.FormattableString;\n\nnamespace UnityEditor.EditorIterationProfiler.Formatting\n{\n    public abstract class Formatter\n    {\n        public virtual string GetFormatString(in IIterationList iterationList)\n        {\n            var finalStringBuilder = GetPrefixStringBuilder(iterationList).Append(GetMainStringBuilder(iterationList).Append(GetPostfixStringBuilder(iterationList)));\n\n            return finalStringBuilder.ToString();\n        }\n\n        protected virtual StringBuilder GetPrefixStringBuilder(in IIterationList iterationList = null)\n        {\n            return new StringBuilder();\n        }\n\n        protected virtual StringBuilder GetMainStringBuilder(in IIterationList iterationList)\n        {\n            var sb = new StringBuilder();\n\n            if (iterationList.IterationEventRoots.Count > 0)\n            {\n                RecursiveIterationList(iterationList, ref sb);\n            }\n\n            return sb;\n        }\n\n        protected virtual StringBuilder GetPostfixStringBuilder(in IIterationList iterationList = null)\n        {\n            return new StringBuilder();\n        }\n\n        protected virtual void RecursiveIterationList(in IIterationList iterationList, ref StringBuilder sb, params object[] parameters)\n        {\n            if (iterationList.IterationEventRoots.Count == 0)\n            {\n                return;\n            }\n\n            for (int i = 0; i < iterationList.IterationEventRoots.Count; ++i)\n            {\n                RecursiveIterationEventRoot(iterationList.IterationEventRoots[i], ref sb, 1, parameters);\n            }\n        }\n\n        protected virtual void RecursiveIterationEventRoot(in IterationEventRoot iterationEventRoot, ref StringBuilder sb, params object[] parameters)\n        {\n            foreach (var ed in iterationEventRoot.Events)\n            {\n                if (ed.ParentIndex < 0)\n                {\n                    RecursiveEventData(ed, iterationEventRoot, ref sb, parameters);\n                }\n            }\n        }\n\n        protected virtual void RecursiveEventData(in EventData ed, in IterationEventRoot iterationEventRoot, ref StringBuilder sb, params object[] parameters)\n        {\n            RecursiveEventDataWalker(in ed, in iterationEventRoot, ref sb, parameters);\n        }\n\n        protected virtual void RecursiveEventDataWalker(in EventData ed, in IterationEventRoot iterationEventRoot, ref StringBuilder sb, params object[] parameters)\n        {\n            if (ed.Children == null || ed.Children.Count == 0)\n            {\n                return;\n            }\n\n            foreach (var child in ed.Children)\n            {\n                var newParameters = new object[parameters.Length];\n                Array.Copy(parameters, newParameters, parameters.Length);\n                newParameters[0] = (int)newParameters[0] + 1;\n\n                RecursiveEventData(child, iterationEventRoot, ref sb, newParameters);\n            }\n        }\n\n        public static string ToTimeString(double time)\n        {\n            return Invariant($\"{time:0.000} ms\");\n        }\n\n        public static string ToPercentageString(double percentage)\n        {\n            return Invariant($\"{percentage:0.00}%\");\n        }\n    }\n}\n"
  },
  {
    "path": "Editor/Formatters/Formatter.cs.meta",
    "content": "fileFormatVersion: 2\nguid: ac320eeadb74a314986b94329a9f324b\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "Editor/Formatters/IndentationProvider.cs",
    "content": "﻿using System.Collections;\nusing System.Collections.Generic;\nusing UnityEngine;\n\nnamespace UnityEditor.EditorIterationProfiler.Formatting\n{\n    public static class IndentationProvider\n    {\n        static Dictionary<int, string> m_Cache = new Dictionary<int, string>(32);\n        const char k_IndentationChar = '\\t';\n\n        public static string Get(int count)\n        {\n            if (count < 1)\n            {\n                return string.Empty;\n            }\n            if (!m_Cache.ContainsKey(count))\n            {\n                m_Cache.Add(count, new string(k_IndentationChar, count));\n            }\n            return m_Cache[count];\n        }\n    }\n}\n"
  },
  {
    "path": "Editor/Formatters/IndentationProvider.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 3b0423ed7f3314147a6125b4bca1b837\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "Editor/Formatters/Reporters/CSVReporter.cs",
    "content": "﻿using System.Text;\n\nnamespace UnityEditor.EditorIterationProfiler.Formatting\n{\n    sealed class CSVReporter : FileReporter\n    {\n        string m_Extension = \"csv\";\n        public override string Extension => m_Extension;\n        \n        string m_Name = \"CSV\";\n        public override string Name => m_Name;\n\n        protected override StringBuilder GetPrefixStringBuilder(in IIterationList iterationList = null)\n        {\n            var sb = new StringBuilder();\n\n           sb.AppendLine($\"{EditorIterationProfilerIntegration.Instance.Settings}\");\n           sb.AppendLine();\n\n            return sb;\n        }\n\n        protected override void RecursiveIterationList(in IIterationList iterationList, ref StringBuilder sb, params object[] parameters)\n        {\n           sb.AppendLine($\"Iteration ID,NodeType,Name,Details,Duration (ms)\");\n\n            for (int i = 0; i < iterationList.IterationEventRoots.Count; ++i)\n            {\n                RecursiveIterationEventRoot(iterationList.IterationEventRoots[i], ref sb, 1);\n            }\n        }\n\n        protected override void RecursiveEventData(in EventData ed, in IterationEventRoot parent, ref StringBuilder sb, params object[] parameters)\n        {\n            if (ed.Children.Count == 0)\n            {\n               sb.AppendLine($\"{parent.IterationIndex + 1} ({parent.IterationEventKind}), Leaf, {ed.Identifier}, {ed.Details}, {ed.Duration:0.000}\");\n            }\n            else\n            {\n               sb.AppendLine($\"{parent.IterationIndex + 1} ({parent.IterationEventKind}), Parent, {ed.Identifier}, {ed.Details}, {ed.Duration:0.000}\");\n            }\n\n            RecursiveEventDataWalker(in ed, in parent, ref sb, parameters);\n        }\n\n        public override string ToString()\n        {\n            return GetType().Name;\n        }\n    }\n}\n"
  },
  {
    "path": "Editor/Formatters/Reporters/CSVReporter.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 6b8bb4034b7400549b745b3ae7c02f4c\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "Editor/Formatters/Reporters/ChromeTracingReporter.cs",
    "content": "﻿using System;\nusing System.Text;\nusing static System.FormattableString;\n\nnamespace UnityEditor.EditorIterationProfiler.Formatting\n{\n    sealed class ChromeTracingReporter : FileReporter\n    {\n        string m_Extension = \"json\";\n        public override string Extension => m_Extension;\n\n        string m_Name = \"JSON for Chrometrace\";\n        public override string Name => m_Name;\n\n        double m_ParentTotalDuration;\n\n        protected override StringBuilder GetPrefixStringBuilder(in IIterationList iterationList = null)\n        {\n            var sb = new StringBuilder(32);\n\n            sb.AppendLine(\"{\");\n\n            sb.AppendLine(\"\\\"otherData\\\": {\");\n            sb.AppendLine($\"\\\"Readme\\\": \\\"Data serialized for use with Chrome Tracing. Load this file into chrome://tracing/ \\\",\");\n            sb.AppendLine($\"\\\"Data\\\": \\\"{EditorIterationProfilerIntegration.Instance.Settings.ToString().Replace(Environment.NewLine, \"; \")}\\\"\");\n            sb.AppendLine(\"},\");\n\n            sb.AppendLine(\"\\\"traceEvents\\\": [\");\n\n            return sb;\n        }\n\n        protected override StringBuilder GetMainStringBuilder(in IIterationList iterationList)\n        {\n            var sb = new StringBuilder();\n\n            if (iterationList.IterationEventRoots.Count > 0)\n            {\n                RecursiveIterationList(iterationList, ref sb);\n\n                // Remove the last comma\n                for (int i = sb.Length - 1; i > 0; --i)\n                {\n                    if (sb[i] == ',')\n                    {\n                        sb.Remove(i, 1);\n                        break;\n                    }\n                }\n            }\n\n            return sb;\n        }\n\n        protected override StringBuilder GetPostfixStringBuilder(in IIterationList iterationList = null)\n        {\n            var sb = new StringBuilder(4);\n\n            sb.AppendLine(\"]\");\n            sb.AppendLine(\"}\");\n\n            return sb;\n        }\n\n        protected override void RecursiveIterationEventRoot(in IterationEventRoot iterationEventRoot, ref StringBuilder sb, params object[] parameters)\n        {\n            double totalDuration = 0;\n\n            foreach (var ed in iterationEventRoot.Events)\n            {\n                if (ed.ParentIndex < 0 && ed.Duration > 0)\n                {\n                    totalDuration += ed.Duration;\n                }\n            }\n\n            m_ParentTotalDuration = totalDuration;\n\n            sb.AppendLine(MetadataEvent(\"process_name\", (iterationEventRoot.IterationIndex + 1).ToString(), \"1\", $\"Iteration {iterationEventRoot.IterationIndex + 1} ({iterationEventRoot.IterationEventKind.ToString()}) ({totalDuration:0.000}ms) \"));\n\n            foreach (var ed in iterationEventRoot.Events)\n            {\n                if (ed.ParentIndex < 0)\n                {\n                    RecursiveEventData(ed, iterationEventRoot, ref sb, ed.StartTime, parameters);\n                }\n            }\n        }\n\n        void RecursiveEventData(in EventData ed, in IterationEventRoot iterationEventRoot, ref StringBuilder sb, double parentStartTime, params object[] parameters)\n        {\n            if (ed.Duration > float.Epsilon)\n            {\n                sb.AppendLine(DurationEvent(ed.Identifier, (iterationEventRoot.IterationIndex + 1).ToString(), \"1\", iterationEventRoot.IterationEventKind.ToString(), ed.StartTime - parentStartTime, ed.Duration));\n            }\n\n            RecursiveEventDataWalker(in ed, in iterationEventRoot, ref sb, parentStartTime, parameters);\n        }\n\n        void RecursiveEventDataWalker(in EventData ed, in IterationEventRoot iterationEventRoot, ref StringBuilder sb, double parentStartTime, params object[] parameters)\n        {\n            if (ed.Children == null || ed.Children.Count == 0)\n            {\n                return;\n            }\n\n            foreach (var child in ed.Children)\n            {\n                var newParameters = new object[parameters.Length];\n                Array.Copy(parameters, newParameters, parameters.Length);\n                newParameters[0] = (int)newParameters[0] + 1;\n\n                RecursiveEventData(child, iterationEventRoot, ref sb, parentStartTime, newParameters);\n            }\n        }\n\n        string DurationEvent(string identifier, string pid, string tid, string category, double startTime, double duration)\n        {\n            return Invariant($\"{{ \\\"pid\\\": {pid}, \\\"tid\\\": {tid}, \\\"ph\\\": \\\"X\\\", \\\"name\\\": \\\"{identifier}\\\", \\\"cat\\\": \\\"{category}\\\", \\\"ts\\\": {startTime * 1000.0:0.000}, \\\"dur\\\": {duration * 1000}, \\\"args\\\": {{ \\\"Duration (ms)\\\": {duration:0.000}, \\\"Start Time (ms)\\\": {startTime:0.000}, \\\"Percentage of total\\\": {(duration / m_ParentTotalDuration * 100.0):0.000} }} }},\");\n        }\n\n        static string MetadataEvent(string identifier, string pid, string tid, string name)\n        {\n            return $\"{{ \\\"pid\\\": {pid}, \\\"tid\\\": {tid}, \\\"ph\\\": \\\"M\\\", \\\"name\\\": \\\"{identifier}\\\", \\\"args\\\": {{ \\\"name\\\": \\\"{name}\\\" }} }},\";\n        }\n\n        public override string ToString()\n        {\n            return GetType().Name;\n        }\n    }\n}\n"
  },
  {
    "path": "Editor/Formatters/Reporters/ChromeTracingReporter.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 72b0e40bb4a14f3478fcab6254a33ddf\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "Editor/Formatters/Reporters/EditorLogReporter.cs",
    "content": "﻿using System.Text;\nusing UnityEngine;\n\nnamespace UnityEditor.EditorIterationProfiler.Formatting\n{\n    public class EditorLogReporter : Formatter, IDataReporter\n    {\n        protected override StringBuilder GetPrefixStringBuilder(in IIterationList iterationList = null)\n        {\n            var sb = new StringBuilder();\n\n            sb.AppendLine($\"{EditorIterationProfilerIntegration.Instance.Settings}\");\n            sb.AppendLine();\n\n            return sb;\n        }\n\n        protected override void RecursiveIterationEventRoot(in IterationEventRoot iterationEventRoot, ref StringBuilder sb, params object[] parameters)\n        {\n            double totalDuration = 0;\n            foreach (var ed in iterationEventRoot.Events)\n            {\n                if (ed.ParentIndex < 0 && ed.Duration > 0)\n                {\n                    totalDuration += ed.Duration;\n                }\n            }\n\n            sb.AppendLine($\"Iteration {iterationEventRoot.IterationIndex + 1} ({iterationEventRoot.IterationEventKind}) [{totalDuration:0.000} ms]\");\n\n            foreach (var ed in iterationEventRoot.Events)\n            {\n                if (ed.ParentIndex < 0)\n                {\n                    RecursiveEventData(ed, iterationEventRoot, ref sb, parameters);\n                }\n            }\n        }\n\n        protected override void RecursiveEventData(in EventData ed, in IterationEventRoot parent, ref StringBuilder sb, params object[] parameters)\n        {\n            var indentation = new string('\\t', (int)parameters[0]);\n\n            sb.AppendLine($\"{indentation}{ed.Identifier} ({ed.Duration:0.000} ms; {ed.Details})\");\n\n            RecursiveEventDataWalker(in ed, in parent, ref sb, parameters);\n        }\n\n        public void Report(in IIterationList iterationList, string path = null)\n        {\n            var message = GetFormatString(iterationList);\n\n            Debug.Log(message);\n        }\n    }\n}\n"
  },
  {
    "path": "Editor/Formatters/Reporters/EditorLogReporter.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 5699fdd33406e234598169fc247e67e6\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "Editor/Formatters/Reporters/HTMLPerfReport.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Text.RegularExpressions;\nusing UnityEditor.EditorIterationProfiler.Formatting;\nusing UnityEngine;\n\nnamespace UnityEditor.EditorIterationProfiler\n{\n    public class HTMLPerfReporter : FileReporter\n    {\n        string m_Extension = \"html\";\n        public override string Extension => m_Extension;\n\n        string m_Name = \"HTML Performance Report\";\n        public override string Name => m_Name;\n\n        // [0-100] percentage. Determines when the children of the current node will stop being logged. If the Parent is under this percentage, only the direct children of it will be printed. After that it stops.\n        const double k_PrunePercentage = 1;\n\n        // [0-100] percentage. Determines what is considered as a divergence in times. This is used to 'flatten' the structure. 1 will basically turn it 'off'.\n        const double k_DivergenceFactor = 75;\n\n        IList<HTMLAggregator> m_Aggregators = new List<HTMLAggregator>();\n\n        double m_ParentTotalDuration;\n\n        public HTMLPerfReporter()\n        {\n            m_Aggregators.Add(new HTMLAggregator(1, \"Garbage Collector\", new Regex(@\"GC\\.C\"), \"color:#F00\"));\n            m_Aggregators.Add(new HTMLAggregator(1, \"Mono.JIT\", new Regex(\"Mono.JIT\"), \"color:#FA1\"));\n            m_Aggregators.Add(new HTMLAggregator(1, \"[MISSING MARKER TIME]\", new Regex(\"MISSING MARKER TIME\"), \"color:#B54\"));\n            m_Aggregators.Add(new HTMLAggregator(1, \"EIP Time\", new Regex(@\"EditorIterationProfiler\"), \"color:#3A7\"));\n            m_Aggregators.Add(new HTMLAggregator(1, \"Object Stuff\", new Regex(@\"Object\\.\"), \"color:#1C7\"));\n            m_Aggregators.Add(new HTMLAggregator(1, \"OnEnable & Awake Stuff\", new Regex(@\"\\.Awake|\\.OnEnable\"), \"color:#17C\"));\n            m_Aggregators.Add(new HTMLAggregator(1, \"UnityEditor Stuff\", new Regex(@\"UnityEditor\\.\"), \"color:#52F\"));\n            m_Aggregators.Add(new HTMLAggregator(1, \"UnityEngine Stuff\", new Regex(@\"UnityEngine\\.\"), \"color:#81B\"));\n            m_Aggregators.Add(new HTMLAggregator(1, \"GUI Stuff\", new Regex(@\"GUI\"), \"color:#C0F\"));\n        }\n\n        public override string GetFormatString(in IIterationList iterationList)\n        {\n            var finalStringBuilder = GetPrefixStringBuilder(iterationList).Append(GetMainStringBuilder(iterationList).Append(GetPostfixStringBuilder(iterationList)));\n\n            return finalStringBuilder.ToString();\n        }\n\n        protected override StringBuilder GetPrefixStringBuilder(in IIterationList iterationList = null)\n        {\n            var sb = new StringBuilder();\n\n            var fileGUID = AssetDatabase.FindAssets(\"HTMLReporterPrefix\").FirstOrDefault();\n            var filePath = AssetDatabase.GUIDToAssetPath(fileGUID);\n            var file = AssetDatabase.LoadAssetAtPath<TextAsset>(filePath);\n            sb.Append(file.text);\n\n            sb.AppendLine($\"<div class=\\\"Details Wordwrap\\\">{EditorIterationProfilerIntegration.Instance.Settings}</div>\");\n\n            sb.AppendLine($\"<br>\");\n            sb.AppendLine();\n\n            sb.AppendLine($\"<body>\");\n            sb.AppendLine($\"<div class=\\\"ToggleButton\\\" onclick=\\\"treeViewToggleAll(true);\\\">Expand all</div>\");\n            sb.AppendLine($\"<div class=\\\"ToggleButton\\\" onclick=\\\"treeViewToggleAll(false);\\\">Collapse all</div>\");\n\n            return sb;\n        }\n\n        protected override StringBuilder GetMainStringBuilder(in IIterationList iterationList)\n        {\n            var sb = new StringBuilder();\n\n            if (iterationList.IterationEventRoots.Count > 0)\n            {\n                RecursiveIterationList(iterationList, ref sb);\n            }\n            else\n            {\n                sb.AppendLine($\"<div>ERROR: No data to export!</div>\");\n            }\n\n            return sb;\n        }\n\n        protected void RecursiveIterationList(in IIterationList iterationList, ref StringBuilder sb)\n        {\n            if (iterationList.IterationEventRoots.Count == 0)\n            {\n                return;\n            }\n\n            for (int i = 0; i < iterationList.IterationEventRoots.Count; ++i)\n            {\n                RecursiveIterationEventRoot(iterationList.IterationEventRoots[i], ref sb);\n            }\n        }\n\n        protected void RecursiveIterationEventRoot(in IterationEventRoot iterationEventRoot, ref StringBuilder sb)\n        {\n            double totalDuration = 0;\n\n            foreach (var ed in iterationEventRoot.Events)\n            {\n                if (ed.ParentIndex < 0 && ed.Duration > 0)\n                {\n                    totalDuration += ed.Duration;\n                }\n            }\n\n            m_ParentTotalDuration = totalDuration;\n\n            foreach (var agg in m_Aggregators)\n            {\n                agg.Reset(totalDuration);\n            }\n\n\n            var foundRoot = new List<bool>(m_Aggregators.Count);\n\n            for (int i = 0; i < foundRoot.Capacity; ++i)\n            {\n                foundRoot.Add(false);\n            }\n\n\n            var indentation1 = IndentationProvider.Get(1);\n\n            sb.AppendLine($\"<div class=\\\"TreeViewItem TreeViewItemCollapsed\\\">\");\n            sb.AppendLine(TimeDisplay(1, totalDuration));\n            sb.AppendLine(PercentageDisplay(1, 100));\n            sb.AppendLine($\"{indentation1}<div class=\\\"NameDisplay\\\" onclick=\\\"treeViewToggle(event);\\\">Iteration {iterationEventRoot.IterationIndex + 1} ({iterationEventRoot.IterationEventKind})</div>\");\n\n            foreach (var ed in iterationEventRoot.Events)\n            {\n                if (ed.ParentIndex < 0)\n                {\n                    RecursiveEventData(ed, iterationEventRoot, ref sb, 1, 100, foundRoot);\n\n                    sb.AppendLine($\"{indentation1}</div>\");\n                }\n            }\n\n            sb.AppendLine(AggregateDataToString());\n\n            sb.AppendLine($\"</div>\");\n        }\n\n        protected void RecursiveEventData(in EventData ed, in IterationEventRoot parent, ref StringBuilder sb, int depth, double parentPercentage, List<bool> foundRoot)\n        {\n            var indentation1 = IndentationProvider.Get(depth);\n            var indentation2 = IndentationProvider.Get(depth + 1);\n            double percentage = ed.Duration / m_ParentTotalDuration * 100;\n\n            var currentFoundRoot = new List<bool>(foundRoot);\n\n            AggregateEventData(ed, percentage, ref currentFoundRoot);\n\n            if (parentPercentage * k_DivergenceFactor / 100 < percentage && ed.Children.Count != 0 && depth > 1 && percentage > 1)\n            {\n                RecursiveEventDataWalker(in ed, in parent, ref sb, depth, percentage, currentFoundRoot);\n                return;\n            }\n\n            bool nodeWasWritten = false;\n\n            if (percentage >= k_PrunePercentage)\n            {\n                if (ed.Children.Count > 0)\n                {\n                    sb.AppendLine($\"{indentation1}<div class=\\\"TreeViewItem TreeViewItemCollapsed\\\">\");\n                    sb.AppendLine(TimeDisplay(depth + 1, ed.Duration));\n                    sb.AppendLine(PercentageDisplay(depth + 1, percentage));\n                    sb.AppendLine($\"{indentation2}<div class=\\\"NameDisplay\\\" onclick=\\\"treeViewToggle(event);\\\">{ed.Identifier}</div>\");\n\n                    double childrenTime = 0;\n                    foreach (var child in ed.Children)\n                    {\n                        childrenTime += child.Duration;\n                    }\n\n                    var ag = FindAggregator(\"MISSING MARKER TIME\");\n                    if (ag != null)\n                    {\n                        if(ed.Duration > childrenTime)\n                        {\n                            ag.Aggregate(ed.Duration - childrenTime);\n                        }\n                    }\n                }\n                else\n                {\n                    sb.AppendLine($\"{indentation1}<div class=\\\"TreeViewItem TreeViewItemLeaf\\\">\");\n                    sb.AppendLine(TimeDisplay(depth + 1, ed.Duration));\n                    sb.AppendLine(PercentageDisplay(depth + 1, percentage));\n\n                    if (!string.IsNullOrEmpty(ed.Details))\n                    {\n                        sb.AppendLine(SimpleLabel(depth + 1, $\"[{ed.Identifier}] ({ed.Details})\"));\n                    }\n                    else\n                    {\n                        sb.AppendLine(SimpleLabel(depth + 1, $\"[{ed.Identifier}]\"));\n                    }\n                }\n\n                nodeWasWritten = true;\n            }\n            else if (parentPercentage >= k_PrunePercentage && percentage < k_PrunePercentage)\n            {\n                sb.AppendLine($\"{indentation1}<div class=\\\"TreeViewItem TreeViewItemLeaf\\\">\");\n                sb.AppendLine(TimeDisplay(depth + 1, ed.Duration));\n                sb.AppendLine(PercentageDisplay(depth + 1, percentage));\n\n                if (!string.IsNullOrEmpty(ed.Details))\n                {\n                    if (ed.Children.Count == 0)\n                    {\n                        sb.AppendLine(SimpleLabel(depth + 1, $\"[{ed.Identifier}] ({ed.Details})\"));\n                    }\n                    else\n                    {\n                        sb.AppendLine(SimpleLabel(depth + 1, $\"{{{ed.Identifier}}} ({ed.Details})\"));\n                    }\n                }\n                else\n                {\n                    if (ed.Children.Count == 0)\n                    {\n                        sb.AppendLine(SimpleLabel(depth + 1, $\"[{ed.Identifier}]\"));\n                    }\n                    else\n                    {\n                        sb.AppendLine(SimpleLabel(depth + 1, $\"{{{ed.Identifier}}}\"));\n                    }\n                }\n\n                nodeWasWritten = true;\n            }\n\n            RecursiveEventDataWalker(in ed, in parent, ref sb, depth, percentage, currentFoundRoot);\n\n            if (nodeWasWritten && depth != 1)\n            {\n                sb.AppendLine($\"{indentation1}</div>\");\n            }\n        }\n\n        protected void RecursiveEventDataWalker(in EventData ed, in IterationEventRoot iterationEventRoot, ref StringBuilder sb, int depth, double percentage, List<bool> foundRoot)\n        {\n            if (ed.Children == null || ed.Children.Count == 0)\n            {\n                return;\n            }\n\n            foreach (var child in ed.Children)\n            {\n                RecursiveEventData(child, iterationEventRoot, ref sb, depth + 1, percentage, foundRoot);\n            }\n        }\n\n        protected static string TimeDisplay(int depth, double time)\n        {\n            return $\"{IndentationProvider.Get(depth)}<div class=\\\"TimeDisplay\\\">{ToTimeString(time)}</div>\";\n        }\n\n        protected static string PercentageDisplay(int depth, double percentage)\n        {\n            return $\"{IndentationProvider.Get(depth)}<div class=\\\"PercentageDisplay\\\">{ToPercentageString(percentage)}</div>\";\n        }\n\n        protected static string SimpleLabel(int depth, string s, string style = \"\")\n        {\n            if (!string.IsNullOrEmpty(style))\n            {\n                return $\"{IndentationProvider.Get(depth)}<div style=\\\"{style}\\\">{s}</div>\";\n            }\n\n            return $\"{IndentationProvider.Get(depth)}<div>{s}</div>\";\n        }\n\n        protected void AggregateEventData(EventData ed, double percentage, ref List<bool> foundRoot)\n        {\n            for (int i = 0; i < m_Aggregators.Count; ++i)\n            {\n                var agg = m_Aggregators[i];\n\n                if (agg.Pattern.IsMatch(ed.Identifier) && !foundRoot[i])\n                {\n                    agg.Aggregate(TimeDisplay(agg.Depth + 1, ed.Duration) + Environment.NewLine, ed.Duration);\n                    agg.Aggregate(PercentageDisplay(agg.Depth + 1, percentage) + Environment.NewLine);\n                    agg.Aggregate(SimpleLabel(agg.Depth + 1, ed.Identifier + (string.IsNullOrEmpty(ed.Details) ? \"\" : $\" ({ed.Details})\"), agg.Style) + Environment.NewLine);\n                    foundRoot[i] = true;\n                }\n            }\n        }\n\n        protected void AggregateData(string name, double time)\n        {\n            foreach (var agg in m_Aggregators)\n            {\n                if (agg.Pattern.IsMatch(name))\n                {\n                    agg.Aggregate(time);\n                }\n            }\n        }\n\n        protected string AggregateDataToString()\n        {\n            var sb = new StringBuilder();\n\n            foreach (var agg in m_Aggregators)\n            {\n                sb.Append(AggregatorLabel(agg));\n            }\n\n            return sb.ToString();\n        }\n\n        protected HTMLAggregator FindAggregator(string name)\n        {\n            return m_Aggregators.FirstOrDefault(x => x.Pattern.IsMatch(name));\n        }\n\n        protected static StringBuilder AggregatorLabel(HTMLAggregator ag)\n        {\n            var sb = new StringBuilder();\n            string indentation = IndentationProvider.Get(ag.Depth);\n\n            if (ag.IsRoot)\n            {\n                sb.AppendLine($\"{indentation}<div class=\\\"TreeViewItem TreeViewItemCollapsed\\\">\");\n                sb.AppendLine($\"{indentation}<div class=\\\"TimeDisplay\\\">{ToTimeString(ag.Time)}</div>\");\n                sb.AppendLine($\"{indentation}<div class=\\\"PercentageDisplay\\\">{ToPercentageString(ag.Percentage)}</div>\");\n                sb.AppendLine($\"{indentation}<div style=\\\"{ag.Style}\\\" onclick=\\\"treeViewToggle(event);\\\" class=\\\"NameDisplay\\\">{ag.Name} (Found Instances: {ag.Calls})</div>\");\n                sb.AppendLine($\"{indentation}<div class=\\\"TreeViewItem TreeViewItemLeaf\\\">\");\n                sb.AppendLine(ag.ToString());\n                sb.AppendLine($\"{indentation}</div>\");\n            }\n            else\n            {\n                sb.AppendLine($\"{indentation}<div class=\\\"TreeViewItem TreeViewItemLeaf\\\">\");\n                sb.AppendLine($\"{indentation}<div class=\\\"TimeDisplay\\\">{ToTimeString(ag.Time)}</div>\");\n                sb.AppendLine($\"{indentation}<div class=\\\"PercentageDisplay\\\">{ToPercentageString(ag.Percentage)}</div>\");\n                sb.AppendLine($\"{indentation}<div style=\\\"{ag.Style}\\\">{ag.Name} ({ag.Calls})</div>\");\n            }\n\n            sb.AppendLine($\"{indentation}</div>\");\n\n            return sb;\n        }\n\n        public override string ToString()\n        {\n            return GetType().Name;\n        }\n    }\n}\n"
  },
  {
    "path": "Editor/Formatters/Reporters/HTMLPerfReport.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 5982d768475803a4185fccf2a6ac8642\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "Editor/Formatters/Reporters/HTMLReporter.cs",
    "content": "﻿using System.Text;\nusing UnityEditor.EditorIterationProfiler.Formatting;\nusing System.IO;\nusing System.Linq;\nusing UnityEngine;\n\nnamespace UnityEditor.EditorIterationProfiler\n{\n    sealed class HTMLReporter : FileReporter\n    {\n        string m_Extension = \"html\";\n        public override string Extension => m_Extension;\n\n        string m_Name = \"HTML\";\n        public override string Name => m_Name;\n\n        double m_ParentTotalDuration;\n\n        protected override StringBuilder GetPrefixStringBuilder(in IIterationList iterationList = null)\n        {\n            var sb = new StringBuilder();\n\n            var fileGUID = AssetDatabase.FindAssets(\"HTMLReporterPrefix\").FirstOrDefault();\n            var filePath = AssetDatabase.GUIDToAssetPath(fileGUID);\n            var file = AssetDatabase.LoadAssetAtPath<TextAsset>(filePath);\n            sb.Append(file.text);\n\n            sb.AppendLine($\"<div class=\\\"Details Wordwrap\\\">{EditorIterationProfilerIntegration.Instance.Settings}</div>\");\n\n            sb.AppendLine($\"<br>\");\n            sb.AppendLine();\n\n            sb.AppendLine($\"<body>\");\n            sb.AppendLine($\"<div class=\\\"ToggleButton\\\" onclick=\\\"treeViewToggleAll(true);\\\">Expand all</div>\");\n            sb.AppendLine($\"<div class=\\\"ToggleButton\\\" onclick=\\\"treeViewToggleAll(false);\\\">Collapse all</div>\");\n\n            return sb;\n        }\n\n        protected override StringBuilder GetMainStringBuilder(in IIterationList iterationList)\n        {\n            var sb = new StringBuilder();\n\n            if (iterationList.IterationEventRoots.Count > 0)\n            {\n                RecursiveIterationList(iterationList, ref sb);\n            }\n            else\n            {\n                sb.AppendLine($\"<div>ERROR: No data to export!</div>\");\n            }\n\n            return sb;\n        }\n\n        void RecursiveIterationList(in IIterationList iterationList, ref StringBuilder sb)\n        {\n            if (iterationList.IterationEventRoots.Count == 0)\n            {\n                return;\n            }\n\n            for (int i = 0; i < iterationList.IterationEventRoots.Count; ++i)\n            {\n                RecursiveIterationEventRoot(iterationList.IterationEventRoots[i], ref sb);\n            }\n        }\n\n        void RecursiveIterationEventRoot(in IterationEventRoot iterationEventRoot, ref StringBuilder sb)\n        {\n            double totalDuration = 0;\n            foreach (var ed in iterationEventRoot.Events)\n            {\n                if (ed.ParentIndex < 0 && ed.Duration > 0)\n                {\n                    totalDuration += ed.Duration;\n                }\n            }\n\n            m_ParentTotalDuration = totalDuration;\n\n            var indentation1 = IndentationProvider.Get(1);\n\n            sb.AppendLine($\"<div class=\\\"TreeViewItem TreeViewItemCollapsed\\\">\");\n            sb.AppendLine(TimeDisplay(1, totalDuration));\n            sb.AppendLine(PercentageDisplay(1, 100));\n            sb.AppendLine($\"{indentation1}<div class=\\\"NameDisplay\\\" onclick=\\\"treeViewToggle(event);\\\">Iteration {iterationEventRoot.IterationIndex + 1} ({iterationEventRoot.IterationEventKind})</div>\");\n\n            foreach (var ed in iterationEventRoot.Events)\n            {\n                if (ed.ParentIndex < 0)\n                {\n                    RecursiveEventData(ed, iterationEventRoot, ref sb, 1, 100);\n\n                    sb.AppendLine($\"{indentation1}</div>\");\n                }\n            }\n\n            sb.AppendLine($\"</div>\");\n        }\n\n        void RecursiveEventData(in EventData ed, in IterationEventRoot parent, ref StringBuilder sb, int depth, double parentPercentage)\n        {\n            var indentation1 = IndentationProvider.Get(depth);\n            var indentation2 = IndentationProvider.Get(depth + 1);\n            double percentage = ed.Duration / m_ParentTotalDuration * 100;\n            if (ed.Children.Count > 0)\n            {\n                sb.AppendLine($\"{indentation1}<div class=\\\"TreeViewItem TreeViewItemCollapsed\\\">\");\n                sb.AppendLine(TimeDisplay(depth + 1, ed.Duration));\n                sb.AppendLine(PercentageDisplay(depth + 1, percentage));\n\n                if (!string.IsNullOrEmpty(ed.Details))\n                {\n                    sb.AppendLine($\"{indentation2}<div class=\\\"NameDisplay\\\" onclick=\\\"treeViewToggle(event);\\\">{ed.Identifier} ({ed.Details})</div>\");\n                }\n                else\n                {\n                    sb.AppendLine($\"{indentation2}<div class=\\\"NameDisplay\\\" onclick=\\\"treeViewToggle(event);\\\">{ed.Identifier}</div>\");\n                }\n            }\n            else\n            {\n                sb.AppendLine($\"{indentation1}<div class=\\\"TreeViewItem TreeViewItemLeaf\\\">\");\n                sb.AppendLine(TimeDisplay(depth + 1, ed.Duration));\n                sb.AppendLine(PercentageDisplay(depth + 1, percentage));\n\n                if (!string.IsNullOrEmpty(ed.Details))\n                {\n                    sb.AppendLine(SimpleLabel(depth + 1, $\"[{ed.Identifier}] ({ed.Details})\"));\n                }\n                else\n                {\n                    sb.AppendLine(SimpleLabel(depth + 1, $\"[{ed.Identifier}]\"));\n                }\n            }\n\n            RecursiveEventDataWalker(in ed, in parent, ref sb, depth, percentage);\n\n            if (depth != 1)\n            {\n                sb.AppendLine($\"{indentation1}</div>\");\n            }\n        }\n\n        void RecursiveEventDataWalker(in EventData ed, in IterationEventRoot iterationEventRoot, ref StringBuilder sb, int depth, double percentage)\n        {\n            if (ed.Children == null || ed.Children.Count == 0)\n            {\n                return;\n            }\n\n            foreach (var child in ed.Children)\n            {\n                RecursiveEventData(child, iterationEventRoot, ref sb, depth + 1, percentage);\n            }\n        }\n\n        string TimeDisplay(int depth, double time)\n        {\n            return $\"{IndentationProvider.Get(depth)}<div class=\\\"TimeDisplay\\\">{ToTimeString(time)}</div>\";\n        }\n\n        string PercentageDisplay(int depth, double percentage)\n        {\n            return $\"{IndentationProvider.Get(depth)}<div class=\\\"PercentageDisplay\\\">{ToPercentageString(percentage)}</div>\";\n        }\n\n        string SimpleLabel(int depth, string s, string style = \"\")\n        {\n            if (!string.IsNullOrEmpty(style))\n            {\n                return $\"{IndentationProvider.Get(depth)}<div style=\\\"{style}\\\">{s}</div>\";\n            }\n\n            return $\"{IndentationProvider.Get(depth)}<div>{s}</div>\";\n        }\n\n        public override string ToString()\n        {\n            return GetType().Name;\n        }\n    }\n}\n"
  },
  {
    "path": "Editor/Formatters/Reporters/HTMLReporter.cs.meta",
    "content": "fileFormatVersion: 2\nguid: e616717ebe9a5aa41a86a75e07d38c16\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "Editor/Formatters/Reporters/HTMLReporterPrefix.txt",
    "content": "﻿<html>\n<head>\n<style>\nbody {\n\tfont-family: monospace;\n}\nbody > .TreeViewItem {\n\tmargin-left: 175px;\n\tborder: none;\n}\n.Wordwrap { \n   white-space: pre-wrap;\n   white-space: -moz-pre-wrap;  \n   white-space: -o-pre-wrap;    \n   word-wrap: break-word;\n}\n.Details {\n\tfont-size: 10px;\n}\n.TreeViewItem {\n\tpadding: 2px;\n\tpadding-left: 10px;\n\tborder-left: 1px solid black;\n}\n.TreeViewItem::before {\n\tcontent: \"-\";\n\tfloat: left;\n\tpadding-right: 2px;\n\tmargin-left: -10px;\n}\n.TreeViewItemCollapsed::before {\n\tcontent: \"+\";\n}\n.TreeViewItemCollapsed > .TreeViewItem {\n\tdisplay: none;\n}\n.TreeViewItemLeaf::before {\n\tcontent: none;\n}\n.TimeDisplay {\n\tposition:absolute;\n\tleft: 0px;\n\twidth: 95px;\n\ttext-align: right;\n\tcolor: purple;\n}\n.PercentageDisplay{\n\tposition:absolute;\n\tleft: 120px;\n\ttext-align: right;\n\tcolor: green;\n}\n.NameDisplay {\n\tcursor: pointer;\n}\n.NameDisplay:hover {\n\ttext-decoration: underline;\n\tcolor: blue;\n}\n.ToggleButton {\n\tpadding: 2px;\n\tmargin: 2px;\n\tborder: 1px solid black;\n\tdisplay: inline-block;\n\tcursor: pointer;\n}\n</style>\n\n<script>\nfunction treeViewToggle(evt) {\n\tif (evt.eventPhase != Event.AT_TARGET)\n\t\treturn;\n\tvar target = evt.target.parentNode;\n\tvar classList = target.className.split(\" \");\n\tvar idx = classList.indexOf(\"TreeViewItemCollapsed\");\n\tif (idx < 0) {\n\t\ttarget.className += \" TreeViewItemCollapsed\";\n\t} else {\n\t\tclassList.splice(idx, 1);\n\t\ttarget.className = classList.join(\" \");\n\t}\n}\nfunction treeViewToggleAll(enable) {\n\tvar elements = document.getElementsByClassName(\"TreeViewItem\");\n\tfor (e = 0; e < elements.length; ++e) {\n\t\tvar elem = elements[e];\n\t\tvar classList = elem.className.split(\" \");\n\t\tif (classList.indexOf(\"TreeViewItemLeaf\") >= 0)\n\t\t\tcontinue;\n\t\tvar idx = classList.indexOf(\"TreeViewItemCollapsed\");\n\t\tif (enable && idx >= 0) {\n\t\t\tclassList.splice(idx, 1);\n\t\t\telem.className = classList.join(\" \");\n\t\t} else if (!enable && idx < 0) {\n\t\t\telem.className += \" TreeViewItemCollapsed\";\n\t\t}\n\n\t}\n}\n</script>\n</head>\n\n"
  },
  {
    "path": "Editor/Formatters/Reporters/HTMLReporterPrefix.txt.meta",
    "content": "fileFormatVersion: 2\nguid: fa0a687d251c5484281dc568e5a0e2ad\nTextScriptImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "Editor/Formatters/Reporters/PlaintextReporter.cs",
    "content": "﻿namespace UnityEditor.EditorIterationProfiler.Formatting\n{\n    public sealed class PlaintextReporter : FileReporter\n    {\n        string m_Extension = \"txt\";\n        public override string Extension => m_Extension;\n\n        string m_Name = \"Plaintext\";\n        public override string Name => m_Name;\n\n        IDataReporter m_El = new EditorLogReporter();\n\n        public override void Report(in IIterationList iterationList, string path)\n        {\n            ReportToFile(m_El.GetFormatString(iterationList), path);\n        }\n\n        public override string ToString()\n        {\n            return GetType().Name;\n        }\n    }\n}\n"
  },
  {
    "path": "Editor/Formatters/Reporters/PlaintextReporter.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 843fc8e922ce90b4fb75e591fe507647\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "Editor/Formatters/Reporters.meta",
    "content": "fileFormatVersion: 2\nguid: dded3bae191a0ba46be87613decab5af\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "Editor/Formatters.meta",
    "content": "fileFormatVersion: 2\nguid: 313fa6debd8d20c46ad511bfbb6b4213\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "Editor/IterationEventKind.cs",
    "content": "﻿using System;\n\nnamespace UnityEditor.EditorIterationProfiler\n{\n    public enum IterationEventKind\n    {\n        None = 0,\n        AssetImport,\n        AssetPostProcess,\n        ScriptCompilation,\n        AssemblyCompilation,\n        EnterPlayMode,\n        ExitPlayMode,\n        AssemblyReload,\n        AssemblyCompilationStart,\n        AssemblyCompilationFinish\n    }\n}\n"
  },
  {
    "path": "Editor/IterationEventKind.cs.meta",
    "content": "fileFormatVersion: 2\nguid: c0ea77b406086944dbb826a1c0895a29\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "Editor/IterationEventRoot.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing UnityEngine;\n\nnamespace UnityEditor.EditorIterationProfiler\n{\n    [Serializable]\n    public class IterationEventRoot\n    {\n        [SerializeField]\n        List<EventData> m_Events = new List<EventData>();\n        public List<EventData> Events => m_Events;\n\n        [SerializeField]\n        int m_IterationIndex;\n        public int IterationIndex\n        {\n            get => m_IterationIndex;\n            set => m_IterationIndex = value;\n        }\n\n        [SerializeField]\n        IterationEventKind m_IterationEventKind;\n        public IterationEventKind IterationEventKind => m_IterationEventKind;\n\n        [SerializeField]\n        Dictionary<string, EventData> m_EventDictionary = new Dictionary<string, EventData>();\n\n        public IterationEventKind LastIterationEventKind\n        {\n            get\n            {\n                if (Events.Count == 0)\n                {\n                    return IterationEventKind.None;\n                }\n\n                return Events.Last().Kind;\n            }\n        }\n\n        public IterationEventRoot(int index)\n        {\n            IterationIndex = index;\n            m_IterationEventKind = IterationEventKind.None;\n        }\n\n        public IterationEventRoot(int index, IterationEventKind eventKind)\n        {\n            IterationIndex = index;\n            m_IterationEventKind = eventKind;\n        }\n\n        public void Reload()\n        {\n            foreach (var eventData in Events)\n            {\n                eventData.Children = new List<EventData>();\n            }\n\n            foreach (var eventData in Events)\n            {\n                int parentIndex = eventData.ParentIndex;\n\n                if (parentIndex >= 0)\n                {\n                    Events[parentIndex].Children.Add(eventData);\n                }\n            }\n        }\n\n        public EventData StartEvent(IterationEventKind kind, string identifier, string metadata)\n        {\n            int index = Events.Count;\n            var eventData = new EventData(kind, identifier, metadata, index);\n\n            Events.Add(eventData);\n            m_EventDictionary[identifier] = eventData;\n\n            return eventData;\n        }\n\n        public EventData StartEvent(IterationEventKind kind)\n        {\n            return StartEvent(kind, kind.ToString(), null);\n        }\n\n        public void FinishEvent(string identifier)\n        {\n            var eventData = FindLastEvent(identifier);\n            eventData?.Finish();\n        }\n\n        public void FinishEvent(IterationEventKind kind)\n        {\n            string identifier = kind.ToString();\n            FinishEvent(identifier);\n        }\n\n        public EventData AddChildEvent(string identifier, string metadata, double startTime, double finishTime, EventData parentEvent, EventDataFlags flags = EventDataFlags.None)\n        {\n            int index = Events.Count;\n\n            var eventData = new EventData(identifier, metadata, index, startTime, finishTime, flags);\n            Events.Add(eventData);\n\n            SetParent(eventData, parentEvent);\n\n            return eventData;\n        }\n\n        public static void SetParent(EventData child, EventData parent)\n        {\n            if (child == null)\n            {\n                throw new ArgumentNullException(nameof(child), \"Argument is null\");\n            }\n\n            if (parent == null)\n            {\n                throw new ArgumentNullException(nameof(parent), \"Argument is null\");\n            }\n\n            child.ParentIndex = parent.Index;\n            parent.Children.Add(child);\n        }\n\n        public void SetParent(EventData child, IterationEventKind kind)\n        {\n            var parent = FindLastEvent(kind);\n            SetParent(child, parent);\n        }\n\n        public EventData FindLastEvent(IterationEventKind kind)\n        {\n            string identifier = kind.ToString();\n            return FindLastEvent(identifier);\n        }\n\n        public EventData FindLastEvent(string identifier)\n        {\n\n            if (m_EventDictionary != null && m_EventDictionary.TryGetValue(identifier, out var eventData))\n            {\n                return eventData;\n            }\n\n            // If an assembly reload happens, then eventDictionary is\n            // empty and we search for the last event with matching\n            // identifier.\n            for (int i = Events.Count - 1; i >= 0; --i)\n            {\n                if (Events[i].Identifier == identifier)\n                {\n                    return Events[i];\n                }\n            }\n\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "Editor/IterationEventRoot.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 6efa6c94e301cfc4da89c7584f3ceb2a\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "Editor/IterationList.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing UnityEngine;\n\nnamespace UnityEditor.EditorIterationProfiler\n{\n    [Serializable]\n    class IterationList : IIterationList\n    {\n        [SerializeField]\n        List<IterationEventRoot> m_IterationIterationEventRoots;\n        public List<IterationEventRoot> IterationEventRoots => m_IterationIterationEventRoots;\n        public IterationEventRoot LastIterationEventRoot => m_IterationIterationEventRoots.LastOrDefault();\n\n        [SerializeField]\n        List<IterationEventKind> m_IterationEventKinds;\n        public List<IterationEventKind> IterationEventKinds => m_IterationEventKinds;\n        \n        [SerializeField]\n        Action<IIterationList> m_Updated;\n        public Action<IIterationList> Updated { get; set; }\n        \n        public IterationList()\n        {\n            m_IterationIterationEventRoots = new List<IterationEventRoot>();\n            m_IterationEventKinds = new List<IterationEventKind>();\n        }\n\n        public void NewIteration(IterationEventKind kind)\n        {\n            int index = IterationEventRoots.Count;\n            IterationEventRoots.Add(new IterationEventRoot(index, kind));\n            IterationEventKinds.Add(kind);\n        }\n\n        public void Clear()\n        {\n            IterationEventRoots.Clear();\n            IterationEventKinds.Clear();\n\n            NotifyUpdated();\n        }\n\n        public void Reload()\n        {\n            foreach (var eventDataList in IterationEventRoots)\n            {\n                eventDataList.Reload();\n            }\n\n            NotifyUpdated();\n        }\n\n        public void NotifyUpdated()\n        {\n            Updated?.Invoke(this);\n        }\n    }\n}\n"
  },
  {
    "path": "Editor/IterationList.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 685ab7a1693ff6d4588b129ce76cef56\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "Editor/ProfilerDataCollector.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing UnityEditor.EditorIterationProfiler.API;\nusing UnityEditor.Profiling;\nusing UnityEditorInternal;\nusing UnityEngine;\nusing UnityEngine.Profiling;\n\nnamespace UnityEditor.EditorIterationProfiler\n{\n    [Serializable]\n    public class ProfilerDataCollector : IProfilerDataCollector\n    {\n        IIterationList m_IterationList;\n\n        //static Dictionary<string, string> s_FlattenMarkers = new Dictionary<string, string>();\n        static Dictionary<IterationEventKind, string[]> s_KeyMarkers = new Dictionary<IterationEventKind, string[]>();\n        static Dictionary<string, EventDataFlags> s_MarkerFlags = new Dictionary<string, EventDataFlags>();\n        static Dictionary<string, string[]> s_MarkerThread = new Dictionary<string, string[]>();\n\n        [SerializeField]\n        List<FrameSearchData> m_FrameSearchDataList = new List<FrameSearchData>();\n\n        public ProfilerDataCollector(IIterationList iterationList)\n        {\n            Initialize(iterationList);\n\n            // Find frame where asset import kicks off compilation.\n            AddKeyMarkers(IterationEventKind.AssetImport, \"CompilationPipeline.CompileScripts\");\n\n            //AddKeyMarkers(IterationEventKind.AssemblyCompilationStart, \"CompilationPipeline.CompileAssemblyStart\");\n            //AddKeyMarkers(IterationEventKind.AssemblyCompilationFinish, \"CompilationPipeline.CompileAssemblyFinish\");\n\n            AddKeyMarkers(IterationEventKind.AssemblyReload, \"ReloadAssemblies\");\n\n            AddKeyMarkers(IterationEventKind.EnterPlayMode, \"EnterPlayMode\");\n\n            AddKeyMarkers(IterationEventKind.ExitPlayMode, \"ExitPlayMode\");\n\n            //AddFlattenMarker(\"ReloadAssembly\", \"ReloadAssemblies\");\n            //AddFlattenMarker(\"BeginReloadAssembly\", \"ReloadAssemblies\");\n            //AddFlattenMarker(\"EndReloadAssembly\", \"ReloadAssemblies\");\n\n            string[] userCodeMarkers =\n            {\n                \"AssemblyReloadEvents.OnBeforeAssemblyReload()\",\n                \"AssemblyReloadEvents.OnAfterAssemblyReload()\",\n                \"DisabledScriptedObjects\",\n                \"BackupScriptedObjects\",\n                \"RestoreManagedReferences\",\n                \"ProcessInitializeOnLoadAttributes\",\n                \"ProcessInitializeOnLoadMethodAttributes\",\n                \"AwakeScriptedObjects\",\n                \"UnloadDomain\"\n            };\n\n            foreach (string marker in userCodeMarkers)\n            {\n                AddMarkerFlags(marker, EventDataFlags.UserCode);\n            }\n\n#if UNITY_2020_3_OR_NEWER\n            AddThreadMarker(\"UnloadDomain\", \"Domain Unloader\", \"Finalizer\");\n#else\n            AddThreadMarker(\"UnloadDomain\", \"Domain unloader\", \"Finalizer\");\n#endif\n        }\n\n        void Initialize(IIterationList iterationList)\n        {\n            m_IterationList = iterationList;\n        }\n\n        public void Clear()\n        {\n            m_FrameSearchDataList.Clear();\n        }\n\n        public void Subscribe()\n        {\n            UnityProfiling.NewProfilerFrameRecorded += ProfilerNewFrame;\n        }\n\n        public void Unsubscribe()\n        {\n            UnityProfiling.NewProfilerFrameRecorded -= ProfilerNewFrame;\n        }\n\n        static void AddKeyMarkers(IterationEventKind iterationEventKind, params string[] markers)\n        {\n            s_KeyMarkers[iterationEventKind] = markers;\n        }\n\n        static string[] GetKeyMarkers(IterationEventKind iterationEventKind)\n        {\n            if (s_KeyMarkers.TryGetValue(iterationEventKind, out string[] marker))\n            {\n                return marker;\n            }\n\n            return null;\n        }\n\n        //static void AddFlattenMarker(string marker, string parentMarker)\n        //{\n        //    s_FlattenMarkers[marker] = parentMarker;\n        //}\n\n        static void AddMarkerFlags(string marker, EventDataFlags flags)\n        {\n            s_MarkerFlags[marker] = flags;\n        }\n\n        static void AddThreadMarker(string marker, params string[] threadNames)\n        {\n            s_MarkerThread[marker] = threadNames;\n        }\n\n        public void Collect(IterationEventKind iterationEventKind, IterationEventRoot iterationEventRoot, EventData rootEvent)\n        {\n            var frameSearchData = new FrameSearchData\n            {\n                IterationEventKind = iterationEventKind,\n                EventListIndex = iterationEventRoot.IterationIndex,\n                EventDataIndex = rootEvent.Index,\n                MaxNumFrames = 600\n            };\n\n            m_FrameSearchDataList.Add(frameSearchData);\n\n#if DEVELOPMENT_BUILD\n            Debug.Log($\"Starting to look for {iterationEventKind}\");\n#endif\n        }\n\n        void ProfilerNewFrame(int connectionId, int newFrameIndex)\n        {\n            // Remove frames which exceeded the search limit.\n            for (var i = m_FrameSearchDataList.Count - 1; i >= 0; --i)\n            {\n                m_FrameSearchDataList[i].MaxNumFrames -= 1;\n\n                if (m_FrameSearchDataList[i].MaxNumFrames <= 0)\n                {\n#if DEVELOPMENT_BUILD\n                    Debug.Log($\"Stopping search for event {m_FrameSearchDataList[i].IterationEventKind}\");\n#endif\n                    m_FrameSearchDataList.RemoveAt(i);\n                }\n            }\n\n            if (m_FrameSearchDataList.Count == 0)\n            {\n                return;\n            }\n\n            var frameData = UnityProfiling.GetFrame(newFrameIndex, 0);\n            if (!frameData.valid)\n            {\n#if DEVELOPMENT_BUILD\n                Debug.LogErrorFormat($\"Unable to retrieve profiler data for frame {newFrameIndex}\");\n#endif\n                return;\n            }\n\n            var markerData = new MarkerData(m_FrameSearchDataList.Count);\n            for (var i = 0; i < markerData.Length; ++i)\n            {\n                var frameSearchData = m_FrameSearchDataList[i];\n                frameSearchData.MaxNumFrames -= 1;\n                markerData.Markers[i] = GetKeyMarkers(frameSearchData.IterationEventKind);\n            }\n\n            var framesNotFound = new List<FrameSearchData>();\n\n            for (int i = 0; i < m_FrameSearchDataList.Count; ++i)\n            {\n                if (markerData.FrameIndices[i] == 0)\n                {\n                    framesNotFound.Add(m_FrameSearchDataList[i]);\n                }\n            }\n\n#if DEVELOPMENT_BUILD\n            Debug.Log($\"Searching for events {string.Join(\",\", framesNotFound.Select(f => f.IterationEventKind.ToString()).ToArray())} in frame {newFrameIndex}\");\n#endif\n\n            if (!FindMarkersInFrameData(frameData, frameData.GetRootItemID(), markerData, ProfilerDriver.deepProfiling ? 12 : 8))\n            {\n#if DEVELOPMENT_BUILD\n                Debug.LogWarning($\"Didn't find all markers in {newFrameIndex}\");\n#endif\n                return;\n            }\n\n            var iterationListUpdated = false;\n\n            for (int i = markerData.Length - 1; i >= 0; --i)\n            {\n                var frameSearchData = m_FrameSearchDataList[i];\n\n                if (markerData.SampleIds[i] == UnityProfiling.InvalidSampleId)\n                {\n                    if (frameSearchData.MaxNumFrames <= 0)\n                    {\n#if DEVELOPMENT_BUILD\n                        Debug.Log($\"Stopping search for event {frameSearchData.IterationEventKind}\");\n#endif\n                        m_FrameSearchDataList.RemoveAt(i);\n                    }\n\n                    continue;\n                }\n\n#if DEVELOPMENT_BUILD\n                Debug.Log($\"Reading profiling data for event {frameSearchData.IterationEventKind} from frame {markerData.FrameIndices[i]}\");\n#endif\n\n                var eventDataList = m_IterationList.IterationEventRoots[frameSearchData.EventListIndex];\n                var eventData = eventDataList.Events[frameSearchData.EventDataIndex];\n\n                ReadProfilingData(eventDataList, eventData, markerData.FrameData[i], markerData.FrameData[i].GetRootItemID(), EventDataFlags.None, false);\n\n                eventData.SetStartFinishTimeFromChildren();\n                eventData.PostProcess();\n\n                iterationListUpdated = true;\n\n                m_FrameSearchDataList.RemoveAt(i);\n            }\n\n            if (iterationListUpdated)\n            {\n                m_IterationList.NotifyUpdated();\n            }\n        }\n\n        internal static void ReadProfilingData(IterationEventRoot iterationEventRoot, EventData parentEventData, HierarchyFrameDataView frameData, int sampleId, EventDataFlags flags, bool parentHasSingleChild)\n        {\n            double duration = frameData.GetItemColumnDataAsDouble(sampleId, HierarchyFrameDataView.columnTotalTime);\n\n            if (duration < 0.01)\n            {\n                return;\n            }\n\n            string markerName = frameData.GetItemName(sampleId);\n            double startTime = frameData.GetItemColumnDataAsDouble(sampleId, HierarchyFrameDataView.columnStartTime);\n            double finishTime = startTime + duration;\n\n            int metadataCount = frameData.GetItemMetadataCount(sampleId);\n            var sb = new StringBuilder();\n\n            sb.Append(\"GC Alloc: \" + frameData.GetItemColumnData(sampleId, 4) + \"; \");\n            sb.Append(\"Calls: \" + frameData.GetItemColumnData(sampleId, 3) + \"; \");\n\n\n            if (metadataCount > 0)\n            {\n                sb.Append(\"Metadata: \");\n                for (var i = 0; i < metadataCount; ++i)\n                {\n                    sb.Append(frameData.GetItemMetadata(sampleId, i));\n                    sb.Append(\"; \");\n                }\n            }\n\n            var markerMetadata = sb.Replace(',', ';').Remove(sb.Length - 2, 1).ToString().Trim();\n            if (s_MarkerFlags.TryGetValue(markerName, out var eventMarkerFlags))\n            {\n                flags |= eventMarkerFlags;\n            }\n\n            var childEvent = iterationEventRoot.AddChildEvent(markerName, markerMetadata, startTime, finishTime, parentEventData, flags);\n\n            if (s_MarkerThread.TryGetValue(markerName, out string[] threadNames))\n            {\n                foreach (string threadName in threadNames)\n                {\n                    var threadFrameData = UnityProfiling.GetFrame(frameData.frameIndex, threadName);\n                    var threadEvent = iterationEventRoot.AddChildEvent($\"Thread: {threadName}\", markerMetadata, parentEventData.StartTime, parentEventData.FinishTime, childEvent, flags);\n\n                    var threadChildIds = new List<int>();\n                    threadFrameData.GetItemChildren(threadFrameData.GetRootItemID(), threadChildIds);\n\n                    foreach (int childId in threadChildIds)\n                    {\n                        ReadProfilingData(iterationEventRoot, threadEvent, threadFrameData, childId, flags, threadChildIds.Count == 1);\n                    }\n\n                    threadEvent.SetStartFinishTimeFromChildren();\n                }\n            }\n\n            var childIds = new List<int>();\n            frameData.GetItemChildren(sampleId, childIds);\n\n            foreach (int childId in childIds)\n            {\n                ReadProfilingData(iterationEventRoot, childEvent, frameData, childId, flags, childIds.Count == 1);\n            }\n        }\n\n        static bool FindMarkersInFrameData(HierarchyFrameDataView frameData, int parentId, MarkerData markerData, int maxDepth)\n        {\n            if (maxDepth == 0)\n            {\n                return false;\n            }\n\n            var childrenIds = new List<int>();\n            frameData.GetItemChildren(parentId, childrenIds);\n\n            string[][] markers = markerData.Markers;\n            int[] sampleIds = markerData.SampleIds;\n            int[] frameIndices = markerData.FrameIndices;\n\n            foreach (int childId in childrenIds)\n            {\n                string name = frameData.GetItemName(childId);\n\n                for (var i = 0; i < markers.Length; ++i)\n                {\n                    if (markers[i] == null)\n                    {\n                        continue;\n                    }\n\n                    string[] localKeyMarkers = markers[i];\n\n                    for (var j = 0; j < localKeyMarkers.Length; ++j)\n                    {\n                        if (name == localKeyMarkers[j])\n                        {\n                            sampleIds[i] = childId;\n                            frameIndices[i] = frameData.frameIndex;\n                            markerData.FrameData[i] = frameData;\n                        }\n                    }\n                }\n\n                if (markerData.FoundAllSampleIds)\n                {\n                    return true;\n                }\n\n                if (FindMarkersInFrameData(frameData, childId, markerData, maxDepth - 1))\n                {\n                    return true;\n                }\n            }\n\n            return false;\n        }\n\n        [Serializable]\n        public class FrameSearchData\n        {\n            public int EventDataIndex;\n            public int EventListIndex;\n            public IterationEventKind IterationEventKind;\n            public int MaxNumFrames;\n        }\n\n        struct MarkerData\n        {\n            public string[][] Markers;\n            public int[] SampleIds;\n            public int[] FrameIndices;\n            public HierarchyFrameDataView[] FrameData;\n\n            public MarkerData(int length)\n            {\n                Markers = new string[length][];\n                SampleIds = new int[length];\n                FrameIndices = new int[length];\n                FrameData = new HierarchyFrameDataView[length];\n\n                for (var i = 0; i < length; ++i)\n                {\n                    SampleIds[i] = UnityProfiling.InvalidSampleId;\n                }\n            }\n\n            public bool FoundAllSampleIds\n            {\n                get\n                {\n                    for (var i = 0; i < Length; ++i)\n                    {\n                        if (SampleIds[i] == UnityProfiling.InvalidSampleId)\n                        {\n                            return false;\n                        }\n                    }\n\n                    return true;\n                }\n            }\n\n            public int Length => Markers.Length;\n        }\n    }\n}\n"
  },
  {
    "path": "Editor/ProfilerDataCollector.cs.meta",
    "content": "fileFormatVersion: 2\nguid: d1e3dc04d1e8e8344a237bfc5e3b756b\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "Editor/Unity.EditorIterationProfiler.Editor.asmdef",
    "content": "{\n    \"name\": \"Unity.EditorIterationProfiler.Editor\",\n    \"references\": [],\n    \"includePlatforms\": [\n        \"Editor\"\n    ],\n    \"excludePlatforms\": [],\n    \"allowUnsafeCode\": false,\n    \"overrideReferences\": false,\n    \"precompiledReferences\": [],\n    \"autoReferenced\": true,\n    \"defineConstraints\": [],\n    \"versionDefines\": [],\n    \"noEngineReferences\": false\n}"
  },
  {
    "path": "Editor/Unity.EditorIterationProfiler.Editor.asmdef.meta",
    "content": "fileFormatVersion: 2\nguid: 00680d720d027674dbb1d8c51e1aaa52\nAssemblyDefinitionImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "Editor/UnityEditorEvents.cs",
    "content": "﻿using System;\nusing System.IO;\nusing UnityEditor.Compilation;\n\nnamespace UnityEditor.EditorIterationProfiler\n{\n    static class UnityEditorEvents\n    {\n        public enum Event\n        {\n            None = 0,\n            ScriptCompilationStarted,\n            ScriptCompilationFinished,\n            AssemblyCompilationStarted,\n            AssemblyCompilationFinished,\n            AssemblyReloadStarted,\n            AssemblyReloadFinished,\n            EnteringPlayMode,\n            EnteredPlayMode,\n            ExitingPlayMode,\n            ExitedPlayMode\n        }\n\n        public static event Action<Event, string> EditorEvent;\n\n        public static void Subscribe()\n        {\n            CompilationPipeline.compilationStarted += ScriptCompilationStarted;\n            CompilationPipeline.compilationFinished += ScriptCompilationFinished;\n            CompilationPipeline.assemblyCompilationStarted += AssemblyCompilationStarted;\n            CompilationPipeline.assemblyCompilationFinished += AssemblyCompilationFinished;\n\n            AssemblyReloadEvents.beforeAssemblyReload += AssemblyReloadStarted;\n            AssemblyReloadEvents.afterAssemblyReload += AssemblyReloadFinished;\n\n            EditorApplication.playModeStateChanged += PlayModeStateChanged;\n        }\n\n        public static void Unsubscribe()\n        {\n            CompilationPipeline.compilationStarted -= ScriptCompilationStarted;\n            CompilationPipeline.compilationFinished -= ScriptCompilationFinished;\n            CompilationPipeline.assemblyCompilationStarted -= AssemblyCompilationStarted;\n            CompilationPipeline.assemblyCompilationFinished -= AssemblyCompilationFinished;\n\n            AssemblyReloadEvents.beforeAssemblyReload -= AssemblyReloadStarted;\n            AssemblyReloadEvents.afterAssemblyReload -= AssemblyReloadFinished;\n\n            EditorApplication.playModeStateChanged -= PlayModeStateChanged;\n        }\n\n        static void ScriptCompilationStarted(object obj)\n        {\n            EditorEvent?.Invoke(Event.ScriptCompilationStarted, null);\n        }\n\n        static void ScriptCompilationFinished(object obj)\n        {\n            EditorEvent?.Invoke(Event.ScriptCompilationFinished, null);\n        }\n\n        static void AssemblyCompilationStarted(string assembly)\n        {\n            EditorEvent?.Invoke(Event.AssemblyCompilationStarted, Path.GetFileName(assembly));\n        }\n\n        static void AssemblyCompilationFinished(string assembly, CompilerMessage[] messages)\n        {\n            EditorEvent?.Invoke(Event.AssemblyCompilationFinished, Path.GetFileName(assembly));\n        }\n\n        static void AssemblyReloadStarted()\n        {\n            EditorEvent?.Invoke(Event.AssemblyReloadStarted, null);\n        }\n\n        static void AssemblyReloadFinished()\n        {\n            EditorEvent?.Invoke(Event.AssemblyReloadFinished, null);\n        }\n\n        static void PlayModeStateChanged(PlayModeStateChange state)\n        {\n            switch (state)\n            {\n                case PlayModeStateChange.ExitingEditMode:\n                {\n                    EditorEvent?.Invoke(Event.EnteringPlayMode, null);\n                }\n                    break;\n\n                case PlayModeStateChange.EnteredPlayMode:\n                {\n                    EditorEvent?.Invoke(Event.EnteredPlayMode, null);\n                }\n                    break;\n\n                case PlayModeStateChange.ExitingPlayMode:\n                {\n                    EditorEvent?.Invoke(Event.ExitingPlayMode, null);\n                }\n                    break;\n\n                case PlayModeStateChange.EnteredEditMode:\n                {\n                    EditorEvent?.Invoke(Event.ExitedPlayMode, null);\n                }\n                    break;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Editor/UnityEditorEvents.cs.meta",
    "content": "fileFormatVersion: 2\nguid: 521d993316e2dc54f9f64b52fe96eadf\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "Editor/UnityProfiling.cs",
    "content": "﻿using System;\nusing UnityEditor.Profiling;\nusing UnityEditorInternal;\n\nnamespace UnityEditor.EditorIterationProfiler\n{\n    static class UnityProfiling\n    {\n        public static bool EditorProfilingEnabled\n        {\n            get => ProfilerDriver.enabled && ProfilerDriver.profileEditor;\n\n            set\n            {\n                ProfilerDriver.enabled = value;\n                ProfilerDriver.profileEditor = value;\n            }\n        }\n\n        public static void SetProfileDeepScripts(bool deep)\n        {\n            if (ProfilerDriver.deepProfiling == deep)\n                return;\n\n            bool doApply = true;\n\n            // When enabling / disabling deep script profiling we need to reload scripts. In play mode this might be intrusive, so we ask the user first.\n            if (EditorApplication.isPlaying)\n            {\n                if (deep)\n                {\n                    doApply = EditorUtility.DisplayDialog(\"Enable deep script profiling\", \"Enabling deep profiling requires reloading scripts.\", \"Reload\", \"Cancel\");\n                }\n                else\n                {\n                    doApply = EditorUtility.DisplayDialog(\"Disable deep script profiling\", \"Disabling deep profiling requires reloading all scripts\", \"Reload\", \"Cancel\");\n                }\n            }\n\n            if (doApply)\n            {\n                EditorIterationProfilerAnalytics.SendInteractionEvent(EditorProfilingEnabled, EditorApplication.isPlaying, ProfilerDriver.deepProfiling, EditorIterationProfilerIntegration.Instance.Settings.Flatten, EditorIterationProfilerIntegration.Instance.Settings.UserCode);\n\n                ProfilerDriver.deepProfiling = deep;\n                EditorPrefs.SetBool(EditorIterationProfilerWindow.Styles.k_EnableDeepProfile, deep);\n                EditorIterationProfilerIntegration.Instance.Settings.DeepProfile = deep;\n                EditorUtility.RequestScriptReload();\n            }\n        }\n\n        public static int InvalidSampleId => HierarchyFrameDataView.invalidSampleId;\n\n        public static event Action<int, int> NewProfilerFrameRecorded\n        {\n            add => ProfilerDriver.NewProfilerFrameRecorded += value;\n            remove => ProfilerDriver.NewProfilerFrameRecorded -= value;\n        }\n\n        public static HierarchyFrameDataView GetFrame(int frameIndex, int threadIndex)\n        {\n            var frame = ProfilerDriver.GetHierarchyFrameDataView(frameIndex, threadIndex, HierarchyFrameDataView.ViewModes.MergeSamplesWithTheSameName, HierarchyFrameDataView.columnTotalTime, false);\n\n            return frame;\n        }\n\n        public static HierarchyFrameDataView GetFrame(int frameIndex, string threadName)\n        {\n            var iter = new ProfilerFrameDataIterator();\n            iter.SetRoot(frameIndex, 0);\n\n            int threadCount = iter.GetThreadCount(frameIndex);\n\n            for (var i = 0; i < threadCount; ++i)\n            {\n                iter.SetRoot(frameIndex, i);\n                string currentThreadName = iter.GetThreadName();\n\n                if (currentThreadName.Equals(threadName, StringComparison.OrdinalIgnoreCase))\n                {\n                    iter.Dispose();\n                    return GetFrame(frameIndex, i);\n                }\n            }\n\n            iter.Dispose();\n            throw new ArgumentException($\"Could not find thread named '{threadName}'. Depending on the Unity version, it could have been renamed.\");\n        }\n    }\n}\n"
  },
  {
    "path": "Editor/UnityProfiling.cs.meta",
    "content": "fileFormatVersion: 2\nguid: dc5baee3fb0bc9f41ba836bff674eb06\nMonoImporter:\n  externalObjects: {}\n  serializedVersion: 2\n  defaultReferences: []\n  executionOrder: 0\n  icon: {instanceID: 0}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "Editor.meta",
    "content": "fileFormatVersion: 2\nguid: 9949f7c4ae59ee7499a083d831233f16\nfolderAsset: yes\nDefaultImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "LICENSE.md",
    "content": "Editor Iteration Profiler copyright © 2020 Unity Technologies ApS\n\nLicensed under the Unity Companion License for Unity-dependent projects--see [Unity Companion License](https://unity3d.com/legal/licenses/Unity_Companion_License).\n\nUnless expressly provided otherwise, the Software under this license is made available strictly on an “AS IS” BASIS WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. Please review the license for details on these and other terms and conditions."
  },
  {
    "path": "LICENSE.md.meta",
    "content": "fileFormatVersion: 2\nguid: 0515e52add3ab464880c7466bcf136b8\nTextScriptImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "README.md",
    "content": "# Editor Iteration Profiler\nAssists in capturing frames from the Profiler of Domain Reloads in the Unity Editor. Compatible with Unity 2019.3+.\n\n# Please see the forum post for details on how to use, gotchas, etc. https://forum.unity.com/threads/introducing-the-editor-iteration-profiler.908390/"
  },
  {
    "path": "README.md.meta",
    "content": "fileFormatVersion: 2\nguid: 41ae1fb9d1a93684bb23091b2c54ad2b\nTextScriptImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  },
  {
    "path": "package.json",
    "content": "{\n\t\"name\": \"com.unity.editoriterationprofiler\",\n\t\"displayName\":\"Editor Iteration Profiler\",\n\t\"version\": \"0.1.2-preview\",\n\t\"unity\": \"2019.3\",\n\t\"description\": \"The Editor Iteration Profiler is an Editor tool which monitors domain reloads. It makes use of the Profiler and works by collecting and storing the relevant frames of the domain reload.\\n\\nMain features:\\n▪ Enter/Exit playmode domain reload monitoring\\n▪ Script Compilation monitoring\\n▪ Ability to export its data or Profiler data to a number of formats such as CSV, HTML, JSON, etc.\\n\",\n\t\"dependencies\": {\n\t}\n}\n"
  },
  {
    "path": "package.json.meta",
    "content": "fileFormatVersion: 2\nguid: 9d114ba67f600c34994534b2b6994a8a\nPackageManifestImporter:\n  externalObjects: {}\n  userData: \n  assetBundleName: \n  assetBundleVariant: \n"
  }
]