while terminar for español ejemplos como ciclo bucle c performance optimization memcmp

terminar - ¿Por qué memcmp es mucho más rápido que una verificación de bucle for?



for i in range python español (4)

¿Es memcmp una instrucción de CPU o algo así?

Es al menos una función intrínseca muy altamente optimizada proporcionada por el compilador. Posiblemente una sola instrucción de máquina, o dos, según la plataforma, que no haya especificado.

¿Por qué es memcmp(a, b, size) mucho más rápido que:

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

¿Es memcmp una instrucción de CPU o algo así? Debe ser bastante profundo porque obtuve una aceleración masiva utilizando memcmp en el bucle.


Por lo general, es un compilador intrínseco que se traduce en un ensamblaje rápido con instrucciones especializadas para comparar bloques de memoria.

memcmp intrínseco


Sí, en el hardware Intel, hay una sola instrucción de ensamblaje para tal bucle. El tiempo de ejecución utilizará eso. (No recuerdo exactamente, era algo así como rep cmps[b|w] , dependiendo también del tamaño de datos)


memcmp menudo se implementa en ensamblaje para aprovechar una serie de características específicas de la arquitectura, que pueden hacerlo mucho más rápido que un simple bucle en C.

Como un "builtin"

GCC admite memcmp (así como un montón de otras funciones) como builtins . En algunas versiones / configuraciones de GCC, una llamada a memcmp será reconocida como __builtin_memcmp . En lugar de emitir una call a la función de biblioteca memcmp , GCC emitirá un puñado de instrucciones para actuar como una versión en línea optimizada de la función.

En x86, esto aprovecha el uso de la instrucción cmpsb , que compara una cadena de bytes en una ubicación de memoria a otra. Esto se combina con el prefijo repe , por lo que las cadenas se comparan hasta que ya no son iguales, o se agota la cuenta. (Exactamente lo que hace memcmp ).

Dado el siguiente código:

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

gcc version 3.4.4 en Cygwin genera el siguiente ensamblaje:

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

Referencia:

Como una función de biblioteca

Versiones altamente optimizadas de memcmp existen en muchas bibliotecas estándar de C. Estos usualmente aprovecharán las instrucciones específicas de la arquitectura para trabajar con muchos datos en paralelo.

En Glibc, hay versiones de memcmp para x86_64 que pueden aprovechar las siguientes extensiones de conjuntos de instrucciones:

La parte interesante es que glibc detectará (en tiempo de ejecución) la configuración más reciente que tiene su CPU y ejecutará la versión optimizada para ella. Vea este fragmento de sysdeps/x86_64/multiarch/memcmp.S desde 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)

En el kernel de linux

Parece que Linux no tiene una versión optimizada de memcmp para x86_64, pero sí para memcpy , en arch/x86/lib/memcpy_64.S . Tenga en cuenta que utiliza la infraestructura de alternativas ( arch/x86/kernel/alternative.c ) no solo para decidir en tiempo de ejecución qué versión usar, sino para parchearse solo para tomar esta decisión una vez en el arranque.