微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如果我使用其他 GPU,为什么我的 OpenCL 功能不起作用?

如何解决如果我使用其他 GPU,为什么我的 OpenCL 功能不起作用?

我正在使用 Cloo 使用我的 GPU 连接大数组,在我的第一台 PC(具有 AMD RX 570)上一切正常,但在第二台(Nvidia 920m)上我的函数什么也不做,我的应用程序崩溃,因为我复制的数组被 0 填充。

这是我的函数(我添加了 prinf 来检查我的程序是否真的在使用它):

kernel void Arraycopy(global uchar* bufferIn,int inOffset,global uchar* bufferOut,int outOffset) 
{
    int index = get_global_id(0);
    bufferOut[index + outOffset] = bufferIn[index + inOffset];
    printf("It works!");
}

我不知道为什么 Cloo 没有给我异常、警告或其他任何信息。

我在调试应用程序时挖掘了一些有关显卡的数据:

谢谢大家,抱歉我的英语不好。

编辑:

我创建了一个通过 UDP socket 发送图像的程序,这些图像可以达到超过 200KB,因此我应该将它们发送到多个数据包中并以相同的顺序重建它们在我的客户端应用程序中。

由于我使用的是 sockets,这些数组将是字节数组 (byte[]),其中 equivalent in OpenCLuchar*

Nodaways 我正在使用 Sytem.Array.Copy 来重建这些图像,由于这些数组的大小,这非常慢。因此,我使用 Cloo 编写了一个函数,它接受 5 个参数(如 System.Array.copy):

  • bufferIn(源数组)
  • inOffset(开始读取值的源索引)
  • bufferOut(目标数组)
  • outOffset(开始设置值的目标索引)
  • 长度(要复制的元素数)。
public void GPUcopy(byte[] bufferIn,byte[] bufferOut,int outOffset,int lenght)
{
    ComputeBuffer<byte> originBuffer,destBuffer;

    originBuffer = new ComputeBuffer<byte>(context,ComputeMemoryFlags.ReadOnly | ComputeMemoryFlags.UseHostPointer,bufferIn);
    destBuffer = new ComputeBuffer<byte>(context,bufferOut);

    kernel.SetMemoryArgument(0,originBuffer);
    kernel.SetValueArgument(1,inOffset);
    kernel.SetMemoryArgument(2,destBuffer);
    kernel.SetValueArgument(3,outOffset);

    queue.Execute(kernel,new long[] { 0 },new long[] { lenght },null,new ComputeEventList());
    queue.Finish();
}

正如我之前所说,这在我的 RX 570 上运行良好,并且在我的 920 米 上没有错误

完整的类源代码在这里

class GPU
{
    private ComputeCommandQueue queue;
    private ComputeContext context;
    private ComputeKernel kernel;

    private string Arraycopy
    {
        get
        {
            return @"
                    kernel void Arraycopy(global uchar* bufferIn,int outOffset) 
                    {
                          int index = get_global_id(0);
                          bufferOut[index + outOffset] = bufferIn[index + inOffset];
                    }";
        }
    }

    public GPU()
    {
        context = new ComputeContext(ComputeDeviceTypes.Gpu,new ComputeContextPropertyList(ComputePlatform.Platforms[0]),IntPtr.Zero);
        queue = new ComputeCommandQueue(context,context.Devices[0],ComputeCommandQueueFlags.None);
        var program = new ComputeProgram(context,Arraycopy);
        program.Build(null,IntPtr.Zero);

        kernel = program.CreateKernel("Arraycopy");
    }

    public void GPUcopy(byte[] bufferIn,int lenght)
    {
        ComputeBuffer<byte> originBuffer,destBuffer;

        originBuffer = new ComputeBuffer<byte>(context,bufferIn);
        destBuffer = new ComputeBuffer<byte>(context,bufferOut);

        kernel.SetMemoryArgument(0,originBuffer);
        kernel.SetValueArgument(1,inOffset);
        kernel.SetMemoryArgument(2,destBuffer);
        kernel.SetValueArgument(3,outOffset);

        queue.Execute(kernel,new ComputeEventList());
        queue.Finish();
    }
}

解决方法

您在问题中提供的信息很少,但我可以想到您需要检查或尝试的一些事项,对此评论有些尴尬,所以这里是一个“答案”:

  • 您的上下文符合哪个版本的 OpenCL?在 OpenCL 1.0 中,字节寻址不是内置的,您一次复制一个字节 (uchar)。因此,如果您的上下文是 OpenCL 1.0 上下文,请检查您的设备是否支持 cl_khr_byte_addressable_store extension 并在您的内核中启用它。 (在 OpenCL 1.1 和更新版本中,您不需要这样做。)
  • 如果上述原因不是导致您出现问题的原因,我希望主机端会返回一些错误。你确定你检查得足够充分吗?我不熟悉 cloo 包装器,似乎没有任何文档(?)但是在普通的 OpenCL 中,几乎每个主机函数都会返回某种结果代码,如果您不检查和处理这个,它通常会导致您看到的那种行为。
  • 如果您的内核确实如您发布的那样,并且这不仅仅是一个简化的示例:对于复制缓冲区子范围,您可能应该使用 clEnqueueCopyBuffer,它使用设备的 DMA 引擎(如果可用),而不是自定义内核。如果这在任何 OpenCL 实现中变慢,我会感到非常惊讶,而在某些实现中它会更快。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。