web-dev-qa-db-ja.com

memcmpがforループチェックよりもはるかに高速なのはなぜですか?

なぜmemcmp(a, b, size)は以下よりもはるかに速いのですか?

for(i = 0; i < nelements; i++) {
    if a[i] != b[i] return 0;
}
return 1;

MemcmpはCPU命令か何かですか?ループ全体でmemcmpを使用して大幅なスピードアップを得たので、かなり深いはずです。

30
jsj

memcmpは、Cの単純なループよりもmuch高速化できる多数のアーキテクチャ固有の機能を利用するために、アセンブリに実装されることがよくあります。

「ビルトイン」として

GCCはmemcmp(および他の多数の関数)を builtins としてサポートします。 GCCの一部のバージョン/構成では、memcmpの呼び出しは__builtin_memcmpとして認識されます。 callmemcmpライブラリ関数に発行する代わりに、GCCは関数の最適化されたインラインバージョンとして機能するためのいくつかの命令を発行します。

X86では、これはcmpsb命令の使用を活用します。これは、あるメモリ位置のバイト文字列を別のメモリ位置と比較します。これは、repe接頭辞と組み合わせられるため、文字列は、等しくなくなるか、カウントがなくなるまで比較されます。 (正確にmemcmpが何をするか)。

次のコードがあるとします:

int test(const void* s1, const void* s2, int count)
{
    return memcmp(s1, s2, count) == 0;
}

Cygwinのgcc version 3.4.4は、次のアセンブリを生成します。

; (prologue)
mov     esi, [ebp+arg_0]    ; Move first pointer to esi
mov     edi, [ebp+arg_4]    ; Move second pointer to edi
mov     ecx, [ebp+arg_8]    ; Move length to ecx

cld                         ; Clear DF, the direction flag, so comparisons happen
                            ; at increasing addresses
cmp     ecx, ecx            ; Special case: If length parameter to memcmp is
                            ; zero, don't compare any bytes.
repe cmpsb                  ; Compare bytes at DS:ESI and ES:EDI, setting flags
                            ; Repeat this while equal ZF is set
setz    al                  ; Set al (return value) to 1 if ZF is still set
                            ; (all bytes were equal).
; (epilogue) 

参照:

ライブラリ関数として

memcmpの高度に最適化されたバージョンは、多くのC標準ライブラリに存在します。これらは通常、アーキテクチャ固有の命令を利用して、大量のデータを並行して処理します。

Glibcには、以下の命令セット拡張を利用できるmemcmpx86_64の場合 のバージョンがあります。

素晴らしい点は、glibcが(実行時に)CPUが持つ最新の命令セットを検出し、それに最適化されたバージョンを実行することです。 sysdeps/x86_64/multiarch/memcmp.S の次のスニペットを参照してください:

ENTRY(memcmp)
    .type   memcmp, @gnu_indirect_function
    LOAD_RTLD_GLOBAL_RO_RDX
    HAS_CPU_FEATURE (SSSE3)
    jnz 2f
    leaq    __memcmp_sse2(%rip), %rax
    ret 

2:  HAS_CPU_FEATURE (SSE4_1)
    jz  3f  
    leaq    __memcmp_sse4_1(%rip), %rax
    ret 

3:  leaq    __memcmp_ssse3(%rip), %rax
    ret 

END(memcmp)

Linuxカーネル

Linuxは、x-86_64用にmemcmpの最適化バージョンを備えていないようですが、memcpyには Arch/x86/lib/memcpy_64.S で含まれています。これは、実行時に使用するバージョンを決定するだけでなく、alternativesインフラストラクチャ( Arch/x86/kernel/alternative.c )を使用することに注意してください。ただし、実際にはパッチ自体で、起動時に一度だけこの決定を行います。

37

MemcmpはCPU命令か何かですか?

これは、少なくとも非常に高度に最適化されたコンパイラー提供の組み込み関数です。おそらく、指定していないプラットフォームに応じて、1つまたは2つの機械命令。

1
user207421

これは通常、メモリのブロックを比較するための特殊な命令を使用して高速アセンブリに変換されるコンパイラ組み込み関数です。

固有のmemcmp

0
a_mole