ROCm编程模型与系统运行时API接口
ROCm的编程模型
HIP(Heterogeneous Compute Interface for Portability,可移植异构计算接口) 是一种厂商中立的C++编程模型,用于实现高度优化的GPU 工作负载。它类似于CUDA,是一种C++方言,支持模板、类、lambda 和其他C++构造。
HIPIFY是一种工具用于帮助将CUDA代码转换成HIP,从而能够针对AMD 或NVIDIA GPU (CUDA) 环境的代码编译。ROCm HIP编译器基于Clang、LLVM 编译器基础架构和libC++标准库。
OpenCL(Open Computing Language,开放运算语言)是第一个开放的、免费的异构系统通用并行编程标准,也是一个统一的编程环境。OpenCL编程模型是基于应用程序API支持的主机设备以及通过总线连接的许多设备的概念。这些都是使用OpenCL C编程的。主机API分为平台层和Runtime层。OpenCL C是一种类似于C的语言,具有用于并行编程的扩展,如内存围栏操作和障碍物。
3.4.5 ROCm驱动
ROCM的驱动由amdgpu和amdkfd Linux设备驱动程序组成,支持AMD的APU(Accelerated Processing Unit,应用处理单元)。
1. AMD KFD驱动
Amdkfd驱动程序是Radeon GPU计算堆栈的内核代码,AMD KFD驱动程序可以与AMD的开源图形堆栈(Gallium3D+AMD GPU LLVM后端)和开源HSA运行时库结合使用,作为HSA Linux的初始实现,以及用于OpenCL计算的Clover状态跟踪器。它可以随时使用,可用于测试AMD Kaveri APU硬件。
AMDKFD驱动程序实现了以下功能:中断处理模块、队列模块、mqd\u管理器模块、内核队列模块、包管理器模块、进程队列管理器模块、设备队列管理器模块、拓扑模块和内存管理模块等等。
2. AMD GPU驱动
drm/amdgpu驱动程序支持基于GNC(Graphics Core Next)架构的所有AMD Radeon GPU。
amdgpu驱动程序实现了对核心驱动基础设施的管理:内存域、缓冲对象、PRIME缓冲区共享、MMU通知程序、AMDGPU虚拟内存、中断处理和IP块。
amdgpu定义了对amdgpu_bo缓冲区对象进行操作的接口,该对象代表驱动程序使用的内存(VRAM、系统内存等)。驱动程序使用这些接口来创建、销毁或设置缓冲区对象,然后由内核TTM内存管理器来管理。这些接口也被内核客户端在内部使用,用于GPU使
用的内核管理分配。
对于中断处理,在GPU硬件中生成的中断会引发中断请求,这些请求会传递给amdgpu IRQ处理程序,该处理程序负责检测中断的来源和类型并调度一个匹配的处理程序。如果处理中断需要调用可能休眠的内核函数,那么该处理程序则将处理分派给工作处理程序。
AMDGPU驱动还提供了XGMI支持、RAS支持、GPU 电源/热控制和监控、GPU产品信息、GPU 内存使用信息和PCIe Accounting信息。
ROCm系统运行时API接口
HSA运行时是一个精简的用户模式API,它公开了必要接口,以访问由 AMDGPU驱动程序集和ROCK内核驱动程序驱动的图形硬件并与之交互。它们一起使程序员能够通过允许主机应用程序直接向图形硬件启动计算内核来直接利用AMD独立图形设备的功能。
HSA运行时 API表达的能力有错误处理、Runtime初始化和关闭、系统和代理信息、信号和同步、结构化调度和内存管理。
1. 内存管理
HSA运行时API可以用于检查可从代理访问的内存区域,以及在这些区域上分配内存。内存区域指具有可由一个或多个代理访问的特定特征的虚拟内存块。Region对象hsa_region_t公开关于内存块的属性,例如关联的内存段、大小,在某些情况下还包括分配特性。
函数hsa_agent_iterate_Regions可用于检查与代理关联的区域集。应用程序可以使用函数hsa_memory_allocate在区域中分配内存,HSA运行时分配器只能用于在全局段和只读段中分配内存。当应用程序不再需要使用函数hsa_memory_allocate分配的缓冲区时,它会调用hsa_memory_free来释放内存。
2. 错误处理
运行时通知类型的API控制ROC运行时通知报告错误和事件,运行时通知的流程图,如图3-7所示。运行库可以同步或异步报告通知错误或事件。运行时使用HSA API中函数的返回值将同步通知传递给应用程序。通知是指示成功或错误的hsa_status_t类型的状态代码。当HSA函数未成功执行时,返回的状态代码可能有助于确定错误的来源。

图 3-7 初始化和关机流程图
运行库以不同的方式传递异步通知。当运行库检测到异步事件时,它会调用应用程序定
义的回调。例如,队列是异步事件的常见来源,因为由应用程序排队的任务由分组处理器异步消耗。当运行库检测到队列中的错误时,它会调用与该队列关联的回调,并向其传递状态代码(来指示发生了什么)和指向错误队列的指针。应用程序可以在创建时将回调与队列相关联。
3. Runtime初始化和关闭
当应用程序在给定进程中首次初始化Runtime(Hsa_Init)时,将创建Runtime实例。对实例进行引用计数,使得同一进程内的多个HSA客户端不会相互干扰。在一个进程内调用初始化例程n次并不会创建n个运行时实例,而是创建一个唯一的Runtime对象,其关联的引用计数器为n。关闭Runtime(Hsa_Shutt_Down)等同于减少其引用计数器。当引用计数器小于1时,Runtime对象将不复存在,并且对它的任何引用(或对它处于活动状态时创建的任何资源的引用)都会导致未定义的行为。
4. System与Agent 信息交互
HSA运行时 API使用hsa_agent_t类型的不透明句柄来表示代理。应用程序可以使用hsa_iterate_agent遍历系统中可用的代理列表,并使用hsa_agent_get_info查询特定于代理的属性,应用程序可以使用hsa_system_get_info查询系统范围的属性。代理属性的示例包括:名称、备份设备类型(CPU、GPU)和支持的队列类型。Hsa_iterate_agent的实现至少需要报告主机(CPU)代理。
5. 信号和同步
代理之间可以通过使用一致的共享(全局)内存或使用信号进行通信。代理可以对信号执行类似于对共享内存位置执行的操作。HSA运行时 API使用hsa_ignal_t类型的不透明信号处理程序来表示信号。信号携带hsa_ignal_value_t类型的带符号整数值,可以通过API调用或HSAIL指令访问或有条件地等待该值。应用程序使用函数hsa_ignal_create创建信号。
6. 代码对象和可执行文件
当应用程序填充内核分派包时,它必须指定一个内核对象,即要执行的机器代码的句柄。内核对象句柄的创建方法:首先将内核源代码向下编译为HSA运行时,然后将代码对象加载到另一个HSA运行时对象(可执行文件)中。应用程序可以使用HSA运行时 API对可执行对象执行查询,以获得内核对象。内核对象生成所经历的阶段的一个示例,如图3-8所示。

图 3-8代码对象检索内核对象句柄流程图
人工智能芯片与自动驾驶

浙公网安备 33010602011771号