arrange of proj structure

This commit is contained in:
Youmu Liu
2026-02-27 17:09:13 +08:00
parent 15434ed053
commit a798ab07f1
173 changed files with 32304 additions and 33955 deletions
@@ -0,0 +1,146 @@
//-----------------------------------------------------------------------
// -----------------------------------------------------------------------
// 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.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace StgSharp.Mathematics.Numeric
{
public static partial class MatrixParallel
{
private static AwaitingQueue _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,
min,
recommendCount
);
do
{
if (Interlocked.Exchange(ref _sortState, 1) == 0)
{
_awaitingLeaderHandle.Enqueue(handle);
_ = Interlocked.Exchange(ref _sortState, 0);
Interlocked.Increment(ref _createGeneration);
break;
}
} while (true);
int cycleGeneration = _createGeneration;
do
{
Thread.Sleep(0);
if (_createGeneration != cycleGeneration)
{
if (Interlocked.Exchange(ref _sortState, 1) == 0)
{
if (_awaitingLeaderHandle.TryPopIfRefEqual(cycleGeneration, in 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;
}
}
} while (true);
} else
{
// directly get the leader
while (true)
{
if (Interlocked.Exchange(ref _sortState, 1) == 0)
{
ret = _threads.PopRange(recommendCount);
_createGeneration++;
_ = Interlocked.Exchange(ref _sortState, 0);
return ret;
}
}
}
// return ret;
}
public static void ReturnParallelResources(ref MatrixParallelThread[] pool)
{
while (true)
{
if (Interlocked.Exchange(ref _sortState, 1) == 0)
{
_threads.PushRange(pool);
Interlocked.Exchange(ref _sortState, 0);
break;
}
}
pool = null!;
}
private record class WaitHandle(int generation, int least, int best)
{
public int CreateGeneration { get; init; } = generation;
public int LeastCount { get; init; } = least;
public int BestCount { get; init; } = best;
public int Priority { get; private set; }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void UpdatePriority(int currentGeneration)
{
Priority = (currentGeneration - CreateGeneration) * (MatrixParallel._threads.Capacity - LeastCount);
}
}
}
}
@@ -0,0 +1,156 @@
//-----------------------------------------------------------------------
// -----------------------------------------------------------------------
// file="MatrixParallel.AwaitingQueue"
// 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.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace StgSharp.Mathematics.Numeric
{
public static partial class MatrixParallel
{
/*
* Because caller of this class has its own sync object
* this queue will use no sync object internally.
*/
private class AwaitingQueue
{
private Element _quickElements = new();
private volatile int _count;
private readonly Queue<WaitHandle> _fallback = [];
public AwaitingQueue() { }
public void Enqueue(WaitHandle handle)
{
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)
{
handle = null!;
return false;
}
for (int i = 0; i < _count; i++) {
_quickElements[i].UpdatePriority(generation);
}
Element.Sort(ref _quickElements);
handle = _quickElements[0];
_count--;
_quickElements[0] = default!;
if (_count > 7) {
_ = _fallback.TryDequeue(out _quickElements[0]!);
}
return true;
}
public bool TryPeek(int generation, out WaitHandle handle)
{
if (_count == 0)
{
handle = null!;
return false;
}
for (int i = 0; i < _count; i++) {
_quickElements[i].UpdatePriority(generation);
}
Element.Sort(ref _quickElements);
handle = _quickElements[0];
return true;
}
public bool TryPopIfRefEqual(int generation, in WaitHandle handle)
{
if (_count == 0) {
return false;
}
for (int i = 0; i < _count; i++) {
_quickElements[i].UpdatePriority(generation);
}
Element.Sort(ref _quickElements);
if (!ReferenceEquals(_quickElements[0], handle)) {
return false;
}
_count--;
_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(ref Element e)
{
int maxIdx = 0;
WaitHandle first = e[0];
int maxPr = first?.Priority ?? int.MinValue;
for (int i = 1; i < 8; i++)
{
WaitHandle cur = e[i];
int p = cur?.Priority ?? int.MinValue;
if (p > maxPr)
{
maxPr = p;
maxIdx = i;
}
}
if (maxIdx != 0) {
(e[0], e[maxIdx]) = (e[maxIdx], e[0]);
}
}
}
}
}
@@ -0,0 +1,80 @@
//-----------------------------------------------------------------------
// -----------------------------------------------------------------------
// file="MatrixParallel.Publish"
// 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 StgSharp.Collections;
using StgSharp.HighPerformance;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace StgSharp.Mathematics.Numeric
{
public static partial class MatrixParallel
{
private const int MIN_TASK_PER_THREAD = 256;
private const int REC_TASK_PER_THREAD = 1024;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static unsafe MatrixParallelWrap ScheduleTask(
MatrixParallelTask* package
)
{
switch (package->ComputeMode.OperationStyle)
{
case MatrixIndexStyle.BUFFER_INDEX:
return ScheduleBufferTask(package);
default:
throw new InvalidOperationException($"Unknown mode {package->ComputeMode.OperationStyle}.");
}
}
private static unsafe MatrixParallelWrap ScheduleBufferTask(
MatrixParallelTask* package
)
{
int primCount = package->PrimCount;
int secCount = package->SecCount;
long count = (long)primCount * secCount;
// Console.WriteLine($"amount of kernels is {count}");
long recommendCount = count / 1024;
MatrixParallelThread[] pool = LeadParallel((int)recommendCount);
MatrixParallelWrap wrap = new MatrixParallelWrap(pool);
wrap.TaskQueue = MatrixParallelQueue.Rent(package);
return wrap;
}
}
}
@@ -0,0 +1,132 @@
//-----------------------------------------------------------------------
// -----------------------------------------------------------------------
// file="MatrixParallel"
// 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 StgSharp.Collections;
using StgSharp.HighPerformance.Memory;
using StgSharp.Internal;
using StgSharp.Mathematics.Internal;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace StgSharp.Mathematics.Numeric
{
public static partial class MatrixParallel
{
private static bool _meaningful;
private static CapacityFixedStack<MatrixParallelThread> _threads;
private static ConcurrentDictionary<SIMDID, nint> contextMap;
private static SlabAllocator<IntrinsicContext> contextAllocator;
public static bool IsParallelSupported { get; } = Environment.ProcessorCount > 6;
public static bool IsParallelMeaningful => Environment.ProcessorCount > 6 && IsInitialized;
private static bool IsInitialized { get; set; } = false;
internal static unsafe IntrinsicContext* GetContext(
SIMDID simd
)
{
if (!IsParallelSupported) {
return null;
}
if (contextMap.TryGetValue(simd, out nint handle))
{
return (IntrinsicContext*)handle;
} else
{
IntrinsicContext* context = (IntrinsicContext*)contextAllocator.Allocate();
return context;
}
}
internal static void Init()
{
if (IsInitialized) {
return;
}
if (!IsParallelSupported)
{
IsInitialized = true;
return;
}
MatrixParallelFactory.Init();
contextAllocator = SlabAllocator<IntrinsicContext>.Create(4, SlabBufferLayout.Chunked, false);
contextMap = [];
int count = Environment.ProcessorCount;
_threads = new(count);
for (int i = 0; i < count; i++)
{
MatrixParallelThread thread = new MatrixParallelThread(i);
_threads.Push(thread);
SpinWait.SpinUntil(() => thread.State == MatrixThreadState.Ready);
}
// TODO 构建全局的保底上下文
foreach (MatrixParallelThread thread in _threads) { }
if (contextMap.Keys.Count == 1)
{
for (int i = 0; i < 4; i++)
{
MatrixParallelThread thread = _threads.Pop();
thread.Dispose();
}
} else
{
// TODO 排序并丢弃四个能力最弱线程
}
_awaitingLeaderHandle = new AwaitingQueue();
IsInitialized = true;
}
[LibraryImport(Native.LibName, EntryPoint = "sn_compare_simd")]
[UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
private static unsafe partial ulong CompareSIMDID(
IntrinsicContext* context,
ulong id
);
[LibraryImport(Native.LibName, EntryPoint = "load_intrinsic_function")]
[UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
private static unsafe partial void LoadIntrinsicFunction(
IntrinsicContext* context,
ulong id
);
}
}
@@ -0,0 +1,81 @@
//-----------------------------------------------------------------------
// -----------------------------------------------------------------------
// file="MatrixParallelQueue"
// 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 Microsoft.VisualBasic.FileIO;
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 unsafe class MatrixParallelQueue
{
private static ConcurrentStack<MatrixParallelQueue> _recycle = [];
private MatrixParallelTask* _package;
private ulong _cursor;
private ulong _maxCount;
private MatrixParallelQueue() { }
public MatrixParallelTask* Package => _package;
public static MatrixParallelQueue Rent(
MatrixParallelTask* pack
)
{
if (!_recycle.TryPop(out MatrixParallelQueue? queue)) {
queue = new MatrixParallelQueue();
}
queue._package = pack;
queue._maxCount = (ulong)pack->PrimCount * (ulong)pack->SecCount;
queue._cursor = 0;
return queue;
}
public static void Return(
MatrixParallelQueue queue
)
{
_recycle.Push(queue);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public (ulong count, ulong offset) Steal(
ulong request
)
{
ulong cursor = Interlocked.Add(ref _cursor, request) - request;
return (Math.Min(request, Math.Max(0, _maxCount - cursor)), cursor);
}
}
}
@@ -0,0 +1,64 @@
//-----------------------------------------------------------------------
// -----------------------------------------------------------------------
// file="MatrixParallelTask"
// 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 StgSharp.HighPerformance;
using StgSharp.Mathematics.Internal;
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace StgSharp.Mathematics.Numeric
{
[StructLayout(LayoutKind.Explicit)]
internal unsafe struct MatrixParallelTask
{
[FieldOffset(0)]public MatrixKernel* Mat1; // 8
[FieldOffset(8)] public MatrixKernel* Mat2; // 8
[FieldOffset(16)] public MatrixKernel* Mat3; // 16
[FieldOffset(32)] public int Common_i;
[FieldOffset(36)] public int Common_j;
[FieldOffset(40)] public int Common_k;
[FieldOffset(44)] public int i;
[FieldOffset(48)] public int j;
[FieldOffset(52)] public int k;
[FieldOffset(56)] public MatrixElementType ElementType; // 56
[FieldOffset(24)] public nint Span; // 24
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Copy(
MatrixParallelTask* source,
MatrixParallelTask* target
)
{
Buffer.MemoryCopy(source, target, sizeof(MatrixParallelTask),
sizeof(MatrixParallelTask));
}
}
}
@@ -0,0 +1,105 @@
//-----------------------------------------------------------------------
// -----------------------------------------------------------------------
// file="MatrixParallelThread.Fma"
// 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 StgSharp.HighPerformance;
using StgSharp.Internal;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace StgSharp.Mathematics.Numeric
{
public partial class MatrixParallelThread
{
internal static unsafe void ComputeFmaPanelF32(
MatrixParallelTask* p
)
{
int f32 = MatrixElementType.F32.IntrinsicNode;
MatrixKernel* leftBuffer = (MatrixKernel*)p->Left;
MatrixKernel* rightBuffer = (MatrixKernel*)p->Right;
MatrixKernel* ansBuffer = (MatrixKernel*)p->Answer;
ref long offsetRef = ref Unsafe.As<int, long>(ref p->PrimTileOffset);
ref long lengthRef = ref Unsafe.As<int, long>(ref p->PrimCount);
int ansWidth = p->AnsPrimOffset;
int ansHeight = p->AnsSecOffset;
int commonK = p->LeftPrimOffset;
M128* enumeration = stackalloc M128[1];
enumeration->Member<int>(2) = commonK;
enumeration->Member<int>(3) = ansHeight;
// in this occasion size must be 1
for (long c = offsetRef; c < offsetRef + lengthRef; c++)
{
int i = (int)(c / ansHeight);
int j = (int)(c % ansHeight);
enumeration->Member<int>(0) = i;
enumeration->Member<int>(1) = j;
NativeIntrinsic.Context.mat[f32].kernel_tile_fma(leftBuffer, rightBuffer, ansBuffer,
enumeration);
}
}
internal static unsafe void ComputeFmaPanelF64(
MatrixParallelTask* p
)
{
int f64 = MatrixElementType.F64.IntrinsicNode;
// int size = 1;
MatrixKernel* leftBuffer = (MatrixKernel*)p->Left;
MatrixKernel* rightBuffer = (MatrixKernel*)p->Right;
MatrixKernel* ansBuffer = (MatrixKernel*)p->Answer;
ref long offsetRef = ref Unsafe.As<int, long>(ref p->PrimTileOffset);
ref long lengthRef = ref Unsafe.As<int, long>(ref p->PrimCount);
int ansWidth = p->AnsPrimOffset;
int ansHeight = p->AnsSecOffset;
int commonK = p->LeftPrimOffset;
M128* enumeration = stackalloc M128[1];
enumeration->Member<int>(2) = commonK;
enumeration->Member<int>(3) = ansHeight;
// in this occasion size must be 1
for (long c = offsetRef; c < offsetRef + lengthRef; c++)
{
int i = (int)(c / ansHeight);
int j = (int)(c % ansHeight);
enumeration->Member<int>(0) = i;
enumeration->Member<int>(1) = j;
NativeIntrinsic.Context.mat[f64].kernel_tile_fma(leftBuffer, rightBuffer, ansBuffer,
enumeration);
}
}
}
}
@@ -0,0 +1,75 @@
//-----------------------------------------------------------------------
// -----------------------------------------------------------------------
// file="MatrixParallelThread.Model"
// 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 StgSharp.HighPerformance;
using System;
using System.Runtime.CompilerServices;
namespace StgSharp.Mathematics.Numeric
{
public partial class MatrixParallelThread
{
private const int KernelStealCount = 64;
internal unsafe void BufferCompute(
MatrixParallelTask* p
)
{
// while () { }
int size = p->ElementSize * 16;
long count = Unsafe.As<int, long>(ref p->PrimCount);
long offset = Unsafe.As<int, long>(ref p->PrimTileOffset) * size;
ScalarPacket* scalar = p->Scalar;
IntPtr computeHandle = _context[p->ComputeHandle];
((delegate* unmanaged[Cdecl]<void*, void*, void*, void*, long, void>)computeHandle)((void*)(p->Left + offset),
(void*)(p->Right + offset),
(void*)(p->Answer + offset),
scalar,
count);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal unsafe void SpecialBufferCompute(
MatrixParallelTask* p
)
{
switch ((MatrixElementType)p->ElementSize)
{
case MatrixElementType.F64:
ComputeFmaPanelF64(p);
return;
case MatrixElementType.F32:
ComputeFmaPanelF32(p);
break;
default:
break;
}
}
}
}
@@ -0,0 +1,169 @@
//-----------------------------------------------------------------------
// -----------------------------------------------------------------------
// file="MatrixParallelThread"
// 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 StgSharp.Internal;
using StgSharp.Mathematics.Internal;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace StgSharp.Mathematics.Numeric
{
internal enum MatrixThreadState : int
{
Born = 0,
Ready = 1,
Running = 2,
Idle = 4,
Retired = 8,
}
public unsafe partial class MatrixParallelThread : IDisposable
{
private IntPtr* _context;
private volatile bool _disposed, _isRetireRequested = false;
private readonly ManualResetEventSlim _resetEvent;
private readonly Thread _managedThread;
internal MatrixParallelThread(
int poolId
)
{
_resetEvent = new ManualResetEventSlim(false);
_managedThread = new Thread(MatrixParallelWorkLoad);
_managedThread.Start();
PoolId = poolId;
}
public int PoolId { get; init; }
public ThreadPriority AfterWork { get; set; }
internal ManualResetEventSlim? LeaderEvent { get; set; }
internal IntrinsicContext* Intrinsic { get; set; }
internal bool IsSingle { get; set; }
internal MatrixParallelWrap BindedWrap { get; set; }
internal MatrixThreadState State { get; set; }
internal SIMDID Simd { get; set; }
public void Dispose()
{
Dispose(disposing:true);
GC.SuppressFinalize(this);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Restart()
{
_resetEvent.Set();
}
[LibraryImport(Native.LibName, EntryPoint = "sn_get_simd_level_local")]
[UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial ulong GetSimdId();
[LibraryImport(Native.LibName, EntryPoint = "sn_set_thread_affinity")]
[UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void SetThreadAffinity(
int coreId
);
protected virtual void Dispose(
bool disposing
)
{
if (!_disposed)
{
if (disposing)
{
_isRetireRequested = true;
_resetEvent.Set();
_managedThread.Join();
_resetEvent.Dispose();
}
_disposed = true;
}
}
private unsafe void MatrixParallelWorkLoad()
{
State = MatrixThreadState.Born;
// Bind OS-thread affinity once when the worker starts running
SetThreadAffinity(PoolId);
Thread.Yield();
SIMDID feature = new();
feature.Mask = GetSimdId();
_context = (nint*)MatrixParallel.GetContext(feature);
State = MatrixThreadState.Ready;
while (true)
{
// Thread self = Thread.CurrentThread;
_resetEvent.Wait();
_resetEvent.Reset();
if (_isRetireRequested)
{
break;
}
State = MatrixThreadState.Running;
AfterWork = BindedWrap.AfterWork;
_managedThread.Priority = ThreadPriority.Highest;
if (IsSingle)
{
// TODO 将外部线程绑定到当前线程上,并执行任务包
} else
{
MatrixParallelQueue taskQueue = BindedWrap.TaskQueue;
MatrixParallelTask* p = taskQueue.Package;
if (0 > (int)p ->ComputeHandle) {
SpecialBufferCompute(p);
}
switch (p->ComputeMode)
{
case MatrixIndexStyle.BUFFER_INDEX:
BufferCompute(p);
break;
default:
break;
}
BindedWrap.ReportThreadAccomplished();
}
_managedThread.Priority = AfterWork;
State = MatrixThreadState.Idle;
}
State = MatrixThreadState.Retired;
}
}
}
@@ -0,0 +1,122 @@
//-----------------------------------------------------------------------
// -----------------------------------------------------------------------
// file="MatrixParallelWrap.cs"
// 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 StgSharp.Collections;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace StgSharp.Mathematics.Numeric
{
public enum SleepMode : int
{
QuickWakeup = ThreadPriority.AboveNormal,
NormalSleep = ThreadPriority.BelowNormal,
DeepSleep = ThreadPriority.Lowest,
}
public class MatrixParallelWrap : IDisposable
{
private MatrixParallelThread[] _threads;
private bool _disposed = false;
private int _count;
internal MatrixParallelWrap(MatrixParallelThread[] threadArray)
{
_threads = threadArray;
IsMultithread = threadArray.Length > 1;
_count = threadArray.Length;
}
public MatrixParallelQueue TaskQueue { get; set; }
public ReadOnlySpan<MatrixParallelThread> Threads
{
get
{
if (_disposed) {
throw new ObjectDisposedException(typeof(MatrixParallelWrap).Name);
}
return _threads;
}
}
public ThreadPriority AfterWork { get; private set; }
private bool IsMultithread { get; init; }
public void Dispose()
{
if (_disposed) {
return;
}
MatrixParallel.ReturnParallelResources(ref _threads);
_disposed = true;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void LaunchParallel(SleepMode afterWork)
{
AfterWork = (ThreadPriority)afterWork;
foreach (MatrixParallelThread thread in _threads)
{
thread.AfterWork = AfterWork;
thread.BindedWrap = this;
}
WaitAllWraps();
}
public void WaitAllWraps()
{
if (_disposed) {
throw new ObjectDisposedException(typeof(MatrixParallelWrap).Name);
}
SpinWait.SpinUntil(() => Volatile.Read(ref _count) == 0);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void ReportThreadAccomplished()
{
if (_disposed) {
throw new ObjectDisposedException(typeof(MatrixParallelWrap).Name);
}
Interlocked.Decrement(ref _count);
}
}
}
@@ -0,0 +1,119 @@
//-----------------------------------------------------------------------
// -----------------------------------------------------------------------
// file="MatrixTaskFactory"
// 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 StgSharp.HighPerformance;
using StgSharp.HighPerformance.Memory;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using hlsfAllocator = StgSharp.HighPerformance.Memory.HybridLayerSegregatedFitAllocator;
namespace StgSharp.Mathematics.Numeric
{
internal static unsafe class MatrixParallelFactory
{
private static hlsfAllocator _intermediateResult;
private static
#if NET9_0_OR_GREATER
Lock
#else
object
#endif
_hlsfLock = new();
private static SlabAllocator<ScalarPacket> _scalarAllocator ;
private static SlabAllocator<MatrixParallelTask> _wrapAllocator;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static MatrixParallelTask* CreateBaseTask()
{
MatrixParallelTask* p = (MatrixParallelTask*)_wrapAllocator.Allocate();
Span<byte> s = new Span<byte>((byte*)p, sizeof(MatrixParallelTask));
s.Fill(0);
return p;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ScalarPacket* CreateScalarPacket()
{
ScalarPacket* p = (ScalarPacket*)_scalarAllocator.Allocate();
return p;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe MatrixParallelTask* FromExistPackage(
MatrixParallelTask* exist
)
{
MatrixParallelTask* ptr = (MatrixParallelTask*)_wrapAllocator.Allocate();
MatrixParallelTask.Copy(exist, ptr);
return ptr;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Release(
ScalarPacket* source
)
{
_scalarAllocator.Free((nuint)source);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Release(
MatrixParallelTask* source
)
{
if (source->Scalar != null) {
_scalarAllocator.Free((nuint)source->Scalar);
}
_wrapAllocator.Free((nuint)source);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void Init()
{
if (_intermediateResult is null)
{
_intermediateResult = new hlsfAllocator(64 * 16 * 16);
_scalarAllocator = SlabAllocator<ScalarPacket>.Create(64 * 1024, SlabBufferLayout.Chunked);
_wrapAllocator = SlabAllocator<MatrixParallelTask>.
Create(128 * 1024, SlabBufferLayout.Chunked);
}
}
}
}