C Nouveau驱动程序如何在GPU端分配内存?
我一直在研究新的GPU驱动程序(Nvidia GPU的开源GPU驱动程序),因为我想了解驱动程序内部的实际情况。 具体来说,我一直在试图弄清楚CPU端运行的新代码如何能够在GPU端分配内存。C Nouveau驱动程序如何在GPU端分配内存?,c,linux-kernel,gpu,driver,gpgpu,C,Linux Kernel,Gpu,Driver,Gpgpu,我一直在研究新的GPU驱动程序(Nvidia GPU的开源GPU驱动程序),因为我想了解驱动程序内部的实际情况。 具体来说,我一直在试图弄清楚CPU端运行的新代码如何能够在GPU端分配内存。 换句话说,我想学习cudamaloc()如何在GPU端分配内存。(我知道cudamaloc()是CUDA API,但我不确定CUDA的cudamaloc()在Nouveau上的等价物是什么) 以下是我目前发现的情况: Nouveau让TTM(翻译表管理器)通过int TTM_bo_init(…)初始化bo(
换句话说,我想学习
cudamaloc()
如何在GPU端分配内存。(我知道cudamaloc()
是CUDA API,但我不确定CUDA的cudamaloc()
在Nouveau上的等价物是什么)以下是我目前发现的情况:
int TTM_bo_init(…)
初始化bo(缓冲区对象),其定义如下所示:int ttm_bo_init(结构ttm_bo_设备*bdev,
结构ttm_缓冲区_对象*bo,
无符号长尺寸,
枚举ttm_bo_类型,
结构ttm_放置*放置,
uint32页面对齐,
无符号长缓冲区\u开始,
布尔可中断,
结构文件*永久交换存储,
尺寸根据尺寸,
void(*销毁)(结构ttm\u缓冲区\u对象*)
{
int-ret=0;
未签名的长数页;
结构ttm_mem_global*mem_glob=bdev->glob->mem_glob;
ret=ttm_mem_global_alloc(mem_glob,acc_size,false,false);
如果(ret){
printk(内核内存不足。\n”);
如果(销毁)
(*销毁)(bo);
其他的
kfree(bo);
return-ENOMEM;
}
大小+=缓冲区开始和页面掩码;
页面数=(大小+页面大小-1)>>页面移位;
如果(页数==0){
printk(KERN_ERR TTM_PFX“非法缓冲区对象大小。\n”);
如果(销毁)
(*销毁)(bo);
其他的
kfree(bo);
返回-艾因瓦尔;
}
bo->销毁=销毁;
kref_init(&bo->kref);
kref_init(&bo->list_kref);
原子_集(&bo->cpu_写入程序,0);
原子集(&bo->保留,1);
init_waitqueue_head(&bo->event_queue);
初始列表头(&bo->lru);
初始列表头(&bo->ddestroy);
初始列表头(&bo->交换);
初始列表头(&bo->io\U储备\U lru);
bo->bdev=bdev;
bo->glob=bdev->glob;
bo->type=类型;
bo->num\u pages=num\u pages;
bo->mem.size=num\u pages mem.mem\u type=TTM\u PL\u系统;
bo->mem.num\u pages=bo->num\u pages;
bo->mem.mm_节点=NULL;
bo->mem.page\u alignment=页面对齐;
bo->mem.bus.io\u reserved\u vm=false;
bo->mem.bus.io_reserved_count=0;
bo->buffer\U start=buffer\U start&PAGE\U MASK;
bo->priv_标志=0;
bo->mem.placement=(TTM_PL_FLAG_SYSTEM | TTM_PL_FLAG_CACHED);
bo->seq_valid=false;
bo->persistent\u swap\u storage=persistent\u swap\u storage;
bo->acc\U size=acc\U size;
原子计数公司(&bo->glob->bo计数);
ret=ttm\u bo\u检查位置(bo,位置);
如果(不太可能(ret!=0))
出去走走;
/*
*对于ttm\u bo\u类型的设备缓冲区,分配
*来自设备的地址空间。
*/
如果(bo->type==ttm\U bo\U type\U设备){
ret=ttm\u bo\u设置\u vm(bo);
如果(ret)
出去走走;
}
ret=ttm_bo_validate(bo、放置、可中断、假、假);
如果(ret)
出去走走;
ttm_bo_unreserve(bo);
返回0;
错误:
ttm_bo_unreserve(bo);
ttm_bo_unref(&bo);
返回ret;
}
我认为对于用户空间应用程序,缓冲区将通过ttm\u bo\u setup\u vm()
在设备(GPU)端的这部分代码上分配:
/*
*对于ttm\u bo\u类型的设备缓冲区,分配
*来自设备的地址空间。
*/
如果(bo->type==ttm\U bo\U type\U设备){
ret=ttm\u bo\u设置\u vm(bo);
如果(ret)
出去走走;
}
而ttm\u bo\u setup\u vm()
定义为:
/**
*ttm\u bo\u设置\u虚拟机:
*
*@bo:为其分配地址空间的缓冲区
*
*在drm设备中分配地址空间,以便应用程序
*可以映射缓冲区并访问内容。仅此而已
*适用于ttm_bo_type_设备对象,其他对象则不适用
*放置在drm设备地址空间中。
*/
静态int ttm\u bo\u设置\u vm(结构ttm\u缓冲区\u对象*bo)
{
结构ttm_bo_设备*bdev=bo->bdev;
int ret;
重试\u预\u获取:
ret=drm_mm_pre_get(&bdev->addr_space_mm);
如果(不太可能(ret!=0))
返回ret;
写入锁定(&bdev->vm锁定);
bo->vm\u node=drm\u mm\u search\u free(&bdev->addr\u space\u mm),
bo->mem.num_页面,0,0);
if(不太可能(bo->vm_节点==NULL)){
ret=-ENOMEM;
跳出去解锁;
}
bo->vm\u节点=drm\u mm\u获取块\u原子(bo->vm\u节点,
bo->mem.num_页面,0);
if(不太可能(bo->vm_节点==NULL)){
写入解锁(&bdev->vm\u锁定);
转到重试\u pre\u get;
}
ttm_bo_vm_insert_rb(bo);
写入解锁(&bdev->vm\u锁定);
bo->addr_space_offset=((uint64_t)bo->vm_node->start)vm_lock);
返回ret;
}
但是我很难找出锁和解锁部分中的代码是如何在GPU端分配内存的。此外,我还偶然发现了近10年前提出的问题,并想知道答案是否仍然有效-是否可以使用常规
malloc()
和free()
来分配和释放GPU端的内存
我知道这个问题有点模糊,但我不知道我还能提供什么其他信息来让它更清楚。任何建议或想法都将不胜感激。提前谢谢