From fdf11c729f72dcc1d56df2bc8df6142295adfcab Mon Sep 17 00:00:00 2001 From: Youmu Liu <105042599+Nitload-NSI@users.noreply.github.com> Date: Tue, 14 Apr 2026 18:08:22 +0800 Subject: [PATCH] find a way to create Thread binded to LogicalCore properly --- .../ProcessorAbstraction/Numa.cs | 8 +- StgSharp.Common/Threading/EmptyThread.cs | 58 ---------- StgSharp.Common/Threading/NumaBuffer.cs | 47 -------- .../{MainThreadAssert.cs => ThreadHelper.cs} | 37 ++++++- .../Threading/VariableCapacitySemaphore.cs | 67 ++++++++++-- .../Numeric/Runtime/MatrixParallel.Numa.cs | 6 +- .../Numeric/Runtime/MatrixParallel.cs | 103 +++++++++++------- .../Numeric/Runtime/MatrixParallelThread.cs | 81 +++++++------- StgSharp.Native/StgSharp.Native.vcxproj | 5 +- .../StgSharp.Native.vcxproj.filters | 12 +- StgSharp.Native/sn-head/StgSharpNative.h | 2 +- StgSharp.Native/sn-src/mk.fma.x86.c | 2 +- StgSharp.Native/sn-src/simdid.x86.c | 24 +--- StgSharp.Native/sn-src/thread.linux.c | 21 ++-- StgSharp.Native/sn-src/thread.windows.c | 9 +- 15 files changed, 228 insertions(+), 254 deletions(-) delete mode 100644 StgSharp.Common/Threading/EmptyThread.cs delete mode 100644 StgSharp.Common/Threading/NumaBuffer.cs rename StgSharp.Common/Threading/{MainThreadAssert.cs => ThreadHelper.cs} (63%) diff --git a/StgSharp.Common/HighPerformance/ProcessorAbstraction/Numa.cs b/StgSharp.Common/HighPerformance/ProcessorAbstraction/Numa.cs index cad7f59f..a8d7e85c 100644 --- a/StgSharp.Common/HighPerformance/ProcessorAbstraction/Numa.cs +++ b/StgSharp.Common/HighPerformance/ProcessorAbstraction/Numa.cs @@ -67,13 +67,15 @@ namespace StgSharp.Common.HighPerformance.ProcessorAbstraction return []; } T[][] arr = new T[_numaNodes.Length][]; - foreach (NumaNode node in _numaNodes) + for (int i = 0; i < _numaNodes.Length; i++) { + NumaNode node = _numaNodes[i]; T[] values = new T[node.LogicalCoreCount]; ReadOnlySpan cores = node.LogicalCores; - for (int i = 0; i < cores.Length; i++) { - values[i] = factory(cores[i]); + for (int j = 0; j < cores.Length; j++) { + values[j] = factory(cores[j]); } + arr[i] = values; } return arr; } diff --git a/StgSharp.Common/Threading/EmptyThread.cs b/StgSharp.Common/Threading/EmptyThread.cs deleted file mode 100644 index 7863593e..00000000 --- a/StgSharp.Common/Threading/EmptyThread.cs +++ /dev/null @@ -1,58 +0,0 @@ -//----------------------------------------------------------------------- -// ----------------------------------------------------------------------- -// file="EmptyThread" -// 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.Diagnostics; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace StgSharp.Threading -{ - public static partial class ThreadHelper - { - - private static readonly Thread _emptyThreadCache = new Thread(() => { }); - - static ThreadHelper() - { - _emptyThreadCache.Start(); - } - - /// - /// An individual thread doing nothing, and its always returns false. - /// - public static Thread EmptyThread - { - get => _emptyThreadCache; - } - - } -} diff --git a/StgSharp.Common/Threading/NumaBuffer.cs b/StgSharp.Common/Threading/NumaBuffer.cs deleted file mode 100644 index 7fff2701..00000000 --- a/StgSharp.Common/Threading/NumaBuffer.cs +++ /dev/null @@ -1,47 +0,0 @@ -//----------------------------------------------------------------------- -// ----------------------------------------------------------------------- -// file="NumaBuffer" -// 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.Common.Threading -{ - public unsafe struct NumaBuffer where T : unmanaged - { - - public readonly T* Buffers; - public readonly int BufferColumnCapacity; - public readonly int BufferRowCapacity; - - public int CurrentColumnCount; - public int CurrentRowCount; - - } -} diff --git a/StgSharp.Common/Threading/MainThreadAssert.cs b/StgSharp.Common/Threading/ThreadHelper.cs similarity index 63% rename from StgSharp.Common/Threading/MainThreadAssert.cs rename to StgSharp.Common/Threading/ThreadHelper.cs index 3928ffa6..8dba6e9e 100644 --- a/StgSharp.Common/Threading/MainThreadAssert.cs +++ b/StgSharp.Common/Threading/ThreadHelper.cs @@ -1,6 +1,6 @@ -//----------------------------------------------------------------------- +//----------------------------------------------------------------------- // ----------------------------------------------------------------------- -// file="MainThreadAssert" +// file="ThreadHelper" // Project: StgSharp // AuthorGroup: Nitload // Copyright (c) Nitload. All rights reserved. @@ -25,8 +25,10 @@ // // ----------------------------------------------------------------------- // ----------------------------------------------------------------------- +using StgSharp.Common.HighPerformance.ProcessorAbstraction; using System; using System.Diagnostics; +using System.Runtime.InteropServices; using System.Threading; namespace StgSharp.Threading @@ -35,9 +37,29 @@ namespace StgSharp.Threading { private static readonly int mainThreadId = Environment.CurrentManagedThreadId; + private static readonly ThreadLocal isNotMainThread = new( () => Environment.CurrentManagedThreadId != mainThreadId); + static ThreadHelper() + { + EmptyThread.Start(); + } + + /// + /// An individual thread doing nothing, and its always returns false. + /// + public static Thread EmptyThread { get; } = new(() => { }); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void BindToLogicalCore( + LogicalCore core + ) + { + SetThreadAffinity(core.GlobalCpuId, core.NumaNodeId); + } + [Conditional("DEBUG")] internal static void MainThreadAssert() { @@ -47,5 +69,16 @@ namespace StgSharp.Threading } } +#pragma warning disable CA5393 + + [LibraryImport(Native.LibName, EntryPoint = "sn_set_thread_affinity")] + [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] + [DefaultDllImportSearchPaths(DllImportSearchPath.AssemblyDirectory)] + internal static partial void SetThreadAffinity( + uint globalCoreId, + uint numaNodeId + ); + +#pragma warning restore CA5393 } } diff --git a/StgSharp.Common/Threading/VariableCapacitySemaphore.cs b/StgSharp.Common/Threading/VariableCapacitySemaphore.cs index fc90f51e..fdc827b5 100644 --- a/StgSharp.Common/Threading/VariableCapacitySemaphore.cs +++ b/StgSharp.Common/Threading/VariableCapacitySemaphore.cs @@ -1,6 +1,33 @@ //----------------------------------------------------------------------- // ----------------------------------------------------------------------- // file="VariableCapacitySemaphore" +// 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. +// +// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------- +// file="VariableCapacitySemaphore" // Project: StgSharp.Common // AuthorGroup: Nitload // License: MIT @@ -40,7 +67,11 @@ namespace StgSharp.Threading /// /// Optional stripe count for MRES (<= 0 to auto choose by CPU). /// - public VariableCapacitySemaphore(int initialCount = 0, int maxPermits = 1, int stripes = 0) + public VariableCapacitySemaphore( + int initialCount = 0, + int maxPermits = 1, + int stripes = 0 + ) { ArgumentOutOfRangeException.ThrowIfLessThan(maxPermits, 1); ArgumentOutOfRangeException.ThrowIfNegative(initialCount); @@ -48,14 +79,16 @@ namespace StgSharp.Threading _max = maxPermits; _current = Math.Min(initialCount, maxPermits); - int stripeCount = stripes > 0 ? stripes : ClampToPow2(Math.Min(Environment.ProcessorCount, 8)); + int stripeCount = (stripes > 0) ? + stripes : + ClampToPow2(Math.Min(Environment.ProcessorCount, 8)); _events = new ManualResetEventSlim[stripeCount]; bool set = _current > 0; for (int i = 0; i < stripeCount; i++) { _events[i] = new ManualResetEventSlim(set, 0); } - _stripeMask = IsPow2(stripeCount) ? (stripeCount - 1) : -1; + _stripeMask = IsPow2(stripeCount) ? (stripeCount - 1) : (-1); } /// @@ -139,7 +172,9 @@ namespace StgSharp.Threading /// count. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public int Release(int permits) + public int Release( + int permits + ) { ArgumentOutOfRangeException.ThrowIfNegativeOrZero(permits); while (true) @@ -150,7 +185,7 @@ namespace StgSharp.Threading return cur; } - long target = (long)cur + permits; + long target = ((long)cur) + permits; if (target > max) { target = max; } @@ -201,7 +236,7 @@ namespace StgSharp.Threading while (true) { int cur = Volatile.Read(ref _current); - if (cur > 0 && Interlocked.CompareExchange(ref _current, cur - 1, cur) == cur) + if ((cur > 0) && (Interlocked.CompareExchange(ref _current, cur - 1, cur) == cur)) { if (cur - 1 == 0) { ResetAll(); @@ -222,7 +257,10 @@ namespace StgSharp.Threading /// /// Block until a permit is available or canceled, then consume one. /// - public bool Wait(int millisecondsTimeout, CancellationToken cancellationToken = default) + public bool Wait( + int millisecondsTimeout, + CancellationToken cancellationToken = default + ) { ManualResetEventSlim gate = GetStripeEvent(); SpinWait spinner = new SpinWait(); @@ -232,7 +270,7 @@ namespace StgSharp.Threading { cancellationToken.ThrowIfCancellationRequested(); int cur = Volatile.Read(ref _current); - if (cur > 0 && Interlocked.CompareExchange(ref _current, cur - 1, cur) == cur) + if ((cur > 0) && (Interlocked.CompareExchange(ref _current, cur - 1, cur) == cur)) { if (cur - 1 == 0) { ResetAll(); @@ -263,7 +301,9 @@ namespace StgSharp.Threading } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static int ClampToPow2(int x) + private static int ClampToPow2( + int x + ) { if (x < 1) { x = 1; @@ -274,7 +314,7 @@ namespace StgSharp.Threading } int p = 1; - while ((p << 1) <= x) { + while (p << 1 <= x) { p <<= 1; } @@ -294,7 +334,12 @@ namespace StgSharp.Threading } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static bool IsPow2(int x) => (x & (x - 1)) == 0; + private static bool IsPow2( + int x + ) + { + return (x & (x - 1)) == 0; + } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void ResetAll() diff --git a/StgSharp.Mathematics/Numeric/Runtime/MatrixParallel.Numa.cs b/StgSharp.Mathematics/Numeric/Runtime/MatrixParallel.Numa.cs index 33b03ef4..6384400c 100644 --- a/StgSharp.Mathematics/Numeric/Runtime/MatrixParallel.Numa.cs +++ b/StgSharp.Mathematics/Numeric/Runtime/MatrixParallel.Numa.cs @@ -36,12 +36,12 @@ namespace StgSharp.Mathematics.Numeric public static unsafe partial class MatrixParallel { - private static int[] NumaPayload; - private static MatrixParallelThread[][] NumaThreads; + private static int[] _numaPayload; + private static MatrixParallelThread[][] _numaThreads; private static void UpdateThreadPayload() { - for (int i = 0; i < NumaPayload.Length; i++) { } + for (int i = 0; i < _numaPayload.Length; i++) { } } } diff --git a/StgSharp.Mathematics/Numeric/Runtime/MatrixParallel.cs b/StgSharp.Mathematics/Numeric/Runtime/MatrixParallel.cs index c829c0c7..acaa3ca4 100644 --- a/StgSharp.Mathematics/Numeric/Runtime/MatrixParallel.cs +++ b/StgSharp.Mathematics/Numeric/Runtime/MatrixParallel.cs @@ -1,34 +1,32 @@ //----------------------------------------------------------------------- // ----------------------------------------------------------------------- -// file="MatrixParallel.cs" +// file="MatrixParallel" // Project: StgSharp -// AuthorGroup: Nitload Space -// Copyright (c) Nitload Space. All rights reserved. +// 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. +// 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.Common.HighPerformance.ProcessorAbstraction; using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -49,7 +47,9 @@ namespace StgSharp.Mathematics.Numeric public static bool IsParallelSupported { get; } = Environment.ProcessorCount > 6; - public static bool IsParallelMeaningful => IsParallelSupported && IsInitialized && _meaningful; + public static bool IsParallelMeaningful => IsParallelSupported && + IsInitialized && + _meaningful; public static int ContextCount { get; private set; } @@ -86,17 +86,20 @@ namespace StgSharp.Mathematics.Numeric SIMDID globalSimd = new SIMDID(0); _threads = new(count); _retiredThreads = new(RESERVED_THREAD_COUNT); - for (int i = 0; i < count; i++) - { - MatrixParallelThread thread = new(i); - _threads.Push(thread); - 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; - } + _numaThreads = Numa.CreateForeachThread( + 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; + }); IntrinsicContext globalContext = new(); LoadIntrinsicFunction(&globalContext, globalSimd.Mask); @@ -111,8 +114,13 @@ namespace StgSharp.Mathematics.Numeric } } else { + // TODO 切换来源 + // TODO _threads退休并移除 MatrixParallelThread[] allThreads = _threads.PopRange(_threads.Count); - Array.Sort(allThreads, static(left, right) => CompareSIMDID(left.Simd, right.Simd)); + Array.Sort(allThreads, static( + left, + right + ) => CompareSIMDID(left.Simd, right.Simd)); int retireCount = Math.Min(RESERVED_THREAD_COUNT, Math.Max(0, allThreads.Length - 1)); for (int i = 0; i < retireCount; i++) { RetireThread(allThreads[i]); @@ -125,26 +133,37 @@ namespace StgSharp.Mathematics.Numeric } [LibraryImport(Native.LibName, EntryPoint = "sn_compare_simd")] - [UnmanagedCallConv(CallConvs = [ typeof(CallConvCdecl) ])] + [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] [DefaultDllImportSearchPaths(DllImportSearchPath.AssemblyDirectory)] - private static partial int CompareSIMDID(SIMDID left, SIMDID right); + private static partial int CompareSIMDID( + SIMDID left, + SIMDID right + ); [LibraryImport(Native.LibName, EntryPoint = "load_intrinsic_function")] - [UnmanagedCallConv(CallConvs = [ typeof(CallConvCdecl) ])] + [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] [DefaultDllImportSearchPaths(DllImportSearchPath.AssemblyDirectory)] - private static partial void LoadIntrinsicFunction(IntrinsicContext* context, ulong id); + private static partial void LoadIntrinsicFunction( + IntrinsicContext* context, + ulong id + ); [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void RetireThread(MatrixParallelThread thread) + private static void RetireThread( + MatrixParallelThread thread + ) { thread.Pause(); _retiredThreads.Push(thread); } [LibraryImport(Native.LibName, EntryPoint = "sn_get_unite_simd")] - [UnmanagedCallConv(CallConvs = [ typeof(CallConvCdecl) ])] + [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] [DefaultDllImportSearchPaths(DllImportSearchPath.AssemblyDirectory)] - private static partial SIMDID UniteSIMDID(SIMDID left, SIMDID right); + private static partial SIMDID UniteSIMDID( + SIMDID left, + SIMDID right + ); } } diff --git a/StgSharp.Mathematics/Numeric/Runtime/MatrixParallelThread.cs b/StgSharp.Mathematics/Numeric/Runtime/MatrixParallelThread.cs index 3bb1fb3a..2267aeeb 100644 --- a/StgSharp.Mathematics/Numeric/Runtime/MatrixParallelThread.cs +++ b/StgSharp.Mathematics/Numeric/Runtime/MatrixParallelThread.cs @@ -1,35 +1,34 @@ //----------------------------------------------------------------------- // ----------------------------------------------------------------------- -// file="MatrixParallelThread.cs" +// file="MatrixParallelThread" // Project: StgSharp -// AuthorGroup: Nitload Space -// Copyright (c) Nitload Space. All rights reserved. +// 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. +// 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.Common.HighPerformance.ProcessorAbstraction; using StgSharp.Internal; using StgSharp.Mathematics.Numeric.Runtime; +using StgSharp.Threading; using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -60,15 +59,17 @@ namespace StgSharp.Mathematics.Numeric private volatile MatrixThreadState _target; private Thread _managedThread; - internal MatrixParallelThread(int poolId) + internal MatrixParallelThread( + LogicalCore binded + ) { _resetEvent = new ManualResetEventSlim(false); _managedThread = new Thread(MatrixParallelWorkLoad); _managedThread.Start(); - PoolId = poolId; + BindedLogicalCore = binded; } - public int PoolId { get; init; } + public LogicalCore BindedLogicalCore { get; init; } public ThreadPriority AfterWork { get; set; } @@ -100,15 +101,9 @@ namespace StgSharp.Mathematics.Numeric _managedThread.Join(); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void SetSingleThreadTask(ref MatrixParallelTask task) - { - if (IsSingle) { - *_currentTask = task; - } - } - - protected virtual void Dispose(bool disposing) + protected virtual void Dispose( + bool disposing + ) { if (!_disposed) { @@ -127,7 +122,7 @@ namespace StgSharp.Mathematics.Numeric State = MatrixThreadState.Born; // Bind OS-thread affinity once when the worker starts running - SetThreadAffinity(PoolId); + ThreadHelper.SetThreadAffinity(BindedLogicalCore); _ = Thread.Yield(); if (Simd.Mask != 0) { @@ -180,19 +175,17 @@ namespace StgSharp.Mathematics.Numeric #pragma warning disable CA5393 [LibraryImport(Native.LibName, EntryPoint = "sn_get_simd_level_local")] - [UnmanagedCallConv(CallConvs = [ typeof(CallConvCdecl) ])] + [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); - [LibraryImport(Native.LibName, EntryPoint = "load_intrinsic_function")] - [UnmanagedCallConv(CallConvs = [ typeof(CallConvCdecl) ])] + [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] [DefaultDllImportSearchPaths(DllImportSearchPath.AssemblyDirectory)] - private static unsafe partial void LoadIntrinsicFunction(IntrinsicContext* context, ulong id); + private static unsafe partial void LoadIntrinsicFunction( + IntrinsicContext* context, + ulong id + ); #pragma warning restore CA5393 } } diff --git a/StgSharp.Native/StgSharp.Native.vcxproj b/StgSharp.Native/StgSharp.Native.vcxproj index 03d1bb29..dba1a988 100644 --- a/StgSharp.Native/StgSharp.Native.vcxproj +++ b/StgSharp.Native/StgSharp.Native.vcxproj @@ -110,7 +110,7 @@ stdc11 true Speed - $(ProjectDir)lib;$(ProjectDir)sn-head;%(AdditionalIncludeDirectories) + $(ProjectDir)lib;$(ProjectDir)sn-head;$(ProjectDir)sn-template;%(AdditionalIncludeDirectories) @@ -172,10 +172,10 @@ - + @@ -208,6 +208,7 @@ + diff --git a/StgSharp.Native/StgSharp.Native.vcxproj.filters b/StgSharp.Native/StgSharp.Native.vcxproj.filters index 3e9133e3..b57a6e3e 100644 --- a/StgSharp.Native/StgSharp.Native.vcxproj.filters +++ b/StgSharp.Native/StgSharp.Native.vcxproj.filters @@ -16,6 +16,9 @@ {fbd74b53-5314-4d9d-a788-07bd1b413f74} + + {c7081772-a85a-4372-b55c-a6dac43c6913} + @@ -39,9 +42,6 @@ 源文件 - - 源文件 - 源文件 @@ -69,6 +69,9 @@ 源文件 + + 源文件 + @@ -113,6 +116,9 @@ 头文件 + + 模板文件 + diff --git a/StgSharp.Native/sn-head/StgSharpNative.h b/StgSharp.Native/sn-head/StgSharpNative.h index 94fd5fe9..e5d41ac6 100644 --- a/StgSharp.Native/sn-head/StgSharpNative.h +++ b/StgSharp.Native/sn-head/StgSharpNative.h @@ -54,7 +54,7 @@ SN_API SIMDID SN_DECL sn_get_simd_level_global(); SN_API SIMDID SN_DECL sn_get_simd_level_local(); SN_API SIMDID SN_DECL sn_get_unite_simd(SIMDID left, SIMDID right); SN_API int SN_DECL sn_compare_simd(SIMDID left, SIMDID right); -SN_API void SN_DECL sn_set_thread_affinity(int core_id); +SN_API void SN_DECL sn_set_thread_affinity(int core_id, int numa_id); SN_API void* SN_DECL sn_numa_alloc(size_t size, int numa_id); SN_API void SN_DECL sn_numa_free(void *ptr, size_t size, int numa_id); SN_API int SN_DECL sn_get_numa_each(int numa_id, uint64_t *internal, uint32_t *global); diff --git a/StgSharp.Native/sn-src/mk.fma.x86.c b/StgSharp.Native/sn-src/mk.fma.x86.c index dc7b5ebe..66ca1e11 100644 --- a/StgSharp.Native/sn-src/mk.fma.x86.c +++ b/StgSharp.Native/sn-src/mk.fma.x86.c @@ -148,7 +148,7 @@ SN_MK_PROC_DECL_STD(float, 512, , fma) register __m512 c_3 = c_0; for (size_t z = 0; z < common_z; z+=4) { - SN_MAT_KERNEL_LOCAL const *right = right + z; + SN_MAT_KERNEL_LOCAL const *right_ = right + z; SN_MAT_KERNEL_LOCAL const *left_0 = left + z + 0; SN_MAT_KERNEL_LOCAL const *left_1 = left + z + 1; SN_MAT_KERNEL_LOCAL const *left_2 = left + z + 2; diff --git a/StgSharp.Native/sn-src/simdid.x86.c b/StgSharp.Native/sn-src/simdid.x86.c index 4717149f..4c4301ba 100644 --- a/StgSharp.Native/sn-src/simdid.x86.c +++ b/StgSharp.Native/sn-src/simdid.x86.c @@ -1,10 +1,11 @@ #include "sn_target.h" -#include "sn_intrinsic.h" -#include "StgSharpNative.h" -static SIMDID global_simdid = { 0 }; +/* clang-format off */ #if SN_IS_ARCH(SN_ARCH_X86_64) +#include "sn_intrinsic.h" +#include "StgSharpNative.h" +static SIMDID global_simdid = { 0 }; #include "sn_intrinsic.context.x86.h" @@ -350,23 +351,6 @@ SN_API SIMDID SN_DECL sn_get_simd_level_global() return global_simdid; } -#else -SN_API SIMDID SN_DECL sn_get_simd_level_local() -{ - SIMDID simdid; - simdid.mask = 0; - return simdid; -} - -SN_API SIMDID SN_DECL sn_get_simd_level_global() -{ - if (global_simdid.mask) { - return global_simdid; - } - - global_simdid = sn_get_simd_level_local(); - return global_simdid; -} #endif diff --git a/StgSharp.Native/sn-src/thread.linux.c b/StgSharp.Native/sn-src/thread.linux.c index 235b88f5..689b5d08 100644 --- a/StgSharp.Native/sn-src/thread.linux.c +++ b/StgSharp.Native/sn-src/thread.linux.c @@ -137,7 +137,7 @@ static int sn_linux_count_cpu_list(char const *path) if (!sn_linux_read_first_line(path, buffer, sizeof(buffer))) return 0; - sn_linux_counter_context counter = {0}; + sn_linux_counter_context counter = { 0 }; if (!sn_linux_visit_id_list(buffer, sn_linux_count_id, &counter)) return 0; @@ -173,8 +173,7 @@ static size_t sn_linux_round_up_to_page_size(size_t size) return rounded - (rounded % effective_page_size); } -static int sn_linux_bind_memory_to_node(void *address, size_t size, int numa_id, - uint32_t flags) +static int sn_linux_bind_memory_to_node(void *address, size_t size, int numa_id, uint32_t flags) { #if defined(SYS_mbind) size_t bits_per_word = sizeof(unsigned long) * 8u; @@ -185,9 +184,8 @@ static int sn_linux_bind_memory_to_node(void *address, size_t size, int numa_id, node_mask[(size_t)numa_id / bits_per_word] = 1ul << ((size_t)numa_id % bits_per_word); - int syscall_result = (int)syscall(SYS_mbind, address, size, - MPOL_BIND | MPOL_F_STATIC_NODES, node_mask, - (unsigned long)numa_id + 1ul, flags); + int syscall_result = (int)syscall(SYS_mbind, address, size, MPOL_BIND | MPOL_F_STATIC_NODES, + node_mask, (unsigned long)numa_id + 1ul, flags); free(node_mask); return syscall_result == 0; #else @@ -216,7 +214,7 @@ static int sn_linux_populate_writable_mapping(void *address, size_t size) /* Pin the calling thread to a single logical processor. * core_id >= 0 : bind to that logical processor (global index, across groups). * core_id < 0 : clear affinity constraint within the current group. */ -SN_API void SN_DECL sn_set_thread_affinity(int core_id) +SN_API void SN_DECL sn_set_thread_affinity(int core_id, int numa_id) { int cpu_count = (int)sysconf(_SC_NPROCESSORS_ONLN); if (cpu_count <= 0) @@ -246,7 +244,7 @@ SN_API int SN_DECL sn_get_numa_overall(int *out_numa_count, int *count_of_each_n if (!sn_linux_read_first_line("/sys/devices/system/node/online", buffer, sizeof(buffer))) return 0; - sn_linux_max_context max_context = {-1}; + sn_linux_max_context max_context = { -1 }; if (!sn_linux_visit_id_list(buffer, sn_linux_track_max_id, &max_context) || max_context.max_value < 0) return 0; @@ -258,7 +256,7 @@ SN_API int SN_DECL sn_get_numa_overall(int *out_numa_count, int *count_of_each_n for (int index = 0; index <= max_context.max_value; index++) count_of_each_numa[index] = 0; - sn_linux_fill_node_count_context fill_context = {count_of_each_numa}; + sn_linux_fill_node_count_context fill_context = { count_of_each_numa }; if (!sn_linux_visit_id_list(buffer, sn_linux_fill_node_cpu_count, &fill_context)) return 0; } @@ -277,7 +275,7 @@ SN_API int SN_DECL sn_get_numa_each(int numa_id, uint64_t *internal, uint32_t *g if (!sn_linux_read_first_line(path, buffer, sizeof(buffer))) return 0; - sn_linux_fill_cpu_context fill_context = {internal, global, 0}; + sn_linux_fill_cpu_context fill_context = { internal, global, 0 }; return sn_linux_visit_id_list(buffer, sn_linux_fill_cpu_id, &fill_context); } @@ -293,8 +291,7 @@ SN_API void *SN_DECL sn_numa_alloc(size_t size, int numa_id) mmap_flags |= MAP_POPULATE; #endif - void *memory = mmap(NULL, allocation_size, PROT_READ | PROT_WRITE, - mmap_flags, -1, 0); + void *memory = mmap(NULL, allocation_size, PROT_READ | PROT_WRITE, mmap_flags, -1, 0); if (memory == MAP_FAILED) return NULL; diff --git a/StgSharp.Native/sn-src/thread.windows.c b/StgSharp.Native/sn-src/thread.windows.c index 378a1894..d17e387c 100644 --- a/StgSharp.Native/sn-src/thread.windows.c +++ b/StgSharp.Native/sn-src/thread.windows.c @@ -6,9 +6,9 @@ /* Pin the calling thread to a single logical processor. * core_id >= 0 : bind to that logical processor (global index, across groups). * core_id < 0 : clear affinity constraint within the current group. */ -SN_API void SN_DECL sn_set_thread_affinity(int core_id) +SN_API void SN_DECL sn_set_thread_affinity(int core_id, int numa_id) { - if (core_id < 0) { + if (core_id < 0 || numa_id < 0) { /* Query which group the thread currently belongs to */ GROUP_AFFINITY current; GetThreadGroupAffinity(GetCurrentThread(), ¤t); @@ -21,14 +21,13 @@ SN_API void SN_DECL sn_set_thread_affinity(int core_id) SetThreadGroupAffinity(GetCurrentThread(), &ga, NULL); return; } - WORD group = (WORD)(core_id / 64); int index = core_id % 64; - DWORD count = GetActiveProcessorCount(group); + DWORD count = GetActiveProcessorCount(numa_id); if ((DWORD)index >= count) return; GROUP_AFFINITY ga; memset(&ga, 0, sizeof(ga)); - ga.Group = group; + ga.Group = (WORD)numa_id; ga.Mask = (KAFFINITY)1 << index; SetThreadGroupAffinity(GetCurrentThread(), &ga, NULL); }