首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >内联装配性能优于C

内联装配性能优于C
EN

Stack Overflow用户
提问于 2012-04-09 23:05:58
回答 3查看 1.1K关注 0票数 4

首先,请原谅我,因为我的问题可能看起来很愚蠢,但我很好奇为什么在这个非常简单的代码中我得到了性能提升。

以下是组装代码:

代码语言:javascript
复制
__asm {
    mov eax, 0
    mov ecx, 0
    jmp startloop
    notequal:
    inc eax
    mov ecx, eax
    sub ecx, 2
    startloop:
    cmp eax, 2000000000
    jne notequal
};

这是C代码:

代码语言:javascript
复制
long x = 0;
long ii = 0;
for(; ii < 2000000000; ++ii)
{
    x = ii - 2;
};

C代码在我的i5 2500 k机器上完成大约1060 ms (在发行版构建),组装以780 ms完成。它的速度增加了25%。我不明白为什么我得到这个结果,因为25%是一个很大的差别。编译器是否足够聪明,能够生成我编写的相同的汇编代码?

顺便说一句,我正在使用MSVC 2010。

谢谢

下面是MSVC生成的(asm)代码

代码语言:javascript
复制
$LL3@main:
; Line 36
    lea esi, DWORD PTR [eax-2]
    inc eax
    cmp eax, 2000000000             ; 77359400H
    jl  SHORT $LL3@main

在这种情况下,lea指令是做什么的?

更新2

非常感谢大家。我刚刚在Nehalem上测试了这段代码,结果在这里是相同的。看起来是因为一个未知的原因,asm代码在Sandy上运行得更快。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-04-09 23:27:20

@modelnine 9的注释是正确的-- lea被用来简化循环中的赋值。你有:

代码语言:javascript
复制
x = ii - 2;

lea (load有效地址)指令正在有效地执行:

代码语言:javascript
复制
esi = &(*(eax - 2));

&*相互取消(这很重要--在本例中取消引用eax可能会导致问题),因此您可以获得:

代码语言:javascript
复制
esi = eax - 2;

这正是你的C代码想要做的。

票数 2
EN

Stack Overflow用户

发布于 2012-04-09 23:57:27

我比较了非asm版本:

代码语言:javascript
复制
#include <iostream>
#include <chrono>

int main() {
    auto start = std::chrono::high_resolution_clock::now();

    long x = 0;
    long ii = 0;
    for(; ii < 2000000000; ++ii)
    {
        x = ii - 2;
    };

    auto finish = std::chrono::high_resolution_clock::now();
    std::cout << (finish-start).count() << '\n';
    std::cout << x << ii << '\n';
}

asm版本:

代码语言:javascript
复制
#include <iostream>
#include <chrono>

int main() {
    auto start = std::chrono::high_resolution_clock::now();

    asm (R"(
         mov $0, %eax
         mov $0, %ecx
         jmp startloop
         notequal:
         inc %eax
         mov %eax,%ecx
         sub $2,%ecx
         startloop:
         cmp $2000000000,%eax
         jne notequal
    )");

    auto finish = std::chrono::high_resolution_clock::now();
    std::cout << (finish-start).count() << '\n';
}

使用clang 3.1

在打开优化之后,asm版本大约需要1.4秒,而非asm版本则需要45纳秒。这样做的结果是程序集版本慢了3200万%。

以下是为非asm版本生成的程序集:

代码语言:javascript
复制
movl    $1999999997, %esi       ## imm = 0x773593FD
callq   __ZNSt3__113basic_ostreamIcNS_11char_traitsIcEEElsEl
movq    %rax, %rdi
movl    $2000000000, %esi       ## imm = 0x77359400
callq   __ZNSt3__113basic_ostreamIcNS_11char_traitsIcEEElsEl
票数 2
EN

Stack Overflow用户

发布于 2012-04-09 23:57:03

你为什么不试试gcc -Ofast或者gcc -O1

下面是一个挑逗者:gcc -Q -Ofast --help=optimizers,就在gnu手册上!

下面是一个比较:

代码语言:javascript
复制
section .text
global _start

_start:
    mov eax, 0
    mov ecx, 0
    jmp startloop
    notequal:
    inc eax
    mov ecx, eax
    sub ecx, 2
    startloop:
    cmp eax, 2000000000
    jne notequal

    int     0x80

    mov     ebx,0
    mov     eax,1
    int     0x80

为此,我获得了1.306ms,而C语言将其计时为:

代码语言:javascript
复制
real    0m0.001s
user    0m0.000s
sys     0m0.000s

使用gcc -O1计时是:

代码语言:javascript
复制
real    0m1.295s
user    0m1.262s
sys     0m0.006s

它实际上执行了代码。

对于MSVC,应该能够使用/O2或/O1编译选项获得类似的结果。这里的详细信息,http://msdn.microsoft.com/en-us/library/k1ack8f1.aspx

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10080997

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档