using Misaki.HighPerformance.Jobs; using System.Numerics; namespace Misaki.HighPerformance.Mathematics.SPMD; public interface IJobSPMD where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { void Execute(int baseIndex, ref readonly JobExecutionContext ctx) where TLane : ISPMD; } internal struct SPMDJobWrapper : IJobParallelFor where T : unmanaged, IJobSPMD where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { public T innerJob; public int totalCount; public void Execute(int loopIndex, ref readonly JobExecutionContext ctx) { var baseIndex = loopIndex * WideLane.LaneWidth; var remaining = totalCount - baseIndex; if (remaining >= WideLane.LaneWidth) { innerJob.Execute>(baseIndex, in ctx); } else { for (var j = 0; j < remaining; j++) { innerJob.Execute>(baseIndex + j, in ctx); } } } } internal struct SPMDScalerJobWrapper : IJobParallelFor where T : unmanaged, IJobSPMD where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { public T innerJob; public int totalCount; public void Execute(int loopIndex, ref readonly JobExecutionContext ctx) { innerJob.Execute>(loopIndex, in ctx); } } public static class IJobParallelForSPMDExtensions { public static void Run(this ref T job, int totalCount, ref readonly JobExecutionContext ctx) where T : struct, IJobSPMD where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { if (WideLane.IsSupported) { var iterations = (totalCount + WideLane.LaneWidth - 1) / WideLane.LaneWidth; for (var loopIndex = 0; loopIndex < iterations; loopIndex++) { var baseIndex = loopIndex * WideLane.LaneWidth; var remaining = totalCount - baseIndex; if (remaining >= WideLane.LaneWidth) { job.Execute>(baseIndex, in ctx); } else { for (var i = 0; i < remaining; i++) { job.Execute>(baseIndex + i, in ctx); } } } } else { for (var loopIndex = 0; loopIndex < totalCount; loopIndex++) { job.Execute>(loopIndex, in ctx); } } } public static JobHandle ScheduleParallelSPDM(this JobScheduler jobScheduler, ref T job, int totalCount, int batchSize, int threadIndex, JobHandle dependency) where T : unmanaged, IJobSPMD where TNumber : unmanaged, INumber, IBinaryNumber, IMinMaxValue, IBitwiseOperators { if (WideLane.IsSupported) { var warper = new SPMDJobWrapper { innerJob = job, totalCount = totalCount, }; var iterations = (totalCount + WideLane.LaneWidth - 1) / WideLane.LaneWidth; return jobScheduler.ScheduleParallelFor(ref warper, iterations, batchSize, threadIndex, dependency); } else { var warper = new SPMDScalerJobWrapper { innerJob = job, totalCount = totalCount, }; return jobScheduler.ScheduleParallelFor(ref warper, totalCount, batchSize, threadIndex, dependency); } } }