Enhance Profiler with Label Metrics and Rolling Windows

- Introduced LabelMetrics and RollingLabelMetrics structs to capture detailed profiling data.
- Implemented a RollingWindow class to maintain a rolling average of metrics.
- Updated Frame class to collect and store label metrics, including memory allocation and garbage collection statistics.
- Enhanced ScopeNode class to support self-time calculations and child duration tracking.
- Improved the Profiler class to manage frame budgets and rolling metrics.
- Refactored the ProfilerVisualizer to support new timeline rendering features, including zoom and pan functionality.
- Added tooltip support for detailed node information in the flame graph.
- Enhanced BoundedQueue to be thread-safe with proper locking mechanisms for concurrent access.
This commit is contained in:
max
2026-08-04 17:19:00 +02:00
parent 5eaf3547dc
commit 2d4139fb2c
4 changed files with 1021 additions and 234 deletions
+75 -18
View File
@@ -5,6 +5,7 @@ namespace Nerfed.Runtime;
public class BoundedQueue<T> : IEnumerable<T>, ICollection, IReadOnlyCollection<T>
{
private readonly Queue<T> queue = null;
private readonly object syncLock = new object();
private readonly int maxSize = 10;
private T lastAddedElement;
@@ -16,58 +17,114 @@ public class BoundedQueue<T> : IEnumerable<T>, ICollection, IReadOnlyCollection<
public void Enqueue(T item)
{
queue.Enqueue(item);
if (queue.Count > maxSize)
{
queue.Dequeue(); // Remove the oldest element
}
Enqueue(item, out _);
}
lastAddedElement = item;
public bool Enqueue(T item, out T evictedItem)
{
lock (syncLock)
{
queue.Enqueue(item);
if (queue.Count > maxSize)
{
evictedItem = queue.Dequeue();
lastAddedElement = item;
return true;
}
evictedItem = default;
lastAddedElement = item;
return false;
}
}
public T Dequeue()
{
return queue.Dequeue();
lock (syncLock)
{
return queue.Dequeue();
}
}
public T Peek()
{
return queue.Peek();
lock (syncLock)
{
return queue.Peek();
}
}
public T LastAddedElement()
{
return lastAddedElement;
lock (syncLock)
{
return lastAddedElement;
}
}
public void Clear()
{
queue.Clear();
lock (syncLock)
{
queue.Clear();
}
}
public bool Contains(T item)
{
return queue.Contains(item);
lock (syncLock)
{
return queue.Contains(item);
}
}
public IEnumerator<T> GetEnumerator()
{
return queue.GetEnumerator();
T[] snapshot;
lock (syncLock)
{
snapshot = queue.ToArray();
}
return ((IEnumerable<T>)snapshot).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return queue.GetEnumerator();
return GetEnumerator();
}
public void CopyTo(Array array, int index)
{
((ICollection)queue).CopyTo(array, index);
lock (syncLock)
{
((ICollection)queue).CopyTo(array, index);
}
}
public int Count
{
get
{
lock (syncLock)
{
return queue.Count;
}
}
}
public int Count => queue.Count;
public int Capacity => maxSize;
public bool IsSynchronized => ((ICollection)queue).IsSynchronized;
public object SyncRoot => ((ICollection)queue).SyncRoot;
int IReadOnlyCollection<T>.Count => queue.Count;
public bool IsSynchronized => true;
public object SyncRoot => syncLock;
int IReadOnlyCollection<T>.Count
{
get
{
lock (syncLock)
{
return queue.Count;
}
}
}
}