switch root namespace name to NITLOAD

This commit is contained in:
Youmu Liu
2026-09-02 18:15:03 +08:00
parent 4218baad48
commit 7c7101ee48
502 changed files with 710 additions and 721 deletions
@@ -0,0 +1,45 @@
// -----------------------------------------------------------------------------
// file="MatrixOperatorPolicy"
// Project: StgSharp
// Copyright (c) Nitload.
// SPDX-License-Identifier: MIT
// -----------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Nitload.Mathematics.Numeric.Runtime
{
internal enum MatrixCachePolicy : short
{
None = 0,
#region usage
Left = 1,
Right = 2,
Ans = 3,
#endregion
#region index direction
RowMajor = 4,
ColMajor = 5,
Sequential = 6,
#endregion
#region shape
Square = 8,
UpperTriangle = 9,
LowerTriangle = 10,
#endregion
}
}
@@ -0,0 +1,157 @@
//-----------------------------------------------------------------------
// -----------------------------------------------------------------------
// 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;
using System.Threading.Tasks;
namespace Nitload.Mathematics.Numeric
{
public static partial class MatrixParallel
{
private static AwaitingQueue _awaitingLeaderHandle;
private static volatile int _createGeneration;
private static int _sortState;
public static MatrixParallelThread[] LeadParallel(
long recommendCount
)
{
int recommend = (recommendCount > int.MaxValue) ? int.MaxValue : ((int)recommendCount);
int min = (int)long.Min(recommend, _threads.Capacity);
min /= 2;
MatrixParallelThread[] ret;
if (_threads.Count < min)
{
WaitHandle handle = new(
_createGeneration,
min,
recommend
);
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(recommend);
_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,169 @@
//-----------------------------------------------------------------------
// -----------------------------------------------------------------------
// 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 Nitload.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;
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,44 @@
// -----------------------------------------------------------------------------
// file="MatrixParallel.Numa"
// Project: StgSharp
// Copyright (c) Nitload.
// SPDX-License-Identifier: MIT
// -----------------------------------------------------------------------------
using Nitload.Common.Collections;
using Nitload.Common.HighPerformance.Memory;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Nitload.Mathematics.Numeric
{
public static unsafe partial class MatrixParallel
{
private static L4[] _numaBuffer;
private static NumaMeasurement[] _numaMeasurements;
private static int[] _numaPayload;
private static MatrixParallelThread[][] _numaSyncHeavy;
private static MatrixParallelThread[][] _numaWaveFront;
private static MatrixParallelThread[] _threads;
private static void UpdateThreadPayload()
{
for (int i = 0; i < _numaPayload.Length; i++) { }
}
private struct NumaMeasurement
{
public uint ActivePredictors;
public uint ActiveThreadCount;
public ulong ActiveTasks;
}
}
}
@@ -0,0 +1,72 @@
// -----------------------------------------------------------------------------
// file="MatrixParallel.Publish"
// Project: StgSharp
// Copyright (c) Nitload.
// SPDX-License-Identifier: MIT
// -----------------------------------------------------------------------------
using Nitload.Common.Collections;
using Nitload.Common.HighPerformance.Memory;
using Nitload.Mathematics;
using Nitload.Mathematics.Numeric.Runtime;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace Nitload.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<TTaskQueue>(
MatrixParallelTask* package
)
{
/*
int primCount = package->PrimCount;
int secCount = package->SecCount;
long count = (long)primCount * secCount;
/**/
// Console.WriteLine($"amount of kernels is {count}");
long payload = 0;
int payloadIndex = 0;
ulong additionalPayload = 0;
for (int i = 0; i < _numaMeasurements.Length; i++)
{
MatrixParallelThread[] numa = _numaWaveFront[i];
if ((numa is null) || (numa.Length == 0))
{
continue;
}
ulong total = (ulong)_numaWaveFront[i].Length;
NumaMeasurement measure = _numaMeasurements[i];
ulong numaPayload = measure.ActiveTasks;
// uint numaActive = measure.ActiveThreadCount;
long curPayload = ((long)total) - (((long)(numaPayload + additionalPayload + 63)) / 64);
if (curPayload < payload)
{
payload = curPayload;
payloadIndex = i;
}
}
L4 cache = _numaBuffer[payloadIndex];
MatrixParallelThread[] selectedNuma = _numaWaveFront[payloadIndex];
throw new NotImplementedException();
}
}
}
@@ -0,0 +1,199 @@
// -----------------------------------------------------------------------------
// file="MatrixParallel"
// Project: StgSharp
// Copyright (c) Nitload.
// SPDX-License-Identifier: MIT
// -----------------------------------------------------------------------------
using Nitload.Common.Collections;
using Nitload.Common.HighPerformance.ProcessorAbstraction;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace Nitload.Mathematics.Numeric
{
public static unsafe partial class MatrixParallel
{
private const int RESERVED_THREAD_COUNT = 4;
private static bool _meaningful;
private static CapacityFixedStack<MatrixParallelThread> _retiredThreads;
public static bool IsParallelSupported { get; } = Environment.ProcessorCount > 6;
public static bool IsParallelMeaningful => IsParallelSupported &&
IsInitialized &&
_meaningful;
public static int ContextCount { get; private set; }
private static bool IsInitialized { get; set; }
internal static void Deinit()
{
foreach (MatrixParallelThread t in _threads)
{
t.Pause();
t.Dispose();
}
foreach (MatrixParallelThread t in _retiredThreads) {
t.Dispose();
}
ContextCount = 0;
IsInitialized = false;
}
internal static void Init()
{
Dictionary<ulong, int> contextMap = [];
if (IsInitialized) {
return;
}
if (!IsParallelSupported)
{
IsInitialized = true;
return;
}
contextMap = [];
int count = Environment.ProcessorCount;
SIMDID globalSimd = new(0);
_retiredThreads = new(RESERVED_THREAD_COUNT);
// init thread on all logical cores
_numaWaveFront = Numa.CreateForeachThread<MatrixParallelThread>(
core => {
MatrixParallelThread thread = new(core);
SpinWait.SpinUntil(() => thread.State == MatrixThreadState.Ready);
SIMDID simd = thread.Simd;
ulong mask = simd.Mask;
contextMap[mask] = contextMap.TryGetValue(mask, out int contextCount) ?
(contextCount + 1) :
1;
globalSimd = (globalSimd.Mask != 0) ? UniteSIMDID(globalSimd, simd) : simd;
return thread;
});
// make global simd context
IntrinsicContext globalContext = new();
LoadIntrinsicFunction(&globalContext, globalSimd.Mask);
NumericalModule.GlobalContext = globalContext;
NumericalModule.GlobalIntrinsicMask = globalSimd;
ContextCount = contextMap.Count;
// retire threads
if (ContextCount == 1)
{
MatrixParallelThread[] threadArr = _numaWaveFront[0];
int retireCount = Math.Min(RESERVED_THREAD_COUNT, Math.Max(0, threadArr.Length));
for (int i = 1; i <= retireCount; i++) {
RetireThread(threadArr[^i]);
}
_numaWaveFront[0] = threadArr[0..^retireCount];
} else
{
RetireWhenMultipleSIMDID(_numaWaveFront);
}
_meaningful = _threads.Length > 1;
// _awaitingLeaderHandle = new AwaitingQueue();
IsInitialized = true;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void RetireThread(
MatrixParallelThread thread
)
{
thread.Pause();
thread.Dispose();
_retiredThreads.Push(thread);
}
private static void RetireWhenMultipleSIMDID(
MatrixParallelThread[][] threads
)
{
MatrixParallelThread[] allThreads = new MatrixParallelThread[Environment.ProcessorCount];
int offset = 0;
foreach (MatrixParallelThread[] threadArr in threads)
{
Array.Copy(threadArr, 0, allThreads, offset, threadArr.Length);
offset += threadArr.Length;
}
Array.Sort(allThreads, static(
left,
right
) => CompareSIMDID(left.Simd, right.Simd));
int retireCount = Math.Min(RESERVED_THREAD_COUNT, Math.Max(0, allThreads.Length));
MatrixParallelThread[] retireArr = new MatrixParallelThread[retireCount];
for (int i = 0; i < retireCount; i++)
{
MatrixParallelThread thread = allThreads[i];
retireArr[i] = thread;
RetireThread(thread);
}
// rebuild numa active arrays
for (int numa = 0; numa < _numaWaveFront.Length; numa++)
{
MatrixParallelThread[] source = threads[numa];
int keepCount = 0;
for (int i = 0; i < source.Length; i++)
{
if (!retireArr.Contains(source[i])) {
keepCount++;
}
}
MatrixParallelThread[] active = new MatrixParallelThread[keepCount];
int index = 0;
for (int i = 0; i < source.Length; i++)
{
MatrixParallelThread thread = source[i];
if (!retireArr.Contains(thread)) {
active[index++] = thread;
}
}
_numaWaveFront[numa] = active;
}
_threads = allThreads[retireCount..];
}
#region C invoke
[LibraryImport(Native.LibName, EntryPoint = "sn_compare_simd")]
[UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
[DefaultDllImportSearchPaths(DllImportSearchPath.AssemblyDirectory)]
private static partial int CompareSIMDID(
SIMDID left,
SIMDID right
);
[LibraryImport(Native.LibName, EntryPoint = "load_intrinsic_function")]
[UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
[DefaultDllImportSearchPaths(DllImportSearchPath.AssemblyDirectory)]
private static partial void LoadIntrinsicFunction(
IntrinsicContext* context,
ulong id
);
[LibraryImport(Native.LibName, EntryPoint = "sn_get_unite_simd")]
[UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
[DefaultDllImportSearchPaths(DllImportSearchPath.AssemblyDirectory)]
private static partial SIMDID UniteSIMDID(
SIMDID left,
SIMDID right
);
#endregion
}
}
@@ -0,0 +1,77 @@
// -----------------------------------------------------------------------------
// file="MatrixParallelQueue"
// Project: StgSharp
// Copyright (c) Nitload.
// SPDX-License-Identifier: MIT
// -----------------------------------------------------------------------------
using Microsoft.VisualBasic.FileIO;
using Nitload.Common.HighPerformance.Memory;
using Nitload.Mathematics.Numeric.Runtime;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices.JavaScript;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Nitload.Mathematics.Numeric
{
internal unsafe class MatrixParallelQueue : IDisposable
{
private MatrixParallelTask[] _currentPack;
private MatrixParallelTask[] _predictBuffer;
private bool disposedValue;
private int _currentCapacity;
private int _cursor;
private int _predictCapacity;
private ManualResetEventSlim _exchangeLock = new();
public MatrixParallelQueue()
{
_currentPack = new MatrixParallelTask[512];
_predictBuffer = new MatrixParallelTask[512];
}
public void Dispose()
{
Dispose(disposing:true);
GC.SuppressFinalize(this);
}
public bool TryGetTask(
out MatrixParallelTask task
)
{
if (_cursor >= _currentCapacity)
{
task = default;
return false;
}
task = _currentPack[_cursor++];
return true;
}
protected virtual void Dispose(
bool disposing
)
{
if (!disposedValue)
{
if (disposing) {
_exchangeLock.Dispose();
}
disposedValue = true;
}
}
}
}
@@ -0,0 +1,70 @@
// -----------------------------------------------------------------------------
// file="MatrixParallelTask"
// Project: StgSharp
// Copyright (c) Nitload.
// SPDX-License-Identifier: MIT
// -----------------------------------------------------------------------------
using Nitload.Common.HighPerformance.Memory;
using Nitload.Common.HighPerformance.ProcessorAbstraction;
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace Nitload.Mathematics.Numeric.Runtime
{
[StructLayout(LayoutKind.Sequential)]
internal struct MatrixParallelSource
{
public MatrixParallelTask Task;
public ulong Count;
public ulong Cursor;
}
[StructLayout(LayoutKind.Explicit, Size = 128)]
internal unsafe struct MatrixParallelTask
{
[FieldOffset(104)] private ulong _reserved0;
[FieldOffset(0)] public L4.Handle Buffer0;
[FieldOffset(16)] public L4.Handle Buffer1;
[FieldOffset(32)] public L4.Handle Buffer2;
[FieldOffset(48)] public L4.Handle Buffer3;
[FieldOffset(112)] public M128 ScalarPack;
[FieldOffset(64)] public M512 Profile;
[FieldOffset(64)] public MatrixElementType ElementType; //记录了类型掩码的类型位宽的union,大小4byte
[FieldOffset(68)] public MatrixIntrinsicHandle ComputeHandle; //记录了函数指针在类型组中的索引,实际就是int,但是为每一个索引起了名字,于是变成了enum,大小4byte
public MatrixParallelTask()
{
Unsafe.SkipInit(out this);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Copy(
MatrixParallelTask* source,
MatrixParallelTask* target
)
{
Buffer.MemoryCopy(source, target, sizeof(MatrixParallelTask),
sizeof(MatrixParallelTask));
}
#region offset and length settings
[FieldOffset(72)] public int Offset0;
[FieldOffset(76)] public int Count0;
[FieldOffset(80)] public int Offset1;
[FieldOffset(84)] public int Count1;
[FieldOffset(88)] public int Offset2;
[FieldOffset(92)] public int Count2;
[FieldOffset(96)] public int Offset3;
[FieldOffset(100)] public int Count3;
#endregion
}
}
@@ -0,0 +1,106 @@
//-----------------------------------------------------------------------
// -----------------------------------------------------------------------
// 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 Nitload.Common.Internal;
using Nitload.Mathematics;
using Nitload.Mathematics.Internal;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace Nitload.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;
NumericalModule.GlobalContext.mat_sk[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;
NumericalModule.GlobalContext.mat_sk[f64].kernel_tile_fma(leftBuffer, rightBuffer,
ansBuffer, enumeration);
}
}
}
}
@@ -0,0 +1,76 @@
//-----------------------------------------------------------------------
// -----------------------------------------------------------------------
// 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 Nitload.Mathematics;
using Nitload.Mathematics.Internal;
using System;
using System.Runtime.CompilerServices;
namespace Nitload.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,17 @@
// -----------------------------------------------------------------------------
// file="MatrixParallelThread.Sequential"
// Project: StgSharp
// Copyright (c) Nitload.
// SPDX-License-Identifier: MIT
// -----------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Nitload.Mathematics.Numeric.Runtime
{
internal class MatrixParallelThread { }
}
@@ -0,0 +1,179 @@
// -----------------------------------------------------------------------------
// file="MatrixParallelThread"
// Project: StgSharp
// Copyright (c) Nitload.
// SPDX-License-Identifier: MIT
// -----------------------------------------------------------------------------
using Nitload.Common.HighPerformance.ProcessorAbstraction;
using Nitload.Common.Internal;
using Nitload.Mathematics.Numeric.Runtime;
using Nitload.Threading;
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
namespace Nitload.Mathematics.Numeric
{
internal enum MatrixThreadState : int
{
Born = 0,
Ready = 1,
Running = 2,
Idle = 4,
Retired = 8,
}
public unsafe partial class MatrixParallelThread : IEquatable<MatrixParallelThread>, IDisposable
{
private IntrinsicContext* _context;
private readonly MatrixParallelTask* _currentTask;
private volatile bool _disposed;
private readonly ManualResetEventSlim _resetEvent;
private volatile MatrixThreadState _target;
private Thread _managedThread;
internal MatrixParallelThread(
LogicalCore binded
)
{
_resetEvent = new ManualResetEventSlim(false);
_managedThread = new Thread(MatrixParallelWorkLoad);
_managedThread.Start();
BindedLogicalCore = binded;
}
public LogicalCore BindedLogicalCore { get; init; }
public ThreadPriority AfterWork { get; set; }
internal MatrixThreadState State { get; private set; }
internal SIMDID Simd { get; private set; }
public void Dispose()
{
Dispose(disposing:true);
GC.SuppressFinalize(this);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Restart()
{
_resetEvent.Set();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void Pause()
{
ObjectDisposedException.ThrowIf(_disposed, nameof(MatrixParallelThread));
if (State == MatrixThreadState.Idle) {
return;
}
_resetEvent.Set();
SpinWait.SpinUntil(() => State == MatrixThreadState.Idle);
_managedThread.Join();
}
protected virtual void Dispose(
bool disposing
)
{
if (!_disposed)
{
if (disposing)
{
_disposed = true;
_resetEvent.Set();
_managedThread.Join();
_resetEvent.Dispose();
}
}
}
private unsafe void MatrixParallelWorkLoad()
{
State = MatrixThreadState.Born;
// Bind OS-thread affinity once when the worker starts running
ThreadHelper.BindToLogicalCore(BindedLogicalCore);
_ = Thread.Yield();
if (Simd.Mask != 0)
{
SIMDID feature = new(GetSimdId());
IntrinsicContext* contextPtr = stackalloc IntrinsicContext[1];
LoadIntrinsicFunction(contextPtr, feature.Mask);
Simd = feature;
_context = contextPtr;
}
MatrixParallelTask* taskPtr = stackalloc MatrixParallelTask[4];
State = MatrixThreadState.Ready;
while (true)
{
// Thread self = Thread.CurrentThread;
_resetEvent.Wait();
_resetEvent.Reset();
if (_disposed)
{
break;
}
if (_target == MatrixThreadState.Idle)
{
State = MatrixThreadState.Idle;
continue;
}
State = MatrixThreadState.Idle;
State = MatrixThreadState.Running;
_managedThread.Priority = ThreadPriority.Highest;
// MatrixParallelQueue taskQueue = BindedWrap.TaskQueue;
/*
if (0 > (int)p ->ComputeHandle) {
SpecialBufferCompute(p);
}
switch (p->ComputeMode)
{
case MatrixIndexStyle.BUFFER_INDEX:
BufferCompute(p);
break;
default:
break;
}
/**/
_managedThread.Priority = AfterWork;
State = MatrixThreadState.Idle;
}
State = MatrixThreadState.Retired;
}
#pragma warning disable CA5393
[LibraryImport(Native.LibName, EntryPoint = "sn_get_simd_level_local")]
[UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
[DefaultDllImportSearchPaths(DllImportSearchPath.AssemblyDirectory)]
internal static partial ulong GetSimdId();
[LibraryImport(Native.LibName, EntryPoint = "load_intrinsic_function")]
[UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
[DefaultDllImportSearchPaths(DllImportSearchPath.AssemblyDirectory)]
private static unsafe partial void LoadIntrinsicFunction(
IntrinsicContext* context,
ulong id
);
public bool Equals(
MatrixParallelThread? other
)
{
return (other is not null) && ReferenceEquals(this, other);
}
#pragma warning restore CA5393
}
}
@@ -0,0 +1,107 @@
// -----------------------------------------------------------------------------
// file="MatrixParallelWrap"
// Project: StgSharp
// Copyright (c) Nitload.
// SPDX-License-Identifier: MIT
// -----------------------------------------------------------------------------
using Nitload.Common.Collections;
using Nitload.Common.HighPerformance.Memory;
using Nitload.Mathematics.Numeric.Runtime;
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;
using System.Threading.Tasks;
namespace Nitload.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;
private readonly CountdownEvent _countdownEvent;
internal MatrixParallelWrap(
MatrixParallelThread[] threadArray
)
{
_threads = threadArray;
_countdownEvent = new CountdownEvent(threadArray.Length);
}
public ReadOnlySpan<MatrixParallelThread> Threads => _disposed ? [] : _threads;
public ThreadPriority AfterWork { get; private set; }
internal L4 DataCache { get; set; }
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void LaunchParallel(
SleepMode afterWork
)
{
ObjectDisposedException.ThrowIf(_disposed, nameof(MatrixParallelWrap));
AfterWork = (ThreadPriority)afterWork;
foreach (MatrixParallelThread thread in _threads)
{
thread.AfterWork = AfterWork;
// thread.BindedWrap = this;
}
WaitAllWraps();
}
public void WaitAllWraps()
{
if (_disposed) {
return;
}
_countdownEvent.Wait();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void ReportThreadAccomplished()
{
ObjectDisposedException.ThrowIf(_disposed, nameof(MatrixParallelWrap));
_ = _countdownEvent.Signal();
}
private void Dispose(
bool disposing
)
{
if (_disposed) {
return;
}
if (disposing)
{
// MatrixParallel.ReturnParallelResources(ref _threads);
_countdownEvent.Dispose();
}
_disposed = true;
}
}
}
@@ -0,0 +1,21 @@
// -----------------------------------------------------------------------------
// file="QueueFactory"
// Project: StgSharp
// Copyright (c) Nitload.
// SPDX-License-Identifier: MIT
// -----------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Nitload.Mathematics.Numeric
{
internal interface IMatrixQueueFactory
{
// IMatrixParallelQueue<IMatrixParallelQueue> CreateSequential();
}
}