我在C中分析了pre和post增量运算符(出于好奇,不是为了微优化目的!),我得到了一些令人惊讶的结果。我期望后增量运算符更慢,但我的所有测试都表明它(非平凡)更快。我甚至查看了在gcc中使用-S
标志生成的汇编代码,并且post有一条额外的指令(如预期的那样)。有谁能解释一下?我在Arch Linux上使用gcc 4.8.1。
这是我的代码。
编辑:我的代码中存在整数溢出错误。它不会影响问题,但您应该注意实际的迭代次数与传入的参数不同。
Post.c:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv) {
if (argc < 2) {
printf("Missing required argument\n");
exit(1);
}
int iterations = atoi(argv[1]);
int x = 1;
int y;
int i;
for (i = 0; i < iterations; i++) {
y = x++;
}
printf("%d\n", y);
}
Pre.c:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv) {
if (argc < 2) {
printf("Missing required argument\n");
exit(1);
}
int iterations = atoi(argv[1]);
int x = 1;
int y;
int i;
for (i = 0; i < iterations; i++) {
y = ++x;
}
printf("%d\n", y);
}
结果如下:
$ gcc post.c -o post
$ gcc pre.c -o pre
$ I=100000000000; time ./post $I; time ./pre $I
1215752192
real 0m2.777s
user 0m2.777s
sys 0m0.000s
1215752193
real 0m3.140s
user 0m3.137s
sys 0m0.003s
我前段时间也写过timing script。运行得到相同的结果:
$ I=100000000000; comptime "./pre $I" "./post $I"
3193 3133 3157 3143 3133 3153 3147 3150 3143 3146 3143
2743 2767 2700 2727 2700 2697 2727 2710 2680 2783 2700
Mean 1: 3149.18
Mean 2: 2721.27
SD 1: 6.1800
SD 2: 21.2700
输出主要是自我解释,但想法是它运行两个程序10次(默认情况下)并计算结果的平均值和标准差(以毫秒为单位)。
我已经将gcc为post.c和pre.c生成的汇编代码包含在pastebin中,因为我不想将这篇文章与可能不必要的内容混为一谈。
很抱歉再次提起这场辩论,但这些数字对我来说似乎很奇怪。
答案 0 :(得分:0)
有趣的问题。我把它作为评论开始,但它有点长。
所以,这就是我所做的,我像这样运行了pre
和post
:
$ for i in $(seq 1 10); do command time -f "%U" ./pre 1000000000 2> pre.times
$ echo 'd=load("pre.times"); min(d), mean(d), max(d), std(d)' | octave -q
我得到了(我已经替换ans
以使其更具可读性):
min = 2.2900
avg = 2.3550
max = 2.4000
std = 0.040893
我类似地跑了post
并得到了:
min = 2.1900
avg = 2.2590
max = 2.3800
std = 0.055668
简而言之,我发现在Ubuntu 12.04 amd64上使用Ivy Bridge CPU和gcc 4.6.3的差异要小得多。
反汇编只显示了一些指令的轻微重新排序,没有额外的指令(我想知道你为什么期望它)。
我最好的猜测是,这是一个非常微妙的CPU问题,例如,μop在保留站中等待操作数转发再花费一个周期。在我的设置上没有什么超级明显的,这是肯定的。