C# 如何合计FloatResidentArray并将值检索到设备或主机
我正在使用Hybridizer对FloatResidentArray进行合计,但由于最终AtomicExpr.apply语句中需要ref语句,因此无法将计算出的合计返回到设备(或主机)。 考虑下面的代码,该代码基于Altimesh提供的GyrimRead示例。 该代码获取一个设备驻留数组a,其浮点长度N,并计算总数–该值位于总数[0]中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)
[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李>
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()更新您的问题吗