//----------------------------------------------------------------------- // ----------------------------------------------------------------------- // file="MatrixParallel.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.HighPerformance; using StgSharp.HighPerformance.Memory; using System; using System.Collections.Generic; using System.IO.Pipes; using System.Linq; using System.Reflection.Metadata; using System.Runtime.CompilerServices; using System.Runtime.ExceptionServices; using System.Text; using System.Threading; using System.Threading.Channels; using System.Threading.Tasks; namespace StgSharp.Mathematics { internal static class MatrixParallel { // TODO 解决多线程协调问题,barrier性能不好,MRES时机不好控制,可能可以使用双MRES private static Thread[] _threads; private static MatrixParallelWrap[] _wraps; private static readonly (int a, int b)[] LookupTable = [(1, 1), (0, 2), (3, 0), (2, 1), (1, 2), (0, 3), (3, 1), (2, 2), (1, 3), (4, 1), (3, 2), (2, 3), (1, 4), (0, 5),]; private static volatile int RemainThreadCount = 0; private static readonly ManualResetEventSlim _resetEvent = new(false); private static readonly object _lock = new(); private static ThreadPriority _AfterWork = ThreadPriority.Lowest; public static bool SupportParallel { get; } = Environment.ProcessorCount > 6; public static void EndParallel() { Monitor.Exit(_lock); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static (int a, int b) FastDecompose(int c) { if (c < 7) { return (0, 0); } c -= 7; int c_prime = c / 14; int d = c % 14; (int a_prime, int b_prime) = LookupTable[d]; return (a_prime + c_prime, b_prime + c_prime); } public static void Init() { int count = Environment.ProcessorCount - 4; count = count == 5 ? 4 : count; int _3wrap = 0, _4wrap = 0; _threads = new Thread[count]; if (count < 6) { _wraps = new MatrixParallelWrap[1]; _wraps[0] = new MatrixParallelWrap(count); for (int i = 1; i < count; i++) //first is reverse for leader thread { _threads[i] = new Thread(MatrixParallelCycle) { IsBackground = true, Priority = ThreadPriority.Highest, Name = $"StgSharp Matrix Parallel Worker {i}" }; _threads[i].Start(new MatrixParallelWrap.Handle(i, _wraps[0])); } } else if (count == 6) { _3wrap = 2; _threads = new Thread[6]; _wraps = new MatrixParallelWrap[2]; _wraps[0] = new(3); _wraps[1] = new(3); for (int i = 1; i < 3; i++) //first is reverse for leader thread { _threads[i] = new Thread(MatrixParallelCycle) { IsBackground = true, Priority = ThreadPriority.Highest, Name = $"StgSharp Matrix Parallel Worker {i}" }; _threads[i].Start(new MatrixParallelWrap.Handle(i, _wraps[0])); } for (int i = 3; i < 6; i++) { _threads[i] = new Thread(MatrixParallelCycle) { IsBackground = true, Priority = ThreadPriority.Highest, Name = $"StgSharp Matrix Parallel Worker {i}" }; _threads[i].Start(new MatrixParallelWrap.Handle(i - 3, _wraps[1])); } } else { (_3wrap, _4wrap) = FastDecompose(count); _wraps = new MatrixParallelWrap[_3wrap + _4wrap]; int i = 0, wi = 0; for (; i < 3 * _3wrap; i += 3) { MatrixParallelWrap wrap = new(3); _wraps[wi] = wrap; wi++; for (int j = i; j < i + 3; j++) { if (j == 0) { continue; //first is reverse for leader thread } _threads[j] = new Thread(MatrixParallelCycle) { IsBackground = true, Priority = ThreadPriority.Highest, Name = $"StgSharp Matrix Parallel Worker {j}" }; _threads[j].Start(new MatrixParallelWrap.Handle(j, wrap)); } } for (; i < count; i += 4) { MatrixParallelWrap wrap = new(4); _wraps[wi] = wrap; wi++; for (int j = i; j < i + 4; j++) { _threads[j] = new Thread(MatrixParallelCycle) { IsBackground = true, Priority = ThreadPriority.Highest, Name = $"StgSharp Matrix Parallel Worker {j}" }; _threads[j].Start(new MatrixParallelWrap.Handle(j, wrap)); } } } } public static void LaunchParallel(SleepMode afterWork) { _resetEvent.Set(); RemainThreadCount = _threads.Length; _AfterWork = (ThreadPriority)afterWork; _resetEvent.Reset(); } public static void LeadParallel() { Monitor.Enter(_lock); } public static void PublishTask() { } private static unsafe void MatrixParallelCycle(object obj) { MatrixParallelWrap.Handle handle = (obj as MatrixParallelWrap.Handle)!; MatrixParallelWrap wrap = handle.Wrap; int inWrapIndex = handle.InWrapIndex; Thread self = Thread.CurrentThread; while (true) { while (wrap.TryGetNextWrapTask(inWrapIndex, out IntPtr ptr)) { MatrixParallelTaskPackage* p = (MatrixParallelTaskPackage*)ptr; MatrixKernel* left = p->left, right = p->left, result = p->result; int count = p->count; ScalarDataPacket* scalar = p->scalerPacket; switch (p->ComputeMode) { case 0: delegate* op_0 = (delegate*)p->executionHandle; for (int i = 0; i < count; i++) { op_0(left, result); left += p->leftStride; result += p->resultStride; } break; case 1: delegate* op_1 = (delegate*)p->executionHandle; for (int i = 0; i < count; i++) { op_1(left, result, scalar); left += p->leftStride; result += p->resultStride; } break; case 2: delegate* op_2 = (delegate*)p->executionHandle; for (int i = 0; i < count; i++) { op_2(left, right, result); right += p->rightStride; left += p->leftStride; result += p->resultStride; } break; case 3: delegate* op_3 = (delegate*)p->executionHandle; for (int i = 0; i < count; i++) { op_3(left, right, result, scalar); right += p->rightStride; left += p->leftStride; result += p->resultStride; } break; default: break; } } _ = Interlocked.Decrement(ref RemainThreadCount); self.Priority = _AfterWork; _resetEvent.Wait(); self.Priority = ThreadPriority.Highest; } } } public enum SleepMode { QuickWakeup = ThreadPriority.AboveNormal, NormalSleep = ThreadPriority.BelowNormal, DeepSleep = ThreadPriority.Lowest, } }