将映射的Linux字符设备内存注册到CudaHosterRegister会导致参数无效

将映射的Linux字符设备内存注册到CudaHosterRegister会导致参数无效,linux,memory,cuda,mmap,chardev,Linux,Memory,Cuda,Mmap,Chardev,我正试图通过以下方式促进DMACPUGPU数据传输: 1.将我的(专有)设备Linux内核分配的内存映射到用户空间 2.使用cudaHostRegister API函数将后一个(映射内存)注册到Cuda 虽然映射映射到我的设备DMA的用户空间分配内存,然后使用cudaHostRegister注册到Cuda工作正常,但尝试注册“KAlloced”内存会导致cudaHostRegister返回“Invalid Argument”错误 首先,我认为问题在于对齐或我的设备驱动程序复杂的内存池管理,因此我

我正试图通过以下方式促进DMACPUGPU数据传输: 1.将我的(专有)设备Linux内核分配的内存映射到用户空间 2.使用cudaHostRegister API函数将后一个(映射内存)注册到Cuda

虽然映射映射到我的设备DMA的用户空间分配内存,然后使用cudaHostRegister注册到Cuda工作正常,但尝试注册“KAlloced”内存会导致cudaHostRegister返回“Invalid Argument”错误

首先,我认为问题在于对齐或我的设备驱动程序复杂的内存池管理,因此我编写了一个最简单的字符设备,它实现了.mmap(),其中kzalloced 10Kb缓冲区用remap_pfn_range重新映射,问题仍然存在

不幸的是,我在网上没有发现任何类似的问题,所以我真诚地希望我能在这里找到答案

一些系统信息和内核驱动程序用户空间应用程序代码+运行时日志信息:

CUDA    : 8.0
OS Dist : Ubuntu 14.04
Kernel  : 3.16.0-31-generic
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 375.26                 Driver Version: 375.26                    |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|                                                                               
|   0  GeForce GTX 770     Off  | 0000:83:00.0     N/A |                  N/A |
| 26%   32C    P8    N/A /  N/A |     79MiB /  1997MiB |     N/A      Default |
+-------------------------------+----------------------+----------------------+
字符设备mmap()代码:

测试应用程序代码:

static unsigned long map_mem_size;

int main(int argc, char** argv)
{
    int fd;
    const char dev_name[] = "/dev/chardev";
    void * address = NULL;
    long page_off = 0;
    cudaError_t cudarc;

    switch(argc)
    {
    case 2:
        page_off = atoi(argv[1]) * getpagesize();
        break;
    default:
        page_off = 0;
        break;
    }

    map_mem_size = 2 * getpagesize();

    printf("Opening %s file\n", dev_name);
    errno = 0;
    if(0 > (fd = open(dev_name, O_RDWR) ))
    {
        printf("Error %d - %s\n", errno, strerror(errno));
    }
    else
    {
        printf("About to map %lu bytes of %s device memory\n", map_mem_size, dev_name);

        errno = 0;
        if(MAP_FAILED == (address = mmap(NULL, map_mem_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, page_off)))
        {
            printf("Error %d - %s\n", errno, strerror(errno));
        }
        else
        {
            printf("mapped %s driver 'kmalloc' memory" \
                    "\n\t\tFirst  8 bytes : %lX" \
                    "\n\t\tSecond 8 bytes: %lX" \
                    "\n\t\tLast   8 bytes: %lX\n",
                    dev_name,
                    *((unsigned long *)address),
                    *((unsigned long *)address + 1),
                    *(unsigned long *)((unsigned char *)address + map_mem_size - sizeof(unsigned long)));

            if (cudaSuccess != (cudarc = cudaHostRegister(address, map_mem_size, cudaHostRegisterDefault)))
            {
                printf("Error: Failed cudaHostRegister: %s, address %p\n", cudaGetErrorString(cudarc), address);
            }
        }
    }

    /*Release resources block*/

    return EXIT_SUCCESS;
}
运行时调试信息:

用户空间:

./chrdev_test 
Opening /dev/chardev file
About to map 8192 bytes of /dev/chardev device memory
mapped /dev/chardev driver 'kmalloc' memory
                First  8 bytes : CDFFFFFFFFFFFFAB
                Second 8 bytes: AB000000000000EF
                Last   8 bytes: EF0000000C0000AA
Error: Failed cudaHostRegister: invalid argument
Unmapping /dev/chardev file
Closing /dev/chardev file
内核空间(tail-f/var/log/syslog):


谢谢你。

成功了

  • 完整答案见:
  • 内存块长度超过2页(>8K)时出现问题 与Cuda合作
谢谢,
尤尔。

@Robert Crovella这就是重点!如果你mmap任何用户区文件,它工作正常,当我mmap内核内存时,问题就会出现。我99%确定你不能使用mmap进行此操作。事实上,我已得到纠正,注册时(普通)文件的
mmap
似乎不正常work@talonmies这很奇怪,据我所知,大多数v4l2驱动程序在内核中分配内存,如果你是对的,没有办法通过CudahosterRegister来提升他们的数据,在这种情况下,除了我之外的其他人也会遇到同样的问题,但我在网上找不到任何关于这一点的记忆…@Talonmes在任何情况下,请你更具体一点,即:为什么不可能?除了将userland分配的内存映射到驱动程序和Cuda之外,还有什么替代方案?
./chrdev_test 
Opening /dev/chardev file
About to map 8192 bytes of /dev/chardev device memory
mapped /dev/chardev driver 'kmalloc' memory
                First  8 bytes : CDFFFFFFFFFFFFAB
                Second 8 bytes: AB000000000000EF
                Last   8 bytes: EF0000000C0000AA
Error: Failed cudaHostRegister: invalid argument
Unmapping /dev/chardev file
Closing /dev/chardev file
 [ 4814.119537] [chardev] chardev.c, chdv_mmap, line 292:MEM_CHUNK_SIZE 4096, pages_per_buf 1, vsize 8192  vma->vm_pgoff 0
    [ 4814.119538] [chardev] chardev.c, chdv_mmap, line 311:PFN : 16306184
    [ 4814.119543] [chardev] chardev.c, chdv_mmap, line 330:Mapped 'kzalloced' buffer
    [ 4814.119543]           First  8 bytes: CDFFFFFFFFFFFFAB
    [ 4814.119543]           Second 8 bytes: AB000000000000EF
    [ 4814.119543]           Last   8 bytes: EF0000000C0000AA