【问题标题】:JCuda Pinned Memory ExampleJCuda 固定内存示例
【发布时间】:2013-03-18 06:12:30
【问题描述】:

JCuda + GEForce Gt640 问题:

在 GPU 计算出结果后,我正在尝试减少与将内存从设备复制到主机相关的延迟。执行简单的 Vector Add 程序,我发现大部分延迟确实是将结果缓冲区复制回主机端。源缓冲区到设备端的传输延迟可以忽略不计 ~.30 毫秒,而将结果复制回大约 20 毫秒。

我进行了研究,发现复制结果的更好替代方法是使用固定内存。据我所知,这个内存是在主机端分配的,但内核可以通过 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

注意:如果这很重要,我正在为 x86 使用 JCuda0.5.0。

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

【问题讨论】:

  • 你实际上并没有在这里问过问题......
  • 我做错了什么?

标签: cuda jcuda


【解决方案1】:

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

诚然,documentation 在这里听起来有误导性:

cuMemAllocHost

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

这听起来像是一个明确的声明。但是,这里的“可访问”不是意味着在所有情况下都可以直接将内存用作内核参数。这仅适用于支持Unified Addressing 的设备。对于所有其他设备,需要获取与分配的主机指针对应的设备指针,cuMemHostGetDevicePointer

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

编辑:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-02
    • 2011-02-25
    • 2011-03-28
    • 2017-09-11
    • 1970-01-01
    相关资源
    最近更新 更多