首页/文章/ 详情

一字之差,程序性能却相去甚远

7月前浏览3724


本文摘要(由AI生成):

本文讨论了内存性能对软件运行速度的影响,指出优秀软件应充分利用内存层次结构。通过比较两段访问二维数组元素的代码,文章指出,即使是很小的代码改动,如交换数组下标,也可能导致运行时性能产生显著差异。这是因为内存访问的连续性和局部性对性能至关重要。此外,文章还介绍了颠簸现象,即由内存容量不足或程序缺乏引用局部性导致的性能下降。因此,程序员应仔细研究内存访问模式,优化代码,以显著提升软件性能。

有意识地根据内存性能设计出来的软件运行要快得多。尽管对于大多数程序来说,系统提供的缓存和分页功能已足好了,但是我们仍然追求运行更快的程序,哪怕系统中没有缓存。最优秀的软件一定会最大限度地利用内层次结构。来看下面的2段程序:

//片段1
//创建一个二维数组并赋值
int array[256][256];
for( i=0; i<256; ++i ) {
    for( j=0; j256; ++j) {
        array[j][i]=i*j;
    }
}

//片段2
//创建一个二维数组并赋值
int array[256][256];
for( i=0; i<256; ++i ) {
    for( j=0; j256; ++j) {
        array[i][j]=i*j;
    }
}

这两段代码的唯一区别就是在访问数组元素时交换了下标i和j。这么小的改动会导致运行时一个(甚至两个)数量级的性能差别!要理解其中的原因,就要知道在C语言中,内存中的二维数组采用的是行优先顺序。因此,第二段代码访问的是内存中连续的单位,具备引用的空间局部性。而第一段代码访问数组元素的顺序是这样的:array[0][0],array[1][0],array[2][0],...,array[254][0]array[255][0],array[0][1],...

如果整型是4个字节,那么按照上面顺序访问的是偏移量为 0、1024、2048、3072等位置的双字值,访问显然不是连续的。这段代码大概率只能将n个整数加载到n路组相联缓存中,然后很快就会出现颠簸,因为后续的数组元素为了避免被覆盖不得不将其从缓存复 制到主存中。第二段代码则不会出现颠簸。假定缓存采用了64字节的缓存行,对于第二段代码来说,一个缓存行一次可以存储 16个整数,然后才会从主存中加载另一个缓存行置换这一块数据。这样,第二段代码每次从内存载入缓存行的数据可以访问16次加载的成本被分摊了,而第一段代码这样的一次内存访问就要加载一次.

总之,我们应该仔细研究程序的内存访问模式,并相应调整代码。花几个小时用手工优化的汇编代码重写程序可能获得 10%的性能提升。但是改变程序访问内存的方式让性能提升一个数量级,也不是不可能。

颠簸是一种性能退化,它会导致系统性能整体下降到内存层次结构中的主存甚至磁盘驱动器这些较慢的层次。导致颠簸的原因主要有两个:

  • 内存层次结构中某个级别的内存容量不足以容纳程序的缓存行工作集或页工作集
  • 程序不具备引用局部性。



来源:数值分析与有限元编程
科普
著作权归作者所有,欢迎分享,未经许可,不得转载
首次发布时间:2024-04-02
最近编辑:7月前
太白金星
本科 慢慢来
获赞 5粉丝 13文章 325课程 0
点赞
收藏
作者推荐

高精度数值运算解病态方程组

本文摘要(由AI生成):本文介绍了针对病态方程组数值不稳定性的问题,可采用高精度数值运算解决。Fortran内置的SELECTED_REAL_KIND函数能够根据需要选择实型数据的精度和范围,保持程序通用性。函数调用方式灵活,参数可选。文章通过算例展示了采用不同精度计算的结果,并指出更复杂的方程组同样可用该函数选择所需精度。往期相关介绍了病态方程组的来源和背景。针对病态方程组对任何算法都将产生数值不稳定性,可采用高精度数值运算解决这个问题。Fortran内置函数SELECTED_REAL_KIND(p, r),默认两个参数p是精度,r是范围。p是所需精度的十进制数值,r是以10^r次方表示的所需数值的范围。当执行该函数的时候,会返回达到或者超过指定精度或者范围的的实型数据的最小类别参数。使用该函数可以保持程序通用性,而不受平台限制。kind_num = SELECTED_REAL_KIND(13,100)kind_num = SELECTED_REAL_KIND(13)kind_num = SELECTED_REAL_KIND(r=100,p=13)kind_num = SELECTED_REAL_KIND(r=100)以上都是函数的调用方法皆正确,因为函数参数是可选的。注意程序中第二个变量所需的精度为13位小数和10^200次方的范围,但是处理器实际分配的精度为15位小数和10^308次方的范围.●算例采用的精度计算,结果为:采用双精度计算,结果为:更复杂的方程组可以用函数SELECTED_REAL_KIND选择所需精度。★★★ 往期相关 ★★★病态方程组来源:数值分析与有限元编程

未登录
还没有评论
课程
培训
服务
行家
VIP会员 学习 福利任务 兑换礼品
下载APP
联系我们
帮助与反馈