ysh329 / OpenCL-101

Learn OpenCL step by step.
123 stars 31 forks source link

【问题排查】GPU内存泄露问题排查思路与解决 #40

Open ysh329 opened 3 years ago

ysh329 commented 3 years ago

背景:在荣耀30Pro手机Mali-G76上,根据adb shell的top命令,观察在同一模型多次run下,会有明显内存增长。排查过程如下:

  1. 用户API侧:加载模型、设置输入、获取输出、predictor执行分别for循环100w次,定位是predictor Run。涉及框架底层;
  2. 排除特殊op:尝试非业务模型、业务模型,均观察到有内存增长的情况。和业务模型的特殊op无关;
  3. 拆分原始模型为小模型:基于构建模型的脚本生成仅有conv、relu的一层小模型,转为部署模型,也存在内存增长情况。可能和io_copy、layout转换有关;
  4. 单元测试:使用conv/act的单元测试,该单元测试不包括io_copy和layout op转换,发现也存在内存增长;
  5. 进入conv实现:分为PrepareForRun、Run、ReInitWhenNeeded,分别放入100w次的for循环内进一步观察定位泄露点,定位到是Run部分,在对Run里的逐行代码分析,逐行放入100w次的for循环内,定位到是command_queue的enqueueNDRangeKernel在多次循环时有明显内存泄露情况;
  6. 观察是否是框架本身引入的问题:command_queue是实体非指针,观察其他框架tnn的调用方式,也是C++ OPENCL API,也存在泄露问题(需要多次运行),进一步观察其他框架(MNN/TFLite/TNN)也均有内存泄露问题;
  7. 确定该问题是gpu驱动bug,即该opencl的enqueueNDRangeKernel方法存在内存泄露。

解决方法:

  1. 尝试升级手机系统,得到解决:升级前OPENCL Driver版本为:OpenCL 2.0 v1.r18p0-01rel0.1e0ebad9d712581fe1bdcd515a8fdf2a,升级后为:OpenCL 2.0 v1.r18p0-01rel0.8e7096aeb046d5aec7d5b43472e6bf72;
  2. 如果无法升级系统,则考虑在用户侧的opencl预判api is_opencl_valid()上,增加黑名单,即在原有的检查so库位置,符号完全性,fp16支持上,增加考虑判断opencl driver版本的检查;
  3. 影响:2的解决方法是在框架层面解决,该问题也可以由业务层逻辑预判检查,与业务层原有的黑名单结合起来。由于该问题是内存泄露,暴露场景只可能是连续跑模型的情况下,造成的结果是内存爆炸,手机重启。对于少次数和非长时应用不会出现,可以忽略跳过,对于长时如视频分割,实时的业务会受到较大影响。