我使用 ILGPU 在 GPU 上运行大量数学代码,我将其组织在按接口隔离的模块化类中,以实现不同的模块化算法。
现在 ILGPU 只允许在 GPU 内核上运行静态方法。因此,我需要从这些嵌套类中取出 IL,并手动内联,输出一个称为 Kernel 的静态方法。
示例中
public interface IFunction
{
public float DoSum(float[] input);
}
public class NormalSum
{
public float(float[] input)
{
float sum=0.0f;
for(int i=0;i<input.Lenght;i++)
sum+=input[i];
}
}
public interface IAlgorithm
{
public void DoAlgorithm(float[] input, float[] output);
}
public class MyAlgorithm
{
IFunction fun;
public MyAlgorithm(IFunction fun)
{
this.fun = fun;
}
public void DoAlgorithm(float[] input, float[] output)
{
for(int j=0;j<output.Length;j++)
{
output[j] = 2.0f* fun.DoSum(input);
}
}
}
没有存储变量,类和接口只是算法的包装器,所以我需要一个代码并期望它将方法内联到类似的东西,而不必费心解决对实例成员的最终引用,我希望“有趣”只是为了提取方法实现,那么“乐趣”就可以丢弃了。
var staticMethod = Inline(new MyAlgorithm(new NormalSum));
// generated IL
public static void GeneratedCode(float[] input, float[] output)
{
for(int j=0;j<output.Length;j++)
{
float sum=0.0f;
for(int i=0;i<input.Length;i++)
sum+=input[i];
float result = sum;
output[j] = 2.0f* result;
}
}
到目前为止,我只是复制了一个静态方法,但无法进入“实现内部”。
MethodInfo existingMethod = typeof(MyStaticClass).GetMethod("MethodToCopy", BindingFlags.Static | BindingFlags.Public);
AssemblyName assemblyName = new AssemblyName("DynamicAssembly");
AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("DynamicModule");
TypeBuilder typeBuilder = moduleBuilder.DefineType("DynamicClass", TypeAttributes.Public);
MethodBuilder methodBuilder = typeBuilder.DefineMethod("DynamicMethod", MethodAttributes.Public | MethodAttributes.Static, existingMethod.ReturnType, new Type[] { });
ILGenerator ilGenerator = methodBuilder.GetILGenerator();
// Copy IL code
foreach (var instruction in existingMethod.GetMethodBody().GetILAsByteArray())
{
ilGenerator.Emit(instruction);
}
Type type = typeBuilder.CreateType();
type.GetMethod("DynamicMethod").Invoke(null, null);
如果您可以使用 C# 11+,那么您可以尝试使用 静态抽象接口成员并完全转储反射:
使用静态方法声明接口:
public interface IAlgorithm1
{
public static abstract void DoAlgorithm(float[] input, float[] ouput) ;
}
public interface IFunction1
{
public static abstract float DoSum(float[] input);
}
然后实施它们:
public class MyAlgorithm1<T> : IAlgorithm1 where T : IFunction1
{
public static void DoAlgorithm(float[] input, float[] output)
{
for(int j=0;j<output.Length;j++)
{
output[j] = 2.0f* T.DoSum(input); // call to the static method of the generic type
}
}
}
public class NormalSum1 : IFunction1
{
public static float DoSum(float[] input)
{
float sum = 0.0f;
for (int i = 0; i < input.Length; i++)
sum += input[i];
return sum;
}
}
然后你可以通过
MyAlgorithm1<NormalSum1>.DoAlgorithm
访问静态方法:
var output = new float[1];
MyAlgorithm1<NormalSum1>.DoAlgorithm(new []{1f}, output);