From 88cf2e14b796a3240f3b79a85e421bce76cccb1c Mon Sep 17 00:00:00 2001 From: bd_ Date: Sat, 16 Mar 2024 15:57:11 +0900 Subject: [PATCH] chore: additional debugging to try to track down FreeSegment issues (#781) --- Runtime/ArmatureAwase/AllocationMap.cs | 10 ++- UnitTests~/ArmatureAwase/AllocationMapTest.cs | 61 ++++++++++++++++++- 2 files changed, 69 insertions(+), 2 deletions(-) diff --git a/Runtime/ArmatureAwase/AllocationMap.cs b/Runtime/ArmatureAwase/AllocationMap.cs index d300c551..11dd16c4 100644 --- a/Runtime/ArmatureAwase/AllocationMap.cs +++ b/Runtime/ArmatureAwase/AllocationMap.cs @@ -2,6 +2,8 @@ using System; using System.Collections.Generic; +using System.Runtime.CompilerServices; +using UnityEngine; #endregion @@ -102,7 +104,13 @@ namespace nadena.dev.modular_avatar.core.armature_lock if (s == null) throw new ArgumentException("Passed a foreign segment???"); int index = segments.BinarySearch(s, Comparer.Create((a, b) => a._offset.CompareTo(b._offset))); - if (index < 0 || segments[index] != s) throw new Exception("Segment not found in FreeSegment"); + if (index < 0 || segments[index] != s) + { + var segmentDump = string.Join("\n", segments.ConvertAll(seg => $"{seg._offset} {seg._length} {seg._inUse} id={RuntimeHelpers.GetHashCode(seg)}")); + segmentDump += "\n\nTarget segment " + s._offset + " " + s._length + " " + s._inUse + " id=" + RuntimeHelpers.GetHashCode(s); + + throw new Exception("Segment not found in FreeSegment\nCurrent segments:\n" + segmentDump); + } if (index == segments.Count - 1) { diff --git a/UnitTests~/ArmatureAwase/AllocationMapTest.cs b/UnitTests~/ArmatureAwase/AllocationMapTest.cs index a5104b38..cfc91abb 100644 --- a/UnitTests~/ArmatureAwase/AllocationMapTest.cs +++ b/UnitTests~/ArmatureAwase/AllocationMapTest.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using nadena.dev.modular_avatar.core.armature_lock; using NUnit.Framework; @@ -66,6 +67,64 @@ namespace UnitTests.ArmatureAwase AssertSegment(s4, 0, 20, true); } + enum Op + { + Allocate, Deallocate, Defrag + } + + [Test] + public void SegmentRandomOps() + { + for (int i = 0; i < 1000; i++) + { + AllocationMap map = new AllocationMap(); + + List segments = new List(); + List<(Op, int)> ops = new List<(Op, int)>(); + + try + { + Random r = new Random(); + for (int j = 0; j < 100; j++) + { + switch (r.Next(0, segments.Count == 0 ? 1 : 3)) + { + case 0: + { + int segSize = r.Next(1, 16); + ISegment s = map.Allocate(segSize); + ops.Add((Op.Allocate, segSize)); + segments.Add(s); + break; + } + case 1: + { + int idx = r.Next(0, segments.Count); + ISegment s = segments[idx]; + map.FreeSegment(s); + ops.Add((Op.Deallocate, idx)); + segments.RemoveAt(idx); + break; + } + case 2: + { + ops.Add((Op.Defrag, 0)); + map.Defragment((src, dst, length) => {}); + break; + } + + } + } + } + catch (Exception e) + { + var trace = string.Join("\n", ops.ConvertAll(op => $"{op.Item1} {op.Item2}")); + Assert.Fail($"Failed at iteration {i} with exception {e}\n{trace}"); + throw; + } + } + } + private void AssertSegment(ISegment segment, int offset, int length, bool inUse) { var s = segment as AllocationMap.Segment;