なぜ strcmp は私の関数よりもはるかに高速なのでしょうか? 質問する

なぜ strcmp は私の関数よりもはるかに高速なのでしょうか? 質問する

私は関数 を書きました。Str::Compareこれは基本的にstrcmp別の方法で書き直したものです。2つの関数を比較すると、ループが500'000'000回繰り返されると、strcmp実行が速すぎて、約x750倍速くなります。

このコードは、パラメータがアクティブな状態で C ライブラリにコンパイルされました-Os

int Str::Compare(char* String_1, char* String_2)
{
    char TempChar_1, TempChar_2;

   do
   {
        TempChar_1 = *String_1++;
        TempChar_2 = *String_2++;
   } while(TempChar_1 && TempChar_1 == TempChar_2);

   return TempChar_1 - TempChar_2;
}

その関数の実行時間は です3.058sが、strcmpだけです0.004s

なぜこんなことが起こるのでしょうか?

また、ベンチマーク ループを実装した方法は次のとおりです。

int main()
{
     char Xx[] = {"huehuehuehuehuehuehuehuehuehuehuehuehuehue"},
          Yy[] = {"huehuehuehuehuehuehuehuehuehuehuehuehuehue"};
     for(int i = 0; i < 500000000; ++i)
         Str::Compare(Xx, Yy);
}

編集: コードをテストしながら最適化を行ったところ、Str::Compare速度が大幅に向上しました。以前strcmpx750倍速くなったのは今だけ250倍新しいコードは次のとおりです。

int Str::Compare(char* String_1, char* String_2)
{
     char TempChar_1, TempChar_2, TempChar_3;

     while(TempChar_1 && !TempChar_3)
     {
          TempChar_1 = *String_1++;
          TempChar_2 = *String_2++;
          TempChar_3 = TempChar_1 ^ TempChar_2;
     }

     return TempChar_1 - TempChar_2;
}

新しい実行時間は です0.994s

ベストアンサー1

私はそれについて興味があったので、テストプログラムを作成しました:

#include <string.h>

compare(char* String_1, char* String_2)
{
    char TempChar_1,
         TempChar_2;

   do
   {
        TempChar_1 = *String_1++;
        TempChar_2 = *String_2++;
   } while(TempChar_1 && TempChar_1 == TempChar_2);

   return TempChar_1 - TempChar_2;
}


int main(){
    int i=strcmp("foo","bar");
    int j=compare("foo","bar");

    return i;
}

gcc 4.7.3 を使用してアセンブラにコンパイルしたところ、gcc -S -Os test.c次のアセンブラが生成されました。

    .file   "test.c"
    .text
    .globl  compare
    .type   compare, @function
compare:
.LFB24:
    .cfi_startproc
    xorl    %edx, %edx
.L2:
    movsbl  (%rdi,%rdx), %eax
    movsbl  (%rsi,%rdx), %ecx
    incq    %rdx
    cmpb    %cl, %al
    jne .L4
    testb   %al, %al
    jne .L2
.L4:
    subl    %ecx, %eax
    ret
    .cfi_endproc
.LFE24:
    .size   compare, .-compare
    .section    .rodata.str1.1,"aMS",@progbits,1
.LC0:
    .string "bar"
.LC1:
    .string "foo"
    .section    .text.startup,"ax",@progbits
    .globl  main
    .type   main, @function
main:
.LFB25:
    .cfi_startproc
    movl    $.LC0, %esi
    movl    $.LC1, %edi
    call    compare
    movl    $1, %eax
    ret
    .cfi_endproc
.LFE25:
    .size   main, .-main
    .ident  "GCC: (Ubuntu/Linaro 4.7.3-1ubuntu1) 4.7.3"
    .section    .note.GNU-stack,"",@progbits

私は x86 アセンブラにそれほど詳しくありませんが、私が見る限り、strcmp への呼び出しは削除され、単に定数式 ( movl $1, %eax) に置き換えられます。したがって、テストに定数式を使用する場合、gcc はおそらく strcmp を定数に最適化します。

おすすめ記事