diff --git a/.cr/personal/Editor/Right Margin Line/Right Margin Line.xml b/.cr/personal/Editor/Right Margin Line/Right Margin Line.xml
index b18e300f..4f8bf4f3 100644
--- a/.cr/personal/Editor/Right Margin Line/Right Margin Line.xml
+++ b/.cr/personal/Editor/Right Margin Line/Right Margin Line.xml
@@ -2,7 +2,7 @@
True
-
+
2
\ No newline at end of file
diff --git a/.cr/team/Editor/Formatting/Wrapping.CSharp.xml b/.cr/team/Editor/Formatting/Wrapping.CSharp.xml
index ee502938..8b5b7c97 100644
--- a/.cr/team/Editor/Formatting/Wrapping.CSharp.xml
+++ b/.cr/team/Editor/Formatting/Wrapping.CSharp.xml
@@ -11,11 +11,13 @@
-
-
+
+ WrapAfter
+ 4
diff --git a/StgSharp.Common/Collections/CapacityFixedStack.cs b/StgSharp.Common/Collections/CapacityFixedStack.cs
index 002e91db..e8389de7 100644
--- a/StgSharp.Common/Collections/CapacityFixedStack.cs
+++ b/StgSharp.Common/Collections/CapacityFixedStack.cs
@@ -29,6 +29,7 @@ using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
+using System.Threading;
namespace StgSharp.Collections
{
@@ -45,6 +46,8 @@ namespace StgSharp.Collections
_index = -1;
}
+ public T? First => Volatile.Read(ref _index) > 0 ? _values[0] : default;
+
public bool IsEmpty => _index == -1;
public int Count => _index + 1;
diff --git a/StgSharp.Common/Collections/ConcurrentCapacityFixedStack.cs b/StgSharp.Common/Collections/ConcurrentCapacityFixedStack.cs
new file mode 100644
index 00000000..92884837
--- /dev/null
+++ b/StgSharp.Common/Collections/ConcurrentCapacityFixedStack.cs
@@ -0,0 +1,287 @@
+//-----------------------------------------------------------------------
+// -----------------------------------------------------------------------
+// file="ConcurrentCapacityFixedStack"
+// Project: StgSharp
+// AuthorGroup: Nitload
+// Copyright (c) Nitload. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+//
+// -----------------------------------------------------------------------
+// -----------------------------------------------------------------------
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Runtime.CompilerServices;
+using System.Threading;
+
+namespace StgSharp.Collections
+{
+ ///
+ /// Lock-free, fixed-capacity stack implemented on top of an array using atomic index
+ /// operations. - No linked list; only array slots - Uses CAS on a shared top index to
+ /// reserve/release slots - Per-slot state flag to safely publish/consume values under races
+ ///
+ public class ConcurrentCapacityFixedStack : IEnumerable
+ {
+
+ private readonly int[] _states; // 0 = empty, 1 = full
+ private readonly T[] _values;
+ private readonly int _capacity;
+
+ // Number of full slots (observable count)
+ private int _count;
+
+ // Next push position (0.._capacity). Only modified via CAS.
+ private int _top;
+
+ public ConcurrentCapacityFixedStack(int capacity)
+ {
+ if (capacity <= 0) {
+ throw new ArgumentOutOfRangeException(nameof(capacity));
+ }
+
+ _capacity = capacity;
+ _values = new T[capacity];
+ _states = new int[capacity];
+ _top = 0;
+ _count = 0;
+ }
+
+ public bool IsEmpty => Count == 0;
+
+ public int Capacity => _capacity;
+
+ public int Count => Volatile.Read(ref _count);
+
+ public void Clear()
+ {
+ // Pop all elements to return slots to empty state
+ while (TryPop(out _)) { }
+ }
+
+ public IEnumerator GetEnumerator()
+ {
+ T[] snap = ToArraySnapshot();
+ for (int i = 0; i < snap.Length; i++) {
+ yield return snap[i];
+ }
+ }
+
+ public T Peek()
+ {
+ if (TryPeek(out T? v)) {
+ return v;
+ }
+
+ throw new InvalidOperationException("Stack is empty.");
+ }
+
+ public T Pop()
+ {
+ if (TryPop(out T value)) {
+ return value;
+ }
+
+ throw new InvalidOperationException("Stack is empty.");
+ }
+
+ public T[] PopRange(int count)
+ {
+ if (count <= 0) {
+ return [];
+ }
+
+ T[] result = new T[count];
+ int i = 0;
+ for (; i < count; i++)
+ {
+ if (!TryPop(out result[i]))
+ {
+ break;
+ }
+ }
+ if (i == count) {
+ return result;
+ }
+
+ if (i == 0) {
+ return [];
+ }
+
+ T[] trimmed = new T[i];
+ Array.Copy(result, trimmed, i);
+ return trimmed;
+ }
+
+ public void Push(T item)
+ {
+ SpinWait sw = default;
+ while (true)
+ {
+ int oldTop = Volatile.Read(ref _top);
+ if (oldTop >= _capacity) {
+ throw new InvalidOperationException("Stack is full.");
+ }
+
+ if (Interlocked.CompareExchange(ref _top, oldTop + 1, oldTop) != oldTop)
+ {
+ sw.SpinOnce();
+ continue; // failed to reserve slot
+ }
+
+ // We exclusively own slot oldTop. Publish value then state.
+ _values[oldTop] = item;
+ Volatile.Write(ref _states[oldTop], 1); // publish
+ _ = Interlocked.Increment(ref _count);
+ return;
+ }
+ }
+
+ public void PushRange(ReadOnlySpan span)
+ {
+ for (int i = 0; i < span.Length; i++) {
+ Push(span[i]);
+ }
+ }
+
+ ///
+ /// Best-effort snapshot for enumeration; not strongly consistent under concurrent
+ /// mutations.
+ ///
+ public T[] ToArraySnapshot()
+ {
+ int expected = Math.Min(Volatile.Read(ref _count), _capacity);
+ if (expected == 0) {
+ return Array.Empty();
+ }
+
+ T[] snap = new T[expected];
+ int copied = 0;
+ int idx = Volatile.Read(ref _top) - 1;
+ while (idx >= 0 && copied < expected)
+ {
+ if (Volatile.Read(ref _states[idx]) == 1) {
+ snap[copied++] = _values[idx];
+ }
+ idx--;
+ }
+
+ if (copied == snap.Length) {
+ return snap;
+ }
+
+ T[] trimmed = new T[copied];
+ Array.Copy(snap, trimmed, copied);
+ return trimmed;
+ }
+
+ public bool TryPeek(out T value)
+ {
+ value = default!;
+ SpinWait sw = default;
+
+ while (true)
+ {
+ int top = Volatile.Read(ref _top);
+ if (top <= 0) {
+ return false;
+ }
+ int idx = top - 1;
+
+ // If not yet published or racing, retry/spin
+ if (Volatile.Read(ref _states[idx]) == 0)
+ {
+ if (Volatile.Read(ref _top) != top)
+ {
+ continue; // head moved, retry
+ }
+ sw.SpinOnce();
+ continue;
+ }
+
+ T v = _values[idx];
+
+ // Validate consistency
+ if (Volatile.Read(ref _top) == top && Volatile.Read(ref _states[idx]) == 1)
+ {
+ value = v;
+ return true;
+ }
+ }
+ }
+
+ public bool TryPop(out T value)
+ {
+ value = default!;
+ SpinWait sw = default;
+
+ while (true)
+ {
+ int oldTop = Volatile.Read(ref _top);
+ if (oldTop <= 0)
+ {
+ return false; // empty
+ }
+
+ int newTop = oldTop - 1; // index to consume
+ if (Interlocked.CompareExchange(ref _top, newTop, oldTop) != oldTop)
+ {
+ sw.SpinOnce();
+ continue; // failed to reserve element
+ }
+
+ // If producer hasn't published yet, roll back our reservation and retry.
+ if (Volatile.Read(ref _states[newTop]) == 0)
+ {
+ // attempt to restore top; ok if it fails due to concurrent operations
+ _ = Interlocked.CompareExchange(ref _top, newTop + 1, newTop);
+ sw.SpinOnce();
+ continue;
+ }
+
+ value = _values[newTop];
+ _values[newTop] = default!; // avoid ref retention
+ Volatile.Write(ref _states[newTop], 0); // mark empty
+ _ = Interlocked.Decrement(ref _count);
+ return true;
+ }
+ }
+
+ public int TryPopRange(Span destination)
+ {
+ if (destination.IsEmpty) {
+ return 0;
+ }
+
+ int i = 0;
+ for (; i < destination.Length; i++)
+ {
+ if (!TryPop(out destination[i]))
+ {
+ break;
+ }
+ }
+ return i;
+ }
+
+ IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
+
+ }
+}
diff --git a/StgSharp.Common/HighPerformance/Memory/ConcurrentBufferStack.cs b/StgSharp.Common/HighPerformance/Memory/ConcurrentBufferStack.cs
index 99171b6b..1e2a2b51 100644
--- a/StgSharp.Common/HighPerformance/Memory/ConcurrentBufferStack.cs
+++ b/StgSharp.Common/HighPerformance/Memory/ConcurrentBufferStack.cs
@@ -47,7 +47,7 @@ namespace StgSharp.HighPerformance.Memory
return new BufferStack(4); // Default small capacity
}
- BufferStack stack = new BufferStack(span.Length);
+ BufferStack stack = new(span.Length);
// Use internal method for efficient bulk initialization
@@ -65,7 +65,7 @@ namespace StgSharp.HighPerformance.Memory
return new ConcurrentBufferStack(4); // Default small capacity
}
- ConcurrentBufferStack stack = new ConcurrentBufferStack(span.Length);
+ ConcurrentBufferStack stack = new(span.Length);
// Use internal method for efficient bulk initialization
@@ -82,7 +82,7 @@ namespace StgSharp.HighPerformance.Memory
private byte* _buffer;
private readonly BufferExpansionLock _lock = new();
- private ulong _count;
+ private long _count;
public ConcurrentBufferStack()
{
@@ -101,17 +101,25 @@ namespace StgSharp.HighPerformance.Memory
public ulong Count
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- get => Volatile.Read(ref _count);
+ get => (ulong)Volatile.Read(ref _count);
}
public void Clear()
{
- Header* header = (Header*)_buffer;
_lock.EnterExpansionProcess();
try
{
- header->Top = 0;
- Volatile.Write(ref _count, 0);
+ _lock.EnterBufferCopy(); // exclusive while mutating Top
+ try
+ {
+ Header* header = (Header*)_buffer;
+ header->Top = 0;
+ Volatile.Write(ref _count, 0);
+ }
+ finally
+ {
+ _lock.ExitBufferCopy();
+ }
}
finally
{
@@ -127,29 +135,29 @@ namespace StgSharp.HighPerformance.Memory
public T Pop()
{
- Header* header = (Header*)_buffer;
while (true)
{
- nuint oldTop = Volatile.Read(ref header->Top);
- if (oldTop <= 0) {
- throw new InvalidOperationException("Stack underflow");
- }
-
- if (Interlocked.CompareExchange(ref header->Top, oldTop - 1, oldTop) == oldTop)
+ _lock.EnterBufferRead(); // prevent buffer being reallocated while reading/modifying Top
+ try
{
- _lock.EnterBufferRead();
- try
+ Header* header = (Header*)_buffer;
+ int oldTop = Volatile.Read(ref header->Top);
+ if (oldTop <= 0) {
+ throw new InvalidOperationException("Stack underflow");
+ }
+
+ if (Interlocked.CompareExchange(ref header->Top, oldTop - 1, oldTop) == oldTop)
{
T* dataStart = (T*)(_buffer + sizeof(Header));
_ = Interlocked.Decrement(ref _count);
return dataStart[oldTop - 1];
}
- finally
- {
- _lock.ExitBufferRead();
- }
}
- Thread.Sleep(0); // Yield to avoid busy waiting
+ finally
+ {
+ _lock.ExitBufferRead();
+ }
+ Thread.Sleep(0);
}
}
@@ -157,14 +165,16 @@ namespace StgSharp.HighPerformance.Memory
{
while (true)
{
+ // Ensure capacity, expanding if needed
_lock.EnterMetaDataRead();
try
{
Header* header = (Header*)_buffer;
- nuint oldTop = Volatile.Read(ref header->Top);
- nuint cap = Volatile.Read(ref header->Capacity);
- if (oldTop >= cap)
+ int topSnapshot = Volatile.Read(ref header->Top);
+ int cap = Volatile.Read(ref header->Capacity);
+ if (topSnapshot >= cap)
{
+ // Need expansion
_lock.ExitMetaDataRead();
_lock.EnterExpansionProcess();
try
@@ -172,8 +182,8 @@ namespace StgSharp.HighPerformance.Memory
header = (Header*)_buffer;
if (header->Top >= header->Capacity)
{
- nuint newCap = header->Capacity * 2;
- nuint newSize = (nuint)sizeof(Header) + (newCap * (nuint)sizeof(T));
+ int newCap = header->Capacity * 2;
+ nuint newSize = (nuint)sizeof(Header) + ((nuint)newCap * (nuint)sizeof(T));
_lock.EnterBufferCopy();
try
@@ -193,22 +203,6 @@ namespace StgSharp.HighPerformance.Memory
}
continue;
}
-
- if (Interlocked.CompareExchange(ref header->Top, oldTop + 1, oldTop) == oldTop)
- {
- _lock.EnterBufferRead();
- try
- {
- T* dataStart = (T*)(_buffer + sizeof(Header));
- dataStart[oldTop] = item;
- _ = Interlocked.Increment(ref _count);
- return;
- }
- finally
- {
- _lock.ExitBufferRead();
- }
- }
}
finally
{
@@ -216,38 +210,60 @@ namespace StgSharp.HighPerformance.Memory
_lock.ExitMetaDataRead();
}
}
- Thread.Sleep(0); // Yield to avoid busy waiting
+
+ // Reserve and write under exclusive buffer lock to avoid consumers reading unwritten data
+ _lock.EnterBufferCopy();
+ try
+ {
+ Header* header = (Header*)_buffer;
+ int idx = header->Top; // reserve next slot
+ if (idx >= header->Capacity)
+ {
+ // lost race against expander or other producer; retry
+ continue;
+ }
+
+ T* dataStart = (T*)(_buffer + sizeof(Header));
+ dataStart[idx] = item; // write first
+ header->Top = idx + 1; // then publish by increasing top
+ _ = Interlocked.Increment(ref _count);
+ return;
+ }
+ finally
+ {
+ _lock.ExitBufferCopy();
+ }
}
}
public bool TryPop(out T value)
{
- Header* header = (Header*)_buffer;
while (true)
{
- nuint oldTop = Volatile.Read(ref header->Top);
- if (oldTop <= 0)
+ _lock.EnterBufferRead();
+ try
{
- value = default;
- return false;
- }
+ Header* header = (Header*)_buffer;
+ int oldTop = Volatile.Read(ref header->Top);
+ if (oldTop <= 0)
+ {
+ value = default;
+ return false;
+ }
- if (Interlocked.CompareExchange(ref header->Top, oldTop - 1, oldTop) == oldTop)
- {
- _lock.EnterBufferRead();
- try
+ if (Interlocked.CompareExchange(ref header->Top, oldTop - 1, oldTop) == oldTop)
{
T* dataStart = (T*)(_buffer + sizeof(Header));
value = dataStart[oldTop - 1];
_ = Interlocked.Decrement(ref _count);
+ return true;
}
- finally
- {
- _lock.ExitBufferRead();
- }
- return true;
}
- Thread.Sleep(0); // Yield to avoid busy waiting
+ finally
+ {
+ _lock.ExitBufferRead();
+ }
+ Thread.Sleep(0);
}
}
@@ -264,28 +280,28 @@ namespace StgSharp.HighPerformance.Memory
fixed (T* sourcePtr = span) {
Buffer.MemoryCopy(sourcePtr, dataStart,
- header->Capacity * (nuint)sizeof(T),
+ (nuint)header->Capacity * (nuint)sizeof(T),
(nuint)span.Length * (nuint)sizeof(T));
}
- header->Top = (nuint)span.Length;
- Volatile.Write(ref _count, (ulong)span.Length);
+ header->Top = span.Length;
+ Volatile.Write(ref _count, span.Length);
}
private void AllocateBuffer(int capacity)
{
- nuint size = (nuint)sizeof(Header) + ((nuint)capacity * (nuint)sizeof(T));
+ nuint size = (nuint)sizeof(Header) + (nuint)capacity * (nuint)sizeof(T);
_buffer = (byte*)NativeMemory.Alloc(size);
Header* header = (Header*)_buffer;
header->Top = 0;
- header->Capacity = (nuint)capacity;
+ header->Capacity = capacity;
}
private struct Header
{
- public nuint Capacity; // max capacity of the stack (number of elements)
- public nuint Top; // next available index in the stack
+ public int Capacity; // max capacity of the stack (number of elements)
+ public int Top; // next available index in the stack
}
diff --git a/StgSharp.Common/Internal/Graphic/gl.cs b/StgSharp.Common/Internal/Graphic/gl.cs
index 07ac1aaa..02a7dc6d 100644
--- a/StgSharp.Common/Internal/Graphic/gl.cs
+++ b/StgSharp.Common/Internal/Graphic/gl.cs
@@ -38,7 +38,7 @@ namespace StgSharp.Internal
internal static partial class GraphicFramework
{
- internal static uint[] GLtype = [];
+ internal static uint[] GLtype = new uint[16];
static GraphicFramework()
{
diff --git a/StgSharp.Common/Internal/Intrinsic/MatInterface.cs b/StgSharp.Common/Internal/Intrinsic/MatInterface.cs
deleted file mode 100644
index d2033627..00000000
--- a/StgSharp.Common/Internal/Intrinsic/MatInterface.cs
+++ /dev/null
@@ -1,35 +0,0 @@
-//-----------------------------------------------------------------------
-// -----------------------------------------------------------------------
-// file="MatInterface"
-// Project: StgSharp
-// AuthorGroup: Nitload
-// Copyright (c) Nitload. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in all
-// copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-// SOFTWARE.
-//
-// -----------------------------------------------------------------------
-// -----------------------------------------------------------------------
-using System;
-using System.Collections.Generic;
-using System.Text;
-
-namespace StgSharp.Internal.Intrinsic
-{
- public interface IMat { }
-}
diff --git a/StgSharp.Common/Mathematics/Graphic/Matrix44.cs b/StgSharp.Common/Mathematics/Graphic/Matrix44.cs
index e747948e..dc37b507 100644
--- a/StgSharp.Common/Mathematics/Graphic/Matrix44.cs
+++ b/StgSharp.Common/Mathematics/Graphic/Matrix44.cs
@@ -27,14 +27,17 @@
// -----------------------------------------------------------------------
using StgSharp.Mathematics.Numeric;
using System;
+using System.Collections;
+using System.Collections.Generic;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace StgSharp.Mathematics.Graphic
{
- [StructLayout(LayoutKind.Explicit, Size = 2 * 16 * sizeof(float) + sizeof(bool), Pack = 16)]
- public unsafe struct Matrix44 : IEquatable, IMatrix
+ [CollectionBuilder(builderType:typeof(Matrix44), methodName: nameof(Matrix44.FromSpan))]
+ [StructLayout(LayoutKind.Explicit, Size = (2 * 16 * sizeof(float)) + sizeof(bool), Pack = 16)]
+ public unsafe struct Matrix44 : IEquatable, IMatrix, IEnumerable
{
[FieldOffset(2 * 64 * sizeof(float))] internal bool isTransposed;
@@ -160,12 +163,6 @@ namespace StgSharp.Mathematics.Graphic
return MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref mat), 16);
}
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public unsafe float Det()
- {
- return 0;
- }
-
public override bool Equals(object? obj)
{
return obj is Matrix44 x && Equals(x);
@@ -176,11 +173,24 @@ namespace StgSharp.Mathematics.Graphic
return mat.Equals(other.mat);
}
+ public static Matrix44 FromSpan(ReadOnlySpan rowSpan)
+ {
+ Matrix44 mat = new Matrix44();
+
+ mat.transpose.colum0 = rowSpan[0].vec;
+ mat.transpose.colum1 = rowSpan[1].vec;
+ mat.transpose.colum2 = rowSpan[2].vec;
+ mat.transpose.colum3 = rowSpan[3].vec;
+
+ NativeIntrinsic.Intrinsic.f32_transpose(&mat.transpose, &mat.mat);
+ mat.isTransposed = false;
+ return mat;
+ }
+
public override int GetHashCode()
{
- return HashCode.Combine(
- mat.colum0.GetHashCode(), mat.colum1.GetHashCode(), mat.colum2.GetHashCode(),
- mat.colum3.GetHashCode());
+ return HashCode.Combine(mat.colum0.GetHashCode(), mat.colum1.GetHashCode(), mat.colum2.GetHashCode(),
+ mat.colum3.GetHashCode());
}
public override string ToString()
@@ -194,11 +204,8 @@ namespace StgSharp.Mathematics.Graphic
{
if (!isTransposed)
{
- fixed (ColumnSet4* source = &mat, target = &transpose)
- {
+ fixed (ColumnSet4* source = &mat, target = &transpose) {
NativeIntrinsic.Intrinsic.f32_transpose(source, target);
-
- // InternalIO.Intrinsic.transpose44(source, target);
}
isTransposed = true;
}
@@ -207,13 +214,9 @@ namespace StgSharp.Mathematics.Graphic
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe Matrix44 operator -(Matrix44 left, Matrix44 right)
{
- return new Matrix44
- {
- column0 = right.column0 - left.column0,
- column1 = right.column1 - left.column1,
- column2 = right.column2 - left.column2,
- column3 = right.column3 - left.column3
- };
+ Matrix44 ret = new();
+ NativeIntrinsic.Intrinsic.f32_sub(&left, &right, &ret);
+ return ret;
}
public static bool operator !=(Matrix44 left, Matrix44 right)
@@ -224,47 +227,37 @@ namespace StgSharp.Mathematics.Graphic
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe Matrix44 operator *(Matrix44 mat, float value)
{
- return new Matrix44(
- mat.mat.colum0 * value, mat.mat.colum1 * value, mat.mat.colum2 * value,
- mat.mat.colum3 * value);
+ return new Matrix44(mat.mat.colum0 * value, mat.mat.colum1 * value, mat.mat.colum2 * value,
+ mat.mat.colum3 * value);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Matrix44 operator *(Matrix44 left, Matrix44 right)
{
left.InternalTranspose();
- return new Matrix44(
- Vector4.Dot(left.transpose.colum0, right.mat.colum0),
- Vector4.Dot(left.transpose.colum0, right.mat.colum1),
- Vector4.Dot(left.transpose.colum0, right.mat.colum2),
- Vector4.Dot(left.transpose.colum0, right.mat.colum3),
-
- Vector4.Dot(left.transpose.colum1, right.mat.colum0),
- Vector4.Dot(left.transpose.colum1, right.mat.colum1),
- Vector4.Dot(left.transpose.colum1, right.mat.colum2),
- Vector4.Dot(left.transpose.colum1, right.mat.colum3),
-
- Vector4.Dot(left.transpose.colum2, right.mat.colum0),
- Vector4.Dot(left.transpose.colum2, right.mat.colum1),
- Vector4.Dot(left.transpose.colum2, right.mat.colum2),
- Vector4.Dot(left.transpose.colum2, right.mat.colum3),
-
- Vector4.Dot(left.transpose.colum3, right.mat.colum0),
- Vector4.Dot(left.transpose.colum3, right.mat.colum1),
- Vector4.Dot(left.transpose.colum3, right.mat.colum2),
- Vector4.Dot(left.transpose.colum3, right.mat.colum3));
+ return new Matrix44(Vector4.Dot(left.transpose.colum0, right.mat.colum0),
+ Vector4.Dot(left.transpose.colum0, right.mat.colum1),
+ Vector4.Dot(left.transpose.colum0, right.mat.colum2),
+ Vector4.Dot(left.transpose.colum0, right.mat.colum3),
+ Vector4.Dot(left.transpose.colum1, right.mat.colum0),
+ Vector4.Dot(left.transpose.colum1, right.mat.colum1),
+ Vector4.Dot(left.transpose.colum1, right.mat.colum2),
+ Vector4.Dot(left.transpose.colum1, right.mat.colum3),
+ Vector4.Dot(left.transpose.colum2, right.mat.colum0),
+ Vector4.Dot(left.transpose.colum2, right.mat.colum1),
+ Vector4.Dot(left.transpose.colum2, right.mat.colum2),
+ Vector4.Dot(left.transpose.colum2, right.mat.colum3),
+ Vector4.Dot(left.transpose.colum3, right.mat.colum0),
+ Vector4.Dot(left.transpose.colum3, right.mat.colum1),
+ Vector4.Dot(left.transpose.colum3, right.mat.colum2),
+ Vector4.Dot(left.transpose.colum3, right.mat.colum3));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe Matrix44 operator +(Matrix44 left, Matrix44 right)
{
- Matrix44 ret = new()
- {
- column0 = left.column0 + right.column0,
- column1 = left.column1 + right.column1,
- column2 = left.column2 + right.column2,
- column3 = left.column3 + right.column3
- };
+ Matrix44 ret = new();
+ NativeIntrinsic.Intrinsic.f32_add(&left, &right, &ret);
return ret;
}
@@ -273,5 +266,18 @@ namespace StgSharp.Mathematics.Graphic
return left.Equals(right);
}
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ throw new NotImplementedException();
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ ref Vec4 col0 = ref column0;
+ for (int i = 0; i < 4; i++) {
+ yield return Unsafe.Add(ref col0, i);
+ }
+ }
+
}
}
diff --git a/StgSharp.Common/Mathematics/Graphic/Vec4.cs b/StgSharp.Common/Mathematics/Graphic/Vec4.cs
index b4186d61..44edf4ae 100644
--- a/StgSharp.Common/Mathematics/Graphic/Vec4.cs
+++ b/StgSharp.Common/Mathematics/Graphic/Vec4.cs
@@ -36,8 +36,9 @@ using System.Runtime.InteropServices;
namespace StgSharp.Mathematics.Graphic
{
+ [CollectionBuilder(builderType:typeof(Vec4), methodName: nameof(Vec4.FromSpan))]
[StructLayout(LayoutKind.Explicit, Size = 16, Pack = 16)]
- public struct Vec4 : IEquatable, IUnmanagedVector
+ public unsafe struct Vec4 : IEquatable, IUnmanagedVector
{
[FieldOffset(0)] internal unsafe fixed float num[4];
@@ -127,11 +128,33 @@ namespace StgSharp.Mathematics.Graphic
return left + right;
}
+ public ReadOnlySpan AsSpan()
+ {
+ return MemoryMarshal.CreateReadOnlySpan(ref reg.Member(0), 4);
+ }
+
public override bool Equals(object obj)
{
return obj is Vec4 v && v == this;
}
+ public static Vec4 FromSpan(ReadOnlySpan span)
+ {
+ return new Vec4
+ {
+ X = span[0],
+ Y = span[1],
+ Z = span[2],
+ W = span[3]
+ };
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public ReadOnlySpan.Enumerator GetEnumerator()
+ {
+ return AsSpan().GetEnumerator();
+ }
+
public override int GetHashCode()
{
return vec.GetHashCode();
@@ -163,11 +186,8 @@ namespace StgSharp.Mathematics.Graphic
public static Vec4 operator *(Matrix44 mat, Vec4 vec)
{
mat.InternalTranspose();
- return new Vec4(
- Vector4.Dot(mat.transpose.colum0, vec.vec),
- Vector4.Dot(mat.transpose.colum1, vec.vec),
- Vector4.Dot(mat.transpose.colum2, vec.vec),
- Vector4.Dot(mat.transpose.colum3, vec.vec));
+ return new Vec4(Vector4.Dot(mat.transpose.colum0, vec.vec), Vector4.Dot(mat.transpose.colum1, vec.vec),
+ Vector4.Dot(mat.transpose.colum2, vec.vec), Vector4.Dot(mat.transpose.colum3, vec.vec));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
diff --git a/StgSharp.Common/Mathematics/Linear/IMatrix.cs b/StgSharp.Common/Mathematics/Linear/IMatrix.cs
index e19a0f81..f626e927 100644
--- a/StgSharp.Common/Mathematics/Linear/IMatrix.cs
+++ b/StgSharp.Common/Mathematics/Linear/IMatrix.cs
@@ -30,6 +30,7 @@ using StgSharp.Graphics;
using System;
using System.Collections.Generic;
using System.Numerics;
+using System.Runtime.CompilerServices;
using System.Text;
namespace StgSharp.Mathematics.Numeric
diff --git a/StgSharp.Common/Threading/BufferExpansionLock.cs b/StgSharp.Common/Threading/BufferExpansionLock.cs
index 6ecbc3f9..df5fbedb 100644
--- a/StgSharp.Common/Threading/BufferExpansionLock.cs
+++ b/StgSharp.Common/Threading/BufferExpansionLock.cs
@@ -42,7 +42,7 @@ namespace StgSharp.Threading
public class BufferExpansionLock : IDisposable
{
- private static readonly ThreadLocal Count = new();
+ private static readonly ThreadLocal Count = new(() => 0);
private readonly ReaderWriterLockSlim _copyLock;
private readonly ReaderWriterLockSlim _expansionLock;
@@ -74,13 +74,11 @@ namespace StgSharp.Threading
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void EnterBufferRead()
{
- if (++Count.Value == 1)
- {
+ int c = Count.Value;
+ if (c == 0) {
_copyLock.EnterReadLock();
- } else
- {
- Count.Value++;
}
+ Count.Value = c + 1;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -104,12 +102,10 @@ namespace StgSharp.Threading
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ExitBufferRead()
{
- if (--Count.Value == 0)
- {
+ int c = Count.Value - 1;
+ Count.Value = c;
+ if (c == 0) {
_copyLock.ExitReadLock();
- } else
- {
- Count.Value--;
}
}
diff --git a/StgSharp.Common/Threading/SamplingAdaptiveBackoff.cs b/StgSharp.Common/Threading/SamplingAdaptiveBackoff.cs
deleted file mode 100644
index 71e7994c..00000000
--- a/StgSharp.Common/Threading/SamplingAdaptiveBackoff.cs
+++ /dev/null
@@ -1,457 +0,0 @@
-//-----------------------------------------------------------------------
-// -----------------------------------------------------------------------
-// file="SamplingAdaptiveBackoff"
-// Project: StgSharp
-// AuthorGroup: Nitload
-// Copyright (c) Nitload. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in all
-// copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-// SOFTWARE.
-//
-// -----------------------------------------------------------------------
-// -----------------------------------------------------------------------
-using System;
-using System.Diagnostics;
-using System.Runtime.CompilerServices;
-using System.Threading;
-
-///
-/// Optimized sampling-based adaptive backoff strategy that re-samples and evaluates the current
-/// contention situation and adjusts the strategy after a certain number of fallbacks
-///
-public struct SamplingAdaptiveBackoff
-{
- /*
- private const int CONFIDENCE_THRESHOLD = 3; // Requires N consecutive sampling confirmations to switch strategies
-
- // Configuration constants
- private const int FALLBACK_SAMPLING_THRESHOLD = 64; // Triggers re-sampling every 64 fallbacks
- private const int INITIAL_SPINWAIT_THRESHOLD = 8; // Cheap spinning for the first few SpinWait attempts
- private const int MAX_SAMPLING_WINDOW_MS = 1000; // Maximum sampling window time
- private const int MIN_SAMPLING_WINDOW_MS = 100; // Minimum sampling window time
- private const int PERFORMANCE_HISTORY_MASK = 7; // Use 3-bit mask for 8 entries (power of 2)
- private const double SIGNIFICANT_IMPROVEMENT = 0.15; // 15% improvement is considered significant
-
- private BackoffMethod _candidateMethod;
- private BackoffMethod _currentMethod;
- private byte _confidenceCounter;
- private byte _consecutiveFailures;
-
- // Packed performance data to reduce memory footprint
- private PackedMethodPerformance _packedPerformances; // Bit-packed performance data for all 3 methods
- private SamplingWindow _currentSample;
-
- // Instance state
- private SpinWait _spinWait;
- private uint _rng;
-
- ///
- /// Gets the current method
- ///
- public readonly BackoffMethod CurrentMethod => _currentMethod;
-
- ///
- /// Creates a new optimized sampling adaptive backoff strategy instance
- ///
- public static SamplingAdaptiveBackoff Create()
- {
- // Choose initial strategy based on system characteristics
- BackoffMethod initialMethod = DetermineInitialMethod();
-
- SamplingAdaptiveBackoff instance = new()
- {
- _spinWait = default,
- _currentMethod = initialMethod,
- _consecutiveFailures = 0,
- _confidenceCounter = 0,
- _candidateMethod = initialMethod,
- _rng = GenerateInitialSeed(),
- _packedPerformances = PackedMethodPerformance.Initialize()
- };
-
- // Start the first sampling window
- instance._currentSample.Reset(initialMethod);
-
- return instance;
- }
-
- ///
- /// Gets the current sampling status (for debugging)
- ///
- public readonly (int attempts, int successes, int fallbacks, double successRate, double fallbackRate) GetCurrentSampleStats()
- {
- return (_currentSample.TotalAttempts,
- _currentSample.SuccessfulAttempts,
- _currentSample.FallbackCount,
- _currentSample.SuccessRate,
- _currentSample.FallbackRate);
- }
-
- ///
- /// Gets the historical performance of the specified method (for monitoring)
- ///
- public readonly (double successRate, double fallbackRate, double overallScore) GetMethodPerformance(
- BackoffMethod method)
- {
- var (successRate, fallbackRate, score) = _packedPerformances.GetPerformance(method);
- return (successRate, fallbackRate, score);
- }
-
- ///
- /// Called when attempting CAS (must be called regardless of success or failure)
- ///
- ///
- /// Whether this CAS attempt was successful
- ///
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void OnCASAttempt(bool success)
- {
- _currentSample.TotalAttempts++;
-
- if (success)
- {
- _currentSample.SuccessfulAttempts++;
- _consecutiveFailures = 0;
- _spinWait = default; // Reset SpinWait after success
- } else
- {
- _consecutiveFailures++;
- }
- }
-
- ///
- /// Called when CAS fails and fallback needs to be executed, performs backoff and may trigger
- /// re-sampling
- ///
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void OnFallbackAndBackoff()
- {
- _currentSample.FallbackCount++;
-
- // Check if re-sampling threshold is reached using bitwise operations for faster comparison
- if ((_currentSample.FallbackCount & ~(FALLBACK_SAMPLING_THRESHOLD - 1)) != 0 ||
- _currentSample.ElapsedTicks > MAX_SAMPLING_WINDOW_MS)
- {
- if (_currentSample.ElapsedTicks >= MIN_SAMPLING_WINDOW_MS) {
- EvaluateCurrentSample();
- }
- }
-
- // Perform backoff using jump table approach for better branch prediction
- PerformBackoffOptimized();
- }
-
- ///
- /// Determines initial method based on system characteristics
- ///
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static BackoffMethod DetermineInitialMethod()
- {
- int logicalCores = Environment.ProcessorCount;
- return logicalCores <= 16 ? BackoffMethod.SpinWait : BackoffMethod.Sleep0;
- }
-
- ///
- /// Determines the method to test in the next sampling window using optimized random selection
- ///
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private BackoffMethod DetermineNextTestMethod()
- {
- // Use bitwise operations for 80%/20% probability split
- return (NextRandom() & 0xF) < 13 ? _candidateMethod : (BackoffMethod)(NextRandom() & 3);
- }
-
- ///
- /// Evaluates the current sampling window and may adjust the strategy
- ///
- [MethodImpl(MethodImplOptions.NoInlining)]
- private void EvaluateCurrentSample()
- {
- // Update performance record for the current method using packed data
- _packedPerformances.UpdatePerformance(
- _currentSample.TestedMethod, _currentSample.SuccessRate, _currentSample.FallbackRate,
- _currentSample.ElapsedTicks / Math.Max(1, _currentSample.TotalAttempts));
-
- // Find the currently best performing method
- BackoffMethod bestMethod = _packedPerformances.FindBestMethod();
-
- // Use branchless logic for confidence tracking
- bool methodChanged = bestMethod != _currentMethod;
- bool candidateMatches = bestMethod == _candidateMethod;
-
- _confidenceCounter = methodChanged ? (candidateMatches ? (byte)(_confidenceCounter + 1) : (byte)1) : (byte)0;
-
- if (methodChanged && candidateMatches && _confidenceCounter >= CONFIDENCE_THRESHOLD)
- {
- SwitchToMethod(bestMethod);
- } else if (methodChanged && !candidateMatches)
- {
- _candidateMethod = bestMethod;
- } else if (!methodChanged) {
- _candidateMethod = _currentMethod;
- }
-
- // Start new sampling window
- BackoffMethod nextTestMethod = DetermineNextTestMethod();
- _currentSample.Reset(nextTestMethod);
-
- if (nextTestMethod != _currentMethod)
- {
- _currentMethod = nextTestMethod;
- _spinWait = default;
- }
- }
-
- ///
- /// Generates initial seed for RNG
- ///
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static uint GenerateInitialSeed()
- {
- return (uint)(Environment.TickCount64 ^ (Thread.CurrentThread.ManagedThreadId * 0x9E3779B9U));
- }
-
- ///
- /// Fast pseudo-random number generator using XorShift32
- ///
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private uint NextRandom()
- {
- // XorShift32 - faster than LCG with better distribution
- _rng ^= _rng << 13;
- _rng ^= _rng >> 17;
- _rng ^= _rng << 5;
- return _rng;
- }
-
- ///
- /// Optimized backoff operation using jump table approach
- ///
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void PerformBackoffOptimized()
- {
- // Use computed goto pattern for better branch prediction
- switch (_currentMethod)
- {
- case BackoffMethod.SpinWait:
- PerformSpinWaitBackoff();
- break;
- case BackoffMethod.Yield:
- _ = Thread.Yield();
- break;
- case BackoffMethod.Sleep0:
- Thread.Sleep(0);
- break;
- default:
- break;
- }
- }
-
- ///
- /// Specialized SpinWait backoff with optimized logic
- ///
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void PerformSpinWaitBackoff()
- {
- if (_consecutiveFailures > INITIAL_SPINWAIT_THRESHOLD && _spinWait.NextSpinWillYield)
- {
- // Optimized random yield count using bitwise operations
- int yields = (int)(NextRandom() & 7) + 1;
- for (int i = 0; i < yields; i++) {
- _ = Thread.Yield();
- }
- } else
- {
- _spinWait.SpinOnce(sleep1Threshold:-1);
- }
- }
-
- ///
- /// Switches to a new method with optimized state reset
- ///
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void SwitchToMethod(BackoffMethod method)
- {
- _currentMethod = method;
- _candidateMethod = method;
- _confidenceCounter = 0;
- _spinWait = default;
- }
-
- public enum BackoffMethod : byte
- {
-
- SpinWait = 0,
- Yield = 1,
- Sleep0 = 2
-
- }
-
- // Optimized sampling window state with better packing
- private struct SamplingWindow
- {
-
- public BackoffMethod TestedMethod; // Current method being tested
- public int FallbackCount; // Number of fallbacks
- public int SuccessfulAttempts; // Number of successful attempts
- public int TotalAttempts; // Total number of attempts
- public long StartTicks; // Sampling window start time
-
- public readonly double SuccessRate
- {
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- get => TotalAttempts == 0 ? 0.0 : (double)SuccessfulAttempts / TotalAttempts;
- }
-
- public readonly double FallbackRate
- {
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- get => TotalAttempts == 0 ? 0.0 : (double)FallbackCount / TotalAttempts;
- }
-
- public readonly long ElapsedTicks
- {
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- get => Environment.TickCount64 - StartTicks;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void Reset(BackoffMethod method)
- {
- StartTicks = Environment.TickCount64;
- TotalAttempts = 0;
- SuccessfulAttempts = 0;
- FallbackCount = 0;
- TestedMethod = method;
- }
-
- }
-
- // Bit-packed performance data structure for memory efficiency
- private struct PackedMethodPerformance
- {
-
- // Pack all 3 methods' performance into compact format
- private ulong _packed0; // Method 0 (SpinWait) data
- private ulong _packed1; // Method 1 (Yield) data
- private ulong _packed2; // Method 2 (Sleep0) data
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public readonly BackoffMethod FindBestMethod()
- {
- (double _, double _, double score0) = UnpackPerformanceData(_packed0);
- (double _, double _, double score1) = UnpackPerformanceData(_packed1);
- (double _, double _, double score2) = UnpackPerformanceData(_packed2);
-
- // Use branchless comparison for best performance
- BackoffMethod best = score1 > score0 + SIGNIFICANT_IMPROVEMENT ?
- BackoffMethod.Yield :
- BackoffMethod.SpinWait;
- best = score2 > GetScore(best) + SIGNIFICANT_IMPROVEMENT ? BackoffMethod.Sleep0 : best;
-
- return best;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public readonly (double successRate, double fallbackRate, double overallScore) GetPerformance(
- BackoffMethod method)
- {
- ulong packed = method switch
- {
- BackoffMethod.SpinWait => _packed0,
- BackoffMethod.Yield => _packed1,
- BackoffMethod.Sleep0 => _packed2,
- _ => _packed0
- };
-
- return UnpackPerformanceData(packed);
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static PackedMethodPerformance Initialize()
- {
- return new PackedMethodPerformance
- {
- _packed0 = PackPerformanceData(0.5, 0.5, 0),
- _packed1 = PackPerformanceData(0.5, 0.5, 0),
- _packed2 = PackPerformanceData(0.5, 0.5, 0)
- };
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void UpdatePerformance(BackoffMethod method, double successRate, double fallbackRate, long avgLatency)
- {
- ulong packed = PackPerformanceData(successRate, fallbackRate, avgLatency);
-
- switch (method)
- {
- case BackoffMethod.SpinWait:
- _packed0 = packed;
- break;
- case BackoffMethod.Yield:
- _packed1 = packed;
- break;
- case BackoffMethod.Sleep0:
- _packed2 = packed;
- break;
- }
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private readonly double GetScore(BackoffMethod method)
- {
- return method switch
- {
- BackoffMethod.SpinWait => UnpackPerformanceData(_packed0).overallScore,
- BackoffMethod.Yield => UnpackPerformanceData(_packed1).overallScore,
- BackoffMethod.Sleep0 => UnpackPerformanceData(_packed2).overallScore,
- _ => 0.0
- };
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static ulong PackPerformanceData(double successRate, double fallbackRate, long avgLatency)
- {
- // Pack data into 64-bit value: 20 bits success rate, 20 bits fallback rate, 24 bits latency
- uint success = (uint)(successRate * 1048575); // 20 bits (2^20 - 1)
- uint fallback = (uint)(fallbackRate * 1048575); // 20 bits
- uint latency = (uint)Math.Min(avgLatency, 16777215); // 24 bits (2^24 - 1)
-
- return ((ulong)success << 44) | ((ulong)fallback << 24) | latency;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static (double successRate, double fallbackRate, double overallScore) UnpackPerformanceData(
- ulong packed)
- {
- double successRate = ((packed >> 44) & 0xFFFFF) / 1048575.0;
- double fallbackRate = ((packed >> 24) & 0xFFFFF) / 1048575.0;
- long avgLatency = (long)(packed & 0xFFFFFF);
-
- // Calculate overall score with optimized formula
- double baseScore = successRate * 0.6 + (1.0 - fallbackRate) * 0.4;
- double latencyPenalty = avgLatency > 0 ? Math.Min(0.1, avgLatency / 10000.0) : 0;
- double overallScore = baseScore - latencyPenalty;
-
- return (successRate, fallbackRate, overallScore);
- }
-
- }
- /**/
-
-}
\ No newline at end of file
diff --git a/StgSharp.Mathematics/Numeric/MatrixCompute.Basic.cs b/StgSharp.Mathematics/Numeric/MatrixCompute.Basic.cs
index 2af8c137..5dd527ac 100644
--- a/StgSharp.Mathematics/Numeric/MatrixCompute.Basic.cs
+++ b/StgSharp.Mathematics/Numeric/MatrixCompute.Basic.cs
@@ -47,10 +47,20 @@ namespace StgSharp.Mathematics.Numeric
}
Matrix ans = Matrix.FromDefault(left.ColumnLength, left.RowLength);
long count = (long)left.KernelColumnLength * left.KernelRowLength;
+ if (count <= 256)
+ {
+ MatrixKernel* leftPtr = left.Buffer;
+ MatrixKernel* rightPtr = right.Buffer;
+ MatrixKernel* ansPtr = ans.Buffer;
+ for (int i = 0; i < count; i++) {
+ NativeIntrinsic.Intrinsic.f32_add(leftPtr + i, rightPtr + i, ansPtr + i);
+ }
+ return ans;
+ }
if (count <= 1024)
{
- CapacityFixedStack pool = MatrixParallel.LeadParallel();
- if (!pool.TryPop(out MatrixParallelThread thread))
+ ReadOnlySpan pool = MatrixParallel.LeadParallel(1);
+ if (pool.Length == 0)
{
/*
* wait
@@ -64,47 +74,14 @@ namespace StgSharp.Mathematics.Numeric
}
return ans;
}
- Stack taskGroup = MatrixParallel.PublicTask(left.GetColumnEnumeration(), right.GetColumnEnumeration(), ans.GetColumnEnumeration(),
+ MatrixParallelHandle taskGroup = MatrixParallel.PublicTask(left.GetColumnEnumeration(), right.GetColumnEnumeration(), ans.GetColumnEnumeration(),
(delegate**, MatrixKernel*, MatrixKernel*, void>)NativeIntrinsic.Intrinsic.f32_add);
MatrixParallel.LaunchParallel(taskGroup, SleepMode.DeepSleep);
/*
* run parallel
*/
- return ans;
- }
-
- public static unsafe Matrix Sub(Matrix left, Matrix right)
- {
- if (left.ColumnLength != right.ColumnLength || left.RowLength != right.RowLength) {
- throw new IndexOutOfRangeException("Matrix dimensions must agree.");
- }
- Matrix ans = Matrix.FromDefault(left.ColumnLength, left.RowLength);
- long count = (long)left.KernelColumnLength * left.KernelRowLength;
- if (count <= 1024)
- {
- // TODO: this is very awkward, blocking thread renting, need a better way to handle small tasks
- CapacityFixedStack pool = MatrixParallel.LeadParallel();
- if (!pool.TryPop(out MatrixParallelThread thread))
- {
- /*
- * wait
- */
- }
- MatrixKernel* leftPtr = left.Buffer;
- MatrixKernel* rightPtr = right.Buffer;
- MatrixKernel* ansPtr = ans.Buffer;
- for (int i = 0; i < count; i++) {
- NativeIntrinsic.Intrinsic.f32_sub(leftPtr + i, rightPtr + i, ansPtr + i);
- }
-
- return ans;
- }
- Stack taskGroup = MatrixParallel.PublicTask(left.GetColumnEnumeration(), right.GetColumnEnumeration(), ans.GetColumnEnumeration(),
- (delegate**, MatrixKernel*, MatrixKernel*, void>)NativeIntrinsic.Intrinsic.f32_sub);
- /*
- * run parallel
- */
+ taskGroup.Dispose();
return ans;
}
diff --git a/StgSharp.Mathematics/Numeric/MatrixParallel.Await.cs b/StgSharp.Mathematics/Numeric/MatrixParallel.Await.cs
new file mode 100644
index 00000000..a64d2b77
--- /dev/null
+++ b/StgSharp.Mathematics/Numeric/MatrixParallel.Await.cs
@@ -0,0 +1,116 @@
+//-----------------------------------------------------------------------
+// -----------------------------------------------------------------------
+// file="MatrixParallel.Await"
+// Project: StgSharp
+// AuthorGroup: Nitload
+// Copyright (c) Nitload. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+//
+// -----------------------------------------------------------------------
+// -----------------------------------------------------------------------
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace StgSharp.Mathematics.Numeric
+{
+ public static partial class MatrixParallel
+ {
+
+ private static ConcurrentQueue _awaitingLeaderHandle;
+
+ private static volatile int _createGeneration = 0;
+ private static int _sortState;
+
+ public static MatrixParallelThread[] LeadParallel(int recommendCount)
+ {
+ int min = int.Min(recommendCount, _threads.Capacity);
+ min /= 2;
+ MatrixParallelThread[] ret;
+ if (_threads.Count < min)
+ {
+ WaitHandle handle = new WaitHandle
+ {
+ CreateGeneration = _createGeneration,
+ LeastCount = min,
+ BestCount = recommendCount
+ };
+ _awaitingLeaderHandle.Enqueue(handle);
+ int cycleGeneration = _createGeneration;
+ while (true)
+ {
+ // TODO 排队等待,对前八个按照优先级排序,优先级最高的独占进行等待,其他继续排队
+ if (_createGeneration != cycleGeneration)
+ {
+ if (Interlocked.Exchange(ref _sortState, 1) == 0)
+ {
+ // TODO 排序
+ _ = Interlocked.Exchange(ref _sortState, 0);
+ } else
+ {
+ cycleGeneration = _createGeneration;
+ continue;
+ }
+ }
+ if (_awaitingLeaderHandle.TryPeek(out WaitHandle? p) && p == handle)
+ {
+ // get the leader
+ ret = _threads.PopRange(recommendCount);
+ _awaitingLeaderHandle.TryDequeue(out _);
+ break;
+ }
+ Thread.Sleep(0);
+ }
+ } else
+ {
+ // directly get the leader
+ ret = _threads.PopRange(recommendCount);
+ }
+ _ = Interlocked.Increment(ref _createGeneration);
+ return ret;
+ }
+
+ public static void ReturnParallelResources(ref MatrixParallelThread[] pool)
+ {
+ _threads.PushRange(pool);
+ pool = null!;
+ }
+
+ private record class WaitHandle
+ {
+
+ public int CreateGeneration { get; set; }
+
+ public int LeastCount { get; set; }
+
+ public int BestCount { get; set; }
+
+ public int CurrentPriority(int currentGeneration)
+ {
+ return (currentGeneration - CreateGeneration) * (MatrixParallel._threads.Capacity - LeastCount);
+ }
+
+ }
+
+ }
+}
diff --git a/StgSharp.Mathematics/Numeric/MatrixParallel.Publish.cs b/StgSharp.Mathematics/Numeric/MatrixParallel.Publish.cs
index 894aa176..eda3cf23 100644
--- a/StgSharp.Mathematics/Numeric/MatrixParallel.Publish.cs
+++ b/StgSharp.Mathematics/Numeric/MatrixParallel.Publish.cs
@@ -40,10 +40,10 @@ namespace StgSharp.Mathematics.Numeric
public static partial class MatrixParallel
{
- public static unsafe Stack PublicTask(
- MatrixSegmentEnumeration source,
- MatrixSegmentEnumeration ans,
- delegate**, MatrixKernel*, MatrixKernel*, void> Operation)
+ public static unsafe MatrixParallelHandle PublicTask(
+ MatrixSegmentEnumeration source,
+ MatrixSegmentEnumeration ans,
+ delegate**, MatrixKernel*, MatrixKernel*, void> Operation)
where T: unmanaged, INumber
{
MatrixParallelTaskPackage* package = MatrixParallelFactory.CreateBaseTask();
@@ -66,11 +66,11 @@ namespace StgSharp.Mathematics.Numeric
return PublicTaskPrivate(package);
}
- public static unsafe Stack PublicTask(
- MatrixSegmentEnumeration left,
- MatrixSegmentEnumeration right,
- MatrixSegmentEnumeration ans,
- delegate**, MatrixKernel*, MatrixKernel*, void> Operation)
+ public static unsafe MatrixParallelHandle PublicTask(
+ MatrixSegmentEnumeration left,
+ MatrixSegmentEnumeration right,
+ MatrixSegmentEnumeration ans,
+ delegate**, MatrixKernel*, MatrixKernel*, void> Operation)
where T: unmanaged, INumber
{
MatrixParallelTaskPackage* package = MatrixParallelFactory.CreateBaseTask();
@@ -99,11 +99,11 @@ namespace StgSharp.Mathematics.Numeric
}
// Unary with 1..8 scalars (each scalar is independent generic type)
- public static unsafe Stack PublicTask(
- MatrixSegmentEnumeration source,
- MatrixSegmentEnumeration ans,
- delegate**, MatrixKernel*, MatrixKernel*, void> Operation,
- TScalar0 s0)
+ public static unsafe MatrixParallelHandle PublicTask(
+ MatrixSegmentEnumeration source,
+ MatrixSegmentEnumeration ans,
+ delegate**, MatrixKernel*, MatrixKernel*, void> Operation,
+ TScalar0 s0)
where T: unmanaged, INumber
where TScalar0: unmanaged, INumber
{
@@ -130,12 +130,12 @@ namespace StgSharp.Mathematics.Numeric
return PublicTaskPrivate(package);
}
- public static unsafe Stack PublicTask(
- MatrixSegmentEnumeration source,
- MatrixSegmentEnumeration ans,
- delegate**, MatrixKernel*, MatrixKernel*, void> Operation,
- TScalar0 s0,
- TScalar1 s1)
+ public static unsafe MatrixParallelHandle PublicTask(
+ MatrixSegmentEnumeration source,
+ MatrixSegmentEnumeration ans,
+ delegate**, MatrixKernel*, MatrixKernel*, void> Operation,
+ TScalar0 s0,
+ TScalar1 s1)
where T: unmanaged, INumber
where TScalar0: unmanaged, INumber
where TScalar1: unmanaged, INumber
@@ -165,12 +165,12 @@ namespace StgSharp.Mathematics.Numeric
}
// Binary with 1..8 scalars (each scalar is independent generic type)
- public static unsafe Stack PublicTask(
- MatrixSegmentEnumeration left,
- MatrixSegmentEnumeration right,
- MatrixSegmentEnumeration ans,
- delegate**, MatrixKernel*, MatrixKernel*, void> Operation,
- TScalar0 s0)
+ public static unsafe MatrixParallelHandle PublicTask(
+ MatrixSegmentEnumeration left,
+ MatrixSegmentEnumeration right,
+ MatrixSegmentEnumeration ans,
+ delegate**, MatrixKernel*, MatrixKernel*, void> Operation,
+ TScalar0 s0)
where T: unmanaged, INumber
where TScalar0: unmanaged, INumber
{
@@ -202,13 +202,13 @@ namespace StgSharp.Mathematics.Numeric
return PublicTaskPrivate(package);
}
- public static unsafe Stack PublicTask(
- MatrixSegmentEnumeration source,
- MatrixSegmentEnumeration ans,
- delegate**, MatrixKernel*, MatrixKernel*, void> Operation,
- TScalar0 s0,
- TScalar1 s1,
- TScalar2 s2)
+ public static unsafe MatrixParallelHandle PublicTask(
+ MatrixSegmentEnumeration source,
+ MatrixSegmentEnumeration ans,
+ delegate**, MatrixKernel*, MatrixKernel*, void> Operation,
+ TScalar0 s0,
+ TScalar1 s1,
+ TScalar2 s2)
where T: unmanaged, INumber
where TScalar0: unmanaged, INumber
where TScalar1: unmanaged, INumber
@@ -239,13 +239,13 @@ namespace StgSharp.Mathematics.Numeric
return PublicTaskPrivate(package);
}
- public static unsafe Stack PublicTask(
- MatrixSegmentEnumeration left,
- MatrixSegmentEnumeration right,
- MatrixSegmentEnumeration ans,
- delegate**, MatrixKernel*, MatrixKernel*, void> Operation,
- TScalar0 s0,
- TScalar1 s1)
+ public static unsafe MatrixParallelHandle PublicTask(
+ MatrixSegmentEnumeration left,
+ MatrixSegmentEnumeration right,
+ MatrixSegmentEnumeration ans,
+ delegate**, MatrixKernel*, MatrixKernel*, void> Operation,
+ TScalar0 s0,
+ TScalar1 s1)
where T: unmanaged, INumber
where TScalar0: unmanaged, INumber
where TScalar1: unmanaged, INumber
@@ -279,14 +279,14 @@ namespace StgSharp.Mathematics.Numeric
return PublicTaskPrivate(package);
}
- public static unsafe Stack PublicTask(
- MatrixSegmentEnumeration source,
- MatrixSegmentEnumeration ans,
- delegate**, MatrixKernel*, MatrixKernel*, void> Operation,
- TScalar0 s0,
- TScalar1 s1,
- TScalar2 s2,
- TScalar3 s3)
+ public static unsafe MatrixParallelHandle PublicTask(
+ MatrixSegmentEnumeration source,
+ MatrixSegmentEnumeration ans,
+ delegate**, MatrixKernel*, MatrixKernel*, void> Operation,
+ TScalar0 s0,
+ TScalar1 s1,
+ TScalar2 s2,
+ TScalar3 s3)
where T: unmanaged, INumber
where TScalar0: unmanaged, INumber
where TScalar1: unmanaged, INumber
@@ -319,14 +319,14 @@ namespace StgSharp.Mathematics.Numeric
return PublicTaskPrivate(package);
}
- public static unsafe Stack PublicTask(
- MatrixSegmentEnumeration left,
- MatrixSegmentEnumeration right,
- MatrixSegmentEnumeration ans,
- delegate**, MatrixKernel*, MatrixKernel*, void> Operation,
- TScalar0 s0,
- TScalar1 s1,
- TScalar2 s2)
+ public static unsafe MatrixParallelHandle PublicTask(
+ MatrixSegmentEnumeration left,
+ MatrixSegmentEnumeration right,
+ MatrixSegmentEnumeration ans,
+ delegate**, MatrixKernel*, MatrixKernel*, void> Operation,
+ TScalar0 s0,
+ TScalar1 s1,
+ TScalar2 s2)
where T: unmanaged, INumber
where TScalar0: unmanaged, INumber
where TScalar1: unmanaged, INumber
@@ -362,15 +362,15 @@ namespace StgSharp.Mathematics.Numeric
return PublicTaskPrivate(package);
}
- public static unsafe Stack PublicTask(
- MatrixSegmentEnumeration source,
- MatrixSegmentEnumeration ans,
- delegate**, MatrixKernel*, MatrixKernel*, void> Operation,
- TScalar0 s0,
- TScalar1 s1,
- TScalar2 s2,
- TScalar3 s3,
- TScalar4 s4)
+ public static unsafe MatrixParallelHandle PublicTask(
+ MatrixSegmentEnumeration source,
+ MatrixSegmentEnumeration ans,
+ delegate**, MatrixKernel*, MatrixKernel*, void> Operation,
+ TScalar0 s0,
+ TScalar1 s1,
+ TScalar2 s2,
+ TScalar3 s3,
+ TScalar4 s4)
where T: unmanaged, INumber
where TScalar0: unmanaged, INumber
where TScalar1: unmanaged, INumber
@@ -405,15 +405,15 @@ namespace StgSharp.Mathematics.Numeric
return PublicTaskPrivate(package);
}
- public static unsafe Stack PublicTask(
- MatrixSegmentEnumeration left,
- MatrixSegmentEnumeration right,
- MatrixSegmentEnumeration ans,
- delegate**, MatrixKernel*, MatrixKernel*, void> Operation,
- TScalar0 s0,
- TScalar1 s1,
- TScalar2 s2,
- TScalar3 s3)
+ public static unsafe MatrixParallelHandle PublicTask(
+ MatrixSegmentEnumeration left,
+ MatrixSegmentEnumeration right,
+ MatrixSegmentEnumeration ans,
+ delegate**, MatrixKernel*, MatrixKernel*, void> Operation,
+ TScalar0 s0,
+ TScalar1 s1,
+ TScalar2 s2,
+ TScalar3 s3)
where T: unmanaged, INumber
where TScalar0: unmanaged, INumber
where TScalar1: unmanaged, INumber
@@ -451,16 +451,16 @@ namespace StgSharp.Mathematics.Numeric
return PublicTaskPrivate(package);
}
- public static unsafe Stack PublicTask(
- MatrixSegmentEnumeration source,
- MatrixSegmentEnumeration