├── .github ├── example.png └── workflows │ ├── autotag.yml │ └── npm-publish.yml ├── .gitignore ├── AsmdefDebug.cs ├── AsmdefDebug.cs.meta ├── AsmdefDebugWindow.cs ├── AsmdefDebugWindow.cs.meta ├── Assembly.Debugger.asmdef ├── Assembly.Debugger.asmdef.meta ├── CompilationReport.cs ├── CompilationReport.cs.meta ├── LICENSE.md ├── LICENSE.md.meta ├── README.md ├── README.md.meta ├── package.json └── package.json.meta /.github/example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bullrich/Unity-Assembly-Debugger/c7da0d0a38bfe78a4147e9ac1b481e8e22db0e25/.github/example.png -------------------------------------------------------------------------------- /.github/workflows/autotag.yml: -------------------------------------------------------------------------------- 1 | name: Create Tag 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v2 13 | - uses: Klemensas/action-autotag@stable 14 | with: 15 | GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" -------------------------------------------------------------------------------- /.github/workflows/npm-publish.yml: -------------------------------------------------------------------------------- 1 | name: NPM Publish 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | publish: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v1 13 | - uses: actions/setup-node@v1 14 | with: 15 | node-version: 10 16 | - uses: JS-DevTools/npm-publish@v1 17 | with: 18 | token: ${{ secrets.NPM_AUTH_TOKEN }} 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /AsmdefDebug.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using AssemblyDebugger; 6 | using UnityEditor; 7 | using UnityEditor.Compilation; 8 | using UnityEngine; 9 | 10 | 11 | // Based on https://gist.github.com/karljj1/9c6cce803096b5cd4511cf0819ff517b 12 | [InitializeOnLoad] 13 | public class AsmdefDebug 14 | { 15 | internal const string CompilationReportEditorPref = "CompilationReportKey"; 16 | internal const string LogEnabledPref = "AsmdefDebugLogKey"; 17 | 18 | private static readonly int ScriptAssembliesPathLen = "Library/ScriptAssemblies/".Length; 19 | private static readonly CompilationReport CompilationReport = new CompilationReport(); 20 | private static readonly Dictionary StartTimes = new Dictionary(); 21 | internal static TimeSpan AssemblyReloadTime { get; private set; } 22 | 23 | private static double compilationTotalTime; 24 | 25 | #if !IGNORE_ASMDEF_DEBUG 26 | static AsmdefDebug() 27 | { 28 | CompilationPipeline.assemblyCompilationStarted += CompilationPipelineOnAssemblyCompilationStarted; 29 | CompilationPipeline.assemblyCompilationFinished += CompilationPipelineOnAssemblyCompilationFinished; 30 | AssemblyReloadEvents.beforeAssemblyReload += AssemblyReloadEventsOnBeforeAssemblyReload; 31 | AssemblyReloadEvents.afterAssemblyReload += AssemblyReloadEventsOnAfterAssemblyReload; 32 | } 33 | #endif 34 | 35 | private static void CompilationPipelineOnAssemblyCompilationStarted(string assembly) 36 | { 37 | StartTimes[assembly] = DateTime.UtcNow; 38 | } 39 | 40 | private static void CompilationPipelineOnAssemblyCompilationFinished(string assembly, CompilerMessage[] arg2) 41 | { 42 | var timeSpan = DateTime.UtcNow - StartTimes[assembly]; 43 | compilationTotalTime += timeSpan.TotalMilliseconds; 44 | var assemblyTime = (timeSpan.TotalMilliseconds / 1000); 45 | var assemblyName = assembly.Substring(ScriptAssembliesPathLen, assembly.Length - ScriptAssembliesPathLen); 46 | CompilationReport.assemblyCompilations.Add(new AssemblyCompilation(assemblyName, assemblyTime)); 47 | } 48 | 49 | private static void AssemblyReloadEventsOnBeforeAssemblyReload() 50 | { 51 | var totalCompilationTimeSeconds = compilationTotalTime / 1000f; 52 | CompilationReport.compilationTotalTime = totalCompilationTimeSeconds; 53 | CompilationReport.reloadEventTimes = DateTime.UtcNow.ToBinary(); 54 | EditorPrefs.SetString(CompilationReportEditorPref, JsonUtility.ToJson(CompilationReport)); 55 | } 56 | 57 | private static void AssemblyReloadEventsOnAfterAssemblyReload() 58 | { 59 | var reportJson = EditorPrefs.GetString(CompilationReportEditorPref); 60 | if (string.IsNullOrEmpty(reportJson)) 61 | { 62 | return; 63 | } 64 | 65 | var report = JsonUtility.FromJson(reportJson); 66 | 67 | var date = DateTime.FromBinary(report.reloadEventTimes); 68 | AssemblyReloadTime = DateTime.UtcNow - date; 69 | 70 | if (!EditorPrefs.GetBool(LogEnabledPref, true)) 71 | { 72 | return; 73 | } 74 | 75 | var totalTimeSeconds = report.compilationTotalTime + AssemblyReloadTime.TotalSeconds; 76 | if (report.assemblyCompilations != null && report.assemblyCompilations.Any()) 77 | { 78 | var builder = new StringBuilder(); 79 | builder.AppendLine($"Compilation Report: {totalTimeSeconds:F2} seconds"); 80 | var orderedCompilations = report.assemblyCompilations.OrderBy(x => x.compilationTime).Reverse(); 81 | foreach (var assCom in orderedCompilations) 82 | { 83 | builder.AppendFormat("{0:0.00}s {1}\n", assCom.compilationTime, assCom.assemblyName); 84 | } 85 | 86 | builder.AppendFormat("Assembly Reload Time: {0}\n", AssemblyReloadTime.TotalSeconds); 87 | 88 | Debug.Log(builder.ToString()); 89 | } 90 | } 91 | } -------------------------------------------------------------------------------- /AsmdefDebug.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f5ea0d9e16d36d34a93872361ce01838 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /AsmdefDebugWindow.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using UnityEditor; 4 | using UnityEditor.Callbacks; 5 | using UnityEngine; 6 | 7 | namespace AssemblyDebugger 8 | { 9 | public class AsmdefDebugWindow : EditorWindow 10 | { 11 | private static string reportJson; 12 | private static CompilationReport report; 13 | private bool logEnabled; 14 | private Vector2 scrollPos; 15 | 16 | [MenuItem("Window/Assemblies Debugger")] 17 | private static void Init() 18 | { 19 | var window = (AsmdefDebugWindow) GetWindow(typeof(AsmdefDebugWindow), false, "Assembly Debugger"); 20 | window.Show(); 21 | } 22 | 23 | #if !IGNORE_ASMDEF_DEBUG 24 | [DidReloadScripts] 25 | #endif 26 | private static void OnReload() 27 | { 28 | reportJson = EditorPrefs.GetString(AsmdefDebug.CompilationReportEditorPref); 29 | } 30 | 31 | private static CompilationReport GenerateReport(string json) 32 | { 33 | if (string.IsNullOrEmpty(json)) 34 | { 35 | return null; 36 | } 37 | 38 | return JsonUtility.FromJson(json); 39 | } 40 | 41 | private void OnEnable() 42 | { 43 | logEnabled = EditorPrefs.GetBool(AsmdefDebug.LogEnabledPref, true); 44 | } 45 | 46 | private void OnGUI() 47 | { 48 | #if IGNORE_ASMDEF_DEBUG 49 | EditorGUILayout.HelpBox( 50 | "Utility won't work until IGNORE_ASMDEF_DEBUG is removed from Scripting Define Symbols", 51 | MessageType.Error); 52 | #else 53 | if (report == null) 54 | { 55 | report = GenerateReport(reportJson); 56 | } 57 | 58 | if (report == null) 59 | { 60 | EditorGUILayout.HelpBox( 61 | "No compilation report found. Modify a script to trigger a recompilation", MessageType.Warning); 62 | return; 63 | } 64 | 65 | GUILayout.Label("Post Compilation Report", EditorStyles.boldLabel); 66 | 67 | var date = DateTime.FromBinary(report.reloadEventTimes); 68 | var totalTimeSeconds = report.compilationTotalTime + AsmdefDebug.AssemblyReloadTime.TotalSeconds; 69 | 70 | EditorGUILayout.TextField("Compilation Report", $"{totalTimeSeconds:F2} seconds", EditorStyles.boldLabel); 71 | var orderedCompilations = report.assemblyCompilations.OrderBy(x => x.compilationTime).Reverse(); 72 | 73 | scrollPos = EditorGUILayout.BeginScrollView(scrollPos); 74 | 75 | foreach (var assCom in orderedCompilations) 76 | { 77 | EditorGUILayout.TextField(assCom.assemblyName, $"{assCom.compilationTime:0.00}s", EditorStyles.label); 78 | } 79 | 80 | EditorGUILayout.EndScrollView(); 81 | 82 | EditorGUILayout.FloatField("Assembly Reload Time", (float) AsmdefDebug.AssemblyReloadTime.TotalSeconds, 83 | EditorStyles.boldLabel); 84 | 85 | 86 | GUILayout.Label("Print compilation time after reload", EditorStyles.boldLabel); 87 | var enableLog = EditorGUILayout.Toggle("Use Debug.Log", logEnabled); 88 | 89 | if (logEnabled != enableLog) 90 | { 91 | EditorPrefs.SetBool(AsmdefDebug.LogEnabledPref, enableLog); 92 | logEnabled = enableLog; 93 | } 94 | #endif 95 | } 96 | } 97 | } -------------------------------------------------------------------------------- /AsmdefDebugWindow.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 94de90b0a6424afda2bd16c3f9a0139f 3 | timeCreated: 1591283768 -------------------------------------------------------------------------------- /Assembly.Debugger.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Assembly.Debugger", 3 | "references": [], 4 | "optionalUnityReferences": [], 5 | "includePlatforms": [ 6 | "Editor" 7 | ], 8 | "excludePlatforms": [], 9 | "allowUnsafeCode": false, 10 | "overrideReferences": false, 11 | "precompiledReferences": [], 12 | "autoReferenced": true, 13 | "defineConstraints": [] 14 | } -------------------------------------------------------------------------------- /Assembly.Debugger.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5c935facf435e8344af5f347c9a093ec 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /CompilationReport.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace AssemblyDebugger 5 | { 6 | [Serializable] 7 | internal class CompilationReport 8 | { 9 | public CompilationReport() 10 | { 11 | assemblyCompilations = new List(); 12 | } 13 | 14 | public double compilationTotalTime; 15 | public List assemblyCompilations; 16 | public long reloadEventTimes; 17 | } 18 | 19 | [Serializable] 20 | internal class AssemblyCompilation 21 | { 22 | public AssemblyCompilation(string assemblyName, double compilationTime) 23 | { 24 | this.assemblyName = assemblyName; 25 | this.compilationTime = compilationTime; 26 | } 27 | 28 | public double compilationTime; 29 | public string assemblyName; 30 | } 31 | } -------------------------------------------------------------------------------- /CompilationReport.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5fc5f8fe8841469388ce66bda972d4ae 3 | timeCreated: 1591284276 -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) [year] [fullname] 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LICENSE.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: be418fe7d28a438a8111e4931945a369 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Unity Assemblies Debugger 2 | 3 | Small utility to show the time it takes to compile each assembly after a reload. 4 | 5 | 6 | 7 | ## Usage 8 | 9 | Just by installing this in your project it will load itself on every reload. 10 | 11 | If you want to see the report, you can open the utility window at `Window > Assemblies Debugger`. 12 | 13 | ### Logs 14 | 15 | By default it will use the console to print the total reloading time. 16 | 17 | You can see an example log here: 18 | 19 | ``` 20 | Compilation Report: 4.14 seconds 21 | 0.62s Unity.TextMeshPro.dll 22 | 0.44s Unity.Analytics.DataPrivacy.dll 23 | 0.44s Unity.PackageManagerUI.Editor.dll 24 | 0.43s Assembly.Debugger.dll 25 | 0.42s Unity.CollabProxy.Editor.dll 26 | 0.30s Unity.TextMeshPro.Editor.dll 27 | 0.24s Assembly-CSharp.dll 28 | Assembly Reload Time: 1.2500003 29 | ``` 30 | 31 | #### Disabling the logs 32 | 33 | If you wish to disable the logs, you can set this in the checkbox in the utility window. 34 | 35 | ### Disabling whole plugin 36 | 37 | If, for some reason, you want to disable the plugin without removing it, you can add the Scripting Define Symbol 38 | `IGNORE_ASMDEF_DEBUG` to your project and it will stop analyzing the reload times. 39 | 40 | ## Installation 41 | 42 | ### Adding the package to the Unity project manifest 43 | 44 | * Navigate to the `Packages` directory of your project. 45 | * Adjust the [project manifest file][Project-Manifest] `manifest.json` in a text editor. 46 | * Ensure `https://package.openupm.com` is part of `scopedRegistries`. 47 | * Ensure `dev.bullrich` is part of `scopes`. 48 | * Add `dev.bullrich.asmdef-debug` to `dependencies`, stating the latest version. 49 | 50 | A minimal example ends up looking like this. 51 | Please note that the version `X.Y.Z` stated here is to be replaced with the latest released version which is currently [![Release][Version-Release]][Releases]. 52 | ```json 53 | { 54 | "scopedRegistries": [ 55 | { 56 | "name": "package.openupm.com", 57 | "url": "https://package.openupm.com", 58 | "scopes": [ 59 | "dev.bullrich", 60 | "com.openupm" 61 | ] 62 | } 63 | ], 64 | "dependencies": { 65 | "dev.bullrich.asmdef-debug": "X.Y.Z", 66 | } 67 | } 68 | ``` 69 | * Switch back to the Unity software and wait for it to finish importing the added package. 70 | 71 | [Project-Manifest]: https://docs.unity3d.com/Manual/upm-manifestPrj.html 72 | [Version-Release]: https://img.shields.io/npm/v/dev.bullrich.asmdef-debug?label=openupm®istry_uri=https://package.openupm.com 73 | [Releases]: https://openupm.com/packages/dev.bullrich.asmdef-debug/ -------------------------------------------------------------------------------- /README.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 33f5c585403c4bbf9a1472a3e89658bd 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dev.bullrich.asmdef-debug", 3 | "version": "1.1.0", 4 | "displayName": "Asmdef Debug", 5 | "description": "Utility to debug the amount of time each assembly takes to reload", 6 | "unity": "2018.4", 7 | "unityRelease": "8f1", 8 | "keywords": [ 9 | "asmdef", 10 | "debug", 11 | "unity" 12 | ], 13 | "homepage": "https://github.com/Bullrich/Unity-Assembly-Debugger/", 14 | "bugs": { 15 | "url": "https://github.com/Bullrich/Unity-Assembly-Debugger/issues" 16 | }, 17 | "repository": { 18 | "type": "git", 19 | "url": "ssh://git@github.com:Bullrich/Unity-Assembly-Debugger.git" 20 | }, 21 | "license": "MIT", 22 | "author": { 23 | "name": "Javier Bullrich", 24 | "email": "javier@bullrich.dev", 25 | "url": "https://bullrich.dev" 26 | }, 27 | "files": [ 28 | "*.md", 29 | "*.meta", 30 | "*.asmdef", 31 | "*.xml", 32 | "*.cs" 33 | ] 34 | } -------------------------------------------------------------------------------- /package.json.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8e99a502401b4380818569282b3acb95 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | --------------------------------------------------------------------------------