为了账号安全,请及时绑定邮箱和手机立即绑定

在没有优化的情况下添加冗余分配可以加快代码的速度

在没有优化的情况下添加冗余分配可以加快代码的速度

浮云间 2019-11-02 14:38:18
我发现一个有趣的现象:#include<stdio.h>#include<time.h>int main() {    int p, q;    clock_t s,e;    s=clock();    for(int i = 1; i < 1000; i++){        for(int j = 1; j < 1000; j++){            for(int k = 1; k < 1000; k++){                p = i + j * k;                q = p;  //Removing this line can increase running time.            }        }    }    e = clock();    double t = (double)(e - s) / CLOCKS_PER_SEC;    printf("%lf\n", t);    return 0;}我在i5-5257U Mac OS上使用GCC 7.3.0编译代码,没有进行任何优化。这是平均运行时间超过10倍: 还有其他人在其他Intel平台上测试该案例并获得相同的结果。 我将在这里发布由GCC生成的程序集。两种汇编代码之间的唯一区别是,在较快的一种汇编代码之前,还有两项操作:在此处输入图片说明addl $1, -12(%rbp)movl    -44(%rbp), %eaxmovl    %eax, -48(%rbp)那么,为什么用这样的分配程序运行得更快?彼得的回答很有帮助。在AMD Phenom II X4 810和ARMv7处理器(BCM2835)上进行的测试显示了相反的结果,该结果支持存储转发加速特定于某些Intel CPU。而BeeOnRope的评论和建议催着我重写的问题。:)这个问题的核心是与处理器架构和组装相关的有趣现象。因此,我认为值得讨论。
查看完整描述

3 回答

?
慕娘9325324

TA贡献1783条经验 获得超4个赞

请注意,call/ret不会创建循环承载的依赖项,因为由推送的地址call来自推测执行+分支预测。当存储不依赖于数据时,多次存储/重载到同一地址可以使每个时钟维持一个时钟。执行ret指令可以每个时钟执行一次,比call指令落后5个周期。(当然,调用/ ret都是分支,因此它们彼此竞争执行资源,因此甚至没有瓶颈。)可能是问题,是a push/pop rbpx=foo(x)by ref。

查看完整回答
反对 回复 2019-11-02
?
BIG阳

TA贡献1859条经验 获得超6个赞

我认为这个问题没有用。您开始时的一大不利之处是没有优化就进行编译,这对于“为什么Y的性能表现得像Z”已经是一个巨大的危险信号-但由于编译器仅针对较慢的情况发出了额外的指令,因此事实证明这很有趣在组装级别的问题。即,您几乎可以删除问题的C起源,以及您在不进行优化的情况下进行编译的事实,并询问程序集的行为,并且可能避免雪崩式的雪崩

查看完整回答
反对 回复 2019-11-02
  • 3 回答
  • 0 关注
  • 436 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信