C# 如何合计FloatResidentArray并将值检索到设备或主机

C# 如何合计FloatResidentArray并将值检索到设备或主机,c#,hybridizer,C#,Hybridizer,我正在使用Hybridizer对FloatResidentArray进行合计,但由于最终AtomicExpr.apply语句中需要ref语句,因此无法将计算出的合计返回到设备(或主机)。 考虑下面的代码,该代码基于Altimesh提供的GyrimRead示例。 该代码获取一个设备驻留数组a,其浮点长度N,并计算总数–该值位于总数[0]中 [Kernel] public static void Total(FloatResidentArray a, int N, float[] total)

我正在使用Hybridizer对FloatResidentArray进行合计,但由于最终AtomicExpr.apply语句中需要ref语句,因此无法将计算出的合计返回到设备(或主机)。 考虑下面的代码,该代码基于Altimesh提供的GyrimRead示例。 该代码获取一个设备驻留数组a,其浮点长度N,并计算总数–该值位于总数[0]

[Kernel]
 public static void Total(FloatResidentArray a, int N, float[] total)
 {
    var cache = new SharedMemoryAllocator<float>().allocate(blockDim.x);

    int tid = threadIdx.x + blockDim.x * blockIdx.x;
    int cacheIndex = threadIdx.x;
    float sum = 0f;           
    while (tid < N)
    {
       sum = sum + a[tid];               
       tid += blockDim.x * gridDim.x;
     }
     cache[cacheIndex] = sum;          
     CUDAIntrinsics.__syncthreads();
     int i = blockDim.x / 2;
     while (i != 0)
     {
        if (cacheIndex < i)
        {
            cache[cacheIndex] = cache[cacheIndex] + cache[cacheIndex + i];
        }
        CUDAIntrinsics.__syncthreads();
        i >>= 1;
     }

     if (cacheIndex == 0)
     {
          AtomicExpr.apply(ref total[0], cache[0], (x, y) => x + y);
     }
  }
[内核]
公共静态无效总计(浮动剩余数组a、整数N、浮动[]总计)
{
var cache=new SharedMemoryAllocator().allocate(blockDim.x);
int tid=threadIdx.x+blockDim.x*blockIdx.x;
int cacheIndex=threadIdx.x;
浮点数和=0f;
而(tid>=1;
}
if(cacheIndex==0)
{
原子表达式应用(参考总计[0],缓存[0],(x,y)=>x+y);
}
}
上述代码无法编译,因为无法在同一参数列表中传递float[]和FloatResidentArray

如果total本身被定义为FloatResidentArray,那么编译器将不允许在最后一行代码中使用ref关键字

如果我只是传递一个float,那么返回的变量不会用total更新

如果我传递一个ref float,那么程序会在HybRunner包装上述代码以创建动态的地方抛出一个运行时错误,错误消息是

不支持按引用的值类型


如何返回总数?-无论是到设备还是到主机内存,两者都是可以接受的。

那么,您需要了解编组是如何工作的

对象和数组(甚至常驻数组)在.Net中创建时都是主机。 然后我们在内核执行之前封送它们(pin主机内存、分配设备内存和将主机复制到设备)

  • 对于float[],这将自动完成
  • 对于IntPtr,我们什么也不做,用户必须确保IntPtr是包含数据的有效设备指针
  • 对于常驻数组,我们什么也不做,当用户想要来回获取数据时,必须手动调用RefreshDevice()和RefreshHost
支持混合ResidentArray和float[],如生成的dll的屏幕截图所示:

不支持的是:混合托管类型和IntPtr

以下是代码的完整版本,正在运行,并返回正确的结果:

using Hybridizer.Runtime.CUDAImports;
using System;
using System.Runtime.InteropServices;

namespace SimpleMetadataDecorator
{
    class Program
    {
        [EntryPoint]
        public static void Total(FloatResidentArray a, int N, float[] total)
        {
            var cache = new SharedMemoryAllocator<float>().allocate(blockDim.x);

            int tid = threadIdx.x + blockDim.x * blockIdx.x;
            int cacheIndex = threadIdx.x;
            float sum = 0f;
            while (tid < N)
            {
                sum = sum + a[tid];
                tid += blockDim.x * gridDim.x;
            }
            cache[cacheIndex] = sum;
            CUDAIntrinsics.__syncthreads();
            int i = blockDim.x / 2;
            while (i != 0)
            {
                if (cacheIndex < i)
                {
                    cache[cacheIndex] = cache[cacheIndex] + cache[cacheIndex + i];
                }
                CUDAIntrinsics.__syncthreads();
                i >>= 1;
            }

            if (cacheIndex == 0)
            {
                AtomicExpr.apply(ref total[0], cache[0], (x, y) => x + y);
            }
        }
        static void Main(string[] args)
        {

            const int N = 1024 * 1024 * 32;
            FloatResidentArray arr = new FloatResidentArray(N);
            float[] res = new float[1];
            for (int i = 0; i < N; ++i)
            {
                arr[i] = 1.0F;
            }

            arr.RefreshDevice();
            var runner = HybRunner.Cuda();
            cudaDeviceProp prop;
            cuda.GetDeviceProperties(out prop, 0);
            runner.SetDistrib(16 * prop.multiProcessorCount, 1, 128, 1, 1, 128 * sizeof(float));
            var wrapped = runner.Wrap(new Program());
            runner.saveAssembly();
            cuda.ERROR_CHECK((cudaError_t)(int)wrapped.Total(arr, N, res));
            cuda.ERROR_CHECK(cuda.DeviceSynchronize());
            Console.WriteLine(res[0]);

        }
    }
}
使用Hybridizer.Runtime.CUDAImports;
使用制度;
使用System.Runtime.InteropServices;
命名空间SimpleMetadataDecorator
{
班级计划
{
[入口点]
公共静态无效总计(浮动剩余数组a、整数N、浮动[]总计)
{
var cache=new SharedMemoryAllocator().allocate(blockDim.x);
int tid=threadIdx.x+blockDim.x*blockIdx.x;
int cacheIndex=threadIdx.x;
浮点数和=0f;
而(tid>=1;
}
if(cacheIndex==0)
{
原子表达式应用(参考总计[0],缓存[0],(x,y)=>x+y);
}
}
静态void Main(字符串[]参数)
{
常数int N=1024*1024*32;
FloatResidentArray arr=新的FloatResidentArray(N);
float[]res=新的float[1];
对于(int i=0;i
我无法重现这个问题。对我来说效果很好。您能用mcve()更新您的问题吗