处理器行为解释
Processor behavior explanation
在询问 之后,我感到非常困惑,因此决定为 C 编译器程序构建类似的测试。这是我的代码:
#include <stdio.h>
#include <time.h>
#include <math.h>
#include <stdlib.h>
#define SUMMATIONS 20000000
int main() {
static int speedups[2101] = { 0 };
srand((unsigned)time(NULL));
while (1) {
unsigned int t1, t2, t3, t4;
signed int tmp, i, n1, n2;
// Slow version
t1 = clock();
for (n1 = rand() % 50, i = 0; i < SUMMATIONS; i++) {
n1 += 3 * i * i;
}
t2 = clock();
// Optimized version
t3 = clock();
for (n2 = rand() % 50, i = 0; i < SUMMATIONS; i++) {
n2 += i * i;
}
n2 *= 3;
t4 = clock();
// gather speedup statistics
if ((int)(t2 - t1) != 0) {
tmp = (int)(100.0f * ((float)(t2 - t1) - (float)(t4 - t3)) / (float)(t2 - t1));
tmp = tmp < -100 ? -100 : tmp > 100 ? 100 : tmp;
tmp = (tmp >= 0 ? 1000 : 2000) + abs(tmp);
speedups[tmp]++;
}
// output statistics
for (i = 0; i < 2101; i++) {
if (speedups[i] != 0) {
char s = i / 1000 == 1 ? '+' : i / 1000 == 2 ? '-' : '?';
printf("%c%i : %i\n", s, i % 1000, speedups[i]);
}
}
printf("error %i ******************\n", abs(n2-n1));
}
return 0;
}
在 GCC 下编译,选项 -O3 -march=native
编辑
测试代码已更改,因此错误值只能在 运行 时(而不是在编译时)获知,因此 GCC 优化器无法删除 for 循环的代码。
结果
当 运行 - 重新计算 CPU 的计数器命中特定的加速值并输出计数器 table。如果我们绘制 CPU 命中与加速值,- 我们将
得到这样的图表:
所以 GCC 使程序产生了 ~ 20% 平均加速。
问题
我们是否应该 期望 在 CPU 中加速? (如GCC编译程序预测的那样)
Should we expect speedup in CPU ?
没有。选择使用高级语言,您就选择了放弃期望任何与性能相关的权利。
您可能假设(但不期望)第一个版本在循环内有一个额外的乘法(额外的 3*
),因此可能会有与该乘法相关的额外成本。
您还可以假设(但不期望)编译器可能将两个版本优化为一个常量,并且可能生成 printf("error %i ******************\n", CONSTANT_CALCULATED_AT_COMPILE_TIME);
的等价物,而无需任何代码来计算 n1
或 n2
在 运行-time.
请注意,这些随机假设是相互排斥的。
在询问
#include <stdio.h>
#include <time.h>
#include <math.h>
#include <stdlib.h>
#define SUMMATIONS 20000000
int main() {
static int speedups[2101] = { 0 };
srand((unsigned)time(NULL));
while (1) {
unsigned int t1, t2, t3, t4;
signed int tmp, i, n1, n2;
// Slow version
t1 = clock();
for (n1 = rand() % 50, i = 0; i < SUMMATIONS; i++) {
n1 += 3 * i * i;
}
t2 = clock();
// Optimized version
t3 = clock();
for (n2 = rand() % 50, i = 0; i < SUMMATIONS; i++) {
n2 += i * i;
}
n2 *= 3;
t4 = clock();
// gather speedup statistics
if ((int)(t2 - t1) != 0) {
tmp = (int)(100.0f * ((float)(t2 - t1) - (float)(t4 - t3)) / (float)(t2 - t1));
tmp = tmp < -100 ? -100 : tmp > 100 ? 100 : tmp;
tmp = (tmp >= 0 ? 1000 : 2000) + abs(tmp);
speedups[tmp]++;
}
// output statistics
for (i = 0; i < 2101; i++) {
if (speedups[i] != 0) {
char s = i / 1000 == 1 ? '+' : i / 1000 == 2 ? '-' : '?';
printf("%c%i : %i\n", s, i % 1000, speedups[i]);
}
}
printf("error %i ******************\n", abs(n2-n1));
}
return 0;
}
在 GCC 下编译,选项 -O3 -march=native
编辑
测试代码已更改,因此错误值只能在 运行 时(而不是在编译时)获知,因此 GCC 优化器无法删除 for 循环的代码。
结果
当 运行 - 重新计算 CPU 的计数器命中特定的加速值并输出计数器 table。如果我们绘制 CPU 命中与加速值,- 我们将 得到这样的图表:
所以 GCC 使程序产生了 ~ 20% 平均加速。
问题
我们是否应该 期望 在 CPU 中加速? (如GCC编译程序预测的那样)
Should we expect speedup in CPU ?
没有。选择使用高级语言,您就选择了放弃期望任何与性能相关的权利。
您可能假设(但不期望)第一个版本在循环内有一个额外的乘法(额外的 3*
),因此可能会有与该乘法相关的额外成本。
您还可以假设(但不期望)编译器可能将两个版本优化为一个常量,并且可能生成 printf("error %i ******************\n", CONSTANT_CALCULATED_AT_COMPILE_TIME);
的等价物,而无需任何代码来计算 n1
或 n2
在 运行-time.
请注意,这些随机假设是相互排斥的。