首页 文章

JCuda固定内存示例

提问于
浏览
0

JCuda GEForce Gt640问题:

我试图减少在GPU计算结果后将内存从设备复制到主机相关的延迟 . 做简单的Vector Add程序我发现大部分延迟确实是将结果缓冲区复制回主机端 . 源缓冲区到设备端的传输延迟可以忽略不计〜 . 30ms,而复制结果的时间大约是20ms .

我做了研究,发现复制结果的更好的替代方法是使用固定内存 . 根据我的学习,这个内存在主机端分配,但内核可以通过pci-e直接访问它,反过来比在批量计算后复制结果产生更高的速度 . 我正在使用以下示例,但结果并未产生我期望的结果 .

内核:{简单示例来说明点,仅启动1个块1个线程}

extern "C"
__global__ void add(int* test)
{
    test[0]=1; test[1]=2; test[2]=3; test[3]=4; test[4]=5;
}

Java的:

import java.io.*;
import jcuda.*;
import jcuda.runtime.*;
import jcuda.driver.*;

import static jcuda.runtime.cudaMemcpyKind.*;
import static jcuda.driver.JCudaDriver.*;

public class JCudaTest
{
    public static void main(String args[])
    {
        // Initialize the driver and create a context for the first device.
        cuInit(0);
        CUdevice device = new CUdevice();
        cuDeviceGet(device, 0);
        CUcontext context = new CUcontext();
        cuCtxCreate(context, 0, device);

        // Load the ptx file.
        CUmodule module = new CUmodule();
        JCudaDriver.cuModuleLoad(module, "JCudaKernel.ptx");

        // Obtain a function pointer to the kernel function.
        CUfunction function = new CUfunction();
        JCudaDriver.cuModuleGetFunction(function, module, "add");

        Pointer P = new Pointer();
        JCudaDriver.cuMemAllocHost(P, 5*Sizeof.INT);

        Pointer kernelParameters = Pointer.to(P);
        // Call the kernel function with 1 block, 1 thread:
        JCudaDriver.cuLaunchKernel(function, 1, 1, 1, 1, 1, 1, 0, null, kernelParameters, null);
        int [] T = new int[5];
        JCuda.cudaMemcpy(Pointer.to(T), P, 5*Sizeof.INT, cudaMemcpyHostToHost);

         // Print the results:
         for(int i=0; i<5; i++)
                System.out.println(T[i]);
    }
}

1.)构建内核:root @ NVS295-CUDA:〜/ JCUDA / MySamples #nvcc -ptx JCudaKernel.cu root @ NVS295-CUDA:〜/ JCUDA / MySamples #ls -lrt | grep ptx -rw-r - r-- 1 root root 3295 Mar 27 17:46 JCudaKernel.ptx

2.)构建Java:root @ NVS295-CUDA:〜/ JCUDA / MySamples #javac -cp“../JCuda-All-0.5.0-bin-linux-x86/*: . ” JCudaTest.java

3.)运行代码:root @ NVS295-CUDA:〜/ JCUDA / MySamples#java -cp“../JCuda-All-0.5.0-bin-linux-x86/*: . ” JCudaTest 0 0 0 0 0

期待:1 2 3 4 5

注意:如果重要的话,我正在使用JCuda0.5.0 for x86 .

请让我知道我做错了什么,并提前感谢:Ilir

1 回答

  • 1

    这里的问题是设备可能直接访问主机内存 .

    不可否认,documentation听起来有误导性:

    cuMemAllocHost分配页面锁定且设备可访问的主机内存的字节大小字节...

    这听起来像一个明确的声明 . 但是,"accessible"这里确实 not 意味着内存可以在所有情况下直接用作内核参数 . 这仅适用于支持Unified Addressing的设备 . 对于所有其他设备,必须使用cuMemHostGetDevicePointer获取与分配的主机指针对应的设备指针 .

    页面锁定主机内存的关键点是主机和设备之间的数据传输速度更快 . 可以在_1662799中看到如何在JCuda中使用此内存的示例(这适用于运行时API,但对于驱动程序API,它的工作方式类似) .

    编辑:

    请注意,CUDA 6的新Unified Memory功能实际上支持您最初打算执行的操作:使用 cudaMallocManaged ,您可以分配主机和设备可直接访问的内存(例如,它可以传递给内核) ,由设备写入,然后由主机读取,无需额外的努力) . 不幸的是,这个概念并没有很好地映射到Java,因为内存仍然由CUDA管理 - 并且这个内存不能替换例如Java VM用于 float[] 数组的内存 . 但至少应该可以从分配有 cudaMallocManaged 的内存中创建 ByteBuffer ,以便您可以访问此内存,例如 FloatBuffer .

相关问题