问题
如果在相同处理器上针对相同输入数据重新运行相同的程序,得到的结果相同吗?
串行代码
串行代码浮点运算结果的差异的唯一已知来源是由外部环境更改引发的数据调整。 例如,用户动态分配了一个包含日期的新字符串。 该字符串的大小随一年中的月份或周的日期而不同,因此需要对分配的日期进行后续调整。 调整范围决定着哪些循环迭代是循环开头或循环结尾(remainder loop)的组成部分,以及哪些是矢量化内核的组成部分。 这反过来影响浮点约分运算的顺序;按照指定精度对不同直接结果执行舍入处理可缩小最终结果的差异范围。 开头、结尾和内核之间的优化不同可得出相似的差异范围。 这些差异范围可通过以下两个方式预防:
1) 通过调整在运行时间分配的任何数据。 对于 C/C++ 编程,可使用经过调整的 malloc/calloc/free 版本等等,例如 _mm_malloc() 和 _mm_free() 或 Posix 类型。 对于 Fortran 编程,!DIR$ ATTRIBUTES ALIGN:64 :: 阵列指令,或命令行交换 -align array64byte (推荐)。 数据调整为 64 位边界也具有性能优势。
2) 通过使用 –fp-model precise 编译。 这禁用约分运算的矢量化以及其它可能导致浮点运算结果差异的优化,不仅仅是 R2R,而且是不同优化级别。 还应评测对性能的潜在影响,因为它取决于应用。 一些不会影响 R2R 再现性的优化可使用 -ftz、-fast-transcendentals、-no-prec-div 与 -no-prec-sqrt 等选项重新启用。
并行代码
并行应用的差异来源不仅限于上述讨论内容。对于包含约分的并行代码,并行分解的更改有可能导致运算顺序的更改,进而影响结果的差异范围。 对于固定分解,英特尔编译器和 run-time 提供一个机制,确保 OpenMP 约分获得可重复的结果,遵守静态调度和固定数量的线程 — 通过将环境参数 KMP_DETERMISTIC_REDUCTION 设置为“true”(或“yes”或“on”或“1”)。 对于多数线程这是默认设置,目前英特尔 64 处理器为 >4,英特尔至强融核协处理器为 >8。
英特尔® 数学核心函数库支持相关条件下的 R2R 再现性。 其中包括输入数据的一致性调整(64 位调整的性能最佳);固定数量的线程;静态 OpenMP 调度;和 KMP_DETERMINISTIC_REDUCTION=true。
英特尔® 线程构建模块支持新函数 parallel_deterministic_reduce(),支持并行约分获得可再现的结果,即使线程数量不同,但是有可能影响性能。 可参考英特尔® Composer XE 2013 产品文档了解更多信息。
英特尔® Cilk™ Plus 线程密钥目前无法确保并行约分的 R2R 再现性。
本文未讨论使用 MPI 进行应用构建,但是类似考虑因素是适用的。
对于在英特尔® 至强处理器上执行的代码和在英特尔® 至强融核™ 协处理器上执行的代码,无法保证代码之间的位对位再现性,即使对于固定数量的线程或串行代码。 如需深入了解潜在差异和控制方法以及英特尔至强融核协处理器浮点计算的其它内容,请参考:https://secure-software.intel.com/sites/default/files/article/326703/floating-point-differences-sept11.pdf相关链接是“编程”下的“浮点运算差异”:http://software.intel.com/en-us/mic-developer。
只要符合上述条件,运行于英特尔至强主机并卸载至一个或多个英特尔至强融核协处理器的程序有望是可再现的,而且同一代码段按照运行顺序卸载至同一协处理器。 如果一个代码段有时卸载有时运行于英特尔至强主机处理器,则很可能不可再现。
讨论
对于上文讨论的浮点运算结果的 R2R 差异范围通常极小,通常位于单次运算的末位。单精度为 1/107,双精度为 1/1016。 这反映了浮点运算的有限精度;一个结果的精度通常和另一个结果的精度“相当”。 如果用户执行大量取消操作(用户有时是下意识操作的),或者用户为了控制质量而依赖位对位协议,则差异范围会很明显。 在任何场景下,结果的差异范围可能表明:结果数值的真实不确定性可能更大,有时会比用户想象的大很多。
对于很多场景,在预期计算差异范围内的结果都是可以接受的。 比较结果时,无论是不同的运行、不同的优化级别、不同的软件版本、不同的处理器、还是不同的架构,我们都建议用户测试在允许误差范围内的结果一致性,而不要追求位对位的结果一致性。
如需深入了解再现性问题、再现性的误差范围、精度和性能,请参考在线文章:http://software.intel.com/en-us/articles/consistency-of-floating-point-results-using-the-intel-compiler/