如何简化ILGPU内核加载时泛型函数的类型参数传递?
问题描述
希望简化ILGPU中加载内核的语句,避免传递冗长的泛型类型参数,例如当前的写法:
var kernel = accelerator_.LoadAutoGroupedStreamKernel<Index2D, ArrayView2D<int, Stride2D.DenseX>, ArrayView2D<int, Stride2D.DenseX>, ArrayView2D<int, Stride2D.DenseX>>(RMatrixKernels.AdditionKernel);
尝试用包装类实现简化但未成功:
public class KernelWrapper { public Delegate Kernel { get; private set; } public KernelWrapper(Delegate kernel) { Kernel = kernel; } }
请问该如何实现简化?
完整源代码:
using ILGPU; using ILGPU.Runtime; using System; using System.Collections.Generic; public class RMatrixKernels { public static void AdditionKernel(Index2D index, ArrayView2D<int, Stride2D.DenseX> matrixA, ArrayView2D<int, Stride2D.DenseX> matrixB, ArrayView2D<int, Stride2D.DenseX> result) { result[index] = matrixA[index] + matrixB[index]; } public static void ScalarMultiplyKernel( Index2D index, ArrayView2D<int, Stride2D.DenseX> aView, int scalar, ArrayView2D<int, Stride2D.DenseX> cView) { cView[index] = aView[index] * scalar; } } public class RMatrix { private int[,] matrix_; public int Rows { get; private set; } public int Cols { get; private set; } private static Accelerator accelerator_; static RMatrix() { var context_ = Context.CreateDefault(); accelerator_ = context_.GetPreferredDevice(preferCPU: true).CreateAccelerator(context_); } public RMatrix(int rows, int cols) { Rows = rows; Cols = cols; matrix_ = new int[rows, cols]; } public RMatrix(int[,] arr) { Rows = arr.GetLength(0); Cols = arr.GetLength(1); matrix_ = new int[Rows, Cols]; Array.Copy(arr, matrix_, arr.Length); } public static RMatrix operator +(RMatrix a, RMatrix b) { if (a.Rows != b.Rows || a.Cols != b.Cols) throw new ArgumentException("Matrix dimensions must match for addition."); var deviceMatrixA = accelerator_.Allocate2DDenseX<int>(new Index2D(a.Rows, a.Cols)); var deviceMatrixB = accelerator_.Allocate2DDenseX<int>(new Index2D(a.Rows, a.Cols)); var deviceResult = accelerator_.Allocate2DDenseX<int>(new Index2D(a.Rows, a.Cols)); deviceMatrixA.CopyFromCPU(a.matrix_); deviceMatrixB.CopyFromCPU(b.matrix_); //TODO: var kernel = accelerator_.LoadAutoGroupedStreamKernel<Index2D, ArrayView2D<int, Stride2D.DenseX>, ArrayView2D<int, Stride2D.DenseX>, ArrayView2D<int, Stride2D.DenseX>>(RMatrixKernels.AdditionKernel); kernel((a.Rows, a.Cols), deviceMatrixA.View, deviceMatrixB.View, deviceResult.View); accelerator_.Synchronize(); int[,] hostResult = new int[a.Rows, a.Cols]; deviceResult.CopyToCPU(hostResult); deviceMatrixA.Dispose(); deviceMatrixB.Dispose(); deviceResult.Dispose(); return new RMatrix(hostResult); } public static RMatrix operator *(RMatrix a, int scalar) { var deviceMatrixA = accelerator_.Allocate2DDenseX<int>(new Index2D(a.Rows, a.Cols)); var deviceResult = accelerator_.Allocate2DDenseX<int>(new Index2D(a.Rows, a.Cols)); deviceMatrixA.CopyFromCPU(a.matrix_); //TODO: var kernel = accelerator_.LoadAutoGroupedStreamKernel<Index2D, ArrayView2D<int, Stride2D.DenseX>, int, ArrayView2D<int, Stride2D.DenseX>>(RMatrixKernels.ScalarMultiplyKernel); kernel((a.Rows, a.Cols), deviceMatrixA.View, scalar, deviceResult.View); accelerator_.Synchronize(); int[,] hostResult = new int[a.Rows, a.Cols]; deviceResult.CopyToCPU(hostResult); deviceMatrixA.Dispose(); deviceResult.Dispose(); return new RMatrix(hostResult); } public void Show() { for (int i = 0; i < Rows; i++) { for (int j = 0; j < Cols; j++) { Console.Write(matrix_[i, j] + "\t"); } Console.WriteLine(); } } } public static class Program { static void Main() { int[,] hostMatrixA = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }; int[,] hostMatrixB = { { 9, 8, 7 }, { 6, 5, 4 }, { 3, 2, 1 } }; RMatrix a = new RMatrix(hostMatrixA); RMatrix b = new RMatrix(hostMatrixB); RMatrix c = a + b; RMatrix d = a * 10; Console.WriteLine("Matrix A + B:"); c.Show(); Console.WriteLine("\nMatrix A * 10:"); d.Show(); } }
解决方案
方法:利用C#类型推断封装扩展方法
给Accelerator创建扩展方法,让编译器自动推断内核方法的泛型参数,无需手动指定:
public static class AcceleratorExtensions { // 适配3个参数的内核(索引+3个参数) public static Action<Index2D, T1, T2, T3> LoadAutoGroupedStreamKernel<T1, T2, T3>(this Accelerator accelerator, Action<Index2D, T1, T2, T3> kernel) { return accelerator.LoadAutoGroupedStreamKernel<Index2D, T1, T2, T3>(kernel); } // 适配4个参数的内核(索引+4个参数) public static Action<Index2D, T1, T2, T3, T4> LoadAutoGroupedStreamKernel<T1, T2, T3, T4>(this Accelerator accelerator, Action<Index2D, T1, T2, T3, T4> kernel) { return accelerator.LoadAutoGroupedStreamKernel<Index2D, T1, T2, T3, T4>(kernel); } }
使用方式
添加扩展方法后,直接传入内核方法组即可,编译器会自动推断泛型参数:
// 加法内核加载 var kernel = accelerator_.LoadAutoGroupedStreamKernel(RMatrixKernels.AdditionKernel); // 标量乘法内核加载 var kernel = accelerator_.LoadAutoGroupedStreamKernel(RMatrixKernels.ScalarMultiplyKernel);
原包装类失败原因
之前的KernelWrapper仅存储Delegate类型,但ILGPU的LoadAutoGroupedStreamKernel需要明确的强类型委托来生成GPU内核代码,Delegate无法让编译器推断出具体泛型参数,因此无法正确加载内核。而扩展方法通过强类型委托,让编译器自动完成泛型参数推断,间接调用ILGPU的原始方法。
内容的提问来源于stack exchange,提问作者user366312
相关产品推荐
相关产品推荐

