Decompiled source of NGPlus AdminTools v1.0.7

plugins/StartupProfiler.dll

Decompiled 2 years ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Logging;
using HarmonyLib;
using Mono.Cecil;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("StartupProfiler")]
[assembly: AssemblyDescription("Log and report the time each plugin takes to load")]
[assembly: AssemblyProduct("StartupProfiler")]
[assembly: Guid("6081c5ae-ab5a-456b-a29f-3eef9ad9eedf")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("https://github.com/BepInEx/BepInEx.Debug")]
[assembly: AssemblyCopyright("Copyright ©  2020")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: AssemblyVersion("9.0.0.0")]
namespace Common
{
	internal static class Metadata
	{
		public const string Version = "9.0";
	}
}
namespace StartupProfiler
{
	public class StartupProfiler
	{
		private static ManualLogSource logger;

		private static Harmony harmony;

		private static Stopwatch chainTimer;

		private static string[] unityMethods = new string[3] { "Awake", "Start", "Main" };

		private static readonly Dictionary<Type, KeyValuePair<BepInPlugin, Stopwatch>> timers = new Dictionary<Type, KeyValuePair<BepInPlugin, Stopwatch>>();

		public static MethodInfo StartTimerMethodInfo = typeof(StartupProfiler).GetMethod("StartTimer");

		public static MethodInfo StopTimerMethodInfo = typeof(StartupProfiler).GetMethod("StopTimer");

		public static IEnumerable<string> TargetDLLs { get; } = new string[0];


		public static void Patch(AssemblyDefinition ass)
		{
		}

		public static void Finish()
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Expected O, but got Unknown
			logger = Logger.CreateLogSource("StartupProfiler");
			harmony = new Harmony("StartupProfiler");
			harmony.Patch((MethodBase)typeof(Chainloader).GetMethod("Initialize"), (HarmonyMethod)null, new HarmonyMethod(typeof(StartupProfiler).GetMethod("ChainloaderHook")), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}

		public static void ChainloaderHook()
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Expected O, but got Unknown
			//IL_006b: Expected O, but got Unknown
			//IL_006b: Expected O, but got Unknown
			harmony.Patch((MethodBase)typeof(Chainloader).GetMethod("Start"), new HarmonyMethod(typeof(StartupProfiler).GetMethod("ChainloaderPre")), new HarmonyMethod(typeof(StartupProfiler).GetMethod("ChainloaderPost")), new HarmonyMethod(typeof(StartupProfiler).GetMethod("FindPluginTypes")), (HarmonyMethod)null, (HarmonyMethod)null);
		}

		public static void ChainloaderPre()
		{
			chainTimer = new Stopwatch();
			chainTimer.Start();
		}

		public static IEnumerable<CodeInstruction> FindPluginTypes(IEnumerable<CodeInstruction> instructions)
		{
			foreach (CodeInstruction code in instructions)
			{
				if (code.opcode == OpCodes.Callvirt && code.operand.ToString().Contains("AddComponent"))
				{
					yield return new CodeInstruction(OpCodes.Call, (object)typeof(StartupProfiler).GetMethod("PatchPlugin"));
				}
				yield return code;
			}
		}

		public static Type PatchPlugin(Type type)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Expected O, but got Unknown
			//IL_0087: Expected O, but got Unknown
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Expected O, but got Unknown
			//IL_00cb: Expected O, but got Unknown
			BepInPlugin key = (BepInPlugin)type.GetCustomAttributes(inherit: false).First((object x) => (object)x.GetType() == typeof(BepInPlugin));
			timers[type] = new KeyValuePair<BepInPlugin, Stopwatch>(key, new Stopwatch());
			string[] array = unityMethods;
			foreach (string name in array)
			{
				MethodInfo method = type.GetMethod(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if ((object)method != null)
				{
					harmony.Patch((MethodBase)method, new HarmonyMethod(StartTimerMethodInfo), new HarmonyMethod(StopTimerMethodInfo), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
			}
			ConstructorInfo[] constructors = type.GetConstructors(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (ConstructorInfo constructorInfo in constructors)
			{
				harmony.Patch((MethodBase)constructorInfo, new HarmonyMethod(StartTimerMethodInfo), new HarmonyMethod(StopTimerMethodInfo), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			return type;
		}

		public static void StartTimer(object __instance)
		{
			if (timers.TryGetValue(__instance.GetType(), out var value))
			{
				value.Value.Start();
			}
		}

		public static void StopTimer(object __instance)
		{
			if (timers.TryGetValue(__instance.GetType(), out var value))
			{
				value.Value.Stop();
			}
		}

		public static void ChainloaderPost()
		{
			chainTimer.Stop();
			((MonoBehaviour)ThreadingHelper.Instance).StartCoroutine(PrintResults());
		}

		public static IEnumerator PrintResults()
		{
			yield return null;
			logger.LogInfo((object)$"Chainloader total: {chainTimer.ElapsedMilliseconds} ms");
			logger.LogInfo((object)$"Plugins total: {timers.Sum((KeyValuePair<Type, KeyValuePair<BepInPlugin, Stopwatch>> x) => x.Value.Value.ElapsedMilliseconds)} ms");
			foreach (KeyValuePair<Type, KeyValuePair<BepInPlugin, Stopwatch>> item in timers.OrderByDescending((KeyValuePair<Type, KeyValuePair<BepInPlugin, Stopwatch>> x) => x.Value.Value.ElapsedMilliseconds))
			{
				logger.LogInfo((object)$"{item.Value.Key.GUID}: {item.Value.Value.ElapsedMilliseconds} ms");
			}
			harmony.UnpatchAll(harmony.Id);
		}
	}
}