back to matrix

This commit is contained in:
Youmu Liu
2026-03-23 20:11:08 +08:00
parent 0ac7b2b71f
commit eee88e1098
10 changed files with 100 additions and 179 deletions
+7
View File
@@ -42,6 +42,13 @@ namespace StgSharp.Mathematics.Internal
[FieldOffset(0)]public fixed byte MaskByte[16]; [FieldOffset(0)]public fixed byte MaskByte[16];
[FieldOffset(0)]public ulong Mask; [FieldOffset(0)]public ulong Mask;
internal SIMDID(
ulong data
)
{
Mask = data;
}
public SIMDID() public SIMDID()
{ {
Unsafe.SkipInit(out this); Unsafe.SkipInit(out this);
@@ -2,8 +2,8 @@
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// file="MatrixCompute.Sequential" // file="MatrixCompute.Sequential"
// Project: StgSharp // Project: StgSharp
// AuthorGroup: Nitload Space // AuthorGroup: Nitload
// Copyright (c) Nitload Space. All rights reserved. // Copyright (c) Nitload. All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
@@ -40,7 +40,11 @@ namespace StgSharp.Mathematics.Numeric.Linear
public static unsafe partial class MatrixCompute public static unsafe partial class MatrixCompute
{ {
public static void Add(Matrix<float> left, Matrix<float> right, Matrix<float> ans) public static void Add(
Matrix<float> left,
Matrix<float> right,
Matrix<float> ans
)
{ {
ArgumentNullException.ThrowIfNull(left, nameof(left)); ArgumentNullException.ThrowIfNull(left, nameof(left));
ArgumentNullException.ThrowIfNull(right, nameof(right)); ArgumentNullException.ThrowIfNull(right, nameof(right));
@@ -69,6 +73,7 @@ namespace StgSharp.Mathematics.Numeric.Linear
t->Mat3 = (MatrixKernel*)ansPtr; t->Mat3 = (MatrixKernel*)ansPtr;
t->ElementType = MatrixElementType.F64; t->ElementType = MatrixElementType.F64;
t->Scalar.Data<long>(0) = count; t->Scalar.Data<long>(0) = count;
MatrixParallelThread[] pool;
if (count <= 256) if (count <= 256)
{ {
add(t); add(t);
@@ -78,32 +83,44 @@ namespace StgSharp.Mathematics.Numeric.Linear
return; return;
} else if (count <= 1024) } else if (count <= 1024)
{ {
MatrixParallelThread[] pool = MatrixParallel.LeadParallel(1); pool = MatrixParallel.LeadParallel(1);
add(t); add(t);
MatrixParallel.ReturnParallelResources(ref pool); MatrixParallel.ReturnParallelResources(ref pool);
return; return;
} }
MatrixParallelWrap taskGroup = MatrixParallel.ScheduleTask<SequentialPredictor>((nuint)add, t); pool = MatrixParallel.LeadParallel((int)(count / 1024));
MatrixParallelWrap taskGroup = MatrixParallel.ScheduleTask<SequentialPredictor>(pool, t);
taskGroup.LaunchParallel(SleepMode.DeepSleep); taskGroup.LaunchParallel(SleepMode.DeepSleep);
taskGroup.Dispose(); taskGroup.Dispose();
return; return;
} }
private sealed class SequentialPredictor : MatrixPredictor<SequentialPredictor> private struct SequentialPredictor : IMatrixPredictor<SequentialPredictor>
{ {
public override bool Predict(Span<CacheLinePrediction> node, out int count) public bool Predict(
Span<CacheLinePrediction> node,
out int count
)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
public override void Prefetch(nuint origin, ulong policy, Span<byte> cache) public void Prefetch(
nuint origin,
ulong policy,
Span<byte> cache
)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
public override void WriteBack(nuint origin, ulong policy, ReadOnlySpan<byte> cache) public void WriteBack(
nuint origin,
ulong policy,
ReadOnlySpan<byte> cache
)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
@@ -41,23 +41,23 @@ namespace StgSharp.Mathematics.Numeric
private static AwaitingQueue _awaitingLeaderHandle; private static AwaitingQueue _awaitingLeaderHandle;
private static volatile int _createGeneration = 0; private static volatile int _createGeneration;
private static int _sortState; private static int _sortState;
public static MatrixParallelThread[] LeadParallel( public static MatrixParallelThread[] LeadParallel(
int recommendCount long recommendCount
) )
{ {
int min = int.Min(recommendCount, _threads.Capacity); int recommend = (recommendCount > int.MaxValue) ? int.MaxValue : ((int)recommendCount);
int min = (int)long.Min(recommend, _threads.Capacity);
min /= 2; min /= 2;
MatrixParallelThread[] ret; MatrixParallelThread[] ret;
if (_threads.Count < min) if (_threads.Count < min)
{ {
WaitHandle handle = new WaitHandle WaitHandle handle = new(
(
_createGeneration, _createGeneration,
min, min,
recommendCount recommend
); );
do do
{ {
@@ -65,7 +65,7 @@ namespace StgSharp.Mathematics.Numeric
{ {
_awaitingLeaderHandle.Enqueue(handle); _awaitingLeaderHandle.Enqueue(handle);
_ = Interlocked.Exchange(ref _sortState, 0); _ = Interlocked.Exchange(ref _sortState, 0);
Interlocked.Increment(ref _createGeneration); _ = Interlocked.Increment(ref _createGeneration);
break; break;
} }
} while (true); } while (true);
@@ -100,7 +100,7 @@ namespace StgSharp.Mathematics.Numeric
{ {
if (Interlocked.Exchange(ref _sortState, 1) == 0) if (Interlocked.Exchange(ref _sortState, 1) == 0)
{ {
ret = _threads.PopRange(recommendCount); ret = _threads.PopRange(recommend);
_createGeneration++; _createGeneration++;
_ = Interlocked.Exchange(ref _sortState, 0); _ = Interlocked.Exchange(ref _sortState, 0);
return ret; return ret;
@@ -120,7 +120,7 @@ namespace StgSharp.Mathematics.Numeric
if (Interlocked.Exchange(ref _sortState, 1) == 0) if (Interlocked.Exchange(ref _sortState, 1) == 0)
{ {
_threads.PushRange(pool); _threads.PushRange(pool);
Interlocked.Exchange(ref _sortState, 0); _ = Interlocked.Exchange(ref _sortState, 0);
break; break;
} }
} }
@@ -2,8 +2,8 @@
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// file="MatrixParallel.Publish" // file="MatrixParallel.Publish"
// Project: StgSharp // Project: StgSharp
// AuthorGroup: Nitload Space // AuthorGroup: Nitload
// Copyright (c) Nitload Space. All rights reserved. // Copyright (c) Nitload. All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
@@ -48,8 +48,10 @@ namespace StgSharp.Mathematics.Numeric
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static unsafe MatrixParallelWrap ScheduleTask<TTask>(nuint computeHandle, MatrixParallelTask* package) internal static unsafe MatrixParallelWrap ScheduleTask<TTask>(
where TTask: IPrefetchPredict MatrixParallelThread[] workers,
MatrixParallelTask* package
) where TTask : IPrefetchPredict
{ {
/* /*
int primCount = package->PrimCount; int primCount = package->PrimCount;
@@ -59,13 +61,10 @@ namespace StgSharp.Mathematics.Numeric
// Console.WriteLine($"amount of kernels is {count}"); // Console.WriteLine($"amount of kernels is {count}");
long recommendCount = /*count / /**/ 1024; return new(workers)
MatrixParallelThread[] pool = LeadParallel((int)recommendCount);
MatrixParallelWrap wrap = new(pool)
{ {
TaskQueue = MatrixParallelQueue.Rent(package) TaskQueue = MatrixParallelQueue.Rent(package)
}; };
return wrap;
} }
} }
@@ -49,36 +49,16 @@ namespace StgSharp.Mathematics.Numeric
private static CapacityFixedStack<MatrixParallelThread> _threads; 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 IsParallelSupported { get; } = Environment.ProcessorCount > 6;
public static bool IsParallelMeaningful => Environment.ProcessorCount > 6 && IsInitialized; public static bool IsParallelMeaningful => (Environment.ProcessorCount > 6) && IsInitialized;
private static bool IsInitialized { get; set; } = false; private static bool IsInitialized { get; set; }
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() internal static void Init()
{ {
Dictionary<SIMDID, int> contextMap = [];
if (IsInitialized) { if (IsInitialized) {
return; return;
} }
@@ -87,16 +67,15 @@ namespace StgSharp.Mathematics.Numeric
IsInitialized = true; IsInitialized = true;
return; return;
} }
MatrixParallelFactory.Init();
contextAllocator = SlabAllocator.Create<IntrinsicContext>(4, SlabBufferLayout.Chunked, false);
contextMap = []; contextMap = [];
int count = Environment.ProcessorCount; int count = Environment.ProcessorCount;
_threads = new(count); _threads = new(count);
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
MatrixParallelThread thread = new MatrixParallelThread(i); MatrixParallelThread thread = new(i);
_threads.Push(thread); _threads.Push(thread);
SpinWait.SpinUntil(() => thread.State == MatrixThreadState.Ready); SpinWait.SpinUntil(() => thread.State == MatrixThreadState.Ready);
var index = (IsParallelSupported && contextMap.TryGetValue(simd, out int index)) ? index : (-1);
} }
// TODO 构建全局的保底上下文 // TODO 构建全局的保底上下文
@@ -1,71 +0,0 @@
//-----------------------------------------------------------------------
// -----------------------------------------------------------------------
// file="MatrixParallelQueue.Concurrent"
// 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.Linq;
using System.Text;
using System.Threading.Tasks;
namespace StgSharp.Mathematics.Numeric.Runtime
{
internal unsafe class ConcurrentPointerQueue
{
private nuint* _current;
private int[] _length;
private nuint[] _queue;
private int _bucketIndex;
private int _head;
private int _tail;
public ConcurrentPointerQueue()
{
_queue = new nuint[8];
}
public void Enqueue(
nuint* pointer,
int count
)
{
_head++;
_head %= _queue.Length;
_bucketIndex = 0;
_queue[_head] = (nuint)pointer;
_length[_head] = count;
}
public int TryDequeue(
Span<nuint> span
)
{
throw new NotImplementedException();
}
}
}
@@ -1,9 +1,9 @@
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// file="MatrixPredictor" // file="MatrixParallelQueue.Predictor"
// Project: StgSharp // Project: StgSharp
// AuthorGroup: Nitload Space // AuthorGroup: Nitload
// Copyright (c) Nitload Space. All rights reserved. // Copyright (c) Nitload. All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
@@ -34,16 +34,6 @@ using System.Threading.Tasks;
namespace StgSharp.Mathematics.Numeric.Runtime namespace StgSharp.Mathematics.Numeric.Runtime
{ {
public abstract class MatrixPredictor<TSelf> : IPrefetchPredict where TSelf: MatrixPredictor<TSelf> internal interface IMatrixPredictor<TSelf> : IPrefetchPredict
{ where TSelf : unmanaged, IMatrixPredictor<TSelf> { }
protected MatrixPredictor() { }
public abstract bool Predict(Span<CacheLinePrediction> node, out int count);
public abstract void Prefetch(nuint origin, ulong policy, Span<byte> cache);
public abstract void WriteBack(nuint origin, ulong policy, ReadOnlySpan<byte> cache);
}
} }
@@ -50,13 +50,7 @@ namespace StgSharp.Mathematics.Numeric
public MatrixParallelTask* BaseTask { get; private set; } public MatrixParallelTask* BaseTask { get; private set; }
public MatrixElementType ElementType { get; private set; }
public MatrixIntrinsicHandle Handle { get; private set; }
public static MatrixParallelQueue Rent( public static MatrixParallelQueue Rent(
MatrixElementType elementType,
MatrixIntrinsicHandle handle,
MatrixParallelTask* pack MatrixParallelTask* pack
) )
{ {
@@ -66,8 +60,6 @@ namespace StgSharp.Mathematics.Numeric
queue.BaseTask = pack; queue.BaseTask = pack;
queue._maxCount = ((ulong)pack->CommonX) * ((ulong)pack->CommonY); queue._maxCount = ((ulong)pack->CommonX) * ((ulong)pack->CommonY);
queue._cursor = 0; queue._cursor = 0;
queue.ElementType = elementType;
queue.Handle = handle;
return queue; return queue;
} }
@@ -2,8 +2,8 @@
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// file="MatrixParallelTask" // file="MatrixParallelTask"
// Project: StgSharp // Project: StgSharp
// AuthorGroup: Nitload Space // AuthorGroup: Nitload
// Copyright (c) Nitload Space. All rights reserved. // Copyright (c) Nitload. All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
@@ -36,17 +36,18 @@ namespace StgSharp.Mathematics.Numeric.Runtime
internal unsafe struct MatrixParallelTask internal unsafe struct MatrixParallelTask
{ {
[FieldOffset(0)] public MatrixKernel* Mat1; // 8 [FieldOffset(0)] public MatrixKernel* Mat1;
[FieldOffset(8)] public MatrixKernel* Mat2; // 8 [FieldOffset(8)] public MatrixKernel* Mat2;
[FieldOffset(16)] public MatrixKernel* Mat3; // 16 [FieldOffset(16)] public MatrixKernel* Mat3;
[FieldOffset(40)] public int CommonK; [FieldOffset(24)] public int CacheIndex;
[FieldOffset(32)] public int CommonX; [FieldOffset(28)] public int CacheLength;
[FieldOffset(36)] public int CommonY; [FieldOffset(32)] public int CommonK;
[FieldOffset(44)] public int i; [FieldOffset(36)] public int CommonX;
[FieldOffset(48)] public int j; [FieldOffset(40)] public int CommonY;
[FieldOffset(52)] public int k; [FieldOffset(44)] public int SpanLength;
[FieldOffset(56)] public MatrixElementType ElementType; // 56 [FieldOffset(48)] public MatrixElementType ElementType;
[FieldOffset(24)] public nint Span; // 24 [FieldOffset(52)] public MatrixIntrinsicHandle ComputeHandle;
[FieldOffset(56)] public nint Span;
[FieldOffset(64)] public ScalarPacket Scalar; [FieldOffset(64)] public ScalarPacket Scalar;
public MatrixParallelTask() public MatrixParallelTask()
@@ -55,9 +56,13 @@ namespace StgSharp.Mathematics.Numeric.Runtime
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Copy(MatrixParallelTask* source, MatrixParallelTask* target) public static void Copy(
MatrixParallelTask* source,
MatrixParallelTask* target
)
{ {
Buffer.MemoryCopy(source, target, sizeof(MatrixParallelTask), sizeof(MatrixParallelTask)); Buffer.MemoryCopy(source, target, sizeof(MatrixParallelTask),
sizeof(MatrixParallelTask));
} }
} }
@@ -69,10 +69,10 @@ namespace StgSharp.Mathematics.Numeric
internal ManualResetEventSlim? LeaderEvent { get; set; } internal ManualResetEventSlim? LeaderEvent { get; set; }
internal IntrinsicContext* Intrinsic { get; set; }
internal bool IsSingle { get; set; } internal bool IsSingle { get; set; }
internal IntrinsicContext Intrinsic { get; private set; }
internal MatrixParallelWrap BindedWrap { get; set; } internal MatrixParallelWrap BindedWrap { get; set; }
internal MatrixThreadState State { get; set; } internal MatrixThreadState State { get; set; }
@@ -91,16 +91,6 @@ namespace StgSharp.Mathematics.Numeric
_resetEvent.Set(); _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( protected virtual void Dispose(
bool disposing bool disposing
) )
@@ -125,11 +115,10 @@ namespace StgSharp.Mathematics.Numeric
// Bind OS-thread affinity once when the worker starts running // Bind OS-thread affinity once when the worker starts running
SetThreadAffinity(PoolId); SetThreadAffinity(PoolId);
_ = Thread.Yield(); _ = Thread.Yield();
SIMDID feature = new() SIMDID feature = new(GetSimdId());
{ int index = MatrixParallel.GetContext(feature);
Mask = GetSimdId() Intrinsic = new IntrinsicContext();
}; if (index > 0) { }
_context = (nint*)MatrixParallel.GetContext(feature);
State = MatrixThreadState.Ready; State = MatrixThreadState.Ready;
while (true) while (true)
{ {
@@ -171,5 +160,19 @@ namespace StgSharp.Mathematics.Numeric
State = MatrixThreadState.Retired; 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 = "sn_set_thread_affinity")]
[UnmanagedCallConv(CallConvs = [ typeof(CallConvCdecl) ])]
[DefaultDllImportSearchPaths(DllImportSearchPath.AssemblyDirectory)]
internal static partial void SetThreadAffinity(
int coreId
);
#pragma warning restore CA5393
} }
} }