先说答案,不一定。

事情是这样的,我在写操作系统,看到田宇大佬写的代码里面,strlen也是用汇编来写的,我很不解,这个不是可以用C来实现吗?难不成纯汇编更快?于是我就写了一个小程序来做实验。看看这两者的速度。

这个程序首先是随机生成了1E6长度的字符串,然后分别进行1000次计算大小,可以发现,C语言的函数运行的更快一些些。

//测试strlen的速度

#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <stdio.h>

int n = 1e6; //生成长度为1e6的字符串

char s[1000007];

void generate_string()
{
    //先删除s

    srand((unsigned)time(NULL));
    for (size_t i = 0; i < n; i++)
    {
        /* code */
        s[i] = 'a' + rand() % 26;
    }
    s[n] = '\0';
}

int _strlen_asm(char *s)
{
    register int __res;
    __asm__ __volatile__("cld	\n\t"
                         "repne	\n\t"
                         "scasb	\n\t"
                         "notl	%0	\n\t"
                         "decl	%0	\n\t"
                         : "=c"(__res)
                         : "D"(s), "a"(0), "0"(0xffffffff)
                         :);
    return __res;
}

int _strlen_c(char *s)
{
    register int __res = 0;
    while (s[__res] != '\0')
    {
        ++__res;
    }
    return __res;
}

int main()
{
    generate_string();
    time_t start, end;

    clock_t total_asm = 0;
    int times = 1000;
    for (int i = 0; i < times; ++i)
    {
        start = clock();
        _strlen_asm(s);
        total_asm += clock()-start;
    }

    printf("%lf\n", 1.0*total_asm/times);

    clock_t total_c = 0;
    for (int i = 0; i < times; ++i)
    {
        start = clock();
        _strlen_c(s);
        total_c += clock()-start;
    }
    printf("%lf\n", 1.0*total_c/times);
}

运行速度:

田宇大佬的汇编版本:平均517.047000ms
C语言版本:平均430.027000ms

可以看到C版本的运行的更快,快了16.8%。

考虑到可能是这两个函数执行先后性的影响,交换一下他们的先后顺序,得到的结果依然不变。

怀着疑问,再来看看他们编译后的汇编代码:也许jmp指令对于处理器的分支预测更友好?

00000000004011de <_strlen_asm>:
  4011de:       55                      push   %rbp
  4011df:       48 89 e5                mov    %rsp,%rbp
  4011e2:       53                      push   %rbx
  4011e3:       48 89 7d f0             mov    %rdi,-0x10(%rbp)
  4011e7:       48 8b 75 f0             mov    -0x10(%rbp),%rsi
  4011eb:       b8 00 00 00 00          mov    $0x0,%eax
  4011f0:       ba ff ff ff ff          mov    $0xffffffff,%edx
  4011f5:       89 d1                   mov    %edx,%ecx
  4011f7:       48 89 f7                mov    %rsi,%rdi
  4011fa:       fc                      cld    
  4011fb:       f2 ae                   repnz scas %es:(%rdi),%al
  4011fd:       f7 d1                   not    %ecx
  4011ff:       ff c9                   dec    %ecx
  401201:       89 ca                   mov    %ecx,%edx
  401203:       89 d3                   mov    %edx,%ebx
  401205:       89 d8                   mov    %ebx,%eax
  401207:       5b                      pop    %rbx
  401208:       5d                      pop    %rbp
  401209:       c3                      ret    

000000000040120a <_strlen_c>:
  40120a:       55                      push   %rbp
  40120b:       48 89 e5                mov    %rsp,%rbp
  40120e:       53                      push   %rbx
  40120f:       48 89 7d f0             mov    %rdi,-0x10(%rbp)
  401213:       bb 00 00 00 00          mov    $0x0,%ebx
  401218:       eb 03                   jmp    40121d <_strlen_c+0x13>
  40121a:       83 c3 01                add    $0x1,%ebx
  40121d:       48 63 d3                movslq %ebx,%rdx
  401220:       48 8b 45 f0             mov    -0x10(%rbp),%rax
  401224:       48 01 d0                add    %rdx,%rax
  401227:       0f b6 00                movzbl (%rax),%eax
  40122a:       84 c0                   test   %al,%al
  40122c:       75 ec                   jne    40121a <_strlen_c+0x10>
  40122e:       89 d8                   mov    %ebx,%eax
  401230:       5b                      pop    %rbx
  401231:       5d                      pop    %rbp
  401232:       c3                      ret 

转载请注明来源:https://longjin666.cn/?p=1329

欢迎关注我的公众号“灯珑”,让我们一起了解更多的事物~

你也可能喜欢

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注