Skip to content

Commit

Permalink
Merge pull request #14 from esnya/feature/object-root-include-children
Browse files Browse the repository at this point in the history
Feature/object root include children
  • Loading branch information
esnya authored Jan 5, 2025
2 parents 4476248 + 6d1c37f commit cc5641d
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 88 deletions.
15 changes: 12 additions & 3 deletions ResoniteMetricsCounter/Metrics/MetricsCounter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ public sealed class MetricsCounter : IDisposable
[JsonInclude] public long ElapsedMilliseconds => stopwatch.ElapsedMilliseconds;
public long ElapsedTicks => stopwatch.ElapsedTicks;

[JsonInclude] public int FrameCount { get; private set; }

public MetricsCounter(IEnumerable<string> blackList)
{
shouldSkip = new(ShouldSkipImpl);
Expand All @@ -48,8 +50,7 @@ public MetricsCounter(IEnumerable<string> blackList)

private bool ShouldSkipImpl(IWorldElement element)
{
var world = element.World;
if (world.Focus != World.WorldFocus.Focused || !ResoniteMetricsCounterMod.CollectStage(world.Stage))
if (element.World.Focus != World.WorldFocus.Focused)
{
return true;
}
Expand Down Expand Up @@ -119,7 +120,10 @@ private void AddForCurrentStage(IWorldElement element, long ticks)
return;
}

ByObjectRoot.Add(objectRoot, ticks);
for (var slot = objectRoot; slot != null; slot = slot.Parent?.GetMetricObjectRoot())
{
ByObjectRoot.Add(slot, ticks);
}
}

private static readonly JsonSerializerOptions jsonSerializerOptions = new()
Expand Down Expand Up @@ -161,4 +165,9 @@ internal void IgnoreHierarchy(Slot slot)
{
IgnoredHierarchy = slot;
}

internal void OnUpdate()
{
FrameCount++;
}
}
171 changes: 93 additions & 78 deletions ResoniteMetricsCounter/Patch/Metric_Profiler_Patch.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using FrooxEngine;
using FrooxEngine;
using FrooxEngine.ProtoFlux;
using HarmonyLib;
using ResoniteModLoader;
Expand All @@ -10,8 +10,8 @@

namespace ResoniteMetricsCounter.Patch;

[HarmonyPatch]
[HarmonyPatchCategory(Category.PROFILER)]
#pragma warning disable CA1859

internal static class Metric_Profiler_Patch
{
private static readonly Stopwatch stopwatch = new();
Expand All @@ -29,101 +29,116 @@ private static void Record(IWorldElement element)
ResoniteMetricsCounterMod.Writer?.AddForCurrentStage(element, stopwatch.ElapsedTicks);
}

[HarmonyPatchCategory("ProtoFluxUpdates")]
[HarmonyPatch(typeof(ProtoFluxController), nameof(ProtoFluxController.RunNodeUpdates))]
[HarmonyTranspiler]
internal static IEnumerable<CodeInstruction> RunNodeUpdatesTranspiler(IEnumerable<CodeInstruction> instructions)
private static class RunNodeUpdates_Patch
{
ResoniteMod.Debug("Patching method for ProtoFluxUpdates");
var matcher = new CodeMatcher(instructions)
.MatchStartForward(CodeMatch.Calls(() => default(ProtoFluxNodeGroup)!.RunNodeUpdates()))
.ThrowIfNotMatchForward("Failed to match RunNodeUpdates call")
.InsertAndAdvance(
CodeInstruction.Call(() => StartTimer()),
new CodeInstruction(OpCodes.Dup)
)
.Advance(1)
.InsertAndAdvance(
CodeInstruction.Call(() => Record(default!))
);
return matcher.Instructions();
internal static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
ResoniteMod.Debug("Patching method for ProtoFluxUpdates");
var matcher = new CodeMatcher(instructions)
.MatchStartForward(CodeMatch.Calls(() => default(ProtoFluxNodeGroup)!.RunNodeUpdates()))
.ThrowIfNotMatchForward("Failed to match RunNodeUpdates call")
.InsertAndAdvance(
CodeInstruction.Call(() => StartTimer()),
new CodeInstruction(OpCodes.Dup)
)
.Advance(1)
.InsertAndAdvance(
CodeInstruction.Call(() => Record(default!))
);
return matcher.Instructions();
}
}

[HarmonyPatchCategory("ProtoFluxContinuousChanges")]
[HarmonyPatch(typeof(ProtoFluxController), nameof(ProtoFluxController.RunContinuousChanges))]
[HarmonyTranspiler]
internal static IEnumerable<CodeInstruction> RunContinuousChangesTranspiler(IEnumerable<CodeInstruction> instructions)
private static class RunContinuousChanges_Patch
{
ResoniteMod.Debug("Patching method for ProtoFluxContinuousChanges");
var matcher = new CodeMatcher(instructions)
.MatchStartForward(CodeMatch.Calls(() => default(ProtoFluxNodeGroup)!.RunNodeChanges()))
.ThrowIfNotMatchForward("Failed to match RunContinuousChanges call")
.InsertAndAdvance(
CodeInstruction.Call(() => StartTimer()),
new CodeInstruction(OpCodes.Dup)
)
.Advance(1)
.InsertAndAdvance(
CodeInstruction.Call(() => Record(default!))
);

return matcher.Instructions();

internal static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
ResoniteMod.Debug("Patching method for ProtoFluxContinuousChanges");
var matcher = new CodeMatcher(instructions)
.MatchStartForward(CodeMatch.Calls(() => default(ProtoFluxNodeGroup)!.RunNodeChanges()))
.ThrowIfNotMatchForward("Failed to match RunContinuousChanges call")
.InsertAndAdvance(
CodeInstruction.Call(() => StartTimer()),
new CodeInstruction(OpCodes.Dup)
)
.Advance(1)
.InsertAndAdvance(
CodeInstruction.Call(() => Record(default!))
);

return matcher.Instructions();
}
}

[HarmonyPatchCategory("Updates")]

[HarmonyPatch(typeof(UpdateManager), nameof(UpdateManager.RunUpdates))]
[HarmonyTranspiler]
internal static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
private static class RunUpdates_Patch
{
ResoniteMod.Debug("Patching method for Updates");
var matcher = new CodeMatcher(instructions)
.MatchStartForward(CodeMatch.Calls(() => default(IUpdatable)!.InternalRunUpdate()))
.ThrowIfNotMatchForward("Failed to match InternalRunUpdate call")
.InsertAndAdvance(
new CodeInstruction(OpCodes.Dup),
CodeInstruction.Call(() => StartTimer())
)
.Advance(1)
.InsertAndAdvance(
CodeInstruction.Call(() => Record(default!))
);

return matcher.Instructions();
internal static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
ResoniteMod.Debug("Patching method for Updates");
var matcher = new CodeMatcher(instructions)
.MatchStartForward(CodeMatch.Calls(() => default(IUpdatable)!.InternalRunUpdate()))
.ThrowIfNotMatchForward("Failed to match InternalRunUpdate call")
.InsertAndAdvance(
new CodeInstruction(OpCodes.Dup),
CodeInstruction.Call(() => StartTimer())
)
.Advance(1)
.InsertAndAdvance(
CodeInstruction.Call(() => Record(default!))
);
return matcher.Instructions();
}
}

[HarmonyPatchCategory(nameof(World.RefreshStage.Changes))]
[HarmonyPatch(typeof(UpdateManager), "ProcessChange")]
[HarmonyTranspiler]
internal static IEnumerable<CodeInstruction> ProcessChangeTranspiler(IEnumerable<CodeInstruction> instructions)
private static class ProcessChange_Patch
{
ResoniteMod.Debug("Patching method for Changes");
var matcher = new CodeMatcher(instructions)
.MatchStartForward(CodeMatch.Calls(() => default(IUpdatable)!.InternalRunApplyChanges(default)))
.ThrowIfNotMatchForward("Failed to match InternalRunApplyChanges call")
.InsertAndAdvance(CodeInstruction.Call(() => StartTimer()))
.Advance(1)
.InsertAndAdvance(
CodeInstruction.LoadArgument(1),
CodeInstruction.Call(() => Record(default!))
);
return matcher.Instructions();
internal static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
ResoniteMod.Debug("Patching method for Changes");
var matcher = new CodeMatcher(instructions)
.MatchStartForward(CodeMatch.Calls(() => default(IUpdatable)!.InternalRunApplyChanges(default)))
.ThrowIfNotMatchForward("Failed to match InternalRunApplyChanges call")
.InsertAndAdvance(CodeInstruction.Call(() => StartTimer()))
.Advance(1)
.InsertAndAdvance(
CodeInstruction.LoadArgument(1),
CodeInstruction.Call(() => Record(default!))
);
return matcher.Instructions();
}
}

[HarmonyPatchCategory("Connectors")]
[HarmonyPatch(typeof(UpdateManager), "ProcessConnectorUpdate")]
[HarmonyTranspiler]
internal static IEnumerable<CodeInstruction> ProcessConnectorUpdateTranspiler(IEnumerable<CodeInstruction> instructions)
private static class ProcessConnectorUpdate_Patch
{
ResoniteMod.Debug("Patching method for Connectors");
var matcher = new CodeMatcher(instructions)
.MatchStartForward(CodeMatch.Calls(() => default(IImplementable)!.InternalUpdateConnector()))
.ThrowIfNotMatchForward("Failed to match InternalUpdateConnector call")
.InsertAndAdvance(CodeInstruction.Call(() => StartTimer()))
.Advance(1)
.InsertAndAdvance(
CodeInstruction.LoadArgument(1),
CodeInstruction.Call(() => Record(default!)
)
);
return matcher.Instructions();
internal static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
ResoniteMod.Debug("Patching method for Connectors");
var matcher = new CodeMatcher(instructions)
.MatchStartForward(CodeMatch.Calls(() => default(IImplementable)!.InternalUpdateConnector()))
.ThrowIfNotMatchForward("Failed to match InternalUpdateConnector call")
.InsertAndAdvance(CodeInstruction.Call(() => StartTimer()))
.Advance(1)
.InsertAndAdvance(
CodeInstruction.LoadArgument(1),
CodeInstruction.Call(() => Record(default!))
);
return matcher.Instructions();
}
}

[HarmonyPatchCategory(Category.PROFILER)]
[HarmonyPatchCategory("PhysicsMoved")]
[HarmonyPatch]
internal static class PhysicsMovedHierarchyEventManager_RunMovedEvent_Patch
{
Expand Down
21 changes: 14 additions & 7 deletions ResoniteMetricsCounter/ResoniteMetricsCounterMod.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,12 +99,6 @@ public override void OnEngineInit()
#endif
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool CollectStage(World.RefreshStage stage)
{
return collectStage.TryGetValue(stage, out var value) && value;
}

private static void Init(ResoniteMod modInstance)
{
harmony.PatchCategory(Category.CORE);
Expand Down Expand Up @@ -146,7 +140,6 @@ public static void OnHotReload(ResoniteMod modInstance)
}
#endif


public static IEnumerable<string> ParseCommaSeparatedString(string? str)
{
return str?.Split(',')?.Select(item => item.Trim()).Where(item => item.Length > 0) ?? Enumerable.Empty<string>();
Expand All @@ -158,13 +151,27 @@ public static void Start(Slot slot)
var blackList = ParseCommaSeparatedString(config?.GetValue(blackListKey));
Writer = new MetricsCounter(blackList);
Panel = new MetricsPanel(slot, Writer, config?.GetValue(panelSizeKey) ?? new float2(1200, 1200), config?.GetValue(maxItemsKey) ?? 256);

foreach (var key in stageConfigKeys)
{
var collect = config?.GetValue(key.Value) ?? true;
if (collect)
{
harmony.PatchCategory(key.Key.ToString());
}
}
harmony.PatchCategory(Category.PROFILER);
}

public static void Stop()
{
Msg("Stopping Profiler");
foreach (var key in stageConfigKeys)
{
harmony.UnpatchCategory(key.Key.ToString());
}
harmony.UnpatchCategory(Category.PROFILER);

Writer?.Dispose();
WorldElementHelper.Clear();
Panel = null;
Expand Down

0 comments on commit cc5641d

Please sign in to comment.