1. 背景

湖海风波任澎湃,一波未平,一波又起,刚处理好CUDA无效设备,又发现Windows 7上视频源断线后,foo通过bar增强图像的功能失效,但Windows 10上正常。

框架

2. 过程

第1天,2022/08/22,周一

  1. 日志中第1个错误发生在D3D9绘制前,foo调用CUDA Driver的cuGraphicsMapResources()去获取CUDA中和D3D9的IDirect3DResource9绑定的显存地址,这样随后把增强图像复制到该地址实现渲染。彻查Map前后的操作没啥发现,试过操作失败仍旧返回成功,使得APP不退出,但结果是图像不再更新,此时软件退出反而提高可用性。
  2. 第2个错误是FFMPEG提示cuvidMapVideoFrame()失败打印CUDA_ERROR_ILLEGAL_ADDRESS: an illegal memory access was encountered
  3. 第3个错误FFMPEG提示cuMemcpy2DAsync()从CUDA解码器中复制显存CUDA_ERROR_ILLEGAL_ADDRESS

第2天,2022/08/23,周二

  1. 由于FFMPEG出错,于是注释掉断线时对ffmpeg的重连操作,又看了下代码,没有有效发现,反而花费许多时间调查由此引发的新现象。
  2. 尝试在Map失败后释放资源、重新分配的“重启”机制,没有效果。
  3. 王德峰老师谈禅宗玄之又玄,身处宇宙万物稳如磐石的关系网,而去洞见宇宙诞生之初物我的关系形态,什么是呢?
  4. 分区注释代码,还是发现在于调用BAR库的API导致顺坏了CUDA,和CUDA无效设备一样。

第3天,2022/08/24,周三

  1. 上午10点,上周五承诺周三结束文档任务,没想到冒出一个新问题,在微信上跟同事说明原委。
  2. 有伙伴提议可否现场升级到Windows10,但是考虑到运维都是半夜进行,没有替代品,万一升级遇到问题又无法回退,就给用户带来太多麻烦,故放弃。
  3. 重读CUDA显存相关代码,有个疑惑点,伙伴建议使用自己的显存空间,可控,于是使用一个变量开关灵活切换自控显存和已有代码中使用的FFMPEG显存,可惜问题照旧。
  4. 既然输入图像没问题,怀疑点就换到输出图像空间的生命周期,读完代码,没有疑惑点无法下手。
  5. 睡觉前想到既然入图像和输出图像都没有非法问题,那就是和调用BAR库API的CUDA上下文有关。
  6. 立秋后北京天气爽快,延庆的夜晚该穿外套了,照例早晚和灰灰铲屎,手爪相握,喵喵喵,摸着大海的手,很快入睡。

第4天,2022/08/25,周四

  1. 调用API前加上push cuda上下文,结束后pop,解决了。
  2. 一点点删除临时代码,反复review每一段分析问题时随手加入的改善代码,避免引入新问题。
  3. BAR库更新API封装cudaGetLastError(),当期内部发现错误返回错误码后,外面再次获取CUDA的详细错误,结果发现第2次调用cudaGetLastError时没有错误了,就改成API直接返回CUDA错误码,外面判断后写日志。
  4. 测试实际环境中2个显卡对应2个进程,通过。

3. 答案

调用BAR库某些API没有提前调用CUDA Driver API中cuCtxPushCurrent(),导致再次“损坏”CUDA环境,同时BAR和FOO没有在第1时间传递故障信息,让FFMPEG和渲染线程再次操作CUDA时才有错误提示,偏离了事故现场,导致排查耗时。

怀疑CUDA Driver和Runtime API的版本和实现不同,导致Windows 10正常,Windows 7失败。下面贴出使用nvidia-smi获取的版本信息:

Windows 7

  • 驱动版本:441.66
  • CUDA版本:10.2

Windows 10

  • 驱动版本:456.71
  • CUDA版本:11.1

CUDA版本差异较大。

4. 重新出发

  1. 既然Windows 10正常,应尽早想到和CUDA版本相关,同时视频源不断线的时候也没事,说明不是cuda渲染和解码的问题,怀疑自己开发的代码,要甚于怀疑她人。
  2. 结合CUDA无效设备,应全部review代码中BAR库和CUDA调用的相关代码,保证CUDA上下文使用正确。

5. 改善点

  1. 应覆盖Windows 7环境的测试。
  2. BAR库第一时间返回故障错误码,立即记录到日志,不让故障蔓延到其他地方,引起迷惑。