我正在研究一个旋转二维数组的项目。当我使用宏来替换某些代码时,结果令人惊讶,因为一切都完全相同。完成任务所需的时间可能会有很大差异。我一直认为宏只是一个占位符,但这怎么可能发生呢?
struct pixel
{
unsigned short red;
unsigned short green;
unsigned short blue;
} ;
//n is the # of elements in the two dimensional array
void rotate1(int n, pixel *src, pixel *dst)
{
int row, col, max = n - 1;
for (row = 0; row < n; row++)
for (col = 0; col < n; col++)
*(dst+ (((max - row)*n)+col)) = *(src+ (row*n + col));
}
void rotate11(int n, pixel *src, pixel *dst)
{
#define TARGET *(dst + (((max - row)*n)+col))
#define SOURCE *(src + (row*n + col))
int row, col, max = n - 1;
for (row = 0; row < n; row++)
for (col = 0; col < n; col++)
{
TARGET = SOURCE;
}
}
结果是:
Time= 2.25 n= 512 Method= rotate1
Time= 2.18 n= 512 Method= rotate11
Time= 8.05 n= 1024 Method= rotate1
Time= 8.08 n= 1024 Method= rotate11
Time= 25.18 n= 2048 Method= rotate1
Time= 25.24 n= 2048 Method= rotate11
Time= 104.38 n= 4096 Method= rotate1
Time= 104.21 n= 4096 Method= rotate11
Time= 1272.41 n= 8192 Method= rotate1
Time= 423.00 n= 8192 Method= rotate11
当n很小时,两者的性能相似,但随着n越来越大,rotate11
的时间越来越少。
答案 0 :(得分:7)
就编译器而言,这两个示例完全相同。你在同一次运行中运行这两个例子吗?可能发生的事情是第一个运行的函数(无论你是否使用过宏)都填充了缓存,第二个运行速度要快得多。
如果更改调用函数的顺序,或者每次执行限制为一个函数运行,该怎么办?你应该看到几乎相同的表现。
答案 1 :(得分:1)
我怀疑内存缓存有些影响。为了确保您可以尝试进行4次调用,run1,run11,run 1,run11,您的数据具有内存访问模式,这可能会导致第一次加载数据的成本很高......
答案 2 :(得分:1)
这里有稳定的增长模式 - 正如@mah指出的那样 - 每当你将n
增长2倍时,你的运行时间就会增加4倍,这是有道理的,因为你的数组是n ^ 2。
根据这个,你的最后一个电话(n = 8192)应该是〜400长,正如第二个电话确实显示的那样。我愿意打赌在第一次调用(上下文切换或其他一些中断)期间只有一些意外事件导致它停止 - 你应该运行几次迭代并查看它是否重现
答案 3 :(得分:0)
在编译器看到代码之前,C预处理器会扩展宏。
您可以通过gcc中的-E选项创建预处理器输出。
例如:
gcc -E foo.c -o foo.i / *创建预处理器文本文件输出* /
VS
gcc -c foo.c -o foo.o / *创建目标文件输出* /
如果在您选择的编辑器中打开foo.i,您将看到扩展为源代码的MACRO。
我真的不知道MACROS会如何影响你的表现。