From 1479cd7c9f12966e9771dad05603103cdd5be4bd Mon Sep 17 00:00:00 2001 From: Nitload Date: Sun, 9 Nov 2025 03:02:28 +0800 Subject: [PATCH] Daily update on 20251109-030228 by Nitload Youmu. Additional Message : Dynamic wrapping is briefly ok, a special sorting is required. Signed-off-by: Nitload --- .../Numeric/MatrixComputeModel.cs | 12 +- .../Numeric/MatrixParallel.Await.cs | 72 ++++--- .../Numeric/MatrixParallel.AwaitingQueue.cs | 178 ++++++++++++++++++ .../Numeric/MatrixParallel.Publish.cs | 4 +- .../Numeric/MatrixParallelPool.cs | 9 +- 5 files changed, 232 insertions(+), 43 deletions(-) create mode 100644 StgSharp.Mathematics/Numeric/MatrixParallel.AwaitingQueue.cs diff --git a/StgSharp.Mathematics/Numeric/MatrixComputeModel.cs b/StgSharp.Mathematics/Numeric/MatrixComputeModel.cs index 99aaf6ab..acef2dab 100644 --- a/StgSharp.Mathematics/Numeric/MatrixComputeModel.cs +++ b/StgSharp.Mathematics/Numeric/MatrixComputeModel.cs @@ -2,8 +2,8 @@ // ----------------------------------------------------------------------- // file="MatrixComputeModel" // Project: StgSharp -// AuthorGroup: Nitload -// Copyright (c) Nitload. All rights reserved. +// AuthorGroup: Nitload Space +// Copyright (c) Nitload Space. 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 @@ -46,7 +46,7 @@ namespace StgSharp.Mathematics.Numeric lCount = (long)p->LeftPrimOffset * p->LeftPrimStride, rCount = (long)p->RightPrimOffset * p->RightPrimStride, aCount = (long)p->ResultPrimOffset * p->ResultPrimStride, - pCount = int.Min(p->PrimCount, p->PrimCountInTile + p->PrimTileOffset) /*count of tile may be too much*/, + pCount = int.Min(p->PrimCount, p->PrimCountInTile + p->PrimTileOffset) /*_count of tile may be too much*/, //edge to reset counters lLimit = pCount - p->LeftPrimOffset, rLimit = pCount - p->RightPrimOffset, @@ -97,7 +97,7 @@ namespace StgSharp.Mathematics.Numeric lCount = (long)p->LeftPrimOffset * p->LeftPrimStride, rCount = (long)p->RightPrimOffset * p->RightPrimStride, aCount = (long)p->ResultPrimOffset * p->ResultPrimStride, - pCount = int.Min(p->PrimCount, p->PrimCountInTile + p->PrimTileOffset) /*count of tile may be too much*/, + pCount = int.Min(p->PrimCount, p->PrimCountInTile + p->PrimTileOffset) /*_count of tile may be too much*/, //edge to reset counters lLimit = pCount - p->LeftPrimOffset, rLimit = pCount - p->RightPrimOffset, @@ -147,7 +147,7 @@ namespace StgSharp.Mathematics.Numeric // set beginning value to counters for primary offsets rCount = (long)p->RightPrimOffset * p->RightPrimStride, aCount = (long)p->ResultPrimOffset * p->ResultPrimStride, - pCount = int.Min(p->PrimCount, p->PrimCountInTile + p->PrimTileOffset) /*count of tile may be too much*/, + pCount = int.Min(p->PrimCount, p->PrimCountInTile + p->PrimTileOffset) /*_count of tile may be too much*/, //edge to reset counters rLimit = pCount - p->RightPrimOffset, aLimit = pCount - p->ResultPrimOffset; @@ -191,7 +191,7 @@ namespace StgSharp.Mathematics.Numeric // set beginning value to counters for primary offsets rCount = (long)p->RightPrimOffset * p->RightPrimStride, aCount = (long)p->ResultPrimOffset * p->ResultPrimStride, - pCount = int.Min(p->PrimCount, p->PrimCountInTile + p->PrimTileOffset) /*count of tile may be too much*/, + pCount = int.Min(p->PrimCount, p->PrimCountInTile + p->PrimTileOffset) /*_count of tile may be too much*/, //edge to reset counters rLimit = pCount - p->RightPrimOffset, aLimit = pCount - p->ResultPrimOffset; diff --git a/StgSharp.Mathematics/Numeric/MatrixParallel.Await.cs b/StgSharp.Mathematics/Numeric/MatrixParallel.Await.cs index a64d2b77..f8dab3b0 100644 --- a/StgSharp.Mathematics/Numeric/MatrixParallel.Await.cs +++ b/StgSharp.Mathematics/Numeric/MatrixParallel.Await.cs @@ -2,8 +2,8 @@ // ----------------------------------------------------------------------- // file="MatrixParallel.Await" // Project: StgSharp -// AuthorGroup: Nitload -// Copyright (c) Nitload. All rights reserved. +// AuthorGroup: Nitload Space +// Copyright (c) Nitload Space. 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 @@ -29,6 +29,7 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; +using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; @@ -37,7 +38,7 @@ namespace StgSharp.Mathematics.Numeric public static partial class MatrixParallel { - private static ConcurrentQueue _awaitingLeaderHandle; + private static AwaitingQueue _awaitingLeaderHandle; private static volatile int _createGeneration = 0; private static int _sortState; @@ -50,44 +51,52 @@ namespace StgSharp.Mathematics.Numeric if (_threads.Count < min) { WaitHandle handle = new WaitHandle - { - CreateGeneration = _createGeneration, - LeastCount = min, - BestCount = recommendCount - }; + ( + _createGeneration, + min, + recommendCount + ); _awaitingLeaderHandle.Enqueue(handle); int cycleGeneration = _createGeneration; - while (true) + do { - // TODO 排队等待,对前八个按照优先级排序,优先级最高的独占进行等待,其他继续排队 + Thread.Sleep(0); + if (_createGeneration != cycleGeneration) { if (Interlocked.Exchange(ref _sortState, 1) == 0) { - // TODO 排序 + if (_awaitingLeaderHandle.TryPopIfRefEqual(cycleGeneration, ref handle)) + { + // Sort is implemented in TryPopIfRefEqual + ret = _threads.PopRange(handle.BestCount); + _createGeneration++; + _ = Interlocked.Exchange(ref _sortState, 0); + return ret; + } _ = 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); - } + } while (true); } else { // directly get the leader - ret = _threads.PopRange(recommendCount); + while (true) + { + if (Interlocked.Exchange(ref _sortState, 1) == 0) + { + ret = _threads.PopRange(recommendCount); + _createGeneration++; + _ = Interlocked.Exchange(ref _sortState, 0); + return ret; + } + } } - _ = Interlocked.Increment(ref _createGeneration); - return ret; + + // return ret; } public static void ReturnParallelResources(ref MatrixParallelThread[] pool) @@ -96,18 +105,21 @@ namespace StgSharp.Mathematics.Numeric pool = null!; } - private record class WaitHandle + private record class WaitHandle(int generation, int least, int best) { - public int CreateGeneration { get; set; } + public int CreateGeneration { get; init; } = generation; - public int LeastCount { get; set; } + public int LeastCount { get; init; } = least; - public int BestCount { get; set; } + public int BestCount { get; init; } = best; - public int CurrentPriority(int currentGeneration) + public int Priority { get; private set; } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void UpdatePriority(int currentGeneration) { - return (currentGeneration - CreateGeneration) * (MatrixParallel._threads.Capacity - LeastCount); + Priority = (currentGeneration - CreateGeneration) * (MatrixParallel._threads.Capacity - LeastCount); } } diff --git a/StgSharp.Mathematics/Numeric/MatrixParallel.AwaitingQueue.cs b/StgSharp.Mathematics/Numeric/MatrixParallel.AwaitingQueue.cs new file mode 100644 index 00000000..49bd62b0 --- /dev/null +++ b/StgSharp.Mathematics/Numeric/MatrixParallel.AwaitingQueue.cs @@ -0,0 +1,178 @@ +//----------------------------------------------------------------------- +// ----------------------------------------------------------------------- +// file="MatrixParallel.AwaitingQueue" +// Project: StgSharp +// AuthorGroup: Nitload Space +// Copyright (c) Nitload Space. 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.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; + +namespace StgSharp.Mathematics.Numeric +{ + public static partial class MatrixParallel + { + + private class AwaitingQueue + { + + private readonly ConcurrentQueue _fallback = []; + private Element _quickElements = new(); + private volatile int _count; + private volatile int _lastGeneration; + private readonly +#if NET9_0_OR_GREATER + Lock +#else + object +#endif + sync = new(); + + public AwaitingQueue() { } + + public void Enqueue(WaitHandle handle) + { + if (_count > 7) + { + _fallback.Enqueue(handle); + Interlocked.Increment(ref _count); + return; + } + lock (sync) + { + if (_count > 7) + { + _fallback.Enqueue(handle); + Interlocked.Increment(ref _count); + return; + } + _quickElements[_count] = handle; + Interlocked.Increment(ref _count); + } + } + + public bool TryDequeue(int generation, out WaitHandle handle) + { + if (_count == 0) + { + _lastGeneration = generation; + handle = null!; + return false; + } + lock (sync) + { + if (_lastGeneration == generation) + { + for (int i = 0; i < _count; i++) { + _quickElements[i].UpdatePriority(generation); + } + Element.Sort(_quickElements); + } else + { + _lastGeneration = generation; + } + handle = _quickElements[0]; + _count--; + if (_count > 7) { + _ = _fallback.TryDequeue(out _quickElements[0]!); + } + return true; + } + } + + public bool TryPeek(int generation, out WaitHandle handle) + { + if (_count == 0) + { + _lastGeneration = generation; + handle = null!; + return false; + } + lock (sync) + { + for (int i = 0; i < _count; i++) { + _quickElements[i].UpdatePriority(generation); + } + Element.Sort(_quickElements); + _lastGeneration = generation; + handle = _quickElements[0]; + _count--; + if (_count > 7) { + _ = _fallback.TryDequeue(out _quickElements[0]!); + } + return true; + } + } + + public bool TryPopIfRefEqual(int generation, ref WaitHandle handle) + { + if (_count == 0) + { + handle = null!; + return false; + } + lock (sync) + { + for (int i = 0; i < _count; i++) { + _quickElements[i].UpdatePriority(generation); + } + Element.Sort(_quickElements); + _lastGeneration = generation; + handle = _quickElements[0]; + _count--; + if (!ReferenceEquals(_quickElements[0], handle)) { + return false; + } + _quickElements[0] = null!; + if (_count > 7) { + _ = _fallback.TryDequeue(out _quickElements[0]!); + } + return true; + } + } + + } + + [InlineArray(8)] + private struct Element + { + + private WaitHandle value; + + public static void Sort(Element e) + { + /* + * yet to do + */ + } + + } + + } +} + diff --git a/StgSharp.Mathematics/Numeric/MatrixParallel.Publish.cs b/StgSharp.Mathematics/Numeric/MatrixParallel.Publish.cs index eda3cf23..8b191f0e 100644 --- a/StgSharp.Mathematics/Numeric/MatrixParallel.Publish.cs +++ b/StgSharp.Mathematics/Numeric/MatrixParallel.Publish.cs @@ -848,7 +848,7 @@ namespace StgSharp.Mathematics.Numeric bool hasSlice = columnAfterBaseTile > 0; bool isLargeSlice = extraColumnCount > 0; - // count tiles for wrap + // _count tiles for wrap int wrapWidth = wrap!.WrapTaskCapacity/**/; int columnFromSlicingCount = (hasSlice ? extraColumnPerThread : 0) * wrapWidth; int baseColumn = wrapWidth * tilePerThreadLess * tileWidth; @@ -869,7 +869,7 @@ namespace StgSharp.Mathematics.Numeric current->SecColumnCountInTile = current->SecCount; current->SecTileOffset = 0; - // remove tiles count + // remove tiles _count extraColumnCount--; columnAfterBaseTile -= columnFromSlicingCount; total -= columnInWrap; diff --git a/StgSharp.Mathematics/Numeric/MatrixParallelPool.cs b/StgSharp.Mathematics/Numeric/MatrixParallelPool.cs index 8553fcfb..0f7c3ce6 100644 --- a/StgSharp.Mathematics/Numeric/MatrixParallelPool.cs +++ b/StgSharp.Mathematics/Numeric/MatrixParallelPool.cs @@ -2,8 +2,8 @@ // ----------------------------------------------------------------------- // file="MatrixParallelPool" // Project: StgSharp -// AuthorGroup: Nitload -// Copyright (c) Nitload. All rights reserved. +// AuthorGroup: Nitload Space +// Copyright (c) Nitload Space. 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 @@ -39,8 +39,7 @@ namespace StgSharp.Mathematics.Numeric public struct MatrixParallelHandle : IDisposable { - private static readonly (int a, int b)[] LookupTable = [ - (1, 1), // 7 + private static readonly (int a, int b)[] LookupTable = [ (1, 1), // 7 (0, 2), // 8 (no non-zero solution) (3, 0), // 9 (no non-zero solution) (2, 1), // 10 @@ -118,7 +117,7 @@ namespace StgSharp.Mathematics.Numeric /* * Thread wrapping to accelerate matrix operations by dividing threads into groups (pool). * For M pool, each containing an average of N threads, we satisfy the condition M * N = T - 4, - * where T is the total thread count of the CPU. Typically, for modern consumer CPUs, T is around 16. + * where T is the total thread _count of the CPU. Typically, for modern consumer CPUs, T is around 16. * For simplicity, let M * N = 16. * * The total time complexity for publishing tasks is O(M + N):