4
SIMD编程代码库的维护成本
题: 软件行业的共识是,干净,简单的代码对于代码库和拥有它的组织的长期生存至关重要。这些属性导致较低的维护成本,并增加了继续使用代码库的可能性。 但是,SIMD代码与通用应用程序代码不同,我想知道是否有专门针对SIMD代码的简洁代码的相似共识。 我的问题的背景。 我为各种图像处理和分析任务编写了大量的SIMD(单指令,多个数据)代码。最近,我还不得不将少量这些功能从一种体系结构(SSE2)移植到另一种体系结构(ARM NEON)。 该代码是为收缩包装的软件编写的,因此,如果没有不受限制的重新分配权限(例如MATLAB),就不能依赖专有语言。 典型代码结构的示例: 使用OpenCV的矩阵类型(Mat)进行所有内存,缓冲区和生命周期管理。 检查输入参数的大小(尺寸)后,将获得指向每行像素起始地址的指针。 像素计数和来自每个输入矩阵的每一行像素的起始地址都传递给一些低级C ++函数。 这些低级C ++函数使用SIMD内部函数(用于Intel Architecture和ARM NEON),从原始指针地址加载并保存到原始指针地址。 这些低级C ++函数的特征: 唯一一维的(在内存中连续) 不处理内存分配。(每个分配,包括临时性,都由外部代码使用OpenCV工具处理。) 符号的名称长度(内部名称,变量名称等)的范围大约为10-20个字符,这是非常大的。(读起来就像是技术泡沫)。 不鼓励重复使用SIMD变量,因为编译器在正确地解析不是以“单分配”编码方式编写的代码方面存在很多缺陷。(我已经提交了几个编译器错误报告。) SIMD编程的哪些方面会使讨论与一般情况有所不同?或者,为什么SIMD与众不同? 初期开发费用 众所周知,与随便编写的 C ++代码相比,具有良好性能的C ++ SIMD代码的初始开发成本约为10倍至100倍(具有较大的余量)。 正如在性能与可读/清洁代码之间进行选择的答案中所指出的那样?,大多数代码(包括随便编写的代码和SIMD代码)起初既不干净也不快速。 不鼓励对代码性能(在标量代码和SIMD代码中)进行进化改进(因为这被视为一种软件返工),并且没有跟踪成本和收益。 就倾向而言 (例如帕累托原则,又称80-20规则) 即使图像处理仅占软件系统的20%(在代码大小和功能上),图像处理也相对较慢(当以所花费的CPU时间的百分比表示),花费的时间超过80%。 这是由于数据大小的影响:典型的图像大小以兆字节为单位,而非图像数据的典型大小以千字节为单位。 在图像处理代码中,SIMD程序员受过训练,可以通过识别C ++代码中的循环结构来自动识别包含热点的20%代码。因此,从SIMD程序员的角度来看,“重要的代码” 100%是性能瓶颈。 通常在图像处理系统中,存在多个热点,并占用相当比例的时间。例如,可能有5个热点分别占总时间(20%,18%,16%,14%,12%)。为了获得高性能,需要在SIMD中重写所有热点。 这被概括为气球弹出规则:气球不能两次弹出。 假设有一些气球,说5个。抽取它们的唯一方法是将它们逐个弹出。 弹出第一个气球后,剩下的4个气球现在占总执行时间的更高百分比。 为了获得更大的收益,然后必须弹出另一个气球。(这违背了80-20的优化规则:采摘了悬挂率最低的20%的水果后,可以获得良好的经济效果。) 在可读性和维护方面 SIMD代码显然难以阅读。 即使遵循每一项软件工程最佳实践,也是如此,例如命名,封装,const正确性(并使副作用显而易见),函数分解等。 即使对于有经验的SIMD程序员也是如此。 与等效的C ++原型代码相比,最佳SIMD代码非常扭曲(请参阅备注)。 扭曲SIMD代码的方法有很多,但是10种这样的尝试中只有1种会获得可接受的快速结果。 …