昇腾学院 | Atlas性能调优之内存管理
作者:熊文博
前面三节课,我们分享了Atlas性能调优之瓶颈分析、流程编排以及编解码的内容,今天,我们将为大家带来Atlas性能调优之内存管理的分享!
跨侧传输
数据的跨侧传输,需要将数据类型序列化之后,再整体发送到对侧,对侧接收到数据后,进行反序列化得出原有数据。
Matrix框架中,数据跨侧传输有普通通道和高速通道两种方式。对于小于256KB的数据,建议使用普通通道,而对于大于等于256KB的数据,建议使用高速通道。
注意:定于数据结构时,对于需要跨侧传输的buffer,请使用智能指针。
普通通道
Matrix的普通通道使用的cereal开源库,用户只需要简单的在数据结构下定义下序列化函数,再使用HIAI_REGISTER_DATA_TYPE注册下该数据结构即可。
使用new申请完内存buffer后,需使用智能指针指向该buffer,指定内存自动释放方法为delete。如以下代码所示:
uint8_t* buffer = newuint8_t[bufferSize];
transData->buf.reset(buffer, [](uint8_t* p) { delete[] p; });
高速通道
高速通道走的是DMA搬运,基本上可以达到PCIE通道的理论极限值。高速通道的实现比普通通道略复杂点,需要实现自定义的序列化函数(GetSerializeFunc)和反序列化函数(GetDeserializeFunc),再使用HIAI_REGISTER_SERIALIZE_FUNC注册该数据结构和对应的序列化反序列化方法。
高速通道可使用HIAI_DMalloc来申请内存,注意对于跨侧传输的数据,HIAI_DMalloc申请的内存会自动释放掉,设置释放方法为空,如以下代码
uint8_t* buffer;
hiai::HIAIMemory::HIAI_DMalloc(bufferSize, (void*&)buffer, 10000);
transData->buf.reset(buffer, [](uint8_t* p){});
Device 侧内存管理
内存消耗
昇腾310处理器侧总共有8G内存,由于310处理器是一颗SOC处理器,片上系统大概占用0.5G左右内存,所以可用内存总共有7.5G左右。其中包含1.9G左右的大页内存。大页内存是提前预留好的,所以没有程序运行时,使用npu-smi info看到已经使用的内存为2.4G左右,其实只有系统占用了0.5G,1.9G的大页内存还可以使用。
处理器侧资源有限,我们来看下有哪些优化点可以节省内存的消耗。
1、DVPP
昇腾310处理器上面包含了多个硬件模块,其中DVPP比较特殊,原本是一个32位的硬件编解码模块,其中大部分所以需要使用的内存必须在4G空间内。该范围的内存可以使用HIAI_DVPP_DMalloc来申请,HIAI_DVPP_DMalloc接口会优先申请之前预留好的大页内存(2M),大页内存申请完之后,会申请普通内存。注意,申请的内存buffer需要使用HIAI_DVPP_DFree来释放。
由于有这个限制在,而编解码又是内存消耗大户,在某些压力场景下,会出现4G空间用完的情况,有以下优化方案。
VDEC的输入不要求在4G空间内,而VDEC的输入一般是跨侧传输过来的,只需要设置VDEC Engine对应的connects的receivememorywithout_dvpp为1就可以保证搬运来的数据不在4G空间内。
如果是一次编解码操作需要申请多个小块4G空间内存,建议申请一块大内存,通过地址偏移完成。 例如,VPC抠图,如果一张图里面扣10个人脸小图,如果每一个输出都单独申请内存,比如小图一张100KB,如果是大页内存,对齐后为2MB占,这样总共占用2*10=20MB,但是如果一次性申请一块2M内存,地址偏移就可以满足了,这样便可以节约了18MB内存。
2、模型
模型是另外一个内存消耗点,模型占用内存固定,可以通过omg工具,使用以下命令生成json文件
omg --mode=1 --om=XXX.om --json=xxx.json
查看生成的json文件,获取memorysize和weightsize值。那么整个模型的消耗大约为memorysize/1024/1024 + weightsize/1024/1024 + (30MB~60MB),括号中的内存消耗,和batch数有关,单batch大约为30MB左右,8batch为60MB左右。
另外,对于推理业务,建议只使用一个Graph,否则多个Graph,每个都加载一遍模型会占用大量内存的。
3、框架
前面文章说过,Engine队列长度,默认值200,上一个Engine发送过来的数据,都会存储在这个队列中。当Engine处理不及时,就会造成数据堆积,一个解码后的图片2M,队列堆满便会总共消耗400M内存。因此业务开发中,需要考虑这种情况,调整适当的队列大小,当出现异常情况导致的队列堆积时,不会把Device侧内存消耗光。
内存拷贝
Matrix框架提供了HIAI_DMalloc / HIAI_DFree 和 HIAI_DVPP_DMalloc / HIAI_DVPP_DFree这两对内存接口。HIAI_DMalloc是用于跨侧传输的,HIAI_DVPP_DMalloc是用于申请DVPP的4G空间的内存的。使用不同接口申请的内存,不需要显示的进行拷贝,可以直接使用,主要点如下:
1、通过HIAI_DMalloc接口申请的内存,作为图像/视频编解码的输入使用,无需进行数据拷贝。
2、HIAI_DVPP_DMalloc接口申请的内存,内存地址满足DVPP的输入/输出要求,可直接作为图像/视频输出的使用。调用HIAI_DVPP_DMalloc接口申请内存后,HIAI_DVPP_DFree接口释放内存。在DVPP内部,VPC模块的输入可直接复用内存中JPEGD模块的输出数据。
3、通过HIAI_DVPP_DMalloc接口申请的内存,可直接作为模型推理首层的输入,无需进行数据拷贝。
- 点赞
- 收藏
- 关注作者
评论(0)