JCuda固定内存示例

JCuda固定内存示例,cuda,jcuda,Cuda,Jcuda,JCuda+GEForce Gt640问题: 在GPU计算出结果后,我试图减少将内存从设备复制到主机的延迟。在执行简单的Vector Add程序时,我发现大部分延迟实际上是将结果缓冲区复制回主机端。源缓冲区到设备端的传输延迟可以忽略~.30ms,而将结果复制回设备端的延迟大约为20ms 我做了这项研究,发现复制结果的更好方法是使用固定内存。据我所知,这个内存是在主机端分配的,但是内核可以通过pci-e直接访问它,从而产生比批量计算后复制结果更高的速度。我正在使用下面的示例,但结果并没有产生我所期

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;
}
爪哇:

import java.io.*;
进口jcuda。*;
导入jcuda.runtime.*;
导入jcuda.driver.*;
导入静态jcuda.runtime.cudaMemcpyKind.*;
导入静态jcuda.driver.JCudaDriver.*;
公共类JCudaTest
{
公共静态void main(字符串参数[])
{
//初始化驱动程序并为第一个设备创建上下文。
cuInit(0);
CUdevice device=新CUdevice();
cuDeviceGet(设备,0);
CUcontext context=新的CUcontext();
cuCtxCreate(上下文,0,设备);
//加载ptx文件。
积云模块=新积云模块();
JCudaDriver.cuModuleLoad(模块,“JCudaKernel.ptx”);
//获取指向内核函数的函数指针。
CUfunction=新的CUfunction();
cuModuleGetFunction(函数,模块,“add”);
指针P=新指针();
JCudaDriver.cumemalochost(P,5*Sizeof.INT);
指针内核参数=指针指向(P);
//使用1块1线程调用内核函数:
内核(函数,1,1,1,1,1,1,1,0,null,kernelParameters,null);
int[]T=新的int[5];
cudaMemcpy(指针指向(T),P,5*Sizeof.INT,cudaMemcpyHostToHost);
//打印结果:

对于(int i=0;i,这里的问题是设备可能无法直接访问主机内存

诚然,这里的声音有误导性:

积垢

分配被页面锁定且可供设备访问的主机内存字节数

这听起来很清楚。但是,此处的“可访问”并不意味着内存在所有情况下都可以直接用作内核参数。这仅在支持的设备上可行。对于所有其他设备,需要获取与分配的主机指针相对应的设备指针,并使用

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

编辑:


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

您实际上没有在这里提出问题……我做错了什么?
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]);
    }
}