小编典典

为什么我的程序在恰好循环 8192 个元素时很慢?

all

这是相关程序的摘录。矩阵img[][]的大小为 SIZE×SIZE,初始化为:

img[j][i] = 2 * j + i

然后,你做一个矩阵res[][],这里的每个字段都是img矩阵中它周围9个字段的平均值。为简单起见,边框保留为 0。

for(i=1;i<SIZE-1;i++) 
    for(j=1;j<SIZE-1;j++) {
        res[j][i]=0;
        for(k=-1;k<2;k++) 
            for(l=-1;l<2;l++) 
                res[j][i] += img[j+l][i+k];
        res[j][i] /= 9;
}

这就是程序的全部内容。为了完整起见,这里是之前的内容。后面没有代码。如您所见,这只是初始化。

#define SIZE 8192
float img[SIZE][SIZE]; // input image
float res[SIZE][SIZE]; //result of mean filter
int i,j,k,l;
for(i=0;i<SIZE;i++) 
    for(j=0;j<SIZE;j++) 
        img[j][i] = (2*j+i)%8196;

基本上,当 SIZE 是 2048 的倍数时,这个程序很慢,例如执行时间:

SIZE = 8191: 3.44 secs
SIZE = 8192: 7.20 secs
SIZE = 8193: 3.18 secs

编译器是 GCC。据我所知,这是因为内存管理,但我对这个主题并不太了解,这就是我在这里问的原因。

另外如何解决这个问题会很好,但如果有人能解释这些执行时间,我已经很高兴了。

我已经知道 malloc/free,但问题不在于使用的内存量,而只是执行时间,所以我不知道这会有什么帮助。


阅读 97

收藏
2022-03-02

共1个答案

小编典典

但这只是因为代码还有另一个问题。

从原始循环开始:

for(i=1;i<SIZE-1;i++) 
    for(j=1;j<SIZE-1;j++) {
        res[j][i]=0;
        for(k=-1;k<2;k++) 
            for(l=-1;l<2;l++) 
                res[j][i] += img[j+l][i+k];
        res[j][i] /= 9;
}

首先注意两个内部循环是微不足道的。它们可以按如下方式展开:

for(i=1;i<SIZE-1;i++) {
    for(j=1;j<SIZE-1;j++) {
        res[j][i]=0;
        res[j][i] += img[j-1][i-1];
        res[j][i] += img[j  ][i-1];
        res[j][i] += img[j+1][i-1];
        res[j][i] += img[j-1][i  ];
        res[j][i] += img[j  ][i  ];
        res[j][i] += img[j+1][i  ];
        res[j][i] += img[j-1][i+1];
        res[j][i] += img[j  ][i+1];
        res[j][i] += img[j+1][i+1];
        res[j][i] /= 9;
    }
}

这样就剩下我们感兴趣的两个外循环了。

现在我们可以看到这个问题的问题是相同的:为什么在迭代二维数组时循环的顺序会影响性能?

您正在逐列而不是逐行迭代矩阵。


要解决这个问题,您应该交换两个循环。

for(j=1;j<SIZE-1;j++) {
    for(i=1;i<SIZE-1;i++) {
        res[j][i]=0;
        res[j][i] += img[j-1][i-1];
        res[j][i] += img[j  ][i-1];
        res[j][i] += img[j+1][i-1];
        res[j][i] += img[j-1][i  ];
        res[j][i] += img[j  ][i  ];
        res[j][i] += img[j+1][i  ];
        res[j][i] += img[j-1][i+1];
        res[j][i] += img[j  ][i+1];
        res[j][i] += img[j+1][i+1];
        res[j][i] /= 9;
    }
}

这完全消除了所有非顺序访问,因此您不再会因大的二次幂而随机减速。


酷睿 i7 920 @ 3.5 GHz

原始代码:

8191: 1.499 seconds
8192: 2.122 seconds
8193: 1.582 seconds

互换外环:

8191: 0.376 seconds
8192: 0.357 seconds
8193: 0.351 seconds
2022-03-02