总览

总体介绍

  • UCP是什么?

    统一计算平台(Unify Compute Platform,以下简称 UCP)定义了一套统一的异构编程接口, 提供应用程序接口(Application Programming Interface,以下简称API)实现对芯片(System on Chip,以下简称SOC)上所有资源的调用。 UCP将SOC上的功能硬件抽象出来并进行封装,对外提供基于功能的API,用于创建相应的UCP任务(如VP算子任务),并支持设置硬件Backend提交至UCP调度器, UCP可基于硬件资源,完成SOC上任务的统一调度。 具体提供了以下几个功能: 视觉处理(Vision Process)、神经网络模型推理(Neural Network)、高性能计算库(High Performance Library)、自定义算子插件开发(待实现)

    image

    Backend相关介绍请查看 Backend说明

  • UCP应用场景:

    单算子调用:可直接使用UCP中的视觉算子、高性能处理算子。

    算子插件开发使用:可进行自定义算子的开发。

    深度学习模型推理:可完成深度学习模型的推理任务,UCP内部完成模型的解析及硬件部署。

  • UCP的优势:

    高度抽象:对于单算子的功能,不会受到硬件差异带来的困扰,可通过指定backend选择需要执行的硬件,降低硬件部署难度。

    集成度高:作为地平线统一的异构编程接口,一套接口完成所有需求开发。

注解

本章节用于指导如何使用UCP进行模型硬件部署等开发任务,具备基本的嵌入式开发的知识、经验和技能可以更好地理解本章节内容。

接口使用流程

UCP任务执行有三种方式:同步执行、异步执行、注册回调函数执行。 以调用VP接口hbVPRoate(hbVPRotate) 为例,说明三种任务执行方式。

同步执行

创建任务时,将taskHandle对应的参数传入nullptr,可立即同步执行,参考代码如下:

#include "hobot/hb_ucp.h" #include "hobot/vp/hb_vp_rotate.h" int main() { // step1: 执行一个rotate任务 hbVPImage src_img{/*do something to init src image*/}; hbVPImage dst_img{/*do something to init dst image*/}; hbVPRotate(nullptr, &dst_img, &src_img, HB_VP_ROTATE_90_CLOCKWISE); return 0; }

异步执行

创建任务时,需要提前将taskHandle参数初始化为nullptr; 提交UCP任务(hbUCPSubmitTask)后,在线程指定位置执行接口(hbUCPWaitTaskDone),等待任务完成,参考代码如下:

#include "hobot/hb_ucp.h" #include "hobot/vp/hb_vp_rotate.h" int main() { // step1: 创建一个rotate任务 hbUCPTaskHandle_t task_handle{nullptr}; hbVPImage src_img{/*do something to init src image*/}; hbVPImage dst_img{/*do something to init dst image*/}; hbVPRotate(&task_handle, &dst_img, &src_img, HB_VP_ROTATE_90_CLOCKWISE); // step2:完成对任务的提交和执行 hbUCPSchedParam sched_param; sched_param.backend = HB_UCP_DSP_CORE_0; sched_param.priority = 0; hbUCPSubmitTask(task_handle, &sched_param); hbUCPWaitTaskDone(task_handle, 100); hbUCPReleaseTask(task_handle); return 0; }

注册回调函数执行

创建任务时,需要提前将taskHandle参数初始化为nullptr; 回调函数需要在任务提交(hbUCPSubmitTask)前注册,否则注册接口会报错。

如下给出设置回调函数的参考代码:

#include "hobot/hb_ucp.h" #include "hobot/vp/hb_vp_rotate.h" typedef struct { std::mutex mutex; std::condition_variable cv; int32_t status; } UserData; void CallBack(hbUCPTaskHandle_t handle, int32_t status, void *userdata) { auto data = static_cast<UserData *>(userdata); data->status = status; data->cv.notify_all(); } void ProcessThread(void *userdata) { auto data = static_cast<UserData *>(userdata); { std::unique_lock<std::mutex> lk{tmp_data->mutex}; tmp_data->cv.wait(lk); } // do something here } int main() { // step1: create a rotate task hbUCPTaskHandle_t task_handle{nullptr}; hbVPImage src_img{/*do something to init src image*/}; hbVPImage dst_img{/*do something to init dst image*/}; hbVPRotate(&task_handle, &dst_img, &src_img, HB_VP_ROTATE_90_CLOCKWISE); // step2: create userdata and custom process thread UserData userdata; userdata.status = 0; std::thread worker(ProcessThread, &userdata); // step3:set callback function before submit task hbUCPSetTaskDoneCb(task_handle, CallBack, &userdata); // step4: submit task hbUCPSchedParam sched_param; HB_UCP_INITIALIZE_SCHED_PARAM(&sched_param); sched_param.backend = HB_UCP_DSP_CORE_0; hbUCPSubmitTask(task_handle, &sched_param); worker.join(); hbUCPReleaseTask(task_handle); return 0; }
注解
  1. UCP内置了Neural Network Kernel,Vision Process Kernel,以及High Performance Kernel,这些kernel算子可能由不同的Backend支持。
  2. UCP任务调度统一按照优先级调度策略,提交任务时可指定任务执行的优先级。
  3. 同步执行不支持配置任务的控制参数和后端选择,UCP会根据当前任务的可执行backend,以及硬件负载信息,选择合适的硬件执行。
  4. 异步执行支持配置任务的控制参数和后端选择,不指定则基于各后端负载均衡选择。
  5. 除了视频编解码任务,所有任务创建时的输入输出内存均需要您按照UCP提供的内存接口自行申请管理。

Backend 说明

backend是指UCP任务执行时的后端计算硬件,当前UCP支持的backend包括BPU、DSP、GDC、STITCH、JPU、VPU、PYRAMID。

backend描述
BPUBrain Process Unit,地平线神经网络计算单元。
DSPDigital Signal Processor,数字信号处理器,是一个可编程的硬件单元。
GDCGeometric Distortion Correction,是ARM上的一个硬件IP,可将输入图像进行视角变换、畸变矫正、图像仿射变换等操作。
STITCHstitch是J6的一个IP单元,可对输入的图像进行裁剪,拼接,拼接模式分别有:alpha融合、alpha beta融合、直接拷贝。
JPUJPEG Processing Unit,主要用以完成JPEG的编解码功能。
VPUVideo Processing Unit,是一种专用的视觉处理单元。
PYRAMID全称Image Pyramid,是一个硬件处理模块,可对整幅原始图像进行缩小。

环境及工具

UCP适用于地平线J6及更高架构的计算平台,您需要具备基本的嵌入式开发的知识技能,以完成交叉编译、部署,使用环境及工具要求参考下表:

环境/工具支持版本
操作系统Linux
开发板J6开发板
开发语言C++11
交叉编译器Linaro 11.4.0
工具链DSPCadence Vsion Q8 2021.7

除开发板外,UCP还在x86仿真环境下提供了与板端同样的开发能力支撑。

x86仿真说明

功能说明

与开发板端相同,UCP在 x86 架构上通过仿真形式提供了同样的视觉处理、模型推理和高性能计算能力,所有的示例及接口代码均可以在仿真环境中等效使用。 您可以在x86环境中进行代码开发和调试,开发过程中获得可即时反馈,并在早期发现和解决问题,从而提高开发效率和代码质量,以确保代码能够无缝迁移到SoC硬件上运行。

UCP支持的各Backend仿真方式如下:

  • BPU和DSP硬件采用指令级仿真。
  • GDC、JPU 和 VPU 硬件采用CModel可执行文件仿真。
    • GDC硬件使用的CModel可执行文件是 gdc_cmodel
    • JPU硬件使用的CModel可执行文件是 Nieuport_JpgEncNieuport_JpgDec ,分别用于JPEG编码和解码。
    • VPU硬件使用的CModel可执行文件是 hevc_enchevc_dec ,分别用于Video编码和解码。
  • STITCH和PYRAMID硬件采用仿真库。

环境说明

编译环境

UCP仿真使用Docker镜像自带的编译器环境即可。

运行环境

  1. 使用DSP硬件进行仿真时,需要配置Xtensa开发环境并指定DSP仿真镜像路径。 环境配置方法可参考 DSP工具链安装 。指定DSP仿真镜像路径可以通过设置环境变量 HB_DSP_CMODEL_IMAGE,以确保应用程序能够找到正确的仿真镜像文件。 参考命令如下:
# 定义DSP镜像路径 export HB_DSP_CMODEL_IMAGE=../x86/bin/image/vdsp0
  1. 运行CModel可执行文件时,需要将可执行文件路径添加到PATH环境变量中,以便在终端可直接运行,参考命令如下:
# 定义CModel可执行文件路径 root=../x86/bin/ # 设置可执行文件搜索路径 export PATH=${root}:${PATH}
  1. 其余硬件仿真运行时不需要进行额外的配置。

性能说明

但x86仿真环境下的性能通常会低于实际硬件的性能,主要原因如下: 前文我们提到,目前UCP支持的各Backend使用的仿真方式包括指令级仿真、CModel可执行文件仿真以及使用仿真库。

  • 指令级仿真:指令级仿真方式需要逐条指令进行模拟和执行,从而导致较高的计算开销和较低的仿真速度。
  • CModel 可执行文件仿真:CModel 可执行文件通过读写文件进行输入输出操作,而文件 I/O 操作较为耗时,在一定程度上会对仿真速度有所影响。
  • 仿真库:仿真库运行在 CPU 上,CPU 模拟硬件加速器的行为,但 CPU 的架构和设计并不专门针对这些任务,因此运行效率较低。 尽管仿真环境下的性能通常低于实际硬件的性能,但仿真环境提供了完整的API支持和精确的功能验证,能够极大地提高您的开发效率和代码质量,有助于您在早期阶段发现并解决潜在的问题。