1. 背景
湖海风波任澎湃,一波未平,一波又起,刚处理好CUDA无效设备,又发现Windows 7上视频源断线后,foo通过bar增强图像的功能失效,但Windows 10上正常。
2. 过程
第1天,2022/08/22,周一
- 日志中第1个错误发生在D3D9绘制前,foo调用CUDA Driver的
cuGraphicsMapResources()
去获取CUDA中和D3D9的IDirect3DResource9
绑定的显存地址,这样随后把增强图像复制到该地址实现渲染。彻查Map前后的操作没啥发现,试过操作失败仍旧返回成功,使得APP不退出,但结果是图像不再更新,此时软件退出反而提高可用性。 - 第2个错误是FFMPEG提示
cuvidMapVideoFrame()
失败打印CUDA_ERROR_ILLEGAL_ADDRESS: an illegal memory access was encountered。 - 第3个错误FFMPEG提示
cuMemcpy2DAsync()
从CUDA解码器中复制显存CUDA_ERROR_ILLEGAL_ADDRESS。
第2天,2022/08/23,周二
- 由于FFMPEG出错,于是注释掉断线时对ffmpeg的重连操作,又看了下代码,没有有效发现,反而花费许多时间调查由此引发的新现象。
- 尝试在Map失败后释放资源、重新分配的“重启”机制,没有效果。
- 王德峰老师谈禅宗玄之又玄,身处宇宙万物稳如磐石的关系网,而去洞见宇宙诞生之初物我的关系形态,什么是禅呢?
- 分区注释代码,还是发现在于调用BAR库的API导致顺坏了CUDA,和CUDA无效设备一样。
第3天,2022/08/24,周三
- 上午10点,上周五承诺周三结束文档任务,没想到冒出一个新问题,在微信上跟同事说明原委。
- 有伙伴提议可否现场升级到Windows10,但是考虑到运维都是半夜进行,没有替代品,万一升级遇到问题又无法回退,就给用户带来太多麻烦,故放弃。
- 重读CUDA显存相关代码,有个疑惑点,伙伴建议使用自己的显存空间,可控,于是使用一个变量开关灵活切换自控显存和已有代码中使用的FFMPEG显存,可惜问题照旧。
- 既然输入图像没问题,怀疑点就换到输出图像空间的生命周期,读完代码,没有疑惑点无法下手。
- 睡觉前想到既然入图像和输出图像都没有非法问题,那就是和调用BAR库API的CUDA上下文有关。
- 立秋后北京天气爽快,延庆的夜晚该穿外套了,照例早晚和灰灰铲屎,手爪相握,喵喵喵,摸着大海的手,很快入睡。
第4天,2022/08/25,周四
- 调用API前加上push cuda上下文,结束后pop,解决了。
- 一点点删除临时代码,反复review每一段分析问题时随手加入的改善代码,避免引入新问题。
- BAR库更新API封装
cudaGetLastError()
,当期内部发现错误返回错误码后,外面再次获取CUDA的详细错误,结果发现第2次调用cudaGetLastError
时没有错误了,就改成API直接返回CUDA错误码,外面判断后写日志。 - 测试实际环境中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. 重新出发
- 既然Windows 10正常,应尽早想到和CUDA版本相关,同时视频源不断线的时候也没事,说明不是cuda渲染和解码的问题,怀疑自己开发的代码,要甚于怀疑她人。
- 结合CUDA无效设备,应全部review代码中BAR库和CUDA调用的相关代码,保证CUDA上下文使用正确。
5. 改善点
- 应覆盖Windows 7环境的测试。
- BAR库第一时间返回故障错误码,立即记录到日志,不让故障蔓延到其他地方,引起迷惑。