OE Agent“天工”新版本发布,请前往论坛顶部查看,欢迎试用并反馈~
查看OE-Skills
专栏算法工具链【地平线J6工具链入门教程】板端部署UCP使用指南-v1.3

【地平线J6工具链入门教程】板端部署UCP使用指南-v1.3

芯链情报局2025-10-26
721
0

文档版本

修订内容

修订时间

v1.3

新增第10章-UCP中继续模式使用

2026/07/07

v1.2

新增第9章-UCP环境变量详解

2026/06/23

v1.1

新增3.2.5节-LRU内存优化

2026/06/22

v1.0

初始版本

2025/10/26

1. 前言

在模型板端部署过程中,开发者主要关心图像如何获取,模型性能如何评测以及如何优化模型等问题。对于图像的获取,地平线提供了Pyramid硬件,其不但可以获取多尺寸图像,且利用内存共享机制可将内存给到BPU直接进行推理。针对耗时,内存占用,DDR带宽占用等指标进行评测和优化,地平线提供了诸如Trace,hrt_ucp_monitor等一系列性能分析工具用于性能监测,使得开发者能够清晰掌握模型运行时的资源占用和硬件效率。最后,地平线提供VP,HPL以及DSP多种模块用于前后处理环节的算法开发。本文将结合实例说明模型如何进行部署,性能分析以及常见的问题解析。

2. UCP简介

J6 工具链在应用部署端新引入了统一计算平台(Unify Compute Platform,以下简称 UCP)。UCP 面向应用层,属于嵌入式应用开发(runtime)范畴,提供视觉处理(Vision Process,以下简称 VP)、模型推理(Neural Network,以下简称 NN)、高性能计算库(High Performance Library,以下简称 HPL)等功能。
UCP还定义了一套统一的异构编程接口,支持对SoC上各后端硬件资源的调用,包括BPU、DSP、ISP、GDC、STITCH、JPU、VPU、PYRAMID 等,以完成 SoC 上任务的统一调度。
UCP 的架构图如下所示:
Description

backend

描述

BPU

Brain Process Unit,地平线神经网络计算单元。

DSP

Digital Signal Processor,数字信号处理器,是一个可编程的硬件单元。

GDC

Geometric Distortion Correction,几何畸变校正模块,可对输入图像进行视角变换、畸变矫正、图像仿射变换等操作。

STITCH

stitch,图像拼接模块,可对输入的图像进行裁剪,拼接,拼接模式分别有:alpha融合、alpha beta融合、直接拷贝。 J6B 上没有此器件。

JPU

JPEG Processing Unit,主要用以完成JPEG的编解码功能。

VPU

Video Processing Unit,是一种专用的视觉处理单元。

PYRAMID

Image Pyramid,图像金字塔,可对整幅原始图像进行缩小。

ISP

Image Signal Processor,图像信号处理模块,可以将富含图像原始信息的RAW格式转换为易于传输处理的YUV格式。

3. 模型推理

3.1 快速上手

以下面的代码为例,说明 DNN 和 UCP 接口的使用方式,整体包含 5 个主要步骤,详细信息可参考用户手册《统一计算平台-模型推理开发》,《模型部署实践指导-模型部署实践指导实例》,《UCP通用API介绍》等相关章节:
Description

⚠️上面的例子仅为demo,实际使用时,需要注意以下几点:

  1. 图像可以直接从Pyramid接口直接获取nv12的输出,无需进行拷贝,可直接传递给BPU进行推理

  2. 输入输出内存的大小和对齐stride,详见第5.3节说明

  3. 接口进行返回值检查,以保证函数的正确执行

3.2 实用技巧

3.2.1 添加desc

有的时候,为了方便自动化作业,需要给不同的模型,输入和输出打上标签以区分他们。

需要注意的是,如果是为输入添加描述信息,由于pyramid和resizer节点会改变bc的输入节点数,因此需要给对应每个节点都添加对应的信息。

比较推荐的做法是在compile之前再添加:

模型部署时,通过下面的接口来获取描述信息:

3.2.2 模型打包

模型打包功能,可以将多个模型打包进一个hbm文件中,对于共享任务可以节省模型的空间,具体api介绍可见《HBDK Tool API Reference》:
在生成hbm文件后,上板运行使用hrt_model_exec查看模型可以看到:
Description
推理测试时,用model_file指定hbm路径,model_name指定具体哪一个模型
Description

3.2.3 小模型批处理

由于BPU为资源独占型硬件,对于那些耗时较短的小模型,其框架调度耗时开销可能大于其模型运行时间,为了缓解这个问题。在J6平台,UCP支持通过复用task_handle方式来一次将多个模型下发,全部执行完成后再一次性返回,从而将N次开销合并为一次:

3.2.4 优先级抢占

在J6计算平台上,BPU硬件本身没有抢占功能,对于一个计算任务其一旦进入BPU后,就无法被打断,其他计算任务只能等待当前计算任务完成退出后才能运行。
此时很容易出现BPU计算资源被一个大模型任务独占,进而影响其他高优先级模型任务的执行,针对这个问题,工具链采用cpu调度的机制来优化BPU资源:
  1. hbm模型在BPU推理表现为一个或多个function-call,function-call为BPU最小的执行单元。当一个模型的所有function-call都执行完成时,这个模型也就执行完成了

  2. BPU模型任务抢占粒度设计为function-all,如果一个模型只有一个function-call那么其无法被抢占,如果一个模型有多个function-call可能出现这个模型完成部分function-call后,BPU挂起当前模型,然后切换执行其他模型

UCP支持任务优先级调度和抢占,可通过hbUCPSchedParam结构体进行配置:

  • priority:任务优先级,支持[0, 255]之间的数值,对于模型任务而言:

    • [0, 253]普通优先级,不可抢占其他任务,但在未执行时支持按优先级进行排队

    • 254:为high优先级,支持抢占普通任务

    • 255:为urgent优先级,支持抢占普通任务和high任务

    • 可被中断抢占的任务,需要在模型编译阶段配置max_time_per_fc进行模型拆分

  • customId:自定义优先级

  • backend:任务硬件id

  • deviceId:设备ID
    比如,有下面的两个模型,一个单线程耗时20.9 ms,一个单线程耗时8.3ms:
Description
Description
让这两个模型同时运行,且设置max_time_per_fc=2000,两个模型的优先级均为普通优先级时UCP trace耗时如下:
Description
当将模型2的优先级设为high,模型1仍为普通优先级时:
Description
可以看到,在下面的模型一次infer过程中,模型被切分为多个2ms运行的function-call运行,中间插入了很多high优先级模型,导致一次模型前向耗时大大增加。

3.2.5 LRU内存优化

3.2.5.1 什么是LRU
LRU全称Least Recently Used,即最近最少使用,属于典型的内存管理算法。它的思想是当缓存满时,会优先淘汰那些最近最少使用的缓存对象,有效的避免了OOM的出现。
在UCP中也存在着近似于OS LRU的功能, 主要用于优化BPU内存的map/umap操作的缓存策略。在使用BPU的内存时,NN模块需要对该块内存进行映射处理map操作才能被BPU正常使用,在使用后需要unmap。如果频繁对模型输入输出内存执行map/unmap,会导致cpu负载变大。LRU主要是通过缓存已map的内存块,减少虚拟内存重复map/unmap的操作,从而降低cpu开销。提升推理性能。
3.2.5.2 使用说明
  1. HB_NN_ENABLE_MEM_LRU_CACHE:设置NN模块是否使用内存LRU缓存,true为使用,默认为false不使用

    判断是否开启LRU内存可以通过配置NN模型环境变量HB_NN_LOG_LEVEL=1来确认。
    alt text
  2. HB_NN_MEM_LRU_CACHE_CLEAN_INTERVAL:置NN模块清理LRU缓存的时间间隔,单位为毫秒,默认为1000ms及1s之后再释放

    推荐使用场景:模型输入输出内存被频繁使用的场景(如连续推理、多帧处理);频繁申请/释放BPU内存导致CPU负载过高的场景。
    不推荐使用的场景:模型输入输出内存仅使用一次,或使用频率较低的场景。
3.2.5.3 注意事项
  1. LRU缓存功能只适用于BPU推理模块,其他模块没有此功能

  2. 在开启LRU后,内存在调用释放接口后,不会立即释放,因此需要注意,如果频繁释放和申请,可能存在内存泄漏感知风险

  3. LRU功能暂时不支持跨进程

3.3 输入输出处理

3.3.1 Crop裁剪

Crop主要思想是利用地址偏移,并通过stride将图像多余的部分进行屏蔽从而送入准备好的模型输入。这种Crop方式不引入memory copy,减少IO开销。
限制:
  1. 图像输入大小要大于模型实际输入大小,w_stride要32(E/M)/64(P/H)字节对齐

  2. 模型的validShape为固定值,stride为动态值

  3. 裁剪偏移的输入首地址要32对齐

详细示例可以参考《基础示例包使用说明》中advanced_samples 的crop示例

3.3.2 Resizer

Resizer主要是指具有nv12图像输入和ROI输入的模型,编译器支持通过JIT动态指令的方式,从nv12图像上完成抠图+Resize功能。其不仅仅是图像stride为动态,输入的H,W也为动态,w_stride也同样需要满足32(E/M)/64(P/H)字节对齐,roi不需要进行对齐:
Description

3.3.3 图像tensor对齐

在J6芯片,有一块叫Pyramid的金字塔硬件处理模块,可提供Camera输入图像的缩放及ROI抠图能力,其输出为nv12类型的图像数据,并可基于共享内存机制直接给到BPU进行模型推理,因此在J6工具链中:

  • Pyramid模型是指具有nv12图像输入的模型

  • Resizer模型指的是具有nv12图像输入和ROI输入的模型,编译器支持通过JIT动态指令的方式,从nv12图像上完成ROI抠图+Resize功能
    J6P/H要求nv12 stride满足64对齐,J6E/M/B是32对齐。
    Pyramid的输入stride为动态,比如模型输入为224x224的nv12图像,其格式为:
Description
Description

其中,-1为占位符,表示为动态,Pyramid输入的stride为动态。那么此时我们就需要通过手动计算方式来获取了:

对于非nv12类型的其他输入,以rgb输入input作为例子,1x224x224x3的rgb图像如下所示:

输入申请的大小可以通过aligned byte size来获取:

3.3.4 内存单元对齐

BPU中的内存单元也是遵循向量化对齐的原则,类似于avx/neon等,需要内存对齐。所以对于不满足对齐最小字节的内存要被强制对齐到最小的内存字节上。
J6H/P tensor最小申请内存是256字节,J6E/M是64字节,J6B是128字节,这个差异会体现在模型的aligned byte size和stride属性上。
举个例子:

上面模型的stride=4000,output需要申请的内存为4000Byte,但由于内存需要对齐,所以实际上的需要申请的内存大小为((4000+(256-1))&~(256-1))=4096Byte。
在模型实际部署中,非图像输入/输出节点所需申请的内存大小均可以从模型节点属性的结构体中读取到,因此无需特别关注:

3.3.5 padding

由于内存单元对齐的影响,feature申请的大小和拷贝需要根据stride和alignedByteSize来进行。用户侧需要手动处理这些padding,可能对前处理和后处理的代码有较大的变动。这里地平线提供了一种优化方案:input_no_padding/ouput_no_padding,在开启这两个选项后,可以直接将输入/出实际大小的内存送入接口,接口内部会自行处理对齐,无需用户侧修改代码。但开启这个参数后,可能会对模型延时产生微小影响。

  • input_no_padding:对所有非图像的输入去padding
  • output_no_padding:对模型所有的输出去padding
    若编译时配置了input_no_padding=True,output_no_padding=True,无需关注非图像的对齐问题:

举个例子,比如一个模型的输出shape为1x21x21x255,其output_no_padding=False和output_no_padding=True的结果如下图所示:

Description
Description

4. 性能分析

4.1 模型性能分析

如果开发者没有实体板子,只有hbm模型,可以使用hbdk4中的hbm_perf接口获取静态性能评估文件(html,json格式)以及模型耗时:

模型中如果有CPU算子,则会影响perf的结果,建议去除CPU算子之后再进行分析。CPU算子一般可以通过以下两种方式查看到:

  1. convert之后的模型可视化,然后查询是否有hbtl类型算子

  2. 利用statistics接口统计bc模型算子类型

如果有与开发环境直连的板子可以使用下面的方式进行测试,与实测偏差会更小:

或按照用户手册《统一计算平台-模型推理工具介绍》使用hrt_model_exec工具在板端进行性能测试:

4.1.1 带宽占用

静态评测时,带宽信息可以从模型编译过程中生成的xxx.html/xxx.json中文件获取,在ptq中会自动生成这两个文件,在qat中,可以通过生成hbm模型后,使用hbm_perf接口来生成这两个文件。
平均带宽
平均带宽(GB/s) = DDR bytes per second( for n FPS)/n * 设计帧率/2^30,以下面的模型为例,实际需求帧率为30FPS,那么该模型所需的平均带宽为:12293553099/57.12 * 30/2^30 = 6.01GB/s:
Description
Description
峰值带宽
峰值带宽可以通过推理带宽柱状图来进行分析,最高的柱子即最大的load/strore带宽。比如下面这个图,该模型的最大load需求为15515MB/s=15.15GB/s,最大的store需求为13125MB/s=12.82GB/s,最大的load+store需求为11954+11812=23766MB/s=23.21GB/s
Description

4.1.2 带宽优化

在实际应用中,模型的推理耗时可能出现比正常评测要更长的现象,主要原因往往来源于BPU的等待耗时以及带宽资源不足的影响。这里主要针对带宽问题进行说明。
BPU模型的带宽消耗主要集中在模型加载、推理时的featuremap读写,输出写回,优化策略如下:
  1. 使用balance参数来平衡带宽和延时

    ptq时,修改配置文件中的compile_mode:

  2. 对于小模型使用多batch推理模式,可以减少weight的加载次数

  3. 减少模型抢占调用:优先级255的抢占任务会刷新整个SRAM,导致大量带宽开销,建议通过任务编排方式运行模型,而不是优先级抢占

  4. Batch拆分:若模型需要concat多路输入(比如BEV类模型),将batch mode拆分,每一路单独提取特征,牺牲很少的延时来降低峰值带宽

4.1.3 内存占用

模型所需的内存可以通过Summary查看到:

含义

Model input memory

模型输入内存

Model output memory

模型输出内存

Shared temporary memory

运行时内存

Intermediate memory

运行时内存

Dynamic memory

前面的相加

Static memory

hbm文件大小

Shared temporary memory共享临时内存,主要目的是用于相同优先级模型共享内存,优化模型推理内存的使用。对于相同优先级的模型,会共享temporary memory。该功能的约束条件:

  1. 跨BPU Core不可用

  2. 跨优先级不可用,0-253的优先级之间的都可以共享,254只能和其他254共享,255只能与其他255共享

  3. 跨进程不可用

当开发人员对模型运行时所需内存进行评测时,可先通过Summary的内容先进行静态数据评估,模型的内存占用=Static Memory + Dynamic Memory。

4.2 动态性能分析

在模型的部署和运行过程中,我们比较关注模型的推理耗时,bpu/cpu占用,DDR读写带宽以及内存占用。这些信息可以通过以下工具来获取:

4.2.1 hrt_model_exec

hrt_model_exec是一个模型执行工具,可直接用于在开发板上评测模型的推理性能,获取模型信息。工具源码路径在samples/ucp_tutorial/tools/hrt_model_exec。
模型输入输出信息:
Description
模型单线程耗时:
Description
模型多线程耗时:
Description
指定优先级运行:
更多的hrt_model_exec命令可以在《统一计算平台-模型推理工具介绍-hrt_model_exec》中查看。
4.2.1.1 单线程和多线程差异
在单线程下,工具按照单核单线程的串行逻辑运行,统计的性能可以理解为单帧处理的平均时间(包括调度开销,BPU执行时间以及CPU执行时间)。
在多线程下,工具会启动多个线程进行模型推理,统计得到的FPS表示充分使用资源情况下模型的吞吐量,主要用于评测高并发情况下的模型处理能力。
  • 为什么单线程模型运行耗时比多线程耗时短?
    答:由于BPU本身是一种独占硬件,同一时间只能运行一个任务,多个线程同时提交任务时,只能按一定顺序执行,因此多线程模式下,模型的Latency耗时的增大,主要来源于任务下发后的等待时间。

4.2.2 hrt_ucp_monitor

工具hrt_ucp_monitor是一个关于监控硬件IP占用率和内存信息的工具。hrt_ucp_monitor工具位于samples/ucp_tutorial/tools中。
hrt_ucp_moitor支持的内存信息包括DDR读写带宽,ION内存,进程内存,默认为每秒采样 500 次,详细的运行参数请参考《hrt_ucp_monitor 工具》。
hrt_ucp_monitor 是一个监控硬件 IP 占用率和内存信息的工具,在使用UCP提交任务时,可以指定任务部署的后端(Backend),这些后端与本文档中的硬件IP相对应。 hrt_ucp_monitor 工具位于 horizon_j6_open_explorer 发布物的以下路径中: Linux 系统:samples/ucp_tutorial/toolsQNX 系统:samples/uc
。在终端运行命令hrt_ucp_monitor即可看到对应的监控信息:

rss查看可以通过以下命令查看:

Description
Description
HBMEM为应用进程申请的总ION大小:
ION:ION是为了解决内存碎片化而引入的通用内存管理器,一共有三种:ion(上面的ion_cam),reserve(上面的cma_reserved)和carveout(上面的carveout)。ion是主要类型,用于一般的内存分配。reserve本质上也是carveout,区分的主要目的是DDR支持多个bank。对于BPU模型来说,其优先在carveout上分配内存。可以通过观察 /sys/kernel/debug/ion/heaps/carveout来测试内存占用:
Description
上图为未加载时,carveout的状态
Description
模型加载后,carveout的状态

4.2.3 hrut_ddr

带宽占用主要使用hrut_ddr来进行分析:

根据hrut_ddr工具的log,获取BPU带宽占用和系统带宽占用,Read+Write的值即为总带宽:
Description

4.3 问题

在实际的运行中,可能会出现与上面带宽评测结果差距较大的情况。这是由于在实际中不仅仅是模型的运行需要带宽,cam和cpu也是需要带宽的。根据过往的经验,可以根据峰值带宽和均值带宽来提前判断是否存在风险,高于理论带宽的75%以上,就需要进行测试验证了。

5. 推理典型问题处理

5.1 timeout问题

5.1.1 模型timeout时间是否设置合理

如果模型是异步推理的,模型本身执行的时间较长,而异步等待接口设置的超时时间不足也可能造成timeout。

timeout的耗时可以设置为模型正常推理时间的一倍即可。

5.1.2 CPU负载是否过高

由于模型的运行调度是由CPU来处理的,如果调度线程一直获取不到时间片,即使任务完成也无法及时同步到用户接口,导致推理延时。
在运行过程中,可以使用top/htop等监视CPU利用率,如果CPU负载超过90%,可能出现系统异常,这个必须得到解决

5.1.3 内存泄漏

当存在内存泄漏时,在系统内存不足的情况下,内存申请缓慢,可能会导致推理超时。可以在编译时添加检测:

或在单元测试时,利用getpid()获取当前进程的pid,再查看/proc/pid/status中的VmRSS。

5.2 推理hang

模型指令原因导致的底层运行错误,错误没有上报,导致hang住。此时,可通过cat/sys/devices/system/bpu/bpu0/task_running对bpu任务情况进行查看,如下图所示:
Description
s_time不为空表示任务已经正常开始,而p_time一直增加没有减少,即可认为BPU任务hang住了, 可以使用watch命令来记录bpu任务情况:

如果发生此类问题,可以提供bpu log给地平线技术支持人员分析,log的地址在:/log/bpux/message 中。

5.3 log获取

在遇到上面的问题的时候,我们可以通过分析日志来获取问题原因,需要的是UCP日志以及系统日志:

5.3.1 UCP日志

在程序运行时可以看到各种log的等级:
Description
在发生上面的问题后,为了获取具体的问题原因,可以修改log等级来抓取不同等级的日志,配置方式如下:
UCP log设置主要通过以下环境变量:
  • HB_UCP_LOG_LEVEL:ucp模块log等级(等级从0到6,分别为trace, debug, info, warn, error, critical, never, 默认为warn)

  • HB_NN_LOG_LEVEL:nn模块log等级

  • HB_UCP_LOG_PATH: ucp日志存储路径

更详细的环境变量和说明可以参考《统一计算平台-UCP通用API介绍-环境变量

5.3.2 系统日志

系统日志获取:
dmesg:在Linux系统中用于显示或控制内核环形缓冲区的内容更,允许查看或操作内核消息。

logcat:可以用于打印设备的系统日志

6. UCP Trace使用

J6算法工具链提供了一套板端实测性能工具UCP Trace,通过在UCP执行的关键路径上嵌入trace记录,进而深入分析UCP应用调度逻辑,具体可以参考《UCP Trace 使用说明》一节。
UCP Tracer记录点:UCP记录点包括任务trace记录点和算子trace记录点

trace类型

名称

说明

算子

SubmitOp

算子提交

OpInfer

算子开始执行

OpFinish

算子执行结束

任务

hbDNNInfer

创建模型推理任务

hbDNNRoiInfer

创建ROI模型推理任务

hbVPxxx

创建视觉处理任务

hbHPLxxx

创建高性能计算任务

hbUCPSubmitTask

任务提交

${TaskType}:Wait

等待任务执行结束

TaskSetDone

通知任务执行完成

hbUCPReleaseTask

任务释放

6.1 in_process模式

6.1.1 运行实例

in_process模式下只能抓取UCP进程内的trace,无需启动prefetto的后台进程
启动步骤:
  • ucp_in_process.json

  • ucp_in_process.cfg

在该目录下会生成trace文件:文件名为output_path中配置的文件名:

Description
1.Perfetto不支持自动覆盖,如果设置路径中有之前的ptrace文件会报错
Description
2.ucp_in_process.json中指定的文件路径是相对路径,需要配置文件和脚本放在同一个路径下

6.1.2 结果解析

生成的ucp.pftrace就是我们要分析的文件,使用Perfetto UI打开:

选择生成的ucp.pftrace文件,选中一个带有forward::Wait字样的一块,如下图所示:

Description
可以看到等待部分耗时大约为80.xms,也可以看到线程和进程的信息(Wait部分)
Description
  • 单线程+多帧

Description
  • 多线程+多帧

Description
如何分析:
  1. 查看UCP内部调度是否正常例如哪块耗时明显高于预期

  2. 观察BPU是否持续在使用:例如两个BPU Opfinish之间的耗时是否符合预期,继而判断任务编排是否合理,任务下发是否及时

  • 多线程+多帧+CPU结果

Description

6.2 system模式

在system模式下,UCP trace只是其中一个数据源,因此需要运行Perfetto的后台进程来完成trace捕获。

  1. 运行Perfetto后台进程

    请注意,为了能够获取完整的数据,需要确保hrt_model_exec执行结束前,perfetto进程未退出。可以适当增加ucp_system.cfg中的duration_ms,当前默认为10000ms

  2. 开启一个新终端,设置环境变量和运行程序

  3. 运行程序,比如运行hrt_model_exec命令,并将获取到的ucp.pftrace解析:
    Description

7. 视觉处理/高性能算子

UCP提供了视觉处理和高性能算子两大方向的多种接口:

  1. 视觉处理主要针对视频编/解码,光流,AVM拼接等常规视觉算法

  2. 高性能算子依赖于DSP的实现,主要用于fft和ifft的加速
    更多信息可以参考用户手册《统一计算平台》的相关章节。

8. DSP使用

J6的dsp使用了Cadence的Tensilica Vision Q8 DSP IP(J6B为 Vision 130)。支持int8/int16/int32/float32/double的浮点计算。
当前DSP可以用于加速模型前后处理比如点云体素化,模型量化反量化等操作,模型中间的算子加速暂不支持。更详细的说明,请参照《DSP算子开发》章节。
完整的算子开发分为三个步骤:
  1. DSP算子开发

  2. 注册算子,编译镜像

  3. 通过UCP API调用,申请计算资源并执行任务

9. UCP环境变量详解

9.1 环境变量配置说明

UCP中的环境变量分为下表中的几大类:

名称

环境变量名称

功能

日志等级配置

HB_XXX_LOG_LEVEL

设置ucp日志等级,XXX为对应模块

后端硬件配置

HB_UCP_ENABLE_XXX_BACKEND_CORE_NUM

设置启用后端硬件的数量,XXX为对应硬件

HB_NN_ENABLE_MEM_LRU_CACHE

设置模型推理是否使用LRU缓存

HB_DNN_USER_DEFINED_L2M_SIZES

设置开启L2缓存时每个bpu核心L2M的大小

线程管理配置

HB_UCP_SCHEDULE_PRIORITY

设置ucp调度任务的优先级

HB_UCP_CPU_PROCESS_THREAD_PRIORITY

设置模型中cpu算子处理的优先级

任务管理配置

HB_UCP_MAX_TASK_NUM

设置VP、HPL、NN各模块允许启用最大任务数量

仿真平台配置

HB_UCP_SIM_PLATFORM_TYPE

设置在x86上推理HBM文件的目标平台

UCP环境变量可以参考OE文档的环境变量章节。

9.2 环境变量配置说明

9.2.1 UCP模块日志配置

在UCP库中,log等级一共分为7个等级0-6,分别对应trace、debug、info、warn、error、critical、never,默认等级为warn对应log等级为3:
alt text
  • HB_UCP_LOG_LEVEL:用于设置ucp模块的日志级别
  • HB_VP_LOG_LEVEL:用于设置vp模块视觉处理的日志级别
  • HB_HPL_LOG_LEVEL:用于设置HPL高性能算子模块的日志级别
  • HB_NN_LOG_LEVEL:用于设置NN模型推理模块的日志级别
  • HB_UCP_LOG_PATH:设置日志存储路径,支持滚动切分
  • HB_UCP_LOG_MAX_SIZE:滚动切分时文件大小,单位MB,默认为1024
  • HB_UCP_LOG_ROTATE_NUM:滚动切分时的文件数量,默认为16

9.2.1 UCP模块日志配置

在程序运行过程中,如果使用了DSP,为了在ARM侧能够获取dsp模块的日志,ucp提供了以下环境变量用于获取日志,更详细的说明请见OE文档对应章节
  • HB_DSP_ENABLE_CONFIG_VDSP:配置DSP侧日志及日志写入ARM侧显示,默认为false,这个变量会决定HB_DSP_WRITE_VDSP_LOG_TO_ARM和HB_DSP_VDSP_LOG_LEVEL是否会被下发到dsp侧
  • HB_DSP_WRITE_VDSP_LOG_TO_ARM:设置DSP侧日志ARM侧显示,默认为false,配置为true后,arm侧能够通过日志查看到dsp的运行日志
  • HB_DSP_LOG_LEVEL:UCP的dsp模块arm侧日志等级,一共7个等级,分别对应Verbose、Debug、Info、Warning、Error、Critical、Never,默认为Warning等级3
  • HB_DSP_VDSP_LOG_LEVEL:UCP的dsp模块dsp侧日志等级,一共5个等级,分别对应为Debug、Info、Warning、Error、Always等级,默认为Warning等级3

dsp侧日志输出配置示例:

9.3 UCP模块日志配置

9.3.1 后端硬件启用配置

在程序运行的时候,默认会启动所有的后端,对于那些对资源要求比较严格的情况,每启动一个器件的线程,就代表浪费了一部分资源,因此,我们可以利用如下环境变量,对不使用的器件进行关闭:

  • HB_UCP_ALL_BACKENDS_DEFAULT_DISABLE:禁用所有后端,值非0则禁用,默认值为0,表示打开所有后端
  • HB_UCP_ENABLE_GDC_BACKEND_CORE_NUM:设置GDC可支持的核数,默认当前计算平台可支持的最大核数(B/E/M上为1个,P上为2个),0表示关闭GDC
  • HB_UCP_ENABLE_STITCH_BACKEND_CORE_NUM:设置STITCH可支持的核数 , 默认当前计算平台可支持的最大核数(E/M/P上均为1个),0表示关闭STITCH
  • HB_UCP_ENABLE_JPU_BACKEND_CORE_NUM:设置JPU可支持的核数,默认当前计算平台可支持的最大核数(E/M上为1个,P上为3个),0表示关闭JPU
  • HB_UCP_ENABLE_VPU_BACKEND_CORE_NUM:设置VPU(Video Process Unit,非BPU中的VPU)可支持的核数,默认当前计算平台可支持的最大核数B/E/M上为1个,P上为3个,0表示关闭VPU
  • HB_UCP_ENABLE_DSP_BACKEND_CORE_NUM:设置DSP可支持的核数,默认当前计算平台可支持的最大核数(B/E/M上为1个,P上为2个),0表示关闭DSP
  • HB_UCP_ENABLE_BPU_BACKEND_CORE_NUM:设置BPU可支持的核数,默认当前计算平台可支持的最大核数(B/E/M上为1个,P上为4个),0表示关闭BPU
  • HB_UCP_ENABLE_PYM_BACKEND_CORE_NUM:设置PYM可支持的核数,默认当前计算平台可支持的最大核数(B上为2个,E/M上为3个,P上为5个),0表示关闭PYM
  • HB_UCP_ENABLE_ISP_BACKEND_CORE_NUM:设置ISP可支持的核数,默认当前计算平台可支持的最大核数(B/E/M上为1个,P上为4个),0表示关闭ISP
  • HB_UCP_ENABLE_CPU_BACKEND_CORE_NUM:设置CPU推理算子的线程数,默认线程数为6,0表示关闭
推荐做法为先全局关闭所有后端,然后针对当前的代码配置所需要的打开的后端以达到节省资源的目的。
下面以J6M为例,进行简单说明:
在不屏蔽禁用任何后端的情况下,启动程序后,在运行到第一个ucp接口后,可以看到所有线程默认都会启动:
alt text
在开启HB_UCP_ALL_BACKENDS_DEFAULT_DISABLE环境变量后,如果依赖的对应器件没有开启,运行到对应位置就会报错:
alt text
仅开启1个BPU(设置),可以看到多了2个bpu的线程:
alt text
如果在推理模型中有cpu算子,可以使用HB_UCP_ENABLE_CPU_BACKEND_CORE_NUM来进行控制,下图为使用1个bpu+1个cpu线程来运行模型:
alt text

9.3.2 BPU推理环境变量配置

在模型推理过程中,可以配置一些环境变量,用于优化模型推理效率:

  • HB_NN_ENABLE_MEM_LRU_CACHE:设置NN模块是否使用内存LRU缓存,true为使用,默认不使用
  • HB_NN_MEM_LRU_CACHE_CLEAN_INTERVAL:设置NN模块清理LRU缓存的时间间隔,单位为毫秒,默认为1000ms

上述两个变量的原理和具体使用方法请参考LRU章节。

  • HB_DNN_USER_DEFINED_L2M_SIZES:用于设置每个BPU核心的L2 Memory大小,让模型推理时使用片上L2 Cache作为临时存储,减少DDR访问带宽,提升推理性能,配置格式如下:
  1. 各core Size以:分隔,单位为MB,仅支持整数
  2. core数量与平台的BPU数量相对应,P为4个,H为3个

  3. corexsize为0时,表示该bpu不配置L2M

模型需要编译时启用L2M才能在运行时利用L2 Cache。编译参数max_l2m_size用于控制模型可用的L2大小:

或者PTQ链路的yaml中进行配置:

设置的L2M内存大小不能超过板端最大可用L2M大小,其可以通过下面的命令来进行查看:

需要注意的一点是:通过HB_DNN_USER_DEFINED_L2M_SIZES给定的L2M大小必须不小于模型编译时给定的max_l2_size,否则推理时会出现L2M不足的报错。
不配置时,默认每个BPU核值均为0。
该变量仅在J6H/P上生效,且启用后不支持优先级抢占推理。

9.4 线程管理设置

线程管理主要用于ucp调度以及模型推理时cpu算子处理的优先级设置:

  • HB_UCP_SCHEDULE_PRIORITY:用于设置UCP线程实时调度优先级,取值范围为0~99,默认为1,设置数值越高,调度的优先级就越高,当优先级设置为0时,线程调度方式会退化为SCHED_OTHER,当优先级设置大于0时,线程的调度方式为SCHED_FIFO(其管理的线程主要有:BPU-LB-Scheduler(bpu任务下发),Codec-Scheduler(编码器后端比如JPU,VPU),Sync-Scheduler(DSP,GDC,PYM等后端)

当设置这个环境变量后,其会设置pthread库中pthread_setschedparam的优先级,pthread_setschedparam接口参数为:

  1. thread:创建的线程

  2. policy:调度策略(SCHIED_OTHER,SCHIED_FIFO,SCHIED_RR)

  3. param:用于设置优先级,即HB_UCP_SCHEDULE_PRIORITY需要设置的值(创建线程时,默认优先级为0)

建议比应用的处理线程优先级高,这个只是调度,不会占用cpu,如果和应用处理线程优先级一样,会影响推理的调度,模型耗时可能会有波动。
以BPU模型推理为例:在调用hbDNNInitializeFromFiles后,每个BPU会创建一个BPU-LB-Scheduler线程,其会根据设置的HB_UCP_SCHEDULE_PRIORITY来设置在BPU负载监控线程在系统OS层面的实时调度优先级,它影响的是BPU-LB-Scheduler线程多快能响应消息并做出调度决策,不会影响BPU实际的推理耗时。在多BPU的平台上,如果配置的后端为HB_UCP_BPU_CORE_ANY提交任务时,该线程会根据各核负载情况,决定将任务分配到哪个BPU核上执行。
  • HB_UCP_CPU_PROCESS_THREAD_PRIORITY:设置模型推理的cpu算子处理线程优先级,取值范围为0~99,默认为0,设置数值越高,计算的优先级也就越高。当优先级设置大于0时,线程的调度方式为SCHED_RR(时间片轮转)
当模型中存在cpu算子时,如果在运行过程中发现cpu部分处理速度较慢,可以通过设置上面的环境变量来进行优化,其对应的线程为:
alt text

9.5 任务管理设置

任务管理环境变量主要用于VP、HPL、NN各自模块允许同时存在的最多任务数量,默认为32,可以通过下面的变量来进行配置:

  • HB_UCP_MAX_TASK_NUM

当程序需要的启用的任务数超过默认设定的任务数量时,就会报出下面的错误:
alt text
这个时候可以通过配置HB_UCP_MAX_TASK_NUM来提升任务数量以满足要求。

9.6 任务管理设置

仿真平台是用于在pc上推理编译生成的HBM文件,默认平台为J6E,如果模拟器配置的版本和编译的版本不相匹配就会报下面的错误:
alt text
可以通过下面的变量进行设置:
  • HB_UCP_SIM_PLATFORM_TYPE:支持如下几个参数: nash-e, nash-m, nash-p, nash-b,nash-h

在pc中可以写入bashrc中 :

10. 中继模式

10.1 中继模式介绍

UCP框架支持两种主要工作模式:直连模式、中继模式。系统默认运行在直连模式下。中继模式是为了方便多进程任务的统一调度而开发的功能,是一种典型的Service/Client模式。通过ucp_service中继服务来进行进程间的任务分发和调度,支持多进程任务的统一调度。

10.2 中继模式使用

中继模式的切换对用户的使用基本无感,接口的调用方式和直连方式一致,不会对应用编程逻辑产生影响。开发时,可基于默认的直连模式完成应用侧的开发和调试,然后切换到中继续模式。
使用中继模式,只需要在运行程序前启动service,其他直连模式一致用法一致。用法如下:
  1. 首先要启动ucp_service,service文件位于oe包的samples/ucp_tutorial/deps_aarch64/ucp/bin/service路径下,并通过设置环境变量HB_UCP_ENABLE_RELAY_MODE=true来启用中继模式
  2. 运行程序

  3. 在任务完成后,使用命令pgrep ucp_service /dev/null killall ucp_service关闭ucp_service
如果想判断是否成功运行在中继模式下,可以将ucp的日志等级切换为debug模式,然后观察日志,出现类似下面的日志即是运行在中继模式下:
alt text

10.3 注意事项

  1. x86仿真平台不支持中继模式,即使设置中继也会被回退到直连模式

  2. 由于中继模式需要进行进程间通信和内存共享,会导致整体的 CPU 负载更高

  3. 模型任务底层资源的竞争都发生于 Service 进程内,相较于直连模式,多个独立进程的竞争强度更高,任务的耗时可能受到影响

  4. ucp_service非正确退出时,会有残留的消息队列文件,需要手动清理(文件为/dev/mqueue/ucp\relay_s.pid和/var/run/ucp_relay_s.lock),否则会影响下次的使用

算法工具链
社区征文官方教程征程6
评论0
0/600