diff --git a/RuntimeUnityEditor.Core/Windows/Breakpoints/BreakpointHit.cs b/RuntimeUnityEditor.Core/Windows/Breakpoints/BreakpointHit.cs index 35a76f4..acd3219 100644 --- a/RuntimeUnityEditor.Core/Windows/Breakpoints/BreakpointHit.cs +++ b/RuntimeUnityEditor.Core/Windows/Breakpoints/BreakpointHit.cs @@ -12,15 +12,21 @@ public sealed class BreakpointHit /// /// Create a new breakpoint hit. /// - public BreakpointHit(BreakpointPatchInfo origin, object instance, object[] args, object result, StackTrace trace) + public BreakpointHit(BreakpointPatchInfo origin, object instance, StackTrace trace) { Origin = origin; Instance = instance; - Args = args; - Result = result; Trace = trace; TraceString = trace.ToString(); Time = DateTime.UtcNow; + _sw = Stopwatch.StartNew(); + } + + internal void Finalize(object[] args, object result) + { + ElapsedMilliseconds = _sw.ElapsedMilliseconds; + Args = args; + Result = result; } /// @@ -34,11 +40,11 @@ public BreakpointHit(BreakpointPatchInfo origin, object instance, object[] args, /// /// The arguments that were passed to the method. /// - public readonly object[] Args; + public object[] Args { get; private set; } /// /// The result of the method call. /// - public readonly object Result; + public object Result { get; private set; } /// /// The stack trace at the time of the hit. /// @@ -49,6 +55,12 @@ public BreakpointHit(BreakpointPatchInfo origin, object instance, object[] args, /// public readonly DateTime Time; + private readonly Stopwatch _sw; + /// + /// Gets the total time the target method ran for, in milliseconds. + /// + public long ElapsedMilliseconds { get; private set; } + private string _toStr, _searchStr; /// /// Returns a string that can be used to search for this breakpoint hit. diff --git a/RuntimeUnityEditor.Core/Windows/Breakpoints/Breakpoints.cs b/RuntimeUnityEditor.Core/Windows/Breakpoints/Breakpoints.cs index 0ac899e..a7c667a 100644 --- a/RuntimeUnityEditor.Core/Windows/Breakpoints/Breakpoints.cs +++ b/RuntimeUnityEditor.Core/Windows/Breakpoints/Breakpoints.cs @@ -12,8 +12,9 @@ namespace RuntimeUnityEditor.Core.Breakpoints public static class Breakpoints { private static readonly Harmony _harmony = new Harmony("RuntimeUnityEditor.Core.Breakpoints"); - private static readonly HarmonyMethod _handlerMethodRet = new HarmonyMethod(typeof(Hooks), nameof(Hooks.BreakpointHandlerReturn)); - private static readonly HarmonyMethod _handlerMethodNoRet = new HarmonyMethod(typeof(Hooks), nameof(Hooks.BreakpointHandlerNoReturn)); + private static readonly HarmonyMethod _handlerMethodPrefix = new HarmonyMethod(typeof(Hooks), nameof(Hooks.BreakpointHandlerPrefix)) { priority = Priority.First }; // wrap around other patches + private static readonly HarmonyMethod _handlerMethodRet = new HarmonyMethod(typeof(Hooks), nameof(Hooks.BreakpointHandlerReturn)) { priority = Priority.Last }; + private static readonly HarmonyMethod _handlerMethodNoRet = new HarmonyMethod(typeof(Hooks), nameof(Hooks.BreakpointHandlerNoReturn)) { priority = Priority.Last }; private static readonly Dictionary _appliedPatches = new Dictionary(); /// /// A collection of all applied patches. @@ -53,7 +54,7 @@ public static bool AttachBreakpoint(MethodBase target, object instance) } var hasReturn = target is MethodInfo mi && mi.ReturnType != typeof(void); - var patch = _harmony.Patch(target, postfix: hasReturn ? _handlerMethodRet : _handlerMethodNoRet); + var patch = _harmony.Patch(target, prefix: _handlerMethodPrefix, postfix: hasReturn ? _handlerMethodRet : _handlerMethodNoRet); if (patch != null) { _appliedPatches[target] = new BreakpointPatchInfo(target, patch, instance); @@ -111,17 +112,24 @@ public static void DetachAll() _appliedPatches.Clear(); } - private static void AddHit(object __instance, MethodBase __originalMethod, object[] __args, object __result) + private static BreakpointHit BeginHit(object __instance, MethodBase __originalMethod) { - if (!Enabled) return; + if (!Enabled) return null; - if (!_appliedPatches.TryGetValue(__originalMethod, out var pi)) return; + if (!_appliedPatches.TryGetValue(__originalMethod, out var pi)) return null; - if (pi.InstanceFilters.Count > 0 && !pi.InstanceFilters.Contains(__instance)) return; + if (pi.InstanceFilters.Count > 0 && !pi.InstanceFilters.Contains(__instance)) return null; + + return new BreakpointHit(pi, __instance, new StackTrace(2, true)); + } + + private static void EndHit(BreakpointHit hit, object[] __args, object __result) + { + hit.Finalize(__args, __result); if (DebuggerBreaking == DebuggerBreakType.ThrowCatch) { - try { throw new BreakpointHitException(pi.Target.Name); } + try { throw new BreakpointHitException(hit.Origin.Target.Name); } catch (BreakpointHitException) { } } else if (DebuggerBreaking == DebuggerBreakType.DebuggerBreak) @@ -129,19 +137,26 @@ private static void AddHit(object __instance, MethodBase __originalMethod, objec Debugger.Break(); } - OnBreakpointHit?.Invoke(new BreakpointHit(pi, __instance, __args, __result, new StackTrace(2, true))); + OnBreakpointHit?.Invoke(hit); } private static class Hooks { - public static void BreakpointHandlerReturn(object __instance, MethodBase __originalMethod, object[] __args, object __result) + public static void BreakpointHandlerPrefix(object __instance, MethodBase __originalMethod, ref BreakpointHit __state) + { + __state = BeginHit(__instance, __originalMethod); + } + + public static void BreakpointHandlerReturn(object[] __args, object __result, BreakpointHit __state) { - AddHit(__instance, __originalMethod, __args, __result); + if (__state != null) + EndHit(__state, __args, __result); } - public static void BreakpointHandlerNoReturn(object __instance, MethodBase __originalMethod, object[] __args) + public static void BreakpointHandlerNoReturn(object[] __args, BreakpointHit __state) { - AddHit(__instance, __originalMethod, __args, null); + if (__state != null) + EndHit(__state, __args, null); } } } diff --git a/RuntimeUnityEditor.Core/Windows/Breakpoints/BreakpointsWindow.cs b/RuntimeUnityEditor.Core/Windows/Breakpoints/BreakpointsWindow.cs index 2f70fef..1732613 100644 --- a/RuntimeUnityEditor.Core/Windows/Breakpoints/BreakpointsWindow.cs +++ b/RuntimeUnityEditor.Core/Windows/Breakpoints/BreakpointsWindow.cs @@ -169,7 +169,7 @@ private void DrawHits() GUILayout.BeginHorizontal(GUI.skin.box); { - GUILayout.Label($"{hit.Time:HH:mm:ss.fff}", GUILayout.Width(85)); + GUILayout.Label($"{hit.Time:HH:mm:ss.fff}\nTook {hit.ElapsedMilliseconds}ms", GUILayout.Width(85)); DrawHitOriginButton(hit.Origin);