web-dev-qa-db-fra.com

Pourquoi memcmp est-il tellement plus rapide qu'un test for loop?

Pourquoi memcmp(a, b, size) est-il tellement plus rapide que:

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

Est-ce que memcmp est une instruction de la CPU? Cela doit être assez profond car j'ai eu une accélération massive en utilisant memcmp sur la boucle.

26
jsj

memcmp est souvent implémenté dans Assembly pour tirer parti d'un certain nombre de fonctionnalités spécifiques à l'architecture, ce qui peut le rendre beaucoup plus rapide qu'une simple boucle en C.

En tant que "intégré"

GCC supporte memcmp (ainsi qu'une tonne d'autres fonctions) sous la forme builtins . Dans certaines versions/configurations de GCC, un appel à memcmp sera reconnu comme __builtin_memcmp. Au lieu d’émettre une call à la fonction de bibliothèque memcmp, GCC émettra une poignée d’instructions qui serviront de version intégrée optimisée de la fonction.

Sur x86, cela exploite l’utilisation de l’instruction cmpsb, qui compare une chaîne d’octets d’un emplacement mémoire à un autre. Ceci est couplé avec le préfixe repe, ainsi les chaînes sont comparées jusqu'à ce qu'elles ne soient plus égales ou qu'un compte soit épuisé. (Exactement ce que memcmp fait).

Étant donné le code suivant:

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

gcc version 3.4.4 sur Cygwin génère l'assembly suivant:

; (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) 

Référence:

En tant que fonction de bibliothèque

Des versions hautement optimisées de memcmp existent dans de nombreuses bibliothèques C standard. Celles-ci s'appuient généralement sur des instructions spécifiques à l'architecture pour travailler avec de nombreuses données en parallèle.

Dans Glibc, certaines versions de memcmpfor x86_64 peuvent tirer parti des extensions de jeu d'instructions suivantes:

La partie intéressante est que glibc détectera (au moment de l'exécution) le dernier jeu d'instructions de votre CPU et exécutera la version optimisée pour ce dernier. Voir cet extrait de 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)

Dans le noyau Linux

Linux ne semble pas avoir une version optimisée de memcmp pour x86_64, mais il en a pour memcpy, dans Arch/x86/lib/memcpy_64.S . Notez que cela utilise alternatives infrastructure ( Arch/x86/kernel/alternative.c ) non seulement pour décider au moment de l’exécution de la version à utiliser, mais en réalité se patcher lui-même pour ne prendre cette décision qu’au démarrage. up.

37
Jonathon Reinhart

Est-ce que memcmp est une instruction de la CPU?

C'est au moins une fonction intrinsèque très optimisée fournie par le compilateur. Peut-être une seule instruction machine, ou deux, selon la plate-forme, que vous n'avez pas spécifiée.

0
user207421

Il s’agit généralement d’un compilateur intrinsèque traduit en assembleur rapide avec des instructions spécifiques permettant de comparer des blocs de mémoire.

memicmp intrinsèque

0
a_mole